@joshuafolkken/kit 1.872.0 → 1.881.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +39 -2
- package/README.md +3 -3
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-KABG6AEW.js → chunk-264QY6KS.js} +7 -0
- package/dist/hooks/{chunk-I4D3NVUD.js → chunk-36UE53LS.js} +2 -2
- package/dist/hooks/{chunk-WCYPBPJC.js → chunk-4OXFU3MK.js} +8 -8
- package/dist/hooks/{chunk-ABVEVV2M.js → chunk-6MQCXEEA.js} +1 -1
- package/dist/hooks/{chunk-46EEEHC3.js → chunk-FNFOLFFV.js} +1 -1
- package/dist/hooks/{chunk-5U5EZYG6.js → chunk-FRJKVSK3.js} +2 -2
- package/dist/hooks/{chunk-2RUPMGGV.js → chunk-PRDCNGA6.js} +4 -4
- package/dist/hooks/{chunk-WMN4TSVF.js → chunk-VGYSA2NT.js} +2 -2
- package/dist/hooks/{chunk-A5YJ3H7E.js → chunk-Y5OYCU2F.js} +3 -3
- package/dist/hooks/{chunk-4QHBNAI4.js → chunk-ZBK4XRAS.js} +3 -3
- package/dist/hooks/codex-hook-adapter.js +10 -10
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +2 -2
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +9 -9
- package/dist/hooks/stop-guard.js +3 -3
- package/dist/josh.js +7 -0
- package/package.json +6 -2
- package/scripts/init/distributed-paths.ts +14 -11
- package/scripts/init/hook-command-bootstrap.ts +51 -0
- package/scripts/init/hook-command-rewrite.ts +9 -1
- package/scripts/init/init-logic.ts +2 -8
- package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +10 -0
- package/scripts/josh/josh-command-map.ts +1 -0
- package/scripts/josh/josh-commands-project.ts +6 -0
- package/scripts/registry-migration/migrate-logic.ts +229 -0
- package/scripts/registry-migration/migrate.ts +280 -0
- package/scripts/registry-migration/user-npmrc.ts +15 -0
- package/templates/workflows/ci.yml +6 -2
- package/dist/hooks/chunk-25JL6FMS.js +0 -4970
- package/dist/hooks/chunk-2ANGT3XM.js +0 -375
- package/dist/hooks/chunk-2EI5GBSW.js +0 -42
- package/dist/hooks/chunk-2OT5XE2N.js +0 -5014
- package/dist/hooks/chunk-2XIGZQMQ.js +0 -3299
- package/dist/hooks/chunk-33ELOKEV.js +0 -910
- package/dist/hooks/chunk-33YRTKM7.js +0 -230
- package/dist/hooks/chunk-36JQU5NN.js +0 -77
- package/dist/hooks/chunk-3EJBTWVS.js +0 -1769
- package/dist/hooks/chunk-3FK5SFAC.js +0 -432
- package/dist/hooks/chunk-3PWPYDD2.js +0 -240
- package/dist/hooks/chunk-3TQU7TDH.js +0 -375
- package/dist/hooks/chunk-3TVLSFZ6.js +0 -432
- package/dist/hooks/chunk-3VXYCB4E.js +0 -77
- package/dist/hooks/chunk-44M6JXGV.js +0 -3398
- package/dist/hooks/chunk-4A7UVP2P.js +0 -364
- package/dist/hooks/chunk-4LFQEZS4.js +0 -137
- package/dist/hooks/chunk-4OCX3V2T.js +0 -469
- package/dist/hooks/chunk-4OHA5DE7.js +0 -49
- package/dist/hooks/chunk-4PMDW3YD.js +0 -68
- package/dist/hooks/chunk-4SSB3FEE.js +0 -3273
- package/dist/hooks/chunk-5A2WQ2CQ.js +0 -5390
- package/dist/hooks/chunk-5EVA2JQB.js +0 -5390
- package/dist/hooks/chunk-5P7VF5VE.js +0 -3230
- package/dist/hooks/chunk-5QWJGGZP.js +0 -49
- package/dist/hooks/chunk-5VUUF3ZV.js +0 -240
- package/dist/hooks/chunk-5WA7UBT3.js +0 -374
- package/dist/hooks/chunk-6EBGRQ3Q.js +0 -301
- package/dist/hooks/chunk-6TVHWMD3.js +0 -432
- package/dist/hooks/chunk-6VAGLEMB.js +0 -68
- package/dist/hooks/chunk-75BTXKFJ.js +0 -3424
- package/dist/hooks/chunk-75RHN67S.js +0 -137
- package/dist/hooks/chunk-76KC3BDD.js +0 -3414
- package/dist/hooks/chunk-76SLS7CZ.js +0 -898
- package/dist/hooks/chunk-7DHZ4DWT.js +0 -5015
- package/dist/hooks/chunk-7INSJDGE.js +0 -458
- package/dist/hooks/chunk-7VJ4FTDX.js +0 -268
- package/dist/hooks/chunk-7XCYNHQK.js +0 -77
- package/dist/hooks/chunk-AAEXXUUL.js +0 -268
- package/dist/hooks/chunk-ACN3YXFL.js +0 -68
- package/dist/hooks/chunk-AD3XE3QZ.js +0 -397
- package/dist/hooks/chunk-AENFZPZH.js +0 -230
- package/dist/hooks/chunk-AFKRFQ6W.js +0 -68
- package/dist/hooks/chunk-AHD5IPWI.js +0 -375
- package/dist/hooks/chunk-AMK5JGV7.js +0 -77
- package/dist/hooks/chunk-ARN7NCQI.js +0 -425
- package/dist/hooks/chunk-AUFY653N.js +0 -3425
- package/dist/hooks/chunk-AXQBNFEF.js +0 -375
- package/dist/hooks/chunk-AYC7R6U4.js +0 -3316
- package/dist/hooks/chunk-AYEA2FJ7.js +0 -5015
- package/dist/hooks/chunk-B2LIXYFL.js +0 -77
- package/dist/hooks/chunk-B4HPNY2I.js +0 -375
- package/dist/hooks/chunk-B4YNCUGB.js +0 -469
- package/dist/hooks/chunk-B57S3VWT.js +0 -922
- package/dist/hooks/chunk-BINZ3PLI.js +0 -364
- package/dist/hooks/chunk-BIWLABFK.js +0 -432
- package/dist/hooks/chunk-BODUSXKK.js +0 -410
- package/dist/hooks/chunk-BQBAT2YK.js +0 -375
- package/dist/hooks/chunk-BUJEBW75.js +0 -391
- package/dist/hooks/chunk-BVNWORKA.js +0 -72
- package/dist/hooks/chunk-BWI47LQS.js +0 -5205
- package/dist/hooks/chunk-C25HRMJX.js +0 -137
- package/dist/hooks/chunk-CBFZNC74.js +0 -375
- package/dist/hooks/chunk-CECYXS4Y.js +0 -3424
- package/dist/hooks/chunk-CELGUP5F.js +0 -49
- package/dist/hooks/chunk-CMHANU3F.js +0 -3442
- package/dist/hooks/chunk-CMN372LI.js +0 -68
- package/dist/hooks/chunk-CPGZLMMK.js +0 -3299
- package/dist/hooks/chunk-CTQKXDC7.js +0 -268
- package/dist/hooks/chunk-CYAT4RIT.js +0 -68
- package/dist/hooks/chunk-CYTWYCH2.js +0 -5014
- package/dist/hooks/chunk-CZSOLRBA.js +0 -77
- package/dist/hooks/chunk-D2PIDYJR.js +0 -3438
- package/dist/hooks/chunk-DE57HI6T.js +0 -137
- package/dist/hooks/chunk-DGXDGAPG.js +0 -5306
- package/dist/hooks/chunk-DNYRSYQG.js +0 -5014
- package/dist/hooks/chunk-DTAXH2A2.js +0 -240
- package/dist/hooks/chunk-E2IZUWI5.js +0 -375
- package/dist/hooks/chunk-E4L2K2BL.js +0 -397
- package/dist/hooks/chunk-E55NKX5F.js +0 -68
- package/dist/hooks/chunk-ECXVCCVD.js +0 -3079
- package/dist/hooks/chunk-EPHO443D.js +0 -68
- package/dist/hooks/chunk-EUFK2BI2.js +0 -375
- package/dist/hooks/chunk-EYCD5ZAV.js +0 -137
- package/dist/hooks/chunk-F2SDYJU4.js +0 -240
- package/dist/hooks/chunk-F4B5D5TF.js +0 -68
- package/dist/hooks/chunk-FGEO3NDX.js +0 -432
- package/dist/hooks/chunk-FJYI52RE.js +0 -137
- package/dist/hooks/chunk-FYTZHIY4.js +0 -3085
- package/dist/hooks/chunk-G7JL2A5K.js +0 -375
- package/dist/hooks/chunk-GA3ITDBW.js +0 -42
- package/dist/hooks/chunk-GDR4H4SV.js +0 -469
- package/dist/hooks/chunk-GFKDXPSM.js +0 -2855
- package/dist/hooks/chunk-GIMRTKFU.js +0 -566
- package/dist/hooks/chunk-GOPHRLGO.js +0 -240
- package/dist/hooks/chunk-GX4HO7SJ.js +0 -230
- package/dist/hooks/chunk-GXKKK23T.js +0 -240
- package/dist/hooks/chunk-GZ6FUVIK.js +0 -566
- package/dist/hooks/chunk-H5HPY5M5.js +0 -2869
- package/dist/hooks/chunk-HCF3OGEE.js +0 -1829
- package/dist/hooks/chunk-HDEXAOUM.js +0 -469
- package/dist/hooks/chunk-HM2TY3TN.js +0 -469
- package/dist/hooks/chunk-HOA7NXA2.js +0 -55
- package/dist/hooks/chunk-HOFEWH6H.js +0 -240
- package/dist/hooks/chunk-HUUI6S5J.js +0 -2669
- package/dist/hooks/chunk-I4Q6WAJE.js +0 -68
- package/dist/hooks/chunk-IB6N4CR2.js +0 -432
- package/dist/hooks/chunk-IFLDYJMD.js +0 -469
- package/dist/hooks/chunk-IGU466YD.js +0 -77
- package/dist/hooks/chunk-IJCQUHKY.js +0 -375
- package/dist/hooks/chunk-IKUMBDJB.js +0 -230
- package/dist/hooks/chunk-IM3BDIBJ.js +0 -5005
- package/dist/hooks/chunk-IMYMAODK.js +0 -3431
- package/dist/hooks/chunk-IN2ZVGXA.js +0 -5005
- package/dist/hooks/chunk-ITVJ2MKQ.js +0 -18
- package/dist/hooks/chunk-J5RIJYTM.js +0 -2669
- package/dist/hooks/chunk-JFLMH4K5.js +0 -3460
- package/dist/hooks/chunk-JR25IFML.js +0 -77
- package/dist/hooks/chunk-JT5AUXFI.js +0 -432
- package/dist/hooks/chunk-JY5YVN6N.js +0 -3234
- package/dist/hooks/chunk-K5Q4ETVI.js +0 -391
- package/dist/hooks/chunk-K67V2F24.js +0 -137
- package/dist/hooks/chunk-KATZESEC.js +0 -3273
- package/dist/hooks/chunk-KFH4H7W7.js +0 -469
- package/dist/hooks/chunk-KMUEI6RX.js +0 -910
- package/dist/hooks/chunk-KMV4OY77.js +0 -3438
- package/dist/hooks/chunk-KQAZNWEY.js +0 -137
- package/dist/hooks/chunk-KZZR6JER.js +0 -5015
- package/dist/hooks/chunk-LAR6DREP.js +0 -77
- package/dist/hooks/chunk-LNCJWEZD.js +0 -5015
- package/dist/hooks/chunk-LRYD2GLM.js +0 -6
- package/dist/hooks/chunk-LXBKYHDV.js +0 -77
- package/dist/hooks/chunk-LYLKIUNE.js +0 -5024
- package/dist/hooks/chunk-LZKCFOVC.js +0 -432
- package/dist/hooks/chunk-M4FCIYRI.js +0 -77
- package/dist/hooks/chunk-M5M7327Q.js +0 -3425
- package/dist/hooks/chunk-MF72MHSX.js +0 -3455
- package/dist/hooks/chunk-MK56LKDO.js +0 -397
- package/dist/hooks/chunk-N3MJADY7.js +0 -240
- package/dist/hooks/chunk-NFQSUDBN.js +0 -458
- package/dist/hooks/chunk-NHREKY45.js +0 -137
- package/dist/hooks/chunk-NP5TTAAW.js +0 -375
- package/dist/hooks/chunk-NQTLTKTJ.js +0 -2993
- package/dist/hooks/chunk-NVRCZPBZ.js +0 -391
- package/dist/hooks/chunk-O46HMMLJ.js +0 -469
- package/dist/hooks/chunk-OFJGH2L4.js +0 -240
- package/dist/hooks/chunk-OLFMCZH5.js +0 -240
- package/dist/hooks/chunk-OMCZS46I.js +0 -49
- package/dist/hooks/chunk-OQZEZW5G.js +0 -469
- package/dist/hooks/chunk-P2MDAT2Y.js +0 -1897
- package/dist/hooks/chunk-P3M2JJIF.js +0 -68
- package/dist/hooks/chunk-PDVHQITQ.js +0 -3453
- package/dist/hooks/chunk-PNT2AMDH.js +0 -391
- package/dist/hooks/chunk-PR2LVSY6.js +0 -3445
- package/dist/hooks/chunk-PRR5R4JK.js +0 -137
- package/dist/hooks/chunk-PXT44QVN.js +0 -566
- package/dist/hooks/chunk-PZLWJLAP.js +0 -469
- package/dist/hooks/chunk-Q2FEAZJ2.js +0 -77
- package/dist/hooks/chunk-Q32WETDO.js +0 -3265
- package/dist/hooks/chunk-Q45DUBLE.js +0 -3600
- package/dist/hooks/chunk-Q7NZSWQ5.js +0 -240
- package/dist/hooks/chunk-QH2JNAMK.js +0 -3085
- package/dist/hooks/chunk-QNNWYQ2R.js +0 -375
- package/dist/hooks/chunk-QPU5H2OS.js +0 -68
- package/dist/hooks/chunk-QRAHZ5TO.js +0 -1829
- package/dist/hooks/chunk-QUZ5HPIE.js +0 -469
- package/dist/hooks/chunk-QVCRG34O.js +0 -2893
- package/dist/hooks/chunk-R3MY4E3S.js +0 -1675
- package/dist/hooks/chunk-R6TXJJXP.js +0 -77
- package/dist/hooks/chunk-REJU6VT7.js +0 -1829
- package/dist/hooks/chunk-REQAQLRC.js +0 -2993
- package/dist/hooks/chunk-RFCXPAHH.js +0 -391
- package/dist/hooks/chunk-RHI6Y22X.js +0 -137
- package/dist/hooks/chunk-RKZVOBBS.js +0 -469
- package/dist/hooks/chunk-RL57TT2Y.js +0 -566
- package/dist/hooks/chunk-RORDOD4S.js +0 -3321
- package/dist/hooks/chunk-RZKYW5P2.js +0 -77
- package/dist/hooks/chunk-SJPJ6VSI.js +0 -391
- package/dist/hooks/chunk-SKSIJQQQ.js +0 -432
- package/dist/hooks/chunk-SSQDZKXG.js +0 -268
- package/dist/hooks/chunk-SYHFKE4C.js +0 -77
- package/dist/hooks/chunk-TCGNI2ZY.js +0 -42
- package/dist/hooks/chunk-TG3WXJF5.js +0 -137
- package/dist/hooks/chunk-TH7IJAY5.js +0 -77
- package/dist/hooks/chunk-TLZ27PCY.js +0 -240
- package/dist/hooks/chunk-U652FXTN.js +0 -566
- package/dist/hooks/chunk-UEK47YUF.js +0 -268
- package/dist/hooks/chunk-UIO45H3O.js +0 -432
- package/dist/hooks/chunk-UNLZEEVH.js +0 -5005
- package/dist/hooks/chunk-UNRVF3SZ.js +0 -432
- package/dist/hooks/chunk-USLFAFOI.js +0 -3453
- package/dist/hooks/chunk-VAEELMLL.js +0 -442
- package/dist/hooks/chunk-VALSWLDQ.js +0 -3453
- package/dist/hooks/chunk-VC5JEPNY.js +0 -3398
- package/dist/hooks/chunk-VEZVK6C7.js +0 -230
- package/dist/hooks/chunk-VK5JKFAR.js +0 -49
- package/dist/hooks/chunk-VNF2KP7Z.js +0 -469
- package/dist/hooks/chunk-VWWCUMW6.js +0 -2669
- package/dist/hooks/chunk-W4JARUQV.js +0 -137
- package/dist/hooks/chunk-WEOBMNJG.js +0 -2993
- package/dist/hooks/chunk-WKJU3J5Y.js +0 -5390
- package/dist/hooks/chunk-WNON54PT.js +0 -3469
- package/dist/hooks/chunk-WOVKBPPX.js +0 -137
- package/dist/hooks/chunk-WRVFORYJ.js +0 -432
- package/dist/hooks/chunk-WUBVYGQZ.js +0 -240
- package/dist/hooks/chunk-WWULTUOM.js +0 -68
- package/dist/hooks/chunk-WXHKKB45.js +0 -4962
- package/dist/hooks/chunk-XAI3YTHJ.js +0 -469
- package/dist/hooks/chunk-XFZH6JZJ.js +0 -77
- package/dist/hooks/chunk-XGPWX6IA.js +0 -137
- package/dist/hooks/chunk-XIXXIVGY.js +0 -566
- package/dist/hooks/chunk-XKDOYJGA.js +0 -922
- package/dist/hooks/chunk-YALTVBHM.js +0 -432
- package/dist/hooks/chunk-YEBEPBFK.js +0 -5014
- package/dist/hooks/chunk-YI2BQ3DK.js +0 -3441
- package/dist/hooks/chunk-YVNBCFGG.js +0 -1829
- package/dist/hooks/chunk-YXBN3RGG.js +0 -432
- package/dist/hooks/chunk-Z2OOJSW3.js +0 -3163
- package/dist/hooks/chunk-ZA3HVBOY.js +0 -2644
- package/dist/hooks/chunk-ZKID46U3.js +0 -137
- package/dist/hooks/chunk-ZPMU2JV6.js +0 -49
- package/dist/hooks/chunk-ZRKY4W7O.js +0 -432
- package/dist/hooks/chunk-ZTMRB7LJ.js +0 -268
- package/dist/hooks/chunk-ZVPPBQ3L.js +0 -3413
|
@@ -1,566 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
stamp_file,
|
|
3
|
-
time_bundle_call,
|
|
4
|
-
time_density_hook,
|
|
5
|
-
time_format,
|
|
6
|
-
time_hook_transcript,
|
|
7
|
-
time_round_trips,
|
|
8
|
-
time_spans,
|
|
9
|
-
time_transcript_line
|
|
10
|
-
} from "./chunk-QVCRG34O.js";
|
|
11
|
-
import {
|
|
12
|
-
josh_environment_file
|
|
13
|
-
} from "./chunk-ITVJ2MKQ.js";
|
|
14
|
-
|
|
15
|
-
// scripts/josh/hook-decision.ts
|
|
16
|
-
import { z } from "zod";
|
|
17
|
-
var payload_schema = z.object({
|
|
18
|
-
transcript_path: z.string().min(1),
|
|
19
|
-
// **`nullish`, not `optional`.** A payload spelling the absent agent as `null` has to read as "no
|
|
20
|
-
// fork"; rejected, it would fail `safeParse` for the whole payload and take the guard off every
|
|
21
|
-
// call of the main line, in silence — the failure every other path here is written to avoid.
|
|
22
|
-
agent_id: z.string().nullish(),
|
|
23
|
-
tool_name: z.string().min(1),
|
|
24
|
-
tool_input: z.unknown()
|
|
25
|
-
});
|
|
26
|
-
var refusal_schema = z.object({ refused_at_ms: z.number() });
|
|
27
|
-
var HOOK_EVENT_NAME = "PreToolUse";
|
|
28
|
-
var DENY_DECISION = "deny";
|
|
29
|
-
var NEVER_MS = 0;
|
|
30
|
-
var MISSING_FILE = "ENOENT";
|
|
31
|
-
var DISABLED_VALUES = ["off", "0", "false", "no"];
|
|
32
|
-
function is_switch_enabled(key) {
|
|
33
|
-
return !DISABLED_VALUES.includes((process.env[key] ?? "").trim().toLowerCase());
|
|
34
|
-
}
|
|
35
|
-
function parse_hook_payload(raw_payload) {
|
|
36
|
-
const parsed = payload_schema.safeParse(JSON.parse(raw_payload));
|
|
37
|
-
return parsed.success ? parsed.data : void 0;
|
|
38
|
-
}
|
|
39
|
-
function deny_envelope(reason) {
|
|
40
|
-
return JSON.stringify({
|
|
41
|
-
hookSpecificOutput: {
|
|
42
|
-
hookEventName: HOOK_EVENT_NAME,
|
|
43
|
-
permissionDecision: DENY_DECISION,
|
|
44
|
-
permissionDecisionReason: reason
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function notice_envelope(notice) {
|
|
49
|
-
return JSON.stringify({
|
|
50
|
-
systemMessage: notice,
|
|
51
|
-
hookSpecificOutput: { hookEventName: HOOK_EVENT_NAME, additionalContext: notice }
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
function stamp_fault(switch_key) {
|
|
55
|
-
return `\u26A0 ${switch_key}: the run is past the limit but the refusal stamp could not be written, so this call was allowed rather than refused. Without the stamp a refusal could repeat and wedge the run. Batch the calls that do not need each other anyway, and check the temp directory is writable.`;
|
|
56
|
-
}
|
|
57
|
-
function is_missing_file(error) {
|
|
58
|
-
if (!(error instanceof Error) || !("code" in error)) return false;
|
|
59
|
-
return typeof error.code === "string" && error.code === MISSING_FILE;
|
|
60
|
-
}
|
|
61
|
-
function error_text(error) {
|
|
62
|
-
if (error instanceof Error) return error.message;
|
|
63
|
-
return typeof error === "string" ? error : "a value that is not an error";
|
|
64
|
-
}
|
|
65
|
-
function fault_notice(switch_key, error) {
|
|
66
|
-
if (is_missing_file(error)) return void 0;
|
|
67
|
-
const detail = error_text(error);
|
|
68
|
-
return `\u26A0 ${switch_key}: the guard could not read the run's history, so this call was allowed without being checked \u2014 silence here is not evidence that the run is batching. Cause: ${detail}`;
|
|
69
|
-
}
|
|
70
|
-
function last_refusal_ms(target) {
|
|
71
|
-
const raw = stamp_file.read_stamp_text(target);
|
|
72
|
-
if (raw === void 0) return NEVER_MS;
|
|
73
|
-
try {
|
|
74
|
-
return refusal_schema.parse(JSON.parse(raw)).refused_at_ms;
|
|
75
|
-
} catch {
|
|
76
|
-
return NEVER_MS;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function record_refusal(target, now_ms) {
|
|
80
|
-
try {
|
|
81
|
-
stamp_file.write_stamp(target, { refused_at_ms: now_ms });
|
|
82
|
-
return true;
|
|
83
|
-
} catch {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function create_refusal_stamp(prefix) {
|
|
88
|
-
function path(transcript_path) {
|
|
89
|
-
return stamp_file.stamp_path(prefix, transcript_path);
|
|
90
|
-
}
|
|
91
|
-
return { path, last_ms: last_refusal_ms, record: record_refusal };
|
|
92
|
-
}
|
|
93
|
-
var { load_environment_file } = josh_environment_file;
|
|
94
|
-
var NO_OUTCOME = { reason: void 0, notice: void 0, fault: void 0 };
|
|
95
|
-
function fire_once(stamp, run, should_fire, switch_key) {
|
|
96
|
-
const target = stamp.path(run.transcript);
|
|
97
|
-
if (!should_fire(stamp.last_ms(target))) return { fired: false, fault: void 0 };
|
|
98
|
-
if (!stamp.record(target, run.now_ms)) return { fired: false, fault: stamp_fault(switch_key) };
|
|
99
|
-
return { fired: true, fault: void 0 };
|
|
100
|
-
}
|
|
101
|
-
function block_outcome(context) {
|
|
102
|
-
const { spec, stamp, tail, call, run } = context;
|
|
103
|
-
const result = fire_once(
|
|
104
|
-
stamp,
|
|
105
|
-
run,
|
|
106
|
-
(last_fired_ms) => spec.should_block(tail, call, last_fired_ms, run),
|
|
107
|
-
spec.switch_key
|
|
108
|
-
);
|
|
109
|
-
if (result.fired) return { reason: spec.reason, notice: void 0, fault: void 0 };
|
|
110
|
-
return { reason: void 0, notice: void 0, fault: result.fault };
|
|
111
|
-
}
|
|
112
|
-
function notify_outcome(context) {
|
|
113
|
-
const { spec, notify_stamp, tail, call, run } = context;
|
|
114
|
-
if (notify_stamp === void 0 || spec.notify === void 0) return NO_OUTCOME;
|
|
115
|
-
const { notify } = spec;
|
|
116
|
-
const result = fire_once(
|
|
117
|
-
notify_stamp,
|
|
118
|
-
run,
|
|
119
|
-
(last_fired_ms) => notify.should_notify(tail, call, last_fired_ms, run),
|
|
120
|
-
spec.switch_key
|
|
121
|
-
);
|
|
122
|
-
if (result.fired) return { reason: void 0, notice: notify.text, fault: void 0 };
|
|
123
|
-
return { reason: void 0, notice: void 0, fault: result.fault };
|
|
124
|
-
}
|
|
125
|
-
function is_clear(outcome) {
|
|
126
|
-
return outcome.reason === void 0 && outcome.notice === void 0 && outcome.fault === void 0;
|
|
127
|
-
}
|
|
128
|
-
function guard_reason_for_payload(parts, payload, now_ms) {
|
|
129
|
-
const call = { name: payload.tool_name, input: payload.tool_input };
|
|
130
|
-
if (!parts.spec.is_candidate(call)) return NO_OUTCOME;
|
|
131
|
-
const transcript = time_hook_transcript.transcript_of(payload.transcript_path, payload.agent_id);
|
|
132
|
-
const tail = time_density_hook.read_tail(transcript);
|
|
133
|
-
const context = { ...parts, tail, call, run: { transcript, now_ms } };
|
|
134
|
-
const blocked = block_outcome(context);
|
|
135
|
-
if (!is_clear(blocked)) return blocked;
|
|
136
|
-
return notify_outcome(context);
|
|
137
|
-
}
|
|
138
|
-
function guard_outcome(parts, raw_payload, now_ms) {
|
|
139
|
-
const payload = parse_hook_payload(raw_payload);
|
|
140
|
-
if (payload === void 0 || !is_switch_enabled(parts.spec.switch_key)) return NO_OUTCOME;
|
|
141
|
-
return guard_reason_for_payload(parts, payload, now_ms);
|
|
142
|
-
}
|
|
143
|
-
function create_transcript_guard(spec) {
|
|
144
|
-
const stamp = create_refusal_stamp(spec.prefix);
|
|
145
|
-
const notify_stamp = spec.notify ? create_refusal_stamp(spec.notify.prefix) : void 0;
|
|
146
|
-
const parts = { spec, stamp, notify_stamp };
|
|
147
|
-
function is_enabled() {
|
|
148
|
-
return is_switch_enabled(spec.switch_key);
|
|
149
|
-
}
|
|
150
|
-
function refusal_path(transcript_path) {
|
|
151
|
-
return stamp.path(transcript_path);
|
|
152
|
-
}
|
|
153
|
-
function outcome(raw_payload, now_ms = Date.now()) {
|
|
154
|
-
try {
|
|
155
|
-
return guard_outcome(parts, raw_payload, now_ms);
|
|
156
|
-
} catch (error) {
|
|
157
|
-
return { reason: void 0, notice: void 0, fault: fault_notice(spec.switch_key, error) };
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function refusal(raw_payload, now_ms = Date.now()) {
|
|
161
|
-
return outcome(raw_payload, now_ms).reason;
|
|
162
|
-
}
|
|
163
|
-
return { is_enabled, outcome, refusal, refusal_path };
|
|
164
|
-
}
|
|
165
|
-
function write_outcome(raw_payload, outcome) {
|
|
166
|
-
load_environment_file();
|
|
167
|
-
const { reason, notice, fault } = outcome(raw_payload);
|
|
168
|
-
if (reason !== void 0) process.stdout.write(`${deny_envelope(reason)}
|
|
169
|
-
`);
|
|
170
|
-
else if (notice !== void 0) process.stdout.write(`${notice_envelope(notice)}
|
|
171
|
-
`);
|
|
172
|
-
else if (fault !== void 0) process.stdout.write(`${notice_envelope(fault)}
|
|
173
|
-
`);
|
|
174
|
-
}
|
|
175
|
-
function write_decision(raw_payload, refusal) {
|
|
176
|
-
write_outcome(raw_payload, (raw) => ({
|
|
177
|
-
reason: refusal(raw),
|
|
178
|
-
notice: void 0,
|
|
179
|
-
fault: void 0
|
|
180
|
-
}));
|
|
181
|
-
}
|
|
182
|
-
function report_no_payload(command) {
|
|
183
|
-
process.stderr.write(
|
|
184
|
-
`${command} reads a Claude Code PreToolUse payload on stdin; it is not run by hand.
|
|
185
|
-
`
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
var hook_decision = {
|
|
189
|
-
DISABLED_VALUES,
|
|
190
|
-
NEVER_MS,
|
|
191
|
-
create_refusal_stamp,
|
|
192
|
-
create_transcript_guard,
|
|
193
|
-
deny_envelope,
|
|
194
|
-
fault_notice,
|
|
195
|
-
is_switch_enabled,
|
|
196
|
-
load_environment_file,
|
|
197
|
-
notice_envelope,
|
|
198
|
-
parse_hook_payload,
|
|
199
|
-
report_no_payload,
|
|
200
|
-
stamp_fault,
|
|
201
|
-
write_decision,
|
|
202
|
-
write_outcome
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// scripts/time-runtime/time-agent-bundles.ts
|
|
206
|
-
var NONE = 0;
|
|
207
|
-
var ONE = 1;
|
|
208
|
-
var MIN_GROUP = 2;
|
|
209
|
-
function is_launch(span) {
|
|
210
|
-
return span.category === time_spans.TOOL_CATEGORY && !span.is_continuation && time_bundle_call.is_launch_tool(span.label);
|
|
211
|
-
}
|
|
212
|
-
function new_walk() {
|
|
213
|
-
return { closed: [], open: NONE, wrote_since: false, turn_id: time_spans.NO_MESSAGE_ID };
|
|
214
|
-
}
|
|
215
|
-
function close_group(walk) {
|
|
216
|
-
if (walk.open >= MIN_GROUP) walk.closed.push(walk.open);
|
|
217
|
-
walk.open = NONE;
|
|
218
|
-
}
|
|
219
|
-
function is_same_turn(walk, span) {
|
|
220
|
-
return span.message_id !== time_spans.NO_MESSAGE_ID && span.message_id === walk.turn_id;
|
|
221
|
-
}
|
|
222
|
-
function open_turn(walk, span) {
|
|
223
|
-
if (walk.wrote_since || span.has_prior_reference) close_group(walk);
|
|
224
|
-
walk.open += ONE;
|
|
225
|
-
walk.turn_id = span.message_id;
|
|
226
|
-
walk.wrote_since = false;
|
|
227
|
-
}
|
|
228
|
-
function step(walk, span) {
|
|
229
|
-
if (span.is_writing) {
|
|
230
|
-
walk.wrote_since = true;
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (!is_launch(span) || is_same_turn(walk, span)) return;
|
|
234
|
-
open_turn(walk, span);
|
|
235
|
-
}
|
|
236
|
-
function agent_bundles(spans) {
|
|
237
|
-
const walk = new_walk();
|
|
238
|
-
for (const span of time_round_trips.in_time_order(spans)) step(walk, span);
|
|
239
|
-
close_group(walk);
|
|
240
|
-
return walk.closed;
|
|
241
|
-
}
|
|
242
|
-
var time_agent_bundles = { agent_bundles };
|
|
243
|
-
|
|
244
|
-
// scripts/time-runtime/time-bundles.ts
|
|
245
|
-
var { unmeasured_row } = time_format;
|
|
246
|
-
var HEADING = "Bundling:";
|
|
247
|
-
var SEQUENCE_LABEL = "bundleable sequences";
|
|
248
|
-
var RECOVERABLE_LABEL = "recoverable round trips";
|
|
249
|
-
var SAVING_LABEL = "recoverable wait";
|
|
250
|
-
var BY_TOOL_LABEL = "recoverable by tool";
|
|
251
|
-
var AGENT_ROW_LABEL = "Agent";
|
|
252
|
-
var ROW_INDENT = " ";
|
|
253
|
-
var MIN_SEQUENCE = 2;
|
|
254
|
-
var ONE_CALL = 1;
|
|
255
|
-
var NONE2 = 0;
|
|
256
|
-
var PATH_SEPARATOR = "/";
|
|
257
|
-
var FIRST_CALL = 1;
|
|
258
|
-
var NO_LABEL = "";
|
|
259
|
-
var NO_BUNDLES = {
|
|
260
|
-
sequence_count: 0,
|
|
261
|
-
longest_sequence: 0,
|
|
262
|
-
recoverable_round_trips: 0,
|
|
263
|
-
by_tool: [],
|
|
264
|
-
unattributed_round_trips: 0,
|
|
265
|
-
is_measured: false
|
|
266
|
-
};
|
|
267
|
-
function contains_segments(whole, part) {
|
|
268
|
-
if (whole.startsWith(`${part}${PATH_SEPARATOR}`)) return true;
|
|
269
|
-
return whole.endsWith(`${PATH_SEPARATOR}${part}`) || whole.includes(`${PATH_SEPARATOR}${part}${PATH_SEPARATOR}`);
|
|
270
|
-
}
|
|
271
|
-
function is_related(left, right) {
|
|
272
|
-
if (left === right) return true;
|
|
273
|
-
return contains_segments(left, right) || contains_segments(right, left);
|
|
274
|
-
}
|
|
275
|
-
function shares_target(left, right) {
|
|
276
|
-
return left.some((one) => right.some((other) => is_related(one, other)));
|
|
277
|
-
}
|
|
278
|
-
function is_dependent(earlier, later) {
|
|
279
|
-
if (earlier.is_writing && later.is_writing) return false;
|
|
280
|
-
return shares_target(earlier.targets, later.targets);
|
|
281
|
-
}
|
|
282
|
-
function conflicts(span, sequence) {
|
|
283
|
-
return sequence.some((earlier) => is_dependent(earlier, span));
|
|
284
|
-
}
|
|
285
|
-
function is_call(span) {
|
|
286
|
-
return span.category === time_spans.TOOL_CATEGORY && !span.is_continuation;
|
|
287
|
-
}
|
|
288
|
-
function is_turn_boundary(span) {
|
|
289
|
-
return span.category === time_spans.MODEL_CATEGORY;
|
|
290
|
-
}
|
|
291
|
-
function new_walk2() {
|
|
292
|
-
return { pending: [], sequence: [], closed: [] };
|
|
293
|
-
}
|
|
294
|
-
function flush(walk) {
|
|
295
|
-
if (walk.sequence.length >= MIN_SEQUENCE) walk.closed.push(walk.sequence);
|
|
296
|
-
walk.sequence = [];
|
|
297
|
-
}
|
|
298
|
-
function extend(walk, span) {
|
|
299
|
-
if (conflicts(span, walk.sequence)) flush(walk);
|
|
300
|
-
walk.sequence.push(span);
|
|
301
|
-
}
|
|
302
|
-
function close_trip(walk) {
|
|
303
|
-
const [only] = walk.pending;
|
|
304
|
-
if (walk.pending.length === ONE_CALL && only?.is_bundleable === true) extend(walk, only);
|
|
305
|
-
else if (walk.pending.length > NONE2) flush(walk);
|
|
306
|
-
walk.pending = [];
|
|
307
|
-
}
|
|
308
|
-
function is_same_turn2(span, pending) {
|
|
309
|
-
const [first] = pending;
|
|
310
|
-
if (first === void 0 || span.is_continuation) return false;
|
|
311
|
-
if (span.message_id === time_spans.NO_MESSAGE_ID) return false;
|
|
312
|
-
return span.message_id === first.message_id;
|
|
313
|
-
}
|
|
314
|
-
function step2(walk, span) {
|
|
315
|
-
if (is_call(span)) {
|
|
316
|
-
walk.pending.push(span);
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (is_same_turn2(span, walk.pending)) return;
|
|
320
|
-
close_trip(walk);
|
|
321
|
-
if (!is_turn_boundary(span)) flush(walk);
|
|
322
|
-
}
|
|
323
|
-
function longest_of(sizes) {
|
|
324
|
-
return sizes.length === NONE2 ? NONE2 : Math.max(...sizes);
|
|
325
|
-
}
|
|
326
|
-
function recoverable_of(sizes) {
|
|
327
|
-
return sizes.reduce((sum, size) => sum + size - ONE_CALL, NONE2);
|
|
328
|
-
}
|
|
329
|
-
function sizes_of(closed) {
|
|
330
|
-
return closed.map((sequence) => sequence.length);
|
|
331
|
-
}
|
|
332
|
-
function tally_for(tallies, label) {
|
|
333
|
-
const found = tallies.get(label);
|
|
334
|
-
if (found !== void 0) return found;
|
|
335
|
-
const created = { sequence_count: NONE2, recoverable_round_trips: NONE2 };
|
|
336
|
-
tallies.set(label, created);
|
|
337
|
-
return created;
|
|
338
|
-
}
|
|
339
|
-
function count_trip(tallies, counted, label) {
|
|
340
|
-
const tally = tally_for(tallies, label);
|
|
341
|
-
tally.recoverable_round_trips += ONE_CALL;
|
|
342
|
-
if (!counted.has(label)) tally.sequence_count += ONE_CALL;
|
|
343
|
-
counted.add(label);
|
|
344
|
-
}
|
|
345
|
-
function tally_sequence(tallies, sequence) {
|
|
346
|
-
const counted = /* @__PURE__ */ new Set();
|
|
347
|
-
for (const span of sequence.slice(FIRST_CALL)) {
|
|
348
|
-
if (span.label !== NO_LABEL) count_trip(tallies, counted, span.label);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
function by_weight(left, right) {
|
|
352
|
-
if (left.recoverable_round_trips !== right.recoverable_round_trips) {
|
|
353
|
-
return right.recoverable_round_trips - left.recoverable_round_trips;
|
|
354
|
-
}
|
|
355
|
-
return left.label.localeCompare(right.label);
|
|
356
|
-
}
|
|
357
|
-
function tool_rows(closed) {
|
|
358
|
-
const tallies = /* @__PURE__ */ new Map();
|
|
359
|
-
for (const sequence of closed) tally_sequence(tallies, sequence);
|
|
360
|
-
return [...tallies].map(([label, tally]) => ({ label, ...tally })).toSorted(by_weight);
|
|
361
|
-
}
|
|
362
|
-
function attributed_of(rows) {
|
|
363
|
-
return rows.reduce((sum, row) => sum + row.recoverable_round_trips, NONE2);
|
|
364
|
-
}
|
|
365
|
-
function with_agent_row(rows, agent_sizes) {
|
|
366
|
-
const recoverable_round_trips = recoverable_of(agent_sizes);
|
|
367
|
-
if (recoverable_round_trips === NONE2) return [...rows];
|
|
368
|
-
const row = {
|
|
369
|
-
label: AGENT_ROW_LABEL,
|
|
370
|
-
sequence_count: agent_sizes.length,
|
|
371
|
-
recoverable_round_trips
|
|
372
|
-
};
|
|
373
|
-
return [...rows, row].toSorted(by_weight);
|
|
374
|
-
}
|
|
375
|
-
function build_bundles(spans) {
|
|
376
|
-
const walk = new_walk2();
|
|
377
|
-
for (const span of time_round_trips.in_time_order(spans)) step2(walk, span);
|
|
378
|
-
close_trip(walk);
|
|
379
|
-
flush(walk);
|
|
380
|
-
const sizes = sizes_of(walk.closed);
|
|
381
|
-
const agent_sizes = time_agent_bundles.agent_bundles(spans);
|
|
382
|
-
const by_tool = with_agent_row(tool_rows(walk.closed), agent_sizes);
|
|
383
|
-
const recoverable_round_trips = recoverable_of(sizes) + recoverable_of(agent_sizes);
|
|
384
|
-
return {
|
|
385
|
-
sequence_count: sizes.length + agent_sizes.length,
|
|
386
|
-
longest_sequence: Math.max(longest_of(sizes), longest_of(agent_sizes)),
|
|
387
|
-
recoverable_round_trips,
|
|
388
|
-
by_tool,
|
|
389
|
-
unattributed_round_trips: recoverable_round_trips - attributed_of(by_tool),
|
|
390
|
-
is_measured: time_spans.has_transcript_data(spans.length)
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
function open_sequence(spans) {
|
|
394
|
-
const walk = new_walk2();
|
|
395
|
-
for (const span of time_round_trips.in_time_order(spans)) step2(walk, span);
|
|
396
|
-
return walk.sequence;
|
|
397
|
-
}
|
|
398
|
-
function sequence_suffix(totals) {
|
|
399
|
-
return `longest ${String(totals.longest_sequence)} turn(s)`;
|
|
400
|
-
}
|
|
401
|
-
function recoverable_suffix(totals, round_trip_count) {
|
|
402
|
-
const share = time_format.format_share(totals.recoverable_round_trips, round_trip_count);
|
|
403
|
-
return `${share} of ${String(round_trip_count)} round trip(s)`;
|
|
404
|
-
}
|
|
405
|
-
function saving_line(totals, model_ms_per_round_trip) {
|
|
406
|
-
const saved_ms = totals.recoverable_round_trips * model_ms_per_round_trip;
|
|
407
|
-
const rate = `at ${time_format.format_seconds(model_ms_per_round_trip)} model time per round trip`;
|
|
408
|
-
return time_format.format_row(SAVING_LABEL, saved_ms, rate);
|
|
409
|
-
}
|
|
410
|
-
function by_tool_suffix(totals) {
|
|
411
|
-
const attributed = totals.recoverable_round_trips - totals.unattributed_round_trips;
|
|
412
|
-
return `${String(attributed)} of ${String(totals.recoverable_round_trips)} attributed`;
|
|
413
|
-
}
|
|
414
|
-
function tool_row(row) {
|
|
415
|
-
return time_format.format_columns(
|
|
416
|
-
`${ROW_INDENT}${row.label}`,
|
|
417
|
-
String(row.recoverable_round_trips),
|
|
418
|
-
`in ${String(row.sequence_count)} sequence(s)`
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
function by_tool_lines(totals) {
|
|
422
|
-
const heading = time_format.format_columns(
|
|
423
|
-
BY_TOOL_LABEL,
|
|
424
|
-
String(totals.by_tool.length),
|
|
425
|
-
by_tool_suffix(totals)
|
|
426
|
-
);
|
|
427
|
-
const rows = totals.by_tool.slice(NONE2, time_format.MAX_ROWS).map((row) => tool_row(row));
|
|
428
|
-
return [heading, ...rows, ...time_format.overflow_line(totals.by_tool.length)];
|
|
429
|
-
}
|
|
430
|
-
function measured_lines(totals, price) {
|
|
431
|
-
return [
|
|
432
|
-
time_format.format_columns(
|
|
433
|
-
SEQUENCE_LABEL,
|
|
434
|
-
String(totals.sequence_count),
|
|
435
|
-
sequence_suffix(totals)
|
|
436
|
-
),
|
|
437
|
-
time_format.format_columns(
|
|
438
|
-
RECOVERABLE_LABEL,
|
|
439
|
-
String(totals.recoverable_round_trips),
|
|
440
|
-
recoverable_suffix(totals, price.round_trip_count)
|
|
441
|
-
),
|
|
442
|
-
saving_line(totals, price.model_ms_per_round_trip),
|
|
443
|
-
...by_tool_lines(totals)
|
|
444
|
-
];
|
|
445
|
-
}
|
|
446
|
-
var LABELS = [SEQUENCE_LABEL, RECOVERABLE_LABEL, SAVING_LABEL, BY_TOOL_LABEL];
|
|
447
|
-
function no_divisor_lines() {
|
|
448
|
-
return LABELS.map((label) => time_format.format_columns(label, "", time_format.NO_CALLS));
|
|
449
|
-
}
|
|
450
|
-
function bundle_lines(totals, price) {
|
|
451
|
-
const heading = ["", HEADING];
|
|
452
|
-
if (!totals.is_measured) return [...heading, ...LABELS.map((label) => unmeasured_row(label))];
|
|
453
|
-
if (price.round_trip_count === NONE2) return [...heading, ...no_divisor_lines()];
|
|
454
|
-
return [...heading, ...measured_lines(totals, price)];
|
|
455
|
-
}
|
|
456
|
-
var time_bundles = {
|
|
457
|
-
HEADING,
|
|
458
|
-
SEQUENCE_LABEL,
|
|
459
|
-
RECOVERABLE_LABEL,
|
|
460
|
-
SAVING_LABEL,
|
|
461
|
-
BY_TOOL_LABEL,
|
|
462
|
-
MIN_SEQUENCE,
|
|
463
|
-
NO_BUNDLES,
|
|
464
|
-
build_bundles,
|
|
465
|
-
bundle_lines,
|
|
466
|
-
is_dependent,
|
|
467
|
-
open_sequence,
|
|
468
|
-
shares_target
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
// scripts/time-runtime/time-command-key.ts
|
|
472
|
-
var UNNAMED_KEY = "";
|
|
473
|
-
function command_key(span) {
|
|
474
|
-
if (span.label === time_spans.UNKNOWN_TOOL) return UNNAMED_KEY;
|
|
475
|
-
return span.josh_command === "" ? span.label : span.josh_command;
|
|
476
|
-
}
|
|
477
|
-
var time_command_key = { UNNAMED_KEY, command_key };
|
|
478
|
-
|
|
479
|
-
// scripts/time-runtime/time-call-identity.ts
|
|
480
|
-
var IDENTITY_SEPARATOR = "\0";
|
|
481
|
-
function identity_of(call) {
|
|
482
|
-
return [
|
|
483
|
-
time_command_key.command_key(call),
|
|
484
|
-
call.check_key,
|
|
485
|
-
[...call.targets].toSorted((left, right) => left.localeCompare(right)).join(",")
|
|
486
|
-
].join(IDENTITY_SEPARATOR);
|
|
487
|
-
}
|
|
488
|
-
var time_call_identity = { identity_of };
|
|
489
|
-
|
|
490
|
-
// scripts/time-runtime/time-batch-guard.ts
|
|
491
|
-
var CONSECUTIVE_LIMIT = 3;
|
|
492
|
-
var ONE_TURN = 1;
|
|
493
|
-
var NONE3 = 0;
|
|
494
|
-
var SEQUENCE_BEFORE_LIMIT = CONSECUTIVE_LIMIT - ONE_TURN;
|
|
495
|
-
var REASON = `\u26D4 batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this one would make ${String(CONSECUTIVE_LIMIT)} in a row. Reissue it in one turn together with the calls meant to follow it that do not need its result. **The criterion is whether this call's input needs another call's result, not what kind of call it is** \u2014 edits are covered exactly as reads are, and it never authorizes weakening a verification gate or a review: fewer turns, never less work. The measured cost and the rejected mechanisms are in \`prompts/collaboration-workflow/turn-batching.md\`. If this turn was already batching, or the call genuinely has nothing to go beside it, reissue it as it was: this fires once per run of single-call turns and cannot repeat on the call in hand.`;
|
|
496
|
-
var NOTICE = `\u{1F4A1} batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this Write makes ${String(CONSECUTIVE_LIMIT)} in a row. This is a notice, not a refusal \u2014 the write proceeds. Where the writes meant to follow it do not need its result, issue them in one turn together. **The criterion is whether a call's input needs another call's result, not what kind of call it is** \u2014 it never authorizes weakening a verification gate or a review: fewer turns, never less work. The measured cost and the rejected mechanisms are in \`prompts/collaboration-workflow/turn-batching.md\`. If this run was already batching, or the write genuinely has nothing to go beside it, carry on: this fires once per run of single-call turns.`;
|
|
497
|
-
var WHOLE_FILE_WRITE_TOOL = "Write";
|
|
498
|
-
function is_guarded_call(call) {
|
|
499
|
-
if (call.name === WHOLE_FILE_WRITE_TOOL) return false;
|
|
500
|
-
return time_bundle_call.call_facts(call.name, call.input).is_bundleable;
|
|
501
|
-
}
|
|
502
|
-
function is_notice_call(call) {
|
|
503
|
-
return call.name === WHOLE_FILE_WRITE_TOOL;
|
|
504
|
-
}
|
|
505
|
-
function is_read_only_call(call) {
|
|
506
|
-
const facts = time_bundle_call.call_facts(call.name, call.input);
|
|
507
|
-
return facts.is_bundleable && !facts.may_write;
|
|
508
|
-
}
|
|
509
|
-
function depends_on_sequence(sequence, facts) {
|
|
510
|
-
return sequence.some((span) => time_bundles.shares_target(span.targets, facts.targets));
|
|
511
|
-
}
|
|
512
|
-
function sequence_started_ms(sequence) {
|
|
513
|
-
return sequence[0]?.ended_ms ?? NONE3;
|
|
514
|
-
}
|
|
515
|
-
function is_sequence_at_limit(sequence, facts, refused_at_ms) {
|
|
516
|
-
if (sequence.length < SEQUENCE_BEFORE_LIMIT) return false;
|
|
517
|
-
if (depends_on_sequence(sequence, facts)) return false;
|
|
518
|
-
return sequence_started_ms(sequence) > refused_at_ms;
|
|
519
|
-
}
|
|
520
|
-
function is_at_limit(spans, call, last_fired_ms) {
|
|
521
|
-
return is_sequence_at_limit(
|
|
522
|
-
time_bundles.open_sequence(spans),
|
|
523
|
-
time_bundle_call.call_facts(call.name, call.input),
|
|
524
|
-
last_fired_ms
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
var GUARD_LABEL = time_transcript_line.guard_from_refusal(REASON);
|
|
528
|
-
function is_reissued_refusal(spans, call) {
|
|
529
|
-
const identity = time_call_identity.identity_of(
|
|
530
|
-
time_spans.to_tool_call(call.name, call.input, time_spans.NO_MESSAGE_ID)
|
|
531
|
-
);
|
|
532
|
-
return spans.some(
|
|
533
|
-
(span) => span.refusal_guard === GUARD_LABEL && time_call_identity.identity_of(span) === identity
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
function should_block(text, call, refused_at_ms) {
|
|
537
|
-
if (!is_guarded_call(call)) return false;
|
|
538
|
-
const { spans } = time_spans.parse_timeline(text);
|
|
539
|
-
if (is_reissued_refusal(spans, call)) return false;
|
|
540
|
-
return is_at_limit(spans, call, refused_at_ms);
|
|
541
|
-
}
|
|
542
|
-
function should_notify(text, call, notified_at_ms) {
|
|
543
|
-
if (!is_notice_call(call)) return false;
|
|
544
|
-
return is_at_limit(time_spans.parse_timeline(text).spans, call, notified_at_ms);
|
|
545
|
-
}
|
|
546
|
-
var STAMP_PREFIX = "josh-batch-guard-";
|
|
547
|
-
var NOTICE_STAMP_PREFIX = "josh-batch-guard-notice-";
|
|
548
|
-
var time_batch_guard = {
|
|
549
|
-
CONSECUTIVE_LIMIT,
|
|
550
|
-
GUARD_LABEL,
|
|
551
|
-
NOTICE,
|
|
552
|
-
NOTICE_STAMP_PREFIX,
|
|
553
|
-
REASON,
|
|
554
|
-
SEQUENCE_BEFORE_LIMIT,
|
|
555
|
-
STAMP_PREFIX,
|
|
556
|
-
is_guarded_call,
|
|
557
|
-
is_notice_call,
|
|
558
|
-
is_read_only_call,
|
|
559
|
-
should_block,
|
|
560
|
-
should_notify
|
|
561
|
-
};
|
|
562
|
-
|
|
563
|
-
export {
|
|
564
|
-
hook_decision,
|
|
565
|
-
time_batch_guard
|
|
566
|
-
};
|