@oneie/claude 0.8.0 → 0.10.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.
Files changed (230) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/abm-strategist.md +67 -1
  3. package/agents/ads-meta.md +67 -1
  4. package/agents/analyst.md +67 -1
  5. package/agents/animator.md +108 -0
  6. package/agents/architect.md +269 -20
  7. package/agents/brand-guardian.md +67 -1
  8. package/agents/brand-strategist.md +67 -1
  9. package/agents/campaign-content.md +67 -1
  10. package/agents/campaign-email.md +67 -1
  11. package/agents/campaign-sms.md +67 -1
  12. package/agents/campaign-social.md +67 -1
  13. package/agents/cco.md +83 -2
  14. package/agents/ceo.md +108 -11
  15. package/agents/chairman.md +197 -0
  16. package/agents/cmo.md +82 -2
  17. package/agents/community-greeter.md +67 -1
  18. package/agents/community-moderator.md +67 -1
  19. package/agents/compliance.md +67 -1
  20. package/agents/copywriter.md +67 -1
  21. package/agents/creative-strategist.md +67 -1
  22. package/agents/cro.md +81 -1
  23. package/agents/cto.md +266 -28
  24. package/agents/customer-interviewer.md +67 -1
  25. package/agents/customer-researcher.md +67 -1
  26. package/agents/customer-success-manager.md +67 -1
  27. package/agents/customer-trainer.md +67 -1
  28. package/agents/cxo.md +82 -1
  29. package/agents/demand-creator.md +67 -1
  30. package/agents/demo-mover.md +67 -1
  31. package/agents/demo-specialist.md +67 -1
  32. package/agents/demo-thai-family-law.md +67 -1
  33. package/agents/designer.md +67 -1
  34. package/agents/discovery-caller.md +67 -1
  35. package/agents/doctor.md +269 -0
  36. package/agents/educate-coach.md +67 -1
  37. package/agents/elevate-tutor.md +67 -1
  38. package/agents/email-lifecycle-marketer.md +67 -1
  39. package/agents/engage-specialist.md +67 -1
  40. package/agents/events-coordinator.md +67 -1
  41. package/agents/foundation-builder.md +67 -1
  42. package/agents/funnel-architect.md +67 -1
  43. package/agents/gift-creator.md +67 -1
  44. package/agents/google-ads.md +67 -1
  45. package/agents/guide.md +67 -1
  46. package/agents/helpdesk-dispatcher.md +67 -1
  47. package/agents/hook-specialist.md +67 -1
  48. package/agents/identify-optimizer.md +67 -1
  49. package/agents/implementer.md +313 -45
  50. package/agents/incident-commander.md +67 -1
  51. package/agents/insights-lead.md +87 -1
  52. package/agents/journey-runner.md +67 -1
  53. package/agents/linkedin-ads.md +67 -1
  54. package/agents/live-sales-chat.md +67 -1
  55. package/agents/market-researcher.md +67 -1
  56. package/agents/media-buyer.md +67 -1
  57. package/agents/memory-keeper.md +195 -0
  58. package/agents/movers-customer-researcher.md +67 -1
  59. package/agents/movers-foundation-builder.md +67 -1
  60. package/agents/movers-market-researcher.md +67 -1
  61. package/agents/movers-pricing-strategist.md +67 -1
  62. package/agents/nurture-architect.md +67 -1
  63. package/agents/offer-architect.md +67 -1
  64. package/agents/onboarder.md +67 -1
  65. package/agents/onboarding-specialist.md +67 -1
  66. package/agents/operations-dashboard.md +87 -1
  67. package/agents/perf-engineer.md +333 -37
  68. package/agents/playbook-writer.md +67 -1
  69. package/agents/plg-strategist.md +67 -1
  70. package/agents/positioning-architect.md +67 -1
  71. package/agents/press-officer.md +67 -1
  72. package/agents/pricing-strategist.md +67 -1
  73. package/agents/privacy-officer.md +67 -1
  74. package/agents/referral-manager.md +67 -1
  75. package/agents/refine-analyst.md +67 -1
  76. package/agents/release-manager.md +446 -39
  77. package/agents/renewals-upsell-rep.md +67 -1
  78. package/agents/review-engineer.md +319 -45
  79. package/agents/rewards-steward.md +67 -1
  80. package/agents/sales-call-coach.md +67 -1
  81. package/agents/sales-closer.md +67 -1
  82. package/agents/security-auditor.md +343 -48
  83. package/agents/sell-closer.md +67 -1
  84. package/agents/share-amplifier.md +67 -1
  85. package/agents/social-media-manager.md +67 -1
  86. package/agents/storyteller.md +301 -0
  87. package/agents/strategist.md +67 -1
  88. package/agents/strategy-aligner.md +67 -1
  89. package/agents/support-agent.md +67 -1
  90. package/agents/tagger.md +327 -0
  91. package/agents/tech-writer.md +195 -22
  92. package/agents/test-engineer.md +398 -29
  93. package/agents/tiktok-ads.md +67 -1
  94. package/agents/tracking-engineer.md +67 -1
  95. package/agents/trailkeeper.md +181 -0
  96. package/agents/upsell-strategist.md +67 -1
  97. package/agents/voice.md +67 -1
  98. package/agents/w1-recon.md +1 -1
  99. package/agents/w2-decide.md +1 -1
  100. package/agents/w3-edit.md +8 -2
  101. package/agents/w4-verify.md +13 -0
  102. package/agents/workflow-optimiser.md +81 -1
  103. package/commands/close.md +916 -160
  104. package/commands/deploy.md +102 -724
  105. package/commands/do.md +58 -2
  106. package/commands/sweep.md +159 -0
  107. package/commands/tasks.md +222 -0
  108. package/hooks/scripts/dev-only.sh +135 -0
  109. package/hooks/scripts/git-add-guard.sh +37 -2
  110. package/hooks/scripts/session-start.sh +32 -4
  111. package/package.json +1 -1
  112. package/rules/scripts.md +85 -0
  113. package/scripts/CLAUDE.md +315 -0
  114. package/scripts/ad-copy-lint.sh +656 -0
  115. package/scripts/agent-actor-parity.sh +129 -0
  116. package/scripts/blocks-manifest-cached.sh +100 -0
  117. package/scripts/chat-context-check.sh +89 -0
  118. package/scripts/chrome.mjs +18 -0
  119. package/scripts/close-metrics.sh +587 -0
  120. package/scripts/close-owner.sh +326 -0
  121. package/scripts/db-sync-lock-check.sh +116 -0
  122. package/scripts/deploy-emit.sh +311 -0
  123. package/scripts/deploy-gate-check.sh +155 -0
  124. package/scripts/deploy-ready.sh +78 -0
  125. package/scripts/deploy-record.sh +605 -0
  126. package/scripts/deploy-schema-check.sh +58 -0
  127. package/scripts/deploy.sh +393 -243
  128. package/scripts/do-auto.sh +127 -26
  129. package/scripts/do-board.sh +429 -0
  130. package/scripts/do-close.sh +1184 -0
  131. package/scripts/do-consumer-sweep.sh +18 -1
  132. package/scripts/do-decide.sh +476 -0
  133. package/scripts/do-fleet.sh +8 -2
  134. package/scripts/do-plan-json.mjs +110 -12
  135. package/scripts/do-prove-selftest.sh +108 -0
  136. package/scripts/do-prove.sh +86 -10
  137. package/scripts/do-rank.py +200 -3
  138. package/scripts/do-reconcile.sh +73 -12
  139. package/scripts/do-signal.sh +101 -23
  140. package/scripts/do-smoke.sh +18 -1
  141. package/scripts/do-w4-gates.sh +11 -1
  142. package/scripts/do-world-check.sh +153 -0
  143. package/scripts/download-stats.sh +172 -0
  144. package/scripts/factory-brief-check.sh +330 -0
  145. package/scripts/factory-check.sh +18 -1
  146. package/scripts/factory-close-check.sh +257 -0
  147. package/scripts/factory-emit.sh +211 -0
  148. package/scripts/factory-executor-check.mjs +353 -0
  149. package/scripts/factory-peak.sh +301 -0
  150. package/scripts/factory-repo.sh +71 -0
  151. package/scripts/factory-review-check.mjs +61 -0
  152. package/scripts/factory-tasks-check.sh +18 -1
  153. package/scripts/fixtures/factory-brief-real.md +44 -0
  154. package/scripts/flywheel-outcome.sh +63 -0
  155. package/scripts/gate-reaper-check.sh +98 -0
  156. package/scripts/gate-reaper.sh +9 -0
  157. package/scripts/gate-watchdog.sh +619 -0
  158. package/scripts/gc-content-check.sh +142 -0
  159. package/scripts/gh-traffic-capture.sh +153 -0
  160. package/scripts/govern-order-check.sh +202 -0
  161. package/scripts/governor-doors-check.sh +86 -5
  162. package/scripts/health.sh +448 -0
  163. package/scripts/id-inventory.mjs +418 -0
  164. package/scripts/incident.sh +212 -0
  165. package/scripts/land.sh +755 -45
  166. package/scripts/lib/gc-finished.sh +77 -0
  167. package/scripts/livekit-ratchet.sh +18 -1
  168. package/scripts/machine-check.sh +1 -1
  169. package/scripts/memory-index-budget.sh +79 -0
  170. package/scripts/npm-downloads.sh +109 -0
  171. package/scripts/one-agents.mjs +204 -8
  172. package/scripts/one-resume.sh +31 -3
  173. package/scripts/pr-body.sh +335 -0
  174. package/scripts/preview-fd-check.sh +289 -0
  175. package/scripts/redirect-lint.sh +169 -0
  176. package/scripts/release.sh +40 -6
  177. package/scripts/resume-lost-sessions.sh +68 -0
  178. package/scripts/shoot-pages.mjs +140 -0
  179. package/scripts/signal-meta-backfill.ts +451 -0
  180. package/scripts/signal-watch.sh +63 -6
  181. package/scripts/speed-cache-check.sh +12 -2
  182. package/scripts/sweep.sh +426 -0
  183. package/scripts/task-titles-dump.ts +101 -0
  184. package/scripts/test-cached.sh +47 -10
  185. package/scripts/test-lanes.sh +14 -0
  186. package/scripts/thread-name-backfill.ts +215 -0
  187. package/scripts/triage-shape-check.sh +149 -0
  188. package/scripts/tsc-cached.sh +155 -8
  189. package/scripts/typedb-flake-check.sh +3 -1
  190. package/scripts/urls-lint.sh +8 -0
  191. package/scripts/verify-board-doors.sh +80 -0
  192. package/scripts/verify-fast.sh +159 -6
  193. package/scripts/worktree-up.sh +21 -3
  194. package/skills/astro/SKILL.md +9 -3
  195. package/skills/astro/optimize-performance.md +3 -2
  196. package/skills/cloudflare/SKILL.md +3 -2
  197. package/skills/cloudflare-security-audit/AI-AND-LLM.md +83 -0
  198. package/skills/cloudflare-security-audit/ATTACK-CLASSES.md +130 -0
  199. package/skills/cloudflare-security-audit/CLIENT-SIDE.md +83 -0
  200. package/skills/cloudflare-security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
  201. package/skills/cloudflare-security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
  202. package/skills/cloudflare-security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
  203. package/skills/cloudflare-security-audit/HUNTING.md +251 -0
  204. package/skills/cloudflare-security-audit/LICENSE +21 -0
  205. package/skills/cloudflare-security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
  206. package/skills/cloudflare-security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
  207. package/skills/cloudflare-security-audit/PROVENANCE.md +78 -0
  208. package/skills/cloudflare-security-audit/RECONNAISSANCE.md +156 -0
  209. package/skills/cloudflare-security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
  210. package/skills/cloudflare-security-audit/SKILL.md +192 -0
  211. package/skills/cloudflare-security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
  212. package/skills/cloudflare-security-audit/VALIDATION-AND-REPORTING.md +186 -0
  213. package/skills/cloudflare-security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
  214. package/skills/cloudflare-security-audit/report-schema.json +461 -0
  215. package/skills/cloudflare-security-audit/validate-coverage-ledger.cjs +872 -0
  216. package/skills/cloudflare-security-audit/validate-coverage-ledger.test.cjs +740 -0
  217. package/skills/cloudflare-security-audit/validate-findings.cjs +773 -0
  218. package/skills/cloudflare-security-audit/validate-findings.test.cjs +652 -0
  219. package/skills/deploy/REFERENCE.md +713 -0
  220. package/skills/deploy/SKILL.md +140 -0
  221. package/skills/fleet-audit/SKILL.md +58 -0
  222. package/skills/meeting/SKILL.md +220 -0
  223. package/skills/planning/SKILL.md +256 -0
  224. package/skills/shadcn/SKILL.md +1 -1
  225. package/skills/typedb/SKILL.md +7 -0
  226. package/skills/voice/SKILL.md +94 -6
  227. package/skills/voice/corpus-check.sh +87 -0
  228. package/templates/template-agent.md +7 -1
  229. package/templates/template-feature.md +9 -0
  230. package/templates/template-todo.md +29 -0
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env bash
2
+ # agent-actor-parity.sh — the Proof line for text/agent-actor-plan.md.
3
+ #
4
+ # THREE GUARDS over the three stores that claim to know which agents are live.
5
+ # All reads are read-only (D1 SELECT, R2 ListObjectsV2, one HTTP GET). Nothing
6
+ # is written, nothing is published.
7
+ #
8
+ # G1 IDENTITY every distinct follows.actor_id is a mintable actor id
9
+ # ^[a-z0-9][a-z0-9-]{0,62}$ — no trailing dot, no domain
10
+ # G2 GROUNDING every distinct follows.actor_id has a live persona in R2
11
+ # at <ws>/agents/<id>.md
12
+ # G3 SUBSTRATE count(R2 live personas) == count(actor with actor-status "live")
13
+ #
14
+ # EXIT CODES ARE THE VERDICT
15
+ # 0 all three pass
16
+ # 1 a guard FAILED (real mismatch)
17
+ # 3 no guard failed but one is UNRUN — an unrun gate is not a pass
18
+ # 4 could not read a store (credentials / network) — UNRUN, never green
19
+ #
20
+ # Usage: bash .claude/scripts/agent-actor-parity.sh [workspace] (default: one)
21
+ # bash .claude/scripts/agent-actor-parity.sh --self-test (red + green proof)
22
+ set -uo pipefail
23
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
24
+ WS="${1:-one}"
25
+
26
+ # ── the guard logic, isolated so --self-test can drive it with fixtures ──────
27
+ guards() { # $1=actor_ids file $2=r2 live names file $3=substrate live count ("" = unrun)
28
+ python3 - "$1" "$2" "${3:-}" <<'PY'
29
+ import re,sys
30
+ ids=[l.strip() for l in open(sys.argv[1]) if l.strip()]
31
+ r2=set(l.strip() for l in open(sys.argv[2]) if l.strip())
32
+ sub=sys.argv[3]
33
+ ID=re.compile(r'^[a-z0-9][a-z0-9-]{0,62}$')
34
+ bad=[i for i in ids if not ID.match(i)]
35
+ ung=[i for i in ids if i not in r2]
36
+ rc=0
37
+ print(f"G1 IDENTITY {'pass' if not bad else 'FAIL'} {len(ids)-len(bad)}/{len(ids)} mintable" + (f" -> {' '.join(sorted(bad))}" if bad else ""))
38
+ print(f"G2 GROUNDING {'pass' if not ung else 'FAIL'} {len(ids)-len(ung)}/{len(ids)} have an R2 persona" + (f" -> {len(ung)} ungrounded" if ung else ""))
39
+ if bad or ung: rc=1
40
+ if sub=="":
41
+ print(f"G3 SUBSTRATE unrun R2 live={len(r2)} actor-status live=UNREADABLE (no door)")
42
+ rc = rc if rc else 3
43
+ else:
44
+ ok = int(sub)==len(r2) and len(r2)>0
45
+ print(f"G3 SUBSTRATE {'pass' if ok else 'FAIL'} R2 live={len(r2)} actor-status live={sub}")
46
+ if not ok: rc=1
47
+ sys.exit(rc)
48
+ PY
49
+ }
50
+
51
+ # ── --self-test: prove the checker can go BOTH ways ─────────────────────────
52
+ if [ "${1:-}" = "--self-test" ]; then
53
+ T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
54
+ printf 'ceo\ncmo.\n' > "$T/red_ids"; printf 'ceo\n' > "$T/red_r2"
55
+ printf 'ceo\ncto\n' > "$T/green_ids"; printf 'ceo\ncto\n' > "$T/green_r2"
56
+ guards "$T/red_ids" "$T/red_r2" 0 >/dev/null 2>&1; r=$?
57
+ guards "$T/green_ids" "$T/green_r2" 2 >/dev/null 2>&1; g=$?
58
+ guards "$T/green_ids" "$T/green_r2" "" >/dev/null 2>&1; u=$?
59
+ echo "self-test: red=$r (want 1) green=$g (want 0) unrun=$u (want 3)"
60
+ [ "$r" = 1 ] && [ "$g" = 0 ] && [ "$u" = 3 ] && { echo "SELF-TEST PASS"; exit 0; }
61
+ echo "SELF-TEST FAIL"; exit 1
62
+ fi
63
+
64
+ WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
65
+
66
+ # ── store 1: D1 follows ─────────────────────────────────────────────────────
67
+ ( cd "$ROOT/one.ie/web" && npx wrangler d1 execute one-owners --remote --json \
68
+ --command "SELECT DISTINCT actor_id FROM follows WHERE workspace='$WS' ORDER BY actor_id" 2>/dev/null ) \
69
+ | python3 -c "import json,sys;d=json.load(sys.stdin);print('\n'.join(r['actor_id'] for r in d[0]['results']))" \
70
+ > "$WORK/ids" || { echo "UNRUN: D1 follows unreadable"; exit 4; }
71
+ [ -s "$WORK/ids" ] || { echo "UNRUN: D1 follows returned no rows for workspace=$WS"; exit 4; }
72
+
73
+ # ── store 2: R2 one-content, ListObjectsV2 (SigV4, stdlib only) ─────────────
74
+ python3 - "$ROOT/one.ie/web/.dev.vars" "one-content" "$WS/agents/" > "$WORK/r2" <<'PY' || { echo "UNRUN: R2 unreadable"; exit 4; }
75
+ import sys,hmac,hashlib,datetime,urllib.request,urllib.parse
76
+ import xml.etree.ElementTree as ET
77
+ env={}
78
+ for line in open(sys.argv[1],encoding='utf-8',errors='ignore'):
79
+ line=line.strip()
80
+ if line and not line.startswith('#') and '=' in line:
81
+ k,v=line.split('=',1); env[k.strip()]=v.strip().strip('"').strip("'")
82
+ AK=env['CLOUDFLARE_R2_S3_ACCESS_KEY_ID']; SK=env['CLOUDFLARE_R2_S3_SECRET_KEY']
83
+ host=f"{env['CLOUDFLARE_ACCOUNT_ID']}.r2.cloudflarestorage.com"
84
+ bucket,prefix=sys.argv[2],sys.argv[3]
85
+ sign=lambda k,m: hmac.new(k,m.encode(),hashlib.sha256).digest()
86
+ def page(tok):
87
+ q={'list-type':'2','prefix':prefix,'max-keys':'1000'}
88
+ if tok: q['continuation-token']=tok
89
+ qs='&'.join(f"{urllib.parse.quote(k,safe='')}={urllib.parse.quote(v,safe='')}" for k,v in sorted(q.items()))
90
+ t=datetime.datetime.now(datetime.timezone.utc)
91
+ ad,ds=t.strftime('%Y%m%dT%H%M%SZ'),t.strftime('%Y%m%d')
92
+ ph=hashlib.sha256(b'').hexdigest()
93
+ cr=f"GET\n/{bucket}\n{qs}\nhost:{host}\nx-amz-content-sha256:{ph}\nx-amz-date:{ad}\n\nhost;x-amz-content-sha256;x-amz-date\n{ph}"
94
+ sc=f"{ds}/auto/s3/aws4_request"
95
+ sts=f"AWS4-HMAC-SHA256\n{ad}\n{sc}\n{hashlib.sha256(cr.encode()).hexdigest()}"
96
+ k=sign(('AWS4'+SK).encode(),ds);k=sign(k,'auto');k=sign(k,'s3');k=sign(k,'aws4_request')
97
+ sig=hmac.new(k,sts.encode(),hashlib.sha256).hexdigest()
98
+ r=urllib.request.Request(f"https://{host}/{bucket}?{qs}",headers={'Host':host,'x-amz-date':ad,
99
+ 'x-amz-content-sha256':ph,'Authorization':f"AWS4-HMAC-SHA256 Credential={AK}/{sc}, "
100
+ f"SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature={sig}"})
101
+ return urllib.request.urlopen(r,timeout=60).read()
102
+ ns='{http://s3.amazonaws.com/doc/2006-03-01/}';keys=[];tok=None
103
+ while True:
104
+ root=ET.fromstring(page(tok))
105
+ keys += [c.find(ns+'Key').text for c in root.findall(ns+'Contents')]
106
+ tr=root.find(ns+'IsTruncated')
107
+ if tr is not None and tr.text=='true': tok=root.find(ns+'NextContinuationToken').text
108
+ else: break
109
+ for k in sorted(keys):
110
+ rel=k[len(prefix):]
111
+ if rel.endswith('.md') and '/' not in rel: print(rel[:-3])
112
+ PY
113
+
114
+ # ── store 3: the substrate. actor-status "live" has no read door today. ─────
115
+ SUB=""
116
+ CODE=$(curl -s -o "$WORK/sub" -w '%{http_code}' --max-time 25 \
117
+ "https://one.ie/api/export/actors?workspace=$WS&status=live" 2>/dev/null || echo 000)
118
+ if [ "$CODE" = "200" ]; then
119
+ SUB=$(python3 -c "
120
+ import json,sys
121
+ try:
122
+ d=json.load(open('$WORK/sub'))
123
+ rows=d if isinstance(d,list) else d.get('actors',d.get('results',[]))
124
+ print(sum(1 for r in rows if str(r.get('actorStatus',r.get('actor-status',''))) == 'live'))
125
+ except Exception: print('')" 2>/dev/null)
126
+ fi
127
+
128
+ echo "workspace=$WS follows_actors=$(wc -l < "$WORK/ids" | tr -d ' ') r2_live_personas=$(wc -l < "$WORK/r2" | tr -d ' ') export_actors_http=$CODE"
129
+ guards "$WORK/ids" "$WORK/r2" "$SUB"
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env bash
2
+ # blocks-manifest-cached.sh — run `blocks-manifest.mjs --check`, or skip it when
3
+ # nothing that feeds the manifest has moved.
4
+ #
5
+ # manifest: needs-env
6
+ #
7
+ # WHY. C2 wired `--check` into verify-fast.sh as Step 0 on 2026-09-09, which was
8
+ # right -- three committed artifacts were generated from one registry and gated by
9
+ # nothing. But it runs on EVERY fast-lane pass, and measured on this box, warm,
10
+ # twice in a row: 8.19s and 6.98s. The fast lane exists to be run on every edit;
11
+ # a fixed ~7s toll on a doc edit, a script edit or a test-only cycle is most of
12
+ # what the lane was built to avoid. Only ~1.0-1.3s of that is the `bunx tsx`
13
+ # resolution leg (measured: `bunx tsx --version` 1.33s then 1.03s) -- the rest is
14
+ # the real work, importing a 7,800-line config through tsx and walking 243 blocks.
15
+ # So vendoring tsx does not fix this. A memo does.
16
+ #
17
+ # WHY NARROWING IS SOUND HERE, AND IS NOT THE test-cached.sh MISTAKE. CLAUDE.md
18
+ # warns: do not narrow test-cached.sh's key, because those tests readFileSync
19
+ # across pay/, channels/, schema/, .claude/ and text/ at runtime, so an import
20
+ # graph is NOT a superset of what a test reads. blocks-manifest.mjs is the
21
+ # opposite shape. Its inputs are DECLARED at :33-38 -- config.tsx, families.ts,
22
+ # block-usage.json -- and the runner it generates does nothing but import
23
+ # config.tsx and walk puckConfig.components. Its inputs ARE its import graph, by
24
+ # construction. Read that precedent before reaching for it here; it is about a
25
+ # different failure.
26
+ #
27
+ # THE KEY IS A SUPERSET ON PURPOSE. Everything the check reads AND all three
28
+ # artifacts it compares against live under one.ie/web/src, so the fingerprint
29
+ # covers that whole tree rather than a hand-listed set of paths. A block
30
+ # component living somewhere the list did not anticipate is exactly how a memo
31
+ # goes unsound, and a drifted manifest reading as cached is far worse than 7s.
32
+ # The cost of the superset is that any src edit misses -- which is correct, and
33
+ # still skips every doc-only, script-only and test-only cycle.
34
+ #
35
+ # SAFETY, the direction that matters: a LOST stamp costs a run, never a skip.
36
+ # The stamp lives in GOVERN_DIR (machine-wide tmp, evaporates), so a fresh box, a
37
+ # cleared tmp or a new worktree all MISS. There is no path where a missing stamp
38
+ # reads as cached. Staged-but-uncommitted edits move the key too, because
39
+ # `ls-files -s` shows the INDEX while `diff` shows the working tree -- one leg
40
+ # alone would miss half of them (the scar sdk-build-cached.sh records).
41
+ #
42
+ # BLOCKS_MANIFEST_FORCE=1 always runs. --self-test drives the red half.
43
+ set -euo pipefail
44
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
45
+ GOVERN_DIR="${GOVERN_DIR:-${TMPDIR:-/tmp}/one-govern}"
46
+ mkdir -p "$GOVERN_DIR"
47
+
48
+ _fp() {
49
+ { git -C "$ROOT" ls-files -s one.ie/web/src 2>/dev/null
50
+ git -C "$ROOT" diff -- one.ie/web/src 2>/dev/null
51
+ git -C "$ROOT" ls-files --others --exclude-standard one.ie/web/src 2>/dev/null \
52
+ | while IFS= read -r u; do shasum -a 256 "$ROOT/$u" 2>/dev/null; done
53
+ } | shasum -a 256 | cut -d' ' -f1
54
+ }
55
+
56
+ _run_check() {
57
+ local out rc
58
+ out="$(mktemp)"
59
+ set +e
60
+ node "$ROOT/.claude/scripts/blocks-manifest.mjs" --check > "$out" 2>&1
61
+ rc=$?
62
+ set -e
63
+ cat "$out"; rm -f "$out"
64
+ return $rc
65
+ }
66
+
67
+ if [ "${1:-}" = "--self-test" ]; then
68
+ fails=0
69
+ probe="$ROOT/one.ie/web/src/lib/puck/.memo-probe.ts"
70
+ BLOCKS_MANIFEST_FORCE=1 bash "$0" >/dev/null 2>&1 || true
71
+ a="$(bash "$0" 2>&1)"
72
+ case "$a" in *cached*) echo "ok: second run on an unchanged tree is CACHED";;
73
+ *) echo "FAIL: unchanged tree re-ran: $a"; fails=$((fails+1));; esac
74
+ # RED HALF: a memo that cannot be shown to MISS is an unrun gate in a
75
+ # performance costume -- the exact class Step 0 was added to close.
76
+ printf 'export const __memoProbe = 1\n' > "$probe"
77
+ b="$(bash "$0" 2>&1)"
78
+ rm -f "$probe"
79
+ case "$b" in *cached*) echo "FAIL: a new file under src did NOT invalidate the memo"; fails=$((fails+1));;
80
+ *) echo "ok: a new file under src MISSES (red half proven)";; esac
81
+ c="$(bash "$0" 2>&1)"
82
+ case "$c" in *cached*) echo "ok: removing the probe returns to the earlier key";;
83
+ *) echo "note: post-probe run re-ran (fine — a miss is never wrong)";; esac
84
+ [ "$fails" -eq 0 ] && echo "blocks-manifest-cached --self-test: PASS" || { echo "blocks-manifest-cached --self-test: $fails FAIL"; exit 1; }
85
+ exit 0
86
+ fi
87
+
88
+ want="$(_fp)"
89
+ STAMP="$GOVERN_DIR/blocks-manifest.$want"
90
+
91
+ if [ "${BLOCKS_MANIFEST_FORCE:-0}" != "1" ] && [ -f "$STAMP" ]; then
92
+ echo "blocks-manifest --check: cached (one.ie/web/src unchanged since the last pass)"
93
+ exit 0
94
+ fi
95
+
96
+ _run_check || exit $?
97
+ # Only a PASS is memoised. A drift result is never stamped: the next run must
98
+ # see it again, and `test-cached.sh` records the same rule for the same reason.
99
+ rm -f "$GOVERN_DIR"/blocks-manifest.* 2>/dev/null || true
100
+ printf '%s' "$want" > "$STAMP"
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ # manifest: monorepo-only
3
+ #
4
+ # chat-context-check.sh — the deep chat context reaches the prompt, and the
5
+ # checker that says so can go RED.
6
+ #
7
+ # WHAT IT GUARDS. Two fields carry the operator's ask: `contextPack.page.body`
8
+ # (the page read in full, not just its headings) and `contextPack.panel` (the
9
+ # tab open in the rail beside the chat, and its rows). Both cross four files —
10
+ # the sender (Chat.tsx), web's edge sanitizer (/api/chat), channels'
11
+ # sanitizer, and channels' renderer — and a field that any one of them does not
12
+ # name is DEAD while every other test stays green. That has happened four times
13
+ # on this exact path (`workflowId` twice, `focusBlockId`, `page`).
14
+ #
15
+ # WHY A SCRIPT AND NOT JUST THE SUITE. The suite proves the field arrives. This
16
+ # proves the SUITE would notice if it stopped: it cuts the copy line out of
17
+ # `sanitizeContextPack`, re-runs, and requires a failure. A green run against a
18
+ # gutted sanitizer would mean the assertions were reading something else.
19
+ #
20
+ # bash .claude/scripts/chat-context-check.sh # green half
21
+ # bash .claude/scripts/chat-context-check.sh --self-test # both halves
22
+ #
23
+ # Exit codes: 0 ok · 1 the suite is red on an untouched tree · 2 the RED PROOF
24
+ # failed (the suite stayed green with the wire cut) · 3 setup (dirty target).
25
+ set -uo pipefail
26
+
27
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
28
+ CTX="$ROOT/channels/src/context.ts"
29
+ SUITES=(test/context-pack-deep.test.ts test/context-pack-parity.test.ts)
30
+
31
+ run_suite() {
32
+ ( cd "$ROOT/channels" && bash "$ROOT/.claude/scripts/gate-run.sh" chat-ctx-check -- bunx vitest run "${SUITES[@]}" ) >"$1" 2>&1
33
+ }
34
+
35
+ TMP="$(mktemp -d)"
36
+ trap 'rm -rf "$TMP"' EXIT
37
+
38
+ echo "[chat-context] green half — the suite on an untouched tree"
39
+ if ! run_suite "$TMP/green.log"; then
40
+ echo "[chat-context] RED on an untouched tree — this is a real failure, not a proof:"
41
+ tail -30 "$TMP/green.log"
42
+ exit 1
43
+ fi
44
+ grep -E 'Tests +[0-9]+ passed' "$TMP/green.log" || true
45
+
46
+ if [ "${1:-}" != "--self-test" ]; then
47
+ echo "[chat-context] ok — pass --self-test for the red proof"
48
+ exit 0
49
+ fi
50
+
51
+ # ── RED PROOF ───────────────────────────────────────────────────────────────
52
+ # Cut the two copy lines out of channels' sanitizer, one at a time, and require
53
+ # the suite to notice. The file is restored on every exit path, including a
54
+ # SIGINT — a checker that can leave the tree mutated is worse than no checker.
55
+ if ! git -C "$ROOT" diff --quiet -- channels/src/context.ts; then
56
+ echo "[chat-context] refusing: channels/src/context.ts already has uncommitted edits."
57
+ echo " The red proof rewrites it and restores from THIS copy; it will not"
58
+ echo " step on work in progress."
59
+ exit 3
60
+ fi
61
+ cp "$CTX" "$TMP/context.ts.orig"
62
+ restore() { cp "$TMP/context.ts.orig" "$CTX"; }
63
+ trap 'restore; rm -rf "$TMP"' EXIT INT TERM
64
+
65
+ fail=0
66
+ cut_and_check() {
67
+ local label="$1" pattern="$2"
68
+ restore
69
+ if ! grep -q "$pattern" "$CTX"; then
70
+ echo "[chat-context] RED PROOF SETUP FAILED — no line matching: $pattern"
71
+ echo " The wire moved. Update this checker or it is guarding nothing."
72
+ fail=1
73
+ return
74
+ fi
75
+ grep -v "$pattern" "$TMP/context.ts.orig" > "$CTX"
76
+ if run_suite "$TMP/red-$label.log"; then
77
+ echo "[chat-context] RED PROOF FAILED ($label) — the suite stayed GREEN with the wire cut."
78
+ fail=1
79
+ else
80
+ echo "[chat-context] red proof ok: cutting $label turns the suite red"
81
+ fi
82
+ }
83
+
84
+ cut_and_check "page.body" "page.body = rawBody.slice"
85
+ cut_and_check "panel.tab" "pack.panel = panel"
86
+ restore
87
+
88
+ [ "$fail" -eq 0 ] || exit 2
89
+ echo "[chat-context] ok — the field arrives, and the checker can go red"
@@ -30,6 +30,9 @@
30
30
  * --header <k: v> extra HTTP header (repeatable)
31
31
  * --ua <string> user agent
32
32
  * --viewport <WxH> viewport (default 1280x800)
33
+ * --reduced-motion emulate `prefers-reduced-motion: reduce` for the run, so a
34
+ * reduced-motion rule can be CHECKED instead of believed:
35
+ * drive the same route twice and diff the computed styles
33
36
  * --headed use full Chromium with a visible window instead of the shell
34
37
  * --max <n> truncation ceiling for text/html/eval (default 4000)
35
38
  *
@@ -184,8 +187,23 @@ const statePath = typeof val('state') === 'string' ? val('state') : null
184
187
  const stateLoaded = Boolean(statePath && existsSync(statePath))
185
188
 
186
189
  const [vw, vh] = String(val('viewport', '1280x800')).split('x').map(Number)
190
+ // THE FLAG text/ehc-motion.md ASKED FOR, and what it buys.
191
+ //
192
+ // That page could not write an `accept:` for its own central rule — "reduced
193
+ // motion must reach the same final frame" — because this harness had no way to
194
+ // ask for the flag, so every reduced-motion block in the repo was believed
195
+ // rather than checked, and one of them (`Layout.astro:599`) had already been
196
+ // correct, reviewed, and DEAD because its sheet was not on the page. An
197
+ // animation is the one kind of code whose failure looks exactly like success.
198
+ //
199
+ // Playwright emulates it per context (CDP `Emulation.setEmulatedMedia`), so the
200
+ // same route can be driven twice and the two `getComputedStyle` readings
201
+ // compared. `--reduced-motion` asks for `reduce`; the default stays `no-preference`
202
+ // so every existing caller reads exactly what it read before.
203
+ const reducedMotion = flag('reduced-motion') ? 'reduce' : 'no-preference'
187
204
  const context = await browser.newContext({
188
205
  viewport: { width: vw || 1280, height: vh || 800 },
206
+ reducedMotion,
189
207
  ...(stateLoaded ? { storageState: statePath } : {}),
190
208
  ...(typeof val('ua') === 'string' ? { userAgent: val('ua') } : {}),
191
209
  ...(all('header').length