blun-king-cli 9.1.25 → 9.1.26
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/blun.mjs +830 -45
- package/package.json +1 -1
package/blun.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// BLUN_BUILD_INPUT_SHA256:
|
|
2
|
+
// BLUN_BUILD_INPUT_SHA256:7d2032417fd49eb3d28a7006057755559c5bb8da252a52c972b2ccc12a33dd14
|
|
3
3
|
import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
4
4
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
5
5
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
@@ -76385,7 +76385,7 @@ var init_telemetry_events = __esmMin((() => {
|
|
|
76385
76385
|
//#endregion
|
|
76386
76386
|
//#region ../../packages/agent-core/src/agent/cron/manager.ts
|
|
76387
76387
|
var STALE_THRESHOLD_MS, CronManager;
|
|
76388
|
-
var init_manager$
|
|
76388
|
+
var init_manager$3 = __esmMin((() => {
|
|
76389
76389
|
init_clock();
|
|
76390
76390
|
init_cron_fire_xml();
|
|
76391
76391
|
init_persist();
|
|
@@ -76797,7 +76797,7 @@ var init_manager$2 = __esmMin((() => {
|
|
|
76797
76797
|
//#endregion
|
|
76798
76798
|
//#region ../../packages/agent-core/src/agent/cron/index.ts
|
|
76799
76799
|
var init_cron$1 = __esmMin((() => {
|
|
76800
|
-
init_manager$
|
|
76800
|
+
init_manager$3();
|
|
76801
76801
|
}));
|
|
76802
76802
|
//#endregion
|
|
76803
76803
|
//#region ../../packages/agent-core/src/tools/policies/sensitive.ts
|
|
@@ -232055,7 +232055,7 @@ var init_mission_contract_bridge = __esmMin((() => {
|
|
|
232055
232055
|
//#endregion
|
|
232056
232056
|
//#region ../../packages/agent-core/src/agent/injection/manager.ts
|
|
232057
232057
|
var ACTIVE_BACKGROUND_TASK_GUIDANCE, InjectionManager;
|
|
232058
|
-
var init_manager$
|
|
232058
|
+
var init_manager$2 = __esmMin((() => {
|
|
232059
232059
|
init_task_list();
|
|
232060
232060
|
init_action_style();
|
|
232061
232061
|
init_error_memory$1();
|
|
@@ -252200,6 +252200,26 @@ var init_edit$1 = __esmMin((() => {
|
|
|
252200
252200
|
edit_default = "Perform exact replacements in existing files.\n\n- Edit is mandatory for every incremental change, especially small edits. DO NOT use Write or Bash `sed`.\n- Read the target file before every Edit. DO NOT call Edit from memory, stale context, or a guessed `old_string`.\n- Take `old_string` and `new_string` from the Read output view.\n- Drop the line-number prefix and tab; match only file content.\n- `old_string` must be unique unless `replace_all` is set.\n- If `old_string` is ambiguous, add surrounding context. Use `replace_all` only when every occurrence should change — for example, renaming a symbol throughout the file.\n- Multiple Edit calls may run in one response only when they do not target the same file.\n- DO NOT issue consecutive Edit calls on the same file. A previous Edit can invalidate a later Edit's `old_string`, causing `old_string not found`. Read the file again before the next Edit.\n- A write lock serializes same-file edits in response order, but serialization does not make stale `old_string` valid.\n- For pure CRLF files, Read shows LF; use LF in `old_string` and `new_string`, and Edit writes CRLF back.\n- For mixed endings or lone carriage returns, Read shows carriage returns as \\r; include actual \\r escapes in those positions.\n- Source files may contain at most 500 lines. An already oversized source may only be edited when the result has fewer lines.\n- Set `single_file_override=true` only when the latest direct user message explicitly requires one single file. The accepted override is reported visibly.\n";
|
|
252201
252201
|
}));
|
|
252202
252202
|
//#endregion
|
|
252203
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/lsp-diagnostics.ts
|
|
252204
|
+
async function appendLspDiagnostics(result, path, lsp) {
|
|
252205
|
+
if (lsp === void 0 || result.isError === true || typeof result.output !== "string") return result;
|
|
252206
|
+
try {
|
|
252207
|
+
const diagnostics = await lsp.diagnosticsAfterChange(path);
|
|
252208
|
+
if (diagnostics === void 0 || diagnostics.length === 0) return result;
|
|
252209
|
+
return {
|
|
252210
|
+
...result,
|
|
252211
|
+
output: `${result.output}\nLSP diagnostics:\n${JSON.stringify(diagnostics, null, 2)}`
|
|
252212
|
+
};
|
|
252213
|
+
} catch (error) {
|
|
252214
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
252215
|
+
return {
|
|
252216
|
+
...result,
|
|
252217
|
+
output: `${result.output}\nLSP diagnostics unavailable: ${message}`
|
|
252218
|
+
};
|
|
252219
|
+
}
|
|
252220
|
+
}
|
|
252221
|
+
var init_lsp_diagnostics = __esmMin((() => {}));
|
|
252222
|
+
//#endregion
|
|
252203
252223
|
//#region ../../packages/agent-core/src/tools/builtin/file/edit.ts
|
|
252204
252224
|
function replaceOnceLiteral(content, oldString, newString) {
|
|
252205
252225
|
const index = content.indexOf(oldString);
|
|
@@ -252216,6 +252236,7 @@ var init_edit = __esmMin((() => {
|
|
|
252216
252236
|
init_line_endings();
|
|
252217
252237
|
init_source_file_line_limit();
|
|
252218
252238
|
init_edit$1();
|
|
252239
|
+
init_lsp_diagnostics();
|
|
252219
252240
|
EditInputSchema = object({
|
|
252220
252241
|
path: string().describe("Path to the text file to edit. Relative paths resolve against the working directory; a path outside the working directory must be absolute."),
|
|
252221
252242
|
old_string: string().min(1).describe("Exact content to replace from the Read output view, without the line-number prefix. Use LF for pure CRLF files; use actual \\r escapes where Read shows \\r."),
|
|
@@ -252227,13 +252248,15 @@ var init_edit = __esmMin((() => {
|
|
|
252227
252248
|
kaos;
|
|
252228
252249
|
workspace;
|
|
252229
252250
|
history;
|
|
252251
|
+
lsp;
|
|
252230
252252
|
name = "Edit";
|
|
252231
252253
|
description = edit_default;
|
|
252232
252254
|
parameters = toInputJsonSchema(EditInputSchema);
|
|
252233
|
-
constructor(kaos, workspace, history) {
|
|
252255
|
+
constructor(kaos, workspace, history, lsp) {
|
|
252234
252256
|
this.kaos = kaos;
|
|
252235
252257
|
this.workspace = workspace;
|
|
252236
252258
|
this.history = history;
|
|
252259
|
+
this.lsp = lsp;
|
|
252237
252260
|
}
|
|
252238
252261
|
resolveExecution(args) {
|
|
252239
252262
|
const path = resolvePathAccessPath(args.path, {
|
|
@@ -252324,7 +252347,7 @@ var init_edit = __esmMin((() => {
|
|
|
252324
252347
|
await this.kaos.writeText(safePath, materialized);
|
|
252325
252348
|
const occurrence = replacementCount === 1 ? "occurrence" : "occurrences";
|
|
252326
252349
|
const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
|
|
252327
|
-
return { output: `Replaced ${String(replacementCount)} ${occurrence} in ${args.path}.` + notice };
|
|
252350
|
+
return appendLspDiagnostics({ output: `Replaced ${String(replacementCount)} ${occurrence} in ${args.path}.` + notice }, safePath, this.lsp);
|
|
252328
252351
|
}
|
|
252329
252352
|
};
|
|
252330
252353
|
}));
|
|
@@ -258411,6 +258434,7 @@ var init_write = __esmMin((() => {
|
|
|
258411
258434
|
init_rule_match();
|
|
258412
258435
|
init_source_file_line_limit();
|
|
258413
258436
|
init_write$1();
|
|
258437
|
+
init_lsp_diagnostics();
|
|
258414
258438
|
S_IFMT = 61440;
|
|
258415
258439
|
S_IFDIR = 16384;
|
|
258416
258440
|
WriteInputSchema = object({
|
|
@@ -258426,13 +258450,15 @@ bytesWritten: number$1().int().nonnegative() });
|
|
|
258426
258450
|
kaos;
|
|
258427
258451
|
workspace;
|
|
258428
258452
|
history;
|
|
258453
|
+
lsp;
|
|
258429
258454
|
name = "Write";
|
|
258430
258455
|
description = write_default;
|
|
258431
258456
|
parameters = toInputJsonSchema(WriteInputSchema);
|
|
258432
|
-
constructor(kaos, workspace, history) {
|
|
258457
|
+
constructor(kaos, workspace, history, lsp) {
|
|
258433
258458
|
this.kaos = kaos;
|
|
258434
258459
|
this.workspace = workspace;
|
|
258435
258460
|
this.history = history;
|
|
258461
|
+
this.lsp = lsp;
|
|
258436
258462
|
}
|
|
258437
258463
|
resolveExecution(args) {
|
|
258438
258464
|
const path = resolvePathAccessPath(args.path, {
|
|
@@ -258489,7 +258515,7 @@ bytesWritten: number$1().int().nonnegative() });
|
|
|
258489
258515
|
else await this.kaos.writeText(safePath, args.content);
|
|
258490
258516
|
const bytesWritten = Buffer.byteLength(args.content, "utf8");
|
|
258491
258517
|
const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
|
|
258492
|
-
return { output: `${mode === "append" ? "Appended" : "Wrote"} ${String(bytesWritten)} bytes to ${args.path}.${notice}` };
|
|
258518
|
+
return appendLspDiagnostics({ output: `${mode === "append" ? "Appended" : "Wrote"} ${String(bytesWritten)} bytes to ${args.path}.${notice}` }, safePath, this.lsp);
|
|
258493
258519
|
} catch (error) {
|
|
258494
258520
|
if (error?.code === "ENOENT") return {
|
|
258495
258521
|
isError: true,
|
|
@@ -261017,6 +261043,83 @@ var init_codebase_search = __esmMin((() => {
|
|
|
261017
261043
|
};
|
|
261018
261044
|
}));
|
|
261019
261045
|
//#endregion
|
|
261046
|
+
//#region ../../packages/agent-core/src/tools/builtin/search/lsp.md?raw
|
|
261047
|
+
var lsp_default;
|
|
261048
|
+
var init_lsp$2 = __esmMin((() => {
|
|
261049
|
+
lsp_default = "Query a configured Language Server Protocol (LSP) server for precise code intelligence.\n\nUse this tool for definitions, references, hover/type information, document or workspace symbols, implementations, and current diagnostics. Line and character positions are one-based. Use `workspace_symbols` with `query`; all other operations require `path`. Position-based operations also require `line` and `character`.\n\nLanguage servers are provided by enabled plugins and start only when first used. If the required server executable is missing, report that exact setup error instead of falling back to a guess.\n";
|
|
261050
|
+
}));
|
|
261051
|
+
//#endregion
|
|
261052
|
+
//#region ../../packages/agent-core/src/tools/builtin/search/lsp.ts
|
|
261053
|
+
var LspInputSchema, LspTool;
|
|
261054
|
+
var init_lsp$1 = __esmMin((() => {
|
|
261055
|
+
init_zod$1();
|
|
261056
|
+
init_tool_access();
|
|
261057
|
+
init_path_access();
|
|
261058
|
+
init_input_schema();
|
|
261059
|
+
init_rule_match();
|
|
261060
|
+
init_lsp$2();
|
|
261061
|
+
LspInputSchema = object({
|
|
261062
|
+
operation: _enum([
|
|
261063
|
+
"definition",
|
|
261064
|
+
"references",
|
|
261065
|
+
"hover",
|
|
261066
|
+
"document_symbols",
|
|
261067
|
+
"workspace_symbols",
|
|
261068
|
+
"implementation",
|
|
261069
|
+
"diagnostics"
|
|
261070
|
+
]),
|
|
261071
|
+
path: string().optional().describe("Source file path, relative to the working directory or absolute."),
|
|
261072
|
+
line: number$1().int().positive().optional().describe("One-based source line."),
|
|
261073
|
+
character: number$1().int().positive().optional().describe("One-based character offset."),
|
|
261074
|
+
query: string().optional().describe("Symbol query for workspace_symbols.")
|
|
261075
|
+
});
|
|
261076
|
+
LspTool = class {
|
|
261077
|
+
service;
|
|
261078
|
+
kaos;
|
|
261079
|
+
workspace;
|
|
261080
|
+
name = "LSP";
|
|
261081
|
+
description = lsp_default;
|
|
261082
|
+
parameters = toInputJsonSchema(LspInputSchema);
|
|
261083
|
+
constructor(service, kaos, workspace) {
|
|
261084
|
+
this.service = service;
|
|
261085
|
+
this.kaos = kaos;
|
|
261086
|
+
this.workspace = workspace;
|
|
261087
|
+
}
|
|
261088
|
+
resolveExecution(args) {
|
|
261089
|
+
const safePath = args.path === void 0 || this.kaos === void 0 || this.workspace === void 0 ? args.path : resolvePathAccessPath(args.path, {
|
|
261090
|
+
kaos: this.kaos,
|
|
261091
|
+
workspace: this.workspace,
|
|
261092
|
+
operation: "read"
|
|
261093
|
+
});
|
|
261094
|
+
return {
|
|
261095
|
+
description: `LSP ${args.operation}${args.path === void 0 ? "" : `: ${args.path}`}`,
|
|
261096
|
+
accesses: safePath === void 0 ? ToolAccesses.searchTree(this.workspace?.workspaceDir ?? ".") : ToolAccesses.readFile(safePath),
|
|
261097
|
+
approvalRule: literalRulePattern(this.name, args.operation),
|
|
261098
|
+
matchesRule: safePath === void 0 || this.kaos === void 0 || this.workspace === void 0 ? void 0 : (ruleArgs) => matchesPathRuleSubject(ruleArgs, safePath, {
|
|
261099
|
+
cwd: this.workspace.workspaceDir,
|
|
261100
|
+
pathClass: this.kaos.pathClass(),
|
|
261101
|
+
homeDir: this.kaos.gethome()
|
|
261102
|
+
}),
|
|
261103
|
+
execute: () => this.execute({
|
|
261104
|
+
...args,
|
|
261105
|
+
path: safePath
|
|
261106
|
+
})
|
|
261107
|
+
};
|
|
261108
|
+
}
|
|
261109
|
+
async execute(args) {
|
|
261110
|
+
try {
|
|
261111
|
+
const result = await this.service.request(args);
|
|
261112
|
+
return { output: JSON.stringify(result ?? null, null, 2) };
|
|
261113
|
+
} catch (error) {
|
|
261114
|
+
return {
|
|
261115
|
+
isError: true,
|
|
261116
|
+
output: error instanceof Error ? error.message : String(error)
|
|
261117
|
+
};
|
|
261118
|
+
}
|
|
261119
|
+
}
|
|
261120
|
+
};
|
|
261121
|
+
}));
|
|
261122
|
+
//#endregion
|
|
261020
261123
|
//#region ../../packages/agent-core/src/tools/builtin/mistake-record.md?raw
|
|
261021
261124
|
var mistake_record_default;
|
|
261022
261125
|
var init_mistake_record$1 = __esmMin((() => {
|
|
@@ -261391,6 +261494,7 @@ var init_builtin = __esmMin((() => {
|
|
|
261391
261494
|
init_fetch_url();
|
|
261392
261495
|
init_web_search();
|
|
261393
261496
|
init_codebase_search();
|
|
261497
|
+
init_lsp$1();
|
|
261394
261498
|
init_mistake_record();
|
|
261395
261499
|
init_blun_media$1();
|
|
261396
261500
|
}));
|
|
@@ -261789,8 +261893,8 @@ var init_tool$1 = __esmMin((() => {
|
|
|
261789
261893
|
const goalToolsEnabled = this.agent.type === "main";
|
|
261790
261894
|
this.builtinTools = new Map([
|
|
261791
261895
|
new ReadTool(kaos, workspace),
|
|
261792
|
-
new WriteTool(kaos, workspace, () => this.agent.context.history),
|
|
261793
|
-
new EditTool(kaos, workspace, () => this.agent.context.history),
|
|
261896
|
+
new WriteTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp),
|
|
261897
|
+
new EditTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp),
|
|
261794
261898
|
new GrepTool(kaos, workspace, this.agent.telemetry),
|
|
261795
261899
|
new GlobTool(kaos, workspace, this.agent.telemetry),
|
|
261796
261900
|
new BashTool(kaos, cwd, background, { allowBackground }),
|
|
@@ -261826,7 +261930,8 @@ var init_tool$1 = __esmMin((() => {
|
|
|
261826
261930
|
toolServices?.media && new LipSyncMediaTool(toolServices.media),
|
|
261827
261931
|
toolServices?.media && new GetMediaTool(toolServices.media),
|
|
261828
261932
|
new MistakeRecordTool(this.agent),
|
|
261829
|
-
new CodebaseSearchTool(cwd)
|
|
261933
|
+
new CodebaseSearchTool(cwd),
|
|
261934
|
+
toolServices?.lsp && new LspTool(toolServices.lsp, kaos, workspace)
|
|
261830
261935
|
].filter((tool) => !!tool).map((tool) => [tool.name, tool]));
|
|
261831
261936
|
}
|
|
261832
261937
|
refreshBuiltinTools() {
|
|
@@ -262220,7 +262325,7 @@ var init_agent = __esmMin((() => {
|
|
|
262220
262325
|
init_error_memory();
|
|
262221
262326
|
init_goal$1();
|
|
262222
262327
|
init_hooks();
|
|
262223
|
-
init_manager$
|
|
262328
|
+
init_manager$2();
|
|
262224
262329
|
init_permission();
|
|
262225
262330
|
init_plan();
|
|
262226
262331
|
init_records();
|
|
@@ -263955,7 +264060,7 @@ var init_ajv_provider = __esmMin((() => {
|
|
|
263955
264060
|
//#endregion
|
|
263956
264061
|
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
|
|
263957
264062
|
var ExperimentalClientTasks;
|
|
263958
|
-
var init_client$
|
|
264063
|
+
var init_client$3 = __esmMin((() => {
|
|
263959
264064
|
init_types$4();
|
|
263960
264065
|
ExperimentalClientTasks = class {
|
|
263961
264066
|
constructor(_client) {
|
|
@@ -264213,12 +264318,12 @@ function getSupportedElicitationModes(capabilities) {
|
|
|
264213
264318
|
};
|
|
264214
264319
|
}
|
|
264215
264320
|
var Client;
|
|
264216
|
-
var init_client$
|
|
264321
|
+
var init_client$2 = __esmMin((() => {
|
|
264217
264322
|
init_protocol();
|
|
264218
264323
|
init_types$4();
|
|
264219
264324
|
init_ajv_provider();
|
|
264220
264325
|
init_zod_compat();
|
|
264221
|
-
init_client$
|
|
264326
|
+
init_client$3();
|
|
264222
264327
|
init_helpers$1();
|
|
264223
264328
|
Client = class extends Protocol {
|
|
264224
264329
|
/**
|
|
@@ -265237,7 +265342,7 @@ function buildMcpHttpHeaders(config, envLookup) {
|
|
|
265237
265342
|
}
|
|
265238
265343
|
var HttpMcpClient;
|
|
265239
265344
|
var init_client_http = __esmMin((() => {
|
|
265240
|
-
init_client$
|
|
265345
|
+
init_client$2();
|
|
265241
265346
|
init_streamableHttp();
|
|
265242
265347
|
init_client_shared();
|
|
265243
265348
|
init_client_remote();
|
|
@@ -265759,7 +265864,7 @@ function isTerminalSseTransportError(error) {
|
|
|
265759
265864
|
}
|
|
265760
265865
|
var SseMcpClient;
|
|
265761
265866
|
var init_client_sse = __esmMin((() => {
|
|
265762
|
-
init_client$
|
|
265867
|
+
init_client$2();
|
|
265763
265868
|
init_sse();
|
|
265764
265869
|
init_client_shared();
|
|
265765
265870
|
init_client_remote();
|
|
@@ -292969,7 +293074,7 @@ var STDERR_BUFFER_CAPACITY, StdioMcpClient, BoundedTail;
|
|
|
292969
293074
|
var init_client_stdio = __esmMin((() => {
|
|
292970
293075
|
init_errors$8();
|
|
292971
293076
|
init_proxy();
|
|
292972
|
-
init_client$
|
|
293077
|
+
init_client$2();
|
|
292973
293078
|
init_stdio();
|
|
292974
293079
|
init_dist$6();
|
|
292975
293080
|
init_client_shared();
|
|
@@ -293235,7 +293340,7 @@ async function withTimeout(promise, timeoutMs, onTimeout) {
|
|
|
293235
293340
|
if (timer !== void 0) clearTimeout(timer);
|
|
293236
293341
|
}
|
|
293237
293342
|
}
|
|
293238
|
-
var DEFAULT_STARTUP_TIMEOUT_MS, McpConnectionManager;
|
|
293343
|
+
var DEFAULT_STARTUP_TIMEOUT_MS$1, McpConnectionManager;
|
|
293239
293344
|
var init_connection_manager = __esmMin((() => {
|
|
293240
293345
|
init_errors$8();
|
|
293241
293346
|
init_logger$1();
|
|
@@ -293246,7 +293351,7 @@ var init_connection_manager = __esmMin((() => {
|
|
|
293246
293351
|
init_client_stdio();
|
|
293247
293352
|
init_public_display();
|
|
293248
293353
|
init_types$1();
|
|
293249
|
-
DEFAULT_STARTUP_TIMEOUT_MS = 3e4;
|
|
293354
|
+
DEFAULT_STARTUP_TIMEOUT_MS$1 = 3e4;
|
|
293250
293355
|
McpConnectionManager = class {
|
|
293251
293356
|
options;
|
|
293252
293357
|
entries = /* @__PURE__ */ new Map();
|
|
@@ -293403,7 +293508,7 @@ var init_connection_manager = __esmMin((() => {
|
|
|
293403
293508
|
await Promise.allSettled(tasks);
|
|
293404
293509
|
}
|
|
293405
293510
|
async connectOne(entry, attemptId) {
|
|
293406
|
-
const timeoutMs = entry.config.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
293511
|
+
const timeoutMs = entry.config.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS$1;
|
|
293407
293512
|
let client;
|
|
293408
293513
|
try {
|
|
293409
293514
|
const startupClient = this.createClient(entry.config, entry.name);
|
|
@@ -293745,6 +293850,446 @@ var init_legacy_memory = __esmMin((() => {
|
|
|
293745
293850
|
LEGACY_LOCAL_MEMORY_SAVE = "When the user tells you something worth remembering (preferences, facts about them, project context, corrections), SAVE it:";
|
|
293746
293851
|
}));
|
|
293747
293852
|
//#endregion
|
|
293853
|
+
//#region ../../packages/agent-core/src/lsp/client.ts
|
|
293854
|
+
async function waitForExit$1(child, timeoutMs) {
|
|
293855
|
+
if (child.exitCode !== null) return;
|
|
293856
|
+
await Promise.race([new Promise((resolve) => {
|
|
293857
|
+
child.once("exit", () => resolve());
|
|
293858
|
+
}), delay(timeoutMs)]);
|
|
293859
|
+
}
|
|
293860
|
+
function delay(timeoutMs) {
|
|
293861
|
+
return new Promise((resolve) => {
|
|
293862
|
+
setTimeout(resolve, timeoutMs).unref?.();
|
|
293863
|
+
});
|
|
293864
|
+
}
|
|
293865
|
+
var DEFAULT_STARTUP_TIMEOUT_MS, DEFAULT_SHUTDOWN_TIMEOUT_MS, REQUEST_TIMEOUT_MS, StdioLspClient;
|
|
293866
|
+
var init_client$1 = __esmMin((() => {
|
|
293867
|
+
DEFAULT_STARTUP_TIMEOUT_MS = 1e4;
|
|
293868
|
+
DEFAULT_SHUTDOWN_TIMEOUT_MS = 2e3;
|
|
293869
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
293870
|
+
StdioLspClient = class {
|
|
293871
|
+
name;
|
|
293872
|
+
config;
|
|
293873
|
+
cwd;
|
|
293874
|
+
process;
|
|
293875
|
+
startPromise;
|
|
293876
|
+
stdout = Buffer.alloc(0);
|
|
293877
|
+
nextId = 1;
|
|
293878
|
+
stopped = false;
|
|
293879
|
+
_generation = 0;
|
|
293880
|
+
pending = /* @__PURE__ */ new Map();
|
|
293881
|
+
diagnosticsByUri = /* @__PURE__ */ new Map();
|
|
293882
|
+
diagnosticsWaiters = /* @__PURE__ */ new Map();
|
|
293883
|
+
constructor(name, config, cwd) {
|
|
293884
|
+
this.name = name;
|
|
293885
|
+
this.config = config;
|
|
293886
|
+
this.cwd = cwd;
|
|
293887
|
+
}
|
|
293888
|
+
get running() {
|
|
293889
|
+
return this.process !== void 0 && this.process.exitCode === null && !this.stopped;
|
|
293890
|
+
}
|
|
293891
|
+
get generation() {
|
|
293892
|
+
return this._generation;
|
|
293893
|
+
}
|
|
293894
|
+
async start() {
|
|
293895
|
+
if (this.running) return;
|
|
293896
|
+
if (this.startPromise !== void 0) return this.startPromise;
|
|
293897
|
+
this.startPromise = this.startInternal().catch((error) => {
|
|
293898
|
+
this.startPromise = void 0;
|
|
293899
|
+
throw error;
|
|
293900
|
+
});
|
|
293901
|
+
return this.startPromise;
|
|
293902
|
+
}
|
|
293903
|
+
async request(method, params) {
|
|
293904
|
+
await this.start();
|
|
293905
|
+
return this.sendRequest(method, params, REQUEST_TIMEOUT_MS);
|
|
293906
|
+
}
|
|
293907
|
+
notify(method, params) {
|
|
293908
|
+
if (!this.running) throw new Error(`LSP server "${this.name}" is not running`);
|
|
293909
|
+
this.write({
|
|
293910
|
+
jsonrpc: "2.0",
|
|
293911
|
+
method,
|
|
293912
|
+
params
|
|
293913
|
+
});
|
|
293914
|
+
}
|
|
293915
|
+
diagnostics(uri) {
|
|
293916
|
+
return this.diagnosticsByUri.get(uri);
|
|
293917
|
+
}
|
|
293918
|
+
clearDiagnostics(uri) {
|
|
293919
|
+
this.diagnosticsByUri.delete(uri);
|
|
293920
|
+
}
|
|
293921
|
+
async waitForDiagnostics(uri, timeoutMs = 300) {
|
|
293922
|
+
const current = this.diagnosticsByUri.get(uri);
|
|
293923
|
+
if (current !== void 0) return current;
|
|
293924
|
+
let notify;
|
|
293925
|
+
const notification = new Promise((resolve) => {
|
|
293926
|
+
notify = resolve;
|
|
293927
|
+
const waiters = this.diagnosticsWaiters.get(uri) ?? [];
|
|
293928
|
+
waiters.push(resolve);
|
|
293929
|
+
this.diagnosticsWaiters.set(uri, waiters);
|
|
293930
|
+
});
|
|
293931
|
+
await Promise.race([notification, delay(timeoutMs)]);
|
|
293932
|
+
const waiters = this.diagnosticsWaiters.get(uri);
|
|
293933
|
+
if (waiters !== void 0) {
|
|
293934
|
+
const remaining = waiters.filter((waiter) => waiter !== notify);
|
|
293935
|
+
if (remaining.length === 0) this.diagnosticsWaiters.delete(uri);
|
|
293936
|
+
else this.diagnosticsWaiters.set(uri, remaining);
|
|
293937
|
+
}
|
|
293938
|
+
return this.diagnosticsByUri.get(uri) ?? [];
|
|
293939
|
+
}
|
|
293940
|
+
async shutdown() {
|
|
293941
|
+
this.stopped = true;
|
|
293942
|
+
const child = this.process;
|
|
293943
|
+
if (child === void 0 || child.exitCode !== null) return;
|
|
293944
|
+
try {
|
|
293945
|
+
await this.sendRequest("shutdown", null, this.config.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS);
|
|
293946
|
+
this.write({
|
|
293947
|
+
jsonrpc: "2.0",
|
|
293948
|
+
method: "exit",
|
|
293949
|
+
params: null
|
|
293950
|
+
});
|
|
293951
|
+
} catch {}
|
|
293952
|
+
await waitForExit$1(child, this.config.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS);
|
|
293953
|
+
if (child.exitCode === null) child.kill();
|
|
293954
|
+
this.process = void 0;
|
|
293955
|
+
this.startPromise = void 0;
|
|
293956
|
+
}
|
|
293957
|
+
async startInternal() {
|
|
293958
|
+
this.stopped = false;
|
|
293959
|
+
const child = spawn(this.config.command, [...this.config.args ?? []], {
|
|
293960
|
+
cwd: this.config.workspaceFolder ?? this.cwd,
|
|
293961
|
+
env: {
|
|
293962
|
+
...process.env,
|
|
293963
|
+
...this.config.env
|
|
293964
|
+
},
|
|
293965
|
+
stdio: [
|
|
293966
|
+
"pipe",
|
|
293967
|
+
"pipe",
|
|
293968
|
+
"pipe"
|
|
293969
|
+
],
|
|
293970
|
+
windowsHide: true
|
|
293971
|
+
});
|
|
293972
|
+
this.process = child;
|
|
293973
|
+
child.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
293974
|
+
child.stderr.on("data", () => {});
|
|
293975
|
+
child.once("error", (error) => this.failProcess(error));
|
|
293976
|
+
child.once("exit", (code, signal) => {
|
|
293977
|
+
if (!this.stopped) this.failProcess(/* @__PURE__ */ new Error(`LSP server "${this.name}" exited unexpectedly (${code === null ? signal : String(code)})`));
|
|
293978
|
+
});
|
|
293979
|
+
const rootPath = this.config.workspaceFolder ?? this.cwd;
|
|
293980
|
+
const rootUri = pathToFileURL(rootPath).href;
|
|
293981
|
+
try {
|
|
293982
|
+
await this.sendRequest("initialize", {
|
|
293983
|
+
processId: process.pid,
|
|
293984
|
+
clientInfo: {
|
|
293985
|
+
name: "BLUN Code",
|
|
293986
|
+
version: "1"
|
|
293987
|
+
},
|
|
293988
|
+
rootPath,
|
|
293989
|
+
rootUri,
|
|
293990
|
+
workspaceFolders: [{
|
|
293991
|
+
uri: rootUri,
|
|
293992
|
+
name: this.name
|
|
293993
|
+
}],
|
|
293994
|
+
capabilities: {
|
|
293995
|
+
textDocument: {
|
|
293996
|
+
hover: { contentFormat: ["markdown", "plaintext"] },
|
|
293997
|
+
definition: { linkSupport: true },
|
|
293998
|
+
implementation: { linkSupport: true },
|
|
293999
|
+
publishDiagnostics: { relatedInformation: true }
|
|
294000
|
+
},
|
|
294001
|
+
workspace: { symbol: { resolveSupport: { properties: ["location.range"] } } }
|
|
294002
|
+
},
|
|
294003
|
+
initializationOptions: this.config.initializationOptions
|
|
294004
|
+
}, this.config.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS);
|
|
294005
|
+
this.notify("initialized", {});
|
|
294006
|
+
this._generation++;
|
|
294007
|
+
if (this.config.settings !== void 0) this.notify("workspace/didChangeConfiguration", { settings: this.config.settings });
|
|
294008
|
+
} catch (error) {
|
|
294009
|
+
if (child.exitCode === null) child.kill();
|
|
294010
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
294011
|
+
throw new Error(`Failed to start LSP server "${this.name}" (${this.config.command}): ${message}`, { cause: error });
|
|
294012
|
+
}
|
|
294013
|
+
}
|
|
294014
|
+
sendRequest(method, params, timeoutMs) {
|
|
294015
|
+
const id = this.nextId++;
|
|
294016
|
+
return new Promise((resolve, reject) => {
|
|
294017
|
+
const timer = setTimeout(() => {
|
|
294018
|
+
this.pending.delete(id);
|
|
294019
|
+
reject(/* @__PURE__ */ new Error(`LSP request "${method}" timed out after ${String(timeoutMs)} ms`));
|
|
294020
|
+
}, timeoutMs);
|
|
294021
|
+
timer.unref?.();
|
|
294022
|
+
this.pending.set(id, {
|
|
294023
|
+
resolve,
|
|
294024
|
+
reject,
|
|
294025
|
+
timer
|
|
294026
|
+
});
|
|
294027
|
+
try {
|
|
294028
|
+
this.write({
|
|
294029
|
+
jsonrpc: "2.0",
|
|
294030
|
+
id,
|
|
294031
|
+
method,
|
|
294032
|
+
params
|
|
294033
|
+
});
|
|
294034
|
+
} catch (error) {
|
|
294035
|
+
clearTimeout(timer);
|
|
294036
|
+
this.pending.delete(id);
|
|
294037
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
294038
|
+
}
|
|
294039
|
+
});
|
|
294040
|
+
}
|
|
294041
|
+
write(message) {
|
|
294042
|
+
const stdin = this.process?.stdin;
|
|
294043
|
+
if (stdin === void 0 || stdin.destroyed) throw new Error(`LSP server "${this.name}" is not available`);
|
|
294044
|
+
const body = Buffer.from(JSON.stringify(message), "utf8");
|
|
294045
|
+
stdin.write(`Content-Length: ${String(body.length)}\r\n\r\n`);
|
|
294046
|
+
stdin.write(body);
|
|
294047
|
+
}
|
|
294048
|
+
onStdout(chunk) {
|
|
294049
|
+
this.stdout = Buffer.concat([this.stdout, chunk]);
|
|
294050
|
+
while (true) {
|
|
294051
|
+
const headerEnd = this.stdout.indexOf("\r\n\r\n");
|
|
294052
|
+
if (headerEnd < 0) return;
|
|
294053
|
+
const header = this.stdout.subarray(0, headerEnd).toString("ascii");
|
|
294054
|
+
const match = /(?:^|\r\n)Content-Length:\s*(\d+)/i.exec(header);
|
|
294055
|
+
if (match === null) {
|
|
294056
|
+
this.failProcess(/* @__PURE__ */ new Error(`Invalid LSP response header from "${this.name}"`));
|
|
294057
|
+
return;
|
|
294058
|
+
}
|
|
294059
|
+
const length = Number(match[1]);
|
|
294060
|
+
const bodyStart = headerEnd + 4;
|
|
294061
|
+
if (this.stdout.length < bodyStart + length) return;
|
|
294062
|
+
const body = this.stdout.subarray(bodyStart, bodyStart + length).toString("utf8");
|
|
294063
|
+
this.stdout = this.stdout.subarray(bodyStart + length);
|
|
294064
|
+
try {
|
|
294065
|
+
this.handleMessage(JSON.parse(body));
|
|
294066
|
+
} catch (error) {
|
|
294067
|
+
this.failProcess(error instanceof Error ? error : new Error(String(error)));
|
|
294068
|
+
return;
|
|
294069
|
+
}
|
|
294070
|
+
}
|
|
294071
|
+
}
|
|
294072
|
+
handleMessage(message) {
|
|
294073
|
+
if (message.id !== void 0 && message.method !== void 0) {
|
|
294074
|
+
this.handleServerRequest(message.id, message.method, message.params);
|
|
294075
|
+
return;
|
|
294076
|
+
}
|
|
294077
|
+
if (message.id !== void 0) {
|
|
294078
|
+
const pending = this.pending.get(message.id);
|
|
294079
|
+
if (pending === void 0) return;
|
|
294080
|
+
clearTimeout(pending.timer);
|
|
294081
|
+
this.pending.delete(message.id);
|
|
294082
|
+
if (message.error !== void 0) pending.reject(/* @__PURE__ */ new Error(`LSP request failed${message.error.code === void 0 ? "" : ` (${String(message.error.code)})`}: ${message.error.message ?? "unknown error"}`));
|
|
294083
|
+
else pending.resolve(message.result);
|
|
294084
|
+
return;
|
|
294085
|
+
}
|
|
294086
|
+
if (message.method !== "textDocument/publishDiagnostics") return;
|
|
294087
|
+
const params = message.params;
|
|
294088
|
+
if (typeof params?.uri !== "string" || !Array.isArray(params.diagnostics)) return;
|
|
294089
|
+
this.diagnosticsByUri.set(params.uri, params.diagnostics);
|
|
294090
|
+
const waiters = this.diagnosticsWaiters.get(params.uri) ?? [];
|
|
294091
|
+
this.diagnosticsWaiters.delete(params.uri);
|
|
294092
|
+
for (const resolve of waiters) resolve();
|
|
294093
|
+
}
|
|
294094
|
+
handleServerRequest(id, method, params) {
|
|
294095
|
+
if (method === "workspace/configuration") {
|
|
294096
|
+
const items = params?.items;
|
|
294097
|
+
const count = Array.isArray(items) ? items.length : 0;
|
|
294098
|
+
this.write({
|
|
294099
|
+
jsonrpc: "2.0",
|
|
294100
|
+
id,
|
|
294101
|
+
result: Array.from({ length: count }, () => this.config.settings ?? null)
|
|
294102
|
+
});
|
|
294103
|
+
return;
|
|
294104
|
+
}
|
|
294105
|
+
if (method === "workspace/workspaceFolders") {
|
|
294106
|
+
const rootPath = this.config.workspaceFolder ?? this.cwd;
|
|
294107
|
+
this.write({
|
|
294108
|
+
jsonrpc: "2.0",
|
|
294109
|
+
id,
|
|
294110
|
+
result: [{
|
|
294111
|
+
uri: pathToFileURL(rootPath).href,
|
|
294112
|
+
name: this.name
|
|
294113
|
+
}]
|
|
294114
|
+
});
|
|
294115
|
+
return;
|
|
294116
|
+
}
|
|
294117
|
+
if (method === "client/registerCapability" || method === "client/unregisterCapability" || method === "window/workDoneProgress/create") {
|
|
294118
|
+
this.write({
|
|
294119
|
+
jsonrpc: "2.0",
|
|
294120
|
+
id,
|
|
294121
|
+
result: null
|
|
294122
|
+
});
|
|
294123
|
+
return;
|
|
294124
|
+
}
|
|
294125
|
+
this.write({
|
|
294126
|
+
jsonrpc: "2.0",
|
|
294127
|
+
id,
|
|
294128
|
+
error: {
|
|
294129
|
+
code: -32601,
|
|
294130
|
+
message: `Client method not supported: ${method}`
|
|
294131
|
+
}
|
|
294132
|
+
});
|
|
294133
|
+
}
|
|
294134
|
+
failProcess(error) {
|
|
294135
|
+
const wrapped = new Error(`LSP server "${this.name}" (${this.config.command}) failed: ${error.message}`, { cause: error });
|
|
294136
|
+
for (const pending of this.pending.values()) {
|
|
294137
|
+
clearTimeout(pending.timer);
|
|
294138
|
+
pending.reject(wrapped);
|
|
294139
|
+
}
|
|
294140
|
+
this.pending.clear();
|
|
294141
|
+
this.process = void 0;
|
|
294142
|
+
if (this.config.restartOnCrash !== false && !this.stopped) this.startPromise = void 0;
|
|
294143
|
+
}
|
|
294144
|
+
};
|
|
294145
|
+
}));
|
|
294146
|
+
//#endregion
|
|
294147
|
+
//#region ../../packages/agent-core/src/lsp/manager.ts
|
|
294148
|
+
function methodForOperation(operation) {
|
|
294149
|
+
switch (operation) {
|
|
294150
|
+
case "definition": return "textDocument/definition";
|
|
294151
|
+
case "references": return "textDocument/references";
|
|
294152
|
+
case "hover": return "textDocument/hover";
|
|
294153
|
+
case "document_symbols": return "textDocument/documentSymbol";
|
|
294154
|
+
case "implementation": return "textDocument/implementation";
|
|
294155
|
+
}
|
|
294156
|
+
}
|
|
294157
|
+
function oneBasedToZeroBased(value, name) {
|
|
294158
|
+
if (value === void 0 || !Number.isInteger(value) || value < 1) throw new Error(`LSP operation requires a one-based ${name}`);
|
|
294159
|
+
return value - 1;
|
|
294160
|
+
}
|
|
294161
|
+
function positionFrom(input) {
|
|
294162
|
+
return {
|
|
294163
|
+
line: oneBasedToZeroBased(input.line, "line"),
|
|
294164
|
+
character: oneBasedToZeroBased(input.character, "character")
|
|
294165
|
+
};
|
|
294166
|
+
}
|
|
294167
|
+
var LspManager;
|
|
294168
|
+
var init_manager$1 = __esmMin((() => {
|
|
294169
|
+
init_client$1();
|
|
294170
|
+
LspManager = class {
|
|
294171
|
+
options;
|
|
294172
|
+
clients = /* @__PURE__ */ new Map();
|
|
294173
|
+
openedDocuments = /* @__PURE__ */ new Map();
|
|
294174
|
+
constructor(options) {
|
|
294175
|
+
this.options = options;
|
|
294176
|
+
}
|
|
294177
|
+
serverNames() {
|
|
294178
|
+
return Object.keys(this.options.servers).toSorted();
|
|
294179
|
+
}
|
|
294180
|
+
runningServerNames() {
|
|
294181
|
+
return [...this.clients.entries()].filter(([, client]) => client.running).map(([name]) => name).toSorted();
|
|
294182
|
+
}
|
|
294183
|
+
async diagnosticsAfterChange(filePath) {
|
|
294184
|
+
const resolvedPath = path.resolve(this.options.cwd, filePath);
|
|
294185
|
+
if (!this.supportsPath(resolvedPath)) return void 0;
|
|
294186
|
+
const diagnostics = await this.request({
|
|
294187
|
+
operation: "diagnostics",
|
|
294188
|
+
path: resolvedPath
|
|
294189
|
+
});
|
|
294190
|
+
return Array.isArray(diagnostics) ? diagnostics : [];
|
|
294191
|
+
}
|
|
294192
|
+
async request(input) {
|
|
294193
|
+
if (input.operation === "workspace_symbols") {
|
|
294194
|
+
if (input.query === void 0) throw new Error("workspace_symbols requires query");
|
|
294195
|
+
const results = await Promise.allSettled(this.serverNames().map(async (name) => {
|
|
294196
|
+
const result = await this.client(name, this.options.servers[name]).request("workspace/symbol", { query: input.query });
|
|
294197
|
+
return Array.isArray(result) ? result : [];
|
|
294198
|
+
}));
|
|
294199
|
+
const fulfilled = results.filter((result) => result.status === "fulfilled");
|
|
294200
|
+
if (fulfilled.length === 0) throw results.find((result) => result.status === "rejected")?.reason ?? /* @__PURE__ */ new Error("No LSP servers are configured");
|
|
294201
|
+
return fulfilled.flatMap((result) => result.value);
|
|
294202
|
+
}
|
|
294203
|
+
const documentPath = this.requireDocumentPath(input.path);
|
|
294204
|
+
const { client, languageId } = this.clientForPath(documentPath);
|
|
294205
|
+
const uri = pathToFileURL(documentPath).href;
|
|
294206
|
+
await this.openOrUpdateDocument(client, uri, documentPath, languageId);
|
|
294207
|
+
if (input.operation === "diagnostics") return client.waitForDiagnostics(uri);
|
|
294208
|
+
const method = methodForOperation(input.operation);
|
|
294209
|
+
const params = input.operation === "document_symbols" ? { textDocument: { uri } } : input.operation === "references" ? {
|
|
294210
|
+
textDocument: { uri },
|
|
294211
|
+
position: positionFrom(input),
|
|
294212
|
+
context: { includeDeclaration: true }
|
|
294213
|
+
} : {
|
|
294214
|
+
textDocument: { uri },
|
|
294215
|
+
position: positionFrom(input)
|
|
294216
|
+
};
|
|
294217
|
+
return client.request(method, params);
|
|
294218
|
+
}
|
|
294219
|
+
async shutdown() {
|
|
294220
|
+
await Promise.allSettled([...this.clients.values()].map((client) => client.shutdown()));
|
|
294221
|
+
this.clients.clear();
|
|
294222
|
+
this.openedDocuments.clear();
|
|
294223
|
+
}
|
|
294224
|
+
clientForPath(filePath) {
|
|
294225
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
294226
|
+
for (const [name, config] of Object.entries(this.options.servers)) {
|
|
294227
|
+
const languageId = config.extensionToLanguage[extension];
|
|
294228
|
+
if (languageId !== void 0) return {
|
|
294229
|
+
client: this.client(name, config),
|
|
294230
|
+
languageId
|
|
294231
|
+
};
|
|
294232
|
+
}
|
|
294233
|
+
throw new Error(`No LSP server is configured for "${extension || path.basename(filePath)}". Configured servers: ${this.serverNames().join(", ") || "none"}`);
|
|
294234
|
+
}
|
|
294235
|
+
supportsPath(filePath) {
|
|
294236
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
294237
|
+
return Object.values(this.options.servers).some((config) => config.extensionToLanguage[extension] !== void 0);
|
|
294238
|
+
}
|
|
294239
|
+
client(name, config) {
|
|
294240
|
+
const existing = this.clients.get(name);
|
|
294241
|
+
if (existing !== void 0) return existing;
|
|
294242
|
+
const client = new StdioLspClient(name, config, this.options.cwd);
|
|
294243
|
+
this.clients.set(name, client);
|
|
294244
|
+
return client;
|
|
294245
|
+
}
|
|
294246
|
+
async openOrUpdateDocument(client, uri, filePath, languageId) {
|
|
294247
|
+
await client.start();
|
|
294248
|
+
const text = await readFile(filePath, "utf8");
|
|
294249
|
+
const key = `${client.name}\0${uri}`;
|
|
294250
|
+
const current = this.openedDocuments.get(key);
|
|
294251
|
+
if (current === void 0 || current.generation !== client.generation) {
|
|
294252
|
+
this.openedDocuments.set(key, {
|
|
294253
|
+
text,
|
|
294254
|
+
version: 1,
|
|
294255
|
+
generation: client.generation
|
|
294256
|
+
});
|
|
294257
|
+
client.notify("textDocument/didOpen", { textDocument: {
|
|
294258
|
+
uri,
|
|
294259
|
+
languageId,
|
|
294260
|
+
version: 1,
|
|
294261
|
+
text
|
|
294262
|
+
} });
|
|
294263
|
+
return;
|
|
294264
|
+
}
|
|
294265
|
+
if (current.text === text) return;
|
|
294266
|
+
const version = current.version + 1;
|
|
294267
|
+
this.openedDocuments.set(key, {
|
|
294268
|
+
text,
|
|
294269
|
+
version,
|
|
294270
|
+
generation: client.generation
|
|
294271
|
+
});
|
|
294272
|
+
client.clearDiagnostics(uri);
|
|
294273
|
+
client.notify("textDocument/didChange", {
|
|
294274
|
+
textDocument: {
|
|
294275
|
+
uri,
|
|
294276
|
+
version
|
|
294277
|
+
},
|
|
294278
|
+
contentChanges: [{ text }]
|
|
294279
|
+
});
|
|
294280
|
+
}
|
|
294281
|
+
requireDocumentPath(input) {
|
|
294282
|
+
if (input === void 0 || input.trim().length === 0) throw new Error("LSP operation requires path");
|
|
294283
|
+
return path.resolve(this.options.cwd, input);
|
|
294284
|
+
}
|
|
294285
|
+
};
|
|
294286
|
+
}));
|
|
294287
|
+
//#endregion
|
|
294288
|
+
//#region ../../packages/agent-core/src/lsp/index.ts
|
|
294289
|
+
var init_lsp = __esmMin((() => {
|
|
294290
|
+
init_manager$1();
|
|
294291
|
+
}));
|
|
294292
|
+
//#endregion
|
|
293748
294293
|
//#region ../../packages/agent-core/src/session/index.ts
|
|
293749
294294
|
async function waitForSettlementOrTimeout(promise, timeoutMs) {
|
|
293750
294295
|
let timeout;
|
|
@@ -293789,6 +294334,7 @@ var init_session$1 = __esmMin((() => {
|
|
|
293789
294334
|
init_flags();
|
|
293790
294335
|
init_abort();
|
|
293791
294336
|
init_vision_reader();
|
|
294337
|
+
init_lsp();
|
|
293792
294338
|
init_subagent_host();
|
|
293793
294339
|
BACKGROUND_KEEP_ALIVE_ON_EXIT_ENV = "BLUN_BACKGROUND_KEEP_ALIVE_ON_EXIT";
|
|
293794
294340
|
ACTIVE_TURN_CLOSE_TIMEOUT_MS = 8e3;
|
|
@@ -293800,6 +294346,7 @@ var init_session$1 = __esmMin((() => {
|
|
|
293800
294346
|
skills;
|
|
293801
294347
|
agents = /* @__PURE__ */ new Map();
|
|
293802
294348
|
mcp;
|
|
294349
|
+
lsp;
|
|
293803
294350
|
log;
|
|
293804
294351
|
logHandle;
|
|
293805
294352
|
hookEngine;
|
|
@@ -293849,6 +294396,10 @@ var init_session$1 = __esmMin((() => {
|
|
|
293849
294396
|
log: this.log,
|
|
293850
294397
|
stdioCwd: options.kaos.getcwd()
|
|
293851
294398
|
});
|
|
294399
|
+
this.lsp = options.lspServers === void 0 || Object.keys(options.lspServers).length === 0 ? void 0 : new LspManager({
|
|
294400
|
+
cwd: options.kaos.getcwd(),
|
|
294401
|
+
servers: options.lspServers
|
|
294402
|
+
});
|
|
293852
294403
|
this.mcp.onStatusChange((entry) => {
|
|
293853
294404
|
this.onMcpServerStatusChange(entry);
|
|
293854
294405
|
});
|
|
@@ -293951,7 +294502,7 @@ var init_session$1 = __esmMin((() => {
|
|
|
293951
294502
|
await this.triggerSessionEnd("exit");
|
|
293952
294503
|
} finally {
|
|
293953
294504
|
try {
|
|
293954
|
-
await this.mcp.shutdown();
|
|
294505
|
+
await Promise.allSettled([this.mcp.shutdown(), this.lsp?.shutdown()]);
|
|
293955
294506
|
} finally {
|
|
293956
294507
|
await this.logHandle?.close();
|
|
293957
294508
|
}
|
|
@@ -293963,7 +294514,7 @@ var init_session$1 = __esmMin((() => {
|
|
|
293963
294514
|
await this.flushMetadata();
|
|
293964
294515
|
} finally {
|
|
293965
294516
|
try {
|
|
293966
|
-
await this.mcp.shutdown();
|
|
294517
|
+
await Promise.allSettled([this.mcp.shutdown(), this.lsp?.shutdown()]);
|
|
293967
294518
|
} finally {
|
|
293968
294519
|
await this.logHandle?.close();
|
|
293969
294520
|
}
|
|
@@ -294351,7 +294902,10 @@ var init_session$1 = __esmMin((() => {
|
|
|
294351
294902
|
...config,
|
|
294352
294903
|
type,
|
|
294353
294904
|
kaos: this.toolKaos.withCwd(cwd),
|
|
294354
|
-
toolServices:
|
|
294905
|
+
toolServices: {
|
|
294906
|
+
...this.options.toolServices,
|
|
294907
|
+
lsp: this.lsp
|
|
294908
|
+
},
|
|
294355
294909
|
config: this.options.config,
|
|
294356
294910
|
blunHomeDir: this.options.blunHomeDir,
|
|
294357
294911
|
homedir,
|
|
@@ -294650,6 +295204,7 @@ async function parseManifest(pluginRoot) {
|
|
|
294650
295204
|
skills,
|
|
294651
295205
|
sessionStart: readSessionStart(raw["sessionStart"], diagnostics),
|
|
294652
295206
|
mcpServers: await readMcpServers(pluginRoot, raw["mcpServers"], diagnostics),
|
|
295207
|
+
lspServers: await readLspServers(pluginRoot, raw["lspServers"], diagnostics),
|
|
294653
295208
|
hooks: readHooks(raw["hooks"], diagnostics),
|
|
294654
295209
|
commands: await readCommands(pluginRoot, raw["commands"], diagnostics),
|
|
294655
295210
|
interface: readInterface(raw["interface"]),
|
|
@@ -294798,6 +295353,114 @@ async function readMcpServers(pluginRoot, raw, diagnostics) {
|
|
|
294798
295353
|
}
|
|
294799
295354
|
return Object.keys(out).length === 0 ? void 0 : out;
|
|
294800
295355
|
}
|
|
295356
|
+
async function readLspServers(pluginRoot, manifestValue, diagnostics) {
|
|
295357
|
+
let raw = manifestValue;
|
|
295358
|
+
if (raw === void 0) {
|
|
295359
|
+
const configPath = path.join(pluginRoot, ".lsp.json");
|
|
295360
|
+
if (!await isFile$1(configPath)) return void 0;
|
|
295361
|
+
try {
|
|
295362
|
+
raw = JSON.parse(await readFile(configPath, "utf8"));
|
|
295363
|
+
} catch (error) {
|
|
295364
|
+
diagnostics.push({
|
|
295365
|
+
severity: "warn",
|
|
295366
|
+
message: `Failed to parse .lsp.json: ${error.message}`
|
|
295367
|
+
});
|
|
295368
|
+
return;
|
|
295369
|
+
}
|
|
295370
|
+
}
|
|
295371
|
+
if (!isObject$4(raw)) {
|
|
295372
|
+
diagnostics.push({
|
|
295373
|
+
severity: "warn",
|
|
295374
|
+
message: "\"lspServers\" must be an object"
|
|
295375
|
+
});
|
|
295376
|
+
return;
|
|
295377
|
+
}
|
|
295378
|
+
const out = {};
|
|
295379
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
295380
|
+
const config = await normalizePluginLspServer(pluginRoot, name, value, diagnostics);
|
|
295381
|
+
if (config !== void 0) out[name] = config;
|
|
295382
|
+
}
|
|
295383
|
+
return out;
|
|
295384
|
+
}
|
|
295385
|
+
async function normalizePluginLspServer(pluginRoot, name, raw, diagnostics) {
|
|
295386
|
+
const field = `lspServers.${name}`;
|
|
295387
|
+
if (!isObject$4(raw)) {
|
|
295388
|
+
diagnostics.push({
|
|
295389
|
+
severity: "warn",
|
|
295390
|
+
message: `"${field}" must be an object`
|
|
295391
|
+
});
|
|
295392
|
+
return;
|
|
295393
|
+
}
|
|
295394
|
+
let command = stringField$3(raw, "command");
|
|
295395
|
+
if (command === void 0) {
|
|
295396
|
+
diagnostics.push({
|
|
295397
|
+
severity: "warn",
|
|
295398
|
+
message: `"${field}.command" is required`
|
|
295399
|
+
});
|
|
295400
|
+
return;
|
|
295401
|
+
}
|
|
295402
|
+
const extensionToLanguage = stringRecordField(raw["extensionToLanguage"]);
|
|
295403
|
+
if (extensionToLanguage === void 0 || Object.keys(extensionToLanguage).length === 0) {
|
|
295404
|
+
diagnostics.push({
|
|
295405
|
+
severity: "warn",
|
|
295406
|
+
message: `"${field}.extensionToLanguage" must map at least one extension to a language`
|
|
295407
|
+
});
|
|
295408
|
+
return;
|
|
295409
|
+
}
|
|
295410
|
+
if (command.startsWith("./")) {
|
|
295411
|
+
command = await resolvePluginPathField({
|
|
295412
|
+
pluginRoot,
|
|
295413
|
+
field: `${field}.command`,
|
|
295414
|
+
value: command,
|
|
295415
|
+
diagnostics
|
|
295416
|
+
});
|
|
295417
|
+
if (command === void 0) return void 0;
|
|
295418
|
+
} else if (command.includes("/") || path.isAbsolute(command)) {
|
|
295419
|
+
diagnostics.push({
|
|
295420
|
+
severity: "warn",
|
|
295421
|
+
message: `"${field}.command" must be a PATH command or start with "./"`
|
|
295422
|
+
});
|
|
295423
|
+
return;
|
|
295424
|
+
}
|
|
295425
|
+
let workspaceFolder = stringField$3(raw, "workspaceFolder");
|
|
295426
|
+
if (workspaceFolder !== void 0) {
|
|
295427
|
+
workspaceFolder = await resolvePluginPathField({
|
|
295428
|
+
pluginRoot,
|
|
295429
|
+
field: `${field}.workspaceFolder`,
|
|
295430
|
+
value: workspaceFolder,
|
|
295431
|
+
diagnostics
|
|
295432
|
+
});
|
|
295433
|
+
if (workspaceFolder === void 0) return void 0;
|
|
295434
|
+
}
|
|
295435
|
+
const args = stringArrayField$1(raw, "args");
|
|
295436
|
+
if (raw["args"] !== void 0 && args === void 0) {
|
|
295437
|
+
diagnostics.push({
|
|
295438
|
+
severity: "warn",
|
|
295439
|
+
message: `"${field}.args" must be a string[]`
|
|
295440
|
+
});
|
|
295441
|
+
return;
|
|
295442
|
+
}
|
|
295443
|
+
const env = stringRecordField(raw["env"]);
|
|
295444
|
+
if (raw["env"] !== void 0 && env === void 0) {
|
|
295445
|
+
diagnostics.push({
|
|
295446
|
+
severity: "warn",
|
|
295447
|
+
message: `"${field}.env" must contain string values`
|
|
295448
|
+
});
|
|
295449
|
+
return;
|
|
295450
|
+
}
|
|
295451
|
+
return {
|
|
295452
|
+
command,
|
|
295453
|
+
args,
|
|
295454
|
+
extensionToLanguage,
|
|
295455
|
+
env,
|
|
295456
|
+
initializationOptions: objectField(raw["initializationOptions"]),
|
|
295457
|
+
settings: objectField(raw["settings"]),
|
|
295458
|
+
workspaceFolder,
|
|
295459
|
+
startupTimeoutMs: positiveNumberField(raw["startupTimeoutMs"]),
|
|
295460
|
+
shutdownTimeoutMs: positiveNumberField(raw["shutdownTimeoutMs"]),
|
|
295461
|
+
restartOnCrash: booleanField(raw["restartOnCrash"])
|
|
295462
|
+
};
|
|
295463
|
+
}
|
|
294801
295464
|
function readHooks(raw, diagnostics) {
|
|
294802
295465
|
if (raw === void 0) return void 0;
|
|
294803
295466
|
if (!Array.isArray(raw)) {
|
|
@@ -294945,6 +295608,19 @@ function stringArrayField$1(raw, key) {
|
|
|
294945
295608
|
if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string")) return;
|
|
294946
295609
|
return value;
|
|
294947
295610
|
}
|
|
295611
|
+
function stringRecordField(value) {
|
|
295612
|
+
if (!isObject$4(value) || !Object.values(value).every((entry) => typeof entry === "string")) return;
|
|
295613
|
+
return value;
|
|
295614
|
+
}
|
|
295615
|
+
function objectField(value) {
|
|
295616
|
+
return isObject$4(value) ? value : void 0;
|
|
295617
|
+
}
|
|
295618
|
+
function positiveNumberField(value) {
|
|
295619
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
295620
|
+
}
|
|
295621
|
+
function booleanField(value) {
|
|
295622
|
+
return typeof value === "boolean" ? value : void 0;
|
|
295623
|
+
}
|
|
294948
295624
|
function isObject$4(value) {
|
|
294949
295625
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
294950
295626
|
}
|
|
@@ -295474,7 +296150,7 @@ function pluginMcpServerInfo(record, name, config) {
|
|
|
295474
296150
|
}
|
|
295475
296151
|
function publicPluginManifest(manifest) {
|
|
295476
296152
|
if (manifest === void 0) return void 0;
|
|
295477
|
-
const { mcpServers: _privateMcpServers, ...publicManifest } = manifest;
|
|
296153
|
+
const { mcpServers: _privateMcpServers, lspServers: _privateLspServers, ...publicManifest } = manifest;
|
|
295478
296154
|
return publicManifest;
|
|
295479
296155
|
}
|
|
295480
296156
|
function sanitizePluginOriginalSource(value) {
|
|
@@ -295724,6 +296400,14 @@ var init_manager = __esmMin((() => {
|
|
|
295724
296400
|
enabledMcpServers() {
|
|
295725
296401
|
return Object.fromEntries(this.mcpServerConfigs().filter((entry) => entry.config.enabled !== false).map((entry) => [entry.runtimeName, entry.config]));
|
|
295726
296402
|
}
|
|
296403
|
+
enabledLspServers() {
|
|
296404
|
+
const out = {};
|
|
296405
|
+
for (const record of this.records.values()) {
|
|
296406
|
+
if (!this.runtimeEnabled(record) || record.state !== "ok" || record.manifest === void 0) continue;
|
|
296407
|
+
for (const [name, config] of Object.entries(record.manifest.lspServers ?? {})) out[`plugin-${record.id}:${name}`] = config;
|
|
296408
|
+
}
|
|
296409
|
+
return out;
|
|
296410
|
+
}
|
|
295727
296411
|
/** All installed plugin MCPs, including disabled plugin/server entries. */
|
|
295728
296412
|
mcpServerConfigs() {
|
|
295729
296413
|
const out = [];
|
|
@@ -312945,6 +313629,7 @@ var init_core_impl = __esmMin((() => {
|
|
|
312945
313629
|
permissionRules: config.permission?.rules,
|
|
312946
313630
|
skills: this.resolveSessionSkillConfig(config),
|
|
312947
313631
|
mcpConfig,
|
|
313632
|
+
lspServers: this.plugins.enabledLspServers(),
|
|
312948
313633
|
experimentalFlags: this.experimentalFlags,
|
|
312949
313634
|
telemetry: sessionTelemetry,
|
|
312950
313635
|
pluginSessionStarts,
|
|
@@ -313041,6 +313726,7 @@ var init_core_impl = __esmMin((() => {
|
|
|
313041
313726
|
permissionRules: config.permission?.rules,
|
|
313042
313727
|
skills: this.resolveSessionSkillConfig(config),
|
|
313043
313728
|
mcpConfig,
|
|
313729
|
+
lspServers: this.plugins.enabledLspServers(),
|
|
313044
313730
|
experimentalFlags: this.experimentalFlags,
|
|
313045
313731
|
telemetry: withTelemetryContext$1(this.telemetry, { sessionId: summary.id }),
|
|
313046
313732
|
initializeMainAgent: false,
|
|
@@ -414965,6 +415651,9 @@ function resolveTelegramBridgeLaunch(bridge, options = {}) {
|
|
|
414965
415651
|
}
|
|
414966
415652
|
};
|
|
414967
415653
|
}
|
|
415654
|
+
function queueIdentity(stats) {
|
|
415655
|
+
return `${stats.dev}:${stats.ino}:${stats.birthtimeMs}`;
|
|
415656
|
+
}
|
|
414968
415657
|
function telegramStateDir() {
|
|
414969
415658
|
return process.env["BLUN_TELEGRAM_STATE_DIR"] ?? join(homedir(), ".blun", "channels", "telegram");
|
|
414970
415659
|
}
|
|
@@ -415036,7 +415725,10 @@ var TelegramChannelController = class {
|
|
|
415036
415725
|
activationTimer;
|
|
415037
415726
|
handoffTimer;
|
|
415038
415727
|
offset = 0;
|
|
415039
|
-
|
|
415728
|
+
checkpointOffset = 0;
|
|
415729
|
+
queueFileId = "";
|
|
415730
|
+
remainder = Buffer.alloc(0);
|
|
415731
|
+
pendingQueueLines = [];
|
|
415040
415732
|
started = false;
|
|
415041
415733
|
stopped = false;
|
|
415042
415734
|
activeOwner = false;
|
|
@@ -415078,6 +415770,9 @@ var TelegramChannelController = class {
|
|
|
415078
415770
|
get queueFile() {
|
|
415079
415771
|
return join(this.dir, "inbound-queue.jsonl");
|
|
415080
415772
|
}
|
|
415773
|
+
get queueCheckpointFile() {
|
|
415774
|
+
return join(this.dir, "inbound-queue.checkpoint.json");
|
|
415775
|
+
}
|
|
415081
415776
|
get botPidFile() {
|
|
415082
415777
|
return join(this.dir, "bot.pid");
|
|
415083
415778
|
}
|
|
@@ -415106,9 +415801,19 @@ var TelegramChannelController = class {
|
|
|
415106
415801
|
this.heartbeatTimer = setInterval(() => this.writeLease(), HEARTBEAT_MS);
|
|
415107
415802
|
this.heartbeatTimer.unref();
|
|
415108
415803
|
try {
|
|
415109
|
-
|
|
415804
|
+
const stats = statSync(this.queueFile);
|
|
415805
|
+
this.queueFileId = queueIdentity(stats);
|
|
415806
|
+
const checkpoint = this.readQueueCheckpoint();
|
|
415807
|
+
if (checkpoint?.fileId === this.queueFileId && checkpoint.offset >= 0 && checkpoint.offset <= stats.size) this.offset = checkpoint.offset;
|
|
415808
|
+
else {
|
|
415809
|
+
this.offset = stats.size;
|
|
415810
|
+
this.writeQueueCheckpoint(this.offset);
|
|
415811
|
+
}
|
|
415812
|
+
this.checkpointOffset = this.offset;
|
|
415110
415813
|
} catch {
|
|
415111
415814
|
this.offset = 0;
|
|
415815
|
+
this.checkpointOffset = 0;
|
|
415816
|
+
this.queueFileId = "";
|
|
415112
415817
|
}
|
|
415113
415818
|
this.tailTimer = setInterval(() => this.drainQueue(), TAIL_POLL_MS);
|
|
415114
415819
|
this.tailTimer.unref();
|
|
@@ -415286,24 +415991,34 @@ var TelegramChannelController = class {
|
|
|
415286
415991
|
this.loseOwnership();
|
|
415287
415992
|
return;
|
|
415288
415993
|
}
|
|
415289
|
-
let
|
|
415994
|
+
let stats;
|
|
415290
415995
|
try {
|
|
415291
|
-
|
|
415996
|
+
stats = statSync(this.queueFile);
|
|
415292
415997
|
} catch {
|
|
415293
415998
|
return;
|
|
415294
415999
|
}
|
|
415295
|
-
|
|
416000
|
+
const size = stats.size;
|
|
416001
|
+
const fileId = queueIdentity(stats);
|
|
416002
|
+
if (this.queueFileId === "") {
|
|
416003
|
+
this.queueFileId = fileId;
|
|
416004
|
+
this.writeQueueCheckpoint(this.checkpointOffset);
|
|
416005
|
+
} else if (fileId !== this.queueFileId || size < this.offset) {
|
|
416006
|
+
this.queueFileId = fileId;
|
|
415296
416007
|
this.offset = 0;
|
|
415297
|
-
this.
|
|
416008
|
+
this.checkpointOffset = 0;
|
|
416009
|
+
this.remainder = Buffer.alloc(0);
|
|
416010
|
+
this.pendingQueueLines.length = 0;
|
|
416011
|
+
this.writeQueueCheckpoint(0);
|
|
415298
416012
|
}
|
|
415299
416013
|
if (size === this.offset) return;
|
|
415300
416014
|
let chunk;
|
|
416015
|
+
const chunkStart = this.offset;
|
|
415301
416016
|
try {
|
|
415302
416017
|
const fd = openSync(this.queueFile, "r");
|
|
415303
416018
|
try {
|
|
415304
416019
|
const buf = Buffer.alloc(size - this.offset);
|
|
415305
416020
|
const read = readSync(fd, buf, 0, buf.length, this.offset);
|
|
415306
|
-
chunk = buf.subarray(0, read)
|
|
416021
|
+
chunk = buf.subarray(0, read);
|
|
415307
416022
|
this.offset += read;
|
|
415308
416023
|
} finally {
|
|
415309
416024
|
closeSync(fd);
|
|
@@ -415311,11 +416026,54 @@ var TelegramChannelController = class {
|
|
|
415311
416026
|
} catch {
|
|
415312
416027
|
return;
|
|
415313
416028
|
}
|
|
415314
|
-
const
|
|
415315
|
-
this.remainder
|
|
415316
|
-
|
|
416029
|
+
const combinedStart = chunkStart - this.remainder.byteLength;
|
|
416030
|
+
const combined = this.remainder.byteLength === 0 ? chunk : Buffer.concat([this.remainder, chunk]);
|
|
416031
|
+
let lineStart = 0;
|
|
416032
|
+
for (let index = 0; index < combined.byteLength; index += 1) {
|
|
416033
|
+
if (combined[index] !== 10) continue;
|
|
416034
|
+
const line = combined.subarray(lineStart, index).toString("utf8");
|
|
416035
|
+
const pending = {
|
|
416036
|
+
endOffset: combinedStart + index + 1,
|
|
416037
|
+
acknowledged: false
|
|
416038
|
+
};
|
|
416039
|
+
this.pendingQueueLines.push(pending);
|
|
415317
416040
|
const envelope = parseChannelEnvelope(line);
|
|
415318
|
-
if (envelope
|
|
416041
|
+
if (envelope === void 0) this.acknowledgeQueueLine(pending);
|
|
416042
|
+
else this.host.inject(envelope, () => this.acknowledgeQueueLine(pending));
|
|
416043
|
+
lineStart = index + 1;
|
|
416044
|
+
}
|
|
416045
|
+
this.remainder = combined.subarray(lineStart);
|
|
416046
|
+
}
|
|
416047
|
+
acknowledgeQueueLine(pending) {
|
|
416048
|
+
if (this.stopped || !this.ownsChannel() || pending.acknowledged) return;
|
|
416049
|
+
pending.acknowledged = true;
|
|
416050
|
+
let nextOffset = this.checkpointOffset;
|
|
416051
|
+
while (this.pendingQueueLines[0]?.acknowledged === true) nextOffset = this.pendingQueueLines.shift().endOffset;
|
|
416052
|
+
if (nextOffset === this.checkpointOffset) return;
|
|
416053
|
+
this.checkpointOffset = nextOffset;
|
|
416054
|
+
this.writeQueueCheckpoint(nextOffset);
|
|
416055
|
+
}
|
|
416056
|
+
readQueueCheckpoint() {
|
|
416057
|
+
try {
|
|
416058
|
+
const parsed = JSON.parse(readFileSync(this.queueCheckpointFile, "utf8"));
|
|
416059
|
+
if (parsed.version === 1 && typeof parsed.fileId === "string" && parsed.fileId.length > 0 && Number.isSafeInteger(parsed.offset) && (parsed.offset ?? -1) >= 0) return parsed;
|
|
416060
|
+
} catch {}
|
|
416061
|
+
}
|
|
416062
|
+
writeQueueCheckpoint(offset) {
|
|
416063
|
+
if (this.queueFileId.length === 0) return;
|
|
416064
|
+
const temporary = join(this.dir, `.inbound-queue.checkpoint.${process.pid}.${this.ownerId}.tmp`);
|
|
416065
|
+
try {
|
|
416066
|
+
const checkpoint = {
|
|
416067
|
+
version: 1,
|
|
416068
|
+
fileId: this.queueFileId,
|
|
416069
|
+
offset
|
|
416070
|
+
};
|
|
416071
|
+
writeFileSync(temporary, `${JSON.stringify(checkpoint)}\n`, { mode: 384 });
|
|
416072
|
+
renameSync(temporary, this.queueCheckpointFile);
|
|
416073
|
+
} catch (error) {
|
|
416074
|
+
this.host.warn(uiText("telegramChannel.leaseWriteFailed", { error: String(error) }));
|
|
416075
|
+
} finally {
|
|
416076
|
+
rmSync(temporary, { force: true });
|
|
415319
416077
|
}
|
|
415320
416078
|
}
|
|
415321
416079
|
/**
|
|
@@ -510529,6 +511287,7 @@ var BlunTUI = class {
|
|
|
510529
511287
|
};
|
|
510530
511288
|
try {
|
|
510531
511289
|
if (!(await this.harness.withInteractiveAgent(item.agentId ?? "main", () => session.steerActive(input, expectedTurnId === void 0 ? {} : { expectedTurnId }))).accepted) return restoreHead();
|
|
511290
|
+
item.channelAcknowledge?.();
|
|
510532
511291
|
} catch (error) {
|
|
510533
511292
|
return restoreHead(error);
|
|
510534
511293
|
}
|
|
@@ -510670,12 +511429,12 @@ var BlunTUI = class {
|
|
|
510670
511429
|
* queuedMessages mechanic as typed input; a completed tool/step boundary
|
|
510671
511430
|
* steers one FIFO head into the active turn without interrupting it.
|
|
510672
511431
|
*/
|
|
510673
|
-
injectChannelMessage(envelope) {
|
|
511432
|
+
injectChannelMessage(envelope, acknowledge) {
|
|
510674
511433
|
injectChannelEnvelope({
|
|
510675
511434
|
canDeliver: () => this.session !== void 0 && this.state.appState.model.trim().length > 0,
|
|
510676
511435
|
isBusy: () => this.state.queuedMessages.length > 0 || this.queueSteerInFlight !== void 0 || this.deferUserMessages || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting,
|
|
510677
511436
|
deliverNow: (modelInput, displayText, origin, contextOnly) => {
|
|
510678
|
-
this.sendChannelMessageInternal(this.requireSession(), modelInput, displayText, origin, envelope.meta.chat_id, envelope.meta["image_path"], contextOnly);
|
|
511437
|
+
this.sendChannelMessageInternal(this.requireSession(), modelInput, displayText, origin, envelope.meta.chat_id, envelope.meta["image_path"], contextOnly, false, acknowledge);
|
|
510679
511438
|
},
|
|
510680
511439
|
enqueue: (modelInput, displayText, origin, contextOnly) => {
|
|
510681
511440
|
this.state.queuedMessages.push({
|
|
@@ -510686,6 +511445,7 @@ var BlunTUI = class {
|
|
|
510686
511445
|
mode: "channel",
|
|
510687
511446
|
channelChatId: envelope.meta.chat_id,
|
|
510688
511447
|
channelContextOnly: contextOnly,
|
|
511448
|
+
channelAcknowledge: acknowledge,
|
|
510689
511449
|
...envelope.meta["image_path"] !== void 0 ? { channelImagePath: envelope.meta["image_path"] } : {}
|
|
510690
511450
|
});
|
|
510691
511451
|
this.syncChannelQueueDeadline();
|
|
@@ -510702,6 +511462,7 @@ var BlunTUI = class {
|
|
|
510702
511462
|
content: displayText,
|
|
510703
511463
|
origin
|
|
510704
511464
|
});
|
|
511465
|
+
acknowledge?.();
|
|
510705
511466
|
this.state.ui.requestRender();
|
|
510706
511467
|
},
|
|
510707
511468
|
reportUndeliverable: (reason) => {
|
|
@@ -510709,7 +511470,7 @@ var BlunTUI = class {
|
|
|
510709
511470
|
}
|
|
510710
511471
|
}, envelope, this.channelPreamble);
|
|
510711
511472
|
}
|
|
510712
|
-
sendChannelMessageInternal(session, modelInput, displayText, origin, channelChatId, channelImagePath, contextOnly = false, transcriptRendered = false) {
|
|
511473
|
+
sendChannelMessageInternal(session, modelInput, displayText, origin, channelChatId, channelImagePath, contextOnly = false, transcriptRendered = false, acknowledge) {
|
|
510713
511474
|
if (!transcriptRendered) this.appendTranscriptEntry({
|
|
510714
511475
|
id: nextTranscriptId(),
|
|
510715
511476
|
kind: "user",
|
|
@@ -510719,12 +511480,14 @@ var BlunTUI = class {
|
|
|
510719
511480
|
origin
|
|
510720
511481
|
});
|
|
510721
511482
|
this.beginSessionRequest();
|
|
510722
|
-
|
|
511483
|
+
const previousGuard = this.pendingChannelReplyGuard;
|
|
511484
|
+
const installedGuard = channelChatId === void 0 ? void 0 : {
|
|
510723
511485
|
chatId: channelChatId,
|
|
510724
511486
|
outboxMarker: outboxMarker(),
|
|
510725
511487
|
transcriptStart: this.state.transcriptEntries.length,
|
|
510726
511488
|
contextOnly
|
|
510727
511489
|
};
|
|
511490
|
+
if (installedGuard !== void 0) this.pendingChannelReplyGuard = installedGuard;
|
|
510728
511491
|
const imagePart = channelImagePath !== void 0 ? buildChannelImagePart(channelImagePath) : void 0;
|
|
510729
511492
|
const visionReaderEnabled = isExperimentalFlagEnabled("vision_reader");
|
|
510730
511493
|
this.setAppState({
|
|
@@ -510735,7 +511498,29 @@ var BlunTUI = class {
|
|
|
510735
511498
|
type: "text",
|
|
510736
511499
|
text: modelInput
|
|
510737
511500
|
}, imagePart] : modelInput;
|
|
510738
|
-
session.promptAccepted(promptInput).
|
|
511501
|
+
session.promptAccepted(promptInput).then((result) => {
|
|
511502
|
+
if (result.accepted) {
|
|
511503
|
+
acknowledge?.();
|
|
511504
|
+
return;
|
|
511505
|
+
}
|
|
511506
|
+
if (installedGuard !== void 0 && this.pendingChannelReplyGuard === installedGuard) this.pendingChannelReplyGuard = previousGuard;
|
|
511507
|
+
this.state.queuedMessages = [{
|
|
511508
|
+
text: modelInput,
|
|
511509
|
+
displayText,
|
|
511510
|
+
origin,
|
|
511511
|
+
agentId: this.harness.interactiveAgentId,
|
|
511512
|
+
mode: "channel",
|
|
511513
|
+
channelChatId,
|
|
511514
|
+
channelContextOnly: contextOnly,
|
|
511515
|
+
channelTranscriptRendered: true,
|
|
511516
|
+
channelAcknowledge: acknowledge,
|
|
511517
|
+
...channelImagePath === void 0 ? {} : { channelImagePath }
|
|
511518
|
+
}, ...this.state.queuedMessages];
|
|
511519
|
+
this.syncChannelQueueDeadline();
|
|
511520
|
+
this.track("input_queue");
|
|
511521
|
+
this.updateQueueDisplay();
|
|
511522
|
+
this.state.ui.requestRender();
|
|
511523
|
+
}).catch((error) => {
|
|
510739
511524
|
this.failSessionRequest(uiText("blunTui.session.sendFailed", { error: formatErrorMessage$2(error) }));
|
|
510740
511525
|
});
|
|
510741
511526
|
this.updateQueueDisplay();
|
|
@@ -510779,8 +511564,8 @@ var BlunTUI = class {
|
|
|
510779
511564
|
}
|
|
510780
511565
|
let controller;
|
|
510781
511566
|
controller = new TelegramChannelController({
|
|
510782
|
-
inject: (envelope) => {
|
|
510783
|
-
this.injectChannelMessage(envelope);
|
|
511567
|
+
inject: (envelope, acknowledge) => {
|
|
511568
|
+
this.injectChannelMessage(envelope, acknowledge);
|
|
510784
511569
|
},
|
|
510785
511570
|
warn: (message) => {
|
|
510786
511571
|
this.showStatus(message, "warning");
|
|
@@ -510904,7 +511689,7 @@ var BlunTUI = class {
|
|
|
510904
511689
|
const activeSession = this.session ?? session;
|
|
510905
511690
|
if (item.mode === "channel") {
|
|
510906
511691
|
this.harness.withInteractiveAgent(item.agentId ?? "main", () => {
|
|
510907
|
-
this.sendChannelMessageInternal(activeSession, item.text, item.displayText ?? "", item.origin, item.channelChatId, item.channelImagePath, item.channelContextOnly, item.channelTranscriptRendered);
|
|
511692
|
+
this.sendChannelMessageInternal(activeSession, item.text, item.displayText ?? "", item.origin, item.channelChatId, item.channelImagePath, item.channelContextOnly, item.channelTranscriptRendered, item.channelAcknowledge);
|
|
510908
511693
|
});
|
|
510909
511694
|
return;
|
|
510910
511695
|
}
|
|
@@ -511263,7 +512048,7 @@ var BlunTUI = class {
|
|
|
511263
512048
|
streamingPhase: "idle"
|
|
511264
512049
|
});
|
|
511265
512050
|
if (!this.preserveQueueAcrossSessionReset) {
|
|
511266
|
-
this.state.queuedMessages =
|
|
512051
|
+
this.state.queuedMessages = this.state.queuedMessages.filter((item) => item.mode === "channel");
|
|
511267
512052
|
this.queueFlushBatchRemaining = 0;
|
|
511268
512053
|
this.queueSteerInFlight = void 0;
|
|
511269
512054
|
}
|