@sdsrs/code-graph 0.148.0 → 0.149.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/claude-plugin/scripts/auto-update.js +52 -6
- package/claude-plugin/scripts/cache-paths.js +89 -0
- package/claude-plugin/scripts/doctor.js +2 -2
- package/claude-plugin/scripts/lifecycle.js +65 -6
- package/claude-plugin/templates/code-graph-snapshot.yml +1 -1
- package/package.json +6 -6
|
@@ -53,7 +53,10 @@ function commandExists(cmd, { exec = execFileSync, timeoutMs = PATH_PROBE_TIMEOU
|
|
|
53
53
|
|
|
54
54
|
// ── Configuration ──────────────────────────────────────────
|
|
55
55
|
const GITHUB_REPO = 'sdsrss/code-graph-mcp';
|
|
56
|
-
const {
|
|
56
|
+
const {
|
|
57
|
+
UPDATE_STATE_FILE: STATE_FILE, MANIFEST_FILE, INSTALL_LOCK_FILE,
|
|
58
|
+
uninstallTombstoneActive,
|
|
59
|
+
} = require('./cache-paths');
|
|
57
60
|
const BINARY_CACHE_DIR = path.join(CACHE_DIR, 'bin');
|
|
58
61
|
const CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6h — steady-state re-check
|
|
59
62
|
const UP_TO_DATE_RECHECK_MS = 30 * 60 * 1000; // 30min — re-verify an "up to date" result (release-race guard)
|
|
@@ -166,14 +169,37 @@ function readState() {
|
|
|
166
169
|
// The unlink/cleanup `catch {}`s elsewhere in this file stay silent on purpose:
|
|
167
170
|
// a failed cleanup costs a stale temp file, not a broken invariant.
|
|
168
171
|
let stateWriteWarned = false;
|
|
169
|
-
function saveState(state) {
|
|
172
|
+
function saveState(state, { tombstoneActive = uninstallTombstoneActive, write = writeJsonAtomic } = {}) {
|
|
173
|
+
// A teardown deleted CACHE_DIR; writeJsonAtomic would re-create it to hold
|
|
174
|
+
// this file. Measured: in the arm where the teardown lands after curl has
|
|
175
|
+
// written its tmp, `update-state.json` was the ONE thing that came back, and
|
|
176
|
+
// it came back through here — noteUpdateFailure records the ENOENT the
|
|
177
|
+
// teardown caused, and the recording re-creates the directory. Guarding only
|
|
178
|
+
// the two download sites leaves this path open, so the arm keeps failing.
|
|
179
|
+
//
|
|
180
|
+
// The check sits inside saveState rather than at its eight call sites: one
|
|
181
|
+
// gate cannot drift out of step with seven others.
|
|
182
|
+
//
|
|
183
|
+
// It costs more than the file, and the cost is worth stating: this is also
|
|
184
|
+
// where the updater's anti-hammer memory lives. `fetchLatestRelease` records
|
|
185
|
+
// a GitHub 403 as `saveState({ ...state, rateLimited: true })` and
|
|
186
|
+
// `shouldCheck` reads it back to hold off; `lastCheck` drives the 6h/30min
|
|
187
|
+
// throttles the same way. While a tombstone stands, neither persists —
|
|
188
|
+
// measured, a rate-limited updater comes back with `rateLimited: null`,
|
|
189
|
+
// `lastCheck` unset and `shouldCheck` true, so it re-hits api.github.com on
|
|
190
|
+
// every invocation instead of backing off. Bounded by the TTL to five
|
|
191
|
+
// minutes, on a machine whose plugin was just torn down. No call site NEEDS
|
|
192
|
+
// the write — the state file lives inside the directory being reclaimed, so
|
|
193
|
+
// persisting it would mean re-creating exactly what this guard exists to
|
|
194
|
+
// prevent — but a reader should not have to discover the throttle loss.
|
|
195
|
+
if (tombstoneActive()) return;
|
|
170
196
|
try {
|
|
171
197
|
// The marker is an in-memory signal, never a persisted field: several call
|
|
172
198
|
// sites do `saveState({ ...readState(), ... })`, and a persisted
|
|
173
199
|
// `stateUnreadable` would park the updater permanently.
|
|
174
200
|
const { stateUnreadable, ...clean } = state || {};
|
|
175
201
|
void stateUnreadable;
|
|
176
|
-
|
|
202
|
+
write(STATE_FILE, clean);
|
|
177
203
|
} catch (e) {
|
|
178
204
|
if (!stateWriteWarned) {
|
|
179
205
|
stateWriteWarned = true;
|
|
@@ -583,7 +609,11 @@ function cachedBinaryStaleVsState(state, { binaryPath = cachedBinaryPath(), read
|
|
|
583
609
|
* `needsUpdate` is injectable for tests only; production always uses the real
|
|
584
610
|
* predicate. Returning false on a skip is accurate: nothing was updated.
|
|
585
611
|
*/
|
|
586
|
-
async function downloadBinary(latest, {
|
|
612
|
+
async function downloadBinary(latest, {
|
|
613
|
+
needsUpdate = cachedBinaryNeedsUpdate,
|
|
614
|
+
tombstoneActive = uninstallTombstoneActive,
|
|
615
|
+
mkdir = fs.mkdirSync,
|
|
616
|
+
} = {}) {
|
|
587
617
|
if (!latest || !latest.binaryUrl) return false;
|
|
588
618
|
if (!needsUpdate(latest)) return false; // already at latest.version — no fetch
|
|
589
619
|
if (!commandExists('curl')) {
|
|
@@ -595,8 +625,15 @@ async function downloadBinary(latest, { needsUpdate = cachedBinaryNeedsUpdate }
|
|
|
595
625
|
const binaryDst = cachedBinaryPath();
|
|
596
626
|
const binaryTmp = binaryDst + '.tmp.' + process.pid;
|
|
597
627
|
|
|
628
|
+
// The 41 MB arm. A teardown that lands before this mkdir gets the whole
|
|
629
|
+
// chain proceeding on a re-created tree, and it finishes by writing a fresh
|
|
630
|
+
// 42 MB binary into a directory the user just reclaimed. Checked here rather
|
|
631
|
+
// than at the top of the function so the guard sits adjacent to the write it
|
|
632
|
+
// protects.
|
|
633
|
+
if (tombstoneActive()) return false;
|
|
634
|
+
|
|
598
635
|
try {
|
|
599
|
-
|
|
636
|
+
mkdir(BINARY_CACHE_DIR, { recursive: true });
|
|
600
637
|
// `-f` (fail on HTTP >= 400), same as the sidecar fetch below. Without it
|
|
601
638
|
// curl writes GitHub's 404/503 HTML body to binaryTmp and exits 0, so the
|
|
602
639
|
// error page travelled on as a candidate binary and was only caught two
|
|
@@ -655,7 +692,8 @@ function sha256File(filePath) {
|
|
|
655
692
|
return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
|
|
656
693
|
}
|
|
657
694
|
|
|
658
|
-
function promoteVerifiedBinary(binaryTmp, binaryDst, expectedVersion, expectedSha256
|
|
695
|
+
function promoteVerifiedBinary(binaryTmp, binaryDst, expectedVersion, expectedSha256,
|
|
696
|
+
{ tombstoneActive = uninstallTombstoneActive } = {}) {
|
|
659
697
|
try {
|
|
660
698
|
// Size floor: every published binary is tens of MB, so anything under 1 MB
|
|
661
699
|
// is a truncated transfer or an error page. It used to return false without
|
|
@@ -714,6 +752,13 @@ function promoteVerifiedBinary(binaryTmp, binaryDst, expectedVersion, expectedSh
|
|
|
714
752
|
return false;
|
|
715
753
|
}
|
|
716
754
|
|
|
755
|
+
// The other arm: the teardown landed after curl wrote the tmp, so the
|
|
756
|
+
// download is verified and ready and the destination directory is gone.
|
|
757
|
+
// Refusing HERE rather than earlier is deliberate — the `finally` below
|
|
758
|
+
// owns binaryTmp and unlinks it, so bailing at the last step costs one
|
|
759
|
+
// wasted download and leaves nothing on disk.
|
|
760
|
+
if (tombstoneActive()) return false;
|
|
761
|
+
|
|
717
762
|
fs.renameSync(binaryTmp, binaryDst);
|
|
718
763
|
clearBinaryCache();
|
|
719
764
|
return true;
|
|
@@ -1529,6 +1574,7 @@ module.exports = {
|
|
|
1529
1574
|
shouldHealGlobalsOnThrottle, inactiveNodeGlobalRelics,
|
|
1530
1575
|
downloadAndInstall, refreshMarketplaceClone, marketplaceCloneDir,
|
|
1531
1576
|
noteUpdateFailure, takeUpdateFailure,
|
|
1577
|
+
saveState,
|
|
1532
1578
|
};
|
|
1533
1579
|
|
|
1534
1580
|
// CLI: node auto-update.js [check|status] [--silent] [--install-missing]
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
// file — it already does `require('./lifecycle')`, so its copy of the three path
|
|
20
20
|
// segments bought nothing. An earlier version of this comment claimed both
|
|
21
21
|
// modules needed the split (pre-ship review 2026-09-07).
|
|
22
|
+
const fs = require('fs');
|
|
22
23
|
const os = require('os');
|
|
23
24
|
const path = require('path');
|
|
24
25
|
|
|
@@ -31,9 +32,97 @@ const MANIFEST_FILE = path.join(CACHE_DIR, 'install-manifest.json');
|
|
|
31
32
|
/** Inter-process install lock (see install-lock.js). */
|
|
32
33
|
const INSTALL_LOCK_FILE = path.join(CACHE_DIR, 'install.lock');
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Teardown tombstone — a SIBLING of CACHE_DIR, deliberately not a file inside
|
|
37
|
+
* it.
|
|
38
|
+
*
|
|
39
|
+
* A teardown that runs while a SessionStart-spawned `auto-update` is in flight
|
|
40
|
+
* used to get CACHE_DIR re-created under it: measured at 42,847,128 B of fresh
|
|
41
|
+
* binary plus three JSON files, 2 of 2 runs, in the arm where the teardown
|
|
42
|
+
* beats the download.
|
|
43
|
+
*
|
|
44
|
+
* INSTALL_LOCK_FILE above is the token the updater already respects, and taking
|
|
45
|
+
* it here was prototyped for exactly this job and REFUTED: it lives at
|
|
46
|
+
* CACHE_DIR/install.lock, `removeCacheResidue()` deletes CACHE_DIR, so the lock
|
|
47
|
+
* goes with the directory and the updater acquires freely seconds later. A
|
|
48
|
+
* mutual-exclusion token stored inside the resource being destroyed cannot
|
|
49
|
+
* guard that destruction — which is why this one is a sibling.
|
|
50
|
+
*/
|
|
51
|
+
const UNINSTALL_TOMBSTONE_FILE = path.join(os.homedir(), '.cache', 'code-graph.uninstalled');
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* How long a tombstone suppresses writes. Longer than any teardown, shorter
|
|
55
|
+
* than any interval over which a stale one could matter: a reinstall inside the
|
|
56
|
+
* window merely skips one update check, and the install itself supplies the
|
|
57
|
+
* binary. The TTL is what keeps this from becoming a permanent kill switch —
|
|
58
|
+
* a tombstone that never expired would disable auto-update for the life of the
|
|
59
|
+
* machine, a worse failure than the residue it prevents.
|
|
60
|
+
*/
|
|
61
|
+
const UNINSTALL_TOMBSTONE_TTL_MS = 5 * 60 * 1000;
|
|
62
|
+
|
|
63
|
+
/** Record that a teardown is in flight. Best-effort: a cache we cannot write
|
|
64
|
+
* to is one the updater's own writes will fail against too. */
|
|
65
|
+
function writeUninstallTombstone({ file = UNINSTALL_TOMBSTONE_FILE, now = Date.now() } = {}) {
|
|
66
|
+
try {
|
|
67
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
68
|
+
fs.writeFileSync(file, JSON.stringify({ at: new Date(now).toISOString() }));
|
|
69
|
+
return true;
|
|
70
|
+
} catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Is a teardown in flight right now?
|
|
77
|
+
*
|
|
78
|
+
* Fail-OPEN on every unreadable shape — absent, unparseable, no timestamp. The
|
|
79
|
+
* alternative is a corrupt file that can never expire, and the spec rates a
|
|
80
|
+
* permanently suppressed updater worse than the 41 MB this exists to stop.
|
|
81
|
+
*/
|
|
82
|
+
function uninstallTombstoneActive({
|
|
83
|
+
file = UNINSTALL_TOMBSTONE_FILE,
|
|
84
|
+
now = Date.now(),
|
|
85
|
+
ttlMs = UNINSTALL_TOMBSTONE_TTL_MS,
|
|
86
|
+
} = {}) {
|
|
87
|
+
let at;
|
|
88
|
+
try {
|
|
89
|
+
at = Date.parse(JSON.parse(fs.readFileSync(file, 'utf8')).at);
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (!Number.isFinite(at)) return false;
|
|
94
|
+
// `age >= 0` is not redundant with the upper bound: a NEGATIVE age — a
|
|
95
|
+
// timestamp in the future — is always less than the TTL, so a bare
|
|
96
|
+
// `age < ttlMs` would treat a tombstone stamped a year ahead as active for a
|
|
97
|
+
// year, and a legitimate one plus an 8h clock rollback (NTP correction, VM
|
|
98
|
+
// restore, RTC drift) as active for 8h05m. That is the never-expiring
|
|
99
|
+
// kill switch this design's TTL exists to prevent, in bounded form, and it is
|
|
100
|
+
// reachable without any corruption because the file carries OUR OWN
|
|
101
|
+
// Date.now(). A future stamp means the clock moved, not that a teardown is in
|
|
102
|
+
// flight, so it fails open like every other shape we cannot trust.
|
|
103
|
+
const age = now - at;
|
|
104
|
+
return age >= 0 && age < ttlMs;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Drop the tombstone. The TTL is the backstop; an install clears it eagerly so
|
|
108
|
+
* a reinstall inside the window does not skip its first update check. */
|
|
109
|
+
function clearUninstallTombstone({ file = UNINSTALL_TOMBSTONE_FILE } = {}) {
|
|
110
|
+
try {
|
|
111
|
+
fs.rmSync(file, { force: true });
|
|
112
|
+
return true;
|
|
113
|
+
} catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
34
118
|
module.exports = {
|
|
35
119
|
CACHE_DIR,
|
|
36
120
|
UPDATE_STATE_FILE,
|
|
37
121
|
MANIFEST_FILE,
|
|
38
122
|
INSTALL_LOCK_FILE,
|
|
123
|
+
UNINSTALL_TOMBSTONE_FILE,
|
|
124
|
+
UNINSTALL_TOMBSTONE_TTL_MS,
|
|
125
|
+
writeUninstallTombstone,
|
|
126
|
+
uninstallTombstoneActive,
|
|
127
|
+
clearUninstallTombstone,
|
|
39
128
|
};
|
|
@@ -1134,7 +1134,7 @@ function runRepairs(results, {
|
|
|
1134
1134
|
console.log('\n Repairing hooks...');
|
|
1135
1135
|
if (relicRepairGuard()) break;
|
|
1136
1136
|
const { install, scanForBrokenPaths } = require('./lifecycle');
|
|
1137
|
-
const installResult = install();
|
|
1137
|
+
const installResult = install({ clearTombstone: true });
|
|
1138
1138
|
// Diagnosis already ran install()+re-scan and the paths were STILL
|
|
1139
1139
|
// broken (that `repaired:false` is what raised hooks-invalid). Verify
|
|
1140
1140
|
// this second attempt actually cleared them before counting it fixed \u2014
|
|
@@ -1173,7 +1173,7 @@ function runRepairs(results, {
|
|
|
1173
1173
|
console.log('\n Registering code-graph hooks in settings.json...');
|
|
1174
1174
|
if (relicRepairGuard()) break;
|
|
1175
1175
|
const { install } = require('./lifecycle');
|
|
1176
|
-
const r = install();
|
|
1176
|
+
const r = install({ clearTombstone: true });
|
|
1177
1177
|
if (r.hooksRegistered) {
|
|
1178
1178
|
console.log(' \u2705 settings.json updated — restart Claude Code to apply');
|
|
1179
1179
|
fixed++;
|
|
@@ -20,7 +20,10 @@ const MARKETPLACE_NAME = 'code-graph-mcp';
|
|
|
20
20
|
// the first version of this comment claimed `MANIFEST_FILE` was exported from
|
|
21
21
|
// here: `CACHE_DIR` and `INSTALL_LOCK_FILE` are exported and still are;
|
|
22
22
|
// `MANIFEST_FILE` is module-private and always was, so nothing importable moved.
|
|
23
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
CACHE_DIR, MANIFEST_FILE, INSTALL_LOCK_FILE,
|
|
25
|
+
writeUninstallTombstone, clearUninstallTombstone,
|
|
26
|
+
} = require('./cache-paths');
|
|
24
27
|
// Bound for the `ps` fallback in getActiveCmdlines (pre-ship review 2026-09-06).
|
|
25
28
|
// 2 s matches the other hook-path probes; the floor is what a budget-exhausted
|
|
26
29
|
// hook still gives it, since an empty list degrades to recency-only.
|
|
@@ -1321,7 +1324,27 @@ function verifyHooksFire({ hooks, env, timeoutMs = 4000, tmpBase } = {}) {
|
|
|
1321
1324
|
|
|
1322
1325
|
// --- Install (idempotent) ---
|
|
1323
1326
|
|
|
1324
|
-
function install({ reclaimStatusline = false } = {}) {
|
|
1327
|
+
function install({ reclaimStatusline = false, clearTombstone = false } = {}) {
|
|
1328
|
+
// Clearing the teardown tombstone is OPT-IN, and defaults to off, because
|
|
1329
|
+
// "an install is happening" does not mean "the user asked to reinstall".
|
|
1330
|
+
//
|
|
1331
|
+
// The first version cleared unconditionally, on the reasoning that an install
|
|
1332
|
+
// ends any teardown. Pre-ship review reproduced the hole: after a genuine
|
|
1333
|
+
// uninstall, a DIFFERENT still-live session's SessionStart finds no manifest
|
|
1334
|
+
// (install-manifest.json went with CACHE_DIR) and no inactive-plugin markers
|
|
1335
|
+
// (the composite and the statusline registry went with it too), so it falls
|
|
1336
|
+
// through to `installReporting()` -> install() and cleared the tombstone 3 s
|
|
1337
|
+
// after it was written — then spawned its own updater fourteen lines later.
|
|
1338
|
+
// A global record that any concurrent session may erase protects nobody.
|
|
1339
|
+
//
|
|
1340
|
+
// So only the two genuinely user-initiated entry points pass true: the
|
|
1341
|
+
// `lifecycle.js install` CLI and doctor's repair pass. Everything automatic —
|
|
1342
|
+
// session-init's install reporting, healthCheck's repair — leaves it standing
|
|
1343
|
+
// and lets the TTL expire it. The cost is that a reinstall inside the window
|
|
1344
|
+
// may skip one update check, which the spec already accepts; the install
|
|
1345
|
+
// itself supplies the binary.
|
|
1346
|
+
if (clearTombstone) clearUninstallTombstone();
|
|
1347
|
+
|
|
1325
1348
|
const version = getPluginVersion();
|
|
1326
1349
|
const manifest = readManifest();
|
|
1327
1350
|
// Probe FIRST, and pay the backup only on the write path (audit 2026-08-29
|
|
@@ -2018,7 +2041,39 @@ const POST_TEARDOWN_UI_NOTE = [
|
|
|
2018
2041
|
'`/plugin uninstall code-graph-mcp` there to sync its UI.',
|
|
2019
2042
|
];
|
|
2020
2043
|
|
|
2021
|
-
function removeCacheResidue() {
|
|
2044
|
+
function removeCacheResidue({ sweep = null } = {}) {
|
|
2045
|
+
// Announce the teardown BEFORE the delete, outside the directory being
|
|
2046
|
+
// deleted. A mid-flight `auto-update` in ANOTHER process will otherwise
|
|
2047
|
+
// re-create CACHE_DIR under us — measured at 42,847,128 B of fresh binary
|
|
2048
|
+
// plus three JSON files, 2 of 2 runs, when the teardown wins the race to
|
|
2049
|
+
// `downloadBinary`'s mkdir.
|
|
2050
|
+
//
|
|
2051
|
+
// The racing updater is always a different process. An earlier version of
|
|
2052
|
+
// this comment said `runSessionInit`'s teardown "runs from the same
|
|
2053
|
+
// SessionStart that spawns the updater"; it does not — that branch returns at
|
|
2054
|
+
// session-init.js:718 with `autoUpdateLaunched: false`, before
|
|
2055
|
+
// `launchBackgroundAutoUpdate`. SessionStart is still the racing surface,
|
|
2056
|
+
// just from a concurrent session rather than this one (pre-ship review).
|
|
2057
|
+
//
|
|
2058
|
+
// All three callers are genuine-uninstall paths — `uninstall()`,
|
|
2059
|
+
// `cleanupDisabledStatusline()` under `isPluginUninstalled`, and
|
|
2060
|
+
// `runSessionInit()` under `if (uninstalled)` — so the tombstone belongs here
|
|
2061
|
+
// rather than in each of them: one site, three callers, and no way for a
|
|
2062
|
+
// fourth to forget it. Verified against five sandbox states (explicit
|
|
2063
|
+
// disable, genuine uninstall, healthy, unreadable registry, missing
|
|
2064
|
+
// registry): only the genuine uninstall writes one.
|
|
2065
|
+
//
|
|
2066
|
+
// BEFORE, not after: written after the sweep there is a window in which an
|
|
2067
|
+
// updater sees nothing and can mkdir mid-delete, and the sweep's own
|
|
2068
|
+
// `catch { return false; }` would skip the write entirely on a failed delete.
|
|
2069
|
+
// `sweep` exists so a test can observe the tombstone at the moment the delete
|
|
2070
|
+
// is attempted — the ordering is the property, and asserting only that the
|
|
2071
|
+
// file exists on return passes with the two lines swapped.
|
|
2072
|
+
//
|
|
2073
|
+
// Best-effort by design: if this write fails, the delete below still runs and
|
|
2074
|
+
// we are no worse off than before the tombstone existed.
|
|
2075
|
+
writeUninstallTombstone();
|
|
2076
|
+
|
|
2022
2077
|
// Path comes from adopt.js rather than a second spelling of the basename —
|
|
2023
2078
|
// a literal here would silently stop matching the day adopt.js renames it,
|
|
2024
2079
|
// and the failure mode is exactly the data loss this guard exists to stop.
|
|
@@ -2046,7 +2101,8 @@ function removeCacheResidue() {
|
|
|
2046
2101
|
}
|
|
2047
2102
|
} catch { /* POSIX-only helper or an unreadable path — nothing to preserve */ }
|
|
2048
2103
|
try {
|
|
2049
|
-
|
|
2104
|
+
if (sweep) sweep(CACHE_DIR);
|
|
2105
|
+
else fs.rmSync(CACHE_DIR, { recursive: true, force: true });
|
|
2050
2106
|
} catch { return false; }
|
|
2051
2107
|
if (registryPath && registry) {
|
|
2052
2108
|
try {
|
|
@@ -2089,8 +2145,11 @@ module.exports = {
|
|
|
2089
2145
|
if (require.main === module) {
|
|
2090
2146
|
const cmd = process.argv[2];
|
|
2091
2147
|
if (cmd === 'install') {
|
|
2092
|
-
// Explicit CLI install = user intent: reset any statusline stand-down and
|
|
2093
|
-
|
|
2148
|
+
// Explicit CLI install = user intent: reset any statusline stand-down and
|
|
2149
|
+
// re-claim, and drop a teardown tombstone if one is standing. This and
|
|
2150
|
+
// doctor's repair pass are the only two callers that pass clearTombstone —
|
|
2151
|
+
// see the comment on install() for why an automatic install must not.
|
|
2152
|
+
const r = install({ reclaimStatusline: true, clearTombstone: true });
|
|
2094
2153
|
// Refusing to touch an unusable settings.json means NOTHING was installed —
|
|
2095
2154
|
// no hooks, no statusline, no manifest stamp. Printing "Installed" and
|
|
2096
2155
|
// exiting 0 there would make `lifecycle.js install && …` chains read the
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
node-version: '20'
|
|
36
36
|
- name: Build snapshot
|
|
37
37
|
run: |
|
|
38
|
-
npx -y -p @sdsrs/code-graph@0.
|
|
38
|
+
npx -y -p @sdsrs/code-graph@0.149.0 code-graph-mcp snapshot create --out snapshot.db
|
|
39
39
|
zstd -9 snapshot.db -o snapshot.db.zst
|
|
40
40
|
mv snapshot.db.zst "code-graph-snapshot-${GITHUB_SHA:0:7}.db.zst"
|
|
41
41
|
- name: Upload to release
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdsrs/code-graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.149.0",
|
|
4
4
|
"description": "MCP server that indexes codebases into an AST knowledge graph with semantic search, call graph traversal, and HTTP route tracing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"node": ">=16"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@sdsrs/code-graph-linux-x64": "0.
|
|
39
|
-
"@sdsrs/code-graph-linux-arm64": "0.
|
|
40
|
-
"@sdsrs/code-graph-darwin-x64": "0.
|
|
41
|
-
"@sdsrs/code-graph-darwin-arm64": "0.
|
|
42
|
-
"@sdsrs/code-graph-win32-x64": "0.
|
|
38
|
+
"@sdsrs/code-graph-linux-x64": "0.149.0",
|
|
39
|
+
"@sdsrs/code-graph-linux-arm64": "0.149.0",
|
|
40
|
+
"@sdsrs/code-graph-darwin-x64": "0.149.0",
|
|
41
|
+
"@sdsrs/code-graph-darwin-arm64": "0.149.0",
|
|
42
|
+
"@sdsrs/code-graph-win32-x64": "0.149.0"
|
|
43
43
|
}
|
|
44
44
|
}
|