things-api 0.11.0 → 0.13.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 (208) hide show
  1. package/README.md +16 -5
  2. package/dist/audit/schema.d.ts +7 -0
  3. package/dist/audit/schema.js.map +1 -1
  4. package/dist/cli/canonical-ref.d.ts +21 -0
  5. package/dist/cli/canonical-ref.js +23 -0
  6. package/dist/cli/canonical-ref.js.map +1 -0
  7. package/dist/cli/commands/area.d.ts +18 -11
  8. package/dist/cli/commands/area.js +81 -77
  9. package/dist/cli/commands/area.js.map +1 -1
  10. package/dist/cli/commands/doctor.d.ts +1 -2
  11. package/dist/cli/commands/doctor.js +11 -1
  12. package/dist/cli/commands/doctor.js.map +1 -1
  13. package/dist/cli/commands/install-skill.d.ts +19 -4
  14. package/dist/cli/commands/install-skill.js +130 -52
  15. package/dist/cli/commands/install-skill.js.map +1 -1
  16. package/dist/cli/commands/mcp.js +21 -1
  17. package/dist/cli/commands/mcp.js.map +1 -1
  18. package/dist/cli/commands/project.d.ts +1 -0
  19. package/dist/cli/commands/project.js +92 -48
  20. package/dist/cli/commands/project.js.map +1 -1
  21. package/dist/cli/commands/reads.d.ts +5 -1
  22. package/dist/cli/commands/reads.js +110 -31
  23. package/dist/cli/commands/reads.js.map +1 -1
  24. package/dist/cli/commands/setup.js +11 -4
  25. package/dist/cli/commands/setup.js.map +1 -1
  26. package/dist/cli/commands/show.js +75 -36
  27. package/dist/cli/commands/show.js.map +1 -1
  28. package/dist/cli/commands/todo.js +2 -2
  29. package/dist/cli/commands/todo.js.map +1 -1
  30. package/dist/cli/commands/writes.js +795 -144
  31. package/dist/cli/commands/writes.js.map +1 -1
  32. package/dist/cli/did-you-mean.d.ts +14 -3
  33. package/dist/cli/did-you-mean.js +44 -7
  34. package/dist/cli/did-you-mean.js.map +1 -1
  35. package/dist/cli/dry-run.d.ts +55 -0
  36. package/dist/cli/dry-run.js +92 -0
  37. package/dist/cli/dry-run.js.map +1 -0
  38. package/dist/cli/glyphs.d.ts +16 -2
  39. package/dist/cli/glyphs.js +60 -12
  40. package/dist/cli/glyphs.js.map +1 -1
  41. package/dist/cli/help.js +69 -13
  42. package/dist/cli/help.js.map +1 -1
  43. package/dist/cli/main.js +8 -1
  44. package/dist/cli/main.js.map +1 -1
  45. package/dist/cli/move-hint.d.ts +3 -2
  46. package/dist/cli/move-hint.js +2 -2
  47. package/dist/cli/move-hint.js.map +1 -1
  48. package/dist/cli/read-driver.d.ts +53 -5
  49. package/dist/cli/read-driver.js +82 -15
  50. package/dist/cli/read-driver.js.map +1 -1
  51. package/dist/cli/ref-render.d.ts +14 -0
  52. package/dist/cli/ref-render.js +9 -0
  53. package/dist/cli/ref-render.js.map +1 -0
  54. package/dist/cli/render.d.ts +40 -14
  55. package/dist/cli/render.js +128 -55
  56. package/dist/cli/render.js.map +1 -1
  57. package/dist/cli/resolve-invocation.d.ts +7 -5
  58. package/dist/cli/resolve-invocation.js +16 -7
  59. package/dist/cli/resolve-invocation.js.map +1 -1
  60. package/dist/cli/skill-check.d.ts +12 -6
  61. package/dist/cli/skill-check.js +31 -14
  62. package/dist/cli/skill-check.js.map +1 -1
  63. package/dist/cli/skill.d.ts +8 -0
  64. package/dist/cli/skill.js +10 -0
  65. package/dist/cli/skill.js.map +1 -1
  66. package/dist/cli/verb-hint.js +1 -1
  67. package/dist/cli/verb-hint.js.map +1 -1
  68. package/dist/client.d.ts +158 -26
  69. package/dist/client.js +254 -38
  70. package/dist/client.js.map +1 -1
  71. package/dist/config.d.ts +66 -2
  72. package/dist/config.js +120 -12
  73. package/dist/config.js.map +1 -1
  74. package/dist/contracts.d.ts +187 -28
  75. package/dist/contracts.js +22 -1
  76. package/dist/contracts.js.map +1 -1
  77. package/dist/db/baselines/db-v26.js +4 -1
  78. package/dist/db/baselines/db-v26.js.map +1 -1
  79. package/dist/diagnose.d.ts +34 -2
  80. package/dist/diagnose.js +36 -1
  81. package/dist/diagnose.js.map +1 -1
  82. package/dist/index.d.ts +21 -8
  83. package/dist/index.js +26 -3
  84. package/dist/index.js.map +1 -1
  85. package/dist/mcp/server.d.ts +9 -0
  86. package/dist/mcp/server.js +790 -322
  87. package/dist/mcp/server.js.map +1 -1
  88. package/dist/model/entities.d.ts +57 -4
  89. package/dist/model/entities.js.map +1 -1
  90. package/dist/model/mappers.d.ts +2 -0
  91. package/dist/model/mappers.js +44 -2
  92. package/dist/model/mappers.js.map +1 -1
  93. package/dist/model/recurrence.d.ts +8 -1
  94. package/dist/model/recurrence.js.map +1 -1
  95. package/dist/model/serialize.js +15 -3
  96. package/dist/model/serialize.js.map +1 -1
  97. package/dist/read/area-filter.d.ts +76 -0
  98. package/dist/read/area-filter.js +58 -0
  99. package/dist/read/area-filter.js.map +1 -0
  100. package/dist/read/area-view.d.ts +22 -11
  101. package/dist/read/area-view.js +54 -28
  102. package/dist/read/area-view.js.map +1 -1
  103. package/dist/read/detail.js +15 -8
  104. package/dist/read/detail.js.map +1 -1
  105. package/dist/read/predicates.d.ts +18 -0
  106. package/dist/read/predicates.js +19 -0
  107. package/dist/read/predicates.js.map +1 -1
  108. package/dist/read/project-view.d.ts +91 -15
  109. package/dist/read/project-view.js +135 -37
  110. package/dist/read/project-view.js.map +1 -1
  111. package/dist/read/pseudo-area.d.ts +29 -0
  112. package/dist/read/pseudo-area.js +27 -0
  113. package/dist/read/pseudo-area.js.map +1 -0
  114. package/dist/read/queries.d.ts +175 -19
  115. package/dist/read/queries.js +376 -32
  116. package/dist/read/queries.js.map +1 -1
  117. package/dist/read/scope.d.ts +126 -0
  118. package/dist/read/scope.js +161 -0
  119. package/dist/read/scope.js.map +1 -0
  120. package/dist/read/search-rank.d.ts +2 -5
  121. package/dist/read/shape.d.ts +181 -0
  122. package/dist/read/shape.js +737 -0
  123. package/dist/read/shape.js.map +1 -0
  124. package/dist/read/show-target.d.ts +9 -1
  125. package/dist/read/show-target.js +77 -17
  126. package/dist/read/show-target.js.map +1 -1
  127. package/dist/read/stage.d.ts +199 -0
  128. package/dist/read/stage.js +125 -0
  129. package/dist/read/stage.js.map +1 -0
  130. package/dist/read/truncation.d.ts +7 -12
  131. package/dist/read/truncation.js +56 -21
  132. package/dist/read/truncation.js.map +1 -1
  133. package/dist/read/views.d.ts +68 -16
  134. package/dist/read/views.js +206 -52
  135. package/dist/read/views.js.map +1 -1
  136. package/dist/surface-copy.d.ts +16 -0
  137. package/dist/surface-copy.js +16 -0
  138. package/dist/surface-copy.js.map +1 -1
  139. package/dist/write/batch.d.ts +49 -10
  140. package/dist/write/batch.js +423 -71
  141. package/dist/write/batch.js.map +1 -1
  142. package/dist/write/commands.js +268 -55
  143. package/dist/write/commands.js.map +1 -1
  144. package/dist/write/guards.d.ts +1 -1
  145. package/dist/write/guards.js +71 -10
  146. package/dist/write/guards.js.map +1 -1
  147. package/dist/write/heading.d.ts +10 -1
  148. package/dist/write/heading.js +35 -5
  149. package/dist/write/heading.js.map +1 -1
  150. package/dist/write/make-repeating-project.d.ts +2 -2
  151. package/dist/write/make-repeating-project.js +9 -9
  152. package/dist/write/make-repeating-project.js.map +1 -1
  153. package/dist/write/move.d.ts +134 -0
  154. package/dist/write/move.js +1874 -0
  155. package/dist/write/move.js.map +1 -0
  156. package/dist/write/operations.d.ts +105 -19
  157. package/dist/write/operations.js +56 -7
  158. package/dist/write/operations.js.map +1 -1
  159. package/dist/write/opid.d.ts +31 -0
  160. package/dist/write/opid.js +30 -0
  161. package/dist/write/opid.js.map +1 -0
  162. package/dist/write/pipeline.d.ts +70 -3
  163. package/dist/write/pipeline.js +198 -33
  164. package/dist/write/pipeline.js.map +1 -1
  165. package/dist/write/pre-state.d.ts +172 -8
  166. package/dist/write/pre-state.js +467 -25
  167. package/dist/write/pre-state.js.map +1 -1
  168. package/dist/write/reorder.d.ts +23 -3
  169. package/dist/write/reorder.js +2106 -86
  170. package/dist/write/reorder.js.map +1 -1
  171. package/dist/write/reversibility.js +19 -7
  172. package/dist/write/reversibility.js.map +1 -1
  173. package/dist/write/scope-guard.d.ts +31 -0
  174. package/dist/write/scope-guard.js +162 -0
  175. package/dist/write/scope-guard.js.map +1 -0
  176. package/dist/write/undo.js +120 -13
  177. package/dist/write/undo.js.map +1 -1
  178. package/dist/write/vectors/applescript.js +16 -7
  179. package/dist/write/vectors/applescript.js.map +1 -1
  180. package/dist/write/vectors/shortcuts.js +1 -1
  181. package/dist/write/vectors/shortcuts.js.map +1 -1
  182. package/dist/write/vectors/simulator.js +83 -27
  183. package/dist/write/vectors/simulator.js.map +1 -1
  184. package/dist/write/vectors/types.d.ts +11 -0
  185. package/dist/write/vectors/ui-certification.d.ts +3 -3
  186. package/dist/write/vectors/ui-certification.js +41 -5
  187. package/dist/write/vectors/ui-certification.js.map +1 -1
  188. package/dist/write/vectors/ui-drag.d.ts +21 -1
  189. package/dist/write/vectors/ui-drag.js +138 -27
  190. package/dist/write/vectors/ui-drag.js.map +1 -1
  191. package/dist/write/vectors/ui-recipes.d.ts +21 -1
  192. package/dist/write/vectors/ui-recipes.js +166 -7
  193. package/dist/write/vectors/ui-recipes.js.map +1 -1
  194. package/dist/write/vectors/ui.d.ts +25 -1
  195. package/dist/write/vectors/ui.js +142 -33
  196. package/dist/write/vectors/ui.js.map +1 -1
  197. package/dist/write/verify/delta.d.ts +17 -1
  198. package/dist/write/verify/delta.js +106 -29
  199. package/dist/write/verify/delta.js.map +1 -1
  200. package/package.json +7 -1
  201. package/schema/envelope.schema.json +397 -0
  202. package/skills/things-cli/SKILL.md +36 -17
  203. package/skills/things-cli/references/banner.md +35 -0
  204. package/skills/things-cli/references/contracts.md +32 -9
  205. package/skills/things-cli/references/errors.md +57 -0
  206. package/skills/things-cli/references/gui.md +1 -1
  207. package/skills/things-cli/references/model.md +18 -7
  208. package/skills/things-cli/references/ordering.md +88 -0
@@ -7,27 +7,42 @@ interface LocationReport {
7
7
  label: string;
8
8
  dir: string;
9
9
  installedVersion: string | null;
10
- /** up-to-date | behind | differs | absent (check); written (install copy). */
11
- status: "up-to-date" | "behind" | "differs" | "absent" | "written";
10
+ /** up-to-date | behind | differs | legacy | absent (check); written (install copy); would-write (dry-run). */
11
+ status: "up-to-date" | "behind" | "differs" | "legacy" | "absent" | "written" | "would-write";
12
12
  }
13
13
  interface InstallSkillData {
14
14
  mode: "install" | "check";
15
15
  path: InstallPath;
16
16
  global: boolean;
17
- bundledVersion: string | null;
17
+ /** The running binary's version — the source of truth we stamp and check against. */
18
+ binaryVersion: string;
18
19
  locations: LocationReport[];
19
20
  detail: string;
20
21
  }
21
22
  /** Injectable side effects, so the integration test never touches the network. */
22
23
  export interface InstallSkillDeps {
23
24
  home: string;
25
+ /** The running binary's version (`CLI_VERSION`); stamped into copies and checked against. */
26
+ binaryVersion: string;
24
27
  /** True to simulate without touching HOME (bench fence). */
25
28
  simulated: boolean;
26
29
  /** Run `skills add`; returns true on success, false when unavailable/failed. */
27
30
  runSkillsCli: (skillDir: string, global: boolean) => boolean;
28
- /** Plain-copy the bundled skill into a destination directory (clean overwrite). */
31
+ /** Plain-copy an already-stamped skill dir into a destination (clean overwrite). */
29
32
  copyInto: (skillDir: string, destDir: string) => void;
30
33
  }
34
+ /**
35
+ * Materialize a stamped copy of the bundled skill in a temp dir and run `fn`
36
+ * against it, cleaning up afterwards. The copy's `SKILL.md` frontmatter is
37
+ * rewritten to `version`, so EVERY location the installer subsequently
38
+ * materializes — the canonical root, `~/.claude`, and any other agent dir the
39
+ * `skills` CLI detects that we do not enumerate — inherits the stamp. Stamping
40
+ * at the source (rather than re-stamping the two locations we know) is why the
41
+ * shell-out path stays correct. The temp dir keeps the skill's canonical
42
+ * basename (`things-cli`) so `skills add <dir>` registers it under the right id.
43
+ * The repo's own `SKILL.md` is never touched — we only ever write to the copy.
44
+ */
45
+ export declare function withStampedSkillDir<T>(srcDir: string, version: string, fn: (dir: string) => T): T;
31
46
  /** Default plain copy: replace the destination directory wholesale. */
32
47
  export declare function defaultCopyInto(skillDir: string, destDir: string): void;
33
48
  /**
@@ -6,12 +6,49 @@
6
6
  * without detection (`~/.agents` and `~/.claude`) when that tool or the network
7
7
  * is unavailable. Re-running it IS the update: the skill directory is replaced
8
8
  * wholesale, so a stale copy is cleanly overwritten.
9
+ *
10
+ * Source of truth for the "current" skill version is the RUNNING BINARY's
11
+ * version (`CLI_VERSION` — `-dev` in a source checkout), NOT the frontmatter of
12
+ * the bundled `SKILL.md`. The repo copy deliberately stays `0.0.0-dev` (stamped
13
+ * only at publish, to keep dev builds git-quiet), so comparing or copying that
14
+ * placeholder is meaningless in a dev checkout. Instead we stamp a temp copy of
15
+ * the skill with the binary's version at install time and hand THAT to the
16
+ * installer, and `--check` compares installed stamps against the binary version.
17
+ * The repo's `SKILL.md` is never modified. (In a published install the two
18
+ * agree — the tarball is pre-stamped to the same version the binary reports —
19
+ * so the outcome is identical to before.)
9
20
  */
10
21
  import { execFileSync } from "node:child_process";
11
- import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
12
- import { dirname } from "node:path";
22
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
23
+ import { tmpdir } from "node:os";
24
+ import { dirname, join } from "node:path";
13
25
  import { ExitCode, okEnvelope, simFenceActive } from "../../index.js";
14
- import { bundledSkillDir, bundledSkillVersion, compareSemver, installedSkillVersion, resolveHome, skillLocations, } from "../skill.js";
26
+ import { bundledSkillDir, compareSemver, installedSkillVersion, isLegacyDevStamp, resolveHome, SKILL_NAME, skillLocations, stampSkillVersion, } from "../skill.js";
27
+ import { CLI_VERSION } from "../version.js";
28
+ /**
29
+ * Materialize a stamped copy of the bundled skill in a temp dir and run `fn`
30
+ * against it, cleaning up afterwards. The copy's `SKILL.md` frontmatter is
31
+ * rewritten to `version`, so EVERY location the installer subsequently
32
+ * materializes — the canonical root, `~/.claude`, and any other agent dir the
33
+ * `skills` CLI detects that we do not enumerate — inherits the stamp. Stamping
34
+ * at the source (rather than re-stamping the two locations we know) is why the
35
+ * shell-out path stays correct. The temp dir keeps the skill's canonical
36
+ * basename (`things-cli`) so `skills add <dir>` registers it under the right id.
37
+ * The repo's own `SKILL.md` is never touched — we only ever write to the copy.
38
+ */
39
+ export function withStampedSkillDir(srcDir, version, fn) {
40
+ const tmp = mkdtempSync(join(tmpdir(), "things-api-skill-stamp-"));
41
+ try {
42
+ const staged = join(tmp, SKILL_NAME);
43
+ cpSync(srcDir, staged, { recursive: true });
44
+ const mdPath = join(staged, "SKILL.md");
45
+ writeFileSync(mdPath, stampSkillVersion(readFileSync(mdPath, "utf8"), version));
46
+ return fn(staged);
47
+ }
48
+ finally {
49
+ rmSync(tmp, { recursive: true, force: true });
50
+ }
51
+ }
15
52
  /** Default `skills` shell-out: `npx -y skills add <dir> [-g] -y`, offline-safe. */
16
53
  function defaultRunSkillsCli(skillDir, global) {
17
54
  const args = ["-y", "skills", "add", skillDir, ...(global ? ["-g"] : []), "-y"];
@@ -33,13 +70,20 @@ export function defaultCopyInto(skillDir, destDir) {
33
70
  function meta(started) {
34
71
  return { dbVersion: null, fingerprint: "unknown", elapsedMs: Date.now() - started };
35
72
  }
36
- /** Classify an installed stamp against the bundled one for `--check`. */
37
- function checkStatus(installed, bundled) {
73
+ /**
74
+ * Classify an installed stamp against the RUNNING BINARY's version for `--check`.
75
+ * A pre-ratchet placeholder (`0.0.0-dev`) reads as `legacy` — an install-skill
76
+ * refresh, not a "hundreds of versions behind" scare. `compareSemver` ignores
77
+ * any `-dev` suffix, so a dev binary vs a same-version stamp reads up-to-date.
78
+ */
79
+ function checkStatus(installed, binary) {
38
80
  if (installed === null)
39
81
  return "absent";
40
- if (installed === bundled)
82
+ if (isLegacyDevStamp(installed))
83
+ return "legacy";
84
+ if (installed === binary)
41
85
  return "up-to-date";
42
- const cmp = compareSemver(installed, bundled);
86
+ const cmp = compareSemver(installed, binary);
43
87
  if (cmp !== null && cmp < 0)
44
88
  return "behind";
45
89
  return cmp === 0 ? "up-to-date" : "differs";
@@ -51,7 +95,7 @@ function checkStatus(installed, bundled) {
51
95
  export function installSkill(opts, deps) {
52
96
  const global = opts.project !== true;
53
97
  const skillDir = bundledSkillDir();
54
- const bundledVersion = bundledSkillVersion();
98
+ const binaryVersion = deps.binaryVersion;
55
99
  const locations = skillLocations(deps.home);
56
100
  if (!existsSync(skillDir)) {
57
101
  return {
@@ -60,13 +104,13 @@ export function installSkill(opts, deps) {
60
104
  mode: opts.check === true ? "check" : "install",
61
105
  path: "check",
62
106
  global,
63
- bundledVersion,
107
+ binaryVersion,
64
108
  locations: [],
65
109
  detail: `bundled skill directory not found: ${skillDir}`,
66
110
  },
67
111
  };
68
112
  }
69
- // --check: read stamps, compare, never write.
113
+ // --check: read stamps, compare against the running binary, never write.
70
114
  if (opts.check === true) {
71
115
  const rows = locations.map((loc) => {
72
116
  const installed = installedSkillVersion(loc.dir);
@@ -74,7 +118,7 @@ export function installSkill(opts, deps) {
74
118
  label: loc.label,
75
119
  dir: loc.dir,
76
120
  installedVersion: installed,
77
- status: checkStatus(installed, bundledVersion),
121
+ status: checkStatus(installed, binaryVersion),
78
122
  };
79
123
  });
80
124
  const canonical = rows.find((_, i) => locations[i]?.canonical === true) ?? rows[0];
@@ -85,7 +129,7 @@ export function installSkill(opts, deps) {
85
129
  mode: "check",
86
130
  path: "check",
87
131
  global,
88
- bundledVersion,
132
+ binaryVersion,
89
133
  locations: rows,
90
134
  detail: ok
91
135
  ? "installed skill is up to date"
@@ -101,62 +145,65 @@ export function installSkill(opts, deps) {
101
145
  mode: "install",
102
146
  path: "simulated",
103
147
  global,
104
- bundledVersion,
148
+ binaryVersion,
105
149
  locations: [],
106
150
  detail: "simulated: no files were written (the skill roots were not touched)",
107
151
  },
108
152
  };
109
153
  }
110
- // Prefer the skills CLI; fall back to a plain copy into the two known roots.
111
- const viaCli = deps.runSkillsCli(skillDir, global);
112
- if (viaCli) {
113
- const rows = locations
114
- .filter((loc) => loc.canonical || existsSync(loc.dir))
115
- .map((loc) => ({
116
- label: loc.label,
117
- dir: loc.dir,
118
- installedVersion: installedSkillVersion(loc.dir),
119
- status: "written",
120
- }));
154
+ // Stamp a temp copy with the binary version and install THAT every location
155
+ // the installer materializes inherits the stamp; the repo copy stays pristine.
156
+ return withStampedSkillDir(skillDir, binaryVersion, (stampedDir) => {
157
+ // Prefer the skills CLI; fall back to a plain copy into the two known roots.
158
+ const viaCli = deps.runSkillsCli(stampedDir, global);
159
+ if (viaCli) {
160
+ const rows = locations
161
+ .filter((loc) => loc.canonical || existsSync(loc.dir))
162
+ .map((loc) => ({
163
+ label: loc.label,
164
+ dir: loc.dir,
165
+ installedVersion: installedSkillVersion(loc.dir),
166
+ status: "written",
167
+ }));
168
+ return {
169
+ exitCode: ExitCode.Ok,
170
+ data: {
171
+ mode: "install",
172
+ path: "skills-cli",
173
+ global,
174
+ binaryVersion,
175
+ locations: rows,
176
+ detail: "installed via the skills CLI (canonical ~/.agents + detected agent dirs)",
177
+ },
178
+ };
179
+ }
180
+ const rows = locations.map((loc) => {
181
+ deps.copyInto(stampedDir, loc.dir);
182
+ return {
183
+ label: loc.label,
184
+ dir: loc.dir,
185
+ installedVersion: installedSkillVersion(loc.dir),
186
+ status: "written",
187
+ };
188
+ });
121
189
  return {
122
190
  exitCode: ExitCode.Ok,
123
191
  data: {
124
192
  mode: "install",
125
- path: "skills-cli",
193
+ path: "builtin-copy",
126
194
  global,
127
- bundledVersion,
195
+ binaryVersion,
128
196
  locations: rows,
129
- detail: "installed via the skills CLI (canonical ~/.agents + detected agent dirs)",
197
+ detail: "skills CLI unavailable used a built-in copy (install `skills` to cover other agents)",
130
198
  },
131
199
  };
132
- }
133
- const rows = locations.map((loc) => {
134
- deps.copyInto(skillDir, loc.dir);
135
- return {
136
- label: loc.label,
137
- dir: loc.dir,
138
- installedVersion: installedSkillVersion(loc.dir),
139
- status: "written",
140
- };
141
200
  });
142
- return {
143
- exitCode: ExitCode.Ok,
144
- data: {
145
- mode: "install",
146
- path: "builtin-copy",
147
- global,
148
- bundledVersion,
149
- locations: rows,
150
- detail: "skills CLI unavailable — used a built-in copy (install `skills` to cover other agents)",
151
- },
152
- };
153
201
  }
154
202
  /** Human-readable rendering of the result. */
155
203
  function render(data) {
156
204
  const lines = [];
157
- const ver = data.bundledVersion ?? "unstamped";
158
205
  if (data.mode === "check") {
159
- lines.push(`bundled skill version: ${ver}`);
206
+ lines.push(`binary version: ${data.binaryVersion}`);
160
207
  for (const r of data.locations) {
161
208
  const iv = r.installedVersion ?? "(not installed)";
162
209
  lines.push(` ${r.label}: ${iv} — ${r.status}`);
@@ -182,15 +229,46 @@ export function registerInstallSkill(program) {
182
229
  .description("Install the bundled agent skill so coding agents can drive `things` with no " +
183
230
  "out-of-band knowledge. Uses the skills CLI when available (covering every " +
184
231
  "detected agent), otherwise a built-in copy into ~/.agents and ~/.claude. " +
185
- "Re-run any time to update — the skill is replaced wholesale. --check compares " +
186
- "the installed version against the bundled one without writing anything.")
187
- .option("--check", "report installed vs bundled skill version without writing")
232
+ "Re-run any time to update — the skill is replaced wholesale. The copy is " +
233
+ "stamped with this binary's version. --check compares the installed version " +
234
+ "against this binary's version without writing anything.")
235
+ .option("--check", "report installed vs this binary's skill version without writing")
188
236
  .option("--project", "install into the current project (.agents) instead of globally")
189
237
  .option("--json", "emit versioned JSON envelope on stdout")
190
238
  .action((opts) => {
191
239
  const started = Date.now();
240
+ // Universal `--dry-run` (../dry-run.ts): install-skill writes local files
241
+ // (not the Things DB), so it honors the flag with an honest preview — name
242
+ // every location it WOULD write, touch nothing, exit 0. (`--check` remains
243
+ // the version-comparison inspector; --dry-run previews the install itself.)
244
+ if (opts.dryRun === true) {
245
+ const rows = skillLocations(resolveHome()).map((loc) => ({
246
+ label: loc.label,
247
+ dir: loc.dir,
248
+ installedVersion: installedSkillVersion(loc.dir),
249
+ status: "would-write",
250
+ }));
251
+ const data = {
252
+ mode: "install",
253
+ path: "simulated",
254
+ global: opts.project !== true,
255
+ binaryVersion: CLI_VERSION,
256
+ locations: rows,
257
+ detail: `dry run: would install the things-cli agent skill (version ${CLI_VERSION}) — nothing was written`,
258
+ };
259
+ if (opts.json === true) {
260
+ process.stdout.write(`${JSON.stringify(okEnvelope("install-skill", data, meta(started)))}\n`);
261
+ }
262
+ else {
263
+ const lines = [data.detail, "", ...rows.map((r) => ` ${r.label}: ${r.dir}`)];
264
+ process.stdout.write(`${lines.join("\n")}\n`);
265
+ }
266
+ process.exitCode = ExitCode.Ok;
267
+ return;
268
+ }
192
269
  const { data, exitCode } = installSkill(opts, {
193
270
  home: resolveHome(),
271
+ binaryVersion: CLI_VERSION,
194
272
  simulated: simFenceActive(),
195
273
  runSkillsCli: defaultRunSkillsCli,
196
274
  copyInto: defaultCopyInto,
@@ -1 +1 @@
1
- {"version":3,"file":"install-skill.js","sourceRoot":"","sources":["../../../src/cli/commands/install-skill.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install-skill.js","sourceRoot":"","sources":["../../../src/cli/commands/install-skill.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { loadMcpServer } from "../../index.js";
1
+ import { ExitCode, loadMcpServer } from "../../index.js";
2
2
  export function registerMcp(program) {
3
3
  program
4
4
  .command("mcp")
@@ -12,7 +12,22 @@ export function registerMcp(program) {
12
12
  .option("--db <path>", "explicit database path")
13
13
  .option("--allow-disruptive", "permit changes that briefly steal window focus")
14
14
  .option("--allow-very-disruptive", "permit changes that visibly drive the Things UI")
15
+ .option("--scope <ref>", "limit the whole server to one area or project (uuid or unique name): only items within " +
16
+ "it are readable, every change is confined to it, and references outside it return " +
17
+ "not-found. Set at launch by whoever controls this server; no tool can widen it. " +
18
+ "Outranks the THINGS_API_SCOPE environment variable.")
15
19
  .action(async (opts) => {
20
+ // Universal `--dry-run` (../dry-run.ts) means "guarantee nothing
21
+ // changes". `mcp` serves a live surface whose tools make changes on
22
+ // demand, with nothing to plan up front — so there is no honest preview.
23
+ // Refuse loudly rather than launch a server that silently ignores the
24
+ // promise (its controls are --scope and the disruption ceilings instead).
25
+ if (opts.dryRun === true) {
26
+ process.stderr.write("error: things mcp does not support --dry-run — it serves a live surface whose tools " +
27
+ "make changes on request; scope it with --scope to confine what it can touch\n");
28
+ process.exitCode = ExitCode.Usage;
29
+ return;
30
+ }
16
31
  // LAZY imports: the MCP SDK + zod load only when `things mcp` actually
17
32
  // runs. Every other CLI command must work in environments that ship a
18
33
  // minimal dependency set (the guest e2e bundle carries only commander).
@@ -33,9 +48,14 @@ export function registerMcp(program) {
33
48
  const server = createThingsMcpServer({
34
49
  ...(opts.db !== undefined && { dbPath: opts.db }),
35
50
  ...(maxDisruption !== undefined && { maxDisruption }),
51
+ ...(opts.scope !== undefined && { scope: opts.scope }),
36
52
  });
37
53
  const transport = new StdioServerTransport();
38
54
  await server.connect(transport);
55
+ // Log the active scope loudly at startup so the jail is never silently on.
56
+ if (opts.scope !== undefined) {
57
+ process.stderr.write(`things-api MCP server scoped to "${opts.scope}"\n`);
58
+ }
39
59
  process.stderr.write("things-api MCP server listening on stdio\n");
40
60
  // The transport keeps the process alive; exit cleanly when it closes.
41
61
  // oxlint-disable-next-line unicorn/prefer-add-event-listener -- MCP SDK Transport exposes an onclose property, not an EventTarget
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/cli/commands/mcp.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAuB,MAAM,gBAAgB,CAAC;AAEpE,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CACV,sFAAsF;QACpF,4EAA4E;QAC5E,iFAAiF;QACjF,qFAAqF;QACrF,oEAAoE;QACpE,gFAAgF;QAChF,0FAA0F,CAC7F;SACA,MAAM,CAAC,aAAa,EAAE,wBAAwB,CAAC;SAC/C,MAAM,CAAC,oBAAoB,EAAE,gDAAgD,CAAC;SAC9E,MAAM,CAAC,yBAAyB,EAAE,iDAAiD,CAAC;SACpF,MAAM,CACL,KAAK,EAAE,IAA+E,EAAE,EAAE;QACxF,uEAAuE;QACvE,sEAAsE;QACtE,wEAAwE;QACxE,kEAAkE;QAClE,wDAAwD;QACxD,MAAM,CAAC,EAAE,qBAAqB,EAAE,EAAE,EAAE,oBAAoB,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC9E,aAAa,EAAE;YACf,MAAM,CAAC,2CAA2C,CAAC;SACpD,CAAC,CAAC;QACH,sEAAsE;QACtE,uEAAuE;QACvE,6EAA6E;QAC7E,MAAM,aAAa,GAA+B,IAAI,CAAC,mBAAmB;YACxE,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,IAAI,CAAC,eAAe;gBACpB,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,SAAS,CAAC;QAChB,MAAM,MAAM,GAAG,qBAAqB,CAAC;YACnC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YACjD,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,EAAE,aAAa,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,sEAAsE;QACtE,kIAAkI;QAClI,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC,CACF,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/cli/commands/mcp.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAuB,MAAM,gBAAgB,CAAC;AAE9E,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CACV,sFAAsF;QACpF,4EAA4E;QAC5E,iFAAiF;QACjF,qFAAqF;QACrF,oEAAoE;QACpE,gFAAgF;QAChF,0FAA0F,CAC7F;SACA,MAAM,CAAC,aAAa,EAAE,wBAAwB,CAAC;SAC/C,MAAM,CAAC,oBAAoB,EAAE,gDAAgD,CAAC;SAC9E,MAAM,CAAC,yBAAyB,EAAE,iDAAiD,CAAC;SACpF,MAAM,CACL,eAAe,EACf,yFAAyF;QACvF,oFAAoF;QACpF,kFAAkF;QAClF,qDAAqD,CACxD;SACA,MAAM,CACL,KAAK,EAAE,IAMN,EAAE,EAAE;QACH,iEAAiE;QACjE,oEAAoE;QACpE,yEAAyE;QACzE,sEAAsE;QACtE,0EAA0E;QAC1E,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,sFAAsF;gBACpF,+EAA+E,CAClF,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC;YAClC,OAAO;QACT,CAAC;QACD,uEAAuE;QACvE,sEAAsE;QACtE,wEAAwE;QACxE,kEAAkE;QAClE,wDAAwD;QACxD,MAAM,CAAC,EAAE,qBAAqB,EAAE,EAAE,EAAE,oBAAoB,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC9E,aAAa,EAAE;YACf,MAAM,CAAC,2CAA2C,CAAC;SACpD,CAAC,CAAC;QACH,sEAAsE;QACtE,uEAAuE;QACvE,6EAA6E;QAC7E,MAAM,aAAa,GAA+B,IAAI,CAAC,mBAAmB;YACxE,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,IAAI,CAAC,eAAe;gBACpB,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,SAAS,CAAC;QAChB,MAAM,MAAM,GAAG,qBAAqB,CAAC;YACnC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YACjD,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,EAAE,aAAa,EAAE,CAAC;YACrD,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;SACvD,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,2EAA2E;QAC3E,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,sEAAsE;QACtE,kIAAkI;QAClI,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC,CACF,CAAC;AACN,CAAC"}
@@ -29,6 +29,7 @@ export type ProjectShowActionOpts = ProjectShowOpts & TagFlags & {
29
29
  json?: boolean;
30
30
  db?: string;
31
31
  all?: boolean;
32
+ full?: boolean;
32
33
  /** Content scope: keep only child to-dos whose own deadline is overdue. */
33
34
  overdue?: boolean;
34
35
  };