@chances-ai/tui 16.0.0 → 18.0.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/app.d.ts +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +2 -2
- package/dist/app.js.map +1 -1
- package/dist/code-view.js +1 -1
- package/dist/code-view.js.map +1 -1
- package/dist/diff-view.js +1 -1
- package/dist/diff-view.js.map +1 -1
- package/dist/help-view.d.ts +46 -0
- package/dist/help-view.d.ts.map +1 -0
- package/dist/help-view.js +52 -0
- package/dist/help-view.js.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/select.d.ts +5 -0
- package/dist/select.d.ts.map +1 -1
- package/dist/select.js +11 -1
- package/dist/select.js.map +1 -1
- package/dist/theme.d.ts +15 -101
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +18 -109
- package/dist/theme.js.map +1 -1
- package/dist/tool-message.js +1 -1
- package/dist/tool-message.js.map +1 -1
- package/package.json +6 -5
- package/dist/diff-model.d.ts +0 -64
- package/dist/diff-model.d.ts.map +0 -1
- package/dist/diff-model.js +0 -156
- package/dist/diff-model.js.map +0 -1
- package/dist/frame-scheduler.d.ts +0 -44
- package/dist/frame-scheduler.d.ts.map +0 -1
- package/dist/frame-scheduler.js +0 -58
- package/dist/frame-scheduler.js.map +0 -1
- package/dist/highlight-to-segments.d.ts +0 -18
- package/dist/highlight-to-segments.d.ts.map +0 -1
- package/dist/highlight-to-segments.js +0 -224
- package/dist/highlight-to-segments.js.map +0 -1
- package/dist/tool-line.d.ts +0 -33
- package/dist/tool-line.d.ts.map +0 -1
- package/dist/tool-line.js +0 -168
- package/dist/tool-line.js.map +0 -1
- package/dist/view-model.d.ts +0 -226
- package/dist/view-model.d.ts.map +0 -1
- package/dist/view-model.js +0 -488
- package/dist/view-model.js.map +0 -1
package/dist/theme.js
CHANGED
|
@@ -1,116 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* (
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `theme
|
|
7
|
-
*
|
|
8
|
-
* Colors are emitted as Ink-compatible `rgb(r,g,b)` strings; Ink renders them
|
|
9
|
-
* through chalk, which downsamples truecolor → 256/16 by the terminal's
|
|
10
|
-
* detected level. We therefore keep ONE truecolor palette per mode and let
|
|
11
|
-
* chalk degrade — there is no hand-rolled 16-ANSI fallback table (5.9 §0).
|
|
12
|
-
*
|
|
13
|
-
* `NO_COLOR` (https://no-color.org) is honored explicitly here because chalk
|
|
14
|
-
* 5 / Ink 7 only read the `--no-color` *flag*, not the env var (codex R1
|
|
15
|
-
* MUST-2): when set, `resolveTheme` returns a palette whose every color is
|
|
16
|
-
* `undefined`, so components emit no `color`/`backgroundColor` and meaning is
|
|
17
|
-
* carried by glyphs + sigils alone (the diff `+`/`-`, the `⏺`/`⎿` shapes).
|
|
18
|
-
*
|
|
19
|
-
* Dark RGB values are the facts of claude-code's `darkTheme` visual language
|
|
20
|
-
* (verified `~/Projects/github/claude-code/src/utils/theme.ts`); light values
|
|
21
|
-
* track its `lightTheme`. Syntax colors are an OneDark-ish set legible on the
|
|
22
|
-
* respective background.
|
|
2
|
+
* (v17 M0) TUI theme shim. The pure visual-language tokens + functions now live
|
|
3
|
+
* in `@chances-ai/ui-core` (browser-safe — no `node:*`, no `process.*`). This
|
|
4
|
+
* module re-exports them and adds the TUI's Node-bound conveniences: the
|
|
5
|
+
* `process.env`-defaulting `isNoColor` / `resolveTheme`, and the
|
|
6
|
+
* `process.platform`-derived `GLYPHS` constant. Keeping the same `./theme.js`
|
|
7
|
+
* specifier means every TUI component import is unchanged.
|
|
23
8
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
planMode: "rgb(72,150,140)",
|
|
31
|
-
autoAccept: "rgb(175,135,255)",
|
|
32
|
-
bashPink: "rgb(253,93,177)",
|
|
33
|
-
diffAddedBg: "rgb(34,92,43)",
|
|
34
|
-
diffRemovedBg: "rgb(122,41,54)",
|
|
35
|
-
diffAddedWordBg: "rgb(56,166,96)",
|
|
36
|
-
diffRemovedWordBg: "rgb(179,89,107)",
|
|
37
|
-
userMessageBg: "rgb(55,55,55)",
|
|
38
|
-
stall: "rgb(171,43,63)",
|
|
39
|
-
synKeyword: "rgb(198,120,221)",
|
|
40
|
-
synString: "rgb(152,195,121)",
|
|
41
|
-
synComment: "rgb(106,115,125)",
|
|
42
|
-
synNumber: "rgb(209,154,102)",
|
|
43
|
-
synFunction: "rgb(97,175,239)",
|
|
44
|
-
synType: "rgb(229,192,123)",
|
|
45
|
-
synLiteral: "rgb(86,182,194)",
|
|
46
|
-
synTitle: "rgb(97,175,239)",
|
|
47
|
-
synAttr: "rgb(209,154,102)",
|
|
48
|
-
};
|
|
49
|
-
const lightTheme = {
|
|
50
|
-
accent: "rgb(215,119,87)",
|
|
51
|
-
success: "rgb(44,122,57)",
|
|
52
|
-
error: "rgb(171,43,63)",
|
|
53
|
-
warning: "rgb(150,108,30)",
|
|
54
|
-
permission: "rgb(87,105,247)",
|
|
55
|
-
planMode: "rgb(0,102,102)",
|
|
56
|
-
autoAccept: "rgb(135,0,255)",
|
|
57
|
-
bashPink: "rgb(255,0,135)",
|
|
58
|
-
diffAddedBg: "rgb(105,219,124)",
|
|
59
|
-
diffRemovedBg: "rgb(255,168,180)",
|
|
60
|
-
diffAddedWordBg: "rgb(47,157,68)",
|
|
61
|
-
diffRemovedWordBg: "rgb(209,69,75)",
|
|
62
|
-
userMessageBg: "rgb(240,240,240)",
|
|
63
|
-
stall: "rgb(171,43,63)",
|
|
64
|
-
synKeyword: "rgb(166,38,164)",
|
|
65
|
-
synString: "rgb(80,161,79)",
|
|
66
|
-
synComment: "rgb(160,161,167)",
|
|
67
|
-
synNumber: "rgb(152,104,1)",
|
|
68
|
-
synFunction: "rgb(64,120,242)",
|
|
69
|
-
synType: "rgb(193,132,1)",
|
|
70
|
-
synLiteral: "rgb(1,132,188)",
|
|
71
|
-
synTitle: "rgb(64,120,242)",
|
|
72
|
-
synAttr: "rgb(152,104,1)",
|
|
73
|
-
};
|
|
74
|
-
/** Every color undefined ⇒ no color props emitted (glyphs/sigils carry meaning). */
|
|
75
|
-
const noColorTheme = {};
|
|
76
|
-
/** `NO_COLOR` (https://no-color.org): present and NON-EMPTY ⇒ disable color,
|
|
77
|
-
* regardless of value. An empty string does NOT disable (per the spec). */
|
|
9
|
+
import { makeGlyphs, isNoColor as isNoColorCore, resolveTheme as resolveThemeCore, } from "@chances-ai/ui-core";
|
|
10
|
+
export { makeGlyphs, SPINNER_FRAMES, SPINNER_STATIC } from "@chances-ai/ui-core";
|
|
11
|
+
/** Glyph set for the running platform (`process.platform`). */
|
|
12
|
+
export const GLYPHS = makeGlyphs(process.platform);
|
|
13
|
+
/** `NO_COLOR` check defaulting to `process.env` (TUI convenience over the pure
|
|
14
|
+
* ui-core `isNoColor(env)` — https://no-color.org). */
|
|
78
15
|
export function isNoColor(env = process.env) {
|
|
79
|
-
|
|
80
|
-
|
|
16
|
+
// Project to the narrow `NoColorEnv` (ui-core reads only NO_COLOR); a bare
|
|
17
|
+
// `process.env` (index-signature-only) isn't structurally assignable.
|
|
18
|
+
return isNoColorCore({ NO_COLOR: env.NO_COLOR });
|
|
81
19
|
}
|
|
82
|
-
/**
|
|
83
|
-
*
|
|
84
|
-
* the light palette and `'dark'`/`'auto'`/undefined → dark.
|
|
85
|
-
*/
|
|
20
|
+
/** Resolve a palette, defaulting the env to `process.env` (TUI convenience over
|
|
21
|
+
* the pure ui-core `resolveTheme(setting, env)`). */
|
|
86
22
|
export function resolveTheme(setting, env = process.env) {
|
|
87
|
-
|
|
88
|
-
return noColorTheme;
|
|
89
|
-
return setting === "light" ? lightTheme : darkTheme;
|
|
90
|
-
}
|
|
91
|
-
/** Build the glyph set for a platform. Exported as a function so tests can pin
|
|
92
|
-
* both the darwin (`⏺`) and non-darwin (`●`) dot without monkey-patching. */
|
|
93
|
-
export function makeGlyphs(platform = process.platform) {
|
|
94
|
-
return {
|
|
95
|
-
dot: platform === "darwin" ? "⏺" : "●",
|
|
96
|
-
branch: "⎿",
|
|
97
|
-
prompt: "❯",
|
|
98
|
-
blockquote: "▎",
|
|
99
|
-
plan: "⏸",
|
|
100
|
-
accept: "⏵⏵",
|
|
101
|
-
tick: "✓",
|
|
102
|
-
hr: "─",
|
|
103
|
-
bullet: "•",
|
|
104
|
-
thinking: "✻",
|
|
105
|
-
arrowDown: "↓",
|
|
106
|
-
arrowUp: "↑",
|
|
107
|
-
};
|
|
23
|
+
return resolveThemeCore(setting, { NO_COLOR: env.NO_COLOR });
|
|
108
24
|
}
|
|
109
|
-
export const GLYPHS = makeGlyphs();
|
|
110
|
-
/** Spinner pulse: 6 frames then their reverse = a 12-step in/out pulse
|
|
111
|
-
* (claude-code `Spinner.tsx` `[...frames, ...reversed]`). Tick ~120 ms. */
|
|
112
|
-
const SPINNER_BASE = ["·", "✢", "✱", "✶", "✻", "✽"];
|
|
113
|
-
export const SPINNER_FRAMES = [...SPINNER_BASE, ...[...SPINNER_BASE].reverse()];
|
|
114
|
-
/** Static glyph shown instead of the animation under reduced-motion / NO_COLOR. */
|
|
115
|
-
export const SPINNER_STATIC = "●";
|
|
116
25
|
//# sourceMappingURL=theme.js.map
|
package/dist/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,UAAU,EACV,SAAS,IAAI,aAAa,EAC1B,YAAY,IAAI,gBAAgB,GAIjC,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEjF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,MAAM,GAAW,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE3D;wDACwD;AACxD,MAAM,UAAU,SAAS,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC5D,2EAA2E;IAC3E,sEAAsE;IACtE,OAAO,aAAa,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;AACnD,CAAC;AAED;sDACsD;AACtD,MAAM,UAAU,YAAY,CAC1B,OAAiC,EACjC,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,gBAAgB,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/D,CAAC"}
|
package/dist/tool-message.js
CHANGED
|
@@ -12,7 +12,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
12
12
|
*/
|
|
13
13
|
import { Box, Text } from "ink";
|
|
14
14
|
import { DiffView } from "./diff-view.js";
|
|
15
|
-
import { toolDisplayName } from "
|
|
15
|
+
import { toolDisplayName } from "@chances-ai/ui-core";
|
|
16
16
|
import { useTheme } from "./theme-context.js";
|
|
17
17
|
/** Left indent (cols) the embedded diff sits under the `⎿` branch. */
|
|
18
18
|
const DIFF_INDENT = 5;
|
package/dist/tool-message.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-message.js","sourceRoot":"","sources":["../src/tool-message.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"tool-message.js","sourceRoot":"","sources":["../src/tool-message.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,sEAAsE;AACtE,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,SAAS,WAAW;IAClB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;IACrC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1D,CAAC;AAkBD,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,UAAU,EACV,EAAE,EACF,MAAM,EACN,IAAI,EACJ,QAAQ,GAAG,KAAK,EAChB,KAAK,GACY;IACjB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IACpF,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvD,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,QAAQ,YAAG,MAAM,CAAC,GAAG,GAAQ,EAAC,GAAG,EAC9C,KAAC,IAAI,IAAC,IAAI,kBAAE,OAAO,GAAQ,EAC1B,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,IAC/B,EACN,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAC5B,MAAC,IAAI,IAAS,KAAK,EAAE,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,KAAK,KAAK,aAChF,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,EACzC,IAAI,KAFI,CAAC,CAGL,CACR,CAAC,EACD,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,GAAG,IAAC,WAAW,EAAE,WAAW,YAG3B,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,WAAW,EAAE,CAAC,GAAG,WAAW,GAAI,GACvF,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC;AAED;;kDAEkD;AAClD,SAAS,YAAY,CAAC,MAAc;IAClC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7F,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chances-ai/tui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
"dist"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@chances-ai/ink-ext": "
|
|
18
|
-
"@chances-ai/plugin-api": "
|
|
19
|
-
"@chances-ai/runtime": "
|
|
20
|
-
"@chances-ai/tools": "
|
|
17
|
+
"@chances-ai/ink-ext": "18.0.0",
|
|
18
|
+
"@chances-ai/plugin-api": "18.0.0",
|
|
19
|
+
"@chances-ai/runtime": "18.0.0",
|
|
20
|
+
"@chances-ai/tools": "18.0.0",
|
|
21
|
+
"@chances-ai/ui-core": "18.0.0",
|
|
21
22
|
"marked": "^18.0.0",
|
|
22
23
|
"highlight.js": "^11.11.1",
|
|
23
24
|
"diff": "^9.0.0",
|
package/dist/diff-model.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* (5.9 / v14) Pure parser that turns the `linesDiff` text block (carried in a
|
|
3
|
-
* write/edit `tool:permission` summary — see `view-model.ts`) into structured,
|
|
4
|
-
* renderable rows. NO React/Ink here — this is the correctness core, fully
|
|
5
|
-
* unit-tested in isolation.
|
|
6
|
-
*
|
|
7
|
-
* `linesDiff` (`packages/tools/src/diff.ts`) emits, in order:
|
|
8
|
-
* `@@ -start,rem +start,add @@`
|
|
9
|
-
* `- <removed line>` × rem
|
|
10
|
-
* `+ <added line>` × add
|
|
11
|
-
* — i.e. ALL removes then ALL adds, NO context lines; with a `… (N lines
|
|
12
|
-
* elided)` marker injected in the middle when the block exceeds its 14-body-row
|
|
13
|
-
* cap (so a full block is up to 15 lines incl. the header — codex R1 SHOULD-5).
|
|
14
|
-
*
|
|
15
|
-
* Line numbers (codex R1 MUST-1): `write` diffs are whole-file-anchored
|
|
16
|
-
* (`linesDiff(before, content)`), so `@@ -start` is the real file line — render
|
|
17
|
-
* the gutter. `edit` diffs are `find`↔`replace` snippets, so `@@ -1` is
|
|
18
|
-
* snippet-relative — the caller passes `anchored: false` and no gutter is shown.
|
|
19
|
-
*/
|
|
20
|
-
/** Threshold above which a remove/add pair renders as whole-line (not word-level).
|
|
21
|
-
* Matches claude-code `StructuredDiff/Fallback.tsx` `CHANGE_THRESHOLD`. */
|
|
22
|
-
export declare const CHANGE_THRESHOLD = 0.4;
|
|
23
|
-
export interface WordSeg {
|
|
24
|
-
text: string;
|
|
25
|
-
/** True ⇒ this word was added (on an add row) or removed (on a remove row). */
|
|
26
|
-
changed: boolean;
|
|
27
|
-
}
|
|
28
|
-
export interface DiffRow {
|
|
29
|
-
kind: "add" | "remove" | "elision";
|
|
30
|
-
/** Code content with the `+`/`-`/space sigil stripped (the raw elision text
|
|
31
|
-
* for `kind:"elision"`). */
|
|
32
|
-
text: string;
|
|
33
|
-
/** Assigned line number, or null when unanchored (edit) or an elision row. */
|
|
34
|
-
lineNo: number | null;
|
|
35
|
-
/** Word-level segments when this row is part of a sub-threshold pair; null ⇒
|
|
36
|
-
* render the whole line with the line background. */
|
|
37
|
-
words: WordSeg[] | null;
|
|
38
|
-
}
|
|
39
|
-
export interface ParsedDiff {
|
|
40
|
-
rows: DiffRow[];
|
|
41
|
-
/** The hunk's old start line (1-based) parsed from the `@@` header, or null. */
|
|
42
|
-
startLine: number | null;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Detect whether a text block is a renderable diff (the non-diff guard, 5.9 §3):
|
|
46
|
-
* true only when it contains a `@@ -d +d @@` hunk header.
|
|
47
|
-
*/
|
|
48
|
-
export declare function looksLikeDiff(text: string): boolean;
|
|
49
|
-
/**
|
|
50
|
-
* Parse a `linesDiff` block. `anchored` (write=true, edit=false) controls
|
|
51
|
-
* whether line numbers are assigned. Returns rows in source order with
|
|
52
|
-
* word-level segments computed for sub-threshold remove/add pairs.
|
|
53
|
-
*/
|
|
54
|
-
export declare function parseDiff(text: string, opts: {
|
|
55
|
-
anchored: boolean;
|
|
56
|
-
}): ParsedDiff;
|
|
57
|
-
/**
|
|
58
|
-
* Word-level segments for one side of a pair. `side:"remove"` keeps common +
|
|
59
|
-
* removed words; `side:"add"` keeps common + added words. Returns null when the
|
|
60
|
-
* pair changed more than {@link CHANGE_THRESHOLD} of its total length (render
|
|
61
|
-
* whole-line instead).
|
|
62
|
-
*/
|
|
63
|
-
export declare function wordSegs(removeText: string, addText: string, side: "add" | "remove"): WordSeg[] | null;
|
|
64
|
-
//# sourceMappingURL=diff-model.d.ts.map
|
package/dist/diff-model.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diff-model.d.ts","sourceRoot":"","sources":["../src/diff-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH;4EAC4E;AAC5E,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;IACnC;iCAC6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;0DACsD;IACtD,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,gFAAgF;IAChF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAQD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAOD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,GAAG,UAAU,CAuB/E;AAqED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,EAAE,GAAG,IAAI,CAiBtG"}
|
package/dist/diff-model.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* (5.9 / v14) Pure parser that turns the `linesDiff` text block (carried in a
|
|
3
|
-
* write/edit `tool:permission` summary — see `view-model.ts`) into structured,
|
|
4
|
-
* renderable rows. NO React/Ink here — this is the correctness core, fully
|
|
5
|
-
* unit-tested in isolation.
|
|
6
|
-
*
|
|
7
|
-
* `linesDiff` (`packages/tools/src/diff.ts`) emits, in order:
|
|
8
|
-
* `@@ -start,rem +start,add @@`
|
|
9
|
-
* `- <removed line>` × rem
|
|
10
|
-
* `+ <added line>` × add
|
|
11
|
-
* — i.e. ALL removes then ALL adds, NO context lines; with a `… (N lines
|
|
12
|
-
* elided)` marker injected in the middle when the block exceeds its 14-body-row
|
|
13
|
-
* cap (so a full block is up to 15 lines incl. the header — codex R1 SHOULD-5).
|
|
14
|
-
*
|
|
15
|
-
* Line numbers (codex R1 MUST-1): `write` diffs are whole-file-anchored
|
|
16
|
-
* (`linesDiff(before, content)`), so `@@ -start` is the real file line — render
|
|
17
|
-
* the gutter. `edit` diffs are `find`↔`replace` snippets, so `@@ -1` is
|
|
18
|
-
* snippet-relative — the caller passes `anchored: false` and no gutter is shown.
|
|
19
|
-
*/
|
|
20
|
-
import { diffWordsWithSpace } from "diff";
|
|
21
|
-
/** Threshold above which a remove/add pair renders as whole-line (not word-level).
|
|
22
|
-
* Matches claude-code `StructuredDiff/Fallback.tsx` `CHANGE_THRESHOLD`. */
|
|
23
|
-
export const CHANGE_THRESHOLD = 0.4;
|
|
24
|
-
const HUNK_RE = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
|
|
25
|
-
// Anchored + exact: `linesDiff` emits the marker as `… (N lines elided)`. A
|
|
26
|
-
// loose `lines elided)` alternative (codex R2 SHOULD-4) would misclassify a
|
|
27
|
-
// real source line that merely contains that phrase.
|
|
28
|
-
const ELISION_RE = /^… \(\d+ lines elided\)$/;
|
|
29
|
-
/**
|
|
30
|
-
* Detect whether a text block is a renderable diff (the non-diff guard, 5.9 §3):
|
|
31
|
-
* true only when it contains a `@@ -d +d @@` hunk header.
|
|
32
|
-
*/
|
|
33
|
-
export function looksLikeDiff(text) {
|
|
34
|
-
return text.split("\n").some((l) => HUNK_RE.test(l));
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Parse a `linesDiff` block. `anchored` (write=true, edit=false) controls
|
|
38
|
-
* whether line numbers are assigned. Returns rows in source order with
|
|
39
|
-
* word-level segments computed for sub-threshold remove/add pairs.
|
|
40
|
-
*/
|
|
41
|
-
export function parseDiff(text, opts) {
|
|
42
|
-
const lines = text.split("\n");
|
|
43
|
-
let startLine = null;
|
|
44
|
-
const raw = [];
|
|
45
|
-
for (const line of lines) {
|
|
46
|
-
const hunk = HUNK_RE.exec(line);
|
|
47
|
-
if (hunk) {
|
|
48
|
-
if (startLine === null)
|
|
49
|
-
startLine = Number(hunk[1]);
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (ELISION_RE.test(line)) {
|
|
53
|
-
raw.push({ kind: "elision", text: line });
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (line.startsWith("- "))
|
|
57
|
-
raw.push({ kind: "remove", text: line.slice(2) });
|
|
58
|
-
else if (line.startsWith("+ "))
|
|
59
|
-
raw.push({ kind: "add", text: line.slice(2) });
|
|
60
|
-
else if (line === "-" || line === "+")
|
|
61
|
-
raw.push({ kind: line === "+" ? "add" : "remove", text: "" });
|
|
62
|
-
// Anything else (stray context / blank) is ignored: linesDiff never emits it.
|
|
63
|
-
}
|
|
64
|
-
const rows = numberAndPair(raw, startLine ?? 1, opts.anchored);
|
|
65
|
-
return { rows, startLine };
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Assign line numbers (anchored only) and compute word-level pairing. Mirrors
|
|
69
|
-
* claude-code's `numberDiffLines` + `processAdjacentLines`: a run of removes
|
|
70
|
-
* followed by a run of adds pairs index-wise; the line counter rewinds by the
|
|
71
|
-
* number of removes so the matching add reuses the same displayed number.
|
|
72
|
-
*/
|
|
73
|
-
function numberAndPair(raw, startLine, anchored) {
|
|
74
|
-
const out = [];
|
|
75
|
-
let i = 0;
|
|
76
|
-
let lineNo = startLine;
|
|
77
|
-
while (i < raw.length) {
|
|
78
|
-
const cur = raw[i];
|
|
79
|
-
if (cur.kind === "elision") {
|
|
80
|
-
out.push({ kind: "elision", text: cur.text, lineNo: null, words: null });
|
|
81
|
-
i++;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
if (cur.kind === "remove") {
|
|
85
|
-
// Collect the remove run, then the following add run.
|
|
86
|
-
const removes = [];
|
|
87
|
-
while (i < raw.length && raw[i].kind === "remove")
|
|
88
|
-
removes.push(raw[i++]);
|
|
89
|
-
const adds = [];
|
|
90
|
-
while (i < raw.length && raw[i].kind === "add")
|
|
91
|
-
adds.push(raw[i++]);
|
|
92
|
-
const removeBase = lineNo;
|
|
93
|
-
removes.forEach((r, k) => {
|
|
94
|
-
const paired = adds[k];
|
|
95
|
-
out.push({
|
|
96
|
-
kind: "remove",
|
|
97
|
-
text: r.text,
|
|
98
|
-
lineNo: anchored ? removeBase + k : null,
|
|
99
|
-
words: paired ? wordSegs(r.text, paired.text, "remove") : null,
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
// Rewind: removed lines don't exist in the new file — adds reuse the numbers.
|
|
103
|
-
adds.forEach((a, k) => {
|
|
104
|
-
const paired = removes[k];
|
|
105
|
-
out.push({
|
|
106
|
-
kind: "add",
|
|
107
|
-
text: a.text,
|
|
108
|
-
lineNo: anchored ? removeBase + k : null,
|
|
109
|
-
// wordSegs always takes (removeText, addText); here the add's pair is
|
|
110
|
-
// the remove at the same index.
|
|
111
|
-
words: paired ? wordSegs(paired.text, a.text, "add") : null,
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
lineNo = removeBase + Math.max(removes.length, adds.length);
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
// A lone add run (pure insertion, no preceding removes).
|
|
118
|
-
if (cur.kind === "add") {
|
|
119
|
-
while (i < raw.length && raw[i].kind === "add") {
|
|
120
|
-
const a = raw[i++];
|
|
121
|
-
out.push({ kind: "add", text: a.text, lineNo: anchored ? lineNo++ : null, words: null });
|
|
122
|
-
}
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
i++;
|
|
126
|
-
}
|
|
127
|
-
return out;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Word-level segments for one side of a pair. `side:"remove"` keeps common +
|
|
131
|
-
* removed words; `side:"add"` keeps common + added words. Returns null when the
|
|
132
|
-
* pair changed more than {@link CHANGE_THRESHOLD} of its total length (render
|
|
133
|
-
* whole-line instead).
|
|
134
|
-
*/
|
|
135
|
-
export function wordSegs(removeText, addText, side) {
|
|
136
|
-
const parts = diffWordsWithSpace(removeText, addText);
|
|
137
|
-
const total = removeText.length + addText.length;
|
|
138
|
-
const changedLen = parts.reduce((sum, p) => (p.added || p.removed ? sum + p.value.length : sum), 0);
|
|
139
|
-
if (total === 0 || changedLen / total > CHANGE_THRESHOLD)
|
|
140
|
-
return null;
|
|
141
|
-
const segs = [];
|
|
142
|
-
for (const p of parts) {
|
|
143
|
-
if (side === "remove") {
|
|
144
|
-
if (p.added)
|
|
145
|
-
continue;
|
|
146
|
-
segs.push({ text: p.value, changed: !!p.removed });
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
if (p.removed)
|
|
150
|
-
continue;
|
|
151
|
-
segs.push({ text: p.value, changed: !!p.added });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return segs;
|
|
155
|
-
}
|
|
156
|
-
//# sourceMappingURL=diff-model.js.map
|
package/dist/diff-model.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diff-model.js","sourceRoot":"","sources":["../src/diff-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* (5.8 / v13) Frame-coalescing scheduler.
|
|
3
|
-
*
|
|
4
|
-
* Streaming `assistant:delta` events arrive one-per-token (engine.ts emits a
|
|
5
|
-
* bump per stream chunk). Before v13 each one drove a full React re-render of
|
|
6
|
-
* the whole scrollback. The view-model now routes delta-driven re-renders
|
|
7
|
-
* through `schedule()` so at most ONE render happens per ~16 ms frame, while
|
|
8
|
-
* structural events (a finished message, a tool call/result, turn end) still
|
|
9
|
-
* flush immediately via the view-model's force-flush path (which `cancel()`s
|
|
10
|
-
* any pending frame first).
|
|
11
|
-
*
|
|
12
|
-
* The scheduler is injectable so tests run deterministically with no timers:
|
|
13
|
-
* inject {@link ManualFrameScheduler}, drive events, then `flush()` — the
|
|
14
|
-
* assertion is "N deltas → exactly one notification", which a real
|
|
15
|
-
* `setTimeout` clock can't express without flakiness.
|
|
16
|
-
*/
|
|
17
|
-
/** Opaque handle returned by {@link FrameScheduler.schedule}; pass it back to
|
|
18
|
-
* `cancel()`. Callers must not inspect it. */
|
|
19
|
-
export type FrameHandle = unknown;
|
|
20
|
-
export interface FrameScheduler {
|
|
21
|
-
/** Run `cb` on a later frame; returns a handle for {@link cancel}. */
|
|
22
|
-
schedule(cb: () => void): FrameHandle;
|
|
23
|
-
/** Cancel a scheduled `cb` if it has not run yet. Idempotent. */
|
|
24
|
-
cancel(handle: FrameHandle): void;
|
|
25
|
-
}
|
|
26
|
-
/** Default production scheduler: a single `setTimeout` per coalescing window. */
|
|
27
|
-
export declare const defaultFrameScheduler: FrameScheduler;
|
|
28
|
-
/**
|
|
29
|
-
* Deterministic scheduler for tests. `schedule()` enqueues a callback (no
|
|
30
|
-
* timer), `cancel()` removes it, `flush()` runs all queued callbacks in FIFO
|
|
31
|
-
* order and clears the queue. `pending` exposes the queue depth so a test can
|
|
32
|
-
* assert coalescing ("after N deltas, exactly one callback is queued").
|
|
33
|
-
*/
|
|
34
|
-
export declare class ManualFrameScheduler implements FrameScheduler {
|
|
35
|
-
private readonly queue;
|
|
36
|
-
private nextId;
|
|
37
|
-
schedule(cb: () => void): FrameHandle;
|
|
38
|
-
cancel(handle: FrameHandle): void;
|
|
39
|
-
/** Number of callbacks queued but not yet run or cancelled. */
|
|
40
|
-
get pending(): number;
|
|
41
|
-
/** Run every queued callback (FIFO) and clear the queue. */
|
|
42
|
-
flush(): void;
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=frame-scheduler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"frame-scheduler.d.ts","sourceRoot":"","sources":["../src/frame-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;+CAC+C;AAC/C,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC;AAElC,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,WAAW,CAAC;IACtC,iEAAiE;IACjE,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC;AAMD,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,EAAE,cAKnC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,MAAM,CAAK;IAEnB,QAAQ,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,WAAW;IAMrC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIjC,+DAA+D;IAC/D,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,4DAA4D;IAC5D,KAAK,IAAI,IAAI;CAKd"}
|
package/dist/frame-scheduler.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* (5.8 / v13) Frame-coalescing scheduler.
|
|
3
|
-
*
|
|
4
|
-
* Streaming `assistant:delta` events arrive one-per-token (engine.ts emits a
|
|
5
|
-
* bump per stream chunk). Before v13 each one drove a full React re-render of
|
|
6
|
-
* the whole scrollback. The view-model now routes delta-driven re-renders
|
|
7
|
-
* through `schedule()` so at most ONE render happens per ~16 ms frame, while
|
|
8
|
-
* structural events (a finished message, a tool call/result, turn end) still
|
|
9
|
-
* flush immediately via the view-model's force-flush path (which `cancel()`s
|
|
10
|
-
* any pending frame first).
|
|
11
|
-
*
|
|
12
|
-
* The scheduler is injectable so tests run deterministically with no timers:
|
|
13
|
-
* inject {@link ManualFrameScheduler}, drive events, then `flush()` — the
|
|
14
|
-
* assertion is "N deltas → exactly one notification", which a real
|
|
15
|
-
* `setTimeout` clock can't express without flakiness.
|
|
16
|
-
*/
|
|
17
|
-
/** ~1 frame at 60fps. One coalesced render per frame is imperceptible while
|
|
18
|
-
* capping re-renders during a fast token stream. */
|
|
19
|
-
const FRAME_MS = 16;
|
|
20
|
-
/** Default production scheduler: a single `setTimeout` per coalescing window. */
|
|
21
|
-
export const defaultFrameScheduler = {
|
|
22
|
-
schedule: (cb) => setTimeout(cb, FRAME_MS),
|
|
23
|
-
cancel: (handle) => {
|
|
24
|
-
if (handle !== undefined)
|
|
25
|
-
clearTimeout(handle);
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Deterministic scheduler for tests. `schedule()` enqueues a callback (no
|
|
30
|
-
* timer), `cancel()` removes it, `flush()` runs all queued callbacks in FIFO
|
|
31
|
-
* order and clears the queue. `pending` exposes the queue depth so a test can
|
|
32
|
-
* assert coalescing ("after N deltas, exactly one callback is queued").
|
|
33
|
-
*/
|
|
34
|
-
export class ManualFrameScheduler {
|
|
35
|
-
queue = new Map();
|
|
36
|
-
nextId = 1;
|
|
37
|
-
schedule(cb) {
|
|
38
|
-
const id = this.nextId++;
|
|
39
|
-
this.queue.set(id, cb);
|
|
40
|
-
return id;
|
|
41
|
-
}
|
|
42
|
-
cancel(handle) {
|
|
43
|
-
if (typeof handle === "number")
|
|
44
|
-
this.queue.delete(handle);
|
|
45
|
-
}
|
|
46
|
-
/** Number of callbacks queued but not yet run or cancelled. */
|
|
47
|
-
get pending() {
|
|
48
|
-
return this.queue.size;
|
|
49
|
-
}
|
|
50
|
-
/** Run every queued callback (FIFO) and clear the queue. */
|
|
51
|
-
flush() {
|
|
52
|
-
const callbacks = [...this.queue.values()];
|
|
53
|
-
this.queue.clear();
|
|
54
|
-
for (const cb of callbacks)
|
|
55
|
-
cb();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=frame-scheduler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"frame-scheduler.js","sourceRoot":"","sources":["../src/frame-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAaH;qDACqD;AACrD,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,iFAAiF;AACjF,MAAM,CAAC,MAAM,qBAAqB,GAAmB;IACnD,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC;IAC1C,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,IAAI,MAAM,KAAK,SAAS;YAAE,YAAY,CAAC,MAAuC,CAAC,CAAC;IAClF,CAAC;CACF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IACd,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC/C,MAAM,GAAG,CAAC,CAAC;IAEnB,QAAQ,CAAC,EAAc;QACrB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,MAAmB;QACxB,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5D,CAAC;IAED,+DAA+D;IAC/D,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,4DAA4D;IAC5D,KAAK;QACH,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,KAAK,MAAM,EAAE,IAAI,SAAS;YAAE,EAAE,EAAE,CAAC;IACnC,CAAC;CACF"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { Theme } from "./theme.js";
|
|
2
|
-
/** Stable highlight scopes we color. Everything else → `"plain"` (no color). */
|
|
3
|
-
export type HlScope = "plain" | "keyword" | "string" | "comment" | "number" | "function" | "type" | "literal" | "attr";
|
|
4
|
-
export interface Segment {
|
|
5
|
-
text: string;
|
|
6
|
-
scope: HlScope;
|
|
7
|
-
}
|
|
8
|
-
/** scope → theme color role (used by views to pick the `<Text color>`). */
|
|
9
|
-
export declare const SCOPE_TO_THEME: Record<HlScope, keyof Theme | undefined>;
|
|
10
|
-
/** Resolve a user-supplied language label to a registered grammar, or null. */
|
|
11
|
-
export declare function resolveLanguage(lang: string | undefined): string | null;
|
|
12
|
-
/**
|
|
13
|
-
* Highlight `code` as `lang` into themed segments. Unknown/absent language or
|
|
14
|
-
* any highlighter error → a single `"plain"` segment with the original code
|
|
15
|
-
* (callers render it as plain text).
|
|
16
|
-
*/
|
|
17
|
-
export declare function highlightToSegments(code: string, lang: string | undefined): Segment[];
|
|
18
|
-
//# sourceMappingURL=highlight-to-segments.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"highlight-to-segments.d.ts","sourceRoot":"","sources":["../src/highlight-to-segments.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AA4ExC,gFAAgF;AAChF,MAAM,MAAM,OAAO,GACf,OAAO,GACP,SAAS,GACT,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,UAAU,GACV,MAAM,GACN,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AA6CD,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,SAAS,CAUnE,CAAC;AAgBF,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAMvE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,EAAE,CAWrF"}
|