@wrongstack/webui 0.104.0 → 0.107.2

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.
@@ -106,7 +106,8 @@ declare function browserOpenCommand(url: string, platform?: NodeJS.Platform): {
106
106
  command: string;
107
107
  args: string[];
108
108
  };
109
- /** Spawn the OS browser-opener for `url`. Never throws. */
109
+ /** Spawn the OS browser-opener for `url` and register it as a protected
110
+ * process so it survives kill/killAll. Never throws. */
110
111
  declare function openBrowser(url: string, platform?: NodeJS.Platform): void;
111
112
 
112
113
  /**
@@ -1614,6 +1614,25 @@ function openBrowser(url, platform = process.platform) {
1614
1614
  child.on("error", () => {
1615
1615
  });
1616
1616
  child.unref();
1617
+ if (child.pid) {
1618
+ try {
1619
+ import("@wrongstack/tools").then(({ getProcessRegistry }) => {
1620
+ getProcessRegistry().register({
1621
+ pid: child.pid,
1622
+ name: "browser",
1623
+ command: `${command} ${args.join(" ")}`,
1624
+ startedAt: Date.now(),
1625
+ child,
1626
+ protected: true
1627
+ });
1628
+ child.on("exit", () => {
1629
+ getProcessRegistry().unregister(child.pid);
1630
+ });
1631
+ }).catch(() => {
1632
+ });
1633
+ } catch {
1634
+ }
1635
+ }
1617
1636
  } catch {
1618
1637
  }
1619
1638
  }
@@ -3151,6 +3170,111 @@ async function startWebUI(opts = {}) {
3151
3170
  });
3152
3171
  break;
3153
3172
  }
3173
+ case "process.list": {
3174
+ try {
3175
+ const { getProcessRegistry } = await import("@wrongstack/tools");
3176
+ const procs = getProcessRegistry().list();
3177
+ send(ws, {
3178
+ type: "process.list",
3179
+ payload: {
3180
+ processes: procs.map((p) => ({
3181
+ pid: p.pid,
3182
+ command: p.command,
3183
+ tool: p.name,
3184
+ startedAt: p.startedAt,
3185
+ status: p.killed ? "killed" : "running",
3186
+ protected: p.protected
3187
+ }))
3188
+ }
3189
+ });
3190
+ } catch {
3191
+ send(ws, { type: "process.list", payload: { processes: [] } });
3192
+ }
3193
+ break;
3194
+ }
3195
+ case "process.kill": {
3196
+ const { pid } = msg.payload;
3197
+ try {
3198
+ const { getProcessRegistry } = await import("@wrongstack/tools");
3199
+ const proc = getProcessRegistry().get(pid);
3200
+ if (proc?.protected) {
3201
+ sendResult(ws, false, `Cannot kill protected process (PID ${pid})`);
3202
+ break;
3203
+ }
3204
+ getProcessRegistry().kill(pid);
3205
+ sendResult(ws, true, `Killed PID ${pid}`);
3206
+ } catch (err) {
3207
+ sendResult(ws, false, errMessage(err));
3208
+ }
3209
+ break;
3210
+ }
3211
+ case "process.killAll": {
3212
+ try {
3213
+ const { getProcessRegistry } = await import("@wrongstack/tools");
3214
+ getProcessRegistry().killAll();
3215
+ sendResult(ws, true, "All processes killed");
3216
+ } catch (err) {
3217
+ sendResult(ws, false, errMessage(err));
3218
+ }
3219
+ break;
3220
+ }
3221
+ case "goal.get": {
3222
+ try {
3223
+ const goalPath = path4.join(projectRoot, ".wrongstack", "goal.json");
3224
+ const raw = await fs4.readFile(goalPath, "utf8");
3225
+ const goal = JSON.parse(raw);
3226
+ broadcast(clients, { type: "goal.updated", payload: goal });
3227
+ } catch {
3228
+ broadcast(clients, { type: "goal.updated", payload: null });
3229
+ }
3230
+ break;
3231
+ }
3232
+ case "autonomy.switch": {
3233
+ const { mode } = msg.payload;
3234
+ context.meta["autonomy"] = mode;
3235
+ sendResult(ws, true, `Autonomy mode set to "${mode}"`);
3236
+ break;
3237
+ }
3238
+ case "session.checkpoints": {
3239
+ try {
3240
+ const { DefaultSessionRewinder } = await import("@wrongstack/core");
3241
+ const rewinder = new DefaultSessionRewinder(
3242
+ path4.join(projectRoot, ".wrongstack", "sessions"),
3243
+ projectRoot
3244
+ );
3245
+ const checkpoints = await rewinder.listCheckpoints(session.id);
3246
+ send(ws, {
3247
+ type: "session.checkpoints",
3248
+ payload: { checkpoints }
3249
+ });
3250
+ } catch (err) {
3251
+ send(ws, {
3252
+ type: "session.checkpoints",
3253
+ payload: { checkpoints: [] }
3254
+ });
3255
+ }
3256
+ break;
3257
+ }
3258
+ case "session.rewind": {
3259
+ const { checkpointIndex } = msg.payload;
3260
+ try {
3261
+ const { DefaultSessionRewinder } = await import("@wrongstack/core");
3262
+ const rewinder = new DefaultSessionRewinder(
3263
+ path4.join(projectRoot, ".wrongstack", "sessions"),
3264
+ projectRoot
3265
+ );
3266
+ await rewinder.rewindToCheckpoint(session.id, checkpointIndex);
3267
+ await context.session.truncateToCheckpoint(checkpointIndex);
3268
+ sendResult(ws, true, `Rewound to checkpoint ${checkpointIndex}`);
3269
+ broadcast(clients, {
3270
+ type: "session.start",
3271
+ payload: { ...await sessionStartPayload(), reset: true }
3272
+ });
3273
+ } catch (err) {
3274
+ sendResult(ws, false, errMessage(err));
3275
+ }
3276
+ break;
3277
+ }
3154
3278
  default:
3155
3279
  if (msg.type.startsWith("autophase.")) {
3156
3280
  await autoPhaseHandler.handleMessage(