summrise-agent 1.2.452 → 1.2.454
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/bin/summrise.js +168 -16
- package/package.json +1 -1
- package/summrise-agent.exe +0 -0
package/bin/summrise.js
CHANGED
|
@@ -57,6 +57,13 @@ exports.autostartArgv = autostartArgv;
|
|
|
57
57
|
exports.playwrightProbePs = playwrightProbePs;
|
|
58
58
|
exports.busyIsFresh = busyIsFresh;
|
|
59
59
|
exports.latestCdnVersion = latestCdnVersion;
|
|
60
|
+
exports.latestNpmVersion = latestNpmVersion;
|
|
61
|
+
exports.newestOf = newestOf;
|
|
62
|
+
exports.latestReleaseVersion = latestReleaseVersion;
|
|
63
|
+
exports.cdnBase = cdnBase;
|
|
64
|
+
exports.componentUrl = componentUrl;
|
|
65
|
+
exports.resolveComponent = resolveComponent;
|
|
66
|
+
exports.ensureElectron = ensureElectron;
|
|
60
67
|
exports.statusReport = statusReport;
|
|
61
68
|
exports.isBehind = isBehind;
|
|
62
69
|
exports.behindBy = behindBy;
|
|
@@ -78,6 +85,7 @@ exports.rollbackVersionOk = rollbackVersionOk;
|
|
|
78
85
|
const child_process_1 = require("child_process");
|
|
79
86
|
const crypto = __importStar(require("crypto"));
|
|
80
87
|
const fs = __importStar(require("fs"));
|
|
88
|
+
const os = __importStar(require("os"));
|
|
81
89
|
const path = __importStar(require("path"));
|
|
82
90
|
const EXE_SRC = path.join(__dirname, "..", "summrise-agent.exe");
|
|
83
91
|
// C1 (2026-08-28): the registry is the single source of truth for the install
|
|
@@ -740,6 +748,135 @@ function latestCdnVersion() {
|
|
|
740
748
|
return null;
|
|
741
749
|
}
|
|
742
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* The registry's own answer to "what is latest", asked in the smallest way npm
|
|
753
|
+
* offers: `/-/package/<name>/dist-tags` is a few bytes, where the packument is a
|
|
754
|
+
* document. Same 3 s cap and the same rule as the CDN read — a failure is
|
|
755
|
+
* `null`, which the report renders as "could NOT be checked", never as
|
|
756
|
+
* agreement.
|
|
757
|
+
*/
|
|
758
|
+
function latestNpmVersion() {
|
|
759
|
+
const r = (0, child_process_1.spawnSync)("curl", [
|
|
760
|
+
"-s",
|
|
761
|
+
"-m",
|
|
762
|
+
"3",
|
|
763
|
+
"https://registry.npmjs.org/-/package/summrise-agent/dist-tags",
|
|
764
|
+
], { encoding: "utf8", timeout: 5000 });
|
|
765
|
+
if (r.status !== 0 || !r.stdout)
|
|
766
|
+
return null;
|
|
767
|
+
try {
|
|
768
|
+
const j = JSON.parse(r.stdout);
|
|
769
|
+
const v = j && typeof j.latest === "string" ? j.latest.trim() : "";
|
|
770
|
+
// A dist-tag can point at a prerelease; the device's update path only
|
|
771
|
+
// understands x.y.z, and a tag it cannot parse is not a version.
|
|
772
|
+
return /^\d+\.\d+\.\d+$/.test(v) ? v : null;
|
|
773
|
+
}
|
|
774
|
+
catch {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
/** The newer of two release versions; either may be unknown. */
|
|
779
|
+
function newestOf(a, b) {
|
|
780
|
+
if (!a)
|
|
781
|
+
return b;
|
|
782
|
+
if (!b)
|
|
783
|
+
return a;
|
|
784
|
+
const ta = versionTriple(a);
|
|
785
|
+
const tb = versionTriple(b);
|
|
786
|
+
if (!ta)
|
|
787
|
+
return b;
|
|
788
|
+
if (!tb)
|
|
789
|
+
return a;
|
|
790
|
+
for (let i = 0; i < 3; i++) {
|
|
791
|
+
if (ta[i] !== tb[i])
|
|
792
|
+
return ta[i] > tb[i] ? a : b;
|
|
793
|
+
}
|
|
794
|
+
return a;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* What "latest" means now that there are TWO channels: the newer of the CDN's
|
|
798
|
+
* `version.json` and the registry's dist-tag. `null` only when NEITHER
|
|
799
|
+
* answered — one silent channel must not be reported as agreement, which is the
|
|
800
|
+
* property the CDN-only version already had.
|
|
801
|
+
*/
|
|
802
|
+
function latestReleaseVersion() {
|
|
803
|
+
return newestOf(latestCdnVersion(), latestNpmVersion());
|
|
804
|
+
}
|
|
805
|
+
/** The release host this CLI already trusts for version checks. */
|
|
806
|
+
function cdnBase() {
|
|
807
|
+
return (process.env.SUMMRISE_CDN || "https://agent.saisi.online").replace(/\/+$/, "");
|
|
808
|
+
}
|
|
809
|
+
/** Where a boxed component lives on that host. Pure — the tests pin it. */
|
|
810
|
+
function componentUrl(name) {
|
|
811
|
+
return `${cdnBase()}/summrise-agent/${name}`;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* A boxed component's local path: the copy inside the package if it is there,
|
|
815
|
+
* otherwise the release host's route for it, downloaded to a temp file.
|
|
816
|
+
*
|
|
817
|
+
* WHY THIS EXISTS (2026-09-23). The npm package carries NONE of the big
|
|
818
|
+
* binaries on purpose (cloudflared 54 MB, playwright 31 MB, electron 234 MB), so
|
|
819
|
+
* "not in the package" used to mean "you do not get it, ever" — setup printed a
|
|
820
|
+
* line and moved on. The same shape for cloudflared left a freshly migrated
|
|
821
|
+
* device with no tunnel, and a device with no tunnel is INVISIBLE TO THE
|
|
822
|
+
* CONSOLE while looking perfectly healthy from inside: an hour of that is what
|
|
823
|
+
* this function is for. The release host serves all three, and for cloudflared
|
|
824
|
+
* it proxies a PINNED upstream asset, which the agent's own sha256 pin then
|
|
825
|
+
* checks again on the path it uses.
|
|
826
|
+
*
|
|
827
|
+
* `null` when neither source works: every component here is optional to the
|
|
828
|
+
* AGENT, and a failed fetch must not fail the install.
|
|
829
|
+
*/
|
|
830
|
+
function resolveComponent(name, pkgPath) {
|
|
831
|
+
if (fs.existsSync(pkgPath))
|
|
832
|
+
return pkgPath;
|
|
833
|
+
const dest = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "summrise-comp-")), name);
|
|
834
|
+
// -f: an HTTP error is a FAILURE, not a 404 page written to disk (the
|
|
835
|
+
// HTML-polluted download that round-54 exists to remember).
|
|
836
|
+
const r = (0, child_process_1.spawnSync)("curl", ["-fsSL", "-m", "300", "-o", dest, componentUrl(name)], { encoding: "utf8", timeout: 320000 });
|
|
837
|
+
if (r.status !== 0 || !fs.existsSync(dest) || fs.statSync(dest).size === 0) {
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
console.log(`setup: ${name} fetched from the release host (not in the package)`);
|
|
841
|
+
return dest;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Ensure the desktop shell's electron RUNTIME. The shell's sources are ~90 KB
|
|
845
|
+
* and ship in the package; the runtime is 234 MB and deliberately does not.
|
|
846
|
+
*
|
|
847
|
+
* WHY IT IS FETCHED AND NOT `npx electron`: the release host serves a PINNED
|
|
848
|
+
* upstream proxy of the official build (v33.4.11 when this was written), so a
|
|
849
|
+
* device behind the GFW needs no GitHub access and no ELECTRON_MIRROR — the two
|
|
850
|
+
* things that made the hand-install on 2026-09-23 need a mirror variable at all.
|
|
851
|
+
* `npx electron` would also mean rewriting the launcher, which calls
|
|
852
|
+
* `<shell>\node_modules\electron\dist\electron.exe` directly.
|
|
853
|
+
*
|
|
854
|
+
* The zip's ROOT is the dist contents (`LICENSES.chromium.html` is its first
|
|
855
|
+
* entry — measured through the route, not assumed), so it expands into `dist`.
|
|
856
|
+
* Idempotent, and non-fatal: an install without a window still installs an agent.
|
|
857
|
+
*/
|
|
858
|
+
function ensureElectron() {
|
|
859
|
+
const elDir = path.join(DESK_DIR, "node_modules", "electron");
|
|
860
|
+
const dist = path.join(elDir, "dist");
|
|
861
|
+
if (fs.existsSync(path.join(dist, "electron.exe")))
|
|
862
|
+
return dist;
|
|
863
|
+
const zip = resolveComponent("electron-win32-x64.zip", path.join(__dirname, "..", "electron-win32-x64.zip"));
|
|
864
|
+
if (!zip)
|
|
865
|
+
return null;
|
|
866
|
+
fs.mkdirSync(dist, { recursive: true });
|
|
867
|
+
sh(`powershell -NoProfile -Command "Expand-Archive -Force -Path '${(0, exports.psq)(zip)}' -DestinationPath '${(0, exports.psq)(dist)}'"`);
|
|
868
|
+
if (!fs.existsSync(path.join(dist, "electron.exe")))
|
|
869
|
+
return null;
|
|
870
|
+
try {
|
|
871
|
+
// The electron package's own lookup file; the launcher does not need it, but
|
|
872
|
+
// anything that resolves the package the npm way will.
|
|
873
|
+
fs.writeFileSync(path.join(elDir, "path.txt"), "electron.exe");
|
|
874
|
+
}
|
|
875
|
+
catch {
|
|
876
|
+
/* best-effort */
|
|
877
|
+
}
|
|
878
|
+
return dist;
|
|
879
|
+
}
|
|
743
880
|
function statusReport(f) {
|
|
744
881
|
const out = [];
|
|
745
882
|
out.push(f.agentRunning === null
|
|
@@ -1410,8 +1547,8 @@ const commands = {
|
|
|
1410
1547
|
// B2: stage the boxed playwright bundle (node_modules ONLY — node.exe is
|
|
1411
1548
|
// NOT bundled; the system node detected below runs it). Single small
|
|
1412
1549
|
// artifact in the npm package, Summrise version-locked.
|
|
1413
|
-
const PW_ZIP = path.join(__dirname, "..", "summrise-playwright.zip");
|
|
1414
|
-
if (
|
|
1550
|
+
const PW_ZIP = resolveComponent("summrise-playwright.zip", path.join(__dirname, "..", "summrise-playwright.zip"));
|
|
1551
|
+
if (PW_ZIP) {
|
|
1415
1552
|
const pwDir = PW_DIR;
|
|
1416
1553
|
fs.mkdirSync(pwDir, { recursive: true });
|
|
1417
1554
|
sh(`powershell -NoProfile -Command "Expand-Archive -Force -Path '${(0, exports.psq)(PW_ZIP)}' -DestinationPath '${(0, exports.psq)(COMPONENTS_DIR)}'"`);
|
|
@@ -1446,7 +1583,7 @@ const commands = {
|
|
|
1446
1583
|
}
|
|
1447
1584
|
}
|
|
1448
1585
|
else {
|
|
1449
|
-
console.
|
|
1586
|
+
console.error("setup: WARNING -- the playwright bundle could not be obtained (not in the package, and the release host did not serve it); browser tools stay disabled.");
|
|
1450
1587
|
}
|
|
1451
1588
|
// Node runtime: the device has node (npm works), but the agent runs as
|
|
1452
1589
|
// SYSTEM which may not see the user PATH — resolve the ABSOLUTE node path
|
|
@@ -1469,12 +1606,19 @@ const commands = {
|
|
|
1469
1606
|
}
|
|
1470
1607
|
// C2: stage the boxed cloudflared binary into components/ (optional — local
|
|
1471
1608
|
// mode works without it; only used when the user opts into public access).
|
|
1472
|
-
const CF_SRC = path.join(__dirname, "..", "cloudflared.exe");
|
|
1473
|
-
if (
|
|
1609
|
+
const CF_SRC = resolveComponent("cloudflared.exe", path.join(__dirname, "..", "cloudflared.exe"));
|
|
1610
|
+
if (CF_SRC) {
|
|
1474
1611
|
fs.mkdirSync(COMPONENTS_DIR, { recursive: true });
|
|
1475
1612
|
fs.copyFileSync(CF_SRC, path.join(COMPONENTS_DIR, "cloudflared.exe"));
|
|
1476
1613
|
console.log("setup: cloudflared staged (tunnel optional -- `summrise tunnel install` to enable)");
|
|
1477
1614
|
}
|
|
1615
|
+
else {
|
|
1616
|
+
// This branch used to be SILENT, and that silence is what the 2026-09-23
|
|
1617
|
+
// migration cost an hour of: a device with no cloudflared has no tunnel,
|
|
1618
|
+
// and a device with no tunnel cannot be reached from the console at all
|
|
1619
|
+
// while `summrise status` reports it healthy from inside.
|
|
1620
|
+
console.error("setup: WARNING -- cloudflared could NOT be staged (not in the package, and the release host did not serve it); this device will be unreachable from the console until the binary can be fetched.");
|
|
1621
|
+
}
|
|
1478
1622
|
// P2-4: record the boxed-component versions (never fail-closed).
|
|
1479
1623
|
writeBoxedVersions(DIR, path.join(__dirname, ".."));
|
|
1480
1624
|
// round-330: Tauri summrise-desktop staging removed (retired).
|
|
@@ -1487,6 +1631,13 @@ const commands = {
|
|
|
1487
1631
|
console.log(deskStaged > 0
|
|
1488
1632
|
? `setup: summrise-desktop-electron sources staged (${deskStaged} files)`
|
|
1489
1633
|
: "setup: summrise-desktop-electron sources NOT staged -- the package did not ship them; the desktop shell will not update");
|
|
1634
|
+
// …and the runtime those sources need. Sources without a runtime is a shell
|
|
1635
|
+
// that cannot start: no window, and (before this) nothing in the output said
|
|
1636
|
+
// why — the operator saw only an absent window.
|
|
1637
|
+
const elDist = ensureElectron();
|
|
1638
|
+
console.log(elDist
|
|
1639
|
+
? "setup: electron runtime ready for the desktop shell"
|
|
1640
|
+
: "setup: WARNING -- the electron runtime could not be obtained (not in the package, and the release host did not serve it); start-desktop.ps1 will not open a window until it can be fetched.");
|
|
1490
1641
|
// Layout v2: write the start-desktop.ps1 launcher into scripts\ (the
|
|
1491
1642
|
// SummriseDesktop onlogon task + desktop Summrise.lnk both call it). Was never
|
|
1492
1643
|
// written before — a real gap that left the shell unlaunchable.
|
|
@@ -1726,13 +1877,14 @@ const commands = {
|
|
|
1726
1877
|
catch {
|
|
1727
1878
|
/* best-effort */
|
|
1728
1879
|
}
|
|
1729
|
-
// What the
|
|
1730
|
-
// the question every round of this project's log answered by
|
|
1731
|
-
// HARD (3 s): `status` is the command an operator runs
|
|
1732
|
-
// already wrong, and a status that hangs on a network
|
|
1733
|
-
// that says it could not check.
|
|
1734
|
-
// renders as "could NOT be checked" —
|
|
1735
|
-
|
|
1880
|
+
// What the TWO channels advertise, so `status` can answer "is this device
|
|
1881
|
+
// current" — the question every round of this project's log answered by
|
|
1882
|
+
// hand. Bounded HARD (3 s each): `status` is the command an operator runs
|
|
1883
|
+
// when something is already wrong, and a status that hangs on a network
|
|
1884
|
+
// blip is worse than one that says it could not check. `null` only when
|
|
1885
|
+
// BOTH are silent, which the report renders as "could NOT be checked" —
|
|
1886
|
+
// never as agreement.
|
|
1887
|
+
const latestVersion = latestReleaseVersion();
|
|
1736
1888
|
for (const line of statusReport({
|
|
1737
1889
|
agentRunning: agentState === "unknown" ? null : agentState === "yes",
|
|
1738
1890
|
installDir: DIR,
|
|
@@ -1853,15 +2005,15 @@ const commands = {
|
|
|
1853
2005
|
// `agent_update` reads that file as its LOCAL version. An older CLI therefore stamps the install with the version it
|
|
1854
2006
|
// already has, the swap installs the same build, and nothing moves. Refuse before touching the device, and say the
|
|
1855
2007
|
// thing that works — the release flow has always been two steps.
|
|
1856
|
-
const
|
|
2008
|
+
const latest = latestReleaseVersion();
|
|
1857
2009
|
const selfVersion = String(require("../package.json").version || "");
|
|
1858
|
-
if (
|
|
1859
|
-
console.error(`update: this CLI is ${selfVersion} and the
|
|
2010
|
+
if (latest && selfVersion && isBehind(selfVersion, latest)) {
|
|
2011
|
+
console.error(`update: this CLI is ${selfVersion} and the release channel has ${latest}.` +
|
|
1860
2012
|
"\n Updating from here would stamp the device with " +
|
|
1861
2013
|
selfVersion +
|
|
1862
2014
|
" and change nothing, because the device reads <install>/.summrise-release (written by this package) as its version." +
|
|
1863
2015
|
"\n Install the new CLI first, then update again:" +
|
|
1864
|
-
|
|
2016
|
+
"\n npm i -g summrise-agent" +
|
|
1865
2017
|
"\n summrise update");
|
|
1866
2018
|
process.exit(1);
|
|
1867
2019
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "summrise-agent",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.454",
|
|
4
4
|
"description": "Summrise Agent — Windows device MCP server (terminal/SSH/serial) + panel. Self-hosted npm distribution.",
|
|
5
5
|
"//build": "唯一构建路径:在本目录执行 npm run build。它是自包含的:经 npm exec 按需拉取 typescript@5,无需预装任何 node_modules(干净检出可跑;旧脚本引用 ../summrise-desktop-electron/node_modules/.bin/tsc,干净检出必 ENOENT)。必须用 npm exec --package … -- tsc 的形式:npx 会吃掉传给 tsc 的 -p/--outDir 等参数(round-435:npx 写法从未真正跑通过)。先编 electron TS(--noCheck 纯 emit,与 release.yml 一致)同步两处 src/*.js,再编 src/summrise.ts 到 bin/summrise.js 并校验 round-298 标记(弱 oracle,只证某次构建发生,新鲜性由 publish-release.sh 的 tsc 重编 + cmp 门保证)。",
|
|
6
6
|
"bin": {
|
package/summrise-agent.exe
CHANGED
|
Binary file
|