agent-control-plane 0.1.16 → 0.2.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 +93 -14
- package/bin/pr-risk.sh +28 -6
- package/hooks/heartbeat-hooks.sh +62 -22
- package/npm/bin/agent-control-plane.js +322 -9
- package/package.json +1 -1
- package/references/architecture.md +8 -0
- package/references/control-plane-map.md +6 -2
- package/references/release-checklist.md +0 -2
- package/tools/bin/agent-github-update-labels +6 -1
- package/tools/bin/agent-project-catch-up-issue-pr-links +118 -0
- package/tools/bin/agent-project-catch-up-merged-prs +77 -21
- package/tools/bin/agent-project-catch-up-scheduled-issue-retries +123 -0
- package/tools/bin/agent-project-cleanup-session +84 -0
- package/tools/bin/agent-project-heartbeat-loop +10 -3
- package/tools/bin/agent-project-reconcile-issue-session +24 -12
- package/tools/bin/agent-project-run-claude-session +2 -2
- package/tools/bin/agent-project-run-kilo-session +346 -14
- package/tools/bin/agent-project-run-ollama-session +658 -0
- package/tools/bin/agent-project-run-openclaw-session +27 -25
- package/tools/bin/agent-project-run-opencode-session +354 -14
- package/tools/bin/agent-project-run-pi-session +479 -0
- package/tools/bin/agent-project-worker-status +1 -1
- package/tools/bin/flow-config-lib.sh +116 -3
- package/tools/bin/flow-resident-worker-lib.sh +1 -1
- package/tools/bin/flow-shell-lib.sh +5 -2
- package/tools/bin/heartbeat-recovery-preflight.sh +1 -0
- package/tools/bin/heartbeat-safe-auto.sh +105 -17
- package/tools/bin/install-project-launchd.sh +19 -2
- package/tools/bin/prepare-worktree.sh +4 -4
- package/tools/bin/profile-activate.sh +2 -2
- package/tools/bin/profile-adopt.sh +2 -2
- package/tools/bin/project-init.sh +1 -1
- package/tools/bin/project-runtimectl.sh +90 -7
- package/tools/bin/provider-cooldown-state.sh +14 -14
- package/tools/bin/render-flow-config.sh +30 -33
- package/tools/bin/run-codex-task.sh +53 -4
- package/tools/bin/scaffold-profile.sh +18 -3
- package/tools/bin/start-issue-worker.sh +1 -1
- package/tools/bin/start-pr-fix-worker.sh +30 -0
- package/tools/bin/start-pr-review-worker.sh +31 -0
- package/tools/bin/start-resident-issue-loop.sh +4 -4
- package/tools/bin/sync-agent-repo.sh +2 -2
- package/tools/bin/sync-dependency-baseline.sh +3 -3
- package/tools/bin/sync-shared-agent-home.sh +4 -1
- package/tools/templates/pr-fix-template.md +3 -7
- package/tools/templates/pr-merge-repair-template.md +3 -7
- package/tools/templates/pr-review-template.md +2 -1
|
@@ -17,9 +17,6 @@ CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
|
17
17
|
for _clean in ACP_CODING_WORKER ACP_OPENCLAW_MODEL ACP_CLAUDE_MODEL \
|
|
18
18
|
ACP_CLAUDE_TIMEOUT_SECONDS ACP_CLAUDE_MAX_ATTEMPTS ACP_CLAUDE_RETRY_BACKOFF_SECONDS \
|
|
19
19
|
ACP_OPENCLAW_THINKING ACP_OPENCLAW_TIMEOUT_SECONDS \
|
|
20
|
-
F_LOSNING_CODING_WORKER F_LOSNING_OPENCLAW_MODEL F_LOSNING_CLAUDE_MODEL \
|
|
21
|
-
F_LOSNING_CLAUDE_TIMEOUT_SECONDS F_LOSNING_CLAUDE_MAX_ATTEMPTS F_LOSNING_CLAUDE_RETRY_BACKOFF_SECONDS \
|
|
22
|
-
F_LOSNING_OPENCLAW_THINKING F_LOSNING_OPENCLAW_TIMEOUT_SECONDS \
|
|
23
20
|
CODING_WORKER; do
|
|
24
21
|
unset "${_clean}" 2>/dev/null || true
|
|
25
22
|
done
|
|
@@ -69,33 +66,33 @@ if [[ -f "${PROFILE_NOTES}" ]]; then
|
|
|
69
66
|
else
|
|
70
67
|
printf 'PROFILE_NOTES_EXISTS=no\n'
|
|
71
68
|
fi
|
|
72
|
-
printf 'EFFECTIVE_REPO_ROOT=%s\n' "$(config_or_env 'ACP_REPO_ROOT
|
|
73
|
-
printf 'EFFECTIVE_AGENT_REPO_ROOT=%s\n' "$(config_or_env 'ACP_AGENT_REPO_ROOT
|
|
74
|
-
printf 'EFFECTIVE_WORKTREE_ROOT=%s\n' "$(config_or_env 'ACP_WORKTREE_ROOT
|
|
75
|
-
printf 'EFFECTIVE_RUNS_ROOT=%s\n' "$(config_or_env 'ACP_RUNS_ROOT
|
|
76
|
-
printf 'EFFECTIVE_STATE_ROOT=%s\n' "$(config_or_env 'ACP_STATE_ROOT
|
|
77
|
-
printf 'EFFECTIVE_RETAINED_REPO_ROOT=%s\n' "$(config_or_env 'ACP_RETAINED_REPO_ROOT
|
|
78
|
-
printf 'EFFECTIVE_VSCODE_WORKSPACE_FILE=%s\n' "$(config_or_env 'ACP_VSCODE_WORKSPACE_FILE
|
|
79
|
-
printf 'EFFECTIVE_CODING_WORKER=%s\n' "$(config_or_env 'ACP_CODING_WORKER
|
|
80
|
-
printf 'EFFECTIVE_PROVIDER_QUOTA_COOLDOWNS=%s\n' "$(config_or_env 'ACP_PROVIDER_QUOTA_COOLDOWNS
|
|
81
|
-
printf 'EFFECTIVE_PROVIDER_POOL_ORDER=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_ORDER
|
|
82
|
-
printf 'EFFECTIVE_PROVIDER_POOL_NAME=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_POOL_NAME
|
|
83
|
-
printf 'EFFECTIVE_PROVIDER_POOL_BACKEND=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_BACKEND
|
|
84
|
-
printf 'EFFECTIVE_PROVIDER_POOL_MODEL=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_MODEL
|
|
85
|
-
printf 'EFFECTIVE_PROVIDER_POOL_KEY=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_KEY
|
|
86
|
-
printf 'EFFECTIVE_PROVIDER_POOLS_EXHAUSTED=%s\n' "$(config_or_env 'ACP_PROVIDER_POOLS_EXHAUSTED
|
|
87
|
-
printf 'EFFECTIVE_PROVIDER_POOL_SELECTION_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_SELECTION_REASON
|
|
88
|
-
printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH
|
|
89
|
-
printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_AT=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_AT
|
|
90
|
-
printf 'EFFECTIVE_PROVIDER_POOL_LAST_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_LAST_REASON
|
|
91
|
-
printf 'EFFECTIVE_CODEX_PROFILE_SAFE=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_SAFE
|
|
92
|
-
printf 'EFFECTIVE_CODEX_PROFILE_BYPASS=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_BYPASS
|
|
93
|
-
printf 'EFFECTIVE_CLAUDE_MODEL=%s\n' "$(config_or_env 'ACP_CLAUDE_MODEL
|
|
94
|
-
printf 'EFFECTIVE_CLAUDE_PERMISSION_MODE=%s\n' "$(config_or_env 'ACP_CLAUDE_PERMISSION_MODE
|
|
95
|
-
printf 'EFFECTIVE_CLAUDE_EFFORT=%s\n' "$(config_or_env 'ACP_CLAUDE_EFFORT
|
|
96
|
-
printf 'EFFECTIVE_CLAUDE_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_TIMEOUT_SECONDS
|
|
97
|
-
printf 'EFFECTIVE_CLAUDE_MAX_ATTEMPTS=%s\n' "$(config_or_env 'ACP_CLAUDE_MAX_ATTEMPTS
|
|
98
|
-
printf 'EFFECTIVE_CLAUDE_RETRY_BACKOFF_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_RETRY_BACKOFF_SECONDS
|
|
99
|
-
printf 'EFFECTIVE_OPENCLAW_MODEL=%s\n' "$(config_or_env 'ACP_OPENCLAW_MODEL
|
|
100
|
-
printf 'EFFECTIVE_OPENCLAW_THINKING=%s\n' "$(config_or_env 'ACP_OPENCLAW_THINKING
|
|
101
|
-
printf 'EFFECTIVE_OPENCLAW_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_OPENCLAW_TIMEOUT_SECONDS
|
|
69
|
+
printf 'EFFECTIVE_REPO_ROOT=%s\n' "$(config_or_env 'ACP_REPO_ROOT' repo.root)"
|
|
70
|
+
printf 'EFFECTIVE_AGENT_REPO_ROOT=%s\n' "$(config_or_env 'ACP_AGENT_REPO_ROOT' runtime.agent_repo_root)"
|
|
71
|
+
printf 'EFFECTIVE_WORKTREE_ROOT=%s\n' "$(config_or_env 'ACP_WORKTREE_ROOT' runtime.worktree_root)"
|
|
72
|
+
printf 'EFFECTIVE_RUNS_ROOT=%s\n' "$(config_or_env 'ACP_RUNS_ROOT' runtime.runs_root)"
|
|
73
|
+
printf 'EFFECTIVE_STATE_ROOT=%s\n' "$(config_or_env 'ACP_STATE_ROOT' runtime.state_root)"
|
|
74
|
+
printf 'EFFECTIVE_RETAINED_REPO_ROOT=%s\n' "$(config_or_env 'ACP_RETAINED_REPO_ROOT' runtime.retained_repo_root)"
|
|
75
|
+
printf 'EFFECTIVE_VSCODE_WORKSPACE_FILE=%s\n' "$(config_or_env 'ACP_VSCODE_WORKSPACE_FILE' runtime.vscode_workspace_file)"
|
|
76
|
+
printf 'EFFECTIVE_CODING_WORKER=%s\n' "$(config_or_env 'ACP_CODING_WORKER' execution.coding_worker)"
|
|
77
|
+
printf 'EFFECTIVE_PROVIDER_QUOTA_COOLDOWNS=%s\n' "$(config_or_env 'ACP_PROVIDER_QUOTA_COOLDOWNS' execution.provider_quota.cooldowns)"
|
|
78
|
+
printf 'EFFECTIVE_PROVIDER_POOL_ORDER=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_ORDER' execution.provider_pool_order)"
|
|
79
|
+
printf 'EFFECTIVE_PROVIDER_POOL_NAME=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_POOL_NAME')"
|
|
80
|
+
printf 'EFFECTIVE_PROVIDER_POOL_BACKEND=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_BACKEND')"
|
|
81
|
+
printf 'EFFECTIVE_PROVIDER_POOL_MODEL=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_MODEL')"
|
|
82
|
+
printf 'EFFECTIVE_PROVIDER_POOL_KEY=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_KEY')"
|
|
83
|
+
printf 'EFFECTIVE_PROVIDER_POOLS_EXHAUSTED=%s\n' "$(config_or_env 'ACP_PROVIDER_POOLS_EXHAUSTED')"
|
|
84
|
+
printf 'EFFECTIVE_PROVIDER_POOL_SELECTION_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_SELECTION_REASON')"
|
|
85
|
+
printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH')"
|
|
86
|
+
printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_AT=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_AT')"
|
|
87
|
+
printf 'EFFECTIVE_PROVIDER_POOL_LAST_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_LAST_REASON')"
|
|
88
|
+
printf 'EFFECTIVE_CODEX_PROFILE_SAFE=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_SAFE' execution.safe_profile)"
|
|
89
|
+
printf 'EFFECTIVE_CODEX_PROFILE_BYPASS=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_BYPASS' execution.bypass_profile)"
|
|
90
|
+
printf 'EFFECTIVE_CLAUDE_MODEL=%s\n' "$(config_or_env 'ACP_CLAUDE_MODEL' execution.claude.model)"
|
|
91
|
+
printf 'EFFECTIVE_CLAUDE_PERMISSION_MODE=%s\n' "$(config_or_env 'ACP_CLAUDE_PERMISSION_MODE' execution.claude.permission_mode)"
|
|
92
|
+
printf 'EFFECTIVE_CLAUDE_EFFORT=%s\n' "$(config_or_env 'ACP_CLAUDE_EFFORT' execution.claude.effort)"
|
|
93
|
+
printf 'EFFECTIVE_CLAUDE_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_TIMEOUT_SECONDS' execution.claude.timeout_seconds)"
|
|
94
|
+
printf 'EFFECTIVE_CLAUDE_MAX_ATTEMPTS=%s\n' "$(config_or_env 'ACP_CLAUDE_MAX_ATTEMPTS' execution.claude.max_attempts)"
|
|
95
|
+
printf 'EFFECTIVE_CLAUDE_RETRY_BACKOFF_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_RETRY_BACKOFF_SECONDS' execution.claude.retry_backoff_seconds)"
|
|
96
|
+
printf 'EFFECTIVE_OPENCLAW_MODEL=%s\n' "$(config_or_env 'ACP_OPENCLAW_MODEL' execution.openclaw.model)"
|
|
97
|
+
printf 'EFFECTIVE_OPENCLAW_THINKING=%s\n' "$(config_or_env 'ACP_OPENCLAW_THINKING' execution.openclaw.thinking)"
|
|
98
|
+
printf 'EFFECTIVE_OPENCLAW_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_OPENCLAW_TIMEOUT_SECONDS' execution.openclaw.timeout_seconds)"
|
|
@@ -35,7 +35,7 @@ RECONCILE_COMMAND=""
|
|
|
35
35
|
ADAPTER_ID="$(flow_resolve_adapter_id "${CONFIG_YAML}")"
|
|
36
36
|
ISSUE_SESSION_PREFIX="$(flow_resolve_issue_session_prefix "${CONFIG_YAML}")"
|
|
37
37
|
PR_SESSION_PREFIX="$(flow_resolve_pr_session_prefix "${CONFIG_YAML}")"
|
|
38
|
-
CODING_WORKER="${ACP_CODING_WORKER
|
|
38
|
+
CODING_WORKER="${ACP_CODING_WORKER:-codex}"
|
|
39
39
|
CODEX_PROFILE_SAFE="${ACP_CODEX_PROFILE_SAFE:-${F_LOSNING_CODEX_PROFILE_SAFE:-${CODEX_PROFILE_SAFE:-f_losning_safe_auto}}}"
|
|
40
40
|
CODEX_PROFILE_BYPASS="${ACP_CODEX_PROFILE_BYPASS:-${F_LOSNING_CODEX_PROFILE_BYPASS:-${CODEX_PROFILE_BYPASS:-f_losning_yolo}}}"
|
|
41
41
|
if [[ "$MODE" == "bypass" ]]; then
|
|
@@ -64,23 +64,47 @@ RESIDENT_OPENCLAW_CONFIG_PATH="${ACP_RESIDENT_OPENCLAW_CONFIG_PATH:-${F_LOSNING_
|
|
|
64
64
|
OPENCLAW_MODEL="${OPENCLAW_MODEL:-${ACP_OPENCLAW_MODEL:-${F_LOSNING_OPENCLAW_MODEL:-openrouter/qwen/qwen3.6-plus-preview:free}}}"
|
|
65
65
|
OPENCLAW_THINKING="${OPENCLAW_THINKING:-${ACP_OPENCLAW_THINKING:-${F_LOSNING_OPENCLAW_THINKING:-low}}}"
|
|
66
66
|
OPENCLAW_TIMEOUT_SECONDS="${OPENCLAW_TIMEOUT_SECONDS:-${ACP_OPENCLAW_TIMEOUT_SECONDS:-${F_LOSNING_OPENCLAW_TIMEOUT_SECONDS:-900}}}"
|
|
67
|
+
OLLAMA_MODEL="${ACP_OLLAMA_MODEL:-${F_LOSNING_OLLAMA_MODEL:-qwen2.5-coder:7b}}"
|
|
68
|
+
OLLAMA_BASE_URL="${ACP_OLLAMA_BASE_URL:-${F_LOSNING_OLLAMA_BASE_URL:-http://localhost:11434}}"
|
|
69
|
+
OLLAMA_TIMEOUT_SECONDS="${ACP_OLLAMA_TIMEOUT_SECONDS:-${F_LOSNING_OLLAMA_TIMEOUT_SECONDS:-900}}"
|
|
70
|
+
PI_MODEL="${ACP_PI_MODEL:-${F_LOSNING_PI_MODEL:-openrouter/qwen/qwen3.6-plus:free}}"
|
|
71
|
+
PI_THINKING="${ACP_PI_THINKING:-${F_LOSNING_PI_THINKING:-low}}"
|
|
72
|
+
PI_TIMEOUT_SECONDS="${ACP_PI_TIMEOUT_SECONDS:-${F_LOSNING_PI_TIMEOUT_SECONDS:-900}}"
|
|
73
|
+
PI_STALL_SECONDS="${ACP_PI_STALL_SECONDS:-${F_LOSNING_PI_STALL_SECONDS:-300}}"
|
|
74
|
+
OPENCODE_MODEL="${ACP_OPENCODE_MODEL:-${F_LOSNING_OPENCODE_MODEL:-anthropic/claude-sonnet-4-20250514}}"
|
|
75
|
+
OPENCODE_TIMEOUT_SECONDS="${ACP_OPENCODE_TIMEOUT_SECONDS:-${F_LOSNING_OPENCODE_TIMEOUT_SECONDS:-900}}"
|
|
76
|
+
KILO_MODEL="${ACP_KILO_MODEL:-${F_LOSNING_KILO_MODEL:-anthropic/claude-sonnet-4-20250514}}"
|
|
77
|
+
KILO_TIMEOUT_SECONDS="${ACP_KILO_TIMEOUT_SECONDS:-${F_LOSNING_KILO_TIMEOUT_SECONDS:-900}}"
|
|
67
78
|
printf -v SESSION_Q '%q' "$SESSION"
|
|
68
79
|
printf -v CONFIG_YAML_Q '%q' "$CONFIG_YAML"
|
|
69
80
|
printf -v ADAPTER_ID_Q '%q' "$ADAPTER_ID"
|
|
70
|
-
|
|
81
|
+
printf -v CANONICAL_REPO_ROOT_Q '%q' "$CANONICAL_REPO_ROOT"
|
|
82
|
+
RECONCILE_ENV_PREFIX="ACP_PROJECT_ID=${ADAPTER_ID_Q} AGENT_PROJECT_ID=${ADAPTER_ID_Q} AGENT_CONTROL_PLANE_CONFIG=${CONFIG_YAML_Q} ACP_CONFIG=${CONFIG_YAML_Q} ACP_ROOT=${CANONICAL_REPO_ROOT_Q} AGENT_CONTROL_PLANE_ROOT=${CANONICAL_REPO_ROOT_Q}"
|
|
83
|
+
|
|
84
|
+
# The materialized skills surface is cleaned up after each heartbeat cycle.
|
|
85
|
+
# Reconcile runs post-tmux via nohup, after the skills dir is gone.
|
|
86
|
+
# Use the permanent runtime-home/tools/bin path derived from AGENT_PLATFORM_HOME.
|
|
87
|
+
_runtime_tools_bin="${AGENT_PLATFORM_HOME:-${HOME}/.agent-runtime}/runtime-home/tools/bin"
|
|
88
|
+
if [[ -f "${_runtime_tools_bin}/reconcile-pr-worker.sh" ]]; then
|
|
89
|
+
RECONCILE_ISSUE_BIN="${_runtime_tools_bin}/reconcile-issue-worker.sh"
|
|
90
|
+
RECONCILE_PR_BIN="${_runtime_tools_bin}/reconcile-pr-worker.sh"
|
|
91
|
+
else
|
|
92
|
+
RECONCILE_ISSUE_BIN="${WORKSPACE_DIR}/bin/reconcile-issue-worker.sh"
|
|
93
|
+
RECONCILE_PR_BIN="${WORKSPACE_DIR}/bin/reconcile-pr-worker.sh"
|
|
94
|
+
fi
|
|
71
95
|
|
|
72
96
|
case "$SESSION" in
|
|
73
97
|
"${ISSUE_SESSION_PREFIX}"*)
|
|
74
98
|
TASK_KIND="issue"
|
|
75
99
|
TASK_ID="${ISSUE_ID:-${SESSION#${ISSUE_SESSION_PREFIX}}}"
|
|
76
100
|
if [[ "${RESIDENT_WORKER_ENABLED}" != "yes" ]]; then
|
|
77
|
-
RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${
|
|
101
|
+
RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${RECONCILE_ISSUE_BIN} ${SESSION_Q}"
|
|
78
102
|
fi
|
|
79
103
|
;;
|
|
80
104
|
"${PR_SESSION_PREFIX}"*)
|
|
81
105
|
TASK_KIND="pr"
|
|
82
106
|
TASK_ID="${PR_NUMBER:-${SESSION#${PR_SESSION_PREFIX}}}"
|
|
83
|
-
RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${
|
|
107
|
+
RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${RECONCILE_PR_BIN} ${SESSION_Q}"
|
|
84
108
|
;;
|
|
85
109
|
esac
|
|
86
110
|
|
|
@@ -219,11 +243,36 @@ case "$CODING_WORKER" in
|
|
|
219
243
|
bash "${FLOW_TOOLS_DIR}/agent-project-run-openclaw-session" "${ARGS[@]}"
|
|
220
244
|
;;
|
|
221
245
|
opencode)
|
|
246
|
+
ARGS+=(
|
|
247
|
+
--opencode-model "${OPENCODE_MODEL}"
|
|
248
|
+
--opencode-timeout-seconds "${OPENCODE_TIMEOUT_SECONDS}"
|
|
249
|
+
)
|
|
222
250
|
bash "${FLOW_TOOLS_DIR}/agent-project-run-opencode-session" "${ARGS[@]}"
|
|
223
251
|
;;
|
|
224
252
|
kilo)
|
|
253
|
+
ARGS+=(
|
|
254
|
+
--kilo-model "${KILO_MODEL}"
|
|
255
|
+
--kilo-timeout-seconds "${KILO_TIMEOUT_SECONDS}"
|
|
256
|
+
)
|
|
225
257
|
bash "${FLOW_TOOLS_DIR}/agent-project-run-kilo-session" "${ARGS[@]}"
|
|
226
258
|
;;
|
|
259
|
+
ollama)
|
|
260
|
+
ARGS+=(
|
|
261
|
+
--ollama-model "${OLLAMA_MODEL}"
|
|
262
|
+
--ollama-base-url "${OLLAMA_BASE_URL}"
|
|
263
|
+
--ollama-timeout-seconds "${OLLAMA_TIMEOUT_SECONDS}"
|
|
264
|
+
)
|
|
265
|
+
bash "${FLOW_TOOLS_DIR}/agent-project-run-ollama-session" "${ARGS[@]}"
|
|
266
|
+
;;
|
|
267
|
+
pi)
|
|
268
|
+
ARGS+=(
|
|
269
|
+
--pi-model "${PI_MODEL}"
|
|
270
|
+
--pi-thinking "${PI_THINKING}"
|
|
271
|
+
--pi-timeout-seconds "${PI_TIMEOUT_SECONDS}"
|
|
272
|
+
--pi-stall-seconds "${PI_STALL_SECONDS}"
|
|
273
|
+
)
|
|
274
|
+
bash "${FLOW_TOOLS_DIR}/agent-project-run-pi-session" "${ARGS[@]}"
|
|
275
|
+
;;
|
|
227
276
|
*)
|
|
228
277
|
echo "unsupported coding worker: ${CODING_WORKER}" >&2
|
|
229
278
|
exit 1
|
|
@@ -22,7 +22,7 @@ Options:
|
|
|
22
22
|
--worktree-root <path> Worktree parent root
|
|
23
23
|
--retained-repo-root <path> Optional retained/manual checkout root
|
|
24
24
|
--vscode-workspace-file <path> Optional VS Code workspace file
|
|
25
|
-
--coding-worker <codex|openclaw|claude>
|
|
25
|
+
--coding-worker <codex|openclaw|claude|ollama|pi|opencode|kilo>
|
|
26
26
|
Default coding backend (default: openclaw)
|
|
27
27
|
--claude-model <model> Claude model alias or full name
|
|
28
28
|
--claude-permission-mode <mode> Claude permission mode (default: acceptEdits)
|
|
@@ -97,9 +97,9 @@ if [[ ! "$profile_id" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
|
|
|
97
97
|
fi
|
|
98
98
|
|
|
99
99
|
case "$coding_worker" in
|
|
100
|
-
codex|openclaw|claude) ;;
|
|
100
|
+
codex|openclaw|claude|ollama|pi|opencode|kilo) ;;
|
|
101
101
|
*)
|
|
102
|
-
echo "--coding-worker must be codex, openclaw, or
|
|
102
|
+
echo "--coding-worker must be codex, openclaw, claude, ollama, pi, opencode, or kilo" >&2
|
|
103
103
|
exit 1
|
|
104
104
|
;;
|
|
105
105
|
esac
|
|
@@ -271,6 +271,21 @@ execution:
|
|
|
271
271
|
model: "${openclaw_model}"
|
|
272
272
|
thinking: "${openclaw_thinking}"
|
|
273
273
|
timeout_seconds: ${openclaw_timeout_seconds}
|
|
274
|
+
ollama:
|
|
275
|
+
model: "qwen2.5-coder:7b"
|
|
276
|
+
base_url: "http://localhost:11434"
|
|
277
|
+
timeout_seconds: 900
|
|
278
|
+
pi:
|
|
279
|
+
model: "openrouter/qwen/qwen3.6-plus:free"
|
|
280
|
+
thinking: "low"
|
|
281
|
+
timeout_seconds: 900
|
|
282
|
+
stall_seconds: 300
|
|
283
|
+
opencode:
|
|
284
|
+
model: "anthropic/claude-sonnet-4-20250514"
|
|
285
|
+
timeout_seconds: 900
|
|
286
|
+
kilo:
|
|
287
|
+
model: "anthropic/claude-sonnet-4-20250514"
|
|
288
|
+
timeout_seconds: 900
|
|
274
289
|
review_requires_independent_final_review: true
|
|
275
290
|
verification:
|
|
276
291
|
web_playwright_command: "pnpm exec playwright test"
|
|
@@ -30,7 +30,7 @@ LOCAL_INSTALL_POLICY_BIN="${WORKSPACE_DIR}/bin/issue-requires-local-workspace-in
|
|
|
30
30
|
SESSION="${ISSUE_SESSION_PREFIX}${ISSUE_ID}"
|
|
31
31
|
RUN_DIR="${RUNS_ROOT}/${SESSION}"
|
|
32
32
|
UPDATE_LABELS_BIN="${WORKSPACE_DIR}/bin/agent-github-update-labels"
|
|
33
|
-
CODING_WORKER="${ACP_CODING_WORKER
|
|
33
|
+
CODING_WORKER="${ACP_CODING_WORKER:-codex}"
|
|
34
34
|
launch_success="no"
|
|
35
35
|
label_rollback_armed="no"
|
|
36
36
|
RECURRING_CHECKLIST_SYNC_BIN="${FLOW_TOOLS_DIR}/sync-recurring-issue-checklist.sh"
|
|
@@ -133,6 +133,34 @@ PR_LINKED_ISSUE_ID="$(jq -r '.linkedIssueId // ""' <<<"$RISK_JSON")"
|
|
|
133
133
|
PR_FILES_TEXT="$(jq -r '.files[] | "- " + .' <<<"$RISK_JSON")"
|
|
134
134
|
PR_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
|
|
135
135
|
PR_DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-${F_LOSNING_DEPENDENCY_SOURCE_ROOT:-$PR_REPO_ROOT}}"
|
|
136
|
+
render_pr_context_reads_text() {
|
|
137
|
+
local repo_root="${1:?repo root required}"
|
|
138
|
+
local -a candidate_paths=(
|
|
139
|
+
"${repo_root}/AGENTS.md"
|
|
140
|
+
"${repo_root}/openspec/AGENT_RULES.md"
|
|
141
|
+
"${repo_root}/openspec/AGENTS.md"
|
|
142
|
+
"${repo_root}/openspec/project.md"
|
|
143
|
+
"${repo_root}/openspec/CONVENTIONS.md"
|
|
144
|
+
"${repo_root}/docs/TESTING_AND_SEED_POLICY.md"
|
|
145
|
+
)
|
|
146
|
+
local -a existing_paths=()
|
|
147
|
+
local candidate_path=""
|
|
148
|
+
|
|
149
|
+
for candidate_path in "${candidate_paths[@]}"; do
|
|
150
|
+
if [[ -f "${candidate_path}" ]]; then
|
|
151
|
+
existing_paths+=("${candidate_path}")
|
|
152
|
+
fi
|
|
153
|
+
done
|
|
154
|
+
|
|
155
|
+
if [[ "${#existing_paths[@]}" -eq 0 ]]; then
|
|
156
|
+
printf '%s\n' '- No repo-specific context files were found under the expected AGENTS/OpenSpec/testing-doc locations; rely on the current diff and nearby source.'
|
|
157
|
+
return 0
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
printf '%s\n' "${existing_paths[@]}" | sed 's/^/- `/' | sed 's/$/`/'
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
PR_CONTEXT_READS_TEXT="$(render_pr_context_reads_text "${PR_REPO_ROOT}")"
|
|
136
164
|
PR_CHECK_FAILURES_TEXT="$(jq -r '(.checkFailures + .pendingChecks)[]? | "- " + .' <<<"$RISK_JSON")"
|
|
137
165
|
if [[ -z "$PR_CHECK_FAILURES_TEXT" ]]; then
|
|
138
166
|
PR_CHECK_FAILURES_TEXT="- none reported"
|
|
@@ -293,6 +321,7 @@ PR_MERGE_STATE_STATUS="$PR_MERGE_STATE_STATUS" \
|
|
|
293
321
|
PR_MERGEABLE_STATUS="$PR_MERGEABLE_STATUS" \
|
|
294
322
|
PR_CHECKS_TEXT="$PR_CHECKS_TEXT" \
|
|
295
323
|
PR_FILES_TEXT="$PR_FILES_TEXT" \
|
|
324
|
+
PR_CONTEXT_READS_TEXT="$PR_CONTEXT_READS_TEXT" \
|
|
296
325
|
PR_CHECK_FAILURES_TEXT="$PR_CHECK_FAILURES_TEXT" \
|
|
297
326
|
PR_MISSING_REASONS_TEXT="$PR_MISSING_REASONS_TEXT" \
|
|
298
327
|
PR_REVIEW_FINDINGS_TEXT="$PR_REVIEW_FINDINGS_TEXT" \
|
|
@@ -403,6 +432,7 @@ const replacements = {
|
|
|
403
432
|
'{PR_MERGEABLE_STATUS}': process.env.PR_MERGEABLE_STATUS || '',
|
|
404
433
|
'{PR_CHECKS_TEXT}': process.env.PR_CHECKS_TEXT || '',
|
|
405
434
|
'{PR_FILES_TEXT}': process.env.PR_FILES_TEXT || '',
|
|
435
|
+
'{PR_CONTEXT_READS_TEXT}': process.env.PR_CONTEXT_READS_TEXT || '',
|
|
406
436
|
'{PR_CHECK_FAILURES_TEXT}': process.env.PR_CHECK_FAILURES_TEXT || '',
|
|
407
437
|
'{PR_MISSING_REASONS_TEXT}': process.env.PR_MISSING_REASONS_TEXT || '',
|
|
408
438
|
'{PR_REVIEW_FINDINGS_TEXT}': process.env.PR_REVIEW_FINDINGS_TEXT || '',
|
|
@@ -123,6 +123,35 @@ PR_FILES_TEXT="$(jq -r '.files[] | "- " + .' <<<"$RISK_JSON")"
|
|
|
123
123
|
PR_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
|
|
124
124
|
PR_DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-${F_LOSNING_DEPENDENCY_SOURCE_ROOT:-$PR_REPO_ROOT}}"
|
|
125
125
|
|
|
126
|
+
render_pr_context_reads_text() {
|
|
127
|
+
local repo_root="${1:?repo root required}"
|
|
128
|
+
local -a candidate_paths=(
|
|
129
|
+
"${repo_root}/AGENTS.md"
|
|
130
|
+
"${repo_root}/openspec/AGENT_RULES.md"
|
|
131
|
+
"${repo_root}/openspec/AGENTS.md"
|
|
132
|
+
"${repo_root}/openspec/project.md"
|
|
133
|
+
"${repo_root}/openspec/CONVENTIONS.md"
|
|
134
|
+
"${repo_root}/docs/TESTING_AND_SEED_POLICY.md"
|
|
135
|
+
)
|
|
136
|
+
local -a existing_paths=()
|
|
137
|
+
local candidate_path=""
|
|
138
|
+
|
|
139
|
+
for candidate_path in "${candidate_paths[@]}"; do
|
|
140
|
+
if [[ -f "${candidate_path}" ]]; then
|
|
141
|
+
existing_paths+=("${candidate_path}")
|
|
142
|
+
fi
|
|
143
|
+
done
|
|
144
|
+
|
|
145
|
+
if [[ "${#existing_paths[@]}" -eq 0 ]]; then
|
|
146
|
+
printf '%s\n' '- No repo-specific context files were found under the expected AGENTS/OpenSpec/testing-doc locations; rely on the current diff and nearby source.'
|
|
147
|
+
return 0
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
printf '%s\n' "${existing_paths[@]}" | sed 's/^/- `/' | sed 's/$/`/'
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
PR_CONTEXT_READS_TEXT="$(render_pr_context_reads_text "${PR_REPO_ROOT}")"
|
|
154
|
+
|
|
126
155
|
case "$PR_AGENT_LANE" in
|
|
127
156
|
double-check-1)
|
|
128
157
|
PR_REVIEW_STAGE_TEXT="Independent agent double-check 1 of 2. A clean pass should advance this PR to the second review pass, not merge it yet."
|
|
@@ -157,6 +186,7 @@ PR_CHECKS_BYPASSED="$PR_CHECKS_BYPASSED" \
|
|
|
157
186
|
PR_MERGE_STATE_STATUS="$PR_MERGE_STATE_STATUS" \
|
|
158
187
|
PR_CHECKS_TEXT="$PR_CHECKS_TEXT" \
|
|
159
188
|
PR_FILES_TEXT="$PR_FILES_TEXT" \
|
|
189
|
+
PR_CONTEXT_READS_TEXT="$PR_CONTEXT_READS_TEXT" \
|
|
160
190
|
PR_REPO_ROOT="$PR_REPO_ROOT" \
|
|
161
191
|
PR_DEPENDENCY_SOURCE_ROOT="$PR_DEPENDENCY_SOURCE_ROOT" \
|
|
162
192
|
REPO_SLUG="$REPO_SLUG" \
|
|
@@ -183,6 +213,7 @@ const replacements = {
|
|
|
183
213
|
'{PR_MERGE_STATE_STATUS}': process.env.PR_MERGE_STATE_STATUS || '',
|
|
184
214
|
'{PR_CHECKS_TEXT}': process.env.PR_CHECKS_TEXT || '',
|
|
185
215
|
'{PR_FILES_TEXT}': process.env.PR_FILES_TEXT || '',
|
|
216
|
+
'{PR_CONTEXT_READS_TEXT}': process.env.PR_CONTEXT_READS_TEXT || '',
|
|
186
217
|
'{REPO_ROOT}': process.env.PR_REPO_ROOT || '',
|
|
187
218
|
'{DEPENDENCY_SOURCE_ROOT}': process.env.PR_DEPENDENCY_SOURCE_ROOT || '',
|
|
188
219
|
};
|
|
@@ -29,7 +29,7 @@ PENDING_LAUNCH_DIR="${ACP_PENDING_LAUNCH_DIR:-${F_LOSNING_PENDING_LAUNCH_DIR:-${
|
|
|
29
29
|
SCHEDULED_STATE_DIR="${STATE_ROOT}/scheduled-issues"
|
|
30
30
|
CONTROLLER_FILE="$(flow_resident_issue_controller_file "${CONFIG_YAML}" "${ISSUE_ID}")"
|
|
31
31
|
RESIDENT_META_FILE="$(flow_resident_issue_meta_file "${CONFIG_YAML}" "${ISSUE_ID}")"
|
|
32
|
-
CODING_WORKER="${ACP_CODING_WORKER
|
|
32
|
+
CODING_WORKER="${ACP_CODING_WORKER:-codex}"
|
|
33
33
|
MAX_IMMEDIATE_CYCLES="$(flow_resident_issue_controller_max_immediate_cycles "${CONFIG_YAML}")"
|
|
34
34
|
POLL_SECONDS="$(flow_resident_issue_controller_poll_seconds "${CONFIG_YAML}")"
|
|
35
35
|
IDLE_TIMEOUT_SECONDS="$(flow_resident_issue_controller_idle_timeout_seconds "${CONFIG_YAML}")"
|
|
@@ -192,7 +192,7 @@ issue_id_is_scheduled() {
|
|
|
192
192
|
|
|
193
193
|
controller_refresh_execution_context() {
|
|
194
194
|
unset \
|
|
195
|
-
ACP_CODING_WORKER
|
|
195
|
+
ACP_CODING_WORKER \
|
|
196
196
|
ACP_CODEX_PROFILE_SAFE F_LOSNING_CODEX_PROFILE_SAFE \
|
|
197
197
|
ACP_CODEX_PROFILE_BYPASS F_LOSNING_CODEX_PROFILE_BYPASS \
|
|
198
198
|
ACP_CLAUDE_MODEL F_LOSNING_CLAUDE_MODEL \
|
|
@@ -216,7 +216,7 @@ controller_refresh_execution_context() {
|
|
|
216
216
|
ACP_PROVIDER_POOL_LAST_REASON F_LOSNING_PROVIDER_POOL_LAST_REASON
|
|
217
217
|
flow_export_execution_env "${CONFIG_YAML}"
|
|
218
218
|
flow_export_project_env_aliases
|
|
219
|
-
CODING_WORKER="${ACP_CODING_WORKER
|
|
219
|
+
CODING_WORKER="${ACP_CODING_WORKER:-codex}"
|
|
220
220
|
controller_capture_active_provider_context
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -544,7 +544,7 @@ controller_provider_state() {
|
|
|
544
544
|
|
|
545
545
|
provider_state="$(
|
|
546
546
|
env \
|
|
547
|
-
-u ACP_CODING_WORKER
|
|
547
|
+
-u ACP_CODING_WORKER \
|
|
548
548
|
-u ACP_CODEX_PROFILE_SAFE -u F_LOSNING_CODEX_PROFILE_SAFE \
|
|
549
549
|
-u ACP_CODEX_PROFILE_BYPASS -u F_LOSNING_CODEX_PROFILE_BYPASS \
|
|
550
550
|
-u ACP_CLAUDE_MODEL -u F_LOSNING_CLAUDE_MODEL \
|
|
@@ -6,11 +6,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
6
6
|
source "${SCRIPT_DIR}/flow-config-lib.sh"
|
|
7
7
|
|
|
8
8
|
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
9
|
-
SOURCE_REPO_ROOT="${ACP_SOURCE_REPO_ROOT:-$
|
|
9
|
+
SOURCE_REPO_ROOT="${ACP_SOURCE_REPO_ROOT:-$(flow_resolve_retained_repo_root "${CONFIG_YAML}")}"
|
|
10
10
|
CANONICAL_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
|
|
11
11
|
AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
|
|
12
12
|
DEFAULT_BRANCH="$(flow_resolve_default_branch "${CONFIG_YAML}")"
|
|
13
|
-
REMOTE_NAME="${ACP_REMOTE_NAME
|
|
13
|
+
REMOTE_NAME="${ACP_REMOTE_NAME:-origin}"
|
|
14
14
|
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
15
15
|
FLOW_TOOLS_DIR="${FLOW_SKILL_DIR}/tools/bin"
|
|
16
16
|
|
|
@@ -13,9 +13,9 @@ STATE_ROOT="$(flow_resolve_state_root "${CONFIG_YAML}")"
|
|
|
13
13
|
LOCK_DIR="${STATE_ROOT}/dependency-baseline.lock"
|
|
14
14
|
PID_FILE="${LOCK_DIR}/pid"
|
|
15
15
|
HASH_FILE="${STATE_ROOT}/dependency-baseline.sha256"
|
|
16
|
-
PACKAGE_MANAGER_BIN="${ACP_PACKAGE_MANAGER_BIN
|
|
17
|
-
WORKSPACE_BUILD_PACKAGES_RAW="${ACP_WORKSPACE_BUILD_PACKAGES
|
|
18
|
-
WORKSPACE_BUILD_ARTIFACTS_RAW="${ACP_WORKSPACE_BUILD_ARTIFACTS
|
|
16
|
+
PACKAGE_MANAGER_BIN="${ACP_PACKAGE_MANAGER_BIN:-pnpm}"
|
|
17
|
+
WORKSPACE_BUILD_PACKAGES_RAW="${ACP_WORKSPACE_BUILD_PACKAGES:-}"
|
|
18
|
+
WORKSPACE_BUILD_ARTIFACTS_RAW="${ACP_WORKSPACE_BUILD_ARTIFACTS:-}"
|
|
19
19
|
declare -a WORKSPACE_BUILD_PACKAGES=()
|
|
20
20
|
declare -a WORKSPACE_BUILD_ARTIFACTS=()
|
|
21
21
|
|
|
@@ -207,7 +207,10 @@ sync_tree_rsync() {
|
|
|
207
207
|
local target_dir="${2:?target dir required}"
|
|
208
208
|
[[ -d "${source_dir}" ]] || return 0
|
|
209
209
|
mkdir -p "${target_dir}"
|
|
210
|
-
rsync -a --delete --exclude='.git/' "${source_dir}/" "${target_dir}/"
|
|
210
|
+
if rsync -a --delete --exclude='.git/' "${source_dir}/" "${target_dir}/"; then
|
|
211
|
+
return 0
|
|
212
|
+
fi
|
|
213
|
+
sync_tree_copy_mode "${source_dir}" "${target_dir}"
|
|
211
214
|
}
|
|
212
215
|
|
|
213
216
|
reset_runtime_skill_targets() {
|
|
@@ -2,13 +2,9 @@ You are the PR repair worker for `{REPO_SLUG}`.
|
|
|
2
2
|
|
|
3
3
|
Before making any change:
|
|
4
4
|
|
|
5
|
-
1. Read
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
4. If present, read `{REPO_ROOT}/openspec/project.md`.
|
|
9
|
-
5. If present, read `{REPO_ROOT}/openspec/CONVENTIONS.md`.
|
|
10
|
-
6. If present, read `{REPO_ROOT}/docs/TESTING_AND_SEED_POLICY.md`.
|
|
11
|
-
7. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
|
|
5
|
+
1. Read the following repo context before changing code:
|
|
6
|
+
{PR_CONTEXT_READS_TEXT}
|
|
7
|
+
2. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
|
|
12
8
|
|
|
13
9
|
PR metadata:
|
|
14
10
|
|
|
@@ -2,13 +2,9 @@ You are the PR merge-repair worker for `{REPO_SLUG}`.
|
|
|
2
2
|
|
|
3
3
|
Before making any change:
|
|
4
4
|
|
|
5
|
-
1. Read
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
4. If present, read `{REPO_ROOT}/openspec/project.md`.
|
|
9
|
-
5. If present, read `{REPO_ROOT}/openspec/CONVENTIONS.md`.
|
|
10
|
-
6. If present, read `{REPO_ROOT}/docs/TESTING_AND_SEED_POLICY.md`.
|
|
11
|
-
7. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
|
|
5
|
+
1. Read the following repo context before changing code:
|
|
6
|
+
{PR_CONTEXT_READS_TEXT}
|
|
7
|
+
2. Stay on this PR branch worktree. Do not push or mutate GitHub from inside the worker.
|
|
12
8
|
|
|
13
9
|
PR metadata:
|
|
14
10
|
|
|
@@ -2,7 +2,8 @@ You are the PR review and final-merge worker for `{REPO_SLUG}`.
|
|
|
2
2
|
|
|
3
3
|
Before making any decision:
|
|
4
4
|
|
|
5
|
-
1. Read
|
|
5
|
+
1. Read the following repo context before deciding:
|
|
6
|
+
{PR_CONTEXT_READS_TEXT}
|
|
6
7
|
2. Do not edit product code in this worktree. This is review and final-review only.
|
|
7
8
|
3. Never run dependency bootstrap or workspace-mutating commands here.
|
|
8
9
|
|