@coderook/cli 0.31.7 → 0.31.8
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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "coderook",
|
|
3
3
|
"displayName": "CodeRook",
|
|
4
4
|
"description": "Save, browse and restore whole-snapshot versions of a project on CodeRook, from Claude Code.",
|
|
5
|
-
"version": "0.31.
|
|
5
|
+
"version": "0.31.8",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ACCA Gaming Productions",
|
|
8
8
|
"url": "https://coderook.com"
|
|
@@ -19,6 +19,7 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
19
19
|
const faults_js_1 = require("./faults.js");
|
|
20
20
|
const identify_js_1 = require("./identify.js");
|
|
21
21
|
const worktree_js_1 = require("./worktree.js");
|
|
22
|
+
const rules_js_1 = require("./rules.js");
|
|
22
23
|
const publish_name_js_1 = require("./publish_name.js");
|
|
23
24
|
const compress_js_1 = require("./compress.js");
|
|
24
25
|
const compression_policy_js_1 = require("../shared/compression_policy.js");
|
|
@@ -142,6 +143,8 @@ class Uploader {
|
|
|
142
143
|
*/
|
|
143
144
|
plannedLayouts = new Map();
|
|
144
145
|
plannedQuote = null;
|
|
146
|
+
/** Files sent only because git tracks them; named in the save so the service allows them. */
|
|
147
|
+
trackedByGit = [];
|
|
145
148
|
/*
|
|
146
149
|
Digests worked out while planning, so sending does not work them out again.
|
|
147
150
|
|
|
@@ -407,6 +410,13 @@ class Uploader {
|
|
|
407
410
|
const rules = request.allowIgnored
|
|
408
411
|
? { shared: "", local: "" }
|
|
409
412
|
: await (0, worktree_js_1.readRules)(request.localPath);
|
|
413
|
+
/*
|
|
414
|
+
What the survey keeps only because git tracks it, named for the
|
|
415
|
+
service: its own check of the rules would otherwise refuse them as a
|
|
416
|
+
rule this client forgot. See gitTracked.
|
|
417
|
+
*/
|
|
418
|
+
this.trackedByGit = [];
|
|
419
|
+
const tracked = request.allowIgnored ? null : await (0, worktree_js_1.gitTracked)(request.localPath);
|
|
410
420
|
/*
|
|
411
421
|
Surveyed, not listed.
|
|
412
422
|
|
|
@@ -443,6 +453,12 @@ class Uploader {
|
|
|
443
453
|
percent: 6,
|
|
444
454
|
bytesPerSecond: 0,
|
|
445
455
|
})));
|
|
456
|
+
if (tracked) {
|
|
457
|
+
const layers = await (0, worktree_js_1.collectLayers)(request.localPath, rules);
|
|
458
|
+
this.trackedByGit = everything
|
|
459
|
+
.map((file) => file.path)
|
|
460
|
+
.filter((file) => tracked.files.has(file) && (0, rules_js_1.excludes)(file, false, layers));
|
|
461
|
+
}
|
|
446
462
|
(0, profile_js_1.counted)("files surveyed", everything.length);
|
|
447
463
|
const unticked = new Set(request.excluded ?? []);
|
|
448
464
|
const ticked = request.excluded
|
|
@@ -854,6 +870,7 @@ class Uploader {
|
|
|
854
870
|
: { expectedHeadVersionId: request.expectedHeadVersionId }),
|
|
855
871
|
...(request.track ? { track: request.track } : {}),
|
|
856
872
|
...(request.allowIgnored ? { allowIgnored: true } : {}),
|
|
873
|
+
...(this.trackedByGit.length ? { trackedByGit: this.trackedByGit } : {}),
|
|
857
874
|
...(request.allowSecrets ? { allowSecrets: true } : {}),
|
|
858
875
|
...(request.linesAdded === undefined ? {} : { linesAdded: request.linesAdded }),
|
|
859
876
|
...(request.linesRemoved === undefined
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.IGNORE_HEADING = exports.KEEP_HEADING = exports.LOCAL_EXCLUDE_FILE = exports.IGNORE_FILE = exports.STARTER_IGNORE = exports.CODEROOK_TAIL = exports.CODEROOK_TAIL_HEADING = exports.KEPT_ANYWAY = exports.KEPT_ANYWAY_HEADING = exports.ALSO_LEFT_OUT = exports.ALSO_LEFT_OUT_HEADING = exports.STARTER_MARKER = exports.EVALUATION_FILE_LIMIT = void 0;
|
|
6
|
+
exports.IGNORE_HEADING = exports.KEEP_HEADING = exports.TRACKED_BY_GIT = exports.LOCAL_EXCLUDE_FILE = exports.IGNORE_FILE = exports.STARTER_IGNORE = exports.CODEROOK_TAIL = exports.CODEROOK_TAIL_HEADING = exports.KEPT_ANYWAY = exports.KEPT_ANYWAY_HEADING = exports.ALSO_LEFT_OUT = exports.ALSO_LEFT_OUT_HEADING = exports.STARTER_MARKER = exports.EVALUATION_FILE_LIMIT = void 0;
|
|
7
7
|
exports.ruleTarget = ruleTarget;
|
|
8
8
|
exports.keptTargets = keptTargets;
|
|
9
9
|
exports.withoutOpposites = withoutOpposites;
|
|
@@ -11,6 +11,7 @@ exports.starterAuthored = starterAuthored;
|
|
|
11
11
|
exports.missingStarterRules = missingStarterRules;
|
|
12
12
|
exports.missingEngineRules = missingEngineRules;
|
|
13
13
|
exports.isRepository = isRepository;
|
|
14
|
+
exports.gitTracked = gitTracked;
|
|
14
15
|
exports.migrateRetiredRules = migrateRetiredRules;
|
|
15
16
|
exports.starterFor = starterFor;
|
|
16
17
|
exports.moveRule = moveRule;
|
|
@@ -404,6 +405,39 @@ async function isRepository(root) {
|
|
|
404
405
|
return false;
|
|
405
406
|
}
|
|
406
407
|
}
|
|
408
|
+
/** The label a file kept because git tracks it carries, where a rule would be. */
|
|
409
|
+
exports.TRACKED_BY_GIT = "(tracked by git)";
|
|
410
|
+
/**
|
|
411
|
+
* The files git tracks here, which an ignore rule does not take away.
|
|
412
|
+
*
|
|
413
|
+
* Git applies .gitignore only to files it does not track yet. Once a file is
|
|
414
|
+
* committed, a rule written later — or a broad one like `storage/` that also
|
|
415
|
+
* matches a source folder three levels down — leaves it exactly where it is.
|
|
416
|
+
* This applied the rules to everything, so a project whose .gitignore said
|
|
417
|
+
* `storage/` arrived without `internal/storage/*.go`: in git, whole; on
|
|
418
|
+
* CodeRook, missing the six files that made it build.
|
|
419
|
+
*
|
|
420
|
+
* Null when the folder is not a repository, or git cannot be asked — then the
|
|
421
|
+
* rules alone decide, as they always did.
|
|
422
|
+
*/
|
|
423
|
+
async function gitTracked(root) {
|
|
424
|
+
if (!(await isRepository(root)))
|
|
425
|
+
return null;
|
|
426
|
+
const listed = await git(root, "ls-files", "-z");
|
|
427
|
+
if (listed === null)
|
|
428
|
+
return null;
|
|
429
|
+
const files = new Set(listed.split(String.fromCharCode(0)).filter(Boolean));
|
|
430
|
+
const folders = new Set();
|
|
431
|
+
for (const file of files) {
|
|
432
|
+
for (let cut = file.lastIndexOf("/"); cut > 0; cut = file.lastIndexOf("/", cut - 1)) {
|
|
433
|
+
const folder = file.slice(0, cut);
|
|
434
|
+
if (folders.has(folder))
|
|
435
|
+
break;
|
|
436
|
+
folders.add(folder);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return { files, folders };
|
|
440
|
+
}
|
|
407
441
|
/**
|
|
408
442
|
* Convert the rules an earlier build wrote into one .gitignore.
|
|
409
443
|
*
|
|
@@ -519,6 +553,15 @@ async function moveRule(root, file, keep) {
|
|
|
519
553
|
const directory = await (0, promises_1.stat)(node_path_1.default.join(root, bare))
|
|
520
554
|
.then((entry) => entry.isDirectory())
|
|
521
555
|
.catch(() => file.endsWith("/"));
|
|
556
|
+
/*
|
|
557
|
+
A file git tracks cannot be ignored by a rule — git keeps it, and so does
|
|
558
|
+
this. Writing the rule anyway would look like it worked and change
|
|
559
|
+
nothing, so it is refused with what would actually leave it out.
|
|
560
|
+
*/
|
|
561
|
+
if (!keep && !directory && (await gitTracked(root))?.files.has(bare)) {
|
|
562
|
+
throw new Error(`git tracks ${bare}, so a rule cannot leave it out. Untick it for one ` +
|
|
563
|
+
`save, or stop git tracking it: git rm --cached "${bare}"`);
|
|
564
|
+
}
|
|
522
565
|
const target = directory ? `${bare}/` : bare;
|
|
523
566
|
const line = keep ? `!${target}` : target;
|
|
524
567
|
/*
|
|
@@ -885,6 +928,8 @@ stats,
|
|
|
885
928
|
/** Filled with how much of the folder the cap allowed through. */
|
|
886
929
|
outcome) {
|
|
887
930
|
const layers = await collectLayers(root, rules);
|
|
931
|
+
/* What git already tracks goes up whatever a rule says; see gitTracked. */
|
|
932
|
+
const tracked = await gitTracked(root);
|
|
888
933
|
const files = [];
|
|
889
934
|
const present = new Set();
|
|
890
935
|
const pending = [root];
|
|
@@ -926,7 +971,9 @@ outcome) {
|
|
|
926
971
|
// Skipping an excluded directory outright is what keeps this fast,
|
|
927
972
|
// but a `!` rule exists to rescue what is inside one, so the subtree
|
|
928
973
|
// is only skipped when no negation could reach into it.
|
|
929
|
-
if ((0, rules_js_1.excludes)(relative, true, layers) &&
|
|
974
|
+
if ((0, rules_js_1.excludes)(relative, true, layers) &&
|
|
975
|
+
!(0, rules_js_1.negationReachesInto)(relative, layers) &&
|
|
976
|
+
!tracked?.folders.has(relative)) {
|
|
930
977
|
continue;
|
|
931
978
|
}
|
|
932
979
|
pending.push(full);
|
|
@@ -934,7 +981,7 @@ outcome) {
|
|
|
934
981
|
}
|
|
935
982
|
if (!entry.isFile())
|
|
936
983
|
continue;
|
|
937
|
-
if ((0, rules_js_1.excludes)(relative, false, layers))
|
|
984
|
+
if ((0, rules_js_1.excludes)(relative, false, layers) && !tracked?.files.has(relative))
|
|
938
985
|
continue;
|
|
939
986
|
wanted.push({ full, relative });
|
|
940
987
|
}
|
|
@@ -1060,6 +1107,7 @@ async function surveyFiles(root, rules,
|
|
|
1060
1107
|
*/
|
|
1061
1108
|
onFound) {
|
|
1062
1109
|
const layers = await collectLayers(root, rules);
|
|
1110
|
+
const tracked = await gitTracked(root);
|
|
1063
1111
|
const found = [];
|
|
1064
1112
|
/*
|
|
1065
1113
|
A level at a time, eight in flight.
|
|
@@ -1094,7 +1142,8 @@ onFound) {
|
|
|
1094
1142
|
const relative = node_path_1.default.relative(root, full).split(node_path_1.default.sep).join("/");
|
|
1095
1143
|
if (entry.isDirectory()) {
|
|
1096
1144
|
if ((0, rules_js_1.excludes)(relative, true, layers) &&
|
|
1097
|
-
!(0, rules_js_1.negationReachesInto)(relative, layers)
|
|
1145
|
+
!(0, rules_js_1.negationReachesInto)(relative, layers) &&
|
|
1146
|
+
!tracked?.folders.has(relative)) {
|
|
1098
1147
|
continue;
|
|
1099
1148
|
}
|
|
1100
1149
|
next.push(full);
|
|
@@ -1102,7 +1151,7 @@ onFound) {
|
|
|
1102
1151
|
}
|
|
1103
1152
|
if (!entry.isFile())
|
|
1104
1153
|
continue;
|
|
1105
|
-
if ((0, rules_js_1.excludes)(relative, false, layers))
|
|
1154
|
+
if ((0, rules_js_1.excludes)(relative, false, layers) && !tracked?.files.has(relative))
|
|
1106
1155
|
continue;
|
|
1107
1156
|
here.push({ full, relative });
|
|
1108
1157
|
}
|
|
@@ -1408,6 +1457,7 @@ function relativeTo(root, full) {
|
|
|
1408
1457
|
*/
|
|
1409
1458
|
async function evaluateRules(root, rules, options = {}) {
|
|
1410
1459
|
const layers = await collectLayers(root, rules);
|
|
1460
|
+
const tracked = await gitTracked(root);
|
|
1411
1461
|
const impactBytes = new Map();
|
|
1412
1462
|
const impactFiles = new Map();
|
|
1413
1463
|
const excluded = [];
|
|
@@ -1449,6 +1499,18 @@ async function evaluateRules(root, rules, options = {}) {
|
|
|
1449
1499
|
});
|
|
1450
1500
|
continue;
|
|
1451
1501
|
}
|
|
1502
|
+
if (rule && tracked?.files.has(relative)) {
|
|
1503
|
+
/*
|
|
1504
|
+
A rule matches it, and git tracks it, so it goes up regardless — and
|
|
1505
|
+
is listed with what kept it, beside the files a `!` rule keeps.
|
|
1506
|
+
*/
|
|
1507
|
+
keptFiles += 1;
|
|
1508
|
+
keptBytes += size;
|
|
1509
|
+
uploadFiles += 1;
|
|
1510
|
+
uploadBytes += size;
|
|
1511
|
+
excluded.push({ path: relative, bytes: size, rule: exports.TRACKED_BY_GIT, forceKept: true });
|
|
1512
|
+
continue;
|
|
1513
|
+
}
|
|
1452
1514
|
if (rule) {
|
|
1453
1515
|
skippedFiles += 1;
|
|
1454
1516
|
skippedBytes += size;
|