@monoes/monomindcli 2.16.1 → 2.16.2

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 (214) hide show
  1. package/.claude/helpers/handlers/edit-handler.cjs +14 -12
  2. package/.claude/helpers/handlers/route-handler.cjs +6 -0
  3. package/.claude/helpers/monograph-freshen.cjs +31 -113
  4. package/.claude/helpers/utils/monograph-resolve.cjs +497 -0
  5. package/.claude/helpers/utils/monograph.cjs +8 -51
  6. package/README.md +1 -1
  7. package/dist/src/commands/doctor-hook-monograph-checks.d.ts +8 -0
  8. package/dist/src/commands/doctor-hook-monograph-checks.d.ts.map +1 -0
  9. package/dist/src/commands/doctor-hook-monograph-checks.js +79 -0
  10. package/dist/src/commands/doctor-hook-monograph-checks.js.map +1 -0
  11. package/dist/src/commands/doctor.d.ts.map +1 -1
  12. package/dist/src/commands/doctor.js +4 -1
  13. package/dist/src/commands/doctor.js.map +1 -1
  14. package/dist/src/commands/monograph.d.ts.map +1 -1
  15. package/dist/src/commands/monograph.js +16 -1
  16. package/dist/src/commands/monograph.js.map +1 -1
  17. package/dist/src/orgrt/bash-timeout.d.ts +14 -0
  18. package/dist/src/orgrt/bash-timeout.d.ts.map +1 -0
  19. package/dist/src/orgrt/bash-timeout.js +18 -0
  20. package/dist/src/orgrt/bash-timeout.js.map +1 -0
  21. package/dist/src/orgrt/block-recheck.d.ts +30 -0
  22. package/dist/src/orgrt/block-recheck.d.ts.map +1 -0
  23. package/dist/src/orgrt/block-recheck.js +81 -0
  24. package/dist/src/orgrt/block-recheck.js.map +1 -0
  25. package/dist/src/orgrt/completion-gate.d.ts +4 -0
  26. package/dist/src/orgrt/completion-gate.d.ts.map +1 -1
  27. package/dist/src/orgrt/completion-gate.js +22 -2
  28. package/dist/src/orgrt/completion-gate.js.map +1 -1
  29. package/dist/src/orgrt/daemon.d.ts.map +1 -1
  30. package/dist/src/orgrt/daemon.js +6 -4
  31. package/dist/src/orgrt/daemon.js.map +1 -1
  32. package/dist/src/orgrt/decisions.d.ts +1 -1
  33. package/dist/src/orgrt/decisions.d.ts.map +1 -1
  34. package/dist/src/orgrt/decisions.js +14 -6
  35. package/dist/src/orgrt/decisions.js.map +1 -1
  36. package/dist/src/orgrt/mailbox.d.ts +14 -0
  37. package/dist/src/orgrt/mailbox.d.ts.map +1 -1
  38. package/dist/src/orgrt/mailbox.js +31 -1
  39. package/dist/src/orgrt/mailbox.js.map +1 -1
  40. package/dist/src/orgrt/sandbox-fault.d.ts +16 -6
  41. package/dist/src/orgrt/sandbox-fault.d.ts.map +1 -1
  42. package/dist/src/orgrt/sandbox-fault.js +78 -33
  43. package/dist/src/orgrt/sandbox-fault.js.map +1 -1
  44. package/dist/src/orgrt/session.d.ts +4 -3
  45. package/dist/src/orgrt/session.d.ts.map +1 -1
  46. package/dist/src/orgrt/session.js +24 -13
  47. package/dist/src/orgrt/session.js.map +1 -1
  48. package/dist/src/orgrt/task-dag.d.ts +8 -2
  49. package/dist/src/orgrt/task-dag.d.ts.map +1 -1
  50. package/dist/src/orgrt/task-dag.js +10 -4
  51. package/dist/src/orgrt/task-dag.js.map +1 -1
  52. package/dist/src/orgrt/types.d.ts +11 -0
  53. package/dist/src/orgrt/types.d.ts.map +1 -1
  54. package/dist/src/orgrt/types.js +18 -0
  55. package/dist/src/orgrt/types.js.map +1 -1
  56. package/dist/src/utils/resource-governor.d.ts.map +1 -1
  57. package/dist/src/utils/resource-governor.js +35 -2
  58. package/dist/src/utils/resource-governor.js.map +1 -1
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +6 -6
  61. package/.claude/skills/monodesign/SKILL.md +0 -257
  62. package/.claude/skills/monodesign/adapt.md +0 -53
  63. package/.claude/skills/monodesign/agents/monodesign-asset-producer.md +0 -100
  64. package/.claude/skills/monodesign/agents/monodesign-manual-edit-applier.md +0 -103
  65. package/.claude/skills/monodesign/animate.md +0 -65
  66. package/.claude/skills/monodesign/audit.md +0 -89
  67. package/.claude/skills/monodesign/bolder.md +0 -50
  68. package/.claude/skills/monodesign/clarify.md +0 -64
  69. package/.claude/skills/monodesign/colorize.md +0 -68
  70. package/.claude/skills/monodesign/craft.md +0 -51
  71. package/.claude/skills/monodesign/critique.md +0 -66
  72. package/.claude/skills/monodesign/delight.md +0 -47
  73. package/.claude/skills/monodesign/distill.md +0 -56
  74. package/.claude/skills/monodesign/document.md +0 -83
  75. package/.claude/skills/monodesign/extract.md +0 -74
  76. package/.claude/skills/monodesign/harden.md +0 -65
  77. package/.claude/skills/monodesign/init.md +0 -30
  78. package/.claude/skills/monodesign/layout.md +0 -36
  79. package/.claude/skills/monodesign/live.md +0 -34
  80. package/.claude/skills/monodesign/onboard.md +0 -50
  81. package/.claude/skills/monodesign/optimize.md +0 -64
  82. package/.claude/skills/monodesign/overdrive.md +0 -56
  83. package/.claude/skills/monodesign/polish.md +0 -68
  84. package/.claude/skills/monodesign/quieter.md +0 -57
  85. package/.claude/skills/monodesign/reference/adapt.md +0 -312
  86. package/.claude/skills/monodesign/reference/adapt.native.md +0 -58
  87. package/.claude/skills/monodesign/reference/android.md +0 -40
  88. package/.claude/skills/monodesign/reference/animate.md +0 -203
  89. package/.claude/skills/monodesign/reference/antipatterns-catalog.md +0 -410
  90. package/.claude/skills/monodesign/reference/audit.md +0 -135
  91. package/.claude/skills/monodesign/reference/audit.native.md +0 -139
  92. package/.claude/skills/monodesign/reference/bolder.md +0 -120
  93. package/.claude/skills/monodesign/reference/brand-workflow.md +0 -180
  94. package/.claude/skills/monodesign/reference/brand.md +0 -108
  95. package/.claude/skills/monodesign/reference/clarify.md +0 -288
  96. package/.claude/skills/monodesign/reference/codex.md +0 -105
  97. package/.claude/skills/monodesign/reference/cognitive-load.md +0 -106
  98. package/.claude/skills/monodesign/reference/color-and-contrast.md +0 -105
  99. package/.claude/skills/monodesign/reference/colorize.md +0 -257
  100. package/.claude/skills/monodesign/reference/component-specs.md +0 -260
  101. package/.claude/skills/monodesign/reference/component-states.md +0 -274
  102. package/.claude/skills/monodesign/reference/component-system.md +0 -358
  103. package/.claude/skills/monodesign/reference/copy-formulas.md +0 -160
  104. package/.claude/skills/monodesign/reference/craft.md +0 -123
  105. package/.claude/skills/monodesign/reference/critique.md +0 -780
  106. package/.claude/skills/monodesign/reference/delight.md +0 -302
  107. package/.claude/skills/monodesign/reference/design-principles.md +0 -246
  108. package/.claude/skills/monodesign/reference/distill.md +0 -111
  109. package/.claude/skills/monodesign/reference/document.md +0 -429
  110. package/.claude/skills/monodesign/reference/extract.md +0 -69
  111. package/.claude/skills/monodesign/reference/harden.md +0 -347
  112. package/.claude/skills/monodesign/reference/heuristics-scoring.md +0 -234
  113. package/.claude/skills/monodesign/reference/hooks.md +0 -92
  114. package/.claude/skills/monodesign/reference/image-prompts.md +0 -130
  115. package/.claude/skills/monodesign/reference/init.md +0 -221
  116. package/.claude/skills/monodesign/reference/interaction-design.md +0 -189
  117. package/.claude/skills/monodesign/reference/ios.md +0 -45
  118. package/.claude/skills/monodesign/reference/layout.md +0 -185
  119. package/.claude/skills/monodesign/reference/live.md +0 -710
  120. package/.claude/skills/monodesign/reference/motion-design.md +0 -109
  121. package/.claude/skills/monodesign/reference/onboard.md +0 -234
  122. package/.claude/skills/monodesign/reference/optimize.md +0 -258
  123. package/.claude/skills/monodesign/reference/overdrive.md +0 -130
  124. package/.claude/skills/monodesign/reference/personas.md +0 -179
  125. package/.claude/skills/monodesign/reference/polish.md +0 -241
  126. package/.claude/skills/monodesign/reference/pre-delivery-checklist.md +0 -108
  127. package/.claude/skills/monodesign/reference/product.md +0 -60
  128. package/.claude/skills/monodesign/reference/quieter.md +0 -99
  129. package/.claude/skills/monodesign/reference/responsive-design.md +0 -114
  130. package/.claude/skills/monodesign/reference/shape.md +0 -165
  131. package/.claude/skills/monodesign/reference/spatial-design.md +0 -100
  132. package/.claude/skills/monodesign/reference/teach.md +0 -10
  133. package/.claude/skills/monodesign/reference/token-architecture.md +0 -222
  134. package/.claude/skills/monodesign/reference/typeset.md +0 -301
  135. package/.claude/skills/monodesign/reference/typography.md +0 -159
  136. package/.claude/skills/monodesign/reference/ux-research.md +0 -143
  137. package/.claude/skills/monodesign/reference/ux-rules.md +0 -211
  138. package/.claude/skills/monodesign/reference/ux-writing.md +0 -107
  139. package/.claude/skills/monodesign/scripts/command-metadata.json +0 -94
  140. package/.claude/skills/monodesign/scripts/context-signals.mjs +0 -260
  141. package/.claude/skills/monodesign/scripts/context.mjs +0 -1065
  142. package/.claude/skills/monodesign/scripts/critique-storage.mjs +0 -416
  143. package/.claude/skills/monodesign/scripts/detect-csp.mjs +0 -193
  144. package/.claude/skills/monodesign/scripts/detect.mjs +0 -33
  145. package/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs +0 -1960
  146. package/.claude/skills/monodesign/scripts/detector/cli/main.mjs +0 -321
  147. package/.claude/skills/monodesign/scripts/detector/design-system.mjs +0 -814
  148. package/.claude/skills/monodesign/scripts/detector/detect-antipatterns-browser.js +0 -5628
  149. package/.claude/skills/monodesign/scripts/detector/detect-antipatterns.mjs +0 -50
  150. package/.claude/skills/monodesign/scripts/detector/engines/browser/detect-url.mjs +0 -259
  151. package/.claude/skills/monodesign/scripts/detector/engines/browser/drivers.mjs +0 -339
  152. package/.claude/skills/monodesign/scripts/detector/engines/regex/detect-text.mjs +0 -636
  153. package/.claude/skills/monodesign/scripts/detector/engines/static-html/css-cascade.mjs +0 -1016
  154. package/.claude/skills/monodesign/scripts/detector/engines/static-html/detect-html.mjs +0 -253
  155. package/.claude/skills/monodesign/scripts/detector/engines/visual/screenshot-contrast.mjs +0 -198
  156. package/.claude/skills/monodesign/scripts/detector/findings.mjs +0 -12
  157. package/.claude/skills/monodesign/scripts/detector/fix/css-regions.mjs +0 -181
  158. package/.claude/skills/monodesign/scripts/detector/fix/fixers.mjs +0 -373
  159. package/.claude/skills/monodesign/scripts/detector/fix/index.mjs +0 -426
  160. package/.claude/skills/monodesign/scripts/detector/node/file-system.mjs +0 -198
  161. package/.claude/skills/monodesign/scripts/detector/profile/profiler.mjs +0 -166
  162. package/.claude/skills/monodesign/scripts/detector/registry/antipatterns.mjs +0 -563
  163. package/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +0 -3024
  164. package/.claude/skills/monodesign/scripts/detector/shared/color.mjs +0 -124
  165. package/.claude/skills/monodesign/scripts/detector/shared/constants.mjs +0 -101
  166. package/.claude/skills/monodesign/scripts/detector/shared/fonts.mjs +0 -30
  167. package/.claude/skills/monodesign/scripts/detector/shared/inline-ignores.mjs +0 -148
  168. package/.claude/skills/monodesign/scripts/detector/shared/page.mjs +0 -7
  169. package/.claude/skills/monodesign/scripts/hook-admin.mjs +0 -694
  170. package/.claude/skills/monodesign/scripts/hook-before-edit.mjs +0 -516
  171. package/.claude/skills/monodesign/scripts/hook-lib.mjs +0 -1785
  172. package/.claude/skills/monodesign/scripts/hook.mjs +0 -61
  173. package/.claude/skills/monodesign/scripts/lib/design-parser.mjs +0 -809
  174. package/.claude/skills/monodesign/scripts/lib/is-generated.mjs +0 -69
  175. package/.claude/skills/monodesign/scripts/lib/monodesign-config.mjs +0 -640
  176. package/.claude/skills/monodesign/scripts/lib/monodesign-paths.mjs +0 -129
  177. package/.claude/skills/monodesign/scripts/lib/provider.mjs +0 -4
  178. package/.claude/skills/monodesign/scripts/lib/target-args.mjs +0 -42
  179. package/.claude/skills/monodesign/scripts/live/browser-script-parts.mjs +0 -50
  180. package/.claude/skills/monodesign/scripts/live/completion.mjs +0 -19
  181. package/.claude/skills/monodesign/scripts/live/event-validation.mjs +0 -137
  182. package/.claude/skills/monodesign/scripts/live/insert-ui.mjs +0 -458
  183. package/.claude/skills/monodesign/scripts/live/manual-apply.mjs +0 -939
  184. package/.claude/skills/monodesign/scripts/live/manual-edit-routes.mjs +0 -357
  185. package/.claude/skills/monodesign/scripts/live/manual-edits-buffer.mjs +0 -152
  186. package/.claude/skills/monodesign/scripts/live/session-store.mjs +0 -293
  187. package/.claude/skills/monodesign/scripts/live/svelte-component.mjs +0 -826
  188. package/.claude/skills/monodesign/scripts/live/sveltekit-adapter.mjs +0 -279
  189. package/.claude/skills/monodesign/scripts/live/ui-core.mjs +0 -180
  190. package/.claude/skills/monodesign/scripts/live/vocabulary.mjs +0 -36
  191. package/.claude/skills/monodesign/scripts/live-accept.mjs +0 -812
  192. package/.claude/skills/monodesign/scripts/live-browser-dom.js +0 -147
  193. package/.claude/skills/monodesign/scripts/live-browser-session.js +0 -124
  194. package/.claude/skills/monodesign/scripts/live-browser.js +0 -11213
  195. package/.claude/skills/monodesign/scripts/live-commit-manual-edits.mjs +0 -1241
  196. package/.claude/skills/monodesign/scripts/live-complete.mjs +0 -75
  197. package/.claude/skills/monodesign/scripts/live-copy-edit-agent.mjs +0 -683
  198. package/.claude/skills/monodesign/scripts/live-discard-manual-edits.mjs +0 -51
  199. package/.claude/skills/monodesign/scripts/live-inject.mjs +0 -596
  200. package/.claude/skills/monodesign/scripts/live-insert.mjs +0 -272
  201. package/.claude/skills/monodesign/scripts/live-manual-edit-evidence.mjs +0 -363
  202. package/.claude/skills/monodesign/scripts/live-poll.mjs +0 -384
  203. package/.claude/skills/monodesign/scripts/live-resume.mjs +0 -94
  204. package/.claude/skills/monodesign/scripts/live-server.mjs +0 -1210
  205. package/.claude/skills/monodesign/scripts/live-status.mjs +0 -61
  206. package/.claude/skills/monodesign/scripts/live-target.mjs +0 -30
  207. package/.claude/skills/monodesign/scripts/live-wrap.mjs +0 -884
  208. package/.claude/skills/monodesign/scripts/live.mjs +0 -297
  209. package/.claude/skills/monodesign/scripts/modern-screenshot.umd.js +0 -14
  210. package/.claude/skills/monodesign/scripts/palette.mjs +0 -635
  211. package/.claude/skills/monodesign/scripts/pin.mjs +0 -221
  212. package/.claude/skills/monodesign/shape.md +0 -71
  213. package/.claude/skills/monodesign/teach.md +0 -18
  214. package/.claude/skills/monodesign/typeset.md +0 -59
@@ -0,0 +1,497 @@
1
+ 'use strict';
2
+ // Where the hooks find @monoes/monograph, and how they rebuild the graph with
3
+ // it (#328). monograph-freshen.cjs, the post-edit rebuild in
4
+ // handlers/edit-handler.cjs and utils/monograph.cjs all resolve through here
5
+ // so they agree on one copy. A bare `import '@monoes/monograph'` only walks
6
+ // the project's node_modules, which misses the default npx setup entirely:
7
+ // there the only copy is the one bundled with the monomind CLI in npm's npx
8
+ // cache, or a global install.
9
+ //
10
+ // Resolution happens at hook time rather than being recorded by `init`: the
11
+ // npx cache directory changes with every CLI version and npm prunes it, so a
12
+ // recorded path goes stale, while scanning costs one readdir.
13
+
14
+ const path = require('path');
15
+ const fs = require('fs');
16
+ const os = require('os');
17
+ const { execFileSync, execSync, spawn } = require('child_process');
18
+ const { pathToFileURL } = require('url');
19
+ const { claimLock } = require('./fs-helpers.cjs');
20
+
21
+ const GLOBAL_FIX = 'npm i -g --allow-scripts=better-sqlite3 @monoes/monograph';
22
+ const STALE_LIMIT = 50;
23
+ const BUILD_LOG_MAX_BYTES = 1024 * 1024;
24
+ // Matched against an error's message and code only: a stack through
25
+ // better-sqlite3's JS (SQLITE_BUSY, say) is not a native-load failure.
26
+ const NATIVE_ERROR_RE = /NODE_MODULE_VERSION|bindings file|better_sqlite3\.node|compiled against a different Node|ERR_DLOPEN_FAILED/i;
27
+
28
+ function _readJson(p) {
29
+ try { return JSON.parse(fs.readFileSync(p, 'utf-8')); } catch (_) { return null; }
30
+ }
31
+
32
+ // The package's ESM entry file, read from its own package.json (its exports
33
+ // map has no "require" condition, so require.resolve can't find it).
34
+ function entryFromPkgDir(pkgDir) {
35
+ var pkg = _readJson(path.join(pkgDir, 'package.json'));
36
+ if (!pkg || pkg.name !== '@monoes/monograph') return null;
37
+ var dot = pkg.exports && pkg.exports['.'];
38
+ var rel = (typeof dot === 'string' ? dot : dot && (dot.import || dot.default)) || pkg.main;
39
+ if (!rel) return null;
40
+ var full = path.join(pkgDir, rel);
41
+ return fs.existsSync(full) ? { entry: full, pkgDir: pkgDir, version: String(pkg.version || '0') } : null;
42
+ }
43
+
44
+ function compareVersions(a, b) {
45
+ var pa = String(a).split(/[.-]/).map(function (x) { return parseInt(x, 10) || 0; });
46
+ var pb = String(b).split(/[.-]/).map(function (x) { return parseInt(x, 10) || 0; });
47
+ for (var i = 0; i < Math.max(pa.length, pb.length); i++) {
48
+ if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) - (pb[i] || 0);
49
+ }
50
+ return 0;
51
+ }
52
+
53
+ function _newest(found) {
54
+ found = found.filter(Boolean);
55
+ if (found.length === 0) return null;
56
+ found.sort(function (x, y) { return compareVersions(y.version, x.version); });
57
+ return found[0];
58
+ }
59
+
60
+ function _localCandidates(dir) {
61
+ return [
62
+ // Monorepo workspace build first: it carries unpublished fixes.
63
+ path.join(dir, 'packages', '@monomind', 'monograph'),
64
+ // The project IS the monograph package.
65
+ dir,
66
+ path.join(dir, 'node_modules', '@monoes', 'monograph'),
67
+ path.join(dir, 'node_modules', '@monomind', 'monograph'),
68
+ path.join(dir, 'node_modules', '.pnpm', 'node_modules', '@monoes', 'monograph'),
69
+ path.join(dir, 'packages', 'node_modules', '.pnpm', 'node_modules', '@monoes', 'monograph'),
70
+ // The copy nested under a local, unhoisted monomind CLI install.
71
+ path.join(dir, 'node_modules', '@monoes', 'monomindcli', 'node_modules', '@monoes', 'monograph'),
72
+ path.join(dir, 'node_modules', 'monomind', 'node_modules', '@monoes', 'monograph'),
73
+ ];
74
+ }
75
+
76
+ function _pnpmStore(dir) {
77
+ var base = path.join(dir, 'node_modules', '.pnpm');
78
+ var names;
79
+ try { names = fs.readdirSync(base).filter(function (e) { return e.indexOf('@monoes+monograph@') === 0; }); }
80
+ catch (_) { return null; }
81
+ return _newest(names.map(function (e) {
82
+ return entryFromPkgDir(path.join(base, e, 'node_modules', '@monoes', 'monograph'));
83
+ }));
84
+ }
85
+
86
+ function _resolveLocal(projectDir) {
87
+ var cands = _localCandidates(projectDir);
88
+ for (var i = 0; i < cands.length; i++) {
89
+ var hit = entryFromPkgDir(cands[i]);
90
+ if (hit) return hit;
91
+ }
92
+ var store = _pnpmStore(projectDir);
93
+ if (store) return store;
94
+ // Ancestor walk: what a bare specifier's node_modules lookup would find.
95
+ var dir = path.dirname(projectDir);
96
+ for (;;) {
97
+ var up = entryFromPkgDir(path.join(dir, 'node_modules', '@monoes', 'monograph'));
98
+ if (up) return up;
99
+ var parent = path.dirname(dir);
100
+ if (parent === dir) return null;
101
+ dir = parent;
102
+ }
103
+ }
104
+
105
+ var _globalRootCache;
106
+ function npmGlobalRoot() {
107
+ if (_globalRootCache !== undefined) return _globalRootCache;
108
+ try {
109
+ _globalRootCache = execSync('npm root -g', {
110
+ encoding: 'utf-8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'],
111
+ }).trim() || null;
112
+ } catch (_) { _globalRootCache = null; }
113
+ return _globalRootCache;
114
+ }
115
+
116
+ function _resolveGlobal(globalRoot) {
117
+ if (!globalRoot) return null;
118
+ var nested = path.join('node_modules', '@monoes', 'monograph');
119
+ var cands = [
120
+ path.join(globalRoot, '@monoes', 'monograph'),
121
+ path.join(globalRoot, 'monomind', nested),
122
+ path.join(globalRoot, 'monomind', 'node_modules', '@monoes', 'monomindcli', nested),
123
+ path.join(globalRoot, '@monoes', 'monomindcli', nested),
124
+ ];
125
+ for (var i = 0; i < cands.length; i++) {
126
+ var hit = entryFromPkgDir(cands[i]);
127
+ if (hit) return hit;
128
+ }
129
+ return null;
130
+ }
131
+
132
+ function npxCacheDir() {
133
+ if (process.env.npm_config_cache) return process.env.npm_config_cache;
134
+ if (process.platform === 'win32' && process.env.LOCALAPPDATA) {
135
+ return path.join(process.env.LOCALAPPDATA, 'npm-cache');
136
+ }
137
+ return path.join(os.homedir(), '.npm');
138
+ }
139
+
140
+ // The copy the MCP server's `npx monomind` / `npx @monoes/monomindcli` run
141
+ // installed. Newest version wins when several CLI versions are cached.
142
+ function _resolveNpxCache(cacheDir) {
143
+ var base = path.join(cacheDir, '_npx');
144
+ var dirs;
145
+ try { dirs = fs.readdirSync(base); } catch (_) { return null; }
146
+ return _newest(dirs.map(function (d) {
147
+ return entryFromPkgDir(path.join(base, d, 'node_modules', '@monoes', 'monograph'));
148
+ }));
149
+ }
150
+
151
+ /**
152
+ * Find @monoes/monograph for `projectDir`: the project's own install, then a
153
+ * global npm install (standalone or bundled with the monomind CLI), then the
154
+ * copy bundled with the CLI in the npx cache. Returns
155
+ * { entry, pkgDir, version, source: 'local'|'global'|'npx' } or null.
156
+ * Only absolute paths come back, never a bare specifier.
157
+ */
158
+ function resolveMonographEntry(projectDir, opts) {
159
+ opts = opts || {};
160
+ var hit = _resolveLocal(projectDir);
161
+ if (hit) { hit.source = 'local'; return hit; }
162
+ hit = _resolveGlobal(opts.globalRoot !== undefined ? opts.globalRoot : npmGlobalRoot());
163
+ if (hit) { hit.source = 'global'; return hit; }
164
+ hit = _resolveNpxCache(opts.npxCacheDir || npxCacheDir());
165
+ if (hit) { hit.source = 'npx'; return hit; }
166
+ return null;
167
+ }
168
+
169
+ // The monomind CLI, for `monomind monograph build` when no package resolves:
170
+ // the project's own bin, then PATH (a global install). Never `npx -y`.
171
+ function findMonomindBin(projectDir, pathEnv) {
172
+ var names = process.platform === 'win32' ? ['monomind.cmd', 'monomind.exe'] : ['monomind'];
173
+ var dirs = [path.join(projectDir, 'node_modules', '.bin')]
174
+ .concat(String(pathEnv !== undefined ? pathEnv : process.env.PATH || '').split(path.delimiter));
175
+ for (var i = 0; i < dirs.length; i++) {
176
+ if (!dirs[i]) continue;
177
+ for (var j = 0; j < names.length; j++) {
178
+ var p = path.join(dirs[i], names[j]);
179
+ try { if (fs.statSync(p).isFile()) return p; } catch (_) {}
180
+ }
181
+ }
182
+ return null;
183
+ }
184
+
185
+ function nativeFix(resolved, projectDir) {
186
+ if (!resolved || resolved.source !== 'local') return GLOBAL_FIX;
187
+ var pnpm = fs.existsSync(path.join(projectDir || '', 'pnpm-lock.yaml'));
188
+ return (pnpm ? 'pnpm' : 'npm') + ' rebuild better-sqlite3';
189
+ }
190
+
191
+ function _firstLine(msg) {
192
+ return String(msg || '').split('\n').filter(function (l) { return l.trim(); })[0] || 'unknown error';
193
+ }
194
+
195
+ // Load the better-sqlite3 that `resolved`'s copy would load. A global npm
196
+ // install on current npm skips its install script (allowScripts), leaving no
197
+ // binary; a Node upgrade leaves one built for the wrong ABI.
198
+ function checkNative(resolved, projectDir) {
199
+ try {
200
+ var bs = require.resolve('better-sqlite3', { paths: [path.dirname(resolved.entry)] });
201
+ var Database = require(bs);
202
+ new Database(':memory:').close();
203
+ return { ok: true };
204
+ } catch (e) {
205
+ return { ok: false, error: _firstLine(e && e.message), fix: nativeFix(resolved, projectDir) };
206
+ }
207
+ }
208
+
209
+ function _graphDir(projectDir) { return path.join(projectDir, '.monomind', 'graph'); }
210
+ function _statusPath(projectDir) { return path.join(_graphDir(projectDir), 'rebuild-status.json'); }
211
+
212
+ function readRebuildStatus(projectDir) { return _readJson(_statusPath(projectDir)); }
213
+
214
+ function _writeStatus(projectDir, status) {
215
+ try {
216
+ fs.mkdirSync(_graphDir(projectDir), { recursive: true });
217
+ fs.writeFileSync(_statusPath(projectDir), JSON.stringify(status));
218
+ } catch (_) {}
219
+ }
220
+
221
+ // Keep build.log bounded: past 1 MB it moves to build.log.1 (replacing the
222
+ // previous one), so a failing rebuild can't grow it forever.
223
+ function capBuildLog(projectDir) {
224
+ var logPath = path.join(_graphDir(projectDir), 'build.log');
225
+ try {
226
+ if (fs.statSync(logPath).size > BUILD_LOG_MAX_BYTES) fs.renameSync(logPath, logPath + '.1');
227
+ } catch (_) {}
228
+ }
229
+
230
+ /**
231
+ * Record a failed rebuild in rebuild-status.json and build.log. The same
232
+ * failure repeated only bumps `repeats` in the status file; build.log gets a
233
+ * line when the failure first appears or changes.
234
+ */
235
+ function recordRebuildFailure(projectDir, reason, message, fix) {
236
+ var prev = readRebuildStatus(projectDir) || {};
237
+ var line = '[monograph] rebuild failed (' + reason + '): ' + message + (fix ? ' — fix: ' + fix : '');
238
+ var same = prev.ok === false && prev.line === line;
239
+ _writeStatus(projectDir, {
240
+ ok: false, reason: reason, message: message, fix: fix || null, line: line,
241
+ at: Date.now(), since: same ? prev.since : Date.now(), repeats: same ? (prev.repeats || 1) + 1 : 1,
242
+ });
243
+ if (same) return;
244
+ try {
245
+ capBuildLog(projectDir);
246
+ fs.appendFileSync(path.join(_graphDir(projectDir), 'build.log'), new Date().toISOString() + ' ' + line + '\n');
247
+ } catch (_) {}
248
+ }
249
+
250
+ // Called by the rebuild child (see _childScript) when buildAsync throws.
251
+ function recordBuildError(projectDir, err, source) {
252
+ var msg = _firstLine(err && (err.message || err));
253
+ if (NATIVE_ERROR_RE.test(String(err && err.message || err) + ' ' + String(err && err.code || ''))) {
254
+ recordRebuildFailure(projectDir, 'native', 'better-sqlite3 failed to load: ' + msg, nativeFix({ source: source }, projectDir));
255
+ } else {
256
+ recordRebuildFailure(projectDir, 'build', msg, null);
257
+ }
258
+ }
259
+
260
+ function recordRebuildSuccess(projectDir) { _writeStatus(projectDir, { ok: true, at: Date.now() }); }
261
+
262
+ function _pidAlive(pid) {
263
+ try { process.kill(pid, 0); return true; } catch (e) { return e.code === 'EPERM'; }
264
+ }
265
+
266
+ /**
267
+ * claimLock, but a lock whose PID has exited is stale once it is `minAgeMs`
268
+ * old (a crashed or finished rebuild), not only after `maxAgeMs`.
269
+ */
270
+ function claimRebuildLock(lockPath, minAgeMs, maxAgeMs) {
271
+ try {
272
+ var st = fs.statSync(lockPath);
273
+ var pid = parseInt(fs.readFileSync(lockPath, 'utf-8'), 10);
274
+ if (Date.now() - st.mtimeMs >= minAgeMs && !(pid > 0 && _pidAlive(pid))) {
275
+ var claimed = lockPath + '.' + process.pid + '.' + Date.now() + '.dead';
276
+ fs.renameSync(lockPath, claimed);
277
+ // Another process replaced the lock between the stat and the rename:
278
+ // that lock is live, so put it back.
279
+ var st2 = fs.statSync(claimed);
280
+ if (st2.ino !== st.ino || st2.mtimeMs !== st.mtimeMs) { try { fs.linkSync(claimed, lockPath); } catch (_) {} }
281
+ fs.unlinkSync(claimed);
282
+ }
283
+ } catch (_) { /* no lock, or lost a race — claimLock decides */ }
284
+ return claimLock(lockPath, maxAgeMs);
285
+ }
286
+
287
+ function _childScript(projectDir, resolved, cleanup, vacuum) {
288
+ var j = JSON.stringify;
289
+ var vacuumJs = !vacuum ? '' : `
290
+ try {
291
+ const dbPath = ${j(path.join(projectDir, '.monomind', 'monograph.db'))};
292
+ const fileMB = statSync(dbPath).size / 1024 / 1024;
293
+ // Array argv, no shell: a project path can't inject a command (P3-8).
294
+ const liveMB = parseInt(execFileSync('sqlite3', [dbPath, 'SELECT SUM(pgsize)/1024/1024 FROM dbstat;'],
295
+ { encoding: 'utf-8', timeout: 30000 }).trim(), 10);
296
+ if (fileMB > 100 && liveMB / fileMB < 0.5) execFileSync('sqlite3', [dbPath, 'VACUUM;'], { timeout: 120000 });
297
+ } catch (_) {}`;
298
+ return `
299
+ import { unlinkSync, statSync } from 'fs';
300
+ import { execFileSync } from 'child_process';
301
+ import { createRequire } from 'module';
302
+ const status = createRequire(${j(pathToFileURL(__filename).href)})(${j(__filename)});
303
+ try {
304
+ const { buildAsync } = await import(${j(pathToFileURL(resolved.entry).href)});
305
+ await buildAsync(${j(projectDir)});
306
+ status.recordRebuildSuccess(${j(projectDir)});${vacuumJs}
307
+ } catch (err) {
308
+ status.recordBuildError(${j(projectDir)}, err, ${j(resolved.source)});
309
+ process.exitCode = 1;
310
+ } finally {
311
+ for (const p of ${j(cleanup)}) { try { unlinkSync(p); } catch {} }
312
+ }`;
313
+ }
314
+
315
+ /**
316
+ * Start a detached background rebuild of `projectDir`'s graph; never waits
317
+ * for it. Imports the resolved package by absolute file URL; with nothing
318
+ * resolvable, runs `monomind monograph build` from the project or PATH; with
319
+ * neither, records an 'unresolvable' failure. The child's PID replaces the
320
+ * caller's in `opts.lockPath`, and the module child removes the lock and
321
+ * `opts.cleanup` files when done.
322
+ * Returns { mode: 'module'|'cli'|'none', pid?, resolved? }.
323
+ */
324
+ function startRebuild(projectDir, opts) {
325
+ opts = opts || {};
326
+ var resolved = opts.resolved !== undefined ? opts.resolved : resolveMonographEntry(projectDir);
327
+ var bin = resolved ? null : findMonomindBin(projectDir);
328
+ if (!resolved && !bin) {
329
+ recordRebuildFailure(projectDir, 'unresolvable',
330
+ '@monoes/monograph not found in the project, the global npm root or the npx cache', GLOBAL_FIX);
331
+ return { mode: 'none' };
332
+ }
333
+ var graphDir = _graphDir(projectDir);
334
+ try { fs.mkdirSync(graphDir, { recursive: true }); } catch (_) {}
335
+ capBuildLog(projectDir);
336
+ var logFd;
337
+ try { logFd = fs.openSync(path.join(graphDir, 'build.log'), 'a'); } catch (_) { logFd = 'ignore'; }
338
+ var cleanup = (opts.lockPath ? [opts.lockPath] : []).concat(opts.cleanup || []);
339
+ var child;
340
+ if (resolved) {
341
+ child = spawn(process.execPath,
342
+ ['--input-type=module', '--eval', _childScript(projectDir, resolved, cleanup, opts.vacuum)],
343
+ { detached: true, stdio: ['ignore', logFd, logFd], cwd: projectDir });
344
+ } else {
345
+ child = spawn(bin, ['monograph', 'build', '--path', projectDir], {
346
+ detached: true, stdio: ['ignore', logFd, logFd], cwd: projectDir,
347
+ shell: process.platform === 'win32',
348
+ });
349
+ }
350
+ child.on('error', function () {});
351
+ child.unref();
352
+ if (typeof logFd === 'number') { try { fs.closeSync(logFd); } catch (_) {} }
353
+ if (opts.lockPath && child.pid) { try { fs.writeFileSync(opts.lockPath, String(child.pid)); } catch (_) {} }
354
+ return { mode: resolved ? 'module' : 'cli', pid: child.pid, resolved: resolved };
355
+ }
356
+
357
+ function _suppressSqliteWarning(fn) {
358
+ var orig = process.emitWarning;
359
+ process.emitWarning = function (w) {
360
+ if (/SQLite is an experimental feature/.test(String(w && w.message || w))) return;
361
+ return orig.apply(process, arguments);
362
+ };
363
+ try { return fn(); } finally { process.emitWarning = orig; }
364
+ }
365
+
366
+ var COMMIT_SQL = "SELECT value FROM index_meta WHERE key IN ('last_commit_hash','lastCommit') ORDER BY key = 'last_commit_hash' DESC LIMIT 1";
367
+
368
+ // The commit the graph was built at, read with node:sqlite so it works even
369
+ // when @monoes/monograph or its native addon is what's missing.
370
+ function readIndexedCommit(dbPath) {
371
+ try {
372
+ return _suppressSqliteWarning(function () {
373
+ var DatabaseSync = require('node:sqlite').DatabaseSync;
374
+ var db = new DatabaseSync(dbPath, { readOnly: true });
375
+ try { var row = db.prepare(COMMIT_SQL).get(); return row && row.value ? String(row.value) : null; }
376
+ finally { db.close(); }
377
+ });
378
+ } catch (_) { return null; }
379
+ }
380
+
381
+ function commitsBehind(projectDir, commit) {
382
+ if (!commit || !/^[0-9a-f]{7,40}$/i.test(commit)) return null;
383
+ try {
384
+ var n = parseInt(execFileSync('git', ['rev-list', '--count', commit + '..HEAD'], {
385
+ cwd: projectDir, encoding: 'utf-8', timeout: 2000, stdio: ['ignore', 'pipe', 'ignore'],
386
+ }).trim(), 10);
387
+ return isNaN(n) ? null : n;
388
+ } catch (_) { return null; }
389
+ }
390
+
391
+ /**
392
+ * Everything `doctor` and the SessionStart warning need, from the hooks' point
393
+ * of view: { resolved, cliBin, native, dbExists, commit, behind, canRebuild,
394
+ * problem, fix, lastStatus }. `problem` says why the hooks can't rebuild.
395
+ */
396
+ function diagnose(projectDir, opts) {
397
+ opts = opts || {};
398
+ var resolved = resolveMonographEntry(projectDir, opts);
399
+ var cliBin = resolved ? null : findMonomindBin(projectDir, opts.pathEnv);
400
+ var native = resolved ? checkNative(resolved, projectDir) : null;
401
+ var dbPath = path.join(projectDir, '.monomind', 'monograph.db');
402
+ var dbExists = fs.existsSync(dbPath);
403
+ var commit = dbExists ? readIndexedCommit(dbPath) : null;
404
+ var problem = null;
405
+ var fix = null;
406
+ if (!resolved && !cliBin) {
407
+ problem = '@monoes/monograph not found by the hooks (project, global npm root, npx cache)';
408
+ fix = GLOBAL_FIX;
409
+ } else if (native && !native.ok) {
410
+ problem = 'better-sqlite3 for ' + resolved.pkgDir + ' failed to load: ' + native.error;
411
+ fix = native.fix;
412
+ }
413
+ return {
414
+ resolved: resolved, cliBin: cliBin, native: native, dbExists: dbExists, commit: commit,
415
+ behind: commitsBehind(projectDir, commit), canRebuild: !problem, problem: problem, fix: fix,
416
+ lastStatus: readRebuildStatus(projectDir),
417
+ };
418
+ }
419
+
420
+ // The one-line SessionStart warning, or null when there is nothing to say:
421
+ // shown when the hooks can't build a missing graph, or the graph is behind
422
+ // HEAD (or its commit can't be read) and the hooks can't rebuild it or the
423
+ // last rebuild failed.
424
+ function sessionWarning(diag) {
425
+ if (!diag.dbExists) {
426
+ return diag.problem ? '[MONOGRAPH_WARN] The hooks cannot build the monograph graph: ' + diag.problem + ' — run: ' + diag.fix : null;
427
+ }
428
+ if (diag.behind === 0) return null;
429
+ var last = diag.lastStatus && diag.lastStatus.ok === false ? diag.lastStatus : null;
430
+ var problem = diag.problem || (last && ('last rebuild failed: ' + last.message));
431
+ if (!problem) return null;
432
+ var fix = diag.fix || (last && last.fix) || 'see .monomind/graph/build.log';
433
+ var age = diag.behind == null ? 'may be stale' : 'is ' + diag.behind + ' commit(s) behind HEAD';
434
+ return '[MONOGRAPH_WARN] The monograph graph ' + age + ' and the hooks cannot rebuild it: ' +
435
+ problem + ' — run: ' + fix;
436
+ }
437
+
438
+ /**
439
+ * Once per cause, say that the grep gate and graph hints are off: the graph
440
+ * DB exists but the hooks can't open it (`db` null), or it is more than 50
441
+ * commits behind. Later prompts with the same cause return null.
442
+ */
443
+ function graphOffNoticeOnce(projectDir, db) {
444
+ var dbPath = path.join(projectDir, '.monomind', 'monograph.db');
445
+ var key;
446
+ var behind = null;
447
+ var commit = null;
448
+ if (!db) {
449
+ if (!fs.existsSync(dbPath)) return null;
450
+ key = 'unloadable';
451
+ } else {
452
+ try { var row = db.prepare(COMMIT_SQL).get(); commit = row && row.value; } catch (_) { return null; }
453
+ if (!commit) return null;
454
+ key = 'stale:' + commit;
455
+ }
456
+ var marker = path.join(_graphDir(projectDir), 'gate-off-notice.json');
457
+ var prev = _readJson(marker);
458
+ if (prev && prev.key === key) return null;
459
+ var msg;
460
+ if (!db) {
461
+ msg = '[MONOGRAPH_OFF] The hooks cannot load @monoes/monograph, so the grep gate and [MONOGRAPH] hints are off. Fix: ' + GLOBAL_FIX;
462
+ } else {
463
+ behind = commitsBehind(projectDir, commit);
464
+ if (behind == null || behind <= STALE_LIMIT) return null;
465
+ msg = '[MONOGRAPH_OFF] The monograph graph is ' + behind + ' commits behind HEAD (limit ' + STALE_LIMIT +
466
+ '), so the grep gate and [MONOGRAPH] hints are off until it is rebuilt. Rebuild: npx monomind monograph build (or mcp__monomind__monograph_build)';
467
+ }
468
+ try {
469
+ fs.mkdirSync(path.dirname(marker), { recursive: true });
470
+ fs.writeFileSync(marker, JSON.stringify({ key: key, at: Date.now() }));
471
+ } catch (_) {}
472
+ return msg;
473
+ }
474
+
475
+ module.exports = {
476
+ GLOBAL_FIX,
477
+ STALE_LIMIT,
478
+ BUILD_LOG_MAX_BYTES,
479
+ entryFromPkgDir,
480
+ resolveMonographEntry,
481
+ findMonomindBin,
482
+ npmGlobalRoot,
483
+ npxCacheDir,
484
+ checkNative,
485
+ claimRebuildLock,
486
+ startRebuild,
487
+ capBuildLog,
488
+ recordRebuildFailure,
489
+ recordBuildError,
490
+ recordRebuildSuccess,
491
+ readRebuildStatus,
492
+ readIndexedCommit,
493
+ commitsBehind,
494
+ diagnose,
495
+ sessionWarning,
496
+ graphOffNoticeOnce,
497
+ };
@@ -22,59 +22,16 @@ process.emitWarning = function (warning) {
22
22
  };
23
23
 
24
24
  // @monoes/monograph is "type":"module" with an exports map that has no
25
- // "require" condition — a bare `require('@monoes/monograph')` (or
26
- // require() of its package directory) always throws "No exports main
27
- // defined", regardless of whether the package is actually installed.
28
- // require()-ing the package's *resolved entry file* directly bypasses the
29
- // exports-map restriction and works via Node's require(esm) support (this
30
- // codebase targets Node 20+, which has it). Reads the entry path from the
31
- // package's own package.json instead of hardcoding "dist/src/index.js" so
32
- // this survives a future monograph dist-layout change.
33
- function _resolvePkgEntryFile(pkgDir) {
34
- try {
35
- var pkg = JSON.parse(fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf-8'));
36
- var entry = (pkg.exports && pkg.exports['.'] && (pkg.exports['.'].import || pkg.exports['.'].default)) || pkg.main;
37
- if (!entry) return null;
38
- var full = path.join(pkgDir, entry);
39
- return fs.existsSync(full) ? full : null;
40
- } catch (e) { return null; }
41
- }
42
-
25
+ // "require" condition — a bare `require('@monoes/monograph')` always throws
26
+ // "No exports main defined". require()-ing the package's *resolved entry
27
+ // file* directly works via Node's require(esm) support. The entry comes from
28
+ // monograph-resolve.cjs, the one resolution every hook uses: project install,
29
+ // global npm root, then the copy bundled with the CLI in the npx cache (#328).
43
30
  function _requireMonograph() {
44
- var candidates = [
45
- path.join(CWD, 'node_modules/.pnpm/node_modules/@monoes/monograph'),
46
- path.join(CWD, 'packages/node_modules/.pnpm/node_modules/@monoes/monograph'),
47
- path.join(CWD, 'node_modules/@monoes/monograph'),
48
- ];
49
- for (var i = 0; i < candidates.length; i++) {
50
- var entry = fs.existsSync(candidates[i]) ? _resolvePkgEntryFile(candidates[i]) : null;
51
- if (entry) { try { return require(entry); } catch (e) {} }
52
- }
53
- // Ancestor-directory search — the equivalent of bare `require('@monoes/
54
- // monograph')`'s own node_modules walk, needed since that call form can
55
- // never succeed against this package's exports map.
56
- var dir = CWD;
57
- for (;;) {
58
- var pkgDir = path.join(dir, 'node_modules', '@monoes', 'monograph');
59
- var entry = fs.existsSync(pkgDir) ? _resolvePkgEntryFile(pkgDir) : null;
60
- if (entry) { try { return require(entry); } catch (e) {} break; }
61
- var parent = path.dirname(dir);
62
- if (parent === dir) break;
63
- dir = parent;
64
- }
65
- // Global npm install fallback (e.g. `npm install -g @monoes/monograph`).
66
- // Mirrors monograph-freshen.cjs's resolveMonographEntry(), which already
67
- // checks this — without it, a global-only install builds the graph fine
68
- // (via that script) but every hook-side consumer of this function
69
- // (graph-status, inline suggestions, micro-agents) can never find it.
70
31
  try {
71
- var { execSync } = require('child_process');
72
- var globalRoot = execSync('npm root -g', { encoding: 'utf-8', timeout: 5000 }).trim();
73
- var globalPkgDir = path.join(globalRoot, '@monoes', 'monograph');
74
- var globalEntry = fs.existsSync(globalPkgDir) ? _resolvePkgEntryFile(globalPkgDir) : null;
75
- if (globalEntry) return require(globalEntry);
76
- } catch (e) {}
77
- return null;
32
+ var hit = require('./monograph-resolve.cjs').resolveMonographEntry(CWD);
33
+ return hit ? require(hit.entry) : null;
34
+ } catch (e) { return null; }
78
35
  }
79
36
 
80
37
  // Memoized at module scope — opening monograph.db can take 7-10s.
package/README.md CHANGED
@@ -414,7 +414,7 @@ Everything runs from inside Claude Code via slash commands. Here's the highlight
414
414
  | Package | npm | Purpose |
415
415
  |---|---|---|
416
416
  | `monomind` | [![npm](https://img.shields.io/npm/v/monomind?style=flat-square&color=00D2AA)](https://www.npmjs.com/package/monomind) | Umbrella shim — **install this one** |
417
- | `@monoes/monomindcli` | [![npm](https://img.shields.io/npm/v/@monoes/monomindcli?style=flat-square&color=4F46E5)](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (38 commands, MCP server) |
417
+ | `@monoes/monomindcli` | [![npm](https://img.shields.io/npm/v/@monoes/monomindcli?style=flat-square&color=4F46E5)](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (32 commands, MCP server) |
418
418
  | `@monoes/monograph` | [![npm](https://img.shields.io/npm/v/@monoes/monograph?style=flat-square&color=F59E0B)](https://www.npmjs.com/package/@monoes/monograph) | Code knowledge graph (tree-sitter + SQLite) |
419
419
  | `@monoes/memory` | [![npm](https://img.shields.io/npm/v/@monoes/memory?style=flat-square&color=8B5CF6)](https://www.npmjs.com/package/@monoes/memory) | Persistent memory backends (SQLite + vectors) |
420
420
  | `@monoes/hooks` | [![npm](https://img.shields.io/npm/v/@monoes/hooks?style=flat-square&color=10B981)](https://www.npmjs.com/package/@monoes/hooks) | Hook registry + 9 on-demand workers |
@@ -0,0 +1,8 @@
1
+ import type { HealthCheck } from './doctor-env-checks.js';
2
+ export interface ResolveOptions {
3
+ globalRoot?: string | null;
4
+ npxCacheDir?: string;
5
+ pathEnv?: string;
6
+ }
7
+ export declare function checkHookMonograph(cwd?: string, opts?: ResolveOptions): Promise<HealthCheck>;
8
+ //# sourceMappingURL=doctor-hook-monograph-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-hook-monograph-checks.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor-hook-monograph-checks.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1D,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiCD,wBAAsB,kBAAkB,CACtC,GAAG,GAAE,MAAsB,EAC3B,IAAI,CAAC,EAAE,cAAc,GACpB,OAAO,CAAC,WAAW,CAAC,CA4CtB"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Doctor — can the hooks keep the graph fresh? (#328)
3
+ *
4
+ * The MCP server brings its own @monoes/monograph, but the hooks
5
+ * (monograph-freshen.cjs at SessionStart, the post-edit rebuild, the grep gate
6
+ * and search hints) resolve their own copy. When they can't, the graph goes
7
+ * stale without a word and, past 50 commits, the gate and hints switch off.
8
+ * This check runs the hooks' own resolver (the project's copy of
9
+ * utils/monograph-resolve.cjs, else the one bundled with this package), so it
10
+ * reports exactly what the hooks see.
11
+ */
12
+ import { existsSync } from 'node:fs';
13
+ import { createRequire } from 'node:module';
14
+ import { dirname, join } from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+ const NAME = 'Hook graph rebuild';
17
+ const REL = join('.claude', 'helpers', 'utils', 'monograph-resolve.cjs');
18
+ const HERE = dirname(fileURLToPath(import.meta.url));
19
+ function loadResolver(cwd) {
20
+ const candidates = [
21
+ join(cwd, REL),
22
+ // src/commands → ../.. is the package root; dist/src/commands → ../../..
23
+ join(HERE, '..', '..', REL),
24
+ join(HERE, '..', '..', '..', REL),
25
+ ];
26
+ const file = candidates.find((p) => existsSync(p));
27
+ try {
28
+ return file ? createRequire(import.meta.url)(file) : null;
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ export async function checkHookMonograph(cwd = process.cwd(), opts) {
35
+ const mod = loadResolver(cwd);
36
+ if (!mod) {
37
+ return {
38
+ name: NAME,
39
+ status: 'warn',
40
+ message: 'utils/monograph-resolve.cjs is missing, so the hooks cannot rebuild the graph',
41
+ fix: 'npx monomind init upgrade',
42
+ };
43
+ }
44
+ const d = mod.diagnose(cwd, opts);
45
+ const limit = mod.STALE_LIMIT;
46
+ const pastLimit = d.dbExists && d.behind !== null && d.behind > limit;
47
+ if (!d.canRebuild) {
48
+ return {
49
+ name: NAME,
50
+ status: pastLimit ? 'fail' : 'warn',
51
+ message: pastLimit
52
+ ? `Graph ${d.behind} commits behind HEAD and the hooks can't rebuild it: ${d.problem}`
53
+ : `The hooks can't rebuild the graph: ${d.problem}`,
54
+ fix: d.fix ?? undefined,
55
+ };
56
+ }
57
+ if (pastLimit) {
58
+ return {
59
+ name: NAME,
60
+ status: 'warn',
61
+ message: `Graph ${d.behind} commits behind HEAD (limit ${limit}): the grep gate and search hints are off until it is rebuilt`,
62
+ fix: 'npx monomind monograph build',
63
+ };
64
+ }
65
+ if (d.lastStatus && d.lastStatus.ok === false) {
66
+ const times = (d.lastStatus.repeats ?? 1) > 1 ? ` (${d.lastStatus.repeats}x)` : '';
67
+ return {
68
+ name: NAME,
69
+ status: 'warn',
70
+ message: `Last hook rebuild failed${times}: ${d.lastStatus.message}`,
71
+ fix: d.lastStatus.fix ?? 'cat .monomind/graph/build.log',
72
+ };
73
+ }
74
+ const via = d.resolved
75
+ ? `@monoes/monograph v${d.resolved.version} (${d.resolved.source})`
76
+ : `monomind monograph build (${d.cliBin})`;
77
+ return { name: NAME, status: 'pass', message: `Hooks rebuild the graph with ${via}` };
78
+ }
79
+ //# sourceMappingURL=doctor-hook-monograph-checks.js.map