local-operator-ui 0.39.5 → 0.39.7
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/out/main/index.js +689 -93
- package/out/renderer/assets/{_basePickBy-BgM1I5lG.js → _basePickBy-CEnbnbbH.js} +1 -1
- package/out/renderer/assets/{_baseUniq-Bmkgy85v.js → _baseUniq-CdOS48Ck.js} +1 -1
- package/out/renderer/assets/{addressOverlayList-8wdZRD_t.css → addressOverlayList-B7X6o95l.css} +1 -1
- package/out/renderer/assets/{addressOverlayList-BEh9WU4R.js → addressOverlayList-SGt8bawf.js} +1 -1
- package/out/renderer/assets/{agent-details-page-Du26ZU6E.js → agent-details-page-tp9kdqtV.js} +1 -1
- package/out/renderer/assets/{agent-hub-page-BwVMuSzt.js → agent-hub-page-DLGKHTRy.js} +1 -1
- package/out/renderer/assets/{agents-page-BhSbjEpr.js → agents-page-zlHPJdIG.js} +3 -3
- package/out/renderer/assets/{arc-3zNC_x2n.js → arc-BNz9sDxF.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-IEHRJDOE-CtDg0QNg.js → architectureDiagram-IEHRJDOE-PT8IWaJd.js} +1 -1
- package/out/renderer/assets/{blockDiagram-JOT3LUYC-4XryKcIu.js → blockDiagram-JOT3LUYC-TofPikdt.js} +1 -1
- package/out/renderer/assets/{book-open-lnC7oth0.js → book-open-C9j4VQTg.js} +1 -1
- package/out/renderer/assets/browser-page-_iKE2RNe.js +1 -0
- package/out/renderer/assets/{browser-webauthn-prompt-BTC3LWcr.js → browser-webauthn-prompt-7G2sk0mv.js} +1 -1
- package/out/renderer/assets/{building-2-CRI7K1ut.js → building-2-C-Qj7y2j.js} +1 -1
- package/out/renderer/assets/{c4Diagram-VJAJSXHY-n2cPdK4v.js → c4Diagram-VJAJSXHY-aQCw2eBK.js} +1 -1
- package/out/renderer/assets/channel-ckpV6c4V.js +1 -0
- package/out/renderer/assets/{chunk-4BMEZGHF-P7BOtABr.js → chunk-4BMEZGHF-BfamF_Ga.js} +1 -1
- package/out/renderer/assets/{chunk-A2AXSNBT-BmO2P02x.js → chunk-A2AXSNBT-DkYCFJWH.js} +1 -1
- package/out/renderer/assets/{chunk-AEK57VVT-KMJMGzZF.js → chunk-AEK57VVT-BJsKs1c3.js} +1 -1
- package/out/renderer/assets/{chunk-D6G4REZN-WA3nwEd_.js → chunk-D6G4REZN-DQafTOcO.js} +1 -1
- package/out/renderer/assets/{chunk-RZ5BOZE2-C4md2pdG.js → chunk-RZ5BOZE2-BtdIGif_.js} +1 -1
- package/out/renderer/assets/{chunk-XZIHB7SX-MPSf1VFR.js → chunk-XZIHB7SX-CPFZQYMe.js} +1 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-B3X9me6N.js +1 -0
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-B3X9me6N.js +1 -0
- package/out/renderer/assets/clone-gWuEtEL1.js +1 -0
- package/out/renderer/assets/{console-mirror-CnVv9rOt.js → console-mirror-BKH21iCK.js} +14 -14
- package/out/renderer/assets/{consoleCapture-B_hi3E9g.js → consoleCapture-CVwDUtXD.js} +1 -1
- package/out/renderer/assets/{conversation-input-sync-CQ0nQbSV.js → conversation-input-sync-DTwv4LpE.js} +4 -4
- package/out/renderer/assets/{dagre-OKDRZEBW-QrYk8i27.js → dagre-OKDRZEBW-OgXmMciL.js} +1 -1
- package/out/renderer/assets/{diagram-SSKATNLV-CpIwEDtE.js → diagram-SSKATNLV-BmsZgHTq.js} +1 -1
- package/out/renderer/assets/{diagram-VNBRO52H-DtHOhSDJ.js → diagram-VNBRO52H-Cr9Grlgh.js} +1 -1
- package/out/renderer/assets/{erDiagram-Q7BY3M3F-AEs8Bb_A.js → erDiagram-Q7BY3M3F-fgqi2edy.js} +1 -1
- package/out/renderer/assets/{error-boundary-CU2PiR3H.js → error-boundary-aqUJ0ROL.js} +1 -1
- package/out/renderer/assets/{flowDiagram-4HSFHLVR-CliaNR7R.js → flowDiagram-4HSFHLVR-Clb0_Qdc.js} +1 -1
- package/out/renderer/assets/{ganttDiagram-APWFNJXF-Br5lLrlI.js → ganttDiagram-APWFNJXF-C2YI1HlL.js} +1 -1
- package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-D68CT6c8.js → gitGraphDiagram-7IBYFJ6S-Bcg0BnMu.js} +1 -1
- package/out/renderer/assets/{graph-LIDYSJHC.js → graph-BzD7EvQb.js} +1 -1
- package/out/renderer/assets/{hash-5VU7fofJ.js → hash-neDzbCXS.js} +1 -1
- package/out/renderer/assets/{index-Bpi83aqM.js → index-B16LGlVe.js} +1 -1
- package/out/renderer/assets/index-CQml9u-9.js +57 -0
- package/out/renderer/assets/{index-ZC-NNW64.css → index-CXsn7x-M.css} +1 -1
- package/out/renderer/assets/{index-BoQsbSXg.js → index-DTi580qk.js} +204 -199
- package/out/renderer/assets/{index-BpJ3H71K.js → index-_kad0jHX.js} +1 -1
- package/out/renderer/assets/{infoDiagram-PH2N3AL5-U0UUgi63.js → infoDiagram-PH2N3AL5-DUD1Zb9n.js} +1 -1
- package/out/renderer/assets/{installer-9uv2KfFf.js → installer-CmbKACIX.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-U35MCT3I-FFIRpntM.js → journeyDiagram-U35MCT3I-Bn1cTo4G.js} +1 -1
- package/out/renderer/assets/{kanban-definition-NDS4AKOZ-BRpcp-A3.js → kanban-definition-NDS4AKOZ-Bw7rDfia.js} +1 -1
- package/out/renderer/assets/{layout-MxBLCasM.js → layout-BDVYAAmD.js} +1 -1
- package/out/renderer/assets/{legacy-agents-page-D-vnYlfr.js → legacy-agents-page-CuQMfUeR.js} +1 -1
- package/out/renderer/assets/{library-page-D5TOCNDL.js → library-page-B9s2FYnU.js} +3 -3
- package/out/renderer/assets/{mermaid.core-D0JYobPd.js → mermaid.core-D-DUuSel.js} +5 -5
- package/out/renderer/assets/{mesh-page-MMyOu2-i.js → mesh-page-CwkFm-eu.js} +1 -1
- package/out/renderer/assets/{mindmap-definition-ALO5MXBD-BSmr1_Tl.js → mindmap-definition-ALO5MXBD-CiqYdj8Q.js} +1 -1
- package/out/renderer/assets/{mini-DX97EGZ9.js → mini-BVDybISg.js} +1 -1
- package/out/renderer/assets/{notebook-pen-CaY2CqYY.js → notebook-pen-DzZsHKPn.js} +1 -1
- package/out/renderer/assets/{org-access-D-BFcZvI.js → org-access-B2_ZIy5A.js} +1 -1
- package/out/renderer/assets/{org-surface-gate-BmRiAyd4.js → org-surface-gate-BygOcwMP.js} +1 -1
- package/out/renderer/assets/{page-header-B078STNU.js → page-header-CPOxzTkT.js} +1 -1
- package/out/renderer/assets/{pieDiagram-IB7DONF6-DkC-Pw7E.js → pieDiagram-IB7DONF6-B46iHAdf.js} +1 -1
- package/out/renderer/assets/{projects-page-2kYMpXGt.js → projects-page-Dnu4aFn8.js} +1 -1
- package/out/renderer/assets/{publication-validation-Cp6mINOP.js → publication-validation-Drtrxi_K.js} +1 -1
- package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-IVRMgBez.js → quadrantDiagram-7GDLP6J5-C75t3aEo.js} +1 -1
- package/out/renderer/assets/{radar-MK3ICKWK-sedwCyEl.js → radar-MK3ICKWK-CJBxj3CR.js} +1 -1
- package/out/renderer/assets/{radient-auth-buttons-vFQgdlYP.js → radient-auth-buttons-Bidxea5I.js} +1 -1
- package/out/renderer/assets/{requirementDiagram-KVF5MWMF-DwdfgrvA.js → requirementDiagram-KVF5MWMF-DU98zhsJ.js} +1 -1
- package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-BPvKdY7g.js → sankeyDiagram-QLVOVGJD-BZ6FyTnr.js} +1 -1
- package/out/renderer/assets/{schedules-page-BWxSAtp5.js → schedules-page-BuvWSSxo.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-swhS4JaV.js → sequenceDiagram-X6HHIX6F-mLpOc_fL.js} +1 -1
- package/out/renderer/assets/{settings-page-CNeq8zEo.js → settings-page-I6YHq2CK.js} +1 -1
- package/out/renderer/assets/{smartart-h3hobM9P.js → smartart-Dc8xSTBM.js} +1 -1
- package/out/renderer/assets/{stateDiagram-DGXRK772-DQjtzeCn.js → stateDiagram-DGXRK772-tqceD2-c.js} +1 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-BDhmSYxY.js +1 -0
- package/out/renderer/assets/{team-bridge-page-DwXTOl4x.js → team-bridge-page-DWzmxmoj.js} +1 -1
- package/out/renderer/assets/{timeline-definition-BDJGKUSR-BE4DUnJN.js → timeline-definition-BDJGKUSR-ByRwOK4b.js} +1 -1
- package/out/renderer/assets/ui-preferences-store-D031PAZ1.js +1 -0
- package/out/renderer/assets/{use-download-agent-mutation-C_zKpXBu.js → use-download-agent-mutation-DlpEsjDM.js} +1 -1
- package/out/renderer/assets/{use-session-snapshot-B6UGWZI5.js → use-session-snapshot-BvNfXQEV.js} +1 -1
- package/out/renderer/assets/{xychartDiagram-VJFVF3MP-D6nHKfw6.js → xychartDiagram-VJFVF3MP-RnUOVpB_.js} +1 -1
- package/out/renderer/browser-address-overlay-list.html +2 -2
- package/out/renderer/console-capture.html +5 -5
- package/out/renderer/index.html +7 -7
- package/out/renderer/installer.html +4 -4
- package/out/renderer/mini.html +7 -7
- package/package.json +2 -2
- package/out/renderer/assets/browser-page-CsoEGi9k.js +0 -1
- package/out/renderer/assets/channel-MJ9Q5Gdp.js +0 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-PYFoG-nl.js +0 -1
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-PYFoG-nl.js +0 -1
- package/out/renderer/assets/clone-BWjAp2XI.js +0 -1
- package/out/renderer/assets/index-B_mT8ft1.js +0 -57
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-BoHuPFVZ.js +0 -1
- package/out/renderer/assets/ui-preferences-store-DUB1goHr.js +0 -1
package/out/main/index.js
CHANGED
|
@@ -24765,7 +24765,7 @@ function consoleCompletionHooks(deps) {
|
|
|
24765
24765
|
const state2 = deps.host()?.state();
|
|
24766
24766
|
return state2?.displayed_surface === surface;
|
|
24767
24767
|
};
|
|
24768
|
-
const completionFor = (surface, exitCode, key) => {
|
|
24768
|
+
const completionFor = (surface, exitCode, key, exitSignal = null) => {
|
|
24769
24769
|
const described = describe2(surface);
|
|
24770
24770
|
if (!described) return null;
|
|
24771
24771
|
return {
|
|
@@ -24773,6 +24773,7 @@ function consoleCompletionHooks(deps) {
|
|
|
24773
24773
|
surface,
|
|
24774
24774
|
surfaceName: described.command,
|
|
24775
24775
|
exitCode,
|
|
24776
|
+
exitSignal,
|
|
24776
24777
|
displayed: displayed(surface),
|
|
24777
24778
|
key
|
|
24778
24779
|
};
|
|
@@ -24826,7 +24827,8 @@ function consoleCompletionHooks(deps) {
|
|
|
24826
24827
|
*/
|
|
24827
24828
|
onExit: ({
|
|
24828
24829
|
surface,
|
|
24829
|
-
exitCode
|
|
24830
|
+
exitCode,
|
|
24831
|
+
exitSignal
|
|
24830
24832
|
}) => {
|
|
24831
24833
|
const key = exitKey(surface);
|
|
24832
24834
|
const previous = lastBanner.get(surface);
|
|
@@ -24836,7 +24838,7 @@ function consoleCompletionHooks(deps) {
|
|
|
24836
24838
|
);
|
|
24837
24839
|
return;
|
|
24838
24840
|
}
|
|
24839
|
-
const notice = completionFor(surface, exitCode, key);
|
|
24841
|
+
const notice = completionFor(surface, exitCode, key, exitSignal ?? null);
|
|
24840
24842
|
if (notice) announce(notice, "exit");
|
|
24841
24843
|
}
|
|
24842
24844
|
};
|
|
@@ -25426,6 +25428,7 @@ class ConsoleRegistry {
|
|
|
25426
25428
|
rows: input.rows,
|
|
25427
25429
|
running: input.live !== false,
|
|
25428
25430
|
exitCode: null,
|
|
25431
|
+
exitSignal: null,
|
|
25429
25432
|
lastActivity: this.now(),
|
|
25430
25433
|
live: input.live !== false,
|
|
25431
25434
|
retain: input.retain,
|
|
@@ -25549,6 +25552,18 @@ const PERSIST_FLUSH_MS = 250;
|
|
|
25549
25552
|
const PERSIST_FLUSH_BYTES = 256 * 1024;
|
|
25550
25553
|
const FRAME_RETRY_DELAY_MS = 120;
|
|
25551
25554
|
const CLOSE_GRACE_MS = 1500;
|
|
25555
|
+
const QUIT_EXIT_CAPTURE_MS = 400;
|
|
25556
|
+
function signalName(signal) {
|
|
25557
|
+
if (typeof signal === "string") {
|
|
25558
|
+
if (signal.length === 0) return null;
|
|
25559
|
+
return signal.startsWith("SIG") ? signal : `SIG${signal}`;
|
|
25560
|
+
}
|
|
25561
|
+
if (typeof signal !== "number" || signal <= 0) return null;
|
|
25562
|
+
for (const [name, number] of Object.entries(os.constants.signals))
|
|
25563
|
+
if (number === signal) return name;
|
|
25564
|
+
return `SIG${signal}`;
|
|
25565
|
+
}
|
|
25566
|
+
const QUIT_SIGNAL_GRACE_MS = 900;
|
|
25552
25567
|
const SURFACE_ENV_MARKER = "LOCAL_OPERATOR_CONSOLE_SURFACE";
|
|
25553
25568
|
const SESSION_ENV_MARKER = "LOCAL_OPERATOR_CONSOLE_SESSION";
|
|
25554
25569
|
const SURFACE_TERM = "xterm-256color";
|
|
@@ -25624,6 +25639,12 @@ class ConsoleHost {
|
|
|
25624
25639
|
* removes the record rather than leaving a surface that lists as running.
|
|
25625
25640
|
*/
|
|
25626
25641
|
create(options) {
|
|
25642
|
+
if (this.disposing)
|
|
25643
|
+
throw new ConsoleError(
|
|
25644
|
+
"console_unavailable",
|
|
25645
|
+
"The console host is shutting down",
|
|
25646
|
+
{ reason: "host_disposing" }
|
|
25647
|
+
);
|
|
25627
25648
|
if (this.failedAllocations.size)
|
|
25628
25649
|
throw new ConsoleError(
|
|
25629
25650
|
"console_unavailable",
|
|
@@ -25708,7 +25729,9 @@ class ConsoleHost {
|
|
|
25708
25729
|
};
|
|
25709
25730
|
this.registry.attach(surface, runtime);
|
|
25710
25731
|
pty.onData((data) => this.consume(surface, data));
|
|
25711
|
-
pty.onExit(
|
|
25732
|
+
pty.onExit(
|
|
25733
|
+
(event) => this.exited(surface, event.exitCode, signalName(event.signal))
|
|
25734
|
+
);
|
|
25712
25735
|
if (options.input) pty.write(options.input);
|
|
25713
25736
|
if (entry.record.retain) this.flush(surface);
|
|
25714
25737
|
this.options.log(
|
|
@@ -25810,10 +25833,13 @@ class ConsoleHost {
|
|
|
25810
25833
|
meta.surface,
|
|
25811
25834
|
Number.isFinite(meta.exit_epoch) ? meta.exit_epoch : 0
|
|
25812
25835
|
);
|
|
25836
|
+
if (meta.end_reason === "app_quit")
|
|
25837
|
+
this.endReasons.set(meta.surface, "app_quit");
|
|
25813
25838
|
if (!existing)
|
|
25814
25839
|
this.registry.update(meta.surface, {
|
|
25815
25840
|
running: false,
|
|
25816
25841
|
exitCode: meta.exit_code,
|
|
25842
|
+
exitSignal: meta.exit_signal,
|
|
25817
25843
|
live: false,
|
|
25818
25844
|
secure: meta.secure === true,
|
|
25819
25845
|
lastActivity: meta.last_seen_at
|
|
@@ -25872,6 +25898,7 @@ class ConsoleHost {
|
|
|
25872
25898
|
this.registry.update(entry.record.surface, {
|
|
25873
25899
|
running: false,
|
|
25874
25900
|
exitCode: meta.exit_code,
|
|
25901
|
+
exitSignal: meta.exit_signal,
|
|
25875
25902
|
live: false,
|
|
25876
25903
|
lastActivity: meta.last_seen_at
|
|
25877
25904
|
});
|
|
@@ -25913,6 +25940,12 @@ class ConsoleHost {
|
|
|
25913
25940
|
rows: record.rows,
|
|
25914
25941
|
running: record.running,
|
|
25915
25942
|
exit_code: record.exitCode,
|
|
25943
|
+
exit_signal: record.exitSignal,
|
|
25944
|
+
/* Why the end happened when no code was observable (§7.3). Only the quit
|
|
25945
|
+
* path writes one, and it is the difference between "nobody could have
|
|
25946
|
+
* seen this" and main's old silence, which the pane read as an unknown
|
|
25947
|
+
* status. */
|
|
25948
|
+
end_reason: this.endReasons.get(record.surface) ?? null,
|
|
25916
25949
|
last_activity: record.lastActivity,
|
|
25917
25950
|
live: record.live,
|
|
25918
25951
|
agent_owned: record.origin === "agent",
|
|
@@ -25947,6 +25980,8 @@ class ConsoleHost {
|
|
|
25947
25980
|
return {
|
|
25948
25981
|
running: entry.record.running,
|
|
25949
25982
|
exit_code: entry.record.exitCode,
|
|
25983
|
+
exit_signal: entry.record.exitSignal,
|
|
25984
|
+
end_reason: this.endReasons.get(surface) ?? null,
|
|
25950
25985
|
// The retention layer's counter, bumped once per `process_exited` (§7.3,
|
|
25951
25986
|
// §10.2). Read from the host's live view of it: the sidecar is what makes
|
|
25952
25987
|
// it survive a relaunch, and this is what the running process reports.
|
|
@@ -26430,14 +26465,16 @@ class ConsoleHost {
|
|
|
26430
26465
|
}, OUTPUT_COALESCE_MS);
|
|
26431
26466
|
runtime.pendingTimer.unref?.();
|
|
26432
26467
|
}
|
|
26433
|
-
exited(surface, exitCode) {
|
|
26468
|
+
exited(surface, exitCode, exitSignal = null) {
|
|
26434
26469
|
const entry = this.registry.find(surface);
|
|
26435
26470
|
if (!entry || !entry.runtime) return;
|
|
26436
26471
|
this.registry.update(surface, {
|
|
26437
26472
|
running: false,
|
|
26438
26473
|
exitCode,
|
|
26474
|
+
exitSignal,
|
|
26439
26475
|
lastActivity: this.now()
|
|
26440
26476
|
});
|
|
26477
|
+
this.endReasons.delete(surface);
|
|
26441
26478
|
this.bumpExitEpoch(entry);
|
|
26442
26479
|
if (entry.record.retain) this.flush(surface);
|
|
26443
26480
|
const runtime = entry.runtime;
|
|
@@ -26446,18 +26483,20 @@ class ConsoleHost {
|
|
|
26446
26483
|
if (!runtime.exitDelivered) {
|
|
26447
26484
|
runtime.exitDelivered = true;
|
|
26448
26485
|
for (const subscriber of runtime.subscribers) {
|
|
26449
|
-
subscriber.exit({ surface, exitCode });
|
|
26486
|
+
subscriber.exit({ surface, exitCode, exitSignal });
|
|
26450
26487
|
}
|
|
26451
26488
|
}
|
|
26452
26489
|
this.options.log(
|
|
26453
|
-
`[console] surface ${redactSurface(surface)} exited ${exitCode}`
|
|
26490
|
+
`[console] surface ${redactSurface(surface)} exited ${exitCode}${exitSignal === null ? "" : ` by ${exitSignal}`}`
|
|
26454
26491
|
);
|
|
26455
26492
|
this.options.onChanged?.();
|
|
26456
|
-
this.
|
|
26457
|
-
|
|
26458
|
-
|
|
26459
|
-
|
|
26460
|
-
|
|
26493
|
+
if (!this.disposing)
|
|
26494
|
+
this.options.onExit?.({
|
|
26495
|
+
surface,
|
|
26496
|
+
sessionId: entry.record.sessionId,
|
|
26497
|
+
exitCode,
|
|
26498
|
+
exitSignal
|
|
26499
|
+
});
|
|
26461
26500
|
void runtime.emulator.whenIdle().then(() => {
|
|
26462
26501
|
const current = this.registry.find(surface);
|
|
26463
26502
|
if (!current || current.runtime !== runtime || current.record.running || !current.record.retain || current.record.secure || current.runtime.subscribers.size || surface === this.displayed || !this.options.history)
|
|
@@ -26812,6 +26851,8 @@ class ConsoleHost {
|
|
|
26812
26851
|
created_at: this.createdAt.get(surface) ?? this.now(),
|
|
26813
26852
|
last_seen_at: record.lastActivity,
|
|
26814
26853
|
exit_code: record.exitCode,
|
|
26854
|
+
exit_signal: record.exitSignal,
|
|
26855
|
+
end_reason: this.endReasons.get(surface) ?? null,
|
|
26815
26856
|
truncated: runtime.log.truncated,
|
|
26816
26857
|
exit_epoch: this.exitEpoch.get(surface) ?? 0,
|
|
26817
26858
|
secure: record.secure,
|
|
@@ -26926,10 +26967,62 @@ class ConsoleHost {
|
|
|
26926
26967
|
this.persistedBytes.delete(surface);
|
|
26927
26968
|
this.metaSignatures.delete(surface);
|
|
26928
26969
|
this.exitEpoch.delete(surface);
|
|
26970
|
+
this.endReasons.delete(surface);
|
|
26929
26971
|
this.options.onChanged?.();
|
|
26930
26972
|
}
|
|
26973
|
+
/**
|
|
26974
|
+
* Let the quit path OBSERVE a surface's exit instead of killing it blind (§7.3).
|
|
26975
|
+
*
|
|
26976
|
+
* THE DEFECT THIS CLOSES: `dispose` used to persist the sidecar (with
|
|
26977
|
+
* `exit_code: null`) and then kill the pty, so the next launch restored "exit
|
|
26978
|
+
* code not observed" for a surface the app itself closed — a status the app
|
|
26979
|
+
* could have had, reported as one nobody could have. The order is now flush,
|
|
26980
|
+
* signal, wait, and let the exit land in the record before the final persist.
|
|
26981
|
+
*
|
|
26982
|
+
* BOUNDED TWICE, AND IN PARALLEL ACROSS SURFACES (`dispose` awaits them all at
|
|
26983
|
+
* once): SIGTERM gets the same grace a user-initiated close does, SIGKILL gets
|
|
26984
|
+
* `QUIT_EXIT_CAPTURE_MS` for the event loop to deliver its `onExit`, and only
|
|
26985
|
+
* after BOTH fail is the end recorded as `app_quit` — the honest sentence for a
|
|
26986
|
+
* status that genuinely could not be observed, and distinguishable from a legacy
|
|
26987
|
+
* sidecar that never looked.
|
|
26988
|
+
*/
|
|
26989
|
+
async settleOnQuit(entry, persistHistory) {
|
|
26990
|
+
const runtime = entry.runtime;
|
|
26991
|
+
if (!runtime || !entry.record.running || !runtime.pty) return;
|
|
26992
|
+
if (persistHistory && entry.record.retain) this.persist(entry, runtime);
|
|
26993
|
+
const pty = runtime.pty;
|
|
26994
|
+
const exit = new Promise((resolve) => {
|
|
26995
|
+
runtime.exitWaiters.push(resolve);
|
|
26996
|
+
});
|
|
26997
|
+
let signalled = true;
|
|
26998
|
+
try {
|
|
26999
|
+
pty.kill();
|
|
27000
|
+
} catch {
|
|
27001
|
+
signalled = false;
|
|
27002
|
+
}
|
|
27003
|
+
const observed = await Promise.race([
|
|
27004
|
+
exit,
|
|
27005
|
+
delay(QUIT_SIGNAL_GRACE_MS).then(() => null)
|
|
27006
|
+
]);
|
|
27007
|
+
if (observed !== null) return;
|
|
27008
|
+
try {
|
|
27009
|
+
pty.kill("SIGKILL");
|
|
27010
|
+
} catch {
|
|
27011
|
+
}
|
|
27012
|
+
const killed = await Promise.race([
|
|
27013
|
+
exit,
|
|
27014
|
+
delay(QUIT_EXIT_CAPTURE_MS).then(() => null)
|
|
27015
|
+
]);
|
|
27016
|
+
if (killed === null) {
|
|
27017
|
+
this.endReasons.set(entry.record.surface, "app_quit");
|
|
27018
|
+
this.options.log(
|
|
27019
|
+
`[console] surface ${redactSurface(entry.record.surface)} did not report an exit within the quit bound${signalled ? "" : " (the signal itself was refused)"}; recording app_quit`
|
|
27020
|
+
);
|
|
27021
|
+
}
|
|
27022
|
+
}
|
|
26931
27023
|
/** Stop everything: every pty, every record, every subscriber. */
|
|
26932
|
-
dispose(persistHistory = true) {
|
|
27024
|
+
async dispose(persistHistory = true) {
|
|
27025
|
+
this.disposing = true;
|
|
26933
27026
|
const allocationFailures = [...this.failedAllocations].flatMap(
|
|
26934
27027
|
(allocation) => this.releaseFailedAllocation(allocation)
|
|
26935
27028
|
);
|
|
@@ -26980,21 +27073,31 @@ class ConsoleHost {
|
|
|
26980
27073
|
failures,
|
|
26981
27074
|
"Partial console runtime cleanup incomplete."
|
|
26982
27075
|
);
|
|
26983
|
-
} else
|
|
26984
|
-
|
|
27076
|
+
} else {
|
|
27077
|
+
const entries = this.registry.list();
|
|
27078
|
+
for (const entry of entries) {
|
|
26985
27079
|
const runtime = entry.runtime;
|
|
26986
27080
|
if (!runtime) continue;
|
|
26987
27081
|
if (runtime.pendingTimer) clearTimeout(runtime.pendingTimer);
|
|
26988
27082
|
if (runtime.persistTimer) clearTimeout(runtime.persistTimer);
|
|
26989
27083
|
runtime.subscribers.clear();
|
|
27084
|
+
}
|
|
27085
|
+
await Promise.all(
|
|
27086
|
+
entries.map((entry) => this.settleOnQuit(entry, persistHistory))
|
|
27087
|
+
);
|
|
27088
|
+
for (const entry of entries) {
|
|
27089
|
+
const runtime = entry.runtime;
|
|
27090
|
+
if (!runtime) continue;
|
|
26990
27091
|
if (persistHistory && entry.record.retain) this.persist(entry, runtime);
|
|
26991
|
-
if (entry.record.running) runtime.pty?.kill();
|
|
26992
27092
|
runtime.emulator.dispose();
|
|
26993
27093
|
}
|
|
27094
|
+
this.registry.clear();
|
|
27095
|
+
}
|
|
26994
27096
|
this.createdAt.clear();
|
|
26995
27097
|
this.persistedBytes.clear();
|
|
26996
27098
|
this.metaSignatures.clear();
|
|
26997
27099
|
this.exitEpoch.clear();
|
|
27100
|
+
this.endReasons.clear();
|
|
26998
27101
|
if (allocationFailures.length)
|
|
26999
27102
|
throw new AggregateError(
|
|
27000
27103
|
allocationFailures,
|
|
@@ -27012,10 +27115,23 @@ class ConsoleHost {
|
|
|
27012
27115
|
metaSignatures = /* @__PURE__ */ new Map();
|
|
27013
27116
|
/** Each surface's exit generation, seeded from the sidecar on restore (§7.3). */
|
|
27014
27117
|
exitEpoch = /* @__PURE__ */ new Map();
|
|
27118
|
+
/**
|
|
27119
|
+
* Why a surface's end could not be observed, when the quit path itself ended it.
|
|
27120
|
+
*
|
|
27121
|
+
* A SEPARATE MAP FROM THE RECORD, like `exitEpoch`: the reason has to outlive the
|
|
27122
|
+
* process that owns the record (it is persisted into the sidecar and read back on
|
|
27123
|
+
* the next launch), and it is cleared the moment a real exit is observed so a
|
|
27124
|
+
* subsequent run under the same handle cannot inherit the previous ending.
|
|
27125
|
+
*/
|
|
27126
|
+
endReasons = /* @__PURE__ */ new Map();
|
|
27127
|
+
/** True from the first line of `dispose`; refuses creates and suppresses the
|
|
27128
|
+
* completion seam for the whole teardown (M-1, m-2). */
|
|
27129
|
+
disposing = false;
|
|
27015
27130
|
}
|
|
27016
27131
|
function metaSignature(meta) {
|
|
27017
27132
|
return [
|
|
27018
27133
|
meta.exit_code,
|
|
27134
|
+
meta.end_reason ?? "",
|
|
27019
27135
|
meta.truncated,
|
|
27020
27136
|
meta.cols,
|
|
27021
27137
|
meta.rows,
|
|
@@ -27639,6 +27755,9 @@ class ConsoleHistory {
|
|
|
27639
27755
|
function parseMeta(raw) {
|
|
27640
27756
|
const meta = JSON.parse(raw);
|
|
27641
27757
|
if (typeof meta.exit_epoch !== "number") meta.exit_epoch = 0;
|
|
27758
|
+
if (meta.end_reason !== "app_quit") meta.end_reason = null;
|
|
27759
|
+
if (typeof meta.exit_signal !== "string" || !/^SIG[A-Z0-9]+$/.test(meta.exit_signal))
|
|
27760
|
+
meta.exit_signal = null;
|
|
27642
27761
|
return meta;
|
|
27643
27762
|
}
|
|
27644
27763
|
function enforceModes(path2) {
|
|
@@ -28171,12 +28290,12 @@ async function startConsoleHost(options) {
|
|
|
28171
28290
|
let policyWatcher = null;
|
|
28172
28291
|
let capacityProbe = null;
|
|
28173
28292
|
let rollbackOwners = [];
|
|
28174
|
-
const cleanupStartupOwners = () => {
|
|
28293
|
+
const cleanupStartupOwners = async () => {
|
|
28175
28294
|
const pending = [];
|
|
28176
28295
|
const failures = [];
|
|
28177
28296
|
for (const release of rollbackOwners.splice(0).reverse()) {
|
|
28178
28297
|
try {
|
|
28179
|
-
release();
|
|
28298
|
+
await release();
|
|
28180
28299
|
} catch (error) {
|
|
28181
28300
|
pending.unshift(release);
|
|
28182
28301
|
failures.push(error);
|
|
@@ -28326,13 +28445,13 @@ async function startConsoleHost(options) {
|
|
|
28326
28445
|
capacityProbe?.stop();
|
|
28327
28446
|
unregisterConsoleIpc();
|
|
28328
28447
|
capture?.dispose();
|
|
28329
|
-
readyHost.dispose();
|
|
28448
|
+
await readyHost.dispose();
|
|
28330
28449
|
log2("[console] host stopped");
|
|
28331
28450
|
}
|
|
28332
28451
|
};
|
|
28333
28452
|
} catch (error) {
|
|
28334
28453
|
try {
|
|
28335
|
-
cleanupStartupOwners();
|
|
28454
|
+
await cleanupStartupOwners();
|
|
28336
28455
|
} catch (cleanupError) {
|
|
28337
28456
|
log2(
|
|
28338
28457
|
`[console] partial cleanup retained for stop: ${String(cleanupError)}`
|
|
@@ -28350,7 +28469,7 @@ async function startConsoleHost(options) {
|
|
|
28350
28469
|
policyWatcher?.stop();
|
|
28351
28470
|
capacityProbe?.stop();
|
|
28352
28471
|
unregisterConsoleIpc();
|
|
28353
|
-
cleanupStartupOwners();
|
|
28472
|
+
await cleanupStartupOwners();
|
|
28354
28473
|
}
|
|
28355
28474
|
};
|
|
28356
28475
|
}
|
|
@@ -28848,7 +28967,6 @@ const ADDRESS_LIST_THEME_FALLBACK = "#1b1f24";
|
|
|
28848
28967
|
const DIP_INT32_MAX$1 = 2 ** 31 - 1;
|
|
28849
28968
|
const NOTICE_KINDS = [
|
|
28850
28969
|
"error",
|
|
28851
|
-
"hint",
|
|
28852
28970
|
"empty",
|
|
28853
28971
|
"no_match"
|
|
28854
28972
|
];
|
|
@@ -35358,11 +35476,15 @@ const enUiBrowser = {
|
|
|
35358
35476
|
"ui.browser.browser_tab_strip.unmute_tab": "Unmute tab",
|
|
35359
35477
|
"ui.browser.browser_tab_strip.watch": 'Watch "{title}"',
|
|
35360
35478
|
"ui.browser.browser_url_bar.address": "Address",
|
|
35361
|
-
"ui.browser.browser_url_bar.
|
|
35479
|
+
"ui.browser.browser_url_bar.address_search_row": 'Search DuckDuckGo for "{query}"',
|
|
35480
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Already open — {title}",
|
|
35481
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Already open",
|
|
35362
35482
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} suggestion available} other {{count, number, ::group-off} suggestions available}}",
|
|
35363
|
-
"ui.browser.browser_url_bar.
|
|
35364
|
-
"ui.browser.browser_url_bar.
|
|
35365
|
-
"ui.browser.browser_url_bar.
|
|
35483
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Only web addresses can open here.",
|
|
35484
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "No browsing history yet.",
|
|
35485
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "From your history",
|
|
35486
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Suggestions",
|
|
35487
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "No matching pages in your history.",
|
|
35366
35488
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Address suggestions are unavailable.",
|
|
35367
35489
|
"ui.browser.browser_url_bar.approvals_waiting": "Approvals, {count, plural, other {{count, number, ::group-off} waiting}}",
|
|
35368
35490
|
"ui.browser.browser_url_bar.back": "Back",
|
|
@@ -36233,6 +36355,7 @@ const enUiConsole = {
|
|
|
36233
36355
|
"ui.console.empty.detail": "A console runs a program in this conversation's directory and keeps its output, whether or not this pane is open.",
|
|
36234
36356
|
"ui.console.empty.title": "No console in this session",
|
|
36235
36357
|
"ui.console.ended.exit_code": "exit code {code}",
|
|
36358
|
+
"ui.console.ended.exit_signal": "killed by {signal}",
|
|
36236
36359
|
"ui.console.ended.exit_unknown": "exit code not observed",
|
|
36237
36360
|
"ui.console.ended.live": "This terminal has ended",
|
|
36238
36361
|
"ui.console.ended.restored": "This terminal has ended and its history was restored",
|
|
@@ -36253,6 +36376,7 @@ const enUiConsole = {
|
|
|
36253
36376
|
"ui.console.unavailable.title": "The console is not available in this app",
|
|
36254
36377
|
"ui.console.unavailable.unknown.detail": "This window could not reach the console, and did not say why. The app's log carries the reason.",
|
|
36255
36378
|
"ui.console.tab.ended": "ended",
|
|
36379
|
+
"ui.console.tab.exit_code": "exit {code}",
|
|
36256
36380
|
"ui.console.tab.agent_opened": "An agent opened this console",
|
|
36257
36381
|
"ui.console.tab.agent_typed": "An agent has typed into this console",
|
|
36258
36382
|
"ui.console.tab.close_label": "Close {title}, tab {index, number, ::group-off} of {total, number, ::group-off}",
|
|
@@ -36263,7 +36387,11 @@ const enUiConsole = {
|
|
|
36263
36387
|
"ui.console.secure_toggle.start_tooltip": "Secure input: stop recording this terminal",
|
|
36264
36388
|
"ui.console.close.cancel": "Cancel",
|
|
36265
36389
|
"ui.console.terminal.prompt_label": "Terminal input",
|
|
36266
|
-
"ui.console.terminal.too_much_output": "Too much output to announce, navigate to rows manually to read"
|
|
36390
|
+
"ui.console.terminal.too_much_output": "Too much output to announce, navigate to rows manually to read",
|
|
36391
|
+
"ui.console.ended.app_quit": "the app closed it when it quit",
|
|
36392
|
+
"ui.console.ended.marker": "End of history",
|
|
36393
|
+
"ui.console.ended.marker_detail": "This terminal is read-only. Select text to copy it.",
|
|
36394
|
+
"ui.console.ended.input_blocked": "This terminal has ended, so that key was not sent. Open a new console to type again."
|
|
36267
36395
|
};
|
|
36268
36396
|
const enUiHubComments = {
|
|
36269
36397
|
"ui.hub.comments.delete.confirm": "Are you sure you want to delete this comment?",
|
|
@@ -39088,11 +39216,15 @@ const esUiBrowser = {
|
|
|
39088
39216
|
"ui.browser.browser_url_bar.stop_loading": "Detener carga",
|
|
39089
39217
|
"ui.browser.browser_url_bar.reload": "Recargar",
|
|
39090
39218
|
"ui.browser.browser_url_bar.address": "Dirección",
|
|
39091
|
-
"ui.browser.browser_url_bar.
|
|
39219
|
+
"ui.browser.browser_url_bar.address_search_row": "Buscar «{query}» en DuckDuckGo",
|
|
39220
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Ya abierto — {title}",
|
|
39221
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Ya abierto",
|
|
39092
39222
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} sugerencia disponible} other {{count, number, ::group-off} sugerencias disponibles}}",
|
|
39093
|
-
"ui.browser.browser_url_bar.
|
|
39094
|
-
"ui.browser.browser_url_bar.
|
|
39095
|
-
"ui.browser.browser_url_bar.
|
|
39223
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Aquí solo se pueden abrir direcciones web.",
|
|
39224
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Aún no hay historial de navegación.",
|
|
39225
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "De tu historial",
|
|
39226
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Sugerencias",
|
|
39227
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "No hay páginas coincidentes en tu historial.",
|
|
39096
39228
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Las sugerencias de direcciones no están disponibles.",
|
|
39097
39229
|
"ui.browser.browser_url_bar.approvals_waiting": "Aprobaciones, {count, plural, other {{count, number, ::group-off} en espera}}",
|
|
39098
39230
|
"ui.browser.browser_url_bar.home_destination": "Inicio — ir a la página inicial (en blanco)",
|
|
@@ -39809,9 +39941,14 @@ const esUiConsole = {
|
|
|
39809
39941
|
"ui.console.create_failed.title": "No se pudo iniciar la consola en esta sesión",
|
|
39810
39942
|
"ui.console.empty.detail": "Una consola ejecuta un programa en la carpeta de esta conversación y conserva su salida, aunque este panel esté cerrado.",
|
|
39811
39943
|
"ui.console.empty.title": "No hay ninguna consola en esta sesión",
|
|
39944
|
+
"ui.console.ended.app_quit": "la app la cerró al salir",
|
|
39812
39945
|
"ui.console.ended.exit_code": "código de salida {code}",
|
|
39946
|
+
"ui.console.ended.exit_signal": "terminada por {signal}",
|
|
39813
39947
|
"ui.console.ended.exit_unknown": "código de salida no observado",
|
|
39948
|
+
"ui.console.ended.input_blocked": "Esta terminal ha finalizado, así que esa tecla no se envió. Abre una nueva consola para volver a escribir.",
|
|
39814
39949
|
"ui.console.ended.live": "Esta terminal ha finalizado",
|
|
39950
|
+
"ui.console.ended.marker": "Fin del historial",
|
|
39951
|
+
"ui.console.ended.marker_detail": "Esta terminal es de solo lectura. Selecciona el texto para copiarlo.",
|
|
39815
39952
|
"ui.console.ended.restored": "Esta terminal ha finalizado y se ha restaurado su historial",
|
|
39816
39953
|
"ui.console.loading.create": "Iniciando una consola",
|
|
39817
39954
|
"ui.console.loading.read": "Leyendo la consola de esta sesión",
|
|
@@ -39830,6 +39967,7 @@ const esUiConsole = {
|
|
|
39830
39967
|
"ui.console.unavailable.title": "La consola no está disponible en esta app",
|
|
39831
39968
|
"ui.console.unavailable.unknown.detail": "Esta ventana no pudo acceder a la consola y no indicó por qué. El registro de la app contiene el motivo.",
|
|
39832
39969
|
"ui.console.tab.ended": "finalizada",
|
|
39970
|
+
"ui.console.tab.exit_code": "código {code}",
|
|
39833
39971
|
"ui.console.tab.agent_opened": "Un agente abrió esta consola",
|
|
39834
39972
|
"ui.console.tab.agent_typed": "Un agente ha escrito en esta consola",
|
|
39835
39973
|
"ui.console.tab.close_label": "Cerrar {title}, pestaña {index, number, ::group-off} de {total, number, ::group-off}",
|
|
@@ -42665,11 +42803,15 @@ const frUiBrowser = {
|
|
|
42665
42803
|
"ui.browser.browser_url_bar.stop_loading": "Arrêter le chargement",
|
|
42666
42804
|
"ui.browser.browser_url_bar.reload": "Recharger",
|
|
42667
42805
|
"ui.browser.browser_url_bar.address": "Adresse",
|
|
42668
|
-
"ui.browser.browser_url_bar.
|
|
42806
|
+
"ui.browser.browser_url_bar.address_search_row": "Rechercher « {query} » sur DuckDuckGo",
|
|
42807
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Déjà ouvert — {title}",
|
|
42808
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Déjà ouvert",
|
|
42669
42809
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} suggestion disponible} many {{count, number, ::group-off} de suggestions disponibles} other {{count, number, ::group-off} suggestions disponibles}}",
|
|
42670
|
-
"ui.browser.browser_url_bar.
|
|
42671
|
-
"ui.browser.browser_url_bar.
|
|
42672
|
-
"ui.browser.browser_url_bar.
|
|
42810
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Seules les adresses web peuvent s’ouvrir ici.",
|
|
42811
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Pas encore d'historique de navigation.",
|
|
42812
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "De votre historique",
|
|
42813
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Suggestions",
|
|
42814
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "Aucune page correspondante dans votre historique.",
|
|
42673
42815
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Les suggestions d’adresses ne sont pas disponibles.",
|
|
42674
42816
|
"ui.browser.browser_url_bar.approvals_waiting": "Approbations, {count, plural, one {{count, number, ::group-off} en attente} many {{count, number, ::group-off} en attente} other {{count, number, ::group-off} en attente}}",
|
|
42675
42817
|
"ui.browser.browser_url_bar.home_destination": "Accueil — aller à la page de départ (vide)",
|
|
@@ -43371,9 +43513,14 @@ const frUiConsole = {
|
|
|
43371
43513
|
"ui.console.create_failed.title": "Impossible de démarrer la console dans cette session",
|
|
43372
43514
|
"ui.console.empty.detail": "Une console exécute un programme dans le dossier de cette conversation et conserve sa sortie, même si ce volet est fermé.",
|
|
43373
43515
|
"ui.console.empty.title": "Aucune console dans cette session",
|
|
43516
|
+
"ui.console.ended.app_quit": "l’application l’a fermé en quittant",
|
|
43374
43517
|
"ui.console.ended.exit_code": "code de sortie {code}",
|
|
43518
|
+
"ui.console.ended.exit_signal": "tué par {signal}",
|
|
43375
43519
|
"ui.console.ended.exit_unknown": "code de sortie non observé",
|
|
43520
|
+
"ui.console.ended.input_blocked": "Ce terminal est terminé : cette touche n’a pas été envoyée. Ouvrez une nouvelle console pour saisir à nouveau.",
|
|
43376
43521
|
"ui.console.ended.live": "Ce terminal est terminé",
|
|
43522
|
+
"ui.console.ended.marker": "Fin de l’historique",
|
|
43523
|
+
"ui.console.ended.marker_detail": "Ce terminal est en lecture seule. Sélectionnez le texte à copier.",
|
|
43377
43524
|
"ui.console.ended.restored": "Ce terminal est terminé, historique restauré",
|
|
43378
43525
|
"ui.console.loading.create": "Démarrage d’une console",
|
|
43379
43526
|
"ui.console.loading.read": "Lecture de la console de cette session",
|
|
@@ -43407,6 +43554,7 @@ const frUiConsole = {
|
|
|
43407
43554
|
"ui.console.dismiss.title": "Effacer ce terminal ?",
|
|
43408
43555
|
"ui.console.dismiss.confirm": "Effacer le terminal",
|
|
43409
43556
|
"ui.console.tab.ended": "terminé",
|
|
43557
|
+
"ui.console.tab.exit_code": "sortie {code}",
|
|
43410
43558
|
"ui.console.tab.agent_opened": "Un agent a ouvert cette console",
|
|
43411
43559
|
"ui.console.tab.agent_typed": "Un agent a saisi du texte dans cette console",
|
|
43412
43560
|
"ui.console.tab.close_label": "Fermer {title}, onglet {index, number, ::group-off} sur {total, number, ::group-off}",
|
|
@@ -46241,11 +46389,15 @@ const hiUiBrowser = {
|
|
|
46241
46389
|
"ui.browser.browser_tab_strip.unmute_tab": "टैब की आवाज़ चालू करें",
|
|
46242
46390
|
"ui.browser.browser_tab_strip.watch": '"{title}" देखें',
|
|
46243
46391
|
"ui.browser.browser_url_bar.address": "पता",
|
|
46244
|
-
"ui.browser.browser_url_bar.
|
|
46392
|
+
"ui.browser.browser_url_bar.address_search_row": 'DuckDuckGo पर "{query}" खोजें',
|
|
46393
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "पहले से खुला — {title}",
|
|
46394
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "पहले से खुला",
|
|
46245
46395
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} सुझाव उपलब्ध है} other {{count, number, ::group-off} सुझाव उपलब्ध हैं}}",
|
|
46246
|
-
"ui.browser.browser_url_bar.
|
|
46247
|
-
"ui.browser.browser_url_bar.
|
|
46248
|
-
"ui.browser.browser_url_bar.
|
|
46396
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "यहाँ केवल वेब पते खुल सकते हैं।",
|
|
46397
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "अभी तक कोई ब्राउज़िंग इतिहास नहीं।",
|
|
46398
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "आपके इतिहास से",
|
|
46399
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "सुझाव",
|
|
46400
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "आपके इतिहास में कोई मेल खाता पृष्ठ नहीं।",
|
|
46249
46401
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "पते के सुझाव उपलब्ध नहीं हैं।",
|
|
46250
46402
|
"ui.browser.browser_url_bar.approvals_waiting": "स्वीकृतियाँ, {count, plural, other {{count, number, ::group-off} इंतज़ार में}}",
|
|
46251
46403
|
"ui.browser.browser_url_bar.back": "पीछे",
|
|
@@ -46932,9 +47084,14 @@ const hiUiConsole = {
|
|
|
46932
47084
|
"ui.console.create_failed.title": "इस सत्र में कंसोल शुरू नहीं हो सका",
|
|
46933
47085
|
"ui.console.empty.detail": "कंसोल इस बातचीत के फ़ोल्डर में प्रोग्राम चलाता है और उसका आउटपुट रखता है, चाहे यह पैनल खुला हो या नहीं।",
|
|
46934
47086
|
"ui.console.empty.title": "इस सत्र में कोई कंसोल नहीं है",
|
|
47087
|
+
"ui.console.ended.app_quit": "ऐप बंद होने पर इसे बंद किया गया",
|
|
46935
47088
|
"ui.console.ended.exit_code": "एग्ज़िट कोड {code}",
|
|
47089
|
+
"ui.console.ended.exit_signal": "{signal} से बंद किया गया",
|
|
46936
47090
|
"ui.console.ended.exit_unknown": "एग्ज़िट कोड उपलब्ध नहीं है",
|
|
47091
|
+
"ui.console.ended.input_blocked": "यह टर्मिनल समाप्त हो चुका है, इसलिए वह कुंजी नहीं भेजी गई। फिर से टाइप करने के लिए नया कंसोल खोलें।",
|
|
46937
47092
|
"ui.console.ended.live": "यह टर्मिनल समाप्त हो चुका है",
|
|
47093
|
+
"ui.console.ended.marker": "इतिहास का अंत",
|
|
47094
|
+
"ui.console.ended.marker_detail": "यह टर्मिनल सिर्फ़ पढ़ने के लिए है। कॉपी करने के लिए टेक्स्ट चुनें।",
|
|
46938
47095
|
"ui.console.ended.restored": "यह टर्मिनल समाप्त हो चुका है और उसका इतिहास बहाल किया गया है",
|
|
46939
47096
|
"ui.console.loading.create": "कंसोल शुरू हो रहा है",
|
|
46940
47097
|
"ui.console.loading.read": "इस सत्र का कंसोल पढ़ा जा रहा है",
|
|
@@ -46953,6 +47110,7 @@ const hiUiConsole = {
|
|
|
46953
47110
|
"ui.console.unavailable.title": "इस ऐप में कंसोल उपलब्ध नहीं है",
|
|
46954
47111
|
"ui.console.unavailable.unknown.detail": "यह विंडो कंसोल से संपर्क नहीं कर सकी और इसकी वजह नहीं बताई। वजह ऐप के लॉग में दी गई है।",
|
|
46955
47112
|
"ui.console.tab.ended": "समाप्त",
|
|
47113
|
+
"ui.console.tab.exit_code": "एग्ज़िट {code}",
|
|
46956
47114
|
"ui.console.tab.agent_opened": "यह कंसोल किसी एजेंट ने खोला था",
|
|
46957
47115
|
"ui.console.tab.agent_typed": "इस कंसोल में किसी एजेंट ने टाइप किया है",
|
|
46958
47116
|
"ui.console.tab.close_label": "{title} बंद करें, टैब {index, number, ::group-off}, कुल {total, number, ::group-off}",
|
|
@@ -49595,11 +49753,15 @@ const ruUiBrowser = {
|
|
|
49595
49753
|
"ui.browser.browser_tab_strip.unmute_tab": "Включить звук вкладки",
|
|
49596
49754
|
"ui.browser.browser_tab_strip.watch": "Смотреть «{title}»",
|
|
49597
49755
|
"ui.browser.browser_url_bar.address": "Адрес",
|
|
49598
|
-
"ui.browser.browser_url_bar.
|
|
49756
|
+
"ui.browser.browser_url_bar.address_search_row": "Искать «{query}» в DuckDuckGo",
|
|
49757
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Уже открыто — {title}",
|
|
49758
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Уже открыто",
|
|
49599
49759
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} подсказка доступна} few {{count, number, ::group-off} подсказки доступны} many {{count, number, ::group-off} подсказок доступно} other {{count, number, ::group-off} подсказки доступны}}",
|
|
49600
|
-
"ui.browser.browser_url_bar.
|
|
49601
|
-
"ui.browser.browser_url_bar.
|
|
49602
|
-
"ui.browser.browser_url_bar.
|
|
49760
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Здесь можно открывать только веб-адреса.",
|
|
49761
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Истории просмотров пока нет.",
|
|
49762
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "Из вашей истории",
|
|
49763
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Подсказки",
|
|
49764
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "В вашей истории нет подходящих страниц.",
|
|
49603
49765
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Подсказки адресов недоступны.",
|
|
49604
49766
|
"ui.browser.browser_url_bar.approvals_waiting": "Одобрения, {count, plural, one {ожидает {count, number, ::group-off}} few {ожидают {count, number, ::group-off}} many {ожидают {count, number, ::group-off}} other {ожидают {count, number, ::group-off}}}",
|
|
49605
49767
|
"ui.browser.browser_url_bar.back": "Назад",
|
|
@@ -50306,9 +50468,14 @@ const ruUiConsole = {
|
|
|
50306
50468
|
"ui.console.create_failed.title": "Не удалось запустить консоль в этой сессии",
|
|
50307
50469
|
"ui.console.empty.detail": "Консоль запускает программу в папке этого разговора и сохраняет её вывод, даже когда эта панель закрыта.",
|
|
50308
50470
|
"ui.console.empty.title": "В этой сессии нет консоли",
|
|
50471
|
+
"ui.console.ended.app_quit": "приложение закрыло его при выходе",
|
|
50309
50472
|
"ui.console.ended.exit_code": "код завершения {code}",
|
|
50473
|
+
"ui.console.ended.exit_signal": "остановлен сигналом {signal}",
|
|
50310
50474
|
"ui.console.ended.exit_unknown": "код завершения не получен",
|
|
50475
|
+
"ui.console.ended.input_blocked": "Этот терминал завершил работу, поэтому нажатие не отправлено. Откройте новую консоль, чтобы снова вводить текст.",
|
|
50311
50476
|
"ui.console.ended.live": "Этот терминал завершил работу",
|
|
50477
|
+
"ui.console.ended.marker": "Конец истории",
|
|
50478
|
+
"ui.console.ended.marker_detail": "Терминал только для чтения. Выделите текст, чтобы скопировать его.",
|
|
50312
50479
|
"ui.console.ended.restored": "Этот терминал завершил работу; его история восстановлена",
|
|
50313
50480
|
"ui.console.loading.create": "Запуск консоли",
|
|
50314
50481
|
"ui.console.loading.read": "Чтение консоли этой сессии",
|
|
@@ -50327,6 +50494,7 @@ const ruUiConsole = {
|
|
|
50327
50494
|
"ui.console.unavailable.title": "Консоль недоступна в этом приложении",
|
|
50328
50495
|
"ui.console.unavailable.unknown.detail": "Это окно не смогло подключиться к консоли и не сообщило причину. Она указана в журнале приложения.",
|
|
50329
50496
|
"ui.console.tab.ended": "завершён",
|
|
50497
|
+
"ui.console.tab.exit_code": "код {code}",
|
|
50330
50498
|
"ui.console.tab.agent_opened": "Агент открыл эту консоль",
|
|
50331
50499
|
"ui.console.tab.agent_typed": "Агент вводил текст в этой консоли",
|
|
50332
50500
|
"ui.console.tab.close_label": "Закрыть {title}, вкладка {index, number, ::group-off} из {total, number, ::group-off}",
|
|
@@ -53055,11 +53223,15 @@ const urUiBrowser = {
|
|
|
53055
53223
|
"ui.browser.browser_tab_strip.unmute_tab": "ٹیب کی آواز بحال کریں",
|
|
53056
53224
|
"ui.browser.browser_tab_strip.watch": "“{title}” پر نظر رکھیں",
|
|
53057
53225
|
"ui.browser.browser_url_bar.address": "پتہ",
|
|
53058
|
-
"ui.browser.browser_url_bar.
|
|
53226
|
+
"ui.browser.browser_url_bar.address_search_row": 'DuckDuckGo پر "{query}" تلاش کریں',
|
|
53227
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "پہلے سے کھلا — {title}",
|
|
53228
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "پہلے سے کھلا",
|
|
53059
53229
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} تجویز دستیاب ہے} other {{count, number, ::group-off} تجاویز دستیاب ہیں}}",
|
|
53060
|
-
"ui.browser.browser_url_bar.
|
|
53061
|
-
"ui.browser.browser_url_bar.
|
|
53062
|
-
"ui.browser.browser_url_bar.
|
|
53230
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "یہاں صرف ویب پتے کھل سکتے ہیں۔",
|
|
53231
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "ابھی تک کوئی براؤزنگ سرگزشت نہیں۔",
|
|
53232
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "آپ کی سرگزشت سے",
|
|
53233
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "تجاویز",
|
|
53234
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "آپ کی سرگزشت میں کوئی مماثل صفحہ نہیں۔",
|
|
53063
53235
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "پتے کی تجاویز دستیاب نہیں ہیں۔",
|
|
53064
53236
|
"ui.browser.browser_url_bar.approvals_waiting": "منظوریاں، {count, plural, other {{count, number, ::group-off} منتظر}}",
|
|
53065
53237
|
"ui.browser.browser_url_bar.back": "پیچھے",
|
|
@@ -53766,9 +53938,14 @@ const urUiConsole = {
|
|
|
53766
53938
|
"ui.console.create_failed.title": "اس سیشن میں کنسول شروع نہیں ہو سکا",
|
|
53767
53939
|
"ui.console.empty.detail": "کنسول اس گفتگو کی ڈائریکٹری میں پروگرام چلاتا اور اس کا آؤٹ پٹ محفوظ رکھتا ہے، چاہے یہ پین کھلا ہو یا نہ ہو۔",
|
|
53768
53940
|
"ui.console.empty.title": "اس سیشن میں کوئی کنسول نہیں",
|
|
53941
|
+
"ui.console.ended.app_quit": "ایپ کے بند ہونے پر اسے بند کر دیا گیا",
|
|
53769
53942
|
"ui.console.ended.exit_code": "اخراج کوڈ {code}",
|
|
53943
|
+
"ui.console.ended.exit_signal": "{signal} کے ذریعے ختم کیا گیا",
|
|
53770
53944
|
"ui.console.ended.exit_unknown": "اخراج کوڈ معلوم نہیں ہوا",
|
|
53945
|
+
"ui.console.ended.input_blocked": "یہ ٹرمینل ختم ہو چکا ہے، اس لیے وہ کلید نہیں بھیجی گئی۔ دوبارہ ٹائپ کرنے کے لیے نیا کنسول کھولیں۔",
|
|
53771
53946
|
"ui.console.ended.live": "یہ ٹرمینل ختم ہو چکا ہے",
|
|
53947
|
+
"ui.console.ended.marker": "تاریخچے کا اختتام",
|
|
53948
|
+
"ui.console.ended.marker_detail": "یہ ٹرمینل صرف پڑھنے کے لیے ہے۔ اسے نقل کرنے کے لیے متن منتخب کریں۔",
|
|
53772
53949
|
"ui.console.ended.restored": "یہ ٹرمینل ختم ہو چکا ہے اور اس کا تاریخچہ بحال ہو گیا",
|
|
53773
53950
|
"ui.console.loading.create": "کنسول شروع ہو رہا ہے",
|
|
53774
53951
|
"ui.console.loading.read": "اس سیشن کا کنسول پڑھا جا رہا ہے",
|
|
@@ -53787,6 +53964,7 @@ const urUiConsole = {
|
|
|
53787
53964
|
"ui.console.unavailable.title": "اس ایپ میں کنسول دستیاب نہیں",
|
|
53788
53965
|
"ui.console.unavailable.unknown.detail": "یہ ونڈو کنسول تک نہیں پہنچ سکی، اور وجہ نہیں بتائی۔ وجہ ایپ کے لاگ میں درج ہے۔",
|
|
53789
53966
|
"ui.console.tab.ended": "ختم شدہ",
|
|
53967
|
+
"ui.console.tab.exit_code": "اخراج {code}",
|
|
53790
53968
|
"ui.console.tab.agent_opened": "ایک ایجنٹ نے یہ کنسول کھولا",
|
|
53791
53969
|
"ui.console.tab.agent_typed": "ایک ایجنٹ نے اس کنسول میں ٹائپ کیا ہے",
|
|
53792
53970
|
"ui.console.tab.close_label": "{title} بند کریں، {total, number, ::group-off} میں سے ٹیب {index, number, ::group-off}",
|
|
@@ -56429,11 +56607,15 @@ const viUiBrowser = {
|
|
|
56429
56607
|
"ui.browser.browser_tab_strip.unmute_tab": "Bật tiếng tab",
|
|
56430
56608
|
"ui.browser.browser_tab_strip.watch": 'Theo dõi "{title}"',
|
|
56431
56609
|
"ui.browser.browser_url_bar.address": "Địa chỉ",
|
|
56432
|
-
"ui.browser.browser_url_bar.
|
|
56610
|
+
"ui.browser.browser_url_bar.address_search_row": 'Tìm "{query}" trên DuckDuckGo',
|
|
56611
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Đã mở — {title}",
|
|
56612
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Đã mở",
|
|
56433
56613
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, other {{count, number, ::group-off} gợi ý có sẵn}}",
|
|
56434
|
-
"ui.browser.browser_url_bar.
|
|
56435
|
-
"ui.browser.browser_url_bar.
|
|
56436
|
-
"ui.browser.browser_url_bar.
|
|
56614
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Chỉ có thể mở địa chỉ web ở đây.",
|
|
56615
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Chưa có lịch sử duyệt web.",
|
|
56616
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "Từ lịch sử của bạn",
|
|
56617
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Gợi ý",
|
|
56618
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "Không có trang nào phù hợp trong lịch sử của bạn.",
|
|
56437
56619
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Gợi ý địa chỉ không khả dụng.",
|
|
56438
56620
|
"ui.browser.browser_url_bar.approvals_waiting": "Phê duyệt, {count, plural, other {{count, number, ::group-off} đang chờ}}",
|
|
56439
56621
|
"ui.browser.browser_url_bar.back": "Quay lại",
|
|
@@ -57140,9 +57322,14 @@ const viUiConsole = {
|
|
|
57140
57322
|
"ui.console.create_failed.title": "Không thể khởi động bảng lệnh trong phiên này",
|
|
57141
57323
|
"ui.console.empty.detail": "Bảng lệnh chạy chương trình trong thư mục của cuộc trò chuyện này và giữ lại đầu ra, dù khung này có mở hay không.",
|
|
57142
57324
|
"ui.console.empty.title": "Phiên này chưa có bảng lệnh",
|
|
57325
|
+
"ui.console.ended.app_quit": "ứng dụng đã đóng nó khi thoát",
|
|
57143
57326
|
"ui.console.ended.exit_code": "mã thoát {code}",
|
|
57327
|
+
"ui.console.ended.exit_signal": "bị dừng bởi {signal}",
|
|
57144
57328
|
"ui.console.ended.exit_unknown": "chưa ghi nhận mã thoát",
|
|
57329
|
+
"ui.console.ended.input_blocked": "Cửa sổ dòng lệnh này đã kết thúc nên phím đó không được gửi. Mở bảng lệnh mới để nhập lại.",
|
|
57145
57330
|
"ui.console.ended.live": "Cửa sổ dòng lệnh này đã kết thúc",
|
|
57331
|
+
"ui.console.ended.marker": "Kết thúc lịch sử",
|
|
57332
|
+
"ui.console.ended.marker_detail": "Cửa sổ dòng lệnh này chỉ đọc. Chọn văn bản để sao chép.",
|
|
57146
57333
|
"ui.console.ended.restored": "Cửa sổ dòng lệnh này đã kết thúc và lịch sử đã được khôi phục",
|
|
57147
57334
|
"ui.console.loading.create": "Đang khởi động bảng lệnh",
|
|
57148
57335
|
"ui.console.loading.read": "Đang đọc bảng lệnh của phiên này",
|
|
@@ -57161,6 +57348,7 @@ const viUiConsole = {
|
|
|
57161
57348
|
"ui.console.unavailable.title": "Bảng lệnh không khả dụng trong ứng dụng này",
|
|
57162
57349
|
"ui.console.unavailable.unknown.detail": "Cửa sổ này không truy cập được bảng lệnh và không cho biết lý do. Lý do có trong nhật ký ứng dụng.",
|
|
57163
57350
|
"ui.console.tab.ended": "đã kết thúc",
|
|
57351
|
+
"ui.console.tab.exit_code": "mã thoát {code}",
|
|
57164
57352
|
"ui.console.tab.agent_opened": "Một tác nhân đã mở bảng lệnh này",
|
|
57165
57353
|
"ui.console.tab.agent_typed": "Một tác nhân đã nhập vào bảng lệnh này",
|
|
57166
57354
|
"ui.console.tab.close_label": "Đóng {title}, thẻ {index, number, ::group-off} trên {total, number, ::group-off}",
|
|
@@ -59698,11 +59886,15 @@ const zhCNUiBrowser = {
|
|
|
59698
59886
|
"ui.browser.browser_tab_strip.unmute_tab": "取消标签页静音",
|
|
59699
59887
|
"ui.browser.browser_tab_strip.watch": "查看“{title}”",
|
|
59700
59888
|
"ui.browser.browser_url_bar.address": "地址",
|
|
59701
|
-
"ui.browser.browser_url_bar.
|
|
59889
|
+
"ui.browser.browser_url_bar.address_search_row": "在 DuckDuckGo 中搜索“{query}”",
|
|
59890
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "已打开 — {title}",
|
|
59891
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "已打开",
|
|
59702
59892
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, other {{count, number, ::group-off}条建议可用}}",
|
|
59703
|
-
"ui.browser.browser_url_bar.
|
|
59704
|
-
"ui.browser.browser_url_bar.
|
|
59705
|
-
"ui.browser.browser_url_bar.
|
|
59893
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "此处只能打开网页地址。",
|
|
59894
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "还没有浏览历史记录。",
|
|
59895
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "来自你的历史记录",
|
|
59896
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "建议",
|
|
59897
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "你的历史记录中没有匹配的页面。",
|
|
59706
59898
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "地址建议不可用。",
|
|
59707
59899
|
"ui.browser.browser_url_bar.approvals_waiting": "审批,{count, plural, other {{count, number, ::group-off}项待处理}}",
|
|
59708
59900
|
"ui.browser.browser_url_bar.back": "后退",
|
|
@@ -60420,9 +60612,14 @@ const zhCNUiConsole = {
|
|
|
60420
60612
|
"ui.console.create_failed.title": "无法在此会话中启动控制台",
|
|
60421
60613
|
"ui.console.empty.detail": "控制台在此对话的目录中运行程序,无论此面板是否打开,都会保留输出。",
|
|
60422
60614
|
"ui.console.empty.title": "此会话中没有控制台",
|
|
60615
|
+
"ui.console.ended.app_quit": "应用退出时将其关闭",
|
|
60423
60616
|
"ui.console.ended.exit_code": "退出码{code}",
|
|
60617
|
+
"ui.console.ended.exit_signal": "被{signal}终止",
|
|
60424
60618
|
"ui.console.ended.exit_unknown": "未获取退出码",
|
|
60619
|
+
"ui.console.ended.input_blocked": "此终端已结束,因此该按键未被发送。打开新的控制台即可再次输入。",
|
|
60425
60620
|
"ui.console.ended.live": "此终端已结束",
|
|
60621
|
+
"ui.console.ended.marker": "历史记录结束",
|
|
60622
|
+
"ui.console.ended.marker_detail": "此终端为只读状态。选中文本即可复制。",
|
|
60426
60623
|
"ui.console.ended.restored": "此终端已结束,历史记录已恢复",
|
|
60427
60624
|
"ui.console.loading.create": "正在启动控制台",
|
|
60428
60625
|
"ui.console.loading.read": "正在读取此会话的控制台",
|
|
@@ -60441,6 +60638,7 @@ const zhCNUiConsole = {
|
|
|
60441
60638
|
"ui.console.unavailable.title": "此应用中控制台不可用",
|
|
60442
60639
|
"ui.console.unavailable.unknown.detail": "此窗口无法连接控制台,也未说明原因。原因记录在应用日志中。",
|
|
60443
60640
|
"ui.console.tab.ended": "已结束",
|
|
60641
|
+
"ui.console.tab.exit_code": "退出{code}",
|
|
60444
60642
|
"ui.console.tab.agent_opened": "此控制台由智能体打开",
|
|
60445
60643
|
"ui.console.tab.agent_typed": "智能体已在此控制台中输入过内容",
|
|
60446
60644
|
"ui.console.tab.close_label": "关闭{title},第{index, number, ::group-off}个标签页,共{total, number, ::group-off}个",
|
|
@@ -65995,7 +66193,8 @@ const ADDRESS_HISTORY_MAX_ENTRIES_PER_TAB = 50;
|
|
|
65995
66193
|
const ADDRESS_HISTORY_MAX_ENTRIES = 256;
|
|
65996
66194
|
const ADDRESS_HISTORY_MAX_URL_LENGTH = 2048;
|
|
65997
66195
|
const ADDRESS_HISTORY_MAX_TITLE_LENGTH = 256;
|
|
65998
|
-
const
|
|
66196
|
+
const ADDRESS_HISTORY_MAX_QUERY_LENGTH = ADDRESS_HISTORY_MAX_URL_LENGTH;
|
|
66197
|
+
const ADDRESS_HISTORY_MAX_LIMIT = 20;
|
|
65999
66198
|
const CONTROL_CHARS$1 = /[\p{Cc}]/u;
|
|
66000
66199
|
function windowAround(entries, activeIndexRaw, max) {
|
|
66001
66200
|
const activeIndex = Math.min(
|
|
@@ -66071,12 +66270,9 @@ function historyTitle(raw) {
|
|
|
66071
66270
|
const cleaned = raw.replace(CONTROL_CHARS$1, " ").replace(/\s+/g, " ").trim();
|
|
66072
66271
|
return cleaned.length > ADDRESS_HISTORY_MAX_TITLE_LENGTH ? cleaned.slice(0, ADDRESS_HISTORY_MAX_TITLE_LENGTH) : cleaned;
|
|
66073
66272
|
}
|
|
66074
|
-
function collectAddressHistory(tabs2,
|
|
66075
|
-
const
|
|
66076
|
-
|
|
66077
|
-
);
|
|
66078
|
-
const active = inScope.find((tab) => tab.tabId === activeTabId);
|
|
66079
|
-
const ordered = active ? [active, ...inScope.filter((tab) => tab.tabId !== activeTabId)] : inScope;
|
|
66273
|
+
function collectAddressHistory(tabs2, activeTabId) {
|
|
66274
|
+
const active = tabs2.find((tab) => tab.tabId === activeTabId);
|
|
66275
|
+
const ordered = active ? [active, ...tabs2.filter((tab) => tab.tabId !== activeTabId)] : [...tabs2];
|
|
66080
66276
|
const seen = /* @__PURE__ */ new Set();
|
|
66081
66277
|
const entries = [];
|
|
66082
66278
|
for (const tab of ordered.slice(0, ADDRESS_HISTORY_MAX_TABS)) {
|
|
@@ -66092,6 +66288,12 @@ function collectAddressHistory(tabs2, scope, activeTabId) {
|
|
|
66092
66288
|
entries.push({
|
|
66093
66289
|
url,
|
|
66094
66290
|
title: historyTitle(entry.title),
|
|
66291
|
+
// A stack has no visit count and no visit timestamp. Zero is the
|
|
66292
|
+
// honest absence; the renderer treats a tab row's order as stack
|
|
66293
|
+
// distance, never as frequency.
|
|
66294
|
+
visitCount: 0,
|
|
66295
|
+
lastVisitedAt: 0,
|
|
66296
|
+
source: "tab",
|
|
66095
66297
|
sourceTabId: tab.tabId,
|
|
66096
66298
|
sourceIndex,
|
|
66097
66299
|
activeTab: tab.tabId === activeTabId,
|
|
@@ -66105,6 +66307,38 @@ function collectAddressHistory(tabs2, scope, activeTabId) {
|
|
|
66105
66307
|
}
|
|
66106
66308
|
return { activeTabId, entries };
|
|
66107
66309
|
}
|
|
66310
|
+
function foldAscii(value) {
|
|
66311
|
+
return value.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
|
|
66312
|
+
}
|
|
66313
|
+
function mergeAddressHistory(tabEntries, historyEntries, query, limit) {
|
|
66314
|
+
const cap = Math.max(0, Math.floor(limit));
|
|
66315
|
+
if (cap === 0) return [];
|
|
66316
|
+
const seen = /* @__PURE__ */ new Set();
|
|
66317
|
+
const merged = [];
|
|
66318
|
+
for (const entry of historyEntries) {
|
|
66319
|
+
if (merged.length >= cap) break;
|
|
66320
|
+
const url = canonicalHistoryUrl(entry.url);
|
|
66321
|
+
if (!url || seen.has(url)) continue;
|
|
66322
|
+
seen.add(url);
|
|
66323
|
+
merged.push({
|
|
66324
|
+
url,
|
|
66325
|
+
title: historyTitle(entry.title),
|
|
66326
|
+
visitCount: entry.visitCount,
|
|
66327
|
+
lastVisitedAt: entry.lastVisitedAt,
|
|
66328
|
+
source: "history"
|
|
66329
|
+
});
|
|
66330
|
+
}
|
|
66331
|
+
const needle = foldAscii(query.trim());
|
|
66332
|
+
for (const entry of tabEntries) {
|
|
66333
|
+
if (merged.length >= cap) break;
|
|
66334
|
+
if (seen.has(entry.url)) continue;
|
|
66335
|
+
if (needle.length > 0 && !foldAscii(entry.url).includes(needle) && !foldAscii(entry.title).includes(needle))
|
|
66336
|
+
continue;
|
|
66337
|
+
seen.add(entry.url);
|
|
66338
|
+
merged.push(entry);
|
|
66339
|
+
}
|
|
66340
|
+
return merged;
|
|
66341
|
+
}
|
|
66108
66342
|
class ChromeTabOrder {
|
|
66109
66343
|
ids = [];
|
|
66110
66344
|
customized = false;
|
|
@@ -66134,6 +66368,305 @@ class ChromeTabOrder {
|
|
|
66134
66368
|
return true;
|
|
66135
66369
|
}
|
|
66136
66370
|
}
|
|
66371
|
+
const HISTORY_STORE_VERSION = 1;
|
|
66372
|
+
const HISTORY_STORE_MAX_ENTRIES = 5e3;
|
|
66373
|
+
const HISTORY_STORE_MAX_BYTES = 2 * 1024 * 1024;
|
|
66374
|
+
const HISTORY_STORE_WRITE_DEBOUNCE_MS = 500;
|
|
66375
|
+
const HISTORY_STORE_MAX_CANDIDATES = 200;
|
|
66376
|
+
const PREFIX_WIDTH = 3;
|
|
66377
|
+
const RECENCY_HALF_LIFE_DAYS = 7;
|
|
66378
|
+
const DAY_MS = 24 * 60 * 60 * 1e3;
|
|
66379
|
+
const SCHEME_PREFIX = /^([a-z][a-z0-9+.-]*):\/\//i;
|
|
66380
|
+
const PATH_OR_QUERY = /[/?#]/;
|
|
66381
|
+
function schemeLess(value) {
|
|
66382
|
+
const match = SCHEME_PREFIX.exec(value);
|
|
66383
|
+
return match ? value.slice(match[0].length) : value;
|
|
66384
|
+
}
|
|
66385
|
+
function stripWww(value) {
|
|
66386
|
+
return value.startsWith("www.") && value.length > "www.".length ? value.slice("www.".length) : value;
|
|
66387
|
+
}
|
|
66388
|
+
function matchKey(value) {
|
|
66389
|
+
return stripWww(schemeLess(value.trim()).toLowerCase());
|
|
66390
|
+
}
|
|
66391
|
+
function literalKey(value) {
|
|
66392
|
+
return schemeLess(value.trim()).toLowerCase();
|
|
66393
|
+
}
|
|
66394
|
+
function indexKeys(url) {
|
|
66395
|
+
const keys = /* @__PURE__ */ new Set([literalKey(url), matchKey(url)]);
|
|
66396
|
+
return [...keys].filter((key) => key.length > 0);
|
|
66397
|
+
}
|
|
66398
|
+
function queryNeedles(raw) {
|
|
66399
|
+
const literal = literalKey(raw);
|
|
66400
|
+
const keys = /* @__PURE__ */ new Set([literal, stripWww(literal)]);
|
|
66401
|
+
return [...keys].filter((key) => key.length > 0);
|
|
66402
|
+
}
|
|
66403
|
+
function matchesNeedle(value, needle) {
|
|
66404
|
+
if (!value.startsWith(needle)) return false;
|
|
66405
|
+
const hostOnly = !PATH_OR_QUERY.test(needle);
|
|
66406
|
+
if (!hostOnly) return true;
|
|
66407
|
+
if (!needle.includes(".") || needle.endsWith(".")) return true;
|
|
66408
|
+
const next = value.charAt(needle.length);
|
|
66409
|
+
return next === "" || next === "/" || next === "?" || next === "#" || next === ":";
|
|
66410
|
+
}
|
|
66411
|
+
function prefixKey(matchKeyValue) {
|
|
66412
|
+
return matchKeyValue.slice(0, PREFIX_WIDTH);
|
|
66413
|
+
}
|
|
66414
|
+
function historyScore(entry, now) {
|
|
66415
|
+
const ageDays = Math.max(0, now - entry.lastVisitedAt) / DAY_MS;
|
|
66416
|
+
return Math.log2(1 + entry.visitCount) + 0.5 ** (ageDays / RECENCY_HALF_LIFE_DAYS);
|
|
66417
|
+
}
|
|
66418
|
+
function compareEntries(now) {
|
|
66419
|
+
return (a, b) => {
|
|
66420
|
+
const scoreDiff = historyScore(b, now) - historyScore(a, now);
|
|
66421
|
+
if (scoreDiff !== 0) return scoreDiff;
|
|
66422
|
+
if (a.lastVisitedAt !== b.lastVisitedAt)
|
|
66423
|
+
return b.lastVisitedAt - a.lastVisitedAt;
|
|
66424
|
+
return a.url < b.url ? -1 : a.url > b.url ? 1 : 0;
|
|
66425
|
+
};
|
|
66426
|
+
}
|
|
66427
|
+
function storageUrl(raw) {
|
|
66428
|
+
const canonical = canonicalHistoryUrl(raw);
|
|
66429
|
+
if (!canonical) return null;
|
|
66430
|
+
const hash = canonical.indexOf("#");
|
|
66431
|
+
return hash < 0 ? canonical : canonical.slice(0, hash);
|
|
66432
|
+
}
|
|
66433
|
+
function isEntry(value) {
|
|
66434
|
+
if (typeof value !== "object" || value === null) return false;
|
|
66435
|
+
const record = value;
|
|
66436
|
+
return typeof record.url === "string" && typeof record.title === "string" && typeof record.host === "string" && Number.isSafeInteger(record.visitCount) && record.visitCount > 0 && typeof record.lastVisitedAt === "number" && Number.isFinite(record.lastVisitedAt);
|
|
66437
|
+
}
|
|
66438
|
+
function createBrowserHistoryStore(filePath, options = {}) {
|
|
66439
|
+
const now = options.now ?? Date.now;
|
|
66440
|
+
const byUrl = /* @__PURE__ */ new Map();
|
|
66441
|
+
const prefix = /* @__PURE__ */ new Map();
|
|
66442
|
+
let writeTimer = null;
|
|
66443
|
+
let approxBytes = 0;
|
|
66444
|
+
function estimate(entry) {
|
|
66445
|
+
return entry.url.length + entry.title.length + entry.host.length + 192;
|
|
66446
|
+
}
|
|
66447
|
+
function indexAdd(entry) {
|
|
66448
|
+
approxBytes += estimate(entry);
|
|
66449
|
+
for (const key of indexKeys(entry.url)) {
|
|
66450
|
+
const bucketKey = prefixKey(key);
|
|
66451
|
+
let bucket = prefix.get(bucketKey);
|
|
66452
|
+
if (!bucket) {
|
|
66453
|
+
bucket = /* @__PURE__ */ new Set();
|
|
66454
|
+
prefix.set(bucketKey, bucket);
|
|
66455
|
+
}
|
|
66456
|
+
bucket.add(entry.url);
|
|
66457
|
+
}
|
|
66458
|
+
}
|
|
66459
|
+
function indexRemove(entry) {
|
|
66460
|
+
approxBytes -= estimate(entry);
|
|
66461
|
+
for (const key of indexKeys(entry.url)) {
|
|
66462
|
+
const bucketKey = prefixKey(key);
|
|
66463
|
+
const bucket = prefix.get(bucketKey);
|
|
66464
|
+
bucket?.delete(entry.url);
|
|
66465
|
+
if (bucket?.size === 0) prefix.delete(bucketKey);
|
|
66466
|
+
}
|
|
66467
|
+
}
|
|
66468
|
+
function setTitle(entry, next) {
|
|
66469
|
+
const before = estimate(entry);
|
|
66470
|
+
entry.title = next;
|
|
66471
|
+
approxBytes += estimate(entry) - before;
|
|
66472
|
+
}
|
|
66473
|
+
function enforceBounds(at) {
|
|
66474
|
+
let changed = false;
|
|
66475
|
+
if (byUrl.size <= HISTORY_STORE_MAX_ENTRIES && approxBytes <= HISTORY_STORE_MAX_BYTES)
|
|
66476
|
+
return false;
|
|
66477
|
+
if (byUrl.size > HISTORY_STORE_MAX_ENTRIES) {
|
|
66478
|
+
const overflow = byUrl.size - HISTORY_STORE_MAX_ENTRIES;
|
|
66479
|
+
const victims = [...byUrl.values()].sort(compareEntries(at)).reverse().slice(0, overflow);
|
|
66480
|
+
for (const victim of victims) {
|
|
66481
|
+
byUrl.delete(victim.url);
|
|
66482
|
+
indexRemove(victim);
|
|
66483
|
+
changed = true;
|
|
66484
|
+
}
|
|
66485
|
+
}
|
|
66486
|
+
let guard = 0;
|
|
66487
|
+
while (guard < 200 && byUrl.size > 0) {
|
|
66488
|
+
guard += 1;
|
|
66489
|
+
const bytes = Buffer.byteLength(
|
|
66490
|
+
JSON.stringify(document(), null, 2),
|
|
66491
|
+
"utf8"
|
|
66492
|
+
);
|
|
66493
|
+
if (bytes <= HISTORY_STORE_MAX_BYTES) {
|
|
66494
|
+
approxBytes = bytes;
|
|
66495
|
+
break;
|
|
66496
|
+
}
|
|
66497
|
+
const batch = Math.max(1, Math.ceil(byUrl.size / 100));
|
|
66498
|
+
const victims = [...byUrl.values()].sort(compareEntries(at)).reverse().slice(0, batch);
|
|
66499
|
+
for (const victim of victims) {
|
|
66500
|
+
byUrl.delete(victim.url);
|
|
66501
|
+
indexRemove(victim);
|
|
66502
|
+
changed = true;
|
|
66503
|
+
}
|
|
66504
|
+
}
|
|
66505
|
+
return changed;
|
|
66506
|
+
}
|
|
66507
|
+
function document() {
|
|
66508
|
+
return {
|
|
66509
|
+
version: HISTORY_STORE_VERSION,
|
|
66510
|
+
entries: [...byUrl.values()]
|
|
66511
|
+
};
|
|
66512
|
+
}
|
|
66513
|
+
function writeNow() {
|
|
66514
|
+
if (writeTimer !== null) {
|
|
66515
|
+
clearTimeout(writeTimer);
|
|
66516
|
+
writeTimer = null;
|
|
66517
|
+
}
|
|
66518
|
+
writeJsonAtomic(filePath, document());
|
|
66519
|
+
}
|
|
66520
|
+
function scheduleWrite2() {
|
|
66521
|
+
if (writeTimer !== null) return;
|
|
66522
|
+
writeTimer = setTimeout(() => {
|
|
66523
|
+
writeTimer = null;
|
|
66524
|
+
writeJsonAtomic(filePath, document());
|
|
66525
|
+
}, HISTORY_STORE_WRITE_DEBOUNCE_MS);
|
|
66526
|
+
writeTimer.unref?.();
|
|
66527
|
+
}
|
|
66528
|
+
const loaded = readJson(filePath);
|
|
66529
|
+
if (loaded && loaded.version === HISTORY_STORE_VERSION && Array.isArray(loaded.entries)) {
|
|
66530
|
+
for (const raw of loaded.entries) {
|
|
66531
|
+
if (!isEntry(raw)) continue;
|
|
66532
|
+
const url = storageUrl(raw.url);
|
|
66533
|
+
if (!url) continue;
|
|
66534
|
+
const host = new URL(url).host;
|
|
66535
|
+
const existing = byUrl.get(url);
|
|
66536
|
+
if (existing) {
|
|
66537
|
+
existing.visitCount = Math.max(existing.visitCount, raw.visitCount);
|
|
66538
|
+
existing.lastVisitedAt = Math.max(
|
|
66539
|
+
existing.lastVisitedAt,
|
|
66540
|
+
raw.lastVisitedAt
|
|
66541
|
+
);
|
|
66542
|
+
if (existing.title.length === 0) {
|
|
66543
|
+
const title = historyTitle(raw.title);
|
|
66544
|
+
if (title.length > 0) setTitle(existing, title);
|
|
66545
|
+
}
|
|
66546
|
+
continue;
|
|
66547
|
+
}
|
|
66548
|
+
const entry = {
|
|
66549
|
+
url,
|
|
66550
|
+
title: historyTitle(raw.title),
|
|
66551
|
+
host,
|
|
66552
|
+
visitCount: raw.visitCount,
|
|
66553
|
+
lastVisitedAt: raw.lastVisitedAt
|
|
66554
|
+
};
|
|
66555
|
+
byUrl.set(url, entry);
|
|
66556
|
+
indexAdd(entry);
|
|
66557
|
+
}
|
|
66558
|
+
if (enforceBounds(now())) {
|
|
66559
|
+
writeNow();
|
|
66560
|
+
}
|
|
66561
|
+
}
|
|
66562
|
+
return {
|
|
66563
|
+
record(rawUrl, rawTitle, at = now()) {
|
|
66564
|
+
const url = storageUrl(rawUrl);
|
|
66565
|
+
if (!url) return;
|
|
66566
|
+
const title = historyTitle(rawTitle);
|
|
66567
|
+
const existing = byUrl.get(url);
|
|
66568
|
+
if (existing) {
|
|
66569
|
+
existing.visitCount += 1;
|
|
66570
|
+
existing.lastVisitedAt = at;
|
|
66571
|
+
if (title.length > 0 && title !== existing.title)
|
|
66572
|
+
setTitle(existing, title);
|
|
66573
|
+
} else {
|
|
66574
|
+
const entry = {
|
|
66575
|
+
url,
|
|
66576
|
+
title,
|
|
66577
|
+
host: new URL(url).host,
|
|
66578
|
+
visitCount: 1,
|
|
66579
|
+
lastVisitedAt: at
|
|
66580
|
+
};
|
|
66581
|
+
byUrl.set(url, entry);
|
|
66582
|
+
indexAdd(entry);
|
|
66583
|
+
}
|
|
66584
|
+
enforceBounds(at);
|
|
66585
|
+
scheduleWrite2();
|
|
66586
|
+
},
|
|
66587
|
+
updateTitle(rawUrl, rawTitle) {
|
|
66588
|
+
const url = storageUrl(rawUrl);
|
|
66589
|
+
if (!url) return;
|
|
66590
|
+
const entry = byUrl.get(url);
|
|
66591
|
+
if (!entry) return;
|
|
66592
|
+
const title = historyTitle(rawTitle);
|
|
66593
|
+
if (title.length === 0 || title === entry.title) return;
|
|
66594
|
+
setTitle(entry, title);
|
|
66595
|
+
enforceBounds(now());
|
|
66596
|
+
scheduleWrite2();
|
|
66597
|
+
},
|
|
66598
|
+
suggest(rawQuery, limit) {
|
|
66599
|
+
const wanted = Math.max(0, Math.floor(limit));
|
|
66600
|
+
if (wanted === 0 || byUrl.size === 0) return [];
|
|
66601
|
+
const at = now();
|
|
66602
|
+
if (rawQuery.length === 0) {
|
|
66603
|
+
return [...byUrl.values()].sort(compareEntries(at)).slice(0, wanted);
|
|
66604
|
+
}
|
|
66605
|
+
const needles = queryNeedles(rawQuery);
|
|
66606
|
+
if (needles.length === 0) return [];
|
|
66607
|
+
const bucketSet = /* @__PURE__ */ new Set();
|
|
66608
|
+
for (const needle of needles) {
|
|
66609
|
+
if (needle.length >= PREFIX_WIDTH) {
|
|
66610
|
+
const bucket = prefix.get(prefixKey(needle));
|
|
66611
|
+
if (bucket) bucketSet.add(bucket);
|
|
66612
|
+
} else {
|
|
66613
|
+
for (const [key, bucket] of prefix) {
|
|
66614
|
+
if (key.startsWith(needle)) bucketSet.add(bucket);
|
|
66615
|
+
}
|
|
66616
|
+
}
|
|
66617
|
+
}
|
|
66618
|
+
const buckets = [...bucketSet];
|
|
66619
|
+
if (buckets.length === 0) return [];
|
|
66620
|
+
const candidates = [];
|
|
66621
|
+
const seen = /* @__PURE__ */ new Set();
|
|
66622
|
+
for (const bucket of buckets) {
|
|
66623
|
+
for (const url of bucket) {
|
|
66624
|
+
if (candidates.length >= HISTORY_STORE_MAX_CANDIDATES) break;
|
|
66625
|
+
if (seen.has(url)) continue;
|
|
66626
|
+
const keys = indexKeys(url);
|
|
66627
|
+
const hit = needles.some(
|
|
66628
|
+
(needle) => keys.some((key) => matchesNeedle(key, needle))
|
|
66629
|
+
);
|
|
66630
|
+
if (!hit) continue;
|
|
66631
|
+
const entry = byUrl.get(url);
|
|
66632
|
+
if (!entry) continue;
|
|
66633
|
+
seen.add(url);
|
|
66634
|
+
candidates.push(entry);
|
|
66635
|
+
}
|
|
66636
|
+
if (candidates.length >= HISTORY_STORE_MAX_CANDIDATES) break;
|
|
66637
|
+
}
|
|
66638
|
+
candidates.sort(compareEntries(at));
|
|
66639
|
+
return candidates.slice(0, wanted);
|
|
66640
|
+
},
|
|
66641
|
+
size() {
|
|
66642
|
+
return byUrl.size;
|
|
66643
|
+
},
|
|
66644
|
+
clear() {
|
|
66645
|
+
byUrl.clear();
|
|
66646
|
+
prefix.clear();
|
|
66647
|
+
writeNow();
|
|
66648
|
+
},
|
|
66649
|
+
clearOrigin(rawOrigin) {
|
|
66650
|
+
let parsed;
|
|
66651
|
+
try {
|
|
66652
|
+
parsed = new URL(rawOrigin);
|
|
66653
|
+
} catch {
|
|
66654
|
+
return;
|
|
66655
|
+
}
|
|
66656
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return;
|
|
66657
|
+
const origin = parsed.origin;
|
|
66658
|
+
for (const [url, entry] of [...byUrl.entries()]) {
|
|
66659
|
+
if (new URL(url).origin !== origin) continue;
|
|
66660
|
+
byUrl.delete(url);
|
|
66661
|
+
indexRemove(entry);
|
|
66662
|
+
}
|
|
66663
|
+
writeNow();
|
|
66664
|
+
},
|
|
66665
|
+
flush() {
|
|
66666
|
+
if (writeTimer !== null) writeNow();
|
|
66667
|
+
}
|
|
66668
|
+
};
|
|
66669
|
+
}
|
|
66137
66670
|
const PAGE_ZOOM_STEPS = [
|
|
66138
66671
|
0.25,
|
|
66139
66672
|
0.33,
|
|
@@ -66512,6 +67045,9 @@ class BrowserHost {
|
|
|
66512
67045
|
* projection as the tabs, so the renderer has one source for "child or
|
|
66513
67046
|
* fallback" and never guesses from a failed IPC call. */
|
|
66514
67047
|
addressOverlayMode;
|
|
67048
|
+
/** One instance per host, constructed once in the constructor. `null` when
|
|
67049
|
+
* no path was supplied (see `BrowserHostOptions.historyFilePath`). */
|
|
67050
|
+
historyStore;
|
|
66515
67051
|
/**
|
|
66516
67052
|
* The last main-frame load failure per tab, cleared by the next load.
|
|
66517
67053
|
*
|
|
@@ -66538,6 +67074,7 @@ class BrowserHost {
|
|
|
66538
67074
|
this.facts = options.facts;
|
|
66539
67075
|
this.forgetSiteData = options.forgetSiteData;
|
|
66540
67076
|
this.addressOverlayMode = options.addressOverlayMode ?? (() => ({ mode: "suspend", reason: "unavailable" }));
|
|
67077
|
+
this.historyStore = options.historyFilePath ? createBrowserHistoryStore(options.historyFilePath) : null;
|
|
66541
67078
|
}
|
|
66542
67079
|
/** Answer one wire request. The only place a method name becomes an action. */
|
|
66543
67080
|
async dispatch(method, params, requestId2) {
|
|
@@ -67405,8 +67942,13 @@ class BrowserHost {
|
|
|
67405
67942
|
* no longer matches, which covers the race between this check and the reply
|
|
67406
67943
|
* landing.
|
|
67407
67944
|
*
|
|
67408
|
-
*
|
|
67409
|
-
*
|
|
67945
|
+
* RANKING MOVED HERE with the persistent store: the renderer used to rank a
|
|
67946
|
+
* snapshot of every stack, which cannot scale to a 5000-entry history either
|
|
67947
|
+
* in memory or across IPC. Main now asks the store for its top matches, puts
|
|
67948
|
+
* them ahead of the live-tab rows (`mergeAddressHistory`), and bounds the
|
|
67949
|
+
* answer by `request.limit`. The renderer still derives display text, the
|
|
67950
|
+
* target URL and the inline suffix, because those depend on exactly what the
|
|
67951
|
+
* user typed.
|
|
67410
67952
|
*/
|
|
67411
67953
|
addressHistory(request) {
|
|
67412
67954
|
const activeTabId = this.registry.activeTab?.tabId ?? null;
|
|
@@ -67416,20 +67958,59 @@ class BrowserHost {
|
|
|
67416
67958
|
"the active tab changed before suggestions were read"
|
|
67417
67959
|
);
|
|
67418
67960
|
}
|
|
67961
|
+
const live = collectAddressHistory(
|
|
67962
|
+
this.registry.list().map((record) => ({
|
|
67963
|
+
tabId: record.tabId,
|
|
67964
|
+
sessionId: record.sessionId,
|
|
67965
|
+
webContents: record.view.webContents,
|
|
67966
|
+
restoreRow: record.restoreRow ?? null
|
|
67967
|
+
})),
|
|
67968
|
+
activeTabId
|
|
67969
|
+
);
|
|
67970
|
+
const historyMatches = this.historyStore?.suggest(request.query, request.limit) ?? [];
|
|
67419
67971
|
return {
|
|
67420
67972
|
requestId: request.requestId,
|
|
67421
|
-
|
|
67422
|
-
|
|
67423
|
-
|
|
67424
|
-
|
|
67425
|
-
|
|
67426
|
-
|
|
67427
|
-
})),
|
|
67428
|
-
request.scope,
|
|
67429
|
-
activeTabId
|
|
67973
|
+
activeTabId: live.activeTabId,
|
|
67974
|
+
entries: mergeAddressHistory(
|
|
67975
|
+
live.entries,
|
|
67976
|
+
historyMatches,
|
|
67977
|
+
request.query,
|
|
67978
|
+
request.limit
|
|
67430
67979
|
)
|
|
67431
67980
|
};
|
|
67432
67981
|
}
|
|
67982
|
+
/**
|
|
67983
|
+
* Record one committed top-level navigation.
|
|
67984
|
+
*
|
|
67985
|
+
* Called from the per-view wiring in `index.ts`, which is the only place that
|
|
67986
|
+
* sees the event for every tab. A non-HTTP(S) URL is dropped by the store, so
|
|
67987
|
+
* `about:blank`, `chrome://` and a refused scheme never enter the document.
|
|
67988
|
+
* The title is filled in by `recordHistoryTitle` when Chromium announces it;
|
|
67989
|
+
* recording the visit first is deliberate, because the commit is the fact and
|
|
67990
|
+
* the title is a later, optional update.
|
|
67991
|
+
*/
|
|
67992
|
+
recordHistoryVisit(url) {
|
|
67993
|
+
this.historyStore?.record(url, "");
|
|
67994
|
+
}
|
|
67995
|
+
/** Update the stored title for a URL that is already in the history. Never
|
|
67996
|
+
* increments a visit: `page-title-updated` fires for a page that has already
|
|
67997
|
+
* been counted, sometimes several times. */
|
|
67998
|
+
recordHistoryTitle(url, title) {
|
|
67999
|
+
this.historyStore?.updateTitle(url, title);
|
|
68000
|
+
}
|
|
68001
|
+
/** Write any debounced history change now (quit, and the host's own stop). */
|
|
68002
|
+
flushHistory() {
|
|
68003
|
+
this.historyStore?.flush();
|
|
68004
|
+
}
|
|
68005
|
+
/** "Clear everything" also forgets the suggestion history (`profile.ts` is
|
|
68006
|
+
* the path that calls this, so cookies/cache alone cannot reach it). */
|
|
68007
|
+
clearHistory() {
|
|
68008
|
+
this.historyStore?.clear();
|
|
68009
|
+
}
|
|
68010
|
+
/** "Forget this site" drops that origin's rows; other origins stay. */
|
|
68011
|
+
clearOriginHistory(origin) {
|
|
68012
|
+
this.historyStore?.clearOrigin(origin);
|
|
68013
|
+
}
|
|
67433
68014
|
/**
|
|
67434
68015
|
* A URL the USER typed goes through here, and it is deliberately different from
|
|
67435
68016
|
* an agent navigation in one way and identical in another (design 6.1):
|
|
@@ -68889,21 +69470,17 @@ function addressHistoryRequestOrThrow(value) {
|
|
|
68889
69470
|
const request = value;
|
|
68890
69471
|
const requestId2 = numberOrThrow(request.requestId, "requestId");
|
|
68891
69472
|
const expectedTabId = tabIdOrThrow(request.expectedTabId, "expectedTabId");
|
|
68892
|
-
|
|
68893
|
-
|
|
68894
|
-
|
|
68895
|
-
|
|
68896
|
-
|
|
68897
|
-
|
|
68898
|
-
throw new Error(
|
|
68899
|
-
"The address history scope needs a valid conversation id."
|
|
68900
|
-
);
|
|
68901
|
-
}
|
|
68902
|
-
scope = { sessionId: sessionId2 };
|
|
68903
|
-
} else {
|
|
68904
|
-
throw new Error("The address history scope is invalid.");
|
|
69473
|
+
if (typeof request.query !== "string") {
|
|
69474
|
+
throw new Error("The address history query must be a string.");
|
|
69475
|
+
}
|
|
69476
|
+
const query = request.query;
|
|
69477
|
+
if (query.length > ADDRESS_HISTORY_MAX_QUERY_LENGTH || CONTROL_CHARS.test(query)) {
|
|
69478
|
+
throw new Error("The address history query is invalid.");
|
|
68905
69479
|
}
|
|
68906
|
-
|
|
69480
|
+
if (typeof request.limit !== "number" || !Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > ADDRESS_HISTORY_MAX_LIMIT) {
|
|
69481
|
+
throw new Error("The address history limit is invalid.");
|
|
69482
|
+
}
|
|
69483
|
+
return { requestId: requestId2, expectedTabId, query, limit: request.limit };
|
|
68907
69484
|
}
|
|
68908
69485
|
function closeTabsIntentOrThrow(value) {
|
|
68909
69486
|
if (!value || typeof value !== "object") {
|
|
@@ -69422,7 +69999,7 @@ function installBrowserSessionHandlers(browserSession, hooks = {}) {
|
|
|
69422
69999
|
browserSession.removeListener("will-download", onDownload);
|
|
69423
70000
|
};
|
|
69424
70001
|
}
|
|
69425
|
-
async function clearBrowsingData(browserSession, what) {
|
|
70002
|
+
async function clearBrowsingData(browserSession, what, history) {
|
|
69426
70003
|
browserSession.flushStorageData();
|
|
69427
70004
|
if (what === "cache") {
|
|
69428
70005
|
await browserSession.clearCache();
|
|
@@ -69444,8 +70021,9 @@ async function clearBrowsingData(browserSession, what) {
|
|
|
69444
70021
|
}
|
|
69445
70022
|
await browserSession.clearData();
|
|
69446
70023
|
await browserSession.clearCache();
|
|
70024
|
+
history?.clear();
|
|
69447
70025
|
}
|
|
69448
|
-
async function clearOriginData(browserSession, origin) {
|
|
70026
|
+
async function clearOriginData(browserSession, origin, history) {
|
|
69449
70027
|
browserSession.flushStorageData();
|
|
69450
70028
|
await browserSession.clearData({
|
|
69451
70029
|
origins: [origin],
|
|
@@ -69461,6 +70039,7 @@ async function clearOriginData(browserSession, origin) {
|
|
|
69461
70039
|
"cache"
|
|
69462
70040
|
]
|
|
69463
70041
|
});
|
|
70042
|
+
history?.clearOrigin(origin);
|
|
69464
70043
|
}
|
|
69465
70044
|
function flushBrowserStorage(browserSession) {
|
|
69466
70045
|
try {
|
|
@@ -70747,6 +71326,9 @@ function refusesNavigation(rawUrl) {
|
|
|
70747
71326
|
}
|
|
70748
71327
|
}
|
|
70749
71328
|
let activeHost = null;
|
|
71329
|
+
electron.app.on("before-quit", () => {
|
|
71330
|
+
activeHost?.host.flushHistory();
|
|
71331
|
+
});
|
|
70750
71332
|
function routeBrowserZoomInput(event, input) {
|
|
70751
71333
|
const candidate = browserChordIntent(
|
|
70752
71334
|
{ ...input, isAutoRepeat: false, isComposing: false },
|
|
@@ -71094,7 +71676,10 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71094
71676
|
notifyChrome();
|
|
71095
71677
|
});
|
|
71096
71678
|
contents.on("did-stop-loading", notifyChrome);
|
|
71097
|
-
contents.on("page-title-updated",
|
|
71679
|
+
contents.on("page-title-updated", (_event, title) => {
|
|
71680
|
+
host.recordHistoryTitle(contents.getURL(), title);
|
|
71681
|
+
notifyChrome();
|
|
71682
|
+
});
|
|
71098
71683
|
contents.on("render-process-gone", () => {
|
|
71099
71684
|
addressOverlay?.onPageGone(tabId);
|
|
71100
71685
|
});
|
|
@@ -71122,12 +71707,14 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71122
71707
|
stopLogCapture(contents.id);
|
|
71123
71708
|
startLogCapture(contents.id);
|
|
71124
71709
|
log2(`[browser] tab ${tabId} navigated to ${url}`);
|
|
71710
|
+
host.recordHistoryVisit(url);
|
|
71125
71711
|
notifyChanged();
|
|
71126
71712
|
});
|
|
71127
71713
|
contents.on("did-navigate-in-page", (_event, url, isMainFrame) => {
|
|
71128
71714
|
if (!isMainFrame) return;
|
|
71129
71715
|
registry.bumpEpoch(tabId, false);
|
|
71130
71716
|
log2(`[browser] tab ${tabId} navigated in page to ${url}`);
|
|
71717
|
+
host.recordHistoryVisit(url);
|
|
71131
71718
|
notifyChanged();
|
|
71132
71719
|
});
|
|
71133
71720
|
contents.on("destroyed", () => {
|
|
@@ -71266,6 +71853,9 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71266
71853
|
rollback.add(() => webauthn.dispose());
|
|
71267
71854
|
const detachWebauthn = attachWebauthnChooser(browserSession, webauthn, log2);
|
|
71268
71855
|
rollback.add(detachWebauthn);
|
|
71856
|
+
const historyClearer = {
|
|
71857
|
+
current: null
|
|
71858
|
+
};
|
|
71269
71859
|
const cookieJar = createHiddenCookieJarTarget(
|
|
71270
71860
|
new electron.WebContentsView({
|
|
71271
71861
|
webPreferences: { ...HIDDEN_COOKIE_JAR_WEB_PREFERENCES }
|
|
@@ -71277,7 +71867,7 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71277
71867
|
cipher: browserProfileCipher(),
|
|
71278
71868
|
...sessionCookiePaths(options.userDataDir),
|
|
71279
71869
|
flushStore: () => browserSession.cookies.flushStore(),
|
|
71280
|
-
clearSessionData: (what) => clearBrowsingData(browserSession, what),
|
|
71870
|
+
clearSessionData: (what) => clearBrowsingData(browserSession, what, historyClearer.current),
|
|
71281
71871
|
log: log2
|
|
71282
71872
|
});
|
|
71283
71873
|
let restoreReport = null;
|
|
@@ -71434,12 +72024,17 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71434
72024
|
log: log2,
|
|
71435
72025
|
onChanged: notifyChanged,
|
|
71436
72026
|
facts: () => facts,
|
|
71437
|
-
forgetSiteData: (origin) => clearOriginData(browserSession, origin),
|
|
72027
|
+
forgetSiteData: (origin) => clearOriginData(browserSession, origin, historyClearer.current),
|
|
72028
|
+
historyFilePath: path$1.join(options.userDataDir, "browser-history.json"),
|
|
71438
72029
|
addressOverlayMode: () => addressOverlay ? addressOverlay.mode() : {
|
|
71439
72030
|
mode: "suspend",
|
|
71440
72031
|
reason: options.addressOverlay?.product === true ? "unavailable" : "platform"
|
|
71441
72032
|
}
|
|
71442
72033
|
});
|
|
72034
|
+
historyClearer.current = {
|
|
72035
|
+
clear: () => host.clearHistory(),
|
|
72036
|
+
clearOrigin: (origin) => host.clearOriginHistory(origin)
|
|
72037
|
+
};
|
|
71443
72038
|
const ownsChrome = () => browserChromeOwnsChord({
|
|
71444
72039
|
logicalFocus: host.chordFocus,
|
|
71445
72040
|
chromeVisible: registry.chromeVisible,
|
|
@@ -71687,6 +72282,7 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71687
72282
|
...addressOverlay ? { addressOverlay: probeAddressOverlay } : {},
|
|
71688
72283
|
stop: async () => {
|
|
71689
72284
|
detachChords();
|
|
72285
|
+
host.flushHistory();
|
|
71690
72286
|
const atStop = captureTabs(
|
|
71691
72287
|
registry.list(),
|
|
71692
72288
|
registry.activeTab?.tabId ?? null,
|
|
@@ -72608,7 +73204,7 @@ class DesktopNotifier {
|
|
|
72608
73204
|
notice.sessionId,
|
|
72609
73205
|
notice.surfaceName,
|
|
72610
73206
|
"",
|
|
72611
|
-
notice.exitCode === null ? "Console finished" : `Console exited with code ${notice.exitCode}`,
|
|
73207
|
+
notice.exitSignal ? `Console killed by ${notice.exitSignal}` : notice.exitCode === null ? "Console finished" : `Console exited with code ${notice.exitCode}`,
|
|
72612
73208
|
false,
|
|
72613
73209
|
false,
|
|
72614
73210
|
notice.surface
|