totemlayer 0.1.92 → 0.1.94
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/agent-runner.mjs +23 -5
- package/bin/agent-setup.mjs +11 -1
- package/bin/automatic-runtime.mjs +8 -4
- package/bin/installation.mjs +9 -0
- package/bin/native/darwin-lifetime +0 -0
- package/bin/native/darwin-lifetime.json +1 -1
- package/bin/setup-assets/api-manifest.json +1 -1
- package/bin/setup-assets/manifest.json +1 -1
- package/bin/startup-diagnostics.mjs +18 -1
- package/package.json +1 -1
package/bin/agent-runner.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { parseArgs } from "node:util";
|
|
|
12
12
|
import { readAgentCredential, readAgentProfile, withAgentProfileLock } from "./agent-profile.mjs";
|
|
13
13
|
import { localClientEnvironment } from "./platform-client.mjs";
|
|
14
14
|
import { Totem } from "./sdk/index.js";
|
|
15
|
-
import { runtimeRoot, privateWrite } from "./runtime-installation.mjs";
|
|
15
|
+
import { runtimeRoot, privateRead, privateWrite } from "./runtime-installation.mjs";
|
|
16
16
|
import { RUNTIME_ERROR_CODES, runtimeErrorCode } from "./runtime-diagnostics.mjs";
|
|
17
17
|
|
|
18
18
|
const PACKAGE_VERSION = JSON.parse(
|
|
@@ -585,12 +585,12 @@ export async function runAgentSession(profile, options = {}) {
|
|
|
585
585
|
} catch (error) {
|
|
586
586
|
result = 1;
|
|
587
587
|
const diagnostic = startupDiagnostic(error);
|
|
588
|
-
if (!diagnostic.retryable)
|
|
588
|
+
if (!diagnostic.retryable || diagnostic.retryAt)
|
|
589
589
|
await privateWrite(join(profile.stateDirectory, "automatic-health.json"), {
|
|
590
|
-
state: "needs_attention",
|
|
590
|
+
state: diagnostic.retryAt ? "waiting" : "needs_attention",
|
|
591
591
|
code: "LISTENER_START_FAILED",
|
|
592
592
|
...diagnostic,
|
|
593
|
-
retryAt: null,
|
|
593
|
+
retryAt: diagnostic.retryAt ?? null,
|
|
594
594
|
updatedAt: new Date().toISOString(),
|
|
595
595
|
});
|
|
596
596
|
emit({
|
|
@@ -680,12 +680,30 @@ export async function agentStartMain(args, options = {}) {
|
|
|
680
680
|
}
|
|
681
681
|
let profile = await readAgentProfile(parsed.profile, { environment });
|
|
682
682
|
assertExecutorConfigured(profile);
|
|
683
|
+
if (automatic) {
|
|
684
|
+
const health = await privateRead(join(profile.stateDirectory, "automatic-health.json")).catch(
|
|
685
|
+
(error) => {
|
|
686
|
+
if (error.code !== "ENOENT") throw error;
|
|
687
|
+
return null;
|
|
688
|
+
},
|
|
689
|
+
);
|
|
690
|
+
const cooldown = startupDiagnostic(health);
|
|
691
|
+
if (
|
|
692
|
+
cooldown.causeCode === "CHAT_PROMPT_RATE_LIMITED" &&
|
|
693
|
+
cooldown.retryAt &&
|
|
694
|
+
!(await readAgentRuntimeStatus(profile)).running
|
|
695
|
+
)
|
|
696
|
+
throw Object.assign(new Error(cooldown.cause), {
|
|
697
|
+
code: cooldown.causeCode,
|
|
698
|
+
retryAt: cooldown.retryAt,
|
|
699
|
+
});
|
|
700
|
+
}
|
|
683
701
|
if (
|
|
684
702
|
profile.interactiveRequired &&
|
|
685
703
|
(!profile.codexThreadId ||
|
|
686
704
|
!(await (await import("./harness-bootstrap.mjs")).harnessStartupReady(profile)))
|
|
687
705
|
) {
|
|
688
|
-
if (!automatic && profile.codexThreadId) {
|
|
706
|
+
if (!automatic && (profile.codexThreadId || profile.codexNativeCallbacks)) {
|
|
689
707
|
// Explicit start can finish this selected binding; passive recovery cannot unpause it.
|
|
690
708
|
const { setAutomaticEnabled } = await import("./automatic-runtime.mjs");
|
|
691
709
|
const { ensureInteractiveHarness } = await import("./harness-bootstrap.mjs");
|
package/bin/agent-setup.mjs
CHANGED
|
@@ -480,6 +480,11 @@ export async function agentSetupMain(args, options = {}) {
|
|
|
480
480
|
"This profile is bound to another agent or origin. Choose a new profile or explicitly use --replace.",
|
|
481
481
|
);
|
|
482
482
|
const repositoryRoots = await selectedRepositories(selectedRoots, previous, io);
|
|
483
|
+
const nativeCallbacks = Boolean(
|
|
484
|
+
mode === "codex" &&
|
|
485
|
+
identity.listenerConnectionId &&
|
|
486
|
+
(previous?.codexNativeCallbacks || (!previous && !codexThreadId)),
|
|
487
|
+
);
|
|
483
488
|
let profile;
|
|
484
489
|
try {
|
|
485
490
|
profile = await saveAgentProfile(
|
|
@@ -496,7 +501,8 @@ export async function agentSetupMain(args, options = {}) {
|
|
|
496
501
|
repositoryRoots,
|
|
497
502
|
...(["codex", "claude"].includes(mode) ? { client: mode } : {}),
|
|
498
503
|
...(codexThreadId === undefined ? {} : { codexThreadId }),
|
|
499
|
-
...(
|
|
504
|
+
...(nativeCallbacks ? { codexNativeCallbacks: true } : {}),
|
|
505
|
+
...(!connectionOnly && (previous?.interactiveRequired || nativeCallbacks)
|
|
500
506
|
? { interactiveRequired: true }
|
|
501
507
|
: {}),
|
|
502
508
|
},
|
|
@@ -525,6 +531,10 @@ export async function agentSetupMain(args, options = {}) {
|
|
|
525
531
|
// connection into a persistent opt-out. An existing pause stays untouched.
|
|
526
532
|
if (!connectionOnly && !flags["no-start"] && !io.deferActivation) {
|
|
527
533
|
try {
|
|
534
|
+
if (nativeCallbacks)
|
|
535
|
+
profile = await (
|
|
536
|
+
io.ensureHarness ?? (await import("./harness-bootstrap.mjs")).ensureInteractiveHarness
|
|
537
|
+
)(profile, io.env);
|
|
528
538
|
const activate =
|
|
529
539
|
io.activateConnection ?? (await import("./installation.mjs")).activateConnection;
|
|
530
540
|
automatic = await activate(profile, io.env);
|
|
@@ -151,7 +151,11 @@ export async function superviseOnce(env = process.env, options = {}) {
|
|
|
151
151
|
continue;
|
|
152
152
|
}
|
|
153
153
|
const newAcceptance = activationIds.some((id) => !health?.activationIds?.includes(id));
|
|
154
|
-
if (
|
|
154
|
+
if (
|
|
155
|
+
(!newAcceptance || health?.causeCode === "CHAT_PROMPT_RATE_LIMITED") &&
|
|
156
|
+
Number.isFinite(health?.retryAt) &&
|
|
157
|
+
health.retryAt > Date.now()
|
|
158
|
+
)
|
|
155
159
|
continue;
|
|
156
160
|
// The run-local journal decides whether any interrupted work can safely resume.
|
|
157
161
|
const result = await (options.start ?? agentStartMain)(
|
|
@@ -205,9 +209,9 @@ export async function superviseOnce(env = process.env, options = {}) {
|
|
|
205
209
|
code: "LISTENER_START_FAILED",
|
|
206
210
|
...diagnostic,
|
|
207
211
|
attempts: attempts + 1,
|
|
208
|
-
retryAt:
|
|
209
|
-
|
|
210
|
-
: null,
|
|
212
|
+
retryAt:
|
|
213
|
+
diagnostic.retryAt ??
|
|
214
|
+
(diagnostic.retryable ? Date.now() + Math.min(300000, 5000 * 2 ** attempts) : null),
|
|
211
215
|
updatedAt: new Date().toISOString(),
|
|
212
216
|
}).catch(() => {});
|
|
213
217
|
/* One offline/revoked connection cannot stop other profiles. */
|
package/bin/installation.mjs
CHANGED
|
@@ -20,6 +20,15 @@ export async function activateConnection(profile, env = process.env, options = {
|
|
|
20
20
|
if (error.code !== "ENOENT") throw error;
|
|
21
21
|
},
|
|
22
22
|
);
|
|
23
|
+
const cooldown = startupDiagnostic(health);
|
|
24
|
+
if (cooldown.causeCode === "CHAT_PROMPT_RATE_LIMITED" && cooldown.retryAt)
|
|
25
|
+
return {
|
|
26
|
+
state: "needs_attention",
|
|
27
|
+
ready: false,
|
|
28
|
+
...cooldown,
|
|
29
|
+
message:
|
|
30
|
+
"Automatic receiving is waiting for its existing chat prompt cooldown. Saved messages remain queued.",
|
|
31
|
+
};
|
|
23
32
|
if (health?.retryable === false)
|
|
24
33
|
return { state: "needs_attention", ready: false, ...startupDiagnostic(health) };
|
|
25
34
|
try {
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"sourceSha256":"e15dc6cfd6f828dbcb829fc6fa3f5f6ef51062f45462ec6532b8c52f532c7951","binarySha256":"
|
|
1
|
+
{"sourceSha256":"e15dc6cfd6f828dbcb829fc6fa3f5f6ef51062f45462ec6532b8c52f532c7951","binarySha256":"f516045a8e5ecb13e997c44785abad1e340e77cc4d7782e6bdbc3972ec33ceb7","architectures":["arm64","x86_64"],"minimumMacOS":"13.0"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":1,"packageVersion":"0.1.
|
|
1
|
+
{"version":1,"packageVersion":"0.1.94","bytes":27189,"sha256":"c62a0116c76177d905051b40ddcbb0503e042b1fc8f5d024c1ebf41c7f173983"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":1,"packageVersion":"0.1.
|
|
1
|
+
{"version":1,"packageVersion":"0.1.94","bytes":36144,"sha256":"66535754c594ad559c91b68c93348ec5579f10a0d791c462cecf98cb618ea2ae"}
|
|
@@ -4,6 +4,10 @@ export const HOST_APPROVAL_RECOVERY =
|
|
|
4
4
|
"Stop retrying. Ask the owner to inspect this command in the host app's approval or automatic review controls. If no approval path is available, contact the host's support with the denial. Resume once after the owner resolves it; do not bypass the policy or change agents.";
|
|
5
5
|
|
|
6
6
|
const causes = {
|
|
7
|
+
CHAT_PROMPT_RATE_LIMITED: [
|
|
8
|
+
"Automatic chat prompts are waiting for their existing cooldown.",
|
|
9
|
+
"Keep saved messages queued. Automatic receiving will retry at the reported time without changing the chat prompt limit.",
|
|
10
|
+
],
|
|
7
11
|
STARTUP_CONFLICT: [
|
|
8
12
|
"The existing startup task or shortcut uses a different command.",
|
|
9
13
|
"Inspect the current-user Windows startup task with totem repair-startup. Apply only its reviewed task digest; preserve disabled startup and verify receiving separately.",
|
|
@@ -191,5 +195,18 @@ export function startupDiagnostic(error) {
|
|
|
191
195
|
: "RUNTIME_AUTHORIZATION_REJECTED"
|
|
192
196
|
: "STARTUP_CAUSE_UNAVAILABLE";
|
|
193
197
|
const [cause, recovery, retryable = true] = causes[causeCode];
|
|
194
|
-
|
|
198
|
+
const retryAt = match?.retryAt;
|
|
199
|
+
const now = Date.now();
|
|
200
|
+
return {
|
|
201
|
+
causeCode,
|
|
202
|
+
cause,
|
|
203
|
+
recovery,
|
|
204
|
+
retryable,
|
|
205
|
+
...(causeCode === "CHAT_PROMPT_RATE_LIMITED" &&
|
|
206
|
+
Number.isFinite(retryAt) &&
|
|
207
|
+
retryAt > now &&
|
|
208
|
+
retryAt <= now + 60 * 60 * 1000
|
|
209
|
+
? { retryAt }
|
|
210
|
+
: {}),
|
|
211
|
+
};
|
|
195
212
|
}
|