@rubytech/taskmaster 1.0.14 → 1.0.16
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/dist/auto-reply/reply/agent-runner-execution.js +6 -2
- package/dist/build-info.json +3 -3
- package/dist/control-ui/assets/{index-Cdd801b1.js → index-CII8VIT3.js} +212 -186
- package/dist/control-ui/assets/index-CII8VIT3.js.map +1 -0
- package/dist/control-ui/assets/{index-dMMqL7A5.css → index-CJPjbUly.css} +1 -1
- package/dist/control-ui/index.html +2 -2
- package/dist/gateway/server-methods/update.js +63 -2
- package/dist/gateway/server-runtime-config.js +1 -1
- package/dist/gateway/server-startup.js +8 -3
- package/dist/gateway/test-helpers.server.js +1 -1
- package/dist/macos/gateway-daemon.js +1 -4
- package/package.json +1 -1
- package/dist/control-ui/assets/index-Cdd801b1.js.map +0 -1
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
import { loadConfig } from "../../config/config.js";
|
|
2
2
|
import { resolveTaskmasterPackageRoot } from "../../infra/taskmaster-root.js";
|
|
3
3
|
import { scheduleGatewaySigusr1Restart } from "../../infra/restart.js";
|
|
4
|
-
import { formatDoctorNonInteractiveHint, writeRestartSentinel, } from "../../infra/restart-sentinel.js";
|
|
4
|
+
import { formatDoctorNonInteractiveHint, readRestartSentinel, writeRestartSentinel, } from "../../infra/restart-sentinel.js";
|
|
5
5
|
import { checkUpdateStatus, compareSemverStrings } from "../../infra/update-check.js";
|
|
6
6
|
import { normalizeUpdateChannel, resolveEffectiveUpdateChannel, } from "../../infra/update-channels.js";
|
|
7
7
|
import { runGatewayUpdate } from "../../infra/update-runner.js";
|
|
8
8
|
import { VERSION } from "../../version.js";
|
|
9
9
|
import { ErrorCodes, errorShape, formatValidationErrors, validateUpdateRunParams, } from "../protocol/index.js";
|
|
10
|
+
let lastUpdateResult = null;
|
|
11
|
+
function cacheFromSentinel(status, ts, stats) {
|
|
12
|
+
const failedStep = stats?.steps?.find((s) => s.log?.exitCode != null && s.log.exitCode !== 0);
|
|
13
|
+
lastUpdateResult = {
|
|
14
|
+
status,
|
|
15
|
+
ts,
|
|
16
|
+
mode: stats?.mode ?? null,
|
|
17
|
+
before: stats?.before ?? null,
|
|
18
|
+
after: stats?.after ?? null,
|
|
19
|
+
reason: stats?.reason ?? null,
|
|
20
|
+
durationMs: stats?.durationMs ?? null,
|
|
21
|
+
failedStep: failedStep
|
|
22
|
+
? { name: failedStep.name, exitCode: failedStep.log?.exitCode ?? null }
|
|
23
|
+
: null,
|
|
24
|
+
currentVersion: VERSION,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Read the restart sentinel into memory before it gets consumed by
|
|
29
|
+
* scheduleRestartSentinelWake. Must be called early in gateway startup.
|
|
30
|
+
*/
|
|
31
|
+
export async function cacheLastUpdateSentinel() {
|
|
32
|
+
try {
|
|
33
|
+
const sentinel = await readRestartSentinel();
|
|
34
|
+
if (sentinel?.payload.kind === "update") {
|
|
35
|
+
cacheFromSentinel(sentinel.payload.status, sentinel.payload.ts, sentinel.payload.stats);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Non-critical — worst case we don't show a result banner
|
|
40
|
+
}
|
|
41
|
+
}
|
|
10
42
|
export const updateHandlers = {
|
|
11
43
|
"gateway.restart": async ({ params, respond }) => {
|
|
12
44
|
const reason = typeof params.reason === "string"
|
|
@@ -70,7 +102,10 @@ export const updateHandlers = {
|
|
|
70
102
|
}, undefined);
|
|
71
103
|
}
|
|
72
104
|
},
|
|
73
|
-
"update.
|
|
105
|
+
"update.lastResult": async ({ respond }) => {
|
|
106
|
+
respond(true, { ok: true, result: lastUpdateResult }, undefined);
|
|
107
|
+
},
|
|
108
|
+
"update.run": async ({ params, respond, context }) => {
|
|
74
109
|
if (!validateUpdateRunParams(params)) {
|
|
75
110
|
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid update.run params: ${formatValidationErrors(validateUpdateRunParams.errors)}`));
|
|
76
111
|
return;
|
|
@@ -89,6 +124,26 @@ export const updateHandlers = {
|
|
|
89
124
|
const timeoutMs = typeof timeoutMsRaw === "number" && Number.isFinite(timeoutMsRaw)
|
|
90
125
|
? Math.max(1000, Math.floor(timeoutMsRaw))
|
|
91
126
|
: undefined;
|
|
127
|
+
const progress = {
|
|
128
|
+
onStepStart: (step) => {
|
|
129
|
+
context.broadcast("update.progress", {
|
|
130
|
+
phase: "step-start",
|
|
131
|
+
name: step.name,
|
|
132
|
+
index: step.index,
|
|
133
|
+
total: step.total,
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
onStepComplete: (step) => {
|
|
137
|
+
context.broadcast("update.progress", {
|
|
138
|
+
phase: "step-done",
|
|
139
|
+
name: step.name,
|
|
140
|
+
index: step.index,
|
|
141
|
+
total: step.total,
|
|
142
|
+
durationMs: step.durationMs,
|
|
143
|
+
ok: step.exitCode === 0 || step.exitCode === null,
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
};
|
|
92
147
|
let result;
|
|
93
148
|
try {
|
|
94
149
|
const root = (await resolveTaskmasterPackageRoot({
|
|
@@ -100,6 +155,7 @@ export const updateHandlers = {
|
|
|
100
155
|
timeoutMs,
|
|
101
156
|
cwd: root,
|
|
102
157
|
argv1: process.argv[1],
|
|
158
|
+
progress,
|
|
103
159
|
});
|
|
104
160
|
}
|
|
105
161
|
catch (err) {
|
|
@@ -145,6 +201,11 @@ export const updateHandlers = {
|
|
|
145
201
|
catch {
|
|
146
202
|
sentinelPath = null;
|
|
147
203
|
}
|
|
204
|
+
context.broadcast("update.progress", {
|
|
205
|
+
phase: "complete",
|
|
206
|
+
status: result.status,
|
|
207
|
+
reason: result.reason ?? null,
|
|
208
|
+
});
|
|
148
209
|
const restart = scheduleGatewaySigusr1Restart({
|
|
149
210
|
delayMs: restartDelayMs,
|
|
150
211
|
reason: "update.run",
|
|
@@ -3,7 +3,7 @@ import { normalizeControlUiBasePath } from "./control-ui-shared.js";
|
|
|
3
3
|
import { resolveHooksConfig } from "./hooks.js";
|
|
4
4
|
import { isLoopbackHost, resolveGatewayBindHost } from "./net.js";
|
|
5
5
|
export async function resolveGatewayRuntimeConfig(params) {
|
|
6
|
-
const bindMode = params.bind ?? params.cfg.gateway?.bind ?? "
|
|
6
|
+
const bindMode = params.bind ?? params.cfg.gateway?.bind ?? "lan";
|
|
7
7
|
const customBindHost = params.cfg.gateway?.customBindHost;
|
|
8
8
|
const bindHost = params.host ?? (await resolveGatewayBindHost(bindMode, customBindHost));
|
|
9
9
|
const controlUiEnabled = params.controlUiEnabled ?? params.cfg.gateway?.controlUi?.enabled ?? true;
|
|
@@ -8,6 +8,7 @@ import { loadInternalHooks } from "../hooks/loader.js";
|
|
|
8
8
|
import { startPluginServices } from "../plugins/services.js";
|
|
9
9
|
import { startBrowserControlServerIfEnabled } from "./server-browser.js";
|
|
10
10
|
import { scheduleRestartSentinelWake, shouldWakeFromRestartSentinel, } from "./server-restart-sentinel.js";
|
|
11
|
+
import { cacheLastUpdateSentinel } from "./server-methods/update.js";
|
|
11
12
|
export async function startGatewaySidecars(params) {
|
|
12
13
|
// Start Taskmaster browser control server (unless disabled via config).
|
|
13
14
|
let browserControl = null;
|
|
@@ -111,9 +112,13 @@ export async function startGatewaySidecars(params) {
|
|
|
111
112
|
params.log.warn(`plugin services failed to start: ${String(err)}`);
|
|
112
113
|
}
|
|
113
114
|
if (shouldWakeFromRestartSentinel()) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
// Cache the sentinel in memory BEFORE it gets consumed, so update.lastResult
|
|
116
|
+
// can serve it to the UI after reconnect.
|
|
117
|
+
void cacheLastUpdateSentinel().finally(() => {
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
void scheduleRestartSentinelWake({ deps: params.deps });
|
|
120
|
+
}, 750);
|
|
121
|
+
});
|
|
117
122
|
}
|
|
118
123
|
return { browserControl, pluginServices };
|
|
119
124
|
}
|
|
@@ -224,7 +224,7 @@ timeoutMs = 10_000) {
|
|
|
224
224
|
}
|
|
225
225
|
export async function startGatewayServer(port, opts) {
|
|
226
226
|
const mod = await serverModulePromise;
|
|
227
|
-
return await mod.startGatewayServer(port, opts);
|
|
227
|
+
return await mod.startGatewayServer(port, { bind: "loopback", ...opts });
|
|
228
228
|
}
|
|
229
229
|
export async function startServerWithClient(token, opts) {
|
|
230
230
|
let port = await getFreePort();
|
|
@@ -55,10 +55,7 @@ async function main() {
|
|
|
55
55
|
defaultRuntime.error(`Invalid --port (${portRaw})`);
|
|
56
56
|
process.exit(1);
|
|
57
57
|
}
|
|
58
|
-
const bindRaw = argValue(args, "--bind") ??
|
|
59
|
-
process.env.TASKMASTER_GATEWAY_BIND ??
|
|
60
|
-
cfg.gateway?.bind ??
|
|
61
|
-
"loopback";
|
|
58
|
+
const bindRaw = argValue(args, "--bind") ?? process.env.TASKMASTER_GATEWAY_BIND ?? cfg.gateway?.bind ?? "lan";
|
|
62
59
|
const bind = bindRaw === "loopback" ||
|
|
63
60
|
bindRaw === "lan" ||
|
|
64
61
|
bindRaw === "auto" ||
|