cawdev-cli 0.9.0 → 1.0.0-beta
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 +4 -171
- package/lib/run-plugin.mjs +40 -0
- package/lib/usage-report.mjs +27 -0
- package/lib/version.mjs +48 -0
- package/package.json +1 -1
- package/runner/README.md +56 -0
- package/runner/attach.mjs +442 -1
- package/runner/banner.mjs +11 -1
- package/runner/bootstrap.mjs +70 -35
- package/runner/cawdev.mjs +215 -19
- package/runner/configure.mjs +412 -0
- package/runner/paths.mjs +254 -0
- package/runner/runner.mjs +829 -131
- package/runner/token-store.mjs +14 -2
package/README.md
CHANGED
|
@@ -1,175 +1,8 @@
|
|
|
1
1
|
# tools
|
|
2
|
-
|
|
3
|
-
Plain Node, **zero dependencies**, by design
|
|
2
|
+
# Cawdev CLI Runner
|
|
3
|
+
Plain Node, **zero dependencies**, by design : stdio JSON-RPC
|
|
4
4
|
and spawning processes are Node's home turf, and a file with no dependencies is
|
|
5
5
|
one you can read before running it against your repositories.
|
|
6
|
+
visit https://cawdev.com to learn more
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
`CAWDEV_PROJECT` from the environment or a `.env` at the repository root —
|
|
9
|
-
**read on every call**, so editing `.env` needs no restart.
|
|
10
|
-
|
|
11
|
-
Mint a token in the console under **Agent tokens**. It needs `roadmap:write`
|
|
12
|
-
and `changelog:write` on the project you are exporting.
|
|
13
|
-
|
|
14
|
-
## The generated files
|
|
15
|
-
|
|
16
|
-
`ROADMAP.md` and `CHANGELOG.md` at the repository root are **exports**. Editing
|
|
17
|
-
them by hand is lost at the next export. Change the entry in the console or
|
|
18
|
-
through MCP, then regenerate:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
node tools/roadmap/export.mjs cawdev
|
|
22
|
-
node tools/changelog/export.mjs cawdev
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Both are byte-stable: the same data produces the same bytes, so a regenerated
|
|
26
|
-
file shows a diff only when the roadmap actually changed. CI proves
|
|
27
|
-
export → import → export is a fixed point.
|
|
28
|
-
|
|
29
|
-
### Where a section goes in the file
|
|
30
|
-
|
|
31
|
-
An entry's `section` is a planning decision and lives in the database. The
|
|
32
|
-
**order** the sections appear in is prose layout, and lives beside the exporter
|
|
33
|
-
as `SECTION_ORDER` in `tools/roadmap/export.mjs`. `Considering` and `Declined`
|
|
34
|
-
are not in that list: they are derived from status by `sectionOf`, and always
|
|
35
|
-
come last.
|
|
36
|
-
|
|
37
|
-
A section that is not in `SECTION_ORDER` is **appended, and named in the note
|
|
38
|
-
the exporter prints** under its per-status counts, along with the number of
|
|
39
|
-
entries it holds. It is a note rather than a failure — a new phase is
|
|
40
|
-
legitimate, and an exporter that refused one would block the release that
|
|
41
|
-
introduced it — but it should not arrive unannounced. Silence is how the list
|
|
42
|
-
fell three sections behind and `"Roadmap"`, the fallback for an entry with no
|
|
43
|
-
section of its own, became a junk drawer holding eight built features (R45).
|
|
44
|
-
|
|
45
|
-
When you see the note: add the section to `SECTION_ORDER` in the position it
|
|
46
|
-
should read in, or give those entries a section that is already there. Sections
|
|
47
|
-
are renamed, merged and unfiled from the console's **Sections** dialog on the
|
|
48
|
-
roadmap board (R264), and that dialog cannot reach this file: after a rename,
|
|
49
|
-
update `SECTION_ORDER` too, or the note will list the new name.
|
|
50
|
-
|
|
51
|
-
## `tools/roadmap/import.mjs`
|
|
52
|
-
|
|
53
|
-
The one-time move from a hand-written `ROADMAP.md` into the platform, and the
|
|
54
|
-
other half of that fixed point.
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
node tools/roadmap/import.mjs cawdev --file ROADMAP.md
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
It is **idempotent enough to re-run after a partial failure**: entries that
|
|
61
|
-
already exist are updated rather than duplicated. It refuses to start when
|
|
62
|
-
preserving ids is impossible — ids are permanent, and silently renumbering them
|
|
63
|
-
would break every commit message that points at one.
|
|
64
|
-
|
|
65
|
-
## `roadmap.mjs` (repository root)
|
|
66
|
-
|
|
67
|
-
```sh
|
|
68
|
-
node roadmap.mjs # shape: ids unique, statuses legal, required fields present
|
|
69
|
-
node roadmap.mjs --live # also: SHIPPED versions are real tags, CODING and
|
|
70
|
-
# REVIEW branches exist, and the file matches the database
|
|
71
|
-
node roadmap.mjs --live --project cawdev # when CAWDEV_PROJECT is not set
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Both forms run in CI. The shape checks catch what a review forgets — an entry
|
|
75
|
-
that says `CODING` without naming a branch, an entry that says `MERGED` without
|
|
76
|
-
naming the merge, a `Related:` pointing at nothing. `--live` catches the claims a
|
|
77
|
-
file cannot check about itself: that a version someone wrote down was in fact
|
|
78
|
-
tagged, and that the file is still the export it says it is. A `REVIEW` entry's
|
|
79
|
-
branch is checked like a `CODING` one — the status claims there is something to
|
|
80
|
-
read. A `MERGED` entry is checked against neither tags nor branches, because its
|
|
81
|
-
branch is meant to have been deleted.
|
|
82
|
-
|
|
83
|
-
That last one re-runs `tools/roadmap/export.mjs` into a temporary file and
|
|
84
|
-
compares the bytes. It goes through the exporter rather than rendering a second
|
|
85
|
-
copy of it, so the two cannot drift apart. A difference fails and names the
|
|
86
|
-
entries — missing here, missing there, or changed — with the remedy. If every
|
|
87
|
-
entry agrees and the bytes still differ, the preamble or the section layout was
|
|
88
|
-
edited by hand.
|
|
89
|
-
|
|
90
|
-
It needs a `CAWDEV_TOKEN` and a project. Without them it prints a note saying it
|
|
91
|
-
was skipped and the git checks still run; a check that cannot answer says so
|
|
92
|
-
rather than passing (R41). If the token is set and the platform rejects it or is
|
|
93
|
-
down, that is not "cannot answer" — it fails, with the API's own message.
|
|
94
|
-
|
|
95
|
-
## Tests
|
|
96
|
-
|
|
97
|
-
```sh
|
|
98
|
-
node --test "tools/**/*.test.mjs"
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
`tools/lib/roadmap-format.test.mjs` covers the parse/render round trip. If those
|
|
102
|
-
two stop agreeing, the generated file churns on every export and its diff stops
|
|
103
|
-
meaning "the roadmap changed".
|
|
104
|
-
|
|
105
|
-
`tools/lib/usage.test.mjs` covers what a turn reports. One of its tests asserts
|
|
106
|
-
that **no dollar figure reaches a transcript**: the CLI quotes list prices, and
|
|
107
|
-
a subscription does not work that way.
|
|
108
|
-
|
|
109
|
-
`tools/lib/tool-rules.test.mjs` covers the matcher for what a run may do (R51).
|
|
110
|
-
Every assertion of `false` in it is asserting that somebody gets asked a
|
|
111
|
-
question they may have answered before — the cheap failure. The expensive one is
|
|
112
|
-
a `true` nobody intended.
|
|
113
|
-
|
|
114
|
-
`tools/mcp/approve.test.mjs` drives the real server over stdio against a faked
|
|
115
|
-
platform, and pins the shape Claude Code reads back: a permission decision is
|
|
116
|
-
JSON in the result text, and getting it wrong does not fail loudly — it stops a
|
|
117
|
-
session, which is the failure R51 exists to end.
|
|
118
|
-
|
|
119
|
-
`tools/runner/control.test.mjs` covers the socket a daemon offers (R52) on a
|
|
120
|
-
real socket, including the backlog somebody attaching to an hour-old session
|
|
121
|
-
needs, and that an unknown command is ignored rather than obeyed — that socket
|
|
122
|
-
is a read-only view on purpose.
|
|
123
|
-
|
|
124
|
-
`tools/runner/attach.test.mjs` covers the rendering arithmetic, which is where a
|
|
125
|
-
terminal UI goes wrong silently: transcripts carry the agent's ANSI colour, and
|
|
126
|
-
measuring it as plain text wraps the pane into nonsense.
|
|
127
|
-
|
|
128
|
-
`tools/runner/workspaces.test.mjs` is R47 against the real daemon: two coding
|
|
129
|
-
runs on one project, at the same time, in different checkouts, each reporting
|
|
130
|
-
which. Getting that gate wrong is expensive in both directions — too tight and a
|
|
131
|
-
machine with three checkouts still runs one session, too loose and two agents
|
|
132
|
-
share a working copy.
|
|
133
|
-
|
|
134
|
-
`tools/runner/test-platform.mjs` is the cawdev those two tests register with.
|
|
135
|
-
Not a test itself, and not production code: it is a fake platform with a queue,
|
|
136
|
-
shared because two fakes drift.
|
|
137
|
-
|
|
138
|
-
`tools/runner/daemon-boot.test.mjs` starts the **real daemon** against a faked
|
|
139
|
-
platform and a fake agent command. It is the only test of the first ten seconds
|
|
140
|
-
— registering, the R51 permission-flag probe, opening the socket, and removing
|
|
141
|
-
it again on the way out — a path that otherwise needs a `runner:operate` token
|
|
142
|
-
to reach at all.
|
|
143
|
-
|
|
144
|
-
## `tools/mcp/`
|
|
145
|
-
|
|
146
|
-
The MCP server an agent talks to — zero dependencies, stdio JSON-RPC.
|
|
147
|
-
`tools/mcp/README.md` covers setting it up in a repository, and is also written
|
|
148
|
-
for the agent that reads it: it teaches the working method (branch first,
|
|
149
|
-
`CODING` names the branch before the first commit, `roadmap_where` when in
|
|
150
|
-
doubt).
|
|
151
|
-
|
|
152
|
-
`tools/mcp/smoke.mjs` drives the server the way a client does — spawn, write
|
|
153
|
-
lines to stdin, read lines from stdout — because the parts most likely to break
|
|
154
|
-
are the transport and the framing. CI runs it against the compose stack.
|
|
155
|
-
|
|
156
|
-
## `tools/runner/`
|
|
157
|
-
|
|
158
|
-
The daemon that claims queued runs and spawns a real agent CLI in a working
|
|
159
|
-
copy. `tools/runner/README.md` covers running one.
|
|
160
|
-
|
|
161
|
-
## `tools/console/`
|
|
162
|
-
|
|
163
|
-
`console-smoke.mjs` is the end-to-end test for the console's half of the loop
|
|
164
|
-
(R12): start a run on an entry, watch the messages, answer the question from the
|
|
165
|
-
inbox, see the finish report carrying the branch — all over the endpoints the
|
|
166
|
-
browser calls, on a real session cookie. Point it at a **scratch project**: it
|
|
167
|
-
creates an entry, cancels any live run, and declines the entry afterwards.
|
|
168
|
-
|
|
169
|
-
```sh
|
|
170
|
-
node tools/console/console-smoke.mjs scratch
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Unlike everything else here it signs in rather than using `CAWDEV_TOKEN`, because
|
|
174
|
-
starting a run and answering a question are both a *person's* acts — an agent
|
|
175
|
-
cannot do either, so the test cannot bootstrap itself from a token.
|
|
8
|
+
https://github.com/4dali/cawdev-cli
|
package/lib/run-plugin.mjs
CHANGED
|
@@ -92,6 +92,46 @@ export function agentFile(agent) {
|
|
|
92
92
|
return `${head.join('\n')}\n${agent.body ?? ''}\n`;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Antigravity's own name for the same idea — R279. `agy plugin install
|
|
97
|
+
* <directory>` reads almost the same shape Claude Code's plugin does
|
|
98
|
+
* (`agents/*.md`, same frontmatter, same `agentFile()` below), confirmed by
|
|
99
|
+
* hand against the real CLI (v1.2.6): the one difference is where the
|
|
100
|
+
* manifest lives, `plugin.json` at the plugin's own root rather than under
|
|
101
|
+
* `.claude-plugin/`. No `skills/` here — R278 already inlines those into the
|
|
102
|
+
* prompt for this agent, since it has no lazy `Skill` tool to fetch one
|
|
103
|
+
* through a plugin the way Claude Code does.
|
|
104
|
+
*
|
|
105
|
+
* <p>A fixed name, like `registerAntigravityMcp`'s `cawdev` server: `agy
|
|
106
|
+
* plugin install` is machine-wide state, one project's experts at a time, so
|
|
107
|
+
* the runner removes whatever this name currently holds and reinstalls
|
|
108
|
+
* fresh before every spawn rather than trying to reconcile two projects'
|
|
109
|
+
* agents under one name.
|
|
110
|
+
*/
|
|
111
|
+
export const ANTIGRAVITY_EXPERTS_PLUGIN = 'cawdev-experts';
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Writes the run's experts as an Antigravity plugin directory — R279's half
|
|
115
|
+
* of `writeRunPlugin`. Returns the directory, or null when nothing was
|
|
116
|
+
* turned on, same contract.
|
|
117
|
+
*/
|
|
118
|
+
export async function writeAntigravityExpertsPlugin(directory, expertAgents) {
|
|
119
|
+
if (!expertAgents.length) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const root = join(directory, ANTIGRAVITY_EXPERTS_PLUGIN);
|
|
123
|
+
await mkdir(join(root, 'agents'), { recursive: true });
|
|
124
|
+
await writeFile(join(root, 'plugin.json'), JSON.stringify({
|
|
125
|
+
name: ANTIGRAVITY_EXPERTS_PLUGIN,
|
|
126
|
+
description: 'What this project turned on in cawdev.',
|
|
127
|
+
version: '1.0.0',
|
|
128
|
+
}, null, 2));
|
|
129
|
+
for (const agent of expertAgents) {
|
|
130
|
+
await writeFile(join(root, 'agents', `${agent.key}.md`), agentFile(agent));
|
|
131
|
+
}
|
|
132
|
+
return root;
|
|
133
|
+
}
|
|
134
|
+
|
|
95
135
|
export function skillFile(skill) {
|
|
96
136
|
const head = [
|
|
97
137
|
'---',
|
package/lib/usage-report.mjs
CHANGED
|
@@ -112,6 +112,33 @@ export function parseUsage(text, now = new Date()) {
|
|
|
112
112
|
if (!text) {
|
|
113
113
|
return [];
|
|
114
114
|
}
|
|
115
|
+
|
|
116
|
+
// Handle Agy output format
|
|
117
|
+
if (String(text).includes('Limit Remaining')) {
|
|
118
|
+
const windows = [];
|
|
119
|
+
for (const raw of String(text).split('\n')) {
|
|
120
|
+
const line = raw.trim();
|
|
121
|
+
if (!line || line.startsWith('Quota:')) continue;
|
|
122
|
+
|
|
123
|
+
const match = /^(.*?)\s+(Weekly|Five Hour)\s+Limit Remaining\s+(\d{1,3})%\s+(.*Z)$/i.exec(line);
|
|
124
|
+
if (!match) continue;
|
|
125
|
+
|
|
126
|
+
const model = match[1].trim();
|
|
127
|
+
const kind = match[2].toLowerCase() === 'weekly' ? 'WEEKLY' : 'FIVE_HOUR';
|
|
128
|
+
const remainingPercent = Number(match[3]);
|
|
129
|
+
const resetsAt = new Date(match[4].trim());
|
|
130
|
+
|
|
131
|
+
windows.push({
|
|
132
|
+
kind,
|
|
133
|
+
model: model,
|
|
134
|
+
percent: 100 - remainingPercent,
|
|
135
|
+
resetsAt: isNaN(resetsAt.getTime()) ? null : resetsAt,
|
|
136
|
+
label: line,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return windows;
|
|
140
|
+
}
|
|
141
|
+
|
|
115
142
|
const windows = [];
|
|
116
143
|
for (const raw of String(text).split('\n')) {
|
|
117
144
|
const line = raw.trim();
|
package/lib/version.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// R283 — the CLI's own version, and whether it is old enough to matter.
|
|
2
|
+
//
|
|
3
|
+
// Zero dependencies, like everything in tools/: no semver package, just the
|
|
4
|
+
// three numbers this project actually uses (`tools/package.json`'s own
|
|
5
|
+
// version is always `major.minor.patch`, and so is what the platform sends
|
|
6
|
+
// back on `/api/health`).
|
|
7
|
+
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
/** This CLI's own version, read from `tools/package.json`. */
|
|
15
|
+
export async function cliVersion() {
|
|
16
|
+
const path = join(HERE, '..', 'package.json');
|
|
17
|
+
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
18
|
+
return parsed.version;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* `major.minor.patch` as three numbers, or null for anything that is not
|
|
23
|
+
* shaped that way — a pre-release suffix, a build nobody tagged, garbage from
|
|
24
|
+
* a setting typed by hand. Null is "cannot compare", never "oldest possible":
|
|
25
|
+
* refusing a version we cannot parse would turn a typo in a setting into
|
|
26
|
+
* every runner on the platform refusing to boot.
|
|
27
|
+
*/
|
|
28
|
+
function parts(version) {
|
|
29
|
+
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(String(version ?? '').trim());
|
|
30
|
+
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether `version` is older than `minimum`. False when either cannot be
|
|
35
|
+
* parsed, or when `minimum` is blank — "cannot tell" and "no requirement" are
|
|
36
|
+
* both the safe reading here, matching `PlatformSettingService`'s own
|
|
37
|
+
* treatment of a blank `minimum_cli_version`.
|
|
38
|
+
*/
|
|
39
|
+
export function isBelow(version, minimum) {
|
|
40
|
+
if (!minimum || !String(minimum).trim()) return false;
|
|
41
|
+
const have = parts(version);
|
|
42
|
+
const need = parts(minimum);
|
|
43
|
+
if (!have || !need) return false;
|
|
44
|
+
for (let i = 0; i < 3; i += 1) {
|
|
45
|
+
if (have[i] !== need[i]) return have[i] < need[i];
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
package/package.json
CHANGED
package/runner/README.md
CHANGED
|
@@ -76,6 +76,7 @@ cawdev --config <path> the runner config to start a daemon from
|
|
|
76
76
|
cawdev --no-start attach only; never launch a daemon
|
|
77
77
|
cawdev --watch-only do not sign in; watch without being able to act
|
|
78
78
|
cawdev --leave-running leave the daemon running when you quit
|
|
79
|
+
cawdev --version this CLI's version, and the platform's
|
|
79
80
|
```
|
|
80
81
|
|
|
81
82
|
**Quitting stops the daemon** — R123. One word starts the machine and the
|
|
@@ -94,6 +95,59 @@ process and one terminal**, which is what you want when the daemon should die
|
|
|
94
95
|
with the window — there `q` stops it, and asks first when sessions are live.
|
|
95
96
|
`node runner.mjs attach` joins a daemon started elsewhere.
|
|
96
97
|
|
|
98
|
+
### `c`, `/config`, `cawdev config` — one change, not the whole walk
|
|
99
|
+
|
|
100
|
+
`cawdev --setup` (above) asks everything a fresh machine needs at once. Once a
|
|
101
|
+
machine is configured, most changes are smaller than that. **Inside the
|
|
102
|
+
terminal, press `c`** (or type `/config`): a picker over what this machine does
|
|
103
|
+
— add a project, add a workspace, each agent with its current state ("Disable
|
|
104
|
+
claude", "Enable agy"), the console-rules switch, and the config itself with the
|
|
105
|
+
token cut short. Every row is one of the shell commands below, driven through
|
|
106
|
+
the terminal's own line editor and picker; `esc` anywhere in a step changes
|
|
107
|
+
nothing. The screen edits the file the daemon says it booted from (the hello
|
|
108
|
+
carries `configPath` since R288), so an older daemon is told to restart rather
|
|
109
|
+
than guessed at, and adding a project asks for a `/login` first because it
|
|
110
|
+
widens the machine's token.
|
|
111
|
+
|
|
112
|
+
**Choosing where a checkout goes** (R289) is a picker before it is a line: the
|
|
113
|
+
folder beside the checkouts this machine already serves, the default
|
|
114
|
+
`~/cawdev/<slug>`, for a second workspace `<checkout>-2` — each row saying what
|
|
115
|
+
is there now ("new folder — will clone here", "already a checkout of cawdev",
|
|
116
|
+
"a checkout of …/else, not cawdev"). The last row opens a line **pre-filled**
|
|
117
|
+
with the first suggestion; `tab` completes directories from disk the way a
|
|
118
|
+
shell does, `~` expands, and a preview under the line says what the path is as
|
|
119
|
+
you type. Before anything is cloned the URL and the path are confirmed once; a
|
|
120
|
+
checkout of the same repository already at the path is taken as it is, with no
|
|
121
|
+
question; anything else that exists is refused in words. `paths.mjs` is that
|
|
122
|
+
logic, shared with the shell form below so the two doors agree. The shell form
|
|
123
|
+
is for scripts and for a machine with no daemon to attach to:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
cawdev config a menu, the same Select widget as everywhere else
|
|
127
|
+
cawdev config add-project serve one more project you can write to
|
|
128
|
+
cawdev config add-workspace another checkout for a project already served
|
|
129
|
+
cawdev config agent enable|disable <claude|agy>
|
|
130
|
+
cawdev config rules on|off accept permission rules from the console — R126
|
|
131
|
+
cawdev config show this machine's config, token redacted
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Every one of these writes `runner.config.json` and nothing else. Adding a
|
|
135
|
+
project widens the machine's existing `runner:operate` token in place
|
|
136
|
+
(`PUT /api/tokens/{id}/grants`) rather than minting a second one — the id
|
|
137
|
+
travels beside the secret since this card, and a machine set up before it
|
|
138
|
+
falls back to a lookup by label the first time this runs, after which it
|
|
139
|
+
remembers.
|
|
140
|
+
|
|
141
|
+
Adding a project or a workspace needs a restart to take effect, same as any
|
|
142
|
+
other change to `"projects"` — a live daemon says so. Enabling or disabling an
|
|
143
|
+
agent and turning `rules` on or off do **not**: `cawdev config` — and the `c`
|
|
144
|
+
screen, through the pid the hello names — sends the running daemon a `SIGHUP`,
|
|
145
|
+
which re-reads just those three settings from the file and updates what the
|
|
146
|
+
hello advertises, so the next `c` shows the new state. That is a unix convention asked of a process this operator already
|
|
147
|
+
owns, not a command sent over the control socket in `attach.mjs` — that socket
|
|
148
|
+
is deliberately read-only (see its own header), and a config change is not an
|
|
149
|
+
exception carved into it.
|
|
150
|
+
|
|
97
151
|
### What it shows you
|
|
98
152
|
|
|
99
153
|
The console shows you a session. This shows you **the machine** — and the
|
|
@@ -130,6 +184,7 @@ long it has been going, and the key that stops it. It is absent when nothing is.
|
|
|
130
184
|
| `Y` | allow always, here — writes a project rule |
|
|
131
185
|
| `x`, twice | cancel the session |
|
|
132
186
|
| `g` | print the daemon's own log instead of the transcript |
|
|
187
|
+
| `c` | configure this machine — the `cawdev config` menu, inside the terminal (R288) |
|
|
133
188
|
| `q` | stop the runner and leave (`--leave-running` keeps it up) |
|
|
134
189
|
| `esc` | close whatever is open, without ending the session |
|
|
135
190
|
| `ctrl+c`, twice | the same, and then leave |
|
|
@@ -144,6 +199,7 @@ move through the command list while one is open.
|
|
|
144
199
|
| `/login` | sign in through the browser |
|
|
145
200
|
| `/logout` | forget the stored session on this machine |
|
|
146
201
|
| `/runs` | the run list — the same as `L` |
|
|
202
|
+
| `/config` | this machine's config — the same as `c` |
|
|
147
203
|
| `/cancel` | cancel the session you are watching |
|
|
148
204
|
| `/log` | the daemon's own log, on or off |
|
|
149
205
|
| `/quit` | leave |
|