finitemonkey 0.1.0-next.17 → 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/dist/finitemonkey.mjs +177 -46
- package/package.json +1 -1
package/dist/finitemonkey.mjs
CHANGED
|
@@ -3923,10 +3923,21 @@ var gitFindings = (args2) => {
|
|
|
3923
3923
|
return found;
|
|
3924
3924
|
};
|
|
3925
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
|
+
};
|
|
3926
3934
|
var fmFindings = (argv) => {
|
|
3927
|
-
const start = argv
|
|
3928
|
-
|
|
3929
|
-
|
|
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 [];
|
|
3930
3941
|
};
|
|
3931
3942
|
var detectBypass = (commandLine) => parseShell(commandLine).flatMap((command) => [
|
|
3932
3943
|
...envFindings(command),
|
|
@@ -4244,9 +4255,6 @@ var testsGuard = (input) => {
|
|
|
4244
4255
|
return deny(t("gate.guard.tests.model", { detail: reason }), t("gate.guard.tests.human", { detail: reason }));
|
|
4245
4256
|
};
|
|
4246
4257
|
|
|
4247
|
-
// src/gate/hooks/config.ts
|
|
4248
|
-
import { join as join13 } from "node:path";
|
|
4249
|
-
|
|
4250
4258
|
// src/gate/hooks/common.ts
|
|
4251
4259
|
import { dirname as dirname5, join as join12 } from "node:path";
|
|
4252
4260
|
var DEFAULT_GATE_BUDGET_MS = 3e5;
|
|
@@ -4277,7 +4285,90 @@ var contextOutput = (event, additionalContext, systemMessage) => ({
|
|
|
4277
4285
|
});
|
|
4278
4286
|
var human = (text6) => `finitemonkey: ${text6}`;
|
|
4279
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
|
+
|
|
4280
4370
|
// src/gate/hooks/config.ts
|
|
4371
|
+
import { join as join13 } from "node:path";
|
|
4281
4372
|
var CONFIG_FILE3 = "config-hooks.json";
|
|
4282
4373
|
var GUARDED_SOURCES = /* @__PURE__ */ new Set(["user_settings", "project_settings", "local_settings"]);
|
|
4283
4374
|
var countIn = (value) => {
|
|
@@ -4343,38 +4434,6 @@ var configChange = (input) => {
|
|
|
4343
4434
|
};
|
|
4344
4435
|
};
|
|
4345
4436
|
|
|
4346
|
-
// src/guards/release/markers.ts
|
|
4347
|
-
var LINE = /^\s*(?:finitemonkey|fm):\s+(allow|approve|trust)\s+(\S+)(?:\s+(.*))?$/i;
|
|
4348
|
-
var NAME = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,80}$/;
|
|
4349
|
-
var NOT_FROM_PERSON = [
|
|
4350
|
-
/<task-notification\b/i,
|
|
4351
|
-
/<agent-message\b/i,
|
|
4352
|
-
/^\s*\[julius2claude\]/,
|
|
4353
|
-
/\[Subagent hand-back\]/i
|
|
4354
|
-
];
|
|
4355
|
-
var comesFromPerson = (prompt) => !NOT_FROM_PERSON.some((pattern) => pattern.test(prompt));
|
|
4356
|
-
var toMarker = (verb, target, rest) => {
|
|
4357
|
-
if (!NAME.test(target)) return void 0;
|
|
4358
|
-
if (verb === "trust") return { type: "trust", task: target };
|
|
4359
|
-
if (verb === "allow") {
|
|
4360
|
-
return rest.length >= 3 ? { type: "allow", guard: target.toLowerCase(), reason: rest } : void 0;
|
|
4361
|
-
}
|
|
4362
|
-
const slash = target.indexOf("/");
|
|
4363
|
-
const task = slash < 0 ? void 0 : target.slice(0, slash);
|
|
4364
|
-
const check2 = slash < 0 ? target : target.slice(slash + 1);
|
|
4365
|
-
if (check2 === "") return void 0;
|
|
4366
|
-
return { type: "approve", check: check2, reason: rest, ...task === void 0 || task === "" ? {} : { task } };
|
|
4367
|
-
};
|
|
4368
|
-
var parseMarkers = (prompt) => {
|
|
4369
|
-
if (!comesFromPerson(prompt)) return [];
|
|
4370
|
-
return prompt.split(/\r?\n/).flatMap((line2) => {
|
|
4371
|
-
const match = LINE.exec(line2);
|
|
4372
|
-
if (match === null) return [];
|
|
4373
|
-
const marker = toMarker((match[1] ?? "").toLowerCase(), match[2] ?? "", (match[3] ?? "").trim());
|
|
4374
|
-
return marker === void 0 ? [] : [marker];
|
|
4375
|
-
});
|
|
4376
|
-
};
|
|
4377
|
-
|
|
4378
4437
|
// src/task/implicit.ts
|
|
4379
4438
|
var IMPLICIT_ID = "implicit";
|
|
4380
4439
|
var LOCKFILES2 = [
|
|
@@ -5953,6 +6012,7 @@ var en_default = {
|
|
|
5953
6012
|
"gate.guard.bypass.hooks_path": "Finite Monkey: blocked: {detail} points git away from the project hooks. requires: core.hooksPath stays as configured.",
|
|
5954
6013
|
"gate.guard.bypass.hook_env": "Finite Monkey: blocked: {detail} turns hooks or guards off. requires: hooks and guards stay on.",
|
|
5955
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.",
|
|
5956
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>",
|
|
5957
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.",
|
|
5958
6018
|
"gate.guard.self.allow_store": "Finite Monkey: blocked: {file} records what the person released; tools never write it.",
|
|
@@ -6129,7 +6189,14 @@ var en_default = {
|
|
|
6129
6189
|
"gate.runtime.body_mismatch": '{route} did not contain "{body}"',
|
|
6130
6190
|
"gate.runtime.request_failed": "the request to {route} failed: {detail}",
|
|
6131
6191
|
"gate.runtime.orphan": "the app on port {port} could not be stopped",
|
|
6132
|
-
"gate.runtime.probe_failed": "the app check did not report a result: {line}"
|
|
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)"
|
|
6133
6200
|
};
|
|
6134
6201
|
|
|
6135
6202
|
// src/i18n/es.json
|
|
@@ -6506,6 +6573,7 @@ var es_default = {
|
|
|
6506
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.",
|
|
6507
6574
|
"gate.guard.bypass.hook_env": "Finite Monkey: bloqueado: {detail} apaga hooks o guardas. exige: hooks y guardas quedan encendidos.",
|
|
6508
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.",
|
|
6509
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>",
|
|
6510
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.",
|
|
6511
6579
|
"gate.guard.self.allow_store": "Finite Monkey: bloqueado: {file} registra lo que la persona liberó; ninguna herramienta lo escribe.",
|
|
@@ -6682,7 +6750,14 @@ var es_default = {
|
|
|
6682
6750
|
"gate.runtime.body_mismatch": '{route} no contenía "{body}"',
|
|
6683
6751
|
"gate.runtime.request_failed": "la petición a {route} falló: {detail}",
|
|
6684
6752
|
"gate.runtime.orphan": "no se pudo detener la app del puerto {port}",
|
|
6685
|
-
"gate.runtime.probe_failed": "la comprobación de la app no devolvió resultado: {line}"
|
|
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)"
|
|
6686
6761
|
};
|
|
6687
6762
|
|
|
6688
6763
|
// src/i18n/pt-BR.json
|
|
@@ -7059,6 +7134,7 @@ var pt_BR_default = {
|
|
|
7059
7134
|
"gate.guard.bypass.hooks_path": "Finite Monkey: barrado: {detail} desvia o git dos hooks do projeto. exige: core.hooksPath fica como está configurado.",
|
|
7060
7135
|
"gate.guard.bypass.hook_env": "Finite Monkey: barrado: {detail} desliga hooks ou travas. exige: hooks e travas ficam ligados.",
|
|
7061
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.",
|
|
7062
7138
|
"gate.guard.bypass.human": "Barrei {detail}: desligaria a rede de proteção. Se quiser mesmo, digite numa linha: finitemonkey: allow bypass <motivo>",
|
|
7063
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.",
|
|
7064
7140
|
"gate.guard.self.allow_store": "Finite Monkey: barrado: {file} registra o que a pessoa liberou; ferramenta nunca escreve nele.",
|
|
@@ -7235,7 +7311,14 @@ var pt_BR_default = {
|
|
|
7235
7311
|
"gate.runtime.body_mismatch": '{route} não continha "{body}"',
|
|
7236
7312
|
"gate.runtime.request_failed": "a requisição para {route} falhou: {detail}",
|
|
7237
7313
|
"gate.runtime.orphan": "o app na porta {port} não pôde ser parado",
|
|
7238
|
-
"gate.runtime.probe_failed": "a checagem do app não devolveu resultado: {line}"
|
|
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)"
|
|
7239
7322
|
};
|
|
7240
7323
|
|
|
7241
7324
|
// src/i18n/review.json
|
|
@@ -7613,6 +7696,7 @@ var review_default = {
|
|
|
7613
7696
|
"gate.guard.bypass.hooks_path": "machine",
|
|
7614
7697
|
"gate.guard.bypass.hook_env": "machine",
|
|
7615
7698
|
"gate.guard.bypass.fm_allow": "machine",
|
|
7699
|
+
"gate.guard.bypass.fm_pause": "machine",
|
|
7616
7700
|
"gate.guard.bypass.human": "machine",
|
|
7617
7701
|
"gate.guard.self.policy": "machine",
|
|
7618
7702
|
"gate.guard.self.allow_store": "machine",
|
|
@@ -7789,7 +7873,14 @@ var review_default = {
|
|
|
7789
7873
|
"gate.runtime.body_mismatch": "machine",
|
|
7790
7874
|
"gate.runtime.request_failed": "machine",
|
|
7791
7875
|
"gate.runtime.orphan": "machine",
|
|
7792
|
-
"gate.runtime.probe_failed": "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"
|
|
7793
7884
|
},
|
|
7794
7885
|
es: {
|
|
7795
7886
|
"command.init.summary": "machine",
|
|
@@ -8164,6 +8255,7 @@ var review_default = {
|
|
|
8164
8255
|
"gate.guard.bypass.hooks_path": "machine",
|
|
8165
8256
|
"gate.guard.bypass.hook_env": "machine",
|
|
8166
8257
|
"gate.guard.bypass.fm_allow": "machine",
|
|
8258
|
+
"gate.guard.bypass.fm_pause": "machine",
|
|
8167
8259
|
"gate.guard.bypass.human": "machine",
|
|
8168
8260
|
"gate.guard.self.policy": "machine",
|
|
8169
8261
|
"gate.guard.self.allow_store": "machine",
|
|
@@ -8340,7 +8432,14 @@ var review_default = {
|
|
|
8340
8432
|
"gate.runtime.body_mismatch": "machine",
|
|
8341
8433
|
"gate.runtime.request_failed": "machine",
|
|
8342
8434
|
"gate.runtime.orphan": "machine",
|
|
8343
|
-
"gate.runtime.probe_failed": "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"
|
|
8344
8443
|
}
|
|
8345
8444
|
};
|
|
8346
8445
|
|
|
@@ -11566,9 +11665,9 @@ var subagentStart = (input) => {
|
|
|
11566
11665
|
// src/gate/hooks/index.ts
|
|
11567
11666
|
var PORTAO_HANDLERS = {
|
|
11568
11667
|
PreToolUse: [selfGuard, bypassGuard, testsGuard],
|
|
11569
|
-
UserPromptSubmit: [promptRelease],
|
|
11570
|
-
Stop: [stopGate],
|
|
11571
|
-
SubagentStop: [subagentStopGate],
|
|
11668
|
+
UserPromptSubmit: [pausePrompt, promptRelease],
|
|
11669
|
+
Stop: [unlessPaused(stopGate)],
|
|
11670
|
+
SubagentStop: [unlessPaused(subagentStopGate)],
|
|
11572
11671
|
SubagentStart: [subagentStart],
|
|
11573
11672
|
PreCompact: [preCompact],
|
|
11574
11673
|
SessionStart: [sessionStart],
|
|
@@ -13289,6 +13388,7 @@ var recordShadow = (input, paths, set, policy, reason) => {
|
|
|
13289
13388
|
var governed = (set, handler) => async (input) => {
|
|
13290
13389
|
const paths = projectPaths(input);
|
|
13291
13390
|
if (paths === void 0) return handler(input);
|
|
13391
|
+
if (pausedFor(input.runtime, paths, input.payload.sessionId) !== void 0) return { kind: "allow" };
|
|
13292
13392
|
const policy = loadPolicy(input.runtime, paths.root);
|
|
13293
13393
|
const mode = modeOf2(set, policy, readShadow(input.runtime, paths));
|
|
13294
13394
|
if (mode === "off") return { kind: "allow" };
|
|
@@ -16081,6 +16181,35 @@ var initCommand = {
|
|
|
16081
16181
|
}
|
|
16082
16182
|
};
|
|
16083
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
|
+
|
|
16084
16213
|
// src/commands/policy.ts
|
|
16085
16214
|
var FIX = `finitemonkey policy false-positive <${OPTIONAL_GUARDS.join("|")}>`;
|
|
16086
16215
|
var recordFalsePositive = (ctx, guard) => {
|
|
@@ -17069,6 +17198,8 @@ var REGISTRY = [
|
|
|
17069
17198
|
secretsScanCommand,
|
|
17070
17199
|
secretsAcceptCommand,
|
|
17071
17200
|
policyFalsePositiveCommand,
|
|
17201
|
+
offCommand,
|
|
17202
|
+
onCommand,
|
|
17072
17203
|
secretsIncidentCommand,
|
|
17073
17204
|
proseCheckCommand,
|
|
17074
17205
|
snapshotCommand,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "finitemonkey",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.18",
|
|
4
4
|
"description": "Claude Code hooks that stop a coding agent from saying done before the tests pass: a machine-checked definition of done, plus guardrails for secrets, git safety and production. Pre-release.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|