nolo-cli 0.107.0-alpha.3 → 0.107.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/README.md +1 -1
- package/{_executeModel-UDCSOTD2.js → _executeModel-C4EH5TZG.js} +77 -69
- package/action-GVA5ARSJ.js +20 -0
- package/{addContentAction-MB2HHMDZ.js → addContentAction-M2WOWZCL.js} +13 -12
- package/{addDialogAgentAction-MCEABSBA.js → addDialogAgentAction-QMAQ5Z6N.js} +19 -20
- package/{agentDeleteCommand-OWYHN6D6.js → agentDeleteCommand-D3RICSHX.js} +118 -43
- package/{agentEmailCommands-BQFXQIHF.js → agentEmailCommands-YC2A4USQ.js} +99 -89
- package/agentListCommands-UDJELMYP.js +741 -0
- package/{agentMachineCommands-6DTI7YSG.js → agentMachineCommands-XH4IBGTO.js} +48 -44
- package/{agentProviderCommands-GNPTL5XR.js → agentProviderCommands-CMVTBY5X.js} +97 -2
- package/{agentPullCommand-O5MPVJ5E.js → agentPullCommand-B4T2DJ5H.js} +1 -1
- package/agentRecordCommands-3EOC2QMN.js +138 -0
- package/agentRunCommand-BTHYOVVS.js +167 -0
- package/{agentRunControl-AVJR4JW4.js → agentRunControl-3HWA2LLQ.js} +2 -2
- package/{agentRuntimeLocal-KCMC2TBD.js → agentRuntimeLocal-N4YGKL7M.js} +44 -40
- package/{agentSlice-R7PR6KYM.js → agentSlice-NIN4T6CF.js} +15 -14
- package/{appDeleteCommands-JEPA3EWE.js → appDeleteCommands-7DAF33AM.js} +46 -42
- package/{appDeployCommands-UTB76XFM.js → appDeployCommands-ZPZSMFGZ.js} +46 -42
- package/{appDeployStatusCommands-LGHF2SBD.js → appDeployStatusCommands-FWBDSSS5.js} +46 -42
- package/{appGetCommands-PX2BFHOB.js → appGetCommands-SZZOHGEP.js} +46 -42
- package/{appListCommands-BSMPTWKC.js → appListCommands-FPMUBDPM.js} +46 -42
- package/{authCommand-YW42YZA4.js → authCommand-VL3G26NQ.js} +119 -25
- package/{authCommands-RGOGCPP6.js → authCommands-5RTUDYZW.js} +7 -5
- package/{builtinSkillRegistry-FUAVTRVZ.js → builtinSkillRegistry-ZK4K67Y5.js} +11 -9
- package/{chromeCommands-FZYAU75D.js → chromeCommands-AU5ZJXBG.js} +289 -37
- package/{chromeOpsCommands-62P2Q2YB.js → chromeOpsCommands-ZYTCMNHG.js} +156 -22
- package/{chunk-JDPFV2JV.js → chunk-2NNRWRM5.js} +20 -11
- package/{chunk-JEDZAO7L.js → chunk-2SYTUTLI.js} +257 -37
- package/{chunk-HVURBGF3.js → chunk-2U3NHADM.js} +6 -6
- package/{chunk-AVTT555J.js → chunk-2ZHBFX5R.js} +29 -9
- package/{chunk-QTGQ2LTL.js → chunk-3DQY5IFB.js} +6 -10
- package/chunk-4LCOCOR5.js +50 -0
- package/{chunk-JPGCXHNM.js → chunk-4LKMZ3RR.js} +1 -1
- package/{chunk-2GRGFCF6.js → chunk-4VJAC32I.js} +2 -1
- package/{chunk-6D6VBVEW.js → chunk-4W24JM32.js} +80 -14
- package/{chunk-MC4XLIJ7.js → chunk-523DITKR.js} +1 -1
- package/{chunk-E4MARS3Q.js → chunk-5GVBDNTO.js} +1 -1
- package/chunk-5MMAK75Q.js +15 -0
- package/{chunk-7S4YWN7P.js → chunk-5UUIGN6I.js} +4 -4
- package/{chunk-42V6BK2E.js → chunk-62IL3KQV.js} +4 -34
- package/{chunk-C63CN6KA.js → chunk-6IJDSYUA.js} +849 -279
- package/{chunk-4MK3I7Y4.js → chunk-6MAW4XOF.js} +5 -5
- package/chunk-76HO2DP6.js +15 -0
- package/chunk-7AY2H3GA.js +13692 -0
- package/{chunk-4CR5I7BD.js → chunk-7HYOPBUW.js} +47 -67
- package/{chunk-VLTIYV3X.js → chunk-7I25CBT5.js} +34 -8
- package/chunk-AGIM7IMJ.js +147 -0
- package/{chunk-5UTFL4QJ.js → chunk-AOTBKDRK.js} +7 -0
- package/{chunk-6OZ36FXI.js → chunk-BIPGGSJS.js} +22 -4
- package/{chunk-EYAQT56M.js → chunk-BNQMNUKZ.js} +9 -6
- package/{chunk-62CATUYY.js → chunk-CBUMFIFE.js} +834 -962
- package/{chunk-OIVSQH2O.js → chunk-CDEEFJXN.js} +308 -11
- package/chunk-CHOZJMJS.js +78 -0
- package/{chunk-ETI2NYVF.js → chunk-CIP3AAMT.js} +4 -4
- package/{chunk-GBRG75BQ.js → chunk-D2MDMY2M.js} +1 -0
- package/{chunk-IBOZNTG2.js → chunk-DGEUP3DK.js} +23 -28
- package/{chunk-Q554LLSI.js → chunk-DMXLXZKL.js} +1 -1
- package/{chunk-3VNWWVKB.js → chunk-E3YWHWCR.js} +50 -18
- package/{chunk-HKNXJGEC.js → chunk-ECFHBYUW.js} +85 -50
- package/{chunk-ACTMNVHM.js → chunk-EHSYSKXV.js} +1 -1
- package/{chunk-WV42OMV7.js → chunk-ELUDRSRD.js} +8 -8
- package/{chunk-ABQYVJBJ.js → chunk-EV235ILT.js} +5 -5
- package/{chunk-TRV2MIDW.js → chunk-EXAJ6DCR.js} +1 -0
- package/{chunk-BFDFRLLQ.js → chunk-EZ4VZHAG.js} +5 -5
- package/{chunk-GO3Z72MT.js → chunk-FHLMQIU7.js} +65 -95
- package/{chunk-2F7RJC6L.js → chunk-FOXQ7BAB.js} +1 -1
- package/{chunk-SH43IESU.js → chunk-GGC55Q32.js} +199 -29
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-FDTR4QJ6.js → chunk-H6A6X4EK.js} +32 -1
- package/{chunk-DVINR3PL.js → chunk-HDLLCBRF.js} +1 -1
- package/{chunk-QOKAKDPE.js → chunk-HIM3FCLF.js} +0 -1
- package/{chunk-ONXOABJR.js → chunk-HNGRBWYF.js} +3 -0
- package/{chunk-BNGW5ASC.js → chunk-I2RGRVQ7.js} +22 -2
- package/{chunk-O6OSWFZQ.js → chunk-IHPDK6UD.js} +6 -0
- package/{chunk-QDSINZM3.js → chunk-IXH3HKY2.js} +1 -22
- package/{chunk-GQBOR3G6.js → chunk-JBKHQOYK.js} +8 -4
- package/{chunk-XD2MJFUG.js → chunk-JEFXP73H.js} +1 -1
- package/{chunk-PBA4UJBK.js → chunk-JIXGJTBU.js} +4 -4
- package/{chunk-AEOE4Z6Q.js → chunk-K6L5PNXK.js} +39 -15
- package/{chunk-Z77CRGTW.js → chunk-KA5O5KQL.js} +1 -1
- package/{chunk-GPCZ7UXG.js → chunk-KD6D6BLA.js} +1 -1
- package/{chunk-UZGQNTVW.js → chunk-KHKTDMYG.js} +8 -6
- package/{chunk-MRIHM22T.js → chunk-LBFL6RZG.js} +58 -9
- package/{chunk-C3M4465B.js → chunk-LKIVH2I2.js} +403 -658
- package/{chunk-LS2ZANRJ.js → chunk-LOCNXNOU.js} +1 -1
- package/{chunk-DHDMC6FO.js → chunk-LUBFABMJ.js} +15 -14
- package/{chunk-NA35QHCF.js → chunk-LVBFKW65.js} +1 -1
- package/chunk-LWLNLZC5.js +265 -0
- package/{chunk-EEGDMATE.js → chunk-M3NMHYRB.js} +86 -81
- package/chunk-N4NGJDT6.js +929 -0
- package/{chunk-GL3EHUR4.js → chunk-N7NLLRQQ.js} +68 -46
- package/{chunk-BFU6C242.js → chunk-NMFV26UG.js} +1 -1
- package/{chunk-FZGV4FGK.js → chunk-NUHHBEJC.js} +378 -187
- package/chunk-NWENLDMM.js +42 -0
- package/chunk-O7SVKKLY.js +875 -0
- package/chunk-OCZKATRC.js +129 -0
- package/{chunk-6Z7MY3V7.js → chunk-OEJLGVBL.js} +5 -5
- package/{chunk-VMFTFOWF.js → chunk-OKGVNZTL.js} +35 -8
- package/{chunk-GEPUP7OO.js → chunk-OR2UWD6X.js} +3 -3
- package/{chunk-KQHGZWSV.js → chunk-OXME3PEE.js} +1 -1
- package/{chunk-J4MOO56S.js → chunk-PNXHPLRU.js} +10 -2
- package/{chunk-3BMYXEUW.js → chunk-R5AJODNI.js} +1 -1
- package/{chunk-P5EVSOPA.js → chunk-R6EBQEQE.js} +22 -29
- package/{chunk-NOF3HDSN.js → chunk-RLSF5CSE.js} +11 -9
- package/chunk-RQ6CTX2E.js +164 -0
- package/{chunk-3UZPUAES.js → chunk-RSB4PWX4.js} +1 -1
- package/{chunk-KQ4ONNQD.js → chunk-RXA3HAVW.js} +190 -8
- package/{chunk-IIVGDG4I.js → chunk-SJKULPGX.js} +13 -7
- package/chunk-SQHMSDDU.js +8004 -0
- package/{chunk-Q67DOFOO.js → chunk-SZC4REES.js} +212 -105
- package/{chunk-JRQFUXY7.js → chunk-TBAXFWOS.js} +99 -22
- package/{chunk-PQFHGD77.js → chunk-TBM2RS3U.js} +161 -14
- package/{chunk-XT35TTFG.js → chunk-TCYU7L6V.js} +18 -20
- package/{chunk-BYMV6QZG.js → chunk-TNIX77YM.js} +4 -0
- package/chunk-TY3TIUJK.js +89 -0
- package/{chunk-I3TQJXQ7.js → chunk-U3C3IA32.js} +9 -2
- package/{chunk-YYLHWIW6.js → chunk-UKZX3NHN.js} +1 -1
- package/chunk-UM7TA3K4.js +1008 -0
- package/{chunk-6YTOJY35.js → chunk-VBG7GWWR.js} +253 -8
- package/chunk-VIWDGTDA.js +8 -0
- package/chunk-VJVNU77E.js +83 -0
- package/{chunk-W7HLWAQ7.js → chunk-VPLUU4IX.js} +118 -90
- package/{chunk-UKWGR5SS.js → chunk-VY6VFGKR.js} +194 -1144
- package/chunk-VZLO4XJD.js +17 -0
- package/{chunk-AHAHBQMU.js → chunk-WDLSZMTA.js} +2 -2
- package/{chunk-53HEEOTT.js → chunk-WF5X57VW.js} +83 -16
- package/{chunk-VRTTFDBM.js → chunk-WPHY3VPF.js} +35 -22
- package/{chunk-ASIFZ2WY.js → chunk-YKZLFY5J.js} +66 -54
- package/chunk-YV25TM3R.js +780 -0
- package/{chunk-B2C6QTY4.js → chunk-YXKNBVYW.js} +19 -17
- package/chunk-ZRAU6T47.js +56 -0
- package/commandRegistry-UU6IOTHI.js +833 -0
- package/{contentThunks-IV2T3EJC.js → contentThunks-ARD56LKI.js} +39 -36
- package/{cooldownCommands-REAWYVTY.js → cooldownCommands-ZLEPIB4A.js} +2 -2
- package/{createAgentAutomationAction-JCOIEYY4.js → createAgentAutomationAction-HWJLU6DD.js} +40 -37
- package/createDialogAction-CHYA6PZE.js +70 -0
- package/{createPageAction-D2VOOLP3.js → createPageAction-TSCYNFX7.js} +47 -43
- package/{chunk-VFEJQMH4.js → cursorProvider-YGGNMVWX.js} +2751 -10172
- package/{dbSlice-A6C6H32X.js → dbSlice-TG4MZ5EB.js} +12 -11
- package/{deleteFile-YG6QMJLU.js → deleteFile-KESP65GC.js} +7 -6
- package/{dialogCommands-H7FPUYUQ.js → dialogCommands-IJYQAQMB.js} +49 -46
- package/{dialogSlice-6JZOOTDS.js → dialogSlice-H476I77R.js} +57 -37
- package/{dist-VODFSGNG.js → dist-NJC2W7I4.js} +61 -54
- package/{docCreateCommands-WRG2JLGM.js → docCreateCommands-AZSK4NAG.js} +48 -44
- package/{docDeleteCommands-SHWJIBJS.js → docDeleteCommands-DDJMSMFZ.js} +49 -45
- package/{docReadCommands-WJN3WT6O.js → docReadCommands-5F5Q6EBZ.js} +47 -43
- package/{docStore-HUPQ2FSS.js → docStore-HW2RDZDM.js} +17 -13
- package/{docUpdateCommands-IE32IL6O.js → docUpdateCommands-XPNPVZOC.js} +48 -44
- package/{fetchMessages-EIU7UFFK.js → fetchMessages-3PXAHKCR.js} +5 -5
- package/{getPricing-LUSEABA6.js → getPricing-DOBBZLOK.js} +4 -4
- package/{handleSendMessageAction-DFPMQ7YM.js → handleSendMessageAction-IOXE7ILC.js} +109 -42
- package/index.js +87 -884
- package/{lib-FRRS27KN.js → lib-PU2G2MSO.js} +523 -191
- package/{localDialogRead-BTFJ4V2I.js → localDialogRead-UYCKO7YZ.js} +2 -2
- package/{localRuntimeAuthority-6IR6BBXE.js → localRuntimeAuthority-TU6OBC76.js} +9 -6
- package/{localRuntimeDb-SYQGUF4U.js → localRuntimeDb-VKWVOPPI.js} +1 -1
- package/{machineCommands-OL4NLMXG.js → machineCommands-Q7TDGM6P.js} +96 -86
- package/machineWsRunDispatch-T5VFOQ3R.js +154 -0
- package/{memberThunks-P2ECUJ56.js → memberThunks-5S5D3N4U.js} +20 -18
- package/{models-T3SG6MJ5.js → models-PQU25T6Q.js} +2 -2
- package/oauthTokenStore-ITEB663N.js +23 -0
- package/package.json +1 -1
- package/processSpawn-SOAV3FEV.js +11 -0
- package/profileConfig-ZGOFORWV.js +43 -0
- package/{providerPresetApply-FG6NZ57W.js → providerPresetApply-HAQWVAQX.js} +7 -7
- package/{providerRegistry-757OWH3O.js → providerRegistry-5FGWB3X5.js} +11 -7
- package/{read-COE3ZYR6.js → read-LSYFLSIM.js} +8 -7
- package/{readDocTool-5USN4A6V.js → readDocTool-XWRXV3DR.js} +5 -3
- package/{readlineWorkspace-BOENUIW2.js → readlineWorkspace-25U6P3DG.js} +2595 -2031
- package/{removeDialogAgentAction-J6X5QMTA.js → removeDialogAgentAction-4TEFC3VL.js} +22 -26
- package/{runAgentClientLoop-5ZA62FBA.js → runAgentClientLoop-CZOYWHDN.js} +78 -71
- package/{runtimeDoctorCommands-X6WDBEQX.js → runtimeDoctorCommands-PIVSBZRZ.js} +4 -4
- package/runtimeModeArgs-2Y7BALTO.js +31 -0
- package/{setDialogExtraReferencesAction-WX5VTY6O.js → setDialogExtraReferencesAction-LSEN44OY.js} +16 -14
- package/{setPrimaryDialogAgentAction-FN22THHT.js → setPrimaryDialogAgentAction-SR366X5A.js} +23 -27
- package/{chunk-GP5LKBUZ.js → settingThunks-CTVPPGIN.js} +226 -940
- package/{skillDiscovery-CYUCJMAG.js → skillDiscovery-ZBU76COE.js} +3 -3
- package/{slateUtils-RIZES3PV.js → slateUtils-NGV2NMKM.js} +1 -1
- package/{spaceCommands-5GLCWZPO.js → spaceCommands-3UK63WPE.js} +51 -47
- package/{streamAgentChatTurn-6UZJMYRB.js → streamAgentChatTurn-LV6ZWUD4.js} +214 -114
- package/{switchDialogAgentAction-LVTEV3FR.js → switchDialogAgentAction-M6NAFOOU.js} +19 -20
- package/{tableCommands-O6NWHFKV.js → tableCommands-6U4BMLRR.js} +10 -10
- package/{toolApiClient-QVJ6HDNN.js → toolApiClient-AD7CXTA4.js} +4 -3
- package/tools-UJOV6CQZ.js +117 -0
- package/{tuiSummaryLlmCaller-OHHFTHMG.js → tuiSummaryLlmCaller-DEH7ZEM6.js} +25 -23
- package/{updateCommands-2M74UL7P.js → updateCommands-4EHDLF5J.js} +3 -3
- package/{updateDialogTitleAction-QTKNIURB.js → updateDialogTitleAction-JYXKIBNJ.js} +84 -45
- package/action-P4TNFGAD.js +0 -31
- package/agentListCommands-B2V4YAC4.js +0 -410
- package/agentRecordCommands-UTHKMMJY.js +0 -128
- package/agentRunCommand-D4OBAOVW.js +0 -156
- package/browser-image-compression-MFDTD7K6.js +0 -1763
- package/chatQueueReduxAdapter-2P6NFX64.js +0 -186
- package/chunk-CQ3WA2NE.js +0 -299
- package/chunk-M76ECQRD.js +0 -13658
- package/chunk-MEYIRKDN.js +0 -8967
- package/chunk-PUOC4YRO.js +0 -394
- package/chunk-Q5FJJ6XI.js +0 -103
- package/chunk-S7Z2HMCN.js +0 -25
- package/chunk-T75QD6AB.js +0 -20923
- package/chunk-Y5GCAMGP.js +0 -9
- package/chunk-YPREESF4.js +0 -225
- package/createDialogAction-NGG7YVNU.js +0 -65
- package/machineWsRunDispatch-64SG2RUI.js +0 -144
- package/settingSlice-P4ZW7K5X.js +0 -204
- package/syncMapping-N6RGXGBW.js +0 -437
- package/tools-KMGFWO43.js +0 -110
- package/{chunk-X7HHHIOZ.js → chunk-Y6ROFCZO.js} +0 -0
- package/{db-WK5MDZVN.js → db-VQSAOWAO.js} +1 -1
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOLO_CHROME_CONNECTOR_EXTENSION_ID,
|
|
3
3
|
NOLO_CHROME_CONNECTOR_PROTOCOL_VERSION,
|
|
4
|
+
NOLO_CONNECTOR_EXTENSION_IDS,
|
|
5
|
+
NOLO_FIREFOX_CONNECTOR_EXTENSION_ID,
|
|
4
6
|
REQUIRED_CHROME_CONNECTOR_FEATURES,
|
|
5
|
-
createChromeConnectorClient
|
|
6
|
-
|
|
7
|
+
createChromeConnectorClient,
|
|
8
|
+
resolveUploadRoots
|
|
9
|
+
} from "./chunk-GGC55Q32.js";
|
|
7
10
|
import {
|
|
8
11
|
toErrorMessage
|
|
9
12
|
} from "./chunk-HNMXYYJR.js";
|
|
@@ -11,16 +14,18 @@ import "./chunk-KUG52IAP.js";
|
|
|
11
14
|
import "./chunk-4VNS5WPM.js";
|
|
12
15
|
|
|
13
16
|
// packages/cli/chromeCommands.ts
|
|
14
|
-
import {
|
|
17
|
+
import { spawnSync } from "node:child_process";
|
|
18
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
15
19
|
import { resolve as resolve2 } from "node:path";
|
|
16
20
|
|
|
17
21
|
// packages/desktop-chrome-connector/nativeHostInstall.mjs
|
|
18
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
19
23
|
import { createHash, randomBytes } from "node:crypto";
|
|
20
24
|
import { dirname, resolve } from "node:path";
|
|
21
25
|
import { execFileSync } from "node:child_process";
|
|
22
26
|
import { fileURLToPath } from "node:url";
|
|
23
27
|
var DEFAULT_CONNECTOR_ROOT = dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
var FIREFOX_EXTENSION_ID = "nolo-browser-connector@nolo.chat";
|
|
24
29
|
function extensionIdFromPublicKey(publicKeyBase64) {
|
|
25
30
|
const digest = createHash("sha256").update(Buffer.from(publicKeyBase64, "base64")).digest();
|
|
26
31
|
return Array.from(
|
|
@@ -40,8 +45,23 @@ function resolveNodePath() {
|
|
|
40
45
|
}
|
|
41
46
|
function nativeMessagingHostsDir({
|
|
42
47
|
home = process.env.HOME || "",
|
|
43
|
-
platform = process.platform
|
|
48
|
+
platform = process.platform,
|
|
49
|
+
browser = "chrome"
|
|
44
50
|
} = {}) {
|
|
51
|
+
if (browser === "firefox") {
|
|
52
|
+
if (platform === "darwin") {
|
|
53
|
+
return resolve(home, "Library/Application Support/Mozilla/NativeMessagingHosts");
|
|
54
|
+
}
|
|
55
|
+
if (platform === "linux") {
|
|
56
|
+
return resolve(home, ".mozilla/native-messaging-hosts");
|
|
57
|
+
}
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Firefox native host installation is not implemented for platform "${platform}". Windows needs a registry value under HKCU\\Software\\Mozilla\\NativeMessagingHosts pointing at the manifest file.`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (browser !== "chrome") {
|
|
63
|
+
throw new Error(`Unknown native messaging browser target: "${browser}".`);
|
|
64
|
+
}
|
|
45
65
|
if (platform === "darwin") {
|
|
46
66
|
return resolve(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts");
|
|
47
67
|
}
|
|
@@ -55,54 +75,71 @@ function nativeMessagingHostsDir({
|
|
|
55
75
|
function resolveNativeHostInstallPaths({
|
|
56
76
|
home = process.env.HOME || "",
|
|
57
77
|
connectorRoot = DEFAULT_CONNECTOR_ROOT,
|
|
58
|
-
platform = process.platform
|
|
78
|
+
platform = process.platform,
|
|
79
|
+
browser = "chrome"
|
|
59
80
|
} = {}) {
|
|
60
81
|
const supportDir = resolve(home, "Library/Application Support/Nolo/ChromeConnector");
|
|
82
|
+
const wrapperName = browser === "firefox" ? "nolo-firefox-native-host" : "nolo-chrome-native-host";
|
|
61
83
|
return {
|
|
62
84
|
connectorRoot,
|
|
85
|
+
browser,
|
|
63
86
|
extensionManifestPath: resolve(connectorRoot, "extension", "manifest.json"),
|
|
64
87
|
hostPath: resolve(connectorRoot, "native-host", "nolo-chrome-native-host.mjs"),
|
|
65
88
|
templatePath: resolve(connectorRoot, "native-host", "com.nolo.chrome_connector.json"),
|
|
66
89
|
nativeManifestPath: resolve(
|
|
67
|
-
nativeMessagingHostsDir({ home, platform }),
|
|
90
|
+
nativeMessagingHostsDir({ home, platform, browser }),
|
|
68
91
|
"com.nolo.chrome_connector.json"
|
|
69
92
|
),
|
|
70
93
|
supportDir,
|
|
71
94
|
tokenPath: resolve(supportDir, "token"),
|
|
72
|
-
wrapperPath: resolve(supportDir,
|
|
95
|
+
wrapperPath: resolve(supportDir, wrapperName)
|
|
73
96
|
};
|
|
74
97
|
}
|
|
98
|
+
function connectorPortForBrowser({ browser = "chrome", env = process.env } = {}) {
|
|
99
|
+
if (browser === "firefox") {
|
|
100
|
+
return Number(env.NOLO_FIREFOX_CONNECTOR_PORT || 38948);
|
|
101
|
+
}
|
|
102
|
+
return Number(env.NOLO_CHROME_CONNECTOR_PORT || 38947);
|
|
103
|
+
}
|
|
75
104
|
function installNativeHostManifest({
|
|
76
105
|
home = process.env.HOME || "",
|
|
77
106
|
connectorRoot = DEFAULT_CONNECTOR_ROOT,
|
|
78
107
|
platform = process.platform,
|
|
79
108
|
extensionId,
|
|
80
|
-
nodePath
|
|
109
|
+
nodePath,
|
|
110
|
+
browser = "chrome"
|
|
81
111
|
} = {}) {
|
|
82
|
-
const paths = resolveNativeHostInstallPaths({ home, connectorRoot, platform });
|
|
112
|
+
const paths = resolveNativeHostInstallPaths({ home, connectorRoot, platform, browser });
|
|
83
113
|
const manifest = JSON.parse(readFileSync(paths.templatePath, "utf8"));
|
|
84
114
|
const extensionManifest = JSON.parse(readFileSync(paths.extensionManifestPath, "utf8"));
|
|
85
|
-
const resolvedExtensionId = extensionId || extensionIdFromPublicKey(extensionManifest.key);
|
|
115
|
+
const resolvedExtensionId = extensionId || (browser === "firefox" ? FIREFOX_EXTENSION_ID : extensionIdFromPublicKey(extensionManifest.key));
|
|
86
116
|
const resolvedNodePath = nodePath || resolveNodePath();
|
|
87
117
|
mkdirSync(paths.supportDir, { recursive: true });
|
|
88
118
|
const existingToken = existsSync(paths.tokenPath) ? readFileSync(paths.tokenPath, "utf8").trim() : "";
|
|
89
119
|
const token = existingToken || randomBytes(32).toString("hex");
|
|
90
120
|
writeFileSync(paths.tokenPath, `${token}
|
|
91
121
|
`, { mode: 384 });
|
|
122
|
+
const port = connectorPortForBrowser({ browser });
|
|
92
123
|
writeFileSync(
|
|
93
124
|
paths.wrapperPath,
|
|
94
125
|
`#!/bin/sh
|
|
95
|
-
NOLO_CHROME_CONNECTOR_TOKEN=${JSON.stringify(token)} exec ${JSON.stringify(resolvedNodePath)} ${JSON.stringify(paths.hostPath)}
|
|
126
|
+
NOLO_CHROME_CONNECTOR_BROWSER=${JSON.stringify(browser)} NOLO_CHROME_CONNECTOR_TOKEN=${JSON.stringify(token)} ${browser === "firefox" ? `NOLO_FIREFOX_CONNECTOR_PORT=${JSON.stringify(String(port))} ` : ""}exec ${JSON.stringify(resolvedNodePath)} ${JSON.stringify(paths.hostPath)}
|
|
96
127
|
`
|
|
97
128
|
);
|
|
98
129
|
chmodSync(paths.wrapperPath, 493);
|
|
99
130
|
manifest.path = paths.wrapperPath;
|
|
100
|
-
|
|
131
|
+
if (browser === "firefox") {
|
|
132
|
+
delete manifest.allowed_origins;
|
|
133
|
+
manifest.allowed_extensions = [FIREFOX_EXTENSION_ID];
|
|
134
|
+
} else {
|
|
135
|
+
manifest.allowed_origins = [`chrome-extension://${resolvedExtensionId}/`];
|
|
136
|
+
}
|
|
101
137
|
mkdirSync(dirname(paths.nativeManifestPath), { recursive: true });
|
|
102
138
|
writeFileSync(paths.nativeManifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
103
139
|
`);
|
|
104
140
|
return {
|
|
105
141
|
extensionId: resolvedExtensionId,
|
|
142
|
+
browser,
|
|
106
143
|
nodePath: resolvedNodePath,
|
|
107
144
|
tokenPath: paths.tokenPath,
|
|
108
145
|
...paths
|
|
@@ -119,6 +156,79 @@ var CLI_CONNECTOR_ROOT_CANDIDATES = [
|
|
|
119
156
|
var FULL_SUPPORT_CHROME_FEATURES = [
|
|
120
157
|
...new Set(Object.values(REQUIRED_CHROME_CONNECTOR_FEATURES).flat())
|
|
121
158
|
].sort();
|
|
159
|
+
var FIREFOX_UNAVAILABLE_FEATURES = ["browser_debug", "file_upload"];
|
|
160
|
+
function resolveConnectorBrowser(extensionId) {
|
|
161
|
+
if (!extensionId) return null;
|
|
162
|
+
if (extensionId === NOLO_FIREFOX_CONNECTOR_EXTENSION_ID) return "firefox";
|
|
163
|
+
if (NOLO_CONNECTOR_EXTENSION_IDS.includes(extensionId)) return "chrome";
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
function expectedFeaturesForBrowser(browser) {
|
|
167
|
+
return browser === "firefox" ? FULL_SUPPORT_CHROME_FEATURES.filter(
|
|
168
|
+
(feature) => !FIREFOX_UNAVAILABLE_FEATURES.includes(feature)
|
|
169
|
+
) : FULL_SUPPORT_CHROME_FEATURES;
|
|
170
|
+
}
|
|
171
|
+
function browserLabel(browser) {
|
|
172
|
+
return browser === "firefox" ? "Firefox" : browser === "chrome" ? "Chrome" : "browser";
|
|
173
|
+
}
|
|
174
|
+
async function fetchOnlineBuildSha(fetchImpl = fetch, timeoutMs = 3e3) {
|
|
175
|
+
try {
|
|
176
|
+
const controller = new AbortController();
|
|
177
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
178
|
+
const res = await fetchImpl("https://us.nolo.chat/public/latest-assets.json", {
|
|
179
|
+
signal: controller.signal
|
|
180
|
+
}).finally(() => clearTimeout(timer));
|
|
181
|
+
if (!res.ok) return null;
|
|
182
|
+
const data = await res.json();
|
|
183
|
+
return typeof data?.buildSha === "string" ? data.buildSha : null;
|
|
184
|
+
} catch {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function resolveLocalHeadSha() {
|
|
189
|
+
try {
|
|
190
|
+
const result = spawnSync("git", ["rev-parse", "HEAD"], {
|
|
191
|
+
encoding: "utf8",
|
|
192
|
+
timeout: 3e3,
|
|
193
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
194
|
+
});
|
|
195
|
+
if (result.status === 0 && typeof result.stdout === "string") {
|
|
196
|
+
const sha = result.stdout.trim();
|
|
197
|
+
return sha.length >= 7 ? sha : null;
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
} catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function compareDeployShas(localSha, onlineSha) {
|
|
205
|
+
if (!localSha || !onlineSha) return "unknown";
|
|
206
|
+
if (localSha === onlineSha || localSha.slice(0, 7) === onlineSha.slice(0, 7)) {
|
|
207
|
+
return "in sync";
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const localAhead = spawnSync("git", ["merge-base", "--is-ancestor", onlineSha, localSha], {
|
|
211
|
+
timeout: 3e3,
|
|
212
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
213
|
+
});
|
|
214
|
+
if (localAhead.status === 0) return "local ahead";
|
|
215
|
+
const onlineAhead = spawnSync("git", ["merge-base", "--is-ancestor", localSha, onlineSha], {
|
|
216
|
+
timeout: 3e3,
|
|
217
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
218
|
+
});
|
|
219
|
+
if (onlineAhead.status === 0) return "online ahead";
|
|
220
|
+
const objCheck = spawnSync("git", ["cat-file", "-e", `${onlineSha}^{commit}`], {
|
|
221
|
+
timeout: 3e3,
|
|
222
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
223
|
+
});
|
|
224
|
+
if (objCheck.status === 0) {
|
|
225
|
+
return "diverged";
|
|
226
|
+
}
|
|
227
|
+
return "unknown";
|
|
228
|
+
} catch {
|
|
229
|
+
return "unknown";
|
|
230
|
+
}
|
|
231
|
+
}
|
|
122
232
|
function pickCliConnectorRoot(candidates) {
|
|
123
233
|
for (const candidate of candidates) {
|
|
124
234
|
if (existsSync2(resolve2(candidate, "extension", "manifest.json"))) return candidate;
|
|
@@ -158,7 +268,7 @@ function detectWorktreeCheckout(connectorRoot) {
|
|
|
158
268
|
if (existsSync2(gitEntry)) {
|
|
159
269
|
let isGitFile = null;
|
|
160
270
|
try {
|
|
161
|
-
isGitFile =
|
|
271
|
+
isGitFile = statSync2(gitEntry).isFile();
|
|
162
272
|
} catch {
|
|
163
273
|
}
|
|
164
274
|
if (isGitFile === true) {
|
|
@@ -233,9 +343,13 @@ async function probeConnectorRpc(requestChrome) {
|
|
|
233
343
|
}
|
|
234
344
|
}
|
|
235
345
|
function resolveStatusNextStep(report) {
|
|
346
|
+
const targetBrowser = report.rpc.browser ?? report.nativeHost.browser;
|
|
347
|
+
const installCmd = targetBrowser === "firefox" ? "nolo chrome install --browser firefox" : "nolo chrome install";
|
|
348
|
+
const connectedLabel = browserLabel(targetBrowser);
|
|
349
|
+
const browserText = connectedLabel === "browser" ? "the browser" : connectedLabel;
|
|
236
350
|
if (!report.connectorRoot) {
|
|
237
351
|
if (report.rpc.online && report.rpc.protocolVersion === report.rpc.expectedProtocolVersion) {
|
|
238
|
-
return "
|
|
352
|
+
return "The Nolo Browser Connector is online, but this CLI cannot see a connector checkout, so `nolo chrome install` / manifest checks are unavailable here. Set NOLO_CHROME_CONNECTOR_ROOT (or run the CLI from a repo checkout) to enable them.";
|
|
239
353
|
}
|
|
240
354
|
return "Run the CLI from a repo checkout that contains packages/desktop-chrome-connector, or set NOLO_CHROME_CONNECTOR_ROOT to one, then rerun `nolo chrome status`.";
|
|
241
355
|
}
|
|
@@ -243,20 +357,20 @@ function resolveStatusNextStep(report) {
|
|
|
243
357
|
return `This platform has no supported native messaging host install (Chrome looks the host up through a registry value on Windows), so non-interactive install is not available: ${report.nativeHost.platformError ?? "unsupported platform"}`;
|
|
244
358
|
}
|
|
245
359
|
if (!report.nativeHost.installed || !report.token.present) {
|
|
246
|
-
return
|
|
360
|
+
return installCmd;
|
|
247
361
|
}
|
|
248
362
|
if (!report.nativeHost.wrapperPathMatches || !report.nativeHost.allowedOriginMatches) {
|
|
249
363
|
const installedWrapperPath = report.nativeHost.installedWrapperPath;
|
|
250
364
|
if (!report.nativeHost.wrapperPathMatches && installedWrapperPath && installedWrapperPath !== report.nativeHost.wrapperPath && existsSync2(installedWrapperPath)) {
|
|
251
|
-
return `Native host is installed for a different checkout (${installedWrapperPath}); this CLI is looking at ${report.connectorRoot}. Run \`nolo chrome status\` from the checkout that installed it, or run \`
|
|
365
|
+
return `Native host is installed for a different checkout (${installedWrapperPath}); this CLI is looking at ${report.connectorRoot}. Run \`nolo chrome status\` from the checkout that installed it, or run \`${installCmd}\` from here only if ${browserText} should switch to this one.`;
|
|
252
366
|
}
|
|
253
|
-
return
|
|
367
|
+
return `${installCmd} (the installed manifest does not point at this checkout's wrapper / extension id, which ${browserText} silently ignores)`;
|
|
254
368
|
}
|
|
255
369
|
if (!report.rpc.online) {
|
|
256
|
-
return `Load the unpacked extension from ${report.extension.path} in chrome://extensions (
|
|
370
|
+
return `Load the unpacked extension from ${report.extension.path} in chrome://extensions (Chrome) or about:debugging#/runtime/this-firefox (Firefox), or install the Nolo Browser Connector from https://nolo.chat/downloads, then rerun \`nolo chrome status\`.`;
|
|
257
371
|
}
|
|
258
|
-
if (report.rpc.extensionId && report.rpc.
|
|
259
|
-
return `The connected extension (${report.rpc.extensionId}) is not
|
|
372
|
+
if (report.rpc.extensionId && report.rpc.browser === null) {
|
|
373
|
+
return `The connected extension (${report.rpc.extensionId}) is not a recognized Nolo Browser Connector build; reload it (\`nolo chrome reload\`) or remove the other copy, then rerun \`nolo chrome status\`.`;
|
|
260
374
|
}
|
|
261
375
|
if (report.rpc.protocolVersion !== report.rpc.expectedProtocolVersion) {
|
|
262
376
|
return `nolo chrome reload (the running extension does not speak protocol ${report.rpc.expectedProtocolVersion}; a reload restarts the worker with the files on disk)`;
|
|
@@ -264,12 +378,13 @@ function resolveStatusNextStep(report) {
|
|
|
264
378
|
if (report.rpc.missingFeatures.length > 0) {
|
|
265
379
|
return `nolo chrome reload (the running extension is missing ${report.rpc.missingFeatures.join(", ")}); if that persists, the checkout's extension is older than the CLI expects.`;
|
|
266
380
|
}
|
|
267
|
-
return
|
|
381
|
+
return `The Nolo Browser Connector is online (${connectedLabel}): connector tools execute against this ${connectedLabel} profile.`;
|
|
268
382
|
}
|
|
269
383
|
async function buildChromeConnectorStatus(args = {}) {
|
|
270
384
|
const env = args.env ?? process.env;
|
|
271
385
|
const home = args.home ?? env.HOME ?? "";
|
|
272
386
|
const platform = args.platform ?? process.platform;
|
|
387
|
+
const browserTarget = args.browser;
|
|
273
388
|
let connectorRoot = args.connectorRoot ?? null;
|
|
274
389
|
let rootError = null;
|
|
275
390
|
if (!connectorRoot) {
|
|
@@ -295,38 +410,112 @@ async function buildChromeConnectorStatus(args = {}) {
|
|
|
295
410
|
wrapperPath: null,
|
|
296
411
|
installedWrapperPath: null,
|
|
297
412
|
wrapperPathMatches: false,
|
|
298
|
-
allowedOriginMatches: false
|
|
413
|
+
allowedOriginMatches: false,
|
|
414
|
+
browser: null
|
|
299
415
|
},
|
|
300
416
|
token: { path: null, present: false },
|
|
417
|
+
uploadRoots: { roots: [], isDefault: false },
|
|
418
|
+
deploy: {
|
|
419
|
+
localSha: null,
|
|
420
|
+
onlineSha: null,
|
|
421
|
+
sync: "unknown"
|
|
422
|
+
},
|
|
301
423
|
rpc: {
|
|
302
424
|
online: false,
|
|
303
425
|
extensionId: null,
|
|
304
426
|
protocolVersion: null,
|
|
305
427
|
features: [],
|
|
428
|
+
browser: null,
|
|
306
429
|
missingFeatures: [...FULL_SUPPORT_CHROME_FEATURES],
|
|
307
430
|
expectedProtocolVersion: NOLO_CHROME_CONNECTOR_PROTOCOL_VERSION
|
|
308
431
|
},
|
|
309
432
|
nextStep: ""
|
|
310
433
|
};
|
|
311
|
-
|
|
434
|
+
try {
|
|
435
|
+
const rootsInfo = resolveUploadRoots({ ...env, ...home ? { HOME: home } : {} });
|
|
436
|
+
report.uploadRoots = {
|
|
437
|
+
roots: rootsInfo.roots,
|
|
438
|
+
isDefault: rootsInfo.isDefault
|
|
439
|
+
};
|
|
440
|
+
} catch (error) {
|
|
441
|
+
report.uploadRoots = {
|
|
442
|
+
roots: [],
|
|
443
|
+
isDefault: false,
|
|
444
|
+
error: toErrorMessage(error)
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
let localHeadSha = null;
|
|
448
|
+
try {
|
|
449
|
+
localHeadSha = (args.resolveLocalHeadSha ?? resolveLocalHeadSha)();
|
|
450
|
+
} catch {
|
|
451
|
+
localHeadSha = null;
|
|
452
|
+
}
|
|
453
|
+
let onlineBuildSha = null;
|
|
454
|
+
try {
|
|
455
|
+
onlineBuildSha = await (args.fetchOnlineBuildSha ?? fetchOnlineBuildSha)();
|
|
456
|
+
} catch {
|
|
457
|
+
onlineBuildSha = null;
|
|
458
|
+
}
|
|
459
|
+
let sync = "unknown";
|
|
460
|
+
try {
|
|
461
|
+
const compareShas = args.compareDeployShas ?? compareDeployShas;
|
|
462
|
+
sync = compareShas(localHeadSha, onlineBuildSha);
|
|
463
|
+
} catch {
|
|
464
|
+
sync = "unknown";
|
|
465
|
+
}
|
|
466
|
+
report.deploy = {
|
|
467
|
+
localSha: localHeadSha,
|
|
468
|
+
onlineSha: onlineBuildSha,
|
|
469
|
+
sync
|
|
470
|
+
};
|
|
471
|
+
const requestChrome = args.requestChrome ?? createChromeConnectorClient({ browser: browserTarget }).request;
|
|
312
472
|
const probe = await probeConnectorRpc(requestChrome);
|
|
313
473
|
report.rpc.online = probe.online;
|
|
314
474
|
report.rpc.extensionId = probe.extensionId;
|
|
315
475
|
report.rpc.protocolVersion = probe.protocolVersion;
|
|
316
476
|
report.rpc.features = probe.features;
|
|
317
|
-
report.rpc.
|
|
477
|
+
report.rpc.browser = probe.online ? resolveConnectorBrowser(probe.extensionId) ?? (probe.extensionId === expectedId ? "chrome" : null) : null;
|
|
478
|
+
report.rpc.missingFeatures = expectedFeaturesForBrowser(report.rpc.browser).filter(
|
|
318
479
|
(feature) => !probe.features.includes(feature)
|
|
319
480
|
);
|
|
320
481
|
if (!probe.online) report.rpc.error = probe.error;
|
|
321
482
|
if (!connectorRoot) {
|
|
322
483
|
if (rootError) report.connectorRootError = rootError;
|
|
323
|
-
report.
|
|
484
|
+
report.nativeHost.browser = report.rpc.browser;
|
|
485
|
+
report.ok = report.rpc.online && report.rpc.browser !== null && probe.protocolVersion === NOLO_CHROME_CONNECTOR_PROTOCOL_VERSION && report.rpc.missingFeatures.length === 0;
|
|
324
486
|
report.nextStep = resolveStatusNextStep(report);
|
|
325
487
|
return report;
|
|
326
488
|
}
|
|
489
|
+
let manifestBrowser = browserTarget ?? (report.rpc.browser === "firefox" ? "firefox" : "chrome");
|
|
490
|
+
if (!report.rpc.browser) {
|
|
491
|
+
try {
|
|
492
|
+
const chromeManifestPath = resolveNativeHostInstallPaths({
|
|
493
|
+
home,
|
|
494
|
+
connectorRoot,
|
|
495
|
+
platform,
|
|
496
|
+
browser: "chrome"
|
|
497
|
+
}).nativeManifestPath;
|
|
498
|
+
const firefoxManifestPath = resolveNativeHostInstallPaths({
|
|
499
|
+
home,
|
|
500
|
+
connectorRoot,
|
|
501
|
+
platform,
|
|
502
|
+
browser: "firefox"
|
|
503
|
+
}).nativeManifestPath;
|
|
504
|
+
if (!existsSync2(chromeManifestPath) && existsSync2(firefoxManifestPath)) {
|
|
505
|
+
manifestBrowser = "firefox";
|
|
506
|
+
}
|
|
507
|
+
} catch {
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
report.nativeHost.browser = manifestBrowser;
|
|
327
511
|
let paths = null;
|
|
328
512
|
try {
|
|
329
|
-
paths = resolveNativeHostInstallPaths({
|
|
513
|
+
paths = resolveNativeHostInstallPaths({
|
|
514
|
+
home,
|
|
515
|
+
connectorRoot,
|
|
516
|
+
platform,
|
|
517
|
+
browser: manifestBrowser
|
|
518
|
+
});
|
|
330
519
|
} catch (error) {
|
|
331
520
|
report.nativeHost.supported = false;
|
|
332
521
|
report.nativeHost.platformError = toErrorMessage(error);
|
|
@@ -340,8 +529,7 @@ async function buildChromeConnectorStatus(args = {}) {
|
|
|
340
529
|
report.nativeHost.installed = installedManifest !== null;
|
|
341
530
|
report.nativeHost.installedWrapperPath = typeof installedManifest?.path === "string" ? installedManifest.path : null;
|
|
342
531
|
report.nativeHost.wrapperPathMatches = report.nativeHost.installedWrapperPath === paths.wrapperPath;
|
|
343
|
-
|
|
344
|
-
report.nativeHost.allowedOriginMatches = Array.isArray(installedManifest?.allowed_origins) && installedManifest.allowed_origins.includes(expectedOrigin);
|
|
532
|
+
report.nativeHost.allowedOriginMatches = manifestBrowser === "firefox" ? Array.isArray(installedManifest?.allowed_extensions) && installedManifest.allowed_extensions.includes(NOLO_FIREFOX_CONNECTOR_EXTENSION_ID) : Array.isArray(installedManifest?.allowed_origins) && installedManifest.allowed_origins.includes(`chrome-extension://${expectedId}/`);
|
|
345
533
|
if (existsSync2(paths.tokenPath)) {
|
|
346
534
|
try {
|
|
347
535
|
report.token.present = readFileSync2(paths.tokenPath, "utf8").trim().length > 0;
|
|
@@ -349,7 +537,7 @@ async function buildChromeConnectorStatus(args = {}) {
|
|
|
349
537
|
report.token.present = false;
|
|
350
538
|
}
|
|
351
539
|
}
|
|
352
|
-
report.ok = report.nativeHost.supported && report.nativeHost.installed && report.nativeHost.wrapperPathMatches && report.nativeHost.allowedOriginMatches && report.token.present && probe.online &&
|
|
540
|
+
report.ok = report.nativeHost.supported && report.nativeHost.installed && report.nativeHost.wrapperPathMatches && report.nativeHost.allowedOriginMatches && report.token.present && probe.online && report.rpc.browser !== null && probe.protocolVersion === NOLO_CHROME_CONNECTOR_PROTOCOL_VERSION && report.rpc.missingFeatures.length === 0;
|
|
353
541
|
report.nextStep = resolveStatusNextStep(report);
|
|
354
542
|
return report;
|
|
355
543
|
}
|
|
@@ -357,7 +545,7 @@ function yesNo(value) {
|
|
|
357
545
|
return value ? "ok" : "mismatch";
|
|
358
546
|
}
|
|
359
547
|
function formatChromeConnectorStatus(report) {
|
|
360
|
-
const lines = ["Nolo
|
|
548
|
+
const lines = ["Nolo Browser Connector"];
|
|
361
549
|
lines.push(
|
|
362
550
|
` connector source : ${report.connectorRoot ?? "(not found)"}`
|
|
363
551
|
);
|
|
@@ -374,10 +562,21 @@ function formatChromeConnectorStatus(report) {
|
|
|
374
562
|
lines.push(
|
|
375
563
|
` token : ${report.token.present ? "present" : "missing"}${report.token.path ? ` ${report.token.path}` : ""}`
|
|
376
564
|
);
|
|
565
|
+
if (report.uploadRoots.error) {
|
|
566
|
+
lines.push(` upload roots : error (${report.uploadRoots.error})`);
|
|
567
|
+
} else if (report.uploadRoots.roots.length > 0) {
|
|
568
|
+
const originLabel = report.uploadRoots.isDefault ? "default" : "configured";
|
|
569
|
+
lines.push(` upload roots : ${report.uploadRoots.roots.join(", ")} (${originLabel})`);
|
|
570
|
+
} else {
|
|
571
|
+
lines.push(` upload roots : (none)`);
|
|
572
|
+
}
|
|
573
|
+
const localShort = report.deploy.localSha ? report.deploy.localSha.slice(0, 7) : "unknown";
|
|
574
|
+
const onlineShort = report.deploy.onlineSha ? report.deploy.onlineSha.slice(0, 7) : "unknown";
|
|
575
|
+
lines.push(` deploy status : local ${localShort} online ${onlineShort} (${report.deploy.sync})`);
|
|
377
576
|
const rpc = report.rpc;
|
|
378
577
|
if (rpc.online) {
|
|
379
578
|
lines.push(
|
|
380
|
-
` RPC : online extension ${rpc.extensionId ?? "unknown"} protocolVersion ${rpc.protocolVersion ?? "unknown"} features ${rpc.features.length > 0 ? rpc.features.join(", ") : "(none)"}`
|
|
579
|
+
` RPC : online browser ${rpc.browser ?? "unrecognized"} extension ${rpc.extensionId ?? "unknown"} protocolVersion ${rpc.protocolVersion ?? "unknown"} features ${rpc.features.length > 0 ? rpc.features.join(", ") : "(none)"}`
|
|
381
580
|
);
|
|
382
581
|
} else {
|
|
383
582
|
lines.push(
|
|
@@ -390,9 +589,14 @@ function formatChromeConnectorStatus(report) {
|
|
|
390
589
|
}
|
|
391
590
|
async function runChromeStatusCommand(args, deps = {}) {
|
|
392
591
|
const output = deps.output ?? process.stdout;
|
|
592
|
+
const browser = readBrowserOption(args);
|
|
593
|
+
if (browser === null) {
|
|
594
|
+
output.write('[nolo] Chrome connector status failed: --browser must be "chrome" or "firefox".\n');
|
|
595
|
+
return 1;
|
|
596
|
+
}
|
|
393
597
|
let report;
|
|
394
598
|
try {
|
|
395
|
-
report = await buildChromeConnectorStatus(deps);
|
|
599
|
+
report = await buildChromeConnectorStatus({ ...deps, browser });
|
|
396
600
|
} catch (error) {
|
|
397
601
|
output.write(`[nolo] Chrome connector status failed: ${toErrorMessage(error)}
|
|
398
602
|
`);
|
|
@@ -406,9 +610,26 @@ async function runChromeStatusCommand(args, deps = {}) {
|
|
|
406
610
|
}
|
|
407
611
|
return report.ok ? 0 : 1;
|
|
408
612
|
}
|
|
613
|
+
function readBrowserOption(args) {
|
|
614
|
+
const equalsForm = args.find((arg) => arg.startsWith("--browser="));
|
|
615
|
+
const index = args.indexOf("--browser");
|
|
616
|
+
const raw = equalsForm !== void 0 ? equalsForm.slice("--browser=".length) : index >= 0 ? args[index + 1] : void 0;
|
|
617
|
+
if (raw === void 0) return void 0;
|
|
618
|
+
const value = raw.trim();
|
|
619
|
+
if (value === "chrome" || value === "firefox") return value;
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
409
622
|
async function runChromeInstallCommand(args, deps = {}) {
|
|
410
623
|
const env = deps.env ?? process.env;
|
|
411
624
|
const output = deps.output ?? process.stdout;
|
|
625
|
+
const parsed = readBrowserOption(args);
|
|
626
|
+
if (parsed === null) {
|
|
627
|
+
output.write(
|
|
628
|
+
'[nolo] Chrome native host install failed: --browser must be "chrome" or "firefox".\n'
|
|
629
|
+
);
|
|
630
|
+
return 1;
|
|
631
|
+
}
|
|
632
|
+
const browser = parsed ?? "chrome";
|
|
412
633
|
const install = deps.installNativeHost ?? installNativeHostManifest;
|
|
413
634
|
let connectorRoot;
|
|
414
635
|
try {
|
|
@@ -432,6 +653,7 @@ async function runChromeInstallCommand(args, deps = {}) {
|
|
|
432
653
|
result = install({
|
|
433
654
|
home: deps.home ?? env.HOME ?? "",
|
|
434
655
|
connectorRoot,
|
|
656
|
+
browser,
|
|
435
657
|
...deps.platform ? { platform: deps.platform } : {},
|
|
436
658
|
...deps.nodePath ? { nodePath: deps.nodePath } : {}
|
|
437
659
|
});
|
|
@@ -446,12 +668,12 @@ async function runChromeInstallCommand(args, deps = {}) {
|
|
|
446
668
|
} else {
|
|
447
669
|
output.write(
|
|
448
670
|
[
|
|
449
|
-
|
|
671
|
+
`Nolo Browser Connector native host installed (${browser}).`,
|
|
450
672
|
` manifest : ${result.nativeManifestPath}`,
|
|
451
673
|
` wrapper : ${result.wrapperPath} -> ${result.nodePath}`,
|
|
452
674
|
` token : ${result.tokenPath} (an existing token is kept, so reruns are idempotent)`,
|
|
453
675
|
` extension: ${result.extensionId}`,
|
|
454
|
-
`Next step: load the unpacked extension from ${resolve2(connectorRoot, "extension")} in chrome://extensions (Developer mode) or install
|
|
676
|
+
`Next step: load the unpacked extension from ${resolve2(connectorRoot, "extension")} in ` + (browser === "firefox" ? "about:debugging#/runtime/this-firefox, or install the signed Nolo Browser Connector add-on from https://nolo.chat/downloads, then run `nolo chrome status`." : "chrome://extensions (Developer mode), or install the Nolo Browser Connector from https://nolo.chat/downloads (Chrome or Firefox), then run `nolo chrome status`."),
|
|
455
677
|
""
|
|
456
678
|
].join("\n")
|
|
457
679
|
);
|
|
@@ -460,8 +682,32 @@ async function runChromeInstallCommand(args, deps = {}) {
|
|
|
460
682
|
}
|
|
461
683
|
async function runChromeReloadCommand(args, deps = {}) {
|
|
462
684
|
const output = deps.output ?? process.stdout;
|
|
463
|
-
const
|
|
685
|
+
const browser = readBrowserOption(args);
|
|
686
|
+
if (browser === null) {
|
|
687
|
+
output.write('[nolo] Chrome connector reload failed: --browser must be "chrome" or "firefox".\n');
|
|
688
|
+
return 1;
|
|
689
|
+
}
|
|
690
|
+
const requestChrome = deps.requestChrome ?? createChromeConnectorClient({ browser }).request;
|
|
464
691
|
try {
|
|
692
|
+
if (browser) {
|
|
693
|
+
try {
|
|
694
|
+
const info = await requestChrome("connector_info", {});
|
|
695
|
+
const connectedBrowser = resolveConnectorBrowser(
|
|
696
|
+
typeof info?.extensionId === "string" ? info.extensionId : null
|
|
697
|
+
);
|
|
698
|
+
if (connectedBrowser !== null && connectedBrowser !== browser) {
|
|
699
|
+
const mismatch = new Error(
|
|
700
|
+
`the connector on this endpoint answers as ${browserLabel(connectedBrowser)}, not ${browserLabel(browser)} \u2014 refusing to reload the wrong browser. Check NOLO_CHROME_CONNECTOR_RPC_URL / the per-browser port overrides.`
|
|
701
|
+
);
|
|
702
|
+
mismatch.code = "CHROME_CONNECTOR_EXTENSION_MISMATCH";
|
|
703
|
+
throw mismatch;
|
|
704
|
+
}
|
|
705
|
+
} catch (error) {
|
|
706
|
+
if (error?.code === "CHROME_CONNECTOR_EXTENSION_MISMATCH") {
|
|
707
|
+
throw error;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
465
711
|
const result = await requestChrome("reload_extension", {});
|
|
466
712
|
if (args.includes("--json")) {
|
|
467
713
|
output.write(`${JSON.stringify({ ok: true, result }, null, 2)}
|
|
@@ -480,7 +726,7 @@ The connector service worker restarts within ~1s; verify with \`nolo chrome stat
|
|
|
480
726
|
`);
|
|
481
727
|
if (code === "CHROME_CONNECTOR_UNAVAILABLE") {
|
|
482
728
|
output.write(
|
|
483
|
-
"The native host is not reachable: load the unpacked connector extension in chrome://extensions
|
|
729
|
+
"The native host is not reachable: open Chrome or Firefox with the Nolo Browser Connector extension enabled, or install it from https://nolo.chat/downloads (or load the unpacked connector extension in chrome://extensions), then rerun `nolo chrome reload`.\n"
|
|
484
730
|
);
|
|
485
731
|
}
|
|
486
732
|
return 1;
|
|
@@ -488,11 +734,17 @@ The connector service worker restarts within ~1s; verify with \`nolo chrome stat
|
|
|
488
734
|
}
|
|
489
735
|
export {
|
|
490
736
|
CLI_CONNECTOR_ROOT_CANDIDATES,
|
|
737
|
+
FIREFOX_UNAVAILABLE_FEATURES,
|
|
491
738
|
FULL_SUPPORT_CHROME_FEATURES,
|
|
492
739
|
buildChromeConnectorStatus,
|
|
740
|
+
compareDeployShas,
|
|
493
741
|
detectWorktreeCheckout,
|
|
742
|
+
expectedFeaturesForBrowser,
|
|
743
|
+
fetchOnlineBuildSha,
|
|
494
744
|
formatChromeConnectorStatus,
|
|
495
745
|
resolveCliConnectorRoot,
|
|
746
|
+
resolveConnectorBrowser,
|
|
747
|
+
resolveLocalHeadSha,
|
|
496
748
|
runChromeInstallCommand,
|
|
497
749
|
runChromeReloadCommand,
|
|
498
750
|
runChromeStatusCommand
|