grounder 0.4.0 → 0.6.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 (221) hide show
  1. package/README.md +150 -271
  2. package/dist/agents/claude.d.ts +4 -4
  3. package/dist/agents/claude.d.ts.map +1 -1
  4. package/dist/agents/claude.js +158 -178
  5. package/dist/agents/claude.js.map +1 -1
  6. package/dist/agents/cursor.d.ts +3 -3
  7. package/dist/agents/cursor.d.ts.map +1 -1
  8. package/dist/agents/cursor.js +97 -143
  9. package/dist/agents/cursor.js.map +1 -1
  10. package/dist/agents/home-skills.d.ts +46 -0
  11. package/dist/agents/home-skills.d.ts.map +1 -0
  12. package/dist/agents/home-skills.js +83 -0
  13. package/dist/agents/home-skills.js.map +1 -0
  14. package/dist/agents/hook-fragment.d.ts +52 -0
  15. package/dist/agents/hook-fragment.d.ts.map +1 -0
  16. package/dist/agents/hook-fragment.js +76 -0
  17. package/dist/agents/hook-fragment.js.map +1 -0
  18. package/dist/agents/hook-install.d.ts +62 -0
  19. package/dist/agents/hook-install.d.ts.map +1 -0
  20. package/dist/agents/hook-install.js +74 -0
  21. package/dist/agents/hook-install.js.map +1 -0
  22. package/dist/agents/hook-runtime.d.ts +80 -13
  23. package/dist/agents/hook-runtime.d.ts.map +1 -1
  24. package/dist/agents/hook-runtime.js +278 -74
  25. package/dist/agents/hook-runtime.js.map +1 -1
  26. package/dist/agents/index.d.ts +8 -14
  27. package/dist/agents/index.d.ts.map +1 -1
  28. package/dist/agents/index.js +13 -19
  29. package/dist/agents/index.js.map +1 -1
  30. package/dist/agents/types.d.ts +56 -16
  31. package/dist/agents/types.d.ts.map +1 -1
  32. package/dist/cli.js +15 -10
  33. package/dist/cli.js.map +1 -1
  34. package/dist/commands/apply.d.ts +69 -0
  35. package/dist/commands/apply.d.ts.map +1 -0
  36. package/dist/commands/apply.js +238 -0
  37. package/dist/commands/apply.js.map +1 -0
  38. package/dist/commands/doctor.d.ts.map +1 -1
  39. package/dist/commands/doctor.js +197 -101
  40. package/dist/commands/doctor.js.map +1 -1
  41. package/dist/commands/handoff/list.d.ts +23 -13
  42. package/dist/commands/handoff/list.d.ts.map +1 -1
  43. package/dist/commands/handoff/list.js +28 -16
  44. package/dist/commands/handoff/list.js.map +1 -1
  45. package/dist/commands/handoff/peek.d.ts +1 -1
  46. package/dist/commands/handoff/peek.d.ts.map +1 -1
  47. package/dist/commands/handoff/peek.js +28 -12
  48. package/dist/commands/handoff/peek.js.map +1 -1
  49. package/dist/commands/handoff.d.ts +2 -0
  50. package/dist/commands/handoff.d.ts.map +1 -1
  51. package/dist/commands/handoff.js +10 -1
  52. package/dist/commands/handoff.js.map +1 -1
  53. package/dist/commands/install-drift.d.ts +34 -0
  54. package/dist/commands/install-drift.d.ts.map +1 -0
  55. package/dist/commands/install-drift.js +72 -0
  56. package/dist/commands/install-drift.js.map +1 -0
  57. package/dist/commands/link.d.ts +12 -0
  58. package/dist/commands/link.d.ts.map +1 -0
  59. package/dist/commands/{repo/init.js → link.js} +35 -27
  60. package/dist/commands/link.js.map +1 -0
  61. package/dist/commands/migrate.d.ts +11 -3
  62. package/dist/commands/migrate.d.ts.map +1 -1
  63. package/dist/commands/migrate.js +66 -34
  64. package/dist/commands/migrate.js.map +1 -1
  65. package/dist/commands/note/list.d.ts +17 -9
  66. package/dist/commands/note/list.d.ts.map +1 -1
  67. package/dist/commands/note/list.js +19 -14
  68. package/dist/commands/note/list.js.map +1 -1
  69. package/dist/commands/note.d.ts +2 -0
  70. package/dist/commands/note.d.ts.map +1 -1
  71. package/dist/commands/note.js +10 -1
  72. package/dist/commands/note.js.map +1 -1
  73. package/dist/commands/output.d.ts +22 -2
  74. package/dist/commands/output.d.ts.map +1 -1
  75. package/dist/commands/output.js +18 -6
  76. package/dist/commands/output.js.map +1 -1
  77. package/dist/commands/overview.d.ts +33 -0
  78. package/dist/commands/overview.d.ts.map +1 -0
  79. package/dist/commands/overview.js +150 -0
  80. package/dist/commands/overview.js.map +1 -0
  81. package/dist/commands/plan/list.d.ts +20 -12
  82. package/dist/commands/plan/list.d.ts.map +1 -1
  83. package/dist/commands/plan/list.js +22 -17
  84. package/dist/commands/plan/list.js.map +1 -1
  85. package/dist/commands/plan.d.ts +2 -0
  86. package/dist/commands/plan.d.ts.map +1 -1
  87. package/dist/commands/plan.js +12 -2
  88. package/dist/commands/plan.js.map +1 -1
  89. package/dist/commands/render-artifact-table.d.ts +85 -0
  90. package/dist/commands/render-artifact-table.d.ts.map +1 -0
  91. package/dist/commands/render-artifact-table.js +232 -0
  92. package/dist/commands/render-artifact-table.js.map +1 -0
  93. package/dist/commands/require-linked.js +2 -2
  94. package/dist/commands/require-linked.js.map +1 -1
  95. package/dist/commands/search.d.ts +23 -0
  96. package/dist/commands/search.d.ts.map +1 -0
  97. package/dist/commands/search.js +288 -0
  98. package/dist/commands/search.js.map +1 -0
  99. package/dist/commands/{vault/init.d.ts → setup.d.ts} +5 -4
  100. package/dist/commands/setup.d.ts.map +1 -0
  101. package/dist/commands/setup.js +210 -0
  102. package/dist/commands/setup.js.map +1 -0
  103. package/dist/commands/status.d.ts +7 -0
  104. package/dist/commands/status.d.ts.map +1 -1
  105. package/dist/commands/status.js +273 -83
  106. package/dist/commands/status.js.map +1 -1
  107. package/dist/commands/upgrade-banner.d.ts +2 -2
  108. package/dist/commands/upgrade-banner.js +2 -2
  109. package/dist/connector/home.d.ts +12 -0
  110. package/dist/connector/home.d.ts.map +1 -1
  111. package/dist/connector/home.js +26 -2
  112. package/dist/connector/home.js.map +1 -1
  113. package/dist/connector/ledger-migrations.d.ts +55 -0
  114. package/dist/connector/ledger-migrations.d.ts.map +1 -0
  115. package/dist/connector/ledger-migrations.js +94 -0
  116. package/dist/connector/ledger-migrations.js.map +1 -0
  117. package/dist/connector/state.d.ts +97 -60
  118. package/dist/connector/state.d.ts.map +1 -1
  119. package/dist/connector/state.js +165 -107
  120. package/dist/connector/state.js.map +1 -1
  121. package/dist/connector/vault.d.ts +2 -0
  122. package/dist/connector/vault.d.ts.map +1 -1
  123. package/dist/connector/vault.js +6 -1
  124. package/dist/connector/vault.js.map +1 -1
  125. package/dist/help.d.ts +3 -3
  126. package/dist/help.d.ts.map +1 -1
  127. package/dist/help.js +97 -56
  128. package/dist/help.js.map +1 -1
  129. package/dist/reconcile/apply.d.ts +31 -0
  130. package/dist/reconcile/apply.d.ts.map +1 -0
  131. package/dist/reconcile/apply.js +97 -0
  132. package/dist/reconcile/apply.js.map +1 -0
  133. package/dist/reconcile/core.d.ts +82 -0
  134. package/dist/reconcile/core.d.ts.map +1 -0
  135. package/dist/reconcile/core.js +163 -0
  136. package/dist/reconcile/core.js.map +1 -0
  137. package/dist/reconcile/disk.d.ts +13 -0
  138. package/dist/reconcile/disk.d.ts.map +1 -0
  139. package/dist/reconcile/disk.js +28 -0
  140. package/dist/reconcile/disk.js.map +1 -0
  141. package/dist/util/frontmatter.d.ts +9 -7
  142. package/dist/util/frontmatter.d.ts.map +1 -1
  143. package/dist/util/frontmatter.js +29 -4
  144. package/dist/util/frontmatter.js.map +1 -1
  145. package/dist/util/fs.d.ts +14 -0
  146. package/dist/util/fs.d.ts.map +1 -1
  147. package/dist/util/fs.js +27 -1
  148. package/dist/util/fs.js.map +1 -1
  149. package/dist/util/merge-json.d.ts +13 -2
  150. package/dist/util/merge-json.d.ts.map +1 -1
  151. package/dist/util/merge-json.js +24 -10
  152. package/dist/util/merge-json.js.map +1 -1
  153. package/dist/util/path.d.ts +23 -0
  154. package/dist/util/path.d.ts.map +1 -1
  155. package/dist/util/path.js +39 -0
  156. package/dist/util/path.js.map +1 -1
  157. package/dist/vault/list-handoffs.d.ts +14 -2
  158. package/dist/vault/list-handoffs.d.ts.map +1 -1
  159. package/dist/vault/list-handoffs.js +40 -23
  160. package/dist/vault/list-handoffs.js.map +1 -1
  161. package/dist/vault/list-markdown.d.ts +8 -0
  162. package/dist/vault/list-markdown.d.ts.map +1 -0
  163. package/dist/vault/list-markdown.js +35 -0
  164. package/dist/vault/list-markdown.js.map +1 -0
  165. package/dist/vault/list-notes.d.ts +15 -6
  166. package/dist/vault/list-notes.d.ts.map +1 -1
  167. package/dist/vault/list-notes.js +23 -27
  168. package/dist/vault/list-notes.js.map +1 -1
  169. package/dist/vault/list-plans.d.ts +12 -3
  170. package/dist/vault/list-plans.d.ts.map +1 -1
  171. package/dist/vault/list-plans.js +20 -24
  172. package/dist/vault/list-plans.js.map +1 -1
  173. package/dist/vault/search.d.ts +55 -0
  174. package/dist/vault/search.d.ts.map +1 -0
  175. package/dist/vault/search.js +432 -0
  176. package/dist/vault/search.js.map +1 -0
  177. package/dist/vault/write-handoff.d.ts +2 -0
  178. package/dist/vault/write-handoff.d.ts.map +1 -1
  179. package/dist/vault/write-handoff.js +5 -0
  180. package/dist/vault/write-handoff.js.map +1 -1
  181. package/dist/vault/write-note.d.ts +2 -0
  182. package/dist/vault/write-note.d.ts.map +1 -1
  183. package/dist/vault/write-note.js +9 -1
  184. package/dist/vault/write-note.js.map +1 -1
  185. package/dist/vault/write-plan.d.ts +4 -0
  186. package/dist/vault/write-plan.d.ts.map +1 -1
  187. package/dist/vault/write-plan.js +14 -1
  188. package/dist/vault/write-plan.js.map +1 -1
  189. package/package.json +11 -4
  190. package/templates/agents/claude/skills/grounder-handoff/SKILL.md +73 -0
  191. package/templates/agents/claude/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +12 -2
  192. package/templates/agents/claude/skills/grounder-overview/SKILL.md +21 -0
  193. package/templates/agents/claude/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +13 -5
  194. package/templates/agents/claude/skills/grounder-recall/SKILL.md +34 -0
  195. package/templates/agents/claude/skills/grounder-search/SKILL.md +152 -0
  196. package/templates/agents/cursor/skills/grounder-handoff/SKILL.md +73 -0
  197. package/templates/agents/cursor/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +12 -2
  198. package/templates/agents/cursor/skills/grounder-overview/SKILL.md +21 -0
  199. package/templates/agents/cursor/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +13 -5
  200. package/templates/agents/cursor/skills/grounder-recall/SKILL.md +34 -0
  201. package/templates/agents/cursor/skills/grounder-search/SKILL.md +152 -0
  202. package/templates/vault/plan.md +1 -1
  203. package/templates/vault/session-handoff.md +2 -1
  204. package/dist/agents/install-command.d.ts +0 -35
  205. package/dist/agents/install-command.d.ts.map +0 -1
  206. package/dist/agents/install-command.js +0 -65
  207. package/dist/agents/install-command.js.map +0 -1
  208. package/dist/commands/apply-agent-installs.d.ts +0 -34
  209. package/dist/commands/apply-agent-installs.d.ts.map +0 -1
  210. package/dist/commands/apply-agent-installs.js +0 -137
  211. package/dist/commands/apply-agent-installs.js.map +0 -1
  212. package/dist/commands/repo/init.d.ts +0 -11
  213. package/dist/commands/repo/init.d.ts.map +0 -1
  214. package/dist/commands/repo/init.js.map +0 -1
  215. package/dist/commands/vault/init.d.ts.map +0 -1
  216. package/dist/commands/vault/init.js +0 -90
  217. package/dist/commands/vault/init.js.map +0 -1
  218. package/templates/agents/claude/commands/grounder-task-handoff.md +0 -54
  219. package/templates/agents/claude/commands/grounder-task.md +0 -22
  220. package/templates/agents/cursor/commands/grounder-task-handoff.md +0 -54
  221. package/templates/agents/cursor/commands/grounder-task.md +0 -22
@@ -0,0 +1,210 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import { runtimeCliPath } from "../agents/hook-runtime.js";
3
+ import { resolveAgents } from "../agents/index.js";
4
+ import { homeConfigPath, InvalidHomeConfigError, readHomeConfig, withHomeDir, writeHomeConfig, } from "../connector/home.js";
5
+ import { ledgerVersionChanged, readGrounderState, statePath, } from "../connector/state.js";
6
+ import { isUnsupportedSchemaError } from "../connector/unsupported-schema.js";
7
+ import { helpExitCode } from "../help.js";
8
+ import { VERSION } from "../index.js";
9
+ import { flagBool, flagStrings, parseArgs } from "../util/parse-args.js";
10
+ import { resolveUserPath } from "../util/path.js";
11
+ import { confirm } from "../util/prompt.js";
12
+ import { projectsParent } from "../vault/layout.js";
13
+ import { applyAgentInstalls } from "./apply.js";
14
+ import { renderAgentErrors, renderModifiedNote, renderSummary, renderTable, rowsFromApplyResult, stateRow, } from "./render-artifact-table.js";
15
+ /**
16
+ * Read the existing home config for the "already exists with a different
17
+ * vault" conflict check. A corrupt/invalid file has no value worth
18
+ * conflict-checking — treat it as absent so `setup` can recreate it without
19
+ * requiring the user to manually delete it first.
20
+ */
21
+ async function readExistingHomeForSetup() {
22
+ try {
23
+ return { home: await readHomeConfig(), invalidReason: null };
24
+ }
25
+ catch (error) {
26
+ const reason = error instanceof InvalidHomeConfigError
27
+ ? error.reason
28
+ : error instanceof Error
29
+ ? error.message
30
+ : String(error);
31
+ return { home: null, invalidReason: reason };
32
+ }
33
+ }
34
+ export async function runSetup(argv) {
35
+ const helpCode = helpExitCode(argv, "setup");
36
+ if (helpCode !== null) {
37
+ return helpCode;
38
+ }
39
+ const { positional, flags, repeated } = parseArgs(argv);
40
+ const vaultPathArg = positional[0];
41
+ const yes = flagBool(flags, "yes", "y");
42
+ const force = flagBool(flags, "force", "f");
43
+ const hooks = flagBool(flags, "hooks");
44
+ const dryRun = flagBool(flags, "dry-run");
45
+ const agents = flagStrings(repeated, "agent");
46
+ if (!vaultPathArg) {
47
+ process.stderr.write("Usage: grounder setup <path>\n");
48
+ return 1;
49
+ }
50
+ return runSetupWithOptions({
51
+ vaultPath: vaultPathArg,
52
+ yes,
53
+ force,
54
+ hooks,
55
+ dryRun,
56
+ agents: agents.length > 0 ? agents : undefined,
57
+ });
58
+ }
59
+ export async function runSetupWithOptions(options) {
60
+ return withHomeDir(options.homeDir, async () => {
61
+ const vaultRoot = resolveUserPath(options.vaultPath);
62
+ const yes = options.yes ?? false;
63
+ const force = options.force ?? false;
64
+ const hooks = options.hooks ?? false;
65
+ const dryRun = options.dryRun ?? false;
66
+ const homeDir = options.homeDir;
67
+ const { home: existingHome, invalidReason } = await readExistingHomeForSetup();
68
+ const projectsDir = projectsParent(vaultRoot);
69
+ const agents = await resolveAgents(options.agents);
70
+ if (existingHome && existingHome.vaultRoot !== vaultRoot && !force) {
71
+ process.stderr.write(`Home config already exists with vault ${existingHome.vaultRoot}. Use --force to overwrite.\n`);
72
+ return 1;
73
+ }
74
+ if (invalidReason) {
75
+ process.stdout.write(dryRun
76
+ ? `Would replace invalid home config (${invalidReason}).\n`
77
+ : `Will replace invalid home config (${invalidReason}).\n`);
78
+ }
79
+ process.stdout.write(`Vault root: ${vaultRoot}\n`);
80
+ process.stdout.write("Connect to a markdown vault (once per machine).\n");
81
+ process.stdout.write(dryRun ? "Would write:\n" : "Will write:\n");
82
+ // One label column shared by every preview line — "runtime" (not "grounder
83
+ // runtime") so it's no wider than it needs to be and lines up with the
84
+ // agent ids instead of forcing its own, much wider, column.
85
+ const previewLabelWidth = Math.max("home".length, "vault".length, "runtime".length, ...agents.map((agent) => agent.id.length));
86
+ process.stdout.write(` ${"home".padEnd(previewLabelWidth)} ${homeConfigPath(homeDir)}\n`);
87
+ process.stdout.write(` ${"vault".padEnd(previewLabelWidth)} 10-Projects/ (if missing)\n`);
88
+ if (agents.length > 0) {
89
+ process.stdout.write(` ${"runtime".padEnd(previewLabelWidth)} ${runtimeCliPath(homeDir)}\n`);
90
+ }
91
+ for (const agent of agents) {
92
+ const label = agent.id.padEnd(previewLabelWidth);
93
+ for (const artifactPath of agent.expectedArtifacts(homeDir)) {
94
+ process.stdout.write(` ${label} ${artifactPath}\n`);
95
+ }
96
+ if (hooks && agent.expectedHookArtifacts) {
97
+ for (const hookPath of agent.expectedHookArtifacts(homeDir)) {
98
+ process.stdout.write(` ${label} hook ${hookPath}\n`);
99
+ }
100
+ }
101
+ }
102
+ if (agents.length === 0) {
103
+ process.stdout.write(" (no supported agents detected — skipping agent artifacts)\n");
104
+ }
105
+ process.stdout.write("\n");
106
+ if (dryRun) {
107
+ let priorState;
108
+ let applyResult;
109
+ try {
110
+ priorState = await readGrounderState(homeDir);
111
+ applyResult = await applyAgentInstalls({
112
+ agents,
113
+ force,
114
+ hooks,
115
+ // `setup` never retires legacy pre-skill command files, even with
116
+ // `--force` — see docs/upgrading.md and ApplyAgentInstallsOptions#retireLegacy.
117
+ retireLegacy: false,
118
+ dryRun: true,
119
+ homeDir,
120
+ grounderVersion: VERSION,
121
+ });
122
+ }
123
+ catch (error) {
124
+ if (isUnsupportedSchemaError(error)) {
125
+ process.stderr.write(`${error.message}\n`);
126
+ return 1;
127
+ }
128
+ const detail = error instanceof Error ? error.message : String(error);
129
+ process.stderr.write(`Dry run failed: agent install would not succeed:\n ${detail}\n`);
130
+ return 1;
131
+ }
132
+ if (agents.length === 0) {
133
+ return 0;
134
+ }
135
+ // A dry run never writes `~/.grounder/config.json` — if it doesn't
136
+ // already exist (first-time setup, or one whose config is invalid and
137
+ // would be replaced), `grounder migrate --force` would fail with "No
138
+ // home config found" until this exact command is re-run without
139
+ // `--dry-run`. Point the reader at that instead of a command that
140
+ // can't work yet.
141
+ const forceCommand = existingHome
142
+ ? "grounder migrate"
143
+ : `grounder setup ${options.vaultPath}`;
144
+ const hadAgentError = reportAgentInstalls(applyResult, priorState, homeDir, true, forceCommand);
145
+ return hadAgentError ? 1 : 0;
146
+ }
147
+ if (!yes) {
148
+ const proceed = await confirm("Proceed?");
149
+ if (!proceed) {
150
+ process.stdout.write("Aborted.\n");
151
+ return 0;
152
+ }
153
+ }
154
+ await writeHomeConfig({ vaultRoot });
155
+ await mkdir(projectsDir, { recursive: true });
156
+ process.stdout.write("✓ Wrote home config\n");
157
+ process.stdout.write(`✓ Vault scaffold: ${projectsDir}\n`);
158
+ let priorState;
159
+ let applyResult;
160
+ try {
161
+ priorState = await readGrounderState(homeDir);
162
+ applyResult = await applyAgentInstalls({
163
+ agents,
164
+ force,
165
+ hooks,
166
+ retireLegacy: false,
167
+ homeDir,
168
+ grounderVersion: VERSION,
169
+ });
170
+ }
171
+ catch (error) {
172
+ if (isUnsupportedSchemaError(error)) {
173
+ process.stderr.write(`${error.message}\n`);
174
+ return 1;
175
+ }
176
+ const detail = error instanceof Error ? error.message : String(error);
177
+ process.stderr.write(`\nHome config and vault scaffold were written, but agent skill files/hooks were not installed:\n ${detail}\n`);
178
+ return 1;
179
+ }
180
+ if (agents.length === 0) {
181
+ return 0;
182
+ }
183
+ // Real setup has already written a valid home config by this point
184
+ // (above), so `grounder migrate --force` always works as the remediation
185
+ // command here.
186
+ const hadAgentError = reportAgentInstalls(applyResult, priorState, homeDir, false, "grounder migrate");
187
+ return hadAgentError ? 1 : 0;
188
+ });
189
+ }
190
+ /**
191
+ * Render the table/summary/conflict-note block shared by a dry-run preview
192
+ * and a real apply — same rows, same wording, only `renderSummary`'s tense
193
+ * differs, so a dry run tells the truth about what a real run would show.
194
+ * Returns whether any agent's hook step failed (see
195
+ * `AgentApplyResult#error`), so the caller can exit non-zero without
196
+ * duplicating that check.
197
+ */
198
+ function reportAgentInstalls(applyResult, priorState, homeDir, dryRun, forceCommand) {
199
+ const rows = rowsFromApplyResult(applyResult);
200
+ const ledgerChanged = applyResult.agents.some((a) => a.ledgerChanged) || ledgerVersionChanged(priorState, VERSION);
201
+ rows.push(stateRow(ledgerChanged, priorState, statePath(homeDir)));
202
+ process.stdout.write("\n");
203
+ renderTable(rows);
204
+ process.stdout.write("\n");
205
+ renderSummary(rows, dryRun);
206
+ renderModifiedNote(rows, forceCommand);
207
+ renderAgentErrors(applyResult);
208
+ return applyResult.agents.some((a) => a.error !== undefined);
209
+ }
210
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,14 @@
1
1
  export interface StatusOptions {
2
2
  cwd?: string;
3
3
  homeDir?: string;
4
+ json?: boolean;
4
5
  }
6
+ /**
7
+ * Bump whenever `writeJsonOutput`'s payload shape changes (fields added,
8
+ * removed, or renamed) — consumers (the VS Code extension's `status.ts`)
9
+ * compare this directly instead of inferring compatibility structurally.
10
+ */
11
+ export declare const STATUS_JSON_SCHEMA_VERSION = 1;
5
12
  export declare function runStatus(argv: string[]): Promise<number>;
6
13
  export declare function runStatusWithOptions(options?: StatusOptions): Promise<number>;
7
14
  //# sourceMappingURL=status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAyED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/D;AAED,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4EvF"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAoWD;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAoC5C,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB/D;AAED,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUvF"}
@@ -1,36 +1,30 @@
1
1
  import path from "node:path";
2
- import { ALL_AGENTS } from "../agents/index.js";
3
2
  import { currentBranch, findGitRoot } from "../connector/git.js";
4
3
  import { homeConfigPath, readHomeConfig, withHomeDir } from "../connector/home.js";
5
4
  import { findLinkedRepoRoot, readRepoConfig, repoConfigPath, } from "../connector/repo.js";
6
- import { isInstallSchemaStale, readGrounderState, statePath } from "../connector/state.js";
5
+ import { readGrounderState, statePath } from "../connector/state.js";
7
6
  import { isUnsupportedSchemaError } from "../connector/unsupported-schema.js";
8
- import { resolveLogsDir, resolveNotesDir, resolvePlansDir, resolveVaultRoot, } from "../connector/vault.js";
7
+ import { resolveLogsDir, resolveNotesDir, resolvePlansDir, resolveProjectVaultRoot, resolveVaultRoot, } from "../connector/vault.js";
9
8
  import { helpExitCode } from "../help.js";
10
9
  import { VERSION } from "../index.js";
10
+ import { flagBool, parseArgs } from "../util/parse-args.js";
11
+ import { installDriftDetected } from "./install-drift.js";
11
12
  import { writeSection } from "./output.js";
12
13
  import { packageVersionNotice } from "./package-version-notice.js";
13
14
  const LABEL_WIDTH = 12;
14
- const VAULT_INIT = "grounder vault init <path>";
15
- const REPO_INIT = "grounder init";
16
- const REPO_INIT_FORCE = "grounder init --force";
15
+ const VAULT_INIT = "grounder setup <path>";
16
+ const REPO_INIT = "grounder link";
17
+ const REPO_INIT_FORCE = "grounder link --force";
17
18
  const MIGRATE = "grounder migrate";
18
19
  const MIGRATE_FORCE = "grounder migrate --force";
19
20
  const UPGRADE_GROUNDER = "upgrade grounder";
21
+ const USAGE = "Usage: grounder status [--json]\n";
20
22
  function statusLine(label, value) {
21
23
  return ` ${label.padEnd(LABEL_WIDTH)}${value}\n`;
22
24
  }
23
25
  function errorDetail(error) {
24
26
  return error instanceof Error ? error.message : String(error);
25
27
  }
26
- async function writeGitLine(gitRoot) {
27
- if (!gitRoot) {
28
- return;
29
- }
30
- const branch = await currentBranch(gitRoot);
31
- const gitValue = branch !== undefined ? `${gitRoot} (branch: ${branch})` : gitRoot;
32
- process.stdout.write(statusLine("Git:", gitValue));
33
- }
34
28
  async function tryReadHome() {
35
29
  try {
36
30
  return { home: await readHomeConfig(), invalid: null };
@@ -51,94 +45,290 @@ async function tryReadRepo(linkedRoot) {
51
45
  };
52
46
  }
53
47
  }
54
- async function writeInstallStateLine(homeDir) {
48
+ async function gatherStateInfo(homeDir) {
55
49
  try {
56
50
  const state = await readGrounderState(homeDir);
57
51
  if (!state) {
58
- process.stdout.write(statusLine("State:", `missing → ${MIGRATE_FORCE}`));
59
- return;
60
- }
61
- process.stdout.write(statusLine("State:", statePath(homeDir)));
62
- const packageNotice = packageVersionNotice(VERSION, state.grounderVersion);
63
- if (packageNotice) {
64
- process.stdout.write(statusLine("Package:", packageNotice.status));
65
- }
66
- if (isInstallSchemaStale(state, ALL_AGENTS)) {
67
- process.stdout.write(statusLine("Schemas:", `ledger stale → ${MIGRATE}`));
68
- }
69
- else {
70
- process.stdout.write(statusLine("Schemas:", "current"));
52
+ return {
53
+ path: statePath(homeDir),
54
+ status: "missing",
55
+ packageNotice: null,
56
+ installCurrent: null,
57
+ };
71
58
  }
59
+ const notice = packageVersionNotice(VERSION, state.grounderVersion);
60
+ const drift = await installDriftDetected(state, homeDir);
61
+ return {
62
+ path: statePath(homeDir),
63
+ status: "ok",
64
+ packageNotice: notice,
65
+ installCurrent: !drift,
66
+ };
67
+ }
68
+ catch (error) {
69
+ return {
70
+ path: statePath(homeDir),
71
+ status: isUnsupportedSchemaError(error) ? "unsupported" : "invalid",
72
+ packageNotice: null,
73
+ installCurrent: null,
74
+ };
75
+ }
76
+ }
77
+ async function gatherMachine(homeInvalid, home, homeDir) {
78
+ const configPath = homeConfigPath(homeDir);
79
+ if (homeInvalid) {
80
+ return { configPath, configState: "invalid", vaultRoot: null, state: null };
81
+ }
82
+ if (!home) {
83
+ return { configPath, configState: "missing", vaultRoot: null, state: null };
84
+ }
85
+ return {
86
+ configPath,
87
+ configState: "ok",
88
+ vaultRoot: resolveVaultRoot(home),
89
+ state: await gatherStateInfo(homeDir),
90
+ };
91
+ }
92
+ async function gatherGit(gitRoot) {
93
+ if (!gitRoot) {
94
+ return null;
95
+ }
96
+ const branch = await currentBranch(gitRoot);
97
+ return { root: gitRoot, branch: branch ?? null };
98
+ }
99
+ async function gatherProject(params) {
100
+ const { cwd, gitRoot, linkedRoot, repo, repoInvalid, repoUnsupported, home } = params;
101
+ if (!linkedRoot) {
102
+ return {
103
+ linked: false,
104
+ folder: null,
105
+ isAncestorLink: false,
106
+ configPath: null,
107
+ configState: "missing",
108
+ projectId: null,
109
+ vaultRoot: null,
110
+ notesDir: null,
111
+ logsDir: null,
112
+ plansDir: null,
113
+ git: null,
114
+ };
115
+ }
116
+ const git = await gatherGit(gitRoot);
117
+ const isAncestorLink = linkedRoot !== cwd;
118
+ const configPath = repoConfigPath(linkedRoot);
119
+ if (repoInvalid || !repo) {
120
+ const configState = repoUnsupported
121
+ ? "unsupported"
122
+ : repoInvalid
123
+ ? "invalid"
124
+ : "missing";
125
+ return {
126
+ linked: true,
127
+ folder: linkedRoot,
128
+ isAncestorLink,
129
+ configPath,
130
+ configState,
131
+ projectId: null,
132
+ vaultRoot: null,
133
+ notesDir: null,
134
+ logsDir: null,
135
+ plansDir: null,
136
+ git,
137
+ };
138
+ }
139
+ return {
140
+ linked: true,
141
+ folder: linkedRoot,
142
+ isAncestorLink,
143
+ configPath,
144
+ configState: "ok",
145
+ projectId: repo.projectId,
146
+ vaultRoot: home ? resolveProjectVaultRoot(home, repo) : null,
147
+ notesDir: home ? resolveNotesDir(home, repo) : null,
148
+ logsDir: home ? resolveLogsDir(home, repo) : null,
149
+ plansDir: home ? resolvePlansDir(home, repo) : null,
150
+ git,
151
+ };
152
+ }
153
+ async function gatherStatus(options) {
154
+ const cwd = path.resolve(options.cwd ?? process.cwd());
155
+ const { home, invalid: homeInvalid } = await tryReadHome();
156
+ const gitRoot = await findGitRoot(cwd);
157
+ const linkedRoot = await findLinkedRepoRoot(cwd, gitRoot);
158
+ const { repo, invalid: repoInvalid, unsupported: repoUnsupported, } = linkedRoot
159
+ ? await tryReadRepo(linkedRoot)
160
+ : { repo: null, invalid: null, unsupported: false };
161
+ const machine = await gatherMachine(homeInvalid, home, options.homeDir);
162
+ const project = await gatherProject({
163
+ cwd,
164
+ gitRoot,
165
+ linkedRoot,
166
+ repo,
167
+ repoInvalid,
168
+ repoUnsupported,
169
+ home,
170
+ });
171
+ return { cwd, machine, project };
172
+ }
173
+ /**
174
+ * `findLinkedRepoRoot` walks up to the nearest `.grounder.json`, so a
175
+ * subdirectory of a linked repo inherits that link. Surface it explicitly
176
+ * when `linkedRoot` isn't `cwd` itself, so callers (agents included) don't
177
+ * mistake an ancestor's link for this exact folder being linked.
178
+ */
179
+ function writeAncestorNoteIfAny(cwd, folder) {
180
+ if (folder === cwd) {
181
+ return;
182
+ }
183
+ process.stdout.write(statusLine("Note:", `linked ancestor — ${cwd} itself is unlinked; grounder link here would create a separate project`));
184
+ }
185
+ function writeGitLine(git) {
186
+ if (!git) {
187
+ return;
188
+ }
189
+ const value = git.branch !== null ? `${git.root} (branch: ${git.branch})` : git.root;
190
+ process.stdout.write(statusLine("Git:", value));
191
+ }
192
+ function writeStateLines(state) {
193
+ if (state.status === "missing") {
194
+ process.stdout.write(statusLine("State:", `missing → ${MIGRATE_FORCE}`));
195
+ return;
196
+ }
197
+ if (state.status === "unsupported") {
198
+ process.stdout.write(statusLine("State:", `unsupported → ${UPGRADE_GROUNDER}`));
199
+ return;
72
200
  }
73
- catch {
201
+ if (state.status === "invalid") {
74
202
  process.stdout.write(statusLine("State:", `invalid → ${MIGRATE_FORCE}`));
203
+ return;
75
204
  }
205
+ process.stdout.write(statusLine("State:", state.path));
206
+ if (state.packageNotice) {
207
+ process.stdout.write(statusLine("Package:", state.packageNotice.status));
208
+ }
209
+ process.stdout.write(statusLine("Install:", state.installCurrent ? "current" : `outdated → ${MIGRATE}`));
210
+ }
211
+ function writeTextOutput(status) {
212
+ const { cwd, machine, project } = status;
213
+ writeSection("Machine");
214
+ if (machine.configState === "invalid") {
215
+ process.stdout.write(statusLine("Config:", `invalid → ${VAULT_INIT}`));
216
+ }
217
+ else if (machine.configState === "missing") {
218
+ process.stdout.write(statusLine("Config:", `missing → ${VAULT_INIT}`));
219
+ }
220
+ else {
221
+ process.stdout.write(statusLine("Config:", machine.configPath));
222
+ process.stdout.write(statusLine("Vault:", machine.vaultRoot));
223
+ writeStateLines(machine.state);
224
+ }
225
+ process.stdout.write("\n");
226
+ writeSection("Project");
227
+ if (!project.linked) {
228
+ process.stdout.write(statusLine("Linked:", "no"));
229
+ if (machine.configState === "ok") {
230
+ process.stdout.write(statusLine("Config:", `missing → ${REPO_INIT}`));
231
+ }
232
+ return;
233
+ }
234
+ const folder = project.folder;
235
+ if (project.configState !== "ok") {
236
+ const fix = project.configState === "unsupported"
237
+ ? UPGRADE_GROUNDER
238
+ : machine.configState === "ok"
239
+ ? REPO_INIT_FORCE
240
+ : VAULT_INIT;
241
+ process.stdout.write(statusLine("Linked:", project.configState === "unsupported" ? `unsupported → ${fix}` : `incomplete → ${fix}`));
242
+ process.stdout.write(statusLine("Folder:", folder));
243
+ writeAncestorNoteIfAny(cwd, folder);
244
+ process.stdout.write(statusLine("Config:", project.configState === "unsupported"
245
+ ? `unsupported → ${UPGRADE_GROUNDER}`
246
+ : project.configState === "invalid"
247
+ ? `invalid → ${REPO_INIT_FORCE}`
248
+ : `missing → ${REPO_INIT}`));
249
+ writeGitLine(project.git);
250
+ return;
251
+ }
252
+ process.stdout.write(statusLine("Linked:", "yes"));
253
+ process.stdout.write(statusLine("Folder:", folder));
254
+ writeAncestorNoteIfAny(cwd, folder);
255
+ process.stdout.write(statusLine("Config:", project.configPath));
256
+ process.stdout.write(statusLine("Id:", project.projectId));
257
+ if (project.notesDir) {
258
+ process.stdout.write(statusLine("In Vault:", project.vaultRoot));
259
+ process.stdout.write(statusLine("Notes:", project.notesDir));
260
+ process.stdout.write(statusLine("Logs:", project.logsDir));
261
+ process.stdout.write(statusLine("Plans:", project.plansDir));
262
+ }
263
+ writeGitLine(project.git);
264
+ }
265
+ /**
266
+ * Bump whenever `writeJsonOutput`'s payload shape changes (fields added,
267
+ * removed, or renamed) — consumers (the VS Code extension's `status.ts`)
268
+ * compare this directly instead of inferring compatibility structurally.
269
+ */
270
+ export const STATUS_JSON_SCHEMA_VERSION = 1;
271
+ function writeJsonOutput(status) {
272
+ const { machine, project } = status;
273
+ const payload = {
274
+ schemaVersion: STATUS_JSON_SCHEMA_VERSION,
275
+ machine: {
276
+ configPath: machine.configPath,
277
+ configState: machine.configState,
278
+ vaultRoot: machine.vaultRoot,
279
+ state: machine.state
280
+ ? {
281
+ path: machine.state.path,
282
+ status: machine.state.status,
283
+ packageVersionNotice: machine.state.packageNotice?.message ?? null,
284
+ installCurrent: machine.state.installCurrent,
285
+ }
286
+ : null,
287
+ },
288
+ project: {
289
+ linked: project.linked,
290
+ folder: project.folder,
291
+ isAncestorLink: project.isAncestorLink,
292
+ configPath: project.configPath,
293
+ configState: project.configState,
294
+ projectId: project.projectId,
295
+ vaultRoot: project.vaultRoot,
296
+ notesDir: project.notesDir,
297
+ logsDir: project.logsDir,
298
+ plansDir: project.plansDir,
299
+ git: project.git,
300
+ },
301
+ };
302
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
76
303
  }
77
304
  export async function runStatus(argv) {
78
305
  const helpCode = helpExitCode(argv, "status");
79
306
  if (helpCode !== null) {
80
307
  return helpCode;
81
308
  }
82
- return runStatusWithOptions({});
309
+ const { positional, flags } = parseArgs(argv);
310
+ if (positional.length > 0) {
311
+ process.stderr.write(USAGE);
312
+ return 1;
313
+ }
314
+ const allowedFlags = new Set(["json"]);
315
+ for (const key of flags.keys()) {
316
+ if (!allowedFlags.has(key)) {
317
+ process.stderr.write(USAGE);
318
+ return 1;
319
+ }
320
+ }
321
+ return runStatusWithOptions({ json: flagBool(flags, "json") });
83
322
  }
84
323
  export async function runStatusWithOptions(options = {}) {
85
324
  return withHomeDir(options.homeDir, async () => {
86
- const cwd = path.resolve(options.cwd ?? process.cwd());
87
- const { home, invalid: homeInvalid } = await tryReadHome();
88
- const gitRoot = await findGitRoot(cwd);
89
- const linkedRoot = await findLinkedRepoRoot(cwd, gitRoot);
90
- const { repo, invalid: repoInvalid, unsupported: repoUnsupported, } = linkedRoot
91
- ? await tryReadRepo(linkedRoot)
92
- : { repo: null, invalid: null, unsupported: false };
93
- writeSection("Machine");
94
- if (homeInvalid) {
95
- process.stdout.write(statusLine("Config:", `invalid → ${VAULT_INIT}`));
96
- }
97
- else if (!home) {
98
- process.stdout.write(statusLine("Config:", `missing → ${VAULT_INIT}`));
325
+ const status = await gatherStatus(options);
326
+ if (options.json) {
327
+ writeJsonOutput(status);
99
328
  }
100
329
  else {
101
- process.stdout.write(statusLine("Config:", homeConfigPath()));
102
- process.stdout.write(statusLine("Vault:", resolveVaultRoot(home)));
103
- await writeInstallStateLine(options.homeDir);
104
- }
105
- process.stdout.write("\n");
106
- writeSection("Project");
107
- if (!linkedRoot) {
108
- process.stdout.write(statusLine("Linked:", "no"));
109
- if (home) {
110
- process.stdout.write(statusLine("Config:", `missing → ${REPO_INIT}`));
111
- }
112
- return 0;
113
- }
114
- if (repoInvalid || !repo) {
115
- const fix = repoUnsupported ? UPGRADE_GROUNDER : home ? REPO_INIT_FORCE : VAULT_INIT;
116
- process.stdout.write(statusLine("Linked:", repoUnsupported ? `unsupported → ${fix}` : `incomplete → ${fix}`));
117
- process.stdout.write(statusLine("Folder:", linkedRoot));
118
- process.stdout.write(statusLine("Config:", repoUnsupported
119
- ? `unsupported → ${UPGRADE_GROUNDER}`
120
- : repoInvalid
121
- ? `invalid → ${REPO_INIT_FORCE}`
122
- : `missing → ${REPO_INIT}`));
123
- await writeGitLine(gitRoot);
124
- return 0;
125
- }
126
- if (!home) {
127
- process.stdout.write(statusLine("Linked:", `incomplete → ${VAULT_INIT}`));
128
- process.stdout.write(statusLine("Folder:", linkedRoot));
129
- process.stdout.write(statusLine("Config:", repoConfigPath(linkedRoot)));
130
- process.stdout.write(statusLine("Id:", repo.projectId));
131
- await writeGitLine(gitRoot);
132
- return 0;
330
+ writeTextOutput(status);
133
331
  }
134
- process.stdout.write(statusLine("Linked:", "yes"));
135
- process.stdout.write(statusLine("Folder:", linkedRoot));
136
- process.stdout.write(statusLine("Config:", repoConfigPath(linkedRoot)));
137
- process.stdout.write(statusLine("Id:", repo.projectId));
138
- process.stdout.write(statusLine("Notes:", resolveNotesDir(home, repo)));
139
- process.stdout.write(statusLine("Logs:", resolveLogsDir(home, repo)));
140
- process.stdout.write(statusLine("Plans:", resolvePlansDir(home, repo)));
141
- await writeGitLine(gitRoot);
142
332
  return 0;
143
333
  });
144
334
  }