crewforth 3.1.1 → 3.2.0-rc.1

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/README.md +4 -3
  3. package/VERSION +1 -1
  4. package/adopt.sh +11 -0
  5. package/kit/AGENT_TEMPLATE.md +2 -1
  6. package/kit/CLAUDE.md +9 -8
  7. package/kit/agents/crew-commit-agent.md +7 -2
  8. package/kit/agents/crew-docs-agent.md +71 -0
  9. package/kit/agents/crew-planner.md +2 -0
  10. package/kit/agents/crew-refuter.md +77 -0
  11. package/kit/agents/crew-security-expert.md +3 -1
  12. package/kit/agents/crew-session-manager.md +11 -9
  13. package/kit/eval/doctor.sh +91 -3
  14. package/kit/eval/golden-routing.txt +9 -0
  15. package/kit/eval/lib/crew-map/crew-map.sh +26 -0
  16. package/kit/eval/lib/crew-map/detect.mjs +238 -0
  17. package/kit/eval/lib/crew-map/narrative.mjs +98 -0
  18. package/kit/eval/lib/crew-map/parse.mjs +305 -0
  19. package/kit/eval/lib/crew-map/project.mjs +163 -0
  20. package/kit/eval/lib/crew-map/rules/names.json +38 -0
  21. package/kit/eval/lib/crew-map/rules/packages.json +142 -0
  22. package/kit/eval/lib/crew-map/rules/python-stdlib.json +197 -0
  23. package/kit/eval/lib/crew-map/scan.mjs +214 -0
  24. package/kit/eval/lib/crew-map/stacks.mjs +441 -0
  25. package/kit/eval/lib/crew-map/surface.mjs +457 -0
  26. package/kit/eval/lib/findings/findings.mjs +410 -0
  27. package/kit/eval/lib/findings/findings.schema.json +122 -0
  28. package/kit/eval/lib/findings/findings.sh +29 -0
  29. package/kit/eval/lib/settings-json.awk +5 -0
  30. package/kit/eval/lib/star.sh +23 -7
  31. package/kit/eval/lib/statusline.settings.json +6 -0
  32. package/kit/eval/lib/statusline.sh +115 -0
  33. package/kit/eval/smoke-test.sh +465 -38
  34. package/kit/hooks/agent-outcome.sh +6 -3
  35. package/kit/hooks/guard-agent-model.sh +15 -5
  36. package/kit/hooks/guard-bash.sh +240 -182
  37. package/kit/hooks/guard-question.sh +73 -0
  38. package/kit/hooks/guard-write.sh +21 -0
  39. package/kit/hooks/prompt-approval.sh +320 -103
  40. package/kit/hooks/refuter-ledger.sh +80 -0
  41. package/kit/owned-blobs.tsv +4 -4
  42. package/kit/settings.json +33 -0
  43. package/kit/skills/crew-approve/SKILL.md +7 -0
  44. package/kit/skills/crew-doctor/SKILL.md +5 -1
  45. package/kit/skills/crew-handoff/SKILL.md +3 -2
  46. package/kit/skills/crew-map/SKILL.md +44 -0
  47. package/kit/skills/crew-review/SKILL.md +2 -0
  48. package/kit/skills/crew-update/SKILL.md +1 -1
  49. package/kit/skills/incident-runbook/SKILL.md +2 -2
  50. package/kit/skills/security-scan/references/verify.md +6 -3
  51. package/kit/studio/README.md +12 -0
  52. package/kit/studio/server/index.js +114 -11
  53. package/kit/studio/server/lib/crew-map.js +113 -0
  54. package/kit/studio/server/lib/model-outcomes.js +130 -15
  55. package/kit/studio/server/lib/pricing.js +3 -0
  56. package/kit/studio/server/lib/remote.js +99 -0
  57. package/kit/studio/server/lib/usage.js +74 -14
  58. package/kit/studio/web/app.js +214 -12
  59. package/kit/studio/web/canvas.js +44 -120
  60. package/kit/studio/web/graph-plan.js +10 -4
  61. package/kit/studio/web/index.html +10 -5
  62. package/kit/studio/web/map-plan.js +341 -0
  63. package/kit/studio/web/map.js +503 -0
  64. package/kit/studio/web/models-plan.js +61 -7
  65. package/kit/studio/web/models.js +19 -3
  66. package/kit/studio/web/style.css +125 -0
  67. package/kit/studio/web/usage.js +12 -0
  68. package/kit/studio/web/viewport.js +160 -0
  69. package/package.json +6 -5
  70. package/start.sh +10 -0
@@ -19,7 +19,8 @@
19
19
  # -> blocked: not run, nothing concluded.
20
20
  # not finished in CREW_VERIFY_TIMEOUT seconds (540)
21
21
  # -> timeout: stopped, nothing concluded.
22
- # Then one line is added to .claude/state/model-outcomes.tsv, and the class is looked at:
22
+ # Then one line is added to .claude/state/model-outcomes.tsv, its last column the gate's reason
23
+ # when the work is critical (risk_why, "-" when it is not), and the class is looked at:
23
24
  # where the first try failed too often, its floor goes one model up (crew-model-floors.auto).
24
25
  # Only ever up: lowering a floor is the user's decision and nothing here does it.
25
26
  # PostToolUse (Agent) a foreground call has come back. If its verify failed, or its report closed with
@@ -280,6 +281,8 @@ case "$EV" in
280
281
  _am_rec_get "$REC" verify; VCMD="$_AMV"
281
282
  _am_rec_get "$REC" agent; AG="$_AMV"; _am_rec_get "$REC" change; CH="$_AMV"; _am_rec_get "$REC" risk; RK="$_AMV"
282
283
  _am_rec_get "$REC" card; CID="$_AMV"; _am_rec_get "$REC" esc; ESC="${_AMV:--}"
284
+ # A record written before the gate kept its reason has none: that is "-", not a reason made up here.
285
+ _am_rec_get "$REC" why; RW="${_AMV:--}"; RW="${RW//$'\t'/ }"
283
286
  _am_rec_get "$REC" asked || _am_rec_get "$REC" tier; ASK="$_AMV"
284
287
  mkdir -p "$_AMD/results" "$_AMD/tries" "$_AMD/fails" 2>/dev/null || exit 0
285
288
  TRIES=0; [ -f "$_AMD/tries/$AID" ] && IFS= read -r TRIES < "$_AMD/tries/$AID"; case "$TRIES" in ''|*[!0-9]*) TRIES=0 ;; esac
@@ -359,10 +362,10 @@ case "$EV" in
359
362
  printf 'verify=%s\nfixes=%s\nconfidence=%s\ntier=%s\nesc=%s\nescalate=%s\nwhynot=%s\ncmd=%s\n' "$RES" "$TRIES" "$CONF" "$ASK" "$ESC" "$ESCL" "$WHYNOT" "$VCMD" > "$_AMD/results/$AID" 2>/dev/null
360
363
  case "$REC" in "$_AMD/pending/"*) rm -f "$REC" 2>/dev/null ;; *) : > "$REC.used" 2>/dev/null ;; esac
361
364
  TSV="$_AMS/model-outcomes.tsv"
362
- [ -s "$TSV" ] || printf 'ts\tagent_id\tagent\tchange\trisk\tcard\tmodel\tverify\tfixes\tescalated_from\tran_on\tconfidence\n' > "$TSV" 2>/dev/null
365
+ [ -s "$TSV" ] || printf 'ts\tagent_id\tagent\tchange\trisk\tcard\tmodel\tverify\tfixes\tescalated_from\tran_on\tconfidence\trisk_why\n' > "$TSV" 2>/dev/null
363
366
  _ao_now
364
367
  _ao_lock
365
- printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$_AON" "$AID" "$AG" "$CH" "$RK" "$CID" "$ASK" "$RES" "$TRIES" "$ESC" "$RAN" "$CONF" >> "$TSV" 2>/dev/null
368
+ printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$_AON" "$AID" "$AG" "$CH" "$RK" "$CID" "$ASK" "$RES" "$TRIES" "$ESC" "$RAN" "$CONF" "$RW" >> "$TSV" 2>/dev/null
366
369
  _ao_unlock
367
370
  case "$RES" in pass|fail) _ao_calibrate "$AG" "$CH" "$RK" ;; esac
368
371
  exit 0 ;;
@@ -357,9 +357,13 @@ _am_tier(){ # $1 = a model as a call or a transcript names it -> _AMT haiku|son
357
357
  # a .sql file, schema.prisma. The path is read from the project's root down, so the name of the folder the project
358
358
  # sits in decides nothing. .claude/crew-model-rules, which only the user writes, adds (`+ glob`) and removes
359
359
  # (`- glob`); the last line that matches wins.
360
- _AM_W_L='auth|authn|authz|authentication|authorization|oauth|payments?|billing|migrations?|security|crypto|secrets?'
361
- _AM_W_C='Auth|Authn|Authz|Authentication|Authorization|OAuth|Payments?|Billing|Migrations?|Security|Crypto|Secrets?'
362
- _AM_W_U='AUTH|AUTHN|AUTHZ|OAUTH|PAYMENTS?|BILLING|MIGRATIONS?|SECURITY|CRYPTO|SECRETS?'
360
+ # Legal and personal-data texts are critical too (crew-docs-agent's work): legal, privacy, consent in every form, and
361
+ # terms only in lower case — `terms/`, `terms-of-service.md` — because the camelCase `searchTerms` is a search box.
362
+ # Store listings are critical by place and only as text: under store/, store-listing/, fastlane/metadata/ or
363
+ # metadata/android|ios/, a .txt .md .xml .yml .yaml is; code there (a Redux `store/index.ts`) and images are not.
364
+ _AM_W_L='auth|authn|authz|authentication|authorization|oauth|payments?|billing|migrations?|security|crypto|secrets?|legal|privacy|terms|consent'
365
+ _AM_W_C='Auth|Authn|Authz|Authentication|Authorization|OAuth|Payments?|Billing|Migrations?|Security|Crypto|Secrets?|Legal|Privacy|Consent'
366
+ _AM_W_U='AUTH|AUTHN|AUTHZ|OAUTH|PAYMENTS?|BILLING|MIGRATIONS?|SECURITY|CRYPTO|SECRETS?|LEGAL|PRIVACY|TERMS|CONSENT'
363
367
  _AM_RE_L="(^|[^A-Za-z])($_AM_W_L)([^a-z]|\$)"
364
368
  _AM_RE_C="(^|[^A-Z])($_AM_W_C)([^a-z]|\$)"
365
369
  _AM_RE_U="(^|[^A-Za-z])($_AM_W_U)([^A-Za-z]|\$)"
@@ -394,7 +398,10 @@ _am_crit_path(){ # $1 = a path or a glob -> 0 critical (_AMW says by what), 1 n
394
398
  local p r k g hit=1
395
399
  _am_rel "$1"; p="$_AMRP"; _AMW=""
396
400
  if [[ "$p" =~ $_AM_RE_L ]] || [[ "$p" =~ $_AM_RE_C ]] || [[ "$p" =~ $_AM_RE_U ]]; then hit=0; _AMW="${BASH_REMATCH[2]}"
397
- else case "$p" in *.sql|*.SQL) hit=0; _AMW="a .sql file" ;; schema.prisma|*/schema.prisma) hit=0; _AMW="schema.prisma" ;; esac; fi
401
+ else case "$p" in *.sql|*.SQL) hit=0; _AMW="a .sql file" ;; schema.prisma|*/schema.prisma) hit=0; _AMW="schema.prisma" ;;
402
+ store/*|*/store/*|store-listing/*|*/store-listing/*|fastlane/metadata/*|*/fastlane/metadata/*|metadata/android/*|*/metadata/android/*|metadata/ios/*|*/metadata/ios/*)
403
+ case "$p" in *.txt|*.md|*.xml|*.yml|*.yaml) hit=0; _AMW="a store listing text" ;; esac ;;
404
+ esac; fi
398
405
  _am_rules
399
406
  for r in ${_AM_RULES[@]+"${_AM_RULES[@]}"}; do
400
407
  k="${r%%$'\t'*}"; g="${r#*$'\t'}"
@@ -818,7 +825,10 @@ fi
818
825
  _json_slice "$INPUT" tool_use_id >/dev/null; tid="$_JS"; case "$tid" in ''|*[!A-Za-z0-9._-]*) tid="x$RANDOM" ;; esac
819
826
  if mkdir -p "$_AMD/pending" 2>/dev/null; then
820
827
  if [ "${BASH_VERSINFO[0]}" -ge 5 ] || { [ "${BASH_VERSINFO[0]}" -eq 4 ] && [ "${BASH_VERSINFO[1]}" -ge 2 ]; }; then printf -v t '%(%s)T' -1; else t="$(date +%s)"; fi
821
- { printf 'agent=%s\ntier=%s\nchange=%s\nrisk=%s\ncard=%s\nbg=%s\nesc=%s\nverify=%s\nfiles=%s\n' "$st" "$m" "$CARD_CHANGE" "$CARD_RISK" "$CARD_ID" "$bg" "${p:--}" "$CARD_VERIFY" "$CARD_FILES" > "$_AMD/pending/$t-$tid"; } 2>/dev/null || true
828
+ # Why the work counts as critical, as the gate decided it, so a reader shows the reason and does not work it out
829
+ # again: one line, no tab (it ends up in a column of model-outcomes.tsv).
830
+ rw="${CARD_RISKWHY:--}"; rw="${rw//$'\t'/ }"; rw="${rw//$'\r'/ }"; rw="${rw//$'\n'/ }"
831
+ { printf 'agent=%s\ntier=%s\nchange=%s\nrisk=%s\ncard=%s\nbg=%s\nesc=%s\nverify=%s\nfiles=%s\nwhy=%s\n' "$st" "$m" "$CARD_CHANGE" "$CARD_RISK" "$CARD_ID" "$bg" "${p:--}" "$CARD_VERIFY" "$CARD_FILES" "$rw" > "$_AMD/pending/$t-$tid"; } 2>/dev/null || true
822
832
  fi
823
833
  exit 0
824
834
  }