decorated-pi 0.3.0 → 0.4.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/README.md +58 -34
- package/extensions/file-times.ts +60 -2
- package/extensions/guidance.ts +5 -3
- package/extensions/index.ts +2 -0
- package/extensions/io.ts +210 -29
- package/extensions/lsp/client.ts +181 -428
- package/extensions/lsp/env.ts +45 -12
- package/extensions/lsp/format.ts +102 -237
- package/extensions/lsp/index.ts +8 -11
- package/extensions/lsp/manager.ts +249 -0
- package/extensions/lsp/prompt.ts +3 -42
- package/extensions/lsp/protocol.ts +219 -0
- package/extensions/lsp/servers.ts +80 -160
- package/extensions/lsp/tools.ts +160 -553
- package/extensions/lsp/types.ts +42 -0
- package/extensions/mcp/builtin.ts +126 -0
- package/extensions/mcp/client.ts +106 -0
- package/extensions/mcp/index.ts +123 -0
- package/extensions/patch.ts +291 -73
- package/extensions/providers/ark-coding.ts +2 -0
- package/extensions/safety/detect.ts +20 -744
- package/extensions/safety/entropy.ts +226 -0
- package/extensions/safety/index.ts +1 -93
- package/extensions/safety/patterns.ts +155 -0
- package/extensions/safety/types.ts +50 -0
- package/extensions/settings.ts +8 -0
- package/extensions/slash.ts +161 -7
- package/extensions/smart-at.ts +5 -5
- package/extensions/subdir-agents.ts +43 -13
- package/package.json +2 -3
- package/tsconfig.json +16 -0
- package/extensions/lsp/server-manager.ts +0 -309
- package/extensions/lsp/trust.ts +0 -45
package/extensions/settings.ts
CHANGED
|
@@ -25,11 +25,17 @@ export interface ProviderCache {
|
|
|
25
25
|
models: ProviderModelEntry[];
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export interface McpServerEntry {
|
|
29
|
+
url: string;
|
|
30
|
+
enabled?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
export interface ModuleSettings {
|
|
29
34
|
safety?: boolean;
|
|
30
35
|
lsp?: boolean;
|
|
31
36
|
"smart-at"?: boolean;
|
|
32
37
|
patch?: boolean;
|
|
38
|
+
mcp?: boolean;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
export interface DecoratedPiConfig {
|
|
@@ -37,6 +43,7 @@ export interface DecoratedPiConfig {
|
|
|
37
43
|
compactModelKey?: string | null;
|
|
38
44
|
providers?: Record<string, ProviderCache>;
|
|
39
45
|
modules?: ModuleSettings;
|
|
46
|
+
mcpServers?: Record<string, McpServerEntry>;
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
export function loadConfig(): DecoratedPiConfig {
|
|
@@ -113,6 +120,7 @@ const DEFAULT_MODULES: Required<ModuleSettings> = {
|
|
|
113
120
|
lsp: true,
|
|
114
121
|
"smart-at": true,
|
|
115
122
|
patch: true,
|
|
123
|
+
mcp: true,
|
|
116
124
|
};
|
|
117
125
|
|
|
118
126
|
export function isModuleEnabled(name: keyof ModuleSettings): boolean {
|
package/extensions/slash.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
import type { ExtensionAPI, ExtensionContext, Theme as PiTheme } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import { ModelPickerComponent } from "./model-integration.js";
|
|
11
11
|
import { getAllModuleSettings, setModuleEnabled, type ModuleSettings } from "./settings.js";
|
|
12
|
-
import {
|
|
12
|
+
import { getMcpStatus } from "./mcp/index.js";
|
|
13
|
+
import { Container, SettingsList, Spacer, Text, type TUI, type SettingsListTheme, type Component, getKeybindings } from "@earendil-works/pi-tui";
|
|
13
14
|
|
|
14
15
|
// ─── Border component (matches native DynamicBorder) ────────────────────────
|
|
15
16
|
|
|
@@ -60,17 +61,19 @@ function setupDpModelCommand(pi: ExtensionAPI) {
|
|
|
60
61
|
// ─── /dp-settings ──────────────────────────────────────────────────────────
|
|
61
62
|
|
|
62
63
|
const MODULE_LABELS: Record<keyof ModuleSettings, string> = {
|
|
63
|
-
patch: "
|
|
64
|
-
safety: "
|
|
65
|
-
lsp: "LSP
|
|
66
|
-
"smart-at": "
|
|
64
|
+
patch: "patch",
|
|
65
|
+
safety: "Secret Redaction",
|
|
66
|
+
lsp: "LSP",
|
|
67
|
+
"smart-at": "@ overload",
|
|
68
|
+
mcp: "MCP",
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
const MODULE_DESCS: Record<keyof ModuleSettings, string> = {
|
|
70
72
|
patch: "Replace edit/write with patch tool (old_str/new_str replacement + overwrite)",
|
|
71
|
-
safety: "
|
|
73
|
+
safety: "Redact secrets from read / bash output before they enter model context",
|
|
72
74
|
lsp: "Language server diagnostics, hover, definition, references, symbols, rename",
|
|
73
75
|
"smart-at": "Project-aware file search replacing default autocomplete",
|
|
76
|
+
mcp: "MCP client for context7 and exa (zero-config)",
|
|
74
77
|
};
|
|
75
78
|
|
|
76
79
|
class ModuleSettingsComponent extends Container {
|
|
@@ -119,7 +122,7 @@ function setupDpSettingsCommand(pi: ExtensionAPI) {
|
|
|
119
122
|
(tui, theme, _kb, done) =>
|
|
120
123
|
new ModuleSettingsComponent(tui, theme, () => done(undefined))
|
|
121
124
|
);
|
|
122
|
-
ctx.ui.notify("Module settings updated. /reload to apply.", "
|
|
125
|
+
ctx.ui.notify("Module settings updated. /reload to apply.", "warning");
|
|
123
126
|
return;
|
|
124
127
|
}
|
|
125
128
|
ctx.ui.notify("dp-settings requires interactive mode.", "warning");
|
|
@@ -127,6 +130,156 @@ function setupDpSettingsCommand(pi: ExtensionAPI) {
|
|
|
127
130
|
});
|
|
128
131
|
}
|
|
129
132
|
|
|
133
|
+
// ─── /mcp ──────────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
class McpStatusComponent extends Container {
|
|
136
|
+
private textComponent: Text;
|
|
137
|
+
private tui: TUI;
|
|
138
|
+
private theme: PiTheme;
|
|
139
|
+
private done: () => void;
|
|
140
|
+
private timer: ReturnType<typeof setInterval> | null = null;
|
|
141
|
+
|
|
142
|
+
constructor(tui: TUI, theme: PiTheme, onDone: () => void) {
|
|
143
|
+
super();
|
|
144
|
+
this.tui = tui;
|
|
145
|
+
this.theme = theme;
|
|
146
|
+
this.done = onDone;
|
|
147
|
+
|
|
148
|
+
this.addChild(new DynamicBorder(theme));
|
|
149
|
+
this.addChild(new Spacer(1));
|
|
150
|
+
|
|
151
|
+
this.textComponent = new Text("", 1, 0);
|
|
152
|
+
this.addChild(this.textComponent);
|
|
153
|
+
|
|
154
|
+
this.addChild(new Spacer(1));
|
|
155
|
+
this.addChild(new Text(this.theme.fg("dim", "Press q to close."), 1, 0));
|
|
156
|
+
this.addChild(new Spacer(1));
|
|
157
|
+
this.addChild(new DynamicBorder(theme));
|
|
158
|
+
|
|
159
|
+
this.refresh();
|
|
160
|
+
|
|
161
|
+
this.timer = setInterval(() => {
|
|
162
|
+
this.refresh();
|
|
163
|
+
const allSettled = getMcpStatus().every((s) => s.state !== "connecting");
|
|
164
|
+
if (allSettled && this.timer) {
|
|
165
|
+
clearInterval(this.timer);
|
|
166
|
+
this.timer = null;
|
|
167
|
+
}
|
|
168
|
+
}, 500);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private refresh() {
|
|
172
|
+
const servers = getMcpStatus();
|
|
173
|
+
|
|
174
|
+
if (servers.length === 0) {
|
|
175
|
+
this.textComponent.setText("No MCP servers configured.");
|
|
176
|
+
this.tui.requestRender();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const connected = servers.filter((s) => s.state === "connected");
|
|
181
|
+
const connecting = servers.filter((s) => s.state === "connecting");
|
|
182
|
+
const failed = servers.filter((s) => s.state === "failed");
|
|
183
|
+
|
|
184
|
+
const lines: string[] = [
|
|
185
|
+
`MCP servers (${servers.length}):`,
|
|
186
|
+
"",
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
for (const s of connected) {
|
|
190
|
+
lines.push(this.theme.fg("accent", `• ${s.name}`) + ` (${s.source})`);
|
|
191
|
+
lines.push(` URL: ${s.url}`);
|
|
192
|
+
lines.push(` Tools: ${s.toolCount}`);
|
|
193
|
+
for (const tool of s.tools) {
|
|
194
|
+
const desc = tool.description ? ` — ${tool.description.slice(0, 60)}` : "";
|
|
195
|
+
lines.push(` - ${tool.name}${desc}`);
|
|
196
|
+
}
|
|
197
|
+
lines.push("");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (const s of connecting) {
|
|
201
|
+
lines.push(this.theme.fg("accent", `• ${s.name}`) + ` (${s.source})`);
|
|
202
|
+
lines.push(` URL: ${s.url}`);
|
|
203
|
+
lines.push(` Status: ${this.theme.fg("warning", "connecting...")}`);
|
|
204
|
+
lines.push("");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for (const s of failed) {
|
|
208
|
+
lines.push(this.theme.fg("accent", `• ${s.name}`) + ` (${s.source})`);
|
|
209
|
+
lines.push(` URL: ${s.url}`);
|
|
210
|
+
lines.push(` Status: ${this.theme.fg("error", "failed")} — ${s.error ?? "unknown error"}`);
|
|
211
|
+
lines.push("");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.textComponent.setText(lines.join("\n"));
|
|
215
|
+
this.tui.requestRender();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
handleInput(data: string) {
|
|
219
|
+
const kb = getKeybindings();
|
|
220
|
+
if (
|
|
221
|
+
data === "q" ||
|
|
222
|
+
data === "\r" ||
|
|
223
|
+
data === "\n" ||
|
|
224
|
+
kb.matches(data, "tui.select.cancel")
|
|
225
|
+
) {
|
|
226
|
+
if (this.timer) {
|
|
227
|
+
clearInterval(this.timer);
|
|
228
|
+
this.timer = null;
|
|
229
|
+
}
|
|
230
|
+
this.done();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
dispose() {
|
|
235
|
+
if (this.timer) {
|
|
236
|
+
clearInterval(this.timer);
|
|
237
|
+
this.timer = null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function setupMcpCommand(pi: ExtensionAPI) {
|
|
243
|
+
pi.registerCommand("mcp", {
|
|
244
|
+
description: "Show active MCP servers and their tools",
|
|
245
|
+
handler: async (_args, ctx) => {
|
|
246
|
+
if (ctx.hasUI) {
|
|
247
|
+
await ctx.ui.custom<void>(
|
|
248
|
+
(tui, theme, _kb, done) => new McpStatusComponent(tui, theme, () => done(undefined))
|
|
249
|
+
);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Fallback for non-interactive (print / RPC) mode.
|
|
254
|
+
const servers = getMcpStatus();
|
|
255
|
+
if (servers.length === 0) {
|
|
256
|
+
ctx.ui.notify("No MCP servers configured.", "info");
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const lines: string[] = [`MCP servers (${servers.length}):`, ""];
|
|
261
|
+
for (const s of servers) {
|
|
262
|
+
lines.push(`• ${s.name} (${s.source})`);
|
|
263
|
+
lines.push(` URL: ${s.url}`);
|
|
264
|
+
if (s.state === "connecting") {
|
|
265
|
+
lines.push(` Status: connecting...`);
|
|
266
|
+
} else if (s.state === "failed") {
|
|
267
|
+
lines.push(` Status: failed — ${s.error ?? "unknown error"}`);
|
|
268
|
+
} else {
|
|
269
|
+
lines.push(` Tools: ${s.toolCount}`);
|
|
270
|
+
for (const tool of s.tools) {
|
|
271
|
+
const desc = tool.description ? ` — ${tool.description.slice(0, 60)}` : "";
|
|
272
|
+
lines.push(` - ${tool.name}${desc}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
lines.push("");
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
pi.sendMessage({ customType: "mcp-status", content: lines.join("\n"), display: true }, { triggerTurn: false });
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
130
283
|
// ─── /retry ────────────────────────────────────────────────────────────────
|
|
131
284
|
|
|
132
285
|
function setupRetryCommand(pi: ExtensionAPI) {
|
|
@@ -165,5 +318,6 @@ function setupRetryCommand(pi: ExtensionAPI) {
|
|
|
165
318
|
export function setupSlash(pi: ExtensionAPI) {
|
|
166
319
|
setupDpModelCommand(pi);
|
|
167
320
|
setupDpSettingsCommand(pi);
|
|
321
|
+
setupMcpCommand(pi);
|
|
168
322
|
setupRetryCommand(pi);
|
|
169
323
|
}
|
package/extensions/smart-at.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* Tier 2 (-300): 在 .* 或 __* 目录下
|
|
21
21
|
* Tier 3 (-200): 在已知噪音目录下(build/dist/coverage 等)
|
|
22
22
|
* Tier 4 (-150~-80): 坏扩展名(二进制/编译产物/媒体文件)
|
|
23
|
-
* Base (always): -depth*
|
|
23
|
+
* Base (always): -depth*30 - name.length
|
|
24
24
|
*
|
|
25
25
|
* 匹配:
|
|
26
26
|
* - 大小写敏感
|
|
@@ -104,7 +104,7 @@ function computePenaltyMeta(filePath: string, isDir: boolean, gitIgnored: boolea
|
|
|
104
104
|
tierPenalty = EXT_PENALTY[ext]!;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
const basePenalty = -(depth *
|
|
107
|
+
const basePenalty = -(depth * 30) - name.length;
|
|
108
108
|
return { tier, penalty: tierPenalty + basePenalty };
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -306,7 +306,7 @@ function computeMatchScore(candidate: FileCandidate, query: string): number {
|
|
|
306
306
|
let s = 0;
|
|
307
307
|
|
|
308
308
|
// 大小写敏感匹配
|
|
309
|
-
if (stem === query) s = isDir ? 1500 :
|
|
309
|
+
if (stem === query) s = isDir ? 1500 : 1050;
|
|
310
310
|
else if (name.startsWith(query + ".") || name.startsWith(query + "_")) s = 1000;
|
|
311
311
|
else if (name.startsWith(query)) s = 900;
|
|
312
312
|
else if (name.includes(query)) s = 600;
|
|
@@ -316,10 +316,10 @@ function computeMatchScore(candidate: FileCandidate, query: string): number {
|
|
|
316
316
|
if (!s) return 0;
|
|
317
317
|
|
|
318
318
|
// 目录轻微加成(tiebreaker,不碾压深度)
|
|
319
|
-
if (isDir) s +=
|
|
319
|
+
if (isDir) s += 100;
|
|
320
320
|
|
|
321
321
|
// 父目录命中加成
|
|
322
|
-
if (inDir) s +=
|
|
322
|
+
if (inDir) s += 50;
|
|
323
323
|
|
|
324
324
|
return s;
|
|
325
325
|
}
|
|
@@ -4,29 +4,49 @@
|
|
|
4
4
|
* 当 agent 读取或编辑子目录中的文件时,自动发现该目录及父目录中的 AGENTS.md/CLAUDE.md,
|
|
5
5
|
* 将其内容注入到 tool result 中。
|
|
6
6
|
*
|
|
7
|
-
* 状态通过 pi.appendEntry() 持久化到 session JSONL 文件中,resume
|
|
7
|
+
* 状态通过 pi.appendEntry() 持久化到 session JSONL 文件中,resume / reload 时恢复。
|
|
8
|
+
* compaction 视为上下文边界:仅恢复当前 branch 上最后一个 compaction 之后的已加载状态。
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import { dirname, resolve, relative, join } from "node:path";
|
|
12
|
+
import { dirname, resolve, relative, join, normalize } from "node:path";
|
|
12
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
13
14
|
|
|
14
15
|
const CUSTOM_TYPE = "decorated-pi.subdir-agents";
|
|
15
16
|
const AGENTS_NAMES = ["AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"];
|
|
16
17
|
|
|
18
|
+
interface SessionLikeEntry {
|
|
19
|
+
type: string;
|
|
20
|
+
customType?: string;
|
|
21
|
+
data?: unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
const discovered = new Set<string>();
|
|
18
25
|
const pendingPaths = new Map<string, string>();
|
|
19
26
|
let sessionCwd = process.cwd();
|
|
20
27
|
|
|
21
|
-
function
|
|
28
|
+
function normalizeAbsPath(cwd: string, p: string): string {
|
|
29
|
+
return normalize(resolve(cwd, p));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function lastCompactionIndex(entries: SessionLikeEntry[]): number {
|
|
33
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
34
|
+
if (entries[i]?.type === "compaction") return i;
|
|
35
|
+
}
|
|
36
|
+
return -1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function restoreFromBranch(ctx: { cwd: string; sessionManager: { getBranch: () => Array<SessionLikeEntry> } }) {
|
|
22
40
|
discovered.clear();
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
const branch = ctx.sessionManager.getBranch();
|
|
42
|
+
const start = lastCompactionIndex(branch) + 1;
|
|
43
|
+
for (const entry of branch.slice(start)) {
|
|
44
|
+
if (entry.type !== "custom" || entry.customType !== CUSTOM_TYPE) continue;
|
|
45
|
+
const paths = entry.data as string[] | undefined;
|
|
46
|
+
if (!Array.isArray(paths)) continue;
|
|
47
|
+
for (const p of paths) {
|
|
48
|
+
if (typeof p === "string" && p.trim()) {
|
|
49
|
+
discovered.add(normalizeAbsPath(ctx.cwd, p));
|
|
30
50
|
}
|
|
31
51
|
}
|
|
32
52
|
}
|
|
@@ -34,7 +54,7 @@ function restoreFromSession(ctx: { cwd: string; sessionManager: { getEntries: ()
|
|
|
34
54
|
|
|
35
55
|
function findNewAgents(filePath: string, cwd: string): Array<{ path: string; content: string }> {
|
|
36
56
|
const resolvedCwd = resolve(cwd);
|
|
37
|
-
let dir = dirname(resolve(filePath));
|
|
57
|
+
let dir = dirname(resolve(cwd, filePath));
|
|
38
58
|
const results: Array<{ path: string; content: string }> = [];
|
|
39
59
|
|
|
40
60
|
while (true) {
|
|
@@ -42,7 +62,7 @@ function findNewAgents(filePath: string, cwd: string): Array<{ path: string; con
|
|
|
42
62
|
if (rel === "" || rel.startsWith("..")) break;
|
|
43
63
|
|
|
44
64
|
for (const name of AGENTS_NAMES) {
|
|
45
|
-
const agentsPath = join(dir, name);
|
|
65
|
+
const agentsPath = normalize(join(dir, name));
|
|
46
66
|
if (existsSync(agentsPath) && !discovered.has(agentsPath)) {
|
|
47
67
|
try {
|
|
48
68
|
const content = readFileSync(agentsPath, "utf-8");
|
|
@@ -65,10 +85,20 @@ function findNewAgents(filePath: string, cwd: string): Array<{ path: string; con
|
|
|
65
85
|
return results.reverse();
|
|
66
86
|
}
|
|
67
87
|
|
|
88
|
+
export const __subdirAgentsTest = {
|
|
89
|
+
restoreFromBranch,
|
|
90
|
+
findNewAgents,
|
|
91
|
+
};
|
|
92
|
+
|
|
68
93
|
export function setupSubdirAgents(pi: ExtensionAPI) {
|
|
69
94
|
pi.on("session_start", (_event, ctx) => {
|
|
70
95
|
sessionCwd = ctx.cwd;
|
|
71
|
-
|
|
96
|
+
restoreFromBranch(ctx);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
pi.on("session_compact", () => {
|
|
100
|
+
discovered.clear();
|
|
101
|
+
pendingPaths.clear();
|
|
72
102
|
});
|
|
73
103
|
|
|
74
104
|
pi.on("tool_call", (event) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "decorated-pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A pi extension with better work-flow: patch tool, safety gates, secret redaction, smart @ completion, dynamic AGENTS loading, image fallback, and LSP tools",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -22,8 +22,7 @@
|
|
|
22
22
|
"homepage": "https://github.com/lcwecker/decorated-pi#readme",
|
|
23
23
|
"bugs": "https://github.com/lcwecker/decorated-pi/issues",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"@spences10/pi-project-trust": "0.0.6",
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
27
26
|
"openai": "^6.37.0"
|
|
28
27
|
},
|
|
29
28
|
"peerDependencies": {
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"types": ["node"],
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
"rootDir": ".",
|
|
12
|
+
"noEmit": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["extensions/**/*.ts", "test/**/*.ts"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|