@delorenj/pjangler 1.5.27 โ 1.5.29
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/crank/tui.js +1 -0
- package/dist/index.js +52 -24
- package/package.json +1 -1
package/dist/crank/tui.js
CHANGED
|
@@ -435,6 +435,7 @@ function CrankDashboard({ controller, refreshMs = 5e3, clock = Date.now, onQuit
|
|
|
435
435
|
}
|
|
436
436
|
async function runCrankDashboard(controller, run = {}) {
|
|
437
437
|
const { refreshMs, ...ink } = run;
|
|
438
|
+
controller.read();
|
|
438
439
|
await runInk((finish) => /* @__PURE__ */ jsx3(CrankDashboard, { controller, refreshMs, onQuit: () => finish() }), { alternateScreen: true, ...ink });
|
|
439
440
|
}
|
|
440
441
|
export {
|
package/dist/index.js
CHANGED
|
@@ -6064,7 +6064,7 @@ var init_capture = __esm({
|
|
|
6064
6064
|
|
|
6065
6065
|
// src/index.ts
|
|
6066
6066
|
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
6067
|
-
import { existsSync as
|
|
6067
|
+
import { existsSync as existsSync26, readdirSync as readdirSync12, readFileSync as readFileSync29, statSync as statSync8 } from "node:fs";
|
|
6068
6068
|
import { basename as basename11, join as join34, resolve as resolve25 } from "node:path";
|
|
6069
6069
|
import { Command as Command3, CommanderError, Option } from "commander";
|
|
6070
6070
|
|
|
@@ -20377,6 +20377,8 @@ init_project();
|
|
|
20377
20377
|
init_style();
|
|
20378
20378
|
|
|
20379
20379
|
// src/tui/load.ts
|
|
20380
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
20381
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
20380
20382
|
var TuiUnavailableError = class extends Error {
|
|
20381
20383
|
};
|
|
20382
20384
|
function isInteractive(streams = {}) {
|
|
@@ -20384,6 +20386,9 @@ function isInteractive(streams = {}) {
|
|
|
20384
20386
|
const stdout = streams.stdout ?? process.stdout;
|
|
20385
20387
|
return Boolean(stdin.isTTY && stdout.isTTY);
|
|
20386
20388
|
}
|
|
20389
|
+
var RESOLVER_FRAME = /node:internal\/modules\/(?:esm\/resolve|package_json_reader)/;
|
|
20390
|
+
var CANNOT_FIND = /^Cannot find (package|module) '([^']+)' imported from (.+)$/;
|
|
20391
|
+
var INSTALL_DEPS = "run npm ci in this checkout, or reinstall the global package (npm i -g @delorenj/pjangler)";
|
|
20387
20392
|
async function loadScreen(relativeToDist, base) {
|
|
20388
20393
|
const url = new URL(relativeToDist, base);
|
|
20389
20394
|
try {
|
|
@@ -20392,10 +20397,15 @@ async function loadScreen(relativeToDist, base) {
|
|
|
20392
20397
|
url.href
|
|
20393
20398
|
);
|
|
20394
20399
|
} catch (error) {
|
|
20395
|
-
|
|
20400
|
+
const err = error;
|
|
20401
|
+
if (err?.code !== "ERR_MODULE_NOT_FOUND") throw error;
|
|
20402
|
+
if (!existsSync24(fileURLToPath6(url))) {
|
|
20396
20403
|
throw new TuiUnavailableError(`TUI screen ${relativeToDist} is not built (run: npm run build); looked for ${url.pathname}`);
|
|
20397
20404
|
}
|
|
20398
|
-
throw error;
|
|
20405
|
+
if (typeof err.stack !== "string" || !RESOLVER_FRAME.test(err.stack)) throw error;
|
|
20406
|
+
const missing = CANNOT_FIND.exec(err.message);
|
|
20407
|
+
const detail = missing ? `cannot find ${missing[1]} '${missing[2]}' imported by ${missing[3]}` : "an import of it cannot be resolved";
|
|
20408
|
+
throw new TuiUnavailableError(`TUI screen ${relativeToDist} is built but its dependencies are not installed: ${detail}; ${INSTALL_DEPS}`);
|
|
20399
20409
|
}
|
|
20400
20410
|
}
|
|
20401
20411
|
|
|
@@ -20420,7 +20430,7 @@ var TAB_STATUS_SUFFIX = /[\s๐ข๐ก๐ด๐โซโณโปโยทโ]+$/u;
|
|
|
20420
20430
|
var defaultShell = (command, args) => {
|
|
20421
20431
|
const result2 = spawnSync16(command, args, { encoding: "utf8", timeout: 1e4 });
|
|
20422
20432
|
if (result2.error) return { stdout: "", status: 127 };
|
|
20423
|
-
return { stdout: result2.stdout ?? "", status: result2.status ?? 1 };
|
|
20433
|
+
return { stdout: result2.stdout ?? "", status: result2.status ?? 1, stderr: result2.stderr ?? "" };
|
|
20424
20434
|
};
|
|
20425
20435
|
function tabDisplay(name) {
|
|
20426
20436
|
const trimmed2 = (name ?? "").trim();
|
|
@@ -20503,10 +20513,28 @@ function redis(deps = {}) {
|
|
|
20503
20513
|
const endpoint = redisEndpoint();
|
|
20504
20514
|
const host = deps.host ?? endpoint.host;
|
|
20505
20515
|
const port = deps.port ?? endpoint.port;
|
|
20506
|
-
const call = (args) => shell("redis-cli", ["--raw", "-h", host, "-p", String(port), ...args]);
|
|
20516
|
+
const call = (args) => shell("redis-cli", ["--raw", "-e", "-h", host, "-p", String(port), ...args]);
|
|
20517
|
+
let errorExitSupport = "unprobed";
|
|
20518
|
+
const requireErrorExit = () => {
|
|
20519
|
+
if (errorExitSupport === "unprobed") {
|
|
20520
|
+
const help = shell("redis-cli", ["--help"]);
|
|
20521
|
+
errorExitSupport = help.status === 0 && /^usage: redis-cli/im.test(help.stdout) ? /(^|\n)\s+-e\s/.test(help.stdout) ? "yes" : "no" : "unknown";
|
|
20522
|
+
}
|
|
20523
|
+
if (errorExitSupport === "no") {
|
|
20524
|
+
throw new Error(
|
|
20525
|
+
`redis-cli is too old for the crank store at ${host}:${port}: no -e flag (needs redis-tools >= 6.2) to fail on Redis error replies \u2014 upgrade redis-tools`
|
|
20526
|
+
);
|
|
20527
|
+
}
|
|
20528
|
+
};
|
|
20529
|
+
const notAnswering = (stderr) => !stderr || stderr.startsWith("Could not connect to Redis at") || stderr.startsWith("Error: ");
|
|
20507
20530
|
const run = (...args) => {
|
|
20531
|
+
requireErrorExit();
|
|
20508
20532
|
const result2 = call(args);
|
|
20509
|
-
if (result2.status !== 0)
|
|
20533
|
+
if (result2.status !== 0) {
|
|
20534
|
+
const stderr = (result2.stderr ?? "").trim();
|
|
20535
|
+
if (notAnswering(stderr)) throw new Error(`Redis is not answering at ${host}:${port} (${args[0]} failed)`);
|
|
20536
|
+
throw new Error(`Redis error reply at ${host}:${port}: ${stderr.split("\n")[0]} (${args.join(" ")})`);
|
|
20537
|
+
}
|
|
20510
20538
|
return result2.stdout.replace(/\r?\n$/, "");
|
|
20511
20539
|
};
|
|
20512
20540
|
const lines = (out) => out.split("\n").map((line) => line.replace(/\r$/, "")).filter(Boolean);
|
|
@@ -20515,6 +20543,7 @@ function redis(deps = {}) {
|
|
|
20515
20543
|
endpoint: `${host}:${port}`,
|
|
20516
20544
|
/** PING -> true only when Redis answers PONG. */
|
|
20517
20545
|
ping: () => {
|
|
20546
|
+
requireErrorExit();
|
|
20518
20547
|
const result2 = call(["PING"]);
|
|
20519
20548
|
return result2.status === 0 && result2.stdout.replace(/\r?\n$/, "") === "PONG";
|
|
20520
20549
|
},
|
|
@@ -20970,24 +20999,23 @@ function registerCrankCli(program2) {
|
|
|
20970
20999
|
console.error(`${xmark} --tail needs a positive integer, got "${options.tail}"`);
|
|
20971
21000
|
process.exit(1);
|
|
20972
21001
|
}
|
|
20973
|
-
let current;
|
|
20974
21002
|
try {
|
|
20975
|
-
current = resolveCurrentTab();
|
|
21003
|
+
const current = resolveCurrentTab();
|
|
21004
|
+
const store = redis();
|
|
21005
|
+
const rows = store.logRows(current.tab);
|
|
21006
|
+
if (!rows.length) {
|
|
21007
|
+
console.log(` ${dim(`no crank log rows for ${current.tab}`)}`);
|
|
21008
|
+
return;
|
|
21009
|
+
}
|
|
21010
|
+
const shown = rows.slice(-tail);
|
|
21011
|
+
console.log(` ${bold("crank log")} ${dim(glyph.dot)} ${cyan(current.tab)} ${dim(`(${shown.length}/${rows.length} rows, newest last)`)}`);
|
|
21012
|
+
for (const raw of shown) {
|
|
21013
|
+
console.log(renderLogRow(raw) ?? raw);
|
|
21014
|
+
}
|
|
20976
21015
|
} catch (error) {
|
|
20977
21016
|
console.error(`${xmark} ${error instanceof Error ? error.message : String(error)}`);
|
|
20978
21017
|
process.exit(1);
|
|
20979
21018
|
}
|
|
20980
|
-
const store = redis();
|
|
20981
|
-
const rows = store.logRows(current.tab);
|
|
20982
|
-
if (!rows.length) {
|
|
20983
|
-
console.log(` ${dim(`no crank log rows for ${current.tab}`)}`);
|
|
20984
|
-
return;
|
|
20985
|
-
}
|
|
20986
|
-
const shown = rows.slice(-tail);
|
|
20987
|
-
console.log(` ${bold("crank log")} ${dim(glyph.dot)} ${cyan(current.tab)} ${dim(`(${shown.length}/${rows.length} rows, newest last)`)}`);
|
|
20988
|
-
for (const raw of shown) {
|
|
20989
|
-
console.log(renderLogRow(raw) ?? raw);
|
|
20990
|
-
}
|
|
20991
21019
|
});
|
|
20992
21020
|
}
|
|
20993
21021
|
function fail(error, what) {
|
|
@@ -21100,7 +21128,7 @@ async function promptForRuleIds(rules) {
|
|
|
21100
21128
|
return selected;
|
|
21101
21129
|
}
|
|
21102
21130
|
function readJson2(path) {
|
|
21103
|
-
if (!
|
|
21131
|
+
if (!existsSync26(path)) return void 0;
|
|
21104
21132
|
try {
|
|
21105
21133
|
const parsed = JSON.parse(readFileSync29(path, "utf8"));
|
|
21106
21134
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
@@ -21195,7 +21223,7 @@ function actionNeedsRun(plan, kind, syncMode) {
|
|
|
21195
21223
|
if (!action || action.kind !== "project.write-manifest") return false;
|
|
21196
21224
|
const next = `${JSON.stringify(action.manifest, null, 2)}
|
|
21197
21225
|
`;
|
|
21198
|
-
return !
|
|
21226
|
+
return !existsSync26(action.path) || readFileSync29(action.path, "utf8") !== next;
|
|
21199
21227
|
}
|
|
21200
21228
|
if (kind === "copier.copy.commonproject") return true;
|
|
21201
21229
|
if (kind === "ticket-provider.create-or-link") return plan.actions.some((action) => action.kind === kind && action.enabled);
|
|
@@ -21252,7 +21280,7 @@ async function resolveProjectInitTarget(name, options) {
|
|
|
21252
21280
|
if (!targetDir && cwdGitRoot) {
|
|
21253
21281
|
targetDir = cwdGitRoot;
|
|
21254
21282
|
}
|
|
21255
|
-
if (!targetDir && !name &&
|
|
21283
|
+
if (!targetDir && !name && existsSync26(join34(cwd, ".project.json"))) {
|
|
21256
21284
|
targetDir = cwd;
|
|
21257
21285
|
}
|
|
21258
21286
|
if (!targetDir && interactive) {
|
|
@@ -21263,10 +21291,10 @@ async function resolveProjectInitTarget(name, options) {
|
|
|
21263
21291
|
if (!targetDir) {
|
|
21264
21292
|
throw new Error("Project name or --target-dir is required when project init is not run inside a git repo or a directory carrying .project.json");
|
|
21265
21293
|
}
|
|
21266
|
-
const targetExists =
|
|
21294
|
+
const targetExists = existsSync26(targetDir);
|
|
21267
21295
|
if (targetExists && !statSync8(targetDir).isDirectory()) throw new Error(`Target path is not a directory: ${targetDir}`);
|
|
21268
21296
|
const targetGitRoot = targetExists ? findGitRoot(targetDir) : void 0;
|
|
21269
|
-
const alreadyScaffolded = targetExists && (
|
|
21297
|
+
const alreadyScaffolded = targetExists && (existsSync26(join34(targetDir, ".project.json")) || existsSync26(join34(targetDir, ".copier-answers.yml")));
|
|
21270
21298
|
const syncMode = Boolean(
|
|
21271
21299
|
targetGitRoot && resolve25(targetGitRoot) === resolve25(targetDir) || alreadyScaffolded
|
|
21272
21300
|
);
|