@cydm/happy-elves 0.1.0-beta.633 → 0.1.0-beta.634
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
CHANGED
|
@@ -6,8 +6,8 @@ Public beta CLI for Happy Elves.
|
|
|
6
6
|
|
|
7
7
|
Run once in the existing user account; it detects %USERPROFILE%\.happy-elves\hosted, keeps the current daemon and sessions running, installs the independent updater, and registers per-user startup.
|
|
8
8
|
|
|
9
|
-
npm.cmd install --prefix $HOME\.happy-elves\management-entry --ignore-scripts --no-audit --no-fund --package-lock=false @cydm/happy-elves@0.1.0-beta.
|
|
10
|
-
npm.cmd exec --yes --package @cydm/happy-elves@0.1.0-beta.
|
|
9
|
+
npm.cmd install --prefix $HOME\.happy-elves\management-entry --ignore-scripts --no-audit --no-fund --package-lock=false @cydm/happy-elves@0.1.0-beta.634
|
|
10
|
+
npm.cmd exec --yes --package @cydm/happy-elves@0.1.0-beta.634 -- happy-elves-updater install --state-root $HOME\.happy-elves\hosted --autostart
|
|
11
11
|
|
|
12
12
|
The same updater entrypoint works on macOS after selecting a permanent user prefix.
|
|
13
13
|
|
package/apps/cli/package.json
CHANGED
|
@@ -748,6 +748,9 @@ export async function connectOnce(config) {
|
|
|
748
748
|
token: config.machineToken,
|
|
749
749
|
nodeKind: "machine",
|
|
750
750
|
nodeId: config.machineId,
|
|
751
|
+
// The daemon only needs presence, manifests and machine commands.
|
|
752
|
+
// Full retained transcripts can exceed the Relay send budget.
|
|
753
|
+
snapshotMode: "routing",
|
|
751
754
|
};
|
|
752
755
|
ws.send(JSON.stringify(hello));
|
|
753
756
|
});
|
|
@@ -776,7 +779,7 @@ export async function connectOnce(config) {
|
|
|
776
779
|
await appendUnscopedRelayError(config, "DAEMON_COMMAND_FAILED", error);
|
|
777
780
|
});
|
|
778
781
|
});
|
|
779
|
-
ws.addEventListener("close", () => {
|
|
782
|
+
ws.addEventListener("close", (event) => {
|
|
780
783
|
authenticated = false;
|
|
781
784
|
clearActiveRelaySocket(ws);
|
|
782
785
|
if (loopTimer)
|
|
@@ -785,7 +788,7 @@ export async function connectOnce(config) {
|
|
|
785
788
|
clearInterval(scheduleTimer);
|
|
786
789
|
if (orchestrationTimer)
|
|
787
790
|
clearInterval(orchestrationTimer);
|
|
788
|
-
console.log(
|
|
791
|
+
console.log(`Relay connection closed${event.code ? ` (code ${event.code})` : ""}; reconnecting...`);
|
|
789
792
|
resolve();
|
|
790
793
|
});
|
|
791
794
|
ws.addEventListener("error", () => {
|
package/apps/daemon/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cydm/happy-elves",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.634",
|
|
4
4
|
"description": "Remote controller for local coding agents with hosted or self-hosted relay support.",
|
|
5
|
-
"buildId": "
|
|
6
|
-
"sourceCommit": "
|
|
5
|
+
"buildId": "8ddea898d758800d92712964ca969e81",
|
|
6
|
+
"sourceCommit": "5619fccb7a9bfaa976dd1384e1a399f6707889ec",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"type": "module",
|
|
9
9
|
"bin": {
|
|
@@ -41,6 +41,8 @@ class CodexHeadlessRuntimeProvider {
|
|
|
41
41
|
sidechat: { strategy: "native", forkIsolation: "clean" },
|
|
42
42
|
};
|
|
43
43
|
clients = new Map();
|
|
44
|
+
connectingClients = new Map();
|
|
45
|
+
disposing = false;
|
|
44
46
|
// Native history is read through a short-lived app-server so a long-lived
|
|
45
47
|
// writer connection cannot replay its cached thread snapshot after an
|
|
46
48
|
// external Codex CLI turn. The reader is never used for resume/start/turn
|
|
@@ -702,10 +704,11 @@ class CodexHeadlessRuntimeProvider {
|
|
|
702
704
|
await active.client.request("turn/steer", { threadId: active.codexThreadId, expectedTurnId: codexTurnId, input: input.input });
|
|
703
705
|
}
|
|
704
706
|
async dispose() {
|
|
707
|
+
this.disposing = true;
|
|
705
708
|
const active = [...this.activeTurnsByRuntimeTurn.values()];
|
|
706
709
|
this.failActiveTurns(new Error("Codex app-server disposed."));
|
|
707
710
|
await Promise.all(active.map((turn) => turn.queue.catch(() => undefined)));
|
|
708
|
-
const clients = [...new Set(this.clients.values())];
|
|
711
|
+
const clients = [...new Set([...this.clients.values(), ...[...this.connectingClients.values()].map((entry) => entry.client)])];
|
|
709
712
|
this.clients.clear();
|
|
710
713
|
this.nativeHistoryRefreshPending.clear();
|
|
711
714
|
await Promise.all(clients.map((client) => client.close()));
|
|
@@ -713,9 +716,14 @@ class CodexHeadlessRuntimeProvider {
|
|
|
713
716
|
this.pendingSidechatCleanup.clear();
|
|
714
717
|
}
|
|
715
718
|
async ensureClient(cwd, clientProfile = "default", clientKey = codexCatalogClientKey(clientProfile)) {
|
|
719
|
+
if (this.disposing)
|
|
720
|
+
throw new HeadlessRuntimeCoreError("INVALID_REQUEST", "Codex app-server provider is disposed.");
|
|
716
721
|
const existing = this.clients.get(clientKey);
|
|
717
722
|
if (existing?.isAlive())
|
|
718
723
|
return existing;
|
|
724
|
+
const connecting = this.connectingClients.get(clientKey);
|
|
725
|
+
if (connecting)
|
|
726
|
+
return await connecting.ready;
|
|
719
727
|
const client = new CodexAppServerClient({
|
|
720
728
|
command: this.options.command ?? process.env.HAPPY_ELVES_CODEX_COMMAND ?? "codex",
|
|
721
729
|
args: codexAppServerArgs(clientProfile),
|
|
@@ -738,15 +746,25 @@ class CodexHeadlessRuntimeProvider {
|
|
|
738
746
|
this.failActiveTurns(error, client);
|
|
739
747
|
},
|
|
740
748
|
});
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
749
|
+
const ready = (async () => {
|
|
750
|
+
try {
|
|
751
|
+
await client.connect();
|
|
752
|
+
if (this.disposing)
|
|
753
|
+
throw new HeadlessRuntimeCoreError("INVALID_REQUEST", "Codex app-server provider is disposed.");
|
|
754
|
+
this.clients.set(clientKey, client);
|
|
755
|
+
return client;
|
|
756
|
+
}
|
|
757
|
+
catch (error) {
|
|
758
|
+
await client.close().catch(() => undefined);
|
|
759
|
+
throw error;
|
|
760
|
+
}
|
|
761
|
+
finally {
|
|
762
|
+
if (this.connectingClients.get(clientKey)?.client === client)
|
|
763
|
+
this.connectingClients.delete(clientKey);
|
|
764
|
+
}
|
|
765
|
+
})();
|
|
766
|
+
this.connectingClients.set(clientKey, { client, ready });
|
|
767
|
+
return await ready;
|
|
750
768
|
}
|
|
751
769
|
async replaceClientAfterNativeHistoryRefresh(cwd, clientProfile, threadId) {
|
|
752
770
|
const clientKey = codexClientKeyForThread(threadId, clientProfile);
|