agent-composer 0.4.0 → 0.4.1
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/package.json
CHANGED
|
@@ -151,7 +151,7 @@ case "$TOOL" in
|
|
|
151
151
|
Edit|Update|Write|NotebookEdit \
|
|
152
152
|
| mcp__*__write_file | mcp__*__edit_file | mcp__*__bash \
|
|
153
153
|
| mcp__*__write | mcp__*__edit | mcp__*__exec)
|
|
154
|
-
emit_deny "
|
|
154
|
+
emit_deny "Expected — not a failure. Composer is routing this edit so changes stay reviewable: apply it with composer_code_cli (or composer_code_chain), or run /composer disable to edit directly. Bash inspection stays available."
|
|
155
155
|
;;
|
|
156
156
|
esac
|
|
157
157
|
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
# codexReview.preCommitHook.enabled are true, and the Codex review verdict
|
|
5
5
|
# reaches the configured blockOnSeverity threshold.
|
|
6
6
|
#
|
|
7
|
-
# Fail-open by default: reviewer/JQ/plugin
|
|
8
|
-
#
|
|
7
|
+
# Fail-open by default: reviewer/JQ/plugin failures warn to stderr and allow the
|
|
8
|
+
# commit unless codexReview.preCommitHook.failClosed is true. EXCEPTION: a review
|
|
9
|
+
# timeout/hang ALWAYS fails closed (blocks the commit) so a slow or hung reviewer
|
|
10
|
+
# cannot bypass the gate; raise preCommitHook.timeoutMs if reviews need more time.
|
|
9
11
|
# Config keys:
|
|
10
12
|
# codexReview.preCommitCommand, scope, base, model
|
|
11
13
|
# codexReview.preCommitHook.enabled, blockOnSeverity, timeoutMs, failClosed, maxConsecutiveBlocks
|
|
@@ -896,6 +898,10 @@ END_SECONDS="$(date +%s)"
|
|
|
896
898
|
DURATION_MS=$(( (END_SECONDS - START_SECONDS) * 1000 ))
|
|
897
899
|
|
|
898
900
|
if [[ "$REVIEW_STATUS" -eq 124 ]]; then
|
|
901
|
+
# A reviewer timeout/hang must NOT silently open the gate — otherwise a slow or
|
|
902
|
+
# hung reviewer could bypass review entirely. The timeout path always fails
|
|
903
|
+
# closed, regardless of the configured failClosed. If legitimate reviews need
|
|
904
|
+
# more time, raise codexReview.preCommitHook.timeoutMs instead.
|
|
899
905
|
fail_review "true" "review timed out after ${TIMEOUT_SECONDS}s" "$DURATION_MS" "hook_timeout"
|
|
900
906
|
fi
|
|
901
907
|
if [[ "$REVIEW_STATUS" -ne 0 ]]; then
|
|
@@ -84,6 +84,12 @@ lookups fast and cheap.
|
|
|
84
84
|
Research. Omit (`auto`) to let the script classify.
|
|
85
85
|
- It is ADVISORY: the tool never edits files. Hand its plan to
|
|
86
86
|
`composer_code_cli` for implementation, then `composer_review`.
|
|
87
|
+
- **Ground it in real code, never a paraphrase.** When asking Oracle to review
|
|
88
|
+
committed branch work, do NOT describe the diff in prose —
|
|
89
|
+
`scripts/oracle-pro-safe.sh` auto-attaches the real branch diff (`base...HEAD`)
|
|
90
|
+
plus changed-file contents. Pass `--base <branch>` (or set
|
|
91
|
+
`ORACLE_PRO_DIFF_BASE`) when auto-detection (main/master/develop) would pick
|
|
92
|
+
the wrong base. Reviewing from a summary yields `[inference]` false positives.
|
|
87
93
|
- Requires a one-time Oracle browser login and the `oraclePlanner` role in the
|
|
88
94
|
active config. Full answers persist under `.composer/oracle/answers/`
|
|
89
95
|
(gitignored); the tool returns a bounded summary.
|
|
@@ -22,6 +22,7 @@ Options:
|
|
|
22
22
|
--no-manual-login Do not pass --browser-manual-login even if supported
|
|
23
23
|
--model <model> Override selected Oracle model
|
|
24
24
|
--thinking <level> Override browser thinking level: light|standard|extended|heavy
|
|
25
|
+
--base <ref> Override branch-diff base ref for review-class modes
|
|
25
26
|
--research deep|off Override browser research mode
|
|
26
27
|
-p, --prompt <prompt> Prompt text
|
|
27
28
|
-h, --help
|
|
@@ -42,6 +43,9 @@ Environment overrides:
|
|
|
42
43
|
ORACLE_PRO_REATTACH_INTERVAL default: 2m
|
|
43
44
|
ORACLE_PRO_REATTACH_TIMEOUT default: 2m
|
|
44
45
|
ORACLE_PRO_ATTACHMENTS default: never (inline files; set to auto/bundle for large files)
|
|
46
|
+
ORACLE_PRO_DIFF_BASE default: auto-detect main/master/develop/origin HEAD
|
|
47
|
+
ORACLE_PRO_MAX_CHANGED_FILES default: 40
|
|
48
|
+
ORACLE_PRO_MAX_CHANGED_FILE_BYTES default: 120000
|
|
45
49
|
|
|
46
50
|
Secret file protection:
|
|
47
51
|
--file paths matching known secret patterns (.env, *.pem, *.key, id_rsa, .aws/credentials,
|
|
@@ -113,6 +117,7 @@ MODEL_OVERRIDE=""
|
|
|
113
117
|
THINKING_OVERRIDE=""
|
|
114
118
|
RESEARCH_OVERRIDE=""
|
|
115
119
|
FILES=()
|
|
120
|
+
DIFF_BASE="${ORACLE_PRO_DIFF_BASE:-}"
|
|
116
121
|
|
|
117
122
|
while [[ $# -gt 0 ]]; do
|
|
118
123
|
case "$1" in
|
|
@@ -130,6 +135,8 @@ while [[ $# -gt 0 ]]; do
|
|
|
130
135
|
--model=*) MODEL_OVERRIDE="${1#*=}"; shift ;;
|
|
131
136
|
--thinking) THINKING_OVERRIDE="${2:-}"; shift 2 ;;
|
|
132
137
|
--thinking=*) THINKING_OVERRIDE="${1#*=}"; shift ;;
|
|
138
|
+
--base) DIFF_BASE="${2:-}"; shift 2 ;;
|
|
139
|
+
--base=*) DIFF_BASE="${1#*=}"; shift ;;
|
|
133
140
|
--research) RESEARCH_OVERRIDE="${2:-}"; shift 2 ;;
|
|
134
141
|
--research=*) RESEARCH_OVERRIDE="${1#*=}"; shift ;;
|
|
135
142
|
-p|--prompt) PROMPT="${2:-}"; shift 2 ;;
|
|
@@ -185,7 +192,6 @@ STANDARD_THINKING="${ORACLE_PRO_STANDARD_THINKING:-standard}"
|
|
|
185
192
|
DEEP_THINKING="${ORACLE_PRO_DEEP_THINKING:-extended}"
|
|
186
193
|
RESEARCH_MODE="off"
|
|
187
194
|
DEFAULT_STRATEGY="select"
|
|
188
|
-
ATTACHMENTS_MODE="${ORACLE_PRO_ATTACHMENTS:-never}"
|
|
189
195
|
|
|
190
196
|
case "$MODE" in
|
|
191
197
|
quick) MODEL="$QUICK_MODEL"; THINKING="$QUICK_THINKING"; DEFAULT_STRATEGY="current" ;;
|
|
@@ -198,6 +204,30 @@ esac
|
|
|
198
204
|
[[ -z "$THINKING_OVERRIDE" ]] || THINKING="$THINKING_OVERRIDE"
|
|
199
205
|
[[ -z "$RESEARCH_OVERRIDE" ]] || RESEARCH_MODE="$RESEARCH_OVERRIDE"
|
|
200
206
|
|
|
207
|
+
# Delivery: quick/standard stay inline (fast, no upload-timeout risk); review-class
|
|
208
|
+
# modes default to `auto` (inline up to oracle's ~60k-char limit, then upload) so large
|
|
209
|
+
# branch diffs are no longer silently truncated. Override with ORACLE_PRO_ATTACHMENTS.
|
|
210
|
+
ATTACHMENTS_MODE="${ORACLE_PRO_ATTACHMENTS:-}"
|
|
211
|
+
if [[ -z "$ATTACHMENTS_MODE" ]]; then
|
|
212
|
+
case "$MODE" in
|
|
213
|
+
quick|standard) ATTACHMENTS_MODE="never" ;;
|
|
214
|
+
*) ATTACHMENTS_MODE="auto" ;;
|
|
215
|
+
esac
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# ChatGPT's Pro model auto-selects "Pro Extended"; its picker no longer exposes a
|
|
219
|
+
# separate thinking-time submenu, so --browser-thinking-time errors out with
|
|
220
|
+
# "Thinking time: menu not found for pro (requested ...)" and oracle exits 1.
|
|
221
|
+
# The flag is redundant for the Pro model, so skip it there. Override with
|
|
222
|
+
# ORACLE_PRO_FORCE_THINKING_FLAG=1 if a future oracle/UI restores the menu.
|
|
223
|
+
case "$MODEL" in
|
|
224
|
+
*pro*)
|
|
225
|
+
if [[ "${ORACLE_PRO_FORCE_THINKING_FLAG:-0}" != "1" ]]; then
|
|
226
|
+
USE_THINKING_FLAG=0
|
|
227
|
+
fi
|
|
228
|
+
;;
|
|
229
|
+
esac
|
|
230
|
+
|
|
201
231
|
OUT_DIR="${ORACLE_PRO_OUTPUT_DIR:-.composer/oracle/answers}"
|
|
202
232
|
CTX_DIR="${ORACLE_PRO_CONTEXT_DIR:-.composer/oracle/context}"
|
|
203
233
|
mkdir -p "$OUT_DIR" "$CTX_DIR"
|
|
@@ -288,6 +318,31 @@ write_context_file() {
|
|
|
288
318
|
if [[ -s "$path" ]]; then AUTO_FILES+=("$path"); fi
|
|
289
319
|
}
|
|
290
320
|
|
|
321
|
+
detect_diff_base() {
|
|
322
|
+
local b
|
|
323
|
+
if [[ -n "$DIFF_BASE" ]]; then printf '%s' "$DIFF_BASE"; return; fi
|
|
324
|
+
for b in main master develop; do
|
|
325
|
+
git rev-parse --verify --quiet "refs/heads/$b" >/dev/null 2>&1 && { printf '%s' "$b"; return; }
|
|
326
|
+
done
|
|
327
|
+
for b in origin/main origin/master origin/develop; do
|
|
328
|
+
git rev-parse --verify --quiet "refs/remotes/$b" >/dev/null 2>&1 && { printf '%s' "$b"; return; }
|
|
329
|
+
done
|
|
330
|
+
git symbolic-ref --quiet refs/remotes/origin/HEAD 2>/dev/null | sed 's#refs/remotes/##' || true
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
# Populates the global SECRET_EXCLUDES array with :(exclude,literal)<path> pathspecs
|
|
334
|
+
# for every changed file that is_secret_file rejects, giving git-diff patch generation
|
|
335
|
+
# the SAME denylist coverage as explicit --file uploads. Args: optional git diff range.
|
|
336
|
+
build_secret_excludes() {
|
|
337
|
+
SECRET_EXCLUDES=()
|
|
338
|
+
[[ "${ORACLE_PRO_ALLOW_SECRET_FILES:-0}" == "1" ]] && return 0
|
|
339
|
+
local cf
|
|
340
|
+
while IFS= read -r cf; do
|
|
341
|
+
[[ -n "$cf" ]] || continue
|
|
342
|
+
if is_secret_file "$cf"; then SECRET_EXCLUDES+=(":(exclude,literal)$cf"); fi
|
|
343
|
+
done < <(git diff --name-only "$@" 2>/dev/null)
|
|
344
|
+
}
|
|
345
|
+
|
|
291
346
|
if [[ "$AUTO_CONTEXT" -eq 1 ]]; then
|
|
292
347
|
# Authority class B — current policy/context (safe as source-of-truth).
|
|
293
348
|
policy_files=(CLAUDE.md composer.config.json docs/STATUS.md)
|
|
@@ -318,12 +373,52 @@ if [[ "$AUTO_CONTEXT" -eq 1 ]]; then
|
|
|
318
373
|
write_context_file "git-status.txt" "git status --short"
|
|
319
374
|
write_context_file "git-diff-stat.txt" "git diff --stat"
|
|
320
375
|
if [[ "$MODE" != "quick" && "$MODE" != "standard" ]]; then
|
|
321
|
-
|
|
376
|
+
build_secret_excludes
|
|
377
|
+
wt_patch="$CTX_DIR/$SLUG.git-diff.patch"
|
|
378
|
+
git diff -- . ':(exclude).env' ':(exclude).env.*' ':(exclude)*.pem' ':(exclude)*.key' ':(exclude)*.p12' \
|
|
379
|
+
${SECRET_EXCLUDES[@]+"${SECRET_EXCLUDES[@]}"} 2>/dev/null \
|
|
380
|
+
| sed -E -e '/(api[_-]?key|secret|token|passwd|password|credential|authorization|client[_-]?secret|access[_-]?token|refresh[_-]?token|private[_-]?key)[^a-z0-9]{0,4}[:=]/Id' -e '/bearer[[:space:]]+[a-z0-9._-]{6,}/Id' \
|
|
381
|
+
| head -c 200000 > "$wt_patch" 2>/dev/null || true
|
|
382
|
+
[[ -s "$wt_patch" ]] && AUTO_FILES+=("$wt_patch")
|
|
322
383
|
fi
|
|
323
384
|
# Exact installed top-level deps (package.json shows ranges, not the installed tree).
|
|
324
385
|
if [[ "$MODE" != "quick" && "$MODE" != "standard" ]] && [[ -f package.json ]]; then
|
|
325
386
|
write_context_file "deps.txt" "npm ls --depth=0 2>/dev/null || true"
|
|
326
387
|
fi
|
|
388
|
+
if [[ "$MODE" != "quick" && "$MODE" != "standard" ]]; then
|
|
389
|
+
DIFF_BASE_RESOLVED="$(detect_diff_base)"
|
|
390
|
+
# Defense-in-depth: a git ref can legally contain shell metacharacters
|
|
391
|
+
# (`;`, `$()`, backticks). Since the ref is later interpolated into commands,
|
|
392
|
+
# reject anything outside a safe charset and forbid a leading dash (git option
|
|
393
|
+
# injection) before use.
|
|
394
|
+
if [[ -n "$DIFF_BASE_RESOLVED" && ! "$DIFF_BASE_RESOLVED" =~ ^[A-Za-z0-9._/][A-Za-z0-9._/-]*$ ]]; then
|
|
395
|
+
warn "ignoring unsafe diff-base ref (disallowed characters): $DIFF_BASE_RESOLVED"
|
|
396
|
+
DIFF_BASE_RESOLVED=""
|
|
397
|
+
fi
|
|
398
|
+
CUR_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo HEAD)"
|
|
399
|
+
if [[ -n "$DIFF_BASE_RESOLVED" && "$CUR_BRANCH" != "$DIFF_BASE_RESOLVED" ]] \
|
|
400
|
+
&& git rev-parse --verify --quiet "$DIFF_BASE_RESOLVED" >/dev/null 2>&1; then
|
|
401
|
+
# The committed branch diff vs its base is the REAL review target (working-tree diff
|
|
402
|
+
# is empty once work is committed). This is the primary accuracy fix.
|
|
403
|
+
build_secret_excludes "$DIFF_BASE_RESOLVED...HEAD"
|
|
404
|
+
base_patch="$CTX_DIR/$SLUG.branch-diff.patch"
|
|
405
|
+
git diff "$DIFF_BASE_RESOLVED...HEAD" -- . ':(exclude).env' ':(exclude).env.*' ':(exclude)*.pem' ':(exclude)*.key' ':(exclude)*.p12' \
|
|
406
|
+
${SECRET_EXCLUDES[@]+"${SECRET_EXCLUDES[@]}"} 2>/dev/null \
|
|
407
|
+
| sed -E -e '/(api[_-]?key|secret|token|passwd|password|credential|authorization|client[_-]?secret|access[_-]?token|refresh[_-]?token|private[_-]?key)[^a-z0-9]{0,4}[:=]/Id' -e '/bearer[[:space:]]+[a-z0-9._-]{6,}/Id' \
|
|
408
|
+
| head -c 400000 > "$base_patch" 2>/dev/null || true
|
|
409
|
+
[[ -s "$base_patch" ]] && AUTO_FILES+=("$base_patch")
|
|
410
|
+
write_context_file "branch-diff-stat.txt" "git diff ${DIFF_BASE_RESOLVED}...HEAD --stat"
|
|
411
|
+
# Attach the full content of changed files (enclosing scope for the diff hunks),
|
|
412
|
+
# capped by count and per-file size, secret-filtered.
|
|
413
|
+
while IFS= read -r changed; do
|
|
414
|
+
[[ -n "$changed" && -f "$changed" ]] || continue
|
|
415
|
+
if is_secret_file "$changed" && [[ "${ORACLE_PRO_ALLOW_SECRET_FILES:-0}" != "1" ]]; then continue; fi
|
|
416
|
+
csz="$(wc -c < "$changed" 2>/dev/null | tr -d ' ')"
|
|
417
|
+
[[ -n "$csz" && "$csz" -le "${ORACLE_PRO_MAX_CHANGED_FILE_BYTES:-120000}" ]] || continue
|
|
418
|
+
AUTO_FILES+=("$changed")
|
|
419
|
+
done < <(git diff --name-only "${DIFF_BASE_RESOLVED}...HEAD" -- . ':(exclude).env' ':(exclude).env.*' 2>/dev/null | head -n "${ORACLE_PRO_MAX_CHANGED_FILES:-40}")
|
|
420
|
+
fi
|
|
421
|
+
fi
|
|
327
422
|
fi
|
|
328
423
|
fi
|
|
329
424
|
|
|
@@ -351,6 +446,9 @@ fi
|
|
|
351
446
|
add_supported_flag ARGS --browser-timeout "${ORACLE_PRO_TIMEOUT:-20m}"
|
|
352
447
|
add_supported_flag ARGS --browser-input-timeout "${ORACLE_PRO_INPUT_TIMEOUT:-60s}"
|
|
353
448
|
add_supported_flag ARGS --browser-attachments "$ATTACHMENTS_MODE"
|
|
449
|
+
if [[ "$ATTACHMENTS_MODE" != "never" ]]; then
|
|
450
|
+
add_supported_flag ARGS --browser-bundle-format "${ORACLE_PRO_BUNDLE_FORMAT:-text}"
|
|
451
|
+
fi
|
|
354
452
|
add_supported_flag ARGS --browser-auto-reattach-delay "${ORACLE_PRO_REATTACH_DELAY:-30s}"
|
|
355
453
|
add_supported_flag ARGS --browser-auto-reattach-interval "${ORACLE_PRO_REATTACH_INTERVAL:-2m}"
|
|
356
454
|
add_supported_flag ARGS --browser-auto-reattach-timeout "${ORACLE_PRO_REATTACH_TIMEOUT:-2m}"
|
|
@@ -437,14 +535,17 @@ Repo-state hash: ${repo_state_hash}
|
|
|
437
535
|
Runtime: node=${node_ver} npm=${npm_ver} os=${os_ver} arch=${arch_ver}
|
|
438
536
|
Task: ${MODE}
|
|
439
537
|
Authority order:
|
|
440
|
-
A. Live source-of-truth: ${SLUG}.manifest.json, ${SLUG}.git-status.txt, ${SLUG}.git-diff.patch, ${SLUG}.deps.txt, targeted source/tests
|
|
538
|
+
A. Live source-of-truth: ${SLUG}.manifest.json, ${SLUG}.git-status.txt, ${SLUG}.git-diff.patch, ${SLUG}.branch-diff.patch, ${SLUG}.deps.txt, changed source files, targeted source/tests
|
|
441
539
|
B. Current policy/context: CLAUDE.md, composer.config.json, docs/STATUS.md, relevant ADRs
|
|
442
540
|
C. Background/history: README.md, AGENTS.md
|
|
443
541
|
Rules:
|
|
444
542
|
- Treat class A as authoritative for the local repo. If A conflicts with B or C, A wins.
|
|
543
|
+
- The attached files are the ONLY authoritative source for any code-level claim. Any description of the code in the TASK below is a hint about what to review, NOT source of truth — never treat prose as code.
|
|
445
544
|
- Ignore prior chat memory, project memory, and earlier attachments if they conflict with this snapshot.
|
|
446
545
|
- For each substantive claim, tag it [attached], [runtime], [web], or [inference].
|
|
447
546
|
- Cite attached claims with file path and line span.
|
|
547
|
+
- For EACH finding: first quote the exact supporting line(s) verbatim from an attached file as \`path:line\`, THEN state the finding. If you cannot quote supporting lines from the attached files, label it "INSUFFICIENT EVIDENCE — not in provided context" and do not raise it as a blocker.
|
|
548
|
+
- Do not infer a bug from an absent detail; absence of code in the attachments means unknown, not broken.
|
|
448
549
|
- For current API/library claims not proven by attached files, verify on the web against primary docs.
|
|
449
550
|
- If evidence is insufficient, say: "unknown from provided context".
|
|
450
551
|
EOF
|