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 +31 -0
- package/dist/cli/tui.d.ts +13 -0
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +145 -6
- package/dist/cli/tui.js.map +1 -1
- package/dist/compiler_prompt.d.ts +1 -1
- package/dist/compiler_prompt.d.ts.map +1 -1
- package/dist/compiler_prompt.js +4 -2
- package/dist/compiler_prompt.js.map +1 -1
- package/dist/prolog-src/deepclause_mi.pl +40 -2
- package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +20 -1
- package/dist/system/assets/skills/skill-creator.dml +1 -0
- package/package.json +1 -1
- package/src/prolog-src/deepclause_mi.pl +40 -2
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;
|
package/dist/cli/tui.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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.
|
|
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) => {
|