aiur-cli 0.0.8 → 0.0.9-nightly.3c81f85
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/bin/aiur.js +37 -17
- package/libexec/aiur-engine.sh +55 -19
- package/package.json +4 -4
package/bin/aiur.js
CHANGED
|
@@ -165,8 +165,8 @@ function ensureTmux() {
|
|
|
165
165
|
// True only when the pinned opencode is on PATH; a wrong (e.g. newer,
|
|
166
166
|
// unverified) version must be replaced with the pin, so presence alone
|
|
167
167
|
// isn't enough.
|
|
168
|
-
function opencodeMatchesPin() {
|
|
169
|
-
const result = safeSpawn(
|
|
168
|
+
function opencodeMatchesPin(command = "opencode") {
|
|
169
|
+
const result = safeSpawn(command, ["--version"], { encoding: "utf8" });
|
|
170
170
|
return !result.error && result.status === 0 && (result.stdout || "").trim() === opencodeVersion();
|
|
171
171
|
}
|
|
172
172
|
|
|
@@ -185,40 +185,60 @@ function installOpencode() {
|
|
|
185
185
|
return !result.error && result.status === 0;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// npm's global bin may be shadowed by another OpenCode on the incoming PATH.
|
|
189
|
+
// Verify the actual installed executable before making it the release's choice.
|
|
190
|
+
function selectGlobalOpencode() {
|
|
191
|
+
const result = safeSpawn("npm", ["prefix", "-g"], { encoding: "utf8" });
|
|
192
|
+
if (result.error || result.status !== 0) return false;
|
|
193
|
+
const prefix = (result.stdout || "").trim();
|
|
194
|
+
if (!path.isAbsolute(prefix)) return false;
|
|
195
|
+
const bin = path.join(prefix, "bin");
|
|
196
|
+
if (!opencodeMatchesPin(path.join(bin, "opencode"))) return false;
|
|
197
|
+
process.env.PATH = `${bin}${path.delimiter}${process.env.PATH || ""}`;
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
188
201
|
// opencode powers the interactive "take the wheel" panes. Non-fatal: everything
|
|
189
202
|
// else works without it.
|
|
190
203
|
function ensureOpencode() {
|
|
191
|
-
if (opencodeMatchesPin()) return;
|
|
204
|
+
if (opencodeMatchesPin() || selectGlobalOpencode()) return;
|
|
192
205
|
if (process.env.AIUR_SKIP_OPENCODE_INSTALL !== "1") {
|
|
193
206
|
process.stderr.write(
|
|
194
207
|
`aiur: provisioning opencode@${opencodeVersion()} (one-time, for the interactive 'take the wheel' panes)…\n`,
|
|
195
208
|
);
|
|
196
209
|
installOpencode();
|
|
197
|
-
if (opencodeMatchesPin()) return;
|
|
210
|
+
if (opencodeMatchesPin() || selectGlobalOpencode()) return;
|
|
198
211
|
}
|
|
199
212
|
process.stderr.write(
|
|
200
|
-
|
|
213
|
+
`aiur: opencode@${opencodeVersion()} is unavailable. The interactive 'take the wheel' ` +
|
|
201
214
|
"feature needs it; everything else works without it. " +
|
|
202
|
-
|
|
215
|
+
`Install with: npm install -g opencode-ai@${opencodeVersion()}, ` +
|
|
216
|
+
"and put npm's global bin ahead of other opencode binaries on PATH.\n",
|
|
203
217
|
);
|
|
204
218
|
}
|
|
205
219
|
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
220
|
+
// Match the shared engine's first-argument dispatch: only session launch paths
|
|
221
|
+
// need interactive tools. Unknown commands still reach the engine's usage error.
|
|
222
|
+
function requiresInteractiveTools(argv) {
|
|
223
|
+
const command = argv[0] || "";
|
|
224
|
+
if (["", "run", "restart", "--bg"].includes(command)) return true;
|
|
225
|
+
const nonLaunchCommands = new Set([
|
|
226
|
+
"__identity", "help", "-h", "-help", "--h", "--help", "--version", "--todo", "--only",
|
|
227
|
+
"init", "findings", "ask", "asks", "status", "usage", "agents", "commands", "units",
|
|
228
|
+
"build-orders", "analytics", "github-cost", "github-usage", "alerts", "watch", "set",
|
|
229
|
+
"upgrade", "pause", "resume", "reset-budget", "message", "cleanup-stale", "stop",
|
|
230
|
+
"executor-answer", "executor-escalate", "executor-moot", "executor-listen", "executor-wait",
|
|
231
|
+
"executor-emit", "executor-subscribe", "executor-unsubscribe", "executor-subscriptions",
|
|
232
|
+
"executor-roster", "executor-fast-forward", "executor-claim", "executor-release", "executor-revoke",
|
|
233
|
+
]);
|
|
234
|
+
if (nonLaunchCommands.has(command)) return false;
|
|
235
|
+
return command.startsWith("-") || fs.existsSync(command);
|
|
216
236
|
}
|
|
217
237
|
|
|
218
238
|
function main() {
|
|
219
239
|
const releaseDir = resolveReleaseDir();
|
|
220
240
|
|
|
221
|
-
if (
|
|
241
|
+
if (requiresInteractiveTools(process.argv.slice(2))) {
|
|
222
242
|
ensureTmux();
|
|
223
243
|
ensureOpencode();
|
|
224
244
|
}
|
package/libexec/aiur-engine.sh
CHANGED
|
@@ -560,6 +560,46 @@ parse_todo_args() {
|
|
|
560
560
|
[ "$saw_todo" -eq 1 ] && [ "${#parsed_targets[@]}" -gt 0 ]
|
|
561
561
|
}
|
|
562
562
|
|
|
563
|
+
# `--todo` is the one control command whose runtime scales with its arguments
|
|
564
|
+
# rather than with daemon state: every requested ID is a GitHub issue fetch, and
|
|
565
|
+
# `--only` adds an active-ticket enumeration plus up to 50 serial label DELETEs.
|
|
566
|
+
# On a repo with a deep `agent:todo` queue that is minutes of network work, and
|
|
567
|
+
# the shared 10s budget killed it every time — labels half-applied, outcome
|
|
568
|
+
# reported as unknown, `--only` scoping unusable (#2519). Size the watchdog to
|
|
569
|
+
# the work instead. An explicit operator override still wins outright.
|
|
570
|
+
todo_rpc_seconds_base=15
|
|
571
|
+
todo_rpc_seconds_per_id=3
|
|
572
|
+
todo_rpc_seconds_only=90
|
|
573
|
+
# The daemon is handed a budget this many seconds shorter than the watchdog, so
|
|
574
|
+
# it always stops itself and prints its summary and exit marker before the
|
|
575
|
+
# watchdog can discard them.
|
|
576
|
+
todo_rpc_grace_seconds=10
|
|
577
|
+
|
|
578
|
+
todo_rpc_seconds() {
|
|
579
|
+
local id_count="$1" only="$2" seconds
|
|
580
|
+
|
|
581
|
+
# Only a usable override wins. Everywhere else an unset, zero, or malformed
|
|
582
|
+
# value falls back to the shared 10s default; here that default is the bug, so
|
|
583
|
+
# fall back to work-proportional sizing instead.
|
|
584
|
+
if [[ "${AIUR_CONTROL_RPC_TIMEOUT_SECONDS:-}" =~ ^[1-9][0-9]*$ ]]; then
|
|
585
|
+
printf '%s' "$AIUR_CONTROL_RPC_TIMEOUT_SECONDS"
|
|
586
|
+
return 0
|
|
587
|
+
fi
|
|
588
|
+
|
|
589
|
+
seconds=$((todo_rpc_seconds_base + todo_rpc_seconds_per_id * id_count))
|
|
590
|
+
[ "$only" -eq 1 ] && seconds=$((seconds + todo_rpc_seconds_only))
|
|
591
|
+
printf '%s' "$seconds"
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
# Never hand the daemon a non-positive budget: an operator who sets the override
|
|
595
|
+
# below the grace window should still get a bounded run rather than an unlimited
|
|
596
|
+
# one.
|
|
597
|
+
todo_daemon_budget_ms() {
|
|
598
|
+
local seconds=$(($1 - todo_rpc_grace_seconds))
|
|
599
|
+
[ "$seconds" -ge 1 ] || seconds=1
|
|
600
|
+
printf '%s' $((seconds * 1000))
|
|
601
|
+
}
|
|
602
|
+
|
|
563
603
|
run_todo() {
|
|
564
604
|
if ! parse_todo_args "$@"; then
|
|
565
605
|
echo "aiur: --todo expects one or more numeric issue IDs, optionally followed by --only" >&2
|
|
@@ -568,7 +608,13 @@ run_todo() {
|
|
|
568
608
|
|
|
569
609
|
local only_arg="false"
|
|
570
610
|
[ "$parsed_todo_only" -eq 1 ] && only_arg="true"
|
|
571
|
-
|
|
611
|
+
|
|
612
|
+
local seconds budget_ms
|
|
613
|
+
seconds="$(todo_rpc_seconds "${#parsed_targets[@]}" "$parsed_todo_only")"
|
|
614
|
+
budget_ms="$(todo_daemon_budget_ms "$seconds")"
|
|
615
|
+
|
|
616
|
+
AIUR_CONTROL_RPC_TIMEOUT_SECONDS="$seconds" \
|
|
617
|
+
run_control_rpc "Aiur.AgentControlCLI.todo($(elixir_list_literal "${parsed_targets[@]}"), only: $only_arg, budget_ms: $budget_ms, emit_exit_marker: true)"
|
|
572
618
|
}
|
|
573
619
|
|
|
574
620
|
# --- one-shot: findings (distribution-free, no daemon/tmux) -------------------
|
|
@@ -677,22 +723,10 @@ scrub_run_only_env() {
|
|
|
677
723
|
}
|
|
678
724
|
|
|
679
725
|
run_argv=()
|
|
680
|
-
# Default dashboard bind host.
|
|
681
|
-
#
|
|
682
|
-
# fall back to loopback when Tailscale is absent, or when dashboard credentials
|
|
683
|
-
# are unset (a non-loopback bind requires them, so we stay on loopback rather
|
|
684
|
-
# than refuse to start). The BEAM applies this below an explicit `server.host`,
|
|
685
|
-
# while an explicit `--host` remains the highest-precedence value.
|
|
726
|
+
# Default dashboard bind host. Remote access is an explicit operator choice.
|
|
727
|
+
# The BEAM applies this below `server.host`; `--host` has highest precedence.
|
|
686
728
|
default_dashboard_host() {
|
|
687
|
-
|
|
688
|
-
if command -v tailscale >/dev/null 2>&1; then
|
|
689
|
-
ip="$(tailscale ip -4 2>/dev/null | grep -m1 -E '^100\.[0-9]+\.[0-9]+\.[0-9]+$' || true)"
|
|
690
|
-
fi
|
|
691
|
-
if [ -n "$ip" ] && [ -n "${AIUR_DASHBOARD_USERNAME:-}" ] && [ -n "${AIUR_DASHBOARD_PASSWORD:-}" ]; then
|
|
692
|
-
printf '%s' "$ip"
|
|
693
|
-
else
|
|
694
|
-
printf '127.0.0.1'
|
|
695
|
-
fi
|
|
729
|
+
printf '%s' "${AIUR_DEFAULT_DASHBOARD_HOST:-127.0.0.1}"
|
|
696
730
|
}
|
|
697
731
|
|
|
698
732
|
build_run_argv() {
|
|
@@ -834,9 +868,10 @@ run_session() {
|
|
|
834
868
|
# supplied. `aiur --bg --interactive` opts back into the full terminal stack
|
|
835
869
|
# for an attachable background session.
|
|
836
870
|
build_run_argv "$mode" "$@"
|
|
837
|
-
local no_dashboard=0
|
|
871
|
+
local no_dashboard=0 surface_mode=interactive
|
|
838
872
|
for run_arg in "${run_argv[@]}"; do
|
|
839
873
|
[ "$run_arg" = "--no-dashboard" ] && no_dashboard=1
|
|
874
|
+
[ "$run_arg" = "--headless" ] && surface_mode=headless
|
|
840
875
|
done
|
|
841
876
|
write_argv "${run_argv[@]}"
|
|
842
877
|
export AIUR_ARGV_FILE="$argv_file"
|
|
@@ -1043,7 +1078,7 @@ run_session() {
|
|
|
1043
1078
|
exit 1
|
|
1044
1079
|
fi
|
|
1045
1080
|
|
|
1046
|
-
write_aiur_instance_record "$session" "$socket"
|
|
1081
|
+
write_aiur_instance_record "$session" "$socket" replace "$surface_mode"
|
|
1047
1082
|
release_aiur_launch_lock "$launch_lock"
|
|
1048
1083
|
_session_launch_lock=""
|
|
1049
1084
|
print_config_status "$startup_capture"
|
|
@@ -1549,7 +1584,7 @@ release_aiur_launch_lock() {
|
|
|
1549
1584
|
}
|
|
1550
1585
|
|
|
1551
1586
|
write_aiur_instance_record() {
|
|
1552
|
-
local session="$1" socket="$2" write_mode="${3:-replace}" record_dir record tmp root
|
|
1587
|
+
local session="$1" socket="$2" write_mode="${3:-replace}" surface_mode="${4:-unknown}" record_dir record tmp root
|
|
1553
1588
|
record_dir="$(aiur_instances_dir)"
|
|
1554
1589
|
record="$(aiur_instance_record_path)"
|
|
1555
1590
|
root="$(canonical_workspace_root "${AIUR_PROJECT_ROOT:-}")"
|
|
@@ -1561,6 +1596,7 @@ write_aiur_instance_record() {
|
|
|
1561
1596
|
printf 'AIUR_RECORD_SESSION=%q\n' "$session"
|
|
1562
1597
|
printf 'AIUR_RECORD_SOCKET=%q\n' "$socket"
|
|
1563
1598
|
printf 'AIUR_RECORD_AGENT_TMPFILE=%q\n' "${AIUR_AGENT_TMPFILE:-}"
|
|
1599
|
+
printf 'AIUR_RECORD_SURFACE_MODE=%q\n' "$surface_mode"
|
|
1564
1600
|
printf 'AIUR_RECORD_WORKSPACE_ROOT_FILE=%q\n' "${AIUR_WORKSPACE_ROOT_FILE:-}"
|
|
1565
1601
|
printf 'AIUR_RECORD_PROJECT_ROOT=%q\n' "$root"
|
|
1566
1602
|
printf 'AIUR_RECORD_PROJECT_ROOT_SOURCE=%q\n' "${AIUR_PROJECT_ROOT_SOURCE:-}"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiur-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9-nightly.3c81f85",
|
|
4
4
|
"description": "AI Unit Runtime for Executors.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/aiur-team/aiur",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
],
|
|
36
36
|
"opencodeVersion": "1.17.10",
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"aiur-cli-linux-x64": "0.0.
|
|
39
|
-
"aiur-cli-linux-arm64": "0.0.
|
|
40
|
-
"aiur-cli-darwin-arm64": "0.0.
|
|
38
|
+
"aiur-cli-linux-x64": "0.0.9-nightly.3c81f85",
|
|
39
|
+
"aiur-cli-linux-arm64": "0.0.9-nightly.3c81f85",
|
|
40
|
+
"aiur-cli-darwin-arm64": "0.0.9-nightly.3c81f85"
|
|
41
41
|
}
|
|
42
42
|
}
|