@oneie/claude 0.7.0 → 0.9.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/agents/abm-strategist.md +89 -0
- package/agents/ads-meta.md +97 -0
- package/agents/analyst.md +173 -0
- package/agents/architect.md +280 -0
- package/agents/brand-guardian.md +88 -0
- package/agents/brand-strategist.md +92 -0
- package/agents/campaign-content.md +90 -0
- package/agents/campaign-email.md +88 -0
- package/agents/campaign-sms.md +87 -0
- package/agents/campaign-social.md +87 -0
- package/agents/cco.md +99 -0
- package/agents/ceo.md +106 -0
- package/agents/chairman.md +120 -0
- package/agents/cmo.md +101 -0
- package/agents/community-greeter.md +89 -0
- package/agents/community-moderator.md +92 -0
- package/agents/compliance.md +92 -0
- package/agents/copywriter.md +100 -0
- package/agents/creative-strategist.md +95 -0
- package/agents/cro.md +98 -0
- package/agents/cto.md +267 -0
- package/agents/customer-interviewer.md +93 -0
- package/agents/customer-researcher.md +89 -0
- package/agents/customer-success-manager.md +90 -0
- package/agents/customer-trainer.md +90 -0
- package/agents/cxo.md +100 -0
- package/agents/demand-creator.md +89 -0
- package/agents/demo-mover.md +83 -0
- package/agents/demo-specialist.md +89 -0
- package/agents/demo-thai-family-law.md +87 -0
- package/agents/designer.md +112 -0
- package/agents/discovery-caller.md +98 -0
- package/agents/doctor.md +139 -0
- package/agents/educate-coach.md +100 -0
- package/agents/elevate-tutor.md +83 -0
- package/agents/email-lifecycle-marketer.md +91 -0
- package/agents/engage-specialist.md +99 -0
- package/agents/events-coordinator.md +90 -0
- package/agents/foundation-builder.md +94 -0
- package/agents/funnel-architect.md +89 -0
- package/agents/gift-creator.md +100 -0
- package/agents/google-ads.md +103 -0
- package/agents/guide.md +292 -0
- package/agents/helpdesk-dispatcher.md +88 -0
- package/agents/hook-specialist.md +91 -0
- package/agents/identify-optimizer.md +101 -0
- package/agents/implementer.md +305 -0
- package/agents/incident-commander.md +120 -0
- package/agents/insights-lead.md +93 -0
- package/agents/journey-runner.md +113 -0
- package/agents/linkedin-ads.md +123 -0
- package/agents/live-sales-chat.md +90 -0
- package/agents/market-researcher.md +88 -0
- package/agents/media-buyer.md +96 -0
- package/agents/movers-customer-researcher.md +95 -0
- package/agents/movers-foundation-builder.md +96 -0
- package/agents/movers-market-researcher.md +97 -0
- package/agents/movers-pricing-strategist.md +171 -0
- package/agents/nurture-architect.md +99 -0
- package/agents/offer-architect.md +92 -0
- package/agents/onboarder.md +222 -0
- package/agents/onboarding-specialist.md +92 -0
- package/agents/operations-dashboard.md +98 -0
- package/agents/perf-engineer.md +348 -0
- package/agents/playbook-writer.md +71 -0
- package/agents/plg-strategist.md +91 -0
- package/agents/positioning-architect.md +88 -0
- package/agents/press-officer.md +89 -0
- package/agents/pricing-strategist.md +94 -0
- package/agents/privacy-officer.md +92 -0
- package/agents/referral-manager.md +91 -0
- package/agents/refine-analyst.md +102 -0
- package/agents/release-manager.md +261 -0
- package/agents/renewals-upsell-rep.md +90 -0
- package/agents/review-engineer.md +327 -0
- package/agents/rewards-steward.md +82 -0
- package/agents/sales-call-coach.md +94 -0
- package/agents/sales-closer.md +98 -0
- package/agents/security-auditor.md +313 -0
- package/agents/sell-closer.md +101 -0
- package/agents/share-amplifier.md +99 -0
- package/agents/social-media-manager.md +92 -0
- package/agents/storyteller.md +250 -0
- package/agents/strategist.md +83 -0
- package/agents/strategy-aligner.md +94 -0
- package/agents/support-agent.md +90 -0
- package/agents/tagger.md +245 -0
- package/agents/tech-writer.md +216 -0
- package/agents/test-engineer.md +243 -0
- package/agents/tiktok-ads.md +105 -0
- package/agents/tracking-engineer.md +92 -0
- package/agents/upsell-strategist.md +101 -0
- package/agents/voice.md +85 -0
- package/agents/w4-tools.md +153 -0
- package/agents/w4-verify.md +20 -138
- package/agents/workflow-optimiser.md +84 -0
- package/commands/close.md +814 -160
- package/commands/create.md +2 -2
- package/commands/deploy.md +554 -175
- package/commands/do.md +119 -109
- package/commands/fast.md +67 -0
- package/commands/improve.md +2 -2
- package/commands/one.md +418 -0
- package/commands/see.md +1 -1
- package/commands/sync.md +1 -1
- package/commands/tasks.md +222 -0
- package/commands/vespio.md +110 -0
- package/commands/vespio.remote.md +227 -0
- package/hooks/hooks.json +25 -79
- package/hooks/lib/governor-escape-match.sh +88 -0
- package/hooks/lib/hook.sh +4 -13
- package/hooks/lib/signal.sh +9 -2
- package/hooks/scripts/branch-pin.sh +6 -0
- package/hooks/scripts/config-protect.sh +6 -0
- package/hooks/scripts/do-outcome-gate.sh +19 -2
- package/hooks/scripts/git-add-guard.sh +43 -2
- package/hooks/scripts/governor-escape.sh +96 -0
- package/hooks/scripts/load-guard.sh +127 -0
- package/hooks/scripts/post-edit-check.sh +36 -29
- package/hooks/scripts/session-start.sh +34 -80
- package/hooks/scripts/task-complete-verify.sh +46 -40
- package/package.json +1 -1
- package/rules/documentation.md +9 -0
- package/scripts/ad-copy-lint.sh +656 -0
- package/scripts/agentverse-audit.sh +256 -0
- package/scripts/asi-walk.sh +435 -0
- package/scripts/astro-build-cached.sh +143 -0
- package/scripts/blocks-manifest-cached.sh +100 -0
- package/scripts/blocks-manifest.mjs +497 -0
- package/scripts/blocks-ratchet.sh +116 -0
- package/scripts/blocks-render-probe.mjs +529 -0
- package/scripts/blocks-usage.mjs +334 -0
- package/scripts/chat-context-check.sh +89 -0
- package/scripts/close-metrics.sh +558 -0
- package/scripts/close-owner.sh +268 -0
- package/scripts/db-sync-lock-check.sh +116 -0
- package/scripts/deploy-dev.sh +35 -0
- package/scripts/deploy-emit.sh +298 -0
- package/scripts/deploy-gate-check.sh +128 -0
- package/scripts/deploy-ready.sh +78 -0
- package/scripts/deploy-record.sh +605 -0
- package/scripts/deploy.sh +1273 -0
- package/scripts/do-auto.sh +598 -48
- package/scripts/do-brief.sh +113 -0
- package/scripts/do-close.sh +1137 -0
- package/scripts/do-commit.sh +75 -0
- package/scripts/do-consumer-sweep.sh +18 -1
- package/scripts/do-cycle-shape-check.sh +160 -0
- package/scripts/do-decide.sh +476 -0
- package/scripts/do-derive-check.sh +436 -0
- package/scripts/do-fleet.sh +106 -28
- package/scripts/do-folder.sh +10 -1
- package/scripts/do-next.sh +106 -0
- package/scripts/do-orchestrate.sh +17 -5
- package/scripts/do-plan-json.mjs +201 -0
- package/scripts/do-plan-json.sh +8 -0
- package/scripts/do-preflight.sh +117 -0
- package/scripts/do-project.sh +157 -0
- package/scripts/do-prove-selftest.sh +108 -0
- package/scripts/do-prove.sh +295 -23
- package/scripts/do-rank.py +31 -1
- package/scripts/do-recon-cache.sh +7 -1
- package/scripts/do-recon-pack.sh +196 -0
- package/scripts/do-reconcile.sh +121 -4
- package/scripts/do-signal.sh +280 -23
- package/scripts/do-smoke.sh +18 -1
- package/scripts/do-test-gate.sh +80 -0
- package/scripts/do-tick.sh +102 -0
- package/scripts/do-tier.sh +6 -0
- package/scripts/do-triage.sh +182 -0
- package/scripts/do-ui-gate.sh +1 -1
- package/scripts/do-w4-gates.sh +451 -0
- package/scripts/do-walk.sh +12 -1
- package/scripts/env-sync.sh +173 -0
- package/scripts/factory-brief-check.sh +330 -0
- package/scripts/factory-check.sh +68 -14
- 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 +118 -3
- package/scripts/factory-review-check.mjs +61 -0
- package/scripts/factory-ship.sh +61 -0
- package/scripts/factory-tasks-check.sh +18 -1
- package/scripts/factory-turn.sh +326 -0
- package/scripts/factory-walk.sh +396 -0
- package/scripts/factory-width.sh +57 -0
- package/scripts/fade-toxic.sh +4 -3
- package/scripts/fixtures/factory-brief-real.md +44 -0
- package/scripts/fixtures/triage-dupe.md +5 -0
- package/scripts/fleet-manifest.mjs +108 -0
- package/scripts/fleet-status.sh +110 -0
- package/scripts/full-suite-paths-check.sh +144 -0
- package/scripts/gate-reaper-check.sh +98 -0
- package/scripts/gate-reaper.sh +125 -0
- package/scripts/gate-run.sh +73 -0
- package/scripts/gc-content-check.sh +140 -0
- package/scripts/gen-dev-config.py +20 -0
- package/scripts/govern-bound-check.sh +60 -0
- package/scripts/govern-claims-check.sh +233 -0
- package/scripts/govern-mem-check.sh +290 -0
- package/scripts/governor-doors-check.sh +362 -0
- package/scripts/governor-escape-check.sh +171 -0
- package/scripts/health.sh +413 -0
- package/scripts/id-inventory.mjs +418 -0
- package/scripts/land.sh +551 -0
- package/scripts/lib/gc-finished.sh +77 -0
- package/scripts/lib/govern.sh +361 -0
- package/scripts/lib/govern.ts +756 -0
- package/scripts/lighthouse-run.sh +187 -0
- package/scripts/livekit-live-check.sh +61 -0
- package/scripts/livekit-ratchet.sh +46 -0
- package/scripts/load-guard-check.sh +49 -0
- package/scripts/machine-check.sh +102 -0
- package/scripts/machine-watch.sh +177 -0
- package/scripts/one-agents.mjs +415 -0
- package/scripts/one-resume.sh +78 -0
- package/scripts/orphan-baseline.json +182 -0
- package/scripts/orphan-modules.mjs +179 -0
- package/scripts/pr-body.sh +335 -0
- package/scripts/preview-fd-check.sh +289 -0
- package/scripts/promise-manifest.mjs +24 -1
- package/scripts/release.sh +322 -0
- package/scripts/roles-check.sh +946 -0
- package/scripts/sdk-build-cached.sh +64 -0
- package/scripts/signal-watch.sh +241 -0
- package/scripts/skills-publish.sh +94 -0
- package/scripts/speed-cache-check.sh +173 -0
- package/scripts/speed-check.mjs +907 -0
- package/scripts/speed-parity-check.sh +648 -0
- package/scripts/speed-waterfall-check.sh +355 -0
- package/scripts/substrate-env-parity.mjs +156 -0
- package/scripts/tasks-claim-race.mjs +108 -0
- package/scripts/tasks-loop.sh +185 -0
- package/scripts/test-cached.sh +255 -0
- package/scripts/test-full.sh +87 -0
- package/scripts/test-honesty.mjs +137 -0
- package/scripts/test-lanes.sh +166 -0
- package/scripts/test-speed.sh +94 -0
- package/scripts/triage-shape-check.sh +149 -0
- package/scripts/tsc-cached.sh +179 -0
- package/scripts/typedb-flake-check.sh +197 -0
- package/scripts/urls-lint.sh +15 -0
- package/scripts/verify-fast.sh +445 -0
- package/scripts/vespio-sync.sh +149 -0
- package/scripts/wf-check.mjs +104 -1
- package/scripts/worktree-preview.sh +879 -0
- package/scripts/worktree-up.sh +208 -0
- package/skills/livekit-agents/SKILL.md +285 -0
- package/skills/livekit-agents/references/freshness-rules.md +168 -0
- package/skills/shadcn/SKILL.md +1 -1
- package/skills/signal/SKILL.md +0 -1
- package/skills/voice/SKILL.md +94 -6
- package/skills/voice/corpus-check.sh +87 -0
- package/hooks/scripts/compact-hint.sh +0 -35
- package/hooks/scripts/gate-guard.sh +0 -83
- package/hooks/scripts/read-tracker.sh +0 -26
- package/hooks/scripts/session-end-verify.sh +0 -51
- package/hooks/scripts/stop-reflect.sh +0 -140
- package/hooks/scripts/sync-priority-todo.sh +0 -57
- package/hooks/scripts/sync-todo-docs.sh +0 -46
- package/hooks/scripts/tool-signal.sh +0 -48
- package/scripts/do-tasks-bridge.py +0 -366
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# do-recon-pack.sh <slug> [--files <path>...] — the DETERMINISTIC W1.
|
|
3
|
+
#
|
|
4
|
+
# manifest: needs-env
|
|
5
|
+
#
|
|
6
|
+
# needs-env, not portable: it JOINs do-brief.sh (needs-env) and do-recon-cache.sh,
|
|
7
|
+
# so it can be no cleaner than its inputs.
|
|
8
|
+
#
|
|
9
|
+
# WHY. `.claude/commands/do.md` Step 0.5 already states the contract: "with the
|
|
10
|
+
# brief compiled, a cycle needs at most TWO model calls — W2 (decide) and W3
|
|
11
|
+
# (make it). W1 collapses into the brief plus do-recon-cache.sh check." Step 3
|
|
12
|
+
# still spawned a `w1-recon` agent every cycle anyway. Measured 2026-09-01, that
|
|
13
|
+
# spawn re-loads 6.4KB of agent prose to narrate, in <400 words, facts that are
|
|
14
|
+
# on disk: which files exist, how big they are, what they export, who imports
|
|
15
|
+
# them, which docs carry the slug, and what the previous cycle left in
|
|
16
|
+
# `.w4-improvements.json` / `.claude/improvements.queue.md`. None of that is
|
|
17
|
+
# judgment. All of it is grep.
|
|
18
|
+
#
|
|
19
|
+
# This is a JOIN plus a symbol inventory, not new logic:
|
|
20
|
+
# do-brief.sh -> slug, plan, ready, files, folders, tier, spine, ceiling
|
|
21
|
+
# do-recon-cache.sh -> a warm prior recon for the same file shas (0 tokens)
|
|
22
|
+
# git grep / wc -> exports, imports, consumers, doc family
|
|
23
|
+
#
|
|
24
|
+
# It does NOT replace the `w1-recon` AGENT for SURVEY or INVESTIGATE (the spine
|
|
25
|
+
# stops in do.md Step 2). Those are once-per-PLAN judgment calls — reuse verdicts
|
|
26
|
+
# and root-cause forensics — and are not the per-cycle bill. This replaces the
|
|
27
|
+
# per-cycle RECON spawn only.
|
|
28
|
+
#
|
|
29
|
+
# Output: ONE json object on stdout. Non-zero exit + EMPTY stdout when the brief
|
|
30
|
+
# cannot be compiled — a half-pack is worse than no pack, because the caller
|
|
31
|
+
# cannot tell which half is missing (same law as do-brief.sh).
|
|
32
|
+
#
|
|
33
|
+
# --self-test runs the fixtures INCLUDING a red proof; exits non-zero on failure.
|
|
34
|
+
set -euo pipefail
|
|
35
|
+
|
|
36
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
37
|
+
S="$ROOT/.claude/scripts"
|
|
38
|
+
MAX_FILES="${RECON_PACK_MAX_FILES:-40}"
|
|
39
|
+
|
|
40
|
+
_exports() { # exported symbol names, capped
|
|
41
|
+
grep -hoE '^[[:space:]]*export[[:space:]]+(default[[:space:]]+)?(async[[:space:]]+)?(function|const|let|class|type|interface|enum)[[:space:]]+[A-Za-z_$][A-Za-z0-9_$]*' "$1" 2>/dev/null \
|
|
42
|
+
| awk '{print $NF}' | sort -u | head -30
|
|
43
|
+
}
|
|
44
|
+
_imports() { # module specifiers this file pulls in, capped
|
|
45
|
+
[ "$WIDE" = true ] || return 0
|
|
46
|
+
grep -hoE "from[[:space:]]+['\"][^'\"]+['\"]" "$1" 2>/dev/null \
|
|
47
|
+
| sed -E "s/.*['\"]([^'\"]+)['\"].*/\1/" | sort -u | head -30
|
|
48
|
+
}
|
|
49
|
+
_consumers() { # files that import this one, by basename stem, capped
|
|
50
|
+
local stem; stem="$(basename "$1")"; stem="${stem%.*}"
|
|
51
|
+
[ -n "$stem" ] || return 0
|
|
52
|
+
git -C "$ROOT" grep -l -F -- "/$stem'" -- '*.ts' '*.tsx' '*.astro' 2>/dev/null \
|
|
53
|
+
| grep -vxF "$1" | head -"$CO_CAP" || true
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# WIDTH CAP. This pack replaces a receipt do.md caps at 400 words (~2.5KB), and
|
|
57
|
+
# a recon input bigger than the agent prompt it removed is not a saving.
|
|
58
|
+
# Measured 2026-09-01: 5 files -> 6.4KB, 15 files -> 12.1KB uncapped. Past 10
|
|
59
|
+
# files the per-file detail narrows — `imports` goes first, because W2 needs the
|
|
60
|
+
# exported surface and who depends on it, almost never the module specifiers.
|
|
61
|
+
CO_CAP=12
|
|
62
|
+
WIDE=true
|
|
63
|
+
_set_caps() { # <file-count>
|
|
64
|
+
if [ "$1" -gt "${RECON_PACK_WIDE_MAX:-10}" ]; then CO_CAP=5; WIDE=false
|
|
65
|
+
else CO_CAP=12; WIDE=true; fi
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_json_arr() { # stdin lines -> json array (empty stdin -> [])
|
|
69
|
+
jq -R -s 'split("\n") | map(select(length > 0))'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_pack() {
|
|
73
|
+
local brief slug files_json
|
|
74
|
+
# The brief is the floor. If it refuses, we refuse — identically.
|
|
75
|
+
brief="$(bash "$S/do-brief.sh" "$@" 2>/dev/null)" || return 1
|
|
76
|
+
[ -n "$brief" ] || return 1
|
|
77
|
+
printf '%s' "$brief" | jq -e . >/dev/null 2>&1 || return 1
|
|
78
|
+
|
|
79
|
+
slug="$(printf '%s' "$brief" | jq -r '.slug // ""')"
|
|
80
|
+
files_json="$(printf '%s' "$brief" | jq -r '.files[]?' | head -"$MAX_FILES" | _json_arr)"
|
|
81
|
+
_set_caps "$(printf '%s' "$files_json" | jq 'length')"
|
|
82
|
+
|
|
83
|
+
# ---- per-file inventory (the part W1 used to narrate) ----
|
|
84
|
+
local inv='[]' f entry
|
|
85
|
+
while IFS= read -r f; do
|
|
86
|
+
[ -n "$f" ] || continue
|
|
87
|
+
if [ -f "$ROOT/$f" ]; then
|
|
88
|
+
entry="$(jq -n \
|
|
89
|
+
--arg path "$f" \
|
|
90
|
+
--argjson loc "$(wc -l < "$ROOT/$f" | tr -d ' ')" \
|
|
91
|
+
--arg sha "$(git -C "$ROOT" hash-object "$f" 2>/dev/null || echo '')" \
|
|
92
|
+
--argjson exports "$(_exports "$ROOT/$f" | _json_arr)" \
|
|
93
|
+
--argjson imports "$(_imports "$ROOT/$f" | _json_arr)" \
|
|
94
|
+
--argjson consumers "$(_consumers "$f" | _json_arr)" \
|
|
95
|
+
'{path:$path, exists:true, loc:$loc, sha:$sha, exports:$exports, imports:$imports, consumers:$consumers}')"
|
|
96
|
+
else
|
|
97
|
+
entry="$(jq -n --arg path "$f" '{path:$path, exists:false, loc:0, sha:"", exports:[], imports:[], consumers:[]}')"
|
|
98
|
+
fi
|
|
99
|
+
inv="$(printf '%s' "$inv" | jq --argjson e "$entry" '. + [$e]')"
|
|
100
|
+
done < <(printf '%s' "$files_json" | jq -r '.[]?')
|
|
101
|
+
|
|
102
|
+
# ---- prior-cycle carry-over (W1's non-recon side effects — must not be lost) ----
|
|
103
|
+
local improvements='[]' queue='[]' docs='[]'
|
|
104
|
+
if [ -f "$ROOT/.w4-improvements.json" ]; then
|
|
105
|
+
improvements="$(jq -c '[.. | objects | select(has("item") or has("improve"))] | .[0:10]' \
|
|
106
|
+
"$ROOT/.w4-improvements.json" 2>/dev/null || echo '[]')"
|
|
107
|
+
fi
|
|
108
|
+
if [ -n "$slug" ] && [ -f "$ROOT/.claude/improvements.queue.md" ]; then
|
|
109
|
+
queue="$(grep -i -- "$slug" "$ROOT/.claude/improvements.queue.md" 2>/dev/null | head -5 | _json_arr)"
|
|
110
|
+
fi
|
|
111
|
+
if [ -n "$slug" ]; then
|
|
112
|
+
docs="$(cd "$ROOT" && ls "text/$slug.md" "text/$slug-plan.md" "text/$slug-features.md" \
|
|
113
|
+
"text/$slug-ui.md" "text/$slug-todo.md" "text/$slug-docs.md" 2>/dev/null | _json_arr)"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# ---- warm recon cache (0-token prior findings for the same shas) ----
|
|
117
|
+
local cache_hit=false cache_findings="" flist
|
|
118
|
+
flist="$(printf '%s' "$files_json" | jq -r '.[]?')"
|
|
119
|
+
if [ -n "$flist" ]; then
|
|
120
|
+
if cache_findings="$(cd "$ROOT" && bash "$S/do-recon-cache.sh" check $flist 2>/dev/null)"; then
|
|
121
|
+
cache_hit=true
|
|
122
|
+
else
|
|
123
|
+
cache_findings=""
|
|
124
|
+
fi
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
jq -n \
|
|
128
|
+
--argjson brief "$brief" \
|
|
129
|
+
--argjson inventory "$inv" \
|
|
130
|
+
--argjson improvements "$improvements" \
|
|
131
|
+
--argjson queue "$queue" \
|
|
132
|
+
--argjson docs "$docs" \
|
|
133
|
+
--argjson cache_hit "$cache_hit" \
|
|
134
|
+
--arg cache_findings "$cache_findings" \
|
|
135
|
+
'{brief:$brief, inventory:$inventory, doc_family:$docs,
|
|
136
|
+
improvements_open:$improvements, improvements_queue:$queue,
|
|
137
|
+
recon_cache:{hit:$cache_hit, findings:$cache_findings}}'
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_self_test() {
|
|
141
|
+
local fails=0 out
|
|
142
|
+
|
|
143
|
+
# 1. refusal parity with do-brief: a missing plan must refuse with EMPTY stdout.
|
|
144
|
+
if out=$(bash "$S/do-recon-pack.sh" __nosuchplan__ 2>/dev/null); then
|
|
145
|
+
echo "FAIL: missing plan produced a pack"; fails=$((fails+1))
|
|
146
|
+
else
|
|
147
|
+
[ -z "${out:-}" ] || { echo "FAIL: missing plan wrote to stdout"; fails=$((fails+1)); }
|
|
148
|
+
echo "ok: missing plan refuses (exit non-zero, empty stdout)"
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# 2. the pack is valid JSON and carries the brief + a real symbol inventory.
|
|
152
|
+
if out=$(bash "$S/do-recon-pack.sh" --files one.ie/web/src/lib/authority.ts 2>/dev/null); then
|
|
153
|
+
if printf '%s' "$out" | jq -e '.brief.tier and (.inventory | length > 0)' >/dev/null 2>&1; then
|
|
154
|
+
echo "ok: pack is valid JSON with brief + inventory"
|
|
155
|
+
else
|
|
156
|
+
echo "FAIL: pack missing brief/inventory"; fails=$((fails+1))
|
|
157
|
+
fi
|
|
158
|
+
if printf '%s' "$out" | jq -e '.inventory[0].exports | length > 0' >/dev/null 2>&1; then
|
|
159
|
+
echo "ok: exports extracted from a real source file"
|
|
160
|
+
else
|
|
161
|
+
echo "FAIL: no exports extracted from authority.ts"; fails=$((fails+1))
|
|
162
|
+
fi
|
|
163
|
+
else
|
|
164
|
+
echo "FAIL: --files pack did not run"; fails=$((fails+1))
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# 3. RED PROOF — a checker that cannot go red proves nothing.
|
|
168
|
+
# Feed a file that does NOT exist. The pack must report exists:false and
|
|
169
|
+
# exports:[] rather than fabricate an inventory — AND the exact assertion
|
|
170
|
+
# that passed in (2) must now FAIL, proving it bites.
|
|
171
|
+
if out=$(bash "$S/do-recon-pack.sh" --files no/such/file.ts 2>/dev/null); then
|
|
172
|
+
if printf '%s' "$out" | jq -e '.inventory[0].exists == false and (.inventory[0].exports | length == 0)' >/dev/null 2>&1; then
|
|
173
|
+
echo "ok: RED PROOF — a missing target is reported exists:false, not fabricated"
|
|
174
|
+
else
|
|
175
|
+
echo "FAIL: RED PROOF — missing target was not marked absent"; fails=$((fails+1))
|
|
176
|
+
fi
|
|
177
|
+
if printf '%s' "$out" | jq -e '.inventory[0].exports | length > 0' >/dev/null 2>&1; then
|
|
178
|
+
echo "FAIL: RED PROOF — the exports assertion passed on a file with no exports"; fails=$((fails+1))
|
|
179
|
+
else
|
|
180
|
+
echo "ok: RED PROOF — the exports assertion goes RED on a file with none"
|
|
181
|
+
fi
|
|
182
|
+
else
|
|
183
|
+
echo "FAIL: RED PROOF — pack refused a syntactically fine --files target"; fails=$((fails+1))
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
if [ "$fails" -eq 0 ]; then echo "do-recon-pack: self-test PASS"; return 0; fi
|
|
187
|
+
echo "do-recon-pack: self-test FAIL ($fails)"; return 1
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
case "${1:-}" in
|
|
191
|
+
--self-test) _self_test; exit $? ;;
|
|
192
|
+
""|-h|--help) echo "usage: do-recon-pack.sh <slug> | --files <path>... | --self-test" >&2; exit 2 ;;
|
|
193
|
+
esac
|
|
194
|
+
|
|
195
|
+
out="$(_pack "$@")" || exit 1
|
|
196
|
+
printf '%s\n' "$out"
|
package/scripts/do-reconcile.sh
CHANGED
|
@@ -47,6 +47,36 @@ _sanitize() {
|
|
|
47
47
|
| _strip_allow
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
# Read stdin with a wall clock. macOS ships no `timeout(1)` (the same absence the
|
|
51
|
+
# gate governor had to work around), so the bound is built from `read -t`.
|
|
52
|
+
#
|
|
53
|
+
# NOT with a backgrounded `cat`: the first attempt did that and read NOTHING,
|
|
54
|
+
# because a job backgrounded by a non-interactive shell gets /dev/null for stdin.
|
|
55
|
+
# The checker then reported OK on input containing a dead name -- a green gate
|
|
56
|
+
# over a red input, which is worse than the hang it was fixing. Caught by the red
|
|
57
|
+
# proof (`echo 'colony trail' | do-reconcile.sh dictionary` must FAIL); the
|
|
58
|
+
# original caught 'trail', the rewrite did not.
|
|
59
|
+
#
|
|
60
|
+
# `read -t` distinguishes the two endings that matter: exit >128 is the timeout,
|
|
61
|
+
# exit 1 is a clean EOF. Real pipes hit EOF in milliseconds.
|
|
62
|
+
_read_stdin_bounded() {
|
|
63
|
+
local secs="${RECONCILE_STDIN_TIMEOUT:-10}" line out="" st rc=0
|
|
64
|
+
while true; do
|
|
65
|
+
if IFS= read -r -t "$secs" line; then
|
|
66
|
+
out="$out$line
|
|
67
|
+
"
|
|
68
|
+
else
|
|
69
|
+
st=$?
|
|
70
|
+
# a final unterminated line still carries content
|
|
71
|
+
[ -n "$line" ] && out="$out$line"
|
|
72
|
+
[ "$st" -gt 128 ] && rc=1
|
|
73
|
+
break
|
|
74
|
+
fi
|
|
75
|
+
done
|
|
76
|
+
printf '%s' "$out"
|
|
77
|
+
return "$rc"
|
|
78
|
+
}
|
|
79
|
+
|
|
50
80
|
_load_text() {
|
|
51
81
|
local text=""
|
|
52
82
|
if [ "$#" -gt 0 ]; then
|
|
@@ -56,7 +86,32 @@ _load_text() {
|
|
|
56
86
|
if [ -f "$a" ]; then text="$text $(_sanitize < "$a")"; else text="$text $(printf '%s' "$a" | _sanitize)"; fi
|
|
57
87
|
done
|
|
58
88
|
else
|
|
59
|
-
|
|
89
|
+
# STDIN FALLBACK -- bounded, because an unbounded one hangs the loop.
|
|
90
|
+
#
|
|
91
|
+
# Measured 2026-09-01: `do-reconcile.sh dictionary` with no file argument and
|
|
92
|
+
# an inherited-but-idle stdin blocked for over NINE MINUTES before it was
|
|
93
|
+
# killed. It is not slow; it is waiting for an EOF that never comes. And
|
|
94
|
+
# do.md's own toolbox documents exactly that argument-less form
|
|
95
|
+
# ("do-reconcile.sh dictionary # no dead name, no new synonym"), so an agent
|
|
96
|
+
# copying the documented invocation stalls its whole cycle until do-auto's
|
|
97
|
+
# hard cap reaps it -- which reads as a mysteriously slow wave, not as a hang.
|
|
98
|
+
#
|
|
99
|
+
# Two guards. A terminal stdin can never deliver piped input, so that is a
|
|
100
|
+
# usage error, immediately. Anything else is read under a wall clock: real
|
|
101
|
+
# pipes (`git diff --name-only | do-reconcile.sh types`) close in
|
|
102
|
+
# milliseconds, so the bound only ever fires on the pathological case.
|
|
103
|
+
if [ -t 0 ]; then
|
|
104
|
+
printf 'do-reconcile: %s needs a file argument, or input on stdin.\n' "$CANON" >&2
|
|
105
|
+
printf ' do-reconcile.sh %s <file>...\n git diff --name-only | do-reconcile.sh %s\n' "$CANON" "$CANON" >&2
|
|
106
|
+
exit 2
|
|
107
|
+
fi
|
|
108
|
+
local _raw=""
|
|
109
|
+
if ! _raw="$(_read_stdin_bounded)"; then
|
|
110
|
+
printf 'do-reconcile: %s timed out waiting on stdin after %ss — no file argument was given.\n' \
|
|
111
|
+
"$CANON" "${RECONCILE_STDIN_TIMEOUT:-10}" >&2
|
|
112
|
+
exit 2
|
|
113
|
+
fi
|
|
114
|
+
text="$(printf '%s' "$_raw" | _sanitize)"
|
|
60
115
|
fi
|
|
61
116
|
printf '%s' "$text"
|
|
62
117
|
}
|
|
@@ -247,9 +302,71 @@ case "$CANON" in
|
|
|
247
302
|
|
|
248
303
|
current=0
|
|
249
304
|
if [ -d "$folder" ] && [ -f "$folder/tsconfig.json" ]; then
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
305
|
+
# ── Governed tsc (2026-08-18) ──────────────────────────────────────
|
|
306
|
+
# Six concurrent Claude sessions ran this canon at once, each spawning
|
|
307
|
+
# its own `tsc --noEmit` over the SAME tree for the SAME answer: load 57
|
|
308
|
+
# on 10 cores, swap exhausted, ~26 MB/s swapins. Starved, each tsc took
|
|
309
|
+
# 18 min instead of 2, sessions timed out, and retries piled on more.
|
|
310
|
+
# Fix: one tsc per (folder, tree-fingerprint); everyone else reuses its
|
|
311
|
+
# result. Identical work collapses instead of multiplying.
|
|
312
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib/govern.sh"
|
|
313
|
+
|
|
314
|
+
# Fingerprint the tree: same fingerprint => same tsc answer.
|
|
315
|
+
#
|
|
316
|
+
# ONE derivation, shared with tsc-cached.sh: tsc_tree_fingerprint in
|
|
317
|
+
# lib/govern.sh hashes the CONTENT of everything tsc reads (the folder's
|
|
318
|
+
# .ts/.tsx/.json + lockfile, tracked or not, plus packages/sdk/src for the
|
|
319
|
+
# folders that resolve @oneie/sdk types). It used to be an mtime stat
|
|
320
|
+
# here AND a second copy in tsc-cached.sh — two derivations of one key is
|
|
321
|
+
# how the memo split, and mtime is why it never shared across worktrees.
|
|
322
|
+
_fp_extra=""
|
|
323
|
+
case "$folder" in one.ie/web|channels) _fp_extra="packages/sdk/src" ;; esac
|
|
324
|
+
_fp=$(tsc_tree_fingerprint "$folder" $_fp_extra)
|
|
325
|
+
_cache="$GOVERN_DIR/tsc-$(printf '%s' "$folder" | tr '/' '_').$_fp"
|
|
326
|
+
|
|
327
|
+
if [ -s "$_cache" ]; then
|
|
328
|
+
current=$(cat "$_cache" | tr -d '[:space:]') # someone already computed it
|
|
329
|
+
elif gate_lock "tsc-$(printf '%s' "$folder" | tr '/' '_')" "${RECONCILE_TSC_WAIT:-900}"; then
|
|
330
|
+
trap 'gate_release_all' EXIT INT TERM
|
|
331
|
+
if [ -s "$_cache" ]; then
|
|
332
|
+
current=$(cat "$_cache" | tr -d '[:space:]') # computed while we queued
|
|
333
|
+
else
|
|
334
|
+
_tsc_tmp=$(mktemp)
|
|
335
|
+
# THE SLOT, not just the lock — same defect as tsc-cached.sh, same fix.
|
|
336
|
+
# The gate_lock above dedupes this folder against other reconciles; it
|
|
337
|
+
# does nothing about N worktrees typechecking N different folders at
|
|
338
|
+
# once. See tsc-cached.sh for the 2026-09-07 measurement.
|
|
339
|
+
# Resolve gate-run from THIS script's own directory. An earlier
|
|
340
|
+
# version used "$ROOT/..." -- ROOT is never set in this file, and under
|
|
341
|
+
# `set -u` that is a hard "unbound variable" that killed the whole
|
|
342
|
+
# `types` canon. Caught by tests/integration/reconcile.test.ts, which is
|
|
343
|
+
# the reason that test exists.
|
|
344
|
+
_gr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/gate-run.sh"
|
|
345
|
+
GOVERN_GATE_TIMEOUT="${RECONCILE_TSC_TIMEOUT:-600}" \
|
|
346
|
+
bash "$_gr" "tsc-reconcile:$folder" -- \
|
|
347
|
+
bash -c "cd '$folder' && bunx tsc --noEmit 2>&1 | grep -c 'error TS' > '$_tsc_tmp'" \
|
|
348
|
+
|| true
|
|
349
|
+
current=$(cat "$_tsc_tmp" 2>/dev/null | tr -d '[:space:]'); rm -f "$_tsc_tmp"
|
|
350
|
+
current=${current:-0}
|
|
351
|
+
printf '%s' "$current" > "$_cache"
|
|
352
|
+
fi
|
|
353
|
+
gate_release_all; trap - EXIT INT TERM
|
|
354
|
+
else
|
|
355
|
+
# Lock held for the full wait. Re-check the cache once — the holder may
|
|
356
|
+
# have finished and released between our last poll and now.
|
|
357
|
+
if [ -s "$_cache" ]; then
|
|
358
|
+
current=$(cat "$_cache" | tr -d '[:space:]')
|
|
359
|
+
else
|
|
360
|
+
# Never exit 0 without an answer: a gate that passes because it was
|
|
361
|
+
# busy is a fail-open, which is worse than the load it avoids.
|
|
362
|
+
echo "RECONCILE[types]: lock held ${RECONCILE_TSC_WAIT:-900}s — checking anyway" >&2
|
|
363
|
+
_tsc_tmp=$(mktemp)
|
|
364
|
+
run_bounded "${RECONCILE_TSC_TIMEOUT:-600}" \
|
|
365
|
+
bash -c "cd '$folder' && bunx tsc --noEmit 2>&1 | grep -c 'error TS' > '$_tsc_tmp'" \
|
|
366
|
+
2>/dev/null || true
|
|
367
|
+
current=$(cat "$_tsc_tmp" 2>/dev/null | tr -d '[:space:]'); rm -f "$_tsc_tmp"
|
|
368
|
+
fi
|
|
369
|
+
fi
|
|
253
370
|
current=${current:-0}
|
|
254
371
|
fi
|
|
255
372
|
|