oh-my-customcode 1.1.77 → 1.1.79

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/dist/cli/index.js CHANGED
@@ -217,7 +217,7 @@ var init_package = __esm(() => {
217
217
  workspaces: [
218
218
  "packages/*"
219
219
  ],
220
- version: "1.1.77",
220
+ version: "1.1.79",
221
221
  description: "Batteries-included agent harness for Claude Code",
222
222
  type: "module",
223
223
  bin: {
@@ -265,7 +265,7 @@ var init_package = __esm(() => {
265
265
  yaml: "^2.8.2"
266
266
  },
267
267
  devDependencies: {
268
- "@anthropic-ai/sdk": "^0.123.0",
268
+ "@anthropic-ai/sdk": "^0.127.0",
269
269
  "@biomejs/biome": "^2.3.12",
270
270
  "@types/bun": "^1.3.6",
271
271
  "@types/js-yaml": "^4.0.9",
package/dist/index.js CHANGED
@@ -2326,7 +2326,7 @@ var package_default = {
2326
2326
  workspaces: [
2327
2327
  "packages/*"
2328
2328
  ],
2329
- version: "1.1.77",
2329
+ version: "1.1.79",
2330
2330
  description: "Batteries-included agent harness for Claude Code",
2331
2331
  type: "module",
2332
2332
  bin: {
@@ -2374,7 +2374,7 @@ var package_default = {
2374
2374
  yaml: "^2.8.2"
2375
2375
  },
2376
2376
  devDependencies: {
2377
- "@anthropic-ai/sdk": "^0.123.0",
2377
+ "@anthropic-ai/sdk": "^0.127.0",
2378
2378
  "@biomejs/biome": "^2.3.12",
2379
2379
  "@types/bun": "^1.3.6",
2380
2380
  "@types/js-yaml": "^4.0.9",
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "1.1.77",
6
+ "version": "1.1.79",
7
7
  "description": "Batteries-included agent harness for Claude Code",
8
8
  "type": "module",
9
9
  "bin": {
@@ -51,7 +51,7 @@
51
51
  "yaml": "^2.8.2"
52
52
  },
53
53
  "devDependencies": {
54
- "@anthropic-ai/sdk": "^0.123.0",
54
+ "@anthropic-ai/sdk": "^0.127.0",
55
55
  "@biomejs/biome": "^2.3.12",
56
56
  "@types/bun": "^1.3.6",
57
57
  "@types/js-yaml": "^4.0.9",
@@ -34,20 +34,22 @@ hash_int() {
34
34
  }
35
35
 
36
36
  # ---------------------------------------------------------------------------
37
- # shuffle_labels <seed> <vendor_id>... — seeded Fisher-Yates, then A/B/C in order.
37
+ # label_permutation <r-list> <vendor_id>... — apply a precomputed Fisher-Yates
38
+ # swap sequence and emit A/B/C JSON. <r-list> is a single space-joined string
39
+ # of decimal integers, one per swap step, ordered i=n-1..1 (the same order the
40
+ # loop below walks) — a STRING, not a bash array: a 1-vendor caller produces
41
+ # an EMPTY r-list, and under `set -u` a zero-element bash array is unbound on
42
+ # access (bash 3.2 quirk), whereas an empty string has no such trap.
38
43
  # ---------------------------------------------------------------------------
39
- shuffle_labels() {
40
- local seed="$1"; shift
41
- if [ "$#" -eq 0 ]; then
42
- printf 'anonymize.sh: shuffle_labels needs at least one vendor\n' >&2
43
- return 64
44
- fi
45
-
44
+ label_permutation() {
45
+ local r_list="$1"; shift
46
46
  local vendors=("$@")
47
47
  local n=${#vendors[@]}
48
48
  local i j r tmp
49
+ # shellcheck disable=SC2086 # intentional word-split of the r-list string
50
+ set -- $r_list
49
51
  for (( i = n - 1; i > 0; i-- )); do
50
- r=$(hash_int "$seed" "$i")
52
+ r="$1"; shift
51
53
  j=$(( r % (i + 1) ))
52
54
  tmp="${vendors[$i]}"
53
55
  vendors[$i]="${vendors[$j]}"
@@ -64,6 +66,160 @@ shuffle_labels() {
64
66
  printf '%s\n' "$out"
65
67
  }
66
68
 
69
+ # ---------------------------------------------------------------------------
70
+ # shuffle_labels <seed> <vendor_id>... — seeded Fisher-Yates, then A/B/C in order.
71
+ # ---------------------------------------------------------------------------
72
+ shuffle_labels() {
73
+ local seed="$1"; shift
74
+ if [ "$#" -eq 0 ]; then
75
+ printf 'anonymize.sh: shuffle_labels needs at least one vendor\n' >&2
76
+ return 64
77
+ fi
78
+
79
+ local n=$#
80
+ local i rs=''
81
+ for (( i = n - 1; i > 0; i-- )); do
82
+ rs+="$(hash_int "$seed" "$i") "
83
+ done
84
+
85
+ label_permutation "$rs" "$@"
86
+ }
87
+
88
+ # ---------------------------------------------------------------------------
89
+ # hash_hex_stream — batch form of hash_int's hex step: reads "<seed>:<counter>"
90
+ # lines on stdin, emits one 8-hex-char digest per line. `shasum` itself is a
91
+ # perl script wrapping Digest::SHA (`head -1 "$(which shasum)"` shows the
92
+ # shebang `#!/usr/bin/perl` — an ABSOLUTE path), but this function resolves
93
+ # `perl` from PATH instead of that fixed interpreter; the two usually
94
+ # coincide but are not guaranteed identical. What "no new dependency" means
95
+ # precisely: Digest::SHA is already required because shasum needs it, so
96
+ # calling perl directly here trades N subprocess forks — one `shasum`
97
+ # pipeline per Fisher-Yates swap — for one perl process handling every swap
98
+ # of every seed in a `--shuffle-many` batch (spec #1724).
99
+ # ---------------------------------------------------------------------------
100
+ hash_hex_stream() {
101
+ perl -MDigest::SHA=sha256_hex -lne 'print substr(sha256_hex($_), 0, 8)'
102
+ }
103
+
104
+ # ---------------------------------------------------------------------------
105
+ # shuffle_many <count> <vendor_id>... — batch form of calling
106
+ # `shuffle_labels "agora-shuffle-$k" <vendor_id>...` for k=1..count and
107
+ # concatenating the output, but with ALL hashing for the whole batch done by
108
+ # a SINGLE hash_hex_stream invocation instead of one `shasum` pipeline per
109
+ # swap per k (#1724 — CI timeout on 600 sequential shuffles). Emits one JSON
110
+ # map per line, same as the loop it replaces.
111
+ # ---------------------------------------------------------------------------
112
+ shuffle_many() {
113
+ local count="$1"; shift
114
+
115
+ # Validate count as a non-negative DECIMAL integer, rejecting anything a
116
+ # bare `[ "$count" -ge 1 ]` would either silently accept-as-wrong or blow
117
+ # up on later (measured against the original script, a70f6f47): "abc",
118
+ # "3.0", "0x3" and "1+1" all made `[` itself fail with "integer expression
119
+ # expected" while `shuffle_many` had ALREADY returned rc 0 with no output
120
+ # (the `||` short-circuits `[`'s failure into the same path as count=0);
121
+ # "08" reached the arithmetic `for` below and aborted there instead, with
122
+ # "value too great for base", because bash arithmetic context reads a
123
+ # leading-zero numeral as OCTAL and "8" is not a valid octal digit. Every
124
+ # one of those is a silent-or-confusing failure for a caller that passed a
125
+ # non-integer; reject them all up front with one explicit message instead.
126
+ #
127
+ # Design choices, both intentionally more conservative than the original:
128
+ # - Negative counts ("-3"): the original returned rc 0 with no output,
129
+ # identical to a real count of 0 — indistinguishable from "the batch
130
+ # was empty on purpose". Reject instead so a negative count can never
131
+ # be mistaken for a legitimate empty result (spec #1724 review M1).
132
+ # - Leading zeros ("08", "00"): reject rather than normalize (e.g. by
133
+ # stripping to "8"), because normalization would let two different
134
+ # caller-supplied strings silently produce the same batch size — an
135
+ # error is more honest than a silent reinterpretation. "0" itself
136
+ # (the literal zero, not zero-with-padding) stays valid and unchanged:
137
+ # rc 0, no output, exactly as before.
138
+ case "$count" in
139
+ 0) ;;
140
+ *[!0-9]*|'')
141
+ printf 'anonymize.sh: --shuffle-many count must be a non-negative integer\n' >&2
142
+ return 64
143
+ ;;
144
+ 0*)
145
+ printf 'anonymize.sh: --shuffle-many count must be a non-negative integer\n' >&2
146
+ return 64
147
+ ;;
148
+ esac
149
+
150
+ [ "$count" -ge 1 ] || return 0
151
+
152
+ if [ "$#" -eq 0 ]; then
153
+ # Zero vendors: reuse shuffle_labels for its existing error message and
154
+ # exit code (64) — under `set -e` this aborts the whole script on the
155
+ # first call, exactly as the original per-k loop did on its first
156
+ # iteration, regardless of how large `count` is.
157
+ shuffle_labels "agora-shuffle-1" "$@"
158
+ return
159
+ fi
160
+
161
+ local n=$#
162
+ local per_row=$(( n - 1 ))
163
+ local k
164
+
165
+ if [ "$per_row" -le 0 ]; then
166
+ # Single-vendor case: no Fisher-Yates swaps needed, so no hashing at all —
167
+ # the same short-circuit label_permutation already takes for an empty
168
+ # r-list, just repeated `count` times.
169
+ for (( k = 1; k <= count; k++ )); do
170
+ label_permutation '' "$@"
171
+ done
172
+ return
173
+ fi
174
+
175
+ # Build every "<seed>:<counter>" line for the whole batch up front, in the
176
+ # same nested order (k outer, i=n-1..1 inner) that the per-row consumption
177
+ # loop below expects, then hash them all in one perl process.
178
+ local i lines=''
179
+ for (( k = 1; k <= count; k++ )); do
180
+ for (( i = n - 1; i > 0; i-- )); do
181
+ lines+="agora-shuffle-$k:$i"$'\n'
182
+ done
183
+ done
184
+
185
+ local hexes
186
+ hexes=$(printf '%s' "$lines" | hash_hex_stream)
187
+
188
+ # hash_hex_stream runs under a pipeline, and `set -euo pipefail` only
189
+ # catches a non-zero EXIT from perl — it says nothing about the perl
190
+ # process emitting fewer lines than it was fed while still exiting 0
191
+ # (e.g. a truncating wrapper ahead of the real perl on PATH). A short
192
+ # stream here is silent data loss: label_permutation would just get
193
+ # called fewer times than `count`, with no error at all. Count the hex
194
+ # lines actually consumed and require BOTH that the total matches
195
+ # count*per_row (spec #1724 review L1) AND that the consume loop below
196
+ # ends with `seen -eq 0` — i.e. the last group closed exactly on a
197
+ # `per_row` boundary rather than being cut off mid-group. The second
198
+ # check is redundant with the first in every case this function can
199
+ # reach (count*per_row is itself a multiple of per_row, so a short total
200
+ # is caught either way), but it is cheap and it directly verifies the
201
+ # invariant the consume loop below depends on, rather than trusting the
202
+ # arithmetic that implies it.
203
+ local hex rs='' seen=0 total=0
204
+ while IFS= read -r hex; do
205
+ rs+="$(( 16#$hex )) "
206
+ seen=$(( seen + 1 ))
207
+ total=$(( total + 1 ))
208
+ if [ "$seen" -eq "$per_row" ]; then
209
+ label_permutation "$rs" "$@"
210
+ rs=''
211
+ seen=0
212
+ fi
213
+ done <<< "$hexes"
214
+
215
+ local expected=$(( count * per_row ))
216
+ if [ "$total" -ne "$expected" ] || [ "$seen" -ne 0 ]; then
217
+ printf 'anonymize.sh: --shuffle-many hash stream truncated: got %s hex digest(s), expected %s\n' \
218
+ "$total" "$expected" >&2
219
+ return 70
220
+ fi
221
+ }
222
+
67
223
  # ---------------------------------------------------------------------------
68
224
  # Fingerprint guard (spec §12-(1)). Case-insensitive; a hit aborts the session.
69
225
  # Three tiers, because "vendor name" and "ordinary English word" overlap:
@@ -464,10 +620,7 @@ main() {
464
620
  --shuffle-many)
465
621
  shift
466
622
  local count="$1"; shift
467
- local k
468
- for (( k = 1; k <= count; k++ )); do
469
- shuffle_labels "agora-shuffle-$k" "$@"
470
- done
623
+ shuffle_many "$count" "$@"
471
624
  ;;
472
625
  --build)
473
626
  shift
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.77",
2
+ "version": "1.1.79",
3
3
  "lastUpdated": "2026-09-03",
4
4
  "omcustomMinClaudeCode": "2.1.121",
5
5
  "omcustomMinClaudeCodeReason": "Sensitive-path direct Write/Edit on .claude/** under bypassPermissions (R010 deprecation, #1101)",