@assuredloop/orca-bot-kit 0.25.4 → 0.26.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 +27 -10
- package/SETUP.md +33 -13
- package/package.json +4 -3
- package/rules/limits.md +3 -3
- package/rules/mail.md +4 -0
- package/skills/obk-bot-building/SKILL.md +29 -18
- package/src/book.js +3 -0
- package/src/bot.js +61 -6
- package/src/cli.js +237 -129
- package/src/commands.js +74 -0
- package/src/health.js +9 -3
- package/src/hook-trust.js +179 -0
- package/src/hooks.js +11 -0
- package/src/launch.js +25 -0
- package/src/orca.js +15 -1
- package/src/permissions.js +81 -64
- package/src/temp.js +153 -30
- package/src/up.js +4 -1
package/README.md
CHANGED
|
@@ -128,8 +128,8 @@ obk up --bots /path/to/my-bots
|
|
|
128
128
|
that file and the rule units, `CLAUDE.md` as a symlink to it, and a `.gitignore`
|
|
129
129
|
for `work/`.
|
|
130
130
|
`session add` writes one session into `bot.yaml`: its harness (the bot's unless
|
|
131
|
-
it says otherwise), model, effort, context window,
|
|
132
|
-
work dir and any extra arguments for the harness. A start prompt is either text
|
|
131
|
+
it says otherwise), model, effort, context window, start prompt,
|
|
132
|
+
work dir and any extra arguments for the harness, and the approval level. A start prompt is either text
|
|
133
133
|
(`--prompt`) or, when it is long, a file in the bot home the session points at
|
|
134
134
|
(`--prompt-file prompts/reviewer.md`), and it reaches the harness as written,
|
|
135
135
|
apart from two things the kit does on purpose: blank space at either end is
|
|
@@ -138,7 +138,18 @@ note about it. Anything you leave out is the
|
|
|
138
138
|
harness's own default; the kit names no model of its own. The approval level is
|
|
139
139
|
`auto` — the harness's real auto mode — unless you ask for `ask` or, in those
|
|
140
140
|
words, `dangerously-skip`
|
|
141
|
-
([ADR 0015](docs/adr/0015-three-approval-levels-auto-by-default.md)).
|
|
141
|
+
([ADR 0015](docs/adr/0015-three-approval-levels-auto-by-default.md)). Only
|
|
142
|
+
`obk permission approval` changes it, after your yes: `session add` and
|
|
143
|
+
`session change` take no approval, and refuse an extra argument that sets one
|
|
144
|
+
([ADR 0037](docs/adr/0037-permission-changes-and-risky-operations-have-commands-of-their-own.md)).
|
|
145
|
+
|
|
146
|
+
Every bot gets the kit's default permission rules, written by the kit with
|
|
147
|
+
nobody asked: its own commands for this bots folder, reading a long message,
|
|
148
|
+
`git add` and `git commit`, and Orca's `orca orchestration check --run`
|
|
149
|
+
([ADR 0036](docs/adr/0036-the-kit-writes-every-bots-default-permission-rules.md)).
|
|
150
|
+
`obk permission`, `obk retire`, `obk pause` and `obk init` are not in the set,
|
|
151
|
+
and keep your yes. A rule beyond the set is written by `obk permission allow`,
|
|
152
|
+
after your yes to the exact rule.
|
|
142
153
|
|
|
143
154
|
Neither command touches Orca. `obk up` is what makes it all real there: an Orca
|
|
144
155
|
project per bot, a tab per session, each started at the bot home with its own
|
|
@@ -443,6 +454,11 @@ Bot Father does these for you when you ask; these are the commands it runs.
|
|
|
443
454
|
|
|
444
455
|
```sh
|
|
445
456
|
obk bot change --bots /path/to/my-bots --bot api-bot --charter "…"
|
|
457
|
+
obk bot change --bots /path/to/my-bots --bot api-bot --role-cap reviewer=2
|
|
458
|
+
obk permission allow --bots /path/to/my-bots --bot api-bot --rule 'Bash(gh pr merge:*)'
|
|
459
|
+
obk permission disallow --bots /path/to/my-bots --bot api-bot --rule 'Bash(gh pr merge:*)'
|
|
460
|
+
obk permission approval --bots /path/to/my-bots --bot api-bot --session daily --approval ask
|
|
461
|
+
obk permission approval --bots /path/to/my-bots --bot api-bot --temps --approval dangerously-skip
|
|
446
462
|
obk session change --bots /path/to/my-bots --bot api-bot --session daily --model opus
|
|
447
463
|
obk skills remove --bots /path/to/my-bots --bot api-bot --skill kit:obk-tdd
|
|
448
464
|
obk pause --bots /path/to/my-bots --bot api-bot [--session daily]
|
|
@@ -643,13 +659,14 @@ npm run mutate # the mutation audit, on what your branch changed
|
|
|
643
659
|
|
|
644
660
|
The tests come in two layers, and every test file belongs to one of them.
|
|
645
661
|
|
|
646
|
-
`npm test` is `test/*.test.js`: unit tests and
|
|
647
|
-
throwaway folder, with a fake `orca` on PATH. It
|
|
648
|
-
[GitHub Actions](.github/workflows/ci.yml) runs it on
|
|
649
|
-
into shards that run side by side, on Node 25.8.0, the
|
|
650
|
-
runs every shard on 25.8.0 and again on 24.21.0, the
|
|
651
|
-
promises users, with only the kit's own dependencies
|
|
652
|
-
is published.
|
|
662
|
+
`npm test` is `test/*.test.js` and `test/dev/*.test.js`: unit tests and
|
|
663
|
+
end-to-end runs of the CLI in a throwaway folder, with a fake `orca` on PATH. It
|
|
664
|
+
needs nothing but Node, so [GitHub Actions](.github/workflows/ci.yml) runs it on
|
|
665
|
+
every pull request, split into shards that run side by side, on Node 25.8.0, the
|
|
666
|
+
current line. A release runs every shard on 25.8.0 and again on 24.21.0, the
|
|
667
|
+
floor `engines.node` promises users, with only the kit's own dependencies
|
|
668
|
+
installed, before anything is published. The floor leaves out `test/dev/`, the
|
|
669
|
+
tests that need a development tool.
|
|
653
670
|
|
|
654
671
|
`npm run test:system` is `test/system/*.test.js`: the real `obk` against the
|
|
655
672
|
real Orca and the real harnesses on your own machine. No CI runner can do that,
|
package/SETUP.md
CHANGED
|
@@ -128,11 +128,12 @@ tab, which is a plain shell for work across the whole fleet.
|
|
|
128
128
|
Read everything it prints. Three parts of it matter to them:
|
|
129
129
|
|
|
130
130
|
- **what it created** — say it in a sentence, not as a file listing;
|
|
131
|
-
- **the permission rules it
|
|
132
|
-
|
|
133
|
-
bots folder, and its commits
|
|
134
|
-
|
|
135
|
-
`
|
|
131
|
+
- **the permission rules it wrote**: the kit's default set, so auto mode does
|
|
132
|
+
not stop Bot Father for the kit's own commands, reading a long message
|
|
133
|
+
beside the bots folder, and its commits. The kit writes this set for every
|
|
134
|
+
bot, with nobody asked. Say in a sentence what it allows, and that
|
|
135
|
+
`obk permission`, `obk retire`, `obk pause` and `obk init` are not in it and
|
|
136
|
+
keep their yes;
|
|
136
137
|
- **anything it says about Orca's own default launch arguments.** Orca adds
|
|
137
138
|
these to every agent it launches, relaunches and resumes. When they carry a
|
|
138
139
|
permission bypass, every session runs in that mode whatever approval level the
|
|
@@ -228,8 +229,8 @@ home. The kit never makes a git worktree, so
|
|
|
228
229
|
`2. New worktree` is never the answer.
|
|
229
230
|
|
|
230
231
|
A bot's own temporary sessions are answered by their maker, through the kit, so
|
|
231
|
-
that
|
|
232
|
-
tab. On Codex's hooks review, the maker runs
|
|
232
|
+
that a narrow permission rule of the kit's default set allows it rather than a
|
|
233
|
+
rule to type into any tab. On Codex's hooks review, the maker runs
|
|
233
234
|
`obk temp trust-hooks --bots <their path> --name <session>`. On Claude Code's
|
|
234
235
|
`Teach auto mode` screen, it runs `obk temp answer --bots <their path> --name <session>`.
|
|
235
236
|
That command reads the screen and answers only when it holds one of the two
|
|
@@ -237,16 +238,35 @@ shapes in the table exactly as the kit knows it: Esc for the 2.1.283 form, and
|
|
|
237
238
|
**2. Not now** for the 2.1.289 list. On the list it sends the arrows, reads the
|
|
238
239
|
screen again, and sends the return only with the selection on **2. Not now**.
|
|
239
240
|
It refuses any other screen, types nothing then, and prints what it saw.
|
|
240
|
-
Afterwards it checks that the screen has gone.
|
|
241
|
-
|
|
242
|
-
`<kit>`, as the command's own
|
|
241
|
+
Afterwards it checks that the screen has gone. The kit's default set allows
|
|
242
|
+
both commands for every bot, so there is nothing to ask the user. The rules
|
|
243
|
+
are these, with the kit's full CLI path for `<kit>`, as the command's own
|
|
244
|
+
output prints it:
|
|
243
245
|
|
|
244
246
|
```text
|
|
245
|
-
Bash(<kit> temp answer
|
|
247
|
+
Bash(<kit> temp answer --bots <their path>:*)
|
|
248
|
+
Bash(<kit> temp trust-hooks --bots <their path>:*)
|
|
246
249
|
```
|
|
247
250
|
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
A long-lived session's two screens go through the kit as well, not through the
|
|
252
|
+
keys. On Codex's hooks review, run
|
|
253
|
+
`obk session trust-hooks --bots <their path> --bot <bot> --session <session>`.
|
|
254
|
+
On Claude Code's `Teach auto mode` screen, run
|
|
255
|
+
`obk session answer --bots <their path> --bot <bot> --session <session>`.
|
|
256
|
+
A long-lived session is Bot Father's, so run them from outside the fleet's tabs,
|
|
257
|
+
as you do here, or from a Bot Father session. A session of any other bot is
|
|
258
|
+
refused. They make the same checks as the temp commands. Before either
|
|
259
|
+
trust-hooks command trusts hooks, the kit checks that the hooks on the review
|
|
260
|
+
are its own: the bot's `.codex/hooks.json` holds only the kit's hooks, and the
|
|
261
|
+
count on the screen is the number of the kit's hooks that Codex does not trust
|
|
262
|
+
yet. When it refuses, it says what it saw: type nothing, and tell them what it
|
|
263
|
+
said. Use the keys in the table for the screens the kit does not answer.
|
|
264
|
+
The kit reads Codex's trust from the caller's `CODEX_HOME`, else `~/.codex`;
|
|
265
|
+
a bot run under another `CODEX_HOME` is outside what the kit can see.
|
|
266
|
+
The kit also records the extra arguments it launched each session with, and
|
|
267
|
+
refuses when they mention hooks, or when there is no record. A Codex that
|
|
268
|
+
someone started again by hand in that tab, with other flags, is outside what
|
|
269
|
+
the kit records.
|
|
250
270
|
|
|
251
271
|
**Anything you do not recognise: type nothing.** Tell them what is on the
|
|
252
272
|
screen and which tab it is in, and wait. A keypress into a menu you have not read
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assuredloop/orca-bot-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,8 +23,9 @@
|
|
|
23
23
|
"SETUP.md"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"test": "node --test test/*.test.js",
|
|
27
|
-
"test:shard": "node --test --test-shard=$SHARD test/*.test.js",
|
|
26
|
+
"test": "node --test test/*.test.js test/dev/*.test.js",
|
|
27
|
+
"test:shard": "node --test --test-shard=$SHARD test/*.test.js test/dev/*.test.js",
|
|
28
|
+
"test:floor": "node --test --test-shard=$SHARD test/*.test.js",
|
|
28
29
|
"test:system": "node scripts/test-system.js",
|
|
29
30
|
"mutate": "node scripts/mutate.js"
|
|
30
31
|
},
|
package/rules/limits.md
CHANGED
|
@@ -17,6 +17,6 @@ publishing, releasing, spending money, anything another person receives.
|
|
|
17
17
|
When something you were told to use is missing (a model, a tool, a file), say
|
|
18
18
|
so and ask. Quietly using a different one hides the change.
|
|
19
19
|
|
|
20
|
-
Permission rules
|
|
21
|
-
after the user's yes to
|
|
22
|
-
|
|
20
|
+
Permission rules and approvals are the kit's to write: its default set at once,
|
|
21
|
+
anything else after the user's yes to it, by `"${OBK_CLI:-obk}" permission allow`,
|
|
22
|
+
`disallow` or `approval`. Never edit one in or out yourself, Bot Father included.
|
package/rules/mail.md
CHANGED
|
@@ -8,6 +8,10 @@ To reach another session, ask the kit for the road rather than guessing an
|
|
|
8
8
|
address: `"${OBK_CLI:-obk}" message to --bots <bots> --to <bot>/<session>`. It
|
|
9
9
|
answers with the address and the command that carries it.
|
|
10
10
|
|
|
11
|
+
If your harness refuses a message, do not send it again by another road. Tell
|
|
12
|
+
your maker or your user, with the harness's reason. A refusal can mean a missing
|
|
13
|
+
permission rule, which they can add through the kit after the user's yes.
|
|
14
|
+
|
|
11
15
|
Mail is queued, not an interruption. Read it when you finish what you are on.
|
|
12
16
|
|
|
13
17
|
Ask for a reply when you need one, and send one when you were asked for one.
|
|
@@ -194,7 +194,7 @@ The kit's command line does the writing, and the files belong to the user:
|
|
|
194
194
|
source add` records where online skills come from and `obk skills fetch`
|
|
195
195
|
clones them, `obk skills add` puts one on a bot, `obk skills build` links
|
|
196
196
|
them, and `obk up` opens what is missing in Orca. `obk bot change` gives a
|
|
197
|
-
bot a new charter, `obk session change` changes a session's settings, and
|
|
197
|
+
bot a new charter or a role's cap, `obk session change` changes a session's settings, and
|
|
198
198
|
`obk skills remove` takes a skill off a list (then `obk skills build`). `obk
|
|
199
199
|
pause` stops a bot or a session for now and `obk unpause` brings it back;
|
|
200
200
|
`obk retire` ends one. After `obk up`, `obk restart` or `obk unpause`, read
|
|
@@ -206,16 +206,15 @@ Run `obk --help` for the flags of the version actually installed rather than
|
|
|
206
206
|
trusting a line you remember.
|
|
207
207
|
|
|
208
208
|
A bot needs a few permission rules so that auto mode, or Codex's sandbox and
|
|
209
|
-
reviewer, does not stop it for what the kit's own rules tell it to do:
|
|
210
|
-
|
|
211
|
-
its commits.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
rule into a settings or rules file by hand.
|
|
209
|
+
reviewer, does not stop it for what the kit's own rules tell it to do: the
|
|
210
|
+
kit's own commands, reading a long message kept beside the bots folder, and
|
|
211
|
+
its commits. The kit writes this default set itself, with nobody asked:
|
|
212
|
+
`obk bot create`, `obk up` and `obk rules build` add each default rule a bot
|
|
213
|
+
does not have yet to its `bot.yaml` and its settings, or for Codex its
|
|
214
|
+
`.codex/rules/obk.rules`, and say which rules they wrote. The set leaves out
|
|
215
|
+
the commands that keep the user's yes: `obk permission`, `obk retire`, `obk
|
|
216
|
+
pause` and `obk init`. Never write a permission rule into a settings or rules
|
|
217
|
+
file by hand.
|
|
219
218
|
|
|
220
219
|
The charter decides what else the bot needs. What it lets the bot do without
|
|
221
220
|
asking, such as merging pull requests, auto mode or Codex's sandbox can still
|
|
@@ -228,14 +227,14 @@ Spell them in Claude Code's form for a Codex bot too, `Bash(<command>:*)`: the
|
|
|
228
227
|
kit writes Codex's own form of each, and says which ones Codex has none for,
|
|
229
228
|
such as an `Edit` rule or one exact command.
|
|
230
229
|
Show the user the list word for word, with a line on what each lets the bot do,
|
|
231
|
-
and only after their yes run `obk
|
|
232
|
-
yes to. On a no, run nothing. `obk bot change --charter` names the rules the
|
|
230
|
+
and only after their yes run `obk permission allow --rule <rule>`, once per
|
|
231
|
+
rule they said yes to. On a no, run nothing. `obk bot change --charter` names the rules the
|
|
233
232
|
bot is allowed now; say which of them the new charter no longer grants, show
|
|
234
233
|
each word for word, and ask whether to take it back. Only after their yes run
|
|
235
|
-
`obk
|
|
234
|
+
`obk permission disallow --rule <rule>`, once per rule, which takes it out of `bot.yaml`
|
|
236
235
|
and the bot's settings or Codex rules; on a no, run nothing, and it stays
|
|
237
236
|
allowed. A rule the user added to a settings file by hand is theirs to take
|
|
238
|
-
out; the kit refuses it. Keep
|
|
237
|
+
out; the kit refuses it, and it refuses a rule of its own default set too. Keep
|
|
239
238
|
each rule narrow: a program and what it does. The kit refuses a rule that lets
|
|
240
239
|
the bot run any command, a program with any arguments, or a shell or
|
|
241
240
|
interpreter with any arguments; a user who wants one for a bot adds it to that
|
|
@@ -331,9 +330,21 @@ into any tab. The same goes for Claude Code's `Teach auto mode` screen on a
|
|
|
331
330
|
temporary session you made: answer it with `obk temp answer --bots <bots>
|
|
332
331
|
--name <session>`. It answers only a shape in the table exactly as the kit
|
|
333
332
|
knows it (Esc on the 2.1.283 form, 2. Not now on the 2.1.289 list, the return
|
|
334
|
-
only after a second look), refuses any other screen, and checks that it went.
|
|
335
|
-
|
|
336
|
-
|
|
333
|
+
only after a second look), refuses any other screen, and checks that it went. The kit's
|
|
334
|
+
default set allows it, as it allows `obk temp trust-hooks`.
|
|
335
|
+
|
|
336
|
+
A long-lived session's two screens go through the kit too: Codex's hooks
|
|
337
|
+
review with `obk session trust-hooks --bots <bots> --bot <bot> --session
|
|
338
|
+
<session>`, and Claude Code's `Teach auto mode` screen with `obk session
|
|
339
|
+
answer --bots <bots> --bot <bot> --session <session>`. A long-lived session is
|
|
340
|
+
Bot Father's: the caller is a Bot Father session or the user, from outside the
|
|
341
|
+
fleet's tabs, and a session of any other bot is refused. They make the same
|
|
342
|
+
checks as the temp commands. Before either trust-hooks command trusts hooks,
|
|
343
|
+
it checks that the hooks on the review are the kit's own: the bot's
|
|
344
|
+
`.codex/hooks.json` holds only the kit's, and the count on the screen is the
|
|
345
|
+
number of the kit's hooks Codex does not trust yet. A refusal says what it
|
|
346
|
+
saw; then type nothing and take it to the user. The keys in the table are for
|
|
347
|
+
the screens the kit does not answer.
|
|
337
348
|
|
|
338
349
|
Where the kit says no session came up, the shell swallowed the launch line,
|
|
339
350
|
usually while it was asking its own question. Answer the shell, then close
|
package/src/book.js
CHANGED
|
@@ -28,6 +28,9 @@ const HEADER = `# What Orca calls this bot on this machine, and where each of it
|
|
|
28
28
|
# \`rules\` is a stamp of the bot's AGENTS.md as the session last read it, so a
|
|
29
29
|
# change to it after the session started can be told apart.
|
|
30
30
|
#
|
|
31
|
+
# \`launched_with\` is the extra arguments the kit typed on the session's last
|
|
32
|
+
# launch line, as bot.yaml's extra_args gave them then.
|
|
33
|
+
#
|
|
31
34
|
# \`retired\` holds what the book knew about each session \`obk retire\` took off
|
|
32
35
|
# the bot, with when, so the conversations it had are still accounted for.
|
|
33
36
|
#
|
package/src/bot.js
CHANGED
|
@@ -11,7 +11,7 @@ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSy
|
|
|
11
11
|
import os from 'node:os';
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { isDeepStrictEqual } from 'node:util';
|
|
14
|
-
import { parse, parseDocument, stringify } from 'yaml';
|
|
14
|
+
import { isSeq, parse, parseDocument, stringify } from 'yaml';
|
|
15
15
|
|
|
16
16
|
import { DEFAULT_APPROVAL, HARNESSES, harnessOf, sessionTrouble } from './launch.js';
|
|
17
17
|
|
|
@@ -161,6 +161,9 @@ export function readBot(home, name = path.basename(home)) {
|
|
|
161
161
|
allow: bot.allow,
|
|
162
162
|
// The roles its temporary sessions can be made in, judged by tempRoles.
|
|
163
163
|
...(bot.temp_roles === undefined ? {} : { temp_roles: bot.temp_roles }),
|
|
164
|
+
// The widest approval its temporary sessions may be made at, the user's yes
|
|
165
|
+
// kept by `permission approval --temps` (ADR 0037).
|
|
166
|
+
...(bot.temp_approval === undefined ? {} : { temp_approval: bot.temp_approval }),
|
|
164
167
|
// A paused bot is one `obk up` leaves closed; its sessions keep their book.
|
|
165
168
|
...(bot.paused === true ? { paused: true } : {}),
|
|
166
169
|
sessions: sessions.map((session) => {
|
|
@@ -278,10 +281,10 @@ export function changeBot(bots, bot, { charter }) {
|
|
|
278
281
|
/**
|
|
279
282
|
* The bot's `allow` list as it is, after refusing what `allowRules` or
|
|
280
283
|
* `disallowRules` would refuse: an empty rule, or a list already there that is
|
|
281
|
-
* not a list of rules. Asked before anything is written, so a refused
|
|
282
|
-
*
|
|
284
|
+
* not a list of rules. Asked before anything is written, so a refused
|
|
285
|
+
* `permission allow` or `permission disallow` changes nothing.
|
|
283
286
|
*/
|
|
284
|
-
export function allowedNow(bots, bot, rules, flag = '--
|
|
287
|
+
export function allowedNow(bots, bot, rules, flag = '--rule') {
|
|
285
288
|
if (rules.some((rule) => rule.trim() === '')) {
|
|
286
289
|
throw new Error(`${flag} is empty. Give it the exact permission rule the user said yes to, such as Bash(git add:*).`);
|
|
287
290
|
}
|
|
@@ -320,7 +323,7 @@ export function allowRules(bots, bot, rules, { write = true } = {}) {
|
|
|
320
323
|
* false it only refuses what the edit would refuse, and writes nothing.
|
|
321
324
|
*/
|
|
322
325
|
export function disallowRules(bots, bot, rules, { write = true } = {}) {
|
|
323
|
-
const { home, was } = allowedNow(bots, bot, rules
|
|
326
|
+
const { home, was } = allowedNow(bots, bot, rules);
|
|
324
327
|
const disallowed = [...new Set(rules)];
|
|
325
328
|
const allow = was.filter((rule) => !disallowed.includes(rule));
|
|
326
329
|
editBot(bots, bot, `take back ${disallowed.join(', ')} for ${bot}`, (doc) => doc.set('allow', allow), (before) => ({ ...before, allow }), write);
|
|
@@ -357,6 +360,58 @@ export function changeSession(bots, bot, name, settings) {
|
|
|
357
360
|
return { bot, home, session };
|
|
358
361
|
}
|
|
359
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Record the widest approval the bot's temporary sessions may be made at,
|
|
365
|
+
* `level`, as `temp_approval` (ADR 0037). Returns { bot, home, level }.
|
|
366
|
+
*/
|
|
367
|
+
export function setTempApproval(bots, bot, level) {
|
|
368
|
+
editBot(bots, bot, `let ${bot}'s temporary sessions be made at ${level}`, (doc) => doc.set('temp_approval', level), (was) => ({ ...was, temp_approval: level }));
|
|
369
|
+
return { bot, home: botDir(bots, bot), level };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Set the caps of roles in the bot's `temp_roles`: `caps` is a list of
|
|
374
|
+
* `[role, cap]`, a cap of undefined taking it off. A role written as a list of
|
|
375
|
+
* options becomes a mapping that holds that list as `options` beside its cap.
|
|
376
|
+
* A role the bot does not have is refused before anything is written. Returns
|
|
377
|
+
* { bot, home, caps }. With `write` false it only refuses what the edit would
|
|
378
|
+
* refuse, and writes nothing.
|
|
379
|
+
*/
|
|
380
|
+
export function setRoleCaps(bots, bot, caps, { write = true } = {}) {
|
|
381
|
+
const home = existingBot(bots, bot);
|
|
382
|
+
const roles = readBot(home, bot).temp_roles;
|
|
383
|
+
const file = path.join(home, BOT_YAML);
|
|
384
|
+
for (const [role] of caps) {
|
|
385
|
+
if (roles === null || typeof roles !== 'object' || Array.isArray(roles) || !Object.hasOwn(roles, role)) {
|
|
386
|
+
const has = roles !== null && typeof roles === 'object' && !Array.isArray(roles) ? Object.keys(roles) : [];
|
|
387
|
+
throw new Error(`${bot} has no temporary-session role called ${role} in ${file}${has.length === 0 ? ', and no temp_roles at all' : `. It has: ${has.join(', ')}`}. Nothing was changed.`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const capped = (written, cap) => {
|
|
391
|
+
const { cap: was, ...rest } = Array.isArray(written) ? { options: written } : written;
|
|
392
|
+
return cap === undefined ? rest : { ...rest, cap };
|
|
393
|
+
};
|
|
394
|
+
editBot(bots, bot, `set the caps of ${caps.map(([role]) => role).join(', ')}`, (doc) => {
|
|
395
|
+
for (const [role, cap] of caps) {
|
|
396
|
+
const node = doc.getIn(['temp_roles', role], true);
|
|
397
|
+
if (isSeq(node)) {
|
|
398
|
+
doc.setIn(['temp_roles', role], doc.createNode(capped(node.toJSON(), cap)));
|
|
399
|
+
} else if (cap === undefined) {
|
|
400
|
+
doc.deleteIn(['temp_roles', role, 'cap']);
|
|
401
|
+
} else {
|
|
402
|
+
doc.setIn(['temp_roles', role, 'cap'], cap);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}, (was) => ({
|
|
406
|
+
...was,
|
|
407
|
+
temp_roles: Object.fromEntries(Object.entries(was.temp_roles).map(([role, written]) => {
|
|
408
|
+
const asked = caps.findLast(([one]) => one === role);
|
|
409
|
+
return [role, asked === undefined ? written : capped(written, asked[1])];
|
|
410
|
+
})),
|
|
411
|
+
}), write);
|
|
412
|
+
return { bot, home, caps };
|
|
413
|
+
}
|
|
414
|
+
|
|
360
415
|
/**
|
|
361
416
|
* Mark the bot `bot`, or its session `name`, paused or not. Returns whether
|
|
362
417
|
* the file changed. A paused bot or session is one `obk up` leaves closed.
|
|
@@ -497,7 +552,7 @@ export const SESSION_FIELDS = [
|
|
|
497
552
|
];
|
|
498
553
|
|
|
499
554
|
/** Everything the top of a bot's own file can hold. */
|
|
500
|
-
const BOT_FIELDS = ['name', 'harness', 'charter', 'rules', 'skills', 'allow', 'sessions', 'paused', 'temp_roles'];
|
|
555
|
+
const BOT_FIELDS = ['name', 'harness', 'charter', 'rules', 'skills', 'allow', 'sessions', 'paused', 'temp_roles', 'temp_approval'];
|
|
501
556
|
|
|
502
557
|
/**
|
|
503
558
|
* The keys in a bot's file that the kit does not know, and so that nothing
|