@memo-code/memo 0.8.8 → 0.8.10

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 (58) hide show
  1. package/README.md +1 -0
  2. package/dist/web/server/main.cjs +286 -184
  3. package/dist/web/ui/assets/{_baseUniq-kMerwpPq.js → _baseUniq-DltOgNCU.js} +1 -1
  4. package/dist/web/ui/assets/{arc-BulUmzON.js → arc-CsVqK9Lb.js} +1 -1
  5. package/dist/web/ui/assets/{architectureDiagram-VXUJARFQ-CkXEUKP9.js → architectureDiagram-VXUJARFQ-BkwnFF8Y.js} +1 -1
  6. package/dist/web/ui/assets/{blockDiagram-VD42YOAC-DXcW7NDi.js → blockDiagram-VD42YOAC-CA94VAjC.js} +1 -1
  7. package/dist/web/ui/assets/{c4Diagram-YG6GDRKO-QrajWDN7.js → c4Diagram-YG6GDRKO-C0WsU_nq.js} +1 -1
  8. package/dist/web/ui/assets/channel-CM-YZjf5.js +1 -0
  9. package/dist/web/ui/assets/{chunk-4BX2VUAB-CzB06K-m.js → chunk-4BX2VUAB-DglUTwZW.js} +1 -1
  10. package/dist/web/ui/assets/{chunk-55IACEB6-e5LXEkOB.js → chunk-55IACEB6-DOOGSRjL.js} +1 -1
  11. package/dist/web/ui/assets/{chunk-B4BG7PRW-YVg5pH4D.js → chunk-B4BG7PRW-w6hF0Zcb.js} +1 -1
  12. package/dist/web/ui/assets/{chunk-DI55MBZ5-Carl7-xm.js → chunk-DI55MBZ5-C0Vb_bLp.js} +1 -1
  13. package/dist/web/ui/assets/{chunk-FMBD7UC4-06dN5sRQ.js → chunk-FMBD7UC4-Ctx35DPt.js} +1 -1
  14. package/dist/web/ui/assets/{chunk-QN33PNHL-Cl3zdZ7K.js → chunk-QN33PNHL-DtVZR3nr.js} +1 -1
  15. package/dist/web/ui/assets/{chunk-QZHKN3VN-CDOQBeOx.js → chunk-QZHKN3VN-Ch_jdCsH.js} +1 -1
  16. package/dist/web/ui/assets/{chunk-TZMSLE5B-DWeaVk_X.js → chunk-TZMSLE5B-BePFLhiS.js} +1 -1
  17. package/dist/web/ui/assets/classDiagram-2ON5EDUG-5ACEbCYo.js +1 -0
  18. package/dist/web/ui/assets/classDiagram-v2-WZHVMYZB-5ACEbCYo.js +1 -0
  19. package/dist/web/ui/assets/clone-DIMUORAQ.js +1 -0
  20. package/dist/web/ui/assets/{code-block-OCS4YCEC-DmdcLUqO.js → code-block-OCS4YCEC-B7AH2kqV.js} +1 -1
  21. package/dist/web/ui/assets/{cose-bilkent-S5V4N54A-CDHjR7aY.js → cose-bilkent-S5V4N54A-BBRhnVZA.js} +1 -1
  22. package/dist/web/ui/assets/{dagre-6UL2VRFP-BvAH8ysH.js → dagre-6UL2VRFP-B6v_Z71G.js} +1 -1
  23. package/dist/web/ui/assets/{diagram-PSM6KHXK-CKk6ZAaV.js → diagram-PSM6KHXK-Ce-iOIx7.js} +1 -1
  24. package/dist/web/ui/assets/{diagram-QEK2KX5R-Ewj4cQfm.js → diagram-QEK2KX5R-DXcCGip6.js} +1 -1
  25. package/dist/web/ui/assets/{diagram-S2PKOQOG-B-i75ELR.js → diagram-S2PKOQOG-DVADDX-W.js} +1 -1
  26. package/dist/web/ui/assets/{erDiagram-Q2GNP2WA-BMe1fyY7.js → erDiagram-Q2GNP2WA-C8AlUD42.js} +1 -1
  27. package/dist/web/ui/assets/{flowDiagram-NV44I4VS-DTOpgGDg.js → flowDiagram-NV44I4VS-D7Sf06Qi.js} +1 -1
  28. package/dist/web/ui/assets/{ganttDiagram-JELNMOA3-DdrlqPr-.js → ganttDiagram-JELNMOA3-DC1ZI7BI.js} +1 -1
  29. package/dist/web/ui/assets/{gitGraphDiagram-NY62KEGX-DOpYoqH8.js → gitGraphDiagram-NY62KEGX-BfZ1rfoJ.js} +1 -1
  30. package/dist/web/ui/assets/{graph-DNq5-vTB.js → graph-BQpF6Nij.js} +1 -1
  31. package/dist/web/ui/assets/index-CHzX9Qy5.js +441 -0
  32. package/dist/web/ui/assets/index-pRZWTg6V.css +1 -0
  33. package/dist/web/ui/assets/{infoDiagram-WHAUD3N6-D3Wwcqmd.js → infoDiagram-WHAUD3N6-DpMWPNO4.js} +1 -1
  34. package/dist/web/ui/assets/{journeyDiagram-XKPGCS4Q-BKDrlvIB.js → journeyDiagram-XKPGCS4Q-C1NnAV9d.js} +1 -1
  35. package/dist/web/ui/assets/{kanban-definition-3W4ZIXB7-Dj6sXTJI.js → kanban-definition-3W4ZIXB7-Dwx-vzmF.js} +1 -1
  36. package/dist/web/ui/assets/{layout-4XvXY0m8.js → layout-pecnt6B2.js} +1 -1
  37. package/dist/web/ui/assets/{linear-CUPS720l.js → linear-McmfKs1N.js} +1 -1
  38. package/dist/web/ui/assets/{min-KWXImKVx.js → min-E1T_dxKi.js} +1 -1
  39. package/dist/web/ui/assets/{mindmap-definition-VGOIOE7T-D9ty43l7.js → mindmap-definition-VGOIOE7T-EDAtU3iP.js} +1 -1
  40. package/dist/web/ui/assets/{pieDiagram-ADFJNKIX-BlMxxSdO.js → pieDiagram-ADFJNKIX-Cn-bUvlG.js} +1 -1
  41. package/dist/web/ui/assets/{quadrantDiagram-AYHSOK5B-Cam0yXvU.js → quadrantDiagram-AYHSOK5B-rDZ_wUTY.js} +1 -1
  42. package/dist/web/ui/assets/{requirementDiagram-UZGBJVZJ-D_yH3UAt.js → requirementDiagram-UZGBJVZJ-B8HT8i6v.js} +1 -1
  43. package/dist/web/ui/assets/{sankeyDiagram-TZEHDZUN-Dm93-uJ1.js → sankeyDiagram-TZEHDZUN-DQNSFlyU.js} +1 -1
  44. package/dist/web/ui/assets/{sequenceDiagram-WL72ISMW-D6C4PHTO.js → sequenceDiagram-WL72ISMW-CtGDTINH.js} +1 -1
  45. package/dist/web/ui/assets/{stateDiagram-FKZM4ZOC-msXCFM-o.js → stateDiagram-FKZM4ZOC-vyJFWQYy.js} +1 -1
  46. package/dist/web/ui/assets/stateDiagram-v2-4FDKWEC3-CrSesN6R.js +1 -0
  47. package/dist/web/ui/assets/{timeline-definition-IT6M3QCI-OhdHqGpr.js → timeline-definition-IT6M3QCI-Bd8FOmSP.js} +1 -1
  48. package/dist/web/ui/assets/{treemap-KMMF4GRG-BBa7Tuyx.js → treemap-KMMF4GRG-DH-VqRiC.js} +1 -1
  49. package/dist/web/ui/assets/{xychartDiagram-PRI3JC2R-CwWrUftO.js → xychartDiagram-PRI3JC2R-BQK9j5Ts.js} +1 -1
  50. package/dist/web/ui/index.html +2 -2
  51. package/package.json +1 -1
  52. package/dist/web/ui/assets/channel-DcFyxfzD.js +0 -1
  53. package/dist/web/ui/assets/classDiagram-2ON5EDUG-DmyEwwBr.js +0 -1
  54. package/dist/web/ui/assets/classDiagram-v2-WZHVMYZB-DmyEwwBr.js +0 -1
  55. package/dist/web/ui/assets/clone-DZ5SCP6k.js +0 -1
  56. package/dist/web/ui/assets/index-B3TLzmaO.js +0 -441
  57. package/dist/web/ui/assets/index-BSSBc2rS.css +0 -1
  58. package/dist/web/ui/assets/stateDiagram-v2-4FDKWEC3-BxRi32Am.js +0 -1
package/README.md CHANGED
@@ -84,6 +84,7 @@ memo web --host 127.0.0.1 --port 5494 --open
84
84
  - Sidebar includes dedicated entries for `MCP Servers` and `Skills`:
85
85
  - MCP: create/edit/remove/login/logout and active toggles.
86
86
  - Skills: create/delete, detail preview, and active toggles.
87
+ - Web chat input panel shows live context usage percentage.
87
88
 
88
89
  ## Configuration
89
90
 
@@ -142776,6 +142776,7 @@ var require_chat_service = __commonJS({
142776
142776
  var stream_service_1 = require_stream_service();
142777
142777
  var workspaces_service_1 = require_workspaces_service();
142778
142778
  var MAX_LIVE_SESSIONS = 20;
142779
+ var MAX_QUEUED_INPUTS = 3;
142779
142780
  function normalizeMode(value) {
142780
142781
  if (value === "none" || value === "once" || value === "full")
142781
142782
  return value;
@@ -142847,6 +142848,7 @@ var require_chat_service = __commonJS({
142847
142848
  await this.workspacesService.touchLastUsed(workspace.id);
142848
142849
  const config = await this.memoConfigService.load();
142849
142850
  const provider = this.selectProvider(config.providers, input.providerName, config.current_provider);
142851
+ const contextWindow = (0, core_1.resolveContextWindowForProvider)(config, provider);
142850
142852
  const sessionId = (0, node_crypto_1.randomUUID)();
142851
142853
  const runtime = await this.createRuntime({
142852
142854
  id: sessionId,
@@ -142858,7 +142860,8 @@ var require_chat_service = __commonJS({
142858
142860
  cwd: workspace.cwd,
142859
142861
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
142860
142862
  activeMcpServers: input.activeMcpServers && input.activeMcpServers.length > 0 ? input.activeMcpServers : config.active_mcp_servers,
142861
- toolPermissionMode: normalizeMode(input.toolPermissionMode)
142863
+ toolPermissionMode: normalizeMode(input.toolPermissionMode),
142864
+ contextWindow
142862
142865
  });
142863
142866
  this.sessions.set(runtime.id, runtime);
142864
142867
  this.touchSession(runtime);
@@ -142878,6 +142881,7 @@ var require_chat_service = __commonJS({
142878
142881
  await this.workspacesService.touchLastUsed(workspace.id);
142879
142882
  const config = await this.memoConfigService.load();
142880
142883
  const provider = this.selectProvider(config.providers, void 0, config.current_provider);
142884
+ const contextWindow = (0, core_1.resolveContextWindowForProvider)(config, provider);
142881
142885
  const historyMessages = [];
142882
142886
  const turns = [];
142883
142887
  for (const turn of detail.turns) {
@@ -142910,7 +142914,8 @@ var require_chat_service = __commonJS({
142910
142914
  startedAt: detail.date.startedAt,
142911
142915
  activeMcpServers: config.active_mcp_servers,
142912
142916
  toolPermissionMode: "once",
142913
- historyFilePath: detail.filePath
142917
+ historyFilePath: detail.filePath,
142918
+ contextWindow
142914
142919
  });
142915
142920
  const system = runtime.agentSession.history[0];
142916
142921
  runtime.agentSession.history = system ? [system, ...historyMessages] : [...historyMessages];
@@ -143033,23 +143038,70 @@ var require_chat_service = __commonJS({
143033
143038
  }
143034
143039
  async submitInput(sessionId, input) {
143035
143040
  const session = this.requireSession(sessionId);
143041
+ const trimmed = input.trim();
143042
+ if (!trimmed) {
143043
+ throw new common_1.BadRequestException("input is required");
143044
+ }
143036
143045
  if (session.status === "running") {
143046
+ if (session.queuedInputs.length >= MAX_QUEUED_INPUTS) {
143047
+ return {
143048
+ accepted: false,
143049
+ kind: "turn",
143050
+ status: "error",
143051
+ message: `Queue is full (max ${MAX_QUEUED_INPUTS}).`
143052
+ };
143053
+ }
143054
+ session.queuedInputs.push({
143055
+ id: (0, node_crypto_1.randomUUID)(),
143056
+ input: trimmed,
143057
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
143058
+ });
143059
+ this.touchSession(session);
143060
+ this.streamService.broadcast(session.id, {
143061
+ type: "session.snapshot",
143062
+ payload: this.toState(session)
143063
+ });
143037
143064
  return {
143038
- accepted: false,
143065
+ accepted: true,
143039
143066
  kind: "turn",
143040
- status: "error",
143041
- message: "Session is busy."
143067
+ status: "ok"
143042
143068
  };
143043
143069
  }
143044
- const trimmed = input.trim();
143045
- if (!trimmed) {
143046
- throw new common_1.BadRequestException("input is required");
143047
- }
143048
143070
  if (trimmed.startsWith("/")) {
143049
143071
  return this.runSlashCommand(session, trimmed);
143050
143072
  }
143051
143073
  return this.runCoreTurn(session, trimmed, trimmed);
143052
143074
  }
143075
+ removeQueuedInput(sessionId, queueId) {
143076
+ const session = this.requireSession(sessionId);
143077
+ const targetQueueId = queueId.trim();
143078
+ if (!targetQueueId) {
143079
+ throw new common_1.BadRequestException("queueId is required");
143080
+ }
143081
+ const next = session.queuedInputs.filter((item) => item.id !== targetQueueId);
143082
+ if (next.length === session.queuedInputs.length) {
143083
+ return { removed: false };
143084
+ }
143085
+ session.queuedInputs = next;
143086
+ this.touchSession(session);
143087
+ this.streamService.broadcast(session.id, {
143088
+ type: "session.snapshot",
143089
+ payload: this.toState(session)
143090
+ });
143091
+ return { removed: true };
143092
+ }
143093
+ sendQueuedInputNow(sessionId) {
143094
+ const session = this.requireSession(sessionId);
143095
+ if (session.queuedInputs.length === 0) {
143096
+ return { triggered: false };
143097
+ }
143098
+ if (session.status === "running") {
143099
+ this.cancelCurrentTurn(sessionId);
143100
+ return { triggered: true };
143101
+ }
143102
+ void this.drainQueuedInputs(session);
143103
+ return { triggered: true };
143104
+ }
143053
143105
  cancelCurrentTurn(sessionId) {
143054
143106
  const session = this.requireSession(sessionId);
143055
143107
  if (session.status === "running") {
@@ -143061,6 +143113,12 @@ var require_chat_service = __commonJS({
143061
143113
  async compactSession(sessionId) {
143062
143114
  const session = this.requireSession(sessionId);
143063
143115
  const result = await session.agentSession.compactHistory("manual");
143116
+ session.currentContextTokens = Math.max(0, result.afterTokens);
143117
+ this.touchSession(session);
143118
+ this.streamService.broadcast(session.id, {
143119
+ type: "session.snapshot",
143120
+ payload: this.toState(session)
143121
+ });
143064
143122
  this.streamService.broadcast(session.id, {
143065
143123
  type: "system.message",
143066
143124
  payload: {
@@ -143119,6 +143177,10 @@ var require_chat_service = __commonJS({
143119
143177
  title: "New Session",
143120
143178
  resetTurns: true
143121
143179
  });
143180
+ this.streamService.broadcast(session.id, {
143181
+ type: "session.snapshot",
143182
+ payload: this.toState(session)
143183
+ });
143122
143184
  this.sendSystemMessage(session, "New Session", "Started a fresh session.");
143123
143185
  return { accepted: true, kind: "command", status: "ok" };
143124
143186
  }
@@ -143206,9 +143268,41 @@ var require_chat_service = __commonJS({
143206
143268
  };
143207
143269
  }
143208
143270
  }
143271
+ async drainQueuedInputs(session) {
143272
+ if (session.status !== "idle")
143273
+ return;
143274
+ if (session.queueDraining)
143275
+ return;
143276
+ if (session.queuedInputs.length === 0)
143277
+ return;
143278
+ session.queueDraining = true;
143279
+ try {
143280
+ while (session.status === "idle" && session.queuedInputs.length > 0) {
143281
+ const next = session.queuedInputs.shift();
143282
+ if (!next)
143283
+ break;
143284
+ this.touchSession(session);
143285
+ this.streamService.broadcast(session.id, {
143286
+ type: "session.snapshot",
143287
+ payload: this.toState(session)
143288
+ });
143289
+ const input = next.input.trim();
143290
+ if (!input)
143291
+ continue;
143292
+ if (input.startsWith("/")) {
143293
+ await this.runSlashCommand(session, input);
143294
+ } else {
143295
+ await this.runCoreTurn(session, input, input);
143296
+ }
143297
+ }
143298
+ } finally {
143299
+ session.queueDraining = false;
143300
+ }
143301
+ }
143209
143302
  async recreateSessionRuntime(session, options) {
143210
143303
  this.resolvePendingApprovals(session, "deny");
143211
143304
  await session.agentSession.close();
143305
+ const config = await this.memoConfigService.load();
143212
143306
  if (options.providerName)
143213
143307
  session.providerName = options.providerName;
143214
143308
  if (options.model)
@@ -143222,6 +143316,11 @@ var require_chat_service = __commonJS({
143222
143316
  if (options.title) {
143223
143317
  session.title = options.title;
143224
143318
  }
143319
+ session.contextWindow = (0, core_1.resolveContextWindowForProvider)(config, {
143320
+ name: session.providerName,
143321
+ model: session.model
143322
+ });
143323
+ session.currentContextTokens = 0;
143225
143324
  if (options.resetTurns) {
143226
143325
  session.turn = 0;
143227
143326
  session.turns = [];
@@ -143275,6 +143374,10 @@ var require_chat_service = __commonJS({
143275
143374
  historyFilePath: input.historyFilePath,
143276
143375
  turns: [],
143277
143376
  pendingApprovals: /* @__PURE__ */ new Map(),
143377
+ currentContextTokens: 0,
143378
+ contextWindow: input.contextWindow,
143379
+ queuedInputs: [],
143380
+ queueDraining: false,
143278
143381
  agentSession: null
143279
143382
  };
143280
143383
  runtime.agentSession = await this.createCoreSession(runtime);
@@ -143325,10 +143428,11 @@ var require_chat_service = __commonJS({
143325
143428
  });
143326
143429
  },
143327
143430
  hooks: {
143328
- onTurnStart: ({ turn, input }) => {
143431
+ onTurnStart: ({ turn, input, promptTokens }) => {
143329
143432
  runtime.status = "running";
143330
143433
  runtime.activeTurn = turn;
143331
143434
  runtime.turn = Math.max(runtime.turn, turn);
143435
+ runtime.currentContextTokens = typeof promptTokens === "number" && Number.isFinite(promptTokens) ? Math.max(0, promptTokens) : runtime.currentContextTokens;
143332
143436
  const displayInput = runtime.nextInputDisplay ?? input;
143333
143437
  runtime.nextInputDisplay = void 0;
143334
143438
  const record = this.getOrCreateTurnRecord(runtime, turn);
@@ -143350,7 +143454,24 @@ var require_chat_service = __commonJS({
143350
143454
  type: "turn.start",
143351
143455
  payload: {
143352
143456
  turn,
143353
- input: displayInput
143457
+ input: displayInput,
143458
+ promptTokens
143459
+ }
143460
+ });
143461
+ },
143462
+ onContextUsage: ({ turn, step, phase, promptTokens, contextWindow, thresholdTokens, usagePercent }) => {
143463
+ runtime.currentContextTokens = Math.max(0, promptTokens);
143464
+ runtime.contextWindow = Math.max(0, contextWindow);
143465
+ this.streamService.broadcast(runtime.id, {
143466
+ type: "context.usage",
143467
+ payload: {
143468
+ turn,
143469
+ step,
143470
+ phase,
143471
+ promptTokens,
143472
+ contextWindow,
143473
+ thresholdTokens,
143474
+ usagePercent
143354
143475
  }
143355
143476
  });
143356
143477
  },
@@ -143416,6 +143537,7 @@ var require_chat_service = __commonJS({
143416
143537
  type: "session.snapshot",
143417
143538
  payload: this.toState(runtime)
143418
143539
  });
143540
+ void this.drainQueuedInputs(runtime);
143419
143541
  },
143420
143542
  onTitleGenerated: ({ title }) => {
143421
143543
  runtime.title = title;
@@ -143442,6 +143564,7 @@ var require_chat_service = __commonJS({
143442
143564
  sessionId: runtime.id,
143443
143565
  mode: "interactive",
143444
143566
  providerName: runtime.providerName,
143567
+ contextWindow: runtime.contextWindow,
143445
143568
  activeMcpServers: runtime.activeMcpServers,
143446
143569
  toolPermissionMode: runtime.toolPermissionMode,
143447
143570
  dangerous: runtime.toolPermissionMode === "full",
@@ -143516,7 +143639,10 @@ var require_chat_service = __commonJS({
143516
143639
  params: session.pendingApproval.params
143517
143640
  } : void 0,
143518
143641
  activeMcpServers: session.activeMcpServers,
143519
- toolPermissionMode: session.toolPermissionMode
143642
+ toolPermissionMode: session.toolPermissionMode,
143643
+ queuedInputs: session.queuedInputs.map((item) => ({ ...item })),
143644
+ currentContextTokens: session.currentContextTokens,
143645
+ contextWindow: session.contextWindow
143520
143646
  };
143521
143647
  }
143522
143648
  toSnapshot(session) {
@@ -144363,6 +144489,8 @@ var require_rpc_router_service = __commonJS({
144363
144489
  var workspaces_service_1 = require_workspaces_service();
144364
144490
  var session_runtime_registry_service_1 = require_session_runtime_registry_service();
144365
144491
  var ws_errors_1 = require_ws_errors();
144492
+ var TOOL_PERMISSION_MODES = ["none", "once", "full"];
144493
+ var APPROVAL_DECISIONS = ["once", "session", "deny"];
144366
144494
  function asObject(input) {
144367
144495
  if (!input || typeof input !== "object" || Array.isArray(input)) {
144368
144496
  return {};
@@ -144382,6 +144510,32 @@ var require_rpc_router_service = __commonJS({
144382
144510
  const trimmed = value.trim();
144383
144511
  return trimmed.length > 0 ? trimmed : void 0;
144384
144512
  }
144513
+ function asFiniteNumber(value) {
144514
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
144515
+ }
144516
+ function asStringArray(value) {
144517
+ if (!Array.isArray(value))
144518
+ return void 0;
144519
+ return value.filter((item) => typeof item === "string");
144520
+ }
144521
+ function requireTrimmedStringArray(input, key) {
144522
+ if (!Array.isArray(input[key])) {
144523
+ throw new ws_errors_1.WsRpcError("BAD_REQUEST", `${key} must be string[]`);
144524
+ }
144525
+ return input[key].filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
144526
+ }
144527
+ function asEnum(value, allowed) {
144528
+ if (typeof value !== "string")
144529
+ return void 0;
144530
+ return allowed.includes(value) ? value : void 0;
144531
+ }
144532
+ function requireEnum(value, allowed, message) {
144533
+ const parsed = asEnum(value, allowed);
144534
+ if (!parsed) {
144535
+ throw new ws_errors_1.WsRpcError("BAD_REQUEST", message);
144536
+ }
144537
+ return parsed;
144538
+ }
144385
144539
  var RpcRouterService = class RpcRouterService {
144386
144540
  sessionsService;
144387
144541
  chatService;
@@ -144389,6 +144543,7 @@ var require_rpc_router_service = __commonJS({
144389
144543
  skillsService;
144390
144544
  workspacesService;
144391
144545
  sessionRegistry;
144546
+ handlers;
144392
144547
  constructor(sessionsService, chatService, mcpService, skillsService, workspacesService, sessionRegistry) {
144393
144548
  this.sessionsService = sessionsService;
144394
144549
  this.chatService = chatService;
@@ -144396,199 +144551,140 @@ var require_rpc_router_service = __commonJS({
144396
144551
  this.skillsService = skillsService;
144397
144552
  this.workspacesService = workspacesService;
144398
144553
  this.sessionRegistry = sessionRegistry;
144554
+ this.handlers = {
144555
+ ...this.buildSessionHandlers(),
144556
+ ...this.buildChatHandlers(),
144557
+ ...this.buildMcpHandlers(),
144558
+ ...this.buildSkillHandlers(),
144559
+ ...this.buildWorkspaceHandlers()
144560
+ };
144399
144561
  }
144400
144562
  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);
144563
+ const handler = this.handlers[method];
144564
+ if (!handler) {
144565
+ throw new ws_errors_1.WsRpcError("METHOD_NOT_FOUND", `Unknown method: ${method}`);
144416
144566
  }
144417
- if (method === "chat.session.create") {
144418
- const mode = input.toolPermissionMode;
144419
- return this.chatService.createSession({
144567
+ return handler(context, asObject(params));
144568
+ }
144569
+ buildSessionHandlers() {
144570
+ return {
144571
+ "sessions.list": (_context, input) => this.sessionsService.list(input),
144572
+ "sessions.detail": (_context, input) => this.sessionsService.getSessionDetail(requireString(input, "sessionId")),
144573
+ "sessions.events": (_context, input) => this.sessionsService.getSessionEvents(requireString(input, "sessionId"), input),
144574
+ "sessions.remove": (_context, input) => this.chatService.deleteSession(requireString(input, "sessionId"))
144575
+ };
144576
+ }
144577
+ buildChatHandlers() {
144578
+ return {
144579
+ "chat.session.create": (_context, input) => this.chatService.createSession({
144420
144580
  providerName: asString(input.providerName),
144421
144581
  workspaceId: asString(input.workspaceId),
144422
144582
  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({
144583
+ toolPermissionMode: asEnum(input.toolPermissionMode, TOOL_PERMISSION_MODES),
144584
+ activeMcpServers: asStringArray(input.activeMcpServers)
144585
+ }),
144586
+ "chat.providers.list": () => this.chatService.listProviders(),
144587
+ "chat.runtimes.list": (_context, input) => this.chatService.listRuntimeBadges({
144432
144588
  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) {
144589
+ }),
144590
+ "chat.session.state": (context, input) => this.chatService.getSessionState(this.requireOwnedSession(input, context)),
144591
+ "chat.session.attach": async (context, input) => {
144592
+ const sessionId = requireString(input, "sessionId");
144593
+ this.sessionRegistry.claim(sessionId, context.connectionId);
144594
+ try {
144595
+ return await this.chatService.attachSession(sessionId);
144596
+ } catch (error) {
144597
+ this.sessionRegistry.release(sessionId, context.connectionId);
144598
+ throw error;
144599
+ }
144600
+ },
144601
+ "chat.session.close": (context, input) => {
144602
+ const sessionId = this.requireOwnedSession(input, context);
144603
+ const result = this.chatService.closeSession(sessionId);
144446
144604
  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({
144605
+ return result;
144606
+ },
144607
+ "chat.files.suggest": (context, input) => {
144608
+ const sessionId = asString(input.sessionId);
144609
+ if (sessionId) {
144610
+ this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144611
+ }
144612
+ return this.chatService.suggestFiles({
144613
+ query: typeof input.query === "string" ? input.query : "",
144614
+ limit: asFiniteNumber(input.limit),
144615
+ sessionId,
144616
+ workspaceId: asString(input.workspaceId)
144617
+ });
144618
+ },
144619
+ "chat.input.submit": (context, input) => this.chatService.submitInput(this.requireOwnedSession(input, context), requireString(input, "input")),
144620
+ "chat.queue.remove": (context, input) => this.chatService.removeQueuedInput(this.requireOwnedSession(input, context), requireString(input, "queueId")),
144621
+ "chat.queue.send_now": (context, input) => this.chatService.sendQueuedInputNow(this.requireOwnedSession(input, context)),
144622
+ "chat.turn.cancel": (context, input) => this.chatService.cancelCurrentTurn(this.requireOwnedSession(input, context)),
144623
+ "chat.session.compact": (context, input) => this.chatService.compactSession(this.requireOwnedSession(input, context)),
144624
+ "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"))
144625
+ };
144626
+ }
144627
+ buildMcpHandlers() {
144628
+ return {
144629
+ "mcp.servers.list": () => this.mcpService.list(),
144630
+ "mcp.servers.get": (_context, input) => this.mcpService.get(requireString(input, "name")),
144631
+ "mcp.servers.create": (_context, input) => this.mcpService.create(requireString(input, "name"), input.config),
144632
+ "mcp.servers.update": (_context, input) => this.mcpService.update(requireString(input, "name"), input.config),
144633
+ "mcp.servers.remove": (_context, input) => this.mcpService.remove(requireString(input, "name")),
144634
+ "mcp.servers.login": (_context, input) => this.mcpService.login(requireString(input, "name"), asStringArray(input.scopes)),
144635
+ "mcp.servers.logout": (_context, input) => this.mcpService.logout(requireString(input, "name")),
144636
+ "mcp.active.set": (_context, input) => this.mcpService.setActive(requireTrimmedStringArray(input, "names"))
144637
+ };
144638
+ }
144639
+ buildSkillHandlers() {
144640
+ return {
144641
+ "skills.list": (_context, input) => this.skillsService.list({
144531
144642
  scope: input.scope,
144532
144643
  q: input.q,
144533
144644
  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({
144645
+ }),
144646
+ "skills.get": (_context, input) => this.skillsService.get(requireString(input, "id")),
144647
+ "skills.create": (_context, input) => this.skillsService.create({
144541
144648
  scope: input.scope,
144542
144649
  name: input.name,
144543
144650
  description: input.description,
144544
144651
  content: input.content,
144545
144652
  workspaceId: input.workspaceId
144546
- });
144547
- }
144548
- if (method === "skills.update") {
144549
- return this.skillsService.update(requireString(input, "id"), {
144653
+ }),
144654
+ "skills.update": (_context, input) => this.skillsService.update(requireString(input, "id"), {
144550
144655
  description: input.description,
144551
144656
  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({
144657
+ }),
144658
+ "skills.remove": (_context, input) => this.skillsService.remove(requireString(input, "id")),
144659
+ "skills.active.set": (_context, input) => this.skillsService.setActive(requireTrimmedStringArray(input, "ids"))
144660
+ };
144661
+ }
144662
+ buildWorkspaceHandlers() {
144663
+ return {
144664
+ "workspace.list": () => this.workspacesService.list(),
144665
+ "workspace.add": (_context, input) => this.workspacesService.add({
144569
144666
  cwd: input.cwd,
144570
144667
  name: input.name
144571
- });
144572
- }
144573
- if (method === "workspace.update") {
144574
- return this.workspacesService.update(requireString(input, "workspaceId"), {
144668
+ }),
144669
+ "workspace.update": (_context, input) => this.workspacesService.update(requireString(input, "workspaceId"), {
144575
144670
  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}`);
144671
+ }),
144672
+ "workspace.remove": async (_context, input) => {
144673
+ const workspaceId = requireString(input, "workspaceId");
144674
+ const sessionsResult = await this.sessionsService.removeSessionsByWorkspace(workspaceId);
144675
+ const workspaceResult = await this.workspacesService.remove(workspaceId);
144676
+ return {
144677
+ ...workspaceResult,
144678
+ deletedSessions: sessionsResult.deletedSessions
144679
+ };
144680
+ },
144681
+ "workspace.fs.list": (_context, input) => this.workspacesService.listDirectories(asString(input.path))
144682
+ };
144683
+ }
144684
+ requireOwnedSession(input, context) {
144685
+ const sessionId = requireString(input, "sessionId");
144686
+ this.sessionRegistry.requireOwner(sessionId, context.connectionId);
144687
+ return sessionId;
144592
144688
  }
144593
144689
  };
144594
144690
  exports2.RpcRouterService = RpcRouterService;
@@ -144952,6 +145048,12 @@ var require_ws_gateway_service = __commonJS({
144952
145048
  data: { sessionId, ...frame.payload }
144953
145049
  };
144954
145050
  }
145051
+ if (frame.type === "context.usage") {
145052
+ return {
145053
+ topic: "chat.context.usage",
145054
+ data: { sessionId, ...frame.payload }
145055
+ };
145056
+ }
144955
145057
  if (frame.type === "turn.final") {
144956
145058
  return {
144957
145059
  topic: "chat.turn.final",