crewforth 3.2.0-rc.7 → 3.2.0-rc.9
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/CHANGELOG.md +8 -0
- package/VERSION +1 -1
- package/kit/eval/lib/crew-map/surface.mjs +19 -2
- package/kit/eval/smoke-test.sh +4 -3
- package/kit/hooks/guard-agent-model.sh +4 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -220,6 +220,11 @@ versioning follows [SemVer](https://semver.org/).
|
|
|
220
220
|
|
|
221
221
|
### Fixed
|
|
222
222
|
|
|
223
|
+
- **Crew Map reads a `fetch` call's method from its own options only.** The method was taken from the next four
|
|
224
|
+
lines, so in a file of one-line calls a `{ method: 'POST' }` on a later call was given to the earlier ones, and the
|
|
225
|
+
map reported `POST /api/products is called but no endpoint in this repo provides it` (endpoint-missing) for a
|
|
226
|
+
plain `fetch('/api/products')`. The scan now reads the call's arguments up to its own closing parenthesis, over
|
|
227
|
+
strings and nested brackets; a method on a later line of the same call is still read.
|
|
223
228
|
- **A push approval covers a tag on the approved commit.** `git push <remote> <tag>` had no way to be approved: the
|
|
224
229
|
click and `/crew-approve push` both record a push of the branch, and the tag push of a release was refused after
|
|
225
230
|
either, so the session handed the user the command to run. It now passes when the tag points at the commit the
|
|
@@ -228,6 +233,9 @@ versioning follows [SemVer](https://semver.org/).
|
|
|
228
233
|
- **`change: review` is read as `audit`.** The model table of the working rules names review with audit, and
|
|
229
234
|
`crew-review-agent` cards that said `change: review` were refused. It now takes the audit floor, on a critical path
|
|
230
235
|
too; a kind that is not on the list is still refused.
|
|
236
|
+
- **A one-line task card may open with `Kart`.** Sessions that write in Turkish lead the card with `Kart —` as
|
|
237
|
+
others write `Card —`, and the call was refused as having no card. The Turkish word is read like the English one;
|
|
238
|
+
the fields after it are held to the same rules.
|
|
231
239
|
- **`above:` is read anywhere among a task card's three lines.** A card with `above: <why>` between `change:` and
|
|
232
240
|
`verify:` was refused ("line 3 of the task is not one of files:, change:, verify:") and the call was sent again
|
|
233
241
|
with the line moved down. It is now read in any position and keeps the model as it does after the three; the three
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.2.0-rc.
|
|
1
|
+
3.2.0-rc.9
|
|
@@ -270,6 +270,24 @@ function firstArg(L, i, from) {
|
|
|
270
270
|
}
|
|
271
271
|
return null;
|
|
272
272
|
}
|
|
273
|
+
// The arguments of a call whose `(` ends at `from` on line i, up to its own `)`, across at most four lines: strings
|
|
274
|
+
// and nested brackets are stepped over, so `method:` is read from this call's options and never from the next call's.
|
|
275
|
+
function callArgs(L, i, from) {
|
|
276
|
+
let out = ''; let depth = 0; let q = null;
|
|
277
|
+
for (let j = i; j < Math.min(L.length, i + 4); j++) {
|
|
278
|
+
const s = j === i ? L[i].slice(from) : L[j];
|
|
279
|
+
for (let k = 0; k < s.length; k++) {
|
|
280
|
+
const c = s[k];
|
|
281
|
+
if (q) { if (c === '\\') { out += c + (s[k + 1] ?? ''); k += 1; continue; } if (c === q) q = null; }
|
|
282
|
+
else if (c === '"' || c === "'" || c === '`') q = c;
|
|
283
|
+
else if (c === '(' || c === '[' || c === '{') depth += 1;
|
|
284
|
+
else if (c === ')' || c === ']' || c === '}') { if (depth === 0) return out; depth -= 1; }
|
|
285
|
+
out += c;
|
|
286
|
+
}
|
|
287
|
+
out += ' ';
|
|
288
|
+
}
|
|
289
|
+
return out;
|
|
290
|
+
}
|
|
273
291
|
// The names a module calls HTTP through: axios, and every `x = axios.create(…)` in any of its files (a client made
|
|
274
292
|
// in lib/api.ts is called from every component). A name a file itself makes a server of is not one there.
|
|
275
293
|
function httpClients(pj, m) {
|
|
@@ -358,8 +376,7 @@ export function endpoints(pj, st, out) {
|
|
|
358
376
|
if (nm && nest !== null) add(provides, m, nm[1] === 'All' ? '*' : nm[1], join(nest, nm[2] || ''), f, i, `@${nm[1]}`);
|
|
359
377
|
const fe = /\bfetch\(\s*(['"`])([^'"`]+)\1/.exec(l);
|
|
360
378
|
if (fe && !/^https?:/.test(fe[2])) {
|
|
361
|
-
const
|
|
362
|
-
const mt = /method\s*:\s*['"](\w+)['"]/.exec(win);
|
|
379
|
+
const mt = /method\s*:\s*['"](\w+)['"]/.exec(callArgs(L, i, fe.index + l.slice(fe.index).indexOf('(') + 1));
|
|
363
380
|
add(consumes, m, mt ? mt[1] : 'GET', fe[2], f, i, fe[2]);
|
|
364
381
|
}
|
|
365
382
|
// `api.get<User[]>("/x")` and a call whose path is on the next line read alike.
|
package/kit/eval/smoke-test.sh
CHANGED
|
@@ -8601,7 +8601,8 @@ done
|
|
|
8601
8601
|
_v2b=""; _v2one(){ printf '{"hook_event_name":"PreToolUse","tool_name":"Agent","tool_input":{"prompt":"%s\\n\\nDo it.","subagent_type":"crew-backend-expert","model":"%s"}}' "$1" "$2" > "$_v2/one.json"
|
|
8602
8602
|
( cd "$_v2p" && _v2e bash "$_V2G" < "$_v2/one.json" >"$_v2/oneout" 2>"$_v2/err" ); _rc=$?; }
|
|
8603
8603
|
for _pr in 'files: src/ui/a.ts · change: feature · verify: true' 'files: src/ui/a.ts; change: feature; verify: true' 'files: src/ui/a.ts | change: feature | verify: true' \
|
|
8604
|
-
'Card: files: src/ui/a.ts, src/ui/b.ts · change: feature · verify: true.' 'Card — files: src/ui/a.ts · change: text · verify: none'
|
|
8604
|
+
'Card: files: src/ui/a.ts, src/ui/b.ts · change: feature · verify: true.' 'Card — files: src/ui/a.ts · change: text · verify: none' \
|
|
8605
|
+
'Kart — files: src/ui/a.ts · change: text · verify: none' 'Kart: files: src/ui/a.ts · change: feature · verify: true'; do
|
|
8605
8606
|
_v2one "$_pr" sonnet; [ "$_rc" = 0 ] || _v2b="$_v2b [refused: $_pr → $_rc $(head -c 120 "$_v2/err")]"
|
|
8606
8607
|
done
|
|
8607
8608
|
_v2one 'files: src/payments/p.ts · change: feature · verify: true' sonnet
|
|
@@ -8612,10 +8613,10 @@ _v2one 'files: src/ui/a.ts · change: feature (a small one) · verify: true' son
|
|
|
8612
8613
|
_v2one 'files: src/ui/a.ts · change: architecture (planning only) · verify: none' sonnet
|
|
8613
8614
|
{ [ "$_rc" = 2 ] && grep -q 'runs on opus' "$_v2/err"; } || _v2b="$_v2b [architecture (planning only) was not read as architecture, which runs on opus (rc $_rc)]"
|
|
8614
8615
|
_v2one 'files: src/ui/a.ts\nchange: refactor (no behaviour change)\nverify: true' sonnet; [ "$_rc" = 0 ] || _v2b="$_v2b [a kind with a note in parentheses, three lines → $_rc]"
|
|
8615
|
-
for _pr in 'files: a · change: archi (planning only) · verify: none' 'files: a · change: feature extra · verify: none' 'files: a · verify: true · change: text' 'files: a · change: feature' 'Do this. files: a · change: feature · verify: true'; do
|
|
8616
|
+
for _pr in 'files: a · change: archi (planning only) · verify: none' 'files: a · change: feature extra · verify: none' 'files: a · verify: true · change: text' 'files: a · change: feature' 'Do this. files: a · change: feature · verify: true' 'Kartal files: a · change: feature · verify: true'; do
|
|
8616
8617
|
_v2one "$_pr" sonnet; { [ "$_rc" = 2 ] && grep -q 'opens with its task card' "$_v2/err"; } || _v2b="$_v2b [passed: $_pr → $_rc]"
|
|
8617
8618
|
done
|
|
8618
|
-
[ -z "$_v2b" ] && pass "a card on one line (· ; | separators, a Card: lead, above: on the line) is read by its labels and held to the three-line rules: a critical path still needs opus; a kind with a note in parentheses is the kind, on one line or three; a bad change, labels out of order, a missing verify or prose first are refused" \
|
|
8619
|
+
[ -z "$_v2b" ] && pass "a card on one line (· ; | separators, a Card: or Kart: lead, above: on the line) is read by its labels and held to the three-line rules: a critical path still needs opus; a kind with a note in parentheses is the kind, on one line or three; a bad change, labels out of order, a missing verify or prose first are refused" \
|
|
8619
8620
|
|| fail "the one-line card:$_v2b"
|
|
8620
8621
|
# `above:` among the three lines, not only after them (2026-10-19: 2 of 19 line refusals had it between change: and
|
|
8621
8622
|
# verify:; the retry moved it down and passed). It keeps the model the same way; the three are still all required.
|
|
@@ -442,11 +442,12 @@ _am_trim(){ # $1 -> _AMT: no white space around it, and no separator or full st
|
|
|
442
442
|
}
|
|
443
443
|
# THE CARD ON ONE LINE. Sessions write it as `files: … · change: … · verify: …` (measured on this machine's transcripts,
|
|
444
444
|
# 2026-10-18: 17 of the 39 calls refused for their card, in 6 projects; the next call was the same card on three lines).
|
|
445
|
-
# It is read by its labels, in that order, after an optional `Card:` / `Card
|
|
446
|
-
# fields are then held to exactly the rules of the
|
|
445
|
+
# It is read by its labels, in that order, after an optional `Card:` / `Card —` (or `Kart`, the Turkish word: 2 refused
|
|
446
|
+
# calls, 2026-10-21); `above: <why>` may close the line. The fields are then held to exactly the rules of the
|
|
447
|
+
# three-line card below, so nothing passes here that would not there.
|
|
447
448
|
_am_card_line(){ # $1 = the first line of the task -> 0 and CARD_* set (unchecked); 1 when it is not a one-line card
|
|
448
449
|
local l="$1" r f c v a=""
|
|
449
|
-
case "$l" in [Cc]ard*) l="${l#[Cc]ard}"; l="${l#\*\*}"
|
|
450
|
+
case "$l" in [Cc]ard*|[Kk]art*) l="${l#[Cc]ard}"; l="${l#[Kk]art}"; l="${l#\*\*}"
|
|
450
451
|
while :; do case "$l" in [$' \t:*']*|'—'*|'–'*|-*) case "$l" in '—'*) l="${l#'—'}" ;; '–'*) l="${l#'–'}" ;; *) l="${l:1}" ;; esac ;; *) break ;; esac; done ;;
|
|
451
452
|
esac
|
|
452
453
|
case "$l" in files:*) ;; *) return 1 ;; esac
|
package/package.json
CHANGED