noumen 0.1.0 → 0.3.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 +846 -51
- package/dist/a2a/index.d.ts +148 -0
- package/dist/a2a/index.js +579 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/acp/index.d.ts +129 -0
- package/dist/acp/index.js +498 -0
- package/dist/acp/index.js.map +1 -0
- package/dist/agent-1nFVUP9E.d.ts +1332 -0
- package/dist/cache-DsRqxx6v.d.ts +38 -0
- package/dist/chunk-3HEYCV26.js +10 -0
- package/dist/chunk-3HEYCV26.js.map +1 -0
- package/dist/chunk-3SK5GCI6.js +75 -0
- package/dist/chunk-3SK5GCI6.js.map +1 -0
- package/dist/chunk-42PHHZUA.js +132 -0
- package/dist/chunk-42PHHZUA.js.map +1 -0
- package/dist/chunk-4HW6LN6D.js +10365 -0
- package/dist/chunk-4HW6LN6D.js.map +1 -0
- package/dist/chunk-4SQA2UCV.js +26 -0
- package/dist/chunk-4SQA2UCV.js.map +1 -0
- package/dist/chunk-5GEX6ZSB.js +179 -0
- package/dist/chunk-5GEX6ZSB.js.map +1 -0
- package/dist/chunk-5JN4SPI7.js +94 -0
- package/dist/chunk-5JN4SPI7.js.map +1 -0
- package/dist/chunk-AMYIJSAZ.js +57 -0
- package/dist/chunk-AMYIJSAZ.js.map +1 -0
- package/dist/chunk-BZSFUEWM.js +43 -0
- package/dist/chunk-BZSFUEWM.js.map +1 -0
- package/dist/chunk-CS6WNDCF.js +171 -0
- package/dist/chunk-CS6WNDCF.js.map +1 -0
- package/dist/chunk-D43BWEZA.js +346 -0
- package/dist/chunk-D43BWEZA.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/chunk-EKOGVTBT.js +472 -0
- package/dist/chunk-EKOGVTBT.js.map +1 -0
- package/dist/chunk-HEQQQGK5.js +131 -0
- package/dist/chunk-HEQQQGK5.js.map +1 -0
- package/dist/chunk-HL6JCRZJ.js +3112 -0
- package/dist/chunk-HL6JCRZJ.js.map +1 -0
- package/dist/chunk-JACGEMTF.js +43 -0
- package/dist/chunk-JACGEMTF.js.map +1 -0
- package/dist/chunk-JX7CLUCV.js +21 -0
- package/dist/chunk-JX7CLUCV.js.map +1 -0
- package/dist/chunk-KXDB56YW.js +39 -0
- package/dist/chunk-KXDB56YW.js.map +1 -0
- package/dist/chunk-L3L3FG5T.js +16 -0
- package/dist/chunk-L3L3FG5T.js.map +1 -0
- package/dist/chunk-OGXNFXFA.js +196 -0
- package/dist/chunk-OGXNFXFA.js.map +1 -0
- package/dist/chunk-UVSSQBDY.js +192 -0
- package/dist/chunk-UVSSQBDY.js.map +1 -0
- package/dist/chunk-Y45R3PQL.js +684 -0
- package/dist/chunk-Y45R3PQL.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +874 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/client/index.d.ts +64 -0
- package/dist/client/index.js +409 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client-CRRO2376.js +10 -0
- package/dist/client-CRRO2376.js.map +1 -0
- package/dist/headless-FFU2DESQ.js +142 -0
- package/dist/headless-FFU2DESQ.js.map +1 -0
- package/dist/history-snip-64GYP4ZL.js +12 -0
- package/dist/history-snip-64GYP4ZL.js.map +1 -0
- package/dist/index.d.ts +1459 -422
- package/dist/index.js +398 -1757
- package/dist/index.js.map +1 -1
- package/dist/jsonrpc/index.d.ts +54 -0
- package/dist/jsonrpc/index.js +34 -0
- package/dist/jsonrpc/index.js.map +1 -0
- package/dist/lsp/index.d.ts +36 -0
- package/dist/lsp/index.js +16 -0
- package/dist/lsp/index.js.map +1 -0
- package/dist/lsp-PS3BWIHC.js +8 -0
- package/dist/lsp-PS3BWIHC.js.map +1 -0
- package/dist/manager-DLXK63XC.js +8 -0
- package/dist/manager-DLXK63XC.js.map +1 -0
- package/dist/mcp/index.d.ts +111 -0
- package/dist/mcp/index.js +105 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp-auth-AEI2R4ZC.js +9 -0
- package/dist/mcp-auth-AEI2R4ZC.js.map +1 -0
- package/dist/provider-factory-KCLIF34X.js +20 -0
- package/dist/provider-factory-KCLIF34X.js.map +1 -0
- package/dist/providers/anthropic.d.ts +19 -0
- package/dist/providers/anthropic.js +35 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/bedrock.d.ts +39 -0
- package/dist/providers/bedrock.js +56 -0
- package/dist/providers/bedrock.js.map +1 -0
- package/dist/providers/gemini.d.ts +17 -0
- package/dist/providers/gemini.js +262 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/ollama.d.ts +13 -0
- package/dist/providers/ollama.js +20 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/openai.d.ts +21 -0
- package/dist/providers/openai.js +9 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/openrouter.d.ts +16 -0
- package/dist/providers/openrouter.js +24 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/vertex.d.ts +42 -0
- package/dist/providers/vertex.js +67 -0
- package/dist/providers/vertex.js.map +1 -0
- package/dist/render-GRN4ZSSW.js +14 -0
- package/dist/render-GRN4ZSSW.js.map +1 -0
- package/dist/resolve-4JA2BBDA.js +14 -0
- package/dist/resolve-4JA2BBDA.js.map +1 -0
- package/dist/server/index.d.ts +143 -0
- package/dist/server/index.js +695 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server-CHMxuWKq.d.ts +96 -0
- package/dist/spinner-OJNR6NFO.js +8 -0
- package/dist/spinner-OJNR6NFO.js.map +1 -0
- package/dist/types-2kTLUCnD.d.ts +107 -0
- package/dist/types-CD0rUKKT.d.ts +109 -0
- package/dist/types-LrU4LRmX.d.ts +575 -0
- package/dist/types-NIyVwQ4h.d.ts +109 -0
- package/dist/types-QwfylltH.d.ts +71 -0
- package/dist/types-RPKUTu1k.d.ts +645 -0
- package/dist/uuid-RVN2T26F.js +8 -0
- package/dist/uuid-RVN2T26F.js.map +1 -0
- package/dist/zod-7YXKWYMC.js +12 -0
- package/dist/zod-7YXKWYMC.js.map +1 -0
- package/package.json +141 -7
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// src/cli/spinner.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
var CHARACTERS = process.env.TERM === "xterm-ghostty" ? ["\xB7", "\u2722", "\u2733", "\u2736", "\u273B", "*"] : process.platform === "darwin" ? ["\xB7", "\u2722", "\u2733", "\u2736", "\u273B", "\u273D"] : ["\xB7", "\u2722", "*", "\u2736", "\u273B", "\u273D"];
|
|
4
|
+
var FRAMES = [...CHARACTERS, ...CHARACTERS.slice().reverse()];
|
|
5
|
+
var FRAME_MS = 120;
|
|
6
|
+
function formatElapsed(ms) {
|
|
7
|
+
const s = Math.floor(ms / 1e3);
|
|
8
|
+
if (s < 60) return `${s}s`;
|
|
9
|
+
const m = Math.floor(s / 60);
|
|
10
|
+
return `${m}m ${s % 60}s`;
|
|
11
|
+
}
|
|
12
|
+
function startSpinner(label = "Thinking") {
|
|
13
|
+
const start = Date.now();
|
|
14
|
+
let frameIdx = 0;
|
|
15
|
+
let lastFrameTime = start;
|
|
16
|
+
const write = () => {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
if (now - lastFrameTime >= FRAME_MS) {
|
|
19
|
+
frameIdx = (frameIdx + 1) % FRAMES.length;
|
|
20
|
+
lastFrameTime = now;
|
|
21
|
+
}
|
|
22
|
+
const glyph = chalk.cyan(FRAMES[frameIdx]);
|
|
23
|
+
const elapsed = chalk.dim(formatElapsed(now - start));
|
|
24
|
+
process.stderr.write(` ${glyph} ${chalk.dim(label)} ${elapsed}\r`);
|
|
25
|
+
};
|
|
26
|
+
write();
|
|
27
|
+
const interval = setInterval(write, 50);
|
|
28
|
+
return {
|
|
29
|
+
stop() {
|
|
30
|
+
clearInterval(interval);
|
|
31
|
+
process.stderr.write("\x1B[2K\r");
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
startSpinner
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=chunk-KXDB56YW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/spinner.ts"],"sourcesContent":["import chalk from \"chalk\";\n\nconst CHARACTERS =\n process.env.TERM === \"xterm-ghostty\"\n ? [\"·\", \"✢\", \"✳\", \"✶\", \"✻\", \"*\"]\n : process.platform === \"darwin\"\n ? [\"·\", \"✢\", \"✳\", \"✶\", \"✻\", \"✽\"]\n : [\"·\", \"✢\", \"*\", \"✶\", \"✻\", \"✽\"];\n\nconst FRAMES = [...CHARACTERS, ...CHARACTERS.slice().reverse()];\nconst FRAME_MS = 120;\n\nfunction formatElapsed(ms: number): string {\n const s = Math.floor(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n return `${m}m ${s % 60}s`;\n}\n\nexport interface Spinner {\n stop(): void;\n}\n\nexport function startSpinner(label = \"Thinking\"): Spinner {\n const start = Date.now();\n let frameIdx = 0;\n let lastFrameTime = start;\n\n const write = () => {\n const now = Date.now();\n if (now - lastFrameTime >= FRAME_MS) {\n frameIdx = (frameIdx + 1) % FRAMES.length;\n lastFrameTime = now;\n }\n const glyph = chalk.cyan(FRAMES[frameIdx]);\n const elapsed = chalk.dim(formatElapsed(now - start));\n process.stderr.write(` ${glyph} ${chalk.dim(label)} ${elapsed}\\r`);\n };\n\n write();\n const interval = setInterval(write, 50);\n\n return {\n stop() {\n clearInterval(interval);\n process.stderr.write(\"\\x1b[2K\\r\");\n },\n };\n}\n"],"mappings":";AAAA,OAAO,WAAW;AAElB,IAAM,aACJ,QAAQ,IAAI,SAAS,kBACjB,CAAC,QAAK,UAAK,UAAK,UAAK,UAAK,GAAG,IAC7B,QAAQ,aAAa,WACnB,CAAC,QAAK,UAAK,UAAK,UAAK,UAAK,QAAG,IAC7B,CAAC,QAAK,UAAK,KAAK,UAAK,UAAK,QAAG;AAErC,IAAM,SAAS,CAAC,GAAG,YAAY,GAAG,WAAW,MAAM,EAAE,QAAQ,CAAC;AAC9D,IAAM,WAAW;AAEjB,SAAS,cAAc,IAAoB;AACzC,QAAM,IAAI,KAAK,MAAM,KAAK,GAAI;AAC9B,MAAI,IAAI,GAAI,QAAO,GAAG,CAAC;AACvB,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,SAAO,GAAG,CAAC,KAAK,IAAI,EAAE;AACxB;AAMO,SAAS,aAAa,QAAQ,YAAqB;AACxD,QAAM,QAAQ,KAAK,IAAI;AACvB,MAAI,WAAW;AACf,MAAI,gBAAgB;AAEpB,QAAM,QAAQ,MAAM;AAClB,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,MAAM,iBAAiB,UAAU;AACnC,kBAAY,WAAW,KAAK,OAAO;AACnC,sBAAgB;AAAA,IAClB;AACA,UAAM,QAAQ,MAAM,KAAK,OAAO,QAAQ,CAAC;AACzC,UAAM,UAAU,MAAM,IAAI,cAAc,MAAM,KAAK,CAAC;AACpD,YAAQ,OAAO,MAAM,KAAK,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC,KAAK,OAAO,IAAI;AAAA,EACrE;AAEA,QAAM;AACN,QAAM,WAAW,YAAY,OAAO,EAAE;AAEtC,SAAO;AAAA,IACL,OAAO;AACL,oBAAc,QAAQ;AACtB,cAAQ,OAAO,MAAM,WAAW;AAAA,IAClC;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/providers/types.ts
|
|
2
|
+
var ChatStreamError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
retryAfter;
|
|
5
|
+
constructor(message, opts) {
|
|
6
|
+
super(message, { cause: opts?.cause });
|
|
7
|
+
this.name = "ChatStreamError";
|
|
8
|
+
this.status = opts?.status;
|
|
9
|
+
this.retryAfter = opts?.retryAfter;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
ChatStreamError
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=chunk-L3L3FG5T.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/types.ts"],"sourcesContent":["import type { ChatMessage } from \"../session/types.js\";\nimport type { ThinkingConfig } from \"../thinking/types.js\";\n\nexport interface ToolParameterProperty {\n type: string;\n description?: string;\n enum?: string[];\n default?: unknown;\n minimum?: number;\n maximum?: number;\n}\n\nexport interface ToolDefinition {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: Record<string, ToolParameterProperty>;\n required?: string[];\n };\n };\n}\n\n// Streaming chunk types (OpenAI-compatible)\n\nexport interface ChatStreamDelta {\n role?: \"assistant\";\n content?: string | null;\n thinking_content?: string | null;\n thinking_signature?: string | null;\n /** Opaque data payload for Anthropic redacted_thinking blocks. */\n redacted_thinking_data?: string | null;\n tool_calls?: Array<{\n index: number;\n id?: string;\n type?: \"function\";\n function?: {\n name?: string;\n arguments?: string;\n };\n }>;\n}\n\nexport interface ChatStreamChoice {\n index: number;\n delta: ChatStreamDelta;\n finish_reason: string | null;\n}\n\nexport interface ChatStreamChunk {\n id: string;\n choices: ChatStreamChoice[];\n model: string;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n cache_read_tokens?: number;\n cache_creation_tokens?: number;\n thinking_tokens?: number;\n };\n}\n\nexport interface ChatCompletionUsage {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n cache_read_tokens?: number;\n cache_creation_tokens?: number;\n thinking_tokens?: number;\n}\n\n/**\n * Structured output format. When provided, the model is constrained to\n * produce a response matching the given JSON schema.\n *\n * - `json_schema`: the model must produce JSON conforming to the given schema.\n * - `json_object`: the model must produce valid JSON (no specific schema).\n */\nexport type OutputFormat = JsonSchemaOutputFormat | JsonObjectOutputFormat;\n\nexport interface JsonSchemaOutputFormat {\n type: \"json_schema\";\n /** JSON Schema object describing the expected output shape. */\n schema: Record<string, unknown>;\n /** Optional name for the schema (required by some providers). */\n name?: string;\n /** When true, the provider enforces strict schema adherence. */\n strict?: boolean;\n}\n\nexport interface JsonObjectOutputFormat {\n type: \"json_object\";\n}\n\nexport interface ChatParams {\n model: string;\n messages: ChatMessage[];\n tools?: ToolDefinition[];\n max_tokens?: number;\n system?: string;\n temperature?: number;\n thinking?: ThinkingConfig;\n /** Constrain the model to produce structured output matching this schema. */\n outputFormat?: OutputFormat;\n /**\n * When true, the provider should place the cache breakpoint on the\n * second-to-last message instead of the last. Used by subagent forks\n * to avoid writing fork-only tails into the shared prompt cache.\n */\n skipCacheWrite?: boolean;\n /** Abort signal — providers should forward this to cancel in-flight HTTP requests. */\n signal?: AbortSignal;\n}\n\nexport interface AIProvider {\n chat(params: ChatParams): AsyncIterable<ChatStreamChunk>;\n}\n\n/**\n * Extended error type that providers can throw to convey retry-relevant metadata.\n * Consumers (like the retry engine) can inspect these fields without knowing\n * provider-specific SDK error types.\n */\nexport class ChatStreamError extends Error {\n status?: number;\n retryAfter?: string;\n\n constructor(\n message: string,\n opts?: { status?: number; retryAfter?: string; cause?: unknown },\n ) {\n super(message, { cause: opts?.cause });\n this.name = \"ChatStreamError\";\n this.status = opts?.status;\n this.retryAfter = opts?.retryAfter;\n }\n}\n"],"mappings":";AA8HO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC;AAAA,EACA;AAAA,EAEA,YACE,SACA,MACA;AACA,UAAM,SAAS,EAAE,OAAO,MAAM,MAAM,CAAC;AACrC,SAAK,OAAO;AACZ,SAAK,SAAS,MAAM;AACpB,SAAK,aAAa,MAAM;AAAA,EAC1B;AACF;","names":[]}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// src/cli/render.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import "readline/promises";
|
|
4
|
+
function renderEvent(event, config, state) {
|
|
5
|
+
if (config.json) {
|
|
6
|
+
renderJsonl(event);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (config.quiet) {
|
|
10
|
+
if (event.type === "text_delta") {
|
|
11
|
+
state.accumulatedText += event.text;
|
|
12
|
+
}
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
renderPretty(event, config, state);
|
|
16
|
+
}
|
|
17
|
+
var VISIBLE_EVENTS = /* @__PURE__ */ new Set([
|
|
18
|
+
"text_delta",
|
|
19
|
+
"tool_use_start",
|
|
20
|
+
"tool_result",
|
|
21
|
+
"permission_request",
|
|
22
|
+
"permission_denied",
|
|
23
|
+
"error",
|
|
24
|
+
"compact_start",
|
|
25
|
+
"retry_attempt",
|
|
26
|
+
"retry_exhausted",
|
|
27
|
+
"subagent_start",
|
|
28
|
+
"subagent_end",
|
|
29
|
+
"session_resumed",
|
|
30
|
+
"max_turns_reached"
|
|
31
|
+
]);
|
|
32
|
+
function isVisibleEvent(event, config) {
|
|
33
|
+
if (config.json) return true;
|
|
34
|
+
if (event.type === "thinking_delta" && config.verbose) return true;
|
|
35
|
+
if (event.type === "cost_update" && config.verbose) return true;
|
|
36
|
+
if (event.type === "permission_granted" && config.verbose) return true;
|
|
37
|
+
return VISIBLE_EVENTS.has(event.type);
|
|
38
|
+
}
|
|
39
|
+
function createRenderState() {
|
|
40
|
+
return {
|
|
41
|
+
accumulatedText: "",
|
|
42
|
+
activeTools: /* @__PURE__ */ new Map(),
|
|
43
|
+
showedActivity: false
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function renderJsonl(event) {
|
|
47
|
+
const serializable = { ...event };
|
|
48
|
+
if ("error" in event && event.type === "error") {
|
|
49
|
+
serializable.error = {
|
|
50
|
+
message: event.error.message,
|
|
51
|
+
name: event.error.name
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
process.stdout.write(JSON.stringify(serializable) + "\n");
|
|
55
|
+
}
|
|
56
|
+
function renderPretty(event, config, state) {
|
|
57
|
+
switch (event.type) {
|
|
58
|
+
case "text_delta":
|
|
59
|
+
process.stdout.write(event.text);
|
|
60
|
+
state.accumulatedText += event.text;
|
|
61
|
+
break;
|
|
62
|
+
case "thinking_delta":
|
|
63
|
+
if (config.verbose) {
|
|
64
|
+
process.stderr.write(chalk.dim.italic(event.text));
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case "tool_use_start":
|
|
68
|
+
state.activeTools.set(event.toolUseId, event.toolName);
|
|
69
|
+
process.stderr.write(chalk.dim(` [${event.toolName}] `));
|
|
70
|
+
if (config.verbose) {
|
|
71
|
+
process.stderr.write(chalk.dim("running..."));
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
case "tool_result": {
|
|
75
|
+
state.activeTools.delete(event.toolUseId);
|
|
76
|
+
if (config.verbose) {
|
|
77
|
+
const preview = truncateResult(
|
|
78
|
+
typeof event.result === "string" ? event.result : JSON.stringify(event.result),
|
|
79
|
+
120
|
|
80
|
+
);
|
|
81
|
+
process.stderr.write(chalk.dim(preview) + "\n");
|
|
82
|
+
} else {
|
|
83
|
+
process.stderr.write(chalk.dim("done\n"));
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case "permission_request":
|
|
88
|
+
process.stderr.write(
|
|
89
|
+
"\n" + chalk.yellow(" Permission required: ") + chalk.white(event.toolName) + "\n" + chalk.dim(" " + event.message) + "\n"
|
|
90
|
+
);
|
|
91
|
+
break;
|
|
92
|
+
case "permission_granted":
|
|
93
|
+
if (config.verbose) {
|
|
94
|
+
process.stderr.write(chalk.green(" \u2713 Granted\n"));
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case "permission_denied":
|
|
98
|
+
process.stderr.write(
|
|
99
|
+
chalk.red(" \u2717 Denied: ") + chalk.dim(event.message) + "\n"
|
|
100
|
+
);
|
|
101
|
+
break;
|
|
102
|
+
case "error":
|
|
103
|
+
process.stderr.write(
|
|
104
|
+
chalk.red("\n Error: ") + event.error.message + "\n"
|
|
105
|
+
);
|
|
106
|
+
break;
|
|
107
|
+
case "compact_start":
|
|
108
|
+
process.stderr.write(chalk.dim(" Compacting conversation..."));
|
|
109
|
+
break;
|
|
110
|
+
case "compact_complete":
|
|
111
|
+
process.stderr.write(chalk.dim(" done\n"));
|
|
112
|
+
break;
|
|
113
|
+
case "cost_update":
|
|
114
|
+
if (config.verbose) {
|
|
115
|
+
const s = event.summary;
|
|
116
|
+
process.stderr.write(
|
|
117
|
+
chalk.dim(
|
|
118
|
+
`
|
|
119
|
+
Cost: $${s.totalCostUSD.toFixed(4)} (${s.totalInputTokens} in / ${s.totalOutputTokens} out)
|
|
120
|
+
`
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
case "retry_attempt":
|
|
126
|
+
process.stderr.write(
|
|
127
|
+
chalk.yellow(
|
|
128
|
+
`
|
|
129
|
+
Retrying (${event.attempt}/${event.maxRetries}) in ${event.delayMs}ms...
|
|
130
|
+
`
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
break;
|
|
134
|
+
case "retry_exhausted":
|
|
135
|
+
process.stderr.write(
|
|
136
|
+
chalk.red(`
|
|
137
|
+
All ${event.attempts} retry attempts failed.
|
|
138
|
+
`)
|
|
139
|
+
);
|
|
140
|
+
break;
|
|
141
|
+
case "subagent_start": {
|
|
142
|
+
const preview = event.prompt.slice(0, 60);
|
|
143
|
+
process.stderr.write(chalk.dim(` [subagent] ${preview}...
|
|
144
|
+
`));
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case "subagent_end":
|
|
148
|
+
process.stderr.write(chalk.dim(" [subagent] complete\n"));
|
|
149
|
+
break;
|
|
150
|
+
case "session_resumed":
|
|
151
|
+
process.stderr.write(
|
|
152
|
+
chalk.dim(
|
|
153
|
+
`
|
|
154
|
+
Resumed session ${event.sessionId.slice(0, 8)}... (${event.messageCount} messages)
|
|
155
|
+
`
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
break;
|
|
159
|
+
case "max_turns_reached":
|
|
160
|
+
process.stderr.write(
|
|
161
|
+
chalk.yellow(
|
|
162
|
+
`
|
|
163
|
+
Max turns reached (${event.turnCount}/${event.maxTurns})
|
|
164
|
+
`
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
break;
|
|
168
|
+
case "turn_complete":
|
|
169
|
+
if (state.accumulatedText && !state.accumulatedText.endsWith("\n")) {
|
|
170
|
+
process.stdout.write("\n");
|
|
171
|
+
}
|
|
172
|
+
state.accumulatedText = "";
|
|
173
|
+
break;
|
|
174
|
+
default:
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async function promptPermission(rl, toolName, message) {
|
|
179
|
+
const answer = await rl.question(
|
|
180
|
+
chalk.yellow(` Allow ${toolName}? `) + chalk.dim("[Y/n] ")
|
|
181
|
+
);
|
|
182
|
+
const normalized = answer.trim().toLowerCase();
|
|
183
|
+
return normalized === "" || normalized === "y" || normalized === "yes";
|
|
184
|
+
}
|
|
185
|
+
function truncateResult(text, max) {
|
|
186
|
+
if (text.length <= max) return text;
|
|
187
|
+
return text.slice(0, max) + "...";
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export {
|
|
191
|
+
renderEvent,
|
|
192
|
+
isVisibleEvent,
|
|
193
|
+
createRenderState,
|
|
194
|
+
promptPermission
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=chunk-OGXNFXFA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/render.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport * as readline from \"node:readline/promises\";\nimport type { StreamEvent } from \"../session/types.js\";\nimport type { MergedConfig } from \"./config.js\";\n\n/**\n * Render a single StreamEvent to the terminal. Handles three modes:\n * - JSONL (--json): one JSON line per event to stdout\n * - Quiet (--quiet): accumulates text, caller prints at end\n * - Pretty (default): colored streaming output\n */\nexport function renderEvent(\n event: StreamEvent,\n config: MergedConfig,\n state: RenderState,\n): void {\n if (config.json) {\n renderJsonl(event);\n return;\n }\n\n if (config.quiet) {\n if (event.type === \"text_delta\") {\n state.accumulatedText += event.text;\n }\n return;\n }\n\n renderPretty(event, config, state);\n}\n\n/** Event types that produce visible terminal output in pretty mode. */\nconst VISIBLE_EVENTS = new Set([\n \"text_delta\",\n \"tool_use_start\",\n \"tool_result\",\n \"permission_request\",\n \"permission_denied\",\n \"error\",\n \"compact_start\",\n \"retry_attempt\",\n \"retry_exhausted\",\n \"subagent_start\",\n \"subagent_end\",\n \"session_resumed\",\n \"max_turns_reached\",\n]);\n\nexport function isVisibleEvent(event: StreamEvent, config: MergedConfig): boolean {\n if (config.json) return true;\n if (event.type === \"thinking_delta\" && config.verbose) return true;\n if (event.type === \"cost_update\" && config.verbose) return true;\n if (event.type === \"permission_granted\" && config.verbose) return true;\n return VISIBLE_EVENTS.has(event.type);\n}\n\nexport interface RenderState {\n accumulatedText: string;\n activeTools: Map<string, string>;\n showedActivity: boolean;\n}\n\nexport function createRenderState(): RenderState {\n return {\n accumulatedText: \"\",\n activeTools: new Map(),\n showedActivity: false,\n };\n}\n\nfunction renderJsonl(event: StreamEvent): void {\n const serializable = { ...event } as Record<string, unknown>;\n if (\"error\" in event && event.type === \"error\") {\n serializable.error = {\n message: event.error.message,\n name: event.error.name,\n };\n }\n process.stdout.write(JSON.stringify(serializable) + \"\\n\");\n}\n\nfunction renderPretty(\n event: StreamEvent,\n config: MergedConfig,\n state: RenderState,\n): void {\n switch (event.type) {\n case \"text_delta\":\n process.stdout.write(event.text);\n state.accumulatedText += event.text;\n break;\n\n case \"thinking_delta\":\n if (config.verbose) {\n process.stderr.write(chalk.dim.italic(event.text));\n }\n break;\n\n case \"tool_use_start\":\n state.activeTools.set(event.toolUseId, event.toolName);\n process.stderr.write(chalk.dim(` [${event.toolName}] `));\n if (config.verbose) {\n process.stderr.write(chalk.dim(\"running...\"));\n }\n break;\n\n case \"tool_result\": {\n state.activeTools.delete(event.toolUseId);\n if (config.verbose) {\n const preview = truncateResult(\n typeof event.result === \"string\"\n ? event.result\n : JSON.stringify(event.result),\n 120,\n );\n process.stderr.write(chalk.dim(preview) + \"\\n\");\n } else {\n process.stderr.write(chalk.dim(\"done\\n\"));\n }\n break;\n }\n\n case \"permission_request\":\n process.stderr.write(\n \"\\n\" +\n chalk.yellow(\" Permission required: \") +\n chalk.white(event.toolName) +\n \"\\n\" +\n chalk.dim(\" \" + event.message) +\n \"\\n\",\n );\n break;\n\n case \"permission_granted\":\n if (config.verbose) {\n process.stderr.write(chalk.green(\" ✓ Granted\\n\"));\n }\n break;\n\n case \"permission_denied\":\n process.stderr.write(\n chalk.red(\" ✗ Denied: \") + chalk.dim(event.message) + \"\\n\",\n );\n break;\n\n case \"error\":\n process.stderr.write(\n chalk.red(\"\\n Error: \") + event.error.message + \"\\n\",\n );\n break;\n\n case \"compact_start\":\n process.stderr.write(chalk.dim(\" Compacting conversation...\"));\n break;\n\n case \"compact_complete\":\n process.stderr.write(chalk.dim(\" done\\n\"));\n break;\n\n case \"cost_update\":\n if (config.verbose) {\n const s = event.summary;\n process.stderr.write(\n chalk.dim(\n `\\n Cost: $${s.totalCostUSD.toFixed(4)} ` +\n `(${s.totalInputTokens} in / ${s.totalOutputTokens} out)\\n`,\n ),\n );\n }\n break;\n\n case \"retry_attempt\":\n process.stderr.write(\n chalk.yellow(\n `\\n Retrying (${event.attempt}/${event.maxRetries}) in ${event.delayMs}ms...\\n`,\n ),\n );\n break;\n\n case \"retry_exhausted\":\n process.stderr.write(\n chalk.red(`\\n All ${event.attempts} retry attempts failed.\\n`),\n );\n break;\n\n case \"subagent_start\": {\n const preview = event.prompt.slice(0, 60);\n process.stderr.write(chalk.dim(` [subagent] ${preview}...\\n`));\n break;\n }\n\n case \"subagent_end\":\n process.stderr.write(chalk.dim(\" [subagent] complete\\n\"));\n break;\n\n case \"session_resumed\":\n process.stderr.write(\n chalk.dim(\n `\\n Resumed session ${event.sessionId.slice(0, 8)}... (${event.messageCount} messages)\\n`,\n ),\n );\n break;\n\n case \"max_turns_reached\":\n process.stderr.write(\n chalk.yellow(\n `\\n Max turns reached (${event.turnCount}/${event.maxTurns})\\n`,\n ),\n );\n break;\n\n case \"turn_complete\":\n if (state.accumulatedText && !state.accumulatedText.endsWith(\"\\n\")) {\n process.stdout.write(\"\\n\");\n }\n state.accumulatedText = \"\";\n break;\n\n default:\n break;\n }\n}\n\n/**\n * Create a permission handler that prompts Y/n in the terminal.\n * Writes to stderr so stdout stays clean for JSONL piping.\n */\nexport async function promptPermission(\n rl: readline.Interface,\n toolName: string,\n message: string,\n): Promise<boolean> {\n const answer = await rl.question(\n chalk.yellow(` Allow ${toolName}? `) + chalk.dim(\"[Y/n] \"),\n );\n const normalized = answer.trim().toLowerCase();\n return normalized === \"\" || normalized === \"y\" || normalized === \"yes\";\n}\n\nfunction truncateResult(text: string, max: number): string {\n if (text.length <= max) return text;\n return text.slice(0, max) + \"...\";\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// src/tools/lsp.ts
|
|
2
|
+
var lspTool = {
|
|
3
|
+
name: "LSP",
|
|
4
|
+
description: "Query language servers for code intelligence. Supports: goToDefinition, findReferences, hover, documentSymbol, workspaceSymbol. Line and character are 1-based.",
|
|
5
|
+
parameters: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
operation: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "The LSP operation to perform",
|
|
11
|
+
enum: [
|
|
12
|
+
"goToDefinition",
|
|
13
|
+
"findReferences",
|
|
14
|
+
"hover",
|
|
15
|
+
"documentSymbol",
|
|
16
|
+
"workspaceSymbol"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
filePath: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "Absolute path to the file (required for all except workspaceSymbol)"
|
|
22
|
+
},
|
|
23
|
+
line: {
|
|
24
|
+
type: "number",
|
|
25
|
+
description: "1-based line number (required for definition/references/hover)",
|
|
26
|
+
minimum: 1
|
|
27
|
+
},
|
|
28
|
+
character: {
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "1-based character offset (required for definition/references/hover)",
|
|
31
|
+
minimum: 1
|
|
32
|
+
},
|
|
33
|
+
query: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Search query for workspaceSymbol (optional, empty = all)"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: ["operation"]
|
|
39
|
+
},
|
|
40
|
+
isReadOnly: true,
|
|
41
|
+
isConcurrencySafe: true,
|
|
42
|
+
async call(args, ctx) {
|
|
43
|
+
if (!ctx.lspManager) {
|
|
44
|
+
return { content: "LSP is not configured.", isError: true };
|
|
45
|
+
}
|
|
46
|
+
if (!ctx.lspManager.isConnected()) {
|
|
47
|
+
return { content: "No LSP servers are connected.", isError: true };
|
|
48
|
+
}
|
|
49
|
+
const op = args.operation;
|
|
50
|
+
const filePath = args.filePath;
|
|
51
|
+
const line = args.line ?? 1;
|
|
52
|
+
const character = args.character ?? 1;
|
|
53
|
+
try {
|
|
54
|
+
switch (op) {
|
|
55
|
+
case "goToDefinition": {
|
|
56
|
+
if (!filePath) return { content: "filePath is required for goToDefinition", isError: true };
|
|
57
|
+
const result = await ctx.lspManager.sendRequest(
|
|
58
|
+
filePath,
|
|
59
|
+
"textDocument/definition",
|
|
60
|
+
{
|
|
61
|
+
textDocument: { uri: `file://${filePath}` },
|
|
62
|
+
position: { line: line - 1, character: character - 1 }
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
return { content: formatLocations("Definition", result) };
|
|
66
|
+
}
|
|
67
|
+
case "findReferences": {
|
|
68
|
+
if (!filePath) return { content: "filePath is required for findReferences", isError: true };
|
|
69
|
+
const result = await ctx.lspManager.sendRequest(
|
|
70
|
+
filePath,
|
|
71
|
+
"textDocument/references",
|
|
72
|
+
{
|
|
73
|
+
textDocument: { uri: `file://${filePath}` },
|
|
74
|
+
position: { line: line - 1, character: character - 1 },
|
|
75
|
+
context: { includeDeclaration: true }
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
return { content: formatLocations("References", result) };
|
|
79
|
+
}
|
|
80
|
+
case "hover": {
|
|
81
|
+
if (!filePath) return { content: "filePath is required for hover", isError: true };
|
|
82
|
+
const result = await ctx.lspManager.sendRequest(
|
|
83
|
+
filePath,
|
|
84
|
+
"textDocument/hover",
|
|
85
|
+
{
|
|
86
|
+
textDocument: { uri: `file://${filePath}` },
|
|
87
|
+
position: { line: line - 1, character: character - 1 }
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
if (!result) return { content: "No hover information available." };
|
|
91
|
+
return { content: formatHover(result.contents) };
|
|
92
|
+
}
|
|
93
|
+
case "documentSymbol": {
|
|
94
|
+
if (!filePath) return { content: "filePath is required for documentSymbol", isError: true };
|
|
95
|
+
const result = await ctx.lspManager.sendRequest(
|
|
96
|
+
filePath,
|
|
97
|
+
"textDocument/documentSymbol",
|
|
98
|
+
{ textDocument: { uri: `file://${filePath}` } }
|
|
99
|
+
);
|
|
100
|
+
return { content: formatDocumentSymbols(result) };
|
|
101
|
+
}
|
|
102
|
+
case "workspaceSymbol": {
|
|
103
|
+
const query = args.query ?? "";
|
|
104
|
+
const firstFile = filePath ?? "";
|
|
105
|
+
const result = await ctx.lspManager.sendRequest(
|
|
106
|
+
firstFile,
|
|
107
|
+
"workspace/symbol",
|
|
108
|
+
{ query }
|
|
109
|
+
);
|
|
110
|
+
return { content: formatWorkspaceSymbols(result) };
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
return { content: `Unknown LSP operation: ${op}`, isError: true };
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
117
|
+
return { content: `LSP error: ${message}`, isError: true };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
function formatLocations(label, result) {
|
|
122
|
+
if (!result) return `${label}: No results found.`;
|
|
123
|
+
const arr = Array.isArray(result) ? result : [result];
|
|
124
|
+
if (arr.length === 0) return `${label}: No results found.`;
|
|
125
|
+
const lines = arr.map((loc) => {
|
|
126
|
+
const path = loc.uri.replace("file://", "");
|
|
127
|
+
return ` ${path}:${loc.range.start.line + 1}:${loc.range.start.character + 1}`;
|
|
128
|
+
});
|
|
129
|
+
return `${label} (${arr.length} result${arr.length > 1 ? "s" : ""}):
|
|
130
|
+
${lines.join("\n")}`;
|
|
131
|
+
}
|
|
132
|
+
function formatHover(contents) {
|
|
133
|
+
if (typeof contents === "string") return contents;
|
|
134
|
+
if ("value" in contents) return contents.value;
|
|
135
|
+
return contents.map((c) => typeof c === "string" ? c : c.value).join("\n\n");
|
|
136
|
+
}
|
|
137
|
+
function formatDocumentSymbols(symbols, indent = 0) {
|
|
138
|
+
if (!symbols || symbols.length === 0) return "No symbols found.";
|
|
139
|
+
const prefix = " ".repeat(indent);
|
|
140
|
+
return symbols.map((s) => {
|
|
141
|
+
const line = `${prefix}${symbolKindName(s.kind)} ${s.name} (line ${s.range.start.line + 1})`;
|
|
142
|
+
if (s.children?.length) {
|
|
143
|
+
return line + "\n" + formatDocumentSymbols(s.children, indent + 1);
|
|
144
|
+
}
|
|
145
|
+
return line;
|
|
146
|
+
}).join("\n");
|
|
147
|
+
}
|
|
148
|
+
function formatWorkspaceSymbols(symbols) {
|
|
149
|
+
if (!symbols || symbols.length === 0) return "No symbols found.";
|
|
150
|
+
return symbols.slice(0, 100).map((s) => {
|
|
151
|
+
const path = s.location.uri.replace("file://", "");
|
|
152
|
+
const loc = `${path}:${s.location.range.start.line + 1}`;
|
|
153
|
+
const container = s.containerName ? ` (in ${s.containerName})` : "";
|
|
154
|
+
return ` ${symbolKindName(s.kind)} ${s.name}${container} \u2014 ${loc}`;
|
|
155
|
+
}).join("\n");
|
|
156
|
+
}
|
|
157
|
+
var SYMBOL_KINDS = {
|
|
158
|
+
1: "File",
|
|
159
|
+
2: "Module",
|
|
160
|
+
3: "Namespace",
|
|
161
|
+
4: "Package",
|
|
162
|
+
5: "Class",
|
|
163
|
+
6: "Method",
|
|
164
|
+
7: "Property",
|
|
165
|
+
8: "Field",
|
|
166
|
+
9: "Constructor",
|
|
167
|
+
10: "Enum",
|
|
168
|
+
11: "Interface",
|
|
169
|
+
12: "Function",
|
|
170
|
+
13: "Variable",
|
|
171
|
+
14: "Constant",
|
|
172
|
+
15: "String",
|
|
173
|
+
16: "Number",
|
|
174
|
+
17: "Boolean",
|
|
175
|
+
18: "Array",
|
|
176
|
+
19: "Object",
|
|
177
|
+
20: "Key",
|
|
178
|
+
21: "Null",
|
|
179
|
+
22: "EnumMember",
|
|
180
|
+
23: "Struct",
|
|
181
|
+
24: "Event",
|
|
182
|
+
25: "Operator",
|
|
183
|
+
26: "TypeParameter"
|
|
184
|
+
};
|
|
185
|
+
function symbolKindName(kind) {
|
|
186
|
+
return SYMBOL_KINDS[kind] ?? `Kind(${kind})`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
lspTool
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=chunk-UVSSQBDY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/lsp.ts"],"sourcesContent":["import type { Tool } from \"./types.js\";\nimport type { LspLocation, LspSymbol } from \"../lsp/types.js\";\n\nexport const lspTool: Tool = {\n name: \"LSP\",\n description:\n \"Query language servers for code intelligence. Supports: goToDefinition, \" +\n \"findReferences, hover, documentSymbol, workspaceSymbol. \" +\n \"Line and character are 1-based.\",\n parameters: {\n type: \"object\",\n properties: {\n operation: {\n type: \"string\",\n description: \"The LSP operation to perform\",\n enum: [\n \"goToDefinition\",\n \"findReferences\",\n \"hover\",\n \"documentSymbol\",\n \"workspaceSymbol\",\n ],\n },\n filePath: {\n type: \"string\",\n description: \"Absolute path to the file (required for all except workspaceSymbol)\",\n },\n line: {\n type: \"number\",\n description: \"1-based line number (required for definition/references/hover)\",\n minimum: 1,\n },\n character: {\n type: \"number\",\n description: \"1-based character offset (required for definition/references/hover)\",\n minimum: 1,\n },\n query: {\n type: \"string\",\n description: \"Search query for workspaceSymbol (optional, empty = all)\",\n },\n },\n required: [\"operation\"],\n },\n isReadOnly: true,\n isConcurrencySafe: true,\n\n async call(args, ctx) {\n if (!ctx.lspManager) {\n return { content: \"LSP is not configured.\", isError: true };\n }\n if (!ctx.lspManager.isConnected()) {\n return { content: \"No LSP servers are connected.\", isError: true };\n }\n\n const op = args.operation as string;\n const filePath = args.filePath as string | undefined;\n const line = (args.line as number | undefined) ?? 1;\n const character = (args.character as number | undefined) ?? 1;\n\n try {\n switch (op) {\n case \"goToDefinition\": {\n if (!filePath) return { content: \"filePath is required for goToDefinition\", isError: true };\n const result = await ctx.lspManager.sendRequest<LspLocationResult | LspLocationResult[]>(\n filePath,\n \"textDocument/definition\",\n {\n textDocument: { uri: `file://${filePath}` },\n position: { line: line - 1, character: character - 1 },\n },\n );\n return { content: formatLocations(\"Definition\", result) };\n }\n\n case \"findReferences\": {\n if (!filePath) return { content: \"filePath is required for findReferences\", isError: true };\n const result = await ctx.lspManager.sendRequest<LspLocationResult[]>(\n filePath,\n \"textDocument/references\",\n {\n textDocument: { uri: `file://${filePath}` },\n position: { line: line - 1, character: character - 1 },\n context: { includeDeclaration: true },\n },\n );\n return { content: formatLocations(\"References\", result) };\n }\n\n case \"hover\": {\n if (!filePath) return { content: \"filePath is required for hover\", isError: true };\n const result = await ctx.lspManager.sendRequest<{ contents: string | { value: string } | Array<string | { value: string }> } | null>(\n filePath,\n \"textDocument/hover\",\n {\n textDocument: { uri: `file://${filePath}` },\n position: { line: line - 1, character: character - 1 },\n },\n );\n if (!result) return { content: \"No hover information available.\" };\n return { content: formatHover(result.contents) };\n }\n\n case \"documentSymbol\": {\n if (!filePath) return { content: \"filePath is required for documentSymbol\", isError: true };\n const result = await ctx.lspManager.sendRequest<LspDocumentSymbol[]>(\n filePath,\n \"textDocument/documentSymbol\",\n { textDocument: { uri: `file://${filePath}` } },\n );\n return { content: formatDocumentSymbols(result) };\n }\n\n case \"workspaceSymbol\": {\n const query = (args.query as string) ?? \"\";\n const firstFile = filePath ?? \"\";\n const result = await ctx.lspManager.sendRequest<LspWorkspaceSymbol[]>(\n firstFile,\n \"workspace/symbol\",\n { query },\n );\n return { content: formatWorkspaceSymbols(result) };\n }\n\n default:\n return { content: `Unknown LSP operation: ${op}`, isError: true };\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { content: `LSP error: ${message}`, isError: true };\n }\n },\n};\n\ninterface LspLocationResult {\n uri: string;\n range: { start: { line: number; character: number }; end: { line: number; character: number } };\n}\n\ninterface LspDocumentSymbol {\n name: string;\n kind: number;\n range: { start: { line: number; character: number } };\n children?: LspDocumentSymbol[];\n}\n\ninterface LspWorkspaceSymbol {\n name: string;\n kind: number;\n location: { uri: string; range: { start: { line: number; character: number } } };\n containerName?: string;\n}\n\nfunction formatLocations(\n label: string,\n result: LspLocationResult | LspLocationResult[] | null,\n): string {\n if (!result) return `${label}: No results found.`;\n const arr = Array.isArray(result) ? result : [result];\n if (arr.length === 0) return `${label}: No results found.`;\n\n const lines = arr.map((loc) => {\n const path = loc.uri.replace(\"file://\", \"\");\n return ` ${path}:${loc.range.start.line + 1}:${loc.range.start.character + 1}`;\n });\n return `${label} (${arr.length} result${arr.length > 1 ? \"s\" : \"\"}):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction formatHover(\n contents: string | { value: string } | Array<string | { value: string }>,\n): string {\n if (typeof contents === \"string\") return contents;\n if (\"value\" in contents) return contents.value;\n return contents\n .map((c) => (typeof c === \"string\" ? c : c.value))\n .join(\"\\n\\n\");\n}\n\nfunction formatDocumentSymbols(\n symbols: LspDocumentSymbol[] | null,\n indent = 0,\n): string {\n if (!symbols || symbols.length === 0) return \"No symbols found.\";\n const prefix = \" \".repeat(indent);\n return symbols\n .map((s) => {\n const line = `${prefix}${symbolKindName(s.kind)} ${s.name} (line ${s.range.start.line + 1})`;\n if (s.children?.length) {\n return line + \"\\n\" + formatDocumentSymbols(s.children, indent + 1);\n }\n return line;\n })\n .join(\"\\n\");\n}\n\nfunction formatWorkspaceSymbols(symbols: LspWorkspaceSymbol[] | null): string {\n if (!symbols || symbols.length === 0) return \"No symbols found.\";\n return symbols\n .slice(0, 100)\n .map((s) => {\n const path = s.location.uri.replace(\"file://\", \"\");\n const loc = `${path}:${s.location.range.start.line + 1}`;\n const container = s.containerName ? ` (in ${s.containerName})` : \"\";\n return ` ${symbolKindName(s.kind)} ${s.name}${container} — ${loc}`;\n })\n .join(\"\\n\");\n}\n\nconst SYMBOL_KINDS: Record<number, string> = {\n 1: \"File\", 2: \"Module\", 3: \"Namespace\", 4: \"Package\",\n 5: \"Class\", 6: \"Method\", 7: \"Property\", 8: \"Field\",\n 9: \"Constructor\", 10: \"Enum\", 11: \"Interface\", 12: \"Function\",\n 13: \"Variable\", 14: \"Constant\", 15: \"String\", 16: \"Number\",\n 17: \"Boolean\", 18: \"Array\", 19: \"Object\", 20: \"Key\",\n 21: \"Null\", 22: \"EnumMember\", 23: \"Struct\", 24: \"Event\",\n 25: \"Operator\", 26: \"TypeParameter\",\n};\n\nfunction symbolKindName(kind: number): string {\n return SYMBOL_KINDS[kind] ?? `Kind(${kind})`;\n}\n"],"mappings":"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","names":[]}
|