@crazyhappyone/dsh-tui 0.1.0-alpha.5 → 0.1.0-alpha.7

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
@@ -1,4 +1,3 @@
1
- import * as __nodeModule from 'node:module'; const require = __nodeModule.createRequire(import.meta.url);
2
1
  var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -31876,6 +31875,126 @@ function assertNever(value, context) {
31876
31875
  const rendered = JSON.stringify(value) ?? String(value);
31877
31876
  throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`);
31878
31877
  }
31878
+ function hasIntrinsicConstructor(prototype, name2) {
31879
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, "constructor");
31880
+ const constructor = descriptor?.value;
31881
+ if (typeof constructor !== "function") return false;
31882
+ try {
31883
+ return constructor.name === name2 && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name2}() { [native code] }`;
31884
+ } catch {
31885
+ return false;
31886
+ }
31887
+ }
31888
+ function isIntrinsicObjectPrototype(value) {
31889
+ return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, "Object");
31890
+ }
31891
+ function hasPlainArrayPrototype(value) {
31892
+ const prototype = Object.getPrototypeOf(value);
31893
+ if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false;
31894
+ const objectPrototype = Object.getPrototypeOf(prototype);
31895
+ return typeof objectPrototype === "object" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);
31896
+ }
31897
+ function hasPlainObjectPrototype(value) {
31898
+ const prototype = Object.getPrototypeOf(value);
31899
+ return prototype === null || typeof prototype === "object" && isIntrinsicObjectPrototype(prototype);
31900
+ }
31901
+ function enumerableStringKeys(value) {
31902
+ const keys = Reflect.ownKeys(value);
31903
+ if (keys.some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;
31904
+ return keys;
31905
+ }
31906
+ function walkJsonValue(value, detach) {
31907
+ const ancestors = /* @__PURE__ */ new Set();
31908
+ let root;
31909
+ const assign = (destination, item) => {
31910
+ if (destination === void 0) return;
31911
+ if (destination.kind === "root") {
31912
+ root = item;
31913
+ } else if (destination.kind === "array") {
31914
+ destination.target[destination.index] = item;
31915
+ } else {
31916
+ Object.defineProperty(destination.target, destination.key, {
31917
+ value: item,
31918
+ enumerable: true,
31919
+ configurable: true,
31920
+ writable: true
31921
+ });
31922
+ }
31923
+ };
31924
+ const tasks = [{
31925
+ kind: "visit",
31926
+ value,
31927
+ ...detach ? { destination: { kind: "root" } } : {}
31928
+ }];
31929
+ for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {
31930
+ if (task.kind === "leave") {
31931
+ ancestors.delete(task.source);
31932
+ continue;
31933
+ }
31934
+ if (task.kind === "array-item") {
31935
+ if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;
31936
+ tasks.push({
31937
+ kind: "visit",
31938
+ value: task.source[task.index],
31939
+ ...task.target === void 0 ? {} : { destination: { kind: "array", target: task.target, index: task.index } }
31940
+ });
31941
+ continue;
31942
+ }
31943
+ if (task.kind === "object-property") {
31944
+ tasks.push({
31945
+ kind: "visit",
31946
+ value: task.source[task.key],
31947
+ ...task.target === void 0 ? {} : { destination: { kind: "object", target: task.target, key: task.key } }
31948
+ });
31949
+ continue;
31950
+ }
31951
+ const current = task.value;
31952
+ if (current === null) {
31953
+ assign(task.destination, null);
31954
+ continue;
31955
+ }
31956
+ if (typeof current === "boolean" || typeof current === "string") {
31957
+ assign(task.destination, current);
31958
+ continue;
31959
+ }
31960
+ if (typeof current === "number") {
31961
+ if (!Number.isFinite(current) || Object.is(current, -0)) return void 0;
31962
+ assign(task.destination, current);
31963
+ continue;
31964
+ }
31965
+ if (typeof current !== "object") return void 0;
31966
+ if (ancestors.has(current)) return void 0;
31967
+ if (Array.isArray(current)) {
31968
+ if (!hasPlainArrayPrototype(current)) return void 0;
31969
+ const length = current.length;
31970
+ if (Reflect.ownKeys(current).length !== length + 1) return void 0;
31971
+ const target2 = detach ? [] : void 0;
31972
+ if (target2 !== void 0) assign(task.destination, target2);
31973
+ ancestors.add(current);
31974
+ tasks.push({ kind: "leave", source: current });
31975
+ for (let index2 = length - 1; index2 >= 0; index2--) {
31976
+ tasks.push({ kind: "array-item", source: current, index: index2, ...target2 === void 0 ? {} : { target: target2 } });
31977
+ }
31978
+ continue;
31979
+ }
31980
+ if (!hasPlainObjectPrototype(current)) return void 0;
31981
+ const keys = enumerableStringKeys(current);
31982
+ if (keys === void 0) return void 0;
31983
+ const target = detach ? {} : void 0;
31984
+ if (target !== void 0) assign(task.destination, target);
31985
+ ancestors.add(current);
31986
+ tasks.push({ kind: "leave", source: current });
31987
+ for (let index2 = keys.length - 1; index2 >= 0; index2--) {
31988
+ const key = keys[index2];
31989
+ if (key === void 0) return void 0;
31990
+ tasks.push({ kind: "object-property", source: current, key, ...target === void 0 ? {} : { target } });
31991
+ }
31992
+ }
31993
+ return detach ? root : true;
31994
+ }
31995
+ function snapshotJsonValue(value) {
31996
+ return walkJsonValue(value, true);
31997
+ }
31879
31998
  function deepFreeze(value) {
31880
31999
  const seen = /* @__PURE__ */ new WeakSet();
31881
32000
  const pending = [{ kind: "visit", node: value }];
@@ -32970,10 +33089,763 @@ var UserQuestionError = class extends HarnessError {
32970
33089
  }
32971
33090
  };
32972
33091
 
33092
+ // ../deepseek-harness/packages/core/session/src/index.ts
33093
+ import { isAbsolute } from "node:path";
33094
+
32973
33095
  // ../deepseek-harness/packages/core/session/src/types.ts
32974
33096
  function SessionId(id) {
32975
33097
  return brandString(id);
32976
33098
  }
33099
+ var SESSION_FORMAT_VERSION = 0;
33100
+
33101
+ // ../deepseek-harness/packages/core/session/src/surface.ts
33102
+ var SURFACE_EVENT_TYPES = /* @__PURE__ */ new Set([
33103
+ "user/message",
33104
+ "assistant/message",
33105
+ "tool/result"
33106
+ ]);
33107
+ function isSurfaceEligibleType(type) {
33108
+ return SURFACE_EVENT_TYPES.has(type);
33109
+ }
33110
+ function deriveEventMessage(event) {
33111
+ switch (event.type) {
33112
+ // Ordinary prompts and injected context project in user role: the event's
33113
+ // model-facing content stays verbatim. Do NOT re-add per-type framing
33114
+ // (e.g. `<context>`) here: framing is caller-owned — a producer bakes it
33115
+ // into `content`, as agent-instructions does with `<system-reminder>` — or,
33116
+ // if reintroduced, must be driven by the event `meta` map and a dedicated
33117
+ // renderer, keeping this projection a verbatim pass-through. See the
33118
+ // deferred design note in
33119
+ // ../../../../.agents/notes/implemented/simplification/2026-07-20-unwrap-injected-content-envelopes.md
33120
+ case "user/message": {
33121
+ return event.data;
33122
+ }
33123
+ case "assistant/message": {
33124
+ if (event.data.message.content.length === 0) return null;
33125
+ return event.data.message;
33126
+ }
33127
+ case "tool/result": {
33128
+ return event.data.message;
33129
+ }
33130
+ default:
33131
+ return null;
33132
+ }
33133
+ }
33134
+ function createFoldState() {
33135
+ return { nodes: [], replaceGeneration: 0 };
33136
+ }
33137
+ function isEventSeq(value) {
33138
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
33139
+ }
33140
+ function isReplaceOp(value) {
33141
+ const op = value;
33142
+ return Object.keys(op).length === 3 && Object.hasOwn(op, "op") && Object.hasOwn(op, "start") && Object.hasOwn(op, "end") && op["op"] === "replace" && isEventSeq(op["start"]) && isEventSeq(op["end"]);
33143
+ }
33144
+ function surfaceOpOf(event) {
33145
+ const raw = event;
33146
+ if (!isSurfaceEligibleType(event.type)) {
33147
+ if (raw.surfaceOp !== void 0) {
33148
+ throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`);
33149
+ }
33150
+ if (raw.sourceEventSeqs !== void 0) {
33151
+ throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`);
33152
+ }
33153
+ return;
33154
+ }
33155
+ const op = raw.surfaceOp;
33156
+ if (op === void 0) {
33157
+ throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`);
33158
+ }
33159
+ if (op === "append") return op;
33160
+ if (op === null || typeof op !== "object" || Array.isArray(op)) {
33161
+ throw new Error(`session event "${event.type}" carries an invalid surfaceOp`);
33162
+ }
33163
+ if (!isReplaceOp(op)) {
33164
+ throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`);
33165
+ }
33166
+ return op;
33167
+ }
33168
+ function assertProvenance(event, shadowedSeqs) {
33169
+ const raw = event.sourceEventSeqs;
33170
+ const sources = /* @__PURE__ */ new Set();
33171
+ if (raw !== void 0) {
33172
+ if (!Array.isArray(raw)) {
33173
+ throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`);
33174
+ }
33175
+ if (raw.length === 0 && event.type !== "assistant/message") {
33176
+ throw new Error("sourceEventSeqs must not be empty except on assistant/message");
33177
+ }
33178
+ let nonEarlierSource;
33179
+ for (const source of raw) {
33180
+ if (!isEventSeq(source)) {
33181
+ throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`);
33182
+ }
33183
+ sources.add(source);
33184
+ if (nonEarlierSource === void 0 && source >= event.seq) nonEarlierSource = source;
33185
+ }
33186
+ if (sources.size !== raw.length) {
33187
+ throw new Error("sourceEventSeqs must not contain duplicates");
33188
+ }
33189
+ if (nonEarlierSource !== void 0) {
33190
+ throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`);
33191
+ }
33192
+ }
33193
+ const missing = shadowedSeqs.filter((seq) => !sources.has(seq));
33194
+ if (missing.length > 0) {
33195
+ throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(", ")}`);
33196
+ }
33197
+ }
33198
+ function replacementRange(state, op) {
33199
+ const startIdx = state.nodes.indexOf(op.start);
33200
+ if (startIdx === -1) {
33201
+ throw new Error(`surface replace: start seq ${op.start} not found in surface`);
33202
+ }
33203
+ const endIdx = state.nodes.indexOf(op.end);
33204
+ if (endIdx === -1) {
33205
+ throw new Error(`surface replace: end seq ${op.end} not found in surface`);
33206
+ }
33207
+ if (startIdx > endIdx) {
33208
+ throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`);
33209
+ }
33210
+ return {
33211
+ startIdx,
33212
+ endIdx,
33213
+ shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1)
33214
+ };
33215
+ }
33216
+ function isDeepEqualJson(a, b) {
33217
+ if (a === b) return true;
33218
+ if (Array.isArray(a) || Array.isArray(b)) {
33219
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
33220
+ return a.every((item, i) => isDeepEqualJson(item, b[i]));
33221
+ }
33222
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
33223
+ const aKeys = Object.keys(a);
33224
+ const bRecord = b;
33225
+ if (aKeys.length !== Object.keys(b).length) return false;
33226
+ return aKeys.every((key) => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key]));
33227
+ }
33228
+ function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) {
33229
+ if (event.type !== "tool/result") return;
33230
+ if (shadowedSeqs.length !== 1) {
33231
+ throw new Error("tool/result surface replacement must rewrite exactly one current node");
33232
+ }
33233
+ for (const originalSeq of shadowedSeqs) {
33234
+ const original = events[originalSeq - baseSeq];
33235
+ if (original?.type !== "tool/result") {
33236
+ throw new Error("tool/result surface replacement must target a current tool/result");
33237
+ }
33238
+ const originalRest = { ...original.data };
33239
+ const replacementRest = { ...event.data };
33240
+ const originalResult = original.data.message.content[0];
33241
+ const replacementResult = event.data.message.content[0];
33242
+ originalRest["message"] = {
33243
+ ...original.data.message,
33244
+ content: [{ ...originalResult, content: null }]
33245
+ };
33246
+ replacementRest["message"] = {
33247
+ ...event.data.message,
33248
+ content: [{ ...replacementResult, content: null }]
33249
+ };
33250
+ if (!isDeepEqualJson(originalRest, replacementRest)) {
33251
+ throw new Error("tool/result surface replacement may change only content");
33252
+ }
33253
+ }
33254
+ }
33255
+ function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) {
33256
+ if (event.seq !== expectedSeq) {
33257
+ throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`);
33258
+ }
33259
+ const surfaceOp = surfaceOpOf(event);
33260
+ if (surfaceOp === void 0) return;
33261
+ if (surfaceOp === "append") {
33262
+ assertProvenance(event, []);
33263
+ return { kind: "append", seq: event.seq };
33264
+ }
33265
+ const range = replacementRange(state, surfaceOp);
33266
+ assertProvenance(event, range.shadowedSeqs);
33267
+ assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq);
33268
+ return {
33269
+ kind: "replace",
33270
+ seq: event.seq,
33271
+ start: surfaceOp.start,
33272
+ end: surfaceOp.end,
33273
+ ...range
33274
+ };
33275
+ }
33276
+ function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) {
33277
+ const plan = planSurfaceEvent(state, event, expectedSeq, events, baseSeq);
33278
+ return applySurfacePlan(state, plan);
33279
+ }
33280
+ function applySurfacePlan(state, plan) {
33281
+ if (plan?.kind === "append") {
33282
+ state.nodes.push(plan.seq);
33283
+ } else if (plan?.kind === "replace") {
33284
+ state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq);
33285
+ state.replaceGeneration += 1;
33286
+ }
33287
+ if (plan?.kind !== "replace") return;
33288
+ return {
33289
+ seq: plan.seq,
33290
+ start: plan.start,
33291
+ end: plan.end,
33292
+ shadowedSeqs: plan.shadowedSeqs
33293
+ };
33294
+ }
33295
+ var SurfaceManager = class {
33296
+ /**
33297
+ * @param log - Contiguous complete log or loaded event window.
33298
+ * @param baseSeq - Absolute sequence of the window's first event.
33299
+ */
33300
+ constructor(log, baseSeq = 0) {
33301
+ this.log = log;
33302
+ this.baseSeq = baseSeq;
33303
+ this._lastProcessedSeq = baseSeq - 1;
33304
+ }
33305
+ log;
33306
+ baseSeq;
33307
+ /** Shared transition state; replacement history is not retained. */
33308
+ _state = createFoldState();
33309
+ /** Last processed absolute seq. */
33310
+ _lastProcessedSeq;
33311
+ /** Candidate already validated by `validateNext`, pending exact log admission. */
33312
+ _pendingPlan;
33313
+ /**
33314
+ * Validate the next candidate without mutating the committed surface.
33315
+ * @param event - candidate event that has not entered the log yet.
33316
+ */
33317
+ validateNext(event) {
33318
+ if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33319
+ const expectedSeq = this.baseSeq + this.log.length;
33320
+ this._pendingPlan = {
33321
+ event,
33322
+ expectedSeq,
33323
+ plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq)
33324
+ };
33325
+ }
33326
+ /** Monotonic count of folded positional replacements. */
33327
+ get replaceGeneration() {
33328
+ if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33329
+ return this._state.replaceGeneration;
33330
+ }
33331
+ /** Surface event sequences in model-visible order. */
33332
+ get nodes() {
33333
+ if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
33334
+ return this._state.nodes;
33335
+ }
33336
+ /** Fold events appended since the previous access. */
33337
+ _processDelta() {
33338
+ const tailSeq = this.baseSeq + this.log.length - 1;
33339
+ for (let seq = this._lastProcessedSeq + 1; seq <= tailSeq; seq++) {
33340
+ const index2 = seq - this.baseSeq;
33341
+ const event = this.log[index2];
33342
+ const pending = this._pendingPlan;
33343
+ if (pending?.event === event && pending.expectedSeq === seq) {
33344
+ applySurfacePlan(this._state, pending.plan);
33345
+ } else {
33346
+ applySurfaceEvent(this._state, event, seq, this.log, this.baseSeq);
33347
+ }
33348
+ if (pending !== void 0 && pending.expectedSeq <= seq) this._pendingPlan = void 0;
33349
+ this._lastProcessedSeq = seq;
33350
+ }
33351
+ }
33352
+ };
33353
+
33354
+ // ../deepseek-harness/packages/core/session/src/request-header.ts
33355
+ function canonicalHeader(header) {
33356
+ const adapterDefaults = header.adapterDefaults;
33357
+ return {
33358
+ config: header.config,
33359
+ ...adapterDefaults?.reasoningEffort === true || adapterDefaults?.maxTokens === true ? { adapterDefaults } : {},
33360
+ ...header.system !== void 0 && header.system.length > 0 ? { system: header.system } : {},
33361
+ ...header.tools !== void 0 && header.tools.length > 0 ? { tools: header.tools } : {}
33362
+ };
33363
+ }
33364
+ function foldRequestHeader(events, from2) {
33365
+ let state = from2;
33366
+ for (const event of events) {
33367
+ if (event.type === "request/header") state = canonicalHeader(event.data.header);
33368
+ }
33369
+ return state;
33370
+ }
33371
+
33372
+ // ../deepseek-harness/packages/core/session/src/index.ts
33373
+ function validateSessionHeader(id, input) {
33374
+ if (input === null || typeof input !== "object" || Array.isArray(input)) {
33375
+ throw new Error("session header is not a plain JSON record");
33376
+ }
33377
+ const record2 = input;
33378
+ if (record2.version !== SESSION_FORMAT_VERSION) {
33379
+ throw new Error(`session header version must be ${SESSION_FORMAT_VERSION}, got ${String(record2.version)}`);
33380
+ }
33381
+ if (record2.id !== id) {
33382
+ throw new Error(`session header id "${String(record2.id)}" does not match session id "${id}"`);
33383
+ }
33384
+ if (typeof record2.createdAt !== "number" || !Number.isSafeInteger(record2.createdAt) || record2.createdAt < 0) {
33385
+ throw new Error("session header createdAt must be a non-negative safe integer");
33386
+ }
33387
+ if (record2.cwd !== void 0) {
33388
+ if (typeof record2.cwd !== "string") throw new Error("session header cwd must be a string");
33389
+ if (!isAbsolute(record2.cwd)) {
33390
+ throw new Error(`session header cwd must be an absolute path, got "${record2.cwd}"`);
33391
+ }
33392
+ }
33393
+ if (record2.parentSession !== void 0 && typeof record2.parentSession !== "string") {
33394
+ throw new Error("session header parentSession must be a string");
33395
+ }
33396
+ if (record2.seedLength !== void 0 && (typeof record2.seedLength !== "number" || !Number.isSafeInteger(record2.seedLength) || record2.seedLength < 0)) {
33397
+ throw new Error("session header seedLength must be a non-negative safe integer");
33398
+ }
33399
+ if (record2.origin !== void 0 && record2.origin !== "subagent") {
33400
+ throw new Error('session header origin must be "subagent"');
33401
+ }
33402
+ if (record2.delegationDepth !== void 0 && (typeof record2.delegationDepth !== "number" || !Number.isSafeInteger(record2.delegationDepth) || record2.delegationDepth < 0)) {
33403
+ throw new Error("session header delegationDepth must be a non-negative safe integer");
33404
+ }
33405
+ if (record2.agentPreset !== void 0 && typeof record2.agentPreset !== "string") {
33406
+ throw new Error("session header agentPreset must be a string");
33407
+ }
33408
+ return deepFreeze(record2);
33409
+ }
33410
+ function validateRestoredSessionHeader(id, input) {
33411
+ if (input !== null && typeof input === "object" && !Array.isArray(input)) {
33412
+ const prototype = Reflect.getPrototypeOf(input);
33413
+ if (prototype !== Object.prototype && prototype !== null) {
33414
+ throw new Error("session header is not a plain JSON record");
33415
+ }
33416
+ }
33417
+ return validateSessionHeader(id, input);
33418
+ }
33419
+ function snapshotSessionHeader(id, source) {
33420
+ const input = source === void 0 ? { version: SESSION_FORMAT_VERSION, id, createdAt: Date.now() } : source;
33421
+ const snapshot = snapshotJsonValue(input);
33422
+ if (snapshot === void 0) throw new Error("session header is not losslessly JSON-serializable");
33423
+ return validateSessionHeader(id, snapshot);
33424
+ }
33425
+ function freezeRestoredObject(value) {
33426
+ const pending = [value];
33427
+ while (pending.length > 0) {
33428
+ const current = pending.pop();
33429
+ Object.freeze(current);
33430
+ for (const key in current) {
33431
+ const child = current[key];
33432
+ if (child !== null && typeof child === "object") pending.push(child);
33433
+ }
33434
+ }
33435
+ return value;
33436
+ }
33437
+ function assertSessionEventEnvelope(value, index2) {
33438
+ const event = value;
33439
+ if (event["type"] === "request/header-delta") {
33440
+ throw new Error(`seed event at index ${index2} uses unsupported legacy request/header-delta format`);
33441
+ }
33442
+ for (const key in event) {
33443
+ switch (key) {
33444
+ case "type":
33445
+ case "seq":
33446
+ case "time":
33447
+ case "data":
33448
+ case "surfaceOp":
33449
+ case "sourceEventSeqs":
33450
+ case "ignorable":
33451
+ break;
33452
+ default:
33453
+ throw new Error(`seed event at index ${index2} has an invalid event envelope`);
33454
+ }
33455
+ }
33456
+ const type = event["type"];
33457
+ const seq = event["seq"];
33458
+ const time3 = event["time"];
33459
+ if (typeof type !== "string" || typeof seq !== "number" || !Number.isSafeInteger(seq) || seq < 0 || typeof time3 !== "number" || !Number.isSafeInteger(time3) || event["data"] === void 0 || event["ignorable"] !== void 0 && event["ignorable"] !== true) {
33460
+ throw new Error(`seed event at index ${index2} has an invalid event envelope`);
33461
+ }
33462
+ switch (type) {
33463
+ case "request/header":
33464
+ case "user/message":
33465
+ case "assistant/message":
33466
+ case "tool/result":
33467
+ assertCurrentLlmShape(event, index2);
33468
+ break;
33469
+ }
33470
+ }
33471
+ function assertCurrentLlmShape(event, index2) {
33472
+ const data = event["data"];
33473
+ const record2 = typeof data === "object" && data !== null ? data : void 0;
33474
+ if (event["type"] === "request/header") {
33475
+ const header = record2?.["header"];
33476
+ const headerRecord = typeof header === "object" && header !== null && !Array.isArray(header) ? header : void 0;
33477
+ const config2 = headerRecord?.["config"];
33478
+ if (!hasProviderModel(config2)) throw new Error(`seed request/header at index ${index2} lacks provider/model`);
33479
+ const configRecord = config2;
33480
+ const reasoningEffort = configRecord["reasoningEffort"];
33481
+ if (reasoningEffort !== void 0 && (typeof reasoningEffort !== "string" || reasoningEffort.length === 0)) {
33482
+ throw new Error(`seed request/header at index ${index2} has an invalid reasoningEffort`);
33483
+ }
33484
+ assertAdapterDefaults(headerRecord?.["adapterDefaults"], configRecord, index2);
33485
+ }
33486
+ const type = event["type"];
33487
+ if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return;
33488
+ assertMessageEventShape(event, `seed ${type} at index ${index2}`);
33489
+ }
33490
+ var allowedAdapterKeys = /* @__PURE__ */ new Set(["reasoningEffort", "maxTokens"]);
33491
+ function assertAdapterDefaults(value, config2, index2) {
33492
+ if (value === void 0) return;
33493
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
33494
+ throw new Error(`seed request/header at index ${index2} has invalid adapterDefaults`);
33495
+ }
33496
+ const defaults = value;
33497
+ if (Object.keys(defaults).some((key) => !allowedAdapterKeys.has(key)) || Object.values(defaults).some((marker) => marker !== true) || defaults["reasoningEffort"] === true && config2["reasoningEffort"] === void 0 || defaults["maxTokens"] === true && config2["maxTokens"] === void 0) {
33498
+ throw new Error(`seed request/header at index ${index2} has invalid adapterDefaults`);
33499
+ }
33500
+ }
33501
+ function assertMessageEventShape(event, subject) {
33502
+ const type = event["type"];
33503
+ if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return;
33504
+ const data = event["data"];
33505
+ const record2 = typeof data === "object" && data !== null ? data : void 0;
33506
+ const message = type === "user/message" ? record2 : record2?.["message"];
33507
+ if (typeof message !== "object" || message === null || typeof message["id"] !== "string" || message["id"] === "") {
33508
+ throw new Error(`${subject} lacks an identified message`);
33509
+ }
33510
+ const messageRecord = message;
33511
+ const expectedRole = type === "assistant/message" ? "assistant" : "user";
33512
+ if (messageRecord["role"] !== expectedRole) {
33513
+ throw new Error(`${subject} message must have role "${expectedRole}"`);
33514
+ }
33515
+ const source = messageRecord["source"];
33516
+ if (typeof source !== "object" || source === null || typeof source["kind"] !== "string" || source["kind"] === "") {
33517
+ throw new Error(`${subject} message has invalid source`);
33518
+ }
33519
+ if (!Array.isArray(messageRecord["content"])) {
33520
+ throw new Error(`${subject} message has invalid content`);
33521
+ }
33522
+ const sourceRecord = source;
33523
+ if (type === "assistant/message") {
33524
+ if (sourceRecord["kind"] !== "model" || !hasProviderModel(sourceRecord)) {
33525
+ throw new Error(`${subject} message must have model source`);
33526
+ }
33527
+ return;
33528
+ }
33529
+ if (type !== "tool/result") return;
33530
+ if (sourceRecord["kind"] !== "tool" || typeof sourceRecord["callId"] !== "string" || sourceRecord["callId"] === "") {
33531
+ throw new Error(`${subject} message must have tool source`);
33532
+ }
33533
+ const content3 = messageRecord["content"];
33534
+ const block = content3[0];
33535
+ if (content3.length !== 1 || typeof block !== "object" || block === null || block["type"] !== "tool-result" || !Array.isArray(block["content"])) {
33536
+ throw new Error(`${subject} message must contain one tool-result block`);
33537
+ }
33538
+ if (block["toolCallId"] !== sourceRecord["callId"]) {
33539
+ throw new Error(`${subject} message has mismatched tool call ids`);
33540
+ }
33541
+ }
33542
+ function hasProviderModel(value) {
33543
+ if (typeof value !== "object" || value === null) return false;
33544
+ const pair = value;
33545
+ return typeof pair["provider"] === "string" && pair["provider"].length > 0 && typeof pair["model"] === "string" && pair["model"].length > 0;
33546
+ }
33547
+ function assertSupportedRequestHeader(type, data, location) {
33548
+ if (type === "request/header-delta") {
33549
+ throw new Error(`${location} uses unsupported legacy request/header-delta format`);
33550
+ }
33551
+ if (type === "request/header" && data !== null && typeof data === "object" && !Array.isArray(data) && data["reason"] === "fallback") {
33552
+ throw new Error(`${location} uses unsupported legacy request/header reason "fallback"`);
33553
+ }
33554
+ }
33555
+ function collectSessionCallbacks(ctx, args) {
33556
+ return [...ctx.events.dispatch("emit", args)];
33557
+ }
33558
+ function invokeContainedSessionObservers(ctx, name2, id, args, callbacks) {
33559
+ for (const callback of callbacks) {
33560
+ try {
33561
+ const returned = callback(...args);
33562
+ void Promise.resolve(returned).catch((error51) => {
33563
+ ctx.logger.warn(`session "${id}": ${name2} listener rejected: ${String(error51)}`);
33564
+ });
33565
+ } catch (error51) {
33566
+ ctx.logger.warn(`session "${id}": ${name2} listener threw: ${String(error51)}`);
33567
+ }
33568
+ }
33569
+ }
33570
+ var attachments = /* @__PURE__ */ new WeakMap();
33571
+ var Session = class _Session {
33572
+ log = [];
33573
+ /** Single incremental owner of surface acceptance and projection state. */
33574
+ surfaceManager = new SurfaceManager(this.log);
33575
+ /** The ordered surface over this session's event log. */
33576
+ get surface() {
33577
+ return this.surfaceManager;
33578
+ }
33579
+ /**
33580
+ * Detached, deep-frozen creation metadata (format version, cwd, lineage,
33581
+ * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a
33582
+ * `Session` is created without a store-owned header, a minimal header is
33583
+ * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so
33584
+ * `session.header` is always present. Kept out of the event log — it is a
33585
+ * storage concern, not replayable conversation state.
33586
+ */
33587
+ header;
33588
+ /** The session identity, derived from its durable header's single copy. */
33589
+ get id() {
33590
+ return this.header.id;
33591
+ }
33592
+ /**
33593
+ * The first seq appended IN THIS PROCESS: the length of the constructor
33594
+ * seed (0 without one). Events with smaller seq values entered through
33595
+ * construction — replay, fork, or resume — and were never published on the
33596
+ * `session/event` firehose (constructor seeds do not emit), so consumers
33597
+ * that replay the log as a publication substitute (telemetry adoption)
33598
+ * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage
33599
+ * boundary: a resumed session's constructor seed is its full stored log,
33600
+ * while its header keeps the original fork value — this field is the
33601
+ * in-process construction fact.
33602
+ *
33603
+ * Not persisted itself: a seeded session projects it into the log as the
33604
+ * `session/end-seed` event, which is what a consumer reading STORED history
33605
+ * reads. Locate the LAST such event, not necessarily one at this seq — a
33606
+ * seed already ending in one is not re-marked, so reopening an untouched
33607
+ * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer
33608
+ * this field in-process: it is exact before the marker reaches storage.
33609
+ *
33610
+ * When this lifecycle appends the marker, it occupies this seq before the
33611
+ * store attaches and therefore does not publish either. Otherwise this seq
33612
+ * holds an ordinary published write.
33613
+ */
33614
+ firstLiveSeq;
33615
+ /**
33616
+ * Create a detached session by validating and snapshotting borrowed seed
33617
+ * events and storage metadata.
33618
+ * @param id - session identity.
33619
+ * @param seed - optional borrowed replay or fork events.
33620
+ * @param header - optional borrowed storage metadata.
33621
+ * @returns a detached session.
33622
+ */
33623
+ static create(id, seed, header) {
33624
+ return new _Session(id, seed, header);
33625
+ }
33626
+ /**
33627
+ * Restore a detached session by taking ownership of fresh persistence values.
33628
+ * The storage format, event envelopes, sequence continuity, surface transitions,
33629
+ * and header fields are validated before the restored objects are frozen.
33630
+ * @param id - restored session identity.
33631
+ * @param seed - fresh detached events whose ownership is transferred.
33632
+ * @param header - fresh detached metadata whose ownership is transferred.
33633
+ * @returns a restored detached session.
33634
+ */
33635
+ static fromRestore(id, seed, header) {
33636
+ return new _Session(id, seed, header, "restore");
33637
+ }
33638
+ constructor(id, seed, header, mode = "snapshot") {
33639
+ const restoredHeader = mode === "restore" ? validateRestoredSessionHeader(id, header) : void 0;
33640
+ if (seed !== void 0) {
33641
+ for (const [index2, source] of seed.entries()) {
33642
+ const snapshot = mode === "restore" ? source : snapshotJsonValue(source);
33643
+ if (snapshot === void 0) {
33644
+ throw new Error(`seed event at index ${index2} is not losslessly JSON-serializable`);
33645
+ }
33646
+ assertSessionEventEnvelope(snapshot, index2);
33647
+ assertSupportedRequestHeader(snapshot.type, snapshot.data, `seed event at index ${index2}`);
33648
+ if (snapshot.seq !== index2) {
33649
+ throw new Error(`seed event at index ${index2} has seq ${snapshot.seq} (expected ${index2}); seed must be contiguous from 0`);
33650
+ }
33651
+ try {
33652
+ this.surfaceManager.validateNext(snapshot);
33653
+ } catch (error51) {
33654
+ throw new Error(`invalid seed event at index ${index2}: ${error51 instanceof Error ? error51.message : "invalid surface metadata"}`);
33655
+ }
33656
+ this.log.push(mode === "restore" ? freezeRestoredObject(snapshot) : deepFreeze(snapshot));
33657
+ }
33658
+ }
33659
+ this.firstLiveSeq = this.log.length;
33660
+ this.header = restoredHeader ?? snapshotSessionHeader(id, header);
33661
+ if (seed !== void 0 && this.log.at(-1)?.type !== "session/end-seed") {
33662
+ this.append("session/end-seed", {});
33663
+ }
33664
+ }
33665
+ /** Cached immutable public snapshot of the private append-only log. */
33666
+ eventsSnapshot;
33667
+ /**
33668
+ * An immutable snapshot of the append-only event log. The snapshot is reused
33669
+ * until the next append; a previously returned array does not grow later.
33670
+ * Events and their nested data are deep-frozen at acceptance, so neither a
33671
+ * cast nor ordinary JavaScript can rewrite durable history.
33672
+ */
33673
+ get events() {
33674
+ this.eventsSnapshot ??= Object.freeze([...this.log]);
33675
+ return this.eventsSnapshot;
33676
+ }
33677
+ /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */
33678
+ get seq() {
33679
+ return this.log.length;
33680
+ }
33681
+ /**
33682
+ * Append one typed event to the log and synchronously notify observers via
33683
+ * the store-owned, module-private publication hooks. The hot path never blocks
33684
+ * on I/O — persistence plugins buffer asynchronously. Once the event enters
33685
+ * the log, the append is committed: observer failures are logged and
33686
+ * contained per listener, so they do not change the return value or prevent
33687
+ * later listeners from observing the same accepted event.
33688
+ *
33689
+ * @param type - The event type (key of {@link SessionEventMap}).
33690
+ * @param data - The event payload; must be JSON-serializable.
33691
+ * @param opts - Surface metadata: `surfaceOp` controls how the event enters
33692
+ * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier
33693
+ * events this one derives from. REQUIRED for
33694
+ * {@link SurfaceEventType} events (every message-producing event must
33695
+ * declare how it joins the surface, the sole source of derived model
33696
+ * history) and
33697
+ * rejected by the compiler for non-surface types like `turn/start` or
33698
+ * `assistant/chunk`.
33699
+ * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of
33700
+ * `data` that entered the log, so reading `event.data` back sees the logged
33701
+ * value, never the caller's still-mutable input.
33702
+ * @throws if `data` or surface metadata is not losslessly JSON-serializable
33703
+ * (BigInt, function, symbol, undefined, negative zero, non-finite number,
33704
+ * circular reference, sparse array, or an exotic object such as
33705
+ * Map/Set/Date/class instance), or when the candidate violates the
33706
+ * canonical surface contract (marker shape and eligibility, unique
33707
+ * earlier source-event references, positional replacement validity, and complete
33708
+ * shadowed-node coverage). One iterative pass reads, validates, and
33709
+ * copies each nested value once, so a stateful getter cannot supply one value
33710
+ * to validation and another to storage. The event log is the durable source
33711
+ * of truth, so a bad event fails at the append site rather than later during
33712
+ * a backend flush. A synchronous internal dispatch validation failure or an
33713
+ * append reentered while this acceptance/publication boundary is open also
33714
+ * rejects before the log changes.
33715
+ */
33716
+ append(type, data, ...opts) {
33717
+ const surfaceOpts = opts[0];
33718
+ const surfaceMetadata = {
33719
+ ...surfaceOpts?.sourceEventSeqs === void 0 ? {} : { sourceEventSeqs: surfaceOpts.sourceEventSeqs },
33720
+ ...surfaceOpts?.surfaceOp === void 0 ? {} : { surfaceOp: surfaceOpts.surfaceOp }
33721
+ };
33722
+ const dataSnapshot = snapshotJsonValue(data);
33723
+ if (dataSnapshot === void 0) {
33724
+ throw new Error(`session event "${type}" carries non-JSON-serializable data`);
33725
+ }
33726
+ assertSupportedRequestHeader(type, dataSnapshot, `session event "${type}"`);
33727
+ const surfaceMetadataSnapshot = snapshotJsonValue(surfaceMetadata);
33728
+ if (surfaceMetadataSnapshot === void 0) {
33729
+ throw new Error(`session event "${type}" carries non-JSON-serializable surface metadata`);
33730
+ }
33731
+ const entry = attachments.get(this);
33732
+ if (entry?.appending) {
33733
+ throw new Error("session append cannot reenter while another append is being published");
33734
+ }
33735
+ const event = deepFreeze({
33736
+ type,
33737
+ seq: this.log.length,
33738
+ time: Date.now(),
33739
+ data: dataSnapshot,
33740
+ ...surfaceMetadataSnapshot
33741
+ });
33742
+ this.surfaceManager.validateNext(event);
33743
+ if (entry !== void 0) entry.appending = true;
33744
+ try {
33745
+ let callbacks;
33746
+ const callbackArgs = [this, event];
33747
+ if (entry !== void 0) {
33748
+ callbacks = collectSessionCallbacks(entry.emitCtx, [entry.carrier, "session/event", ...callbackArgs]);
33749
+ }
33750
+ this.log.push(event);
33751
+ this.eventsSnapshot = void 0;
33752
+ if (callbacks !== void 0 && entry !== void 0) {
33753
+ invokeContainedSessionObservers(entry.emitCtx, "session/event", entry.id, callbackArgs, callbacks);
33754
+ }
33755
+ return event;
33756
+ } finally {
33757
+ if (entry !== void 0) {
33758
+ entry.appending = false;
33759
+ if (entry.detachRequested && !entry.announcing) entry.detach();
33760
+ }
33761
+ }
33762
+ }
33763
+ /** Cached fold of the request-header events — see {@link requestHeader}. */
33764
+ headerFold;
33765
+ /** Log position (events consumed) the header fold has reached. */
33766
+ headerFoldSeq = 0;
33767
+ /**
33768
+ * The {@link EpochHeader} in force after the log's last header event — the
33769
+ * header the NEXT request will be compared against — or undefined before
33770
+ * the first `request/header` snapshot. The live, incrementally-maintained
33771
+ * form of `foldRequestHeader(session.events)`: each header event is folded
33772
+ * once, when first seen, so a per-step read costs O(new events).
33773
+ * @returns the folded header, or undefined when no header event exists yet.
33774
+ */
33775
+ requestHeader() {
33776
+ if (this.headerFoldSeq < this.log.length) {
33777
+ this.headerFold = deepFreeze(foldRequestHeader(this.log.slice(this.headerFoldSeq), this.headerFold));
33778
+ this.headerFoldSeq = this.log.length;
33779
+ }
33780
+ return this.headerFold;
33781
+ }
33782
+ /** Cached fold of `request/context` events. */
33783
+ contextFold;
33784
+ contextFoldSeq = 0;
33785
+ /**
33786
+ * Return the latest resolved route metadata, or `undefined` before the first
33787
+ * `request/context` event. Each event is folded once.
33788
+ * @returns the latest immutable route metadata.
33789
+ */
33790
+ requestContext() {
33791
+ if (this.contextFoldSeq < this.log.length) {
33792
+ for (const event of this.log.slice(this.contextFoldSeq)) {
33793
+ if (event.type === "request/context") this.contextFold = deepFreeze({ ...event.data });
33794
+ }
33795
+ this.contextFoldSeq = this.log.length;
33796
+ }
33797
+ return this.contextFold;
33798
+ }
33799
+ /** The derived-message cache: frozen projections, extended per unseen node. */
33800
+ derived = [];
33801
+ /** Surface position (nodes projected) the cache has reached. */
33802
+ derivedNodes = 0;
33803
+ /** {@link SurfaceManager.replaceGeneration} the cache was built under. */
33804
+ derivedGeneration = 0;
33805
+ /**
33806
+ * Derive the LLM message history by walking the ordered sequences of
33807
+ * message-producing events maintained by `surfaceOp` markers. The
33808
+ * surface is the single source of derived history: every message-producing
33809
+ * append records its `surfaceOp`, so a raw event with no marker (a chunk, a
33810
+ * turn boundary) is correctly absent, and a compaction `replace` deletes the
33811
+ * shadowed nodes from the derivation. The projection rules are
33812
+ * {@link deriveEventMessage}, folded per node.
33813
+ *
33814
+ * CACHED: each surface node is projected exactly once, when first seen — a
33815
+ * call costs O(new nodes), and a surface rewrite (a `replace`;
33816
+ * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is
33817
+ * a fresh snapshot per call (later appends never grow an array a caller
33818
+ * already holds); the `Message` objects in it are SHARED and **deep-frozen**.
33819
+ * Their content reuses the already frozen durable event data, so the cache
33820
+ * needs no second deep clone and consumers still cannot mutate the log.
33821
+ * @returns a fresh array of the shared, frozen derived history.
33822
+ */
33823
+ deriveMessages() {
33824
+ const surface = this.surface;
33825
+ const nodes = surface.nodes;
33826
+ const generation = surface.replaceGeneration;
33827
+ if (generation !== this.derivedGeneration) {
33828
+ this.derived = [];
33829
+ this.derivedNodes = 0;
33830
+ this.derivedGeneration = generation;
33831
+ }
33832
+ for (const seq of nodes.slice(this.derivedNodes)) {
33833
+ const msg = this.deriveEventMessage(this.log[seq]);
33834
+ if (msg) this.derived.push(msg);
33835
+ }
33836
+ this.derivedNodes = nodes.length;
33837
+ return [...this.derived];
33838
+ }
33839
+ /**
33840
+ * Instance face of the pure per-node `deriveEventMessage` export from
33841
+ * `surface.ts`.
33842
+ * @param event - the event to project.
33843
+ * @returns the derived message, or null when the event produces none.
33844
+ */
33845
+ deriveEventMessage(event) {
33846
+ return deriveEventMessage(event);
33847
+ }
33848
+ };
32977
33849
 
32978
33850
  // ../deepseek-harness/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
32979
33851
  var external_exports = {};
@@ -58245,7 +59117,7 @@ function producedPathsForTurn(cards) {
58245
59117
 
58246
59118
  // ../deepseek-harness/packages/tui/tui-render/src/stream-view.tsx
58247
59119
  import { pathToFileURL as pathToFileURL2 } from "node:url";
58248
- import { isAbsolute as isAbsolute2 } from "node:path";
59120
+ import { isAbsolute as isAbsolute3 } from "node:path";
58249
59121
 
58250
59122
  // ../deepseek-harness/packages/tui/tui-render/src/markdown.tsx
58251
59123
  var import_react34 = __toESM(require_react(), 1);
@@ -69430,7 +70302,7 @@ function toolCardOriginalText(card, options) {
69430
70302
  }
69431
70303
 
69432
70304
  // ../deepseek-harness/packages/tui/tui-render/src/tool-cards.ts
69433
- import { isAbsolute } from "node:path";
70305
+ import { isAbsolute as isAbsolute2 } from "node:path";
69434
70306
  import { pathToFileURL } from "node:url";
69435
70307
  function toolCardDisplayStatus(card) {
69436
70308
  const terminal = card.resultView?.card === "terminal" ? card.resultView : void 0;
@@ -69593,7 +70465,7 @@ function fileUrlFromToolArguments(argumentsJson) {
69593
70465
  const record2 = parsed;
69594
70466
  for (const key of FILE_PATH_KEYS) {
69595
70467
  const value = record2[key];
69596
- if (typeof value !== "string" || !isAbsolute(value)) continue;
70468
+ if (typeof value !== "string" || !isAbsolute2(value)) continue;
69597
70469
  if (/[\u0000-\u001f\u007f]/.test(value)) continue;
69598
70470
  return pathToFileURL(value).href;
69599
70471
  }
@@ -74614,7 +75486,7 @@ function StreamView({
74614
75486
  prefix = " \xB7 ";
74615
75487
  }
74616
75488
  const segment2 = styled(escapeContent(`${prefix}${path2}`), "fgDim");
74617
- const href = isAbsolute2(path2) ? pathToFileURL2(path2).href : void 0;
75489
+ const href = isAbsolute3(path2) ? pathToFileURL2(path2).href : void 0;
74618
75490
  const run2 = hyperlinksEnabled() && href !== void 0 && isOsc8Href(href) ? wrapOsc8(segment2, href) : segment2;
74619
75491
  rowRuns.push(run2);
74620
75492
  rowWidth += displayWidth(`${prefix}${path2}`);
@@ -78877,6 +79749,7 @@ function createProjector() {
78877
79749
  return {
78878
79750
  push: push3,
78879
79751
  seed(events) {
79752
+ if (!events || typeof events[Symbol.iterator] !== "function") return;
78880
79753
  for (const event of events) push3(event);
78881
79754
  },
78882
79755
  snapshot() {
@@ -79141,7 +80014,9 @@ async function exportSessionMarkdown(session, dir) {
79141
80014
  throw new Error("session export target must be a direct child of the export directory");
79142
80015
  }
79143
80016
  await mkdir(resolvedDir, { recursive: true });
79144
- await writeFile(target, renderSessionMarkdown(session.events), "utf8");
80017
+ const legacy = session;
80018
+ const events = typeof legacy.snapshotEvents === "function" ? legacy.snapshotEvents() : session.events;
80019
+ await writeFile(target, renderSessionMarkdown(events), "utf8");
79145
80020
  return target;
79146
80021
  }
79147
80022
 
@@ -79245,6 +80120,51 @@ function settingsRowsFromDescribe(descriptors, read) {
79245
80120
  }
79246
80121
 
79247
80122
  // ../deepseek-harness/packages/tui/tui/src/index.ts
80123
+ try {
80124
+ if (typeof Session === "function" && !("events" in Session.prototype)) {
80125
+ Object.defineProperty(Session.prototype, "events", {
80126
+ get() {
80127
+ return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
80128
+ },
80129
+ configurable: true,
80130
+ enumerable: false
80131
+ });
80132
+ }
80133
+ } catch {
80134
+ }
80135
+ function ensureSessionEventsCompat(session) {
80136
+ if (!session || typeof session !== "object") return;
80137
+ try {
80138
+ const proto2 = Object.getPrototypeOf(session);
80139
+ if (proto2 && typeof proto2 === "object" && !("events" in proto2)) {
80140
+ Object.defineProperty(proto2, "events", {
80141
+ get() {
80142
+ return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
80143
+ },
80144
+ configurable: true,
80145
+ enumerable: false
80146
+ });
80147
+ } else if (!("events" in session)) {
80148
+ Object.defineProperty(session, "events", {
80149
+ get() {
80150
+ return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
80151
+ },
80152
+ configurable: true,
80153
+ enumerable: false
80154
+ });
80155
+ }
80156
+ } catch {
80157
+ }
80158
+ }
80159
+ function getSessionEvents(session) {
80160
+ if (!session || typeof session !== "object") return [];
80161
+ const s = session;
80162
+ if (s.events !== void 0) return s.events;
80163
+ if (typeof s.snapshotEvents === "function") {
80164
+ return s.snapshotEvents();
80165
+ }
80166
+ return [];
80167
+ }
79248
80168
  var FEEDBACK_MS = 2e3;
79249
80169
  var FEEDBACK_COPY = {
79250
80170
  // Safe copy: tells the user the action failed and they can retry. The
@@ -79992,7 +80912,7 @@ var RuntimeController = class _RuntimeController {
79992
80912
  */
79993
80913
  getTitle() {
79994
80914
  if (this.session === void 0) return "";
79995
- return topBarTitle(this.session.events);
80915
+ return topBarTitle(getSessionEvents(this.session));
79996
80916
  }
79997
80917
  /**
79998
80918
  * Return the current session-directory state.
@@ -81754,7 +82674,7 @@ var RuntimeController = class _RuntimeController {
81754
82674
  * in those cases and is not appropriate here.
81755
82675
  */
81756
82676
  notifySessionTitle() {
81757
- return this.session === void 0 ? void 0 : notifySessionTitle(this.session.events);
82677
+ return this.session === void 0 ? void 0 : notifySessionTitle(getSessionEvents(this.session));
81758
82678
  }
81759
82679
  /** Record local user input for the notification quiet window. */
81760
82680
  noteUserActivity() {
@@ -82180,8 +83100,9 @@ var RuntimeController = class _RuntimeController {
82180
83100
  });
82181
83101
  const allocated = await this.allocateCandidate(request);
82182
83102
  candidate = allocated.handle;
83103
+ ensureSessionEventsCompat(candidate.agent.session);
82183
83104
  const projector = createProjector();
82184
- projector.seed(candidate.agent.session.events);
83105
+ projector.seed(getSessionEvents(candidate.agent.session));
82185
83106
  this.setTransition({ phase: "binding", intent: request.intent });
82186
83107
  this.commitCandidate({ ...allocated, projector });
82187
83108
  } catch (primaryError) {
@@ -83159,10 +84080,11 @@ var RuntimeController = class _RuntimeController {
83159
84080
  }
83160
84081
  /** Fold the bound live session into a directory row without waiting for persistence. */
83161
84082
  rowForLiveSession(session) {
84083
+ const events = getSessionEvents(session);
83162
84084
  return {
83163
84085
  id: session.id,
83164
- title: listTitleOf(session.events),
83165
- updatedAt: session.events.at(-1)?.time ?? session.header.createdAt
84086
+ title: listTitleOf(events),
84087
+ updatedAt: events.at(-1)?.time ?? session.header.createdAt
83166
84088
  };
83167
84089
  }
83168
84090
  /** Fold one listed session into a directory row; corrupt logs degrade to the id. */
@@ -83646,6 +84568,7 @@ var RuntimeController = class _RuntimeController {
83646
84568
  }
83647
84569
  };
83648
84570
  function topBarTitle(events) {
84571
+ if (!Array.isArray(events)) return "";
83649
84572
  const folded = foldSessionTitle(events);
83650
84573
  if (folded === void 0) return "";
83651
84574
  if (folded.source.kind === "fallback" && events.some(isHumanUserMessage)) {
@@ -83654,9 +84577,11 @@ function topBarTitle(events) {
83654
84577
  return folded.title;
83655
84578
  }
83656
84579
  function notifySessionTitle(events) {
84580
+ if (!Array.isArray(events)) return void 0;
83657
84581
  return foldTitle(events);
83658
84582
  }
83659
84583
  function foldTitle(events) {
84584
+ if (!Array.isArray(events)) return void 0;
83660
84585
  const folded = foldSessionTitle(events);
83661
84586
  if (folded !== void 0) return folded.title;
83662
84587
  const firstUser = events.find(isHumanUserMessage);
@@ -83672,6 +84597,7 @@ function foldTitle(events) {
83672
84597
  return void 0;
83673
84598
  }
83674
84599
  function listTitleOf(events) {
84600
+ if (!Array.isArray(events)) return "\u672A\u547D\u540D\u4F1A\u8BDD";
83675
84601
  return foldTitle(events) ?? "\u672A\u547D\u540D\u4F1A\u8BDD";
83676
84602
  }
83677
84603
  function firstLine2(text4) {
@@ -83977,6 +84903,18 @@ async function run(ctx, config2, io) {
83977
84903
  }
83978
84904
  }
83979
84905
  function apply(ctx, config2) {
84906
+ try {
84907
+ if (typeof Session === "function" && !("events" in Session.prototype)) {
84908
+ Object.defineProperty(Session.prototype, "events", {
84909
+ get() {
84910
+ return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
84911
+ },
84912
+ configurable: true,
84913
+ enumerable: false
84914
+ });
84915
+ }
84916
+ } catch {
84917
+ }
83980
84918
  const exit3 = ctx.get("appExit");
83981
84919
  if (exit3 === void 0) {
83982
84920
  throw new Error(
@@ -84023,6 +84961,8 @@ export {
84023
84961
  RuntimeController,
84024
84962
  SEARCH_DEBOUNCE_MS,
84025
84963
  apply,
84964
+ ensureSessionEventsCompat,
84965
+ getSessionEvents,
84026
84966
  inject,
84027
84967
  internals,
84028
84968
  name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crazyhappyone/dsh-tui",
3
- "version": "0.1.0-alpha.5",
3
+ "version": "0.1.0-alpha.7",
4
4
  "description": "Source-runtime launcher for the DeepSeek Harness terminal interface",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -35,12 +35,40 @@
35
35
  openAt: first-search
36
36
 
37
37
  - insert:
38
+ # Code Mode is a core execution capability, not a Web component.
39
+ - id: code-runtime
40
+ name: "@deepseek-ai/dsh-code-runtime-worker-thread"
41
+
42
+ # Per-round token/duration stats for the terminal status line.
43
+ - id: session-stats
44
+ name: "@deepseek-ai/dsh-session-stats"
45
+
46
+ # Base owns the shared storage/domain/projection-cache stack. This layer
47
+ # contributes only the TUI-facing feedback consumer over that stack.
48
+ - id: message-feedback
49
+ name: "@deepseek-ai/dsh-message-feedback"
50
+ config:
51
+ maxNoteBytes: 8192
52
+
53
+ - id: tool-ask-user
54
+ name: "@deepseek-ai/dsh-tool-ask-user"
55
+
38
56
  - id: tui-startup
39
- name: "./dist/startup.js"
57
+ name: "@deepseek-ai/dsh-tui/startup"
58
+
59
+ # Zero-config official OpenAI/Anthropic routes. They register
60
+ # openai-official / anthropic-official so they do not collide with the
61
+ # dormant llm-pi-ai catalog keys openai / anthropic that the Web Models
62
+ # page already owns.
63
+ - id: llm-openai
64
+ name: "@deepseek-ai/dsh-llm-openai"
65
+
66
+ - id: llm-anthropic
67
+ name: "@deepseek-ai/dsh-llm-anthropic"
40
68
 
41
69
  # Reads its task from the ordinary tuiStartup provider.
42
70
  - id: tui-runtime
43
- name: "./dist/index.js"
71
+ name: "@deepseek-ai/dsh-tui"
44
72
  inject: [tuiStartup]
45
73
  config:
46
74
  task: !!js ctx.tuiStartup.task