adhdev 0.7.39 → 0.7.41

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/cli/index.js CHANGED
@@ -176,7 +176,8 @@ var init_config = __esm({
176
176
  workspaces: [],
177
177
  defaultWorkspaceId: null,
178
178
  recentActivity: [],
179
- recentSessionReads: {},
179
+ sessionReads: {},
180
+ sessionReadMarkers: {},
180
181
  machineNickname: null,
181
182
  machineId: void 0,
182
183
  machineSecret: null,
@@ -389,18 +390,27 @@ function appendRecentActivity(config2, entry) {
389
390
  function getRecentActivity(config2, limit = 20) {
390
391
  return [...config2.recentActivity || []].sort((a, b2) => b2.lastUsedAt - a.lastUsedAt).slice(0, limit);
391
392
  }
392
- function getRecentSessionSeenAt(config2, recentKey) {
393
- return config2.recentSessionReads?.[recentKey] || 0;
393
+ function getSessionSeenAt(config2, sessionId) {
394
+ return config2.sessionReads?.[sessionId] || 0;
394
395
  }
395
- function markRecentSessionSeen(config2, recentKey, seenAt = Date.now()) {
396
- const prev = config2.recentSessionReads || {};
397
- const nextSeenAt = Math.max(prev[recentKey] || 0, seenAt);
396
+ function getSessionSeenMarker(config2, sessionId) {
397
+ return config2.sessionReadMarkers?.[sessionId] || "";
398
+ }
399
+ function markSessionSeen(config2, sessionId, seenAt = Date.now(), completionMarker) {
400
+ const prev = config2.sessionReads || {};
401
+ const nextSeenAt = Math.max(prev[sessionId] || 0, seenAt);
402
+ const prevMarkers = config2.sessionReadMarkers || {};
403
+ const nextMarker = typeof completionMarker === "string" ? completionMarker : "";
398
404
  return {
399
405
  ...config2,
400
- recentSessionReads: {
406
+ sessionReads: {
401
407
  ...prev,
402
- [recentKey]: nextSeenAt
403
- }
408
+ [sessionId]: nextSeenAt
409
+ },
410
+ sessionReadMarkers: nextMarker ? {
411
+ ...prevMarkers,
412
+ [sessionId]: nextMarker
413
+ } : prevMarkers
404
414
  };
405
415
  }
406
416
  var path2, MAX_ACTIVITY;
@@ -3591,6 +3601,8 @@ function buildCliSession(state) {
3591
3601
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
3592
3602
  runtimeWriteOwner: state.runtime?.writeOwner || null,
3593
3603
  runtimeAttachedClients: state.runtime?.attachedClients || [],
3604
+ launchMode: state.launchMode,
3605
+ mode: state.mode,
3594
3606
  resume: state.resume,
3595
3607
  activeChat,
3596
3608
  capabilities: PTY_SESSION_CAPABILITIES,
@@ -8838,337 +8850,6 @@ var init_command_log = __esm({
8838
8850
  }
8839
8851
  });
8840
8852
 
8841
- // ../../oss/packages/daemon-core/src/commands/router.ts
8842
- var fs7, CHAT_COMMANDS, DaemonCommandRouter;
8843
- var init_router = __esm({
8844
- "../../oss/packages/daemon-core/src/commands/router.ts"() {
8845
- "use strict";
8846
- init_manager();
8847
- init_setup();
8848
- init_launch();
8849
- init_config();
8850
- init_workspaces();
8851
- init_recent_activity();
8852
- init_ide_detector();
8853
- init_logger();
8854
- init_command_log();
8855
- init_logger();
8856
- fs7 = __toESM(require("fs"));
8857
- CHAT_COMMANDS = [
8858
- "send_chat",
8859
- "new_chat",
8860
- "switch_chat",
8861
- "set_mode",
8862
- "change_model"
8863
- ];
8864
- DaemonCommandRouter = class {
8865
- deps;
8866
- constructor(deps) {
8867
- this.deps = deps;
8868
- }
8869
- /**
8870
- * Unified command routing.
8871
- * Returns result for all commands:
8872
- * 1. Daemon-level commands (launch_ide, stop_ide, etc.)
8873
- * 2. CLI commands (launch_cli, stop_cli, agent_command)
8874
- * 3. DaemonCommandHandler delegation (CDP/agent-stream/file commands)
8875
- *
8876
- * @param cmd Command name
8877
- * @param args Command arguments
8878
- * @param source Log source ('ws' | 'p2p' | 'standalone' | etc.)
8879
- */
8880
- async execute(cmd, args, source = "unknown") {
8881
- const cmdStart = Date.now();
8882
- try {
8883
- const daemonResult = await this.executeDaemonCommand(cmd, args);
8884
- if (daemonResult) {
8885
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
8886
- return daemonResult;
8887
- }
8888
- const handlerResult = await this.deps.commandHandler.handle(cmd, args);
8889
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
8890
- if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
8891
- this.deps.onPostChatCommand();
8892
- }
8893
- return handlerResult;
8894
- } catch (e) {
8895
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
8896
- throw e;
8897
- }
8898
- }
8899
- // ─── Daemon-level command core ───────────────────
8900
- /**
8901
- * Daemon-level command execution (IDE start/stop/restart, CLI, detect, logs).
8902
- * Returns null if not handled at this level → caller delegates to CommandHandler.
8903
- */
8904
- async executeDaemonCommand(cmd, args) {
8905
- switch (cmd) {
8906
- // ─── CLI / ACP commands ───
8907
- case "launch_cli":
8908
- case "stop_cli":
8909
- case "agent_command": {
8910
- return this.deps.cliManager.handleCliCommand(cmd, args);
8911
- }
8912
- // ─── Logs ───
8913
- case "get_logs": {
8914
- const count = parseInt(args?.count) || parseInt(args?.lines) || 100;
8915
- const minLevel = args?.minLevel || "info";
8916
- const sinceTs = args?.since || 0;
8917
- try {
8918
- let logs = getRecentLogs(count, minLevel);
8919
- if (sinceTs > 0) {
8920
- logs = logs.filter((l) => l.ts > sinceTs);
8921
- }
8922
- if (logs.length > 0) {
8923
- return { success: true, logs, totalBuffered: logs.length };
8924
- }
8925
- if (fs7.existsSync(LOG_PATH)) {
8926
- const content = fs7.readFileSync(LOG_PATH, "utf-8");
8927
- const allLines = content.split("\n");
8928
- const recent = allLines.slice(-count).join("\n");
8929
- return { success: true, logs: recent, totalLines: allLines.length };
8930
- }
8931
- return { success: true, logs: [], totalBuffered: 0 };
8932
- } catch (e) {
8933
- return { success: false, error: e.message };
8934
- }
8935
- }
8936
- // ─── restart_session: IDE / CLI / ACP unified ───
8937
- case "restart_session": {
8938
- const targetType = args?.cliType || args?.agentType || args?.ideType;
8939
- if (!targetType) throw new Error("cliType or ideType required");
8940
- const isIde = this.deps.cdpManagers.has(targetType) || this.deps.providerLoader.getMeta(targetType)?.category === "ide";
8941
- if (isIde) {
8942
- await this.stopIde(targetType, true);
8943
- const launchResult = await this.executeDaemonCommand("launch_ide", { ideType: targetType, enableCdp: true, workspace: args?.workspace });
8944
- return { success: true, restarted: true, ideType: targetType, launch: launchResult };
8945
- }
8946
- return this.deps.cliManager.handleCliCommand(cmd, args);
8947
- }
8948
- // ─── IDE stop ───
8949
- case "stop_ide": {
8950
- const ideType = args?.ideType;
8951
- if (!ideType) throw new Error("ideType required");
8952
- const killProcess = args?.killProcess !== false;
8953
- await this.stopIde(ideType, killProcess);
8954
- return { success: true, ideType, stopped: true, processKilled: killProcess };
8955
- }
8956
- // ─── IDE restart ───
8957
- case "restart_ide": {
8958
- const ideType = args?.ideType;
8959
- if (!ideType) throw new Error("ideType required");
8960
- await this.stopIde(ideType, true);
8961
- const launchResult = await this.executeDaemonCommand("launch_ide", { ideType, enableCdp: true, workspace: args?.workspace });
8962
- return { success: true, ideType, restarted: true, launch: launchResult };
8963
- }
8964
- // ─── IDE launch + CDP connect ───
8965
- case "launch_ide": {
8966
- const ideKey = args?.ideId || args?.ideType;
8967
- const resolvedWorkspace = resolveIdeLaunchWorkspace(
8968
- {
8969
- workspace: args?.workspace,
8970
- workspaceId: args?.workspaceId,
8971
- useDefaultWorkspace: args?.useDefaultWorkspace
8972
- },
8973
- loadConfig()
8974
- );
8975
- const launchArgs = {
8976
- ideId: ideKey,
8977
- workspace: resolvedWorkspace,
8978
- newWindow: args?.newWindow
8979
- };
8980
- LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
8981
- const result = await launchWithCdp(launchArgs);
8982
- if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
8983
- const logFn = this.deps.getCdpLogFn ? this.deps.getCdpLogFn(result.ideId) : LOG.forComponent(`CDP:${result.ideId}`).asLogFn();
8984
- const provider = this.deps.providerLoader.getMeta(result.ideId);
8985
- const manager = new DaemonCdpManager(result.port, logFn, void 0, provider?.targetFilter);
8986
- const connected = await manager.connect();
8987
- if (connected) {
8988
- registerExtensionProviders(this.deps.providerLoader, manager, result.ideId);
8989
- this.deps.cdpManagers.set(result.ideId, manager);
8990
- LOG.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
8991
- LOG.info("CDP", `${this.deps.cdpManagers.size} IDE(s) connected`);
8992
- this.deps.onCdpManagerCreated?.(result.ideId, manager);
8993
- }
8994
- }
8995
- this.deps.onIdeConnected?.();
8996
- if (result.success && resolvedWorkspace) {
8997
- try {
8998
- const next = appendRecentActivity(loadConfig(), {
8999
- kind: "ide",
9000
- providerType: result.ideId || ideKey,
9001
- providerName: result.ideId || ideKey,
9002
- workspace: resolvedWorkspace,
9003
- title: result.ideId || ideKey
9004
- });
9005
- saveConfig(next);
9006
- } catch {
9007
- }
9008
- } else if (result.success && (result.ideId || ideKey)) {
9009
- try {
9010
- saveConfig(appendRecentActivity(loadConfig(), {
9011
- kind: "ide",
9012
- providerType: result.ideId || ideKey,
9013
- providerName: result.ideId || ideKey,
9014
- title: result.ideId || ideKey
9015
- }));
9016
- } catch {
9017
- }
9018
- }
9019
- return { success: result.success, ...result };
9020
- }
9021
- // ─── Detect IDEs ───
9022
- case "detect_ides": {
9023
- const results = await detectIDEs();
9024
- this.deps.detectedIdes.value = results;
9025
- return { success: true, detectedInfo: results };
9026
- }
9027
- // ─── Set User Name ───
9028
- case "set_user_name": {
9029
- const name = args?.userName;
9030
- if (!name || typeof name !== "string") throw new Error("userName required");
9031
- updateConfig({ userName: name });
9032
- return { success: true, userName: name };
9033
- }
9034
- case "mark_recent_seen": {
9035
- const kind = args?.kind;
9036
- const providerType = args?.providerType;
9037
- if (!kind || !providerType) {
9038
- return { success: false, error: "kind and providerType are required" };
9039
- }
9040
- const recentKey = args?.recentKey || buildRecentActivityKey({
9041
- kind,
9042
- providerType,
9043
- workspace: args?.workspace || null
9044
- });
9045
- const next = markRecentSessionSeen(
9046
- loadConfig(),
9047
- recentKey,
9048
- typeof args?.seenAt === "number" ? args.seenAt : Date.now()
9049
- );
9050
- saveConfig(next);
9051
- this.deps.onStatusChange?.();
9052
- return {
9053
- success: true,
9054
- recentKey,
9055
- seenAt: next.recentSessionReads?.[recentKey] || Date.now()
9056
- };
9057
- }
9058
- // ─── Daemon Self-Upgrade ───
9059
- case "daemon_upgrade": {
9060
- LOG.info("Upgrade", "Remote upgrade requested from dashboard");
9061
- try {
9062
- const { execSync: execSync7 } = await import("child_process");
9063
- const isStandalone = this.deps.packageName === "@adhdev/daemon-standalone" || process.argv[1]?.includes("daemon-standalone");
9064
- const pkgName = isStandalone ? "@adhdev/daemon-standalone" : "adhdev";
9065
- const latest = execSync7(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
9066
- LOG.info("Upgrade", `Latest ${pkgName}: v${latest}`);
9067
- execSync7(`npm install -g ${pkgName}@latest --force`, {
9068
- encoding: "utf-8",
9069
- timeout: 12e4,
9070
- stdio: ["pipe", "pipe", "pipe"]
9071
- });
9072
- LOG.info("Upgrade", `\u2705 Upgraded to v${latest}`);
9073
- setTimeout(() => {
9074
- LOG.info("Upgrade", "Restarting daemon with new version...");
9075
- try {
9076
- const path18 = require("path");
9077
- const fs16 = require("fs");
9078
- const pidFile = path18.join(process.env.HOME || process.env.USERPROFILE || "", ".adhdev", "daemon.pid");
9079
- if (fs16.existsSync(pidFile)) fs16.unlinkSync(pidFile);
9080
- } catch {
9081
- }
9082
- const { spawn: spawn4 } = require("child_process");
9083
- const child = spawn4(process.execPath, process.argv.slice(1), {
9084
- detached: true,
9085
- stdio: "ignore",
9086
- env: { ...process.env }
9087
- });
9088
- child.unref();
9089
- process.exit(0);
9090
- }, 3e3);
9091
- return { success: true, upgraded: true, version: latest };
9092
- } catch (e) {
9093
- LOG.error("Upgrade", `Failed: ${e.message}`);
9094
- return { success: false, error: e.message };
9095
- }
9096
- }
9097
- // ─── Machine Settings ───
9098
- case "set_machine_nickname": {
9099
- const nickname = args?.nickname;
9100
- updateConfig({ machineNickname: nickname || null });
9101
- return { success: true };
9102
- }
9103
- default:
9104
- break;
9105
- }
9106
- return null;
9107
- }
9108
- /**
9109
- * IDE stop: CDP disconnect + InstanceManager cleanup + optionally kill OS process
9110
- */
9111
- async stopIde(ideType, killProcess = false) {
9112
- const cdpKeysToRemove = [];
9113
- for (const key of this.deps.cdpManagers.keys()) {
9114
- if (key === ideType || key.startsWith(`${ideType}_`)) {
9115
- cdpKeysToRemove.push(key);
9116
- }
9117
- }
9118
- for (const key of cdpKeysToRemove) {
9119
- const cdp = this.deps.cdpManagers.get(key);
9120
- if (cdp) {
9121
- try {
9122
- cdp.disconnect();
9123
- } catch {
9124
- }
9125
- this.deps.cdpManagers.delete(key);
9126
- this.deps.sessionRegistry.unregisterByManagerKey(key);
9127
- LOG.info("StopIDE", `CDP disconnected: ${key}`);
9128
- }
9129
- }
9130
- const keysToRemove = [];
9131
- for (const key of this.deps.instanceManager.listInstanceIds()) {
9132
- if (key === `ide:${ideType}` || typeof key === "string" && key.startsWith(`ide:${ideType}_`)) {
9133
- keysToRemove.push(key);
9134
- }
9135
- }
9136
- for (const instanceKey of keysToRemove) {
9137
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
9138
- if (ideInstance) {
9139
- this.deps.instanceManager.removeInstance(instanceKey);
9140
- LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
9141
- }
9142
- }
9143
- if (keysToRemove.length === 0) {
9144
- const instanceKey = `ide:${ideType}`;
9145
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
9146
- if (ideInstance) {
9147
- this.deps.instanceManager.removeInstance(instanceKey);
9148
- LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
9149
- }
9150
- }
9151
- if (killProcess) {
9152
- const running = isIdeRunning(ideType);
9153
- if (running) {
9154
- LOG.info("StopIDE", `Killing IDE process: ${ideType}`);
9155
- const killed = await killIdeProcess(ideType);
9156
- if (killed) {
9157
- LOG.info("StopIDE", `\u2705 Process killed: ${ideType}`);
9158
- } else {
9159
- LOG.warn("StopIDE", `\u26A0 Could not kill process: ${ideType} (may need manual intervention)`);
9160
- }
9161
- } else {
9162
- LOG.info("StopIDE", `Process not running: ${ideType}`);
9163
- }
9164
- }
9165
- this.deps.onStatusChange?.();
9166
- LOG.info("StopIDE", `IDE stopped: ${ideType} (processKill=${killProcess})`);
9167
- }
9168
- };
9169
- }
9170
- });
9171
-
9172
8853
  // ../../oss/packages/daemon-core/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts
9173
8854
  function isModuleNotFoundError(error48, ref) {
9174
8855
  if (!(error48 instanceof Error)) return false;
@@ -9996,7 +9677,7 @@ function Ec(s15, t) {
9996
9677
  function Tc(s15) {
9997
9678
  return s15.keyCode === 16 || s15.keyCode === 17 || s15.keyCode === 18;
9998
9679
  }
9999
- var zs, Rl, Ll, M, S, Gs, mi, $s, _i, er, tr, ir, we, De, rt, q, js, Hn, Fn, F, rr, ge, Zs, xt, nr, H, sr, Js, Be, wt, nt, ae, Dt, ce, Qs, or, Re, lr, Wn, Bl, Un, bi, ar, Rt, cr, ro, so, At, lo, ao, oo, ur, zn, Wl, dt, hr, dr, Ee, D, ye, fe, kt, G, Ct, zl, mr, Gl, fo, $l, $, Mt, $n, po, br, Vn, gi, qn, Yn, Vl, Pt, ql, Yl, _r, v, jn, gr, Si, Eu, Tu, Ot, Ei, Bt, Ti, Sr, Iu, yu, vr, Nt, yr, xr, Ii, Zl, vo, go, Jl, Ql, ea, ta, Tr, Ir, bo, ia, $e, Ve, xe, So, ra, Xn, wr, Te, Zn, Dr, na, xu, Fe, st, sa, oa, Eo, la, wu, Du, Ru, Lu, ot, aa, yi, Jn, To, Io, yo, Qn, Rr, es, ua, ha, da, fa, ft, wo, Lr, qe, xi, Do, ma, ts2, Ye, kr, ba, Ar, va, _e, Cr, Bh, be, Nh, Fh, Hh, Oo, Wh, Uh, No, Kh, zh, ss, os10, wa, mt, Mr, Di, pt, Gh, Y, Da, ls, Wt, He, Q, Pr, lt, Uo, Or, cs, Ri, Br, Nr, Fr, Ca, Ut, Kt, Wr, Ur, Ma, Ko, zo, us, zr, hs, ds, Kr, zt, Gt, Gr, We, at, Li, bt, b, Ai, fs8, $t, ue, he, de, J, ps, j, U, z, ve, $r, Vr, ct, Vt, Yr, ms, _s, Le, jr, jo, ki, Xr, Na, Yt, jt, Zr, bs, vs, Jr, gs, Qr, Xt, en, tn, Mi, Pi, Oi, Ss, Fa, Zo, Zt, Wa, Ua, Es, Bi, Ts, rn, Is, ys, Jt, nn, Qt, xs, on, Ds, Ya, ja, Xa, Za, Ja, ei, Hi, Wi, re, St, Ki, tl, il, Ui, Qa, ti, Rs, ln, ec, tc, ii, ic, zi, B, X, an, Ls, Ze, un, cn, ne, Je, cl, $i, hn, ks, Cs, ni, si, nc, dn, ul, hl, li, dl, Ps, fl, ai, Os, ac, se, fn, Ae, pn, Vi, uc, ci, qi, mn, pe, Yi, _n, ji, Xi, Fs, ke, hc, bn, dc, fc, mc, ut, _l, vl, gl, vn, Zi, _c, El, bc, gn, ui, Tl, Sn, gc, ee, En, Us, yl, Tn, Ks, Sc, In, xl, wl, Tt, hi, yn, xn, wn, Ji, Dn, Rn, Ln, Ic, Ue, Dl;
9680
+ var zs, Rl, Ll, M, S, Gs, mi, $s, _i, er, tr, ir, we, De, rt, q, js, Hn, Fn, F, rr, ge, Zs, xt, nr, H, sr, Js, Be, wt, nt, ae, Dt, ce, Qs, or, Re, lr, Wn, Bl, Un, bi, ar, Rt, cr, ro, so, At, lo, ao, oo, ur, zn, Wl, dt, hr, dr, Ee, D, ye, fe, kt, G, Ct, zl, mr, Gl, fo, $l, $, Mt, $n, po, br, Vn, gi, qn, Yn, Vl, Pt, ql, Yl, _r, v, jn, gr, Si, Eu, Tu, Ot, Ei, Bt, Ti, Sr, Iu, yu, vr, Nt, yr, xr, Ii, Zl, vo, go, Jl, Ql, ea, ta, Tr, Ir, bo, ia, $e, Ve, xe, So, ra, Xn, wr, Te, Zn, Dr, na, xu, Fe, st, sa, oa, Eo, la, wu, Du, Ru, Lu, ot, aa, yi, Jn, To, Io, yo, Qn, Rr, es, ua, ha, da, fa, ft, wo, Lr, qe, xi, Do, ma, ts2, Ye, kr, ba, Ar, va, _e, Cr, Bh, be, Nh, Fh, Hh, Oo, Wh, Uh, No, Kh, zh, ss, os10, wa, mt, Mr, Di, pt, Gh, Y, Da, ls, Wt, He, Q, Pr, lt, Uo, Or, cs, Ri, Br, Nr, Fr, Ca, Ut, Kt, Wr, Ur, Ma, Ko, zo, us, zr, hs, ds, Kr, zt, Gt, Gr, We, at, Li, bt, b, Ai, fs7, $t, ue, he, de, J, ps, j, U, z, ve, $r, Vr, ct, Vt, Yr, ms, _s, Le, jr, jo, ki, Xr, Na, Yt, jt, Zr, bs, vs, Jr, gs, Qr, Xt, en, tn, Mi, Pi, Oi, Ss, Fa, Zo, Zt, Wa, Ua, Es, Bi, Ts, rn, Is, ys, Jt, nn, Qt, xs, on, Ds, Ya, ja, Xa, Za, Ja, ei, Hi, Wi, re, St, Ki, tl, il, Ui, Qa, ti, Rs, ln, ec, tc, ii, ic, zi, B, X, an, Ls, Ze, un, cn, ne, Je, cl, $i, hn, ks, Cs, ni, si, nc, dn, ul, hl, li, dl, Ps, fl, ai, Os, ac, se, fn, Ae, pn, Vi, uc, ci, qi, mn, pe, Yi, _n, ji, Xi, Fs, ke, hc, bn, dc, fc, mc, ut, _l, vl, gl, vn, Zi, _c, El, bc, gn, ui, Tl, Sn, gc, ee, En, Us, yl, Tn, Ks, Sc, In, xl, wl, Tt, hi, yn, xn, wn, Ji, Dn, Rn, Ln, Ic, Ue, Dl;
10000
9681
  var init_xterm = __esm({
10001
9682
  "../../oss/node_modules/@xterm/xterm/lib/xterm.mjs"() {
10002
9683
  "use strict";
@@ -13271,7 +12952,7 @@ ${h.join(`
13271
12952
  ((E) => (E.NUL = "\0", E.SOH = "", E.STX = "", E.ETX = "", E.EOT = "", E.ENQ = "", E.ACK = "", E.BEL = "\x07", E.BS = "\b", E.HT = " ", E.LF = `
13272
12953
  `, E.VT = "\v", E.FF = "\f", E.CR = "\r", E.SO = "", E.SI = "", E.DLE = "", E.DC1 = "", E.DC2 = "", E.DC3 = "", E.DC4 = "", E.NAK = "", E.SYN = "", E.ETB = "", E.CAN = "", E.EM = "", E.SUB = "", E.ESC = "\x1B", E.FS = "", E.GS = "", E.RS = "", E.US = "", E.SP = " ", E.DEL = "\x7F"))(b ||= {});
13273
12954
  ((g) => (g.PAD = "\x80", g.HOP = "\x81", g.BPH = "\x82", g.NBH = "\x83", g.IND = "\x84", g.NEL = "\x85", g.SSA = "\x86", g.ESA = "\x87", g.HTS = "\x88", g.HTJ = "\x89", g.VTS = "\x8A", g.PLD = "\x8B", g.PLU = "\x8C", g.RI = "\x8D", g.SS2 = "\x8E", g.SS3 = "\x8F", g.DCS = "\x90", g.PU1 = "\x91", g.PU2 = "\x92", g.STS = "\x93", g.CCH = "\x94", g.MW = "\x95", g.SPA = "\x96", g.EPA = "\x97", g.SOS = "\x98", g.SGCI = "\x99", g.SCI = "\x9A", g.CSI = "\x9B", g.ST = "\x9C", g.OSC = "\x9D", g.PM = "\x9E", g.APC = "\x9F"))(Ai ||= {});
13274
- ((t) => t.ST = `${b.ESC}\\`)(fs8 ||= {});
12955
+ ((t) => t.ST = `${b.ESC}\\`)(fs7 ||= {});
13275
12956
  $t = class {
13276
12957
  constructor(t, e, i, r, n, o) {
13277
12958
  this._textarea = t;
@@ -17700,7 +17381,7 @@ ${h.join(`
17700
17381
  switch (i.type) {
17701
17382
  case 0:
17702
17383
  let o = U.toColorRGB(r === "ansi" ? this._themeService.colors.ansi[i.index] : this._themeService.colors[r]);
17703
- this.coreService.triggerDataEvent(`${b.ESC}]${n};${ml(o)}${fs8.ST}`);
17384
+ this.coreService.triggerDataEvent(`${b.ESC}]${n};${ml(o)}${fs7.ST}`);
17704
17385
  break;
17705
17386
  case 1:
17706
17387
  if (r === "ansi") this._themeService.modifyColors((l) => l.ansi[i.index] = j.toColor(...i.color));
@@ -18541,94 +18222,45 @@ function getSessionMessageUpdatedAt(session) {
18541
18222
  if (!lastMessage) return 0;
18542
18223
  return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
18543
18224
  }
18225
+ function getSessionCompletionMarker(session) {
18226
+ const lastMessage = session.activeChat?.messages?.at?.(-1);
18227
+ if (!lastMessage) return "";
18228
+ const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
18229
+ if (role === "user" || role === "human") return "";
18230
+ if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
18231
+ if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
18232
+ if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
18233
+ const timestamp = parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt);
18234
+ return timestamp > 0 ? `ts:${timestamp}` : "";
18235
+ }
18544
18236
  function getSessionLastUsedAt(session) {
18545
18237
  return getSessionMessageUpdatedAt(session) || session.lastUpdated || Date.now();
18546
18238
  }
18547
- function getSessionKind(session) {
18548
- return session.transport === "cdp-page" || session.transport === "cdp-webview" ? "ide" : session.transport === "acp" ? "acp" : "cli";
18549
- }
18550
18239
  function getLastMessageRole(session) {
18551
18240
  const role = session.activeChat?.messages?.at?.(-1)?.role;
18552
18241
  return typeof role === "string" ? role : "";
18553
18242
  }
18554
- function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole) {
18243
+ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole, completionMarker, seenCompletionMarker) {
18555
18244
  if (status === "waiting_approval") {
18556
18245
  return { unread: false, inboxBucket: "needs_attention" };
18557
18246
  }
18558
18247
  if (status === "generating" || status === "starting") {
18559
18248
  return { unread: false, inboxBucket: "working" };
18560
18249
  }
18561
- const unread = hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
18250
+ const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
18562
18251
  return { unread, inboxBucket: unread ? "task_complete" : "idle" };
18563
18252
  }
18564
- function buildRecentSessions(sessions, recentActivity, readState) {
18565
- const visibleKeys = /* @__PURE__ */ new Set();
18566
- const hiddenKeys = /* @__PURE__ */ new Set();
18567
- const live = sessions.filter((session) => !session.surfaceHidden && session.status !== "stopped").map((session) => {
18568
- const kind = getSessionKind(session);
18569
- const recentKey = buildRecentActivityKey({
18570
- kind,
18571
- providerType: session.providerType,
18572
- workspace: session.workspace
18573
- });
18574
- const lastSeenAt = readState[recentKey] || 0;
18575
- const lastUsedAt = getSessionLastUsedAt(session);
18576
- const { unread, inboxBucket } = getUnreadState(
18577
- getSessionMessageUpdatedAt(session) > 0,
18578
- session.status,
18579
- lastUsedAt,
18580
- lastSeenAt,
18581
- getLastMessageRole(session)
18582
- );
18583
- return {
18584
- id: session.id,
18585
- recentKey,
18586
- sessionId: session.id,
18587
- providerType: session.providerType,
18588
- providerName: session.providerName,
18589
- kind,
18590
- title: session.activeChat?.title || session.title || session.providerName,
18591
- workspace: session.workspace,
18592
- currentModel: session.currentModel,
18593
- status: session.status,
18594
- lastUsedAt,
18595
- unread,
18596
- lastSeenAt,
18597
- inboxBucket,
18598
- surfaceHidden: false
18599
- };
18600
- });
18601
- for (const item of live) {
18602
- visibleKeys.add(`${item.kind}:${item.providerType}:${item.workspace || ""}`);
18603
- }
18604
- for (const session of sessions) {
18605
- if (!session.surfaceHidden) continue;
18606
- hiddenKeys.add(`${getSessionKind(session)}:${session.providerType}:${session.workspace || ""}`);
18607
- }
18608
- const persisted = recentActivity.filter((item) => {
18609
- const key = `${item.kind}:${item.providerType}:${item.workspace || ""}`;
18610
- return !visibleKeys.has(key) && !hiddenKeys.has(key);
18611
- }).map((item) => {
18612
- const lastSeenAt = readState[item.id] || 0;
18613
- const unread = item.lastUsedAt > lastSeenAt;
18614
- return {
18615
- id: item.id,
18616
- recentKey: item.id,
18617
- sessionId: item.sessionId || null,
18618
- providerType: item.providerType,
18619
- providerName: item.providerName,
18620
- kind: item.kind,
18621
- title: item.title || item.providerName,
18622
- workspace: item.workspace,
18623
- currentModel: item.currentModel,
18624
- lastUsedAt: item.lastUsedAt,
18625
- unread,
18626
- lastSeenAt,
18627
- inboxBucket: unread ? "task_complete" : "idle",
18628
- surfaceHidden: false
18629
- };
18630
- });
18631
- return [...live, ...persisted].sort((a, b2) => b2.lastUsedAt - a.lastUsedAt).slice(0, 12);
18253
+ function buildRecentLaunches(recentActivity) {
18254
+ return recentActivity.map((item) => ({
18255
+ id: item.id,
18256
+ providerType: item.providerType,
18257
+ providerName: item.providerName,
18258
+ kind: item.kind,
18259
+ title: item.title || item.providerName,
18260
+ workspace: item.workspace,
18261
+ currentModel: item.currentModel,
18262
+ lastLaunchedAt: item.lastUsedAt
18263
+ })).sort((a, b2) => b2.lastLaunchedAt - a.lastLaunchedAt).slice(0, 12);
18632
18264
  }
18633
18265
  function buildStatusSnapshot(options) {
18634
18266
  const cfg = loadConfig();
@@ -18639,27 +18271,29 @@ function buildStatusSnapshot(options) {
18639
18271
  options.allStates,
18640
18272
  options.cdpManagers
18641
18273
  );
18642
- const readState = cfg.recentSessionReads || {};
18643
18274
  for (const session of sessions) {
18644
- const kind = getSessionKind(session);
18645
- const recentKey = buildRecentActivityKey({
18646
- kind,
18647
- providerType: session.providerType,
18648
- workspace: session.workspace
18649
- });
18650
- const lastSeenAt = getRecentSessionSeenAt(cfg, recentKey);
18275
+ const lastSeenAt = getSessionSeenAt(cfg, session.id);
18276
+ const seenCompletionMarker = getSessionSeenMarker(cfg, session.id);
18651
18277
  const lastUsedAt = getSessionLastUsedAt(session);
18278
+ const completionMarker = getSessionCompletionMarker(session);
18652
18279
  const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
18653
18280
  getSessionMessageUpdatedAt(session) > 0,
18654
18281
  session.status,
18655
18282
  lastUsedAt,
18656
18283
  lastSeenAt,
18657
- getLastMessageRole(session)
18284
+ getLastMessageRole(session),
18285
+ completionMarker,
18286
+ seenCompletionMarker
18658
18287
  );
18659
- session.recentKey = recentKey;
18660
18288
  session.lastSeenAt = lastSeenAt;
18661
18289
  session.unread = unread;
18662
18290
  session.inboxBucket = inboxBucket;
18291
+ if (READ_DEBUG_ENABLED && (session.unread || session.inboxBucket !== "idle" || session.providerType.includes("codex"))) {
18292
+ LOG.info(
18293
+ "RecentRead",
18294
+ `snapshot session id=${session.id} provider=${session.providerType} status=${String(session.status || "")} bucket=${inboxBucket} unread=${String(unread)} lastSeenAt=${lastSeenAt} completionMarker=${completionMarker || "-"} seenMarker=${seenCompletionMarker || "-"} lastUpdated=${String(session.lastUpdated || 0)} lastUsedAt=${lastUsedAt} lastRole=${getLastMessageRole(session)} msgUpdatedAt=${getSessionMessageUpdatedAt(session)}`
18295
+ );
18296
+ }
18663
18297
  }
18664
18298
  const terminalBackend = getTerminalBackendRuntimeStatus();
18665
18299
  return {
@@ -18686,12 +18320,12 @@ function buildStatusSnapshot(options) {
18686
18320
  workspaces: wsState.workspaces,
18687
18321
  defaultWorkspaceId: wsState.defaultWorkspaceId,
18688
18322
  defaultWorkspacePath: wsState.defaultWorkspacePath,
18689
- recentSessions: buildRecentSessions(sessions, recentActivity, readState),
18323
+ recentLaunches: buildRecentLaunches(recentActivity),
18690
18324
  terminalBackend,
18691
18325
  availableProviders: buildAvailableProviders(options.providerLoader)
18692
18326
  };
18693
18327
  }
18694
- var os11;
18328
+ var os11, READ_DEBUG_ENABLED;
18695
18329
  var init_snapshot = __esm({
18696
18330
  "../../oss/packages/daemon-core/src/status/snapshot.ts"() {
18697
18331
  "use strict";
@@ -18701,7 +18335,350 @@ var init_snapshot = __esm({
18701
18335
  init_workspaces();
18702
18336
  init_host_memory();
18703
18337
  init_terminal_screen();
18338
+ init_logger();
18339
+ init_builders();
18340
+ READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
18341
+ }
18342
+ });
18343
+
18344
+ // ../../oss/packages/daemon-core/src/commands/router.ts
18345
+ var fs8, CHAT_COMMANDS, READ_DEBUG_ENABLED2, DaemonCommandRouter;
18346
+ var init_router = __esm({
18347
+ "../../oss/packages/daemon-core/src/commands/router.ts"() {
18348
+ "use strict";
18349
+ init_manager();
18350
+ init_setup();
18351
+ init_launch();
18352
+ init_config();
18353
+ init_workspaces();
18354
+ init_recent_activity();
18355
+ init_ide_detector();
18356
+ init_logger();
18357
+ init_command_log();
18358
+ init_logger();
18704
18359
  init_builders();
18360
+ init_snapshot();
18361
+ fs8 = __toESM(require("fs"));
18362
+ CHAT_COMMANDS = [
18363
+ "send_chat",
18364
+ "new_chat",
18365
+ "switch_chat",
18366
+ "set_mode",
18367
+ "change_model"
18368
+ ];
18369
+ READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
18370
+ DaemonCommandRouter = class {
18371
+ deps;
18372
+ constructor(deps) {
18373
+ this.deps = deps;
18374
+ }
18375
+ /**
18376
+ * Unified command routing.
18377
+ * Returns result for all commands:
18378
+ * 1. Daemon-level commands (launch_ide, stop_ide, etc.)
18379
+ * 2. CLI commands (launch_cli, stop_cli, agent_command)
18380
+ * 3. DaemonCommandHandler delegation (CDP/agent-stream/file commands)
18381
+ *
18382
+ * @param cmd Command name
18383
+ * @param args Command arguments
18384
+ * @param source Log source ('ws' | 'p2p' | 'standalone' | etc.)
18385
+ */
18386
+ async execute(cmd, args, source = "unknown") {
18387
+ const cmdStart = Date.now();
18388
+ try {
18389
+ const daemonResult = await this.executeDaemonCommand(cmd, args);
18390
+ if (daemonResult) {
18391
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
18392
+ return daemonResult;
18393
+ }
18394
+ const handlerResult = await this.deps.commandHandler.handle(cmd, args);
18395
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
18396
+ if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
18397
+ this.deps.onPostChatCommand();
18398
+ }
18399
+ return handlerResult;
18400
+ } catch (e) {
18401
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
18402
+ throw e;
18403
+ }
18404
+ }
18405
+ // ─── Daemon-level command core ───────────────────
18406
+ /**
18407
+ * Daemon-level command execution (IDE start/stop/restart, CLI, detect, logs).
18408
+ * Returns null if not handled at this level → caller delegates to CommandHandler.
18409
+ */
18410
+ async executeDaemonCommand(cmd, args) {
18411
+ switch (cmd) {
18412
+ // ─── CLI / ACP commands ───
18413
+ case "launch_cli":
18414
+ case "stop_cli":
18415
+ case "agent_command": {
18416
+ return this.deps.cliManager.handleCliCommand(cmd, args);
18417
+ }
18418
+ // ─── Logs ───
18419
+ case "get_logs": {
18420
+ const count = parseInt(args?.count) || parseInt(args?.lines) || 100;
18421
+ const minLevel = args?.minLevel || "info";
18422
+ const sinceTs = args?.since || 0;
18423
+ try {
18424
+ let logs = getRecentLogs(count, minLevel);
18425
+ if (sinceTs > 0) {
18426
+ logs = logs.filter((l) => l.ts > sinceTs);
18427
+ }
18428
+ if (logs.length > 0) {
18429
+ return { success: true, logs, totalBuffered: logs.length };
18430
+ }
18431
+ if (fs8.existsSync(LOG_PATH)) {
18432
+ const content = fs8.readFileSync(LOG_PATH, "utf-8");
18433
+ const allLines = content.split("\n");
18434
+ const recent = allLines.slice(-count).join("\n");
18435
+ return { success: true, logs: recent, totalLines: allLines.length };
18436
+ }
18437
+ return { success: true, logs: [], totalBuffered: 0 };
18438
+ } catch (e) {
18439
+ return { success: false, error: e.message };
18440
+ }
18441
+ }
18442
+ // ─── restart_session: IDE / CLI / ACP unified ───
18443
+ case "restart_session": {
18444
+ const targetType = args?.cliType || args?.agentType || args?.ideType;
18445
+ if (!targetType) throw new Error("cliType or ideType required");
18446
+ const isIde = this.deps.cdpManagers.has(targetType) || this.deps.providerLoader.getMeta(targetType)?.category === "ide";
18447
+ if (isIde) {
18448
+ await this.stopIde(targetType, true);
18449
+ const launchResult = await this.executeDaemonCommand("launch_ide", { ideType: targetType, enableCdp: true, workspace: args?.workspace });
18450
+ return { success: true, restarted: true, ideType: targetType, launch: launchResult };
18451
+ }
18452
+ return this.deps.cliManager.handleCliCommand(cmd, args);
18453
+ }
18454
+ // ─── IDE stop ───
18455
+ case "stop_ide": {
18456
+ const ideType = args?.ideType;
18457
+ if (!ideType) throw new Error("ideType required");
18458
+ const killProcess = args?.killProcess !== false;
18459
+ await this.stopIde(ideType, killProcess);
18460
+ return { success: true, ideType, stopped: true, processKilled: killProcess };
18461
+ }
18462
+ // ─── IDE restart ───
18463
+ case "restart_ide": {
18464
+ const ideType = args?.ideType;
18465
+ if (!ideType) throw new Error("ideType required");
18466
+ await this.stopIde(ideType, true);
18467
+ const launchResult = await this.executeDaemonCommand("launch_ide", { ideType, enableCdp: true, workspace: args?.workspace });
18468
+ return { success: true, ideType, restarted: true, launch: launchResult };
18469
+ }
18470
+ // ─── IDE launch + CDP connect ───
18471
+ case "launch_ide": {
18472
+ const ideKey = args?.ideId || args?.ideType;
18473
+ const resolvedWorkspace = resolveIdeLaunchWorkspace(
18474
+ {
18475
+ workspace: args?.workspace,
18476
+ workspaceId: args?.workspaceId,
18477
+ useDefaultWorkspace: args?.useDefaultWorkspace
18478
+ },
18479
+ loadConfig()
18480
+ );
18481
+ const launchArgs = {
18482
+ ideId: ideKey,
18483
+ workspace: resolvedWorkspace,
18484
+ newWindow: args?.newWindow
18485
+ };
18486
+ LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
18487
+ const result = await launchWithCdp(launchArgs);
18488
+ if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
18489
+ const logFn = this.deps.getCdpLogFn ? this.deps.getCdpLogFn(result.ideId) : LOG.forComponent(`CDP:${result.ideId}`).asLogFn();
18490
+ const provider = this.deps.providerLoader.getMeta(result.ideId);
18491
+ const manager = new DaemonCdpManager(result.port, logFn, void 0, provider?.targetFilter);
18492
+ const connected = await manager.connect();
18493
+ if (connected) {
18494
+ registerExtensionProviders(this.deps.providerLoader, manager, result.ideId);
18495
+ this.deps.cdpManagers.set(result.ideId, manager);
18496
+ LOG.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
18497
+ LOG.info("CDP", `${this.deps.cdpManagers.size} IDE(s) connected`);
18498
+ this.deps.onCdpManagerCreated?.(result.ideId, manager);
18499
+ }
18500
+ }
18501
+ this.deps.onIdeConnected?.();
18502
+ if (result.success && resolvedWorkspace) {
18503
+ try {
18504
+ const next = appendRecentActivity(loadConfig(), {
18505
+ kind: "ide",
18506
+ providerType: result.ideId || ideKey,
18507
+ providerName: result.ideId || ideKey,
18508
+ workspace: resolvedWorkspace,
18509
+ title: result.ideId || ideKey
18510
+ });
18511
+ saveConfig(next);
18512
+ } catch {
18513
+ }
18514
+ } else if (result.success && (result.ideId || ideKey)) {
18515
+ try {
18516
+ saveConfig(appendRecentActivity(loadConfig(), {
18517
+ kind: "ide",
18518
+ providerType: result.ideId || ideKey,
18519
+ providerName: result.ideId || ideKey,
18520
+ title: result.ideId || ideKey
18521
+ }));
18522
+ } catch {
18523
+ }
18524
+ }
18525
+ return { success: result.success, ...result };
18526
+ }
18527
+ // ─── Detect IDEs ───
18528
+ case "detect_ides": {
18529
+ const results = await detectIDEs();
18530
+ this.deps.detectedIdes.value = results;
18531
+ return { success: true, detectedInfo: results };
18532
+ }
18533
+ // ─── Set User Name ───
18534
+ case "set_user_name": {
18535
+ const name = args?.userName;
18536
+ if (!name || typeof name !== "string") throw new Error("userName required");
18537
+ updateConfig({ userName: name });
18538
+ return { success: true, userName: name };
18539
+ }
18540
+ case "mark_session_seen": {
18541
+ const sessionId = args?.sessionId;
18542
+ if (!sessionId || typeof sessionId !== "string") {
18543
+ return { success: false, error: "sessionId is required" };
18544
+ }
18545
+ const currentConfig = loadConfig();
18546
+ const prevSeenAt = currentConfig.sessionReads?.[sessionId] || 0;
18547
+ const sessionEntries = buildSessionEntries(
18548
+ this.deps.instanceManager.collectAllStates(),
18549
+ this.deps.cdpManagers
18550
+ );
18551
+ const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
18552
+ const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : "";
18553
+ const next = markSessionSeen(
18554
+ currentConfig,
18555
+ sessionId,
18556
+ typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
18557
+ completionMarker
18558
+ );
18559
+ if (READ_DEBUG_ENABLED2) {
18560
+ LOG.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
18561
+ }
18562
+ saveConfig(next);
18563
+ this.deps.onStatusChange?.();
18564
+ return {
18565
+ success: true,
18566
+ sessionId,
18567
+ seenAt: next.sessionReads?.[sessionId] || Date.now(),
18568
+ completionMarker
18569
+ };
18570
+ }
18571
+ // ─── Daemon Self-Upgrade ───
18572
+ case "daemon_upgrade": {
18573
+ LOG.info("Upgrade", "Remote upgrade requested from dashboard");
18574
+ try {
18575
+ const { execSync: execSync7 } = await import("child_process");
18576
+ const isStandalone = this.deps.packageName === "@adhdev/daemon-standalone" || process.argv[1]?.includes("daemon-standalone");
18577
+ const pkgName = isStandalone ? "@adhdev/daemon-standalone" : "adhdev";
18578
+ const latest = execSync7(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
18579
+ LOG.info("Upgrade", `Latest ${pkgName}: v${latest}`);
18580
+ execSync7(`npm install -g ${pkgName}@latest --force`, {
18581
+ encoding: "utf-8",
18582
+ timeout: 12e4,
18583
+ stdio: ["pipe", "pipe", "pipe"]
18584
+ });
18585
+ LOG.info("Upgrade", `\u2705 Upgraded to v${latest}`);
18586
+ setTimeout(() => {
18587
+ LOG.info("Upgrade", "Restarting daemon with new version...");
18588
+ try {
18589
+ const path18 = require("path");
18590
+ const fs16 = require("fs");
18591
+ const pidFile = path18.join(process.env.HOME || process.env.USERPROFILE || "", ".adhdev", "daemon.pid");
18592
+ if (fs16.existsSync(pidFile)) fs16.unlinkSync(pidFile);
18593
+ } catch {
18594
+ }
18595
+ const { spawn: spawn4 } = require("child_process");
18596
+ const child = spawn4(process.execPath, process.argv.slice(1), {
18597
+ detached: true,
18598
+ stdio: "ignore",
18599
+ env: { ...process.env }
18600
+ });
18601
+ child.unref();
18602
+ process.exit(0);
18603
+ }, 3e3);
18604
+ return { success: true, upgraded: true, version: latest };
18605
+ } catch (e) {
18606
+ LOG.error("Upgrade", `Failed: ${e.message}`);
18607
+ return { success: false, error: e.message };
18608
+ }
18609
+ }
18610
+ // ─── Machine Settings ───
18611
+ case "set_machine_nickname": {
18612
+ const nickname = args?.nickname;
18613
+ updateConfig({ machineNickname: nickname || null });
18614
+ return { success: true };
18615
+ }
18616
+ default:
18617
+ break;
18618
+ }
18619
+ return null;
18620
+ }
18621
+ /**
18622
+ * IDE stop: CDP disconnect + InstanceManager cleanup + optionally kill OS process
18623
+ */
18624
+ async stopIde(ideType, killProcess = false) {
18625
+ const cdpKeysToRemove = [];
18626
+ for (const key of this.deps.cdpManagers.keys()) {
18627
+ if (key === ideType || key.startsWith(`${ideType}_`)) {
18628
+ cdpKeysToRemove.push(key);
18629
+ }
18630
+ }
18631
+ for (const key of cdpKeysToRemove) {
18632
+ const cdp = this.deps.cdpManagers.get(key);
18633
+ if (cdp) {
18634
+ try {
18635
+ cdp.disconnect();
18636
+ } catch {
18637
+ }
18638
+ this.deps.cdpManagers.delete(key);
18639
+ this.deps.sessionRegistry.unregisterByManagerKey(key);
18640
+ LOG.info("StopIDE", `CDP disconnected: ${key}`);
18641
+ }
18642
+ }
18643
+ const keysToRemove = [];
18644
+ for (const key of this.deps.instanceManager.listInstanceIds()) {
18645
+ if (key === `ide:${ideType}` || typeof key === "string" && key.startsWith(`ide:${ideType}_`)) {
18646
+ keysToRemove.push(key);
18647
+ }
18648
+ }
18649
+ for (const instanceKey of keysToRemove) {
18650
+ const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
18651
+ if (ideInstance) {
18652
+ this.deps.instanceManager.removeInstance(instanceKey);
18653
+ LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
18654
+ }
18655
+ }
18656
+ if (keysToRemove.length === 0) {
18657
+ const instanceKey = `ide:${ideType}`;
18658
+ const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
18659
+ if (ideInstance) {
18660
+ this.deps.instanceManager.removeInstance(instanceKey);
18661
+ LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
18662
+ }
18663
+ }
18664
+ if (killProcess) {
18665
+ const running = isIdeRunning(ideType);
18666
+ if (running) {
18667
+ LOG.info("StopIDE", `Killing IDE process: ${ideType}`);
18668
+ const killed = await killIdeProcess(ideType);
18669
+ if (killed) {
18670
+ LOG.info("StopIDE", `\u2705 Process killed: ${ideType}`);
18671
+ } else {
18672
+ LOG.warn("StopIDE", `\u26A0 Could not kill process: ${ideType} (may need manual intervention)`);
18673
+ }
18674
+ } else {
18675
+ LOG.info("StopIDE", `Process not running: ${ideType}`);
18676
+ }
18677
+ }
18678
+ this.deps.onStatusChange?.();
18679
+ LOG.info("StopIDE", `IDE stopped: ${ideType} (processKill=${killProcess})`);
18680
+ }
18681
+ };
18705
18682
  }
18706
18683
  });
18707
18684
 
@@ -18860,7 +18837,7 @@ var init_reporter = __esm({
18860
18837
  currentModel: session.currentModel,
18861
18838
  currentPlan: session.currentPlan,
18862
18839
  currentAutoApprove: session.currentAutoApprove,
18863
- recentKey: session.recentKey,
18840
+ lastUpdated: session.lastUpdated,
18864
18841
  unread: session.unread,
18865
18842
  lastSeenAt: session.lastSeenAt,
18866
18843
  inboxBucket: session.inboxBucket,
@@ -20122,12 +20099,14 @@ var init_cli_provider_instance = __esm({
20122
20099
  init_chat_history();
20123
20100
  init_logger();
20124
20101
  CliProviderInstance = class {
20125
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
20102
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
20126
20103
  this.provider = provider;
20127
20104
  this.workingDir = workingDir;
20128
20105
  this.cliArgs = cliArgs;
20129
20106
  this.type = provider.type;
20130
20107
  this.instanceId = instanceId || crypto3.randomUUID();
20108
+ this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
20109
+ this.resolvedOutputFormat = this.resolveOutputFormat();
20131
20110
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
20132
20111
  this.monitor = new StatusMonitor();
20133
20112
  this.historyWriter = new ChatHistoryWriter();
@@ -20146,6 +20125,26 @@ var init_cli_provider_instance = __esm({
20146
20125
  lastApprovalEventAt = 0;
20147
20126
  historyWriter;
20148
20127
  instanceId;
20128
+ launchMode;
20129
+ resolvedOutputFormat;
20130
+ /**
20131
+ * Determine output rendering format from:
20132
+ * 1. launchMode.outputFormat (explicit override)
20133
+ * 2. launchOptions[].outputFormatMap — check actual args for matching values
20134
+ * 3. Default: 'terminal'
20135
+ */
20136
+ resolveOutputFormat() {
20137
+ if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
20138
+ if (this.provider.launchOptions?.length) {
20139
+ for (const opt of this.provider.launchOptions) {
20140
+ if (!opt.outputFormatMap) continue;
20141
+ for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
20142
+ if (this.cliArgs.includes(val)) return fmt;
20143
+ }
20144
+ }
20145
+ }
20146
+ return "terminal";
20147
+ }
20149
20148
  // ─── Lifecycle ─────────────────────────────────
20150
20149
  async init(context) {
20151
20150
  this.context = context;
@@ -20185,7 +20184,8 @@ var init_cli_provider_instance = __esm({
20185
20184
  name: this.provider.name,
20186
20185
  category: "cli",
20187
20186
  status: adapterStatus.status,
20188
- mode: "terminal",
20187
+ mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
20188
+ launchMode: this.launchMode?.id,
20189
20189
  activeChat: {
20190
20190
  id: `${this.type}_${this.workingDir}`,
20191
20191
  title: `${this.provider.name} \xB7 ${dirName}`,
@@ -37656,12 +37656,12 @@ var init_cli_manager = __esm({
37656
37656
  }
37657
37657
  }, 3e3);
37658
37658
  }
37659
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
37659
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
37660
37660
  const instanceManager = this.deps.getInstanceManager();
37661
37661
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
37662
37662
  if (!instanceManager) throw new Error("InstanceManager not available");
37663
37663
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
37664
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
37664
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
37665
37665
  try {
37666
37666
  await instanceManager.addInstance(key, cliInstance, {
37667
37667
  serverConn: this.deps.getServerConn(),
@@ -37687,7 +37687,7 @@ var init_cli_manager = __esm({
37687
37687
  this.startCliExitMonitor(key, cliType);
37688
37688
  }
37689
37689
  // ─── Session start/management ──────────────────────────────
37690
- async startSession(cliType, workingDir, cliArgs, initialModel) {
37690
+ async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
37691
37691
  const trimmed = (workingDir || "").trim();
37692
37692
  if (!trimmed) throw new Error("working directory required");
37693
37693
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os14.homedir()) : path10.resolve(trimmed);
@@ -37779,6 +37779,29 @@ ${installInfo}`
37779
37779
  if (provider) {
37780
37780
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
37781
37781
  }
37782
+ let resolvedCliArgs = cliArgs;
37783
+ let resolvedLaunchMode = launchMode;
37784
+ const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
37785
+ if (activeMode) {
37786
+ resolvedLaunchMode = activeMode.id;
37787
+ }
37788
+ if (provider?.launchArgBuilder) {
37789
+ const defaults = {};
37790
+ for (const opt of provider.launchOptions || []) {
37791
+ if (opt.default !== void 0) defaults[opt.id] = opt.default;
37792
+ }
37793
+ const modeOptions = activeMode?.options || {};
37794
+ const userOptions = launchOptionValues || {};
37795
+ const merged = { ...defaults, ...modeOptions, ...userOptions };
37796
+ const extraArgs = provider.launchArgBuilder(merged);
37797
+ if (extraArgs.length) {
37798
+ resolvedCliArgs = [...cliArgs || [], ...extraArgs];
37799
+ console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
37800
+ }
37801
+ } else if (activeMode?.extraArgs?.length) {
37802
+ resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
37803
+ console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
37804
+ }
37782
37805
  const instanceManager = this.deps.getInstanceManager();
37783
37806
  if (provider && instanceManager) {
37784
37807
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -37787,14 +37810,15 @@ ${installInfo}`
37787
37810
  normalizedType,
37788
37811
  cliType,
37789
37812
  resolvedDir,
37790
- cliArgs,
37813
+ resolvedCliArgs,
37791
37814
  resolvedProvider,
37792
37815
  {},
37793
- false
37816
+ false,
37817
+ resolvedLaunchMode
37794
37818
  );
37795
37819
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
37796
37820
  } else {
37797
- const adapter = this.createAdapter(cliType, resolvedDir, cliArgs, key, false);
37821
+ const adapter = this.createAdapter(cliType, resolvedDir, resolvedCliArgs, key, false);
37798
37822
  try {
37799
37823
  await adapter.spawn();
37800
37824
  } catch (spawnErr) {
@@ -37902,7 +37926,8 @@ ${installInfo}`
37902
37926
  record2.cliArgs,
37903
37927
  resolvedProvider,
37904
37928
  {},
37905
- true
37929
+ true,
37930
+ record2.launchMode
37906
37931
  );
37907
37932
  restored += 1;
37908
37933
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record2.runtimeKey || record2.runtimeId} (${record2.displayName || record2.workspace})`);
@@ -37972,7 +37997,7 @@ ${installInfo}`
37972
37997
  const dir = resolved.path;
37973
37998
  const launchSource = resolved.source;
37974
37999
  if (!cliType) throw new Error("cliType required");
37975
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
38000
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
37976
38001
  let newKey = null;
37977
38002
  for (const [k, adapter] of this.adapters) {
37978
38003
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -45685,7 +45710,7 @@ var init_adhdev_daemon = __esm({
45685
45710
  fs15 = __toESM(require("fs"));
45686
45711
  path17 = __toESM(require("path"));
45687
45712
  import_chalk2 = __toESM(require("chalk"));
45688
- pkgVersion = "0.7.39";
45713
+ pkgVersion = "0.7.41";
45689
45714
  if (pkgVersion === "unknown") {
45690
45715
  try {
45691
45716
  const possiblePaths = [