@dan-ai-studio/dshopencodego 0.1.63 → 0.1.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -55,16 +55,16 @@ function parseGoQuota(value) {
55
55
  function parseCost(value) {
56
56
  if (value === null || typeof value !== "object") throw new Error("invalid model cost");
57
57
  const row = value;
58
- const rate = (key) => {
58
+ const rate3 = (key) => {
59
59
  const entry = row[key];
60
60
  if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) throw new Error(`invalid model cost "${key}"`);
61
61
  return entry;
62
62
  };
63
63
  return {
64
- input: rate("input"),
65
- output: rate("output"),
66
- ...typeof row["cacheRead"] === "number" ? { cacheRead: rate("cacheRead") } : {},
67
- ...typeof row["cacheWrite"] === "number" ? { cacheWrite: rate("cacheWrite") } : {}
64
+ input: rate3("input"),
65
+ output: rate3("output"),
66
+ ...typeof row["cacheRead"] === "number" ? { cacheRead: rate3("cacheRead") } : {},
67
+ ...typeof row["cacheWrite"] === "number" ? { cacheWrite: rate3("cacheWrite") } : {}
68
68
  };
69
69
  }
70
70
  function parseModalities(value) {
@@ -115,7 +115,7 @@ function parseCatalogReading(value) {
115
115
  throw new Error("invalid catalog reading");
116
116
  }
117
117
  const numbers = counts;
118
- const count = (key) => {
118
+ const count3 = (key) => {
119
119
  const entry = numbers[key];
120
120
  if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) throw new Error(`invalid catalog count "${key}"`);
121
121
  return entry;
@@ -134,11 +134,11 @@ function parseCatalogReading(value) {
134
134
  fetchedAtMs: row["fetchedAtMs"],
135
135
  quotaSource: quotaSource ?? "seed",
136
136
  counts: {
137
- total: count("total"),
138
- enabled: count("enabled"),
139
- deprecated: count("deprecated"),
140
- unconfigured: count("unconfigured"),
141
- inferred: count("inferred")
137
+ total: count3("total"),
138
+ enabled: count3("enabled"),
139
+ deprecated: count3("deprecated"),
140
+ unconfigured: count3("unconfigured"),
141
+ inferred: count3("inferred")
142
142
  }
143
143
  };
144
144
  }
@@ -207,6 +207,115 @@ var networkRemote = {
207
207
  ]
208
208
  };
209
209
 
210
+ // src/request-log/contract.ts
211
+ function count(key, row, optional) {
212
+ const entry = row[key];
213
+ if (entry === void 0) {
214
+ if (optional === true) return void 0;
215
+ throw new Error(`invalid request-log entry "${key}"`);
216
+ }
217
+ if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) {
218
+ throw new Error(`invalid request-log entry "${key}"`);
219
+ }
220
+ return entry;
221
+ }
222
+ function text(key, row, optional) {
223
+ const entry = row[key];
224
+ if (entry === void 0) {
225
+ if (optional === true) return void 0;
226
+ throw new Error(`invalid request-log entry "${key}"`);
227
+ }
228
+ if (typeof entry !== "string") throw new Error(`invalid request-log entry "${key}"`);
229
+ return entry;
230
+ }
231
+ function parseEntry(value) {
232
+ if (value === null || typeof value !== "object") throw new Error("invalid request-log entry");
233
+ const row = value;
234
+ const shape = row["shape"];
235
+ const headers = row["headers"];
236
+ return {
237
+ seq: count("seq", row),
238
+ atMs: count("atMs", row),
239
+ model: text("model", row),
240
+ session: text("session", row),
241
+ method: text("method", row),
242
+ url: text("url", row),
243
+ ...row["status"] === void 0 ? {} : { status: count("status", row) },
244
+ ...row["inputTokens"] === void 0 ? {} : { inputTokens: count("inputTokens", row) },
245
+ ...row["outputTokens"] === void 0 ? {} : { outputTokens: count("outputTokens", row) },
246
+ ...row["cacheReadTokens"] === void 0 ? {} : { cacheReadTokens: count("cacheReadTokens", row) },
247
+ ...row["durationMs"] === void 0 ? {} : { durationMs: count("durationMs", row) },
248
+ ...row["firstTokenMs"] === void 0 ? {} : { firstTokenMs: count("firstTokenMs", row) },
249
+ ...row["decodeMs"] === void 0 ? {} : { decodeMs: count("decodeMs", row) },
250
+ ...row["tps"] === void 0 ? {} : { tps: rate("tps", row) },
251
+ ok: row["ok"] === true,
252
+ ...typeof row["code"] === "string" ? { code: row["code"] } : {},
253
+ ...typeof row["poolKey"] === "string" ? { poolKey: row["poolKey"] } : {},
254
+ ...shape !== null && typeof shape === "object" ? {
255
+ shape: {
256
+ messages: count("messages", shape),
257
+ hasImage: shape["hasImage"] === true,
258
+ tools: count("tools", shape)
259
+ }
260
+ } : {},
261
+ ...headers !== null && typeof headers === "object" ? {
262
+ headers: {
263
+ ...typeof headers["session"] === "string" ? { session: headers["session"] } : {},
264
+ ...typeof headers["userAgent"] === "string" ? { userAgent: headers["userAgent"] } : {}
265
+ }
266
+ } : {}
267
+ };
268
+ }
269
+ function rate(key, row) {
270
+ const entry = row[key];
271
+ if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) {
272
+ throw new Error(`invalid request-log entry "${key}"`);
273
+ }
274
+ return entry;
275
+ }
276
+ function parsePoolEvent(value) {
277
+ if (value === null || typeof value !== "object") throw new Error("invalid request-log pool event");
278
+ const row = value;
279
+ const type = row["type"];
280
+ if (type !== "create" && type !== "close") throw new Error("invalid request-log pool event");
281
+ return { atMs: count("atMs", row), type, key: text("key", row) };
282
+ }
283
+ function parseRequestLogSnapshot(value) {
284
+ if (value === null || typeof value !== "object") throw new Error("invalid request-log snapshot");
285
+ const row = value;
286
+ if (!Array.isArray(row["entries"]) || !Array.isArray(row["poolEvents"])) {
287
+ throw new Error("invalid request-log snapshot");
288
+ }
289
+ return {
290
+ entries: row["entries"].map(parseEntry),
291
+ poolEvents: row["poolEvents"].map(parsePoolEvent),
292
+ totalRecords: count("totalRecords", row),
293
+ droppedRecords: count("droppedRecords", row),
294
+ newConnections: count("newConnections", row),
295
+ ...typeof row["poolKey"] === "string" ? { poolKey: row["poolKey"] } : {}
296
+ };
297
+ }
298
+ var codec3 = {
299
+ mode: "strict",
300
+ typeSymbol: "@dan-ai-studio/dshopencodego#RequestLogSnapshot",
301
+ schema: { parse: parseRequestLogSnapshot },
302
+ create: () => ({ parse: parseRequestLogSnapshot })
303
+ };
304
+ var requestLogRemote = {
305
+ package: "@dan-ai-studio/dshopencodego",
306
+ descriptors: [
307
+ {
308
+ id: "@dan-ai-studio/dshopencodego#opencodeGoRequestLog/readLog",
309
+ service: "opencodeGoRequestLog",
310
+ namespace: "opencodeGoRequestLog",
311
+ method: "readLog",
312
+ invocation: { kind: "direct" },
313
+ parameters: [],
314
+ result: codec3
315
+ }
316
+ ]
317
+ };
318
+
210
319
  // src/update/contract.ts
211
320
  function parseUpdateStatus(value) {
212
321
  if (value === null || typeof value !== "object") throw new Error("invalid update reading");
@@ -226,7 +335,7 @@ function parseUpdateStatus(value) {
226
335
  checked: row["checked"]
227
336
  };
228
337
  }
229
- var codec3 = (typeSymbol, parse) => ({
338
+ var codec4 = (typeSymbol, parse) => ({
230
339
  mode: "strict",
231
340
  typeSymbol,
232
341
  schema: { parse },
@@ -242,7 +351,7 @@ var updateRemote = {
242
351
  method: "readUpdate",
243
352
  invocation: { kind: "direct" },
244
353
  parameters: [],
245
- result: codec3("@dan-ai-studio/dshopencodego#UpdateStatus", parseUpdateStatus)
354
+ result: codec4("@dan-ai-studio/dshopencodego#UpdateStatus", parseUpdateStatus)
246
355
  },
247
356
  {
248
357
  id: "@dan-ai-studio/dshopencodego#opencodeGoUpdate/refreshUpdate",
@@ -251,7 +360,7 @@ var updateRemote = {
251
360
  method: "refreshUpdate",
252
361
  invocation: { kind: "direct" },
253
362
  parameters: [],
254
- result: codec3("@dan-ai-studio/dshopencodego#UpdateStatus", parseUpdateStatus)
363
+ result: codec4("@dan-ai-studio/dshopencodego#UpdateStatus", parseUpdateStatus)
255
364
  }
256
365
  ]
257
366
  };
@@ -278,22 +387,22 @@ function parseUsageWindows(value) {
278
387
  function parseTotals(value) {
279
388
  if (value === null || typeof value !== "object") throw new Error("invalid meter totals");
280
389
  const row = value;
281
- const count = (key) => {
390
+ const count3 = (key) => {
282
391
  const entry = row[key];
283
392
  if (typeof entry !== "number" || !Number.isFinite(entry) || entry < 0) throw new Error(`invalid meter field "${key}"`);
284
393
  return entry;
285
394
  };
286
- const optionalCount = (key) => row[key] === void 0 ? void 0 : count(key);
395
+ const optionalCount = (key) => row[key] === void 0 ? void 0 : count3(key);
287
396
  const reasoningTokens = optionalCount("reasoningTokens");
288
397
  const estimatedUSD = optionalCount("estimatedUSD");
289
398
  const unpricedTokens = optionalCount("unpricedTokens");
290
399
  return {
291
- calls: count("calls"),
292
- inputTokens: count("inputTokens"),
293
- outputTokens: count("outputTokens"),
294
- cacheReadTokens: count("cacheReadTokens"),
295
- cacheWriteTokens: count("cacheWriteTokens"),
296
- totalTokens: count("totalTokens"),
400
+ calls: count3("calls"),
401
+ inputTokens: count3("inputTokens"),
402
+ outputTokens: count3("outputTokens"),
403
+ cacheReadTokens: count3("cacheReadTokens"),
404
+ cacheWriteTokens: count3("cacheWriteTokens"),
405
+ totalTokens: count3("totalTokens"),
297
406
  ...reasoningTokens === void 0 ? {} : { reasoningTokens },
298
407
  ...estimatedUSD === void 0 ? {} : { estimatedUSD },
299
408
  ...unpricedTokens === void 0 ? {} : { unpricedTokens }
@@ -317,7 +426,7 @@ function parseGoMeter(value) {
317
426
  })
318
427
  };
319
428
  }
320
- var codec4 = (typeSymbol, parse) => ({
429
+ var codec5 = (typeSymbol, parse) => ({
321
430
  mode: "strict",
322
431
  typeSymbol,
323
432
  schema: { parse },
@@ -333,7 +442,7 @@ var usageRemote = {
333
442
  method: "readWindows",
334
443
  invocation: { kind: "direct" },
335
444
  parameters: [],
336
- result: codec4("@dan-ai-studio/dshopencodego#GoUsageWindows", parseUsageWindows)
445
+ result: codec5("@dan-ai-studio/dshopencodego#GoUsageWindows", parseUsageWindows)
337
446
  },
338
447
  {
339
448
  id: "@dan-ai-studio/dshopencodego#opencodeGoUsage/readMeter",
@@ -342,7 +451,7 @@ var usageRemote = {
342
451
  method: "readMeter",
343
452
  invocation: { kind: "direct" },
344
453
  parameters: [],
345
- result: codec4("@dan-ai-studio/dshopencodego#GoMeter", parseGoMeter)
454
+ result: codec5("@dan-ai-studio/dshopencodego#GoMeter", parseGoMeter)
346
455
  }
347
456
  ]
348
457
  };
@@ -388,6 +497,70 @@ var en = {
388
497
  refreshHint: "How long requests and the model picker reuse one listing.",
389
498
  keepAliveLabel: "Connection kept idle (seconds)",
390
499
  keepAliveHint: "How long a connection to the gateway is held between requests. Longer pauses in a conversation cost one handshake each; the timer restarts on every answer.",
500
+ requestLogTitle: "Request log",
501
+ requestLogHint: "Per-request records for troubleshooting. Off by default; enabling it does not change what requests do.",
502
+ requestLogPageHint: "One row per request. The table scrolls; the filters stay put.",
503
+ requestLogEnabled: "Record requests",
504
+ requestLogDebug: "Debug detail",
505
+ requestLogDebugHint: "Pool events and full session ids. Otherwise sessions are truncated to 8 characters.",
506
+ requestLogMaxEntries: "Keep at most (entries)",
507
+ requestLogMaxEntriesHint: "50 to 500; oldest entries are dropped first. Default 200.",
508
+ requestLogOpen: "Open request log",
509
+ requestLogClose: "Close",
510
+ requestLogRefresh: "Refresh",
511
+ requestLogEmpty: "No requests recorded. Turn the log on, then make a request.",
512
+ requestLogDisabled: "The request log is off.",
513
+ requestLogFilterModel: "Model",
514
+ requestLogFilterModelAll: "All models",
515
+ requestLogFilterResult: "Result",
516
+ requestLogResultAll: "All",
517
+ requestLogResultOk: "Succeeded",
518
+ requestLogResultFail: "Failed",
519
+ requestLogSlowOnly: "Slow only",
520
+ requestLogSlowSeconds: "slower than (seconds)",
521
+ requestLogFilterSession: "Session contains",
522
+ requestLogOnlySession: "this session only",
523
+ requestLogGroupBy: "Group by",
524
+ requestLogGroupNone: "None",
525
+ requestLogGroupSession: "Session",
526
+ requestLogGroupModel: "Model",
527
+ requestLogGroupResult: "Result",
528
+ requestLogPagePrev: "Previous",
529
+ requestLogPageNext: "Next",
530
+ requestLogPageOf: "of",
531
+ requestLogReuse: "Connection reuse",
532
+ requestLogReuseHint: "Share of recorded requests that reused a kept-alive connection, estimated from new sockets vs recorded requests.",
533
+ requestLogDropped: "dropped",
534
+ requestLogColTime: "Time",
535
+ requestLogColModel: "Model",
536
+ requestLogColSession: "Session",
537
+ requestLogColIn: "In",
538
+ requestLogColOut: "Out",
539
+ requestLogColCache: "Cached",
540
+ requestLogColLatency: "Latency",
541
+ requestLogColTps: "tok/s",
542
+ requestLogColFirstToken: "First token",
543
+ requestLogColStatus: "Status",
544
+ requestLogDetailRequest: "Request",
545
+ requestLogDetailTiming: "Timing",
546
+ requestLogDetailResult: "Result",
547
+ requestLogDetailMethod: "Method",
548
+ requestLogDetailUrl: "URL",
549
+ requestLogDetailSession: "Session",
550
+ requestLogDetailPool: "Pool",
551
+ requestLogDetailError: "Error",
552
+ requestLogDetailTokens: "Tokens",
553
+ requestLogDetailHeaders: "Headers",
554
+ requestLogDetailUserAgent: "User-Agent",
555
+ requestLogDetailShape: "Shape",
556
+ requestLogDetailMessages: "messages",
557
+ requestLogDetailTools: "tools",
558
+ requestLogDetailHasImage: "with images",
559
+ requestLogStatRequests: "Requests",
560
+ requestLogStatFailures: "Failures",
561
+ requestLogStatLatency: "Mean latency",
562
+ requestLogStatFirstToken: "Mean first token",
563
+ requestLogStatTps: "Mean tok/s",
391
564
  writeRejected: "The settings write was rejected (the namespace was reloaded) \u2014 try again",
392
565
  writeFailed: "The settings write failed",
393
566
  filterPlaceholder: "Filter by name or id",
@@ -500,6 +673,70 @@ var zh = {
500
673
  refreshHint: "\u8BF7\u6C42\u4E0E\u6A21\u578B\u9009\u62E9\u5668\u590D\u7528\u540C\u4E00\u4EFD\u5217\u8868\u7684\u65F6\u957F\u3002",
501
674
  keepAliveLabel: "\u8FDE\u63A5\u7A7A\u95F2\u4FDD\u7559\uFF08\u79D2\uFF09",
502
675
  keepAliveHint: "\u4E0E\u7F51\u5173\u7684\u8FDE\u63A5\u5728\u4E24\u6B21\u8BF7\u6C42\u4E4B\u95F4\u4FDD\u7559\u591A\u4E45\u3002\u5BF9\u8BDD\u4E2D\u6BCF\u6B21\u505C\u987F\u8F83\u4E45\u90FD\u8981\u91CD\u65B0\u63E1\u624B\u4E00\u6B21\uFF1B\u6BCF\u6B21\u6536\u5230\u56DE\u7B54\u540E\u8BA1\u65F6\u90FD\u4F1A\u91CD\u65B0\u5F00\u59CB\u3002",
676
+ requestLogTitle: "\u8BF7\u6C42\u65E5\u5FD7",
677
+ requestLogHint: "\u6392\u67E5\u7528\u7684\u9010\u8BF7\u6C42\u8BB0\u5F55\u3002\u9ED8\u8BA4\u5173\u95ED\uFF1B\u6253\u5F00\u5B83\u4E0D\u4F1A\u6539\u53D8\u8BF7\u6C42\u672C\u8EAB\u7684\u884C\u4E3A\u3002",
678
+ requestLogPageHint: "\u6BCF\u4E2A\u8BF7\u6C42\u4E00\u884C\u3002\u8868\u683C\u6EDA\u52A8\uFF0C\u7B5B\u9009\u680F\u56FA\u5B9A\u5728\u4E0A\u65B9\u3002",
679
+ requestLogEnabled: "\u8BB0\u5F55\u8BF7\u6C42",
680
+ requestLogDebug: "\u6392\u9519\u8BE6\u60C5",
681
+ requestLogDebugHint: "\u8FDE\u63A5\u6C60\u4E8B\u4EF6\u4E0E\u5B8C\u6574\u4F1A\u8BDD id\u3002\u4E0D\u5F00\u5219\u4F1A\u8BDD\u53EA\u4FDD\u7559\u524D 8 \u4F4D\u3002",
682
+ requestLogMaxEntries: "\u6700\u591A\u4FDD\u7559\uFF08\u6761\uFF09",
683
+ requestLogMaxEntriesHint: "50\uFF5E500 \u6761\uFF0C\u8D85\u9650\u4E22\u5F03\u6700\u65E7\u7684\u3002\u9ED8\u8BA4 200 \u6761\u3002",
684
+ requestLogOpen: "\u6253\u5F00\u8BF7\u6C42\u65E5\u5FD7",
685
+ requestLogClose: "\u5173\u95ED",
686
+ requestLogRefresh: "\u5237\u65B0",
687
+ requestLogEmpty: "\u6682\u65E0\u8BB0\u5F55\u3002\u5148\u6253\u5F00\u65E5\u5FD7\u5F00\u5173\uFF0C\u518D\u53D1\u8D77\u4E00\u6B21\u8BF7\u6C42\u3002",
688
+ requestLogDisabled: "\u8BF7\u6C42\u65E5\u5FD7\u672A\u5F00\u542F\u3002",
689
+ requestLogFilterModel: "\u6A21\u578B",
690
+ requestLogFilterModelAll: "\u5168\u90E8\u6A21\u578B",
691
+ requestLogFilterResult: "\u7ED3\u679C",
692
+ requestLogResultAll: "\u5168\u90E8",
693
+ requestLogResultOk: "\u6210\u529F",
694
+ requestLogResultFail: "\u5931\u8D25",
695
+ requestLogSlowOnly: "\u53EA\u770B\u6162\u8BF7\u6C42",
696
+ requestLogSlowSeconds: "\u6162\u4E8E\uFF08\u79D2\uFF09",
697
+ requestLogFilterSession: "\u4F1A\u8BDD\u5305\u542B",
698
+ requestLogOnlySession: "\u4EC5\u672C\u4F1A\u8BDD",
699
+ requestLogGroupBy: "\u5206\u7EC4",
700
+ requestLogGroupNone: "\u4E0D\u5206\u7EC4",
701
+ requestLogGroupSession: "\u6309\u4F1A\u8BDD",
702
+ requestLogGroupModel: "\u6309\u6A21\u578B",
703
+ requestLogGroupResult: "\u6309\u7ED3\u679C",
704
+ requestLogPagePrev: "\u4E0A\u4E00\u9875",
705
+ requestLogPageNext: "\u4E0B\u4E00\u9875",
706
+ requestLogPageOf: "\uFF0F\u5171",
707
+ requestLogReuse: "\u8FDE\u63A5\u590D\u7528\u7387",
708
+ requestLogReuseHint: "\u590D\u7528\u4FDD\u6D3B\u8FDE\u63A5\u7684\u8BF7\u6C42\u5360\u6BD4\uFF0C\u7528\u65B0\u5EFA\u8FDE\u63A5\u6570\u4E0E\u5DF2\u8BB0\u5F55\u8BF7\u6C42\u6570\u4F30\u7B97\u3002",
709
+ requestLogDropped: "\u5DF2\u4E22\u5F03",
710
+ requestLogColTime: "\u65F6\u95F4",
711
+ requestLogColModel: "\u6A21\u578B",
712
+ requestLogColSession: "\u4F1A\u8BDD",
713
+ requestLogColIn: "\u8F93\u5165",
714
+ requestLogColOut: "\u8F93\u51FA",
715
+ requestLogColCache: "\u7F13\u5B58",
716
+ requestLogColLatency: "\u8017\u65F6",
717
+ requestLogColTps: "tok/s",
718
+ requestLogColFirstToken: "\u9996\u5B57",
719
+ requestLogColStatus: "\u72B6\u6001",
720
+ requestLogDetailRequest: "\u8BF7\u6C42",
721
+ requestLogDetailTiming: "\u8017\u65F6",
722
+ requestLogDetailResult: "\u7ED3\u679C",
723
+ requestLogDetailMethod: "\u65B9\u6CD5",
724
+ requestLogDetailUrl: "\u5730\u5740",
725
+ requestLogDetailSession: "\u4F1A\u8BDD",
726
+ requestLogDetailPool: "\u8FDE\u63A5\u6C60",
727
+ requestLogDetailError: "\u9519\u8BEF",
728
+ requestLogDetailTokens: "Token",
729
+ requestLogDetailHeaders: "\u8BF7\u6C42\u5934",
730
+ requestLogDetailUserAgent: "User-Agent",
731
+ requestLogDetailShape: "\u8BF7\u6C42\u6784\u6210",
732
+ requestLogDetailMessages: "\u6761\u6D88\u606F",
733
+ requestLogDetailTools: "\u4E2A\u5DE5\u5177",
734
+ requestLogDetailHasImage: "\u542B\u56FE\u7247",
735
+ requestLogStatRequests: "\u8BF7\u6C42\u6570",
736
+ requestLogStatFailures: "\u5931\u8D25\u6570",
737
+ requestLogStatLatency: "\u5E73\u5747\u8017\u65F6",
738
+ requestLogStatFirstToken: "\u5E73\u5747\u9996\u5B57",
739
+ requestLogStatTps: "\u5E73\u5747 tok/s",
503
740
  writeRejected: "\u8BBE\u7F6E\u5199\u5165\u88AB\u62D2\u7EDD\uFF08\u5DF2\u91CD\u65B0\u8F7D\u5165\uFF09\uFF0C\u8BF7\u91CD\u8BD5",
504
741
  writeFailed: "\u8BBE\u7F6E\u5199\u5165\u5931\u8D25",
505
742
  filterPlaceholder: "\u6309\u540D\u79F0\u6216 ID \u7B5B\u9009",
@@ -588,6 +825,11 @@ var MAX_KEEP_ALIVE_TIMEOUT_SECONDS = 1800;
588
825
  var DEFAULT_KEEP_ALIVE_TIMEOUT_MS = DEFAULT_KEEP_ALIVE_TIMEOUT_SECONDS * 1e3;
589
826
  var MAX_KEEP_ALIVE_TIMEOUT_MS = MAX_KEEP_ALIVE_TIMEOUT_SECONDS * 1e3;
590
827
 
828
+ // src/request-log/limits.ts
829
+ var DEFAULT_REQUEST_LOG_MAX_ENTRIES = 200;
830
+ var MIN_REQUEST_LOG_MAX_ENTRIES = 50;
831
+ var MAX_REQUEST_LOG_MAX_ENTRIES = 500;
832
+
591
833
  // src/go-limits.ts
592
834
  var SEED_TRANSCRIBED = "2026-09-25";
593
835
  function monthlyRequestsRank(quota) {
@@ -629,18 +871,18 @@ function isIPv6(value) {
629
871
  const head = groups(halves[0] ?? "");
630
872
  const tail = halves.length === 2 ? groups(halves[1] ?? "") : [];
631
873
  const all = [...head, ...tail];
632
- let count = 0;
874
+ let count3 = 0;
633
875
  for (const [index, group] of all.entries()) {
634
876
  if (group.includes(".")) {
635
877
  if (index !== all.length - 1) return false;
636
878
  if (!isDottedQuad(group)) return false;
637
- count += 2;
879
+ count3 += 2;
638
880
  continue;
639
881
  }
640
882
  if (!/^[0-9a-fA-F]{1,4}$/.test(group)) return false;
641
- count += 1;
883
+ count3 += 1;
642
884
  }
643
- return halves.length === 2 ? count <= 7 : count === 8;
885
+ return halves.length === 2 ? count3 <= 7 : count3 === 8;
644
886
  }
645
887
  function isAddress(value) {
646
888
  const trimmed = value.trim();
@@ -749,11 +991,17 @@ function settingsOf(value) {
749
991
  const pins = record["pinnedAddresses"];
750
992
  const pinEntries = pins !== null && typeof pins === "object" ? Object.entries(pins).filter(([, address]) => typeof address === "string") : [];
751
993
  const keepAlive = record["keepAliveTimeoutMs"];
994
+ const requestLogEnabled = record["requestLogEnabled"];
995
+ const requestLogDebug = record["requestLogDebug"];
996
+ const requestLogMaxEntries = record["requestLogMaxEntries"];
752
997
  return {
753
998
  modelVisibility: Object.fromEntries(entries),
754
999
  refreshMinutes: minutes,
755
1000
  pinnedAddresses: Object.fromEntries(pinEntries),
756
- keepAliveTimeoutMs: typeof keepAlive === "number" ? keepAlive : DEFAULT_KEEP_ALIVE_TIMEOUT_MS
1001
+ keepAliveTimeoutMs: typeof keepAlive === "number" ? keepAlive : DEFAULT_KEEP_ALIVE_TIMEOUT_MS,
1002
+ requestLogEnabled: typeof requestLogEnabled === "boolean" ? requestLogEnabled : false,
1003
+ requestLogDebug: typeof requestLogDebug === "boolean" ? requestLogDebug : false,
1004
+ requestLogMaxEntries: typeof requestLogMaxEntries === "number" ? requestLogMaxEntries : DEFAULT_REQUEST_LOG_MAX_ENTRIES
757
1005
  };
758
1006
  }
759
1007
  var SectionController = class _SectionController {
@@ -843,6 +1091,18 @@ var SectionController = class _SectionController {
843
1091
  });
844
1092
  }
845
1093
  }
1094
+ /**
1095
+ * Read one request-log snapshot for the viewer. The viewer opens it on
1096
+ * demand and refreshes it when asked; nothing polls, so a closed viewer
1097
+ * costs no wire traffic at all.
1098
+ */
1099
+ async readRequestLog() {
1100
+ const remote = this.services.remote.opencodeGoRequestLog;
1101
+ if (remote === void 0) throw new Error("the request-log Remote is not mounted");
1102
+ const result = await remote.readLog();
1103
+ if (!result.ok) throw result.error;
1104
+ return result.value;
1105
+ }
846
1106
  /**
847
1107
  * Pin the gateway to one address.
848
1108
  *
@@ -1053,8 +1313,8 @@ var SectionController = class _SectionController {
1053
1313
  * the UI never waits on the Host round trip and a burst of clicks becomes a
1054
1314
  * single write of the final dict.
1055
1315
  */
1056
- setVisibility(id3, enabled) {
1057
- this.mergeVisibility({ [id3]: enabled });
1316
+ setVisibility(id4, enabled) {
1317
+ this.mergeVisibility({ [id4]: enabled });
1058
1318
  }
1059
1319
  /**
1060
1320
  * Set every configurable model at once (select-all / select-none).
@@ -1153,6 +1413,49 @@ var SectionController = class _SectionController {
1153
1413
  () => this.set({ settings: { ...current, keepAliveTimeoutMs: milliseconds } })
1154
1414
  );
1155
1415
  }
1416
+ /**
1417
+ * Flip the request-log master switch. Off (the default) means no record is
1418
+ * kept and the request path reads exactly as without the log.
1419
+ */
1420
+ async setRequestLogEnabled(enabled) {
1421
+ const scope = this.services.scope;
1422
+ const current = this.state.settings;
1423
+ if (scope === void 0 || current === void 0 || !this.state.writable) return;
1424
+ if (typeof enabled !== "boolean") return;
1425
+ await this.write(
1426
+ () => scope.set("requestLogEnabled", enabled),
1427
+ () => this.set({ settings: { ...current, requestLogEnabled: enabled } })
1428
+ );
1429
+ }
1430
+ /**
1431
+ * Flip request-log debug detail. Only recorded while the master switch is
1432
+ * on; the page does not enforce the pairing, the recorder does.
1433
+ */
1434
+ async setRequestLogDebug(debug) {
1435
+ const scope = this.services.scope;
1436
+ const current = this.state.settings;
1437
+ if (scope === void 0 || current === void 0 || !this.state.writable) return;
1438
+ if (typeof debug !== "boolean") return;
1439
+ await this.write(
1440
+ () => scope.set("requestLogDebug", debug),
1441
+ () => this.set({ settings: { ...current, requestLogDebug: debug } })
1442
+ );
1443
+ }
1444
+ /**
1445
+ * Set how many request-log entries the Host keeps, clamped to the schema's
1446
+ * own bounds. A lowered bound trims on the next read; raising it backfills
1447
+ * nothing.
1448
+ */
1449
+ async setRequestLogMaxEntries(entries) {
1450
+ const scope = this.services.scope;
1451
+ const current = this.state.settings;
1452
+ if (scope === void 0 || current === void 0 || !this.state.writable) return;
1453
+ if (!Number.isSafeInteger(entries) || entries < MIN_REQUEST_LOG_MAX_ENTRIES || entries > MAX_REQUEST_LOG_MAX_ENTRIES) return;
1454
+ await this.write(
1455
+ () => scope.set("requestLogMaxEntries", entries),
1456
+ () => this.set({ settings: { ...current, requestLogMaxEntries: entries } })
1457
+ );
1458
+ }
1156
1459
  async write(operation, onAccepted) {
1157
1460
  this.set({ saving: true });
1158
1461
  try {
@@ -1315,7 +1618,7 @@ function updateFailureText(message, t) {
1315
1618
  if (message === "pending-builds") return t("updatePendingBuilds");
1316
1619
  return message;
1317
1620
  }
1318
- function Section({ controller, t, getLocale }) {
1621
+ function Section({ controller, t, getLocale, openRequestLog }) {
1319
1622
  const state = (0, import_react.useSyncExternalStore)(controller.subscribe, controller.snapshot, controller.snapshot);
1320
1623
  const [keyDraft, setKeyDraft] = (0, import_react.useState)("");
1321
1624
  const [pinDraft, setPinDraft] = (0, import_react.useState)("");
@@ -1550,6 +1853,67 @@ function Section({ controller, t, getLocale }) {
1550
1853
  ),
1551
1854
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: t("keepAliveHint") })
1552
1855
  ] }),
1856
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: section_default.row, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("requestLogTitle") }) }),
1857
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: section_default.hint, children: t("requestLogHint") }),
1858
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: section_default.row, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: section_default.hint, children: [
1859
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1860
+ "input",
1861
+ {
1862
+ type: "checkbox",
1863
+ checked: state.settings?.requestLogEnabled ?? false,
1864
+ disabled: !editable || state.saving,
1865
+ onChange: (event) => {
1866
+ void act(async () => {
1867
+ await controller.setRequestLogEnabled(event.target.checked);
1868
+ });
1869
+ }
1870
+ }
1871
+ ),
1872
+ ` ${t("requestLogEnabled")}`
1873
+ ] }) }),
1874
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
1875
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: section_default.hint, children: [
1876
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1877
+ "input",
1878
+ {
1879
+ type: "checkbox",
1880
+ checked: state.settings?.requestLogDebug ?? false,
1881
+ disabled: !editable || state.saving,
1882
+ onChange: (event) => {
1883
+ void act(async () => {
1884
+ await controller.setRequestLogDebug(event.target.checked);
1885
+ });
1886
+ }
1887
+ }
1888
+ ),
1889
+ ` ${t("requestLogDebug")}`
1890
+ ] }),
1891
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: t("requestLogDebugHint") })
1892
+ ] }),
1893
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
1894
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: section_default.hint, htmlFor: "dshopencodego-requestlog-max", children: t("requestLogMaxEntries") }),
1895
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1896
+ "input",
1897
+ {
1898
+ id: "dshopencodego-requestlog-max",
1899
+ className: section_default.number,
1900
+ type: "number",
1901
+ min: MIN_REQUEST_LOG_MAX_ENTRIES,
1902
+ max: MAX_REQUEST_LOG_MAX_ENTRIES,
1903
+ disabled: !editable || state.saving,
1904
+ value: state.settings?.requestLogMaxEntries ?? "",
1905
+ onChange: (event) => {
1906
+ void act(async () => {
1907
+ await controller.setRequestLogMaxEntries(Number(event.target.value));
1908
+ });
1909
+ }
1910
+ }
1911
+ ),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: section_default.hint, children: t("requestLogMaxEntriesHint") })
1913
+ ] }),
1914
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: section_default.row, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: section_default.button, onClick: () => {
1915
+ openRequestLog?.();
1916
+ }, children: t("requestLogOpen") }) }),
1553
1917
  state.writeFailure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: section_default.warn, children: state.writeFailure.kind === "rejected" ? t("writeRejected") : state.writeFailure.message.length === 0 ? t("writeFailed") : `${t("writeFailed")}: ${state.writeFailure.message}` }),
1554
1918
  reading !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: section_default.row, children: [
1555
1919
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1658,22 +2022,406 @@ function Section({ controller, t, getLocale }) {
1658
2022
  ] });
1659
2023
  }
1660
2024
 
1661
- // src/client/UsagePill.tsx
2025
+ // src/client/RequestLogPage.tsx
1662
2026
  var import_react2 = require("react");
2027
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
1663
2028
 
1664
- // plugin-css:/home/runner/work/dshopencodego/dshopencodego/src/client/pill.module.css
1665
- var id2 = "@dan-ai-studio/dshopencodego/pill.module.css";
2029
+ // plugin-css:/home/runner/work/dshopencodego/dshopencodego/src/client/request-log.module.css
2030
+ var id2 = "@dan-ai-studio/dshopencodego/request-log.module.css";
1666
2031
  if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]")) {
1667
2032
  const style = document.createElement("style");
1668
2033
  style.dataset.plugin = "@dan-ai-studio/dshopencodego";
1669
2034
  style.dataset.pluginCss = id2;
2035
+ style.textContent = ".Lx7MOq_page{box-sizing:border-box;background:var(--dsw-alias-bg-base);height:100%;min-height:0;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex;overflow:hidden}.Lx7MOq_head{flex-wrap:wrap;flex:none;align-items:center;gap:12px;padding:20px clamp(16px,3vw,32px) 12px;display:flex}.Lx7MOq_headText{min-width:0}.Lx7MOq_title{margin:0;font-size:20px;font-weight:500;line-height:28px}.Lx7MOq_subtitle{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px;line-height:20px}.Lx7MOq_headActions{flex:none;align-items:center;gap:8px;margin-left:auto;display:flex}.Lx7MOq_button{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-bg-layer-1);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;align-items:center;gap:6px;padding:0 12px;font-size:13px;display:inline-flex}.Lx7MOq_button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Lx7MOq_button:disabled{cursor:default;opacity:.5}.Lx7MOq_summary{flex-wrap:wrap;flex:none;gap:8px;padding:0 clamp(16px,3vw,32px) 12px;display:flex}.Lx7MOq_card{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);flex-direction:column;gap:2px;min-width:104px;padding:8px 12px;display:flex}.Lx7MOq_cardLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:16px}.Lx7MOq_cardValue{font-variant-numeric:tabular-nums;font-size:16px;font-weight:500;line-height:22px}.Lx7MOq_cardError .Lx7MOq_cardValue{color:var(--dsw-alias-state-error-primary)}.Lx7MOq_cardWarn .Lx7MOq_cardValue{color:var(--dsw-alias-state-warn-primary)}.Lx7MOq_toolbar{flex-wrap:wrap;flex:none;align-items:center;gap:8px 12px;padding:0 clamp(16px,3vw,32px) 12px;display:flex}.Lx7MOq_field{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:13px;line-height:20px;display:inline-flex}.Lx7MOq_select,.Lx7MOq_input{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-bg-layer-1);height:28px;color:var(--dsw-alias-label-primary);font:inherit;padding:0 8px;font-size:13px}.Lx7MOq_input{width:160px}.Lx7MOq_inputNumber{width:72px}.Lx7MOq_checkbox{accent-color:var(--dsw-alias-brand-primary)}.Lx7MOq_tableWrap{border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);flex:1;min-height:0;margin:0 clamp(16px,3vw,32px);overflow:auto}.Lx7MOq_table{border-collapse:separate;border-spacing:0;width:100%;min-width:940px;font-size:13px;line-height:20px}.Lx7MOq_table th{z-index:1;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);text-align:left;white-space:nowrap;padding:8px 10px;font-size:12px;font-weight:500;position:sticky;top:0}.Lx7MOq_table td{border-bottom:1px solid var(--dsw-alias-border-l1);white-space:nowrap;font-variant-numeric:tabular-nums;padding:6px 10px}.Lx7MOq_table tbody tr:last-child td{border-bottom:none}.Lx7MOq_row{cursor:pointer}.Lx7MOq_row:hover td{background:var(--dsw-alias-interactive-bg-hover)}.Lx7MOq_rowOk td:first-child{box-shadow:inset 3px 0 0 var(--dsw-alias-border-l3)}.Lx7MOq_rowSlow td:first-child{box-shadow:inset 3px 0 0 var(--dsw-alias-state-warn-primary)}.Lx7MOq_rowFail td:first-child{box-shadow:inset 3px 0 0 var(--dsw-alias-state-error-primary)}.Lx7MOq_rowFail td:last-child,.Lx7MOq_rowSlow td:last-child{color:var(--dsw-alias-state-error-primary)}.Lx7MOq_group td{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);padding-top:12px;font-weight:500}.Lx7MOq_detail td{border-bottom:1px solid var(--dsw-alias-border-l1);white-space:normal;background:var(--dsw-alias-bg-layer-2);padding:12px 10px 16px}.Lx7MOq_detailGrid{grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:6px 24px;display:grid}.Lx7MOq_detailItem{gap:8px;min-width:0;font-size:13px;line-height:20px;display:flex}.Lx7MOq_detailLabel{color:var(--dsw-alias-label-tertiary);flex:none}.Lx7MOq_detailValue{overflow-wrap:anywhere;min-width:0;color:var(--dsw-alias-label-primary)}.Lx7MOq_mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}.Lx7MOq_empty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:48px 16px}.Lx7MOq_foot{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;flex:none;align-items:center;gap:12px;padding:12px clamp(16px,3vw,32px) 20px;font-size:12px;display:flex}.Lx7MOq_pager{align-items:center;gap:8px;margin-left:auto;display:flex}.Lx7MOq_notice{color:var(--dsw-alias-label-secondary);padding:0 clamp(16px,3vw,32px) 12px;font-size:13px;line-height:20px}.Lx7MOq_noticeError{color:var(--dsw-alias-state-error-primary)}";
2036
+ document.head.appendChild(style);
2037
+ }
2038
+ var request_log_default = { "button": "Lx7MOq_button", "card": "Lx7MOq_card", "cardError": "Lx7MOq_cardError", "cardLabel": "Lx7MOq_cardLabel", "cardValue": "Lx7MOq_cardValue", "cardWarn": "Lx7MOq_cardWarn", "checkbox": "Lx7MOq_checkbox", "detail": "Lx7MOq_detail", "detailGrid": "Lx7MOq_detailGrid", "detailItem": "Lx7MOq_detailItem", "detailLabel": "Lx7MOq_detailLabel", "detailValue": "Lx7MOq_detailValue", "empty": "Lx7MOq_empty", "field": "Lx7MOq_field", "foot": "Lx7MOq_foot", "group": "Lx7MOq_group", "head": "Lx7MOq_head", "headActions": "Lx7MOq_headActions", "headText": "Lx7MOq_headText", "input": "Lx7MOq_input", "inputNumber": "Lx7MOq_inputNumber", "mono": "Lx7MOq_mono", "notice": "Lx7MOq_notice", "noticeError": "Lx7MOq_noticeError", "page": "Lx7MOq_page", "pager": "Lx7MOq_pager", "row": "Lx7MOq_row", "rowFail": "Lx7MOq_rowFail", "rowOk": "Lx7MOq_rowOk", "rowSlow": "Lx7MOq_rowSlow", "select": "Lx7MOq_select", "subtitle": "Lx7MOq_subtitle", "summary": "Lx7MOq_summary", "table": "Lx7MOq_table", "tableWrap": "Lx7MOq_tableWrap", "title": "Lx7MOq_title", "toolbar": "Lx7MOq_toolbar" };
2039
+
2040
+ // src/client/RequestLogPage.tsx
2041
+ var import_jsx_runtime2 = require("react/jsx-runtime");
2042
+ var PAGE_SIZE = 50;
2043
+ function count2(value) {
2044
+ return value === void 0 ? "\u2014" : value.toLocaleString();
2045
+ }
2046
+ function duration(value) {
2047
+ if (value === void 0) return "\u2014";
2048
+ return value < 1e3 ? `${Math.round(value)}ms` : `${(value / 1e3).toFixed(2)}s`;
2049
+ }
2050
+ function rate2(value) {
2051
+ return value === void 0 ? "\u2014" : value.toFixed(1);
2052
+ }
2053
+ function average(values) {
2054
+ if (values.length === 0) return void 0;
2055
+ let sum = 0;
2056
+ for (const value of values) sum += value;
2057
+ return sum / values.length;
2058
+ }
2059
+ function groupKey(entry, groupBy) {
2060
+ switch (groupBy) {
2061
+ case "session":
2062
+ return entry.session === "" ? "\u2014" : entry.session;
2063
+ case "model":
2064
+ return entry.model;
2065
+ case "result":
2066
+ return entry.ok ? "ok" : entry.code ?? "fail";
2067
+ case "none":
2068
+ return void 0;
2069
+ }
2070
+ }
2071
+ function RequestLogPage({ readLog, enabled, t, getLocale, sessionId }) {
2072
+ const [snapshot, setSnapshot] = (0, import_react2.useState)(void 0);
2073
+ const [failure, setFailure] = (0, import_react2.useState)(void 0);
2074
+ const [refreshing, setRefreshing] = (0, import_react2.useState)(false);
2075
+ const [model, setModel] = (0, import_react2.useState)("all");
2076
+ const [result, setResult] = (0, import_react2.useState)("all");
2077
+ const [slowOnly, setSlowOnly] = (0, import_react2.useState)(false);
2078
+ const [slowSeconds, setSlowSeconds] = (0, import_react2.useState)(5);
2079
+ const [sessionQuery, setSessionQuery] = (0, import_react2.useState)("");
2080
+ const [groupBy, setGroupBy] = (0, import_react2.useState)("none");
2081
+ const [page, setPage] = (0, import_react2.useState)(0);
2082
+ const [expanded, setExpanded] = (0, import_react2.useState)(null);
2083
+ const sessionPrefix = sessionId === void 0 ? "" : sessionId.slice(0, 8);
2084
+ const [onlySession, setOnlySession] = (0, import_react2.useState)(sessionPrefix !== "");
2085
+ const load = (0, import_react2.useCallback)(async () => {
2086
+ setRefreshing(true);
2087
+ try {
2088
+ const next = await readLog();
2089
+ setSnapshot(next);
2090
+ setFailure(void 0);
2091
+ } catch (error) {
2092
+ setFailure(error instanceof Error ? error.message : String(error));
2093
+ } finally {
2094
+ setRefreshing(false);
2095
+ }
2096
+ }, [readLog]);
2097
+ (0, import_react2.useEffect)(() => {
2098
+ void load();
2099
+ }, [load]);
2100
+ const models = (0, import_react2.useMemo)(() => {
2101
+ const ids = /* @__PURE__ */ new Set();
2102
+ for (const entry of snapshot?.entries ?? []) ids.add(entry.model);
2103
+ return [...ids].toSorted();
2104
+ }, [snapshot]);
2105
+ const filtered = (0, import_react2.useMemo)(() => {
2106
+ const query = sessionQuery.trim();
2107
+ return (snapshot?.entries ?? []).filter((entry) => {
2108
+ if (model !== "all" && entry.model !== model) return false;
2109
+ if (result === "ok" && !entry.ok) return false;
2110
+ if (result === "fail" && entry.ok) return false;
2111
+ if (slowOnly && (entry.durationMs ?? 0) < Math.max(0, slowSeconds) * 1e3) return false;
2112
+ if (onlySession && sessionPrefix !== "" && !entry.session.startsWith(sessionPrefix)) return false;
2113
+ if (query !== "" && !entry.session.includes(query)) return false;
2114
+ return true;
2115
+ });
2116
+ }, [snapshot, model, result, slowOnly, slowSeconds, sessionQuery, onlySession, sessionPrefix]);
2117
+ const pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
2118
+ const safePage = Math.min(page, pages - 1);
2119
+ const pageEntries = filtered.slice(safePage * PAGE_SIZE, (safePage + 1) * PAGE_SIZE);
2120
+ const failures = filtered.filter((entry) => !entry.ok).length;
2121
+ const meanLatency = average(filtered.flatMap((entry) => entry.durationMs === void 0 ? [] : [entry.durationMs]));
2122
+ const meanFirstToken = average(filtered.flatMap((entry) => entry.firstTokenMs === void 0 ? [] : [entry.firstTokenMs]));
2123
+ const meanTps = average(filtered.flatMap((entry) => entry.tps === void 0 ? [] : [entry.tps]));
2124
+ const reuse = snapshot !== void 0 && snapshot.totalRecords > 0 ? Math.max(0, Math.min(1, 1 - snapshot.newConnections / snapshot.totalRecords)) : void 0;
2125
+ const rows = () => {
2126
+ const out = [];
2127
+ let lastGroup;
2128
+ for (const entry of pageEntries) {
2129
+ const group = groupKey(entry, groupBy);
2130
+ if (group !== void 0 && group !== lastGroup) {
2131
+ lastGroup = group;
2132
+ out.push(
2133
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.group, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 10, children: group }) }, `group-${group}-${entry.seq}`)
2134
+ );
2135
+ }
2136
+ const state = !entry.ok ? "rowFail" : entry.tps !== void 0 && entry.tps < 5 ? "rowSlow" : "rowOk";
2137
+ out.push(
2138
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2139
+ "tr",
2140
+ {
2141
+ className: `${request_log_default.row} ${request_log_default[state]}`,
2142
+ onClick: () => {
2143
+ setExpanded(expanded === entry.seq ? null : entry.seq);
2144
+ },
2145
+ children: [
2146
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: new Date(entry.atMs).toLocaleTimeString(getLocale(), { hour12: false }) }),
2147
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: request_log_default.mono, children: entry.model }),
2148
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: request_log_default.mono, children: entry.session === "" ? "\u2014" : entry.session }),
2149
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.inputTokens) }),
2150
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.outputTokens) }),
2151
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: count2(entry.cacheReadTokens) }),
2152
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: rate2(entry.tps) }),
2153
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.firstTokenMs) }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: duration(entry.durationMs) }),
2155
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: entry.ok ? entry.status === void 0 ? "\u2713" : String(entry.status) : entry.code ?? "\u2717" })
2156
+ ]
2157
+ },
2158
+ entry.seq
2159
+ )
2160
+ );
2161
+ if (expanded === entry.seq) {
2162
+ out.push(
2163
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: request_log_default.detail, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 10, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailGrid, children: [
2164
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2165
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailMethod") }),
2166
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.method })
2167
+ ] }),
2168
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2169
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailUrl") }),
2170
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.url })
2171
+ ] }),
2172
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2173
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailSession") }),
2174
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.session === "" ? "\u2014" : entry.session })
2175
+ ] }),
2176
+ entry.poolKey !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2177
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailPool") }),
2178
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: entry.poolKey })
2179
+ ] }),
2180
+ entry.headers !== void 0 && (entry.headers.session !== void 0 || entry.headers.userAgent !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2181
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailUserAgent") }),
2182
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${request_log_default.detailValue} ${request_log_default.mono}`, children: [entry.headers.session, entry.headers.userAgent].filter((part) => part !== void 0).join(" \xB7 ") })
2183
+ ] }),
2184
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2185
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailShape") }),
2186
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: request_log_default.detailValue, children: [
2187
+ `${entry.shape?.messages ?? 0} ${t("requestLogDetailMessages")}`,
2188
+ entry.shape !== void 0 && entry.shape.tools > 0 && ` \xB7 ${entry.shape.tools} ${t("requestLogDetailTools")}`,
2189
+ entry.shape?.hasImage === true && ` \xB7 ${t("requestLogDetailHasImage")}`
2190
+ ] })
2191
+ ] }),
2192
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2193
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailTokens") }),
2194
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: `${count2(entry.inputTokens)} / ${count2(entry.outputTokens)} / ${count2(entry.cacheReadTokens)}` })
2195
+ ] }),
2196
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2197
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogColTps") }),
2198
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: rate2(entry.tps) })
2199
+ ] }),
2200
+ !entry.ok && entry.code !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.detailItem, children: [
2201
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailLabel, children: t("requestLogDetailError") }),
2202
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.detailValue, children: entry.code })
2203
+ ] })
2204
+ ] }) }) }, `detail-${entry.seq}`)
2205
+ );
2206
+ }
2207
+ }
2208
+ return out;
2209
+ };
2210
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.page, children: [
2211
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.head, children: [
2212
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.headText, children: [
2213
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: request_log_default.title, children: t("requestLogTitle") }),
2214
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.subtitle, children: t("requestLogPageHint") })
2215
+ ] }),
2216
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.headActions, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", className: request_log_default.button, onClick: () => {
2217
+ void load();
2218
+ }, disabled: refreshing, children: [
2219
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives.IconRefreshOutlineRegular, { size: 13 }),
2220
+ t("requestLogRefresh")
2221
+ ] }) })
2222
+ ] }),
2223
+ !enabled() && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.notice, children: t("requestLogDisabled") }),
2224
+ failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `${request_log_default.notice} ${request_log_default.noticeError}`, children: failure }),
2225
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.summary, children: [
2226
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2227
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatRequests") }),
2228
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: filtered.length.toLocaleString(getLocale()) })
2229
+ ] }),
2230
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `${request_log_default.card} ${failures > 0 ? request_log_default.cardError : ""}`, children: [
2231
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFailures") }),
2232
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: failures.toLocaleString(getLocale()) })
2233
+ ] }),
2234
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2235
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatLatency") }),
2236
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanLatency) })
2237
+ ] }),
2238
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2239
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatFirstToken") }),
2240
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: duration(meanFirstToken) })
2241
+ ] }),
2242
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2243
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogStatTps") }),
2244
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: rate2(meanTps) })
2245
+ ] }),
2246
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.card, children: [
2247
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardLabel, children: t("requestLogReuse") }),
2248
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: request_log_default.cardValue, children: reuse === void 0 ? "\u2014" : `${(reuse * 100).toFixed(0)}%` })
2249
+ ] })
2250
+ ] }),
2251
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.toolbar, children: [
2252
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2253
+ t("requestLogFilterModel"),
2254
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2255
+ "select",
2256
+ {
2257
+ className: request_log_default.select,
2258
+ value: model,
2259
+ onChange: (event) => {
2260
+ setModel(event.target.value);
2261
+ setPage(0);
2262
+ },
2263
+ children: [
2264
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogFilterModelAll") }),
2265
+ models.map((id4) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: id4, children: id4 }, id4))
2266
+ ]
2267
+ }
2268
+ )
2269
+ ] }),
2270
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2271
+ t("requestLogFilterResult"),
2272
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2273
+ "select",
2274
+ {
2275
+ className: request_log_default.select,
2276
+ value: result,
2277
+ onChange: (event) => {
2278
+ setResult(event.target.value);
2279
+ setPage(0);
2280
+ },
2281
+ children: [
2282
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "all", children: t("requestLogResultAll") }),
2283
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "ok", children: t("requestLogResultOk") }),
2284
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fail", children: t("requestLogResultFail") })
2285
+ ]
2286
+ }
2287
+ )
2288
+ ] }),
2289
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2290
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2291
+ "input",
2292
+ {
2293
+ className: request_log_default.checkbox,
2294
+ type: "checkbox",
2295
+ checked: slowOnly,
2296
+ onChange: (event) => {
2297
+ setSlowOnly(event.target.checked);
2298
+ setPage(0);
2299
+ }
2300
+ }
2301
+ ),
2302
+ t("requestLogSlowOnly"),
2303
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2304
+ "input",
2305
+ {
2306
+ className: `${request_log_default.input} ${request_log_default.inputNumber}`,
2307
+ type: "number",
2308
+ min: 1,
2309
+ value: slowSeconds,
2310
+ disabled: !slowOnly,
2311
+ "aria-label": t("requestLogSlowSeconds"),
2312
+ onChange: (event) => {
2313
+ setSlowSeconds(Number(event.target.value));
2314
+ setPage(0);
2315
+ }
2316
+ }
2317
+ ),
2318
+ t("requestLogSlowSeconds")
2319
+ ] }),
2320
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2321
+ t("requestLogFilterSession"),
2322
+ sessionPrefix !== "" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2323
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2324
+ "input",
2325
+ {
2326
+ className: request_log_default.checkbox,
2327
+ type: "checkbox",
2328
+ checked: onlySession,
2329
+ onChange: (event) => {
2330
+ setOnlySession(event.target.checked);
2331
+ setPage(0);
2332
+ }
2333
+ }
2334
+ ),
2335
+ t("requestLogOnlySession")
2336
+ ] }),
2337
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2338
+ "input",
2339
+ {
2340
+ className: request_log_default.input,
2341
+ type: "search",
2342
+ value: sessionQuery,
2343
+ disabled: onlySession,
2344
+ onChange: (event) => {
2345
+ setSessionQuery(event.target.value);
2346
+ setPage(0);
2347
+ }
2348
+ }
2349
+ )
2350
+ ] }),
2351
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: request_log_default.field, children: [
2352
+ t("requestLogGroupBy"),
2353
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2354
+ "select",
2355
+ {
2356
+ className: request_log_default.select,
2357
+ value: groupBy,
2358
+ onChange: (event) => {
2359
+ setGroupBy(event.target.value);
2360
+ setPage(0);
2361
+ },
2362
+ children: [
2363
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "none", children: t("requestLogGroupNone") }),
2364
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "session", children: t("requestLogGroupSession") }),
2365
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "model", children: t("requestLogGroupModel") }),
2366
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "result", children: t("requestLogGroupResult") })
2367
+ ]
2368
+ }
2369
+ )
2370
+ ] })
2371
+ ] }),
2372
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: request_log_default.tableWrap, children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: request_log_default.empty, children: t("requestLogEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { className: request_log_default.table, children: [
2373
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
2374
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColTime") }),
2375
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColModel") }),
2376
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColSession") }),
2377
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColIn") }),
2378
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColOut") }),
2379
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColCache") }),
2380
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColTps") }),
2381
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColFirstToken") }),
2382
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColLatency") }),
2383
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: t("requestLogColStatus") })
2384
+ ] }) }),
2385
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: rows() })
2386
+ ] }) }),
2387
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.foot, children: [
2388
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${filtered.length.toLocaleString(getLocale())} / ${(snapshot?.totalRecords ?? 0).toLocaleString(getLocale())} ${t("requestLogStatRequests")}` }),
2389
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: request_log_default.pager, children: [
2390
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage <= 0, onClick: () => {
2391
+ setPage(safePage - 1);
2392
+ }, children: t("requestLogPagePrev") }),
2393
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: `${safePage + 1} ${t("requestLogPageOf")} ${pages}` }),
2394
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: request_log_default.button, disabled: safePage >= pages - 1, onClick: () => {
2395
+ setPage(safePage + 1);
2396
+ }, children: t("requestLogPageNext") })
2397
+ ] })
2398
+ ] })
2399
+ ] });
2400
+ }
2401
+
2402
+ // src/client/RequestLogPanelIcon.tsx
2403
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
2404
+ var import_jsx_runtime3 = require("react/jsx-runtime");
2405
+ function RequestLogPanelIcon({ size }) {
2406
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives2.IconDataOutlineRegular, { size });
2407
+ }
2408
+
2409
+ // src/client/UsagePill.tsx
2410
+ var import_react3 = require("react");
2411
+
2412
+ // plugin-css:/home/runner/work/dshopencodego/dshopencodego/src/client/pill.module.css
2413
+ var id3 = "@dan-ai-studio/dshopencodego/pill.module.css";
2414
+ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id3) + "]")) {
2415
+ const style = document.createElement("style");
2416
+ style.dataset.plugin = "@dan-ai-studio/dshopencodego";
2417
+ style.dataset.pluginCss = id3;
1670
2418
  style.textContent = ".mMNkkW_root{align-items:center;display:inline-flex;position:relative}.mMNkkW_trigger{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;border-radius:999px;padding:.35rem .6rem;font-size:.8rem;line-height:1}.mMNkkW_trigger:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.mMNkkW_panel{z-index:20;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-overlay);width:18rem;color:var(--dsw-alias-label-primary);border-radius:.6rem;flex-direction:column;gap:.6rem;padding:.75rem .85rem;display:flex;position:absolute;bottom:calc(100% + .5rem);right:0;box-shadow:0 8px 24px #0000002e}.mMNkkW_window{flex-direction:column;gap:.25rem;display:flex}.mMNkkW_row{justify-content:space-between;gap:.5rem;font-size:.85rem;display:flex}.mMNkkW_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:.75rem}.mMNkkW_progress{width:100%;height:.35rem;accent-color:var(--dsw-alias-brand-primary)}.mMNkkW_limited{color:var(--dsw-alias-state-warn-primary);font-size:.75rem}.mMNkkW_warning{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-label-primary);border-radius:.4rem;padding:.4rem .5rem;font-size:.75rem}.mMNkkW_retry{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:.35rem;align-self:flex-start;padding:.25rem .5rem;font-size:.75rem}.mMNkkW_local{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:.2rem;padding-top:.5rem;display:flex}";
1671
2419
  document.head.appendChild(style);
1672
2420
  }
1673
2421
  var pill_default = { "hint": "mMNkkW_hint", "limited": "mMNkkW_limited", "local": "mMNkkW_local", "panel": "mMNkkW_panel", "progress": "mMNkkW_progress", "retry": "mMNkkW_retry", "root": "mMNkkW_root", "row": "mMNkkW_row", "trigger": "mMNkkW_trigger", "warning": "mMNkkW_warning", "window": "mMNkkW_window" };
1674
2422
 
1675
2423
  // src/client/UsagePill.tsx
1676
- var import_jsx_runtime2 = require("react/jsx-runtime");
2424
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1677
2425
  function failureOf(error) {
1678
2426
  if (error !== null && typeof error === "object" && "code" in error && error.code === "dshopencodego/usage-unavailable") {
1679
2427
  const details = error.details;
@@ -1694,8 +2442,8 @@ function formatUSD(value) {
1694
2442
  return value < 1 ? `$${value.toFixed(4)}` : `$${value.toFixed(2)}`;
1695
2443
  }
1696
2444
  function UsagePill({ directory, ...rest }) {
1697
- const state = (0, import_react2.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
1698
- return state.current?.provider === "opencode-go" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActiveUsage, { ...rest }) : null;
2445
+ const state = (0, import_react3.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
2446
+ return state.current?.provider === "opencode-go" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ActiveUsage, { ...rest }) : null;
1699
2447
  }
1700
2448
  function ActiveUsage({
1701
2449
  readWindows,
@@ -1703,14 +2451,14 @@ function ActiveUsage({
1703
2451
  t,
1704
2452
  getLocale
1705
2453
  }) {
1706
- const [windows, setWindows] = (0, import_react2.useState)(void 0);
1707
- const [meter, setMeter] = (0, import_react2.useState)(void 0);
1708
- const [failure, setFailure] = (0, import_react2.useState)(void 0);
1709
- const [updatedAt, setUpdatedAt] = (0, import_react2.useState)(void 0);
1710
- const [refreshing, setRefreshing] = (0, import_react2.useState)(false);
1711
- const [open, setOpen] = (0, import_react2.useState)(false);
1712
- const root = (0, import_react2.useRef)(null);
1713
- const refresh = (0, import_react2.useCallback)(async () => {
2454
+ const [windows, setWindows] = (0, import_react3.useState)(void 0);
2455
+ const [meter, setMeter] = (0, import_react3.useState)(void 0);
2456
+ const [failure, setFailure] = (0, import_react3.useState)(void 0);
2457
+ const [updatedAt, setUpdatedAt] = (0, import_react3.useState)(void 0);
2458
+ const [refreshing, setRefreshing] = (0, import_react3.useState)(false);
2459
+ const [open, setOpen] = (0, import_react3.useState)(false);
2460
+ const root = (0, import_react3.useRef)(null);
2461
+ const refresh = (0, import_react3.useCallback)(async () => {
1714
2462
  setRefreshing(true);
1715
2463
  try {
1716
2464
  const [nextWindows, nextMeter] = await Promise.all([readWindows(), readMeter()]);
@@ -1729,7 +2477,7 @@ function ActiveUsage({
1729
2477
  setRefreshing(false);
1730
2478
  }
1731
2479
  }, [readWindows, readMeter]);
1732
- (0, import_react2.useEffect)(() => {
2480
+ (0, import_react3.useEffect)(() => {
1733
2481
  let alive = true;
1734
2482
  const run = () => {
1735
2483
  if (!alive || document.visibilityState === "hidden") return;
@@ -1744,7 +2492,7 @@ function ActiveUsage({
1744
2492
  document.removeEventListener("visibilitychange", run);
1745
2493
  };
1746
2494
  }, [refresh]);
1747
- (0, import_react2.useEffect)(() => {
2495
+ (0, import_react3.useEffect)(() => {
1748
2496
  if (!open) return;
1749
2497
  const close = (event) => {
1750
2498
  if (!root.current?.contains(event.target)) setOpen(false);
@@ -1762,8 +2510,8 @@ function ActiveUsage({
1762
2510
  const label = windows === void 0 ? `Go \xB7 ${failure === void 0 ? "\u2026" : t("usageUnavailable")}` : `Go \xB7 ${t("usageRolling")} ${windows.rolling.percent}% \xB7 ${t("usageWeekly")} ${windows.weekly.percent}%` + (failure === void 0 ? "" : ` \xB7 ${t("usageStale")}`);
1763
2511
  const unpriced = (meter?.models ?? []).filter((entry) => entry.estimatedUSD === void 0);
1764
2512
  const unpricedModels = unpriced.slice(0, MAX_UNPRICED_IDS).map((entry) => entry.model).join(", ") + (unpriced.length > MAX_UNPRICED_IDS ? ` +${unpriced.length - MAX_UNPRICED_IDS}` : "");
1765
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: pill_default.root, ref: root, children: [
1766
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2513
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: pill_default.root, ref: root, children: [
2514
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1767
2515
  "button",
1768
2516
  {
1769
2517
  type: "button",
@@ -1777,71 +2525,71 @@ function ActiveUsage({
1777
2525
  children: label
1778
2526
  }
1779
2527
  ),
1780
- open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
1781
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageTitle") }),
1782
- failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.warning, role: "alert", children: [
1783
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageUnavailable") }) }),
1784
- failure.message.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: failure.message }),
1785
- windows !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: t("usageStale") })
2528
+ open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
2529
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("usageTitle") }),
2530
+ failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.warning, role: "alert", children: [
2531
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("usageUnavailable") }) }),
2532
+ failure.message.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: failure.message }),
2533
+ windows !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: t("usageStale") })
1786
2534
  ] }),
1787
- windows === void 0 && failure === void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: pill_default.hint, children: t("usageLoading") }),
1788
- windows !== void 0 && [["rolling", "usageRolling"], ["weekly", "usageWeekly"], ["monthly", "usageMonthly"]].map(([key, label2]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.window, children: [
1789
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
1790
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t(label2) }),
1791
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
2535
+ windows === void 0 && failure === void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: pill_default.hint, children: t("usageLoading") }),
2536
+ windows !== void 0 && [["rolling", "usageRolling"], ["weekly", "usageWeekly"], ["monthly", "usageMonthly"]].map(([key, label2]) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.window, children: [
2537
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.row, children: [
2538
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t(label2) }),
2539
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("strong", { children: [
1792
2540
  windows[key].percent,
1793
2541
  "%"
1794
2542
  ] })
1795
2543
  ] }),
1796
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("progress", { className: pill_default.progress, max: 100, value: Math.min(100, windows[key].percent), "aria-label": t(label2) }),
1797
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.hint, children: [
2544
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("progress", { className: pill_default.progress, max: 100, value: Math.min(100, windows[key].percent), "aria-label": t(label2) }),
2545
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.hint, children: [
1798
2546
  t("usageResets"),
1799
2547
  " ",
1800
2548
  new Date(windows[key].resetsAt).toLocaleString(getLocale?.())
1801
2549
  ] }),
1802
- windows[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: pill_default.limited, children: t("usageLimited") })
2550
+ windows[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: pill_default.limited, children: t("usageLimited") })
1803
2551
  ] }, key)),
1804
- meter !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.local, children: [
1805
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageSinceBoot") }),
1806
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
1807
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageCallsUnit") }),
1808
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.calls })
2552
+ meter !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.local, children: [
2553
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("usageSinceBoot") }),
2554
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.row, children: [
2555
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("usageCallsUnit") }),
2556
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: meter.totals.calls })
1809
2557
  ] }),
1810
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
1811
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageTokensUnit") }),
1812
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.totalTokens.toLocaleString(getLocale?.()) })
2558
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.row, children: [
2559
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("usageTokensUnit") }),
2560
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: meter.totals.totalTokens.toLocaleString(getLocale?.()) })
1813
2561
  ] }),
1814
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
1815
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageCached") }),
1816
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.cacheReadTokens.toLocaleString(getLocale?.()) })
2562
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.row, children: [
2563
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("usageCached") }),
2564
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: meter.totals.cacheReadTokens.toLocaleString(getLocale?.()) })
1817
2565
  ] }),
1818
- meter.totals.reasoningTokens !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
1819
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageReasoning") }),
1820
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.reasoningTokens.toLocaleString(getLocale?.()) })
2566
+ meter.totals.reasoningTokens !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.row, children: [
2567
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("usageReasoning") }),
2568
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: meter.totals.reasoningTokens.toLocaleString(getLocale?.()) })
1821
2569
  ] }),
1822
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.row, children: [
1823
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("usageSpend") }),
1824
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: meter.totals.estimatedUSD === void 0 ? t("usageUnpriced") : formatUSD(meter.totals.estimatedUSD) })
2570
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.row, children: [
2571
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("usageSpend") }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: meter.totals.estimatedUSD === void 0 ? t("usageUnpriced") : formatUSD(meter.totals.estimatedUSD) })
1825
2573
  ] }),
1826
- meter.totals.unpricedTokens !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.hint, children: [
2574
+ meter.totals.unpricedTokens !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.hint, children: [
1827
2575
  t("usageSpendPartial"),
1828
2576
  " ",
1829
2577
  meter.totals.unpricedTokens.toLocaleString(getLocale?.())
1830
2578
  ] }),
1831
- unpriced.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: pill_default.hint, children: [
2579
+ unpriced.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: pill_default.hint, children: [
1832
2580
  t("usageUnpricedModels"),
1833
2581
  " ",
1834
2582
  unpricedModels
1835
2583
  ] }),
1836
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: pill_default.hint, children: t("usageSpendHint") }),
1837
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: pill_default.hint, children: t("usageLocalHint") })
2584
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: pill_default.hint, children: t("usageSpendHint") }),
2585
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: pill_default.hint, children: t("usageLocalHint") })
1838
2586
  ] }),
1839
- updatedAt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: pill_default.hint, children: [
2587
+ updatedAt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: pill_default.hint, children: [
1840
2588
  t("usageLastUpdated"),
1841
2589
  " ",
1842
2590
  new Date(updatedAt).toLocaleString(getLocale?.())
1843
2591
  ] }),
1844
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: pill_default.retry, disabled: refreshing, onClick: () => {
2592
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: pill_default.retry, disabled: refreshing, onClick: () => {
1845
2593
  void refresh();
1846
2594
  }, children: t(refreshing ? "usageRefreshing" : "usageRetry") })
1847
2595
  ] })
@@ -1850,6 +2598,7 @@ function ActiveUsage({
1850
2598
 
1851
2599
  // src/client/index.ts
1852
2600
  var NS = "settings.dshopencodego";
2601
+ var REQUEST_LOG_PANEL = "dshopencodego-request-log";
1853
2602
  var inject = ["slots", "locale", "remote"];
1854
2603
  function apply(ctx) {
1855
2604
  ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dshopencodego: copy dictionaries");
@@ -1859,7 +2608,8 @@ function apply(ctx) {
1859
2608
  ...usageRemote.descriptors,
1860
2609
  ...catalogRemote.descriptors,
1861
2610
  ...updateRemote.descriptors,
1862
- ...networkRemote.descriptors
2611
+ ...networkRemote.descriptors,
2612
+ ...requestLogRemote.descriptors
1863
2613
  ]
1864
2614
  });
1865
2615
  ctx.effect(() => {
@@ -1872,13 +2622,14 @@ function apply(ctx) {
1872
2622
  void dispose?.();
1873
2623
  };
1874
2624
  }, "dshopencodego: usage Remote");
1875
- ctx.inject(["configForms", "remote.opencodeGoCatalog", "remote.opencodeGoUpdate", "remote.opencodeGoNetwork", "remote.credentials"], (scope) => {
2625
+ ctx.inject(["configForms", "remote.opencodeGoCatalog", "remote.opencodeGoUpdate", "remote.opencodeGoNetwork", "remote.opencodeGoRequestLog", "remote.credentials"], (scope) => {
1876
2626
  const forms = scope.get("configForms");
1877
2627
  const pluginManager = {};
2628
+ const profile = forms?.get("dshopencodego");
1878
2629
  const controller = new SectionController({
1879
2630
  remote: scope.remote,
1880
2631
  pluginManager,
1881
- scope: forms?.get("dshopencodego")
2632
+ scope: profile
1882
2633
  });
1883
2634
  scope.inject(["remote.pluginManager"], (managerScope) => {
1884
2635
  pluginManager.current = managerScope.remote.pluginManager;
@@ -1890,6 +2641,47 @@ function apply(ctx) {
1890
2641
  scope.effect(() => () => {
1891
2642
  controller.dispose();
1892
2643
  });
2644
+ const requestLog = {
2645
+ readLog: async () => {
2646
+ const result = await scope.remote.opencodeGoRequestLog.readLog();
2647
+ if (!result.ok) throw result.error;
2648
+ return result.value;
2649
+ },
2650
+ // Read live: the switch on the settings page can change while the log
2651
+ // page sits open, and the page says so rather than pretending.
2652
+ enabled: () => {
2653
+ const value = profile?.getSnapshot().value;
2654
+ if (value === null || typeof value !== "object") return false;
2655
+ return value.requestLogEnabled === true;
2656
+ },
2657
+ t: (key) => translate(key),
2658
+ getLocale: () => scope.locale.getLocale().active
2659
+ };
2660
+ scope.slots.inject("main", function* () {
2661
+ yield scope.slots.register({
2662
+ name: "main",
2663
+ key: REQUEST_LOG_PANEL,
2664
+ locale: NS,
2665
+ inject: () => requestLog
2666
+ }, RequestLogPage);
2667
+ });
2668
+ scope.slots.inject("sidebar.panellist", () => scope.slots.register({
2669
+ name: "sidebar.panellist",
2670
+ id: REQUEST_LOG_PANEL,
2671
+ // After the Host's own panels, which run from 0.
2672
+ order: 100,
2673
+ label: () => translate("requestLogTitle"),
2674
+ locale: NS
2675
+ }, RequestLogPanelIcon));
2676
+ scope.slots.inject("conversation.view", () => scope.slots.register({
2677
+ name: "conversation.view",
2678
+ id: "dshopencodego-request-log",
2679
+ // After the Host's own View (the chat itself), which runs at 0.
2680
+ order: 100,
2681
+ label: () => translate("requestLogTitle"),
2682
+ locale: NS,
2683
+ inject: (sessionId) => ({ ...requestLog, sessionId: String(sessionId) })
2684
+ }, RequestLogPage));
1893
2685
  scope.slots.inject("settings.section", () => scope.slots.register({
1894
2686
  name: "settings.section",
1895
2687
  id: "dshopencodego",
@@ -1902,7 +2694,16 @@ function apply(ctx) {
1902
2694
  inject: () => ({
1903
2695
  controller,
1904
2696
  t: (key) => translate(key),
1905
- getLocale: () => scope.locale.getLocale().active
2697
+ getLocale: () => scope.locale.getLocale().active,
2698
+ // The settings page opens the log in the main column, beside this
2699
+ // page rather than over it. A composition without the layout service
2700
+ // has no main column to select, so the button does nothing there.
2701
+ openRequestLog: () => {
2702
+ try {
2703
+ ctx.layout.selectPanel(REQUEST_LOG_PANEL);
2704
+ } catch {
2705
+ }
2706
+ }
1906
2707
  })
1907
2708
  }, Section));
1908
2709
  });