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/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;
@@ -3417,6 +3427,8 @@ function buildCliSession(state) {
3417
3427
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
3418
3428
  runtimeWriteOwner: state.runtime?.writeOwner || null,
3419
3429
  runtimeAttachedClients: state.runtime?.attachedClients || [],
3430
+ launchMode: state.launchMode,
3431
+ mode: state.mode,
3420
3432
  resume: state.resume,
3421
3433
  activeChat,
3422
3434
  capabilities: PTY_SESSION_CAPABILITIES,
@@ -8636,337 +8648,6 @@ var init_command_log = __esm({
8636
8648
  }
8637
8649
  });
8638
8650
 
8639
- // ../../oss/packages/daemon-core/src/commands/router.ts
8640
- var fs7, CHAT_COMMANDS, DaemonCommandRouter;
8641
- var init_router = __esm({
8642
- "../../oss/packages/daemon-core/src/commands/router.ts"() {
8643
- "use strict";
8644
- init_manager();
8645
- init_setup();
8646
- init_launch();
8647
- init_config();
8648
- init_workspaces();
8649
- init_recent_activity();
8650
- init_ide_detector();
8651
- init_logger();
8652
- init_command_log();
8653
- init_logger();
8654
- fs7 = __toESM(require("fs"));
8655
- CHAT_COMMANDS = [
8656
- "send_chat",
8657
- "new_chat",
8658
- "switch_chat",
8659
- "set_mode",
8660
- "change_model"
8661
- ];
8662
- DaemonCommandRouter = class {
8663
- deps;
8664
- constructor(deps) {
8665
- this.deps = deps;
8666
- }
8667
- /**
8668
- * Unified command routing.
8669
- * Returns result for all commands:
8670
- * 1. Daemon-level commands (launch_ide, stop_ide, etc.)
8671
- * 2. CLI commands (launch_cli, stop_cli, agent_command)
8672
- * 3. DaemonCommandHandler delegation (CDP/agent-stream/file commands)
8673
- *
8674
- * @param cmd Command name
8675
- * @param args Command arguments
8676
- * @param source Log source ('ws' | 'p2p' | 'standalone' | etc.)
8677
- */
8678
- async execute(cmd, args, source = "unknown") {
8679
- const cmdStart = Date.now();
8680
- try {
8681
- const daemonResult = await this.executeDaemonCommand(cmd, args);
8682
- if (daemonResult) {
8683
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
8684
- return daemonResult;
8685
- }
8686
- const handlerResult = await this.deps.commandHandler.handle(cmd, args);
8687
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
8688
- if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
8689
- this.deps.onPostChatCommand();
8690
- }
8691
- return handlerResult;
8692
- } catch (e) {
8693
- logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
8694
- throw e;
8695
- }
8696
- }
8697
- // ─── Daemon-level command core ───────────────────
8698
- /**
8699
- * Daemon-level command execution (IDE start/stop/restart, CLI, detect, logs).
8700
- * Returns null if not handled at this level → caller delegates to CommandHandler.
8701
- */
8702
- async executeDaemonCommand(cmd, args) {
8703
- switch (cmd) {
8704
- // ─── CLI / ACP commands ───
8705
- case "launch_cli":
8706
- case "stop_cli":
8707
- case "agent_command": {
8708
- return this.deps.cliManager.handleCliCommand(cmd, args);
8709
- }
8710
- // ─── Logs ───
8711
- case "get_logs": {
8712
- const count = parseInt(args?.count) || parseInt(args?.lines) || 100;
8713
- const minLevel = args?.minLevel || "info";
8714
- const sinceTs = args?.since || 0;
8715
- try {
8716
- let logs = getRecentLogs(count, minLevel);
8717
- if (sinceTs > 0) {
8718
- logs = logs.filter((l) => l.ts > sinceTs);
8719
- }
8720
- if (logs.length > 0) {
8721
- return { success: true, logs, totalBuffered: logs.length };
8722
- }
8723
- if (fs7.existsSync(LOG_PATH)) {
8724
- const content = fs7.readFileSync(LOG_PATH, "utf-8");
8725
- const allLines = content.split("\n");
8726
- const recent = allLines.slice(-count).join("\n");
8727
- return { success: true, logs: recent, totalLines: allLines.length };
8728
- }
8729
- return { success: true, logs: [], totalBuffered: 0 };
8730
- } catch (e) {
8731
- return { success: false, error: e.message };
8732
- }
8733
- }
8734
- // ─── restart_session: IDE / CLI / ACP unified ───
8735
- case "restart_session": {
8736
- const targetType = args?.cliType || args?.agentType || args?.ideType;
8737
- if (!targetType) throw new Error("cliType or ideType required");
8738
- const isIde = this.deps.cdpManagers.has(targetType) || this.deps.providerLoader.getMeta(targetType)?.category === "ide";
8739
- if (isIde) {
8740
- await this.stopIde(targetType, true);
8741
- const launchResult = await this.executeDaemonCommand("launch_ide", { ideType: targetType, enableCdp: true, workspace: args?.workspace });
8742
- return { success: true, restarted: true, ideType: targetType, launch: launchResult };
8743
- }
8744
- return this.deps.cliManager.handleCliCommand(cmd, args);
8745
- }
8746
- // ─── IDE stop ───
8747
- case "stop_ide": {
8748
- const ideType = args?.ideType;
8749
- if (!ideType) throw new Error("ideType required");
8750
- const killProcess = args?.killProcess !== false;
8751
- await this.stopIde(ideType, killProcess);
8752
- return { success: true, ideType, stopped: true, processKilled: killProcess };
8753
- }
8754
- // ─── IDE restart ───
8755
- case "restart_ide": {
8756
- const ideType = args?.ideType;
8757
- if (!ideType) throw new Error("ideType required");
8758
- await this.stopIde(ideType, true);
8759
- const launchResult = await this.executeDaemonCommand("launch_ide", { ideType, enableCdp: true, workspace: args?.workspace });
8760
- return { success: true, ideType, restarted: true, launch: launchResult };
8761
- }
8762
- // ─── IDE launch + CDP connect ───
8763
- case "launch_ide": {
8764
- const ideKey = args?.ideId || args?.ideType;
8765
- const resolvedWorkspace = resolveIdeLaunchWorkspace(
8766
- {
8767
- workspace: args?.workspace,
8768
- workspaceId: args?.workspaceId,
8769
- useDefaultWorkspace: args?.useDefaultWorkspace
8770
- },
8771
- loadConfig()
8772
- );
8773
- const launchArgs = {
8774
- ideId: ideKey,
8775
- workspace: resolvedWorkspace,
8776
- newWindow: args?.newWindow
8777
- };
8778
- LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
8779
- const result = await launchWithCdp(launchArgs);
8780
- if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
8781
- const logFn = this.deps.getCdpLogFn ? this.deps.getCdpLogFn(result.ideId) : LOG.forComponent(`CDP:${result.ideId}`).asLogFn();
8782
- const provider = this.deps.providerLoader.getMeta(result.ideId);
8783
- const manager = new DaemonCdpManager(result.port, logFn, void 0, provider?.targetFilter);
8784
- const connected = await manager.connect();
8785
- if (connected) {
8786
- registerExtensionProviders(this.deps.providerLoader, manager, result.ideId);
8787
- this.deps.cdpManagers.set(result.ideId, manager);
8788
- LOG.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
8789
- LOG.info("CDP", `${this.deps.cdpManagers.size} IDE(s) connected`);
8790
- this.deps.onCdpManagerCreated?.(result.ideId, manager);
8791
- }
8792
- }
8793
- this.deps.onIdeConnected?.();
8794
- if (result.success && resolvedWorkspace) {
8795
- try {
8796
- const next = appendRecentActivity(loadConfig(), {
8797
- kind: "ide",
8798
- providerType: result.ideId || ideKey,
8799
- providerName: result.ideId || ideKey,
8800
- workspace: resolvedWorkspace,
8801
- title: result.ideId || ideKey
8802
- });
8803
- saveConfig(next);
8804
- } catch {
8805
- }
8806
- } else if (result.success && (result.ideId || ideKey)) {
8807
- try {
8808
- saveConfig(appendRecentActivity(loadConfig(), {
8809
- kind: "ide",
8810
- providerType: result.ideId || ideKey,
8811
- providerName: result.ideId || ideKey,
8812
- title: result.ideId || ideKey
8813
- }));
8814
- } catch {
8815
- }
8816
- }
8817
- return { success: result.success, ...result };
8818
- }
8819
- // ─── Detect IDEs ───
8820
- case "detect_ides": {
8821
- const results = await detectIDEs();
8822
- this.deps.detectedIdes.value = results;
8823
- return { success: true, detectedInfo: results };
8824
- }
8825
- // ─── Set User Name ───
8826
- case "set_user_name": {
8827
- const name = args?.userName;
8828
- if (!name || typeof name !== "string") throw new Error("userName required");
8829
- updateConfig({ userName: name });
8830
- return { success: true, userName: name };
8831
- }
8832
- case "mark_recent_seen": {
8833
- const kind = args?.kind;
8834
- const providerType = args?.providerType;
8835
- if (!kind || !providerType) {
8836
- return { success: false, error: "kind and providerType are required" };
8837
- }
8838
- const recentKey = args?.recentKey || buildRecentActivityKey({
8839
- kind,
8840
- providerType,
8841
- workspace: args?.workspace || null
8842
- });
8843
- const next = markRecentSessionSeen(
8844
- loadConfig(),
8845
- recentKey,
8846
- typeof args?.seenAt === "number" ? args.seenAt : Date.now()
8847
- );
8848
- saveConfig(next);
8849
- this.deps.onStatusChange?.();
8850
- return {
8851
- success: true,
8852
- recentKey,
8853
- seenAt: next.recentSessionReads?.[recentKey] || Date.now()
8854
- };
8855
- }
8856
- // ─── Daemon Self-Upgrade ───
8857
- case "daemon_upgrade": {
8858
- LOG.info("Upgrade", "Remote upgrade requested from dashboard");
8859
- try {
8860
- const { execSync: execSync6 } = await import("child_process");
8861
- const isStandalone = this.deps.packageName === "@adhdev/daemon-standalone" || process.argv[1]?.includes("daemon-standalone");
8862
- const pkgName = isStandalone ? "@adhdev/daemon-standalone" : "adhdev";
8863
- const latest = execSync6(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
8864
- LOG.info("Upgrade", `Latest ${pkgName}: v${latest}`);
8865
- execSync6(`npm install -g ${pkgName}@latest --force`, {
8866
- encoding: "utf-8",
8867
- timeout: 12e4,
8868
- stdio: ["pipe", "pipe", "pipe"]
8869
- });
8870
- LOG.info("Upgrade", `\u2705 Upgraded to v${latest}`);
8871
- setTimeout(() => {
8872
- LOG.info("Upgrade", "Restarting daemon with new version...");
8873
- try {
8874
- const path18 = require("path");
8875
- const fs16 = require("fs");
8876
- const pidFile = path18.join(process.env.HOME || process.env.USERPROFILE || "", ".adhdev", "daemon.pid");
8877
- if (fs16.existsSync(pidFile)) fs16.unlinkSync(pidFile);
8878
- } catch {
8879
- }
8880
- const { spawn: spawn4 } = require("child_process");
8881
- const child = spawn4(process.execPath, process.argv.slice(1), {
8882
- detached: true,
8883
- stdio: "ignore",
8884
- env: { ...process.env }
8885
- });
8886
- child.unref();
8887
- process.exit(0);
8888
- }, 3e3);
8889
- return { success: true, upgraded: true, version: latest };
8890
- } catch (e) {
8891
- LOG.error("Upgrade", `Failed: ${e.message}`);
8892
- return { success: false, error: e.message };
8893
- }
8894
- }
8895
- // ─── Machine Settings ───
8896
- case "set_machine_nickname": {
8897
- const nickname = args?.nickname;
8898
- updateConfig({ machineNickname: nickname || null });
8899
- return { success: true };
8900
- }
8901
- default:
8902
- break;
8903
- }
8904
- return null;
8905
- }
8906
- /**
8907
- * IDE stop: CDP disconnect + InstanceManager cleanup + optionally kill OS process
8908
- */
8909
- async stopIde(ideType, killProcess = false) {
8910
- const cdpKeysToRemove = [];
8911
- for (const key of this.deps.cdpManagers.keys()) {
8912
- if (key === ideType || key.startsWith(`${ideType}_`)) {
8913
- cdpKeysToRemove.push(key);
8914
- }
8915
- }
8916
- for (const key of cdpKeysToRemove) {
8917
- const cdp = this.deps.cdpManagers.get(key);
8918
- if (cdp) {
8919
- try {
8920
- cdp.disconnect();
8921
- } catch {
8922
- }
8923
- this.deps.cdpManagers.delete(key);
8924
- this.deps.sessionRegistry.unregisterByManagerKey(key);
8925
- LOG.info("StopIDE", `CDP disconnected: ${key}`);
8926
- }
8927
- }
8928
- const keysToRemove = [];
8929
- for (const key of this.deps.instanceManager.listInstanceIds()) {
8930
- if (key === `ide:${ideType}` || typeof key === "string" && key.startsWith(`ide:${ideType}_`)) {
8931
- keysToRemove.push(key);
8932
- }
8933
- }
8934
- for (const instanceKey of keysToRemove) {
8935
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
8936
- if (ideInstance) {
8937
- this.deps.instanceManager.removeInstance(instanceKey);
8938
- LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
8939
- }
8940
- }
8941
- if (keysToRemove.length === 0) {
8942
- const instanceKey = `ide:${ideType}`;
8943
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
8944
- if (ideInstance) {
8945
- this.deps.instanceManager.removeInstance(instanceKey);
8946
- LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
8947
- }
8948
- }
8949
- if (killProcess) {
8950
- const running = isIdeRunning(ideType);
8951
- if (running) {
8952
- LOG.info("StopIDE", `Killing IDE process: ${ideType}`);
8953
- const killed = await killIdeProcess(ideType);
8954
- if (killed) {
8955
- LOG.info("StopIDE", `\u2705 Process killed: ${ideType}`);
8956
- } else {
8957
- LOG.warn("StopIDE", `\u26A0 Could not kill process: ${ideType} (may need manual intervention)`);
8958
- }
8959
- } else {
8960
- LOG.info("StopIDE", `Process not running: ${ideType}`);
8961
- }
8962
- }
8963
- this.deps.onStatusChange?.();
8964
- LOG.info("StopIDE", `IDE stopped: ${ideType} (processKill=${killProcess})`);
8965
- }
8966
- };
8967
- }
8968
- });
8969
-
8970
8651
  // ../../oss/packages/daemon-core/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts
8971
8652
  function isModuleNotFoundError(error48, ref) {
8972
8653
  if (!(error48 instanceof Error)) return false;
@@ -9794,7 +9475,7 @@ function Ec(s15, t) {
9794
9475
  function Tc(s15) {
9795
9476
  return s15.keyCode === 16 || s15.keyCode === 17 || s15.keyCode === 18;
9796
9477
  }
9797
- 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;
9478
+ 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;
9798
9479
  var init_xterm = __esm({
9799
9480
  "../../oss/node_modules/@xterm/xterm/lib/xterm.mjs"() {
9800
9481
  "use strict";
@@ -13069,7 +12750,7 @@ ${h.join(`
13069
12750
  ((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 = `
13070
12751
  `, 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 ||= {});
13071
12752
  ((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 ||= {});
13072
- ((t) => t.ST = `${b.ESC}\\`)(fs8 ||= {});
12753
+ ((t) => t.ST = `${b.ESC}\\`)(fs7 ||= {});
13073
12754
  $t = class {
13074
12755
  constructor(t, e, i, r, n, o) {
13075
12756
  this._textarea = t;
@@ -17498,7 +17179,7 @@ ${h.join(`
17498
17179
  switch (i.type) {
17499
17180
  case 0:
17500
17181
  let o = U.toColorRGB(r === "ansi" ? this._themeService.colors.ansi[i.index] : this._themeService.colors[r]);
17501
- this.coreService.triggerDataEvent(`${b.ESC}]${n};${ml(o)}${fs8.ST}`);
17182
+ this.coreService.triggerDataEvent(`${b.ESC}]${n};${ml(o)}${fs7.ST}`);
17502
17183
  break;
17503
17184
  case 1:
17504
17185
  if (r === "ansi") this._themeService.modifyColors((l) => l.ansi[i.index] = j.toColor(...i.color));
@@ -18339,94 +18020,45 @@ function getSessionMessageUpdatedAt(session) {
18339
18020
  if (!lastMessage) return 0;
18340
18021
  return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
18341
18022
  }
18023
+ function getSessionCompletionMarker(session) {
18024
+ const lastMessage = session.activeChat?.messages?.at?.(-1);
18025
+ if (!lastMessage) return "";
18026
+ const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
18027
+ if (role === "user" || role === "human") return "";
18028
+ if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
18029
+ if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
18030
+ if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
18031
+ const timestamp = parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt);
18032
+ return timestamp > 0 ? `ts:${timestamp}` : "";
18033
+ }
18342
18034
  function getSessionLastUsedAt(session) {
18343
18035
  return getSessionMessageUpdatedAt(session) || session.lastUpdated || Date.now();
18344
18036
  }
18345
- function getSessionKind(session) {
18346
- return session.transport === "cdp-page" || session.transport === "cdp-webview" ? "ide" : session.transport === "acp" ? "acp" : "cli";
18347
- }
18348
18037
  function getLastMessageRole(session) {
18349
18038
  const role = session.activeChat?.messages?.at?.(-1)?.role;
18350
18039
  return typeof role === "string" ? role : "";
18351
18040
  }
18352
- function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole) {
18041
+ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole, completionMarker, seenCompletionMarker) {
18353
18042
  if (status === "waiting_approval") {
18354
18043
  return { unread: false, inboxBucket: "needs_attention" };
18355
18044
  }
18356
18045
  if (status === "generating" || status === "starting") {
18357
18046
  return { unread: false, inboxBucket: "working" };
18358
18047
  }
18359
- const unread = hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
18048
+ const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
18360
18049
  return { unread, inboxBucket: unread ? "task_complete" : "idle" };
18361
18050
  }
18362
- function buildRecentSessions(sessions, recentActivity, readState) {
18363
- const visibleKeys = /* @__PURE__ */ new Set();
18364
- const hiddenKeys = /* @__PURE__ */ new Set();
18365
- const live = sessions.filter((session) => !session.surfaceHidden && session.status !== "stopped").map((session) => {
18366
- const kind = getSessionKind(session);
18367
- const recentKey = buildRecentActivityKey({
18368
- kind,
18369
- providerType: session.providerType,
18370
- workspace: session.workspace
18371
- });
18372
- const lastSeenAt = readState[recentKey] || 0;
18373
- const lastUsedAt = getSessionLastUsedAt(session);
18374
- const { unread, inboxBucket } = getUnreadState(
18375
- getSessionMessageUpdatedAt(session) > 0,
18376
- session.status,
18377
- lastUsedAt,
18378
- lastSeenAt,
18379
- getLastMessageRole(session)
18380
- );
18381
- return {
18382
- id: session.id,
18383
- recentKey,
18384
- sessionId: session.id,
18385
- providerType: session.providerType,
18386
- providerName: session.providerName,
18387
- kind,
18388
- title: session.activeChat?.title || session.title || session.providerName,
18389
- workspace: session.workspace,
18390
- currentModel: session.currentModel,
18391
- status: session.status,
18392
- lastUsedAt,
18393
- unread,
18394
- lastSeenAt,
18395
- inboxBucket,
18396
- surfaceHidden: false
18397
- };
18398
- });
18399
- for (const item of live) {
18400
- visibleKeys.add(`${item.kind}:${item.providerType}:${item.workspace || ""}`);
18401
- }
18402
- for (const session of sessions) {
18403
- if (!session.surfaceHidden) continue;
18404
- hiddenKeys.add(`${getSessionKind(session)}:${session.providerType}:${session.workspace || ""}`);
18405
- }
18406
- const persisted = recentActivity.filter((item) => {
18407
- const key = `${item.kind}:${item.providerType}:${item.workspace || ""}`;
18408
- return !visibleKeys.has(key) && !hiddenKeys.has(key);
18409
- }).map((item) => {
18410
- const lastSeenAt = readState[item.id] || 0;
18411
- const unread = item.lastUsedAt > lastSeenAt;
18412
- return {
18413
- id: item.id,
18414
- recentKey: item.id,
18415
- sessionId: item.sessionId || null,
18416
- providerType: item.providerType,
18417
- providerName: item.providerName,
18418
- kind: item.kind,
18419
- title: item.title || item.providerName,
18420
- workspace: item.workspace,
18421
- currentModel: item.currentModel,
18422
- lastUsedAt: item.lastUsedAt,
18423
- unread,
18424
- lastSeenAt,
18425
- inboxBucket: unread ? "task_complete" : "idle",
18426
- surfaceHidden: false
18427
- };
18428
- });
18429
- return [...live, ...persisted].sort((a, b2) => b2.lastUsedAt - a.lastUsedAt).slice(0, 12);
18051
+ function buildRecentLaunches(recentActivity) {
18052
+ return recentActivity.map((item) => ({
18053
+ id: item.id,
18054
+ providerType: item.providerType,
18055
+ providerName: item.providerName,
18056
+ kind: item.kind,
18057
+ title: item.title || item.providerName,
18058
+ workspace: item.workspace,
18059
+ currentModel: item.currentModel,
18060
+ lastLaunchedAt: item.lastUsedAt
18061
+ })).sort((a, b2) => b2.lastLaunchedAt - a.lastLaunchedAt).slice(0, 12);
18430
18062
  }
18431
18063
  function buildStatusSnapshot(options) {
18432
18064
  const cfg = loadConfig();
@@ -18437,27 +18069,29 @@ function buildStatusSnapshot(options) {
18437
18069
  options.allStates,
18438
18070
  options.cdpManagers
18439
18071
  );
18440
- const readState = cfg.recentSessionReads || {};
18441
18072
  for (const session of sessions) {
18442
- const kind = getSessionKind(session);
18443
- const recentKey = buildRecentActivityKey({
18444
- kind,
18445
- providerType: session.providerType,
18446
- workspace: session.workspace
18447
- });
18448
- const lastSeenAt = getRecentSessionSeenAt(cfg, recentKey);
18073
+ const lastSeenAt = getSessionSeenAt(cfg, session.id);
18074
+ const seenCompletionMarker = getSessionSeenMarker(cfg, session.id);
18449
18075
  const lastUsedAt = getSessionLastUsedAt(session);
18076
+ const completionMarker = getSessionCompletionMarker(session);
18450
18077
  const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
18451
18078
  getSessionMessageUpdatedAt(session) > 0,
18452
18079
  session.status,
18453
18080
  lastUsedAt,
18454
18081
  lastSeenAt,
18455
- getLastMessageRole(session)
18082
+ getLastMessageRole(session),
18083
+ completionMarker,
18084
+ seenCompletionMarker
18456
18085
  );
18457
- session.recentKey = recentKey;
18458
18086
  session.lastSeenAt = lastSeenAt;
18459
18087
  session.unread = unread;
18460
18088
  session.inboxBucket = inboxBucket;
18089
+ if (READ_DEBUG_ENABLED && (session.unread || session.inboxBucket !== "idle" || session.providerType.includes("codex"))) {
18090
+ LOG.info(
18091
+ "RecentRead",
18092
+ `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)}`
18093
+ );
18094
+ }
18461
18095
  }
18462
18096
  const terminalBackend = getTerminalBackendRuntimeStatus();
18463
18097
  return {
@@ -18484,12 +18118,12 @@ function buildStatusSnapshot(options) {
18484
18118
  workspaces: wsState.workspaces,
18485
18119
  defaultWorkspaceId: wsState.defaultWorkspaceId,
18486
18120
  defaultWorkspacePath: wsState.defaultWorkspacePath,
18487
- recentSessions: buildRecentSessions(sessions, recentActivity, readState),
18121
+ recentLaunches: buildRecentLaunches(recentActivity),
18488
18122
  terminalBackend,
18489
18123
  availableProviders: buildAvailableProviders(options.providerLoader)
18490
18124
  };
18491
18125
  }
18492
- var os11;
18126
+ var os11, READ_DEBUG_ENABLED;
18493
18127
  var init_snapshot = __esm({
18494
18128
  "../../oss/packages/daemon-core/src/status/snapshot.ts"() {
18495
18129
  "use strict";
@@ -18499,7 +18133,350 @@ var init_snapshot = __esm({
18499
18133
  init_workspaces();
18500
18134
  init_host_memory();
18501
18135
  init_terminal_screen();
18136
+ init_logger();
18137
+ init_builders();
18138
+ READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
18139
+ }
18140
+ });
18141
+
18142
+ // ../../oss/packages/daemon-core/src/commands/router.ts
18143
+ var fs8, CHAT_COMMANDS, READ_DEBUG_ENABLED2, DaemonCommandRouter;
18144
+ var init_router = __esm({
18145
+ "../../oss/packages/daemon-core/src/commands/router.ts"() {
18146
+ "use strict";
18147
+ init_manager();
18148
+ init_setup();
18149
+ init_launch();
18150
+ init_config();
18151
+ init_workspaces();
18152
+ init_recent_activity();
18153
+ init_ide_detector();
18154
+ init_logger();
18155
+ init_command_log();
18156
+ init_logger();
18502
18157
  init_builders();
18158
+ init_snapshot();
18159
+ fs8 = __toESM(require("fs"));
18160
+ CHAT_COMMANDS = [
18161
+ "send_chat",
18162
+ "new_chat",
18163
+ "switch_chat",
18164
+ "set_mode",
18165
+ "change_model"
18166
+ ];
18167
+ READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
18168
+ DaemonCommandRouter = class {
18169
+ deps;
18170
+ constructor(deps) {
18171
+ this.deps = deps;
18172
+ }
18173
+ /**
18174
+ * Unified command routing.
18175
+ * Returns result for all commands:
18176
+ * 1. Daemon-level commands (launch_ide, stop_ide, etc.)
18177
+ * 2. CLI commands (launch_cli, stop_cli, agent_command)
18178
+ * 3. DaemonCommandHandler delegation (CDP/agent-stream/file commands)
18179
+ *
18180
+ * @param cmd Command name
18181
+ * @param args Command arguments
18182
+ * @param source Log source ('ws' | 'p2p' | 'standalone' | etc.)
18183
+ */
18184
+ async execute(cmd, args, source = "unknown") {
18185
+ const cmdStart = Date.now();
18186
+ try {
18187
+ const daemonResult = await this.executeDaemonCommand(cmd, args);
18188
+ if (daemonResult) {
18189
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
18190
+ return daemonResult;
18191
+ }
18192
+ const handlerResult = await this.deps.commandHandler.handle(cmd, args);
18193
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
18194
+ if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
18195
+ this.deps.onPostChatCommand();
18196
+ }
18197
+ return handlerResult;
18198
+ } catch (e) {
18199
+ logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
18200
+ throw e;
18201
+ }
18202
+ }
18203
+ // ─── Daemon-level command core ───────────────────
18204
+ /**
18205
+ * Daemon-level command execution (IDE start/stop/restart, CLI, detect, logs).
18206
+ * Returns null if not handled at this level → caller delegates to CommandHandler.
18207
+ */
18208
+ async executeDaemonCommand(cmd, args) {
18209
+ switch (cmd) {
18210
+ // ─── CLI / ACP commands ───
18211
+ case "launch_cli":
18212
+ case "stop_cli":
18213
+ case "agent_command": {
18214
+ return this.deps.cliManager.handleCliCommand(cmd, args);
18215
+ }
18216
+ // ─── Logs ───
18217
+ case "get_logs": {
18218
+ const count = parseInt(args?.count) || parseInt(args?.lines) || 100;
18219
+ const minLevel = args?.minLevel || "info";
18220
+ const sinceTs = args?.since || 0;
18221
+ try {
18222
+ let logs = getRecentLogs(count, minLevel);
18223
+ if (sinceTs > 0) {
18224
+ logs = logs.filter((l) => l.ts > sinceTs);
18225
+ }
18226
+ if (logs.length > 0) {
18227
+ return { success: true, logs, totalBuffered: logs.length };
18228
+ }
18229
+ if (fs8.existsSync(LOG_PATH)) {
18230
+ const content = fs8.readFileSync(LOG_PATH, "utf-8");
18231
+ const allLines = content.split("\n");
18232
+ const recent = allLines.slice(-count).join("\n");
18233
+ return { success: true, logs: recent, totalLines: allLines.length };
18234
+ }
18235
+ return { success: true, logs: [], totalBuffered: 0 };
18236
+ } catch (e) {
18237
+ return { success: false, error: e.message };
18238
+ }
18239
+ }
18240
+ // ─── restart_session: IDE / CLI / ACP unified ───
18241
+ case "restart_session": {
18242
+ const targetType = args?.cliType || args?.agentType || args?.ideType;
18243
+ if (!targetType) throw new Error("cliType or ideType required");
18244
+ const isIde = this.deps.cdpManagers.has(targetType) || this.deps.providerLoader.getMeta(targetType)?.category === "ide";
18245
+ if (isIde) {
18246
+ await this.stopIde(targetType, true);
18247
+ const launchResult = await this.executeDaemonCommand("launch_ide", { ideType: targetType, enableCdp: true, workspace: args?.workspace });
18248
+ return { success: true, restarted: true, ideType: targetType, launch: launchResult };
18249
+ }
18250
+ return this.deps.cliManager.handleCliCommand(cmd, args);
18251
+ }
18252
+ // ─── IDE stop ───
18253
+ case "stop_ide": {
18254
+ const ideType = args?.ideType;
18255
+ if (!ideType) throw new Error("ideType required");
18256
+ const killProcess = args?.killProcess !== false;
18257
+ await this.stopIde(ideType, killProcess);
18258
+ return { success: true, ideType, stopped: true, processKilled: killProcess };
18259
+ }
18260
+ // ─── IDE restart ───
18261
+ case "restart_ide": {
18262
+ const ideType = args?.ideType;
18263
+ if (!ideType) throw new Error("ideType required");
18264
+ await this.stopIde(ideType, true);
18265
+ const launchResult = await this.executeDaemonCommand("launch_ide", { ideType, enableCdp: true, workspace: args?.workspace });
18266
+ return { success: true, ideType, restarted: true, launch: launchResult };
18267
+ }
18268
+ // ─── IDE launch + CDP connect ───
18269
+ case "launch_ide": {
18270
+ const ideKey = args?.ideId || args?.ideType;
18271
+ const resolvedWorkspace = resolveIdeLaunchWorkspace(
18272
+ {
18273
+ workspace: args?.workspace,
18274
+ workspaceId: args?.workspaceId,
18275
+ useDefaultWorkspace: args?.useDefaultWorkspace
18276
+ },
18277
+ loadConfig()
18278
+ );
18279
+ const launchArgs = {
18280
+ ideId: ideKey,
18281
+ workspace: resolvedWorkspace,
18282
+ newWindow: args?.newWindow
18283
+ };
18284
+ LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
18285
+ const result = await launchWithCdp(launchArgs);
18286
+ if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
18287
+ const logFn = this.deps.getCdpLogFn ? this.deps.getCdpLogFn(result.ideId) : LOG.forComponent(`CDP:${result.ideId}`).asLogFn();
18288
+ const provider = this.deps.providerLoader.getMeta(result.ideId);
18289
+ const manager = new DaemonCdpManager(result.port, logFn, void 0, provider?.targetFilter);
18290
+ const connected = await manager.connect();
18291
+ if (connected) {
18292
+ registerExtensionProviders(this.deps.providerLoader, manager, result.ideId);
18293
+ this.deps.cdpManagers.set(result.ideId, manager);
18294
+ LOG.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
18295
+ LOG.info("CDP", `${this.deps.cdpManagers.size} IDE(s) connected`);
18296
+ this.deps.onCdpManagerCreated?.(result.ideId, manager);
18297
+ }
18298
+ }
18299
+ this.deps.onIdeConnected?.();
18300
+ if (result.success && resolvedWorkspace) {
18301
+ try {
18302
+ const next = appendRecentActivity(loadConfig(), {
18303
+ kind: "ide",
18304
+ providerType: result.ideId || ideKey,
18305
+ providerName: result.ideId || ideKey,
18306
+ workspace: resolvedWorkspace,
18307
+ title: result.ideId || ideKey
18308
+ });
18309
+ saveConfig(next);
18310
+ } catch {
18311
+ }
18312
+ } else if (result.success && (result.ideId || ideKey)) {
18313
+ try {
18314
+ saveConfig(appendRecentActivity(loadConfig(), {
18315
+ kind: "ide",
18316
+ providerType: result.ideId || ideKey,
18317
+ providerName: result.ideId || ideKey,
18318
+ title: result.ideId || ideKey
18319
+ }));
18320
+ } catch {
18321
+ }
18322
+ }
18323
+ return { success: result.success, ...result };
18324
+ }
18325
+ // ─── Detect IDEs ───
18326
+ case "detect_ides": {
18327
+ const results = await detectIDEs();
18328
+ this.deps.detectedIdes.value = results;
18329
+ return { success: true, detectedInfo: results };
18330
+ }
18331
+ // ─── Set User Name ───
18332
+ case "set_user_name": {
18333
+ const name = args?.userName;
18334
+ if (!name || typeof name !== "string") throw new Error("userName required");
18335
+ updateConfig({ userName: name });
18336
+ return { success: true, userName: name };
18337
+ }
18338
+ case "mark_session_seen": {
18339
+ const sessionId = args?.sessionId;
18340
+ if (!sessionId || typeof sessionId !== "string") {
18341
+ return { success: false, error: "sessionId is required" };
18342
+ }
18343
+ const currentConfig = loadConfig();
18344
+ const prevSeenAt = currentConfig.sessionReads?.[sessionId] || 0;
18345
+ const sessionEntries = buildSessionEntries(
18346
+ this.deps.instanceManager.collectAllStates(),
18347
+ this.deps.cdpManagers
18348
+ );
18349
+ const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
18350
+ const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : "";
18351
+ const next = markSessionSeen(
18352
+ currentConfig,
18353
+ sessionId,
18354
+ typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
18355
+ completionMarker
18356
+ );
18357
+ if (READ_DEBUG_ENABLED2) {
18358
+ LOG.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
18359
+ }
18360
+ saveConfig(next);
18361
+ this.deps.onStatusChange?.();
18362
+ return {
18363
+ success: true,
18364
+ sessionId,
18365
+ seenAt: next.sessionReads?.[sessionId] || Date.now(),
18366
+ completionMarker
18367
+ };
18368
+ }
18369
+ // ─── Daemon Self-Upgrade ───
18370
+ case "daemon_upgrade": {
18371
+ LOG.info("Upgrade", "Remote upgrade requested from dashboard");
18372
+ try {
18373
+ const { execSync: execSync6 } = await import("child_process");
18374
+ const isStandalone = this.deps.packageName === "@adhdev/daemon-standalone" || process.argv[1]?.includes("daemon-standalone");
18375
+ const pkgName = isStandalone ? "@adhdev/daemon-standalone" : "adhdev";
18376
+ const latest = execSync6(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
18377
+ LOG.info("Upgrade", `Latest ${pkgName}: v${latest}`);
18378
+ execSync6(`npm install -g ${pkgName}@latest --force`, {
18379
+ encoding: "utf-8",
18380
+ timeout: 12e4,
18381
+ stdio: ["pipe", "pipe", "pipe"]
18382
+ });
18383
+ LOG.info("Upgrade", `\u2705 Upgraded to v${latest}`);
18384
+ setTimeout(() => {
18385
+ LOG.info("Upgrade", "Restarting daemon with new version...");
18386
+ try {
18387
+ const path18 = require("path");
18388
+ const fs16 = require("fs");
18389
+ const pidFile = path18.join(process.env.HOME || process.env.USERPROFILE || "", ".adhdev", "daemon.pid");
18390
+ if (fs16.existsSync(pidFile)) fs16.unlinkSync(pidFile);
18391
+ } catch {
18392
+ }
18393
+ const { spawn: spawn4 } = require("child_process");
18394
+ const child = spawn4(process.execPath, process.argv.slice(1), {
18395
+ detached: true,
18396
+ stdio: "ignore",
18397
+ env: { ...process.env }
18398
+ });
18399
+ child.unref();
18400
+ process.exit(0);
18401
+ }, 3e3);
18402
+ return { success: true, upgraded: true, version: latest };
18403
+ } catch (e) {
18404
+ LOG.error("Upgrade", `Failed: ${e.message}`);
18405
+ return { success: false, error: e.message };
18406
+ }
18407
+ }
18408
+ // ─── Machine Settings ───
18409
+ case "set_machine_nickname": {
18410
+ const nickname = args?.nickname;
18411
+ updateConfig({ machineNickname: nickname || null });
18412
+ return { success: true };
18413
+ }
18414
+ default:
18415
+ break;
18416
+ }
18417
+ return null;
18418
+ }
18419
+ /**
18420
+ * IDE stop: CDP disconnect + InstanceManager cleanup + optionally kill OS process
18421
+ */
18422
+ async stopIde(ideType, killProcess = false) {
18423
+ const cdpKeysToRemove = [];
18424
+ for (const key of this.deps.cdpManagers.keys()) {
18425
+ if (key === ideType || key.startsWith(`${ideType}_`)) {
18426
+ cdpKeysToRemove.push(key);
18427
+ }
18428
+ }
18429
+ for (const key of cdpKeysToRemove) {
18430
+ const cdp = this.deps.cdpManagers.get(key);
18431
+ if (cdp) {
18432
+ try {
18433
+ cdp.disconnect();
18434
+ } catch {
18435
+ }
18436
+ this.deps.cdpManagers.delete(key);
18437
+ this.deps.sessionRegistry.unregisterByManagerKey(key);
18438
+ LOG.info("StopIDE", `CDP disconnected: ${key}`);
18439
+ }
18440
+ }
18441
+ const keysToRemove = [];
18442
+ for (const key of this.deps.instanceManager.listInstanceIds()) {
18443
+ if (key === `ide:${ideType}` || typeof key === "string" && key.startsWith(`ide:${ideType}_`)) {
18444
+ keysToRemove.push(key);
18445
+ }
18446
+ }
18447
+ for (const instanceKey of keysToRemove) {
18448
+ const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
18449
+ if (ideInstance) {
18450
+ this.deps.instanceManager.removeInstance(instanceKey);
18451
+ LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
18452
+ }
18453
+ }
18454
+ if (keysToRemove.length === 0) {
18455
+ const instanceKey = `ide:${ideType}`;
18456
+ const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
18457
+ if (ideInstance) {
18458
+ this.deps.instanceManager.removeInstance(instanceKey);
18459
+ LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
18460
+ }
18461
+ }
18462
+ if (killProcess) {
18463
+ const running = isIdeRunning(ideType);
18464
+ if (running) {
18465
+ LOG.info("StopIDE", `Killing IDE process: ${ideType}`);
18466
+ const killed = await killIdeProcess(ideType);
18467
+ if (killed) {
18468
+ LOG.info("StopIDE", `\u2705 Process killed: ${ideType}`);
18469
+ } else {
18470
+ LOG.warn("StopIDE", `\u26A0 Could not kill process: ${ideType} (may need manual intervention)`);
18471
+ }
18472
+ } else {
18473
+ LOG.info("StopIDE", `Process not running: ${ideType}`);
18474
+ }
18475
+ }
18476
+ this.deps.onStatusChange?.();
18477
+ LOG.info("StopIDE", `IDE stopped: ${ideType} (processKill=${killProcess})`);
18478
+ }
18479
+ };
18503
18480
  }
18504
18481
  });
18505
18482
 
@@ -18658,7 +18635,7 @@ var init_reporter = __esm({
18658
18635
  currentModel: session.currentModel,
18659
18636
  currentPlan: session.currentPlan,
18660
18637
  currentAutoApprove: session.currentAutoApprove,
18661
- recentKey: session.recentKey,
18638
+ lastUpdated: session.lastUpdated,
18662
18639
  unread: session.unread,
18663
18640
  lastSeenAt: session.lastSeenAt,
18664
18641
  inboxBucket: session.inboxBucket,
@@ -19920,12 +19897,14 @@ var init_cli_provider_instance = __esm({
19920
19897
  init_chat_history();
19921
19898
  init_logger();
19922
19899
  CliProviderInstance = class {
19923
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
19900
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
19924
19901
  this.provider = provider;
19925
19902
  this.workingDir = workingDir;
19926
19903
  this.cliArgs = cliArgs;
19927
19904
  this.type = provider.type;
19928
19905
  this.instanceId = instanceId || crypto3.randomUUID();
19906
+ this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
19907
+ this.resolvedOutputFormat = this.resolveOutputFormat();
19929
19908
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
19930
19909
  this.monitor = new StatusMonitor();
19931
19910
  this.historyWriter = new ChatHistoryWriter();
@@ -19944,6 +19923,26 @@ var init_cli_provider_instance = __esm({
19944
19923
  lastApprovalEventAt = 0;
19945
19924
  historyWriter;
19946
19925
  instanceId;
19926
+ launchMode;
19927
+ resolvedOutputFormat;
19928
+ /**
19929
+ * Determine output rendering format from:
19930
+ * 1. launchMode.outputFormat (explicit override)
19931
+ * 2. launchOptions[].outputFormatMap — check actual args for matching values
19932
+ * 3. Default: 'terminal'
19933
+ */
19934
+ resolveOutputFormat() {
19935
+ if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
19936
+ if (this.provider.launchOptions?.length) {
19937
+ for (const opt of this.provider.launchOptions) {
19938
+ if (!opt.outputFormatMap) continue;
19939
+ for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
19940
+ if (this.cliArgs.includes(val)) return fmt;
19941
+ }
19942
+ }
19943
+ }
19944
+ return "terminal";
19945
+ }
19947
19946
  // ─── Lifecycle ─────────────────────────────────
19948
19947
  async init(context) {
19949
19948
  this.context = context;
@@ -19983,7 +19982,8 @@ var init_cli_provider_instance = __esm({
19983
19982
  name: this.provider.name,
19984
19983
  category: "cli",
19985
19984
  status: adapterStatus.status,
19986
- mode: "terminal",
19985
+ mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
19986
+ launchMode: this.launchMode?.id,
19987
19987
  activeChat: {
19988
19988
  id: `${this.type}_${this.workingDir}`,
19989
19989
  title: `${this.provider.name} \xB7 ${dirName}`,
@@ -37454,12 +37454,12 @@ var init_cli_manager = __esm({
37454
37454
  }
37455
37455
  }, 3e3);
37456
37456
  }
37457
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
37457
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
37458
37458
  const instanceManager = this.deps.getInstanceManager();
37459
37459
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
37460
37460
  if (!instanceManager) throw new Error("InstanceManager not available");
37461
37461
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
37462
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
37462
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
37463
37463
  try {
37464
37464
  await instanceManager.addInstance(key, cliInstance, {
37465
37465
  serverConn: this.deps.getServerConn(),
@@ -37485,7 +37485,7 @@ var init_cli_manager = __esm({
37485
37485
  this.startCliExitMonitor(key, cliType);
37486
37486
  }
37487
37487
  // ─── Session start/management ──────────────────────────────
37488
- async startSession(cliType, workingDir, cliArgs, initialModel) {
37488
+ async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
37489
37489
  const trimmed = (workingDir || "").trim();
37490
37490
  if (!trimmed) throw new Error("working directory required");
37491
37491
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os14.homedir()) : path10.resolve(trimmed);
@@ -37577,6 +37577,29 @@ ${installInfo}`
37577
37577
  if (provider) {
37578
37578
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
37579
37579
  }
37580
+ let resolvedCliArgs = cliArgs;
37581
+ let resolvedLaunchMode = launchMode;
37582
+ const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
37583
+ if (activeMode) {
37584
+ resolvedLaunchMode = activeMode.id;
37585
+ }
37586
+ if (provider?.launchArgBuilder) {
37587
+ const defaults = {};
37588
+ for (const opt of provider.launchOptions || []) {
37589
+ if (opt.default !== void 0) defaults[opt.id] = opt.default;
37590
+ }
37591
+ const modeOptions = activeMode?.options || {};
37592
+ const userOptions = launchOptionValues || {};
37593
+ const merged = { ...defaults, ...modeOptions, ...userOptions };
37594
+ const extraArgs = provider.launchArgBuilder(merged);
37595
+ if (extraArgs.length) {
37596
+ resolvedCliArgs = [...cliArgs || [], ...extraArgs];
37597
+ console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
37598
+ }
37599
+ } else if (activeMode?.extraArgs?.length) {
37600
+ resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
37601
+ console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
37602
+ }
37580
37603
  const instanceManager = this.deps.getInstanceManager();
37581
37604
  if (provider && instanceManager) {
37582
37605
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -37585,14 +37608,15 @@ ${installInfo}`
37585
37608
  normalizedType,
37586
37609
  cliType,
37587
37610
  resolvedDir,
37588
- cliArgs,
37611
+ resolvedCliArgs,
37589
37612
  resolvedProvider,
37590
37613
  {},
37591
- false
37614
+ false,
37615
+ resolvedLaunchMode
37592
37616
  );
37593
37617
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
37594
37618
  } else {
37595
- const adapter = this.createAdapter(cliType, resolvedDir, cliArgs, key, false);
37619
+ const adapter = this.createAdapter(cliType, resolvedDir, resolvedCliArgs, key, false);
37596
37620
  try {
37597
37621
  await adapter.spawn();
37598
37622
  } catch (spawnErr) {
@@ -37700,7 +37724,8 @@ ${installInfo}`
37700
37724
  record2.cliArgs,
37701
37725
  resolvedProvider,
37702
37726
  {},
37703
- true
37727
+ true,
37728
+ record2.launchMode
37704
37729
  );
37705
37730
  restored += 1;
37706
37731
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record2.runtimeKey || record2.runtimeId} (${record2.displayName || record2.workspace})`);
@@ -37770,7 +37795,7 @@ ${installInfo}`
37770
37795
  const dir = resolved.path;
37771
37796
  const launchSource = resolved.source;
37772
37797
  if (!cliType) throw new Error("cliType required");
37773
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
37798
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
37774
37799
  let newKey = null;
37775
37800
  for (const [k, adapter] of this.adapters) {
37776
37801
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -45166,7 +45191,7 @@ var init_adhdev_daemon = __esm({
45166
45191
  fs15 = __toESM(require("fs"));
45167
45192
  path17 = __toESM(require("path"));
45168
45193
  import_chalk2 = __toESM(require("chalk"));
45169
- pkgVersion = "0.7.39";
45194
+ pkgVersion = "0.7.41";
45170
45195
  if (pkgVersion === "unknown") {
45171
45196
  try {
45172
45197
  const possiblePaths = [