aicodeman 1.18.3 → 1.19.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 +15 -0
- package/dist/attachment-registry.d.ts +25 -0
- package/dist/attachment-registry.d.ts.map +1 -1
- package/dist/attachment-registry.js +45 -1
- package/dist/attachment-registry.js.map +1 -1
- package/dist/hooks-config.d.ts +22 -16
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +20 -14
- package/dist/hooks-config.js.map +1 -1
- package/dist/types/tools.d.ts +1 -1
- package/dist/types/tools.d.ts.map +1 -1
- package/dist/web/ports/config-port.d.ts +2 -0
- package/dist/web/ports/config-port.d.ts.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.a8b08065.js +34 -0
- package/dist/web/public/app.a8b08065.js.br +0 -0
- package/dist/web/public/app.a8b08065.js.gz +0 -0
- package/dist/web/public/approvals-ui.js +24 -15
- package/dist/web/public/approvals-ui.js.br +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.822a486d.js → constants.35c7f91c.js} +167 -20
- package/dist/web/public/constants.35c7f91c.js.br +0 -0
- package/dist/web/public/constants.35c7f91c.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/home-sessions.js +79 -35
- package/dist/web/public/home-sessions.js.br +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/i18n.bb8949de.js +1 -0
- package/dist/web/public/i18n.bb8949de.js.br +0 -0
- package/dist/web/public/i18n.bb8949de.js.gz +0 -0
- package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
- package/dist/web/public/index.html +109 -18
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.0454a3e9.js.gz +0 -0
- package/dist/web/public/{mobile-handlers.bc45f976.js → mobile-handlers.05b89237.js} +16 -0
- package/dist/web/public/mobile-handlers.05b89237.js.br +0 -0
- package/dist/web/public/mobile-handlers.05b89237.js.gz +0 -0
- package/dist/web/public/mobile-overview.js +17 -15
- package/dist/web/public/mobile-overview.js.br +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.c40d28a6.css +1 -0
- package/dist/web/public/mobile.c40d28a6.css.br +0 -0
- package/dist/web/public/mobile.c40d28a6.css.gz +0 -0
- package/dist/web/public/notification-manager.5d229063.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.1e4cb4b2.js → panels-ui.c5a82b6e.js} +48 -46
- package/dist/web/public/panels-ui.c5a82b6e.js.br +0 -0
- package/dist/web/public/panels-ui.c5a82b6e.js.gz +0 -0
- package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
- package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
- package/dist/web/public/session-lineage.js +47 -2
- package/dist/web/public/session-lineage.js.br +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/{session-ui.20be58fa.js → session-ui.71a0ce9a.js} +3 -3
- package/dist/web/public/session-ui.71a0ce9a.js.br +0 -0
- package/dist/web/public/session-ui.71a0ce9a.js.gz +0 -0
- package/dist/web/public/{settings-ui.eacb4f92.js → settings-ui.6cb12d4b.js} +2 -2
- package/dist/web/public/settings-ui.6cb12d4b.js.br +0 -0
- package/dist/web/public/settings-ui.6cb12d4b.js.gz +0 -0
- package/dist/web/public/styles.325eb4f3.css +1 -0
- package/dist/web/public/styles.325eb4f3.css.br +0 -0
- package/dist/web/public/styles.325eb4f3.css.gz +0 -0
- package/dist/web/public/{subagent-windows.2a192c3e.js → subagent-windows.e6ca799f.js} +24 -12
- package/dist/web/public/subagent-windows.e6ca799f.js.br +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/terminal-ui.02b89e2c.js +4 -0
- package/dist/web/public/terminal-ui.02b89e2c.js.br +0 -0
- package/dist/web/public/terminal-ui.02b89e2c.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js +15 -19
- package/dist/web/public/ultracode-windows.js.br +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.6cec0fba.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.4ec670b0.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js +3 -0
- package/dist/web/public/webview-tabs.js.br +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +48 -6
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +50 -12
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +5 -0
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +13 -0
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/sensitive-path.d.ts.map +1 -1
- package/dist/web/sensitive-path.js +17 -0
- package/dist/web/sensitive-path.js.map +1 -1
- package/dist/web/server.d.ts +20 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +51 -0
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-listener-wiring.d.ts.map +1 -1
- package/dist/web/session-listener-wiring.js +5 -0
- package/dist/web/session-listener-wiring.js.map +1 -1
- package/package.json +1 -1
- package/skills/codeman/SKILL.md +41 -26
- package/skills/codeman/preamble.sh +8 -8
- package/skills/codeman/reference/endpoints.md +28 -34
- package/skills/codeman/reference/messaging.md +8 -6
- package/skills/codeman/reference/recipes.md +3 -3
- package/skills/codeman/reference/verbs.md +39 -24
- package/dist/web/public/app.445f1584.js +0 -34
- package/dist/web/public/app.445f1584.js.br +0 -0
- package/dist/web/public/app.445f1584.js.gz +0 -0
- package/dist/web/public/constants.822a486d.js.br +0 -0
- package/dist/web/public/constants.822a486d.js.gz +0 -0
- package/dist/web/public/i18n.86757605.js +0 -1
- package/dist/web/public/i18n.86757605.js.br +0 -0
- package/dist/web/public/i18n.86757605.js.gz +0 -0
- package/dist/web/public/mobile-handlers.bc45f976.js.br +0 -0
- package/dist/web/public/mobile-handlers.bc45f976.js.gz +0 -0
- package/dist/web/public/mobile.1eef31fe.css +0 -1
- package/dist/web/public/mobile.1eef31fe.css.br +0 -0
- package/dist/web/public/mobile.1eef31fe.css.gz +0 -0
- package/dist/web/public/panels-ui.1e4cb4b2.js.br +0 -0
- package/dist/web/public/panels-ui.1e4cb4b2.js.gz +0 -0
- package/dist/web/public/session-ui.20be58fa.js.br +0 -0
- package/dist/web/public/session-ui.20be58fa.js.gz +0 -0
- package/dist/web/public/settings-ui.eacb4f92.js.br +0 -0
- package/dist/web/public/settings-ui.eacb4f92.js.gz +0 -0
- package/dist/web/public/styles.70bf9c2a.css +0 -1
- package/dist/web/public/styles.70bf9c2a.css.br +0 -0
- package/dist/web/public/styles.70bf9c2a.css.gz +0 -0
- package/dist/web/public/subagent-windows.2a192c3e.js.br +0 -0
- package/dist/web/public/subagent-windows.2a192c3e.js.gz +0 -0
- package/dist/web/public/terminal-ui.c182a68d.js +0 -4
- package/dist/web/public/terminal-ui.c182a68d.js.br +0 -0
- package/dist/web/public/terminal-ui.c182a68d.js.gz +0 -0
package/skills/codeman/SKILL.md
CHANGED
|
@@ -42,18 +42,22 @@ hundred-odd lines at the top of every call (a half-re-pasted preamble used to be
|
|
|
42
42
|
single most likely way to break a run).
|
|
43
43
|
|
|
44
44
|
**Codeman seeds the preamble file for you** when it spawns a claude session (server
|
|
45
|
-
1.18.3+), so the bootstrap is usually
|
|
46
|
-
call
|
|
45
|
+
1.18.3+), so the bootstrap is usually nothing at all: these are the two lines every
|
|
46
|
+
later call opens with, and your first REAL call performs them anyway:
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
49
|
. "${XDG_CACHE_HOME:-$HOME/.cache}/codeman-agent-$CODEMAN_SESSION_ID.sh" 2>/dev/null
|
|
50
|
-
[ "${CODEMAN_PREAMBLE:-}" = 1.
|
|
50
|
+
[ "${CODEMAN_PREAMBLE:-}" = 1.19.0 ] || { echo "preamble missing or stale; run the full §0 block"; exit 1; }
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
loader, so when §1 is the job
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
⚠️ **Never spend a Bash call on this check alone.** §1's block opens with this same
|
|
54
|
+
loader, so when §1 is the job, start there: the check rides the spawn call for free,
|
|
55
|
+
and a standalone "preamble OK" call buys nothing while costing a full model turn
|
|
56
|
+
(measured live: a lone check plus the deliberation around it added ~6 s to a 28 s
|
|
57
|
+
two-worker run). §0 is done the moment any job call passes its opening check. Only
|
|
58
|
+
when a call reports missing or stale, run the full block below once — and run it
|
|
59
|
+
**verbatim**: paste it as-is, never re-type it, trim it, or "extract the parts you
|
|
60
|
+
need". A hand-assembled
|
|
57
61
|
preamble is the documented failure mode of this skill: one live run rebuilt it
|
|
58
62
|
"minimally" and lost the `X-Codeman-Parent-Session` header (every worker spawned with
|
|
59
63
|
no lineage arc in the web UI) and the fast-path functions (the spawn fell back to a
|
|
@@ -71,8 +75,8 @@ PRE="${XDG_CACHE_HOME:-$HOME/.cache}/codeman-agent-$CODEMAN_SESSION_ID.sh"
|
|
|
71
75
|
mkdir -p "$(dirname "$PRE")"
|
|
72
76
|
# Rewrite unless the file already ends with THIS version's stamp, so a stale or a
|
|
73
77
|
# half-written file self-heals here instead of costing you a round trip to rm it.
|
|
74
|
-
grep -qs '^CODEMAN_PREAMBLE=1.
|
|
75
|
-
# ---- Codeman agent preamble 1.
|
|
78
|
+
grep -qs '^CODEMAN_PREAMBLE=1.19.0$' "$PRE" || (umask 077; cat > "$PRE" <<'PREAMBLE'
|
|
79
|
+
# ---- Codeman agent preamble 1.19.0 (seeded by Codeman at session spawn; the SKILL.md §0 bootstrap rewrites it when missing or stale) ----
|
|
76
80
|
API="${CODEMAN_API_URL:?CODEMAN_API_URL not set; refusing to guess}"
|
|
77
81
|
SELF="${CODEMAN_SESSION_ID:?CODEMAN_SESSION_ID not set}"
|
|
78
82
|
# Credentials, cheapest first. Your session has usually INHERITED the server's
|
|
@@ -134,14 +138,14 @@ spawn_worker() {
|
|
|
134
138
|
# NOT retryable in a loop: every quick-start failure code is terminal (§5.1).
|
|
135
139
|
[ -n "$sid" ] || { jq -c '{error,errorCode}' <<<"$q" >&2; return 1; }
|
|
136
140
|
[ "$mode" = claude ] || { printf '%s\n' "$sid"; return 0; } # only claude draws a composer
|
|
137
|
-
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
# would false-resolve on flapping idle,
|
|
141
|
-
# rather than run the job there.
|
|
141
|
+
# The server installs hooks into every claude workspace now, so this grep normally
|
|
142
|
+
# passes; it stays because the install is gated on a setting the operator can turn
|
|
143
|
+
# off, remote sessions never get hooks, and a session created by an older server
|
|
144
|
+
# still has none. No marker means sendwait would false-resolve on flapping idle,
|
|
145
|
+
# possibly inside the user's REAL repo: refuse rather than run the job there.
|
|
142
146
|
cp=$(jq -r '.data.casePath // empty' <<<"$q")
|
|
143
147
|
grep -qs '/api/hook-event' "$cp/.claude/settings.local.json" || {
|
|
144
|
-
echo "case '$name' resolved to '$cp', which has no Codeman hooks (
|
|
148
|
+
echo "case '$name' resolved to '$cp', which has no Codeman hooks (workspaceHooksEnabled off, remote, or an older server?): turn the setting on, or work §5.1+§5.5 by hand with markers" >&2
|
|
145
149
|
delete_session "$sid" >/dev/null; return 1; }
|
|
146
150
|
# Short composer wait FIRST, then the trust-dialog probe: a case still showing the
|
|
147
151
|
# dialog can never pass the composer wait, so probing early keeps a cold case from
|
|
@@ -229,10 +233,10 @@ last_text() {
|
|
|
229
233
|
# The stamp is the LAST line on purpose (a truncated write leaves it unset) and is kept
|
|
230
234
|
# bare on purpose: the write condition above anchors on it with $, so an inline comment
|
|
231
235
|
# here would fail that match and rewrite this file on every single bootstrap.
|
|
232
|
-
CODEMAN_PREAMBLE=1.
|
|
236
|
+
CODEMAN_PREAMBLE=1.19.0
|
|
233
237
|
PREAMBLE
|
|
234
238
|
)
|
|
235
|
-
. "$PRE"; [ "${CODEMAN_PREAMBLE:-}" = 1.
|
|
239
|
+
. "$PRE"; [ "${CODEMAN_PREAMBLE:-}" = 1.19.0 ] || { echo "preamble at $PRE is stale or truncated: rm it and re-run this block"; exit 1; }
|
|
236
240
|
```
|
|
237
241
|
|
|
238
242
|
Every later Bash call that touches the API starts with the same two loader lines from
|
|
@@ -273,14 +277,18 @@ plain-text 401: see §6 and [the symptom gallery](reference/endpoints.md#symptom
|
|
|
273
277
|
block is the whole thing. Run it, report, and stop reading. §2 onward is for jobs this
|
|
274
278
|
does not cover; you are not being careless by not reading them.**
|
|
275
279
|
|
|
276
|
-
Fill in the case names and the prompts
|
|
277
|
-
|
|
278
|
-
|
|
280
|
+
Fill in the case names and the prompts, then run it as your FIRST Bash call: no
|
|
281
|
+
standalone preamble check before it (line one below IS that check), and no
|
|
282
|
+
reconnaissance. `ls ~/codeman-cases` answers nothing this block needs: invented
|
|
283
|
+
fresh names need no lookup, and `spawn_worker` refuses a name that already exists
|
|
284
|
+
rather than silently reusing it. Everything below is `spawn_workers` / `sendwait` /
|
|
285
|
+
`last_text` / `delete_session` from the §0 preamble, so there is nothing to assemble
|
|
286
|
+
and no per-call body to hand-build.
|
|
279
287
|
|
|
280
288
|
```bash
|
|
281
289
|
. "${XDG_CACHE_HOME:-$HOME/.cache}/codeman-agent-$CODEMAN_SESSION_ID.sh" 2>/dev/null # §0 loader
|
|
282
|
-
[ "${CODEMAN_PREAMBLE:-}" = 1.
|
|
283
|
-
N=(alpha beta)
|
|
290
|
+
[ "${CODEMAN_PREAMBLE:-}" = 1.19.0 ] || { echo "preamble missing or stale; run the full §0 block"; exit 1; }
|
|
291
|
+
N=(alpha beta) # INVENT one fresh case name per worker; never list cases first
|
|
284
292
|
T=('reply with one line: the absolute path of your working directory'
|
|
285
293
|
'reply with one line: your model name') # tasks, same order as N
|
|
286
294
|
|
|
@@ -307,10 +315,16 @@ done; rm -rf "$D"
|
|
|
307
315
|
|
|
308
316
|
Measured against a live 1.18.0 server: two cold workers spawned and ready in **6.3 s**,
|
|
309
317
|
both turns dispatched and both answers read in **4.0 s** more. If your run takes minutes,
|
|
310
|
-
the time went into deliberation, not the API. The
|
|
318
|
+
the time went into deliberation, not the API. The four things that actually cost time:
|
|
311
319
|
|
|
312
320
|
- **Spawning serially.** One worker per Bash call is one model turn per worker. `&` plus
|
|
313
321
|
`wait`, as above, makes N workers cost about what one costs.
|
|
322
|
+
- **Reconnaissance turns before the spawn.** A standalone preamble check, an
|
|
323
|
+
`ls ~/codeman-cases`, a `list_sessions` "to see what is there": each is a whole
|
|
324
|
+
model turn spent learning something this block already handles (line one performs
|
|
325
|
+
the preamble check, invented names need no listing, and `spawn_worker` refuses
|
|
326
|
+
collisions). A live two-worker run spent ~12 s of its 28 s total on exactly two
|
|
327
|
+
such turns; the API work in between was under 10 s.
|
|
314
328
|
- **Re-deriving the happy path** from §5.1 + §5.2 + §5.3 + §5.10. That is what the
|
|
315
329
|
preamble functions exist to end. Compose them; do not rebuild them. The tells that
|
|
316
330
|
you are rebuilding anyway: a `for` loop around `quick-start`, a poll on `.data.pid`,
|
|
@@ -329,7 +343,8 @@ Four things this block leans on, each one link away, no detour needed to run it:
|
|
|
329
343
|
`~/codeman-cases/<name>`, not your repo. A name that already means something (a
|
|
330
344
|
linked case, a pre-existing directory) is refused by `spawn_worker` rather than
|
|
331
345
|
silently reused. Spawning where the work actually is (a linked case, a git worktree)
|
|
332
|
-
is a different call
|
|
346
|
+
is a different call, and picking the wrong one is the costliest mistake in this
|
|
347
|
+
skill: §5.1. Those workspaces do get hooks now, unless the operator disabled it.
|
|
333
348
|
- `sendwait` supplies the `\r`, picks a fresh `seq`, and self-heals a stranded Enter.
|
|
334
349
|
A prompt without the `\r` is never submitted (§3), a reused `seq` is silently
|
|
335
350
|
swallowed as an already-applied duplicate, and an Enter eaten by an Ink repaint
|
|
@@ -344,9 +359,9 @@ One row per job. Acting on this table alone is correct; the §5 links are the de
|
|
|
344
359
|
|
|
345
360
|
| I want to | Call | Detail |
|
|
346
361
|
|-----------|------|--------|
|
|
347
|
-
| start a worker **where the work is** | `POST /api/v1/quick-start {"caseName":…}`, which **creates** `~/codeman-cases/<name>` unless the name is already a case
|
|
362
|
+
| start a worker **where the work is** | `POST /api/v1/quick-start {"caseName":…}`, which **creates** `~/codeman-cases/<name>` unless the name is already a case. Any other path (a git worktree): `POST /api/v1/sessions {"workingDir":…}` then `POST /api/v1/sessions/:id/interactive`. Both install hooks by default, so expect full signals in either, and **verify** rather than assume. N workers means N worktrees | [§5.1](reference/verbs.md#51-where-to-spawn) |
|
|
348
363
|
| know a new worker can accept a prompt | `GET .../wait-output?match=shift+tab&from=buffer` (urlencode the `+`) | [§5.2](reference/verbs.md#52-readiness) |
|
|
349
|
-
| deliver a task **and** know when it finished | `POST .../input` with `"input":"…\r"`, `clientId`, `seq`, `"wait":true`. Resolves on `stop`, so it is only
|
|
364
|
+
| deliver a task **and** know when it finished | `POST .../input` with `"input":"…\r"`, `clientId`, `seq`, `"wait":true`. Resolves on `stop`, so it is trustworthy only where the workspace **has hooks** (claude mode; installed by default, but the operator can disable it and remote sessions never get them). Costs the worker one billed turn | [§5.3](reference/verbs.md#53-send-a-task-and-wait) |
|
|
350
365
|
| know a hook-less worker finished | it has no `stop`, and `wait:true` there resolves on flapping `idle` **without erroring**: make it print a split, unique marker and `wait-output` on that instead | [§5.5](reference/verbs.md#55-markers-for-hook-less-workers) |
|
|
351
366
|
| read the answer | `GET .../last-response`, **polled** (claude/codex only; empty for the other modes) | [§5.4](reference/verbs.md#54-read-the-answer) |
|
|
352
367
|
| know if it is alive | `GET .../wait?until=exit&timeout=1000`: an immediate `signal:"exit"` means dead. `status` and `pid` both lie | [§5.6](reference/verbs.md#56-alive-and-stuck) |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ---- Codeman agent preamble 1.
|
|
1
|
+
# ---- Codeman agent preamble 1.19.0 (seeded by Codeman at session spawn; the SKILL.md §0 bootstrap rewrites it when missing or stale) ----
|
|
2
2
|
API="${CODEMAN_API_URL:?CODEMAN_API_URL not set; refusing to guess}"
|
|
3
3
|
SELF="${CODEMAN_SESSION_ID:?CODEMAN_SESSION_ID not set}"
|
|
4
4
|
# Credentials, cheapest first. Your session has usually INHERITED the server's
|
|
@@ -60,14 +60,14 @@ spawn_worker() {
|
|
|
60
60
|
# NOT retryable in a loop: every quick-start failure code is terminal (§5.1).
|
|
61
61
|
[ -n "$sid" ] || { jq -c '{error,errorCode}' <<<"$q" >&2; return 1; }
|
|
62
62
|
[ "$mode" = claude ] || { printf '%s\n' "$sid"; return 0; } # only claude draws a composer
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
# would false-resolve on flapping idle,
|
|
67
|
-
# rather than run the job there.
|
|
63
|
+
# The server installs hooks into every claude workspace now, so this grep normally
|
|
64
|
+
# passes; it stays because the install is gated on a setting the operator can turn
|
|
65
|
+
# off, remote sessions never get hooks, and a session created by an older server
|
|
66
|
+
# still has none. No marker means sendwait would false-resolve on flapping idle,
|
|
67
|
+
# possibly inside the user's REAL repo: refuse rather than run the job there.
|
|
68
68
|
cp=$(jq -r '.data.casePath // empty' <<<"$q")
|
|
69
69
|
grep -qs '/api/hook-event' "$cp/.claude/settings.local.json" || {
|
|
70
|
-
echo "case '$name' resolved to '$cp', which has no Codeman hooks (
|
|
70
|
+
echo "case '$name' resolved to '$cp', which has no Codeman hooks (workspaceHooksEnabled off, remote, or an older server?): turn the setting on, or work §5.1+§5.5 by hand with markers" >&2
|
|
71
71
|
delete_session "$sid" >/dev/null; return 1; }
|
|
72
72
|
# Short composer wait FIRST, then the trust-dialog probe: a case still showing the
|
|
73
73
|
# dialog can never pass the composer wait, so probing early keeps a cold case from
|
|
@@ -155,4 +155,4 @@ last_text() {
|
|
|
155
155
|
# The stamp is the LAST line on purpose (a truncated write leaves it unset) and is kept
|
|
156
156
|
# bare on purpose: the write condition above anchors on it with $, so an inline comment
|
|
157
157
|
# here would fail that match and rewrite this file on every single bootstrap.
|
|
158
|
-
CODEMAN_PREAMBLE=1.
|
|
158
|
+
CODEMAN_PREAMBLE=1.19.0
|
|
@@ -251,10 +251,12 @@ that is expected, not a failure: read `terminal?tail=` and strip ANSI instead.
|
|
|
251
251
|
**It means** that session has no Codeman hooks, so `stop` can never fire and the wait
|
|
252
252
|
silently degraded to `idle`, which flaps mid-turn. Nothing rejected your request:
|
|
253
253
|
`wait:true` (and even an explicit `until=stop`) is accepted because the 400 is about
|
|
254
|
-
session **mode**, and the mode really is `claude`. Hooks are
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
session **mode**, and the mode really is `claude`. Hooks are installed into every
|
|
255
|
+
claude workspace at session create (synced `workspaceHooksEnabled`, default ON) and
|
|
256
|
+
swept across recovered sessions at boot, so a linked case or a raw `workingDir` gets
|
|
257
|
+
them too; with the setting off, on a remote session, or on a session from an older
|
|
258
|
+
server, they are absent, see the table under
|
|
259
|
+
[Signals by mode](#signals-by-mode). Measured before that changed: on a
|
|
258
260
|
linked case whose `.claude/settings.local.json` carries env/model/permissions/statusLine
|
|
259
261
|
and no `hooks` block, a `wait?until=stop,exit` parked for twelve consecutive 60 s rounds
|
|
260
262
|
never resolved although the worker finished its turn.
|
|
@@ -360,10 +362,10 @@ loop.
|
|
|
360
362
|
⚠️ `caseName` resolves through the linked-cases registry first, so a name that happens
|
|
361
363
|
to match a case the user linked in lands in that **real repo**, not a fresh scratch
|
|
362
364
|
directory. Pick distinctive scratch names, and use a linked name deliberately when you
|
|
363
|
-
do want a worker in an existing checkout.
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
365
|
+
do want a worker in an existing checkout. It no longer decides whether you get hooks:
|
|
366
|
+
every claude create path installs them, so a linked case and a raw path both get a
|
|
367
|
+
`stop` signal unless the operator turned `workspaceHooksEnabled` off
|
|
368
|
+
([Signals by mode](#signals-by-mode)).
|
|
367
369
|
|
|
368
370
|
**The two-step alternative, `POST /api/v1/sessions`.** Use it when you need a session in
|
|
369
371
|
a directory that is not a case (body takes `workingDir`, `mode`, `name`, `effort`,
|
|
@@ -614,35 +616,27 @@ Three bounded long-polls. Shared semantics:
|
|
|
614
616
|
| `exit` | PTY exited or session deleted | every mode |
|
|
615
617
|
|
|
616
618
|
⚠️ **`claude` mode is necessary for `stop`/`blocked`, not sufficient. The real
|
|
617
|
-
precondition is that the session's working directory has a Codeman hooks block**,
|
|
618
|
-
|
|
619
|
+
precondition is that the session's working directory has a Codeman hooks block**, which
|
|
620
|
+
is now installed by default rather than depending on who created the directory:
|
|
619
621
|
|
|
620
622
|
| The worker's directory | Hooks | `stop` / `blocked` | Synchronize with |
|
|
621
623
|
|------------------------|-------|--------------------|------------------|
|
|
622
|
-
|
|
|
623
|
-
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
`writeHooksConfig()` runs only on the create paths (`case-routes.ts:341`, `:520`,
|
|
639
|
-
`:869`, `ralph-routes.ts:318`, `session-routes.ts:2799` inside
|
|
640
|
-
`if (!existsSync(resolvedCasePath))`, `:2841` for docker). Quick-start against a
|
|
641
|
-
directory that already exists takes the else-if branch and calls
|
|
642
|
-
`refreshStaleCodemanHooks()`, which returns immediately when there is no
|
|
643
|
-
`settings.local.json` and again when the hooks it finds are not ours
|
|
644
|
-
(`hooks-config.ts:706-731`); it never *adds* a hooks block. `POST /api/cases/link` is
|
|
645
|
-
not on that list at all: it only records a name-to-path entry. See
|
|
624
|
+
| any claude workspace, with `workspaceHooksEnabled` ON (the default) | installed at session create, add-only merge | fire | send-and-wait on `stop` |
|
|
625
|
+
| the same, with the setting OFF and no block already on disk | none added | never fire | `wait-output` markers only |
|
|
626
|
+
| a remote SSH session, a docker case that opted out, a workspace Codeman cannot write | none | never fire | `wait-output` markers only |
|
|
627
|
+
| a session created by a pre-1.19.0 server and never restarted since | whatever it had | only if present | check, then choose |
|
|
628
|
+
|
|
629
|
+
The install is an add-only merge, so a user's own hook entries survive and a malformed
|
|
630
|
+
settings file is left untouched. Sessions recovered at server boot get the same sweep,
|
|
631
|
+
which is what heals sessions created before this behavior existed. When in doubt, test
|
|
632
|
+
it rather than reason about it: grep for `/api/hook-event` in
|
|
633
|
+
`<casePath>/.claude/settings.local.json`.
|
|
634
|
+
|
|
635
|
+
Before 1.19.0, `writeHooksConfig()` ran only on the create paths and `quick-start`
|
|
636
|
+
against an existing directory called `refreshStaleCodemanHooks()`, which never *adds* a
|
|
637
|
+
block, so a linked case or a raw `workingDir` had no hooks at all. `POST
|
|
638
|
+
/api/cases/link` still only records a name-to-path entry; what changed is that the
|
|
639
|
+
session-create path installs hooks regardless of how the directory got there. See
|
|
646
640
|
[symptom 8](#8-send-and-wait-resolves-instantly-with-signalidle-and-the-answer-is-last-turns).
|
|
647
641
|
|
|
648
642
|
Default `until` set: `stop,idle,exit`. On non-claude modes the server silently drops
|
|
@@ -196,12 +196,14 @@ idle:
|
|
|
196
196
|
The contract an orchestrator follows for any fleet of two or more messaging workers.
|
|
197
197
|
Every topology in the next section is this protocol plus a wiring diagram.
|
|
198
198
|
|
|
199
|
-
1. **Spawn with a name, and
|
|
200
|
-
`--name` gate above)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
`
|
|
204
|
-
|
|
199
|
+
1. **Spawn with a name, and confirm hooks.** Use `quick-start` with `sessionName` (the
|
|
200
|
+
`--name` gate above). Session create installs the hooks block into the workspace
|
|
201
|
+
whatever kind it is, so a linked case and a raw `POST /api/sessions` path both get
|
|
202
|
+
`stop`/`blocked` by default. ⚠️ Not unconditionally: the operator can turn
|
|
203
|
+
`workspaceHooksEnabled` off, remote SSH sessions never get hooks, and a session from
|
|
204
|
+
an older server may have none, and without them every synchronization below degrades
|
|
205
|
+
to output markers. Grep `<casePath>/.claude/settings.local.json` for
|
|
206
|
+
`/api/hook-event` at spawn rather than inferring it from how the directory got there.
|
|
205
207
|
2. **Readiness before addressing.** Flow 1's ladder per worker, then the availability
|
|
206
208
|
probe. A worker that fails the probe is an HTTP worker for the rest of the run; that
|
|
207
209
|
is a routing decision, not an error.
|
|
@@ -492,9 +492,9 @@ What breaks if you use send-and-wait anyway: `wait:true` is accepted (the 400 is
|
|
|
492
492
|
*mode*, not about hooks, and these are claude-mode sessions), so the call falls back to
|
|
493
493
|
the default set's `idle`, which is a heuristic that flaps mid-turn. You get a "finished"
|
|
494
494
|
answer for a turn still running, and `last-response` then hands you the *previous*
|
|
495
|
-
turn's text. The contrast is the lesson: a worker
|
|
496
|
-
|
|
497
|
-
worker instead.
|
|
495
|
+
turn's text. The contrast is the lesson: a worker whose workspace carries the hooks
|
|
496
|
+
block (Flow 1, and by default any other workspace too) has a `stop` that is definitive
|
|
497
|
+
and free. Where the block is absent you pay one marker per worker instead.
|
|
498
498
|
|
|
499
499
|
```bash
|
|
500
500
|
declare -A TOK
|
|
@@ -30,28 +30,40 @@ wrong directory.** `quick-start` with a new `caseName` does not find your repo:
|
|
|
30
30
|
| Where the work is | Call | Hooks, and therefore signals |
|
|
31
31
|
|-------------------|------|------------------------------|
|
|
32
32
|
| a fresh scratch dir (throwaway experiments) | `POST /api/v1/quick-start {"caseName":"scratch-1","mode":"claude"}` with a **new** case name | Codeman creates the directory and **writes hooks**: `stop` and `blocked` fire, send-and-wait is trustworthy |
|
|
33
|
-
| a linked case (a real repo in the linked-cases registry) | same call with the linked name | **
|
|
34
|
-
| any other absolute path, e.g. a git worktree you made | `POST /api/v1/sessions {"workingDir":"/abs/path","mode":"claude"}` then `POST /api/v1/sessions/:id/interactive` | **
|
|
33
|
+
| a linked case (a real repo in the linked-cases registry) | same call with the linked name | **hooks installed at session create**, so `stop` fires here too. Not guaranteed: the operator can turn it off. Check |
|
|
34
|
+
| any other absolute path, e.g. a git worktree you made | `POST /api/v1/sessions {"workingDir":"/abs/path","mode":"claude"}` then `POST /api/v1/sessions/:id/interactive` | same: **hooks installed at session create**, subject to the same setting. Check |
|
|
35
35
|
|
|
36
36
|
Read `.data.casePath` back from the `quick-start` response and check it is where you
|
|
37
37
|
meant. `caseName` accepts letters, digits, `-` and `_` only, and it resolves through
|
|
38
38
|
the linked-cases registry **first**, so a name that collides with something the user
|
|
39
39
|
linked in lands in that real repo rather than a scratch dir.
|
|
40
40
|
|
|
41
|
-
**The rule is who created the directory.**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
**The rule is a setting, not who created the directory.** Every claude create path
|
|
42
|
+
(`POST /api/sessions`, `POST /api/quick-start`, and quick-start's docker branch) now
|
|
43
|
+
installs the hooks block into the workspace, and the server sweeps the workspaces of
|
|
44
|
+
sessions it recovers at boot. So a linked case, a cloned repo and a hand-made git
|
|
45
|
+
worktree all get `stop`/`blocked`, not just a scratch case Codeman scaffolded. The
|
|
46
|
+
install is an **add-only merge**: a user's own hook entries and every other settings
|
|
47
|
+
key survive, and a malformed settings file is left alone.
|
|
48
|
+
|
|
49
|
+
The gate is the synced **`workspaceHooksEnabled`** setting, **default ON** (an absent
|
|
50
|
+
key counts as ON). Turned OFF, the old behavior returns exactly: an existing Codeman
|
|
51
|
+
block is still refreshed when stale, but one is never added, and the boot sweep is
|
|
52
|
+
skipped. Three cases stay hook-less regardless: **remote SSH sessions** (their
|
|
53
|
+
`workingDir` is a path on another host), **docker cases that opted out**, and any
|
|
54
|
+
workspace Codeman cannot write to.
|
|
55
|
+
|
|
56
|
+
Until this landed, hooks existed only where Codeman created the directory, and the
|
|
57
|
+
gap was invisible: a worker in a linked case never resolved a parked
|
|
58
|
+
`wait?until=stop,exit` across twelve consecutive 60 s rounds, although it had finished
|
|
59
|
+
its turn. If you are driving an older server, assume that older rule.
|
|
60
|
+
|
|
61
|
+
**Check, do not assume.** This is now the load-bearing habit, because you cannot tell
|
|
62
|
+
from the call which way the setting is set, and an old session created before the fix
|
|
63
|
+
on a server that has not restarted still has nothing. Read
|
|
64
|
+
`<casePath>/.claude/settings.local.json` with your own file tools and look for
|
|
65
|
+
`/api/hook-event`. Present means `stop`/`blocked` will fire; absent means they never
|
|
66
|
+
will, whatever kind of workspace it is.
|
|
55
67
|
|
|
56
68
|
⚠️ **The hook-less failure is silent, and it is the worst one in this skill.**
|
|
57
69
|
`"wait":true` is still **accepted** on a hook-less claude session: the 400 you may be
|
|
@@ -59,9 +71,10 @@ expecting is about session *mode*, not about hooks. With no `stop` to resolve on
|
|
|
59
71
|
default signal set falls back to the heuristic `idle`, which flaps mid-turn, so
|
|
60
72
|
send-and-wait returns "finished" while the worker is still working, and the
|
|
61
73
|
`last-response` you read next hands you the **previous** turn's text. No error is
|
|
62
|
-
raised anywhere.
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
raised anywhere. Hooks are installed by default now, so this is rarer than it was, but
|
|
75
|
+
the failure is unchanged when it happens: in any workspace whose settings file has no
|
|
76
|
+
`/api/hook-event`, use markers ([§5.5](#55-markers-for-hook-less-workers)) and treat
|
|
77
|
+
send-and-wait's answer as unreliable.
|
|
65
78
|
|
|
66
79
|
Spawning at a raw path:
|
|
67
80
|
|
|
@@ -238,11 +251,13 @@ fi
|
|
|
238
251
|
|
|
239
252
|
### 5.3 Send a task and wait
|
|
240
253
|
|
|
241
|
-
⚠️ **Precondition:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
254
|
+
⚠️ **Precondition: a claude worker whose workspace has the hooks block**, because
|
|
255
|
+
this is trustworthy only when the `stop` hook exists. Every claude create path installs
|
|
256
|
+
it by default now, so that is the normal case, but where it is absent (the setting off,
|
|
257
|
+
a remote session, an older server) the call is still accepted, resolves on flapping
|
|
258
|
+
`idle`, and reports a turn as finished while it is still running, with no error
|
|
259
|
+
anywhere. Check hooks first ([§5.1](#51-where-to-spawn)); where they are absent, use
|
|
260
|
+
markers
|
|
246
261
|
([§5.5](#55-markers-for-hook-less-workers)).
|
|
247
262
|
|
|
248
263
|
It registers the waiter *before* typing,
|