pubblue 0.6.1 → 0.6.8
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-AZQD654L.js +1489 -0
- package/dist/index.js +201 -204
- package/dist/live-daemon-entry.js +778 -0
- package/package.json +4 -4
- package/dist/chunk-BBJOOZHS.js +0 -676
- package/dist/chunk-WXNNDR4T.js +0 -1313
- package/dist/tunnel-daemon-BR5XKNEA.js +0 -7
- package/dist/tunnel-daemon-entry.js +0 -27
- /package/dist/{tunnel-daemon-entry.d.ts → live-daemon-entry.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -6,32 +6,28 @@ import {
|
|
|
6
6
|
TEXT_FILE_EXTENSIONS,
|
|
7
7
|
buildBridgeProcessEnv,
|
|
8
8
|
buildDaemonForkStdio,
|
|
9
|
-
createApiClient,
|
|
10
9
|
ensureNodeDatachannelAvailable,
|
|
10
|
+
errorMessage,
|
|
11
11
|
failCli,
|
|
12
12
|
formatApiError,
|
|
13
13
|
generateMessageId,
|
|
14
14
|
getAgentSocketPath,
|
|
15
|
-
getConfig,
|
|
16
15
|
getFollowReadDelayMs,
|
|
17
16
|
getMimeType,
|
|
18
|
-
getTelegramMiniAppUrl,
|
|
19
17
|
ipcCall,
|
|
20
18
|
isDaemonRunning,
|
|
21
19
|
liveInfoPath,
|
|
22
20
|
liveLogPath,
|
|
23
|
-
loadConfig,
|
|
24
21
|
messageContainsPong,
|
|
25
22
|
parsePositiveIntegerOption,
|
|
26
23
|
readLogTail,
|
|
27
24
|
resolveActiveSlug,
|
|
28
25
|
resolveBridgeMode,
|
|
29
|
-
saveConfig,
|
|
30
26
|
stopOtherDaemons,
|
|
31
27
|
toCliFailure,
|
|
32
28
|
waitForDaemonReady,
|
|
33
29
|
writeLatestCliVersion
|
|
34
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-AZQD654L.js";
|
|
35
31
|
|
|
36
32
|
// src/program.ts
|
|
37
33
|
import { Command } from "commander";
|
|
@@ -39,11 +35,71 @@ import { Command } from "commander";
|
|
|
39
35
|
// src/commands/configure.ts
|
|
40
36
|
import { createInterface } from "readline/promises";
|
|
41
37
|
|
|
42
|
-
// src/
|
|
38
|
+
// src/lib/config.ts
|
|
43
39
|
import * as fs from "fs";
|
|
40
|
+
import * as os from "os";
|
|
44
41
|
import * as path from "path";
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
var DEFAULT_BASE_URL = "https://silent-guanaco-514.convex.site";
|
|
43
|
+
function getConfigDir(homeDir) {
|
|
44
|
+
const home = homeDir || os.homedir();
|
|
45
|
+
return path.join(home, ".config", "pubblue");
|
|
46
|
+
}
|
|
47
|
+
function getConfigPath(homeDir) {
|
|
48
|
+
const dir = getConfigDir(homeDir);
|
|
49
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
50
|
+
try {
|
|
51
|
+
fs.chmodSync(dir, 448);
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
return path.join(dir, "config.json");
|
|
55
|
+
}
|
|
56
|
+
function readConfig(homeDir) {
|
|
57
|
+
const configPath = getConfigPath(homeDir);
|
|
58
|
+
if (!fs.existsSync(configPath)) return null;
|
|
59
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
60
|
+
return JSON.parse(raw);
|
|
61
|
+
}
|
|
62
|
+
function saveConfig(config, homeDir) {
|
|
63
|
+
const configPath = getConfigPath(homeDir);
|
|
64
|
+
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
65
|
+
`, {
|
|
66
|
+
mode: 384
|
|
67
|
+
});
|
|
68
|
+
try {
|
|
69
|
+
fs.chmodSync(configPath, 384);
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function getConfig(homeDir) {
|
|
74
|
+
const envKey = process.env.PUBBLUE_API_KEY;
|
|
75
|
+
const envUrl = process.env.PUBBLUE_URL;
|
|
76
|
+
const baseUrl = envUrl || DEFAULT_BASE_URL;
|
|
77
|
+
const saved = readConfig(homeDir);
|
|
78
|
+
if (envKey) {
|
|
79
|
+
return { apiKey: envKey, baseUrl, bridge: saved?.bridge };
|
|
80
|
+
}
|
|
81
|
+
if (!saved) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
"Not configured. Run `pubblue configure` or set PUBBLUE_API_KEY environment variable."
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
apiKey: saved.apiKey,
|
|
88
|
+
baseUrl,
|
|
89
|
+
bridge: saved.bridge
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function getTelegramMiniAppUrl(slug) {
|
|
93
|
+
const saved = readConfig();
|
|
94
|
+
if (!saved?.telegram?.botUsername) return null;
|
|
95
|
+
return `https://t.me/${saved.telegram.botUsername}?startapp=${slug}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/commands/shared.ts
|
|
99
|
+
import * as fs2 from "fs";
|
|
100
|
+
import * as path2 from "path";
|
|
101
|
+
function createClient(configOverride) {
|
|
102
|
+
const config = configOverride || getConfig();
|
|
47
103
|
return new PubApiClient(config.baseUrl, config.apiKey);
|
|
48
104
|
}
|
|
49
105
|
async function readFromStdin() {
|
|
@@ -65,13 +121,13 @@ function resolveVisibilityFlags(opts) {
|
|
|
65
121
|
return void 0;
|
|
66
122
|
}
|
|
67
123
|
function readFile(filePath) {
|
|
68
|
-
const resolved =
|
|
69
|
-
if (!
|
|
124
|
+
const resolved = path2.resolve(filePath);
|
|
125
|
+
if (!fs2.existsSync(resolved)) {
|
|
70
126
|
failCli(`File not found: ${resolved}`);
|
|
71
127
|
}
|
|
72
128
|
return {
|
|
73
|
-
content:
|
|
74
|
-
basename:
|
|
129
|
+
content: fs2.readFileSync(resolved, "utf-8"),
|
|
130
|
+
basename: path2.basename(resolved)
|
|
75
131
|
};
|
|
76
132
|
}
|
|
77
133
|
|
|
@@ -133,103 +189,78 @@ function parsePositiveInteger(raw, key) {
|
|
|
133
189
|
}
|
|
134
190
|
return parsed;
|
|
135
191
|
}
|
|
136
|
-
var
|
|
137
|
-
"openclaw.path",
|
|
138
|
-
"openclaw.
|
|
139
|
-
"openclaw.
|
|
140
|
-
"openclaw.
|
|
141
|
-
"openclaw.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
"openclaw.
|
|
147
|
-
"
|
|
148
|
-
|
|
192
|
+
var CONFIG_KEY_REGISTRY = {
|
|
193
|
+
"openclaw.path": { target: "bridge", field: "openclawPath", type: "string" },
|
|
194
|
+
"openclaw.stateDir": { target: "bridge", field: "openclawStateDir", type: "string" },
|
|
195
|
+
"openclaw.sessionId": { target: "bridge", field: "sessionId", type: "string" },
|
|
196
|
+
"openclaw.threadId": { target: "bridge", field: "threadId", type: "string" },
|
|
197
|
+
"openclaw.canvasReminderEvery": {
|
|
198
|
+
target: "bridge",
|
|
199
|
+
field: "canvasReminderEvery",
|
|
200
|
+
type: "integer"
|
|
201
|
+
},
|
|
202
|
+
"openclaw.deliver": { target: "bridge", field: "deliver", type: "boolean" },
|
|
203
|
+
"openclaw.deliverChannel": { target: "bridge", field: "deliverChannel", type: "string" },
|
|
204
|
+
"openclaw.replyTo": { target: "bridge", field: "replyTo", type: "string" },
|
|
205
|
+
"openclaw.deliverTimeoutMs": { target: "bridge", field: "deliverTimeoutMs", type: "integer" },
|
|
206
|
+
"openclaw.attachmentDir": { target: "bridge", field: "attachmentDir", type: "string" },
|
|
207
|
+
"openclaw.attachmentMaxBytes": { target: "bridge", field: "attachmentMaxBytes", type: "integer" },
|
|
208
|
+
"claude-code.path": { target: "bridge", field: "claudeCodePath", type: "string" },
|
|
209
|
+
"claude-code.model": { target: "bridge", field: "claudeCodeModel", type: "string" },
|
|
210
|
+
"claude-code.allowedTools": { target: "bridge", field: "claudeCodeAllowedTools", type: "string" },
|
|
211
|
+
"claude-code.appendSystemPrompt": {
|
|
212
|
+
target: "bridge",
|
|
213
|
+
field: "claudeCodeAppendSystemPrompt",
|
|
214
|
+
type: "string",
|
|
215
|
+
displayAs: "set-only"
|
|
216
|
+
},
|
|
217
|
+
"claude-code.maxTurns": { target: "bridge", field: "claudeCodeMaxTurns", type: "integer" },
|
|
218
|
+
"claude-code.cwd": { target: "bridge", field: "claudeCodeCwd", type: "string" },
|
|
219
|
+
"telegram.botToken": {
|
|
220
|
+
target: "telegram",
|
|
221
|
+
field: "botToken",
|
|
222
|
+
type: "string",
|
|
223
|
+
cascadeUnset: ["botUsername", "hasMainWebApp"]
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
var SUPPORTED_KEYS = Object.keys(CONFIG_KEY_REGISTRY);
|
|
227
|
+
function coerceValue(raw, type, key) {
|
|
228
|
+
if (type === "integer") return parsePositiveInteger(raw, key);
|
|
229
|
+
if (type === "boolean") return parseBooleanValue(raw, key);
|
|
230
|
+
return raw;
|
|
231
|
+
}
|
|
149
232
|
function applyConfigSet(bridge, telegram, key, value) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return;
|
|
166
|
-
case "openclaw.deliverChannel":
|
|
167
|
-
bridge.deliverChannel = value;
|
|
168
|
-
return;
|
|
169
|
-
case "openclaw.replyTo":
|
|
170
|
-
bridge.replyTo = value;
|
|
171
|
-
return;
|
|
172
|
-
case "openclaw.deliverTimeoutMs":
|
|
173
|
-
bridge.deliverTimeoutMs = parsePositiveInteger(value, key);
|
|
174
|
-
return;
|
|
175
|
-
case "openclaw.attachmentDir":
|
|
176
|
-
bridge.attachmentDir = value;
|
|
177
|
-
return;
|
|
178
|
-
case "openclaw.attachmentMaxBytes":
|
|
179
|
-
bridge.attachmentMaxBytes = parsePositiveInteger(value, key);
|
|
180
|
-
return;
|
|
181
|
-
case "telegram.botToken":
|
|
182
|
-
telegram.botToken = value;
|
|
183
|
-
return;
|
|
184
|
-
default:
|
|
185
|
-
throw new Error(
|
|
186
|
-
[
|
|
187
|
-
`Unknown config key: ${key}`,
|
|
188
|
-
"Supported keys:",
|
|
189
|
-
...SUPPORTED_KEYS.map((k) => ` ${k}`)
|
|
190
|
-
].join("\n")
|
|
191
|
-
);
|
|
233
|
+
const def = CONFIG_KEY_REGISTRY[key];
|
|
234
|
+
if (!def) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
[
|
|
237
|
+
`Unknown config key: ${key}`,
|
|
238
|
+
"Supported keys:",
|
|
239
|
+
...SUPPORTED_KEYS.map((k) => ` ${k}`)
|
|
240
|
+
].join("\n")
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
const coerced = coerceValue(value, def.type, key);
|
|
244
|
+
if (def.target === "bridge") {
|
|
245
|
+
Object.assign(bridge, { [def.field]: coerced });
|
|
246
|
+
} else {
|
|
247
|
+
Object.assign(telegram, { [def.field]: coerced });
|
|
192
248
|
}
|
|
193
249
|
}
|
|
194
250
|
function applyConfigUnset(bridge, telegram, key) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
case "openclaw.deliver":
|
|
209
|
-
delete bridge.deliver;
|
|
210
|
-
return;
|
|
211
|
-
case "openclaw.deliverChannel":
|
|
212
|
-
delete bridge.deliverChannel;
|
|
213
|
-
return;
|
|
214
|
-
case "openclaw.replyTo":
|
|
215
|
-
delete bridge.replyTo;
|
|
216
|
-
return;
|
|
217
|
-
case "openclaw.deliverTimeoutMs":
|
|
218
|
-
delete bridge.deliverTimeoutMs;
|
|
219
|
-
return;
|
|
220
|
-
case "openclaw.attachmentDir":
|
|
221
|
-
delete bridge.attachmentDir;
|
|
222
|
-
return;
|
|
223
|
-
case "openclaw.attachmentMaxBytes":
|
|
224
|
-
delete bridge.attachmentMaxBytes;
|
|
225
|
-
return;
|
|
226
|
-
case "telegram.botToken":
|
|
227
|
-
delete telegram.botToken;
|
|
228
|
-
delete telegram.botUsername;
|
|
229
|
-
delete telegram.hasMainWebApp;
|
|
230
|
-
return;
|
|
231
|
-
default:
|
|
232
|
-
throw new Error(`Unknown config key for --unset: ${key}`);
|
|
251
|
+
const def = CONFIG_KEY_REGISTRY[key];
|
|
252
|
+
if (!def) {
|
|
253
|
+
throw new Error(`Unknown config key for --unset: ${key}`);
|
|
254
|
+
}
|
|
255
|
+
if (def.target === "bridge") {
|
|
256
|
+
delete bridge[def.field];
|
|
257
|
+
} else {
|
|
258
|
+
delete telegram[def.field];
|
|
259
|
+
if (def.cascadeUnset) {
|
|
260
|
+
for (const cascadeField of def.cascadeUnset) {
|
|
261
|
+
delete telegram[cascadeField];
|
|
262
|
+
}
|
|
263
|
+
}
|
|
233
264
|
}
|
|
234
265
|
}
|
|
235
266
|
function hasValues(obj) {
|
|
@@ -261,41 +292,32 @@ async function telegramSetMenuButton(token, button) {
|
|
|
261
292
|
throw new Error(data.description ?? "setChatMenuButton failed");
|
|
262
293
|
}
|
|
263
294
|
}
|
|
264
|
-
function
|
|
265
|
-
if (
|
|
266
|
-
|
|
295
|
+
function formatFieldValue(value, def) {
|
|
296
|
+
if (def.displayAs === "set-only") return "(set)";
|
|
297
|
+
if (def.type === "boolean") return value ? "true" : "false";
|
|
298
|
+
return String(value);
|
|
299
|
+
}
|
|
300
|
+
function printBridgeConfig(bridge) {
|
|
301
|
+
if (!hasValues(bridge)) {
|
|
302
|
+
console.log(" bridge: none");
|
|
267
303
|
return;
|
|
268
304
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (
|
|
273
|
-
|
|
274
|
-
if (saved.bridge.threadId) console.log(` openclaw.threadId: ${saved.bridge.threadId}`);
|
|
275
|
-
if (saved.bridge.canvasReminderEvery !== void 0)
|
|
276
|
-
console.log(` openclaw.canvasReminderEvery: ${saved.bridge.canvasReminderEvery}`);
|
|
277
|
-
if (saved.bridge.deliver !== void 0)
|
|
278
|
-
console.log(` openclaw.deliver: ${saved.bridge.deliver ? "true" : "false"}`);
|
|
279
|
-
if (saved.bridge.deliverChannel)
|
|
280
|
-
console.log(` openclaw.deliverChannel: ${saved.bridge.deliverChannel}`);
|
|
281
|
-
if (saved.bridge.replyTo) console.log(` openclaw.replyTo: ${saved.bridge.replyTo}`);
|
|
282
|
-
if (saved.bridge.deliverTimeoutMs !== void 0)
|
|
283
|
-
console.log(` openclaw.deliverTimeoutMs: ${saved.bridge.deliverTimeoutMs}`);
|
|
284
|
-
if (saved.bridge.attachmentDir)
|
|
285
|
-
console.log(` openclaw.attachmentDir: ${saved.bridge.attachmentDir}`);
|
|
286
|
-
if (saved.bridge.attachmentMaxBytes !== void 0)
|
|
287
|
-
console.log(` openclaw.attachmentMaxBytes: ${saved.bridge.attachmentMaxBytes}`);
|
|
288
|
-
} else {
|
|
289
|
-
console.log(" bridge: none");
|
|
305
|
+
for (const [key, def] of Object.entries(CONFIG_KEY_REGISTRY)) {
|
|
306
|
+
if (def.target !== "bridge") continue;
|
|
307
|
+
const value = bridge[def.field];
|
|
308
|
+
if (value === void 0) continue;
|
|
309
|
+
console.log(` ${key}: ${formatFieldValue(value, def)}`);
|
|
290
310
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
311
|
+
}
|
|
312
|
+
function printTelegramConfig(telegram) {
|
|
313
|
+
if (telegram?.botToken && telegram.botUsername) {
|
|
314
|
+
console.log(` telegram.botToken: ${maskSecret(telegram.botToken)}`);
|
|
315
|
+
console.log(` telegram.botUsername: @${telegram.botUsername}`);
|
|
316
|
+
if (!telegram.hasMainWebApp) {
|
|
295
317
|
console.log(" INFO: Register Mini App in @BotFather for deep links to open in Telegram");
|
|
296
318
|
}
|
|
297
|
-
} else if (
|
|
298
|
-
console.log(` telegram.botToken: ${maskSecret(
|
|
319
|
+
} else if (telegram?.botToken) {
|
|
320
|
+
console.log(` telegram.botToken: ${maskSecret(telegram.botToken)}`);
|
|
299
321
|
console.log(" telegram.botUsername: (not resolved)");
|
|
300
322
|
} else {
|
|
301
323
|
console.log(" telegram: not configured");
|
|
@@ -303,6 +325,16 @@ function printConfigSummary(saved) {
|
|
|
303
325
|
console.log(" Example: pubblue configure --set telegram.botToken=<BOT_TOKEN>");
|
|
304
326
|
}
|
|
305
327
|
}
|
|
328
|
+
function printConfigSummary(saved) {
|
|
329
|
+
if (!saved) {
|
|
330
|
+
console.log("Saved config: none");
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
console.log("Saved config:");
|
|
334
|
+
console.log(` apiKey: ${maskSecret(saved.apiKey)}`);
|
|
335
|
+
printBridgeConfig(saved.bridge ?? {});
|
|
336
|
+
printTelegramConfig(saved.telegram);
|
|
337
|
+
}
|
|
306
338
|
function registerConfigureCommand(program2) {
|
|
307
339
|
program2.command("configure").description("Configure the CLI with your API key").option("--api-key <key>", "Your API key (less secure: appears in shell history)").option("--api-key-stdin", "Read API key from stdin").option(
|
|
308
340
|
"--set <key=value>",
|
|
@@ -311,7 +343,7 @@ function registerConfigureCommand(program2) {
|
|
|
311
343
|
[]
|
|
312
344
|
).option("--unset <key>", "Unset config key (repeatable)", collectValues, []).option("--show", "Show saved configuration").action(
|
|
313
345
|
async (opts) => {
|
|
314
|
-
const saved =
|
|
346
|
+
const saved = readConfig();
|
|
315
347
|
const hasApiUpdate = Boolean(opts.apiKey || opts.apiKeyStdin);
|
|
316
348
|
const hasSet = opts.set.length > 0;
|
|
317
349
|
const hasUnset = opts.unset.length > 0;
|
|
@@ -349,7 +381,7 @@ function registerConfigureCommand(program2) {
|
|
|
349
381
|
console.log("Telegram menu button reset to default.");
|
|
350
382
|
} catch (error) {
|
|
351
383
|
console.error(
|
|
352
|
-
`Warning: failed to reset Telegram menu button: ${
|
|
384
|
+
`Warning: failed to reset Telegram menu button: ${errorMessage(error)}`
|
|
353
385
|
);
|
|
354
386
|
}
|
|
355
387
|
}
|
|
@@ -389,21 +421,21 @@ function registerConfigureCommand(program2) {
|
|
|
389
421
|
}
|
|
390
422
|
|
|
391
423
|
// src/commands/live.ts
|
|
392
|
-
import * as
|
|
393
|
-
import * as
|
|
424
|
+
import * as fs3 from "fs";
|
|
425
|
+
import * as path3 from "path";
|
|
394
426
|
|
|
395
427
|
// package.json
|
|
396
428
|
var package_default = {
|
|
397
429
|
name: "pubblue",
|
|
398
|
-
version: "0.6.
|
|
399
|
-
description: "CLI tool for publishing content and running
|
|
430
|
+
version: "0.6.8",
|
|
431
|
+
description: "CLI tool for publishing content and running live sessions via pub.blue",
|
|
400
432
|
type: "module",
|
|
401
433
|
bin: {
|
|
402
434
|
pubblue: "./dist/index.js"
|
|
403
435
|
},
|
|
404
436
|
scripts: {
|
|
405
|
-
build: "tsup src/index.ts src/
|
|
406
|
-
dev: "tsup src/index.ts src/
|
|
437
|
+
build: "tsup src/index.ts src/live-daemon-entry.ts --format esm --dts --clean",
|
|
438
|
+
dev: "tsup src/index.ts src/live-daemon-entry.ts --format esm --watch",
|
|
407
439
|
test: "vitest run",
|
|
408
440
|
"test:watch": "vitest",
|
|
409
441
|
lint: "tsc --noEmit"
|
|
@@ -455,39 +487,19 @@ function registerLiveCommands(program2) {
|
|
|
455
487
|
registerDoctorCommand(program2);
|
|
456
488
|
}
|
|
457
489
|
function registerStartCommand(program2) {
|
|
458
|
-
program2.command("start").description("Start the agent daemon (registers presence, awaits live requests)").requiredOption("--agent-name <name>", "Agent display name shown to the browser user").option("--bridge <mode>", "Bridge mode: openclaw|
|
|
490
|
+
program2.command("start").description("Start the agent daemon (registers presence, awaits live requests)").requiredOption("--agent-name <name>", "Agent display name shown to the browser user").option("--bridge <mode>", "Bridge mode: openclaw|claude-code").action(async (opts) => {
|
|
459
491
|
await ensureNodeDatachannelAvailable();
|
|
460
492
|
writeLatestCliVersion(CLI_VERSION);
|
|
461
493
|
const runtimeConfig = getConfig();
|
|
462
|
-
const apiClient = createApiClient(runtimeConfig);
|
|
463
494
|
const bridgeMode = resolveBridgeMode(opts);
|
|
464
495
|
const bridgeProcessEnv = buildBridgeProcessEnv(runtimeConfig.bridge);
|
|
465
496
|
const socketPath = getAgentSocketPath();
|
|
466
497
|
const infoPath = liveInfoPath("agent");
|
|
467
498
|
const logPath = liveLogPath("agent");
|
|
468
499
|
await stopOtherDaemons();
|
|
469
|
-
if (opts.foreground) {
|
|
470
|
-
const { startDaemon } = await import("./tunnel-daemon-BR5XKNEA.js");
|
|
471
|
-
console.log("Agent daemon starting in foreground...");
|
|
472
|
-
console.log("Press Ctrl+C to stop.");
|
|
473
|
-
try {
|
|
474
|
-
await startDaemon({
|
|
475
|
-
cliVersion: CLI_VERSION,
|
|
476
|
-
apiClient,
|
|
477
|
-
socketPath,
|
|
478
|
-
infoPath,
|
|
479
|
-
bridgeMode,
|
|
480
|
-
agentName: opts.agentName
|
|
481
|
-
});
|
|
482
|
-
} catch (error) {
|
|
483
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
484
|
-
failCli(`Daemon failed: ${message}`);
|
|
485
|
-
}
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
500
|
const { fork } = await import("child_process");
|
|
489
|
-
const daemonScript =
|
|
490
|
-
const daemonLogFd =
|
|
501
|
+
const daemonScript = path3.join(import.meta.dirname, "live-daemon-entry.js");
|
|
502
|
+
const daemonLogFd = fs3.openSync(logPath, "a");
|
|
491
503
|
const child = fork(daemonScript, [], {
|
|
492
504
|
detached: true,
|
|
493
505
|
stdio: buildDaemonForkStdio(daemonLogFd),
|
|
@@ -502,7 +514,7 @@ function registerStartCommand(program2) {
|
|
|
502
514
|
PUBBLUE_DAEMON_BRIDGE_MODE: bridgeMode
|
|
503
515
|
}
|
|
504
516
|
});
|
|
505
|
-
|
|
517
|
+
fs3.closeSync(daemonLogFd);
|
|
506
518
|
if (child.connected) {
|
|
507
519
|
child.disconnect();
|
|
508
520
|
}
|
|
@@ -564,12 +576,13 @@ function registerStatusCommand(program2) {
|
|
|
564
576
|
console.log(` Last error: ${response.lastError}`);
|
|
565
577
|
}
|
|
566
578
|
const logPath = liveLogPath("agent");
|
|
567
|
-
if (
|
|
579
|
+
if (fs3.existsSync(logPath)) {
|
|
568
580
|
console.log(` Log: ${logPath}`);
|
|
569
581
|
}
|
|
570
582
|
const bridge = response.bridge;
|
|
571
583
|
if (bridge) {
|
|
572
|
-
|
|
584
|
+
const bridgeLabel = response.bridgeMode ?? "unknown";
|
|
585
|
+
console.log(` Bridge: ${bridgeLabel} (${bridge.running ? "running" : "stopped"})`);
|
|
573
586
|
if (bridge.sessionId) {
|
|
574
587
|
console.log(` Bridge session: ${bridge.sessionId}`);
|
|
575
588
|
}
|
|
@@ -593,10 +606,10 @@ function registerWriteCommand(program2) {
|
|
|
593
606
|
let msg;
|
|
594
607
|
let binaryBase64;
|
|
595
608
|
if (opts.file) {
|
|
596
|
-
const filePath =
|
|
597
|
-
const ext =
|
|
598
|
-
const bytes =
|
|
599
|
-
const filename =
|
|
609
|
+
const filePath = path3.resolve(opts.file);
|
|
610
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
611
|
+
const bytes = fs3.readFileSync(filePath);
|
|
612
|
+
const filename = path3.basename(filePath);
|
|
600
613
|
if (ext === ".html" || ext === ".htm") {
|
|
601
614
|
msg = {
|
|
602
615
|
id: generateMessageId(),
|
|
@@ -713,45 +726,29 @@ function registerDoctorCommand(program2) {
|
|
|
713
726
|
const timeoutMs = timeoutSeconds * 1e3;
|
|
714
727
|
const socketPath = getAgentSocketPath();
|
|
715
728
|
const slug = await resolveActiveSlug();
|
|
716
|
-
const apiClient =
|
|
729
|
+
const apiClient = createClient();
|
|
717
730
|
const fail = (message) => failCli(`Doctor failed: ${message}`);
|
|
718
731
|
console.log(`Doctor: ${slug}`);
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
`daemon is unreachable (${error instanceof Error ? error.message : String(error)}).`
|
|
728
|
-
);
|
|
729
|
-
}
|
|
730
|
-
if (!statusResponse) {
|
|
731
|
-
fail("daemon status returned no response.");
|
|
732
|
-
}
|
|
733
|
-
const daemonStatus = statusResponse;
|
|
734
|
-
if (!daemonStatus.ok) {
|
|
735
|
-
fail(`daemon returned non-ok status: ${String(daemonStatus.error || "unknown error")}`);
|
|
736
|
-
}
|
|
737
|
-
if (!daemonStatus.connected) {
|
|
732
|
+
const statusResponse = await ipcCall(socketPath, {
|
|
733
|
+
method: "status",
|
|
734
|
+
params: {}
|
|
735
|
+
}).catch((error) => fail(`daemon is unreachable (${errorMessage(error)}).`));
|
|
736
|
+
if (!statusResponse.ok) {
|
|
737
|
+
fail(`daemon returned non-ok status: ${String(statusResponse.error || "unknown error")}`);
|
|
738
|
+
}
|
|
739
|
+
if (!statusResponse.connected) {
|
|
738
740
|
fail("daemon is running but browser is not connected.");
|
|
739
741
|
}
|
|
740
|
-
const channelNames = Array.isArray(
|
|
742
|
+
const channelNames = Array.isArray(statusResponse.channels) ? statusResponse.channels.map((entry) => String(entry)) : [];
|
|
741
743
|
for (const required of [CONTROL_CHANNEL, CHANNELS.CHAT, CHANNELS.CANVAS]) {
|
|
742
744
|
if (!channelNames.includes(required)) {
|
|
743
745
|
fail(`required channel is missing: ${required}`);
|
|
744
746
|
}
|
|
745
747
|
}
|
|
746
748
|
console.log("Daemon/channel check: OK");
|
|
747
|
-
const live = await (
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
} catch (error) {
|
|
751
|
-
fail(`failed to fetch live info from API: ${formatApiError(error)}`);
|
|
752
|
-
}
|
|
753
|
-
throw new Error("unreachable");
|
|
754
|
-
})();
|
|
749
|
+
const live = await apiClient.getLive(slug).catch(
|
|
750
|
+
(error) => fail(`failed to fetch live info from API: ${formatApiError(error)}`)
|
|
751
|
+
);
|
|
755
752
|
if (live.status !== "active") {
|
|
756
753
|
fail(`API reports live is not active (status: ${live.status})`);
|
|
757
754
|
}
|
|
@@ -932,7 +929,7 @@ function registerPubCommands(program2) {
|
|
|
932
929
|
});
|
|
933
930
|
program2.command("delete").description("Delete a pub").argument("<slug>", "Slug of the pub to delete").action(async (slug) => {
|
|
934
931
|
const client = createClient();
|
|
935
|
-
await client.
|
|
932
|
+
await client.deletePub(slug);
|
|
936
933
|
console.log(`Deleted: ${slug}`);
|
|
937
934
|
});
|
|
938
935
|
}
|