agent-control-plane 0.3.0 → 0.6.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 (106) hide show
  1. package/README.md +141 -28
  2. package/assets/workflow-catalog.json +1 -1
  3. package/bin/pr-risk.sh +22 -7
  4. package/bin/sync-pr-labels.sh +1 -1
  5. package/hooks/heartbeat-hooks.sh +125 -12
  6. package/hooks/issue-reconcile-hooks.sh +1 -1
  7. package/hooks/pr-reconcile-hooks.sh +1 -1
  8. package/npm/bin/agent-control-plane.js +257 -59
  9. package/package.json +39 -32
  10. package/tools/bin/debug-session.sh +106 -0
  11. package/tools/bin/flow-config-lib.sh +1203 -60
  12. package/tools/bin/flow-runtime-doctor-linux.sh +136 -0
  13. package/tools/bin/flow-runtime-doctor.sh +5 -1
  14. package/tools/bin/flow-shell-lib.sh +32 -0
  15. package/tools/bin/github-core-rate-limit-state.sh +77 -0
  16. package/tools/bin/github-write-outbox.sh +470 -0
  17. package/tools/bin/heartbeat-loop-scheduling-lib.sh +7 -7
  18. package/tools/bin/heartbeat-safe-auto.sh +42 -0
  19. package/tools/bin/install-project-launchd.sh +17 -2
  20. package/tools/bin/install-project-systemd.sh +255 -0
  21. package/tools/bin/project-init.sh +21 -1
  22. package/tools/bin/project-launchd-bootstrap.sh +5 -1
  23. package/tools/bin/project-runtimectl.sh +91 -2
  24. package/tools/bin/project-systemd-bootstrap.sh +74 -0
  25. package/tools/bin/scaffold-profile.sh +61 -3
  26. package/tools/bin/uninstall-project-systemd.sh +87 -0
  27. package/tools/dashboard/app.js +228 -6
  28. package/tools/dashboard/dashboard_snapshot.py +55 -0
  29. package/tools/dashboard/issue_queue_state.py +101 -0
  30. package/tools/dashboard/server.py +123 -1
  31. package/tools/dashboard/styles.css +526 -455
  32. package/tools/templates/pr-fix-template.md +3 -1
  33. package/tools/templates/pr-merge-repair-template.md +2 -1
  34. package/references/architecture.md +0 -217
  35. package/references/commands.md +0 -128
  36. package/references/control-plane-map.md +0 -124
  37. package/references/docs-map.md +0 -73
  38. package/references/release-checklist.md +0 -65
  39. package/references/repo-map.md +0 -36
  40. package/tools/bin/agent-cleanup-worktree +0 -247
  41. package/tools/bin/agent-github-update-labels +0 -71
  42. package/tools/bin/agent-init-worktree +0 -216
  43. package/tools/bin/agent-project-archive-run +0 -52
  44. package/tools/bin/agent-project-capture-worker +0 -46
  45. package/tools/bin/agent-project-catch-up-issue-pr-links +0 -118
  46. package/tools/bin/agent-project-catch-up-merged-prs +0 -194
  47. package/tools/bin/agent-project-catch-up-scheduled-issue-retries +0 -123
  48. package/tools/bin/agent-project-cleanup-session +0 -513
  49. package/tools/bin/agent-project-detached-launch +0 -127
  50. package/tools/bin/agent-project-heartbeat-loop +0 -1029
  51. package/tools/bin/agent-project-open-issue-worktree +0 -89
  52. package/tools/bin/agent-project-open-pr-worktree +0 -80
  53. package/tools/bin/agent-project-publish-issue-pr +0 -465
  54. package/tools/bin/agent-project-reconcile-issue-session +0 -1398
  55. package/tools/bin/agent-project-reconcile-pr-session +0 -1230
  56. package/tools/bin/agent-project-retry-state +0 -147
  57. package/tools/bin/agent-project-run-claude-session +0 -805
  58. package/tools/bin/agent-project-run-codex-resilient +0 -955
  59. package/tools/bin/agent-project-run-codex-session +0 -435
  60. package/tools/bin/agent-project-run-kilo-session +0 -369
  61. package/tools/bin/agent-project-run-ollama-session +0 -658
  62. package/tools/bin/agent-project-run-openclaw-session +0 -1309
  63. package/tools/bin/agent-project-run-opencode-session +0 -377
  64. package/tools/bin/agent-project-run-pi-session +0 -479
  65. package/tools/bin/agent-project-sync-anchor-repo +0 -139
  66. package/tools/bin/agent-project-worker-status +0 -188
  67. package/tools/bin/branch-verification-guard.sh +0 -364
  68. package/tools/bin/capture-worker.sh +0 -18
  69. package/tools/bin/cleanup-worktree.sh +0 -52
  70. package/tools/bin/codex-quota +0 -31
  71. package/tools/bin/create-follow-up-issue.sh +0 -114
  72. package/tools/bin/dashboard-launchd-bootstrap.sh +0 -50
  73. package/tools/bin/issue-publish-localization-guard.sh +0 -142
  74. package/tools/bin/issue-publish-scope-guard.sh +0 -242
  75. package/tools/bin/issue-requires-local-workspace-install.sh +0 -31
  76. package/tools/bin/issue-resource-class.sh +0 -12
  77. package/tools/bin/kick-scheduler.sh +0 -75
  78. package/tools/bin/label-follow-up-issues.sh +0 -14
  79. package/tools/bin/new-pr-worktree.sh +0 -50
  80. package/tools/bin/new-worktree.sh +0 -49
  81. package/tools/bin/pr-risk.sh +0 -12
  82. package/tools/bin/prepare-worktree.sh +0 -142
  83. package/tools/bin/provider-cooldown-state.sh +0 -204
  84. package/tools/bin/publish-issue-worker.sh +0 -31
  85. package/tools/bin/reconcile-bootstrap-lib.sh +0 -113
  86. package/tools/bin/reconcile-issue-worker.sh +0 -34
  87. package/tools/bin/reconcile-pr-worker.sh +0 -34
  88. package/tools/bin/record-verification.sh +0 -71
  89. package/tools/bin/render-flow-config.sh +0 -98
  90. package/tools/bin/resident-issue-controller-lib.sh +0 -448
  91. package/tools/bin/resident-issue-queue-status.py +0 -35
  92. package/tools/bin/retry-state.sh +0 -31
  93. package/tools/bin/reuse-issue-worktree.sh +0 -121
  94. package/tools/bin/run-codex-bypass.sh +0 -3
  95. package/tools/bin/run-codex-safe.sh +0 -3
  96. package/tools/bin/run-codex-task.sh +0 -280
  97. package/tools/bin/serve-dashboard.sh +0 -5
  98. package/tools/bin/split-retained-slice.sh +0 -124
  99. package/tools/bin/start-issue-worker.sh +0 -943
  100. package/tools/bin/start-pr-fix-worker.sh +0 -491
  101. package/tools/bin/start-pr-merge-repair-worker.sh +0 -8
  102. package/tools/bin/start-pr-review-worker.sh +0 -261
  103. package/tools/bin/start-resident-issue-loop.sh +0 -499
  104. package/tools/bin/update-github-labels.sh +0 -14
  105. package/tools/bin/worker-status.sh +0 -19
  106. package/tools/bin/workflow-catalog.sh +0 -77
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- # shellcheck source=/dev/null
6
- source "${SCRIPT_DIR}/flow-shell-lib.sh"
7
- # shellcheck source=/dev/null
8
- source "${SCRIPT_DIR}/flow-config-lib.sh"
9
-
10
- KIND="${1:?usage: retry-state.sh issue|pr ID get|schedule|clear [reason]}"
11
- ITEM_ID="${2:?usage: retry-state.sh issue|pr ID get|schedule|clear [reason]}"
12
- ACTION="${3:?usage: retry-state.sh issue|pr ID get|schedule|clear [reason]}"
13
- REASON="${4:-}"
14
-
15
- CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
16
- AGENT_ROOT="$(flow_resolve_agent_root "${CONFIG_YAML}")"
17
- STATE_ROOT="$(flow_resolve_state_root "${CONFIG_YAML}")"
18
- COOLDOWNS="$(flow_resolve_retry_cooldowns "${CONFIG_YAML}")"
19
- FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
20
- FLOW_TOOLS_DIR="${FLOW_SKILL_DIR}/tools/bin"
21
-
22
- ACP_AGENT_ROOT="$AGENT_ROOT" \
23
- ACP_STATE_ROOT="$STATE_ROOT" \
24
- ACP_RETRY_COOLDOWNS="$COOLDOWNS" \
25
- exec bash "${FLOW_TOOLS_DIR}/agent-project-retry-state" \
26
- --state-root "$STATE_ROOT" \
27
- --kind "$KIND" \
28
- --item-id "$ITEM_ID" \
29
- --action "$ACTION" \
30
- --reason "$REASON" \
31
- --cooldowns "$COOLDOWNS"
@@ -1,121 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- # shellcheck source=/dev/null
6
- source "${SCRIPT_DIR}/flow-config-lib.sh"
7
-
8
- usage() {
9
- cat <<'EOF'
10
- Usage:
11
- reuse-issue-worktree.sh WORKTREE ISSUE_ID [SLUG]
12
-
13
- Reset and re-branch an existing managed issue worktree so a recurring issue can
14
- reuse the same workspace path across multiple cycles.
15
- EOF
16
- }
17
-
18
- WORKTREE="${1:-}"
19
- ISSUE_ID="${2:-}"
20
- SLUG_INPUT="${3:-task}"
21
-
22
- if [[ -z "${WORKTREE}" || -z "${ISSUE_ID}" ]]; then
23
- usage >&2
24
- exit 1
25
- fi
26
-
27
- FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
28
- if ! flow_require_explicit_profile_selection "${FLOW_SKILL_DIR}" "reuse-issue-worktree.sh"; then
29
- exit 64
30
- fi
31
-
32
- CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
33
- AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
34
- WORKTREE_ROOT="$(flow_resolve_worktree_root "${CONFIG_YAML}")"
35
- ISSUE_BRANCH_PREFIX="$(flow_resolve_issue_branch_prefix "${CONFIG_YAML}")"
36
- DEFAULT_BRANCH="$(flow_resolve_default_branch "${CONFIG_YAML}")"
37
- BASE_REF="origin/${DEFAULT_BRANCH}"
38
- PREPARE_SCRIPT="${SCRIPT_DIR}/prepare-worktree.sh"
39
-
40
- safe_slug="$(printf '%s' "${SLUG_INPUT}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-')"
41
- safe_slug="${safe_slug#-}"
42
- safe_slug="${safe_slug%-}"
43
- if [[ -z "${safe_slug}" ]]; then
44
- safe_slug="task"
45
- fi
46
-
47
- stamp="$(date +%Y%m%d-%H%M%S)"
48
- branch_name="${ISSUE_BRANCH_PREFIX}-${ISSUE_ID}-${safe_slug}-${stamp}"
49
- previous_branch="$(git -C "${WORKTREE}" branch --show-current 2>/dev/null || true)"
50
- resolved_worktree=""
51
- actual_branch=""
52
- rotated_worktree=""
53
-
54
- if ! git -C "${WORKTREE}" rev-parse --git-dir >/dev/null 2>&1; then
55
- echo "invalid managed worktree: ${WORKTREE}" >&2
56
- exit 1
57
- fi
58
-
59
- git -C "${AGENT_REPO_ROOT}" fetch \
60
- origin \
61
- "+refs/heads/${DEFAULT_BRANCH}:refs/remotes/origin/${DEFAULT_BRANCH}" \
62
- --prune >/dev/null
63
-
64
- # Reset the resident workspace to the latest baseline before switching to the
65
- # next focused cycle branch.
66
- git -C "${WORKTREE}" reset --hard >/dev/null
67
- git -C "${WORKTREE}" clean -fd >/dev/null
68
- git -C "${WORKTREE}" checkout -B "${branch_name}" "${BASE_REF}" >/dev/null
69
-
70
- if [[ -n "${previous_branch}" && "${previous_branch}" != "${branch_name}" ]]; then
71
- git -C "${AGENT_REPO_ROOT}" branch -D "${previous_branch}" >/dev/null 2>&1 || true
72
- fi
73
-
74
- "${PREPARE_SCRIPT}" "${WORKTREE}" >/dev/null
75
-
76
- if ! git -C "${WORKTREE}" rev-parse --git-dir >/dev/null 2>&1; then
77
- echo "invalid managed worktree after reuse: ${WORKTREE}" >&2
78
- exit 1
79
- fi
80
-
81
- resolved_worktree="$(cd "${WORKTREE}" 2>/dev/null && pwd -P || true)"
82
- if [[ -z "${resolved_worktree}" || ! -d "${resolved_worktree}" ]]; then
83
- echo "reused worktree path is unavailable: ${WORKTREE}" >&2
84
- exit 1
85
- fi
86
- WORKTREE="${resolved_worktree}"
87
-
88
- if [[ -n "${WORKTREE_ROOT}" ]]; then
89
- mkdir -p "${WORKTREE_ROOT}"
90
- rotated_worktree="${WORKTREE_ROOT}/issue-${ISSUE_ID}-${stamp}"
91
- if [[ "${resolved_worktree}" != "${rotated_worktree}" ]]; then
92
- if [[ -e "${rotated_worktree}" ]]; then
93
- echo "rotated worktree path already exists: ${rotated_worktree}" >&2
94
- exit 1
95
- fi
96
- git -C "${AGENT_REPO_ROOT}" worktree move "${resolved_worktree}" "${rotated_worktree}" >/dev/null
97
- WORKTREE="${rotated_worktree}"
98
- resolved_worktree="$(cd "${WORKTREE}" 2>/dev/null && pwd -P || true)"
99
- if [[ -z "${resolved_worktree}" || ! -d "${resolved_worktree}" ]]; then
100
- echo "rotated worktree path is unavailable: ${WORKTREE}" >&2
101
- exit 1
102
- fi
103
- WORKTREE="${resolved_worktree}"
104
- fi
105
- fi
106
-
107
- if ! git -C "${AGENT_REPO_ROOT}" worktree list --porcelain | grep -Fqx "worktree ${resolved_worktree}"; then
108
- echo "reused worktree is no longer registered: ${resolved_worktree}" >&2
109
- exit 1
110
- fi
111
-
112
- actual_branch="$(git -C "${WORKTREE}" branch --show-current 2>/dev/null || true)"
113
- if [[ -z "${actual_branch}" || "${actual_branch}" != "${branch_name}" ]]; then
114
- echo "reused worktree branch mismatch: expected ${branch_name} got ${actual_branch:-<none>}" >&2
115
- exit 1
116
- fi
117
-
118
- printf 'WORKTREE=%s\n' "${WORKTREE}"
119
- printf 'BRANCH=%s\n' "${branch_name}"
120
- printf 'BASE_REF=%s\n' "${BASE_REF}"
121
- printf 'REUSED=yes\n'
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- "$(dirname "$0")/run-codex-task.sh" bypass "$@"
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- "$(dirname "$0")/run-codex-task.sh" safe "$@"
@@ -1,280 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- # shellcheck source=/dev/null
6
- source "${SCRIPT_DIR}/flow-config-lib.sh"
7
-
8
- MODE="${1:?usage: run-codex-task.sh MODE SESSION WORKTREE PROMPT_FILE}"
9
- SESSION="${2:?usage: run-codex-task.sh MODE SESSION WORKTREE PROMPT_FILE}"
10
- WORKTREE="${3:?usage: run-codex-task.sh MODE SESSION WORKTREE PROMPT_FILE}"
11
- PROMPT_FILE="${4:?usage: run-codex-task.sh MODE SESSION WORKTREE PROMPT_FILE}"
12
-
13
- WORKSPACE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
14
- CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
15
- flow_export_execution_env "${CONFIG_YAML}"
16
- flow_export_project_env_aliases
17
- AGENT_ROOT="$(flow_resolve_agent_root "${CONFIG_YAML}")"
18
- RUNS_ROOT="$(flow_resolve_runs_root "${CONFIG_YAML}")"
19
- AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
20
- CANONICAL_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
21
- WORKTREE_ROOT="$(flow_resolve_worktree_root "${CONFIG_YAML}")"
22
- DEPENDENCY_SOURCE_ROOT="${ACP_DEPENDENCY_SOURCE_ROOT:-${F_LOSNING_DEPENDENCY_SOURCE_ROOT:-$CANONICAL_REPO_ROOT}}"
23
- RETAINED_REPO_ROOT="$(flow_resolve_retained_repo_root "${CONFIG_YAML}")"
24
- ISSUE_ID="${ACP_ISSUE_ID:-${F_LOSNING_ISSUE_ID:-}}"
25
- ISSUE_URL="${ACP_ISSUE_URL:-${F_LOSNING_ISSUE_URL:-}}"
26
- ISSUE_AUTOMERGE="${ACP_ISSUE_AUTOMERGE:-${F_LOSNING_ISSUE_AUTOMERGE:-no}}"
27
- PR_NUMBER="${ACP_PR_NUMBER:-${F_LOSNING_PR_NUMBER:-}}"
28
- PR_URL="${ACP_PR_URL:-${F_LOSNING_PR_URL:-}}"
29
- PR_HEAD_REF="${ACP_PR_HEAD_REF:-${F_LOSNING_PR_HEAD_REF:-}}"
30
- FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
31
- FLOW_TOOLS_DIR="${FLOW_SKILL_DIR}/tools/bin"
32
- TASK_KIND="task"
33
- TASK_ID="$SESSION"
34
- RECONCILE_COMMAND=""
35
- ADAPTER_ID="$(flow_resolve_adapter_id "${CONFIG_YAML}")"
36
- ISSUE_SESSION_PREFIX="$(flow_resolve_issue_session_prefix "${CONFIG_YAML}")"
37
- PR_SESSION_PREFIX="$(flow_resolve_pr_session_prefix "${CONFIG_YAML}")"
38
- CODING_WORKER="${ACP_CODING_WORKER:-codex}"
39
- CODEX_PROFILE_SAFE="${ACP_CODEX_PROFILE_SAFE:-${F_LOSNING_CODEX_PROFILE_SAFE:-${CODEX_PROFILE_SAFE:-f_losning_safe_auto}}}"
40
- CODEX_PROFILE_BYPASS="${ACP_CODEX_PROFILE_BYPASS:-${F_LOSNING_CODEX_PROFILE_BYPASS:-${CODEX_PROFILE_BYPASS:-f_losning_yolo}}}"
41
- if [[ "$MODE" == "bypass" ]]; then
42
- CLAUDE_PERMISSION_MODE_DEFAULT="bypassPermissions"
43
- else
44
- CLAUDE_PERMISSION_MODE_DEFAULT="acceptEdits"
45
- fi
46
- CLAUDE_MODEL="${ACP_CLAUDE_MODEL:-${F_LOSNING_CLAUDE_MODEL:-sonnet}}"
47
- CLAUDE_PERMISSION_MODE="${ACP_CLAUDE_PERMISSION_MODE:-${F_LOSNING_CLAUDE_PERMISSION_MODE:-${CLAUDE_PERMISSION_MODE_DEFAULT}}}"
48
- CLAUDE_EFFORT="${ACP_CLAUDE_EFFORT:-${F_LOSNING_CLAUDE_EFFORT:-medium}}"
49
- CLAUDE_TIMEOUT_SECONDS="${ACP_CLAUDE_TIMEOUT_SECONDS:-${F_LOSNING_CLAUDE_TIMEOUT_SECONDS:-900}}"
50
- CLAUDE_MAX_ATTEMPTS="${ACP_CLAUDE_MAX_ATTEMPTS:-${F_LOSNING_CLAUDE_MAX_ATTEMPTS:-3}}"
51
- CLAUDE_RETRY_BACKOFF_SECONDS="${ACP_CLAUDE_RETRY_BACKOFF_SECONDS:-${F_LOSNING_CLAUDE_RETRY_BACKOFF_SECONDS:-30}}"
52
- RESIDENT_WORKER_ENABLED="${ACP_RESIDENT_WORKER_ENABLED:-${F_LOSNING_RESIDENT_WORKER_ENABLED:-}}"
53
- RESIDENT_WORKER_KEY="${ACP_RESIDENT_WORKER_KEY:-${F_LOSNING_RESIDENT_WORKER_KEY:-}}"
54
- RESIDENT_WORKER_DIR="${ACP_RESIDENT_WORKER_DIR:-${F_LOSNING_RESIDENT_WORKER_DIR:-}}"
55
- RESIDENT_WORKER_META_FILE="${ACP_RESIDENT_WORKER_META_FILE:-${F_LOSNING_RESIDENT_WORKER_META_FILE:-}}"
56
- RESIDENT_TASK_COUNT="${ACP_RESIDENT_TASK_COUNT:-${F_LOSNING_RESIDENT_TASK_COUNT:-}}"
57
- RESIDENT_WORKTREE_REUSED="${ACP_RESIDENT_WORKTREE_REUSED:-${F_LOSNING_RESIDENT_WORKTREE_REUSED:-}}"
58
- RESIDENT_OPENCLAW_AGENT_ID="${ACP_RESIDENT_OPENCLAW_AGENT_ID:-${F_LOSNING_RESIDENT_OPENCLAW_AGENT_ID:-}}"
59
- RESIDENT_OPENCLAW_SESSION_ID="${ACP_RESIDENT_OPENCLAW_SESSION_ID:-${F_LOSNING_RESIDENT_OPENCLAW_SESSION_ID:-}}"
60
- RESIDENT_OPENCLAW_AGENT_DIR="${ACP_RESIDENT_OPENCLAW_AGENT_DIR:-${F_LOSNING_RESIDENT_OPENCLAW_AGENT_DIR:-}}"
61
- RESIDENT_OPENCLAW_STATE_DIR="${ACP_RESIDENT_OPENCLAW_STATE_DIR:-${F_LOSNING_RESIDENT_OPENCLAW_STATE_DIR:-}}"
62
- RESIDENT_OPENCLAW_CONFIG_PATH="${ACP_RESIDENT_OPENCLAW_CONFIG_PATH:-${F_LOSNING_RESIDENT_OPENCLAW_CONFIG_PATH:-}}"
63
- # Set defaults if not set from yaml or env
64
- OPENCLAW_MODEL="${OPENCLAW_MODEL:-${ACP_OPENCLAW_MODEL:-${F_LOSNING_OPENCLAW_MODEL:-openrouter/qwen/qwen3.6-plus-preview:free}}}"
65
- OPENCLAW_THINKING="${OPENCLAW_THINKING:-${ACP_OPENCLAW_THINKING:-${F_LOSNING_OPENCLAW_THINKING:-low}}}"
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}}"
78
- printf -v SESSION_Q '%q' "$SESSION"
79
- printf -v CONFIG_YAML_Q '%q' "$CONFIG_YAML"
80
- printf -v ADAPTER_ID_Q '%q' "$ADAPTER_ID"
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
95
-
96
- case "$SESSION" in
97
- "${ISSUE_SESSION_PREFIX}"*)
98
- TASK_KIND="issue"
99
- TASK_ID="${ISSUE_ID:-${SESSION#${ISSUE_SESSION_PREFIX}}}"
100
- if [[ "${RESIDENT_WORKER_ENABLED}" != "yes" ]]; then
101
- RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${RECONCILE_ISSUE_BIN} ${SESSION_Q}"
102
- fi
103
- ;;
104
- "${PR_SESSION_PREFIX}"*)
105
- TASK_KIND="pr"
106
- TASK_ID="${PR_NUMBER:-${SESSION#${PR_SESSION_PREFIX}}}"
107
- RECONCILE_COMMAND="${RECONCILE_ENV_PREFIX} ${RECONCILE_PR_BIN} ${SESSION_Q}"
108
- ;;
109
- esac
110
-
111
- realpath_safe() {
112
- local path="${1:-}"
113
- [[ -n "$path" ]] || return 1
114
- if command -v python3 >/dev/null 2>&1; then
115
- python3 - "$path" <<'PY'
116
- import os
117
- import sys
118
- print(os.path.realpath(sys.argv[1]))
119
- PY
120
- return
121
- fi
122
- cd "$path" 2>/dev/null && pwd -P
123
- }
124
-
125
- assert_isolated_worker_worktree() {
126
- local worktree_real worktree_root_real canonical_real retained_real git_common_dir expected_git_common_dir
127
- worktree_real="$(realpath_safe "$WORKTREE")"
128
- worktree_root_real="$(realpath_safe "$WORKTREE_ROOT")"
129
- canonical_real="$(realpath_safe "$CANONICAL_REPO_ROOT")"
130
- retained_real="$(realpath_safe "$RETAINED_REPO_ROOT")"
131
- expected_git_common_dir="$(realpath_safe "${AGENT_REPO_ROOT}/.git")"
132
-
133
- if [[ -z "$worktree_real" || ! -d "$worktree_real" ]]; then
134
- echo "invalid worker worktree: $WORKTREE" >&2
135
- exit 1
136
- fi
137
-
138
- if [[ -n "$canonical_real" && "$worktree_real" == "$canonical_real" ]]; then
139
- echo "refusing to run worker in canonical checkout: $worktree_real" >&2
140
- exit 1
141
- fi
142
-
143
- if [[ -n "$retained_real" && ( "$worktree_real" == "$retained_real" || "${worktree_real}/" == "${retained_real}/"* ) ]]; then
144
- echo "refusing to run worker in retained checkout: $worktree_real" >&2
145
- exit 1
146
- fi
147
-
148
- if [[ -z "$worktree_root_real" || "${worktree_real}/" != "${worktree_root_real}/"* ]]; then
149
- echo "refusing to run worker outside managed worktree root: $worktree_real" >&2
150
- exit 1
151
- fi
152
-
153
- git_common_dir="$(git -C "$WORKTREE" rev-parse --git-common-dir 2>/dev/null || true)"
154
- if [[ -z "$git_common_dir" ]]; then
155
- echo "unable to resolve git common dir for worker worktree: $worktree_real" >&2
156
- exit 1
157
- fi
158
- if [[ "$git_common_dir" == /* ]]; then
159
- git_common_dir="$(realpath_safe "$git_common_dir")"
160
- else
161
- git_common_dir="$(realpath_safe "$WORKTREE/$git_common_dir")"
162
- fi
163
- if [[ -z "$expected_git_common_dir" || "$git_common_dir" != "$expected_git_common_dir" ]]; then
164
- echo "refusing to run worker with non-agent git dir: $git_common_dir" >&2
165
- exit 1
166
- fi
167
- }
168
-
169
- assert_isolated_worker_worktree
170
-
171
- ARGS=(
172
- --mode "$MODE"
173
- --session "$SESSION"
174
- --worktree "$WORKTREE"
175
- --prompt-file "$PROMPT_FILE"
176
- --runs-root "$RUNS_ROOT"
177
- --adapter-id "$ADAPTER_ID"
178
- --task-kind "$TASK_KIND"
179
- --task-id "$TASK_ID"
180
- --env-prefix "F_LOSNING_"
181
- --context "ISSUE_ID=${ISSUE_ID}"
182
- --context "ISSUE_URL=${ISSUE_URL}"
183
- --context "ISSUE_AUTOMERGE=${ISSUE_AUTOMERGE}"
184
- --context "PR_NUMBER=${PR_NUMBER}"
185
- --context "PR_URL=${PR_URL}"
186
- --context "PR_HEAD_REF=${PR_HEAD_REF}"
187
- --context "CODING_WORKER=${CODING_WORKER}"
188
- --context "FLOW_TOOLS_DIR=${FLOW_TOOLS_DIR}"
189
- --context "RESIDENT_WORKER_ENABLED=${RESIDENT_WORKER_ENABLED}"
190
- --context "RESIDENT_WORKER_KEY=${RESIDENT_WORKER_KEY}"
191
- --context "RESIDENT_WORKER_DIR=${RESIDENT_WORKER_DIR}"
192
- --context "RESIDENT_WORKER_META_FILE=${RESIDENT_WORKER_META_FILE}"
193
- --context "RESIDENT_TASK_COUNT=${RESIDENT_TASK_COUNT}"
194
- --context "RESIDENT_WORKTREE_REUSED=${RESIDENT_WORKTREE_REUSED}"
195
- --context "RESIDENT_OPENCLAW_AGENT_ID=${RESIDENT_OPENCLAW_AGENT_ID}"
196
- --context "RESIDENT_OPENCLAW_SESSION_ID=${RESIDENT_OPENCLAW_SESSION_ID}"
197
- --context "RESIDENT_OPENCLAW_AGENT_DIR=${RESIDENT_OPENCLAW_AGENT_DIR}"
198
- --context "RESIDENT_OPENCLAW_STATE_DIR=${RESIDENT_OPENCLAW_STATE_DIR}"
199
- --context "RESIDENT_OPENCLAW_CONFIG_PATH=${RESIDENT_OPENCLAW_CONFIG_PATH}"
200
- --collect-file "pr-comment.md"
201
- --collect-file "issue-comment.md"
202
- --collect-file "verification.jsonl"
203
- )
204
- if [[ -n "$RECONCILE_COMMAND" ]]; then
205
- ARGS+=(--reconcile-command "$RECONCILE_COMMAND")
206
- fi
207
-
208
- case "$CODING_WORKER" in
209
- codex)
210
- ARGS+=(
211
- --safe-profile "${CODEX_PROFILE_SAFE}"
212
- --bypass-profile "${CODEX_PROFILE_BYPASS}"
213
- )
214
- bash "${FLOW_TOOLS_DIR}/agent-project-run-codex-session" "${ARGS[@]}"
215
- ;;
216
- claude)
217
- ARGS+=(
218
- --claude-model "${CLAUDE_MODEL}"
219
- --claude-permission-mode "${CLAUDE_PERMISSION_MODE}"
220
- --claude-effort "${CLAUDE_EFFORT}"
221
- --claude-timeout-seconds "${CLAUDE_TIMEOUT_SECONDS}"
222
- --claude-max-attempts "${CLAUDE_MAX_ATTEMPTS}"
223
- --claude-retry-backoff-seconds "${CLAUDE_RETRY_BACKOFF_SECONDS}"
224
- )
225
- bash "${FLOW_TOOLS_DIR}/agent-project-run-claude-session" "${ARGS[@]}"
226
- ;;
227
- openclaw)
228
- ARGS+=(
229
- --openclaw-model "${OPENCLAW_MODEL}"
230
- --openclaw-thinking "${OPENCLAW_THINKING}"
231
- --openclaw-timeout-seconds "${OPENCLAW_TIMEOUT_SECONDS}"
232
- )
233
- if [[ "${RESIDENT_WORKER_ENABLED}" == "yes" ]]; then
234
- ARGS+=(
235
- --keep-agent
236
- --openclaw-agent-id "${RESIDENT_OPENCLAW_AGENT_ID}"
237
- --openclaw-session-id "${RESIDENT_OPENCLAW_SESSION_ID}"
238
- --openclaw-agent-dir "${RESIDENT_OPENCLAW_AGENT_DIR}"
239
- --openclaw-state-dir "${RESIDENT_OPENCLAW_STATE_DIR}"
240
- --openclaw-config-path "${RESIDENT_OPENCLAW_CONFIG_PATH}"
241
- )
242
- fi
243
- bash "${FLOW_TOOLS_DIR}/agent-project-run-openclaw-session" "${ARGS[@]}"
244
- ;;
245
- opencode)
246
- ARGS+=(
247
- --opencode-model "${OPENCODE_MODEL}"
248
- --opencode-timeout-seconds "${OPENCODE_TIMEOUT_SECONDS}"
249
- )
250
- bash "${FLOW_TOOLS_DIR}/agent-project-run-opencode-session" "${ARGS[@]}"
251
- ;;
252
- kilo)
253
- ARGS+=(
254
- --kilo-model "${KILO_MODEL}"
255
- --kilo-timeout-seconds "${KILO_TIMEOUT_SECONDS}"
256
- )
257
- bash "${FLOW_TOOLS_DIR}/agent-project-run-kilo-session" "${ARGS[@]}"
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
- ;;
276
- *)
277
- echo "unsupported coding worker: ${CODING_WORKER}" >&2
278
- exit 1
279
- ;;
280
- esac
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- exec python3 "${SCRIPT_DIR}/../dashboard/server.py" "$@"
@@ -1,124 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SOURCE_ROOT=""
5
- TARGET_ROOT=""
6
- PATHS_FILE=""
7
- BACKUP_ROOT=""
8
- MOVE_MODE="false"
9
-
10
- usage() {
11
- cat <<'EOF'
12
- Usage:
13
- split-retained-slice.sh --source <path> --target <path> --paths-file <file> [options]
14
-
15
- Copies a curated slice of uncommitted changes from one retained worktree to
16
- another. Optionally removes that slice from the source after verifying the copy.
17
-
18
- Options:
19
- --source <path> Source retained worktree
20
- --target <path> Target retained worktree
21
- --paths-file <file> Newline-delimited relative paths to copy
22
- --backup-root <path> Where to store a safety backup copy (default: mktemp)
23
- --move Remove the copied paths from the source after verify
24
- --help Show this help
25
- EOF
26
- }
27
-
28
- while [[ $# -gt 0 ]]; do
29
- case "$1" in
30
- --source) SOURCE_ROOT="${2:-}"; shift 2 ;;
31
- --target) TARGET_ROOT="${2:-}"; shift 2 ;;
32
- --paths-file) PATHS_FILE="${2:-}"; shift 2 ;;
33
- --backup-root) BACKUP_ROOT="${2:-}"; shift 2 ;;
34
- --move) MOVE_MODE="true"; shift ;;
35
- --help|-h) usage; exit 0 ;;
36
- *) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
37
- esac
38
- done
39
-
40
- if [[ -z "$SOURCE_ROOT" || -z "$TARGET_ROOT" || -z "$PATHS_FILE" ]]; then
41
- usage >&2
42
- exit 1
43
- fi
44
-
45
- for required_path in "$SOURCE_ROOT" "$TARGET_ROOT" "$PATHS_FILE"; do
46
- [[ -e "$required_path" ]] || { echo "missing path: $required_path" >&2; exit 1; }
47
- done
48
-
49
- if [[ ! -d "$SOURCE_ROOT/.git" && ! -f "$SOURCE_ROOT/.git" ]]; then
50
- echo "source is not a git checkout: $SOURCE_ROOT" >&2
51
- exit 1
52
- fi
53
- if [[ ! -d "$TARGET_ROOT/.git" && ! -f "$TARGET_ROOT/.git" ]]; then
54
- echo "target is not a git checkout: $TARGET_ROOT" >&2
55
- exit 1
56
- fi
57
-
58
- if [[ -n "$(git -C "$TARGET_ROOT" status --short)" ]]; then
59
- echo "target worktree must be clean before splitting: $TARGET_ROOT" >&2
60
- exit 1
61
- fi
62
-
63
- if [[ -z "$BACKUP_ROOT" ]]; then
64
- BACKUP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/retained-slice-backup.XXXXXX")"
65
- else
66
- mkdir -p "$BACKUP_ROOT"
67
- fi
68
-
69
- copy_path() {
70
- local source_path="${1:?source path required}"
71
- local dest_root="${2:?destination root required}"
72
- local rel_path="${3:?relative path required}"
73
-
74
- if [[ -d "$source_path" ]]; then
75
- mkdir -p "$(dirname "${dest_root}/${rel_path}")"
76
- rm -rf "${dest_root}/${rel_path}"
77
- cp -R "$source_path" "${dest_root}/${rel_path}"
78
- else
79
- mkdir -p "$(dirname "${dest_root}/${rel_path}")"
80
- cp -p "$source_path" "${dest_root}/${rel_path}"
81
- fi
82
- }
83
-
84
- tracked_path_exists() {
85
- local repo_root="${1:?repo root required}"
86
- local rel_path="${2:?relative path required}"
87
- git -C "$repo_root" ls-files --error-unmatch -- "$rel_path" >/dev/null 2>&1
88
- }
89
-
90
- while IFS= read -r rel_path || [[ -n "$rel_path" ]]; do
91
- [[ -n "$rel_path" ]] || continue
92
- [[ "$rel_path" != \#* ]] || continue
93
-
94
- source_path="${SOURCE_ROOT}/${rel_path}"
95
- [[ -e "$source_path" ]] || { echo "source path missing: $rel_path" >&2; exit 1; }
96
-
97
- copy_path "$source_path" "$BACKUP_ROOT" "$rel_path"
98
- copy_path "$source_path" "$TARGET_ROOT" "$rel_path"
99
-
100
- diff -qr "$source_path" "${TARGET_ROOT}/${rel_path}" >/dev/null
101
- done <"$PATHS_FILE"
102
-
103
- if [[ "$MOVE_MODE" == "true" ]]; then
104
- while IFS= read -r rel_path || [[ -n "$rel_path" ]]; do
105
- [[ -n "$rel_path" ]] || continue
106
- [[ "$rel_path" != \#* ]] || continue
107
-
108
- was_tracked="false"
109
- if tracked_path_exists "$SOURCE_ROOT" "$rel_path"; then
110
- was_tracked="true"
111
- git -C "$SOURCE_ROOT" restore --worktree --source=HEAD -- "$rel_path"
112
- fi
113
-
114
- if [[ "$was_tracked" != "true" && -e "${SOURCE_ROOT}/${rel_path}" ]]; then
115
- rm -rf "${SOURCE_ROOT:?}/${rel_path}"
116
- fi
117
- done <"$PATHS_FILE"
118
- fi
119
-
120
- printf 'SOURCE_ROOT=%s\n' "$SOURCE_ROOT"
121
- printf 'TARGET_ROOT=%s\n' "$TARGET_ROOT"
122
- printf 'PATHS_FILE=%s\n' "$PATHS_FILE"
123
- printf 'BACKUP_ROOT=%s\n' "$BACKUP_ROOT"
124
- printf 'MOVE_MODE=%s\n' "$MOVE_MODE"