token-goat 2.9.30 → 2.9.31
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.md +24 -7
- package/SECURITY.md +10 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/native/linux-arm64/tg-hook +0 -0
- package/dist/native/linux-x64/tg-hook +0 -0
- package/dist/native/win32-arm64/tg-hook.exe +0 -0
- package/dist/native/win32-x64/tg-hook.exe +0 -0
- package/dist/{token-goat-chunk-QSBRTGM2.mjs → token-goat-chunk-25TRAWET.mjs} +17 -7
- package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
- package/dist/{token-goat-chunk-IVKIZWAB.mjs → token-goat-chunk-2M7E4PF7.mjs} +41 -12
- package/dist/{token-goat-chunk-SMVRN2HU.mjs → token-goat-chunk-2UPZGKKY.mjs} +2 -2
- package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
- package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
- package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
- package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
- package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
- package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
- package/dist/{token-goat-chunk-KWPNJBDH.mjs → token-goat-chunk-4GILLLWY.mjs} +7 -4
- package/dist/{token-goat-chunk-67TQJ76B.mjs → token-goat-chunk-4NAPX7BA.mjs} +36 -3
- package/dist/{token-goat-chunk-PU7V3FD6.mjs → token-goat-chunk-4SC7UJYV.mjs} +3354 -2553
- package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
- package/dist/{token-goat-chunk-AFLYLHDH.mjs → token-goat-chunk-4ZBFWLXF.mjs} +283 -427
- package/dist/{token-goat-chunk-JDWCRD6M.mjs → token-goat-chunk-57BIAXJL.mjs} +73 -40
- package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
- package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
- package/dist/token-goat-chunk-646E6U44.mjs +398 -0
- package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
- package/dist/{token-goat-chunk-JN4XMLSD.mjs → token-goat-chunk-6DG6HWP3.mjs} +8 -2
- package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
- package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
- package/dist/{token-goat-chunk-VPBBTSJR.mjs → token-goat-chunk-76FGDLRO.mjs} +262 -255
- package/dist/{token-goat-chunk-7IN2MKDS.mjs → token-goat-chunk-7EZTZOMC.mjs} +121 -289
- package/dist/{token-goat-chunk-OJBNYTJP.mjs → token-goat-chunk-7MAOA6X4.mjs} +640 -80
- package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
- package/dist/{token-goat-chunk-PD5VKH46.mjs → token-goat-chunk-AUNGYYQX.mjs} +2 -2
- package/dist/{token-goat-chunk-HG45AF2B.mjs → token-goat-chunk-AUQYRMMH.mjs} +794 -37
- package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
- package/dist/{token-goat-chunk-A3CK6N5Z.mjs → token-goat-chunk-BA4HI6BW.mjs} +1309 -110
- package/dist/{token-goat-chunk-JB6QN6VF.mjs → token-goat-chunk-BFCWY73P.mjs} +59 -23
- package/dist/{token-goat-chunk-B45VMIIH.mjs → token-goat-chunk-BWGFUZZE.mjs} +7 -5
- package/dist/{token-goat-chunk-P4QMM4WK.mjs → token-goat-chunk-C75NA7PL.mjs} +50 -23
- package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
- package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
- package/dist/{token-goat-chunk-H2PHHGM5.mjs → token-goat-chunk-CIMQ2BB3.mjs} +57 -12
- package/dist/{token-goat-chunk-N2NMER56.mjs → token-goat-chunk-CJLS3CDL.mjs} +46 -4
- package/dist/{token-goat-chunk-VES7EL7O.mjs → token-goat-chunk-CO3UYX6G.mjs} +1 -1
- package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
- package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
- package/dist/{token-goat-chunk-4LCCNRTG.mjs → token-goat-chunk-CVCEVUGK.mjs} +8 -6
- package/dist/{token-goat-chunk-B2RZZCSS.mjs → token-goat-chunk-CXHOFN7R.mjs} +37 -20
- package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
- package/dist/{token-goat-chunk-APGZXSPS.mjs → token-goat-chunk-DGS2LVNA.mjs} +47 -30
- package/dist/{token-goat-chunk-54K3EUV3.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
- package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
- package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
- package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
- package/dist/{token-goat-chunk-5BCIJXMO.mjs → token-goat-chunk-EELTBKDM.mjs} +14 -10
- package/dist/{token-goat-chunk-W3QCJS6G.mjs → token-goat-chunk-F4HYL64R.mjs} +8 -6
- package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
- package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
- package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
- package/dist/{token-goat-chunk-C63JQV5K.mjs → token-goat-chunk-GL3ETKSC.mjs} +233 -15
- package/dist/token-goat-chunk-GVB2MUST.mjs +1298 -0
- package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
- package/dist/{token-goat-chunk-ZEJVMUQH.mjs → token-goat-chunk-HLPW63A7.mjs} +2 -2
- package/dist/{token-goat-chunk-GOLEOXZP.mjs → token-goat-chunk-HU4TORC5.mjs} +44 -26
- package/dist/{token-goat-chunk-Z57YODA2.mjs → token-goat-chunk-I7VKZZAW.mjs} +2 -2
- package/dist/{token-goat-chunk-NYKZLXMK.mjs → token-goat-chunk-IA6XSPE3.mjs} +6 -6
- package/dist/{token-goat-chunk-E3OQX2XT.mjs → token-goat-chunk-IAGXMHIK.mjs} +81 -42
- package/dist/{token-goat-chunk-HYBFA5X3.mjs → token-goat-chunk-IK2DRMFX.mjs} +24 -68
- package/dist/{token-goat-chunk-COBQGL5S.mjs → token-goat-chunk-INNPTRUX.mjs} +249 -299
- package/dist/{token-goat-chunk-7NADEDKJ.mjs → token-goat-chunk-JJ5BX4F4.mjs} +6 -1
- package/dist/{token-goat-chunk-PEPTHRFF.mjs → token-goat-chunk-JVFSHVFJ.mjs} +6 -6
- package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
- package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
- package/dist/{token-goat-chunk-Q5VTGRH7.mjs → token-goat-chunk-LCNQ2CNN.mjs} +55 -319
- package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
- package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
- package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
- package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
- package/dist/{token-goat-chunk-T4FK7VOV.mjs → token-goat-chunk-MHX7XCC3.mjs} +2 -1
- package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
- package/dist/{token-goat-chunk-LOBGHXPB.mjs → token-goat-chunk-N5MMR2IW.mjs} +1 -1
- package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
- package/dist/{token-goat-chunk-RHXKCZX3.mjs → token-goat-chunk-NISNMD7T.mjs} +2182 -2959
- package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
- package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
- package/dist/{token-goat-chunk-KQNZDCBD.mjs → token-goat-chunk-NSNSPPBG.mjs} +25 -3
- package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
- package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
- package/dist/{token-goat-chunk-JTQQGXZH.mjs → token-goat-chunk-ODBT2USM.mjs} +124 -57
- package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
- package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
- package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
- package/dist/{token-goat-chunk-DZX2YDPT.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -2
- package/dist/{token-goat-chunk-QCLDAQTS.mjs → token-goat-chunk-P6HQSWQ3.mjs} +50 -53
- package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
- package/dist/{token-goat-chunk-7BXSNBY5.mjs → token-goat-chunk-PFWIMH2E.mjs} +23 -15
- package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
- package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
- package/dist/{token-goat-chunk-GFBSN7BD.mjs → token-goat-chunk-PX5PQWTY.mjs} +22 -250
- package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
- package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
- package/dist/{token-goat-chunk-FBNQNSJK.mjs → token-goat-chunk-QH7YVYOY.mjs} +2198 -2782
- package/dist/{token-goat-chunk-64FBPDTK.mjs → token-goat-chunk-QLMUHEPB.mjs} +12 -9
- package/dist/{token-goat-chunk-RZRTDST7.mjs → token-goat-chunk-QQOJIHL3.mjs} +37 -11
- package/dist/{token-goat-chunk-XKI4SEMX.mjs → token-goat-chunk-QQTWJY2O.mjs} +19 -0
- package/dist/{token-goat-chunk-U4N3BN2W.mjs → token-goat-chunk-QYHO5CPH.mjs} +3 -2
- package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
- package/dist/{token-goat-chunk-ETBHVDB6.mjs → token-goat-chunk-RSLPOBKQ.mjs} +22 -11
- package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
- package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
- package/dist/{token-goat-chunk-4JJS54TR.mjs → token-goat-chunk-SOAFZNNZ.mjs} +161 -38
- package/dist/{token-goat-chunk-664RTTUV.mjs → token-goat-chunk-SRTHT7KV.mjs} +21 -16
- package/dist/{token-goat-chunk-4FVIAHSI.mjs → token-goat-chunk-T5P5ACNQ.mjs} +7 -6
- package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
- package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
- package/dist/{token-goat-chunk-COTXZHTS.mjs → token-goat-chunk-TM6MC754.mjs} +4 -3
- package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
- package/dist/{token-goat-chunk-3CHUNJ2O.mjs → token-goat-chunk-U2KSB4SG.mjs} +8 -5
- package/dist/{token-goat-chunk-3Z5S4KGM.mjs → token-goat-chunk-U4WHMG6Y.mjs} +29 -49
- package/dist/{token-goat-chunk-PY533T7F.mjs → token-goat-chunk-UGJHGR5A.mjs} +21 -15
- package/dist/{token-goat-chunk-CYCEYAEO.mjs → token-goat-chunk-UOUDVA5U.mjs} +1 -1
- package/dist/{token-goat-chunk-JDHE26RP.mjs → token-goat-chunk-URRJ33GR.mjs} +16 -5
- package/dist/{token-goat-chunk-56EIMS3E.mjs → token-goat-chunk-UZOROKIS.mjs} +23 -17
- package/dist/{token-goat-chunk-CZ3LUXYZ.mjs → token-goat-chunk-VIHGGGEI.mjs} +427 -308
- package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
- package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
- package/dist/{token-goat-chunk-YARZFCZS.mjs → token-goat-chunk-VWZA2H4P.mjs} +62 -53
- package/dist/{token-goat-chunk-SQSSNQPE.mjs → token-goat-chunk-VXEXMJDL.mjs} +3979 -4745
- package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
- package/dist/{token-goat-chunk-SJHWVNDQ.mjs → token-goat-chunk-WDH44VAU.mjs} +7 -4
- package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
- package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
- package/dist/{token-goat-chunk-FZ3NEW5O.mjs → token-goat-chunk-XLRBNZCC.mjs} +13 -8
- package/dist/{token-goat-chunk-Z44YO3QZ.mjs → token-goat-chunk-XRKUX6CM.mjs} +1 -1
- package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
- package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
- package/dist/{token-goat-chunk-WY3L4DVT.mjs → token-goat-chunk-Y2ZTQOCL.mjs} +13 -8
- package/dist/{token-goat-chunk-UQ5UK2T7.mjs → token-goat-chunk-YB4VMGK2.mjs} +1 -1
- package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
- package/dist/{token-goat-chunk-ZQSJMO2R.mjs → token-goat-chunk-YHVDKQBR.mjs} +105 -105
- package/dist/{token-goat-chunk-H2K3QP6H.mjs → token-goat-chunk-YJB5XLWI.mjs} +8 -6
- package/dist/{token-goat-chunk-ZCDTCVIS.mjs → token-goat-chunk-YKB6AQG3.mjs} +5 -2
- package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
- package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
- package/dist/{token-goat-chunk-HOJLCGDP.mjs → token-goat-chunk-YY6AVUFL.mjs} +2033 -2251
- package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
- package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
- package/dist/token-goat-hook-client.cjs +1 -1
- package/dist/token-goat-hook-client.mjs +3 -3
- package/dist/token-goat-hook.mjs +67 -38
- package/dist/token-goat.core.mjs +4 -4
- package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
- package/docs/cli.md +40 -21
- package/docs/install.md +19 -9
- package/docs/security.md +5 -3
- package/package.json +2 -1
- package/dist/token-goat-chunk-5KDMCMF2.mjs +0 -362
- package/dist/token-goat-chunk-6QMAS7AB.mjs +0 -42
- package/dist/token-goat-chunk-7F2UBPD3.mjs +0 -397
- package/dist/token-goat-chunk-ARDNEC2U.mjs +0 -248
- package/dist/token-goat-chunk-ATCPY7EQ.mjs +0 -134
- package/dist/token-goat-chunk-EFHMMIGP.mjs +0 -68
- package/dist/token-goat-chunk-IVALLT3S.mjs +0 -48
- package/dist/token-goat-chunk-JDU3EXSU.mjs +0 -65
- package/dist/token-goat-chunk-MKPF4CL5.mjs +0 -37
- package/dist/token-goat-chunk-RC35RBUL.mjs +0 -312
- package/dist/token-goat-chunk-USILZ3T3.mjs +0 -53
- package/dist/token-goat-chunk-VL3YIFHZ.mjs +0 -2975
- package/dist/token-goat-chunk-XU4P6Z24.mjs +0 -133
- package/dist/token-goat-chunk-Y776AENC.mjs +0 -1597
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
errorPrefix
|
|
5
|
+
} from "./token-goat-chunk-JVFSHVFJ.mjs";
|
|
6
|
+
import {
|
|
7
|
+
stripLeadingAssignments
|
|
8
|
+
} from "./token-goat-chunk-DGS2LVNA.mjs";
|
|
9
|
+
import "./token-goat-chunk-INNPTRUX.mjs";
|
|
10
|
+
import {
|
|
11
|
+
applyHintTracking,
|
|
12
|
+
uncorrelatedHint
|
|
13
|
+
} from "./token-goat-chunk-4SMRO4TO.mjs";
|
|
14
|
+
import {
|
|
15
|
+
sessionSidecarPath
|
|
16
|
+
} from "./token-goat-chunk-WBA5SKT4.mjs";
|
|
17
|
+
import "./token-goat-chunk-MNWKPRAL.mjs";
|
|
18
|
+
import {
|
|
19
|
+
sessionStateKey
|
|
20
|
+
} from "./token-goat-chunk-C75NA7PL.mjs";
|
|
21
|
+
import "./token-goat-chunk-P6VGNTQT.mjs";
|
|
22
|
+
import {
|
|
23
|
+
contextOutput,
|
|
24
|
+
getCwd
|
|
25
|
+
} from "./token-goat-chunk-76FGDLRO.mjs";
|
|
26
|
+
import "./token-goat-chunk-GL3ETKSC.mjs";
|
|
27
|
+
import "./token-goat-chunk-U4WHMG6Y.mjs";
|
|
28
|
+
import "./token-goat-chunk-GVB2MUST.mjs";
|
|
29
|
+
import "./token-goat-chunk-XB5KKOCG.mjs";
|
|
30
|
+
import "./token-goat-chunk-OUKDTVNU.mjs";
|
|
31
|
+
import "./token-goat-chunk-4GILLLWY.mjs";
|
|
32
|
+
import "./token-goat-chunk-BFCWY73P.mjs";
|
|
33
|
+
import "./token-goat-chunk-KGEFFSHD.mjs";
|
|
34
|
+
import "./token-goat-chunk-XX6O25RN.mjs";
|
|
35
|
+
import "./token-goat-chunk-HAVAOB3S.mjs";
|
|
36
|
+
import {
|
|
37
|
+
hasPreciseSecret,
|
|
38
|
+
redactSecrets
|
|
39
|
+
} from "./token-goat-chunk-T5P5ACNQ.mjs";
|
|
40
|
+
import "./token-goat-chunk-7EZTZOMC.mjs";
|
|
41
|
+
import "./token-goat-chunk-QYHO5CPH.mjs";
|
|
42
|
+
import {
|
|
43
|
+
projectHash,
|
|
44
|
+
resolveProjectRoot
|
|
45
|
+
} from "./token-goat-chunk-4GBVPH3D.mjs";
|
|
46
|
+
import {
|
|
47
|
+
registerReset
|
|
48
|
+
} from "./token-goat-chunk-YZAAZU2S.mjs";
|
|
49
|
+
import "./token-goat-chunk-IVE6U7KV.mjs";
|
|
50
|
+
import {
|
|
51
|
+
atomicWriteText,
|
|
52
|
+
ensureDirSync
|
|
53
|
+
} from "./token-goat-chunk-HU4TORC5.mjs";
|
|
54
|
+
import {
|
|
55
|
+
fencedCommand
|
|
56
|
+
} from "./token-goat-chunk-GGGG7RWB.mjs";
|
|
57
|
+
import "./token-goat-chunk-AM5V6GSX.mjs";
|
|
58
|
+
import {
|
|
59
|
+
displaySafeText
|
|
60
|
+
} from "./token-goat-chunk-FNFBKLRD.mjs";
|
|
61
|
+
import {
|
|
62
|
+
dataDir
|
|
63
|
+
} from "./token-goat-chunk-CO3UYX6G.mjs";
|
|
64
|
+
import {
|
|
65
|
+
init_define_import_meta_env
|
|
66
|
+
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
67
|
+
|
|
68
|
+
// src/recovery_pairs.ts
|
|
69
|
+
init_define_import_meta_env();
|
|
70
|
+
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
71
|
+
import { linkSync, lstatSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
72
|
+
import { dirname, isAbsolute, join, posix, relative, sep } from "node:path";
|
|
73
|
+
|
|
74
|
+
// src/recovery_fix_policy.ts
|
|
75
|
+
init_define_import_meta_env();
|
|
76
|
+
var SAFE_FLAG_NAMES = [
|
|
77
|
+
"--ci",
|
|
78
|
+
"--ignore-scripts",
|
|
79
|
+
"--frozen-lockfile",
|
|
80
|
+
"--immutable",
|
|
81
|
+
"--no-audit",
|
|
82
|
+
"--no-fund",
|
|
83
|
+
"--silent",
|
|
84
|
+
"--quiet",
|
|
85
|
+
"--verbose",
|
|
86
|
+
"--offline",
|
|
87
|
+
"--prefer-offline",
|
|
88
|
+
"--production",
|
|
89
|
+
"--legacy-peer-deps",
|
|
90
|
+
"--if-present",
|
|
91
|
+
"--release",
|
|
92
|
+
"--locked",
|
|
93
|
+
"--frozen",
|
|
94
|
+
"--all-features",
|
|
95
|
+
"--all-targets",
|
|
96
|
+
"--no-default-features",
|
|
97
|
+
"--workspace",
|
|
98
|
+
"--lib",
|
|
99
|
+
"--bins",
|
|
100
|
+
"--tests",
|
|
101
|
+
"--dev",
|
|
102
|
+
"--no-dev",
|
|
103
|
+
"--all-extras",
|
|
104
|
+
"--upgrade",
|
|
105
|
+
"--no-cache-dir",
|
|
106
|
+
"--no-cache",
|
|
107
|
+
"--no-deps",
|
|
108
|
+
"--no-build-isolation",
|
|
109
|
+
"--no-install-project",
|
|
110
|
+
"--no-fail-fast",
|
|
111
|
+
"--fail-fast",
|
|
112
|
+
"--info",
|
|
113
|
+
"--stacktrace",
|
|
114
|
+
"--no-daemon",
|
|
115
|
+
"--batch-mode",
|
|
116
|
+
"--no-restore",
|
|
117
|
+
"--no-build",
|
|
118
|
+
"--nologo",
|
|
119
|
+
"-q",
|
|
120
|
+
"-vvv",
|
|
121
|
+
"-vv",
|
|
122
|
+
"-v",
|
|
123
|
+
"-B",
|
|
124
|
+
"-U",
|
|
125
|
+
"-o",
|
|
126
|
+
"-e",
|
|
127
|
+
"-race",
|
|
128
|
+
"-short",
|
|
129
|
+
"-json",
|
|
130
|
+
"-DskipTests"
|
|
131
|
+
];
|
|
132
|
+
var SAFE_FLAG_VALUES = ["-count", "-parallel", "--jobs", "--concurrency", "--maxsockets"];
|
|
133
|
+
var FLAG = String.raw`(?:\s+(?:(?:${SAFE_FLAG_NAMES.join("|")})(?:=(?:true|false|\d{1,5}))?|(?:${SAFE_FLAG_VALUES.join("|")})=\d{1,5}|-j\d{1,3}|--console=plain)(?=\s|$))`;
|
|
134
|
+
var NO_DOTDOT = String.raw`(?![\w./-]*?(?<![\w.-])\.\.(?![\w.-]))`;
|
|
135
|
+
var PATH_ARG = String.raw`(?![/-])${NO_DOTDOT}[\w./-]+`;
|
|
136
|
+
var PIP_ARGS = String.raw`(?:${FLAG}|\s+-r\s+${PATH_ARG}|\s+-e\s+(?=\.)${PATH_ARG}|\s+\.)*`;
|
|
137
|
+
var FIX_TASK_VERBS = ["build", "tests?", "lint", "typecheck", "check", "setup", "install", "bootstrap", "generate", "gen", "codegen", "compile"];
|
|
138
|
+
var UNSAFE_TASK_WORDS = ["deploy", "publish", "release", "reset", "drop", "migrat", "seed", "push", "upload", "prune", "wipe", "destroy", "clean", "purge", "delete", "rollback"];
|
|
139
|
+
var TASK = String.raw`(?!\S*(?:${UNSAFE_TASK_WORDS.join("|")}))(?:${FIX_TASK_VERBS.join("|")})(?:[:_-][\w:.-]*)?(?=\s|$)`;
|
|
140
|
+
var FIX_VERB_ALLOWLIST = [
|
|
141
|
+
{ name: "js package manager install, build or test", pattern: new RegExp(String.raw`^(?:npm|pnpm|yarn|bun)\s+(?:ci|install|i|test|t|build|rebuild)${FLAG}*$`), example: "npm ci" },
|
|
142
|
+
{ name: "js package manager script", pattern: new RegExp(String.raw`^(?:npm|pnpm|yarn|bun)\s+run\s+${TASK}${FLAG}*$`), example: "npm run build" },
|
|
143
|
+
{ name: "pip install from a manifest", pattern: new RegExp(String.raw`^(?:python3?\s+-m\s+)?pip3?\s+install${PIP_ARGS}$`), example: "pip install -r requirements.txt" },
|
|
144
|
+
{ name: "uv pip install from a manifest", pattern: new RegExp(String.raw`^uv\s+pip\s+install${PIP_ARGS}$`), example: "uv pip install -e ." },
|
|
145
|
+
{ name: "python environment sync", pattern: new RegExp(String.raw`^(?:uv\s+sync|poetry\s+install|pipenv\s+(?:install|sync))${FLAG}*$`), example: "uv sync" },
|
|
146
|
+
{ name: "cargo", pattern: new RegExp(String.raw`^cargo\s+(?:build|test|fetch|check)${FLAG}*$`), example: "cargo fetch" },
|
|
147
|
+
{ name: "go build and test", pattern: new RegExp(String.raw`^go\s+(?:build|test|vet)(?:${FLAG}|\s+(?=\./)${PATH_ARG})*$`), example: "go test ./..." },
|
|
148
|
+
{ name: "go modules", pattern: new RegExp(String.raw`^go\s+mod\s+(?:download|tidy|vendor)${FLAG}*$`), example: "go mod download" },
|
|
149
|
+
{ name: "make target", pattern: new RegExp(String.raw`^make(?:\s+${TASK}|${FLAG})*$`), example: "make setup" },
|
|
150
|
+
{ name: "virtualenv activation", pattern: new RegExp(String.raw`^(?:source|\.)\s+(?=${PATH_ARG}$)[\w./-]*activate(?:\.\w+)?$`), example: "source .venv/bin/activate" },
|
|
151
|
+
{ name: "bundler", pattern: new RegExp(String.raw`^bundle\s+install${FLAG}*$`), example: "bundle install" },
|
|
152
|
+
{ name: "dotnet", pattern: new RegExp(String.raw`^dotnet\s+(?:restore|build|test)${FLAG}*$`), example: "dotnet restore" },
|
|
153
|
+
{ name: "maven and gradle", pattern: new RegExp(String.raw`^(?:\./)?(?:mvnw?|gradlew?)(?:\s+(?:clean|install|compile|test|package|verify|build|assemble)|${FLAG})+$`), example: "mvn clean install" },
|
|
154
|
+
{ name: "cd into a directory", pattern: new RegExp(String.raw`^cd\s+${PATH_ARG}$`), example: "cd services/api" }
|
|
155
|
+
];
|
|
156
|
+
var RERUN_COMMAND = /^(?:python3?\s+-m\s+)?(?:pytest|vitest|jest|mocha|tsc|eslint|ruff|mypy|flake8)(?:\s+\S.*)?$|^ls(?:\s+[\w./-]+)*$/;
|
|
157
|
+
var CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
|
|
158
|
+
var FORBIDDEN_IN_PART = /[|;<>&$`]|\b(?:curl|wget|sudo|iex|eval|base64)\b|Invoke-Expression/i;
|
|
159
|
+
var SOURCE_FLAG = /(?:^|\s)(?:--?(?:index-url|extra-index-url|default-index|index|find-links|registry|trusted-host|proxy|repository|repository-url|file|makefile)|-[ifc])(?:=|\s|$)/i;
|
|
160
|
+
var SAFE_ENV_NAMES = /* @__PURE__ */ new Set(["CI", "NODE_ENV", "FORCE_COLOR", "NO_COLOR", "TZ", "LANG", "LC_ALL", "RUST_BACKTRACE", "DEBUG"]);
|
|
161
|
+
var SAFE_ENV_VALUE = /^[\w.,:-]{0,32}$/;
|
|
162
|
+
function setsUnsafeVariable(word) {
|
|
163
|
+
if (!word.includes("=")) return false;
|
|
164
|
+
const assign = /^([A-Za-z_]\w*)=(.*)$/.exec(word);
|
|
165
|
+
return assign === null || !SAFE_ENV_NAMES.has(assign[1] ?? "") || !SAFE_ENV_VALUE.test(assign[2] ?? "");
|
|
166
|
+
}
|
|
167
|
+
var SAFE_WRAPPER_FLAGS = /* @__PURE__ */ new Set(["-y", "--yes", "--no-install"]);
|
|
168
|
+
var WRAPPER_WORDS = /* @__PURE__ */ new Set(["env", "npx", "bunx", "uv", "run", "poetry", "pipenv", "pnpm", "exec"]);
|
|
169
|
+
function peeledWordIsSafe(word) {
|
|
170
|
+
if (word === "" || SAFE_WRAPPER_FLAGS.has(word) || WRAPPER_WORDS.has(word)) return true;
|
|
171
|
+
return /^[A-Za-z_]\w*=/.test(word) && !setsUnsafeVariable(word);
|
|
172
|
+
}
|
|
173
|
+
function peelPart(segment, wrappers) {
|
|
174
|
+
const squeezed = segment.replace(/\s+/g, " ").trim();
|
|
175
|
+
let core = segment;
|
|
176
|
+
for (let peel = 0; peel < 4; peel++) {
|
|
177
|
+
const next = stripLeadingAssignments(core).replace(/\s+/g, " ").trim().replace(wrappers, "");
|
|
178
|
+
if (next === core) break;
|
|
179
|
+
core = next;
|
|
180
|
+
}
|
|
181
|
+
core = core.replace(/\s+/g, " ").trim();
|
|
182
|
+
if (!squeezed.endsWith(core)) return { core, envIsSafe: false };
|
|
183
|
+
return { core, envIsSafe: squeezed.slice(0, squeezed.length - core.length).split(" ").every(peeledWordIsSafe) };
|
|
184
|
+
}
|
|
185
|
+
var RERUN_PLACEHOLDER = "(the same command)";
|
|
186
|
+
var SAFE_LEAD = /^(?:(?:npx\s+(?:(?:-y|--yes|--no-install)\s+)*|bunx\s+|uv\s+run\s+|poetry\s+run\s+|pipenv\s+run\s+|pnpm\s+exec\s+))?$/;
|
|
187
|
+
var JS_RUNNER_CORE = /^(?:vitest|jest|mocha|tsc|eslint)(?:\s|$)/;
|
|
188
|
+
function leadFitsCore(lead, core) {
|
|
189
|
+
return !/(?:^|\s)(?:npx|bunx|pnpm\s+exec)(?:\s|$)/.test(lead) || JS_RUNNER_CORE.test(core);
|
|
190
|
+
}
|
|
191
|
+
function rerunIsAllowed(core) {
|
|
192
|
+
if (FORBIDDEN_IN_PART.test(core) || SOURCE_FLAG.test(core)) return false;
|
|
193
|
+
return RERUN_COMMAND.test(core) || FIX_VERB_ALLOWLIST.some((verb) => verb.pattern.test(core));
|
|
194
|
+
}
|
|
195
|
+
var MAKE_ENV_OVERRIDE = /^make\b.*\s(?:-e|--environment-overrides)(?=\s|$)/;
|
|
196
|
+
function fixIsAllowed(fix, wrappers) {
|
|
197
|
+
if (CONTROL_CHARS.test(fix)) return false;
|
|
198
|
+
for (const part of fix.split(" && ")) {
|
|
199
|
+
if (part === "" || FORBIDDEN_IN_PART.test(part) || SOURCE_FLAG.test(part)) return false;
|
|
200
|
+
if (part.endsWith(RERUN_PLACEHOLDER)) {
|
|
201
|
+
if (!SAFE_LEAD.test(part.slice(0, part.length - RERUN_PLACEHOLDER.length))) return false;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const { core, envIsSafe } = peelPart(part, wrappers);
|
|
205
|
+
if (!envIsSafe || MAKE_ENV_OVERRIDE.test(core) || !FIX_VERB_ALLOWLIST.some((verb) => verb.pattern.test(core))) return false;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
var CREDENTIAL_PATTERNS = [
|
|
210
|
+
/(?:^|\s)--?(?:password|passwd|passphrase|pass|pwd|pw|token|api[-_]?key|secret|access[-_]?key|client[-_]?secret|auth|cookie|credentials?)(?:=|\s+)\S/i,
|
|
211
|
+
/(?:^|\s)(?:-u|--user)\s+\S*:\S/,
|
|
212
|
+
/\b(?:mysql|mysqldump|mysqladmin|psql|pg_dump|pg_restore|mongo\w*|redis-cli|sqlcmd)\b[^|;&]*\s-(?:p\S|W\s+\S)/i,
|
|
213
|
+
/(?:^|[\s;&|])(?:[A-Za-z_]\w*)?(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|PASSPHRASE|PASS|PWD|PAT|CRED|CREDENTIALS?|AUTH)=/i,
|
|
214
|
+
/\bsshpass\b/i,
|
|
215
|
+
/\bopenssl\b[^|;&]*\s-(?:k|kfile|pass|passin|passout)\s+\S/i,
|
|
216
|
+
/(?:^|\s)(?:-H|--header)[\s=]+["']?[\w-]*(?:auth|token|key|secret|cookie|session|passw)[\w-]*\s*:\s*\S/i,
|
|
217
|
+
/:\/\/[^\s/:@]+:[^\s/@]+@/,
|
|
218
|
+
/\b(?:authorization|bearer)\b/i
|
|
219
|
+
];
|
|
220
|
+
function carriesCredential(text) {
|
|
221
|
+
return redactSecrets(text).text !== text || hasPreciseSecret(text) || CREDENTIAL_PATTERNS.some((pattern) => pattern.test(text));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/recovery_pairs.ts
|
|
225
|
+
var RECOVERY_WINDOW = 6;
|
|
226
|
+
var MAX_OPEN = 4;
|
|
227
|
+
var MAX_PAIRS = 50;
|
|
228
|
+
var PAIR_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
229
|
+
var MAX_FIX_CHARS = 200;
|
|
230
|
+
var MAX_COMMAND_CHARS = 400;
|
|
231
|
+
var MAX_FIX_COMMANDS = 2;
|
|
232
|
+
var PENDING_SUFFIX = ".recovery-pending";
|
|
233
|
+
var STORE_VERSION = 4;
|
|
234
|
+
var PENDING_VERSION = 4;
|
|
235
|
+
var OTHER_STEP = "<other>";
|
|
236
|
+
var MIN_SESSIONS = 2;
|
|
237
|
+
var MAX_SESSIONS = 8;
|
|
238
|
+
var DIAGNOSTIC_WORDS = /* @__PURE__ */ new Set(["ls", "dir", "cat", "pwd", "which", "where", "echo", "head", "tail", "grep", "rg", "find", "type", "wc", "stat", "file", "cd", "test", "true", "date", "whoami", "env", "printenv"]);
|
|
239
|
+
var DIAGNOSTIC_GIT = /^git\s+(?:status|log|diff|show|branch|remote|rev-parse)\b/;
|
|
240
|
+
var VERSION_PROBE = /\s(?:--version|-v|-V|version)\s*$/;
|
|
241
|
+
var DESTRUCTIVE = /\brm\s+-[a-z]*[rf]|\bgit\s+reset\s+--hard\b|\bgit\s+clean\s+-[a-z]*f|\bgit\s+push\b[^|;&]*(?:--force|\s-f\b)|\b(?:drop|truncate)\s+(?:table|database|schema)\b|\bRemove-Item\b[^|;&]*-Recurse|\bdel\s+\/[sq]|\bformat\s+[a-z]:|\bmkfs\b|\bdd\s+if=/i;
|
|
242
|
+
var UNFENCEABLE = /[`\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
|
|
243
|
+
var WRAPPER = /^(?:env\s+(?:(?:-i|--ignore-environment)\s+)*|npx\s+(?:(?:-y|--yes|--no-install)\s+)*|bunx\s+|uv\s+run\s+|poetry\s+run\s+|pipenv\s+run\s+|pnpm\s+exec\s+)/;
|
|
244
|
+
function squeeze(text) {
|
|
245
|
+
return text.replace(/\s+/g, " ").trim();
|
|
246
|
+
}
|
|
247
|
+
function isLearnableCommand(command) {
|
|
248
|
+
const text = command.trim();
|
|
249
|
+
if (text === "" || text.length > MAX_COMMAND_CHARS) return false;
|
|
250
|
+
if (UNFENCEABLE.test(text)) return false;
|
|
251
|
+
if (/token-goat/i.test(text) || DESTRUCTIVE.test(text)) return false;
|
|
252
|
+
return !carriesCredential(text);
|
|
253
|
+
}
|
|
254
|
+
function splitCommandPrefix(command) {
|
|
255
|
+
const text = squeeze(command);
|
|
256
|
+
let quote = null;
|
|
257
|
+
let cut = 0;
|
|
258
|
+
for (let i = 0; i < text.length; i++) {
|
|
259
|
+
const ch = text[i] ?? "";
|
|
260
|
+
if (quote !== null) {
|
|
261
|
+
if (ch === quote) quote = null;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (ch === '"' || ch === "'") quote = ch;
|
|
265
|
+
else if (ch === ";") cut = i + 1;
|
|
266
|
+
else if (ch === "&" && text[i + 1] === "&" && text[i - 1] !== "&") {
|
|
267
|
+
cut = i + 2;
|
|
268
|
+
i += 1;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const prefix = text.slice(0, cut).trim();
|
|
272
|
+
const run = text.slice(cut).trim();
|
|
273
|
+
let core = run;
|
|
274
|
+
for (let peel = 0; peel < 4; peel++) {
|
|
275
|
+
const stripped = squeeze(stripLeadingAssignments(core));
|
|
276
|
+
const next = stripped.replace(WRAPPER, "");
|
|
277
|
+
if (next === core) break;
|
|
278
|
+
core = next;
|
|
279
|
+
}
|
|
280
|
+
return { prefix, run, core };
|
|
281
|
+
}
|
|
282
|
+
function isDiagnostic(command) {
|
|
283
|
+
const { core } = splitCommandPrefix(command);
|
|
284
|
+
if (DIAGNOSTIC_GIT.test(core) || VERSION_PROBE.test(` ${core}`)) return true;
|
|
285
|
+
const word = core.split(" ")[0] ?? "";
|
|
286
|
+
return DIAGNOSTIC_WORDS.has(word) && !/[>|]/.test(core);
|
|
287
|
+
}
|
|
288
|
+
function learnableFix(failed, success, between) {
|
|
289
|
+
if (![failed, ...between].every(isLearnableCommand)) return null;
|
|
290
|
+
const steps = between.flatMap((command) => {
|
|
291
|
+
const step = betweenStep(command);
|
|
292
|
+
return step === null ? [] : [step];
|
|
293
|
+
});
|
|
294
|
+
return learnFromDigest(digestFailed(failed), success, steps);
|
|
295
|
+
}
|
|
296
|
+
function digestKeyPath() {
|
|
297
|
+
return join(dataDir(), "recovery_pairs", "install.key");
|
|
298
|
+
}
|
|
299
|
+
var DIGEST_KEY_HEX = /^[0-9a-f]{64}$/;
|
|
300
|
+
var digestKeyCache;
|
|
301
|
+
registerReset(() => {
|
|
302
|
+
digestKeyCache = void 0;
|
|
303
|
+
});
|
|
304
|
+
function digestKey() {
|
|
305
|
+
const path = digestKeyPath();
|
|
306
|
+
if (digestKeyCache?.path === path) return digestKeyCache.key;
|
|
307
|
+
let key = readRegularKey(path);
|
|
308
|
+
if (key === null) {
|
|
309
|
+
const fresh = randomBytes(32).toString("hex");
|
|
310
|
+
key = installKey(path, fresh) ?? readRegularKey(path) ?? fresh;
|
|
311
|
+
}
|
|
312
|
+
digestKeyCache = { path, key };
|
|
313
|
+
return key;
|
|
314
|
+
}
|
|
315
|
+
function readRegularKey(path) {
|
|
316
|
+
try {
|
|
317
|
+
if (!lstatSync(path).isFile()) return null;
|
|
318
|
+
const key = readFileSync(path, "utf8").trim();
|
|
319
|
+
return DIGEST_KEY_HEX.test(key) ? key : null;
|
|
320
|
+
} catch {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function writeTempKey(path, key) {
|
|
325
|
+
for (let attempt = 0; ; attempt++) {
|
|
326
|
+
const temp = `${path}.${randomBytes(8).toString("hex")}.tmp`;
|
|
327
|
+
try {
|
|
328
|
+
writeFileSync(temp, key, { flag: "wx", mode: 384 });
|
|
329
|
+
return temp;
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (error.code !== "EEXIST" || attempt >= 3) throw error;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function installKey(path, key) {
|
|
336
|
+
let temp;
|
|
337
|
+
try {
|
|
338
|
+
ensureDirSync(dirname(path));
|
|
339
|
+
temp = writeTempKey(path, key);
|
|
340
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
341
|
+
const present = readRegularKey(path);
|
|
342
|
+
if (present !== null) return present;
|
|
343
|
+
rmSync(path, { recursive: true, force: true });
|
|
344
|
+
try {
|
|
345
|
+
linkSync(temp, path);
|
|
346
|
+
return readRegularKey(path);
|
|
347
|
+
} catch (error) {
|
|
348
|
+
const code = error.code;
|
|
349
|
+
if (code === "EEXIST") continue;
|
|
350
|
+
renameSync(temp, path);
|
|
351
|
+
return readRegularKey(path);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return readRegularKey(path);
|
|
355
|
+
} catch {
|
|
356
|
+
return null;
|
|
357
|
+
} finally {
|
|
358
|
+
if (temp !== void 0) rmSync(temp, { force: true });
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function digestOf(text) {
|
|
362
|
+
return createHmac("sha256", digestKey()).update(text).digest("hex");
|
|
363
|
+
}
|
|
364
|
+
function digestFailed(command) {
|
|
365
|
+
const { prefix, run, core } = splitCommandPrefix(command);
|
|
366
|
+
return { core: digestOf(core), prefix: digestOf(prefix), run: digestOf(run) };
|
|
367
|
+
}
|
|
368
|
+
function betweenStep(command) {
|
|
369
|
+
if (isDiagnostic(command)) return null;
|
|
370
|
+
const text = squeeze(command);
|
|
371
|
+
return text.length <= MAX_FIX_CHARS && !carriesCredential(text) && fixIsAllowed(text, WRAPPER) ? text : OTHER_STEP;
|
|
372
|
+
}
|
|
373
|
+
function rerunPart(success) {
|
|
374
|
+
if (!rerunIsAllowed(success.core) || !success.run.endsWith(success.core)) return null;
|
|
375
|
+
const lead = success.run.slice(0, success.run.length - success.core.length);
|
|
376
|
+
if (success.prefix === "" && lead === "") return null;
|
|
377
|
+
if (!leadFitsCore(lead, success.core)) return null;
|
|
378
|
+
return squeeze(`${success.prefix} ${lead}${RERUN_PLACEHOLDER}`);
|
|
379
|
+
}
|
|
380
|
+
function learnFromDigest(failed, success, steps) {
|
|
381
|
+
const s = splitCommandPrefix(success);
|
|
382
|
+
if (s.core === "" || digestOf(s.core) !== failed.core || !isLearnableCommand(success)) return null;
|
|
383
|
+
const wrapperDelta = digestOf(s.prefix) !== failed.prefix || digestOf(s.run) !== failed.run;
|
|
384
|
+
const parts = steps.slice(-MAX_FIX_COMMANDS);
|
|
385
|
+
if (wrapperDelta) {
|
|
386
|
+
const rerun = rerunPart(s);
|
|
387
|
+
if (rerun === null) return null;
|
|
388
|
+
parts.push(rerun);
|
|
389
|
+
}
|
|
390
|
+
if (parts.length === 0) return null;
|
|
391
|
+
const fix = parts.join(" && ");
|
|
392
|
+
return isReplayable(fix) ? fix : null;
|
|
393
|
+
}
|
|
394
|
+
function storePath(key) {
|
|
395
|
+
return join(dataDir(), "recovery_pairs", `${key}.json`);
|
|
396
|
+
}
|
|
397
|
+
function recoveryStorePath(key) {
|
|
398
|
+
return storePath(key);
|
|
399
|
+
}
|
|
400
|
+
function dropStore(key) {
|
|
401
|
+
try {
|
|
402
|
+
rmSync(storePath(key), { force: true });
|
|
403
|
+
} catch {
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function loadStore(key, now) {
|
|
407
|
+
try {
|
|
408
|
+
const parsed = JSON.parse(readFileSync(storePath(key), "utf8"));
|
|
409
|
+
if (parsed.version !== STORE_VERSION) {
|
|
410
|
+
dropStore(key);
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
const pairs = parsed.pairs;
|
|
414
|
+
if (!Array.isArray(pairs)) return [];
|
|
415
|
+
const kept = pairs.filter((p) => {
|
|
416
|
+
const o = p;
|
|
417
|
+
return o !== null && typeof o === "object" && typeof o.signature === "string" && typeof o.commandShape === "string" && typeof o.fix === "string" && typeof o.count === "number" && typeof o.lastSeen === "number" && typeof o.helped === "number" && typeof o.hurt === "number" && now - o.lastSeen <= PAIR_TTL_MS;
|
|
418
|
+
}).map((p) => ({ ...p, sessions: Array.isArray(p.sessions) ? p.sessions.filter((s) => typeof s === "string") : [] }));
|
|
419
|
+
if (kept.length === 0) dropStore(key);
|
|
420
|
+
return kept;
|
|
421
|
+
} catch {
|
|
422
|
+
return [];
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function saveStore(key, pairs) {
|
|
426
|
+
try {
|
|
427
|
+
const kept = [...pairs].sort((a, b) => b.lastSeen - a.lastSeen).slice(0, MAX_PAIRS);
|
|
428
|
+
if (kept.length === 0) {
|
|
429
|
+
dropStore(key);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const target = storePath(key);
|
|
433
|
+
ensureDirSync(dirname(target));
|
|
434
|
+
atomicWriteText(target, JSON.stringify({ version: STORE_VERSION, pairs: kept }));
|
|
435
|
+
} catch {
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function isRetired(pair) {
|
|
439
|
+
return pair.hurt >= 2 && pair.hurt > pair.helped;
|
|
440
|
+
}
|
|
441
|
+
function matches(pair, signature, shape) {
|
|
442
|
+
return pair.signature === signature && pair.commandShape === shape;
|
|
443
|
+
}
|
|
444
|
+
function isReplayable(fix) {
|
|
445
|
+
return fix.length <= MAX_FIX_CHARS && !carriesCredential(fix) && fixIsAllowed(fix, WRAPPER);
|
|
446
|
+
}
|
|
447
|
+
function placeholderLeadFits(fix, core) {
|
|
448
|
+
const last = fix.split(" && ").pop() ?? "";
|
|
449
|
+
return !last.endsWith(RERUN_PLACEHOLDER) || leadFitsCore(last.slice(0, last.length - RERUN_PLACEHOLDER.length), core);
|
|
450
|
+
}
|
|
451
|
+
function isOffered(pair, offered, signature, shape) {
|
|
452
|
+
return pair.fix === offered.fix && matches(pair, signature, shape);
|
|
453
|
+
}
|
|
454
|
+
function sessionTag(event) {
|
|
455
|
+
return createHash("sha256").update(sessionStateKey(event)).digest("hex").slice(0, 12);
|
|
456
|
+
}
|
|
457
|
+
function addSession(pair, tag) {
|
|
458
|
+
if (!pair.sessions.includes(tag)) pair.sessions = [...pair.sessions, tag].slice(-MAX_SESSIONS);
|
|
459
|
+
}
|
|
460
|
+
function recoveryProjectKey(cwd) {
|
|
461
|
+
try {
|
|
462
|
+
return projectHash(resolveProjectRoot(cwd === void 0 ? void 0 : { project: cwd }));
|
|
463
|
+
} catch {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function loadRecoveryPairs(cwd) {
|
|
468
|
+
const key = recoveryProjectKey(cwd);
|
|
469
|
+
return key === null ? [] : loadStore(key, Date.now());
|
|
470
|
+
}
|
|
471
|
+
function pendingPath(event) {
|
|
472
|
+
return event.sessionId ? sessionSidecarPath(sessionStateKey(event), PENDING_SUFFIX) : null;
|
|
473
|
+
}
|
|
474
|
+
function isOpenPair(value) {
|
|
475
|
+
const o = value;
|
|
476
|
+
return o !== null && typeof o === "object" && typeof o.key === "string" && typeof o.shape === "string" && typeof o.failedPrefix === "string" && typeof o.failedRun === "string" && typeof o.signature === "string" && typeof o.calls === "number" && Array.isArray(o.between) && o.between.every((step) => typeof step === "string");
|
|
477
|
+
}
|
|
478
|
+
function readPending(target) {
|
|
479
|
+
try {
|
|
480
|
+
const parsed = JSON.parse(readFileSync(target, "utf8"));
|
|
481
|
+
if (parsed.version !== PENDING_VERSION) {
|
|
482
|
+
const fresh = { open: [], shown: [] };
|
|
483
|
+
writePending(target, fresh);
|
|
484
|
+
return fresh;
|
|
485
|
+
}
|
|
486
|
+
const state = { open: Array.isArray(parsed.open) ? parsed.open.filter(isOpenPair) : [], shown: Array.isArray(parsed.shown) ? parsed.shown : [] };
|
|
487
|
+
if (parsed.projectKey !== void 0) state.projectKey = typeof parsed.projectKey === "string" ? parsed.projectKey : null;
|
|
488
|
+
if (parsed.root !== void 0) state.root = typeof parsed.root === "string" ? parsed.root : null;
|
|
489
|
+
if (typeof parsed.cwd === "string") state.cwd = parsed.cwd;
|
|
490
|
+
return state;
|
|
491
|
+
} catch {
|
|
492
|
+
return { open: [], shown: [] };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function projectFor(state, event) {
|
|
496
|
+
const cwd = getCwd(event);
|
|
497
|
+
if (state.projectKey !== void 0 && state.root !== void 0 && state.cwd === cwd) return { key: state.projectKey, root: state.root };
|
|
498
|
+
let root = null;
|
|
499
|
+
let key = null;
|
|
500
|
+
try {
|
|
501
|
+
root = resolveProjectRoot(cwd === void 0 ? void 0 : { project: cwd });
|
|
502
|
+
key = projectHash(root);
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
state.projectKey = key;
|
|
506
|
+
state.root = root;
|
|
507
|
+
if (cwd === void 0) delete state.cwd;
|
|
508
|
+
else state.cwd = cwd;
|
|
509
|
+
return { key, root };
|
|
510
|
+
}
|
|
511
|
+
function writePending(target, state) {
|
|
512
|
+
try {
|
|
513
|
+
ensureDirSync(dirname(target));
|
|
514
|
+
atomicWriteText(target, JSON.stringify({ ...state, version: PENDING_VERSION }));
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function toPosix(path) {
|
|
519
|
+
return path.split(sep).join("/");
|
|
520
|
+
}
|
|
521
|
+
var LEADING_CD = /^cd\s+("[^"]+"|'[^']+'|[^\s;&|]+)\s*(?:&&|;)/;
|
|
522
|
+
function scopeOf(root, cwd, command) {
|
|
523
|
+
if (root === null || cwd === void 0) return "";
|
|
524
|
+
let dir = toPosix(relative(root, cwd)) || ".";
|
|
525
|
+
const cd = LEADING_CD.exec(squeeze(command));
|
|
526
|
+
if (cd !== null) {
|
|
527
|
+
const target = (cd[1] ?? "").replace(/^["']|["']$/g, "");
|
|
528
|
+
dir = isAbsolute(target) ? toPosix(relative(root, target)) || "." : posix.join(dir, target);
|
|
529
|
+
}
|
|
530
|
+
const scope = posix.normalize(dir);
|
|
531
|
+
return scope === "." ? "" : scope.replace(/\/$/, "");
|
|
532
|
+
}
|
|
533
|
+
function shapeOf(scope, core) {
|
|
534
|
+
return scope === "" ? core : `${scope}::${core}`;
|
|
535
|
+
}
|
|
536
|
+
function isGenericHeader(line) {
|
|
537
|
+
return /^>\s/.test(line) || /^[=\-*#~_\s]*$/.test(line) || /^[=\-*#~_]{2}/.test(line) && /[=\-*#~_]{2}$/.test(line) || !/[A-Za-z0-9]/.test(line);
|
|
538
|
+
}
|
|
539
|
+
var ERROR_LINE = /error|fail|cannot|not found|exception|denied|no such|traceback/i;
|
|
540
|
+
function signatureOf(errorText) {
|
|
541
|
+
const lines = redactSecrets(errorText).text.split("\n").map((line) => line.trim()).filter((line) => line !== "" && !/^Exit code \d+$/.test(line));
|
|
542
|
+
const exit = /^Exit code (\d+)/.exec(redactSecrets(errorText).text.trim());
|
|
543
|
+
const informative = lines.filter((line) => !isGenericHeader(line));
|
|
544
|
+
if (informative.length === 0) return null;
|
|
545
|
+
const chosen = informative.find((line) => ERROR_LINE.test(line));
|
|
546
|
+
const picked = chosen === void 0 ? informative.slice(0, 3) : [chosen];
|
|
547
|
+
const text = `${exit === null ? "" : `exit ${exit[1] ?? ""}: `}${picked.map((line) => errorPrefix(line)).join(" | ")}`;
|
|
548
|
+
const signature = text.slice(0, MAX_FIX_CHARS);
|
|
549
|
+
return carriesCredential(signature) ? null : digestOf(signature);
|
|
550
|
+
}
|
|
551
|
+
function recoveryAfterFailure(event, failure) {
|
|
552
|
+
try {
|
|
553
|
+
const target = pendingPath(event);
|
|
554
|
+
if (target === null || !isLearnableCommand(failure.command)) return null;
|
|
555
|
+
const { core } = splitCommandPrefix(failure.command);
|
|
556
|
+
if (core === "") return null;
|
|
557
|
+
const signature = signatureOf(failure.errorText);
|
|
558
|
+
if (signature === null) return null;
|
|
559
|
+
const state = readPending(target);
|
|
560
|
+
const { key, root } = projectFor(state, event);
|
|
561
|
+
const failed = digestFailed(failure.command);
|
|
562
|
+
const shape = digestOf(shapeOf(scopeOf(root, getCwd(event), failure.command), core));
|
|
563
|
+
const now = Date.now();
|
|
564
|
+
const pairs = key === null ? [] : loadStore(key, now);
|
|
565
|
+
const prior = state.open.find((o) => o.key === failed.core);
|
|
566
|
+
if (prior?.offered !== void 0 && prior.fixRan === true) {
|
|
567
|
+
const pair = pairs.find((p) => prior.offered !== void 0 && isOffered(p, prior.offered, prior.signature, prior.shape));
|
|
568
|
+
if (pair !== void 0 && key !== null) {
|
|
569
|
+
pair.hurt += 1;
|
|
570
|
+
saveStore(key, pairs);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
const candidates = pairs.filter((p) => matches(p, signature, shape) && !isRetired(p) && p.sessions.length >= MIN_SESSIONS && isReplayable(p.fix) && placeholderLeadFits(p.fix, core)).sort((a, b) => b.helped - b.hurt - (a.helped - a.hurt) || b.count - a.count || b.lastSeen - a.lastSeen);
|
|
574
|
+
const best = candidates[0];
|
|
575
|
+
const open = { key: failed.core, shape, failedPrefix: failed.prefix, failedRun: failed.run, signature, calls: 0, between: [], ...best === void 0 ? {} : { offered: { fix: best.fix } } };
|
|
576
|
+
state.open = [...state.open.filter((o) => o.key !== failed.core), open].slice(-MAX_OPEN);
|
|
577
|
+
const id = `${signature}
|
|
578
|
+
${shape}`;
|
|
579
|
+
const speak = best !== void 0 && !state.shown.includes(id);
|
|
580
|
+
if (speak) state.shown = [...state.shown, id].slice(-64);
|
|
581
|
+
writePending(target, state);
|
|
582
|
+
if (!speak || best === void 0) return null;
|
|
583
|
+
const text = `[token-goat] In an earlier session this same failure was followed by: ${fencedCommand(displaySafeText(best.fix))} (seen ${best.count} ${best.count === 1 ? "time" : "times"}, not verified)`;
|
|
584
|
+
const out = applyHintTracking(event, contextOutput(text), uncorrelatedHint("recovery_pair"));
|
|
585
|
+
return out.hookType === "context" ? out.context : null;
|
|
586
|
+
} catch {
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
function advanceOfferedFix(open, command) {
|
|
591
|
+
const offered = open.offered;
|
|
592
|
+
if (offered === void 0 || open.fixRan === true) return;
|
|
593
|
+
const ran = squeeze(command);
|
|
594
|
+
const parts = offered.fix.split(" && ");
|
|
595
|
+
if (ran === offered.fix) {
|
|
596
|
+
open.fixRan = true;
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const next = open.progress ?? 0;
|
|
600
|
+
if (ran !== parts[next]) return;
|
|
601
|
+
open.progress = next + 1;
|
|
602
|
+
if (open.progress === parts.length) open.fixRan = true;
|
|
603
|
+
}
|
|
604
|
+
function recoveryAfterSuccess(event, command) {
|
|
605
|
+
try {
|
|
606
|
+
const target = pendingPath(event);
|
|
607
|
+
if (target === null) return;
|
|
608
|
+
const state = readPending(target);
|
|
609
|
+
if (state.open.length === 0) return;
|
|
610
|
+
const clean = isLearnableCommand(command);
|
|
611
|
+
const now = Date.now();
|
|
612
|
+
const { key } = projectFor(state, event);
|
|
613
|
+
const tag = sessionTag(event);
|
|
614
|
+
const keep = [];
|
|
615
|
+
const coreDigest = digestOf(splitCommandPrefix(command).core);
|
|
616
|
+
const step = clean ? betweenStep(command) : null;
|
|
617
|
+
let store = null;
|
|
618
|
+
let changed = false;
|
|
619
|
+
for (const open of state.open) {
|
|
620
|
+
open.calls += 1;
|
|
621
|
+
if (open.calls > RECOVERY_WINDOW) continue;
|
|
622
|
+
if (!clean) continue;
|
|
623
|
+
if (coreDigest === open.key) {
|
|
624
|
+
store ??= key === null ? [] : loadStore(key, now);
|
|
625
|
+
const offered = open.offered;
|
|
626
|
+
if (offered !== void 0 && open.fixRan === true) {
|
|
627
|
+
const pair = store.find((p) => isOffered(p, offered, open.signature, open.shape));
|
|
628
|
+
if (pair !== void 0) {
|
|
629
|
+
pair.helped += 1;
|
|
630
|
+
pair.count += 1;
|
|
631
|
+
pair.lastSeen = now;
|
|
632
|
+
addSession(pair, tag);
|
|
633
|
+
changed = true;
|
|
634
|
+
}
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
const fix = learnFromDigest({ core: open.key, prefix: open.failedPrefix, run: open.failedRun }, command, open.between);
|
|
638
|
+
if (fix !== null) {
|
|
639
|
+
const sameShape = store.filter((p) => matches(p, open.signature, open.shape));
|
|
640
|
+
const same = sameShape.find((p) => p.fix === fix);
|
|
641
|
+
if (same !== void 0) {
|
|
642
|
+
same.count += 1;
|
|
643
|
+
same.lastSeen = now;
|
|
644
|
+
addSession(same, tag);
|
|
645
|
+
changed = true;
|
|
646
|
+
} else if (!sameShape.some((p) => p.helped > 0)) {
|
|
647
|
+
store = [...store.filter((p) => !matches(p, open.signature, open.shape)), { signature: open.signature, commandShape: open.shape, fix, count: 1, lastSeen: now, helped: 0, hurt: 0, sessions: [tag] }];
|
|
648
|
+
changed = true;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
advanceOfferedFix(open, command);
|
|
654
|
+
if (step !== null) open.between = [...open.between, step].slice(-RECOVERY_WINDOW);
|
|
655
|
+
keep.push(open);
|
|
656
|
+
}
|
|
657
|
+
if (changed && store !== null && key !== null) saveStore(key, store);
|
|
658
|
+
state.open = keep;
|
|
659
|
+
writePending(target, state);
|
|
660
|
+
} catch {
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function recoveryAfterEdit(event) {
|
|
664
|
+
try {
|
|
665
|
+
const target = pendingPath(event);
|
|
666
|
+
if (target === null) return;
|
|
667
|
+
const state = readPending(target);
|
|
668
|
+
if (state.open.length === 0) return;
|
|
669
|
+
state.open = [];
|
|
670
|
+
writePending(target, state);
|
|
671
|
+
} catch {
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
export {
|
|
675
|
+
MAX_FIX_CHARS,
|
|
676
|
+
MAX_PAIRS,
|
|
677
|
+
OTHER_STEP,
|
|
678
|
+
PAIR_TTL_MS,
|
|
679
|
+
RECOVERY_WINDOW,
|
|
680
|
+
WRAPPER,
|
|
681
|
+
installKey,
|
|
682
|
+
isLearnableCommand,
|
|
683
|
+
isRetired,
|
|
684
|
+
learnableFix,
|
|
685
|
+
loadRecoveryPairs,
|
|
686
|
+
recoveryAfterEdit,
|
|
687
|
+
recoveryAfterFailure,
|
|
688
|
+
recoveryAfterSuccess,
|
|
689
|
+
recoveryProjectKey,
|
|
690
|
+
recoveryStorePath,
|
|
691
|
+
splitCommandPrefix
|
|
692
|
+
};
|