mm scripts: default to MiniMax-M3.1-Flash-Preview with per-script effort
Flash is the default model; --m3 falls back to M3, --effort overrides. Defaults: max (review-minimax, review-loop, mm-worktree-task), medium (explore), low (ci-triage). ask-minimax-run applies MINIMAX_EFFORT to Flash models when --effort is not passed. Bump stale fixture date.
This commit is contained in:
@@ -26,4 +26,15 @@ export CLAUDE_CONFIG_DIR="$MINIMAX_DIR"
|
||||
export CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1
|
||||
export COLORTERM=truecolor
|
||||
|
||||
# MINIMAX_EFFORT (provider.env) applies to Flash models only, unless the caller passed --effort.
|
||||
model="${ANTHROPIC_MODEL:-}"; has_effort=0; prev=""
|
||||
for a in "$@"; do
|
||||
[[ "$prev" == "--model" ]] && model="$a"
|
||||
[[ "$a" == "--effort" ]] && has_effort=1
|
||||
prev="$a"
|
||||
done
|
||||
if [[ -n "${MINIMAX_EFFORT:-}" && $has_effort -eq 0 && "$model" == *Flash* ]]; then
|
||||
set -- --effort "$MINIMAX_EFFORT" "$@"
|
||||
fi
|
||||
|
||||
exec claude "$@"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Triage a failing Gitea Actions run in a MiniMax M3 sub-session.
|
||||
# Triage a failing Gitea Actions run in a MiniMax sub-session.
|
||||
# Fetches logs via gitea-agent-companion (token stays inside gac), redacts
|
||||
# credential-shaped content, and has MiniMax write a structured triage file.
|
||||
# Spec: specs/ci-triage-minimax-run.spec.md. Used by /ci-triage-minimax.
|
||||
@@ -7,7 +7,7 @@
|
||||
# Usage:
|
||||
# ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>]
|
||||
# [--out <triage-file>] [--tail N] [--max-turns N] [--timeout SECS]
|
||||
# [--dryrun|-n]
|
||||
# [--dryrun|-n] [--m3] [--effort low|medium|high|xhigh|max]
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 triage file written
|
||||
@@ -25,6 +25,8 @@ OUT_FILE=""
|
||||
TAIL_LINES=2000
|
||||
MAX_TURNS=25
|
||||
TIMEOUT_SECS=300
|
||||
USE_M3=0
|
||||
EFFORT_ARG=""
|
||||
DRYRUN=0
|
||||
CRED_PATTERN='ghp_[A-Za-z0-9]|glpat-|x-access-token:|Authorization:|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}'
|
||||
|
||||
@@ -37,11 +39,15 @@ while [[ $# -gt 0 ]]; do
|
||||
--tail) TAIL_LINES="$2"; shift 2 ;;
|
||||
--max-turns) MAX_TURNS="$2"; shift 2 ;;
|
||||
--timeout) TIMEOUT_SECS="$2"; shift 2 ;;
|
||||
--m3) USE_M3=1; shift ;;
|
||||
--effort) EFFORT_ARG="$2"; shift 2 ;;
|
||||
--dryrun|-n) DRYRUN=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "error: unknown argument '$1'" >&2; usage >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3[1m]"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-low}"; fi
|
||||
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { echo "error: --effort must be low|medium|high|xhigh|max" >&2; exit 1; }
|
||||
|
||||
# --- CT-1 preflight -----------------------------------------------------------
|
||||
[[ "$REPO" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]] || { echo "error: --repo must be owner/repo" >&2; exit 1; }
|
||||
@@ -82,7 +88,7 @@ if [[ "$DRYRUN" -eq 1 ]]; then
|
||||
echo "-- failing step --"
|
||||
echo "<run-logs not fetched in dryrun>"
|
||||
echo "-- sub-session command --"
|
||||
echo "cd <workdir> && timeout $TIMEOUT_SECS ask-minimax-run --model 'MiniMax-M3[1m]'" \
|
||||
echo "cd <workdir> && timeout $TIMEOUT_SECS ask-minimax-run --model '$MODEL'${EFFORT:+ --effort $EFFORT}" \
|
||||
"--permission-mode default --allowedTools 'Read,Glob,Grep,Write'" \
|
||||
"--disallowedTools 'Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch'" \
|
||||
"--max-turns $MAX_TURNS --output-format json --add-dir $OUT_DIR -p < prompt.txt"
|
||||
@@ -163,7 +169,7 @@ run_once() {
|
||||
return 0
|
||||
fi
|
||||
( cd "$WORK_DIR" && timeout "$TIMEOUT_SECS" ask-minimax-run \
|
||||
--model "MiniMax-M3[1m]" \
|
||||
--model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
|
||||
--permission-mode default \
|
||||
--allowedTools "Read,Glob,Grep,Write" \
|
||||
--disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run a read-only codebase exploration sweep in a MiniMax M3 sub-session.
|
||||
# Run a read-only codebase exploration sweep in a MiniMax sub-session.
|
||||
# Wraps ask-minimax-run with the hardening the exploration case needs:
|
||||
# - --add-dir per search root (paths outside cwd are otherwise denied)
|
||||
# - secrets-root refusal + skip-list in the prompt preamble
|
||||
@@ -11,7 +11,8 @@
|
||||
# Usage:
|
||||
# explore-minimax-run --root <path> [--root <path> ...] \
|
||||
# --prompt-file <question-file> --out <result-file> \
|
||||
# [--breadth medium|very-thorough] [--max-turns N] [--timeout SECS]
|
||||
# [--breadth medium|very-thorough] [--max-turns N] [--timeout SECS] \
|
||||
# [--m3] [--effort low|medium|high|xhigh|max]
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 answer written to --out
|
||||
@@ -20,7 +21,7 @@
|
||||
# 3 ran but answer is empty or carries no file:line citations — fall back to an Explore agent
|
||||
set -euo pipefail
|
||||
|
||||
usage() { grep '^#' "$0" | sed 's/^# \{0,1\}//' | sed -n '2,20p'; }
|
||||
usage() { grep '^#' "$0" | sed 's/^# \{0,1\}//' | sed -n '2,21p'; }
|
||||
|
||||
ROOTS=()
|
||||
PROMPT_FILE=""
|
||||
@@ -28,6 +29,8 @@ OUT_FILE=""
|
||||
BREADTH="medium"
|
||||
MAX_TURNS=40
|
||||
TIMEOUT_SECS=540
|
||||
USE_M3=0
|
||||
EFFORT_ARG=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -37,10 +40,14 @@ while [[ $# -gt 0 ]]; do
|
||||
--breadth) BREADTH="$2"; shift 2 ;;
|
||||
--max-turns) MAX_TURNS="$2"; shift 2 ;;
|
||||
--timeout) TIMEOUT_SECS="$2"; shift 2 ;;
|
||||
--m3) USE_M3=1; shift ;;
|
||||
--effort) EFFORT_ARG="$2"; shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "error: unknown argument '$1'" >&2; usage >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-medium}"; fi
|
||||
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { echo "error: --effort must be low|medium|high|xhigh|max" >&2; exit 1; }
|
||||
|
||||
[[ ${#ROOTS[@]} -gt 0 ]] || { echo "error: at least one --root required" >&2; exit 1; }
|
||||
[[ -n "$PROMPT_FILE" && -f "$PROMPT_FILE" ]] || { echo "error: --prompt-file missing or not a file" >&2; exit 1; }
|
||||
@@ -109,7 +116,7 @@ run_once() {
|
||||
# --disallowedTools: the minimax profile defaults to acceptEdits and allows
|
||||
# Edit(/tmp/**)/WebFetch at user level; deny beats allow.
|
||||
timeout "$TIMEOUT_SECS" ask-minimax-run \
|
||||
--model MiniMax-M3 \
|
||||
--model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
|
||||
--permission-mode default \
|
||||
--allowedTools "Read,Glob,Grep" \
|
||||
--disallowedTools "Write,Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Launch a MiniMax M3 implementation sub-session in an isolated git worktree,
|
||||
# Launch a MiniMax implementation sub-session in an isolated git worktree,
|
||||
# with the prompt assembled from a planner work item. See specs/mm-worktree-task.spec.md.
|
||||
set -euo pipefail
|
||||
|
||||
@@ -15,7 +15,7 @@ usage() {
|
||||
cat <<'EOF'
|
||||
Usage: mm-worktree-task <item-uuid> [OPTIONS]
|
||||
|
||||
Launch a MiniMax M3 implementation sub-session (via ask-minimax-run) in an
|
||||
Launch a MiniMax implementation sub-session (via ask-minimax-run) in an
|
||||
isolated git worktree of the current repo, with the prompt assembled from a
|
||||
planner work item.
|
||||
|
||||
@@ -33,6 +33,9 @@ Options:
|
||||
--docs all|recent|none Which item documents to bundle (default: recent)
|
||||
--tools "<list>" Extra --allowedTools entries (comma-separated)
|
||||
--timeout <secs> Sub-session timeout (default: 1800)
|
||||
--m3 Use MiniMax-M3[1m] instead of the default MiniMax-M3.1-Flash-Preview
|
||||
--effort <level> Thinking depth low|medium|high|xhigh|max (default: max;
|
||||
not sent with --m3 unless given)
|
||||
--gate "<command>" Re-run this command in the worktree yourself, after
|
||||
the sub-session exits, against its LAST commit.
|
||||
Appended as a "Supervisor gate" section in the
|
||||
@@ -68,6 +71,8 @@ BASE="main"
|
||||
DOCS="recent"
|
||||
EXTRA_TOOLS=""
|
||||
TIMEOUT=1800
|
||||
USE_M3=0
|
||||
EFFORT_ARG=""
|
||||
GATE=""
|
||||
GATE_TIMEOUT=900
|
||||
UPLOAD=0
|
||||
@@ -87,6 +92,8 @@ while [[ $# -gt 0 ]]; do
|
||||
--gate) GATE="$2"; shift 2 ;;
|
||||
--gate-timeout) GATE_TIMEOUT="$2"; shift 2 ;;
|
||||
--context) CP_CONTEXT="$2"; shift 2 ;;
|
||||
--m3) USE_M3=1; shift ;;
|
||||
--effort) EFFORT_ARG="$2"; shift 2 ;;
|
||||
--upload) UPLOAD=1; shift ;;
|
||||
--collect) COLLECT=1; shift ;;
|
||||
--dryrun|-n) DRYRUN=1; shift ;;
|
||||
@@ -98,6 +105,9 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3[1m]"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-max}"; fi
|
||||
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { err "--effort must be low|medium|high|xhigh|max"; exit 1; }
|
||||
|
||||
case "$DOCS" in all|recent|none) ;; *) err "--docs must be all|recent|none"; exit 1 ;; esac
|
||||
|
||||
if [[ -z "$UUID" ]]; then
|
||||
@@ -374,7 +384,7 @@ EOF
|
||||
|
||||
PROMPT_CONTENT="$(build_prompt)"
|
||||
|
||||
CMD="cd ${WORKTREE} && setsid nohup timeout ${TIMEOUT} ask-minimax-run --model \"MiniMax-M3[1m]\" --allowedTools \"${ALLOWLIST}\" --permission-mode acceptEdits --add-dir ${REPORT_DIR} -p \"\$(cat ${PROMPT_FILE})\" > ${STDOUT_FILE} 2>&1"
|
||||
CMD="cd ${WORKTREE} && setsid nohup timeout ${TIMEOUT} ask-minimax-run --model \"${MODEL}\"${EFFORT:+ --effort ${EFFORT}} --allowedTools \"${ALLOWLIST}\" --permission-mode acceptEdits --add-dir ${REPORT_DIR} -p \"\$(cat ${PROMPT_FILE})\" > ${STDOUT_FILE} 2>&1"
|
||||
|
||||
if [[ $DRYRUN -eq 1 ]]; then
|
||||
echo "[dryrun] mm-worktree-task — no changes will be made"
|
||||
@@ -510,7 +520,7 @@ info "launching ask-minimax-run (detached, timeout ${TIMEOUT}s)"
|
||||
cd "$WORKTREE"
|
||||
start=$(date +%s)
|
||||
set +e
|
||||
setsid nohup timeout "$TIMEOUT" ask-minimax-run --model "MiniMax-M3[1m]" \
|
||||
setsid nohup timeout "$TIMEOUT" ask-minimax-run --model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
|
||||
--allowedTools "$ALLOWLIST" --permission-mode acceptEdits \
|
||||
--add-dir "$REPORT_DIR" -p "$(cat "$PROMPT_FILE")" \
|
||||
> "$STDOUT_FILE" 2>&1
|
||||
|
||||
@@ -17,6 +17,7 @@ Usage:
|
||||
review-loop-run launch --kind <plan|spec|tests|code|verify> --name <tag> [--round N]
|
||||
--file <path> [--file <path> ...] [--context "<text>"]
|
||||
[--prev <result.md>] [--tools "<extra>"] [--timeout <secs>]
|
||||
[--m3] [--effort low|medium|high|xhigh|max]
|
||||
[--project <repo>] [--dryrun|-n]
|
||||
review-loop-run status [--name <tag>] [--round N] [--project <repo>]
|
||||
review-loop-run counts <result.md>
|
||||
@@ -238,7 +239,7 @@ kind_tools() {
|
||||
}
|
||||
|
||||
cmd_launch() {
|
||||
local kind="" name="" round=1 context="" prev="" tools="" timeout=1500 project="" dryrun=0
|
||||
local kind="" name="" round=1 context="" prev="" tools="" timeout=1500 project="" dryrun=0 use_m3=0 effort_arg=""
|
||||
local -a files=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -251,11 +252,15 @@ cmd_launch() {
|
||||
--tools) tools="$2"; shift 2 ;;
|
||||
--timeout) timeout="$2"; shift 2 ;;
|
||||
--project) project="$2"; shift 2 ;;
|
||||
--m3) use_m3=1; shift ;;
|
||||
--effort) effort_arg="$2"; shift 2 ;;
|
||||
--dryrun|-n) dryrun=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) die "unknown option: $1" 2 ;;
|
||||
esac
|
||||
done
|
||||
if [[ $use_m3 -eq 1 ]]; then model="MiniMax-M3"; effort="$effort_arg"; else model="MiniMax-M3.1-Flash-Preview"; effort="${effort_arg:-max}"; fi
|
||||
[[ -z "$effort" || "$effort" =~ ^(low|medium|high|xhigh|max)$ ]] || die "--effort must be low|medium|high|xhigh|max" 2
|
||||
[[ " $KINDS " == *" $kind "* ]] || die "--kind must be one of: $KINDS" 2
|
||||
[[ "$name" =~ ^[A-Za-z0-9._-]+$ ]] || die "--name must match ^[A-Za-z0-9._-]+\$" 2
|
||||
[[ "$round" =~ ^[0-9]+$ ]] || die "--round must be an integer" 2
|
||||
@@ -323,7 +328,7 @@ EOF
|
||||
launch_body=$(cat <<EOF
|
||||
#!/usr/bin/env bash
|
||||
cd "$repo" || exit 1
|
||||
timeout ${timeout} ask-minimax-run --model MiniMax-M3 --allowedTools "$allow" --permission-mode acceptEdits -p "\$(cat "$prompt")" > "$stdout" 2>&1
|
||||
timeout ${timeout} ask-minimax-run --model ${model}${effort:+ --effort ${effort}} --allowedTools "$allow" --permission-mode acceptEdits -p "\$(cat "$prompt")" > "$stdout" 2>&1
|
||||
echo "exit=\$?" >> "$stdout"
|
||||
EOF
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# First-pass code review of a git branch in a MiniMax M3 sub-session.
|
||||
# First-pass code review of a git branch in a MiniMax sub-session.
|
||||
# The wrapper materialises the diff/log itself (the sub-session gets no Bash),
|
||||
# runs MiniMax read-only except for one findings file, and gates the result.
|
||||
# Spec: specs/review-minimax-run.spec.md. Used by /review-minimax; safe directly.
|
||||
@@ -7,7 +7,7 @@
|
||||
# Usage:
|
||||
# review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>]
|
||||
# [--profile agent-runtimes] [--max-diff-lines N] [--max-turns N]
|
||||
# [--timeout SECS] [--dryrun|-n]
|
||||
# [--timeout SECS] [--dryrun|-n] [--m3] [--effort low|medium|high|xhigh|max]
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 findings file written (may contain "NO FINDINGS")
|
||||
@@ -25,6 +25,8 @@ PROFILE=""
|
||||
MAX_DIFF_LINES=6000
|
||||
MAX_TURNS=40
|
||||
TIMEOUT_SECS=540
|
||||
USE_M3=0
|
||||
EFFORT_ARG=""
|
||||
DRYRUN=0
|
||||
# RM-3: credential-shaped content in the diff aborts the review outright.
|
||||
CRED_PATTERN='ghp_[A-Za-z0-9]|glpat-|x-access-token:|Authorization:|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}'
|
||||
@@ -38,11 +40,15 @@ while [[ $# -gt 0 ]]; do
|
||||
--max-diff-lines) MAX_DIFF_LINES="$2"; shift 2 ;;
|
||||
--max-turns) MAX_TURNS="$2"; shift 2 ;;
|
||||
--timeout) TIMEOUT_SECS="$2"; shift 2 ;;
|
||||
--m3) USE_M3=1; shift ;;
|
||||
--effort) EFFORT_ARG="$2"; shift 2 ;;
|
||||
--dryrun|-n) DRYRUN=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "error: unknown argument '$1'" >&2; usage >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3[1m]"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-max}"; fi
|
||||
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { echo "error: --effort must be low|medium|high|xhigh|max" >&2; exit 1; }
|
||||
|
||||
# --- RM-1 preflight -----------------------------------------------------------
|
||||
[[ -n "$WORKTREE" ]] || { echo "error: --worktree required" >&2; exit 1; }
|
||||
@@ -172,7 +178,7 @@ if [[ "$DRYRUN" -eq 1 ]]; then
|
||||
echo "-- prompt --"
|
||||
cat "$FULL_PROMPT"
|
||||
echo "-- command --"
|
||||
echo "cd $WORK_DIR && timeout $TIMEOUT_SECS ask-minimax-run --model 'MiniMax-M3[1m]'" \
|
||||
echo "cd $WORK_DIR && timeout $TIMEOUT_SECS ask-minimax-run --model '$MODEL'${EFFORT:+ --effort $EFFORT}" \
|
||||
"--permission-mode default --allowedTools 'Read,Glob,Grep,Write'" \
|
||||
"--disallowedTools 'Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch'" \
|
||||
"--max-turns $MAX_TURNS --output-format json --add-dir $WORKTREE --add-dir $OUT_DIR -p < prompt.txt"
|
||||
@@ -189,7 +195,7 @@ run_once() {
|
||||
return 0
|
||||
fi
|
||||
( cd "$WORK_DIR" && timeout "$TIMEOUT_SECS" ask-minimax-run \
|
||||
--model "MiniMax-M3[1m]" \
|
||||
--model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
|
||||
--permission-mode default \
|
||||
--allowedTools "Read,Glob,Grep,Write" \
|
||||
--disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" \
|
||||
|
||||
@@ -8,7 +8,7 @@ Triage a failing Gitea Actions run in a MiniMax M3 sub-session: fetch the run's
|
||||
|
||||
```
|
||||
ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>] \
|
||||
[--out <triage-file>] [--tail N] [--max-turns N] [--timeout SECS] [--dryrun|-n]
|
||||
[--out <triage-file>] [--tail N] [--max-turns N] [--timeout SECS] [--dryrun|-n] [--m3] [--effort LEVEL]
|
||||
```
|
||||
|
||||
| Flag | Default | Description |
|
||||
@@ -20,6 +20,8 @@ ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>] \
|
||||
| `--tail` | 2000 | Log lines fetched (gac `--tail`) |
|
||||
| `--max-turns` | 25 | Sub-session turn cap |
|
||||
| `--timeout` | 300 | Internal timeout (logs-only task; well under the harness Bash 600s cap) |
|
||||
| `--m3` | off | Use `MiniMax-M3[1m]` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
|
||||
| `--effort <level>` | `low` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
|
||||
| `--dryrun`, `-n` | off | Print resolved config, the gac command, the full prompt, and the sub-session command line; invoke neither gac's log fetch nor the sub-session |
|
||||
|
||||
## Requirements
|
||||
@@ -30,7 +32,7 @@ ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>] \
|
||||
- **CT-4 Redaction.** Before prompt assembly, credential-shaped content in `run-logs.ndjson` (`ghp_…|glpat-|x-access-token:|Authorization:|BEGIN … PRIVATE KEY|AKIA…` — same pattern set as review-minimax-run) is replaced in place with `[REDACTED]`. Redact-and-continue, not abort: CI logs routinely carry unmasked clone URLs and the log is the whole payload. Residual risk: best-effort patterns; novel credential formats can pass.
|
||||
- **CT-5 Envelope parse.** `failed_step`, `sliced`, and `note` are extracted from the NDJSON envelope with jq. If `failed_step` is null (cancelled/crashed run, green multi-job), the prompt states this and the output contract requires the literal `UNKNOWN` under `## Failing step` — no fabricated step names.
|
||||
- **CT-6 Prompt contract.** Fixed preamble: read-only triage of the two files in cwd; explicit error-signature patterns to search (`error:|FAILED|Traceback|exit code|denied|timeout|not found|no such|ECONN|refused`); do not suggest running tests or builds; if the log carries the truncation marker or `sliced` is partial, say so — do not improvise. Output sections, exactly: `## Failing step` / `## Error excerpt` (≤10 verbatim lines) / `## Probable cause` (1–3 sentences, non-empty) / `## Suggested next action` (one command or one edit description — advisory only) / `## Confidence`.
|
||||
- **CT-7 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "MiniMax-M3[1m]" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <out-dir> -p`. Same rationale set as review-minimax-run RM-6; no worktree access needed.
|
||||
- **CT-7 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <out-dir> -p`. Same rationale set as review-minimax-run RM-6; no worktree access needed.
|
||||
- **CT-8 Result gate.** Triage file exists, contains `## Failing step`, and has a non-blank line under `## Probable cause`.
|
||||
- **CT-9 Retry.** On MiniMax error or gate failure: remove the out-file, retry once; never retry timeout (rc 124); then exit 2 (transport) or 3 (gate). The gac fetch is NOT retried by the script (single fetch, reused across both attempts).
|
||||
- **CT-10 Test seams.** `CI_TRIAGE_FAKE_LOGS=<file>` bypasses the gac fetch (file used as `run-logs.ndjson`; `jobs.txt` gets a placeholder); `CI_TRIAGE_FAKE_JSON=<file>` substitutes the sub-session envelope; `CI_TRIAGE_FAKE_TRIAGE=<file>` (companion, optional) plays the sub-session's Write of the triage file. Gates and retry logic still run, so exits 0/2/3 and the redaction step are assertable offline.
|
||||
|
||||
@@ -9,7 +9,7 @@ Run a broad, read-only "where does X live" codebase exploration in a MiniMax M3
|
||||
```
|
||||
explore-minimax-run --root <path> [--root <path> ...] \
|
||||
--prompt-file <question-file> --out <result-file> \
|
||||
[--breadth medium|very-thorough] [--max-turns N] [--timeout SECS]
|
||||
[--breadth medium|very-thorough] [--max-turns N] [--timeout SECS] [--m3] [--effort LEVEL]
|
||||
```
|
||||
|
||||
| Flag | Default | Description |
|
||||
@@ -20,6 +20,8 @@ explore-minimax-run --root <path> [--root <path> ...] \
|
||||
| `--breadth` | `medium` | `medium` (stop when confidently answered) or `very-thorough` (full sweep, alternate naming conventions) |
|
||||
| `--max-turns` | 40 | Sub-session turn cap |
|
||||
| `--timeout` | 540 | Internal timeout in seconds (keeps callers under the harness Bash 600s cap) |
|
||||
| `--m3` | off | Use `MiniMax-M3` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
|
||||
| `--effort <level>` | `medium` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
|
||||
|
||||
## Behaviour / requirements
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ mm-worktree-task <item-uuid> [OPTIONS]
|
||||
| `--docs all\|recent\|none` | `recent` | Which item documents to bundle. `recent` = documents updated in the last 14 days; falls back to `all` if the CLI does not expose update dates. The full list of document names is always included in the prompt regardless of which are bundled. |
|
||||
| `--tools "<list>"` | — | Extra `--allowedTools` entries merged into the default allowlist (comma-separated). |
|
||||
| `--timeout <secs>` | `1800` | Max seconds the sub-session may run (`timeout <secs>` wrapper). |
|
||||
| `--m3` | off | Use `MiniMax-M3[1m]` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
|
||||
| `--effort <level>` | `max` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
|
||||
| `--gate "<command>"` | — | Supervisor gate: after the sub-session exits, `mm-worktree-task` itself re-runs this command in the worktree against the sub-session's LAST commit and appends a `## Supervisor gate` section to the result file (see Behaviour §8). Never trust the agent's own "tests pass" claim — this re-run is the check. |
|
||||
| `--gate-timeout <secs>` | `900` | Max seconds `--gate`'s command may run before it is killed and recorded as a timed-out (failed) gate. |
|
||||
| `--context <name>` | resolved (see §0) | `cp-cli --context` used for every planner call. |
|
||||
@@ -76,7 +78,7 @@ mm-worktree-task <item-uuid> [OPTIONS]
|
||||
- If `--brief <file>` is given, its content is appended (or used standalone as the task body when no uuid was given).
|
||||
8. Launch detached (skipped under `--dryrun` and `--collect`):
|
||||
```
|
||||
cd <worktree> && setsid nohup timeout <secs> ask-minimax-run --model "MiniMax-M3[1m]" \
|
||||
cd <worktree> && setsid nohup timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" \
|
||||
--allowedTools "<default-allowlist>[,<--tools>]" --permission-mode acceptEdits \
|
||||
--add-dir <report-dir> -p "$(cat <prompt-file>)" \
|
||||
> <report-dir>/<slug>-stdout.txt 2>&1
|
||||
|
||||
@@ -9,7 +9,7 @@ Launch a detached MiniMax M3 review of a review-loop artefact (plan, spec diff,
|
||||
```
|
||||
review-loop-run launch --kind <plan|spec|tests|code|verify> --name <tag> [--round N] \
|
||||
--file <path> [--file <path> ...] [--context "<text>"] [--prev <result.md>] \
|
||||
[--tools "<extra allowedTools>"] [--timeout <secs>] [--dryrun|-n]
|
||||
[--tools "<extra allowedTools>"] [--timeout <secs>] [--m3] [--effort <level>] [--dryrun|-n]
|
||||
review-loop-run status [--name <tag>] [--round N]
|
||||
review-loop-run counts <result.md>
|
||||
review-loop-run --help
|
||||
@@ -35,6 +35,8 @@ review-loop-run --help
|
||||
| `--prev` | auto | Explicit previous-round result file (overrides the auto lookup). |
|
||||
| `--tools` | kind default | Extra `--allowedTools` entries (comma-separated). |
|
||||
| `--timeout` | 1500 | Seconds before the sub-session is killed. |
|
||||
| `--m3` | off | Use `MiniMax-M3` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
|
||||
| `--effort <level>` | `max` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
|
||||
| `--project` | current repo root | Repo to `cd` into before launching. |
|
||||
| `--dryrun`, `-n` | off | Print the assembled prompt and the exact launch command; write nothing; launch nothing. |
|
||||
|
||||
@@ -51,7 +53,7 @@ review-loop-run --help
|
||||
2. Validate: kind in the closed set, name matches `^[A-Za-z0-9._-]+$`, every `--file` exists, `ask-minimax-run` on PATH, MiniMax profile present.
|
||||
3. Assemble the prompt from the kind template (§Templates): header (non-interactive, write to the output file), task text, `--context`, the "Files to read" list = `--file` entries + the kind's default best-practices/gotcha files that exist + the previous-round result (rounds ≥2), the output path, constraints.
|
||||
4. Write `<dir>/<name>-r<N>-prompt.txt`.
|
||||
5. Write `<dir>/<name>-r<N>-launch.sh` (a tiny bash script that `cd`s to the repo, runs `timeout <secs> ask-minimax-run --model MiniMax-M3 --allowedTools "<list>" --permission-mode acceptEdits -p "$(cat prompt)" > stdout 2>&1`, then appends `exit=$?` to the stdout file) and starts it with `setsid nohup <launch.sh> >/dev/null 2>&1 &`.
|
||||
5. Write `<dir>/<name>-r<N>-launch.sh` (a tiny bash script that `cd`s to the repo, runs `timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" --allowedTools "<list>" --permission-mode acceptEdits -p "$(cat prompt)" > stdout 2>&1`, then appends `exit=$?` to the stdout file) and starts it with `setsid nohup <launch.sh> >/dev/null 2>&1 &`.
|
||||
6. Print the three paths and `launched`.
|
||||
|
||||
`status` scans `<dir>/*-r*-stdout.txt`; a file whose last line matches `^exit=` is `done`, else `running`; counts come from `counts`.
|
||||
|
||||
@@ -9,7 +9,7 @@ Run a first-pass code review of a git branch (typically an agent-produced worktr
|
||||
```
|
||||
review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>] \
|
||||
[--profile agent-runtimes] [--max-diff-lines N] [--max-turns N] \
|
||||
[--timeout SECS] [--dryrun|-n]
|
||||
[--timeout SECS] [--dryrun|-n] [--m3] [--effort LEVEL]
|
||||
```
|
||||
|
||||
| Flag | Default | Description |
|
||||
@@ -21,6 +21,8 @@ review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>] \
|
||||
| `--max-diff-lines` | 6000 | Diff budget; larger diffs exit 1 with the count |
|
||||
| `--max-turns` | 40 | Sub-session turn cap |
|
||||
| `--timeout` | 540 | Internal timeout (keeps callers under the harness Bash 600s cap). Why: a longer run invoked synchronously from a skill is killed by the harness with no findings file. |
|
||||
| `--m3` | off | Use `MiniMax-M3[1m]` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
|
||||
| `--effort <level>` | `max` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
|
||||
| `--dryrun`, `-n` | off | Print resolved config, materialised-input plan, full prompt, and the exact sub-session command line; create/invoke nothing beyond the scratch dir |
|
||||
|
||||
## Requirements
|
||||
@@ -30,7 +32,7 @@ review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>] \
|
||||
- **RM-3 Redaction gate.** If `diff.patch` matches `ghp_[A-Za-z0-9]|glpat-|x-access-token:|Authorization:|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}`, exit 1 with "diff contains credential-shaped content; review in-session". No redact-and-continue for diffs: a credential in a diff means the branch itself needs attention.
|
||||
- **RM-4 Empty/oversize diff.** Empty `diff.patch` → exit 1 "nothing to review". More than `--max-diff-lines` lines → exit 1 with the count.
|
||||
- **RM-5 Prompt contract.** Fixed preamble: first-pass reviewer, non-interactive; inputs are the three files in cwd; the worktree is readable for surrounding context only; write ONLY the findings file at the given path; never modify any other file; do not run anything, fix anything, or improvise if an input is missing/truncated — say so and stop. Checklist = unconditional core (distilled from llm-code-security §10/§12: injection, hardcoded credentials, unquoted shell vars, verify=False, weak hashing/random, missing input validation, chmod 777, curl|bash, unpinned images/deps, missing idempotency, unconditional health checks, missing locking) as explicit grep-able patterns; `--profile agent-runtimes` appends the 5 recurring MiniMax test-file bugs. Findings format: `### [BLOCKER|SHOULD-FIX|NIT] <title>` blocks with `file:line`, ≤10-line excerpt, category, `Confidence: confirmed|suspected`; clean review → literal `NO FINDINGS`.
|
||||
- **RM-6 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "MiniMax-M3[1m]" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <worktree> --add-dir <out-dir> -p < prompt > response.json`. Why each: `[1m]` pins the 1M window (unknown model ids get 200k + early auto-compact); `Write` must be allowlisted or MiniMax exits 0 without creating the file; `default` not `acceptEdits` — new-file Write needs no edit approval and nothing else is auto-approved; deny-list beats the profile's permissive defaults.
|
||||
- **RM-6 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <worktree> --add-dir <out-dir> -p < prompt > response.json`. Why each: `$MODEL` is Flash (1M natively) by default; with `--m3`, `[1m]` pins the 1M window (unknown model ids get 200k + early auto-compact); `Write` must be allowlisted or MiniMax exits 0 without creating the file; `default` not `acceptEdits` — new-file Write needs no edit approval and nothing else is auto-approved; deny-list beats the profile's permissive defaults.
|
||||
- **RM-7 Clean-tree assertion.** After each attempt, `git -C <worktree> status --porcelain` must be empty; a dirtied tree is exit 2 (and the dirt is reported, not reverted).
|
||||
- **RM-8 Result gate.** Findings file exists AND (contains `NO FINDINGS` OR (≥1 line matching `^### \[(BLOCKER|SHOULD-FIX|NIT)\]` AND ≥1 finding cites a path that exists relative to the worktree)). A bare `:NNN` match is NOT sufficient — timestamps and counters satisfy that.
|
||||
- **RM-9 Retry.** On MiniMax error OR gate failure: remove the out-file and retry once (covers the "exit 0, file never written" failure and prevents a stale attempt-1 file passing the gate). Never retry a timeout (rc 124). Then exit 2 (transport/timeout/dirty-tree) or 3 (gate).
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"documents": [{"name": "notes.md", "updated_at": "2026-09-01T00:00:00Z"}, {"name": "old-notes.md", "updated_at": "2020-01-01T00:00:00Z"}]}
|
||||
{"documents": [{"name": "notes.md", "updated_at": "2026-10-10T00:00:00Z"}, {"name": "old-notes.md", "updated_at": "2020-01-01T00:00:00Z"}]}
|
||||
|
||||
@@ -27,6 +27,16 @@ assert_contains() {
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_contains() {
|
||||
local label=$1 needle=$2 haystack=$3
|
||||
if [[ "$haystack" != *"$needle"* ]]; then
|
||||
printf " ${GREEN}PASS${NC} %s\n" "$label"; PASS=$((PASS + 1))
|
||||
else
|
||||
printf " ${RED}FAIL${NC} %s\n" "$label"
|
||||
printf " expected NOT to contain: %s\n" "$needle"; FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_eq() {
|
||||
local label=$1 expected=$2 actual=$3
|
||||
if [[ "$expected" == "$actual" ]]; then
|
||||
@@ -70,10 +80,20 @@ echo "== dryrun =="
|
||||
DRY_OUT="$("$SCRIPT" --repo skynet/gac-scratch --run 42 --dryrun 2>&1)"
|
||||
assert_eq "dryrun exits 0" 0 $?
|
||||
assert_contains "dryrun shows gac command" "inspect skynet/gac-scratch --run 42" "$DRY_OUT"
|
||||
assert_contains "dryrun shows model pin" "MiniMax-M3[1m]" "$DRY_OUT"
|
||||
assert_contains "dryrun defaults to Flash" "MiniMax-M3.1-Flash-Preview" "$DRY_OUT"
|
||||
assert_contains "dryrun default effort low" "--effort low" "$DRY_OUT"
|
||||
assert_contains "dryrun defers fetch" "not fetched in dryrun" "$DRY_OUT"
|
||||
assert_contains "dryrun shows job passthrough default" "job: auto" "$DRY_OUT"
|
||||
|
||||
echo "== dryrun --m3/--effort =="
|
||||
M3_OUT="$("$SCRIPT" --repo skynet/gac-scratch --run 42 --m3 --dryrun 2>&1)"
|
||||
assert_eq "m3 dryrun exits 0" 0 $?
|
||||
assert_contains "m3 dryrun shows M3 model" "MiniMax-M3[1m]" "$M3_OUT"
|
||||
assert_not_contains "m3 dryrun sends no effort" "--effort" "$M3_OUT"
|
||||
EF_OUT="$("$SCRIPT" --repo skynet/gac-scratch --run 42 --effort high --dryrun 2>&1)"
|
||||
assert_contains "explicit effort overrides default" "--effort high" "$EF_OUT"
|
||||
"$SCRIPT" --repo o/r --run 1 --effort bogus --dryrun >/dev/null 2>&1; assert_eq "bad effort exits 1" 1 $?
|
||||
|
||||
echo "== fake logs: redaction + failing step in prompt, exit 0 =="
|
||||
OUT0="$TMP/out0.md"
|
||||
RUN_OUT="$(CI_TRIAGE_FAKE_LOGS="$FAKE_LOGS" CI_TRIAGE_FAKE_JSON="$FAKE_OK_JSON" CI_TRIAGE_FAKE_TRIAGE="$FAKE_TRIAGE" \
|
||||
|
||||
@@ -83,7 +83,15 @@ assert_contains "dryrun shows worktree path" ".claude/worktrees/mm-testslug" "$D
|
||||
assert_contains "dryrun shows branch name" "mm/testslug" "$DRY_OUT"
|
||||
assert_contains "dryrun shows bundle path" "testslug-bundle.md" "$DRY_OUT"
|
||||
assert_contains "dryrun shows the ask-minimax-run command" "ask-minimax-run" "$DRY_OUT"
|
||||
assert_contains "dryrun command uses MiniMax-M3[1m] model" 'MiniMax-M3[1m]' "$DRY_OUT"
|
||||
assert_contains "dryrun command defaults to Flash model" 'MiniMax-M3.1-Flash-Preview' "$DRY_OUT"
|
||||
assert_contains "dryrun default effort max" "--effort max" "$DRY_OUT"
|
||||
M3_OUT="$("$SCRIPT" "$TEST_UUID" --slug testslug --m3 --dryrun 2>&1)"
|
||||
assert_eq "m3 dryrun exits 0" "0" "$?"
|
||||
assert_contains "m3 dryrun uses M3[1m] model" 'MiniMax-M3[1m]' "$M3_OUT"
|
||||
assert_not_contains "m3 dryrun sends no effort" "--effort" "$M3_OUT"
|
||||
EF_OUT="$("$SCRIPT" "$TEST_UUID" --slug testslug --effort low --dryrun 2>&1)"
|
||||
assert_contains "explicit effort overrides default" "--effort low" "$EF_OUT"
|
||||
"$SCRIPT" "$TEST_UUID" --effort bogus --dryrun >/dev/null 2>&1; assert_eq "bad effort exits 1" "1" "$?"
|
||||
assert_contains "dryrun bundles recent doc notes.md" "notes.md (bundled below)" "$DRY_OUT"
|
||||
assert_contains "dryrun lists old doc as available only" "old-notes.md (available only)" "$DRY_OUT"
|
||||
assert_not_contains "dryrun does not bundle stale doc body" "Stale notes, should not be bundled" "$DRY_OUT"
|
||||
|
||||
@@ -19,6 +19,9 @@ assert_contains "dryrun banner" "[dryrun]" "$out"
|
||||
assert_contains "nothing launched" "nothing launched" "$out"
|
||||
assert_contains "task text is the spec template" "OUT OF SCOPE: reporting that a symbol" "$out"
|
||||
assert_contains "context included" "Context: closes bug 1234" "$out"
|
||||
assert_contains "defaults to Flash" "--model MiniMax-M3.1-Flash-Preview --effort max" "$out"
|
||||
out_m3=$("$SCRIPT" launch --kind spec --name spec-Y --file "$TMP/spec.diff" --m3 -n 2>&1)
|
||||
assert_contains "--m3 uses M3 with no effort" "--model MiniMax-M3 --allowedTools" "$out_m3"
|
||||
assert_contains "output path uses tag" "spec-X-r1-result.md" "$out"
|
||||
assert_contains "present default listed" "$TMP/bp/spec-driven-development.md" "$out"
|
||||
assert_contains "absent default skipped" "default file absent, skipped" "$out"
|
||||
|
||||
@@ -27,6 +27,16 @@ assert_contains() {
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_contains() {
|
||||
local label=$1 needle=$2 haystack=$3
|
||||
if [[ "$haystack" != *"$needle"* ]]; then
|
||||
printf " ${GREEN}PASS${NC} %s\n" "$label"; PASS=$((PASS + 1))
|
||||
else
|
||||
printf " ${RED}FAIL${NC} %s\n" "$label"
|
||||
printf " expected NOT to contain: %s\n" "$needle"; FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_eq() {
|
||||
local label=$1 expected=$2 actual=$3
|
||||
if [[ "$expected" == "$actual" ]]; then
|
||||
@@ -68,7 +78,15 @@ echo "== dryrun =="
|
||||
DRY_OUT="$("$SCRIPT" --worktree "$REPO" --dryrun 2>&1)"
|
||||
assert_eq "dryrun exits 0" 0 $?
|
||||
assert_contains "dryrun shows branch" "branch: feature" "$DRY_OUT"
|
||||
assert_contains "dryrun shows model pin" "MiniMax-M3[1m]" "$DRY_OUT"
|
||||
assert_contains "dryrun defaults to Flash" "MiniMax-M3.1-Flash-Preview" "$DRY_OUT"
|
||||
assert_contains "dryrun default effort max" "--effort max" "$DRY_OUT"
|
||||
M3_OUT="$("$SCRIPT" --worktree "$REPO" --m3 --dryrun 2>&1)"
|
||||
assert_eq "m3 dryrun exits 0" 0 $?
|
||||
assert_contains "m3 dryrun shows M3 model" "MiniMax-M3[1m]" "$M3_OUT"
|
||||
assert_not_contains "m3 dryrun sends no effort" "--effort" "$M3_OUT"
|
||||
EF_OUT="$("$SCRIPT" --worktree "$REPO" --effort high --dryrun 2>&1)"
|
||||
assert_contains "explicit effort overrides default" "--effort high" "$EF_OUT"
|
||||
"$SCRIPT" --worktree "$REPO" --effort bogus --dryrun >/dev/null 2>&1; assert_eq "bad effort exits 1" 1 $?
|
||||
assert_contains "dryrun shows deny list" "Bash,WebFetch,WebSearch" "$DRY_OUT"
|
||||
assert_contains "dryrun prompt has findings format" "NO FINDINGS" "$DRY_OUT"
|
||||
assert_contains "dryrun shows checklist" "shell=True" "$DRY_OUT"
|
||||
|
||||
Reference in New Issue
Block a user