ctxr-cli 0.8.0 → 0.10.0

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 (250) hide show
  1. package/README.md +313 -22
  2. package/dist/adapters/types.d.ts +0 -5
  3. package/dist/adapters/types.d.ts.map +1 -1
  4. package/dist/commands/adapters-generate.d.ts.map +1 -1
  5. package/dist/commands/adapters-generate.js +2 -3
  6. package/dist/commands/adapters-generate.js.map +1 -1
  7. package/dist/commands/context-gather.d.ts +22 -0
  8. package/dist/commands/context-gather.d.ts.map +1 -0
  9. package/dist/commands/context-gather.js +36 -0
  10. package/dist/commands/context-gather.js.map +1 -0
  11. package/dist/commands/graph-query.d.ts.map +1 -1
  12. package/dist/commands/graph-query.js +6 -8
  13. package/dist/commands/graph-query.js.map +1 -1
  14. package/dist/commands/ingest.d.ts +22 -9
  15. package/dist/commands/ingest.d.ts.map +1 -1
  16. package/dist/commands/ingest.js +86 -24
  17. package/dist/commands/ingest.js.map +1 -1
  18. package/dist/commands/init.d.ts.map +1 -1
  19. package/dist/commands/init.js +22 -5
  20. package/dist/commands/init.js.map +1 -1
  21. package/dist/commands/publish-check.d.ts.map +1 -1
  22. package/dist/commands/publish-check.js +8 -0
  23. package/dist/commands/publish-check.js.map +1 -1
  24. package/dist/commands/publish-new.d.ts.map +1 -1
  25. package/dist/commands/publish-new.js +15 -0
  26. package/dist/commands/publish-new.js.map +1 -1
  27. package/dist/commands/serve.d.ts.map +1 -1
  28. package/dist/commands/serve.js +33 -11
  29. package/dist/commands/serve.js.map +1 -1
  30. package/dist/commands/session-start.d.ts.map +1 -1
  31. package/dist/commands/session-start.js +9 -1
  32. package/dist/commands/session-start.js.map +1 -1
  33. package/dist/commands/source-check.d.ts.map +1 -1
  34. package/dist/commands/source-check.js +52 -9
  35. package/dist/commands/source-check.js.map +1 -1
  36. package/dist/commands/source-stamp.d.ts +6 -5
  37. package/dist/commands/source-stamp.d.ts.map +1 -1
  38. package/dist/commands/source-stamp.js +8 -7
  39. package/dist/commands/source-stamp.js.map +1 -1
  40. package/dist/commands/update.d.ts.map +1 -1
  41. package/dist/commands/update.js +7 -1
  42. package/dist/commands/update.js.map +1 -1
  43. package/dist/commands/verify.d.ts +11 -2
  44. package/dist/commands/verify.d.ts.map +1 -1
  45. package/dist/commands/verify.js +86 -5
  46. package/dist/commands/verify.js.map +1 -1
  47. package/dist/commands/version.d.ts +31 -0
  48. package/dist/commands/version.d.ts.map +1 -0
  49. package/dist/commands/version.js +87 -0
  50. package/dist/commands/version.js.map +1 -0
  51. package/dist/config/defaults.d.ts +113 -4
  52. package/dist/config/defaults.d.ts.map +1 -1
  53. package/dist/config/defaults.js +83 -4
  54. package/dist/config/defaults.js.map +1 -1
  55. package/dist/config/load.d.ts +2 -2
  56. package/dist/config/load.d.ts.map +1 -1
  57. package/dist/config/load.js +13 -3
  58. package/dist/config/load.js.map +1 -1
  59. package/dist/config/render.d.ts +5 -0
  60. package/dist/config/render.d.ts.map +1 -1
  61. package/dist/config/render.js +62 -3
  62. package/dist/config/render.js.map +1 -1
  63. package/dist/config/schema.d.ts +47 -76
  64. package/dist/config/schema.d.ts.map +1 -1
  65. package/dist/config/schema.js +171 -134
  66. package/dist/config/schema.js.map +1 -1
  67. package/dist/core/agents-doc.d.ts.map +1 -1
  68. package/dist/core/agents-doc.js +4 -1
  69. package/dist/core/agents-doc.js.map +1 -1
  70. package/dist/core/browse/nav.d.ts.map +1 -1
  71. package/dist/core/browse/nav.js +4 -1
  72. package/dist/core/browse/nav.js.map +1 -1
  73. package/dist/core/browse/preferences.d.ts +26 -0
  74. package/dist/core/browse/preferences.d.ts.map +1 -0
  75. package/dist/core/browse/preferences.js +74 -0
  76. package/dist/core/browse/preferences.js.map +1 -0
  77. package/dist/core/browse/routes.d.ts +10 -8
  78. package/dist/core/browse/routes.d.ts.map +1 -1
  79. package/dist/core/browse/routes.js +113 -24
  80. package/dist/core/browse/routes.js.map +1 -1
  81. package/dist/core/browse/templates.d.ts +14 -4
  82. package/dist/core/browse/templates.d.ts.map +1 -1
  83. package/dist/core/browse/templates.js +22 -4
  84. package/dist/core/browse/templates.js.map +1 -1
  85. package/dist/core/checks/harness-portability-checks.d.ts +22 -1
  86. package/dist/core/checks/harness-portability-checks.d.ts.map +1 -1
  87. package/dist/core/checks/harness-portability-checks.js +48 -4
  88. package/dist/core/checks/harness-portability-checks.js.map +1 -1
  89. package/dist/core/checks/integrity-checks.d.ts +0 -2
  90. package/dist/core/checks/integrity-checks.d.ts.map +1 -1
  91. package/dist/core/checks/integrity-checks.js +2 -27
  92. package/dist/core/checks/integrity-checks.js.map +1 -1
  93. package/dist/core/checks/manifest.d.ts.map +1 -1
  94. package/dist/core/checks/manifest.js +2 -0
  95. package/dist/core/checks/manifest.js.map +1 -1
  96. package/dist/core/checks/organize-checks.d.ts +11 -1
  97. package/dist/core/checks/organize-checks.d.ts.map +1 -1
  98. package/dist/core/checks/organize-checks.js +42 -12
  99. package/dist/core/checks/organize-checks.js.map +1 -1
  100. package/dist/core/checks/retrieval-checks.d.ts +9 -0
  101. package/dist/core/checks/retrieval-checks.d.ts.map +1 -0
  102. package/dist/core/checks/retrieval-checks.js +30 -0
  103. package/dist/core/checks/retrieval-checks.js.map +1 -0
  104. package/dist/core/command.d.ts +6 -0
  105. package/dist/core/command.d.ts.map +1 -1
  106. package/dist/core/content/canonicalize.d.ts +10 -0
  107. package/dist/core/content/canonicalize.d.ts.map +1 -1
  108. package/dist/core/content/canonicalize.js +12 -0
  109. package/dist/core/content/canonicalize.js.map +1 -1
  110. package/dist/core/env.d.ts +5 -0
  111. package/dist/core/env.d.ts.map +1 -1
  112. package/dist/core/env.js +3 -0
  113. package/dist/core/env.js.map +1 -1
  114. package/dist/core/environment/probe.d.ts +12 -0
  115. package/dist/core/environment/probe.d.ts.map +1 -0
  116. package/dist/core/environment/probe.js +36 -0
  117. package/dist/core/environment/probe.js.map +1 -0
  118. package/dist/core/errors.d.ts +32 -0
  119. package/dist/core/errors.d.ts.map +1 -1
  120. package/dist/core/errors.js +81 -3
  121. package/dist/core/errors.js.map +1 -1
  122. package/dist/core/fs/prefix.d.ts +13 -0
  123. package/dist/core/fs/prefix.d.ts.map +1 -0
  124. package/dist/core/fs/prefix.js +22 -0
  125. package/dist/core/fs/prefix.js.map +1 -0
  126. package/dist/core/git/worktree.d.ts +22 -0
  127. package/dist/core/git/worktree.d.ts.map +1 -1
  128. package/dist/core/git/worktree.js +34 -0
  129. package/dist/core/git/worktree.js.map +1 -1
  130. package/dist/core/graph/persist.d.ts +13 -0
  131. package/dist/core/graph/persist.d.ts.map +1 -1
  132. package/dist/core/graph/persist.js +24 -0
  133. package/dist/core/graph/persist.js.map +1 -1
  134. package/dist/core/harness/isolated-run.d.ts +52 -0
  135. package/dist/core/harness/isolated-run.d.ts.map +1 -0
  136. package/dist/core/harness/isolated-run.js +100 -0
  137. package/dist/core/harness/isolated-run.js.map +1 -0
  138. package/dist/core/hooks.d.ts +3 -12
  139. package/dist/core/hooks.d.ts.map +1 -1
  140. package/dist/core/hooks.js +24 -20
  141. package/dist/core/hooks.js.map +1 -1
  142. package/dist/core/ingest/capture-hash.d.ts +16 -0
  143. package/dist/core/ingest/capture-hash.d.ts.map +1 -0
  144. package/dist/core/ingest/capture-hash.js +34 -0
  145. package/dist/core/ingest/capture-hash.js.map +1 -0
  146. package/dist/core/ingest/identity.d.ts +7 -1
  147. package/dist/core/ingest/identity.d.ts.map +1 -1
  148. package/dist/core/ingest/identity.js +16 -1
  149. package/dist/core/ingest/identity.js.map +1 -1
  150. package/dist/core/ingest/model.d.ts +17 -2
  151. package/dist/core/ingest/model.d.ts.map +1 -1
  152. package/dist/core/ingest/model.js +5 -0
  153. package/dist/core/ingest/model.js.map +1 -1
  154. package/dist/core/install-kind.d.ts +25 -0
  155. package/dist/core/install-kind.d.ts.map +1 -0
  156. package/dist/core/install-kind.js +56 -0
  157. package/dist/core/install-kind.js.map +1 -0
  158. package/dist/core/notes/list.d.ts +20 -0
  159. package/dist/core/notes/list.d.ts.map +1 -1
  160. package/dist/core/notes/list.js +27 -6
  161. package/dist/core/notes/list.js.map +1 -1
  162. package/dist/core/publish/script-check.d.ts +5 -2
  163. package/dist/core/publish/script-check.d.ts.map +1 -1
  164. package/dist/core/publish/script-check.js +5 -2
  165. package/dist/core/publish/script-check.js.map +1 -1
  166. package/dist/core/records.d.ts +7 -0
  167. package/dist/core/records.d.ts.map +1 -1
  168. package/dist/core/records.js +12 -2
  169. package/dist/core/records.js.map +1 -1
  170. package/dist/core/registry.d.ts +40 -0
  171. package/dist/core/registry.d.ts.map +1 -0
  172. package/dist/core/registry.js +55 -0
  173. package/dist/core/registry.js.map +1 -0
  174. package/dist/core/retrieval/pass.d.ts +66 -0
  175. package/dist/core/retrieval/pass.d.ts.map +1 -0
  176. package/dist/core/retrieval/pass.js +171 -0
  177. package/dist/core/retrieval/pass.js.map +1 -0
  178. package/dist/core/root.d.ts +11 -5
  179. package/dist/core/root.d.ts.map +1 -1
  180. package/dist/core/root.js +20 -8
  181. package/dist/core/root.js.map +1 -1
  182. package/dist/core/skills.d.ts.map +1 -1
  183. package/dist/core/skills.js +7 -0
  184. package/dist/core/skills.js.map +1 -1
  185. package/dist/core/version-check.d.ts +63 -0
  186. package/dist/core/version-check.d.ts.map +1 -0
  187. package/dist/core/version-check.js +181 -0
  188. package/dist/core/version-check.js.map +1 -0
  189. package/dist/core/write-lifecycle/path-gate.d.ts +2 -2
  190. package/dist/core/write-lifecycle/path-gate.d.ts.map +1 -1
  191. package/dist/core/write-lifecycle/path-gate.js +9 -10
  192. package/dist/core/write-lifecycle/path-gate.js.map +1 -1
  193. package/dist/run.d.ts +1 -6
  194. package/dist/run.d.ts.map +1 -1
  195. package/dist/run.js +76 -19
  196. package/dist/run.js.map +1 -1
  197. package/dist/version.d.ts +8 -1
  198. package/dist/version.d.ts.map +1 -1
  199. package/dist/version.js +8 -1
  200. package/dist/version.js.map +1 -1
  201. package/package.json +12 -4
  202. package/templates/agents/canonical.md +1 -1
  203. package/templates/agents/capture-and-ingest.md +27 -8
  204. package/templates/agents/retrieval-leg-routing.md +34 -8
  205. package/templates/hooks/_resolve-ctxr.sh +37 -0
  206. package/templates/hooks/claude-code-write-gate.sh +34 -6
  207. package/templates/hooks/pre-commit.sh +15 -8
  208. package/templates/serve/shell.html +16 -2
  209. package/templates/serve/style.css +145 -3
  210. package/templates/skills/ctxr-connection-finding.md +7 -5
  211. package/templates/skills/ctxr-ingest-orchestration.md +15 -9
  212. package/templates/skills/ctxr-publish.md +7 -8
  213. package/templates/skills/ctxr-session-lifecycle.md +20 -0
  214. package/templates/skills/ctxr-upgrade.md +44 -0
  215. package/dist/commands/migrate.d.ts +0 -30
  216. package/dist/commands/migrate.d.ts.map +0 -1
  217. package/dist/commands/migrate.js +0 -56
  218. package/dist/commands/migrate.js.map +0 -1
  219. package/dist/core/migrations/add-explanation-craft-skill.d.ts +0 -26
  220. package/dist/core/migrations/add-explanation-craft-skill.d.ts.map +0 -1
  221. package/dist/core/migrations/add-explanation-craft-skill.js +0 -94
  222. package/dist/core/migrations/add-explanation-craft-skill.js.map +0 -1
  223. package/dist/core/migrations/archive-destination-from-taxonomy.d.ts +0 -35
  224. package/dist/core/migrations/archive-destination-from-taxonomy.d.ts.map +0 -1
  225. package/dist/core/migrations/archive-destination-from-taxonomy.js +0 -109
  226. package/dist/core/migrations/archive-destination-from-taxonomy.js.map +0 -1
  227. package/dist/core/migrations/drop-access-axes.d.ts +0 -24
  228. package/dist/core/migrations/drop-access-axes.d.ts.map +0 -1
  229. package/dist/core/migrations/drop-access-axes.js +0 -54
  230. package/dist/core/migrations/drop-access-axes.js.map +0 -1
  231. package/dist/core/migrations/drop-forge-and-workspaces-external.d.ts +0 -19
  232. package/dist/core/migrations/drop-forge-and-workspaces-external.d.ts.map +0 -1
  233. package/dist/core/migrations/drop-forge-and-workspaces-external.js +0 -49
  234. package/dist/core/migrations/drop-forge-and-workspaces-external.js.map +0 -1
  235. package/dist/core/migrations/registry.d.ts +0 -16
  236. package/dist/core/migrations/registry.d.ts.map +0 -1
  237. package/dist/core/migrations/registry.js +0 -30
  238. package/dist/core/migrations/registry.js.map +0 -1
  239. package/dist/core/migrations/rename-conventions-path.d.ts +0 -26
  240. package/dist/core/migrations/rename-conventions-path.d.ts.map +0 -1
  241. package/dist/core/migrations/rename-conventions-path.js +0 -86
  242. package/dist/core/migrations/rename-conventions-path.js.map +0 -1
  243. package/dist/core/migrations/rename-procedures-path.d.ts +0 -17
  244. package/dist/core/migrations/rename-procedures-path.d.ts.map +0 -1
  245. package/dist/core/migrations/rename-procedures-path.js +0 -45
  246. package/dist/core/migrations/rename-procedures-path.js.map +0 -1
  247. package/dist/core/migrations/types.d.ts +0 -27
  248. package/dist/core/migrations/types.d.ts.map +0 -1
  249. package/dist/core/migrations/types.js +0 -2
  250. package/dist/core/migrations/types.js.map +0 -1
@@ -0,0 +1,63 @@
1
+ import type { RunEnv } from './env.js';
2
+ import type { Finding } from './envelope.js';
3
+ import type { Store } from './store.js';
4
+ /**
5
+ * The release comparison behind `ctxr version --check` and the session-start /
6
+ * update advisory (cli-contract: an explicit release check reports its answer
7
+ * through the exit code).
8
+ *
9
+ * Hand-rolled over the plain three-part shape rather than taking a semver
10
+ * dependency (design.md D7): every published release is X.Y.Z with no
11
+ * prerelease or build metadata, and a comparison that handles exactly that and
12
+ * REFUSES anything else fails in the right direction. An unrecognized version
13
+ * is reported as undeterminable and named — the fail-loud contract applied to
14
+ * parsing — never compared by guesswork, and never quietly treated as "current".
15
+ */
16
+ export type ReleaseComparison = {
17
+ readonly kind: 'current';
18
+ } | {
19
+ readonly kind: 'newer-available';
20
+ readonly installed: string;
21
+ readonly latest: string;
22
+ } | {
23
+ readonly kind: 'undetermined';
24
+ readonly reason: string;
25
+ };
26
+ /** Parses a plain X.Y.Z version. Returns undefined for anything else — including
27
+ * a prerelease, build metadata, a `v` prefix, or a leading/trailing space. */
28
+ export declare function parseVersion(version: string): [number, number, number] | undefined;
29
+ /**
30
+ * An installed version AHEAD of the published one is 'current', not an error:
31
+ * that is exactly what a maintainer running an unreleased build sees, and it
32
+ * is not a condition to nag them about.
33
+ */
34
+ export declare function compareRelease(installed: string, latest: string): ReleaseComparison;
35
+ /**
36
+ * Store-local, under the derived-cache subpath that is already gitignored and
37
+ * already declared in `derived.paths` — so it needs no new plumbing and never
38
+ * rides review. Deliberately NOT ~/.cache: that would be the first thing this
39
+ * codebase writes outside a store root, and under the integration tests'
40
+ * hermetic HOME it would write to a nonexistent path and silently do nothing
41
+ * (design.md D6).
42
+ */
43
+ export declare function updateCheckCachePath(store: Store): string;
44
+ /** The environment variable that suppresses the check for one invocation. */
45
+ export declare const UPDATE_CHECK_ENV_VAR = "CONTEXTURE_UPDATE_CHECK";
46
+ export interface UpdateAdvisory {
47
+ findings: Finding[];
48
+ /** The stderr line, when there is one to print. */
49
+ notice?: string;
50
+ }
51
+ /**
52
+ * cli-contract: an advisory about a newer release never changes the outcome of
53
+ * the command carrying it.
54
+ *
55
+ * This function has NO throwing path, and that is a requirement rather than an
56
+ * intention (design.md D5). Session start creates a git worktree BEFORE this
57
+ * runs, and runCommand maps any escaping error to the internal-error code — so
58
+ * an unhandled rejection here would report a failed session that had in fact
59
+ * succeeded, leaving an orphan worktree behind. Every failure below becomes a
60
+ * finding.
61
+ */
62
+ export declare function updateAdvisory(env: RunEnv, store: Store): Promise<UpdateAdvisory>;
63
+ //# sourceMappingURL=version-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/core/version-check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzF;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAI/D;+EAC+E;AAC/E,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAQlF;AAWD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAanF;AAQD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEzD;AAED,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AA0D9D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAiBD;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,cAAc,CAAC,CAoCvF"}
@@ -0,0 +1,181 @@
1
+ import { mkdir, readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { SHIPPED_DEFAULTS } from '../config/defaults.js';
4
+ import { writeFileAtomic } from './fs/atomic.js';
5
+ import { ownPackageName } from './registry.js';
6
+ import { CLI_VERSION } from '../version.js';
7
+ const THREE_PART = /^(\d+)\.(\d+)\.(\d+)$/;
8
+ /** Parses a plain X.Y.Z version. Returns undefined for anything else — including
9
+ * a prerelease, build metadata, a `v` prefix, or a leading/trailing space. */
10
+ export function parseVersion(version) {
11
+ const match = THREE_PART.exec(version);
12
+ if (!match)
13
+ return undefined;
14
+ const parts = [match[1], match[2], match[3]].map((part) => Number(part));
15
+ // Number() on a digits-only string cannot be NaN, but it can exceed the safe
16
+ // integer range on absurd input; refuse rather than compare imprecisely.
17
+ if (parts.some((part) => !Number.isSafeInteger(part)))
18
+ return undefined;
19
+ return [parts[0], parts[1], parts[2]];
20
+ }
21
+ /** Numeric, component-wise. Returns a negative number when `a` precedes `b`. */
22
+ function compareParsed(a, b) {
23
+ for (let i = 0; i < 3; i += 1) {
24
+ const diff = a[i] - b[i];
25
+ if (diff !== 0)
26
+ return diff;
27
+ }
28
+ return 0;
29
+ }
30
+ /**
31
+ * An installed version AHEAD of the published one is 'current', not an error:
32
+ * that is exactly what a maintainer running an unreleased build sees, and it
33
+ * is not a condition to nag them about.
34
+ */
35
+ export function compareRelease(installed, latest) {
36
+ const installedParts = parseVersion(installed);
37
+ if (!installedParts) {
38
+ return { kind: 'undetermined', reason: `the installed version "${installed}" is not a X.Y.Z version` };
39
+ }
40
+ const latestParts = parseVersion(latest);
41
+ if (!latestParts) {
42
+ return { kind: 'undetermined', reason: `the published version "${latest}" is not a X.Y.Z version` };
43
+ }
44
+ if (compareParsed(installedParts, latestParts) < 0) {
45
+ return { kind: 'newer-available', installed, latest };
46
+ }
47
+ return { kind: 'current' };
48
+ }
49
+ // ---------------------------------------------------------------------------
50
+ // The advisory: the cached, never-throwing path used by session start and
51
+ // update. `ctxr version --check` deliberately does NOT come through here — an
52
+ // operator asking explicitly is asking about now, not about the last answer.
53
+ // ---------------------------------------------------------------------------
54
+ /**
55
+ * Store-local, under the derived-cache subpath that is already gitignored and
56
+ * already declared in `derived.paths` — so it needs no new plumbing and never
57
+ * rides review. Deliberately NOT ~/.cache: that would be the first thing this
58
+ * codebase writes outside a store root, and under the integration tests'
59
+ * hermetic HOME it would write to a nonexistent path and silently do nothing
60
+ * (design.md D6).
61
+ */
62
+ export function updateCheckCachePath(store) {
63
+ return path.join(store.root, '.contexture', 'cache', 'update-check.json');
64
+ }
65
+ /** The environment variable that suppresses the check for one invocation. */
66
+ export const UPDATE_CHECK_ENV_VAR = 'CONTEXTURE_UPDATE_CHECK';
67
+ function isFresh(entry, now, ttlHours) {
68
+ const checkedAt = Date.parse(entry.checked_at);
69
+ if (!Number.isFinite(checkedAt))
70
+ return false;
71
+ const ageMs = now.getTime() - checkedAt;
72
+ // A cache stamped in the future is not fresh — a clock that moved backwards
73
+ // must not pin the answer forever.
74
+ return ageMs >= 0 && ageMs < ttlHours * 60 * 60 * 1000;
75
+ }
76
+ async function readCache(store, now, ttlHours) {
77
+ try {
78
+ const raw = await readFile(updateCheckCachePath(store), 'utf8');
79
+ const entry = JSON.parse(raw);
80
+ if (typeof entry.latest !== 'string' || typeof entry.checked_at !== 'string')
81
+ return undefined;
82
+ return isFresh(entry, now, ttlHours) ? entry.latest : undefined;
83
+ }
84
+ catch {
85
+ // Missing, unreadable, or corrupt are all a miss — never an error. The
86
+ // cache is an optimization; failing on it would let a stray byte on disk
87
+ // fail a session.
88
+ return undefined;
89
+ }
90
+ }
91
+ async function writeCache(store, now, latest) {
92
+ try {
93
+ const filePath = updateCheckCachePath(store);
94
+ await mkdir(path.dirname(filePath), { recursive: true });
95
+ const entry = { checked_at: now.toISOString(), latest };
96
+ await writeFileAtomic(filePath, `${JSON.stringify(entry, null, 2)}\n`);
97
+ }
98
+ catch {
99
+ // An unwritable cache costs one extra request next time. It is not a
100
+ // reason to fail the command that was carrying the advisory.
101
+ }
102
+ }
103
+ /** Reads the effective settings, falling back to the shipped defaults for a config that predates the block. */
104
+ function updateCheckSettings(store) {
105
+ const configured = store.config.update_check;
106
+ return {
107
+ enabled: configured?.enabled ?? SHIPPED_DEFAULTS.update_check.enabled,
108
+ ttlHours: configured?.ttl_hours ?? SHIPPED_DEFAULTS.update_check.ttl_hours,
109
+ };
110
+ }
111
+ /** Any explicit falsey spelling turns the check off for this invocation. */
112
+ function suppressedByEnv(env) {
113
+ const raw = env.env[UPDATE_CHECK_ENV_VAR];
114
+ if (raw === undefined)
115
+ return false;
116
+ return ['0', 'false', 'no', 'off', ''].includes(raw.trim().toLowerCase());
117
+ }
118
+ const NO_ADVISORY = { findings: [] };
119
+ function checkFailed(reason) {
120
+ return {
121
+ findings: [
122
+ {
123
+ code: 'cli.update_check_failed',
124
+ severity: 'info',
125
+ message: `the release check could not be completed: ${reason}`,
126
+ subject: ownPackageName(),
127
+ },
128
+ ],
129
+ };
130
+ }
131
+ /**
132
+ * cli-contract: an advisory about a newer release never changes the outcome of
133
+ * the command carrying it.
134
+ *
135
+ * This function has NO throwing path, and that is a requirement rather than an
136
+ * intention (design.md D5). Session start creates a git worktree BEFORE this
137
+ * runs, and runCommand maps any escaping error to the internal-error code — so
138
+ * an unhandled rejection here would report a failed session that had in fact
139
+ * succeeded, leaving an orphan worktree behind. Every failure below becomes a
140
+ * finding.
141
+ */
142
+ export async function updateAdvisory(env, store) {
143
+ try {
144
+ const { enabled, ttlHours } = updateCheckSettings(store);
145
+ if (!enabled || suppressedByEnv(env))
146
+ return NO_ADVISORY;
147
+ const now = env.now();
148
+ let latest = await readCache(store, now, ttlHours);
149
+ if (latest === undefined) {
150
+ const lookup = await env.registry.latestVersion(ownPackageName());
151
+ if (lookup.kind === 'undetermined')
152
+ return checkFailed(lookup.reason);
153
+ latest = lookup.version;
154
+ await writeCache(store, now, latest);
155
+ }
156
+ const comparison = compareRelease(CLI_VERSION, latest);
157
+ if (comparison.kind === 'undetermined')
158
+ return checkFailed(comparison.reason);
159
+ if (comparison.kind === 'current')
160
+ return NO_ADVISORY;
161
+ const message = `ctxr ${comparison.installed} is installed; ${comparison.latest} is available.`;
162
+ return {
163
+ findings: [
164
+ {
165
+ code: 'cli.update_available',
166
+ severity: 'info',
167
+ message,
168
+ subject: ownPackageName(),
169
+ details: { installed: comparison.installed, latest: comparison.latest },
170
+ },
171
+ ],
172
+ notice: `${message} Run the ctxr-upgrade skill to upgrade.`,
173
+ };
174
+ }
175
+ catch (err) {
176
+ // The backstop for anything the branches above did not anticipate. Reaching
177
+ // it is a bug, but reaching it must still not fail the caller's command.
178
+ return checkFailed(err instanceof Error ? err.message : String(err));
179
+ }
180
+ }
181
+ //# sourceMappingURL=version-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/core/version-check.ts"],"names":[],"mappings":"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"}
@@ -13,8 +13,8 @@ export interface PathGateResult {
13
13
  * directory's symlinks are followed. The sanctioned-location rule is
14
14
  * opt-in — with `write_lifecycle.writable_paths` empty (the default),
15
15
  * every in-store path is accepted; once any path is declared, only a
16
- * configured taxonomy layer, the inbox, a declared writable path, or a
17
- * contexture-owned location passes.
16
+ * configured taxonomy layer, the capture tier, a declared writable path, or
17
+ * a contexture-owned location passes.
18
18
  */
19
19
  export declare function sanctionedPath(config: StoreConfig, root: string, relativePath: string): Promise<PathGateResult>;
20
20
  export interface WriteScopeResult {
@@ -1 +1 @@
1
- {"version":3,"file":"path-gate.d.ts","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsFD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAqBrH;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqBvH"}
1
+ {"version":3,"file":"path-gate.d.ts","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmFD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAsBrH;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqBvH"}
@@ -2,6 +2,7 @@ import { existsSync } from 'node:fs';
2
2
  import { realpath } from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
  import { configuredAdapters } from '../../adapters/registry.js';
5
+ import { isUnderAnyPrefix } from '../fs/prefix.js';
5
6
  import { isLinkedWorktreeRoot } from '../git/repo.js';
6
7
  function normalizePrefix(prefix) {
7
8
  return prefix.replace(/\/+$/, '');
@@ -33,12 +34,6 @@ async function resolveStorePath(root, relativePath) {
33
34
  }
34
35
  return { kind: 'inside', rel };
35
36
  }
36
- function isUnderAnyPrefix(relativePath, prefixes) {
37
- return prefixes.some((prefix) => {
38
- const trimmed = normalizePrefix(prefix);
39
- return relativePath === trimmed || relativePath.startsWith(`${trimmed}/`);
40
- });
41
- }
42
37
  /**
43
38
  * session-capture-command spec (D5): locations contexture itself owns are
44
39
  * always sanctioned, regardless of writable_paths.
@@ -67,7 +62,11 @@ function contextureOwnedPrefixes(config) {
67
62
  function sanctionedPrefixesFor(config) {
68
63
  return [
69
64
  ...config.taxonomy.layers.map((layer) => layer.path),
70
- config.ingest.inbox_path,
65
+ // retain-captures-as-provenance: the capture ROOT, not the inbox inside
66
+ // it — ingest's own write moves a capture out of the inbox and into the
67
+ // tier's dated directory, which a store declaring writable_paths would
68
+ // otherwise refuse.
69
+ config.ingest.capture_root,
71
70
  ...config.write_lifecycle.writable_paths,
72
71
  ...contextureOwnedPrefixes(config),
73
72
  ];
@@ -82,8 +81,8 @@ function sanctionedPrefixesFor(config) {
82
81
  * directory's symlinks are followed. The sanctioned-location rule is
83
82
  * opt-in — with `write_lifecycle.writable_paths` empty (the default),
84
83
  * every in-store path is accepted; once any path is declared, only a
85
- * configured taxonomy layer, the inbox, a declared writable path, or a
86
- * contexture-owned location passes.
84
+ * configured taxonomy layer, the capture tier, a declared writable path, or
85
+ * a contexture-owned location passes.
87
86
  */
88
87
  export async function sanctionedPath(config, root, relativePath) {
89
88
  const resolution = await resolveStorePath(root, relativePath);
@@ -100,7 +99,7 @@ export async function sanctionedPath(config, root, relativePath) {
100
99
  if (!isUnderAnyPrefix(rel, sanctionedPrefixesFor(config))) {
101
100
  return {
102
101
  ok: false,
103
- reason: 'is not under a configured taxonomy layer, the inbox, a declared writable path, or a contexture-owned location',
102
+ reason: 'is not under a configured taxonomy layer, the capture tier, a declared writable path, or a contexture-owned location',
104
103
  };
105
104
  }
106
105
  return { ok: true };
@@ -1 +1 @@
1
- {"version":3,"file":"path-gate.js","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"path-gate.js","sourceRoot":"","sources":["../../../src/core/write-lifecycle/path-gate.ts"],"names":[],"mappings":"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"}
package/dist/run.d.ts CHANGED
@@ -6,11 +6,6 @@ import { ExitCode } from './core/exit-codes.js';
6
6
  * automatically gets json-envelope-conformance coverage the moment it's
7
7
  * added here.
8
8
  */
9
- export declare const COMMAND_NAMES: readonly ['init', 'doctor'];
10
- /**
11
- * The one testable seam for the whole CLI: given argv and an injected
12
- * RunEnv, returns the exit code it would have produced — no process-global
13
- * mutation, no real subprocess required for a unit test.
14
- */
9
+ export declare const COMMAND_NAMES: readonly ['init', 'doctor', 'version'];
15
10
  export declare function run(argv: readonly string[], env: RunEnv): Promise<ExitCode>;
16
11
  //# sourceMappingURL=run.d.ts.map
package/dist/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOhD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,YAAI,MAAM,EAAE,QAAQ,CAAU,CAAC;AAiFzD;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2ejF"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQhD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,YAAI,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAC;AA+GpE,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAghBjF"}
package/dist/run.js CHANGED
@@ -8,7 +8,7 @@ import * as archiveCommand from './commands/archive.js';
8
8
  import * as doctorCommand from './commands/doctor.js';
9
9
  import * as ingestCommand from './commands/ingest.js';
10
10
  import * as lintCommand from './commands/lint.js';
11
- import * as migrateCommand from './commands/migrate.js';
11
+ import * as contextGatherCommand from './commands/context-gather.js';
12
12
  import * as graphBuildCommand from './commands/graph-build.js';
13
13
  import * as entryAppendCommand from './commands/entry-append.js';
14
14
  import * as graphQueryCommand from './commands/graph-query.js';
@@ -34,6 +34,7 @@ import { createReporter } from './core/reporter.js';
34
34
  import { openStore } from './core/store.js';
35
35
  import * as updateCommand from './commands/update.js';
36
36
  import * as verifyCommand from './commands/verify.js';
37
+ import * as versionCommand from './commands/version.js';
37
38
  import { CLI_VERSION } from './version.js';
38
39
  /**
39
40
  * Every registered top-level command name (excluding subcommand groups like
@@ -41,7 +42,7 @@ import { CLI_VERSION } from './version.js';
41
42
  * automatically gets json-envelope-conformance coverage the moment it's
42
43
  * added here.
43
44
  */
44
- export const COMMAND_NAMES = ['init', 'doctor'];
45
+ export const COMMAND_NAMES = ['init', 'doctor', 'version'];
45
46
  function isCommanderError(err) {
46
47
  return typeof err === 'object' && err !== null && 'code' in err && typeof err.code === 'string';
47
48
  }
@@ -72,6 +73,8 @@ async function runCommand(commandName, env, jsonMode, body) {
72
73
  data: outcome.data,
73
74
  exitCode: outcome.exitCode,
74
75
  });
76
+ for (const notice of outcome.notices ?? [])
77
+ reporter.warn(notice);
75
78
  reporter.emitResult(envelope, outcome.humanSummary);
76
79
  return outcome.exitCode;
77
80
  }
@@ -109,7 +112,34 @@ async function runCommand(commandName, env, jsonMode, body) {
109
112
  * RunEnv, returns the exit code it would have produced — no process-global
110
113
  * mutation, no real subprocess required for a unit test.
111
114
  */
115
+ /**
116
+ * commander's own `.version()` writes through configureOutput's writeOut, which
117
+ * this program routes to stderr so parser chatter can never contaminate --json
118
+ * stdout. That is the one place a version query must NOT go, so the flag is
119
+ * recognized ahead of parsing and dispatched to the same command path as the
120
+ * subcommand (design.md D8) — one envelope, on stdout, and the two cannot drift.
121
+ *
122
+ * Only a bare global query is intercepted: a version flag alongside anything
123
+ * other than the global output flags falls through to commander, which reports
124
+ * it as the usage error it is.
125
+ */
126
+ const VERSION_FLAGS = new Set(['--version', '-V']);
127
+ const GLOBAL_PASSTHROUGH_FLAGS = new Set(['--json', '--no-input']);
128
+ function isGlobalVersionRequest(argv) {
129
+ if (!argv.some((arg) => VERSION_FLAGS.has(arg)))
130
+ return false;
131
+ return argv.every((arg) => VERSION_FLAGS.has(arg) || GLOBAL_PASSTHROUGH_FLAGS.has(arg));
132
+ }
133
+ /** Accumulates a repeatable option's values — commander keeps only the last without it. */
134
+ function collect(value, previous) {
135
+ return [...previous, value];
136
+ }
112
137
  export async function run(argv, env) {
138
+ if (isGlobalVersionRequest(argv)) {
139
+ const jsonMode = argv.includes('--json');
140
+ const runEnv = { ...env, noInput: env.noInput || argv.includes('--no-input') || jsonMode };
141
+ return runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv));
142
+ }
113
143
  const program = new Command();
114
144
  program
115
145
  .name('ctxr')
@@ -118,7 +148,7 @@ export async function run(argv, env) {
118
148
  writeOut: (str) => env.io.stderr.write(str),
119
149
  writeErr: (str) => env.io.stderr.write(str),
120
150
  })
121
- .option('--root <path>', 'store root (overrides CONTEXTURE_ROOT)')
151
+ .option('--root <path>', 'store root (overrides CONTEXTURE_STORE_ROOT)')
122
152
  .option('--json', 'emit machine-readable output')
123
153
  .option('--no-input', 'never prompt; fail loud instead of blocking');
124
154
  let result = ExitCode.Ok;
@@ -189,6 +219,34 @@ export async function run(argv, env) {
189
219
  return catalogShowCommand.execute(store, { section: cmdOpts.section });
190
220
  });
191
221
  });
222
+ const contextCommand = program.command('context').description('the retrieval pass over the store');
223
+ contextCommand
224
+ .command('gather')
225
+ .description('expand entry selectors through the built graph into a gloss-annotated, ordered candidate set — no query, no ranking')
226
+ .option('--seed <path>', 'a note already in hand (repeatable)', collect, [])
227
+ .option('--section <id>', 'every note a catalog section lists (repeatable)', collect, [])
228
+ .option('--under <prefix>', 'every retrievable note under this path prefix (repeatable)', collect, [])
229
+ .option('--entity <name>', 'every note linking to this entity (same enumeration as rollup gather; repeatable)', collect, [])
230
+ .option('--hops <n>', 'how many graph hops to expand from the entry set', (v) => Number.parseInt(v, 10), 1)
231
+ .option('--direction <dir>', 'expand along in, out, or both edge directions', 'both')
232
+ .option('--type <name>', 'expand only along edges of one configured relation')
233
+ .option('--max-notes <n>', 'cap the returned set; truncation is reported, never silent', (v) => Number.parseInt(v, 10))
234
+ .action(async (cmdOpts, cmd) => {
235
+ const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
236
+ result = await runCommand('context.gather', runEnv, jsonMode, async () => {
237
+ const store = await openStore(runEnv, { root });
238
+ return contextGatherCommand.execute(store, {
239
+ seed: cmdOpts.seed,
240
+ section: cmdOpts.section,
241
+ under: cmdOpts.under,
242
+ entity: cmdOpts.entity,
243
+ hops: cmdOpts.hops,
244
+ direction: cmdOpts.direction,
245
+ type: cmdOpts.type,
246
+ maxNotes: cmdOpts.maxNotes,
247
+ });
248
+ });
249
+ });
192
250
  const graphCommand = program.command('graph').description('the wikilink graph derived from the store');
193
251
  graphCommand
194
252
  .command('build')
@@ -284,15 +342,17 @@ export async function run(argv, env) {
284
342
  });
285
343
  program
286
344
  .command('ingest <path>')
287
- .description('stamp source-identity fields onto an inbox file, turning it into a note')
345
+ .description('retain a capture with its source identity, and cite it from the note it informed')
346
+ .requiredOption('--into <note>', 'the note this material informed — new or existing; ingest never creates it')
288
347
  .requiredOption('--source-type <type>', 'the kind of source this material came from')
289
348
  .requiredOption('--source-id <id>', 'a stable identifier for this specific source')
290
- .action(async (notePath, cmdOpts, cmd) => {
349
+ .action(async (capturePath, cmdOpts, cmd) => {
291
350
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
292
351
  result = await runCommand('ingest', runEnv, jsonMode, async () => {
293
352
  const store = await openStore(runEnv, { root });
294
353
  return ingestCommand.execute(runEnv, store, {
295
- path: notePath,
354
+ path: capturePath,
355
+ into: cmdOpts.into,
296
356
  sourceType: cmdOpts.sourceType,
297
357
  sourceId: cmdOpts.sourceId,
298
358
  });
@@ -467,6 +527,14 @@ export async function run(argv, env) {
467
527
  return serveCommand.execute(runEnv, store, { port: cmdOpts.port, host: cmdOpts.host });
468
528
  });
469
529
  });
530
+ program
531
+ .command('version')
532
+ .description("report the installed ctxr version, where it is installed from, and (with --check) whether a newer release is published")
533
+ .option('--check', 'resolve the latest published release and compare it against the installed one')
534
+ .action(async (cmdOpts, cmd) => {
535
+ const { runEnv, jsonMode } = deriveRunEnv(env, cmd);
536
+ result = await runCommand('version', runEnv, jsonMode, () => versionCommand.execute(runEnv, { check: cmdOpts.check }));
537
+ });
470
538
  program
471
539
  .command('update')
472
540
  .description('bring every contexture-owned file in the store up to the installed version (docs, skills, hooks, adapter outputs)')
@@ -480,23 +548,12 @@ export async function run(argv, env) {
480
548
  program
481
549
  .command('verify')
482
550
  .description('exercise core store operations end to end, from an environment with no harness-specific state')
483
- .option('--portable', 'the portability test: a retrieval query, a derived-artifact build, and following one skill')
551
+ .option('--portable', "verify the store's recorded commit in a disposable checkout, in a child process with no harness state reachable")
484
552
  .action(async (cmdOpts, cmd) => {
485
553
  const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
486
554
  result = await runCommand('verify', runEnv, jsonMode, async () => {
487
555
  const store = await openStore(runEnv, { root });
488
- return verifyCommand.execute(store, { portable: cmdOpts.portable });
489
- });
490
- });
491
- program
492
- .command('migrate')
493
- .description('apply every pending schema migration, bringing the store up to the current schema_version')
494
- .option('--dry-run', 'report the exact changes each pending migration would make, without applying them')
495
- .action(async (cmdOpts, cmd) => {
496
- const { runEnv, jsonMode, root } = deriveRunEnv(env, cmd);
497
- result = await runCommand('migrate', runEnv, jsonMode, async () => {
498
- const store = await openStore(runEnv, { root });
499
- return migrateCommand.execute(store, { dryRun: cmdOpts.dryRun });
556
+ return verifyCommand.execute(runEnv, store, { portable: cmdOpts.portable });
500
557
  });
501
558
  });
502
559
  const sessionCommand = program.command('session').description('manage session worktrees');