@elliotsystems/eai 0.1.2 → 0.1.4
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 +10 -5
- package/bin/eai +53 -3
- package/config/opencode.json +4 -0
- package/config/themes/elliot.json +105 -0
- package/config/tui.json +9 -0
- package/lib/resolve.js +44 -12
- package/lib/setup.js +231 -0
- package/lib/stage.js +116 -0
- package/package.json +8 -10
- package/plugin/opencode-plugin/README.md +64 -0
- package/plugin/opencode-plugin/package.json +32 -0
- package/plugin/opencode-plugin/src/classifier.ts +238 -0
- package/plugin/opencode-plugin/src/elliot-auth.ts +133 -0
- package/plugin/opencode-plugin/src/identity.ts +69 -0
- package/plugin/opencode-plugin/src/index.ts +211 -0
- package/plugin/opencode-plugin/src/mcp-keys.ts +30 -0
- package/plugin/opencode-plugin/src/policy.ts +122 -0
- package/plugin/opencode-plugin/src/proxy-provider.ts +96 -0
- package/plugin/opencode-plugin/src/scope.ts +78 -0
- package/plugin/opencode-plugin/src/tui/api.ts +117 -0
- package/plugin/opencode-plugin/src/tui/format.ts +73 -0
- package/plugin/opencode-plugin/src/tui/home.tsx +88 -0
- package/plugin/opencode-plugin/src/tui/host.d.ts +95 -0
- package/plugin/opencode-plugin/src/tui/index.tsx +99 -0
- package/plugin/opencode-plugin/src/tui/knowledge.ts +243 -0
- package/plugin/opencode-plugin/src/tui/prompt.tsx +62 -0
- package/plugin/opencode-plugin/src/tui/sidebar.tsx +184 -0
- package/plugin/opencode-plugin/src/tui/wordmark.tsx +109 -0
- package/plugin/opencode-plugin/themes/elliot.json +105 -0
- package/plugin/opencode-plugin/tsconfig.json +19 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Elliot knowledge panel — `sidebar_content`, plus Elliot's identity in
|
|
3
|
+
* `sidebar_title` and `sidebar_footer`.
|
|
4
|
+
*
|
|
5
|
+
* It shows only what nothing else in the sidebar shows. Upstream's built-in
|
|
6
|
+
* sections already list MCP servers, LSP clients, todos and changed files, so
|
|
7
|
+
* restating any of them here would be exactly the duplication this redesign is
|
|
8
|
+
* removing. What is left — and what no stock sidebar can know — is the retrieval
|
|
9
|
+
* scope in force and the sources Elliot actually cited in this session.
|
|
10
|
+
*
|
|
11
|
+
* Knowledge health therefore earns a row only when it is NOT healthy. A problem
|
|
12
|
+
* explains a bad answer and is worth the space; "working normally" is already
|
|
13
|
+
* visible in the MCP section and is not.
|
|
14
|
+
*/
|
|
15
|
+
import { For, Show } from "solid-js"
|
|
16
|
+
|
|
17
|
+
import type { SessionSlotProps, TuiPluginApi } from "./api.js"
|
|
18
|
+
import {
|
|
19
|
+
collectKnowledgeResults,
|
|
20
|
+
distinctCitations,
|
|
21
|
+
elliotServerNames,
|
|
22
|
+
knowledgeConnection,
|
|
23
|
+
type Citation,
|
|
24
|
+
type KnowledgeResult,
|
|
25
|
+
} from "./knowledge.js"
|
|
26
|
+
|
|
27
|
+
/** A height-bounded panel: past this, rows push the built-in sections off. */
|
|
28
|
+
const MAX_CITATIONS = 6
|
|
29
|
+
|
|
30
|
+
/** A small-caps-style section label, matching upstream's sidebar rhythm. */
|
|
31
|
+
function Label(props: { api: TuiPluginApi; children: string }) {
|
|
32
|
+
return (
|
|
33
|
+
<text fg={props.api.theme.current.border} selectable={false}>
|
|
34
|
+
{props.children}
|
|
35
|
+
</text>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Every knowledge lookup in this session.
|
|
41
|
+
*
|
|
42
|
+
* Reads the transcript rather than calling the backend — see `knowledge.ts` for
|
|
43
|
+
* why a fetch here would violate the no-second-credential-path rule.
|
|
44
|
+
*/
|
|
45
|
+
function resultsFor(api: TuiPluginApi, sessionID: string): KnowledgeResult[] {
|
|
46
|
+
const servers = elliotServerNames(api.state.mcp())
|
|
47
|
+
if (servers.length === 0) return []
|
|
48
|
+
|
|
49
|
+
const parts = api.state.session
|
|
50
|
+
.messages(sessionID)
|
|
51
|
+
.flatMap((message) => [...api.state.part(message.id)])
|
|
52
|
+
return collectKnowledgeResults(parts, servers)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The scope retrieval actually ran under.
|
|
57
|
+
*
|
|
58
|
+
* The backend echoes `repo_scope` in its envelope, so the most recent lookup is
|
|
59
|
+
* authoritative — that is the scope Elliot *used*, not the one we assume from
|
|
60
|
+
* the worktree. Falling back to the branch keeps the row useful before the first
|
|
61
|
+
* lookup, and a missing scope is reported as tenant-wide rather than left blank,
|
|
62
|
+
* because "unscoped" is a real and meaningful state.
|
|
63
|
+
*/
|
|
64
|
+
function scopeLabel(results: readonly KnowledgeResult[]): string | undefined {
|
|
65
|
+
for (const result of [...results].reverse()) {
|
|
66
|
+
if (result.repoScope) return result.repoScope
|
|
67
|
+
}
|
|
68
|
+
return undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function CitationRow(props: { api: TuiPluginApi; citation: Citation }) {
|
|
72
|
+
const theme = props.api.theme.current
|
|
73
|
+
return (
|
|
74
|
+
<box flexDirection="row" gap={1}>
|
|
75
|
+
<text fg={theme.textMuted} selectable={true}>
|
|
76
|
+
{props.citation.path}
|
|
77
|
+
</text>
|
|
78
|
+
<Show when={props.citation.symbol}>
|
|
79
|
+
<text fg={theme.border} selectable={false}>
|
|
80
|
+
{props.citation.symbol}
|
|
81
|
+
</text>
|
|
82
|
+
</Show>
|
|
83
|
+
</box>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** The one row that appears only on trouble. */
|
|
88
|
+
function Trouble(props: { api: TuiPluginApi }) {
|
|
89
|
+
const theme = props.api.theme.current
|
|
90
|
+
const connection = () => knowledgeConnection(props.api.state.mcp())
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Show when={connection().status === "failed" || connection().status === undefined}>
|
|
94
|
+
<box flexDirection="row" gap={1}>
|
|
95
|
+
<text fg={connection().status === "failed" ? theme.error : theme.warning} selectable={false}>
|
|
96
|
+
!
|
|
97
|
+
</text>
|
|
98
|
+
<text fg={theme.textMuted} selectable={false}>
|
|
99
|
+
{connection().status === "failed"
|
|
100
|
+
? "knowledge unreachable — answers are unsourced"
|
|
101
|
+
: "no knowledge server configured"}
|
|
102
|
+
</text>
|
|
103
|
+
</box>
|
|
104
|
+
</Show>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function SidebarContent(props: { api: TuiPluginApi; slot: SessionSlotProps }) {
|
|
109
|
+
const theme = props.api.theme.current
|
|
110
|
+
const results = () => resultsFor(props.api, props.slot.session_id)
|
|
111
|
+
const scope = () => scopeLabel(results())
|
|
112
|
+
const citations = () => distinctCitations(results(), MAX_CITATIONS)
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<box gap={1}>
|
|
116
|
+
<box>
|
|
117
|
+
<Label api={props.api}>KNOWLEDGE</Label>
|
|
118
|
+
<Trouble api={props.api} />
|
|
119
|
+
<Show
|
|
120
|
+
when={scope()}
|
|
121
|
+
fallback={
|
|
122
|
+
<text fg={theme.textMuted} selectable={false}>
|
|
123
|
+
organisation-wide
|
|
124
|
+
</text>
|
|
125
|
+
}
|
|
126
|
+
>
|
|
127
|
+
<text fg={theme.text} selectable={true}>
|
|
128
|
+
{scope()}
|
|
129
|
+
</text>
|
|
130
|
+
</Show>
|
|
131
|
+
</box>
|
|
132
|
+
|
|
133
|
+
<Show when={citations().length > 0}>
|
|
134
|
+
<box>
|
|
135
|
+
<Label api={props.api}>SOURCES CITED</Label>
|
|
136
|
+
<For each={citations()}>
|
|
137
|
+
{(citation) => <CitationRow api={props.api} citation={citation} />}
|
|
138
|
+
</For>
|
|
139
|
+
</box>
|
|
140
|
+
</Show>
|
|
141
|
+
</box>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The session title, with Elliot's mark ahead of it.
|
|
147
|
+
*
|
|
148
|
+
* `sidebar_title` is `single_winner`, so this replaces upstream's title block
|
|
149
|
+
* rather than stacking with it — which is why the title itself is reproduced
|
|
150
|
+
* here instead of only the branding.
|
|
151
|
+
*/
|
|
152
|
+
export function SidebarTitle(props: { api: TuiPluginApi; slot: SessionSlotProps & { title: string } }) {
|
|
153
|
+
const theme = props.api.theme.current
|
|
154
|
+
return (
|
|
155
|
+
<box paddingRight={1}>
|
|
156
|
+
<box flexDirection="row" gap={1}>
|
|
157
|
+
<text fg={theme.primary} selectable={false}>
|
|
158
|
+
●
|
|
159
|
+
</text>
|
|
160
|
+
<text fg={theme.text} selectable={true}>
|
|
161
|
+
{props.slot.title}
|
|
162
|
+
</text>
|
|
163
|
+
</box>
|
|
164
|
+
</box>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Replaces upstream's "OpenCode <version>" line; the build is Elliot's. */
|
|
169
|
+
export function SidebarFooter(props: { api: TuiPluginApi }) {
|
|
170
|
+
const theme = props.api.theme.current
|
|
171
|
+
return (
|
|
172
|
+
<box flexDirection="row" gap={1}>
|
|
173
|
+
<text fg={theme.primary} selectable={false}>
|
|
174
|
+
●
|
|
175
|
+
</text>
|
|
176
|
+
<text fg={theme.text} selectable={false}>
|
|
177
|
+
Elliot AI
|
|
178
|
+
</text>
|
|
179
|
+
<text fg={theme.border} selectable={false}>
|
|
180
|
+
{props.api.app.version}
|
|
181
|
+
</text>
|
|
182
|
+
</box>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ELLIOT AI wordmark, filling `home_logo` (declared `mode="replace"`, so it
|
|
3
|
+
* supplants upstream's `<Logo/>`).
|
|
4
|
+
*
|
|
5
|
+
* Colour comes from the active theme, never from literals, so `themes/elliot.json`
|
|
6
|
+
* stays the single source of truth and the mark degrades correctly under another
|
|
7
|
+
* theme.
|
|
8
|
+
*/
|
|
9
|
+
import { For } from "solid-js"
|
|
10
|
+
import { RGBA, TextAttributes } from "@opentui/core"
|
|
11
|
+
|
|
12
|
+
import type { TuiPluginApi } from "./api.js"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* ELLIOT / AI, transcribed from the design's glyph grid.
|
|
16
|
+
*
|
|
17
|
+
* 4-column glyphs separated by one space, except `I` and `T` which are 3 — that
|
|
18
|
+
* is the design's own metric. `left` is 27 columns, `right` is 8.
|
|
19
|
+
*
|
|
20
|
+
* `_` and `^` are the host's shading marks (`packages/tui/src/logo.ts`): a cell
|
|
21
|
+
* painted on a tinted background, and `▀` on that same tint.
|
|
22
|
+
*/
|
|
23
|
+
const WORDMARK = {
|
|
24
|
+
left: [
|
|
25
|
+
"█▀▀▀ █ █ ▀▀▀ █▀▀█ ▀▀▀",
|
|
26
|
+
"█^^^ █ █ █ █__█ █ ",
|
|
27
|
+
"▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀ ▀▀▀▀ ▀ ",
|
|
28
|
+
],
|
|
29
|
+
right: ["█▀▀█ ▀▀▀", "█^^█ █ ", "▀ ▀ ▀▀▀"],
|
|
30
|
+
} as const
|
|
31
|
+
|
|
32
|
+
/** The design sets ELLIOT and AI two columns apart, not one. */
|
|
33
|
+
const WORDMARK_GAP = 2
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Tint a shadow from the theme, mirroring the host's `tint(background, fg, 0.25)`
|
|
37
|
+
* so a plugin-rendered wordmark shades identically to a host-rendered one.
|
|
38
|
+
* Reimplemented rather than imported because the host's theme context is not a
|
|
39
|
+
* shared module.
|
|
40
|
+
*
|
|
41
|
+
* It must return a real `RGBA`, not a matching plain object. The renderer hands
|
|
42
|
+
* colours to opentui's FFI (`textBufferSetDefaultBg`), which needs the
|
|
43
|
+
* Float32Array an `RGBA` carries; a structurally identical literal reaches the
|
|
44
|
+
* boundary and dies with "Expected ArrayBufferView but received Cell to a
|
|
45
|
+
* pointer", taking the whole TUI down. That crash was latent for as long as this
|
|
46
|
+
* plugin never loaded -- fixing the loader is what surfaced it.
|
|
47
|
+
*/
|
|
48
|
+
function shadowOf(background: RGBA, fg: RGBA): RGBA {
|
|
49
|
+
const mix = (a: number, b: number) => a + (b - a) * 0.25
|
|
50
|
+
return RGBA.fromValues(
|
|
51
|
+
mix(background.r, fg.r),
|
|
52
|
+
mix(background.g, fg.g),
|
|
53
|
+
mix(background.b, fg.b),
|
|
54
|
+
background.a ?? 1,
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function Glyphs(props: { line: string; fg: RGBA; shadow: RGBA; bold: boolean }) {
|
|
59
|
+
const attrs = props.bold ? TextAttributes.BOLD : undefined
|
|
60
|
+
return (
|
|
61
|
+
<box flexDirection="row">
|
|
62
|
+
{Array.from(props.line).map((char) => {
|
|
63
|
+
if (char === "_")
|
|
64
|
+
return (
|
|
65
|
+
<text fg={props.fg} bg={props.shadow} attributes={attrs} selectable={false}>
|
|
66
|
+
{" "}
|
|
67
|
+
</text>
|
|
68
|
+
)
|
|
69
|
+
if (char === "^")
|
|
70
|
+
return (
|
|
71
|
+
<text fg={props.fg} bg={props.shadow} attributes={attrs} selectable={false}>
|
|
72
|
+
▀
|
|
73
|
+
</text>
|
|
74
|
+
)
|
|
75
|
+
return (
|
|
76
|
+
<text fg={props.fg} attributes={attrs} selectable={false}>
|
|
77
|
+
{char}
|
|
78
|
+
</text>
|
|
79
|
+
)
|
|
80
|
+
})}
|
|
81
|
+
</box>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function Wordmark(props: { api: TuiPluginApi }) {
|
|
86
|
+
const theme = props.api.theme.current
|
|
87
|
+
return (
|
|
88
|
+
<box>
|
|
89
|
+
<For each={WORDMARK.left}>
|
|
90
|
+
{(line, index) => (
|
|
91
|
+
<box flexDirection="row" gap={WORDMARK_GAP}>
|
|
92
|
+
<Glyphs
|
|
93
|
+
line={line}
|
|
94
|
+
fg={theme.textMuted}
|
|
95
|
+
shadow={shadowOf(theme.background, theme.textMuted)}
|
|
96
|
+
bold={false}
|
|
97
|
+
/>
|
|
98
|
+
<Glyphs
|
|
99
|
+
line={WORDMARK.right[index()] ?? ""}
|
|
100
|
+
fg={theme.primary}
|
|
101
|
+
shadow={shadowOf(theme.background, theme.primary)}
|
|
102
|
+
bold={true}
|
|
103
|
+
/>
|
|
104
|
+
</box>
|
|
105
|
+
)}
|
|
106
|
+
</For>
|
|
107
|
+
</box>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://opencode.ai/theme.json",
|
|
3
|
+
"defs": {
|
|
4
|
+
"brandOrange": "#FF6600",
|
|
5
|
+
"accentOrange": "#FF7A2E",
|
|
6
|
+
"accentOrangeLit": "#FF9354",
|
|
7
|
+
"accentOrangeSoft": "#FFB07A",
|
|
8
|
+
"accentOrangeDeep": "#C2410C",
|
|
9
|
+
"accentOrangeInk": "#7C2D12",
|
|
10
|
+
|
|
11
|
+
"ground": "#0B0C0E",
|
|
12
|
+
"panel": "#121315",
|
|
13
|
+
"elevated": "#191B1D",
|
|
14
|
+
"elevated2": "#212325",
|
|
15
|
+
"border": "#262829",
|
|
16
|
+
"borderSoft": "#1C1E20",
|
|
17
|
+
|
|
18
|
+
"text": "#F5F6F8",
|
|
19
|
+
"textFaint": "#A0A3A8",
|
|
20
|
+
"textDim": "#8E9297",
|
|
21
|
+
"textGhost": "#3A3D3F",
|
|
22
|
+
|
|
23
|
+
"success": "#5DD89B",
|
|
24
|
+
"warning": "#E8C33A",
|
|
25
|
+
"error": "#F7768E",
|
|
26
|
+
"teal": "#5EEAD4",
|
|
27
|
+
|
|
28
|
+
"lightGround": "#FFFFFF",
|
|
29
|
+
"lightPanel": "#FAFAFA",
|
|
30
|
+
"lightElevated": "#F2F2F4",
|
|
31
|
+
"lightElevated2": "#E9E9EC",
|
|
32
|
+
"lightBorder": "#D9D9DE",
|
|
33
|
+
"lightBorderSoft": "#EDEDF0",
|
|
34
|
+
"lightText": "#0B0C0E",
|
|
35
|
+
"lightTextDim": "#6B6E73",
|
|
36
|
+
"lightTextFaint": "#8E9297",
|
|
37
|
+
"lightTextGhost": "#C4C6CA",
|
|
38
|
+
"lightSuccess": "#1B7F4F",
|
|
39
|
+
"lightWarning": "#8A6D0B",
|
|
40
|
+
"lightError": "#C2334C",
|
|
41
|
+
"lightTeal": "#0F766E"
|
|
42
|
+
},
|
|
43
|
+
"theme": {
|
|
44
|
+
"primary": { "dark": "brandOrange", "light": "brandOrange" },
|
|
45
|
+
"accent": { "dark": "accentOrange", "light": "accentOrangeDeep" },
|
|
46
|
+
"secondary": { "dark": "teal", "light": "lightTeal" },
|
|
47
|
+
"info": { "dark": "accentOrangeSoft", "light": "accentOrangeDeep" },
|
|
48
|
+
|
|
49
|
+
"error": { "dark": "error", "light": "lightError" },
|
|
50
|
+
"warning": { "dark": "warning", "light": "lightWarning" },
|
|
51
|
+
"success": { "dark": "success", "light": "lightSuccess" },
|
|
52
|
+
|
|
53
|
+
"text": { "dark": "text", "light": "lightText" },
|
|
54
|
+
"textMuted": { "dark": "textDim", "light": "lightTextDim" },
|
|
55
|
+
|
|
56
|
+
"selectedListItemText": { "dark": "ground", "light": "lightGround" },
|
|
57
|
+
|
|
58
|
+
"background": { "dark": "ground", "light": "lightGround" },
|
|
59
|
+
"backgroundPanel": { "dark": "panel", "light": "lightPanel" },
|
|
60
|
+
"backgroundElement": { "dark": "elevated", "light": "lightElevated" },
|
|
61
|
+
"backgroundMenu": { "dark": "elevated2", "light": "lightElevated2" },
|
|
62
|
+
|
|
63
|
+
"border": { "dark": "border", "light": "lightBorder" },
|
|
64
|
+
"borderActive": { "dark": "accentOrange", "light": "accentOrangeDeep" },
|
|
65
|
+
"borderSubtle": { "dark": "borderSoft", "light": "lightBorderSoft" },
|
|
66
|
+
|
|
67
|
+
"diffAdded": { "dark": "success", "light": "lightSuccess" },
|
|
68
|
+
"diffRemoved": { "dark": "error", "light": "lightError" },
|
|
69
|
+
"diffContext": { "dark": "textDim", "light": "lightTextDim" },
|
|
70
|
+
"diffHunkHeader": { "dark": "textFaint", "light": "lightTextFaint" },
|
|
71
|
+
"diffHighlightAdded": { "dark": "#8DE8B8", "light": "#12603B" },
|
|
72
|
+
"diffHighlightRemoved": { "dark": "#FF9BAC", "light": "#A62740" },
|
|
73
|
+
"diffAddedBg": { "dark": "#0F2018", "light": "#E4F5EB" },
|
|
74
|
+
"diffRemovedBg": { "dark": "#241318", "light": "#FBE4E9" },
|
|
75
|
+
"diffContextBg": { "dark": "panel", "light": "lightPanel" },
|
|
76
|
+
"diffLineNumber": { "dark": "textGhost", "light": "lightTextGhost" },
|
|
77
|
+
"diffAddedLineNumberBg": { "dark": "#0C1913", "light": "#D6EDDF" },
|
|
78
|
+
"diffRemovedLineNumberBg": { "dark": "#1D0F13", "light": "#F6D8DF" },
|
|
79
|
+
|
|
80
|
+
"markdownText": { "dark": "text", "light": "lightText" },
|
|
81
|
+
"markdownHeading": { "dark": "brandOrange", "light": "accentOrangeDeep" },
|
|
82
|
+
"markdownLink": { "dark": "accentOrange", "light": "accentOrangeDeep" },
|
|
83
|
+
"markdownLinkText": { "dark": "accentOrangeSoft", "light": "accentOrangeDeep" },
|
|
84
|
+
"markdownCode": { "dark": "accentOrangeSoft", "light": "accentOrangeDeep" },
|
|
85
|
+
"markdownBlockQuote": { "dark": "textFaint", "light": "lightTextFaint" },
|
|
86
|
+
"markdownEmph": { "dark": "accentOrangeLit", "light": "accentOrangeDeep" },
|
|
87
|
+
"markdownStrong": { "dark": "accentOrange", "light": "accentOrangeDeep" },
|
|
88
|
+
"markdownHorizontalRule": { "dark": "borderSoft", "light": "lightBorderSoft" },
|
|
89
|
+
"markdownListItem": { "dark": "accentOrange", "light": "accentOrangeDeep" },
|
|
90
|
+
"markdownListEnumeration": { "dark": "accentOrangeLit", "light": "accentOrangeDeep" },
|
|
91
|
+
"markdownImage": { "dark": "accentOrange", "light": "accentOrangeDeep" },
|
|
92
|
+
"markdownImageText": { "dark": "textFaint", "light": "lightTextFaint" },
|
|
93
|
+
"markdownCodeBlock": { "dark": "text", "light": "lightText" },
|
|
94
|
+
|
|
95
|
+
"syntaxComment": { "dark": "textGhost", "light": "lightTextGhost" },
|
|
96
|
+
"syntaxKeyword": { "dark": "accentOrange", "light": "accentOrangeDeep" },
|
|
97
|
+
"syntaxFunction": { "dark": "accentOrangeLit", "light": "accentOrangeInk" },
|
|
98
|
+
"syntaxVariable": { "dark": "text", "light": "lightText" },
|
|
99
|
+
"syntaxString": { "dark": "success", "light": "lightSuccess" },
|
|
100
|
+
"syntaxNumber": { "dark": "accentOrangeSoft", "light": "accentOrangeDeep" },
|
|
101
|
+
"syntaxType": { "dark": "teal", "light": "lightTeal" },
|
|
102
|
+
"syntaxOperator": { "dark": "textFaint", "light": "lightTextFaint" },
|
|
103
|
+
"syntaxPunctuation": { "dark": "textDim", "light": "lightTextDim" }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2022"
|
|
7
|
+
],
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"jsx": "preserve"
|
|
14
|
+
},
|
|
15
|
+
"include": [
|
|
16
|
+
"src/**/*",
|
|
17
|
+
"test/**/*"
|
|
18
|
+
]
|
|
19
|
+
}
|