@openacp/cli 0.2.16 → 0.2.18
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/dist/chunk-3UGSZYSQ.js +278 -0
- package/dist/chunk-3UGSZYSQ.js.map +1 -0
- package/dist/{chunk-TKOYKVXH.js → chunk-HTXK4NLG.js} +654 -82
- package/dist/chunk-HTXK4NLG.js.map +1 -0
- package/dist/chunk-ZATQZUJT.js +193 -0
- package/dist/chunk-ZATQZUJT.js.map +1 -0
- package/dist/cli.js +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +206 -15
- package/dist/index.js +10 -8
- package/dist/{main-C4QWS4PK.js → main-4H43GCXO.js} +16 -5
- package/dist/main-4H43GCXO.js.map +1 -0
- package/dist/{setup-5RQ7YLYW.js → setup-FB4DGR6R.js} +12 -2
- package/dist/{setup-5RQ7YLYW.js.map → setup-FB4DGR6R.js.map} +1 -1
- package/dist/tunnel-service-FPRPBPQ5.js +633 -0
- package/dist/tunnel-service-FPRPBPQ5.js.map +1 -0
- package/package.json +5 -1
- package/dist/chunk-HTUZOMIT.js +0 -421
- package/dist/chunk-HTUZOMIT.js.map +0 -1
- package/dist/chunk-TKOYKVXH.js.map +0 -1
- package/dist/main-C4QWS4PK.js.map +0 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { installPlugin
|
|
1
|
+
{"version":3,"sources":["../../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { setDefaultAutoSelectFamily } from \"node:net\";\nsetDefaultAutoSelectFamily(false);\n\nimport {\n installPlugin,\n uninstallPlugin,\n listPlugins,\n} from \"./core/plugin-manager.js\";\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction printHelp(): void {\n console.log(`\nOpenACP - Self-hosted bridge for AI coding agents\n\nUsage:\n openacp Start the server\n openacp install <package> Install a plugin adapter\n openacp uninstall <package> Uninstall a plugin adapter\n openacp plugins List installed plugins\n openacp --version Show version\n openacp --help Show this help\n\nInstall:\n npm install -g @openacp/cli\n\nExamples:\n openacp\n openacp install @openacp/adapter-discord\n openacp uninstall @openacp/adapter-discord\n`);\n}\n\nasync function main() {\n if (command === \"--help\" || command === \"-h\") {\n printHelp();\n return;\n }\n\n if (command === \"--version\" || command === \"-v\") {\n // In published build: read version from own package.json via createRequire\n // In dev: fallback to 'dev'\n try {\n const { createRequire } = await import(\"node:module\");\n const require = createRequire(import.meta.url);\n const pkg = require(\"../package.json\");\n console.log(`openacp v${pkg.version}`);\n } catch {\n console.log(\"openacp v0.0.0-dev\");\n }\n return;\n }\n\n if (command === \"install\") {\n const pkg = args[1];\n if (!pkg) {\n console.error(\"Usage: openacp install <package>\");\n process.exit(1);\n }\n installPlugin(pkg);\n return;\n }\n\n if (command === \"uninstall\") {\n const pkg = args[1];\n if (!pkg) {\n console.error(\"Usage: openacp uninstall <package>\");\n process.exit(1);\n }\n uninstallPlugin(pkg);\n return;\n }\n\n if (command === \"plugins\") {\n const plugins = listPlugins();\n const entries = Object.entries(plugins);\n if (entries.length === 0) {\n console.log(\"No plugins installed.\");\n } else {\n console.log(\"Installed plugins:\");\n for (const [name, version] of entries) {\n console.log(` ${name}@${version}`);\n }\n }\n return;\n }\n\n // Default: start server\n if (command && !command.startsWith(\"-\")) {\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n\n // Import and run server start\n const { startServer } = await import(\"./main.js\");\n await startServer();\n}\n\nmain().catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;AAEA,SAAS,kCAAkC;AAC3C,2BAA2B,KAAK;AAQhC,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAkBb;AACD;AAEA,eAAe,OAAO;AACpB,MAAI,YAAY,YAAY,YAAY,MAAM;AAC5C,cAAU;AACV;AAAA,EACF;AAEA,MAAI,YAAY,eAAe,YAAY,MAAM;AAG/C,QAAI;AACF,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,QAAa;AACpD,YAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,YAAM,MAAMA,SAAQ,iBAAiB;AACrC,cAAQ,IAAI,YAAY,IAAI,OAAO,EAAE;AAAA,IACvC,QAAQ;AACN,cAAQ,IAAI,oBAAoB;AAAA,IAClC;AACA;AAAA,EACF;AAEA,MAAI,YAAY,WAAW;AACzB,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,kCAAkC;AAChD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,kBAAc,GAAG;AACjB;AAAA,EACF;AAEA,MAAI,YAAY,aAAa;AAC3B,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,oCAAoC;AAClD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,oBAAgB,GAAG;AACnB;AAAA,EACF;AAEA,MAAI,YAAY,WAAW;AACzB,UAAM,UAAU,YAAY;AAC5B,UAAM,UAAU,OAAO,QAAQ,OAAO;AACtC,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,uBAAuB;AAAA,IACrC,OAAO;AACL,cAAQ,IAAI,oBAAoB;AAChC,iBAAW,CAAC,MAAM,OAAO,KAAK,SAAS;AACrC,gBAAQ,IAAI,KAAK,IAAI,IAAI,OAAO,EAAE;AAAA,MACpC;AAAA,IACF;AACA;AAAA,EACF;AAGA,MAAI,WAAW,CAAC,QAAQ,WAAW,GAAG,GAAG;AACvC,YAAQ,MAAM,oBAAoB,OAAO,EAAE;AAC3C,cAAU;AACV,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,oBAAW;AAChD,QAAM,YAAY;AACpB;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,UAAU,GAAG;AAC3B,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["require"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ interface IncomingMessage {
|
|
|
10
10
|
text: string;
|
|
11
11
|
}
|
|
12
12
|
interface OutgoingMessage {
|
|
13
|
-
type:
|
|
13
|
+
type: "text" | "thought" | "tool_call" | "tool_update" | "plan" | "usage" | "session_end" | "error";
|
|
14
14
|
text: string;
|
|
15
15
|
metadata?: Record<string, unknown>;
|
|
16
16
|
}
|
|
@@ -27,7 +27,7 @@ interface PermissionOption {
|
|
|
27
27
|
interface NotificationMessage {
|
|
28
28
|
sessionId: string;
|
|
29
29
|
sessionName?: string;
|
|
30
|
-
type:
|
|
30
|
+
type: "completed" | "error" | "permission" | "input_required";
|
|
31
31
|
summary: string;
|
|
32
32
|
deepLink?: string;
|
|
33
33
|
}
|
|
@@ -37,13 +37,13 @@ interface AgentCommand {
|
|
|
37
37
|
input?: unknown;
|
|
38
38
|
}
|
|
39
39
|
type AgentEvent = {
|
|
40
|
-
type:
|
|
40
|
+
type: "text";
|
|
41
41
|
content: string;
|
|
42
42
|
} | {
|
|
43
|
-
type:
|
|
43
|
+
type: "thought";
|
|
44
44
|
content: string;
|
|
45
45
|
} | {
|
|
46
|
-
type:
|
|
46
|
+
type: "tool_call";
|
|
47
47
|
id: string;
|
|
48
48
|
name: string;
|
|
49
49
|
kind?: string;
|
|
@@ -51,16 +51,16 @@ type AgentEvent = {
|
|
|
51
51
|
content?: unknown;
|
|
52
52
|
locations?: unknown;
|
|
53
53
|
} | {
|
|
54
|
-
type:
|
|
54
|
+
type: "tool_update";
|
|
55
55
|
id: string;
|
|
56
56
|
status: string;
|
|
57
57
|
content?: unknown;
|
|
58
58
|
locations?: unknown;
|
|
59
59
|
} | {
|
|
60
|
-
type:
|
|
60
|
+
type: "plan";
|
|
61
61
|
entries: PlanEntry[];
|
|
62
62
|
} | {
|
|
63
|
-
type:
|
|
63
|
+
type: "usage";
|
|
64
64
|
tokensUsed?: number;
|
|
65
65
|
contextSize?: number;
|
|
66
66
|
cost?: {
|
|
@@ -68,19 +68,19 @@ type AgentEvent = {
|
|
|
68
68
|
currency: string;
|
|
69
69
|
};
|
|
70
70
|
} | {
|
|
71
|
-
type:
|
|
71
|
+
type: "commands_update";
|
|
72
72
|
commands: AgentCommand[];
|
|
73
73
|
} | {
|
|
74
|
-
type:
|
|
74
|
+
type: "session_end";
|
|
75
75
|
reason: string;
|
|
76
76
|
} | {
|
|
77
|
-
type:
|
|
77
|
+
type: "error";
|
|
78
78
|
message: string;
|
|
79
79
|
};
|
|
80
80
|
interface PlanEntry {
|
|
81
81
|
content: string;
|
|
82
|
-
status:
|
|
83
|
-
priority:
|
|
82
|
+
status: "pending" | "in_progress" | "completed";
|
|
83
|
+
priority: "high" | "medium" | "low";
|
|
84
84
|
}
|
|
85
85
|
interface AgentDefinition {
|
|
86
86
|
name: string;
|
|
@@ -89,7 +89,22 @@ interface AgentDefinition {
|
|
|
89
89
|
workingDirectory?: string;
|
|
90
90
|
env?: Record<string, string>;
|
|
91
91
|
}
|
|
92
|
-
type SessionStatus =
|
|
92
|
+
type SessionStatus = "initializing" | "active" | "cancelled" | "finished" | "error";
|
|
93
|
+
interface SessionRecord<P = Record<string, unknown>> {
|
|
94
|
+
sessionId: string;
|
|
95
|
+
agentSessionId: string;
|
|
96
|
+
agentName: string;
|
|
97
|
+
workingDir: string;
|
|
98
|
+
channelId: string;
|
|
99
|
+
status: SessionStatus;
|
|
100
|
+
createdAt: string;
|
|
101
|
+
lastActiveAt: string;
|
|
102
|
+
name?: string;
|
|
103
|
+
platform: P;
|
|
104
|
+
}
|
|
105
|
+
interface TelegramPlatformData {
|
|
106
|
+
topicId: number;
|
|
107
|
+
}
|
|
93
108
|
|
|
94
109
|
declare const PLUGINS_DIR: string;
|
|
95
110
|
declare const LoggingSchema: z.ZodDefault<z.ZodObject<{
|
|
@@ -112,6 +127,44 @@ declare const LoggingSchema: z.ZodDefault<z.ZodObject<{
|
|
|
112
127
|
sessionLogRetentionDays?: number | undefined;
|
|
113
128
|
}>>;
|
|
114
129
|
type LoggingConfig = z.infer<typeof LoggingSchema>;
|
|
130
|
+
declare const TunnelSchema: z.ZodDefault<z.ZodObject<{
|
|
131
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
132
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
133
|
+
provider: z.ZodDefault<z.ZodEnum<["cloudflare", "ngrok", "bore"]>>;
|
|
134
|
+
options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
135
|
+
storeTtlMinutes: z.ZodDefault<z.ZodNumber>;
|
|
136
|
+
auth: z.ZodDefault<z.ZodObject<{
|
|
137
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
138
|
+
token: z.ZodOptional<z.ZodString>;
|
|
139
|
+
}, "strip", z.ZodTypeAny, {
|
|
140
|
+
enabled: boolean;
|
|
141
|
+
token?: string | undefined;
|
|
142
|
+
}, {
|
|
143
|
+
enabled?: boolean | undefined;
|
|
144
|
+
token?: string | undefined;
|
|
145
|
+
}>>;
|
|
146
|
+
}, "strip", z.ZodTypeAny, {
|
|
147
|
+
options: Record<string, unknown>;
|
|
148
|
+
enabled: boolean;
|
|
149
|
+
port: number;
|
|
150
|
+
provider: "cloudflare" | "ngrok" | "bore";
|
|
151
|
+
storeTtlMinutes: number;
|
|
152
|
+
auth: {
|
|
153
|
+
enabled: boolean;
|
|
154
|
+
token?: string | undefined;
|
|
155
|
+
};
|
|
156
|
+
}, {
|
|
157
|
+
options?: Record<string, unknown> | undefined;
|
|
158
|
+
enabled?: boolean | undefined;
|
|
159
|
+
port?: number | undefined;
|
|
160
|
+
provider?: "cloudflare" | "ngrok" | "bore" | undefined;
|
|
161
|
+
storeTtlMinutes?: number | undefined;
|
|
162
|
+
auth?: {
|
|
163
|
+
enabled?: boolean | undefined;
|
|
164
|
+
token?: string | undefined;
|
|
165
|
+
} | undefined;
|
|
166
|
+
}>>;
|
|
167
|
+
type TunnelConfig = z.infer<typeof TunnelSchema>;
|
|
115
168
|
declare const ConfigSchema: z.ZodObject<{
|
|
116
169
|
channels: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
117
170
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -179,6 +232,50 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
179
232
|
maxFiles?: number | undefined;
|
|
180
233
|
sessionLogRetentionDays?: number | undefined;
|
|
181
234
|
}>>;
|
|
235
|
+
sessionStore: z.ZodDefault<z.ZodObject<{
|
|
236
|
+
ttlDays: z.ZodDefault<z.ZodNumber>;
|
|
237
|
+
}, "strip", z.ZodTypeAny, {
|
|
238
|
+
ttlDays: number;
|
|
239
|
+
}, {
|
|
240
|
+
ttlDays?: number | undefined;
|
|
241
|
+
}>>;
|
|
242
|
+
tunnel: z.ZodDefault<z.ZodObject<{
|
|
243
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
244
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
245
|
+
provider: z.ZodDefault<z.ZodEnum<["cloudflare", "ngrok", "bore"]>>;
|
|
246
|
+
options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
247
|
+
storeTtlMinutes: z.ZodDefault<z.ZodNumber>;
|
|
248
|
+
auth: z.ZodDefault<z.ZodObject<{
|
|
249
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
250
|
+
token: z.ZodOptional<z.ZodString>;
|
|
251
|
+
}, "strip", z.ZodTypeAny, {
|
|
252
|
+
enabled: boolean;
|
|
253
|
+
token?: string | undefined;
|
|
254
|
+
}, {
|
|
255
|
+
enabled?: boolean | undefined;
|
|
256
|
+
token?: string | undefined;
|
|
257
|
+
}>>;
|
|
258
|
+
}, "strip", z.ZodTypeAny, {
|
|
259
|
+
options: Record<string, unknown>;
|
|
260
|
+
enabled: boolean;
|
|
261
|
+
port: number;
|
|
262
|
+
provider: "cloudflare" | "ngrok" | "bore";
|
|
263
|
+
storeTtlMinutes: number;
|
|
264
|
+
auth: {
|
|
265
|
+
enabled: boolean;
|
|
266
|
+
token?: string | undefined;
|
|
267
|
+
};
|
|
268
|
+
}, {
|
|
269
|
+
options?: Record<string, unknown> | undefined;
|
|
270
|
+
enabled?: boolean | undefined;
|
|
271
|
+
port?: number | undefined;
|
|
272
|
+
provider?: "cloudflare" | "ngrok" | "bore" | undefined;
|
|
273
|
+
storeTtlMinutes?: number | undefined;
|
|
274
|
+
auth?: {
|
|
275
|
+
enabled?: boolean | undefined;
|
|
276
|
+
token?: string | undefined;
|
|
277
|
+
} | undefined;
|
|
278
|
+
}>>;
|
|
182
279
|
}, "strip", z.ZodTypeAny, {
|
|
183
280
|
channels: Record<string, z.objectOutputType<{
|
|
184
281
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -206,6 +303,20 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
206
303
|
maxFiles: number;
|
|
207
304
|
sessionLogRetentionDays: number;
|
|
208
305
|
};
|
|
306
|
+
sessionStore: {
|
|
307
|
+
ttlDays: number;
|
|
308
|
+
};
|
|
309
|
+
tunnel: {
|
|
310
|
+
options: Record<string, unknown>;
|
|
311
|
+
enabled: boolean;
|
|
312
|
+
port: number;
|
|
313
|
+
provider: "cloudflare" | "ngrok" | "bore";
|
|
314
|
+
storeTtlMinutes: number;
|
|
315
|
+
auth: {
|
|
316
|
+
enabled: boolean;
|
|
317
|
+
token?: string | undefined;
|
|
318
|
+
};
|
|
319
|
+
};
|
|
209
320
|
}, {
|
|
210
321
|
channels: Record<string, z.objectInputType<{
|
|
211
322
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -233,6 +344,20 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
233
344
|
maxFiles?: number | undefined;
|
|
234
345
|
sessionLogRetentionDays?: number | undefined;
|
|
235
346
|
} | undefined;
|
|
347
|
+
sessionStore?: {
|
|
348
|
+
ttlDays?: number | undefined;
|
|
349
|
+
} | undefined;
|
|
350
|
+
tunnel?: {
|
|
351
|
+
options?: Record<string, unknown> | undefined;
|
|
352
|
+
enabled?: boolean | undefined;
|
|
353
|
+
port?: number | undefined;
|
|
354
|
+
provider?: "cloudflare" | "ngrok" | "bore" | undefined;
|
|
355
|
+
storeTtlMinutes?: number | undefined;
|
|
356
|
+
auth?: {
|
|
357
|
+
enabled?: boolean | undefined;
|
|
358
|
+
token?: string | undefined;
|
|
359
|
+
} | undefined;
|
|
360
|
+
} | undefined;
|
|
236
361
|
}>;
|
|
237
362
|
type Config = z.infer<typeof ConfigSchema>;
|
|
238
363
|
declare function expandHome(p: string): string;
|
|
@@ -316,7 +441,10 @@ declare class AgentInstance {
|
|
|
316
441
|
onSessionUpdate: (event: AgentEvent) => void;
|
|
317
442
|
onPermissionRequest: (request: PermissionRequest) => Promise<string>;
|
|
318
443
|
private constructor();
|
|
444
|
+
private static spawnSubprocess;
|
|
445
|
+
private setupCrashDetection;
|
|
319
446
|
static spawn(agentDef: AgentDefinition, workingDirectory: string): Promise<AgentInstance>;
|
|
447
|
+
static resume(agentDef: AgentDefinition, workingDirectory: string, agentSessionId: string): Promise<AgentInstance>;
|
|
320
448
|
private createClient;
|
|
321
449
|
prompt(text: string): Promise<PromptResponse>;
|
|
322
450
|
cancel(): Promise<void>;
|
|
@@ -329,6 +457,7 @@ declare class AgentManager {
|
|
|
329
457
|
getAvailableAgents(): AgentDefinition[];
|
|
330
458
|
getAgent(name: string): AgentDefinition | undefined;
|
|
331
459
|
spawn(agentName: string, workingDirectory: string): Promise<AgentInstance>;
|
|
460
|
+
resume(agentName: string, workingDirectory: string, agentSessionId: string): Promise<AgentInstance>;
|
|
332
461
|
}
|
|
333
462
|
|
|
334
463
|
declare class Session {
|
|
@@ -338,6 +467,7 @@ declare class Session {
|
|
|
338
467
|
agentName: string;
|
|
339
468
|
workingDirectory: string;
|
|
340
469
|
agentInstance: AgentInstance;
|
|
470
|
+
agentSessionId: string;
|
|
341
471
|
status: SessionStatus;
|
|
342
472
|
name?: string;
|
|
343
473
|
promptQueue: string[];
|
|
@@ -365,22 +495,81 @@ declare class Session {
|
|
|
365
495
|
destroy(): Promise<void>;
|
|
366
496
|
}
|
|
367
497
|
|
|
498
|
+
interface SessionStore {
|
|
499
|
+
save(record: SessionRecord): Promise<void>;
|
|
500
|
+
get(sessionId: string): SessionRecord | undefined;
|
|
501
|
+
findByPlatform(channelId: string, predicate: (platform: Record<string, unknown>) => boolean): SessionRecord | undefined;
|
|
502
|
+
list(channelId?: string): SessionRecord[];
|
|
503
|
+
remove(sessionId: string): Promise<void>;
|
|
504
|
+
}
|
|
505
|
+
|
|
368
506
|
declare class SessionManager {
|
|
369
507
|
private sessions;
|
|
508
|
+
private store;
|
|
509
|
+
constructor(store?: SessionStore | null);
|
|
370
510
|
createSession(channelId: string, agentName: string, workingDirectory: string, agentManager: AgentManager): Promise<Session>;
|
|
371
511
|
getSession(sessionId: string): Session | undefined;
|
|
372
512
|
getSessionByThread(channelId: string, threadId: string): Session | undefined;
|
|
513
|
+
registerSession(session: Session): void;
|
|
514
|
+
updateSessionPlatform(sessionId: string, platform: Record<string, unknown>): Promise<void>;
|
|
515
|
+
updateSessionActivity(sessionId: string): Promise<void>;
|
|
516
|
+
updateSessionStatus(sessionId: string, status: SessionStatus): Promise<void>;
|
|
373
517
|
cancelSession(sessionId: string): Promise<void>;
|
|
374
518
|
listSessions(channelId?: string): Session[];
|
|
375
519
|
destroyAll(): Promise<void>;
|
|
376
520
|
}
|
|
377
521
|
|
|
522
|
+
interface ViewerEntry {
|
|
523
|
+
id: string;
|
|
524
|
+
type: 'file' | 'diff';
|
|
525
|
+
filePath?: string;
|
|
526
|
+
content: string;
|
|
527
|
+
oldContent?: string;
|
|
528
|
+
language?: string;
|
|
529
|
+
sessionId: string;
|
|
530
|
+
workingDirectory: string;
|
|
531
|
+
createdAt: number;
|
|
532
|
+
expiresAt: number;
|
|
533
|
+
}
|
|
534
|
+
declare class ViewerStore {
|
|
535
|
+
private entries;
|
|
536
|
+
private cleanupTimer;
|
|
537
|
+
private ttlMs;
|
|
538
|
+
constructor(ttlMinutes?: number);
|
|
539
|
+
storeFile(sessionId: string, filePath: string, content: string, workingDirectory: string): string | null;
|
|
540
|
+
storeDiff(sessionId: string, filePath: string, oldContent: string, newContent: string, workingDirectory: string): string | null;
|
|
541
|
+
get(id: string): ViewerEntry | undefined;
|
|
542
|
+
private cleanup;
|
|
543
|
+
private isPathAllowed;
|
|
544
|
+
private detectLanguage;
|
|
545
|
+
destroy(): void;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
declare class TunnelService {
|
|
549
|
+
private provider;
|
|
550
|
+
private store;
|
|
551
|
+
private server;
|
|
552
|
+
private publicUrl;
|
|
553
|
+
private config;
|
|
554
|
+
constructor(config: TunnelConfig);
|
|
555
|
+
start(): Promise<string>;
|
|
556
|
+
stop(): Promise<void>;
|
|
557
|
+
getPublicUrl(): string;
|
|
558
|
+
getStore(): ViewerStore;
|
|
559
|
+
fileUrl(entryId: string): string;
|
|
560
|
+
diffUrl(entryId: string): string;
|
|
561
|
+
private createProvider;
|
|
562
|
+
}
|
|
563
|
+
|
|
378
564
|
declare class OpenACPCore {
|
|
379
565
|
configManager: ConfigManager;
|
|
380
566
|
agentManager: AgentManager;
|
|
381
567
|
sessionManager: SessionManager;
|
|
382
568
|
notificationManager: NotificationManager;
|
|
383
569
|
adapters: Map<string, ChannelAdapter>;
|
|
570
|
+
tunnelService?: TunnelService;
|
|
571
|
+
private sessionStore;
|
|
572
|
+
private resumeLocks;
|
|
384
573
|
constructor(configManager: ConfigManager);
|
|
385
574
|
registerAdapter(name: string, adapter: ChannelAdapter): void;
|
|
386
575
|
start(): Promise<void>;
|
|
@@ -388,7 +577,9 @@ declare class OpenACPCore {
|
|
|
388
577
|
handleMessage(message: IncomingMessage): Promise<void>;
|
|
389
578
|
handleNewSession(channelId: string, agentName?: string, workspacePath?: string): Promise<Session>;
|
|
390
579
|
handleNewChat(channelId: string, currentThreadId: string): Promise<Session | null>;
|
|
580
|
+
private lazyResume;
|
|
391
581
|
private toOutgoingMessage;
|
|
582
|
+
private enrichWithViewerLinks;
|
|
392
583
|
wireSessionEvents(session: Session, adapter: ChannelAdapter): void;
|
|
393
584
|
}
|
|
394
585
|
|
|
@@ -434,4 +625,4 @@ declare class TelegramAdapter extends ChannelAdapter {
|
|
|
434
625
|
private finalizeDraft;
|
|
435
626
|
}
|
|
436
627
|
|
|
437
|
-
export { type AdapterFactory, type AgentCommand, type AgentDefinition, type AgentEvent, AgentInstance, AgentManager, ChannelAdapter, type ChannelConfig, type Config, ConfigManager, type IncomingMessage, type Logger, type LoggingConfig, NotificationManager, type NotificationMessage, OpenACPCore, type OutgoingMessage, PLUGINS_DIR, type PermissionOption, type PermissionRequest, type PlanEntry, Session, SessionManager, type SessionStatus, StderrCapture, TelegramAdapter, cleanupOldSessionLogs, createChildLogger, createSessionLogger, expandHome, initLogger, installPlugin, listPlugins, loadAdapterFactory, log, nodeToWebReadable, nodeToWebWritable, shutdownLogger, uninstallPlugin };
|
|
628
|
+
export { type AdapterFactory, type AgentCommand, type AgentDefinition, type AgentEvent, AgentInstance, AgentManager, ChannelAdapter, type ChannelConfig, type Config, ConfigManager, type IncomingMessage, type Logger, type LoggingConfig, NotificationManager, type NotificationMessage, OpenACPCore, type OutgoingMessage, PLUGINS_DIR, type PermissionOption, type PermissionRequest, type PlanEntry, Session, SessionManager, type SessionRecord, type SessionStatus, StderrCapture, TelegramAdapter, type TelegramPlatformData, cleanupOldSessionLogs, createChildLogger, createSessionLogger, expandHome, initLogger, installPlugin, listPlugins, loadAdapterFactory, log, nodeToWebReadable, nodeToWebWritable, shutdownLogger, uninstallPlugin };
|
package/dist/index.js
CHANGED
|
@@ -10,22 +10,24 @@ import {
|
|
|
10
10
|
TelegramAdapter,
|
|
11
11
|
nodeToWebReadable,
|
|
12
12
|
nodeToWebWritable
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-HTXK4NLG.js";
|
|
14
14
|
import {
|
|
15
15
|
ConfigManager,
|
|
16
16
|
PLUGINS_DIR,
|
|
17
|
-
cleanupOldSessionLogs,
|
|
18
|
-
createChildLogger,
|
|
19
|
-
createSessionLogger,
|
|
20
17
|
expandHome,
|
|
21
|
-
initLogger,
|
|
22
18
|
installPlugin,
|
|
23
19
|
listPlugins,
|
|
24
20
|
loadAdapterFactory,
|
|
25
|
-
log,
|
|
26
|
-
shutdownLogger,
|
|
27
21
|
uninstallPlugin
|
|
28
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-3UGSZYSQ.js";
|
|
23
|
+
import {
|
|
24
|
+
cleanupOldSessionLogs,
|
|
25
|
+
createChildLogger,
|
|
26
|
+
createSessionLogger,
|
|
27
|
+
initLogger,
|
|
28
|
+
log,
|
|
29
|
+
shutdownLogger
|
|
30
|
+
} from "./chunk-ZATQZUJT.js";
|
|
29
31
|
export {
|
|
30
32
|
AgentInstance,
|
|
31
33
|
AgentManager,
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
import {
|
|
3
3
|
OpenACPCore,
|
|
4
4
|
TelegramAdapter
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HTXK4NLG.js";
|
|
6
6
|
import {
|
|
7
7
|
ConfigManager,
|
|
8
|
+
loadAdapterFactory
|
|
9
|
+
} from "./chunk-3UGSZYSQ.js";
|
|
10
|
+
import {
|
|
8
11
|
cleanupOldSessionLogs,
|
|
9
12
|
initLogger,
|
|
10
|
-
loadAdapterFactory,
|
|
11
13
|
log,
|
|
12
14
|
shutdownLogger
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ZATQZUJT.js";
|
|
14
16
|
|
|
15
17
|
// src/main.ts
|
|
16
18
|
var shuttingDown = false;
|
|
@@ -18,7 +20,7 @@ async function startServer() {
|
|
|
18
20
|
const configManager = new ConfigManager();
|
|
19
21
|
const configExists = await configManager.exists();
|
|
20
22
|
if (!configExists) {
|
|
21
|
-
const { runSetup } = await import("./setup-
|
|
23
|
+
const { runSetup } = await import("./setup-FB4DGR6R.js");
|
|
22
24
|
const shouldStart = await runSetup(configManager);
|
|
23
25
|
if (!shouldStart) process.exit(0);
|
|
24
26
|
}
|
|
@@ -30,6 +32,14 @@ async function startServer() {
|
|
|
30
32
|
(err) => log.warn({ err }, "Session log cleanup failed")
|
|
31
33
|
);
|
|
32
34
|
const core = new OpenACPCore(configManager);
|
|
35
|
+
let tunnelService;
|
|
36
|
+
if (config.tunnel.enabled) {
|
|
37
|
+
const { TunnelService } = await import("./tunnel-service-FPRPBPQ5.js");
|
|
38
|
+
tunnelService = new TunnelService(config.tunnel);
|
|
39
|
+
const publicUrl = await tunnelService.start();
|
|
40
|
+
core.tunnelService = tunnelService;
|
|
41
|
+
log.info({ publicUrl }, "Tunnel started");
|
|
42
|
+
}
|
|
33
43
|
for (const [channelName, channelConfig] of Object.entries(config.channels)) {
|
|
34
44
|
if (!channelConfig.enabled) continue;
|
|
35
45
|
if (channelName === "telegram") {
|
|
@@ -64,6 +74,7 @@ async function startServer() {
|
|
|
64
74
|
log.info({ signal }, "Signal received, shutting down");
|
|
65
75
|
try {
|
|
66
76
|
await core.stop();
|
|
77
|
+
if (tunnelService) await tunnelService.stop();
|
|
67
78
|
} catch (err) {
|
|
68
79
|
log.error({ err }, "Error during shutdown");
|
|
69
80
|
}
|
|
@@ -89,4 +100,4 @@ if (isDirectExecution) {
|
|
|
89
100
|
export {
|
|
90
101
|
startServer
|
|
91
102
|
};
|
|
92
|
-
//# sourceMappingURL=main-
|
|
103
|
+
//# sourceMappingURL=main-4H43GCXO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ConfigManager } from './core/config.js'\nimport { OpenACPCore } from './core/core.js'\nimport { loadAdapterFactory } from './core/plugin-manager.js'\nimport { initLogger, shutdownLogger, cleanupOldSessionLogs, log } from './core/log.js'\nimport { TelegramAdapter } from './adapters/telegram/index.js'\n\nlet shuttingDown = false\n\nexport async function startServer() {\n // 1. Check config exists, run setup if not\n const configManager = new ConfigManager()\n const configExists = await configManager.exists()\n\n if (!configExists) {\n const { runSetup } = await import('./core/setup.js')\n const shouldStart = await runSetup(configManager)\n if (!shouldStart) process.exit(0)\n }\n\n // 2. Load config (validates with Zod)\n await configManager.load()\n const config = configManager.get()\n initLogger(config.logging)\n log.info({ configPath: configManager.getConfigPath() }, 'Config loaded')\n\n // Async cleanup of old session logs (non-blocking)\n cleanupOldSessionLogs(config.logging.sessionLogRetentionDays).catch(err =>\n log.warn({ err }, 'Session log cleanup failed')\n )\n\n // 3. Create core\n const core = new OpenACPCore(configManager)\n\n // 3.5 Start tunnel if configured\n let tunnelService: import('./tunnel/tunnel-service.js').TunnelService | undefined\n if (config.tunnel.enabled) {\n const { TunnelService } = await import('./tunnel/tunnel-service.js')\n tunnelService = new TunnelService(config.tunnel)\n const publicUrl = await tunnelService.start()\n core.tunnelService = tunnelService\n log.info({ publicUrl }, 'Tunnel started')\n }\n\n // 4. Register adapters from config\n for (const [channelName, channelConfig] of Object.entries(config.channels)) {\n if (!channelConfig.enabled) continue\n\n if (channelName === 'telegram') {\n core.registerAdapter('telegram', new TelegramAdapter(core, channelConfig as any))\n log.info({ adapter: 'telegram' }, 'Adapter registered')\n } else if (channelConfig.adapter) {\n // Plugin adapter\n const factory = await loadAdapterFactory(channelConfig.adapter)\n if (factory) {\n const adapter = factory.createAdapter(core, channelConfig)\n core.registerAdapter(channelName, adapter)\n log.info({ adapter: channelName, plugin: channelConfig.adapter }, 'Adapter registered')\n } else {\n const name = channelName\n const err = channelConfig.adapter\n log.error({ adapter: name, err }, 'Failed to load adapter')\n }\n } else {\n log.error({ adapter: channelName }, 'Channel has no built-in adapter; set \"adapter\" field to a plugin package')\n }\n }\n\n if (core.adapters.size === 0) {\n log.error('No channels enabled. Enable at least one channel in config.')\n process.exit(1)\n }\n\n // 5. Start\n await core.start()\n\n // 6. Log ready\n const agents = Object.keys(config.agents)\n log.info({ agents }, 'OpenACP started')\n log.info('Press Ctrl+C to stop')\n\n // 7. Graceful shutdown\n const shutdown = async (signal: string) => {\n if (shuttingDown) return\n shuttingDown = true\n log.info({ signal }, 'Signal received, shutting down')\n\n try {\n await core.stop()\n if (tunnelService) await tunnelService.stop()\n } catch (err) {\n log.error({ err }, 'Error during shutdown')\n }\n\n await shutdownLogger()\n process.exit(0)\n }\n\n process.on('SIGINT', () => shutdown('SIGINT'))\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n\n process.on('uncaughtException', (err) => {\n log.error({ err }, 'Uncaught exception')\n })\n\n process.on('unhandledRejection', (err) => {\n log.error({ err }, 'Unhandled rejection')\n })\n}\n\n// Direct execution for dev (node dist/main.js)\nconst isDirectExecution = process.argv[1]?.endsWith('main.js')\nif (isDirectExecution) {\n startServer().catch((err) => {\n log.error({ err }, 'Fatal error')\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
|
|
@@ -174,7 +174,8 @@ async function detectChatId(token) {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
var KNOWN_AGENTS = [
|
|
177
|
-
{ name: "claude", commands: ["claude-agent-acp"] }
|
|
177
|
+
{ name: "claude", commands: ["claude-agent-acp", "claude-code", "claude"] },
|
|
178
|
+
{ name: "codex", commands: ["codex"] }
|
|
178
179
|
];
|
|
179
180
|
function commandExists(cmd) {
|
|
180
181
|
try {
|
|
@@ -305,6 +306,15 @@ async function runSetup(configManager) {
|
|
|
305
306
|
maxFileSize: "10m",
|
|
306
307
|
maxFiles: 7,
|
|
307
308
|
sessionLogRetentionDays: 30
|
|
309
|
+
},
|
|
310
|
+
sessionStore: { ttlDays: 30 },
|
|
311
|
+
tunnel: {
|
|
312
|
+
enabled: false,
|
|
313
|
+
port: 3100,
|
|
314
|
+
provider: "cloudflare",
|
|
315
|
+
options: {},
|
|
316
|
+
storeTtlMinutes: 60,
|
|
317
|
+
auth: { enabled: false }
|
|
308
318
|
}
|
|
309
319
|
};
|
|
310
320
|
try {
|
|
@@ -340,4 +350,4 @@ export {
|
|
|
340
350
|
validateBotToken,
|
|
341
351
|
validateChatId
|
|
342
352
|
};
|
|
343
|
-
//# sourceMappingURL=setup-
|
|
353
|
+
//# sourceMappingURL=setup-FB4DGR6R.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/setup.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { input, select } from \"@inquirer/prompts\";\nimport type { Config, ConfigManager } from \"./config.js\";\n\n// --- ANSI colors ---\n\nconst c = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n red: \"\\x1b[31m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n};\n\nconst ok = (msg: string) =>\n `${c.green}${c.bold}✓${c.reset} ${c.green}${msg}${c.reset}`;\nconst warn = (msg: string) => `${c.yellow}⚠ ${msg}${c.reset}`;\nconst fail = (msg: string) => `${c.red}✗ ${msg}${c.reset}`;\nconst step = (n: number, title: string) =>\n `\\n${c.cyan}${c.bold}[${n}/3]${c.reset} ${c.bold}${title}${c.reset}\\n`;\nconst dim = (msg: string) => `${c.dim}${msg}${c.reset}`;\n\n// --- Telegram validation ---\n\nexport async function validateBotToken(\n token: string,\n): Promise<\n | { ok: true; botName: string; botUsername: string }\n | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);\n const data = (await res.json()) as {\n ok: boolean;\n result?: { first_name: string; username: string };\n description?: string;\n };\n if (data.ok && data.result) {\n return {\n ok: true,\n botName: data.result.first_name,\n botUsername: data.result.username,\n };\n }\n return { ok: false, error: data.description || \"Invalid token\" };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\nexport async function validateChatId(\n token: string,\n chatId: number,\n): Promise<\n { ok: true; title: string; isForum: boolean } | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getChat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n result?: { title: string; type: string; is_forum?: boolean };\n description?: string;\n };\n if (!data.ok || !data.result) {\n return { ok: false, error: data.description || \"Invalid chat ID\" };\n }\n if (data.result.type !== \"supergroup\") {\n return {\n ok: false,\n error: `Chat is \"${data.result.type}\", must be a supergroup`,\n };\n }\n return {\n ok: true,\n title: data.result.title,\n isForum: data.result.is_forum === true,\n };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\n// --- Chat ID auto-detection ---\n\nfunction promptManualChatId(): Promise<number> {\n return input({\n message: \"Supergroup chat ID (e.g. -1001234567890):\",\n validate: (val) => {\n const n = Number(val.trim());\n if (isNaN(n) || !Number.isInteger(n)) return \"Chat ID must be an integer\";\n return true;\n },\n }).then((val) => Number(val.trim()));\n}\n\nasync function detectChatId(token: string): Promise<number> {\n // Clear old updates\n let lastUpdateId = 0;\n try {\n const clearRes = await fetch(\n `https://api.telegram.org/bot${token}/getUpdates?offset=-1`,\n );\n const clearData = (await clearRes.json()) as {\n ok: boolean;\n result?: Array<{ update_id: number }>;\n };\n if (clearData.ok && clearData.result?.length) {\n lastUpdateId = clearData.result[clearData.result.length - 1].update_id;\n }\n } catch {\n // ignore\n }\n\n console.log(\"\");\n console.log(` ${c.bold}If you don't have a supergroup yet:${c.reset}`);\n console.log(dim(\" 1. Open Telegram → New Group → add your bot\"));\n console.log(dim(\" 2. Group Settings → convert to Supergroup\"));\n console.log(dim(\" 3. Enable Topics in group settings\"));\n console.log(\"\");\n console.log(` ${c.bold}Then send \"hi\" in the group.${c.reset}`);\n console.log(\n dim(\n ` Listening... press ${c.reset}${c.yellow}m${c.reset}${c.dim} to enter ID manually`,\n ),\n );\n console.log(\"\");\n\n const MAX_ATTEMPTS = 120;\n const POLL_INTERVAL = 1000;\n\n // Listen for 'm' keypress to switch to manual\n let cancelled = false;\n const onKeypress = (data: Buffer) => {\n const key = data.toString();\n if (key === \"m\" || key === \"M\") {\n cancelled = true;\n }\n };\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.on(\"data\", onKeypress);\n }\n\n const cleanup = () => {\n if (process.stdin.isTTY) {\n process.stdin.removeListener(\"data\", onKeypress);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n }\n };\n\n try {\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n if (cancelled) {\n cleanup();\n return promptManualChatId();\n }\n\n try {\n const offset = lastUpdateId ? lastUpdateId + 1 : 0;\n const res = await fetch(\n `https://api.telegram.org/bot${token}/getUpdates?offset=${offset}&timeout=1`,\n );\n const data = (await res.json()) as {\n ok: boolean;\n result?: Array<{\n update_id: number;\n message?: {\n chat: { id: number; title?: string; type: string };\n };\n my_chat_member?: {\n chat: { id: number; title?: string; type: string };\n };\n }>;\n };\n\n if (!data.ok || !data.result?.length) {\n await new Promise((r) => setTimeout(r, POLL_INTERVAL));\n continue;\n }\n\n const groups = new Map<number, string>();\n for (const update of data.result) {\n lastUpdateId = update.update_id;\n const chat = update.message?.chat ?? update.my_chat_member?.chat;\n if (chat && (chat.type === \"supergroup\" || chat.type === \"group\")) {\n groups.set(chat.id, chat.title ?? String(chat.id));\n }\n }\n\n if (groups.size === 1) {\n const [id, title] = [...groups.entries()][0];\n console.log(\n ok(`Group detected: ${c.bold}${title}${c.reset}${c.green} (${id})`),\n );\n cleanup();\n return id;\n }\n\n if (groups.size > 1) {\n cleanup();\n const choices = [...groups.entries()].map(([id, title]) => ({\n name: `${title} (${id})`,\n value: id,\n }));\n return select({\n message: \"Multiple groups found. Pick one:\",\n choices,\n });\n }\n } catch {\n // Network error, retry\n }\n await new Promise((r) => setTimeout(r, POLL_INTERVAL));\n }\n\n console.log(warn(\"Timed out waiting for messages.\"));\n cleanup();\n return promptManualChatId();\n } catch (err) {\n cleanup();\n throw err;\n }\n}\n\n// --- Agent detection ---\n\nconst KNOWN_AGENTS: Array<{ name: string; commands: string[] }> = [\n { name: \"claude\", commands: [\"claude-agent-acp\"] },\n];\n\nfunction commandExists(cmd: string): boolean {\n try {\n execFileSync(\"which\", [cmd], { stdio: \"pipe\" });\n return true;\n } catch {\n // not in PATH\n }\n let dir = process.cwd();\n while (true) {\n const binPath = path.join(dir, \"node_modules\", \".bin\", cmd);\n if (fs.existsSync(binPath)) return true;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nexport async function detectAgents(): Promise<\n Array<{ name: string; command: string }>\n> {\n const found: Array<{ name: string; command: string }> = [];\n for (const agent of KNOWN_AGENTS) {\n const available: string[] = [];\n for (const cmd of agent.commands) {\n if (commandExists(cmd)) {\n available.push(cmd);\n }\n }\n if (available.length > 0) {\n found.push({ name: agent.name, command: available[0] });\n }\n }\n return found;\n}\n\nexport async function validateAgentCommand(command: string): Promise<boolean> {\n try {\n execFileSync(\"which\", [command], { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\n// --- Setup steps ---\n\nexport async function setupTelegram(): Promise<Config[\"channels\"][string]> {\n console.log(step(1, \"Telegram Bot\"));\n\n let botToken = \"\";\n\n while (true) {\n botToken = await input({\n message: \"Bot token (from @BotFather):\",\n validate: (val) => val.trim().length > 0 || \"Token cannot be empty\",\n });\n botToken = botToken.trim();\n\n const result = await validateBotToken(botToken);\n if (result.ok) {\n console.log(ok(`Connected to @${result.botUsername}`));\n break;\n }\n console.log(fail(result.error));\n const action = await select({\n message: \"What to do?\",\n choices: [\n { name: \"Re-enter token\", value: \"retry\" },\n { name: \"Use as-is (skip validation)\", value: \"skip\" },\n ],\n });\n if (action === \"skip\") break;\n }\n\n console.log(step(2, \"Group Chat\"));\n\n const chatId = await detectChatId(botToken);\n\n return {\n enabled: true,\n botToken,\n chatId,\n notificationTopicId: null,\n assistantTopicId: null,\n };\n}\n\nexport async function setupAgents(): Promise<{\n agents: Config[\"agents\"];\n defaultAgent: string;\n}> {\n const detected = await detectAgents();\n const agents: Config[\"agents\"] = {};\n\n if (detected.length > 0) {\n for (const agent of detected) {\n agents[agent.name] = { command: agent.command, args: [], env: {} };\n }\n } else {\n agents[\"claude\"] = { command: \"claude-agent-acp\", args: [], env: {} };\n }\n\n const defaultAgent = Object.keys(agents)[0];\n const agentCmd = agents[defaultAgent].command;\n console.log(\n ok(`Agent: ${c.bold}${defaultAgent}${c.reset}${c.green} (${agentCmd})`),\n );\n\n return { agents, defaultAgent };\n}\n\nexport async function setupWorkspace(): Promise<{ baseDir: string }> {\n console.log(step(3, \"Workspace\"));\n\n const baseDir = await input({\n message: \"Base directory for workspaces:\",\n default: \"~/openacp-workspace\",\n validate: (val) => val.trim().length > 0 || \"Path cannot be empty\",\n });\n\n return { baseDir: baseDir.trim().replace(/^['\"]|['\"]$/g, \"\") };\n}\n\n// --- Orchestrator ---\n\nfunction printWelcomeBanner(): void {\n console.log(`\n${c.cyan}${c.bold} ╔══════════════════════════════╗\n ║ Welcome to OpenACP ║\n ╚══════════════════════════════╝${c.reset}\n`);\n}\n\nexport async function runSetup(configManager: ConfigManager): Promise<boolean> {\n printWelcomeBanner();\n\n try {\n const telegram = await setupTelegram();\n const { agents, defaultAgent } = await setupAgents();\n const workspace = await setupWorkspace();\n const security = {\n allowedUserIds: [] as string[],\n maxConcurrentSessions: 5,\n sessionTimeoutMinutes: 60,\n };\n\n const config: Config = {\n channels: { telegram },\n agents,\n defaultAgent,\n workspace,\n security,\n logging: {\n level: \"info\",\n logDir: \"~/.openacp/logs\",\n maxFileSize: \"10m\",\n maxFiles: 7,\n sessionLogRetentionDays: 30,\n },\n };\n\n try {\n await configManager.writeNew(config);\n } catch (writeErr) {\n console.log(\n fail(`Could not save config: ${(writeErr as Error).message}`),\n );\n return false;\n }\n\n console.log(\"\");\n console.log(\n ok(`Config saved to ${c.bold}${configManager.getConfigPath()}`),\n );\n console.log(ok(\"Starting OpenACP...\"));\n console.log(\"\");\n\n return true;\n } catch (err) {\n if ((err as Error).name === \"ExitPromptError\") {\n console.log(dim(\"\\nSetup cancelled.\"));\n return false;\n }\n throw err;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/setup.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { input, select } from \"@inquirer/prompts\";\nimport type { Config, ConfigManager } from \"./config.js\";\n\n// --- ANSI colors ---\n\nconst c = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n red: \"\\x1b[31m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n};\n\nconst ok = (msg: string) =>\n `${c.green}${c.bold}✓${c.reset} ${c.green}${msg}${c.reset}`;\nconst warn = (msg: string) => `${c.yellow}⚠ ${msg}${c.reset}`;\nconst fail = (msg: string) => `${c.red}✗ ${msg}${c.reset}`;\nconst step = (n: number, title: string) =>\n `\\n${c.cyan}${c.bold}[${n}/3]${c.reset} ${c.bold}${title}${c.reset}\\n`;\nconst dim = (msg: string) => `${c.dim}${msg}${c.reset}`;\n\n// --- Telegram validation ---\n\nexport async function validateBotToken(\n token: string,\n): Promise<\n | { ok: true; botName: string; botUsername: string }\n | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);\n const data = (await res.json()) as {\n ok: boolean;\n result?: { first_name: string; username: string };\n description?: string;\n };\n if (data.ok && data.result) {\n return {\n ok: true,\n botName: data.result.first_name,\n botUsername: data.result.username,\n };\n }\n return { ok: false, error: data.description || \"Invalid token\" };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\nexport async function validateChatId(\n token: string,\n chatId: number,\n): Promise<\n { ok: true; title: string; isForum: boolean } | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getChat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n result?: { title: string; type: string; is_forum?: boolean };\n description?: string;\n };\n if (!data.ok || !data.result) {\n return { ok: false, error: data.description || \"Invalid chat ID\" };\n }\n if (data.result.type !== \"supergroup\") {\n return {\n ok: false,\n error: `Chat is \"${data.result.type}\", must be a supergroup`,\n };\n }\n return {\n ok: true,\n title: data.result.title,\n isForum: data.result.is_forum === true,\n };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\n// --- Chat ID auto-detection ---\n\nfunction promptManualChatId(): Promise<number> {\n return input({\n message: \"Supergroup chat ID (e.g. -1001234567890):\",\n validate: (val) => {\n const n = Number(val.trim());\n if (isNaN(n) || !Number.isInteger(n)) return \"Chat ID must be an integer\";\n return true;\n },\n }).then((val) => Number(val.trim()));\n}\n\nasync function detectChatId(token: string): Promise<number> {\n // Clear old updates\n let lastUpdateId = 0;\n try {\n const clearRes = await fetch(\n `https://api.telegram.org/bot${token}/getUpdates?offset=-1`,\n );\n const clearData = (await clearRes.json()) as {\n ok: boolean;\n result?: Array<{ update_id: number }>;\n };\n if (clearData.ok && clearData.result?.length) {\n lastUpdateId = clearData.result[clearData.result.length - 1].update_id;\n }\n } catch {\n // ignore\n }\n\n console.log(\"\");\n console.log(` ${c.bold}If you don't have a supergroup yet:${c.reset}`);\n console.log(dim(\" 1. Open Telegram → New Group → add your bot\"));\n console.log(dim(\" 2. Group Settings → convert to Supergroup\"));\n console.log(dim(\" 3. Enable Topics in group settings\"));\n console.log(\"\");\n console.log(` ${c.bold}Then send \"hi\" in the group.${c.reset}`);\n console.log(\n dim(\n ` Listening... press ${c.reset}${c.yellow}m${c.reset}${c.dim} to enter ID manually`,\n ),\n );\n console.log(\"\");\n\n const MAX_ATTEMPTS = 120;\n const POLL_INTERVAL = 1000;\n\n // Listen for 'm' keypress to switch to manual\n let cancelled = false;\n const onKeypress = (data: Buffer) => {\n const key = data.toString();\n if (key === \"m\" || key === \"M\") {\n cancelled = true;\n }\n };\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.on(\"data\", onKeypress);\n }\n\n const cleanup = () => {\n if (process.stdin.isTTY) {\n process.stdin.removeListener(\"data\", onKeypress);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n }\n };\n\n try {\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n if (cancelled) {\n cleanup();\n return promptManualChatId();\n }\n\n try {\n const offset = lastUpdateId ? lastUpdateId + 1 : 0;\n const res = await fetch(\n `https://api.telegram.org/bot${token}/getUpdates?offset=${offset}&timeout=1`,\n );\n const data = (await res.json()) as {\n ok: boolean;\n result?: Array<{\n update_id: number;\n message?: {\n chat: { id: number; title?: string; type: string };\n };\n my_chat_member?: {\n chat: { id: number; title?: string; type: string };\n };\n }>;\n };\n\n if (!data.ok || !data.result?.length) {\n await new Promise((r) => setTimeout(r, POLL_INTERVAL));\n continue;\n }\n\n const groups = new Map<number, string>();\n for (const update of data.result) {\n lastUpdateId = update.update_id;\n const chat = update.message?.chat ?? update.my_chat_member?.chat;\n if (chat && (chat.type === \"supergroup\" || chat.type === \"group\")) {\n groups.set(chat.id, chat.title ?? String(chat.id));\n }\n }\n\n if (groups.size === 1) {\n const [id, title] = [...groups.entries()][0];\n console.log(\n ok(`Group detected: ${c.bold}${title}${c.reset}${c.green} (${id})`),\n );\n cleanup();\n return id;\n }\n\n if (groups.size > 1) {\n cleanup();\n const choices = [...groups.entries()].map(([id, title]) => ({\n name: `${title} (${id})`,\n value: id,\n }));\n return select({\n message: \"Multiple groups found. Pick one:\",\n choices,\n });\n }\n } catch {\n // Network error, retry\n }\n await new Promise((r) => setTimeout(r, POLL_INTERVAL));\n }\n\n console.log(warn(\"Timed out waiting for messages.\"));\n cleanup();\n return promptManualChatId();\n } catch (err) {\n cleanup();\n throw err;\n }\n}\n\n// --- Agent detection ---\n\nconst KNOWN_AGENTS: Array<{ name: string; commands: string[] }> = [\n { name: \"claude\", commands: [\"claude-agent-acp\", \"claude-code\", \"claude\"] },\n { name: \"codex\", commands: [\"codex\"] },\n];\n\nfunction commandExists(cmd: string): boolean {\n try {\n execFileSync(\"which\", [cmd], { stdio: \"pipe\" });\n return true;\n } catch {\n // not in PATH\n }\n // Check node_modules/.bin (walks up from cwd)\n let dir = process.cwd();\n while (true) {\n const binPath = path.join(dir, \"node_modules\", \".bin\", cmd);\n if (fs.existsSync(binPath)) return true;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nexport async function detectAgents(): Promise<\n Array<{ name: string; command: string }>\n> {\n const found: Array<{ name: string; command: string }> = [];\n for (const agent of KNOWN_AGENTS) {\n // Find all available commands for this agent (PATH + node_modules/.bin)\n const available: string[] = [];\n for (const cmd of agent.commands) {\n if (commandExists(cmd)) {\n available.push(cmd);\n }\n }\n if (available.length > 0) {\n // Prefer claude-agent-acp over claude/claude-code (priority order)\n found.push({ name: agent.name, command: available[0] });\n }\n }\n return found;\n}\n\nexport async function validateAgentCommand(command: string): Promise<boolean> {\n try {\n execFileSync(\"which\", [command], { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\n// --- Setup steps ---\n\nexport async function setupTelegram(): Promise<Config[\"channels\"][string]> {\n console.log(step(1, \"Telegram Bot\"));\n\n let botToken = \"\";\n\n while (true) {\n botToken = await input({\n message: \"Bot token (from @BotFather):\",\n validate: (val) => val.trim().length > 0 || \"Token cannot be empty\",\n });\n botToken = botToken.trim();\n\n const result = await validateBotToken(botToken);\n if (result.ok) {\n console.log(ok(`Connected to @${result.botUsername}`));\n break;\n }\n console.log(fail(result.error));\n const action = await select({\n message: \"What to do?\",\n choices: [\n { name: \"Re-enter token\", value: \"retry\" },\n { name: \"Use as-is (skip validation)\", value: \"skip\" },\n ],\n });\n if (action === \"skip\") break;\n }\n\n console.log(step(2, \"Group Chat\"));\n\n const chatId = await detectChatId(botToken);\n\n return {\n enabled: true,\n botToken,\n chatId,\n notificationTopicId: null,\n assistantTopicId: null,\n };\n}\n\nexport async function setupAgents(): Promise<{\n agents: Config[\"agents\"];\n defaultAgent: string;\n}> {\n const detected = await detectAgents();\n const agents: Config[\"agents\"] = {};\n\n if (detected.length > 0) {\n for (const agent of detected) {\n agents[agent.name] = { command: agent.command, args: [], env: {} };\n }\n } else {\n agents[\"claude\"] = { command: \"claude-agent-acp\", args: [], env: {} };\n }\n\n const defaultAgent = Object.keys(agents)[0];\n const agentCmd = agents[defaultAgent].command;\n console.log(\n ok(`Agent: ${c.bold}${defaultAgent}${c.reset}${c.green} (${agentCmd})`),\n );\n\n return { agents, defaultAgent };\n}\n\nexport async function setupWorkspace(): Promise<{ baseDir: string }> {\n console.log(step(3, \"Workspace\"));\n\n const baseDir = await input({\n message: \"Base directory for workspaces:\",\n default: \"~/openacp-workspace\",\n validate: (val) => val.trim().length > 0 || \"Path cannot be empty\",\n });\n\n return { baseDir: baseDir.trim().replace(/^['\"]|['\"]$/g, \"\") };\n}\n\n// --- Orchestrator ---\n\nfunction printWelcomeBanner(): void {\n console.log(`\n${c.cyan}${c.bold} ╔══════════════════════════════╗\n ║ Welcome to OpenACP ║\n ╚══════════════════════════════╝${c.reset}\n`);\n}\n\nexport async function runSetup(configManager: ConfigManager): Promise<boolean> {\n printWelcomeBanner();\n\n try {\n const telegram = await setupTelegram();\n const { agents, defaultAgent } = await setupAgents();\n const workspace = await setupWorkspace();\n const security = {\n allowedUserIds: [] as string[],\n maxConcurrentSessions: 5,\n sessionTimeoutMinutes: 60,\n };\n\n const config: Config = {\n channels: { telegram },\n agents,\n defaultAgent,\n workspace,\n security,\n logging: {\n level: \"info\",\n logDir: \"~/.openacp/logs\",\n maxFileSize: \"10m\",\n maxFiles: 7,\n sessionLogRetentionDays: 30,\n },\n sessionStore: { ttlDays: 30 },\n tunnel: {\n enabled: false,\n port: 3100,\n provider: \"cloudflare\",\n options: {},\n storeTtlMinutes: 60,\n auth: { enabled: false },\n },\n };\n\n try {\n await configManager.writeNew(config);\n } catch (writeErr) {\n console.log(\n fail(`Could not save config: ${(writeErr as Error).message}`),\n );\n return false;\n }\n\n console.log(\"\");\n console.log(\n ok(`Config saved to ${c.bold}${configManager.getConfigPath()}`),\n );\n console.log(ok(\"Starting OpenACP...\"));\n console.log(\"\");\n\n return true;\n } catch (err) {\n if ((err as Error).name === \"ExitPromptError\") {\n console.log(dim(\"\\nSetup cancelled.\"));\n return false;\n }\n throw err;\n }\n}\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,OAAO,cAAc;AAK9B,IAAM,IAAI;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AACT;AAEA,IAAM,KAAK,CAAC,QACV,GAAG,EAAE,KAAK,GAAG,EAAE,IAAI,SAAI,EAAE,KAAK,IAAI,EAAE,KAAK,GAAG,GAAG,GAAG,EAAE,KAAK;AAC3D,IAAM,OAAO,CAAC,QAAgB,GAAG,EAAE,MAAM,UAAK,GAAG,GAAG,EAAE,KAAK;AAC3D,IAAM,OAAO,CAAC,QAAgB,GAAG,EAAE,GAAG,UAAK,GAAG,GAAG,EAAE,KAAK;AACxD,IAAM,OAAO,CAAC,GAAW,UACvB;AAAA,EAAK,EAAE,IAAI,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,IAAI,GAAG,KAAK,GAAG,EAAE,KAAK;AAAA;AACpE,IAAM,MAAM,CAAC,QAAgB,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,EAAE,KAAK;AAIrD,eAAsB,iBACpB,OAIA;AACA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,+BAA+B,KAAK,QAAQ;AACpE,UAAM,OAAQ,MAAM,IAAI,KAAK;AAK7B,QAAI,KAAK,MAAM,KAAK,QAAQ;AAC1B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS,KAAK,OAAO;AAAA,QACrB,aAAa,KAAK,OAAO;AAAA,MAC3B;AAAA,IACF;AACA,WAAO,EAAE,IAAI,OAAO,OAAO,KAAK,eAAe,gBAAgB;AAAA,EACjE,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,OAAQ,IAAc,QAAQ;AAAA,EACpD;AACF;AAEA,eAAsB,eACpB,OACA,QAGA;AACA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,+BAA+B,KAAK,YAAY;AAAA,MACtE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,OAAO,CAAC;AAAA,IAC1C,CAAC;AACD,UAAM,OAAQ,MAAM,IAAI,KAAK;AAK7B,QAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,aAAO,EAAE,IAAI,OAAO,OAAO,KAAK,eAAe,kBAAkB;AAAA,IACnE;AACA,QAAI,KAAK,OAAO,SAAS,cAAc;AACrC,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,YAAY,KAAK,OAAO,IAAI;AAAA,MACrC;AAAA,IACF;AACA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,KAAK,OAAO;AAAA,MACnB,SAAS,KAAK,OAAO,aAAa;AAAA,IACpC;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,OAAQ,IAAc,QAAQ;AAAA,EACpD;AACF;AAIA,SAAS,qBAAsC;AAC7C,SAAO,MAAM;AAAA,IACX,SAAS;AAAA,IACT,UAAU,CAAC,QAAQ;AACjB,YAAM,IAAI,OAAO,IAAI,KAAK,CAAC;AAC3B,UAAI,MAAM,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,EAAG,QAAO;AAC7C,aAAO;AAAA,IACT;AAAA,EACF,CAAC,EAAE,KAAK,CAAC,QAAQ,OAAO,IAAI,KAAK,CAAC,CAAC;AACrC;AAEA,eAAe,aAAa,OAAgC;AAE1D,MAAI,eAAe;AACnB,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB,+BAA+B,KAAK;AAAA,IACtC;AACA,UAAM,YAAa,MAAM,SAAS,KAAK;AAIvC,QAAI,UAAU,MAAM,UAAU,QAAQ,QAAQ;AAC5C,qBAAe,UAAU,OAAO,UAAU,OAAO,SAAS,CAAC,EAAE;AAAA,IAC/D;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,KAAK,EAAE,IAAI,sCAAsC,EAAE,KAAK,EAAE;AACtE,UAAQ,IAAI,IAAI,yDAA+C,CAAC;AAChE,UAAQ,IAAI,IAAI,kDAA6C,CAAC;AAC9D,UAAQ,IAAI,IAAI,sCAAsC,CAAC;AACvD,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,KAAK,EAAE,IAAI,+BAA+B,EAAE,KAAK,EAAE;AAC/D,UAAQ;AAAA,IACN;AAAA,MACE,wBAAwB,EAAE,KAAK,GAAG,EAAE,MAAM,IAAI,EAAE,KAAK,GAAG,EAAE,GAAG;AAAA,IAC/D;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AAEd,QAAM,eAAe;AACrB,QAAM,gBAAgB;AAGtB,MAAI,YAAY;AAChB,QAAM,aAAa,CAAC,SAAiB;AACnC,UAAM,MAAM,KAAK,SAAS;AAC1B,QAAI,QAAQ,OAAO,QAAQ,KAAK;AAC9B,kBAAY;AAAA,IACd;AAAA,EACF;AACA,MAAI,QAAQ,MAAM,OAAO;AACvB,YAAQ,MAAM,WAAW,IAAI;AAC7B,YAAQ,MAAM,OAAO;AACrB,YAAQ,MAAM,GAAG,QAAQ,UAAU;AAAA,EACrC;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,MAAM,eAAe,QAAQ,UAAU;AAC/C,cAAQ,MAAM,WAAW,KAAK;AAC9B,cAAQ,MAAM,MAAM;AAAA,IACtB;AAAA,EACF;AAEA,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,cAAc,KAAK;AACrC,UAAI,WAAW;AACb,gBAAQ;AACR,eAAO,mBAAmB;AAAA,MAC5B;AAEA,UAAI;AACF,cAAM,SAAS,eAAe,eAAe,IAAI;AACjD,cAAM,MAAM,MAAM;AAAA,UAChB,+BAA+B,KAAK,sBAAsB,MAAM;AAAA,QAClE;AACA,cAAM,OAAQ,MAAM,IAAI,KAAK;AAa7B,YAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ,QAAQ;AACpC,gBAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AACrD;AAAA,QACF;AAEA,cAAM,SAAS,oBAAI,IAAoB;AACvC,mBAAW,UAAU,KAAK,QAAQ;AAChC,yBAAe,OAAO;AACtB,gBAAM,OAAO,OAAO,SAAS,QAAQ,OAAO,gBAAgB;AAC5D,cAAI,SAAS,KAAK,SAAS,gBAAgB,KAAK,SAAS,UAAU;AACjE,mBAAO,IAAI,KAAK,IAAI,KAAK,SAAS,OAAO,KAAK,EAAE,CAAC;AAAA,UACnD;AAAA,QACF;AAEA,YAAI,OAAO,SAAS,GAAG;AACrB,gBAAM,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,OAAO,QAAQ,CAAC,EAAE,CAAC;AAC3C,kBAAQ;AAAA,YACN,GAAG,mBAAmB,EAAE,IAAI,GAAG,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,GAAG;AAAA,UACpE;AACA,kBAAQ;AACR,iBAAO;AAAA,QACT;AAEA,YAAI,OAAO,OAAO,GAAG;AACnB,kBAAQ;AACR,gBAAM,UAAU,CAAC,GAAG,OAAO,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;AAAA,YAC1D,MAAM,GAAG,KAAK,KAAK,EAAE;AAAA,YACrB,OAAO;AAAA,UACT,EAAE;AACF,iBAAO,OAAO;AAAA,YACZ,SAAS;AAAA,YACT;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AAAA,MAER;AACA,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAAA,IACvD;AAEA,YAAQ,IAAI,KAAK,iCAAiC,CAAC;AACnD,YAAQ;AACR,WAAO,mBAAmB;AAAA,EAC5B,SAAS,KAAK;AACZ,YAAQ;AACR,UAAM;AAAA,EACR;AACF;AAIA,IAAM,eAA4D;AAAA,EAChE,EAAE,MAAM,UAAU,UAAU,CAAC,oBAAoB,eAAe,QAAQ,EAAE;AAAA,EAC1E,EAAE,MAAM,SAAS,UAAU,CAAC,OAAO,EAAE;AACvC;AAEA,SAAS,cAAc,KAAsB;AAC3C,MAAI;AACF,iBAAa,SAAS,CAAC,GAAG,GAAG,EAAE,OAAO,OAAO,CAAC;AAC9C,WAAO;AAAA,EACT,QAAQ;AAAA,EAER;AAEA,MAAI,MAAM,QAAQ,IAAI;AACtB,SAAO,MAAM;AACX,UAAM,UAAe,UAAK,KAAK,gBAAgB,QAAQ,GAAG;AAC1D,QAAO,cAAW,OAAO,EAAG,QAAO;AACnC,UAAM,SAAc,aAAQ,GAAG;AAC/B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEA,eAAsB,eAEpB;AACA,QAAM,QAAkD,CAAC;AACzD,aAAW,SAAS,cAAc;AAEhC,UAAM,YAAsB,CAAC;AAC7B,eAAW,OAAO,MAAM,UAAU;AAChC,UAAI,cAAc,GAAG,GAAG;AACtB,kBAAU,KAAK,GAAG;AAAA,MACpB;AAAA,IACF;AACA,QAAI,UAAU,SAAS,GAAG;AAExB,YAAM,KAAK,EAAE,MAAM,MAAM,MAAM,SAAS,UAAU,CAAC,EAAE,CAAC;AAAA,IACxD;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,qBAAqB,SAAmC;AAC5E,MAAI;AACF,iBAAa,SAAS,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,CAAC;AAClD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,eAAsB,gBAAqD;AACzE,UAAQ,IAAI,KAAK,GAAG,cAAc,CAAC;AAEnC,MAAI,WAAW;AAEf,SAAO,MAAM;AACX,eAAW,MAAM,MAAM;AAAA,MACrB,SAAS;AAAA,MACT,UAAU,CAAC,QAAQ,IAAI,KAAK,EAAE,SAAS,KAAK;AAAA,IAC9C,CAAC;AACD,eAAW,SAAS,KAAK;AAEzB,UAAM,SAAS,MAAM,iBAAiB,QAAQ;AAC9C,QAAI,OAAO,IAAI;AACb,cAAQ,IAAI,GAAG,iBAAiB,OAAO,WAAW,EAAE,CAAC;AACrD;AAAA,IACF;AACA,YAAQ,IAAI,KAAK,OAAO,KAAK,CAAC;AAC9B,UAAM,SAAS,MAAM,OAAO;AAAA,MAC1B,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAM,kBAAkB,OAAO,QAAQ;AAAA,QACzC,EAAE,MAAM,+BAA+B,OAAO,OAAO;AAAA,MACvD;AAAA,IACF,CAAC;AACD,QAAI,WAAW,OAAQ;AAAA,EACzB;AAEA,UAAQ,IAAI,KAAK,GAAG,YAAY,CAAC;AAEjC,QAAM,SAAS,MAAM,aAAa,QAAQ;AAE1C,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,qBAAqB;AAAA,IACrB,kBAAkB;AAAA,EACpB;AACF;AAEA,eAAsB,cAGnB;AACD,QAAM,WAAW,MAAM,aAAa;AACpC,QAAM,SAA2B,CAAC;AAElC,MAAI,SAAS,SAAS,GAAG;AACvB,eAAW,SAAS,UAAU;AAC5B,aAAO,MAAM,IAAI,IAAI,EAAE,SAAS,MAAM,SAAS,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE;AAAA,IACnE;AAAA,EACF,OAAO;AACL,WAAO,QAAQ,IAAI,EAAE,SAAS,oBAAoB,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE;AAAA,EACtE;AAEA,QAAM,eAAe,OAAO,KAAK,MAAM,EAAE,CAAC;AAC1C,QAAM,WAAW,OAAO,YAAY,EAAE;AACtC,UAAQ;AAAA,IACN,GAAG,UAAU,EAAE,IAAI,GAAG,YAAY,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK,QAAQ,GAAG;AAAA,EACxE;AAEA,SAAO,EAAE,QAAQ,aAAa;AAChC;AAEA,eAAsB,iBAA+C;AACnE,UAAQ,IAAI,KAAK,GAAG,WAAW,CAAC;AAEhC,QAAM,UAAU,MAAM,MAAM;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU,CAAC,QAAQ,IAAI,KAAK,EAAE,SAAS,KAAK;AAAA,EAC9C,CAAC;AAED,SAAO,EAAE,SAAS,QAAQ,KAAK,EAAE,QAAQ,gBAAgB,EAAE,EAAE;AAC/D;AAIA,SAAS,qBAA2B;AAClC,UAAQ,IAAI;AAAA,EACZ,EAAE,IAAI,GAAG,EAAE,IAAI;AAAA;AAAA,oMAEmB,EAAE,KAAK;AAAA,CAC1C;AACD;AAEA,eAAsB,SAAS,eAAgD;AAC7E,qBAAmB;AAEnB,MAAI;AACF,UAAM,WAAW,MAAM,cAAc;AACrC,UAAM,EAAE,QAAQ,aAAa,IAAI,MAAM,YAAY;AACnD,UAAM,YAAY,MAAM,eAAe;AACvC,UAAM,WAAW;AAAA,MACf,gBAAgB,CAAC;AAAA,MACjB,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,IACzB;AAEA,UAAM,SAAiB;AAAA,MACrB,UAAU,EAAE,SAAS;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,QACP,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,UAAU;AAAA,QACV,yBAAyB;AAAA,MAC3B;AAAA,MACA,cAAc,EAAE,SAAS,GAAG;AAAA,MAC5B,QAAQ;AAAA,QACN,SAAS;AAAA,QACT,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,CAAC;AAAA,QACV,iBAAiB;AAAA,QACjB,MAAM,EAAE,SAAS,MAAM;AAAA,MACzB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,cAAc,SAAS,MAAM;AAAA,IACrC,SAAS,UAAU;AACjB,cAAQ;AAAA,QACN,KAAK,0BAA2B,SAAmB,OAAO,EAAE;AAAA,MAC9D;AACA,aAAO;AAAA,IACT;AAEA,YAAQ,IAAI,EAAE;AACd,YAAQ;AAAA,MACN,GAAG,mBAAmB,EAAE,IAAI,GAAG,cAAc,cAAc,CAAC,EAAE;AAAA,IAChE;AACA,YAAQ,IAAI,GAAG,qBAAqB,CAAC;AACrC,YAAQ,IAAI,EAAE;AAEd,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAK,IAAc,SAAS,mBAAmB;AAC7C,cAAQ,IAAI,IAAI,oBAAoB,CAAC;AACrC,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;","names":[]}
|