@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.
- package/.claude-plugin/plugin.json +1 -1
- package/agents/abm-strategist.md +67 -1
- package/agents/ads-meta.md +67 -1
- package/agents/analyst.md +67 -1
- package/agents/animator.md +108 -0
- package/agents/architect.md +269 -20
- package/agents/brand-guardian.md +67 -1
- package/agents/brand-strategist.md +67 -1
- package/agents/campaign-content.md +67 -1
- package/agents/campaign-email.md +67 -1
- package/agents/campaign-sms.md +67 -1
- package/agents/campaign-social.md +67 -1
- package/agents/cco.md +83 -2
- package/agents/ceo.md +108 -11
- package/agents/chairman.md +197 -0
- package/agents/cmo.md +82 -2
- package/agents/community-greeter.md +67 -1
- package/agents/community-moderator.md +67 -1
- package/agents/compliance.md +67 -1
- package/agents/copywriter.md +67 -1
- package/agents/creative-strategist.md +67 -1
- package/agents/cro.md +81 -1
- package/agents/cto.md +266 -28
- package/agents/customer-interviewer.md +67 -1
- package/agents/customer-researcher.md +67 -1
- package/agents/customer-success-manager.md +67 -1
- package/agents/customer-trainer.md +67 -1
- package/agents/cxo.md +82 -1
- package/agents/demand-creator.md +67 -1
- package/agents/demo-mover.md +67 -1
- package/agents/demo-specialist.md +67 -1
- package/agents/demo-thai-family-law.md +67 -1
- package/agents/designer.md +67 -1
- package/agents/discovery-caller.md +67 -1
- package/agents/doctor.md +269 -0
- package/agents/educate-coach.md +67 -1
- package/agents/elevate-tutor.md +67 -1
- package/agents/email-lifecycle-marketer.md +67 -1
- package/agents/engage-specialist.md +67 -1
- package/agents/events-coordinator.md +67 -1
- package/agents/foundation-builder.md +67 -1
- package/agents/funnel-architect.md +67 -1
- package/agents/gift-creator.md +67 -1
- package/agents/google-ads.md +67 -1
- package/agents/guide.md +67 -1
- package/agents/helpdesk-dispatcher.md +67 -1
- package/agents/hook-specialist.md +67 -1
- package/agents/identify-optimizer.md +67 -1
- package/agents/implementer.md +313 -45
- package/agents/incident-commander.md +67 -1
- package/agents/insights-lead.md +87 -1
- package/agents/journey-runner.md +67 -1
- package/agents/linkedin-ads.md +67 -1
- package/agents/live-sales-chat.md +67 -1
- package/agents/market-researcher.md +67 -1
- package/agents/media-buyer.md +67 -1
- package/agents/memory-keeper.md +195 -0
- package/agents/movers-customer-researcher.md +67 -1
- package/agents/movers-foundation-builder.md +67 -1
- package/agents/movers-market-researcher.md +67 -1
- package/agents/movers-pricing-strategist.md +67 -1
- package/agents/nurture-architect.md +67 -1
- package/agents/offer-architect.md +67 -1
- package/agents/onboarder.md +67 -1
- package/agents/onboarding-specialist.md +67 -1
- package/agents/operations-dashboard.md +87 -1
- package/agents/perf-engineer.md +333 -37
- package/agents/playbook-writer.md +67 -1
- package/agents/plg-strategist.md +67 -1
- package/agents/positioning-architect.md +67 -1
- package/agents/press-officer.md +67 -1
- package/agents/pricing-strategist.md +67 -1
- package/agents/privacy-officer.md +67 -1
- package/agents/referral-manager.md +67 -1
- package/agents/refine-analyst.md +67 -1
- package/agents/release-manager.md +446 -39
- package/agents/renewals-upsell-rep.md +67 -1
- package/agents/review-engineer.md +319 -45
- package/agents/rewards-steward.md +67 -1
- package/agents/sales-call-coach.md +67 -1
- package/agents/sales-closer.md +67 -1
- package/agents/security-auditor.md +343 -48
- package/agents/sell-closer.md +67 -1
- package/agents/share-amplifier.md +67 -1
- package/agents/social-media-manager.md +67 -1
- package/agents/storyteller.md +301 -0
- package/agents/strategist.md +67 -1
- package/agents/strategy-aligner.md +67 -1
- package/agents/support-agent.md +67 -1
- package/agents/tagger.md +327 -0
- package/agents/tech-writer.md +195 -22
- package/agents/test-engineer.md +398 -29
- package/agents/tiktok-ads.md +67 -1
- package/agents/tracking-engineer.md +67 -1
- package/agents/trailkeeper.md +181 -0
- package/agents/upsell-strategist.md +67 -1
- package/agents/voice.md +67 -1
- package/agents/w1-recon.md +1 -1
- package/agents/w2-decide.md +1 -1
- package/agents/w3-edit.md +8 -2
- package/agents/w4-verify.md +13 -0
- package/agents/workflow-optimiser.md +81 -1
- package/commands/close.md +916 -160
- package/commands/deploy.md +102 -724
- package/commands/do.md +58 -2
- package/commands/sweep.md +159 -0
- package/commands/tasks.md +222 -0
- package/hooks/scripts/dev-only.sh +135 -0
- package/hooks/scripts/git-add-guard.sh +37 -2
- package/hooks/scripts/session-start.sh +32 -4
- package/package.json +1 -1
- package/rules/scripts.md +85 -0
- package/scripts/CLAUDE.md +315 -0
- package/scripts/ad-copy-lint.sh +656 -0
- package/scripts/agent-actor-parity.sh +129 -0
- package/scripts/blocks-manifest-cached.sh +100 -0
- package/scripts/chat-context-check.sh +89 -0
- package/scripts/chrome.mjs +18 -0
- package/scripts/close-metrics.sh +587 -0
- package/scripts/close-owner.sh +326 -0
- package/scripts/db-sync-lock-check.sh +116 -0
- package/scripts/deploy-emit.sh +311 -0
- package/scripts/deploy-gate-check.sh +155 -0
- package/scripts/deploy-ready.sh +78 -0
- package/scripts/deploy-record.sh +605 -0
- package/scripts/deploy-schema-check.sh +58 -0
- package/scripts/deploy.sh +393 -243
- package/scripts/do-auto.sh +127 -26
- package/scripts/do-board.sh +429 -0
- package/scripts/do-close.sh +1184 -0
- package/scripts/do-consumer-sweep.sh +18 -1
- package/scripts/do-decide.sh +476 -0
- package/scripts/do-fleet.sh +8 -2
- package/scripts/do-plan-json.mjs +110 -12
- package/scripts/do-prove-selftest.sh +108 -0
- package/scripts/do-prove.sh +86 -10
- package/scripts/do-rank.py +200 -3
- package/scripts/do-reconcile.sh +73 -12
- package/scripts/do-signal.sh +101 -23
- package/scripts/do-smoke.sh +18 -1
- package/scripts/do-w4-gates.sh +11 -1
- package/scripts/do-world-check.sh +153 -0
- package/scripts/download-stats.sh +172 -0
- package/scripts/factory-brief-check.sh +330 -0
- package/scripts/factory-check.sh +18 -1
- package/scripts/factory-close-check.sh +257 -0
- package/scripts/factory-emit.sh +211 -0
- package/scripts/factory-executor-check.mjs +353 -0
- package/scripts/factory-peak.sh +301 -0
- package/scripts/factory-repo.sh +71 -0
- package/scripts/factory-review-check.mjs +61 -0
- package/scripts/factory-tasks-check.sh +18 -1
- package/scripts/fixtures/factory-brief-real.md +44 -0
- package/scripts/flywheel-outcome.sh +63 -0
- package/scripts/gate-reaper-check.sh +98 -0
- package/scripts/gate-reaper.sh +9 -0
- package/scripts/gate-watchdog.sh +619 -0
- package/scripts/gc-content-check.sh +142 -0
- package/scripts/gh-traffic-capture.sh +153 -0
- package/scripts/govern-order-check.sh +202 -0
- package/scripts/governor-doors-check.sh +86 -5
- package/scripts/health.sh +448 -0
- package/scripts/id-inventory.mjs +418 -0
- package/scripts/incident.sh +212 -0
- package/scripts/land.sh +755 -45
- package/scripts/lib/gc-finished.sh +77 -0
- package/scripts/livekit-ratchet.sh +18 -1
- package/scripts/machine-check.sh +1 -1
- package/scripts/memory-index-budget.sh +79 -0
- package/scripts/npm-downloads.sh +109 -0
- package/scripts/one-agents.mjs +204 -8
- package/scripts/one-resume.sh +31 -3
- package/scripts/pr-body.sh +335 -0
- package/scripts/preview-fd-check.sh +289 -0
- package/scripts/redirect-lint.sh +169 -0
- package/scripts/release.sh +40 -6
- package/scripts/resume-lost-sessions.sh +68 -0
- package/scripts/shoot-pages.mjs +140 -0
- package/scripts/signal-meta-backfill.ts +451 -0
- package/scripts/signal-watch.sh +63 -6
- package/scripts/speed-cache-check.sh +12 -2
- package/scripts/sweep.sh +426 -0
- package/scripts/task-titles-dump.ts +101 -0
- package/scripts/test-cached.sh +47 -10
- package/scripts/test-lanes.sh +14 -0
- package/scripts/thread-name-backfill.ts +215 -0
- package/scripts/triage-shape-check.sh +149 -0
- package/scripts/tsc-cached.sh +155 -8
- package/scripts/typedb-flake-check.sh +3 -1
- package/scripts/urls-lint.sh +8 -0
- package/scripts/verify-board-doors.sh +80 -0
- package/scripts/verify-fast.sh +159 -6
- package/scripts/worktree-up.sh +21 -3
- package/skills/astro/SKILL.md +9 -3
- package/skills/astro/optimize-performance.md +3 -2
- package/skills/cloudflare/SKILL.md +3 -2
- package/skills/cloudflare-security-audit/AI-AND-LLM.md +83 -0
- package/skills/cloudflare-security-audit/ATTACK-CLASSES.md +130 -0
- package/skills/cloudflare-security-audit/CLIENT-SIDE.md +83 -0
- package/skills/cloudflare-security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
- package/skills/cloudflare-security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
- package/skills/cloudflare-security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
- package/skills/cloudflare-security-audit/HUNTING.md +251 -0
- package/skills/cloudflare-security-audit/LICENSE +21 -0
- package/skills/cloudflare-security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
- package/skills/cloudflare-security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
- package/skills/cloudflare-security-audit/PROVENANCE.md +78 -0
- package/skills/cloudflare-security-audit/RECONNAISSANCE.md +156 -0
- package/skills/cloudflare-security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
- package/skills/cloudflare-security-audit/SKILL.md +192 -0
- package/skills/cloudflare-security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
- package/skills/cloudflare-security-audit/VALIDATION-AND-REPORTING.md +186 -0
- package/skills/cloudflare-security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
- package/skills/cloudflare-security-audit/report-schema.json +461 -0
- package/skills/cloudflare-security-audit/validate-coverage-ledger.cjs +872 -0
- package/skills/cloudflare-security-audit/validate-coverage-ledger.test.cjs +740 -0
- package/skills/cloudflare-security-audit/validate-findings.cjs +773 -0
- package/skills/cloudflare-security-audit/validate-findings.test.cjs +652 -0
- package/skills/deploy/REFERENCE.md +713 -0
- package/skills/deploy/SKILL.md +140 -0
- package/skills/fleet-audit/SKILL.md +58 -0
- package/skills/meeting/SKILL.md +220 -0
- package/skills/planning/SKILL.md +256 -0
- package/skills/shadcn/SKILL.md +1 -1
- package/skills/typedb/SKILL.md +7 -0
- package/skills/voice/SKILL.md +94 -6
- package/skills/voice/corpus-check.sh +87 -0
- package/templates/template-agent.md +7 -1
- package/templates/template-feature.md +9 -0
- 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"
|
package/scripts/chrome.mjs
CHANGED
|
@@ -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
|