codebase-snapshot 0.9.5 → 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 +46 -0
- package/README.md +4 -1
- package/dist/bin.js +405 -203
- package/dist/{chunk-B336MMNC.js → chunk-3KUL3QRH.js} +379 -222
- package/dist/{chunk-4AHHSNGG.js → chunk-ZKZOGGM3.js} +33 -7
- package/dist/cli.cjs +508 -310
- package/dist/cli.d.cts +7 -1
- package/dist/cli.d.ts +7 -1
- package/dist/cli.js +16 -2
- package/dist/index.cjs +384 -215
- 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 +19 -2
- package/docs/mcp.md +3 -3
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { spawnSync } from "child_process";
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
5
|
+
import * as fs17 from "fs";
|
|
6
|
+
import * as path18 from "path";
|
|
7
7
|
import { parseArgs } from "util";
|
|
8
8
|
|
|
9
9
|
// src/diff.ts
|
|
@@ -4346,7 +4346,7 @@ function gitignorePath(cwd, filePath) {
|
|
|
4346
4346
|
|
|
4347
4347
|
// src/version.ts
|
|
4348
4348
|
var GENERATOR_NAME = "codebase-snapshot";
|
|
4349
|
-
var GENERATOR_VERSION = "0.9.
|
|
4349
|
+
var GENERATOR_VERSION = "0.9.6";
|
|
4350
4350
|
var LEGACY_GENERATOR_NAMES = ["@ankurhalder/codebase-snapshot"];
|
|
4351
4351
|
function isOurGeneratorName(name) {
|
|
4352
4352
|
if (typeof name !== "string") return false;
|
|
@@ -5289,9 +5289,9 @@ function hasPriorSnapshot(cwd, outDir) {
|
|
|
5289
5289
|
// src/index.ts
|
|
5290
5290
|
import * as crypto3 from "crypto";
|
|
5291
5291
|
import { AsyncLocalStorage } from "async_hooks";
|
|
5292
|
-
import * as
|
|
5293
|
-
import * as
|
|
5294
|
-
import * as
|
|
5292
|
+
import * as fs12 from "fs";
|
|
5293
|
+
import * as os2 from "os";
|
|
5294
|
+
import * as path13 from "path";
|
|
5295
5295
|
|
|
5296
5296
|
// src/ast/profiles/shared.ts
|
|
5297
5297
|
var MAX_SUMMARY_CHARS = 1e6;
|
|
@@ -5515,9 +5515,9 @@ var JAVA_METHOD = /^\s+(?:public|private|protected)\s+(?:static\s+)?(?:final\s+)
|
|
|
5515
5515
|
var jvmProfile = {
|
|
5516
5516
|
id: "jvm",
|
|
5517
5517
|
extensions: [".java", ".kt", ".kts", ".scala"],
|
|
5518
|
-
summarize(
|
|
5518
|
+
summarize(path19, content) {
|
|
5519
5519
|
const summary = emptySummary();
|
|
5520
|
-
const lower =
|
|
5520
|
+
const lower = path19.toLowerCase();
|
|
5521
5521
|
const isJava = lower.endsWith(".java");
|
|
5522
5522
|
const isKotlin = lower.endsWith(".kt") || lower.endsWith(".kts");
|
|
5523
5523
|
eachLine(content, (line) => {
|
|
@@ -5973,16 +5973,16 @@ function summarizeTypeScriptSource(relativePath, content) {
|
|
|
5973
5973
|
// src/ast/profiles/sfc.ts
|
|
5974
5974
|
var SCRIPT_BLOCK = /<script[^>]*>([\s\S]*?)<\/script>/gi;
|
|
5975
5975
|
var ASTRO_FRONTMATTER = /^\uFEFF?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?=\r?\n|$)/;
|
|
5976
|
-
function componentName(
|
|
5977
|
-
const base =
|
|
5976
|
+
function componentName(path19) {
|
|
5977
|
+
const base = path19.split("/").pop() ?? path19;
|
|
5978
5978
|
return base.replace(/\.[^.]+$/, "");
|
|
5979
5979
|
}
|
|
5980
5980
|
var sfcProfile = {
|
|
5981
5981
|
id: "sfc",
|
|
5982
5982
|
extensions: [".vue", ".svelte", ".astro"],
|
|
5983
|
-
summarize(
|
|
5983
|
+
summarize(path19, content) {
|
|
5984
5984
|
let script = "";
|
|
5985
|
-
if (
|
|
5985
|
+
if (path19.toLowerCase().endsWith(".astro")) {
|
|
5986
5986
|
const frontmatter = ASTRO_FRONTMATTER.exec(content);
|
|
5987
5987
|
if (frontmatter) script += `${frontmatter[1]}
|
|
5988
5988
|
`;
|
|
@@ -5991,7 +5991,7 @@ var sfcProfile = {
|
|
|
5991
5991
|
script += `${match[1]}
|
|
5992
5992
|
`;
|
|
5993
5993
|
}
|
|
5994
|
-
const name = componentName(
|
|
5994
|
+
const name = componentName(path19);
|
|
5995
5995
|
if (!script.trim()) {
|
|
5996
5996
|
const summary2 = emptySummary();
|
|
5997
5997
|
if (name) {
|
|
@@ -6025,15 +6025,15 @@ for (const profile of LANGUAGE_PROFILES) {
|
|
|
6025
6025
|
BY_EXTENSION.set(extension.toLowerCase(), profile);
|
|
6026
6026
|
}
|
|
6027
6027
|
}
|
|
6028
|
-
function profileForPath(
|
|
6029
|
-
const lower =
|
|
6028
|
+
function profileForPath(path19) {
|
|
6029
|
+
const lower = path19.toLowerCase();
|
|
6030
6030
|
const dot = lower.lastIndexOf(".");
|
|
6031
6031
|
if (dot === -1) return null;
|
|
6032
6032
|
return BY_EXTENSION.get(lower.slice(dot)) ?? null;
|
|
6033
6033
|
}
|
|
6034
|
-
function summarizeWithProfile(
|
|
6035
|
-
const profile = profileForPath(
|
|
6036
|
-
return profile ? profile.summarize(
|
|
6034
|
+
function summarizeWithProfile(path19, content) {
|
|
6035
|
+
const profile = profileForPath(path19);
|
|
6036
|
+
return profile ? profile.summarize(path19, content) : null;
|
|
6037
6037
|
}
|
|
6038
6038
|
|
|
6039
6039
|
// src/ast/structured.ts
|
|
@@ -6882,6 +6882,168 @@ function generateProjectTree(filePaths) {
|
|
|
6882
6882
|
return ["# Project Tree", "", `${fence}text`, ...lines, fence, ""].join("\n");
|
|
6883
6883
|
}
|
|
6884
6884
|
|
|
6885
|
+
// src/update-check.ts
|
|
6886
|
+
import * as fs11 from "fs";
|
|
6887
|
+
import * as https from "https";
|
|
6888
|
+
import * as os from "os";
|
|
6889
|
+
import * as path12 from "path";
|
|
6890
|
+
var PACKAGE_LATEST_URL = "https://registry.npmjs.org/codebase-snapshot/latest";
|
|
6891
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
6892
|
+
var FAILURE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
6893
|
+
var REQUEST_TIMEOUT_MS = 1200;
|
|
6894
|
+
function versionParts(value) {
|
|
6895
|
+
const core = value.trim().replace(/^v/i, "").split("-")[0];
|
|
6896
|
+
return core.split(".").map((part) => {
|
|
6897
|
+
const parsed = Number(part);
|
|
6898
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
6899
|
+
});
|
|
6900
|
+
}
|
|
6901
|
+
function isNewer(candidate, current) {
|
|
6902
|
+
const left = versionParts(candidate);
|
|
6903
|
+
const right = versionParts(current);
|
|
6904
|
+
const length = Math.max(left.length, right.length);
|
|
6905
|
+
for (let index = 0; index < length; index += 1) {
|
|
6906
|
+
const a = left[index] ?? 0;
|
|
6907
|
+
const b = right[index] ?? 0;
|
|
6908
|
+
if (a !== b) return a > b;
|
|
6909
|
+
}
|
|
6910
|
+
return false;
|
|
6911
|
+
}
|
|
6912
|
+
function cacheDirectory(env = process.env, platform = process.platform) {
|
|
6913
|
+
if (platform === "win32") {
|
|
6914
|
+
const base2 = env.LOCALAPPDATA ?? path12.join(os.homedir(), "AppData", "Local");
|
|
6915
|
+
return path12.join(base2, "codebase-snapshot");
|
|
6916
|
+
}
|
|
6917
|
+
if (platform === "darwin") {
|
|
6918
|
+
return path12.join(os.homedir(), "Library", "Caches", "codebase-snapshot");
|
|
6919
|
+
}
|
|
6920
|
+
const base = env.XDG_CACHE_HOME ?? path12.join(os.homedir(), ".cache");
|
|
6921
|
+
return path12.join(base, "codebase-snapshot");
|
|
6922
|
+
}
|
|
6923
|
+
function cacheFilePath(env = process.env) {
|
|
6924
|
+
return path12.join(cacheDirectory(env), "update-check.json");
|
|
6925
|
+
}
|
|
6926
|
+
function shouldCheck(argv, env) {
|
|
6927
|
+
const disabled = ["1", "true", "yes"].includes(
|
|
6928
|
+
String(env.CODEBASE_SNAPSHOT_NO_UPDATE_CHECK ?? "").toLowerCase()
|
|
6929
|
+
);
|
|
6930
|
+
if (disabled) return false;
|
|
6931
|
+
if (env.CI !== void 0 && env.CI !== "" && env.CI !== "false" && env.CI !== "0") return false;
|
|
6932
|
+
const args = argv.map((argument) => argument.toLowerCase());
|
|
6933
|
+
if (args.includes("--no-update-check")) return false;
|
|
6934
|
+
for (const skip of ["mcp", "describe", "skill", "--version", "-v", "--help", "-h"]) {
|
|
6935
|
+
if (args.includes(skip)) return false;
|
|
6936
|
+
}
|
|
6937
|
+
if (args.some((argument) => argument.includes("json"))) return false;
|
|
6938
|
+
return true;
|
|
6939
|
+
}
|
|
6940
|
+
function readCache(file) {
|
|
6941
|
+
let raw;
|
|
6942
|
+
try {
|
|
6943
|
+
raw = fs11.readFileSync(file, "utf8");
|
|
6944
|
+
} catch {
|
|
6945
|
+
return null;
|
|
6946
|
+
}
|
|
6947
|
+
try {
|
|
6948
|
+
const parsed = JSON.parse(raw);
|
|
6949
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
6950
|
+
const candidate = parsed;
|
|
6951
|
+
if (typeof candidate.checkedAt !== "number") return null;
|
|
6952
|
+
const latest = typeof candidate.latest === "string" ? candidate.latest : null;
|
|
6953
|
+
return { checkedAt: candidate.checkedAt, latest };
|
|
6954
|
+
} catch {
|
|
6955
|
+
return null;
|
|
6956
|
+
}
|
|
6957
|
+
}
|
|
6958
|
+
function writeCache(file, entry) {
|
|
6959
|
+
try {
|
|
6960
|
+
fs11.mkdirSync(path12.dirname(file), { recursive: true });
|
|
6961
|
+
fs11.writeFileSync(file, `${JSON.stringify(entry)}
|
|
6962
|
+
`, "utf8");
|
|
6963
|
+
} catch {
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
function fetchLatestVersion(url = PACKAGE_LATEST_URL, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
6967
|
+
return new Promise((resolve9) => {
|
|
6968
|
+
let settled = false;
|
|
6969
|
+
const finish = (value) => {
|
|
6970
|
+
if (settled) return;
|
|
6971
|
+
settled = true;
|
|
6972
|
+
resolve9(value);
|
|
6973
|
+
};
|
|
6974
|
+
const request = https.get(
|
|
6975
|
+
url,
|
|
6976
|
+
{
|
|
6977
|
+
headers: {
|
|
6978
|
+
accept: "application/json",
|
|
6979
|
+
"user-agent": "codebase-snapshot (update check)"
|
|
6980
|
+
}
|
|
6981
|
+
},
|
|
6982
|
+
(response) => {
|
|
6983
|
+
if (response.statusCode !== 200) {
|
|
6984
|
+
response.resume();
|
|
6985
|
+
finish(null);
|
|
6986
|
+
return;
|
|
6987
|
+
}
|
|
6988
|
+
let body = "";
|
|
6989
|
+
response.setEncoding("utf8");
|
|
6990
|
+
response.on("data", (chunk) => {
|
|
6991
|
+
body += chunk;
|
|
6992
|
+
if (body.length > 64 * 1024) {
|
|
6993
|
+
request.destroy();
|
|
6994
|
+
finish(null);
|
|
6995
|
+
}
|
|
6996
|
+
});
|
|
6997
|
+
response.on("end", () => {
|
|
6998
|
+
try {
|
|
6999
|
+
const parsed = JSON.parse(body);
|
|
7000
|
+
finish(typeof parsed.version === "string" ? parsed.version : null);
|
|
7001
|
+
} catch {
|
|
7002
|
+
finish(null);
|
|
7003
|
+
}
|
|
7004
|
+
});
|
|
7005
|
+
}
|
|
7006
|
+
);
|
|
7007
|
+
request.on("error", () => finish(null));
|
|
7008
|
+
request.setTimeout(timeoutMs, () => {
|
|
7009
|
+
request.destroy();
|
|
7010
|
+
finish(null);
|
|
7011
|
+
});
|
|
7012
|
+
});
|
|
7013
|
+
}
|
|
7014
|
+
async function checkForUpdate(options) {
|
|
7015
|
+
if (options.enabled === false) return null;
|
|
7016
|
+
const now = options.now ?? (() => Date.now());
|
|
7017
|
+
const fetchLatest = options.fetchLatest ?? fetchLatestVersion;
|
|
7018
|
+
let latest = null;
|
|
7019
|
+
try {
|
|
7020
|
+
const cached = readCache(options.cacheFile);
|
|
7021
|
+
let needsFetch = cached === null;
|
|
7022
|
+
if (cached) {
|
|
7023
|
+
const age = now() - cached.checkedAt;
|
|
7024
|
+
if (cached.latest === null) {
|
|
7025
|
+
needsFetch = age >= FAILURE_INTERVAL_MS;
|
|
7026
|
+
} else {
|
|
7027
|
+
latest = cached.latest;
|
|
7028
|
+
needsFetch = age >= CHECK_INTERVAL_MS;
|
|
7029
|
+
}
|
|
7030
|
+
}
|
|
7031
|
+
if (needsFetch) {
|
|
7032
|
+
const fetched = await fetchLatest(PACKAGE_LATEST_URL, REQUEST_TIMEOUT_MS);
|
|
7033
|
+
writeCache(options.cacheFile, { checkedAt: now(), latest: fetched });
|
|
7034
|
+
latest = fetched;
|
|
7035
|
+
}
|
|
7036
|
+
} catch {
|
|
7037
|
+
return null;
|
|
7038
|
+
}
|
|
7039
|
+
if (!latest) return null;
|
|
7040
|
+
return isNewer(latest, options.current) ? { current: options.current, latest } : null;
|
|
7041
|
+
}
|
|
7042
|
+
function formatUpdateNotice(notice) {
|
|
7043
|
+
return `\u2191 codebase-snapshot ${notice.latest} is available \u2014 you have ${notice.current}.
|
|
7044
|
+
npm install -g codebase-snapshot`;
|
|
7045
|
+
}
|
|
7046
|
+
|
|
6885
7047
|
// src/index.ts
|
|
6886
7048
|
var SCHEMA_VERSION = "3.0.0";
|
|
6887
7049
|
var SUMMARY_MAX_SOURCE_BYTES = 2 * 1024 * 1024;
|
|
@@ -6963,13 +7125,13 @@ function buildImportResolver(files) {
|
|
|
6963
7125
|
const relativePath = file.relativePath;
|
|
6964
7126
|
remember(byPath, relativePath, relativePath);
|
|
6965
7127
|
remember(byPathFolded, relativePath.toLowerCase(), relativePath);
|
|
6966
|
-
const extension =
|
|
7128
|
+
const extension = path13.posix.extname(relativePath);
|
|
6967
7129
|
if (!SOURCE_EXTENSIONS.has(extension)) continue;
|
|
6968
7130
|
const stem = relativePath.slice(0, -extension.length);
|
|
6969
7131
|
remember(byStem, stem, relativePath);
|
|
6970
7132
|
remember(byStemFolded, stem.toLowerCase(), relativePath);
|
|
6971
|
-
if (
|
|
6972
|
-
const directory =
|
|
7133
|
+
if (path13.posix.basename(stem) === "index") {
|
|
7134
|
+
const directory = path13.posix.dirname(stem);
|
|
6973
7135
|
remember(byStem, directory, relativePath);
|
|
6974
7136
|
remember(byStemFolded, directory.toLowerCase(), relativePath);
|
|
6975
7137
|
}
|
|
@@ -6978,8 +7140,8 @@ function buildImportResolver(files) {
|
|
|
6978
7140
|
}
|
|
6979
7141
|
function resolveSpecifier(fromFile, specifier, resolver) {
|
|
6980
7142
|
if (!RELATIVE_SPECIFIER.test(specifier)) return null;
|
|
6981
|
-
const joined =
|
|
6982
|
-
|
|
7143
|
+
const joined = path13.posix.normalize(
|
|
7144
|
+
path13.posix.join(path13.posix.dirname(fromFile), specifier)
|
|
6983
7145
|
);
|
|
6984
7146
|
const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
|
|
6985
7147
|
const direct = exact(joined);
|
|
@@ -7072,11 +7234,11 @@ function verifyInMemory(files, parts, maxPartBytes) {
|
|
|
7072
7234
|
return errors;
|
|
7073
7235
|
}
|
|
7074
7236
|
function resolveSafeOutputDirs(config) {
|
|
7075
|
-
const cwd =
|
|
7076
|
-
const outDir =
|
|
7077
|
-
const tmpDir =
|
|
7078
|
-
const root =
|
|
7079
|
-
const contains = (parent, child) => child === parent || child.startsWith(`${parent}${
|
|
7237
|
+
const cwd = path13.resolve(config.cwd);
|
|
7238
|
+
const outDir = path13.resolve(cwd, config.outDir);
|
|
7239
|
+
const tmpDir = path13.resolve(cwd, config.tmpDir);
|
|
7240
|
+
const root = path13.parse(cwd).root;
|
|
7241
|
+
const contains = (parent, child) => child === parent || child.startsWith(`${parent}${path13.sep}`);
|
|
7080
7242
|
const reject = (reason) => {
|
|
7081
7243
|
throw new Error(
|
|
7082
7244
|
`Refusing to generate: ${reason}. outDir=${outDir} tmpDir=${tmpDir} cwd=${cwd}`
|
|
@@ -7132,14 +7294,14 @@ function listEntries(dir) {
|
|
|
7132
7294
|
const walk = (absolute, prefix) => {
|
|
7133
7295
|
let children;
|
|
7134
7296
|
try {
|
|
7135
|
-
children =
|
|
7297
|
+
children = fs12.readdirSync(absolute, { withFileTypes: true });
|
|
7136
7298
|
} catch {
|
|
7137
7299
|
return;
|
|
7138
7300
|
}
|
|
7139
7301
|
for (const child of children) {
|
|
7140
7302
|
const relative11 = prefix === "" ? child.name : `${prefix}/${child.name}`;
|
|
7141
7303
|
entries.push(relative11);
|
|
7142
|
-
if (child.isDirectory()) walk(
|
|
7304
|
+
if (child.isDirectory()) walk(path13.join(absolute, child.name), relative11);
|
|
7143
7305
|
}
|
|
7144
7306
|
};
|
|
7145
7307
|
walk(dir, "");
|
|
@@ -7156,28 +7318,28 @@ function markerPayload(dir, state, id, createdAt) {
|
|
|
7156
7318
|
pid: process.pid,
|
|
7157
7319
|
entries: listEntries(dir)
|
|
7158
7320
|
};
|
|
7159
|
-
const manifestPath =
|
|
7160
|
-
if (
|
|
7161
|
-
marker2.manifestSha256 = sha256Hex2(
|
|
7321
|
+
const manifestPath = path13.join(dir, "manifest.json");
|
|
7322
|
+
if (fs12.existsSync(manifestPath)) {
|
|
7323
|
+
marker2.manifestSha256 = sha256Hex2(fs12.readFileSync(manifestPath));
|
|
7162
7324
|
}
|
|
7163
7325
|
return marker2;
|
|
7164
7326
|
}
|
|
7165
7327
|
function writeOwnershipMarker(dir, marker2) {
|
|
7166
|
-
|
|
7167
|
-
|
|
7328
|
+
fs12.writeFileSync(
|
|
7329
|
+
path13.join(dir, OWNERSHIP_MARKER),
|
|
7168
7330
|
`${JSON.stringify(marker2, null, 2)}
|
|
7169
7331
|
`,
|
|
7170
7332
|
"utf8"
|
|
7171
7333
|
);
|
|
7172
7334
|
}
|
|
7173
7335
|
function readOwnershipMarker(dir) {
|
|
7174
|
-
const markerPath =
|
|
7175
|
-
if (!
|
|
7336
|
+
const markerPath = path13.join(dir, OWNERSHIP_MARKER);
|
|
7337
|
+
if (!fs12.existsSync(markerPath)) {
|
|
7176
7338
|
return { marker: null, problem: "it holds no .codebase-snapshot marker" };
|
|
7177
7339
|
}
|
|
7178
7340
|
let raw;
|
|
7179
7341
|
try {
|
|
7180
|
-
raw =
|
|
7342
|
+
raw = fs12.readFileSync(markerPath, "utf8");
|
|
7181
7343
|
} catch {
|
|
7182
7344
|
return { marker: null, problem: "its .codebase-snapshot marker could not be read" };
|
|
7183
7345
|
}
|
|
@@ -7245,11 +7407,11 @@ function assessSnapshotDirectory(dir) {
|
|
|
7245
7407
|
marker: marker2
|
|
7246
7408
|
};
|
|
7247
7409
|
}
|
|
7248
|
-
const manifestPath =
|
|
7249
|
-
if (
|
|
7410
|
+
const manifestPath = path13.join(dir, "manifest.json");
|
|
7411
|
+
if (fs12.existsSync(manifestPath)) {
|
|
7250
7412
|
let raw;
|
|
7251
7413
|
try {
|
|
7252
|
-
raw =
|
|
7414
|
+
raw = fs12.readFileSync(manifestPath, "utf8");
|
|
7253
7415
|
} catch {
|
|
7254
7416
|
return {
|
|
7255
7417
|
owned: false,
|
|
@@ -7331,13 +7493,13 @@ function containsNoFiles(dir) {
|
|
|
7331
7493
|
const current = pending.pop();
|
|
7332
7494
|
let entries;
|
|
7333
7495
|
try {
|
|
7334
|
-
entries =
|
|
7496
|
+
entries = fs12.readdirSync(current, { withFileTypes: true });
|
|
7335
7497
|
} catch {
|
|
7336
7498
|
return false;
|
|
7337
7499
|
}
|
|
7338
7500
|
for (const entry of entries) {
|
|
7339
7501
|
if (entry.isDirectory()) {
|
|
7340
|
-
pending.push(
|
|
7502
|
+
pending.push(path13.join(current, entry.name));
|
|
7341
7503
|
} else if (!IGNORABLE_ENTRIES.has(entry.name)) {
|
|
7342
7504
|
return false;
|
|
7343
7505
|
}
|
|
@@ -7346,13 +7508,13 @@ function containsNoFiles(dir) {
|
|
|
7346
7508
|
return true;
|
|
7347
7509
|
}
|
|
7348
7510
|
function assertReplaceable(target, label, secretRules) {
|
|
7349
|
-
if (!
|
|
7350
|
-
if (!
|
|
7511
|
+
if (!fs12.existsSync(target)) return;
|
|
7512
|
+
if (!fs12.statSync(target).isDirectory()) {
|
|
7351
7513
|
throw new Error(
|
|
7352
7514
|
`Refusing to write into ${label} ${target}: it exists but is not a directory.`
|
|
7353
7515
|
);
|
|
7354
7516
|
}
|
|
7355
|
-
const entries =
|
|
7517
|
+
const entries = fs12.readdirSync(target);
|
|
7356
7518
|
if (entries.length === 0) return;
|
|
7357
7519
|
if (entries.every((name) => IGNORABLE_ENTRIES.has(name))) return;
|
|
7358
7520
|
if (containsNoFiles(target)) return;
|
|
@@ -7372,18 +7534,18 @@ function assertReplaceable(target, label, secretRules) {
|
|
|
7372
7534
|
);
|
|
7373
7535
|
}
|
|
7374
7536
|
function assertStagingRootUsable(tmpDir, secretRules) {
|
|
7375
|
-
if (!
|
|
7376
|
-
if (!
|
|
7537
|
+
if (!fs12.existsSync(tmpDir)) return;
|
|
7538
|
+
if (!fs12.statSync(tmpDir).isDirectory()) {
|
|
7377
7539
|
throw new Error(`Refusing to write into tmpDir ${tmpDir}: it exists but is not a directory.`);
|
|
7378
7540
|
}
|
|
7379
|
-
const entries =
|
|
7541
|
+
const entries = fs12.readdirSync(tmpDir);
|
|
7380
7542
|
if (entries.length === 0) return;
|
|
7381
7543
|
const foreign = entries.filter((name) => {
|
|
7382
|
-
const full =
|
|
7544
|
+
const full = path13.join(tmpDir, name);
|
|
7383
7545
|
if (!name.startsWith(RUN_DIR_PREFIX)) return true;
|
|
7384
7546
|
let stats;
|
|
7385
7547
|
try {
|
|
7386
|
-
stats =
|
|
7548
|
+
stats = fs12.statSync(full);
|
|
7387
7549
|
} catch {
|
|
7388
7550
|
return true;
|
|
7389
7551
|
}
|
|
@@ -7391,7 +7553,7 @@ function assertStagingRootUsable(tmpDir, secretRules) {
|
|
|
7391
7553
|
const { marker: marker2 } = readOwnershipMarker(full);
|
|
7392
7554
|
if (marker2) return false;
|
|
7393
7555
|
try {
|
|
7394
|
-
return
|
|
7556
|
+
return fs12.readdirSync(full).length > 0;
|
|
7395
7557
|
} catch {
|
|
7396
7558
|
return true;
|
|
7397
7559
|
}
|
|
@@ -7406,13 +7568,13 @@ function assertStagingRootUsable(tmpDir, secretRules) {
|
|
|
7406
7568
|
function cleanStaleRunDirs(tmpDir) {
|
|
7407
7569
|
let entries;
|
|
7408
7570
|
try {
|
|
7409
|
-
entries =
|
|
7571
|
+
entries = fs12.readdirSync(tmpDir);
|
|
7410
7572
|
} catch {
|
|
7411
7573
|
return;
|
|
7412
7574
|
}
|
|
7413
7575
|
for (const name of entries) {
|
|
7414
7576
|
if (!name.startsWith(RUN_DIR_PREFIX)) continue;
|
|
7415
|
-
const full =
|
|
7577
|
+
const full = path13.join(tmpDir, name);
|
|
7416
7578
|
const { marker: marker2 } = readOwnershipMarker(full);
|
|
7417
7579
|
if (marker2) {
|
|
7418
7580
|
const created = Date.parse(marker2.createdAt);
|
|
@@ -7420,33 +7582,33 @@ function cleanStaleRunDirs(tmpDir) {
|
|
|
7420
7582
|
const abandoned = typeof marker2.pid === "number" && !isProcessAlive(marker2.pid);
|
|
7421
7583
|
if (aged || abandoned) {
|
|
7422
7584
|
try {
|
|
7423
|
-
|
|
7585
|
+
fs12.rmSync(full, { recursive: true, force: true });
|
|
7424
7586
|
} catch {
|
|
7425
7587
|
}
|
|
7426
7588
|
}
|
|
7427
7589
|
continue;
|
|
7428
7590
|
}
|
|
7429
7591
|
try {
|
|
7430
|
-
if (
|
|
7592
|
+
if (fs12.readdirSync(full).length === 0) fs12.rmSync(full, { recursive: true, force: true });
|
|
7431
7593
|
} catch {
|
|
7432
7594
|
}
|
|
7433
7595
|
}
|
|
7434
7596
|
}
|
|
7435
7597
|
function removeIfEmpty(dir) {
|
|
7436
7598
|
try {
|
|
7437
|
-
if (
|
|
7599
|
+
if (fs12.readdirSync(dir).length === 0) fs12.rmSync(dir, { recursive: true, force: true });
|
|
7438
7600
|
} catch {
|
|
7439
7601
|
}
|
|
7440
7602
|
}
|
|
7441
7603
|
function ensureParentDirectory(target, label) {
|
|
7442
|
-
const parent =
|
|
7443
|
-
if (
|
|
7604
|
+
const parent = path13.dirname(target);
|
|
7605
|
+
if (fs12.existsSync(parent) && !fs12.statSync(parent).isDirectory()) {
|
|
7444
7606
|
throw new Error(
|
|
7445
7607
|
`Refusing to create ${label} ${target}: ${parent} exists but is not a directory.`
|
|
7446
7608
|
);
|
|
7447
7609
|
}
|
|
7448
7610
|
try {
|
|
7449
|
-
|
|
7611
|
+
fs12.mkdirSync(parent, { recursive: true });
|
|
7450
7612
|
} catch (err) {
|
|
7451
7613
|
throw new Error(
|
|
7452
7614
|
`Refusing to create ${label} ${target}: its parent ${parent} could not be created (${err.message}).`
|
|
@@ -7455,7 +7617,7 @@ function ensureParentDirectory(target, label) {
|
|
|
7455
7617
|
}
|
|
7456
7618
|
function acquireRunLock(stagingRoot) {
|
|
7457
7619
|
const key = lockKeyFor(stagingRoot);
|
|
7458
|
-
const lockPath =
|
|
7620
|
+
const lockPath = path13.join(os2.tmpdir(), `codebase-snapshot-${key}.lock`);
|
|
7459
7621
|
const payload = `${JSON.stringify({
|
|
7460
7622
|
pid: process.pid,
|
|
7461
7623
|
stagingRoot,
|
|
@@ -7464,22 +7626,22 @@ function acquireRunLock(stagingRoot) {
|
|
|
7464
7626
|
`;
|
|
7465
7627
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
7466
7628
|
try {
|
|
7467
|
-
const handle =
|
|
7629
|
+
const handle = fs12.openSync(lockPath, "wx");
|
|
7468
7630
|
try {
|
|
7469
|
-
|
|
7631
|
+
fs12.writeSync(handle, payload);
|
|
7470
7632
|
} finally {
|
|
7471
|
-
|
|
7633
|
+
fs12.closeSync(handle);
|
|
7472
7634
|
}
|
|
7473
7635
|
return () => {
|
|
7474
7636
|
try {
|
|
7475
|
-
|
|
7637
|
+
fs12.rmSync(lockPath, { force: true });
|
|
7476
7638
|
} catch {
|
|
7477
7639
|
}
|
|
7478
7640
|
};
|
|
7479
7641
|
} catch (err) {
|
|
7480
7642
|
if (err.code !== "EEXIST") throw err;
|
|
7481
7643
|
if (attempt === 0 && lockOwnerIsGone(lockPath)) {
|
|
7482
|
-
|
|
7644
|
+
fs12.rmSync(lockPath, { force: true });
|
|
7483
7645
|
continue;
|
|
7484
7646
|
}
|
|
7485
7647
|
throw new Error(
|
|
@@ -7492,7 +7654,7 @@ function acquireRunLock(stagingRoot) {
|
|
|
7492
7654
|
function lockKeyFor(stagingRoot) {
|
|
7493
7655
|
let key = stagingRoot;
|
|
7494
7656
|
try {
|
|
7495
|
-
key =
|
|
7657
|
+
key = fs12.realpathSync(stagingRoot);
|
|
7496
7658
|
} catch {
|
|
7497
7659
|
}
|
|
7498
7660
|
if (process.platform === "win32" || process.platform === "darwin") key = key.toLowerCase();
|
|
@@ -7501,7 +7663,7 @@ function lockKeyFor(stagingRoot) {
|
|
|
7501
7663
|
function lockOwnerIsGone(lockPath) {
|
|
7502
7664
|
let raw;
|
|
7503
7665
|
try {
|
|
7504
|
-
raw =
|
|
7666
|
+
raw = fs12.readFileSync(lockPath, "utf8");
|
|
7505
7667
|
} catch {
|
|
7506
7668
|
return false;
|
|
7507
7669
|
}
|
|
@@ -7521,12 +7683,12 @@ function lockOwnerIsGone(lockPath) {
|
|
|
7521
7683
|
}
|
|
7522
7684
|
function writeManifestAtomically(manifestPath, manifest) {
|
|
7523
7685
|
const tempPath = `${manifestPath}.${process.pid}.tmp`;
|
|
7524
|
-
|
|
7686
|
+
fs12.writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf8");
|
|
7525
7687
|
try {
|
|
7526
|
-
|
|
7688
|
+
fs12.renameSync(tempPath, manifestPath);
|
|
7527
7689
|
} catch (err) {
|
|
7528
7690
|
try {
|
|
7529
|
-
|
|
7691
|
+
fs12.rmSync(tempPath, { force: true });
|
|
7530
7692
|
} catch {
|
|
7531
7693
|
}
|
|
7532
7694
|
throw err;
|
|
@@ -7549,31 +7711,31 @@ function swapIntoPlace(stagingDir, outDir) {
|
|
|
7549
7711
|
}
|
|
7550
7712
|
function swapOnce(stagingDir, outDir) {
|
|
7551
7713
|
const backupDir = `${outDir}.backup-${process.pid}-${Date.now()}`;
|
|
7552
|
-
const hadPrevious =
|
|
7553
|
-
if (hadPrevious)
|
|
7714
|
+
const hadPrevious = fs12.existsSync(outDir);
|
|
7715
|
+
if (hadPrevious) fs12.renameSync(outDir, backupDir);
|
|
7554
7716
|
try {
|
|
7555
7717
|
try {
|
|
7556
|
-
|
|
7718
|
+
fs12.renameSync(stagingDir, outDir);
|
|
7557
7719
|
} catch (err) {
|
|
7558
7720
|
if (err.code !== "EXDEV") throw err;
|
|
7559
7721
|
const partialDir = `${outDir}.partial-${process.pid}-${Date.now()}`;
|
|
7560
7722
|
try {
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7723
|
+
fs12.cpSync(stagingDir, partialDir, { recursive: true });
|
|
7724
|
+
fs12.renameSync(partialDir, outDir);
|
|
7725
|
+
fs12.rmSync(stagingDir, { recursive: true, force: true });
|
|
7564
7726
|
} catch (copyErr) {
|
|
7565
7727
|
try {
|
|
7566
|
-
|
|
7728
|
+
fs12.rmSync(partialDir, { recursive: true, force: true });
|
|
7567
7729
|
} catch {
|
|
7568
7730
|
}
|
|
7569
7731
|
throw copyErr;
|
|
7570
7732
|
}
|
|
7571
7733
|
}
|
|
7572
|
-
if (hadPrevious)
|
|
7734
|
+
if (hadPrevious) fs12.rmSync(backupDir, { recursive: true, force: true });
|
|
7573
7735
|
} catch (err) {
|
|
7574
|
-
if (hadPrevious &&
|
|
7575
|
-
if (
|
|
7576
|
-
|
|
7736
|
+
if (hadPrevious && fs12.existsSync(backupDir)) {
|
|
7737
|
+
if (fs12.existsSync(outDir)) fs12.rmSync(outDir, { recursive: true, force: true });
|
|
7738
|
+
fs12.renameSync(backupDir, outDir);
|
|
7577
7739
|
}
|
|
7578
7740
|
throw err;
|
|
7579
7741
|
}
|
|
@@ -7668,7 +7830,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7668
7830
|
// first run cannot have marked them yet, so the name alone keeps a run from recording its own
|
|
7669
7831
|
// output — but only at these exact paths, not at every directory that shares the name.
|
|
7670
7832
|
toolOwnedPaths: [config.outDir, config.tmpDir].map(
|
|
7671
|
-
(directory) =>
|
|
7833
|
+
(directory) => path13.relative(config.cwd, path13.resolve(config.cwd, directory)).replace(/\\/g, "/")
|
|
7672
7834
|
).filter((relative11) => relative11.length > 0 && !relative11.startsWith(".."))
|
|
7673
7835
|
});
|
|
7674
7836
|
const files = [];
|
|
@@ -7689,12 +7851,12 @@ function generateSnapshot(configInput, options) {
|
|
|
7689
7851
|
let totalSizeBytes = 0;
|
|
7690
7852
|
let largeFileCount = 0;
|
|
7691
7853
|
for (const relativePath of collection.files) {
|
|
7692
|
-
const absolutePath =
|
|
7854
|
+
const absolutePath = path13.join(config.cwd, relativePath);
|
|
7693
7855
|
let stats;
|
|
7694
7856
|
try {
|
|
7695
|
-
stats =
|
|
7857
|
+
stats = fs12.statSync(absolutePath);
|
|
7696
7858
|
if (!stats.isFile()) {
|
|
7697
|
-
const nestedRepository = stats.isDirectory() &&
|
|
7859
|
+
const nestedRepository = stats.isDirectory() && fs12.existsSync(path13.join(absolutePath, ".git"));
|
|
7698
7860
|
skipped.push(
|
|
7699
7861
|
nestedRepository ? {
|
|
7700
7862
|
path: relativePath,
|
|
@@ -7714,7 +7876,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7714
7876
|
}
|
|
7715
7877
|
let buffer;
|
|
7716
7878
|
try {
|
|
7717
|
-
buffer =
|
|
7879
|
+
buffer = fs12.readFileSync(absolutePath);
|
|
7718
7880
|
} catch {
|
|
7719
7881
|
skipped.push({ path: relativePath, reason: "read-error" });
|
|
7720
7882
|
continue;
|
|
@@ -8044,12 +8206,12 @@ function generateSnapshot(configInput, options) {
|
|
|
8044
8206
|
let stagingDir = null;
|
|
8045
8207
|
try {
|
|
8046
8208
|
ensureParentDirectory(outDir, "outDir");
|
|
8047
|
-
|
|
8209
|
+
fs12.mkdirSync(tmpDir, { recursive: true });
|
|
8048
8210
|
cleanStaleRunDirs(tmpDir);
|
|
8049
8211
|
const snapshotId = crypto3.randomUUID();
|
|
8050
8212
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8051
|
-
stagingDir =
|
|
8052
|
-
|
|
8213
|
+
stagingDir = path13.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
|
|
8214
|
+
fs12.mkdirSync(stagingDir);
|
|
8053
8215
|
writeOwnershipMarker(stagingDir, {
|
|
8054
8216
|
generator: GENERATOR_NAME,
|
|
8055
8217
|
version: GENERATOR_VERSION,
|
|
@@ -8059,41 +8221,41 @@ function generateSnapshot(configInput, options) {
|
|
|
8059
8221
|
id: snapshotId,
|
|
8060
8222
|
pid: process.pid
|
|
8061
8223
|
});
|
|
8062
|
-
const partsDir =
|
|
8063
|
-
const reportsDir =
|
|
8064
|
-
if (artifacts.parts)
|
|
8224
|
+
const partsDir = path13.join(stagingDir, "parts");
|
|
8225
|
+
const reportsDir = path13.join(stagingDir, "reports");
|
|
8226
|
+
if (artifacts.parts) fs12.mkdirSync(partsDir, { recursive: true });
|
|
8065
8227
|
if (artifacts.navigation || artifacts.projectTree || artifacts.audit) {
|
|
8066
|
-
|
|
8228
|
+
fs12.mkdirSync(reportsDir, { recursive: true });
|
|
8067
8229
|
}
|
|
8068
8230
|
if (artifacts.parts) {
|
|
8069
8231
|
for (const part of parts) {
|
|
8070
|
-
|
|
8232
|
+
fs12.writeFileSync(path13.join(partsDir, part.filename), part.markdown, "utf8");
|
|
8071
8233
|
}
|
|
8072
8234
|
}
|
|
8073
8235
|
if (projectTree !== null) {
|
|
8074
|
-
|
|
8236
|
+
fs12.writeFileSync(path13.join(reportsDir, "project-tree.md"), projectTree, "utf8");
|
|
8075
8237
|
}
|
|
8076
8238
|
if (artifacts.navigation) {
|
|
8077
|
-
|
|
8239
|
+
fs12.writeFileSync(path13.join(reportsDir, "navigation.md"), generateNavigation(manifest), "utf8");
|
|
8078
8240
|
}
|
|
8079
8241
|
if (artifacts.audit) {
|
|
8080
|
-
|
|
8081
|
-
|
|
8242
|
+
fs12.writeFileSync(
|
|
8243
|
+
path13.join(reportsDir, "audit.md"),
|
|
8082
8244
|
generateAuditReport(manifest, secretFindings, config.secretRules),
|
|
8083
8245
|
"utf8"
|
|
8084
8246
|
);
|
|
8085
8247
|
}
|
|
8086
8248
|
if (artifacts.readme) {
|
|
8087
|
-
|
|
8249
|
+
fs12.writeFileSync(path13.join(stagingDir, "README.md"), generateReadme(manifest, artifacts), "utf8");
|
|
8088
8250
|
}
|
|
8089
8251
|
if (artifacts.manifest) {
|
|
8090
|
-
|
|
8252
|
+
fs12.writeFileSync(path13.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
|
|
8091
8253
|
}
|
|
8092
8254
|
if (monolithJson !== null) {
|
|
8093
|
-
|
|
8255
|
+
fs12.writeFileSync(path13.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
|
|
8094
8256
|
}
|
|
8095
8257
|
if (monolithMarkdown !== null) {
|
|
8096
|
-
|
|
8258
|
+
fs12.writeFileSync(path13.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
|
|
8097
8259
|
}
|
|
8098
8260
|
writeOwnershipMarker(stagingDir, markerPayload(stagingDir, "complete", snapshotId, createdAt));
|
|
8099
8261
|
swapIntoPlace(stagingDir, outDir);
|
|
@@ -8102,7 +8264,7 @@ function generateSnapshot(configInput, options) {
|
|
|
8102
8264
|
const pendingHook = runAfterGenerate(config, manifest);
|
|
8103
8265
|
const shipHookState = () => {
|
|
8104
8266
|
if (artifacts.manifest && manifest.warnings.length !== warningsBeforeHook) {
|
|
8105
|
-
writeManifestAtomically(
|
|
8267
|
+
writeManifestAtomically(path13.join(outDir, "manifest.json"), manifest);
|
|
8106
8268
|
}
|
|
8107
8269
|
writeOwnershipMarker(outDir, markerPayload(outDir, "complete", snapshotId, createdAt));
|
|
8108
8270
|
};
|
|
@@ -8125,7 +8287,7 @@ function generateSnapshot(configInput, options) {
|
|
|
8125
8287
|
} catch (err) {
|
|
8126
8288
|
if (stagingDir !== null) {
|
|
8127
8289
|
try {
|
|
8128
|
-
|
|
8290
|
+
fs12.rmSync(stagingDir, { recursive: true, force: true });
|
|
8129
8291
|
} catch {
|
|
8130
8292
|
}
|
|
8131
8293
|
}
|
|
@@ -8137,8 +8299,8 @@ function generateSnapshot(configInput, options) {
|
|
|
8137
8299
|
}
|
|
8138
8300
|
|
|
8139
8301
|
// src/mcp/tools.ts
|
|
8140
|
-
import * as
|
|
8141
|
-
import * as
|
|
8302
|
+
import * as fs14 from "fs";
|
|
8303
|
+
import * as path15 from "path";
|
|
8142
8304
|
|
|
8143
8305
|
// src/mcp/part.ts
|
|
8144
8306
|
var FILE_HEADING = "### FILE: ";
|
|
@@ -8224,15 +8386,15 @@ function windowText(body, fromLine, lineCount) {
|
|
|
8224
8386
|
}
|
|
8225
8387
|
|
|
8226
8388
|
// src/mcp/workspace.ts
|
|
8227
|
-
import * as
|
|
8228
|
-
import * as
|
|
8389
|
+
import * as fs13 from "fs";
|
|
8390
|
+
import * as path14 from "path";
|
|
8229
8391
|
function foldForComparison(value) {
|
|
8230
8392
|
return process.platform === "win32" || process.platform === "darwin" ? value.toLowerCase() : value;
|
|
8231
8393
|
}
|
|
8232
8394
|
function canonicalPath(value) {
|
|
8233
|
-
const absolute =
|
|
8395
|
+
const absolute = path14.resolve(value);
|
|
8234
8396
|
try {
|
|
8235
|
-
return
|
|
8397
|
+
return fs13.realpathSync(absolute);
|
|
8236
8398
|
} catch {
|
|
8237
8399
|
return absolute;
|
|
8238
8400
|
}
|
|
@@ -8240,17 +8402,17 @@ function canonicalPath(value) {
|
|
|
8240
8402
|
function isInside2(parent, child) {
|
|
8241
8403
|
const foldedParent = foldForComparison(parent);
|
|
8242
8404
|
const foldedChild = foldForComparison(child);
|
|
8243
|
-
return foldedChild === foldedParent || foldedChild.startsWith(`${foldedParent}${
|
|
8405
|
+
return foldedChild === foldedParent || foldedChild.startsWith(`${foldedParent}${path14.sep}`);
|
|
8244
8406
|
}
|
|
8245
8407
|
function resolveRoot(requested, context) {
|
|
8246
8408
|
if (requested !== void 0 && (typeof requested !== "string" || requested.trim().length === 0)) {
|
|
8247
8409
|
return { ok: false, message: '"root" must be a non-empty string when provided.' };
|
|
8248
8410
|
}
|
|
8249
8411
|
const wanted = typeof requested === "string" ? requested.trim() : context.cwd;
|
|
8250
|
-
const absolute =
|
|
8412
|
+
const absolute = path14.resolve(context.cwd, wanted);
|
|
8251
8413
|
let stats;
|
|
8252
8414
|
try {
|
|
8253
|
-
stats =
|
|
8415
|
+
stats = fs13.statSync(absolute);
|
|
8254
8416
|
} catch {
|
|
8255
8417
|
return { ok: false, message: `"${wanted}" does not exist, so it cannot be a repository root.` };
|
|
8256
8418
|
}
|
|
@@ -8301,14 +8463,14 @@ async function openWorkspace(root, overrides = {}) {
|
|
|
8301
8463
|
}
|
|
8302
8464
|
var manifestCache = /* @__PURE__ */ new Map();
|
|
8303
8465
|
function manifestPathFor(workspace) {
|
|
8304
|
-
return
|
|
8466
|
+
return path14.resolve(workspace.root, workspace.config.outDir, "manifest.json");
|
|
8305
8467
|
}
|
|
8306
8468
|
function readManifest3(workspace) {
|
|
8307
8469
|
const file = manifestPathFor(workspace);
|
|
8308
|
-
const shown =
|
|
8470
|
+
const shown = path14.relative(workspace.root, file).split(path14.sep).join("/") || file;
|
|
8309
8471
|
let stats;
|
|
8310
8472
|
try {
|
|
8311
|
-
stats =
|
|
8473
|
+
stats = fs13.statSync(file);
|
|
8312
8474
|
} catch {
|
|
8313
8475
|
return {
|
|
8314
8476
|
ok: false,
|
|
@@ -8322,7 +8484,7 @@ function readManifest3(workspace) {
|
|
|
8322
8484
|
}
|
|
8323
8485
|
let raw;
|
|
8324
8486
|
try {
|
|
8325
|
-
raw =
|
|
8487
|
+
raw = fs13.readFileSync(file, "utf8");
|
|
8326
8488
|
} catch (error) {
|
|
8327
8489
|
return {
|
|
8328
8490
|
ok: false,
|
|
@@ -8380,7 +8542,7 @@ function formatBytes(bytes) {
|
|
|
8380
8542
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
8381
8543
|
}
|
|
8382
8544
|
function relativeFor(workspace, absolute) {
|
|
8383
|
-
return
|
|
8545
|
+
return path15.relative(workspace.root, absolute).split(path15.sep).join("/");
|
|
8384
8546
|
}
|
|
8385
8547
|
function capped(values, limit = 20) {
|
|
8386
8548
|
return { count: values.length, sample: values.slice(0, limit) };
|
|
@@ -8399,12 +8561,12 @@ function summarizeDrift(drift) {
|
|
|
8399
8561
|
function toRelativePath(root, value) {
|
|
8400
8562
|
const cleaned = value.trim();
|
|
8401
8563
|
if (cleaned.length === 0) return null;
|
|
8402
|
-
if (!
|
|
8564
|
+
if (!path15.isAbsolute(cleaned)) {
|
|
8403
8565
|
return cleaned.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
8404
8566
|
}
|
|
8405
|
-
const relative11 =
|
|
8406
|
-
if (relative11.startsWith("..") ||
|
|
8407
|
-
return relative11.split(
|
|
8567
|
+
const relative11 = path15.relative(root, cleaned);
|
|
8568
|
+
if (relative11.startsWith("..") || path15.isAbsolute(relative11)) return null;
|
|
8569
|
+
return relative11.split(path15.sep).join("/");
|
|
8408
8570
|
}
|
|
8409
8571
|
function symbolsOf(entry) {
|
|
8410
8572
|
const summary = entry.summary;
|
|
@@ -8615,7 +8777,7 @@ var generateTool = {
|
|
|
8615
8777
|
return failure(error instanceof Error ? error.message : String(error));
|
|
8616
8778
|
}
|
|
8617
8779
|
forgetManifest(manifestPathFor(workspace));
|
|
8618
|
-
const written = relativeFor(workspace,
|
|
8780
|
+
const written = relativeFor(workspace, path15.resolve(workspace.root, workspace.config.outDir));
|
|
8619
8781
|
const lines = [
|
|
8620
8782
|
`Wrote ${written}/`,
|
|
8621
8783
|
`Files: ${manifest.counts.totalFiles} included, ${manifest.counts.skippedCount} skipped, ${plural(manifest.counts.partsCount, "part")}`,
|
|
@@ -8880,10 +9042,10 @@ var readTool = {
|
|
|
8880
9042
|
`${relativePath} is not in the snapshot. Call snapshot_locate to find the path, or snapshot_explain to learn why it was excluded.`
|
|
8881
9043
|
);
|
|
8882
9044
|
}
|
|
8883
|
-
const partPath =
|
|
9045
|
+
const partPath = path15.resolve(workspace.root, workspace.config.outDir, "parts", entry.part);
|
|
8884
9046
|
let partText;
|
|
8885
9047
|
try {
|
|
8886
|
-
partText =
|
|
9048
|
+
partText = fs14.readFileSync(partPath, "utf8");
|
|
8887
9049
|
} catch {
|
|
8888
9050
|
return failure(
|
|
8889
9051
|
`${entry.part} could not be read, so the snapshot is damaged. Run snapshot_generate to rebuild it.`
|
|
@@ -9145,6 +9307,7 @@ var VALIDATE_OPTIONS = [
|
|
|
9145
9307
|
"no-config",
|
|
9146
9308
|
"discovery",
|
|
9147
9309
|
"format",
|
|
9310
|
+
"no-update-check",
|
|
9148
9311
|
"mode",
|
|
9149
9312
|
"help",
|
|
9150
9313
|
"version"
|
|
@@ -9168,6 +9331,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9168
9331
|
"watch",
|
|
9169
9332
|
"autopilot",
|
|
9170
9333
|
"no-install",
|
|
9334
|
+
"no-update-check",
|
|
9171
9335
|
"help",
|
|
9172
9336
|
"version"
|
|
9173
9337
|
],
|
|
@@ -9183,6 +9347,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9183
9347
|
"skip-artifacts",
|
|
9184
9348
|
"only-artifacts",
|
|
9185
9349
|
"no-config",
|
|
9350
|
+
"no-update-check",
|
|
9186
9351
|
"format",
|
|
9187
9352
|
"mode",
|
|
9188
9353
|
"help",
|
|
@@ -9200,12 +9365,13 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9200
9365
|
"only-artifacts",
|
|
9201
9366
|
"no-config",
|
|
9202
9367
|
"discovery",
|
|
9368
|
+
"no-update-check",
|
|
9203
9369
|
"format",
|
|
9204
9370
|
"mode",
|
|
9205
9371
|
"help",
|
|
9206
9372
|
"version"
|
|
9207
9373
|
],
|
|
9208
|
-
diff: ["format", "mode", "no-config", "help", "version"],
|
|
9374
|
+
diff: ["format", "mode", "no-config", "no-update-check", "help", "version"],
|
|
9209
9375
|
describe: ["format", "mode", "help", "version"],
|
|
9210
9376
|
init: [
|
|
9211
9377
|
"cwd",
|
|
@@ -9220,6 +9386,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9220
9386
|
"yes",
|
|
9221
9387
|
"force",
|
|
9222
9388
|
"dry-run",
|
|
9389
|
+
"no-update-check",
|
|
9223
9390
|
"format",
|
|
9224
9391
|
"mode",
|
|
9225
9392
|
"help",
|
|
@@ -9243,6 +9410,7 @@ var COMMAND_OPTION_SCOPE = {
|
|
|
9243
9410
|
"force",
|
|
9244
9411
|
"no-install",
|
|
9245
9412
|
"dry-run",
|
|
9413
|
+
"no-update-check",
|
|
9246
9414
|
"format",
|
|
9247
9415
|
"mode",
|
|
9248
9416
|
"help",
|
|
@@ -9675,6 +9843,13 @@ function buildAgentContract() {
|
|
|
9675
9843
|
default: false,
|
|
9676
9844
|
appliesTo: optionAppliesTo("no-install"),
|
|
9677
9845
|
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)."
|
|
9846
|
+
},
|
|
9847
|
+
{
|
|
9848
|
+
flag: "--no-update-check",
|
|
9849
|
+
type: "boolean",
|
|
9850
|
+
default: false,
|
|
9851
|
+
appliesTo: optionAppliesTo("no-update-check"),
|
|
9852
|
+
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."
|
|
9678
9853
|
}
|
|
9679
9854
|
],
|
|
9680
9855
|
presets: PRESETS.map((preset) => ({
|
|
@@ -9807,8 +9982,8 @@ function buildAgentContract() {
|
|
|
9807
9982
|
}
|
|
9808
9983
|
|
|
9809
9984
|
// src/agent/install-skill.ts
|
|
9810
|
-
import * as
|
|
9811
|
-
import * as
|
|
9985
|
+
import * as fs15 from "fs";
|
|
9986
|
+
import * as path16 from "path";
|
|
9812
9987
|
|
|
9813
9988
|
// src/agent/skill.ts
|
|
9814
9989
|
var PACKAGE_NAME2 = "codebase-snapshot";
|
|
@@ -9966,17 +10141,17 @@ var LEGACY_AGENTS_MARKER = "<!-- codebase-snapshot:skill:start -->";
|
|
|
9966
10141
|
function targetPath(cwd, target) {
|
|
9967
10142
|
switch (target) {
|
|
9968
10143
|
case "claude":
|
|
9969
|
-
return
|
|
10144
|
+
return path16.join(cwd, ".claude", "skills", SKILL_NAME, "SKILL.md");
|
|
9970
10145
|
case "cursor":
|
|
9971
|
-
return
|
|
10146
|
+
return path16.join(cwd, ".cursor", "rules", `${SKILL_NAME}.mdc`);
|
|
9972
10147
|
}
|
|
9973
10148
|
}
|
|
9974
10149
|
function assertWritableInsideRepository(cwd, filePath) {
|
|
9975
|
-
const root =
|
|
9976
|
-
const shown =
|
|
10150
|
+
const root = fs15.realpathSync(cwd);
|
|
10151
|
+
const shown = path16.relative(root, filePath) || filePath;
|
|
9977
10152
|
let stat = null;
|
|
9978
10153
|
try {
|
|
9979
|
-
stat =
|
|
10154
|
+
stat = fs15.lstatSync(filePath);
|
|
9980
10155
|
} catch {
|
|
9981
10156
|
stat = null;
|
|
9982
10157
|
}
|
|
@@ -9992,32 +10167,32 @@ function assertWritableInsideRepository(cwd, filePath) {
|
|
|
9992
10167
|
}
|
|
9993
10168
|
let existing = filePath;
|
|
9994
10169
|
const missing = [];
|
|
9995
|
-
while (!
|
|
9996
|
-
missing.unshift(
|
|
9997
|
-
const parent =
|
|
10170
|
+
while (!fs15.existsSync(existing)) {
|
|
10171
|
+
missing.unshift(path16.basename(existing));
|
|
10172
|
+
const parent = path16.dirname(existing);
|
|
9998
10173
|
if (parent === existing) break;
|
|
9999
10174
|
existing = parent;
|
|
10000
10175
|
}
|
|
10001
|
-
const realAncestor =
|
|
10002
|
-
const resolved = missing.length === 0 ? realAncestor :
|
|
10003
|
-
if (resolved !== root && !resolved.startsWith(`${root}${
|
|
10176
|
+
const realAncestor = fs15.realpathSync(existing);
|
|
10177
|
+
const resolved = missing.length === 0 ? realAncestor : path16.join(realAncestor, ...missing);
|
|
10178
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path16.sep}`)) {
|
|
10004
10179
|
throw new Error(
|
|
10005
10180
|
`${REFUSED}: ${shown} resolves outside the repository (${resolved}). Move it back inside ${root}, or remove the link, and run again.`
|
|
10006
10181
|
);
|
|
10007
10182
|
}
|
|
10008
10183
|
}
|
|
10009
10184
|
function writeIfChanged(target, filePath, content) {
|
|
10010
|
-
const existing =
|
|
10185
|
+
const existing = fs15.existsSync(filePath) ? fs15.readFileSync(filePath, "utf8") : null;
|
|
10011
10186
|
if (existing === content) return { target, path: filePath, action: "unchanged" };
|
|
10012
|
-
|
|
10013
|
-
|
|
10187
|
+
fs15.mkdirSync(path16.dirname(filePath), { recursive: true });
|
|
10188
|
+
fs15.writeFileSync(filePath, content, "utf8");
|
|
10014
10189
|
return { target, path: filePath, action: existing === null ? "created" : "updated" };
|
|
10015
10190
|
}
|
|
10016
10191
|
function legacyAgentsNote(cwd) {
|
|
10017
|
-
const filePath =
|
|
10192
|
+
const filePath = path16.join(cwd, "AGENTS.md");
|
|
10018
10193
|
try {
|
|
10019
|
-
if (!
|
|
10020
|
-
if (!
|
|
10194
|
+
if (!fs15.existsSync(filePath)) return null;
|
|
10195
|
+
if (!fs15.readFileSync(filePath, "utf8").includes(LEGACY_AGENTS_MARKER)) return null;
|
|
10021
10196
|
} catch {
|
|
10022
10197
|
return null;
|
|
10023
10198
|
}
|
|
@@ -10029,9 +10204,9 @@ function installSkill(cwd, target = "all") {
|
|
|
10029
10204
|
const notes = [];
|
|
10030
10205
|
const wanted = target === "all" ? ["claude", "cursor"] : [target];
|
|
10031
10206
|
for (const item of wanted) assertWritableInsideRepository(cwd, targetPath(cwd, item));
|
|
10032
|
-
const createsSomething = wanted.some((item) => !
|
|
10207
|
+
const createsSomething = wanted.some((item) => !fs15.existsSync(targetPath(cwd, item)));
|
|
10033
10208
|
if (createsSomething) {
|
|
10034
|
-
assertWritableInsideRepository(cwd,
|
|
10209
|
+
assertWritableInsideRepository(cwd, path16.join(cwd, ".gitignore"));
|
|
10035
10210
|
}
|
|
10036
10211
|
for (const item of wanted) {
|
|
10037
10212
|
written.push(writeIfChanged(item, targetPath(cwd, item), skill));
|
|
@@ -10166,52 +10341,52 @@ function validateArguments(schema, value) {
|
|
|
10166
10341
|
}
|
|
10167
10342
|
return problems;
|
|
10168
10343
|
}
|
|
10169
|
-
function checkValue(
|
|
10344
|
+
function checkValue(path19, schema, value) {
|
|
10170
10345
|
if (schema.enum && !schema.enum.includes(value)) {
|
|
10171
|
-
return [`"${
|
|
10346
|
+
return [`"${path19}" must be one of: ${schema.enum.join(", ")}`];
|
|
10172
10347
|
}
|
|
10173
10348
|
switch (schema.type) {
|
|
10174
10349
|
case "string": {
|
|
10175
|
-
if (typeof value !== "string") return [`"${
|
|
10350
|
+
if (typeof value !== "string") return [`"${path19}" must be a string`];
|
|
10176
10351
|
const problems = [];
|
|
10177
10352
|
if (schema.minLength !== void 0 && value.length < schema.minLength) {
|
|
10178
|
-
problems.push(`"${
|
|
10353
|
+
problems.push(`"${path19}" must be at least ${schema.minLength} character(s)`);
|
|
10179
10354
|
}
|
|
10180
10355
|
if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
|
|
10181
|
-
problems.push(`"${
|
|
10356
|
+
problems.push(`"${path19}" must be at most ${schema.maxLength} character(s)`);
|
|
10182
10357
|
}
|
|
10183
10358
|
return problems;
|
|
10184
10359
|
}
|
|
10185
10360
|
case "number":
|
|
10186
10361
|
case "integer": {
|
|
10187
10362
|
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
10188
|
-
return [`"${
|
|
10363
|
+
return [`"${path19}" must be a number`];
|
|
10189
10364
|
}
|
|
10190
10365
|
if (schema.type === "integer" && !Number.isInteger(value)) {
|
|
10191
|
-
return [`"${
|
|
10366
|
+
return [`"${path19}" must be an integer`];
|
|
10192
10367
|
}
|
|
10193
10368
|
const problems = [];
|
|
10194
10369
|
if (schema.minimum !== void 0 && value < schema.minimum) {
|
|
10195
|
-
problems.push(`"${
|
|
10370
|
+
problems.push(`"${path19}" must be >= ${schema.minimum}`);
|
|
10196
10371
|
}
|
|
10197
10372
|
if (schema.maximum !== void 0 && value > schema.maximum) {
|
|
10198
|
-
problems.push(`"${
|
|
10373
|
+
problems.push(`"${path19}" must be <= ${schema.maximum}`);
|
|
10199
10374
|
}
|
|
10200
10375
|
return problems;
|
|
10201
10376
|
}
|
|
10202
10377
|
case "boolean":
|
|
10203
|
-
return typeof value === "boolean" ? [] : [`"${
|
|
10378
|
+
return typeof value === "boolean" ? [] : [`"${path19}" must be a boolean`];
|
|
10204
10379
|
case "array": {
|
|
10205
|
-
if (!Array.isArray(value)) return [`"${
|
|
10380
|
+
if (!Array.isArray(value)) return [`"${path19}" must be an array`];
|
|
10206
10381
|
if (!schema.items) return [];
|
|
10207
10382
|
const problems = [];
|
|
10208
10383
|
value.forEach((item, index) => {
|
|
10209
|
-
problems.push(...checkValue(`${
|
|
10384
|
+
problems.push(...checkValue(`${path19}[${index}]`, schema.items, item));
|
|
10210
10385
|
});
|
|
10211
10386
|
return problems;
|
|
10212
10387
|
}
|
|
10213
10388
|
case "object":
|
|
10214
|
-
return isJsonObject(value) ? [] : [`"${
|
|
10389
|
+
return isJsonObject(value) ? [] : [`"${path19}" must be an object`];
|
|
10215
10390
|
default:
|
|
10216
10391
|
return [];
|
|
10217
10392
|
}
|
|
@@ -10225,6 +10400,18 @@ function applyDefaults(schema, value) {
|
|
|
10225
10400
|
}
|
|
10226
10401
|
return out;
|
|
10227
10402
|
}
|
|
10403
|
+
function coerceNumericStrings(schema, value) {
|
|
10404
|
+
const out = { ...value };
|
|
10405
|
+
for (const [key, propertySchema] of Object.entries(schema.properties)) {
|
|
10406
|
+
const raw = out[key];
|
|
10407
|
+
if (typeof raw !== "string") continue;
|
|
10408
|
+
if (propertySchema.type !== "number" && propertySchema.type !== "integer") continue;
|
|
10409
|
+
if (raw.trim().length === 0) continue;
|
|
10410
|
+
const parsed = Number(raw);
|
|
10411
|
+
if (Number.isFinite(parsed)) out[key] = parsed;
|
|
10412
|
+
}
|
|
10413
|
+
return out;
|
|
10414
|
+
}
|
|
10228
10415
|
|
|
10229
10416
|
// src/mcp/server.ts
|
|
10230
10417
|
function capabilities() {
|
|
@@ -10313,7 +10500,8 @@ function createMcpServer(options) {
|
|
|
10313
10500
|
if (!isJsonObject(rawArguments)) {
|
|
10314
10501
|
return errorResponse(id, ERROR_CODES.invalidParams, '"arguments" must be a JSON object.');
|
|
10315
10502
|
}
|
|
10316
|
-
const
|
|
10503
|
+
const supplied = coerceNumericStrings(tool.inputSchema, rawArguments);
|
|
10504
|
+
const problems = validateArguments(tool.inputSchema, supplied);
|
|
10317
10505
|
if (problems.length > 0) {
|
|
10318
10506
|
return ok(
|
|
10319
10507
|
id,
|
|
@@ -10325,7 +10513,7 @@ function createMcpServer(options) {
|
|
|
10325
10513
|
modern
|
|
10326
10514
|
);
|
|
10327
10515
|
}
|
|
10328
|
-
const args = applyDefaults(tool.inputSchema,
|
|
10516
|
+
const args = applyDefaults(tool.inputSchema, supplied);
|
|
10329
10517
|
let outcome;
|
|
10330
10518
|
try {
|
|
10331
10519
|
outcome = await tool.handler(args, options.context);
|
|
@@ -10494,8 +10682,8 @@ function createMcpServer(options) {
|
|
|
10494
10682
|
}
|
|
10495
10683
|
|
|
10496
10684
|
// src/mcp/resources.ts
|
|
10497
|
-
import * as
|
|
10498
|
-
import * as
|
|
10685
|
+
import * as fs16 from "fs";
|
|
10686
|
+
import * as path17 from "path";
|
|
10499
10687
|
var MAX_RESOURCE_BYTES = 512 * 1024;
|
|
10500
10688
|
var PART_URI = /^snapshot:\/\/parts\/(\d+)$/;
|
|
10501
10689
|
var REPORT_URIS = /* @__PURE__ */ new Map([
|
|
@@ -10529,7 +10717,7 @@ async function workspaceFor(context) {
|
|
|
10529
10717
|
}
|
|
10530
10718
|
function readFileIfPresent(file) {
|
|
10531
10719
|
try {
|
|
10532
|
-
return
|
|
10720
|
+
return fs16.readFileSync(file, "utf8");
|
|
10533
10721
|
} catch {
|
|
10534
10722
|
return null;
|
|
10535
10723
|
}
|
|
@@ -10608,7 +10796,7 @@ function buildResourceProvider() {
|
|
|
10608
10796
|
const report = REPORT_URIS.get(uri);
|
|
10609
10797
|
if (report) {
|
|
10610
10798
|
const text2 = readFileIfPresent(
|
|
10611
|
-
|
|
10799
|
+
path17.resolve(workspace.root, workspace.config.outDir, "reports", report.file)
|
|
10612
10800
|
);
|
|
10613
10801
|
if (text2 === null) return null;
|
|
10614
10802
|
return { uri, mimeType: "text/markdown", text: capUtf8(text2, MAX_RESOURCE_BYTES).text };
|
|
@@ -10627,7 +10815,7 @@ function buildResourceProvider() {
|
|
|
10627
10815
|
const part = read.manifest.parts.find((candidate) => candidate.index === index);
|
|
10628
10816
|
if (!part) return null;
|
|
10629
10817
|
const text2 = readFileIfPresent(
|
|
10630
|
-
|
|
10818
|
+
path17.resolve(workspace.root, workspace.config.outDir, "parts", part.filename)
|
|
10631
10819
|
);
|
|
10632
10820
|
if (text2 === null) return null;
|
|
10633
10821
|
return { uri, mimeType: "text/markdown", text: capUtf8(text2, MAX_RESOURCE_BYTES).text };
|
|
@@ -10865,6 +11053,7 @@ var CLI_OPTIONS = {
|
|
|
10865
11053
|
install: { type: "boolean" },
|
|
10866
11054
|
"no-install": { type: "boolean" },
|
|
10867
11055
|
target: { type: "string" },
|
|
11056
|
+
"no-update-check": { type: "boolean" },
|
|
10868
11057
|
help: { type: "boolean", short: "h" },
|
|
10869
11058
|
version: { type: "boolean", short: "v" }
|
|
10870
11059
|
};
|
|
@@ -10939,6 +11128,8 @@ Options:
|
|
|
10939
11128
|
--install Write the skill into the repository instead of printing
|
|
10940
11129
|
--target <name> claude | cursor | all (default: all)
|
|
10941
11130
|
|
|
11131
|
+
--no-update-check Skip the daily check for a newer published version
|
|
11132
|
+
|
|
10942
11133
|
-h, --help Display this help message
|
|
10943
11134
|
-v, --version Display version
|
|
10944
11135
|
|
|
@@ -11003,10 +11194,10 @@ function parseCliArgs(argv) {
|
|
|
11003
11194
|
}
|
|
11004
11195
|
if (values.cwd !== void 0) {
|
|
11005
11196
|
const target = String(values.cwd);
|
|
11006
|
-
if (!
|
|
11197
|
+
if (!fs17.existsSync(target)) {
|
|
11007
11198
|
throw new UsageError(`--cwd directory does not exist: ${target}`);
|
|
11008
11199
|
}
|
|
11009
|
-
if (!
|
|
11200
|
+
if (!fs17.statSync(target).isDirectory()) {
|
|
11010
11201
|
throw new UsageError(`--cwd is not a directory: ${target}`);
|
|
11011
11202
|
}
|
|
11012
11203
|
}
|
|
@@ -11152,7 +11343,7 @@ function parseCliArgs(argv) {
|
|
|
11152
11343
|
install: values.install === true,
|
|
11153
11344
|
noInstall: values["no-install"] === true,
|
|
11154
11345
|
target: values.target === void 0 ? void 0 : String(values.target),
|
|
11155
|
-
cwd: values.cwd === void 0 ? process.cwd() :
|
|
11346
|
+
cwd: values.cwd === void 0 ? process.cwd() : path18.resolve(String(values.cwd)),
|
|
11156
11347
|
outDir: values["out-dir"] === void 0 ? void 0 : String(values["out-dir"]),
|
|
11157
11348
|
includeMonolith: values["include-monolith"] === true || onlyNamesMonolith === true ? true : void 0,
|
|
11158
11349
|
includeSensitiveFiles: values["include-sensitive-files"] === true ? true : void 0,
|
|
@@ -11209,24 +11400,24 @@ function splitList(value) {
|
|
|
11209
11400
|
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
11210
11401
|
}
|
|
11211
11402
|
function displayOutPath(cwd, outDir, ...segments) {
|
|
11212
|
-
const absolute =
|
|
11213
|
-
const relative11 =
|
|
11214
|
-
if (relative11 && !relative11.startsWith("..") && !
|
|
11403
|
+
const absolute = path18.resolve(cwd, outDir, ...segments);
|
|
11404
|
+
const relative11 = path18.relative(cwd, absolute);
|
|
11405
|
+
if (relative11 && !relative11.startsWith("..") && !path18.isAbsolute(relative11)) return relative11;
|
|
11215
11406
|
return absolute;
|
|
11216
11407
|
}
|
|
11217
11408
|
function nextStepHint(cwd, scriptsAddedNow) {
|
|
11218
11409
|
let hasScript = scriptsAddedNow;
|
|
11219
11410
|
if (!hasScript) {
|
|
11220
11411
|
try {
|
|
11221
|
-
const parsed = JSON.parse(
|
|
11412
|
+
const parsed = JSON.parse(fs17.readFileSync(path18.join(cwd, "package.json"), "utf8"));
|
|
11222
11413
|
hasScript = typeof parsed.scripts?.snapshot === "string";
|
|
11223
11414
|
} catch {
|
|
11224
11415
|
hasScript = false;
|
|
11225
11416
|
}
|
|
11226
11417
|
}
|
|
11227
11418
|
if (!hasScript) return `npx ${GENERATOR_NAME} generate`;
|
|
11228
|
-
const bin =
|
|
11229
|
-
const installed =
|
|
11419
|
+
const bin = path18.join(cwd, "node_modules", ".bin", "codebase-snapshot");
|
|
11420
|
+
const installed = fs17.existsSync(bin) || fs17.existsSync(`${bin}.cmd`);
|
|
11230
11421
|
return installed ? "npm run snapshot" : "npm install && npm run snapshot";
|
|
11231
11422
|
}
|
|
11232
11423
|
function presetSummary(init) {
|
|
@@ -11256,7 +11447,7 @@ async function runInitCommand(invocation) {
|
|
|
11256
11447
|
info(result.configText);
|
|
11257
11448
|
return 0;
|
|
11258
11449
|
}
|
|
11259
|
-
info(`\u2705 Created ${
|
|
11450
|
+
info(`\u2705 Created ${path18.basename(result.configPath)} (${presetSummary(result)})`);
|
|
11260
11451
|
if (result.scripts.length > 0) info(` Added npm scripts: ${result.scripts.join(", ")}`);
|
|
11261
11452
|
if (result.dependency.added && result.dependency.range !== null) {
|
|
11262
11453
|
info(` Added devDependency: ${result.dependency.name} ${result.dependency.range}`);
|
|
@@ -11276,7 +11467,7 @@ async function runInitCommand(invocation) {
|
|
|
11276
11467
|
}
|
|
11277
11468
|
}
|
|
11278
11469
|
function detectPackageManager(cwd) {
|
|
11279
|
-
const has = (name) =>
|
|
11470
|
+
const has = (name) => fs17.existsSync(path18.join(cwd, name));
|
|
11280
11471
|
if (has("bun.lockb") || has("bun.lock")) return { name: "bun", command: "bun", args: ["install"] };
|
|
11281
11472
|
if (has("pnpm-lock.yaml")) return { name: "pnpm", command: "pnpm", args: ["install"] };
|
|
11282
11473
|
if (has("yarn.lock")) return { name: "yarn", command: "yarn", args: ["install"] };
|
|
@@ -11365,7 +11556,7 @@ async function runSetupCommand(invocation, options = {}) {
|
|
|
11365
11556
|
}
|
|
11366
11557
|
info("\n\u{1F9EA} Dry run \u2014 setup would:");
|
|
11367
11558
|
info(
|
|
11368
|
-
` 1. ${init.reused ? `keep ${
|
|
11559
|
+
` 1. ${init.reused ? `keep ${path18.basename(init.configPath)}` : `write ${path18.basename(init.configPath)} (preset: ${init.preset})`}`
|
|
11369
11560
|
);
|
|
11370
11561
|
info(" 2. add the npm scripts, the devDependency and the .gitignore entries");
|
|
11371
11562
|
if (manager !== null) info(` 3. install with ${manager}`);
|
|
@@ -11377,9 +11568,9 @@ async function runSetupCommand(invocation, options = {}) {
|
|
|
11377
11568
|
if (invocation.format !== "json") {
|
|
11378
11569
|
if (!interactive) info(`\u{1F680} Setup for: ${invocation.cwd}`);
|
|
11379
11570
|
if (init.reused) {
|
|
11380
|
-
info(`\u267B Keeping ${
|
|
11571
|
+
info(`\u267B Keeping ${path18.basename(init.configPath)} (${presetSummary(init)})`);
|
|
11381
11572
|
} else {
|
|
11382
|
-
info(`\u2705 Created ${
|
|
11573
|
+
info(`\u2705 Created ${path18.basename(init.configPath)} (${presetSummary(init)})`);
|
|
11383
11574
|
}
|
|
11384
11575
|
if (init.scripts.length > 0) info(` Added npm scripts: ${init.scripts.join(", ")}`);
|
|
11385
11576
|
if (init.dependency.added && init.dependency.range !== null) {
|
|
@@ -11487,7 +11678,7 @@ function runSkillCommand(invocation) {
|
|
|
11487
11678
|
}
|
|
11488
11679
|
info(`\u2705 Agent skill installed (${SKILL_NAME}):`);
|
|
11489
11680
|
for (const item of result.written) {
|
|
11490
|
-
const shown =
|
|
11681
|
+
const shown = path18.relative(invocation.cwd, item.path) || item.path;
|
|
11491
11682
|
info(` - ${item.action.padEnd(9)} ${shown}`);
|
|
11492
11683
|
}
|
|
11493
11684
|
if (result.gitignored.length > 0) {
|
|
@@ -11551,6 +11742,17 @@ function requestsJsonFormat(argv) {
|
|
|
11551
11742
|
return format === "json";
|
|
11552
11743
|
}
|
|
11553
11744
|
async function main(argv = process.argv.slice(2)) {
|
|
11745
|
+
const pending = process.stdout.isTTY === true && shouldCheck(argv, process.env) ? checkForUpdate({ current: GENERATOR_VERSION, cacheFile: cacheFilePath() }) : null;
|
|
11746
|
+
const code = await runCommand(argv);
|
|
11747
|
+
if (pending) {
|
|
11748
|
+
const notice = await pending;
|
|
11749
|
+
if (notice) process.stderr.write(`
|
|
11750
|
+
${formatUpdateNotice(notice)}
|
|
11751
|
+
`);
|
|
11752
|
+
}
|
|
11753
|
+
return code;
|
|
11754
|
+
}
|
|
11755
|
+
async function runCommand(argv) {
|
|
11554
11756
|
let invocation;
|
|
11555
11757
|
try {
|
|
11556
11758
|
invocation = parseCliArgs(argv);
|
|
@@ -11583,7 +11785,7 @@ ${USAGE}
|
|
|
11583
11785
|
return runSkillCommand(invocation);
|
|
11584
11786
|
}
|
|
11585
11787
|
if (invocation.command === "mcp") {
|
|
11586
|
-
return await runStdioServer({ cwd:
|
|
11788
|
+
return await runStdioServer({ cwd: path18.resolve(invocation.cwd) });
|
|
11587
11789
|
}
|
|
11588
11790
|
if (invocation.command === "setup") {
|
|
11589
11791
|
return runSetupCommand(invocation);
|
|
@@ -11600,7 +11802,7 @@ ${USAGE}
|
|
|
11600
11802
|
warn("\u274C The config file could not be read. Fix it, or delete it to use the defaults.");
|
|
11601
11803
|
return 1;
|
|
11602
11804
|
}
|
|
11603
|
-
if (loaded.file) info(`\u2699 Using config ${
|
|
11805
|
+
if (loaded.file) info(`\u2699 Using config ${path18.relative(process.cwd(), loaded.file) || loaded.file}`);
|
|
11604
11806
|
const resolved = resolveConfig(
|
|
11605
11807
|
loaded.config,
|
|
11606
11808
|
{
|
|
@@ -11622,10 +11824,10 @@ ${USAGE}
|
|
|
11622
11824
|
if (invocation.command === "validate") {
|
|
11623
11825
|
const result = validateSnapshot(resolved);
|
|
11624
11826
|
if (result.valid) {
|
|
11625
|
-
const manifestPath =
|
|
11827
|
+
const manifestPath = path18.resolve(resolved.cwd, resolved.outDir, "manifest.json");
|
|
11626
11828
|
let manifest;
|
|
11627
11829
|
try {
|
|
11628
|
-
manifest = JSON.parse(
|
|
11830
|
+
manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
|
|
11629
11831
|
} catch {
|
|
11630
11832
|
manifest = void 0;
|
|
11631
11833
|
}
|
|
@@ -11638,13 +11840,13 @@ ${USAGE}
|
|
|
11638
11840
|
return result.valid ? 0 : 1;
|
|
11639
11841
|
}
|
|
11640
11842
|
if (invocation.command === "report") {
|
|
11641
|
-
const manifestPath =
|
|
11642
|
-
if (!
|
|
11843
|
+
const manifestPath = path18.resolve(resolved.cwd, resolved.outDir, "manifest.json");
|
|
11844
|
+
if (!fs17.existsSync(manifestPath)) {
|
|
11643
11845
|
return fail(invocation.format, `Manifest not found at ${manifestPath}. Run generate first.`);
|
|
11644
11846
|
}
|
|
11645
11847
|
let manifest;
|
|
11646
11848
|
try {
|
|
11647
|
-
manifest = JSON.parse(
|
|
11849
|
+
manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
|
|
11648
11850
|
} catch (err) {
|
|
11649
11851
|
return fail(invocation.format, `Could not read ${manifestPath}: ${err.message}`);
|
|
11650
11852
|
}
|
|
@@ -11808,20 +12010,20 @@ function finishWatchRun(state, now) {
|
|
|
11808
12010
|
};
|
|
11809
12011
|
}
|
|
11810
12012
|
function comparablePath(value) {
|
|
11811
|
-
const absolute =
|
|
12013
|
+
const absolute = path18.resolve(value);
|
|
11812
12014
|
return process.platform === "win32" ? absolute.toLowerCase() : absolute;
|
|
11813
12015
|
}
|
|
11814
12016
|
function isSameOrInside(parent, candidate) {
|
|
11815
|
-
const relative11 =
|
|
11816
|
-
return relative11 === "" || relative11 !== ".." && !relative11.startsWith(`..${
|
|
12017
|
+
const relative11 = path18.relative(parent, candidate);
|
|
12018
|
+
return relative11 === "" || relative11 !== ".." && !relative11.startsWith(`..${path18.sep}`) && !path18.isAbsolute(relative11);
|
|
11817
12019
|
}
|
|
11818
12020
|
function isGeneratedWatchPath(candidate, paths) {
|
|
11819
|
-
const absolute = comparablePath(
|
|
11820
|
-
const outDir = comparablePath(
|
|
11821
|
-
const tmpDir = comparablePath(
|
|
12021
|
+
const absolute = comparablePath(path18.resolve(paths.cwd, candidate));
|
|
12022
|
+
const outDir = comparablePath(path18.resolve(paths.cwd, paths.outDir));
|
|
12023
|
+
const tmpDir = comparablePath(path18.resolve(paths.cwd, paths.tmpDir));
|
|
11822
12024
|
if (isSameOrInside(outDir, absolute) || isSameOrInside(tmpDir, absolute)) return true;
|
|
11823
|
-
const parent =
|
|
11824
|
-
if (parent ===
|
|
12025
|
+
const parent = path18.dirname(absolute);
|
|
12026
|
+
if (parent === path18.dirname(outDir) && path18.basename(absolute).startsWith(`${path18.basename(outDir)}.backup-`)) {
|
|
11825
12027
|
return true;
|
|
11826
12028
|
}
|
|
11827
12029
|
return absolute.split(/[\\/]+/).some((segment) => VCS_SEGMENTS.has(segment));
|
|
@@ -11838,8 +12040,8 @@ function decideWatchEvent(state, event, paths) {
|
|
|
11838
12040
|
return { state, action: "schedule" };
|
|
11839
12041
|
}
|
|
11840
12042
|
async function runWatchLoop(invocation, resolved) {
|
|
11841
|
-
const outDir =
|
|
11842
|
-
const tmpDir =
|
|
12043
|
+
const outDir = path18.resolve(resolved.cwd, resolved.outDir);
|
|
12044
|
+
const tmpDir = path18.resolve(resolved.cwd, resolved.tmpDir);
|
|
11843
12045
|
const paths = { cwd: resolved.cwd, outDir, tmpDir };
|
|
11844
12046
|
let state = initialWatchState();
|
|
11845
12047
|
let timer = null;
|
|
@@ -11904,11 +12106,11 @@ async function runWatchLoop(invocation, resolved) {
|
|
|
11904
12106
|
};
|
|
11905
12107
|
info("\u{1F440} Watching for changes. Press Ctrl+C to stop.");
|
|
11906
12108
|
void regenerate();
|
|
11907
|
-
const watcher =
|
|
12109
|
+
const watcher = fs17.watch(resolved.cwd, { recursive: true }, (_event, filename) => {
|
|
11908
12110
|
const decision = decideWatchEvent(
|
|
11909
12111
|
state,
|
|
11910
12112
|
{
|
|
11911
|
-
path: filename ?
|
|
12113
|
+
path: filename ? path18.resolve(resolved.cwd, filename.toString()) : null,
|
|
11912
12114
|
now: performance.now()
|
|
11913
12115
|
},
|
|
11914
12116
|
paths
|
|
@@ -11936,7 +12138,7 @@ async function runWatchLoop(invocation, resolved) {
|
|
|
11936
12138
|
return 0;
|
|
11937
12139
|
}
|
|
11938
12140
|
var entryFile = process.argv[1] ?? "";
|
|
11939
|
-
var entryName =
|
|
12141
|
+
var entryName = path18.basename(entryFile).toLowerCase();
|
|
11940
12142
|
var invokedDirectly = entryName === "cli.js" || entryName === "cli.cjs";
|
|
11941
12143
|
if (invokedDirectly) {
|
|
11942
12144
|
void main().then(
|