@sdsrs/code-graph 0.137.0 → 0.139.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/README.md +1 -0
- package/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/claude-plugin/scripts/auto-update.js +4 -4
- package/claude-plugin/scripts/cache-paths.js +39 -0
- package/claude-plugin/scripts/doctor.js +4 -3
- package/claude-plugin/scripts/lifecycle.js +9 -3
- package/claude-plugin/scripts/session-init.js +2 -1
- package/claude-plugin/scripts/statusline-composite.js +59 -1
- package/claude-plugin/scripts/statusline.js +2 -3
- package/claude-plugin/scripts/user-prompt-context.js +5 -3
- package/claude-plugin/templates/code-graph-snapshot.yml +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -590,6 +590,7 @@ plugins' entries. An installer that reads exit codes must not treat it as
|
|
|
590
590
|
| Variable | Set by | Purpose |
|
|
591
591
|
|---|---|---|
|
|
592
592
|
| `CODE_GRAPH_STATUSLINE_CWD` | statusline-composite | Forwards Claude Code's authoritative cwd to each statusline provider. |
|
|
593
|
+
| `CODE_GRAPH_STATUSLINE_DEBUG` | test suite | Makes statusline-composite print why it dropped a provider instead of swallowing the error. Off by default so a broken third-party provider stays silent in a real statusline. |
|
|
593
594
|
| `CODE_GRAPH_INSTALL_LOCK_HELD` | launcher | Tells a child that the parent already holds the install lock, so it does not deadlock. |
|
|
594
595
|
| `CODE_GRAPH_AUTO_UPDATE_SILENT` | session-init | Runs the update check without console output. |
|
|
595
596
|
| `CODE_GRAPH_NO_ANSWER_IN_DENY` | lifecycle | Keeps `cg-answer` out of the deny path. |
|
|
@@ -35,7 +35,7 @@ function commandExists(cmd) {
|
|
|
35
35
|
|
|
36
36
|
// ── Configuration ──────────────────────────────────────────
|
|
37
37
|
const GITHUB_REPO = 'sdsrss/code-graph-mcp';
|
|
38
|
-
const STATE_FILE =
|
|
38
|
+
const { UPDATE_STATE_FILE: STATE_FILE, MANIFEST_FILE, INSTALL_LOCK_FILE } = require('./cache-paths');
|
|
39
39
|
const BINARY_CACHE_DIR = path.join(CACHE_DIR, 'bin');
|
|
40
40
|
const CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6h — steady-state re-check
|
|
41
41
|
const UP_TO_DATE_RECHECK_MS = 30 * 60 * 1000; // 30min — re-verify an "up to date" result (release-race guard)
|
|
@@ -956,7 +956,7 @@ async function downloadAndInstall(latest, {
|
|
|
956
956
|
const manifest = readManifest();
|
|
957
957
|
manifest.version = latest.version;
|
|
958
958
|
manifest.updatedAt = new Date().toISOString();
|
|
959
|
-
writeJsonAtomic(
|
|
959
|
+
writeJsonAtomic(MANIFEST_FILE, manifest);
|
|
960
960
|
} catch { /* not fatal */ }
|
|
961
961
|
}
|
|
962
962
|
|
|
@@ -1272,7 +1272,7 @@ async function checkForUpdate({ installMissing = false, force = false, requestJs
|
|
|
1272
1272
|
// shouldHealGlobalsOnThrottle). Cheap local check first; only the actually-
|
|
1273
1273
|
// stale case takes the slow, lock-guarded npm path.
|
|
1274
1274
|
if (shouldHealGlobalsOnThrottle(state)) {
|
|
1275
|
-
installLock = acquireLock(
|
|
1275
|
+
installLock = acquireLock(INSTALL_LOCK_FILE);
|
|
1276
1276
|
if (installLock) {
|
|
1277
1277
|
const globalHeal = await selfHealGlobalPkgs({ version: state.latestVersion }, state);
|
|
1278
1278
|
saveState({ ...readState(), ...globalHeal });
|
|
@@ -1317,7 +1317,7 @@ async function checkForUpdate({ installMissing = false, force = false, requestJs
|
|
|
1317
1317
|
// it marks that with CODE_GRAPH_INSTALL_LOCK_HELD so we don't deadlock
|
|
1318
1318
|
// against our own parent.
|
|
1319
1319
|
if (process.env.CODE_GRAPH_INSTALL_LOCK_HELD !== '1') {
|
|
1320
|
-
installLock = acquireLock(
|
|
1320
|
+
installLock = acquireLock(INSTALL_LOCK_FILE);
|
|
1321
1321
|
// Reason, not null — same misreport as the fetch failure above: the
|
|
1322
1322
|
// holder is mid-update, so "Up to date (v<old>)" is exactly wrong.
|
|
1323
1323
|
if (!installLock) return { noop: true, reason: 'install-lock-held', from: installedVersion };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Single home for the `~/.cache/code-graph` file names.
|
|
3
|
+
//
|
|
4
|
+
// JS-05 (audit 2026-09-05): `update-state.json` was spelled in five modules,
|
|
5
|
+
// `install.lock` in two, `install-manifest.json` in three — and two of those
|
|
6
|
+
// rebuilt the whole path out of `os.homedir()` rather than joining `CACHE_DIR`,
|
|
7
|
+
// so the modules that would break first if the cache layout moved were also the
|
|
8
|
+
// two that never load the module where it was defined. A rename had to be found
|
|
9
|
+
// by grep. `tests/hardening.rs::cache_file_names_have_exactly_one_spelling`
|
|
10
|
+
// keeps this the only file that may spell them.
|
|
11
|
+
//
|
|
12
|
+
// Deliberately tiny and dependency-free beyond node builtins, for ONE consumer:
|
|
13
|
+
// `user-prompt-context.js` runs on the UserPromptSubmit hook path and does not
|
|
14
|
+
// load `lifecycle.js`, so taking a path string from there would cost it the
|
|
15
|
+
// whole module. Measured at 30.1 ms as shipped versus 34.5 ms if it also loaded
|
|
16
|
+
// `lifecycle.js` (+14%).
|
|
17
|
+
//
|
|
18
|
+
// `statusline.js` was the other hardcoded spelling and is NOT a reason for this
|
|
19
|
+
// file — it already does `require('./lifecycle')`, so its copy of the three path
|
|
20
|
+
// segments bought nothing. An earlier version of this comment claimed both
|
|
21
|
+
// modules needed the split (pre-ship review 2026-09-07).
|
|
22
|
+
const os = require('os');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
|
|
25
|
+
const CACHE_DIR = path.join(os.homedir(), '.cache', 'code-graph');
|
|
26
|
+
|
|
27
|
+
/** Auto-update bookkeeping: available version, attempt counters, last error. */
|
|
28
|
+
const UPDATE_STATE_FILE = path.join(CACHE_DIR, 'update-state.json');
|
|
29
|
+
/** What the last install wrote, and where. Absent = never installed. */
|
|
30
|
+
const MANIFEST_FILE = path.join(CACHE_DIR, 'install-manifest.json');
|
|
31
|
+
/** Inter-process install lock (see install-lock.js). */
|
|
32
|
+
const INSTALL_LOCK_FILE = path.join(CACHE_DIR, 'install.lock');
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
CACHE_DIR,
|
|
36
|
+
UPDATE_STATE_FILE,
|
|
37
|
+
MANIFEST_FILE,
|
|
38
|
+
INSTALL_LOCK_FILE,
|
|
39
|
+
};
|
|
@@ -6,10 +6,11 @@ const path = require('path');
|
|
|
6
6
|
const os = require('os');
|
|
7
7
|
const { readBinaryVersion, isDevMode, getNewestMtime } = require('./version-utils');
|
|
8
8
|
const {
|
|
9
|
-
getPluginVersion, readJson, readJsonResult, healthCheck, scanForBrokenPaths,
|
|
9
|
+
getPluginVersion, readJson, readJsonResult, healthCheck, scanForBrokenPaths,
|
|
10
10
|
settingsPath, surveyHookCoverage,
|
|
11
11
|
installedGlobalPkgs, GLOBAL_INSTALL_MARKER, SHELL_PKG,
|
|
12
12
|
} = require('./lifecycle');
|
|
13
|
+
const { UPDATE_STATE_FILE } = require('./cache-paths');
|
|
13
14
|
const { findBinary, clearCache: clearBinaryCache } = require('./find-binary');
|
|
14
15
|
const { hidden } = require('./proc-opts');
|
|
15
16
|
const { MAX_UPDATE_ATTEMPTS, GLOBAL_PKG_HEAL_MAX_ATTEMPTS, isBinaryHealExhausted, readState } = require('./auto-update');
|
|
@@ -589,7 +590,7 @@ function runDiagnostics({ checkOnly = false } = {}) {
|
|
|
589
590
|
// this line used to hardcode 3 while the comment named the constant, so
|
|
590
591
|
// raising the cap in auto-update.js would have left this diagnosis
|
|
591
592
|
// reporting the old one (audit 2026-08-29 JS-07).
|
|
592
|
-
const state = readJson(
|
|
593
|
+
const state = readJson(UPDATE_STATE_FILE) || {};
|
|
593
594
|
const healGaveUp = (state.globalPkgHealAttempts || 0) >= GLOBAL_PKG_HEAL_MAX_ATTEMPTS;
|
|
594
595
|
results.push({
|
|
595
596
|
name: 'Global npm packages',
|
|
@@ -858,7 +859,7 @@ function probeHealth({ find = findBinary } = {}) {
|
|
|
858
859
|
}
|
|
859
860
|
|
|
860
861
|
function readUpdateState() {
|
|
861
|
-
try { return readJson(
|
|
862
|
+
try { return readJson(UPDATE_STATE_FILE); } catch { return null; }
|
|
862
863
|
}
|
|
863
864
|
|
|
864
865
|
/**
|
|
@@ -12,7 +12,15 @@ const OLD_PLUGIN_IDS = [
|
|
|
12
12
|
'code-graph@sdsrss-code-graph', // v2 legacy ID (pre-rename)
|
|
13
13
|
];
|
|
14
14
|
const MARKETPLACE_NAME = 'code-graph-mcp';
|
|
15
|
-
|
|
15
|
+
// Imported, not defined here: five other modules needed these three names and
|
|
16
|
+
// one of them — `user-prompt-context.js`, on the UserPromptSubmit hook path —
|
|
17
|
+
// cannot afford to load this file for them (see cache-paths.js, JS-05).
|
|
18
|
+
//
|
|
19
|
+
// The export surface below is unchanged. Measured rather than asserted, after
|
|
20
|
+
// the first version of this comment claimed `MANIFEST_FILE` was exported from
|
|
21
|
+
// here: `CACHE_DIR` and `INSTALL_LOCK_FILE` are exported and still are;
|
|
22
|
+
// `MANIFEST_FILE` is module-private and always was, so nothing importable moved.
|
|
23
|
+
const { CACHE_DIR, MANIFEST_FILE, INSTALL_LOCK_FILE } = require('./cache-paths');
|
|
16
24
|
// Bound for the `ps` fallback in getActiveCmdlines (pre-ship review 2026-09-06).
|
|
17
25
|
// 2 s matches the other hook-path probes; the floor is what a budget-exhausted
|
|
18
26
|
// hook still gives it, since an empty list degrades to recency-only.
|
|
@@ -22,14 +30,12 @@ const PS_PROBE_MIN_MS = 250;
|
|
|
22
30
|
// plugins when hooks run in shared process context (e.g. claude-mem-lite sets it
|
|
23
31
|
// to its own marketplace path, polluting all subsequent settings.json hook processes).
|
|
24
32
|
const PLUGIN_ROOT = path.resolve(__dirname, '..');
|
|
25
|
-
const MANIFEST_FILE = path.join(CACHE_DIR, 'install-manifest.json');
|
|
26
33
|
const REGISTRY_FILE = path.join(CACHE_DIR, 'statusline-registry.json');
|
|
27
34
|
// Written by the launcher's background install when ITS `npm install -g` step
|
|
28
35
|
// introduced the global shell + platform packages. Uninstall only removes
|
|
29
36
|
// global packages it can prove the plugin installed (marker present) or when
|
|
30
37
|
// the user passes --purge-global — a deliberate user install is never yanked.
|
|
31
38
|
const GLOBAL_INSTALL_MARKER = path.join(CACHE_DIR, 'global-install-marker.json');
|
|
32
|
-
const INSTALL_LOCK_FILE = path.join(CACHE_DIR, 'install.lock');
|
|
33
39
|
const SHELL_PKG = '@sdsrs/code-graph';
|
|
34
40
|
|
|
35
41
|
// Lazy resolvers — Claude Code's config dir can be overridden by CLAUDE_CONFIG_DIR
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
cleanupDisabledStatusline, isPluginInactive, isPluginUninstalled, removeCacheResidue,
|
|
9
9
|
readJson, CACHE_DIR, settingsPath, isStaleRelicContext, hookCmdScript,
|
|
10
10
|
} = require('./lifecycle');
|
|
11
|
+
const { UPDATE_STATE_FILE } = require('./cache-paths');
|
|
11
12
|
const { readBinaryVersion, isDevMode, getNewestMtime } = require('./version-utils');
|
|
12
13
|
const { maybeAutoAdopt, isAdopted, unadopt } = require('./adopt');
|
|
13
14
|
const { isNonProjectCwd } = require('./project-detect');
|
|
@@ -604,7 +605,7 @@ function consistencyCheck(binary) {
|
|
|
604
605
|
|
|
605
606
|
// Check 3: Auto-update incomplete
|
|
606
607
|
try {
|
|
607
|
-
const statePath =
|
|
608
|
+
const statePath = UPDATE_STATE_FILE;
|
|
608
609
|
const state = readJson(statePath);
|
|
609
610
|
if (state && state.updateAvailable && state.binaryUpdated === false) {
|
|
610
611
|
issues.push({
|
|
@@ -140,7 +140,65 @@ function runProvider(command, needsStdin, stdin, id) {
|
|
|
140
140
|
})).toString().trim();
|
|
141
141
|
|
|
142
142
|
return out || null;
|
|
143
|
-
} catch {
|
|
143
|
+
} catch (err) {
|
|
144
|
+
// EPIPE is OUR failure to deliver, not the provider's failure to answer.
|
|
145
|
+
// `execFileSync` writes `input` into the child's stdin; a provider that
|
|
146
|
+
// exits without reading it (a static `echo`, an env-var-only line) makes
|
|
147
|
+
// that write fail — and by then the child has already produced its output
|
|
148
|
+
// in full. Discarding it drops the user's original statusline for a reason
|
|
149
|
+
// that has nothing to do with the provider. `_previous` is registered with
|
|
150
|
+
// needsStdin unconditionally true (lifecycle.js), so every such user is
|
|
151
|
+
// exposed. Measured: 10/10 EPIPE with a payload past the pipe buffer and
|
|
152
|
+
// the child's stdout complete in 10 of 10; on ordinary payloads the same
|
|
153
|
+
// discard happens as a timing race, which is what made
|
|
154
|
+
// lifecycle.e2e.test.js's "issue #24" intermittent for two releases.
|
|
155
|
+
// An empty stdout still falls through: nothing was produced, nothing to keep.
|
|
156
|
+
// Gated on a CLEAN exit. A provider that genuinely failed can EPIPE too, and
|
|
157
|
+
// its stdout is then partial by definition. Measured: a `set -e` script that
|
|
158
|
+
// prints one segment and exits 1 salvages as "SEGMENT-ONE |" — half a line,
|
|
159
|
+
// rendered as if whole, and rendering differently run to run depending on
|
|
160
|
+
// which side of the race it lands. `err.status` is 0 in the case this exists
|
|
161
|
+
// for (pre-ship delta review 2026-09-06).
|
|
162
|
+
//
|
|
163
|
+
// `status === 0`, not `!status`: a signal-killed child reports `status:
|
|
164
|
+
// null`, which `!status` would wave through — and that is a live path, not a
|
|
165
|
+
// defensive one. A provider that prints and then takes a signal while we
|
|
166
|
+
// still have stdin to write lands HERE, with `code: 'EPIPE'`, `status: null`
|
|
167
|
+
// and half a line; measured 6 runs of 6 across SIGTERM and SIGKILL. Only our
|
|
168
|
+
// OWN 3 s timeout misses this branch, surfacing as ETIMEDOUT instead.
|
|
169
|
+
// Measured set: clean → EPIPE / 0 / whole line; `exit 1` → EPIPE / 1 / half;
|
|
170
|
+
// self-signal → EPIPE / null / half; our timeout → ETIMEDOUT / null / half.
|
|
171
|
+
const salvaged =
|
|
172
|
+
err && err.code === 'EPIPE' && err.status === 0
|
|
173
|
+
? (err.stdout || '').toString().trim()
|
|
174
|
+
: '';
|
|
175
|
+
// Swallowing is correct in production and stays the default: a third-party
|
|
176
|
+
// provider that throws must not take the user's whole statusline with it.
|
|
177
|
+
// But a swallowed error is also why `lifecycle.e2e.test.js`'s "issue #24"
|
|
178
|
+
// has gone intermittently red with nothing to go on — a dropped provider and
|
|
179
|
+
// a provider that printed nothing are the same observation from outside, so
|
|
180
|
+
// every diagnosis of it so far has been a guess. Opt-in, off unless the env
|
|
181
|
+
// var is set, so no shipped behavior changes.
|
|
182
|
+
if (process.env.CODE_GRAPH_STATUSLINE_DEBUG) {
|
|
183
|
+
// Its own try/catch. On Linux this is belt-and-braces rather than
|
|
184
|
+
// load-bearing: a write to a closed stderr does NOT throw synchronously —
|
|
185
|
+
// measured both shapes, `fs.closeSync(2)` is a silent no-op and a piped
|
|
186
|
+
// reader that exits surfaces one tick later as an uncaughtException, which
|
|
187
|
+
// no try/catch here can see (hook-fail-open.js already handles that path
|
|
188
|
+
// and skips its own stderr write on EPIPE). It earns its place on Windows,
|
|
189
|
+
// where piped stderr writes are synchronous, and it costs nothing: this
|
|
190
|
+
// sits inside the catch that keeps a bad provider from taking the whole
|
|
191
|
+
// statusline down, so a debug switch must not be the thing that does.
|
|
192
|
+
try {
|
|
193
|
+
const why = err && (err.code || err.message) ? (err.code || err.message) : String(err);
|
|
194
|
+
// Report BOTH outcomes. Returning early on a salvage would make the
|
|
195
|
+
// channel silent on the exact failure it was built to diagnose.
|
|
196
|
+
const verb = salvaged ? 'recovered after' : 'dropped';
|
|
197
|
+
process.stderr.write(`[statusline] provider '${id}' ${verb}: ${why}\n`);
|
|
198
|
+
} catch { /* diagnostics are best-effort; rendering is not */ }
|
|
199
|
+
}
|
|
200
|
+
return salvaged || null;
|
|
201
|
+
}
|
|
144
202
|
}
|
|
145
203
|
|
|
146
204
|
// Extract Claude Code's current working directory from the stdin JSON context.
|
|
@@ -10,11 +10,11 @@ if (require.main === module) require('./hook-fail-open').installHookFailOpen('st
|
|
|
10
10
|
|
|
11
11
|
const { execFileSync } = require('child_process');
|
|
12
12
|
const fs = require('fs');
|
|
13
|
-
const os = require('os');
|
|
14
13
|
const path = require('path');
|
|
15
14
|
const { findBinary } = require('./find-binary');
|
|
16
15
|
const { resolveProjectRoot } = require('./project-root');
|
|
17
16
|
const lifecycle = require('./lifecycle');
|
|
17
|
+
const { UPDATE_STATE_FILE } = require('./cache-paths');
|
|
18
18
|
const { hidden } = require('./proc-opts');
|
|
19
19
|
const cleanupDisabledStatusline = lifecycle.cleanupDisabledStatusline || (() => ({ cleaned: false }));
|
|
20
20
|
|
|
@@ -29,8 +29,7 @@ const cleanupDisabledStatusline = lifecycle.cleanupDisabledStatusline || (() =>
|
|
|
29
29
|
const STUCK_UPDATE_ATTEMPTS = 5;
|
|
30
30
|
function readUpdateState() {
|
|
31
31
|
try {
|
|
32
|
-
return JSON.parse(fs.readFileSync(
|
|
33
|
-
path.join(os.homedir(), '.cache', 'code-graph', 'update-state.json'), 'utf8'));
|
|
32
|
+
return JSON.parse(fs.readFileSync(UPDATE_STATE_FILE, 'utf8'));
|
|
34
33
|
} catch { return null; /* no state file or unreadable */ }
|
|
35
34
|
}
|
|
36
35
|
function updatePending(st = readUpdateState()) {
|
|
@@ -14,7 +14,6 @@ if (require.main === module) require('./hook-fail-open').installHookFailOpen('Us
|
|
|
14
14
|
const { execFileSync } = require('child_process');
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
|
-
const os = require('os');
|
|
18
17
|
// Hook cooldown flags + the restart notice go under cgTmpDir() (a code-graph-mcp/
|
|
19
18
|
// subdir of os.tmpdir()), NOT bare os.tmpdir(): Claude Code overrides $TMPDIR to
|
|
20
19
|
// ~/.claude/tmp/, so bare-tmp flags interleave with transcript captures —
|
|
@@ -23,8 +22,11 @@ const os = require('os');
|
|
|
23
22
|
const { cgTmpDir, cwdHash } = require('./tmp-dir');
|
|
24
23
|
const { hidden } = require('./proc-opts');
|
|
25
24
|
|
|
26
|
-
// Mid-session install detection: hook fires but no manifest yet.
|
|
27
|
-
|
|
25
|
+
// Mid-session install detection: hook fires but no manifest yet. The path comes
|
|
26
|
+
// from `cache-paths.js` — deliberately NOT from `lifecycle.js`, which this hook
|
|
27
|
+
// must not load (startup budget); it used to be a third hand-spelled copy of the
|
|
28
|
+
// same three path segments (JS-05).
|
|
29
|
+
const { MANIFEST_FILE: MANIFEST_PATH } = require('./cache-paths');
|
|
28
30
|
|
|
29
31
|
// --- Per-type rate limiting (replaces single global cooldown) ---
|
|
30
32
|
const COOLDOWNS = {
|
|
@@ -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.139.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.139.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.139.0",
|
|
39
|
+
"@sdsrs/code-graph-linux-arm64": "0.139.0",
|
|
40
|
+
"@sdsrs/code-graph-darwin-x64": "0.139.0",
|
|
41
|
+
"@sdsrs/code-graph-darwin-arm64": "0.139.0",
|
|
42
|
+
"@sdsrs/code-graph-win32-x64": "0.139.0"
|
|
43
43
|
}
|
|
44
44
|
}
|