@cxi-lmai/ci-agent-platform 3.0.0 → 3.1.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/README.md +27 -5
- package/package.json +2 -2
- package/payload/INSTALL.md +14 -5
- package/payload/agents/agent-architect.md +1 -1
- package/payload/agents/code-reviewer.md +1 -1
- package/payload/agents/codebase-auditor.md +1 -1
- package/payload/agents/coder.md +3 -3
- package/payload/agents/decomposer.md +1 -1
- package/payload/agents/docs-sync.md +1 -1
- package/payload/agents/e2e-test-writer.md +1 -1
- package/payload/agents/performance-reviewer.md +1 -1
- package/payload/agents/release-mr.md +1 -1
- package/payload/agents/security-reviewer.md +1 -1
- package/payload/agents/test-fix.md +4 -4
- package/payload/agents/test-writer.md +3 -3
- package/payload/agents-omp/agent-architect.md +101 -0
- package/payload/agents-omp/code-reviewer.md +86 -0
- package/payload/agents-omp/codebase-auditor.md +73 -0
- package/payload/agents-omp/coder.md +57 -0
- package/payload/agents-omp/decomposer.md +70 -0
- package/payload/agents-omp/docs-sync.md +114 -0
- package/payload/agents-omp/e2e-test-writer.md +47 -0
- package/payload/agents-omp/migration-reviewer.md +99 -0
- package/payload/agents-omp/orchestrator.md +50 -0
- package/payload/agents-omp/performance-reviewer.md +81 -0
- package/payload/agents-omp/postmortem.md +82 -0
- package/payload/agents-omp/release-mr.md +274 -0
- package/payload/agents-omp/security-reviewer.md +121 -0
- package/payload/agents-omp/test-fix.md +33 -0
- package/payload/agents-omp/test-writer.md +39 -0
- package/payload/ci-templates/claude-pipeline.gitlab-ci.yml +220 -7
- package/payload/ci-templates/github/claude-issue-pipeline.yml +1 -1
- package/payload/ci-templates/github/claude-pipeline.yml +2 -2
- package/payload/ci-templates/github/claude-test-fix.yml +1 -1
- package/payload/ci-templates/scripts/agent-architect.sh +233 -0
- package/payload/ci-templates/scripts/code.sh +35 -35
- package/payload/ci-templates/scripts/codebase-audit.sh +252 -0
- package/payload/ci-templates/scripts/coverage-ratchet.sh +77 -0
- package/payload/ci-templates/scripts/cve-fix.sh +246 -0
- package/payload/ci-templates/scripts/docs-sync.sh +225 -0
- package/payload/ci-templates/scripts/e2e-test-gen.sh +201 -0
- package/payload/ci-templates/scripts/lib/failure-notice.sh +104 -0
- package/payload/ci-templates/scripts/lib/issue-loop.sh +155 -40
- package/payload/ci-templates/scripts/lib/pipeline-common.sh +233 -31
- package/payload/ci-templates/scripts/lib/platform.sh +270 -13
- package/payload/ci-templates/scripts/lib/usage-capture-omp.sh +123 -0
- package/payload/ci-templates/scripts/lib/usage-capture.sh +7 -1
- package/payload/ci-templates/scripts/metrics-snapshot.sh +377 -0
- package/payload/ci-templates/scripts/orchestrate.sh +56 -38
- package/payload/ci-templates/scripts/postmortem.sh +11 -1
- package/payload/ci-templates/scripts/review-fix.sh +23 -12
- package/payload/ci-templates/scripts/review.sh +12 -8
- package/payload/ci-templates/scripts/test-fix.sh +8 -1
- package/payload/skills/agent-architect/SKILL.md +45 -0
- package/payload/skills/codebase-audit/SKILL.md +84 -0
- package/payload/skills/cve-fix/SKILL.md +98 -0
- package/payload/skills/docs-sync/SKILL.md +74 -0
- package/payload/skills/e2e-test-gen/SKILL.md +65 -0
- package/payload/skills/fix-review-findings/SKILL.md +3 -3
- package/payload/skills/fix-tests/SKILL.md +4 -4
- package/payload/skills/implement-issue/SKILL.md +1 -1
- package/payload/skills/init-pipeline-config/SKILL.md +4 -4
- package/payload/skills/postmortem-mr/SKILL.md +1 -1
- package/payload/skills/review-mr/SKILL.md +1 -1
- package/payload/skills/triage-issue/SKILL.md +2 -2
- package/payload/templates/memory-index.template.md +34 -0
- package/payload/templates/pipeline-config.template.md +11 -1
- package/payload/templates/review_suppressions.template.md +55 -0
- package/payload/templates/spec-issue.template.md +39 -7
|
@@ -9,8 +9,12 @@ set -u
|
|
|
9
9
|
SCRIPT_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
10
|
# shellcheck source=./usage-capture.sh
|
|
11
11
|
source "$SCRIPT_LIB_DIR/usage-capture.sh"
|
|
12
|
+
# shellcheck source=./usage-capture-omp.sh
|
|
13
|
+
source "$SCRIPT_LIB_DIR/usage-capture-omp.sh"
|
|
12
14
|
# shellcheck source=./platform.sh
|
|
13
15
|
source "$SCRIPT_LIB_DIR/platform.sh"
|
|
16
|
+
# shellcheck source=./failure-notice.sh
|
|
17
|
+
source "$SCRIPT_LIB_DIR/failure-notice.sh"
|
|
14
18
|
|
|
15
19
|
# --- Defaults ---------------------------------------------------------------
|
|
16
20
|
# Every PIPE_ variable has a default here so a project that overrides nothing
|
|
@@ -23,28 +27,87 @@ pipe_defaults() {
|
|
|
23
27
|
: "${PIPE_CONFIG_PATH:=.claude/pipeline-config.md}"
|
|
24
28
|
: "${PIPE_CONTEXT_DIR:=build/pipeline}"
|
|
25
29
|
: "${PIPE_METRICS_DIR:=$PIPE_CONTEXT_DIR/metrics}"
|
|
30
|
+
: "${PIPE_AGENT_STDERR:=$PIPE_CONTEXT_DIR/agent-stderr.log}"
|
|
26
31
|
: "${PIPE_TARGET_BRANCH:=main}"
|
|
27
32
|
: "${PIPE_FIX_LOOP_CAP:=2}"
|
|
28
33
|
: "${PIPE_CODER_CAP:=3}"
|
|
29
34
|
: "${PIPE_ISSUE_SCAN:=20}"
|
|
30
|
-
: "${
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
: "${PIPE_HARNESS:=claude}"
|
|
36
|
+
# Model defaults track the active harness. Each PIPE_MODEL_* variable remains
|
|
37
|
+
# explicitly overridable.
|
|
38
|
+
if [ "$PIPE_HARNESS" = "omp" ]; then
|
|
39
|
+
: "${PIPE_MODEL_TRIAGE:=openrouter/anthropic/claude-haiku-4-5}"
|
|
40
|
+
: "${PIPE_MODEL_CODE:=openrouter/anthropic/claude-sonnet-5-0}"
|
|
41
|
+
: "${PIPE_MODEL_REVIEW:=openrouter/anthropic/claude-sonnet-5-0}"
|
|
42
|
+
else
|
|
43
|
+
: "${PIPE_MODEL_TRIAGE:=haiku}"
|
|
44
|
+
: "${PIPE_MODEL_CODE:=claude-sonnet-5-0}"
|
|
45
|
+
: "${PIPE_MODEL_REVIEW:=claude-sonnet-5-0}"
|
|
46
|
+
fi
|
|
33
47
|
: "${PIPE_COMMIT_TESTFIX:=Fix test errors}"
|
|
34
48
|
: "${PIPE_COMMIT_REVIEWFIX:=Fix review findings}"
|
|
35
49
|
: "${PIPE_COMMIT_COVERAGE:=Add coverage tests}"
|
|
50
|
+
: "${PIPE_COMMIT_DOCSSYNC:=Update docs per docs-sync findings}"
|
|
51
|
+
: "${PIPE_COMMIT_AUDIT:=docs: apply convention audit findings}"
|
|
52
|
+
: "${PIPE_COMMIT_CVEFIX:=Update dependencies to resolve CVEs}"
|
|
36
53
|
: "${PIPE_LABEL_READY:=pipe-ready}"
|
|
37
54
|
: "${PIPE_LABEL_WIP:=pipe-wip}"
|
|
38
55
|
: "${PIPE_LABEL_STUCK:=pipe-stuck}"
|
|
39
56
|
: "${PIPE_LABEL_BLOCKER:=pipe-blocker}"
|
|
40
57
|
: "${PIPE_LABEL_BLOCKED:=pipe-blocked}"
|
|
41
58
|
: "${PIPE_LABEL_DECOMPOSED:=pipe-decomposed}"
|
|
59
|
+
: "${PIPE_LABEL_AUDIT:=codebase-audit}"
|
|
42
60
|
: "${PIPE_RESULT_REVIEW:=$PIPE_CONTEXT_DIR/code-review-result.txt}"
|
|
43
61
|
: "${PIPE_RESULT_REVIEWFIX:=$PIPE_CONTEXT_DIR/review-fix-result.json}"
|
|
62
|
+
: "${PIPE_RESULT_DOCSSYNC:=$PIPE_CONTEXT_DIR/docs-sync.json}"
|
|
44
63
|
: "${PIPE_VERIFY_CMD:=}"
|
|
45
64
|
: "${PIPE_COMPILE_CMD:=${PIPE_VERIFY_CMD}}"
|
|
46
65
|
: "${PIPE_TEST_REPORT_GLOB:=}"
|
|
66
|
+
: "${PIPE_COVERAGE_RATCHET:=0}"
|
|
67
|
+
: "${PIPE_COVERAGE_REPORT:=}"
|
|
68
|
+
: "${PIPE_COVERAGE_REPORT_KIND:=jacoco}"
|
|
47
69
|
: "${PIPE_COVERAGE_SIGNAL:=}"
|
|
70
|
+
# CVE remediation. Off by default: project-local scanners provide the
|
|
71
|
+
# HIGH/CRITICAL identifier list when PIPE_CVE_FIX=1 enables this job.
|
|
72
|
+
: "${PIPE_CVE_FIX:=0}"
|
|
73
|
+
: "${PIPE_DEPENDENCY_MANIFEST:=build.gradle}"
|
|
74
|
+
: "${PIPE_CVE_SUPPRESSIONS:=owasp-suppressions.xml}"
|
|
75
|
+
# Issue-driven E2E generation. Off by default; PIPE_VERIFY_CMD is the
|
|
76
|
+
# configured verification command and must be non-empty before tests run.
|
|
77
|
+
: "${PIPE_E2E_TEST_GEN:=0}"
|
|
78
|
+
: "${PIPE_LABEL_TESTREADY:=test-ready}"
|
|
79
|
+
: "${PIPE_LABEL_E2E_SCOPE:=}"
|
|
80
|
+
: "${PIPE_E2E_TEST_DIR:=e2e/tests}"
|
|
81
|
+
: "${PIPE_E2E_BASE_URL:=}"
|
|
82
|
+
: "${PIPE_E2E_VERIFY_CMD:=}"
|
|
83
|
+
# Documentation sync. Off by default: the job only runs when the pipeline
|
|
84
|
+
# sets PIPE_DOCS_SYNC=1. PIPE_DOCS_ROOTS is the comma-separated set of paths
|
|
85
|
+
# the docs-sync agent may edit and the runner may commit.
|
|
86
|
+
: "${PIPE_DOCS_SYNC:=0}"
|
|
87
|
+
: "${PIPE_DOCS_ROOTS:=docs,CLAUDE.md,.claude/memory}"
|
|
88
|
+
# Codebase audit. Off by default: the job only runs on a schedule that sets
|
|
89
|
+
# PIPE_CODEBASE_AUDIT=1. Reuses PIPE_DOCS_ROOTS for the optional auto-fix
|
|
90
|
+
# phase's coder scope.
|
|
91
|
+
: "${PIPE_CODEBASE_AUDIT:=0}"
|
|
92
|
+
# Agent architect. Off by default: a scheduled pipeline explicitly enables
|
|
93
|
+
# this evidence-backed proposal job after a project has reviewed its output.
|
|
94
|
+
: "${PIPE_AGENT_ARCHITECT:=0}"
|
|
95
|
+
: "${PIPE_ARCHITECT_WINDOW_DAYS:=7}"
|
|
96
|
+
: "${PIPE_ARCHITECT_DRY_RUN:=true}"
|
|
97
|
+
: "${PIPE_LABEL_IMPROVEMENT:=pipe-improvement}"
|
|
98
|
+
# Metrics aggregation. Off by default: the job only runs on a schedule that
|
|
99
|
+
# sets PIPE_METRICS_SNAPSHOT=1, and it publishes an artifact unless the
|
|
100
|
+
# project explicitly opts in to committing generated data to its repository.
|
|
101
|
+
: "${PIPE_METRICS_SNAPSHOT:=0}"
|
|
102
|
+
: "${PIPE_METRICS_OUTPUT_DIR:=data/metrics/snapshots}"
|
|
103
|
+
: "${PIPE_METRICS_WINDOW_DAYS:=1}"
|
|
104
|
+
: "${PIPE_METRICS_COMMIT_REPO:=false}"
|
|
105
|
+
: "${PIPE_METRICS_REVIEW_AGENTS:=code-reviewer,review-verdict,review-fix}"
|
|
106
|
+
# Commit subjects that mark a defect in already-merged work. Keep in sync with
|
|
107
|
+
# the Metrics Conventions section of the pipeline config.
|
|
108
|
+
: "${PIPE_METRICS_DEFECT_REVERT:=Reverts !}"
|
|
109
|
+
: "${PIPE_METRICS_DEFECT_REGRESSION:=Fixes regression from !}"
|
|
110
|
+
: "${PIPE_METRICS_DEFECT_REINTRODUCE:=Reintroduces work from !}"
|
|
48
111
|
# Spec template path. GitHub projects usually keep it under .github, GitLab
|
|
49
112
|
# under .gitlab, so the default follows the detected platform.
|
|
50
113
|
if [ "$PIPE_PLATFORM" = "github" ]; then
|
|
@@ -58,13 +121,21 @@ pipe_defaults() {
|
|
|
58
121
|
# would pick up result files (E2E finding N-6). A `*` gitignore inside the
|
|
59
122
|
# dir hides everything in it, including itself, from any git add.
|
|
60
123
|
[ -f "$PIPE_CONTEXT_DIR/.gitignore" ] || printf '*\n' > "$PIPE_CONTEXT_DIR/.gitignore"
|
|
61
|
-
export PIPE_PLATFORM PIPE_CONFIG_PATH PIPE_CONTEXT_DIR PIPE_METRICS_DIR \
|
|
124
|
+
export PIPE_PLATFORM PIPE_CONFIG_PATH PIPE_CONTEXT_DIR PIPE_METRICS_DIR PIPE_AGENT_STDERR \
|
|
62
125
|
PIPE_TARGET_BRANCH PIPE_FIX_LOOP_CAP PIPE_CODER_CAP PIPE_ISSUE_SCAN PIPE_COMMIT_TESTFIX \
|
|
63
|
-
PIPE_COMMIT_REVIEWFIX PIPE_COMMIT_COVERAGE PIPE_LABEL_READY PIPE_LABEL_WIP \
|
|
64
|
-
PIPE_LABEL_STUCK PIPE_LABEL_BLOCKER PIPE_LABEL_BLOCKED PIPE_LABEL_DECOMPOSED \
|
|
65
|
-
PIPE_RESULT_REVIEW PIPE_RESULT_REVIEWFIX
|
|
66
|
-
|
|
67
|
-
|
|
126
|
+
PIPE_COMMIT_REVIEWFIX PIPE_COMMIT_COVERAGE PIPE_COMMIT_CVEFIX PIPE_LABEL_READY PIPE_LABEL_WIP \
|
|
127
|
+
PIPE_LABEL_STUCK PIPE_LABEL_BLOCKER PIPE_LABEL_BLOCKED PIPE_LABEL_DECOMPOSED PIPE_LABEL_AUDIT \
|
|
128
|
+
PIPE_RESULT_REVIEW PIPE_RESULT_REVIEWFIX PIPE_RESULT_DOCSSYNC PIPE_COMMIT_DOCSSYNC PIPE_COMMIT_AUDIT \
|
|
129
|
+
PIPE_CVE_FIX PIPE_DEPENDENCY_MANIFEST PIPE_CVE_SUPPRESSIONS PIPE_E2E_TEST_GEN PIPE_LABEL_TESTREADY \
|
|
130
|
+
PIPE_LABEL_E2E_SCOPE PIPE_E2E_TEST_DIR PIPE_E2E_BASE_URL PIPE_E2E_VERIFY_CMD PIPE_DOCS_SYNC PIPE_DOCS_ROOTS PIPE_VERIFY_CMD PIPE_COMPILE_CMD \
|
|
131
|
+
PIPE_TEST_REPORT_GLOB PIPE_COVERAGE_RATCHET PIPE_COVERAGE_REPORT PIPE_COVERAGE_REPORT_KIND \
|
|
132
|
+
PIPE_COVERAGE_SIGNAL PIPE_SPEC_TEMPLATE_PATH PIPE_CODEBASE_AUDIT PIPE_AGENT_ARCHITECT \
|
|
133
|
+
PIPE_ARCHITECT_WINDOW_DAYS PIPE_ARCHITECT_DRY_RUN PIPE_LABEL_IMPROVEMENT \
|
|
134
|
+
PIPE_METRICS_SNAPSHOT PIPE_METRICS_OUTPUT_DIR PIPE_METRICS_WINDOW_DAYS \
|
|
135
|
+
PIPE_METRICS_COMMIT_REPO PIPE_METRICS_REVIEW_AGENTS PIPE_METRICS_DEFECT_REVERT \
|
|
136
|
+
PIPE_METRICS_DEFECT_REGRESSION PIPE_METRICS_DEFECT_REINTRODUCE \
|
|
137
|
+
PIPE_METRICS_SNAPSHOT_DATE PIPE_METRICS_RAW_DIR PIPE_METRICS_MRS_FILE \
|
|
138
|
+
PIPE_HARNESS PIPE_MODEL_TRIAGE PIPE_MODEL_CODE PIPE_MODEL_REVIEW
|
|
68
139
|
}
|
|
69
140
|
|
|
70
141
|
pipe_log() { echo "[pipeline] $*"; }
|
|
@@ -88,6 +159,17 @@ pipe_git_identity() {
|
|
|
88
159
|
# Checkout the real source branch so commits land on the branch tip, not on the
|
|
89
160
|
# detached MR/PR ref that can fall behind and cause non-fast-forward push errors.
|
|
90
161
|
pipe_checkout_source() {
|
|
162
|
+
# The MR/PR itself is the authoritative source of the branch name. A
|
|
163
|
+
# workflow_run or branch pipeline carries no merge-request source ref, and
|
|
164
|
+
# without one this checkout used to no-op silently, leaving the fix commit on
|
|
165
|
+
# a detached head that no push could land.
|
|
166
|
+
if [ -z "${PIPE_SOURCE_BRANCH:-}" ] && [ -n "${PIPE_MR_IID:-}" ]; then
|
|
167
|
+
# `|| PIPE_SOURCE_BRANCH=""` is the whole error path: an unreachable or
|
|
168
|
+
# unconfigured API must leave the caller where it was, not abort it.
|
|
169
|
+
PIPE_SOURCE_BRANCH=$(platform_mr_meta 2>/dev/null | jq -r '.source_branch // ""' 2>/dev/null) \
|
|
170
|
+
|| PIPE_SOURCE_BRANCH=""
|
|
171
|
+
export PIPE_SOURCE_BRANCH
|
|
172
|
+
fi
|
|
91
173
|
[ -z "${PIPE_SOURCE_BRANCH:-}" ] && return 0
|
|
92
174
|
git fetch origin "$PIPE_TARGET_BRANCH" "$PIPE_SOURCE_BRANCH" 2>/dev/null || true
|
|
93
175
|
git checkout -B "$PIPE_SOURCE_BRANCH" "origin/$PIPE_SOURCE_BRANCH" 2>/dev/null || true
|
|
@@ -106,15 +188,17 @@ pipe_rebase_and_push() {
|
|
|
106
188
|
}
|
|
107
189
|
|
|
108
190
|
# --- Cap counting -----------------------------------------------------------
|
|
109
|
-
# Count consecutive commits from the tip back toward the target branch
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
|
|
191
|
+
# Count consecutive matching commits from the tip back toward the target branch.
|
|
192
|
+
# Docs-sync commits are transparent: they do not count, but do not interrupt a
|
|
193
|
+
# fix streak. The skills use the same exact-subject rules for their cap checks;
|
|
194
|
+
# the runner needs this count only to detect whether a fix commit landed.
|
|
113
195
|
pipe_count_fix_commits() {
|
|
114
196
|
local pattern="$1" count=0 subject
|
|
115
197
|
while IFS= read -r subject; do
|
|
116
|
-
if
|
|
198
|
+
if [ "$subject" = "$pattern" ]; then
|
|
117
199
|
count=$((count + 1))
|
|
200
|
+
elif [ "$subject" = "$PIPE_COMMIT_DOCSSYNC" ]; then
|
|
201
|
+
continue
|
|
118
202
|
else
|
|
119
203
|
break
|
|
120
204
|
fi
|
|
@@ -131,14 +215,22 @@ pipe_count_fix_commits() {
|
|
|
131
215
|
|
|
132
216
|
pipe_agent_secret_var() {
|
|
133
217
|
# Return success when an exported variable looks credential-bearing and is
|
|
134
|
-
# not explicitly required by the
|
|
135
|
-
# project verification command. The allowlist is comma/space
|
|
218
|
+
# not explicitly required by the active harness's own auth or allowlisted
|
|
219
|
+
# for a project verification command. The allowlist is comma/space
|
|
220
|
+
# separated.
|
|
136
221
|
local name="$1" allow=" ${PIPE_AGENT_ENV_ALLOWLIST:-} "
|
|
137
222
|
allow=" ${allow//,/ } "
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
case "$
|
|
141
|
-
|
|
223
|
+
# Preserve only the active harness's built-in model credentials. Credentials
|
|
224
|
+
# for the inactive harness fall through to the generic secret-name check.
|
|
225
|
+
case "${PIPE_HARNESS:-claude}" in
|
|
226
|
+
omp)
|
|
227
|
+
[ "$name" = "OPENROUTER_API_KEY" ] && return 1
|
|
228
|
+
;;
|
|
229
|
+
*)
|
|
230
|
+
case "$name" in
|
|
231
|
+
ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_CODE_OAUTH_TOKEN) return 1 ;;
|
|
232
|
+
esac
|
|
233
|
+
;;
|
|
142
234
|
esac
|
|
143
235
|
[[ "$allow" == *" $name "* ]] && return 1
|
|
144
236
|
case "$name" in
|
|
@@ -213,6 +305,115 @@ pipe_run_claude() {
|
|
|
213
305
|
rm -f "$stdin_file"
|
|
214
306
|
}
|
|
215
307
|
|
|
308
|
+
# --- omp invocation -----------------------------------------------------
|
|
309
|
+
# Runs `omp -p "/<skill>"` wrapped in usage-capture, the omp equivalent of
|
|
310
|
+
# pipe_run_claude. Same non-root/su-user dance (unverified whether omp
|
|
311
|
+
# tolerates root under --yolo; the same-user fallback Claude Code needs is
|
|
312
|
+
# always safe, so it ships unconditionally either way).
|
|
313
|
+
|
|
314
|
+
pipe_translate_tools_to_omp() {
|
|
315
|
+
# $1 = Claude Code-style comma-separated tool list, e.g.
|
|
316
|
+
# "Agent,Read,Write,Edit,Glob,Grep,Bash". Echoes the omp-equivalent
|
|
317
|
+
# comma-separated list, deduplicated and order-preserving. Tokens with no
|
|
318
|
+
# omp equivalent (LS, NotebookRead, Skill, KillShell, BashOutput) are
|
|
319
|
+
# dropped; mcp__* and any unrecognized token pass through unchanged. See
|
|
320
|
+
# the translation table in
|
|
321
|
+
# docs/superpowers/specs/2026-08-26-omp-openrouter-harness-design.md.
|
|
322
|
+
local tools="$1" tok mapped seen="," result=""
|
|
323
|
+
IFS=',' read -ra tokens <<< "$tools"
|
|
324
|
+
for tok in "${tokens[@]}"; do
|
|
325
|
+
case "$tok" in
|
|
326
|
+
Agent) mapped=task ;;
|
|
327
|
+
Bash) mapped=bash ;;
|
|
328
|
+
Edit|MultiEdit) mapped=edit ;;
|
|
329
|
+
Glob) mapped=glob ;;
|
|
330
|
+
Grep) mapped="grep" ;;
|
|
331
|
+
Read|WebFetch) mapped="read" ;;
|
|
332
|
+
Write) mapped="write" ;;
|
|
333
|
+
TodoWrite) mapped=todo ;;
|
|
334
|
+
WebSearch) mapped=web_search ;;
|
|
335
|
+
LS|NotebookRead|Skill|KillShell|BashOutput) continue ;;
|
|
336
|
+
*) mapped="$tok" ;;
|
|
337
|
+
esac
|
|
338
|
+
case "$seen" in *",$mapped,"*) continue ;; esac
|
|
339
|
+
seen="$seen$mapped,"
|
|
340
|
+
result="$result,$mapped"
|
|
341
|
+
done
|
|
342
|
+
echo "${result#,}"
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
pipe_run_omp() {
|
|
346
|
+
# $1 = agent label for metrics, $2 = skill invocation (e.g. "/review-mr"),
|
|
347
|
+
# $3 = allowed tools in Claude Code naming (optional, translated
|
|
348
|
+
# internally), $4 = model for the main loop (optional, e.g.
|
|
349
|
+
# $PIPE_MODEL_REVIEW; subagents keep the models from their own
|
|
350
|
+
# frontmatter), stdin = extra prompt (optional, usually empty).
|
|
351
|
+
local label="$1" skill="$2" tools="${3:-Agent,Read,Write,Edit,Glob,Grep,Bash}" model="${4:-}"
|
|
352
|
+
local omp_tools; omp_tools=$(pipe_translate_tools_to_omp "$tools")
|
|
353
|
+
local stdin_file; stdin_file=$(mktemp)
|
|
354
|
+
cat > "$stdin_file" || true
|
|
355
|
+
|
|
356
|
+
if [ "$(id -u)" -eq 0 ]; then
|
|
357
|
+
local runuser="pipelinebot"
|
|
358
|
+
id "$runuser" &>/dev/null || useradd -m -s /bin/bash "$runuser"
|
|
359
|
+
chown -R "$runuser:$runuser" "$PWD" "$PIPE_CONTEXT_DIR" "$stdin_file" 2>/dev/null || true
|
|
360
|
+
local runner; runner=$(mktemp)
|
|
361
|
+
{
|
|
362
|
+
printf '#!/bin/bash\nset -e\nexport HOME=/home/%s\n' "$runuser"
|
|
363
|
+
# Re-export the runtime environment the skill and usage-capture need.
|
|
364
|
+
local v
|
|
365
|
+
for v in $(compgen -v | grep -E '^(PIPE_|CI_|GH_|GITHUB_|OPENROUTER_)'); do
|
|
366
|
+
pipe_agent_secret_var "$v" && continue
|
|
367
|
+
printf 'export %s=%q\n' "$v" "${!v}"
|
|
368
|
+
done
|
|
369
|
+
# `su -m` preserves the parent environment, so explicitly remove every
|
|
370
|
+
# detected credential after exporting the safe runtime values above.
|
|
371
|
+
for v in $(compgen -e); do
|
|
372
|
+
pipe_agent_secret_var "$v" && printf 'unset %q\n' "$v"
|
|
373
|
+
done
|
|
374
|
+
printf 'cd %q\n' "$PWD"
|
|
375
|
+
printf 'source %q\n' "$SCRIPT_LIB_DIR/usage-capture-omp.sh"
|
|
376
|
+
printf 'export PIPE_CAPTURE_MODEL=%q\n' "$model"
|
|
377
|
+
if [ -n "$model" ]; then
|
|
378
|
+
printf 'capture_omp %q -- --yolo --no-session --no-title --model %q --tools %q -p %q < %q\n' \
|
|
379
|
+
"$label" "$model" "$omp_tools" "$skill" "$stdin_file"
|
|
380
|
+
else
|
|
381
|
+
printf 'capture_omp %q -- --yolo --no-session --no-title --tools %q -p %q < %q\n' \
|
|
382
|
+
"$label" "$omp_tools" "$skill" "$stdin_file"
|
|
383
|
+
fi
|
|
384
|
+
} > "$runner"
|
|
385
|
+
chmod +x "$runner"
|
|
386
|
+
chown "$runuser:$runuser" "$runner"
|
|
387
|
+
su -m "$runuser" -s /bin/bash "$runner" || true
|
|
388
|
+
chown -R root:root "$PWD" 2>/dev/null || true
|
|
389
|
+
rm -f "$runner"
|
|
390
|
+
else
|
|
391
|
+
(
|
|
392
|
+
pipe_scrub_agent_secrets
|
|
393
|
+
export PIPE_CAPTURE_MODEL="$model"
|
|
394
|
+
if [ -n "$model" ]; then
|
|
395
|
+
capture_omp "$label" -- --yolo --no-session --no-title --model "$model" --tools "$omp_tools" -p "$skill" < "$stdin_file"
|
|
396
|
+
else
|
|
397
|
+
capture_omp "$label" -- --yolo --no-session --no-title --tools "$omp_tools" -p "$skill" < "$stdin_file"
|
|
398
|
+
fi
|
|
399
|
+
) || true
|
|
400
|
+
fi
|
|
401
|
+
rm -f "$stdin_file"
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
# --- Harness dispatch ---------------------------------------------------
|
|
405
|
+
# Single entry point every job script calls. Same signature/contract as
|
|
406
|
+
# pipe_run_claude/pipe_run_omp themselves: $1 label, $2 skill, $3 tools
|
|
407
|
+
# (optional, Claude Code naming, translated internally when the target is
|
|
408
|
+
# omp), $4 model (optional).
|
|
409
|
+
|
|
410
|
+
pipe_run_agent() {
|
|
411
|
+
case "${PIPE_HARNESS:-claude}" in
|
|
412
|
+
omp) pipe_run_omp "$@" ;;
|
|
413
|
+
*) pipe_run_claude "$@" ;;
|
|
414
|
+
esac
|
|
415
|
+
}
|
|
416
|
+
|
|
216
417
|
# --- dotenv -----------------------------------------------------------------
|
|
217
418
|
|
|
218
419
|
# Load KEY=VALUE lines from a marker file into the current shell.
|
|
@@ -240,23 +441,24 @@ pipe_get_env() {
|
|
|
240
441
|
pipe_apply_escalation() {
|
|
241
442
|
local pm_env="$PIPE_CONTEXT_DIR/postmortem.env"
|
|
242
443
|
local pm_body="$PIPE_CONTEXT_DIR/postmortem.md"
|
|
243
|
-
local add remove category
|
|
444
|
+
local add remove category comment_file
|
|
244
445
|
add=$(pipe_get_env "$pm_env" ADD_LABELS); add=${add:-$PIPE_LABEL_STUCK}
|
|
245
446
|
remove=$(pipe_get_env "$pm_env" REMOVE_LABELS); remove=${remove:-$PIPE_LABEL_WIP}
|
|
246
447
|
category=$(pipe_get_env "$pm_env" FAILURE_CATEGORY); category=${category:-${1:-other}}
|
|
247
448
|
|
|
248
449
|
platform_set_labels "$add" "$remove"
|
|
249
450
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
451
|
+
comment_file="$PIPE_CONTEXT_DIR/auto-fix-stuck.md"
|
|
452
|
+
{
|
|
453
|
+
printf '🤖 **Auto-fix stuck after %s attempts. Diagnostic analysis:**\n\n' "$PIPE_FIX_LOOP_CAP"
|
|
454
|
+
if [ -s "$pm_body" ]; then
|
|
455
|
+
cat "$pm_body"
|
|
456
|
+
else
|
|
457
|
+
printf 'Automated fixes were exhausted after %s attempts. A human needs to take over.' "$PIPE_FIX_LOOP_CAP"
|
|
458
|
+
fi
|
|
459
|
+
printf '\n\nHuman intervention needed.\n'
|
|
460
|
+
} > "$comment_file"
|
|
461
|
+
platform_post_comment_file "$comment_file"
|
|
260
462
|
|
|
261
463
|
pipe_metric_event postmortem dev_stuck \
|
|
262
464
|
"$(jq -n --arg c "$category" --arg ctx "${2:-unknown}" '{failure_category: $c, context: $ctx}')"
|