@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,140 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# gc-content-check.sh — the red proof for lib/gc-finished.sh.
|
|
3
|
+
#
|
|
4
|
+
# manifest: portable
|
|
5
|
+
#
|
|
6
|
+
# Builds a sandbox repo carrying the branch shapes the sweep meets, drives the
|
|
7
|
+
# REAL predicate (sourced, never re-implemented), and then proves the OLD
|
|
8
|
+
# commit-count predicate gets the important one wrong. A checker that only shows
|
|
9
|
+
# the new code passing would not tell you the change was worth making.
|
|
10
|
+
#
|
|
11
|
+
# NOT reproduced here: `git cherry`'s blind spot on a merge commit. That was
|
|
12
|
+
# measured on this repo (merge/trunk-reconcile, 2026-09-07: cherry reported
|
|
13
|
+
# 0-new for a branch holding 24 files and 3416 lines dev had never seen) and the
|
|
14
|
+
# reasoning lives in lib/gc-finished.sh. Faking a multi-merge-base history to
|
|
15
|
+
# re-stage it would be asserting a claim this sandbox does not actually show —
|
|
16
|
+
# the fourth case below covers the same risk directly: a merge carrying unique
|
|
17
|
+
# content must read NOT finished.
|
|
18
|
+
#
|
|
19
|
+
# bash .claude/scripts/gc-content-check.sh # exits non-zero on failure
|
|
20
|
+
set -uo pipefail
|
|
21
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
. "$HERE/lib/gc-finished.sh"
|
|
23
|
+
|
|
24
|
+
SANDBOX="$(mktemp -d)"; trap 'rm -rf "$SANDBOX"' EXIT
|
|
25
|
+
fails=0
|
|
26
|
+
EXPECT_RED=0 # set while driving the neutered predicate, so an INTENDED failure
|
|
27
|
+
# does not print the word FAIL and read as a broken checker.
|
|
28
|
+
ok() { printf ' ok %s\n' "$1"; }
|
|
29
|
+
bad() {
|
|
30
|
+
if [ "$EXPECT_RED" = 1 ]; then printf ' red %s — as intended\n' "$1"
|
|
31
|
+
else printf ' FAIL %s\n' "$1"; fi
|
|
32
|
+
fails=$((fails+1))
|
|
33
|
+
}
|
|
34
|
+
want() { # <expected 0|1> <branch> <what>
|
|
35
|
+
gc_finished trunk "$2"; local got=$?
|
|
36
|
+
[ "$got" -eq "$1" ] && ok "$3" || bad "$3 (wanted finished=$1, got $got)"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
cd "$SANDBOX"
|
|
40
|
+
git init -q -b trunk .
|
|
41
|
+
git config user.email t@e.st; git config user.name t
|
|
42
|
+
git config commit.gpgsign false
|
|
43
|
+
echo base > a.txt; git add a.txt; git commit -qm base
|
|
44
|
+
echo one > c.txt; git add c.txt; git commit -qm second
|
|
45
|
+
B1="$(git rev-parse HEAD)"
|
|
46
|
+
|
|
47
|
+
# 1 — REBASED DUPLICATE: the branch's patch reaches trunk under a DIFFERENT sha.
|
|
48
|
+
# This is the case the commit count gets wrong, and the reason for this file.
|
|
49
|
+
git checkout -q -b dup "$B1"
|
|
50
|
+
echo fixed > a.txt; git commit -qam "fix a"
|
|
51
|
+
git checkout -q trunk
|
|
52
|
+
git cherry-pick dup >/dev/null 2>&1 || { bad "sandbox: cherry-pick failed"; exit 1; }
|
|
53
|
+
# Re-message it. A cherry-pick onto the same parent, in the same second, with the
|
|
54
|
+
# same author and message, produces a byte-identical commit OBJECT — trunk then
|
|
55
|
+
# fast-forwards onto the branch and there is no divergence left to detect. That
|
|
56
|
+
# is a sandbox artifact, not the real world, where a re-landed patch always
|
|
57
|
+
# arrives with a different sha. The amend forces the sha apart while leaving the
|
|
58
|
+
# patch identical, which is precisely the case under test.
|
|
59
|
+
git commit -q --amend -m "fix a (relanded under a different sha)"
|
|
60
|
+
|
|
61
|
+
# 2 — ORDINARY UNLANDED BRANCH.
|
|
62
|
+
git checkout -q -b ahead trunk
|
|
63
|
+
echo new > b.txt; git add b.txt; git commit -qm "adds b"
|
|
64
|
+
|
|
65
|
+
# 3 — FULLY CONTAINED: tip is an ancestor of trunk.
|
|
66
|
+
git checkout -q -b behind "$B1"
|
|
67
|
+
|
|
68
|
+
# 4 — MERGE COMMIT CARRYING UNIQUE CONTENT. The shape that makes a
|
|
69
|
+
# patch-counting test (git cherry) unsafe on its own.
|
|
70
|
+
git checkout -q -b side "$B1"
|
|
71
|
+
echo unique > only-here.txt; git add only-here.txt; git commit -qm "unique file"
|
|
72
|
+
git checkout -q -b mergey trunk
|
|
73
|
+
git merge --no-edit side >/dev/null 2>&1 || { bad "sandbox: merge failed"; exit 1; }
|
|
74
|
+
|
|
75
|
+
echo "== the predicate the sweep runs"
|
|
76
|
+
want 0 dup "a rebased duplicate reads FINISHED — its content is already on the platform"
|
|
77
|
+
want 1 ahead "an ordinary unlanded branch reads NOT finished"
|
|
78
|
+
want 0 behind "a branch fully contained in the base reads FINISHED"
|
|
79
|
+
want 1 mergey "a merge carrying a file the base lacks reads NOT finished"
|
|
80
|
+
|
|
81
|
+
echo "== what the OLD commit-count predicate would have said"
|
|
82
|
+
old_finished() { [ "$(git rev-list --count "trunk..$1" 2>/dev/null || echo 1)" -eq 0 ]; }
|
|
83
|
+
if old_finished dup
|
|
84
|
+
then bad "the count predicate should MISS the duplicate — this proof is broken"
|
|
85
|
+
else ok "the count predicate hoards the duplicate for ever — the ~120MB this fixes"; fi
|
|
86
|
+
if old_finished ahead
|
|
87
|
+
then bad "the count predicate wrongly sweeps an unlanded branch"
|
|
88
|
+
else ok "the count predicate keeps an unlanded branch (both agree here)"; fi
|
|
89
|
+
|
|
90
|
+
echo "== the clean-worktree path survives set -e"
|
|
91
|
+
# The sweep runs under `set -euo pipefail`, and `grep -v` exits 1 when it filters
|
|
92
|
+
# EVERYTHING out — the clean-worktree case. Inline, that killed the sweep at the
|
|
93
|
+
# first worktree it was meant to remove: four keep lines, exit 1, no summary, and
|
|
94
|
+
# invisible behind a `| cat`. Drive the real function in a real subshell under
|
|
95
|
+
# the real flags, because that is the only way this comes back red.
|
|
96
|
+
git checkout -q trunk
|
|
97
|
+
if out="$(bash -c '
|
|
98
|
+
set -euo pipefail
|
|
99
|
+
. "'"$HERE"'/lib/gc-finished.sh"
|
|
100
|
+
d="$(gc_real_dirt "'"$SANDBOX"'")"
|
|
101
|
+
[ -z "$d" ] && echo CLEAN-AND-ALIVE
|
|
102
|
+
' 2>&1)" && [ "$out" = "CLEAN-AND-ALIVE" ]; then
|
|
103
|
+
ok "a clean worktree reports no dirt AND the shell survives it"
|
|
104
|
+
else
|
|
105
|
+
bad "the clean-tree path died under set -e (got: ${out:-<nothing>})"
|
|
106
|
+
fi
|
|
107
|
+
# And it still SEES real work, or the fix would be a mute button.
|
|
108
|
+
echo scratch > "$SANDBOX/uncommitted.txt"
|
|
109
|
+
if [ -n "$(gc_real_dirt "$SANDBOX")" ]
|
|
110
|
+
then ok "uncommitted work is still reported — the guard did not silence it"
|
|
111
|
+
else bad "gc_real_dirt missed an uncommitted file"; fi
|
|
112
|
+
rm -f "$SANDBOX/uncommitted.txt"
|
|
113
|
+
# Ephemera alone must NOT read as work, or nothing is ever swept.
|
|
114
|
+
# The tracked file is required, not decoration: git COLLAPSES a wholly-untracked
|
|
115
|
+
# directory to its top level, so an unrepresentative sandbox reports `?? one.ie/`
|
|
116
|
+
# and no path pattern can match. A real worktree has one.ie/web/ tracked, so git
|
|
117
|
+
# descends and reports `?? one.ie/web/.astro` — which is what the filter is
|
|
118
|
+
# written against. Committing one file reproduces that.
|
|
119
|
+
mkdir -p "$SANDBOX/one.ie/web"; echo keep > "$SANDBOX/one.ie/web/keep.txt"
|
|
120
|
+
git add one.ie/web/keep.txt; git commit -qm "tracked file under one.ie/web"
|
|
121
|
+
mkdir -p "$SANDBOX/one.ie/web/.astro"; echo x > "$SANDBOX/one.ie/web/.astro/gen.d.ts"
|
|
122
|
+
if [ -z "$(gc_real_dirt "$SANDBOX")" ]
|
|
123
|
+
then ok "build output alone does not count as work"
|
|
124
|
+
else bad "ephemeral dirt was reported as work — nothing would ever be swept"; fi
|
|
125
|
+
rm -rf "$SANDBOX/one.ie/web/.astro"
|
|
126
|
+
|
|
127
|
+
echo "== red proof: neuter the predicate and the checks must fail"
|
|
128
|
+
gc_finished() { return 0; } # claim every branch is finished
|
|
129
|
+
before=$fails; EXPECT_RED=1
|
|
130
|
+
want 1 ahead "(neutered) an unlanded branch must NOT read finished"
|
|
131
|
+
want 1 mergey "(neutered) a unique-content merge must NOT read finished"
|
|
132
|
+
if [ "$fails" -eq $((before+2)) ]; then
|
|
133
|
+
fails=$before; EXPECT_RED=0; ok "both checks bite when the predicate is gutted"
|
|
134
|
+
else
|
|
135
|
+
fails=$((before+1)); EXPECT_RED=0; printf ' FAIL a gutted predicate still passed — this checker proves nothing\n'
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
echo
|
|
139
|
+
[ "$fails" -eq 0 ] && { echo "gc-content-check: PASS"; exit 0; }
|
|
140
|
+
echo "gc-content-check: FAIL ($fails)"; exit 1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import json, pathlib, sys
|
|
2
|
+
# Patch the ASTRO-GENERATED config (which carries `main` + the assets binding)
|
|
3
|
+
# rather than hand-rolling one: wrangler.toml omits `main` by design, so a
|
|
4
|
+
# standalone copy deploys as an assets-only Worker and is rejected.
|
|
5
|
+
p = pathlib.Path("dist/server/wrangler.json")
|
|
6
|
+
if not p.exists():
|
|
7
|
+
print("[gen-dev-config] FATAL: dist/server/wrangler.json missing - build first"); sys.exit(1)
|
|
8
|
+
c = json.loads(p.read_text())
|
|
9
|
+
c["name"] = "one-dev"
|
|
10
|
+
c["routes"] = [{"pattern": "dev.one.ie", "custom_domain": True}]
|
|
11
|
+
# STRIP CRONS. The dev worker shares production's D1/KV bindings, so inheriting
|
|
12
|
+
# prod's schedules means TWO workers running the same handlers against the same
|
|
13
|
+
# rows - double sends, double syncs, races. Dev observes prod data; it must not
|
|
14
|
+
# also drive prod's clock. (Measured 2026-08-25: the first dev deploy shipped
|
|
15
|
+
# 6 schedules including */5 * * * *.)
|
|
16
|
+
for k in ("triggers", "crons"):
|
|
17
|
+
c.pop(k, None)
|
|
18
|
+
out = pathlib.Path("dist/server/wrangler.dev.json")
|
|
19
|
+
out.write_text(json.dumps(c, indent=2))
|
|
20
|
+
print(f"[gen-dev-config] {out} -> name={c['name']} routes={c['routes']} main={c.get('main')}")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# govern-bound-check.sh — prove run_bounded neither hangs its caller nor leaks
|
|
3
|
+
# its watchdog. Three checks, each one a measured outage.
|
|
4
|
+
#
|
|
5
|
+
# manifest: portable
|
|
6
|
+
#
|
|
7
|
+
# 1. A CAPTURED call returns when the command returns. `$(run_bounded 60 true
|
|
8
|
+
# 2>&1)` must come back in ~0s, not 60s. The watchdog used to inherit the
|
|
9
|
+
# caller's stdout (fixed 2026-09-01, `>&2`) and then its stderr (measured
|
|
10
|
+
# 2026-09-03 as 1800s of nothing inside `$(… 2>&1)`, and again inside
|
|
11
|
+
# `… 2>&1 | tail`). A wait that reads as a hang gets killed at 144 = UNRUN.
|
|
12
|
+
# 2. NO ORPHAN SLEEP survives a bounded call. `kill "$watch_pid"` reaped the
|
|
13
|
+
# watchdog subshell but not the `sleep` it forked — 21 `sleep 1800` with
|
|
14
|
+
# ppid 1 were on the box on 2026-09-04, each holding a dead caller's pipe.
|
|
15
|
+
# 3. The bound still BITES: a command that outlives its cap is killed, the
|
|
16
|
+
# whole process group with it, and the parent says so on stderr.
|
|
17
|
+
#
|
|
18
|
+
# Exit 0 = all three hold · 1 = one did not. Touches nothing machine-wide:
|
|
19
|
+
# GOVERN_DIR is a sandbox.
|
|
20
|
+
set -uo pipefail
|
|
21
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
22
|
+
export GOVERN_DIR="${TMPDIR:-/tmp}/one-govern-boundcheck.$$"
|
|
23
|
+
mkdir -p "$GOVERN_DIR"; trap 'rm -rf "$GOVERN_DIR"' EXIT
|
|
24
|
+
# shellcheck source=lib/govern.sh
|
|
25
|
+
. "$ROOT/.claude/scripts/lib/govern.sh"
|
|
26
|
+
fails=0
|
|
27
|
+
ok() { printf ' ok %s\n' "$*"; }
|
|
28
|
+
bad() { printf ' FAIL %s\n' "$*"; fails=$((fails+1)); }
|
|
29
|
+
now() { date +%s; }
|
|
30
|
+
tag="bound-check-$$"
|
|
31
|
+
|
|
32
|
+
echo "== 1. a captured call returns with the command, not with the watchdog"
|
|
33
|
+
t0=$(now)
|
|
34
|
+
out="$(run_bounded 61 bash -c "echo answer-$tag" 2>&1)"; rc=$?
|
|
35
|
+
dt=$(( $(now) - t0 ))
|
|
36
|
+
if [ "$rc" -eq 0 ] && [ "$dt" -le 3 ] && [ "$out" = "answer-$tag" ]; then ok "\$(run_bounded 60 …) returned in ${dt}s with the output intact"
|
|
37
|
+
else bad "captured call took ${dt}s rc=$rc out='$out' (a 60s wait here is the watchdog holding the pipe)"; fi
|
|
38
|
+
t0=$(now)
|
|
39
|
+
out="$(run_bounded 61 bash -c "echo answer2-$tag" 2>&1 | cat)"
|
|
40
|
+
dt=$(( $(now) - t0 ))
|
|
41
|
+
[ "$dt" -le 3 ] && ok "… and through a pipe (${dt}s)" || bad "piped call took ${dt}s"
|
|
42
|
+
|
|
43
|
+
echo "== 2. no orphaned watchdog sleep survives"
|
|
44
|
+
sleep 1
|
|
45
|
+
n=$(ps -Ao command= | grep -c "^sleep 61$")
|
|
46
|
+
[ "$n" -eq 0 ] && ok "no 'sleep 61' left behind" || bad "$n orphaned 'sleep 61' still running (the watchdog's child outlived it)"
|
|
47
|
+
|
|
48
|
+
echo "== 3. the bound still bites, and the group goes with it"
|
|
49
|
+
t0=$(now)
|
|
50
|
+
err="$(run_bounded 1 bash -c "sleep 31 & sleep 31; echo lived-$tag" 2>&1 >/dev/null)"; rc=$?
|
|
51
|
+
dt=$(( $(now) - t0 ))
|
|
52
|
+
if [ "$rc" -ne 0 ] && [ "$dt" -le 12 ]; then ok "a 31s command under a 1s cap died in ${dt}s (rc=$rc)"
|
|
53
|
+
else bad "cap did not bite: rc=$rc after ${dt}s"; fi
|
|
54
|
+
case "$err" in *TIMEOUT*) ok "the parent printed the TIMEOUT line" ;; *) bad "no TIMEOUT line on stderr: '$err'" ;; esac
|
|
55
|
+
sleep 1
|
|
56
|
+
n=$(ps -Ao command= | grep -c "^sleep 31$")
|
|
57
|
+
[ "$n" -eq 0 ] && ok "the process group was reaped (no 'sleep 31' survivors)" || bad "$n 'sleep 31' survived the group kill"
|
|
58
|
+
|
|
59
|
+
[ "$fails" -eq 0 ] && { echo "govern-bound-check: PASS"; exit 0; }
|
|
60
|
+
echo "govern-bound-check: FAILED ($fails)"; exit 1
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# govern-claims-check.sh — the two properties the claim registry exists for.
|
|
3
|
+
#
|
|
4
|
+
# C1 MUTUAL EXCLUSION two workers cannot hold the same claim
|
|
5
|
+
# C2 EVAPORATION a dead owner's claim expires with no human in the loop
|
|
6
|
+
#
|
|
7
|
+
# Plus the checks that stop C1/C2 from passing against a gutted implementation:
|
|
8
|
+
# C3 the TTL branch also evaporates (the pid branch is not the only one)
|
|
9
|
+
# C4 a partial claim rolls back (a loser holds no ground)
|
|
10
|
+
# C5 do-fleet's has_conflict seam inherits the reap — the caller, not just
|
|
11
|
+
# the primitive
|
|
12
|
+
# R1/R2 RED-PROOF: with the reaper disabled, C2 and C5 must FAIL. A checker
|
|
13
|
+
# that stays green against a broken implementation is not a check.
|
|
14
|
+
#
|
|
15
|
+
# No coordinator anywhere in here — every worker is an independent process and
|
|
16
|
+
# mkdir(2) is the only arbiter.
|
|
17
|
+
#
|
|
18
|
+
# bash .claude/scripts/govern-claims-check.sh
|
|
19
|
+
set -uo pipefail
|
|
20
|
+
|
|
21
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
SANDBOX="$(mktemp -d)"
|
|
23
|
+
trap 'rm -rf "$SANDBOX"' EXIT
|
|
24
|
+
|
|
25
|
+
# Point the whole library at a throwaway dir — this test must never touch the
|
|
26
|
+
# real machine registry other sessions are coordinating through.
|
|
27
|
+
export GOVERN_DIR="$SANDBOX/govern"
|
|
28
|
+
export GOVERN_CLAIMS_DIR="$GOVERN_DIR/claims"
|
|
29
|
+
# shellcheck source=lib/govern.sh
|
|
30
|
+
. "$HERE/lib/govern.sh"
|
|
31
|
+
|
|
32
|
+
PASS=0; FAIL=0
|
|
33
|
+
ok() { echo " ok $*"; PASS=$(( PASS + 1 )); }
|
|
34
|
+
bad() { echo " FAIL $*"; FAIL=$(( FAIL + 1 )); }
|
|
35
|
+
head_() { echo ""; echo "$*"; }
|
|
36
|
+
|
|
37
|
+
reset_registry() { rm -rf "$GOVERN_CLAIMS_DIR"; mkdir -p "$GOVERN_CLAIMS_DIR"; }
|
|
38
|
+
|
|
39
|
+
# A worker is a separate bash process that sources the library and tries to
|
|
40
|
+
# claim. It records WON or LOST and then HOLDS — a worker that exits the instant
|
|
41
|
+
# it wins is a DEAD owner, and the next contender would rightly reap it, so the
|
|
42
|
+
# exclusion test would end up measuring evaporation instead of exclusion (it did,
|
|
43
|
+
# first run: 12 winners). Nothing coordinates these processes; mkdir(2) is the
|
|
44
|
+
# only arbiter between them.
|
|
45
|
+
worker() { # worker <region> <slug> <outfile>
|
|
46
|
+
bash -c '
|
|
47
|
+
. "$1/lib/govern.sh"
|
|
48
|
+
if claim_take "$2" "$3"; then echo WON > "$4"; else echo LOST > "$4"; fi
|
|
49
|
+
sleep 20
|
|
50
|
+
' _ "$HERE" "$1" "$2" "$3" >/dev/null 2>&1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# ─── C1 · two workers cannot hold the same claim ──────────────────────────────
|
|
54
|
+
head_ "C1 mutual exclusion — N concurrent workers, one region"
|
|
55
|
+
reset_registry
|
|
56
|
+
N=12
|
|
57
|
+
WPIDS=""
|
|
58
|
+
for i in $(seq 1 $N); do
|
|
59
|
+
worker "one.ie/web/src/lib/resolvers" "fleet-$i" "$SANDBOX/w$i" &
|
|
60
|
+
WPIDS="$WPIDS $!"
|
|
61
|
+
disown %% 2>/dev/null || true # keep the reap quiet; we kill by pid below
|
|
62
|
+
done
|
|
63
|
+
# Wait until every worker has decided — all of them are still holding.
|
|
64
|
+
for _ in $(seq 1 100); do
|
|
65
|
+
[ "$(cat "$SANDBOX"/w* 2>/dev/null | grep -c . || true)" = "$N" ] && break
|
|
66
|
+
sleep 0.1
|
|
67
|
+
done
|
|
68
|
+
WON=$(cat "$SANDBOX"/w* 2>/dev/null | grep -c WON || true)
|
|
69
|
+
LOST=$(cat "$SANDBOX"/w* 2>/dev/null | grep -c LOST || true)
|
|
70
|
+
HOLDERS=$(claim_list | grep -c . || true)
|
|
71
|
+
[ "$WON" = "1" ] && ok "exactly 1 of $N concurrent workers won the region (won=$WON lost=$LOST)" \
|
|
72
|
+
|| bad "expected exactly 1 winner, got $WON (lost=$LOST)"
|
|
73
|
+
[ "$HOLDERS" = "1" ] && ok "registry holds exactly 1 claim on the region" \
|
|
74
|
+
|| bad "registry holds $HOLDERS claims on one region"
|
|
75
|
+
# shellcheck disable=SC2086
|
|
76
|
+
kill -9 $WPIDS 2>/dev/null || true
|
|
77
|
+
rm -f "$SANDBOX"/w*
|
|
78
|
+
|
|
79
|
+
# Two DIFFERENT regions must never collide into one claim. Sanitising a path
|
|
80
|
+
# into a filename is lossy (a/b and a_b sanitise alike); the key must not be.
|
|
81
|
+
reset_registry
|
|
82
|
+
claim_take "a/b" "p1" >/dev/null 2>&1
|
|
83
|
+
claim_take "a_b" "p2" >/dev/null 2>&1
|
|
84
|
+
KEYS=$(claim_list | grep -c . || true)
|
|
85
|
+
[ "$KEYS" = "2" ] && ok "distinct regions a/b and a_b get distinct claims (key is injective)" \
|
|
86
|
+
|| bad "a/b and a_b produced $KEYS claim(s) — the claim key collides"
|
|
87
|
+
|
|
88
|
+
# ─── C2 · a dead owner's claim evaporates ─────────────────────────────────────
|
|
89
|
+
head_ "C2 evaporation — kill the owner, prove the claim clears"
|
|
90
|
+
reset_registry
|
|
91
|
+
REGION="auth-seam"
|
|
92
|
+
# Spawn a real process, let IT take the claim, then kill it. The claim outlives
|
|
93
|
+
# the process on disk — that is the whole hazard.
|
|
94
|
+
bash -c '. "$1/lib/govern.sh"; claim_take "$2" "dead-fleet" >/dev/null; sleep 300' \
|
|
95
|
+
_ "$HERE" "$REGION" &
|
|
96
|
+
DEAD_PID=$!
|
|
97
|
+
for _ in 1 2 3 4 5 6 7 8 9 10; do
|
|
98
|
+
[ -n "$(claim_owner "$REGION")" ] && break
|
|
99
|
+
sleep 0.2
|
|
100
|
+
done
|
|
101
|
+
OWNER_BEFORE="$(claim_owner "$REGION")"
|
|
102
|
+
[ -n "$OWNER_BEFORE" ] && ok "claim is held while the owner lives ($OWNER_BEFORE)" \
|
|
103
|
+
|| bad "owner never took the claim — test is not exercising anything"
|
|
104
|
+
|
|
105
|
+
kill -9 "$DEAD_PID" 2>/dev/null || true
|
|
106
|
+
wait "$DEAD_PID" 2>/dev/null || true
|
|
107
|
+
|
|
108
|
+
# No sweeper ran. No human intervened. The next contender's own read reaps it.
|
|
109
|
+
OWNER_AFTER="$(claim_owner "$REGION")"
|
|
110
|
+
[ -z "$OWNER_AFTER" ] && ok "after the owner dies, claim_owner reports nobody" \
|
|
111
|
+
|| bad "dead owner still reads as holding the claim ($OWNER_AFTER)"
|
|
112
|
+
|
|
113
|
+
if claim_take "$REGION" "next-fleet"; then
|
|
114
|
+
NEW_OWNER="$(claim_owner "$REGION" | awk '{print $1}')"
|
|
115
|
+
[ "$NEW_OWNER" = "next-fleet" ] \
|
|
116
|
+
&& ok "the ground is reclaimable — new owner is next-fleet" \
|
|
117
|
+
|| bad "claim taken but metadata still names '$NEW_OWNER'"
|
|
118
|
+
else
|
|
119
|
+
bad "a dead owner's region could not be reclaimed — evaporation failed"
|
|
120
|
+
fi
|
|
121
|
+
claim_release "$REGION"
|
|
122
|
+
|
|
123
|
+
# ─── C3 · the TTL branch evaporates too ───────────────────────────────────────
|
|
124
|
+
head_ "C3 evaporation — an expired lease clears even while the owner lives"
|
|
125
|
+
reset_registry
|
|
126
|
+
GOVERN_CLAIM_TTL_SECS=5400 claim_take "stale-region" "silent-fleet" >/dev/null
|
|
127
|
+
KEY="$GOVERN_CLAIMS_DIR/$(_gv_claim_key "stale-region")"
|
|
128
|
+
# Backdate the deposit past its lease. Owner (this shell) is very much alive,
|
|
129
|
+
# so ONLY the timestamp branch can clear this.
|
|
130
|
+
sed -i.bak "s/^started=.*/started=$(( $(date +%s) - 6000 ))/" "$KEY/meta" && rm -f "$KEY/meta.bak"
|
|
131
|
+
[ -z "$(claim_owner "stale-region")" ] \
|
|
132
|
+
&& ok "a lease older than ttl reads as free although the owner is alive" \
|
|
133
|
+
|| bad "expired lease still reads as held — the TTL branch never fires"
|
|
134
|
+
|
|
135
|
+
# …and an in-lease claim from a live owner is NOT reaped (the check can say no).
|
|
136
|
+
reset_registry
|
|
137
|
+
claim_take "fresh-region" "live-fleet" >/dev/null
|
|
138
|
+
[ -n "$(claim_owner "fresh-region")" ] \
|
|
139
|
+
&& ok "a fresh claim from a live owner is still held (reaper is not indiscriminate)" \
|
|
140
|
+
|| bad "reaper cleared a live, in-lease claim"
|
|
141
|
+
claim_release "fresh-region"
|
|
142
|
+
|
|
143
|
+
# ─── C4 · partial claim rolls back ────────────────────────────────────────────
|
|
144
|
+
head_ "C4 rollback — a worker that loses one region holds none"
|
|
145
|
+
reset_registry
|
|
146
|
+
# Another live worker owns region B.
|
|
147
|
+
bash -c '. "$1/lib/govern.sh"; claim_take "regionB" "other" >/dev/null; sleep 60' _ "$HERE" &
|
|
148
|
+
OTHER=$!
|
|
149
|
+
for _ in 1 2 3 4 5 6 7 8 9 10; do [ -n "$(claim_owner regionB)" ] && break; sleep 0.2; done
|
|
150
|
+
# Our worker wants A and B; it must end up holding neither.
|
|
151
|
+
bash -c '
|
|
152
|
+
. "$1/lib/govern.sh"
|
|
153
|
+
taken=()
|
|
154
|
+
for r in regionA regionB; do
|
|
155
|
+
if claim_take "$r" "mine"; then taken+=("$r"); else
|
|
156
|
+
for t in "${taken[@]}"; do claim_release "$t"; done
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
done
|
|
160
|
+
exit 0' _ "$HERE" 2>/dev/null
|
|
161
|
+
[ $? -ne 0 ] && ok "the multi-region worker correctly failed" || bad "worker claimed a region another holds"
|
|
162
|
+
[ -z "$(claim_owner regionA)" ] \
|
|
163
|
+
&& ok "regionA was released on rollback — no orphan ground" \
|
|
164
|
+
|| bad "regionA left claimed by a worker that never launched"
|
|
165
|
+
kill -9 "$OTHER" 2>/dev/null || true; wait "$OTHER" 2>/dev/null || true
|
|
166
|
+
|
|
167
|
+
# ─── C5 · the do-fleet seam inherits the reap ─────────────────────────────────
|
|
168
|
+
head_ "C5 seam — do-fleet's REAL has_conflict/free_dirs read through the reaper"
|
|
169
|
+
reset_registry
|
|
170
|
+
# Lift the ACTUAL function bodies out of do-fleet.sh — not a hand-written copy.
|
|
171
|
+
# A copy passes while the shipped function dies on an unquoted var or a stray
|
|
172
|
+
# awk field, which is precisely the drift this check exists to catch.
|
|
173
|
+
FLEET="$HERE/do-fleet.sh"
|
|
174
|
+
eval "$(awk '/^has_conflict\(\) \{/,/^\}/' "$FLEET")"
|
|
175
|
+
eval "$(awk '/^free_dirs\(\) \{/,/^\}/' "$FLEET")"
|
|
176
|
+
# do-fleet gets its dir list from do-rank.py; stub that one seam so the test
|
|
177
|
+
# needs no plan files. Everything below is do-fleet's own code.
|
|
178
|
+
deliverable_dirs() { case "$1" in newplan|ghostplan) echo "one.ie/web/src/pages";; *) : ;; esac; }
|
|
179
|
+
declare -f has_conflict >/dev/null && ok "lifted the real has_conflict() out of do-fleet.sh" \
|
|
180
|
+
|| bad "could not lift has_conflict() — check the awk range"
|
|
181
|
+
|
|
182
|
+
bash -c '. "$1/lib/govern.sh"; claim_take "one.ie/web/src/pages" "ghostplan" >/dev/null; sleep 300' \
|
|
183
|
+
_ "$HERE" &
|
|
184
|
+
GHOST=$!
|
|
185
|
+
for _ in 1 2 3 4 5 6 7 8 9 10; do [ -n "$(claim_owner "one.ie/web/src/pages")" ] && break; sleep 0.2; done
|
|
186
|
+
if has_conflict "newplan" >/dev/null 2>&1; then
|
|
187
|
+
ok "a live ghost blocks the region (real has_conflict says conflict)"
|
|
188
|
+
else
|
|
189
|
+
bad "real has_conflict failed to see another fleet's live claim"
|
|
190
|
+
fi
|
|
191
|
+
kill -9 "$GHOST" 2>/dev/null || true; wait "$GHOST" 2>/dev/null || true
|
|
192
|
+
if has_conflict "newplan" >/dev/null 2>&1; then
|
|
193
|
+
bad "real has_conflict still blocks on a DEAD owner — the fleet would stay wedged"
|
|
194
|
+
else
|
|
195
|
+
ok "after the owner dies the real has_conflict clears — the fleet reroutes in"
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# free_dirs must not hand back a sentinel this slug never took.
|
|
199
|
+
reset_registry
|
|
200
|
+
claim_take "__ANY__" "unscoped-plan" >/dev/null
|
|
201
|
+
free_dirs "newplan" # a DIFFERENT, scoped plan finishing
|
|
202
|
+
[ "$(claim_owner "__ANY__" | awk '{print $1}')" = "unscoped-plan" ] \
|
|
203
|
+
&& ok "free_dirs leaves another slug's __ANY__ sentinel alone" \
|
|
204
|
+
|| bad "a scoped plan's free_dirs released the unscoped plan's sole-slot claim"
|
|
205
|
+
free_dirs "unscoped-plan"
|
|
206
|
+
[ -z "$(claim_owner "__ANY__")" ] \
|
|
207
|
+
&& ok "the sentinel's own slug can still release it" \
|
|
208
|
+
|| bad "__ANY__ could not be released by its owner"
|
|
209
|
+
|
|
210
|
+
# ─── R1/R2 · prove the checker can go RED ─────────────────────────────────────
|
|
211
|
+
head_ "R1/R2 red-proof — with the reaper gutted, C2 and C5 must FAIL"
|
|
212
|
+
reset_registry
|
|
213
|
+
(
|
|
214
|
+
# A gutted implementation: the owner is always "alive", so nothing evaporates.
|
|
215
|
+
_gv_alive() { return 0; }
|
|
216
|
+
bash -c '. "$1/lib/govern.sh"; claim_take "red-region" "zombie" >/dev/null; sleep 300' \
|
|
217
|
+
_ "$HERE" &
|
|
218
|
+
Z=$!
|
|
219
|
+
for _ in 1 2 3 4 5 6 7 8 9 10; do [ -d "$GOVERN_CLAIMS_DIR/$(_gv_claim_key red-region)" ] && break; sleep 0.2; done
|
|
220
|
+
kill -9 "$Z" 2>/dev/null || true; wait "$Z" 2>/dev/null || true
|
|
221
|
+
if [ -n "$(claim_owner "red-region")" ]; then
|
|
222
|
+
echo " ok with _gv_alive stubbed true, the dead owner's claim does NOT clear"
|
|
223
|
+
echo " -> C2/C5 are testing the reaper, not an empty directory"
|
|
224
|
+
exit 0
|
|
225
|
+
fi
|
|
226
|
+
echo " FAIL C2/C5 pass even with the reaper disabled — they prove nothing"
|
|
227
|
+
exit 1
|
|
228
|
+
)
|
|
229
|
+
if [ $? -eq 0 ]; then PASS=$(( PASS + 1 )); else FAIL=$(( FAIL + 1 )); fi
|
|
230
|
+
|
|
231
|
+
echo ""
|
|
232
|
+
echo "govern-claims-check: $PASS passed, $FAIL failed"
|
|
233
|
+
[ "$FAIL" -eq 0 ] || exit 1
|