@nogataka/smart-edit 0.0.14
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/LICENSE +22 -0
- package/README.md +244 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +7 -0
- package/dist/devtools/generate_prompt_factory.d.ts +5 -0
- package/dist/devtools/generate_prompt_factory.js +114 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +34 -0
- package/dist/interprompt/index.d.ts +2 -0
- package/dist/interprompt/index.js +1 -0
- package/dist/interprompt/jinja_template.d.ts +10 -0
- package/dist/interprompt/jinja_template.js +174 -0
- package/dist/interprompt/multilang_prompt.d.ts +54 -0
- package/dist/interprompt/multilang_prompt.js +302 -0
- package/dist/interprompt/prompt_factory.d.ts +16 -0
- package/dist/interprompt/prompt_factory.js +189 -0
- package/dist/interprompt/util/class_decorators.d.ts +1 -0
- package/dist/interprompt/util/class_decorators.js +1 -0
- package/dist/interprompt/util/index.d.ts +1 -0
- package/dist/interprompt/util/index.js +1 -0
- package/dist/serena/agent.d.ts +118 -0
- package/dist/serena/agent.js +675 -0
- package/dist/serena/agno.d.ts +111 -0
- package/dist/serena/agno.js +278 -0
- package/dist/serena/analytics.d.ts +24 -0
- package/dist/serena/analytics.js +119 -0
- package/dist/serena/cli.d.ts +9 -0
- package/dist/serena/cli.js +731 -0
- package/dist/serena/code_editor.d.ts +42 -0
- package/dist/serena/code_editor.js +239 -0
- package/dist/serena/config/context_mode.d.ts +41 -0
- package/dist/serena/config/context_mode.js +239 -0
- package/dist/serena/config/serena_config.d.ts +134 -0
- package/dist/serena/config/serena_config.js +718 -0
- package/dist/serena/constants.d.ts +18 -0
- package/dist/serena/constants.js +27 -0
- package/dist/serena/dashboard.d.ts +55 -0
- package/dist/serena/dashboard.js +472 -0
- package/dist/serena/generated/generated_prompt_factory.d.ts +27 -0
- package/dist/serena/generated/generated_prompt_factory.js +42 -0
- package/dist/serena/gui_log_viewer.d.ts +41 -0
- package/dist/serena/gui_log_viewer.js +436 -0
- package/dist/serena/mcp.d.ts +118 -0
- package/dist/serena/mcp.js +904 -0
- package/dist/serena/project.d.ts +62 -0
- package/dist/serena/project.js +321 -0
- package/dist/serena/prompt_factory.d.ts +20 -0
- package/dist/serena/prompt_factory.js +42 -0
- package/dist/serena/resources/config/contexts/agent.yml +8 -0
- package/dist/serena/resources/config/contexts/chatgpt.yml +28 -0
- package/dist/serena/resources/config/contexts/codex.yml +27 -0
- package/dist/serena/resources/config/contexts/context.template.yml +11 -0
- package/dist/serena/resources/config/contexts/desktop-app.yml +17 -0
- package/dist/serena/resources/config/contexts/ide-assistant.yml +26 -0
- package/dist/serena/resources/config/contexts/oaicompat-agent.yml +8 -0
- package/dist/serena/resources/config/internal_modes/jetbrains.yml +15 -0
- package/dist/serena/resources/config/modes/editing.yml +112 -0
- package/dist/serena/resources/config/modes/interactive.yml +11 -0
- package/dist/serena/resources/config/modes/mode.template.yml +7 -0
- package/dist/serena/resources/config/modes/no-onboarding.yml +8 -0
- package/dist/serena/resources/config/modes/onboarding.yml +16 -0
- package/dist/serena/resources/config/modes/one-shot.yml +15 -0
- package/dist/serena/resources/config/modes/planning.yml +15 -0
- package/dist/serena/resources/config/prompt_templates/simple_tool_outputs.yml +75 -0
- package/dist/serena/resources/config/prompt_templates/system_prompt.yml +66 -0
- package/dist/serena/resources/dashboard/dashboard.js +815 -0
- package/dist/serena/resources/dashboard/index.html +314 -0
- package/dist/serena/resources/dashboard/jquery.min.js +3 -0
- package/dist/serena/resources/dashboard/serena-icon-16.png +0 -0
- package/dist/serena/resources/dashboard/serena-icon-32.png +0 -0
- package/dist/serena/resources/dashboard/serena-icon-48.png +0 -0
- package/dist/serena/resources/dashboard/serena-logs-dark-mode.png +0 -0
- package/dist/serena/resources/dashboard/serena-logs.png +0 -0
- package/dist/serena/resources/project.template.yml +67 -0
- package/dist/serena/resources/serena_config.template.yml +85 -0
- package/dist/serena/symbol.d.ts +199 -0
- package/dist/serena/symbol.js +616 -0
- package/dist/serena/text_utils.d.ts +51 -0
- package/dist/serena/text_utils.js +267 -0
- package/dist/serena/tools/cmd_tools.d.ts +31 -0
- package/dist/serena/tools/cmd_tools.js +48 -0
- package/dist/serena/tools/config_tools.d.ts +53 -0
- package/dist/serena/tools/config_tools.js +176 -0
- package/dist/serena/tools/file_tools.d.ts +231 -0
- package/dist/serena/tools/file_tools.js +511 -0
- package/dist/serena/tools/index.d.ts +7 -0
- package/dist/serena/tools/index.js +7 -0
- package/dist/serena/tools/memory_tools.d.ts +60 -0
- package/dist/serena/tools/memory_tools.js +135 -0
- package/dist/serena/tools/symbol_tools.d.ts +165 -0
- package/dist/serena/tools/symbol_tools.js +362 -0
- package/dist/serena/tools/tools_base.d.ts +162 -0
- package/dist/serena/tools/tools_base.js +378 -0
- package/dist/serena/tools/workflow_tools.d.ts +35 -0
- package/dist/serena/tools/workflow_tools.js +161 -0
- package/dist/serena/util/class_decorators.d.ts +7 -0
- package/dist/serena/util/class_decorators.js +37 -0
- package/dist/serena/util/exception.d.ts +8 -0
- package/dist/serena/util/exception.js +53 -0
- package/dist/serena/util/file_system.d.ts +30 -0
- package/dist/serena/util/file_system.js +352 -0
- package/dist/serena/util/general.d.ts +11 -0
- package/dist/serena/util/general.js +42 -0
- package/dist/serena/util/git.d.ts +11 -0
- package/dist/serena/util/git.js +37 -0
- package/dist/serena/util/inspection.d.ts +45 -0
- package/dist/serena/util/inspection.js +221 -0
- package/dist/serena/util/logging.d.ts +46 -0
- package/dist/serena/util/logging.js +205 -0
- package/dist/serena/util/shell.d.ts +21 -0
- package/dist/serena/util/shell.js +95 -0
- package/dist/serena/util/thread.d.ts +23 -0
- package/dist/serena/util/thread.js +88 -0
- package/dist/serena/version.d.ts +1 -0
- package/dist/serena/version.js +23 -0
- package/dist/solidlsp/language_servers/autoload.d.ts +23 -0
- package/dist/solidlsp/language_servers/autoload.js +25 -0
- package/dist/solidlsp/language_servers/bash_language_server.d.ts +10 -0
- package/dist/solidlsp/language_servers/bash_language_server.js +64 -0
- package/dist/solidlsp/language_servers/clangd_language_server.d.ts +13 -0
- package/dist/solidlsp/language_servers/clangd_language_server.js +110 -0
- package/dist/solidlsp/language_servers/clojure_lsp.d.ts +13 -0
- package/dist/solidlsp/language_servers/clojure_lsp.js +137 -0
- package/dist/solidlsp/language_servers/common.d.ts +41 -0
- package/dist/solidlsp/language_servers/common.js +365 -0
- package/dist/solidlsp/language_servers/csharp_language_server.d.ts +21 -0
- package/dist/solidlsp/language_servers/csharp_language_server.js +694 -0
- package/dist/solidlsp/language_servers/dart_language_server.d.ts +10 -0
- package/dist/solidlsp/language_servers/dart_language_server.js +122 -0
- package/dist/solidlsp/language_servers/eclipse_jdtls.d.ts +24 -0
- package/dist/solidlsp/language_servers/eclipse_jdtls.js +671 -0
- package/dist/solidlsp/language_servers/erlang_language_server.d.ts +22 -0
- package/dist/solidlsp/language_servers/erlang_language_server.js +327 -0
- package/dist/solidlsp/language_servers/gopls.d.ts +12 -0
- package/dist/solidlsp/language_servers/gopls.js +59 -0
- package/dist/solidlsp/language_servers/intelephense.d.ts +13 -0
- package/dist/solidlsp/language_servers/intelephense.js +121 -0
- package/dist/solidlsp/language_servers/jedi_server.d.ts +18 -0
- package/dist/solidlsp/language_servers/jedi_server.js +234 -0
- package/dist/solidlsp/language_servers/kotlin_language_server.d.ts +19 -0
- package/dist/solidlsp/language_servers/kotlin_language_server.js +474 -0
- package/dist/solidlsp/language_servers/lua_ls.d.ts +18 -0
- package/dist/solidlsp/language_servers/lua_ls.js +319 -0
- package/dist/solidlsp/language_servers/nixd_language_server.d.ts +17 -0
- package/dist/solidlsp/language_servers/nixd_language_server.js +341 -0
- package/dist/solidlsp/language_servers/pyright_server.d.ts +19 -0
- package/dist/solidlsp/language_servers/pyright_server.js +180 -0
- package/dist/solidlsp/language_servers/r_language_server.d.ts +19 -0
- package/dist/solidlsp/language_servers/r_language_server.js +184 -0
- package/dist/solidlsp/language_servers/ruby_common.d.ts +10 -0
- package/dist/solidlsp/language_servers/ruby_common.js +136 -0
- package/dist/solidlsp/language_servers/ruby_lsp.d.ts +18 -0
- package/dist/solidlsp/language_servers/ruby_lsp.js +230 -0
- package/dist/solidlsp/language_servers/rust_analyzer.d.ts +13 -0
- package/dist/solidlsp/language_servers/rust_analyzer.js +96 -0
- package/dist/solidlsp/language_servers/solargraph.d.ts +18 -0
- package/dist/solidlsp/language_servers/solargraph.js +208 -0
- package/dist/solidlsp/language_servers/sourcekit_lsp.d.ts +24 -0
- package/dist/solidlsp/language_servers/sourcekit_lsp.js +449 -0
- package/dist/solidlsp/language_servers/terraform_ls.d.ts +13 -0
- package/dist/solidlsp/language_servers/terraform_ls.js +139 -0
- package/dist/solidlsp/language_servers/typescript_language_server.d.ts +20 -0
- package/dist/solidlsp/language_servers/typescript_language_server.js +237 -0
- package/dist/solidlsp/language_servers/vts_language_server.d.ts +13 -0
- package/dist/solidlsp/language_servers/vts_language_server.js +121 -0
- package/dist/solidlsp/language_servers/zls.d.ts +20 -0
- package/dist/solidlsp/language_servers/zls.js +254 -0
- package/dist/solidlsp/ls.d.ts +197 -0
- package/dist/solidlsp/ls.js +507 -0
- package/dist/solidlsp/ls_config.d.ts +43 -0
- package/dist/solidlsp/ls_config.js +157 -0
- package/dist/solidlsp/ls_exceptions.d.ts +5 -0
- package/dist/solidlsp/ls_exceptions.js +14 -0
- package/dist/solidlsp/ls_handler.d.ts +54 -0
- package/dist/solidlsp/ls_handler.js +406 -0
- package/dist/solidlsp/ls_request.d.ts +31 -0
- package/dist/solidlsp/ls_request.js +42 -0
- package/dist/solidlsp/ls_types.d.ts +7 -0
- package/dist/solidlsp/ls_types.js +8 -0
- package/dist/solidlsp/lsp_protocol_handler/server.d.ts +61 -0
- package/dist/solidlsp/lsp_protocol_handler/server.js +68 -0
- package/dist/solidlsp/util/subprocess_util.d.ts +6 -0
- package/dist/solidlsp/util/subprocess_util.js +11 -0
- package/dist/solidlsp/util/zip.d.ts +25 -0
- package/dist/solidlsp/util/zip.js +188 -0
- package/package.json +65 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const SERENA_MANAGED_DIR_NAME = ".smart-edit";
|
|
2
|
+
export declare const SERENA_MANAGED_DIR_IN_HOME: string;
|
|
3
|
+
export declare const REPO_ROOT: string;
|
|
4
|
+
export declare const PROMPT_TEMPLATES_DIR_INTERNAL: string;
|
|
5
|
+
export declare const PROMPT_TEMPLATES_DIR_IN_USER_HOME: string;
|
|
6
|
+
export declare const SERENAS_OWN_CONTEXT_YAMLS_DIR: string;
|
|
7
|
+
export declare const USER_CONTEXT_YAMLS_DIR: string;
|
|
8
|
+
export declare const SERENAS_OWN_MODE_YAMLS_DIR: string;
|
|
9
|
+
export declare const USER_MODE_YAMLS_DIR: string;
|
|
10
|
+
export declare const INTERNAL_MODE_YAMLS_DIR: string;
|
|
11
|
+
export declare const SERENA_DASHBOARD_DIR: string;
|
|
12
|
+
export declare const SERENA_ICON_DIR: string;
|
|
13
|
+
export declare const DEFAULT_ENCODING = "utf-8";
|
|
14
|
+
export declare const DEFAULT_CONTEXT = "desktop-app";
|
|
15
|
+
export declare const DEFAULT_MODES: readonly ["interactive", "editing"];
|
|
16
|
+
export declare const PROJECT_TEMPLATE_FILE: string;
|
|
17
|
+
export declare const SERENA_CONFIG_TEMPLATE_FILE: string;
|
|
18
|
+
export declare const SERENA_LOG_FORMAT = "%(levelname)-5s %(asctime)-15s [%(threadName)s] %(name)s:%(funcName)s:%(lineno)d - %(message)s";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = path.dirname(__filename);
|
|
6
|
+
const repoRoot = path.resolve(__dirname, '..', '..');
|
|
7
|
+
const serenaPackageRoot = path.resolve(__dirname);
|
|
8
|
+
const serenaManagedDirName = '.smart-edit';
|
|
9
|
+
const serenaManagedDirInHome = path.join(os.homedir(), serenaManagedDirName);
|
|
10
|
+
export const SERENA_MANAGED_DIR_NAME = serenaManagedDirName;
|
|
11
|
+
export const SERENA_MANAGED_DIR_IN_HOME = serenaManagedDirInHome;
|
|
12
|
+
export const REPO_ROOT = repoRoot;
|
|
13
|
+
export const PROMPT_TEMPLATES_DIR_INTERNAL = path.join(serenaPackageRoot, 'resources', 'config', 'prompt_templates');
|
|
14
|
+
export const PROMPT_TEMPLATES_DIR_IN_USER_HOME = path.join(serenaManagedDirInHome, 'prompt_templates');
|
|
15
|
+
export const SERENAS_OWN_CONTEXT_YAMLS_DIR = path.join(serenaPackageRoot, 'resources', 'config', 'contexts');
|
|
16
|
+
export const USER_CONTEXT_YAMLS_DIR = path.join(serenaManagedDirInHome, 'contexts');
|
|
17
|
+
export const SERENAS_OWN_MODE_YAMLS_DIR = path.join(serenaPackageRoot, 'resources', 'config', 'modes');
|
|
18
|
+
export const USER_MODE_YAMLS_DIR = path.join(serenaManagedDirInHome, 'modes');
|
|
19
|
+
export const INTERNAL_MODE_YAMLS_DIR = path.join(serenaPackageRoot, 'resources', 'config', 'internal_modes');
|
|
20
|
+
export const SERENA_DASHBOARD_DIR = path.join(serenaPackageRoot, 'resources', 'dashboard');
|
|
21
|
+
export const SERENA_ICON_DIR = path.join(serenaPackageRoot, 'resources', 'icons');
|
|
22
|
+
export const DEFAULT_ENCODING = 'utf-8';
|
|
23
|
+
export const DEFAULT_CONTEXT = 'desktop-app';
|
|
24
|
+
export const DEFAULT_MODES = ['interactive', 'editing'];
|
|
25
|
+
export const PROJECT_TEMPLATE_FILE = path.join(serenaPackageRoot, 'resources', 'project.template.yml');
|
|
26
|
+
export const SERENA_CONFIG_TEMPLATE_FILE = path.join(serenaPackageRoot, 'resources', 'serena_config.template.yml');
|
|
27
|
+
export const SERENA_LOG_FORMAT = '%(levelname)-5s %(asctime)-15s [%(threadName)s] %(name)s:%(funcName)s:%(lineno)d - %(message)s';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { MemoryLogHandler } from './util/logging.js';
|
|
2
|
+
import type { ToolUsageStats } from './analytics.js';
|
|
3
|
+
interface DashboardAgentLike {
|
|
4
|
+
getActiveProject(): {
|
|
5
|
+
projectName?: string | null;
|
|
6
|
+
} | null;
|
|
7
|
+
}
|
|
8
|
+
export interface DashboardThread {
|
|
9
|
+
stop(): void;
|
|
10
|
+
}
|
|
11
|
+
export interface SerenaDashboardApiOptions {
|
|
12
|
+
shutdownCallback?: () => void;
|
|
13
|
+
toolUsageStats?: ToolUsageStats | null;
|
|
14
|
+
}
|
|
15
|
+
export declare class SerenaDashboardAPI {
|
|
16
|
+
private readonly memoryLogHandler;
|
|
17
|
+
private toolNames;
|
|
18
|
+
private readonly agent;
|
|
19
|
+
private readonly shutdownCallback?;
|
|
20
|
+
private readonly toolUsageStats?;
|
|
21
|
+
private server;
|
|
22
|
+
private listeningPort;
|
|
23
|
+
private readonly sseClients;
|
|
24
|
+
private logSequence;
|
|
25
|
+
private logListener?;
|
|
26
|
+
private heartbeatTimer;
|
|
27
|
+
private streamingAttached;
|
|
28
|
+
constructor(memoryLogHandler: MemoryLogHandler, toolNames: string[], agent: DashboardAgentLike, options?: SerenaDashboardApiOptions);
|
|
29
|
+
runInThread(): Promise<[DashboardThread, number]>;
|
|
30
|
+
getToolNames(): string[];
|
|
31
|
+
setToolNames(toolNames: string[]): void;
|
|
32
|
+
private broadcastToolNames;
|
|
33
|
+
clearToolStats(): void;
|
|
34
|
+
shutdown(): void;
|
|
35
|
+
private startServer;
|
|
36
|
+
private listenOnPort;
|
|
37
|
+
private ensureLogStreamingAttached;
|
|
38
|
+
private detachLogStreaming;
|
|
39
|
+
private onLogMessage;
|
|
40
|
+
private broadcastSseEvent;
|
|
41
|
+
private sendHeartbeat;
|
|
42
|
+
private removeSseClient;
|
|
43
|
+
private formatSseEvent;
|
|
44
|
+
private handleLogStream;
|
|
45
|
+
private handleRequest;
|
|
46
|
+
private serveDashboardAsset;
|
|
47
|
+
private handleGetLogMessages;
|
|
48
|
+
private getToolStats;
|
|
49
|
+
private getNumberFromRecord;
|
|
50
|
+
private parseRequestBody;
|
|
51
|
+
private respondNotFound;
|
|
52
|
+
private respondMethodNotAllowed;
|
|
53
|
+
private sendJson;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { clearInterval, setInterval } from 'node:timers';
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { parse as parseUrl } from 'node:url';
|
|
5
|
+
import { promises as fs } from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import process from 'node:process';
|
|
8
|
+
import { createSerenaLogger } from './util/logging.js';
|
|
9
|
+
import { SERENA_DASHBOARD_DIR } from './constants.js';
|
|
10
|
+
const { logger } = createSerenaLogger({ name: 'serena.dashboard', emitToConsole: false, level: 'info' });
|
|
11
|
+
const DEFAULT_DASHBOARD_PORT = 0x5eda;
|
|
12
|
+
const DASHBOARD_HOST = '127.0.0.1';
|
|
13
|
+
const SSE_HEARTBEAT_INTERVAL_MS = 15_000;
|
|
14
|
+
const CONTENT_TYPE_BY_EXTENSION = {
|
|
15
|
+
'.html': 'text/html; charset=utf-8',
|
|
16
|
+
'.js': 'application/javascript; charset=utf-8',
|
|
17
|
+
'.css': 'text/css; charset=utf-8',
|
|
18
|
+
'.png': 'image/png',
|
|
19
|
+
'.json': 'application/json; charset=utf-8',
|
|
20
|
+
'.ico': 'image/x-icon'
|
|
21
|
+
};
|
|
22
|
+
class DashboardHttpThread {
|
|
23
|
+
server;
|
|
24
|
+
onStop;
|
|
25
|
+
stopped = false;
|
|
26
|
+
constructor(server, onStop) {
|
|
27
|
+
this.server = server;
|
|
28
|
+
this.onStop = onStop;
|
|
29
|
+
}
|
|
30
|
+
stop() {
|
|
31
|
+
if (this.stopped) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.stopped = true;
|
|
35
|
+
this.server.close((error) => {
|
|
36
|
+
if (error) {
|
|
37
|
+
logger.warn('Failed to stop Serena dashboard server cleanly.', error);
|
|
38
|
+
}
|
|
39
|
+
this.onStop?.();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const SSE_HEADERS = {
|
|
44
|
+
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
45
|
+
'Cache-Control': 'no-cache',
|
|
46
|
+
Connection: 'keep-alive'
|
|
47
|
+
};
|
|
48
|
+
export class SerenaDashboardAPI {
|
|
49
|
+
memoryLogHandler;
|
|
50
|
+
toolNames;
|
|
51
|
+
agent;
|
|
52
|
+
shutdownCallback;
|
|
53
|
+
toolUsageStats;
|
|
54
|
+
server = null;
|
|
55
|
+
listeningPort = null;
|
|
56
|
+
sseClients = new Set();
|
|
57
|
+
logSequence = 0;
|
|
58
|
+
logListener;
|
|
59
|
+
heartbeatTimer = null;
|
|
60
|
+
streamingAttached = false;
|
|
61
|
+
constructor(memoryLogHandler, toolNames, agent, options = {}) {
|
|
62
|
+
this.memoryLogHandler = memoryLogHandler;
|
|
63
|
+
this.toolNames = [...toolNames];
|
|
64
|
+
this.agent = agent;
|
|
65
|
+
this.shutdownCallback = options.shutdownCallback;
|
|
66
|
+
this.toolUsageStats = options.toolUsageStats;
|
|
67
|
+
this.logSequence = this.memoryLogHandler.getLogMessages().length;
|
|
68
|
+
}
|
|
69
|
+
async runInThread() {
|
|
70
|
+
if (this.server && this.listeningPort !== null) {
|
|
71
|
+
this.ensureLogStreamingAttached();
|
|
72
|
+
return [new DashboardHttpThread(this.server), this.listeningPort];
|
|
73
|
+
}
|
|
74
|
+
const { server, port } = await this.startServer();
|
|
75
|
+
this.server = server;
|
|
76
|
+
this.listeningPort = port;
|
|
77
|
+
this.ensureLogStreamingAttached();
|
|
78
|
+
const thread = new DashboardHttpThread(server, () => {
|
|
79
|
+
this.server = null;
|
|
80
|
+
this.listeningPort = null;
|
|
81
|
+
this.detachLogStreaming();
|
|
82
|
+
});
|
|
83
|
+
logger.info(`Serena dashboard listening on http://${DASHBOARD_HOST}:${port}/dashboard/index.html`);
|
|
84
|
+
return [thread, port];
|
|
85
|
+
}
|
|
86
|
+
getToolNames() {
|
|
87
|
+
return [...this.toolNames];
|
|
88
|
+
}
|
|
89
|
+
setToolNames(toolNames) {
|
|
90
|
+
this.toolNames = [...toolNames];
|
|
91
|
+
this.broadcastToolNames();
|
|
92
|
+
}
|
|
93
|
+
broadcastToolNames() {
|
|
94
|
+
this.broadcastSseEvent('toolNames', { toolNames: this.getToolNames() });
|
|
95
|
+
}
|
|
96
|
+
clearToolStats() {
|
|
97
|
+
this.toolUsageStats?.clear();
|
|
98
|
+
}
|
|
99
|
+
shutdown() {
|
|
100
|
+
logger.info('Dashboard shutdown triggered.');
|
|
101
|
+
this.detachLogStreaming();
|
|
102
|
+
if (this.shutdownCallback) {
|
|
103
|
+
this.shutdownCallback();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
108
|
+
async startServer() {
|
|
109
|
+
let candidatePort = DEFAULT_DASHBOARD_PORT;
|
|
110
|
+
let lastError = null;
|
|
111
|
+
while (candidatePort <= 65535) {
|
|
112
|
+
const server = createServer((req, res) => {
|
|
113
|
+
void this.handleRequest(req, res);
|
|
114
|
+
});
|
|
115
|
+
try {
|
|
116
|
+
const port = await this.listenOnPort(server, candidatePort);
|
|
117
|
+
server.on('close', () => {
|
|
118
|
+
this.server = null;
|
|
119
|
+
this.listeningPort = null;
|
|
120
|
+
this.detachLogStreaming();
|
|
121
|
+
});
|
|
122
|
+
return { server, port };
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
lastError = error;
|
|
126
|
+
try {
|
|
127
|
+
server.close();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// ignore close errors
|
|
131
|
+
}
|
|
132
|
+
if (lastError && (lastError.code === 'EADDRINUSE' || lastError.code === 'EACCES')) {
|
|
133
|
+
candidatePort += 1;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
logger.error('Failed to start Serena dashboard server.', lastError ?? undefined);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
throw new Error(lastError?.message ?? 'Unable to start Serena dashboard server; no available ports in the configured range.');
|
|
141
|
+
}
|
|
142
|
+
listenOnPort(server, port) {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const onError = (error) => {
|
|
145
|
+
cleanup();
|
|
146
|
+
reject(error);
|
|
147
|
+
};
|
|
148
|
+
const onListening = () => {
|
|
149
|
+
const address = server.address();
|
|
150
|
+
cleanup();
|
|
151
|
+
if (address && typeof address === 'object') {
|
|
152
|
+
resolve(address.port);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
resolve(port);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const cleanup = () => {
|
|
159
|
+
server.off('error', onError);
|
|
160
|
+
server.off('listening', onListening);
|
|
161
|
+
};
|
|
162
|
+
server.once('error', onError);
|
|
163
|
+
server.once('listening', onListening);
|
|
164
|
+
server.listen({ port, host: DASHBOARD_HOST, exclusive: true });
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
ensureLogStreamingAttached() {
|
|
168
|
+
if (this.streamingAttached) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.streamingAttached = true;
|
|
172
|
+
this.logSequence = this.memoryLogHandler.getLogMessages().length;
|
|
173
|
+
this.logListener = (message) => {
|
|
174
|
+
this.onLogMessage(message);
|
|
175
|
+
};
|
|
176
|
+
this.memoryLogHandler.addEmitCallback(this.logListener);
|
|
177
|
+
const timer = setInterval(() => {
|
|
178
|
+
this.sendHeartbeat();
|
|
179
|
+
}, SSE_HEARTBEAT_INTERVAL_MS);
|
|
180
|
+
if (typeof timer.unref === 'function') {
|
|
181
|
+
timer.unref();
|
|
182
|
+
}
|
|
183
|
+
this.heartbeatTimer = timer;
|
|
184
|
+
}
|
|
185
|
+
detachLogStreaming() {
|
|
186
|
+
if (!this.streamingAttached) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
this.streamingAttached = false;
|
|
190
|
+
if (this.logListener) {
|
|
191
|
+
this.memoryLogHandler.removeEmitCallback(this.logListener);
|
|
192
|
+
this.logListener = undefined;
|
|
193
|
+
}
|
|
194
|
+
if (this.heartbeatTimer) {
|
|
195
|
+
clearInterval(this.heartbeatTimer);
|
|
196
|
+
this.heartbeatTimer = null;
|
|
197
|
+
}
|
|
198
|
+
if (this.sseClients.size > 0) {
|
|
199
|
+
const shutdownFrame = this.formatSseEvent('shutdown', { reason: 'server_stop' });
|
|
200
|
+
for (const client of this.sseClients) {
|
|
201
|
+
try {
|
|
202
|
+
client.write(shutdownFrame);
|
|
203
|
+
if (!client.writableEnded) {
|
|
204
|
+
client.end();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// ignore errors when closing clients
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
this.sseClients.clear();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
onLogMessage(message) {
|
|
215
|
+
const payload = {
|
|
216
|
+
message,
|
|
217
|
+
idx: this.logSequence,
|
|
218
|
+
activeProject: this.agent.getActiveProject()?.projectName ?? null
|
|
219
|
+
};
|
|
220
|
+
this.logSequence += 1;
|
|
221
|
+
this.broadcastSseEvent('log', payload);
|
|
222
|
+
}
|
|
223
|
+
broadcastSseEvent(event, payload) {
|
|
224
|
+
if (this.sseClients.size === 0) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const frame = this.formatSseEvent(event, payload);
|
|
228
|
+
for (const client of [...this.sseClients]) {
|
|
229
|
+
try {
|
|
230
|
+
client.write(frame);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
this.removeSseClient(client);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
sendHeartbeat() {
|
|
238
|
+
if (this.sseClients.size === 0) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const heartbeat = `: heartbeat ${Date.now()}\n\n`;
|
|
242
|
+
for (const client of [...this.sseClients]) {
|
|
243
|
+
try {
|
|
244
|
+
client.write(heartbeat);
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
this.removeSseClient(client);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
removeSseClient(res) {
|
|
252
|
+
if (!this.sseClients.has(res)) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
this.sseClients.delete(res);
|
|
256
|
+
try {
|
|
257
|
+
if (!res.writableEnded) {
|
|
258
|
+
res.end();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// ignore errors during cleanup
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
formatSseEvent(event, payload) {
|
|
266
|
+
return `event: ${event}\ndata: ${JSON.stringify(payload)}\n\n`;
|
|
267
|
+
}
|
|
268
|
+
handleLogStream(req, res) {
|
|
269
|
+
this.ensureLogStreamingAttached();
|
|
270
|
+
this.sseClients.add(res);
|
|
271
|
+
const teardown = () => {
|
|
272
|
+
this.removeSseClient(res);
|
|
273
|
+
};
|
|
274
|
+
res.on('close', teardown);
|
|
275
|
+
res.on('error', teardown);
|
|
276
|
+
req.on('close', teardown);
|
|
277
|
+
req.on('error', teardown);
|
|
278
|
+
res.writeHead(200, SSE_HEADERS);
|
|
279
|
+
res.write(': connected\n\n');
|
|
280
|
+
// Send current tool names and log history so the client can hydrate immediately.
|
|
281
|
+
const toolNamesPayload = { toolNames: this.getToolNames() };
|
|
282
|
+
res.write(this.formatSseEvent('toolNames', toolNamesPayload));
|
|
283
|
+
const logMessages = this.memoryLogHandler.getLogMessages();
|
|
284
|
+
const historyPayload = {
|
|
285
|
+
messages: logMessages,
|
|
286
|
+
maxIdx: logMessages.length > 0 ? logMessages.length - 1 : -1,
|
|
287
|
+
activeProject: this.agent.getActiveProject()?.projectName ?? null
|
|
288
|
+
};
|
|
289
|
+
res.write(this.formatSseEvent('history', historyPayload));
|
|
290
|
+
}
|
|
291
|
+
async handleRequest(req, res) {
|
|
292
|
+
const method = req.method?.toUpperCase() ?? 'GET';
|
|
293
|
+
const url = parseUrl(req.url ?? '/', true);
|
|
294
|
+
const pathname = url.pathname ?? '/';
|
|
295
|
+
try {
|
|
296
|
+
if (pathname.startsWith('/dashboard')) {
|
|
297
|
+
if (method !== 'GET') {
|
|
298
|
+
this.respondMethodNotAllowed(res);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
await this.serveDashboardAsset(pathname, res);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (pathname === '/log_stream') {
|
|
305
|
+
if (method !== 'GET') {
|
|
306
|
+
this.respondMethodNotAllowed(res);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
this.handleLogStream(req, res);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
switch (pathname) {
|
|
313
|
+
case '/get_log_messages':
|
|
314
|
+
if (method !== 'POST') {
|
|
315
|
+
this.respondMethodNotAllowed(res);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
await this.handleGetLogMessages(req, res);
|
|
319
|
+
return;
|
|
320
|
+
case '/get_tool_names':
|
|
321
|
+
if (method !== 'GET') {
|
|
322
|
+
this.respondMethodNotAllowed(res);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
this.sendJson(res, 200, { tool_names: this.getToolNames() });
|
|
326
|
+
return;
|
|
327
|
+
case '/get_tool_stats':
|
|
328
|
+
if (method !== 'GET') {
|
|
329
|
+
this.respondMethodNotAllowed(res);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
this.sendJson(res, 200, { stats: this.getToolStats() });
|
|
333
|
+
return;
|
|
334
|
+
case '/clear_tool_stats':
|
|
335
|
+
if (method !== 'POST') {
|
|
336
|
+
this.respondMethodNotAllowed(res);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
this.clearToolStats();
|
|
340
|
+
this.sendJson(res, 200, { status: 'cleared' });
|
|
341
|
+
return;
|
|
342
|
+
case '/get_token_count_estimator_name':
|
|
343
|
+
if (method !== 'GET') {
|
|
344
|
+
this.respondMethodNotAllowed(res);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
this.sendJson(res, 200, {
|
|
348
|
+
token_count_estimator_name: this.toolUsageStats?.tokenEstimatorName ?? 'unknown'
|
|
349
|
+
});
|
|
350
|
+
return;
|
|
351
|
+
case '/shutdown':
|
|
352
|
+
if (method !== 'PUT') {
|
|
353
|
+
this.respondMethodNotAllowed(res);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
this.shutdown();
|
|
357
|
+
this.sendJson(res, 200, { status: 'shutting down' });
|
|
358
|
+
return;
|
|
359
|
+
default:
|
|
360
|
+
this.respondNotFound(res);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
logger.error('Dashboard request failed.', error instanceof Error ? error : undefined);
|
|
365
|
+
this.sendJson(res, 500, { error: 'Internal server error' });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async serveDashboardAsset(pathname, res) {
|
|
369
|
+
const relativePath = pathname.replace(/^\/dashboard\/?/, '');
|
|
370
|
+
const safeRelativePath = relativePath.length === 0 ? 'index.html' : relativePath;
|
|
371
|
+
const resolvedPath = path.resolve(SERENA_DASHBOARD_DIR, decodeURIComponent(safeRelativePath));
|
|
372
|
+
if (!resolvedPath.startsWith(path.resolve(SERENA_DASHBOARD_DIR))) {
|
|
373
|
+
this.respondNotFound(res);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
const file = await fs.readFile(resolvedPath);
|
|
378
|
+
const ext = path.extname(resolvedPath).toLowerCase();
|
|
379
|
+
const contentType = CONTENT_TYPE_BY_EXTENSION[ext] ?? 'application/octet-stream';
|
|
380
|
+
res.statusCode = 200;
|
|
381
|
+
res.setHeader('Content-Type', contentType);
|
|
382
|
+
res.setHeader('Content-Length', file.length);
|
|
383
|
+
res.end(file);
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
if (error.code === 'ENOENT') {
|
|
387
|
+
this.respondNotFound(res);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async handleGetLogMessages(req, res) {
|
|
394
|
+
const requestBody = await this.parseRequestBody(req);
|
|
395
|
+
const startIdxCandidate = requestBody ? this.getNumberFromRecord(requestBody, 'start_idx') : undefined;
|
|
396
|
+
const startIdxRaw = startIdxCandidate ?? 0;
|
|
397
|
+
const startIdx = Number.isFinite(startIdxRaw) && startIdxRaw >= 0 ? Math.floor(startIdxRaw) : 0;
|
|
398
|
+
const logMessages = this.memoryLogHandler.getLogMessages();
|
|
399
|
+
const messages = startIdx <= logMessages.length ? logMessages.slice(startIdx) : [];
|
|
400
|
+
const maxIdx = logMessages.length > 0 ? logMessages.length - 1 : -1;
|
|
401
|
+
const activeProject = this.agent.getActiveProject()?.projectName ?? null;
|
|
402
|
+
const response = {
|
|
403
|
+
messages,
|
|
404
|
+
maxIdx,
|
|
405
|
+
activeProject
|
|
406
|
+
};
|
|
407
|
+
this.sendJson(res, 200, {
|
|
408
|
+
messages: response.messages,
|
|
409
|
+
max_idx: response.maxIdx,
|
|
410
|
+
active_project: response.activeProject
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
getToolStats() {
|
|
414
|
+
if (!this.toolUsageStats) {
|
|
415
|
+
return {};
|
|
416
|
+
}
|
|
417
|
+
const stats = this.toolUsageStats.getToolStatsDict();
|
|
418
|
+
const result = {};
|
|
419
|
+
for (const [toolName, entry] of Object.entries(stats)) {
|
|
420
|
+
const numTimesCalled = typeof entry.numTimesCalled === 'number' ? entry.numTimesCalled : 0;
|
|
421
|
+
const inputTokens = typeof entry.inputTokens === 'number' ? entry.inputTokens : 0;
|
|
422
|
+
const outputTokens = typeof entry.outputTokens === 'number' ? entry.outputTokens : 0;
|
|
423
|
+
result[toolName] = {
|
|
424
|
+
num_times_called: numTimesCalled,
|
|
425
|
+
input_tokens: inputTokens,
|
|
426
|
+
output_tokens: outputTokens
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
return result;
|
|
430
|
+
}
|
|
431
|
+
getNumberFromRecord(record, key) {
|
|
432
|
+
const value = record[key];
|
|
433
|
+
return typeof value === 'number' ? value : undefined;
|
|
434
|
+
}
|
|
435
|
+
async parseRequestBody(req) {
|
|
436
|
+
req.setEncoding('utf8');
|
|
437
|
+
let raw = '';
|
|
438
|
+
for await (const chunk of req) {
|
|
439
|
+
raw += chunk;
|
|
440
|
+
}
|
|
441
|
+
const trimmed = raw.trim();
|
|
442
|
+
if (trimmed.length === 0) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
const parsed = JSON.parse(trimmed);
|
|
447
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
448
|
+
return parsed;
|
|
449
|
+
}
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
logger.warn('Failed to parse dashboard request payload as JSON.', error instanceof Error ? error : undefined);
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
respondNotFound(res) {
|
|
458
|
+
res.statusCode = 404;
|
|
459
|
+
res.end('Not found');
|
|
460
|
+
}
|
|
461
|
+
respondMethodNotAllowed(res) {
|
|
462
|
+
res.statusCode = 405;
|
|
463
|
+
res.end('Method not allowed');
|
|
464
|
+
}
|
|
465
|
+
sendJson(res, statusCode, payload) {
|
|
466
|
+
const body = JSON.stringify(payload);
|
|
467
|
+
res.statusCode = statusCode;
|
|
468
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
469
|
+
res.setHeader('Content-Length', Buffer.byteLength(body, 'utf-8'));
|
|
470
|
+
res.end(body);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PromptFactoryBase, type PromptFactoryBaseOptions } from '../../interprompt/prompt_factory.js';
|
|
2
|
+
export interface CreateOnboardingPromptParams {
|
|
3
|
+
system: string;
|
|
4
|
+
}
|
|
5
|
+
export interface CreateSystemPromptParams {
|
|
6
|
+
availableMarkers: Iterable<string>;
|
|
7
|
+
availableTools: Iterable<string>;
|
|
8
|
+
contextSystemPrompt: string;
|
|
9
|
+
modeSystemPrompts: Iterable<string>;
|
|
10
|
+
}
|
|
11
|
+
export declare class PromptFactory extends PromptFactoryBase {
|
|
12
|
+
create_onboarding_prompt: (params: CreateOnboardingPromptParams) => string;
|
|
13
|
+
create_prepare_for_new_conversation: () => string;
|
|
14
|
+
create_summarize_changes: () => string;
|
|
15
|
+
create_system_prompt: (params: CreateSystemPromptParams) => string;
|
|
16
|
+
create_think_about_collected_information: () => string;
|
|
17
|
+
create_think_about_task_adherence: () => string;
|
|
18
|
+
create_think_about_whether_you_are_done: () => string;
|
|
19
|
+
constructor(options: PromptFactoryBaseOptions);
|
|
20
|
+
createOnboardingPrompt(params: CreateOnboardingPromptParams): string;
|
|
21
|
+
createPrepareForNewConversation(): string;
|
|
22
|
+
createSummarizeChanges(): string;
|
|
23
|
+
createSystemPrompt(params: CreateSystemPromptParams): string;
|
|
24
|
+
createThinkAboutCollectedInformation(): string;
|
|
25
|
+
createThinkAboutTaskAdherence(): string;
|
|
26
|
+
createThinkAboutWhetherYouAreDone(): string;
|
|
27
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// NOTE: This module is auto-generated via interprompt.autogeneratePromptFactoryModule. Do not edit manually.
|
|
2
|
+
import { PromptFactoryBase, } from '../../interprompt/prompt_factory.js';
|
|
3
|
+
export class PromptFactory extends PromptFactoryBase {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super(options);
|
|
6
|
+
this.create_onboarding_prompt = (params) => this.createOnboardingPrompt(params);
|
|
7
|
+
this.create_prepare_for_new_conversation = () => this.createPrepareForNewConversation();
|
|
8
|
+
this.create_summarize_changes = () => this.createSummarizeChanges();
|
|
9
|
+
this.create_system_prompt = (params) => this.createSystemPrompt(params);
|
|
10
|
+
this.create_think_about_collected_information = () => this.createThinkAboutCollectedInformation();
|
|
11
|
+
this.create_think_about_task_adherence = () => this.createThinkAboutTaskAdherence();
|
|
12
|
+
this.create_think_about_whether_you_are_done = () => this.createThinkAboutWhetherYouAreDone();
|
|
13
|
+
}
|
|
14
|
+
createOnboardingPrompt(params) {
|
|
15
|
+
return this.renderPromptTemplate('onboarding_prompt', {
|
|
16
|
+
system: params.system
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
createPrepareForNewConversation() {
|
|
20
|
+
return this.renderPromptTemplate('prepare_for_new_conversation', {});
|
|
21
|
+
}
|
|
22
|
+
createSummarizeChanges() {
|
|
23
|
+
return this.renderPromptTemplate('summarize_changes', {});
|
|
24
|
+
}
|
|
25
|
+
createSystemPrompt(params) {
|
|
26
|
+
return this.renderPromptTemplate('system_prompt', {
|
|
27
|
+
available_markers: Array.from(params.availableMarkers ?? []),
|
|
28
|
+
available_tools: Array.from(params.availableTools ?? []),
|
|
29
|
+
context_system_prompt: params.contextSystemPrompt,
|
|
30
|
+
mode_system_prompts: Array.from(params.modeSystemPrompts ?? [])
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
createThinkAboutCollectedInformation() {
|
|
34
|
+
return this.renderPromptTemplate('think_about_collected_information', {});
|
|
35
|
+
}
|
|
36
|
+
createThinkAboutTaskAdherence() {
|
|
37
|
+
return this.renderPromptTemplate('think_about_task_adherence', {});
|
|
38
|
+
}
|
|
39
|
+
createThinkAboutWhetherYouAreDone() {
|
|
40
|
+
return this.renderPromptTemplate('think_about_whether_you_are_done', {});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { MemoryLogHandler } from './util/logging.js';
|
|
2
|
+
export interface GuiLogViewerOptions {
|
|
3
|
+
title?: string;
|
|
4
|
+
memoryLogHandler?: MemoryLogHandler;
|
|
5
|
+
host?: string;
|
|
6
|
+
port?: number;
|
|
7
|
+
autoOpen?: boolean;
|
|
8
|
+
historyLimit?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class GuiLogViewer {
|
|
11
|
+
private readonly channel;
|
|
12
|
+
private readonly title;
|
|
13
|
+
private readonly memoryLogHandler?;
|
|
14
|
+
private readonly host;
|
|
15
|
+
private readonly requestedPort;
|
|
16
|
+
private readonly autoOpen;
|
|
17
|
+
private readonly historyLimit;
|
|
18
|
+
private toolNames;
|
|
19
|
+
private started;
|
|
20
|
+
private server;
|
|
21
|
+
private readonly sseClients;
|
|
22
|
+
private readonly history;
|
|
23
|
+
private memoryCallback?;
|
|
24
|
+
private readyPromise;
|
|
25
|
+
private port;
|
|
26
|
+
private logSequence;
|
|
27
|
+
constructor(channel: string, options?: GuiLogViewerOptions);
|
|
28
|
+
start(): Promise<void>;
|
|
29
|
+
stop(): Promise<void>;
|
|
30
|
+
setToolNames(toolNames: string[]): void;
|
|
31
|
+
addLog(message: string): void;
|
|
32
|
+
getBaseUrl(): string | null;
|
|
33
|
+
private recordLogMessage;
|
|
34
|
+
private broadcastLog;
|
|
35
|
+
private handleRequest;
|
|
36
|
+
private handleIndexRequest;
|
|
37
|
+
private handleEventStream;
|
|
38
|
+
private broadcast;
|
|
39
|
+
private renderHtmlPage;
|
|
40
|
+
}
|
|
41
|
+
export declare function showFatalException(error: unknown): Promise<void>;
|