@crazyhappyone/dsh-tui 0.1.0-alpha.27 → 0.1.0-alpha.29

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/README.i18n.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  # Bilingual-pair consistency record: both languages carry equal authority.
2
2
  # This source-only mirror has no DSH pairing runner. Recompute with:
3
3
  # git hash-object README.md README.zh.md
4
- README.md: 496d812168deb2af7d4a933f961b58c1cfd814cd
5
- README.zh.md: 8474c7be4cf16c0d5123222bab95b5231f34e185
4
+ README.md: 9edd0d7b9c067fc810fa59fc53525eed8be07dd9
5
+ README.zh.md: 9f4e419aeb64eb7e676b7763caa9b69e835cf0dd
package/README.md CHANGED
@@ -33,9 +33,9 @@ English | [中文](README.zh.md)
33
33
  <a id="screenshots"></a>
34
34
  ## Screenshots
35
35
 
36
- Idle home:
36
+ Interactive settings pane (`/settings`):
37
37
 
38
- ![dsh-tui idle home](assets/screenshots/dsh-tui-home.png)
38
+ ![dsh-tui settings pane](assets/screenshots/dsh-tui-settings.png)
39
39
 
40
40
  After sending `你好`:
41
41
 
package/README.zh.md CHANGED
@@ -33,9 +33,9 @@ kind: "package-group"
33
33
  <a id="screenshots"></a>
34
34
  ## 截图
35
35
 
36
- 空闲首页:
36
+ 交互式设置面板(`/settings`):
37
37
 
38
- ![dsh-tui 空闲首页](assets/screenshots/dsh-tui-home.png)
38
+ ![dsh-tui 设置面板](assets/screenshots/dsh-tui-settings.png)
39
39
 
40
40
  发送 `你好` 后:
41
41
 
package/dist/index.js CHANGED
@@ -228,6 +228,7 @@ var THEME_LEVELS = {
228
228
  toolBg: "#252830",
229
229
  inputBg: "#23262B",
230
230
  codeBg: "#202328",
231
+ settingsCardBg: "#182236",
231
232
  fg: "#EEF0F2",
232
233
  fgSoft: "#D1D4D8",
233
234
  fgDim: "#A4A9B0",
@@ -253,6 +254,7 @@ var THEME_LEVELS = {
253
254
  toolBg: "236",
254
255
  inputBg: "235",
255
256
  codeBg: "235",
257
+ settingsCardBg: "236",
256
258
  fg: "255",
257
259
  fgSoft: "252",
258
260
  fgDim: "248",
@@ -278,6 +280,7 @@ var THEME_LEVELS = {
278
280
  toolBg: "black",
279
281
  inputBg: "bright-black",
280
282
  codeBg: "black",
283
+ settingsCardBg: "blue",
281
284
  fg: "white",
282
285
  fgSoft: "white",
283
286
  fgDim: "white",
@@ -303,6 +306,7 @@ var THEME_LEVELS = {
303
306
  toolBg: "",
304
307
  inputBg: "",
305
308
  codeBg: "",
309
+ settingsCardBg: "",
306
310
  fg: "",
307
311
  fgSoft: "",
308
312
  fgDim: "",
@@ -416,7 +420,8 @@ var BACKGROUND_TOKENS = /* @__PURE__ */ new Set([
416
420
  "messageBg",
417
421
  "toolBg",
418
422
  "inputBg",
419
- "codeBg"
423
+ "codeBg",
424
+ "settingsCardBg"
420
425
  ]);
421
426
 
422
427
  // tui-render/src/brand.ts
@@ -3169,6 +3174,220 @@ var RowSequence = class {
3169
3174
  }
3170
3175
  };
3171
3176
 
3177
+ // tui-render/src/tool-cards.ts
3178
+ import { isAbsolute } from "node:path";
3179
+ import { pathToFileURL } from "node:url";
3180
+ function toolCardDisplayStatus(card) {
3181
+ const terminal = card.resultView?.card === "terminal" ? card.resultView : void 0;
3182
+ if (terminal?.signal !== void 0) return "error";
3183
+ if (terminal?.exitCode !== void 0 && terminal.exitCode !== 0) return "error";
3184
+ return card.status;
3185
+ }
3186
+ function collapsedResultTail(text) {
3187
+ if (text === void 0) return void 0;
3188
+ const line5 = text.split(/\r?\n/u).map((item) => item.trim()).filter(Boolean).at(-1);
3189
+ return line5 === void 0 ? void 0 : escapeContent(line5);
3190
+ }
3191
+ function collapsedFailureSummary(card) {
3192
+ const terminal = card.resultView?.card === "terminal" ? card.resultView : void 0;
3193
+ const identity = terminal?.exitCode !== void 0 ? `exitCode ${String(terminal.exitCode)}` : terminal?.signal !== void 0 ? `signal ${terminal.signal}` : card.error?.code;
3194
+ const detail = collapsedResultTail(terminal?.output ?? card.resultText);
3195
+ if (identity === void 0) return detail;
3196
+ return detail === void 0 || detail === identity ? identity : `${identity} \xB7 ${detail}`;
3197
+ }
3198
+ function collapsedToolCardSummary(card) {
3199
+ if (toolCardDisplayStatus(card) === "error") {
3200
+ const failure = collapsedFailureSummary(card);
3201
+ if (failure !== void 0) return failure;
3202
+ }
3203
+ const result = card.resultView;
3204
+ const kind = result?.card ?? card.callView?.card ?? "generic";
3205
+ switch (kind) {
3206
+ case "terminal":
3207
+ if (result?.card === "terminal" && result.exitCode !== void 0) {
3208
+ return `exitCode ${String(result.exitCode)}`;
3209
+ }
3210
+ if (result?.card === "terminal" && result.signal !== void 0) {
3211
+ return `signal ${result.signal}`;
3212
+ }
3213
+ if (result?.card === "terminal" && result.output !== void 0 && result.output !== "") {
3214
+ return escapeContent(result.output.replace(/\n/g, " "));
3215
+ }
3216
+ return card.callView?.card === "terminal" && card.callView.cwd !== void 0 ? escapeContent(card.callView.cwd) : void 0;
3217
+ case "diff": {
3218
+ const paths = card.callView?.card === "diff" ? card.callView.locations ?? card.callView.diffs.map((diff) => ({ path: diff.path })) : result.diffs.map((diff) => ({ path: diff.path }));
3219
+ return paths.length === 0 ? void 0 : escapeContent(paths.map((entry) => entry.path).join(" \xB7 "));
3220
+ }
3221
+ case "search":
3222
+ return result?.card === "search" ? `${String(result.total)} matches` : void 0;
3223
+ case "read":
3224
+ return result?.card === "read" ? escapeContent(result.path) : void 0;
3225
+ case "web":
3226
+ if (result?.card !== "web") return void 0;
3227
+ if (result.kind === "fetch") {
3228
+ return escapeContent(`${result.url} \xB7 ${String(result.statusCode)}`);
3229
+ }
3230
+ if (result.sources.length === 0) return void 0;
3231
+ return escapeContent(result.sources.length === 1 ? result.sources[0]?.title ?? result.sources[0]?.url : `${String(result.sources.length)} sources`);
3232
+ default:
3233
+ return card.callView === void 0 ? collapsedCardSummary(card.arguments) : void 0;
3234
+ }
3235
+ }
3236
+ function cardsFrom(content) {
3237
+ const pending = /* @__PURE__ */ new Map();
3238
+ const ordered = [];
3239
+ for (const item of content) {
3240
+ if (item.kind === "tool-call") {
3241
+ const card2 = {
3242
+ callId: item.callId,
3243
+ name: item.name,
3244
+ arguments: item.arguments,
3245
+ status: "running"
3246
+ };
3247
+ pending.set(item.callId, card2);
3248
+ ordered.push(card2);
3249
+ continue;
3250
+ }
3251
+ if (item.kind !== "tool-result") continue;
3252
+ const card = pending.get(item.callId);
3253
+ if (card === void 0) continue;
3254
+ card.status = item.isError ? "error" : "ok";
3255
+ card.resultText = item.text;
3256
+ if (item.meta !== void 0) card.meta = item.meta;
3257
+ if (item.error !== void 0) card.error = item.error;
3258
+ }
3259
+ return ordered;
3260
+ }
3261
+ function cardsFromActiveTurn(toolCalls, content = []) {
3262
+ const calls = toolCalls.map((call) => ({
3263
+ kind: "tool-call",
3264
+ callId: call.callId,
3265
+ name: call.name,
3266
+ arguments: call.arguments
3267
+ }));
3268
+ const results = content.filter(
3269
+ (item) => item.kind === "tool-result"
3270
+ );
3271
+ return cardsFrom([...calls, ...results]);
3272
+ }
3273
+ function cardsFromTurn(turn) {
3274
+ return cardsFromActiveTurn(turn.toolCalls, turn.content ?? []);
3275
+ }
3276
+ function attachPresenterViews(tools, card) {
3277
+ if (tools === void 0) return card;
3278
+ let args;
3279
+ try {
3280
+ args = JSON.parse(card.arguments);
3281
+ } catch {
3282
+ return card;
3283
+ }
3284
+ const def = tools.get(card.name);
3285
+ if (def === void 0) return card;
3286
+ let callView;
3287
+ try {
3288
+ const view = def.presentCall?.(args);
3289
+ if (view !== void 0 && typeof view.title === "string" && view.title !== "") {
3290
+ callView = view;
3291
+ }
3292
+ } catch {
3293
+ }
3294
+ let resultView;
3295
+ if (card.status !== "running") {
3296
+ try {
3297
+ const view = def.presentResult?.(args, {
3298
+ content: [{ type: "text", text: card.resultText ?? "" }],
3299
+ isError: card.status === "error",
3300
+ ...card.meta === void 0 ? {} : { meta: card.meta }
3301
+ });
3302
+ if (view !== void 0) {
3303
+ resultView = view;
3304
+ }
3305
+ } catch {
3306
+ }
3307
+ }
3308
+ if (callView === void 0 && resultView === void 0) return card;
3309
+ return {
3310
+ ...card,
3311
+ ...callView === void 0 ? {} : { callView },
3312
+ ...resultView === void 0 ? {} : { resultView }
3313
+ };
3314
+ }
3315
+ function parseSubagentArguments(argumentsJson) {
3316
+ if (argumentsJson === "" || argumentsJson === "{}") return void 0;
3317
+ try {
3318
+ const parsed = JSON.parse(argumentsJson);
3319
+ if (parsed !== null && typeof parsed === "object") {
3320
+ const obj = parsed;
3321
+ const description = typeof obj.description === "string" && obj.description !== "" ? obj.description : void 0;
3322
+ const prompt = typeof obj.prompt === "string" && obj.prompt !== "" ? obj.prompt : void 0;
3323
+ const model = typeof obj.model === "string" && obj.model !== "" ? obj.model : void 0;
3324
+ const runInBackground = typeof obj.run_in_background === "boolean" ? obj.run_in_background : void 0;
3325
+ if (description !== void 0 || prompt !== void 0 || model !== void 0) {
3326
+ return { description, prompt, model, runInBackground };
3327
+ }
3328
+ }
3329
+ } catch {
3330
+ }
3331
+ return void 0;
3332
+ }
3333
+ function collapsedCardSummary(argumentsJson) {
3334
+ if (argumentsJson === "") return void 0;
3335
+ let command;
3336
+ try {
3337
+ const parsed = JSON.parse(argumentsJson);
3338
+ if (parsed !== null && typeof parsed === "object") {
3339
+ const obj = parsed;
3340
+ if (typeof obj.command === "string" && obj.command !== "") {
3341
+ command = obj.command;
3342
+ } else if (typeof obj.description === "string" && obj.description !== "") {
3343
+ command = obj.description;
3344
+ } else if (typeof obj.prompt === "string" && obj.prompt !== "") {
3345
+ command = obj.prompt;
3346
+ } else if (typeof obj.query === "string" && obj.query !== "") {
3347
+ command = obj.query;
3348
+ } else if (typeof obj.task === "string" && obj.task !== "") {
3349
+ command = obj.task;
3350
+ }
3351
+ }
3352
+ } catch {
3353
+ }
3354
+ return escapeContent(command ?? argumentsJson).replace(/\n/g, " ");
3355
+ }
3356
+ function truncateDisplay(text, maxCols) {
3357
+ if (maxCols <= 0) return "";
3358
+ if (displayWidth(text) <= maxCols) return text;
3359
+ if (maxCols === 1) return "\u2026";
3360
+ return `${wcwidthSafeSlice(text, maxCols - 1)}\u2026`;
3361
+ }
3362
+ var FILE_PATH_KEYS = ["path", "file_path", "file", "target_file", "target"];
3363
+ function fileUrlFromToolArguments(argumentsJson) {
3364
+ try {
3365
+ const parsed = JSON.parse(argumentsJson);
3366
+ if (parsed === null || typeof parsed !== "object") return void 0;
3367
+ const record = parsed;
3368
+ for (const key of FILE_PATH_KEYS) {
3369
+ const value = record[key];
3370
+ if (typeof value !== "string" || !isAbsolute(value)) continue;
3371
+ if (/[\u0000-\u001f\u007f]/.test(value)) continue;
3372
+ return pathToFileURL(value).href;
3373
+ }
3374
+ } catch {
3375
+ }
3376
+ return void 0;
3377
+ }
3378
+ function tokenizeCommandHeading(heading) {
3379
+ const trimmed = heading.trimStart();
3380
+ const leading = heading.slice(0, heading.length - trimmed.length);
3381
+ const firstSpace = trimmed.indexOf(" ");
3382
+ const cmd = firstSpace === -1 ? trimmed : trimmed.slice(0, firstSpace);
3383
+ const rest = firstSpace === -1 ? "" : trimmed.slice(firstSpace);
3384
+ const tokens = [];
3385
+ if (leading !== "") tokens.push({ text: leading, token: "fgSoft" });
3386
+ if (cmd !== "") tokens.push({ text: cmd, token: "codeCommand" });
3387
+ if (rest !== "") tokens.push({ text: rest, token: "fgSoft" });
3388
+ return Object.freeze(tokens);
3389
+ }
3390
+
3172
3391
  // tui-render/src/tool-body.ts
3173
3392
  var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
3174
3393
  function textLines(text, prefix = "") {
@@ -3383,10 +3602,31 @@ function createToolBodyDocument(card, options) {
3383
3602
  }
3384
3603
  }
3385
3604
  break;
3386
- default:
3387
- args();
3605
+ default: {
3606
+ const isSubagent = card.name === "subagent" || card.name.startsWith("subagent_") || card.name === "delegate";
3607
+ const subInfo = isSubagent ? parseSubagentArguments(card.arguments) : void 0;
3608
+ if (subInfo !== void 0) {
3609
+ if (subInfo.description !== void 0) {
3610
+ section(options.locale === "zh-CN" ? "\u4EFB\u52A1\u76EE\u6807" : "Task", textLines(subInfo.description));
3611
+ }
3612
+ if (subInfo.model !== void 0) {
3613
+ section(options.locale === "zh-CN" ? "\u59D4\u6D3E\u6A21\u578B" : "Model", textLines(subInfo.model));
3614
+ }
3615
+ if (card.status === "running") {
3616
+ section(
3617
+ options.locale === "zh-CN" ? "\u8FD0\u884C\u72B6\u6001" : "Status",
3618
+ textLines(options.locale === "zh-CN" ? "\u25CF \u6B63\u5728\u6267\u884C\u5B50\u4EE3\u7406\u4EFB\u52A1..." : "\u25CF Running subagent task...")
3619
+ );
3620
+ }
3621
+ if (subInfo.prompt !== void 0) {
3622
+ section(options.locale === "zh-CN" ? "\u4EFB\u52A1\u6307\u4EE4" : "Prompt", textLines(subInfo.prompt));
3623
+ }
3624
+ } else {
3625
+ args();
3626
+ }
3388
3627
  if (card.resultText !== void 0) section(tuiCopy("result", options.locale), textLines(card.resultText));
3389
3628
  break;
3629
+ }
3390
3630
  }
3391
3631
  if (result === void 0 && kind !== "generic" && card.resultText !== void 0) {
3392
3632
  section(tuiCopy("result", options.locale), textLines(card.resultText));
@@ -3441,191 +3681,6 @@ function toolCardOriginalText(card, options) {
3441
3681
  `;
3442
3682
  }
3443
3683
 
3444
- // tui-render/src/tool-cards.ts
3445
- import { isAbsolute } from "node:path";
3446
- import { pathToFileURL } from "node:url";
3447
- function toolCardDisplayStatus(card) {
3448
- const terminal = card.resultView?.card === "terminal" ? card.resultView : void 0;
3449
- if (terminal?.signal !== void 0) return "error";
3450
- if (terminal?.exitCode !== void 0 && terminal.exitCode !== 0) return "error";
3451
- return card.status;
3452
- }
3453
- function collapsedResultTail(text) {
3454
- if (text === void 0) return void 0;
3455
- const line5 = text.split(/\r?\n/u).map((item) => item.trim()).filter(Boolean).at(-1);
3456
- return line5 === void 0 ? void 0 : escapeContent(line5);
3457
- }
3458
- function collapsedFailureSummary(card) {
3459
- const terminal = card.resultView?.card === "terminal" ? card.resultView : void 0;
3460
- const identity = terminal?.exitCode !== void 0 ? `exitCode ${String(terminal.exitCode)}` : terminal?.signal !== void 0 ? `signal ${terminal.signal}` : card.error?.code;
3461
- const detail = collapsedResultTail(terminal?.output ?? card.resultText);
3462
- if (identity === void 0) return detail;
3463
- return detail === void 0 || detail === identity ? identity : `${identity} \xB7 ${detail}`;
3464
- }
3465
- function collapsedToolCardSummary(card) {
3466
- if (toolCardDisplayStatus(card) === "error") {
3467
- const failure = collapsedFailureSummary(card);
3468
- if (failure !== void 0) return failure;
3469
- }
3470
- const result = card.resultView;
3471
- const kind = result?.card ?? card.callView?.card ?? "generic";
3472
- switch (kind) {
3473
- case "terminal":
3474
- if (result?.card === "terminal" && result.exitCode !== void 0) {
3475
- return `exitCode ${String(result.exitCode)}`;
3476
- }
3477
- if (result?.card === "terminal" && result.signal !== void 0) {
3478
- return `signal ${result.signal}`;
3479
- }
3480
- if (result?.card === "terminal" && result.output !== void 0 && result.output !== "") {
3481
- return escapeContent(result.output.replace(/\n/g, " "));
3482
- }
3483
- return card.callView?.card === "terminal" && card.callView.cwd !== void 0 ? escapeContent(card.callView.cwd) : void 0;
3484
- case "diff": {
3485
- const paths = card.callView?.card === "diff" ? card.callView.locations ?? card.callView.diffs.map((diff) => ({ path: diff.path })) : result.diffs.map((diff) => ({ path: diff.path }));
3486
- return paths.length === 0 ? void 0 : escapeContent(paths.map((entry) => entry.path).join(" \xB7 "));
3487
- }
3488
- case "search":
3489
- return result?.card === "search" ? `${String(result.total)} matches` : void 0;
3490
- case "read":
3491
- return result?.card === "read" ? escapeContent(result.path) : void 0;
3492
- case "web":
3493
- if (result?.card !== "web") return void 0;
3494
- if (result.kind === "fetch") {
3495
- return escapeContent(`${result.url} \xB7 ${String(result.statusCode)}`);
3496
- }
3497
- if (result.sources.length === 0) return void 0;
3498
- return escapeContent(result.sources.length === 1 ? result.sources[0]?.title ?? result.sources[0]?.url : `${String(result.sources.length)} sources`);
3499
- default:
3500
- return card.callView === void 0 ? collapsedCardSummary(card.arguments) : void 0;
3501
- }
3502
- }
3503
- function cardsFrom(content) {
3504
- const pending = /* @__PURE__ */ new Map();
3505
- const ordered = [];
3506
- for (const item of content) {
3507
- if (item.kind === "tool-call") {
3508
- const card2 = {
3509
- callId: item.callId,
3510
- name: item.name,
3511
- arguments: item.arguments,
3512
- status: "running"
3513
- };
3514
- pending.set(item.callId, card2);
3515
- ordered.push(card2);
3516
- continue;
3517
- }
3518
- if (item.kind !== "tool-result") continue;
3519
- const card = pending.get(item.callId);
3520
- if (card === void 0) continue;
3521
- card.status = item.isError ? "error" : "ok";
3522
- card.resultText = item.text;
3523
- if (item.meta !== void 0) card.meta = item.meta;
3524
- if (item.error !== void 0) card.error = item.error;
3525
- }
3526
- return ordered;
3527
- }
3528
- function cardsFromActiveTurn(toolCalls, content = []) {
3529
- const calls = toolCalls.map((call) => ({
3530
- kind: "tool-call",
3531
- callId: call.callId,
3532
- name: call.name,
3533
- arguments: call.arguments
3534
- }));
3535
- const results = content.filter(
3536
- (item) => item.kind === "tool-result"
3537
- );
3538
- return cardsFrom([...calls, ...results]);
3539
- }
3540
- function cardsFromTurn(turn) {
3541
- return cardsFromActiveTurn(turn.toolCalls, turn.content ?? []);
3542
- }
3543
- function attachPresenterViews(tools, card) {
3544
- if (tools === void 0) return card;
3545
- let args;
3546
- try {
3547
- args = JSON.parse(card.arguments);
3548
- } catch {
3549
- return card;
3550
- }
3551
- const def = tools.get(card.name);
3552
- if (def === void 0) return card;
3553
- let callView;
3554
- try {
3555
- const view = def.presentCall?.(args);
3556
- if (view !== void 0 && typeof view.title === "string" && view.title !== "") {
3557
- callView = view;
3558
- }
3559
- } catch {
3560
- }
3561
- let resultView;
3562
- if (card.status !== "running") {
3563
- try {
3564
- const view = def.presentResult?.(args, {
3565
- content: [{ type: "text", text: card.resultText ?? "" }],
3566
- isError: card.status === "error",
3567
- ...card.meta === void 0 ? {} : { meta: card.meta }
3568
- });
3569
- if (view !== void 0) {
3570
- resultView = view;
3571
- }
3572
- } catch {
3573
- }
3574
- }
3575
- if (callView === void 0 && resultView === void 0) return card;
3576
- return {
3577
- ...card,
3578
- ...callView === void 0 ? {} : { callView },
3579
- ...resultView === void 0 ? {} : { resultView }
3580
- };
3581
- }
3582
- function collapsedCardSummary(argumentsJson) {
3583
- if (argumentsJson === "") return void 0;
3584
- let command;
3585
- try {
3586
- const parsed = JSON.parse(argumentsJson);
3587
- if (parsed !== null && typeof parsed === "object" && "command" in parsed && typeof parsed.command === "string") {
3588
- command = parsed.command;
3589
- }
3590
- } catch {
3591
- }
3592
- return escapeContent(command ?? argumentsJson).replace(/\n/g, " ");
3593
- }
3594
- function truncateDisplay(text, maxCols) {
3595
- if (maxCols <= 0) return "";
3596
- if (displayWidth(text) <= maxCols) return text;
3597
- if (maxCols === 1) return "\u2026";
3598
- return `${wcwidthSafeSlice(text, maxCols - 1)}\u2026`;
3599
- }
3600
- var FILE_PATH_KEYS = ["path", "file_path", "file", "target_file", "target"];
3601
- function fileUrlFromToolArguments(argumentsJson) {
3602
- try {
3603
- const parsed = JSON.parse(argumentsJson);
3604
- if (parsed === null || typeof parsed !== "object") return void 0;
3605
- const record = parsed;
3606
- for (const key of FILE_PATH_KEYS) {
3607
- const value = record[key];
3608
- if (typeof value !== "string" || !isAbsolute(value)) continue;
3609
- if (/[\u0000-\u001f\u007f]/.test(value)) continue;
3610
- return pathToFileURL(value).href;
3611
- }
3612
- } catch {
3613
- }
3614
- return void 0;
3615
- }
3616
- function tokenizeCommandHeading(heading) {
3617
- const trimmed = heading.trimStart();
3618
- const leading = heading.slice(0, heading.length - trimmed.length);
3619
- const firstSpace = trimmed.indexOf(" ");
3620
- const cmd = firstSpace === -1 ? trimmed : trimmed.slice(0, firstSpace);
3621
- const rest = firstSpace === -1 ? "" : trimmed.slice(firstSpace);
3622
- const tokens = [];
3623
- if (leading !== "") tokens.push({ text: leading, token: "fgSoft" });
3624
- if (cmd !== "") tokens.push({ text: cmd, token: "codeCommand" });
3625
- if (rest !== "") tokens.push({ text: rest, token: "fgSoft" });
3626
- return Object.freeze(tokens);
3627
- }
3628
-
3629
3684
  // tui-render/src/tool-rows.ts
3630
3685
  var graphemes2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
3631
3686
  function truncateMiddleDisplay(text, maxCols, leadingShare = 0.5) {
@@ -3668,8 +3723,48 @@ function toolRow(parts, index, width, background) {
3668
3723
  }
3669
3724
  function toolHeadingRow(card, width, expanded, locale) {
3670
3725
  const status = toolCardDisplayStatus(card);
3671
- const label = status === "ok" ? "\u2713" : tuiCopy(status === "error" ? "failed" : "running", locale);
3672
3726
  const glyph = expanded ? "\u25BE" : "\u25B8";
3727
+ const isSubagent = card.name === "subagent" || card.name.startsWith("subagent_") || card.name === "delegate";
3728
+ const subagentInfo = isSubagent ? parseSubagentArguments(card.arguments) : void 0;
3729
+ if (isSubagent) {
3730
+ const statusLabel = status === "ok" ? locale === "zh-CN" ? "\u2713 \u5DF2\u5B8C\u6210" : "\u2713 completed" : status === "error" ? locale === "zh-CN" ? "\u2717 \u5931\u8D25" : "\u2717 failed" : locale === "zh-CN" ? "\u25CF \u8FD0\u884C\u4E2D" : "\u25CF running";
3731
+ const statusToken2 = status === "error" ? "error" : status === "running" ? "accentText" : "success";
3732
+ const glyphToken = status === "running" ? "accentText" : "fgDim";
3733
+ const tag = locale === "zh-CN" ? "[\u5B50\u4EE3\u7406] " : "[Subagent] ";
3734
+ if (width < displayWidth(`${glyph} \u2026 \xB7 ${statusLabel}`)) {
3735
+ return toolRow([{ text: truncateDisplay(`${glyph} ${statusLabel}`, width), token: statusToken2 }], 0, width, "toolBg");
3736
+ }
3737
+ const headingText = subagentInfo?.description !== void 0 && subagentInfo.description !== "" ? subagentInfo.description : card.resultView?.title ?? card.callView?.title ?? card.name;
3738
+ const heading2 = escapeContent(headingText).replace(/[\n\t]/gu, " ");
3739
+ const prefixBudget = displayWidth(`${glyph} ${tag} \xB7 ${statusLabel}`);
3740
+ const fitted2 = truncateMiddleDisplay(heading2, Math.max(1, width - prefixBudget), 0.6);
3741
+ const parts2 = [
3742
+ { text: `${glyph} `, token: glyphToken },
3743
+ { text: tag, token: "codeKeyword" },
3744
+ { text: `${fitted2} \xB7 `, token: "fg" },
3745
+ { text: statusLabel, token: statusToken2 }
3746
+ ];
3747
+ if (subagentInfo?.model !== void 0) {
3748
+ parts2.push({ text: ` [${subagentInfo.model}]`, token: "markdownCode" });
3749
+ }
3750
+ let summary2;
3751
+ if (status === "error") {
3752
+ summary2 = collapsedToolCardSummary(card);
3753
+ } else if (!expanded) {
3754
+ if (subagentInfo?.prompt !== void 0 && subagentInfo.prompt !== "") {
3755
+ summary2 = escapeContent(subagentInfo.prompt).replace(/\n/g, " ");
3756
+ } else {
3757
+ summary2 = collapsedToolCardSummary(card);
3758
+ }
3759
+ }
3760
+ const available2 = width - parts2.reduce((sum, part) => sum + displayWidth(part.text), 0) - 1;
3761
+ const href2 = fileUrlFromToolArguments(card.arguments);
3762
+ if (summary2 !== void 0 && available2 >= 2) {
3763
+ parts2.push({ text: ` ${truncateDisplay(summary2, available2)}`, token: "fgSoft", ...href2 === void 0 ? {} : { href: href2 } });
3764
+ }
3765
+ return toolRow(parts2, 0, width, "toolBg");
3766
+ }
3767
+ const label = status === "ok" ? "\u2713" : tuiCopy(status === "error" ? "failed" : "running", locale);
3673
3768
  if (width < displayWidth(`${glyph} \u2026 \xB7 ${label}`)) return toolRow([{ text: truncateDisplay(`${glyph} ${label}`, width), token: status === "error" ? "error" : "fgDim" }], 0, width, "toolBg");
3674
3769
  const heading = escapeContent(card.resultView?.title ?? card.callView?.title ?? card.name).replace(/[\n\t]/gu, " ");
3675
3770
  const terminal = card.callView?.card === "terminal" || card.resultView?.card === "terminal";
@@ -3741,6 +3836,9 @@ function toolBodyRenderRow(line5, index, width) {
3741
3836
  if (diffKind !== void 0) {
3742
3837
  return toolRow(formatDiffParts(line5.text, diffKind), index, width, bg);
3743
3838
  }
3839
+ if (line5.text.includes("\u25CF \u6B63\u5728\u6267\u884C") || line5.text.includes("\u25CF Running")) {
3840
+ return toolRow([{ text: ` ${line5.text}`, token: "accentText" }], index, width, bg);
3841
+ }
3744
3842
  return toolRow([{ text: ` ${line5.text}`, token: line5.token === "codeBg" ? "fgSoft" : "fgDim" }], index, width, bg);
3745
3843
  }
3746
3844
  function toolRemainingRow(remaining, width, index, locale) {
@@ -9634,12 +9732,14 @@ function fitValue(value, maxCols) {
9634
9732
  if (budget <= 0) return wcwidthSafeSlice(VALUE_ELLIPSIS, maxCols);
9635
9733
  return `${wcwidthSafeSlice(value, budget)}${VALUE_ELLIPSIS}`;
9636
9734
  }
9637
- function fieldRow(label, value, selected, columns) {
9735
+ function fieldRow(label, value, selected, columns, required = false) {
9638
9736
  const marker = selected ? styled(escapeContent("\u203A "), "accent", void 0, true) : " ";
9737
+ const reqMark = required ? styled("* ", "error", void 0, true) : "";
9738
+ const reqWidth = required ? 2 : 0;
9639
9739
  const escapedLabel = escapeContent(label);
9640
9740
  const escapedValue = escapeContent(value);
9641
- const labelToken = selected ? "fg" : "fgDim";
9642
- const labelCols = MARKER_COLS + displayWidth(escapedLabel);
9741
+ const labelToken = selected ? "fg" : "fgSoft";
9742
+ const labelCols = MARKER_COLS + reqWidth + displayWidth(escapedLabel);
9643
9743
  const valueBudget = Math.max(0, columns - labelCols - VALUE_GAP);
9644
9744
  const fittedValue = fitValue(escapedValue, valueBudget);
9645
9745
  const gap = Math.max(
@@ -9648,9 +9748,10 @@ function fieldRow(label, value, selected, columns) {
9648
9748
  );
9649
9749
  return [
9650
9750
  marker,
9751
+ ...required ? [reqMark] : [],
9651
9752
  styled(escapedLabel, labelToken),
9652
- styled(" ".repeat(gap), "bg"),
9653
- ...fittedValue === "" ? [] : [styled(fittedValue, "fgDim")]
9753
+ styled(" ".repeat(gap), "settingsCardBg"),
9754
+ ...fittedValue === "" ? [] : [styled(fittedValue, selected ? "fg" : "fgDim")]
9654
9755
  ];
9655
9756
  }
9656
9757
  function computeSettingsWindow(maxRows, totalRows, errorReason) {
@@ -9683,25 +9784,35 @@ function SettingsPane({
9683
9784
  rows.length - size
9684
9785
  );
9685
9786
  const visible = rows.slice(start, start + size);
9787
+ const renderLine = (text, token, bold = false) => /* @__PURE__ */ jsx14(Box14, { width: "100%", children: /* @__PURE__ */ jsx14(Text14, { children: paintBackgroundRow([styled(escapeContent(text), token, void 0, bold)], "settingsCardBg", width) }) });
9686
9788
  return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", width: "100%", children: [
9687
- renderPaneLine(onboarding === true ? ONBOARDING_TITLE : TITLE2, "fg", true),
9688
- start > 0 ? renderPaneLine(`\u2026 \u8FD8\u6709 ${String(start)} \u9879`, "fgDim") : null,
9789
+ renderLine(onboarding === true ? ONBOARDING_TITLE : TITLE2, "fg", true),
9790
+ start > 0 ? renderLine(`\u2026 \u8FD8\u6709 ${String(start)} \u9879`, "fgDim") : null,
9689
9791
  visible.map((row, index) => {
9690
9792
  const absolute = start + index;
9691
9793
  const selected = absolute === selectedIndex;
9692
- const localized = row.namespace === "tui" && (row.field === "reasoning" || row.field === "scrollbar" || row.field === "statusDetails" || row.field === "locale") ? `${row.field} \xB7 ${tuiCopy(row.field, locale)}` : row.field === "apiKeyEnv" ? `${row.field} \xB7 \u73AF\u5883\u53D8\u91CF\u540D` : row.field;
9693
- const label = `${row.namespace} \xB7 ${localized}`;
9694
- return /* @__PURE__ */ jsx14(Box14, { width: "100%", children: /* @__PURE__ */ jsx14(Text14, { children: paintRow(fieldRow(label, row.value, selected, width)) }) }, `${row.namespace}:${row.field}`);
9794
+ let localized;
9795
+ if (row.label !== void 0) {
9796
+ localized = row.label;
9797
+ } else if (row.namespace === "tui" && (row.field === "reasoning" || row.field === "scrollbar" || row.field === "statusDetails" || row.field === "locale")) {
9798
+ localized = `${row.field} \xB7 ${tuiCopy(row.field, locale)}`;
9799
+ } else if (row.field === "apiKeyEnv") {
9800
+ localized = `${row.field} \xB7 \u73AF\u5883\u53D8\u91CF\u540D`;
9801
+ } else {
9802
+ localized = row.field;
9803
+ }
9804
+ const label = row.label === void 0 ? `${row.namespace} \xB7 ${localized}` : localized;
9805
+ return /* @__PURE__ */ jsx14(Box14, { width: "100%", children: /* @__PURE__ */ jsx14(Text14, { children: paintBackgroundRow(fieldRow(label, row.value, selected, width, row.required === true), "settingsCardBg", width) }) }, `${row.namespace}:${row.field}`);
9695
9806
  }),
9696
- rows.length > start + size ? renderPaneLine(`\u2026 \u8FD8\u6709 ${String(rows.length - start - size)} \u9879`, "fgDim") : null,
9697
- errorReason !== void 0 ? /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", width: "100%", children: [
9698
- renderPaneLine(
9807
+ rows.length > start + size ? renderLine(`\u2026 \u8FD8\u6709 ${String(rows.length - start - size)} \u9879`, "fgDim") : null,
9808
+ errorReason === void 0 ? null : /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", width: "100%", children: [
9809
+ renderLine(
9699
9810
  errorReason === EMPTY_TABLE_REASON2 ? EMPTY_TABLE_REASON2 : `\u2717 \u66F4\u65B0\u5931\u8D25\uFF1A${errorReason}`,
9700
9811
  "error"
9701
9812
  ),
9702
- errorReason === EMPTY_TABLE_REASON2 ? null : renderPaneLine(FAIL_NEXT2, "fgDim")
9703
- ] }) : null,
9704
- renderPaneLine(footnote, "fgDim")
9813
+ errorReason === EMPTY_TABLE_REASON2 ? null : renderLine(FAIL_NEXT2, "fgDim")
9814
+ ] }),
9815
+ renderLine(footnote, "fgDim")
9705
9816
  ] });
9706
9817
  }
9707
9818
 
@@ -13838,6 +13949,7 @@ export {
13838
13949
  notifyBytes,
13839
13950
  paintBackgroundRow,
13840
13951
  paintRow,
13952
+ parseSubagentArguments,
13841
13953
  physicalLineIdentity,
13842
13954
  physicalScrollRailGeometry,
13843
13955
  planToolBodyWindow,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crazyhappyone/dsh-tui",
3
- "version": "0.1.0-alpha.27",
3
+ "version": "0.1.0-alpha.29",
4
4
  "description": "Source-runtime launcher for the DeepSeek Harness terminal interface",
5
5
  "type": "module",
6
6
  "license": "MIT",
Binary file