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.
Files changed (47) hide show
  1. package/README.md +93 -14
  2. package/bin/pr-risk.sh +28 -6
  3. package/hooks/heartbeat-hooks.sh +62 -22
  4. package/npm/bin/agent-control-plane.js +322 -9
  5. package/package.json +1 -1
  6. package/references/architecture.md +8 -0
  7. package/references/control-plane-map.md +6 -2
  8. package/references/release-checklist.md +0 -2
  9. package/tools/bin/agent-github-update-labels +6 -1
  10. package/tools/bin/agent-project-catch-up-issue-pr-links +118 -0
  11. package/tools/bin/agent-project-catch-up-merged-prs +77 -21
  12. package/tools/bin/agent-project-catch-up-scheduled-issue-retries +123 -0
  13. package/tools/bin/agent-project-cleanup-session +84 -0
  14. package/tools/bin/agent-project-heartbeat-loop +10 -3
  15. package/tools/bin/agent-project-reconcile-issue-session +24 -12
  16. package/tools/bin/agent-project-run-claude-session +2 -2
  17. package/tools/bin/agent-project-run-kilo-session +346 -14
  18. package/tools/bin/agent-project-run-ollama-session +658 -0
  19. package/tools/bin/agent-project-run-openclaw-session +27 -25
  20. package/tools/bin/agent-project-run-opencode-session +354 -14
  21. package/tools/bin/agent-project-run-pi-session +479 -0
  22. package/tools/bin/agent-project-worker-status +1 -1
  23. package/tools/bin/flow-config-lib.sh +116 -3
  24. package/tools/bin/flow-resident-worker-lib.sh +1 -1
  25. package/tools/bin/flow-shell-lib.sh +5 -2
  26. package/tools/bin/heartbeat-recovery-preflight.sh +1 -0
  27. package/tools/bin/heartbeat-safe-auto.sh +105 -17
  28. package/tools/bin/install-project-launchd.sh +19 -2
  29. package/tools/bin/prepare-worktree.sh +4 -4
  30. package/tools/bin/profile-activate.sh +2 -2
  31. package/tools/bin/profile-adopt.sh +2 -2
  32. package/tools/bin/project-init.sh +1 -1
  33. package/tools/bin/project-runtimectl.sh +90 -7
  34. package/tools/bin/provider-cooldown-state.sh +14 -14
  35. package/tools/bin/render-flow-config.sh +30 -33
  36. package/tools/bin/run-codex-task.sh +53 -4
  37. package/tools/bin/scaffold-profile.sh +18 -3
  38. package/tools/bin/start-issue-worker.sh +1 -1
  39. package/tools/bin/start-pr-fix-worker.sh +30 -0
  40. package/tools/bin/start-pr-review-worker.sh +31 -0
  41. package/tools/bin/start-resident-issue-loop.sh +4 -4
  42. package/tools/bin/sync-agent-repo.sh +2 -2
  43. package/tools/bin/sync-dependency-baseline.sh +3 -3
  44. package/tools/bin/sync-shared-agent-home.sh +4 -1
  45. package/tools/templates/pr-fix-template.md +3 -7
  46. package/tools/templates/pr-merge-repair-template.md +3 -7
  47. package/tools/templates/pr-review-template.md +2 -1
@@ -118,7 +118,7 @@ flow_resident_issue_backend_supported() {
118
118
  local backend="${1:-}"
119
119
 
120
120
  case "${backend}" in
121
- codex|openclaw|claude)
121
+ codex|openclaw|claude|ollama|pi)
122
122
  return 0
123
123
  ;;
124
124
  *)
@@ -35,7 +35,6 @@ flow_export_compat_env_aliases() {
35
35
  flow_export_env_alias_if_unset F_LOSNING_MEMORY_DIR ACP_MEMORY_DIR
36
36
  flow_export_env_alias_if_unset F_LOSNING_RETAINED_REPO_ROOT ACP_RETAINED_REPO_ROOT
37
37
  flow_export_env_alias_if_unset F_LOSNING_VSCODE_WORKSPACE_FILE ACP_VSCODE_WORKSPACE_FILE
38
- flow_export_env_alias_if_unset F_LOSNING_CODING_WORKER ACP_CODING_WORKER
39
38
  flow_export_env_alias_if_unset F_LOSNING_CODEX_PROFILE_SAFE ACP_CODEX_PROFILE_SAFE
40
39
  flow_export_env_alias_if_unset F_LOSNING_CODEX_PROFILE_BYPASS ACP_CODEX_PROFILE_BYPASS
41
40
  flow_export_env_alias_if_unset F_LOSNING_CLAUDE_MODEL ACP_CLAUDE_MODEL
@@ -84,7 +83,6 @@ flow_export_canonical_env_aliases() {
84
83
  flow_export_env_alias_if_unset ACP_MEMORY_DIR F_LOSNING_MEMORY_DIR
85
84
  flow_export_env_alias_if_unset ACP_RETAINED_REPO_ROOT F_LOSNING_RETAINED_REPO_ROOT
86
85
  flow_export_env_alias_if_unset ACP_VSCODE_WORKSPACE_FILE F_LOSNING_VSCODE_WORKSPACE_FILE
87
- flow_export_env_alias_if_unset ACP_CODING_WORKER F_LOSNING_CODING_WORKER
88
86
  flow_export_env_alias_if_unset ACP_CODEX_PROFILE_SAFE F_LOSNING_CODEX_PROFILE_SAFE
89
87
  flow_export_env_alias_if_unset ACP_CODEX_PROFILE_BYPASS F_LOSNING_CODEX_PROFILE_BYPASS
90
88
  flow_export_env_alias_if_unset ACP_CLAUDE_MODEL F_LOSNING_CLAUDE_MODEL
@@ -223,6 +221,11 @@ resolve_shared_agent_home() {
223
221
  flow_root="$(resolve_flow_skill_dir "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}")"
224
222
  fi
225
223
 
224
+ if flow_is_skill_root "${flow_root}"; then
225
+ flow_print_dir "${flow_root}"
226
+ return 0
227
+ fi
228
+
226
229
  flow_print_dir "${flow_root}/../../.."
227
230
  }
228
231
 
@@ -80,6 +80,7 @@ run_preflight_test "heartbeat-no-tmux-sessions" "${TEST_DIR}/test-heartbeat-safe
80
80
  run_preflight_test "heartbeat-static-capacity-without-quota-cache" "${TEST_DIR}/test-heartbeat-safe-auto-static-capacity-without-quota-cache.sh"
81
81
  run_preflight_test "heartbeat-openclaw-skips-codex-quota" "${TEST_DIR}/test-heartbeat-safe-auto-openclaw-skips-codex-quota.sh"
82
82
  run_preflight_test "heartbeat-empty-schedule-label-sync" "${TEST_DIR}/test-heartbeat-sync-issue-labels-empty-schedule.sh"
83
+ run_preflight_test "heartbeat-open-issue-terminal-sync" "${TEST_DIR}/test-heartbeat-sync-open-agent-issues-terminal-clears-running.sh"
83
84
  run_preflight_test "heartbeat-open-pr-terminal-sync" "${TEST_DIR}/test-heartbeat-sync-open-agent-prs-terminal-clears-running.sh"
84
85
  run_preflight_test "heartbeat-pr-launch-dedup" "${TEST_DIR}/test-heartbeat-loop-pr-launch-dedup.sh"
85
86
  run_preflight_test "heartbeat-auth-wait-capacity" "${TEST_DIR}/test-heartbeat-loop-auth-wait-does-not-consume-capacity.sh"
@@ -17,6 +17,8 @@ flow_export_execution_env "${CONFIG_YAML}"
17
17
  AGENT_ROOT="$(flow_resolve_agent_root "${CONFIG_YAML}")"
18
18
  RUNS_ROOT="$(flow_resolve_runs_root "${CONFIG_YAML}")"
19
19
  STATE_ROOT="$(flow_resolve_state_root "${CONFIG_YAML}")"
20
+ HISTORY_ROOT="$(flow_resolve_history_root "${CONFIG_YAML}")"
21
+ WORKTREE_ROOT="$(flow_resolve_worktree_root "${CONFIG_YAML}")"
20
22
  MEMORY_DIR="${ACP_MEMORY_DIR:-${F_LOSNING_MEMORY_DIR:-${AGENT_CONTROL_PLANE_WORKSPACE:-$HOME/.agent-runtime/control-plane/workspace}/memory}}"
21
23
  REPO_SLUG="$(flow_resolve_repo_slug "${CONFIG_YAML}")"
22
24
  MAX_CONCURRENT_WORKERS="${ACP_MAX_CONCURRENT_WORKERS:-${F_LOSNING_MAX_CONCURRENT_WORKERS:-20}}"
@@ -29,7 +31,7 @@ MAX_CONCURRENT_BLOCKED_RECOVERY_ISSUE_WORKERS="${ACP_MAX_CONCURRENT_BLOCKED_RECO
29
31
  BLOCKED_RECOVERY_COOLDOWN_SECONDS="${ACP_BLOCKED_RECOVERY_COOLDOWN_SECONDS:-${F_LOSNING_BLOCKED_RECOVERY_COOLDOWN_SECONDS:-900}}"
30
32
  MAX_OPEN_AGENT_PRS_FOR_RECURRING="${ACP_MAX_OPEN_AGENT_PRS_FOR_RECURRING:-${F_LOSNING_MAX_OPEN_AGENT_PRS_FOR_RECURRING:-12}}"
31
33
  MAX_LAUNCHES_PER_HEARTBEAT="${ACP_MAX_LAUNCHES_PER_HEARTBEAT:-${F_LOSNING_MAX_LAUNCHES_PER_HEARTBEAT:-$MAX_CONCURRENT_WORKERS}}"
32
- CODING_WORKER="${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-codex}}"
34
+ CODING_WORKER="${ACP_CODING_WORKER:-codex}"
33
35
  # The catchup and shared heartbeat passes can legitimately take a few minutes
34
36
  # once they reconcile stale sessions, sync labels, and launch multiple workers.
35
37
  CATCHUP_TIMEOUT_SECONDS="${ACP_CATCHUP_TIMEOUT_SECONDS:-${F_LOSNING_CATCHUP_TIMEOUT_SECONDS:-180}}"
@@ -67,9 +69,12 @@ AGENT_WORKTREE_AUDIT_TIMEOUT_SECONDS="${ACP_AGENT_WORKTREE_AUDIT_TIMEOUT_SECONDS
67
69
  LOCK_DIR="${STATE_ROOT}/heartbeat-loop.lock"
68
70
  PID_FILE="${LOCK_DIR}/pid"
69
71
  SHARED_LOOP_PID_FILE="${STATE_ROOT}/shared-heartbeat-loop.pid"
72
+ SHARED_LOOP_STATUS_FILE="${STATE_ROOT}/shared-heartbeat-loop.env"
70
73
  QUOTA_LOCK_DIR="${STATE_ROOT}/quota-preflight.lock"
71
74
  QUOTA_PID_FILE="${QUOTA_LOCK_DIR}/pid"
72
75
 
76
+ mkdir -p "${AGENT_ROOT}" "${RUNS_ROOT}" "${STATE_ROOT}" "${HISTORY_ROOT}" "${WORKTREE_ROOT}" "${MEMORY_DIR}"
77
+
73
78
  acquire_lock() {
74
79
  mkdir -p "${STATE_ROOT}"
75
80
 
@@ -124,6 +129,29 @@ release_quota_lock() {
124
129
  rm -rf "${QUOTA_LOCK_DIR}"
125
130
  }
126
131
 
132
+ write_shared_loop_status() {
133
+ local state="${1:-}"
134
+ local status="${2:-}"
135
+ local timestamp=""
136
+ local tmp_file=""
137
+
138
+ timestamp="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
139
+ mkdir -p "${STATE_ROOT}"
140
+ tmp_file="$(mktemp)"
141
+ if [[ -f "${SHARED_LOOP_STATUS_FILE}" ]]; then
142
+ grep -Ev '^(STATE|STATUS|STARTED_AT|UPDATED_AT)=' "${SHARED_LOOP_STATUS_FILE}" >"${tmp_file}" || true
143
+ fi
144
+ printf 'STATE=%s\n' "${state}" >>"${tmp_file}"
145
+ if [[ -n "${status}" ]]; then
146
+ printf 'STATUS=%s\n' "${status}" >>"${tmp_file}"
147
+ fi
148
+ if [[ "${state}" == "running" ]]; then
149
+ printf 'STARTED_AT=%s\n' "${timestamp}" >>"${tmp_file}"
150
+ fi
151
+ printf 'UPDATED_AT=%s\n' "${timestamp}" >>"${tmp_file}"
152
+ mv "${tmp_file}" "${SHARED_LOOP_STATUS_FILE}"
153
+ }
154
+
127
155
  run_with_timeout() {
128
156
  local timeout_seconds="${1:?timeout seconds required}"
129
157
  shift
@@ -530,6 +558,7 @@ fi
530
558
  derive_dynamic_limits
531
559
 
532
560
  printf '[%s] shared heartbeat loop start\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
561
+ write_shared_loop_status "running" ""
533
562
  if ACP_TIMEOUT_CHILD_PID_FILE="${SHARED_LOOP_PID_FILE}" \
534
563
  F_LOSNING_TIMEOUT_CHILD_PID_FILE="${SHARED_LOOP_PID_FILE}" \
535
564
  run_with_timeout "${HEARTBEAT_LOOP_TIMEOUT_SECONDS}" \
@@ -563,9 +592,11 @@ printf '[%s] shared heartbeat loop start\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
563
592
  --heavy-running-label "E2E_ISSUE" \
564
593
  --heavy-deferred-key "E2E_DEFERRED" \
565
594
  --heavy-deferred-message "E2E-heavy issues remain queued until the single e2e slot is free."; then
595
+ write_shared_loop_status "idle" "0"
566
596
  printf '[%s] shared heartbeat loop end status=0\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
567
597
  else
568
598
  loop_status=$?
599
+ write_shared_loop_status "idle" "${loop_status}"
569
600
  if [[ "${loop_status}" -eq 124 ]]; then
570
601
  printf 'HEARTBEAT_LOOP_TIMEOUT=yes\n'
571
602
  fi
@@ -573,21 +604,78 @@ else
573
604
  exit "${loop_status}"
574
605
  fi
575
606
 
576
- printf '[%s] merged-pr catchup start\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
577
- if run_with_timeout "${CATCHUP_TIMEOUT_SECONDS}" \
578
- env \
579
- ACP_RUNS_ROOT="$RUNS_ROOT" \
580
- F_LOSNING_RUNS_ROOT="$RUNS_ROOT" \
581
- bash "${FLOW_TOOLS_DIR}/agent-project-catch-up-merged-prs" \
582
- --repo-slug "$REPO_SLUG" \
583
- --state-root "$STATE_ROOT" \
584
- --hook-file "$HOOK_FILE" \
585
- --limit 100; then
586
- printf '[%s] merged-pr catchup end status=0\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
587
- else
588
- catchup_status=$?
589
- if [[ "${catchup_status}" -eq 124 ]]; then
590
- printf 'CATCHUP_TIMEOUT=yes\n'
607
+ # ── Throttled catch-up passes ──────────────────────────────────────────────────
608
+ # These scripts fetch merged/closed PRs and linked issues which change rarely.
609
+ # Run them at most once every CATCHUP_INTERVAL_SECONDS (default 300 = 5 min)
610
+ # to avoid burning API quota on every heartbeat cycle.
611
+ CATCHUP_INTERVAL_SECONDS="${ACP_CATCHUP_INTERVAL_SECONDS:-${F_LOSNING_CATCHUP_INTERVAL_SECONDS:-300}}"
612
+ CATCHUP_STAMP_FILE="${STATE_ROOT}/last-catchup-timestamp"
613
+ _catchup_now="$(date +%s)"
614
+ _catchup_last="0"
615
+ if [[ -f "${CATCHUP_STAMP_FILE}" ]]; then
616
+ _catchup_last="$(cat "${CATCHUP_STAMP_FILE}" 2>/dev/null || echo 0)"
617
+ fi
618
+ _catchup_age=$(( _catchup_now - _catchup_last ))
619
+
620
+ if [[ "${_catchup_age}" -ge "${CATCHUP_INTERVAL_SECONDS}" ]]; then
621
+ printf '[%s] merged-pr catchup start\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
622
+ if run_with_timeout "${CATCHUP_TIMEOUT_SECONDS}" \
623
+ env \
624
+ ACP_RUNS_ROOT="$RUNS_ROOT" \
625
+ F_LOSNING_RUNS_ROOT="$RUNS_ROOT" \
626
+ bash "${FLOW_TOOLS_DIR}/agent-project-catch-up-merged-prs" \
627
+ --repo-slug "$REPO_SLUG" \
628
+ --state-root "$STATE_ROOT" \
629
+ --hook-file "$HOOK_FILE" \
630
+ --limit 100; then
631
+ printf '[%s] merged-pr catchup end status=0\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
632
+ else
633
+ catchup_status=$?
634
+ if [[ "${catchup_status}" -eq 124 ]]; then
635
+ printf 'CATCHUP_TIMEOUT=yes\n'
636
+ fi
637
+ printf '[%s] merged-pr catchup end status=%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "${catchup_status}"
638
+ fi
639
+
640
+ printf '[%s] linked-pr issue catchup start\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
641
+ if run_with_timeout "${CATCHUP_TIMEOUT_SECONDS}" \
642
+ env \
643
+ ACP_RUNS_ROOT="$RUNS_ROOT" \
644
+ F_LOSNING_RUNS_ROOT="$RUNS_ROOT" \
645
+ bash "${FLOW_TOOLS_DIR}/agent-project-catch-up-issue-pr-links" \
646
+ --repo-slug "$REPO_SLUG" \
647
+ --state-root "$STATE_ROOT" \
648
+ --hook-file "$HOOK_FILE" \
649
+ --limit 100; then
650
+ printf '[%s] linked-pr issue catchup end status=0\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
651
+ else
652
+ linked_issue_catchup_status=$?
653
+ if [[ "${linked_issue_catchup_status}" -eq 124 ]]; then
654
+ printf 'LINKED_ISSUE_CATCHUP_TIMEOUT=yes\n'
655
+ fi
656
+ printf '[%s] linked-pr issue catchup end status=%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "${linked_issue_catchup_status}"
657
+ fi
658
+
659
+ printf '[%s] scheduled-issue retry catchup start\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
660
+ if run_with_timeout "${CATCHUP_TIMEOUT_SECONDS}" \
661
+ env \
662
+ ACP_RUNS_ROOT="$RUNS_ROOT" \
663
+ F_LOSNING_RUNS_ROOT="$RUNS_ROOT" \
664
+ bash "${FLOW_TOOLS_DIR}/agent-project-catch-up-scheduled-issue-retries" \
665
+ --repo-slug "$REPO_SLUG" \
666
+ --state-root "$STATE_ROOT" \
667
+ --hook-file "$HOOK_FILE" \
668
+ --limit 100; then
669
+ printf '[%s] scheduled-issue retry catchup end status=0\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
670
+ else
671
+ scheduled_issue_catchup_status=$?
672
+ if [[ "${scheduled_issue_catchup_status}" -eq 124 ]]; then
673
+ printf 'SCHEDULED_ISSUE_CATCHUP_TIMEOUT=yes\n'
674
+ fi
675
+ printf '[%s] scheduled-issue retry catchup end status=%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "${scheduled_issue_catchup_status}"
591
676
  fi
592
- printf '[%s] merged-pr catchup end status=%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "${catchup_status}"
677
+
678
+ printf '%s' "${_catchup_now}" >"${CATCHUP_STAMP_FILE}"
679
+ else
680
+ printf '[%s] catchup skipped (age=%ss, interval=%ss)\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "${_catchup_age}" "${CATCHUP_INTERVAL_SECONDS}"
593
681
  fi
@@ -54,7 +54,7 @@ build_launchd_base_path() {
54
54
  local tool_name=""
55
55
  local tool_dir=""
56
56
 
57
- for tool_name in node gh git python3 openclaw codex claude; do
57
+ for tool_name in node gh git python3 openclaw codex claude ollama pi crush kilo; do
58
58
  tool_dir="$(resolved_tool_dir "${tool_name}" || true)"
59
59
  append_path_dir path_value "${tool_dir}"
60
60
  done
@@ -112,7 +112,14 @@ fi
112
112
  PROFILE_ID="$(flow_resolve_adapter_id "${CONFIG_YAML}")"
113
113
  profile_slug="$(printf '%s' "${PROFILE_ID}" | tr -c 'A-Za-z0-9._-' '-')"
114
114
  HOME_DIR="${ACP_PROJECT_RUNTIME_HOME_DIR:-${HOME:-}}"
115
- SOURCE_HOME="${ACP_PROJECT_RUNTIME_SOURCE_HOME:-$(cd "${FLOW_SKILL_DIR}/../../.." && pwd)}"
115
+ SOURCE_HOME="${ACP_PROJECT_RUNTIME_SOURCE_HOME:-}"
116
+ if [[ -z "${SOURCE_HOME}" ]]; then
117
+ if flow_is_skill_root "${FLOW_SKILL_DIR}"; then
118
+ SOURCE_HOME="${FLOW_SKILL_DIR}"
119
+ else
120
+ SOURCE_HOME="$(cd "${FLOW_SKILL_DIR}/../../.." && pwd)"
121
+ fi
122
+ fi
116
123
  RUNTIME_HOME="${ACP_PROJECT_RUNTIME_RUNTIME_HOME:-${HOME_DIR}/.agent-runtime/runtime-home}"
117
124
  WORKSPACE_DIR="${ACP_PROJECT_RUNTIME_WORKSPACE_DIR:-${HOME_DIR}/.agent-runtime/control-plane/workspace}"
118
125
  PROFILE_REGISTRY_ROOT="${ACP_PROJECT_RUNTIME_PROFILE_REGISTRY_ROOT:-${ACP_PROFILE_REGISTRY_ROOT:-${HOME_DIR}/.agent-runtime/control-plane/profiles}}"
@@ -120,6 +127,7 @@ LAUNCH_AGENTS_DIR="${ACP_PROJECT_RUNTIME_LAUNCH_AGENTS_DIR:-${HOME_DIR}/Library/
120
127
  LOG_DIR="${ACP_PROJECT_RUNTIME_LOG_DIR:-${HOME_DIR}/.agent-runtime/logs}"
121
128
  LABEL="${label_override:-${ACP_PROJECT_RUNTIME_LAUNCHD_LABEL:-ai.agent.project.${profile_slug}}}"
122
129
  BASE_PATH="$(build_launchd_base_path)"
130
+ CODING_WORKER_OVERRIDE="${ACP_PROJECT_RUNTIME_CODING_WORKER:-${ACP_CODING_WORKER:-}}"
123
131
  SYNC_SCRIPT="${ACP_PROJECT_RUNTIME_SYNC_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/sync-shared-agent-home.sh}"
124
132
  BOOTSTRAP_SCRIPT="${ACP_PROJECT_RUNTIME_BOOTSTRAP_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/project-launchd-bootstrap.sh}"
125
133
  SUPERVISOR_SCRIPT="${ACP_PROJECT_RUNTIME_SUPERVISOR_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/project-runtime-supervisor.sh}"
@@ -152,6 +160,15 @@ export AGENT_PROJECT_ID='${PROFILE_ID}'
152
160
  export ACP_PROJECT_RUNTIME_PATH='${BASE_PATH}'
153
161
  export ACP_PROJECT_RUNTIME_SYNC_SCRIPT='${SYNC_SCRIPT}'
154
162
  export ACP_PROFILE_REGISTRY_ROOT='${PROFILE_REGISTRY_ROOT}'
163
+ EOF
164
+
165
+ if [[ -n "${CODING_WORKER_OVERRIDE}" ]]; then
166
+ cat >>"${WRAPPER_PATH}" <<EOF
167
+ export ACP_CODING_WORKER='${CODING_WORKER_OVERRIDE}'
168
+ EOF
169
+ fi
170
+
171
+ cat >>"${WRAPPER_PATH}" <<EOF
155
172
  exec bash '${SUPERVISOR_SCRIPT}' --bootstrap-script '${BOOTSTRAP_SCRIPT}' --pid-file '${SUPERVISOR_PID_FILE}' --delay-seconds '${delay_seconds}' --interval-seconds '${interval_seconds}'
156
173
  EOF
157
174
  chmod +x "${WRAPPER_PATH}"
@@ -9,10 +9,10 @@ CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
9
9
  AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
10
10
  CANONICAL_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
11
11
  DEFAULT_DEPENDENCY_SOURCE_ROOT="$CANONICAL_REPO_ROOT"
12
- DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-${F_LOSNING_DEPENDENCY_SOURCE_ROOT:-$DEFAULT_DEPENDENCY_SOURCE_ROOT}}"
13
- SYNC_DEPENDENCY_BASELINE_SCRIPT="${ACP_SYNC_DEPENDENCY_BASELINE_SCRIPT:-${F_LOSNING_SYNC_DEPENDENCY_BASELINE_SCRIPT:-${SCRIPT_DIR}/sync-dependency-baseline.sh}}"
14
- PACKAGE_MANAGER_BIN="${ACP_PACKAGE_MANAGER_BIN:-${F_LOSNING_PACKAGE_MANAGER_BIN:-pnpm}}"
15
- LOCAL_WORKSPACE_INSTALL="${ACP_WORKTREE_LOCAL_INSTALL:-${F_LOSNING_WORKTREE_LOCAL_INSTALL:-false}}"
12
+ DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-$DEFAULT_DEPENDENCY_SOURCE_ROOT}"
13
+ SYNC_DEPENDENCY_BASELINE_SCRIPT="${ACP_SYNC_DEPENDENCY_BASELINE_SCRIPT:-${SCRIPT_DIR}/sync-dependency-baseline.sh}"
14
+ PACKAGE_MANAGER_BIN="${ACP_PACKAGE_MANAGER_BIN:-pnpm}"
15
+ LOCAL_WORKSPACE_INSTALL="${ACP_WORKTREE_LOCAL_INSTALL:-false}"
16
16
  WORKTREE="${1:?usage: prepare-worktree.sh WORKTREE}"
17
17
 
18
18
  realpath_safe() {
@@ -56,8 +56,8 @@ AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
56
56
  WORKTREE_ROOT="$(flow_resolve_worktree_root "${CONFIG_YAML}")"
57
57
  RUNS_ROOT="$(flow_resolve_runs_root "${CONFIG_YAML}")"
58
58
  STATE_ROOT="$(flow_resolve_state_root "${CONFIG_YAML}")"
59
- CODING_WORKER="${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-codex}}"
60
- ACTIVE_PROVIDER_POOL_NAME="${ACP_ACTIVE_PROVIDER_POOL_NAME:-${F_LOSNING_ACTIVE_PROVIDER_POOL_NAME:-}}"
59
+ CODING_WORKER="${ACP_CODING_WORKER:-codex}"
60
+ ACTIVE_PROVIDER_POOL_NAME="${ACP_ACTIVE_PROVIDER_POOL_NAME:-}"
61
61
 
62
62
  if [[ "${exports_only}" == "1" ]]; then
63
63
  printf 'export ACP_PROJECT_ID=%q
@@ -69,8 +69,8 @@ HISTORY_ROOT="$(flow_resolve_history_root "${CONFIG_YAML}")"
69
69
  WORKTREE_ROOT="$(flow_resolve_worktree_root "${CONFIG_YAML}")"
70
70
  RETAINED_REPO_ROOT="$(flow_resolve_retained_repo_root "${CONFIG_YAML}")"
71
71
  VSCODE_WORKSPACE_FILE="$(flow_resolve_vscode_workspace_file "${CONFIG_YAML}")"
72
- REMOTE_NAME="${ACP_REMOTE_NAME:-${F_LOSNING_REMOTE_NAME:-origin}}"
73
- SOURCE_REPO_ROOT="${source_repo_root_override:-${ACP_SOURCE_REPO_ROOT:-${F_LOSNING_SOURCE_REPO_ROOT:-${RETAINED_REPO_ROOT}}}}"
72
+ REMOTE_NAME="${ACP_REMOTE_NAME:-origin}"
73
+ SOURCE_REPO_ROOT="${source_repo_root_override:-${ACP_SOURCE_REPO_ROOT:-${RETAINED_REPO_ROOT}}}"
74
74
  PROFILE_LINK="${AGENT_ROOT}/control-plane.yaml"
75
75
  WORKSPACE_LINK="${AGENT_ROOT}/workspace.code-workspace"
76
76
  INSTALLED_PROFILE_DIR="$(dirname "${CONFIG_YAML}")"
@@ -42,7 +42,7 @@ Common options:
42
42
  --worktree-root <path> Worktree parent root
43
43
  --retained-repo-root <path> Retained/manual checkout root
44
44
  --vscode-workspace-file <path> VS Code workspace file
45
- --coding-worker <codex|openclaw|claude>
45
+ --coding-worker <codex|openclaw|claude|ollama|pi|opencode|kilo>
46
46
  --claude-model <model>
47
47
  --claude-permission-mode <mode>
48
48
  --claude-effort <level>
@@ -168,13 +168,15 @@ join_by_comma() {
168
168
  runtime_started() {
169
169
  local heartbeat=""
170
170
  local shared_loop=""
171
- local supervisor=""
171
+ local active_sessions=""
172
+ local pending_pids=""
172
173
 
173
174
  heartbeat="$(heartbeat_pid)"
174
175
  shared_loop="$(shared_loop_pid)"
175
- supervisor="$(supervisor_pid)"
176
+ active_sessions="$(collect_active_tmux_sessions | sort -u)"
177
+ pending_pids="$(collect_pending_launch_pids | sort -u)"
176
178
 
177
- [[ -n "${heartbeat}" || -n "${shared_loop}" || -n "${supervisor}" ]]
179
+ [[ -n "${heartbeat}" || -n "${shared_loop}" || -n "${active_sessions}" || -n "${pending_pids}" ]]
178
180
  }
179
181
 
180
182
  wait_for_runtime_start() {
@@ -197,6 +199,13 @@ sync_stamp_value() {
197
199
  | sed -e "s/^'//" -e "s/'$//"
198
200
  }
199
201
 
202
+ shared_loop_status_value() {
203
+ local key="${1:?key required}"
204
+ local file="${STATE_ROOT}/shared-heartbeat-loop.env"
205
+ [[ -f "${file}" ]] || return 1
206
+ awk -F= -v target="${key}" '$1 == target {print $2; exit}' "${file}" 2>/dev/null
207
+ }
208
+
200
209
  tmux_session_exists() {
201
210
  local session="${1:-}"
202
211
  [[ -n "${TMUX_BIN}" && -n "${session}" ]] || return 1
@@ -218,14 +227,53 @@ collect_run_sessions() {
218
227
  done < <(find "${RUNS_ROOT}" -mindepth 2 -maxdepth 2 -type f -name run.env 2>/dev/null | sort -u)
219
228
  }
220
229
 
230
+ list_tmux_sessions() {
231
+ [[ -n "${TMUX_BIN}" ]] || return 0
232
+ "${TMUX_BIN}" list-sessions -F '#S' 2>/dev/null || true
233
+ }
234
+
235
+ collect_profile_tmux_sessions() {
236
+ local issue_prefix=""
237
+ local pr_prefix=""
238
+ local session=""
239
+
240
+ issue_prefix="$(flow_resolve_issue_session_prefix "${CONFIG_YAML}")"
241
+ pr_prefix="$(flow_resolve_pr_session_prefix "${CONFIG_YAML}")"
242
+
243
+ while IFS= read -r session; do
244
+ [[ -n "${session}" ]] || continue
245
+ case "${session}" in
246
+ "${issue_prefix}"*|"${pr_prefix}"*)
247
+ printf '%s\n' "${session}"
248
+ ;;
249
+ esac
250
+ done < <(list_tmux_sessions)
251
+ }
252
+
221
253
  collect_active_tmux_sessions() {
254
+ local known_sessions=""
222
255
  local session=""
256
+ known_sessions="$(collect_run_sessions | sort -u)"
257
+
223
258
  while IFS= read -r session; do
224
259
  [[ -n "${session}" ]] || continue
225
- if tmux_session_exists "${session}"; then
260
+ if tmux_session_exists "${session}" && grep -Fxq "${session}" <<<"${known_sessions}"; then
226
261
  printf '%s\n' "${session}"
227
262
  fi
228
- done < <(collect_run_sessions)
263
+ done < <(collect_profile_tmux_sessions)
264
+ }
265
+
266
+ collect_stale_tmux_sessions() {
267
+ local known_sessions=""
268
+ local session=""
269
+ known_sessions="$(collect_run_sessions | sort -u)"
270
+
271
+ while IFS= read -r session; do
272
+ [[ -n "${session}" ]] || continue
273
+ if tmux_session_exists "${session}" && ! grep -Fxq "${session}" <<<"${known_sessions}"; then
274
+ printf '%s\n' "${session}"
275
+ fi
276
+ done < <(collect_profile_tmux_sessions)
229
277
  }
230
278
 
231
279
  collect_repo_shared_loop_pids() {
@@ -336,15 +384,21 @@ print_status() {
336
384
  local supervisor=""
337
385
  local controller_pids=""
338
386
  local active_sessions=""
387
+ local stale_sessions=""
339
388
  local pending_pids=""
340
389
  local runtime_status="stopped"
341
390
  local controller_count="0"
342
391
  local active_session_count="0"
392
+ local stale_session_count="0"
343
393
  local pending_count="0"
344
394
  local launchd_state=""
345
395
  local runtime_sync_status=""
346
396
  local runtime_sync_updated_at=""
347
397
  local runtime_sync_fingerprint=""
398
+ local shared_loop_state=""
399
+ local shared_loop_last_status=""
400
+ local shared_loop_started_at=""
401
+ local shared_loop_updated_at=""
348
402
 
349
403
  heartbeat="$(heartbeat_pid)"
350
404
  shared_loop="$(shared_loop_pid)"
@@ -352,16 +406,18 @@ print_status() {
352
406
  heartbeat_parent="$(heartbeat_parent_pid)"
353
407
  controller_pids="$(collect_controller_pids | sort -u)"
354
408
  active_sessions="$(collect_active_tmux_sessions | sort -u)"
409
+ stale_sessions="$(collect_stale_tmux_sessions | sort -u)"
355
410
  pending_pids="$(collect_pending_launch_pids | sort -u)"
356
411
 
357
412
  [[ -n "${controller_pids}" ]] && controller_count="$(printf '%s\n' "${controller_pids}" | awk 'NF {c+=1} END {print c+0}')"
358
413
  [[ -n "${active_sessions}" ]] && active_session_count="$(printf '%s\n' "${active_sessions}" | awk 'NF {c+=1} END {print c+0}')"
414
+ [[ -n "${stale_sessions}" ]] && stale_session_count="$(printf '%s\n' "${stale_sessions}" | awk 'NF {c+=1} END {print c+0}')"
359
415
  [[ -n "${pending_pids}" ]] && pending_count="$(printf '%s\n' "${pending_pids}" | awk 'NF {c+=1} END {print c+0}')"
360
416
 
361
- if [[ -n "${heartbeat}" || -n "${shared_loop}" || -n "${supervisor}" || "${controller_count}" != "0" || "${active_session_count}" != "0" ]]; then
417
+ if [[ -n "${heartbeat}" || -n "${shared_loop}" || "${active_session_count}" != "0" ]]; then
362
418
  runtime_status="running"
363
419
  fi
364
- if [[ -z "${heartbeat}" && -z "${supervisor}" && "${active_session_count}" == "0" && ( -n "${shared_loop}" || "${controller_count}" != "0" ) ]]; then
420
+ if [[ "${runtime_status}" != "running" && ( -n "${supervisor}" || "${controller_count}" != "0" || "${pending_count}" != "0" || "${stale_session_count}" != "0" ) ]]; then
365
421
  runtime_status="partial"
366
422
  fi
367
423
 
@@ -369,6 +425,10 @@ print_status() {
369
425
  runtime_sync_status="$(sync_stamp_value "SYNC_STATUS" || true)"
370
426
  runtime_sync_updated_at="$(sync_stamp_value "UPDATED_AT" || true)"
371
427
  runtime_sync_fingerprint="$(sync_stamp_value "SOURCE_FINGERPRINT" || true)"
428
+ shared_loop_state="$(shared_loop_status_value "STATE" || true)"
429
+ shared_loop_last_status="$(shared_loop_status_value "STATUS" || true)"
430
+ shared_loop_started_at="$(shared_loop_status_value "STARTED_AT" || true)"
431
+ shared_loop_updated_at="$(shared_loop_status_value "UPDATED_AT" || true)"
372
432
 
373
433
  printf 'PROFILE_ID=%s\n' "${PROFILE_ID}"
374
434
  printf 'CONFIG_YAML=%s\n' "${CONFIG_YAML}"
@@ -382,12 +442,18 @@ print_status() {
382
442
  printf 'HEARTBEAT_PID=%s\n' "${heartbeat}"
383
443
  printf 'HEARTBEAT_PARENT_PID=%s\n' "${heartbeat_parent}"
384
444
  printf 'SHARED_LOOP_PID=%s\n' "${shared_loop}"
445
+ printf 'SHARED_LOOP_STATE=%s\n' "${shared_loop_state}"
446
+ printf 'SHARED_LOOP_LAST_STATUS=%s\n' "${shared_loop_last_status}"
447
+ printf 'SHARED_LOOP_STARTED_AT=%s\n' "${shared_loop_started_at}"
448
+ printf 'SHARED_LOOP_UPDATED_AT=%s\n' "${shared_loop_updated_at}"
385
449
  printf 'SUPERVISOR_PID=%s\n' "${supervisor}"
386
450
  printf 'CONTROLLER_COUNT=%s\n' "${controller_count}"
387
451
  printf 'ACTIVE_TMUX_SESSION_COUNT=%s\n' "${active_session_count}"
452
+ printf 'STALE_TMUX_SESSION_COUNT=%s\n' "${stale_session_count}"
388
453
  printf 'PENDING_LAUNCH_COUNT=%s\n' "${pending_count}"
389
454
  printf 'CONTROLLER_PIDS=%s\n' "$(printf '%s\n' "${controller_pids}" | join_by_comma)"
390
455
  printf 'ACTIVE_TMUX_SESSIONS=%s\n' "$(printf '%s\n' "${active_sessions}" | join_by_comma)"
456
+ printf 'STALE_TMUX_SESSIONS=%s\n' "$(printf '%s\n' "${stale_sessions}" | join_by_comma)"
391
457
  printf 'PENDING_LAUNCH_PIDS=%s\n' "$(printf '%s\n' "${pending_pids}" | join_by_comma)"
392
458
  printf 'SYNC_STAMP_FILE=%s\n' "${SYNC_STAMP_FILE}"
393
459
  printf 'RUNTIME_SYNC_STATUS=%s\n' "${runtime_sync_status}"
@@ -452,12 +518,18 @@ clear_running_labels_after_stop() {
452
518
  fi
453
519
 
454
520
  issue_json="$(flow_github_issue_list_json "${REPO_SLUG}" open 100 2>/dev/null || printf '[]\n')"
521
+ if [[ "${issue_json}" == "[]" ]]; then
522
+ issue_json="$(gh issue list -R "${REPO_SLUG}" --state open --limit 100 --json number,labels 2>/dev/null || printf '[]\n')"
523
+ fi
455
524
  while IFS= read -r number; do
456
525
  [[ -n "${number}" ]] || continue
457
526
  bash "${UPDATE_LABELS_SCRIPT}" --repo-slug "${REPO_SLUG}" --number "${number}" --remove agent-running >/dev/null 2>&1 || true
458
527
  done < <(jq -r '.[] | select(any(.labels[]?; .name == "agent-running")) | .number' <<<"${issue_json}" 2>/dev/null || true)
459
528
 
460
529
  pr_json="$(flow_github_pr_list_json "${REPO_SLUG}" open 100 2>/dev/null || printf '[]\n')"
530
+ if [[ "${pr_json}" == "[]" ]]; then
531
+ pr_json="$(gh pr list -R "${REPO_SLUG}" --state open --limit 100 --json number,labels 2>/dev/null || printf '[]\n')"
532
+ fi
461
533
  while IFS= read -r number; do
462
534
  [[ -n "${number}" ]] || continue
463
535
  bash "${UPDATE_LABELS_SCRIPT}" --repo-slug "${REPO_SLUG}" --number "${number}" --remove agent-running >/dev/null 2>&1 || true
@@ -466,6 +538,7 @@ clear_running_labels_after_stop() {
466
538
 
467
539
  stop_runtime() {
468
540
  local -a tmux_sessions=()
541
+ local -a stale_tmux_sessions=()
469
542
  local -a pid_targets=()
470
543
  local session=""
471
544
  local pid=""
@@ -476,6 +549,11 @@ stop_runtime() {
476
549
  tmux_sessions+=("${session}")
477
550
  done < <(collect_active_tmux_sessions | sort -u)
478
551
 
552
+ while IFS= read -r session; do
553
+ [[ -n "${session}" ]] || continue
554
+ stale_tmux_sessions+=("${session}")
555
+ done < <(collect_stale_tmux_sessions | sort -u)
556
+
479
557
  while IFS= read -r pid; do
480
558
  [[ -n "${pid}" ]] || continue
481
559
  pid_targets+=("${pid}")
@@ -501,6 +579,9 @@ stop_runtime() {
501
579
  for session in "${tmux_sessions[@]+"${tmux_sessions[@]}"}"; do
502
580
  "${TMUX_BIN}" kill-session -t "${session}" >/dev/null 2>&1 || true
503
581
  done
582
+ for session in "${stale_tmux_sessions[@]+"${stale_tmux_sessions[@]}"}"; do
583
+ "${TMUX_BIN}" kill-session -t "${session}" >/dev/null 2>&1 || true
584
+ done
504
585
  fi
505
586
 
506
587
  terminate_pid_list TERM "${pid_targets[@]+"${pid_targets[@]}"}"
@@ -513,8 +594,10 @@ stop_runtime() {
513
594
  printf 'LAUNCHD_STOPPED=%s\n' "${launchd_stopped}"
514
595
  printf 'STOPPED_PID_COUNT=%s\n' "$(printf '%s\n' "${pid_targets[@]+"${pid_targets[@]}"}" | awk 'NF {c+=1} END {print c+0}')"
515
596
  printf 'STOPPED_TMUX_SESSION_COUNT=%s\n' "$(printf '%s\n' "${tmux_sessions[@]+"${tmux_sessions[@]}"}" | awk 'NF {c+=1} END {print c+0}')"
597
+ printf 'STOPPED_STALE_TMUX_SESSION_COUNT=%s\n' "$(printf '%s\n' "${stale_tmux_sessions[@]+"${stale_tmux_sessions[@]}"}" | awk 'NF {c+=1} END {print c+0}')"
516
598
  printf 'STOPPED_PIDS=%s\n' "$(printf '%s\n' "${pid_targets[@]+"${pid_targets[@]}"}" | join_by_comma)"
517
599
  printf 'STOPPED_TMUX_SESSIONS=%s\n' "$(printf '%s\n' "${tmux_sessions[@]+"${tmux_sessions[@]}"}" | join_by_comma)"
600
+ printf 'STOPPED_STALE_TMUX_SESSIONS=%s\n' "$(printf '%s\n' "${stale_tmux_sessions[@]+"${stale_tmux_sessions[@]}"}" | join_by_comma)"
518
601
  }
519
602
 
520
603
  start_runtime() {
@@ -65,13 +65,13 @@ resolve_backend() {
65
65
  return 0
66
66
  fi
67
67
 
68
- if [[ -n "${ACP_ACTIVE_PROVIDER_BACKEND:-${F_LOSNING_ACTIVE_PROVIDER_BACKEND:-}}" ]]; then
69
- printf '%s\n' "${ACP_ACTIVE_PROVIDER_BACKEND:-${F_LOSNING_ACTIVE_PROVIDER_BACKEND:-}}"
68
+ if [[ -n "${ACP_ACTIVE_PROVIDER_BACKEND:-}" ]]; then
69
+ printf '%s\n' "${ACP_ACTIVE_PROVIDER_BACKEND:-}"
70
70
  return 0
71
71
  fi
72
72
 
73
- if [[ -n "${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-}}" ]]; then
74
- printf '%s\n' "${ACP_CODING_WORKER:-${F_LOSNING_CODING_WORKER:-}}"
73
+ if [[ -n "${ACP_CODING_WORKER:-}" ]]; then
74
+ printf '%s\n' "${ACP_CODING_WORKER:-}"
75
75
  return 0
76
76
  fi
77
77
 
@@ -79,7 +79,7 @@ resolve_backend() {
79
79
  }
80
80
 
81
81
  resolve_codex_label() {
82
- local configured_label="${ACP_ACTIVE_PROVIDER_LABEL:-${F_LOSNING_ACTIVE_PROVIDER_LABEL:-}}"
82
+ local configured_label="${ACP_ACTIVE_PROVIDER_LABEL:-}"
83
83
  local codex_quota_bin=""
84
84
  local active_label=""
85
85
 
@@ -88,8 +88,8 @@ resolve_codex_label() {
88
88
  return 0
89
89
  fi
90
90
 
91
- if [[ -n "${ACP_CODEX_QUOTA_LABEL:-${F_LOSNING_CODEX_QUOTA_LABEL:-}}" ]]; then
92
- printf '%s\n' "${ACP_CODEX_QUOTA_LABEL:-${F_LOSNING_CODEX_QUOTA_LABEL:-}}"
91
+ if [[ -n "${ACP_CODEX_QUOTA_LABEL:-}" ]]; then
92
+ printf '%s\n' "${ACP_CODEX_QUOTA_LABEL:-}"
93
93
  return 0
94
94
  fi
95
95
 
@@ -108,7 +108,7 @@ resolve_codex_label() {
108
108
  resolve_model() {
109
109
  local resolved_backend="${1:?backend required}"
110
110
  local raw_model="${2:-}"
111
- local active_provider_model="${ACP_ACTIVE_PROVIDER_MODEL:-${F_LOSNING_ACTIVE_PROVIDER_MODEL:-}}"
111
+ local active_provider_model="${ACP_ACTIVE_PROVIDER_MODEL:-}"
112
112
 
113
113
  if [[ -n "${raw_model}" ]]; then
114
114
  printf '%s\n' "${raw_model}"
@@ -121,8 +121,8 @@ resolve_model() {
121
121
  printf '%s\n' "${OPENCLAW_MODEL}"
122
122
  elif [[ -n "${active_provider_model}" ]]; then
123
123
  printf '%s\n' "${active_provider_model}"
124
- elif [[ -n "${ACP_OPENCLAW_MODEL:-${F_LOSNING_OPENCLAW_MODEL:-}}" ]]; then
125
- printf '%s\n' "${ACP_OPENCLAW_MODEL:-${F_LOSNING_OPENCLAW_MODEL:-}}"
124
+ elif [[ -n "${ACP_OPENCLAW_MODEL:-}" ]]; then
125
+ printf '%s\n' "${ACP_OPENCLAW_MODEL:-}"
126
126
  else
127
127
  flow_config_get "${CONFIG_YAML}" "execution.openclaw.model"
128
128
  fi
@@ -132,8 +132,8 @@ resolve_model() {
132
132
  printf '%s\n' "${CLAUDE_MODEL}"
133
133
  elif [[ -n "${active_provider_model}" ]]; then
134
134
  printf '%s\n' "${active_provider_model}"
135
- elif [[ -n "${ACP_CLAUDE_MODEL:-${F_LOSNING_CLAUDE_MODEL:-}}" ]]; then
136
- printf '%s\n' "${ACP_CLAUDE_MODEL:-${F_LOSNING_CLAUDE_MODEL:-}}"
135
+ elif [[ -n "${ACP_CLAUDE_MODEL:-}" ]]; then
136
+ printf '%s\n' "${ACP_CLAUDE_MODEL:-}"
137
137
  else
138
138
  flow_config_get "${CONFIG_YAML}" "execution.claude.model"
139
139
  fi
@@ -143,8 +143,8 @@ resolve_model() {
143
143
  printf '%s\n' "${CODEX_PROFILE_SAFE}"
144
144
  elif [[ -n "${active_provider_model}" ]]; then
145
145
  printf '%s\n' "${active_provider_model}"
146
- elif [[ -n "${ACP_CODEX_PROFILE_SAFE:-${F_LOSNING_CODEX_PROFILE_SAFE:-}}" ]]; then
147
- printf '%s\n' "${ACP_CODEX_PROFILE_SAFE:-${F_LOSNING_CODEX_PROFILE_SAFE:-}}"
146
+ elif [[ -n "${ACP_CODEX_PROFILE_SAFE:-}" ]]; then
147
+ printf '%s\n' "${ACP_CODEX_PROFILE_SAFE:-}"
148
148
  else
149
149
  flow_config_get "${CONFIG_YAML}" "execution.safe_profile"
150
150
  fi