@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.
- package/.claude/helpers/handlers/edit-handler.cjs +14 -12
- package/.claude/helpers/handlers/route-handler.cjs +6 -0
- package/.claude/helpers/monograph-freshen.cjs +31 -113
- package/.claude/helpers/utils/monograph-resolve.cjs +497 -0
- package/.claude/helpers/utils/monograph.cjs +8 -51
- package/README.md +1 -1
- package/dist/src/commands/doctor-hook-monograph-checks.d.ts +8 -0
- package/dist/src/commands/doctor-hook-monograph-checks.d.ts.map +1 -0
- package/dist/src/commands/doctor-hook-monograph-checks.js +79 -0
- package/dist/src/commands/doctor-hook-monograph-checks.js.map +1 -0
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +4 -1
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/monograph.d.ts.map +1 -1
- package/dist/src/commands/monograph.js +16 -1
- package/dist/src/commands/monograph.js.map +1 -1
- package/dist/src/orgrt/bash-timeout.d.ts +14 -0
- package/dist/src/orgrt/bash-timeout.d.ts.map +1 -0
- package/dist/src/orgrt/bash-timeout.js +18 -0
- package/dist/src/orgrt/bash-timeout.js.map +1 -0
- package/dist/src/orgrt/block-recheck.d.ts +30 -0
- package/dist/src/orgrt/block-recheck.d.ts.map +1 -0
- package/dist/src/orgrt/block-recheck.js +81 -0
- package/dist/src/orgrt/block-recheck.js.map +1 -0
- package/dist/src/orgrt/completion-gate.d.ts +4 -0
- package/dist/src/orgrt/completion-gate.d.ts.map +1 -1
- package/dist/src/orgrt/completion-gate.js +22 -2
- package/dist/src/orgrt/completion-gate.js.map +1 -1
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +6 -4
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/decisions.d.ts +1 -1
- package/dist/src/orgrt/decisions.d.ts.map +1 -1
- package/dist/src/orgrt/decisions.js +14 -6
- package/dist/src/orgrt/decisions.js.map +1 -1
- package/dist/src/orgrt/mailbox.d.ts +14 -0
- package/dist/src/orgrt/mailbox.d.ts.map +1 -1
- package/dist/src/orgrt/mailbox.js +31 -1
- package/dist/src/orgrt/mailbox.js.map +1 -1
- package/dist/src/orgrt/sandbox-fault.d.ts +16 -6
- package/dist/src/orgrt/sandbox-fault.d.ts.map +1 -1
- package/dist/src/orgrt/sandbox-fault.js +78 -33
- package/dist/src/orgrt/sandbox-fault.js.map +1 -1
- package/dist/src/orgrt/session.d.ts +4 -3
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +24 -13
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/task-dag.d.ts +8 -2
- package/dist/src/orgrt/task-dag.d.ts.map +1 -1
- package/dist/src/orgrt/task-dag.js +10 -4
- package/dist/src/orgrt/task-dag.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +11 -0
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +18 -0
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/utils/resource-governor.d.ts.map +1 -1
- package/dist/src/utils/resource-governor.js +35 -2
- package/dist/src/utils/resource-governor.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/.claude/skills/monodesign/SKILL.md +0 -257
- package/.claude/skills/monodesign/adapt.md +0 -53
- package/.claude/skills/monodesign/agents/monodesign-asset-producer.md +0 -100
- package/.claude/skills/monodesign/agents/monodesign-manual-edit-applier.md +0 -103
- package/.claude/skills/monodesign/animate.md +0 -65
- package/.claude/skills/monodesign/audit.md +0 -89
- package/.claude/skills/monodesign/bolder.md +0 -50
- package/.claude/skills/monodesign/clarify.md +0 -64
- package/.claude/skills/monodesign/colorize.md +0 -68
- package/.claude/skills/monodesign/craft.md +0 -51
- package/.claude/skills/monodesign/critique.md +0 -66
- package/.claude/skills/monodesign/delight.md +0 -47
- package/.claude/skills/monodesign/distill.md +0 -56
- package/.claude/skills/monodesign/document.md +0 -83
- package/.claude/skills/monodesign/extract.md +0 -74
- package/.claude/skills/monodesign/harden.md +0 -65
- package/.claude/skills/monodesign/init.md +0 -30
- package/.claude/skills/monodesign/layout.md +0 -36
- package/.claude/skills/monodesign/live.md +0 -34
- package/.claude/skills/monodesign/onboard.md +0 -50
- package/.claude/skills/monodesign/optimize.md +0 -64
- package/.claude/skills/monodesign/overdrive.md +0 -56
- package/.claude/skills/monodesign/polish.md +0 -68
- package/.claude/skills/monodesign/quieter.md +0 -57
- package/.claude/skills/monodesign/reference/adapt.md +0 -312
- package/.claude/skills/monodesign/reference/adapt.native.md +0 -58
- package/.claude/skills/monodesign/reference/android.md +0 -40
- package/.claude/skills/monodesign/reference/animate.md +0 -203
- package/.claude/skills/monodesign/reference/antipatterns-catalog.md +0 -410
- package/.claude/skills/monodesign/reference/audit.md +0 -135
- package/.claude/skills/monodesign/reference/audit.native.md +0 -139
- package/.claude/skills/monodesign/reference/bolder.md +0 -120
- package/.claude/skills/monodesign/reference/brand-workflow.md +0 -180
- package/.claude/skills/monodesign/reference/brand.md +0 -108
- package/.claude/skills/monodesign/reference/clarify.md +0 -288
- package/.claude/skills/monodesign/reference/codex.md +0 -105
- package/.claude/skills/monodesign/reference/cognitive-load.md +0 -106
- package/.claude/skills/monodesign/reference/color-and-contrast.md +0 -105
- package/.claude/skills/monodesign/reference/colorize.md +0 -257
- package/.claude/skills/monodesign/reference/component-specs.md +0 -260
- package/.claude/skills/monodesign/reference/component-states.md +0 -274
- package/.claude/skills/monodesign/reference/component-system.md +0 -358
- package/.claude/skills/monodesign/reference/copy-formulas.md +0 -160
- package/.claude/skills/monodesign/reference/craft.md +0 -123
- package/.claude/skills/monodesign/reference/critique.md +0 -780
- package/.claude/skills/monodesign/reference/delight.md +0 -302
- package/.claude/skills/monodesign/reference/design-principles.md +0 -246
- package/.claude/skills/monodesign/reference/distill.md +0 -111
- package/.claude/skills/monodesign/reference/document.md +0 -429
- package/.claude/skills/monodesign/reference/extract.md +0 -69
- package/.claude/skills/monodesign/reference/harden.md +0 -347
- package/.claude/skills/monodesign/reference/heuristics-scoring.md +0 -234
- package/.claude/skills/monodesign/reference/hooks.md +0 -92
- package/.claude/skills/monodesign/reference/image-prompts.md +0 -130
- package/.claude/skills/monodesign/reference/init.md +0 -221
- package/.claude/skills/monodesign/reference/interaction-design.md +0 -189
- package/.claude/skills/monodesign/reference/ios.md +0 -45
- package/.claude/skills/monodesign/reference/layout.md +0 -185
- package/.claude/skills/monodesign/reference/live.md +0 -710
- package/.claude/skills/monodesign/reference/motion-design.md +0 -109
- package/.claude/skills/monodesign/reference/onboard.md +0 -234
- package/.claude/skills/monodesign/reference/optimize.md +0 -258
- package/.claude/skills/monodesign/reference/overdrive.md +0 -130
- package/.claude/skills/monodesign/reference/personas.md +0 -179
- package/.claude/skills/monodesign/reference/polish.md +0 -241
- package/.claude/skills/monodesign/reference/pre-delivery-checklist.md +0 -108
- package/.claude/skills/monodesign/reference/product.md +0 -60
- package/.claude/skills/monodesign/reference/quieter.md +0 -99
- package/.claude/skills/monodesign/reference/responsive-design.md +0 -114
- package/.claude/skills/monodesign/reference/shape.md +0 -165
- package/.claude/skills/monodesign/reference/spatial-design.md +0 -100
- package/.claude/skills/monodesign/reference/teach.md +0 -10
- package/.claude/skills/monodesign/reference/token-architecture.md +0 -222
- package/.claude/skills/monodesign/reference/typeset.md +0 -301
- package/.claude/skills/monodesign/reference/typography.md +0 -159
- package/.claude/skills/monodesign/reference/ux-research.md +0 -143
- package/.claude/skills/monodesign/reference/ux-rules.md +0 -211
- package/.claude/skills/monodesign/reference/ux-writing.md +0 -107
- package/.claude/skills/monodesign/scripts/command-metadata.json +0 -94
- package/.claude/skills/monodesign/scripts/context-signals.mjs +0 -260
- package/.claude/skills/monodesign/scripts/context.mjs +0 -1065
- package/.claude/skills/monodesign/scripts/critique-storage.mjs +0 -416
- package/.claude/skills/monodesign/scripts/detect-csp.mjs +0 -193
- package/.claude/skills/monodesign/scripts/detect.mjs +0 -33
- package/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs +0 -1960
- package/.claude/skills/monodesign/scripts/detector/cli/main.mjs +0 -321
- package/.claude/skills/monodesign/scripts/detector/design-system.mjs +0 -814
- package/.claude/skills/monodesign/scripts/detector/detect-antipatterns-browser.js +0 -5628
- package/.claude/skills/monodesign/scripts/detector/detect-antipatterns.mjs +0 -50
- package/.claude/skills/monodesign/scripts/detector/engines/browser/detect-url.mjs +0 -259
- package/.claude/skills/monodesign/scripts/detector/engines/browser/drivers.mjs +0 -339
- package/.claude/skills/monodesign/scripts/detector/engines/regex/detect-text.mjs +0 -636
- package/.claude/skills/monodesign/scripts/detector/engines/static-html/css-cascade.mjs +0 -1016
- package/.claude/skills/monodesign/scripts/detector/engines/static-html/detect-html.mjs +0 -253
- package/.claude/skills/monodesign/scripts/detector/engines/visual/screenshot-contrast.mjs +0 -198
- package/.claude/skills/monodesign/scripts/detector/findings.mjs +0 -12
- package/.claude/skills/monodesign/scripts/detector/fix/css-regions.mjs +0 -181
- package/.claude/skills/monodesign/scripts/detector/fix/fixers.mjs +0 -373
- package/.claude/skills/monodesign/scripts/detector/fix/index.mjs +0 -426
- package/.claude/skills/monodesign/scripts/detector/node/file-system.mjs +0 -198
- package/.claude/skills/monodesign/scripts/detector/profile/profiler.mjs +0 -166
- package/.claude/skills/monodesign/scripts/detector/registry/antipatterns.mjs +0 -563
- package/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +0 -3024
- package/.claude/skills/monodesign/scripts/detector/shared/color.mjs +0 -124
- package/.claude/skills/monodesign/scripts/detector/shared/constants.mjs +0 -101
- package/.claude/skills/monodesign/scripts/detector/shared/fonts.mjs +0 -30
- package/.claude/skills/monodesign/scripts/detector/shared/inline-ignores.mjs +0 -148
- package/.claude/skills/monodesign/scripts/detector/shared/page.mjs +0 -7
- package/.claude/skills/monodesign/scripts/hook-admin.mjs +0 -694
- package/.claude/skills/monodesign/scripts/hook-before-edit.mjs +0 -516
- package/.claude/skills/monodesign/scripts/hook-lib.mjs +0 -1785
- package/.claude/skills/monodesign/scripts/hook.mjs +0 -61
- package/.claude/skills/monodesign/scripts/lib/design-parser.mjs +0 -809
- package/.claude/skills/monodesign/scripts/lib/is-generated.mjs +0 -69
- package/.claude/skills/monodesign/scripts/lib/monodesign-config.mjs +0 -640
- package/.claude/skills/monodesign/scripts/lib/monodesign-paths.mjs +0 -129
- package/.claude/skills/monodesign/scripts/lib/provider.mjs +0 -4
- package/.claude/skills/monodesign/scripts/lib/target-args.mjs +0 -42
- package/.claude/skills/monodesign/scripts/live/browser-script-parts.mjs +0 -50
- package/.claude/skills/monodesign/scripts/live/completion.mjs +0 -19
- package/.claude/skills/monodesign/scripts/live/event-validation.mjs +0 -137
- package/.claude/skills/monodesign/scripts/live/insert-ui.mjs +0 -458
- package/.claude/skills/monodesign/scripts/live/manual-apply.mjs +0 -939
- package/.claude/skills/monodesign/scripts/live/manual-edit-routes.mjs +0 -357
- package/.claude/skills/monodesign/scripts/live/manual-edits-buffer.mjs +0 -152
- package/.claude/skills/monodesign/scripts/live/session-store.mjs +0 -293
- package/.claude/skills/monodesign/scripts/live/svelte-component.mjs +0 -826
- package/.claude/skills/monodesign/scripts/live/sveltekit-adapter.mjs +0 -279
- package/.claude/skills/monodesign/scripts/live/ui-core.mjs +0 -180
- package/.claude/skills/monodesign/scripts/live/vocabulary.mjs +0 -36
- package/.claude/skills/monodesign/scripts/live-accept.mjs +0 -812
- package/.claude/skills/monodesign/scripts/live-browser-dom.js +0 -147
- package/.claude/skills/monodesign/scripts/live-browser-session.js +0 -124
- package/.claude/skills/monodesign/scripts/live-browser.js +0 -11213
- package/.claude/skills/monodesign/scripts/live-commit-manual-edits.mjs +0 -1241
- package/.claude/skills/monodesign/scripts/live-complete.mjs +0 -75
- package/.claude/skills/monodesign/scripts/live-copy-edit-agent.mjs +0 -683
- package/.claude/skills/monodesign/scripts/live-discard-manual-edits.mjs +0 -51
- package/.claude/skills/monodesign/scripts/live-inject.mjs +0 -596
- package/.claude/skills/monodesign/scripts/live-insert.mjs +0 -272
- package/.claude/skills/monodesign/scripts/live-manual-edit-evidence.mjs +0 -363
- package/.claude/skills/monodesign/scripts/live-poll.mjs +0 -384
- package/.claude/skills/monodesign/scripts/live-resume.mjs +0 -94
- package/.claude/skills/monodesign/scripts/live-server.mjs +0 -1210
- package/.claude/skills/monodesign/scripts/live-status.mjs +0 -61
- package/.claude/skills/monodesign/scripts/live-target.mjs +0 -30
- package/.claude/skills/monodesign/scripts/live-wrap.mjs +0 -884
- package/.claude/skills/monodesign/scripts/live.mjs +0 -297
- package/.claude/skills/monodesign/scripts/modern-screenshot.umd.js +0 -14
- package/.claude/skills/monodesign/scripts/palette.mjs +0 -635
- package/.claude/skills/monodesign/scripts/pin.mjs +0 -221
- package/.claude/skills/monodesign/shape.md +0 -71
- package/.claude/skills/monodesign/teach.md +0 -18
- 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')`
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
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` | [](https://www.npmjs.com/package/monomind) | Umbrella shim — **install this one** |
|
|
417
|
-
| `@monoes/monomindcli` | [](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (
|
|
417
|
+
| `@monoes/monomindcli` | [](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (32 commands, MCP server) |
|
|
418
418
|
| `@monoes/monograph` | [](https://www.npmjs.com/package/@monoes/monograph) | Code knowledge graph (tree-sitter + SQLite) |
|
|
419
419
|
| `@monoes/memory` | [](https://www.npmjs.com/package/@monoes/memory) | Persistent memory backends (SQLite + vectors) |
|
|
420
420
|
| `@monoes/hooks` | [](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
|