@assuredloop/orca-bot-kit 0.22.0 → 0.24.1

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/src/temp.js CHANGED
@@ -28,7 +28,7 @@ import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
28
28
  import path from 'node:path';
29
29
  import { setTimeout as pause } from 'node:timers/promises';
30
30
 
31
- import { readBook, updateBook } from './book.js';
31
+ import { readBook, takeLineTurn, TYPING_HELD, TYPING_WAIT_MS, updateBook } from './book.js';
32
32
  import { addSession, dropSession, NAME, readBot, tempRoles } from './bot.js';
33
33
  import { DEFAULT_APPROVAL, harnessOf, isShortPrompt, ownCli, shellWord, startPrompt, workDirOf } from './launch.js';
34
34
  import { sessionInTab } from './message.js';
@@ -353,16 +353,23 @@ export async function trustHooks(bots, { tab, name }) {
353
353
  if (handle === undefined) {
354
354
  throw new Error(`${run} has no tab open in Orca, so there is no review of its to answer. ${nothing}`);
355
355
  }
356
- const seen = screenRows(handle);
357
- if (seen.rows === undefined) {
358
- throw new Error(`${run}'s screen could not be read (${seen.unreadable}), so the kit cannot tell whether its hooks review is there. ${nothing}`);
359
- }
360
- const keys = keysToTrustAll(seen.rows);
361
- if (keys === undefined) {
362
- throw new Error(`${run}'s screen shows no "${HOOKS_REVIEW}" with its choices, so there is nothing for this to answer. It shows: ${shown(seen.rows)}. ${nothing}`);
356
+ // The session's turn for a line (#482), for the look and the keys.
357
+ const turn = takeLineTurn(caller.home, name, TYPING_WAIT_MS);
358
+ if (turn === undefined) throw new Error(`${run}: ${TYPING_HELD}.`);
359
+ try {
360
+ const seen = screenRows(handle);
361
+ if (seen.rows === undefined) {
362
+ throw new Error(`${run}'s screen could not be read (${seen.unreadable}), so the kit cannot tell whether its hooks review is there. ${nothing}`);
363
+ }
364
+ const keys = keysToTrustAll(seen.rows);
365
+ if (keys === undefined) {
366
+ throw new Error(`${run}'s screen shows no "${HOOKS_REVIEW}" with its choices, so there is nothing for this to answer. It shows: ${shown(seen.rows)}. ${nothing}`);
367
+ }
368
+ // The return is inside the text: `--enter` would be a second key.
369
+ orca(['terminal', 'send', '--terminal', handle, '--text', keys]);
370
+ } finally {
371
+ turn.release();
363
372
  }
364
- // The return is inside the text: `--enter` would be a second key.
365
- orca(['terminal', 'send', '--terminal', handle, '--text', keys]);
366
373
  for (let waited = 0; ; waited += 500) {
367
374
  const after = screenRows(handle);
368
375
  if (after.rows !== undefined && !after.rows.some((row) => row.includes(HOOKS_REVIEW))) break;
package/src/up.js CHANGED
@@ -8,7 +8,7 @@ import { existsSync, mkdirSync, realpathSync, writeFileSync } from 'node:fs';
8
8
  import path from 'node:path';
9
9
  import { setTimeout as pause } from 'node:timers/promises';
10
10
 
11
- import { forgetClaimed, forgetSession, MAILBOX_WAIT_MS, readBook, sessionIdsIn, tabIdsIn, takeMailboxTurn, updateBook, withUnclaimed } from './book.js';
11
+ import { forgetClaimed, forgetSession, MAILBOX_WAIT_MS, readBook, sessionIdsIn, tabIdsIn, takeLineTurn, takeMailboxTurn, TYPING_HELD, TYPING_WAIT_MS, updateBook, withUnclaimed } from './book.js';
12
12
  import { botDir, botNames, displayName, projectName, readBot } from './bot.js';
13
13
  import { conversationsIn, hasConversation, heldAsUserTurn, transcriptsIn } from './conversations.js';
14
14
  import { installHook } from './hooks.js';
@@ -374,7 +374,7 @@ async function bringUpSession(bots, home, live, session, bot, title) {
374
374
  // 0.157.1 (#226). So it is given one line, through the same gate as a mail
375
375
  // notice, which the owner allowed. A fresh start's first turn is its prompt.
376
376
  const list = harness === 'codex' && launch.resume !== undefined && tui.running === true
377
- ? await typeListLine(home, made.tabId)
377
+ ? await typeListLine(home, session.name, made.tabId)
378
378
  : undefined;
379
379
 
380
380
  return entry(made, {
@@ -408,42 +408,65 @@ const LIST_LOOK_MS = 2000;
408
408
  const LIST_ASK_MS = 500;
409
409
 
410
410
  /**
411
- * Type LIST_LINE into the tab `tabId` once the gate every typed line goes
412
- * through lets it: `{ typed: true }`, or `{ typed: false, why }` with the
413
- * gate's last reason once LIST_WAIT_MS is up. Nothing goes into a question, a
414
- * form or a menu (#329, #416), nor into a tab the kit cannot tell about.
411
+ * Type `line`, LIST_LINE unless told otherwise, into the tab `tabId` of
412
+ * `session` once the gate every typed line goes through lets it:
413
+ * `{ typed: true }`, or `{ typed: false, why }` with the gate's last reason
414
+ * once LIST_WAIT_MS is up. Nothing goes into a question, a form or a menu
415
+ * (#329, #416), nor into a tab the kit cannot tell about. Each look and its
416
+ * line are taken in the session's turn for a line (#482), unless the caller
417
+ * says it holds the session's typing turn already (`held`).
415
418
  */
416
- async function typeListLine(home, tabId) {
419
+ export async function typeListLine(home, session, tabId, { line = LIST_LINE, held = false } = {}) {
417
420
  const until = Date.now() + LIST_WAIT_MS;
418
421
  for (;;) {
419
- let found;
420
- try {
421
- // Each look waits no longer than what is left of the wait.
422
- found = tabToTypeInto(home, tabId, Math.max(1, Math.min(LIST_LOOK_MS, until - Date.now())));
423
- } catch (error) {
424
- return { typed: false, why: `Orca would not say whether it may be typed into: ${error.message}` };
425
- }
426
- // A yes that comes after the wait is too late: the wait is a cutoff, not a
427
- // count of looks (review of PR #421).
428
- if (found.handle !== undefined && Date.now() > until) {
429
- return { typed: false, why: `the ${LIST_WAIT_MS / 1000} s wait for it ran out before the kit could tell it may be typed into` };
430
- }
431
- if (found.handle !== undefined) {
422
+ let turn;
423
+ if (!held) {
432
424
  try {
433
- typeIntoTab(found.handle, LIST_LINE);
434
- return { typed: true };
425
+ turn = takeLineTurn(home, session, TYPING_WAIT_MS);
435
426
  } catch (error) {
436
- return { typed: false, why: `Orca refused the line: ${error.message}` };
427
+ return { typed: false, why: error.message };
437
428
  }
429
+ if (turn === undefined) return { typed: false, why: TYPING_HELD };
438
430
  }
439
- if (Date.now() >= until) {
440
- const last = found.blocked !== undefined ? `it is waiting on ${found.blocked}` : found.unsure ?? 'no harness is running in it';
441
- return { typed: false, why: `the ${LIST_WAIT_MS / 1000} s wait for it ran out: ${last}` };
431
+ try {
432
+ const done = lookAndType(home, tabId, line, until);
433
+ if (done !== undefined) return done;
434
+ } finally {
435
+ turn?.release();
442
436
  }
443
437
  await pause(LIST_ASK_MS);
444
438
  }
445
439
  }
446
440
 
441
+ /** One look of typeListLine's, and its line when the gate lets it: what it returns, or undefined to look again. */
442
+ function lookAndType(home, tabId, line, until) {
443
+ let found;
444
+ try {
445
+ // Each look waits no longer than what is left of the wait.
446
+ found = tabToTypeInto(home, tabId, Math.max(1, Math.min(LIST_LOOK_MS, until - Date.now())));
447
+ } catch (error) {
448
+ return { typed: false, why: `Orca would not say whether it may be typed into: ${error.message}` };
449
+ }
450
+ // A yes that comes after the wait is too late: the wait is a cutoff, not a
451
+ // count of looks (review of PR #421).
452
+ if (found.handle !== undefined && Date.now() > until) {
453
+ return { typed: false, why: `the ${LIST_WAIT_MS / 1000} s wait for it ran out before the kit could tell it may be typed into` };
454
+ }
455
+ if (found.handle !== undefined) {
456
+ try {
457
+ typeIntoTab(found.handle, line);
458
+ return { typed: true };
459
+ } catch (error) {
460
+ return { typed: false, why: `Orca refused the line: ${error.message}` };
461
+ }
462
+ }
463
+ if (Date.now() >= until) {
464
+ const last = found.blocked !== undefined ? `it is waiting on ${found.blocked}` : found.unsure ?? 'no harness is running in it';
465
+ return { typed: false, why: `the ${LIST_WAIT_MS / 1000} s wait for it ran out: ${last}` };
466
+ }
467
+ return undefined;
468
+ }
469
+
447
470
  /**
448
471
  * The line that starts this session: resuming `resume`, or, with none, a fresh
449
472
  * start carrying its duty. Returns `{ resume, prompt, promptFile, command, address }`.