@chrisdudek/yg 4.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +178 -158
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -3891,6 +3891,158 @@ function registerOwnerCommand(program2) {
|
|
|
3891
3891
|
});
|
|
3892
3892
|
}
|
|
3893
3893
|
|
|
3894
|
+
// src/utils/hash.ts
|
|
3895
|
+
import { readFile as readFile14, readdir as readdir6, stat as stat5 } from "fs/promises";
|
|
3896
|
+
import path15 from "path";
|
|
3897
|
+
import { createHash } from "crypto";
|
|
3898
|
+
import { createRequire } from "module";
|
|
3899
|
+
var require2 = createRequire(import.meta.url);
|
|
3900
|
+
var ignoreFactory = require2("ignore");
|
|
3901
|
+
async function hashFile(filePath) {
|
|
3902
|
+
const content = await readFile14(filePath);
|
|
3903
|
+
return createHash("sha256").update(content).digest("hex");
|
|
3904
|
+
}
|
|
3905
|
+
async function loadRootGitignoreStack(projectRoot) {
|
|
3906
|
+
if (!projectRoot) return [];
|
|
3907
|
+
try {
|
|
3908
|
+
const content = await readFile14(path15.join(projectRoot, ".gitignore"), "utf-8");
|
|
3909
|
+
const matcher = ignoreFactory();
|
|
3910
|
+
matcher.add(content);
|
|
3911
|
+
return [{ basePath: projectRoot, matcher }];
|
|
3912
|
+
} catch {
|
|
3913
|
+
return [];
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
function isIgnoredByStack(candidatePath, stack) {
|
|
3917
|
+
for (const { basePath, matcher } of stack) {
|
|
3918
|
+
const relativePath = path15.relative(basePath, candidatePath);
|
|
3919
|
+
if (relativePath === "" || relativePath.startsWith("..")) continue;
|
|
3920
|
+
if (matcher.ignores(relativePath) || matcher.ignores(relativePath + "/")) return true;
|
|
3921
|
+
}
|
|
3922
|
+
return false;
|
|
3923
|
+
}
|
|
3924
|
+
function hashString(content) {
|
|
3925
|
+
return createHash("sha256").update(content).digest("hex");
|
|
3926
|
+
}
|
|
3927
|
+
async function hashTrackedFiles(projectRoot, trackedFiles, storedFileData, excludePrefixes) {
|
|
3928
|
+
const fileHashes = {};
|
|
3929
|
+
const fileMtimes = {};
|
|
3930
|
+
const gitignoreStack = await loadRootGitignoreStack(projectRoot);
|
|
3931
|
+
const allFiles = [];
|
|
3932
|
+
for (const tf of trackedFiles) {
|
|
3933
|
+
if (tf.syntheticHash) {
|
|
3934
|
+
fileHashes[tf.path] = tf.syntheticHash;
|
|
3935
|
+
continue;
|
|
3936
|
+
}
|
|
3937
|
+
const absPath = path15.join(projectRoot, tf.path);
|
|
3938
|
+
try {
|
|
3939
|
+
const st = await stat5(absPath);
|
|
3940
|
+
if (st.isDirectory()) {
|
|
3941
|
+
const dirEntries = await collectDirectoryFilePaths(absPath, absPath, {
|
|
3942
|
+
projectRoot,
|
|
3943
|
+
gitignoreStack
|
|
3944
|
+
});
|
|
3945
|
+
for (const entry of dirEntries) {
|
|
3946
|
+
allFiles.push({
|
|
3947
|
+
relPath: path15.join(tf.path, entry.relPath).replace(/\\/g, "/").replace(/\/+$/, ""),
|
|
3948
|
+
absPath: entry.absPath,
|
|
3949
|
+
mtimeMs: entry.mtimeMs
|
|
3950
|
+
});
|
|
3951
|
+
}
|
|
3952
|
+
} else {
|
|
3953
|
+
allFiles.push({ relPath: tf.path, absPath, mtimeMs: st.mtimeMs });
|
|
3954
|
+
}
|
|
3955
|
+
} catch {
|
|
3956
|
+
continue;
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
const filtered = excludePrefixes?.length ? allFiles.filter((entry) => !excludePrefixes.some((prefix) => entry.relPath === prefix || entry.relPath.startsWith(prefix + "/"))) : allFiles;
|
|
3960
|
+
const dirty = [];
|
|
3961
|
+
for (const entry of filtered) {
|
|
3962
|
+
const storedMtime = storedFileData?.mtimes[entry.relPath];
|
|
3963
|
+
const storedHash = storedFileData?.hashes[entry.relPath];
|
|
3964
|
+
if (storedMtime !== void 0 && storedHash !== void 0 && entry.mtimeMs === storedMtime) {
|
|
3965
|
+
fileHashes[entry.relPath] = storedHash;
|
|
3966
|
+
} else {
|
|
3967
|
+
dirty.push(entry);
|
|
3968
|
+
}
|
|
3969
|
+
fileMtimes[entry.relPath] = entry.mtimeMs;
|
|
3970
|
+
}
|
|
3971
|
+
const BATCH_SIZE = 256;
|
|
3972
|
+
for (let i = 0; i < dirty.length; i += BATCH_SIZE) {
|
|
3973
|
+
const batch = dirty.slice(i, i + BATCH_SIZE);
|
|
3974
|
+
const hashes = await Promise.all(batch.map((e) => hashFile(e.absPath)));
|
|
3975
|
+
for (let j = 0; j < batch.length; j++) {
|
|
3976
|
+
fileHashes[batch[j].relPath] = hashes[j];
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
const sorted = Object.entries(fileHashes).sort(([a], [b]) => a.localeCompare(b));
|
|
3980
|
+
const digest = sorted.map(([p2, h]) => `${p2}:${h}`).join("\n");
|
|
3981
|
+
const canonicalHash = hashString(digest);
|
|
3982
|
+
return { canonicalHash, fileHashes, fileMtimes };
|
|
3983
|
+
}
|
|
3984
|
+
async function collectDirectoryFilePaths(directoryPath, rootDirectoryPath, options) {
|
|
3985
|
+
let stack = options.gitignoreStack ?? [];
|
|
3986
|
+
try {
|
|
3987
|
+
const localContent = await readFile14(path15.join(directoryPath, ".gitignore"), "utf-8");
|
|
3988
|
+
const localMatcher = ignoreFactory();
|
|
3989
|
+
localMatcher.add(localContent);
|
|
3990
|
+
stack = [...stack, { basePath: directoryPath, matcher: localMatcher }];
|
|
3991
|
+
} catch {
|
|
3992
|
+
}
|
|
3993
|
+
const entries = await readdir6(directoryPath, { withFileTypes: true });
|
|
3994
|
+
const dirs = [];
|
|
3995
|
+
const files = [];
|
|
3996
|
+
for (const entry of entries) {
|
|
3997
|
+
const absoluteChildPath = path15.join(directoryPath, entry.name);
|
|
3998
|
+
if (isIgnoredByStack(absoluteChildPath, stack)) continue;
|
|
3999
|
+
if (entry.isDirectory()) dirs.push(absoluteChildPath);
|
|
4000
|
+
else if (entry.isFile()) files.push(absoluteChildPath);
|
|
4001
|
+
}
|
|
4002
|
+
const [dirResults, fileStats] = await Promise.all([
|
|
4003
|
+
Promise.all(dirs.map((d) => collectDirectoryFilePaths(d, rootDirectoryPath, {
|
|
4004
|
+
projectRoot: options.projectRoot,
|
|
4005
|
+
gitignoreStack: stack
|
|
4006
|
+
}))),
|
|
4007
|
+
Promise.all(files.map(async (f) => {
|
|
4008
|
+
const fileStat = await stat5(f);
|
|
4009
|
+
return {
|
|
4010
|
+
relPath: path15.relative(rootDirectoryPath, f).replace(/\\/g, "/").replace(/\/+$/, ""),
|
|
4011
|
+
absPath: f,
|
|
4012
|
+
mtimeMs: fileStat.mtimeMs
|
|
4013
|
+
};
|
|
4014
|
+
}))
|
|
4015
|
+
]);
|
|
4016
|
+
const result = [];
|
|
4017
|
+
for (const nested of dirResults) result.push(...nested);
|
|
4018
|
+
result.push(...fileStats);
|
|
4019
|
+
return result;
|
|
4020
|
+
}
|
|
4021
|
+
async function expandMappingPaths(projectRoot, mappingPaths) {
|
|
4022
|
+
const gitignoreStack = await loadRootGitignoreStack(projectRoot);
|
|
4023
|
+
const result = [];
|
|
4024
|
+
for (const mp of mappingPaths) {
|
|
4025
|
+
const absPath = path15.join(projectRoot, mp);
|
|
4026
|
+
try {
|
|
4027
|
+
const st = await stat5(absPath);
|
|
4028
|
+
if (st.isDirectory()) {
|
|
4029
|
+
const dirEntries = await collectDirectoryFilePaths(absPath, absPath, {
|
|
4030
|
+
projectRoot,
|
|
4031
|
+
gitignoreStack
|
|
4032
|
+
});
|
|
4033
|
+
for (const entry of dirEntries) {
|
|
4034
|
+
result.push(path15.join(mp, entry.relPath).replace(/\\/g, "/").replace(/\/+$/, ""));
|
|
4035
|
+
}
|
|
4036
|
+
} else {
|
|
4037
|
+
result.push(mp);
|
|
4038
|
+
}
|
|
4039
|
+
} catch {
|
|
4040
|
+
continue;
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
return result;
|
|
4044
|
+
}
|
|
4045
|
+
|
|
3894
4046
|
// src/cli/build-context.ts
|
|
3895
4047
|
function findCandidateNodes(graph, unmappedFile) {
|
|
3896
4048
|
const dir = unmappedFile.replace(/\/[^/]+$/, "");
|
|
@@ -4024,17 +4176,15 @@ ${errorList}`
|
|
|
4024
4176
|
process.stdout.write(formatFileContext(data));
|
|
4025
4177
|
} else {
|
|
4026
4178
|
const data = buildNodeContextData(graph, nodePath);
|
|
4179
|
+
const projectRoot = projectRootFromGraph(graph.rootPath);
|
|
4180
|
+
data.sourceFiles = await expandMappingPaths(projectRoot, data.sourceFiles);
|
|
4027
4181
|
process.stdout.write(formatNodeContext(data));
|
|
4028
4182
|
}
|
|
4029
4183
|
} catch (error) {
|
|
4030
4184
|
const err = error;
|
|
4031
4185
|
if (err.code === "ENOENT") {
|
|
4032
4186
|
process.stderr.write(
|
|
4033
|
-
chalk3.red(
|
|
4034
|
-
what: "No .yggdrasil/ directory found.",
|
|
4035
|
-
why: "Yggdrasil is not initialized in this project.",
|
|
4036
|
-
next: "Run 'yg init' to initialize."
|
|
4037
|
-
}) + "\n")
|
|
4187
|
+
chalk3.red("Error: No .yggdrasil/ directory found. Run 'yg init' first.\n")
|
|
4038
4188
|
);
|
|
4039
4189
|
} else {
|
|
4040
4190
|
process.stderr.write(chalk3.red(`Error: ${error.message}
|
|
@@ -4049,31 +4199,30 @@ ${errorList}`
|
|
|
4049
4199
|
// src/cli/approve.ts
|
|
4050
4200
|
import chalk4 from "chalk";
|
|
4051
4201
|
import path20 from "path";
|
|
4052
|
-
import { readFile as readFile18 } from "fs/promises";
|
|
4053
4202
|
|
|
4054
4203
|
// src/io/drift-state-store.ts
|
|
4055
|
-
import { readFile as
|
|
4056
|
-
import
|
|
4204
|
+
import { readFile as readFile15, writeFile as writeFile5, stat as stat6, readdir as readdir7, mkdir as mkdir3, rm as rm2 } from "fs/promises";
|
|
4205
|
+
import path16 from "path";
|
|
4057
4206
|
var DRIFT_STATE_DIR = ".drift-state";
|
|
4058
4207
|
function nodeStatePath(yggRoot, nodePath) {
|
|
4059
|
-
return
|
|
4208
|
+
return path16.join(yggRoot, DRIFT_STATE_DIR, `${nodePath}.json`);
|
|
4060
4209
|
}
|
|
4061
4210
|
async function scanJsonFiles(dir, baseDir) {
|
|
4062
4211
|
const results = [];
|
|
4063
4212
|
let entries;
|
|
4064
4213
|
try {
|
|
4065
|
-
entries = await
|
|
4214
|
+
entries = await readdir7(dir, { withFileTypes: true });
|
|
4066
4215
|
} catch (err) {
|
|
4067
4216
|
debugWrite(`[drift-state-store] scanJsonFiles readdir: ${err.message}`);
|
|
4068
4217
|
return results;
|
|
4069
4218
|
}
|
|
4070
4219
|
for (const entry of entries) {
|
|
4071
|
-
const fullPath =
|
|
4220
|
+
const fullPath = path16.join(dir, entry.name);
|
|
4072
4221
|
if (entry.isDirectory()) {
|
|
4073
4222
|
const nested = await scanJsonFiles(fullPath, baseDir);
|
|
4074
4223
|
results.push(...nested);
|
|
4075
4224
|
} else if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
4076
|
-
const relPath =
|
|
4225
|
+
const relPath = path16.relative(baseDir, fullPath);
|
|
4077
4226
|
const nodePath = relPath.replace(/\\/g, "/").replace(/\.json$/, "");
|
|
4078
4227
|
results.push(nodePath);
|
|
4079
4228
|
}
|
|
@@ -4081,13 +4230,13 @@ async function scanJsonFiles(dir, baseDir) {
|
|
|
4081
4230
|
return results;
|
|
4082
4231
|
}
|
|
4083
4232
|
async function removeEmptyParents(filePath, stopDir) {
|
|
4084
|
-
let dir =
|
|
4233
|
+
let dir = path16.dirname(filePath);
|
|
4085
4234
|
while (dir !== stopDir && dir.startsWith(stopDir)) {
|
|
4086
4235
|
try {
|
|
4087
|
-
const entries = await
|
|
4236
|
+
const entries = await readdir7(dir);
|
|
4088
4237
|
if (entries.length === 0) {
|
|
4089
4238
|
await rm2(dir, { recursive: true });
|
|
4090
|
-
dir =
|
|
4239
|
+
dir = path16.dirname(dir);
|
|
4091
4240
|
} else {
|
|
4092
4241
|
break;
|
|
4093
4242
|
}
|
|
@@ -4100,7 +4249,7 @@ async function removeEmptyParents(filePath, stopDir) {
|
|
|
4100
4249
|
async function readNodeDriftState(yggRoot, nodePath) {
|
|
4101
4250
|
try {
|
|
4102
4251
|
const filePath = nodeStatePath(yggRoot, nodePath);
|
|
4103
|
-
const content = await
|
|
4252
|
+
const content = await readFile15(filePath, "utf-8");
|
|
4104
4253
|
const parsed = JSON.parse(content);
|
|
4105
4254
|
return parsed;
|
|
4106
4255
|
} catch (err) {
|
|
@@ -4110,12 +4259,12 @@ async function readNodeDriftState(yggRoot, nodePath) {
|
|
|
4110
4259
|
}
|
|
4111
4260
|
async function writeNodeDriftState(yggRoot, nodePath, nodeState) {
|
|
4112
4261
|
const filePath = nodeStatePath(yggRoot, nodePath);
|
|
4113
|
-
await mkdir3(
|
|
4262
|
+
await mkdir3(path16.dirname(filePath), { recursive: true });
|
|
4114
4263
|
const content = JSON.stringify(nodeState, null, 2) + "\n";
|
|
4115
4264
|
await writeFile5(filePath, content, "utf-8");
|
|
4116
4265
|
}
|
|
4117
4266
|
async function garbageCollectDriftState(yggRoot, validNodePaths) {
|
|
4118
|
-
const driftDir =
|
|
4267
|
+
const driftDir = path16.join(yggRoot, DRIFT_STATE_DIR);
|
|
4119
4268
|
const allNodePaths = await scanJsonFiles(driftDir, driftDir);
|
|
4120
4269
|
const removed = [];
|
|
4121
4270
|
for (const nodePath of allNodePaths) {
|
|
@@ -4129,10 +4278,10 @@ async function garbageCollectDriftState(yggRoot, validNodePaths) {
|
|
|
4129
4278
|
return removed.sort();
|
|
4130
4279
|
}
|
|
4131
4280
|
async function readDriftState(yggRoot) {
|
|
4132
|
-
const driftPath =
|
|
4281
|
+
const driftPath = path16.join(yggRoot, DRIFT_STATE_DIR);
|
|
4133
4282
|
let driftStat;
|
|
4134
4283
|
try {
|
|
4135
|
-
driftStat = await
|
|
4284
|
+
driftStat = await stat6(driftPath);
|
|
4136
4285
|
} catch (err) {
|
|
4137
4286
|
debugWrite(`[drift-state-store] readDriftState stat: ${err.message}`);
|
|
4138
4287
|
return {};
|
|
@@ -4152,134 +4301,6 @@ async function readDriftState(yggRoot) {
|
|
|
4152
4301
|
return state;
|
|
4153
4302
|
}
|
|
4154
4303
|
|
|
4155
|
-
// src/utils/hash.ts
|
|
4156
|
-
import { readFile as readFile15, readdir as readdir7, stat as stat6 } from "fs/promises";
|
|
4157
|
-
import path16 from "path";
|
|
4158
|
-
import { createHash } from "crypto";
|
|
4159
|
-
import { createRequire } from "module";
|
|
4160
|
-
var require2 = createRequire(import.meta.url);
|
|
4161
|
-
var ignoreFactory = require2("ignore");
|
|
4162
|
-
async function hashFile(filePath) {
|
|
4163
|
-
const content = await readFile15(filePath);
|
|
4164
|
-
return createHash("sha256").update(content).digest("hex");
|
|
4165
|
-
}
|
|
4166
|
-
async function loadRootGitignoreStack(projectRoot) {
|
|
4167
|
-
if (!projectRoot) return [];
|
|
4168
|
-
try {
|
|
4169
|
-
const content = await readFile15(path16.join(projectRoot, ".gitignore"), "utf-8");
|
|
4170
|
-
const matcher = ignoreFactory();
|
|
4171
|
-
matcher.add(content);
|
|
4172
|
-
return [{ basePath: projectRoot, matcher }];
|
|
4173
|
-
} catch {
|
|
4174
|
-
return [];
|
|
4175
|
-
}
|
|
4176
|
-
}
|
|
4177
|
-
function isIgnoredByStack(candidatePath, stack) {
|
|
4178
|
-
for (const { basePath, matcher } of stack) {
|
|
4179
|
-
const relativePath = path16.relative(basePath, candidatePath);
|
|
4180
|
-
if (relativePath === "" || relativePath.startsWith("..")) continue;
|
|
4181
|
-
if (matcher.ignores(relativePath) || matcher.ignores(relativePath + "/")) return true;
|
|
4182
|
-
}
|
|
4183
|
-
return false;
|
|
4184
|
-
}
|
|
4185
|
-
function hashString(content) {
|
|
4186
|
-
return createHash("sha256").update(content).digest("hex");
|
|
4187
|
-
}
|
|
4188
|
-
async function hashTrackedFiles(projectRoot, trackedFiles, storedFileData, excludePrefixes) {
|
|
4189
|
-
const fileHashes = {};
|
|
4190
|
-
const fileMtimes = {};
|
|
4191
|
-
const gitignoreStack = await loadRootGitignoreStack(projectRoot);
|
|
4192
|
-
const allFiles = [];
|
|
4193
|
-
for (const tf of trackedFiles) {
|
|
4194
|
-
if (tf.syntheticHash) {
|
|
4195
|
-
fileHashes[tf.path] = tf.syntheticHash;
|
|
4196
|
-
continue;
|
|
4197
|
-
}
|
|
4198
|
-
const absPath = path16.join(projectRoot, tf.path);
|
|
4199
|
-
try {
|
|
4200
|
-
const st = await stat6(absPath);
|
|
4201
|
-
if (st.isDirectory()) {
|
|
4202
|
-
const dirEntries = await collectDirectoryFilePaths(absPath, absPath, {
|
|
4203
|
-
projectRoot,
|
|
4204
|
-
gitignoreStack
|
|
4205
|
-
});
|
|
4206
|
-
for (const entry of dirEntries) {
|
|
4207
|
-
allFiles.push({
|
|
4208
|
-
relPath: path16.join(tf.path, entry.relPath).replace(/\\/g, "/").replace(/\/+$/, ""),
|
|
4209
|
-
absPath: entry.absPath,
|
|
4210
|
-
mtimeMs: entry.mtimeMs
|
|
4211
|
-
});
|
|
4212
|
-
}
|
|
4213
|
-
} else {
|
|
4214
|
-
allFiles.push({ relPath: tf.path, absPath, mtimeMs: st.mtimeMs });
|
|
4215
|
-
}
|
|
4216
|
-
} catch {
|
|
4217
|
-
continue;
|
|
4218
|
-
}
|
|
4219
|
-
}
|
|
4220
|
-
const filtered = excludePrefixes?.length ? allFiles.filter((entry) => !excludePrefixes.some((prefix) => entry.relPath === prefix || entry.relPath.startsWith(prefix + "/"))) : allFiles;
|
|
4221
|
-
const dirty = [];
|
|
4222
|
-
for (const entry of filtered) {
|
|
4223
|
-
const storedMtime = storedFileData?.mtimes[entry.relPath];
|
|
4224
|
-
const storedHash = storedFileData?.hashes[entry.relPath];
|
|
4225
|
-
if (storedMtime !== void 0 && storedHash !== void 0 && entry.mtimeMs === storedMtime) {
|
|
4226
|
-
fileHashes[entry.relPath] = storedHash;
|
|
4227
|
-
} else {
|
|
4228
|
-
dirty.push(entry);
|
|
4229
|
-
}
|
|
4230
|
-
fileMtimes[entry.relPath] = entry.mtimeMs;
|
|
4231
|
-
}
|
|
4232
|
-
const BATCH_SIZE = 256;
|
|
4233
|
-
for (let i = 0; i < dirty.length; i += BATCH_SIZE) {
|
|
4234
|
-
const batch = dirty.slice(i, i + BATCH_SIZE);
|
|
4235
|
-
const hashes = await Promise.all(batch.map((e) => hashFile(e.absPath)));
|
|
4236
|
-
for (let j = 0; j < batch.length; j++) {
|
|
4237
|
-
fileHashes[batch[j].relPath] = hashes[j];
|
|
4238
|
-
}
|
|
4239
|
-
}
|
|
4240
|
-
const sorted = Object.entries(fileHashes).sort(([a], [b]) => a.localeCompare(b));
|
|
4241
|
-
const digest = sorted.map(([p2, h]) => `${p2}:${h}`).join("\n");
|
|
4242
|
-
const canonicalHash = hashString(digest);
|
|
4243
|
-
return { canonicalHash, fileHashes, fileMtimes };
|
|
4244
|
-
}
|
|
4245
|
-
async function collectDirectoryFilePaths(directoryPath, rootDirectoryPath, options) {
|
|
4246
|
-
let stack = options.gitignoreStack ?? [];
|
|
4247
|
-
try {
|
|
4248
|
-
const localContent = await readFile15(path16.join(directoryPath, ".gitignore"), "utf-8");
|
|
4249
|
-
const localMatcher = ignoreFactory();
|
|
4250
|
-
localMatcher.add(localContent);
|
|
4251
|
-
stack = [...stack, { basePath: directoryPath, matcher: localMatcher }];
|
|
4252
|
-
} catch {
|
|
4253
|
-
}
|
|
4254
|
-
const entries = await readdir7(directoryPath, { withFileTypes: true });
|
|
4255
|
-
const dirs = [];
|
|
4256
|
-
const files = [];
|
|
4257
|
-
for (const entry of entries) {
|
|
4258
|
-
const absoluteChildPath = path16.join(directoryPath, entry.name);
|
|
4259
|
-
if (isIgnoredByStack(absoluteChildPath, stack)) continue;
|
|
4260
|
-
if (entry.isDirectory()) dirs.push(absoluteChildPath);
|
|
4261
|
-
else if (entry.isFile()) files.push(absoluteChildPath);
|
|
4262
|
-
}
|
|
4263
|
-
const [dirResults, fileStats] = await Promise.all([
|
|
4264
|
-
Promise.all(dirs.map((d) => collectDirectoryFilePaths(d, rootDirectoryPath, {
|
|
4265
|
-
projectRoot: options.projectRoot,
|
|
4266
|
-
gitignoreStack: stack
|
|
4267
|
-
}))),
|
|
4268
|
-
Promise.all(files.map(async (f) => {
|
|
4269
|
-
const fileStat = await stat6(f);
|
|
4270
|
-
return {
|
|
4271
|
-
relPath: path16.relative(rootDirectoryPath, f).replace(/\\/g, "/").replace(/\/+$/, ""),
|
|
4272
|
-
absPath: f,
|
|
4273
|
-
mtimeMs: fileStat.mtimeMs
|
|
4274
|
-
};
|
|
4275
|
-
}))
|
|
4276
|
-
]);
|
|
4277
|
-
const result = [];
|
|
4278
|
-
for (const nested of dirResults) result.push(...nested);
|
|
4279
|
-
result.push(...fileStats);
|
|
4280
|
-
return result;
|
|
4281
|
-
}
|
|
4282
|
-
|
|
4283
4304
|
// src/core/context-files.ts
|
|
4284
4305
|
import path17 from "path";
|
|
4285
4306
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -5760,14 +5781,13 @@ function registerApproveCommand(program2) {
|
|
|
5760
5781
|
}
|
|
5761
5782
|
const aspects = resolveAspects(node2, graph);
|
|
5762
5783
|
const projectRoot = path20.dirname(graph.rootPath);
|
|
5763
|
-
const
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
}
|
|
5784
|
+
const trackedFiles = collectTrackedFiles(node2, graph);
|
|
5785
|
+
const { fileHashes } = await hashTrackedFiles(projectRoot, trackedFiles, void 0, []);
|
|
5786
|
+
const sourceFilePaths = Object.keys(fileHashes).filter((f) => {
|
|
5787
|
+
const normalized = f.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
5788
|
+
return !normalized.startsWith(yggPrefix);
|
|
5789
|
+
});
|
|
5790
|
+
const sourceFiles = await loadSourceFiles(sourceFilePaths, projectRoot);
|
|
5771
5791
|
process.stdout.write(chalk4.bold(`
|
|
5772
5792
|
--- Dry run: ${nodePath2} ---
|
|
5773
5793
|
|
|
@@ -6531,7 +6551,7 @@ function registerFlowsCommand(program2) {
|
|
|
6531
6551
|
|
|
6532
6552
|
// src/cli/check.ts
|
|
6533
6553
|
import chalk9 from "chalk";
|
|
6534
|
-
import {
|
|
6554
|
+
import { execFileSync } from "child_process";
|
|
6535
6555
|
import path21 from "path";
|
|
6536
6556
|
function registerCheckCommand(program2) {
|
|
6537
6557
|
program2.command("check").description("Unified graph gate \u2014 errors, drift, coverage, completeness").action(async () => {
|
|
@@ -6542,7 +6562,7 @@ function registerCheckCommand(program2) {
|
|
|
6542
6562
|
let gitFiles = null;
|
|
6543
6563
|
try {
|
|
6544
6564
|
const projectRoot = path21.dirname(graph.rootPath);
|
|
6545
|
-
const output =
|
|
6565
|
+
const output = execFileSync("git", ["ls-files", "."], {
|
|
6546
6566
|
cwd: projectRoot,
|
|
6547
6567
|
encoding: "utf-8",
|
|
6548
6568
|
stdio: ["pipe", "pipe", "pipe"]
|