laohuang 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -16
- package/dist/agent.d.ts +166 -0
- package/dist/agent.js +858 -0
- package/dist/agent.js.map +1 -0
- package/dist/bash-runner.d.ts +79 -0
- package/dist/bash-runner.js +464 -0
- package/dist/bash-runner.js.map +1 -0
- package/dist/cancellation.d.ts +36 -0
- package/dist/cancellation.js +123 -0
- package/dist/cancellation.js.map +1 -0
- package/dist/cli.d.ts +117 -0
- package/dist/cli.js +1307 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +17 -0
- package/dist/client.js.map +1 -0
- package/dist/commands.d.ts +123 -0
- package/dist/commands.js +660 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.js +183 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.d.ts +12 -0
- package/dist/credentials.js +102 -0
- package/dist/credentials.js.map +1 -0
- package/dist/events.d.ts +288 -0
- package/dist/events.js +838 -0
- package/dist/events.js.map +1 -0
- package/dist/model-adapter.d.ts +138 -0
- package/dist/model-adapter.js +244 -0
- package/dist/model-adapter.js.map +1 -0
- package/dist/model-selection.d.ts +67 -0
- package/dist/model-selection.js +148 -0
- package/dist/model-selection.js.map +1 -0
- package/dist/model-stream.d.ts +128 -0
- package/dist/model-stream.js +582 -0
- package/dist/model-stream.js.map +1 -0
- package/dist/project-instructions.d.ts +99 -0
- package/dist/project-instructions.js +348 -0
- package/dist/project-instructions.js.map +1 -0
- package/dist/providers.d.ts +9 -0
- package/dist/providers.js +26 -0
- package/dist/providers.js.map +1 -0
- package/dist/routing.d.ts +170 -0
- package/dist/routing.js +669 -0
- package/dist/routing.js.map +1 -0
- package/dist/semantic-classifier.d.ts +66 -0
- package/dist/semantic-classifier.js +86 -0
- package/dist/semantic-classifier.js.map +1 -0
- package/dist/session.d.ts +162 -0
- package/dist/session.js +871 -0
- package/dist/session.js.map +1 -0
- package/dist/system-prompt.d.ts +16 -0
- package/dist/system-prompt.js +42 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/terminal/editor.d.ts +161 -0
- package/dist/terminal/editor.js +1060 -0
- package/dist/terminal/editor.js.map +1 -0
- package/dist/terminal/input.d.ts +61 -0
- package/dist/terminal/input.js +276 -0
- package/dist/terminal/input.js.map +1 -0
- package/dist/terminal/markdown.d.ts +20 -0
- package/dist/terminal/markdown.js +621 -0
- package/dist/terminal/markdown.js.map +1 -0
- package/dist/terminal/screen.d.ts +66 -0
- package/dist/terminal/screen.js +624 -0
- package/dist/terminal/screen.js.map +1 -0
- package/dist/terminal/theme.d.ts +23 -0
- package/dist/terminal/theme.js +101 -0
- package/dist/terminal/theme.js.map +1 -0
- package/dist/terminal/ui.d.ts +285 -0
- package/dist/terminal/ui.js +1815 -0
- package/dist/terminal/ui.js.map +1 -0
- package/dist/tools.d.ts +95 -0
- package/dist/tools.js +444 -0
- package/dist/tools.js.map +1 -0
- package/dist/ui-state.d.ts +51 -0
- package/dist/ui-state.js +194 -0
- package/dist/ui-state.js.map +1 -0
- package/dist/web.d.ts +56 -0
- package/dist/web.js +247 -0
- package/dist/web.js.map +1 -0
- package/package.json +24 -21
- package/bin/laohuang.js +0 -10
- package/lib/launcher.js +0 -133
- package/vendor/laohuangcode-0.3.2-py3-none-any.whl +0 -0
package/README.md
CHANGED
|
@@ -1,27 +1,153 @@
|
|
|
1
|
-
#
|
|
1
|
+
# laoHuangCode
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
一个最小的 coding agent,基于 TypeScript/Node.js、官方 `openai` npm SDK 和
|
|
4
|
+
Chat Completions 原生工具调用。
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
当前提供四个工具:`read`、`write`、`edit`、`bash`。所有工具均直接执行,当前原型
|
|
7
|
+
暂不提供权限确认。
|
|
8
|
+
|
|
9
|
+
同一次模型响应中的只读工具与多个 Bash 调用默认并发执行。实时事件按工具实际完成
|
|
10
|
+
顺序发出,回传模型的 `tool` 消息保持原始调用顺序。只要一个批次包含 `write` 或
|
|
11
|
+
`edit`,Agent 会保守地串行执行整个批次,避免读写或多次修改之间出现竞态。
|
|
12
|
+
|
|
13
|
+
交互终端采用后台 AgentSession:模型回复和 Bash 的 stderr/状态会实时显示,stdout
|
|
14
|
+
会保留在工具结果中但默认不刷到终端,
|
|
15
|
+
Agent 运行时仍可继续输入。后续输入由事件路由器放入 pending/held 队列,并在安全点
|
|
16
|
+
成批交给模型;当前任务可以通过 `/cancel` 或运行中的 `Ctrl+C` 协作式取消。
|
|
17
|
+
连续重复的工具调用和 Token、耗时预算会触发安全保护;保护触发后
|
|
18
|
+
Agent 会禁用工具并尝试基于已有信息完成一次最终回答。
|
|
19
|
+
|
|
20
|
+
## 快速开始
|
|
21
|
+
|
|
22
|
+
需要 Node.js 18+。面向普通用户的安装方式:
|
|
11
23
|
|
|
12
24
|
```bash
|
|
13
25
|
npm install --global laohuang
|
|
14
|
-
laohuang --version
|
|
15
26
|
laohuang
|
|
16
27
|
```
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
首次启动会在终端中依次选择 DeepSeek 或 OpenAI、隐藏输入 API key、选择模型,
|
|
30
|
+
不需要设置环境变量。配置完成后,进入任意项目目录直接运行 `laohuang`。
|
|
31
|
+
|
|
32
|
+
从源码运行:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git clone https://github.com/hxr223/laoHuangCode.git
|
|
36
|
+
cd laoHuangCode
|
|
37
|
+
npm ci
|
|
38
|
+
npm run build
|
|
39
|
+
node dist/cli.js
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 模型配置
|
|
43
|
+
|
|
44
|
+
首次运行时,终端会提供两个供应商:
|
|
45
|
+
|
|
46
|
+
- DeepSeek:内置 `deepseek-v4-flash` 和 `deepseek-v4-pro`。
|
|
47
|
+
- OpenAI:使用输入的 API key 动态读取账户可用模型,也可手动输入模型名。
|
|
48
|
+
|
|
49
|
+
API key 使用隐藏输入,保存在独立的
|
|
50
|
+
`~/.config/laohuang/credentials.json` 中。普通模型配置保存在同目录的
|
|
51
|
+
`config.json`;两个文件均使用 `0600` 权限,目录使用 `0700` 权限。
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
/model 交互选择供应商和模型
|
|
55
|
+
/model current 查看当前模型
|
|
56
|
+
/model deepseek deepseek-v4-pro 直接切换模型
|
|
57
|
+
/model openai <model-name> 直接切换 OpenAI 模型
|
|
58
|
+
/login 交互选择供应商并登录
|
|
59
|
+
/login deepseek 输入或覆盖 DeepSeek API key
|
|
60
|
+
/logout openai 删除保存的 OpenAI 凭据
|
|
61
|
+
/cancel 取消当前运行任务
|
|
62
|
+
/queue 查看 pending/held/dead-letter 与估算 token
|
|
63
|
+
/queue resume 恢复取消后保留的消息
|
|
64
|
+
/queue clear 清空 pending/held/dead-letter
|
|
65
|
+
/clear 清空当前对话上下文
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
认证和模型选择相互独立:`/login`、`/logout` 管理凭据,`/model` 只切换模型。
|
|
69
|
+
如果请求返回 401,Agent 会提示对应的 `/login <provider>` 命令。旧的
|
|
70
|
+
`/apikey set`、`/apikey remove` 暂时保留为兼容别名。
|
|
71
|
+
|
|
72
|
+
常用配置命令:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
laohuang config list
|
|
76
|
+
laohuang config use default
|
|
77
|
+
laohuang doctor
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
完整规则见 [模型配置文档](docs/configuration.md)。
|
|
81
|
+
|
|
82
|
+
## 运行
|
|
83
|
+
|
|
84
|
+
进入希望 Agent 操作的项目目录后执行:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
laohuang
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
输入任务,使用 `/help` 查看命令,使用 `/exit` 或 `Ctrl+D` 退出。通过 `/model`
|
|
91
|
+
切换供应商或模型时会保留当前对话上下文。
|
|
92
|
+
|
|
93
|
+
交互终端使用简洁的上下边框标识输入区域,不显示常驻状态或快捷键底栏。输入 `/` 会
|
|
94
|
+
立即显示命令、说明和参数补全;`Tab`/`Enter` 可接受当前补全,`/model` 会按
|
|
95
|
+
“供应商 → 模型”分层补全。终端还支持多行
|
|
96
|
+
编辑和当前会话输入历史:
|
|
97
|
+
|
|
98
|
+
- `Enter`:发送任务。
|
|
99
|
+
- `Alt+Enter`:插入换行。
|
|
100
|
+
- `↑` / `↓`:浏览历史输入。
|
|
101
|
+
- Agent 运行中按 `Ctrl+C`:取消当前任务。
|
|
102
|
+
- Agent 空闲时按 `Ctrl+C`:清空输入;500ms 内再按一次:退出。
|
|
103
|
+
- `Ctrl+D`:退出。
|
|
104
|
+
|
|
105
|
+
模型文本和 Bash stderr/状态采用 append-only inline 流式展示,工具输出按 tool call 分组;
|
|
106
|
+
被取消或截断的半条模型回复会保留在屏幕上并标记“未加入上下文”。完整的逐轮事件仍可
|
|
107
|
+
通过 Web 日志面板查看。输出被重定向或由程序调用 CLI 时,会自动回退到稳定的纯文本
|
|
108
|
+
格式。
|
|
109
|
+
|
|
110
|
+
### 验证交互终端
|
|
111
|
+
|
|
112
|
+
1. 在真实 TTY 中运行 `laohuang`。
|
|
113
|
+
2. 发送第一个问题并等待回答完成。
|
|
114
|
+
3. 发送第二个问题;向上滚动确认第一个问题和回答仍保留且未被改写。
|
|
115
|
+
4. 输入 `/` 和 `/e`,确认候选只占可见行数,`Tab` 可接受 `/exit`,继续编辑会移除补全层。
|
|
116
|
+
5. 任务运行中按 `Ctrl+C` 取消;空闲且编辑器为空时按 `Ctrl+D` 退出。
|
|
117
|
+
|
|
118
|
+
当前版本不会在工具执行前请求确认。请只在你信任的项目和环境中运行。
|
|
119
|
+
|
|
120
|
+
### Web 日志面板
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
laohuang --web
|
|
124
|
+
laohuang --web --web-port 9000
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
面板默认位于 <http://127.0.0.1:8765>,展示模型轮次、工具调用和最终
|
|
128
|
+
回复。它只监听本机,数据只存在内存中,进程退出后清空。
|
|
129
|
+
|
|
130
|
+
## 开发与发布检查
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm ci
|
|
134
|
+
npm run build
|
|
135
|
+
npm test
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`npm run build` 通过 `tsc` 把 `src/` 编译到 `dist/`;`npm test` 使用 Node 自带的
|
|
139
|
+
`node:test` 运行 `test/` 下的离线测试套件,不需要网络访问。发布流程见
|
|
140
|
+
[发布流程](docs/publishing.md) 和 [npm 分发说明](docs/npm-distribution.md)。
|
|
141
|
+
|
|
142
|
+
## 安全边界
|
|
143
|
+
|
|
144
|
+
文件工具会限制在启动目录内并阻止符号链接逃逸;API key 不通过环境变量传递给
|
|
145
|
+
Bash。但 `bash` **没有操作系统级沙箱**,执行后仍能访问项目外文件、网络和其他
|
|
146
|
+
系统资源。公开使用前请阅读 [安全模型](docs/security.md)。
|
|
21
147
|
|
|
22
|
-
|
|
148
|
+
架构说明见 [docs/architecture.md](docs/architecture.md);设计文档归档在
|
|
149
|
+
[docs/superpowers/specs/](docs/superpowers/specs/)。
|
|
23
150
|
|
|
24
|
-
|
|
25
|
-
- `LAOHUANG_CACHE_HOME`: override the launcher's cache root.
|
|
151
|
+
## License
|
|
26
152
|
|
|
27
|
-
|
|
153
|
+
MIT
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The model/tool loop at the heart of laoHuangCode.
|
|
3
|
+
*
|
|
4
|
+
* One user turn streams model completions through the provider-neutral
|
|
5
|
+
* adapter boundary (model-adapter.ts), commits
|
|
6
|
+
* only fully validated attempts to history (atomically, via the owning
|
|
7
|
+
* session's commit hooks when present), executes tool-call batches
|
|
8
|
+
* (read-only tools and multiple bash calls concurrently; any write/edit or
|
|
9
|
+
* sequential-mode tool makes the whole batch serial), and enforces the
|
|
10
|
+
* runtime guard rails: repeated-identical-tool-call detection plus token and
|
|
11
|
+
* duration budgets. A triggered guard disables tools and asks the model for
|
|
12
|
+
* one final answer from the information already gathered.
|
|
13
|
+
*/
|
|
14
|
+
import { CancelToken } from "./cancellation.ts";
|
|
15
|
+
import { EventKind, EventSource, type EventBus } from "./events.ts";
|
|
16
|
+
import { type ChatClientLike } from "./model-adapter.ts";
|
|
17
|
+
import type { ToolDefinition, ToolExecutionContextLike, ToolExecutionMode, ToolResult, ToolSpec } from "./tools.ts";
|
|
18
|
+
import { ProjectInstructionState } from "./project-instructions.ts";
|
|
19
|
+
export declare const FORCED_FINAL_PROMPT = "Tool use has been stopped by the runtime safety guard.\nDo not call any tools. Give the user the best concise answer possible from the\ninformation already available. Clearly state any limitation caused by stopping\ntool use, but do not mention internal implementation details unless useful.";
|
|
20
|
+
/** Raised when the model response cannot drive the agent loop. */
|
|
21
|
+
export declare class AgentError extends Error {
|
|
22
|
+
constructor(message: string, options?: {
|
|
23
|
+
cause?: unknown;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** Raised when the active agent task is cooperatively cancelled. */
|
|
27
|
+
export declare class AgentCancelled extends AgentError {
|
|
28
|
+
constructor(message: string, options?: {
|
|
29
|
+
cause?: unknown;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export type AgentEventCallback = (eventType: string, payload: Record<string, unknown>) => void;
|
|
33
|
+
export type ToolEventCallback = (name: string, args: Record<string, unknown>, result: ToolResult) => void;
|
|
34
|
+
export type { ChatClientLike } from "./model-adapter.ts";
|
|
35
|
+
/** Structural minimum of ToolRegistry (tools.ts) the agent relies on. */
|
|
36
|
+
export interface AgentToolRegistry {
|
|
37
|
+
readonly definitions: readonly ToolDefinition[];
|
|
38
|
+
readonly orderedSpecs: readonly ToolSpec[];
|
|
39
|
+
executionMode(name: string): ToolExecutionMode | undefined;
|
|
40
|
+
execute(name: string, args: Record<string, unknown>, context?: ToolExecutionContextLike): Promise<ToolResult> | ToolResult;
|
|
41
|
+
}
|
|
42
|
+
/** Pending user input handed over at a session safe point. */
|
|
43
|
+
export interface PendingInputBatchLike {
|
|
44
|
+
content?: string | undefined;
|
|
45
|
+
eventIds?: readonly string[] | undefined;
|
|
46
|
+
}
|
|
47
|
+
/** Options for the session-owned publish hook. */
|
|
48
|
+
export interface AgentEventPublishOptions {
|
|
49
|
+
source: EventSource;
|
|
50
|
+
correlation_id: string | null;
|
|
51
|
+
payload: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Capabilities the owning session (session.ts) exposes to one agent run.
|
|
55
|
+
* Every member is optional; without a context the agent runs standalone and
|
|
56
|
+
* manages its own history commits and cancellation checks.
|
|
57
|
+
*/
|
|
58
|
+
export interface AgentContext {
|
|
59
|
+
readonly sessionId?: string | null;
|
|
60
|
+
readonly taskId?: string | null;
|
|
61
|
+
readonly cancelToken?: CancelToken | null;
|
|
62
|
+
readonly eventBus?: EventBus | null;
|
|
63
|
+
publish?(kind: EventKind, options: AgentEventPublishOptions): unknown;
|
|
64
|
+
/** Return false to cancel before the model request is sent. */
|
|
65
|
+
modelStarted?(): boolean | void;
|
|
66
|
+
/** Called once the SDK acknowledged the streaming request. */
|
|
67
|
+
modelRequestOpened?(): boolean | void;
|
|
68
|
+
toolsStarted?(): void;
|
|
69
|
+
safePoint?(): PendingInputBatchLike | null | undefined;
|
|
70
|
+
/** Atomically commit the user message; rollback undoes a failed commit. */
|
|
71
|
+
commitInput?(append: () => void, rollback: () => void): boolean;
|
|
72
|
+
commitPending?(batch: PendingInputBatchLike, append: () => void, rollback: () => void): boolean;
|
|
73
|
+
/** Atomically reject history commits once cancellation has won. */
|
|
74
|
+
commitIfActive?(callback: () => void): boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface RunOptions {
|
|
77
|
+
cancelToken?: CancelToken | null;
|
|
78
|
+
requestId?: string | null;
|
|
79
|
+
isRequestActive?: ((requestId: string) => boolean) | null;
|
|
80
|
+
}
|
|
81
|
+
export interface CodingAgentOptions {
|
|
82
|
+
client: ChatClientLike;
|
|
83
|
+
model: string;
|
|
84
|
+
tools: AgentToolRegistry;
|
|
85
|
+
maxTotalTokens?: number;
|
|
86
|
+
maxElapsedSeconds?: number;
|
|
87
|
+
repeatedToolCallLimit?: number;
|
|
88
|
+
onToolEvent?: ToolEventCallback | null;
|
|
89
|
+
onAgentEvent?: AgentEventCallback | null;
|
|
90
|
+
provider?: string | null;
|
|
91
|
+
toolExecution?: ToolExecutionMode;
|
|
92
|
+
/**
|
|
93
|
+
* Project root used only for project-instruction loading (both this and
|
|
94
|
+
* `startupCwd` must be set; omit both to disable instruction injection).
|
|
95
|
+
*/
|
|
96
|
+
projectRoot?: string | null;
|
|
97
|
+
/** Startup cwd for project-instruction discovery. */
|
|
98
|
+
startupCwd?: string | null;
|
|
99
|
+
}
|
|
100
|
+
/** Execution context handed to every tool call in a batch. */
|
|
101
|
+
export interface AgentToolContext extends ToolExecutionContextLike {
|
|
102
|
+
readonly sessionId: string | null;
|
|
103
|
+
readonly taskId: string | null;
|
|
104
|
+
readonly toolCallId: string | null;
|
|
105
|
+
readonly cancelToken: CancelToken | null;
|
|
106
|
+
}
|
|
107
|
+
export declare class CodingAgent {
|
|
108
|
+
client: ChatClientLike;
|
|
109
|
+
model: string;
|
|
110
|
+
provider: string | null;
|
|
111
|
+
/** Provider-neutral model access; resolved from `provider`. */
|
|
112
|
+
private adapter;
|
|
113
|
+
readonly tools: AgentToolRegistry;
|
|
114
|
+
readonly maxTotalTokens: number;
|
|
115
|
+
readonly maxElapsedSeconds: number;
|
|
116
|
+
readonly repeatedToolCallLimit: number;
|
|
117
|
+
readonly toolExecution: ToolExecutionMode;
|
|
118
|
+
/** Conversation history in Chat Completions wire shape. */
|
|
119
|
+
messages: Array<Record<string, unknown>>;
|
|
120
|
+
private readonly onToolEvent;
|
|
121
|
+
private readonly onAgentEvent;
|
|
122
|
+
private readonly instructionRoot;
|
|
123
|
+
private readonly startupCwd;
|
|
124
|
+
private baselineInstructionsLoaded;
|
|
125
|
+
private instructionState;
|
|
126
|
+
private turn;
|
|
127
|
+
private activeContext;
|
|
128
|
+
private activeRequestId;
|
|
129
|
+
constructor(options: CodingAgentOptions);
|
|
130
|
+
/** Bookkeeping for loaded project instructions (never model-visible). */
|
|
131
|
+
get projectInstructionState(): ProjectInstructionState | null;
|
|
132
|
+
/** Swap the model client mid-conversation, keeping portable history. */
|
|
133
|
+
switchModel(options: {
|
|
134
|
+
client: unknown;
|
|
135
|
+
model: string;
|
|
136
|
+
provider: string;
|
|
137
|
+
}): void;
|
|
138
|
+
/** Run one user turn, committing only fully validated model attempts. */
|
|
139
|
+
run(userInput: string, context?: AgentContext | null, options?: RunOptions): Promise<string>;
|
|
140
|
+
private budgetGuardReason;
|
|
141
|
+
private guardPayload;
|
|
142
|
+
private recordRepeatedToolCalls;
|
|
143
|
+
private executeToolBatch;
|
|
144
|
+
private executeTool;
|
|
145
|
+
private finishToolEvent;
|
|
146
|
+
/**
|
|
147
|
+
* Append the rendered baseline project instructions once per session,
|
|
148
|
+
* right after the first direct user message and before the first model
|
|
149
|
+
* request. Append-only: the system prompt and committed history are never
|
|
150
|
+
* rebuilt, and nothing is appended when no instruction files exist.
|
|
151
|
+
*/
|
|
152
|
+
private injectBaselineInstructions;
|
|
153
|
+
/**
|
|
154
|
+
* DSH-style dynamic descendant discovery: for every parent directory from
|
|
155
|
+
* the instruction root to each successfully touched path's directory,
|
|
156
|
+
* render instructions from scopes not already represented by the
|
|
157
|
+
* instruction state as one additional reminder message. Append-only and
|
|
158
|
+
* duplicate-suppressed by ProjectInstructionState; a no-op when
|
|
159
|
+
* instruction loading is not configured.
|
|
160
|
+
*/
|
|
161
|
+
private discoverForTouchedPaths;
|
|
162
|
+
private commitContextMessage;
|
|
163
|
+
private emit;
|
|
164
|
+
private emitLegacy;
|
|
165
|
+
private publishRuntimeEvent;
|
|
166
|
+
}
|