@assuredloop/orca-bot-kit 0.37.0 → 0.38.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 CHANGED
@@ -528,7 +528,15 @@ effort and context go back to the new harness's defaults unless you give them
528
528
  too. A pause closes the tabs the way a restart does, with the
529
529
  same refusals, and one more: it also refuses a tab with only its shell in front
530
530
  whose conversation the book does not name. `obk up` leaves what is paused
531
- closed until `obk unpause` brings it back with its conversations. Retiring a
531
+ closed until `obk unpause` brings it back with its conversations. The closed
532
+ tab ended the background shells of each paused session, as a restart does. So
533
+ the unpause tells each session it took off pause and resumed, in one typed
534
+ line, as a restart does: its old tab is closed and its background shells
535
+ ended, and it looks at its scheduled jobs and its mail. The report says under
536
+ each tab whether the line went in. In the `--json` answer, `restartLine` means
537
+ the same after an unpause as after a restart: `true` when the line went in, or
538
+ `false` with the reason in `restartLineTrouble`, and then you tell the session
539
+ yourself. Retiring a
532
540
  session takes it off the bot and keeps its conversations in the book under
533
541
  `retired`. Once its tab is closed, it stops what the session left running in
534
542
  its work dir: each of your processes whose working folder is there, and what
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assuredloop/orca-bot-kit",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
package/src/cli.js CHANGED
@@ -690,7 +690,7 @@ const commands = {
690
690
  const answer = { bots, bot, session, changed, created: [], completed: [], ...up };
691
691
  return {
692
692
  answer,
693
- lines: tabLines(answer, `${changed ? 'Unpaused' : 'Not paused, so brought up as it is'}: ${what}. Your bots folder: ${bots}`),
693
+ lines: tabLines(answer, `${changed ? 'Unpaused' : 'Not paused, so brought up as it is'}: ${what}. Your bots folder: ${bots}`, 'pause'),
694
694
  };
695
695
  },
696
696
 
@@ -1918,7 +1918,7 @@ function settingsLine({ bot, session, running, settings, rules }) {
1918
1918
  return `${word.padEnd(9)} ${who} ${each.join(' ')} rules ${rules.state}`;
1919
1919
  }
1920
1920
 
1921
- function tabLines({ bots, created, completed, rules, skills, permissions = [], tabs, paused = [], projects = [], found = [] }, summary) {
1921
+ function tabLines({ bots, created, completed, rules, skills, permissions = [], tabs, paused = [], projects = [], found = [] }, summary, closedBy = 'restart') {
1922
1922
  const lines = [
1923
1923
  ...created.map((entry) => `created ${entry}`),
1924
1924
  ...completed.map((entry) => `completed ${entry}`),
@@ -1929,7 +1929,7 @@ function tabLines({ bots, created, completed, rules, skills, permissions = [], t
1929
1929
 
1930
1930
  for (const tab of tabs) {
1931
1931
  lines.push(`${tab.created ? 'opened' : 'found '} ${tab.title} tab ${tab.tabId} terminal ${tab.terminal}`);
1932
- lines.push(...harnessLines(tab, bots));
1932
+ lines.push(...harnessLines(tab, bots, closedBy));
1933
1933
  if (tab.noMailbox) {
1934
1934
  lines.push(` it has no mailbox: ${noMailboxYet({ bots, bot: tab.bot, session: tab.name })}`);
1935
1935
  }
@@ -1962,7 +1962,7 @@ function tabLines({ bots, created, completed, rules, skills, permissions = [], t
1962
1962
  * The caller decides what to do next from these lines, so they say both what
1963
1963
  * was typed and what was seen afterwards, and never one in place of the other.
1964
1964
  */
1965
- function harnessLines(tab, bots) {
1965
+ function harnessLines(tab, bots, closedBy) {
1966
1966
  if (!tab.created || tab.name === null) return [];
1967
1967
 
1968
1968
  // Nothing was typed into it, so there is nothing more to say about a harness
@@ -1988,7 +1988,7 @@ function harnessLines(tab, bots) {
1988
1988
  ` Look at it: ${lookAt(tab.terminal)}`,
1989
1989
  ...ANSWER_IT,
1990
1990
  ...promptLines(tab),
1991
- ...restartLines(tab),
1991
+ ...restartLines(tab, closedBy),
1992
1992
  ];
1993
1993
  }
1994
1994
 
@@ -2010,7 +2010,7 @@ function harnessLines(tab, bots) {
2010
2010
  ...ANSWER_IT,
2011
2011
  ];
2012
2012
 
2013
- lines.push(...promptLines(tab), ...listLines(tab), ...restartLines(tab));
2013
+ lines.push(...promptLines(tab), ...listLines(tab), ...restartLines(tab, closedBy));
2014
2014
  if (tab.unclaimed !== undefined) lines.push(...unclaimedLines(tab, bots));
2015
2015
  return lines;
2016
2016
  }
@@ -2027,11 +2027,13 @@ function listLines(tab) {
2027
2027
 
2028
2028
  /**
2029
2029
  * Whether a session `obk restart` resumed was typed the line that tells it what
2030
- * the restart ended (#726). When it was not, the caller is the one left to tell it.
2030
+ * the restart ended (#726), or one `obk unpause` resumed, what the pause ended
2031
+ * (#732): `closedBy` names which. When it was not, the caller is the one left
2032
+ * to tell it.
2031
2033
  */
2032
- function restartLines(tab) {
2033
- if (tab.restartLine === true) return [' it was typed one line that tells it what the restart ended: its background shells, and to look at its scheduled jobs and its mail.'];
2034
- if (tab.restartLine === false) return [` it was not told what the restart ended (${tab.restartLineTrouble}): tell it yourself that its background shells ended, and to look at its scheduled jobs and its mail.`];
2034
+ function restartLines(tab, closedBy) {
2035
+ if (tab.restartLine === true) return [` it was typed one line that tells it what the ${closedBy} ended: its background shells, and to look at its scheduled jobs and its mail.`];
2036
+ if (tab.restartLine === false) return [` it was not told what the ${closedBy} ended (${tab.restartLineTrouble}): tell it yourself that its background shells ended, and to look at its scheduled jobs and its mail.`];
2035
2037
  return [];
2036
2038
  }
2037
2039
 
package/src/pause.js CHANGED
@@ -40,10 +40,14 @@ export async function pauseSessions(bots, { bot, session }) {
40
40
  */
41
41
  export async function unpauseSessions(bots, { bot, session }) {
42
42
  const home = fleetMember(bots, bot, 'unpause', session);
43
- sessionsOf(readBot(home, bot), session);
43
+ const sessions = sessionsOf(readBot(home, bot), session);
44
44
 
45
45
  const changed = markPaused(bots, bot, session, false);
46
- return { bot, session, changed, ...(await bringUp(bots, { bot, session })) };
46
+ // The sessions this took the pause off are told, once they are resumed, what
47
+ // their closed tab ended (#732). One still paused on its own is not brought
48
+ // up, so it is told nothing; nothing is told when nothing was paused.
49
+ const unpaused = changed ? new Set(sessions.map((one) => one.name)) : undefined;
50
+ return { bot, session, changed, ...(await bringUp(bots, { bot, session, unpaused })) };
47
51
  }
48
52
 
49
53
  /**
package/src/up.js CHANGED
@@ -49,7 +49,7 @@ const SECOND_LOOK_MS = 2000;
49
49
  * one bot and `session` one of its sessions, for a caller that wants one thing
50
50
  * back rather than the fleet.
51
51
  */
52
- export async function bringUp(bots, { bot: onlyBot, session: onlySession, restarted } = {}) {
52
+ export async function bringUp(bots, { bot: onlyBot, session: onlySession, restarted, unpaused } = {}) {
53
53
  const named = botsNamed(bots, onlyBot);
54
54
  if (onlySession !== undefined && onlyBot === undefined) {
55
55
  throw new Error('--session needs --bot: say which bot the session belongs to.');
@@ -72,7 +72,7 @@ export async function bringUp(bots, { bot: onlyBot, session: onlySession, restar
72
72
  for (const session of sessionsOf(bot, onlySession)) {
73
73
  if (session.paused === true) paused.push({ bot: bot.name, session: session.name });
74
74
  }
75
- const up = await bringUpBot(bots, home, bot, onlySession, restarted);
75
+ const up = await bringUpBot(bots, home, bot, onlySession, { restarted, unpaused });
76
76
  report.push(...up.tabs);
77
77
  if (up.project !== undefined) projects.push(up.project);
78
78
  }
@@ -230,7 +230,7 @@ export function sessionsOf(bot, onlySession) {
230
230
  return named;
231
231
  }
232
232
 
233
- async function bringUpBot(bots, home, bot, onlySession, restarted) {
233
+ async function bringUpBot(bots, home, bot, onlySession, { restarted, unpaused } = {}) {
234
234
  const name = bot.name;
235
235
  const title = displayName(name);
236
236
  const sessions = awake(sessionsOf(bot, onlySession));
@@ -250,7 +250,10 @@ async function bringUpBot(bots, home, bot, onlySession, restarted) {
250
250
 
251
251
  const live = new Map(tabs(home).map((tab) => [tab.tabId, tab]));
252
252
  const report = [];
253
- for (const session of sessions) report.push(await bringUpSession(bots, home, live, session, bot, title, restarted?.has(session.name) === true));
253
+ // Which command closed the session's old tab, when one did and the session
254
+ // is to be told what that ended (#726, #732).
255
+ const endedBy = (name) => (restarted?.has(name) ? 'restart' : unpaused?.has(name) ? 'unpause' : undefined);
256
+ for (const session of sessions) report.push(await bringUpSession(bots, home, live, session, bot, title, endedBy(session.name)));
254
257
 
255
258
  // The ops tab, and the whole of what the kit knows about it: Bot Father's
256
259
  // project needs one tab that is not a session, for work across the fleet. Any
@@ -274,7 +277,7 @@ async function bringUpBot(bots, home, bot, onlySession, restarted) {
274
277
  return { tabs: report, project: change === undefined && windowTrouble === undefined ? undefined : project };
275
278
  }
276
279
 
277
- async function bringUpSession(bots, home, live, session, bot, title, restarted) {
280
+ async function bringUpSession(bots, home, live, session, bot, title, endedBy) {
278
281
  const harness = harnessOf(session, bot.harness);
279
282
  const book = readBook(home);
280
283
  const was = book.sessions[session.name];
@@ -432,12 +435,13 @@ async function bringUpSession(bots, home, live, session, bot, title, restarted)
432
435
  : await heldInRecord(home, session.name, harness, launch.prompt, { launched, running: tui.running === true });
433
436
 
434
437
  // A session whose tab `obk restart` closed lost the background shells its
435
- // harness ran there, and nothing else tells it (#726). So once it is resumed
436
- // it is typed one line that says so, through the same gate, whatever its
437
- // harness. For Codex that line is its first turn too, so it takes the place
438
- // of the list line below.
439
- const told = !restarted || launch.resume === undefined ? undefined
440
- : tui.running === true ? await typeListLine(home, session.name, made.tabId, { line: restartLine(bots) })
438
+ // harness ran there, and nothing else tells it (#726). So does one that
439
+ // `obk unpause` took off pause: its old tab is closed (#732). So once it is
440
+ // resumed it is typed one line that says so, through the same gate, whatever
441
+ // its harness. For Codex that line is its first turn too, so it takes the
442
+ // place of the list line below.
443
+ const told = endedBy === undefined || launch.resume === undefined ? undefined
444
+ : tui.running === true ? await typeListLine(home, session.name, made.tabId, { line: (endedBy === 'unpause' ? unpauseLine : restartLine)(bots) })
441
445
  : { typed: false, why: 'its harness did not come up in the new tab' };
442
446
 
443
447
  // A Codex session resumed here is not among Orca's agents until its first
@@ -540,12 +544,29 @@ const listLine = (bots) => 'obk: this session was resumed in a new tab, and the
540
544
  */
541
545
  const restartLine = (bots) => 'obk: obk restart closed this session\'s old tab and resumed the conversation in this new one.'
542
546
  + ' Closing the old tab ended the harness there, and the background shells it ran ended with it.'
543
- + ' The kit cannot tell which shells ran, or whether a scheduled job of the harness still runs.'
547
+ + whatToDoAfterTheClose(bots);
548
+
549
+ /**
550
+ * What the restart line and the unpause line both say after their first two
551
+ * sentences: what the kit cannot tell, and what the session does about it.
552
+ */
553
+ const whatToDoAfterTheClose = (bots) => ' The kit cannot tell which shells ran, or whether a scheduled job of the harness still runs.'
544
554
  + ' Look at the harness\'s scheduled jobs before you make one again, so that only one of each runs.'
545
555
  + ' Start again the shells you still need.'
546
556
  + ` Read your mail with \`${shellWord(ownCli())} message check --bots ${shellWord(bots)}\`, and do what it asks.`
547
557
  + ' That includes mail you read just before this line. If nothing needs doing, reply "ok".';
548
558
 
559
+ /**
560
+ * The line a session is typed once `obk unpause` has taken it off pause and
561
+ * resumed it in a new tab, in the architect's ruling (#732). Its first two
562
+ * sentences take the place of the restart line's: the kit cannot tell whether
563
+ * the pause closed the old tab or it was closed before, and the words are true
564
+ * either way. The rest is the restart line's, word for word.
565
+ */
566
+ const unpauseLine = (bots) => 'obk: obk unpause took this session off pause and resumed its conversation in this new tab.'
567
+ + ' Its old tab is closed, which ended the harness there, and the background shells it ran ended with it.'
568
+ + whatToDoAfterTheClose(bots);
569
+
549
570
  /**
550
571
  * How long a resumed Codex tab is given to be one the kit may type into: live,
551
572
  * Orca named the agent 7 to 11 s after the restart (#226), and the gate waits