@coderook/cli 0.44.0 → 0.46.0
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/.claude-plugin/plugin.json +1 -1
- package/dist/cbx/src/core/upload.js +40 -0
- package/dist/cbx/src/core/worktree.js +77 -10
- package/dist/cbx/src/local/history.js +6 -3
- package/dist/cbx/src/local/snapshot.js +99 -22
- package/dist/cbx/src/local/store.js +26 -0
- package/dist/cbx/src/shared/native_engine.js +267 -0
- package/dist/cli/src/api.js +2 -0
- package/dist/cli/src/bin.js +86 -0
- package/dist/cli/src/cli.js +40 -2
- package/dist/cli/src/local_commands.js +68 -116
- package/dist/cli/src/local_status.js +72 -0
- package/dist/cli/src/network.js +21 -7
- package/dist/cli/src/project_commands.js +10 -4
- package/dist/cli/src/registry.js +1 -1
- package/dist/cli/src/reminder_gate.js +37 -0
- package/dist/cli/src/update_command.js +160 -0
- package/dist/cli/src/workspace_threads.js +3 -13
- package/engine-bin/darwin-arm64/cbx-engine +0 -0
- package/engine-bin/darwin-x64/cbx-engine +0 -0
- package/engine-bin/linux-arm64/cbx-engine +0 -0
- package/engine-bin/linux-x64/cbx-engine +0 -0
- package/engine-bin/win32-x64/cbx-engine.exe +0 -0
- package/package.json +5 -4
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ENGINE_SCAN_MIN_FILES = exports.ENGINE_MIN_BYTES = exports.ENGINE_MIN_FILES = void 0;
|
|
7
|
+
exports.enginePath = enginePath;
|
|
8
|
+
exports.engineProblem = engineProblem;
|
|
9
|
+
exports.worthTheEngine = worthTheEngine;
|
|
10
|
+
exports.engineStore = engineStore;
|
|
11
|
+
exports.engineMeasure = engineMeasure;
|
|
12
|
+
exports.engineScan = engineScan;
|
|
13
|
+
exports.resetEngineForTests = resetEngineForTests;
|
|
14
|
+
/**
|
|
15
|
+
* The native byte engine (cbx/engine, Rust), when there is one.
|
|
16
|
+
*
|
|
17
|
+
* The engine does the same byte work as the TypeScript here — hashing, cutting
|
|
18
|
+
* big files, framing and packing objects — with the same results: the same
|
|
19
|
+
* SHA-256 names, the same chunk cuts, the same "cbx-local 1" store. It is only
|
|
20
|
+
* faster, because it reads, hashes and compresses on every core at once. The
|
|
21
|
+
* cross-tests in cbx/engine/compat compare the two on real folders.
|
|
22
|
+
*
|
|
23
|
+
* It is optional. Every caller keeps its own TypeScript path and uses it
|
|
24
|
+
* whenever this returns null: no engine for this platform, CBX_ENGINE=off, a
|
|
25
|
+
* failed run, or an answer that does not look right. A run that fails once is
|
|
26
|
+
* not tried again in the same process, so a broken binary costs one attempt.
|
|
27
|
+
*
|
|
28
|
+
* Where it is looked for:
|
|
29
|
+
* CBX_ENGINE=<path> that binary ("off" turns the engine off)
|
|
30
|
+
* engine-bin/<platform>-<arch>/cbx-engine[.exe] in this package or a folder above it
|
|
31
|
+
*/
|
|
32
|
+
const node_child_process_1 = require("node:child_process");
|
|
33
|
+
const node_fs_1 = require("node:fs");
|
|
34
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
35
|
+
/** The engine's command protocol this code speaks; `cbx-engine version` reports its own. */
|
|
36
|
+
const PROTOCOL = 1;
|
|
37
|
+
/** Below this much work, starting a process costs more than it saves. */
|
|
38
|
+
exports.ENGINE_MIN_FILES = 24;
|
|
39
|
+
exports.ENGINE_MIN_BYTES = 32 * 1024 * 1024;
|
|
40
|
+
/** Below this many files a folder is walked faster here than by starting the engine. */
|
|
41
|
+
exports.ENGINE_SCAN_MIN_FILES = 400;
|
|
42
|
+
let located;
|
|
43
|
+
let broken = null;
|
|
44
|
+
function binaryName() {
|
|
45
|
+
return process.platform === "win32" ? "cbx-engine.exe" : "cbx-engine";
|
|
46
|
+
}
|
|
47
|
+
/*
|
|
48
|
+
Whether the binary may be run, making it so when it can be.
|
|
49
|
+
|
|
50
|
+
A package packed on Windows carries no execute bit, so on macOS and Linux the
|
|
51
|
+
engine arrives as a plain file. Setting the bit is all it needs; where the
|
|
52
|
+
install folder is not ours to change, the TypeScript path is used instead.
|
|
53
|
+
*/
|
|
54
|
+
function runnable(candidate) {
|
|
55
|
+
if (process.platform === "win32")
|
|
56
|
+
return true;
|
|
57
|
+
try {
|
|
58
|
+
(0, node_fs_1.accessSync)(candidate, node_fs_1.constants.X_OK);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
try {
|
|
63
|
+
(0, node_fs_1.chmodSync)(candidate, 0o755);
|
|
64
|
+
(0, node_fs_1.accessSync)(candidate, node_fs_1.constants.X_OK);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Where the engine is, or null when there is none to use. */
|
|
73
|
+
function enginePath() {
|
|
74
|
+
if (located !== undefined)
|
|
75
|
+
return located;
|
|
76
|
+
const chosen = process.env.CBX_ENGINE?.trim();
|
|
77
|
+
if (chosen === "off" || chosen === "0" || chosen === "false")
|
|
78
|
+
return (located = null);
|
|
79
|
+
if (chosen)
|
|
80
|
+
return (located = (0, node_fs_1.existsSync)(chosen) ? chosen : null);
|
|
81
|
+
/* CommonJS here; in an ES module build __dirname is not defined and only CBX_ENGINE applies. */
|
|
82
|
+
let directory = typeof __dirname === "string" ? __dirname : null;
|
|
83
|
+
const wanted = node_path_1.default.join("engine-bin", `${process.platform}-${process.arch}`, binaryName());
|
|
84
|
+
for (let depth = 0; directory && depth < 8; depth += 1) {
|
|
85
|
+
const candidate = node_path_1.default.join(directory, wanted);
|
|
86
|
+
if ((0, node_fs_1.existsSync)(candidate))
|
|
87
|
+
return (located = runnable(candidate) ? candidate : null);
|
|
88
|
+
const parent = node_path_1.default.dirname(directory);
|
|
89
|
+
directory = parent === directory ? null : parent;
|
|
90
|
+
}
|
|
91
|
+
return (located = null);
|
|
92
|
+
}
|
|
93
|
+
/** Why the engine is not being used, for diagnostics; null when it is available. */
|
|
94
|
+
function engineProblem() {
|
|
95
|
+
if (broken)
|
|
96
|
+
return broken;
|
|
97
|
+
return enginePath() ? null : "no engine for this platform";
|
|
98
|
+
}
|
|
99
|
+
/** Whether a batch of this size is worth handing to the engine. */
|
|
100
|
+
function worthTheEngine(files, bytes) {
|
|
101
|
+
if (enginePath() === null || broken || files === 0)
|
|
102
|
+
return false;
|
|
103
|
+
/* CBX_ENGINE_ALWAYS=1 sends every batch, however small, so tests can run everything through it. */
|
|
104
|
+
if (process.env.CBX_ENGINE_ALWAYS === "1")
|
|
105
|
+
return true;
|
|
106
|
+
return files >= exports.ENGINE_MIN_FILES || bytes >= exports.ENGINE_MIN_BYTES;
|
|
107
|
+
}
|
|
108
|
+
function run(args, input, onLine, signal) {
|
|
109
|
+
const binary = enginePath();
|
|
110
|
+
return new Promise((resolve) => {
|
|
111
|
+
let child;
|
|
112
|
+
try {
|
|
113
|
+
child = (0, node_child_process_1.spawn)(binary, args, { stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
resolve({ stdout: "", stderr: String(error), code: -1 });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
/* Cancelling the operation stops the engine with it. */
|
|
120
|
+
const stop = () => child.kill();
|
|
121
|
+
if (signal?.aborted)
|
|
122
|
+
stop();
|
|
123
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
124
|
+
child.on("close", () => signal?.removeEventListener("abort", stop));
|
|
125
|
+
const out = [];
|
|
126
|
+
let err = "";
|
|
127
|
+
let partial = "";
|
|
128
|
+
child.stdout.on("data", (data) => out.push(data));
|
|
129
|
+
child.stderr.on("data", (data) => {
|
|
130
|
+
const text = partial + data.toString("utf8");
|
|
131
|
+
const lines = text.split("\n");
|
|
132
|
+
partial = lines.pop() ?? "";
|
|
133
|
+
for (const line of lines) {
|
|
134
|
+
if (onLine && line.startsWith("{"))
|
|
135
|
+
onLine(line);
|
|
136
|
+
else
|
|
137
|
+
err += `${line}\n`;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
child.on("error", (error) => resolve({ stdout: "", stderr: String(error), code: -1 }));
|
|
141
|
+
child.on("close", (code) => resolve({ stdout: Buffer.concat(out).toString("utf8"), stderr: err + partial, code }));
|
|
142
|
+
child.stdin.on("error", () => {
|
|
143
|
+
/* The engine exited before reading; its exit code says why. */
|
|
144
|
+
});
|
|
145
|
+
child.stdin.end(input ?? "");
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/*
|
|
149
|
+
Every answer carries the protocol it speaks, so an engine from another
|
|
150
|
+
release is caught on its first answer without a separate process to ask.
|
|
151
|
+
*/
|
|
152
|
+
function usable() {
|
|
153
|
+
return Boolean(enginePath()) && !broken;
|
|
154
|
+
}
|
|
155
|
+
async function ask(args, input, onLine, signal) {
|
|
156
|
+
if (!usable())
|
|
157
|
+
return null;
|
|
158
|
+
const answer = await run(args, JSON.stringify(input), onLine, signal);
|
|
159
|
+
/* Stopped on purpose is not a broken engine; the caller sees its own cancellation. */
|
|
160
|
+
if (signal?.aborted)
|
|
161
|
+
return null;
|
|
162
|
+
if (answer.code !== 0) {
|
|
163
|
+
broken = `cbx-engine ${args[0]} failed: ${answer.stderr.trim().slice(0, 300)}`;
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
let parsed = null;
|
|
167
|
+
try {
|
|
168
|
+
parsed = JSON.parse(answer.stdout);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
broken = `cbx-engine ${args[0]} gave an answer that is not JSON`;
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
if (parsed?.protocol !== PROTOCOL) {
|
|
175
|
+
broken = `engine at ${enginePath()} does not speak protocol ${PROTOCOL}`;
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
return parsed;
|
|
179
|
+
}
|
|
180
|
+
const progressFrom = (report) => report
|
|
181
|
+
? (line) => {
|
|
182
|
+
try {
|
|
183
|
+
const parsed = JSON.parse(line);
|
|
184
|
+
report(parsed.done, parsed.total, parsed.path);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
/* A line that is not progress; ignored. */
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
: undefined;
|
|
191
|
+
/**
|
|
192
|
+
* Store files into a "cbx-local 1" object store, as `storeFile` does for each.
|
|
193
|
+
*
|
|
194
|
+
* Null when the engine is not available or the run failed; a file the engine
|
|
195
|
+
* could not read comes back with `error`, for the caller's own path to retry
|
|
196
|
+
* and report. Objects are on disk (packs flushed) when this returns.
|
|
197
|
+
*/
|
|
198
|
+
async function engineStore(objectsDirectory, root, files, progress, signal) {
|
|
199
|
+
const answer = await ask(["store", objectsDirectory, root, ...(progress ? ["--progress"] : [])], files, progressFrom(progress), signal);
|
|
200
|
+
if (!answer || !Array.isArray(answer.files) || answer.files.length !== files.length) {
|
|
201
|
+
if (answer)
|
|
202
|
+
broken = "cbx-engine store answered for the wrong number of files";
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
const byPath = new Map();
|
|
206
|
+
for (const one of answer.files)
|
|
207
|
+
byPath.set(one.path, one);
|
|
208
|
+
return byPath;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Digests of many files at once; with `count`, also lines and whether the file is binary,
|
|
212
|
+
* worked out as `measure` in core/worktree.ts does.
|
|
213
|
+
*/
|
|
214
|
+
async function engineMeasure(root, files, progress, signal) {
|
|
215
|
+
const answer = await ask(["measure", root, ...(progress ? ["--progress"] : [])], files, progressFrom(progress), signal);
|
|
216
|
+
if (!answer || !Array.isArray(answer.files) || answer.files.length !== files.length) {
|
|
217
|
+
if (answer)
|
|
218
|
+
broken = "cbx-engine measure answered for the wrong number of files";
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
const byPath = new Map();
|
|
222
|
+
for (const one of answer.files)
|
|
223
|
+
byPath.set(one.path, one);
|
|
224
|
+
return byPath;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* The files the ignore rules let into a save, found by the engine's own walk.
|
|
228
|
+
*
|
|
229
|
+
* Decided exactly as core/rules.ts and the walks in core/worktree.ts decide (the cross-test
|
|
230
|
+
* engine/compat/rules-cross.mjs compares them under many rule sets), returned in the order
|
|
231
|
+
* changedFiles meets them: breadth first, each folder in disk order. `rules` is what readRules
|
|
232
|
+
* gave; `tracked` what gitTracked gave. Each file's size, mtimeMs and mode come from one stat.
|
|
233
|
+
* Null when there is no engine or the walk failed, including on a rule JavaScript could not
|
|
234
|
+
* compile, so the TypeScript walk runs and fails in its own words.
|
|
235
|
+
*/
|
|
236
|
+
async function engineScan(root, rules, tracked,
|
|
237
|
+
/** How many files the folder held last time, when known; a small folder is walked faster without a process. */
|
|
238
|
+
expectedFiles,
|
|
239
|
+
/**
|
|
240
|
+
* Stat every file (the default). False lets the engine use the size and time the folder
|
|
241
|
+
* listing already carries, which costs nothing per file on Windows; a file still open for
|
|
242
|
+
* writing can show its previous size and time there, so only read-only reports ask for it.
|
|
243
|
+
*/
|
|
244
|
+
exact = true) {
|
|
245
|
+
if (!enginePath() || broken)
|
|
246
|
+
return null;
|
|
247
|
+
if (expectedFiles !== undefined && expectedFiles < exports.ENGINE_SCAN_MIN_FILES && process.env.CBX_ENGINE_ALWAYS !== "1")
|
|
248
|
+
return null;
|
|
249
|
+
if (process.env.CBX_ENGINE_SCAN === "off")
|
|
250
|
+
return null;
|
|
251
|
+
const answer = await ask(["scan"], {
|
|
252
|
+
root,
|
|
253
|
+
shared: rules.shared,
|
|
254
|
+
local: rules.local,
|
|
255
|
+
trackedFiles: tracked ? [...tracked.files] : null,
|
|
256
|
+
trackedFolders: tracked ? [...tracked.folders] : null,
|
|
257
|
+
exact,
|
|
258
|
+
});
|
|
259
|
+
if (!answer || answer.invalidRule || !Array.isArray(answer.files))
|
|
260
|
+
return null;
|
|
261
|
+
return answer.files;
|
|
262
|
+
}
|
|
263
|
+
/** For tests: forget what was found, so a changed CBX_ENGINE is read again. */
|
|
264
|
+
function resetEngineForTests() {
|
|
265
|
+
located = undefined;
|
|
266
|
+
broken = null;
|
|
267
|
+
}
|
package/dist/cli/src/api.js
CHANGED
|
@@ -427,6 +427,8 @@ async function aiAccess(repositoryId) {
|
|
|
427
427
|
const allowed = (key) => ai[key] !== false;
|
|
428
428
|
return {
|
|
429
429
|
aiRead: allowed("read"),
|
|
430
|
+
/* The one answer that starts as no: a service that does not send it has not been asked. */
|
|
431
|
+
aiTrain: ai.train === true,
|
|
430
432
|
aiDownload: allowed("download"),
|
|
431
433
|
aiContribute: allowed("contribute"),
|
|
432
434
|
aiRequest: allowed("request"),
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
/**
|
|
38
|
+
* The cbx command.
|
|
39
|
+
*
|
|
40
|
+
* `cbx status` in a folder with a local history is the command people run
|
|
41
|
+
* most, and it needs only that history: no sign-in, no network, none of the
|
|
42
|
+
* upload, project or workspace code. Answered here it loads a handful of
|
|
43
|
+
* modules instead of all of the CLI's, which was most of its time. It prints
|
|
44
|
+
* through the same function the full command table uses (local_status.ts).
|
|
45
|
+
*
|
|
46
|
+
* Everything else goes to cli.ts unchanged, and so does status whenever
|
|
47
|
+
* anything about it is out of the ordinary: other arguments, a Node that is
|
|
48
|
+
* too old, no local history here, or the unread-messages reminder being due.
|
|
49
|
+
*/
|
|
50
|
+
const reminder_gate_js_1 = require("./reminder_gate.js");
|
|
51
|
+
async function quickStatus() {
|
|
52
|
+
const argv = process.argv.slice(2);
|
|
53
|
+
if (argv.length !== 1 || argv[0] !== "status")
|
|
54
|
+
return null;
|
|
55
|
+
const { nodeTooOld } = await Promise.resolve().then(() => __importStar(require("./node_check.js")));
|
|
56
|
+
if (nodeTooOld())
|
|
57
|
+
return null;
|
|
58
|
+
if (await (0, reminder_gate_js_1.reminderDue)("status"))
|
|
59
|
+
return null;
|
|
60
|
+
const { Repository } = await Promise.resolve().then(() => __importStar(require("../../cbx/src/local/repository.js")));
|
|
61
|
+
const repository = await Repository.find(process.cwd());
|
|
62
|
+
if (!repository)
|
|
63
|
+
return null;
|
|
64
|
+
const { printLocalStatus, red } = await Promise.resolve().then(() => __importStar(require("./local_status.js")));
|
|
65
|
+
try {
|
|
66
|
+
return await printLocalStatus(repository);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
/* What localStatus's wrapper prints for anything status itself can raise. */
|
|
70
|
+
console.error(red(error instanceof Error ? error.message : String(error)));
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
quickStatus().then((code) => {
|
|
75
|
+
if (code === null) {
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
77
|
+
require("./cli.js").start();
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
process.exitCode = code;
|
|
81
|
+
}
|
|
82
|
+
}, () => {
|
|
83
|
+
/* Anything unexpected here: the full command line answers instead. */
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
85
|
+
require("./cli.js").start();
|
|
86
|
+
});
|
package/dist/cli/src/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.REGISTRY = void 0;
|
|
8
|
+
exports.start = start;
|
|
8
9
|
/**
|
|
9
10
|
* cbx — the CBX engine from the command line, talking to CodeRook.
|
|
10
11
|
*
|
|
@@ -33,6 +34,7 @@ const upload_progress_js_1 = require("./upload_progress.js");
|
|
|
33
34
|
const publish_js_1 = require("./publish.js");
|
|
34
35
|
const attach_command_js_1 = require("./attach_command.js");
|
|
35
36
|
const build_command_js_1 = require("./build_command.js");
|
|
37
|
+
const update_command_js_1 = require("./update_command.js");
|
|
36
38
|
const node_check_js_1 = require("./node_check.js");
|
|
37
39
|
const pages_command_js_1 = require("./pages_command.js");
|
|
38
40
|
const mods_command_js_1 = require("./mods_command.js");
|
|
@@ -501,7 +503,23 @@ async function commandStatus(parsed) {
|
|
|
501
503
|
send, with the flag that would send them spelled out. The safe default
|
|
502
504
|
does not change: a save adds and updates.
|
|
503
505
|
*/
|
|
504
|
-
|
|
506
|
+
/*
|
|
507
|
+
The digests submit keeps, so an unchanged file is not read again just to
|
|
508
|
+
be reported unchanged. Without them status read and hashed every file in
|
|
509
|
+
the folder each time it ran. What it learns is kept for the next run.
|
|
510
|
+
*/
|
|
511
|
+
const knownDigests = link?.repositoryId
|
|
512
|
+
? await (0, config_js_1.readDigests)(link.repositoryId)
|
|
513
|
+
: new Map();
|
|
514
|
+
let learned = 0;
|
|
515
|
+
const remember = knownDigests.set.bind(knownDigests);
|
|
516
|
+
knownDigests.set = (key, value) => {
|
|
517
|
+
learned += 1;
|
|
518
|
+
return remember(key, value);
|
|
519
|
+
};
|
|
520
|
+
const found = await (0, worktree_js_1.changedFiles)(folder, rules, baseline, "synchronize", knownDigests, undefined, false);
|
|
521
|
+
if (learned && link?.repositoryId)
|
|
522
|
+
await (0, config_js_1.writeDigests)(link.repositoryId, knownDigests);
|
|
505
523
|
const gone = found.filter((file) => file.deleted);
|
|
506
524
|
const files = found.filter((file) => !file.deleted);
|
|
507
525
|
// Tells the project's Actions page what this machine's folder holds; never delays or fails status.
|
|
@@ -4050,6 +4068,23 @@ const SPECS = [
|
|
|
4050
4068
|
examples: ["claude mcp add coderook -- cbx mcp"],
|
|
4051
4069
|
run: parsed => parsed.flags.has("workspaces") ? (0, workspace_command_js_1.commandWorkspaceMcp)() : (0, mcp_js_1.commandMcp)(version_js_1.VERSION),
|
|
4052
4070
|
},
|
|
4071
|
+
{
|
|
4072
|
+
name: "update",
|
|
4073
|
+
aliases: ["upgrade"],
|
|
4074
|
+
group: "Getting started",
|
|
4075
|
+
summary: "install the newest cbx",
|
|
4076
|
+
usage: "update",
|
|
4077
|
+
options: [
|
|
4078
|
+
{ flags: "--check", description: "only say whether a newer cbx is out" },
|
|
4079
|
+
],
|
|
4080
|
+
detail: "Updates cbx itself, not a folder: `cbx get` brings a project's files\n" +
|
|
4081
|
+
"up to date. Asks the npm registry for the newest @coderook/cli and\n" +
|
|
4082
|
+
"installs it the way this copy was installed: globally with npm, or in\n" +
|
|
4083
|
+
"the project whose packages hold it. Through npx there is nothing to\n" +
|
|
4084
|
+
"install. Your folders, sign-in and settings are left as they are.",
|
|
4085
|
+
examples: ["cbx update", "cbx update --check"],
|
|
4086
|
+
run: parsed => (0, update_command_js_1.commandUpdate)(parsed.flags),
|
|
4087
|
+
},
|
|
4053
4088
|
{
|
|
4054
4089
|
name: "doctor",
|
|
4055
4090
|
group: "Getting started",
|
|
@@ -4199,7 +4234,8 @@ function leave(code) {
|
|
|
4199
4234
|
command table — that every command is listed once, and fits — and must not
|
|
4200
4235
|
find itself running a command with the test runner's own arguments.
|
|
4201
4236
|
*/
|
|
4202
|
-
|
|
4237
|
+
/** Run the command line with this process's arguments. bin.ts calls this for everything it does not answer itself. */
|
|
4238
|
+
function start() {
|
|
4203
4239
|
(0, network_js_1.tuneNetwork)();
|
|
4204
4240
|
main(node_process_1.default.argv.slice(2))
|
|
4205
4241
|
.then(leave)
|
|
@@ -4208,3 +4244,5 @@ if (require.main === module) {
|
|
|
4208
4244
|
leave(1);
|
|
4209
4245
|
});
|
|
4210
4246
|
}
|
|
4247
|
+
if (require.main === module)
|
|
4248
|
+
start();
|