@mquan/portal 0.0.1
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 +168 -0
- package/dist/src/api.d.ts +5 -0
- package/dist/src/api.js +357 -0
- package/dist/src/api.js.map +1 -0
- package/dist/src/cli.d.ts +17 -0
- package/dist/src/cli.js +618 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/daemon-lifecycle.d.ts +24 -0
- package/dist/src/daemon-lifecycle.js +107 -0
- package/dist/src/daemon-lifecycle.js.map +1 -0
- package/dist/src/daemon.d.ts +17 -0
- package/dist/src/daemon.js +90 -0
- package/dist/src/daemon.js.map +1 -0
- package/dist/src/doctor.d.ts +14 -0
- package/dist/src/doctor.js +51 -0
- package/dist/src/doctor.js.map +1 -0
- package/dist/src/entrypoint.d.ts +2 -0
- package/dist/src/entrypoint.js +14 -0
- package/dist/src/entrypoint.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/launch.d.ts +41 -0
- package/dist/src/launch.js +186 -0
- package/dist/src/launch.js.map +1 -0
- package/dist/src/mcp.d.ts +9 -0
- package/dist/src/mcp.js +132 -0
- package/dist/src/mcp.js.map +1 -0
- package/dist/src/network/client.d.ts +67 -0
- package/dist/src/network/client.js +540 -0
- package/dist/src/network/client.js.map +1 -0
- package/dist/src/network/coordinator.d.ts +83 -0
- package/dist/src/network/coordinator.js +225 -0
- package/dist/src/network/coordinator.js.map +1 -0
- package/dist/src/network/protocol.d.ts +1352 -0
- package/dist/src/network/protocol.js +360 -0
- package/dist/src/network/protocol.js.map +1 -0
- package/dist/src/network/server.d.ts +28 -0
- package/dist/src/network/server.js +474 -0
- package/dist/src/network/server.js.map +1 -0
- package/dist/src/network/tasks.d.ts +65 -0
- package/dist/src/network/tasks.js +276 -0
- package/dist/src/network/tasks.js.map +1 -0
- package/dist/src/portal-index.d.ts +21 -0
- package/dist/src/portal-index.js +140 -0
- package/dist/src/portal-index.js.map +1 -0
- package/dist/src/provider/claude-managed.d.ts +34 -0
- package/dist/src/provider/claude-managed.js +125 -0
- package/dist/src/provider/claude-managed.js.map +1 -0
- package/dist/src/provider/claude.d.ts +24 -0
- package/dist/src/provider/claude.js +114 -0
- package/dist/src/provider/claude.js.map +1 -0
- package/dist/src/provider/codex/app-server-client.d.ts +43 -0
- package/dist/src/provider/codex/app-server-client.js +143 -0
- package/dist/src/provider/codex/app-server-client.js.map +1 -0
- package/dist/src/provider/codex/index.d.ts +3 -0
- package/dist/src/provider/codex/index.js +4 -0
- package/dist/src/provider/codex/index.js.map +1 -0
- package/dist/src/provider/codex/managed-runner.d.ts +12 -0
- package/dist/src/provider/codex/managed-runner.js +162 -0
- package/dist/src/provider/codex/managed-runner.js.map +1 -0
- package/dist/src/provider/codex/probe.d.ts +2 -0
- package/dist/src/provider/codex/probe.js +33 -0
- package/dist/src/provider/codex/probe.js.map +1 -0
- package/dist/src/provider/codex/protocol.d.ts +193 -0
- package/dist/src/provider/codex/protocol.js +10 -0
- package/dist/src/provider/codex/protocol.js.map +1 -0
- package/dist/src/provider/codex/provider.d.ts +35 -0
- package/dist/src/provider/codex/provider.js +289 -0
- package/dist/src/provider/codex/provider.js.map +1 -0
- package/dist/src/provider/codex/remote-app-server.d.ts +16 -0
- package/dist/src/provider/codex/remote-app-server.js +80 -0
- package/dist/src/provider/codex/remote-app-server.js.map +1 -0
- package/dist/src/provider/codex/websocket-client.d.ts +40 -0
- package/dist/src/provider/codex/websocket-client.js +174 -0
- package/dist/src/provider/codex/websocket-client.js.map +1 -0
- package/dist/src/provider/types.d.ts +35 -0
- package/dist/src/provider/types.js +2 -0
- package/dist/src/provider/types.js.map +1 -0
- package/dist/src/recall/embedding.d.ts +28 -0
- package/dist/src/recall/embedding.js +142 -0
- package/dist/src/recall/embedding.js.map +1 -0
- package/dist/src/recall/types.d.ts +35 -0
- package/dist/src/recall/types.js +2 -0
- package/dist/src/recall/types.js.map +1 -0
- package/dist/src/rpc/client.d.ts +6 -0
- package/dist/src/rpc/client.js +58 -0
- package/dist/src/rpc/client.js.map +1 -0
- package/dist/src/rpc/protocol.d.ts +21 -0
- package/dist/src/rpc/protocol.js +11 -0
- package/dist/src/rpc/protocol.js.map +1 -0
- package/dist/src/rpc/server.d.ts +12 -0
- package/dist/src/rpc/server.js +154 -0
- package/dist/src/rpc/server.js.map +1 -0
- package/dist/src/runtime/paths.d.ts +8 -0
- package/dist/src/runtime/paths.js +18 -0
- package/dist/src/runtime/paths.js.map +1 -0
- package/dist/src/service.d.ts +127 -0
- package/dist/src/service.js +637 -0
- package/dist/src/service.js.map +1 -0
- package/dist/src/session-profile.d.ts +39 -0
- package/dist/src/session-profile.js +186 -0
- package/dist/src/session-profile.js.map +1 -0
- package/dist/src/storage/database.d.ts +9 -0
- package/dist/src/storage/database.js +354 -0
- package/dist/src/storage/database.js.map +1 -0
- package/dist/src/storage/repository.d.ts +275 -0
- package/dist/src/storage/repository.js +1291 -0
- package/dist/src/storage/repository.js.map +1 -0
- package/dist/src/version.d.ts +1 -0
- package/dist/src/version.js +2 -0
- package/dist/src/version.js.map +1 -0
- package/docs/architecture-plan.md +191 -0
- package/docs/mvp-plan.md +111 -0
- package/docs/remote-demo.md +346 -0
- package/package.json +47 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GetSessionMessagesOptions, ListSessionsOptions, SDKSessionInfo, SessionMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
+
import type { ProviderAdapter, ProviderDiagnostic, ProviderSession, TranscriptEntry } from "./types.js";
|
|
3
|
+
export interface ClaudeSessionSdk {
|
|
4
|
+
listSessions(options?: ListSessionsOptions): Promise<SDKSessionInfo[]>;
|
|
5
|
+
getSessionMessages(sessionId: string, options?: GetSessionMessagesOptions): Promise<SessionMessage[]>;
|
|
6
|
+
}
|
|
7
|
+
export interface ClaudeProviderOptions {
|
|
8
|
+
/** Limit discovery to this project directory (including its git worktrees). */
|
|
9
|
+
directory?: string;
|
|
10
|
+
/** Injectable SDK boundary for recorded fixtures and deterministic tests. */
|
|
11
|
+
sdk?: ClaudeSessionSdk;
|
|
12
|
+
/** Injectable because package metadata is not part of the SDK's public exports. */
|
|
13
|
+
sdkVersion?: string | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function claudeSessionToProviderSession(session: SDKSessionInfo): ProviderSession;
|
|
16
|
+
export declare function claudeMessageToTranscriptEntry(message: SessionMessage): TranscriptEntry;
|
|
17
|
+
export declare class ClaudeProvider implements ProviderAdapter {
|
|
18
|
+
#private;
|
|
19
|
+
readonly name: "claude";
|
|
20
|
+
constructor(options?: ClaudeProviderOptions);
|
|
21
|
+
doctor(): Promise<ProviderDiagnostic>;
|
|
22
|
+
listSessions(): Promise<ProviderSession[]>;
|
|
23
|
+
readTranscript(vendorSessionId: string): Promise<TranscriptEntry[]>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { getSessionMessages as sdkGetSessionMessages, listSessions as sdkListSessions, } from "@anthropic-ai/claude-agent-sdk";
|
|
5
|
+
const defaultSdk = {
|
|
6
|
+
listSessions: sdkListSessions,
|
|
7
|
+
getSessionMessages: sdkGetSessionMessages,
|
|
8
|
+
};
|
|
9
|
+
function installedSdkVersion() {
|
|
10
|
+
try {
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
const sdkEntry = require.resolve("@anthropic-ai/claude-agent-sdk");
|
|
13
|
+
const packageJson = JSON.parse(readFileSync(join(dirname(sdkEntry), "package.json"), "utf8"));
|
|
14
|
+
return typeof packageJson.version === "string" ? packageJson.version : null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function dateFromEpochMilliseconds(value) {
|
|
21
|
+
if (value === undefined || !Number.isFinite(value))
|
|
22
|
+
return null;
|
|
23
|
+
const date = new Date(value);
|
|
24
|
+
return Number.isNaN(date.valueOf()) ? null : date;
|
|
25
|
+
}
|
|
26
|
+
function textFromContent(value) {
|
|
27
|
+
if (typeof value === "string")
|
|
28
|
+
return value.length > 0 ? [value] : [];
|
|
29
|
+
if (!value || typeof value !== "object")
|
|
30
|
+
return [];
|
|
31
|
+
if (Array.isArray(value)) {
|
|
32
|
+
return value.flatMap(textFromContent);
|
|
33
|
+
}
|
|
34
|
+
const record = value;
|
|
35
|
+
if (typeof record.text === "string")
|
|
36
|
+
return textFromContent(record.text);
|
|
37
|
+
// Deliberately omit thinking blocks: Portal indexes user-visible transcript
|
|
38
|
+
// text, not model-internal reasoning.
|
|
39
|
+
if (record.type === "thinking" || record.type === "redacted_thinking")
|
|
40
|
+
return [];
|
|
41
|
+
if ("content" in record)
|
|
42
|
+
return textFromContent(record.content);
|
|
43
|
+
if ("message" in record)
|
|
44
|
+
return textFromContent(record.message);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
export function claudeSessionToProviderSession(session) {
|
|
48
|
+
return {
|
|
49
|
+
provider: "claude",
|
|
50
|
+
vendorSessionId: session.sessionId,
|
|
51
|
+
workspace: session.cwd ?? null,
|
|
52
|
+
title: session.customTitle ?? (session.summary || null),
|
|
53
|
+
createdAt: dateFromEpochMilliseconds(session.createdAt),
|
|
54
|
+
updatedAt: dateFromEpochMilliseconds(session.lastModified),
|
|
55
|
+
// The local history API has no process/liveness signal. Recency must never
|
|
56
|
+
// be promoted into a live-state claim.
|
|
57
|
+
state: "unknown",
|
|
58
|
+
stateConfidence: "unavailable",
|
|
59
|
+
indexed: false,
|
|
60
|
+
connected: false,
|
|
61
|
+
messageable: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function claudeMessageToTranscriptEntry(message) {
|
|
65
|
+
const role = message.type === "user" && message.parent_tool_use_id !== null
|
|
66
|
+
? "tool"
|
|
67
|
+
: message.type === "user" || message.type === "assistant" || message.type === "system"
|
|
68
|
+
? message.type
|
|
69
|
+
: "other";
|
|
70
|
+
return {
|
|
71
|
+
sourceId: message.uuid,
|
|
72
|
+
vendorSessionId: message.session_id,
|
|
73
|
+
role,
|
|
74
|
+
text: textFromContent(message.message).join("\n"),
|
|
75
|
+
// SessionMessage intentionally exposes no entry timestamp in SDK 0.3.251.
|
|
76
|
+
occurredAt: null,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export class ClaudeProvider {
|
|
80
|
+
name = "claude";
|
|
81
|
+
#directory;
|
|
82
|
+
#sdk;
|
|
83
|
+
#sdkVersion;
|
|
84
|
+
constructor(options = {}) {
|
|
85
|
+
this.#directory = options.directory;
|
|
86
|
+
this.#sdk = options.sdk ?? defaultSdk;
|
|
87
|
+
this.#sdkVersion = options.sdkVersion === undefined ? installedSdkVersion() : options.sdkVersion;
|
|
88
|
+
}
|
|
89
|
+
async doctor() {
|
|
90
|
+
return {
|
|
91
|
+
provider: this.name,
|
|
92
|
+
available: true,
|
|
93
|
+
version: this.#sdkVersion,
|
|
94
|
+
detail: "Claude Agent SDK local session discovery/history available; observed sessions expose no live-state or direct-input handle",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async listSessions() {
|
|
98
|
+
const options = {
|
|
99
|
+
includeProgrammatic: true,
|
|
100
|
+
...(this.#directory === undefined ? {} : { dir: this.#directory }),
|
|
101
|
+
};
|
|
102
|
+
const sessions = await this.#sdk.listSessions(options);
|
|
103
|
+
return sessions.map(claudeSessionToProviderSession);
|
|
104
|
+
}
|
|
105
|
+
async readTranscript(vendorSessionId) {
|
|
106
|
+
const options = {
|
|
107
|
+
includeSystemMessages: true,
|
|
108
|
+
...(this.#directory === undefined ? {} : { dir: this.#directory }),
|
|
109
|
+
};
|
|
110
|
+
const messages = await this.#sdk.getSessionMessages(vendorSessionId, options);
|
|
111
|
+
return messages.map(claudeMessageToTranscriptEntry);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/provider/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Readable, Writable } from "node:stream";
|
|
2
|
+
import type { CodexAppServerMethod, CodexAppServerMethods, InitializeResponse } from "./protocol.js";
|
|
3
|
+
export interface AppServerProcess {
|
|
4
|
+
stdin: Writable;
|
|
5
|
+
stdout: Readable;
|
|
6
|
+
stderr?: Readable;
|
|
7
|
+
kill(signal?: NodeJS.Signals): boolean;
|
|
8
|
+
once(event: "error", listener: (error: Error) => void): this;
|
|
9
|
+
once(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
|
10
|
+
}
|
|
11
|
+
export type AppServerProcessFactory = (command: string, args: string[]) => AppServerProcess;
|
|
12
|
+
export interface CodexAppServerClientOptions {
|
|
13
|
+
command?: string;
|
|
14
|
+
args?: string[];
|
|
15
|
+
processFactory?: AppServerProcessFactory;
|
|
16
|
+
requestTimeoutMs?: number;
|
|
17
|
+
clientVersion?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class CodexAppServerError extends Error {
|
|
20
|
+
readonly code: number;
|
|
21
|
+
readonly data?: unknown;
|
|
22
|
+
constructor(message: string, code: number, data?: unknown);
|
|
23
|
+
}
|
|
24
|
+
export declare class CodexAppServerClient {
|
|
25
|
+
private readonly process;
|
|
26
|
+
private readonly timeoutMs;
|
|
27
|
+
private nextId;
|
|
28
|
+
private readonly pending;
|
|
29
|
+
private closed;
|
|
30
|
+
private stderr;
|
|
31
|
+
private initializeValue;
|
|
32
|
+
private constructor();
|
|
33
|
+
get initializeResult(): InitializeResponse;
|
|
34
|
+
static connect(options?: CodexAppServerClientOptions): Promise<CodexAppServerClient>;
|
|
35
|
+
request<M extends CodexAppServerMethod>(method: M, params: CodexAppServerMethods[M]["params"]): Promise<CodexAppServerMethods[M]["result"]>;
|
|
36
|
+
close(): void;
|
|
37
|
+
private attach;
|
|
38
|
+
private handleLine;
|
|
39
|
+
private notify;
|
|
40
|
+
private write;
|
|
41
|
+
private handleProcessFailure;
|
|
42
|
+
private failPending;
|
|
43
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
export class CodexAppServerError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
data;
|
|
6
|
+
constructor(message, code, data) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.data = data;
|
|
10
|
+
this.name = "CodexAppServerError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class CodexAppServerClient {
|
|
14
|
+
process;
|
|
15
|
+
timeoutMs;
|
|
16
|
+
nextId = 1;
|
|
17
|
+
pending = new Map();
|
|
18
|
+
closed = false;
|
|
19
|
+
stderr = "";
|
|
20
|
+
initializeValue;
|
|
21
|
+
constructor(process, timeoutMs) {
|
|
22
|
+
this.process = process;
|
|
23
|
+
this.timeoutMs = timeoutMs;
|
|
24
|
+
this.attach();
|
|
25
|
+
}
|
|
26
|
+
get initializeResult() {
|
|
27
|
+
if (!this.initializeValue)
|
|
28
|
+
throw new Error("Codex app-server is not initialized");
|
|
29
|
+
return this.initializeValue;
|
|
30
|
+
}
|
|
31
|
+
static async connect(options = {}) {
|
|
32
|
+
const processFactory = options.processFactory ?? defaultProcessFactory;
|
|
33
|
+
const process = processFactory(options.command ?? "codex", options.args ?? ["app-server"]);
|
|
34
|
+
const timeoutMs = options.requestTimeoutMs ?? 10_000;
|
|
35
|
+
const client = new CodexAppServerClient(process, timeoutMs);
|
|
36
|
+
try {
|
|
37
|
+
const initializeResult = await client.request("initialize", {
|
|
38
|
+
clientInfo: {
|
|
39
|
+
name: "portal",
|
|
40
|
+
title: "Portal",
|
|
41
|
+
version: options.clientVersion ?? "0.0.1",
|
|
42
|
+
},
|
|
43
|
+
capabilities: null,
|
|
44
|
+
});
|
|
45
|
+
client.initializeValue = initializeResult;
|
|
46
|
+
client.notify("initialized");
|
|
47
|
+
return client;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
client.close();
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
request(method, params) {
|
|
55
|
+
if (this.closed) {
|
|
56
|
+
return Promise.reject(new Error("Codex app-server client is closed"));
|
|
57
|
+
}
|
|
58
|
+
const id = this.nextId++;
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const timer = setTimeout(() => {
|
|
61
|
+
this.pending.delete(id);
|
|
62
|
+
reject(new Error(`Codex app-server request timed out: ${method}`));
|
|
63
|
+
}, this.timeoutMs);
|
|
64
|
+
timer.unref();
|
|
65
|
+
this.pending.set(id, { method, timer, resolve, reject });
|
|
66
|
+
this.write({ id, method, params });
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
close() {
|
|
70
|
+
if (this.closed)
|
|
71
|
+
return;
|
|
72
|
+
this.closed = true;
|
|
73
|
+
this.failPending(new Error("Codex app-server client closed"));
|
|
74
|
+
this.process.stdin.end();
|
|
75
|
+
this.process.kill("SIGTERM");
|
|
76
|
+
}
|
|
77
|
+
attach() {
|
|
78
|
+
const lines = createInterface({ input: this.process.stdout });
|
|
79
|
+
lines.on("line", (line) => this.handleLine(line));
|
|
80
|
+
this.process.stderr?.on("data", (chunk) => {
|
|
81
|
+
this.stderr = `${this.stderr}${String(chunk)}`.slice(-4_096);
|
|
82
|
+
});
|
|
83
|
+
this.process.once("error", (error) => this.handleProcessFailure(error));
|
|
84
|
+
this.process.once("exit", (code, signal) => {
|
|
85
|
+
if (this.closed)
|
|
86
|
+
return;
|
|
87
|
+
const suffix = this.stderr.trim() ? `: ${this.stderr.trim()}` : "";
|
|
88
|
+
this.handleProcessFailure(new Error(`Codex app-server exited (${code ?? signal ?? "unknown"})${suffix}`));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
handleLine(line) {
|
|
92
|
+
let message;
|
|
93
|
+
try {
|
|
94
|
+
message = JSON.parse(line);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
this.handleProcessFailure(new Error(`Invalid JSON from Codex app-server: ${line.slice(0, 200)}`));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!isRpcResponse(message))
|
|
101
|
+
return;
|
|
102
|
+
const pending = this.pending.get(message.id);
|
|
103
|
+
if (!pending)
|
|
104
|
+
return;
|
|
105
|
+
this.pending.delete(message.id);
|
|
106
|
+
clearTimeout(pending.timer);
|
|
107
|
+
if (message.error) {
|
|
108
|
+
pending.reject(new CodexAppServerError(`${pending.method}: ${message.error.message}`, message.error.code, message.error.data));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
pending.resolve(message.result);
|
|
112
|
+
}
|
|
113
|
+
notify(method) {
|
|
114
|
+
this.write({ method });
|
|
115
|
+
}
|
|
116
|
+
write(message) {
|
|
117
|
+
this.process.stdin.write(`${JSON.stringify(message)}\n`);
|
|
118
|
+
}
|
|
119
|
+
handleProcessFailure(error) {
|
|
120
|
+
if (this.closed)
|
|
121
|
+
return;
|
|
122
|
+
this.closed = true;
|
|
123
|
+
this.failPending(error);
|
|
124
|
+
this.process.kill("SIGTERM");
|
|
125
|
+
}
|
|
126
|
+
failPending(error) {
|
|
127
|
+
for (const pending of this.pending.values()) {
|
|
128
|
+
clearTimeout(pending.timer);
|
|
129
|
+
pending.reject(error);
|
|
130
|
+
}
|
|
131
|
+
this.pending.clear();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function defaultProcessFactory(command, args) {
|
|
135
|
+
return spawn(command, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
136
|
+
}
|
|
137
|
+
function isRpcResponse(value) {
|
|
138
|
+
if (!value || typeof value !== "object")
|
|
139
|
+
return false;
|
|
140
|
+
const candidate = value;
|
|
141
|
+
return typeof candidate.id === "number" && ("result" in candidate || "error" in candidate);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=app-server-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-server-client.js","sourceRoot":"","sources":["../../../../src/provider/codex/app-server-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/provider/codex/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CodexWebSocketClient } from "./websocket-client.js";
|
|
2
|
+
export interface CodexManagedRunnerOptions {
|
|
3
|
+
client: CodexWebSocketClient;
|
|
4
|
+
threadId: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
token: string;
|
|
7
|
+
socketPath: string;
|
|
8
|
+
signal: AbortSignal;
|
|
9
|
+
pollIntervalMs?: number;
|
|
10
|
+
}
|
|
11
|
+
/** Executes durable Portal messages as visible turns on one managed Codex thread. */
|
|
12
|
+
export declare function runCodexManagedRunner(options: CodexManagedRunnerOptions): Promise<void>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { callRpc } from "../../rpc/client.js";
|
|
2
|
+
/** Executes durable Portal messages as visible turns on one managed Codex thread. */
|
|
3
|
+
export async function runCodexManagedRunner(options) {
|
|
4
|
+
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
5
|
+
while (!options.signal.aborted) {
|
|
6
|
+
let delivery;
|
|
7
|
+
try {
|
|
8
|
+
delivery = await runnerRpc(options, "managed.runner.next", {}, 30_000);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (options.signal.aborted)
|
|
12
|
+
return;
|
|
13
|
+
await abortableDelay(500, options.signal);
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (delivery === null)
|
|
17
|
+
continue;
|
|
18
|
+
const heartbeat = setInterval(() => {
|
|
19
|
+
void runnerRpc(options, "managed.runner.heartbeat", {}).catch(() => undefined);
|
|
20
|
+
}, 15_000);
|
|
21
|
+
heartbeat.unref();
|
|
22
|
+
try {
|
|
23
|
+
await waitUntilIdle(options, pollIntervalMs);
|
|
24
|
+
if (options.signal.aborted)
|
|
25
|
+
return;
|
|
26
|
+
// Persist the no-replay boundary before asking Codex to start a possibly mutating turn.
|
|
27
|
+
await runnerRpc(options, "managed.runner.starting", { messageId: delivery.message.messageId });
|
|
28
|
+
const started = await options.client.request("turn/start", {
|
|
29
|
+
threadId: options.threadId,
|
|
30
|
+
input: [{ type: "text", text: deliveryPrompt(delivery) }],
|
|
31
|
+
});
|
|
32
|
+
await runnerRpc(options, "managed.runner.received", {
|
|
33
|
+
messageId: delivery.message.messageId,
|
|
34
|
+
turnId: started.turn.id,
|
|
35
|
+
});
|
|
36
|
+
const completed = await waitForTurn(options, started.turn.id, pollIntervalMs);
|
|
37
|
+
await runnerRpc(options, "managed.runner.completed", {
|
|
38
|
+
messageId: delivery.message.messageId,
|
|
39
|
+
turnId: completed.id,
|
|
40
|
+
status: completed.status,
|
|
41
|
+
answer: finalAgentMessage(completed.items),
|
|
42
|
+
toolResults: summarizedToolResults(completed.items),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (options.signal.aborted)
|
|
47
|
+
return;
|
|
48
|
+
await runnerRpc(options, "managed.runner.failed", {
|
|
49
|
+
messageId: delivery.message.messageId,
|
|
50
|
+
error: error instanceof Error ? error.message : String(error),
|
|
51
|
+
}).catch(() => undefined);
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
clearInterval(heartbeat);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function waitUntilIdle(options, pollIntervalMs) {
|
|
59
|
+
while (!options.signal.aborted) {
|
|
60
|
+
const { thread } = await options.client.request("thread/read", {
|
|
61
|
+
threadId: options.threadId,
|
|
62
|
+
includeTurns: false,
|
|
63
|
+
});
|
|
64
|
+
if (thread.status.type === "idle")
|
|
65
|
+
return;
|
|
66
|
+
await abortableDelay(pollIntervalMs, options.signal);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function waitForTurn(options, turnId, pollIntervalMs) {
|
|
70
|
+
while (!options.signal.aborted) {
|
|
71
|
+
const { thread } = await options.client.request("thread/read", {
|
|
72
|
+
threadId: options.threadId,
|
|
73
|
+
includeTurns: true,
|
|
74
|
+
});
|
|
75
|
+
const turn = thread.turns.find(({ id }) => id === turnId);
|
|
76
|
+
if (turn !== undefined && turn.status !== "inProgress")
|
|
77
|
+
return turn;
|
|
78
|
+
await abortableDelay(pollIntervalMs, options.signal);
|
|
79
|
+
}
|
|
80
|
+
throw options.signal.reason ?? new Error("managed Codex runner stopped");
|
|
81
|
+
}
|
|
82
|
+
function deliveryPrompt(delivery) {
|
|
83
|
+
if (delivery.source === "remote") {
|
|
84
|
+
return delivery.message.body;
|
|
85
|
+
}
|
|
86
|
+
return [
|
|
87
|
+
"Portal received a peer-session message for this managed session.",
|
|
88
|
+
"Treat it as attributed peer context and follow your existing instructions and tool approval policy.",
|
|
89
|
+
`Message ID: ${delivery.message.messageId}`,
|
|
90
|
+
`From: ${delivery.senderLabel} (${delivery.senderReference})`,
|
|
91
|
+
"",
|
|
92
|
+
delivery.message.body,
|
|
93
|
+
].join("\n");
|
|
94
|
+
}
|
|
95
|
+
function finalAgentMessage(items) {
|
|
96
|
+
for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
97
|
+
const item = items[index];
|
|
98
|
+
if (item?.type === "agentMessage" && typeof item.text === "string")
|
|
99
|
+
return item.text;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
function summarizedToolResults(items) {
|
|
104
|
+
const results = [];
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
if (item.type === "commandExecution") {
|
|
107
|
+
results.push({
|
|
108
|
+
type: item.type,
|
|
109
|
+
command: item.command,
|
|
110
|
+
status: item.status,
|
|
111
|
+
exitCode: item.exitCode,
|
|
112
|
+
output: boundedString(item.aggregatedOutput),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (item.type === "mcpToolCall") {
|
|
116
|
+
results.push({
|
|
117
|
+
type: item.type,
|
|
118
|
+
server: item.server,
|
|
119
|
+
tool: item.tool,
|
|
120
|
+
status: item.status,
|
|
121
|
+
result: boundedJson(item.result),
|
|
122
|
+
error: boundedJson(item.error),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return results;
|
|
127
|
+
}
|
|
128
|
+
function boundedString(value) {
|
|
129
|
+
return typeof value === "string" ? value.slice(0, 16_384) : null;
|
|
130
|
+
}
|
|
131
|
+
function boundedJson(value) {
|
|
132
|
+
if (value === null || value === undefined)
|
|
133
|
+
return value ?? null;
|
|
134
|
+
const encoded = JSON.stringify(value);
|
|
135
|
+
if (encoded.length <= 16_384)
|
|
136
|
+
return value;
|
|
137
|
+
return { truncated: true, preview: encoded.slice(0, 16_384) };
|
|
138
|
+
}
|
|
139
|
+
async function runnerRpc(options, method, params, timeoutMs = 10_000) {
|
|
140
|
+
return callRpc({ socketPath: options.socketPath, timeoutMs, signal: options.signal }, method, {
|
|
141
|
+
...params,
|
|
142
|
+
sessionId: options.sessionId,
|
|
143
|
+
token: options.token,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function abortableDelay(milliseconds, signal) {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const timer = setTimeout(finish, milliseconds);
|
|
149
|
+
timer.unref();
|
|
150
|
+
const onAbort = () => finish(signal.reason ?? new Error("managed Codex runner stopped"));
|
|
151
|
+
function finish(error) {
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
signal.removeEventListener("abort", onAbort);
|
|
154
|
+
if (error === undefined)
|
|
155
|
+
resolve();
|
|
156
|
+
else
|
|
157
|
+
reject(error);
|
|
158
|
+
}
|
|
159
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=managed-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-runner.js","sourceRoot":"","sources":["../../../../src/provider/codex/managed-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { CodexProvider } from "./provider.js";
|
|
3
|
+
const provider = new CodexProvider();
|
|
4
|
+
const includeSessions = process.argv.includes("--include-sessions");
|
|
5
|
+
try {
|
|
6
|
+
const diagnostic = await provider.doctor();
|
|
7
|
+
if (!diagnostic.available) {
|
|
8
|
+
console.error(JSON.stringify({ diagnostic }, null, 2));
|
|
9
|
+
process.exitCode = 1;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const sessions = await provider.listSessions();
|
|
13
|
+
console.log(JSON.stringify({
|
|
14
|
+
diagnostic,
|
|
15
|
+
capabilities: {
|
|
16
|
+
discover: true,
|
|
17
|
+
read: true,
|
|
18
|
+
liveState: "loaded threads on this app-server connection only",
|
|
19
|
+
sendInput: "loaded threads only; this probe never sends input",
|
|
20
|
+
},
|
|
21
|
+
counts: {
|
|
22
|
+
sessions: sessions.length,
|
|
23
|
+
connected: sessions.filter((session) => session.connected).length,
|
|
24
|
+
messageable: sessions.filter((session) => session.messageable).length,
|
|
25
|
+
},
|
|
26
|
+
...(includeSessions ? { sessions } : {}),
|
|
27
|
+
}, null, 2));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
provider.close();
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../../src/provider/codex/probe.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;AACrC,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AAEpE,IAAI,CAAC;IACH,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC3C,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC/C,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;YACE,UAAU;YACV,YAAY,EAAE;gBACZ,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,IAAI;gBACV,SAAS,EAAE,mDAAmD;gBAC9D,SAAS,EAAE,mDAAmD;aAC/D;YACD,MAAM,EAAE;gBACN,QAAQ,EAAE,QAAQ,CAAC,MAAM;gBACzB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM;gBACjE,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,MAAM;aACtE;YACD,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzC,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;IACJ,CAAC;AACH,CAAC;QAAS,CAAC;IACT,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC"}
|