@assuredloop/orca-bot-kit 0.8.0 → 0.9.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 +5 -2
- package/SETUP.md +8 -3
- package/package.json +1 -1
- package/skills/obk-bot-building/SKILL.md +4 -3
- package/src/launch.js +47 -0
- package/src/up.js +6 -6
package/README.md
CHANGED
|
@@ -529,7 +529,8 @@ name. Everything else goes through Orca's mailbox, which the kit does carry.
|
|
|
529
529
|
|
|
530
530
|
That includes a Claude session still running under a name from before the
|
|
531
531
|
token, `<bot>.<session>`: `message to` answers the mailbox road for it, never
|
|
532
|
-
that name, until the
|
|
532
|
+
that name, until the kit's launch line next starts it (`obk restart`, or
|
|
533
|
+
`obk up` after its tab is gone), which gives it a token name of its own.
|
|
533
534
|
|
|
534
535
|
A session's mailbox is made the first time the kit starts it, and written in
|
|
535
536
|
the book beside its tab. It is an Orca Run rather than the session's tab,
|
|
@@ -598,7 +599,9 @@ cannot be read as one that passed. `-- --yes` is how you say you meant it. When
|
|
|
598
599
|
Orca is not answering, the command says which Orca it asked and skips, rather
|
|
599
600
|
than report a kit that is not broken. Name files after it to run only those;
|
|
600
601
|
each must be one of the `*.test.js` files under `test/system/`, links followed,
|
|
601
|
-
and a name that is not is refused before anything runs.
|
|
602
|
+
and a name that is not is refused before anything runs. This command is the
|
|
603
|
+
only way in: a system test loaded any other way, with `node --test` or an
|
|
604
|
+
editor's runner, skips and says how to run it.
|
|
602
605
|
|
|
603
606
|
`npm run mutate` runs [StrykerJS](https://stryker-mutator.io) over the
|
|
604
607
|
JavaScript this branch changed against `main` — committed, still in the working
|
package/SETUP.md
CHANGED
|
@@ -37,7 +37,7 @@ node --version # 24.21.0 or newer
|
|
|
37
37
|
git --version
|
|
38
38
|
/Applications/Orca.app/Contents/Resources/bin/orca status --json
|
|
39
39
|
claude --version # at least one of these
|
|
40
|
-
codex --version
|
|
40
|
+
codex --version # 0.156.1 or newer
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
The Orca line must come back with `ok: true` and `result.runtime.reachable:
|
|
@@ -55,6 +55,10 @@ first release measured here that loads it without an experimental warning.
|
|
|
55
55
|
If neither harness is installed, say so and stop. If only one is, that is fine,
|
|
56
56
|
and it is the one Bot Father will run on.
|
|
57
57
|
|
|
58
|
+
If Codex is older than 0.156.1, say so and ask them to update it before a bot
|
|
59
|
+
runs on Codex. The kit starts Codex with `--no-daemon`, and older Codex refuses
|
|
60
|
+
that flag.
|
|
61
|
+
|
|
58
62
|
## 2. Make `obk` runnable
|
|
59
63
|
|
|
60
64
|
**First ask whether it already is:**
|
|
@@ -206,8 +210,9 @@ empty book and nothing says why.
|
|
|
206
210
|
Codex's trust question applies to the **repository root**, which for a bot means
|
|
207
211
|
the whole bots folder rather than the one bot. That is what they are agreeing to.
|
|
208
212
|
|
|
209
|
-
Codex's `/new` question (0.156.1
|
|
210
|
-
|
|
213
|
+
Codex's `/new` question (seen on 0.156.1; 0.157.1 did not show it in the runs
|
|
214
|
+
seen so far) is always answered with the current checkout, which is the bot
|
|
215
|
+
home. The kit never makes a git worktree, so
|
|
211
216
|
`2. New worktree` is never the answer.
|
|
212
217
|
|
|
213
218
|
**Anything you do not recognise: type nothing.** Tell them what is on the
|
package/package.json
CHANGED
|
@@ -260,9 +260,10 @@ table: a harness that has added an option has moved them. Codex's hooks
|
|
|
260
260
|
question matters most. The kit's hook is how the book learns which
|
|
261
261
|
conversation the session is running, and until it is answered the
|
|
262
262
|
conversation has not started. Codex's trust applies to the repository root,
|
|
263
|
-
which is the whole bots folder. Codex's `/new`
|
|
264
|
-
conversation runs
|
|
265
|
-
and never `2. New worktree`:
|
|
263
|
+
which is the whole bots folder. Codex's `/new` may ask where the new
|
|
264
|
+
conversation runs (0.156.1 did; 0.157.1 has not so far); the answer is
|
|
265
|
+
always the current checkout, the bot home, and never `2. New worktree`:
|
|
266
|
+
the kit never makes a git worktree.
|
|
266
267
|
|
|
267
268
|
Where the kit says no session came up, the shell swallowed the launch line,
|
|
268
269
|
usually while it was asking its own question. Answer the shell, then close
|
package/src/launch.js
CHANGED
|
@@ -99,6 +99,48 @@ export const setsNetworkAccess = (session) =>
|
|
|
99
99
|
export const reachesMail = (session, harness) =>
|
|
100
100
|
harness !== 'codex' || !turnedOff(session);
|
|
101
101
|
|
|
102
|
+
/** Codex's flag for running without its shared background server (0.156.1 on). */
|
|
103
|
+
const NO_DAEMON = '--no-daemon';
|
|
104
|
+
|
|
105
|
+
// A string is shell text, so it is read as the shell will split it: `'--no-daemon'`
|
|
106
|
+
// is the flag, and `'/tmp/a --no-daemon b'` is one path that merely says it.
|
|
107
|
+
const setsNoDaemon = (session) => {
|
|
108
|
+
const extra = session.extra_args;
|
|
109
|
+
const words = Array.isArray(extra) ? extra.map(String) : set(extra) ? shellWords(String(extra)) : [];
|
|
110
|
+
return words.includes(NO_DAEMON);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The words a shell makes of `text`: split on blanks outside quotes, quotes
|
|
115
|
+
* removed, a backslash keeping the next character. Nothing is expanded.
|
|
116
|
+
*/
|
|
117
|
+
function shellWords(text) {
|
|
118
|
+
const words = [];
|
|
119
|
+
let word;
|
|
120
|
+
let quote;
|
|
121
|
+
for (let at = 0; at < text.length; at += 1) {
|
|
122
|
+
const char = text[at];
|
|
123
|
+
if (quote === "'") {
|
|
124
|
+
if (char === "'") quote = undefined;
|
|
125
|
+
else word += char;
|
|
126
|
+
} else if (quote === '"') {
|
|
127
|
+
if (char === '"') quote = undefined;
|
|
128
|
+
else if (char === '\\' && '"\\$`'.includes(text[at + 1] ?? ' ')) word += text[(at += 1)];
|
|
129
|
+
else word += char;
|
|
130
|
+
} else if (/\s/.test(char)) {
|
|
131
|
+
if (word !== undefined) words.push(word);
|
|
132
|
+
word = undefined;
|
|
133
|
+
} else {
|
|
134
|
+
word ??= '';
|
|
135
|
+
if (char === "'" || char === '"') quote = char;
|
|
136
|
+
else if (char === '\\') word += text[(at += 1)] ?? '';
|
|
137
|
+
else word += char;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (word !== undefined) words.push(word);
|
|
141
|
+
return words;
|
|
142
|
+
}
|
|
143
|
+
|
|
102
144
|
const turnedOff = (session) =>
|
|
103
145
|
extraWords(session.extra_args).some((word) => word.includes(`${NETWORK_ACCESS}=false`));
|
|
104
146
|
|
|
@@ -174,6 +216,11 @@ export function launchCommand(session, { harness, home, workDir, prompt, promptF
|
|
|
174
216
|
// take every other flag exactly as a fresh session does.
|
|
175
217
|
if (resume !== undefined && harness === 'codex') words.push('resume');
|
|
176
218
|
words.push(...APPROVAL[harness][set(session.approval) ? session.approval : DEFAULT_APPROVAL]);
|
|
219
|
+
// Codex 0.157 shares one background server between sessions by default, and
|
|
220
|
+
// a resume through it was seen to fail; without it Codex runs as 0.156 did
|
|
221
|
+
// (tech notes, section 3, #330). Codex refuses the flag twice, so the user's
|
|
222
|
+
// own wins.
|
|
223
|
+
if (harness === 'codex' && !setsNoDaemon(session)) words.push(NO_DAEMON);
|
|
177
224
|
|
|
178
225
|
if (harness === 'claude') {
|
|
179
226
|
// The name is the address other Claude sessions write to, so it goes on
|
package/src/up.js
CHANGED
|
@@ -377,13 +377,13 @@ function launchFor(bots, bot, session, harness, home, workDir, resume, held) {
|
|
|
377
377
|
// through the tab's shell a character at a time.
|
|
378
378
|
const promptFile = prompt === undefined || isShortPrompt(prompt) ? undefined : promptPath(bots, bot.name, session.name);
|
|
379
379
|
// A new conversation is given a new name. A resume goes on under the one the
|
|
380
|
-
// kit gave it, and
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
380
|
+
// kit gave it, and gets a new one when the book `held` none of the kit's own:
|
|
381
|
+
// `--resume <id> -n <name>` renames the conversation, proven live (#319), so
|
|
382
|
+
// a session still under the shared `<bot>.<session>` moves to an address of
|
|
383
|
+
// its own here.
|
|
384
384
|
const address = harness !== 'claude' ? undefined
|
|
385
|
-
: resume
|
|
386
|
-
:
|
|
385
|
+
: resume !== undefined && isAddressOf(bot.name, session.name, held) ? held
|
|
386
|
+
: addressOf(bot.name, session.name);
|
|
387
387
|
const line = launchCommand(session, {
|
|
388
388
|
harness,
|
|
389
389
|
home,
|