@skillfm/local 2.2.0 → 2.5.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.
Files changed (101) hide show
  1. package/README.md +12 -0
  2. package/dist/doctor.js.map +1 -1
  3. package/dist/guard/cli.d.ts.map +1 -1
  4. package/dist/guard/cli.js.map +1 -1
  5. package/dist/harness/kernels/deny-pipeline.js +1 -1
  6. package/dist/harness/kernels/deny-pipeline.js.map +1 -1
  7. package/dist/harness/writers.d.ts.map +1 -1
  8. package/dist/harness/writers.js +2 -0
  9. package/dist/harness/writers.js.map +1 -1
  10. package/dist/index.js +29 -3
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp-stdio/api-client.d.ts.map +1 -1
  13. package/dist/mcp-stdio/api-client.js +3 -0
  14. package/dist/mcp-stdio/api-client.js.map +1 -1
  15. package/dist/mcp-stdio/render-flow.d.ts.map +1 -1
  16. package/dist/mcp-stdio/render-flow.js.map +1 -1
  17. package/dist/mcp-stdio/request-context.d.ts.map +1 -1
  18. package/dist/mcp-stdio/request-context.js +1 -0
  19. package/dist/mcp-stdio/request-context.js.map +1 -1
  20. package/dist/mcp-stdio/server.d.ts.map +1 -1
  21. package/dist/mcp-stdio/server.js +118 -17
  22. package/dist/mcp-stdio/server.js.map +1 -1
  23. package/dist/mcp-stdio/sse-progress-client.js.map +1 -1
  24. package/dist/skill-installer/bundle-fetcher.d.ts +40 -0
  25. package/dist/skill-installer/bundle-fetcher.d.ts.map +1 -0
  26. package/dist/skill-installer/bundle-fetcher.js +133 -0
  27. package/dist/skill-installer/bundle-fetcher.js.map +1 -0
  28. package/dist/skill-installer/errors.d.ts +12 -0
  29. package/dist/skill-installer/errors.d.ts.map +1 -0
  30. package/dist/skill-installer/errors.js +42 -0
  31. package/dist/skill-installer/errors.js.map +1 -0
  32. package/dist/skill-installer/index.d.ts +20 -0
  33. package/dist/skill-installer/index.d.ts.map +1 -0
  34. package/dist/skill-installer/index.js +193 -0
  35. package/dist/skill-installer/index.js.map +1 -0
  36. package/dist/skill-installer/lockfile.d.ts +8 -0
  37. package/dist/skill-installer/lockfile.d.ts.map +1 -0
  38. package/dist/skill-installer/lockfile.js +52 -0
  39. package/dist/skill-installer/lockfile.js.map +1 -0
  40. package/dist/skill-installer/npm-installer.d.ts +16 -0
  41. package/dist/skill-installer/npm-installer.d.ts.map +1 -0
  42. package/dist/skill-installer/npm-installer.js +83 -0
  43. package/dist/skill-installer/npm-installer.js.map +1 -0
  44. package/dist/skill-installer/paths.d.ts +4 -0
  45. package/dist/skill-installer/paths.d.ts.map +1 -0
  46. package/dist/skill-installer/paths.js +16 -0
  47. package/dist/skill-installer/paths.js.map +1 -0
  48. package/dist/skill-installer/tar-extractor.d.ts +15 -0
  49. package/dist/skill-installer/tar-extractor.d.ts.map +1 -0
  50. package/dist/skill-installer/tar-extractor.js +56 -0
  51. package/dist/skill-installer/tar-extractor.js.map +1 -0
  52. package/dist/skill-md/template.js +2 -2
  53. package/dist/skill-runner/cli.d.ts +4 -0
  54. package/dist/skill-runner/cli.d.ts.map +1 -0
  55. package/dist/skill-runner/cli.js +81 -0
  56. package/dist/skill-runner/cli.js.map +1 -0
  57. package/dist/skill-runner/discovery.d.ts +3 -0
  58. package/dist/skill-runner/discovery.d.ts.map +1 -0
  59. package/dist/skill-runner/discovery.js +108 -0
  60. package/dist/skill-runner/discovery.js.map +1 -0
  61. package/dist/skill-runner/index.d.ts +9 -0
  62. package/dist/skill-runner/index.d.ts.map +1 -0
  63. package/dist/skill-runner/index.js +100 -0
  64. package/dist/skill-runner/index.js.map +1 -0
  65. package/dist/skill-runner/registry.d.ts +11 -0
  66. package/dist/skill-runner/registry.d.ts.map +1 -0
  67. package/dist/skill-runner/registry.js +79 -0
  68. package/dist/skill-runner/registry.js.map +1 -0
  69. package/dist/skill-runner/spawner.d.ts +14 -0
  70. package/dist/skill-runner/spawner.d.ts.map +1 -0
  71. package/dist/skill-runner/spawner.js +85 -0
  72. package/dist/skill-runner/spawner.js.map +1 -0
  73. package/dist/skill-runner/types.d.ts +62 -0
  74. package/dist/skill-runner/types.d.ts.map +1 -0
  75. package/dist/skill-runner/types.js +6 -0
  76. package/dist/skill-runner/types.js.map +1 -0
  77. package/dist/skill-tunnel/cli.d.ts +5 -0
  78. package/dist/skill-tunnel/cli.d.ts.map +1 -0
  79. package/dist/skill-tunnel/cli.js +205 -0
  80. package/dist/skill-tunnel/cli.js.map +1 -0
  81. package/dist/skill-tunnel/client.d.ts +56 -0
  82. package/dist/skill-tunnel/client.d.ts.map +1 -0
  83. package/dist/skill-tunnel/client.js +260 -0
  84. package/dist/skill-tunnel/client.js.map +1 -0
  85. package/dist/skill-tunnel/handshake.d.ts +35 -0
  86. package/dist/skill-tunnel/handshake.d.ts.map +1 -0
  87. package/dist/skill-tunnel/handshake.js +61 -0
  88. package/dist/skill-tunnel/handshake.js.map +1 -0
  89. package/dist/skill-tunnel/heartbeat.d.ts +34 -0
  90. package/dist/skill-tunnel/heartbeat.d.ts.map +1 -0
  91. package/dist/skill-tunnel/heartbeat.js +86 -0
  92. package/dist/skill-tunnel/heartbeat.js.map +1 -0
  93. package/dist/skill-tunnel/local-bridge.d.ts +30 -0
  94. package/dist/skill-tunnel/local-bridge.d.ts.map +1 -0
  95. package/dist/skill-tunnel/local-bridge.js +224 -0
  96. package/dist/skill-tunnel/local-bridge.js.map +1 -0
  97. package/dist/skill-tunnel/reconnect.d.ts +21 -0
  98. package/dist/skill-tunnel/reconnect.d.ts.map +1 -0
  99. package/dist/skill-tunnel/reconnect.js +72 -0
  100. package/dist/skill-tunnel/reconnect.js.map +1 -0
  101. package/package.json +5 -2
@@ -0,0 +1,85 @@
1
+ // M1 skill-runner — skill 子进程 spawn + health check
2
+ //
3
+ // 设计原则:
4
+ // - 一旦 spawn 成功,立即返回 PID 给调用者(不阻塞等 health ready)
5
+ // - health check 另起一次异步 poll,失败不 kill 子进程(交给调用者决定)—— 方便诊断
6
+ import { spawn } from 'node:child_process';
7
+ import { setTimeout as sleep } from 'node:timers/promises';
8
+ function spawnEntry(entryPath, env, label) {
9
+ const proc = spawn(process.execPath, [entryPath], {
10
+ env,
11
+ detached: true,
12
+ stdio: 'ignore',
13
+ });
14
+ if (!proc.pid) {
15
+ throw Object.assign(new Error(`spawn ${label} 失败:pid 未返回`), { code: 'SPAWN_FAILED' });
16
+ }
17
+ // 脱离 parent 事件循环,允许 @skillfm/local 退出后子进程继续跑
18
+ proc.unref();
19
+ return proc;
20
+ }
21
+ export async function spawnSkill(params) {
22
+ const { location, env_overrides, start_daemon } = params;
23
+ const env = {
24
+ ...process.env,
25
+ ...env_overrides,
26
+ SKILL_HOST: '127.0.0.1',
27
+ SKILL_PORT: String(location.port),
28
+ };
29
+ const serverProc = spawnEntry(location.server_entry, env, `${location.slug} server`);
30
+ let daemonPid = null;
31
+ if (start_daemon && location.daemon_entry) {
32
+ const daemonProc = spawnEntry(location.daemon_entry, env, `${location.slug} daemon`);
33
+ daemonPid = daemonProc.pid ?? null;
34
+ }
35
+ return {
36
+ slug: location.slug,
37
+ version: location.version,
38
+ port: location.port,
39
+ server_pid: serverProc.pid,
40
+ daemon_pid: daemonPid,
41
+ started_at: new Date().toISOString(),
42
+ endpoint: `http://127.0.0.1:${location.port}`,
43
+ };
44
+ }
45
+ /** Poll GET {endpoint}/health 直到 200 或超时 */
46
+ export async function waitForHealthy(endpoint, timeoutMs) {
47
+ const healthUrl = `${endpoint}/health`;
48
+ const deadline = Date.now() + timeoutMs;
49
+ let attempt = 0;
50
+ while (Date.now() < deadline) {
51
+ attempt += 1;
52
+ try {
53
+ const controller = new AbortController();
54
+ const timer = setTimeout(() => controller.abort(), 2000);
55
+ const res = await fetch(healthUrl, { signal: controller.signal });
56
+ clearTimeout(timer);
57
+ if (res.ok)
58
+ return true;
59
+ }
60
+ catch {
61
+ // fall through to sleep
62
+ }
63
+ // 指数退避但 cap 在 1s
64
+ const delay = Math.min(200 * 2 ** Math.min(attempt, 3), 1000);
65
+ await sleep(delay);
66
+ }
67
+ return false;
68
+ }
69
+ /** Kill a running skill process tree. Returns true if kill signal delivered. */
70
+ export function killSkill(handle) {
71
+ let killed = false;
72
+ for (const pid of [handle.server_pid, handle.daemon_pid]) {
73
+ if (pid && pid > 0) {
74
+ try {
75
+ process.kill(pid, 'SIGTERM');
76
+ killed = true;
77
+ }
78
+ catch {
79
+ // Process may already be dead — swallow
80
+ }
81
+ }
82
+ }
83
+ return killed;
84
+ }
85
+ //# sourceMappingURL=spawner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawner.js","sourceRoot":"","sources":["../../src/skill-runner/spawner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ export interface SkillBundleLocation {
2
+ /** skill slug(manifest.metadata.slug)*/
3
+ slug: string;
4
+ /** skill 语义版本(manifest.metadata.version)*/
5
+ version: string;
6
+ /** bundle 根目录绝对路径 */
7
+ bundle_dir: string;
8
+ /** runtime server 入口脚本绝对路径(默认 <bundle>/runtime/server.js)*/
9
+ server_entry: string;
10
+ /** runtime daemon 入口脚本绝对路径(可选)*/
11
+ daemon_entry: string | null;
12
+ /** loopback 监听端口,从 manifest runtime.endpoint 解析 */
13
+ port: number;
14
+ }
15
+ export interface SkillDaemonHandle {
16
+ slug: string;
17
+ version: string;
18
+ port: number;
19
+ /** server 子进程 PID */
20
+ server_pid: number;
21
+ /** daemon 子进程 PID(可选,M1 默认不启动 daemon 进程)*/
22
+ daemon_pid: number | null;
23
+ started_at: string;
24
+ /** loopback URL —— 永远 127.0.0.1,守 §1.5 BYOK 红线 */
25
+ endpoint: string;
26
+ }
27
+ export interface LocalSkillRegistryEntry extends SkillDaemonHandle {
28
+ /** skill bundle 目录(方便 stop 命令清理时直接找)*/
29
+ bundle_dir: string;
30
+ /** 上次 health check 成功时间(ms timestamp)*/
31
+ last_health_at: number;
32
+ }
33
+ /** `~/.skillfm/skills.local.json` 顶层结构 */
34
+ export interface LocalSkillRegistry {
35
+ version: 1;
36
+ skills: Record<string, LocalSkillRegistryEntry>;
37
+ }
38
+ export interface RunSkillOptions {
39
+ /** skill slug,例如 `xianyu-avatar-adult` */
40
+ slug: string;
41
+ /** 可选:bundle 查找根目录覆盖。默认 env `SKILLFM_SKILL_BUNDLE_ROOT` 或 `~/.skillfm/skills` */
42
+ bundle_root_override?: string;
43
+ /** health check 轮询超时(默认 20s)*/
44
+ health_timeout_ms?: number;
45
+ /** 是否同时启动 daemon 子进程(默认 false —— M1 先只启动 server)*/
46
+ start_daemon?: boolean;
47
+ /** 注入到 skill 子进程的环境变量(用于 cookie 路径等 BYOK 配置)*/
48
+ env_overrides?: Record<string, string>;
49
+ }
50
+ /** run-skill CLI 输出(成功时)*/
51
+ export interface RunSkillResult {
52
+ ok: true;
53
+ handle: SkillDaemonHandle;
54
+ hint_for_agent: string;
55
+ }
56
+ export interface RunSkillError {
57
+ ok: false;
58
+ error: 'SKILL_NOT_FOUND' | 'MANIFEST_INVALID' | 'ALREADY_RUNNING' | 'PORT_CONFLICT' | 'SPAWN_FAILED' | 'HEALTH_TIMEOUT';
59
+ message: string;
60
+ hint_for_agent: string;
61
+ }
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/skill-runner/types.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,2BAA2B;AAC3B,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,iBAAiB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EACD,iBAAiB,GACjB,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,GACf,cAAc,GACd,gBAAgB,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB"}
@@ -0,0 +1,6 @@
1
+ // M1 skill-runner — shared types
2
+ //
3
+ // 本文件是 @skillfm/local skill daemon 管理模块的对外类型。其它 subagent(M2 tunnel client)
4
+ // 会依赖这里的 SkillDaemonHandle / LocalSkillRegistryEntry,不依赖内部实现。
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/skill-runner/types.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,EAAE;AACF,2EAA2E;AAC3E,8DAA8D"}
@@ -0,0 +1,5 @@
1
+ export declare function cmdTunnelStart(): Promise<void>;
2
+ export declare function cmdTunnelStop(): void;
3
+ export declare function cmdTunnelStatus(): void;
4
+ export declare function cmdTunnel(): Promise<void>;
5
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/skill-tunnel/cli.ts"],"names":[],"mappings":"AA2EA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAyFpD;AAED,wBAAgB,aAAa,IAAI,IAAI,CA8BpC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAQtC;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAwB/C"}
@@ -0,0 +1,205 @@
1
+ // M2 SkillTunnelClient — CLI subcommand
2
+ //
3
+ // `skillfm-local tunnel start|stop|status`
4
+ // 简易实现: start 在当前进程起 tunnel(不 daemon 化),stop/status 通过 PID 文件。
5
+ // daemon 化(launchd / nohup)留给上层部署脚本,这里只提供基础设施。
6
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync, } from 'node:fs';
7
+ import { join, dirname } from 'node:path';
8
+ import { homedir } from 'node:os';
9
+ import { readRegistry } from '../skill-runner/registry.js';
10
+ import { SkillTunnelClient } from './client.js';
11
+ const PID_FILE = join(homedir(), '.skillfm', 'tunnel.pid');
12
+ const DEFAULT_BRAIN_URL = process.env.SKILLFM_BRAIN_TUNNEL_URL ?? 'wss://api.skillfm.ai/v1/skill-tunnel';
13
+ function ensureDir() {
14
+ const dir = dirname(PID_FILE);
15
+ if (!existsSync(dir))
16
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
17
+ }
18
+ function parseFlags(args) {
19
+ const flags = {};
20
+ for (let i = 0; i < args.length; i += 1) {
21
+ const t = args[i];
22
+ if (!t.startsWith('--'))
23
+ continue;
24
+ const eq = t.indexOf('=');
25
+ if (eq > 0) {
26
+ flags[t.slice(2, eq)] = t.slice(eq + 1);
27
+ }
28
+ else {
29
+ const next = args[i + 1];
30
+ if (next !== undefined && !next.startsWith('--')) {
31
+ flags[t.slice(2)] = next;
32
+ i += 1;
33
+ }
34
+ else {
35
+ flags[t.slice(2)] = true;
36
+ }
37
+ }
38
+ }
39
+ return flags;
40
+ }
41
+ function readConfig() {
42
+ const path = join(homedir(), '.skillfm', 'config.json');
43
+ if (!existsSync(path))
44
+ return {};
45
+ try {
46
+ return JSON.parse(readFileSync(path, 'utf-8'));
47
+ }
48
+ catch {
49
+ return {};
50
+ }
51
+ }
52
+ function readPackageVersion() {
53
+ // 只读顶层 package.json 里版本;build 后 dist/ 同级已经没有 package.json,fallback 环境变量
54
+ return process.env.SKILLFM_LOCAL_VERSION ?? '0.0.0';
55
+ }
56
+ function isProcessAlive(pid) {
57
+ try {
58
+ process.kill(pid, 0);
59
+ return true;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }
65
+ export async function cmdTunnelStart() {
66
+ const flags = parseFlags(process.argv.slice(3));
67
+ const brainUrl = typeof flags['brain-url'] === 'string' ? flags['brain-url'] : DEFAULT_BRAIN_URL;
68
+ // 检查是否已在跑
69
+ if (existsSync(PID_FILE)) {
70
+ const pid = Number.parseInt(readFileSync(PID_FILE, 'utf-8'), 10);
71
+ if (Number.isFinite(pid) && isProcessAlive(pid)) {
72
+ console.log(JSON.stringify({
73
+ ok: false,
74
+ error: 'ALREADY_RUNNING',
75
+ message: `tunnel 已在跑 (pid=${pid})`,
76
+ }));
77
+ process.exit(1);
78
+ return;
79
+ }
80
+ // PID 文件残留,清理
81
+ try {
82
+ rmSync(PID_FILE);
83
+ }
84
+ catch {
85
+ // ignore
86
+ }
87
+ }
88
+ const cfg = readConfig();
89
+ const agentToken = process.env.SKILLFM_AGENT_TOKEN ?? cfg.agent_token ?? '';
90
+ const authSecret = process.env.SKILLFM_SKILL_AUTH_SECRET ?? cfg.auth_secret ?? '';
91
+ if (!agentToken || !authSecret) {
92
+ console.log(JSON.stringify({
93
+ ok: false,
94
+ error: 'MISSING_CREDENTIALS',
95
+ message: 'agent_token / auth_secret 缺失. 请设 env SKILLFM_AGENT_TOKEN + SKILLFM_SKILL_AUTH_SECRET,或写入 ~/.skillfm/config.json',
96
+ }));
97
+ process.exit(1);
98
+ return;
99
+ }
100
+ const registry = readRegistry();
101
+ const localSkills = Object.values(registry.skills);
102
+ ensureDir();
103
+ writeFileSync(PID_FILE, String(process.pid), { mode: 0o600 });
104
+ const client = new SkillTunnelClient({
105
+ brainUrl,
106
+ agentToken,
107
+ authSecret,
108
+ localSkills,
109
+ skillfmLocalVersion: readPackageVersion(),
110
+ onStatusChange: (s) => {
111
+ console.error(`[tunnel] status=${s}`);
112
+ },
113
+ });
114
+ const cleanup = async () => {
115
+ try {
116
+ await client.stop();
117
+ }
118
+ finally {
119
+ try {
120
+ rmSync(PID_FILE);
121
+ }
122
+ catch {
123
+ // ignore
124
+ }
125
+ }
126
+ };
127
+ process.on('SIGINT', () => {
128
+ void cleanup().then(() => process.exit(0));
129
+ });
130
+ process.on('SIGTERM', () => {
131
+ void cleanup().then(() => process.exit(0));
132
+ });
133
+ console.log(JSON.stringify({
134
+ ok: true,
135
+ message: `tunnel 启动 pid=${process.pid} brain=${brainUrl} skills=${localSkills.length}`,
136
+ pid: process.pid,
137
+ }));
138
+ await client.start();
139
+ // 保持进程存活
140
+ await new Promise(() => { });
141
+ }
142
+ export function cmdTunnelStop() {
143
+ if (!existsSync(PID_FILE)) {
144
+ console.log(JSON.stringify({ ok: false, error: 'NOT_RUNNING' }));
145
+ process.exit(1);
146
+ return;
147
+ }
148
+ const pid = Number.parseInt(readFileSync(PID_FILE, 'utf-8'), 10);
149
+ if (!Number.isFinite(pid)) {
150
+ try {
151
+ rmSync(PID_FILE);
152
+ }
153
+ catch {
154
+ // ignore
155
+ }
156
+ console.log(JSON.stringify({ ok: false, error: 'BAD_PID_FILE' }));
157
+ process.exit(1);
158
+ return;
159
+ }
160
+ try {
161
+ process.kill(pid, 'SIGTERM');
162
+ console.log(JSON.stringify({ ok: true, pid, message: 'SIGTERM sent' }));
163
+ }
164
+ catch (err) {
165
+ console.log(JSON.stringify({
166
+ ok: false,
167
+ error: 'KILL_FAILED',
168
+ message: err.message,
169
+ }));
170
+ process.exit(1);
171
+ }
172
+ }
173
+ export function cmdTunnelStatus() {
174
+ if (!existsSync(PID_FILE)) {
175
+ console.log(JSON.stringify({ ok: true, running: false }));
176
+ return;
177
+ }
178
+ const pid = Number.parseInt(readFileSync(PID_FILE, 'utf-8'), 10);
179
+ const alive = Number.isFinite(pid) && isProcessAlive(pid);
180
+ console.log(JSON.stringify({ ok: true, running: alive, pid }));
181
+ }
182
+ export async function cmdTunnel() {
183
+ const sub = process.argv[3];
184
+ switch (sub) {
185
+ case 'start':
186
+ // shift argv so parseFlags 看到 `start` 之后的 flags
187
+ process.argv.splice(3, 1);
188
+ await cmdTunnelStart();
189
+ break;
190
+ case 'stop':
191
+ cmdTunnelStop();
192
+ break;
193
+ case 'status':
194
+ cmdTunnelStatus();
195
+ break;
196
+ default:
197
+ console.error(JSON.stringify({
198
+ ok: false,
199
+ error: 'UNKNOWN_SUBCOMMAND',
200
+ message: 'Usage: skillfm-local tunnel <start|stop|status> [--brain-url=<url>]',
201
+ }));
202
+ process.exit(1);
203
+ }
204
+ }
205
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/skill-tunnel/cli.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,EAAE;AACF,2CAA2C;AAC3C,+DAA+D;AAC/D,+CAA+C;AAE/C,OAAO,EACL,YAAY,EACZ,aAAa,EACb,UAAU,EACV,SAAS,EACT,MAAM,GACP,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAC3D,MAAM,iBAAiB,GACrB,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,sCAAsC,CAAC;AAEjF,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,UAAU,CAAC,IAAc;IAChC,MAAM,KAAK,GAAqC,EAAE,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACX,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjD,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;gBACzB,CAAC,IAAI,CAAC,CAAC;YACT,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU;IACjB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAG5C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB;IACzB,wEAAwE;IACxE,OAAO,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,OAAO,CAAC;AACtD,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAEjG,UAAU;IACV,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACjE,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;gBACb,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,iBAAiB;gBACxB,OAAO,EAAE,mBAAmB,GAAG,GAAG;aACnC,CAAC,CACH,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QACD,cAAc;QACd,IAAI,CAAC;YACH,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;IAC5E,MAAM,UAAU,GACd,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;IACjE,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;YACb,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,qBAAqB;YAC5B,OAAO,EACL,iHAAiH;SACpH,CAAC,CACH,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEnD,SAAS,EAAE,CAAC;IACZ,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAE9D,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC;QACnC,QAAQ;QACR,UAAU;QACV,UAAU;QACV,WAAW;QACX,mBAAmB,EAAE,kBAAkB,EAAE;QACzC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;YACpB,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC;gBACH,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,KAAK,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,KAAK,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;QACb,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,iBAAiB,OAAO,CAAC,GAAG,UAAU,QAAQ,WAAW,WAAW,CAAC,MAAM,EAAE;QACtF,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CACH,CAAC;IAEF,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,SAAS;IACT,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;YACb,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,aAAa;YACpB,OAAO,EAAG,GAAa,CAAC,OAAO;SAChC,CAAC,CACH,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,OAAO;YACV,gDAAgD;YAChD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1B,MAAM,cAAc,EAAE,CAAC;YACvB,MAAM;QACR,KAAK,MAAM;YACT,aAAa,EAAE,CAAC;YAChB,MAAM;QACR,KAAK,QAAQ;YACX,eAAe,EAAE,CAAC;YAClB,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CACX,IAAI,CAAC,SAAS,CAAC;gBACb,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,qEAAqE;aAC/E,CAAC,CACH,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { WebSocket } from 'ws';
2
+ import { TUNNEL_ERROR_CODES } from '@skillfm/contracts/skill-tunnel';
3
+ import type { HeartbeatTunnelResult, JsonRpcSuccessResponse, JsonRpcErrorResponse, SkillUpdateTunnelParams } from '@skillfm/contracts/skill-tunnel';
4
+ import type { LocalSkillRegistryEntry } from '../skill-runner/types.js';
5
+ export type TunnelStatus = 'connecting' | 'connected' | 'disconnected';
6
+ export interface SkillTunnelClientOptions {
7
+ /** e.g. wss://api.skillfm.ai/v1/skill-tunnel */
8
+ brainUrl: string;
9
+ agentToken: string;
10
+ /** 来自 M1 readRegistry() 的 entries 列表 */
11
+ localSkills: LocalSkillRegistryEntry[];
12
+ skillfmLocalVersion: string;
13
+ /** SKILLFM_SKILL_AUTH_SECRET — HMAC 密钥(handshake + JSON-RPC meta + 本地 skill 调用都用这把)*/
14
+ authSecret: string;
15
+ onStatusChange?: (status: TunnelStatus) => void;
16
+ /** 可选: 注入 fetch 给 LocalBridge(测试用)*/
17
+ fetch?: typeof fetch;
18
+ /** 可选: 注入 WebSocket 构造器(测试用)*/
19
+ webSocketCtor?: typeof WebSocket;
20
+ }
21
+ export declare class SkillTunnelClient {
22
+ private readonly opts;
23
+ private readonly bridge;
24
+ private readonly reconnect;
25
+ private readonly heartbeat;
26
+ private ws;
27
+ private status;
28
+ private lastConnectedAt;
29
+ private stopped;
30
+ private readonly pending;
31
+ constructor(opts: SkillTunnelClientOptions);
32
+ start(): Promise<void>;
33
+ stop(): Promise<void>;
34
+ status$(): {
35
+ connected: boolean;
36
+ lastConnectedAt: number | null;
37
+ reconnectAttempts: number;
38
+ };
39
+ /** 主动上报 skill lifecycle 事件 */
40
+ sendSkillUpdate(params: SkillUpdateTunnelParams): Promise<void>;
41
+ private connectOnce;
42
+ private onOpen;
43
+ private onError;
44
+ private onClose;
45
+ private onMessage;
46
+ private handleServerRequest;
47
+ private handleResponse;
48
+ private sendFrame;
49
+ private sendClientRequest;
50
+ private buildHeartbeatStatus;
51
+ private handleHeartbeatTimeout;
52
+ private setStatus;
53
+ }
54
+ export type { JsonRpcSuccessResponse, JsonRpcErrorResponse, HeartbeatTunnelResult };
55
+ export { TUNNEL_ERROR_CODES };
56
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/skill-tunnel/client.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,SAAS,EAAgB,MAAM,IAAI,CAAC;AAC7C,OAAO,EAGL,kBAAkB,EACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAEV,qBAAqB,EAIrB,sBAAsB,EACtB,oBAAoB,EAEpB,uBAAuB,EACxB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAMxE,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;AAEvE,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,WAAW,EAAE,uBAAuB,EAAE,CAAC;IACvC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAChD,qCAAqC;IACrC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,OAAO,SAAS,CAAC;CAClC;AAQD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAE1C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;gBAE7C,IAAI,EAAE,wBAAwB;IAkBpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB3B,OAAO,IAAI;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE;IAQ5F,8BAA8B;IACxB,eAAe,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;YAQvD,WAAW;IAyBzB,OAAO,CAAC,MAAM;IAOd,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,OAAO;IAsBf,OAAO,CAAC,SAAS;YAqBH,mBAAmB;IAKjC,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,SAAS;YASH,iBAAiB;IAsC/B,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,SAAS;CAKlB;AAGD,YAAY,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}