grounder 0.1.0 → 0.3.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 (167) hide show
  1. package/README.md +115 -28
  2. package/dist/agents/claude.d.ts +15 -0
  3. package/dist/agents/claude.d.ts.map +1 -1
  4. package/dist/agents/claude.js +256 -11
  5. package/dist/agents/claude.js.map +1 -1
  6. package/dist/agents/cursor-hook-input.d.ts +14 -0
  7. package/dist/agents/cursor-hook-input.d.ts.map +1 -0
  8. package/dist/agents/cursor-hook-input.js +80 -0
  9. package/dist/agents/cursor-hook-input.js.map +1 -0
  10. package/dist/agents/cursor.d.ts +11 -0
  11. package/dist/agents/cursor.d.ts.map +1 -1
  12. package/dist/agents/cursor.js +206 -11
  13. package/dist/agents/cursor.js.map +1 -1
  14. package/dist/agents/hook-runtime.d.ts +152 -0
  15. package/dist/agents/hook-runtime.d.ts.map +1 -0
  16. package/dist/agents/hook-runtime.js +401 -0
  17. package/dist/agents/hook-runtime.js.map +1 -0
  18. package/dist/agents/index.d.ts +18 -0
  19. package/dist/agents/index.d.ts.map +1 -1
  20. package/dist/agents/index.js +27 -4
  21. package/dist/agents/index.js.map +1 -1
  22. package/dist/agents/install-command.d.ts +37 -0
  23. package/dist/agents/install-command.d.ts.map +1 -0
  24. package/dist/agents/install-command.js +65 -0
  25. package/dist/agents/install-command.js.map +1 -0
  26. package/dist/agents/types.d.ts +23 -1
  27. package/dist/agents/types.d.ts.map +1 -1
  28. package/dist/cli.js +62 -53
  29. package/dist/cli.js.map +1 -1
  30. package/dist/commands/apply-agent-installs.d.ts +34 -0
  31. package/dist/commands/apply-agent-installs.d.ts.map +1 -0
  32. package/dist/commands/apply-agent-installs.js +137 -0
  33. package/dist/commands/apply-agent-installs.js.map +1 -0
  34. package/dist/commands/doctor.d.ts.map +1 -1
  35. package/dist/commands/doctor.js +231 -14
  36. package/dist/commands/doctor.js.map +1 -1
  37. package/dist/commands/handoff/list.d.ts +9 -0
  38. package/dist/commands/handoff/list.d.ts.map +1 -1
  39. package/dist/commands/handoff/list.js +20 -4
  40. package/dist/commands/handoff/list.js.map +1 -1
  41. package/dist/commands/handoff/peek.d.ts +41 -0
  42. package/dist/commands/handoff/peek.d.ts.map +1 -0
  43. package/dist/commands/handoff/peek.js +161 -0
  44. package/dist/commands/handoff/peek.js.map +1 -0
  45. package/dist/commands/handoff.d.ts.map +1 -1
  46. package/dist/commands/handoff.js +5 -0
  47. package/dist/commands/handoff.js.map +1 -1
  48. package/dist/commands/migrate.d.ts +23 -0
  49. package/dist/commands/migrate.d.ts.map +1 -0
  50. package/dist/commands/migrate.js +104 -0
  51. package/dist/commands/migrate.js.map +1 -0
  52. package/dist/commands/note.d.ts.map +1 -1
  53. package/dist/commands/note.js +5 -0
  54. package/dist/commands/note.js.map +1 -1
  55. package/dist/commands/package-version-notice.d.ts +18 -0
  56. package/dist/commands/package-version-notice.d.ts.map +1 -0
  57. package/dist/commands/package-version-notice.js +39 -0
  58. package/dist/commands/package-version-notice.js.map +1 -0
  59. package/dist/commands/path/logs.d.ts +1 -1
  60. package/dist/commands/path/logs.d.ts.map +1 -1
  61. package/dist/commands/path/logs.js +6 -1
  62. package/dist/commands/path/logs.js.map +1 -1
  63. package/dist/commands/path/notes.d.ts +1 -1
  64. package/dist/commands/path/notes.d.ts.map +1 -1
  65. package/dist/commands/path/notes.js +6 -1
  66. package/dist/commands/path/notes.js.map +1 -1
  67. package/dist/commands/path/plans.d.ts +7 -0
  68. package/dist/commands/path/plans.d.ts.map +1 -0
  69. package/dist/commands/path/plans.js +22 -0
  70. package/dist/commands/path/plans.js.map +1 -0
  71. package/dist/commands/plan/list.d.ts +23 -0
  72. package/dist/commands/plan/list.d.ts.map +1 -0
  73. package/dist/commands/plan/list.js +69 -0
  74. package/dist/commands/plan/list.js.map +1 -0
  75. package/dist/commands/plan.d.ts +34 -0
  76. package/dist/commands/plan.d.ts.map +1 -0
  77. package/dist/commands/plan.js +121 -0
  78. package/dist/commands/plan.js.map +1 -0
  79. package/dist/commands/repo/init.d.ts.map +1 -1
  80. package/dist/commands/repo/init.js +12 -1
  81. package/dist/commands/repo/init.js.map +1 -1
  82. package/dist/commands/status.d.ts +1 -1
  83. package/dist/commands/status.d.ts.map +1 -1
  84. package/dist/commands/status.js +52 -9
  85. package/dist/commands/status.js.map +1 -1
  86. package/dist/commands/upgrade-banner.d.ts +9 -0
  87. package/dist/commands/upgrade-banner.d.ts.map +1 -0
  88. package/dist/commands/upgrade-banner.js +27 -0
  89. package/dist/commands/upgrade-banner.js.map +1 -0
  90. package/dist/commands/vault/init.d.ts +2 -0
  91. package/dist/commands/vault/init.d.ts.map +1 -1
  92. package/dist/commands/vault/init.js +28 -11
  93. package/dist/commands/vault/init.js.map +1 -1
  94. package/dist/connector/repo.d.ts +2 -0
  95. package/dist/connector/repo.d.ts.map +1 -1
  96. package/dist/connector/repo.js +12 -1
  97. package/dist/connector/repo.js.map +1 -1
  98. package/dist/connector/state.d.ts +95 -0
  99. package/dist/connector/state.d.ts.map +1 -0
  100. package/dist/connector/state.js +189 -0
  101. package/dist/connector/state.js.map +1 -0
  102. package/dist/connector/unsupported-schema.d.ts +9 -0
  103. package/dist/connector/unsupported-schema.d.ts.map +1 -0
  104. package/dist/connector/unsupported-schema.js +14 -0
  105. package/dist/connector/unsupported-schema.js.map +1 -0
  106. package/dist/connector/vault.d.ts +2 -0
  107. package/dist/connector/vault.d.ts.map +1 -1
  108. package/dist/connector/vault.js +6 -1
  109. package/dist/connector/vault.js.map +1 -1
  110. package/dist/help.d.ts +45 -0
  111. package/dist/help.d.ts.map +1 -0
  112. package/dist/help.js +355 -0
  113. package/dist/help.js.map +1 -0
  114. package/dist/util/frontmatter.d.ts +11 -0
  115. package/dist/util/frontmatter.d.ts.map +1 -0
  116. package/dist/util/frontmatter.js +69 -0
  117. package/dist/util/frontmatter.js.map +1 -0
  118. package/dist/util/fs.d.ts +6 -0
  119. package/dist/util/fs.d.ts.map +1 -1
  120. package/dist/util/fs.js +15 -1
  121. package/dist/util/fs.js.map +1 -1
  122. package/dist/util/hash.d.ts +3 -0
  123. package/dist/util/hash.d.ts.map +1 -0
  124. package/dist/util/hash.js +6 -0
  125. package/dist/util/hash.js.map +1 -0
  126. package/dist/util/merge-json.d.ts +15 -0
  127. package/dist/util/merge-json.d.ts.map +1 -0
  128. package/dist/util/merge-json.js +40 -0
  129. package/dist/util/merge-json.js.map +1 -0
  130. package/dist/util/path.d.ts +10 -0
  131. package/dist/util/path.d.ts.map +1 -1
  132. package/dist/util/path.js +31 -0
  133. package/dist/util/path.js.map +1 -1
  134. package/dist/util/plan-name.d.ts +10 -0
  135. package/dist/util/plan-name.d.ts.map +1 -0
  136. package/dist/util/plan-name.js +18 -0
  137. package/dist/util/plan-name.js.map +1 -0
  138. package/dist/util/semver.d.ts +10 -0
  139. package/dist/util/semver.d.ts.map +1 -0
  140. package/dist/util/semver.js +40 -0
  141. package/dist/util/semver.js.map +1 -0
  142. package/dist/vault/find-usable-handoff.d.ts +19 -0
  143. package/dist/vault/find-usable-handoff.d.ts.map +1 -0
  144. package/dist/vault/find-usable-handoff.js +28 -0
  145. package/dist/vault/find-usable-handoff.js.map +1 -0
  146. package/dist/vault/layout.d.ts +2 -0
  147. package/dist/vault/layout.d.ts.map +1 -1
  148. package/dist/vault/layout.js +4 -0
  149. package/dist/vault/layout.js.map +1 -1
  150. package/dist/vault/list-plans.d.ts +11 -0
  151. package/dist/vault/list-plans.d.ts.map +1 -0
  152. package/dist/vault/list-plans.js +40 -0
  153. package/dist/vault/list-plans.js.map +1 -0
  154. package/dist/vault/write-plan.d.ts +28 -0
  155. package/dist/vault/write-plan.d.ts.map +1 -0
  156. package/dist/vault/write-plan.js +61 -0
  157. package/dist/vault/write-plan.js.map +1 -0
  158. package/package.json +1 -1
  159. package/templates/agents/claude/commands/grounder-note.md +1 -1
  160. package/templates/agents/claude/commands/grounder-plan.md +65 -0
  161. package/templates/agents/claude/commands/grounder-task-handoff.md +3 -3
  162. package/templates/agents/claude/commands/grounder-task.md +4 -4
  163. package/templates/agents/cursor/commands/grounder-note.md +1 -1
  164. package/templates/agents/cursor/commands/grounder-plan.md +65 -0
  165. package/templates/agents/cursor/commands/grounder-task-handoff.md +3 -3
  166. package/templates/agents/cursor/commands/grounder-task.md +4 -4
  167. package/templates/vault/plan.md +16 -0
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Home-local runtime shared by session hooks *and* slash commands (originally
3
+ * "Issue 2 — replace `npx grounder` in session hooks"; later extended to cover
4
+ * slash-command templates too, since they had the identical problem).
5
+ *
6
+ * ## Why
7
+ * Both surfaces used to shell out via `npx grounder …`. `npx <pkg>` (no
8
+ * version specifier) matches against whatever `grounder` version exists in
9
+ * the *current project's own dependencies*; only when the project doesn't
10
+ * declare `grounder` as a dependency does it fall back to fetching
11
+ * `grounder@latest` from the registry. Session hooks and slash commands both
12
+ * run from arbitrary linked projects, which normally have no reason to depend
13
+ * on `grounder` themselves, so contributors (and anyone ahead of the last
14
+ * publish, or deliberately pinned to an older version) get the wrong binary.
15
+ * Global `pnpm link` / `pnpm add -g` does not change this fallback — see
16
+ * [npm/cli#9244](https://github.com/npm/cli/issues/9244).
17
+ *
18
+ * ## Design
19
+ * On `vault init`, materialize this package's `dist/` at
20
+ * `~/.grounder/runtime/dist/` and point both host hook configs *and* the
21
+ * commands copied into `~/.cursor/commands/` / `~/.claude/commands/` at:
22
+ * `process.execPath` + `~/.grounder/runtime/dist/cli.js` + `<subcommand> …`
23
+ * No global install and no registry fetch at invocation time, for either
24
+ * surface. This mirrors how Corepack (packageManager shims) and Husky/lint-staged
25
+ * (moved off bare `npx` for the same reason, see the strapi/strapi#27006 fix)
26
+ * solve the identical "ambient resolution isn't stable" problem.
27
+ *
28
+ * How it's materialized depends on where grounder is running from:
29
+ * - **Durable source** (monorepo checkout, global install, linked devDependency) →
30
+ * **symlink** `dist/` straight to the source. `pnpm build` / upgrading the
31
+ * global install overwrites that same path in place, so hooks and commands
32
+ * pick up new code immediately — no re-run of `vault init` ever needed.
33
+ * - **Ephemeral source** (bare `npx grounder …`, no install — each invocation
34
+ * resolves to an immutable, version-keyed npx cache dir that can be evicted
35
+ * or swapped out from under a symlink) → **copy** `dist/`. Re-run
36
+ * `grounder vault init <vault>` after upgrading to refresh; this is an
37
+ * inherent limitation of using npx with no install for something that must
38
+ * persist, not something we can engineer around.
39
+ *
40
+ * This mirrors husky/pre-commit hook shims: staying current is an explicit,
41
+ * idempotent step (never silent self-healing inside a hook itself — session
42
+ * hooks must stay fast and side-effect-free), and the step is a no-op unless
43
+ * something has actually changed.
44
+ *
45
+ * ## REVERT
46
+ * To restore the previous `npx grounder …` behavior for hooks and/or commands:
47
+ * 1. Delete this file and its tests (`test/agents/hook-runtime.test.ts`).
48
+ * 2. In `cursor.ts` / `claude.ts`, set `*_PEEK_HOOK_COMMAND` back to
49
+ * `"npx grounder handoff peek"` and `installCommand` back to a plain
50
+ * `copyFile` (drop the `{{GROUNDER_CLI}}` template substitution), dropping
51
+ * calls to {@link installHookRuntime} / {@link peekHookCommand} /
52
+ * {@link runtimeInvocation} / {@link extractRuntimeNodePath} /
53
+ * {@link findRuntimeNodePathsInText} /
54
+ * {@link collectGrounderPeekHookCommands} / {@link hookFileGrounderPeekCommands} /
55
+ * {@link isGrounderPeekHookCommand} / {@link isHookRuntimeStale}.
56
+ * 3. Remove runtime paths from `expectedHookArtifacts` and docs that mention
57
+ * `~/.grounder/runtime`, and revert templates' `{{GROUNDER_CLI}}` back to
58
+ * literal `npx grounder`.
59
+ */
60
+ import { cp, lstat, mkdir, readFile, realpath, rename, rm, symlink, writeFile, } from "node:fs/promises";
61
+ import os from "node:os";
62
+ import path from "node:path";
63
+ import { fileURLToPath } from "node:url";
64
+ import { resolveHomeDir } from "../connector/home.js";
65
+ import { fileExists } from "../util/fs.js";
66
+ /** Package root (`packages/grounder`) when running from `dist/agents/`. */
67
+ const defaultPackageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
68
+ /** `~/.grounder/runtime` — private materialization of the CLI used only by session hooks. */
69
+ export function grounderRuntimeDir(homeDir) {
70
+ return path.join(resolveHomeDir(homeDir), ".grounder", "runtime");
71
+ }
72
+ /** Absolute path to the materialized CLI entry (`…/runtime/dist/cli.js`). */
73
+ export function runtimeCliPath(homeDir) {
74
+ return path.join(grounderRuntimeDir(homeDir), "dist", "cli.js");
75
+ }
76
+ export function runtimeManifestPath(homeDir) {
77
+ return path.join(grounderRuntimeDir(homeDir), "manifest.json");
78
+ }
79
+ /**
80
+ * POSIX-safe single-quote for embedding paths in hook `command` strings
81
+ * (Cursor/Claude run hooks via a shell on macOS/Linux and Git Bash on Windows).
82
+ */
83
+ export function shellQuote(value) {
84
+ return `'${value.replace(/'/g, `'\\''`)}'`;
85
+ }
86
+ /**
87
+ * Reverse one {@link shellQuote} token starting at `start`.
88
+ * Handles the close/escape/reopen sequence (`'\''`) for embedded quotes.
89
+ */
90
+ function parseShellQuoted(input, start) {
91
+ if (input[start] !== "'") {
92
+ return null;
93
+ }
94
+ let i = start + 1;
95
+ let value = "";
96
+ while (i < input.length) {
97
+ if (input[i] === "'") {
98
+ // shellQuote escape: close quote, literal `'`, reopen — characters `'\''`
99
+ if (input[i + 1] === "\\" && input[i + 2] === "'" && input[i + 3] === "'") {
100
+ value += "'";
101
+ i += 4;
102
+ continue;
103
+ }
104
+ return { value, next: i + 1 };
105
+ }
106
+ value += input[i];
107
+ i += 1;
108
+ }
109
+ return null;
110
+ }
111
+ function isAbsolutePath(p) {
112
+ return path.posix.isAbsolute(p) || path.win32.isAbsolute(p);
113
+ }
114
+ /**
115
+ * Extract the baked Node interpreter path from a home-runtime invocation
116
+ * string (`'<abs node>' '<abs …/runtime/dist/cli.js>' …`).
117
+ *
118
+ * Returns `null` when the string is not that exact shape — including legacy
119
+ * `npx grounder …` entries, which have no absolute interpreter to validate.
120
+ */
121
+ export function extractRuntimeNodePath(command) {
122
+ if (typeof command !== "string") {
123
+ return null;
124
+ }
125
+ const trimmed = command.trim();
126
+ const first = parseShellQuoted(trimmed, 0);
127
+ if (!first || !isAbsolutePath(first.value)) {
128
+ return null;
129
+ }
130
+ let i = first.next;
131
+ if (trimmed[i] !== " ") {
132
+ return null;
133
+ }
134
+ while (trimmed[i] === " ") {
135
+ i += 1;
136
+ }
137
+ const second = parseShellQuoted(trimmed, i);
138
+ if (!second) {
139
+ return null;
140
+ }
141
+ const cliNormalized = second.value.replace(/\\/g, "/");
142
+ if (!cliNormalized.includes("/.grounder/runtime/dist/cli.js")) {
143
+ return null;
144
+ }
145
+ return first.value;
146
+ }
147
+ /**
148
+ * Find every baked Node interpreter path embedded in free-form text (slash-command
149
+ * markdown, etc.). Scans for the same `'<abs node>' '<abs …/cli.js>'` shape as
150
+ * {@link extractRuntimeNodePath}, including mid-line / backtick-wrapped uses.
151
+ */
152
+ export function findRuntimeNodePathsInText(text) {
153
+ const found = [];
154
+ const seen = new Set();
155
+ for (let i = 0; i < text.length; i++) {
156
+ if (text[i] !== "'") {
157
+ continue;
158
+ }
159
+ const nodePath = extractRuntimeNodePath(text.slice(i));
160
+ if (nodePath !== null && !seen.has(nodePath)) {
161
+ seen.add(nodePath);
162
+ found.push(nodePath);
163
+ }
164
+ }
165
+ return found;
166
+ }
167
+ /**
168
+ * Quoted `<node> <runtime cli.js>` prefix, shared by every home-runtime
169
+ * invocation (session hooks and slash-command templates alike). Append
170
+ * subcommand args to build a full command string.
171
+ */
172
+ export function runtimeInvocation(homeDir) {
173
+ return `${shellQuote(process.execPath)} ${shellQuote(runtimeCliPath(homeDir))}`;
174
+ }
175
+ /**
176
+ * Build the sessionStart / SessionStart hook command for the home runtime.
177
+ *
178
+ * @param homeDir - Override home (tests / `GROUNDER_HOME`)
179
+ * @param extraArgs - Extra CLI args after `handoff peek` (e.g. `--json` for Cursor)
180
+ */
181
+ export function peekHookCommand(homeDir, extraArgs = []) {
182
+ return [runtimeInvocation(homeDir), "handoff", "peek", ...extraArgs].join(" ");
183
+ }
184
+ /**
185
+ * True when `command` is Grounder's peek hook — current home-runtime form or
186
+ * legacy `npx grounder handoff peek` (with optional trailing flags).
187
+ * Used so upgrades replace the old entry instead of appending a duplicate.
188
+ */
189
+ export function isGrounderPeekHookCommand(command) {
190
+ if (typeof command !== "string") {
191
+ return false;
192
+ }
193
+ const trimmed = command.trim();
194
+ if (/^npx\s+grounder\s+handoff\s+peek(?:\s|$)/.test(trimmed)) {
195
+ return true;
196
+ }
197
+ // Normalize separators so Windows absolute paths still match.
198
+ const normalized = trimmed.replace(/\\/g, "/");
199
+ return (normalized.includes("/.grounder/runtime/dist/cli.js") && /\bhandoff\s+peek\b/.test(normalized));
200
+ }
201
+ /** Collect Grounder peek hook `command` strings nested anywhere in parsed JSON. */
202
+ export function collectGrounderPeekHookCommands(value) {
203
+ const out = [];
204
+ const walk = (v) => {
205
+ if (Array.isArray(v)) {
206
+ for (const item of v) {
207
+ walk(item);
208
+ }
209
+ return;
210
+ }
211
+ if (v && typeof v === "object") {
212
+ const obj = v;
213
+ if (typeof obj.command === "string" && isGrounderPeekHookCommand(obj.command)) {
214
+ out.push(obj.command);
215
+ }
216
+ for (const child of Object.values(obj)) {
217
+ walk(child);
218
+ }
219
+ }
220
+ };
221
+ walk(value);
222
+ return out;
223
+ }
224
+ /** True when any nested `command` field in parsed JSON is Grounder's peek hook. */
225
+ export function jsonContainsGrounderPeekCommand(value) {
226
+ return collectGrounderPeekHookCommands(value).length > 0;
227
+ }
228
+ /** Grounder peek hook command strings in a hooks/settings JSON file (empty if absent/unreadable). */
229
+ export async function hookFileGrounderPeekCommands(filePath) {
230
+ try {
231
+ if (!(await fileExists(filePath))) {
232
+ return [];
233
+ }
234
+ const parsed = JSON.parse(await readFile(filePath, "utf8"));
235
+ return collectGrounderPeekHookCommands(parsed);
236
+ }
237
+ catch {
238
+ return [];
239
+ }
240
+ }
241
+ /** True when a hooks/settings JSON file contains Grounder's peek hook entry. */
242
+ export async function hookFileHasGrounderEntry(filePath) {
243
+ return (await hookFileGrounderPeekCommands(filePath)).length > 0;
244
+ }
245
+ /**
246
+ * Best-effort: is `root` inside a throwaway cache (npx / pnpm dlx), where
247
+ * content can be evicted or swapped for a *different* version at any time?
248
+ * Those sources can't be symlinked durably — copy instead.
249
+ */
250
+ function isEphemeralSource(root) {
251
+ const normalized = `${path.resolve(root).replace(/\\/g, "/")}/`;
252
+ const tmp = `${path.resolve(os.tmpdir()).replace(/\\/g, "/")}/`;
253
+ if (normalized.startsWith(tmp)) {
254
+ return true;
255
+ }
256
+ return /\/(_npx|\.npm\/_npx|\.pnpm-dlx-|pnpm-dlx-)[^/]*\//.test(normalized);
257
+ }
258
+ async function readPackageVersion(packageRoot) {
259
+ try {
260
+ const raw = JSON.parse(await readFile(path.join(packageRoot, "package.json"), "utf8"));
261
+ return typeof raw.version === "string" ? raw.version : "unknown";
262
+ }
263
+ catch {
264
+ return "unknown";
265
+ }
266
+ }
267
+ async function readRuntimeManifest(homeDir) {
268
+ try {
269
+ const raw = JSON.parse(await readFile(runtimeManifestPath(homeDir), "utf8"));
270
+ if (typeof raw.version !== "string" || (raw.mode !== "symlink" && raw.mode !== "copy")) {
271
+ return null;
272
+ }
273
+ return {
274
+ mode: raw.mode,
275
+ version: raw.version,
276
+ sourcePackageRoot: typeof raw.sourcePackageRoot === "string" ? raw.sourcePackageRoot : "",
277
+ installedAt: typeof raw.installedAt === "string" ? raw.installedAt : "",
278
+ };
279
+ }
280
+ catch {
281
+ return null;
282
+ }
283
+ }
284
+ /** Realpath of `destDist` if it's currently a directory symlink, else `null`. */
285
+ async function currentSymlinkTarget(destDist) {
286
+ try {
287
+ const info = await lstat(destDist);
288
+ if (!info.isSymbolicLink()) {
289
+ return null;
290
+ }
291
+ return await realpath(destDist);
292
+ }
293
+ catch {
294
+ return null;
295
+ }
296
+ }
297
+ /**
298
+ * True when the materialized runtime is missing or out of date for the given
299
+ * source package:
300
+ * - **Symlink mode** (durable source): stale iff `dist/` isn't currently a
301
+ * symlink resolving to this source's `dist/` (cheap `realpath` compare — no
302
+ * staleness window, since a matching symlink is *always* current).
303
+ * - **Copy mode** (ephemeral `npx` source): stale iff the manifest is
304
+ * missing/unreadable or its recorded version differs from this source's.
305
+ *
306
+ * @param packageRoot - Source package root to compare against (defaults to the
307
+ * currently running package — override only in tests)
308
+ */
309
+ export async function isHookRuntimeStale(homeDir, packageRoot = defaultPackageRoot) {
310
+ if (!(await fileExists(runtimeCliPath(homeDir)))) {
311
+ return true;
312
+ }
313
+ const destDist = path.join(grounderRuntimeDir(homeDir), "dist");
314
+ if (isEphemeralSource(packageRoot)) {
315
+ const manifest = await readRuntimeManifest(homeDir);
316
+ if (manifest?.mode !== "copy") {
317
+ return true;
318
+ }
319
+ return manifest.version !== (await readPackageVersion(packageRoot));
320
+ }
321
+ const sourceDistDir = path.join(packageRoot, "dist");
322
+ const resolvedSource = await realpath(sourceDistDir).catch(() => path.resolve(sourceDistDir));
323
+ const target = await currentSymlinkTarget(destDist);
324
+ return target !== resolvedSource;
325
+ }
326
+ /**
327
+ * Materialize this package's `dist/` at `~/.grounder/runtime/dist/` — symlinked
328
+ * when the source is durable, copied when it's an ephemeral `npx` cache — and
329
+ * write a manifest recording how.
330
+ *
331
+ * Callers should gate on {@link isHookRuntimeStale} (or `force`) before calling —
332
+ * this always replaces whatever is currently at the destination, staging the
333
+ * new materialization first so a failed symlink/cp leaves the live runtime intact.
334
+ *
335
+ * @param options.packageRoot - Source package root to materialize (defaults to
336
+ * the currently running package — override only in tests)
337
+ */
338
+ export async function installHookRuntime(options) {
339
+ const packageRoot = options.packageRoot ?? defaultPackageRoot;
340
+ const sourceDistDir = path.join(packageRoot, "dist");
341
+ const runtimeDir = grounderRuntimeDir(options.homeDir);
342
+ const destDist = path.join(runtimeDir, "dist");
343
+ const cliPath = runtimeCliPath(options.homeDir);
344
+ const existed = await fileExists(cliPath);
345
+ if (!(await fileExists(path.join(sourceDistDir, "cli.js")))) {
346
+ throw new Error(`Grounder dist missing at ${sourceDistDir}. Run \`pnpm build\` (or install a published package) before vault init.`);
347
+ }
348
+ await mkdir(runtimeDir, { recursive: true });
349
+ // Stage into a sibling path first, then swap. If symlink/cp fails, the live
350
+ // `dist/` (and any hooks pointing at it) stay intact.
351
+ const stagingDist = `${destDist}.staging`;
352
+ const backupDist = `${destDist}.bak`;
353
+ await rm(stagingDist, { recursive: true, force: true });
354
+ await rm(backupDist, { recursive: true, force: true });
355
+ const mode = isEphemeralSource(packageRoot) ? "copy" : "symlink";
356
+ try {
357
+ if (mode === "symlink") {
358
+ const resolvedSource = await realpath(sourceDistDir).catch(() => path.resolve(sourceDistDir));
359
+ await symlink(resolvedSource, stagingDist, process.platform === "win32" ? "junction" : "dir");
360
+ }
361
+ else {
362
+ await cp(sourceDistDir, stagingDist, { recursive: true, force: true });
363
+ }
364
+ // Move the live dest aside (if any), then promote staging. On promote
365
+ // failure, restore the backup so hooks keep a working cli.js.
366
+ try {
367
+ await rename(destDist, backupDist);
368
+ }
369
+ catch (error) {
370
+ if (error.code !== "ENOENT") {
371
+ throw error;
372
+ }
373
+ }
374
+ try {
375
+ await rename(stagingDist, destDist);
376
+ }
377
+ catch (error) {
378
+ try {
379
+ await rename(backupDist, destDist);
380
+ }
381
+ catch {
382
+ // Best-effort restore; rethrow the promote failure below.
383
+ }
384
+ throw error;
385
+ }
386
+ await rm(backupDist, { recursive: true, force: true });
387
+ }
388
+ catch (error) {
389
+ await rm(stagingDist, { recursive: true, force: true }).catch(() => undefined);
390
+ throw error;
391
+ }
392
+ const manifest = {
393
+ mode,
394
+ version: await readPackageVersion(packageRoot),
395
+ sourcePackageRoot: packageRoot,
396
+ installedAt: new Date().toISOString(),
397
+ };
398
+ await writeFile(runtimeManifestPath(options.homeDir), `${JSON.stringify(manifest, null, 2)}\n`);
399
+ return { cliPath, status: existed ? "overwritten" : "created", mode };
400
+ }
401
+ //# sourceMappingURL=hook-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-runtime.js","sourceRoot":"","sources":["../../src/agents/hook-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,EACL,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,EAAE,EACF,OAAO,EACP,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,2EAA2E;AAC3E,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAU/F,6FAA6F;AAC7F,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,OAAO,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AACpE,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,KAAa,EAAE,KAAa;IACpD,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAClB,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,0EAA0E;YAC1E,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC1E,KAAK,IAAI,GAAG,CAAC;gBACb,CAAC,IAAI,CAAC,CAAC;gBACP,SAAS;YACX,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,CAAC;QACD,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;IACnB,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QAC1B,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gCAAgC,CAAC,EAAE,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACpB,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACnB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;AAClF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAgB,EAAE,YAA+B,EAAE;IACjF,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,0CAA0C,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,8DAA8D;IAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,CACL,UAAU,CAAC,QAAQ,CAAC,gCAAgC,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,CAC/F,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,+BAA+B,CAAC,KAAc;IAC5D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,CAAC,CAAU,EAAQ,EAAE;QAChC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,CAA4B,CAAC;YACzC,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,yBAAyB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC9E,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACxB,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,CAAC,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,KAAK,CAAC,CAAC;IACZ,OAAO,GAAG,CAAC;AACb,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,+BAA+B,CAAC,KAAc;IAC5D,OAAO,+BAA+B,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3D,CAAC;AAED,qGAAqG;AACrG,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,QAAgB;IACjE,IAAI,CAAC;QACH,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YAClC,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACrE,OAAO,+BAA+B,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,QAAgB;IAC7D,OAAO,CAAC,MAAM,4BAA4B,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,UAAU,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC;IAChE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC;IAChE,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,mDAAmD,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC9E,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,WAAmB;IACnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAEpF,CAAC;QACF,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,OAAgB;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAE1E,CAAC;QACF,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,CAAC;YACvF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,iBAAiB,EAAE,OAAO,GAAG,CAAC,iBAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE;YACzF,WAAW,EAAE,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;SACxE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,oBAAoB,CAAC,QAAgB;IAClD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAgB,EAChB,cAAsB,kBAAkB;IAExC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAChE,IAAI,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,QAAQ,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,QAAQ,CAAC,OAAO,KAAK,CAAC,MAAM,kBAAkB,CAAC,WAAW,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IAC9F,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACpD,OAAO,MAAM,KAAK,cAAc,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAGxC;IACC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC9D,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;IAE1C,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CACb,4BAA4B,aAAa,0EAA0E,CACpH,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7C,4EAA4E;IAC5E,sDAAsD;IACtD,MAAM,WAAW,GAAG,GAAG,QAAQ,UAAU,CAAC;IAC1C,MAAM,UAAU,GAAG,GAAG,QAAQ,MAAM,CAAC;IACrC,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvD,MAAM,IAAI,GAAuB,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACrF,IAAI,CAAC;QACH,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;YAC9F,MAAM,OAAO,CAAC,cAAc,EAAE,WAAW,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;QAED,sEAAsE;QACtE,8DAA8D;QAC9D,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACrC,CAAC;YAAC,MAAM,CAAC;gBACP,0DAA0D;YAC5D,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC/E,MAAM,KAAK,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAwB;QACpC,IAAI;QACJ,OAAO,EAAE,MAAM,kBAAkB,CAAC,WAAW,CAAC;QAC9C,iBAAiB,EAAE,WAAW;QAC9B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACtC,CAAC;IACF,MAAM,SAAS,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAEhG,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC;AACxE,CAAC"}
@@ -2,10 +2,28 @@ import type { AgentAdapter } from "./types.js";
2
2
  export { claude } from "./claude.js";
3
3
  export { cursor } from "./cursor.js";
4
4
  export type { AgentAdapter, AgentInstallOptions, AgentInstallResult, ArtifactStatus, } from "./types.js";
5
+ /** Every agent adapter this Grounder build knows about (Cursor, Claude, …). */
6
+ export declare const ALL_AGENTS: readonly AgentAdapter[];
5
7
  /**
6
8
  * Resolve which adapters to run:
7
9
  * - If `ids` is provided, return those adapters (throws on unknown id).
8
10
  * - Otherwise, auto-detect by checking isInstalled() for each adapter.
9
11
  */
10
12
  export declare function resolveAgents(ids?: string[]): Promise<AgentAdapter[]>;
13
+ /**
14
+ * Write this agent's install version info into `~/.grounder/state.json` after
15
+ * install. If hooks were installed and the agent supports them, store the hooks
16
+ * version; otherwise leave any existing hooks version as-is.
17
+ *
18
+ * When `advanceCommandsSchema` is false (every command file was left alone
19
+ * because it looked locally edited or from an old install), do not bump the
20
+ * commands version in state — otherwise doctor/peek would stop warning even
21
+ * though the files were never updated. Use `--force` (or a real write) first.
22
+ */
23
+ export declare function recordAgentInstallState(agent: AgentAdapter, opts?: {
24
+ hooksInstalled?: boolean;
25
+ homeDir?: string;
26
+ /** Default true. Pass false when no command file was written or already up to date. */
27
+ advanceCommandsSchema?: boolean;
28
+ }): Promise<void>;
11
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,YAAY,CAAC;AAIpB;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAc3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,+EAA+E;AAC/E,eAAO,MAAM,UAAU,EAAE,SAAS,YAAY,EAAqB,CAAC;AAEpE;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAc3E;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE;IACJ,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAC5B,GACL,OAAO,CAAC,IAAI,CAAC,CAUf"}
@@ -1,8 +1,11 @@
1
+ import { recordAgentInstall } from "../connector/state.js";
2
+ import { VERSION } from "../index.js";
1
3
  import { claude } from "./claude.js";
2
4
  import { cursor } from "./cursor.js";
3
5
  export { claude } from "./claude.js";
4
6
  export { cursor } from "./cursor.js";
5
- const ALL_ADAPTERS = [cursor, claude];
7
+ /** Every agent adapter this Grounder build knows about (Cursor, Claude, …). */
8
+ export const ALL_AGENTS = [cursor, claude];
6
9
  /**
7
10
  * Resolve which adapters to run:
8
11
  * - If `ids` is provided, return those adapters (throws on unknown id).
@@ -10,14 +13,34 @@ const ALL_ADAPTERS = [cursor, claude];
10
13
  */
11
14
  export async function resolveAgents(ids) {
12
15
  if (ids && ids.length > 0) {
13
- const found = ALL_ADAPTERS.filter((a) => ids.includes(a.id));
14
- const unknown = ids.filter((id) => !ALL_ADAPTERS.some((a) => a.id === id));
16
+ const found = ALL_AGENTS.filter((a) => ids.includes(a.id));
17
+ const unknown = ids.filter((id) => !ALL_AGENTS.some((a) => a.id === id));
15
18
  if (unknown.length > 0) {
16
19
  throw new Error(`Unknown agent id(s): ${unknown.join(", ")}`);
17
20
  }
18
21
  return found;
19
22
  }
20
- const results = await Promise.all(ALL_ADAPTERS.map(async (a) => ({ adapter: a, ok: await a.isInstalled() })));
23
+ const results = await Promise.all(ALL_AGENTS.map(async (a) => ({ adapter: a, ok: await a.isInstalled() })));
21
24
  return results.filter((r) => r.ok).map((r) => r.adapter);
22
25
  }
26
+ /**
27
+ * Write this agent's install version info into `~/.grounder/state.json` after
28
+ * install. If hooks were installed and the agent supports them, store the hooks
29
+ * version; otherwise leave any existing hooks version as-is.
30
+ *
31
+ * When `advanceCommandsSchema` is false (every command file was left alone
32
+ * because it looked locally edited or from an old install), do not bump the
33
+ * commands version in state — otherwise doctor/peek would stop warning even
34
+ * though the files were never updated. Use `--force` (or a real write) first.
35
+ */
36
+ export async function recordAgentInstallState(agent, opts = {}) {
37
+ const advanceCommandsSchema = opts.advanceCommandsSchema !== false;
38
+ await recordAgentInstall({
39
+ agentId: agent.id,
40
+ ...(advanceCommandsSchema ? { commandsSchema: agent.commandsSchema } : {}),
41
+ hooksSchema: opts.hooksInstalled && agent.hooksSchema !== undefined ? agent.hooksSchema : undefined,
42
+ grounderVersion: VERSION,
43
+ homeDir: opts.homeDir,
44
+ });
45
+ }
23
46
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,MAAM,YAAY,GAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAc;IAChD,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC3E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAC3E,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,UAAU,GAA4B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEpE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAc;IAChD,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACzE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CACzE,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAmB,EACnB,OAKI,EAAE;IAEN,MAAM,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,KAAK,KAAK,CAAC;IACnE,MAAM,kBAAkB,CAAC;QACvB,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,WAAW,EACT,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;QACxF,eAAe,EAAE,OAAO;QACxB,OAAO,EAAE,IAAI,CAAC,OAAO;KACtB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { AgentInstallOptions, ArtifactStatus } from "./types.js";
2
+ export interface InstallCommandFileOptions extends AgentInstallOptions {
3
+ agentId: string;
4
+ commandsSchema: number;
5
+ templateDir: string;
6
+ commandsDir: string;
7
+ filename: string;
8
+ }
9
+ export interface InstallCommandFileResult {
10
+ dest: string;
11
+ status: ArtifactStatus;
12
+ /** Present when content was (or would be) written — for ledger updates. */
13
+ hash?: string;
14
+ }
15
+ /**
16
+ * Install one slash-command markdown file with chezmoi-style drift detection.
17
+ *
18
+ * When the file already exists and `--force` is off:
19
+ * - on-disk hash matches the ledger → safe to refresh to the new template
20
+ * - no ledger hash, or on-disk hash differs → treat as user-edited (`modified`)
21
+ */
22
+ export declare function installCommandFile(opts: InstallCommandFileOptions): Promise<InstallCommandFileResult>;
23
+ /**
24
+ * Persist per-file hashes after a command install. No-op when `files` is empty
25
+ * or `dryRun` is set.
26
+ */
27
+ export declare function recordCommandFileHashes(opts: {
28
+ agentId: string;
29
+ commandsSchema: number;
30
+ files: Record<string, {
31
+ schema: number;
32
+ hash: string;
33
+ }>;
34
+ homeDir?: string;
35
+ dryRun?: boolean;
36
+ }): Promise<void>;
37
+ //# sourceMappingURL=install-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-command.d.ts","sourceRoot":"","sources":["../../src/agents/install-command.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEtE,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,wBAAwB,CAAC,CAuCnC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhB"}
@@ -0,0 +1,65 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readGrounderState, recordAgentInstall, recordedFileHash } from "../connector/state.js";
4
+ import { VERSION } from "../index.js";
5
+ import { fileExists } from "../util/fs.js";
6
+ import { hashContent } from "../util/hash.js";
7
+ import { runtimeInvocation } from "./hook-runtime.js";
8
+ /**
9
+ * Install one slash-command markdown file with chezmoi-style drift detection.
10
+ *
11
+ * When the file already exists and `--force` is off:
12
+ * - on-disk hash matches the ledger → safe to refresh to the new template
13
+ * - no ledger hash, or on-disk hash differs → treat as user-edited (`modified`)
14
+ */
15
+ export async function installCommandFile(opts) {
16
+ const dest = path.join(opts.commandsDir, opts.filename);
17
+ const existed = await fileExists(dest);
18
+ const template = await readFile(path.join(opts.templateDir, opts.filename), "utf8");
19
+ const rendered = template.replaceAll("{{GROUNDER_CLI}}", runtimeInvocation(opts.homeDir));
20
+ const renderedHash = hashContent(rendered);
21
+ if (existed && !opts.force) {
22
+ const onDisk = await readFile(dest, "utf8");
23
+ const onDiskHash = hashContent(onDisk);
24
+ const state = await readGrounderState(opts.homeDir);
25
+ const recorded = recordedFileHash(state, opts.agentId, dest);
26
+ if (recorded !== undefined && recorded === onDiskHash) {
27
+ // Untouched since Grounder last wrote it — safe to auto-update.
28
+ if (onDiskHash === renderedHash) {
29
+ return { dest, status: "skipped", hash: renderedHash };
30
+ }
31
+ if (!opts.dryRun) {
32
+ await writeFile(dest, rendered);
33
+ }
34
+ return { dest, status: "overwritten", hash: renderedHash };
35
+ }
36
+ // Legacy (no hash) or user-edited — protect content.
37
+ return { dest, status: "modified" };
38
+ }
39
+ if (!opts.dryRun) {
40
+ await mkdir(path.dirname(dest), { recursive: true });
41
+ await writeFile(dest, rendered);
42
+ }
43
+ return {
44
+ dest,
45
+ status: existed ? "overwritten" : "created",
46
+ hash: renderedHash,
47
+ };
48
+ }
49
+ /**
50
+ * Persist per-file hashes after a command install. No-op when `files` is empty
51
+ * or `dryRun` is set.
52
+ */
53
+ export async function recordCommandFileHashes(opts) {
54
+ if (opts.dryRun || Object.keys(opts.files).length === 0) {
55
+ return;
56
+ }
57
+ await recordAgentInstall({
58
+ agentId: opts.agentId,
59
+ commandsSchema: opts.commandsSchema,
60
+ files: opts.files,
61
+ grounderVersion: VERSION,
62
+ homeDir: opts.homeDir,
63
+ });
64
+ }
65
+ //# sourceMappingURL=install-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-command.js","sourceRoot":"","sources":["../../src/agents/install-command.ts"],"names":[],"mappings":"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"}