deepclause-sdk 0.0.63 → 0.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -719,6 +719,37 @@ agent_main(Topic) :-
719
719
  answer(Final).
720
720
  ```
721
721
 
722
+ ### Shared Predicates Across DML Files
723
+
724
+ When a skill grows beyond one file, move reusable predicates into helper files and load them at the top of the main DML. This is useful for shared search helpers, validation predicates, common formatting logic, or domain-specific utilities that multiple skills reuse.
725
+
726
+ ```prolog
727
+ % .deepclause/tools/repo-review/helpers/search_helpers.dml
728
+ normalize_query(Query, Normalized) :-
729
+ format(string(Normalized), "site:github.com ~w", [Query]).
730
+
731
+ search_and_summarize(Query, Summary) :-
732
+ normalize_query(Query, Normalized),
733
+ exec(web_search(query: Normalized), Results),
734
+ task("Summarize these results: {Results}", Summary).
735
+ ```
736
+
737
+ ```prolog
738
+ % .deepclause/tools/repo-review.dml
739
+ :- use_module(library(lists)).
740
+ :- use_module(library(clpfd)).
741
+ :- consult('.deepclause/tools/repo-review/helpers/search_helpers.dml').
742
+
743
+ agent_main(Topic) :-
744
+ search_and_summarize(Topic, Summary),
745
+ answer(Summary).
746
+ ```
747
+
748
+ - Use `:- use_module(library(...)).` for standard SWI-Prolog libraries such as `lists`, `clpfd`, `clpq`, and `clpr`.
749
+ - Use `:- consult('workspace-relative/path.dml').` for local shared DML helpers inside the workspace.
750
+ - Local `:- use_module('.deepclause/tools/repo-review/helpers/search_helpers.dml').` also works as a convenience alias, but today it has consult-style loading semantics rather than full SWI module export filtering.
751
+ - When a helper belongs to one skill, keep it in a dedicated subfolder such as `.deepclause/tools/<skill-slug>/helpers/` so the skill and its shared predicates stay together.
752
+
722
753
  ## Using as a Library
723
754
 
724
755
  Embed DeepClause in your own applications:
package/dist/cli/tui.d.ts CHANGED
@@ -54,6 +54,7 @@ export declare class ActivityBuffer {
54
54
  finish(): void;
55
55
  clear(): void;
56
56
  snapshot(): string[];
57
+ snapshotTail(limit: number): string[];
57
58
  private handleStream;
58
59
  private flushStream;
59
60
  private trim;
@@ -73,6 +74,14 @@ export declare function parseCommandArgs(rawArgs: string): string[];
73
74
  export declare function parseCommandBarInput(line: string): ParsedTuiInput;
74
75
  export declare function parseSlashInput(line: string): ParsedTuiInput;
75
76
  export declare function canSubmitParsedInputWhileBusy(parsed: ParsedTuiInput): boolean;
77
+ export declare function reconcileEphemeralMessages(persistedMessages: Array<{
78
+ role: 'user' | 'assistant';
79
+ content: string;
80
+ }>, ephemeralMessages: DisplayMessage[]): DisplayMessage[];
81
+ export declare function sessionMessagesContainCompletedTaskPreview(persistedMessages: Array<{
82
+ role: 'user' | 'assistant';
83
+ content: string;
84
+ }>, previewEntries: DisplayMessage[]): boolean;
76
85
  export declare function computeFramePatch(previousLines: string[] | null, nextLines: string[], previousSize: {
77
86
  columns: number;
78
87
  rows: number;
@@ -100,6 +109,10 @@ export declare function nextWrappedIndex(currentIndex: number, delta: -1 | 1, le
100
109
  export declare function selectMenuItemByTypeahead(items: ReadonlyArray<{
101
110
  label: string;
102
111
  }>, query: string, currentIndex?: number): number;
112
+ export declare function collectTailWrappedLines(body: string[], innerWidth: number, limit: number): {
113
+ lines: string[];
114
+ truncated: boolean;
115
+ };
103
116
  export declare function filterPickerItems<T extends {
104
117
  label: string;
105
118
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../../src/cli/tui.ts"],"names":[],"mappings":"AAOA,OAAO,EAAyD,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAGpG,OAAO,EAML,KAAK,iBAAiB,EAGvB,MAAM,gCAAgC,CAAC;AAaxC,QAAA,MAAM,sBAAsB,yGAA0G,CAAC;AAyDvI,KAAK,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAsInE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;CAC9B;AAmBD,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAC/E;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,oBAAoB;IAK7B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAL5B,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,UAAU,CAAS;gBAGR,KAAK,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAA2C,EACpE,SAAS,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAkC;IAGlF,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAmDzC,MAAM,IAAI,IAAI;IAId,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,cAAc;CAOvB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuC;IACnE,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,gBAAgB,CAAM;IAE9B,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAmDzC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAS5B,MAAM,IAAI,IAAI;IAKd,KAAK,IAAI,IAAI;IAOb,QAAQ,IAAI,MAAM,EAAE;IAapB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,cAAc;IA4BtB,OAAO,CAAC,oBAAoB;CAY7B;AAm0FD,wBAAsB,QAAQ,CAC5B,aAAa,SAAgB,EAC7B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAClC,OAAO,CAAC,IAAI,CAAC,CAQf;AAyLD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,aAAa,SAAgB,EAC7B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAClC,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAwID,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,cAAc,GAAG,IAAI,CAsB1F;AAED,wBAAgB,gCAAgC,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAOlF;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc,CAQ/F;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAmD1D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CA0CjE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAE5D;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAE7E;AAED,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,EAC9B,SAAS,EAAE,MAAM,EAAE,EACnB,YAAY,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EACtD,QAAQ,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAmB5E;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAoCpG;AA6CD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,CAkD7F;AA0DD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,SAAK,GAAG,MAAM,CAetF;AAwLD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BnE;AAUD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAqWD,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM5F;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,YAAY,SAAK,GAChB,MAAM,CAiBR;AA+DD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,EACjG,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,KAAK,EAAE,MAAM,GACZ,CAAC,EAAE,CAWL"}
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../../src/cli/tui.ts"],"names":[],"mappings":"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"}
package/dist/cli/tui.js CHANGED
@@ -212,6 +212,19 @@ export class ActivityBuffer {
212
212
  ? [...activeLines, '', ...body]
213
213
  : activeLines;
214
214
  }
215
+ snapshotTail(limit) {
216
+ const boundedLimit = Math.max(1, limit);
217
+ const body = this.activeStreamLine
218
+ ? [...this.lines.slice(-boundedLimit), this.activeStreamLine]
219
+ : this.lines.slice(-boundedLimit);
220
+ const activeLines = this.buildActiveToolLines();
221
+ if (activeLines.length === 0) {
222
+ return body;
223
+ }
224
+ return body.length > 0
225
+ ? [...activeLines, '', ...body]
226
+ : activeLines;
227
+ }
215
228
  handleStream(logEvent) {
216
229
  const streamKey = logEvent.scope === 'child' ? `child:${logEvent.childSlug ?? '?'}` : 'main';
217
230
  if (this.activeStreamKey !== streamKey) {
@@ -860,9 +873,12 @@ class FullscreenTui {
860
873
  },
861
874
  });
862
875
  activity.finish();
876
+ this.completeCurrentPreview({
877
+ finalText: result.answer,
878
+ error: result.error,
879
+ });
863
880
  await this.refreshSessions({ createIfMissing: true, selectedSessionId: result.sessionId });
864
881
  await this.refreshCommands();
865
- this.finishExecutionPreview({ persist: false });
866
882
  this.statusLine = result.error ? 'Task failed.' : 'Task finished.';
867
883
  }
868
884
  catch (error) {
@@ -2108,6 +2124,21 @@ class FullscreenTui {
2108
2124
  }
2109
2125
  this.currentPreview = null;
2110
2126
  }
2127
+ completeCurrentPreview(options) {
2128
+ if (!this.currentPreview || this.currentPreview.kind === 'shell') {
2129
+ return;
2130
+ }
2131
+ this.currentPreview.activeChildTag = undefined;
2132
+ const assistant = this.ensurePreviewAssistantMessage();
2133
+ if (typeof options.finalText === 'string' && options.finalText.trim()) {
2134
+ assistant.content = options.finalText;
2135
+ }
2136
+ if (typeof options.error === 'string' && options.error.trim()) {
2137
+ assistant.content = options.error;
2138
+ assistant.error = true;
2139
+ }
2140
+ assistant.pending = false;
2141
+ }
2111
2142
  cancelCurrentExecution(message) {
2112
2143
  if (!this.busy || !this.currentAbortController) {
2113
2144
  this.statusLine = 'No execution is currently running.';
@@ -2264,6 +2295,22 @@ class FullscreenTui {
2264
2295
  return;
2265
2296
  }
2266
2297
  this.sessionDetail = await getConductorSessionDetail(this.workspaceRoot, this.selectedSessionId);
2298
+ if (this.currentPreview
2299
+ && this.currentPreview.kind === 'task'
2300
+ && this.currentPreview.sessionId === this.selectedSessionId
2301
+ && sessionMessagesContainCompletedTaskPreview(this.sessionDetail.messages, this.currentPreview.entries)) {
2302
+ this.currentPreview = null;
2303
+ }
2304
+ const existingEphemeral = this.ephemeralMessagesBySessionId.get(this.selectedSessionId);
2305
+ if (!existingEphemeral || existingEphemeral.length === 0) {
2306
+ return;
2307
+ }
2308
+ const reconciled = reconcileEphemeralMessages(this.sessionDetail.messages, existingEphemeral);
2309
+ if (reconciled.length === 0) {
2310
+ this.ephemeralMessagesBySessionId.delete(this.selectedSessionId);
2311
+ return;
2312
+ }
2313
+ this.ephemeralMessagesBySessionId.set(this.selectedSessionId, reconciled);
2267
2314
  }
2268
2315
  activityFor(key) {
2269
2316
  const existing = this.activityBySessionId.get(key);
@@ -2430,7 +2477,7 @@ class FullscreenTui {
2430
2477
  }
2431
2478
  return lines;
2432
2479
  }
2433
- buildMessagesPaneBody() {
2480
+ buildMessageEntries() {
2434
2481
  const entries = [];
2435
2482
  if (this.sessionDetail) {
2436
2483
  for (const message of this.sessionDetail.messages) {
@@ -2442,6 +2489,10 @@ class FullscreenTui {
2442
2489
  if (this.currentPreview && this.currentPreview.sessionId === this.selectedSessionId) {
2443
2490
  entries.push(...this.currentPreview.entries);
2444
2491
  }
2492
+ return entries;
2493
+ }
2494
+ buildMessagesPaneBody(options = {}) {
2495
+ const entries = this.buildMessageEntries();
2445
2496
  if (entries.length === 0) {
2446
2497
  return [
2447
2498
  '[System] No messages yet.',
@@ -2449,8 +2500,11 @@ class FullscreenTui {
2449
2500
  ' The center pane shows user and assistant messages.',
2450
2501
  ];
2451
2502
  }
2503
+ const visibleEntries = typeof options.recentEntryLimit === 'number' && options.recentEntryLimit > 0
2504
+ ? entries.slice(-options.recentEntryLimit)
2505
+ : entries;
2452
2506
  const lines = [];
2453
- for (const entry of entries) {
2507
+ for (const entry of visibleEntries) {
2454
2508
  const header = this.formatMessageHeader(entry);
2455
2509
  lines.push(header);
2456
2510
  const bodyLines = entry.content
@@ -2466,8 +2520,10 @@ class FullscreenTui {
2466
2520
  }
2467
2521
  return lines;
2468
2522
  }
2469
- buildProcessPaneBody() {
2470
- const activity = this.currentProcessActivity().snapshot();
2523
+ buildProcessPaneBody(options = {}) {
2524
+ const activity = typeof options.tailLineLimit === 'number' && options.tailLineLimit > 0
2525
+ ? this.currentProcessActivity().snapshotTail(options.tailLineLimit)
2526
+ : this.currentProcessActivity().snapshot();
2471
2527
  if (activity.length > 0) {
2472
2528
  return activity;
2473
2529
  }
@@ -2531,7 +2587,7 @@ class FullscreenTui {
2531
2587
  return body;
2532
2588
  }
2533
2589
  buildPaneView(kind, title, width, height) {
2534
- const metrics = this.getPaneMetrics(kind, width, height);
2590
+ const metrics = this.getRenderPaneMetrics(kind, width, height);
2535
2591
  const paneTitle = this.buildPaneTitle(title, kind, metrics);
2536
2592
  return buildPane(paneTitle, metrics.lines.slice(metrics.start, metrics.start + metrics.viewportLines), width, height, kind, this.focusedPane === kind);
2537
2593
  }
@@ -2681,6 +2737,23 @@ class FullscreenTui {
2681
2737
  ? `${title}${this.focusedPane === kind ? ' [focus]' : ''} [follow]`
2682
2738
  : `${title}${this.focusedPane === kind ? ' [focus]' : ''} [-${this.paneScroll[kind]}]`;
2683
2739
  }
2740
+ getRenderPaneMetrics(kind, width = paneDimensionsForKind(kind, output.columns ?? 120, output.rows ?? 40).width, height = paneDimensionsForKind(kind, output.columns ?? 120, output.rows ?? 40).height) {
2741
+ if ((kind === 'process' || kind === 'messages') && this.paneScroll[kind] === 0) {
2742
+ const innerWidth = Math.max(1, width - 2);
2743
+ const viewportLines = Math.max(0, height - 2);
2744
+ const rawBody = kind === 'messages'
2745
+ ? this.buildMessagesPaneBody({ recentEntryLimit: Math.max(8, viewportLines * 2) })
2746
+ : this.buildProcessPaneBody({ tailLineLimit: Math.max(16, viewportLines * 4) });
2747
+ const tail = collectTailWrappedLines(rawBody, innerWidth, viewportLines);
2748
+ return {
2749
+ lines: tail.lines,
2750
+ start: 0,
2751
+ maxStart: tail.truncated ? 1 : 0,
2752
+ viewportLines,
2753
+ };
2754
+ }
2755
+ return this.getPaneMetrics(kind, width, height);
2756
+ }
2684
2757
  getPaneMetrics(kind, width = paneDimensionsForKind(kind, output.columns ?? 120, output.rows ?? 40).width, height = paneDimensionsForKind(kind, output.columns ?? 120, output.rows ?? 40).height) {
2685
2758
  const innerWidth = Math.max(1, width - 2);
2686
2759
  const rawBody = this.getPaneBody(kind);
@@ -3157,6 +3230,49 @@ export function parseSlashInput(line) {
3157
3230
  export function canSubmitParsedInputWhileBusy(parsed) {
3158
3231
  return parsed.kind === 'builtin' && (parsed.name === 'cancel' || parsed.name === 'exit' || parsed.name === 'quit');
3159
3232
  }
3233
+ export function reconcileEphemeralMessages(persistedMessages, ephemeralMessages) {
3234
+ if (ephemeralMessages.length === 0) {
3235
+ return [];
3236
+ }
3237
+ const persistedCounts = new Map();
3238
+ for (const message of persistedMessages) {
3239
+ const key = `${message.role}\u0000${message.content}`;
3240
+ persistedCounts.set(key, (persistedCounts.get(key) ?? 0) + 1);
3241
+ }
3242
+ const remaining = [];
3243
+ for (const message of ephemeralMessages) {
3244
+ if (message.pending || message.role === 'system') {
3245
+ remaining.push(message);
3246
+ continue;
3247
+ }
3248
+ const key = `${message.role}\u0000${message.content}`;
3249
+ const count = persistedCounts.get(key) ?? 0;
3250
+ if (count > 0) {
3251
+ persistedCounts.set(key, count - 1);
3252
+ continue;
3253
+ }
3254
+ remaining.push(message);
3255
+ }
3256
+ return remaining;
3257
+ }
3258
+ export function sessionMessagesContainCompletedTaskPreview(persistedMessages, previewEntries) {
3259
+ const previewUser = [...previewEntries].reverse().find((entry) => entry.role === 'user' && entry.content);
3260
+ const previewAssistant = [...previewEntries].reverse().find((entry) => entry.role === 'assistant' && !entry.pending && entry.content);
3261
+ if (!previewUser || !previewAssistant) {
3262
+ return false;
3263
+ }
3264
+ for (let index = persistedMessages.length - 1; index >= 1; index -= 1) {
3265
+ const assistant = persistedMessages[index];
3266
+ const user = persistedMessages[index - 1];
3267
+ if (user?.role === 'user'
3268
+ && assistant?.role === 'assistant'
3269
+ && user.content === previewUser.content
3270
+ && assistant.content === previewAssistant.content) {
3271
+ return true;
3272
+ }
3273
+ }
3274
+ return false;
3275
+ }
3160
3276
  export function computeFramePatch(previousLines, nextLines, previousSize, nextSize) {
3161
3277
  if (!previousLines
3162
3278
  || !previousSize
@@ -3855,6 +3971,29 @@ function wrapBodyLines(body, innerWidth) {
3855
3971
  }
3856
3972
  return lines;
3857
3973
  }
3974
+ export function collectTailWrappedLines(body, innerWidth, limit) {
3975
+ if (limit <= 0) {
3976
+ return { lines: [], truncated: body.length > 0 };
3977
+ }
3978
+ const collected = [];
3979
+ let truncated = false;
3980
+ for (let index = body.length - 1; index >= 0; index -= 1) {
3981
+ const wrapped = wrapPlainText(body[index], innerWidth);
3982
+ const remaining = limit - collected.length;
3983
+ if (remaining <= 0) {
3984
+ truncated = true;
3985
+ break;
3986
+ }
3987
+ if (wrapped.length <= remaining) {
3988
+ collected.unshift(...wrapped);
3989
+ continue;
3990
+ }
3991
+ collected.unshift(...wrapped.slice(wrapped.length - remaining));
3992
+ truncated = true;
3993
+ break;
3994
+ }
3995
+ return { lines: collected, truncated };
3996
+ }
3858
3997
  async function listWorkspaceTextFiles(workspaceRoot) {
3859
3998
  const results = [];
3860
3999
  const visit = async (relativeDir) => {