agent-control-plane 0.1.16 → 0.3.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 +360 -10
- package/package.json +6 -3
- 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 +78 -21
- package/tools/bin/agent-project-catch-up-scheduled-issue-retries +123 -0
- package/tools/bin/agent-project-cleanup-session +132 -4
- package/tools/bin/agent-project-heartbeat-loop +116 -1461
- package/tools/bin/agent-project-reconcile-issue-session +90 -117
- package/tools/bin/agent-project-reconcile-pr-session +76 -111
- package/tools/bin/agent-project-run-claude-session +12 -2
- package/tools/bin/agent-project-run-codex-resilient +86 -9
- package/tools/bin/agent-project-run-codex-session +16 -5
- package/tools/bin/agent-project-run-kilo-session +356 -14
- package/tools/bin/agent-project-run-ollama-session +658 -0
- package/tools/bin/agent-project-run-openclaw-session +37 -25
- package/tools/bin/agent-project-run-opencode-session +364 -14
- package/tools/bin/agent-project-run-pi-session +479 -0
- package/tools/bin/agent-project-worker-status +11 -8
- package/tools/bin/cleanup-worktree.sh +6 -1
- package/tools/bin/flow-config-lib.sh +196 -3
- package/tools/bin/flow-resident-worker-lib.sh +120 -2
- package/tools/bin/flow-shell-lib.sh +29 -2
- package/tools/bin/heartbeat-loop-cache-lib.sh +164 -0
- package/tools/bin/heartbeat-loop-counting-lib.sh +306 -0
- package/tools/bin/heartbeat-loop-pr-strategy-lib.sh +199 -0
- package/tools/bin/heartbeat-loop-scheduling-lib.sh +506 -0
- package/tools/bin/heartbeat-loop-worker-lib.sh +319 -0
- package/tools/bin/heartbeat-recovery-preflight.sh +13 -1
- package/tools/bin/heartbeat-safe-auto.sh +119 -20
- 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-launchd-bootstrap.sh +11 -8
- package/tools/bin/project-runtimectl.sh +90 -7
- package/tools/bin/provider-cooldown-state.sh +14 -14
- package/tools/bin/reconcile-bootstrap-lib.sh +113 -0
- package/tools/bin/render-flow-config.sh +30 -33
- package/tools/bin/resident-issue-controller-lib.sh +448 -0
- package/tools/bin/resident-issue-queue-status.py +35 -0
- 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 +27 -438
- 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/dashboard/app.js +7 -0
- package/tools/dashboard/dashboard_snapshot.py +13 -29
- 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
- package/SKILL.md +0 -149
|
@@ -1699,6 +1699,76 @@ flow_provider_pool_openclaw_timeout_seconds() {
|
|
|
1699
1699
|
flow_provider_pool_value "${config_file}" "${pool_name}" "openclaw.timeout_seconds"
|
|
1700
1700
|
}
|
|
1701
1701
|
|
|
1702
|
+
flow_provider_pool_ollama_model() {
|
|
1703
|
+
local config_file="${1:?config file required}"
|
|
1704
|
+
local pool_name="${2:?pool name required}"
|
|
1705
|
+
|
|
1706
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "ollama.model"
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
flow_provider_pool_ollama_base_url() {
|
|
1710
|
+
local config_file="${1:?config file required}"
|
|
1711
|
+
local pool_name="${2:?pool name required}"
|
|
1712
|
+
|
|
1713
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "ollama.base_url"
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
flow_provider_pool_ollama_timeout_seconds() {
|
|
1717
|
+
local config_file="${1:?config file required}"
|
|
1718
|
+
local pool_name="${2:?pool name required}"
|
|
1719
|
+
|
|
1720
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "ollama.timeout_seconds"
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
flow_provider_pool_pi_model() {
|
|
1724
|
+
local config_file="${1:?config file required}"
|
|
1725
|
+
local pool_name="${2:?pool name required}"
|
|
1726
|
+
|
|
1727
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "pi.model"
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
flow_provider_pool_pi_thinking() {
|
|
1731
|
+
local config_file="${1:?config file required}"
|
|
1732
|
+
local pool_name="${2:?pool name required}"
|
|
1733
|
+
|
|
1734
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "pi.thinking"
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
flow_provider_pool_pi_timeout_seconds() {
|
|
1738
|
+
local config_file="${1:?config file required}"
|
|
1739
|
+
local pool_name="${2:?pool name required}"
|
|
1740
|
+
|
|
1741
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "pi.timeout_seconds"
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
flow_provider_pool_opencode_model() {
|
|
1745
|
+
local config_file="${1:?config file required}"
|
|
1746
|
+
local pool_name="${2:?pool name required}"
|
|
1747
|
+
|
|
1748
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "opencode.model"
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
flow_provider_pool_opencode_timeout_seconds() {
|
|
1752
|
+
local config_file="${1:?config file required}"
|
|
1753
|
+
local pool_name="${2:?pool name required}"
|
|
1754
|
+
|
|
1755
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "opencode.timeout_seconds"
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
flow_provider_pool_kilo_model() {
|
|
1759
|
+
local config_file="${1:?config file required}"
|
|
1760
|
+
local pool_name="${2:?pool name required}"
|
|
1761
|
+
|
|
1762
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "kilo.model"
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
flow_provider_pool_kilo_timeout_seconds() {
|
|
1766
|
+
local config_file="${1:?config file required}"
|
|
1767
|
+
local pool_name="${2:?pool name required}"
|
|
1768
|
+
|
|
1769
|
+
flow_provider_pool_value "${config_file}" "${pool_name}" "kilo.timeout_seconds"
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1702
1772
|
flow_sanitize_provider_key() {
|
|
1703
1773
|
local raw_key="${1:?raw key required}"
|
|
1704
1774
|
|
|
@@ -1723,6 +1793,18 @@ flow_provider_pool_model_identity() {
|
|
|
1723
1793
|
openclaw)
|
|
1724
1794
|
flow_provider_pool_openclaw_model "${config_file}" "${pool_name}"
|
|
1725
1795
|
;;
|
|
1796
|
+
ollama)
|
|
1797
|
+
flow_provider_pool_ollama_model "${config_file}" "${pool_name}"
|
|
1798
|
+
;;
|
|
1799
|
+
pi)
|
|
1800
|
+
flow_provider_pool_pi_model "${config_file}" "${pool_name}"
|
|
1801
|
+
;;
|
|
1802
|
+
opencode)
|
|
1803
|
+
flow_provider_pool_opencode_model "${config_file}" "${pool_name}"
|
|
1804
|
+
;;
|
|
1805
|
+
kilo)
|
|
1806
|
+
flow_provider_pool_kilo_model "${config_file}" "${pool_name}"
|
|
1807
|
+
;;
|
|
1726
1808
|
*)
|
|
1727
1809
|
printf '\n'
|
|
1728
1810
|
;;
|
|
@@ -1756,6 +1838,16 @@ flow_provider_pool_state_get() {
|
|
|
1756
1838
|
local openclaw_model=""
|
|
1757
1839
|
local openclaw_thinking=""
|
|
1758
1840
|
local openclaw_timeout_seconds=""
|
|
1841
|
+
local ollama_model=""
|
|
1842
|
+
local ollama_base_url=""
|
|
1843
|
+
local ollama_timeout_seconds=""
|
|
1844
|
+
local pi_model=""
|
|
1845
|
+
local pi_thinking=""
|
|
1846
|
+
local pi_timeout_seconds=""
|
|
1847
|
+
local opencode_model=""
|
|
1848
|
+
local opencode_timeout_seconds=""
|
|
1849
|
+
local kilo_model=""
|
|
1850
|
+
local kilo_timeout_seconds=""
|
|
1759
1851
|
|
|
1760
1852
|
backend="$(flow_provider_pool_backend "${config_file}" "${pool_name}")"
|
|
1761
1853
|
safe_profile="$(flow_provider_pool_safe_profile "${config_file}" "${pool_name}")"
|
|
@@ -1769,6 +1861,16 @@ flow_provider_pool_state_get() {
|
|
|
1769
1861
|
openclaw_model="$(flow_provider_pool_openclaw_model "${config_file}" "${pool_name}")"
|
|
1770
1862
|
openclaw_thinking="$(flow_provider_pool_openclaw_thinking "${config_file}" "${pool_name}")"
|
|
1771
1863
|
openclaw_timeout_seconds="$(flow_provider_pool_openclaw_timeout_seconds "${config_file}" "${pool_name}")"
|
|
1864
|
+
ollama_model="$(flow_provider_pool_ollama_model "${config_file}" "${pool_name}")"
|
|
1865
|
+
ollama_base_url="$(flow_provider_pool_ollama_base_url "${config_file}" "${pool_name}")"
|
|
1866
|
+
ollama_timeout_seconds="$(flow_provider_pool_ollama_timeout_seconds "${config_file}" "${pool_name}")"
|
|
1867
|
+
pi_model="$(flow_provider_pool_pi_model "${config_file}" "${pool_name}")"
|
|
1868
|
+
pi_thinking="$(flow_provider_pool_pi_thinking "${config_file}" "${pool_name}")"
|
|
1869
|
+
pi_timeout_seconds="$(flow_provider_pool_pi_timeout_seconds "${config_file}" "${pool_name}")"
|
|
1870
|
+
opencode_model="$(flow_provider_pool_opencode_model "${config_file}" "${pool_name}")"
|
|
1871
|
+
opencode_timeout_seconds="$(flow_provider_pool_opencode_timeout_seconds "${config_file}" "${pool_name}")"
|
|
1872
|
+
kilo_model="$(flow_provider_pool_kilo_model "${config_file}" "${pool_name}")"
|
|
1873
|
+
kilo_timeout_seconds="$(flow_provider_pool_kilo_timeout_seconds "${config_file}" "${pool_name}")"
|
|
1772
1874
|
model="$(flow_provider_pool_model_identity "${config_file}" "${pool_name}")"
|
|
1773
1875
|
|
|
1774
1876
|
case "${backend}" in
|
|
@@ -1781,6 +1883,18 @@ flow_provider_pool_state_get() {
|
|
|
1781
1883
|
openclaw)
|
|
1782
1884
|
[[ -n "${openclaw_model}" && -n "${openclaw_thinking}" && -n "${openclaw_timeout_seconds}" ]] || valid="no"
|
|
1783
1885
|
;;
|
|
1886
|
+
ollama)
|
|
1887
|
+
[[ -n "${ollama_model}" ]] || valid="no"
|
|
1888
|
+
;;
|
|
1889
|
+
pi)
|
|
1890
|
+
[[ -n "${pi_model}" ]] || valid="no"
|
|
1891
|
+
;;
|
|
1892
|
+
opencode)
|
|
1893
|
+
[[ -n "${opencode_model}" && -n "${opencode_timeout_seconds}" ]] || valid="no"
|
|
1894
|
+
;;
|
|
1895
|
+
kilo)
|
|
1896
|
+
[[ -n "${kilo_model}" && -n "${kilo_timeout_seconds}" ]] || valid="no"
|
|
1897
|
+
;;
|
|
1784
1898
|
*)
|
|
1785
1899
|
valid="no"
|
|
1786
1900
|
;;
|
|
@@ -1833,6 +1947,16 @@ flow_provider_pool_state_get() {
|
|
|
1833
1947
|
printf 'OPENCLAW_MODEL=%s\n' "${openclaw_model}"
|
|
1834
1948
|
printf 'OPENCLAW_THINKING=%s\n' "${openclaw_thinking}"
|
|
1835
1949
|
printf 'OPENCLAW_TIMEOUT_SECONDS=%s\n' "${openclaw_timeout_seconds}"
|
|
1950
|
+
printf 'OLLAMA_MODEL=%s\n' "${ollama_model}"
|
|
1951
|
+
printf 'OLLAMA_BASE_URL=%s\n' "${ollama_base_url}"
|
|
1952
|
+
printf 'OLLAMA_TIMEOUT_SECONDS=%s\n' "${ollama_timeout_seconds}"
|
|
1953
|
+
printf 'PI_MODEL=%s\n' "${pi_model}"
|
|
1954
|
+
printf 'PI_THINKING=%s\n' "${pi_thinking}"
|
|
1955
|
+
printf 'PI_TIMEOUT_SECONDS=%s\n' "${pi_timeout_seconds}"
|
|
1956
|
+
printf 'OPENCODE_MODEL=%s\n' "${opencode_model}"
|
|
1957
|
+
printf 'OPENCODE_TIMEOUT_SECONDS=%s\n' "${opencode_timeout_seconds}"
|
|
1958
|
+
printf 'KILO_MODEL=%s\n' "${kilo_model}"
|
|
1959
|
+
printf 'KILO_TIMEOUT_SECONDS=%s\n' "${kilo_timeout_seconds}"
|
|
1836
1960
|
}
|
|
1837
1961
|
|
|
1838
1962
|
flow_selected_provider_pool_env() {
|
|
@@ -2040,11 +2164,21 @@ flow_export_execution_env() {
|
|
|
2040
2164
|
local openclaw_thinking=""
|
|
2041
2165
|
local openclaw_timeout=""
|
|
2042
2166
|
local openclaw_stall=""
|
|
2167
|
+
local ollama_model=""
|
|
2168
|
+
local ollama_base_url=""
|
|
2169
|
+
local ollama_timeout=""
|
|
2170
|
+
local pi_model=""
|
|
2171
|
+
local pi_thinking=""
|
|
2172
|
+
local pi_timeout=""
|
|
2173
|
+
local opencode_model=""
|
|
2174
|
+
local opencode_timeout=""
|
|
2175
|
+
local kilo_model=""
|
|
2176
|
+
local kilo_timeout=""
|
|
2043
2177
|
|
|
2044
2178
|
repo_id="$(flow_resolve_repo_id "${config_file}")"
|
|
2045
2179
|
provider_quota_cooldowns="$(flow_resolve_provider_quota_cooldowns "${config_file}")"
|
|
2046
2180
|
provider_pool_order="$(flow_resolve_provider_pool_order "${config_file}")"
|
|
2047
|
-
explicit_coding_worker="${ACP_CODING_WORKER
|
|
2181
|
+
explicit_coding_worker="${ACP_CODING_WORKER:-}"
|
|
2048
2182
|
if [[ -z "${explicit_coding_worker}" && -n "${provider_pool_order}" ]]; then
|
|
2049
2183
|
provider_pool_selection="$(flow_selected_provider_pool_env "${config_file}" || true)"
|
|
2050
2184
|
fi
|
|
@@ -2073,11 +2207,21 @@ flow_export_execution_env() {
|
|
|
2073
2207
|
openclaw_thinking="$(flow_kv_get "${provider_pool_selection}" "OPENCLAW_THINKING")"
|
|
2074
2208
|
openclaw_timeout="$(flow_kv_get "${provider_pool_selection}" "OPENCLAW_TIMEOUT_SECONDS")"
|
|
2075
2209
|
openclaw_stall="$(flow_kv_get "${provider_pool_selection}" "OPENCLAW_STALL_SECONDS")"
|
|
2210
|
+
ollama_model="$(flow_kv_get "${provider_pool_selection}" "OLLAMA_MODEL")"
|
|
2211
|
+
ollama_base_url="$(flow_kv_get "${provider_pool_selection}" "OLLAMA_BASE_URL")"
|
|
2212
|
+
ollama_timeout="$(flow_kv_get "${provider_pool_selection}" "OLLAMA_TIMEOUT_SECONDS")"
|
|
2213
|
+
pi_model="$(flow_kv_get "${provider_pool_selection}" "PI_MODEL")"
|
|
2214
|
+
pi_thinking="$(flow_kv_get "${provider_pool_selection}" "PI_THINKING")"
|
|
2215
|
+
pi_timeout="$(flow_kv_get "${provider_pool_selection}" "PI_TIMEOUT_SECONDS")"
|
|
2216
|
+
opencode_model="$(flow_kv_get "${provider_pool_selection}" "OPENCODE_MODEL")"
|
|
2217
|
+
opencode_timeout="$(flow_kv_get "${provider_pool_selection}" "OPENCODE_TIMEOUT_SECONDS")"
|
|
2218
|
+
kilo_model="$(flow_kv_get "${provider_pool_selection}" "KILO_MODEL")"
|
|
2219
|
+
kilo_timeout="$(flow_kv_get "${provider_pool_selection}" "KILO_TIMEOUT_SECONDS")"
|
|
2076
2220
|
else
|
|
2077
2221
|
if [[ -n "${explicit_coding_worker}" ]]; then
|
|
2078
2222
|
active_provider_selection_reason="env-override"
|
|
2079
2223
|
fi
|
|
2080
|
-
coding_worker="$(flow_env_or_config "${config_file}" "ACP_CODING_WORKER
|
|
2224
|
+
coding_worker="$(flow_env_or_config "${config_file}" "ACP_CODING_WORKER" "execution.coding_worker" "")"
|
|
2081
2225
|
safe_profile="$(flow_env_or_config "${config_file}" "ACP_CODEX_PROFILE_SAFE F_LOSNING_CODEX_PROFILE_SAFE" "execution.safe_profile" "")"
|
|
2082
2226
|
bypass_profile="$(flow_env_or_config "${config_file}" "ACP_CODEX_PROFILE_BYPASS F_LOSNING_CODEX_PROFILE_BYPASS" "execution.bypass_profile" "")"
|
|
2083
2227
|
claude_model="$(flow_env_or_config "${config_file}" "ACP_CLAUDE_MODEL F_LOSNING_CLAUDE_MODEL" "execution.claude.model" "")"
|
|
@@ -2090,10 +2234,19 @@ flow_export_execution_env() {
|
|
|
2090
2234
|
openclaw_thinking="$(flow_env_or_config "${config_file}" "ACP_OPENCLAW_THINKING F_LOSNING_OPENCLAW_THINKING" "execution.openclaw.thinking" "")"
|
|
2091
2235
|
openclaw_timeout="$(flow_env_or_config "${config_file}" "ACP_OPENCLAW_TIMEOUT_SECONDS F_LOSNING_OPENCLAW_TIMEOUT_SECONDS" "execution.openclaw.timeout_seconds" "")"
|
|
2092
2236
|
openclaw_stall="$(flow_env_or_config "${config_file}" "ACP_OPENCLAW_STALL_SECONDS F_LOSNING_OPENCLAW_STALL_SECONDS" "execution.openclaw.stall_seconds" "")"
|
|
2237
|
+
ollama_model="$(flow_env_or_config "${config_file}" "ACP_OLLAMA_MODEL F_LOSNING_OLLAMA_MODEL" "execution.ollama.model" "")"
|
|
2238
|
+
ollama_base_url="$(flow_env_or_config "${config_file}" "ACP_OLLAMA_BASE_URL F_LOSNING_OLLAMA_BASE_URL" "execution.ollama.base_url" "")"
|
|
2239
|
+
ollama_timeout="$(flow_env_or_config "${config_file}" "ACP_OLLAMA_TIMEOUT_SECONDS F_LOSNING_OLLAMA_TIMEOUT_SECONDS" "execution.ollama.timeout_seconds" "")"
|
|
2240
|
+
pi_model="$(flow_env_or_config "${config_file}" "ACP_PI_MODEL F_LOSNING_PI_MODEL" "execution.pi.model" "")"
|
|
2241
|
+
pi_thinking="$(flow_env_or_config "${config_file}" "ACP_PI_THINKING F_LOSNING_PI_THINKING" "execution.pi.thinking" "")"
|
|
2242
|
+
pi_timeout="$(flow_env_or_config "${config_file}" "ACP_PI_TIMEOUT_SECONDS F_LOSNING_PI_TIMEOUT_SECONDS" "execution.pi.timeout_seconds" "")"
|
|
2243
|
+
opencode_model="$(flow_env_or_config "${config_file}" "ACP_OPENCODE_MODEL F_LOSNING_OPENCODE_MODEL" "execution.opencode.model" "")"
|
|
2244
|
+
opencode_timeout="$(flow_env_or_config "${config_file}" "ACP_OPENCODE_TIMEOUT_SECONDS F_LOSNING_OPENCODE_TIMEOUT_SECONDS" "execution.opencode.timeout_seconds" "")"
|
|
2245
|
+
kilo_model="$(flow_env_or_config "${config_file}" "ACP_KILO_MODEL F_LOSNING_KILO_MODEL" "execution.kilo.model" "")"
|
|
2246
|
+
kilo_timeout="$(flow_env_or_config "${config_file}" "ACP_KILO_TIMEOUT_SECONDS F_LOSNING_KILO_TIMEOUT_SECONDS" "execution.kilo.timeout_seconds" "")"
|
|
2093
2247
|
fi
|
|
2094
2248
|
|
|
2095
2249
|
if [[ -n "${coding_worker}" ]]; then
|
|
2096
|
-
export F_LOSNING_CODING_WORKER="${coding_worker}"
|
|
2097
2250
|
export ACP_CODING_WORKER="${coding_worker}"
|
|
2098
2251
|
fi
|
|
2099
2252
|
if [[ -n "${repo_id}" ]]; then
|
|
@@ -2174,6 +2327,46 @@ flow_export_execution_env() {
|
|
|
2174
2327
|
export F_LOSNING_OPENCLAW_STALL_SECONDS="${openclaw_stall}"
|
|
2175
2328
|
export ACP_OPENCLAW_STALL_SECONDS="${openclaw_stall}"
|
|
2176
2329
|
fi
|
|
2330
|
+
if [[ -n "${ollama_model}" ]]; then
|
|
2331
|
+
export F_LOSNING_OLLAMA_MODEL="${ollama_model}"
|
|
2332
|
+
export ACP_OLLAMA_MODEL="${ollama_model}"
|
|
2333
|
+
fi
|
|
2334
|
+
if [[ -n "${ollama_base_url}" ]]; then
|
|
2335
|
+
export F_LOSNING_OLLAMA_BASE_URL="${ollama_base_url}"
|
|
2336
|
+
export ACP_OLLAMA_BASE_URL="${ollama_base_url}"
|
|
2337
|
+
fi
|
|
2338
|
+
if [[ -n "${ollama_timeout}" ]]; then
|
|
2339
|
+
export F_LOSNING_OLLAMA_TIMEOUT_SECONDS="${ollama_timeout}"
|
|
2340
|
+
export ACP_OLLAMA_TIMEOUT_SECONDS="${ollama_timeout}"
|
|
2341
|
+
fi
|
|
2342
|
+
if [[ -n "${pi_model}" ]]; then
|
|
2343
|
+
export F_LOSNING_PI_MODEL="${pi_model}"
|
|
2344
|
+
export ACP_PI_MODEL="${pi_model}"
|
|
2345
|
+
fi
|
|
2346
|
+
if [[ -n "${pi_thinking}" ]]; then
|
|
2347
|
+
export F_LOSNING_PI_THINKING="${pi_thinking}"
|
|
2348
|
+
export ACP_PI_THINKING="${pi_thinking}"
|
|
2349
|
+
fi
|
|
2350
|
+
if [[ -n "${pi_timeout}" ]]; then
|
|
2351
|
+
export F_LOSNING_PI_TIMEOUT_SECONDS="${pi_timeout}"
|
|
2352
|
+
export ACP_PI_TIMEOUT_SECONDS="${pi_timeout}"
|
|
2353
|
+
fi
|
|
2354
|
+
if [[ -n "${opencode_model}" ]]; then
|
|
2355
|
+
export F_LOSNING_OPENCODE_MODEL="${opencode_model}"
|
|
2356
|
+
export ACP_OPENCODE_MODEL="${opencode_model}"
|
|
2357
|
+
fi
|
|
2358
|
+
if [[ -n "${opencode_timeout}" ]]; then
|
|
2359
|
+
export F_LOSNING_OPENCODE_TIMEOUT_SECONDS="${opencode_timeout}"
|
|
2360
|
+
export ACP_OPENCODE_TIMEOUT_SECONDS="${opencode_timeout}"
|
|
2361
|
+
fi
|
|
2362
|
+
if [[ -n "${kilo_model}" ]]; then
|
|
2363
|
+
export F_LOSNING_KILO_MODEL="${kilo_model}"
|
|
2364
|
+
export ACP_KILO_MODEL="${kilo_model}"
|
|
2365
|
+
fi
|
|
2366
|
+
if [[ -n "${kilo_timeout}" ]]; then
|
|
2367
|
+
export F_LOSNING_KILO_TIMEOUT_SECONDS="${kilo_timeout}"
|
|
2368
|
+
export ACP_KILO_TIMEOUT_SECONDS="${kilo_timeout}"
|
|
2369
|
+
fi
|
|
2177
2370
|
|
|
2178
2371
|
flow_export_github_cli_auth_env "$(flow_resolve_repo_slug "${config_file}")"
|
|
2179
2372
|
flow_export_project_env_aliases
|
|
@@ -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
|
*)
|
|
@@ -285,6 +285,22 @@ flow_resident_issue_queue_file() {
|
|
|
285
285
|
printf '%s/issue-%s.env\n' "$(flow_resident_issue_queue_pending_dir "${config_file}")" "${issue_id}"
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
flow_resident_issue_claim_file() {
|
|
289
|
+
local config_file="${1:-}"
|
|
290
|
+
local issue_id="${2:?issue id required}"
|
|
291
|
+
local claimer_key="${3:?claimer key required}"
|
|
292
|
+
|
|
293
|
+
if [[ -z "${config_file}" ]]; then
|
|
294
|
+
config_file="$(resolve_flow_config_yaml "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}")"
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
printf '%s/issue-%s.%s.%s.env\n' \
|
|
298
|
+
"$(flow_resident_issue_queue_claims_dir "${config_file}")" \
|
|
299
|
+
"${issue_id}" \
|
|
300
|
+
"${claimer_key}" \
|
|
301
|
+
"$$"
|
|
302
|
+
}
|
|
303
|
+
|
|
288
304
|
flow_resident_issue_controller_file() {
|
|
289
305
|
local config_file="${1:-}"
|
|
290
306
|
local issue_id="${2:?issue id required}"
|
|
@@ -342,8 +358,11 @@ flow_resident_issue_enqueue() {
|
|
|
342
358
|
|
|
343
359
|
tmp_file="${queue_file}.tmp.$$"
|
|
344
360
|
flow_resident_write_metadata "${tmp_file}" \
|
|
361
|
+
"STATE_FORMAT_VERSION=1" \
|
|
362
|
+
"STATE_KIND=pending" \
|
|
345
363
|
"ISSUE_ID=${issue_id}" \
|
|
346
364
|
"QUEUED_BY=${queued_by}" \
|
|
365
|
+
"UPDATED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
347
366
|
"QUEUED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
348
367
|
mv "${tmp_file}" "${queue_file}"
|
|
349
368
|
|
|
@@ -361,6 +380,9 @@ flow_resident_issue_claim_next() {
|
|
|
361
380
|
local issue_id=""
|
|
362
381
|
local claim_file=""
|
|
363
382
|
local claim_key=""
|
|
383
|
+
local queued_by=""
|
|
384
|
+
local queued_at=""
|
|
385
|
+
local claimed_at=""
|
|
364
386
|
|
|
365
387
|
if [[ -z "${config_file}" ]]; then
|
|
366
388
|
config_file="$(resolve_flow_config_yaml "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}")"
|
|
@@ -378,8 +400,22 @@ flow_resident_issue_claim_next() {
|
|
|
378
400
|
[[ -n "${issue_id}" ]] || continue
|
|
379
401
|
[[ "${issue_id}" != "${skip_issue_id}" ]] || continue
|
|
380
402
|
|
|
381
|
-
|
|
403
|
+
queued_by="$(flow_resident_metadata_value "${queue_file}" "QUEUED_BY" || true)"
|
|
404
|
+
queued_at="$(flow_resident_metadata_value "${queue_file}" "QUEUED_AT" || true)"
|
|
405
|
+
claimed_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
406
|
+
claim_file="$(flow_resident_issue_claim_file "${config_file}" "${issue_id}" "${claim_key}")"
|
|
382
407
|
if mv "${queue_file}" "${claim_file}" 2>/dev/null; then
|
|
408
|
+
flow_resident_write_metadata "${claim_file}" \
|
|
409
|
+
"STATE_FORMAT_VERSION=1" \
|
|
410
|
+
"STATE_KIND=claim" \
|
|
411
|
+
"ISSUE_ID=${issue_id}" \
|
|
412
|
+
"QUEUED_BY=${queued_by}" \
|
|
413
|
+
"QUEUED_AT=${queued_at}" \
|
|
414
|
+
"SESSION=${claimer_key}" \
|
|
415
|
+
"CLAIMED_BY=${claim_key}" \
|
|
416
|
+
"CLAIMED_AT=${claimed_at}" \
|
|
417
|
+
"UPDATED_AT=${claimed_at}" \
|
|
418
|
+
"CLAIM_FILE=${claim_file}"
|
|
383
419
|
printf 'ISSUE_ID=%s\n' "${issue_id}"
|
|
384
420
|
printf 'CLAIM_FILE=%s\n' "${claim_file}"
|
|
385
421
|
return 0
|
|
@@ -441,6 +477,87 @@ flow_resident_issue_controller_reap_file() {
|
|
|
441
477
|
return 0
|
|
442
478
|
}
|
|
443
479
|
|
|
480
|
+
flow_resident_issue_reap_stale_claims() {
|
|
481
|
+
local config_file="${1:-}"
|
|
482
|
+
local claims_dir=""
|
|
483
|
+
local claim_file=""
|
|
484
|
+
local claim_token=""
|
|
485
|
+
local claim_pid=""
|
|
486
|
+
local issue_id=""
|
|
487
|
+
local queued_by=""
|
|
488
|
+
local queued_at=""
|
|
489
|
+
local claimed_at=""
|
|
490
|
+
local existing_pending_file=""
|
|
491
|
+
local other_claim=""
|
|
492
|
+
local other_token=""
|
|
493
|
+
local other_pid=""
|
|
494
|
+
|
|
495
|
+
if [[ -z "${config_file}" ]]; then
|
|
496
|
+
config_file="$(resolve_flow_config_yaml "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}")"
|
|
497
|
+
fi
|
|
498
|
+
|
|
499
|
+
claims_dir="$(flow_resident_issue_queue_claims_dir "${config_file}")"
|
|
500
|
+
mkdir -p "${claims_dir}"
|
|
501
|
+
|
|
502
|
+
for claim_file in "${claims_dir}"/issue-*.env; do
|
|
503
|
+
[[ -f "${claim_file}" ]] || continue
|
|
504
|
+
|
|
505
|
+
claim_token="${claim_file##*/}"
|
|
506
|
+
claim_token="${claim_token%.env}"
|
|
507
|
+
claim_pid="${claim_token##*.}"
|
|
508
|
+
[[ "${claim_pid}" =~ ^[0-9]+$ ]] || continue
|
|
509
|
+
|
|
510
|
+
if flow_resident_controller_pid_live "${claim_pid}" "start-resident-issue-loop.sh"; then
|
|
511
|
+
continue
|
|
512
|
+
fi
|
|
513
|
+
|
|
514
|
+
issue_id="$(flow_resident_metadata_value "${claim_file}" "ISSUE_ID" || true)"
|
|
515
|
+
[[ -n "${issue_id}" ]] || issue_id="${claim_token#issue-}"
|
|
516
|
+
issue_id="${issue_id%%.*}"
|
|
517
|
+
[[ -n "${issue_id}" ]] || continue
|
|
518
|
+
|
|
519
|
+
# If another live claim exists for the same issue, do not re-queue this one.
|
|
520
|
+
for other_claim in "${claims_dir}/issue-${issue_id}."*; do
|
|
521
|
+
[[ -f "${other_claim}" ]] || continue
|
|
522
|
+
other_token="${other_claim##*/}"
|
|
523
|
+
other_token="${other_token%.env}"
|
|
524
|
+
other_pid="${other_token##*.}"
|
|
525
|
+
[[ "${other_pid}" =~ ^[0-9]+$ ]] || continue
|
|
526
|
+
if [[ "${other_pid}" == "${claim_pid}" ]]; then
|
|
527
|
+
continue
|
|
528
|
+
fi
|
|
529
|
+
if flow_resident_controller_pid_live "${other_pid}" "start-resident-issue-loop.sh"; then
|
|
530
|
+
issue_id=""
|
|
531
|
+
break
|
|
532
|
+
fi
|
|
533
|
+
done
|
|
534
|
+
[[ -n "${issue_id}" ]] || continue
|
|
535
|
+
|
|
536
|
+
existing_pending_file="$(flow_resident_issue_queue_file "${config_file}" "${issue_id}")"
|
|
537
|
+
if [[ -f "${existing_pending_file}" ]]; then
|
|
538
|
+
rm -f "${claim_file}"
|
|
539
|
+
continue
|
|
540
|
+
fi
|
|
541
|
+
|
|
542
|
+
queued_by="$(flow_resident_metadata_value "${claim_file}" "QUEUED_BY" || true)"
|
|
543
|
+
queued_at="$(flow_resident_metadata_value "${claim_file}" "QUEUED_AT" || true)"
|
|
544
|
+
claimed_at="$(flow_resident_metadata_value "${claim_file}" "CLAIMED_AT" || true)"
|
|
545
|
+
|
|
546
|
+
[[ -n "${queued_by}" ]] || queued_by="heartbeat"
|
|
547
|
+
[[ -n "${queued_at}" ]] || queued_at="${claimed_at:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}"
|
|
548
|
+
|
|
549
|
+
flow_resident_write_metadata "${existing_pending_file}" \
|
|
550
|
+
"STATE_FORMAT_VERSION=1" \
|
|
551
|
+
"STATE_KIND=pending" \
|
|
552
|
+
"ISSUE_ID=${issue_id}" \
|
|
553
|
+
"QUEUED_BY=${queued_by}" \
|
|
554
|
+
"QUEUED_AT=${queued_at}" \
|
|
555
|
+
"UPDATED_AT=${claimed_at:-${queued_at}}"
|
|
556
|
+
rm -f "${claim_file}"
|
|
557
|
+
|
|
558
|
+
done
|
|
559
|
+
}
|
|
560
|
+
|
|
444
561
|
flow_resident_issue_reap_stale_state() {
|
|
445
562
|
local config_file="${1:-}"
|
|
446
563
|
local resident_root=""
|
|
@@ -458,6 +575,7 @@ flow_resident_issue_reap_stale_state() {
|
|
|
458
575
|
reaped=$((reaped + 1))
|
|
459
576
|
fi
|
|
460
577
|
done
|
|
578
|
+
flow_resident_issue_reap_stale_claims "${config_file}" || true
|
|
461
579
|
|
|
462
580
|
printf '%s\n' "${reaped}"
|
|
463
581
|
}
|
|
@@ -5,6 +5,30 @@ flow_canonical_skill_name() {
|
|
|
5
5
|
printf '%s\n' "${AGENT_CONTROL_PLANE_SKILL_NAME:-agent-control-plane}"
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
flow_resolve_python_bin() {
|
|
9
|
+
if [[ -n "${PYTHON_BIN:-}" && -x "${PYTHON_BIN:-}" ]]; then
|
|
10
|
+
printf '%s\n' "${PYTHON_BIN}"
|
|
11
|
+
return 0
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
15
|
+
command -v python3
|
|
16
|
+
return 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
if [[ -x /opt/homebrew/bin/python3 ]]; then
|
|
20
|
+
printf '%s\n' "/opt/homebrew/bin/python3"
|
|
21
|
+
return 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if command -v python >/dev/null 2>&1; then
|
|
25
|
+
command -v python
|
|
26
|
+
return 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
return 1
|
|
30
|
+
}
|
|
31
|
+
|
|
8
32
|
flow_compat_skill_alias() {
|
|
9
33
|
printf '%s\n' "${AGENT_CONTROL_PLANE_COMPAT_ALIAS:-}"
|
|
10
34
|
}
|
|
@@ -35,7 +59,6 @@ flow_export_compat_env_aliases() {
|
|
|
35
59
|
flow_export_env_alias_if_unset F_LOSNING_MEMORY_DIR ACP_MEMORY_DIR
|
|
36
60
|
flow_export_env_alias_if_unset F_LOSNING_RETAINED_REPO_ROOT ACP_RETAINED_REPO_ROOT
|
|
37
61
|
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
62
|
flow_export_env_alias_if_unset F_LOSNING_CODEX_PROFILE_SAFE ACP_CODEX_PROFILE_SAFE
|
|
40
63
|
flow_export_env_alias_if_unset F_LOSNING_CODEX_PROFILE_BYPASS ACP_CODEX_PROFILE_BYPASS
|
|
41
64
|
flow_export_env_alias_if_unset F_LOSNING_CLAUDE_MODEL ACP_CLAUDE_MODEL
|
|
@@ -84,7 +107,6 @@ flow_export_canonical_env_aliases() {
|
|
|
84
107
|
flow_export_env_alias_if_unset ACP_MEMORY_DIR F_LOSNING_MEMORY_DIR
|
|
85
108
|
flow_export_env_alias_if_unset ACP_RETAINED_REPO_ROOT F_LOSNING_RETAINED_REPO_ROOT
|
|
86
109
|
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
110
|
flow_export_env_alias_if_unset ACP_CODEX_PROFILE_SAFE F_LOSNING_CODEX_PROFILE_SAFE
|
|
89
111
|
flow_export_env_alias_if_unset ACP_CODEX_PROFILE_BYPASS F_LOSNING_CODEX_PROFILE_BYPASS
|
|
90
112
|
flow_export_env_alias_if_unset ACP_CLAUDE_MODEL F_LOSNING_CLAUDE_MODEL
|
|
@@ -223,6 +245,11 @@ resolve_shared_agent_home() {
|
|
|
223
245
|
flow_root="$(resolve_flow_skill_dir "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}")"
|
|
224
246
|
fi
|
|
225
247
|
|
|
248
|
+
if flow_is_skill_root "${flow_root}"; then
|
|
249
|
+
flow_print_dir "${flow_root}"
|
|
250
|
+
return 0
|
|
251
|
+
fi
|
|
252
|
+
|
|
226
253
|
flow_print_dir "${flow_root}/../../.."
|
|
227
254
|
}
|
|
228
255
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# heartbeat-loop-cache-lib.sh — scheduler cache management and attribute caching
|
|
3
|
+
|
|
4
|
+
cleanup_scheduler_caches() {
|
|
5
|
+
tmux_sessions_cache=""
|
|
6
|
+
tmux_sessions_cache_loaded="no"
|
|
7
|
+
all_running_workers_cache=""
|
|
8
|
+
all_running_workers_cache_loaded="no"
|
|
9
|
+
running_issue_workers_cache=""
|
|
10
|
+
running_issue_workers_cache_loaded="no"
|
|
11
|
+
running_pr_workers_cache=""
|
|
12
|
+
running_pr_workers_cache_loaded="no"
|
|
13
|
+
completed_workers_cache=""
|
|
14
|
+
completed_workers_cache_loaded="no"
|
|
15
|
+
ready_issue_ids_cache=""
|
|
16
|
+
ready_issue_ids_cache_loaded="no"
|
|
17
|
+
open_agent_pr_ids_cache=""
|
|
18
|
+
open_agent_pr_ids_cache_loaded="no"
|
|
19
|
+
running_issue_ids_cache=""
|
|
20
|
+
running_issue_ids_cache_loaded="no"
|
|
21
|
+
exclusive_issue_ids_cache=""
|
|
22
|
+
exclusive_issue_ids_cache_loaded="no"
|
|
23
|
+
exclusive_pr_ids_cache=""
|
|
24
|
+
exclusive_pr_ids_cache_loaded="no"
|
|
25
|
+
blocked_recovery_issue_ids_cache=""
|
|
26
|
+
blocked_recovery_issue_ids_cache_loaded="no"
|
|
27
|
+
ordered_ready_issue_ids_cache=""
|
|
28
|
+
ordered_ready_issue_ids_cache_loaded="no"
|
|
29
|
+
due_scheduled_issue_ids_cache=""
|
|
30
|
+
due_scheduled_issue_ids_cache_loaded="no"
|
|
31
|
+
due_blocked_recovery_issue_ids_cache=""
|
|
32
|
+
due_blocked_recovery_issue_ids_cache_loaded="no"
|
|
33
|
+
if [[ -n "${issue_attr_cache_dir:-}" && -d "${issue_attr_cache_dir}" ]]; then
|
|
34
|
+
rm -rf "${issue_attr_cache_dir}" || true
|
|
35
|
+
fi
|
|
36
|
+
if [[ -n "${pr_attr_cache_dir:-}" && -d "${pr_attr_cache_dir}" ]]; then
|
|
37
|
+
rm -rf "${pr_attr_cache_dir}" || true
|
|
38
|
+
fi
|
|
39
|
+
if [[ -n "${pr_risk_cache_dir:-}" && -d "${pr_risk_cache_dir}" ]]; then
|
|
40
|
+
rm -rf "${pr_risk_cache_dir}" || true
|
|
41
|
+
fi
|
|
42
|
+
if declare -F heartbeat_invalidate_snapshot_cache >/dev/null 2>&1; then
|
|
43
|
+
heartbeat_invalidate_snapshot_cache
|
|
44
|
+
fi
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
cache_prefix() {
|
|
48
|
+
local raw_prefix="${issue_prefix:-${pr_prefix:-agent-control-plane}}"
|
|
49
|
+
local sanitized=""
|
|
50
|
+
|
|
51
|
+
sanitized="$(printf '%s' "${raw_prefix}" | tr '/[:space:]' '-' | tr -cd '[:alnum:]_.-')"
|
|
52
|
+
if [[ -z "${sanitized}" ]]; then
|
|
53
|
+
sanitized="agent-control-plane"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
printf '%s\n' "${sanitized}"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ensure_issue_attr_cache_dir() {
|
|
60
|
+
if [[ -z "${issue_attr_cache_dir:-}" || ! -d "${issue_attr_cache_dir:-}" ]]; then
|
|
61
|
+
issue_attr_cache_dir="$(mktemp -d "${TMPDIR:-/tmp}/$(cache_prefix)-issue-attrs.XXXXXX")"
|
|
62
|
+
fi
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
ensure_pr_attr_cache_dir() {
|
|
66
|
+
if [[ -z "${pr_attr_cache_dir:-}" || ! -d "${pr_attr_cache_dir:-}" ]]; then
|
|
67
|
+
pr_attr_cache_dir="$(mktemp -d "${TMPDIR:-/tmp}/$(cache_prefix)-pr-attrs.XXXXXX")"
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ensure_pr_risk_cache_dir() {
|
|
72
|
+
if [[ -z "${pr_risk_cache_dir:-}" || ! -d "${pr_risk_cache_dir:-}" ]]; then
|
|
73
|
+
pr_risk_cache_dir="$(mktemp -d "${TMPDIR:-/tmp}/$(cache_prefix)-pr-risk.XXXXXX")"
|
|
74
|
+
fi
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
pr_risk_runtime_cache_fresh() {
|
|
78
|
+
local cache_file="${1:?cache file required}"
|
|
79
|
+
local modified_at now age
|
|
80
|
+
[[ -f "$cache_file" ]] || return 1
|
|
81
|
+
modified_at="$(stat -f '%m' "$cache_file" 2>/dev/null || true)"
|
|
82
|
+
[[ "$modified_at" =~ ^[0-9]+$ ]] || return 1
|
|
83
|
+
now="$(date +%s)"
|
|
84
|
+
age=$((now - modified_at))
|
|
85
|
+
(( age >= 0 && age <= pr_risk_runtime_cache_ttl_seconds ))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
cached_issue_attr() {
|
|
89
|
+
local attr_name="${1:?attr name required}"
|
|
90
|
+
local issue_id="${2:?issue id required}"
|
|
91
|
+
local cache_file attr_value
|
|
92
|
+
|
|
93
|
+
ensure_issue_attr_cache_dir
|
|
94
|
+
cache_file="${issue_attr_cache_dir}/${issue_id}.${attr_name}"
|
|
95
|
+
if [[ -f "${cache_file}" ]]; then
|
|
96
|
+
cat "${cache_file}"
|
|
97
|
+
return 0
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
case "${attr_name}" in
|
|
101
|
+
heavy)
|
|
102
|
+
attr_value="$(heartbeat_issue_is_heavy "${issue_id}")"
|
|
103
|
+
;;
|
|
104
|
+
recurring)
|
|
105
|
+
attr_value="$(heartbeat_issue_is_recurring "${issue_id}")"
|
|
106
|
+
;;
|
|
107
|
+
scheduled)
|
|
108
|
+
attr_value="$(heartbeat_issue_is_scheduled "${issue_id}")"
|
|
109
|
+
;;
|
|
110
|
+
schedule_interval_seconds)
|
|
111
|
+
attr_value="$(heartbeat_issue_schedule_interval_seconds "${issue_id}")"
|
|
112
|
+
;;
|
|
113
|
+
exclusive)
|
|
114
|
+
attr_value="$(heartbeat_issue_is_exclusive "${issue_id}")"
|
|
115
|
+
;;
|
|
116
|
+
*)
|
|
117
|
+
echo "unsupported issue cache attr: ${attr_name}" >&2
|
|
118
|
+
return 1
|
|
119
|
+
;;
|
|
120
|
+
esac
|
|
121
|
+
|
|
122
|
+
printf '%s\n' "${attr_value}" >"${cache_file}"
|
|
123
|
+
printf '%s\n' "${attr_value}"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
cached_pr_is_exclusive() {
|
|
127
|
+
local pr_number="${1:?pr number required}"
|
|
128
|
+
local cache_file attr_value
|
|
129
|
+
|
|
130
|
+
ensure_pr_attr_cache_dir
|
|
131
|
+
cache_file="${pr_attr_cache_dir}/${pr_number}.exclusive"
|
|
132
|
+
if [[ -f "${cache_file}" ]]; then
|
|
133
|
+
cat "${cache_file}"
|
|
134
|
+
return 0
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
attr_value="$(heartbeat_pr_is_exclusive "${pr_number}")"
|
|
138
|
+
printf '%s\n' "${attr_value}" >"${cache_file}"
|
|
139
|
+
printf '%s\n' "${attr_value}"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
cached_pr_risk_json() {
|
|
143
|
+
local pr_number="${1:?pr number required}"
|
|
144
|
+
local cache_file runtime_cache_file risk_json
|
|
145
|
+
|
|
146
|
+
ensure_pr_risk_cache_dir
|
|
147
|
+
cache_file="${pr_risk_cache_dir}/${pr_number}.json"
|
|
148
|
+
runtime_cache_file="${pr_risk_runtime_cache_dir}/${pr_number}.json"
|
|
149
|
+
if [[ -f "${cache_file}" ]]; then
|
|
150
|
+
cat "${cache_file}"
|
|
151
|
+
return 0
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
if pr_risk_runtime_cache_fresh "${runtime_cache_file}"; then
|
|
155
|
+
cp "${runtime_cache_file}" "${cache_file}"
|
|
156
|
+
cat "${cache_file}"
|
|
157
|
+
return 0
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
risk_json="$(heartbeat_pr_risk_json "${pr_number}")"
|
|
161
|
+
printf '%s\n' "${risk_json}" >"${cache_file}"
|
|
162
|
+
printf '%s\n' "${risk_json}" >"${runtime_cache_file}"
|
|
163
|
+
printf '%s\n' "${risk_json}"
|
|
164
|
+
}
|