dsh-edge 0.2.0 → 0.3.0-alpha.2

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.
@@ -2893,14 +2893,52 @@ window.__ModuleLoader__.load({
2893
2893
  const whole = Math.round(s);
2894
2894
  return `${Math.floor(whole / 60)}m${whole % 60}s`;
2895
2895
  }
2896
+ /** Round a cache-read ratio to an integer percentage, with positive ties rounded up. */
2897
+ function roundedIntegerPercent(cacheReadTokens, denominator) {
2898
+ const denominatorQuotient = Math.floor(denominator / 200);
2899
+ const denominatorRemainder = denominator % 200;
2900
+ let lower = 0;
2901
+ let upper = 100;
2902
+ while (lower < upper) {
2903
+ const candidate = Math.floor((lower + upper + 1) / 2);
2904
+ const factor = candidate * 2 - 1;
2905
+ if (cacheReadTokens >= factor * denominatorQuotient + Math.ceil(factor * denominatorRemainder / 200)) lower = candidate;
2906
+ else upper = candidate - 1;
2907
+ }
2908
+ return lower;
2909
+ }
2896
2910
  /**
2897
- * Cache-hit share of prompt-side input over the whole durable log.
2911
+ * Display-ready cache-hit share of prompt-side input over the whole durable log.
2898
2912
  * @param usage - the session's token-usage projection value.
2899
- * @returns rounded integer percent, or null when no input was billed.
2913
+ * @returns integer text when integer rounding stays below 100, otherwise the
2914
+ * minimum decimal precision that still rounds below 100; a full hit returns
2915
+ * 100, and no billed input returns null.
2900
2916
  */
2901
2917
  function cacheHitPercent(usage) {
2902
2918
  const denominator = billedInputTokens(usage);
2903
- return denominator === 0 ? null : Math.round(usage.cacheReadTokens / denominator * 100);
2919
+ if (denominator === 0) return null;
2920
+ const missedInputTokens = usage.uncachedInputTokens + usage.cacheWriteTokens;
2921
+ if (missedInputTokens === 0) return "100";
2922
+ const integerPercent = roundedIntegerPercent(usage.cacheReadTokens, denominator);
2923
+ if (integerPercent < 100) return String(integerPercent);
2924
+ let decimalPlaces = 1;
2925
+ let scaledDoubleGap = missedInputTokens * 200;
2926
+ const denominatorTens = Math.floor(denominator / 10);
2927
+ while (scaledDoubleGap <= denominatorTens) {
2928
+ scaledDoubleGap *= 10;
2929
+ decimalPlaces += 1;
2930
+ }
2931
+ const denominatorOnes = denominator % 10;
2932
+ let roundedLoss = 5;
2933
+ for (let loss = 1; loss < 5; loss += 1) {
2934
+ const factor = loss * 2 + 1;
2935
+ const threshold = factor * denominatorTens + Math.floor(factor * denominatorOnes / 10);
2936
+ if (scaledDoubleGap <= threshold) {
2937
+ roundedLoss = loss;
2938
+ break;
2939
+ }
2940
+ }
2941
+ return `99.${"9".repeat(decimalPlaces - 1)}${10 - roundedLoss}`;
2904
2942
  }
2905
2943
  /**
2906
2944
  * Sum the three disjoint prompt-side billing buckets.
@@ -3203,8 +3241,8 @@ window.__ModuleLoader__.load({
3203
3241
  //#region lib/types/client/skeleton/PermissionSelect.js
3204
3242
  const FULL_ACCESS = "danger-full-access";
3205
3243
  const shieldOutline = "M8.20554 0.899994L14.7901 3.36857V7.01026C14.7901 12 11.0466 14.2103 8.20554 15.3C5.36446 14.2103 1.62012 12 1.62012 7.01026V3.36857L8.20554 0.899994Z";
3206
- const permissionGlyphs = {
3207
- "read-only": (0, react_jsx_runtime.jsxs)("svg", {
3244
+ const permissionGlyphs = new Map([
3245
+ ["read-only", (0, react_jsx_runtime.jsxs)("svg", {
3208
3246
  width: "16",
3209
3247
  height: "16",
3210
3248
  viewBox: "0 0 16 16",
@@ -3219,8 +3257,8 @@ window.__ModuleLoader__.load({
3219
3257
  d: "M12.1654 5.7552L8.9447 9.41475C8.73044 9.65816 8.53628 9.8804 8.35774 10.0423C8.1713 10.2114 7.94235 10.3717 7.64016 10.4254C7.48207 10.4535 7.32 10.4552 7.16151 10.4294C6.85843 10.3801 6.62728 10.2223 6.43836 10.0559C6.25752 9.89653 6.06037 9.67732 5.84264 9.43705L4.72925 8.20897L5.63557 7.38707L6.74897 8.61594C6.98603 8.87755 7.12974 9.03533 7.24673 9.13839C7.31033 9.19443 7.34485 9.21476 7.35823 9.22122C7.38068 9.22484 7.40352 9.22515 7.42593 9.22122C7.40522 9.22502 7.42893 9.23294 7.53583 9.136C7.65132 9.03126 7.79316 8.87139 8.02643 8.60638L11.2479 4.94763L12.1654 5.7552Z",
3220
3258
  fill: "currentColor"
3221
3259
  })]
3222
- }),
3223
- "workspace-write": (0, react_jsx_runtime.jsxs)("svg", {
3260
+ })],
3261
+ ["workspace-write", (0, react_jsx_runtime.jsxs)("svg", {
3224
3262
  width: "16",
3225
3263
  height: "16",
3226
3264
  viewBox: "0 0 16 16",
@@ -3248,8 +3286,8 @@ window.__ModuleLoader__.load({
3248
3286
  fill: "currentColor"
3249
3287
  })
3250
3288
  ]
3251
- }),
3252
- [FULL_ACCESS]: (0, react_jsx_runtime.jsxs)("svg", {
3289
+ })],
3290
+ [FULL_ACCESS, (0, react_jsx_runtime.jsxs)("svg", {
3253
3291
  width: "16",
3254
3292
  height: "16",
3255
3293
  viewBox: "0 0 16 16",
@@ -3271,25 +3309,33 @@ window.__ModuleLoader__.load({
3271
3309
  fill: "currentColor"
3272
3310
  })
3273
3311
  ]
3274
- })
3275
- };
3312
+ })]
3313
+ ]);
3276
3314
  /** Glyph for a permission option value; host-configured names outside the design set get none. */
3277
3315
  function permissionGlyph(value) {
3278
- return permissionGlyphs[value];
3316
+ return permissionGlyphs.get(value);
3279
3317
  }
3280
3318
  /**
3281
- * Display transform: kebab-case machine names render as title-case labels
3282
- * (`workspace-write` → `Workspace Write`); non-kebab host-configured names
3283
- * pass through. Full access intentionally overrides the machine-name
3284
- * transform so both permission surfaces use the product label `Full access`;
3285
- * the warning body remains locale-aware.
3319
+ * Display transform: built-in machine names render as locale product labels;
3320
+ * non-kebab host-configured names pass through.
3286
3321
  */
3287
3322
  function displayName(name) {
3288
3323
  if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) return name;
3289
3324
  return name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
3290
3325
  }
3291
- function optionLabel(option) {
3292
- return option.value === FULL_ACCESS ? "Full access" : displayName(option.name);
3326
+ const BUILT_IN_PERMISSION_NAMES = new Map([
3327
+ ["read-only", "Read Only"],
3328
+ ["workspace-write", "Workspace Write"],
3329
+ [FULL_ACCESS, "Full access"]
3330
+ ]);
3331
+ function permissionLabel(value, name, t) {
3332
+ const builtInName = BUILT_IN_PERMISSION_NAMES.get(value);
3333
+ if (builtInName !== void 0 && (name === value || name === builtInName)) {
3334
+ if (value === "read-only") return t("access.preset.readOnly");
3335
+ if (value === "workspace-write") return t("access.preset.workspaceWrite");
3336
+ if (value === FULL_ACCESS) return t("access.preset.fullAccess");
3337
+ }
3338
+ return displayName(name);
3293
3339
  }
3294
3340
  function PermissionSelect({ value, locked, command, t }) {
3295
3341
  const [pick, setPick] = (0, react.useState)(null);
@@ -3305,12 +3351,13 @@ window.__ModuleLoader__.load({
3305
3351
  if (value === void 0) return null;
3306
3352
  const currentValue = pick ?? value.currentValue;
3307
3353
  const current = value.options.find((option) => option.value === currentValue);
3354
+ const currentLabel = current === void 0 ? permissionLabel(currentValue, currentValue, t) : permissionLabel(current.value, current.name, t);
3308
3355
  const busy = pick !== null || confirmation !== null;
3309
3356
  const items = value.options.filter((o) => o.value !== "custom").map((option) => {
3310
3357
  const icon = permissionGlyph(option.value);
3311
3358
  return {
3312
3359
  id: option.value,
3313
- label: optionLabel(option),
3360
+ label: permissionLabel(option.value, option.name, t),
3314
3361
  ...icon === void 0 ? {} : { icon }
3315
3362
  };
3316
3363
  });
@@ -3352,7 +3399,7 @@ window.__ModuleLoader__.load({
3352
3399
  anchor: (0, react_jsx_runtime.jsxs)("button", {
3353
3400
  type: "button",
3354
3401
  className: PermissionSelect_module_css_default.trigger,
3355
- "aria-label": t("input.accessMode", { name: current === void 0 ? displayName(currentValue) : optionLabel(current) }),
3402
+ "aria-label": t("input.accessMode", { name: currentLabel }),
3356
3403
  title: current?.description,
3357
3404
  disabled: locked || busy,
3358
3405
  onClick: () => {
@@ -3366,7 +3413,7 @@ window.__ModuleLoader__.load({
3366
3413
  }),
3367
3414
  (0, react_jsx_runtime.jsx)("span", {
3368
3415
  className: PermissionSelect_module_css_default.triggerLabel,
3369
- children: current === void 0 ? displayName(currentValue) : optionLabel(current)
3416
+ children: currentLabel
3370
3417
  }),
3371
3418
  (0, react_jsx_runtime.jsx)("span", {
3372
3419
  className: clsx(PermissionSelect_module_css_default.chevron, open && PermissionSelect_module_css_default.chevronOpen),
@@ -3484,6 +3531,41 @@ window.__ModuleLoader__.load({
3484
3531
  textRefs: [],
3485
3532
  hint: null
3486
3533
  };
3534
+ /**
3535
+ * Resolve one edit's range from the record taken before it applied.
3536
+ * A selection the edit replaces is the range outright. A caret delete replaces
3537
+ * nothing and reports the bare caret, so the removed span is whatever the draft
3538
+ * lost, on the side `inputType` names — measured, because one caret gesture can
3539
+ * remove a multi-unit grapheme, a word, or a line.
3540
+ * @param pending - record taken at `beforeinput`, null when none was seen.
3541
+ * @param prevLength - length of the draft the edit applied to.
3542
+ * @param nextLength - length of the resulting draft.
3543
+ * @returns the exact range, or undefined when the record cannot describe this
3544
+ * edit and the machine's diff scan has to recover it.
3545
+ */
3546
+ function editRangeOf(pending, prevLength, nextLength) {
3547
+ if (pending === null || pending.draftLength !== prevLength) return void 0;
3548
+ const { start, end, inputType } = pending;
3549
+ if (start > end || end > prevLength) return void 0;
3550
+ const insertedLength = nextLength - prevLength + (end - start);
3551
+ if (insertedLength >= 0) return {
3552
+ start,
3553
+ end,
3554
+ insertedLength
3555
+ };
3556
+ if (start !== end) return void 0;
3557
+ const removed = prevLength - nextLength;
3558
+ if (inputType.endsWith("Backward")) return removed <= start ? {
3559
+ start: start - removed,
3560
+ end: start,
3561
+ insertedLength: 0
3562
+ } : void 0;
3563
+ if (inputType.endsWith("Forward")) return start + removed <= prevLength ? {
3564
+ start,
3565
+ end: start + removed,
3566
+ insertedLength: 0
3567
+ } : void 0;
3568
+ }
3487
3569
  function InputBar({ useSession, useInput, inputActions, keyboard, addImages, removeImage, draftImages, resolveSubmitMode, toggleCommandMenu, stop, command, t, renderSlot, useNotices, useLexicon, useMenuLauncher, useProjection, sessionId, variant, disabled: inert = false, blocked, workspacePickerOpen = false, onRequestWorkspace, placeholder, accessory, overlay, leftItems, rightItems, footer }) {
3488
3570
  const input = useInput((s) => s);
3489
3571
  const notice = useNotices((s) => s);
@@ -3621,6 +3703,28 @@ window.__ModuleLoader__.load({
3621
3703
  start: el.selectionStart ?? 0,
3622
3704
  end: el.selectionEnd ?? el.selectionStart ?? 0
3623
3705
  });
3706
+ const pendingEditRef = (0, react.useRef)(null);
3707
+ (0, react.useEffect)(() => {
3708
+ const el = inputRef.current;
3709
+ if (el === null) return;
3710
+ const onBeforeInput = (e) => {
3711
+ if (!e.inputType.startsWith("insert") && !e.inputType.startsWith("delete")) {
3712
+ pendingEditRef.current = null;
3713
+ return;
3714
+ }
3715
+ const { start, end } = selectionOf(el);
3716
+ pendingEditRef.current = {
3717
+ start,
3718
+ end,
3719
+ draftLength: el.value.length,
3720
+ inputType: e.inputType
3721
+ };
3722
+ };
3723
+ el.addEventListener("beforeinput", onBeforeInput);
3724
+ return () => {
3725
+ el.removeEventListener("beforeinput", onBeforeInput);
3726
+ };
3727
+ }, []);
3624
3728
  const onKeyDown = (e) => {
3625
3729
  if (workspaceTrigger) {
3626
3730
  if (e.key === "Enter" || e.key === " ") {
@@ -3692,8 +3796,10 @@ window.__ModuleLoader__.load({
3692
3796
  if (keyboard === void 0 || locked) return;
3693
3797
  if (machineBusy) return;
3694
3798
  const next = e.target.value;
3799
+ const pending = pendingEditRef.current;
3800
+ pendingEditRef.current = null;
3695
3801
  safariNativeShrinkRef.current = safari && next.length < draft.length;
3696
- keyboard.setDraft(next);
3802
+ keyboard.setDraft(next, editRangeOf(pending, draft.length, next.length));
3697
3803
  keyboard.track(next, e.target.selectionStart ?? next.length);
3698
3804
  };
3699
3805
  const onCopyOrCut = (e, cut) => {
@@ -3742,12 +3848,14 @@ window.__ModuleLoader__.load({
3742
3848
  keyboard.track(keyboard.snapshot.draft, caret);
3743
3849
  };
3744
3850
  const intakeImages = (0, react.useCallback)((files) => {
3745
- if (imageLimits === void 0 || addImages === void 0 || files.length === 0) return;
3851
+ if (addImages === void 0 || files.length === 0) return;
3746
3852
  const rejected = (() => {
3747
- if (files.some((file) => !imageLimits.mediaTypes.includes(file.type))) return addImages(files);
3748
- if (attachments.length + files.length > imageLimits.maxImagesPerMessage) return t("image.tooMany", { count: imageLimits.maxImagesPerMessage });
3749
- if (files.some((file) => file.size > imageLimits.maxImageBytes)) return t("image.fileTooLarge", { size: imageSizeText(imageLimits.maxImageBytes) });
3750
- if (attachments.reduce((sum, attachment) => sum + attachment.file.size, 0) + files.reduce((sum, file) => sum + file.size, 0) > imageLimits.maxMessageImageBytes) return t("image.totalTooLarge", { size: imageSizeText(imageLimits.maxMessageImageBytes) });
3853
+ if (imageLimits !== void 0) {
3854
+ if (files.some((file) => !imageLimits.mediaTypes.includes(file.type))) return addImages(files);
3855
+ if (attachments.length + files.length > imageLimits.maxImagesPerMessage) return t("image.tooMany", { count: imageLimits.maxImagesPerMessage });
3856
+ if (files.some((file) => file.size > imageLimits.maxImageBytes)) return t("image.fileTooLarge", { size: imageSizeText(imageLimits.maxImageBytes) });
3857
+ if (attachments.reduce((sum, attachment) => sum + attachment.file.size, 0) + files.reduce((sum, file) => sum + file.size, 0) > imageLimits.maxMessageImageBytes) return t("image.totalTooLarge", { size: imageSizeText(imageLimits.maxMessageImageBytes) });
3858
+ }
3751
3859
  return addImages(files);
3752
3860
  })();
3753
3861
  if (rejected !== null) showToast(rejected);
@@ -3758,7 +3866,7 @@ window.__ModuleLoader__.load({
3758
3866
  showToast,
3759
3867
  t
3760
3868
  ]);
3761
- const canAcceptDrop = !locked && !machineBusy && imageLimits !== void 0 && addImages !== void 0;
3869
+ const canAcceptDrop = !locked && !machineBusy && addImages !== void 0;
3762
3870
  const onSelect = (e) => {
3763
3871
  if (keyboard !== void 0 && keyboard.snapshot.paste !== void 0) keyboard.invalidatePaste();
3764
3872
  };
@@ -3808,10 +3916,11 @@ window.__ModuleLoader__.load({
3808
3916
  at: chip.offset,
3809
3917
  kind: "chip",
3810
3918
  chip
3811
- })), ...deco.textRefs.map((ref) => ({
3919
+ })), ...deco.textRefs.map((ref, ordinal) => ({
3812
3920
  at: ref.start,
3813
3921
  kind: "text-ref",
3814
- ref
3922
+ ref,
3923
+ ordinal
3815
3924
  }))].sort((a, b) => a.at - b.at);
3816
3925
  for (const b of boundaries) {
3817
3926
  if (b.at < cursor) continue;
@@ -3854,7 +3963,7 @@ window.__ModuleLoader__.load({
3854
3963
  className: InputBar_module_css_default.textRefIcon
3855
3964
  })]
3856
3965
  }), text.slice(1)] }) : text
3857
- }, `ref-${b.ref.start}`));
3966
+ }, `ref-${b.ordinal}`));
3858
3967
  cursor = b.ref.end;
3859
3968
  }
3860
3969
  }
@@ -5349,7 +5458,7 @@ window.__ModuleLoader__.load({
5349
5458
  });
5350
5459
  //#endregion
5351
5460
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/chat/ChatView.module.css.mjs
5352
- const css$11 = ".Md3f7G_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative}.Md3f7G_scroll{min-height:0;padding:16px calc(var(--dsh-composer-side-clearance) + 16px);flex:auto;overflow-y:auto}[data-conversation-scroll] .Md3f7G_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .Md3f7G_scroll{flex:none;min-height:auto;overflow:visible}.Md3f7G_column{max-width:var(--dsh-chat-content-width);flex-direction:column;gap:16px;width:100%;margin:0 auto;display:flex}.Md3f7G_flowItem{min-width:0}.Md3f7G_flowItem:empty{display:none}.Md3f7G_callRow{border-radius:6px}.Md3f7G_turnStatus{height:26px;font:var(--dsw-font-s-strong-14);white-space:nowrap;background:linear-gradient(90deg, var(--dsw-static-deepseek-500) 0%, var(--dsw-static-deepseek-500) 40%, var(--dsw-static-deepseek-200) 50%, var(--dsw-static-deepseek-500) 60%, var(--dsw-static-deepseek-500) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;flex:none;align-self:flex-start;align-items:center;animation:1.8s linear infinite Md3f7G_dsh-turn-status-shimmer;display:inline-flex}.Md3f7G_turnStatusClock{font:var(--dsw-font-xs-13);font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-caption);-webkit-text-fill-color:var(--dsw-alias-label-caption);margin-left:8px;font-weight:400}@keyframes Md3f7G_dsh-turn-status-shimmer{to{background-position:0 0}}@media (prefers-reduced-motion:reduce){.Md3f7G_turnStatus{background-position:0 0;background-size:100% 100%;animation:none}}.Md3f7G_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.Md3f7G_openError{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.Md3f7G_older{justify-content:center;display:flex}.Md3f7G_older button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover-solid);cursor:pointer;border:none;border-radius:14px;padding:4px 12px;font-size:12px}.Md3f7G_older button:disabled{cursor:default;opacity:.6}.Md3f7G_toBottomSlot{z-index:8;height:0;padding-right:max(0px, calc((100% - var(--dsh-chat-content-width)) / 2));pointer-events:none;justify-content:flex-end;display:flex;position:sticky;bottom:16px}[data-conversation-scroll] .Md3f7G_toBottomSlot{bottom:calc(var(--dsh-composer-height,152px) + 16px)}.Md3f7G_toBottom{border:1px solid var(--dsw-alias-border-l2);width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill);box-shadow:var(--dsw-shadow-lv2);cursor:pointer;pointer-events:auto;border-radius:100px;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.Md3f7G_toBottom:hover{background:var(--dsw-alias-button-floating-hover)}.Md3f7G_modalAction{min-width:72px}";
5461
+ const css$11 = ".Md3f7G_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative}.Md3f7G_scroll{min-height:0;padding:16px calc(var(--dsh-composer-side-clearance) + 16px);flex:auto;overflow-y:auto;container-type:inline-size}[data-conversation-scroll] .Md3f7G_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .Md3f7G_scroll{flex:none;min-height:auto;overflow:visible}.Md3f7G_column{max-width:var(--dsh-chat-content-width);flex-direction:column;gap:16px;width:100%;margin:0 auto;display:flex}.Md3f7G_flowItem{min-width:0}.Md3f7G_flowItem:empty{display:none}.Md3f7G_callRow{border-radius:6px}.Md3f7G_turnStatus{height:26px;font:var(--dsw-font-s-strong-14);white-space:nowrap;background:linear-gradient(90deg, var(--dsw-static-deepseek-500) 0%, var(--dsw-static-deepseek-500) 40%, var(--dsw-static-deepseek-200) 50%, var(--dsw-static-deepseek-500) 60%, var(--dsw-static-deepseek-500) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;flex:none;align-self:flex-start;align-items:center;animation:1.8s linear infinite Md3f7G_dsh-turn-status-shimmer;display:inline-flex}.Md3f7G_turnStatusClock{font:var(--dsw-font-xs-13);font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-caption);-webkit-text-fill-color:var(--dsw-alias-label-caption);margin-left:8px;font-weight:400}@keyframes Md3f7G_dsh-turn-status-shimmer{to{background-position:0 0}}@media (prefers-reduced-motion:reduce){.Md3f7G_turnStatus{background-position:0 0;background-size:100% 100%;animation:none}}.Md3f7G_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.Md3f7G_openError{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.Md3f7G_older{justify-content:center;display:flex}.Md3f7G_older button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover-solid);cursor:pointer;border:none;border-radius:14px;padding:4px 12px;font-size:12px}.Md3f7G_older button:disabled{cursor:default;opacity:.6}.Md3f7G_toBottomSlot{z-index:8;height:0;padding-right:max(0px, calc((100% - var(--dsh-chat-content-width)) / 2));pointer-events:none;justify-content:flex-end;display:flex;position:sticky;bottom:16px}[data-conversation-scroll] .Md3f7G_toBottomSlot{bottom:calc(var(--dsh-composer-height,152px) + 16px)}.Md3f7G_toBottom{border:1px solid var(--dsw-alias-border-l2);width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill);box-shadow:var(--dsw-shadow-lv2);cursor:pointer;pointer-events:auto;border-radius:100px;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.Md3f7G_toBottom:hover{background:var(--dsw-alias-button-floating-hover)}.Md3f7G_modalAction{min-width:72px}";
5353
5462
  const tagId$11 = "@deepseek-ai/dsh-client-ui-conversation/ChatView.module.css";
5354
5463
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$11) + "]") === null) {
5355
5464
  const tag = document.createElement("style");
@@ -6080,11 +6189,14 @@ window.__ModuleLoader__.load({
6080
6189
  "settings.enter.description": "仅在智能体运行时生效;Cmd/Ctrl+Enter 使用另一行为",
6081
6190
  "settings.enter.queue": "排队发送",
6082
6191
  "settings.enter.steer": "插话发送",
6083
- "access.confirm.title": "确认启用 Full access?",
6084
- "access.confirm.description": "启用 Full access 后,agent 将减少确认步骤,并且可以直接执行更多操作,包括敏感操作、文件修改或外部命令。仅建议在你信任当前任务时使用。",
6192
+ "access.preset.readOnly": "仅可查看",
6193
+ "access.preset.workspaceWrite": "可写入工作区",
6194
+ "access.preset.fullAccess": "完全权限",
6195
+ "access.confirm.title": "确认启用完全权限?",
6196
+ "access.confirm.description": "启用完全权限后,智能体将减少确认步骤,并且可以直接执行更多操作,包括敏感操作、文件修改或外部命令。仅建议在你信任当前任务时使用。",
6085
6197
  "access.confirm.acknowledge": "我已了解风险,并愿意继续",
6086
6198
  "access.confirm.cancel": "取消",
6087
- "access.confirm.enable": "启用 Full access",
6199
+ "access.confirm.enable": "启用完全权限",
6088
6200
  "hero.headline": "探索未至之境",
6089
6201
  "hero.preview": "预览版",
6090
6202
  "hero.chooseWorkspace": "选择工作区",
@@ -6253,6 +6365,9 @@ window.__ModuleLoader__.load({
6253
6365
  "settings.enter.description": "Busy only; Cmd/Ctrl+Enter uses the other behavior",
6254
6366
  "settings.enter.queue": "Queue",
6255
6367
  "settings.enter.steer": "Steer",
6368
+ "access.preset.readOnly": "Read Only",
6369
+ "access.preset.workspaceWrite": "Workspace Write",
6370
+ "access.preset.fullAccess": "Full access",
6256
6371
  "access.confirm.title": "Enable Full access?",
6257
6372
  "access.confirm.description": "Full access reduces confirmation steps and lets the agent perform more actions directly, including sensitive operations, file changes, or external commands. Only use it when you trust the current task.",
6258
6373
  "access.confirm.acknowledge": "I understand the risks and want to continue",
@@ -7015,7 +7130,7 @@ window.__ModuleLoader__.load({
7015
7130
  }
7016
7131
  //#endregion
7017
7132
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css.mjs
7018
- const css$6 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);--dsh-chat-content-width:748px;--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;min-width:0;height:100%;display:flex}.wSkVaW_header{border-bottom:1px solid #0000;flex:none;padding:12px 28px 0 20px;position:relative}.wSkVaW_header:after{content:\"\";z-index:0;background:var(--dsw-alias-border-l2);pointer-events:none;height:1px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_headerHidden{display:none}.wSkVaW_titleRow{align-items:center;gap:0;min-height:32px;display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;overflow:hidden}.wSkVaW_crumb:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_tabs{z-index:1;gap:36px;margin-top:4px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 11px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden auto}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px;position:relative}.wSkVaW_heroGlow{z-index:-1;aspect-ratio:1051/468;pointer-events:none;width:135.438%;position:absolute;bottom:92px;left:50%;transform:translate(-50%,50%)}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding-left:20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
7133
+ const css$6 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);--dsh-chat-content-width:748px;--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;min-width:0;height:100%;display:flex}.wSkVaW_header{border-bottom:1px solid #0000;flex:none;padding:12px 28px 0 20px;position:relative}.wSkVaW_header:after{content:\"\";z-index:0;background:var(--dsw-alias-border-l2);pointer-events:none;height:1px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_headerHidden{display:none}.wSkVaW_titleRow{align-items:center;gap:0;min-height:32px;display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;overflow:hidden}.wSkVaW_crumbSubagent{font-size:12px;line-height:18px}.wSkVaW_crumb:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_tabs{z-index:1;gap:36px;margin-top:4px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 11px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden auto}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px;position:relative}.wSkVaW_heroGlow{z-index:-1;aspect-ratio:1051/468;pointer-events:none;width:135.438%;position:absolute;bottom:92px;left:50%;transform:translate(-50%,50%)}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding-left:20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
7019
7134
  const tagId$6 = "@deepseek-ai/dsh-client-ui-conversation/ConversationRoot.module.css";
7020
7135
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
7021
7136
  const tag = document.createElement("style");
@@ -7032,6 +7147,7 @@ window.__ModuleLoader__.load({
7032
7147
  "crumbCurrent": "wSkVaW_crumbCurrent",
7033
7148
  "crumbSeg": "wSkVaW_crumbSeg",
7034
7149
  "crumbSep": "wSkVaW_crumbSep",
7150
+ "crumbSubagent": "wSkVaW_crumbSubagent",
7035
7151
  "crumbs": "wSkVaW_crumbs",
7036
7152
  "header": "wSkVaW_header",
7037
7153
  "headerActions": "wSkVaW_headerActions",
@@ -7198,7 +7314,8 @@ window.__ModuleLoader__.load({
7198
7314
  if (summary === void 0) break;
7199
7315
  chain.unshift({
7200
7316
  id: summary.id,
7201
- displayTitle: summary.displayTitle
7317
+ displayTitle: summary.displayTitle,
7318
+ subagent: summary.origin === "subagent"
7202
7319
  });
7203
7320
  if (summary.origin !== "subagent") break;
7204
7321
  cursor = summary.parentId;
@@ -7235,20 +7352,29 @@ window.__ModuleLoader__.load({
7235
7352
  "aria-label": t("session.hierarchy"),
7236
7353
  children: [ancestry.map((summary, index) => {
7237
7354
  const last = index === ancestry.length - 1;
7355
+ const title = (0, react_jsx_runtime.jsx)("button", {
7356
+ type: "button",
7357
+ className: clsx(ConversationRoot_module_css_default.crumb, summary.subagent && ConversationRoot_module_css_default.crumbSubagent, last && ConversationRoot_module_css_default.crumbCurrent),
7358
+ disabled: last,
7359
+ onClick: () => {
7360
+ open(summary.id);
7361
+ },
7362
+ children: summary.displayTitle
7363
+ });
7364
+ const lineage = last || summary.subagent;
7365
+ const lineageOwner = {
7366
+ lineageSessionId: summary.id,
7367
+ displayTitle: summary.displayTitle,
7368
+ ...last ? {} : { openTitle: () => {
7369
+ open(summary.id);
7370
+ } }
7371
+ };
7238
7372
  return (0, react_jsx_runtime.jsxs)("span", {
7239
7373
  className: ConversationRoot_module_css_default.crumbSeg,
7240
7374
  children: [index > 0 && (0, react_jsx_runtime.jsx)("span", {
7241
7375
  className: ConversationRoot_module_css_default.crumbSep,
7242
7376
  children: "/"
7243
- }), (0, react_jsx_runtime.jsx)("button", {
7244
- type: "button",
7245
- className: clsx(ConversationRoot_module_css_default.crumb, last && ConversationRoot_module_css_default.crumbCurrent),
7246
- disabled: last,
7247
- onClick: () => {
7248
- open(summary.id);
7249
- },
7250
- children: summary.displayTitle
7251
- })]
7377
+ }), lineage ? summary.subagent ? renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: title }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [title, renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: null })] }) : title]
7252
7378
  }, summary.id);
7253
7379
  }), ancestry.length === 0 && (0, react_jsx_runtime.jsx)("span", {
7254
7380
  className: ConversationRoot_module_css_default.crumbCurrent,
@@ -8886,9 +9012,6 @@ window.__ModuleLoader__.load({
8886
9012
  if (location?.kind !== "turn" && location?.kind !== "step") return 0;
8887
9013
  return location.turn.steps.at(-1)?.step ?? 0;
8888
9014
  }
8889
- function retryTurn(event) {
8890
- return event.type === "llm/retry" || event.type === "llm/retry-started" ? event.data.turn : void 0;
8891
- }
8892
9015
  function failureFrom(match) {
8893
9016
  if (match.event.type !== "turn/end" || match.event.data.reason.kind !== "error") return void 0;
8894
9017
  const failure = match.event.data.reason.error;
@@ -8904,14 +9027,16 @@ window.__ModuleLoader__.load({
8904
9027
  if (end?.event.type !== "turn/end") return void 0;
8905
9028
  const failure = failureFrom(end);
8906
9029
  if (failure === void 0) return void 0;
8907
- const turn = end.event.data.turn;
8908
9030
  return {
8909
- turn,
8910
- hidden: context.matches.some((match) => retryTurn(match.event) === turn),
9031
+ turn: end.event.data.turn,
8911
9032
  failure
8912
9033
  };
8913
9034
  }
8914
- /** Terminal turn failure Definition, suppressed when the turn owns a retry chain. */
9035
+ /**
9036
+ * Terminal turn failure Definition. Retries run inside the failing turn, so the
9037
+ * turn's `llm/retry` history never suppresses this terminal row; the model-retry
9038
+ * node renders that history separately.
9039
+ */
8915
9040
  const turnErrorDefinition = {
8916
9041
  kind: "turn-error",
8917
9042
  target: "chat",
@@ -8924,29 +9049,18 @@ window.__ModuleLoader__.load({
8924
9049
  id: String(event.data.turn),
8925
9050
  role: "update"
8926
9051
  };
8927
- const turn = retryTurn(event);
8928
- return turn === void 0 ? null : {
8929
- id: String(turn),
8930
- role: "update"
8931
- };
9052
+ return null;
8932
9053
  },
8933
9054
  start: (_context, match) => {
8934
9055
  if (match.event.type !== "turn/start") throw new Error("turn-error start requires turn/start");
8935
- return {
8936
- turn: match.event.data.turn,
8937
- hidden: false
8938
- };
9056
+ return { turn: match.event.data.turn };
8939
9057
  },
8940
9058
  update: (context, match) => {
8941
9059
  const failure = failureFrom(match);
8942
- if (failure !== void 0) return {
9060
+ return failure === void 0 ? context.state : {
8943
9061
  ...context.state,
8944
9062
  failure
8945
9063
  };
8946
- return retryTurn(match.event) === context.state.turn ? {
8947
- ...context.state,
8948
- hidden: true
8949
- } : context.state;
8950
9064
  },
8951
9065
  buildViewNode: (context) => {
8952
9066
  const state = context.state ?? fallbackState(context);
@@ -8961,9 +9075,7 @@ window.__ModuleLoader__.load({
8961
9075
  message: failure.message,
8962
9076
  ...failure.code === void 0 ? {} : { code: failure.code }
8963
9077
  };
8964
- if (!state.hidden) return chatNode(context, "turn-error", node.seq, node);
8965
- const current = context.current.get("chat");
8966
- return current === void 0 || current === null ? null : chatNode(context, "turn-error", node.seq, node, { visibility: "hidden" });
9078
+ return chatNode(context, "turn-error", node.seq, node);
8967
9079
  }
8968
9080
  };
8969
9081
  /**
@@ -9343,7 +9455,7 @@ window.__ModuleLoader__.load({
9343
9455
  }
9344
9456
  //#endregion
9345
9457
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/chat/AssistantMarkdown.module.css.mjs
9346
- const css$2 = ".Sxvs8a_root{color:var(--dsw-alias-label-primary);flex-direction:column;font-size:16px;line-height:28px;display:flex}.Sxvs8a_body{flex-direction:column;gap:16px;display:flex}.Sxvs8a_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;padding:0 6px;font-size:11px;line-height:18px}.Sxvs8a_actions{margin-top:16px;margin-left:-6px}";
9458
+ const css$2 = ".Sxvs8a_root{color:var(--dsw-alias-label-primary);flex-direction:column;font-size:16px;line-height:28px;display:flex}.Sxvs8a_body{flex-direction:column;gap:16px;display:flex}.Sxvs8a_body .md-table-wide{--dsh-table-spare:max(0px, calc((100cqw - var(--dsh-chat-content-width)) / 2));--dsh-table-lead:calc(var(--dsh-table-spare) + min(var(--dsh-chat-content-width), 100cqw) - 100%);box-sizing:border-box;width:calc(100% + var(--dsh-table-lead) + var(--dsh-table-spare));max-width:none;margin-left:calc(-1 * var(--dsh-table-lead));padding-left:var(--dsh-table-lead)}.Sxvs8a_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;padding:0 6px;font-size:11px;line-height:18px}.Sxvs8a_actions{margin-top:16px;margin-left:-6px}";
9347
9459
  const tagId$2 = "@deepseek-ai/dsh-client-ui-conversation/AssistantMarkdown.module.css";
9348
9460
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
9349
9461
  const tag = document.createElement("style");
@@ -9949,6 +10061,10 @@ window.__ModuleLoader__.load({
9949
10061
  name: "conversation.session.header",
9950
10062
  locale: NS,
9951
10063
  children: {
10064
+ "conversation.session.header.lineage": {
10065
+ kind: "single",
10066
+ scope: "session"
10067
+ },
9952
10068
  "conversation.session.header.actions": {
9953
10069
  kind: "list",
9954
10070
  scope: "session"