codebase-snapshot 0.9.4 → 0.9.6
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/CHANGELOG.md +84 -0
- package/README.md +4 -1
- package/dist/bin.js +594 -304
- package/dist/{chunk-FCWD4LY7.js → chunk-3KUL3QRH.js} +564 -318
- package/dist/{chunk-EWZYK3VX.js → chunk-ZKZOGGM3.js} +33 -7
- package/dist/cli.cjs +697 -411
- package/dist/cli.d.cts +7 -1
- package/dist/cli.d.ts +7 -1
- package/dist/cli.js +19 -6
- package/dist/index.cjs +570 -312
- package/dist/index.d.cts +54 -2
- package/dist/index.d.ts +54 -2
- package/dist/index.js +1 -1
- package/dist/mcp.cjs +31 -4
- package/dist/mcp.d.cts +14 -1
- package/dist/mcp.d.ts +14 -1
- package/dist/mcp.js +2 -2
- package/docs/cli.md +29 -2
- package/docs/mcp.md +3 -3
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var childProcess = require('child_process');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var fs12 = require('fs');
|
|
5
|
+
var path13 = require('path');
|
|
6
6
|
var util = require('util');
|
|
7
7
|
var crypto2 = require('crypto');
|
|
8
8
|
var module$1 = require('module');
|
|
@@ -11,6 +11,7 @@ var readline = require('readline');
|
|
|
11
11
|
var async_hooks = require('async_hooks');
|
|
12
12
|
var os = require('os');
|
|
13
13
|
var ts = require('typescript');
|
|
14
|
+
var https = require('https');
|
|
14
15
|
|
|
15
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
17
|
|
|
@@ -33,12 +34,13 @@ function _interopNamespace(e) {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
var childProcess__namespace = /*#__PURE__*/_interopNamespace(childProcess);
|
|
36
|
-
var
|
|
37
|
-
var
|
|
37
|
+
var fs12__namespace = /*#__PURE__*/_interopNamespace(fs12);
|
|
38
|
+
var path13__namespace = /*#__PURE__*/_interopNamespace(path13);
|
|
38
39
|
var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
|
|
39
40
|
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
|
|
40
41
|
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
41
42
|
var ts__default = /*#__PURE__*/_interopDefault(ts);
|
|
43
|
+
var https__namespace = /*#__PURE__*/_interopNamespace(https);
|
|
42
44
|
|
|
43
45
|
// src/cli.ts
|
|
44
46
|
var MANIFEST_FILES = [
|
|
@@ -87,15 +89,15 @@ var SKIPPED_WALK_DIRS = /* @__PURE__ */ new Set([
|
|
|
87
89
|
]);
|
|
88
90
|
function readSmallFile(fullPath) {
|
|
89
91
|
try {
|
|
90
|
-
const stats =
|
|
92
|
+
const stats = fs12__namespace.statSync(fullPath);
|
|
91
93
|
if (!stats.isFile() || stats.size > MANIFEST_MAX_BYTES) return null;
|
|
92
|
-
return
|
|
94
|
+
return fs12__namespace.readFileSync(fullPath, "utf8");
|
|
93
95
|
} catch {
|
|
94
96
|
return null;
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
function readManifest(cwd, name) {
|
|
98
|
-
return readSmallFile(
|
|
100
|
+
return readSmallFile(path13__namespace.join(cwd, name));
|
|
99
101
|
}
|
|
100
102
|
function dependenciesFromPackageJson(raw) {
|
|
101
103
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -155,7 +157,7 @@ function pnpmWorkspacePatterns(raw) {
|
|
|
155
157
|
function childDirectories(cwd, parent) {
|
|
156
158
|
let entries;
|
|
157
159
|
try {
|
|
158
|
-
entries =
|
|
160
|
+
entries = fs12__namespace.readdirSync(path13__namespace.join(cwd, parent), { withFileTypes: true });
|
|
159
161
|
} catch {
|
|
160
162
|
return [];
|
|
161
163
|
}
|
|
@@ -191,12 +193,12 @@ function scanWorkspacePackages(cwd, patterns) {
|
|
|
191
193
|
const files = /* @__PURE__ */ new Set();
|
|
192
194
|
const dependencies = /* @__PURE__ */ new Set();
|
|
193
195
|
for (const relative11 of workspacePackageDirs(cwd, patterns)) {
|
|
194
|
-
const full =
|
|
196
|
+
const full = path13__namespace.join(cwd, relative11);
|
|
195
197
|
try {
|
|
196
|
-
for (const entry of
|
|
198
|
+
for (const entry of fs12__namespace.readdirSync(full, { withFileTypes: true })) files.add(entry.name);
|
|
197
199
|
} catch {
|
|
198
200
|
}
|
|
199
|
-
const raw = readSmallFile(
|
|
201
|
+
const raw = readSmallFile(path13__namespace.join(full, "package.json"));
|
|
200
202
|
if (raw !== null) {
|
|
201
203
|
for (const name of dependenciesFromPackageJson(raw)) dependencies.add(name);
|
|
202
204
|
}
|
|
@@ -213,7 +215,7 @@ function countMarkdownFiles(cwd) {
|
|
|
213
215
|
directoriesSeen += 1;
|
|
214
216
|
let entries;
|
|
215
217
|
try {
|
|
216
|
-
entries =
|
|
218
|
+
entries = fs12__namespace.readdirSync(current.dir, { withFileTypes: true });
|
|
217
219
|
} catch {
|
|
218
220
|
continue;
|
|
219
221
|
}
|
|
@@ -224,7 +226,7 @@ function countMarkdownFiles(cwd) {
|
|
|
224
226
|
}
|
|
225
227
|
if (!entry.isDirectory() || current.depth >= 2) continue;
|
|
226
228
|
if (entry.name.startsWith(".") || SKIPPED_WALK_DIRS.has(entry.name)) continue;
|
|
227
|
-
queue.push({ dir:
|
|
229
|
+
queue.push({ dir: path13__namespace.join(current.dir, entry.name), depth: current.depth + 1 });
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
return count;
|
|
@@ -233,7 +235,7 @@ function buildPresetContext(cwd) {
|
|
|
233
235
|
const files = /* @__PURE__ */ new Set();
|
|
234
236
|
const dirs = /* @__PURE__ */ new Set();
|
|
235
237
|
try {
|
|
236
|
-
for (const entry of
|
|
238
|
+
for (const entry of fs12__namespace.readdirSync(cwd, { withFileTypes: true })) {
|
|
237
239
|
if (entry.isDirectory()) dirs.add(entry.name);
|
|
238
240
|
else if (entry.isFile()) files.add(entry.name);
|
|
239
241
|
}
|
|
@@ -250,7 +252,7 @@ function buildPresetContext(cwd) {
|
|
|
250
252
|
const isWorkspace = files.has("pnpm-workspace.yaml") || files.has("nx.json") || files.has("turbo.json") || files.has("lerna.json") || packageJson !== void 0 && packageJson.includes('"workspaces"') || declaredWorkspaces.length > 0;
|
|
251
253
|
let workspace = { files: /* @__PURE__ */ new Set(), dependencies: /* @__PURE__ */ new Set() };
|
|
252
254
|
if (isWorkspace) {
|
|
253
|
-
const pnpmRaw = files.has("pnpm-workspace.yaml") ? readSmallFile(
|
|
255
|
+
const pnpmRaw = files.has("pnpm-workspace.yaml") ? readSmallFile(path13__namespace.join(cwd, "pnpm-workspace.yaml")) : null;
|
|
254
256
|
const declared = pnpmRaw === null ? [] : pnpmWorkspacePatterns(pnpmRaw);
|
|
255
257
|
const patterns = declared.length > 0 ? declared : declaredWorkspaces.length > 0 ? declaredWorkspaces : DEFAULT_WORKSPACE_PATTERNS;
|
|
256
258
|
workspace = scanWorkspacePackages(cwd, patterns);
|
|
@@ -1525,14 +1527,14 @@ var PRESET_IGNORES = new Set(
|
|
|
1525
1527
|
);
|
|
1526
1528
|
function readLinkTarget(linkPath, fallback) {
|
|
1527
1529
|
try {
|
|
1528
|
-
return
|
|
1530
|
+
return fs12__namespace.readlinkSync(linkPath);
|
|
1529
1531
|
} catch {
|
|
1530
1532
|
return fallback;
|
|
1531
1533
|
}
|
|
1532
1534
|
}
|
|
1533
1535
|
function isInside(root, candidate) {
|
|
1534
|
-
const relative11 =
|
|
1535
|
-
return relative11 === "" || !relative11.startsWith(`..${
|
|
1536
|
+
const relative11 = path13__namespace.relative(root, candidate);
|
|
1537
|
+
return relative11 === "" || !relative11.startsWith(`..${path13__namespace.sep}`) && relative11 !== ".." && !path13__namespace.isAbsolute(relative11);
|
|
1536
1538
|
}
|
|
1537
1539
|
function getGitInfo(cwd, fallbackBranch = "main") {
|
|
1538
1540
|
try {
|
|
@@ -1737,10 +1739,10 @@ function trimUnescapedTrailingSpaces(line) {
|
|
|
1737
1739
|
return line.slice(0, end);
|
|
1738
1740
|
}
|
|
1739
1741
|
function readGitignoreRules(dir) {
|
|
1740
|
-
const gitignorePath2 =
|
|
1742
|
+
const gitignorePath2 = path13__namespace.join(dir, ".gitignore");
|
|
1741
1743
|
let raw;
|
|
1742
1744
|
try {
|
|
1743
|
-
raw =
|
|
1745
|
+
raw = fs12__namespace.readFileSync(gitignorePath2, "utf8");
|
|
1744
1746
|
} catch {
|
|
1745
1747
|
return [];
|
|
1746
1748
|
}
|
|
@@ -1867,7 +1869,7 @@ function isToolOwnedDirName(name) {
|
|
|
1867
1869
|
}
|
|
1868
1870
|
function hasSnapshotMarker(target) {
|
|
1869
1871
|
try {
|
|
1870
|
-
return
|
|
1872
|
+
return fs12__namespace.statSync(target).isDirectory() && fs12__namespace.existsSync(path13__namespace.join(target, ".codebase-snapshot"));
|
|
1871
1873
|
} catch {
|
|
1872
1874
|
return false;
|
|
1873
1875
|
}
|
|
@@ -1881,7 +1883,7 @@ function makeToolOwnedDecider(cwd, toolOwnedPaths) {
|
|
|
1881
1883
|
const prefix = parts.slice(0, depth).join("/");
|
|
1882
1884
|
let hasMarker = markers.get(prefix);
|
|
1883
1885
|
if (hasMarker === void 0) {
|
|
1884
|
-
hasMarker =
|
|
1886
|
+
hasMarker = fs12__namespace.existsSync(path13__namespace.join(cwd, prefix, ".codebase-snapshot"));
|
|
1885
1887
|
markers.set(prefix, hasMarker);
|
|
1886
1888
|
}
|
|
1887
1889
|
if (hasMarker) return true;
|
|
@@ -1896,7 +1898,7 @@ function makeLinkProbe() {
|
|
|
1896
1898
|
let known = cache.get(absolutePath);
|
|
1897
1899
|
if (known === void 0) {
|
|
1898
1900
|
try {
|
|
1899
|
-
known =
|
|
1901
|
+
known = fs12__namespace.lstatSync(absolutePath).isSymbolicLink();
|
|
1900
1902
|
} catch {
|
|
1901
1903
|
known = false;
|
|
1902
1904
|
}
|
|
@@ -1909,7 +1911,7 @@ function dropLinkedDirectories(cwd, candidates, skipped) {
|
|
|
1909
1911
|
const isLink = makeLinkProbe();
|
|
1910
1912
|
let rootReal = cwd;
|
|
1911
1913
|
try {
|
|
1912
|
-
rootReal =
|
|
1914
|
+
rootReal = fs12__namespace.realpathSync(cwd);
|
|
1913
1915
|
} catch {
|
|
1914
1916
|
}
|
|
1915
1917
|
const reported = /* @__PURE__ */ new Set();
|
|
@@ -1919,7 +1921,7 @@ function dropLinkedDirectories(cwd, candidates, skipped) {
|
|
|
1919
1921
|
let linkedDir = null;
|
|
1920
1922
|
for (let depth = 1; depth <= parts.length; depth += 1) {
|
|
1921
1923
|
const prefix = parts.slice(0, depth).join("/");
|
|
1922
|
-
if (isLink(
|
|
1924
|
+
if (isLink(path13__namespace.join(cwd, prefix))) {
|
|
1923
1925
|
linkedDir = prefix;
|
|
1924
1926
|
break;
|
|
1925
1927
|
}
|
|
@@ -1930,10 +1932,10 @@ function dropLinkedDirectories(cwd, candidates, skipped) {
|
|
|
1930
1932
|
}
|
|
1931
1933
|
if (reported.has(linkedDir)) continue;
|
|
1932
1934
|
reported.add(linkedDir);
|
|
1933
|
-
const absolute =
|
|
1935
|
+
const absolute = path13__namespace.join(cwd, linkedDir);
|
|
1934
1936
|
let targetReal = absolute;
|
|
1935
1937
|
try {
|
|
1936
|
-
targetReal =
|
|
1938
|
+
targetReal = fs12__namespace.realpathSync(absolute);
|
|
1937
1939
|
} catch {
|
|
1938
1940
|
}
|
|
1939
1941
|
const target = readLinkTarget(absolute, targetReal);
|
|
@@ -2010,7 +2012,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2010
2012
|
"Discovery mode is `git`, but git could not list this directory's files. Run inside a working repository, or pass --discovery walk (or auto) to scan the tree directly."
|
|
2011
2013
|
);
|
|
2012
2014
|
}
|
|
2013
|
-
if (
|
|
2015
|
+
if (fs12__namespace.existsSync(path13__namespace.join(cwd, ".git"))) {
|
|
2014
2016
|
throw new Error(
|
|
2015
2017
|
"This directory is a git repository, but git could not list its files. A plain walk honours .gitignore files, but git also applies .git/info/exclude and your global excludes file, includes files that are tracked although a .gitignore now matches them, and treats a submodule as a single entry. Fix the repository (git status should work), run outside git, or pass --discovery walk to accept those differences."
|
|
2016
2018
|
);
|
|
@@ -2069,7 +2071,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2069
2071
|
}
|
|
2070
2072
|
function rootRealFor(root) {
|
|
2071
2073
|
try {
|
|
2072
|
-
return
|
|
2074
|
+
return fs12__namespace.realpathSync(root);
|
|
2073
2075
|
} catch {
|
|
2074
2076
|
return root;
|
|
2075
2077
|
}
|
|
@@ -2077,18 +2079,18 @@ function rootRealFor(root) {
|
|
|
2077
2079
|
function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PURE__ */ new Set(), parentGitignoreLayers = []) {
|
|
2078
2080
|
const results = { files: [], skipped: [] };
|
|
2079
2081
|
const stack = [];
|
|
2080
|
-
const relativeToBase = (target) =>
|
|
2082
|
+
const relativeToBase = (target) => path13__namespace.relative(baseDir, target).replace(/\\/g, "/") || ".";
|
|
2081
2083
|
const enter = (current, layers) => {
|
|
2082
2084
|
if (visited.has(current)) return false;
|
|
2083
2085
|
visited.add(current);
|
|
2084
2086
|
const localRules = readGitignoreRules(current);
|
|
2085
2087
|
const gitignoreLayers = localRules.length === 0 ? layers : [
|
|
2086
2088
|
...layers,
|
|
2087
|
-
{ prefix:
|
|
2089
|
+
{ prefix: path13__namespace.relative(baseDir, current).replace(/\\/g, "/"), rules: localRules }
|
|
2088
2090
|
];
|
|
2089
2091
|
let entries;
|
|
2090
2092
|
try {
|
|
2091
|
-
entries =
|
|
2093
|
+
entries = fs12__namespace.readdirSync(current, { withFileTypes: true });
|
|
2092
2094
|
} catch {
|
|
2093
2095
|
results.skipped.push({
|
|
2094
2096
|
path: relativeToBase(current),
|
|
@@ -2110,8 +2112,8 @@ function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PU
|
|
|
2110
2112
|
}
|
|
2111
2113
|
const entry = frame.entries[frame.index];
|
|
2112
2114
|
frame.index += 1;
|
|
2113
|
-
const fullPath =
|
|
2114
|
-
const relPath =
|
|
2115
|
+
const fullPath = path13__namespace.join(frame.dir, entry.name);
|
|
2116
|
+
const relPath = path13__namespace.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
2115
2117
|
if (isToolOwnedDirName(entry.name) && reservedPaths.has(relPath)) continue;
|
|
2116
2118
|
if (DEFAULT_IGNORED_DIRS.includes(entry.name)) {
|
|
2117
2119
|
results.skipped.push({
|
|
@@ -2144,14 +2146,14 @@ function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PU
|
|
|
2144
2146
|
if (entry.isSymbolicLink()) {
|
|
2145
2147
|
let targetReal;
|
|
2146
2148
|
try {
|
|
2147
|
-
targetReal =
|
|
2149
|
+
targetReal = fs12__namespace.realpathSync(fullPath);
|
|
2148
2150
|
} catch {
|
|
2149
2151
|
results.skipped.push({ path: relPath, reason: "read-error", detail: "broken symlink" });
|
|
2150
2152
|
continue;
|
|
2151
2153
|
}
|
|
2152
2154
|
let stats;
|
|
2153
2155
|
try {
|
|
2154
|
-
stats =
|
|
2156
|
+
stats = fs12__namespace.statSync(fullPath);
|
|
2155
2157
|
} catch {
|
|
2156
2158
|
results.skipped.push({ path: relPath, reason: "read-error", detail: "unreadable symlink" });
|
|
2157
2159
|
continue;
|
|
@@ -2204,13 +2206,13 @@ var CONFIG_FILENAMES = [
|
|
|
2204
2206
|
];
|
|
2205
2207
|
function findConfigFile(cwd) {
|
|
2206
2208
|
for (const filename of CONFIG_FILENAMES) {
|
|
2207
|
-
const fullPath =
|
|
2208
|
-
if (
|
|
2209
|
+
const fullPath = path13__namespace.join(cwd, filename);
|
|
2210
|
+
if (fs12__namespace.existsSync(fullPath)) return fullPath;
|
|
2209
2211
|
}
|
|
2210
|
-
const pkgJsonPath =
|
|
2211
|
-
if (!
|
|
2212
|
+
const pkgJsonPath = path13__namespace.join(cwd, "package.json");
|
|
2213
|
+
if (!fs12__namespace.existsSync(pkgJsonPath)) return null;
|
|
2212
2214
|
try {
|
|
2213
|
-
const parsed = JSON.parse(
|
|
2215
|
+
const parsed = JSON.parse(fs12__namespace.readFileSync(pkgJsonPath, "utf8"));
|
|
2214
2216
|
return parsed.snapshot === void 0 ? null : pkgJsonPath;
|
|
2215
2217
|
} catch {
|
|
2216
2218
|
return null;
|
|
@@ -2461,11 +2463,11 @@ async function loadConfigFileDetailed(cwd) {
|
|
|
2461
2463
|
const warnings = [];
|
|
2462
2464
|
const errors = [];
|
|
2463
2465
|
for (const filename of CONFIG_FILENAMES) {
|
|
2464
|
-
const fullPath =
|
|
2465
|
-
if (!
|
|
2466
|
+
const fullPath = path13__namespace.join(cwd, filename);
|
|
2467
|
+
if (!fs12__namespace.existsSync(fullPath)) continue;
|
|
2466
2468
|
if (filename.endsWith(".json") || filename === ".snapshotrc") {
|
|
2467
2469
|
try {
|
|
2468
|
-
const config = parseJsonish(
|
|
2470
|
+
const config = parseJsonish(fs12__namespace.readFileSync(fullPath, "utf8"), fullPath);
|
|
2469
2471
|
if (config === null || typeof config !== "object" || Array.isArray(config)) {
|
|
2470
2472
|
throw new Error(
|
|
2471
2473
|
`${fullPath} does not hold a configuration object (received ${describeValue2(config)}).`
|
|
@@ -2499,10 +2501,10 @@ async function loadConfigFileDetailed(cwd) {
|
|
|
2499
2501
|
continue;
|
|
2500
2502
|
}
|
|
2501
2503
|
}
|
|
2502
|
-
const pkgJsonPath =
|
|
2503
|
-
if (
|
|
2504
|
+
const pkgJsonPath = path13__namespace.join(cwd, "package.json");
|
|
2505
|
+
if (fs12__namespace.existsSync(pkgJsonPath)) {
|
|
2504
2506
|
try {
|
|
2505
|
-
const parsed = parseJsonish(
|
|
2507
|
+
const parsed = parseJsonish(fs12__namespace.readFileSync(pkgJsonPath, "utf8"), pkgJsonPath);
|
|
2506
2508
|
const snapshotKey = parsed.snapshot;
|
|
2507
2509
|
if (snapshotKey && typeof snapshotKey === "object" && !Array.isArray(snapshotKey)) {
|
|
2508
2510
|
return { config: snapshotKey, file: pkgJsonPath, warnings, errors };
|
|
@@ -2670,9 +2672,9 @@ function resolveKindRules(value) {
|
|
|
2670
2672
|
function outputExcludePatterns(cwd, outDir, tmpDir) {
|
|
2671
2673
|
const patterns = [];
|
|
2672
2674
|
for (const dir of [outDir, tmpDir]) {
|
|
2673
|
-
const absolute =
|
|
2674
|
-
const relative11 =
|
|
2675
|
-
if (!relative11 || relative11 === ".." || relative11.startsWith(`..${
|
|
2675
|
+
const absolute = path13__namespace.resolve(cwd, dir);
|
|
2676
|
+
const relative11 = path13__namespace.relative(cwd, absolute);
|
|
2677
|
+
if (!relative11 || relative11 === ".." || relative11.startsWith(`..${path13__namespace.sep}`) || path13__namespace.isAbsolute(relative11)) {
|
|
2676
2678
|
continue;
|
|
2677
2679
|
}
|
|
2678
2680
|
patterns.push(`${relative11.replace(/\\/g, "/")}/**`);
|
|
@@ -2791,11 +2793,11 @@ function resolveCandidateCwd(userConfig, cliOptions, baseDir) {
|
|
|
2791
2793
|
);
|
|
2792
2794
|
}
|
|
2793
2795
|
const candidate = cliOptions?.cwd || userConfig?.cwd || baseDir || process.cwd();
|
|
2794
|
-
const resolved =
|
|
2795
|
-
if (!
|
|
2796
|
+
const resolved = path13__namespace.resolve(candidate);
|
|
2797
|
+
if (!fs12__namespace.existsSync(resolved)) {
|
|
2796
2798
|
throw new Error(`Working directory does not exist: ${resolved}`);
|
|
2797
2799
|
}
|
|
2798
|
-
if (!
|
|
2800
|
+
if (!fs12__namespace.statSync(resolved).isDirectory()) {
|
|
2799
2801
|
throw new Error(`Working directory is not a directory: ${resolved}`);
|
|
2800
2802
|
}
|
|
2801
2803
|
return resolved;
|
|
@@ -3021,7 +3023,7 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
3021
3023
|
".so"
|
|
3022
3024
|
]);
|
|
3023
3025
|
function isBinaryExtension(filePath) {
|
|
3024
|
-
const ext =
|
|
3026
|
+
const ext = path13__namespace.extname(filePath).toLowerCase();
|
|
3025
3027
|
return BINARY_EXTENSIONS.has(ext);
|
|
3026
3028
|
}
|
|
3027
3029
|
function countControlBytes(buffer) {
|
|
@@ -3188,13 +3190,13 @@ function isBinaryFile(absolutePath) {
|
|
|
3188
3190
|
if (isBinaryExtension(absolutePath)) return true;
|
|
3189
3191
|
let fd;
|
|
3190
3192
|
try {
|
|
3191
|
-
fd =
|
|
3193
|
+
fd = fs12__namespace.openSync(absolutePath, "r");
|
|
3192
3194
|
const buffer = Buffer.alloc(CHUNK);
|
|
3193
3195
|
let sample;
|
|
3194
3196
|
let position = 0;
|
|
3195
3197
|
while (position < BINARY_SCAN_BYTES) {
|
|
3196
3198
|
const wanted = Math.min(CHUNK, BINARY_SCAN_BYTES - position);
|
|
3197
|
-
const bytesRead =
|
|
3199
|
+
const bytesRead = fs12__namespace.readSync(fd, buffer, 0, wanted, position);
|
|
3198
3200
|
if (bytesRead === 0) return false;
|
|
3199
3201
|
const chunk = buffer.subarray(0, bytesRead);
|
|
3200
3202
|
if (sample === void 0) {
|
|
@@ -3212,7 +3214,7 @@ function isBinaryFile(absolutePath) {
|
|
|
3212
3214
|
} finally {
|
|
3213
3215
|
if (fd !== void 0) {
|
|
3214
3216
|
try {
|
|
3215
|
-
|
|
3217
|
+
fs12__namespace.closeSync(fd);
|
|
3216
3218
|
} catch {
|
|
3217
3219
|
}
|
|
3218
3220
|
}
|
|
@@ -3225,33 +3227,33 @@ function maskedPath(value, secretRules) {
|
|
|
3225
3227
|
}
|
|
3226
3228
|
function confineToDirectory(directory, filename) {
|
|
3227
3229
|
if (filename.includes("\0")) return null;
|
|
3228
|
-
if (
|
|
3229
|
-
const base =
|
|
3230
|
-
const resolved =
|
|
3230
|
+
if (path13__namespace.isAbsolute(filename)) return null;
|
|
3231
|
+
const base = path13__namespace.resolve(directory);
|
|
3232
|
+
const resolved = path13__namespace.resolve(base, filename);
|
|
3231
3233
|
const caseInsensitive = process.platform === "win32" || process.platform === "darwin";
|
|
3232
|
-
const prefix = caseInsensitive ? `${base}${
|
|
3234
|
+
const prefix = caseInsensitive ? `${base}${path13__namespace.sep}`.toLowerCase() : `${base}${path13__namespace.sep}`;
|
|
3233
3235
|
const candidate = caseInsensitive ? resolved.toLowerCase() : resolved;
|
|
3234
3236
|
return candidate.startsWith(prefix) ? resolved : null;
|
|
3235
3237
|
}
|
|
3236
3238
|
function findStagingDirectory(config) {
|
|
3237
|
-
const tmpDir =
|
|
3239
|
+
const tmpDir = path13__namespace.resolve(config.cwd, config.tmpDir);
|
|
3238
3240
|
let entries;
|
|
3239
3241
|
try {
|
|
3240
|
-
entries =
|
|
3242
|
+
entries = fs12__namespace.readdirSync(tmpDir);
|
|
3241
3243
|
} catch {
|
|
3242
3244
|
return null;
|
|
3243
3245
|
}
|
|
3244
3246
|
const runs = entries.filter((name) => name.startsWith("run-")).sort();
|
|
3245
3247
|
const newest = runs[runs.length - 1];
|
|
3246
|
-
return newest ?
|
|
3248
|
+
return newest ? path13__namespace.join(tmpDir, newest) : null;
|
|
3247
3249
|
}
|
|
3248
3250
|
function describeMissingManifest(config, manifestPath) {
|
|
3249
|
-
const outDir =
|
|
3250
|
-
const markerPath =
|
|
3251
|
+
const outDir = path13__namespace.resolve(config.cwd, config.outDir);
|
|
3252
|
+
const markerPath = path13__namespace.join(outDir, ".codebase-snapshot");
|
|
3251
3253
|
let marker2 = null;
|
|
3252
3254
|
try {
|
|
3253
|
-
if (
|
|
3254
|
-
const parsed = JSON.parse(
|
|
3255
|
+
if (fs12__namespace.existsSync(markerPath)) {
|
|
3256
|
+
const parsed = JSON.parse(fs12__namespace.readFileSync(markerPath, "utf8"));
|
|
3255
3257
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3256
3258
|
marker2 = parsed;
|
|
3257
3259
|
}
|
|
@@ -3287,14 +3289,14 @@ function sha256Hex(buffer) {
|
|
|
3287
3289
|
}
|
|
3288
3290
|
var VERIFY_SNIFF_MAX_BYTES = 8 * 1024 * 1024;
|
|
3289
3291
|
function wouldNowBeIncluded(cwd, relativePath, reason) {
|
|
3290
|
-
const absolutePath =
|
|
3292
|
+
const absolutePath = path13__namespace.join(cwd, relativePath);
|
|
3291
3293
|
try {
|
|
3292
|
-
const stats =
|
|
3294
|
+
const stats = fs12__namespace.statSync(absolutePath);
|
|
3293
3295
|
if (!stats.isFile()) return false;
|
|
3294
3296
|
if (isBinaryFile(absolutePath)) return false;
|
|
3295
3297
|
if (reason !== "binary") return true;
|
|
3296
3298
|
if (stats.size > VERIFY_SNIFF_MAX_BYTES) return false;
|
|
3297
|
-
return !decodeText(
|
|
3299
|
+
return !decodeText(fs12__namespace.readFileSync(absolutePath)).binary;
|
|
3298
3300
|
} catch {
|
|
3299
3301
|
return false;
|
|
3300
3302
|
}
|
|
@@ -3352,8 +3354,8 @@ function describeManifestShapeProblem(value) {
|
|
|
3352
3354
|
function validateSnapshot(configInput) {
|
|
3353
3355
|
assertUsableConfigInput(configInput);
|
|
3354
3356
|
const config = isResolvedConfig(configInput) ? normalizeResolvedConfig(configInput) : resolveConfig(configInput);
|
|
3355
|
-
const manifestPath =
|
|
3356
|
-
if (!
|
|
3357
|
+
const manifestPath = path13__namespace.resolve(config.cwd, config.outDir, "manifest.json");
|
|
3358
|
+
if (!fs12__namespace.existsSync(manifestPath)) {
|
|
3357
3359
|
return {
|
|
3358
3360
|
valid: false,
|
|
3359
3361
|
manifestPresent: false,
|
|
@@ -3364,7 +3366,7 @@ function validateSnapshot(configInput) {
|
|
|
3364
3366
|
}
|
|
3365
3367
|
let manifest;
|
|
3366
3368
|
try {
|
|
3367
|
-
manifest = JSON.parse(
|
|
3369
|
+
manifest = JSON.parse(fs12__namespace.readFileSync(manifestPath, "utf8"));
|
|
3368
3370
|
} catch (err) {
|
|
3369
3371
|
return {
|
|
3370
3372
|
valid: false,
|
|
@@ -3386,7 +3388,7 @@ function validateSnapshot(configInput) {
|
|
|
3386
3388
|
}
|
|
3387
3389
|
const drift = emptyDrift();
|
|
3388
3390
|
const warnings = [];
|
|
3389
|
-
const snapshotDir =
|
|
3391
|
+
const snapshotDir = path13__namespace.resolve(config.cwd, config.outDir);
|
|
3390
3392
|
const manifestFileMap = /* @__PURE__ */ new Map();
|
|
3391
3393
|
for (const file of manifest.files) {
|
|
3392
3394
|
if (file && typeof file.relativePath === "string") {
|
|
@@ -3420,7 +3422,7 @@ function validateSnapshot(configInput) {
|
|
|
3420
3422
|
}
|
|
3421
3423
|
let diskHash;
|
|
3422
3424
|
try {
|
|
3423
|
-
diskHash = sha256Hex(
|
|
3425
|
+
diskHash = sha256Hex(fs12__namespace.readFileSync(path13__namespace.join(config.cwd, diskFile)));
|
|
3424
3426
|
} catch (err) {
|
|
3425
3427
|
if (err.code === "ENOENT") {
|
|
3426
3428
|
drift.missingOnDisk.push(diskFile);
|
|
@@ -3444,7 +3446,7 @@ function validateSnapshot(configInput) {
|
|
|
3444
3446
|
}
|
|
3445
3447
|
let statFailure = null;
|
|
3446
3448
|
try {
|
|
3447
|
-
|
|
3449
|
+
fs12__namespace.statSync(confined);
|
|
3448
3450
|
} catch (err) {
|
|
3449
3451
|
statFailure = err;
|
|
3450
3452
|
}
|
|
@@ -3464,7 +3466,7 @@ function validateSnapshot(configInput) {
|
|
|
3464
3466
|
...Object.values(config.budgets.byLayer)
|
|
3465
3467
|
);
|
|
3466
3468
|
const partNames = /* @__PURE__ */ new Set();
|
|
3467
|
-
const partsDir =
|
|
3469
|
+
const partsDir = path13__namespace.join(snapshotDir, "parts");
|
|
3468
3470
|
for (const part of manifest.parts) {
|
|
3469
3471
|
if (!part || typeof part.filename !== "string") continue;
|
|
3470
3472
|
partNames.add(part.filename);
|
|
@@ -3479,7 +3481,7 @@ function validateSnapshot(configInput) {
|
|
|
3479
3481
|
}
|
|
3480
3482
|
let buffer;
|
|
3481
3483
|
try {
|
|
3482
|
-
buffer =
|
|
3484
|
+
buffer = fs12__namespace.readFileSync(partPath);
|
|
3483
3485
|
} catch {
|
|
3484
3486
|
drift.partIssues.push({ part: part.filename, issue: "missing from snapshot/parts" });
|
|
3485
3487
|
continue;
|
|
@@ -3693,9 +3695,9 @@ function validateSnapshot(configInput) {
|
|
|
3693
3695
|
["full-codebase.md", manifest.artifacts?.fullMarkdown]
|
|
3694
3696
|
]) {
|
|
3695
3697
|
if (!artifact) continue;
|
|
3696
|
-
const artifactPath =
|
|
3698
|
+
const artifactPath = path13__namespace.join(snapshotDir, key);
|
|
3697
3699
|
try {
|
|
3698
|
-
const buffer =
|
|
3700
|
+
const buffer = fs12__namespace.readFileSync(artifactPath);
|
|
3699
3701
|
if (sha256Hex(buffer) !== artifact.sha256 || buffer.length !== artifact.byteSize) {
|
|
3700
3702
|
drift.partIssues.push({ part: key, issue: "artifact does not match its recorded digest" });
|
|
3701
3703
|
}
|
|
@@ -3956,14 +3958,14 @@ function compareManifests(before, after) {
|
|
|
3956
3958
|
function loadManifest(target) {
|
|
3957
3959
|
let isDirectory;
|
|
3958
3960
|
try {
|
|
3959
|
-
isDirectory =
|
|
3961
|
+
isDirectory = fs12__namespace.statSync(target).isDirectory();
|
|
3960
3962
|
} catch {
|
|
3961
3963
|
throw new Error(`No snapshot found at ${target}: the path does not exist.`);
|
|
3962
3964
|
}
|
|
3963
|
-
const manifestPath = isDirectory ?
|
|
3965
|
+
const manifestPath = isDirectory ? path13__namespace.join(target, "manifest.json") : target;
|
|
3964
3966
|
let raw;
|
|
3965
3967
|
try {
|
|
3966
|
-
raw =
|
|
3968
|
+
raw = fs12__namespace.readFileSync(manifestPath, "utf8");
|
|
3967
3969
|
} catch {
|
|
3968
3970
|
throw new Error(`Could not read a manifest at ${manifestPath}.`);
|
|
3969
3971
|
}
|
|
@@ -4114,10 +4116,10 @@ var LANGUAGE_BY_BASENAME = {
|
|
|
4114
4116
|
};
|
|
4115
4117
|
function detectLanguage(filePath) {
|
|
4116
4118
|
const normalized = filePath.replace(/\\/g, "/");
|
|
4117
|
-
const base =
|
|
4119
|
+
const base = path13__namespace.posix.basename(normalized);
|
|
4118
4120
|
if (LANGUAGE_BY_BASENAME[base]) return LANGUAGE_BY_BASENAME[base];
|
|
4119
4121
|
if (base === ".env" || base.startsWith(".env.")) return "dotenv";
|
|
4120
|
-
const ext =
|
|
4122
|
+
const ext = path13__namespace.posix.extname(base).toLowerCase();
|
|
4121
4123
|
return LANGUAGE_BY_EXTENSION[ext] ?? "text";
|
|
4122
4124
|
}
|
|
4123
4125
|
|
|
@@ -4159,10 +4161,10 @@ function describeMatcher(matcher) {
|
|
|
4159
4161
|
return String(matcher);
|
|
4160
4162
|
}
|
|
4161
4163
|
function normalizeTarget(cwd, target) {
|
|
4162
|
-
const absolute =
|
|
4163
|
-
const relative11 =
|
|
4164
|
-
if (relative11.startsWith("..") ||
|
|
4165
|
-
return relative11.split(
|
|
4164
|
+
const absolute = path13__namespace.resolve(cwd, target);
|
|
4165
|
+
const relative11 = path13__namespace.relative(cwd, absolute);
|
|
4166
|
+
if (relative11.startsWith("..") || path13__namespace.isAbsolute(relative11)) return target;
|
|
4167
|
+
return relative11.split(path13__namespace.sep).join("/");
|
|
4166
4168
|
}
|
|
4167
4169
|
function findRuleMatch(rules, relativePath) {
|
|
4168
4170
|
return rules.find(
|
|
@@ -4181,20 +4183,20 @@ function findRecordedAncestor(skipped, relative11, maskedPath2) {
|
|
|
4181
4183
|
return nearest;
|
|
4182
4184
|
}
|
|
4183
4185
|
function readManifest2(config) {
|
|
4184
|
-
const manifestPath =
|
|
4186
|
+
const manifestPath = path13__namespace.resolve(config.cwd, config.outDir, "manifest.json");
|
|
4185
4187
|
try {
|
|
4186
|
-
return JSON.parse(
|
|
4188
|
+
return JSON.parse(fs12__namespace.readFileSync(manifestPath, "utf8"));
|
|
4187
4189
|
} catch {
|
|
4188
4190
|
return null;
|
|
4189
4191
|
}
|
|
4190
4192
|
}
|
|
4191
4193
|
function explainPath(config, target) {
|
|
4192
4194
|
const relative11 = normalizeTarget(config.cwd, target);
|
|
4193
|
-
const absolute =
|
|
4195
|
+
const absolute = path13__namespace.join(config.cwd, relative11);
|
|
4194
4196
|
const maskedPath2 = findSecretInPath(relative11, config.secretRules)?.masked ?? relative11;
|
|
4195
4197
|
const result = {
|
|
4196
4198
|
path: maskedPath2,
|
|
4197
|
-
exists:
|
|
4199
|
+
exists: fs12__namespace.existsSync(absolute),
|
|
4198
4200
|
included: false
|
|
4199
4201
|
};
|
|
4200
4202
|
const collection = collectFiles(config.cwd, {
|
|
@@ -4205,7 +4207,7 @@ function explainPath(config, target) {
|
|
|
4205
4207
|
// Same exclusion `generate` applies, so `explain` never says "not-discovered" about a file
|
|
4206
4208
|
// that is only missing because the walker dropped the tool's own output directory.
|
|
4207
4209
|
toolOwnedPaths: [config.outDir, config.tmpDir].map(
|
|
4208
|
-
(directory) =>
|
|
4210
|
+
(directory) => path13__namespace.relative(config.cwd, path13__namespace.resolve(config.cwd, directory)).replace(/\\/g, "/")
|
|
4209
4211
|
).filter((relative12) => relative12.length > 0 && !relative12.startsWith(".."))
|
|
4210
4212
|
});
|
|
4211
4213
|
if (!collection.files.includes(relative11)) {
|
|
@@ -4244,8 +4246,8 @@ function explainPath(config, target) {
|
|
|
4244
4246
|
if (layerRule) result.layerMatch = describeMatcher(layerRule.match);
|
|
4245
4247
|
const kindRule = findRuleMatch(config.kinds, relative11);
|
|
4246
4248
|
if (kindRule) result.kindMatch = describeMatcher(kindRule.match);
|
|
4247
|
-
if (
|
|
4248
|
-
const buffer =
|
|
4249
|
+
if (fs12__namespace.existsSync(absolute) && fs12__namespace.statSync(absolute).isFile()) {
|
|
4250
|
+
const buffer = fs12__namespace.readFileSync(absolute);
|
|
4249
4251
|
const decoded = decodeText(buffer);
|
|
4250
4252
|
if (decoded.binary) {
|
|
4251
4253
|
result.included = false;
|
|
@@ -4304,15 +4306,15 @@ function renderExplainText(result) {
|
|
|
4304
4306
|
function appendGitignoreEntries(cwd, entries) {
|
|
4305
4307
|
const wanted = [...new Set(entries)].filter((entry) => entry.trim().length > 0);
|
|
4306
4308
|
if (wanted.length === 0) return { added: [], note: null };
|
|
4307
|
-
const ignorePath =
|
|
4309
|
+
const ignorePath = path13__namespace.join(cwd, ".gitignore");
|
|
4308
4310
|
const manual = `Add ${wanted.map((entry) => `"${entry}"`).join(" and ")} to your .gitignore yourself.`;
|
|
4309
4311
|
let existing = "";
|
|
4310
4312
|
try {
|
|
4311
|
-
if (
|
|
4312
|
-
if (
|
|
4313
|
+
if (fs12__namespace.existsSync(ignorePath)) {
|
|
4314
|
+
if (fs12__namespace.statSync(ignorePath).isDirectory()) {
|
|
4313
4315
|
return { added: [], note: `${ignorePath} is a directory, so it was not updated. ${manual}` };
|
|
4314
4316
|
}
|
|
4315
|
-
existing =
|
|
4317
|
+
existing = fs12__namespace.readFileSync(ignorePath, "utf8");
|
|
4316
4318
|
}
|
|
4317
4319
|
} catch (err) {
|
|
4318
4320
|
return {
|
|
@@ -4325,7 +4327,7 @@ function appendGitignoreEntries(cwd, entries) {
|
|
|
4325
4327
|
if (added.length === 0) return { added: [], note: null };
|
|
4326
4328
|
const prefix = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
4327
4329
|
try {
|
|
4328
|
-
|
|
4330
|
+
fs12__namespace.writeFileSync(ignorePath, `${existing}${prefix}${added.join("\n")}
|
|
4329
4331
|
`, "utf8");
|
|
4330
4332
|
} catch (err) {
|
|
4331
4333
|
return { added: [], note: `${err.message}. ${manual}` };
|
|
@@ -4333,12 +4335,12 @@ function appendGitignoreEntries(cwd, entries) {
|
|
|
4333
4335
|
return { added, note: null };
|
|
4334
4336
|
}
|
|
4335
4337
|
function gitignorePath(cwd, filePath) {
|
|
4336
|
-
return
|
|
4338
|
+
return path13__namespace.relative(cwd, filePath).split(path13__namespace.sep).join("/");
|
|
4337
4339
|
}
|
|
4338
4340
|
|
|
4339
4341
|
// src/version.ts
|
|
4340
4342
|
var GENERATOR_NAME = "codebase-snapshot";
|
|
4341
|
-
var GENERATOR_VERSION = "0.9.
|
|
4343
|
+
var GENERATOR_VERSION = "0.9.6";
|
|
4342
4344
|
var LEGACY_GENERATOR_NAMES = ["@ankurhalder/codebase-snapshot"];
|
|
4343
4345
|
function isOurGeneratorName(name) {
|
|
4344
4346
|
if (typeof name !== "string") return false;
|
|
@@ -4472,6 +4474,12 @@ var PromptCancelled = class extends Error {
|
|
|
4472
4474
|
this.name = "PromptCancelled";
|
|
4473
4475
|
}
|
|
4474
4476
|
};
|
|
4477
|
+
var PromptBack = class extends Error {
|
|
4478
|
+
constructor() {
|
|
4479
|
+
super("Prompt back");
|
|
4480
|
+
this.name = "PromptBack";
|
|
4481
|
+
}
|
|
4482
|
+
};
|
|
4475
4483
|
function defaultIO() {
|
|
4476
4484
|
return { input: process.stdin, output: process.stdout };
|
|
4477
4485
|
}
|
|
@@ -4495,35 +4503,40 @@ function choiceLine(choice, active) {
|
|
|
4495
4503
|
const hint = choice.hint ? ` ${choice.hint}` : "";
|
|
4496
4504
|
return ` ${marker(active)} ${choice.label}${hint}`;
|
|
4497
4505
|
}
|
|
4498
|
-
function
|
|
4506
|
+
function listFooter(base, allowBack) {
|
|
4507
|
+
return allowBack ? `${base} \xB7 \u2190 back` : base;
|
|
4508
|
+
}
|
|
4509
|
+
function renderSelect(message, choices, index, allowBack = false) {
|
|
4499
4510
|
const lines = [`\u25C6 ${message}`, ""];
|
|
4500
4511
|
choices.forEach((choice, position) => lines.push(choiceLine(choice, position === index)));
|
|
4501
|
-
lines.push("", "
|
|
4512
|
+
lines.push("", ` ${listFooter("\u2191\u2193 move \xB7 enter select", allowBack)}`);
|
|
4502
4513
|
return lines.join("\n");
|
|
4503
4514
|
}
|
|
4504
|
-
function renderMultiSelect(message, choices, index, selected) {
|
|
4515
|
+
function renderMultiSelect(message, choices, index, selected, allowBack = false) {
|
|
4505
4516
|
const lines = [`\u25C6 ${message}`, ""];
|
|
4506
4517
|
choices.forEach((choice, position) => {
|
|
4507
4518
|
const box = selected.has(position) ? "\u25FC" : "\u25FB";
|
|
4508
4519
|
const hint = choice.hint ? ` ${choice.hint}` : "";
|
|
4509
4520
|
lines.push(` ${marker(position === index)} ${box} ${choice.label}${hint}`);
|
|
4510
4521
|
});
|
|
4511
|
-
lines.push("", "
|
|
4522
|
+
lines.push("", ` ${listFooter("\u2191\u2193 move \xB7 space toggle \xB7 enter confirm", allowBack)}`);
|
|
4512
4523
|
return lines.join("\n");
|
|
4513
4524
|
}
|
|
4514
|
-
function renderConfirm(message, value) {
|
|
4525
|
+
function renderConfirm(message, value, allowBack = false) {
|
|
4526
|
+
const footer = allowBack ? "\u2190\u2192 or y/n \xB7 enter confirm \xB7 b back" : "\u2190\u2192 or y/n \xB7 enter confirm";
|
|
4515
4527
|
return [
|
|
4516
4528
|
`\u25C6 ${message}`,
|
|
4517
4529
|
"",
|
|
4518
4530
|
` ${marker(value)} Yes`,
|
|
4519
4531
|
` ${marker(!value)} No`,
|
|
4520
4532
|
"",
|
|
4521
|
-
|
|
4533
|
+
` ${footer}`
|
|
4522
4534
|
].join("\n");
|
|
4523
4535
|
}
|
|
4524
|
-
function renderText(message, value, error) {
|
|
4536
|
+
function renderText(message, value, error, allowBack = false) {
|
|
4525
4537
|
const lines = [`\u25C6 ${message}`, "", ` ${value || "\u258F"}`];
|
|
4526
4538
|
if (error) lines.push("", ` \u2716 ${error}`);
|
|
4539
|
+
if (allowBack) lines.push("", " enter confirm \xB7 \u2190 back");
|
|
4527
4540
|
return lines.join("\n");
|
|
4528
4541
|
}
|
|
4529
4542
|
function keyReader(input) {
|
|
@@ -4572,14 +4585,18 @@ var Frame = class {
|
|
|
4572
4585
|
function isCancel(key) {
|
|
4573
4586
|
return key.ctrl === true && key.name === "c" || key.ctrl === true && key.name === "d";
|
|
4574
4587
|
}
|
|
4588
|
+
function isListBack(key, allowBack) {
|
|
4589
|
+
return allowBack && (key.name === "left" || key.name === "b");
|
|
4590
|
+
}
|
|
4575
4591
|
async function select(io, message, choices, options = {}) {
|
|
4576
4592
|
if (choices.length === 0) throw new Error("select() requires at least one choice.");
|
|
4593
|
+
const allowBack = options.allowBack === true;
|
|
4577
4594
|
const fallbackIndex = Math.max(
|
|
4578
4595
|
0,
|
|
4579
4596
|
choices.findIndex((choice) => choice.value === options.defaultValue)
|
|
4580
4597
|
);
|
|
4581
4598
|
if (!isInteractive(io)) {
|
|
4582
|
-
io.output.write(`${renderSelect(message, choices, fallbackIndex)}
|
|
4599
|
+
io.output.write(`${renderSelect(message, choices, fallbackIndex, allowBack)}
|
|
4583
4600
|
`);
|
|
4584
4601
|
return choices[fallbackIndex].value;
|
|
4585
4602
|
}
|
|
@@ -4588,9 +4605,10 @@ async function select(io, message, choices, options = {}) {
|
|
|
4588
4605
|
let index = fallbackIndex;
|
|
4589
4606
|
try {
|
|
4590
4607
|
for (; ; ) {
|
|
4591
|
-
frame.draw(renderSelect(message, choices, index));
|
|
4608
|
+
frame.draw(renderSelect(message, choices, index, allowBack));
|
|
4592
4609
|
const key = await reader.next();
|
|
4593
4610
|
if (isCancel(key)) throw new PromptCancelled();
|
|
4611
|
+
if (isListBack(key, allowBack)) throw new PromptBack();
|
|
4594
4612
|
if (key.name === "up") index = moveSelection(index, -1, choices.length);
|
|
4595
4613
|
else if (key.name === "down") index = moveSelection(index, 1, choices.length);
|
|
4596
4614
|
else if (key.name === "return" || key.name === "enter") {
|
|
@@ -4599,18 +4617,22 @@ async function select(io, message, choices, options = {}) {
|
|
|
4599
4617
|
} else if (key.name === "j") index = moveSelection(index, 1, choices.length);
|
|
4600
4618
|
else if (key.name === "k") index = moveSelection(index, -1, choices.length);
|
|
4601
4619
|
}
|
|
4620
|
+
} catch (error) {
|
|
4621
|
+
frame.erase();
|
|
4622
|
+
throw error;
|
|
4602
4623
|
} finally {
|
|
4603
4624
|
reader.close();
|
|
4604
4625
|
}
|
|
4605
4626
|
}
|
|
4606
4627
|
async function multiSelect(io, message, choices, options = {}) {
|
|
4628
|
+
const allowBack = options.allowBack === true;
|
|
4607
4629
|
const selected = /* @__PURE__ */ new Set();
|
|
4608
4630
|
choices.forEach((choice, position) => {
|
|
4609
4631
|
if (options.defaults?.includes(choice.value)) selected.add(position);
|
|
4610
4632
|
});
|
|
4611
4633
|
const result = () => choices.filter((_, position) => selected.has(position)).map((choice) => choice.value);
|
|
4612
4634
|
if (!isInteractive(io)) {
|
|
4613
|
-
io.output.write(`${renderMultiSelect(message, choices, 0, selected)}
|
|
4635
|
+
io.output.write(`${renderMultiSelect(message, choices, 0, selected, allowBack)}
|
|
4614
4636
|
`);
|
|
4615
4637
|
return result();
|
|
4616
4638
|
}
|
|
@@ -4619,9 +4641,10 @@ async function multiSelect(io, message, choices, options = {}) {
|
|
|
4619
4641
|
let index = 0;
|
|
4620
4642
|
try {
|
|
4621
4643
|
for (; ; ) {
|
|
4622
|
-
frame.draw(renderMultiSelect(message, choices, index, selected));
|
|
4644
|
+
frame.draw(renderMultiSelect(message, choices, index, selected, allowBack));
|
|
4623
4645
|
const key = await reader.next();
|
|
4624
4646
|
if (isCancel(key)) throw new PromptCancelled();
|
|
4647
|
+
if (isListBack(key, allowBack)) throw new PromptBack();
|
|
4625
4648
|
if (key.name === "up") index = moveSelection(index, -1, choices.length);
|
|
4626
4649
|
else if (key.name === "down") index = moveSelection(index, 1, choices.length);
|
|
4627
4650
|
else if (key.name === "space") {
|
|
@@ -4636,14 +4659,18 @@ async function multiSelect(io, message, choices, options = {}) {
|
|
|
4636
4659
|
return result();
|
|
4637
4660
|
}
|
|
4638
4661
|
}
|
|
4662
|
+
} catch (error) {
|
|
4663
|
+
frame.erase();
|
|
4664
|
+
throw error;
|
|
4639
4665
|
} finally {
|
|
4640
4666
|
reader.close();
|
|
4641
4667
|
}
|
|
4642
4668
|
}
|
|
4643
4669
|
async function confirm(io, message, options = {}) {
|
|
4670
|
+
const allowBack = options.allowBack === true;
|
|
4644
4671
|
let value = options.defaultValue ?? true;
|
|
4645
4672
|
if (!isInteractive(io)) {
|
|
4646
|
-
io.output.write(`${renderConfirm(message, value)}
|
|
4673
|
+
io.output.write(`${renderConfirm(message, value, allowBack)}
|
|
4647
4674
|
`);
|
|
4648
4675
|
return value;
|
|
4649
4676
|
}
|
|
@@ -4651,9 +4678,10 @@ async function confirm(io, message, options = {}) {
|
|
|
4651
4678
|
const reader = keyReader(io.input);
|
|
4652
4679
|
try {
|
|
4653
4680
|
for (; ; ) {
|
|
4654
|
-
frame.draw(renderConfirm(message, value));
|
|
4681
|
+
frame.draw(renderConfirm(message, value, allowBack));
|
|
4655
4682
|
const key = await reader.next();
|
|
4656
4683
|
if (isCancel(key)) throw new PromptCancelled();
|
|
4684
|
+
if (allowBack && key.name === "b") throw new PromptBack();
|
|
4657
4685
|
if (key.name === "up" || key.name === "left") value = true;
|
|
4658
4686
|
else if (key.name === "down" || key.name === "right") value = false;
|
|
4659
4687
|
else if (key.name === "y") value = true;
|
|
@@ -4663,14 +4691,18 @@ async function confirm(io, message, options = {}) {
|
|
|
4663
4691
|
return value;
|
|
4664
4692
|
}
|
|
4665
4693
|
}
|
|
4694
|
+
} catch (error) {
|
|
4695
|
+
frame.erase();
|
|
4696
|
+
throw error;
|
|
4666
4697
|
} finally {
|
|
4667
4698
|
reader.close();
|
|
4668
4699
|
}
|
|
4669
4700
|
}
|
|
4670
4701
|
async function text(io, message, options = {}) {
|
|
4702
|
+
const allowBack = options.allowBack === true;
|
|
4671
4703
|
const fallback = options.defaultValue ?? "";
|
|
4672
4704
|
if (!isInteractive(io)) {
|
|
4673
|
-
io.output.write(`${renderText(message, fallback)}
|
|
4705
|
+
io.output.write(`${renderText(message, fallback, void 0, allowBack)}
|
|
4674
4706
|
`);
|
|
4675
4707
|
return fallback;
|
|
4676
4708
|
}
|
|
@@ -4680,9 +4712,10 @@ async function text(io, message, options = {}) {
|
|
|
4680
4712
|
let error;
|
|
4681
4713
|
try {
|
|
4682
4714
|
for (; ; ) {
|
|
4683
|
-
frame.draw(renderText(message, value, error));
|
|
4715
|
+
frame.draw(renderText(message, value, error, allowBack));
|
|
4684
4716
|
const key = await reader.next();
|
|
4685
4717
|
if (isCancel(key)) throw new PromptCancelled();
|
|
4718
|
+
if (allowBack && key.name === "left") throw new PromptBack();
|
|
4686
4719
|
error = void 0;
|
|
4687
4720
|
if (key.name === "return" || key.name === "enter") {
|
|
4688
4721
|
const problem = options.validate ? options.validate(value) : null;
|
|
@@ -4703,6 +4736,9 @@ async function text(io, message, options = {}) {
|
|
|
4703
4736
|
}
|
|
4704
4737
|
if (_isPrintable(key)) value += _keyText(key);
|
|
4705
4738
|
}
|
|
4739
|
+
} catch (error_) {
|
|
4740
|
+
frame.erase();
|
|
4741
|
+
throw error_;
|
|
4706
4742
|
} finally {
|
|
4707
4743
|
reader.close();
|
|
4708
4744
|
}
|
|
@@ -4726,10 +4762,10 @@ var CONFIG_CANDIDATES = [
|
|
|
4726
4762
|
];
|
|
4727
4763
|
function chooseConfigFileName(cwd) {
|
|
4728
4764
|
if (!supportsTypeScriptImports()) return "snapshot.config.mjs";
|
|
4729
|
-
const pkgPath =
|
|
4730
|
-
if (!
|
|
4765
|
+
const pkgPath = path13__namespace.join(cwd, "package.json");
|
|
4766
|
+
if (!fs12__namespace.existsSync(pkgPath)) return "snapshot.config.mjs";
|
|
4731
4767
|
try {
|
|
4732
|
-
const parsed = JSON.parse(
|
|
4768
|
+
const parsed = JSON.parse(fs12__namespace.readFileSync(pkgPath, "utf8"));
|
|
4733
4769
|
return parsed.type === "module" ? "snapshot.config.ts" : "snapshot.config.mjs";
|
|
4734
4770
|
} catch {
|
|
4735
4771
|
return "snapshot.config.mjs";
|
|
@@ -4743,7 +4779,7 @@ var SIZE_CHOICES = [
|
|
|
4743
4779
|
];
|
|
4744
4780
|
function packageJsonHasConfig(cwd) {
|
|
4745
4781
|
try {
|
|
4746
|
-
const parsed = JSON.parse(
|
|
4782
|
+
const parsed = JSON.parse(fs12__namespace.readFileSync(path13__namespace.join(cwd, "package.json"), "utf8"));
|
|
4747
4783
|
return typeof parsed.snapshot === "object" && parsed.snapshot !== null && !Array.isArray(parsed.snapshot);
|
|
4748
4784
|
} catch {
|
|
4749
4785
|
return false;
|
|
@@ -4764,7 +4800,7 @@ function artifactAnswers(options) {
|
|
|
4764
4800
|
}
|
|
4765
4801
|
function topLevelDirs(cwd) {
|
|
4766
4802
|
try {
|
|
4767
|
-
return
|
|
4803
|
+
return fs12__namespace.readdirSync(cwd, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules").map((entry) => entry.name).sort();
|
|
4768
4804
|
} catch {
|
|
4769
4805
|
return [];
|
|
4770
4806
|
}
|
|
@@ -4777,7 +4813,7 @@ function describeJsonValue(value) {
|
|
|
4777
4813
|
}
|
|
4778
4814
|
function writeFileOrExplain(target, content) {
|
|
4779
4815
|
try {
|
|
4780
|
-
|
|
4816
|
+
fs12__namespace.writeFileSync(target, content, "utf8");
|
|
4781
4817
|
} catch (err) {
|
|
4782
4818
|
const code = err.code;
|
|
4783
4819
|
const reason = code === "EACCES" || code === "EPERM" || code === "EROFS" ? `permission denied (${code})` : code === "EISDIR" ? "it is a directory" : `${err.message}`;
|
|
@@ -4788,7 +4824,7 @@ function canWriteModuleConfig(name, cwd) {
|
|
|
4788
4824
|
if (name.endsWith(".mjs") || name.endsWith(".ts")) return true;
|
|
4789
4825
|
if (!name.endsWith(".js")) return false;
|
|
4790
4826
|
try {
|
|
4791
|
-
const parsed = JSON.parse(
|
|
4827
|
+
const parsed = JSON.parse(fs12__namespace.readFileSync(path13__namespace.join(cwd, "package.json"), "utf8"));
|
|
4792
4828
|
return parsed.type === "module";
|
|
4793
4829
|
} catch {
|
|
4794
4830
|
return false;
|
|
@@ -4823,19 +4859,19 @@ function serializePackageJson(raw, value) {
|
|
|
4823
4859
|
return `${text2}${raw.endsWith("\n") ? crlf ? "\r\n" : "\n" : ""}`;
|
|
4824
4860
|
}
|
|
4825
4861
|
function updatePackageJson(cwd, notes) {
|
|
4826
|
-
const packagePath =
|
|
4862
|
+
const packagePath = path13__namespace.join(cwd, "package.json");
|
|
4827
4863
|
const unchanged = {
|
|
4828
4864
|
scripts: [],
|
|
4829
4865
|
dependency: { name: GENERATOR_NAME, range: null, added: false }
|
|
4830
4866
|
};
|
|
4831
|
-
if (!
|
|
4867
|
+
if (!fs12__namespace.existsSync(packagePath)) {
|
|
4832
4868
|
notes.push("No package.json found, so npm scripts and the devDependency were not added.");
|
|
4833
4869
|
return unchanged;
|
|
4834
4870
|
}
|
|
4835
4871
|
let raw;
|
|
4836
4872
|
let parsed;
|
|
4837
4873
|
try {
|
|
4838
|
-
raw =
|
|
4874
|
+
raw = fs12__namespace.readFileSync(packagePath, "utf8");
|
|
4839
4875
|
parsed = JSON.parse(raw);
|
|
4840
4876
|
} catch {
|
|
4841
4877
|
notes.push("Could not parse package.json; npm scripts and the devDependency were not added.");
|
|
@@ -4959,98 +4995,108 @@ async function runInit(options) {
|
|
|
4959
4995
|
{ value: "walk", label: "Go through each setting", hint: "every question starts on its default" },
|
|
4960
4996
|
{ value: "choose", label: "Pick a different preset", hint: "everything else stays at the defaults" }
|
|
4961
4997
|
];
|
|
4962
|
-
const
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
{
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
]
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
4998
|
+
const baseInclude = [...answers.include];
|
|
4999
|
+
const baseExclude = [...answers.excludePatterns];
|
|
5000
|
+
let lastScope = "all";
|
|
5001
|
+
const artifactChoices = [
|
|
5002
|
+
{ value: "readme", label: "README.md", hint: "orientation page" },
|
|
5003
|
+
{ value: "manifest", label: "manifest.json", hint: "required by validate and report" },
|
|
5004
|
+
{ value: "parts", label: "parts/", hint: "the code payload" },
|
|
5005
|
+
{ value: "navigation", label: "reports/navigation.md", hint: "file \u2192 part index" },
|
|
5006
|
+
{ value: "projectTree", label: "reports/project-tree.md", hint: "ASCII tree" },
|
|
5007
|
+
{ value: "audit", label: "reports/audit.md", hint: "security and health findings" },
|
|
5008
|
+
{ value: "monolith", label: "full-codebase.json + .md", hint: "roughly doubles output" }
|
|
5009
|
+
];
|
|
5010
|
+
const scopeStep = async () => {
|
|
5011
|
+
for (; ; ) {
|
|
5012
|
+
const scope = await select(
|
|
5013
|
+
io,
|
|
5014
|
+
"What should go into the snapshot?",
|
|
5015
|
+
[
|
|
5016
|
+
{ value: "all", label: "Everything the scanner finds", hint: "recommended \xB7 respects .gitignore" },
|
|
5017
|
+
{ value: "folders", label: "Only specific folders\u2026" },
|
|
5018
|
+
{ value: "no-tests", label: "Everything, but skip tests" },
|
|
5019
|
+
{ value: "custom", label: "Let me write glob patterns" }
|
|
5020
|
+
],
|
|
5021
|
+
{ defaultValue: lastScope, allowBack: true }
|
|
5022
|
+
);
|
|
5023
|
+
lastScope = scope;
|
|
5024
|
+
answers.include = [...baseInclude];
|
|
5025
|
+
answers.excludePatterns = [...baseExclude];
|
|
5026
|
+
try {
|
|
5027
|
+
if (scope === "folders") {
|
|
5028
|
+
const dirs = topLevelDirs(options.cwd).slice(0, 40);
|
|
5029
|
+
if (dirs.length === 0) {
|
|
5030
|
+
notes.push("No top-level directories found; the snapshot will include everything.");
|
|
5031
|
+
} else {
|
|
5032
|
+
const chosen = await multiSelect(
|
|
5033
|
+
io,
|
|
5034
|
+
"Select folders",
|
|
5035
|
+
dirs.map((name) => ({ value: name, label: `${name}/` })),
|
|
5036
|
+
{ defaults: dirs, allowBack: true }
|
|
5037
|
+
);
|
|
5038
|
+
answers.include = chosen.map((name) => `${name}/**`);
|
|
5039
|
+
}
|
|
5040
|
+
} else if (scope === "no-tests") {
|
|
5041
|
+
answers.excludePatterns = [...baseExclude, "**/*.test.*", "**/*.spec.*", "tests", "test"];
|
|
5042
|
+
} else if (scope === "custom") {
|
|
5043
|
+
const raw = await text(io, "Glob patterns to include (comma separated)", {
|
|
5044
|
+
defaultValue: baseInclude.join(", "),
|
|
5045
|
+
allowBack: true
|
|
5046
|
+
});
|
|
5047
|
+
answers.include = raw.split(",").map((value) => value.trim()).filter(Boolean);
|
|
5048
|
+
}
|
|
5049
|
+
return;
|
|
5050
|
+
} catch (error) {
|
|
5051
|
+
if (error instanceof PromptBack) continue;
|
|
5052
|
+
throw error;
|
|
5003
5053
|
}
|
|
5004
|
-
} else if (scope === "no-tests") {
|
|
5005
|
-
answers.excludePatterns = [
|
|
5006
|
-
...answers.excludePatterns,
|
|
5007
|
-
"**/*.test.*",
|
|
5008
|
-
"**/*.spec.*",
|
|
5009
|
-
"tests",
|
|
5010
|
-
"test"
|
|
5011
|
-
];
|
|
5012
|
-
} else if (scope === "custom") {
|
|
5013
|
-
const raw = await text(io, "Glob patterns to include (comma separated)", {
|
|
5014
|
-
defaultValue: ""
|
|
5015
|
-
});
|
|
5016
|
-
answers.include = raw.split(",").map((value) => value.trim()).filter(Boolean);
|
|
5017
5054
|
}
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
validate: (value) => parseByteSize(value) === void 0 ? "Not a valid size." : null
|
|
5055
|
+
};
|
|
5056
|
+
const sizeStep = async () => {
|
|
5057
|
+
for (; ; ) {
|
|
5058
|
+
const currentBudget = String(answers.maxPartBytes);
|
|
5059
|
+
const sizeChoice = await select(io, "How large should each part be?", SIZE_CHOICES, {
|
|
5060
|
+
defaultValue: SIZE_CHOICES.some((choice) => choice.value === currentBudget) ? currentBudget : "custom",
|
|
5061
|
+
allowBack: true
|
|
5026
5062
|
});
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5063
|
+
if (sizeChoice !== "custom") {
|
|
5064
|
+
answers.maxPartBytes = sizeChoice;
|
|
5065
|
+
return;
|
|
5066
|
+
}
|
|
5067
|
+
try {
|
|
5068
|
+
const raw = await text(io, "Part size (e.g. 150k, 1.5mb, 900000)", {
|
|
5069
|
+
defaultValue: currentBudget,
|
|
5070
|
+
validate: (value) => parseByteSize(value) === void 0 ? "Not a valid size." : null,
|
|
5071
|
+
allowBack: true
|
|
5072
|
+
});
|
|
5073
|
+
answers.maxPartBytes = parseByteSize(raw) ?? answers.maxPartBytes;
|
|
5074
|
+
return;
|
|
5075
|
+
} catch (error) {
|
|
5076
|
+
if (error instanceof PromptBack) continue;
|
|
5077
|
+
throw error;
|
|
5078
|
+
}
|
|
5079
|
+
}
|
|
5080
|
+
};
|
|
5081
|
+
const artifactsStep = async () => {
|
|
5082
|
+
const enabled = ARTIFACT_NAMES.filter((name) => answers.artifacts[name]);
|
|
5041
5083
|
const selectedArtifacts = await multiSelect(
|
|
5042
5084
|
io,
|
|
5043
5085
|
"Which artifacts should be generated?",
|
|
5044
5086
|
artifactChoices,
|
|
5045
|
-
{ defaults:
|
|
5087
|
+
{ defaults: enabled, allowBack: true }
|
|
5046
5088
|
);
|
|
5047
5089
|
for (const name of ARTIFACT_NAMES) answers.artifacts[name] = selectedArtifacts.includes(name);
|
|
5048
|
-
|
|
5090
|
+
};
|
|
5091
|
+
const credentialsStep = async () => {
|
|
5049
5092
|
answers.includeSensitiveFiles = await confirm(
|
|
5050
5093
|
io,
|
|
5051
|
-
"Include credential files (.env, *.pem,
|
|
5052
|
-
{ defaultValue:
|
|
5094
|
+
"Include credential files (.env, *.pem, *.npmrc, *.ssh/)?",
|
|
5095
|
+
{ defaultValue: answers.includeSensitiveFiles, allowBack: true }
|
|
5053
5096
|
);
|
|
5097
|
+
};
|
|
5098
|
+
const reviewStep = async () => {
|
|
5099
|
+
const enabledCount = ARTIFACT_NAMES.filter((name) => answers.artifacts[name]).length;
|
|
5054
5100
|
io.output.write("\n Review\n\n");
|
|
5055
5101
|
io.output.write(` project ${answers.preset}
|
|
5056
5102
|
`);
|
|
@@ -5065,14 +5111,59 @@ async function runInit(options) {
|
|
|
5065
5111
|
`);
|
|
5066
5112
|
io.output.write(" Will write snapshot.config with your answers, plus every other setting\n");
|
|
5067
5113
|
io.output.write(" at its default \u2014 so nothing is hidden behind the docs.\n\n");
|
|
5068
|
-
const proceed = await confirm(io, "Write this and continue?", {
|
|
5069
|
-
|
|
5114
|
+
const proceed = await confirm(io, "Write this and continue?", {
|
|
5115
|
+
defaultValue: true,
|
|
5116
|
+
allowBack: true
|
|
5117
|
+
});
|
|
5118
|
+
if (!proceed) throw new PromptBack();
|
|
5119
|
+
};
|
|
5120
|
+
const walk = async () => {
|
|
5121
|
+
const steps = [scopeStep, sizeStep, artifactsStep, credentialsStep, reviewStep];
|
|
5122
|
+
let index = 0;
|
|
5123
|
+
while (index < steps.length) {
|
|
5124
|
+
try {
|
|
5125
|
+
await steps[index]();
|
|
5126
|
+
index += 1;
|
|
5127
|
+
} catch (error) {
|
|
5128
|
+
if (!(error instanceof PromptBack)) throw error;
|
|
5129
|
+
if (index === 0) return false;
|
|
5130
|
+
index -= 1;
|
|
5131
|
+
io.output.write("\n");
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
return true;
|
|
5135
|
+
};
|
|
5136
|
+
for (; ; ) {
|
|
5137
|
+
const pace = await select(io, "How should I set this up?", paceChoices, {
|
|
5138
|
+
defaultValue: fallback ? "choose" : "recommended"
|
|
5139
|
+
});
|
|
5140
|
+
if (pace === "choose") {
|
|
5141
|
+
try {
|
|
5142
|
+
answers.preset = await select(
|
|
5143
|
+
io,
|
|
5144
|
+
"What kind of project is this?",
|
|
5145
|
+
listPresetNames().map(
|
|
5146
|
+
(name) => resolvePresetChoice(fallback ? null : detected.presetName, name)
|
|
5147
|
+
),
|
|
5148
|
+
{ defaultValue: answers.preset, allowBack: true }
|
|
5149
|
+
);
|
|
5150
|
+
} catch (error) {
|
|
5151
|
+
if (error instanceof PromptBack) continue;
|
|
5152
|
+
throw error;
|
|
5153
|
+
}
|
|
5154
|
+
const chosen = detectPreset(options.cwd, answers.preset);
|
|
5155
|
+
answers.preset = chosen.presetName;
|
|
5156
|
+
reason = null;
|
|
5157
|
+
fallback = false;
|
|
5158
|
+
}
|
|
5159
|
+
if (pace === "walk" && !await walk()) continue;
|
|
5160
|
+
break;
|
|
5070
5161
|
}
|
|
5071
5162
|
}
|
|
5072
5163
|
const configText = renderConfig(answers);
|
|
5073
5164
|
const preferredName = chooseConfigFileName(options.cwd);
|
|
5074
5165
|
const presentConfigs = CONFIG_CANDIDATES.filter(
|
|
5075
|
-
(name) =>
|
|
5166
|
+
(name) => fs12__namespace.existsSync(path13__namespace.join(options.cwd, name))
|
|
5076
5167
|
);
|
|
5077
5168
|
const present = presentConfigs[0] ?? null;
|
|
5078
5169
|
if (presentConfigs.length > 1) {
|
|
@@ -5081,7 +5172,7 @@ async function runInit(options) {
|
|
|
5081
5172
|
);
|
|
5082
5173
|
}
|
|
5083
5174
|
const configName = present !== null && options.force ? present : preferredName;
|
|
5084
|
-
const configPath =
|
|
5175
|
+
const configPath = path13__namespace.join(options.cwd, configName);
|
|
5085
5176
|
const reused = present !== null && options.force !== true && options.reuseConfig === true;
|
|
5086
5177
|
if (reused) notes.push(`Kept the existing ${present} instead of writing a new one.`);
|
|
5087
5178
|
if (options.dryRun) {
|
|
@@ -5114,7 +5205,7 @@ async function runInit(options) {
|
|
|
5114
5205
|
'package.json already defines a "snapshot" config. Remove that key, or re-run with --force to write a config file that takes precedence over it.'
|
|
5115
5206
|
);
|
|
5116
5207
|
}
|
|
5117
|
-
if (
|
|
5208
|
+
if (fs12__namespace.existsSync(configPath) && !options.force && !reused) {
|
|
5118
5209
|
throw new Error(`${configName} already exists. Re-run with --force to replace it.`);
|
|
5119
5210
|
}
|
|
5120
5211
|
if (!reused) writeFileOrExplain(configPath, configText);
|
|
@@ -5136,9 +5227,9 @@ async function runInit(options) {
|
|
|
5136
5227
|
};
|
|
5137
5228
|
}
|
|
5138
5229
|
function describeTarget(cwd) {
|
|
5139
|
-
const relative11 =
|
|
5230
|
+
const relative11 = path13__namespace.relative(process.cwd(), cwd);
|
|
5140
5231
|
if (relative11 === "") return "this directory";
|
|
5141
|
-
if (relative11.startsWith("..") ||
|
|
5232
|
+
if (relative11.startsWith("..") || path13__namespace.isAbsolute(relative11)) return cwd;
|
|
5142
5233
|
return relative11;
|
|
5143
5234
|
}
|
|
5144
5235
|
function firstRunMessage(reason, cwd) {
|
|
@@ -5162,7 +5253,7 @@ function planFirstRun(facts) {
|
|
|
5162
5253
|
var NOT_CONTENT = /* @__PURE__ */ new Set([".git", ".hg", ".svn", ".bzr", ".DS_Store", "Thumbs.db"]);
|
|
5163
5254
|
function isEffectivelyEmpty(cwd) {
|
|
5164
5255
|
try {
|
|
5165
|
-
return
|
|
5256
|
+
return fs12__namespace.readdirSync(cwd).every((entry) => NOT_CONTENT.has(entry));
|
|
5166
5257
|
} catch {
|
|
5167
5258
|
return false;
|
|
5168
5259
|
}
|
|
@@ -5170,7 +5261,7 @@ function isEffectivelyEmpty(cwd) {
|
|
|
5170
5261
|
function hasPriorSnapshot(cwd, outDir) {
|
|
5171
5262
|
let parsed;
|
|
5172
5263
|
try {
|
|
5173
|
-
parsed = JSON.parse(
|
|
5264
|
+
parsed = JSON.parse(fs12__namespace.readFileSync(path13__namespace.join(cwd, outDir, ".codebase-snapshot"), "utf8"));
|
|
5174
5265
|
} catch {
|
|
5175
5266
|
return false;
|
|
5176
5267
|
}
|
|
@@ -5400,9 +5491,9 @@ var JAVA_METHOD = /^\s+(?:public|private|protected)\s+(?:static\s+)?(?:final\s+)
|
|
|
5400
5491
|
var jvmProfile = {
|
|
5401
5492
|
id: "jvm",
|
|
5402
5493
|
extensions: [".java", ".kt", ".kts", ".scala"],
|
|
5403
|
-
summarize(
|
|
5494
|
+
summarize(path19, content) {
|
|
5404
5495
|
const summary = emptySummary();
|
|
5405
|
-
const lower =
|
|
5496
|
+
const lower = path19.toLowerCase();
|
|
5406
5497
|
const isJava = lower.endsWith(".java");
|
|
5407
5498
|
const isKotlin = lower.endsWith(".kt") || lower.endsWith(".kts");
|
|
5408
5499
|
eachLine(content, (line) => {
|
|
@@ -5855,16 +5946,16 @@ function summarizeTypeScriptSource(relativePath, content) {
|
|
|
5855
5946
|
// src/ast/profiles/sfc.ts
|
|
5856
5947
|
var SCRIPT_BLOCK = /<script[^>]*>([\s\S]*?)<\/script>/gi;
|
|
5857
5948
|
var ASTRO_FRONTMATTER = /^\uFEFF?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?=\r?\n|$)/;
|
|
5858
|
-
function componentName(
|
|
5859
|
-
const base =
|
|
5949
|
+
function componentName(path19) {
|
|
5950
|
+
const base = path19.split("/").pop() ?? path19;
|
|
5860
5951
|
return base.replace(/\.[^.]+$/, "");
|
|
5861
5952
|
}
|
|
5862
5953
|
var sfcProfile = {
|
|
5863
5954
|
id: "sfc",
|
|
5864
5955
|
extensions: [".vue", ".svelte", ".astro"],
|
|
5865
|
-
summarize(
|
|
5956
|
+
summarize(path19, content) {
|
|
5866
5957
|
let script = "";
|
|
5867
|
-
if (
|
|
5958
|
+
if (path19.toLowerCase().endsWith(".astro")) {
|
|
5868
5959
|
const frontmatter = ASTRO_FRONTMATTER.exec(content);
|
|
5869
5960
|
if (frontmatter) script += `${frontmatter[1]}
|
|
5870
5961
|
`;
|
|
@@ -5873,7 +5964,7 @@ var sfcProfile = {
|
|
|
5873
5964
|
script += `${match[1]}
|
|
5874
5965
|
`;
|
|
5875
5966
|
}
|
|
5876
|
-
const name = componentName(
|
|
5967
|
+
const name = componentName(path19);
|
|
5877
5968
|
if (!script.trim()) {
|
|
5878
5969
|
const summary2 = emptySummary();
|
|
5879
5970
|
if (name) {
|
|
@@ -5907,15 +5998,15 @@ for (const profile of LANGUAGE_PROFILES) {
|
|
|
5907
5998
|
BY_EXTENSION.set(extension.toLowerCase(), profile);
|
|
5908
5999
|
}
|
|
5909
6000
|
}
|
|
5910
|
-
function profileForPath(
|
|
5911
|
-
const lower =
|
|
6001
|
+
function profileForPath(path19) {
|
|
6002
|
+
const lower = path19.toLowerCase();
|
|
5912
6003
|
const dot = lower.lastIndexOf(".");
|
|
5913
6004
|
if (dot === -1) return null;
|
|
5914
6005
|
return BY_EXTENSION.get(lower.slice(dot)) ?? null;
|
|
5915
6006
|
}
|
|
5916
|
-
function summarizeWithProfile(
|
|
5917
|
-
const profile = profileForPath(
|
|
5918
|
-
return profile ? profile.summarize(
|
|
6007
|
+
function summarizeWithProfile(path19, content) {
|
|
6008
|
+
const profile = profileForPath(path19);
|
|
6009
|
+
return profile ? profile.summarize(path19, content) : null;
|
|
5919
6010
|
}
|
|
5920
6011
|
|
|
5921
6012
|
// src/ast/structured.ts
|
|
@@ -6760,6 +6851,162 @@ function generateProjectTree(filePaths) {
|
|
|
6760
6851
|
const fence = fenceForText(lines.join("\n"), 3);
|
|
6761
6852
|
return ["# Project Tree", "", `${fence}text`, ...lines, fence, ""].join("\n");
|
|
6762
6853
|
}
|
|
6854
|
+
var PACKAGE_LATEST_URL = "https://registry.npmjs.org/codebase-snapshot/latest";
|
|
6855
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
6856
|
+
var FAILURE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
6857
|
+
var REQUEST_TIMEOUT_MS = 1200;
|
|
6858
|
+
function versionParts(value) {
|
|
6859
|
+
const core = value.trim().replace(/^v/i, "").split("-")[0];
|
|
6860
|
+
return core.split(".").map((part) => {
|
|
6861
|
+
const parsed = Number(part);
|
|
6862
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
6863
|
+
});
|
|
6864
|
+
}
|
|
6865
|
+
function isNewer(candidate, current) {
|
|
6866
|
+
const left = versionParts(candidate);
|
|
6867
|
+
const right = versionParts(current);
|
|
6868
|
+
const length = Math.max(left.length, right.length);
|
|
6869
|
+
for (let index = 0; index < length; index += 1) {
|
|
6870
|
+
const a = left[index] ?? 0;
|
|
6871
|
+
const b = right[index] ?? 0;
|
|
6872
|
+
if (a !== b) return a > b;
|
|
6873
|
+
}
|
|
6874
|
+
return false;
|
|
6875
|
+
}
|
|
6876
|
+
function cacheDirectory(env = process.env, platform = process.platform) {
|
|
6877
|
+
if (platform === "win32") {
|
|
6878
|
+
const base2 = env.LOCALAPPDATA ?? path13__namespace.join(os__namespace.homedir(), "AppData", "Local");
|
|
6879
|
+
return path13__namespace.join(base2, "codebase-snapshot");
|
|
6880
|
+
}
|
|
6881
|
+
if (platform === "darwin") {
|
|
6882
|
+
return path13__namespace.join(os__namespace.homedir(), "Library", "Caches", "codebase-snapshot");
|
|
6883
|
+
}
|
|
6884
|
+
const base = env.XDG_CACHE_HOME ?? path13__namespace.join(os__namespace.homedir(), ".cache");
|
|
6885
|
+
return path13__namespace.join(base, "codebase-snapshot");
|
|
6886
|
+
}
|
|
6887
|
+
function cacheFilePath(env = process.env) {
|
|
6888
|
+
return path13__namespace.join(cacheDirectory(env), "update-check.json");
|
|
6889
|
+
}
|
|
6890
|
+
function shouldCheck(argv, env) {
|
|
6891
|
+
const disabled = ["1", "true", "yes"].includes(
|
|
6892
|
+
String(env.CODEBASE_SNAPSHOT_NO_UPDATE_CHECK ?? "").toLowerCase()
|
|
6893
|
+
);
|
|
6894
|
+
if (disabled) return false;
|
|
6895
|
+
if (env.CI !== void 0 && env.CI !== "" && env.CI !== "false" && env.CI !== "0") return false;
|
|
6896
|
+
const args = argv.map((argument) => argument.toLowerCase());
|
|
6897
|
+
if (args.includes("--no-update-check")) return false;
|
|
6898
|
+
for (const skip of ["mcp", "describe", "skill", "--version", "-v", "--help", "-h"]) {
|
|
6899
|
+
if (args.includes(skip)) return false;
|
|
6900
|
+
}
|
|
6901
|
+
if (args.some((argument) => argument.includes("json"))) return false;
|
|
6902
|
+
return true;
|
|
6903
|
+
}
|
|
6904
|
+
function readCache(file) {
|
|
6905
|
+
let raw;
|
|
6906
|
+
try {
|
|
6907
|
+
raw = fs12__namespace.readFileSync(file, "utf8");
|
|
6908
|
+
} catch {
|
|
6909
|
+
return null;
|
|
6910
|
+
}
|
|
6911
|
+
try {
|
|
6912
|
+
const parsed = JSON.parse(raw);
|
|
6913
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
6914
|
+
const candidate = parsed;
|
|
6915
|
+
if (typeof candidate.checkedAt !== "number") return null;
|
|
6916
|
+
const latest = typeof candidate.latest === "string" ? candidate.latest : null;
|
|
6917
|
+
return { checkedAt: candidate.checkedAt, latest };
|
|
6918
|
+
} catch {
|
|
6919
|
+
return null;
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
function writeCache(file, entry) {
|
|
6923
|
+
try {
|
|
6924
|
+
fs12__namespace.mkdirSync(path13__namespace.dirname(file), { recursive: true });
|
|
6925
|
+
fs12__namespace.writeFileSync(file, `${JSON.stringify(entry)}
|
|
6926
|
+
`, "utf8");
|
|
6927
|
+
} catch {
|
|
6928
|
+
}
|
|
6929
|
+
}
|
|
6930
|
+
function fetchLatestVersion(url = PACKAGE_LATEST_URL, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
6931
|
+
return new Promise((resolve9) => {
|
|
6932
|
+
let settled = false;
|
|
6933
|
+
const finish = (value) => {
|
|
6934
|
+
if (settled) return;
|
|
6935
|
+
settled = true;
|
|
6936
|
+
resolve9(value);
|
|
6937
|
+
};
|
|
6938
|
+
const request = https__namespace.get(
|
|
6939
|
+
url,
|
|
6940
|
+
{
|
|
6941
|
+
headers: {
|
|
6942
|
+
accept: "application/json",
|
|
6943
|
+
"user-agent": "codebase-snapshot (update check)"
|
|
6944
|
+
}
|
|
6945
|
+
},
|
|
6946
|
+
(response) => {
|
|
6947
|
+
if (response.statusCode !== 200) {
|
|
6948
|
+
response.resume();
|
|
6949
|
+
finish(null);
|
|
6950
|
+
return;
|
|
6951
|
+
}
|
|
6952
|
+
let body = "";
|
|
6953
|
+
response.setEncoding("utf8");
|
|
6954
|
+
response.on("data", (chunk) => {
|
|
6955
|
+
body += chunk;
|
|
6956
|
+
if (body.length > 64 * 1024) {
|
|
6957
|
+
request.destroy();
|
|
6958
|
+
finish(null);
|
|
6959
|
+
}
|
|
6960
|
+
});
|
|
6961
|
+
response.on("end", () => {
|
|
6962
|
+
try {
|
|
6963
|
+
const parsed = JSON.parse(body);
|
|
6964
|
+
finish(typeof parsed.version === "string" ? parsed.version : null);
|
|
6965
|
+
} catch {
|
|
6966
|
+
finish(null);
|
|
6967
|
+
}
|
|
6968
|
+
});
|
|
6969
|
+
}
|
|
6970
|
+
);
|
|
6971
|
+
request.on("error", () => finish(null));
|
|
6972
|
+
request.setTimeout(timeoutMs, () => {
|
|
6973
|
+
request.destroy();
|
|
6974
|
+
finish(null);
|
|
6975
|
+
});
|
|
6976
|
+
});
|
|
6977
|
+
}
|
|
6978
|
+
async function checkForUpdate(options) {
|
|
6979
|
+
if (options.enabled === false) return null;
|
|
6980
|
+
const now = options.now ?? (() => Date.now());
|
|
6981
|
+
const fetchLatest = options.fetchLatest ?? fetchLatestVersion;
|
|
6982
|
+
let latest = null;
|
|
6983
|
+
try {
|
|
6984
|
+
const cached = readCache(options.cacheFile);
|
|
6985
|
+
let needsFetch = cached === null;
|
|
6986
|
+
if (cached) {
|
|
6987
|
+
const age = now() - cached.checkedAt;
|
|
6988
|
+
if (cached.latest === null) {
|
|
6989
|
+
needsFetch = age >= FAILURE_INTERVAL_MS;
|
|
6990
|
+
} else {
|
|
6991
|
+
latest = cached.latest;
|
|
6992
|
+
needsFetch = age >= CHECK_INTERVAL_MS;
|
|
6993
|
+
}
|
|
6994
|
+
}
|
|
6995
|
+
if (needsFetch) {
|
|
6996
|
+
const fetched = await fetchLatest(PACKAGE_LATEST_URL, REQUEST_TIMEOUT_MS);
|
|
6997
|
+
writeCache(options.cacheFile, { checkedAt: now(), latest: fetched });
|
|
6998
|
+
latest = fetched;
|
|
6999
|
+
}
|
|
7000
|
+
} catch {
|
|
7001
|
+
return null;
|
|
7002
|
+
}
|
|
7003
|
+
if (!latest) return null;
|
|
7004
|
+
return isNewer(latest, options.current) ? { current: options.current, latest } : null;
|
|
7005
|
+
}
|
|
7006
|
+
function formatUpdateNotice(notice) {
|
|
7007
|
+
return `\u2191 codebase-snapshot ${notice.latest} is available \u2014 you have ${notice.current}.
|
|
7008
|
+
npm install -g codebase-snapshot`;
|
|
7009
|
+
}
|
|
6763
7010
|
|
|
6764
7011
|
// src/index.ts
|
|
6765
7012
|
var SCHEMA_VERSION = "3.0.0";
|
|
@@ -6841,13 +7088,13 @@ function buildImportResolver(files) {
|
|
|
6841
7088
|
const relativePath = file.relativePath;
|
|
6842
7089
|
remember(byPath, relativePath, relativePath);
|
|
6843
7090
|
remember(byPathFolded, relativePath.toLowerCase(), relativePath);
|
|
6844
|
-
const extension =
|
|
7091
|
+
const extension = path13__namespace.posix.extname(relativePath);
|
|
6845
7092
|
if (!SOURCE_EXTENSIONS.has(extension)) continue;
|
|
6846
7093
|
const stem = relativePath.slice(0, -extension.length);
|
|
6847
7094
|
remember(byStem, stem, relativePath);
|
|
6848
7095
|
remember(byStemFolded, stem.toLowerCase(), relativePath);
|
|
6849
|
-
if (
|
|
6850
|
-
const directory =
|
|
7096
|
+
if (path13__namespace.posix.basename(stem) === "index") {
|
|
7097
|
+
const directory = path13__namespace.posix.dirname(stem);
|
|
6851
7098
|
remember(byStem, directory, relativePath);
|
|
6852
7099
|
remember(byStemFolded, directory.toLowerCase(), relativePath);
|
|
6853
7100
|
}
|
|
@@ -6856,8 +7103,8 @@ function buildImportResolver(files) {
|
|
|
6856
7103
|
}
|
|
6857
7104
|
function resolveSpecifier(fromFile, specifier, resolver) {
|
|
6858
7105
|
if (!RELATIVE_SPECIFIER.test(specifier)) return null;
|
|
6859
|
-
const joined =
|
|
6860
|
-
|
|
7106
|
+
const joined = path13__namespace.posix.normalize(
|
|
7107
|
+
path13__namespace.posix.join(path13__namespace.posix.dirname(fromFile), specifier)
|
|
6861
7108
|
);
|
|
6862
7109
|
const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
|
|
6863
7110
|
const direct = exact(joined);
|
|
@@ -6950,11 +7197,11 @@ function verifyInMemory(files, parts, maxPartBytes) {
|
|
|
6950
7197
|
return errors;
|
|
6951
7198
|
}
|
|
6952
7199
|
function resolveSafeOutputDirs(config) {
|
|
6953
|
-
const cwd =
|
|
6954
|
-
const outDir =
|
|
6955
|
-
const tmpDir =
|
|
6956
|
-
const root =
|
|
6957
|
-
const contains = (parent, child) => child === parent || child.startsWith(`${parent}${
|
|
7200
|
+
const cwd = path13__namespace.resolve(config.cwd);
|
|
7201
|
+
const outDir = path13__namespace.resolve(cwd, config.outDir);
|
|
7202
|
+
const tmpDir = path13__namespace.resolve(cwd, config.tmpDir);
|
|
7203
|
+
const root = path13__namespace.parse(cwd).root;
|
|
7204
|
+
const contains = (parent, child) => child === parent || child.startsWith(`${parent}${path13__namespace.sep}`);
|
|
6958
7205
|
const reject = (reason) => {
|
|
6959
7206
|
throw new Error(
|
|
6960
7207
|
`Refusing to generate: ${reason}. outDir=${outDir} tmpDir=${tmpDir} cwd=${cwd}`
|
|
@@ -7010,14 +7257,14 @@ function listEntries(dir) {
|
|
|
7010
7257
|
const walk = (absolute, prefix) => {
|
|
7011
7258
|
let children;
|
|
7012
7259
|
try {
|
|
7013
|
-
children =
|
|
7260
|
+
children = fs12__namespace.readdirSync(absolute, { withFileTypes: true });
|
|
7014
7261
|
} catch {
|
|
7015
7262
|
return;
|
|
7016
7263
|
}
|
|
7017
7264
|
for (const child of children) {
|
|
7018
7265
|
const relative11 = prefix === "" ? child.name : `${prefix}/${child.name}`;
|
|
7019
7266
|
entries.push(relative11);
|
|
7020
|
-
if (child.isDirectory()) walk(
|
|
7267
|
+
if (child.isDirectory()) walk(path13__namespace.join(absolute, child.name), relative11);
|
|
7021
7268
|
}
|
|
7022
7269
|
};
|
|
7023
7270
|
walk(dir, "");
|
|
@@ -7034,28 +7281,28 @@ function markerPayload(dir, state, id, createdAt) {
|
|
|
7034
7281
|
pid: process.pid,
|
|
7035
7282
|
entries: listEntries(dir)
|
|
7036
7283
|
};
|
|
7037
|
-
const manifestPath =
|
|
7038
|
-
if (
|
|
7039
|
-
marker2.manifestSha256 = sha256Hex2(
|
|
7284
|
+
const manifestPath = path13__namespace.join(dir, "manifest.json");
|
|
7285
|
+
if (fs12__namespace.existsSync(manifestPath)) {
|
|
7286
|
+
marker2.manifestSha256 = sha256Hex2(fs12__namespace.readFileSync(manifestPath));
|
|
7040
7287
|
}
|
|
7041
7288
|
return marker2;
|
|
7042
7289
|
}
|
|
7043
7290
|
function writeOwnershipMarker(dir, marker2) {
|
|
7044
|
-
|
|
7045
|
-
|
|
7291
|
+
fs12__namespace.writeFileSync(
|
|
7292
|
+
path13__namespace.join(dir, OWNERSHIP_MARKER),
|
|
7046
7293
|
`${JSON.stringify(marker2, null, 2)}
|
|
7047
7294
|
`,
|
|
7048
7295
|
"utf8"
|
|
7049
7296
|
);
|
|
7050
7297
|
}
|
|
7051
7298
|
function readOwnershipMarker(dir) {
|
|
7052
|
-
const markerPath =
|
|
7053
|
-
if (!
|
|
7299
|
+
const markerPath = path13__namespace.join(dir, OWNERSHIP_MARKER);
|
|
7300
|
+
if (!fs12__namespace.existsSync(markerPath)) {
|
|
7054
7301
|
return { marker: null, problem: "it holds no .codebase-snapshot marker" };
|
|
7055
7302
|
}
|
|
7056
7303
|
let raw;
|
|
7057
7304
|
try {
|
|
7058
|
-
raw =
|
|
7305
|
+
raw = fs12__namespace.readFileSync(markerPath, "utf8");
|
|
7059
7306
|
} catch {
|
|
7060
7307
|
return { marker: null, problem: "its .codebase-snapshot marker could not be read" };
|
|
7061
7308
|
}
|
|
@@ -7123,11 +7370,11 @@ function assessSnapshotDirectory(dir) {
|
|
|
7123
7370
|
marker: marker2
|
|
7124
7371
|
};
|
|
7125
7372
|
}
|
|
7126
|
-
const manifestPath =
|
|
7127
|
-
if (
|
|
7373
|
+
const manifestPath = path13__namespace.join(dir, "manifest.json");
|
|
7374
|
+
if (fs12__namespace.existsSync(manifestPath)) {
|
|
7128
7375
|
let raw;
|
|
7129
7376
|
try {
|
|
7130
|
-
raw =
|
|
7377
|
+
raw = fs12__namespace.readFileSync(manifestPath, "utf8");
|
|
7131
7378
|
} catch {
|
|
7132
7379
|
return {
|
|
7133
7380
|
owned: false,
|
|
@@ -7209,13 +7456,13 @@ function containsNoFiles(dir) {
|
|
|
7209
7456
|
const current = pending.pop();
|
|
7210
7457
|
let entries;
|
|
7211
7458
|
try {
|
|
7212
|
-
entries =
|
|
7459
|
+
entries = fs12__namespace.readdirSync(current, { withFileTypes: true });
|
|
7213
7460
|
} catch {
|
|
7214
7461
|
return false;
|
|
7215
7462
|
}
|
|
7216
7463
|
for (const entry of entries) {
|
|
7217
7464
|
if (entry.isDirectory()) {
|
|
7218
|
-
pending.push(
|
|
7465
|
+
pending.push(path13__namespace.join(current, entry.name));
|
|
7219
7466
|
} else if (!IGNORABLE_ENTRIES.has(entry.name)) {
|
|
7220
7467
|
return false;
|
|
7221
7468
|
}
|
|
@@ -7224,13 +7471,13 @@ function containsNoFiles(dir) {
|
|
|
7224
7471
|
return true;
|
|
7225
7472
|
}
|
|
7226
7473
|
function assertReplaceable(target, label, secretRules) {
|
|
7227
|
-
if (!
|
|
7228
|
-
if (!
|
|
7474
|
+
if (!fs12__namespace.existsSync(target)) return;
|
|
7475
|
+
if (!fs12__namespace.statSync(target).isDirectory()) {
|
|
7229
7476
|
throw new Error(
|
|
7230
7477
|
`Refusing to write into ${label} ${target}: it exists but is not a directory.`
|
|
7231
7478
|
);
|
|
7232
7479
|
}
|
|
7233
|
-
const entries =
|
|
7480
|
+
const entries = fs12__namespace.readdirSync(target);
|
|
7234
7481
|
if (entries.length === 0) return;
|
|
7235
7482
|
if (entries.every((name) => IGNORABLE_ENTRIES.has(name))) return;
|
|
7236
7483
|
if (containsNoFiles(target)) return;
|
|
@@ -7250,18 +7497,18 @@ function assertReplaceable(target, label, secretRules) {
|
|
|
7250
7497
|
);
|
|
7251
7498
|
}
|
|
7252
7499
|
function assertStagingRootUsable(tmpDir, secretRules) {
|
|
7253
|
-
if (!
|
|
7254
|
-
if (!
|
|
7500
|
+
if (!fs12__namespace.existsSync(tmpDir)) return;
|
|
7501
|
+
if (!fs12__namespace.statSync(tmpDir).isDirectory()) {
|
|
7255
7502
|
throw new Error(`Refusing to write into tmpDir ${tmpDir}: it exists but is not a directory.`);
|
|
7256
7503
|
}
|
|
7257
|
-
const entries =
|
|
7504
|
+
const entries = fs12__namespace.readdirSync(tmpDir);
|
|
7258
7505
|
if (entries.length === 0) return;
|
|
7259
7506
|
const foreign = entries.filter((name) => {
|
|
7260
|
-
const full =
|
|
7507
|
+
const full = path13__namespace.join(tmpDir, name);
|
|
7261
7508
|
if (!name.startsWith(RUN_DIR_PREFIX)) return true;
|
|
7262
7509
|
let stats;
|
|
7263
7510
|
try {
|
|
7264
|
-
stats =
|
|
7511
|
+
stats = fs12__namespace.statSync(full);
|
|
7265
7512
|
} catch {
|
|
7266
7513
|
return true;
|
|
7267
7514
|
}
|
|
@@ -7269,7 +7516,7 @@ function assertStagingRootUsable(tmpDir, secretRules) {
|
|
|
7269
7516
|
const { marker: marker2 } = readOwnershipMarker(full);
|
|
7270
7517
|
if (marker2) return false;
|
|
7271
7518
|
try {
|
|
7272
|
-
return
|
|
7519
|
+
return fs12__namespace.readdirSync(full).length > 0;
|
|
7273
7520
|
} catch {
|
|
7274
7521
|
return true;
|
|
7275
7522
|
}
|
|
@@ -7284,13 +7531,13 @@ function assertStagingRootUsable(tmpDir, secretRules) {
|
|
|
7284
7531
|
function cleanStaleRunDirs(tmpDir) {
|
|
7285
7532
|
let entries;
|
|
7286
7533
|
try {
|
|
7287
|
-
entries =
|
|
7534
|
+
entries = fs12__namespace.readdirSync(tmpDir);
|
|
7288
7535
|
} catch {
|
|
7289
7536
|
return;
|
|
7290
7537
|
}
|
|
7291
7538
|
for (const name of entries) {
|
|
7292
7539
|
if (!name.startsWith(RUN_DIR_PREFIX)) continue;
|
|
7293
|
-
const full =
|
|
7540
|
+
const full = path13__namespace.join(tmpDir, name);
|
|
7294
7541
|
const { marker: marker2 } = readOwnershipMarker(full);
|
|
7295
7542
|
if (marker2) {
|
|
7296
7543
|
const created = Date.parse(marker2.createdAt);
|
|
@@ -7298,33 +7545,33 @@ function cleanStaleRunDirs(tmpDir) {
|
|
|
7298
7545
|
const abandoned = typeof marker2.pid === "number" && !isProcessAlive(marker2.pid);
|
|
7299
7546
|
if (aged || abandoned) {
|
|
7300
7547
|
try {
|
|
7301
|
-
|
|
7548
|
+
fs12__namespace.rmSync(full, { recursive: true, force: true });
|
|
7302
7549
|
} catch {
|
|
7303
7550
|
}
|
|
7304
7551
|
}
|
|
7305
7552
|
continue;
|
|
7306
7553
|
}
|
|
7307
7554
|
try {
|
|
7308
|
-
if (
|
|
7555
|
+
if (fs12__namespace.readdirSync(full).length === 0) fs12__namespace.rmSync(full, { recursive: true, force: true });
|
|
7309
7556
|
} catch {
|
|
7310
7557
|
}
|
|
7311
7558
|
}
|
|
7312
7559
|
}
|
|
7313
7560
|
function removeIfEmpty(dir) {
|
|
7314
7561
|
try {
|
|
7315
|
-
if (
|
|
7562
|
+
if (fs12__namespace.readdirSync(dir).length === 0) fs12__namespace.rmSync(dir, { recursive: true, force: true });
|
|
7316
7563
|
} catch {
|
|
7317
7564
|
}
|
|
7318
7565
|
}
|
|
7319
7566
|
function ensureParentDirectory(target, label) {
|
|
7320
|
-
const parent =
|
|
7321
|
-
if (
|
|
7567
|
+
const parent = path13__namespace.dirname(target);
|
|
7568
|
+
if (fs12__namespace.existsSync(parent) && !fs12__namespace.statSync(parent).isDirectory()) {
|
|
7322
7569
|
throw new Error(
|
|
7323
7570
|
`Refusing to create ${label} ${target}: ${parent} exists but is not a directory.`
|
|
7324
7571
|
);
|
|
7325
7572
|
}
|
|
7326
7573
|
try {
|
|
7327
|
-
|
|
7574
|
+
fs12__namespace.mkdirSync(parent, { recursive: true });
|
|
7328
7575
|
} catch (err) {
|
|
7329
7576
|
throw new Error(
|
|
7330
7577
|
`Refusing to create ${label} ${target}: its parent ${parent} could not be created (${err.message}).`
|
|
@@ -7333,7 +7580,7 @@ function ensureParentDirectory(target, label) {
|
|
|
7333
7580
|
}
|
|
7334
7581
|
function acquireRunLock(stagingRoot) {
|
|
7335
7582
|
const key = lockKeyFor(stagingRoot);
|
|
7336
|
-
const lockPath =
|
|
7583
|
+
const lockPath = path13__namespace.join(os__namespace.tmpdir(), `codebase-snapshot-${key}.lock`);
|
|
7337
7584
|
const payload = `${JSON.stringify({
|
|
7338
7585
|
pid: process.pid,
|
|
7339
7586
|
stagingRoot,
|
|
@@ -7342,22 +7589,22 @@ function acquireRunLock(stagingRoot) {
|
|
|
7342
7589
|
`;
|
|
7343
7590
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
7344
7591
|
try {
|
|
7345
|
-
const handle =
|
|
7592
|
+
const handle = fs12__namespace.openSync(lockPath, "wx");
|
|
7346
7593
|
try {
|
|
7347
|
-
|
|
7594
|
+
fs12__namespace.writeSync(handle, payload);
|
|
7348
7595
|
} finally {
|
|
7349
|
-
|
|
7596
|
+
fs12__namespace.closeSync(handle);
|
|
7350
7597
|
}
|
|
7351
7598
|
return () => {
|
|
7352
7599
|
try {
|
|
7353
|
-
|
|
7600
|
+
fs12__namespace.rmSync(lockPath, { force: true });
|
|
7354
7601
|
} catch {
|
|
7355
7602
|
}
|
|
7356
7603
|
};
|
|
7357
7604
|
} catch (err) {
|
|
7358
7605
|
if (err.code !== "EEXIST") throw err;
|
|
7359
7606
|
if (attempt === 0 && lockOwnerIsGone(lockPath)) {
|
|
7360
|
-
|
|
7607
|
+
fs12__namespace.rmSync(lockPath, { force: true });
|
|
7361
7608
|
continue;
|
|
7362
7609
|
}
|
|
7363
7610
|
throw new Error(
|
|
@@ -7370,7 +7617,7 @@ function acquireRunLock(stagingRoot) {
|
|
|
7370
7617
|
function lockKeyFor(stagingRoot) {
|
|
7371
7618
|
let key = stagingRoot;
|
|
7372
7619
|
try {
|
|
7373
|
-
key =
|
|
7620
|
+
key = fs12__namespace.realpathSync(stagingRoot);
|
|
7374
7621
|
} catch {
|
|
7375
7622
|
}
|
|
7376
7623
|
if (process.platform === "win32" || process.platform === "darwin") key = key.toLowerCase();
|
|
@@ -7379,7 +7626,7 @@ function lockKeyFor(stagingRoot) {
|
|
|
7379
7626
|
function lockOwnerIsGone(lockPath) {
|
|
7380
7627
|
let raw;
|
|
7381
7628
|
try {
|
|
7382
|
-
raw =
|
|
7629
|
+
raw = fs12__namespace.readFileSync(lockPath, "utf8");
|
|
7383
7630
|
} catch {
|
|
7384
7631
|
return false;
|
|
7385
7632
|
}
|
|
@@ -7399,12 +7646,12 @@ function lockOwnerIsGone(lockPath) {
|
|
|
7399
7646
|
}
|
|
7400
7647
|
function writeManifestAtomically(manifestPath, manifest) {
|
|
7401
7648
|
const tempPath = `${manifestPath}.${process.pid}.tmp`;
|
|
7402
|
-
|
|
7649
|
+
fs12__namespace.writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf8");
|
|
7403
7650
|
try {
|
|
7404
|
-
|
|
7651
|
+
fs12__namespace.renameSync(tempPath, manifestPath);
|
|
7405
7652
|
} catch (err) {
|
|
7406
7653
|
try {
|
|
7407
|
-
|
|
7654
|
+
fs12__namespace.rmSync(tempPath, { force: true });
|
|
7408
7655
|
} catch {
|
|
7409
7656
|
}
|
|
7410
7657
|
throw err;
|
|
@@ -7427,31 +7674,31 @@ function swapIntoPlace(stagingDir, outDir) {
|
|
|
7427
7674
|
}
|
|
7428
7675
|
function swapOnce(stagingDir, outDir) {
|
|
7429
7676
|
const backupDir = `${outDir}.backup-${process.pid}-${Date.now()}`;
|
|
7430
|
-
const hadPrevious =
|
|
7431
|
-
if (hadPrevious)
|
|
7677
|
+
const hadPrevious = fs12__namespace.existsSync(outDir);
|
|
7678
|
+
if (hadPrevious) fs12__namespace.renameSync(outDir, backupDir);
|
|
7432
7679
|
try {
|
|
7433
7680
|
try {
|
|
7434
|
-
|
|
7681
|
+
fs12__namespace.renameSync(stagingDir, outDir);
|
|
7435
7682
|
} catch (err) {
|
|
7436
7683
|
if (err.code !== "EXDEV") throw err;
|
|
7437
7684
|
const partialDir = `${outDir}.partial-${process.pid}-${Date.now()}`;
|
|
7438
7685
|
try {
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7686
|
+
fs12__namespace.cpSync(stagingDir, partialDir, { recursive: true });
|
|
7687
|
+
fs12__namespace.renameSync(partialDir, outDir);
|
|
7688
|
+
fs12__namespace.rmSync(stagingDir, { recursive: true, force: true });
|
|
7442
7689
|
} catch (copyErr) {
|
|
7443
7690
|
try {
|
|
7444
|
-
|
|
7691
|
+
fs12__namespace.rmSync(partialDir, { recursive: true, force: true });
|
|
7445
7692
|
} catch {
|
|
7446
7693
|
}
|
|
7447
7694
|
throw copyErr;
|
|
7448
7695
|
}
|
|
7449
7696
|
}
|
|
7450
|
-
if (hadPrevious)
|
|
7697
|
+
if (hadPrevious) fs12__namespace.rmSync(backupDir, { recursive: true, force: true });
|
|
7451
7698
|
} catch (err) {
|
|
7452
|
-
if (hadPrevious &&
|
|
7453
|
-
if (
|
|
7454
|
-
|
|
7699
|
+
if (hadPrevious && fs12__namespace.existsSync(backupDir)) {
|
|
7700
|
+
if (fs12__namespace.existsSync(outDir)) fs12__namespace.rmSync(outDir, { recursive: true, force: true });
|
|
7701
|
+
fs12__namespace.renameSync(backupDir, outDir);
|
|
7455
7702
|
}
|
|
7456
7703
|
throw err;
|
|
7457
7704
|
}
|
|
@@ -7546,7 +7793,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7546
7793
|
// first run cannot have marked them yet, so the name alone keeps a run from recording its own
|
|
7547
7794
|
// output — but only at these exact paths, not at every directory that shares the name.
|
|
7548
7795
|
toolOwnedPaths: [config.outDir, config.tmpDir].map(
|
|
7549
|
-
(directory) =>
|
|
7796
|
+
(directory) => path13__namespace.relative(config.cwd, path13__namespace.resolve(config.cwd, directory)).replace(/\\/g, "/")
|
|
7550
7797
|
).filter((relative11) => relative11.length > 0 && !relative11.startsWith(".."))
|
|
7551
7798
|
});
|
|
7552
7799
|
const files = [];
|
|
@@ -7567,12 +7814,12 @@ function generateSnapshot(configInput, options) {
|
|
|
7567
7814
|
let totalSizeBytes = 0;
|
|
7568
7815
|
let largeFileCount = 0;
|
|
7569
7816
|
for (const relativePath of collection.files) {
|
|
7570
|
-
const absolutePath =
|
|
7817
|
+
const absolutePath = path13__namespace.join(config.cwd, relativePath);
|
|
7571
7818
|
let stats;
|
|
7572
7819
|
try {
|
|
7573
|
-
stats =
|
|
7820
|
+
stats = fs12__namespace.statSync(absolutePath);
|
|
7574
7821
|
if (!stats.isFile()) {
|
|
7575
|
-
const nestedRepository = stats.isDirectory() &&
|
|
7822
|
+
const nestedRepository = stats.isDirectory() && fs12__namespace.existsSync(path13__namespace.join(absolutePath, ".git"));
|
|
7576
7823
|
skipped.push(
|
|
7577
7824
|
nestedRepository ? {
|
|
7578
7825
|
path: relativePath,
|
|
@@ -7592,7 +7839,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7592
7839
|
}
|
|
7593
7840
|
let buffer;
|
|
7594
7841
|
try {
|
|
7595
|
-
buffer =
|
|
7842
|
+
buffer = fs12__namespace.readFileSync(absolutePath);
|
|
7596
7843
|
} catch {
|
|
7597
7844
|
skipped.push({ path: relativePath, reason: "read-error" });
|
|
7598
7845
|
continue;
|
|
@@ -7922,12 +8169,12 @@ function generateSnapshot(configInput, options) {
|
|
|
7922
8169
|
let stagingDir = null;
|
|
7923
8170
|
try {
|
|
7924
8171
|
ensureParentDirectory(outDir, "outDir");
|
|
7925
|
-
|
|
8172
|
+
fs12__namespace.mkdirSync(tmpDir, { recursive: true });
|
|
7926
8173
|
cleanStaleRunDirs(tmpDir);
|
|
7927
8174
|
const snapshotId = crypto2__namespace.randomUUID();
|
|
7928
8175
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7929
|
-
stagingDir =
|
|
7930
|
-
|
|
8176
|
+
stagingDir = path13__namespace.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
|
|
8177
|
+
fs12__namespace.mkdirSync(stagingDir);
|
|
7931
8178
|
writeOwnershipMarker(stagingDir, {
|
|
7932
8179
|
generator: GENERATOR_NAME,
|
|
7933
8180
|
version: GENERATOR_VERSION,
|
|
@@ -7937,41 +8184,41 @@ function generateSnapshot(configInput, options) {
|
|
|
7937
8184
|
id: snapshotId,
|
|
7938
8185
|
pid: process.pid
|
|
7939
8186
|
});
|
|
7940
|
-
const partsDir =
|
|
7941
|
-
const reportsDir =
|
|
7942
|
-
if (artifacts.parts)
|
|
8187
|
+
const partsDir = path13__namespace.join(stagingDir, "parts");
|
|
8188
|
+
const reportsDir = path13__namespace.join(stagingDir, "reports");
|
|
8189
|
+
if (artifacts.parts) fs12__namespace.mkdirSync(partsDir, { recursive: true });
|
|
7943
8190
|
if (artifacts.navigation || artifacts.projectTree || artifacts.audit) {
|
|
7944
|
-
|
|
8191
|
+
fs12__namespace.mkdirSync(reportsDir, { recursive: true });
|
|
7945
8192
|
}
|
|
7946
8193
|
if (artifacts.parts) {
|
|
7947
8194
|
for (const part of parts) {
|
|
7948
|
-
|
|
8195
|
+
fs12__namespace.writeFileSync(path13__namespace.join(partsDir, part.filename), part.markdown, "utf8");
|
|
7949
8196
|
}
|
|
7950
8197
|
}
|
|
7951
8198
|
if (projectTree !== null) {
|
|
7952
|
-
|
|
8199
|
+
fs12__namespace.writeFileSync(path13__namespace.join(reportsDir, "project-tree.md"), projectTree, "utf8");
|
|
7953
8200
|
}
|
|
7954
8201
|
if (artifacts.navigation) {
|
|
7955
|
-
|
|
8202
|
+
fs12__namespace.writeFileSync(path13__namespace.join(reportsDir, "navigation.md"), generateNavigation(manifest), "utf8");
|
|
7956
8203
|
}
|
|
7957
8204
|
if (artifacts.audit) {
|
|
7958
|
-
|
|
7959
|
-
|
|
8205
|
+
fs12__namespace.writeFileSync(
|
|
8206
|
+
path13__namespace.join(reportsDir, "audit.md"),
|
|
7960
8207
|
generateAuditReport(manifest, secretFindings, config.secretRules),
|
|
7961
8208
|
"utf8"
|
|
7962
8209
|
);
|
|
7963
8210
|
}
|
|
7964
8211
|
if (artifacts.readme) {
|
|
7965
|
-
|
|
8212
|
+
fs12__namespace.writeFileSync(path13__namespace.join(stagingDir, "README.md"), generateReadme(manifest, artifacts), "utf8");
|
|
7966
8213
|
}
|
|
7967
8214
|
if (artifacts.manifest) {
|
|
7968
|
-
|
|
8215
|
+
fs12__namespace.writeFileSync(path13__namespace.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
|
|
7969
8216
|
}
|
|
7970
8217
|
if (monolithJson !== null) {
|
|
7971
|
-
|
|
8218
|
+
fs12__namespace.writeFileSync(path13__namespace.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
|
|
7972
8219
|
}
|
|
7973
8220
|
if (monolithMarkdown !== null) {
|
|
7974
|
-
|
|
8221
|
+
fs12__namespace.writeFileSync(path13__namespace.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
|
|
7975
8222
|
}
|
|
7976
8223
|
writeOwnershipMarker(stagingDir, markerPayload(stagingDir, "complete", snapshotId, createdAt));
|
|
7977
8224
|
swapIntoPlace(stagingDir, outDir);
|
|
@@ -7980,7 +8227,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7980
8227
|
const pendingHook = runAfterGenerate(config, manifest);
|
|
7981
8228
|
const shipHookState = () => {
|
|
7982
8229
|
if (artifacts.manifest && manifest.warnings.length !== warningsBeforeHook) {
|
|
7983
|
-
writeManifestAtomically(
|
|
8230
|
+
writeManifestAtomically(path13__namespace.join(outDir, "manifest.json"), manifest);
|
|
7984
8231
|
}
|
|
7985
8232
|
writeOwnershipMarker(outDir, markerPayload(outDir, "complete", snapshotId, createdAt));
|
|
7986
8233
|
};
|
|
@@ -8003,7 +8250,7 @@ function generateSnapshot(configInput, options) {
|
|
|
8003
8250
|
} catch (err) {
|
|
8004
8251
|
if (stagingDir !== null) {
|
|
8005
8252
|
try {
|
|
8006
|
-
|
|
8253
|
+
fs12__namespace.rmSync(stagingDir, { recursive: true, force: true });
|
|
8007
8254
|
} catch {
|
|
8008
8255
|
}
|
|
8009
8256
|
}
|
|
@@ -8100,9 +8347,9 @@ function foldForComparison(value) {
|
|
|
8100
8347
|
return process.platform === "win32" || process.platform === "darwin" ? value.toLowerCase() : value;
|
|
8101
8348
|
}
|
|
8102
8349
|
function canonicalPath(value) {
|
|
8103
|
-
const absolute =
|
|
8350
|
+
const absolute = path13__namespace.resolve(value);
|
|
8104
8351
|
try {
|
|
8105
|
-
return
|
|
8352
|
+
return fs12__namespace.realpathSync(absolute);
|
|
8106
8353
|
} catch {
|
|
8107
8354
|
return absolute;
|
|
8108
8355
|
}
|
|
@@ -8110,17 +8357,17 @@ function canonicalPath(value) {
|
|
|
8110
8357
|
function isInside2(parent, child) {
|
|
8111
8358
|
const foldedParent = foldForComparison(parent);
|
|
8112
8359
|
const foldedChild = foldForComparison(child);
|
|
8113
|
-
return foldedChild === foldedParent || foldedChild.startsWith(`${foldedParent}${
|
|
8360
|
+
return foldedChild === foldedParent || foldedChild.startsWith(`${foldedParent}${path13__namespace.sep}`);
|
|
8114
8361
|
}
|
|
8115
8362
|
function resolveRoot(requested, context) {
|
|
8116
8363
|
if (requested !== void 0 && (typeof requested !== "string" || requested.trim().length === 0)) {
|
|
8117
8364
|
return { ok: false, message: '"root" must be a non-empty string when provided.' };
|
|
8118
8365
|
}
|
|
8119
8366
|
const wanted = typeof requested === "string" ? requested.trim() : context.cwd;
|
|
8120
|
-
const absolute =
|
|
8367
|
+
const absolute = path13__namespace.resolve(context.cwd, wanted);
|
|
8121
8368
|
let stats;
|
|
8122
8369
|
try {
|
|
8123
|
-
stats =
|
|
8370
|
+
stats = fs12__namespace.statSync(absolute);
|
|
8124
8371
|
} catch {
|
|
8125
8372
|
return { ok: false, message: `"${wanted}" does not exist, so it cannot be a repository root.` };
|
|
8126
8373
|
}
|
|
@@ -8171,14 +8418,14 @@ async function openWorkspace(root, overrides = {}) {
|
|
|
8171
8418
|
}
|
|
8172
8419
|
var manifestCache = /* @__PURE__ */ new Map();
|
|
8173
8420
|
function manifestPathFor(workspace) {
|
|
8174
|
-
return
|
|
8421
|
+
return path13__namespace.resolve(workspace.root, workspace.config.outDir, "manifest.json");
|
|
8175
8422
|
}
|
|
8176
8423
|
function readManifest3(workspace) {
|
|
8177
8424
|
const file = manifestPathFor(workspace);
|
|
8178
|
-
const shown =
|
|
8425
|
+
const shown = path13__namespace.relative(workspace.root, file).split(path13__namespace.sep).join("/") || file;
|
|
8179
8426
|
let stats;
|
|
8180
8427
|
try {
|
|
8181
|
-
stats =
|
|
8428
|
+
stats = fs12__namespace.statSync(file);
|
|
8182
8429
|
} catch {
|
|
8183
8430
|
return {
|
|
8184
8431
|
ok: false,
|
|
@@ -8192,7 +8439,7 @@ function readManifest3(workspace) {
|
|
|
8192
8439
|
}
|
|
8193
8440
|
let raw;
|
|
8194
8441
|
try {
|
|
8195
|
-
raw =
|
|
8442
|
+
raw = fs12__namespace.readFileSync(file, "utf8");
|
|
8196
8443
|
} catch (error) {
|
|
8197
8444
|
return {
|
|
8198
8445
|
ok: false,
|
|
@@ -8250,7 +8497,7 @@ function formatBytes(bytes) {
|
|
|
8250
8497
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
8251
8498
|
}
|
|
8252
8499
|
function relativeFor(workspace, absolute) {
|
|
8253
|
-
return
|
|
8500
|
+
return path13__namespace.relative(workspace.root, absolute).split(path13__namespace.sep).join("/");
|
|
8254
8501
|
}
|
|
8255
8502
|
function capped(values, limit = 20) {
|
|
8256
8503
|
return { count: values.length, sample: values.slice(0, limit) };
|
|
@@ -8269,12 +8516,12 @@ function summarizeDrift(drift) {
|
|
|
8269
8516
|
function toRelativePath(root, value) {
|
|
8270
8517
|
const cleaned = value.trim();
|
|
8271
8518
|
if (cleaned.length === 0) return null;
|
|
8272
|
-
if (!
|
|
8519
|
+
if (!path13__namespace.isAbsolute(cleaned)) {
|
|
8273
8520
|
return cleaned.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
8274
8521
|
}
|
|
8275
|
-
const relative11 =
|
|
8276
|
-
if (relative11.startsWith("..") ||
|
|
8277
|
-
return relative11.split(
|
|
8522
|
+
const relative11 = path13__namespace.relative(root, cleaned);
|
|
8523
|
+
if (relative11.startsWith("..") || path13__namespace.isAbsolute(relative11)) return null;
|
|
8524
|
+
return relative11.split(path13__namespace.sep).join("/");
|
|
8278
8525
|
}
|
|
8279
8526
|
function symbolsOf(entry) {
|
|
8280
8527
|
const summary = entry.summary;
|
|
@@ -8485,7 +8732,7 @@ var generateTool = {
|
|
|
8485
8732
|
return failure(error instanceof Error ? error.message : String(error));
|
|
8486
8733
|
}
|
|
8487
8734
|
forgetManifest(manifestPathFor(workspace));
|
|
8488
|
-
const written = relativeFor(workspace,
|
|
8735
|
+
const written = relativeFor(workspace, path13__namespace.resolve(workspace.root, workspace.config.outDir));
|
|
8489
8736
|
const lines = [
|
|
8490
8737
|
`Wrote ${written}/`,
|
|
8491
8738
|
`Files: ${manifest.counts.totalFiles} included, ${manifest.counts.skippedCount} skipped, ${plural(manifest.counts.partsCount, "part")}`,
|
|
@@ -8750,10 +8997,10 @@ var readTool = {
|
|
|
8750
8997
|
`${relativePath} is not in the snapshot. Call snapshot_locate to find the path, or snapshot_explain to learn why it was excluded.`
|
|
8751
8998
|
);
|
|
8752
8999
|
}
|
|
8753
|
-
const partPath =
|
|
9000
|
+
const partPath = path13__namespace.resolve(workspace.root, workspace.config.outDir, "parts", entry.part);
|
|
8754
9001
|
let partText;
|
|
8755
9002
|
try {
|
|
8756
|
-
partText =
|
|
9003
|
+
partText = fs12__namespace.readFileSync(partPath, "utf8");
|
|
8757
9004
|
} catch {
|
|
8758
9005
|
return failure(
|
|
8759
9006
|
`${entry.part} could not be read, so the snapshot is damaged. Run snapshot_generate to rebuild it.`
|
|
@@ -9011,6 +9258,7 @@ var VALIDATE_OPTIONS = [
|
|
|
9011
9258
|
"no-config",
|
|
9012
9259
|
"discovery",
|
|
9013
9260
|
"format",
|
|
9261
|
+
"no-update-check",
|
|
9014
9262
|
"mode",
|
|
9015
9263
|
"help",
|
|
9016
9264
|
"version"
|
|
@@ -9034,6 +9282,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9034
9282
|
"watch",
|
|
9035
9283
|
"autopilot",
|
|
9036
9284
|
"no-install",
|
|
9285
|
+
"no-update-check",
|
|
9037
9286
|
"help",
|
|
9038
9287
|
"version"
|
|
9039
9288
|
],
|
|
@@ -9049,6 +9298,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9049
9298
|
"skip-artifacts",
|
|
9050
9299
|
"only-artifacts",
|
|
9051
9300
|
"no-config",
|
|
9301
|
+
"no-update-check",
|
|
9052
9302
|
"format",
|
|
9053
9303
|
"mode",
|
|
9054
9304
|
"help",
|
|
@@ -9066,12 +9316,13 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9066
9316
|
"only-artifacts",
|
|
9067
9317
|
"no-config",
|
|
9068
9318
|
"discovery",
|
|
9319
|
+
"no-update-check",
|
|
9069
9320
|
"format",
|
|
9070
9321
|
"mode",
|
|
9071
9322
|
"help",
|
|
9072
9323
|
"version"
|
|
9073
9324
|
],
|
|
9074
|
-
diff: ["format", "mode", "no-config", "help", "version"],
|
|
9325
|
+
diff: ["format", "mode", "no-config", "no-update-check", "help", "version"],
|
|
9075
9326
|
describe: ["format", "mode", "help", "version"],
|
|
9076
9327
|
init: [
|
|
9077
9328
|
"cwd",
|
|
@@ -9086,6 +9337,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9086
9337
|
"yes",
|
|
9087
9338
|
"force",
|
|
9088
9339
|
"dry-run",
|
|
9340
|
+
"no-update-check",
|
|
9089
9341
|
"format",
|
|
9090
9342
|
"mode",
|
|
9091
9343
|
"help",
|
|
@@ -9109,6 +9361,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9109
9361
|
"force",
|
|
9110
9362
|
"no-install",
|
|
9111
9363
|
"dry-run",
|
|
9364
|
+
"no-update-check",
|
|
9112
9365
|
"format",
|
|
9113
9366
|
"mode",
|
|
9114
9367
|
"help",
|
|
@@ -9541,6 +9794,13 @@ function buildAgentContract() {
|
|
|
9541
9794
|
default: false,
|
|
9542
9795
|
appliesTo: optionAppliesTo("no-install"),
|
|
9543
9796
|
summary: "Skip installing the dependency before generating: `setup`, or `generate --autopilot` (CI, offline, or a lockfile you do not want a package manager to touch)."
|
|
9797
|
+
},
|
|
9798
|
+
{
|
|
9799
|
+
flag: "--no-update-check",
|
|
9800
|
+
type: "boolean",
|
|
9801
|
+
default: false,
|
|
9802
|
+
appliesTo: optionAppliesTo("no-update-check"),
|
|
9803
|
+
summary: "Skip the once-a-day check for a newer published version. The check is already skipped when stdout is not a terminal, in CI, in a JSON invocation, and in `mcp`, which makes no network requests."
|
|
9544
9804
|
}
|
|
9545
9805
|
],
|
|
9546
9806
|
presets: PRESETS.map((preset) => ({
|
|
@@ -9828,17 +10088,17 @@ var LEGACY_AGENTS_MARKER = "<!-- codebase-snapshot:skill:start -->";
|
|
|
9828
10088
|
function targetPath(cwd, target) {
|
|
9829
10089
|
switch (target) {
|
|
9830
10090
|
case "claude":
|
|
9831
|
-
return
|
|
10091
|
+
return path13__namespace.join(cwd, ".claude", "skills", SKILL_NAME, "SKILL.md");
|
|
9832
10092
|
case "cursor":
|
|
9833
|
-
return
|
|
10093
|
+
return path13__namespace.join(cwd, ".cursor", "rules", `${SKILL_NAME}.mdc`);
|
|
9834
10094
|
}
|
|
9835
10095
|
}
|
|
9836
10096
|
function assertWritableInsideRepository(cwd, filePath) {
|
|
9837
|
-
const root =
|
|
9838
|
-
const shown =
|
|
10097
|
+
const root = fs12__namespace.realpathSync(cwd);
|
|
10098
|
+
const shown = path13__namespace.relative(root, filePath) || filePath;
|
|
9839
10099
|
let stat = null;
|
|
9840
10100
|
try {
|
|
9841
|
-
stat =
|
|
10101
|
+
stat = fs12__namespace.lstatSync(filePath);
|
|
9842
10102
|
} catch {
|
|
9843
10103
|
stat = null;
|
|
9844
10104
|
}
|
|
@@ -9854,32 +10114,32 @@ function assertWritableInsideRepository(cwd, filePath) {
|
|
|
9854
10114
|
}
|
|
9855
10115
|
let existing = filePath;
|
|
9856
10116
|
const missing = [];
|
|
9857
|
-
while (!
|
|
9858
|
-
missing.unshift(
|
|
9859
|
-
const parent =
|
|
10117
|
+
while (!fs12__namespace.existsSync(existing)) {
|
|
10118
|
+
missing.unshift(path13__namespace.basename(existing));
|
|
10119
|
+
const parent = path13__namespace.dirname(existing);
|
|
9860
10120
|
if (parent === existing) break;
|
|
9861
10121
|
existing = parent;
|
|
9862
10122
|
}
|
|
9863
|
-
const realAncestor =
|
|
9864
|
-
const resolved = missing.length === 0 ? realAncestor :
|
|
9865
|
-
if (resolved !== root && !resolved.startsWith(`${root}${
|
|
10123
|
+
const realAncestor = fs12__namespace.realpathSync(existing);
|
|
10124
|
+
const resolved = missing.length === 0 ? realAncestor : path13__namespace.join(realAncestor, ...missing);
|
|
10125
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path13__namespace.sep}`)) {
|
|
9866
10126
|
throw new Error(
|
|
9867
10127
|
`${REFUSED}: ${shown} resolves outside the repository (${resolved}). Move it back inside ${root}, or remove the link, and run again.`
|
|
9868
10128
|
);
|
|
9869
10129
|
}
|
|
9870
10130
|
}
|
|
9871
10131
|
function writeIfChanged(target, filePath, content) {
|
|
9872
|
-
const existing =
|
|
10132
|
+
const existing = fs12__namespace.existsSync(filePath) ? fs12__namespace.readFileSync(filePath, "utf8") : null;
|
|
9873
10133
|
if (existing === content) return { target, path: filePath, action: "unchanged" };
|
|
9874
|
-
|
|
9875
|
-
|
|
10134
|
+
fs12__namespace.mkdirSync(path13__namespace.dirname(filePath), { recursive: true });
|
|
10135
|
+
fs12__namespace.writeFileSync(filePath, content, "utf8");
|
|
9876
10136
|
return { target, path: filePath, action: existing === null ? "created" : "updated" };
|
|
9877
10137
|
}
|
|
9878
10138
|
function legacyAgentsNote(cwd) {
|
|
9879
|
-
const filePath =
|
|
10139
|
+
const filePath = path13__namespace.join(cwd, "AGENTS.md");
|
|
9880
10140
|
try {
|
|
9881
|
-
if (!
|
|
9882
|
-
if (!
|
|
10141
|
+
if (!fs12__namespace.existsSync(filePath)) return null;
|
|
10142
|
+
if (!fs12__namespace.readFileSync(filePath, "utf8").includes(LEGACY_AGENTS_MARKER)) return null;
|
|
9883
10143
|
} catch {
|
|
9884
10144
|
return null;
|
|
9885
10145
|
}
|
|
@@ -9891,9 +10151,9 @@ function installSkill(cwd, target = "all") {
|
|
|
9891
10151
|
const notes = [];
|
|
9892
10152
|
const wanted = target === "all" ? ["claude", "cursor"] : [target];
|
|
9893
10153
|
for (const item of wanted) assertWritableInsideRepository(cwd, targetPath(cwd, item));
|
|
9894
|
-
const createsSomething = wanted.some((item) => !
|
|
10154
|
+
const createsSomething = wanted.some((item) => !fs12__namespace.existsSync(targetPath(cwd, item)));
|
|
9895
10155
|
if (createsSomething) {
|
|
9896
|
-
assertWritableInsideRepository(cwd,
|
|
10156
|
+
assertWritableInsideRepository(cwd, path13__namespace.join(cwd, ".gitignore"));
|
|
9897
10157
|
}
|
|
9898
10158
|
for (const item of wanted) {
|
|
9899
10159
|
written.push(writeIfChanged(item, targetPath(cwd, item), skill));
|
|
@@ -10028,52 +10288,52 @@ function validateArguments(schema, value) {
|
|
|
10028
10288
|
}
|
|
10029
10289
|
return problems;
|
|
10030
10290
|
}
|
|
10031
|
-
function checkValue(
|
|
10291
|
+
function checkValue(path19, schema, value) {
|
|
10032
10292
|
if (schema.enum && !schema.enum.includes(value)) {
|
|
10033
|
-
return [`"${
|
|
10293
|
+
return [`"${path19}" must be one of: ${schema.enum.join(", ")}`];
|
|
10034
10294
|
}
|
|
10035
10295
|
switch (schema.type) {
|
|
10036
10296
|
case "string": {
|
|
10037
|
-
if (typeof value !== "string") return [`"${
|
|
10297
|
+
if (typeof value !== "string") return [`"${path19}" must be a string`];
|
|
10038
10298
|
const problems = [];
|
|
10039
10299
|
if (schema.minLength !== void 0 && value.length < schema.minLength) {
|
|
10040
|
-
problems.push(`"${
|
|
10300
|
+
problems.push(`"${path19}" must be at least ${schema.minLength} character(s)`);
|
|
10041
10301
|
}
|
|
10042
10302
|
if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
|
|
10043
|
-
problems.push(`"${
|
|
10303
|
+
problems.push(`"${path19}" must be at most ${schema.maxLength} character(s)`);
|
|
10044
10304
|
}
|
|
10045
10305
|
return problems;
|
|
10046
10306
|
}
|
|
10047
10307
|
case "number":
|
|
10048
10308
|
case "integer": {
|
|
10049
10309
|
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
10050
|
-
return [`"${
|
|
10310
|
+
return [`"${path19}" must be a number`];
|
|
10051
10311
|
}
|
|
10052
10312
|
if (schema.type === "integer" && !Number.isInteger(value)) {
|
|
10053
|
-
return [`"${
|
|
10313
|
+
return [`"${path19}" must be an integer`];
|
|
10054
10314
|
}
|
|
10055
10315
|
const problems = [];
|
|
10056
10316
|
if (schema.minimum !== void 0 && value < schema.minimum) {
|
|
10057
|
-
problems.push(`"${
|
|
10317
|
+
problems.push(`"${path19}" must be >= ${schema.minimum}`);
|
|
10058
10318
|
}
|
|
10059
10319
|
if (schema.maximum !== void 0 && value > schema.maximum) {
|
|
10060
|
-
problems.push(`"${
|
|
10320
|
+
problems.push(`"${path19}" must be <= ${schema.maximum}`);
|
|
10061
10321
|
}
|
|
10062
10322
|
return problems;
|
|
10063
10323
|
}
|
|
10064
10324
|
case "boolean":
|
|
10065
|
-
return typeof value === "boolean" ? [] : [`"${
|
|
10325
|
+
return typeof value === "boolean" ? [] : [`"${path19}" must be a boolean`];
|
|
10066
10326
|
case "array": {
|
|
10067
|
-
if (!Array.isArray(value)) return [`"${
|
|
10327
|
+
if (!Array.isArray(value)) return [`"${path19}" must be an array`];
|
|
10068
10328
|
if (!schema.items) return [];
|
|
10069
10329
|
const problems = [];
|
|
10070
10330
|
value.forEach((item, index) => {
|
|
10071
|
-
problems.push(...checkValue(`${
|
|
10331
|
+
problems.push(...checkValue(`${path19}[${index}]`, schema.items, item));
|
|
10072
10332
|
});
|
|
10073
10333
|
return problems;
|
|
10074
10334
|
}
|
|
10075
10335
|
case "object":
|
|
10076
|
-
return isJsonObject(value) ? [] : [`"${
|
|
10336
|
+
return isJsonObject(value) ? [] : [`"${path19}" must be an object`];
|
|
10077
10337
|
default:
|
|
10078
10338
|
return [];
|
|
10079
10339
|
}
|
|
@@ -10087,6 +10347,18 @@ function applyDefaults(schema, value) {
|
|
|
10087
10347
|
}
|
|
10088
10348
|
return out;
|
|
10089
10349
|
}
|
|
10350
|
+
function coerceNumericStrings(schema, value) {
|
|
10351
|
+
const out = { ...value };
|
|
10352
|
+
for (const [key, propertySchema] of Object.entries(schema.properties)) {
|
|
10353
|
+
const raw = out[key];
|
|
10354
|
+
if (typeof raw !== "string") continue;
|
|
10355
|
+
if (propertySchema.type !== "number" && propertySchema.type !== "integer") continue;
|
|
10356
|
+
if (raw.trim().length === 0) continue;
|
|
10357
|
+
const parsed = Number(raw);
|
|
10358
|
+
if (Number.isFinite(parsed)) out[key] = parsed;
|
|
10359
|
+
}
|
|
10360
|
+
return out;
|
|
10361
|
+
}
|
|
10090
10362
|
|
|
10091
10363
|
// src/mcp/server.ts
|
|
10092
10364
|
function capabilities() {
|
|
@@ -10175,7 +10447,8 @@ function createMcpServer(options) {
|
|
|
10175
10447
|
if (!isJsonObject(rawArguments)) {
|
|
10176
10448
|
return errorResponse(id, ERROR_CODES.invalidParams, '"arguments" must be a JSON object.');
|
|
10177
10449
|
}
|
|
10178
|
-
const
|
|
10450
|
+
const supplied = coerceNumericStrings(tool.inputSchema, rawArguments);
|
|
10451
|
+
const problems = validateArguments(tool.inputSchema, supplied);
|
|
10179
10452
|
if (problems.length > 0) {
|
|
10180
10453
|
return ok(
|
|
10181
10454
|
id,
|
|
@@ -10187,7 +10460,7 @@ function createMcpServer(options) {
|
|
|
10187
10460
|
modern
|
|
10188
10461
|
);
|
|
10189
10462
|
}
|
|
10190
|
-
const args = applyDefaults(tool.inputSchema,
|
|
10463
|
+
const args = applyDefaults(tool.inputSchema, supplied);
|
|
10191
10464
|
let outcome;
|
|
10192
10465
|
try {
|
|
10193
10466
|
outcome = await tool.handler(args, options.context);
|
|
@@ -10385,7 +10658,7 @@ async function workspaceFor(context) {
|
|
|
10385
10658
|
}
|
|
10386
10659
|
function readFileIfPresent(file) {
|
|
10387
10660
|
try {
|
|
10388
|
-
return
|
|
10661
|
+
return fs12__namespace.readFileSync(file, "utf8");
|
|
10389
10662
|
} catch {
|
|
10390
10663
|
return null;
|
|
10391
10664
|
}
|
|
@@ -10464,7 +10737,7 @@ function buildResourceProvider() {
|
|
|
10464
10737
|
const report = REPORT_URIS.get(uri);
|
|
10465
10738
|
if (report) {
|
|
10466
10739
|
const text2 = readFileIfPresent(
|
|
10467
|
-
|
|
10740
|
+
path13__namespace.resolve(workspace.root, workspace.config.outDir, "reports", report.file)
|
|
10468
10741
|
);
|
|
10469
10742
|
if (text2 === null) return null;
|
|
10470
10743
|
return { uri, mimeType: "text/markdown", text: capUtf8(text2, MAX_RESOURCE_BYTES).text };
|
|
@@ -10483,7 +10756,7 @@ function buildResourceProvider() {
|
|
|
10483
10756
|
const part = read.manifest.parts.find((candidate) => candidate.index === index);
|
|
10484
10757
|
if (!part) return null;
|
|
10485
10758
|
const text2 = readFileIfPresent(
|
|
10486
|
-
|
|
10759
|
+
path13__namespace.resolve(workspace.root, workspace.config.outDir, "parts", part.filename)
|
|
10487
10760
|
);
|
|
10488
10761
|
if (text2 === null) return null;
|
|
10489
10762
|
return { uri, mimeType: "text/markdown", text: capUtf8(text2, MAX_RESOURCE_BYTES).text };
|
|
@@ -10721,6 +10994,7 @@ var CLI_OPTIONS = {
|
|
|
10721
10994
|
install: { type: "boolean" },
|
|
10722
10995
|
"no-install": { type: "boolean" },
|
|
10723
10996
|
target: { type: "string" },
|
|
10997
|
+
"no-update-check": { type: "boolean" },
|
|
10724
10998
|
help: { type: "boolean", short: "h" },
|
|
10725
10999
|
version: { type: "boolean", short: "v" }
|
|
10726
11000
|
};
|
|
@@ -10795,6 +11069,8 @@ Options:
|
|
|
10795
11069
|
--install Write the skill into the repository instead of printing
|
|
10796
11070
|
--target <name> claude | cursor | all (default: all)
|
|
10797
11071
|
|
|
11072
|
+
--no-update-check Skip the daily check for a newer published version
|
|
11073
|
+
|
|
10798
11074
|
-h, --help Display this help message
|
|
10799
11075
|
-v, --version Display version
|
|
10800
11076
|
|
|
@@ -10871,10 +11147,10 @@ function parseCliArgs(argv) {
|
|
|
10871
11147
|
}
|
|
10872
11148
|
if (values.cwd !== void 0) {
|
|
10873
11149
|
const target = String(values.cwd);
|
|
10874
|
-
if (!
|
|
11150
|
+
if (!fs12__namespace.existsSync(target)) {
|
|
10875
11151
|
throw new UsageError(`--cwd directory does not exist: ${target}`);
|
|
10876
11152
|
}
|
|
10877
|
-
if (!
|
|
11153
|
+
if (!fs12__namespace.statSync(target).isDirectory()) {
|
|
10878
11154
|
throw new UsageError(`--cwd is not a directory: ${target}`);
|
|
10879
11155
|
}
|
|
10880
11156
|
}
|
|
@@ -11020,7 +11296,7 @@ function parseCliArgs(argv) {
|
|
|
11020
11296
|
install: values.install === true,
|
|
11021
11297
|
noInstall: values["no-install"] === true,
|
|
11022
11298
|
target: values.target === void 0 ? void 0 : String(values.target),
|
|
11023
|
-
cwd: values.cwd === void 0 ? process.cwd() :
|
|
11299
|
+
cwd: values.cwd === void 0 ? process.cwd() : path13__namespace.resolve(String(values.cwd)),
|
|
11024
11300
|
outDir: values["out-dir"] === void 0 ? void 0 : String(values["out-dir"]),
|
|
11025
11301
|
includeMonolith: values["include-monolith"] === true || onlyNamesMonolith === true ? true : void 0,
|
|
11026
11302
|
includeSensitiveFiles: values["include-sensitive-files"] === true ? true : void 0,
|
|
@@ -11077,24 +11353,24 @@ function splitList(value) {
|
|
|
11077
11353
|
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
11078
11354
|
}
|
|
11079
11355
|
function displayOutPath(cwd, outDir, ...segments) {
|
|
11080
|
-
const absolute =
|
|
11081
|
-
const relative11 =
|
|
11082
|
-
if (relative11 && !relative11.startsWith("..") && !
|
|
11356
|
+
const absolute = path13__namespace.resolve(cwd, outDir, ...segments);
|
|
11357
|
+
const relative11 = path13__namespace.relative(cwd, absolute);
|
|
11358
|
+
if (relative11 && !relative11.startsWith("..") && !path13__namespace.isAbsolute(relative11)) return relative11;
|
|
11083
11359
|
return absolute;
|
|
11084
11360
|
}
|
|
11085
11361
|
function nextStepHint(cwd, scriptsAddedNow) {
|
|
11086
11362
|
let hasScript = scriptsAddedNow;
|
|
11087
11363
|
if (!hasScript) {
|
|
11088
11364
|
try {
|
|
11089
|
-
const parsed = JSON.parse(
|
|
11365
|
+
const parsed = JSON.parse(fs12__namespace.readFileSync(path13__namespace.join(cwd, "package.json"), "utf8"));
|
|
11090
11366
|
hasScript = typeof parsed.scripts?.snapshot === "string";
|
|
11091
11367
|
} catch {
|
|
11092
11368
|
hasScript = false;
|
|
11093
11369
|
}
|
|
11094
11370
|
}
|
|
11095
11371
|
if (!hasScript) return `npx ${GENERATOR_NAME} generate`;
|
|
11096
|
-
const bin =
|
|
11097
|
-
const installed =
|
|
11372
|
+
const bin = path13__namespace.join(cwd, "node_modules", ".bin", "codebase-snapshot");
|
|
11373
|
+
const installed = fs12__namespace.existsSync(bin) || fs12__namespace.existsSync(`${bin}.cmd`);
|
|
11098
11374
|
return installed ? "npm run snapshot" : "npm install && npm run snapshot";
|
|
11099
11375
|
}
|
|
11100
11376
|
function presetSummary(init) {
|
|
@@ -11124,7 +11400,7 @@ async function runInitCommand(invocation) {
|
|
|
11124
11400
|
info(result.configText);
|
|
11125
11401
|
return 0;
|
|
11126
11402
|
}
|
|
11127
|
-
info(`\u2705 Created ${
|
|
11403
|
+
info(`\u2705 Created ${path13__namespace.basename(result.configPath)} (${presetSummary(result)})`);
|
|
11128
11404
|
if (result.scripts.length > 0) info(` Added npm scripts: ${result.scripts.join(", ")}`);
|
|
11129
11405
|
if (result.dependency.added && result.dependency.range !== null) {
|
|
11130
11406
|
info(` Added devDependency: ${result.dependency.name} ${result.dependency.range}`);
|
|
@@ -11144,7 +11420,7 @@ async function runInitCommand(invocation) {
|
|
|
11144
11420
|
}
|
|
11145
11421
|
}
|
|
11146
11422
|
function detectPackageManager(cwd) {
|
|
11147
|
-
const has = (name) =>
|
|
11423
|
+
const has = (name) => fs12__namespace.existsSync(path13__namespace.join(cwd, name));
|
|
11148
11424
|
if (has("bun.lockb") || has("bun.lock")) return { name: "bun", command: "bun", args: ["install"] };
|
|
11149
11425
|
if (has("pnpm-lock.yaml")) return { name: "pnpm", command: "pnpm", args: ["install"] };
|
|
11150
11426
|
if (has("yarn.lock")) return { name: "yarn", command: "yarn", args: ["install"] };
|
|
@@ -11163,14 +11439,13 @@ function installDependencies(cwd) {
|
|
|
11163
11439
|
const manager = detectPackageManager(cwd);
|
|
11164
11440
|
const command = `${manager.command} ${manager.args.join(" ")}`;
|
|
11165
11441
|
const started = performance.now();
|
|
11166
|
-
const
|
|
11442
|
+
const spawnOptions = {
|
|
11167
11443
|
cwd,
|
|
11168
11444
|
encoding: "utf8",
|
|
11169
|
-
// npm, pnpm and yarn ship as `.cmd` shims on Windows, which spawnSync cannot exec directly.
|
|
11170
|
-
shell: process.platform === "win32",
|
|
11171
11445
|
timeout: INSTALL_TIMEOUT_MS,
|
|
11172
11446
|
env: cleanInstallEnv()
|
|
11173
|
-
}
|
|
11447
|
+
};
|
|
11448
|
+
const result = process.platform === "win32" ? childProcess.spawnSync(command, { ...spawnOptions, shell: true }) : childProcess.spawnSync(manager.command, manager.args, spawnOptions);
|
|
11174
11449
|
const seconds = `${((performance.now() - started) / 1e3).toFixed(1)}s`;
|
|
11175
11450
|
if (result.error) {
|
|
11176
11451
|
return { manager: manager.name, command, ok: false, detail: `${result.error.message} (${seconds})` };
|
|
@@ -11234,7 +11509,7 @@ async function runSetupCommand(invocation, options = {}) {
|
|
|
11234
11509
|
}
|
|
11235
11510
|
info("\n\u{1F9EA} Dry run \u2014 setup would:");
|
|
11236
11511
|
info(
|
|
11237
|
-
` 1. ${init.reused ? `keep ${
|
|
11512
|
+
` 1. ${init.reused ? `keep ${path13__namespace.basename(init.configPath)}` : `write ${path13__namespace.basename(init.configPath)} (preset: ${init.preset})`}`
|
|
11238
11513
|
);
|
|
11239
11514
|
info(" 2. add the npm scripts, the devDependency and the .gitignore entries");
|
|
11240
11515
|
if (manager !== null) info(` 3. install with ${manager}`);
|
|
@@ -11246,9 +11521,9 @@ async function runSetupCommand(invocation, options = {}) {
|
|
|
11246
11521
|
if (invocation.format !== "json") {
|
|
11247
11522
|
if (!interactive) info(`\u{1F680} Setup for: ${invocation.cwd}`);
|
|
11248
11523
|
if (init.reused) {
|
|
11249
|
-
info(`\u267B Keeping ${
|
|
11524
|
+
info(`\u267B Keeping ${path13__namespace.basename(init.configPath)} (${presetSummary(init)})`);
|
|
11250
11525
|
} else {
|
|
11251
|
-
info(`\u2705 Created ${
|
|
11526
|
+
info(`\u2705 Created ${path13__namespace.basename(init.configPath)} (${presetSummary(init)})`);
|
|
11252
11527
|
}
|
|
11253
11528
|
if (init.scripts.length > 0) info(` Added npm scripts: ${init.scripts.join(", ")}`);
|
|
11254
11529
|
if (init.dependency.added && init.dependency.range !== null) {
|
|
@@ -11356,7 +11631,7 @@ function runSkillCommand(invocation) {
|
|
|
11356
11631
|
}
|
|
11357
11632
|
info(`\u2705 Agent skill installed (${SKILL_NAME}):`);
|
|
11358
11633
|
for (const item of result.written) {
|
|
11359
|
-
const shown =
|
|
11634
|
+
const shown = path13__namespace.relative(invocation.cwd, item.path) || item.path;
|
|
11360
11635
|
info(` - ${item.action.padEnd(9)} ${shown}`);
|
|
11361
11636
|
}
|
|
11362
11637
|
if (result.gitignored.length > 0) {
|
|
@@ -11420,6 +11695,17 @@ function requestsJsonFormat(argv) {
|
|
|
11420
11695
|
return format === "json";
|
|
11421
11696
|
}
|
|
11422
11697
|
async function main(argv = process.argv.slice(2)) {
|
|
11698
|
+
const pending = process.stdout.isTTY === true && shouldCheck(argv, process.env) ? checkForUpdate({ current: GENERATOR_VERSION, cacheFile: cacheFilePath() }) : null;
|
|
11699
|
+
const code = await runCommand(argv);
|
|
11700
|
+
if (pending) {
|
|
11701
|
+
const notice = await pending;
|
|
11702
|
+
if (notice) process.stderr.write(`
|
|
11703
|
+
${formatUpdateNotice(notice)}
|
|
11704
|
+
`);
|
|
11705
|
+
}
|
|
11706
|
+
return code;
|
|
11707
|
+
}
|
|
11708
|
+
async function runCommand(argv) {
|
|
11423
11709
|
let invocation;
|
|
11424
11710
|
try {
|
|
11425
11711
|
invocation = parseCliArgs(argv);
|
|
@@ -11452,7 +11738,7 @@ ${USAGE}
|
|
|
11452
11738
|
return runSkillCommand(invocation);
|
|
11453
11739
|
}
|
|
11454
11740
|
if (invocation.command === "mcp") {
|
|
11455
|
-
return await runStdioServer({ cwd:
|
|
11741
|
+
return await runStdioServer({ cwd: path13__namespace.resolve(invocation.cwd) });
|
|
11456
11742
|
}
|
|
11457
11743
|
if (invocation.command === "setup") {
|
|
11458
11744
|
return runSetupCommand(invocation);
|
|
@@ -11469,7 +11755,7 @@ ${USAGE}
|
|
|
11469
11755
|
warn("\u274C The config file could not be read. Fix it, or delete it to use the defaults.");
|
|
11470
11756
|
return 1;
|
|
11471
11757
|
}
|
|
11472
|
-
if (loaded.file) info(`\u2699 Using config ${
|
|
11758
|
+
if (loaded.file) info(`\u2699 Using config ${path13__namespace.relative(process.cwd(), loaded.file) || loaded.file}`);
|
|
11473
11759
|
const resolved = resolveConfig(
|
|
11474
11760
|
loaded.config,
|
|
11475
11761
|
{
|
|
@@ -11491,10 +11777,10 @@ ${USAGE}
|
|
|
11491
11777
|
if (invocation.command === "validate") {
|
|
11492
11778
|
const result = validateSnapshot(resolved);
|
|
11493
11779
|
if (result.valid) {
|
|
11494
|
-
const manifestPath =
|
|
11780
|
+
const manifestPath = path13__namespace.resolve(resolved.cwd, resolved.outDir, "manifest.json");
|
|
11495
11781
|
let manifest;
|
|
11496
11782
|
try {
|
|
11497
|
-
manifest = JSON.parse(
|
|
11783
|
+
manifest = JSON.parse(fs12__namespace.readFileSync(manifestPath, "utf8"));
|
|
11498
11784
|
} catch {
|
|
11499
11785
|
manifest = void 0;
|
|
11500
11786
|
}
|
|
@@ -11507,13 +11793,13 @@ ${USAGE}
|
|
|
11507
11793
|
return result.valid ? 0 : 1;
|
|
11508
11794
|
}
|
|
11509
11795
|
if (invocation.command === "report") {
|
|
11510
|
-
const manifestPath =
|
|
11511
|
-
if (!
|
|
11796
|
+
const manifestPath = path13__namespace.resolve(resolved.cwd, resolved.outDir, "manifest.json");
|
|
11797
|
+
if (!fs12__namespace.existsSync(manifestPath)) {
|
|
11512
11798
|
return fail(invocation.format, `Manifest not found at ${manifestPath}. Run generate first.`);
|
|
11513
11799
|
}
|
|
11514
11800
|
let manifest;
|
|
11515
11801
|
try {
|
|
11516
|
-
manifest = JSON.parse(
|
|
11802
|
+
manifest = JSON.parse(fs12__namespace.readFileSync(manifestPath, "utf8"));
|
|
11517
11803
|
} catch (err) {
|
|
11518
11804
|
return fail(invocation.format, `Could not read ${manifestPath}: ${err.message}`);
|
|
11519
11805
|
}
|
|
@@ -11677,20 +11963,20 @@ function finishWatchRun(state, now) {
|
|
|
11677
11963
|
};
|
|
11678
11964
|
}
|
|
11679
11965
|
function comparablePath(value) {
|
|
11680
|
-
const absolute =
|
|
11966
|
+
const absolute = path13__namespace.resolve(value);
|
|
11681
11967
|
return process.platform === "win32" ? absolute.toLowerCase() : absolute;
|
|
11682
11968
|
}
|
|
11683
11969
|
function isSameOrInside(parent, candidate) {
|
|
11684
|
-
const relative11 =
|
|
11685
|
-
return relative11 === "" || relative11 !== ".." && !relative11.startsWith(`..${
|
|
11970
|
+
const relative11 = path13__namespace.relative(parent, candidate);
|
|
11971
|
+
return relative11 === "" || relative11 !== ".." && !relative11.startsWith(`..${path13__namespace.sep}`) && !path13__namespace.isAbsolute(relative11);
|
|
11686
11972
|
}
|
|
11687
11973
|
function isGeneratedWatchPath(candidate, paths) {
|
|
11688
|
-
const absolute = comparablePath(
|
|
11689
|
-
const outDir = comparablePath(
|
|
11690
|
-
const tmpDir = comparablePath(
|
|
11974
|
+
const absolute = comparablePath(path13__namespace.resolve(paths.cwd, candidate));
|
|
11975
|
+
const outDir = comparablePath(path13__namespace.resolve(paths.cwd, paths.outDir));
|
|
11976
|
+
const tmpDir = comparablePath(path13__namespace.resolve(paths.cwd, paths.tmpDir));
|
|
11691
11977
|
if (isSameOrInside(outDir, absolute) || isSameOrInside(tmpDir, absolute)) return true;
|
|
11692
|
-
const parent =
|
|
11693
|
-
if (parent ===
|
|
11978
|
+
const parent = path13__namespace.dirname(absolute);
|
|
11979
|
+
if (parent === path13__namespace.dirname(outDir) && path13__namespace.basename(absolute).startsWith(`${path13__namespace.basename(outDir)}.backup-`)) {
|
|
11694
11980
|
return true;
|
|
11695
11981
|
}
|
|
11696
11982
|
return absolute.split(/[\\/]+/).some((segment) => VCS_SEGMENTS.has(segment));
|
|
@@ -11707,8 +11993,8 @@ function decideWatchEvent(state, event, paths) {
|
|
|
11707
11993
|
return { state, action: "schedule" };
|
|
11708
11994
|
}
|
|
11709
11995
|
async function runWatchLoop(invocation, resolved) {
|
|
11710
|
-
const outDir =
|
|
11711
|
-
const tmpDir =
|
|
11996
|
+
const outDir = path13__namespace.resolve(resolved.cwd, resolved.outDir);
|
|
11997
|
+
const tmpDir = path13__namespace.resolve(resolved.cwd, resolved.tmpDir);
|
|
11712
11998
|
const paths = { cwd: resolved.cwd, outDir, tmpDir };
|
|
11713
11999
|
let state = initialWatchState();
|
|
11714
12000
|
let timer = null;
|
|
@@ -11773,11 +12059,11 @@ async function runWatchLoop(invocation, resolved) {
|
|
|
11773
12059
|
};
|
|
11774
12060
|
info("\u{1F440} Watching for changes. Press Ctrl+C to stop.");
|
|
11775
12061
|
void regenerate();
|
|
11776
|
-
const watcher =
|
|
12062
|
+
const watcher = fs12__namespace.watch(resolved.cwd, { recursive: true }, (_event, filename) => {
|
|
11777
12063
|
const decision = decideWatchEvent(
|
|
11778
12064
|
state,
|
|
11779
12065
|
{
|
|
11780
|
-
path: filename ?
|
|
12066
|
+
path: filename ? path13__namespace.resolve(resolved.cwd, filename.toString()) : null,
|
|
11781
12067
|
now: performance.now()
|
|
11782
12068
|
},
|
|
11783
12069
|
paths
|
|
@@ -11805,7 +12091,7 @@ async function runWatchLoop(invocation, resolved) {
|
|
|
11805
12091
|
return 0;
|
|
11806
12092
|
}
|
|
11807
12093
|
var entryFile = process.argv[1] ?? "";
|
|
11808
|
-
var entryName =
|
|
12094
|
+
var entryName = path13__namespace.basename(entryFile).toLowerCase();
|
|
11809
12095
|
var invokedDirectly = entryName === "cli.js" || entryName === "cli.cjs";
|
|
11810
12096
|
if (invokedDirectly) {
|
|
11811
12097
|
void main().then(
|