pubblue 0.6.1 → 0.6.4
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-BBJOOZHS.js → chunk-JXEXE632.js} +71 -139
- package/dist/{chunk-WXNNDR4T.js → chunk-QFJDLFK5.js} +71 -18
- package/dist/index.js +101 -62
- package/dist/live-daemon-EEIBVVBU.js +7 -0
- package/dist/{tunnel-daemon-entry.js → live-daemon-entry.js} +6 -6
- package/package.json +3 -3
- package/dist/tunnel-daemon-BR5XKNEA.js +0 -7
- /package/dist/{tunnel-daemon-entry.d.ts → live-daemon-entry.d.ts} +0 -0
|
@@ -11,6 +11,9 @@ var CliError = class extends Error {
|
|
|
11
11
|
function failCli(message, exitCode = 1) {
|
|
12
12
|
throw new CliError(message, exitCode);
|
|
13
13
|
}
|
|
14
|
+
function errorMessage(error) {
|
|
15
|
+
return error instanceof Error ? error.message : String(error);
|
|
16
|
+
}
|
|
14
17
|
function toCliFailure(error) {
|
|
15
18
|
if (error instanceof CommanderError) {
|
|
16
19
|
return {
|
|
@@ -24,15 +27,9 @@ function toCliFailure(error) {
|
|
|
24
27
|
message: error.message
|
|
25
28
|
};
|
|
26
29
|
}
|
|
27
|
-
if (error instanceof Error) {
|
|
28
|
-
return {
|
|
29
|
-
exitCode: 1,
|
|
30
|
-
message: error.message
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
30
|
return {
|
|
34
31
|
exitCode: 1,
|
|
35
|
-
message:
|
|
32
|
+
message: errorMessage(error)
|
|
36
33
|
};
|
|
37
34
|
}
|
|
38
35
|
|
|
@@ -50,8 +47,8 @@ var PubApiClient = class {
|
|
|
50
47
|
this.baseUrl = baseUrl;
|
|
51
48
|
this.apiKey = apiKey;
|
|
52
49
|
}
|
|
53
|
-
async request(
|
|
54
|
-
const url = new URL(
|
|
50
|
+
async request(path2, options = {}) {
|
|
51
|
+
const url = new URL(path2, this.baseUrl);
|
|
55
52
|
const res = await fetch(url, {
|
|
56
53
|
...options,
|
|
57
54
|
headers: {
|
|
@@ -115,7 +112,7 @@ var PubApiClient = class {
|
|
|
115
112
|
body: JSON.stringify(body)
|
|
116
113
|
});
|
|
117
114
|
}
|
|
118
|
-
async
|
|
115
|
+
async deletePub(slug) {
|
|
119
116
|
await this.request(`/api/v1/pubs/${encodeURIComponent(slug)}`, {
|
|
120
117
|
method: "DELETE"
|
|
121
118
|
});
|
|
@@ -201,72 +198,12 @@ function shouldAcknowledgeMessage(channel, msg) {
|
|
|
201
198
|
return channel !== CONTROL_CHANNEL && parseAckMessage(msg) === null;
|
|
202
199
|
}
|
|
203
200
|
|
|
204
|
-
// src/commands/
|
|
205
|
-
import * as fs2 from "fs";
|
|
206
|
-
import { homedir as homedir2 } from "os";
|
|
207
|
-
import * as path2 from "path";
|
|
208
|
-
|
|
209
|
-
// src/lib/config.ts
|
|
201
|
+
// src/commands/live-helpers.ts
|
|
210
202
|
import * as fs from "fs";
|
|
211
|
-
import
|
|
203
|
+
import { homedir } from "os";
|
|
212
204
|
import * as path from "path";
|
|
213
|
-
var DEFAULT_BASE_URL = "https://silent-guanaco-514.convex.site";
|
|
214
|
-
function getConfigDir(homeDir) {
|
|
215
|
-
const home = homeDir || os.homedir();
|
|
216
|
-
return path.join(home, ".config", "pubblue");
|
|
217
|
-
}
|
|
218
|
-
function getConfigPath(homeDir) {
|
|
219
|
-
const dir = getConfigDir(homeDir);
|
|
220
|
-
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
221
|
-
try {
|
|
222
|
-
fs.chmodSync(dir, 448);
|
|
223
|
-
} catch {
|
|
224
|
-
}
|
|
225
|
-
return path.join(dir, "config.json");
|
|
226
|
-
}
|
|
227
|
-
function loadConfig(homeDir) {
|
|
228
|
-
const configPath = getConfigPath(homeDir);
|
|
229
|
-
if (!fs.existsSync(configPath)) return null;
|
|
230
|
-
const raw = fs.readFileSync(configPath, "utf-8");
|
|
231
|
-
return JSON.parse(raw);
|
|
232
|
-
}
|
|
233
|
-
function saveConfig(config, homeDir) {
|
|
234
|
-
const configPath = getConfigPath(homeDir);
|
|
235
|
-
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
236
|
-
`, {
|
|
237
|
-
mode: 384
|
|
238
|
-
});
|
|
239
|
-
try {
|
|
240
|
-
fs.chmodSync(configPath, 384);
|
|
241
|
-
} catch {
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
function getConfig(homeDir) {
|
|
245
|
-
const envKey = process.env.PUBBLUE_API_KEY;
|
|
246
|
-
const envUrl = process.env.PUBBLUE_URL;
|
|
247
|
-
const baseUrl = envUrl || DEFAULT_BASE_URL;
|
|
248
|
-
const saved = loadConfig(homeDir);
|
|
249
|
-
if (envKey) {
|
|
250
|
-
return { apiKey: envKey, baseUrl, bridge: saved?.bridge };
|
|
251
|
-
}
|
|
252
|
-
if (!saved) {
|
|
253
|
-
throw new Error(
|
|
254
|
-
"Not configured. Run `pubblue configure` or set PUBBLUE_API_KEY environment variable."
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
return {
|
|
258
|
-
apiKey: saved.apiKey,
|
|
259
|
-
baseUrl,
|
|
260
|
-
bridge: saved.bridge
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
function getTelegramMiniAppUrl(slug) {
|
|
264
|
-
const saved = loadConfig();
|
|
265
|
-
if (!saved?.telegram?.botUsername) return null;
|
|
266
|
-
return `https://t.me/${saved.telegram.botUsername}?startapp=${slug}`;
|
|
267
|
-
}
|
|
268
205
|
|
|
269
|
-
// src/lib/
|
|
206
|
+
// src/lib/live-ipc.ts
|
|
270
207
|
import * as net from "net";
|
|
271
208
|
function getAgentSocketPath() {
|
|
272
209
|
return "/tmp/pubblue-agent.sock";
|
|
@@ -318,7 +255,7 @@ async function ipcCall(socketPath, request) {
|
|
|
318
255
|
});
|
|
319
256
|
}
|
|
320
257
|
|
|
321
|
-
// src/commands/
|
|
258
|
+
// src/commands/live-helpers.ts
|
|
322
259
|
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
323
260
|
".txt",
|
|
324
261
|
".md",
|
|
@@ -340,52 +277,54 @@ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
340
277
|
".less",
|
|
341
278
|
".log"
|
|
342
279
|
]);
|
|
280
|
+
var MIME_BY_EXT = {
|
|
281
|
+
".html": "text/html; charset=utf-8",
|
|
282
|
+
".htm": "text/html; charset=utf-8",
|
|
283
|
+
".txt": "text/plain; charset=utf-8",
|
|
284
|
+
".md": "text/markdown; charset=utf-8",
|
|
285
|
+
".markdown": "text/markdown; charset=utf-8",
|
|
286
|
+
".json": "application/json",
|
|
287
|
+
".csv": "text/csv; charset=utf-8",
|
|
288
|
+
".xml": "application/xml",
|
|
289
|
+
".yaml": "application/x-yaml",
|
|
290
|
+
".yml": "application/x-yaml",
|
|
291
|
+
".js": "text/javascript; charset=utf-8",
|
|
292
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
293
|
+
".cjs": "text/javascript; charset=utf-8",
|
|
294
|
+
".ts": "text/typescript; charset=utf-8",
|
|
295
|
+
".tsx": "text/typescript; charset=utf-8",
|
|
296
|
+
".jsx": "text/javascript; charset=utf-8",
|
|
297
|
+
".css": "text/css; charset=utf-8",
|
|
298
|
+
".scss": "text/x-scss; charset=utf-8",
|
|
299
|
+
".sass": "text/x-sass; charset=utf-8",
|
|
300
|
+
".less": "text/x-less; charset=utf-8",
|
|
301
|
+
".log": "text/plain; charset=utf-8",
|
|
302
|
+
".png": "image/png",
|
|
303
|
+
".jpg": "image/jpeg",
|
|
304
|
+
".jpeg": "image/jpeg",
|
|
305
|
+
".gif": "image/gif",
|
|
306
|
+
".webp": "image/webp",
|
|
307
|
+
".svg": "image/svg+xml",
|
|
308
|
+
".pdf": "application/pdf",
|
|
309
|
+
".zip": "application/zip",
|
|
310
|
+
".mp3": "audio/mpeg",
|
|
311
|
+
".wav": "audio/wav",
|
|
312
|
+
".mp4": "video/mp4"
|
|
313
|
+
};
|
|
343
314
|
function getMimeType(filePath) {
|
|
344
|
-
const ext =
|
|
345
|
-
|
|
346
|
-
".html": "text/html; charset=utf-8",
|
|
347
|
-
".htm": "text/html; charset=utf-8",
|
|
348
|
-
".txt": "text/plain; charset=utf-8",
|
|
349
|
-
".md": "text/markdown; charset=utf-8",
|
|
350
|
-
".markdown": "text/markdown; charset=utf-8",
|
|
351
|
-
".json": "application/json",
|
|
352
|
-
".csv": "text/csv; charset=utf-8",
|
|
353
|
-
".xml": "application/xml",
|
|
354
|
-
".yaml": "application/x-yaml",
|
|
355
|
-
".yml": "application/x-yaml",
|
|
356
|
-
".png": "image/png",
|
|
357
|
-
".jpg": "image/jpeg",
|
|
358
|
-
".jpeg": "image/jpeg",
|
|
359
|
-
".gif": "image/gif",
|
|
360
|
-
".webp": "image/webp",
|
|
361
|
-
".svg": "image/svg+xml",
|
|
362
|
-
".pdf": "application/pdf",
|
|
363
|
-
".zip": "application/zip",
|
|
364
|
-
".mp3": "audio/mpeg",
|
|
365
|
-
".wav": "audio/wav",
|
|
366
|
-
".mp4": "video/mp4"
|
|
367
|
-
};
|
|
368
|
-
return mimeByExt[ext] || "application/octet-stream";
|
|
315
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
316
|
+
return MIME_BY_EXT[ext] || "application/octet-stream";
|
|
369
317
|
}
|
|
370
318
|
function liveInfoDir() {
|
|
371
|
-
const dir =
|
|
372
|
-
|
|
373
|
-
".config",
|
|
374
|
-
"pubblue",
|
|
375
|
-
"lives"
|
|
376
|
-
);
|
|
377
|
-
if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
|
|
319
|
+
const dir = path.join(homedir(), ".config", "pubblue", "lives");
|
|
320
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
378
321
|
return dir;
|
|
379
322
|
}
|
|
380
323
|
function liveInfoPath(slug) {
|
|
381
|
-
return
|
|
324
|
+
return path.join(liveInfoDir(), `${slug}.json`);
|
|
382
325
|
}
|
|
383
326
|
function liveLogPath(slug) {
|
|
384
|
-
return
|
|
385
|
-
}
|
|
386
|
-
function createApiClient(configOverride) {
|
|
387
|
-
const config = configOverride || getConfig();
|
|
388
|
-
return new PubApiClient(config.baseUrl, config.apiKey);
|
|
327
|
+
return path.join(liveInfoDir(), `${slug}.log`);
|
|
389
328
|
}
|
|
390
329
|
function buildBridgeProcessEnv(bridgeConfig) {
|
|
391
330
|
const env = { ...process.env };
|
|
@@ -396,7 +335,7 @@ function buildBridgeProcessEnv(bridgeConfig) {
|
|
|
396
335
|
env[key] = String(value);
|
|
397
336
|
};
|
|
398
337
|
setIfMissing("PUBBLUE_PROJECT_ROOT", process.cwd());
|
|
399
|
-
setIfMissing("OPENCLAW_HOME",
|
|
338
|
+
setIfMissing("OPENCLAW_HOME", homedir());
|
|
400
339
|
if (!bridgeConfig) return env;
|
|
401
340
|
setIfMissing("OPENCLAW_PATH", bridgeConfig.openclawPath);
|
|
402
341
|
setIfMissing("OPENCLAW_SESSION_ID", bridgeConfig.sessionId);
|
|
@@ -417,12 +356,11 @@ async function ensureNodeDatachannelAvailable() {
|
|
|
417
356
|
try {
|
|
418
357
|
await import("node-datachannel");
|
|
419
358
|
} catch (error) {
|
|
420
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
421
359
|
failCli(
|
|
422
360
|
[
|
|
423
361
|
"node-datachannel native module is not available.",
|
|
424
362
|
"Run `pnpm rebuild node-datachannel` in the cli package and retry.",
|
|
425
|
-
`Details: ${
|
|
363
|
+
`Details: ${errorMessage(error)}`
|
|
426
364
|
].join("\n")
|
|
427
365
|
);
|
|
428
366
|
}
|
|
@@ -432,39 +370,38 @@ function isDaemonRunning(slug) {
|
|
|
432
370
|
}
|
|
433
371
|
function readDaemonProcessInfo(slug) {
|
|
434
372
|
const infoPath = liveInfoPath(slug);
|
|
435
|
-
if (!fs2.existsSync(infoPath)) return null;
|
|
436
373
|
try {
|
|
437
|
-
const info = JSON.parse(
|
|
374
|
+
const info = JSON.parse(fs.readFileSync(infoPath, "utf-8"));
|
|
438
375
|
if (!Number.isFinite(info.pid)) throw new Error("invalid daemon pid");
|
|
439
376
|
if (!isProcessAlive(info.pid)) throw new Error("process not alive");
|
|
440
377
|
return info;
|
|
441
378
|
} catch {
|
|
442
379
|
try {
|
|
443
|
-
|
|
380
|
+
fs.unlinkSync(infoPath);
|
|
444
381
|
} catch {
|
|
445
382
|
}
|
|
446
383
|
return null;
|
|
447
384
|
}
|
|
448
385
|
}
|
|
449
386
|
function latestCliVersionPath() {
|
|
450
|
-
return
|
|
387
|
+
return path.join(liveInfoDir(), "cli-version.txt");
|
|
451
388
|
}
|
|
452
389
|
function readLatestCliVersion(versionPath) {
|
|
453
390
|
const resolved = versionPath || latestCliVersionPath();
|
|
454
|
-
if (!fs2.existsSync(resolved)) return null;
|
|
455
391
|
try {
|
|
456
|
-
const value =
|
|
392
|
+
const value = fs.readFileSync(resolved, "utf-8").trim();
|
|
457
393
|
return value.length === 0 ? null : value;
|
|
458
394
|
} catch {
|
|
459
395
|
return null;
|
|
460
396
|
}
|
|
461
397
|
}
|
|
462
398
|
function writeLatestCliVersion(version, versionPath) {
|
|
463
|
-
|
|
399
|
+
const trimmed = version.trim();
|
|
400
|
+
if (trimmed.length === 0) return;
|
|
464
401
|
const resolved = versionPath || latestCliVersionPath();
|
|
465
|
-
const dir =
|
|
466
|
-
|
|
467
|
-
|
|
402
|
+
const dir = path.dirname(resolved);
|
|
403
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
404
|
+
fs.writeFileSync(resolved, trimmed, "utf-8");
|
|
468
405
|
}
|
|
469
406
|
function isProcessAlive(pid) {
|
|
470
407
|
try {
|
|
@@ -484,7 +421,7 @@ async function waitForProcessExit(pid, timeoutMs) {
|
|
|
484
421
|
}
|
|
485
422
|
async function stopDaemonForLive(info) {
|
|
486
423
|
const pid = info.pid;
|
|
487
|
-
if (!
|
|
424
|
+
if (!isProcessAlive(pid)) return null;
|
|
488
425
|
const socketPath = info.socketPath;
|
|
489
426
|
if (socketPath) {
|
|
490
427
|
try {
|
|
@@ -493,14 +430,14 @@ async function stopDaemonForLive(info) {
|
|
|
493
430
|
try {
|
|
494
431
|
process.kill(pid, "SIGTERM");
|
|
495
432
|
} catch (killError) {
|
|
496
|
-
return `daemon ${pid}: IPC close failed (${
|
|
433
|
+
return `daemon ${pid}: IPC close failed (${errorMessage(error)}); SIGTERM failed (${errorMessage(killError)})`;
|
|
497
434
|
}
|
|
498
435
|
}
|
|
499
436
|
} else {
|
|
500
437
|
try {
|
|
501
438
|
process.kill(pid, "SIGTERM");
|
|
502
439
|
} catch (error) {
|
|
503
|
-
return `daemon ${pid}: no socketPath and SIGTERM failed (${
|
|
440
|
+
return `daemon ${pid}: no socketPath and SIGTERM failed (${errorMessage(error)})`;
|
|
504
441
|
}
|
|
505
442
|
}
|
|
506
443
|
const stopped = await waitForProcessExit(pid, 8e3);
|
|
@@ -509,7 +446,7 @@ async function stopDaemonForLive(info) {
|
|
|
509
446
|
}
|
|
510
447
|
async function stopOtherDaemons() {
|
|
511
448
|
const dir = liveInfoDir();
|
|
512
|
-
const entries =
|
|
449
|
+
const entries = fs.readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
513
450
|
const failures = [];
|
|
514
451
|
for (const entry of entries) {
|
|
515
452
|
const slug = entry.replace(/\.json$/, "");
|
|
@@ -561,9 +498,8 @@ function messageContainsPong(payload) {
|
|
|
561
498
|
return type === "text" && typeof data === "string" && data.trim().toLowerCase() === "pong";
|
|
562
499
|
}
|
|
563
500
|
function readLogTail(logPath, maxChars = 4e3) {
|
|
564
|
-
if (!fs2.existsSync(logPath)) return null;
|
|
565
501
|
try {
|
|
566
|
-
const content =
|
|
502
|
+
const content = fs.readFileSync(logPath, "utf-8");
|
|
567
503
|
if (content.length <= maxChars) return content;
|
|
568
504
|
return content.slice(-maxChars);
|
|
569
505
|
} catch {
|
|
@@ -577,7 +513,7 @@ function formatApiError(error) {
|
|
|
577
513
|
}
|
|
578
514
|
return `${error.message} (HTTP ${error.status})`;
|
|
579
515
|
}
|
|
580
|
-
return
|
|
516
|
+
return errorMessage(error);
|
|
581
517
|
}
|
|
582
518
|
async function resolveActiveSlug() {
|
|
583
519
|
const socketPath = getAgentSocketPath();
|
|
@@ -616,12 +552,12 @@ function waitForDaemonReady({
|
|
|
616
552
|
};
|
|
617
553
|
child.on("exit", onExit);
|
|
618
554
|
const poll = setInterval(() => {
|
|
619
|
-
if (pollInFlight || !
|
|
555
|
+
if (pollInFlight || !fs.existsSync(infoPath)) return;
|
|
620
556
|
pollInFlight = true;
|
|
621
557
|
void ipcCall(socketPath, { method: "status", params: {} }).then((status) => {
|
|
622
558
|
if (status.ok) done({ ok: true });
|
|
623
559
|
}).catch((error) => {
|
|
624
|
-
lastIpcError =
|
|
560
|
+
lastIpcError = errorMessage(error);
|
|
625
561
|
}).finally(() => {
|
|
626
562
|
pollInFlight = false;
|
|
627
563
|
});
|
|
@@ -635,11 +571,8 @@ function waitForDaemonReady({
|
|
|
635
571
|
|
|
636
572
|
export {
|
|
637
573
|
failCli,
|
|
574
|
+
errorMessage,
|
|
638
575
|
toCliFailure,
|
|
639
|
-
loadConfig,
|
|
640
|
-
saveConfig,
|
|
641
|
-
getConfig,
|
|
642
|
-
getTelegramMiniAppUrl,
|
|
643
576
|
PubApiError,
|
|
644
577
|
PubApiClient,
|
|
645
578
|
CONTROL_CHANNEL,
|
|
@@ -656,7 +589,6 @@ export {
|
|
|
656
589
|
getMimeType,
|
|
657
590
|
liveInfoPath,
|
|
658
591
|
liveLogPath,
|
|
659
|
-
createApiClient,
|
|
660
592
|
buildBridgeProcessEnv,
|
|
661
593
|
ensureNodeDatachannelAvailable,
|
|
662
594
|
isDaemonRunning,
|
|
@@ -4,15 +4,16 @@ import {
|
|
|
4
4
|
PubApiError,
|
|
5
5
|
decodeMessage,
|
|
6
6
|
encodeMessage,
|
|
7
|
+
errorMessage,
|
|
7
8
|
generateMessageId,
|
|
8
9
|
latestCliVersionPath,
|
|
9
10
|
makeAckMessage,
|
|
10
11
|
parseAckMessage,
|
|
11
12
|
readLatestCliVersion,
|
|
12
13
|
shouldAcknowledgeMessage
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JXEXE632.js";
|
|
14
15
|
|
|
15
|
-
// src/lib/
|
|
16
|
+
// src/lib/live-daemon.ts
|
|
16
17
|
import * as fs from "fs";
|
|
17
18
|
import * as net from "net";
|
|
18
19
|
import * as path from "path";
|
|
@@ -24,7 +25,7 @@ function resolveAckChannel(input) {
|
|
|
24
25
|
return null;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
// src/lib/
|
|
28
|
+
// src/lib/live-bridge-openclaw.ts
|
|
28
29
|
import { execFile, execFileSync } from "child_process";
|
|
29
30
|
import { createHash } from "crypto";
|
|
30
31
|
import {
|
|
@@ -192,6 +193,46 @@ function buildAttachmentPrompt(slug, staged, includeCanvasReminder) {
|
|
|
192
193
|
`Canvas update: pubblue write --slug ${slug} -c canvas -f /path/to/file.html`
|
|
193
194
|
].filter(Boolean).join("\n");
|
|
194
195
|
}
|
|
196
|
+
function parseSessionContextMeta(meta) {
|
|
197
|
+
if (!meta) return null;
|
|
198
|
+
const payload = {};
|
|
199
|
+
if (typeof meta.title === "string") payload.title = meta.title;
|
|
200
|
+
if (typeof meta.contentType === "string") payload.contentType = meta.contentType;
|
|
201
|
+
if (typeof meta.contentPreview === "string") payload.contentPreview = meta.contentPreview;
|
|
202
|
+
if (typeof meta.isPublic === "boolean") payload.isPublic = meta.isPublic;
|
|
203
|
+
if (meta.preferences && typeof meta.preferences === "object") {
|
|
204
|
+
const prefs = meta.preferences;
|
|
205
|
+
payload.preferences = {};
|
|
206
|
+
if (typeof prefs.voiceModeEnabled === "boolean") {
|
|
207
|
+
payload.preferences.voiceModeEnabled = prefs.voiceModeEnabled;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return payload;
|
|
211
|
+
}
|
|
212
|
+
function buildSessionBriefing(slug, ctx) {
|
|
213
|
+
const lines = [`[Pubblue ${slug}] Session started.`, "", "## Pub Context"];
|
|
214
|
+
if (ctx.title) lines.push(`- Title: ${ctx.title}`);
|
|
215
|
+
if (ctx.contentType) lines.push(`- Content type: ${ctx.contentType}`);
|
|
216
|
+
if (ctx.isPublic !== void 0)
|
|
217
|
+
lines.push(`- Visibility: ${ctx.isPublic ? "public" : "private"}`);
|
|
218
|
+
if (ctx.contentPreview) {
|
|
219
|
+
lines.push("- Content preview:");
|
|
220
|
+
lines.push(ctx.contentPreview);
|
|
221
|
+
}
|
|
222
|
+
if (ctx.preferences) {
|
|
223
|
+
lines.push("", "## User Preferences");
|
|
224
|
+
if (ctx.preferences.voiceModeEnabled !== void 0) {
|
|
225
|
+
lines.push(`- Voice mode: ${ctx.preferences.voiceModeEnabled ? "on" : "off"}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
lines.push(
|
|
229
|
+
"",
|
|
230
|
+
"## Commands",
|
|
231
|
+
`Reply: pubblue write --slug ${slug} "<your reply>"`,
|
|
232
|
+
`Canvas: pubblue write --slug ${slug} -c canvas -f /path/to/file.html`
|
|
233
|
+
);
|
|
234
|
+
return lines.join("\n");
|
|
235
|
+
}
|
|
195
236
|
function readTextChatMessage(entry) {
|
|
196
237
|
if (entry.channel !== CHANNELS.CHAT) return null;
|
|
197
238
|
const msg = entry.msg;
|
|
@@ -254,7 +295,7 @@ function resolveSessionFromOpenClaw(threadId) {
|
|
|
254
295
|
const sessionsData = JSON.parse(readFileSync(sessionsPath, "utf-8"));
|
|
255
296
|
return resolveSessionFromSessionsData(sessionsData, threadId);
|
|
256
297
|
} catch (error) {
|
|
257
|
-
const readError =
|
|
298
|
+
const readError = errorMessage(error);
|
|
258
299
|
return { attemptedKeys, readError, sessionId: null };
|
|
259
300
|
}
|
|
260
301
|
}
|
|
@@ -509,6 +550,7 @@ async function createOpenClawBridgeRunner(config) {
|
|
|
509
550
|
let lastError;
|
|
510
551
|
let stopping = false;
|
|
511
552
|
let loopDone;
|
|
553
|
+
let sessionBriefingSent = false;
|
|
512
554
|
const queue = [];
|
|
513
555
|
let notify = null;
|
|
514
556
|
function enqueue(entries) {
|
|
@@ -535,6 +577,16 @@ async function createOpenClawBridgeRunner(config) {
|
|
|
535
577
|
seenIds.clear();
|
|
536
578
|
}
|
|
537
579
|
try {
|
|
580
|
+
if (!sessionBriefingSent && entry.channel === CONTROL_CHANNEL && entry.msg.type === "event" && entry.msg.data === "session-context") {
|
|
581
|
+
const ctx = parseSessionContextMeta(entry.msg.meta);
|
|
582
|
+
if (ctx) {
|
|
583
|
+
sessionBriefingSent = true;
|
|
584
|
+
const briefing = buildSessionBriefing(slug, ctx);
|
|
585
|
+
await deliverMessageToOpenClaw({ openclawPath, sessionId, text: briefing });
|
|
586
|
+
debugLog("session briefing delivered");
|
|
587
|
+
}
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
538
590
|
const includeCanvasReminder = shouldIncludeCanvasPolicyReminder(
|
|
539
591
|
forwardedMessageCount + 1,
|
|
540
592
|
canvasReminderEvery
|
|
@@ -564,7 +616,7 @@ async function createOpenClawBridgeRunner(config) {
|
|
|
564
616
|
forwardedMessageCount += 1;
|
|
565
617
|
}
|
|
566
618
|
} catch (error) {
|
|
567
|
-
const message =
|
|
619
|
+
const message = errorMessage(error);
|
|
568
620
|
lastError = message;
|
|
569
621
|
debugLog(`bridge entry processing failed: ${message}`, error);
|
|
570
622
|
config.sendMessage(CHANNELS.CHAT, {
|
|
@@ -601,8 +653,8 @@ async function createOpenClawBridgeRunner(config) {
|
|
|
601
653
|
};
|
|
602
654
|
}
|
|
603
655
|
|
|
604
|
-
// src/lib/
|
|
605
|
-
function
|
|
656
|
+
// src/lib/live-daemon-answer.ts
|
|
657
|
+
function createAnswer(peer, browserOffer, timeoutMs) {
|
|
606
658
|
return new Promise((resolve, reject) => {
|
|
607
659
|
let resolved = false;
|
|
608
660
|
const done = (sdp, type) => {
|
|
@@ -635,14 +687,14 @@ function generateAnswer(peer, browserOffer, timeoutMs) {
|
|
|
635
687
|
});
|
|
636
688
|
}
|
|
637
689
|
|
|
638
|
-
// src/lib/
|
|
690
|
+
// src/lib/live-daemon-shared.ts
|
|
639
691
|
var OFFER_TIMEOUT_MS = 1e4;
|
|
640
692
|
var SIGNAL_POLL_WAITING_MS = 5e3;
|
|
641
693
|
var SIGNAL_POLL_CONNECTED_MS = 15e3;
|
|
642
694
|
var LOCAL_CANDIDATE_FLUSH_MS = 2e3;
|
|
643
695
|
var WRITE_ACK_TIMEOUT_MS = 5e3;
|
|
644
696
|
var NOT_CONNECTED_WRITE_ERROR = "No browser connected. Ask the user to open the pub URL first, then retry.";
|
|
645
|
-
function
|
|
697
|
+
function getLiveWriteReadinessError(isConnected) {
|
|
646
698
|
return isConnected ? null : NOT_CONNECTED_WRITE_ERROR;
|
|
647
699
|
}
|
|
648
700
|
function shouldRecoverForBrowserOfferChange(params) {
|
|
@@ -670,7 +722,7 @@ function getSignalPollDelayMs(params) {
|
|
|
670
722
|
return Math.max(baseDelay, Math.ceil(params.retryAfterSeconds * 1e3));
|
|
671
723
|
}
|
|
672
724
|
|
|
673
|
-
// src/lib/
|
|
725
|
+
// src/lib/live-daemon.ts
|
|
674
726
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
675
727
|
var HEALTH_CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
676
728
|
var PERSIST_TIMEOUT_MS = 3e3;
|
|
@@ -699,7 +751,7 @@ async function startDaemon(config) {
|
|
|
699
751
|
let localCandidateStopTimer = null;
|
|
700
752
|
let healthCheckTimer = null;
|
|
701
753
|
let lastError = null;
|
|
702
|
-
const debugEnabled = process.env.
|
|
754
|
+
const debugEnabled = process.env.PUBBLUE_LIVE_DEBUG === "1";
|
|
703
755
|
const versionFilePath = latestCliVersionPath();
|
|
704
756
|
let bridgeRunner = null;
|
|
705
757
|
function debugLog(message, error) {
|
|
@@ -999,7 +1051,7 @@ async function startDaemon(config) {
|
|
|
999
1051
|
createPeer();
|
|
1000
1052
|
resetNegotiationState();
|
|
1001
1053
|
if (!peer) throw new Error("PeerConnection not initialized");
|
|
1002
|
-
const answer = await
|
|
1054
|
+
const answer = await createAnswer(peer, browserOffer, OFFER_TIMEOUT_MS);
|
|
1003
1055
|
lastAppliedBrowserOffer = browserOffer;
|
|
1004
1056
|
activeSlug = slug;
|
|
1005
1057
|
await apiClient.signalAnswer({ slug, answer, agentName });
|
|
@@ -1113,7 +1165,7 @@ async function startDaemon(config) {
|
|
|
1113
1165
|
return;
|
|
1114
1166
|
}
|
|
1115
1167
|
handleIpcRequest(request).then((response) => conn.write(`${JSON.stringify(response)}
|
|
1116
|
-
`)).catch((err) => conn.write(`${JSON.stringify({ ok: false, error:
|
|
1168
|
+
`)).catch((err) => conn.write(`${JSON.stringify({ ok: false, error: errorMessage(err) })}
|
|
1117
1169
|
`));
|
|
1118
1170
|
});
|
|
1119
1171
|
});
|
|
@@ -1221,7 +1273,7 @@ async function startDaemon(config) {
|
|
|
1221
1273
|
switch (req.method) {
|
|
1222
1274
|
case "write": {
|
|
1223
1275
|
const channel = req.params.channel || CHANNELS.CHAT;
|
|
1224
|
-
const readinessError =
|
|
1276
|
+
const readinessError = getLiveWriteReadinessError(connected);
|
|
1225
1277
|
if (readinessError) return { ok: false, error: readinessError };
|
|
1226
1278
|
const msg = req.params.msg;
|
|
1227
1279
|
const binaryBase64 = typeof req.params.binaryBase64 === "string" ? req.params.binaryBase64 : void 0;
|
|
@@ -1231,9 +1283,8 @@ async function startDaemon(config) {
|
|
|
1231
1283
|
try {
|
|
1232
1284
|
await waitForChannelOpen(targetDc);
|
|
1233
1285
|
} catch (error) {
|
|
1234
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1235
1286
|
markError(`channel "${channel}" failed to open`, error);
|
|
1236
|
-
return { ok: false, error: `Channel "${channel}" not open: ${
|
|
1287
|
+
return { ok: false, error: `Channel "${channel}" not open: ${errorMessage(error)}` };
|
|
1237
1288
|
}
|
|
1238
1289
|
const waitForAck = shouldAcknowledgeMessage(channel, msg) ? waitForDeliveryAck(msg.id, WRITE_ACK_TIMEOUT_MS) : null;
|
|
1239
1290
|
try {
|
|
@@ -1250,9 +1301,11 @@ async function startDaemon(config) {
|
|
|
1250
1301
|
}
|
|
1251
1302
|
} catch (error) {
|
|
1252
1303
|
if (waitForAck) settlePendingAck(msg.id, false);
|
|
1253
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1254
1304
|
markError(`failed to send message on channel "${channel}"`, error);
|
|
1255
|
-
return {
|
|
1305
|
+
return {
|
|
1306
|
+
ok: false,
|
|
1307
|
+
error: `Failed to send on channel "${channel}": ${errorMessage(error)}`
|
|
1308
|
+
};
|
|
1256
1309
|
}
|
|
1257
1310
|
if (waitForAck) {
|
|
1258
1311
|
const acked = await waitForAck;
|
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-JXEXE632.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
|
|
|
@@ -311,7 +367,7 @@ function registerConfigureCommand(program2) {
|
|
|
311
367
|
[]
|
|
312
368
|
).option("--unset <key>", "Unset config key (repeatable)", collectValues, []).option("--show", "Show saved configuration").action(
|
|
313
369
|
async (opts) => {
|
|
314
|
-
const saved =
|
|
370
|
+
const saved = readConfig();
|
|
315
371
|
const hasApiUpdate = Boolean(opts.apiKey || opts.apiKeyStdin);
|
|
316
372
|
const hasSet = opts.set.length > 0;
|
|
317
373
|
const hasUnset = opts.unset.length > 0;
|
|
@@ -349,7 +405,7 @@ function registerConfigureCommand(program2) {
|
|
|
349
405
|
console.log("Telegram menu button reset to default.");
|
|
350
406
|
} catch (error) {
|
|
351
407
|
console.error(
|
|
352
|
-
`Warning: failed to reset Telegram menu button: ${
|
|
408
|
+
`Warning: failed to reset Telegram menu button: ${errorMessage(error)}`
|
|
353
409
|
);
|
|
354
410
|
}
|
|
355
411
|
}
|
|
@@ -389,21 +445,21 @@ function registerConfigureCommand(program2) {
|
|
|
389
445
|
}
|
|
390
446
|
|
|
391
447
|
// src/commands/live.ts
|
|
392
|
-
import * as
|
|
393
|
-
import * as
|
|
448
|
+
import * as fs3 from "fs";
|
|
449
|
+
import * as path3 from "path";
|
|
394
450
|
|
|
395
451
|
// package.json
|
|
396
452
|
var package_default = {
|
|
397
453
|
name: "pubblue",
|
|
398
|
-
version: "0.6.
|
|
454
|
+
version: "0.6.4",
|
|
399
455
|
description: "CLI tool for publishing content and running interactive sessions via pub.blue",
|
|
400
456
|
type: "module",
|
|
401
457
|
bin: {
|
|
402
458
|
pubblue: "./dist/index.js"
|
|
403
459
|
},
|
|
404
460
|
scripts: {
|
|
405
|
-
build: "tsup src/index.ts src/
|
|
406
|
-
dev: "tsup src/index.ts src/
|
|
461
|
+
build: "tsup src/index.ts src/live-daemon-entry.ts --format esm --dts --clean",
|
|
462
|
+
dev: "tsup src/index.ts src/live-daemon-entry.ts --format esm --watch",
|
|
407
463
|
test: "vitest run",
|
|
408
464
|
"test:watch": "vitest",
|
|
409
465
|
lint: "tsc --noEmit"
|
|
@@ -459,7 +515,7 @@ function registerStartCommand(program2) {
|
|
|
459
515
|
await ensureNodeDatachannelAvailable();
|
|
460
516
|
writeLatestCliVersion(CLI_VERSION);
|
|
461
517
|
const runtimeConfig = getConfig();
|
|
462
|
-
const apiClient =
|
|
518
|
+
const apiClient = createClient(runtimeConfig);
|
|
463
519
|
const bridgeMode = resolveBridgeMode(opts);
|
|
464
520
|
const bridgeProcessEnv = buildBridgeProcessEnv(runtimeConfig.bridge);
|
|
465
521
|
const socketPath = getAgentSocketPath();
|
|
@@ -467,7 +523,7 @@ function registerStartCommand(program2) {
|
|
|
467
523
|
const logPath = liveLogPath("agent");
|
|
468
524
|
await stopOtherDaemons();
|
|
469
525
|
if (opts.foreground) {
|
|
470
|
-
const { startDaemon } = await import("./
|
|
526
|
+
const { startDaemon } = await import("./live-daemon-EEIBVVBU.js");
|
|
471
527
|
console.log("Agent daemon starting in foreground...");
|
|
472
528
|
console.log("Press Ctrl+C to stop.");
|
|
473
529
|
try {
|
|
@@ -480,14 +536,13 @@ function registerStartCommand(program2) {
|
|
|
480
536
|
agentName: opts.agentName
|
|
481
537
|
});
|
|
482
538
|
} catch (error) {
|
|
483
|
-
|
|
484
|
-
failCli(`Daemon failed: ${message}`);
|
|
539
|
+
failCli(`Daemon failed: ${errorMessage(error)}`);
|
|
485
540
|
}
|
|
486
541
|
return;
|
|
487
542
|
}
|
|
488
543
|
const { fork } = await import("child_process");
|
|
489
|
-
const daemonScript =
|
|
490
|
-
const daemonLogFd =
|
|
544
|
+
const daemonScript = path3.join(import.meta.dirname, "live-daemon-entry.js");
|
|
545
|
+
const daemonLogFd = fs3.openSync(logPath, "a");
|
|
491
546
|
const child = fork(daemonScript, [], {
|
|
492
547
|
detached: true,
|
|
493
548
|
stdio: buildDaemonForkStdio(daemonLogFd),
|
|
@@ -502,7 +557,7 @@ function registerStartCommand(program2) {
|
|
|
502
557
|
PUBBLUE_DAEMON_BRIDGE_MODE: bridgeMode
|
|
503
558
|
}
|
|
504
559
|
});
|
|
505
|
-
|
|
560
|
+
fs3.closeSync(daemonLogFd);
|
|
506
561
|
if (child.connected) {
|
|
507
562
|
child.disconnect();
|
|
508
563
|
}
|
|
@@ -564,7 +619,7 @@ function registerStatusCommand(program2) {
|
|
|
564
619
|
console.log(` Last error: ${response.lastError}`);
|
|
565
620
|
}
|
|
566
621
|
const logPath = liveLogPath("agent");
|
|
567
|
-
if (
|
|
622
|
+
if (fs3.existsSync(logPath)) {
|
|
568
623
|
console.log(` Log: ${logPath}`);
|
|
569
624
|
}
|
|
570
625
|
const bridge = response.bridge;
|
|
@@ -593,10 +648,10 @@ function registerWriteCommand(program2) {
|
|
|
593
648
|
let msg;
|
|
594
649
|
let binaryBase64;
|
|
595
650
|
if (opts.file) {
|
|
596
|
-
const filePath =
|
|
597
|
-
const ext =
|
|
598
|
-
const bytes =
|
|
599
|
-
const filename =
|
|
651
|
+
const filePath = path3.resolve(opts.file);
|
|
652
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
653
|
+
const bytes = fs3.readFileSync(filePath);
|
|
654
|
+
const filename = path3.basename(filePath);
|
|
600
655
|
if (ext === ".html" || ext === ".htm") {
|
|
601
656
|
msg = {
|
|
602
657
|
id: generateMessageId(),
|
|
@@ -713,45 +768,29 @@ function registerDoctorCommand(program2) {
|
|
|
713
768
|
const timeoutMs = timeoutSeconds * 1e3;
|
|
714
769
|
const socketPath = getAgentSocketPath();
|
|
715
770
|
const slug = await resolveActiveSlug();
|
|
716
|
-
const apiClient =
|
|
771
|
+
const apiClient = createClient();
|
|
717
772
|
const fail = (message) => failCli(`Doctor failed: ${message}`);
|
|
718
773
|
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) {
|
|
774
|
+
const statusResponse = await ipcCall(socketPath, {
|
|
775
|
+
method: "status",
|
|
776
|
+
params: {}
|
|
777
|
+
}).catch((error) => fail(`daemon is unreachable (${errorMessage(error)}).`));
|
|
778
|
+
if (!statusResponse.ok) {
|
|
779
|
+
fail(`daemon returned non-ok status: ${String(statusResponse.error || "unknown error")}`);
|
|
780
|
+
}
|
|
781
|
+
if (!statusResponse.connected) {
|
|
738
782
|
fail("daemon is running but browser is not connected.");
|
|
739
783
|
}
|
|
740
|
-
const channelNames = Array.isArray(
|
|
784
|
+
const channelNames = Array.isArray(statusResponse.channels) ? statusResponse.channels.map((entry) => String(entry)) : [];
|
|
741
785
|
for (const required of [CONTROL_CHANNEL, CHANNELS.CHAT, CHANNELS.CANVAS]) {
|
|
742
786
|
if (!channelNames.includes(required)) {
|
|
743
787
|
fail(`required channel is missing: ${required}`);
|
|
744
788
|
}
|
|
745
789
|
}
|
|
746
790
|
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
|
-
})();
|
|
791
|
+
const live = await apiClient.getLive(slug).catch(
|
|
792
|
+
(error) => fail(`failed to fetch live info from API: ${formatApiError(error)}`)
|
|
793
|
+
);
|
|
755
794
|
if (live.status !== "active") {
|
|
756
795
|
fail(`API reports live is not active (status: ${live.status})`);
|
|
757
796
|
}
|
|
@@ -932,7 +971,7 @@ function registerPubCommands(program2) {
|
|
|
932
971
|
});
|
|
933
972
|
program2.command("delete").description("Delete a pub").argument("<slug>", "Slug of the pub to delete").action(async (slug) => {
|
|
934
973
|
const client = createClient();
|
|
935
|
-
await client.
|
|
974
|
+
await client.deletePub(slug);
|
|
936
975
|
console.log(`Deleted: ${slug}`);
|
|
937
976
|
});
|
|
938
977
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
startDaemon
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QFJDLFK5.js";
|
|
4
4
|
import {
|
|
5
|
-
PubApiClient
|
|
6
|
-
|
|
5
|
+
PubApiClient,
|
|
6
|
+
errorMessage
|
|
7
|
+
} from "./chunk-JXEXE632.js";
|
|
7
8
|
|
|
8
|
-
// src/
|
|
9
|
+
// src/live-daemon-entry.ts
|
|
9
10
|
var baseUrl = process.env.PUBBLUE_DAEMON_BASE_URL;
|
|
10
11
|
var apiKey = process.env.PUBBLUE_DAEMON_API_KEY;
|
|
11
12
|
var socketPath = process.env.PUBBLUE_DAEMON_SOCKET;
|
|
@@ -20,8 +21,7 @@ if (!baseUrl || !apiKey || !socketPath || !infoPath) {
|
|
|
20
21
|
var apiClient = new PubApiClient(baseUrl, apiKey);
|
|
21
22
|
void startDaemon({ apiClient, socketPath, infoPath, cliVersion, bridgeMode, agentName }).catch(
|
|
22
23
|
(error) => {
|
|
23
|
-
|
|
24
|
-
console.error(`Daemon failed to start: ${message}`);
|
|
24
|
+
console.error(`Daemon failed to start: ${errorMessage(error)}`);
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
);
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pubblue",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "CLI tool for publishing content and running interactive sessions via pub.blue",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"pubblue": "./dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "tsup src/index.ts src/
|
|
11
|
-
"dev": "tsup src/index.ts src/
|
|
10
|
+
"build": "tsup src/index.ts src/live-daemon-entry.ts --format esm --dts --clean",
|
|
11
|
+
"dev": "tsup src/index.ts src/live-daemon-entry.ts --format esm --watch",
|
|
12
12
|
"test": "vitest run",
|
|
13
13
|
"test:watch": "vitest",
|
|
14
14
|
"lint": "tsc --noEmit"
|
|
File without changes
|