summrise-agent 1.2.495 → 1.2.506
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/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "summrise-agent",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "Summrise Agent
|
|
5
|
-
"//build": "
|
|
3
|
+
"version": "1.2.506",
|
|
4
|
+
"description": "Summrise Agent \u2014 Windows device MCP server (terminal/SSH/serial) + panel. Self-hosted npm distribution.",
|
|
5
|
+
"//build": "\u552f\u4e00\u6784\u5efa\u8def\u5f84\uff1a\u5728\u672c\u76ee\u5f55\u6267\u884c npm run build\u3002\u5b83\u662f\u81ea\u5305\u542b\u7684\uff1a\u7ecf npm exec \u6309\u9700\u62c9\u53d6 typescript@5\uff0c\u65e0\u9700\u9884\u88c5\u4efb\u4f55 node_modules\uff08\u5e72\u51c0\u68c0\u51fa\u53ef\u8dd1\uff1b\u65e7\u811a\u672c\u5f15\u7528 ../summrise-desktop-electron/node_modules/.bin/tsc\uff0c\u5e72\u51c0\u68c0\u51fa\u5fc5 ENOENT\uff09\u3002\u5fc5\u987b\u7528 npm exec --package \u2026 -- tsc \u7684\u5f62\u5f0f\uff1anpx \u4f1a\u5403\u6389\u4f20\u7ed9 tsc \u7684 -p/--outDir \u7b49\u53c2\u6570\uff08round-435\uff1anpx \u5199\u6cd5\u4ece\u672a\u771f\u6b63\u8dd1\u901a\u8fc7\uff09\u3002\u5148\u7f16 electron TS\uff08--noCheck \u7eaf emit\uff0c\u4e0e release.yml \u4e00\u81f4\uff09\u540c\u6b65\u4e24\u5904 src/*.js\uff0c\u518d\u7f16 src/summrise.ts \u5230 bin/summrise.js \u5e76\u6821\u9a8c round-298 \u6807\u8bb0\uff08\u5f31 oracle\uff0c\u53ea\u8bc1\u67d0\u6b21\u6784\u5efa\u53d1\u751f\uff0c\u65b0\u9c9c\u6027\u7531 publish-release.sh \u7684 tsc \u91cd\u7f16 + cmp \u95e8\u4fdd\u8bc1\uff09\u3002",
|
|
6
6
|
"bin": {
|
|
7
7
|
"summrise": "bin/summrise.js"
|
|
8
8
|
},
|
package/summrise-agent.exe
CHANGED
|
Binary file
|
|
@@ -692,6 +692,148 @@ ipcHandle("embedded-browser:place", (bounds) => {
|
|
|
692
692
|
return { ok: true };
|
|
693
693
|
});
|
|
694
694
|
ipcHandle("embedded-browser:state", () => embeddedState());
|
|
695
|
+
// ── THE DSH VIEW: the harness's own UI, embedded in summrise ────────────────────────────────
|
|
696
|
+
//
|
|
697
|
+
// WHY LOOPBACK AND NOT THE PUBLIC HOSTNAME. The DSH runs on THIS machine (127.0.0.1:18081), and
|
|
698
|
+
// this view is a window ON this machine — so loopback is the correct address, not the remote
|
|
699
|
+
// one. Going out to the tunnel hostname instead would mean: a Cloudflare round trip for every
|
|
700
|
+
// asset, an Access login inside the shell, and a certificate story — for a service that is
|
|
701
|
+
// already here. (The spec's warning about loopback applies to the OTHER direction: a page viewed
|
|
702
|
+
// REMOTELY resolves 127.0.0.1 to the viewer's machine, which is why the panel's /dsh/ proxy was
|
|
703
|
+
// proposed. A native view on the device has no such problem.)
|
|
704
|
+
//
|
|
705
|
+
// A SECOND view, not a re-use of the browser one: the browser view is a single-tab internet
|
|
706
|
+
// browser an AI drives over CDP, and navigating it to the DSH would throw that session away.
|
|
707
|
+
let dshView = null;
|
|
708
|
+
let dshVisible = false;
|
|
709
|
+
let dshBounds = null;
|
|
710
|
+
/** The DSH's port. Env first (a deployment may move it), else the component's default. */
|
|
711
|
+
function resolveDshPort() {
|
|
712
|
+
const fromEnv = Number(process.env.SUMMRISE_DSH_PORT);
|
|
713
|
+
return Number.isInteger(fromEnv) && fromEnv > 0 && fromEnv < 65536 ? fromEnv : 18081;
|
|
714
|
+
}
|
|
715
|
+
/** The ONE load door for this view: its own origin, or nothing. */
|
|
716
|
+
function dshTarget(raw) {
|
|
717
|
+
return (0, url_policy_1.isDshUrl)(raw) ? new URL(raw).toString() : "about:blank";
|
|
718
|
+
}
|
|
719
|
+
function dshViewEnsure() {
|
|
720
|
+
if (dshView && !dshView.webContents.isDestroyed())
|
|
721
|
+
return dshView;
|
|
722
|
+
const view = new electron_1.WebContentsView({
|
|
723
|
+
webPreferences: {
|
|
724
|
+
contextIsolation: true,
|
|
725
|
+
nodeIntegration: false,
|
|
726
|
+
sandbox: true,
|
|
727
|
+
// No preload: the DSH SPA needs no Node surface, and a view that cannot reach one cannot
|
|
728
|
+
// be talked into using one.
|
|
729
|
+
},
|
|
730
|
+
});
|
|
731
|
+
view.setVisible(false);
|
|
732
|
+
dshVisible = false;
|
|
733
|
+
// The DSH opens links (docs, the operator's own pages) with target=_blank. Deny the POPUP but
|
|
734
|
+
// keep the click meaningful where the door allows it — and the door allows one origin, so in
|
|
735
|
+
// practice an external link is simply dropped rather than silently navigating this view away
|
|
736
|
+
// from the harness.
|
|
737
|
+
view.webContents.setWindowOpenHandler(({ url }) => {
|
|
738
|
+
const target = dshTarget(url);
|
|
739
|
+
if (target !== "about:blank")
|
|
740
|
+
dshNavigate(target);
|
|
741
|
+
return { action: "deny" };
|
|
742
|
+
});
|
|
743
|
+
view.webContents.on("render-process-gone", (_e, details) => {
|
|
744
|
+
try {
|
|
745
|
+
view.setVisible(false);
|
|
746
|
+
}
|
|
747
|
+
catch { /* already gone */ }
|
|
748
|
+
dshVisible = false;
|
|
749
|
+
// The SAME signal the browser view sends, for the same reason (round-256 there): without it
|
|
750
|
+
// the pane shows "starting…" forever over a view that will never paint, and the operator has
|
|
751
|
+
// no way to tell a slow load from a dead renderer.
|
|
752
|
+
if (win && !win.isDestroyed()) {
|
|
753
|
+
win.webContents.send("embedded-dsh:gone", { reason: details.reason, exitCode: details.exitCode });
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
dshView = view;
|
|
757
|
+
if (win)
|
|
758
|
+
win.contentView.addChildView(view);
|
|
759
|
+
return view;
|
|
760
|
+
}
|
|
761
|
+
function dshNavigate(url) {
|
|
762
|
+
const target = dshTarget(url);
|
|
763
|
+
const view = dshViewEnsure();
|
|
764
|
+
view.webContents.loadURL(target).catch(() => { });
|
|
765
|
+
return { ok: true, url: target };
|
|
766
|
+
}
|
|
767
|
+
/** Open (or re-focus) the DSH at its configured address. Idempotent. */
|
|
768
|
+
function dshOpen() {
|
|
769
|
+
return dshNavigate((0, url_policy_1.dshBase)() + "/");
|
|
770
|
+
}
|
|
771
|
+
/** Place the view over the SPA's slot. Empty bounds hide it (the same contract as the browser). */
|
|
772
|
+
function dshPlace(bounds) {
|
|
773
|
+
const view = dshViewEnsure();
|
|
774
|
+
if (!win)
|
|
775
|
+
return;
|
|
776
|
+
if (!bounds || bounds.width < 50 || bounds.height < 50) {
|
|
777
|
+
view.setVisible(false);
|
|
778
|
+
dshVisible = false;
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
dshBounds = bounds;
|
|
782
|
+
view.setBounds(bounds);
|
|
783
|
+
view.setVisible(true);
|
|
784
|
+
dshVisible = true;
|
|
785
|
+
win.contentView.addChildView(view);
|
|
786
|
+
}
|
|
787
|
+
function dshReload() {
|
|
788
|
+
const view = dshView;
|
|
789
|
+
if (!view || view.webContents.isDestroyed())
|
|
790
|
+
return { ok: false };
|
|
791
|
+
try {
|
|
792
|
+
view.webContents.reload();
|
|
793
|
+
return { ok: true };
|
|
794
|
+
}
|
|
795
|
+
catch {
|
|
796
|
+
return { ok: false };
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
/** Recover after a renderer crash: a dead webContents never recovers, so re-create the view. */
|
|
800
|
+
function dshRecover() {
|
|
801
|
+
try {
|
|
802
|
+
if (dshView && !dshView.webContents.isDestroyed())
|
|
803
|
+
dshView.webContents.close({ waitForBeforeUnload: false });
|
|
804
|
+
if (dshView) {
|
|
805
|
+
try {
|
|
806
|
+
win?.contentView.removeChildView(dshView);
|
|
807
|
+
}
|
|
808
|
+
catch { /* already gone */ }
|
|
809
|
+
dshView = null;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
catch { /* fall through to ensure() */ }
|
|
813
|
+
const view = dshViewEnsure();
|
|
814
|
+
if (!view || view.webContents.isDestroyed())
|
|
815
|
+
return { ok: false };
|
|
816
|
+
view.webContents.loadURL((0, url_policy_1.dshBase)() + "/").catch(() => { });
|
|
817
|
+
if (dshVisible && win && dshBounds) {
|
|
818
|
+
view.setBounds(dshBounds);
|
|
819
|
+
view.setVisible(true);
|
|
820
|
+
win.contentView.addChildView(view);
|
|
821
|
+
}
|
|
822
|
+
return { ok: true };
|
|
823
|
+
}
|
|
824
|
+
function dshState() {
|
|
825
|
+
const view = dshView;
|
|
826
|
+
const wc = view && !view.webContents.isDestroyed() ? view.webContents : null;
|
|
827
|
+
return { ok: true, url: wc ? wc.getURL() : "", title: wc ? wc.getTitle() : "", visible: dshVisible && !!wc };
|
|
828
|
+
}
|
|
829
|
+
ipcHandle("embedded-dsh:open", () => dshOpen());
|
|
830
|
+
ipcHandle("embedded-dsh:place", (bounds) => {
|
|
831
|
+
dshPlace(bounds);
|
|
832
|
+
return { ok: true };
|
|
833
|
+
});
|
|
834
|
+
ipcHandle("embedded-dsh:state", () => dshState());
|
|
835
|
+
ipcHandle("embedded-dsh:reload", () => dshReload());
|
|
836
|
+
ipcHandle("embedded-dsh:recover", () => dshRecover());
|
|
695
837
|
// Desktop-app settings (auto-launch) — the Settings page toggles this. We
|
|
696
838
|
// manage a per-user scheduled task ("SummriseDesktop", onlogon) instead of
|
|
697
839
|
// Electron's setLoginItemSettings: in dev mode (electron .) the login-item
|
|
@@ -932,6 +1074,9 @@ if (gotTheLock) {
|
|
|
932
1074
|
// Custom-port installs: pin every origin predicate + probe/load URL to
|
|
933
1075
|
// the agent's actual bind port BEFORE any window or probe exists.
|
|
934
1076
|
(0, url_policy_1.setAgentPort)(resolveAgentPort());
|
|
1077
|
+
// The DSH view's door, pinned the same way and for the same reason: a predicate that ran
|
|
1078
|
+
// before this line would check a port nothing is listening on.
|
|
1079
|
+
(0, url_policy_1.setDshPort)(resolveDshPort());
|
|
935
1080
|
// review #7: with no handler Electron AUTO-GRANTS every permission
|
|
936
1081
|
// request (media/geolocation/clipboard) — deny by default for all
|
|
937
1082
|
// windows, esp. the remote-browser ones loading arbitrary pages.
|
|
@@ -56,6 +56,32 @@ electron_1.contextBridge.exposeInMainWorld("summriseEmbedded", {
|
|
|
56
56
|
return () => electron_1.ipcRenderer.removeListener("embedded-browser:gone", listener);
|
|
57
57
|
},
|
|
58
58
|
});
|
|
59
|
+
// THE DSH VIEW (the shell's second embedded view). The harness's own UI runs on THIS
|
|
60
|
+
// machine's loopback, so the panel never learns its port: `open()` asks the MAIN process to
|
|
61
|
+
// navigate the view to its configured base, and the door that decides what that view may load
|
|
62
|
+
// (url-policy.isDshUrl) has exactly one origin to check. Same placeholder-bounds handshake as
|
|
63
|
+
// the browser view above, because it is the same problem: a native view overlays an empty slot
|
|
64
|
+
// the SPA positions.
|
|
65
|
+
electron_1.contextBridge.exposeInMainWorld("summriseDsh", {
|
|
66
|
+
open: () => electron_1.ipcRenderer.invoke("embedded-dsh:open"),
|
|
67
|
+
place: (bounds) => electron_1.ipcRenderer.invoke("embedded-dsh:place", bounds),
|
|
68
|
+
state: () => electron_1.ipcRenderer.invoke("embedded-dsh:state"),
|
|
69
|
+
reload: () => electron_1.ipcRenderer.invoke("embedded-dsh:reload"),
|
|
70
|
+
// Recovery after a renderer crash: the main process force-re-creates the view.
|
|
71
|
+
recover: () => electron_1.ipcRenderer.invoke("embedded-dsh:recover"),
|
|
72
|
+
// The view's renderer crashed (reason + exitCode) — without this the pane would show
|
|
73
|
+
// "starting…" forever over a view that will never paint. Returns an unsubscribe fn.
|
|
74
|
+
onGone: (handler) => {
|
|
75
|
+
const listener = (_e, d) => {
|
|
76
|
+
try {
|
|
77
|
+
handler(d);
|
|
78
|
+
}
|
|
79
|
+
catch { /* SPA-side */ }
|
|
80
|
+
};
|
|
81
|
+
electron_1.ipcRenderer.on("embedded-dsh:gone", listener);
|
|
82
|
+
return () => electron_1.ipcRenderer.removeListener("embedded-dsh:gone", listener);
|
|
83
|
+
},
|
|
84
|
+
});
|
|
59
85
|
// Desktop-app settings + menu bridge (Electron-specific — hidden when running
|
|
60
86
|
// in a plain browser; the SPA detects the bridge and shows the card only when
|
|
61
87
|
// present).
|
|
@@ -21,6 +21,10 @@ exports.isDesktopSpaUrl = isDesktopSpaUrl;
|
|
|
21
21
|
exports.isPrivateHost = isPrivateHost;
|
|
22
22
|
exports.certBypassAllowed = certBypassAllowed;
|
|
23
23
|
exports.sanitizeBrowserUrl = sanitizeBrowserUrl;
|
|
24
|
+
exports.setDshPort = setDshPort;
|
|
25
|
+
exports.getDshPort = getDshPort;
|
|
26
|
+
exports.dshBase = dshBase;
|
|
27
|
+
exports.isDshUrl = isDshUrl;
|
|
24
28
|
exports.BASE = "http://127.0.0.1:18080";
|
|
25
29
|
exports.BASE_ORIGIN = new URL(exports.BASE).origin;
|
|
26
30
|
// Configurable agent port (custom-port installs): the shell follows the
|
|
@@ -203,3 +207,32 @@ function sanitizeBrowserUrl(url) {
|
|
|
203
207
|
catch { /* fall through */ }
|
|
204
208
|
return "about:blank";
|
|
205
209
|
}
|
|
210
|
+
// THE DSH VIEW'S DOOR. The shell's SECOND embedded view shows the harness's own UI, which
|
|
211
|
+
// runs on THIS machine's loopback — so this door is one origin and nothing else, and it is a
|
|
212
|
+
// SEPARATE predicate from sanitizeBrowserUrl on purpose: the browser view's door is the open
|
|
213
|
+
// internet (an AI drives it), this one is a single port, and a door that is wide for one view
|
|
214
|
+
// must not quietly become wide for the other. The DSH view has no address bar and nothing
|
|
215
|
+
// drives it but the operator, so there is nothing here to widen it for.
|
|
216
|
+
//
|
|
217
|
+
// The port is the DSH's own (default 18081 — main.ts resolves SUMMRISE_DSH_PORT first), and
|
|
218
|
+
// it is deliberately NOT the agent's port: the agent's origin is where the panel lives, and a
|
|
219
|
+
// view that could load the panel could also load /api/* with the panel's own authority.
|
|
220
|
+
let dshPort = null;
|
|
221
|
+
function setDshPort(port) {
|
|
222
|
+
if (Number.isInteger(port) && port > 0 && port < 65536)
|
|
223
|
+
dshPort = port;
|
|
224
|
+
}
|
|
225
|
+
function getDshPort() {
|
|
226
|
+
return dshPort ?? 18081;
|
|
227
|
+
}
|
|
228
|
+
function dshBase() {
|
|
229
|
+
return `http://127.0.0.1:${getDshPort()}`;
|
|
230
|
+
}
|
|
231
|
+
function isDshUrl(url) {
|
|
232
|
+
try {
|
|
233
|
+
return new URL(url).origin === new URL(dshBase()).origin;
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|