dsh-gitnexus-plus 0.0.0-stage → 0.1.1

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 (78) hide show
  1. package/LICENSE +38 -0
  2. package/README.md +483 -2
  3. package/cordis.patch.yml +18 -0
  4. package/lib/bin/gitnexus-coverage.d.ts +14 -0
  5. package/lib/bin/gitnexus-coverage.d.ts.map +1 -0
  6. package/lib/bin/gitnexus-coverage.js +171 -0
  7. package/lib/bin/gitnexus-coverage.js.map +1 -0
  8. package/lib/client.js +1642 -0
  9. package/lib/gitnexus/analyze.d.ts +148 -0
  10. package/lib/gitnexus/analyze.d.ts.map +1 -0
  11. package/lib/gitnexus/analyze.js +283 -0
  12. package/lib/gitnexus/analyze.js.map +1 -0
  13. package/lib/gitnexus/commands.d.ts +96 -0
  14. package/lib/gitnexus/commands.d.ts.map +1 -0
  15. package/lib/gitnexus/commands.js +132 -0
  16. package/lib/gitnexus/commands.js.map +1 -0
  17. package/lib/gitnexus/coverage.d.ts +340 -0
  18. package/lib/gitnexus/coverage.d.ts.map +1 -0
  19. package/lib/gitnexus/coverage.js +552 -0
  20. package/lib/gitnexus/coverage.js.map +1 -0
  21. package/lib/gitnexus/format.d.ts +16 -0
  22. package/lib/gitnexus/format.d.ts.map +1 -0
  23. package/lib/gitnexus/format.js +178 -0
  24. package/lib/gitnexus/format.js.map +1 -0
  25. package/lib/gitnexus/git-activity.d.ts +136 -0
  26. package/lib/gitnexus/git-activity.d.ts.map +1 -0
  27. package/lib/gitnexus/git-activity.js +345 -0
  28. package/lib/gitnexus/git-activity.js.map +1 -0
  29. package/lib/gitnexus/git.d.ts +70 -0
  30. package/lib/gitnexus/git.d.ts.map +1 -0
  31. package/lib/gitnexus/git.js +121 -0
  32. package/lib/gitnexus/git.js.map +1 -0
  33. package/lib/gitnexus/index-meta.d.ts +150 -0
  34. package/lib/gitnexus/index-meta.d.ts.map +1 -0
  35. package/lib/gitnexus/index-meta.js +156 -0
  36. package/lib/gitnexus/index-meta.js.map +1 -0
  37. package/lib/gitnexus/install.d.ts +97 -0
  38. package/lib/gitnexus/install.d.ts.map +1 -0
  39. package/lib/gitnexus/install.js +228 -0
  40. package/lib/gitnexus/install.js.map +1 -0
  41. package/lib/gitnexus/languages.d.ts +73 -0
  42. package/lib/gitnexus/languages.d.ts.map +1 -0
  43. package/lib/gitnexus/languages.js +217 -0
  44. package/lib/gitnexus/languages.js.map +1 -0
  45. package/lib/gitnexus/root.d.ts +68 -0
  46. package/lib/gitnexus/root.d.ts.map +1 -0
  47. package/lib/gitnexus/root.js +162 -0
  48. package/lib/gitnexus/root.js.map +1 -0
  49. package/lib/gitnexus/scan.d.ts +67 -0
  50. package/lib/gitnexus/scan.d.ts.map +1 -0
  51. package/lib/gitnexus/scan.js +247 -0
  52. package/lib/gitnexus/scan.js.map +1 -0
  53. package/lib/gitnexus/toolchain.d.ts +136 -0
  54. package/lib/gitnexus/toolchain.d.ts.map +1 -0
  55. package/lib/gitnexus/toolchain.js +251 -0
  56. package/lib/gitnexus/toolchain.js.map +1 -0
  57. package/lib/index.d.ts +79 -0
  58. package/lib/index.d.ts.map +1 -0
  59. package/lib/index.js +211 -0
  60. package/lib/index.js.map +1 -0
  61. package/lib/routes/analyze.d.ts +35 -0
  62. package/lib/routes/analyze.d.ts.map +1 -0
  63. package/lib/routes/analyze.js +71 -0
  64. package/lib/routes/analyze.js.map +1 -0
  65. package/lib/routes/coverage.d.ts +44 -0
  66. package/lib/routes/coverage.d.ts.map +1 -0
  67. package/lib/routes/coverage.js +68 -0
  68. package/lib/routes/coverage.js.map +1 -0
  69. package/lib/routes/guard.d.ts +92 -0
  70. package/lib/routes/guard.d.ts.map +1 -0
  71. package/lib/routes/guard.js +187 -0
  72. package/lib/routes/guard.js.map +1 -0
  73. package/lib/routes/install.d.ts +27 -0
  74. package/lib/routes/install.d.ts.map +1 -0
  75. package/lib/routes/install.js +46 -0
  76. package/lib/routes/install.js.map +1 -0
  77. package/package.json +87 -4
  78. package/scripts/link-runtime.mjs +146 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Reproduce GitNexus's scan decision and expose what it discards.
3
+ *
4
+ * `walkRepositoryPaths` (gitnexus/dist/core/ingestion/filesystem-walker.js)
5
+ * makes three cuts and only returns the survivors:
6
+ *
7
+ * 1. `glob(recursive, { nodir: true, dot: false, ignore: createIgnoreFilter(repo) })`
8
+ * — drops dotfiles (`dot: false`) and anything the ignore rules match.
9
+ * 2. `stat.size > maxFileSizeBytes` — the large-file cut. **Counted and logged
10
+ * but never returned**, so an external tool cannot see it.
11
+ * 3. `.d.ts` / `.d.mts` / `.d.cts` whose same-stem implementation was also
12
+ * scanned — suppressed as redundant.
13
+ *
14
+ * This module applies cuts 1 and 3 exactly as upstream does (reusing upstream's
15
+ * own `createIgnoreFilter` and glob), and turns cut 2 — the one that is invisible
16
+ * from outside — into data.
17
+ *
18
+ * Deliberate duplication: the single `glob(...)` call below mirrors
19
+ * `filesystem-walker.js:62-67`. It is four lines and must stay in lockstep with
20
+ * upstream. If it ever drifts, `test/run.mjs` catches it by cross-checking the
21
+ * reported large-file count against what `analyze` itself prints.
22
+ */
23
+ import fs from 'node:fs/promises';
24
+ import path from 'node:path';
25
+ import { loadScanPrimitives } from './root.js';
26
+ /** Mirrors DECLARATION_COMPANION_SUFFIXES in filesystem-walker.js. */
27
+ const DECLARATION_COMPANION_SUFFIXES = Object.freeze([
28
+ { declaration: '.d.ts', implementations: ['.ts', '.tsx'] },
29
+ { declaration: '.d.mts', implementations: ['.mts'] },
30
+ { declaration: '.d.cts', implementations: ['.cts'] },
31
+ ]);
32
+ /** Bounded concurrency for `fs.stat`, matching GitNexus's READ_CONCURRENCY. */
33
+ const STAT_CONCURRENCY = 32;
34
+ /**
35
+ * @returns entries minus redundant declaration files
36
+ */
37
+ function dropRedundantDeclarations(entries) {
38
+ const scannedPaths = new Set(entries.map((e) => e.path));
39
+ return entries.filter((entry) => {
40
+ const companion = DECLARATION_COMPANION_SUFFIXES.find(({ declaration }) => entry.path.endsWith(declaration));
41
+ if (!companion)
42
+ return true;
43
+ const stem = entry.path.slice(0, -companion.declaration.length);
44
+ const redundant = companion.implementations.some((suffix) => scannedPaths.has(`${stem}${suffix}`));
45
+ return !redundant;
46
+ });
47
+ }
48
+ function redundantDeclarations(entries, selectedPaths) {
49
+ const kept = new Set(selectedPaths);
50
+ return entries.filter((e) => !kept.has(e.path));
51
+ }
52
+ /**
53
+ * Run a batched `fs.stat` over repo-relative paths.
54
+ * Unreadable files are skipped rather than failing the scan: a file that
55
+ * disappears mid-scan is normal, not an error.
56
+ */
57
+ async function statAll(repoPath, relativePaths) {
58
+ const out = [];
59
+ for (let i = 0; i < relativePaths.length; i += STAT_CONCURRENCY) {
60
+ const batch = relativePaths.slice(i, i + STAT_CONCURRENCY);
61
+ const settled = await Promise.allSettled(batch.map(async (relativePath) => {
62
+ const stat = await fs.stat(path.join(repoPath, relativePath));
63
+ return { path: relativePath.replace(/\\/g, '/'), size: stat.size };
64
+ }));
65
+ for (const result of settled) {
66
+ if (result.status === 'fulfilled')
67
+ out.push(result.value);
68
+ }
69
+ }
70
+ return out;
71
+ }
72
+ /**
73
+ * Scan a repository the way GitNexus does, and report the size cut as data.
74
+ *
75
+ * @param repoPath absolute path to the repository root
76
+ * @param options `capBytes` overrides the cap (used when the index records its own coverage
77
+ * policy); otherwise `GITNEXUS_MAX_FILE_SIZE` decides, as it does for `analyze`.
78
+ */
79
+ export async function scanRepository(repoPath, options = {}) {
80
+ const env = options.env ?? process.env;
81
+ const primitives = options.primitives === undefined ? await loadScanPrimitives({ env }) : options.primitives;
82
+ const defaultCapBytes = primitives?.DEFAULT_MAX_FILE_SIZE_BYTES ?? 512 * 1024;
83
+ const maxCapBytes = primitives?.MAX_FILE_SIZE_UPPER_BOUND_BYTES ?? 32 * 1024 * 1024;
84
+ let capBytes;
85
+ let capSource;
86
+ if (typeof options.capBytes === 'number' && Number.isFinite(options.capBytes) && options.capBytes > 0) {
87
+ capBytes = Math.min(options.capBytes, maxCapBytes);
88
+ capSource = 'index';
89
+ }
90
+ else if (primitives) {
91
+ capBytes = Math.min(primitives.getMaxFileSizeBytes(), maxCapBytes);
92
+ capSource = env.GITNEXUS_MAX_FILE_SIZE ? 'env' : 'default';
93
+ }
94
+ else {
95
+ const parsed = Number(env.GITNEXUS_MAX_FILE_SIZE);
96
+ const valid = Number.isInteger(parsed) && parsed > 0;
97
+ capBytes = valid ? Math.min(parsed * 1024, maxCapBytes) : defaultCapBytes;
98
+ capSource = valid ? 'env' : 'default';
99
+ }
100
+ let matched;
101
+ if (primitives) {
102
+ // Upstream's own filter and glob options, verbatim.
103
+ const ignoreFilter = await primitives.createIgnoreFilter(repoPath);
104
+ matched = await primitives.glob('**/*', {
105
+ cwd: repoPath,
106
+ nodir: true,
107
+ dot: false,
108
+ ignore: ignoreFilter,
109
+ });
110
+ }
111
+ else {
112
+ matched = await fallbackWalk(repoPath);
113
+ }
114
+ const scanned = await statAll(repoPath, matched);
115
+ scanned.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
116
+ const large = [];
117
+ const withinCap = [];
118
+ for (const file of scanned) {
119
+ if (file.size > capBytes)
120
+ large.push(file);
121
+ else
122
+ withinCap.push(file);
123
+ }
124
+ const selected = dropRedundantDeclarations(withinCap);
125
+ const suppressed = redundantDeclarations(withinCap, selected.map((f) => f.path));
126
+ large.sort((a, b) => b.size - a.size || (a.path < b.path ? -1 : 1));
127
+ return {
128
+ selected,
129
+ large,
130
+ suppressedDeclarations: suppressed,
131
+ scannedCount: scanned.length,
132
+ capBytes,
133
+ defaultCapBytes,
134
+ capSource,
135
+ maxCapBytes,
136
+ gitnexusVersion: primitives?.gitnexusVersion ?? 'unknown',
137
+ primitives: primitives ? 'gitnexus' : 'fallback',
138
+ };
139
+ }
140
+ /**
141
+ * Minimal `.gitignore`-style matcher used **only** when GitNexus's ignore service
142
+ * cannot be loaded.
143
+ *
144
+ * This is an approximation and is labelled as one wherever it surfaces
145
+ * (`ScanReport.primitives === 'fallback'`). It deliberately does not implement
146
+ * negation: refusing to un-ignore a file can over-report exclusions, whereas
147
+ * honouring `!` incorrectly would under-report skipped large files — and the
148
+ * second error is the one this tool exists to prevent.
149
+ *
150
+ * @param pattern a gitignore line, already trimmed
151
+ */
152
+ function compileIgnorePattern(pattern) {
153
+ const cleaned = pattern.replace(/^\//, '').replace(/\/+$/, '');
154
+ const parts = cleaned.split('/').filter((p) => p !== '');
155
+ const toSegmentRegex = (segment) => new RegExp(`^${segment.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[^/]*').replace(/\?/g, '[^/]')}$`, 'i');
156
+ return (segments) => {
157
+ // A pattern with no slash matches a basename at any depth; a pattern with one
158
+ // is anchored to the repository root (gitignore's own rule).
159
+ if (parts.length === 1) {
160
+ const re = toSegmentRegex(parts[0]);
161
+ return segments.some((s) => re.test(s));
162
+ }
163
+ // `**` spans any number of segments; expand it greedily by simple recursion.
164
+ const matchFrom = (pi, si) => {
165
+ if (pi === parts.length)
166
+ return true;
167
+ if (si > segments.length)
168
+ return false;
169
+ if (parts[pi] === '**') {
170
+ for (let skip = si; skip <= segments.length; skip += 1) {
171
+ if (matchFrom(pi + 1, skip))
172
+ return true;
173
+ }
174
+ return false;
175
+ }
176
+ if (si === segments.length)
177
+ return false;
178
+ return toSegmentRegex(parts[pi]).test(segments[si]) && matchFrom(pi + 1, si + 1);
179
+ };
180
+ return parts[0] === '**' ? matchFrom(0, 0) : matchFrom(0, 0);
181
+ };
182
+ }
183
+ /**
184
+ * Read `.gitignore` and `.gitnexusignore` into predicates, plus the two
185
+ * directories GitNexus always ignores.
186
+ */
187
+ async function loadFallbackRules(repoPath) {
188
+ const matchers = [compileIgnorePattern('node_modules'), compileIgnorePattern('.git')];
189
+ for (const name of ['.gitignore', '.gitnexusignore']) {
190
+ let text;
191
+ try {
192
+ text = await fs.readFile(path.join(repoPath, name), 'utf8');
193
+ }
194
+ catch {
195
+ continue;
196
+ }
197
+ for (const raw of text.split(/\r?\n/)) {
198
+ const line = raw.trim();
199
+ if (line === '' || line.startsWith('#') || line.startsWith('!'))
200
+ continue;
201
+ matchers.push(compileIgnorePattern(line));
202
+ }
203
+ }
204
+ return matchers;
205
+ }
206
+ /**
207
+ * Dependency-free fallback walk, used only when GitNexus's `glob` cannot be
208
+ * resolved. Mirrors two upstream behaviours that are easy to get wrong:
209
+ *
210
+ * - `dot: false` — a path is excluded when *any* segment begins with `.`,
211
+ * which is why `.github/workflows/ci.yml` never reaches the pipeline.
212
+ * - directories matched by the ignore rules prune their whole subtree.
213
+ *
214
+ * @returns repo-relative paths, forward slashes
215
+ */
216
+ async function fallbackWalk(repoPath) {
217
+ const rules = await loadFallbackRules(repoPath);
218
+ const ignored = (segments) => rules.some((rule) => rule(segments));
219
+ const out = [];
220
+ const queue = [{ abs: repoPath, rel: [] }];
221
+ while (queue.length > 0) {
222
+ const dir = queue.pop();
223
+ let entries;
224
+ try {
225
+ entries = await fs.readdir(dir.abs, { withFileTypes: true });
226
+ }
227
+ catch {
228
+ continue;
229
+ }
230
+ for (const entry of entries) {
231
+ if (entry.name.startsWith('.'))
232
+ continue; // dot: false
233
+ const segments = [...dir.rel, entry.name];
234
+ if (ignored(segments))
235
+ continue;
236
+ const abs = path.join(dir.abs, entry.name);
237
+ if (entry.isDirectory()) {
238
+ queue.push({ abs, rel: segments });
239
+ }
240
+ else if (entry.isFile()) {
241
+ out.push(segments.join('/'));
242
+ }
243
+ }
244
+ }
245
+ return out;
246
+ }
247
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/gitnexus/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Whether GitNexus is actually available on this machine.
3
+ *
4
+ * WHY THIS EXISTS
5
+ * ---------------
6
+ * The plugin declares **no runtime dependencies** and never imports `gitnexus` as a
7
+ * module. It reads an index another tool produced and, when it can, deep-imports the
8
+ * upstream scan primitives at runtime. That design keeps the plugin a pure observer —
9
+ * but it means "the operator has no GitNexus" is a first-class reachable state, not
10
+ * an edge case, and nothing was checking for it.
11
+ *
12
+ * The consequence was not a crash. The engine degrades: `loadScanPrimitives` returns
13
+ * `null`, the local walker takes over, and the size caps fall back to their built-in
14
+ * defaults. The damage was in what the operator was **told**: with no index, the panel
15
+ * handed over `gitnexus analyze --index-only …` — a command that fails with
16
+ * `command not found` on a machine that has no GitNexus, presented as the next step.
17
+ *
18
+ * TWO SEPARATE QUESTIONS
19
+ * ----------------------
20
+ * The library tree and the CLI are different things and are reported separately,
21
+ * because they gate different promises:
22
+ *
23
+ * - **package root** — can this plugin reuse GitNexus's own scan rules and language
24
+ * detector, and are the numbers therefore authoritative?
25
+ * - **CLI on PATH** — will the maintenance command the panel hands over actually
26
+ * run when the operator pastes it?
27
+ *
28
+ * A `gitnexus` installed as a dependency but never linked globally satisfies the
29
+ * first and not the second, and collapsing them into one boolean would make the
30
+ * panel either over- or under-promise in that case.
31
+ */
32
+ /** The probe order for a platform. Exported so a test can assert the ordering. */
33
+ export declare function cliShimNames(platform?: NodeJS.Platform): readonly string[];
34
+ /**
35
+ * The POSIX probe order, kept exported under its original name.
36
+ *
37
+ * Callers that need the real answer must use {@link cliShimNames}; this is the list
38
+ * for a platform where the extensionless shim is the correct one.
39
+ */
40
+ export declare const CLI_SHIM_NAMES: readonly string[];
41
+ export interface CliProbeFound {
42
+ present: true;
43
+ /**
44
+ * Absolute path to the thing that runs the CLI.
45
+ *
46
+ * A `.js` script when it came from the declared `gitnexus` dependency — that
47
+ * package's `bin` is `dist/cli/index.js` — and a shim path when it came from PATH.
48
+ * `viaNode` says which, because the two need different command shapes: a script is
49
+ * spawned as `node <path>`, a shim is spawned directly (and on Windows needs the
50
+ * shell's call operator).
51
+ */
52
+ cliPath: string;
53
+ /** Whether `cliPath` has to be run through `node`. */
54
+ viaNode: boolean;
55
+ /** Where this came from, so an unexpected pick can be diagnosed. */
56
+ source: 'override' | 'managed' | 'dependency' | 'path';
57
+ /** The package root it was resolved from, when it came from a dependency. */
58
+ packageRoot: string | null;
59
+ }
60
+ export interface CliProbeMissing {
61
+ present: false;
62
+ /** How many PATH entries were examined — evidence the probe actually ran. */
63
+ probedDirs: number;
64
+ }
65
+ /**
66
+ * How much of GitNexus is available.
67
+ *
68
+ * `library-only` is the case worth naming: analysis is authoritative, but a handed-over
69
+ * command will not run as typed.
70
+ */
71
+ export type ToolchainVerdict =
72
+ /** Both the library tree and a CLI shim are present. Every promise holds. */
73
+ 'ready'
74
+ /** The library tree is present but no CLI shim was found on PATH. */
75
+ | 'library-only'
76
+ /** Neither was found: the plugin falls back to its own scan rules. */
77
+ | 'absent';
78
+ export interface ToolchainStatus {
79
+ /** Where the GitNexus package tree was found, if anywhere. */
80
+ packageRoot: string | null;
81
+ /** Version read from that tree's manifest, for provenance. */
82
+ packageVersion: string | null;
83
+ /** Whether a `gitnexus` executable is reachable through PATH. */
84
+ cli: CliProbeFound | CliProbeMissing;
85
+ verdict: ToolchainVerdict;
86
+ }
87
+ export interface ToolchainOptions {
88
+ env?: NodeJS.ProcessEnv;
89
+ moduleUrl?: string;
90
+ /** Platform whose shim naming applies. Defaults to the running one. */
91
+ platform?: NodeJS.Platform;
92
+ /**
93
+ * Where this plugin installs GitNexus when the operator asks it to.
94
+ *
95
+ * Checked before the dependency and PATH so that a copy the plugin installed is the
96
+ * one it uses: that copy is the only one whose version it chose, and finding a
97
+ * different one later would make the refresh behave differently from the install that
98
+ * preceded it.
99
+ */
100
+ managedPrefix?: string;
101
+ /** Skips discovery entirely, returning an `absent` verdict — for tests. */
102
+ discover?: boolean;
103
+ }
104
+ /**
105
+ * Resolve the `gitnexus` CLI this plugin will run.
106
+ *
107
+ * ORDER: explicit override, then the declared dependency, then PATH.
108
+ *
109
+ * The dependency comes first because the plugin now declares `gitnexus` as one, so it
110
+ * is present by construction and no PATH search is needed — the "is GitNexus installed"
111
+ * question stops being a runtime check and becomes an install-time guarantee. That was
112
+ * the whole point of taking the dependency: a check that always succeeds is not a check.
113
+ *
114
+ * PATH remains as the fallback rather than the primary, because a normal `npm install`
115
+ * of this plugin puts `gitnexus` beside it in `node_modules`, where PATH never looks.
116
+ * Keeping the search means a machine with a global install still works if the
117
+ * dependency somehow did not land, and it keeps this repository's own tests runnable
118
+ * without a 1 GB install.
119
+ *
120
+ * Does not execute anything. Spawning the CLI to ask its version would be the direct
121
+ * test, but a confined DSH process denies piped stdio (`spawn EPERM`), which is the
122
+ * same constraint that shaped the maintenance commands — so a probe that only stats the
123
+ * filesystem is the one that works everywhere this plugin runs.
124
+ */
125
+ export declare function findGitnexusCli(options?: ToolchainOptions): CliProbeFound | CliProbeMissing;
126
+ /** Resolve the full picture: library tree, CLI shim, and the verdict they imply. */
127
+ export declare function readToolchainStatus(options?: ToolchainOptions): ToolchainStatus;
128
+ /**
129
+ * The one-line explanation the panel and the CLI show, or `null` when everything is
130
+ * present and there is nothing to warn about.
131
+ *
132
+ * Kept here rather than in the browser half so the CLI and the panel cannot describe
133
+ * the same machine state two different ways.
134
+ */
135
+ export declare function toolchainNotice(status: ToolchainStatus): string | null;
136
+ //# sourceMappingURL=toolchain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolchain.d.ts","sourceRoot":"","sources":["../../src/gitnexus/toolchain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AA2CH,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,SAAS,MAAM,EAAE,CAE5F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAAqB,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,IAAI,CAAC;IACd;;;;;;;;OAQG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;IACvD,6EAA6E;IAC7E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB;AAC1B,6EAA6E;AAC3E,OAAO;AACT,qEAAqE;GACnE,cAAc;AAChB,sEAAsE;GACpE,QAAQ,CAAC;AAEb,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,8DAA8D;IAC9D,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iEAAiE;IACjE,GAAG,EAAE,aAAa,GAAG,eAAe,CAAC;IACrC,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAuBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,aAAa,GAAG,eAAe,CAkD/F;AAoDD,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CASnF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAgBtE"}
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Whether GitNexus is actually available on this machine.
3
+ *
4
+ * WHY THIS EXISTS
5
+ * ---------------
6
+ * The plugin declares **no runtime dependencies** and never imports `gitnexus` as a
7
+ * module. It reads an index another tool produced and, when it can, deep-imports the
8
+ * upstream scan primitives at runtime. That design keeps the plugin a pure observer —
9
+ * but it means "the operator has no GitNexus" is a first-class reachable state, not
10
+ * an edge case, and nothing was checking for it.
11
+ *
12
+ * The consequence was not a crash. The engine degrades: `loadScanPrimitives` returns
13
+ * `null`, the local walker takes over, and the size caps fall back to their built-in
14
+ * defaults. The damage was in what the operator was **told**: with no index, the panel
15
+ * handed over `gitnexus analyze --index-only …` — a command that fails with
16
+ * `command not found` on a machine that has no GitNexus, presented as the next step.
17
+ *
18
+ * TWO SEPARATE QUESTIONS
19
+ * ----------------------
20
+ * The library tree and the CLI are different things and are reported separately,
21
+ * because they gate different promises:
22
+ *
23
+ * - **package root** — can this plugin reuse GitNexus's own scan rules and language
24
+ * detector, and are the numbers therefore authoritative?
25
+ * - **CLI on PATH** — will the maintenance command the panel hands over actually
26
+ * run when the operator pastes it?
27
+ *
28
+ * A `gitnexus` installed as a dependency but never linked globally satisfies the
29
+ * first and not the second, and collapsing them into one boolean would make the
30
+ * panel either over- or under-promise in that case.
31
+ */
32
+ import { existsSync } from 'node:fs';
33
+ import { fileURLToPath } from 'node:url';
34
+ import path from 'node:path';
35
+ import { findGitnexusRoot, readGitnexusVersion } from './root.js';
36
+ /**
37
+ * Filenames a `gitnexus` CLI shim can have, in probe order **per platform**.
38
+ *
39
+ * Written out rather than derived from `PATHEXT`, for the reason `root.ts` already
40
+ * documents: under nvm-for-windows the shim is `gitnexus.ps1`, and `PATHEXT` does not
41
+ * list `.ps1`, so extension-driven discovery silently finds nothing on exactly the
42
+ * machines where the CLI is installed.
43
+ *
44
+ * ORDER IS PLATFORM-SPECIFIC, AND THAT IS THE WHOLE POINT
45
+ * ------------------------------------------------------
46
+ * npm writes three shims side by side: `gitnexus` (a `#!/bin/sh` script), `gitnexus.cmd`
47
+ * and `gitnexus.ps1`. The extensionless one is the POSIX entry point; on Windows it is
48
+ * inert. Measured on the reference machine:
49
+ *
50
+ * gitnexus -> no output, no exit status
51
+ * gitnexus.ps1 -> 1.6.12, exit 0
52
+ * gitnexus.cmd -> 1.6.12, exit 0
53
+ *
54
+ * A single order listing the extensionless name first — which is the natural way to
55
+ * write it — therefore selects a shim that cannot run on Windows, and the `.ps1`
56
+ * fix above it never gets a chance to help. The runner would build a command around
57
+ * that path and report a failure that has nothing to do with the repository.
58
+ *
59
+ * `.cmd` leads on Windows because it is the one a batch *or* a PowerShell host can
60
+ * spawn; `.ps1` follows for installs that ship only that.
61
+ */
62
+ const WINDOWS_SHIM_NAMES = [
63
+ 'gitnexus.cmd',
64
+ 'gitnexus.exe',
65
+ 'gitnexus.bat',
66
+ 'gitnexus.ps1',
67
+ 'gitnexus',
68
+ ];
69
+ const POSIX_SHIM_NAMES = ['gitnexus'];
70
+ /** The probe order for a platform. Exported so a test can assert the ordering. */
71
+ export function cliShimNames(platform = process.platform) {
72
+ return platform === 'win32' ? WINDOWS_SHIM_NAMES : POSIX_SHIM_NAMES;
73
+ }
74
+ /**
75
+ * The POSIX probe order, kept exported under its original name.
76
+ *
77
+ * Callers that need the real answer must use {@link cliShimNames}; this is the list
78
+ * for a platform where the extensionless shim is the correct one.
79
+ */
80
+ export const CLI_SHIM_NAMES = POSIX_SHIM_NAMES;
81
+ /**
82
+ * The effective `PATH`, whatever the platform spells it.
83
+ *
84
+ * `process.env` is a case-insensitive proxy — `process.env.PATH` resolves on Windows
85
+ * even though the variable is stored as `Path`. **Spreading it into a plain object
86
+ * drops that**, so `{ ...process.env }.PATH` is `undefined` on the default Windows
87
+ * layout and the probe walks zero directories while reporting a plausible-looking
88
+ * miss. That is how this was found: the runner reported "no gitnexus" on a machine
89
+ * where `gitnexus` runs, with `probedDirs: 0` as the only clue.
90
+ *
91
+ * Caller-supplied values still win, checked in the same three spellings so an
92
+ * override cannot be lost the same way.
93
+ */
94
+ function effectivePath(override) {
95
+ const pick = (source) => {
96
+ if (source === undefined)
97
+ return undefined;
98
+ return source.PATH ?? source.Path ?? source.path;
99
+ };
100
+ return pick(override) ?? pick(process.env) ?? '';
101
+ }
102
+ /**
103
+ * Resolve the `gitnexus` CLI this plugin will run.
104
+ *
105
+ * ORDER: explicit override, then the declared dependency, then PATH.
106
+ *
107
+ * The dependency comes first because the plugin now declares `gitnexus` as one, so it
108
+ * is present by construction and no PATH search is needed — the "is GitNexus installed"
109
+ * question stops being a runtime check and becomes an install-time guarantee. That was
110
+ * the whole point of taking the dependency: a check that always succeeds is not a check.
111
+ *
112
+ * PATH remains as the fallback rather than the primary, because a normal `npm install`
113
+ * of this plugin puts `gitnexus` beside it in `node_modules`, where PATH never looks.
114
+ * Keeping the search means a machine with a global install still works if the
115
+ * dependency somehow did not land, and it keeps this repository's own tests runnable
116
+ * without a 1 GB install.
117
+ *
118
+ * Does not execute anything. Spawning the CLI to ask its version would be the direct
119
+ * test, but a confined DSH process denies piped stdio (`spawn EPERM`), which is the
120
+ * same constraint that shaped the maintenance commands — so a probe that only stats the
121
+ * filesystem is the one that works everywhere this plugin runs.
122
+ */
123
+ export function findGitnexusCli(options = {}) {
124
+ if (options.discover === false)
125
+ return { present: false, probedDirs: 0 };
126
+ const platform = options.platform ?? process.platform;
127
+ // An explicit override wins, so a machine with a non-standard layout — or a test —
128
+ // can name the executable directly.
129
+ const explicit = options.env?.GITNEXUS_CLI ?? process.env.GITNEXUS_CLI;
130
+ if (typeof explicit === 'string' && explicit !== '' && existsSync(explicit)) {
131
+ return {
132
+ present: true,
133
+ cliPath: explicit,
134
+ viaNode: explicit.endsWith('.js'),
135
+ source: 'override',
136
+ packageRoot: null,
137
+ };
138
+ }
139
+ // The copy this plugin installed, when there is one. Ahead of the dependency and PATH
140
+ // because it is the only copy whose version this plugin chose: finding a different one
141
+ // afterwards would make the refresh behave differently from the install before it.
142
+ const managed = options.managedPrefix;
143
+ if (typeof managed === 'string' && managed !== '') {
144
+ const script = path.join(managed, 'node_modules', 'gitnexus', 'dist', 'cli', 'index.js');
145
+ try {
146
+ if (existsSync(script)) {
147
+ return { present: true, cliPath: script, viaNode: true, source: 'managed', packageRoot: path.join(managed, 'node_modules', 'gitnexus') };
148
+ }
149
+ }
150
+ catch {
151
+ /* unreadable managed tree — fall through to the other sources */
152
+ }
153
+ }
154
+ const fromDependency = resolveDependencyCli(options);
155
+ if (fromDependency !== null)
156
+ return fromDependency;
157
+ const entries = effectivePath(options.env).split(path.delimiter).filter((dir) => dir !== '');
158
+ for (const dir of entries) {
159
+ for (const name of cliShimNames(platform)) {
160
+ const candidate = path.join(dir, name);
161
+ try {
162
+ if (existsSync(candidate)) {
163
+ return { present: true, cliPath: candidate, viaNode: false, source: 'path', packageRoot: null };
164
+ }
165
+ }
166
+ catch {
167
+ /* unreadable PATH entry — keep looking */
168
+ }
169
+ }
170
+ }
171
+ return { present: false, probedDirs: entries.length };
172
+ }
173
+ /**
174
+ * The CLI shipped inside the `gitnexus` dependency, if it is installed.
175
+ *
176
+ * Resolved by walking up from this module rather than by asking Node to resolve the
177
+ * package name, because these modules are CommonJS-compiled and a bare `require` of an
178
+ * ESM-only package would throw for a reason unrelated to whether the file exists. Each
179
+ * candidate is a plain `node_modules/gitnexus` directory on the way to the filesystem
180
+ * root, which is exactly where npm and pnpm put it.
181
+ */
182
+ function resolveDependencyCli(options) {
183
+ const startDir = options.moduleUrl === undefined ? undefined : safeDirname(options.moduleUrl);
184
+ let dir = startDir ?? undefined;
185
+ // `import.meta.url` is only available in the host half, so the caller may not pass
186
+ // one; without a starting point there is nothing to walk and PATH is the answer.
187
+ if (dir === undefined)
188
+ return null;
189
+ for (let depth = 0; depth < 24; depth += 1) {
190
+ const candidateRoot = path.join(dir, 'node_modules', 'gitnexus');
191
+ const manifest = path.join(candidateRoot, 'package.json');
192
+ const script = path.join(candidateRoot, 'dist', 'cli', 'index.js');
193
+ try {
194
+ if (existsSync(manifest) && existsSync(script)) {
195
+ return {
196
+ present: true,
197
+ cliPath: script,
198
+ viaNode: true,
199
+ source: 'dependency',
200
+ packageRoot: candidateRoot,
201
+ };
202
+ }
203
+ }
204
+ catch {
205
+ /* unreadable directory — keep walking up */
206
+ }
207
+ const parent = path.dirname(dir);
208
+ if (parent === dir)
209
+ break;
210
+ dir = parent;
211
+ }
212
+ return null;
213
+ }
214
+ /** Directory of one module url, or `undefined` when it cannot be read as a path. */
215
+ function safeDirname(moduleUrl) {
216
+ try {
217
+ return path.dirname(fileURLToPath(moduleUrl));
218
+ }
219
+ catch {
220
+ return undefined;
221
+ }
222
+ }
223
+ /** Resolve the full picture: library tree, CLI shim, and the verdict they imply. */
224
+ export function readToolchainStatus(options = {}) {
225
+ const packageRoot = findGitnexusRoot(options);
226
+ const packageVersion = packageRoot === null ? null : readGitnexusVersion(packageRoot);
227
+ const cli = findGitnexusCli(options);
228
+ const verdict = packageRoot !== null && cli.present ? 'ready' : packageRoot !== null ? 'library-only' : 'absent';
229
+ return { packageRoot, packageVersion, cli, verdict };
230
+ }
231
+ /**
232
+ * The one-line explanation the panel and the CLI show, or `null` when everything is
233
+ * present and there is nothing to warn about.
234
+ *
235
+ * Kept here rather than in the browser half so the CLI and the panel cannot describe
236
+ * the same machine state two different ways.
237
+ */
238
+ export function toolchainNotice(status) {
239
+ switch (status.verdict) {
240
+ case 'ready':
241
+ return null;
242
+ case 'library-only':
243
+ return ('本机有 GitNexus 库但没有 gitnexus 命令(可能只作为依赖安装、未全局链接)。' +
244
+ '下面的命令需要先 `npm i -g gitnexus` 才能直接执行。');
245
+ case 'absent':
246
+ return ('本机没有 GitNexus。扫描规则来自本插件内置的回退实现,' +
247
+ '与 GitNexus 自身的忽略规则不完全一致,覆盖差异数字仅供参考。' +
248
+ '初始化索引需要先安装:`npm i -g gitnexus`。');
249
+ }
250
+ }
251
+ //# sourceMappingURL=toolchain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolchain.js","sourceRoot":"","sources":["../../src/gitnexus/toolchain.ts"],"names":[],"mappings":"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"}