@crazyhappyone/dsh-tui 0.1.0-alpha.44 → 0.1.0-alpha.46

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/dist/index.js CHANGED
@@ -31027,8 +31027,8 @@ var Fiber = class {
31027
31027
  *
31028
31028
  * @param config — the new raw config; validated before anything restarts.
31029
31029
  * @param noSave — hint for persistence hooks not to write the change back.
31030
- * @returns the update waterfall result; the default restart returns a promise.
31031
- * @throws when validation, an update listener, or the restarted plugin fails.
31030
+ * @returns nothing; the restart runs behind the `internal/update` waterfall.
31031
+ * @throws {ValidationError} when the new config fails validation.
31032
31032
  */
31033
31033
  update(config2, noSave = false) {
31034
31034
  this.assertActive();
@@ -31040,7 +31040,7 @@ var Fiber = class {
31040
31040
  return;
31041
31041
  }
31042
31042
  config2 = this._resolveConfig(config2);
31043
- return this.context.waterfall(this, "internal/update", config2, noSave, () => {
31043
+ this.context.waterfall(this, "internal/update", config2, noSave, () => {
31044
31044
  this.config = config2;
31045
31045
  this._error = void 0;
31046
31046
  return this.restart();
@@ -32201,13 +32201,15 @@ function failureSnapshot(value) {
32201
32201
  const status = candidate.status;
32202
32202
  const providerRetryAfterMs = candidate.providerRetryAfterMs;
32203
32203
  const requestId = candidate.requestId;
32204
- if (typeof message !== "string" || message.length === 0 || typeof code2 !== "string" || code2.length === 0 || status !== void 0 && (!Number.isInteger(status) || status < 100 || status > 599) || providerRetryAfterMs !== void 0 && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0) || requestId !== void 0 && (typeof requestId !== "string" || requestId.length === 0)) return void 0;
32204
+ const offloadImages = candidate.offloadImages;
32205
+ if (typeof message !== "string" || message.length === 0 || typeof code2 !== "string" || code2.length === 0 || status !== void 0 && (!Number.isInteger(status) || status < 100 || status > 599) || providerRetryAfterMs !== void 0 && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0) || requestId !== void 0 && (typeof requestId !== "string" || requestId.length === 0) || offloadImages !== void 0 && (!Number.isSafeInteger(offloadImages) || offloadImages <= 0)) return void 0;
32205
32206
  return Object.freeze({
32206
32207
  message,
32207
32208
  code: code2,
32208
32209
  ...status === void 0 ? {} : { status },
32209
32210
  ...providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs },
32210
- ...requestId === void 0 ? {} : { requestId }
32211
+ ...requestId === void 0 ? {} : { requestId },
32212
+ ...offloadImages === void 0 ? {} : { offloadImages }
32211
32213
  });
32212
32214
  } catch (_sdkFailureGetter) {
32213
32215
  return void 0;
@@ -32508,7 +32510,8 @@ var LlmError = class extends HarnessError {
32508
32510
  code: code2,
32509
32511
  ...options?.status === void 0 ? {} : { status: options.status },
32510
32512
  ...options?.providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: options.providerRetryAfterMs },
32511
- ...options?.requestId === void 0 ? {} : { requestId: options.requestId }
32513
+ ...options?.requestId === void 0 ? {} : { requestId: options.requestId },
32514
+ ...options?.offloadImages === void 0 ? {} : { offloadImages: options.offloadImages }
32512
32515
  });
32513
32516
  }
32514
32517
  };
@@ -33274,6 +33277,7 @@ var KNOWN_SESSION_EVENT_TYPES = /* @__PURE__ */ new Set([
33274
33277
  "goal/change",
33275
33278
  "hook/invoked",
33276
33279
  "hook/result",
33280
+ "image/offload",
33277
33281
  "llm/retry",
33278
33282
  "llm/retry-started",
33279
33283
  "model/selection",
@@ -33311,6 +33315,9 @@ var KNOWN_SESSION_EVENT_TYPES = /* @__PURE__ */ new Set([
33311
33315
  "user/message",
33312
33316
  "web/deepseek-search-llm-request"
33313
33317
  ]);
33318
+ var MESSAGE_PROJECTION_EVENT_TYPES = /* @__PURE__ */ new Set([
33319
+ "image/offload"
33320
+ ]);
33314
33321
 
33315
33322
  // packages/core/session/src/surface.ts
33316
33323
  var SURFACE_EVENT_TYPES = /* @__PURE__ */ new Set([
@@ -33322,7 +33329,9 @@ var SURFACE_EVENT_TYPES = /* @__PURE__ */ new Set([
33322
33329
  function isSurfaceEligibleType(type) {
33323
33330
  return SURFACE_EVENT_TYPES.has(type);
33324
33331
  }
33325
- function deriveEventMessage(event) {
33332
+ function deriveEventMessage(event, projectedMessages) {
33333
+ const projected = projectedMessages?.get(event.seq);
33334
+ if (projected !== void 0) return projected;
33326
33335
  switch (event.type) {
33327
33336
  // Ordinary prompts and injected context project in user role: the event's
33328
33337
  // model-facing content stays verbatim. Do NOT re-add per-type framing
@@ -33381,7 +33390,7 @@ function validateSessionEventData(event, subject) {
33381
33390
  }
33382
33391
  }
33383
33392
  function createFoldState() {
33384
- return { nodes: [], replaceGeneration: 0 };
33393
+ return { nodes: [], replaceGeneration: 0, contentGeneration: 0, projectedMessages: /* @__PURE__ */ new Map(), projections: /* @__PURE__ */ new Set() };
33385
33394
  }
33386
33395
  function isEventSeq(value) {
33387
33396
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && !Object.is(value, -0);
@@ -33415,7 +33424,7 @@ function surfaceOpOf(event) {
33415
33424
  }
33416
33425
  return op;
33417
33426
  }
33418
- function assertProvenance(event, shadowedSeqs) {
33427
+ function assertSourceEventReferences(event, shadowedSeqs) {
33419
33428
  const raw = event.sourceEventSeqs;
33420
33429
  if (event.type === "assistant/message" && raw !== void 0) {
33421
33430
  throw new Error("assistant/message embeds its source stream and cannot carry sourceEventSeqs");
@@ -33453,7 +33462,7 @@ function validateSurfaceMetadata(event) {
33453
33462
  if (op !== void 0 && op !== "append" && (op.startSeq >= event.seq || op.endSeq >= event.seq)) {
33454
33463
  throw new Error(`surface replace at seq ${event.seq}: startSeq and endSeq must reference earlier events`);
33455
33464
  }
33456
- if (op !== void 0) assertProvenance(event, []);
33465
+ if (op !== void 0) assertSourceEventReferences(event, []);
33457
33466
  return op;
33458
33467
  }
33459
33468
  function replacementRange(state, op) {
@@ -33521,17 +33530,29 @@ function assertSystemHeadRewrite(event, state, startIdx, shadowedSeqs, events, b
33521
33530
  throw new Error("surface replace: node 0 holds the system prompt and may be rewritten only by a system/message over exactly that node");
33522
33531
  }
33523
33532
  }
33524
- function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) {
33533
+ function planSurfaceEvent(state, event, expectedSeq, events, baseSeq, projections) {
33525
33534
  if (event.seq !== expectedSeq) {
33526
33535
  throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`);
33527
33536
  }
33528
33537
  const surfaceOp = validateSurfaceMetadata(event);
33538
+ const projection = projections.find((item) => item.type === event.type);
33539
+ if (projection !== void 0) {
33540
+ return { kind: "project", projection, messages: projection.project(event, {
33541
+ nodes: state.nodes,
33542
+ events,
33543
+ baseSeq,
33544
+ messages: state.projectedMessages
33545
+ }) };
33546
+ }
33547
+ if (MESSAGE_PROJECTION_EVENT_TYPES.has(event.type)) {
33548
+ throw new Error(`session event "${event.type}" requires a message projection; load its owning plugin or supply its projection definition`);
33549
+ }
33529
33550
  if (surfaceOp === void 0) return;
33530
33551
  if (surfaceOp === "append") {
33531
33552
  return { kind: "append", seq: event.seq };
33532
33553
  }
33533
33554
  const range = replacementRange(state, surfaceOp);
33534
- assertProvenance(event, range.shadowedSeqs);
33555
+ assertSourceEventReferences(event, range.shadowedSeqs);
33535
33556
  assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq);
33536
33557
  assertSystemHeadRewrite(event, state, range.startIdx, range.shadowedSeqs, events, baseSeq);
33537
33558
  return {
@@ -33542,8 +33563,8 @@ function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) {
33542
33563
  ...range
33543
33564
  };
33544
33565
  }
33545
- function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) {
33546
- const plan = planSurfaceEvent(state, event, expectedSeq, events, baseSeq);
33566
+ function applySurfaceEvent(state, event, expectedSeq, events, baseSeq, projections) {
33567
+ const plan = planSurfaceEvent(state, event, expectedSeq, events, baseSeq, projections);
33547
33568
  return applySurfacePlan(state, plan);
33548
33569
  }
33549
33570
  function applySurfacePlan(state, plan) {
@@ -33552,6 +33573,11 @@ function applySurfacePlan(state, plan) {
33552
33573
  } else if (plan?.kind === "replace") {
33553
33574
  state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq);
33554
33575
  state.replaceGeneration += 1;
33576
+ state.contentGeneration += 1;
33577
+ } else if (plan?.kind === "project") {
33578
+ for (const [seq, message] of plan.messages) state.projectedMessages.set(seq, message);
33579
+ state.projections.add(plan.projection);
33580
+ state.contentGeneration += 1;
33555
33581
  }
33556
33582
  if (plan?.kind !== "replace") return;
33557
33583
  return {
@@ -33565,14 +33591,17 @@ var SurfaceManager = class {
33565
33591
  /**
33566
33592
  * @param log - Contiguous complete log or loaded event window.
33567
33593
  * @param baseSeq - Absolute sequence of the window's first event.
33594
+ * @param projections - live borrowed definitions; removing a used definition invalidates further reads.
33568
33595
  */
33569
- constructor(log, baseSeq = SessionLogOffset(0)) {
33596
+ constructor(log, baseSeq = SessionLogOffset(0), projections = []) {
33570
33597
  this.log = log;
33571
33598
  this.baseSeq = baseSeq;
33599
+ this.projections = projections;
33572
33600
  this._lastProcessedSeq = baseSeq === 0 ? -1 : SessionSeq(baseSeq - 1);
33573
33601
  }
33574
33602
  log;
33575
33603
  baseSeq;
33604
+ projections;
33576
33605
  /** Shared transition state; replacement history is not retained. */
33577
33606
  _state = createFoldState();
33578
33607
  /** Last processed absolute seq. */
@@ -33584,21 +33613,40 @@ var SurfaceManager = class {
33584
33613
  * @param event - candidate event that has not entered the log yet.
33585
33614
  */
33586
33615
  validateNext(event) {
33616
+ this._assertProjections();
33587
33617
  if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33588
33618
  const expectedSeq = SessionSeq(this.baseSeq + this.log.length);
33589
33619
  this._pendingPlan = {
33590
33620
  event,
33591
33621
  expectedSeq,
33592
- plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq)
33622
+ plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq, this.projections)
33593
33623
  };
33594
33624
  }
33595
33625
  /** Monotonic count of folded positional replacements. */
33596
33626
  get replaceGeneration() {
33627
+ this._assertProjections();
33597
33628
  if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33598
33629
  return this._state.replaceGeneration;
33599
33630
  }
33631
+ /** Monotonic count of committed changes to existing model-visible content. */
33632
+ get contentGeneration() {
33633
+ this._assertProjections();
33634
+ if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33635
+ return this._state.contentGeneration;
33636
+ }
33637
+ /**
33638
+ * Project one message with every committed message projection applied.
33639
+ * @param event - message-producing or log-only event.
33640
+ * @returns its immutable projected message, or null when it produces none.
33641
+ */
33642
+ deriveEventMessage(event) {
33643
+ this._assertProjections();
33644
+ if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33645
+ return deriveEventMessage(event, this._state.projectedMessages);
33646
+ }
33600
33647
  /** Surface event sequences in model-visible order. */
33601
33648
  get nodes() {
33649
+ this._assertProjections();
33602
33650
  if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33603
33651
  return this._state.nodes;
33604
33652
  }
@@ -33612,12 +33660,23 @@ var SurfaceManager = class {
33612
33660
  if (pending?.event === event && pending.expectedSeq === seq) {
33613
33661
  applySurfacePlan(this._state, pending.plan);
33614
33662
  } else {
33615
- applySurfaceEvent(this._state, event, SessionSeq(seq), this.log, this.baseSeq);
33663
+ applySurfaceEvent(this._state, event, SessionSeq(seq), this.log, this.baseSeq, this.projections);
33616
33664
  }
33617
33665
  if (pending !== void 0 && pending.expectedSeq <= seq) this._pendingPlan = void 0;
33618
33666
  this._lastProcessedSeq = SessionSeq(seq);
33619
33667
  }
33620
33668
  }
33669
+ /** Cached messages cannot outlive the definitions that interpreted their log. */
33670
+ _assertProjections() {
33671
+ const candidate = this._pendingPlan;
33672
+ const pending = candidate !== void 0 && this.log[candidate.expectedSeq - this.baseSeq] === candidate.event ? candidate.plan : void 0;
33673
+ const required2 = pending?.kind === "project" ? [...this._state.projections, pending.projection] : this._state.projections;
33674
+ for (const projection of required2) {
33675
+ if (!this.projections.includes(projection)) {
33676
+ throw new Error(`session message projection "${projection.type}" was removed or replaced; restore the session with its owning plugin`);
33677
+ }
33678
+ }
33679
+ }
33621
33680
  };
33622
33681
 
33623
33682
  // packages/core/session/src/request-header.ts
@@ -33860,7 +33919,7 @@ var attachments = /* @__PURE__ */ new WeakMap();
33860
33919
  var Session = class _Session {
33861
33920
  log = [];
33862
33921
  /** Single incremental owner of surface acceptance and projection state. */
33863
- surfaceManager = new SurfaceManager(this.log);
33922
+ surfaceManager;
33864
33923
  /** The ordered surface over this session's event log. */
33865
33924
  get surface() {
33866
33925
  return this.surfaceManager;
@@ -33911,10 +33970,12 @@ var Session = class _Session {
33911
33970
  * @param seed - optional borrowed replay or fork events.
33912
33971
  * @param header - optional borrowed storage metadata.
33913
33972
  * @param inheritedEventCount - exact fork-inherited prefix length for a seeded header.
33973
+ * @param projections - pure interpreters for plugin-owned message changes.
33914
33974
  * @returns a detached session.
33975
+ * @throws when a seed event requires a missing message interpreter or fails validation.
33915
33976
  */
33916
- static create(id, seed, header, inheritedEventCount) {
33917
- return new _Session(id, seed, header, "snapshot", inheritedEventCount);
33977
+ static create(id, seed, header, inheritedEventCount, projections) {
33978
+ return new _Session(id, seed, header, "snapshot", inheritedEventCount, projections);
33918
33979
  }
33919
33980
  /**
33920
33981
  * Restore a detached session by adopting an independently owned or deeply frozen seed.
@@ -33927,18 +33988,22 @@ var Session = class _Session {
33927
33988
  * @param header - independently owned storage metadata.
33928
33989
  * @param inheritedEventCount - exact fork-inherited prefix length decoded from storage.
33929
33990
  * @param eventState - aliasing state carried from the operation that produced the seed.
33991
+ * @param projections - pure interpreters for plugin-owned message changes.
33930
33992
  * @returns a restored detached session.
33993
+ * @throws when a seed event requires a missing message interpreter or fails validation.
33931
33994
  */
33932
- static fromRestore(id, seed, header, inheritedEventCount, eventState) {
33995
+ static fromRestore(id, seed, header, inheritedEventCount, eventState, projections) {
33933
33996
  return new _Session(
33934
33997
  id,
33935
33998
  seed,
33936
33999
  header,
33937
34000
  eventState,
33938
- inheritedEventCount
34001
+ inheritedEventCount,
34002
+ projections
33939
34003
  );
33940
34004
  }
33941
- constructor(id, seed, header, mode = "snapshot", suppliedInheritedEventCount) {
34005
+ constructor(id, seed, header, mode = "snapshot", suppliedInheritedEventCount, projections = []) {
34006
+ this.surfaceManager = new SurfaceManager(this.log, SessionLogOffset(0), projections);
33942
34007
  const restoredHeader = mode === "snapshot" ? void 0 : validateRestoredSessionHeader(id, header);
33943
34008
  if (seed !== void 0) {
33944
34009
  for (const [index2, source] of seed.entries()) {
@@ -34157,7 +34222,7 @@ var Session = class _Session {
34157
34222
  derived = [];
34158
34223
  /** Surface position (nodes projected) the cache has reached. */
34159
34224
  derivedNodes = 0;
34160
- /** {@link SurfaceManager.replaceGeneration} the cache was built under. */
34225
+ /** {@link SurfaceManager.contentGeneration} the cache was built under. */
34161
34226
  derivedGeneration = 0;
34162
34227
  /**
34163
34228
  * Derive the LLM message history by walking the ordered sequences of
@@ -34166,21 +34231,21 @@ var Session = class _Session {
34166
34231
  * append records its `surfaceOp`, so a raw event with no marker (a chunk, a
34167
34232
  * turn boundary) is correctly absent, and a compaction `replace` deletes the
34168
34233
  * shadowed nodes from the derivation. The projection rules are
34169
- * {@link deriveEventMessage}, folded per node.
34234
+ * {@link deriveEventMessage}, with logged message projections applied
34235
+ * without changing node membership or message identity.
34170
34236
  *
34171
- * CACHED: each surface node is projected exactly once, when first seen — a
34172
- * call costs O(new nodes), and a surface rewrite (a `replace`;
34173
- * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is
34237
+ * CACHED: pure tail growth costs O(new nodes); a replacement or message projection
34238
+ * ({@link SessionSurface.contentGeneration}) rebuilds. The returned array is
34174
34239
  * a fresh snapshot per call (later appends never grow an array a caller
34175
34240
  * already holds); the `Message` objects in it are SHARED and **deep-frozen**.
34176
- * Their content reuses the already frozen durable event data, so the cache
34177
- * needs no second deep clone and consumers still cannot mutate the log.
34241
+ * Unchanged content reuses frozen event data; projected blocks are frozen
34242
+ * derived copies. Consumers cannot mutate the log through either form.
34178
34243
  * @returns a fresh array of the shared, frozen derived history.
34179
34244
  */
34180
34245
  deriveMessages() {
34181
34246
  const surface = this.surface;
34182
34247
  const nodes = surface.nodes;
34183
- const generation = surface.replaceGeneration;
34248
+ const generation = surface.contentGeneration;
34184
34249
  if (generation !== this.derivedGeneration) {
34185
34250
  this.derived = [];
34186
34251
  this.derivedNodes = 0;
@@ -34194,13 +34259,13 @@ var Session = class _Session {
34194
34259
  return [...this.derived];
34195
34260
  }
34196
34261
  /**
34197
- * Instance face of the pure per-node `deriveEventMessage` export from
34198
- * `surface.ts`.
34262
+ * Project one event with all committed message projections applied.
34263
+ * The original durable event remains unchanged.
34199
34264
  * @param event - the event to project.
34200
34265
  * @returns the derived message, or null when the event produces none.
34201
34266
  */
34202
34267
  deriveEventMessage(event) {
34203
- return deriveEventMessage(event);
34268
+ return this.surfaceManager.deriveEventMessage(event);
34204
34269
  }
34205
34270
  };
34206
34271
 
@@ -55243,7 +55308,7 @@ var renderNodeToOutput = (node2, output, options) => {
55243
55308
  };
55244
55309
  var render_node_to_output_default = renderNodeToOutput;
55245
55310
 
55246
- // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/consts.js
55311
+ // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.1/node_modules/@alcalzone/ansi-tokenize/build/consts.js
55247
55312
  var BEL2 = "\x07";
55248
55313
  var ESC2 = "\x1B";
55249
55314
  var BACKSLASH = "\\";
@@ -55267,13 +55332,16 @@ var linkEndCode = `${ESC2}${OSC2}8;;${BEL2}`;
55267
55332
  var linkEndCodeST = `${ESC2}${OSC2}8;;${ESC2}${BACKSLASH}`;
55268
55333
  var linkEndCodeC1ST = `${ESC2}${OSC2}8;;${C1_ST}`;
55269
55334
 
55270
- // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/ansiCodes.js
55335
+ // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.1/node_modules/@alcalzone/ansi-tokenize/build/ansiCodes.js
55271
55336
  var endCodesSet = /* @__PURE__ */ new Set();
55272
55337
  var endCodesMap = /* @__PURE__ */ new Map();
55273
55338
  for (const [start, end] of ansi_styles_default.codes) {
55274
55339
  endCodesSet.add(ansi_styles_default.color.ansi(end));
55275
55340
  endCodesMap.set(ansi_styles_default.color.ansi(start), ansi_styles_default.color.ansi(end));
55276
55341
  }
55342
+ endCodesSet.add(linkEndCode);
55343
+ endCodesSet.add(linkEndCodeST);
55344
+ endCodesSet.add(linkEndCodeC1ST);
55277
55345
  function getEndCode(code2) {
55278
55346
  if (endCodesSet.has(code2))
55279
55347
  return code2;
@@ -55307,7 +55375,7 @@ function isIntensityCode(code2) {
55307
55375
  return code2.code === ansi_styles_default.bold.open || code2.code === ansi_styles_default.dim.open;
55308
55376
  }
55309
55377
 
55310
- // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/reduce.js
55378
+ // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.1/node_modules/@alcalzone/ansi-tokenize/build/reduce.js
55311
55379
  function reduceAnsiCodes(codes) {
55312
55380
  return reduceAnsiCodesIncremental([], codes);
55313
55381
  }
@@ -55332,7 +55400,7 @@ function reduceAnsiCodesIncremental(codes, newCodes) {
55332
55400
  return ret;
55333
55401
  }
55334
55402
 
55335
- // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/undo.js
55403
+ // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.1/node_modules/@alcalzone/ansi-tokenize/build/undo.js
55336
55404
  function undoAnsiCodes2(codes) {
55337
55405
  return reduceAnsiCodes(codes).reverse().map((code2) => ({
55338
55406
  ...code2,
@@ -55340,7 +55408,7 @@ function undoAnsiCodes2(codes) {
55340
55408
  }));
55341
55409
  }
55342
55410
 
55343
- // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/diff.js
55411
+ // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.1/node_modules/@alcalzone/ansi-tokenize/build/diff.js
55344
55412
  function diffAnsiCodes(from2, to) {
55345
55413
  const endCodesInTo = new Set(to.map((code2) => code2.endCode));
55346
55414
  const startCodesInTo = new Set(to.map((code2) => code2.code));
@@ -55359,7 +55427,7 @@ function diffAnsiCodes(from2, to) {
55359
55427
  ];
55360
55428
  }
55361
55429
 
55362
- // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/styledChars.js
55430
+ // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.1/node_modules/@alcalzone/ansi-tokenize/build/styledChars.js
55363
55431
  function styledCharsFromTokens(tokens) {
55364
55432
  let codes = [];
55365
55433
  const ret = [];
@@ -55392,7 +55460,7 @@ function styledCharsToString(chars) {
55392
55460
  return ret;
55393
55461
  }
55394
55462
 
55395
- // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/tokenize.js
55463
+ // node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.1/node_modules/@alcalzone/ansi-tokenize/build/tokenize.js
55396
55464
  var segmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
55397
55465
  function isFullwidthGrapheme(grapheme, baseCodePoint) {
55398
55466
  if (isFullwidthCodePoint(baseCodePoint))
@@ -59298,7 +59366,28 @@ function titleRun(title) {
59298
59366
  }
59299
59367
  return [styled(title, "fg")];
59300
59368
  }
59301
- function AppShell({ title, badge, children, status, input }) {
59369
+ function topDividerLine(columns, label) {
59370
+ if (columns <= 0) return "";
59371
+ if (!label || label.trim() === "") {
59372
+ return paintRow([styled(escapeContent("\u2500".repeat(columns)), "line")]);
59373
+ }
59374
+ const escaped = escapeContent(label);
59375
+ const labelLen = displayWidth(escaped);
59376
+ const prefix = "\u2500\u2500\u2500 ";
59377
+ const prefixLen = displayWidth(prefix);
59378
+ const suffix = " \u2500\u2500\u2500";
59379
+ const suffixLen = displayWidth(suffix);
59380
+ if (prefixLen + labelLen + suffixLen >= columns) {
59381
+ return paintRow([styled(escapeContent("\u2500".repeat(columns)), "line")]);
59382
+ }
59383
+ const dashCount = Math.max(0, columns - prefixLen - labelLen - suffixLen);
59384
+ return paintRow([
59385
+ styled(prefix, "line"),
59386
+ styled(escaped, "accentText"),
59387
+ styled(`${suffix}${"\u2500".repeat(dashCount)}`, "line")
59388
+ ]);
59389
+ }
59390
+ function AppShell({ title, badge, children, status, input, topDividerLabel }) {
59302
59391
  const { columns, rows } = use_window_size_default();
59303
59392
  const fitted = layoutTitleBar(
59304
59393
  escapeContent(title),
@@ -59310,7 +59399,7 @@ function AppShell({ title, badge, children, status, input }) {
59310
59399
  if (fitted.badge !== "") titleParts.push(styled(fitted.badge, "fgDim"));
59311
59400
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", width: "100%", height: rows, children: [
59312
59401
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexDirection: "row", width: "100%", flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: paintRow(titleParts) }) }),
59313
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: "100%", flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: paintRow([styled(escapeContent("\u2500".repeat(columns)), "line")]) }) }),
59402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: "100%", flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { wrap: "truncate", children: topDividerLine(columns, topDividerLabel) }) }),
59314
59403
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexDirection: "column", flexGrow: 1, width: "100%", overflow: "hidden", children }),
59315
59404
  input !== void 0 && input !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexDirection: "row", width: "100%", flexShrink: 0, children: input }) : null,
59316
59405
  status !== void 0 && status !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: "100%", flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: paintRow([styled(escapeContent("\u2500".repeat(columns)), "line")]) }) }) : null,
@@ -70475,10 +70564,21 @@ function ReasoningBlock({
70475
70564
  maxCols
70476
70565
  }) {
70477
70566
  const { columns } = use_window_size_default();
70478
- if (collapsed || text4 === "") return null;
70567
+ if (text4 === "") return null;
70479
70568
  const width = maxCols ?? columns;
70480
70569
  const escaped = escapeContent(text4);
70481
70570
  const body = wrapDisplayLines(escaped, Math.max(1, width - 4));
70571
+ if (collapsed) {
70572
+ const lineCount = body.length;
70573
+ const icon = live ? getBrailleSpinnerFrame(durationMs) : "\u273B";
70574
+ const parts = [
70575
+ styled("\u25B8 ", "accentText"),
70576
+ styled(`${icon} \u601D\u8003\u8FC7\u7A0B`, "accentText"),
70577
+ styled(` (\u5171 ${String(lineCount)} \u884C \xB7 ${formatSeconds(durationMs)}s)`, "fgDim"),
70578
+ styled(" \xB7 Ctrl+O \u5C55\u5F00", "fgDim")
70579
+ ];
70580
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexDirection: "column", width: "100%", backgroundColor: inkColor("toolBg"), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow(parts, "toolBg", width > 0 ? width : 0) }) });
70581
+ }
70482
70582
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", width: "100%", backgroundColor: inkColor("toolBg"), children: [
70483
70583
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { wrap: "truncate", children: thinkingHeader(durationMs, !live, live, width) }),
70484
70584
  body.map((line5, index2) => bodyRow(line5, index2, width))
@@ -71962,6 +72062,44 @@ function physicalScrollRailGeometry(contentRows, viewportRows, offsetFromBottom)
71962
72062
  return { rows, thumbStart: travel - fromBottom, thumbRows };
71963
72063
  }
71964
72064
 
72065
+ // packages/tui/tui-render/src/sticky-header.ts
72066
+ function collapseStickyText(text4) {
72067
+ return text4.replace(/\s+/gu, " ").trim();
72068
+ }
72069
+ function formatStickyThinkingLabel(range) {
72070
+ return `\u{1F4AD} \u601D\u8003\u4E2D (\u7B2C ${String(range.turnOrdinal)} \u8F6E \xB7 ${(range.durationMs / 1e3).toFixed(1)}s) \xB7 [Ctrl+O \u6298\u53E0]`;
72071
+ }
72072
+ function formatStickyToolLabel(range) {
72073
+ const title = collapseStickyText(range.title);
72074
+ return title === "" ? "\u25B8" : `\u25B8 ${title}`;
72075
+ }
72076
+ function formatStickyUserLabel(range) {
72077
+ const text4 = collapseStickyText(range.text);
72078
+ return text4 === "" ? ">" : `> ${text4}`;
72079
+ }
72080
+ function resolveStickyThinkingHeader(viewportTop, ranges) {
72081
+ for (const range of ranges) {
72082
+ if (viewportTop > range.start && viewportTop < range.end) {
72083
+ return formatStickyThinkingLabel(range);
72084
+ }
72085
+ }
72086
+ return void 0;
72087
+ }
72088
+ function resolveStickyTranscriptHeader(viewportTop, ranges) {
72089
+ const thinking = resolveStickyThinkingHeader(viewportTop, ranges.reasoning ?? []);
72090
+ if (thinking !== void 0) return thinking;
72091
+ for (const range of ranges.tools ?? []) {
72092
+ if (viewportTop > range.start && viewportTop < range.end) {
72093
+ return formatStickyToolLabel(range);
72094
+ }
72095
+ }
72096
+ const latestUser = ranges.users?.at(-1);
72097
+ if (latestUser !== void 0 && viewportTop >= latestUser.end) {
72098
+ return formatStickyUserLabel(latestUser);
72099
+ }
72100
+ return void 0;
72101
+ }
72102
+
71965
72103
  // packages/tui/tui-render/src/transcript-layout-cache.ts
71966
72104
  var TranscriptLayoutCache = class {
71967
72105
  scopeKey = "";
@@ -73581,7 +73719,7 @@ function projectBlockRows(entry, scope, markdownState) {
73581
73719
  case "divider":
73582
73720
  return projectDividerEntry(entry, scope);
73583
73721
  case "compaction":
73584
- return projectCompactionEntry(entry);
73722
+ return projectCompactionEntry(entry, scope);
73585
73723
  case "turn-tail":
73586
73724
  return projectTurnTailEntry(entry, scope);
73587
73725
  case "tool-summary":
@@ -73816,9 +73954,21 @@ function projectReasoningEntry(entry, scope) {
73816
73954
  const expanded = entry.meta?.reasoningExpanded === true;
73817
73955
  const live = entry.meta?.reasoningLive === true;
73818
73956
  const secondsLabel = (reasoningDurationMs / 1e3).toFixed(1);
73819
- if (!expanded || entry.source === "") {
73957
+ if (entry.source === "") {
73820
73958
  return { revision: 0, sourceLength: entry.source.length, lines: [] };
73821
73959
  }
73960
+ const escaped = escapeContent(entry.source);
73961
+ const body = wrapDisplayLines(escaped, Math.max(1, scope.width - 4));
73962
+ if (!expanded) {
73963
+ const icon2 = live ? getBrailleSpinnerFrame(reasoningDurationMs) : "\u273B";
73964
+ const capsule = surfaceLine([
73965
+ { text: "\u25B8 ", token: "accentText", bold: false },
73966
+ { text: `${icon2} \u601D\u8003\u8FC7\u7A0B`, token: "accentText", bold: false },
73967
+ { text: ` (\u5171 ${String(body.length)} \u884C \xB7 ${secondsLabel}s)`, token: "fgDim", bold: false },
73968
+ { text: " \xB7 Ctrl+O \u5C55\u5F00", token: "fgDim", bold: false }
73969
+ ], 0, "toolBg", scope.width);
73970
+ return { revision: 0, sourceLength: entry.source.length, lines: [capsule] };
73971
+ }
73822
73972
  const icon = live ? getBrailleSpinnerFrame(reasoningDurationMs) : "\u273B";
73823
73973
  const prefix = live ? "" : "\u25BE ";
73824
73974
  const headerLine = surfaceLine([
@@ -73827,8 +73977,6 @@ function projectReasoningEntry(entry, scope) {
73827
73977
  { text: ` (${secondsLabel}s)`, token: "fgDim", bold: false }
73828
73978
  ], 0, "toolBg", scope.width);
73829
73979
  const lines = [headerLine];
73830
- const escaped = escapeContent(entry.source);
73831
- const body = wrapDisplayLines(escaped, Math.max(1, scope.width - 4));
73832
73980
  for (const row of body) {
73833
73981
  const text4 = `\u2502 ${row}`;
73834
73982
  const cols = displayWidth(text4);
@@ -73866,20 +74014,25 @@ function projectDividerEntry(entry, scope) {
73866
74014
  const line5 = lineForText(entry.source, "fgDim", false, 0);
73867
74015
  return { revision: 0, sourceLength: entry.source.length, lines: [line5] };
73868
74016
  }
73869
- function projectCompactionEntry(entry) {
74017
+ function projectCompactionEntry(entry, scope) {
73870
74018
  const shadowed = entry.meta?.compactionShadowedCount;
73871
74019
  const countLabel = shadowed === void 0 ? "" : ` ${String(shadowed)} \u6761`;
74020
+ const tokens = entry.meta?.compactionShadowedTokenCount;
74021
+ const tokenLabel = tokens === void 0 ? "" : ` \xB7 ~${String(tokens)} tok`;
73872
74022
  const expanded = entry.meta?.compactionExpanded === true;
73873
- const marker = `\u2500\u2500\u2500\u2500 \u2702 \u5DF2\u538B\u7F29${countLabel} \xB7 Ctrl+K ${expanded ? "\u6298\u53E0" : "\u5C55\u5F00"} \u2500\u2500\u2500\u2500`;
74023
+ const marker = `\u2500\u2500\u2500\u2500 \u2702 \u5DF2\u538B\u7F29${countLabel}${tokenLabel} \xB7 Ctrl+K ${expanded ? "\u6298\u53E0" : "\u5C55\u5F00"} \u2500\u2500\u2500\u2500`;
73874
74024
  const lines = [
73875
74025
  lineForText(marker, "fgDim", false, 0)
73876
74026
  ];
73877
74027
  const summary = entry.meta?.compactionSummary ?? "";
73878
74028
  if (expanded && summary !== "") {
73879
- lines.push(mixedLine([
73880
- { text: "\u6458\u8981 ", token: "fgDim", bold: false },
73881
- { text: escapeContent(summary), token: "fg", bold: false }
73882
- ], lines.length));
74029
+ const wrapped = wrapDisplayLines(escapeContent(summary), Math.max(1, scope.width - 4));
74030
+ for (const row of wrapped) {
74031
+ lines.push(surfaceLine([
74032
+ { text: "\u2502 ", token: "accentText", bold: false },
74033
+ { text: row, token: "fg", bold: false }
74034
+ ], lines.length, "toolBg", scope.width));
74035
+ }
73883
74036
  }
73884
74037
  return { revision: 0, sourceLength: entry.source.length, lines };
73885
74038
  }
@@ -74759,8 +74912,8 @@ function isVisiblePart(part) {
74759
74912
  if (part.kind === "card" || part.kind === "tool-summary") return true;
74760
74913
  return part.text !== "";
74761
74914
  }
74762
- function displayedParts(parts, reasoningExpanded) {
74763
- return parts.filter((part) => isVisiblePart(part) && (part.kind !== "reasoning" || reasoningExpanded));
74915
+ function displayedParts(parts, _reasoningExpanded) {
74916
+ return parts.filter(isVisiblePart);
74764
74917
  }
74765
74918
  var COLLAPSED_TOOL_CARD_LIMIT = 3;
74766
74919
  function toolSummaryStatus(summary) {
@@ -74852,7 +75005,8 @@ function activeTurnVersion(turn, revisions) {
74852
75005
  }
74853
75006
  function compactionDividerLabel(divider, expanded) {
74854
75007
  const count = divider.shadowedCount === void 0 ? "" : ` ${String(divider.shadowedCount)} \u6761`;
74855
- return `\u2500\u2500\u2500\u2500 \u2702 \u5DF2\u538B\u7F29${count} \xB7 Ctrl+K ${expanded ? "\u6298\u53E0" : "\u5C55\u5F00"} \u2500\u2500\u2500\u2500`;
75008
+ const tokens = divider.shadowedTokenCount === void 0 ? "" : ` \xB7 ~${String(divider.shadowedTokenCount)} tok`;
75009
+ return `\u2500\u2500\u2500\u2500 \u2702 \u5DF2\u538B\u7F29${count}${tokens} \xB7 Ctrl+K ${expanded ? "\u6298\u53E0" : "\u5C55\u5F00"} \u2500\u2500\u2500\u2500`;
74856
75010
  }
74857
75011
  function partsFrom(content3) {
74858
75012
  const parts = [];
@@ -75191,6 +75345,16 @@ function projectorStateFor(cache4, blockId, scope, aliases = [], source) {
75191
75345
  cache4.set(key, state);
75192
75346
  return state;
75193
75347
  }
75348
+ function stickyToolTitle(card) {
75349
+ return card.resultView?.title ?? card.callView?.title ?? card.name;
75350
+ }
75351
+ function recordToolSticky(map2, id, start, end, card) {
75352
+ if (end - start <= 1) return;
75353
+ const existing = map2.get(id);
75354
+ const next = existing === void 0 ? [] : existing;
75355
+ next.push({ start, end, title: stickyToolTitle(card) });
75356
+ map2.set(id, next);
75357
+ }
75194
75358
  var EMPTY_TEXT_RANGES = [];
75195
75359
  var GAP_LINE = Object.freeze({
75196
75360
  text: " ",
@@ -75370,7 +75534,8 @@ function StreamView({
75370
75534
  motionPaused = false,
75371
75535
  mode = "agent",
75372
75536
  layoutKey,
75373
- locale = "zh-CN"
75537
+ locale = "zh-CN",
75538
+ onStickyHeaderChange
75374
75539
  }) {
75375
75540
  const policy = renderPolicy ?? renderPolicyDefaults();
75376
75541
  const toolRows = (0, import_react37.useMemo)(() => new ToolRowCache(policy.tools), [
@@ -75591,6 +75756,9 @@ function StreamView({
75591
75756
  const map2 = /* @__PURE__ */ new Map();
75592
75757
  const textRanges = /* @__PURE__ */ new Map();
75593
75758
  const storeBlocks = /* @__PURE__ */ new Map();
75759
+ const reasoningSticky = /* @__PURE__ */ new Map();
75760
+ const toolSticky = /* @__PURE__ */ new Map();
75761
+ const userSticky = /* @__PURE__ */ new Map();
75594
75762
  const projectorCache = projectorStates.current;
75595
75763
  const project = makeBlockProjector({ toolRows, plainRows, locale }, storeBlocks);
75596
75764
  const latestAssistant = hasActiveTurn ? void 0 : latestAssistantId(history, void 0);
@@ -75600,7 +75768,8 @@ function StreamView({
75600
75768
  const meta3 = {
75601
75769
  compactionSummary: row.divider.summary,
75602
75770
  compactionExpanded: expandedCompactionId === row.divider.compactionId,
75603
- ...row.divider.shadowedCount === void 0 ? {} : { compactionShadowedCount: row.divider.shadowedCount }
75771
+ ...row.divider.shadowedCount === void 0 ? {} : { compactionShadowedCount: row.divider.shadowedCount },
75772
+ ...row.divider.shadowedTokenCount === void 0 ? {} : { compactionShadowedTokenCount: row.divider.shadowedTokenCount }
75604
75773
  };
75605
75774
  const projection = project(id, {
75606
75775
  id,
@@ -75620,6 +75789,7 @@ function StreamView({
75620
75789
  ...hasSubsequent ? { meta: { userMessageGap: true } } : {}
75621
75790
  }, settledBlockRowsScope, void 0, false);
75622
75791
  map2.set(id, projection.lines);
75792
+ userSticky.set(id, { start: 0, end: projection.lines.length, text: row.message.text });
75623
75793
  continue;
75624
75794
  }
75625
75795
  const parts = displayedParts(
@@ -75632,6 +75802,7 @@ function StreamView({
75632
75802
  for (const [partIndex, part] of parts.entries()) {
75633
75803
  if (turnPartGap(parts, partIndex) > 0) rows2.push(GAP_LINE);
75634
75804
  if (part.kind === "reasoning") {
75805
+ const stickyStart = rows2.length;
75635
75806
  rows2.append(project(id, {
75636
75807
  id: `${id}-r-${String(partIndex)}`,
75637
75808
  kind: "reasoning",
@@ -75642,6 +75813,17 @@ function StreamView({
75642
75813
  reasoningLive: false
75643
75814
  }
75644
75815
  }, settledBlockRowsScope, void 0, false).lines);
75816
+ if (reasoningExpanded && rows2.length - stickyStart > 1) {
75817
+ const existing = reasoningSticky.get(id);
75818
+ const next = existing === void 0 ? [] : [...existing];
75819
+ next.push({
75820
+ start: stickyStart,
75821
+ end: rows2.length,
75822
+ turnOrdinal: row.message.turnOrdinal ?? 1,
75823
+ durationMs: part.durationMs
75824
+ });
75825
+ reasoningSticky.set(id, next);
75826
+ }
75645
75827
  continue;
75646
75828
  }
75647
75829
  if (part.kind === "tool-summary") {
@@ -75655,6 +75837,7 @@ function StreamView({
75655
75837
  continue;
75656
75838
  }
75657
75839
  if (part.kind === "card") {
75840
+ const stickyStart = rows2.length;
75658
75841
  rows2.append(project(
75659
75842
  id,
75660
75843
  makeToolCardBlockEntry(id, part.card),
@@ -75662,6 +75845,7 @@ function StreamView({
75662
75845
  void 0,
75663
75846
  false
75664
75847
  ).lines);
75848
+ recordToolSticky(toolSticky, id, stickyStart, rows2.length, part.card);
75665
75849
  continue;
75666
75850
  }
75667
75851
  const start = rows2.length;
@@ -75710,7 +75894,7 @@ function StreamView({
75710
75894
  map2.set(id, rows2.build());
75711
75895
  if (ranges.length > 0) textRanges.set(id, ranges);
75712
75896
  }
75713
- return { rows: map2, textRanges, storeBlocks };
75897
+ return { rows: map2, textRanges, storeBlocks, reasoningSticky, toolSticky, userSticky };
75714
75898
  }, [
75715
75899
  contentWidth,
75716
75900
  expandedCompactionId,
@@ -75755,7 +75939,7 @@ function StreamView({
75755
75939
  )}s)`
75756
75940
  }
75757
75941
  }, blockRowsScope, void 0, true).lines;
75758
- return { id, lines, ranges: [], storeBlocks };
75942
+ return { id, lines, ranges: [], storeBlocks, reasoningSticky: [], toolSticky: [] };
75759
75943
  }
75760
75944
  const parts = displayedParts(
75761
75945
  compactToolParts(rawParts, toolCardsExpanded, batchPresenters, mode, presenterCache),
@@ -75763,6 +75947,8 @@ function StreamView({
75763
75947
  );
75764
75948
  const rows2 = new RowSequence();
75765
75949
  const ranges = [];
75950
+ const sticky = [];
75951
+ const toolSticky = [];
75766
75952
  let textIndex = 0;
75767
75953
  let lastVisiblePart = -1;
75768
75954
  for (const [partIndex, part] of parts.entries()) {
@@ -75772,16 +75958,26 @@ function StreamView({
75772
75958
  if (turnPartGap(parts, partIndex) > 0) rows2.push(GAP_LINE);
75773
75959
  if (part.kind === "reasoning") {
75774
75960
  const live = status === "generating" && partIndex === lastVisiblePart;
75961
+ const durationMs = live ? liveDurationMs ?? part.durationMs : part.durationMs;
75962
+ const stickyStart = rows2.length;
75775
75963
  rows2.append(project(id, {
75776
75964
  id: `${id}-r-${String(partIndex)}`,
75777
75965
  kind: "reasoning",
75778
75966
  source: part.text,
75779
75967
  meta: {
75780
- reasoningDurationMs: live ? liveDurationMs ?? part.durationMs : part.durationMs,
75968
+ reasoningDurationMs: durationMs,
75781
75969
  reasoningExpanded,
75782
75970
  reasoningLive: live
75783
75971
  }
75784
75972
  }, blockRowsScope, void 0, status === "generating").lines);
75973
+ if (reasoningExpanded && rows2.length - stickyStart > 1) {
75974
+ sticky.push({
75975
+ start: stickyStart,
75976
+ end: rows2.length,
75977
+ turnOrdinal: activeTurn.turn,
75978
+ durationMs
75979
+ });
75980
+ }
75785
75981
  continue;
75786
75982
  }
75787
75983
  if (part.kind === "tool-summary") {
@@ -75795,6 +75991,7 @@ function StreamView({
75795
75991
  continue;
75796
75992
  }
75797
75993
  if (part.kind === "card") {
75994
+ const stickyStart = rows2.length;
75798
75995
  rows2.append(project(
75799
75996
  id,
75800
75997
  makeToolCardBlockEntry(id, part.card),
@@ -75802,6 +75999,13 @@ function StreamView({
75802
75999
  void 0,
75803
76000
  status === "generating"
75804
76001
  ).lines);
76002
+ if (rows2.length - stickyStart > 1) {
76003
+ toolSticky.push({
76004
+ start: stickyStart,
76005
+ end: rows2.length,
76006
+ title: stickyToolTitle(part.card)
76007
+ });
76008
+ }
75805
76009
  continue;
75806
76010
  }
75807
76011
  const start = rows2.length;
@@ -75822,7 +76026,7 @@ function StreamView({
75822
76026
  const lastVisible = parts[parts.length - 1];
75823
76027
  const isReasoningActive = lastRaw?.kind === "reasoning";
75824
76028
  const isToolCompleted = lastVisible?.kind === "card" && lastVisible.card.status !== "running" || lastVisible?.kind === "tool-summary" && lastVisible.summary.runningCount === 0;
75825
- if (isReasoningActive && !reasoningExpanded || isToolCompleted) {
76029
+ if (isToolCompleted && !(isReasoningActive && !reasoningExpanded)) {
75826
76030
  const liveMs = liveDurationMs ?? activeTurn.reasoningDurationMs;
75827
76031
  const spinner = getBrailleSpinnerFrame(liveMs);
75828
76032
  const label = isReasoningActive ? tuiCopy("thinking", locale) : tuiCopy("processing", locale);
@@ -75837,7 +76041,7 @@ function StreamView({
75837
76041
  }, blockRowsScope, void 0, true).lines);
75838
76042
  }
75839
76043
  }
75840
- return { id, lines: rows2.build(), ranges, storeBlocks };
76044
+ return { id, lines: rows2.build(), ranges, storeBlocks, reasoningSticky: sticky, toolSticky };
75841
76045
  }, [
75842
76046
  activeTurn,
75843
76047
  activeVersion,
@@ -75867,7 +76071,15 @@ function StreamView({
75867
76071
  for (const [key, val] of activeTurnRows.storeBlocks) {
75868
76072
  storeBlocks.set(key, val);
75869
76073
  }
75870
- return { rows: map2, textRanges, storeBlocks };
76074
+ const reasoningSticky = new Map(settledEntryRows.reasoningSticky);
76075
+ if (activeTurnRows.reasoningSticky.length > 0) {
76076
+ reasoningSticky.set(activeTurnRows.id, activeTurnRows.reasoningSticky);
76077
+ }
76078
+ const toolSticky = new Map(settledEntryRows.toolSticky);
76079
+ if (activeTurnRows.toolSticky.length > 0) {
76080
+ toolSticky.set(activeTurnRows.id, activeTurnRows.toolSticky);
76081
+ }
76082
+ return { rows: map2, textRanges, storeBlocks, reasoningSticky, toolSticky, userSticky: settledEntryRows.userSticky };
75871
76083
  }, [settledEntryRows, activeTurnRows]);
75872
76084
  const [presentedEntryRows, setPresentedEntryRows] = (0, import_react37.useState)(entryRows);
75873
76085
  const activeEntryRows = status === "generating" ? presentedEntryRows : entryRows;
@@ -76103,6 +76315,58 @@ function StreamView({
76103
76315
  virtualContentRows - effectiveViewportRows - effectiveOffset
76104
76316
  );
76105
76317
  const visibleBottom = visibleTop + effectiveViewportRows;
76318
+ const stickyRanges = (0, import_react37.useMemo)(() => {
76319
+ const reasoning = [];
76320
+ const tools = [];
76321
+ const users = [];
76322
+ for (const layout of virtualLayouts) {
76323
+ if (reasoningExpanded) {
76324
+ const relative = activeEntryRows.reasoningSticky.get(layout.id);
76325
+ if (relative !== void 0) {
76326
+ for (const range of relative) {
76327
+ reasoning.push({
76328
+ start: layout.top + range.start,
76329
+ end: layout.top + range.end,
76330
+ turnOrdinal: range.turnOrdinal,
76331
+ durationMs: range.durationMs
76332
+ });
76333
+ }
76334
+ }
76335
+ }
76336
+ const toolRelative = activeEntryRows.toolSticky.get(layout.id);
76337
+ if (toolRelative !== void 0) {
76338
+ for (const range of toolRelative) {
76339
+ tools.push({
76340
+ start: layout.top + range.start,
76341
+ end: layout.top + range.end,
76342
+ title: range.title
76343
+ });
76344
+ }
76345
+ }
76346
+ const userRelative = activeEntryRows.userSticky.get(layout.id);
76347
+ if (userRelative !== void 0) {
76348
+ users.push({
76349
+ start: layout.top + userRelative.start,
76350
+ end: layout.top + userRelative.end,
76351
+ text: userRelative.text
76352
+ });
76353
+ }
76354
+ }
76355
+ return { reasoning, tools, users };
76356
+ }, [
76357
+ activeEntryRows.reasoningSticky,
76358
+ activeEntryRows.toolSticky,
76359
+ activeEntryRows.userSticky,
76360
+ reasoningExpanded,
76361
+ virtualLayouts
76362
+ ]);
76363
+ const stickyLabel = resolveStickyTranscriptHeader(visibleTop, stickyRanges);
76364
+ (0, import_react37.useLayoutEffect)(() => {
76365
+ onStickyHeaderChange?.(stickyLabel);
76366
+ return () => {
76367
+ onStickyHeaderChange?.(void 0);
76368
+ };
76369
+ }, [onStickyHeaderChange, stickyLabel]);
76106
76370
  const configuredOverscanRows = Math.max(
76107
76371
  0,
76108
76372
  Math.min(
@@ -76338,7 +76602,6 @@ function StreamView({
76338
76602
  } : void 0;
76339
76603
  const visibleFrame = (0, import_react37.useMemo)(() => {
76340
76604
  const snapshotRows = [];
76341
- const verticalBase = Math.max(0, effectiveViewportRows - virtualContentRows);
76342
76605
  for (const { entry, index: layoutIndex } of visibleEntryPairs) {
76343
76606
  const layout = virtualLayouts[layoutIndex];
76344
76607
  if (layout === void 0) continue;
@@ -76349,7 +76612,7 @@ function StreamView({
76349
76612
  for (let index2 = start; index2 < end; index2 += 1) {
76350
76613
  const line5 = entry.lines.at(index2);
76351
76614
  if (line5 === void 0) continue;
76352
- const absoluteRow = 3 + verticalBase + layout.top + index2 - visibleTop;
76615
+ const absoluteRow = 3 + layout.top + index2 - visibleTop;
76353
76616
  if (absoluteRow < 3 || absoluteRow >= 3 + effectiveViewportRows) continue;
76354
76617
  const isBottomRow = absoluteRow === 3 + effectiveViewportRows - 1;
76355
76618
  const promptOverlay = isBottomRow && !viewport.follow ? (() => {
@@ -76560,10 +76823,10 @@ function StreamView({
76560
76823
  const expanded = divider.compactionId === expandedCompactionId;
76561
76824
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
76562
76825
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([styled(escapeContent(compactionDividerLabel(divider, expanded)), "fgDim")]) }),
76563
- expanded && divider.summary !== "" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: paintRow([
76564
- styled("\u6458\u8981 ", "fgDim"),
76565
- styled(escapeContent(divider.summary), "fg")
76566
- ]) }) : null
76826
+ expanded && divider.summary !== "" ? wrapDisplayLines(escapeContent(divider.summary), Math.max(1, contentWidth - 4)).map((row, index2) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow([
76827
+ styled("\u2502 ", "accentText"),
76828
+ styled(row, "fg")
76829
+ ], "toolBg", contentWidth) }, index2)) : null
76567
76830
  ] });
76568
76831
  };
76569
76832
  const renderActiveTurn = (turn) => {
@@ -76597,7 +76860,7 @@ function StreamView({
76597
76860
  const lastVisible = parts[parts.length - 1];
76598
76861
  const isReasoningActive = lastRaw?.kind === "reasoning";
76599
76862
  const isToolCompleted = lastVisible?.kind === "card" && lastVisible.card.status !== "running" || lastVisible?.kind === "tool-summary" && lastVisible.summary.runningCount === 0;
76600
- const showTail = generating && (isReasoningActive && !reasoningExpanded || isToolCompleted);
76863
+ const showTail = generating && isToolCompleted && !(isReasoningActive && !reasoningExpanded);
76601
76864
  const tailLiveMs = liveDurationMs ?? turn.reasoningDurationMs;
76602
76865
  const tailSpinner = getBrailleSpinnerFrame(tailLiveMs);
76603
76866
  const tailLabel = isReasoningActive ? tuiCopy("thinking", locale) : tuiCopy("processing", locale);
@@ -76656,7 +76919,8 @@ function StreamView({
76656
76919
  {
76657
76920
  flexDirection: "column",
76658
76921
  position: physicalViewport ? "absolute" : "relative",
76659
- bottom: physicalViewport ? -effectiveOffset : void 0,
76922
+ top: physicalViewport && virtualContentRows <= effectiveViewportRows ? 0 : void 0,
76923
+ bottom: physicalViewport && virtualContentRows > effectiveViewportRows ? -effectiveOffset : void 0,
76660
76924
  left: physicalViewport ? contentLeft : void 0,
76661
76925
  marginLeft: physicalViewport ? void 0 : contentLeft,
76662
76926
  width: contentWidth,
@@ -78350,10 +78614,37 @@ function WorkspacePane({
78350
78614
  state,
78351
78615
  maxCols
78352
78616
  }) {
78617
+ const { rows: windowRows } = use_window_size_default();
78353
78618
  if (!state.open) return null;
78354
78619
  if (state.error !== void 0) {
78355
78620
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u533A", error: state.error, footnote: "Esc \u5173\u95ED" });
78356
78621
  }
78622
+ if (state.preview !== void 0) {
78623
+ const { name: name2, lines: fileLines, scrollOffset } = state.preview;
78624
+ const pageSize = Math.max(1, windowRows - 6);
78625
+ const total = fileLines.length;
78626
+ const start = Math.min(scrollOffset, Math.max(0, total - 1));
78627
+ const slice = fileLines.slice(start, start + pageSize);
78628
+ const gutterWidth = Math.max(3, String(start + slice.length).length);
78629
+ const previewRows = slice.map((line5, idx) => {
78630
+ const lineNum = start + idx + 1;
78631
+ const lineStr = String(lineNum).padStart(gutterWidth, " ");
78632
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { wrap: "truncate", children: paintRow([
78633
+ styled(`${lineStr} \u2502 `, "fgDim"),
78634
+ styled(escapeContent(line5), "fg")
78635
+ ]) }, lineNum);
78636
+ });
78637
+ const title = `\u9884\u89C8: ${name2} (${String(start + 1)}-${String(Math.min(start + slice.length, total))}/${String(total)} \u884C)`;
78638
+ const footnote2 = "j/k \u6EDA\u52A8 \xB7 q/Esc \u8FD4\u56DE \xB7 i \u63D2\u5165\u8DEF\u5F84";
78639
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
78640
+ OverlayShell,
78641
+ {
78642
+ title,
78643
+ footnote: footnote2,
78644
+ children: previewRows
78645
+ }
78646
+ );
78647
+ }
78357
78648
  const footnote = state.editing ? "Enter \u89E3\u6790 \xB7 Esc \u53D6\u6D88" : state.nodes.length === 0 ? "e \u8F93\u5165\u8DEF\u5F84 \xB7 Esc \u5173\u95ED" : "j/k \u9009\u62E9 \xB7 Enter \u6253\u5F00 \xB7 e \u8DEF\u5F84 \xB7 Esc \u5173\u95ED";
78358
78649
  const rows = [];
78359
78650
  state.nodes.forEach((node2, index2) => {
@@ -79039,19 +79330,7 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
79039
79330
  return holdComposer(state, { kind: "plan-directory-apply" });
79040
79331
  }
79041
79332
  if (workspaceOpen) {
79042
- if (overlays.workspace?.selectedKind === "file") {
79043
- const caret = clampCaretIndex(state.text, state.caretIndex);
79044
- const path2 = overlays.workspace.selectedPath ?? "";
79045
- return {
79046
- kind: "dispatch",
79047
- action: { kind: "workspace-enter" },
79048
- text: state.text.slice(0, caret) + path2 + state.text.slice(caret),
79049
- commandQuery: void 0,
79050
- prefixG: false,
79051
- renaming: state.renaming,
79052
- caretIndex: caret + path2.length
79053
- };
79054
- }
79333
+ if (overlays.workspace?.preview === true) return { kind: "none" };
79055
79334
  return holdComposer(state, { kind: "workspace-enter" });
79056
79335
  }
79057
79336
  if (modelPane.open) {
@@ -79361,7 +79640,33 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
79361
79640
  if (key === "k" || keyInfo.upArrow) {
79362
79641
  return holdComposer(state, { kind: "workspace-move", delta: -1 });
79363
79642
  }
79364
- if (key === "e") {
79643
+ if (keyInfo.pageUp) {
79644
+ return holdComposer(state, { kind: "workspace-move", delta: -20 });
79645
+ }
79646
+ if (keyInfo.pageDown) {
79647
+ return holdComposer(state, { kind: "workspace-move", delta: 20 });
79648
+ }
79649
+ if (key === " ") {
79650
+ if (overlays.workspace?.preview === true) return { kind: "none" };
79651
+ return holdComposer(state, { kind: "workspace-enter" });
79652
+ }
79653
+ if (key === "q") {
79654
+ return holdComposer(state, { kind: "workspace-escape" });
79655
+ }
79656
+ if (key === "i") {
79657
+ const path2 = overlays.workspace?.selectedPath ?? "";
79658
+ const caret = clampCaretIndex(state.text, state.caretIndex);
79659
+ return {
79660
+ kind: "dispatch",
79661
+ action: { kind: "workspace-insert" },
79662
+ text: state.text.slice(0, caret) + path2 + state.text.slice(caret),
79663
+ commandQuery: void 0,
79664
+ prefixG: false,
79665
+ renaming: state.renaming,
79666
+ caretIndex: caret + path2.length
79667
+ };
79668
+ }
79669
+ if (key === "e" && overlays.workspace?.preview !== true) {
79365
79670
  const draft = overlays.workspace?.rootPath ?? "";
79366
79671
  return {
79367
79672
  kind: "dispatch",
@@ -79681,6 +79986,7 @@ function TuiLoop({
79681
79986
  const [planReviewOffset, setPlanReviewOffset] = (0, import_react39.useState)(0);
79682
79987
  const viewportSequenceRef = (0, import_react39.useRef)(0);
79683
79988
  const [viewportCommand, setViewportCommand] = (0, import_react39.useState)();
79989
+ const [topDividerLabel, setTopDividerLabel] = (0, import_react39.useState)();
79684
79990
  const issueViewportCommand = (0, import_react39.useCallback)((command) => {
79685
79991
  frameProbe?.beginMeasurement();
79686
79992
  viewportSequenceRef.current += 1;
@@ -80009,7 +80315,8 @@ function TuiLoop({
80009
80315
  editing: workspacePaneRef.current.editing,
80010
80316
  rootPath: workspacePaneRef.current.root,
80011
80317
  selectedKind: workspacePaneRef.current.nodes[workspacePaneRef.current.selectedIndex]?.kind,
80012
- selectedPath: workspacePaneRef.current.nodes[workspacePaneRef.current.selectedIndex]?.path
80318
+ selectedPath: workspacePaneRef.current.nodes[workspacePaneRef.current.selectedIndex]?.path,
80319
+ preview: workspacePaneRef.current.preview !== void 0
80013
80320
  },
80014
80321
  feedback: {
80015
80322
  open: feedbackPaneRef.current.open,
@@ -80385,7 +80692,8 @@ function TuiLoop({
80385
80692
  renderPolicy,
80386
80693
  frameMetrics,
80387
80694
  motionPaused: viewportMotionPaused,
80388
- mode: currentMode
80695
+ mode: currentMode,
80696
+ onStickyHeaderChange: setTopDividerLabel
80389
80697
  });
80390
80698
  const conversationColumns = conversationWidth(columns);
80391
80699
  const hudRows = [];
@@ -80612,7 +80920,8 @@ function TuiLoop({
80612
80920
  badge: adaptiveInfoFooter === void 0 ? badge : shortenHomePath(controller.getCwd(), homedir()),
80613
80921
  status,
80614
80922
  children: content3,
80615
- input: inputSlot
80923
+ input: inputSlot,
80924
+ topDividerLabel
80616
80925
  });
80617
80926
  }
80618
80927
 
@@ -81077,6 +81386,7 @@ function createProjector() {
81077
81386
  compactionDividers[index2] = deepFreeze({
81078
81387
  ...current,
81079
81388
  shadowedCount: event.data.shadowedSeqs.length,
81389
+ shadowedTokenCount: event.data.shadowedTokenCount,
81080
81390
  summary: event.data.summary.filter((block) => block.type === "text").map((block) => block.text).join("")
81081
81391
  });
81082
81392
  return;
@@ -82308,6 +82618,7 @@ var SEARCH_LIMIT = 30;
82308
82618
  var SEARCH_DEBOUNCE_MS = 120;
82309
82619
  var LOCAL_COMMANDS = [
82310
82620
  { name: "export", description: "Export this session to a Markdown file" },
82621
+ { name: "files", description: "Browse and preview workspace files" },
82311
82622
  { name: "help", description: "Show command help and key bindings" },
82312
82623
  { name: "key", description: "Set or update API key", input: { hint: "[KEY_NAME] <SECRET>" } },
82313
82624
  { name: "login", description: "Set or update API key", input: { hint: "[KEY_NAME] <SECRET>" } },
@@ -82604,6 +82915,7 @@ var RuntimeController = class _RuntimeController {
82604
82915
  workspaceResolveError;
82605
82916
  /** Stale guard for in-flight workspace loads; bumped on open/close/re-root. */
82606
82917
  workspaceSeq = 0;
82918
+ workspacePreview = void 0;
82607
82919
  feedbackOpen = false;
82608
82920
  /** True while the feedback note draft owns the composer. */
82609
82921
  feedbackEditing = false;
@@ -83086,7 +83398,8 @@ var RuntimeController = class _RuntimeController {
83086
83398
  selectedIndex: this.workspaceSelectedIndex,
83087
83399
  editing: this.workspaceEditing,
83088
83400
  error: fs3 === void 0 ? "\u6587\u4EF6\u7CFB\u7EDF\u672A\u7EC4\u5408" : void 0,
83089
- resolveError: this.workspaceResolveError
83401
+ resolveError: this.workspaceResolveError,
83402
+ preview: this.workspacePreview
83090
83403
  };
83091
83404
  }
83092
83405
  return this.workspacePaneSnapshot;
@@ -83177,6 +83490,29 @@ var RuntimeController = class _RuntimeController {
83177
83490
  this.workspaceSelectedIndex = 0;
83178
83491
  this.workspaceResolveError = void 0;
83179
83492
  }
83493
+ /** Load a workspace file into the inline previewer. */
83494
+ async openWorkspacePreview(row) {
83495
+ const fs3 = this.ctx.get("fs");
83496
+ if (fs3 === void 0) return;
83497
+ const seq = this.workspaceSeq;
83498
+ try {
83499
+ const text4 = await fs3.readText(row.target);
83500
+ if (seq !== this.workspaceSeq || !this.workspaceOpen) return;
83501
+ const lines = text4.split(/\r?\n/u);
83502
+ const capped = lines.length > 5e3 ? [...lines.slice(0, 5e3), "\u2026 (truncated)"] : lines;
83503
+ this.workspacePreview = {
83504
+ path: row.target.displayPath,
83505
+ name: row.name,
83506
+ lines: capped,
83507
+ scrollOffset: 0
83508
+ };
83509
+ this.workspacePaneSnapshot = void 0;
83510
+ this.emit();
83511
+ } catch (error51) {
83512
+ if (seq !== this.workspaceSeq || !this.workspaceOpen) return;
83513
+ this.setFeedback(`\u2717 \u65E0\u6CD5\u9884\u89C8\u6587\u4EF6\uFF1A${errorReason(error51)}`);
83514
+ }
83515
+ }
83180
83516
  /**
83181
83517
  * Return the message-feedback overlay targeting the assistant message that
83182
83518
  * was latest when the overlay opened. Paints the S19 opener error when the
@@ -84235,6 +84571,7 @@ var RuntimeController = class _RuntimeController {
84235
84571
  return;
84236
84572
  case "workspace-pane": {
84237
84573
  const opening = !this.workspaceOpen;
84574
+ this.workspacePreview = void 0;
84238
84575
  this.toggleOverlay("workspaceOpen");
84239
84576
  if (opening) {
84240
84577
  this.workspaceSeq += 1;
@@ -84247,12 +84584,26 @@ var RuntimeController = class _RuntimeController {
84247
84584
  }
84248
84585
  case "workspace-escape":
84249
84586
  if (!this.workspaceOpen) return;
84587
+ if (this.workspacePreview !== void 0) {
84588
+ this.workspacePreview = void 0;
84589
+ this.workspacePaneSnapshot = void 0;
84590
+ this.emit();
84591
+ return;
84592
+ }
84250
84593
  this.workspaceOpen = false;
84251
84594
  this.workspaceSeq += 1;
84252
84595
  this.emit();
84253
84596
  return;
84254
84597
  case "workspace-move": {
84255
84598
  if (!this.workspaceOpen || this.workspaceEditing) return;
84599
+ if (this.workspacePreview !== void 0) {
84600
+ const maxOffset2 = Math.max(0, this.workspacePreview.lines.length - 1);
84601
+ const nextOffset = Math.min(maxOffset2, Math.max(0, this.workspacePreview.scrollOffset + action.delta));
84602
+ this.workspacePreview = { ...this.workspacePreview, scrollOffset: nextOffset };
84603
+ this.workspacePaneSnapshot = void 0;
84604
+ this.emit();
84605
+ return;
84606
+ }
84256
84607
  const rowCount = this.computeWorkspaceRows().length;
84257
84608
  this.workspaceSelectedIndex = Math.min(
84258
84609
  Math.max(0, rowCount - 1),
@@ -84263,6 +84614,7 @@ var RuntimeController = class _RuntimeController {
84263
84614
  }
84264
84615
  case "workspace-enter": {
84265
84616
  if (!this.workspaceOpen || this.workspaceEditing) return;
84617
+ if (this.workspacePreview !== void 0) return;
84266
84618
  const row = this.computeWorkspaceRows()[this.workspaceSelectedIndex];
84267
84619
  if (row === void 0) return;
84268
84620
  if (row.kind === "directory") {
@@ -84270,12 +84622,20 @@ var RuntimeController = class _RuntimeController {
84270
84622
  return;
84271
84623
  }
84272
84624
  if (row.kind === "file") {
84273
- this.workspaceOpen = false;
84274
- this.workspaceSeq += 1;
84275
- this.emit();
84625
+ this.ownWork(this.openWorkspacePreview(row), "workspace file preview");
84276
84626
  }
84277
84627
  return;
84278
84628
  }
84629
+ case "workspace-insert": {
84630
+ if (!this.workspaceOpen) return;
84631
+ this.workspaceOpen = false;
84632
+ this.workspacePreview = void 0;
84633
+ this.workspaceEditing = false;
84634
+ this.workspaceSeq += 1;
84635
+ this.workspacePaneSnapshot = void 0;
84636
+ this.emit();
84637
+ return;
84638
+ }
84279
84639
  case "workspace-edit":
84280
84640
  if (!this.workspaceOpen) return;
84281
84641
  this.workspaceEditing = true;
@@ -85387,6 +85747,12 @@ var RuntimeController = class _RuntimeController {
85387
85747
  this.togglePresentationFlag(query === "status" ? "statusDetails" : query);
85388
85748
  return;
85389
85749
  }
85750
+ if (query === "files" || query === "files " || query === "workspace" || query === "workspace ") {
85751
+ if (this.blockingHead() !== void 0) return;
85752
+ this.closeOtherPanels();
85753
+ this.dispatch({ kind: "workspace-pane" });
85754
+ return;
85755
+ }
85390
85756
  if (query === "export") {
85391
85757
  this.ownWork(this.exportLive(), "session export");
85392
85758
  return;
@@ -86155,7 +86521,7 @@ var RuntimeController = class _RuntimeController {
86155
86521
  "g a \u5B50\u4EE3\u7406 \xB7 g t \u5DE5\u4F5C\u533A \xB7 g f \u53CD\u9988 \xB7 g w \u5DE5\u4F5C\u6D41",
86156
86522
  "\u2191\u2193/jk \u6EDA\u52A8 \xB7 g s \u4F1A\u8BDD\u5217\u8868 \xB7 Tab \u8865\u5168 \xB7 Esc \u5173\u95ED \xB7 / \u547D\u4EE4 \xB7 @ \u63D0\u53CA",
86157
86523
  "\u6EDA\u8F6E\u6EDA\u52A8 \xB7 \u70B9\u51FB\u6253\u5F00\u94FE\u63A5 \xB7 \u62D6\u9009\u590D\u5236",
86158
- "/plan \u8BA1\u5212 \xB7 /goal \u76EE\u6807 \xB7 /compact \u538B\u7F29",
86524
+ "/files \u5DE5\u4F5C\u533A \xB7 /plan \u8BA1\u5212 \xB7 /goal \u76EE\u6807 \xB7 /compact \u538B\u7F29",
86159
86525
  "/model \u6A21\u578B\u9009\u62E9 \xB7 /new \u65B0\u4F1A\u8BDD \xB7 /help \u5E2E\u52A9 \xB7 /export \u5BFC\u51FA\u4F1A\u8BDD \xB7 /settings \u8BBE\u7F6E \xB7 /resume \u4F1A\u8BDD \xB7 /reload \u91CD\u8F7D"
86160
86526
  ];
86161
86527
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crazyhappyone/dsh-tui",
3
- "version": "0.1.0-alpha.44",
3
+ "version": "0.1.0-alpha.46",
4
4
  "description": "Source-runtime launcher for the DeepSeek Harness terminal interface",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -87,10 +87,6 @@
87
87
  timeoutMs: 60000
88
88
 
89
89
  - insert:
90
- # Code Mode is a core execution capability, not a Web component.
91
- - id: code-runtime
92
- name: "@deepseek-ai/dsh-code-runtime-worker-thread"
93
-
94
90
  # Per-round token/duration stats for the terminal status line.
95
91
  - id: session-stats
96
92
  name: "@deepseek-ai/dsh-session-stats"