gsd-pi 2.16.0 → 2.17.0
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/resources/extensions/gsd/auto-dashboard.ts +4 -0
- package/dist/resources/extensions/gsd/auto-dispatch.ts +9 -3
- package/dist/resources/extensions/gsd/auto-prompts.ts +71 -41
- package/dist/resources/extensions/gsd/auto-recovery.ts +7 -2
- package/dist/resources/extensions/gsd/auto.ts +54 -15
- package/dist/resources/extensions/gsd/commands.ts +20 -2
- package/dist/resources/extensions/gsd/complexity.ts +236 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/dist/resources/extensions/gsd/files.ts +6 -2
- package/dist/resources/extensions/gsd/git-service.ts +19 -8
- package/dist/resources/extensions/gsd/gitignore.ts +41 -2
- package/dist/resources/extensions/gsd/guided-flow.ts +10 -6
- package/dist/resources/extensions/gsd/metrics.ts +44 -0
- package/dist/resources/extensions/gsd/native-git-bridge.ts +5 -0
- package/dist/resources/extensions/gsd/native-parser-bridge.ts +5 -0
- package/dist/resources/extensions/gsd/preferences.ts +122 -1
- package/dist/resources/extensions/gsd/routing-history.ts +290 -0
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +50 -0
- package/dist/resources/extensions/gsd/tests/budget-prediction.test.ts +220 -0
- package/dist/resources/extensions/gsd/tests/complexity-routing.test.ts +294 -0
- package/dist/resources/extensions/gsd/tests/context-compression.test.ts +180 -0
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +132 -0
- package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +28 -0
- package/dist/resources/extensions/gsd/tests/routing-history.test.ts +87 -0
- package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +130 -0
- package/dist/resources/extensions/gsd/tests/token-profile.test.ts +263 -0
- package/dist/resources/extensions/gsd/types.ts +28 -0
- package/dist/resources/extensions/gsd/worktree.ts +2 -2
- package/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +493 -13
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +422 -62
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.d.ts +12 -0
- package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +9 -22
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-shared.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-shared.test.js +125 -0
- package/packages/pi-ai/dist/providers/google-shared.test.js.map +1 -0
- package/packages/pi-ai/src/models.generated.ts +422 -62
- package/packages/pi-ai/src/providers/google-shared.test.ts +137 -0
- package/packages/pi-ai/src/providers/google-shared.ts +10 -19
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts +7 -7
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +209 -13
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +85 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +245 -17
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +13 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +10 -0
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +4 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +9 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +71 -41
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -2
- package/src/resources/extensions/gsd/auto.ts +54 -15
- package/src/resources/extensions/gsd/commands.ts +20 -2
- package/src/resources/extensions/gsd/complexity.ts +236 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/src/resources/extensions/gsd/files.ts +6 -2
- package/src/resources/extensions/gsd/git-service.ts +19 -8
- package/src/resources/extensions/gsd/gitignore.ts +41 -2
- package/src/resources/extensions/gsd/guided-flow.ts +10 -6
- package/src/resources/extensions/gsd/metrics.ts +44 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +5 -0
- package/src/resources/extensions/gsd/native-parser-bridge.ts +5 -0
- package/src/resources/extensions/gsd/preferences.ts +122 -1
- package/src/resources/extensions/gsd/routing-history.ts +290 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +220 -0
- package/src/resources/extensions/gsd/tests/complexity-routing.test.ts +294 -0
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/preferences-git.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +130 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +263 -0
- package/src/resources/extensions/gsd/types.ts +28 -0
- package/src/resources/extensions/gsd/worktree.ts +2 -2
|
@@ -2,15 +2,11 @@
|
|
|
2
2
|
* Shared diff computation utilities for the edit tool.
|
|
3
3
|
* Used by both edit.ts (for execution) and tool-execution.ts (for preview rendering).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* These helpers intentionally stay in JavaScript. Issue #453 showed that
|
|
6
|
+
* post-tool preview paths must not depend on the native addon because a native
|
|
7
|
+
* hang there can wedge the entire interactive session after a successful tool run.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
-
fuzzyFindText as nativeFuzzyFindText,
|
|
11
|
-
generateDiff as nativeGenerateDiff,
|
|
12
|
-
normalizeForFuzzyMatch as nativeNormalizeForFuzzyMatch,
|
|
13
|
-
} from "@gsd/native";
|
|
14
10
|
import { constants } from "fs";
|
|
15
11
|
import { access, readFile } from "fs/promises";
|
|
16
12
|
import { resolveToCwd } from "./path-utils.js";
|
|
@@ -32,14 +28,23 @@ export function restoreLineEndings(text: string, ending: "\r\n" | "\n"): string
|
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
/**
|
|
35
|
-
* Normalize text for fuzzy matching
|
|
31
|
+
* Normalize text for fuzzy matching.
|
|
36
32
|
* - Strip trailing whitespace from each line
|
|
37
33
|
* - Normalize smart quotes to ASCII equivalents
|
|
38
34
|
* - Normalize Unicode dashes/hyphens to ASCII hyphen
|
|
39
35
|
* - Normalize special Unicode spaces to regular space
|
|
40
36
|
*/
|
|
41
37
|
export function normalizeForFuzzyMatch(text: string): string {
|
|
42
|
-
return
|
|
38
|
+
return text
|
|
39
|
+
.replace(/\r\n/g, "\n")
|
|
40
|
+
.replace(/\r/g, "\n")
|
|
41
|
+
.replace(/[“”]/g, '"')
|
|
42
|
+
.replace(/[‘’]/g, "'")
|
|
43
|
+
.replace(/[‐‑‒–—−]/g, "-")
|
|
44
|
+
.replace(/[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g, " ")
|
|
45
|
+
.split("\n")
|
|
46
|
+
.map((line) => line.replace(/[ \t]+$/g, ""))
|
|
47
|
+
.join("\n");
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
export interface FuzzyMatchResult {
|
|
@@ -59,14 +64,44 @@ export interface FuzzyMatchResult {
|
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
/**
|
|
62
|
-
* Find oldText in content, trying exact match first, then fuzzy match
|
|
63
|
-
* (native Rust implementation).
|
|
67
|
+
* Find oldText in content, trying exact match first, then fuzzy match.
|
|
64
68
|
*
|
|
65
69
|
* When fuzzy matching is used, the returned contentForReplacement is the
|
|
66
70
|
* fuzzy-normalized version of the content.
|
|
67
71
|
*/
|
|
68
72
|
export function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult {
|
|
69
|
-
|
|
73
|
+
const exactIndex = content.indexOf(oldText);
|
|
74
|
+
if (exactIndex !== -1) {
|
|
75
|
+
return {
|
|
76
|
+
found: true,
|
|
77
|
+
index: exactIndex,
|
|
78
|
+
matchLength: oldText.length,
|
|
79
|
+
usedFuzzyMatch: false,
|
|
80
|
+
contentForReplacement: content,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const normalizedContent = normalizeForFuzzyMatch(content);
|
|
85
|
+
const normalizedOldText = normalizeForFuzzyMatch(oldText);
|
|
86
|
+
const fuzzyIndex = normalizedContent.indexOf(normalizedOldText);
|
|
87
|
+
|
|
88
|
+
if (fuzzyIndex === -1) {
|
|
89
|
+
return {
|
|
90
|
+
found: false,
|
|
91
|
+
index: -1,
|
|
92
|
+
matchLength: 0,
|
|
93
|
+
usedFuzzyMatch: false,
|
|
94
|
+
contentForReplacement: content,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
found: true,
|
|
100
|
+
index: fuzzyIndex,
|
|
101
|
+
matchLength: normalizedOldText.length,
|
|
102
|
+
usedFuzzyMatch: true,
|
|
103
|
+
contentForReplacement: normalizedContent,
|
|
104
|
+
};
|
|
70
105
|
}
|
|
71
106
|
|
|
72
107
|
/** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */
|
|
@@ -75,20 +110,81 @@ export function stripBom(content: string): { bom: string; text: string } {
|
|
|
75
110
|
}
|
|
76
111
|
|
|
77
112
|
/**
|
|
78
|
-
* Generate a unified diff string with line numbers and context
|
|
79
|
-
* (native Rust implementation using Myers' algorithm via the `similar` crate).
|
|
113
|
+
* Generate a unified diff string with line numbers and context.
|
|
80
114
|
*
|
|
81
115
|
* Returns both the diff string and the first changed line number (in the new file).
|
|
116
|
+
* Only lines within `contextLines` of a change are included (like unified diff).
|
|
82
117
|
*/
|
|
83
118
|
export function generateDiffString(
|
|
84
119
|
oldContent: string,
|
|
85
120
|
newContent: string,
|
|
86
121
|
contextLines = 4,
|
|
87
122
|
): { diff: string; firstChangedLine: number | undefined } {
|
|
88
|
-
const
|
|
123
|
+
const ops = buildLineDiff(oldContent, newContent);
|
|
124
|
+
let firstChangedLine: number | undefined;
|
|
125
|
+
|
|
126
|
+
// First pass: assign line numbers and find changed indices
|
|
127
|
+
const annotated: { op: LineDiffOp; oldLine: number; newLine: number }[] = [];
|
|
128
|
+
let oldLine = 1;
|
|
129
|
+
let newLine = 1;
|
|
130
|
+
const changedIndices: number[] = [];
|
|
131
|
+
|
|
132
|
+
for (let idx = 0; idx < ops.length; idx++) {
|
|
133
|
+
const op = ops[idx];
|
|
134
|
+
annotated.push({ op, oldLine, newLine });
|
|
135
|
+
|
|
136
|
+
if (op.type !== "context") {
|
|
137
|
+
changedIndices.push(idx);
|
|
138
|
+
if (firstChangedLine === undefined) {
|
|
139
|
+
firstChangedLine = newLine;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (op.type === "remove") {
|
|
144
|
+
oldLine += 1;
|
|
145
|
+
} else if (op.type === "add") {
|
|
146
|
+
newLine += 1;
|
|
147
|
+
} else {
|
|
148
|
+
oldLine += 1;
|
|
149
|
+
newLine += 1;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Build set of indices to include (changes + surrounding context)
|
|
154
|
+
const includeSet = new Set<number>();
|
|
155
|
+
for (const ci of changedIndices) {
|
|
156
|
+
for (let k = Math.max(0, ci - contextLines); k <= Math.min(ops.length - 1, ci + contextLines); k++) {
|
|
157
|
+
includeSet.add(k);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const maxLine = Math.max(oldLine - 1, newLine - 1, 1);
|
|
162
|
+
const lineNumberWidth = String(maxLine).length;
|
|
163
|
+
const rendered: string[] = [];
|
|
164
|
+
let lastIncluded = -1;
|
|
165
|
+
|
|
166
|
+
for (let idx = 0; idx < annotated.length; idx++) {
|
|
167
|
+
if (!includeSet.has(idx)) continue;
|
|
168
|
+
|
|
169
|
+
// Insert separator when there's a gap between included regions
|
|
170
|
+
if (lastIncluded !== -1 && idx > lastIncluded + 1) {
|
|
171
|
+
rendered.push("...");
|
|
172
|
+
}
|
|
173
|
+
lastIncluded = idx;
|
|
174
|
+
|
|
175
|
+
const { op, oldLine: ol, newLine: nl } = annotated[idx];
|
|
176
|
+
if (op.type === "context") {
|
|
177
|
+
rendered.push(` ${String(nl).padStart(lineNumberWidth, " ")} ${op.line}`);
|
|
178
|
+
} else if (op.type === "remove") {
|
|
179
|
+
rendered.push(`-${String(ol).padStart(lineNumberWidth, " ")} ${op.line}`);
|
|
180
|
+
} else {
|
|
181
|
+
rendered.push(`+${String(nl).padStart(lineNumberWidth, " ")} ${op.line}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
89
185
|
return {
|
|
90
|
-
diff:
|
|
91
|
-
firstChangedLine
|
|
186
|
+
diff: rendered.join("\n"),
|
|
187
|
+
firstChangedLine,
|
|
92
188
|
};
|
|
93
189
|
}
|
|
94
190
|
|
|
@@ -101,6 +197,138 @@ export interface EditDiffError {
|
|
|
101
197
|
error: string;
|
|
102
198
|
}
|
|
103
199
|
|
|
200
|
+
type LineDiffOp =
|
|
201
|
+
| { type: "context"; line: string }
|
|
202
|
+
| { type: "remove"; line: string }
|
|
203
|
+
| { type: "add"; line: string };
|
|
204
|
+
|
|
205
|
+
function splitLines(text: string): string[] {
|
|
206
|
+
const lines = text.split("\n");
|
|
207
|
+
if (lines.length > 0 && lines.at(-1) === "") {
|
|
208
|
+
lines.pop();
|
|
209
|
+
}
|
|
210
|
+
return lines;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Maximum number of cells (oldLines * newLines) before we switch from the
|
|
215
|
+
* full LCS DP algorithm to a simpler linear-scan diff. This prevents OOM
|
|
216
|
+
* on large files (e.g. 10k lines would need a 100M-cell matrix).
|
|
217
|
+
*/
|
|
218
|
+
const MAX_DP_CELLS = 4_000_000; // ~32 MB for 64-bit numbers
|
|
219
|
+
|
|
220
|
+
function buildLineDiff(oldContent: string, newContent: string): LineDiffOp[] {
|
|
221
|
+
const oldLines = splitLines(oldContent);
|
|
222
|
+
const newLines = splitLines(newContent);
|
|
223
|
+
|
|
224
|
+
const cells = (oldLines.length + 1) * (newLines.length + 1);
|
|
225
|
+
if (cells > MAX_DP_CELLS) {
|
|
226
|
+
return buildLineDiffLinear(oldLines, newLines);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return buildLineDiffLCS(oldLines, newLines);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Full LCS-based diff using O(n*m) DP table. Produces optimal diffs but
|
|
234
|
+
* is only safe for files where n*m <= MAX_DP_CELLS.
|
|
235
|
+
*/
|
|
236
|
+
function buildLineDiffLCS(oldLines: string[], newLines: string[]): LineDiffOp[] {
|
|
237
|
+
const dp: number[][] = Array.from({ length: oldLines.length + 1 }, () =>
|
|
238
|
+
Array<number>(newLines.length + 1).fill(0),
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
for (let i = oldLines.length - 1; i >= 0; i--) {
|
|
242
|
+
for (let j = newLines.length - 1; j >= 0; j--) {
|
|
243
|
+
if (oldLines[i] === newLines[j]) {
|
|
244
|
+
dp[i][j] = dp[i + 1][j + 1] + 1;
|
|
245
|
+
} else {
|
|
246
|
+
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const ops: LineDiffOp[] = [];
|
|
252
|
+
let i = 0;
|
|
253
|
+
let j = 0;
|
|
254
|
+
|
|
255
|
+
while (i < oldLines.length && j < newLines.length) {
|
|
256
|
+
if (oldLines[i] === newLines[j]) {
|
|
257
|
+
ops.push({ type: "context", line: oldLines[i] });
|
|
258
|
+
i += 1;
|
|
259
|
+
j += 1;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (dp[i + 1][j] >= dp[i][j + 1]) {
|
|
264
|
+
ops.push({ type: "remove", line: oldLines[i] });
|
|
265
|
+
i += 1;
|
|
266
|
+
} else {
|
|
267
|
+
ops.push({ type: "add", line: newLines[j] });
|
|
268
|
+
j += 1;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
while (i < oldLines.length) {
|
|
273
|
+
ops.push({ type: "remove", line: oldLines[i] });
|
|
274
|
+
i += 1;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
while (j < newLines.length) {
|
|
278
|
+
ops.push({ type: "add", line: newLines[j] });
|
|
279
|
+
j += 1;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return ops;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Linear-time fallback diff for large files. Matches common prefix/suffix,
|
|
287
|
+
* then treats the remaining middle as a bulk remove+add. Not optimal but
|
|
288
|
+
* O(n+m) in both time and space.
|
|
289
|
+
*/
|
|
290
|
+
function buildLineDiffLinear(oldLines: string[], newLines: string[]): LineDiffOp[] {
|
|
291
|
+
const ops: LineDiffOp[] = [];
|
|
292
|
+
|
|
293
|
+
// Match common prefix
|
|
294
|
+
let prefixLen = 0;
|
|
295
|
+
const minLen = Math.min(oldLines.length, newLines.length);
|
|
296
|
+
while (prefixLen < minLen && oldLines[prefixLen] === newLines[prefixLen]) {
|
|
297
|
+
prefixLen++;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Match common suffix (not overlapping with prefix)
|
|
301
|
+
let suffixLen = 0;
|
|
302
|
+
while (
|
|
303
|
+
suffixLen < minLen - prefixLen &&
|
|
304
|
+
oldLines[oldLines.length - 1 - suffixLen] === newLines[newLines.length - 1 - suffixLen]
|
|
305
|
+
) {
|
|
306
|
+
suffixLen++;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Emit prefix context
|
|
310
|
+
for (let i = 0; i < prefixLen; i++) {
|
|
311
|
+
ops.push({ type: "context", line: oldLines[i] });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Emit removed lines from the middle
|
|
315
|
+
for (let i = prefixLen; i < oldLines.length - suffixLen; i++) {
|
|
316
|
+
ops.push({ type: "remove", line: oldLines[i] });
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Emit added lines from the middle
|
|
320
|
+
for (let j = prefixLen; j < newLines.length - suffixLen; j++) {
|
|
321
|
+
ops.push({ type: "add", line: newLines[j] });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Emit suffix context
|
|
325
|
+
for (let i = oldLines.length - suffixLen; i < oldLines.length; i++) {
|
|
326
|
+
ops.push({ type: "context", line: oldLines[i] });
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return ops;
|
|
330
|
+
}
|
|
331
|
+
|
|
104
332
|
/**
|
|
105
333
|
* Compute the diff for an edit operation without applying it.
|
|
106
334
|
* Used for preview rendering in the TUI before the tool executes.
|
|
@@ -11,6 +11,11 @@ import {
|
|
|
11
11
|
} from "@gsd/native";
|
|
12
12
|
import { getCustomThemesDir, getThemesDir } from "../../../config.js";
|
|
13
13
|
|
|
14
|
+
// Issue #453: native preview highlighting can wedge the entire interactive
|
|
15
|
+
// session after a successful file tool. Keep the safer plain-text path as the
|
|
16
|
+
// default and allow native highlighting only as an explicit opt-in.
|
|
17
|
+
const NATIVE_TUI_HIGHLIGHT_ENABLED = process.env.GSD_ENABLE_NATIVE_TUI_HIGHLIGHT === "1";
|
|
18
|
+
|
|
14
19
|
// ============================================================================
|
|
15
20
|
// Types & Schema
|
|
16
21
|
// ============================================================================
|
|
@@ -955,6 +960,10 @@ function getHighlightColors(t: Theme): HighlightColors {
|
|
|
955
960
|
* Returns array of highlighted lines.
|
|
956
961
|
*/
|
|
957
962
|
export function highlightCode(code: string, lang?: string): string[] {
|
|
963
|
+
if (!NATIVE_TUI_HIGHLIGHT_ENABLED) {
|
|
964
|
+
return code.split("\n");
|
|
965
|
+
}
|
|
966
|
+
|
|
958
967
|
const validLang = lang && supportsLanguage(lang) ? lang : null;
|
|
959
968
|
try {
|
|
960
969
|
return nativeHighlightCode(code, validLang, getHighlightColors(theme)).split("\n");
|
|
@@ -1051,6 +1060,10 @@ export function getMarkdownTheme(): MarkdownTheme {
|
|
|
1051
1060
|
underline: (text: string) => theme.underline(text),
|
|
1052
1061
|
strikethrough: (text: string) => chalk.strikethrough(text),
|
|
1053
1062
|
highlightCode: (code: string, lang?: string): string[] => {
|
|
1063
|
+
if (!NATIVE_TUI_HIGHLIGHT_ENABLED) {
|
|
1064
|
+
return code.split("\n").map((line) => theme.fg("mdCodeBlock", line));
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1054
1067
|
const validLang = lang && supportsLanguage(lang) ? lang : null;
|
|
1055
1068
|
try {
|
|
1056
1069
|
return nativeHighlightCode(code, validLang, getHighlightColors(theme)).split("\n");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/theme.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/theme.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,10 @@ import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { highlightCode as nativeHighlightCode, supportsLanguage, } from "@gsd/native";
|
|
7
7
|
import { getCustomThemesDir, getThemesDir } from "../../../config.js";
|
|
8
|
+
// Issue #453: native preview highlighting can wedge the entire interactive
|
|
9
|
+
// session after a successful file tool. Keep the safer plain-text path as the
|
|
10
|
+
// default and allow native highlighting only as an explicit opt-in.
|
|
11
|
+
const NATIVE_TUI_HIGHLIGHT_ENABLED = process.env.GSD_ENABLE_NATIVE_TUI_HIGHLIGHT === "1";
|
|
8
12
|
// ============================================================================
|
|
9
13
|
// Types & Schema
|
|
10
14
|
// ============================================================================
|
|
@@ -798,6 +802,9 @@ function getHighlightColors(t) {
|
|
|
798
802
|
* Returns array of highlighted lines.
|
|
799
803
|
*/
|
|
800
804
|
export function highlightCode(code, lang) {
|
|
805
|
+
if (!NATIVE_TUI_HIGHLIGHT_ENABLED) {
|
|
806
|
+
return code.split("\n");
|
|
807
|
+
}
|
|
801
808
|
const validLang = lang && supportsLanguage(lang) ? lang : null;
|
|
802
809
|
try {
|
|
803
810
|
return nativeHighlightCode(code, validLang, getHighlightColors(theme)).split("\n");
|
|
@@ -892,6 +899,9 @@ export function getMarkdownTheme() {
|
|
|
892
899
|
underline: (text) => theme.underline(text),
|
|
893
900
|
strikethrough: (text) => chalk.strikethrough(text),
|
|
894
901
|
highlightCode: (code, lang) => {
|
|
902
|
+
if (!NATIVE_TUI_HIGHLIGHT_ENABLED) {
|
|
903
|
+
return code.split("\n").map((line) => theme.fg("mdCodeBlock", line));
|
|
904
|
+
}
|
|
895
905
|
const validLang = lang && supportsLanguage(lang) ? lang : null;
|
|
896
906
|
try {
|
|
897
907
|
return nativeHighlightCode(code, validLang, getHighlightColors(theme)).split("\n");
|