@assuredloop/orca-bot-kit 0.25.1 → 0.25.2
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/package.json +1 -1
- package/src/clear.js +12 -4
- package/src/orca.js +35 -1
package/package.json
CHANGED
package/src/clear.js
CHANGED
|
@@ -19,7 +19,7 @@ import { botDir, readBot } from './bot.js';
|
|
|
19
19
|
import { claudeTranscript, codexRollout } from './conversations.js';
|
|
20
20
|
import { harnessOf, ownCli, shellWord } from './launch.js';
|
|
21
21
|
import { eachLine, firstLine } from './lines.js';
|
|
22
|
-
import { findProject, orca, QUESTION_ON_SCREEN, questionIn, screenRows, tabs, tabToTypeInto, TIMED_OUT } from './orca.js';
|
|
22
|
+
import { FEEDBACK_PANEL, feedbackPanelIn, findProject, orca, QUESTION_ON_SCREEN, questionIn, screenRows, tabs, tabToTypeInto, TIMED_OUT } from './orca.js';
|
|
23
23
|
import { botsNamed, sessionsOf, typeListLine } from './up.js';
|
|
24
24
|
|
|
25
25
|
/** The harness's own command for each, as typed into its input line. Codex's clear is `/new` (tech notes, section 3). */
|
|
@@ -201,7 +201,7 @@ async function enter(it, verb, before = () => {}) {
|
|
|
201
201
|
if (typing === undefined) throw new Error(`${it.name}: ${TYPING_HELD}. Run this again in a moment.`);
|
|
202
202
|
before();
|
|
203
203
|
},
|
|
204
|
-
cannot: (wrong) => (verb === 'compact' && wrong.menu ? ` ${harnessName(it.harness)} here cannot compact: its menu does not offer ${COMMANDS[verb][it.harness]}.` : ''),
|
|
204
|
+
cannot: (wrong) => (verb === 'compact' && wrong.menu && it.harness === 'codex' ? ` ${harnessName(it.harness)} here cannot compact: its menu does not offer ${COMMANDS[verb][it.harness]}.` : ''),
|
|
205
205
|
});
|
|
206
206
|
return { ...typed, typing };
|
|
207
207
|
} catch (error) {
|
|
@@ -350,8 +350,8 @@ function lookAt(it, { idle = true } = {}) {
|
|
|
350
350
|
const found = tabToTypeInto(it.home, it.tabId, idle ? LOOK_MS : CHAR_LOOK_MS);
|
|
351
351
|
if (found.blocked !== undefined) {
|
|
352
352
|
return {
|
|
353
|
-
why: found.blocked ===
|
|
354
|
-
? 'a question of its harness\'s own is on its screen'
|
|
353
|
+
why: found.blocked === FEEDBACK_PANEL ? PANEL_WHY
|
|
354
|
+
: found.blocked === QUESTION_ON_SCREEN ? 'a question of its harness\'s own is on its screen'
|
|
355
355
|
: `a question is waiting on its screen: Orca says ${found.blocked}`,
|
|
356
356
|
};
|
|
357
357
|
}
|
|
@@ -390,10 +390,18 @@ async function typedWrong(handle, harness, command, version, check) {
|
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Why nothing goes in while Claude Code's panel of feedback drafts is open
|
|
395
|
+
* (#502): it reads single keys from the input line, and one sends a draft to
|
|
396
|
+
* Anthropic, so only the user answers it.
|
|
397
|
+
*/
|
|
398
|
+
const PANEL_WHY = 'its panel of feedback drafts is open above its input box, and the kit does not answer it, since a draft sent from it goes to Anthropic: it clears once the user reviews, sends or dismisses the drafts in that tab';
|
|
399
|
+
|
|
393
400
|
/** Why `rows` say not to type now, as the look says it, or undefined: a turn at work, or a question. */
|
|
394
401
|
function signalIn(rows) {
|
|
395
402
|
const working = rows.find((row) => AT_WORK.some((marker) => marker.test(row)));
|
|
396
403
|
if (working !== undefined) return `it is busy with a turn: its screen shows "${working.trim()}"`;
|
|
404
|
+
if (feedbackPanelIn(rows)) return PANEL_WHY;
|
|
397
405
|
if (questionIn(rows)) return 'a question of its harness\'s own is on its screen';
|
|
398
406
|
return undefined;
|
|
399
407
|
}
|
package/src/orca.js
CHANGED
|
@@ -427,6 +427,7 @@ const ON_A_CHOICE = /^( *[›❯] +)\d+\. /;
|
|
|
427
427
|
* line, lined up with it, and by its layout that is one.
|
|
428
428
|
*/
|
|
429
429
|
export function questionIn(rows) {
|
|
430
|
+
if (feedbackPanelIn(rows)) return true;
|
|
430
431
|
const at = rows.findLastIndex((row) => POINTER_ROW.test(row));
|
|
431
432
|
// A form of the harness's own has no numbers but a foot that says how to
|
|
432
433
|
// answer it: Claude Code 2.1.283's "Teach auto mode" ends `Enter to continue
|
|
@@ -455,6 +456,39 @@ export function questionIn(rows) {
|
|
|
455
456
|
return false;
|
|
456
457
|
}
|
|
457
458
|
|
|
459
|
+
/** The gate's answer for Claude Code's panel of feedback drafts (#502). */
|
|
460
|
+
export const FEEDBACK_PANEL = 'feedback-drafts-panel';
|
|
461
|
+
|
|
462
|
+
/** The first row in the panel's box, as Claude Code 2.1.291 draws it: `✻ Bug report drafted: <title>`. */
|
|
463
|
+
const PANEL_TITLE = /^ *│ +(?:\S+ +)?(?:Bug report|Product feedback|Feature request|Feedback) drafted: /;
|
|
464
|
+
|
|
465
|
+
/** What Claude Code 2.1.291 asks in the panel's place after a `0`, its keys' foot last: `… 0 to turn off · Esc to keep`. */
|
|
466
|
+
const PANEL_TURN_OFF = /^Turn off Claude-drafted feedback\? 0 to turn off · Esc to keep$/i;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Whether the rows of a rendered screen show Claude Code's panel of feedback
|
|
470
|
+
* drafts (#502). It has no pointer and no numbers, but it reads single keys
|
|
471
|
+
* from the input line, and `2` twice sends a draft to Anthropic. Claude Code
|
|
472
|
+
* 2.1.291 draws it as a box, its title row first, as the last thing above its
|
|
473
|
+
* input box's top rule; after a `0`, the question whether to turn the drafts
|
|
474
|
+
* off stands in its place, wrapped as the pane needs, and a typed line answers
|
|
475
|
+
* that too. The same words
|
|
476
|
+
* with anything after them are history.
|
|
477
|
+
*/
|
|
478
|
+
export function feedbackPanelIn(rows) {
|
|
479
|
+
const at = rows.findLastIndex((row) => POINTER_ROW.test(row));
|
|
480
|
+
if (at < 1 || !RULE_ROW.test(rows[at - 1])) return false;
|
|
481
|
+
const end = rows.slice(0, at - 1).findLastIndex((row) => row.trim() !== '');
|
|
482
|
+
if (end < 0) return false;
|
|
483
|
+
// The question is plain text, which a narrow pane wraps onto rows of its
|
|
484
|
+
// own, with a blank row above it: it is the whole block that ends there.
|
|
485
|
+
const start = rows.slice(0, end).findLastIndex((row) => row.trim() === '') + 1;
|
|
486
|
+
if (PANEL_TURN_OFF.test(rows.slice(start, end + 1).map((row) => row.trim()).join(' '))) return true;
|
|
487
|
+
if (!/^ *╰─/.test(rows[end])) return false;
|
|
488
|
+
const top = rows.slice(0, end).findLastIndex((row) => /^ *╭─/.test(row));
|
|
489
|
+
return top >= 0 && PANEL_TITLE.test(rows[top + 1]);
|
|
490
|
+
}
|
|
491
|
+
|
|
458
492
|
/** A rule Claude Code draws right across, as the top of its input box: `─` or `▔`. */
|
|
459
493
|
const RULE_ROW = /^ *[─▔]{8,}/;
|
|
460
494
|
|
|
@@ -538,7 +572,7 @@ export function tabToTypeInto(home, tabId, timeoutMs) {
|
|
|
538
572
|
// Orca's reason does not cover every question: it called Codex's update
|
|
539
573
|
// offer idle, and a return typed into it took "Update now" (#329). So the
|
|
540
574
|
// screen is read too, and one that cannot be read is not a reason to type.
|
|
541
|
-
if (seen.question === true) return { blocked: QUESTION_ON_SCREEN };
|
|
575
|
+
if (seen.question === true) return { blocked: feedbackPanelIn(seen.rows) ? FEEDBACK_PANEL : QUESTION_ON_SCREEN };
|
|
542
576
|
if (seen.question === undefined) {
|
|
543
577
|
return { unsure: `the kit could not tell whether a question is waiting on its screen (${seen.screenUnreadable}), so nothing was typed` };
|
|
544
578
|
}
|