@runuai/host 0.9.57 → 0.9.58
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/lib/engine-login.ts +52 -0
- package/package.json +1 -1
package/lib/engine-login.ts
CHANGED
|
@@ -66,6 +66,8 @@ const LOGIN_MOUNT = "/run/uai-engine-login";
|
|
|
66
66
|
const LOGIN_HOME = `${LOGIN_MOUNT}/home`;
|
|
67
67
|
const CODEX_HOME = `${LOGIN_MOUNT}/codex`;
|
|
68
68
|
const MAX_OUTPUT_TAIL_BYTES = 64 * 1_024;
|
|
69
|
+
/** script(1) transcripts of a login run a few KB; 1MB is a hostile-file cap. */
|
|
70
|
+
const MAX_TRANSCRIPT_BYTES = 1_024 * 1_024;
|
|
69
71
|
const MAX_CODEX_AUTH_BYTES = 1024 * 1024;
|
|
70
72
|
const DOCKER_CONTROL_TIMEOUT_MS = 15_000;
|
|
71
73
|
const DOCKER_CLEANUP_TIMEOUT_MS = 5_000;
|
|
@@ -132,6 +134,14 @@ export interface EngineLoginSeams {
|
|
|
132
134
|
callbackUrl: string,
|
|
133
135
|
): Promise<void>;
|
|
134
136
|
reconcileStaleContainers(): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Read the script(1) PTY transcript from the login leaf (null when absent
|
|
139
|
+
* or unreadable). The transcript is written INSIDE the container, so it is
|
|
140
|
+
* the pure PTY byte stream — structurally free of the container runtime's
|
|
141
|
+
* own stdio chatter, which on the Apple CLI painted XPC noise over the
|
|
142
|
+
* very cells the TUI's diff renderer skipped (live 2026-08-21).
|
|
143
|
+
*/
|
|
144
|
+
readTranscript(tempDir: string): Promise<string | null>;
|
|
135
145
|
persistClaudeToken(token: string): Promise<void>;
|
|
136
146
|
persistCodexAuth(sourceFile: string): Promise<void>;
|
|
137
147
|
/** ADR-116: labeled extra-account captures (never the default slots). */
|
|
@@ -272,6 +282,17 @@ function defaultSeams(options: EngineLoginManagerOptions): EngineLoginSeams {
|
|
|
272
282
|
replayCodexCallback,
|
|
273
283
|
reconcileStaleContainers: () =>
|
|
274
284
|
reconcileStaleEngineLoginResources({ tempRoot }),
|
|
285
|
+
readTranscript: async (tempDir) => {
|
|
286
|
+
try {
|
|
287
|
+
const body = await readBoundedRegularFile(
|
|
288
|
+
join(tempDir, "typescript"),
|
|
289
|
+
MAX_TRANSCRIPT_BYTES,
|
|
290
|
+
);
|
|
291
|
+
return body.toString("utf8");
|
|
292
|
+
} catch {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
},
|
|
275
296
|
persistClaudeToken: (token) => persistClaudeTokenAtomic(token),
|
|
276
297
|
persistCodexAuth: (sourceFile) => persistCodexAuthAtomic(sourceFile),
|
|
277
298
|
addClaudeAccount: (label, token) =>
|
|
@@ -807,6 +828,37 @@ export class EngineLoginManager {
|
|
|
807
828
|
if (operation.finishPromise) await operation.finishPromise;
|
|
808
829
|
return;
|
|
809
830
|
}
|
|
831
|
+
if (
|
|
832
|
+
operation.engine === "claude" &&
|
|
833
|
+
result.code === 0 &&
|
|
834
|
+
operation.inputUsed &&
|
|
835
|
+
operation.tempDir
|
|
836
|
+
) {
|
|
837
|
+
// A clean exit after the code went in means the CLI almost certainly
|
|
838
|
+
// minted and printed the token — a stream capture that saw nothing is
|
|
839
|
+
// the capture's failure, not the login's. The relayed stream can be
|
|
840
|
+
// polluted by the container runtime's own chatter (the Apple CLI's XPC
|
|
841
|
+
// noise painted characters over the cells the TUI's diff renderer
|
|
842
|
+
// skipped, corrupting the reconstructed screen — live 2026-08-21 on
|
|
843
|
+
// the Air, straight after the Linux fix). The PTY transcript is
|
|
844
|
+
// written inside the container and cannot contain that noise, so it
|
|
845
|
+
// gets the authoritative re-read before this operation is failed.
|
|
846
|
+
const transcript = await this.seams.readTranscript(operation.tempDir);
|
|
847
|
+
if (!this.isCurrent(operation) || operation.finishing) return;
|
|
848
|
+
const token = transcript
|
|
849
|
+
? extractClaudeOAuthToken(renderTerminalScreenText(transcript))
|
|
850
|
+
: null;
|
|
851
|
+
if (token) {
|
|
852
|
+
console.log(
|
|
853
|
+
`[engine-login] token recovered from the PTY transcript for ${operation.opId}; persisting`,
|
|
854
|
+
);
|
|
855
|
+
operation.outputTail = "";
|
|
856
|
+
operation.stdoutTail = "";
|
|
857
|
+
this.beginClaudeFinish(operation, token);
|
|
858
|
+
if (operation.finishPromise) await operation.finishPromise;
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
810
862
|
const evidence = lastSignificantOutputLine(operation.outputTail);
|
|
811
863
|
console.warn(
|
|
812
864
|
`[engine-login] login process for ${operation.opId} ended (exit ${result.code ?? "spawn-failed"}) before completion` +
|