viveworker 0.2.1 → 0.3.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 +41 -0
- package/package.json +6 -1
- package/scripts/com.viveworker.moltbook-scout.plist.sample +58 -0
- package/scripts/moltbook-api.mjs +201 -0
- package/scripts/moltbook-cli.mjs +1302 -0
- package/scripts/moltbook-scout-run.sh +14 -0
- package/scripts/moltbook-watcher.mjs +294 -0
- package/scripts/viveworker-bridge.mjs +548 -12
- package/scripts/viveworker-claude-hook.mjs +7 -1
- package/scripts/viveworker.mjs +303 -1
- package/web/app.css +75 -1
- package/web/app.js +298 -25
- package/web/i18n.js +54 -0
- package/web/sw.js +1 -1
package/scripts/viveworker.mjs
CHANGED
|
@@ -27,7 +27,22 @@ 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
|
+
const cli = parseArgs(rawArgs);
|
|
31
46
|
|
|
32
47
|
try {
|
|
33
48
|
await main(cli);
|
|
@@ -300,6 +315,254 @@ async function runSetup(cliOptions) {
|
|
|
300
315
|
console.log("");
|
|
301
316
|
console.log(t(locale, "cli.setup.claudeHooksSkipped"));
|
|
302
317
|
}
|
|
318
|
+
|
|
319
|
+
if (cliOptions.moltbook) {
|
|
320
|
+
try {
|
|
321
|
+
await installMoltbookWatcher({ cliOptions, sessionSecret, port });
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.log("");
|
|
324
|
+
console.log(`Moltbook watcher install failed: ${error.message}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (cliOptions.autoScoutUninstall) {
|
|
329
|
+
await uninstallMoltbookScout();
|
|
330
|
+
} else if (cliOptions.autoScout) {
|
|
331
|
+
try {
|
|
332
|
+
await installMoltbookScout({ cliOptions });
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.log("");
|
|
335
|
+
console.log(`Moltbook auto-scout install failed: ${error.message}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function detectScoutHarness(preferred) {
|
|
341
|
+
const { spawn } = await import("node:child_process");
|
|
342
|
+
const which = (cmd) =>
|
|
343
|
+
new Promise((resolve) => {
|
|
344
|
+
const p = spawn("command", ["-v", cmd], { shell: "/bin/bash", stdio: ["ignore", "pipe", "ignore"] });
|
|
345
|
+
let out = "";
|
|
346
|
+
p.stdout.on("data", (d) => (out += d.toString()));
|
|
347
|
+
p.on("exit", (code) => resolve(code === 0 ? out.trim() : ""));
|
|
348
|
+
p.on("error", () => resolve(""));
|
|
349
|
+
});
|
|
350
|
+
if (preferred === "codex") return { kind: "codex", bin: (await which("codex")) || "codex" };
|
|
351
|
+
if (preferred === "claude") return { kind: "claude", bin: (await which("claude")) || "claude" };
|
|
352
|
+
if (preferred === "manual") return { kind: "manual", bin: "" };
|
|
353
|
+
const codex = await which("codex");
|
|
354
|
+
if (codex) return { kind: "codex", bin: codex };
|
|
355
|
+
const claude = await which("claude");
|
|
356
|
+
if (claude) return { kind: "claude", bin: claude };
|
|
357
|
+
return { kind: "manual", bin: "" };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async function uninstallMoltbookScout() {
|
|
361
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${"com.viveworker.moltbook-scout"}.plist`);
|
|
362
|
+
const { spawn } = await import("node:child_process");
|
|
363
|
+
await new Promise((resolve) => {
|
|
364
|
+
const p = spawn("launchctl", ["bootout", `gui/${process.getuid()}`, plistPath], { stdio: "ignore" });
|
|
365
|
+
p.on("exit", () => resolve());
|
|
366
|
+
p.on("error", () => resolve());
|
|
367
|
+
});
|
|
368
|
+
try {
|
|
369
|
+
await fs.unlink(plistPath);
|
|
370
|
+
console.log("");
|
|
371
|
+
console.log(`Moltbook auto-scout uninstalled (removed ${plistPath}).`);
|
|
372
|
+
} catch {
|
|
373
|
+
console.log("");
|
|
374
|
+
console.log(`No auto-scout plist found at ${plistPath}.`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async function installMoltbookScout({ cliOptions }) {
|
|
379
|
+
const moltbookEnvFile = path.join(os.homedir(), ".viveworker", "moltbook.env");
|
|
380
|
+
try {
|
|
381
|
+
await fs.access(moltbookEnvFile);
|
|
382
|
+
} catch {
|
|
383
|
+
throw new Error(
|
|
384
|
+
`${moltbookEnvFile} not found. Run --moltbook --moltbook-api-key ... --moltbook-agent-id ... first.`
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
const harness = await detectScoutHarness(cliOptions.autoScoutHarness || "auto");
|
|
388
|
+
const interval = Number(cliOptions.autoScoutInterval) || 120;
|
|
389
|
+
const scoutRunScript = path.join(packageRoot, "scripts", "moltbook-scout-run.sh");
|
|
390
|
+
const viveworkerJs = path.join(packageRoot, "scripts", "viveworker.mjs");
|
|
391
|
+
const submoltsFlag = cliOptions.autoScoutSubmolts
|
|
392
|
+
? ` --submolts ${cliOptions.autoScoutSubmolts}`
|
|
393
|
+
: "";
|
|
394
|
+
const maxDailyFlag = cliOptions.autoScoutMaxDaily
|
|
395
|
+
? ` --max-daily ${cliOptions.autoScoutMaxDaily}`
|
|
396
|
+
: "";
|
|
397
|
+
|
|
398
|
+
const personaPath = path.join(os.homedir(), ".viveworker", "moltbook-persona.md");
|
|
399
|
+
let hasPersona = false;
|
|
400
|
+
try {
|
|
401
|
+
const personaText = await fs.readFile(personaPath, "utf8");
|
|
402
|
+
hasPersona = Boolean(personaText.trim());
|
|
403
|
+
} catch {
|
|
404
|
+
// no persona file
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Ensure node (and harness CLI) is on PATH inside launchd's minimal env.
|
|
408
|
+
const nodeBinDir = path.dirname(process.execPath);
|
|
409
|
+
const pathPrefix = `export PATH="${nodeBinDir}:$PATH"`;
|
|
410
|
+
const autoScript = path.join(packageRoot, "scripts", "moltbook-scout-auto.sh");
|
|
411
|
+
|
|
412
|
+
let inner;
|
|
413
|
+
if (harness.kind === "manual") {
|
|
414
|
+
// Manual fallback: just run scout and log the candidate. No drafting.
|
|
415
|
+
inner =
|
|
416
|
+
`${pathPrefix}; set -a; . "${moltbookEnvFile}"; set +a; cd "${packageRoot}" && ` +
|
|
417
|
+
`"${scoutRunScript}"${submoltsFlag}${maxDailyFlag} || true`;
|
|
418
|
+
} else {
|
|
419
|
+
// Use the auto script which runs scout (no LLM), then drafts via harness, then proposes.
|
|
420
|
+
const envVars = [
|
|
421
|
+
`SCOUT_HARNESS=${harness.kind}`,
|
|
422
|
+
submoltsFlag ? `SCOUT_FLAGS="${submoltsFlag.trim()}${maxDailyFlag}"` : maxDailyFlag ? `SCOUT_FLAGS="${maxDailyFlag.trim()}"` : "",
|
|
423
|
+
].filter(Boolean).join(" ");
|
|
424
|
+
inner =
|
|
425
|
+
`${pathPrefix}; set -a; . "${moltbookEnvFile}"; set +a; ${envVars ? envVars + " " : ""}` +
|
|
426
|
+
`"${autoScript}"`;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const userShell = process.env.SHELL || "/bin/zsh";
|
|
430
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${"com.viveworker.moltbook-scout"}.plist`);
|
|
431
|
+
const plistBody = `<?xml version="1.0" encoding="UTF-8"?>
|
|
432
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
433
|
+
<plist version="1.0">
|
|
434
|
+
<dict>
|
|
435
|
+
<key>Label</key><string>${"com.viveworker.moltbook-scout"}</string>
|
|
436
|
+
<key>ProgramArguments</key>
|
|
437
|
+
<array>
|
|
438
|
+
<string>${escapeXml(userShell)}</string>
|
|
439
|
+
<string>-lc</string>
|
|
440
|
+
<string>${escapeXml(inner)}</string>
|
|
441
|
+
</array>
|
|
442
|
+
<key>StartInterval</key><integer>${interval}</integer>
|
|
443
|
+
<key>RunAtLoad</key><false/>
|
|
444
|
+
<key>StandardOutPath</key><string>/tmp/viveworker-moltbook-scout.out.log</string>
|
|
445
|
+
<key>StandardErrorPath</key><string>/tmp/viveworker-moltbook-scout.err.log</string>
|
|
446
|
+
<key>ProcessType</key><string>Background</string>
|
|
447
|
+
</dict>
|
|
448
|
+
</plist>
|
|
449
|
+
`;
|
|
450
|
+
await fs.mkdir(path.dirname(plistPath), { recursive: true });
|
|
451
|
+
await fs.writeFile(plistPath, plistBody, "utf8");
|
|
452
|
+
|
|
453
|
+
const { spawn } = await import("node:child_process");
|
|
454
|
+
await new Promise((resolve) => {
|
|
455
|
+
const p = spawn("launchctl", ["bootout", `gui/${process.getuid()}`, plistPath], { stdio: "ignore" });
|
|
456
|
+
p.on("exit", () => resolve());
|
|
457
|
+
p.on("error", () => resolve());
|
|
458
|
+
});
|
|
459
|
+
try {
|
|
460
|
+
await new Promise((resolve, reject) => {
|
|
461
|
+
const p = spawn("launchctl", ["bootstrap", `gui/${process.getuid()}`, plistPath], { stdio: "ignore" });
|
|
462
|
+
p.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`launchctl bootstrap exited ${code}`))));
|
|
463
|
+
p.on("error", reject);
|
|
464
|
+
});
|
|
465
|
+
} catch (error) {
|
|
466
|
+
console.log("");
|
|
467
|
+
console.log(`Moltbook scout plist written but launchctl bootstrap failed: ${error.message}`);
|
|
468
|
+
console.log(`Run manually: launchctl bootstrap gui/$(id -u) ${plistPath}`);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
console.log("");
|
|
472
|
+
console.log(`Moltbook auto-scout installed (${harness.kind}).`);
|
|
473
|
+
console.log(` plist: ${plistPath}`);
|
|
474
|
+
console.log(` interval: ${interval}s`);
|
|
475
|
+
if (harness.kind === "manual") {
|
|
476
|
+
console.log(
|
|
477
|
+
` 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.`
|
|
478
|
+
);
|
|
479
|
+
} else {
|
|
480
|
+
console.log(` harness: ${harness.bin}`);
|
|
481
|
+
}
|
|
482
|
+
console.log(` logs: /tmp/viveworker-moltbook-scout.{out,err}.log`);
|
|
483
|
+
if (!hasPersona) {
|
|
484
|
+
console.log(
|
|
485
|
+
` tip: No persona file found. Run 'npx viveworker moltbook persona init' to describe your agent — draft quality improves a lot.`
|
|
486
|
+
);
|
|
487
|
+
} else {
|
|
488
|
+
console.log(` persona: ${personaPath}`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async function installMoltbookWatcher({ cliOptions, sessionSecret, port }) {
|
|
493
|
+
if (!cliOptions.moltbookApiKey || !cliOptions.moltbookAgentId) {
|
|
494
|
+
throw new Error(
|
|
495
|
+
"--moltbook requires --moltbook-api-key and --moltbook-agent-id"
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
const moltbookDir = path.join(os.homedir(), ".viveworker");
|
|
499
|
+
const moltbookEnvFile = path.join(moltbookDir, "moltbook.env");
|
|
500
|
+
await fs.mkdir(moltbookDir, { recursive: true });
|
|
501
|
+
const envLines = [
|
|
502
|
+
`MOLTBOOK_API_KEY=${cliOptions.moltbookApiKey}`,
|
|
503
|
+
`MOLTBOOK_AGENT_ID=${cliOptions.moltbookAgentId}`,
|
|
504
|
+
cliOptions.moltbookAgentName ? `MOLTBOOK_AGENT_NAME=${cliOptions.moltbookAgentName}` : "",
|
|
505
|
+
`VIVEWORKER_HOOK_SECRET=${sessionSecret}`,
|
|
506
|
+
`VIVEWORKER_BASE_URL=https://127.0.0.1:${port}`,
|
|
507
|
+
"",
|
|
508
|
+
].filter((line) => line !== null);
|
|
509
|
+
await fs.writeFile(moltbookEnvFile, envLines.join("\n"), { mode: 0o600 });
|
|
510
|
+
await fs.chmod(moltbookEnvFile, 0o600);
|
|
511
|
+
|
|
512
|
+
const plistLabel = "com.viveworker.moltbook-watcher";
|
|
513
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${plistLabel}.plist`);
|
|
514
|
+
const watcherScript = path.join(packageRoot, "scripts", "moltbook-watcher.mjs");
|
|
515
|
+
const nodePath = process.execPath;
|
|
516
|
+
const watcherShell = process.env.SHELL || "/bin/zsh";
|
|
517
|
+
const watcherNodeDir = path.dirname(nodePath);
|
|
518
|
+
const plistBody = `<?xml version="1.0" encoding="UTF-8"?>
|
|
519
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
520
|
+
<plist version="1.0">
|
|
521
|
+
<dict>
|
|
522
|
+
<key>Label</key><string>${plistLabel}</string>
|
|
523
|
+
<key>ProgramArguments</key>
|
|
524
|
+
<array>
|
|
525
|
+
<string>${escapeXml(watcherShell)}</string>
|
|
526
|
+
<string>-lc</string>
|
|
527
|
+
<string>export PATH="${watcherNodeDir}:$PATH"; set -a; . "${moltbookEnvFile}"; set +a; exec "${nodePath}" "${watcherScript}"</string>
|
|
528
|
+
</array>
|
|
529
|
+
<key>RunAtLoad</key><true/>
|
|
530
|
+
<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/><key>Crashed</key><true/></dict>
|
|
531
|
+
<key>ThrottleInterval</key><integer>30</integer>
|
|
532
|
+
<key>StandardOutPath</key><string>/tmp/viveworker-moltbook-watcher.out.log</string>
|
|
533
|
+
<key>StandardErrorPath</key><string>/tmp/viveworker-moltbook-watcher.err.log</string>
|
|
534
|
+
<key>ProcessType</key><string>Background</string>
|
|
535
|
+
</dict>
|
|
536
|
+
</plist>
|
|
537
|
+
`;
|
|
538
|
+
await fs.mkdir(path.dirname(plistPath), { recursive: true });
|
|
539
|
+
await fs.writeFile(plistPath, plistBody, "utf8");
|
|
540
|
+
|
|
541
|
+
// Reload the agent if launchctl is available
|
|
542
|
+
try {
|
|
543
|
+
const { spawn } = await import("node:child_process");
|
|
544
|
+
await new Promise((resolve) => {
|
|
545
|
+
const unload = spawn("launchctl", ["unload", plistPath], { stdio: "ignore" });
|
|
546
|
+
unload.on("exit", () => resolve());
|
|
547
|
+
unload.on("error", () => resolve());
|
|
548
|
+
});
|
|
549
|
+
await new Promise((resolve, reject) => {
|
|
550
|
+
const load = spawn("launchctl", ["load", plistPath], { stdio: "ignore" });
|
|
551
|
+
load.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`launchctl load exited ${code}`))));
|
|
552
|
+
load.on("error", reject);
|
|
553
|
+
});
|
|
554
|
+
} catch (error) {
|
|
555
|
+
console.log("");
|
|
556
|
+
console.log(`Moltbook watcher plist written but launchctl load failed: ${error.message}`);
|
|
557
|
+
console.log(`Run manually: launchctl load ${plistPath}`);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
console.log("");
|
|
562
|
+
console.log(`Moltbook watcher installed.`);
|
|
563
|
+
console.log(` env: ${moltbookEnvFile}`);
|
|
564
|
+
console.log(` plist: ${plistPath}`);
|
|
565
|
+
console.log(` logs: /tmp/viveworker-moltbook-watcher.{out,err}.log`);
|
|
303
566
|
}
|
|
304
567
|
|
|
305
568
|
async function installClaudeHooks({ envFile, claudeSettingsFile, sessionSecret }) {
|
|
@@ -601,6 +864,16 @@ function parseArgs(argv) {
|
|
|
601
864
|
locale: "",
|
|
602
865
|
mkcertTrustStores: "",
|
|
603
866
|
claudeSettingsFile: "",
|
|
867
|
+
moltbook: false,
|
|
868
|
+
moltbookApiKey: "",
|
|
869
|
+
moltbookAgentId: "",
|
|
870
|
+
moltbookAgentName: "",
|
|
871
|
+
autoScout: false,
|
|
872
|
+
autoScoutUninstall: false,
|
|
873
|
+
autoScoutInterval: 120,
|
|
874
|
+
autoScoutHarness: "auto",
|
|
875
|
+
autoScoutSubmolts: "",
|
|
876
|
+
autoScoutMaxDaily: 0,
|
|
604
877
|
};
|
|
605
878
|
|
|
606
879
|
if (argv[0] && !argv[0].startsWith("-")) {
|
|
@@ -682,6 +955,35 @@ function parseArgs(argv) {
|
|
|
682
955
|
} else if (arg === "--claude-settings-file") {
|
|
683
956
|
parsed.claudeSettingsFile = next;
|
|
684
957
|
index += 1;
|
|
958
|
+
} else if (arg === "--moltbook") {
|
|
959
|
+
parsed.moltbook = true;
|
|
960
|
+
} else if (arg === "--moltbook-api-key") {
|
|
961
|
+
parsed.moltbook = true;
|
|
962
|
+
parsed.moltbookApiKey = next;
|
|
963
|
+
index += 1;
|
|
964
|
+
} else if (arg === "--moltbook-agent-id") {
|
|
965
|
+
parsed.moltbook = true;
|
|
966
|
+
parsed.moltbookAgentId = next;
|
|
967
|
+
index += 1;
|
|
968
|
+
} else if (arg === "--moltbook-agent-name") {
|
|
969
|
+
parsed.moltbookAgentName = next;
|
|
970
|
+
index += 1;
|
|
971
|
+
} else if (arg === "--auto-scout") {
|
|
972
|
+
parsed.autoScout = true;
|
|
973
|
+
} else if (arg === "--auto-scout-uninstall") {
|
|
974
|
+
parsed.autoScoutUninstall = true;
|
|
975
|
+
} else if (arg === "--auto-scout-interval") {
|
|
976
|
+
parsed.autoScoutInterval = Number(next) || 120;
|
|
977
|
+
index += 1;
|
|
978
|
+
} else if (arg === "--auto-scout-harness") {
|
|
979
|
+
parsed.autoScoutHarness = next;
|
|
980
|
+
index += 1;
|
|
981
|
+
} else if (arg === "--auto-scout-submolts") {
|
|
982
|
+
parsed.autoScoutSubmolts = next;
|
|
983
|
+
index += 1;
|
|
984
|
+
} else if (arg === "--auto-scout-max-daily") {
|
|
985
|
+
parsed.autoScoutMaxDaily = Number(next) || 0;
|
|
986
|
+
index += 1;
|
|
685
987
|
} else if (arg === "--help" || arg === "-h") {
|
|
686
988
|
parsed.command = "help";
|
|
687
989
|
} 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,75 @@ 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
|
+
.reply-field--title {
|
|
2322
|
+
margin-bottom: 0.5rem;
|
|
2323
|
+
}
|
|
2324
|
+
.reply-field--title .reply-field__input {
|
|
2325
|
+
min-height: auto;
|
|
2326
|
+
padding: 0.65rem 0.85rem;
|
|
2327
|
+
border: 1px solid var(--line);
|
|
2328
|
+
border-radius: 12px;
|
|
2329
|
+
background: rgba(7, 12, 16, 0.96);
|
|
2330
|
+
font-size: 1.05rem;
|
|
2331
|
+
font-weight: 700;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
.reply-composer__title-display {
|
|
2335
|
+
margin: 0.25rem 0 0.5rem;
|
|
2336
|
+
font-size: 1.05rem;
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2269
2339
|
.reply-field {
|
|
2270
2340
|
gap: 0.5rem;
|
|
2271
2341
|
}
|
|
@@ -3347,6 +3417,10 @@ button[data-action-url][aria-busy="true"]:not(.is-loading) {
|
|
|
3347
3417
|
color: #f5a45a;
|
|
3348
3418
|
background: rgba(245, 164, 90, 0.1);
|
|
3349
3419
|
}
|
|
3420
|
+
.provider-badge--moltbook {
|
|
3421
|
+
color: #e07a5f;
|
|
3422
|
+
background: rgba(224, 122, 95, 0.12);
|
|
3423
|
+
}
|
|
3350
3424
|
|
|
3351
3425
|
.provider-filter {
|
|
3352
3426
|
display: inline-flex;
|