summrise-agent 1.2.463 → 1.2.464

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 CHANGED
@@ -1449,6 +1449,28 @@ function svc(action) {
1449
1449
  // silent either way. `autostart` already checks; this is the same pattern.
1450
1450
  return sh(`schtasks /${action} /TN ${TASK}`, { stdio: "inherit" });
1451
1451
  }
1452
+ /**
1453
+ * The scheduled task's State (`Running`, `Ready`, `Disabled`, …) or **null when it could not be read**.
1454
+ *
1455
+ * THREE STATES, NOT ONE. `autostart` states the rule and names the shape — "a failed READ reported as
1456
+ * evidence of ABSENCE" — which it calls the THIRD instance, after `statusReport` and `rollback status`.
1457
+ * Here `null` means "I could not ask", and callers report that as itself instead of as a verdict.
1458
+ *
1459
+ * `LOCALE` is why this asks `Get-ScheduledTask` rather than parsing `schtasks /Query`: the latter's headers
1460
+ * are localized, which is the reason `autostart` uses this call too.
1461
+ */
1462
+ function taskState(name) {
1463
+ const r = (0, child_process_1.spawnSync)("powershell", [
1464
+ "-NoProfile",
1465
+ "-Command",
1466
+ `(Get-ScheduledTask -TaskName '${name}' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty State)`,
1467
+ ], { encoding: "utf8" });
1468
+ const err = r && r.error;
1469
+ if (!r || err || r.status !== 0)
1470
+ return null; // spawn failed, or the read itself failed
1471
+ const s = String(r.stdout || "").trim();
1472
+ return s === "" ? null : s; // empty = the task is not there, which is also "no answer to Running?"
1473
+ }
1452
1474
  // Shared tunnel bootstrap: login (token or interactive) → create tunnel →
1453
1475
  // DNS route → write tunnel.yml. Used by `summrise setup --tunnel` and
1454
1476
  // `summrise tunnel install`.
@@ -1889,12 +1911,25 @@ const commands = {
1889
1911
  try {
1890
1912
  const reg = path.join(SCRIPTS_DIR, "register-desktop-task.ps1");
1891
1913
  fs.writeFileSync(reg, desktopTaskPs(DIR).join("\r\n") + "\r\n");
1892
- sh(
1893
- // DOUBLE quotes — a cmd-layer argument. The single-quoted version this shipped with
1894
- // reached PowerShell with the quotes included and died on the device with "unsupported
1895
- // path format" for a path that was perfectly valid.
1896
- `powershell -NoProfile -ExecutionPolicy Bypass -File "${reg}"`);
1897
- console.log("setup: SummriseDesktop registered (logon + a 5-minute watchdog) and started");
1914
+ // THE STATUS WAS DISCARDED AND THE SUCCESS LINE WAS UNCONDITIONAL, which is the defect the AGENT
1915
+ // task's check ten lines below names in its own comment: "audit #7: used to claim success
1916
+ // regardless". Worse, the `catch` below could not fire for this — `sh()` RETURNS, it does not
1917
+ // throw — so the only thing it ever caught was `writeFileSync`.
1918
+ //
1919
+ // ONE CALL, and its status is READ. DOUBLE quotes in the command: a cmd-layer argument, because the
1920
+ // single-quoted version this shipped with reached PowerShell with the quotes included and died on
1921
+ // the device with "unsupported path format" for a path that was perfectly valid.
1922
+ //
1923
+ // A WARNING, NOT FATAL, unlike the agent task: headless installs have no SummriseDesktop, and the
1924
+ // registration script itself exits quietly when electron is already alive.
1925
+ const reg302 = sh(`powershell -NoProfile -ExecutionPolicy Bypass -File "${reg}"`, { stdio: "pipe" });
1926
+ if (reg302 && reg302.status === 0) {
1927
+ console.log("setup: SummriseDesktop registered (logon + a 5-minute watchdog) and started");
1928
+ }
1929
+ else {
1930
+ console.log(`setup: WARNING -- registering SummriseDesktop failed (status ${reg302 ? reg302.status : "spawn error"}); ` +
1931
+ `run: powershell -File "${SCRIPTS_DIR}\\register-desktop-task.ps1"`);
1932
+ }
1898
1933
  }
1899
1934
  catch {
1900
1935
  console.log(`setup: WARNING -- could not register SummriseDesktop; run: powershell -File "${SCRIPTS_DIR}\\register-desktop-task.ps1"`);
@@ -2156,6 +2191,17 @@ const commands = {
2156
2191
  process.exit(1);
2157
2192
  },
2158
2193
  status() {
2194
+ // THE EXIT CODE IS 0 EVEN WHEN THE REPORT SAYS "UNKNOWN", AND THAT IS THE CONVENTION.
2195
+ //
2196
+ // `status` is asked for a REPORT; it produces one, and the verdict lives in the text. `tunnel`
2197
+ // exits 1 on the same unreadable process list (`:3655-3662`) because the thing IT was asked for —
2198
+ // a running tunnel — did not happen. The two are not inconsistent; they answer different
2199
+ // questions, and the difference is what the caller asked for rather than how bad the news is.
2200
+ //
2201
+ // A script that needs a VERDICT must not read this exit code. `monitor list --json` states its own
2202
+ // contract at `:2424-2426`: "A device that could not be reached is a NON-ZERO EXIT with the reason
2203
+ // on stderr, never a JSON body pretending everything is fine."
2204
+ //
2159
2205
  // NOT via shell: `shell: true` concatenates argv into one cmd.exe string,
2160
2206
  // so the unquoted filter "IMAGENAME eq …" was split at its spaces, tasklist
2161
2207
  // rejected it, and this ALWAYS printed STOPPED even with the agent running.
@@ -2235,8 +2281,27 @@ const commands = {
2235
2281
  markDeliberateStop();
2236
2282
  const r = svc("End");
2237
2283
  if (r && r.status !== 0) {
2238
- console.error(`summrise stop: schtasks /End failed (status ${r.status}) -- the agent may still be running`);
2239
- process.exit(1);
2284
+ // A NON-ZERO `/End` IS NOT EVIDENCE THE AGENT IS STILL RUNNING, and the mirror of this mistake is
2285
+ // already documented twice in this file. `restart` says it about the identical condition: "a task
2286
+ // that was not running has nothing to end, so a non-zero /End is the ordinary case". `svc`'s own
2287
+ // comment records the ORIGINAL bug, which was the opposite — "`stop` printed 'stopped' and exited 0
2288
+ // for a missing task or an access-denied". So the exit code answers neither question.
2289
+ //
2290
+ // ASK INSTEAD. `autostart` reads `Get-ScheduledTask ... -ExpandProperty State` and its comment names
2291
+ // this exact shape — "a failed READ reported as evidence of ABSENCE" — which it calls the THIRD
2292
+ // instance. This is the fourth, from the other side: an ordinary read taken as evidence of PRESENCE,
2293
+ // with "the agent may still be running" printed for a task that had already stopped.
2294
+ const st = taskState(TASK);
2295
+ if (st === null) {
2296
+ // Could not read it — say that, rather than guessing either way (the three-state rule).
2297
+ console.error(`summrise stop: schtasks /End failed (status ${r.status}) and the task's state could not be read`);
2298
+ process.exit(1);
2299
+ }
2300
+ if (st === "Running") {
2301
+ console.error(`summrise stop: schtasks /End failed (status ${r.status}) and the task is still Running`);
2302
+ process.exit(1);
2303
+ }
2304
+ console.error(`summrise stop: schtasks /End returned ${r.status}, but the task is not Running -- nothing to stop`);
2240
2305
  }
2241
2306
  console.log("stopped -- revives via 'summrise start' or the 5-min watchdog ('summrise autostart off' opts out of autostart)");
2242
2307
  },
@@ -3035,8 +3100,17 @@ const commands = {
3035
3100
  if (regLeft.status === 0)
3036
3101
  survivors.push("registry key HKLM\\SOFTWARE\\Summrise\\Agent");
3037
3102
  if (survivors.length) {
3038
- console.log("uninstall: WARNING -- still present after removal:", survivors.join(", "));
3039
- console.log("uninstall: a locked file or a permission problem; re-run after stopping the agent.");
3103
+ // ONE FAILURE CLASS, ONE TREATMENT. The data-dir twin forty lines below exits 1 for exactly this
3104
+ // ("FAILED to purge the data dir -- … is still present"), and this branch warned and exited 0 —
3105
+ // while the comment directly above states the rule it was breaking: `sh()` discards its result
3106
+ // "at every one of its call sites", so a locked file, an AV hold or a denied HKLM write "produced
3107
+ // 'removed' with the thing still there, AND EXIT 0".
3108
+ //
3109
+ // The program dir and the registry key are what `uninstall` was asked to remove. A warning that
3110
+ // exits 0 is the same false verdict the data-dir branch already refuses.
3111
+ console.error("uninstall: FAILED -- still present after removal:", survivors.join(", "));
3112
+ console.error("uninstall: a locked file or a permission problem; re-run after stopping the agent.");
3113
+ process.exitCode = 1;
3040
3114
  }
3041
3115
  else {
3042
3116
  console.log("uninstall: program dir + registry removed");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "summrise-agent",
3
- "version": "1.2.463",
3
+ "version": "1.2.464",
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": {
Binary file