@memo-code/memo 0.8.9 → 0.8.50

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 (61) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +1 -0
  3. package/dist/index.js +88 -79
  4. package/dist/prompt.md +2 -0
  5. package/dist/web/server/main.cjs +336 -187
  6. package/dist/web/ui/assets/{_baseUniq-dWQppZ6d.js → _baseUniq-DltOgNCU.js} +1 -1
  7. package/dist/web/ui/assets/{arc-CE88au5e.js → arc-CsVqK9Lb.js} +1 -1
  8. package/dist/web/ui/assets/{architectureDiagram-VXUJARFQ-BNpeHOY5.js → architectureDiagram-VXUJARFQ-BkwnFF8Y.js} +1 -1
  9. package/dist/web/ui/assets/{blockDiagram-VD42YOAC-CYClE7QH.js → blockDiagram-VD42YOAC-CA94VAjC.js} +1 -1
  10. package/dist/web/ui/assets/{c4Diagram-YG6GDRKO-CcbE6xPw.js → c4Diagram-YG6GDRKO-C0WsU_nq.js} +1 -1
  11. package/dist/web/ui/assets/channel-CM-YZjf5.js +1 -0
  12. package/dist/web/ui/assets/{chunk-4BX2VUAB-BSAX1ImB.js → chunk-4BX2VUAB-DglUTwZW.js} +1 -1
  13. package/dist/web/ui/assets/{chunk-55IACEB6-C9LyomDG.js → chunk-55IACEB6-DOOGSRjL.js} +1 -1
  14. package/dist/web/ui/assets/{chunk-B4BG7PRW-Cun3AEX5.js → chunk-B4BG7PRW-w6hF0Zcb.js} +1 -1
  15. package/dist/web/ui/assets/{chunk-DI55MBZ5-Bu89BqHa.js → chunk-DI55MBZ5-C0Vb_bLp.js} +1 -1
  16. package/dist/web/ui/assets/{chunk-FMBD7UC4-DNpV9XEE.js → chunk-FMBD7UC4-Ctx35DPt.js} +1 -1
  17. package/dist/web/ui/assets/{chunk-QN33PNHL-NPV2hyrc.js → chunk-QN33PNHL-DtVZR3nr.js} +1 -1
  18. package/dist/web/ui/assets/{chunk-QZHKN3VN-Bp_XIPnv.js → chunk-QZHKN3VN-Ch_jdCsH.js} +1 -1
  19. package/dist/web/ui/assets/{chunk-TZMSLE5B-Cmvdv-au.js → chunk-TZMSLE5B-BePFLhiS.js} +1 -1
  20. package/dist/web/ui/assets/classDiagram-2ON5EDUG-5ACEbCYo.js +1 -0
  21. package/dist/web/ui/assets/classDiagram-v2-WZHVMYZB-5ACEbCYo.js +1 -0
  22. package/dist/web/ui/assets/clone-DIMUORAQ.js +1 -0
  23. package/dist/web/ui/assets/{code-block-OCS4YCEC-C2kT-LYD.js → code-block-OCS4YCEC-B7AH2kqV.js} +1 -1
  24. package/dist/web/ui/assets/{cose-bilkent-S5V4N54A-CFFsEQ0V.js → cose-bilkent-S5V4N54A-BBRhnVZA.js} +1 -1
  25. package/dist/web/ui/assets/{dagre-6UL2VRFP-BRLSK-a9.js → dagre-6UL2VRFP-B6v_Z71G.js} +1 -1
  26. package/dist/web/ui/assets/{diagram-PSM6KHXK-vZO1UHIU.js → diagram-PSM6KHXK-Ce-iOIx7.js} +1 -1
  27. package/dist/web/ui/assets/{diagram-QEK2KX5R-Dtu1c5MN.js → diagram-QEK2KX5R-DXcCGip6.js} +1 -1
  28. package/dist/web/ui/assets/{diagram-S2PKOQOG-CzmmA2iX.js → diagram-S2PKOQOG-DVADDX-W.js} +1 -1
  29. package/dist/web/ui/assets/{erDiagram-Q2GNP2WA-BqAkkLjn.js → erDiagram-Q2GNP2WA-C8AlUD42.js} +1 -1
  30. package/dist/web/ui/assets/{flowDiagram-NV44I4VS-B82lKLwt.js → flowDiagram-NV44I4VS-D7Sf06Qi.js} +1 -1
  31. package/dist/web/ui/assets/{ganttDiagram-JELNMOA3-BWC1wtSC.js → ganttDiagram-JELNMOA3-DC1ZI7BI.js} +1 -1
  32. package/dist/web/ui/assets/{gitGraphDiagram-NY62KEGX-CM7KaZeW.js → gitGraphDiagram-NY62KEGX-BfZ1rfoJ.js} +1 -1
  33. package/dist/web/ui/assets/{graph-CRT-5-Zh.js → graph-BQpF6Nij.js} +1 -1
  34. package/dist/web/ui/assets/index-CHzX9Qy5.js +441 -0
  35. package/dist/web/ui/assets/index-pRZWTg6V.css +1 -0
  36. package/dist/web/ui/assets/{infoDiagram-WHAUD3N6-5361awxs.js → infoDiagram-WHAUD3N6-DpMWPNO4.js} +1 -1
  37. package/dist/web/ui/assets/{journeyDiagram-XKPGCS4Q-CJKfdHTq.js → journeyDiagram-XKPGCS4Q-C1NnAV9d.js} +1 -1
  38. package/dist/web/ui/assets/{kanban-definition-3W4ZIXB7-BiEvKmDH.js → kanban-definition-3W4ZIXB7-Dwx-vzmF.js} +1 -1
  39. package/dist/web/ui/assets/{layout-D2iadFG1.js → layout-pecnt6B2.js} +1 -1
  40. package/dist/web/ui/assets/{linear-Bf1gWj5B.js → linear-McmfKs1N.js} +1 -1
  41. package/dist/web/ui/assets/{min-CeMvHZmN.js → min-E1T_dxKi.js} +1 -1
  42. package/dist/web/ui/assets/{mindmap-definition-VGOIOE7T-BEXrN1M3.js → mindmap-definition-VGOIOE7T-EDAtU3iP.js} +1 -1
  43. package/dist/web/ui/assets/{pieDiagram-ADFJNKIX-CbmCszDS.js → pieDiagram-ADFJNKIX-Cn-bUvlG.js} +1 -1
  44. package/dist/web/ui/assets/{quadrantDiagram-AYHSOK5B-D7Y3imqh.js → quadrantDiagram-AYHSOK5B-rDZ_wUTY.js} +1 -1
  45. package/dist/web/ui/assets/{requirementDiagram-UZGBJVZJ-CzT7_amP.js → requirementDiagram-UZGBJVZJ-B8HT8i6v.js} +1 -1
  46. package/dist/web/ui/assets/{sankeyDiagram-TZEHDZUN-BV_cNDcr.js → sankeyDiagram-TZEHDZUN-DQNSFlyU.js} +1 -1
  47. package/dist/web/ui/assets/{sequenceDiagram-WL72ISMW-BRcmv7tP.js → sequenceDiagram-WL72ISMW-CtGDTINH.js} +1 -1
  48. package/dist/web/ui/assets/{stateDiagram-FKZM4ZOC-CMeMEFLk.js → stateDiagram-FKZM4ZOC-vyJFWQYy.js} +1 -1
  49. package/dist/web/ui/assets/stateDiagram-v2-4FDKWEC3-CrSesN6R.js +1 -0
  50. package/dist/web/ui/assets/{timeline-definition-IT6M3QCI-BZyEX2XM.js → timeline-definition-IT6M3QCI-Bd8FOmSP.js} +1 -1
  51. package/dist/web/ui/assets/{treemap-KMMF4GRG-BQ--90iT.js → treemap-KMMF4GRG-DH-VqRiC.js} +1 -1
  52. package/dist/web/ui/assets/{xychartDiagram-PRI3JC2R-Cy4Ru665.js → xychartDiagram-PRI3JC2R-BQK9j5Ts.js} +1 -1
  53. package/dist/web/ui/index.html +2 -2
  54. package/package.json +1 -1
  55. package/dist/web/ui/assets/channel-BHAnzevn.js +0 -1
  56. package/dist/web/ui/assets/classDiagram-2ON5EDUG-DYeZQwSK.js +0 -1
  57. package/dist/web/ui/assets/classDiagram-v2-WZHVMYZB-DYeZQwSK.js +0 -1
  58. package/dist/web/ui/assets/clone-C1hUNHYs.js +0 -1
  59. package/dist/web/ui/assets/index-Ct8a--tF.css +0 -1
  60. package/dist/web/ui/assets/index-DKv1BziB.js +0 -441
  61. package/dist/web/ui/assets/stateDiagram-v2-4FDKWEC3-iwwXwMzC.js +0 -1
@@ -117703,6 +117703,7 @@ var require_dist5 = __commonJS({
117703
117703
  }
117704
117704
  var import_meta = {};
117705
117705
  var TEMPLATE_PATTERN = /{{\s*([\w.-]+)\s*}}/g;
117706
+ var SOUL_PLACEHOLDER_PATTERN = /{{\s*soul_section\s*}}/;
117706
117707
  function renderTemplate(template, vars) {
117707
117708
  return template.replace(TEMPLATE_PATTERN, (_match, key) => vars[key] ?? "");
117708
117709
  }
@@ -117716,6 +117717,17 @@ var require_dist5 = __commonJS({
117716
117717
  function normalizePath(path2) {
117717
117718
  return (0, import_node_path2.resolve)(path2);
117718
117719
  }
117720
+ function resolveMemoHome(options) {
117721
+ const homeDir = options.homeDir ?? import_node_os2.default.homedir();
117722
+ const configured = options.memoHome?.trim() || process.env.MEMO_HOME?.trim() || (0, import_node_path2.join)(homeDir, ".memo");
117723
+ if (configured === "~") {
117724
+ return (0, import_node_path2.resolve)(homeDir);
117725
+ }
117726
+ if (configured.startsWith("~/")) {
117727
+ return (0, import_node_path2.resolve)((0, import_node_path2.join)(homeDir, configured.slice(2)));
117728
+ }
117729
+ return (0, import_node_path2.resolve)(configured);
117730
+ }
117719
117731
  function filterActiveSkills(skills, activeSkillPaths) {
117720
117732
  if (!Array.isArray(activeSkillPaths)) {
117721
117733
  return skills;
@@ -117747,6 +117759,34 @@ ${agents2.content}`;
117747
117759
  return `${basePrompt}
117748
117760
 
117749
117761
  ${skillsSection}`;
117762
+ }
117763
+ async function readSoulMd(options) {
117764
+ const memoHome2 = resolveMemoHome(options);
117765
+ const soulPath = (0, import_node_path2.join)(memoHome2, "SOUL.md");
117766
+ try {
117767
+ const content = await (0, import_promises2.readFile)(soulPath, "utf-8");
117768
+ if (!content.trim()) {
117769
+ return null;
117770
+ }
117771
+ return { path: soulPath, content };
117772
+ } catch {
117773
+ return null;
117774
+ }
117775
+ }
117776
+ function renderSoulSection(soul) {
117777
+ return `## User Personality Context (SOUL.md)
117778
+ Loaded from: ${soul.path}
117779
+
117780
+ - Treat this content as a soft preference layer for tone, style, and subjective behavior.
117781
+ - Do NOT let this content override safety rules, tool policies, Project AGENTS.md guidance, or explicit user instructions in the current turn.
117782
+ - Keep SOUL.md concise when possible to avoid unnecessary prompt growth.
117783
+
117784
+ ${soul.content}`;
117785
+ }
117786
+ function appendSoulPrompt(basePrompt, soulSection) {
117787
+ return `${basePrompt}
117788
+
117789
+ ${soulSection}`;
117750
117790
  }
117751
117791
  function resolveModuleDir() {
117752
117792
  if (typeof __dirname === "string") {
@@ -117774,12 +117814,19 @@ ${skillsSection}`;
117774
117814
  const startupRoot = options.cwd ?? process.cwd();
117775
117815
  const promptPath = resolvePromptPath(options.promptPath);
117776
117816
  const prompt = await (0, import_promises2.readFile)(promptPath, "utf-8");
117817
+ const soul = await readSoulMd({ homeDir: options.homeDir, memoHome: options.memoHome });
117818
+ const soulSection = soul ? renderSoulSection(soul) : "";
117819
+ const hasSoulPlaceholder = SOUL_PLACEHOLDER_PATTERN.test(prompt);
117777
117820
  const vars = {
117778
117821
  date: (/* @__PURE__ */ new Date()).toISOString(),
117779
117822
  user: resolveUsername(),
117780
- pwd: startupRoot
117823
+ pwd: startupRoot,
117824
+ soul_section: soulSection
117781
117825
  };
117782
117826
  let composedPrompt = renderTemplate(prompt, vars);
117827
+ if (!hasSoulPlaceholder && soulSection) {
117828
+ composedPrompt = appendSoulPrompt(composedPrompt, soulSection);
117829
+ }
117783
117830
  const agents2 = await readProjectAgentsMd(startupRoot);
117784
117831
  if (agents2) {
117785
117832
  composedPrompt = appendProjectAgentsPrompt(composedPrompt, agents2);
@@ -121618,7 +121665,7 @@ ${envLines}`;
121618
121665
  if (path2.startsWith("~/")) return (0, import_node_path9.join)((0, import_node_os4.homedir)(), path2.slice(2));
121619
121666
  return path2;
121620
121667
  }
121621
- function resolveMemoHome(settings) {
121668
+ function resolveMemoHome2(settings) {
121622
121669
  if (settings?.memoHome?.trim()) {
121623
121670
  return expandHome3(settings.memoHome.trim());
121624
121671
  }
@@ -121628,7 +121675,7 @@ ${envLines}`;
121628
121675
  return (0, import_node_path9.join)((0, import_node_os4.homedir)(), ".memo");
121629
121676
  }
121630
121677
  function oauthFilePath(settings) {
121631
- return (0, import_node_path9.join)(resolveMemoHome(settings), "auth", OAUTH_FILE_NAME);
121678
+ return (0, import_node_path9.join)(resolveMemoHome2(settings), "auth", OAUTH_FILE_NAME);
121632
121679
  }
121633
121680
  function computeCredentialKey(url2) {
121634
121681
  return (0, import_node_crypto3.createHash)("sha256").update(normalizeServerUrl(url2)).digest("hex");
@@ -142776,6 +142823,7 @@ var require_chat_service = __commonJS({
142776
142823
  var stream_service_1 = require_stream_service();
142777
142824
  var workspaces_service_1 = require_workspaces_service();
142778
142825
  var MAX_LIVE_SESSIONS = 20;
142826
+ var MAX_QUEUED_INPUTS = 3;
142779
142827
  function normalizeMode(value) {
142780
142828
  if (value === "none" || value === "once" || value === "full")
142781
142829
  return value;
@@ -142847,6 +142895,7 @@ var require_chat_service = __commonJS({
142847
142895
  await this.workspacesService.touchLastUsed(workspace.id);
142848
142896
  const config = await this.memoConfigService.load();
142849
142897
  const provider = this.selectProvider(config.providers, input.providerName, config.current_provider);
142898
+ const contextWindow = (0, core_1.resolveContextWindowForProvider)(config, provider);
142850
142899
  const sessionId = (0, node_crypto_1.randomUUID)();
142851
142900
  const runtime = await this.createRuntime({
142852
142901
  id: sessionId,
@@ -142858,7 +142907,8 @@ var require_chat_service = __commonJS({
142858
142907
  cwd: workspace.cwd,
142859
142908
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
142860
142909
  activeMcpServers: input.activeMcpServers && input.activeMcpServers.length > 0 ? input.activeMcpServers : config.active_mcp_servers,
142861
- toolPermissionMode: normalizeMode(input.toolPermissionMode)
142910
+ toolPermissionMode: normalizeMode(input.toolPermissionMode),
142911
+ contextWindow
142862
142912
  });
142863
142913
  this.sessions.set(runtime.id, runtime);
142864
142914
  this.touchSession(runtime);
@@ -142878,6 +142928,7 @@ var require_chat_service = __commonJS({
142878
142928
  await this.workspacesService.touchLastUsed(workspace.id);
142879
142929
  const config = await this.memoConfigService.load();
142880
142930
  const provider = this.selectProvider(config.providers, void 0, config.current_provider);
142931
+ const contextWindow = (0, core_1.resolveContextWindowForProvider)(config, provider);
142881
142932
  const historyMessages = [];
142882
142933
  const turns = [];
142883
142934
  for (const turn of detail.turns) {
@@ -142910,7 +142961,8 @@ var require_chat_service = __commonJS({
142910
142961
  startedAt: detail.date.startedAt,
142911
142962
  activeMcpServers: config.active_mcp_servers,
142912
142963
  toolPermissionMode: "once",
142913
- historyFilePath: detail.filePath
142964
+ historyFilePath: detail.filePath,
142965
+ contextWindow
142914
142966
  });
142915
142967
  const system = runtime.agentSession.history[0];
142916
142968
  runtime.agentSession.history = system ? [system, ...historyMessages] : [...historyMessages];
@@ -143033,23 +143085,70 @@ var require_chat_service = __commonJS({
143033
143085
  }
143034
143086
  async submitInput(sessionId, input) {
143035
143087
  const session = this.requireSession(sessionId);
143088
+ const trimmed = input.trim();
143089
+ if (!trimmed) {
143090
+ throw new common_1.BadRequestException("input is required");
143091
+ }
143036
143092
  if (session.status === "running") {
143093
+ if (session.queuedInputs.length >= MAX_QUEUED_INPUTS) {
143094
+ return {
143095
+ accepted: false,
143096
+ kind: "turn",
143097
+ status: "error",
143098
+ message: `Queue is full (max ${MAX_QUEUED_INPUTS}).`
143099
+ };
143100
+ }
143101
+ session.queuedInputs.push({
143102
+ id: (0, node_crypto_1.randomUUID)(),
143103
+ input: trimmed,
143104
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
143105
+ });
143106
+ this.touchSession(session);
143107
+ this.streamService.broadcast(session.id, {
143108
+ type: "session.snapshot",
143109
+ payload: this.toState(session)
143110
+ });
143037
143111
  return {
143038
- accepted: false,
143112
+ accepted: true,
143039
143113
  kind: "turn",
143040
- status: "error",
143041
- message: "Session is busy."
143114
+ status: "ok"
143042
143115
  };
143043
143116
  }
143044
- const trimmed = input.trim();
143045
- if (!trimmed) {
143046
- throw new common_1.BadRequestException("input is required");
143047
- }
143048
143117
  if (trimmed.startsWith("/")) {
143049
143118
  return this.runSlashCommand(session, trimmed);
143050
143119
  }
143051
143120
  return this.runCoreTurn(session, trimmed, trimmed);
143052
143121
  }
143122
+ removeQueuedInput(sessionId, queueId) {
143123
+ const session = this.requireSession(sessionId);
143124
+ const targetQueueId = queueId.trim();
143125
+ if (!targetQueueId) {
143126
+ throw new common_1.BadRequestException("queueId is required");
143127
+ }
143128
+ const next = session.queuedInputs.filter((item) => item.id !== targetQueueId);
143129
+ if (next.length === session.queuedInputs.length) {
143130
+ return { removed: false };
143131
+ }
143132
+ session.queuedInputs = next;
143133
+ this.touchSession(session);
143134
+ this.streamService.broadcast(session.id, {
143135
+ type: "session.snapshot",
143136
+ payload: this.toState(session)
143137
+ });
143138
+ return { removed: true };
143139
+ }
143140
+ sendQueuedInputNow(sessionId) {
143141
+ const session = this.requireSession(sessionId);
143142
+ if (session.queuedInputs.length === 0) {
143143
+ return { triggered: false };
143144
+ }
143145
+ if (session.status === "running") {
143146
+ this.cancelCurrentTurn(sessionId);
143147
+ return { triggered: true };
143148
+ }
143149
+ void this.drainQueuedInputs(session);
143150
+ return { triggered: true };
143151
+ }
143053
143152
  cancelCurrentTurn(sessionId) {
143054
143153
  const session = this.requireSession(sessionId);
143055
143154
  if (session.status === "running") {
@@ -143061,6 +143160,12 @@ var require_chat_service = __commonJS({
143061
143160
  async compactSession(sessionId) {
143062
143161
  const session = this.requireSession(sessionId);
143063
143162
  const result = await session.agentSession.compactHistory("manual");
143163
+ session.currentContextTokens = Math.max(0, result.afterTokens);
143164
+ this.touchSession(session);
143165
+ this.streamService.broadcast(session.id, {
143166
+ type: "session.snapshot",
143167
+ payload: this.toState(session)
143168
+ });
143064
143169
  this.streamService.broadcast(session.id, {
143065
143170
  type: "system.message",
143066
143171
  payload: {
@@ -143119,6 +143224,10 @@ var require_chat_service = __commonJS({
143119
143224
  title: "New Session",
143120
143225
  resetTurns: true
143121
143226
  });
143227
+ this.streamService.broadcast(session.id, {
143228
+ type: "session.snapshot",
143229
+ payload: this.toState(session)
143230
+ });
143122
143231
  this.sendSystemMessage(session, "New Session", "Started a fresh session.");
143123
143232
  return { accepted: true, kind: "command", status: "ok" };
143124
143233
  }
@@ -143206,9 +143315,41 @@ var require_chat_service = __commonJS({
143206
143315
  };
143207
143316
  }
143208
143317
  }
143318
+ async drainQueuedInputs(session) {
143319
+ if (session.status !== "idle")
143320
+ return;
143321
+ if (session.queueDraining)
143322
+ return;
143323
+ if (session.queuedInputs.length === 0)
143324
+ return;
143325
+ session.queueDraining = true;
143326
+ try {
143327
+ while (session.status === "idle" && session.queuedInputs.length > 0) {
143328
+ const next = session.queuedInputs.shift();
143329
+ if (!next)
143330
+ break;
143331
+ this.touchSession(session);
143332
+ this.streamService.broadcast(session.id, {
143333
+ type: "session.snapshot",
143334
+ payload: this.toState(session)
143335
+ });
143336
+ const input = next.input.trim();
143337
+ if (!input)
143338
+ continue;
143339
+ if (input.startsWith("/")) {
143340
+ await this.runSlashCommand(session, input);
143341
+ } else {
143342
+ await this.runCoreTurn(session, input, input);
143343
+ }
143344
+ }
143345
+ } finally {
143346
+ session.queueDraining = false;
143347
+ }
143348
+ }
143209
143349
  async recreateSessionRuntime(session, options) {
143210
143350
  this.resolvePendingApprovals(session, "deny");
143211
143351
  await session.agentSession.close();
143352
+ const config = await this.memoConfigService.load();
143212
143353
  if (options.providerName)
143213
143354
  session.providerName = options.providerName;
143214
143355
  if (options.model)
@@ -143222,6 +143363,11 @@ var require_chat_service = __commonJS({
143222
143363
  if (options.title) {
143223
143364
  session.title = options.title;
143224
143365
  }
143366
+ session.contextWindow = (0, core_1.resolveContextWindowForProvider)(config, {
143367
+ name: session.providerName,
143368
+ model: session.model
143369
+ });
143370
+ session.currentContextTokens = 0;
143225
143371
  if (options.resetTurns) {
143226
143372
  session.turn = 0;
143227
143373
  session.turns = [];
@@ -143275,6 +143421,10 @@ var require_chat_service = __commonJS({
143275
143421
  historyFilePath: input.historyFilePath,
143276
143422
  turns: [],
143277
143423
  pendingApprovals: /* @__PURE__ */ new Map(),
143424
+ currentContextTokens: 0,
143425
+ contextWindow: input.contextWindow,
143426
+ queuedInputs: [],
143427
+ queueDraining: false,
143278
143428
  agentSession: null
143279
143429
  };
143280
143430
  runtime.agentSession = await this.createCoreSession(runtime);
@@ -143325,10 +143475,11 @@ var require_chat_service = __commonJS({
143325
143475
  });
143326
143476
  },
143327
143477
  hooks: {
143328
- onTurnStart: ({ turn, input }) => {
143478
+ onTurnStart: ({ turn, input, promptTokens }) => {
143329
143479
  runtime.status = "running";
143330
143480
  runtime.activeTurn = turn;
143331
143481
  runtime.turn = Math.max(runtime.turn, turn);
143482
+ runtime.currentContextTokens = typeof promptTokens === "number" && Number.isFinite(promptTokens) ? Math.max(0, promptTokens) : runtime.currentContextTokens;
143332
143483
  const displayInput = runtime.nextInputDisplay ?? input;
143333
143484
  runtime.nextInputDisplay = void 0;
143334
143485
  const record = this.getOrCreateTurnRecord(runtime, turn);
@@ -143350,7 +143501,24 @@ var require_chat_service = __commonJS({
143350
143501
  type: "turn.start",
143351
143502
  payload: {
143352
143503
  turn,
143353
- input: displayInput
143504
+ input: displayInput,
143505
+ promptTokens
143506
+ }
143507
+ });
143508
+ },
143509
+ onContextUsage: ({ turn, step, phase, promptTokens, contextWindow, thresholdTokens, usagePercent }) => {
143510
+ runtime.currentContextTokens = Math.max(0, promptTokens);
143511
+ runtime.contextWindow = Math.max(0, contextWindow);
143512
+ this.streamService.broadcast(runtime.id, {
143513
+ type: "context.usage",
143514
+ payload: {
143515
+ turn,
143516
+ step,
143517
+ phase,
143518
+ promptTokens,
143519
+ contextWindow,
143520
+ thresholdTokens,
143521
+ usagePercent
143354
143522
  }
143355
143523
  });
143356
143524
  },
@@ -143416,6 +143584,7 @@ var require_chat_service = __commonJS({
143416
143584
  type: "session.snapshot",
143417
143585
  payload: this.toState(runtime)
143418
143586
  });
143587
+ void this.drainQueuedInputs(runtime);
143419
143588
  },
143420
143589
  onTitleGenerated: ({ title }) => {
143421
143590
  runtime.title = title;
@@ -143442,6 +143611,7 @@ var require_chat_service = __commonJS({
143442
143611
  sessionId: runtime.id,
143443
143612
  mode: "interactive",
143444
143613
  providerName: runtime.providerName,
143614
+ contextWindow: runtime.contextWindow,
143445
143615
  activeMcpServers: runtime.activeMcpServers,
143446
143616
  toolPermissionMode: runtime.toolPermissionMode,
143447
143617
  dangerous: runtime.toolPermissionMode === "full",
@@ -143516,7 +143686,10 @@ var require_chat_service = __commonJS({
143516
143686
  params: session.pendingApproval.params
143517
143687
  } : void 0,
143518
143688
  activeMcpServers: session.activeMcpServers,
143519
- toolPermissionMode: session.toolPermissionMode
143689
+ toolPermissionMode: session.toolPermissionMode,
143690
+ queuedInputs: session.queuedInputs.map((item) => ({ ...item })),
143691
+ currentContextTokens: session.currentContextTokens,
143692
+ contextWindow: session.contextWindow
143520
143693
  };
143521
143694
  }
143522
143695
  toSnapshot(session) {
@@ -144363,6 +144536,8 @@ var require_rpc_router_service = __commonJS({
144363
144536
  var workspaces_service_1 = require_workspaces_service();
144364
144537
  var session_runtime_registry_service_1 = require_session_runtime_registry_service();
144365
144538
  var ws_errors_1 = require_ws_errors();
144539
+ var TOOL_PERMISSION_MODES = ["none", "once", "full"];
144540
+ var APPROVAL_DECISIONS = ["once", "session", "deny"];
144366
144541
  function asObject(input) {
144367
144542
  if (!input || typeof input !== "object" || Array.isArray(input)) {
144368
144543
  return {};
@@ -144382,6 +144557,32 @@ var require_rpc_router_service = __commonJS({
144382
144557
  const trimmed = value.trim();
144383
144558
  return trimmed.length > 0 ? trimmed : void 0;
144384
144559
  }
144560
+ function asFiniteNumber(value) {
144561
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
144562
+ }
144563
+ function asStringArray(value) {
144564
+ if (!Array.isArray(value))
144565
+ return void 0;
144566
+ return value.filter((item) => typeof item === "string");
144567
+ }
144568
+ function requireTrimmedStringArray(input, key) {
144569
+ if (!Array.isArray(input[key])) {
144570
+ throw new ws_errors_1.WsRpcError("BAD_REQUEST", `${key} must be string[]`);
144571
+ }
144572
+ return input[key].filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
144573
+ }
144574
+ function asEnum(value, allowed) {
144575
+ if (typeof value !== "string")
144576
+ return void 0;
144577
+ return allowed.includes(value) ? value : void 0;
144578
+ }
144579
+ function requireEnum(value, allowed, message) {
144580
+ const parsed = asEnum(value, allowed);
144581
+ if (!parsed) {
144582
+ throw new ws_errors_1.WsRpcError("BAD_REQUEST", message);
144583
+ }
144584
+ return parsed;
144585
+ }
144385
144586
  var RpcRouterService = class RpcRouterService {
144386
144587
  sessionsService;
144387
144588
  chatService;
@@ -144389,6 +144590,7 @@ var require_rpc_router_service = __commonJS({
144389
144590
  skillsService;
144390
144591
  workspacesService;
144391
144592
  sessionRegistry;
144593
+ handlers;
144392
144594
  constructor(sessionsService, chatService, mcpService, skillsService, workspacesService, sessionRegistry) {
144393
144595
  this.sessionsService = sessionsService;
144394
144596
  this.chatService = chatService;
@@ -144396,199 +144598,140 @@ var require_rpc_router_service = __commonJS({
144396
144598
  this.skillsService = skillsService;
144397
144599
  this.workspacesService = workspacesService;
144398
144600
  this.sessionRegistry = sessionRegistry;
144601
+ this.handlers = {
144602
+ ...this.buildSessionHandlers(),
144603
+ ...this.buildChatHandlers(),
144604
+ ...this.buildMcpHandlers(),
144605
+ ...this.buildSkillHandlers(),
144606
+ ...this.buildWorkspaceHandlers()
144607
+ };
144399
144608
  }
144400
144609
  async dispatch(context, method, params) {
144401
- const input = asObject(params);
144402
- if (method === "sessions.list") {
144403
- return this.sessionsService.list(input);
144404
- }
144405
- if (method === "sessions.detail") {
144406
- const sessionId = requireString(input, "sessionId");
144407
- return this.sessionsService.getSessionDetail(sessionId);
144408
- }
144409
- if (method === "sessions.events") {
144410
- const sessionId = requireString(input, "sessionId");
144411
- return this.sessionsService.getSessionEvents(sessionId, input);
144412
- }
144413
- if (method === "sessions.remove") {
144414
- const sessionId = requireString(input, "sessionId");
144415
- return this.chatService.deleteSession(sessionId);
144610
+ const handler = this.handlers[method];
144611
+ if (!handler) {
144612
+ throw new ws_errors_1.WsRpcError("METHOD_NOT_FOUND", `Unknown method: ${method}`);
144416
144613
  }
144417
- if (method === "chat.session.create") {
144418
- const mode = input.toolPermissionMode;
144419
- return this.chatService.createSession({
144614
+ return handler(context, asObject(params));
144615
+ }
144616
+ buildSessionHandlers() {
144617
+ return {
144618
+ "sessions.list": (_context, input) => this.sessionsService.list(input),
144619
+ "sessions.detail": (_context, input) => this.sessionsService.getSessionDetail(requireString(input, "sessionId")),
144620
+ "sessions.events": (_context, input) => this.sessionsService.getSessionEvents(requireString(input, "sessionId"), input),
144621
+ "sessions.remove": (_context, input) => this.chatService.deleteSession(requireString(input, "sessionId"))
144622
+ };
144623
+ }
144624
+ buildChatHandlers() {
144625
+ return {
144626
+ "chat.session.create": (_context, input) => this.chatService.createSession({
144420
144627
  providerName: asString(input.providerName),
144421
144628
  workspaceId: asString(input.workspaceId),
144422
144629
  cwd: asString(input.cwd),
144423
- toolPermissionMode: mode === "none" || mode === "once" || mode === "full" ? mode : void 0,
144424
- activeMcpServers: Array.isArray(input.activeMcpServers) ? input.activeMcpServers.filter((item) => typeof item === "string") : void 0
144425
- });
144426
- }
144427
- if (method === "chat.providers.list") {
144428
- return this.chatService.listProviders();
144429
- }
144430
- if (method === "chat.runtimes.list") {
144431
- return this.chatService.listRuntimeBadges({
144630
+ toolPermissionMode: asEnum(input.toolPermissionMode, TOOL_PERMISSION_MODES),
144631
+ activeMcpServers: asStringArray(input.activeMcpServers)
144632
+ }),
144633
+ "chat.providers.list": () => this.chatService.listProviders(),
144634
+ "chat.runtimes.list": (_context, input) => this.chatService.listRuntimeBadges({
144432
144635
  workspaceId: asString(input.workspaceId)
144433
- });
144434
- }
144435
- if (method === "chat.session.state") {
144436
- const sessionId = requireString(input, "sessionId");
144437
- this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144438
- return this.chatService.getSessionState(sessionId);
144439
- }
144440
- if (method === "chat.session.attach") {
144441
- const sessionId = requireString(input, "sessionId");
144442
- this.sessionRegistry.claim(sessionId, context.connectionId);
144443
- try {
144444
- return await this.chatService.attachSession(sessionId);
144445
- } catch (error) {
144636
+ }),
144637
+ "chat.session.state": (context, input) => this.chatService.getSessionState(this.requireOwnedSession(input, context)),
144638
+ "chat.session.attach": async (context, input) => {
144639
+ const sessionId = requireString(input, "sessionId");
144640
+ this.sessionRegistry.claim(sessionId, context.connectionId);
144641
+ try {
144642
+ return await this.chatService.attachSession(sessionId);
144643
+ } catch (error) {
144644
+ this.sessionRegistry.release(sessionId, context.connectionId);
144645
+ throw error;
144646
+ }
144647
+ },
144648
+ "chat.session.close": (context, input) => {
144649
+ const sessionId = this.requireOwnedSession(input, context);
144650
+ const result = this.chatService.closeSession(sessionId);
144446
144651
  this.sessionRegistry.release(sessionId, context.connectionId);
144447
- throw error;
144448
- }
144449
- }
144450
- if (method === "chat.session.close") {
144451
- const sessionId = requireString(input, "sessionId");
144452
- this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144453
- const result = this.chatService.closeSession(sessionId);
144454
- this.sessionRegistry.release(sessionId, context.connectionId);
144455
- return result;
144456
- }
144457
- if (method === "chat.files.suggest") {
144458
- const sessionId = asString(input.sessionId);
144459
- if (sessionId) {
144460
- this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144461
- }
144462
- const query = typeof input.query === "string" ? input.query : "";
144463
- const limit = typeof input.limit === "number" && Number.isFinite(input.limit) ? input.limit : void 0;
144464
- return this.chatService.suggestFiles({
144465
- query,
144466
- limit,
144467
- sessionId,
144468
- workspaceId: asString(input.workspaceId)
144469
- });
144470
- }
144471
- if (method === "chat.input.submit") {
144472
- const sessionId = requireString(input, "sessionId");
144473
- const text = requireString(input, "input");
144474
- this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144475
- return this.chatService.submitInput(sessionId, text);
144476
- }
144477
- if (method === "chat.turn.cancel") {
144478
- const sessionId = requireString(input, "sessionId");
144479
- this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144480
- return this.chatService.cancelCurrentTurn(sessionId);
144481
- }
144482
- if (method === "chat.session.compact") {
144483
- const sessionId = requireString(input, "sessionId");
144484
- this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144485
- return this.chatService.compactSession(sessionId);
144486
- }
144487
- if (method === "chat.approval.respond") {
144488
- const sessionId = requireString(input, "sessionId");
144489
- const fingerprint = requireString(input, "fingerprint");
144490
- const decision = input.decision;
144491
- if (decision !== "once" && decision !== "session" && decision !== "deny") {
144492
- throw new ws_errors_1.WsRpcError("BAD_REQUEST", "decision must be once | session | deny");
144493
- }
144494
- this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144495
- return this.chatService.applyApprovalDecision(sessionId, fingerprint, decision);
144496
- }
144497
- if (method === "mcp.servers.list") {
144498
- return this.mcpService.list();
144499
- }
144500
- if (method === "mcp.servers.get") {
144501
- return this.mcpService.get(requireString(input, "name"));
144502
- }
144503
- if (method === "mcp.servers.create") {
144504
- const name = requireString(input, "name");
144505
- return this.mcpService.create(name, input.config);
144506
- }
144507
- if (method === "mcp.servers.update") {
144508
- const name = requireString(input, "name");
144509
- return this.mcpService.update(name, input.config);
144510
- }
144511
- if (method === "mcp.servers.remove") {
144512
- return this.mcpService.remove(requireString(input, "name"));
144513
- }
144514
- if (method === "mcp.servers.login") {
144515
- const name = requireString(input, "name");
144516
- const scopes = Array.isArray(input.scopes) ? input.scopes.filter((item) => typeof item === "string") : void 0;
144517
- return this.mcpService.login(name, scopes);
144518
- }
144519
- if (method === "mcp.servers.logout") {
144520
- return this.mcpService.logout(requireString(input, "name"));
144521
- }
144522
- if (method === "mcp.active.set") {
144523
- if (!Array.isArray(input.names)) {
144524
- throw new ws_errors_1.WsRpcError("BAD_REQUEST", "names must be string[]");
144525
- }
144526
- const names = input.names.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
144527
- return this.mcpService.setActive(names);
144528
- }
144529
- if (method === "skills.list") {
144530
- return this.skillsService.list({
144652
+ return result;
144653
+ },
144654
+ "chat.files.suggest": (context, input) => {
144655
+ const sessionId = asString(input.sessionId);
144656
+ if (sessionId) {
144657
+ this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144658
+ }
144659
+ return this.chatService.suggestFiles({
144660
+ query: typeof input.query === "string" ? input.query : "",
144661
+ limit: asFiniteNumber(input.limit),
144662
+ sessionId,
144663
+ workspaceId: asString(input.workspaceId)
144664
+ });
144665
+ },
144666
+ "chat.input.submit": (context, input) => this.chatService.submitInput(this.requireOwnedSession(input, context), requireString(input, "input")),
144667
+ "chat.queue.remove": (context, input) => this.chatService.removeQueuedInput(this.requireOwnedSession(input, context), requireString(input, "queueId")),
144668
+ "chat.queue.send_now": (context, input) => this.chatService.sendQueuedInputNow(this.requireOwnedSession(input, context)),
144669
+ "chat.turn.cancel": (context, input) => this.chatService.cancelCurrentTurn(this.requireOwnedSession(input, context)),
144670
+ "chat.session.compact": (context, input) => this.chatService.compactSession(this.requireOwnedSession(input, context)),
144671
+ "chat.approval.respond": (context, input) => this.chatService.applyApprovalDecision(this.requireOwnedSession(input, context), requireString(input, "fingerprint"), requireEnum(input.decision, APPROVAL_DECISIONS, "decision must be once | session | deny"))
144672
+ };
144673
+ }
144674
+ buildMcpHandlers() {
144675
+ return {
144676
+ "mcp.servers.list": () => this.mcpService.list(),
144677
+ "mcp.servers.get": (_context, input) => this.mcpService.get(requireString(input, "name")),
144678
+ "mcp.servers.create": (_context, input) => this.mcpService.create(requireString(input, "name"), input.config),
144679
+ "mcp.servers.update": (_context, input) => this.mcpService.update(requireString(input, "name"), input.config),
144680
+ "mcp.servers.remove": (_context, input) => this.mcpService.remove(requireString(input, "name")),
144681
+ "mcp.servers.login": (_context, input) => this.mcpService.login(requireString(input, "name"), asStringArray(input.scopes)),
144682
+ "mcp.servers.logout": (_context, input) => this.mcpService.logout(requireString(input, "name")),
144683
+ "mcp.active.set": (_context, input) => this.mcpService.setActive(requireTrimmedStringArray(input, "names"))
144684
+ };
144685
+ }
144686
+ buildSkillHandlers() {
144687
+ return {
144688
+ "skills.list": (_context, input) => this.skillsService.list({
144531
144689
  scope: input.scope,
144532
144690
  q: input.q,
144533
144691
  workspaceId: input.workspaceId
144534
- });
144535
- }
144536
- if (method === "skills.get") {
144537
- return this.skillsService.get(requireString(input, "id"));
144538
- }
144539
- if (method === "skills.create") {
144540
- return this.skillsService.create({
144692
+ }),
144693
+ "skills.get": (_context, input) => this.skillsService.get(requireString(input, "id")),
144694
+ "skills.create": (_context, input) => this.skillsService.create({
144541
144695
  scope: input.scope,
144542
144696
  name: input.name,
144543
144697
  description: input.description,
144544
144698
  content: input.content,
144545
144699
  workspaceId: input.workspaceId
144546
- });
144547
- }
144548
- if (method === "skills.update") {
144549
- return this.skillsService.update(requireString(input, "id"), {
144700
+ }),
144701
+ "skills.update": (_context, input) => this.skillsService.update(requireString(input, "id"), {
144550
144702
  description: input.description,
144551
144703
  content: input.content
144552
- });
144553
- }
144554
- if (method === "skills.remove") {
144555
- return this.skillsService.remove(requireString(input, "id"));
144556
- }
144557
- if (method === "skills.active.set") {
144558
- if (!Array.isArray(input.ids)) {
144559
- throw new ws_errors_1.WsRpcError("BAD_REQUEST", "ids must be string[]");
144560
- }
144561
- const ids = input.ids.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
144562
- return this.skillsService.setActive(ids);
144563
- }
144564
- if (method === "workspace.list") {
144565
- return this.workspacesService.list();
144566
- }
144567
- if (method === "workspace.add") {
144568
- return this.workspacesService.add({
144704
+ }),
144705
+ "skills.remove": (_context, input) => this.skillsService.remove(requireString(input, "id")),
144706
+ "skills.active.set": (_context, input) => this.skillsService.setActive(requireTrimmedStringArray(input, "ids"))
144707
+ };
144708
+ }
144709
+ buildWorkspaceHandlers() {
144710
+ return {
144711
+ "workspace.list": () => this.workspacesService.list(),
144712
+ "workspace.add": (_context, input) => this.workspacesService.add({
144569
144713
  cwd: input.cwd,
144570
144714
  name: input.name
144571
- });
144572
- }
144573
- if (method === "workspace.update") {
144574
- return this.workspacesService.update(requireString(input, "workspaceId"), {
144715
+ }),
144716
+ "workspace.update": (_context, input) => this.workspacesService.update(requireString(input, "workspaceId"), {
144575
144717
  name: input.name
144576
- });
144577
- }
144578
- if (method === "workspace.remove") {
144579
- const workspaceId = requireString(input, "workspaceId");
144580
- const sessionsResult = await this.sessionsService.removeSessionsByWorkspace(workspaceId);
144581
- const workspaceResult = await this.workspacesService.remove(workspaceId);
144582
- return {
144583
- ...workspaceResult,
144584
- deletedSessions: sessionsResult.deletedSessions
144585
- };
144586
- }
144587
- if (method === "workspace.fs.list") {
144588
- const path = asString(input.path);
144589
- return this.workspacesService.listDirectories(path);
144590
- }
144591
- throw new ws_errors_1.WsRpcError("METHOD_NOT_FOUND", `Unknown method: ${method}`);
144718
+ }),
144719
+ "workspace.remove": async (_context, input) => {
144720
+ const workspaceId = requireString(input, "workspaceId");
144721
+ const sessionsResult = await this.sessionsService.removeSessionsByWorkspace(workspaceId);
144722
+ const workspaceResult = await this.workspacesService.remove(workspaceId);
144723
+ return {
144724
+ ...workspaceResult,
144725
+ deletedSessions: sessionsResult.deletedSessions
144726
+ };
144727
+ },
144728
+ "workspace.fs.list": (_context, input) => this.workspacesService.listDirectories(asString(input.path))
144729
+ };
144730
+ }
144731
+ requireOwnedSession(input, context) {
144732
+ const sessionId = requireString(input, "sessionId");
144733
+ this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144734
+ return sessionId;
144592
144735
  }
144593
144736
  };
144594
144737
  exports2.RpcRouterService = RpcRouterService;
@@ -144952,6 +145095,12 @@ var require_ws_gateway_service = __commonJS({
144952
145095
  data: { sessionId, ...frame.payload }
144953
145096
  };
144954
145097
  }
145098
+ if (frame.type === "context.usage") {
145099
+ return {
145100
+ topic: "chat.context.usage",
145101
+ data: { sessionId, ...frame.payload }
145102
+ };
145103
+ }
144955
145104
  if (frame.type === "turn.final") {
144956
145105
  return {
144957
145106
  topic: "chat.turn.final",