agent-office 0.0.6 → 0.0.7

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/cli.js CHANGED
@@ -35,11 +35,15 @@ communicatorCmd
35
35
  .command("web")
36
36
  .description("[HUMAN ONLY] Launch a web chat interface for a single coworker")
37
37
  .argument("<coworker>", "Name of the coworker to chat with (e.g. 'Howard Roark')")
38
- .requiredOption("--url <url>", "URL of the agent-office serve endpoint (e.g. http://localhost:7654)")
39
- .requiredOption("--secret <secret>", "API password for the agent-office server")
38
+ .option("--url <url>", "URL of the agent-office serve endpoint (e.g. http://localhost:7654)", process.env.AGENT_OFFICE_URL ?? "http://localhost:7654")
39
+ .option("--secret <secret>", "API password for the agent-office server", process.env.AGENT_OFFICE_PASSWORD)
40
40
  .option("--host <host>", "Host to bind the communicator web server to", "127.0.0.1")
41
41
  .option("--port <port>", "Port to run the communicator web server on", "7655")
42
42
  .action(async (coworker, options) => {
43
+ if (!options.secret) {
44
+ console.error("Error: --secret is required (or set AGENT_OFFICE_PASSWORD)");
45
+ process.exit(1);
46
+ }
43
47
  const { communicatorWeb } = await import("./commands/communicator.js");
44
48
  await communicatorWeb(coworker, options);
45
49
  });
@@ -328,6 +328,18 @@ function renderPage(coworker, msgs, humanName) {
328
328
  .send-btn:hover { background: #7fa0ff; }
329
329
  .send-btn:active { transform: scale(0.93); }
330
330
  .send-btn svg { width: 20px; height: 20px; }
331
+ .send-btn.sending { background: var(--accent-dim); opacity: 0.7; cursor: not-allowed; pointer-events: none; }
332
+ .send-btn.sending svg { display: none; }
333
+ .send-btn .spinner {
334
+ display: none;
335
+ width: 18px; height: 18px;
336
+ border: 2px solid rgba(255,255,255,0.3);
337
+ border-top-color: #fff;
338
+ border-radius: 50%;
339
+ animation: spin 0.6s linear infinite;
340
+ }
341
+ .send-btn.sending .spinner { display: block; }
342
+ @keyframes spin { to { transform: rotate(360deg); } }
331
343
 
332
344
  /* ── Send error feedback ── */
333
345
  #send-status { min-height: 0; }
@@ -388,7 +400,7 @@ function renderPage(coworker, msgs, humanName) {
388
400
  hx-target="#send-status"
389
401
  hx-swap="innerHTML show:no-scroll"
390
402
  hx-on::after-request="handleSent(event)"
391
- hx-on::before-request="this.querySelector('.send-btn').disabled=true"
403
+ hx-on::before-request="this.querySelector('.send-btn').classList.add('sending')"
392
404
  hx-encoding="application/x-www-form-urlencoded">
393
405
  <textarea
394
406
  class="input-textarea"
@@ -405,6 +417,7 @@ function renderPage(coworker, msgs, humanName) {
405
417
  <line x1="22" y1="2" x2="11" y2="13"></line>
406
418
  <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
407
419
  </svg>
420
+ <div class="spinner"></div>
408
421
  </button>
409
422
  </form>
410
423
  </div>
@@ -443,10 +456,12 @@ function renderPage(coworker, msgs, humanName) {
443
456
  // After send: clear input, re-enable button, trigger refresh
444
457
  function handleSent(event) {
445
458
  const form = event.target
446
- form.querySelector('.send-btn').disabled = false
459
+ const btn = form.querySelector('.send-btn')
460
+ btn.classList.remove('sending')
447
461
  if (event.detail.successful) {
448
462
  input.value = ''
449
463
  input.style.height = 'auto'
464
+ input.focus()
450
465
  // Force scroll on the next swap since we just sent a message
451
466
  lastSeenId = -1
452
467
  htmx.trigger(document.getElementById('messages'), 'load')
@@ -363,6 +363,9 @@ export function createRouter(sql, opencode, serverUrl, scheduler, memoryManager)
363
363
  res.status(500).json({ error: "Failed to get first message ID" });
364
364
  return;
365
365
  }
366
+ // Abort any in-progress generation before reverting, to avoid "session is busy" errors.
367
+ // Swallow errors — the session may not be busy, in which case abort is a no-op.
368
+ await opencode.session.abort(session.session_id).catch(() => { });
366
369
  await opencode.session.revert(session.session_id, { messageID: firstMessage.info.id });
367
370
  const providers = await opencode.app.providers();
368
371
  const defaultEntry = Object.entries(providers.default)[0];
@@ -407,6 +410,8 @@ export function createRouter(sql, opencode, serverUrl, scheduler, memoryManager)
407
410
  results.push({ name: session.name, ok: false, error: "Failed to get first message ID" });
408
411
  continue;
409
412
  }
413
+ // Abort any in-progress generation before reverting
414
+ await opencode.session.abort(session.session_id).catch(() => { });
410
415
  await opencode.session.revert(session.session_id, { messageID: firstMessage.info.id });
411
416
  const clockInToken = `${session.agent_code}@${serverUrl}`;
412
417
  const enrollmentMessage = `You have been enrolled in the agent office.\n\nTo clock in and receive your full briefing, run:\n\n agent-office worker clock-in ${clockInToken}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-office",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Manage OpenCode sessions with named aliases",
5
5
  "type": "module",
6
6
  "license": "MIT",