finitemonkey 0.1.0-next.16 → 0.1.0-next.18
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/README.es.md +1 -0
- package/README.md +1 -0
- package/README.pt-BR.md +1 -0
- package/dist/finitemonkey.mjs +1023 -430
- package/package.json +1 -1
package/dist/finitemonkey.mjs
CHANGED
|
@@ -69,7 +69,7 @@ var resolveWindowsCommand = (command, env, exists) => {
|
|
|
69
69
|
}
|
|
70
70
|
return { command, shell: false };
|
|
71
71
|
};
|
|
72
|
-
var windowsCommandLine = (resolved,
|
|
72
|
+
var windowsCommandLine = (resolved, args2) => [quoteForCmd(resolved.command), ...args2.map(quoteForCmd)].join(" ");
|
|
73
73
|
|
|
74
74
|
// src/core/node-exec.ts
|
|
75
75
|
var SHELL_NOT_FOUND = /* @__PURE__ */ new Set([127, 9009]);
|
|
@@ -117,9 +117,9 @@ var nodeAppendText = (path, content) => {
|
|
|
117
117
|
return reject(error instanceof Error ? error.message : String(error));
|
|
118
118
|
}
|
|
119
119
|
};
|
|
120
|
-
var nodeSpawnSelf = (selfPath) => (
|
|
120
|
+
var nodeSpawnSelf = (selfPath) => (args2, cwd) => {
|
|
121
121
|
try {
|
|
122
|
-
const child2 = spawn(process.execPath, [selfPath, ...
|
|
122
|
+
const child2 = spawn(process.execPath, [selfPath, ...args2], {
|
|
123
123
|
cwd,
|
|
124
124
|
detached: true,
|
|
125
125
|
stdio: "ignore",
|
|
@@ -290,8 +290,8 @@ import { createInterface } from "node:readline";
|
|
|
290
290
|
var MAX_BUFFER2 = 256 * 1024 * 1024;
|
|
291
291
|
var GIT_ENV = { ...process.env, GIT_PAGER: "cat", GIT_TERMINAL_PROMPT: "0", LC_ALL: "C" };
|
|
292
292
|
var notFound = (error) => error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
293
|
-
var nodeGit = (
|
|
294
|
-
const result = spawnSync2("git", [...
|
|
293
|
+
var nodeGit = (args2, cwd) => {
|
|
294
|
+
const result = spawnSync2("git", [...args2], {
|
|
295
295
|
cwd,
|
|
296
296
|
encoding: "utf8",
|
|
297
297
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -305,8 +305,8 @@ var nodeGit = (args, cwd) => {
|
|
|
305
305
|
stdout: typeof stdout === "string" ? stdout : ""
|
|
306
306
|
};
|
|
307
307
|
};
|
|
308
|
-
var nodeGitLines = (
|
|
309
|
-
const child2 = spawn2("git", [...
|
|
308
|
+
var nodeGitLines = (args2, cwd, onLine) => new Promise((resolve2) => {
|
|
309
|
+
const child2 = spawn2("git", [...args2], {
|
|
310
310
|
cwd,
|
|
311
311
|
windowsHide: true,
|
|
312
312
|
env: GIT_ENV,
|
|
@@ -323,8 +323,8 @@ var nodeGitLines = (args, cwd, onLine) => new Promise((resolve2) => {
|
|
|
323
323
|
});
|
|
324
324
|
});
|
|
325
325
|
var textOf = (value) => typeof value === "string" ? value : "";
|
|
326
|
-
var nodeGitWith = (
|
|
327
|
-
const result = spawnSync2("git", [...
|
|
326
|
+
var nodeGitWith = (args2, cwd, options) => {
|
|
327
|
+
const result = spawnSync2("git", [...args2], {
|
|
328
328
|
cwd,
|
|
329
329
|
encoding: "utf8",
|
|
330
330
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -350,15 +350,15 @@ var errnoCode2 = (error) => {
|
|
|
350
350
|
if (!(error instanceof Error) || !("code" in error)) return void 0;
|
|
351
351
|
return typeof error.code === "string" ? error.code : void 0;
|
|
352
352
|
};
|
|
353
|
-
var spawnProbe = (command,
|
|
353
|
+
var spawnProbe = (command, args2, timeout) => {
|
|
354
354
|
const options = { encoding: "utf8", timeout, windowsHide: true };
|
|
355
|
-
return process.platform === "win32" ? spawnSync3([command, ...
|
|
355
|
+
return process.platform === "win32" ? spawnSync3([command, ...args2].join(" "), { ...options, shell: true }) : spawnSync3(command, [...args2], options);
|
|
356
356
|
};
|
|
357
|
-
var nodeProbe = (command,
|
|
358
|
-
if (![command, ...
|
|
357
|
+
var nodeProbe = (command, args2, timeoutMs) => {
|
|
358
|
+
if (![command, ...args2].every((token) => SAFE_TOKEN.test(token))) {
|
|
359
359
|
return { found: false, ok: false, stdout: "", timedOut: false };
|
|
360
360
|
}
|
|
361
|
-
const result = spawnProbe(command,
|
|
361
|
+
const result = spawnProbe(command, args2, timeoutMs);
|
|
362
362
|
const code = errnoCode2(result.error);
|
|
363
363
|
const stdout = result.stdout;
|
|
364
364
|
return {
|
|
@@ -409,14 +409,155 @@ var nodeRuntime = () => ({
|
|
|
409
409
|
exec: nodeExec,
|
|
410
410
|
appendText: nodeAppendText,
|
|
411
411
|
spawnSelf: nodeSpawnSelf(SELF_PATH),
|
|
412
|
+
execSelf: (args2, cwd, timeoutMs) => nodeExec({ command: process.execPath, args: [SELF_PATH, ...args2], cwd, timeoutMs }),
|
|
412
413
|
gitWith: nodeGitWith,
|
|
413
414
|
realpath: nodeRealpath,
|
|
414
415
|
homeDir: homedir,
|
|
415
416
|
systemLocale: () => Intl.DateTimeFormat().resolvedOptions().locale
|
|
416
417
|
});
|
|
417
418
|
|
|
418
|
-
// src/
|
|
419
|
-
import {
|
|
419
|
+
// src/app/node-process.ts
|
|
420
|
+
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
421
|
+
import { connect } from "node:net";
|
|
422
|
+
var MAX_OUTPUT = 64 * 1024;
|
|
423
|
+
var POLL_MS = 150;
|
|
424
|
+
var STOP_GRACE_MS = 3e3;
|
|
425
|
+
var sleep = (ms) => new Promise((resolve2) => {
|
|
426
|
+
setTimeout(resolve2, ms);
|
|
427
|
+
});
|
|
428
|
+
var portOpen = (host, port) => new Promise((resolve2) => {
|
|
429
|
+
const socket = connect({ host, port });
|
|
430
|
+
const done = (open) => {
|
|
431
|
+
socket.destroy();
|
|
432
|
+
resolve2(open);
|
|
433
|
+
};
|
|
434
|
+
socket.setTimeout(1e3, () => {
|
|
435
|
+
done(false);
|
|
436
|
+
});
|
|
437
|
+
socket.once("connect", () => {
|
|
438
|
+
done(true);
|
|
439
|
+
});
|
|
440
|
+
socket.once("error", () => {
|
|
441
|
+
done(false);
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
var startApp = (command, cwd, port) => {
|
|
445
|
+
const child2 = spawn3(command, {
|
|
446
|
+
cwd,
|
|
447
|
+
shell: true,
|
|
448
|
+
detached: process.platform !== "win32",
|
|
449
|
+
windowsHide: true,
|
|
450
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
451
|
+
env: { ...process.env, PORT: String(port) }
|
|
452
|
+
});
|
|
453
|
+
let output = "";
|
|
454
|
+
let exit;
|
|
455
|
+
const collect4 = (chunk) => {
|
|
456
|
+
output = `${output}${chunk.toString("utf8")}`.slice(-MAX_OUTPUT);
|
|
457
|
+
};
|
|
458
|
+
child2.stdout.on("data", collect4);
|
|
459
|
+
child2.stderr.on("data", collect4);
|
|
460
|
+
child2.once("error", (error) => {
|
|
461
|
+
output = `${output}${error.message}`;
|
|
462
|
+
exit = { code: null };
|
|
463
|
+
});
|
|
464
|
+
child2.once("exit", (code) => {
|
|
465
|
+
exit = { code };
|
|
466
|
+
});
|
|
467
|
+
return { child: child2, output: () => output, exited: () => exit };
|
|
468
|
+
};
|
|
469
|
+
var waitForPort = async (app, host, port, deadline) => {
|
|
470
|
+
while (Date.now() < deadline) {
|
|
471
|
+
if (await portOpen(host, port)) return "open";
|
|
472
|
+
if (app.exited() !== void 0) return "exited";
|
|
473
|
+
await sleep(POLL_MS);
|
|
474
|
+
}
|
|
475
|
+
return "timeout";
|
|
476
|
+
};
|
|
477
|
+
var signalGroup = (pid, signal) => {
|
|
478
|
+
try {
|
|
479
|
+
process.kill(-pid, signal);
|
|
480
|
+
} catch {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
var alive = (pid) => {
|
|
485
|
+
try {
|
|
486
|
+
process.kill(-pid, 0);
|
|
487
|
+
return true;
|
|
488
|
+
} catch {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
var stopApp = async (app) => {
|
|
493
|
+
const pid = app.child.pid;
|
|
494
|
+
if (pid === void 0) return true;
|
|
495
|
+
if (process.platform === "win32") {
|
|
496
|
+
spawnSync4("taskkill", ["/pid", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore" });
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
signalGroup(pid, "SIGTERM");
|
|
500
|
+
const deadline = Date.now() + STOP_GRACE_MS;
|
|
501
|
+
while (alive(pid) && Date.now() < deadline) await sleep(POLL_MS);
|
|
502
|
+
if (alive(pid)) signalGroup(pid, "SIGKILL");
|
|
503
|
+
return !alive(pid);
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
// src/app/node-probe.ts
|
|
507
|
+
var BODY_EXCERPT = 200;
|
|
508
|
+
var MAX_BODY = 256 * 1024;
|
|
509
|
+
var url = (request) => {
|
|
510
|
+
const host = request.host.includes(":") ? `[${request.host}]` : request.host;
|
|
511
|
+
return `http://${host}:${String(request.port)}${request.route.startsWith("/") ? "" : "/"}${request.route}`;
|
|
512
|
+
};
|
|
513
|
+
var ask = async (request, deadline) => {
|
|
514
|
+
try {
|
|
515
|
+
const response = await fetch(url(request), {
|
|
516
|
+
redirect: "manual",
|
|
517
|
+
signal: AbortSignal.timeout(Math.max(1e3, deadline - Date.now()))
|
|
518
|
+
});
|
|
519
|
+
const body2 = (await response.text()).slice(0, MAX_BODY);
|
|
520
|
+
const excerpt = body2.slice(0, BODY_EXCERPT);
|
|
521
|
+
if (response.status !== request.status)
|
|
522
|
+
return { kind: "wrong_status", status: response.status, bodyExcerpt: excerpt };
|
|
523
|
+
if (request.body !== void 0 && !body2.includes(request.body)) {
|
|
524
|
+
return { kind: "body_mismatch", status: response.status, bodyExcerpt: excerpt };
|
|
525
|
+
}
|
|
526
|
+
return { kind: "ok", status: response.status };
|
|
527
|
+
} catch (error) {
|
|
528
|
+
return { kind: "request_failed", bodyExcerpt: error instanceof Error ? error.message : String(error) };
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
var finish = async (app, answer, started) => {
|
|
532
|
+
const stopped = app === void 0 ? true : await stopApp(app);
|
|
533
|
+
return {
|
|
534
|
+
...answer,
|
|
535
|
+
reused: app === void 0,
|
|
536
|
+
output: app?.output() ?? "",
|
|
537
|
+
stopped,
|
|
538
|
+
durationMs: Date.now() - started
|
|
539
|
+
};
|
|
540
|
+
};
|
|
541
|
+
var probeApp = async (request) => {
|
|
542
|
+
const started = Date.now();
|
|
543
|
+
const deadline = started + request.timeoutMs;
|
|
544
|
+
if (await portOpen(request.host, request.port)) return finish(void 0, await ask(request, deadline), started);
|
|
545
|
+
if (request.start === void 0) return finish(void 0, { kind: "no_start" }, started);
|
|
546
|
+
const app = startApp(request.start, request.cwd, request.port);
|
|
547
|
+
const port = await waitForPort(app, request.host, request.port, deadline);
|
|
548
|
+
if (port === "exited") return finish(app, { kind: "crashed", exitCode: app.exited()?.code ?? null }, started);
|
|
549
|
+
if (port === "timeout") return finish(app, { kind: "no_port" }, started);
|
|
550
|
+
return finish(app, await ask(request, deadline), started);
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
// src/app/types.ts
|
|
554
|
+
var DEFAULT_HOST = "127.0.0.1";
|
|
555
|
+
var DEFAULT_ROUTE = "/";
|
|
556
|
+
var DEFAULT_STATUS = 200;
|
|
557
|
+
var DEFAULT_APP_TIMEOUT_S = 60;
|
|
558
|
+
|
|
559
|
+
// src/core/args.ts
|
|
560
|
+
import { parseArgs } from "node:util";
|
|
420
561
|
|
|
421
562
|
// src/exit-codes.ts
|
|
422
563
|
var ExitCode = {
|
|
@@ -444,6 +585,89 @@ var exitCodeDocs = {
|
|
|
444
585
|
5: "exit.internal"
|
|
445
586
|
};
|
|
446
587
|
|
|
588
|
+
// src/core/problem.ts
|
|
589
|
+
var usageProblem = (code, messageKey, fix, params2 = {}) => ({
|
|
590
|
+
code,
|
|
591
|
+
messageKey,
|
|
592
|
+
params: params2,
|
|
593
|
+
fix,
|
|
594
|
+
exitCode: ExitCode.Usage
|
|
595
|
+
});
|
|
596
|
+
var needsPersonProblem = (messageKey, fix, params2 = {}) => ({
|
|
597
|
+
code: "needs_confirmation",
|
|
598
|
+
messageKey,
|
|
599
|
+
params: params2,
|
|
600
|
+
fix,
|
|
601
|
+
exitCode: ExitCode.NeedsPerson
|
|
602
|
+
});
|
|
603
|
+
var FmError = class extends Error {
|
|
604
|
+
problem;
|
|
605
|
+
constructor(problem4) {
|
|
606
|
+
super(problem4.code);
|
|
607
|
+
this.name = "FmError";
|
|
608
|
+
this.problem = problem4;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// src/core/args.ts
|
|
613
|
+
var GLOBAL_OPTIONS = {
|
|
614
|
+
json: { type: "boolean" },
|
|
615
|
+
lang: { type: "string" },
|
|
616
|
+
yes: { type: "boolean", short: "y" },
|
|
617
|
+
"dry-run": { type: "boolean" },
|
|
618
|
+
version: { type: "boolean", short: "v" },
|
|
619
|
+
help: { type: "boolean", short: "h" }
|
|
620
|
+
};
|
|
621
|
+
var flag = (values, name) => values[name] === true;
|
|
622
|
+
var looseArgs = (argv) => {
|
|
623
|
+
const { values, positionals } = parseArgs({
|
|
624
|
+
args: [...argv],
|
|
625
|
+
options: GLOBAL_OPTIONS,
|
|
626
|
+
strict: false,
|
|
627
|
+
allowPositionals: true
|
|
628
|
+
});
|
|
629
|
+
const lang = values.lang;
|
|
630
|
+
return {
|
|
631
|
+
positionals,
|
|
632
|
+
json: flag(values, "json"),
|
|
633
|
+
yes: flag(values, "yes"),
|
|
634
|
+
dryRun: flag(values, "dry-run"),
|
|
635
|
+
version: flag(values, "version"),
|
|
636
|
+
help: flag(values, "help"),
|
|
637
|
+
lang: typeof lang === "string" ? lang : void 0
|
|
638
|
+
};
|
|
639
|
+
};
|
|
640
|
+
var resolveCommand = (registry, positionals) => registry.filter((spec2) => spec2.path.every((part2, index) => positionals[index] === part2)).reduce(
|
|
641
|
+
(best, spec2) => best === void 0 || spec2.path.length > best.consumed ? { spec: spec2, consumed: spec2.path.length } : best,
|
|
642
|
+
void 0
|
|
643
|
+
);
|
|
644
|
+
var strictArgs = (argv, spec2) => {
|
|
645
|
+
const fix = `finitemonkey help ${spec2.path.join(" ")}`;
|
|
646
|
+
let parsed;
|
|
647
|
+
try {
|
|
648
|
+
parsed = parseArgs({
|
|
649
|
+
args: [...argv],
|
|
650
|
+
options: { ...GLOBAL_OPTIONS, ...spec2.options },
|
|
651
|
+
strict: true,
|
|
652
|
+
allowPositionals: true
|
|
653
|
+
});
|
|
654
|
+
} catch (error) {
|
|
655
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
656
|
+
return reject(usageProblem("invalid_arguments", "error.invalid_arguments", fix, { detail }));
|
|
657
|
+
}
|
|
658
|
+
const rest = parsed.positionals.slice(spec2.path.length);
|
|
659
|
+
const max = spec2.maxPositionals ?? 0;
|
|
660
|
+
const extra = rest[max];
|
|
661
|
+
if (extra !== void 0) {
|
|
662
|
+
return reject(usageProblem("unexpected_argument", "error.unexpected_argument", fix, { argument: extra }));
|
|
663
|
+
}
|
|
664
|
+
return accept({ values: parsed.values, positionals: rest });
|
|
665
|
+
};
|
|
666
|
+
var stringOption = (values, name) => {
|
|
667
|
+
const value = values[name];
|
|
668
|
+
return typeof value === "string" ? value : void 0;
|
|
669
|
+
};
|
|
670
|
+
|
|
447
671
|
// src/core/result.ts
|
|
448
672
|
var SCHEMA_VERSION = 1;
|
|
449
673
|
var success = (data, human2 = []) => ({
|
|
@@ -468,6 +692,87 @@ var toEnvelope = (command, result) => ({
|
|
|
468
692
|
...result.next === void 0 ? {} : { next: result.next }
|
|
469
693
|
});
|
|
470
694
|
|
|
695
|
+
// src/commands/app-check.ts
|
|
696
|
+
var APP_CHECK_SCHEMA = "finitemonkey/app-check@1";
|
|
697
|
+
var positive = (raw, fallback) => {
|
|
698
|
+
if (raw === void 0) return fallback;
|
|
699
|
+
const value = Number(raw);
|
|
700
|
+
return Number.isInteger(value) && value > 0 ? value : void 0;
|
|
701
|
+
};
|
|
702
|
+
var requestFrom = (ctx, values) => {
|
|
703
|
+
const port = positive(stringOption(values, "port"), 0);
|
|
704
|
+
const status = positive(stringOption(values, "status"), DEFAULT_STATUS);
|
|
705
|
+
const timeout = positive(stringOption(values, "timeout"), DEFAULT_APP_TIMEOUT_S);
|
|
706
|
+
if (port === void 0 || port === 0 || port > 65535 || status === void 0 || timeout === void 0)
|
|
707
|
+
return void 0;
|
|
708
|
+
return {
|
|
709
|
+
host: stringOption(values, "host") ?? DEFAULT_HOST,
|
|
710
|
+
port,
|
|
711
|
+
route: stringOption(values, "route") ?? DEFAULT_ROUTE,
|
|
712
|
+
status,
|
|
713
|
+
body: stringOption(values, "body"),
|
|
714
|
+
start: stringOption(values, "start"),
|
|
715
|
+
cwd: ctx.cwd,
|
|
716
|
+
timeoutMs: timeout * 1e3
|
|
717
|
+
};
|
|
718
|
+
};
|
|
719
|
+
var humanLine = (ctx, data) => ctx.t(`app.check.${data.kind}`, {
|
|
720
|
+
url: data.url,
|
|
721
|
+
status: data.status ?? 0,
|
|
722
|
+
code: data.exitCode ?? -1
|
|
723
|
+
});
|
|
724
|
+
var toResult = (ctx, request, data) => {
|
|
725
|
+
const human2 = [humanLine(ctx, data)];
|
|
726
|
+
if (data.kind === "ok") return success(data, human2);
|
|
727
|
+
return {
|
|
728
|
+
ok: false,
|
|
729
|
+
exitCode: ExitCode.CheckFailed,
|
|
730
|
+
data,
|
|
731
|
+
human: human2,
|
|
732
|
+
error: {
|
|
733
|
+
code: "app_check_failed",
|
|
734
|
+
message: human2.join(" "),
|
|
735
|
+
fix: `finitemonkey app check --port ${String(request.port)}`
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
};
|
|
739
|
+
var appCheckCommand = {
|
|
740
|
+
path: ["app", "check"],
|
|
741
|
+
summaryKey: "command.app_check.summary",
|
|
742
|
+
usage: "finitemonkey app check --port <n> [--start <command>] [--route <path>] [--status <code>] [--body <text>] [--timeout <seconds>] [--host <host>]",
|
|
743
|
+
status: "ready",
|
|
744
|
+
options: {
|
|
745
|
+
port: { type: "string" },
|
|
746
|
+
start: { type: "string" },
|
|
747
|
+
route: { type: "string" },
|
|
748
|
+
status: { type: "string" },
|
|
749
|
+
body: { type: "string" },
|
|
750
|
+
timeout: { type: "string" },
|
|
751
|
+
host: { type: "string" }
|
|
752
|
+
},
|
|
753
|
+
run: async (ctx, args2) => {
|
|
754
|
+
const request = requestFrom(ctx, args2.values);
|
|
755
|
+
if (request === void 0) {
|
|
756
|
+
return {
|
|
757
|
+
ok: false,
|
|
758
|
+
exitCode: ExitCode.Usage,
|
|
759
|
+
human: [ctx.t("app.check.usage")],
|
|
760
|
+
error: {
|
|
761
|
+
code: "app_check_failed",
|
|
762
|
+
message: ctx.t("app.check.usage"),
|
|
763
|
+
fix: "finitemonkey app check --port 3000"
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
const result = await probeApp(request);
|
|
768
|
+
const url2 = `http://${request.host}:${String(request.port)}${request.route}`;
|
|
769
|
+
return toResult(ctx, request, { schema: APP_CHECK_SCHEMA, url: url2, ...result });
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// src/commands/doctor.ts
|
|
774
|
+
import { dirname as dirname7 } from "node:path";
|
|
775
|
+
|
|
471
776
|
// src/install/apply.ts
|
|
472
777
|
import { dirname as dirname3 } from "node:path";
|
|
473
778
|
|
|
@@ -512,12 +817,12 @@ var parseAdded = (value) => {
|
|
|
512
817
|
const deny2 = strings(value["deny"]);
|
|
513
818
|
const { schema, attribution } = value;
|
|
514
819
|
if (deny2 === void 0 || typeof schema !== "boolean" || typeof attribution !== "boolean") return void 0;
|
|
515
|
-
const
|
|
820
|
+
const ask2 = strings(value["ask"]) ?? [];
|
|
516
821
|
const blockReads = value["blockReads"] === true;
|
|
517
822
|
const marketplace = value["marketplace"] === true;
|
|
518
823
|
const plugin = value["plugin"] === true;
|
|
519
824
|
const language = value["language"];
|
|
520
|
-
const added = { schema, attribution, deny: deny2, ask, blockReads, marketplace, plugin };
|
|
825
|
+
const added = { schema, attribution, deny: deny2, ask: ask2, blockReads, marketplace, plugin };
|
|
521
826
|
return typeof language === "string" ? { ...added, language } : added;
|
|
522
827
|
};
|
|
523
828
|
var parseEntry = (value) => {
|
|
@@ -837,8 +1142,8 @@ var execForm = (runner, event) => {
|
|
|
837
1142
|
};
|
|
838
1143
|
var hookHandler = (runner, spec2, failClosedSupported) => {
|
|
839
1144
|
const failure4 = spec2.guard && failClosedSupported ? { onFailure: "block" } : {};
|
|
840
|
-
const { command, args } = execForm(runner, spec2.event);
|
|
841
|
-
return { type: "command", command, args, timeout: spec2.timeout, ...failure4 };
|
|
1145
|
+
const { command, args: args2 } = execForm(runner, spec2.event);
|
|
1146
|
+
return { type: "command", command, args: args2, timeout: spec2.timeout, ...failure4 };
|
|
842
1147
|
};
|
|
843
1148
|
var OWN_SHELL = /(^|[\s/"'])finitemonkey(@[^\s"]+|\.mjs|\.cmd|\.exe)?"?\s+hook\s/;
|
|
844
1149
|
var OWN_SCRIPT = /finitemonkey(\.mjs|\.cmd|\.exe)?$/;
|
|
@@ -847,19 +1152,19 @@ var isOwnHandler = (handler) => {
|
|
|
847
1152
|
if (!isRecord(handler)) return false;
|
|
848
1153
|
const command = handler["command"];
|
|
849
1154
|
if (typeof command !== "string") return false;
|
|
850
|
-
const
|
|
851
|
-
if (
|
|
852
|
-
const hookAt =
|
|
1155
|
+
const args2 = stringsOf(handler["args"]);
|
|
1156
|
+
if (args2.length === 0) return OWN_SHELL.test(`${command} `);
|
|
1157
|
+
const hookAt = args2.indexOf("hook");
|
|
853
1158
|
if (hookAt < 0) return false;
|
|
854
|
-
const target = hookAt === 0 ? command :
|
|
1159
|
+
const target = hookAt === 0 ? command : args2[hookAt - 1] ?? "";
|
|
855
1160
|
return OWN_SCRIPT.test(target);
|
|
856
1161
|
};
|
|
857
1162
|
|
|
858
1163
|
// src/install/skill-template.ts
|
|
859
|
-
var cliCommand = (runner,
|
|
860
|
-
if (runner.kind === "local") return `node ${LOCAL_BIN} ${
|
|
861
|
-
if (runner.kind === "vendored") return `node ${VENDOR_BIN} ${
|
|
862
|
-
return isScript(runner.path) ? `node "${runner.path}" ${
|
|
1164
|
+
var cliCommand = (runner, args2) => {
|
|
1165
|
+
if (runner.kind === "local") return `node ${LOCAL_BIN} ${args2}`;
|
|
1166
|
+
if (runner.kind === "vendored") return `node ${VENDOR_BIN} ${args2}`;
|
|
1167
|
+
return isScript(runner.path) ? `node "${runner.path}" ${args2}` : `"${runner.path}" ${args2}`;
|
|
863
1168
|
};
|
|
864
1169
|
var verifySkillTemplate = (runner, lang) => {
|
|
865
1170
|
const skill = TEMPLATES[lang].verifySkill;
|
|
@@ -1258,7 +1563,7 @@ var mergeSettings = (current2, wanted, recorded) => {
|
|
|
1258
1563
|
const existingDeny = asList(permissions["deny"]);
|
|
1259
1564
|
const existingAsk = asList(permissions["ask"]);
|
|
1260
1565
|
const deny2 = missing(wanted.deny, existingDeny);
|
|
1261
|
-
const
|
|
1566
|
+
const ask2 = missing(wanted.ask, existingAsk);
|
|
1262
1567
|
const blockReads = !(BLOCK_READS in permissions);
|
|
1263
1568
|
const attribution = wanted.attributionOff && !("attribution" in base);
|
|
1264
1569
|
const marketplace = wanted.marketplace && !hasEntry(base, "extraKnownMarketplaces", MARKETPLACE_KEY);
|
|
@@ -1266,14 +1571,14 @@ var mergeSettings = (current2, wanted, recorded) => {
|
|
|
1266
1571
|
const language = "language" in base ? void 0 : wanted.language;
|
|
1267
1572
|
let settings = withPermissions(withHooks(base, hooks), {
|
|
1268
1573
|
deny: [...existingDeny, ...deny2],
|
|
1269
|
-
ask: [...existingAsk, ...
|
|
1574
|
+
ask: [...existingAsk, ...ask2],
|
|
1270
1575
|
blockReads: blockReads ? true : permissions[BLOCK_READS]
|
|
1271
1576
|
});
|
|
1272
1577
|
if (attribution) settings = { ...settings, attribution: ATTRIBUTION_OFF };
|
|
1273
1578
|
if (marketplace) settings = withEntry(settings, "extraKnownMarketplaces", MARKETPLACE_KEY, MARKETPLACE_ENTRY);
|
|
1274
1579
|
if (plugin) settings = withEntry(settings, "enabledPlugins", PLUGIN_ID, true);
|
|
1275
1580
|
if (language !== void 0) settings = { ...settings, language };
|
|
1276
|
-
const added = { schema, deny: deny2, ask, blockReads, attribution, marketplace, plugin };
|
|
1581
|
+
const added = { schema, deny: deny2, ask: ask2, blockReads, attribution, marketplace, plugin };
|
|
1277
1582
|
return { settings, added: language === void 0 ? added : { ...added, language } };
|
|
1278
1583
|
};
|
|
1279
1584
|
var sameAttribution = (value) => JSON.stringify(value) === JSON.stringify(ATTRIBUTION_OFF);
|
|
@@ -2192,8 +2497,8 @@ var fmPaths = (root) => {
|
|
|
2192
2497
|
var HOOK_FAILURE_EVENT = "hook.failed";
|
|
2193
2498
|
var FAILURES = ["failed_open", "failed_closed", "stop_released"];
|
|
2194
2499
|
var MAX_DETAIL = 500;
|
|
2195
|
-
var logHookFailure = (ctx, event,
|
|
2196
|
-
if (!FAILURES.includes(
|
|
2500
|
+
var logHookFailure = (ctx, event, outcome2) => {
|
|
2501
|
+
if (!FAILURES.includes(outcome2.verdict)) return;
|
|
2197
2502
|
const fromEnv = ctx.env["CLAUDE_PROJECT_DIR"];
|
|
2198
2503
|
const root = fromEnv === void 0 ? findGitRoot(ctx.cwd, ctx.runtime) : toAbsolutePath(fromEnv);
|
|
2199
2504
|
if (root === void 0) return;
|
|
@@ -2201,8 +2506,8 @@ var logHookFailure = (ctx, event, outcome) => {
|
|
|
2201
2506
|
if (ctx.runtime.stat(paths.dir)?.kind !== "dir") return;
|
|
2202
2507
|
logEvent(ctx.runtime, paths, HOOK_FAILURE_EVENT, {
|
|
2203
2508
|
hook: event,
|
|
2204
|
-
verdict:
|
|
2205
|
-
detail: maskText(
|
|
2509
|
+
verdict: outcome2.verdict,
|
|
2510
|
+
detail: maskText(outcome2.stderr.trim()).slice(0, MAX_DETAIL)
|
|
2206
2511
|
});
|
|
2207
2512
|
};
|
|
2208
2513
|
|
|
@@ -2615,7 +2920,7 @@ var checkSandbox = (env) => {
|
|
|
2615
2920
|
}
|
|
2616
2921
|
if (os === "macos") return [finding("sandbox", "ok", "doctor.sandbox.ok")];
|
|
2617
2922
|
if (os === "other") return [];
|
|
2618
|
-
const missing2 = SANDBOX_TOOLS.filter(({ command, args }) => !env.runtime.probe(command,
|
|
2923
|
+
const missing2 = SANDBOX_TOOLS.filter(({ command, args: args2 }) => !env.runtime.probe(command, args2, PROBE_MS2).found).map(
|
|
2619
2924
|
({ command }) => command
|
|
2620
2925
|
);
|
|
2621
2926
|
if (missing2.length === 0) return [finding("sandbox", "ok", "doctor.sandbox.ok")];
|
|
@@ -3336,10 +3641,10 @@ var withAssignments = (stage) => {
|
|
|
3336
3641
|
}
|
|
3337
3642
|
return { ...stage, argv: stage.argv.slice(index), env };
|
|
3338
3643
|
};
|
|
3339
|
-
var skipOptions = (
|
|
3644
|
+
var skipOptions = (args2, wrapper) => {
|
|
3340
3645
|
let index = 0;
|
|
3341
|
-
while (index <
|
|
3342
|
-
const arg =
|
|
3646
|
+
while (index < args2.length) {
|
|
3647
|
+
const arg = args2[index] ?? "";
|
|
3343
3648
|
if (arg === "--") return index + 1 + wrapper.positionals;
|
|
3344
3649
|
if (!arg.startsWith("-") || arg === "-") break;
|
|
3345
3650
|
if (wrapper.queries.has(arg)) return void 0;
|
|
@@ -3369,33 +3674,33 @@ var envCommand = (stage) => {
|
|
|
3369
3674
|
return printsEnvironment ? { kind: "command", stage, extra: [] } : shift(stage, index, "env");
|
|
3370
3675
|
};
|
|
3371
3676
|
var shellScript = (stage, name, stdin) => {
|
|
3372
|
-
const
|
|
3677
|
+
const args2 = stage.argv.slice(1);
|
|
3373
3678
|
let index = 0;
|
|
3374
3679
|
let command = false;
|
|
3375
|
-
while (index <
|
|
3376
|
-
const arg =
|
|
3680
|
+
while (index < args2.length && /^[-+]/.test(args2[index] ?? "")) {
|
|
3681
|
+
const arg = args2[index] ?? "";
|
|
3377
3682
|
if (/^-[A-Za-z]*c[A-Za-z]*$/.test(arg)) command = true;
|
|
3378
3683
|
index += SHELL_WITH_VALUE.has(arg) ? 2 : 1;
|
|
3379
3684
|
}
|
|
3380
|
-
const script =
|
|
3685
|
+
const script = args2[index];
|
|
3381
3686
|
if (command && script !== void 0) return { kind: "script", script, dialect: "bash", stage: shift(stage, 0, name) };
|
|
3382
3687
|
if (script === void 0 && stdin !== void 0) return { kind: "script", script: stdin, dialect: "bash", stage };
|
|
3383
3688
|
return void 0;
|
|
3384
3689
|
};
|
|
3385
3690
|
var decodeEncoded = (value) => Buffer.from(value, "base64").toString("utf16le");
|
|
3386
3691
|
var powershellScript = (stage, name) => {
|
|
3387
|
-
const
|
|
3388
|
-
const at =
|
|
3389
|
-
const encoded =
|
|
3692
|
+
const args2 = stage.argv.slice(1);
|
|
3693
|
+
const at = args2.findIndex((arg) => /^[-/](?:c|co|com|comm|comma|comman|command)$/i.test(arg));
|
|
3694
|
+
const encoded = args2.findIndex((arg) => /^[-/](?:e|ec|enc|encodedcommand)$/i.test(arg));
|
|
3390
3695
|
if (at >= 0) {
|
|
3391
3696
|
return {
|
|
3392
3697
|
kind: "script",
|
|
3393
|
-
script:
|
|
3698
|
+
script: args2.slice(at + 1).join(" "),
|
|
3394
3699
|
dialect: "powershell",
|
|
3395
3700
|
stage: shift(stage, 0, name)
|
|
3396
3701
|
};
|
|
3397
3702
|
}
|
|
3398
|
-
const value = encoded >= 0 ?
|
|
3703
|
+
const value = encoded >= 0 ? args2[encoded + 1] : void 0;
|
|
3399
3704
|
if (value !== void 0) {
|
|
3400
3705
|
return { kind: "script", script: decodeEncoded(value), dialect: "powershell", stage: shift(stage, 0, name) };
|
|
3401
3706
|
}
|
|
@@ -3574,20 +3879,20 @@ var envFindings = (command) => {
|
|
|
3574
3879
|
const exported = command.argv[0] === "export" ? command.argv.slice(1).map((arg) => arg.split("=", 2)) : [];
|
|
3575
3880
|
return [...pairs2, ...exported].filter(([name = ""]) => HOOK_ENV.test(name)).map(([name = "", value = ""]) => ({ kind: "hook_env", detail: `${name}=${value}` }));
|
|
3576
3881
|
};
|
|
3577
|
-
var splitGit = (
|
|
3882
|
+
var splitGit = (args2) => {
|
|
3578
3883
|
let index = 0;
|
|
3579
3884
|
const globals = [];
|
|
3580
|
-
while (index <
|
|
3581
|
-
const arg =
|
|
3885
|
+
while (index < args2.length && (args2[index] ?? "").startsWith("-")) {
|
|
3886
|
+
const arg = args2[index] ?? "";
|
|
3582
3887
|
globals.push(arg);
|
|
3583
|
-
if (GIT_VALUE_OPTIONS.has(arg)) globals.push(
|
|
3888
|
+
if (GIT_VALUE_OPTIONS.has(arg)) globals.push(args2[index + 1] ?? "");
|
|
3584
3889
|
index += GIT_VALUE_OPTIONS.has(arg) ? 2 : 1;
|
|
3585
3890
|
}
|
|
3586
|
-
return { globals, rest:
|
|
3891
|
+
return { globals, rest: args2.slice(index) };
|
|
3587
3892
|
};
|
|
3588
|
-
var commitHasShortN = (
|
|
3589
|
-
for (let index = 0; index <
|
|
3590
|
-
const arg =
|
|
3893
|
+
var commitHasShortN = (args2) => {
|
|
3894
|
+
for (let index = 0; index < args2.length; index += 1) {
|
|
3895
|
+
const arg = args2[index] ?? "";
|
|
3591
3896
|
if (arg === "--") return false;
|
|
3592
3897
|
if (!/^-[A-Za-z]/.test(arg)) continue;
|
|
3593
3898
|
for (const char of arg.slice(1)) {
|
|
@@ -3600,8 +3905,8 @@ var commitHasShortN = (args) => {
|
|
|
3600
3905
|
}
|
|
3601
3906
|
return false;
|
|
3602
3907
|
};
|
|
3603
|
-
var gitFindings = (
|
|
3604
|
-
const { globals, rest } = splitGit(
|
|
3908
|
+
var gitFindings = (args2) => {
|
|
3909
|
+
const { globals, rest } = splitGit(args2);
|
|
3605
3910
|
const found = [];
|
|
3606
3911
|
globals.forEach((arg, index) => {
|
|
3607
3912
|
if (arg === "-c" && isHooksPath(globals[index + 1] ?? "") || /^--config-env=core\.hookspath/i.test(arg)) {
|
|
@@ -3618,10 +3923,21 @@ var gitFindings = (args) => {
|
|
|
3618
3923
|
return found;
|
|
3619
3924
|
};
|
|
3620
3925
|
var FM_NAMES = /* @__PURE__ */ new Set(["finitemonkey", "fm"]);
|
|
3926
|
+
var FM_SCRIPT = /(^|[\\/])(finitemonkey|fm)(\.c?m?js)?$/;
|
|
3927
|
+
var RUNNERS = /* @__PURE__ */ new Set(["npx", "pnpm", "bunx", "yarn"]);
|
|
3928
|
+
var fmStart = (argv) => {
|
|
3929
|
+
const first = argv[0] ?? "";
|
|
3930
|
+
if (RUNNERS.has(first)) return argv.findIndex((arg) => FM_NAMES.has(arg.replace(/@.*$/, "")));
|
|
3931
|
+
if (first === "node" || first === "bun" || first === "deno") return FM_SCRIPT.test(argv[1] ?? "") ? 1 : -1;
|
|
3932
|
+
return FM_SCRIPT.test(first) ? 0 : -1;
|
|
3933
|
+
};
|
|
3621
3934
|
var fmFindings = (argv) => {
|
|
3622
|
-
const start = argv
|
|
3623
|
-
|
|
3624
|
-
|
|
3935
|
+
const start = fmStart(argv);
|
|
3936
|
+
if (start < 0) return [];
|
|
3937
|
+
const sub = argv[start + 1];
|
|
3938
|
+
if (sub === "allow") return [{ kind: "fm_allow", detail: "finitemonkey allow" }];
|
|
3939
|
+
if (sub === "off" || sub === "on") return [{ kind: "fm_pause", detail: `finitemonkey ${sub}` }];
|
|
3940
|
+
return [];
|
|
3625
3941
|
};
|
|
3626
3942
|
var detectBypass = (commandLine) => parseShell(commandLine).flatMap((command) => [
|
|
3627
3943
|
...envFindings(command),
|
|
@@ -3678,16 +3994,16 @@ var GIT_WRITERS = /* @__PURE__ */ new Set(["checkout", "restore", "rm", "mv", "c
|
|
|
3678
3994
|
var FM_NAMES2 = /* @__PURE__ */ new Set(["finitemonkey", "fm"]);
|
|
3679
3995
|
var inline = (argv) => argv.some((arg) => arg === "-e" || arg === "-c" || arg === "--eval");
|
|
3680
3996
|
var writtenPaths = (command) => {
|
|
3681
|
-
const [name = "", ...
|
|
3682
|
-
const operands2 =
|
|
3683
|
-
const ddTargets =
|
|
3997
|
+
const [name = "", ...args2] = command.argv;
|
|
3998
|
+
const operands2 = args2.filter((arg) => !arg.startsWith("-"));
|
|
3999
|
+
const ddTargets = args2.filter((arg) => arg.startsWith("of=")).map((arg) => arg.slice(3));
|
|
3684
4000
|
if (FM_NAMES2.has(name)) return command.redirects;
|
|
3685
4001
|
if (COPIERS.has(name)) return [...command.redirects, ...operands2.slice(-1)];
|
|
3686
4002
|
if (WRITERS.has(name)) return [...command.redirects, ...operands2, ...ddTargets];
|
|
3687
|
-
if (IN_PLACE.has(name) &&
|
|
4003
|
+
if (IN_PLACE.has(name) && args2.some((arg) => /^-[a-zA-Z]*i/.test(arg) || arg.startsWith("--in-place"))) {
|
|
3688
4004
|
return [...command.redirects, ...operands2];
|
|
3689
4005
|
}
|
|
3690
|
-
if (INTERPRETERS.has(name) && inline(
|
|
4006
|
+
if (INTERPRETERS.has(name) && inline(args2)) return [...command.redirects, ...args2];
|
|
3691
4007
|
if (name === "git" && GIT_WRITERS.has(operands2[0] ?? "")) return [...command.redirects, ...operands2.slice(1)];
|
|
3692
4008
|
return command.redirects;
|
|
3693
4009
|
};
|
|
@@ -3706,14 +4022,14 @@ var bashSelfTargets = (root, commandLine) => parseShell(commandLine).flatMap(
|
|
|
3706
4022
|
// src/guards/self/hook.ts
|
|
3707
4023
|
var targets = (input) => {
|
|
3708
4024
|
const tool = toolName(input.payload.raw);
|
|
3709
|
-
const
|
|
4025
|
+
const args2 = toolInput(input.payload.raw);
|
|
3710
4026
|
const root = guardRoot(input);
|
|
3711
4027
|
if (FILE_TOOLS.has(tool)) {
|
|
3712
|
-
const path = textField(
|
|
4028
|
+
const path = textField(args2, "file_path", "notebook_path") ?? "";
|
|
3713
4029
|
const kind = path === "" ? void 0 : selfTarget(root, path);
|
|
3714
4030
|
return kind === void 0 ? [] : [{ kind, path }];
|
|
3715
4031
|
}
|
|
3716
|
-
return SHELL_TOOLS.has(tool) ? bashSelfTargets(root, textField(
|
|
4032
|
+
return SHELL_TOOLS.has(tool) ? bashSelfTargets(root, textField(args2, "command") ?? "") : [];
|
|
3717
4033
|
};
|
|
3718
4034
|
var selfGuard = (input) => {
|
|
3719
4035
|
const found = targets(input);
|
|
@@ -3897,19 +4213,19 @@ var read = (input, path) => {
|
|
|
3897
4213
|
const text6 = input.runtime.readText(path);
|
|
3898
4214
|
return text6.ok ? text6.value : void 0;
|
|
3899
4215
|
};
|
|
3900
|
-
var proposed = (tool,
|
|
3901
|
-
if (tool === "Write") return textField(
|
|
3902
|
-
return before === void 0 ? void 0 : applyEdits(before, editsOf(
|
|
4216
|
+
var proposed = (tool, args2, before) => {
|
|
4217
|
+
if (tool === "Write") return textField(args2, "content") ?? "";
|
|
4218
|
+
return before === void 0 ? void 0 : applyEdits(before, editsOf(args2));
|
|
3903
4219
|
};
|
|
3904
4220
|
var fileViolations = (input, root) => {
|
|
3905
4221
|
const tool = toolName(input.payload.raw);
|
|
3906
|
-
const
|
|
3907
|
-
const file = textField(
|
|
4222
|
+
const args2 = toolInput(input.payload.raw);
|
|
4223
|
+
const file = textField(args2, "file_path") ?? "";
|
|
3908
4224
|
if (tool === "NotebookEdit" || file === "") return [];
|
|
3909
4225
|
const local = localPath(root, file);
|
|
3910
4226
|
if (!isTestFile(local) && !isProtectedConfig(local)) return [];
|
|
3911
4227
|
const before = read(input, toAbsolutePath(file, root));
|
|
3912
|
-
const after = proposed(tool,
|
|
4228
|
+
const after = proposed(tool, args2, before);
|
|
3913
4229
|
if (after === void 0) return [];
|
|
3914
4230
|
const accepted2 = readTrust(input.runtime, fmPaths(root)).configs[local];
|
|
3915
4231
|
if (before === void 0) return compareNewTestFile(local, after);
|
|
@@ -3939,9 +4255,6 @@ var testsGuard = (input) => {
|
|
|
3939
4255
|
return deny(t("gate.guard.tests.model", { detail: reason }), t("gate.guard.tests.human", { detail: reason }));
|
|
3940
4256
|
};
|
|
3941
4257
|
|
|
3942
|
-
// src/gate/hooks/config.ts
|
|
3943
|
-
import { join as join13 } from "node:path";
|
|
3944
|
-
|
|
3945
4258
|
// src/gate/hooks/common.ts
|
|
3946
4259
|
import { dirname as dirname5, join as join12 } from "node:path";
|
|
3947
4260
|
var DEFAULT_GATE_BUDGET_MS = 3e5;
|
|
@@ -3972,7 +4285,90 @@ var contextOutput = (event, additionalContext, systemMessage) => ({
|
|
|
3972
4285
|
});
|
|
3973
4286
|
var human = (text6) => `finitemonkey: ${text6}`;
|
|
3974
4287
|
|
|
4288
|
+
// src/guards/release/markers.ts
|
|
4289
|
+
var LINE = /^\s*(?:finitemonkey|fm):\s+(allow|approve|trust)\s+(\S+)(?:\s+(.*))?$/i;
|
|
4290
|
+
var NAME = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,80}$/;
|
|
4291
|
+
var NOT_FROM_PERSON = [
|
|
4292
|
+
/<task-notification\b/i,
|
|
4293
|
+
/<agent-message\b/i,
|
|
4294
|
+
/^\s*\[julius2claude\]/,
|
|
4295
|
+
/\[Subagent hand-back\]/i
|
|
4296
|
+
];
|
|
4297
|
+
var comesFromPerson = (prompt) => !NOT_FROM_PERSON.some((pattern) => pattern.test(prompt));
|
|
4298
|
+
var toMarker = (verb, target, rest) => {
|
|
4299
|
+
if (!NAME.test(target)) return void 0;
|
|
4300
|
+
if (verb === "trust") return { type: "trust", task: target };
|
|
4301
|
+
if (verb === "allow") {
|
|
4302
|
+
return rest.length >= 3 ? { type: "allow", guard: target.toLowerCase(), reason: rest } : void 0;
|
|
4303
|
+
}
|
|
4304
|
+
const slash = target.indexOf("/");
|
|
4305
|
+
const task = slash < 0 ? void 0 : target.slice(0, slash);
|
|
4306
|
+
const check2 = slash < 0 ? target : target.slice(slash + 1);
|
|
4307
|
+
if (check2 === "") return void 0;
|
|
4308
|
+
return { type: "approve", check: check2, reason: rest, ...task === void 0 || task === "" ? {} : { task } };
|
|
4309
|
+
};
|
|
4310
|
+
var parseMarkers = (prompt) => {
|
|
4311
|
+
if (!comesFromPerson(prompt)) return [];
|
|
4312
|
+
return prompt.split(/\r?\n/).flatMap((line2) => {
|
|
4313
|
+
const match = LINE.exec(line2);
|
|
4314
|
+
if (match === null) return [];
|
|
4315
|
+
const marker = toMarker((match[1] ?? "").toLowerCase(), match[2] ?? "", (match[3] ?? "").trim());
|
|
4316
|
+
return marker === void 0 ? [] : [marker];
|
|
4317
|
+
});
|
|
4318
|
+
};
|
|
4319
|
+
|
|
4320
|
+
// src/policy/pause.ts
|
|
4321
|
+
var PAUSE_FILE = "pause.json";
|
|
4322
|
+
var readPause = (runtime, paths) => {
|
|
4323
|
+
const text6 = runtime.readText(paths.cache(PAUSE_FILE));
|
|
4324
|
+
const parsed = text6.ok ? parseJsonObject(text6.value) : void 0;
|
|
4325
|
+
if (parsed?.ok !== true || !isRecord(parsed.value)) return void 0;
|
|
4326
|
+
const { sessionId, since, by } = parsed.value;
|
|
4327
|
+
if (typeof sessionId !== "string" || typeof since !== "string") return void 0;
|
|
4328
|
+
return { sessionId, since, by: by === "terminal" ? "terminal" : "prompt" };
|
|
4329
|
+
};
|
|
4330
|
+
var pausedFor = (runtime, paths, sessionId) => {
|
|
4331
|
+
const pause = readPause(runtime, paths);
|
|
4332
|
+
return pause !== void 0 && sessionId !== void 0 && pause.sessionId === sessionId ? pause : void 0;
|
|
4333
|
+
};
|
|
4334
|
+
var setPause = (runtime, paths, sessionId, by) => {
|
|
4335
|
+
const pause = { sessionId, since: runtime.now(), by };
|
|
4336
|
+
runtime.writeText(paths.cache(PAUSE_FILE), `${JSON.stringify(pause)}
|
|
4337
|
+
`);
|
|
4338
|
+
logEvent(runtime, paths, "gate_paused", { sessionId, by });
|
|
4339
|
+
return pause;
|
|
4340
|
+
};
|
|
4341
|
+
var clearPause = (runtime, paths, by) => {
|
|
4342
|
+
const pause = readPause(runtime, paths);
|
|
4343
|
+
if (pause === void 0) return void 0;
|
|
4344
|
+
runtime.remove(paths.cache(PAUSE_FILE));
|
|
4345
|
+
logEvent(runtime, paths, "gate_resumed", { sessionId: pause.sessionId, since: pause.since, by });
|
|
4346
|
+
return pause;
|
|
4347
|
+
};
|
|
4348
|
+
|
|
4349
|
+
// src/policy/pause-hooks.ts
|
|
4350
|
+
var COMMAND = /^\s*(fm|finitemonkey)\s+(off|on)\s*$/i;
|
|
4351
|
+
var pausePrompt = (input) => {
|
|
4352
|
+
const prompt = textField(input.payload.raw, "prompt", "prompt_text") ?? "";
|
|
4353
|
+
const match = COMMAND.exec(prompt);
|
|
4354
|
+
if (match === null || !comesFromPerson(prompt)) return { kind: "allow" };
|
|
4355
|
+
const paths = projectPaths(input);
|
|
4356
|
+
const sessionId = input.payload.sessionId;
|
|
4357
|
+
if (paths === void 0 || sessionId === void 0) return { kind: "allow" };
|
|
4358
|
+
const off = (match[2] ?? "").toLowerCase() === "off";
|
|
4359
|
+
if (off) setPause(input.runtime, paths, sessionId, "prompt");
|
|
4360
|
+
else clearPause(input.runtime, paths, "prompt");
|
|
4361
|
+
return { kind: "block", reason: human(input.t(off ? "pause.off" : "pause.on")) };
|
|
4362
|
+
};
|
|
4363
|
+
var unlessPaused = (handler) => (input) => {
|
|
4364
|
+
const paths = projectPaths(input);
|
|
4365
|
+
const pause = paths === void 0 ? void 0 : pausedFor(input.runtime, paths, input.payload.sessionId);
|
|
4366
|
+
if (pause === void 0) return handler(input);
|
|
4367
|
+
return allowWith({ systemMessage: human(input.t("pause.report", { since: pause.since })) });
|
|
4368
|
+
};
|
|
4369
|
+
|
|
3975
4370
|
// src/gate/hooks/config.ts
|
|
4371
|
+
import { join as join13 } from "node:path";
|
|
3976
4372
|
var CONFIG_FILE3 = "config-hooks.json";
|
|
3977
4373
|
var GUARDED_SOURCES = /* @__PURE__ */ new Set(["user_settings", "project_settings", "local_settings"]);
|
|
3978
4374
|
var countIn = (value) => {
|
|
@@ -4038,38 +4434,6 @@ var configChange = (input) => {
|
|
|
4038
4434
|
};
|
|
4039
4435
|
};
|
|
4040
4436
|
|
|
4041
|
-
// src/guards/release/markers.ts
|
|
4042
|
-
var LINE = /^\s*(?:finitemonkey|fm):\s+(allow|approve|trust)\s+(\S+)(?:\s+(.*))?$/i;
|
|
4043
|
-
var NAME = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,80}$/;
|
|
4044
|
-
var NOT_FROM_PERSON = [
|
|
4045
|
-
/<task-notification\b/i,
|
|
4046
|
-
/<agent-message\b/i,
|
|
4047
|
-
/^\s*\[julius2claude\]/,
|
|
4048
|
-
/\[Subagent hand-back\]/i
|
|
4049
|
-
];
|
|
4050
|
-
var comesFromPerson = (prompt) => !NOT_FROM_PERSON.some((pattern) => pattern.test(prompt));
|
|
4051
|
-
var toMarker = (verb, target, rest) => {
|
|
4052
|
-
if (!NAME.test(target)) return void 0;
|
|
4053
|
-
if (verb === "trust") return { type: "trust", task: target };
|
|
4054
|
-
if (verb === "allow") {
|
|
4055
|
-
return rest.length >= 3 ? { type: "allow", guard: target.toLowerCase(), reason: rest } : void 0;
|
|
4056
|
-
}
|
|
4057
|
-
const slash = target.indexOf("/");
|
|
4058
|
-
const task = slash < 0 ? void 0 : target.slice(0, slash);
|
|
4059
|
-
const check2 = slash < 0 ? target : target.slice(slash + 1);
|
|
4060
|
-
if (check2 === "") return void 0;
|
|
4061
|
-
return { type: "approve", check: check2, reason: rest, ...task === void 0 || task === "" ? {} : { task } };
|
|
4062
|
-
};
|
|
4063
|
-
var parseMarkers = (prompt) => {
|
|
4064
|
-
if (!comesFromPerson(prompt)) return [];
|
|
4065
|
-
return prompt.split(/\r?\n/).flatMap((line2) => {
|
|
4066
|
-
const match = LINE.exec(line2);
|
|
4067
|
-
if (match === null) return [];
|
|
4068
|
-
const marker = toMarker((match[1] ?? "").toLowerCase(), match[2] ?? "", (match[3] ?? "").trim());
|
|
4069
|
-
return marker === void 0 ? [] : [marker];
|
|
4070
|
-
});
|
|
4071
|
-
};
|
|
4072
|
-
|
|
4073
4437
|
// src/task/implicit.ts
|
|
4074
4438
|
var IMPLICIT_ID = "implicit";
|
|
4075
4439
|
var LOCKFILES2 = [
|
|
@@ -4426,7 +4790,7 @@ var str = (record3, key, at, issues, required) => {
|
|
|
4426
4790
|
}
|
|
4427
4791
|
return value;
|
|
4428
4792
|
};
|
|
4429
|
-
var
|
|
4793
|
+
var positive2 = (record3, key, at, issues) => {
|
|
4430
4794
|
const value = record3[key];
|
|
4431
4795
|
if (value === void 0 || value === null) return void 0;
|
|
4432
4796
|
if (typeof value === "number" && Number.isInteger(value) && value > 0) return value;
|
|
@@ -4446,11 +4810,26 @@ var gitRequire = (value, at, issues) => {
|
|
|
4446
4810
|
if (known2.some((item) => item === void 0)) issues.push(`${at}: use ${GIT_REQUIREMENTS.join(", ")}`);
|
|
4447
4811
|
return known2.filter((item) => item !== void 0);
|
|
4448
4812
|
};
|
|
4813
|
+
var appFields = (record3, kind, at, issues) => {
|
|
4814
|
+
const port = positive2(record3, "port", at, issues);
|
|
4815
|
+
if (kind === "runtime" && port === void 0) issues.push(`${at}port: required`);
|
|
4816
|
+
if (port !== void 0 && port > 65535) issues.push(`${at}port: must be at most 65535`);
|
|
4817
|
+
const status = positive2(record3, "status", at, issues);
|
|
4818
|
+
const route = str(record3, "route", at, issues, false);
|
|
4819
|
+
const body2 = str(record3, "body", at, issues, false);
|
|
4820
|
+
return {
|
|
4821
|
+
...port === void 0 ? {} : { port },
|
|
4822
|
+
...route === void 0 ? {} : { route },
|
|
4823
|
+
...status === void 0 ? {} : { status },
|
|
4824
|
+
...body2 === void 0 ? {} : { body: body2 }
|
|
4825
|
+
};
|
|
4826
|
+
};
|
|
4449
4827
|
var checkFields = (record3, kind, at, issues) => {
|
|
4450
4828
|
const run4 = str(record3, "run", at, issues, kind === "command");
|
|
4451
|
-
const timeoutS =
|
|
4829
|
+
const timeoutS = positive2(record3, "timeout_s", at, issues);
|
|
4452
4830
|
const description = str(record3, "description", at, issues, kind === "manual");
|
|
4453
4831
|
const require2 = kind === "git" ? gitRequire(record3["require"] ?? ["committed"], `${at}require`, issues) : void 0;
|
|
4832
|
+
const app = appFields(record3, kind, at, issues);
|
|
4454
4833
|
const open = record3["require_open"];
|
|
4455
4834
|
if (open !== void 0 && typeof open !== "boolean") issues.push(`${at}require_open: must be true or false`);
|
|
4456
4835
|
return {
|
|
@@ -4458,7 +4837,8 @@ var checkFields = (record3, kind, at, issues) => {
|
|
|
4458
4837
|
...timeoutS === void 0 ? {} : { timeoutS },
|
|
4459
4838
|
...description === void 0 ? {} : { description },
|
|
4460
4839
|
...require2 === void 0 ? {} : { require: require2 },
|
|
4461
|
-
...typeof open === "boolean" ? { requireOpen: open } : {}
|
|
4840
|
+
...typeof open === "boolean" ? { requireOpen: open } : {},
|
|
4841
|
+
...app
|
|
4462
4842
|
};
|
|
4463
4843
|
};
|
|
4464
4844
|
var acceptanceItem = (value, index, issues) => {
|
|
@@ -4496,8 +4876,8 @@ var scope = (value, issues) => {
|
|
|
4496
4876
|
...files === void 0 ? {} : { files },
|
|
4497
4877
|
...lines3 === void 0 ? {} : { lines: lines3 }
|
|
4498
4878
|
}))({
|
|
4499
|
-
files:
|
|
4500
|
-
lines:
|
|
4879
|
+
files: positive2(budget, "files", "scope.diff_budget.", issues),
|
|
4880
|
+
lines: positive2(budget, "lines", "scope.diff_budget.", issues)
|
|
4501
4881
|
}) : void 0;
|
|
4502
4882
|
if (budget !== void 0 && budget !== null && !isRecord(budget)) issues.push("scope.diff_budget: must be a mapping");
|
|
4503
4883
|
const protectedValue = value["tests_protected"];
|
|
@@ -4622,12 +5002,12 @@ var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
|
4622
5002
|
var GIT_TIMEOUT_MS = 15e3;
|
|
4623
5003
|
var EXCLUDE_FM = `:(exclude)${FM_DIR}`;
|
|
4624
5004
|
var gitAt = (runtime, cwd) => {
|
|
4625
|
-
const run4 = (
|
|
5005
|
+
const run4 = (args2) => runtime.exec({ command: "git", args: ["-c", "core.quotepath=off", ...args2], cwd, timeoutMs: GIT_TIMEOUT_MS });
|
|
4626
5006
|
return {
|
|
4627
5007
|
cwd,
|
|
4628
5008
|
run: run4,
|
|
4629
|
-
out: (
|
|
4630
|
-
const result = run4(
|
|
5009
|
+
out: (args2) => {
|
|
5010
|
+
const result = run4(args2);
|
|
4631
5011
|
return result.found && result.exitCode === 0 ? result.stdout : void 0;
|
|
4632
5012
|
}
|
|
4633
5013
|
};
|
|
@@ -4774,7 +5154,7 @@ var parseMergeTreeConflicts = (stdout) => {
|
|
|
4774
5154
|
var PR_FIELDS = "number,url,state,mergeable,mergeStateStatus,baseRefName,headRefOid,statusCheckRollup";
|
|
4775
5155
|
var PR_CACHE_TTL_MS = 6e4;
|
|
4776
5156
|
var GH_TIMEOUT_MS = 8e3;
|
|
4777
|
-
var gh = (runtime, cwd,
|
|
5157
|
+
var gh = (runtime, cwd, args2, timeoutMs = GH_TIMEOUT_MS) => runtime.exec({ command: "gh", args: args2, cwd, timeoutMs });
|
|
4778
5158
|
var ghAuthenticated = (runtime, cwd, timeoutMs = 4e3) => {
|
|
4779
5159
|
const result = gh(runtime, cwd, ["auth", "status"], timeoutMs);
|
|
4780
5160
|
if (result.timedOut) return "timeout";
|
|
@@ -5632,6 +6012,7 @@ var en_default = {
|
|
|
5632
6012
|
"gate.guard.bypass.hooks_path": "Finite Monkey: blocked: {detail} points git away from the project hooks. requires: core.hooksPath stays as configured.",
|
|
5633
6013
|
"gate.guard.bypass.hook_env": "Finite Monkey: blocked: {detail} turns hooks or guards off. requires: hooks and guards stay on.",
|
|
5634
6014
|
"gate.guard.bypass.fm_allow": "Finite Monkey: blocked: releases are made by the person, not by a tool call.",
|
|
6015
|
+
"gate.guard.bypass.fm_pause": "Finite Monkey: blocked: only the person pauses or resumes the gate, by typing `fm off` or `fm on` as the whole prompt.",
|
|
5635
6016
|
"gate.guard.bypass.human": "Blocked {detail}: it would switch the safety net off. If you really want it, type on its own line: finitemonkey: allow bypass <reason>",
|
|
5636
6017
|
"gate.guard.self.policy": "Finite Monkey: blocked: {file} is written only by the finitemonkey executable (evidence, policy and state). requires: change it through finitemonkey commands.",
|
|
5637
6018
|
"gate.guard.self.allow_store": "Finite Monkey: blocked: {file} records what the person released; tools never write it.",
|
|
@@ -5787,7 +6168,35 @@ var en_default = {
|
|
|
5787
6168
|
"gate.callers.warning": "warning only: {percent}% of callers findings were released with callers_ignore ({released} of {total}), above the 5% ceiling",
|
|
5788
6169
|
"command.policy_false_positive.summary": "Record a false positive of a guard in shadow so it is not promoted",
|
|
5789
6170
|
"policy.error.person_only": "Only the person can record a false positive, and this does not look like their terminal (no TTY, or running inside Claude Code)",
|
|
5790
|
-
"policy.false_positive.recorded": "Recorded for {guard}: {count, plural, one {# false positive} other {# false positives}}; it stays in shadow until you set it in .finitemonkey/policy.yml."
|
|
6171
|
+
"policy.false_positive.recorded": "Recorded for {guard}: {count, plural, one {# false positive} other {# false positives}}; it stays in shadow until you set it in .finitemonkey/policy.yml.",
|
|
6172
|
+
"command.app_check.summary": "Start the app or reuse the running one, call one route and check the answer",
|
|
6173
|
+
"app.check.ok": "{url} answered {status}",
|
|
6174
|
+
"app.check.crashed": "the app exited with code {code} before opening the port",
|
|
6175
|
+
"app.check.no_port": "the port of {url} did not open before the timeout",
|
|
6176
|
+
"app.check.no_start": "nothing listens on {url} and no start command was given",
|
|
6177
|
+
"app.check.wrong_status": "{url} answered {status}",
|
|
6178
|
+
"app.check.body_mismatch": "{url} answered {status} without the expected text",
|
|
6179
|
+
"app.check.request_failed": "the request to {url} failed",
|
|
6180
|
+
"app.check.usage": "give --port as a number from 1 to 65535; --status and --timeout must be positive numbers",
|
|
6181
|
+
"gate.require.runtime": "the app starts and `{command}` answers as declared",
|
|
6182
|
+
"gate.runtime.ok": "started, {route} answered {status}, stopped",
|
|
6183
|
+
"gate.runtime.reused": "reused the running app, {route} answered {status}",
|
|
6184
|
+
"gate.runtime.crashed": "the app exited with code {code} before opening its port",
|
|
6185
|
+
"gate.runtime.no_port": "port {port} did not open before the timeout",
|
|
6186
|
+
"gate.runtime.no_start": "nothing listens on port {port} and the check has no `run` to start the app",
|
|
6187
|
+
"gate.runtime.no_port_declared": "the runtime check needs a `port`",
|
|
6188
|
+
"gate.runtime.wrong_status": "{route} answered {status}, expected {expected}",
|
|
6189
|
+
"gate.runtime.body_mismatch": '{route} did not contain "{body}"',
|
|
6190
|
+
"gate.runtime.request_failed": "the request to {route} failed: {detail}",
|
|
6191
|
+
"gate.runtime.orphan": "the app on port {port} could not be stopped",
|
|
6192
|
+
"gate.runtime.probe_failed": "the app check did not report a result: {line}",
|
|
6193
|
+
"command.off.summary": "Pause the gate and warnings for the current Claude Code session (the person only)",
|
|
6194
|
+
"command.on.summary": "Resume the gate after fm off",
|
|
6195
|
+
"pause.off": "Gate paused for this session by the person. Secrets, production and destructive git guards stay on. Type `fm on` to resume.",
|
|
6196
|
+
"pause.on": "Gate resumed.",
|
|
6197
|
+
"pause.report": "The gate did not check this stop: the person paused it with fm off at {since}.",
|
|
6198
|
+
"pause.no_session": "No Claude Code session is recorded for this project yet; start one, then run this again or type `fm off` there.",
|
|
6199
|
+
"pause.error.person_only": "Only the person can pause or resume the gate, and this does not look like their terminal (no TTY, or running inside Claude Code)"
|
|
5791
6200
|
};
|
|
5792
6201
|
|
|
5793
6202
|
// src/i18n/es.json
|
|
@@ -6164,6 +6573,7 @@ var es_default = {
|
|
|
6164
6573
|
"gate.guard.bypass.hooks_path": "Finite Monkey: bloqueado: {detail} desvía git de los hooks del proyecto. exige: core.hooksPath queda como está configurado.",
|
|
6165
6574
|
"gate.guard.bypass.hook_env": "Finite Monkey: bloqueado: {detail} apaga hooks o guardas. exige: hooks y guardas quedan encendidos.",
|
|
6166
6575
|
"gate.guard.bypass.fm_allow": "Finite Monkey: bloqueado: las liberaciones las hace la persona, no una llamada de herramienta.",
|
|
6576
|
+
"gate.guard.bypass.fm_pause": "Finite Monkey: bloqueado: solo la persona pausa o reanuda la compuerta, escribiendo `fm off` o `fm on` como el prompt completo.",
|
|
6167
6577
|
"gate.guard.bypass.human": "Bloqueé {detail}: apagaría la red de seguridad. Si de verdad lo quiere, escriba en una línea: finitemonkey: allow bypass <motivo>",
|
|
6168
6578
|
"gate.guard.self.policy": "Finite Monkey: bloqueado: {file} solo lo escribe el ejecutable finitemonkey (evidencia, política y estado). exige: cambiarlo con los comandos de finitemonkey.",
|
|
6169
6579
|
"gate.guard.self.allow_store": "Finite Monkey: bloqueado: {file} registra lo que la persona liberó; ninguna herramienta lo escribe.",
|
|
@@ -6319,7 +6729,35 @@ var es_default = {
|
|
|
6319
6729
|
"gate.callers.warning": "solo aviso: {percent}% de los hallazgos de callers se liberaron con callers_ignore ({released} de {total}), por encima del techo de 5%",
|
|
6320
6730
|
"command.policy_false_positive.summary": "Registra un falso positivo de un guard en shadow para que no se promueva",
|
|
6321
6731
|
"policy.error.person_only": "Solo la persona puede registrar un falso positivo, y esto no parece su terminal (sin TTY, o dentro de Claude Code)",
|
|
6322
|
-
"policy.false_positive.recorded": "Registrado para {guard}: {count, plural, one {# falso positivo} other {# falsos positivos}}; se queda en shadow hasta que fijes el modo en .finitemonkey/policy.yml."
|
|
6732
|
+
"policy.false_positive.recorded": "Registrado para {guard}: {count, plural, one {# falso positivo} other {# falsos positivos}}; se queda en shadow hasta que fijes el modo en .finitemonkey/policy.yml.",
|
|
6733
|
+
"command.app_check.summary": "Arranca la app o reutiliza la que ya corre, llama a una ruta y comprueba la respuesta",
|
|
6734
|
+
"app.check.ok": "{url} respondió {status}",
|
|
6735
|
+
"app.check.crashed": "la app salió con código {code} antes de abrir el puerto",
|
|
6736
|
+
"app.check.no_port": "el puerto de {url} no se abrió antes del tiempo límite",
|
|
6737
|
+
"app.check.no_start": "nada escucha en {url} y no se indicó comando de arranque",
|
|
6738
|
+
"app.check.wrong_status": "{url} respondió {status}",
|
|
6739
|
+
"app.check.body_mismatch": "{url} respondió {status} sin el texto esperado",
|
|
6740
|
+
"app.check.request_failed": "la petición a {url} falló",
|
|
6741
|
+
"app.check.usage": "indica --port como número de 1 a 65535; --status y --timeout deben ser números positivos",
|
|
6742
|
+
"gate.require.runtime": "la app arranca y `{command}` responde como se declaró",
|
|
6743
|
+
"gate.runtime.ok": "arrancó, {route} respondió {status}, detenida",
|
|
6744
|
+
"gate.runtime.reused": "reutilizó la app en marcha, {route} respondió {status}",
|
|
6745
|
+
"gate.runtime.crashed": "la app salió con código {code} antes de abrir su puerto",
|
|
6746
|
+
"gate.runtime.no_port": "el puerto {port} no se abrió antes del tiempo límite",
|
|
6747
|
+
"gate.runtime.no_start": "nada escucha en el puerto {port} y la comprobación no tiene `run` para arrancar la app",
|
|
6748
|
+
"gate.runtime.no_port_declared": "la comprobación runtime necesita `port`",
|
|
6749
|
+
"gate.runtime.wrong_status": "{route} respondió {status}, se esperaba {expected}",
|
|
6750
|
+
"gate.runtime.body_mismatch": '{route} no contenía "{body}"',
|
|
6751
|
+
"gate.runtime.request_failed": "la petición a {route} falló: {detail}",
|
|
6752
|
+
"gate.runtime.orphan": "no se pudo detener la app del puerto {port}",
|
|
6753
|
+
"gate.runtime.probe_failed": "la comprobación de la app no devolvió resultado: {line}",
|
|
6754
|
+
"command.off.summary": "Pausa la compuerta y los avisos en la sesión actual de Claude Code (solo la persona)",
|
|
6755
|
+
"command.on.summary": "Reanuda la compuerta después de fm off",
|
|
6756
|
+
"pause.off": "Compuerta pausada en esta sesión por la persona. Los bloqueos de secretos, producción y git destructivo siguen activos. Escribe `fm on` para reanudar.",
|
|
6757
|
+
"pause.on": "Compuerta reanudada.",
|
|
6758
|
+
"pause.report": "La compuerta no revisó esta parada: la persona la pausó con fm off a las {since}.",
|
|
6759
|
+
"pause.no_session": "Todavía no hay una sesión de Claude Code registrada en este proyecto; abre una y vuelve a ejecutarlo, o escribe `fm off` allí.",
|
|
6760
|
+
"pause.error.person_only": "Solo la persona puede pausar o reanudar la compuerta, y esto no parece su terminal (sin TTY, o dentro de Claude Code)"
|
|
6323
6761
|
};
|
|
6324
6762
|
|
|
6325
6763
|
// src/i18n/pt-BR.json
|
|
@@ -6696,6 +7134,7 @@ var pt_BR_default = {
|
|
|
6696
7134
|
"gate.guard.bypass.hooks_path": "Finite Monkey: barrado: {detail} desvia o git dos hooks do projeto. exige: core.hooksPath fica como está configurado.",
|
|
6697
7135
|
"gate.guard.bypass.hook_env": "Finite Monkey: barrado: {detail} desliga hooks ou travas. exige: hooks e travas ficam ligados.",
|
|
6698
7136
|
"gate.guard.bypass.fm_allow": "Finite Monkey: barrado: liberação é feita pela pessoa, não por chamada de ferramenta.",
|
|
7137
|
+
"gate.guard.bypass.fm_pause": "Finite Monkey: bloqueado: só a pessoa pausa ou retoma o portão, digitando `fm off` ou `fm on` como o prompt inteiro.",
|
|
6699
7138
|
"gate.guard.bypass.human": "Barrei {detail}: desligaria a rede de proteção. Se quiser mesmo, digite numa linha: finitemonkey: allow bypass <motivo>",
|
|
6700
7139
|
"gate.guard.self.policy": "Finite Monkey: barrado: {file} só é escrito pelo executável finitemonkey (evidência, política e estado). exige: mudar pelos comandos do finitemonkey.",
|
|
6701
7140
|
"gate.guard.self.allow_store": "Finite Monkey: barrado: {file} registra o que a pessoa liberou; ferramenta nunca escreve nele.",
|
|
@@ -6851,7 +7290,35 @@ var pt_BR_default = {
|
|
|
6851
7290
|
"gate.callers.warning": "só aviso: {percent}% dos achados de callers foram liberados com callers_ignore ({released} de {total}), acima do teto de 5%",
|
|
6852
7291
|
"command.policy_false_positive.summary": "Registra um falso positivo de um guard em shadow para ele não ser promovido",
|
|
6853
7292
|
"policy.error.person_only": "Só a pessoa pode registrar um falso positivo, e isto não parece o terminal dela (sem TTY, ou rodando dentro do Claude Code)",
|
|
6854
|
-
"policy.false_positive.recorded": "Registrado para {guard}: {count, plural, one {# falso positivo} other {# falsos positivos}}; ele fica em shadow até você definir o modo em .finitemonkey/policy.yml."
|
|
7293
|
+
"policy.false_positive.recorded": "Registrado para {guard}: {count, plural, one {# falso positivo} other {# falsos positivos}}; ele fica em shadow até você definir o modo em .finitemonkey/policy.yml.",
|
|
7294
|
+
"command.app_check.summary": "Sobe o app ou reaproveita o que está rodando, chama uma rota e confere a resposta",
|
|
7295
|
+
"app.check.ok": "{url} respondeu {status}",
|
|
7296
|
+
"app.check.crashed": "o app saiu com código {code} antes de abrir a porta",
|
|
7297
|
+
"app.check.no_port": "a porta de {url} não abriu antes do tempo limite",
|
|
7298
|
+
"app.check.no_start": "nada escuta em {url} e nenhum comando de início foi dado",
|
|
7299
|
+
"app.check.wrong_status": "{url} respondeu {status}",
|
|
7300
|
+
"app.check.body_mismatch": "{url} respondeu {status} sem o texto esperado",
|
|
7301
|
+
"app.check.request_failed": "a requisição para {url} falhou",
|
|
7302
|
+
"app.check.usage": "passe --port como número de 1 a 65535; --status e --timeout precisam ser números positivos",
|
|
7303
|
+
"gate.require.runtime": "o app sobe e `{command}` responde como declarado",
|
|
7304
|
+
"gate.runtime.ok": "subiu, {route} respondeu {status}, parado",
|
|
7305
|
+
"gate.runtime.reused": "reaproveitou o app rodando, {route} respondeu {status}",
|
|
7306
|
+
"gate.runtime.crashed": "o app saiu com código {code} antes de abrir a porta",
|
|
7307
|
+
"gate.runtime.no_port": "a porta {port} não abriu antes do tempo limite",
|
|
7308
|
+
"gate.runtime.no_start": "nada escuta na porta {port} e a checagem não tem `run` para subir o app",
|
|
7309
|
+
"gate.runtime.no_port_declared": "a checagem runtime precisa de `port`",
|
|
7310
|
+
"gate.runtime.wrong_status": "{route} respondeu {status}, esperado {expected}",
|
|
7311
|
+
"gate.runtime.body_mismatch": '{route} não continha "{body}"',
|
|
7312
|
+
"gate.runtime.request_failed": "a requisição para {route} falhou: {detail}",
|
|
7313
|
+
"gate.runtime.orphan": "o app na porta {port} não pôde ser parado",
|
|
7314
|
+
"gate.runtime.probe_failed": "a checagem do app não devolveu resultado: {line}",
|
|
7315
|
+
"command.off.summary": "Pausa o portão e os avisos na sessão atual do Claude Code (só a pessoa)",
|
|
7316
|
+
"command.on.summary": "Retoma o portão depois de fm off",
|
|
7317
|
+
"pause.off": "Portão pausado nesta sessão pela pessoa. As travas de segredos, produção e git destrutivo continuam ligadas. Digite `fm on` para retomar.",
|
|
7318
|
+
"pause.on": "Portão retomado.",
|
|
7319
|
+
"pause.report": "O portão não conferiu esta parada: a pessoa pausou com fm off em {since}.",
|
|
7320
|
+
"pause.no_session": "Ainda não há sessão do Claude Code registrada neste projeto; abra uma e rode de novo, ou digite `fm off` nela.",
|
|
7321
|
+
"pause.error.person_only": "Só a pessoa pode pausar ou retomar o portão, e isto não parece o terminal dela (sem TTY, ou rodando dentro do Claude Code)"
|
|
6855
7322
|
};
|
|
6856
7323
|
|
|
6857
7324
|
// src/i18n/review.json
|
|
@@ -7229,6 +7696,7 @@ var review_default = {
|
|
|
7229
7696
|
"gate.guard.bypass.hooks_path": "machine",
|
|
7230
7697
|
"gate.guard.bypass.hook_env": "machine",
|
|
7231
7698
|
"gate.guard.bypass.fm_allow": "machine",
|
|
7699
|
+
"gate.guard.bypass.fm_pause": "machine",
|
|
7232
7700
|
"gate.guard.bypass.human": "machine",
|
|
7233
7701
|
"gate.guard.self.policy": "machine",
|
|
7234
7702
|
"gate.guard.self.allow_store": "machine",
|
|
@@ -7384,7 +7852,35 @@ var review_default = {
|
|
|
7384
7852
|
"gate.callers.warning": "machine",
|
|
7385
7853
|
"command.policy_false_positive.summary": "machine",
|
|
7386
7854
|
"policy.error.person_only": "machine",
|
|
7387
|
-
"policy.false_positive.recorded": "machine"
|
|
7855
|
+
"policy.false_positive.recorded": "machine",
|
|
7856
|
+
"command.app_check.summary": "machine",
|
|
7857
|
+
"app.check.ok": "machine",
|
|
7858
|
+
"app.check.crashed": "machine",
|
|
7859
|
+
"app.check.no_port": "machine",
|
|
7860
|
+
"app.check.no_start": "machine",
|
|
7861
|
+
"app.check.wrong_status": "machine",
|
|
7862
|
+
"app.check.body_mismatch": "machine",
|
|
7863
|
+
"app.check.request_failed": "machine",
|
|
7864
|
+
"app.check.usage": "machine",
|
|
7865
|
+
"gate.require.runtime": "machine",
|
|
7866
|
+
"gate.runtime.ok": "machine",
|
|
7867
|
+
"gate.runtime.reused": "machine",
|
|
7868
|
+
"gate.runtime.crashed": "machine",
|
|
7869
|
+
"gate.runtime.no_port": "machine",
|
|
7870
|
+
"gate.runtime.no_start": "machine",
|
|
7871
|
+
"gate.runtime.no_port_declared": "machine",
|
|
7872
|
+
"gate.runtime.wrong_status": "machine",
|
|
7873
|
+
"gate.runtime.body_mismatch": "machine",
|
|
7874
|
+
"gate.runtime.request_failed": "machine",
|
|
7875
|
+
"gate.runtime.orphan": "machine",
|
|
7876
|
+
"gate.runtime.probe_failed": "machine",
|
|
7877
|
+
"command.off.summary": "machine",
|
|
7878
|
+
"command.on.summary": "machine",
|
|
7879
|
+
"pause.off": "machine",
|
|
7880
|
+
"pause.on": "machine",
|
|
7881
|
+
"pause.report": "machine",
|
|
7882
|
+
"pause.no_session": "machine",
|
|
7883
|
+
"pause.error.person_only": "machine"
|
|
7388
7884
|
},
|
|
7389
7885
|
es: {
|
|
7390
7886
|
"command.init.summary": "machine",
|
|
@@ -7759,6 +8255,7 @@ var review_default = {
|
|
|
7759
8255
|
"gate.guard.bypass.hooks_path": "machine",
|
|
7760
8256
|
"gate.guard.bypass.hook_env": "machine",
|
|
7761
8257
|
"gate.guard.bypass.fm_allow": "machine",
|
|
8258
|
+
"gate.guard.bypass.fm_pause": "machine",
|
|
7762
8259
|
"gate.guard.bypass.human": "machine",
|
|
7763
8260
|
"gate.guard.self.policy": "machine",
|
|
7764
8261
|
"gate.guard.self.allow_store": "machine",
|
|
@@ -7914,7 +8411,35 @@ var review_default = {
|
|
|
7914
8411
|
"gate.callers.warning": "machine",
|
|
7915
8412
|
"command.policy_false_positive.summary": "machine",
|
|
7916
8413
|
"policy.error.person_only": "machine",
|
|
7917
|
-
"policy.false_positive.recorded": "machine"
|
|
8414
|
+
"policy.false_positive.recorded": "machine",
|
|
8415
|
+
"command.app_check.summary": "machine",
|
|
8416
|
+
"app.check.ok": "machine",
|
|
8417
|
+
"app.check.crashed": "machine",
|
|
8418
|
+
"app.check.no_port": "machine",
|
|
8419
|
+
"app.check.no_start": "machine",
|
|
8420
|
+
"app.check.wrong_status": "machine",
|
|
8421
|
+
"app.check.body_mismatch": "machine",
|
|
8422
|
+
"app.check.request_failed": "machine",
|
|
8423
|
+
"app.check.usage": "machine",
|
|
8424
|
+
"gate.require.runtime": "machine",
|
|
8425
|
+
"gate.runtime.ok": "machine",
|
|
8426
|
+
"gate.runtime.reused": "machine",
|
|
8427
|
+
"gate.runtime.crashed": "machine",
|
|
8428
|
+
"gate.runtime.no_port": "machine",
|
|
8429
|
+
"gate.runtime.no_start": "machine",
|
|
8430
|
+
"gate.runtime.no_port_declared": "machine",
|
|
8431
|
+
"gate.runtime.wrong_status": "machine",
|
|
8432
|
+
"gate.runtime.body_mismatch": "machine",
|
|
8433
|
+
"gate.runtime.request_failed": "machine",
|
|
8434
|
+
"gate.runtime.orphan": "machine",
|
|
8435
|
+
"gate.runtime.probe_failed": "machine",
|
|
8436
|
+
"command.off.summary": "machine",
|
|
8437
|
+
"command.on.summary": "machine",
|
|
8438
|
+
"pause.off": "machine",
|
|
8439
|
+
"pause.on": "machine",
|
|
8440
|
+
"pause.report": "machine",
|
|
8441
|
+
"pause.no_session": "machine",
|
|
8442
|
+
"pause.error.person_only": "machine"
|
|
7918
8443
|
}
|
|
7919
8444
|
};
|
|
7920
8445
|
|
|
@@ -9294,9 +9819,9 @@ var isFlagged = (report2) => report2.spans.length > 0;
|
|
|
9294
9819
|
var MARKDOWN = /\.(?:md|markdown|mdx)$/i;
|
|
9295
9820
|
var RECORD_FILE = /(?:^|\/)(?:CHANGELOG|RELEASE[-_]?NOTES|HISTORY)[^/]*$/i;
|
|
9296
9821
|
var contextOf = (file) => RECORD_FILE.test(toPosixPath(file)) ? "record" : "docs";
|
|
9297
|
-
var listed = (runtime, root,
|
|
9298
|
-
const result = runtime.git(
|
|
9299
|
-
if (!result.ok) return reject(`git ${
|
|
9822
|
+
var listed = (runtime, root, args2) => {
|
|
9823
|
+
const result = runtime.git(args2, root);
|
|
9824
|
+
if (!result.ok) return reject(`git ${args2.join(" ")} failed`);
|
|
9300
9825
|
return accept(result.stdout.split("\0").map(toPosixPath));
|
|
9301
9826
|
};
|
|
9302
9827
|
var changedMarkdown = (runtime, root) => {
|
|
@@ -9376,6 +9901,121 @@ var reviewCheck = (check2, ctx) => {
|
|
|
9376
9901
|
return failed([...sizeNotes(ctx), note("gate.review.missing", { check: check2.id })]);
|
|
9377
9902
|
};
|
|
9378
9903
|
|
|
9904
|
+
// src/app/parse.ts
|
|
9905
|
+
var KINDS2 = [
|
|
9906
|
+
"ok",
|
|
9907
|
+
"crashed",
|
|
9908
|
+
"no_port",
|
|
9909
|
+
"wrong_status",
|
|
9910
|
+
"body_mismatch",
|
|
9911
|
+
"request_failed",
|
|
9912
|
+
"no_start"
|
|
9913
|
+
];
|
|
9914
|
+
var optionalNumber = (value) => typeof value === "number" ? value : void 0;
|
|
9915
|
+
var parseAppCheck = (stdout) => {
|
|
9916
|
+
const envelope = parseJsonObject(stdout.trim());
|
|
9917
|
+
if (!envelope.ok) return void 0;
|
|
9918
|
+
const data = envelope.value["data"];
|
|
9919
|
+
if (!isRecord(data)) return void 0;
|
|
9920
|
+
const kind = KINDS2.find((item) => item === data["kind"]);
|
|
9921
|
+
const { output, reused, stopped, durationMs, exitCode, bodyExcerpt } = data;
|
|
9922
|
+
if (kind === void 0 || typeof output !== "string" || typeof reused !== "boolean" || typeof stopped !== "boolean")
|
|
9923
|
+
return void 0;
|
|
9924
|
+
const status = optionalNumber(data["status"]);
|
|
9925
|
+
return {
|
|
9926
|
+
kind,
|
|
9927
|
+
output,
|
|
9928
|
+
reused,
|
|
9929
|
+
stopped,
|
|
9930
|
+
durationMs: optionalNumber(durationMs) ?? 0,
|
|
9931
|
+
...status === void 0 ? {} : { status },
|
|
9932
|
+
...typeof exitCode === "number" || exitCode === null ? { exitCode } : {},
|
|
9933
|
+
...typeof bodyExcerpt === "string" ? { bodyExcerpt } : {}
|
|
9934
|
+
};
|
|
9935
|
+
};
|
|
9936
|
+
|
|
9937
|
+
// src/gate/checks/runtime.ts
|
|
9938
|
+
var PROBE_MARGIN_MS = 15e3;
|
|
9939
|
+
var MIN_REMAINING_MS2 = 5e3;
|
|
9940
|
+
var TAIL2 = 160;
|
|
9941
|
+
var lastLine = (text6) => {
|
|
9942
|
+
const rows = text6.split(/\r?\n/).filter((row) => row.trim() !== "" && !/^\s*at\s|^Node\.js v\d/.test(row));
|
|
9943
|
+
const line2 = (rows.findLast((row) => /error/i.test(row)) ?? rows.at(-1))?.trim() ?? "";
|
|
9944
|
+
return line2.length > TAIL2 ? `${line2.slice(0, TAIL2)}…` : line2;
|
|
9945
|
+
};
|
|
9946
|
+
var args = (check2, timeoutS) => [
|
|
9947
|
+
"app",
|
|
9948
|
+
"check",
|
|
9949
|
+
"--json",
|
|
9950
|
+
"--port",
|
|
9951
|
+
String(check2.port ?? 0),
|
|
9952
|
+
"--route",
|
|
9953
|
+
check2.route ?? DEFAULT_ROUTE,
|
|
9954
|
+
"--status",
|
|
9955
|
+
String(check2.status ?? DEFAULT_STATUS),
|
|
9956
|
+
"--timeout",
|
|
9957
|
+
String(timeoutS),
|
|
9958
|
+
...check2.run === void 0 ? [] : ["--start", check2.run],
|
|
9959
|
+
...check2.body === void 0 ? [] : ["--body", check2.body]
|
|
9960
|
+
];
|
|
9961
|
+
var resultNotes = (check2, result, ctx) => {
|
|
9962
|
+
const route = check2.route ?? DEFAULT_ROUTE;
|
|
9963
|
+
const line2 = ctx.mask(lastLine(result.output));
|
|
9964
|
+
const output = line2 === "" ? [] : [note("gate.note.output", { line: line2 })];
|
|
9965
|
+
switch (result.kind) {
|
|
9966
|
+
case "ok":
|
|
9967
|
+
return [note(result.reused ? "gate.runtime.reused" : "gate.runtime.ok", { route, status: result.status ?? 0 })];
|
|
9968
|
+
case "crashed":
|
|
9969
|
+
return [note("gate.runtime.crashed", { code: result.exitCode ?? -1 }), ...output];
|
|
9970
|
+
case "no_port":
|
|
9971
|
+
return [note("gate.runtime.no_port", { port: check2.port ?? 0 }), ...output];
|
|
9972
|
+
case "no_start":
|
|
9973
|
+
return [note("gate.runtime.no_start", { port: check2.port ?? 0 })];
|
|
9974
|
+
case "wrong_status":
|
|
9975
|
+
return [
|
|
9976
|
+
note("gate.runtime.wrong_status", {
|
|
9977
|
+
route,
|
|
9978
|
+
status: result.status ?? 0,
|
|
9979
|
+
expected: check2.status ?? DEFAULT_STATUS
|
|
9980
|
+
})
|
|
9981
|
+
];
|
|
9982
|
+
case "body_mismatch":
|
|
9983
|
+
return [note("gate.runtime.body_mismatch", { route, body: ctx.mask(check2.body ?? "") })];
|
|
9984
|
+
case "request_failed":
|
|
9985
|
+
return [note("gate.runtime.request_failed", { route, detail: ctx.mask(result.bodyExcerpt ?? "") })];
|
|
9986
|
+
}
|
|
9987
|
+
};
|
|
9988
|
+
var outcome = (check2, result, ctx) => {
|
|
9989
|
+
const notes2 = [
|
|
9990
|
+
...resultNotes(check2, result, ctx),
|
|
9991
|
+
...result.stopped ? [] : [note("gate.runtime.orphan", { port: check2.port ?? 0 })]
|
|
9992
|
+
];
|
|
9993
|
+
const base = result.kind === "ok" && result.stopped ? passed(notes2) : failed(notes2);
|
|
9994
|
+
return {
|
|
9995
|
+
...base,
|
|
9996
|
+
...check2.run === void 0 ? {} : { command: check2.run },
|
|
9997
|
+
exitCode: result.exitCode ?? (result.kind === "ok" ? 0 : null),
|
|
9998
|
+
stdoutSha256: sha256Hex(result.output),
|
|
9999
|
+
durationMs: result.durationMs
|
|
10000
|
+
};
|
|
10001
|
+
};
|
|
10002
|
+
var runtimeCheck = (check2, ctx) => {
|
|
10003
|
+
if (check2.port === void 0) return failed([note("gate.runtime.no_port_declared")]);
|
|
10004
|
+
if (check2.run !== void 0 && !ctx.trusted)
|
|
10005
|
+
return { ...unverified("untrusted", [note("gate.note.untrusted", { task: ctx.contract.id })]), command: check2.run };
|
|
10006
|
+
const remaining = ctx.deadline - nowMs(ctx.runtime) - PROBE_MARGIN_MS;
|
|
10007
|
+
if (remaining < MIN_REMAINING_MS2) return unverified("budget", [note("gate.note.budget")]);
|
|
10008
|
+
const timeoutS = Math.max(1, Math.min(check2.timeoutS ?? DEFAULT_APP_TIMEOUT_S, Math.floor(remaining / 1e3)));
|
|
10009
|
+
const run4 = ctx.runtime.execSelf(args(check2, timeoutS), ctx.paths.root, timeoutS * 1e3 + PROBE_MARGIN_MS);
|
|
10010
|
+
if (run4.timedOut) return unverified("timeout", [note("gate.note.timeout", { seconds: timeoutS })]);
|
|
10011
|
+
const result = parseAppCheck(run4.stdout);
|
|
10012
|
+
if (result === void 0) {
|
|
10013
|
+
return failed([note("gate.runtime.probe_failed", { line: ctx.mask(lastLine(`${run4.stdout}
|
|
10014
|
+
${run4.stderr}`)) })]);
|
|
10015
|
+
}
|
|
10016
|
+
return outcome(check2, result, ctx);
|
|
10017
|
+
};
|
|
10018
|
+
|
|
9379
10019
|
// src/secrets/baseline.ts
|
|
9380
10020
|
import { join as join18 } from "node:path";
|
|
9381
10021
|
var BASELINE_FILE2 = ".finitemonkey/findings/baseline.json";
|
|
@@ -9670,15 +10310,15 @@ var diffFindings = (diff) => {
|
|
|
9670
10310
|
return scanner.end().filter((finding3) => !SKIPPED.test(finding3.file));
|
|
9671
10311
|
};
|
|
9672
10312
|
var scanStaged = (runtime, root, includeUnstaged = false) => {
|
|
9673
|
-
const
|
|
9674
|
-
const git = runtime.git(
|
|
10313
|
+
const args2 = includeUnstaged ? ["diff", "HEAD", ...DIFF_FLAGS] : ["diff", "--cached", ...DIFF_FLAGS];
|
|
10314
|
+
const git = runtime.git(args2, root);
|
|
9675
10315
|
if (!git.ok) return reject(git.found ? "git diff failed" : "git not found");
|
|
9676
10316
|
return accept(diffFindings(git.stdout));
|
|
9677
10317
|
};
|
|
9678
10318
|
var scanHistory = async (runtime, root) => {
|
|
9679
10319
|
const scanner = diffScanner();
|
|
9680
|
-
const
|
|
9681
|
-
const git = await runtime.gitLines(
|
|
10320
|
+
const args2 = ["log", "-p", "--all", "--format=commit %H", ...DIFF_FLAGS];
|
|
10321
|
+
const git = await runtime.gitLines(args2, root, scanner.push);
|
|
9682
10322
|
if (!git.ok) return reject(git.found ? "git log failed" : "git not found");
|
|
9683
10323
|
return accept(scanner.end().filter((finding3) => !SKIPPED.test(finding3.file)));
|
|
9684
10324
|
};
|
|
@@ -9694,11 +10334,11 @@ var secretsGateStatus = (runtime, root, since) => {
|
|
|
9694
10334
|
if (!changed.ok) return changed;
|
|
9695
10335
|
const baseline = loadBaseline(runtime, root);
|
|
9696
10336
|
if (!baseline.ok) return baseline;
|
|
9697
|
-
const
|
|
10337
|
+
const outcome2 = ratchet([...changed.value, ...untracked2(runtime, root)], baseline.value, runtime.now(), void 0);
|
|
9698
10338
|
const openIncidents = listIncidents(runtime, root).filter(
|
|
9699
10339
|
(incident) => incident.createdAt >= since && incident.state !== "rotacionado" && incident.state !== "fechado"
|
|
9700
10340
|
);
|
|
9701
|
-
return accept({ findings: [...
|
|
10341
|
+
return accept({ findings: [...outcome2.fresh, ...outcome2.expired], openIncidents });
|
|
9702
10342
|
};
|
|
9703
10343
|
|
|
9704
10344
|
// src/gate/checks/secrets.ts
|
|
@@ -9770,8 +10410,8 @@ var testsCheck = (check2, ctx) => {
|
|
|
9770
10410
|
const released2 = grant === void 0 ? {} : { releasedBy: `person@${grant.grantedAt}` };
|
|
9771
10411
|
const releaseNotes = grant === void 0 ? [] : [...notes2, note("gate.note.released", { guard: "tests", reason: grant.reason })];
|
|
9772
10412
|
if (check2.run === void 0) return { ...passed([note("gate.tests.clean"), ...releaseNotes]), ...released2 };
|
|
9773
|
-
const
|
|
9774
|
-
return { ...
|
|
10413
|
+
const outcome2 = runShellCheck(check2, check2.run, ctx);
|
|
10414
|
+
return { ...outcome2, notes: [...outcome2.notes, ...releaseNotes], ...released2 };
|
|
9775
10415
|
};
|
|
9776
10416
|
|
|
9777
10417
|
// src/git/tree.ts
|
|
@@ -9797,13 +10437,13 @@ var IDENTITY_ENV = {
|
|
|
9797
10437
|
GIT_COMMITTER_EMAIL: "finitemonkey@localhost"
|
|
9798
10438
|
};
|
|
9799
10439
|
var failure = (step3, result) => result.timedOut ? `${step3}: timed out` : `${step3}: ${result.stderr.trim() || "git failed"}`;
|
|
9800
|
-
var run = (runtime, repo,
|
|
9801
|
-
const result = runtime.gitWith(
|
|
10440
|
+
var run = (runtime, repo, args2, env, options, input) => {
|
|
10441
|
+
const result = runtime.gitWith(args2, repo.root, {
|
|
9802
10442
|
env,
|
|
9803
10443
|
timeoutMs: options.timeoutMs,
|
|
9804
10444
|
...input === void 0 ? {} : { input }
|
|
9805
10445
|
});
|
|
9806
|
-
return result.ok ? accept(result.stdout.trim()) : reject(failure(
|
|
10446
|
+
return result.ok ? accept(result.stdout.trim()) : reject(failure(args2[0] ?? "git", result));
|
|
9807
10447
|
};
|
|
9808
10448
|
var dropSensitive = (runtime, repo, env, options) => {
|
|
9809
10449
|
const listed4 = run(runtime, repo, ["ls-files", "-z"], env, options);
|
|
@@ -9866,7 +10506,7 @@ var flushHunk = (draft) => {
|
|
|
9866
10506
|
if (draft.current !== void 0) draft.hunks.push(draft.current);
|
|
9867
10507
|
draft.current = void 0;
|
|
9868
10508
|
};
|
|
9869
|
-
var
|
|
10509
|
+
var finish2 = (draft, out) => {
|
|
9870
10510
|
if (draft === void 0) return;
|
|
9871
10511
|
flushHunk(draft);
|
|
9872
10512
|
out.push({
|
|
@@ -9926,7 +10566,7 @@ var parseUnifiedDiff = (text6) => {
|
|
|
9926
10566
|
const line2 = withoutCarriageReturn(raw);
|
|
9927
10567
|
const start = DIFF_GIT.exec(line2);
|
|
9928
10568
|
if (start !== null) {
|
|
9929
|
-
|
|
10569
|
+
finish2(draft, out);
|
|
9930
10570
|
draft = {
|
|
9931
10571
|
oldPath: start[1],
|
|
9932
10572
|
newPath: start[2],
|
|
@@ -9937,7 +10577,7 @@ var parseUnifiedDiff = (text6) => {
|
|
|
9937
10577
|
};
|
|
9938
10578
|
} else if (draft !== void 0) bodyLine(draft, line2);
|
|
9939
10579
|
}
|
|
9940
|
-
|
|
10580
|
+
finish2(draft, out);
|
|
9941
10581
|
return out;
|
|
9942
10582
|
};
|
|
9943
10583
|
var DIFF_ARGS = [
|
|
@@ -10654,8 +11294,8 @@ var openRepo = (runtime, dir) => {
|
|
|
10654
11294
|
};
|
|
10655
11295
|
var globRegex2 = (pattern) => new RegExp(`^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`);
|
|
10656
11296
|
var matchesBranch = (branch, patterns) => patterns.some((pattern) => globRegex2(pattern).test(branch));
|
|
10657
|
-
var line = (runtime, root,
|
|
10658
|
-
const result = runtime.git(
|
|
11297
|
+
var line = (runtime, root, args2) => {
|
|
11298
|
+
const result = runtime.git(args2, root);
|
|
10659
11299
|
const value = result.stdout.trim();
|
|
10660
11300
|
return result.ok && value !== "" ? value : void 0;
|
|
10661
11301
|
};
|
|
@@ -10781,20 +11421,21 @@ var DEFAULT_CHECKS = {
|
|
|
10781
11421
|
worktree: worktreeCheck,
|
|
10782
11422
|
merge: mergeCheck,
|
|
10783
11423
|
review: reviewCheck,
|
|
10784
|
-
callers: callersCheck
|
|
11424
|
+
callers: callersCheck,
|
|
11425
|
+
runtime: runtimeCheck
|
|
10785
11426
|
};
|
|
10786
11427
|
|
|
10787
11428
|
// src/gate/run.ts
|
|
10788
11429
|
var FAST_PATH_MS = 10 * 6e4;
|
|
10789
|
-
var toEvidence = (ctx, check2,
|
|
11430
|
+
var toEvidence = (ctx, check2, outcome2) => ({
|
|
10790
11431
|
schema: EVIDENCE_SCHEMA,
|
|
10791
11432
|
task: ctx.contract.id,
|
|
10792
11433
|
check: check2.id,
|
|
10793
11434
|
kind: check2.kind,
|
|
10794
11435
|
treeHash: ctx.treeHash,
|
|
10795
11436
|
at: ctx.runtime.now(),
|
|
10796
|
-
...
|
|
10797
|
-
...check2.run === void 0 ||
|
|
11437
|
+
...outcome2,
|
|
11438
|
+
...check2.run === void 0 || outcome2.command !== void 0 ? {} : { command: check2.run }
|
|
10798
11439
|
});
|
|
10799
11440
|
var reusable = (ledger, ctx, check2) => {
|
|
10800
11441
|
if (!REUSABLE_KINDS.includes(check2.kind)) return false;
|
|
@@ -10990,7 +11631,8 @@ var KNOWN_KINDS = /* @__PURE__ */ new Set([
|
|
|
10990
11631
|
"worktree",
|
|
10991
11632
|
"merge",
|
|
10992
11633
|
"review",
|
|
10993
|
-
"callers"
|
|
11634
|
+
"callers",
|
|
11635
|
+
"runtime"
|
|
10994
11636
|
]);
|
|
10995
11637
|
var requirementText = (t, check2) => {
|
|
10996
11638
|
const key = `gate.require.${check2.kind}`;
|
|
@@ -11023,9 +11665,9 @@ var subagentStart = (input) => {
|
|
|
11023
11665
|
// src/gate/hooks/index.ts
|
|
11024
11666
|
var PORTAO_HANDLERS = {
|
|
11025
11667
|
PreToolUse: [selfGuard, bypassGuard, testsGuard],
|
|
11026
|
-
UserPromptSubmit: [promptRelease],
|
|
11027
|
-
Stop: [stopGate],
|
|
11028
|
-
SubagentStop: [subagentStopGate],
|
|
11668
|
+
UserPromptSubmit: [pausePrompt, promptRelease],
|
|
11669
|
+
Stop: [unlessPaused(stopGate)],
|
|
11670
|
+
SubagentStop: [unlessPaused(subagentStopGate)],
|
|
11029
11671
|
SubagentStart: [subagentStart],
|
|
11030
11672
|
PreCompact: [preCompact],
|
|
11031
11673
|
SessionStart: [sessionStart],
|
|
@@ -11183,10 +11825,10 @@ var HELM_READ = /* @__PURE__ */ new Set([
|
|
|
11183
11825
|
"env"
|
|
11184
11826
|
]);
|
|
11185
11827
|
var CURL_WRITE = /^(?:-X|--request|-d|--data.*|-F|--form|-T|--upload-file|-o|--output|-O|--remote-name)$/;
|
|
11186
|
-
var firstPositional = (
|
|
11828
|
+
var firstPositional = (args2, valueFlags = /* @__PURE__ */ new Set()) => {
|
|
11187
11829
|
const out = [];
|
|
11188
|
-
for (let index = 0; index <
|
|
11189
|
-
const arg =
|
|
11830
|
+
for (let index = 0; index < args2.length; index += 1) {
|
|
11831
|
+
const arg = args2[index] ?? "";
|
|
11190
11832
|
if (arg.startsWith("-")) {
|
|
11191
11833
|
if (valueFlags.has(arg)) index += 1;
|
|
11192
11834
|
} else out.push(arg);
|
|
@@ -11221,16 +11863,16 @@ var KUBE_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
|
11221
11863
|
"--container",
|
|
11222
11864
|
"--kube-context"
|
|
11223
11865
|
]);
|
|
11224
|
-
var dockerReadOnly = (
|
|
11225
|
-
const words = firstPositional(
|
|
11866
|
+
var dockerReadOnly = (args2) => {
|
|
11867
|
+
const words = firstPositional(args2, DOCKER_VALUE_FLAGS);
|
|
11226
11868
|
const [first, second] = words;
|
|
11227
11869
|
if (first === void 0) return true;
|
|
11228
11870
|
if (DOCKER_GROUPS.has(first))
|
|
11229
11871
|
return second === void 0 || DOCKER_READ.has(second) || first === "compose" && second === "top";
|
|
11230
11872
|
return DOCKER_READ.has(first);
|
|
11231
11873
|
};
|
|
11232
|
-
var kubectlReadOnly = (program,
|
|
11233
|
-
const [verb, object] = firstPositional(
|
|
11874
|
+
var kubectlReadOnly = (program, args2) => {
|
|
11875
|
+
const [verb, object] = firstPositional(args2, KUBE_VALUE_FLAGS);
|
|
11234
11876
|
if (verb === void 0) return true;
|
|
11235
11877
|
if (program === "helm") return HELM_READ.has(verb);
|
|
11236
11878
|
if (verb === "config") return object === "view" || object === "get-contexts" || object === "current-context";
|
|
@@ -11240,24 +11882,24 @@ var kubectlReadOnly = (program, args) => {
|
|
|
11240
11882
|
var writesFile = (command) => command.redirects.some(
|
|
11241
11883
|
(redirect) => (redirect.op === ">" || redirect.op === ">>" || redirect.op === ">|") && !/^(?:\/dev\/null|&?\d)$/.test(redirect.target) && !redirect.op.startsWith("<")
|
|
11242
11884
|
);
|
|
11243
|
-
var gitReadOnly = (
|
|
11244
|
-
const [verb, ...rest] = firstPositional(
|
|
11885
|
+
var gitReadOnly = (args2) => {
|
|
11886
|
+
const [verb, ...rest] = firstPositional(args2, /* @__PURE__ */ new Set(["-C", "-c"]));
|
|
11245
11887
|
if (verb === void 0) return true;
|
|
11246
11888
|
if (GIT_READ.has(verb)) return true;
|
|
11247
11889
|
return GIT_LIST.has(verb) && (rest.length === 0 || verb === "stash" && rest[0] === "list");
|
|
11248
11890
|
};
|
|
11249
11891
|
var programReadOnly = (command) => {
|
|
11250
|
-
const { program, args } = command;
|
|
11251
|
-
if (program === "git") return gitReadOnly(
|
|
11892
|
+
const { program, args: args2 } = command;
|
|
11893
|
+
if (program === "git") return gitReadOnly(args2);
|
|
11252
11894
|
if (program === "docker" || program === "docker-compose")
|
|
11253
|
-
return dockerReadOnly(program === "docker-compose" ? ["compose", ...
|
|
11254
|
-
if (program === "systemctl") return SYSTEMCTL_READ.has(firstPositional(
|
|
11255
|
-
if (program === "kubectl" || program === "helm") return kubectlReadOnly(program,
|
|
11256
|
-
if (program === "curl") return !
|
|
11895
|
+
return dockerReadOnly(program === "docker-compose" ? ["compose", ...args2] : args2);
|
|
11896
|
+
if (program === "systemctl") return SYSTEMCTL_READ.has(firstPositional(args2)[0] ?? "status");
|
|
11897
|
+
if (program === "kubectl" || program === "helm") return kubectlReadOnly(program, args2);
|
|
11898
|
+
if (program === "curl") return !args2.some((arg) => CURL_WRITE.test(arg));
|
|
11257
11899
|
if (program === "find")
|
|
11258
|
-
return !
|
|
11259
|
-
if (program === "sed") return !
|
|
11260
|
-
if (program === "awk") return !
|
|
11900
|
+
return !args2.some((arg) => arg === "-delete" || arg.startsWith("-exec") || arg.startsWith("-ok"));
|
|
11901
|
+
if (program === "sed") return !args2.some((arg) => arg.startsWith("-i") || arg === "--in-place");
|
|
11902
|
+
if (program === "awk") return !args2.some((arg) => arg.includes("system(") || arg.includes(">"));
|
|
11261
11903
|
return READ_PROGRAMS.has(program);
|
|
11262
11904
|
};
|
|
11263
11905
|
var readOnlyCommand = (command) => !writesFile(command) && programReadOnly(command);
|
|
@@ -11317,11 +11959,11 @@ var RSYNC_LONG_VALUE = /* @__PURE__ */ new Set([
|
|
|
11317
11959
|
"--files-from"
|
|
11318
11960
|
]);
|
|
11319
11961
|
var parseSsh = (command) => {
|
|
11320
|
-
const { args } = command;
|
|
11962
|
+
const { args: args2 } = command;
|
|
11321
11963
|
let index = 0;
|
|
11322
11964
|
let noCommand = false;
|
|
11323
|
-
while (index <
|
|
11324
|
-
const arg =
|
|
11965
|
+
while (index < args2.length && (args2[index] ?? "").startsWith("-")) {
|
|
11966
|
+
const arg = args2[index] ?? "";
|
|
11325
11967
|
if (arg === "--") {
|
|
11326
11968
|
index += 1;
|
|
11327
11969
|
break;
|
|
@@ -11330,17 +11972,17 @@ var parseSsh = (command) => {
|
|
|
11330
11972
|
const last = arg.charAt(arg.length - 1);
|
|
11331
11973
|
index += arg.length === 2 && SSH_VALUE.includes(last) ? 2 : 1;
|
|
11332
11974
|
}
|
|
11333
|
-
const destination =
|
|
11975
|
+
const destination = args2[index];
|
|
11334
11976
|
if (destination === void 0) return void 0;
|
|
11335
|
-
return { destination: destination.replace(/^ssh:\/\//, ""), remote:
|
|
11977
|
+
return { destination: destination.replace(/^ssh:\/\//, ""), remote: args2.slice(index + 1), noCommand };
|
|
11336
11978
|
};
|
|
11337
11979
|
var REMOTE_PATH = /^(?:(?:scp|rsync|sftp):\/\/)?(?:[^@/:\s]+@)?(\[[^\]]+\]|[A-Za-z0-9][A-Za-z0-9.-]*)(?::|::|\/)/;
|
|
11338
11980
|
var remoteHostOf = (operand) => {
|
|
11339
11981
|
if (/^[A-Za-z]:[\\/]/.test(operand) || operand.startsWith("/") || operand.startsWith(".")) return void 0;
|
|
11340
|
-
const
|
|
11982
|
+
const url2 = /^(?:scp|rsync|sftp):\/\//.test(operand);
|
|
11341
11983
|
const match = REMOTE_PATH.exec(operand);
|
|
11342
11984
|
if (match === null) return void 0;
|
|
11343
|
-
if (!
|
|
11985
|
+
if (!url2 && !operand.slice(match[0].length - 1).startsWith(":")) return void 0;
|
|
11344
11986
|
return (match[1] ?? "").replace(/^\[|\]$/g, "");
|
|
11345
11987
|
};
|
|
11346
11988
|
var copyOperands = (command, shortValue) => {
|
|
@@ -11445,12 +12087,12 @@ var copyHit = (command, isProd) => {
|
|
|
11445
12087
|
const source = call.sources.map(remoteHostOf).find((host) => host !== void 0 && isProd(host));
|
|
11446
12088
|
return source === void 0 ? void 0 : hit2("read", hostKey(source), command.program);
|
|
11447
12089
|
};
|
|
11448
|
-
var valueAfter = (
|
|
11449
|
-
for (let index = 0; index <
|
|
11450
|
-
const arg =
|
|
12090
|
+
var valueAfter = (args2, ...names) => {
|
|
12091
|
+
for (let index = 0; index < args2.length; index += 1) {
|
|
12092
|
+
const arg = args2[index] ?? "";
|
|
11451
12093
|
const equals = names.find((name) => arg.startsWith(`${name}=`));
|
|
11452
12094
|
if (equals !== void 0) return arg.slice(equals.length + 1);
|
|
11453
|
-
if (names.includes(arg)) return
|
|
12095
|
+
if (names.includes(arg)) return args2[index + 1];
|
|
11454
12096
|
}
|
|
11455
12097
|
return void 0;
|
|
11456
12098
|
};
|
|
@@ -11492,8 +12134,8 @@ var DUMPS = /* @__PURE__ */ new Set(["pg_dump", "mysqldump"]);
|
|
|
11492
12134
|
var databaseHost = (command) => {
|
|
11493
12135
|
const flag2 = valueAfter(command.args, "-h", "--host");
|
|
11494
12136
|
if (flag2 !== void 0) return flag2;
|
|
11495
|
-
const
|
|
11496
|
-
return
|
|
12137
|
+
const url2 = [...command.args, command.env["DATABASE_URL"] ?? ""].map((arg) => URL_HOST.exec(arg)?.[1]).find((host) => host !== void 0);
|
|
12138
|
+
return url2 ?? command.env["PGHOST"];
|
|
11497
12139
|
};
|
|
11498
12140
|
var databaseReadOnly = (command) => {
|
|
11499
12141
|
if (DUMPS.has(command.program)) return true;
|
|
@@ -11667,14 +12309,14 @@ var globalOption = (globals, name, value) => {
|
|
|
11667
12309
|
var gitInvocation = (command) => {
|
|
11668
12310
|
if (command.program !== "git") return void 0;
|
|
11669
12311
|
const globals = { dirs: [], config: {} };
|
|
11670
|
-
const { args } = command;
|
|
12312
|
+
const { args: args2 } = command;
|
|
11671
12313
|
let index = 0;
|
|
11672
|
-
while (index <
|
|
11673
|
-
const arg =
|
|
12314
|
+
while (index < args2.length && (args2[index] ?? "").startsWith("-")) {
|
|
12315
|
+
const arg = args2[index] ?? "";
|
|
11674
12316
|
const equals = arg.indexOf("=");
|
|
11675
12317
|
const name = equals > 2 && arg.startsWith("--") ? arg.slice(0, equals) : arg;
|
|
11676
12318
|
if (WITH_VALUE.has(name) && equals < 0) {
|
|
11677
|
-
globalOption(globals, name,
|
|
12319
|
+
globalOption(globals, name, args2[index + 1] ?? "");
|
|
11678
12320
|
index += 2;
|
|
11679
12321
|
} else {
|
|
11680
12322
|
if (equals > 0) globalOption(globals, name, arg.slice(equals + 1));
|
|
@@ -11684,8 +12326,8 @@ var gitInvocation = (command) => {
|
|
|
11684
12326
|
return {
|
|
11685
12327
|
dirs: globals.dirs,
|
|
11686
12328
|
config: globals.config,
|
|
11687
|
-
subcommand:
|
|
11688
|
-
args:
|
|
12329
|
+
subcommand: args2[index] ?? "",
|
|
12330
|
+
args: args2.slice(index + 1),
|
|
11689
12331
|
command
|
|
11690
12332
|
};
|
|
11691
12333
|
};
|
|
@@ -11819,14 +12461,14 @@ var shortCluster = (building, arg, next2, spec2) => {
|
|
|
11819
12461
|
}
|
|
11820
12462
|
return 1;
|
|
11821
12463
|
};
|
|
11822
|
-
var parseOptions = (
|
|
12464
|
+
var parseOptions = (args2, spec2) => {
|
|
11823
12465
|
const building = { flags: /* @__PURE__ */ new Set(), values: /* @__PURE__ */ new Map(), positionals: [] };
|
|
11824
12466
|
let index = 0;
|
|
11825
|
-
while (index <
|
|
11826
|
-
const arg =
|
|
11827
|
-
const next2 =
|
|
12467
|
+
while (index < args2.length) {
|
|
12468
|
+
const arg = args2[index] ?? "";
|
|
12469
|
+
const next2 = args2[index + 1];
|
|
11828
12470
|
if (arg === "--") {
|
|
11829
|
-
return { ...building, paths:
|
|
12471
|
+
return { ...building, paths: args2.slice(index + 1), dashdash: true };
|
|
11830
12472
|
}
|
|
11831
12473
|
if (arg.startsWith("--")) index += longOption(building, arg, next2, spec2);
|
|
11832
12474
|
else if (arg.startsWith("-") && arg.length > 1 && !/^-\d+$/.test(arg)) {
|
|
@@ -12264,9 +12906,9 @@ var gitVerdict = (invocation, facts) => {
|
|
|
12264
12906
|
|
|
12265
12907
|
// src/git/switch-target.ts
|
|
12266
12908
|
var CREATES = /* @__PURE__ */ new Set(["-c", "-C", "-b", "-B", "--create", "--force-create", "--orphan"]);
|
|
12267
|
-
var operands = (
|
|
12268
|
-
if (
|
|
12269
|
-
return
|
|
12909
|
+
var operands = (args2) => {
|
|
12910
|
+
if (args2.includes("--")) return void 0;
|
|
12911
|
+
return args2.filter((arg) => !arg.startsWith("-"));
|
|
12270
12912
|
};
|
|
12271
12913
|
var switchTarget = (invocation, facts) => {
|
|
12272
12914
|
if (invocation.subcommand !== "switch" && invocation.subcommand !== "checkout") return void 0;
|
|
@@ -12460,8 +13102,8 @@ var BACKUP_PREFIX = "refs/finitemonkey/backup/";
|
|
|
12460
13102
|
var DEFAULT_SNAPSHOT_TIMEOUT_MS = 2500;
|
|
12461
13103
|
var stampOf = (iso) => iso.replace(/[:.]/g, "-");
|
|
12462
13104
|
var slug = (op) => op.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "manual";
|
|
12463
|
-
var optionalLine = (runtime, repo,
|
|
12464
|
-
const result = runtime.git(
|
|
13105
|
+
var optionalLine = (runtime, repo, args2) => {
|
|
13106
|
+
const result = runtime.git(args2, repo.root);
|
|
12465
13107
|
const value = result.stdout.trim();
|
|
12466
13108
|
return result.ok && value !== "" ? value : void 0;
|
|
12467
13109
|
};
|
|
@@ -12566,17 +13208,17 @@ var fileList = (items) => {
|
|
|
12566
13208
|
return items.length > MAX_FILES2 ? `${head} (+${String(items.length - MAX_FILES2)})` : head;
|
|
12567
13209
|
};
|
|
12568
13210
|
var foreignLabel = (t, file) => t(file.reason === "before-session" ? "git.foreign.before" : "git.foreign.other", { path: file.path });
|
|
12569
|
-
var outcomeMessage = (t,
|
|
12570
|
-
switch (
|
|
13211
|
+
var outcomeMessage = (t, outcome2) => {
|
|
13212
|
+
switch (outcome2.kind) {
|
|
12571
13213
|
case "block":
|
|
12572
|
-
return ruleMessage(t,
|
|
13214
|
+
return ruleMessage(t, outcome2.rule, outcome2.command, outcome2.subject);
|
|
12573
13215
|
case "foreign":
|
|
12574
13216
|
return t("git.block.foreign", {
|
|
12575
|
-
command:
|
|
12576
|
-
files: fileList(
|
|
13217
|
+
command: outcome2.command,
|
|
13218
|
+
files: fileList(outcome2.files.map((file) => foreignLabel(t, file)))
|
|
12577
13219
|
});
|
|
12578
13220
|
case "unknown":
|
|
12579
|
-
return t("git.block.unknown", { command:
|
|
13221
|
+
return t("git.block.unknown", { command: outcome2.command });
|
|
12580
13222
|
case "pass":
|
|
12581
13223
|
case "snapshot":
|
|
12582
13224
|
return void 0;
|
|
@@ -12620,10 +13262,10 @@ var review = (input, commands, owner) => {
|
|
|
12620
13262
|
const decision = PROD_PROGRAMS.has(command.program) ? prod().decide(command) : void 0;
|
|
12621
13263
|
if (decision?.kind === "block") return { blocked: decision.reason, snapshots, reads };
|
|
12622
13264
|
if (decision !== void 0) reads.push(decision);
|
|
12623
|
-
for (const
|
|
12624
|
-
const message = outcomeMessage(input.t,
|
|
13265
|
+
for (const outcome2 of guardGitCommand({ runtime: input.runtime, cwd: input.cwd, owner, chain }, command)) {
|
|
13266
|
+
const message = outcomeMessage(input.t, outcome2);
|
|
12625
13267
|
if (message !== void 0) return { blocked: message, snapshots, reads };
|
|
12626
|
-
if (
|
|
13268
|
+
if (outcome2.kind === "snapshot") snapshots.push(outcome2);
|
|
12627
13269
|
}
|
|
12628
13270
|
}
|
|
12629
13271
|
return { blocked: void 0, snapshots, reads };
|
|
@@ -12746,6 +13388,7 @@ var recordShadow = (input, paths, set, policy, reason) => {
|
|
|
12746
13388
|
var governed = (set, handler) => async (input) => {
|
|
12747
13389
|
const paths = projectPaths(input);
|
|
12748
13390
|
if (paths === void 0) return handler(input);
|
|
13391
|
+
if (pausedFor(input.runtime, paths, input.payload.sessionId) !== void 0) return { kind: "allow" };
|
|
12749
13392
|
const policy = loadPolicy(input.runtime, paths.root);
|
|
12750
13393
|
const mode = modeOf2(set, policy, readShadow(input.runtime, paths));
|
|
12751
13394
|
if (mode === "off") return { kind: "allow" };
|
|
@@ -12869,7 +13512,7 @@ var addsMarker = (input, tool, inputs, file) => {
|
|
|
12869
13512
|
return false;
|
|
12870
13513
|
}
|
|
12871
13514
|
};
|
|
12872
|
-
var isReadOnly = (program,
|
|
13515
|
+
var isReadOnly = (program, args2) => READ_ONLY.has(program) || program === "git" && GIT_READ_ONLY.has(args2[0] ?? "");
|
|
12873
13516
|
var shellAddsMarker = (command) => markerCount(command) > 0 && shellWords(command).segments.some((segment) => !isReadOnly(segment.program, segment.args));
|
|
12874
13517
|
var shown2 = (cwd, file) => {
|
|
12875
13518
|
const rel = toPosixPath(relative6(cwd, file));
|
|
@@ -12907,17 +13550,17 @@ var GIT_FLAGS = { title: [], body: ["-m", "--message"], file: ["-F", "--file"] }
|
|
|
12907
13550
|
var GH_FLAGS = { title: ["-t", "--title"], body: ["-b", "--body"], file: ["-F", "--body-file"] };
|
|
12908
13551
|
var GIT_GLOBAL_WITH_VALUE = /* @__PURE__ */ new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace"]);
|
|
12909
13552
|
var CLUSTER_WITH_MESSAGE = /^-[a-zA-Z]*m$/;
|
|
12910
|
-
var flagValues = (
|
|
13553
|
+
var flagValues = (args2, spec2) => {
|
|
12911
13554
|
const known2 = [...spec2.title, ...spec2.body, ...spec2.file];
|
|
12912
13555
|
const out = [];
|
|
12913
|
-
for (let index = 0; index <
|
|
12914
|
-
const arg =
|
|
13556
|
+
for (let index = 0; index < args2.length; index += 1) {
|
|
13557
|
+
const arg = args2[index] ?? "";
|
|
12915
13558
|
const equals = arg.indexOf("=");
|
|
12916
13559
|
const name = arg.startsWith("--") && equals > 0 ? arg.slice(0, equals) : arg;
|
|
12917
13560
|
if (name !== arg && known2.includes(name)) {
|
|
12918
13561
|
out.push({ flag: name, value: arg.slice(equals + 1) });
|
|
12919
13562
|
} else if (known2.includes(arg) || spec2 === GIT_FLAGS && CLUSTER_WITH_MESSAGE.test(arg)) {
|
|
12920
|
-
out.push({ flag: known2.includes(arg) ? arg : "-m", value:
|
|
13563
|
+
out.push({ flag: known2.includes(arg) ? arg : "-m", value: args2[index + 1] ?? "" });
|
|
12921
13564
|
index += 1;
|
|
12922
13565
|
}
|
|
12923
13566
|
}
|
|
@@ -12931,17 +13574,17 @@ var sourceOf = (value, isFile, segment, heredocs) => {
|
|
|
12931
13574
|
const piped = segment.args.map((arg) => heredocIn(arg, heredocs)).find((text6) => text6 !== void 0);
|
|
12932
13575
|
return { kind: "inline", text: piped ?? "" };
|
|
12933
13576
|
};
|
|
12934
|
-
var collect3 = (target, segment,
|
|
12935
|
-
const values = flagValues(
|
|
13577
|
+
var collect3 = (target, segment, args2, spec2, heredocs) => {
|
|
13578
|
+
const values = flagValues(args2, spec2);
|
|
12936
13579
|
if (values.length === 0) return void 0;
|
|
12937
13580
|
const title = values.find((item) => spec2.title.includes(item.flag));
|
|
12938
13581
|
const bodies = values.filter((item) => !spec2.title.includes(item.flag)).map((item) => sourceOf(item.value, spec2.file.includes(item.flag), segment, heredocs));
|
|
12939
13582
|
return { target, title: title === void 0 ? void 0 : sourceOf(title.value, false, segment, heredocs), bodies };
|
|
12940
13583
|
};
|
|
12941
|
-
var gitSubcommand = (
|
|
13584
|
+
var gitSubcommand = (args2) => {
|
|
12942
13585
|
let index = 0;
|
|
12943
|
-
while (index <
|
|
12944
|
-
index += GIT_GLOBAL_WITH_VALUE.has(
|
|
13586
|
+
while (index < args2.length && (args2[index] ?? "").startsWith("-")) {
|
|
13587
|
+
index += GIT_GLOBAL_WITH_VALUE.has(args2[index] ?? "") ? 2 : 1;
|
|
12945
13588
|
}
|
|
12946
13589
|
return index;
|
|
12947
13590
|
};
|
|
@@ -13157,7 +13800,7 @@ var READERS = /* @__PURE__ */ new Set([
|
|
|
13157
13800
|
var SECRET_NAME = /(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PASS|PWD|CREDENTIAL)/i;
|
|
13158
13801
|
var PERSON_ONLY = /\b(?:finitemonkey|fm)(?:\.mjs)?\s+secrets\s+(?:accept\b|incident\s+(?:rotated|close)\b)/;
|
|
13159
13802
|
var LISTS_ENV = /* @__PURE__ */ new Set(["get-childitem", "gci", "dir", "ls"]);
|
|
13160
|
-
var onlyFlags = (
|
|
13803
|
+
var onlyFlags = (args2) => args2.every((arg) => arg.startsWith("-"));
|
|
13161
13804
|
var readTarget = (segment) => {
|
|
13162
13805
|
const redirected = segment.redirectedFrom.find(isSensitivePath);
|
|
13163
13806
|
if (redirected !== void 0) return redirected;
|
|
@@ -13291,17 +13934,17 @@ var secretsPreToolUse = (input) => {
|
|
|
13291
13934
|
// src/secrets/remotes.ts
|
|
13292
13935
|
var USER_AND_SECRET = /^[a-z][a-z0-9+.-]*:\/\/[^\s/@:]+:[^\s/@]+@/i;
|
|
13293
13936
|
var USERINFO = /^[a-z][a-z0-9+.-]*:\/\/(?<user>[^\s/@]+)@/i;
|
|
13294
|
-
var hasCredential = (
|
|
13295
|
-
if (USER_AND_SECRET.test(
|
|
13296
|
-
const user = USERINFO.exec(
|
|
13937
|
+
var hasCredential = (url2) => {
|
|
13938
|
+
if (USER_AND_SECRET.test(url2)) return true;
|
|
13939
|
+
const user = USERINFO.exec(url2)?.groups?.["user"];
|
|
13297
13940
|
return user !== void 0 && scanText(user, { rules: CREDENTIAL_RULES }).length > 0;
|
|
13298
13941
|
};
|
|
13299
13942
|
var parseRemotes = (output) => {
|
|
13300
13943
|
const remotes = /* @__PURE__ */ new Map();
|
|
13301
13944
|
for (const line2 of output.split(/\r?\n/)) {
|
|
13302
|
-
const [name,
|
|
13303
|
-
if (name === void 0 ||
|
|
13304
|
-
remotes.set(name, [...remotes.get(name) ?? [],
|
|
13945
|
+
const [name, url2] = line2.trim().split(/\s+/);
|
|
13946
|
+
if (name === void 0 || url2 === void 0 || name === "") continue;
|
|
13947
|
+
remotes.set(name, [...remotes.get(name) ?? [], url2]);
|
|
13305
13948
|
}
|
|
13306
13949
|
return remotes;
|
|
13307
13950
|
};
|
|
@@ -13550,9 +14193,9 @@ var invocationOf = (entry2, vars) => {
|
|
|
13550
14193
|
const seconds = typeof timeout === "number" && timeout > 0 ? timeout : DEFAULT_TIMEOUT_S;
|
|
13551
14194
|
const timeoutMs = Math.min(seconds * 1e3, PROBE_TIMEOUT_MS2);
|
|
13552
14195
|
const command = expand(raw, vars);
|
|
13553
|
-
const
|
|
13554
|
-
const shell =
|
|
13555
|
-
return { command, args, shell, timeoutMs, display: [command, ...
|
|
14196
|
+
const args2 = strings3(entry2.handler["args"]).map((arg) => expand(arg, vars));
|
|
14197
|
+
const shell = args2.length === 0;
|
|
14198
|
+
return { command, args: args2, shell, timeoutMs, display: [command, ...args2].join(" ") };
|
|
13556
14199
|
};
|
|
13557
14200
|
var versionInvocation = (invocation) => {
|
|
13558
14201
|
if (invocation.shell) {
|
|
@@ -13561,8 +14204,8 @@ var versionInvocation = (invocation) => {
|
|
|
13561
14204
|
}
|
|
13562
14205
|
const at = invocation.args.indexOf("hook");
|
|
13563
14206
|
if (at < 0) return void 0;
|
|
13564
|
-
const
|
|
13565
|
-
return { ...invocation, args, display: [invocation.command, ...
|
|
14207
|
+
const args2 = [...invocation.args.slice(0, at), "version", "--json"];
|
|
14208
|
+
return { ...invocation, args: args2, display: [invocation.command, ...args2].join(" ") };
|
|
13566
14209
|
};
|
|
13567
14210
|
var syntheticPayload = (event, cwd) => {
|
|
13568
14211
|
const base = { session_id: "finitemonkey-doctor", transcript_path: "", cwd, hook_event_name: event };
|
|
@@ -13763,10 +14406,10 @@ var handlerProblems = (at, handler, claude) => {
|
|
|
13763
14406
|
const type = handler["type"];
|
|
13764
14407
|
if (typeof type !== "string" || !HANDLER_TYPES.some((known2) => known2 === type)) return [`${at}.type: unknown`];
|
|
13765
14408
|
const problems = [];
|
|
13766
|
-
const { command, args, timeout, onFailure } = handler;
|
|
14409
|
+
const { command, args: args2, timeout, onFailure } = handler;
|
|
13767
14410
|
if (type === "command" && (typeof command !== "string" || command.trim() === ""))
|
|
13768
14411
|
problems.push(`${at}.command: empty`);
|
|
13769
|
-
if (
|
|
14412
|
+
if (args2 !== void 0 && !(Array.isArray(args2) && args2.every((arg) => typeof arg === "string"))) {
|
|
13770
14413
|
problems.push(`${at}.args: not a list of strings`);
|
|
13771
14414
|
}
|
|
13772
14415
|
if (timeout !== void 0 && !(typeof timeout === "number" && timeout > 0))
|
|
@@ -14185,9 +14828,9 @@ var CHECKS = [
|
|
|
14185
14828
|
];
|
|
14186
14829
|
var probeOnce = (probe) => {
|
|
14187
14830
|
const seen = /* @__PURE__ */ new Map();
|
|
14188
|
-
return (command,
|
|
14189
|
-
const key = [command, ...
|
|
14190
|
-
const known2 = seen.get(key) ?? probe(command,
|
|
14831
|
+
return (command, args2, timeoutMs) => {
|
|
14832
|
+
const key = [command, ...args2].join(" ");
|
|
14833
|
+
const known2 = seen.get(key) ?? probe(command, args2, timeoutMs);
|
|
14191
14834
|
seen.set(key, known2);
|
|
14192
14835
|
return known2;
|
|
14193
14836
|
};
|
|
@@ -14298,93 +14941,7 @@ var doctorCommand = {
|
|
|
14298
14941
|
usage: "finitemonkey doctor [--fix] [--report] [--dry-run] [--json]",
|
|
14299
14942
|
status: "ready",
|
|
14300
14943
|
options: { fix: { type: "boolean" }, report: { type: "boolean" } },
|
|
14301
|
-
run: (ctx,
|
|
14302
|
-
};
|
|
14303
|
-
|
|
14304
|
-
// src/core/args.ts
|
|
14305
|
-
import { parseArgs } from "node:util";
|
|
14306
|
-
|
|
14307
|
-
// src/core/problem.ts
|
|
14308
|
-
var usageProblem = (code, messageKey, fix, params2 = {}) => ({
|
|
14309
|
-
code,
|
|
14310
|
-
messageKey,
|
|
14311
|
-
params: params2,
|
|
14312
|
-
fix,
|
|
14313
|
-
exitCode: ExitCode.Usage
|
|
14314
|
-
});
|
|
14315
|
-
var needsPersonProblem = (messageKey, fix, params2 = {}) => ({
|
|
14316
|
-
code: "needs_confirmation",
|
|
14317
|
-
messageKey,
|
|
14318
|
-
params: params2,
|
|
14319
|
-
fix,
|
|
14320
|
-
exitCode: ExitCode.NeedsPerson
|
|
14321
|
-
});
|
|
14322
|
-
var FmError = class extends Error {
|
|
14323
|
-
problem;
|
|
14324
|
-
constructor(problem4) {
|
|
14325
|
-
super(problem4.code);
|
|
14326
|
-
this.name = "FmError";
|
|
14327
|
-
this.problem = problem4;
|
|
14328
|
-
}
|
|
14329
|
-
};
|
|
14330
|
-
|
|
14331
|
-
// src/core/args.ts
|
|
14332
|
-
var GLOBAL_OPTIONS = {
|
|
14333
|
-
json: { type: "boolean" },
|
|
14334
|
-
lang: { type: "string" },
|
|
14335
|
-
yes: { type: "boolean", short: "y" },
|
|
14336
|
-
"dry-run": { type: "boolean" },
|
|
14337
|
-
version: { type: "boolean", short: "v" },
|
|
14338
|
-
help: { type: "boolean", short: "h" }
|
|
14339
|
-
};
|
|
14340
|
-
var flag = (values, name) => values[name] === true;
|
|
14341
|
-
var looseArgs = (argv) => {
|
|
14342
|
-
const { values, positionals } = parseArgs({
|
|
14343
|
-
args: [...argv],
|
|
14344
|
-
options: GLOBAL_OPTIONS,
|
|
14345
|
-
strict: false,
|
|
14346
|
-
allowPositionals: true
|
|
14347
|
-
});
|
|
14348
|
-
const lang = values.lang;
|
|
14349
|
-
return {
|
|
14350
|
-
positionals,
|
|
14351
|
-
json: flag(values, "json"),
|
|
14352
|
-
yes: flag(values, "yes"),
|
|
14353
|
-
dryRun: flag(values, "dry-run"),
|
|
14354
|
-
version: flag(values, "version"),
|
|
14355
|
-
help: flag(values, "help"),
|
|
14356
|
-
lang: typeof lang === "string" ? lang : void 0
|
|
14357
|
-
};
|
|
14358
|
-
};
|
|
14359
|
-
var resolveCommand = (registry, positionals) => registry.filter((spec2) => spec2.path.every((part2, index) => positionals[index] === part2)).reduce(
|
|
14360
|
-
(best, spec2) => best === void 0 || spec2.path.length > best.consumed ? { spec: spec2, consumed: spec2.path.length } : best,
|
|
14361
|
-
void 0
|
|
14362
|
-
);
|
|
14363
|
-
var strictArgs = (argv, spec2) => {
|
|
14364
|
-
const fix = `finitemonkey help ${spec2.path.join(" ")}`;
|
|
14365
|
-
let parsed;
|
|
14366
|
-
try {
|
|
14367
|
-
parsed = parseArgs({
|
|
14368
|
-
args: [...argv],
|
|
14369
|
-
options: { ...GLOBAL_OPTIONS, ...spec2.options },
|
|
14370
|
-
strict: true,
|
|
14371
|
-
allowPositionals: true
|
|
14372
|
-
});
|
|
14373
|
-
} catch (error) {
|
|
14374
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
14375
|
-
return reject(usageProblem("invalid_arguments", "error.invalid_arguments", fix, { detail }));
|
|
14376
|
-
}
|
|
14377
|
-
const rest = parsed.positionals.slice(spec2.path.length);
|
|
14378
|
-
const max = spec2.maxPositionals ?? 0;
|
|
14379
|
-
const extra = rest[max];
|
|
14380
|
-
if (extra !== void 0) {
|
|
14381
|
-
return reject(usageProblem("unexpected_argument", "error.unexpected_argument", fix, { argument: extra }));
|
|
14382
|
-
}
|
|
14383
|
-
return accept({ values: parsed.values, positionals: rest });
|
|
14384
|
-
};
|
|
14385
|
-
var stringOption = (values, name) => {
|
|
14386
|
-
const value = values[name];
|
|
14387
|
-
return typeof value === "string" ? value : void 0;
|
|
14944
|
+
run: (ctx, args2) => Promise.resolve(runDoctor(ctx, args2.values["fix"] === true, args2.values["report"] === true))
|
|
14388
14945
|
};
|
|
14389
14946
|
|
|
14390
14947
|
// src/gate/baseline-run.ts
|
|
@@ -14399,8 +14956,8 @@ var runBaseline = (options) => {
|
|
|
14399
14956
|
if (commands.length === 0) return { kind: "skipped", reason: "no_commands" };
|
|
14400
14957
|
const checks = {};
|
|
14401
14958
|
for (const check2 of commands) {
|
|
14402
|
-
const
|
|
14403
|
-
checks[check2.id] = { exitCode:
|
|
14959
|
+
const outcome2 = runShellCheck(check2, check2.run ?? "", ctx);
|
|
14960
|
+
checks[check2.id] = { exitCode: outcome2.exitCode ?? null, failures: outcome2.failures ?? [] };
|
|
14404
14961
|
}
|
|
14405
14962
|
if (treeHash(gitAt(ctx.runtime, ctx.paths.root)) !== ctx.treeHash) return { kind: "skipped", reason: "tree_moved" };
|
|
14406
14963
|
writeBaseline(ctx.runtime, ctx.paths, ctx.treeHash, checks);
|
|
@@ -14459,19 +15016,19 @@ var gateCommand = {
|
|
|
14459
15016
|
baseline: { type: "boolean" },
|
|
14460
15017
|
prs: { type: "boolean" }
|
|
14461
15018
|
},
|
|
14462
|
-
run: (ctx,
|
|
14463
|
-
const taskId = stringOption(
|
|
15019
|
+
run: (ctx, args2) => {
|
|
15020
|
+
const taskId = stringOption(args2.values, "task");
|
|
14464
15021
|
const options = {
|
|
14465
15022
|
runtime: ctx.runtime,
|
|
14466
15023
|
cwd: ctx.cwd,
|
|
14467
15024
|
env: ctx.env,
|
|
14468
15025
|
sessionId: void 0,
|
|
14469
|
-
budgetMs: budgetMs(stringOption(
|
|
14470
|
-
fast:
|
|
15026
|
+
budgetMs: budgetMs(stringOption(args2.values, "budget")),
|
|
15027
|
+
fast: args2.values["fast"] === true,
|
|
14471
15028
|
...taskId === void 0 ? {} : { taskId }
|
|
14472
15029
|
};
|
|
14473
|
-
if (
|
|
14474
|
-
if (
|
|
15030
|
+
if (args2.values["prs"] === true) return Promise.resolve(prsResult(ctx));
|
|
15031
|
+
if (args2.values["baseline"] === true) {
|
|
14475
15032
|
const baseline = runBaseline(options);
|
|
14476
15033
|
return Promise.resolve(
|
|
14477
15034
|
success(baseline, [
|
|
@@ -14481,7 +15038,7 @@ var gateCommand = {
|
|
|
14481
15038
|
])
|
|
14482
15039
|
);
|
|
14483
15040
|
}
|
|
14484
|
-
return Promise.resolve(runResult(ctx, runGate(options),
|
|
15041
|
+
return Promise.resolve(runResult(ctx, runGate(options), args2.values["strict"] === true));
|
|
14485
15042
|
}
|
|
14486
15043
|
};
|
|
14487
15044
|
|
|
@@ -14562,11 +15119,11 @@ var mergeVerifyCommand = {
|
|
|
14562
15119
|
status: "ready",
|
|
14563
15120
|
options: { since: { type: "string" }, dropped: { type: "string" } },
|
|
14564
15121
|
maxPositionals: 1,
|
|
14565
|
-
run: (ctx,
|
|
15122
|
+
run: (ctx, args2) => {
|
|
14566
15123
|
const repo = repoOf2(ctx);
|
|
14567
15124
|
if (repo === void 0) return Promise.resolve(failureFrom(ctx.t, notRepository(ctx.cwd)));
|
|
14568
|
-
const dropped = stringOption(
|
|
14569
|
-
const targets2 = targetsOf2(ctx, repo,
|
|
15125
|
+
const dropped = stringOption(args2.values, "dropped");
|
|
15126
|
+
const targets2 = targetsOf2(ctx, repo, args2.positionals[0], stringOption(args2.values, "since"));
|
|
14570
15127
|
if (targets2.length === 0) {
|
|
14571
15128
|
const data = { schema: MERGE_VERIFY_RUN_SCHEMA, merges: [] };
|
|
14572
15129
|
return Promise.resolve(success(data, [ctx.t("git.merge.none", { detail: "HEAD" })]));
|
|
@@ -14674,11 +15231,11 @@ var rescueCommand = {
|
|
|
14674
15231
|
usage: "finitemonkey rescue [--restore <sha> --branch <name>] [--json]",
|
|
14675
15232
|
status: "ready",
|
|
14676
15233
|
options: { restore: { type: "string" }, branch: { type: "string" } },
|
|
14677
|
-
run: (ctx,
|
|
15234
|
+
run: (ctx, args2) => {
|
|
14678
15235
|
const repo = repoOf2(ctx);
|
|
14679
15236
|
if (repo === void 0) return Promise.resolve(failureFrom(ctx.t, notRepository(ctx.cwd)));
|
|
14680
|
-
const sha = stringOption(
|
|
14681
|
-
const branch = stringOption(
|
|
15237
|
+
const sha = stringOption(args2.values, "restore");
|
|
15238
|
+
const branch = stringOption(args2.values, "branch");
|
|
14682
15239
|
if (sha === void 0 && branch === void 0) {
|
|
14683
15240
|
const report2 = rescueReport(ctx.runtime, repo);
|
|
14684
15241
|
return Promise.resolve(success({ schema: RESCUE_SCHEMA, action: "list", ...report2 }, listing(ctx.t, report2)));
|
|
@@ -14709,8 +15266,8 @@ var rescueCommand = {
|
|
|
14709
15266
|
// src/git/undo.ts
|
|
14710
15267
|
import { basename as basename3, dirname as dirname8, join as join36 } from "node:path";
|
|
14711
15268
|
var INDEX_SUBJECT = "finitemonkey index:";
|
|
14712
|
-
var gitLine = (runtime, repo,
|
|
14713
|
-
const result = runtime.git(
|
|
15269
|
+
var gitLine = (runtime, repo, args2) => {
|
|
15270
|
+
const result = runtime.git(args2, repo.root);
|
|
14714
15271
|
const value = result.stdout.trim();
|
|
14715
15272
|
return result.ok && value !== "" ? value : void 0;
|
|
14716
15273
|
};
|
|
@@ -14758,9 +15315,9 @@ var intoWorktree = (runtime, repo, view2) => {
|
|
|
14758
15315
|
const added = runtime.gitWith(["worktree", "add", "--detach", path, view2.commit], repo.root, {});
|
|
14759
15316
|
return added.ok ? accept(path) : reject(failure2("worktree add", added));
|
|
14760
15317
|
};
|
|
14761
|
-
var step2 = (runtime, repo,
|
|
14762
|
-
const result = runtime.gitWith(
|
|
14763
|
-
return result.ok ? accept(void 0) : reject(failure2(
|
|
15318
|
+
var step2 = (runtime, repo, args2) => {
|
|
15319
|
+
const result = runtime.gitWith(args2, repo.root, {});
|
|
15320
|
+
return result.ok ? accept(void 0) : reject(failure2(args2.join(" "), result));
|
|
14764
15321
|
};
|
|
14765
15322
|
var inPlace = (runtime, repo, view2) => {
|
|
14766
15323
|
const current2 = gitLine(runtime, repo, ["rev-parse", "--verify", "--quiet", "HEAD"]);
|
|
@@ -14793,10 +15350,10 @@ var snapshotCommand = {
|
|
|
14793
15350
|
usage: "finitemonkey snapshot [--message <text>] [--json]",
|
|
14794
15351
|
status: "ready",
|
|
14795
15352
|
options: { message: { type: "string", short: "m" } },
|
|
14796
|
-
run: (ctx,
|
|
15353
|
+
run: (ctx, args2) => {
|
|
14797
15354
|
const repo = repoOf2(ctx);
|
|
14798
15355
|
if (repo === void 0) return Promise.resolve(failureFrom(ctx.t, notRepository(ctx.cwd)));
|
|
14799
|
-
const message =
|
|
15356
|
+
const message = args2.values["message"];
|
|
14800
15357
|
const op = typeof message === "string" && message.trim() !== "" ? message.trim() : "manual";
|
|
14801
15358
|
const taken = takeSnapshot(ctx.runtime, repo, { op });
|
|
14802
15359
|
if (!taken.ok) {
|
|
@@ -14826,12 +15383,12 @@ var undoCommand = {
|
|
|
14826
15383
|
status: "ready",
|
|
14827
15384
|
options: { list: { type: "boolean" }, "in-place": { type: "boolean" } },
|
|
14828
15385
|
maxPositionals: 1,
|
|
14829
|
-
run: (ctx,
|
|
15386
|
+
run: (ctx, args2) => {
|
|
14830
15387
|
const repo = repoOf2(ctx);
|
|
14831
15388
|
if (repo === void 0) return Promise.resolve(failureFrom(ctx.t, notRepository(ctx.cwd)));
|
|
14832
15389
|
const views = snapshotViews(ctx.runtime, repo);
|
|
14833
|
-
if (
|
|
14834
|
-
const wanted =
|
|
15390
|
+
if (args2.values["list"] === true) return Promise.resolve(listResult(ctx, views));
|
|
15391
|
+
const wanted = args2.positionals[0];
|
|
14835
15392
|
const view2 = findSnapshot(views, wanted);
|
|
14836
15393
|
if (view2 === void 0) {
|
|
14837
15394
|
return Promise.resolve(
|
|
@@ -14844,7 +15401,7 @@ var undoCommand = {
|
|
|
14844
15401
|
})
|
|
14845
15402
|
);
|
|
14846
15403
|
}
|
|
14847
|
-
const inPlace2 =
|
|
15404
|
+
const inPlace2 = args2.values["in-place"] === true;
|
|
14848
15405
|
if (inPlace2 && !(ctx.yes && isPerson(ctx))) {
|
|
14849
15406
|
return Promise.resolve(
|
|
14850
15407
|
failureFrom(ctx.t, needsPersonProblem("git.undo.confirm", `finitemonkey undo ${view2.ref} --in-place --yes`))
|
|
@@ -14933,8 +15490,8 @@ var helpCommand = {
|
|
|
14933
15490
|
usage: "finitemonkey help [command]",
|
|
14934
15491
|
status: "ready",
|
|
14935
15492
|
maxPositionals: 3,
|
|
14936
|
-
run: (ctx,
|
|
14937
|
-
|
|
15493
|
+
run: (ctx, args2, registry) => Promise.resolve(
|
|
15494
|
+
args2.positionals.length === 0 ? overview(ctx, registry) : topicHelp(ctx, registry, args2.positionals)
|
|
14938
15495
|
)
|
|
14939
15496
|
};
|
|
14940
15497
|
|
|
@@ -14946,8 +15503,8 @@ var hookCommand = {
|
|
|
14946
15503
|
status: "ready",
|
|
14947
15504
|
maxPositionals: 1,
|
|
14948
15505
|
options: { via: { type: "string" } },
|
|
14949
|
-
run: async (ctx,
|
|
14950
|
-
const raw =
|
|
15506
|
+
run: async (ctx, args2) => {
|
|
15507
|
+
const raw = args2.positionals[0] ?? "";
|
|
14951
15508
|
const event = parseHookEvent(raw);
|
|
14952
15509
|
if (event === void 0) {
|
|
14953
15510
|
const params2 = { event: raw, events: HOOK_EVENTS.join(", ") };
|
|
@@ -14956,10 +15513,10 @@ var hookCommand = {
|
|
|
14956
15513
|
usageProblem("unknown_hook_event", "error.unknown_hook_event", "finitemonkey help hook", params2)
|
|
14957
15514
|
);
|
|
14958
15515
|
}
|
|
14959
|
-
if (stringOption(
|
|
15516
|
+
if (stringOption(args2.values, "via") === PLUGIN_VIA && projectOwnsHooks(ctx)) {
|
|
14960
15517
|
return { ok: true, exitCode: 0, data: { event, verdict: "allow" }, raw: { stdout: YIELD_STDOUT, stderr: "" } };
|
|
14961
15518
|
}
|
|
14962
|
-
const
|
|
15519
|
+
const outcome2 = await runHook(event, {
|
|
14963
15520
|
stdin: ctx.io.stdin,
|
|
14964
15521
|
deadlineMs: deadlineFor(event, ctx.env["FINITEMONKEY_HOOK_DEADLINE_MS"]),
|
|
14965
15522
|
handlers: DEFAULT_HANDLERS,
|
|
@@ -14969,11 +15526,11 @@ var hookCommand = {
|
|
|
14969
15526
|
runtime: ctx.runtime,
|
|
14970
15527
|
env: ctx.env
|
|
14971
15528
|
});
|
|
14972
|
-
logHookFailure(ctx, event,
|
|
14973
|
-
const data = { event, verdict:
|
|
14974
|
-
const output = { stdout:
|
|
14975
|
-
if (
|
|
14976
|
-
const message =
|
|
15529
|
+
logHookFailure(ctx, event, outcome2);
|
|
15530
|
+
const data = { event, verdict: outcome2.verdict };
|
|
15531
|
+
const output = { stdout: outcome2.stdout, stderr: outcome2.stderr };
|
|
15532
|
+
if (outcome2.exitCode === 0) return { ok: true, exitCode: 0, data, raw: output };
|
|
15533
|
+
const message = outcome2.stderr.trim();
|
|
14977
15534
|
return {
|
|
14978
15535
|
ok: false,
|
|
14979
15536
|
exitCode: 2,
|
|
@@ -15244,8 +15801,8 @@ var i18nCheckCommand = {
|
|
|
15244
15801
|
usage: "finitemonkey i18n check [--dir <path>]",
|
|
15245
15802
|
status: "ready",
|
|
15246
15803
|
options: { dir: { type: "string" } },
|
|
15247
|
-
run: (ctx,
|
|
15248
|
-
const dir = stringOption(
|
|
15804
|
+
run: (ctx, args2) => {
|
|
15805
|
+
const dir = stringOption(args2.values, "dir");
|
|
15249
15806
|
return Promise.resolve(runI18nCheck(ctx, dir === void 0 ? void 0 : toAbsolutePath(dir, ctx.cwd)));
|
|
15250
15807
|
}
|
|
15251
15808
|
};
|
|
@@ -15589,11 +16146,11 @@ var runInstall = (ctx, request, presetFallback) => {
|
|
|
15589
16146
|
if (ctx.dryRun || !ctx.yes || !needsWrite(plan.value)) return presentPlan(ctx, request, plan.value);
|
|
15590
16147
|
return applyAndReport(ctx, request, plan.value);
|
|
15591
16148
|
};
|
|
15592
|
-
var initRequest = (
|
|
16149
|
+
var initRequest = (args2) => ({
|
|
15593
16150
|
mode: "init",
|
|
15594
|
-
preset: stringOption(
|
|
15595
|
-
bin: stringOption(
|
|
15596
|
-
marketplace:
|
|
16151
|
+
preset: stringOption(args2.values, "preset"),
|
|
16152
|
+
bin: stringOption(args2.values, "bin"),
|
|
16153
|
+
marketplace: args2.values["marketplace"] === true,
|
|
15597
16154
|
showDiff: false
|
|
15598
16155
|
});
|
|
15599
16156
|
var withLookBack = (ctx, result) => {
|
|
@@ -15618,12 +16175,41 @@ var initCommand = {
|
|
|
15618
16175
|
marketplace: { type: "boolean" },
|
|
15619
16176
|
"look-back": { type: "boolean" }
|
|
15620
16177
|
},
|
|
15621
|
-
run: (ctx,
|
|
15622
|
-
const result = runInstall(ctx, initRequest(
|
|
15623
|
-
return Promise.resolve(
|
|
16178
|
+
run: (ctx, args2) => {
|
|
16179
|
+
const result = runInstall(ctx, initRequest(args2), "neutral");
|
|
16180
|
+
return Promise.resolve(args2.values["look-back"] === true ? withLookBack(ctx, result) : result);
|
|
15624
16181
|
}
|
|
15625
16182
|
};
|
|
15626
16183
|
|
|
16184
|
+
// src/commands/pause.ts
|
|
16185
|
+
var toggle = (ctx, off) => {
|
|
16186
|
+
const command = off ? "finitemonkey off" : "finitemonkey on";
|
|
16187
|
+
if (!isPerson(ctx)) return failureFrom(ctx.t, needsPersonProblem("pause.error.person_only", command));
|
|
16188
|
+
const paths = fmPaths(findRepoRoot(ctx.runtime, ctx.cwd) ?? ctx.cwd);
|
|
16189
|
+
if (!off) {
|
|
16190
|
+
const ended = clearPause(ctx.runtime, paths, "terminal");
|
|
16191
|
+
return success({ paused: false, sessionId: ended?.sessionId ?? null }, [ctx.t("pause.on")]);
|
|
16192
|
+
}
|
|
16193
|
+
const session = readSession(ctx.runtime, paths);
|
|
16194
|
+
if (session === void 0) return success({ paused: false, sessionId: null }, [ctx.t("pause.no_session")]);
|
|
16195
|
+
setPause(ctx.runtime, paths, session.sessionId, "terminal");
|
|
16196
|
+
return success({ paused: true, sessionId: session.sessionId }, [ctx.t("pause.off")]);
|
|
16197
|
+
};
|
|
16198
|
+
var offCommand = {
|
|
16199
|
+
path: ["off"],
|
|
16200
|
+
summaryKey: "command.off.summary",
|
|
16201
|
+
usage: "finitemonkey off",
|
|
16202
|
+
status: "ready",
|
|
16203
|
+
run: (ctx) => Promise.resolve(toggle(ctx, true))
|
|
16204
|
+
};
|
|
16205
|
+
var onCommand = {
|
|
16206
|
+
path: ["on"],
|
|
16207
|
+
summaryKey: "command.on.summary",
|
|
16208
|
+
usage: "finitemonkey on",
|
|
16209
|
+
status: "ready",
|
|
16210
|
+
run: (ctx) => Promise.resolve(toggle(ctx, false))
|
|
16211
|
+
};
|
|
16212
|
+
|
|
15627
16213
|
// src/commands/policy.ts
|
|
15628
16214
|
var FIX = `finitemonkey policy false-positive <${OPTIONAL_GUARDS.join("|")}>`;
|
|
15629
16215
|
var recordFalsePositive = (ctx, guard) => {
|
|
@@ -15647,7 +16233,7 @@ var policyFalsePositiveCommand = {
|
|
|
15647
16233
|
usage: FIX,
|
|
15648
16234
|
status: "ready",
|
|
15649
16235
|
maxPositionals: 1,
|
|
15650
|
-
run: (ctx,
|
|
16236
|
+
run: (ctx, args2) => Promise.resolve(recordFalsePositive(ctx, args2.positionals[0] ?? ""))
|
|
15651
16237
|
};
|
|
15652
16238
|
|
|
15653
16239
|
// src/commands/prose-check.ts
|
|
@@ -15773,10 +16359,10 @@ var proseCheckCommand = {
|
|
|
15773
16359
|
status: "ready",
|
|
15774
16360
|
options: { stdin: { type: "boolean" }, record: { type: "boolean" } },
|
|
15775
16361
|
maxPositionals: 1e3,
|
|
15776
|
-
run: async (ctx,
|
|
16362
|
+
run: async (ctx, args2) => {
|
|
15777
16363
|
const root = projectRoot(ctx);
|
|
15778
|
-
const mode = { stdin:
|
|
15779
|
-
const reports = await reportsOf(ctx, root,
|
|
16364
|
+
const mode = { stdin: args2.values["stdin"] === true, record: args2.values["record"] === true };
|
|
16365
|
+
const reports = await reportsOf(ctx, root, args2.positionals, mode);
|
|
15780
16366
|
if (!reports.ok) return failureFrom(ctx.t, reports.error);
|
|
15781
16367
|
return resultOf2(ctx, reports.value);
|
|
15782
16368
|
}
|
|
@@ -15831,7 +16417,7 @@ var inputProblem = (ctx, id, reason, days) => {
|
|
|
15831
16417
|
}
|
|
15832
16418
|
return void 0;
|
|
15833
16419
|
};
|
|
15834
|
-
var entryOf3 = (ctx, finding3,
|
|
16420
|
+
var entryOf3 = (ctx, finding3, args2) => {
|
|
15835
16421
|
const now = ctx.runtime.now();
|
|
15836
16422
|
return {
|
|
15837
16423
|
id: finding3.id,
|
|
@@ -15839,30 +16425,30 @@ var entryOf3 = (ctx, finding3, args) => {
|
|
|
15839
16425
|
file: finding3.file,
|
|
15840
16426
|
line: finding3.line,
|
|
15841
16427
|
fingerprint: finding3.fingerprint,
|
|
15842
|
-
state:
|
|
16428
|
+
state: args2.falsePositive ? "falso-positivo" : "aceito",
|
|
15843
16429
|
owner: personName(ctx),
|
|
15844
|
-
reason:
|
|
16430
|
+
reason: args2.reason,
|
|
15845
16431
|
acceptedAt: now,
|
|
15846
|
-
expiresAt: plusDays(now,
|
|
16432
|
+
expiresAt: plusDays(now, args2.days)
|
|
15847
16433
|
};
|
|
15848
16434
|
};
|
|
15849
|
-
var acceptEntry = (ctx,
|
|
16435
|
+
var acceptEntry = (ctx, args2) => {
|
|
15850
16436
|
const root = projectRoot(ctx);
|
|
15851
16437
|
const baseline = loadBaseline(ctx.runtime, root);
|
|
15852
16438
|
if (!baseline.ok) {
|
|
15853
16439
|
return failure3(ctx, baselineInvalid(baseline.error));
|
|
15854
16440
|
}
|
|
15855
16441
|
const scanned = scanPath(ctx.runtime, root, ".");
|
|
15856
|
-
const finding3 = scanned.ok ? scanned.value.find((item) => item.id ===
|
|
16442
|
+
const finding3 = scanned.ok ? scanned.value.find((item) => item.id === args2.id) : void 0;
|
|
15857
16443
|
if (finding3 === void 0) {
|
|
15858
16444
|
return failure3(
|
|
15859
16445
|
ctx,
|
|
15860
16446
|
usageProblem("secrets_finding_not_found", "secrets.error.finding_not_found", "finitemonkey secrets scan", {
|
|
15861
|
-
id:
|
|
16447
|
+
id: args2.id
|
|
15862
16448
|
})
|
|
15863
16449
|
);
|
|
15864
16450
|
}
|
|
15865
|
-
const entry2 = entryOf3(ctx, finding3,
|
|
16451
|
+
const entry2 = entryOf3(ctx, finding3, args2);
|
|
15866
16452
|
const entries = [...baseline.value.entries.filter((item) => item.id !== entry2.id), entry2];
|
|
15867
16453
|
const saved = saveBaseline(ctx.runtime, root, { schema: baseline.value.schema, entries });
|
|
15868
16454
|
if (!saved.ok) {
|
|
@@ -15885,10 +16471,10 @@ var secretsAcceptCommand = {
|
|
|
15885
16471
|
status: "ready",
|
|
15886
16472
|
maxPositionals: 1,
|
|
15887
16473
|
options: { reason: { type: "string" }, days: { type: "string" }, "false-positive": { type: "boolean" } },
|
|
15888
|
-
run: (ctx,
|
|
15889
|
-
const id =
|
|
15890
|
-
const reason = stringOption(
|
|
15891
|
-
const days = daysOf(
|
|
16474
|
+
run: (ctx, args2) => {
|
|
16475
|
+
const id = args2.positionals[0] ?? "";
|
|
16476
|
+
const reason = stringOption(args2.values, "reason");
|
|
16477
|
+
const days = daysOf(args2.values);
|
|
15892
16478
|
const problem4 = inputProblem(ctx, id, reason, days);
|
|
15893
16479
|
if (problem4 !== void 0 || reason === void 0 || days === void 0) {
|
|
15894
16480
|
return Promise.resolve(
|
|
@@ -15899,7 +16485,7 @@ var secretsAcceptCommand = {
|
|
|
15899
16485
|
);
|
|
15900
16486
|
}
|
|
15901
16487
|
return Promise.resolve(
|
|
15902
|
-
acceptEntry(ctx, { id, reason, days, falsePositive:
|
|
16488
|
+
acceptEntry(ctx, { id, reason, days, falsePositive: args2.values["false-positive"] === true })
|
|
15903
16489
|
);
|
|
15904
16490
|
}
|
|
15905
16491
|
};
|
|
@@ -15980,18 +16566,18 @@ var secretsIncidentCommand = {
|
|
|
15980
16566
|
usage: USAGE,
|
|
15981
16567
|
status: "ready",
|
|
15982
16568
|
maxPositionals: 2,
|
|
15983
|
-
run: (ctx,
|
|
15984
|
-
const action = actionOf(
|
|
16569
|
+
run: (ctx, args2) => {
|
|
16570
|
+
const action = actionOf(args2.positionals[0]);
|
|
15985
16571
|
const root = projectRoot(ctx);
|
|
15986
16572
|
if (action === void 0)
|
|
15987
16573
|
return Promise.resolve(
|
|
15988
16574
|
fail2(
|
|
15989
16575
|
ctx,
|
|
15990
|
-
usageProblem("invalid_arguments", "error.invalid_arguments", USAGE, { detail:
|
|
16576
|
+
usageProblem("invalid_arguments", "error.invalid_arguments", USAGE, { detail: args2.positionals[0] ?? "" })
|
|
15991
16577
|
)
|
|
15992
16578
|
);
|
|
15993
16579
|
if (action === "list") return Promise.resolve(list2(ctx, root));
|
|
15994
|
-
const id =
|
|
16580
|
+
const id = args2.positionals[1] ?? "";
|
|
15995
16581
|
const incident = readIncident(ctx.runtime, root, id);
|
|
15996
16582
|
if (!incident.ok) return Promise.resolve(notFound2(ctx, id));
|
|
15997
16583
|
return Promise.resolve(action === "purge" ? purge(ctx, incident.value) : move(ctx, root, incident.value, action));
|
|
@@ -16041,25 +16627,25 @@ var historyIncidents = (ctx, root, fresh3) => fresh3.flatMap((finding3) => {
|
|
|
16041
16627
|
const saved = recordIncident(ctx.runtime, root, draft, HOOK_ACTOR);
|
|
16042
16628
|
return saved.ok ? [saved.value.id] : [];
|
|
16043
16629
|
});
|
|
16044
|
-
var dataOf = (mode,
|
|
16630
|
+
var dataOf = (mode, outcome2, incidents) => {
|
|
16045
16631
|
const findings = [
|
|
16046
|
-
...
|
|
16047
|
-
...
|
|
16048
|
-
...
|
|
16632
|
+
...outcome2.fresh.map((finding3) => view(finding3, "new")),
|
|
16633
|
+
...outcome2.known.map((finding3) => view(finding3, "known")),
|
|
16634
|
+
...outcome2.expired.map((finding3) => view(finding3, "expired"))
|
|
16049
16635
|
];
|
|
16050
16636
|
return {
|
|
16051
16637
|
schema: SECRETS_SCAN_SCHEMA,
|
|
16052
16638
|
mode,
|
|
16053
16639
|
baseline: BASELINE_FILE2,
|
|
16054
16640
|
findings,
|
|
16055
|
-
fixed:
|
|
16641
|
+
fixed: outcome2.fixed.map((entry2) => entry2.id),
|
|
16056
16642
|
incidents,
|
|
16057
16643
|
summary: {
|
|
16058
16644
|
total: findings.length,
|
|
16059
|
-
new:
|
|
16060
|
-
known:
|
|
16061
|
-
expired:
|
|
16062
|
-
fixed:
|
|
16645
|
+
new: outcome2.fresh.length,
|
|
16646
|
+
known: outcome2.known.length,
|
|
16647
|
+
expired: outcome2.expired.length,
|
|
16648
|
+
fixed: outcome2.fixed.length
|
|
16063
16649
|
}
|
|
16064
16650
|
};
|
|
16065
16651
|
};
|
|
@@ -16093,8 +16679,8 @@ var resultOf3 = (ctx, data) => {
|
|
|
16093
16679
|
human2
|
|
16094
16680
|
);
|
|
16095
16681
|
};
|
|
16096
|
-
var prune = (ctx, root, baseline,
|
|
16097
|
-
if (
|
|
16682
|
+
var prune = (ctx, root, baseline, outcome2) => {
|
|
16683
|
+
if (outcome2.fixed.length > 0) saveBaseline(ctx.runtime, root, withoutFixed(baseline, outcome2.fixed));
|
|
16098
16684
|
};
|
|
16099
16685
|
var secretsScanCommand = {
|
|
16100
16686
|
path: ["secrets", "scan"],
|
|
@@ -16102,25 +16688,25 @@ var secretsScanCommand = {
|
|
|
16102
16688
|
usage: "finitemonkey secrets scan [--staged | --history | --path <dir>] [--json]",
|
|
16103
16689
|
status: "ready",
|
|
16104
16690
|
options: { staged: { type: "boolean" }, history: { type: "boolean" }, path: { type: "string" } },
|
|
16105
|
-
run: async (ctx,
|
|
16106
|
-
const mode = modeOf3(
|
|
16691
|
+
run: async (ctx, args2) => {
|
|
16692
|
+
const mode = modeOf3(args2.values);
|
|
16107
16693
|
const fix = "finitemonkey help secrets scan";
|
|
16108
16694
|
if (mode === void 0) return failureFrom(ctx.t, usageProblem("invalid_arguments", "secrets.error.one_mode", fix));
|
|
16109
16695
|
const root = projectRoot(ctx);
|
|
16110
|
-
const target = stringOption(
|
|
16696
|
+
const target = stringOption(args2.values, "path") ?? ".";
|
|
16111
16697
|
const scanned = await runScan(ctx, root, mode, target);
|
|
16112
16698
|
if (!scanned.ok) return failureFrom(ctx.t, gitUnavailable(scanned.error));
|
|
16113
16699
|
const baseline = loadBaseline(ctx.runtime, root);
|
|
16114
16700
|
if (!baseline.ok) return failureFrom(ctx.t, baselineInvalid(baseline.error));
|
|
16115
|
-
const
|
|
16701
|
+
const outcome2 = ratchet(
|
|
16116
16702
|
scanned.value,
|
|
16117
16703
|
baseline.value,
|
|
16118
16704
|
ctx.runtime.now(),
|
|
16119
16705
|
mode === "path" ? scopeOf(target) : void 0
|
|
16120
16706
|
);
|
|
16121
|
-
if (mode === "path") prune(ctx, root, baseline.value,
|
|
16122
|
-
const incidents = mode === "history" ? historyIncidents(ctx, root,
|
|
16123
|
-
return resultOf3(ctx, dataOf(mode,
|
|
16707
|
+
if (mode === "path") prune(ctx, root, baseline.value, outcome2);
|
|
16708
|
+
const incidents = mode === "history" ? historyIncidents(ctx, root, outcome2.fresh) : [];
|
|
16709
|
+
return resultOf3(ctx, dataOf(mode, outcome2, incidents));
|
|
16124
16710
|
}
|
|
16125
16711
|
};
|
|
16126
16712
|
|
|
@@ -16171,7 +16757,11 @@ var checkYaml = (check2) => ({
|
|
|
16171
16757
|
...check2.timeoutS === void 0 ? {} : { timeout_s: check2.timeoutS },
|
|
16172
16758
|
...check2.require === void 0 ? {} : { require: [...check2.require] },
|
|
16173
16759
|
...check2.requireOpen === void 0 ? {} : { require_open: check2.requireOpen },
|
|
16174
|
-
...check2.description === void 0 ? {} : { description: check2.description }
|
|
16760
|
+
...check2.description === void 0 ? {} : { description: check2.description },
|
|
16761
|
+
...check2.port === void 0 ? {} : { port: check2.port },
|
|
16762
|
+
...check2.route === void 0 ? {} : { route: check2.route },
|
|
16763
|
+
...check2.status === void 0 ? {} : { status: check2.status },
|
|
16764
|
+
...check2.body === void 0 ? {} : { body: check2.body }
|
|
16175
16765
|
});
|
|
16176
16766
|
var contractYaml = (contract) => ({
|
|
16177
16767
|
id: contract.id,
|
|
@@ -16287,13 +16877,13 @@ var list3 = (values, name) => {
|
|
|
16287
16877
|
return raw.filter((item) => typeof item === "string" && item.trim() !== "");
|
|
16288
16878
|
};
|
|
16289
16879
|
var csv = (values, name) => list3(values, name).flatMap((item) => item.split(",").map((part2) => part2.trim())).filter((part2) => part2 !== "");
|
|
16290
|
-
var
|
|
16880
|
+
var positive3 = (values, name) => {
|
|
16291
16881
|
const parsed = Number.parseInt(stringOption(values, name) ?? "", 10);
|
|
16292
16882
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
16293
16883
|
};
|
|
16294
16884
|
var draftFrom = (ctx, paths, id, values) => {
|
|
16295
|
-
const files =
|
|
16296
|
-
const lines3 =
|
|
16885
|
+
const files = positive3(values, "budget-files");
|
|
16886
|
+
const lines3 = positive3(values, "budget-lines");
|
|
16297
16887
|
const size = SIZES.find((item) => item === stringOption(values, "size")) ?? "S";
|
|
16298
16888
|
return {
|
|
16299
16889
|
id,
|
|
@@ -16396,7 +16986,7 @@ var taskNewCommand = {
|
|
|
16396
16986
|
status: "ready",
|
|
16397
16987
|
options: TASK_OPTIONS,
|
|
16398
16988
|
maxPositionals: 1,
|
|
16399
|
-
run: (ctx,
|
|
16989
|
+
run: (ctx, args2) => Promise.resolve(newTask(ctx, args2.positionals[0], args2.values))
|
|
16400
16990
|
};
|
|
16401
16991
|
var taskShowCommand = {
|
|
16402
16992
|
path: ["task", "show"],
|
|
@@ -16404,7 +16994,7 @@ var taskShowCommand = {
|
|
|
16404
16994
|
usage: "finitemonkey task show [<id>]",
|
|
16405
16995
|
status: "ready",
|
|
16406
16996
|
maxPositionals: 1,
|
|
16407
|
-
run: (ctx,
|
|
16997
|
+
run: (ctx, args2) => Promise.resolve(showTask(ctx, args2.positionals[0]))
|
|
16408
16998
|
};
|
|
16409
16999
|
var taskDoneCommand = {
|
|
16410
17000
|
path: ["task", "done"],
|
|
@@ -16412,7 +17002,7 @@ var taskDoneCommand = {
|
|
|
16412
17002
|
usage: "finitemonkey task done [<id>]",
|
|
16413
17003
|
status: "ready",
|
|
16414
17004
|
maxPositionals: 1,
|
|
16415
|
-
run: (ctx,
|
|
17005
|
+
run: (ctx, args2) => Promise.resolve(doneTask(ctx, args2.positionals[0]))
|
|
16416
17006
|
};
|
|
16417
17007
|
|
|
16418
17008
|
// src/install/uninstall.ts
|
|
@@ -16462,7 +17052,7 @@ var isEmptyDir = (project, relative9) => {
|
|
|
16462
17052
|
const listed4 = project.runtime.listDir(project.abs(relative9));
|
|
16463
17053
|
return listed4.ok && listed4.value.length === 0;
|
|
16464
17054
|
};
|
|
16465
|
-
var
|
|
17055
|
+
var finish3 = (project, plan) => {
|
|
16466
17056
|
const target = plan.purge ? STATE_DIR : LOCK_FILE;
|
|
16467
17057
|
const removed = project.runtime.remove(project.abs(target));
|
|
16468
17058
|
if (!removed.ok) return reject({ path: target, detail: removed.error });
|
|
@@ -16477,7 +17067,7 @@ var applyRemoval = (project, plan) => {
|
|
|
16477
17067
|
}
|
|
16478
17068
|
return accept(void 0);
|
|
16479
17069
|
});
|
|
16480
|
-
return changed.ok ?
|
|
17070
|
+
return changed.ok ? finish3(project, plan) : changed;
|
|
16481
17071
|
};
|
|
16482
17072
|
|
|
16483
17073
|
// src/commands/uninstall.ts
|
|
@@ -16508,22 +17098,22 @@ var linesOf2 = (ctx, data) => [
|
|
|
16508
17098
|
ctx.t("install.uninstall.outside"),
|
|
16509
17099
|
...OUTSIDE.map(({ key, command }) => ` ${ctx.t(key, { command })}`)
|
|
16510
17100
|
];
|
|
16511
|
-
var fixFor = (
|
|
17101
|
+
var fixFor = (args2) => [
|
|
16512
17102
|
"finitemonkey uninstall --yes",
|
|
16513
|
-
...
|
|
16514
|
-
...
|
|
17103
|
+
...args2.values["purge"] === true ? ["--purge"] : [],
|
|
17104
|
+
...args2.values["keep-generated"] === true ? ["--keep-generated"] : []
|
|
16515
17105
|
].join(" ");
|
|
16516
|
-
var runUninstall = (ctx,
|
|
17106
|
+
var runUninstall = (ctx, args2) => {
|
|
16517
17107
|
const { project } = openProject(ctx);
|
|
16518
17108
|
const lock = readPreviousLock(project);
|
|
16519
17109
|
if (!lock.ok) return failureFrom(ctx.t, planProblem(lock.error));
|
|
16520
17110
|
if (lock.value === void 0) return failureFrom(ctx.t, notInstalled());
|
|
16521
|
-
const options = { purge:
|
|
17111
|
+
const options = { purge: args2.values["purge"] === true, keepGenerated: args2.values["keep-generated"] === true };
|
|
16522
17112
|
const plan = planRemoval(project, lock.value, options);
|
|
16523
17113
|
const preview = dataOf2(project.root, plan, false);
|
|
16524
17114
|
if (ctx.dryRun) return success(preview, [...linesOf2(ctx, preview), ctx.t("install.dry_run")]);
|
|
16525
17115
|
if (!ctx.yes) {
|
|
16526
|
-
const next2 = fixFor(
|
|
17116
|
+
const next2 = fixFor(args2);
|
|
16527
17117
|
const problem4 = confirmProblem("uninstall", ctx.t("install.uninstall.question"), next2);
|
|
16528
17118
|
return { ...failureFrom(ctx.t, { ...problem4, data: preview }, linesOf2(ctx, preview)), next: next2 };
|
|
16529
17119
|
}
|
|
@@ -16538,7 +17128,7 @@ var uninstallCommand = {
|
|
|
16538
17128
|
usage: "finitemonkey uninstall [--purge] [--keep-generated] [--dry-run] [--yes]",
|
|
16539
17129
|
status: "ready",
|
|
16540
17130
|
options: { purge: { type: "boolean" }, "keep-generated": { type: "boolean" } },
|
|
16541
|
-
run: (ctx,
|
|
17131
|
+
run: (ctx, args2) => Promise.resolve(runUninstall(ctx, args2))
|
|
16542
17132
|
};
|
|
16543
17133
|
|
|
16544
17134
|
// src/commands/update.ts
|
|
@@ -16561,14 +17151,14 @@ var check = (ctx, bin) => {
|
|
|
16561
17151
|
error: { code: "install_outdated", message: ctx.t("error.install_outdated"), fix: "finitemonkey update --yes" }
|
|
16562
17152
|
};
|
|
16563
17153
|
};
|
|
16564
|
-
var runUpdate = (ctx,
|
|
16565
|
-
const bin = stringOption(
|
|
16566
|
-
if (
|
|
17154
|
+
var runUpdate = (ctx, args2) => {
|
|
17155
|
+
const bin = stringOption(args2.values, "bin");
|
|
17156
|
+
if (args2.values["check"] === true) return check(ctx, bin);
|
|
16567
17157
|
const { project } = openProject(ctx);
|
|
16568
17158
|
const previous = readPreviousLock(project);
|
|
16569
17159
|
if (!previous.ok) return failureFrom(ctx.t, planProblem(previous.error));
|
|
16570
17160
|
if (previous.value === void 0) return failureFrom(ctx.t, notInstalled());
|
|
16571
|
-
const preset = stringOption(
|
|
17161
|
+
const preset = stringOption(args2.values, "preset");
|
|
16572
17162
|
const request = { mode: "update", preset, bin, marketplace: false, showDiff: true };
|
|
16573
17163
|
return runInstall(ctx, request, previous.value.preset);
|
|
16574
17164
|
};
|
|
@@ -16578,7 +17168,7 @@ var updateCommand = {
|
|
|
16578
17168
|
usage: "finitemonkey update [--check] [--preset neutral|gabriel] [--bin <path>] [--yes]",
|
|
16579
17169
|
status: "ready",
|
|
16580
17170
|
options: { check: { type: "boolean" }, preset: { type: "string" }, bin: { type: "string" } },
|
|
16581
|
-
run: (ctx,
|
|
17171
|
+
run: (ctx, args2) => Promise.resolve(runUpdate(ctx, args2))
|
|
16582
17172
|
};
|
|
16583
17173
|
|
|
16584
17174
|
// src/commands/version.ts
|
|
@@ -16608,12 +17198,15 @@ var REGISTRY = [
|
|
|
16608
17198
|
secretsScanCommand,
|
|
16609
17199
|
secretsAcceptCommand,
|
|
16610
17200
|
policyFalsePositiveCommand,
|
|
17201
|
+
offCommand,
|
|
17202
|
+
onCommand,
|
|
16611
17203
|
secretsIncidentCommand,
|
|
16612
17204
|
proseCheckCommand,
|
|
16613
17205
|
snapshotCommand,
|
|
16614
17206
|
undoCommand,
|
|
16615
17207
|
rescueCommand,
|
|
16616
17208
|
mergeVerifyCommand,
|
|
17209
|
+
appCheckCommand,
|
|
16617
17210
|
versionCommand,
|
|
16618
17211
|
helpCommand
|
|
16619
17212
|
];
|
|
@@ -16692,9 +17285,9 @@ var failWith = (ctx, name, problem4) => ({
|
|
|
16692
17285
|
});
|
|
16693
17286
|
var invoke = (ctx, argv, spec2, registry) => {
|
|
16694
17287
|
const name = commandName(spec2);
|
|
16695
|
-
const
|
|
16696
|
-
if (!
|
|
16697
|
-
return { name, execute: () => spec2.run(ctx,
|
|
17288
|
+
const args2 = strictArgs(argv, spec2);
|
|
17289
|
+
if (!args2.ok) return failWith(ctx, name, args2.error);
|
|
17290
|
+
return { name, execute: () => spec2.run(ctx, args2.value, registry) };
|
|
16698
17291
|
};
|
|
16699
17292
|
var builtin = (registry, name) => registry.find((spec2) => commandName(spec2) === name);
|
|
16700
17293
|
var dispatch = (ctx, argv, loose, registry) => {
|