@bubblebrain-ai/bubble 0.0.1
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 +70 -0
- package/dist/agent/evidence-tracker.d.ts +15 -0
- package/dist/agent/evidence-tracker.js +93 -0
- package/dist/agent/execution-governor.d.ts +30 -0
- package/dist/agent/execution-governor.js +169 -0
- package/dist/agent/subtask-policy.d.ts +14 -0
- package/dist/agent/subtask-policy.js +60 -0
- package/dist/agent/task-classifier.d.ts +3 -0
- package/dist/agent/task-classifier.js +36 -0
- package/dist/agent/tool-arbiter.d.ts +7 -0
- package/dist/agent/tool-arbiter.js +33 -0
- package/dist/agent/tool-intent.d.ts +20 -0
- package/dist/agent/tool-intent.js +176 -0
- package/dist/agent.d.ts +95 -0
- package/dist/agent.js +672 -0
- package/dist/approval/controller.d.ts +48 -0
- package/dist/approval/controller.js +78 -0
- package/dist/approval/danger.d.ts +13 -0
- package/dist/approval/danger.js +55 -0
- package/dist/approval/diff-hunks.d.ts +12 -0
- package/dist/approval/diff-hunks.js +32 -0
- package/dist/approval/session-cache.d.ts +35 -0
- package/dist/approval/session-cache.js +68 -0
- package/dist/approval/tool-helper.d.ts +14 -0
- package/dist/approval/tool-helper.js +32 -0
- package/dist/approval/types.d.ts +56 -0
- package/dist/approval/types.js +8 -0
- package/dist/bubble-home.d.ts +8 -0
- package/dist/bubble-home.js +19 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +82 -0
- package/dist/config.d.ts +41 -0
- package/dist/config.js +144 -0
- package/dist/context/budget.d.ts +21 -0
- package/dist/context/budget.js +72 -0
- package/dist/context/compact-llm.d.ts +16 -0
- package/dist/context/compact-llm.js +132 -0
- package/dist/context/compact.d.ts +15 -0
- package/dist/context/compact.js +251 -0
- package/dist/context/overflow.d.ts +9 -0
- package/dist/context/overflow.js +46 -0
- package/dist/context/projector.d.ts +26 -0
- package/dist/context/projector.js +150 -0
- package/dist/context/prune.d.ts +9 -0
- package/dist/context/prune.js +111 -0
- package/dist/lsp/config.d.ts +18 -0
- package/dist/lsp/config.js +58 -0
- package/dist/lsp/diagnostics.d.ts +24 -0
- package/dist/lsp/diagnostics.js +103 -0
- package/dist/lsp/index.d.ts +3 -0
- package/dist/lsp/index.js +3 -0
- package/dist/lsp/service.d.ts +85 -0
- package/dist/lsp/service.js +695 -0
- package/dist/main.d.ts +5 -0
- package/dist/main.js +352 -0
- package/dist/mcp/client.d.ts +68 -0
- package/dist/mcp/client.js +163 -0
- package/dist/mcp/config.d.ts +26 -0
- package/dist/mcp/config.js +127 -0
- package/dist/mcp/manager.d.ts +55 -0
- package/dist/mcp/manager.js +296 -0
- package/dist/mcp/name.d.ts +26 -0
- package/dist/mcp/name.js +40 -0
- package/dist/mcp/transports.d.ts +53 -0
- package/dist/mcp/transports.js +248 -0
- package/dist/mcp/types.d.ts +111 -0
- package/dist/mcp/types.js +14 -0
- package/dist/memory/db.d.ts +62 -0
- package/dist/memory/db.js +313 -0
- package/dist/memory/index.d.ts +9 -0
- package/dist/memory/index.js +9 -0
- package/dist/memory/paths.d.ts +18 -0
- package/dist/memory/paths.js +38 -0
- package/dist/memory/phase1.d.ts +23 -0
- package/dist/memory/phase1.js +172 -0
- package/dist/memory/phase2.d.ts +19 -0
- package/dist/memory/phase2.js +100 -0
- package/dist/memory/prompts.d.ts +19 -0
- package/dist/memory/prompts.js +99 -0
- package/dist/memory/reset.d.ts +1 -0
- package/dist/memory/reset.js +13 -0
- package/dist/memory/start.d.ts +24 -0
- package/dist/memory/start.js +50 -0
- package/dist/memory/storage.d.ts +10 -0
- package/dist/memory/storage.js +82 -0
- package/dist/memory/store.d.ts +43 -0
- package/dist/memory/store.js +193 -0
- package/dist/memory/usage.d.ts +1 -0
- package/dist/memory/usage.js +38 -0
- package/dist/model-catalog.d.ts +20 -0
- package/dist/model-catalog.js +99 -0
- package/dist/model-config.d.ts +32 -0
- package/dist/model-config.js +59 -0
- package/dist/model-pricing.d.ts +23 -0
- package/dist/model-pricing.js +46 -0
- package/dist/oauth/index.d.ts +3 -0
- package/dist/oauth/index.js +2 -0
- package/dist/oauth/openai-codex.d.ts +9 -0
- package/dist/oauth/openai-codex.js +173 -0
- package/dist/oauth/storage.d.ts +18 -0
- package/dist/oauth/storage.js +60 -0
- package/dist/oauth/types.d.ts +15 -0
- package/dist/oauth/types.js +1 -0
- package/dist/orchestrator/default-hooks.d.ts +2 -0
- package/dist/orchestrator/default-hooks.js +96 -0
- package/dist/orchestrator/hooks.d.ts +78 -0
- package/dist/orchestrator/hooks.js +52 -0
- package/dist/orchestrator/workflow.d.ts +10 -0
- package/dist/orchestrator/workflow.js +22 -0
- package/dist/permission/mode.d.ts +23 -0
- package/dist/permission/mode.js +20 -0
- package/dist/permissions/rule.d.ts +39 -0
- package/dist/permissions/rule.js +234 -0
- package/dist/permissions/settings.d.ts +71 -0
- package/dist/permissions/settings.js +202 -0
- package/dist/permissions/types.d.ts +61 -0
- package/dist/permissions/types.js +14 -0
- package/dist/prompt/compose.d.ts +12 -0
- package/dist/prompt/compose.js +67 -0
- package/dist/prompt/environment.d.ts +12 -0
- package/dist/prompt/environment.js +38 -0
- package/dist/prompt/provider-prompts/anthropic.d.ts +1 -0
- package/dist/prompt/provider-prompts/anthropic.js +5 -0
- package/dist/prompt/provider-prompts/codex.d.ts +1 -0
- package/dist/prompt/provider-prompts/codex.js +5 -0
- package/dist/prompt/provider-prompts/default.d.ts +1 -0
- package/dist/prompt/provider-prompts/default.js +6 -0
- package/dist/prompt/provider-prompts/gemini.d.ts +1 -0
- package/dist/prompt/provider-prompts/gemini.js +5 -0
- package/dist/prompt/provider-prompts/gpt.d.ts +1 -0
- package/dist/prompt/provider-prompts/gpt.js +5 -0
- package/dist/prompt/reminders.d.ts +30 -0
- package/dist/prompt/reminders.js +164 -0
- package/dist/prompt/runtime.d.ts +12 -0
- package/dist/prompt/runtime.js +31 -0
- package/dist/prompt/skills.d.ts +2 -0
- package/dist/prompt/skills.js +4 -0
- package/dist/provider-openai-codex.d.ts +14 -0
- package/dist/provider-openai-codex.js +409 -0
- package/dist/provider-registry.d.ts +56 -0
- package/dist/provider-registry.js +244 -0
- package/dist/provider-transform.d.ts +10 -0
- package/dist/provider-transform.js +69 -0
- package/dist/provider.d.ts +31 -0
- package/dist/provider.js +269 -0
- package/dist/question/controller.d.ts +22 -0
- package/dist/question/controller.js +97 -0
- package/dist/question/index.d.ts +2 -0
- package/dist/question/index.js +2 -0
- package/dist/question/types.d.ts +42 -0
- package/dist/question/types.js +6 -0
- package/dist/session-log.d.ts +16 -0
- package/dist/session-log.js +267 -0
- package/dist/session-types.d.ts +55 -0
- package/dist/session-types.js +1 -0
- package/dist/session.d.ts +32 -0
- package/dist/session.js +135 -0
- package/dist/skills/discovery.d.ts +12 -0
- package/dist/skills/discovery.js +148 -0
- package/dist/skills/format.d.ts +2 -0
- package/dist/skills/format.js +47 -0
- package/dist/skills/frontmatter.d.ts +5 -0
- package/dist/skills/frontmatter.js +60 -0
- package/dist/skills/invocation.d.ts +8 -0
- package/dist/skills/invocation.js +51 -0
- package/dist/skills/registry.d.ts +17 -0
- package/dist/skills/registry.js +42 -0
- package/dist/skills/types.d.ts +32 -0
- package/dist/skills/types.js +1 -0
- package/dist/slash-commands/commands.d.ts +7 -0
- package/dist/slash-commands/commands.js +779 -0
- package/dist/slash-commands/index.d.ts +4 -0
- package/dist/slash-commands/index.js +8 -0
- package/dist/slash-commands/registry.d.ts +31 -0
- package/dist/slash-commands/registry.js +70 -0
- package/dist/slash-commands/types.d.ts +44 -0
- package/dist/slash-commands/types.js +1 -0
- package/dist/slash-commands/unified.d.ts +38 -0
- package/dist/slash-commands/unified.js +38 -0
- package/dist/system-prompt.d.ts +34 -0
- package/dist/system-prompt.js +7 -0
- package/dist/tools/bash.d.ts +6 -0
- package/dist/tools/bash.js +135 -0
- package/dist/tools/edit.d.ts +16 -0
- package/dist/tools/edit.js +95 -0
- package/dist/tools/exa-mcp.d.ts +3 -0
- package/dist/tools/exa-mcp.js +74 -0
- package/dist/tools/exit-plan-mode.d.ts +17 -0
- package/dist/tools/exit-plan-mode.js +68 -0
- package/dist/tools/glob.d.ts +5 -0
- package/dist/tools/glob.js +129 -0
- package/dist/tools/grep.d.ts +5 -0
- package/dist/tools/grep.js +111 -0
- package/dist/tools/index.d.ts +36 -0
- package/dist/tools/index.js +59 -0
- package/dist/tools/lsp.d.ts +4 -0
- package/dist/tools/lsp.js +92 -0
- package/dist/tools/memory.d.ts +3 -0
- package/dist/tools/memory.js +90 -0
- package/dist/tools/question.d.ts +3 -0
- package/dist/tools/question.js +174 -0
- package/dist/tools/read.d.ts +7 -0
- package/dist/tools/read.js +83 -0
- package/dist/tools/sensitive-paths.d.ts +3 -0
- package/dist/tools/sensitive-paths.js +24 -0
- package/dist/tools/skill.d.ts +5 -0
- package/dist/tools/skill.js +51 -0
- package/dist/tools/task.d.ts +2 -0
- package/dist/tools/task.js +57 -0
- package/dist/tools/todo.d.ts +12 -0
- package/dist/tools/todo.js +151 -0
- package/dist/tools/tool-search.d.ts +23 -0
- package/dist/tools/tool-search.js +124 -0
- package/dist/tools/web-fetch.d.ts +6 -0
- package/dist/tools/web-fetch.js +75 -0
- package/dist/tools/web-search.d.ts +5 -0
- package/dist/tools/web-search.js +49 -0
- package/dist/tools/write.d.ts +11 -0
- package/dist/tools/write.js +77 -0
- package/dist/tui/display-history.d.ts +35 -0
- package/dist/tui/display-history.js +243 -0
- package/dist/tui/file-mentions.d.ts +29 -0
- package/dist/tui/file-mentions.js +174 -0
- package/dist/tui/image-paste.d.ts +54 -0
- package/dist/tui/image-paste.js +288 -0
- package/dist/tui/markdown-theme-rules.d.ts +23 -0
- package/dist/tui/markdown-theme-rules.js +164 -0
- package/dist/tui/markdown-theme.d.ts +5 -0
- package/dist/tui/markdown-theme.js +27 -0
- package/dist/tui/opencode-spinner.d.ts +21 -0
- package/dist/tui/opencode-spinner.js +216 -0
- package/dist/tui/prompt-keybindings.d.ts +41 -0
- package/dist/tui/prompt-keybindings.js +28 -0
- package/dist/tui/recent-activity.d.ts +8 -0
- package/dist/tui/recent-activity.js +71 -0
- package/dist/tui/run.d.ts +39 -0
- package/dist/tui/run.js +5696 -0
- package/dist/tui/sidebar-mcp.d.ts +31 -0
- package/dist/tui/sidebar-mcp.js +62 -0
- package/dist/tui/sidebar-state.d.ts +12 -0
- package/dist/tui/sidebar-state.js +69 -0
- package/dist/types.d.ts +219 -0
- package/dist/types.js +4 -0
- package/dist/variant/thinking-level.d.ts +5 -0
- package/dist/variant/thinking-level.js +25 -0
- package/dist/variant/variant-resolver.d.ts +4 -0
- package/dist/variant/variant-resolver.js +12 -0
- package/package.json +47 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context-overflow detection.
|
|
3
|
+
*
|
|
4
|
+
* When the upstream provider rejects a request because the prompt exceeds
|
|
5
|
+
* the effective context window, we catch the error here so the agent can
|
|
6
|
+
* compact history and retry automatically.
|
|
7
|
+
*/
|
|
8
|
+
const OVERFLOW_PATTERNS = [
|
|
9
|
+
/context[_ ]length[_ ]exceeded/i,
|
|
10
|
+
/exceeds the context window/i,
|
|
11
|
+
/exceeds the limit of\s+\d+/i,
|
|
12
|
+
/prompt is too long/i,
|
|
13
|
+
/maximum context length/i,
|
|
14
|
+
/too many tokens/i,
|
|
15
|
+
];
|
|
16
|
+
export function isContextOverflowError(error) {
|
|
17
|
+
if (!error)
|
|
18
|
+
return false;
|
|
19
|
+
const messages = [];
|
|
20
|
+
if (typeof error === "string") {
|
|
21
|
+
messages.push(error);
|
|
22
|
+
}
|
|
23
|
+
else if (error instanceof Error) {
|
|
24
|
+
messages.push(error.message);
|
|
25
|
+
const cause = error.cause;
|
|
26
|
+
if (cause instanceof Error)
|
|
27
|
+
messages.push(cause.message);
|
|
28
|
+
else if (typeof cause === "string")
|
|
29
|
+
messages.push(cause);
|
|
30
|
+
}
|
|
31
|
+
else if (typeof error === "object") {
|
|
32
|
+
const anyErr = error;
|
|
33
|
+
if (typeof anyErr.message === "string")
|
|
34
|
+
messages.push(anyErr.message);
|
|
35
|
+
const nested = anyErr.error;
|
|
36
|
+
if (nested && typeof nested === "object" && typeof nested.message === "string") {
|
|
37
|
+
messages.push(nested.message);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return messages.some((msg) => OVERFLOW_PATTERNS.some((re) => re.test(msg)));
|
|
41
|
+
}
|
|
42
|
+
export function isContextOverflowByUsage(inputTokens, contextWindow) {
|
|
43
|
+
if (!inputTokens || !contextWindow)
|
|
44
|
+
return false;
|
|
45
|
+
return inputTokens > contextWindow;
|
|
46
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Message } from "../types.js";
|
|
2
|
+
export interface ProjectionOptions {
|
|
3
|
+
mode?: "full" | "pruned" | "budgeted";
|
|
4
|
+
providerId?: string;
|
|
5
|
+
modelId?: string;
|
|
6
|
+
usageAnchorTokens?: number;
|
|
7
|
+
anchorMessageCount?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function projectMessages(messages: Message[], options?: ProjectionOptions): Message[];
|
|
10
|
+
/**
|
|
11
|
+
* Ensures every assistant `tool_calls` is followed (in order) by tool messages
|
|
12
|
+
* responding to each tool_call_id, with no foreign messages interleaved.
|
|
13
|
+
*
|
|
14
|
+
* This is a defensive sanitizer for the OpenAI/Kimi API contract — any drift
|
|
15
|
+
* (a meta system-reminder injected mid-turn, a streaming bug, a session
|
|
16
|
+
* resumed mid-tool-execution, a compaction split that drops a tool result)
|
|
17
|
+
* would otherwise produce a 400 like:
|
|
18
|
+
*
|
|
19
|
+
* "tool_call_ids did not have response messages: edit:6"
|
|
20
|
+
*
|
|
21
|
+
* Strategy: for each assistant with tool_calls, gather any matching tool
|
|
22
|
+
* messages from the trailing window, drop orphan/interleaving entries, and
|
|
23
|
+
* synthesize placeholder tool messages for any tool_call_id with no captured
|
|
24
|
+
* result. Other messages keep their original order.
|
|
25
|
+
*/
|
|
26
|
+
export declare function repairToolCallChains(messages: Message[]): Message[];
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { getContextBudget } from "./budget.js";
|
|
2
|
+
import { compactMessages } from "./compact.js";
|
|
3
|
+
import { pruneMessages } from "./prune.js";
|
|
4
|
+
export function projectMessages(messages, options = {}) {
|
|
5
|
+
const mode = options.mode ?? "full";
|
|
6
|
+
const projected = [];
|
|
7
|
+
let systemBuffer = [];
|
|
8
|
+
const flushSystemBuffer = () => {
|
|
9
|
+
if (systemBuffer.length === 0)
|
|
10
|
+
return;
|
|
11
|
+
projected.push({
|
|
12
|
+
role: "system",
|
|
13
|
+
content: systemBuffer.join("\n\n"),
|
|
14
|
+
});
|
|
15
|
+
systemBuffer = [];
|
|
16
|
+
};
|
|
17
|
+
for (const message of messages) {
|
|
18
|
+
if (message.role === "system") {
|
|
19
|
+
systemBuffer.push(message.content);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
flushSystemBuffer();
|
|
23
|
+
if (message.role === "assistant" && isEmptyAssistantMessage(message)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
projected.push(cloneMessage(message));
|
|
27
|
+
}
|
|
28
|
+
flushSystemBuffer();
|
|
29
|
+
const repaired = repairToolCallChains(projected);
|
|
30
|
+
if (mode === "pruned") {
|
|
31
|
+
return pruneMessages(repaired);
|
|
32
|
+
}
|
|
33
|
+
if (mode === "budgeted") {
|
|
34
|
+
const pruned = pruneMessages(repaired);
|
|
35
|
+
if (!options.providerId || !options.modelId) {
|
|
36
|
+
return pruned;
|
|
37
|
+
}
|
|
38
|
+
const budget = getContextBudget(options.providerId, options.modelId, pruned, options.usageAnchorTokens !== undefined && options.anchorMessageCount !== undefined
|
|
39
|
+
? {
|
|
40
|
+
usageAnchorTokens: options.usageAnchorTokens,
|
|
41
|
+
tailMessages: pruned.slice(Math.min(options.anchorMessageCount, pruned.length)),
|
|
42
|
+
}
|
|
43
|
+
: undefined);
|
|
44
|
+
if (!budget.shouldCompact) {
|
|
45
|
+
return pruned;
|
|
46
|
+
}
|
|
47
|
+
const compacted = compactMessages(pruned, { keepRecentTurns: 2 });
|
|
48
|
+
if (!compacted.compacted || !compacted.messages) {
|
|
49
|
+
return pruned;
|
|
50
|
+
}
|
|
51
|
+
const afterFirstPass = getContextBudget(options.providerId, options.modelId, compacted.messages);
|
|
52
|
+
if (!afterFirstPass.shouldCompact) {
|
|
53
|
+
return repairToolCallChains(compacted.messages);
|
|
54
|
+
}
|
|
55
|
+
const tighter = compactMessages(pruned, { keepRecentTurns: 1 });
|
|
56
|
+
const finalMessages = tighter.compacted && tighter.messages ? tighter.messages : compacted.messages;
|
|
57
|
+
return repairToolCallChains(finalMessages);
|
|
58
|
+
}
|
|
59
|
+
return repaired;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Ensures every assistant `tool_calls` is followed (in order) by tool messages
|
|
63
|
+
* responding to each tool_call_id, with no foreign messages interleaved.
|
|
64
|
+
*
|
|
65
|
+
* This is a defensive sanitizer for the OpenAI/Kimi API contract — any drift
|
|
66
|
+
* (a meta system-reminder injected mid-turn, a streaming bug, a session
|
|
67
|
+
* resumed mid-tool-execution, a compaction split that drops a tool result)
|
|
68
|
+
* would otherwise produce a 400 like:
|
|
69
|
+
*
|
|
70
|
+
* "tool_call_ids did not have response messages: edit:6"
|
|
71
|
+
*
|
|
72
|
+
* Strategy: for each assistant with tool_calls, gather any matching tool
|
|
73
|
+
* messages from the trailing window, drop orphan/interleaving entries, and
|
|
74
|
+
* synthesize placeholder tool messages for any tool_call_id with no captured
|
|
75
|
+
* result. Other messages keep their original order.
|
|
76
|
+
*/
|
|
77
|
+
export function repairToolCallChains(messages) {
|
|
78
|
+
const result = [];
|
|
79
|
+
const consumed = new Set();
|
|
80
|
+
for (let i = 0; i < messages.length; i++) {
|
|
81
|
+
if (consumed.has(i))
|
|
82
|
+
continue;
|
|
83
|
+
const msg = messages[i];
|
|
84
|
+
if (msg.role === "tool") {
|
|
85
|
+
// Orphan tool message (no preceding assistant tool_call claims it). Drop it —
|
|
86
|
+
// the API rejects orphan tool messages too.
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
result.push(msg);
|
|
90
|
+
if (msg.role !== "assistant" || !msg.toolCalls || msg.toolCalls.length === 0) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// Collect tool messages immediately following the assistant turn (allowing
|
|
94
|
+
// foreign messages in between to be skipped, then re-emitted in their
|
|
95
|
+
// original positions later).
|
|
96
|
+
const matched = new Map();
|
|
97
|
+
const expected = new Set(msg.toolCalls.map((tc) => tc.id));
|
|
98
|
+
for (let j = i + 1; j < messages.length && expected.size > 0; j++) {
|
|
99
|
+
const next = messages[j];
|
|
100
|
+
if (next.role !== "tool")
|
|
101
|
+
continue;
|
|
102
|
+
if (!expected.has(next.toolCallId)) {
|
|
103
|
+
// Orphan tool message — mark consumed so we don't emit it later.
|
|
104
|
+
consumed.add(j);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
matched.set(next.toolCallId, next);
|
|
108
|
+
expected.delete(next.toolCallId);
|
|
109
|
+
consumed.add(j);
|
|
110
|
+
}
|
|
111
|
+
for (const tc of msg.toolCalls) {
|
|
112
|
+
const existing = matched.get(tc.id);
|
|
113
|
+
if (existing) {
|
|
114
|
+
result.push(existing);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
result.push({
|
|
118
|
+
role: "tool",
|
|
119
|
+
toolCallId: tc.id,
|
|
120
|
+
content: `[no result captured for tool call ${tc.name} (${tc.id})]`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
function isEmptyAssistantMessage(message) {
|
|
128
|
+
const hasContent = message.content.trim().length > 0;
|
|
129
|
+
const hasReasoning = (message.reasoning ?? "").trim().length > 0;
|
|
130
|
+
const hasToolCalls = !!message.toolCalls && message.toolCalls.length > 0;
|
|
131
|
+
return !hasContent && !hasReasoning && !hasToolCalls;
|
|
132
|
+
}
|
|
133
|
+
function cloneMessage(message) {
|
|
134
|
+
if (message.role === "assistant") {
|
|
135
|
+
return {
|
|
136
|
+
...message,
|
|
137
|
+
toolCalls: message.toolCalls?.map((toolCall) => ({ ...toolCall })),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
141
|
+
return {
|
|
142
|
+
...message,
|
|
143
|
+
content: message.content.map((part) => ({
|
|
144
|
+
...part,
|
|
145
|
+
...(part.type === "image_url" ? { image_url: { ...part.image_url } } : {}),
|
|
146
|
+
})),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return { ...message };
|
|
150
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Message } from "../types.js";
|
|
2
|
+
export declare function pruneMessages(messages: Message[]): Message[];
|
|
3
|
+
/**
|
|
4
|
+
* Aggressive variant of pruneMessages: drops the content of every prunable
|
|
5
|
+
* tool output except the latest unresolved tool turn that the model still
|
|
6
|
+
* needs to reason over. Used as a last-resort microcompact pass when a
|
|
7
|
+
* standard prune hasn't reclaimed enough budget.
|
|
8
|
+
*/
|
|
9
|
+
export declare function aggressivePruneMessages(messages: Message[]): Message[];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const PRUNEABLE_TOOLS = new Set([
|
|
2
|
+
"read", "bash", "grep", "web_search", "web_fetch", "edit", "write", "glob",
|
|
3
|
+
]);
|
|
4
|
+
const TOOL_RESULT_KEEP_COUNT = 2;
|
|
5
|
+
const MIN_PRUNE_LENGTH = 240;
|
|
6
|
+
export function pruneMessages(messages) {
|
|
7
|
+
const toolNameByCallId = new Map();
|
|
8
|
+
const pruneCandidates = [];
|
|
9
|
+
const protectedToolCallIds = collectProtectedToolCallIds(messages);
|
|
10
|
+
let protectedRetainedCount = 0;
|
|
11
|
+
for (let index = 0; index < messages.length; index++) {
|
|
12
|
+
const message = messages[index];
|
|
13
|
+
if (message.role === "assistant" && message.toolCalls) {
|
|
14
|
+
for (const toolCall of message.toolCalls) {
|
|
15
|
+
toolNameByCallId.set(toolCall.id, toolCall.name);
|
|
16
|
+
}
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (message.role !== "tool") {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (protectedToolCallIds.has(message.toolCallId)) {
|
|
23
|
+
const toolName = toolNameByCallId.get(message.toolCallId);
|
|
24
|
+
if (toolName && shouldPruneToolResult(toolName, message.content)) {
|
|
25
|
+
protectedRetainedCount += 1;
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const toolName = toolNameByCallId.get(message.toolCallId);
|
|
30
|
+
if (!toolName || !shouldPruneToolResult(toolName, message.content)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
pruneCandidates.push({ index, toolName, message });
|
|
34
|
+
}
|
|
35
|
+
const keepBudget = Math.max(0, TOOL_RESULT_KEEP_COUNT - protectedRetainedCount);
|
|
36
|
+
const keepFrom = Math.max(0, pruneCandidates.length - keepBudget);
|
|
37
|
+
const keepIndexes = new Set(pruneCandidates.slice(keepFrom).map((candidate) => candidate.index));
|
|
38
|
+
return messages.map((message, index) => {
|
|
39
|
+
if (message.role !== "tool" || keepIndexes.has(index)) {
|
|
40
|
+
return message;
|
|
41
|
+
}
|
|
42
|
+
const candidate = pruneCandidates.find((item) => item.index === index);
|
|
43
|
+
if (!candidate) {
|
|
44
|
+
return message;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
...message,
|
|
48
|
+
content: summarizePrunedToolResult(candidate.toolName, candidate.message.content),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function shouldPruneToolResult(toolName, content) {
|
|
53
|
+
if (!PRUNEABLE_TOOLS.has(toolName)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (content.length < MIN_PRUNE_LENGTH) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (content.startsWith("Error")) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
function summarizePrunedToolResult(toolName, content) {
|
|
65
|
+
return `[${toolName} output omitted to control context size; original length ${content.length} chars]`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Aggressive variant of pruneMessages: drops the content of every prunable
|
|
69
|
+
* tool output except the latest unresolved tool turn that the model still
|
|
70
|
+
* needs to reason over. Used as a last-resort microcompact pass when a
|
|
71
|
+
* standard prune hasn't reclaimed enough budget.
|
|
72
|
+
*/
|
|
73
|
+
export function aggressivePruneMessages(messages) {
|
|
74
|
+
const toolNameByCallId = new Map();
|
|
75
|
+
const protectedToolCallIds = collectProtectedToolCallIds(messages);
|
|
76
|
+
for (const message of messages) {
|
|
77
|
+
if (message.role === "assistant" && message.toolCalls) {
|
|
78
|
+
for (const toolCall of message.toolCalls) {
|
|
79
|
+
toolNameByCallId.set(toolCall.id, toolCall.name);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return messages.map((message) => {
|
|
84
|
+
if (message.role !== "tool")
|
|
85
|
+
return message;
|
|
86
|
+
if (protectedToolCallIds.has(message.toolCallId)) {
|
|
87
|
+
return message;
|
|
88
|
+
}
|
|
89
|
+
const toolName = toolNameByCallId.get(message.toolCallId);
|
|
90
|
+
if (!toolName || !shouldPruneToolResult(toolName, message.content)) {
|
|
91
|
+
return message;
|
|
92
|
+
}
|
|
93
|
+
return { ...message, content: summarizePrunedToolResult(toolName, message.content) };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function collectProtectedToolCallIds(messages) {
|
|
97
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
98
|
+
const message = messages[index];
|
|
99
|
+
if (message.role === "tool" || message.role === "system") {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (message.role === "user" && message.isMeta) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
|
|
106
|
+
return new Set(message.toolCalls.map((toolCall) => toolCall.id));
|
|
107
|
+
}
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
return new Set();
|
|
111
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface LspServerConfig {
|
|
2
|
+
disabled?: boolean;
|
|
3
|
+
command?: string[];
|
|
4
|
+
extensions?: string[];
|
|
5
|
+
rootMarkers?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
initializationOptions?: Record<string, unknown>;
|
|
8
|
+
languageId?: string;
|
|
9
|
+
}
|
|
10
|
+
export type BuiltinLspServerId = "typescript" | "deno" | "vue" | "eslint" | "oxlint";
|
|
11
|
+
export type LspServerId = BuiltinLspServerId | string;
|
|
12
|
+
export type LspConfig = boolean | Record<string, LspServerConfig>;
|
|
13
|
+
export declare const BUILTIN_LSP_SERVER_IDS: readonly BuiltinLspServerId[];
|
|
14
|
+
export declare function normalizeLspConfig(value: unknown): LspConfig | undefined;
|
|
15
|
+
export declare function isLspEnabled(config: LspConfig | undefined): boolean;
|
|
16
|
+
export declare function isLspServerEnabled(config: LspConfig | undefined, id: LspServerId): boolean;
|
|
17
|
+
export declare function isTypeScriptLspEnabled(config: LspConfig | undefined): boolean;
|
|
18
|
+
export declare function customLspServerEntries(config: LspConfig | undefined): Array<[string, LspServerConfig]>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const BUILTIN_LSP_SERVER_IDS = ["typescript", "deno", "vue", "eslint", "oxlint"];
|
|
2
|
+
export function normalizeLspConfig(value) {
|
|
3
|
+
if (typeof value === "boolean")
|
|
4
|
+
return value;
|
|
5
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6
|
+
return undefined;
|
|
7
|
+
const raw = value;
|
|
8
|
+
const config = {};
|
|
9
|
+
for (const [id, value] of Object.entries(raw)) {
|
|
10
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
11
|
+
continue;
|
|
12
|
+
const server = value;
|
|
13
|
+
const next = {};
|
|
14
|
+
if (typeof server.disabled === "boolean")
|
|
15
|
+
next.disabled = server.disabled;
|
|
16
|
+
if (isStringArray(server.command) && server.command.length > 0)
|
|
17
|
+
next.command = server.command;
|
|
18
|
+
if (isStringArray(server.extensions))
|
|
19
|
+
next.extensions = server.extensions;
|
|
20
|
+
if (isStringArray(server.rootMarkers))
|
|
21
|
+
next.rootMarkers = server.rootMarkers;
|
|
22
|
+
if (server.env && typeof server.env === "object" && !Array.isArray(server.env)) {
|
|
23
|
+
next.env = Object.fromEntries(Object.entries(server.env).filter((entry) => typeof entry[1] === "string"));
|
|
24
|
+
}
|
|
25
|
+
if (server.initializationOptions && typeof server.initializationOptions === "object" && !Array.isArray(server.initializationOptions)) {
|
|
26
|
+
next.initializationOptions = server.initializationOptions;
|
|
27
|
+
}
|
|
28
|
+
if (typeof server.languageId === "string")
|
|
29
|
+
next.languageId = server.languageId;
|
|
30
|
+
config[id] = next;
|
|
31
|
+
}
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
export function isLspEnabled(config) {
|
|
35
|
+
return config !== false;
|
|
36
|
+
}
|
|
37
|
+
export function isLspServerEnabled(config, id) {
|
|
38
|
+
if (!isLspEnabled(config))
|
|
39
|
+
return false;
|
|
40
|
+
if (config && typeof config === "object" && config[id]?.disabled)
|
|
41
|
+
return false;
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
export function isTypeScriptLspEnabled(config) {
|
|
45
|
+
return isLspServerEnabled(config, "typescript");
|
|
46
|
+
}
|
|
47
|
+
export function customLspServerEntries(config) {
|
|
48
|
+
if (!config || typeof config !== "object")
|
|
49
|
+
return [];
|
|
50
|
+
return Object.entries(config).filter(([id, server]) => !BUILTIN_LSP_SERVER_IDS.includes(id)
|
|
51
|
+
&& Array.isArray(server.command)
|
|
52
|
+
&& server.command.length > 0
|
|
53
|
+
&& Array.isArray(server.extensions)
|
|
54
|
+
&& server.extensions.length > 0);
|
|
55
|
+
}
|
|
56
|
+
function isStringArray(value) {
|
|
57
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
58
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface LspDiagnostic {
|
|
2
|
+
range?: {
|
|
3
|
+
start?: {
|
|
4
|
+
line?: number;
|
|
5
|
+
character?: number;
|
|
6
|
+
};
|
|
7
|
+
end?: {
|
|
8
|
+
line?: number;
|
|
9
|
+
character?: number;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
severity?: number;
|
|
13
|
+
code?: string | number;
|
|
14
|
+
source?: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
export interface FormatDiagnosticsOptions {
|
|
18
|
+
max?: number;
|
|
19
|
+
includeSummary?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function formatDiagnostics(filePath: string, diagnostics: LspDiagnostic[], cwd?: string, options?: FormatDiagnosticsOptions): string;
|
|
22
|
+
export declare function formatDiagnosticBlocks(cwd: string, currentFile: string, diagnostics: Record<string, LspDiagnostic[]>): string;
|
|
23
|
+
export declare function normalizeDiagnostics(diagnostics: LspDiagnostic[]): LspDiagnostic[];
|
|
24
|
+
export declare function formatDiagnosticSummary(diagnostics: LspDiagnostic[]): string;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
const SEVERITY_LABELS = {
|
|
3
|
+
1: "error",
|
|
4
|
+
2: "warning",
|
|
5
|
+
3: "info",
|
|
6
|
+
4: "hint",
|
|
7
|
+
};
|
|
8
|
+
const SEVERITY_RANK = {
|
|
9
|
+
1: 0,
|
|
10
|
+
2: 1,
|
|
11
|
+
3: 2,
|
|
12
|
+
4: 3,
|
|
13
|
+
};
|
|
14
|
+
export function formatDiagnostics(filePath, diagnostics, cwd, options = {}) {
|
|
15
|
+
const normalized = normalizeDiagnostics(diagnostics);
|
|
16
|
+
if (!normalized.length)
|
|
17
|
+
return "";
|
|
18
|
+
const label = cwd ? relative(cwd, filePath) || "." : filePath;
|
|
19
|
+
const limit = options.max ?? 20;
|
|
20
|
+
const lines = normalized.slice(0, limit).map((diagnostic) => {
|
|
21
|
+
const line = (diagnostic.range?.start?.line ?? 0) + 1;
|
|
22
|
+
const character = (diagnostic.range?.start?.character ?? 0) + 1;
|
|
23
|
+
const severity = SEVERITY_LABELS[diagnostic.severity ?? 1] ?? "diagnostic";
|
|
24
|
+
const source = diagnostic.source ? ` ${diagnostic.source}` : "";
|
|
25
|
+
const code = diagnostic.code === undefined ? "" : ` [${diagnostic.code}]`;
|
|
26
|
+
return `- ${label}:${line}:${character} ${severity}${source}${code}: ${diagnostic.message}`;
|
|
27
|
+
});
|
|
28
|
+
if (normalized.length > lines.length) {
|
|
29
|
+
lines.push(`- ... ${normalized.length - lines.length} more diagnostic(s)`);
|
|
30
|
+
}
|
|
31
|
+
if (options.includeSummary) {
|
|
32
|
+
lines.unshift(formatDiagnosticSummary(normalized));
|
|
33
|
+
}
|
|
34
|
+
return lines.join("\n");
|
|
35
|
+
}
|
|
36
|
+
export function formatDiagnosticBlocks(cwd, currentFile, diagnostics) {
|
|
37
|
+
let output = "";
|
|
38
|
+
let otherFiles = 0;
|
|
39
|
+
for (const [file, issues] of sortDiagnosticEntries(diagnostics, currentFile)) {
|
|
40
|
+
const normalized = normalizeDiagnostics(issues);
|
|
41
|
+
if (!normalized.length)
|
|
42
|
+
continue;
|
|
43
|
+
if (file === currentFile) {
|
|
44
|
+
output += `\n\nLSP diagnostics in this file:\n${formatDiagnostics(file, normalized, cwd, { includeSummary: true })}`;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (otherFiles >= 5)
|
|
48
|
+
continue;
|
|
49
|
+
otherFiles += 1;
|
|
50
|
+
output += `\n\nLSP diagnostics in other files:\n${formatDiagnostics(file, normalized, cwd, { includeSummary: true })}`;
|
|
51
|
+
}
|
|
52
|
+
return output;
|
|
53
|
+
}
|
|
54
|
+
export function normalizeDiagnostics(diagnostics) {
|
|
55
|
+
const byKey = new Map();
|
|
56
|
+
for (const diagnostic of diagnostics) {
|
|
57
|
+
const key = [
|
|
58
|
+
diagnostic.range?.start?.line ?? 0,
|
|
59
|
+
diagnostic.range?.start?.character ?? 0,
|
|
60
|
+
diagnostic.severity ?? 1,
|
|
61
|
+
diagnostic.source ?? "",
|
|
62
|
+
diagnostic.code ?? "",
|
|
63
|
+
diagnostic.message,
|
|
64
|
+
].join("|");
|
|
65
|
+
if (!byKey.has(key))
|
|
66
|
+
byKey.set(key, diagnostic);
|
|
67
|
+
}
|
|
68
|
+
return [...byKey.values()].sort(compareDiagnostic);
|
|
69
|
+
}
|
|
70
|
+
export function formatDiagnosticSummary(diagnostics) {
|
|
71
|
+
const counts = { error: 0, warning: 0, info: 0, hint: 0 };
|
|
72
|
+
for (const diagnostic of diagnostics) {
|
|
73
|
+
const label = SEVERITY_LABELS[diagnostic.severity ?? 1] ?? "error";
|
|
74
|
+
if (label in counts)
|
|
75
|
+
counts[label] += 1;
|
|
76
|
+
}
|
|
77
|
+
const parts = [
|
|
78
|
+
counts.error ? `${counts.error} error${counts.error === 1 ? "" : "s"}` : "",
|
|
79
|
+
counts.warning ? `${counts.warning} warning${counts.warning === 1 ? "" : "s"}` : "",
|
|
80
|
+
counts.info ? `${counts.info} info` : "",
|
|
81
|
+
counts.hint ? `${counts.hint} hint${counts.hint === 1 ? "" : "s"}` : "",
|
|
82
|
+
].filter(Boolean);
|
|
83
|
+
return parts.length ? `Summary: ${parts.join(", ")}` : "Summary: no diagnostics";
|
|
84
|
+
}
|
|
85
|
+
function sortDiagnosticEntries(diagnostics, currentFile) {
|
|
86
|
+
return Object.entries(diagnostics).sort(([fileA, issuesA], [fileB, issuesB]) => {
|
|
87
|
+
if (fileA === currentFile && fileB !== currentFile)
|
|
88
|
+
return -1;
|
|
89
|
+
if (fileB === currentFile && fileA !== currentFile)
|
|
90
|
+
return 1;
|
|
91
|
+
return strongestSeverity(issuesA) - strongestSeverity(issuesB) || fileA.localeCompare(fileB);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function strongestSeverity(diagnostics) {
|
|
95
|
+
return Math.min(...diagnostics.map((diagnostic) => SEVERITY_RANK[diagnostic.severity ?? 1] ?? 99), 99);
|
|
96
|
+
}
|
|
97
|
+
function compareDiagnostic(a, b) {
|
|
98
|
+
return (SEVERITY_RANK[a.severity ?? 1] ?? 99) - (SEVERITY_RANK[b.severity ?? 1] ?? 99)
|
|
99
|
+
|| (a.range?.start?.line ?? 0) - (b.range?.start?.line ?? 0)
|
|
100
|
+
|| (a.range?.start?.character ?? 0) - (b.range?.start?.character ?? 0)
|
|
101
|
+
|| (a.source ?? "").localeCompare(b.source ?? "")
|
|
102
|
+
|| a.message.localeCompare(b.message);
|
|
103
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { formatDiagnosticBlocks, formatDiagnosticSummary, formatDiagnostics, normalizeDiagnostics, type FormatDiagnosticsOptions, type LspDiagnostic, } from "./diagnostics.js";
|
|
2
|
+
export { isLspEnabled, isTypeScriptLspEnabled, normalizeLspConfig, type LspConfig, type LspServerConfig, } from "./config.js";
|
|
3
|
+
export { getLspService, TypeScriptLspService, type LspLocationInput, type LspService, type LspStatus, } from "./service.js";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { formatDiagnosticBlocks, formatDiagnosticSummary, formatDiagnostics, normalizeDiagnostics, } from "./diagnostics.js";
|
|
2
|
+
export { isLspEnabled, isTypeScriptLspEnabled, normalizeLspConfig, } from "./config.js";
|
|
3
|
+
export { getLspService, TypeScriptLspService, } from "./service.js";
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type LspConfig } from "./config.js";
|
|
2
|
+
import type { LspDiagnostic } from "./diagnostics.js";
|
|
3
|
+
export type LspStatusKind = "starting" | "connected" | "error";
|
|
4
|
+
export interface LspStatus {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
root: string;
|
|
8
|
+
status: LspStatusKind;
|
|
9
|
+
message?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface LspLocationInput {
|
|
12
|
+
file: string;
|
|
13
|
+
line: number;
|
|
14
|
+
character: number;
|
|
15
|
+
}
|
|
16
|
+
export interface LspService {
|
|
17
|
+
onStatusChange(listener: () => void): () => void;
|
|
18
|
+
isDisabled(): boolean;
|
|
19
|
+
updateConfig(config?: LspConfig): void;
|
|
20
|
+
status(): LspStatus[];
|
|
21
|
+
hasClients(filePath: string): Promise<boolean>;
|
|
22
|
+
touchFile(filePath: string, diagnostics?: "document" | "full"): Promise<void>;
|
|
23
|
+
diagnostics(): Record<string, LspDiagnostic[]>;
|
|
24
|
+
restart(): Promise<void>;
|
|
25
|
+
hover(input: LspLocationInput): Promise<unknown[]>;
|
|
26
|
+
definition(input: LspLocationInput): Promise<unknown[]>;
|
|
27
|
+
references(input: LspLocationInput): Promise<unknown[]>;
|
|
28
|
+
implementation(input: LspLocationInput): Promise<unknown[]>;
|
|
29
|
+
documentSymbol(filePath: string): Promise<unknown[]>;
|
|
30
|
+
workspaceSymbol(query: string): Promise<unknown[]>;
|
|
31
|
+
prepareCallHierarchy(input: LspLocationInput): Promise<unknown[]>;
|
|
32
|
+
incomingCalls(input: LspLocationInput): Promise<unknown[]>;
|
|
33
|
+
outgoingCalls(input: LspLocationInput): Promise<unknown[]>;
|
|
34
|
+
}
|
|
35
|
+
export declare class ProjectLspService implements LspService {
|
|
36
|
+
private readonly cwd;
|
|
37
|
+
private readonly emitter;
|
|
38
|
+
private readonly clients;
|
|
39
|
+
private readonly spawning;
|
|
40
|
+
private readonly starting;
|
|
41
|
+
private readonly broken;
|
|
42
|
+
private readonly unavailable;
|
|
43
|
+
private readonly diagnosticsByFile;
|
|
44
|
+
private readonly waiters;
|
|
45
|
+
private disposed;
|
|
46
|
+
private config;
|
|
47
|
+
constructor(cwd: string, config?: LspConfig);
|
|
48
|
+
updateConfig(config?: LspConfig): void;
|
|
49
|
+
restart(): Promise<void>;
|
|
50
|
+
onStatusChange(listener: () => void): () => void;
|
|
51
|
+
isDisabled(): boolean;
|
|
52
|
+
status(): LspStatus[];
|
|
53
|
+
hasClients(filePath: string): Promise<boolean>;
|
|
54
|
+
touchFile(filePath: string, diagnostics?: "document" | "full"): Promise<void>;
|
|
55
|
+
diagnostics(): Record<string, LspDiagnostic[]>;
|
|
56
|
+
hover(input: LspLocationInput): Promise<unknown[]>;
|
|
57
|
+
definition(input: LspLocationInput): Promise<unknown[]>;
|
|
58
|
+
references(input: LspLocationInput): Promise<unknown[]>;
|
|
59
|
+
implementation(input: LspLocationInput): Promise<unknown[]>;
|
|
60
|
+
documentSymbol(filePath: string): Promise<unknown[]>;
|
|
61
|
+
workspaceSymbol(query: string): Promise<unknown[]>;
|
|
62
|
+
prepareCallHierarchy(input: LspLocationInput): Promise<unknown[]>;
|
|
63
|
+
incomingCalls(input: LspLocationInput): Promise<unknown[]>;
|
|
64
|
+
outgoingCalls(input: LspLocationInput): Promise<unknown[]>;
|
|
65
|
+
shutdown(): Promise<void>;
|
|
66
|
+
shutdownNow(): void;
|
|
67
|
+
private runRequest;
|
|
68
|
+
private callHierarchyRequest;
|
|
69
|
+
private getClients;
|
|
70
|
+
private getClient;
|
|
71
|
+
private spawnClient;
|
|
72
|
+
private openOrChange;
|
|
73
|
+
private waitForDiagnostics;
|
|
74
|
+
private resolveDiagnosticWaiters;
|
|
75
|
+
private matchingServers;
|
|
76
|
+
private servers;
|
|
77
|
+
private markBroken;
|
|
78
|
+
private emitStatus;
|
|
79
|
+
private resolveInsideCwd;
|
|
80
|
+
private shutdownClient;
|
|
81
|
+
private shutdownClients;
|
|
82
|
+
private shutdownDisabledClients;
|
|
83
|
+
}
|
|
84
|
+
export declare const TypeScriptLspService: typeof ProjectLspService;
|
|
85
|
+
export declare function getLspService(cwd: string, config?: LspConfig): ProjectLspService;
|