viveworker 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/package.json +16 -2
- package/scripts/a2a-cli.mjs +189 -0
- package/scripts/a2a-executor.mjs +126 -0
- package/scripts/a2a-handler.mjs +439 -0
- package/scripts/a2a-relay-client.mjs +394 -0
- package/scripts/com.viveworker.moltbook-scout.plist.sample +58 -0
- package/scripts/moltbook-api.mjs +206 -0
- package/scripts/moltbook-cli.mjs +1372 -0
- package/scripts/moltbook-scout-auto.sh +447 -0
- package/scripts/moltbook-scout-run.sh +14 -0
- package/scripts/moltbook-watcher.mjs +294 -0
- package/scripts/viveworker-bridge.mjs +814 -16
- package/scripts/viveworker-claude-hook.mjs +7 -1
- package/scripts/viveworker.mjs +314 -1
- package/web/app.css +104 -3
- package/web/app.js +445 -28
- package/web/i18n.js +90 -0
- package/web/sw.js +1 -1
|
@@ -181,7 +181,13 @@ async function handlePermissionRequest() {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
const result = await postEvent("PermissionRequest", body, APPROVAL_TIMEOUT_MS);
|
|
184
|
-
|
|
184
|
+
// If the bridge is unreachable, postEvent resolves to {} with no
|
|
185
|
+
// permissionDecision field. Distinguish that from an explicit deny and
|
|
186
|
+
// fall back to Claude Code's default permission flow instead of blocking.
|
|
187
|
+
if (!result || typeof result.permissionDecision !== "string") {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const behavior = result.permissionDecision === "allow" ? "allow" : "deny";
|
|
185
191
|
const reason = typeof result?.permissionDecisionReason === "string" ? result.permissionDecisionReason : "";
|
|
186
192
|
|
|
187
193
|
const decision = { behavior };
|
package/scripts/viveworker.mjs
CHANGED
|
@@ -27,7 +27,33 @@ const defaultLabel = "io.viveworker.app";
|
|
|
27
27
|
const defaultTlsDir = path.join(defaultConfigDir, "tls");
|
|
28
28
|
const defaultServerPort = 8810;
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const rawArgs = process.argv.slice(2);
|
|
31
|
+
|
|
32
|
+
// `viveworker moltbook <cmd> ...` bypasses the strict parseArgs so that
|
|
33
|
+
// free-form flags like `--text "hello"` reach the Moltbook CLI untouched.
|
|
34
|
+
if (rawArgs[0] === "moltbook") {
|
|
35
|
+
const { runMoltbookCli } = await import("./moltbook-cli.mjs");
|
|
36
|
+
try {
|
|
37
|
+
await runMoltbookCli(rawArgs.slice(1));
|
|
38
|
+
process.exit(0);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(error.message || String(error));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (rawArgs[0] === "a2a") {
|
|
46
|
+
const { runA2ACli } = await import("./a2a-cli.mjs");
|
|
47
|
+
try {
|
|
48
|
+
await runA2ACli(rawArgs.slice(1));
|
|
49
|
+
process.exit(0);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(error.message || String(error));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const cli = parseArgs(rawArgs);
|
|
31
57
|
|
|
32
58
|
try {
|
|
33
59
|
await main(cli);
|
|
@@ -300,6 +326,254 @@ async function runSetup(cliOptions) {
|
|
|
300
326
|
console.log("");
|
|
301
327
|
console.log(t(locale, "cli.setup.claudeHooksSkipped"));
|
|
302
328
|
}
|
|
329
|
+
|
|
330
|
+
if (cliOptions.moltbook) {
|
|
331
|
+
try {
|
|
332
|
+
await installMoltbookWatcher({ cliOptions, sessionSecret, port });
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.log("");
|
|
335
|
+
console.log(`Moltbook watcher install failed: ${error.message}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (cliOptions.autoScoutUninstall) {
|
|
340
|
+
await uninstallMoltbookScout();
|
|
341
|
+
} else if (cliOptions.autoScout) {
|
|
342
|
+
try {
|
|
343
|
+
await installMoltbookScout({ cliOptions });
|
|
344
|
+
} catch (error) {
|
|
345
|
+
console.log("");
|
|
346
|
+
console.log(`Moltbook auto-scout install failed: ${error.message}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async function detectScoutHarness(preferred) {
|
|
352
|
+
const { spawn } = await import("node:child_process");
|
|
353
|
+
const which = (cmd) =>
|
|
354
|
+
new Promise((resolve) => {
|
|
355
|
+
const p = spawn("command", ["-v", cmd], { shell: "/bin/bash", stdio: ["ignore", "pipe", "ignore"] });
|
|
356
|
+
let out = "";
|
|
357
|
+
p.stdout.on("data", (d) => (out += d.toString()));
|
|
358
|
+
p.on("exit", (code) => resolve(code === 0 ? out.trim() : ""));
|
|
359
|
+
p.on("error", () => resolve(""));
|
|
360
|
+
});
|
|
361
|
+
if (preferred === "codex") return { kind: "codex", bin: (await which("codex")) || "codex" };
|
|
362
|
+
if (preferred === "claude") return { kind: "claude", bin: (await which("claude")) || "claude" };
|
|
363
|
+
if (preferred === "manual") return { kind: "manual", bin: "" };
|
|
364
|
+
const codex = await which("codex");
|
|
365
|
+
if (codex) return { kind: "codex", bin: codex };
|
|
366
|
+
const claude = await which("claude");
|
|
367
|
+
if (claude) return { kind: "claude", bin: claude };
|
|
368
|
+
return { kind: "manual", bin: "" };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async function uninstallMoltbookScout() {
|
|
372
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${"com.viveworker.moltbook-scout"}.plist`);
|
|
373
|
+
const { spawn } = await import("node:child_process");
|
|
374
|
+
await new Promise((resolve) => {
|
|
375
|
+
const p = spawn("launchctl", ["bootout", `gui/${process.getuid()}`, plistPath], { stdio: "ignore" });
|
|
376
|
+
p.on("exit", () => resolve());
|
|
377
|
+
p.on("error", () => resolve());
|
|
378
|
+
});
|
|
379
|
+
try {
|
|
380
|
+
await fs.unlink(plistPath);
|
|
381
|
+
console.log("");
|
|
382
|
+
console.log(`Moltbook auto-scout uninstalled (removed ${plistPath}).`);
|
|
383
|
+
} catch {
|
|
384
|
+
console.log("");
|
|
385
|
+
console.log(`No auto-scout plist found at ${plistPath}.`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function installMoltbookScout({ cliOptions }) {
|
|
390
|
+
const moltbookEnvFile = path.join(os.homedir(), ".viveworker", "moltbook.env");
|
|
391
|
+
try {
|
|
392
|
+
await fs.access(moltbookEnvFile);
|
|
393
|
+
} catch {
|
|
394
|
+
throw new Error(
|
|
395
|
+
`${moltbookEnvFile} not found. Run --moltbook --moltbook-api-key ... --moltbook-agent-id ... first.`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
const harness = await detectScoutHarness(cliOptions.autoScoutHarness || "auto");
|
|
399
|
+
const interval = Number(cliOptions.autoScoutInterval) || 120;
|
|
400
|
+
const scoutRunScript = path.join(packageRoot, "scripts", "moltbook-scout-run.sh");
|
|
401
|
+
const viveworkerJs = path.join(packageRoot, "scripts", "viveworker.mjs");
|
|
402
|
+
const submoltsFlag = cliOptions.autoScoutSubmolts
|
|
403
|
+
? ` --submolts ${cliOptions.autoScoutSubmolts}`
|
|
404
|
+
: "";
|
|
405
|
+
const maxDailyFlag = cliOptions.autoScoutMaxDaily
|
|
406
|
+
? ` --max-daily ${cliOptions.autoScoutMaxDaily}`
|
|
407
|
+
: "";
|
|
408
|
+
|
|
409
|
+
const personaPath = path.join(os.homedir(), ".viveworker", "moltbook-persona.md");
|
|
410
|
+
let hasPersona = false;
|
|
411
|
+
try {
|
|
412
|
+
const personaText = await fs.readFile(personaPath, "utf8");
|
|
413
|
+
hasPersona = Boolean(personaText.trim());
|
|
414
|
+
} catch {
|
|
415
|
+
// no persona file
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Ensure node (and harness CLI) is on PATH inside launchd's minimal env.
|
|
419
|
+
const nodeBinDir = path.dirname(process.execPath);
|
|
420
|
+
const pathPrefix = `export PATH="${nodeBinDir}:$PATH"`;
|
|
421
|
+
const autoScript = path.join(packageRoot, "scripts", "moltbook-scout-auto.sh");
|
|
422
|
+
|
|
423
|
+
let inner;
|
|
424
|
+
if (harness.kind === "manual") {
|
|
425
|
+
// Manual fallback: just run scout and log the candidate. No drafting.
|
|
426
|
+
inner =
|
|
427
|
+
`${pathPrefix}; set -a; . "${moltbookEnvFile}"; set +a; cd "${packageRoot}" && ` +
|
|
428
|
+
`"${scoutRunScript}"${submoltsFlag}${maxDailyFlag} || true`;
|
|
429
|
+
} else {
|
|
430
|
+
// Use the auto script which runs scout (no LLM), then drafts via harness, then proposes.
|
|
431
|
+
const envVars = [
|
|
432
|
+
`SCOUT_HARNESS=${harness.kind}`,
|
|
433
|
+
submoltsFlag ? `SCOUT_FLAGS="${submoltsFlag.trim()}${maxDailyFlag}"` : maxDailyFlag ? `SCOUT_FLAGS="${maxDailyFlag.trim()}"` : "",
|
|
434
|
+
].filter(Boolean).join(" ");
|
|
435
|
+
inner =
|
|
436
|
+
`${pathPrefix}; set -a; . "${moltbookEnvFile}"; set +a; ${envVars ? envVars + " " : ""}` +
|
|
437
|
+
`"${autoScript}"`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const userShell = process.env.SHELL || "/bin/zsh";
|
|
441
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${"com.viveworker.moltbook-scout"}.plist`);
|
|
442
|
+
const plistBody = `<?xml version="1.0" encoding="UTF-8"?>
|
|
443
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
444
|
+
<plist version="1.0">
|
|
445
|
+
<dict>
|
|
446
|
+
<key>Label</key><string>${"com.viveworker.moltbook-scout"}</string>
|
|
447
|
+
<key>ProgramArguments</key>
|
|
448
|
+
<array>
|
|
449
|
+
<string>${escapeXml(userShell)}</string>
|
|
450
|
+
<string>-lc</string>
|
|
451
|
+
<string>${escapeXml(inner)}</string>
|
|
452
|
+
</array>
|
|
453
|
+
<key>StartInterval</key><integer>${interval}</integer>
|
|
454
|
+
<key>RunAtLoad</key><false/>
|
|
455
|
+
<key>StandardOutPath</key><string>/tmp/viveworker-moltbook-scout.out.log</string>
|
|
456
|
+
<key>StandardErrorPath</key><string>/tmp/viveworker-moltbook-scout.err.log</string>
|
|
457
|
+
<key>ProcessType</key><string>Background</string>
|
|
458
|
+
</dict>
|
|
459
|
+
</plist>
|
|
460
|
+
`;
|
|
461
|
+
await fs.mkdir(path.dirname(plistPath), { recursive: true });
|
|
462
|
+
await fs.writeFile(plistPath, plistBody, "utf8");
|
|
463
|
+
|
|
464
|
+
const { spawn } = await import("node:child_process");
|
|
465
|
+
await new Promise((resolve) => {
|
|
466
|
+
const p = spawn("launchctl", ["bootout", `gui/${process.getuid()}`, plistPath], { stdio: "ignore" });
|
|
467
|
+
p.on("exit", () => resolve());
|
|
468
|
+
p.on("error", () => resolve());
|
|
469
|
+
});
|
|
470
|
+
try {
|
|
471
|
+
await new Promise((resolve, reject) => {
|
|
472
|
+
const p = spawn("launchctl", ["bootstrap", `gui/${process.getuid()}`, plistPath], { stdio: "ignore" });
|
|
473
|
+
p.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`launchctl bootstrap exited ${code}`))));
|
|
474
|
+
p.on("error", reject);
|
|
475
|
+
});
|
|
476
|
+
} catch (error) {
|
|
477
|
+
console.log("");
|
|
478
|
+
console.log(`Moltbook scout plist written but launchctl bootstrap failed: ${error.message}`);
|
|
479
|
+
console.log(`Run manually: launchctl bootstrap gui/$(id -u) ${plistPath}`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
console.log("");
|
|
483
|
+
console.log(`Moltbook auto-scout installed (${harness.kind}).`);
|
|
484
|
+
console.log(` plist: ${plistPath}`);
|
|
485
|
+
console.log(` interval: ${interval}s`);
|
|
486
|
+
if (harness.kind === "manual") {
|
|
487
|
+
console.log(
|
|
488
|
+
` note: Neither 'codex' nor 'claude' CLI was found. The scheduled task will only run scout and print candidates to the log. Install Codex CLI (npm i -g @openai/codex) or Claude Code CLI to enable automated drafting.`
|
|
489
|
+
);
|
|
490
|
+
} else {
|
|
491
|
+
console.log(` harness: ${harness.bin}`);
|
|
492
|
+
}
|
|
493
|
+
console.log(` logs: /tmp/viveworker-moltbook-scout.{out,err}.log`);
|
|
494
|
+
if (!hasPersona) {
|
|
495
|
+
console.log(
|
|
496
|
+
` tip: No persona file found. Run 'npx viveworker moltbook persona init' to describe your agent — draft quality improves a lot.`
|
|
497
|
+
);
|
|
498
|
+
} else {
|
|
499
|
+
console.log(` persona: ${personaPath}`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
async function installMoltbookWatcher({ cliOptions, sessionSecret, port }) {
|
|
504
|
+
if (!cliOptions.moltbookApiKey || !cliOptions.moltbookAgentId) {
|
|
505
|
+
throw new Error(
|
|
506
|
+
"--moltbook requires --moltbook-api-key and --moltbook-agent-id"
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
const moltbookDir = path.join(os.homedir(), ".viveworker");
|
|
510
|
+
const moltbookEnvFile = path.join(moltbookDir, "moltbook.env");
|
|
511
|
+
await fs.mkdir(moltbookDir, { recursive: true });
|
|
512
|
+
const envLines = [
|
|
513
|
+
`MOLTBOOK_API_KEY=${cliOptions.moltbookApiKey}`,
|
|
514
|
+
`MOLTBOOK_AGENT_ID=${cliOptions.moltbookAgentId}`,
|
|
515
|
+
cliOptions.moltbookAgentName ? `MOLTBOOK_AGENT_NAME=${cliOptions.moltbookAgentName}` : "",
|
|
516
|
+
`VIVEWORKER_HOOK_SECRET=${sessionSecret}`,
|
|
517
|
+
`VIVEWORKER_BASE_URL=https://127.0.0.1:${port}`,
|
|
518
|
+
"",
|
|
519
|
+
].filter((line) => line !== null);
|
|
520
|
+
await fs.writeFile(moltbookEnvFile, envLines.join("\n"), { mode: 0o600 });
|
|
521
|
+
await fs.chmod(moltbookEnvFile, 0o600);
|
|
522
|
+
|
|
523
|
+
const plistLabel = "com.viveworker.moltbook-watcher";
|
|
524
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${plistLabel}.plist`);
|
|
525
|
+
const watcherScript = path.join(packageRoot, "scripts", "moltbook-watcher.mjs");
|
|
526
|
+
const nodePath = process.execPath;
|
|
527
|
+
const watcherShell = process.env.SHELL || "/bin/zsh";
|
|
528
|
+
const watcherNodeDir = path.dirname(nodePath);
|
|
529
|
+
const plistBody = `<?xml version="1.0" encoding="UTF-8"?>
|
|
530
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
531
|
+
<plist version="1.0">
|
|
532
|
+
<dict>
|
|
533
|
+
<key>Label</key><string>${plistLabel}</string>
|
|
534
|
+
<key>ProgramArguments</key>
|
|
535
|
+
<array>
|
|
536
|
+
<string>${escapeXml(watcherShell)}</string>
|
|
537
|
+
<string>-lc</string>
|
|
538
|
+
<string>export PATH="${watcherNodeDir}:$PATH"; set -a; . "${moltbookEnvFile}"; set +a; exec "${nodePath}" "${watcherScript}"</string>
|
|
539
|
+
</array>
|
|
540
|
+
<key>RunAtLoad</key><true/>
|
|
541
|
+
<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/><key>Crashed</key><true/></dict>
|
|
542
|
+
<key>ThrottleInterval</key><integer>30</integer>
|
|
543
|
+
<key>StandardOutPath</key><string>/tmp/viveworker-moltbook-watcher.out.log</string>
|
|
544
|
+
<key>StandardErrorPath</key><string>/tmp/viveworker-moltbook-watcher.err.log</string>
|
|
545
|
+
<key>ProcessType</key><string>Background</string>
|
|
546
|
+
</dict>
|
|
547
|
+
</plist>
|
|
548
|
+
`;
|
|
549
|
+
await fs.mkdir(path.dirname(plistPath), { recursive: true });
|
|
550
|
+
await fs.writeFile(plistPath, plistBody, "utf8");
|
|
551
|
+
|
|
552
|
+
// Reload the agent if launchctl is available
|
|
553
|
+
try {
|
|
554
|
+
const { spawn } = await import("node:child_process");
|
|
555
|
+
await new Promise((resolve) => {
|
|
556
|
+
const unload = spawn("launchctl", ["unload", plistPath], { stdio: "ignore" });
|
|
557
|
+
unload.on("exit", () => resolve());
|
|
558
|
+
unload.on("error", () => resolve());
|
|
559
|
+
});
|
|
560
|
+
await new Promise((resolve, reject) => {
|
|
561
|
+
const load = spawn("launchctl", ["load", plistPath], { stdio: "ignore" });
|
|
562
|
+
load.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`launchctl load exited ${code}`))));
|
|
563
|
+
load.on("error", reject);
|
|
564
|
+
});
|
|
565
|
+
} catch (error) {
|
|
566
|
+
console.log("");
|
|
567
|
+
console.log(`Moltbook watcher plist written but launchctl load failed: ${error.message}`);
|
|
568
|
+
console.log(`Run manually: launchctl load ${plistPath}`);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
console.log("");
|
|
573
|
+
console.log(`Moltbook watcher installed.`);
|
|
574
|
+
console.log(` env: ${moltbookEnvFile}`);
|
|
575
|
+
console.log(` plist: ${plistPath}`);
|
|
576
|
+
console.log(` logs: /tmp/viveworker-moltbook-watcher.{out,err}.log`);
|
|
303
577
|
}
|
|
304
578
|
|
|
305
579
|
async function installClaudeHooks({ envFile, claudeSettingsFile, sessionSecret }) {
|
|
@@ -601,6 +875,16 @@ function parseArgs(argv) {
|
|
|
601
875
|
locale: "",
|
|
602
876
|
mkcertTrustStores: "",
|
|
603
877
|
claudeSettingsFile: "",
|
|
878
|
+
moltbook: false,
|
|
879
|
+
moltbookApiKey: "",
|
|
880
|
+
moltbookAgentId: "",
|
|
881
|
+
moltbookAgentName: "",
|
|
882
|
+
autoScout: false,
|
|
883
|
+
autoScoutUninstall: false,
|
|
884
|
+
autoScoutInterval: 120,
|
|
885
|
+
autoScoutHarness: "auto",
|
|
886
|
+
autoScoutSubmolts: "",
|
|
887
|
+
autoScoutMaxDaily: 0,
|
|
604
888
|
};
|
|
605
889
|
|
|
606
890
|
if (argv[0] && !argv[0].startsWith("-")) {
|
|
@@ -682,6 +966,35 @@ function parseArgs(argv) {
|
|
|
682
966
|
} else if (arg === "--claude-settings-file") {
|
|
683
967
|
parsed.claudeSettingsFile = next;
|
|
684
968
|
index += 1;
|
|
969
|
+
} else if (arg === "--moltbook") {
|
|
970
|
+
parsed.moltbook = true;
|
|
971
|
+
} else if (arg === "--moltbook-api-key") {
|
|
972
|
+
parsed.moltbook = true;
|
|
973
|
+
parsed.moltbookApiKey = next;
|
|
974
|
+
index += 1;
|
|
975
|
+
} else if (arg === "--moltbook-agent-id") {
|
|
976
|
+
parsed.moltbook = true;
|
|
977
|
+
parsed.moltbookAgentId = next;
|
|
978
|
+
index += 1;
|
|
979
|
+
} else if (arg === "--moltbook-agent-name") {
|
|
980
|
+
parsed.moltbookAgentName = next;
|
|
981
|
+
index += 1;
|
|
982
|
+
} else if (arg === "--auto-scout") {
|
|
983
|
+
parsed.autoScout = true;
|
|
984
|
+
} else if (arg === "--auto-scout-uninstall") {
|
|
985
|
+
parsed.autoScoutUninstall = true;
|
|
986
|
+
} else if (arg === "--auto-scout-interval") {
|
|
987
|
+
parsed.autoScoutInterval = Number(next) || 120;
|
|
988
|
+
index += 1;
|
|
989
|
+
} else if (arg === "--auto-scout-harness") {
|
|
990
|
+
parsed.autoScoutHarness = next;
|
|
991
|
+
index += 1;
|
|
992
|
+
} else if (arg === "--auto-scout-submolts") {
|
|
993
|
+
parsed.autoScoutSubmolts = next;
|
|
994
|
+
index += 1;
|
|
995
|
+
} else if (arg === "--auto-scout-max-daily") {
|
|
996
|
+
parsed.autoScoutMaxDaily = Number(next) || 0;
|
|
997
|
+
index += 1;
|
|
685
998
|
} else if (arg === "--help" || arg === "-h") {
|
|
686
999
|
parsed.command = "help";
|
|
687
1000
|
} else {
|
package/web/app.css
CHANGED
|
@@ -1932,7 +1932,7 @@ code {
|
|
|
1932
1932
|
|
|
1933
1933
|
.detail-page-copy--approval {
|
|
1934
1934
|
margin: 0.78rem 0 0.48rem;
|
|
1935
|
-
padding: 0.
|
|
1935
|
+
padding: 0.25rem 0.4rem;
|
|
1936
1936
|
display: grid;
|
|
1937
1937
|
gap: 0;
|
|
1938
1938
|
line-height: 1.24;
|
|
@@ -2259,6 +2259,7 @@ code {
|
|
|
2259
2259
|
|
|
2260
2260
|
.reply-composer__description {
|
|
2261
2261
|
margin: 0;
|
|
2262
|
+
padding: 0.75rem 1rem;
|
|
2262
2263
|
}
|
|
2263
2264
|
|
|
2264
2265
|
.reply-composer__form {
|
|
@@ -2266,6 +2267,94 @@ code {
|
|
|
2266
2267
|
gap: 0.8rem;
|
|
2267
2268
|
}
|
|
2268
2269
|
|
|
2270
|
+
.reply-composer__context {
|
|
2271
|
+
margin: 0.4rem 0;
|
|
2272
|
+
padding: 0.6rem 0.75rem;
|
|
2273
|
+
border-radius: 12px;
|
|
2274
|
+
background: rgba(255, 255, 255, 0.03);
|
|
2275
|
+
border: 1px solid var(--line);
|
|
2276
|
+
font-size: 0.9rem;
|
|
2277
|
+
}
|
|
2278
|
+
.reply-composer__context summary {
|
|
2279
|
+
cursor: pointer;
|
|
2280
|
+
color: var(--muted);
|
|
2281
|
+
}
|
|
2282
|
+
.reply-composer__context-body {
|
|
2283
|
+
margin-top: 0.5rem;
|
|
2284
|
+
line-height: 1.55;
|
|
2285
|
+
color: var(--text);
|
|
2286
|
+
}
|
|
2287
|
+
.reply-composer__intent {
|
|
2288
|
+
margin: 0.5rem 0;
|
|
2289
|
+
padding: 0.6rem 0.75rem;
|
|
2290
|
+
border-radius: 12px;
|
|
2291
|
+
background: rgba(110, 168, 255, 0.08);
|
|
2292
|
+
border: 1px solid rgba(110, 168, 255, 0.25);
|
|
2293
|
+
}
|
|
2294
|
+
.reply-composer__intent p {
|
|
2295
|
+
margin: 0.35rem 0 0;
|
|
2296
|
+
line-height: 1.5;
|
|
2297
|
+
}
|
|
2298
|
+
.reply-composer__author-meta {
|
|
2299
|
+
margin: 0.1rem 0 0.4rem;
|
|
2300
|
+
font-size: 0.85rem;
|
|
2301
|
+
}
|
|
2302
|
+
.reply-composer__textarea {
|
|
2303
|
+
width: 100%;
|
|
2304
|
+
min-height: 14rem;
|
|
2305
|
+
padding: 0.85rem 0.95rem;
|
|
2306
|
+
border-radius: 14px;
|
|
2307
|
+
border: 1px solid var(--line);
|
|
2308
|
+
background: rgba(7, 12, 16, 0.96);
|
|
2309
|
+
color: var(--text);
|
|
2310
|
+
font: inherit;
|
|
2311
|
+
font-size: 1rem;
|
|
2312
|
+
line-height: 1.55;
|
|
2313
|
+
resize: vertical;
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
.reply-composer__textarea:focus {
|
|
2317
|
+
outline: none;
|
|
2318
|
+
border-color: var(--accent, #6ea8ff);
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
.compose-greeting {
|
|
2322
|
+
display: flex;
|
|
2323
|
+
align-items: center;
|
|
2324
|
+
gap: 0.55rem;
|
|
2325
|
+
margin: 0.6rem 0 0.4rem;
|
|
2326
|
+
padding: 0.65rem 0.85rem;
|
|
2327
|
+
border-radius: 12px;
|
|
2328
|
+
border-left: 3px solid var(--completion, #d2aa63);
|
|
2329
|
+
background: rgba(210, 170, 99, 0.10);
|
|
2330
|
+
}
|
|
2331
|
+
.compose-greeting__icon {
|
|
2332
|
+
font-size: 1.25rem;
|
|
2333
|
+
line-height: 1;
|
|
2334
|
+
}
|
|
2335
|
+
.compose-greeting__text {
|
|
2336
|
+
font-size: 0.92rem;
|
|
2337
|
+
color: var(--text);
|
|
2338
|
+
font-weight: 500;
|
|
2339
|
+
}
|
|
2340
|
+
.reply-field--title {
|
|
2341
|
+
margin-bottom: 0.5rem;
|
|
2342
|
+
}
|
|
2343
|
+
.reply-field--title .reply-field__input {
|
|
2344
|
+
min-height: auto;
|
|
2345
|
+
padding: 0.65rem 0.85rem;
|
|
2346
|
+
border: 1px solid var(--line);
|
|
2347
|
+
border-radius: 12px;
|
|
2348
|
+
background: rgba(7, 12, 16, 0.96);
|
|
2349
|
+
font-size: 1.05rem;
|
|
2350
|
+
font-weight: 700;
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
.reply-composer__title-display {
|
|
2354
|
+
margin: 0.25rem 0 0.5rem;
|
|
2355
|
+
font-size: 1.05rem;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2269
2358
|
.reply-field {
|
|
2270
2359
|
gap: 0.5rem;
|
|
2271
2360
|
}
|
|
@@ -3347,6 +3436,14 @@ button[data-action-url][aria-busy="true"]:not(.is-loading) {
|
|
|
3347
3436
|
color: #f5a45a;
|
|
3348
3437
|
background: rgba(245, 164, 90, 0.1);
|
|
3349
3438
|
}
|
|
3439
|
+
.provider-badge--moltbook {
|
|
3440
|
+
color: #e07a5f;
|
|
3441
|
+
background: rgba(224, 122, 95, 0.12);
|
|
3442
|
+
}
|
|
3443
|
+
.provider-badge--a2a {
|
|
3444
|
+
color: #81c784;
|
|
3445
|
+
background: rgba(129, 199, 132, 0.12);
|
|
3446
|
+
}
|
|
3350
3447
|
|
|
3351
3448
|
.provider-filter {
|
|
3352
3449
|
display: inline-flex;
|
|
@@ -3357,18 +3454,22 @@ button[data-action-url][aria-busy="true"]:not(.is-loading) {
|
|
|
3357
3454
|
background: rgba(255, 255, 255, 0.04);
|
|
3358
3455
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
3359
3456
|
border-radius: 999px;
|
|
3360
|
-
width:
|
|
3457
|
+
max-width: 100%;
|
|
3458
|
+
overflow-x: auto;
|
|
3459
|
+
-webkit-overflow-scrolling: touch;
|
|
3361
3460
|
}
|
|
3362
3461
|
.provider-filter__button {
|
|
3363
3462
|
appearance: none;
|
|
3364
3463
|
background: transparent;
|
|
3365
3464
|
color: var(--text-muted, #9aa6b2);
|
|
3366
3465
|
border: 0;
|
|
3367
|
-
padding: 0.3rem 0.
|
|
3466
|
+
padding: 0.3rem 0.65rem;
|
|
3368
3467
|
font-size: 0.78rem;
|
|
3369
3468
|
font-weight: 600;
|
|
3370
3469
|
border-radius: 999px;
|
|
3371
3470
|
cursor: pointer;
|
|
3471
|
+
white-space: nowrap;
|
|
3472
|
+
flex-shrink: 0;
|
|
3372
3473
|
transition: background 0.15s ease, color 0.15s ease;
|
|
3373
3474
|
}
|
|
3374
3475
|
.provider-filter__button:hover {
|