@edgehero/pi-dispatch 5.0.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +4 -3
- package/src/cancel-cli.mjs +102 -14
- package/src/cancel-state.mjs +9 -3
- package/src/cli.mjs +8 -0
- package/src/connection.mjs +7 -0
- package/src/console-audit.mjs +1 -1
- package/src/console-bootstrap.mjs +211 -45
- package/src/console-devices.mjs +372 -0
- package/src/console-install.mjs +239 -0
- package/src/console-open.mjs +99 -0
- package/src/doctor-bundles.mjs +6 -2
- package/src/doctor-model-proposals.mjs +4 -2
- package/src/doctor.mjs +223 -30
- package/src/envelope.mjs +5 -3
- package/src/mcp-config.mjs +3 -1
- package/src/models-json.mjs +8 -1
- package/src/pause-windows.mjs +19 -3
- package/src/setup-host-entry.mjs +4 -1
- package/src/up.mjs +6 -4
package/src/pause-windows.mjs
CHANGED
|
@@ -83,8 +83,13 @@ export function pauseWindowsVersionRefusal(doc, { supported = PAUSE_WINDOWS_VERS
|
|
|
83
83
|
export function heldPauseWindows(text, path) {
|
|
84
84
|
if ((text ?? "").trim() === "") return { doc: null, windows: [] };
|
|
85
85
|
const { value, problem } = heldDocument(text, "windows");
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
// Whenever the text parsed, a problem with its shape included (`"windows": {}`), as the loader judges the duplicate first.
|
|
87
|
+
const doubled = value !== undefined && findDuplicateKey(text) !== null;
|
|
88
|
+
const refused = doubled ? "has a key written twice" : problem ?? null;
|
|
89
|
+
// A key written twice hands back no document (issue #846): the callers ask the document whether a newer release wrote
|
|
90
|
+
// it before they read `problem`, and `{"version":1,"version":2}` would send the operator to upgrade to a release that
|
|
91
|
+
// refuses the file too. Broken, never newer, as the loader reads it and as the triggers writer does.
|
|
92
|
+
if (refused) return { doc: doubled ? null : value ?? null, problem: `the pause-windows file ${path} ${refused}, so its windows cannot be kept` };
|
|
88
93
|
return { doc: value, windows: Array.isArray(value.windows) ? value.windows : [] };
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -158,7 +163,7 @@ function validateTz(tz, at, path) {
|
|
|
158
163
|
* (unknown fields dropped; `fromMin`/`toMin` precomputed). Throws `configError` (fail-loud) on any malformed
|
|
159
164
|
* entry. `path` is for messages only.
|
|
160
165
|
*
|
|
161
|
-
* The file's `version` is judged
|
|
166
|
+
* The file's `version` is judged right after the duplicate-key check (issue #846) and before the windows (issue #761): a newer file's windows may use a shape this
|
|
162
167
|
* build would call malformed, and the true message is "upgrade". A newer file throws a configError with
|
|
163
168
|
* `.newer === true` (the worker defers jobs rather than misread a pause); a broken `version`, or a window using a field
|
|
164
169
|
* or a value that needs a higher version than the file declares, throws the ordinary configError. `supported`, `table`
|
|
@@ -171,6 +176,17 @@ export function parsePauseWindows(text, path, { supported = PAUSE_WINDOWS_VERSIO
|
|
|
171
176
|
} catch (error) {
|
|
172
177
|
throw configError(`pause-windows file is not valid JSON: ${path} (${error.message})`);
|
|
173
178
|
}
|
|
179
|
+
// Issue #846: a key written twice is REFUSED, after the parse and before anything else, as the triggers loader refuses
|
|
180
|
+
// one (`triggers.mjs`, issue #313). `JSON.parse` keeps the LAST value, so `{"windows":[...],"windows":[]}` loaded no
|
|
181
|
+
// window while a person reading the file sees two, and a reload swapped a live list down to none with nothing said:
|
|
182
|
+
// quiet hours stopped applying, which costs money in exactly the hours someone believes are paused. Refused, the boot
|
|
183
|
+
// does not start and a reload keeps the last good windows and logs why (`reloadPauseWindows`). The writers have
|
|
184
|
+
// refused such a file since #841 (`heldPauseWindows`), so only a hand edit makes one. BEFORE the version, the triggers
|
|
185
|
+
// loader's order: a doubled `version` is broken, never newer, and a newer release refuses the duplicate as well.
|
|
186
|
+
const duplicate = findDuplicateKey(text);
|
|
187
|
+
if (duplicate) {
|
|
188
|
+
throw configError(`pause-windows file has a duplicate key ${JSON.stringify(duplicate.key)} at ${duplicate.at}: JSON keeps the LAST value, so the file a person reads and the file that applies are not the same: ${path}`);
|
|
189
|
+
}
|
|
174
190
|
const problem = pauseWindowsVersionRefusal(parsed, { supported });
|
|
175
191
|
if (problem) {
|
|
176
192
|
const error = configError(`${problem.message}: ${path}`);
|
package/src/setup-host-entry.mjs
CHANGED
|
@@ -4,7 +4,10 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
6
|
export function setupCachePath(path) {
|
|
7
|
-
|
|
7
|
+
// pnpm's, yarn's and bun's temporary stores are as disposable as npm's own. Matched by their whole shape, because a folder someone named
|
|
8
|
+
// `dlx` is an ordinary folder.
|
|
9
|
+
const text = String(path);
|
|
10
|
+
return /(?:^|[/\\])(?:_npx|_cacache|npm-cache|\.cache)(?:[/\\]|$)/.test(text) || /(?:^|[/\\])pnpm[/\\]dlx(?:[/\\]|$)/.test(text) || /(?:^|[/\\])xfs-[^/\\]+[/\\]dlx-\d+(?:[/\\]|$)/.test(text) || /(?:^|[/\\])bunx-\d+-[^/\\]+(?:[/\\]|$)/.test(text) || /(?:^|[/\\])\.yarn[/\\]berry[/\\]cache(?:[/\\]|$)/.test(text);
|
|
8
11
|
}
|
|
9
12
|
export function trustedSetupFile(entry, { uid = process.geteuid?.(), realpath = realpathSync, stat = statSync } = {}) {
|
|
10
13
|
try {
|
package/src/up.mjs
CHANGED
|
@@ -1155,7 +1155,9 @@ export async function runUp(argv = [], deps = {}) {
|
|
|
1155
1155
|
for (const [name, note] of summary) {
|
|
1156
1156
|
out(` ${name.padEnd(21)} ${note}\n`);
|
|
1157
1157
|
}
|
|
1158
|
-
|
|
1158
|
+
// `up --console` goes on to /setup, whose checklist is the next step, and these bare commands are not on a local install's PATH.
|
|
1159
|
+
const nextOut = deps.skipNextSteps ? () => {} : out;
|
|
1160
|
+
nextOut(`
|
|
1159
1161
|
Next:
|
|
1160
1162
|
edit ${envPath}
|
|
1161
1163
|
set ANTHROPIC_API_KEY (or your provider's key) — already logged into pi? leave it blank
|
|
@@ -1167,7 +1169,7 @@ Next:
|
|
|
1167
1169
|
// A worker run BY HAND reads only its shell, so on the podman venue it needs the list exported; the service reads
|
|
1168
1170
|
// `.env` itself. Printed only there, so every other deployment's closing text is unchanged.
|
|
1169
1171
|
if (venues.podmanUsed) {
|
|
1170
|
-
|
|
1172
|
+
nextOut(" (podman venue: a worker started by hand reads only its shell, so export the same PI_BACKENDS there first, or run it as a service with `pi-dispatch service install`, which reads .env)\n");
|
|
1171
1173
|
}
|
|
1172
1174
|
// Issue #708: the console as a service, offered only where it could start (an operator token exists): without one,
|
|
1173
1175
|
// `service install --console` refuses, and a "Next:" line that leads to a refusal is not a next step.
|
|
@@ -1175,10 +1177,10 @@ Next:
|
|
|
1175
1177
|
try {
|
|
1176
1178
|
consoleReady = consoleOperators(cwd) > 0 && !consoleUnitInstalled(cwd);
|
|
1177
1179
|
} catch {}
|
|
1178
|
-
if (consoleReady)
|
|
1180
|
+
if (consoleReady) nextOut(" pi-dispatch service install --console\n keep the operator console running as a service (open it with /dispatch console)\n");
|
|
1179
1181
|
// Issue #707: the openshell venues' own next step, said only where one is blessed.
|
|
1180
1182
|
if (openshell.used) {
|
|
1181
|
-
|
|
1183
|
+
nextOut(` pi-dispatch service install\n the worker as a ${platform === "darwin" ? "LaunchAgent (the gateway runs in this login session: `brew services start openshell`, the service of OpenShell's release formula, keeps it there)" : `user service that pulls in the gateway's own unit (${OPENSHELL_GATEWAY_UNIT})`}; then \`pi-dispatch doctor\` reads the gateway, its engine and the image back. A worker started by hand reads only its shell, so export the same PI_BACKENDS (and PI_OPENSHELL_ENGINE) there first\n`);
|
|
1182
1184
|
}
|
|
1183
1185
|
// Issue #464: a Valkey this pass refused (another account's, or one no one could name) is a failed `up` whatever doctor
|
|
1184
1186
|
// says: a worker started now would take that queue's jobs, and an exit 0 read by a script or the wizard says ready.
|