termdock 1.4.77 → 1.4.79

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.
Files changed (72) hide show
  1. package/dist/client/assets/{ModelPreview-MUquuQ7M.js → ModelPreview-Ctt5O84G.js} +1 -1
  2. package/dist/client/assets/{abnfDiagram-VRR7QNED-bSAQDoRq.js → abnfDiagram-VRR7QNED-2-Vk-uHF.js} +1 -1
  3. package/dist/client/assets/{arc-CRXZasqt.js → arc-BC6EcxRV.js} +1 -1
  4. package/dist/client/assets/{architectureDiagram-ZJ3FMSHR-B5lW2XVL.js → architectureDiagram-ZJ3FMSHR-DrNR18UU.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-677ZJIJ3-BnvUlbML.js → blockDiagram-677ZJIJ3-CEIlwBXq.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-LMCZKHZV-Dh43i8Od.js → c4Diagram-LMCZKHZV-BA8_HWcI.js} +1 -1
  7. package/dist/client/assets/channel-C358_iSm.js +1 -0
  8. package/dist/client/assets/{chunk-2Q5K7J3B-Br9F2z9G.js → chunk-2Q5K7J3B-UA9G57BK.js} +1 -1
  9. package/dist/client/assets/{chunk-32BRIVSS-CR_BEEo8.js → chunk-32BRIVSS-DbHqJEu-.js} +1 -1
  10. package/dist/client/assets/{chunk-5VM5RSS4-RSFWgHJK.js → chunk-5VM5RSS4-pGzDDSb3.js} +1 -1
  11. package/dist/client/assets/{chunk-EX3LRPZG-BojU9tp1.js → chunk-EX3LRPZG-C0yXZOTU.js} +1 -1
  12. package/dist/client/assets/{chunk-JWPE2WC7-Da5LKO28.js → chunk-JWPE2WC7-BtDDBeQD.js} +1 -1
  13. package/dist/client/assets/{chunk-MOJQB5TN-CnH9HN8z.js → chunk-MOJQB5TN-HC3bHHdR.js} +1 -1
  14. package/dist/client/assets/{chunk-RYQCIY6F-OAjuTT8n.js → chunk-RYQCIY6F-zL7eDN0a.js} +1 -1
  15. package/dist/client/assets/{chunk-V7JOEXUC-BeH2Mdv7.js → chunk-V7JOEXUC-CVTjMYIZ.js} +1 -1
  16. package/dist/client/assets/{chunk-VR4S4FIN-BK51NinF.js → chunk-VR4S4FIN-Bh1RANew.js} +1 -1
  17. package/dist/client/assets/{chunk-XXDRQBXY-Df-77sm7.js → chunk-XXDRQBXY-BtEXiXB8.js} +1 -1
  18. package/dist/client/assets/classDiagram-OUVF2IWQ-BJJG-Pnf.js +1 -0
  19. package/dist/client/assets/classDiagram-v2-EOCWNBFH-BJJG-Pnf.js +1 -0
  20. package/dist/client/assets/{cose-bilkent-JH36ORCC-C-FtawL2.js → cose-bilkent-JH36ORCC-DUTcoWBN.js} +1 -1
  21. package/dist/client/assets/{cynefin-VYW2F7L2-O7CaDQi8.js → cynefin-VYW2F7L2-CcbSv45f.js} +1 -1
  22. package/dist/client/assets/{cynefinDiagram-TSTJHNR4-B0fJizeX.js → cynefinDiagram-TSTJHNR4-BGf515TH.js} +1 -1
  23. package/dist/client/assets/{dagre-VKFMJZFB-BsIwc1IF.js → dagre-VKFMJZFB-QI_lDICR.js} +1 -1
  24. package/dist/client/assets/{diagram-FQU43EPY-GDwMRBsa.js → diagram-FQU43EPY-BCLtTsT9.js} +1 -1
  25. package/dist/client/assets/{diagram-G47NLZAW-Chv4syax.js → diagram-G47NLZAW-_yBnM1q_.js} +1 -1
  26. package/dist/client/assets/{diagram-NH7WQ7WH-Dh1F6AVi.js → diagram-NH7WQ7WH-XlYe1OWX.js} +1 -1
  27. package/dist/client/assets/{diagram-OA4YK3LP-CU3z6ul5.js → diagram-OA4YK3LP-BereD6t7.js} +1 -1
  28. package/dist/client/assets/{diagram-WEI45ONY-CYug818o.js → diagram-WEI45ONY-2nxjGQ_U.js} +1 -1
  29. package/dist/client/assets/{ebnfDiagram-CCIWWBDH-zzKMHZmD.js → ebnfDiagram-CCIWWBDH-Cne6J8Re.js} +1 -1
  30. package/dist/client/assets/{erDiagram-Q63AITRT-4yv9ci2k.js → erDiagram-Q63AITRT-B38mH0Dz.js} +1 -1
  31. package/dist/client/assets/{flowDiagram-23GEKE2U-CJj8uFtp.js → flowDiagram-23GEKE2U-Br3s8LhK.js} +1 -1
  32. package/dist/client/assets/{ganttDiagram-NO4QXBWP-WhZonF-5.js → ganttDiagram-NO4QXBWP-DRcCUswk.js} +1 -1
  33. package/dist/client/assets/{gitGraphDiagram-IHSO6WYX-DCmdLenS.js → gitGraphDiagram-IHSO6WYX-C2vtZMRF.js} +1 -1
  34. package/dist/client/assets/{index-ILJW_1zc.js → index-CLBhM0iA.js} +56 -56
  35. package/dist/client/assets/{infoDiagram-FWYZ7A6U-0HrqatQe.js → infoDiagram-FWYZ7A6U-D8wyLDDC.js} +1 -1
  36. package/dist/client/assets/{ishikawaDiagram-FXEZZL3T-DCPrrLNa.js → ishikawaDiagram-FXEZZL3T-kH1-N7T8.js} +1 -1
  37. package/dist/client/assets/{journeyDiagram-5HDEW3XC-CY0RHb4b.js → journeyDiagram-5HDEW3XC-1CmM2XJ1.js} +1 -1
  38. package/dist/client/assets/{kanban-definition-HUTT4EX6-DcH2OBHS.js → kanban-definition-HUTT4EX6-BWk70F73.js} +1 -1
  39. package/dist/client/assets/{linear-BidTRUFO.js → linear-CfygukEL.js} +1 -1
  40. package/dist/client/assets/{mermaid.core-BomIvgGf.js → mermaid.core-DImRwpsu.js} +4 -4
  41. package/dist/client/assets/{mindmap-definition-LN4V7U3C-BVbGSAMP.js → mindmap-definition-LN4V7U3C-7edZ10k5.js} +1 -1
  42. package/dist/client/assets/{pegDiagram-2B236MQR-BPDcfuXr.js → pegDiagram-2B236MQR-uontau4f.js} +1 -1
  43. package/dist/client/assets/{pieDiagram-ENE6RG2P-BEl37TgF.js → pieDiagram-ENE6RG2P-S6s_TLqy.js} +1 -1
  44. package/dist/client/assets/{quadrantDiagram-ABIIQ3AL-B4Jexgtq.js → quadrantDiagram-ABIIQ3AL-B0cY0YeM.js} +1 -1
  45. package/dist/client/assets/{railroadDiagram-RFXS5EU6-DCf5cVwA.js → railroadDiagram-RFXS5EU6-BqOLmm4H.js} +1 -1
  46. package/dist/client/assets/{requirementDiagram-TGXJPOKE-Dutz-kps.js → requirementDiagram-TGXJPOKE-C9fXYfhH.js} +1 -1
  47. package/dist/client/assets/{sankeyDiagram-HTMAVEWB-C5B7Px5r.js → sankeyDiagram-HTMAVEWB-CI7EhpIN.js} +1 -1
  48. package/dist/client/assets/{sequenceDiagram-DBY2YBRQ-BAjlNtX7.js → sequenceDiagram-DBY2YBRQ-xYg51Dle.js} +1 -1
  49. package/dist/client/assets/{sizeCapture-X5ZJPWSS-DxHVj2nI.js → sizeCapture-X5ZJPWSS-B5ynXyfy.js} +1 -1
  50. package/dist/client/assets/{stateDiagram-2N3HPSRC-h0J5lN0m.js → stateDiagram-2N3HPSRC-BehTEqHr.js} +1 -1
  51. package/dist/client/assets/stateDiagram-v2-6OUMAXLB-DOY1e3hd.js +1 -0
  52. package/dist/client/assets/{swimlanes-5IMT3BWC-BVPnl0Ka.js → swimlanes-5IMT3BWC-BUHgtegz.js} +2 -2
  53. package/dist/client/assets/swimlanesDiagram-G3AALYLV-Cc5uFyAu.js +8 -0
  54. package/dist/client/assets/{timeline-definition-FHXFAJF6-Cn5XtHKy.js → timeline-definition-FHXFAJF6-DJnmnV28.js} +1 -1
  55. package/dist/client/assets/{vennDiagram-L72KCM5P-CwBsi2Gg.js → vennDiagram-L72KCM5P-C_ZBj3fr.js} +1 -1
  56. package/dist/client/assets/{wardleyDiagram-EHGQE667-CZMtiWJm.js → wardleyDiagram-EHGQE667-YGm53tR-.js} +1 -1
  57. package/dist/client/assets/{xychartDiagram-FW5EYKEG-uGw9wOMW.js → xychartDiagram-FW5EYKEG-7ajuowBQ.js} +1 -1
  58. package/dist/client/index.html +1 -1
  59. package/dist/client/sw.js +1 -1
  60. package/dist/server/agent/autoTitle.js +30 -5
  61. package/dist/server/agent/renderedTerminalContext.js +94 -0
  62. package/dist/server/agent/session.js +7 -0
  63. package/dist/server/cli.js +1 -0
  64. package/dist/server/routes/terminal.js +85 -16
  65. package/dist/server/utils/settings.js +14 -0
  66. package/package.json +2 -1
  67. package/runtime-manifest.json +3 -3
  68. package/dist/client/assets/channel-Bm8opuca.js +0 -1
  69. package/dist/client/assets/classDiagram-OUVF2IWQ-eErPtGt5.js +0 -1
  70. package/dist/client/assets/classDiagram-v2-EOCWNBFH-eErPtGt5.js +0 -1
  71. package/dist/client/assets/stateDiagram-v2-6OUMAXLB-CtfvvrUK.js +0 -1
  72. package/dist/client/assets/swimlanesDiagram-G3AALYLV-CLhM0GwF.js +0 -8
@@ -14,7 +14,7 @@ import { getPtyHostManager } from '../ptyhost/manager.js';
14
14
  import { pathValidator } from '../utils/pathValidator.js';
15
15
  import { TERMINAL, TMUX } from '../config.js';
16
16
  import { localAccessManager } from '../utils/localAccess.js';
17
- import { normalizeLocalAccessName, getLocaleSetting, setLocaleSetting, getContextDraftHeightSetting, setContextDraftHeightSetting, getAutoRenameAgentsSetting, setAutoRenameAgentsSetting, getAutoRenameNamerSetting, setAutoRenameNamerSetting, getAutoRenameModelsSetting, setAutoRenameModelsSetting, getAutoRenameIntervalMinutesSetting, setAutoRenameIntervalMinutesSetting, getAutoRenamePromptPreferenceSetting, setAutoRenamePromptPreferenceSetting, } from '../utils/settings.js';
17
+ import { normalizeLocalAccessName, getLocaleSetting, setLocaleSetting, getContextDraftHeightSetting, setContextDraftHeightSetting, getAutoRenameAgentsSetting, setAutoRenameAgentsSetting, getAutoRenameNamerSetting, setAutoRenameNamerSetting, getAutoRenameModelsSetting, setAutoRenameModelsSetting, getAutoRenameIntervalMinutesSetting, setAutoRenameIntervalMinutesSetting, getAutoRenamePromptPreferenceSetting, setAutoRenamePromptPreferenceSetting, getAutoRenamePromptPayloadCharsSetting, setAutoRenamePromptPayloadCharsSetting, } from '../utils/settings.js';
18
18
  import { loadContextDraft, saveContextDraft } from '../utils/contextDraft.js';
19
19
  import { getOnboardingServerUrl } from '../onboardingServer.js';
20
20
  import { getFocusSequence, removeClientFocusState, scanFocusTrackingMode, setClientFocusState, } from '../utils/tmuxFocus.js';
@@ -29,8 +29,9 @@ import { notifyAgentTransition, notifyTerminalExit } from '../notifications/push
29
29
  import { setClientViewingSession } from '../notifications/pushViewers.js';
30
30
  import { getQuotaStatus, refreshQuota, startQuotaManager, } from '../quota/QuotaManager.js';
31
31
  import { TermdockAutoUpdateManager } from '../utils/autoUpdate.js';
32
- import { AUTO_TITLE_LONG_RUNNING_DELAY_MS, AUTO_TITLE_MIN_CONTEXT_CHARS, cleanTerminalContext, generateAgentTitle, hasSubstantiveAutoTitleContext, isNewAgentSessionId, isAutoTitleReevaluationDue, shouldReplaceAutoTitle, } from '../agent/autoTitle.js';
32
+ import { AUTO_TITLE_LONG_RUNNING_DELAY_MS, AUTO_TITLE_MIN_CONTEXT_CHARS, cleanTerminalContext, generateAgentTitle, hasSubstantiveAutoTitleContext, isLongRunningAutoTitleTurnEligible, isNewAgentSessionId, isAutoTitleReevaluationDue, shouldReplaceAutoTitle, } from '../agent/autoTitle.js';
33
33
  import { getTitleNamerCatalog, invalidateTitleNamerCatalog, probePluginTitleNamer } from '../agent/titleNamerCatalog.js';
34
+ import { RenderedTerminalContext } from '../agent/renderedTerminalContext.js';
34
35
  const router = express.Router();
35
36
  const execFileAsync = promisify(execFile);
36
37
  const TERMDOCK_DIR = `${os.homedir()}/.termdock`;
@@ -2128,10 +2129,42 @@ function detectSessionAgent(session) {
2128
2129
  }
2129
2130
  return null;
2130
2131
  }
2131
- const AUTO_TITLE_CONTEXT_LIMIT = 24_000;
2132
2132
  const autoTitlePending = new Set();
2133
- function appendAutoTitleContext(session, data) {
2134
- session.autoTitleContext = (session.autoTitleContext + data).slice(-AUTO_TITLE_CONTEXT_LIMIT);
2133
+ function appendAutoTitleContext(sessionId, session, data, schedule) {
2134
+ session.autoTitleTerminal.write(data, (rendered) => {
2135
+ session.autoTitleContext = rendered;
2136
+ if (schedule)
2137
+ maybeScheduleLongRunningAutoTitle(sessionId, session);
2138
+ });
2139
+ }
2140
+ function appendAutoTitlePromptPayload(session, payload) {
2141
+ const maxChars = getAutoRenamePromptPayloadCharsSetting();
2142
+ const bounded = payload.slice(0, maxChars).trim();
2143
+ if (!bounded || session.autoTitlePromptPayloads.at(-1) === bounded)
2144
+ return;
2145
+ session.autoTitlePromptPayloads.push(bounded);
2146
+ session.autoTitlePromptPayloads = session.autoTitlePromptPayloads.slice(-12);
2147
+ while (session.autoTitlePromptPayloads.length > 1
2148
+ && session.autoTitlePromptPayloads.join('\n').length > maxChars) {
2149
+ session.autoTitlePromptPayloads.shift();
2150
+ }
2151
+ }
2152
+ function getBoundedAutoTitlePromptPayloads(session) {
2153
+ const maxChars = getAutoRenamePromptPayloadCharsSetting();
2154
+ const selected = [];
2155
+ let used = 0;
2156
+ for (let index = session.autoTitlePromptPayloads.length - 1; index >= 0; index -= 1) {
2157
+ const payload = session.autoTitlePromptPayloads[index].slice(0, maxChars);
2158
+ const separatorChars = selected.length > 0 ? 1 : 0;
2159
+ if (used + separatorChars + payload.length > maxChars)
2160
+ continue;
2161
+ selected.unshift(payload);
2162
+ used += separatorChars + payload.length;
2163
+ }
2164
+ return selected;
2165
+ }
2166
+ async function resolveAutoTitleContext(session) {
2167
+ return cleanTerminalContext(await session.autoTitleTerminal.snapshot());
2135
2168
  }
2136
2169
  function clearAutoTitleForNewAgentSession(sessionId, session) {
2137
2170
  const record = globalSessionState.sessions.find((item) => item.backendSessionId === sessionId);
@@ -2140,6 +2173,8 @@ function clearAutoTitleForNewAgentSession(sessionId, session) {
2140
2173
  const next = { ...record, customName: undefined, autoTitle: null };
2141
2174
  upsertGlobalSessionRecord(next);
2142
2175
  session.autoTitleContext = '';
2176
+ session.autoTitleTerminal.reset();
2177
+ session.autoTitlePromptPayloads = [];
2143
2178
  if (next.mode === 'tmux' && next.tmuxSessionName) {
2144
2179
  void unsetTmuxOption(next.tmuxSessionName, '@termdock-friendly-name');
2145
2180
  }
@@ -2147,7 +2182,7 @@ function clearAutoTitleForNewAgentSession(sessionId, session) {
2147
2182
  broadcastClientState();
2148
2183
  console.log(`[auto-title] cleared stale title for new agent session in ${sessionId}`);
2149
2184
  }
2150
- async function maybeAutoRenameSession(sessionId, agent, rawContext, options = {}) {
2185
+ async function maybeAutoRenameSession(sessionId, agent, session, options = {}) {
2151
2186
  if (autoTitlePending.has(sessionId))
2152
2187
  return false;
2153
2188
  if (!getAutoRenameAgentsSetting().includes(agent.slug))
@@ -2157,14 +2192,17 @@ async function maybeAutoRenameSession(sessionId, agent, rawContext, options = {}
2157
2192
  return false;
2158
2193
  if (record.autoTitle && !options.forceReevaluation && !isAutoTitleReevaluationDue(record.autoTitle.updatedAt, getAutoRenameIntervalMinutesSetting()))
2159
2194
  return false;
2160
- const context = cleanTerminalContext(rawContext);
2195
+ const context = await resolveAutoTitleContext(session);
2196
+ const promptSubmitPayloads = getBoundedAutoTitlePromptPayloads(session);
2161
2197
  // A new session gets one cheap attempt after its first real exchange. Short
2162
2198
  // conversations ("hi" plus a brief reply) are still valid sessions; the
2163
2199
  // one-hour re-evaluation guard below keeps this from becoming noisy after a
2164
2200
  // title exists.
2165
2201
  if (context.length < AUTO_TITLE_MIN_CONTEXT_CHARS)
2166
2202
  return false;
2167
- const contentHash = createHash('sha256').update(context).digest('hex');
2203
+ const contentHash = createHash('sha256')
2204
+ .update(JSON.stringify({ context, promptSubmitPayloads }))
2205
+ .digest('hex');
2168
2206
  if (record.autoTitle?.contentHash === contentHash)
2169
2207
  return false;
2170
2208
  autoTitlePending.add(sessionId);
@@ -2187,6 +2225,7 @@ async function maybeAutoRenameSession(sessionId, agent, rawContext, options = {}
2187
2225
  models: validModels,
2188
2226
  currentTitle: record.autoTitle ? record.name : undefined,
2189
2227
  userPreference: getAutoRenamePromptPreferenceSetting(),
2228
+ promptSubmitPayloads,
2190
2229
  });
2191
2230
  if (!title)
2192
2231
  return false;
@@ -2239,7 +2278,7 @@ function maybeScheduleLongRunningAutoTitle(sessionId, session) {
2239
2278
  if (!agent || !getAutoRenameAgentsSetting().includes(agent.slug))
2240
2279
  return;
2241
2280
  const phase = session.agentSession?.status;
2242
- if (phase === 'done' || phase === 'idle')
2281
+ if (!isLongRunningAutoTitleTurnEligible(phase, session.autoTitleObservedPrompt, session.autoTitleTurnActive))
2243
2282
  return;
2244
2283
  const record = globalSessionState.sessions.find((item) => item.backendSessionId === sessionId);
2245
2284
  if (!record || record.autoTitle || record.customName === true)
@@ -2252,18 +2291,18 @@ function maybeScheduleLongRunningAutoTitle(sessionId, session) {
2252
2291
  if (liveSession !== session || liveSession.agent?.slug !== agent.slug)
2253
2292
  return;
2254
2293
  const phase = liveSession.agentSession?.status;
2255
- if (phase === 'done' || phase === 'idle')
2294
+ if (!isLongRunningAutoTitleTurnEligible(phase, liveSession.autoTitleObservedPrompt, liveSession.autoTitleTurnActive))
2256
2295
  return;
2257
2296
  const current = globalSessionState.sessions.find((item) => item.backendSessionId === sessionId);
2258
2297
  if (!current || current.autoTitle || current.customName === true)
2259
2298
  return;
2260
- void maybeAutoRenameSession(sessionId, agent, liveSession.autoTitleContext).then((generated) => {
2299
+ void maybeAutoRenameSession(sessionId, agent, liveSession).then((generated) => {
2261
2300
  if (!generated || terminalSessions.get(sessionId) !== liveSession)
2262
2301
  return;
2263
2302
  const completedWhileNaming = liveSession.agentSession?.status === 'done'
2264
2303
  || liveSession.agentSession?.status === 'idle';
2265
2304
  if (completedWhileNaming) {
2266
- void maybeAutoRenameSession(sessionId, agent, liveSession.autoTitleContext, { forceReevaluation: true });
2305
+ void maybeAutoRenameSession(sessionId, agent, liveSession, { forceReevaluation: true });
2267
2306
  return;
2268
2307
  }
2269
2308
  liveSession.autoTitleGeneratedMidTurn = true;
@@ -2459,22 +2498,36 @@ function applyAgentSignals(sessionId, session, events, notification) {
2459
2498
  session.autoTitleGeneratedMidTurn = false;
2460
2499
  clearAutoTitleForNewAgentSession(sessionId, session);
2461
2500
  }
2501
+ if (event.kind === 'session-start') {
2502
+ session.autoTitleObservedPrompt = false;
2503
+ session.autoTitleTurnActive = false;
2504
+ session.autoTitlePromptPayloads = [];
2505
+ }
2462
2506
  if (event.kind === 'prompt-submit') {
2463
2507
  // Before the first automatic title, keep accumulating short turns until
2464
2508
  // there is enough substance to name the session. Once titled, only the
2465
2509
  // latest turn is relevant to the conservative re-evaluation path.
2466
2510
  const persisted = globalSessionState.sessions.find((item) => item.backendSessionId === sessionId);
2467
- if (persisted?.autoTitle) {
2511
+ if (!session.autoTitleObservedPrompt || persisted?.autoTitle) {
2468
2512
  session.autoTitleContext = '';
2513
+ session.autoTitleTerminal.reset();
2469
2514
  }
2515
+ cancelLongRunningAutoTitle(session);
2516
+ session.autoTitleGeneratedMidTurn = false;
2517
+ session.autoTitleObservedPrompt = true;
2518
+ session.autoTitleTurnActive = true;
2519
+ if (event.promptPayload)
2520
+ appendAutoTitlePromptPayload(session, event.promptPayload);
2470
2521
  }
2471
2522
  applyAgentEvent(state, event);
2472
2523
  if (event.kind === 'stop') {
2473
2524
  cancelLongRunningAutoTitle(session);
2525
+ session.autoTitleTurnActive = false;
2474
2526
  completedTurnAgent = event.agent ?? session.agent;
2475
2527
  }
2476
2528
  if (event.kind === 'session-end') {
2477
2529
  cancelLongRunningAutoTitle(session);
2530
+ session.autoTitleTurnActive = false;
2478
2531
  }
2479
2532
  if (event.kind === 'session-start' || event.kind === 'session-end' || event.kind === 'stop') {
2480
2533
  persistAgentResumeBinding(sessionId, session);
@@ -2513,7 +2566,7 @@ function applyAgentSignals(sessionId, session, events, notification) {
2513
2566
  session.autoTitleGeneratedMidTurn = false;
2514
2567
  // Let the current PTY chunk reach the rolling context before reading it.
2515
2568
  setTimeout(() => {
2516
- void maybeAutoRenameSession(sessionId, agent, session.autoTitleContext, { forceReevaluation });
2569
+ void maybeAutoRenameSession(sessionId, agent, session, { forceReevaluation });
2517
2570
  }, 250).unref?.();
2518
2571
  }
2519
2572
  }
@@ -3357,6 +3410,7 @@ function cleanupSession(sessionId, options) {
3357
3410
  session.dataDisposable?.dispose();
3358
3411
  session.exitDisposable?.dispose();
3359
3412
  cancelLongRunningAutoTitle(session);
3413
+ session.autoTitleTerminal.dispose();
3360
3414
  lastAgentStatusSnapshots.delete(sessionId);
3361
3415
  lastGitStatusSnapshots.delete(sessionId);
3362
3416
  destroyTmuxControl(session.tmuxControl);
@@ -3452,6 +3506,7 @@ function applyPtyResize(sessionId, session, cols, rows, source, originClientId)
3452
3506
  }
3453
3507
  session.cols = cleanCols;
3454
3508
  session.rows = cleanRows;
3509
+ session.autoTitleTerminal.resize(cleanCols, cleanRows);
3455
3510
  session.lastActivity = Date.now();
3456
3511
  if (changed) {
3457
3512
  markTmuxClientsForScreenSync(sessionId, session);
@@ -3686,9 +3741,8 @@ function processSessionOutput(sessionId, session, data, opts) {
3686
3741
  }
3687
3742
  }
3688
3743
  catch { /* sniff failure should never block data */ }
3744
+ appendAutoTitleContext(sessionId, session, data, opts.broadcast);
3689
3745
  if (opts.broadcast) {
3690
- appendAutoTitleContext(session, data);
3691
- maybeScheduleLongRunningAutoTitle(sessionId, session);
3692
3746
  broadcastEvent(sessionId, seq !== undefined ? { type: 'data', data, seq } : { type: 'data', data });
3693
3747
  }
3694
3748
  }
@@ -3860,8 +3914,12 @@ async function spawnTerminalSession(req, input) {
3860
3914
  agent: null,
3861
3915
  agentSession: null,
3862
3916
  autoTitleContext: '',
3917
+ autoTitleTerminal: new RenderedTerminalContext(cols, rows),
3918
+ autoTitlePromptPayloads: [],
3863
3919
  autoTitleLongRunningTimer: null,
3864
3920
  autoTitleGeneratedMidTurn: false,
3921
+ autoTitleObservedPrompt: false,
3922
+ autoTitleTurnActive: false,
3865
3923
  lastAgentReviewed: null,
3866
3924
  agentLeftAt: null,
3867
3925
  gitStatus: null,
@@ -3944,8 +4002,12 @@ async function adoptPtyHostSessions() {
3944
4002
  agent: null,
3945
4003
  agentSession: null,
3946
4004
  autoTitleContext: '',
4005
+ autoTitleTerminal: new RenderedTerminalContext(meta.cols, meta.rows),
4006
+ autoTitlePromptPayloads: [],
3947
4007
  autoTitleLongRunningTimer: null,
3948
4008
  autoTitleGeneratedMidTurn: false,
4009
+ autoTitleObservedPrompt: false,
4010
+ autoTitleTurnActive: false,
3949
4011
  lastAgentReviewed: null,
3950
4012
  agentLeftAt: null,
3951
4013
  gitStatus: null,
@@ -4492,6 +4554,7 @@ async function getSettingsPayload() {
4492
4554
  autoRenameModels: getAutoRenameModelsSetting(),
4493
4555
  autoRenameIntervalMinutes: getAutoRenameIntervalMinutesSetting(),
4494
4556
  autoRenamePromptPreference: getAutoRenamePromptPreferenceSetting(),
4557
+ autoRenamePromptPayloadChars: getAutoRenamePromptPayloadCharsSetting(),
4495
4558
  localAccess: {
4496
4559
  ...localAccess,
4497
4560
  interfaces,
@@ -4583,6 +4646,12 @@ router.put('/settings', async (req, res) => {
4583
4646
  if (typeof body.autoRenamePromptPreference === 'string' && body.autoRenamePromptPreference.length <= 2000) {
4584
4647
  setAutoRenamePromptPreferenceSetting(body.autoRenamePromptPreference);
4585
4648
  }
4649
+ if (typeof body.autoRenamePromptPayloadChars === 'number'
4650
+ && Number.isInteger(body.autoRenamePromptPayloadChars)
4651
+ && body.autoRenamePromptPayloadChars >= 1000
4652
+ && body.autoRenamePromptPayloadChars <= 64_000) {
4653
+ setAutoRenamePromptPayloadCharsSetting(body.autoRenamePromptPayloadChars);
4654
+ }
4586
4655
  if (body.localAccess && typeof body.localAccess === 'object') {
4587
4656
  const localAccessBody = body.localAccess;
4588
4657
  if (localAccessBody.reset === true) {
@@ -88,6 +88,12 @@ function normalizeSettings(value) {
88
88
  autoRenamePromptPreference: typeof raw.autoRenamePromptPreference === 'string'
89
89
  ? raw.autoRenamePromptPreference.trim().slice(0, 2000)
90
90
  : '',
91
+ autoRenamePromptPayloadChars: typeof raw.autoRenamePromptPayloadChars === 'number'
92
+ && Number.isInteger(raw.autoRenamePromptPayloadChars)
93
+ && raw.autoRenamePromptPayloadChars >= 1000
94
+ && raw.autoRenamePromptPayloadChars <= 64_000
95
+ ? raw.autoRenamePromptPayloadChars
96
+ : 12_000,
91
97
  updatedAt: typeof raw.updatedAt === 'number' ? raw.updatedAt : Date.now(),
92
98
  };
93
99
  }
@@ -243,6 +249,14 @@ export function setAutoRenamePromptPreferenceSetting(preference) {
243
249
  settings.autoRenamePromptPreference = preference.trim().slice(0, 2000);
244
250
  });
245
251
  }
252
+ export function getAutoRenamePromptPayloadCharsSetting() {
253
+ return loadSettings().autoRenamePromptPayloadChars;
254
+ }
255
+ export function setAutoRenamePromptPayloadCharsSetting(chars) {
256
+ return updateSettings((settings) => {
257
+ settings.autoRenamePromptPayloadChars = Math.max(1000, Math.min(64_000, Math.round(chars)));
258
+ });
259
+ }
246
260
  export function setAutoRenameModelsSetting(models) {
247
261
  return updateSettings((settings) => {
248
262
  settings.autoRenameModels = Object.fromEntries(Object.entries(models)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termdock",
3
- "version": "1.4.77",
3
+ "version": "1.4.79",
4
4
  "description": "A complete web-based terminal application with modern UI",
5
5
  "type": "module",
6
6
  "main": ".desktop-dist/main.js",
@@ -63,6 +63,7 @@
63
63
  "@xterm/addon-unicode11": "^0.10.0-beta.287",
64
64
  "@xterm/addon-web-links": "^0.13.0-beta.287",
65
65
  "@xterm/addon-webgl": "^0.20.0-beta.286",
66
+ "@xterm/headless": "^6.1.0-beta.287",
66
67
  "@xterm/xterm": "^6.1.0-beta.287",
67
68
  "browser-haptic": "^1.0.13",
68
69
  "busboy": "^1.6.0",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "termdock",
4
- "version": "1.4.77",
4
+ "version": "1.4.79",
5
5
  "runtimeProtocolVersion": 1,
6
6
  "minimumDesktopVersion": "1.4.46",
7
7
  "nodeMajor": 22,
8
- "dependencyHash": "sha256-HxC6p3b4kFesefw+vmNYJtPtdIKJaZR1jFNb7DRJqjU=",
9
- "serverBundleHash": "sha256-7ZHVVvi3v7iGa1TX0wCJrBryKQHVBvLBeyAMp5HX+Cw=",
8
+ "dependencyHash": "sha256-emuXnf9w0kJF3ksMJVvdI0u8oLHKwZJ2/OzHBAXulZs=",
9
+ "serverBundleHash": "sha256-GoAVNoJGFUZfHeQMTYoJXmImgDexm9IpIKEgwniGVy4=",
10
10
  "entrypoint": "dist/server/cli.js",
11
11
  "clientEntrypoint": "dist/client/index.html"
12
12
  }
@@ -1 +0,0 @@
1
- import{U as a,C as n}from"./mermaid.core-BomIvgGf.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as t,C as e}from"./chunk-V7JOEXUC-BeH2Mdv7.js";import{b as i}from"./mermaid.core-BomIvgGf.js";import"./chunk-5VM5RSS4-RSFWgHJK.js";import"./chunk-XXDRQBXY-Df-77sm7.js";import"./chunk-VR4S4FIN-BK51NinF.js";import"./chunk-32BRIVSS-CR_BEEo8.js";import"./purify.es-CC4Brkr_.js";import"./index-ILJW_1zc.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as t,C as e}from"./chunk-V7JOEXUC-BeH2Mdv7.js";import{b as i}from"./mermaid.core-BomIvgGf.js";import"./chunk-5VM5RSS4-RSFWgHJK.js";import"./chunk-XXDRQBXY-Df-77sm7.js";import"./chunk-VR4S4FIN-BK51NinF.js";import"./chunk-32BRIVSS-CR_BEEo8.js";import"./purify.es-CC4Brkr_.js";import"./index-ILJW_1zc.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
@@ -1 +0,0 @@
1
- import{b as r,a as e,s as a,S as i}from"./chunk-EX3LRPZG-BojU9tp1.js";import{b as s}from"./mermaid.core-BomIvgGf.js";import"./chunk-XXDRQBXY-Df-77sm7.js";import"./chunk-VR4S4FIN-BK51NinF.js";import"./chunk-32BRIVSS-CR_BEEo8.js";import"./purify.es-CC4Brkr_.js";import"./index-ILJW_1zc.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:a,get db(){return new i(2)},renderer:e,styles:r,init:s(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute},"init")};export{g as diagram};
@@ -1,8 +0,0 @@
1
- import{c as r,s as e}from"./flowDiagram-23GEKE2U-CJj8uFtp.js";import{b as o}from"./mermaid.core-BomIvgGf.js";import"./chunk-5VM5RSS4-RSFWgHJK.js";import"./chunk-XXDRQBXY-Df-77sm7.js";import"./chunk-VR4S4FIN-BK51NinF.js";import"./chunk-32BRIVSS-CR_BEEo8.js";import"./purify.es-CC4Brkr_.js";import"./channel-Bm8opuca.js";import"./index-ILJW_1zc.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var a=o(t=>`${e(t)}
2
- .swimlane.cluster rect {
3
- stroke: ${t.clusterBorder} !important;
4
- }
5
- [data-look="neo"].cluster rect {
6
- filter: none;
7
- }
8
- `,"getStyles"),m=a,v=r({defaultLayout:"swimlane",styles:m});export{v as diagram};