@love-moon/conductor-cli 0.11.0 → 0.11.2
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/CHANGELOG.md +97 -0
- package/bin/conductor-config.js +4 -2
- package/bin/conductor-daemon-update.js +55 -0
- package/package.json +5 -5
- package/src/daemon-update.js +614 -0
- package/src/daemon.js +676 -29
- package/src/fire-session-registry.js +136 -0
- package/src/guest-daemon.js +8 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,102 @@
|
|
|
1
1
|
# @love-moon/conductor-cli
|
|
2
2
|
|
|
3
|
+
## 0.11.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 938efe7: Fix "New task from this" when the successor runs on a different daemon.
|
|
8
|
+
|
|
9
|
+
Picking another daemon in the dialog created the successor row and then killed
|
|
10
|
+
it one second later with `new task failed: Could not resolve resume cwd`. The
|
|
11
|
+
server intentionally drops the source machine's paths for a cross-daemon fork,
|
|
12
|
+
and the target daemon had nothing left to resolve: no launch-config `cwd`, no
|
|
13
|
+
worktree, no local project path (the default project has none, and a project
|
|
14
|
+
bound to another daemon is refused by design), and no source session in its own
|
|
15
|
+
session store.
|
|
16
|
+
|
|
17
|
+
Fork modes now fall back to a fresh `<workspace>/<date>/<run>` directory — the
|
|
18
|
+
same fallback `create_task` already uses — so the successor starts like a
|
|
19
|
+
brand-new task on that machine and picks up the conversation through the
|
|
20
|
+
resume-context URL. In-place restarts still fail loudly, because they must reuse
|
|
21
|
+
the original working directory.
|
|
22
|
+
|
|
23
|
+
- @love-moon/conductor-sdk@0.11.2
|
|
24
|
+
- @love-moon/ai-sdk@0.11.2
|
|
25
|
+
|
|
26
|
+
## 0.11.1
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- cd5e428: Add a built-in "Update daemon" action to the web settings Danger zone.
|
|
31
|
+
|
|
32
|
+
This replaces the hand-rolled `update` custom command people were keeping in
|
|
33
|
+
`custom_commands` (upgrade the CLI, then restart the daemon in tmux) with a
|
|
34
|
+
first-class button on any daemon advertising the new `update_daemon` capability.
|
|
35
|
+
|
|
36
|
+
The update is designed so that a failure never leaves the machine without a
|
|
37
|
+
daemon:
|
|
38
|
+
|
|
39
|
+
- It runs in a **detached** updater process, not inside the daemon, so the
|
|
40
|
+
daemon it replaces can exit without taking the update with it — and a
|
|
41
|
+
crashing update cannot take the daemon down either.
|
|
42
|
+
- Install and verification happen **first**. The running daemon is only stopped
|
|
43
|
+
once the new version is installed, reports the expected version, and passes
|
|
44
|
+
the node-pty native check. Anything failing before that aborts with the old
|
|
45
|
+
daemon still running and still serving tasks.
|
|
46
|
+
- A half-removed global install (the `ENOTEMPTY` case) is uninstalled, its
|
|
47
|
+
package directory removed, and the install retried once.
|
|
48
|
+
- Progress is journaled to `~/.conductor/state/daemon-update.json` (full output
|
|
49
|
+
in `~/.conductor/logs/daemon-update.log`), so the outcome survives the restart
|
|
50
|
+
and the web UI can poll for it across the daemon's reconnect.
|
|
51
|
+
|
|
52
|
+
Homebrew installs, non-global installs, and shared guest daemons refuse the
|
|
53
|
+
action up front with the reason shown in the UI.
|
|
54
|
+
|
|
55
|
+
- 8ad51f3: Adopt the tmux-detached Fire processes a previous daemon left running, instead
|
|
56
|
+
of judging them stale and marking their tasks `killed`.
|
|
57
|
+
|
|
58
|
+
With `fire_tmux_mode`, daemon shutdown deliberately leaves Fires alive. But a
|
|
59
|
+
fresh daemon started with an empty `activeTaskProcesses` map, and both stale
|
|
60
|
+
sweeps — `recoverStaleTasks()` on startup and `reconcileAssignedTasks()` on
|
|
61
|
+
websocket reconnect — decided "this task is dead" from that map alone. Every
|
|
62
|
+
survivor of the hand-off was therefore PATCHed to `killed` seconds after the
|
|
63
|
+
new daemon connected, destroying the work the hand-off exists to preserve.
|
|
64
|
+
This regressed three times (2026-07-23, 2026-07-31, 2026-08-31).
|
|
65
|
+
|
|
66
|
+
The daemon now hands its Fires over to its successor:
|
|
67
|
+
|
|
68
|
+
- Each tmux spawn persists a hand-off record under
|
|
69
|
+
`$CONDUCTOR_HOME/daemon/fire-sessions/`. It carries the fields the liveness
|
|
70
|
+
reaper cannot recompute — most importantly `exitMarkerToken`, a per-spawn
|
|
71
|
+
nonce without which a successor could never read a Fire's exit code.
|
|
72
|
+
- Startup enumerates surviving `conductor-fire-*` sessions and re-registers
|
|
73
|
+
them, so they regain the same watcher a freshly spawned Fire has. Both stale
|
|
74
|
+
sweeps wait for that pass before judging anything, and also adopt in place
|
|
75
|
+
any live session they find without a record.
|
|
76
|
+
- A session that outlived the Fire inside it is detected via its exit marker,
|
|
77
|
+
killed, and reported — adopting it would strand the task at `running`.
|
|
78
|
+
|
|
79
|
+
Two failure modes that used to read as "nothing is running" are now handled
|
|
80
|
+
explicitly: `tmux list-sessions` failing (a wedged server, a timeout) is no
|
|
81
|
+
longer indistinguishable from "no sessions", and a `tmux -V` probe that fails
|
|
82
|
+
once at startup no longer makes the daemon blind to tmux for its whole life.
|
|
83
|
+
Neither authorizes a kill any more.
|
|
84
|
+
|
|
85
|
+
Also fixed along the way:
|
|
86
|
+
|
|
87
|
+
- `stop_task`, `restart_task`, `refresh_session_inplace` and duplicate
|
|
88
|
+
`create_task` gated on a record's child process, which an adopted record does
|
|
89
|
+
not have. Stopping an adopted task reported it killed while leaving the Fire
|
|
90
|
+
running; restarting one could spawn a second Fire into the same worktree.
|
|
91
|
+
- `Recovered N stale task(s) to killed` counted candidates rather than
|
|
92
|
+
successes, so it claimed recovery even after the PATCH returned 409 or 500.
|
|
93
|
+
- Tasks whose spawn is still in flight are no longer eligible for stale kills.
|
|
94
|
+
|
|
95
|
+
Behaviour outside `fire_tmux_mode` is unchanged.
|
|
96
|
+
|
|
97
|
+
- @love-moon/conductor-sdk@0.11.1
|
|
98
|
+
- @love-moon/ai-sdk@0.11.1
|
|
99
|
+
|
|
3
100
|
## 0.11.0
|
|
4
101
|
|
|
5
102
|
### Minor Changes
|
package/bin/conductor-config.js
CHANGED
|
@@ -415,8 +415,10 @@ async function main() {
|
|
|
415
415
|
"# Optional features",
|
|
416
416
|
"# ---------------------------------------------------------------------------",
|
|
417
417
|
"",
|
|
418
|
-
"#
|
|
419
|
-
"# picker
|
|
418
|
+
"# Optional: extra Codex auth.json files to switch between from the app's",
|
|
419
|
+
"# account picker (shown only when more than one is listed). The file name",
|
|
420
|
+
"# (without .json) becomes the account name. Without this, quota comes from",
|
|
421
|
+
"# $CODEX_HOME/auth.json (default ~/.codex/auth.json).",
|
|
420
422
|
"# ai_manager:",
|
|
421
423
|
"# codex:",
|
|
422
424
|
"# auth_json:",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Internal entrypoint for the built-in "Update Daemon" action.
|
|
5
|
+
*
|
|
6
|
+
* The daemon spawns this file *detached* (see `createDaemonUpdateHandlers`) and
|
|
7
|
+
* then forgets about it: the updater has to outlive the very daemon it is about
|
|
8
|
+
* to replace. It is deliberately not registered as a `conductor` subcommand —
|
|
9
|
+
* users update interactively with `conductor update`.
|
|
10
|
+
*
|
|
11
|
+
* Usage: node bin/conductor-daemon-update.js '<params-json>'
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import process from "node:process";
|
|
15
|
+
|
|
16
|
+
import { runDaemonUpdate, writeDaemonUpdateStatus } from "../src/daemon-update.js";
|
|
17
|
+
|
|
18
|
+
const raw = process.argv[2];
|
|
19
|
+
if (!raw) {
|
|
20
|
+
process.stderr.write("conductor-daemon-update: missing params JSON argument\n");
|
|
21
|
+
process.exit(2);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let params;
|
|
25
|
+
try {
|
|
26
|
+
params = JSON.parse(raw);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
process.stderr.write(`conductor-daemon-update: invalid params JSON: ${error?.message || error}\n`);
|
|
29
|
+
process.exit(2);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let result;
|
|
33
|
+
try {
|
|
34
|
+
result = await runDaemonUpdate(params, {
|
|
35
|
+
writeLine: (line) => process.stdout.write(`[${new Date().toISOString()}] ${line}\n`),
|
|
36
|
+
});
|
|
37
|
+
} catch (error) {
|
|
38
|
+
// The status file is how the UI learns the outcome; an unexpected crash here
|
|
39
|
+
// must not leave it stuck on "running" forever.
|
|
40
|
+
const message = error?.stack || error?.message || String(error);
|
|
41
|
+
process.stderr.write(`conductor-daemon-update: ${message}\n`);
|
|
42
|
+
writeDaemonUpdateStatus(params.statusPath, {
|
|
43
|
+
runId: params.runId ?? null,
|
|
44
|
+
status: "failed",
|
|
45
|
+
phase: "done",
|
|
46
|
+
message: "Update failed",
|
|
47
|
+
error: message,
|
|
48
|
+
logPath: params.logPath ?? null,
|
|
49
|
+
daemonRestarted: false,
|
|
50
|
+
finishedAt: new Date().toISOString(),
|
|
51
|
+
});
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
process.exit(result.status === "completed" ? 0 : 1);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@love-moon/conductor-cli",
|
|
3
|
-
"version": "0.11.
|
|
4
|
-
"gitCommitId": "
|
|
3
|
+
"version": "0.11.2",
|
|
4
|
+
"gitCommitId": "067735d",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/lovemoon-ai/conductor.git"
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"test": "node --test test/*.test.js"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@love-moon/ai-sdk": "0.11.
|
|
28
|
-
"@love-moon/conductor-sdk": "0.11.
|
|
27
|
+
"@love-moon/ai-sdk": "0.11.2",
|
|
28
|
+
"@love-moon/conductor-sdk": "0.11.2",
|
|
29
29
|
"@github/copilot-sdk": "^0.3.0",
|
|
30
30
|
"chrome-launcher": "^1.2.1",
|
|
31
31
|
"chrome-remote-interface": "^0.33.0",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
40
|
"@roamhq/wrtc": "^0.10.0",
|
|
41
|
-
"@love-moon/chat-web": "0.11.
|
|
41
|
+
"@love-moon/chat-web": "0.11.2"
|
|
42
42
|
},
|
|
43
43
|
"pnpm": {
|
|
44
44
|
"onlyBuiltDependencies": [
|