@bli-cockpit/cli 0.2.57 → 0.2.59
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/commands/browser-open.js +88 -0
- package/dist/commands/docs.js +27 -6
- package/dist/commands/doctor-report.js +17 -1
- package/dist/commands/doctor.js +12 -2
- package/dist/commands/heartbeat.js +65 -1
- package/dist/commands/issue-contracts.js +99 -0
- package/dist/commands/issue-write.js +129 -0
- package/dist/commands/issue.js +189 -0
- package/dist/commands/jarvis-answer-envelope.js +80 -0
- package/dist/commands/jarvis-turn.js +16 -1
- package/dist/commands/jarvis.js +3 -0
- package/dist/commands/local-args-collector-setup.js +17 -0
- package/dist/commands/local-args-tower-admin.js +12 -2
- package/dist/commands/local-args-tower-docs-msg.js +95 -6
- package/dist/commands/local-args-tower-search.js +50 -0
- package/dist/commands/local-args-tower-work.js +178 -0
- package/dist/commands/local-args-tower.js +7 -1
- package/dist/commands/local-args.js +29 -14
- package/dist/commands/local-command-shapes.js +12 -0
- package/dist/commands/local-help-commands.js +643 -0
- package/dist/commands/local-help.js +12 -551
- package/dist/commands/local.js +9 -0
- package/dist/commands/login.js +91 -8
- package/dist/commands/memory-install-claude.js +35 -15
- package/dist/commands/memory-install-codex-hooks.js +200 -0
- package/dist/commands/memory-install-codex.js +12 -2
- package/dist/commands/memory-install-config.js +140 -0
- package/dist/commands/memory-install-receipt.js +222 -0
- package/dist/commands/memory-install-report.js +113 -0
- package/dist/commands/memory-install.js +99 -276
- package/dist/commands/msg.js +85 -2
- package/dist/commands/notes-door.js +120 -0
- package/dist/commands/notes-reads.js +134 -0
- package/dist/commands/notes-writes.js +208 -0
- package/dist/commands/notes.js +16 -442
- package/dist/commands/onboard-completion.js +47 -0
- package/dist/commands/onboard-setup.js +82 -2
- package/dist/commands/ops-render-memory.js +76 -0
- package/dist/commands/ops-render.js +13 -1
- package/dist/commands/ops.js +65 -3
- package/dist/commands/project.js +38 -0
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/search.js +122 -0
- package/dist/commands/setup-receipt-lines.js +71 -0
- package/dist/commands/setup-receipt.js +241 -0
- package/dist/commands/status.js +20 -1
- package/dist/local-state-pairing-code.js +200 -0
- package/dist/local-state.js +6 -0
- package/dist/repo-identity-fingerprint.js +88 -0
- package/dist/repo-identity-git.js +76 -0
- package/dist/repo-identity-linked-worktrees.js +81 -0
- package/dist/repo-identity.js +5 -222
- package/package.json +7 -7
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adding a discovered repo's linked worktrees (Claude Code isolation
|
|
3
|
+
* worktrees, `git worktree add` checkouts) as first-class candidates.
|
|
4
|
+
* Sibling of `repo-identity.ts`, named in its header.
|
|
5
|
+
*/
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { containsPath, isCodexWorktreePath } from "./root-normalization.js";
|
|
8
|
+
import { listLinkedWorktreePaths } from "./repo-identity-git.js";
|
|
9
|
+
import { compareIdentity, resolveRepoWorktreeIdentity } from "./repo-identity.js";
|
|
10
|
+
/**
|
|
11
|
+
* Directory discovery skips dot-dirs, so Claude Code's isolation worktrees
|
|
12
|
+
* (`<repo>/.claude/worktrees/<name>`) and any other linked worktree are never
|
|
13
|
+
* found by walking the filesystem. A session whose cwd sits inside one would
|
|
14
|
+
* otherwise satisfy `isPathWithin(cwd, parentRoot)` and attribute confidently
|
|
15
|
+
* to the PARENT with the wrong branch and worktree fingerprint. Enumerating
|
|
16
|
+
* `git worktree list --porcelain` for each discovered repo adds the linked
|
|
17
|
+
* worktrees as first-class candidates with their own branch/fingerprint; the
|
|
18
|
+
* deepest-root tie-break (attribution-core D6) then attributes nested-worktree
|
|
19
|
+
* sessions to the correct linked worktree. Benefits Codex sessions identically.
|
|
20
|
+
*/
|
|
21
|
+
export async function expandLinkedWorktrees(identities, maxWorktrees, allowedRoots) {
|
|
22
|
+
const byFingerprint = new Map(identities.map((identity) => [identity.worktree_fingerprint, identity]));
|
|
23
|
+
const seenRoots = new Set(identities.map((identity) => localPathKey(identity.repo_root)));
|
|
24
|
+
let maxWorktreesReached = identities.length > maxWorktrees;
|
|
25
|
+
for (const identity of identities.slice(0, maxWorktrees)) {
|
|
26
|
+
// One `git worktree list` from any worktree returns every worktree of that
|
|
27
|
+
// repo, so a single call per already-discovered repo covers its linked set.
|
|
28
|
+
for (const worktreePath of await listLinkedWorktreePaths(identity.repo_root)) {
|
|
29
|
+
const resolved = path.resolve(worktreePath);
|
|
30
|
+
const rootKey = localPathKey(resolved);
|
|
31
|
+
if (seenRoots.has(rootKey))
|
|
32
|
+
continue;
|
|
33
|
+
seenRoots.add(rootKey);
|
|
34
|
+
const linked = await resolveRepoWorktreeIdentity(resolved).catch(() => null);
|
|
35
|
+
if (!linked ||
|
|
36
|
+
byFingerprint.has(linked.worktree_fingerprint) ||
|
|
37
|
+
!isLinkedWorktreeWithinCollectionScope(linked, identities, allowedRoots)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (byFingerprint.size >= maxWorktrees) {
|
|
41
|
+
maxWorktreesReached = true;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
byFingerprint.set(linked.worktree_fingerprint, linked);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const worktrees = [...byFingerprint.values()]
|
|
48
|
+
.sort(compareIdentity)
|
|
49
|
+
.slice(0, maxWorktrees);
|
|
50
|
+
const incompleteReasons = maxWorktreesReached
|
|
51
|
+
? ["max_worktrees_reached"]
|
|
52
|
+
: [];
|
|
53
|
+
return {
|
|
54
|
+
worktrees,
|
|
55
|
+
complete: incompleteReasons.length === 0,
|
|
56
|
+
incomplete_reasons: incompleteReasons,
|
|
57
|
+
// Expansion asks git for its own worktree list; it never walks folders, so
|
|
58
|
+
// it has no unreadable directories of its own to report.
|
|
59
|
+
unreadable_dirs: [],
|
|
60
|
+
// Linked-worktree expansion is not scoped to one root; callers merge this
|
|
61
|
+
// into a result that already knows which roots were involved.
|
|
62
|
+
incomplete_roots: [],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function isLinkedWorktreeWithinCollectionScope(linked, discoveredFromApprovedRoots, allowedRoots) {
|
|
66
|
+
if (allowedRoots.some((root) => containsPath(root, linked.repo_root))) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
// Codex isolation worktrees live under ~/.codex/worktrees, outside the
|
|
70
|
+
// approved workspace parent. They remain in scope only when Git proves they
|
|
71
|
+
// belong to a clone discovered inside an approved root. Arbitrary sibling or
|
|
72
|
+
// personal linked worktrees do not inherit that consent.
|
|
73
|
+
if (!isCodexWorktreePath(linked.repo_root))
|
|
74
|
+
return false;
|
|
75
|
+
return discoveredFromApprovedRoots.some((identity) => identity.repo_fingerprint === linked.repo_fingerprint &&
|
|
76
|
+
allowedRoots.some((root) => containsPath(root, identity.repo_root)));
|
|
77
|
+
}
|
|
78
|
+
function localPathKey(value) {
|
|
79
|
+
const resolved = path.resolve(value);
|
|
80
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
81
|
+
}
|
package/dist/repo-identity.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
|
-
import crypto from "node:crypto";
|
|
3
1
|
import fs from "node:fs/promises";
|
|
4
2
|
import path from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
3
|
+
import { hasGitMarker, resolveGitBranchWithGit, resolveBranchFromHead, runGit } from "./repo-identity-git.js";
|
|
4
|
+
import { repoFingerprintFromLocalRoot, repoFingerprintFromOrigin, repoLabelFromOrigin, normalizeGitOrigin, sha256, stableWorktreeFingerprint, stableWorktreeRoot, } from "./repo-identity-fingerprint.js";
|
|
5
|
+
import { expandLinkedWorktrees } from "./repo-identity-linked-worktrees.js";
|
|
6
|
+
export { canonicalizeCollectionRootPaths, collectionRootPathAliases, normalizeGitOrigin, repoFingerprintFromLocalRoot, repoFingerprintFromOrigin, repoLabelFromOrigin, stableWorktreeFingerprint, stableWorktreeRoot, } from "./repo-identity-fingerprint.js";
|
|
9
7
|
const SKIPPED_DIR_NAMES = new Set([
|
|
10
8
|
".cache",
|
|
11
9
|
".git",
|
|
@@ -203,112 +201,6 @@ export async function discoverGitWorktreesInRootsWithStatus(roots, options = {})
|
|
|
203
201
|
unreadable_dirs: unreadableDirs,
|
|
204
202
|
};
|
|
205
203
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Canonicalizes existing collection roots through the filesystem so transcript
|
|
208
|
-
* paths and consent roots use the same spelling (for example `/private/var`
|
|
209
|
-
* versus the `/var` symlink on macOS). Missing roots remain resolved as typed.
|
|
210
|
-
*/
|
|
211
|
-
export async function canonicalizeCollectionRootPaths(roots) {
|
|
212
|
-
const canonical = await Promise.all(roots.map(stableWorktreeRoot));
|
|
213
|
-
return [...new Set(canonical)];
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Returns the operator-entered resolved paths plus filesystem-canonical aliases.
|
|
217
|
-
* Both are needed for absent child repos because the child itself cannot be
|
|
218
|
-
* realpathed after deletion, while its transcript may retain either spelling.
|
|
219
|
-
*/
|
|
220
|
-
export async function collectionRootPathAliases(roots) {
|
|
221
|
-
const resolved = roots.map((root) => path.resolve(root));
|
|
222
|
-
const canonical = await canonicalizeCollectionRootPaths(resolved);
|
|
223
|
-
return [...new Set([...resolved, ...canonical])];
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Directory discovery skips dot-dirs, so Claude Code's isolation worktrees
|
|
227
|
-
* (`<repo>/.claude/worktrees/<name>`) and any other linked worktree are never
|
|
228
|
-
* found by walking the filesystem. A session whose cwd sits inside one would
|
|
229
|
-
* otherwise satisfy `isPathWithin(cwd, parentRoot)` and attribute confidently
|
|
230
|
-
* to the PARENT with the wrong branch and worktree fingerprint. Enumerating
|
|
231
|
-
* `git worktree list --porcelain` for each discovered repo adds the linked
|
|
232
|
-
* worktrees as first-class candidates with their own branch/fingerprint; the
|
|
233
|
-
* deepest-root tie-break (attribution-core D6) then attributes nested-worktree
|
|
234
|
-
* sessions to the correct linked worktree. Benefits Codex sessions identically.
|
|
235
|
-
*/
|
|
236
|
-
async function expandLinkedWorktrees(identities, maxWorktrees, allowedRoots) {
|
|
237
|
-
const byFingerprint = new Map(identities.map((identity) => [identity.worktree_fingerprint, identity]));
|
|
238
|
-
const seenRoots = new Set(identities.map((identity) => localPathKey(identity.repo_root)));
|
|
239
|
-
let maxWorktreesReached = identities.length > maxWorktrees;
|
|
240
|
-
for (const identity of identities.slice(0, maxWorktrees)) {
|
|
241
|
-
// One `git worktree list` from any worktree returns every worktree of that
|
|
242
|
-
// repo, so a single call per already-discovered repo covers its linked set.
|
|
243
|
-
for (const worktreePath of await listLinkedWorktreePaths(identity.repo_root)) {
|
|
244
|
-
const resolved = path.resolve(worktreePath);
|
|
245
|
-
const rootKey = localPathKey(resolved);
|
|
246
|
-
if (seenRoots.has(rootKey))
|
|
247
|
-
continue;
|
|
248
|
-
seenRoots.add(rootKey);
|
|
249
|
-
const linked = await resolveRepoWorktreeIdentity(resolved).catch(() => null);
|
|
250
|
-
if (!linked ||
|
|
251
|
-
byFingerprint.has(linked.worktree_fingerprint) ||
|
|
252
|
-
!isLinkedWorktreeWithinCollectionScope(linked, identities, allowedRoots)) {
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
if (byFingerprint.size >= maxWorktrees) {
|
|
256
|
-
maxWorktreesReached = true;
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
byFingerprint.set(linked.worktree_fingerprint, linked);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
const worktrees = [...byFingerprint.values()]
|
|
263
|
-
.sort(compareIdentity)
|
|
264
|
-
.slice(0, maxWorktrees);
|
|
265
|
-
const incompleteReasons = maxWorktreesReached
|
|
266
|
-
? ["max_worktrees_reached"]
|
|
267
|
-
: [];
|
|
268
|
-
return {
|
|
269
|
-
worktrees,
|
|
270
|
-
complete: incompleteReasons.length === 0,
|
|
271
|
-
incomplete_reasons: incompleteReasons,
|
|
272
|
-
// Expansion asks git for its own worktree list; it never walks folders, so
|
|
273
|
-
// it has no unreadable directories of its own to report.
|
|
274
|
-
unreadable_dirs: [],
|
|
275
|
-
// Linked-worktree expansion is not scoped to one root; callers merge this
|
|
276
|
-
// into a result that already knows which roots were involved.
|
|
277
|
-
incomplete_roots: [],
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
function isLinkedWorktreeWithinCollectionScope(linked, discoveredFromApprovedRoots, allowedRoots) {
|
|
281
|
-
if (allowedRoots.some((root) => containsPath(root, linked.repo_root))) {
|
|
282
|
-
return true;
|
|
283
|
-
}
|
|
284
|
-
// Codex isolation worktrees live under ~/.codex/worktrees, outside the
|
|
285
|
-
// approved workspace parent. They remain in scope only when Git proves they
|
|
286
|
-
// belong to a clone discovered inside an approved root. Arbitrary sibling or
|
|
287
|
-
// personal linked worktrees do not inherit that consent.
|
|
288
|
-
if (!isCodexWorktreePath(linked.repo_root))
|
|
289
|
-
return false;
|
|
290
|
-
return discoveredFromApprovedRoots.some((identity) => identity.repo_fingerprint === linked.repo_fingerprint &&
|
|
291
|
-
allowedRoots.some((root) => containsPath(root, identity.repo_root)));
|
|
292
|
-
}
|
|
293
|
-
function localPathKey(value) {
|
|
294
|
-
const resolved = path.resolve(value);
|
|
295
|
-
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
296
|
-
}
|
|
297
|
-
async function listLinkedWorktreePaths(repoRoot) {
|
|
298
|
-
const porcelain = await runGit(["worktree", "list", "--porcelain"], repoRoot).catch(() => "");
|
|
299
|
-
const paths = [];
|
|
300
|
-
for (const line of porcelain.split("\n")) {
|
|
301
|
-
if (line.startsWith("worktree ")) {
|
|
302
|
-
const value = line.slice("worktree ".length).trim();
|
|
303
|
-
if (value)
|
|
304
|
-
paths.push(value);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return paths;
|
|
308
|
-
}
|
|
309
|
-
async function hasGitMarker(dir) {
|
|
310
|
-
return fs.stat(path.join(dir, ".git")).then((stat) => stat.isDirectory() || stat.isFile(), () => false);
|
|
311
|
-
}
|
|
312
204
|
async function fallbackFilesystemIdentity(repoRoot) {
|
|
313
205
|
const resolvedRoot = await stableWorktreeRoot(repoRoot);
|
|
314
206
|
const repoLabel = path.basename(resolvedRoot) || "repo";
|
|
@@ -326,120 +218,11 @@ async function fallbackFilesystemIdentity(repoRoot) {
|
|
|
326
218
|
worktree_is_primary: true,
|
|
327
219
|
};
|
|
328
220
|
}
|
|
329
|
-
export async function stableWorktreeRoot(repoRoot) {
|
|
330
|
-
const resolvedRoot = path.resolve(repoRoot);
|
|
331
|
-
return fs.realpath(resolvedRoot).catch(() => resolvedRoot);
|
|
332
|
-
}
|
|
333
|
-
export function stableWorktreeFingerprint(repoRoot, pathApi = path) {
|
|
334
|
-
return `wt-${sha256(`worktree:${normalizeFingerprintPath(repoRoot, pathApi)}`).slice(0, 24)}`;
|
|
335
|
-
}
|
|
336
|
-
export function repoFingerprintFromLocalRoot(root, pathApi = path) {
|
|
337
|
-
return `repo-${sha256(`local:${normalizeFingerprintPath(root, pathApi)}`).slice(0, 24)}`;
|
|
338
|
-
}
|
|
339
|
-
export function repoFingerprintFromOrigin(origin) {
|
|
340
|
-
const normalizedOrigin = normalizeGitOrigin(origin);
|
|
341
|
-
return `repo-${sha256(`origin:${normalizedOrigin}`).slice(0, 24)}`;
|
|
342
|
-
}
|
|
343
|
-
async function resolveBranchFromHead(repoRoot) {
|
|
344
|
-
try {
|
|
345
|
-
const gitPath = path.join(repoRoot, ".git");
|
|
346
|
-
const stat = await fs.stat(gitPath);
|
|
347
|
-
const headPath = stat.isFile()
|
|
348
|
-
? path.join(await resolveLinkedGitDir(gitPath), "HEAD")
|
|
349
|
-
: path.join(gitPath, "HEAD");
|
|
350
|
-
const head = (await fs.readFile(headPath, "utf8")).trim();
|
|
351
|
-
if (head.startsWith("ref: refs/heads/")) {
|
|
352
|
-
return head.slice("ref: refs/heads/".length);
|
|
353
|
-
}
|
|
354
|
-
return head ? `detached:${head.slice(0, 12)}` : "unknown";
|
|
355
|
-
}
|
|
356
|
-
catch (error) {
|
|
357
|
-
// Not a repo → quiet, that is an ordinary approved folder. A `.git` that
|
|
358
|
-
// exists and will not read → every session from this worktree is labelled
|
|
359
|
-
// branch `unknown` and, until BLI-3238, nothing said why.
|
|
360
|
-
if (!isMissingFileFailure(error)) {
|
|
361
|
-
console.error("[repo-identity] could not read HEAD, branch recorded as unknown", JSON.stringify({
|
|
362
|
-
reason: "git_head_unreadable",
|
|
363
|
-
...describeError(error),
|
|
364
|
-
}));
|
|
365
|
-
}
|
|
366
|
-
return "unknown";
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
async function resolveLinkedGitDir(gitFile) {
|
|
370
|
-
const raw = await fs.readFile(gitFile, "utf8");
|
|
371
|
-
const match = raw.match(/^gitdir:\s*(.+)$/m);
|
|
372
|
-
if (!match)
|
|
373
|
-
return path.dirname(gitFile);
|
|
374
|
-
const gitDir = match[1].trim();
|
|
375
|
-
return path.isAbsolute(gitDir) ? gitDir : path.resolve(path.dirname(gitFile), gitDir);
|
|
376
|
-
}
|
|
377
|
-
export function normalizeGitOrigin(rawOrigin) {
|
|
378
|
-
const trimmed = rawOrigin.trim();
|
|
379
|
-
if (!trimmed)
|
|
380
|
-
return "";
|
|
381
|
-
const scpLike = trimmed.match(/^(?:[^@]+@)?([^:]+):(.+)$/);
|
|
382
|
-
if (scpLike && !trimmed.includes("://")) {
|
|
383
|
-
return normalizeOriginParts(scpLike[1] ?? "", scpLike[2] ?? "");
|
|
384
|
-
}
|
|
385
|
-
try {
|
|
386
|
-
const url = new URL(trimmed);
|
|
387
|
-
return normalizeOriginParts(url.hostname, url.pathname);
|
|
388
|
-
}
|
|
389
|
-
catch {
|
|
390
|
-
// Deliberately silent (BLI-3238). `new URL` is being used as the test for
|
|
391
|
-
// "is this origin URL-shaped?", and a plain path or an unusual remote form
|
|
392
|
-
// failing to parse IS the answer — the fallback below is the intended
|
|
393
|
-
// normalization for exactly that case, not a degradation.
|
|
394
|
-
return trimmed
|
|
395
|
-
.replace(/\.git$/i, "")
|
|
396
|
-
.replace(/^\/+|\/+$/g, "")
|
|
397
|
-
.toLowerCase();
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
export function repoLabelFromOrigin(origin) {
|
|
401
|
-
const segments = origin.split("/").filter(Boolean);
|
|
402
|
-
return segments.at(-1) ?? origin;
|
|
403
|
-
}
|
|
404
|
-
function normalizeOriginParts(host, repoPath) {
|
|
405
|
-
return [
|
|
406
|
-
host.trim().toLowerCase(),
|
|
407
|
-
repoPath
|
|
408
|
-
.trim()
|
|
409
|
-
.replace(/\.git$/i, "")
|
|
410
|
-
.replace(/^\/+|\/+$/g, "")
|
|
411
|
-
.toLowerCase(),
|
|
412
|
-
]
|
|
413
|
-
.filter(Boolean)
|
|
414
|
-
.join("/");
|
|
415
|
-
}
|
|
416
221
|
function shouldSkipDirectory(name) {
|
|
417
222
|
return name.startsWith(".") || SKIPPED_DIR_NAMES.has(name);
|
|
418
223
|
}
|
|
419
|
-
function compareIdentity(a, b) {
|
|
224
|
+
export function compareIdentity(a, b) {
|
|
420
225
|
return (a.repo_label.localeCompare(b.repo_label) ||
|
|
421
226
|
Number(b.worktree_is_primary) - Number(a.worktree_is_primary) ||
|
|
422
227
|
a.worktree_label.localeCompare(b.worktree_label));
|
|
423
|
-
}
|
|
424
|
-
async function resolveGitBranchWithGit(repoRoot) {
|
|
425
|
-
const branch = await runGit(["rev-parse", "--abbrev-ref", "HEAD"], repoRoot).then((value) => value.trim(), () => "");
|
|
426
|
-
if (branch && branch !== "HEAD")
|
|
427
|
-
return branch;
|
|
428
|
-
const head = await runGit(["rev-parse", "--short=12", "HEAD"], repoRoot).then((value) => value.trim(), () => "");
|
|
429
|
-
return head ? `detached:${head}` : "unknown";
|
|
430
|
-
}
|
|
431
|
-
async function runGit(args, cwd) {
|
|
432
|
-
const { stdout } = await execFileAsync("git", args, {
|
|
433
|
-
cwd,
|
|
434
|
-
timeout: 2_000,
|
|
435
|
-
maxBuffer: 1024 * 1024,
|
|
436
|
-
});
|
|
437
|
-
return stdout;
|
|
438
|
-
}
|
|
439
|
-
function normalizeFingerprintPath(repoRoot, pathApi = path) {
|
|
440
|
-
const resolved = pathApi.resolve(repoRoot);
|
|
441
|
-
return pathApi.sep === "\\" ? resolved.toLowerCase() : resolved;
|
|
442
|
-
}
|
|
443
|
-
function sha256(value) {
|
|
444
|
-
return crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
445
228
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.59",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,17 +18,17 @@
|
|
|
18
18
|
"node": ">=20"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"prebuild": "
|
|
21
|
+
"prebuild": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/local-collector",
|
|
22
22
|
"build": "node ../../scripts/build-public-cli.mjs",
|
|
23
23
|
"prepack": "npm run build",
|
|
24
|
-
"pretypecheck": "
|
|
24
|
+
"pretypecheck": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/cli",
|
|
25
25
|
"typecheck": "node -e \"await import('./dist/commands/public-root.js')\"",
|
|
26
|
-
"pretest": "
|
|
26
|
+
"pretest": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/cli",
|
|
27
27
|
"test": "node dist/cli.js --help && node ../../scripts/assert-public-cli-routing.mjs && node ../../scripts/assert-public-cli-runtime-files.mjs && node ../../scripts/assert-public-cli-no-fleet-posts.mjs && node ../../scripts/assert-public-package-pack.mjs --workspace=@bli-cockpit/cli"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@bli-cockpit/memory-mcp": "0.1.
|
|
31
|
-
"@bli-cockpit/mcp": "0.1.
|
|
32
|
-
"@bli-cockpit/telemetry-core": "0.1.
|
|
30
|
+
"@bli-cockpit/memory-mcp": "0.1.7",
|
|
31
|
+
"@bli-cockpit/mcp": "0.1.3",
|
|
32
|
+
"@bli-cockpit/telemetry-core": "0.1.29"
|
|
33
33
|
}
|
|
34
34
|
}
|