cawdev-cli 1.0.11-beta → 1.1.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 +11 -1
- package/lib/roadmap-format.mjs +21 -8
- package/lib/stage-tools.mjs +2 -0
- package/mcp/README.md +43 -30
- package/mcp/server.mjs +95 -47
- package/package.json +1 -1
- package/runner/README.md +22 -25
- package/runner/runner.mjs +16 -0
- package/runner/split.mjs +1 -1
package/README.md
CHANGED
|
@@ -10,4 +10,14 @@ https://github.com/4dali/cawdev-cli
|
|
|
10
10
|
|
|
11
11
|
`jira/import.mjs` brings a Jira Cloud project's issues, epics, sprints and
|
|
12
12
|
comments into a cawdev project, once and again without duplicates (R337). Run from a checkout; see
|
|
13
|
-
"Leaving Jira" in GUIDE.md.
|
|
13
|
+
"Leaving Jira" in GUIDE.md. `--team <team id>` (R489) names the team the sprints open in, when the project is
|
|
14
|
+
shared with several writer teams. Its tests: `node --test "tools/jira/*.test.mjs"`.
|
|
15
|
+
|
|
16
|
+
## The `Sprint:` line
|
|
17
|
+
|
|
18
|
+
A card in a sprint carries one `Sprint:` line in `ROADMAP.md` and `ISSUES.md`
|
|
19
|
+
(`lib/roadmap-format.mjs`): `Sprint: Core team · S7 Notifications` since sprints
|
|
20
|
+
became a team's (R489). Files written before that, `Sprint: S7 Notifications`,
|
|
21
|
+
still parse (with no team). `roadmap/import.mjs` sends the words
|
|
22
|
+
(`Core team · S7`) for the first form and the number for the second, so a file
|
|
23
|
+
naming a sprint the target does not have is refused with the API's own sentence.
|
package/lib/roadmap-format.mjs
CHANGED
|
@@ -332,14 +332,24 @@ export function parseRoadmap(text) {
|
|
|
332
332
|
entry.origin = origin[1].trim();
|
|
333
333
|
continue;
|
|
334
334
|
}
|
|
335
|
-
const sprint = /^Sprint:\s*S(\d+)\s*(.*)$/.exec(line.trim());
|
|
335
|
+
const sprint = /^Sprint:\s*(?:(?!S\d+(?:\s|$))(.+?)\s*·\s*)?S(\d+)\s*(.*)$/.exec(line.trim());
|
|
336
336
|
if (sprint) {
|
|
337
|
-
// R257: `Sprint: S1 Notifications` —
|
|
338
|
-
// as the file says it.
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
|
|
337
|
+
// R257, R489: `Sprint: Core team · S1 Notifications` — a team's
|
|
338
|
+
// sprint, its number and its name as the file says it. A file written
|
|
339
|
+
// before sprints were teams' says `Sprint: S1 Notifications`; that
|
|
340
|
+
// still parses, with no team. The same shape the API's `sprint` has
|
|
341
|
+
// (`label`, `ref`, `number`, `name`), so a re-render from either is
|
|
342
|
+
// byte-identical; the importer sends the team's words and the number,
|
|
343
|
+
// since a sprint's name is the database's to say.
|
|
344
|
+
const number = Number(sprint[2]);
|
|
345
|
+
const team = sprint[1]?.trim() || null;
|
|
346
|
+
entry.sprint = {
|
|
347
|
+
team,
|
|
348
|
+
number,
|
|
349
|
+
ref: `S${number}`,
|
|
350
|
+
label: team ? `${team} · S${number}` : `S${number}`,
|
|
351
|
+
name: sprint[3].trim(),
|
|
352
|
+
};
|
|
343
353
|
continue;
|
|
344
354
|
}
|
|
345
355
|
bodyLines.push(line);
|
|
@@ -619,7 +629,10 @@ function renderEntry(entry) {
|
|
|
619
629
|
// API's `sprint` and the parser's are the same shape, which is what makes
|
|
620
630
|
// render → parse → render a fixed point. State is not written — the file
|
|
621
631
|
// says which sprint, the database says whether it is still open.
|
|
622
|
-
|
|
632
|
+
// R489: the label (`Core team · S7`) is the only spelling that means
|
|
633
|
+
// anything outside the team; `ref` alone is the pre-teams file's.
|
|
634
|
+
const label = entry.sprint.label ?? entry.sprint.ref ?? `S${entry.sprint.number}`;
|
|
635
|
+
lines.push(`Sprint: ${label} ${entry.sprint.name ?? ''}`.trimEnd());
|
|
623
636
|
}
|
|
624
637
|
|
|
625
638
|
if (entry.body?.trim()) {
|
package/lib/stage-tools.mjs
CHANGED
package/mcp/README.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
Plain Node, zero dependencies, stdio JSON-RPC — `server.mjs`, plus the shared
|
|
4
4
|
rule matcher in `tools/lib/tool-rules.mjs` that the runner uses too. It gives a coding
|
|
5
5
|
agent a project's roadmap and changelog — the same verbs a person gets in the
|
|
6
|
-
console, because the API was built to mirror these tools one-for-one.
|
|
6
|
+
console, because the API was built to mirror these tools one-for-one. This README says
|
|
7
|
+
**card** for the roadmap thing and **run** for the work on it, as the console does; the API and
|
|
8
|
+
the tool names say *entry* (`roadmap_list`, `propose_entry`, `EntryRef`) and keep doing so.
|
|
7
9
|
|
|
8
10
|
## Setting it up in a repository
|
|
9
11
|
|
|
@@ -59,23 +61,23 @@ four being different from what you assumed.
|
|
|
59
61
|
|
|
60
62
|
The sequence is fixed, and the second step is the one people skip:
|
|
61
63
|
|
|
62
|
-
1. Branch off an up-to-date `main`, named after the
|
|
63
|
-
2. **Move the
|
|
64
|
+
1. Branch off an up-to-date `main`, named after the card — `r4-roadmap-entries`.
|
|
65
|
+
2. **Move the card to `IN_DEVELOPMENT` naming the branch, before your first commit**
|
|
64
66
|
(`roadmap_set_status`). Not after. The roadmap should be able to answer
|
|
65
67
|
"what is being worked on right now" without asking anyone.
|
|
66
|
-
3. Build to the
|
|
68
|
+
3. Build to the card's "Done when" list.
|
|
67
69
|
4. Finish with a PR. Never push to `main`. As your session ends the platform
|
|
68
70
|
moves the *branch* on the development board, not the card: to `REVIEW` where
|
|
69
71
|
the project runs `require_review` and somebody is going to read it, and to
|
|
70
72
|
`DONE` where it does not — a finish nobody was asked about (R132), because
|
|
71
73
|
there is no reviewer coming.
|
|
72
|
-
5. When the PR merges, move the
|
|
73
|
-
be deleted — `
|
|
74
|
+
5. When the PR merges, move the card to `MERGED` naming it. The branch may then
|
|
75
|
+
be deleted — `IN_DEVELOPMENT` is for work somebody is doing, not work that is done.
|
|
74
76
|
|
|
75
77
|
### What a status must carry
|
|
76
78
|
|
|
77
79
|
`roadmap_statuses` will tell you, and it is worth reading rather than guessing:
|
|
78
|
-
`
|
|
80
|
+
`IN_DEVELOPMENT` needs a branch, `MERGED` needs the merge — a pull request, a merge
|
|
79
81
|
commit, or a sha — `SHIPPED` needs a version that is a real git tag, and
|
|
80
82
|
`DECLINED` needs a reason. `REVIEW` needs nothing, deliberately: the pull
|
|
81
83
|
request it would otherwise carry belongs to the run, and a project that reviews
|
|
@@ -85,19 +87,29 @@ without opening pull requests has none to give it.
|
|
|
85
87
|
when you name no status is the project's rule, per door, and the default for a
|
|
86
88
|
card or issue an agent files is the backlog: waiting until a person or a sprint
|
|
87
89
|
brings it in, in no sprint and on no board column. Its origin names your
|
|
88
|
-
session and the card your run was on. A plan
|
|
90
|
+
session and the card your run was on. A plan run's card lands where the console's
|
|
89
91
|
do (R380). Name a status (`CONSIDERING`, `NEW`) when
|
|
90
92
|
you mean the pipeline. Giving a backlog card a sprint moves it to the first
|
|
91
93
|
status of its kind; moving a card to `BACKLOG` takes it out of its sprint.
|
|
92
94
|
|
|
93
|
-
**
|
|
95
|
+
**Sprints are a team's** (R474, R489). The `sprint` of `roadmap_create`,
|
|
96
|
+
`roadmap_update` and the filter of `roadmap_list` take an integer or a string:
|
|
97
|
+
`7` or `"S7"` when the project's teams have one S7, `"Core team · S7"` (or
|
|
98
|
+
`"Core team / S7"`) when two do — the API refuses an ambiguous `S7` naming both
|
|
99
|
+
spellings, so read the sentence and send the long one — a sprint id, and `0` or
|
|
100
|
+
`""` to take a card out. A completed sprint refuses a card that is not already
|
|
101
|
+
in it, and only a person can reopen one; do not retry. `sprint_list` says which
|
|
102
|
+
sprints there are. A card prints its sprint as `Core team · S7 Name (active)`.
|
|
103
|
+
Opening, starting, completing and renaming a sprint stay a person's.
|
|
104
|
+
|
|
105
|
+
**Any status may move to any other.** There is no transition diagram — a card
|
|
94
106
|
really can go from `CONSIDERING` straight to `SHIPPED` if that is what happened.
|
|
95
107
|
The rules are about what a status *carries*, not the path it took.
|
|
96
108
|
|
|
97
109
|
### The body is what we want; the plan is how; the comments are the argument
|
|
98
110
|
|
|
99
111
|
`roadmap_get` gives you all three, and `task_current` gives you them for the
|
|
100
|
-
|
|
112
|
+
card you are working on.
|
|
101
113
|
|
|
102
114
|
**The plan is the one to read before doing any of the work.** It was written by
|
|
103
115
|
a plan phase and agreed by somebody, and it names the files — R124. If you are
|
|
@@ -110,8 +122,8 @@ either. The first is the platform's — it stores what a plan phase reports when
|
|
|
110
122
|
the phase ends, so that a session which must not write is not handed a writer to
|
|
111
123
|
do its own bookkeeping with. The second is refused outright: *an agent cannot
|
|
112
124
|
start another agent*, which is `RunAccess.requireCanStart`'s rule and not an
|
|
113
|
-
omission here. **Read the discussion before you propose anything about
|
|
114
|
-
|
|
125
|
+
omission here. **Read the discussion before you propose anything about a
|
|
126
|
+
card.** It is where an objection was answered and where an obvious-looking
|
|
115
127
|
approach was ruled out with a reason — and re-proposing what was talked out
|
|
116
128
|
three months ago is precisely what it exists to stop.
|
|
117
129
|
|
|
@@ -123,7 +135,7 @@ that the next reader does not have to reconstruct it from the thread.
|
|
|
123
135
|
A comment you write is attributed to your run as well as to the account that
|
|
124
136
|
minted your token, so a person can tell an agent's reading from a colleague's.
|
|
125
137
|
|
|
126
|
-
### Read what the earlier
|
|
138
|
+
### Read what the earlier runs did before repeating it
|
|
127
139
|
|
|
128
140
|
`task_current` lists **every run this card has already had** — how each ended,
|
|
129
141
|
on what branch, with what model, whether the work was pushed, and the commits it
|
|
@@ -133,21 +145,21 @@ to know what the first tried.
|
|
|
133
145
|
|
|
134
146
|
No transcripts come with it, deliberately: the terminal log is on the run's own
|
|
135
147
|
page in the console, and nine of them would fill the context this call exists to
|
|
136
|
-
orient. If you need the detail, the discussion under the
|
|
137
|
-
previous
|
|
148
|
+
orient. If you need the detail, the discussion under the card is where a
|
|
149
|
+
previous run should have written down what it learned — and where yours
|
|
138
150
|
should.
|
|
139
151
|
|
|
140
152
|
### There is no delete
|
|
141
153
|
|
|
142
154
|
Not in these tools, not in the API. `roadmap_decline` with a reason is the only
|
|
143
|
-
exit
|
|
155
|
+
exit a card has, and the reason is the point: it is what stops the same idea
|
|
144
156
|
being proposed again in six months. Same for changelog entries — correct the
|
|
145
157
|
text, do not remove the record. Same for comments: nothing removes one, and the
|
|
146
158
|
most you can do to your own is correct its wording.
|
|
147
159
|
|
|
148
160
|
### Ids are permanent, and a card is named by its ref
|
|
149
161
|
|
|
150
|
-
|
|
162
|
+
A card's number never changes and is never reused. Commit messages and code
|
|
151
163
|
comments point at it. Since R221 a roadmap card and an issue each count on
|
|
152
164
|
their own sequence, so `R91` and `i91` are two cards: wherever a tool takes
|
|
153
165
|
`number`, `related`, `after` or `entryNumber`, pass the ref — `"i91"` for an
|
|
@@ -169,13 +181,14 @@ what you are allowed to do.
|
|
|
169
181
|
|---|---|
|
|
170
182
|
| `roadmap_where` | Which platform, which token, read from where, and who you are. Start here. |
|
|
171
183
|
| `roadmap_statuses` | The eight statuses, what they mean, what each requires. |
|
|
172
|
-
| `roadmap_list` |
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
184
|
+
| `roadmap_list` | Cards, optionally by status or `sprint` (any spelling below). `brief` omits bodies — use it to survey. |
|
|
185
|
+
| `sprint_list` | The project's sprints with how far each has got (R489): `Core team · S7 Notifications — active — 4 of 9 landed`. ACTIVE and UPCOMING unless `state` says otherwise. A read: PLAN and VERIFY have it. |
|
|
186
|
+
| `roadmap_get` | One card in full: its body, **the plan agreed for it**, and the discussion on it. |
|
|
187
|
+
| `roadmap_create` | Create a card; the platform allocates its permanent number. |
|
|
188
|
+
| `roadmap_update` | Title, body, section, sprint (R489: `7`, `S7`, `"Core team · S7"`, a sprint id; `0` or `""` takes the card out — see below), related ids, the cards it starts coding after (`after` — R181), when it is due and how big it is (`due` — R351: an ISO date, `""` clears; `estimate`: a positive number, `0` clears), the version it is meant for (`targetVersion` — R358, `""` clears; since R362 it must be one the project defined under Project settings → Versions, and any other name is refused), the versions an issue was found in (`affectedVersions` — R378, issues only: names the project defined or shipped in, `[]` clears), and who it is assigned to (`assignee` — R331: a username, `""` clears; `roadmap_list`/`issue_list` take `assignee` too, and `me` means the token's owner). |
|
|
189
|
+
| `roadmap_comment` | Say something *beside* a card rather than inside it. |
|
|
177
190
|
| `done_when_tick` | Tick (or untick) one numbered item of the card's Done-when checklist as built, with one line of evidence (R368). `task_current` lists the items. Defaults to the run's own card and refuses another; the reviewer's column is a person's and no token can set it. |
|
|
178
|
-
| `roadmap_set_status` | Move
|
|
191
|
+
| `roadmap_set_status` | Move a card, carrying whatever the status requires. |
|
|
179
192
|
| `roadmap_decline` | Decline with a reason. The only exit. |
|
|
180
193
|
| `backlog_file` | File **feedback**, not a card — something a person should decide about. A WRITER accepts it as a card or an issue, or refuses it (R199). Tagged `agent` as a source, plus any `tags` you pass — `customer` when you relay what a user said (R372). |
|
|
181
194
|
| `changelog_list` | The changelog, grouped by release, newest first. |
|
|
@@ -192,8 +205,8 @@ token gets a refusal saying so.
|
|
|
192
205
|
|
|
193
206
|
| Tool | What it does |
|
|
194
207
|
|---|---|
|
|
195
|
-
| `task_current` | The
|
|
196
|
-
| `report` | `progress` as often as useful; `done` when finished, naming the branch and any PR; `blocked` when a person must resolve something. `done` and `blocked` end the run; on a coding run `done` is refused until everything is committed and pushed (R345). |
|
|
208
|
+
| `task_current` | The card you are working on, its branch, everything already said and asked on this run, **and every earlier run on the same card**. **Call it first**, and again whenever you are unsure where you are. |
|
|
209
|
+
| `report` | `progress` as often as useful; `done` when finished, naming the branch and any PR; `blocked` when a person must resolve something. `done` and `blocked` end the run; on a review run the `done` body is filed as the branch's review (R529), so write it for the person reading the thread; on a coding run `done` is refused until everything is committed and pushed (R345). |
|
|
197
210
|
| `ask_user` | Ask the person who started the run, and wait. Blocks up to ten minutes, then hands back a `question_id`. |
|
|
198
211
|
| `await_answer` | Resume waiting for a question `ask_user` handed back. |
|
|
199
212
|
| `ask_group` | Ask a **round** — up to twelve questions that belong together, under one title. Blocks until every one of them has been answered, then hands back a `group_id`. |
|
|
@@ -202,7 +215,7 @@ token gets a refusal saying so.
|
|
|
202
215
|
| `approve` | **Not yours to call.** Claude Code calls it itself, as `--permission-prompt-tool`, when no rule covers a tool call. |
|
|
203
216
|
|
|
204
217
|
**`ask_user` is for decisions that are genuinely theirs** — an architectural
|
|
205
|
-
choice, a trade-off with no right answer, something the
|
|
218
|
+
choice, a trade-off with no right answer, something the card does not settle.
|
|
206
219
|
Not for checking work you can check yourself. Every question stops the run and
|
|
207
220
|
costs somebody's attention.
|
|
208
221
|
|
|
@@ -213,7 +226,7 @@ asked because the decision was not yours. Call `await_answer`, or `report`
|
|
|
213
226
|
**`ask_group` is for when you have several questions at once** — R96. One
|
|
214
227
|
question at a time is right for a decision you hit halfway through a piece of
|
|
215
228
|
work; it is wrong when you are trying to understand something, because forty
|
|
216
|
-
separate
|
|
229
|
+
separate Waiting on you items arriving over an afternoon is not a conversation, it is an
|
|
217
230
|
interruption repeated forty times. A round arrives as one form under one title,
|
|
218
231
|
the person answers it in one sitting, and you are woken once when all of it is
|
|
219
232
|
answered.
|
|
@@ -259,9 +272,9 @@ Two smoke tests, both driving the server over real stdio.
|
|
|
259
272
|
CAWDEV_URL=http://localhost:4200 CAWDEV_TOKEN=cawd_… node tools/mcp/smoke.mjs scratch-project
|
|
260
273
|
```
|
|
261
274
|
|
|
262
|
-
**Name a scratch project.** The smoke test creates a roadmap
|
|
263
|
-
it, and
|
|
264
|
-
meant. It left two declined
|
|
275
|
+
**Name a scratch project.** The smoke test creates a roadmap card and declines
|
|
276
|
+
it, and cards cannot be deleted — so it refuses to guess which project you
|
|
277
|
+
meant. It left two declined cards in cawdev's own roadmap before it did.
|
|
265
278
|
|
|
266
279
|
It drives the server the way a client does — spawn, write lines to stdin, read
|
|
267
280
|
lines from stdout — rather than importing its functions, because the parts most
|
package/mcp/server.mjs
CHANGED
|
@@ -375,6 +375,41 @@ const TOOLS = [
|
|
|
375
375
|
},
|
|
376
376
|
},
|
|
377
377
|
|
|
378
|
+
{
|
|
379
|
+
name: 'sprint_list',
|
|
380
|
+
description:
|
|
381
|
+
'The sprints a project\'s cards can be filed into, with how far each has got — R489. Sprints ' +
|
|
382
|
+
'are a team\'s: written `S7` inside the team and `Core team · S7` outside it. Read this before ' +
|
|
383
|
+
'filing a card into one with roadmap_create / roadmap_update `sprint`. State narrows it ' +
|
|
384
|
+
'(ACTIVE, UPCOMING, COMPLETED; comma-separated); the default is ACTIVE and UPCOMING.',
|
|
385
|
+
inputSchema: {
|
|
386
|
+
type: 'object',
|
|
387
|
+
properties: {
|
|
388
|
+
...PROJECT_ARGUMENT,
|
|
389
|
+
state: {
|
|
390
|
+
type: 'string',
|
|
391
|
+
description: 'ACTIVE, UPCOMING, COMPLETED — one or several, comma-separated. Default ACTIVE,UPCOMING.',
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
handler: async (config, args) => {
|
|
396
|
+
const slug = await resolveProject(config, args.project);
|
|
397
|
+
const state = args.state || 'ACTIVE,UPCOMING';
|
|
398
|
+
const sprints = await api(config, `/api/projects/${slug}/sprints?state=${encodeURIComponent(state)}`);
|
|
399
|
+
if (!sprints.length) return `${slug} has no sprints in ${state}.`;
|
|
400
|
+
return sprints
|
|
401
|
+
.map((sprint) => {
|
|
402
|
+
const counts = sprint.counts ?? {};
|
|
403
|
+
return (
|
|
404
|
+
`${sprint.label ?? sprint.ref}${sprint.name ? ` ${sprint.name}` : ''} — ` +
|
|
405
|
+
`${String(sprint.state).toLowerCase()} — ${counts.landed ?? 0} of ${counts.cards ?? 0} landed` +
|
|
406
|
+
(sprint.goal ? `\n goal: ${sprint.goal}` : '')
|
|
407
|
+
);
|
|
408
|
+
})
|
|
409
|
+
.join('\n');
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
|
|
378
413
|
{
|
|
379
414
|
name: 'roadmap_statuses',
|
|
380
415
|
description:
|
|
@@ -396,18 +431,17 @@ const TOOLS = [
|
|
|
396
431
|
{
|
|
397
432
|
name: 'roadmap_list',
|
|
398
433
|
description:
|
|
399
|
-
'A project\'s roadmap
|
|
400
|
-
'to survey without pulling every
|
|
434
|
+
'A project\'s roadmap cards, optionally filtered by status or by sprint. Use brief=true ' +
|
|
435
|
+
'to survey without pulling every card\'s body into context.',
|
|
401
436
|
inputSchema: {
|
|
402
437
|
type: 'object',
|
|
403
438
|
properties: {
|
|
404
439
|
...PROJECT_ARGUMENT,
|
|
405
440
|
sprint: {
|
|
406
|
-
type: 'integer',
|
|
407
|
-
minimum: 1,
|
|
441
|
+
type: ['integer', 'string'],
|
|
408
442
|
description:
|
|
409
|
-
'Only cards in this sprint,
|
|
410
|
-
'sprint for is refused naming the ones it has.',
|
|
443
|
+
'Only cards in this sprint: `S7` (or 7), "Core team · S7" when two teams have an S7, or a ' +
|
|
444
|
+
'sprint id. A sprint the project has none for is refused naming the ones it has.',
|
|
411
445
|
},
|
|
412
446
|
status: {
|
|
413
447
|
type: 'string',
|
|
@@ -439,7 +473,9 @@ const TOOLS = [
|
|
|
439
473
|
if (args.status) query.set('status', args.status);
|
|
440
474
|
// R257. The API refuses a number with no sprint behind it, naming the
|
|
441
475
|
// sprints there are; that sentence is passed through as the tool error.
|
|
442
|
-
if (args.sprint
|
|
476
|
+
if (args.sprint !== undefined && args.sprint !== '' && args.sprint !== 0) {
|
|
477
|
+
query.set('sprint', String(args.sprint));
|
|
478
|
+
}
|
|
443
479
|
if (args.assignee) query.set('assignee', args.assignee);
|
|
444
480
|
query.set('brief', String(brief));
|
|
445
481
|
|
|
@@ -454,7 +490,7 @@ const TOOLS = [
|
|
|
454
490
|
{
|
|
455
491
|
name: 'roadmap_get',
|
|
456
492
|
description:
|
|
457
|
-
'One roadmap
|
|
493
|
+
'One roadmap card in full: its body, THE PLAN somebody agreed for it, and the ' +
|
|
458
494
|
'discussion on it. Read the plan before doing any of the work — it is what was decided, ' +
|
|
459
495
|
'and it names the files. Read the comments before proposing anything: they are where an ' +
|
|
460
496
|
'objection was answered, and re-proposing what was talked out three months ago is the ' +
|
|
@@ -594,7 +630,7 @@ const TOOLS = [
|
|
|
594
630
|
{
|
|
595
631
|
name: 'roadmap_comment',
|
|
596
632
|
description:
|
|
597
|
-
'Say something about
|
|
633
|
+
'Say something about a card, beside the card rather than inside it. Use it for the ' +
|
|
598
634
|
'argument: an objection, a measurement, why an obvious approach was not taken. The body ' +
|
|
599
635
|
'is where a settled conclusion is written down — edit that when the discussion reaches ' +
|
|
600
636
|
'one. Comments cannot be deleted, by you or by anyone.',
|
|
@@ -680,12 +716,12 @@ const TOOLS = [
|
|
|
680
716
|
{
|
|
681
717
|
name: 'roadmap_create',
|
|
682
718
|
description:
|
|
683
|
-
'Create a roadmap
|
|
684
|
-
'a roadmap card and i91 on an issue, one
|
|
719
|
+
'Create a roadmap card. The platform allocates its permanent number — written R91 on ' +
|
|
720
|
+
'a roadmap card and i91 on an issue, two sequences, one per kind — and the ' +
|
|
685
721
|
'project decides where a card you file starts — the BACKLOG by default for a card an ' +
|
|
686
722
|
'agent files, waiting until a person or a sprint brings it in — unless you say ' +
|
|
687
723
|
'otherwise; a status that requires something must be given it. A card in the BACKLOG ' +
|
|
688
|
-
'holds no sprint: giving it one moves it to CONSIDERING. A plan
|
|
724
|
+
'holds no sprint: giving it one moves it to CONSIDERING. A plan run\'s card lands ' +
|
|
689
725
|
'where the console\'s do (R380).',
|
|
690
726
|
inputSchema: {
|
|
691
727
|
type: 'object',
|
|
@@ -714,12 +750,12 @@ const TOOLS = [
|
|
|
714
750
|
reason: { type: 'string' },
|
|
715
751
|
section: { type: 'string', description: 'Which part of the roadmap, e.g. "Phase 2 — …".' },
|
|
716
752
|
sprint: {
|
|
717
|
-
type: 'integer',
|
|
718
|
-
minimum: 0,
|
|
753
|
+
type: ['integer', 'string'],
|
|
719
754
|
description:
|
|
720
|
-
'The sprint to file this card into
|
|
721
|
-
'
|
|
722
|
-
'
|
|
755
|
+
'The sprint to file this card into: `S7` (or 7) when the project\'s teams have one S7, ' +
|
|
756
|
+
'"Core team · S7" when two teams do, a sprint id, or 0 / "" to take it out of its sprint; ' +
|
|
757
|
+
'leave it out to leave it alone. A COMPLETED sprint refuses a card that is not already in it, ' +
|
|
758
|
+
'and only a person can reopen one — do not retry. Sprint_list shows what there is.',
|
|
723
759
|
},
|
|
724
760
|
related: {
|
|
725
761
|
type: 'array',
|
|
@@ -929,7 +965,7 @@ const TOOLS = [
|
|
|
929
965
|
{
|
|
930
966
|
name: 'roadmap_update',
|
|
931
967
|
description:
|
|
932
|
-
'Edit
|
|
968
|
+
'Edit a card\'s title, body, section, sprint, tags, parent, related refs or the cards it ' +
|
|
933
969
|
'starts after. Use roadmap_set_status to move it.',
|
|
934
970
|
inputSchema: {
|
|
935
971
|
type: 'object',
|
|
@@ -943,12 +979,12 @@ const TOOLS = [
|
|
|
943
979
|
body: { type: 'string' },
|
|
944
980
|
section: { type: 'string' },
|
|
945
981
|
sprint: {
|
|
946
|
-
type: 'integer',
|
|
947
|
-
minimum: 0,
|
|
982
|
+
type: ['integer', 'string'],
|
|
948
983
|
description:
|
|
949
|
-
'The sprint to file this card into
|
|
950
|
-
'
|
|
951
|
-
'
|
|
984
|
+
'The sprint to file this card into: `S7` (or 7) when the project\'s teams have one S7, ' +
|
|
985
|
+
'"Core team · S7" when two teams do, a sprint id, or 0 / "" to take it out of its sprint; ' +
|
|
986
|
+
'leave it out to leave it alone. A COMPLETED sprint refuses a card that is not already in it, ' +
|
|
987
|
+
'and only a person can reopen one — do not retry. Sprint_list shows what there is.',
|
|
952
988
|
},
|
|
953
989
|
related: {
|
|
954
990
|
type: 'array',
|
|
@@ -1027,7 +1063,7 @@ const TOOLS = [
|
|
|
1027
1063
|
{
|
|
1028
1064
|
name: 'roadmap_set_status',
|
|
1029
1065
|
description:
|
|
1030
|
-
'Move
|
|
1066
|
+
'Move a card to a status. Any status may move to any other — the rules are about what ' +
|
|
1031
1067
|
'a status must carry, not a permitted path. IN_DEVELOPMENT needs a branch, MERGED the ' +
|
|
1032
1068
|
'merge — the PR, the merge commit or the sha — and SHIPPED a version. Move a card to ' +
|
|
1033
1069
|
'MERGED when its pull request lands; the branch may then be deleted. ' +
|
|
@@ -1076,7 +1112,7 @@ const TOOLS = [
|
|
|
1076
1112
|
{
|
|
1077
1113
|
name: 'roadmap_decline',
|
|
1078
1114
|
description:
|
|
1079
|
-
'Decline
|
|
1115
|
+
'Decline a card, with a reason. This is the only exit a card has — there is no delete. ' +
|
|
1080
1116
|
'The reason is the point: it stops the idea being proposed again.',
|
|
1081
1117
|
inputSchema: {
|
|
1082
1118
|
type: 'object',
|
|
@@ -1153,10 +1189,10 @@ const TOOLS = [
|
|
|
1153
1189
|
entryNumber: {
|
|
1154
1190
|
type: ['string', 'integer'],
|
|
1155
1191
|
description:
|
|
1156
|
-
'The roadmap card or issue this entry describes — R156 — by ref: R91, i91, or a '
|
|
1192
|
+
'The roadmap card or issue this changelog entry describes — R156 — by ref: R91, i91, or a '
|
|
1157
1193
|
+ 'bare number for a roadmap card (R221). Set it. Until R156 the only link was the '
|
|
1158
1194
|
+ 'ref you type into the prose, which cannot be queried, so a release could not '
|
|
1159
|
-
+ 'tell whether a card already had
|
|
1195
|
+
+ 'tell whether a card already had a changelog entry and would write a second one beside '
|
|
1160
1196
|
+ 'the first. Put the ref in the text as well; that is what a reader sees.',
|
|
1161
1197
|
},
|
|
1162
1198
|
},
|
|
@@ -1189,8 +1225,8 @@ const TOOLS = [
|
|
|
1189
1225
|
entryNumber: {
|
|
1190
1226
|
type: ['string', 'integer'],
|
|
1191
1227
|
description:
|
|
1192
|
-
'The roadmap card or issue this entry describes — R156 — by ref (R91, i91; a bare '
|
|
1193
|
-
+ 'number is a roadmap card). Set it on an older entry that has never been linked; '
|
|
1228
|
+
'The roadmap card or issue this changelog entry describes — R156 — by ref (R91, i91; a bare '
|
|
1229
|
+
+ 'number is a roadmap card). Set it on an older changelog entry that has never been linked; '
|
|
1194
1230
|
+ 'omitting it leaves whatever link is already there.',
|
|
1195
1231
|
},
|
|
1196
1232
|
},
|
|
@@ -1211,9 +1247,9 @@ const TOOLS = [
|
|
|
1211
1247
|
{
|
|
1212
1248
|
name: 'task_current',
|
|
1213
1249
|
description:
|
|
1214
|
-
'What you are working on: the roadmap
|
|
1250
|
+
'What you are working on: the roadmap card, THE PLAN agreed for it, its branch, and ' +
|
|
1215
1251
|
'everything already said and asked on this run. Call it first, and again whenever you ' +
|
|
1216
|
-
'are unsure where you are — a resumed or confused session re-orients from this alone.',
|
|
1252
|
+
'are unsure where you are — a resumed or confused agent session re-orients from this alone.',
|
|
1217
1253
|
inputSchema: { type: 'object', properties: {} },
|
|
1218
1254
|
handler: async (config) => {
|
|
1219
1255
|
const { runId, project } = await requireRun(config);
|
|
@@ -1435,20 +1471,20 @@ const TOOLS = [
|
|
|
1435
1471
|
{
|
|
1436
1472
|
name: 'propose_entry',
|
|
1437
1473
|
description:
|
|
1438
|
-
'Record something an audit found, or a card a scoping
|
|
1474
|
+
'Record something an audit found, or a card a scoping run cut, as a proposed card. ' +
|
|
1439
1475
|
'`kind` is your opinion: "issue" ' +
|
|
1440
1476
|
'(broken, unsafe, or loses data — with a severity) or "roadmap" (it should also do this, ' +
|
|
1441
1477
|
'or do it better — no severity). A PERSON decides, and may file it the other way — you ' +
|
|
1442
|
-
'are not creating
|
|
1478
|
+
'are not creating a card, you are suggesting it. Default "issue", so an audit written ' +
|
|
1443
1479
|
'before there was a choice files what it always did. Severity is "critical" (broken, ' +
|
|
1444
1480
|
'unsafe, or loses data), "medium" (it will hurt, but not today) or "minor" (worth doing, ' +
|
|
1445
|
-
'nobody is bleeding). `section` is where you think it belongs; a scoping
|
|
1481
|
+
'nobody is bleeding). `section` is where you think it belongs; a scoping run names ' +
|
|
1446
1482
|
'ONE for every card of the idea. A roadmap card MUST say what it starts after — `after`: ' +
|
|
1447
1483
|
'`[]` for a card that starts after none, `"#2"` for the second card you proposed in this ' +
|
|
1448
1484
|
'run (the number this tool answered with), `"R12"` for a card already on the roadmap. ' +
|
|
1449
1485
|
'You can only name what has already been proposed, so file in build order. Write each ' +
|
|
1450
|
-
'one as
|
|
1451
|
-
'or a scoping
|
|
1486
|
+
'one as a card would be written, and say where in the code you saw it. Only an audit ' +
|
|
1487
|
+
'or a scoping run may use this.',
|
|
1452
1488
|
inputSchema: {
|
|
1453
1489
|
type: 'object',
|
|
1454
1490
|
properties: {
|
|
@@ -1473,7 +1509,7 @@ const TOOLS = [
|
|
|
1473
1509
|
type: 'string',
|
|
1474
1510
|
description:
|
|
1475
1511
|
'The roadmap section this belongs under, in your opinion. Optional. The person ' +
|
|
1476
|
-
'accepting sees it as the default and may file it elsewhere. A scoping
|
|
1512
|
+
'accepting sees it as the default and may file it elsewhere. A scoping run ' +
|
|
1477
1513
|
'uses the same section on every card it cuts from one idea.',
|
|
1478
1514
|
},
|
|
1479
1515
|
after: {
|
|
@@ -1485,7 +1521,7 @@ const TOOLS = [
|
|
|
1485
1521
|
'card you proposed in THIS run, by the number this tool answered with; it must ' +
|
|
1486
1522
|
'already have been proposed, so propose what a card depends on before the card. ' +
|
|
1487
1523
|
'`"R12"` or `"i7"` names a card already on the roadmap. A person adds the cards ' +
|
|
1488
|
-
'in this order, and a coding
|
|
1524
|
+
'in this order, and a coding run on one waits until what it starts after has ' +
|
|
1489
1525
|
'landed.',
|
|
1490
1526
|
},
|
|
1491
1527
|
},
|
|
@@ -1565,7 +1601,7 @@ const TOOLS = [
|
|
|
1565
1601
|
name: 'ask_group',
|
|
1566
1602
|
description:
|
|
1567
1603
|
'Ask a ROUND of questions at once, and wait for all of them. Use it when you have several ' +
|
|
1568
|
-
'things to settle that belong together — they arrive in the person\'s
|
|
1604
|
+
'things to settle that belong together — they arrive in the person\'s Waiting on you page under one ' +
|
|
1569
1605
|
'title, on one form, instead of interrupting them once per question. At most 12 in a ' +
|
|
1570
1606
|
'round; ask the rest in the next one. Blocks for up to ten minutes; if the round is ' +
|
|
1571
1607
|
'unfinished by then it returns a group_id for await_group.',
|
|
@@ -1575,7 +1611,7 @@ const TOOLS = [
|
|
|
1575
1611
|
title: {
|
|
1576
1612
|
type: 'string',
|
|
1577
1613
|
description:
|
|
1578
|
-
'What this round is called in
|
|
1614
|
+
'What this round is called in Waiting on you. A CTO Interview uses "CTO Interview".',
|
|
1579
1615
|
},
|
|
1580
1616
|
intro: {
|
|
1581
1617
|
type: 'string',
|
|
@@ -1705,7 +1741,7 @@ const TOOLS = [
|
|
|
1705
1741
|
name: 'await_answer',
|
|
1706
1742
|
description:
|
|
1707
1743
|
'Resume waiting for a question ask_user handed back. Between the two you experience one ' +
|
|
1708
|
-
'natural blocking ask; the person experiences
|
|
1744
|
+
'natural blocking ask; the person experiences a Waiting on you item.',
|
|
1709
1745
|
inputSchema: {
|
|
1710
1746
|
type: 'object',
|
|
1711
1747
|
properties: { question_id: { type: 'string' } },
|
|
@@ -2065,11 +2101,23 @@ function approvalTimeoutSeconds() {
|
|
|
2065
2101
|
// The same goes for comments — nothing here removes one, and nothing there
|
|
2066
2102
|
// does either.
|
|
2067
2103
|
//
|
|
2068
|
-
// Nor is there a sprint_open,
|
|
2069
|
-
//
|
|
2070
|
-
//
|
|
2071
|
-
//
|
|
2072
|
-
//
|
|
2104
|
+
// Nor is there a sprint_open, sprint_start, sprint_complete or sprint_rename —
|
|
2105
|
+
// R257, and a team's since R474. Opening, starting, completing and renaming a
|
|
2106
|
+
// sprint are a person's acts on the page, and the API says so structurally
|
|
2107
|
+
// (the /api/teams/{id}/sprints writes take a session, not a token). An
|
|
2108
|
+
// agent's whole reach here is reading the sprints (sprint_list) and a card's
|
|
2109
|
+
// sprint, and filing a card into one with roadmap_create / roadmap_update
|
|
2110
|
+
// `sprint`.
|
|
2111
|
+
|
|
2112
|
+
/**
|
|
2113
|
+
* R489. A card's sprint as a line: `Core team · S7 Name (active)`. The label
|
|
2114
|
+
* is the server's one spelling; `S7` alone means nothing outside its team.
|
|
2115
|
+
*/
|
|
2116
|
+
function sprintLine(sprint) {
|
|
2117
|
+
const label = sprint.label ?? sprint.ref ?? `S${sprint.number}`;
|
|
2118
|
+
const state = String(sprint.state ?? '').toLowerCase();
|
|
2119
|
+
return `${label}${sprint.name ? ` ${sprint.name}` : ''}${state ? ` (${state})` : ''}`;
|
|
2120
|
+
}
|
|
2073
2121
|
|
|
2074
2122
|
function pick(source, keys) {
|
|
2075
2123
|
const out = {};
|
|
@@ -2361,7 +2409,7 @@ function formatEntry(entry, { brief, comments, plan }) {
|
|
|
2361
2409
|
// depend on which tool printed the card; a closed sprint says so.
|
|
2362
2410
|
if (entry.sprint) {
|
|
2363
2411
|
lines.push(
|
|
2364
|
-
` sprint: ${entry.sprint
|
|
2412
|
+
` sprint: ${sprintLine(entry.sprint)}`,
|
|
2365
2413
|
);
|
|
2366
2414
|
}
|
|
2367
2415
|
if (entry.related?.length) {
|
package/package.json
CHANGED
package/runner/README.md
CHANGED
|
@@ -158,8 +158,9 @@ served like any added project, and the rest of the console's setup walk —
|
|
|
158
158
|
rules, members, the CTO Interview — is linked at
|
|
159
159
|
`<url>/projects/<slug>/setup`.
|
|
160
160
|
|
|
161
|
-
**What takes effect when** (R294).
|
|
162
|
-
without a restart — `agentCommands`, `grantable`, `acceptsRulesFromConsole
|
|
161
|
+
**What takes effect when** (R294). Four settings a running daemon takes
|
|
162
|
+
without a restart — `agentCommands`, `grantable`, `acceptsRulesFromConsole`
|
|
163
|
+
and `autoWorkspaces`,
|
|
163
164
|
the `HOT_SWAPPABLE` list in `tools/lib/runner-config.mjs`, spelled once —
|
|
164
165
|
because the daemon reads them fresh on every use. Everything else in the file
|
|
165
166
|
(`projects` and their workspaces, `url`, `name`, the token, `browser`, the
|
|
@@ -197,7 +198,7 @@ and its copy all work exactly as they always have, and scrolling up reaches the
|
|
|
197
198
|
start of the session. The only thing pinned is the footer at the bottom, and it
|
|
198
199
|
never scrolls away: which cawdev, who you are signed in as, this machine's
|
|
199
200
|
runner, the per-project session counts against their checkouts and the machine's
|
|
200
|
-
total
|
|
201
|
+
total — plus the run you are watching and the keys that
|
|
201
202
|
work right now. Anything *stopping* a session sits above all of that, because it
|
|
202
203
|
is the only thing in there waiting on a person.
|
|
203
204
|
|
|
@@ -283,7 +284,7 @@ the shape of the decision, and the whole value of asking a person is that they
|
|
|
283
284
|
can say the thing that was not on the list — so getting there costs one key, and
|
|
284
285
|
`esc` from it comes back to the list rather than abandoning the answer. A chosen
|
|
285
286
|
option and a typed sentence resolve the same question the same way, through the
|
|
286
|
-
same endpoint the
|
|
287
|
+
same endpoint the Waiting on you page and the run page post to: one record, the same
|
|
287
288
|
`answeredBy`, and the badge clears at once.
|
|
288
289
|
|
|
289
290
|
A permission request is the same widget — R60's lengths of yes as rows, with the
|
|
@@ -694,7 +695,7 @@ it ends.
|
|
|
694
695
|
A bare path means one workspace, which is what every config meant before this
|
|
695
696
|
existed — nothing changes for a machine that serves one checkout per project.
|
|
696
697
|
|
|
697
|
-
How many coding runs go at once is
|
|
698
|
+
How many coding runs go at once is the number of workspaces. A run that
|
|
698
699
|
waits now says **"no free workspace in cawdev (2 here, all busy)"** instead of
|
|
699
700
|
"that project already has a run here", which was a proxy for it.
|
|
700
701
|
|
|
@@ -717,18 +718,16 @@ says about knowing it.
|
|
|
717
718
|
|
|
718
719
|
**This number caps coding and nothing else** (R70). `ASK`, `ROADMAP`, `AUDIT`
|
|
719
720
|
and `SCOPE` runs take no workspace, so a project whose checkouts are all busy
|
|
720
|
-
still starts a question,
|
|
721
|
-
|
|
721
|
+
still starts a question, a card-writing run, an audit and a scoping
|
|
722
|
+
run at once. `INTERVIEW`, `MERGE`
|
|
722
723
|
and `RELEASE` do take one — each commits something — and count against this
|
|
723
724
|
number; what each may *write* in it is far narrower than a coding run's and is
|
|
724
725
|
decided by the profile, not by the prompt: an interview writes `docs/brief/`,
|
|
725
726
|
a merge writes the files git put conflict markers in, and a release (R187)
|
|
726
727
|
writes exactly the version files the platform names on the claim, with `git`,
|
|
727
728
|
`gh pr create`, `gh pr view` and `node` for the exports — no build tools, no
|
|
728
|
-
permission prompt, no `gh pr merge`. What holds
|
|
729
|
-
is
|
|
730
|
-
(every profile counts)"** is the other thing a waiting run can say, and the log
|
|
731
|
-
always says which of the two it was.
|
|
729
|
+
permission prompt, no `gh pr merge`. What holds a coding run back
|
|
730
|
+
is a free workspace, and the log says so (R109 removed `maxSessions`).
|
|
732
731
|
|
|
733
732
|
**One thing this gate cannot express, and does not try to.** It serialises on a
|
|
734
733
|
checkout, so two runs on *the same branch* in two checkouts are, to this daemon,
|
|
@@ -797,8 +796,8 @@ whether the browser is allowed. Those five answer nearly every "why did that
|
|
|
797
796
|
not happen", and they used to be spread across a config file and a shrug.
|
|
798
797
|
|
|
799
798
|
Attaching adds a second bar row: the URL, each project as **coding sessions over
|
|
800
|
-
checkouts** (`cawdev 1/2`), and the machine's total
|
|
801
|
-
|
|
799
|
+
checkouts** (`cawdev 1/2`), and the machine's total.
|
|
800
|
+
The gate, on screen, counting what it actually bounds — a question is in the
|
|
802
801
|
total on the right and not in any project's figure, because it took no checkout.
|
|
803
802
|
A run that is waiting is explained by the bar
|
|
804
803
|
above it rather than by reading the source. A narrow terminal drops projects
|
|
@@ -849,11 +848,11 @@ than twenty-six. A machine that wants it unattended puts that string in its own
|
|
|
849
848
|
### What a person can ask of a checkout
|
|
850
849
|
|
|
851
850
|
R57. The daemon polls `workspace-requests/claim` every few seconds and does one
|
|
852
|
-
of **
|
|
851
|
+
of **eleven** things to a checkout it serves. It said six for two entries, and
|
|
853
852
|
`HANDOFF` had been missing from the list since R148 — a table that quietly does
|
|
854
853
|
not describe one of the things a person can ask for is worse than no table. So
|
|
855
854
|
count the rows below against that number before you trust either. `CUT_BRANCH`
|
|
856
|
-
is the ninth, R260's; `OPEN_PR` the tenth, R261's.
|
|
855
|
+
is the ninth, R260's; `OPEN_PR` the tenth, R261's, `CREATE_BRANCH` the eleventh, R379's.
|
|
857
856
|
|
|
858
857
|
| | |
|
|
859
858
|
|---|---|
|
|
@@ -867,6 +866,7 @@ is the ninth, R260's; `OPEN_PR` the tenth, R261's.
|
|
|
867
866
|
| `TAG` | R156's release: `git ls-remote --tags origin refs/tags/<version>` for the version in `message`. **The remote, not this clone** — a local tag nobody pushed is exactly the state a release is trying to rule out, and `git tag --list` cannot tell the two apart. A read; it fetches nothing and moves no ref. The sha is reported on the result's first line, the way `MERGE` reports its URL, because the platform will not confirm a release on `ok: true` alone. **A tag that is not there yet is `ok: false` with a sentence, and that is a normal answer** — the release procedure pushes the tag last, so the first check correctly finds nothing. Addressed to a **release** rather than to a directory alone, which is why it is asked for from the roadmap board and refused on this channel. |
|
|
868
867
|
| `CUT_BRANCH` | R260's sprint branch: `git push origin origin/<default>:refs/heads/<name>` for the branch in `message`, after a fetch — so the sprint's cards are cut from what everyone else has, not from whatever this checkout was left on. The second kind after `MERGE` whose effect is **not** in the checkout: the push names two refs and this clone's HEAD is not one of them, so any live checkout of the project will do and nothing local moves. **A branch already on origin is `ok: true`** ("already on origin at <sha>") — the sprint wanted one to exist, and one does. The sha is reported on the result's first line, the way `TAG` reports its. Addressed to a **sprint** and asked for from the sprint page by an OWNER, for `MERGE`'s reason — it reaches the remote — and refused on this channel. A `MERGE` of a card's pull request into a sprint branch still runs `--squash --delete-branch`: the card's branch goes, the sprint's stays. Landing the sprint branch itself is `OPEN_PR` then `MERGE` below. |
|
|
869
868
|
| `OPEN_PR` | R261's sprint merge, first half: `gh pr create --head <branch> --base <base> --title <title>` for the branch in `message` — the sprint's — to `baseBranch ?? defaultBranch`, titled as the claim's `title` (*S1 Notifications*). **An existing pull request is `ok: true` with its URL** — the same `gh pr view` lookup the `auto_pr` rule makes, and the reason the platform can ask this every time: it holds no git-host credential and cannot know whether one exists. The URL is reported on the result's first line, and the platform queues the `MERGE` to this same checkout when it reads one. Nothing is pushed: the branch is on origin already, cut there by `CUT_BRANCH` and merged into by every card. Addressed to a **work item** — the sprint's — and asked for by Merge on the development board or *Merge sprint* on the sprint page, by an OWNER; refused on this channel for `MERGE`'s reason. |
|
|
869
|
+
| `CREATE_BRANCH` | R379's New branch from the console: pushes `origin/<fromBranch>` to `refs/heads/<name>` for the name in `message`. Unlike `CUT_BRANCH` a name already on origin is a **refusal**, because the person asked for a new branch and the existing one may be somebody else's work. Touches no working tree; a daemon that knows the kind says `createBranch: true` in its hello. |
|
|
870
870
|
|
|
871
871
|
**A `MERGE` that fails also says which KIND of failure it was** — R155, in one
|
|
872
872
|
of five words beside `gh`'s own unchanged text:
|
|
@@ -1257,12 +1257,9 @@ rest queue.
|
|
|
1257
1257
|
|
|
1258
1258
|
**Questions are not serialised.** An `ASK` run prepares nothing and writes
|
|
1259
1259
|
nothing, so it runs alongside whatever else is going on — you can ask about a
|
|
1260
|
-
project while an agent is working in it.
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
this daemon has claimed, not children it has spawned: a claim takes a second or
|
|
1264
|
-
two to become a process, and counting processes let one pass of the loop claim
|
|
1265
|
-
the whole queue.
|
|
1260
|
+
project while an agent is working in it. Nothing bounds a question, a roadmap session or an audit but the platform's
|
|
1261
|
+
own queue: `maxSessions` was removed in R109, and the workspace gate above is
|
|
1262
|
+
the only one.
|
|
1266
1263
|
|
|
1267
1264
|
## If the daemon dies mid-run
|
|
1268
1265
|
|
|
@@ -1391,7 +1388,7 @@ permission stops forever.
|
|
|
1391
1388
|
|
|
1392
1389
|
- `--permission-mode acceptEdits` lets it write files.
|
|
1393
1390
|
- `--allowedTools mcp__cawdev__…` lets it use the cawdev tools. **Without this
|
|
1394
|
-
the entire loop is unreachable** — no reading the task, no moving the
|
|
1391
|
+
the entire loop is unreachable** — no reading the task, no moving the card,
|
|
1395
1392
|
no reporting, no asking. A real session found this by being denied
|
|
1396
1393
|
`task_current` and stopping rather than guessing, which was the right call
|
|
1397
1394
|
and a good sign for the prompt.
|
|
@@ -1417,7 +1414,7 @@ never asks you anything — an unlisted tool is refused, not raised (i138).
|
|
|
1417
1414
|
|
|
1418
1415
|
**Anything else stops and asks you** (R51). Rather than being denied in
|
|
1419
1416
|
silence, a session that needs `mvn` or `npm` posts a request that appears in
|
|
1420
|
-
your
|
|
1417
|
+
your Waiting on you page and on the run, and waits for an answer. Allow it once, or allow it
|
|
1421
1418
|
always here — which writes a rule on the project that every runner serving it
|
|
1422
1419
|
inherits.
|
|
1423
1420
|
|
|
@@ -1548,8 +1545,8 @@ after `--mcp-config` fails with `ENAMETOOLONG`, which names neither the flag nor
|
|
|
1548
1545
|
the prompt.
|
|
1549
1546
|
|
|
1550
1547
|
The prompt deliberately teaches the **method**, not the task. The task is in the
|
|
1551
|
-
roadmap
|
|
1552
|
-
in the prompt too would be a second copy that can disagree with the
|
|
1548
|
+
roadmap card, which the agent reads for itself with `task_current` — putting it
|
|
1549
|
+
in the prompt too would be a second copy that can disagree with the card.
|
|
1553
1550
|
|
|
1554
1551
|
### Codex CLI
|
|
1555
1552
|
|
package/runner/runner.mjs
CHANGED
|
@@ -189,6 +189,7 @@ const DEFAULTS = {
|
|
|
189
189
|
'mcp__cawdev__quality_get',
|
|
190
190
|
'mcp__cawdev__roadmap_statuses',
|
|
191
191
|
'mcp__cawdev__roadmap_list',
|
|
192
|
+
'mcp__cawdev__sprint_list',
|
|
192
193
|
'mcp__cawdev__roadmap_get',
|
|
193
194
|
// The MCP server has served this since R37, its README documents it, and
|
|
194
195
|
// the REVIEW prompt below TELLS a session to file its findings with it —
|
|
@@ -9643,6 +9644,17 @@ async function main() {
|
|
|
9643
9644
|
// right way.
|
|
9644
9645
|
quiet = attaching;
|
|
9645
9646
|
|
|
9647
|
+
// A SIGHUP that arrives while booting — `cawdev config` run a moment after
|
|
9648
|
+
// the daemon started — is held, not fatal: Node's default for an unhandled
|
|
9649
|
+
// SIGHUP is to exit, and the real handler is only installed once
|
|
9650
|
+
// `rereadConfig` exists, well after the first lines are logged. It is
|
|
9651
|
+
// applied as soon as that handler is in place.
|
|
9652
|
+
let hupWhileBooting = false;
|
|
9653
|
+
const holdHup = () => {
|
|
9654
|
+
hupWhileBooting = true;
|
|
9655
|
+
};
|
|
9656
|
+
process.on('SIGHUP', holdHup);
|
|
9657
|
+
|
|
9646
9658
|
const config = await readConfig();
|
|
9647
9659
|
// The checkouts made on demand by an earlier run of this daemon, found
|
|
9648
9660
|
// again by their name — nothing about them is in the config.
|
|
@@ -9869,7 +9881,11 @@ async function main() {
|
|
|
9869
9881
|
// event type it does not know.
|
|
9870
9882
|
control?.publish({ type: 'runner', runner: advertised });
|
|
9871
9883
|
};
|
|
9884
|
+
process.off('SIGHUP', holdHup);
|
|
9872
9885
|
process.on('SIGHUP', () => rereadConfig('SIGHUP'));
|
|
9886
|
+
if (hupWhileBooting) {
|
|
9887
|
+
void rereadConfig('SIGHUP (sent while booting)');
|
|
9888
|
+
}
|
|
9873
9889
|
|
|
9874
9890
|
// The heartbeat's half of R294: the file's mtime, read once per beat, and a
|
|
9875
9891
|
// re-read when it moved. `stat` and nothing more when it did not, which is
|
package/runner/split.mjs
CHANGED
|
@@ -963,7 +963,7 @@ export function cardLines(card, ink, url = null) {
|
|
|
963
963
|
field('status', [card.statusDisplay ?? card.status, kind].filter(Boolean).join(' · '));
|
|
964
964
|
field('section', card.section);
|
|
965
965
|
field('tags', card.tags?.length ? card.tags.join(', ') : null);
|
|
966
|
-
field('sprint', card.sprint ? `${card.sprint.ref ?? card.sprint.number} ${card.sprint.name ?? ''}`.trim() : null);
|
|
966
|
+
field('sprint', card.sprint ? `${card.sprint.label ?? card.sprint.ref ?? card.sprint.number} ${card.sprint.name ?? ''}`.trim() : null);
|
|
967
967
|
const item = card.workItem;
|
|
968
968
|
field('branch', card.branch ?? item?.branch);
|
|
969
969
|
field('work', item ? [item.statusDisplay ?? item.status, item.runnerName && `on ${item.runnerName}`]
|