nolo-cli 0.90.0-alpha.1 → 0.91.1
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 +1 -1
- package/{_executeModel-W26HVI75.js → _executeModel-H35GQ2XO.js} +61 -60
- package/{action-6DXQGJMX.js → action-3ZOODRBC.js} +11 -11
- package/{addContentAction-I7VX5SAC.js → addContentAction-IJHG2ZV7.js} +9 -9
- package/{addDialogAgentAction-OJSFV7DZ.js → addDialogAgentAction-IGFS2UBX.js} +11 -11
- package/{agentDeleteCommand-XNFWCKBH.js → agentDeleteCommand-XOFMXMHW.js} +43 -42
- package/{agentEmailCommands-W3X3EJ3V.js → agentEmailCommands-H2SEP6ZQ.js} +82 -78
- package/{agentGrantCommands-YW6PQAQ2.js → agentGrantCommands-M3XFO6EN.js} +2 -2
- package/{agentListCommands-DFWFU6XO.js → agentListCommands-RYGH6NUL.js} +72 -80
- package/{agentMachineCommands-LMFOAEL4.js → agentMachineCommands-XELOBZIP.js} +37 -36
- package/{agentProviderCommands-ZBYHGTGY.js → agentProviderCommands-JCRK6ST2.js} +1 -1
- package/{agentPullCommand-GLOOXJ2E.js → agentPullCommand-HF4A42D4.js} +3 -3
- package/agentRecordCommands-43HAXAZO.js +130 -0
- package/{agentRunCommand-HTBVIBGV.js → agentRunCommand-GIPN6DBO.js} +80 -75
- package/{agentRunControl-XLGD3UZ5.js → agentRunControl-AVJR4JW4.js} +2 -2
- package/{agentRuntimeLocal-2JFG4HDU.js → agentRuntimeLocal-SDOSSCLU.js} +38 -33
- package/{agentSlice-ZNLGFUB5.js → agentSlice-B2DLZMAC.js} +11 -11
- package/{appDeleteCommands-2UN4N2NR.js → appDeleteCommands-7OR5MAOR.js} +37 -36
- package/{appDeployCommands-37D74KRR.js → appDeployCommands-5GNI723H.js} +37 -36
- package/{appDeployStatusCommands-QBLWL2IA.js → appDeployStatusCommands-WL2NG3SG.js} +37 -36
- package/{appGetCommands-6KXIDF2T.js → appGetCommands-7BVKQS44.js} +37 -36
- package/{appListCommands-G2WFGEWQ.js → appListCommands-5VXFJOBU.js} +37 -36
- package/{authCommand-V2DJ7DB7.js → authCommand-N4Q6463J.js} +115 -23
- package/{authCommands-RGOGCPP6.js → authCommands-GBIFZWD3.js} +5 -5
- package/{builtinSkillRegistry-WBGYKIAZ.js → builtinSkillRegistry-JPY2DKRF.js} +7 -7
- package/{chatQueueReduxAdapter-XCJHIY3R.js → chatQueueReduxAdapter-3KDRKXTT.js} +29 -29
- package/{chromeCommands-VOIRNJBL.js → chromeCommands-NKU3OWKH.js} +36 -11
- package/{chromeOpsCommands-M7DPCX2T.js → chromeOpsCommands-OQDJGD4Y.js} +31 -1
- package/{chunk-4BYPU626.js → chunk-232453C2.js} +994 -1036
- package/{chunk-SMZSWB44.js → chunk-25GAGMRK.js} +6 -83
- package/{chunk-PH5J5VUY.js → chunk-3IYMTWYZ.js} +22 -22
- package/{chunk-NTW5GWDM.js → chunk-3VNWWVKB.js} +2 -0
- package/{chunk-TVNI5FLG.js → chunk-46CRK7XP.js} +7 -7
- package/{chunk-2ADBVBEM.js → chunk-55VQ4OPL.js} +4 -4
- package/{chunk-JPGCXHNM.js → chunk-5OA5HMTL.js} +1 -1
- package/{chunk-DWUCB2A3.js → chunk-62IL3KQV.js} +4 -34
- package/{chunk-3R5PH4IP.js → chunk-64TIEZHF.js} +1 -1
- package/{chunk-6YTOJY35.js → chunk-6D2JFXLY.js} +35 -0
- package/{chunk-3BMYXEUW.js → chunk-6O4IK4V2.js} +1 -1
- package/{chunk-WXPVOQD7.js → chunk-6PELJ3DS.js} +533 -236
- package/{chunk-NFMHIUY3.js → chunk-7EMJBGCA.js} +966 -218
- package/{chunk-HYZHJ5GW.js → chunk-7YMUSSHQ.js} +93 -93
- package/chunk-ACTMNVHM.js +93 -0
- package/{chunk-Q554LLSI.js → chunk-AUDNYVRC.js} +1 -1
- package/{chunk-UKWGR5SS.js → chunk-AUXHZ2M5.js} +186 -397
- package/{chunk-7MYYE7WX.js → chunk-B4PW6UAI.js} +61 -34
- package/{chunk-4DRWWIOL.js → chunk-B7ANJQWZ.js} +2 -2
- package/{chunk-XKQJJK4F.js → chunk-BAAKVSMZ.js} +4 -4
- package/{chunk-FQYMLZ6C.js → chunk-BFCXG6AJ.js} +16 -16
- package/{chunk-ZBT3WNBK.js → chunk-BJUDYFV5.js} +10 -2
- package/chunk-BMQ2MJUK.js +153 -0
- package/{chunk-TL6L5XUT.js → chunk-BNGW5ASC.js} +94 -16
- package/{chunk-JTK3TJYV.js → chunk-BTSYHR7J.js} +4 -4
- package/{chunk-LS2ZANRJ.js → chunk-CTUQJVQM.js} +1 -1
- package/{chunk-JEDZAO7L.js → chunk-D2W6WRHT.js} +13 -8
- package/{chunk-6BEA566T.js → chunk-D76D3RTR.js} +2 -2
- package/{chunk-HQCSU3DI.js → chunk-DCLMZ5TX.js} +4 -4
- package/{chunk-L2ICPOAL.js → chunk-EFZKILX6.js} +4 -4
- package/{chunk-JBBZ5KUM.js → chunk-EHO5EGU4.js} +23 -76
- package/{chunk-HVURBGF3.js → chunk-ESRMFY7G.js} +2 -2
- package/{chunk-ABQYVJBJ.js → chunk-ETZWFV6M.js} +1 -1
- package/{chunk-TRV2MIDW.js → chunk-EXAJ6DCR.js} +1 -0
- package/{chunk-VHJLQHPQ.js → chunk-F64B2W3R.js} +110 -34
- package/{chunk-AQZRTHDZ.js → chunk-G4EMOUX3.js} +886 -154
- package/{chunk-XTUY5EL4.js → chunk-GJUKGFHG.js} +74 -16
- package/{chunk-XMGHGEN6.js → chunk-GMVELWJG.js} +3 -3
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-CJCJF5XB.js → chunk-H6A6X4EK.js} +36 -3
- package/{chunk-N3OAPEZE.js → chunk-HBTA2SGQ.js} +97 -21
- package/{chunk-ONXOABJR.js → chunk-HNGRBWYF.js} +3 -0
- package/{chunk-3CR2LC6X.js → chunk-HNRASX3X.js} +8 -8
- package/{chunk-CPH3W5A7.js → chunk-I3TQJXQ7.js} +94 -3
- package/{chunk-GRYGRGPS.js → chunk-IS5VEM2G.js} +140 -15
- package/{chunk-MJHQ3NRV.js → chunk-ISHYYQJC.js} +5 -3
- package/{chunk-ZAB3A45K.js → chunk-K7M4I3PF.js} +30 -7
- package/{chunk-2AYMFHUG.js → chunk-KQOD3G2X.js} +165 -15
- package/{chunk-YOXYA2GU.js → chunk-LNPYTNMG.js} +10 -5
- package/{chunk-F2CGG72C.js → chunk-LS2MI3B4.js} +45 -45
- package/{chunk-GII32WZW.js → chunk-M2EJHDJP.js} +3 -0
- package/{chunk-7S4YWN7P.js → chunk-MX574M24.js} +1 -1
- package/{chunk-DNQPPRHY.js → chunk-N3XA2O6O.js} +1 -1
- package/{chunk-5DFFKASO.js → chunk-NILSKYOE.js} +3 -3
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-K7M3MWCE.js → chunk-OOSVFT6S.js} +2 -2
- package/{chunk-QCZX4FTW.js → chunk-OY5IJI2N.js} +194 -21
- package/{chunk-HMEMJ7GH.js → chunk-PAYUVQ6P.js} +7749 -1320
- package/{chunk-ASGDO77C.js → chunk-Q67DOFOO.js} +92 -4
- package/{chunk-UA5S3LQQ.js → chunk-QALRKMHF.js} +11 -10
- package/{chunk-RZANZZL2.js → chunk-QDSINZM3.js} +1 -1
- package/{chunk-DPQ2WVBY.js → chunk-QJLEMM2V.js} +1 -1
- package/{chunk-IIKPWSPX.js → chunk-R4SQ3LGW.js} +1 -1
- package/{chunk-UTCCPWB2.js → chunk-RZ6CQZB2.js} +34 -20
- package/{chunk-SAFZABH7.js → chunk-SV5IJK6K.js} +1 -1
- package/{chunk-576IMUGH.js → chunk-T5V7HA3K.js} +1 -1
- package/{chunk-BYMV6QZG.js → chunk-TNIX77YM.js} +4 -0
- package/chunk-UNYJU5L6.js +780 -0
- package/{chunk-QFMFJZLO.js → chunk-V7E4PXQD.js} +1 -1
- package/{chunk-QHETQ3KI.js → chunk-VBSVA6CB.js} +2 -2
- package/{chunk-A2C4AKKM.js → chunk-VETFWL5K.js} +1 -1
- package/chunk-VJVNU77E.js +83 -0
- package/{chunk-6D6VBVEW.js → chunk-VPFEPRME.js} +9 -9
- package/{chunk-3CMTBX3X.js → chunk-W2P25VGS.js} +25 -6
- package/{chunk-CLI4LFSM.js → chunk-WC6A2Q7S.js} +5 -3
- package/{chunk-Z33ARZCP.js → chunk-WT2IAJAJ.js} +4 -4
- package/chunk-X6YIXGPT.js +870 -0
- package/{chunk-5V4NJHRM.js → chunk-YMPTI7RZ.js} +9 -9
- package/{chunk-5NMZNPTN.js → chunk-YRIFJ6XQ.js} +13 -13
- package/{chunk-FZGV4FGK.js → chunk-YRRASA5Q.js} +268 -143
- package/{chunk-2F4VYGFW.js → chunk-Z5W7UMQV.js} +4 -3
- package/{chunk-ND2J3NRB.js → chunk-ZGJLSHER.js} +2 -2
- package/{chunk-VRLI2WNW.js → chunk-ZI2MEZMT.js} +314 -142
- package/{chunk-2F7RJC6L.js → chunk-ZOVKKMF6.js} +1 -1
- package/commandRegistry-BP5JLW24.js +822 -0
- package/{contentThunks-VURN3DFW.js → contentThunks-2HYFUXUM.js} +29 -29
- package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-ZLEPIB4A.js} +2 -2
- package/{createAgentAutomationAction-QZAAY77R.js → createAgentAutomationAction-DCKUSJH7.js} +29 -29
- package/{createDialogAction-CHGXVTAC.js → createDialogAction-NRIAEH2A.js} +32 -32
- package/{createPageAction-IOGAFIN7.js → createPageAction-AUJHHXGG.js} +35 -35
- package/{dbSlice-YXQ6RYIH.js → dbSlice-HFPIJT5P.js} +8 -8
- package/{deleteFile-YG6QMJLU.js → deleteFile-UEAD5A5Z.js} +3 -3
- package/{dialogCommands-XREAP6WQ.js → dialogCommands-UJRGCRN6.js} +42 -39
- package/{dialogSlice-DOPGWGS4.js → dialogSlice-AHU4XXIW.js} +35 -29
- package/{dist-VODFSGNG.js → dist-NJC2W7I4.js} +61 -54
- package/{docCreateCommands-3PYZGSCL.js → docCreateCommands-ZOV3ZBLW.js} +39 -38
- package/{docDeleteCommands-3Y6MU44Q.js → docDeleteCommands-G4KAXJYQ.js} +39 -38
- package/{docReadCommands-UBANMAFR.js → docReadCommands-B2MM3JIT.js} +38 -37
- package/{docStore-SYYFBENY.js → docStore-SITH63V3.js} +9 -9
- package/{docUpdateCommands-4GK2X6BN.js → docUpdateCommands-2QNF5CYN.js} +39 -38
- package/{fetchMessages-EIU7UFFK.js → fetchMessages-67MEFPZR.js} +2 -2
- package/{getPricing-F2C65RIX.js → getPricing-OX7B4R6B.js} +3 -3
- package/{handleSendMessageAction-NPVTY2GE.js → handleSendMessageAction-7ZMJMWLC.js} +72 -80
- package/index.js +74 -877
- package/{localDialogRead-BTFJ4V2I.js → localDialogRead-EBRS242U.js} +2 -2
- package/{localRuntimeAuthority-6IR6BBXE.js → localRuntimeAuthority-5W6IJRAD.js} +6 -6
- package/{localRuntimeDb-SYQGUF4U.js → localRuntimeDb-3LRMNLCM.js} +1 -1
- package/{machineCommands-I66X2XB7.js → machineCommands-YCTD5KOL.js} +75 -71
- package/{machineWsRunDispatch-W4FVBOUM.js → machineWsRunDispatch-JFMD4ZAW.js} +73 -69
- package/{memberThunks-5T4J6KXQ.js → memberThunks-SKFZ37VS.js} +9 -9
- package/{models-WW7VFNXB.js → models-T3SG6MJ5.js} +2 -2
- package/oauthTokenStore-ITEB663N.js +23 -0
- package/{offlineMarxistsAgentCommand-JEWCIAWM.js → offlineMarxistsAgentCommand-HGXZV4XJ.js} +1 -1
- package/package.json +1 -1
- package/pdf-U6KSUEZZ.js +26435 -0
- package/processSpawn-SOAV3FEV.js +11 -0
- package/profileConfig-ZGOFORWV.js +43 -0
- package/{providerPresetApply-OCWWKBSD.js → providerPresetApply-2QTBYN36.js} +7 -7
- package/{providerRegistry-ZJQU7AJ7.js → providerRegistry-SVXE4G4T.js} +7 -7
- package/{read-M2Q6WEKB.js → read-IEJLLUXY.js} +5 -5
- package/{readDocTool-T37P3YPB.js → readDocTool-4SPYCP2Y.js} +5 -3
- package/{readlineWorkspace-VY5AMOGR.js → readlineWorkspace-M3PLTBLD.js} +2396 -2018
- package/{removeDialogAgentAction-HB3JBVAI.js → removeDialogAgentAction-LILXTOQY.js} +14 -14
- package/{runAgentClientLoop-3NDADLVE.js → runAgentClientLoop-QMCXBOBH.js} +55 -55
- package/{runtimeDoctorCommands-X6WDBEQX.js → runtimeDoctorCommands-3USD722U.js} +3 -3
- package/runtimeModeArgs-2Y7BALTO.js +31 -0
- package/{setDialogExtraReferencesAction-4XLHRV37.js → setDialogExtraReferencesAction-LVNHLNT5.js} +10 -10
- package/{setPrimaryDialogAgentAction-C3JOFC4W.js → setPrimaryDialogAgentAction-DCKO5NTW.js} +14 -14
- package/{settingSlice-CZRURSTH.js → settingSlice-CNE75ISY.js} +10 -10
- package/{spaceCommands-ENYCUUZH.js → spaceCommands-3U6OHM6O.js} +39 -38
- package/{streamAgentChatTurn-634OFUSR.js → streamAgentChatTurn-JPMJQSEE.js} +144 -84
- package/{switchDialogAgentAction-C6KVUKJP.js → switchDialogAgentAction-JSYUQ5CG.js} +11 -11
- package/{tableCommands-O6NWHFKV.js → tableCommands-G7RV3RU3.js} +4 -4
- package/{toolApiClient-7PSIFQPJ.js → toolApiClient-INIQCPGY.js} +3 -3
- package/{tools-ILBLCF7D.js → tools-XQ5GIH6P.js} +49 -49
- package/{tuiSummaryLlmCaller-LFUBZKXK.js → tuiSummaryLlmCaller-L63PDJUD.js} +16 -15
- package/{updateCommands-2M74UL7P.js → updateCommands-ECWKIWLQ.js} +3 -3
- package/{updateDialogTitleAction-RKFET73N.js → updateDialogTitleAction-EGAZMLUB.js} +32 -32
- package/agentRecordCommands-FVVVCQFM.js +0 -126
- package/chunk-Q5FJJ6XI.js +0 -103
- package/chunk-S7Z2HMCN.js +0 -25
- package/chunk-WS22FPWT.js +0 -79
- package/{chunk-VMFTFOWF.js → chunk-3AH7LNUB.js} +7 -7
- package/{chunk-X7HHHIOZ.js → chunk-Y6ROFCZO.js} +0 -0
- package/{db-WK5MDZVN.js → db-VQSAOWAO.js} +1 -1
|
@@ -6,19 +6,151 @@ import {
|
|
|
6
6
|
} from "./chunk-KUG52IAP.js";
|
|
7
7
|
|
|
8
8
|
// packages/desktop-chrome-connector/chromeConnector.ts
|
|
9
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
-
import { resolve } from "node:path";
|
|
9
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
10
|
+
import { resolve as resolve2 } from "node:path";
|
|
11
|
+
|
|
12
|
+
// packages/desktop-chrome-connector/uploadSecurity.mjs
|
|
13
|
+
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
14
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
15
|
+
var DEFAULT_MAX_FILE_BYTES = 25 * 1024 * 1024;
|
|
16
|
+
var DEFAULT_MAX_FILES = 10;
|
|
17
|
+
var UploadSecurityError = class extends Error {
|
|
18
|
+
constructor(code, message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = "UploadSecurityError";
|
|
21
|
+
this.code = code;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
function createUploadSecurityError(code, message) {
|
|
25
|
+
return new UploadSecurityError(code, message);
|
|
26
|
+
}
|
|
27
|
+
function isSubpath(parent, child) {
|
|
28
|
+
const rel = relative(parent, child);
|
|
29
|
+
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
30
|
+
}
|
|
31
|
+
function parseAllowedRoots(env = process.env) {
|
|
32
|
+
const raw = env?.NOLO_CHROME_UPLOAD_ROOTS;
|
|
33
|
+
if (!raw || typeof raw !== "string") {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
return raw.split(",").map((entry) => entry.trim()).filter(Boolean).filter((entry) => isAbsolute(entry)).map((entry) => {
|
|
37
|
+
const resolved = resolve(entry);
|
|
38
|
+
if (existsSync(resolved)) {
|
|
39
|
+
try {
|
|
40
|
+
return realpathSync(resolved);
|
|
41
|
+
} catch {
|
|
42
|
+
return resolved;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return resolved;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function validateUploadFiles(options = {}) {
|
|
49
|
+
const {
|
|
50
|
+
files,
|
|
51
|
+
env = process.env,
|
|
52
|
+
maxFiles = DEFAULT_MAX_FILES,
|
|
53
|
+
maxFileBytes = DEFAULT_MAX_FILE_BYTES
|
|
54
|
+
} = options;
|
|
55
|
+
if (!Array.isArray(files) || files.length === 0) {
|
|
56
|
+
throw createUploadSecurityError("no_files", "Provide at least one file to upload.");
|
|
57
|
+
}
|
|
58
|
+
if (files.length > maxFiles) {
|
|
59
|
+
throw createUploadSecurityError(
|
|
60
|
+
"too_many_files",
|
|
61
|
+
`Too many files: ${files.length} provided, maximum allowed is ${maxFiles}.`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
const allowedRoots = parseAllowedRoots(env);
|
|
65
|
+
if (allowedRoots.length === 0) {
|
|
66
|
+
throw createUploadSecurityError(
|
|
67
|
+
"path_not_allowed",
|
|
68
|
+
"Upload roots not configured in NOLO_CHROME_UPLOAD_ROOTS; all uploads are refused."
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const fileStats = [];
|
|
72
|
+
const canonicalFiles = [];
|
|
73
|
+
let totalBytes = 0;
|
|
74
|
+
for (const rawFile of files) {
|
|
75
|
+
if (typeof rawFile !== "string" || !rawFile.trim()) {
|
|
76
|
+
throw createUploadSecurityError("path_not_allowed", "File path must be a non-empty string.");
|
|
77
|
+
}
|
|
78
|
+
const trimmed = rawFile.trim();
|
|
79
|
+
const resolvedCandidate = resolve(trimmed);
|
|
80
|
+
if (!existsSync(resolvedCandidate)) {
|
|
81
|
+
throw createUploadSecurityError("path_not_allowed", `File not found or inaccessible: ${rawFile}`);
|
|
82
|
+
}
|
|
83
|
+
let real;
|
|
84
|
+
try {
|
|
85
|
+
real = realpathSync(resolvedCandidate);
|
|
86
|
+
} catch {
|
|
87
|
+
throw createUploadSecurityError("path_not_allowed", `Could not resolve canonical path for: ${rawFile}`);
|
|
88
|
+
}
|
|
89
|
+
let st;
|
|
90
|
+
try {
|
|
91
|
+
st = statSync(real);
|
|
92
|
+
} catch {
|
|
93
|
+
throw createUploadSecurityError("path_not_allowed", `Could not stat file: ${rawFile}`);
|
|
94
|
+
}
|
|
95
|
+
if (!st.isFile()) {
|
|
96
|
+
throw createUploadSecurityError("path_not_allowed", `Target path is not a regular file: ${rawFile}`);
|
|
97
|
+
}
|
|
98
|
+
if (st.size > maxFileBytes) {
|
|
99
|
+
throw createUploadSecurityError(
|
|
100
|
+
"too_large",
|
|
101
|
+
`File size ${st.size} bytes exceeds maximum allowed limit of ${maxFileBytes} bytes: ${rawFile}`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const realInside = allowedRoots.some((root) => isSubpath(root, real));
|
|
105
|
+
if (!realInside) {
|
|
106
|
+
throw createUploadSecurityError(
|
|
107
|
+
"path_not_allowed",
|
|
108
|
+
`Path '${rawFile}' (resolved: '${real}') is not within allowed upload roots.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
canonicalFiles.push(real);
|
|
112
|
+
fileStats.push({ path: real, bytes: st.size });
|
|
113
|
+
totalBytes += st.size;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
ok: true,
|
|
117
|
+
files: canonicalFiles,
|
|
118
|
+
fileStats,
|
|
119
|
+
totalBytes
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function formatUploadAuditLog(entry = {}) {
|
|
123
|
+
const ts = entry.timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
124
|
+
const safeTabId = String(entry.tabId ?? "").replace(/[\x00-\x1f\x7f-\x9f]+/g, " ");
|
|
125
|
+
const safeTarget = String(entry.target ?? "").replace(/[\x00-\x1f\x7f-\x9f]+/g, " ");
|
|
126
|
+
const files = Array.isArray(entry.files) ? entry.files : [];
|
|
127
|
+
const totalBytes = files.reduce((sum, f) => sum + (Number(f.bytes) || 0), 0);
|
|
128
|
+
const fileDetails = files.map((f) => `${String(f.path || "").replace(/[\x00-\x1f\x7f-\x9f]+/g, " ")}(${f.bytes || 0}B)`).join(", ");
|
|
129
|
+
return `[chrome-upload] ${ts} tabId=${safeTabId} target=${safeTarget} files=[${fileDetails}] totalBytes=${totalBytes}`;
|
|
130
|
+
}
|
|
131
|
+
function logUploadAudit(entry, logFn = console.warn) {
|
|
132
|
+
const line = formatUploadAuditLog(entry);
|
|
133
|
+
logFn(line);
|
|
134
|
+
return line;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// packages/desktop-chrome-connector/chromeConnector.ts
|
|
11
138
|
var NOLO_CHROME_CONNECTOR_EXTENSION_ID = "ahpdoopadkamnglhlacfjdfnonpjdplg";
|
|
139
|
+
var NOLO_FIREFOX_CONNECTOR_EXTENSION_ID = "nolo-browser-connector@nolo.chat";
|
|
140
|
+
var NOLO_CONNECTOR_EXTENSION_IDS = [
|
|
141
|
+
NOLO_CHROME_CONNECTOR_EXTENSION_ID,
|
|
142
|
+
NOLO_FIREFOX_CONNECTOR_EXTENSION_ID
|
|
143
|
+
];
|
|
12
144
|
var NOLO_CHROME_CONNECTOR_PROTOCOL_VERSION = "2";
|
|
13
145
|
function defaultTokenPath() {
|
|
14
|
-
return
|
|
146
|
+
return resolve2(
|
|
15
147
|
process.env.HOME || "",
|
|
16
148
|
"Library/Application Support/Nolo/ChromeConnector/token"
|
|
17
149
|
);
|
|
18
150
|
}
|
|
19
151
|
function readConnectorToken(tokenPath = defaultTokenPath()) {
|
|
20
152
|
if (process.env.NOLO_CHROME_CONNECTOR_TOKEN) return process.env.NOLO_CHROME_CONNECTOR_TOKEN;
|
|
21
|
-
if (!
|
|
153
|
+
if (!existsSync2(tokenPath)) return "";
|
|
22
154
|
return readFileSync(tokenPath, "utf8").trim();
|
|
23
155
|
}
|
|
24
156
|
var CHROME_TOOL_ACTIONS = {
|
|
@@ -32,7 +164,10 @@ var CHROME_TOOL_ACTIONS = {
|
|
|
32
164
|
chrome_scroll: "scroll",
|
|
33
165
|
chrome_screenshot: "screenshot",
|
|
34
166
|
chrome_read_console: "read_console",
|
|
35
|
-
chrome_read_network: "read_network"
|
|
167
|
+
chrome_read_network: "read_network",
|
|
168
|
+
chrome_set_files: "set_files",
|
|
169
|
+
chrome_upload_file: "set_files",
|
|
170
|
+
chrome_upload: "set_files"
|
|
36
171
|
};
|
|
37
172
|
function createConnectorError(code, message, details) {
|
|
38
173
|
const error = new Error(message);
|
|
@@ -53,14 +188,18 @@ function parseArguments(raw) {
|
|
|
53
188
|
}
|
|
54
189
|
}
|
|
55
190
|
function errorPayload(error) {
|
|
191
|
+
const code = error?.code ?? "CHROME_CONNECTOR_ERROR";
|
|
56
192
|
return {
|
|
57
|
-
code
|
|
193
|
+
code,
|
|
58
194
|
message: toErrorMessage(error),
|
|
195
|
+
...code === "CHROME_CONNECTOR_UNAVAILABLE" ? {
|
|
196
|
+
hint: "The Nolo Browser Connector is not reachable. It runs inside the user's own Chrome or Firefox \u2014 ask the user to open their browser with the Nolo Browser Connector extension enabled, or install it from https://nolo.chat/downloads (Firefox can install the signed .xpi directly), then retry."
|
|
197
|
+
} : {},
|
|
59
198
|
...error?.details !== void 0 ? { details: error.details } : {}
|
|
60
199
|
};
|
|
61
200
|
}
|
|
62
|
-
var TARGET_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["click", "type"]);
|
|
63
|
-
var TAB_ID_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["close_tab", "detach"]);
|
|
201
|
+
var TARGET_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["click", "type", "set_files"]);
|
|
202
|
+
var TAB_ID_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["close_tab", "detach", "set_files"]);
|
|
64
203
|
function validateChromeConnectorPayload(action, payload) {
|
|
65
204
|
if (TAB_ID_REQUIRED_ACTIONS.has(action)) {
|
|
66
205
|
const raw = payload.tabId;
|
|
@@ -71,16 +210,42 @@ function validateChromeConnectorPayload(action, payload) {
|
|
|
71
210
|
`Provide the tabId from chrome_list_tabs before calling ${action}.`
|
|
72
211
|
);
|
|
73
212
|
}
|
|
74
|
-
return;
|
|
213
|
+
if (!TARGET_REQUIRED_ACTIONS.has(action)) return;
|
|
75
214
|
}
|
|
76
215
|
if (!TARGET_REQUIRED_ACTIONS.has(action)) return;
|
|
77
|
-
const
|
|
216
|
+
const rawRef = typeof payload.elementRef === "string" ? payload.elementRef : typeof payload.ref === "string" ? payload.ref : "";
|
|
217
|
+
const elementRef = rawRef.trim();
|
|
78
218
|
const selector = typeof payload.selector === "string" ? payload.selector.trim() : "";
|
|
79
|
-
if (elementRef
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
219
|
+
if (!elementRef && !selector) {
|
|
220
|
+
throw createConnectorError(
|
|
221
|
+
"ELEMENT_TARGET_REQUIRED",
|
|
222
|
+
"Provide elementRef from chrome_read_page or a CSS selector."
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
if (action === "set_files") {
|
|
226
|
+
if (!Array.isArray(payload.files) || payload.files.length === 0) {
|
|
227
|
+
throw createConnectorError(
|
|
228
|
+
"no_files",
|
|
229
|
+
"Provide at least one file path in files array."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
const validated = validateUploadFiles({
|
|
234
|
+
files: payload.files,
|
|
235
|
+
env: process.env
|
|
236
|
+
});
|
|
237
|
+
payload.files = validated.files;
|
|
238
|
+
const targetStr = elementRef ? `ref:${elementRef}` : `selector:${selector}`;
|
|
239
|
+
logUploadAudit({
|
|
240
|
+
tabId: String(payload.tabId),
|
|
241
|
+
target: targetStr,
|
|
242
|
+
files: validated.fileStats
|
|
243
|
+
});
|
|
244
|
+
} catch (err) {
|
|
245
|
+
const code = err?.code ?? "path_not_allowed";
|
|
246
|
+
throw createConnectorError(code, toErrorMessage(err));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
84
249
|
}
|
|
85
250
|
function createChromeConnectorClient(args) {
|
|
86
251
|
if (args?.request) return { request: args.request };
|
|
@@ -90,6 +255,7 @@ function createChromeConnectorClient(args) {
|
|
|
90
255
|
const token = args?.token ?? readConnectorToken(args?.tokenPath);
|
|
91
256
|
return {
|
|
92
257
|
async request(action, payload) {
|
|
258
|
+
validateChromeConnectorPayload(action, payload);
|
|
93
259
|
let response;
|
|
94
260
|
try {
|
|
95
261
|
response = await fetchImpl(endpoint, {
|
|
@@ -128,27 +294,34 @@ var REQUIRED_CHROME_CONNECTOR_FEATURES = {
|
|
|
128
294
|
type: ["compact_observation_v2", "action_gate"],
|
|
129
295
|
press: ["compact_observation_v2", "action_gate"],
|
|
130
296
|
scroll: ["compact_observation_v2"],
|
|
131
|
-
screenshot:
|
|
297
|
+
// Both browsers advertise the dedicated `screenshot` feature: Chrome serves it through
|
|
298
|
+
// Page.captureScreenshot (browser_debug-adjacent) while Firefox falls back to
|
|
299
|
+
// tabs.captureVisibleTab, so gating on browser_debug would wrongly refuse Firefox.
|
|
300
|
+
screenshot: ["screenshot"],
|
|
132
301
|
read_console: ["browser_debug"],
|
|
133
302
|
read_network: ["browser_debug"],
|
|
134
|
-
detach: ["browser_debug"]
|
|
303
|
+
detach: ["browser_debug"],
|
|
304
|
+
set_files: ["compact_observation_v2", "file_upload"]
|
|
135
305
|
};
|
|
136
306
|
function requiredFeaturesForConnectorAction(action) {
|
|
137
307
|
return [...REQUIRED_CHROME_CONNECTOR_FEATURES[action] ?? []];
|
|
138
308
|
}
|
|
139
309
|
function createVerifiedChromeConnectorClient(args) {
|
|
140
310
|
const client = args?.client ?? createChromeConnectorClient();
|
|
141
|
-
const
|
|
311
|
+
const expectedExtensionIds = new Set(
|
|
312
|
+
args?.expectedExtensionIds ?? (args?.expectedExtensionId ? [args.expectedExtensionId] : NOLO_CONNECTOR_EXTENSION_IDS)
|
|
313
|
+
);
|
|
142
314
|
let verified = null;
|
|
143
315
|
let negotiatedFeatures = [];
|
|
144
316
|
const verify = async () => {
|
|
145
317
|
const connectorInfo = await client.request("connector_info", {});
|
|
146
318
|
const receivedExtensionId = connectorInfo?.extensionId;
|
|
147
|
-
if (receivedExtensionId !==
|
|
319
|
+
if (typeof receivedExtensionId !== "string" || !expectedExtensionIds.has(receivedExtensionId)) {
|
|
320
|
+
const expectedList = [...expectedExtensionIds].join(", ");
|
|
148
321
|
throw createConnectorError(
|
|
149
322
|
"CHROME_CONNECTOR_EXTENSION_MISMATCH",
|
|
150
|
-
`Chrome connector extension id mismatch: expected ${
|
|
151
|
-
{
|
|
323
|
+
`Chrome connector extension id mismatch: expected one of ${expectedList}, received ${typeof receivedExtensionId === "string" ? receivedExtensionId : "unknown"}.`,
|
|
324
|
+
{ expectedExtensionIds: [...expectedExtensionIds], receivedExtensionId }
|
|
152
325
|
);
|
|
153
326
|
}
|
|
154
327
|
const receivedProtocolVersion = connectorInfo?.protocolVersion;
|