@rynx-ai/runtime 0.1.0 → 0.1.9
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/dist/claude/executor.d.ts +3 -5
- package/dist/claude/executor.js +3 -5
- package/dist/claude/native-bridge.d.ts +74 -17
- package/dist/claude/native-bridge.js +225 -30
- package/dist/claude/native-hook-main.js +291 -39
- package/dist/claude/native-hooks.d.ts +3 -2
- package/dist/claude/native-hooks.js +15 -6
- package/dist/claude/native-integration.d.ts +78 -5
- package/dist/claude/native-integration.js +417 -26
- package/dist/claude/settings.d.ts +8 -0
- package/dist/claude/settings.js +50 -0
- package/dist/claude/transcript.d.ts +2 -2
- package/dist/claude/transcript.js +3 -3
- package/dist/codex/rollout-synth.js +1 -1
- package/dist/codex-app-server/client.d.ts +26 -40
- package/dist/codex-app-server/client.js +1128 -99
- package/dist/codex-app-server/forwarder.d.ts +7 -7
- package/dist/codex-app-server/forwarder.js +11 -5
- package/dist/codex-app-server/mapping.d.ts +1 -1
- package/dist/codex-app-server/mapping.js +27 -2
- package/dist/codex-app-server/protocol.d.ts +238 -4
- package/dist/codex-app-server/transport.d.ts +20 -5
- package/dist/codex-app-server/transport.js +93 -40
- package/dist/codex-app-server/ws-channel.d.ts +3 -3
- package/dist/codex-app-server/ws-channel.js +23 -7
- package/dist/codex-child-env.js +33 -0
- package/dist/codex-home.d.ts +6 -6
- package/dist/codex-home.js +8 -9
- package/dist/codex-session-store.d.ts +2 -1
- package/dist/host.d.ts +34 -33
- package/dist/host.js +531 -91
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/interactions.d.ts +61 -0
- package/dist/interactions.js +236 -0
- package/dist/models-catalog.d.ts +1 -1
- package/dist/models-catalog.js +1 -1
- package/dist/runner/child.d.ts +9 -1
- package/dist/runner/child.js +93 -15
- package/dist/runner/manager.d.ts +59 -10
- package/dist/runner/manager.js +385 -41
- package/dist/runner/protocol.d.ts +18 -7
- package/dist/runner-main.js +9 -6
- package/dist/runtime-status.js +1 -1
- package/dist/terminal/claude-tui.d.ts +8 -3
- package/dist/terminal/claude-tui.js +6 -2
- package/dist/terminal/codex-tui.d.ts +3 -3
- package/dist/terminal/codex-tui.js +1 -1
- package/dist/terminal/registry.d.ts +1 -1
- package/dist/terminal/registry.js +1 -1
- package/dist/terminal/tmux.d.ts +6 -6
- package/dist/terminal/tmux.js +10 -10
- package/package.json +3 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function readSettings(path) {
|
|
8
|
+
try {
|
|
9
|
+
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
10
|
+
return isRecord(value) ? value : {};
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function mergeSettings(base, override) {
|
|
17
|
+
const merged = { ...base };
|
|
18
|
+
for (const [key, value] of Object.entries(override)) {
|
|
19
|
+
const current = merged[key];
|
|
20
|
+
merged[key] = isRecord(current) && isRecord(value)
|
|
21
|
+
? mergeSettings(current, value)
|
|
22
|
+
: value;
|
|
23
|
+
}
|
|
24
|
+
return merged;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the single explicit settings document for a rynx-managed Claude
|
|
28
|
+
* Session. Host/project settings still provide auth, env and permission policy,
|
|
29
|
+
* but their plugins and hooks are excluded: rynx must be the only owner of
|
|
30
|
+
* PermissionRequest and AskUserQuestion, and Agent Skills arrive only through
|
|
31
|
+
* the selected `--plugin-dir`.
|
|
32
|
+
*/
|
|
33
|
+
export function buildManagedClaudeSettings(cwd, rynxSettings, configDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join(homedir(), ".claude")) {
|
|
34
|
+
const sources = [
|
|
35
|
+
join(configDir, "settings.json"),
|
|
36
|
+
join(cwd, ".claude", "settings.json"),
|
|
37
|
+
join(cwd, ".claude", "settings.local.json"),
|
|
38
|
+
];
|
|
39
|
+
let inherited = {};
|
|
40
|
+
for (const source of sources)
|
|
41
|
+
inherited = mergeSettings(inherited, readSettings(source));
|
|
42
|
+
// These sources can register competing interaction owners or host Skills.
|
|
43
|
+
// Rynx injects its own hooks/status line below and selected Skills separately.
|
|
44
|
+
delete inherited.hooks;
|
|
45
|
+
delete inherited.statusLine;
|
|
46
|
+
delete inherited.disableAllHooks;
|
|
47
|
+
delete inherited.enabledPlugins;
|
|
48
|
+
delete inherited.extraKnownMarketplaces;
|
|
49
|
+
return mergeSettings(inherited, rynxSettings);
|
|
50
|
+
}
|
|
@@ -45,10 +45,10 @@ export declare function parseTranscriptRecord(record: unknown, opts?: ParseTrans
|
|
|
45
45
|
/**
|
|
46
46
|
* Whether a transcript is a `/fork` (branch) of another session: claude stamps a
|
|
47
47
|
* `forkedFrom: { sessionId }` marker in an early record pointing at the source
|
|
48
|
-
* session (
|
|
48
|
+
* session (reference implementation's `transcript_has_forked_from_marker`). Used to distinguish a
|
|
49
49
|
* fork from an ordinary `resume` (both arrive as `SessionStart source="resume"`).
|
|
50
50
|
* Scans only the head of the file (the marker lands up front). NOTE: unverified on
|
|
51
|
-
* this host — no local transcript carries the marker — so it follows
|
|
51
|
+
* this host — no local transcript carries the marker — so it follows reference implementation's shape.
|
|
52
52
|
*/
|
|
53
53
|
export declare function transcriptHasForkedFrom(path: string, currentSessionId?: string): boolean;
|
|
54
54
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Claude Code transcript reader (Phase E, claude-native). Claude Code appends a
|
|
3
3
|
* JSONL transcript per session at
|
|
4
4
|
* `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl`; the interactive TUI's
|
|
5
|
-
* stdout is a full-screen UI, so — like
|
|
5
|
+
* stdout is a full-screen UI, so — like reference implementation's claude-native — we take the
|
|
6
6
|
* structured story from this file, not the PTY. Each `user`/`assistant` record
|
|
7
7
|
* wraps an Anthropic message (`{ role, content: [blocks] }`), so we map its
|
|
8
8
|
* blocks to the same typed {@link AgentEvent}s the headless executor emits.
|
|
@@ -173,10 +173,10 @@ function isObject(value) {
|
|
|
173
173
|
/**
|
|
174
174
|
* Whether a transcript is a `/fork` (branch) of another session: claude stamps a
|
|
175
175
|
* `forkedFrom: { sessionId }` marker in an early record pointing at the source
|
|
176
|
-
* session (
|
|
176
|
+
* session (reference implementation's `transcript_has_forked_from_marker`). Used to distinguish a
|
|
177
177
|
* fork from an ordinary `resume` (both arrive as `SessionStart source="resume"`).
|
|
178
178
|
* Scans only the head of the file (the marker lands up front). NOTE: unverified on
|
|
179
|
-
* this host — no local transcript carries the marker — so it follows
|
|
179
|
+
* this host — no local transcript carries the marker — so it follows reference implementation's shape.
|
|
180
180
|
*/
|
|
181
181
|
export function transcriptHasForkedFrom(path, currentSessionId) {
|
|
182
182
|
let text;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Synthesize a codex rollout file from rynx's canonical session log, so
|
|
3
3
|
* `codex --remote resume <threadId>` works when the local rollout is missing
|
|
4
|
-
* (fork / worktree / cross-machine). Ports
|
|
4
|
+
* (fork / worktree / cross-machine). Ports reference implementation's
|
|
5
5
|
* `_ensure_local_codex_resume_rollout`, adapted to rynx: the daemon (control-api)
|
|
6
6
|
* has BOTH the session items (`SessionLogStore`) and — since the private CODEX_HOME
|
|
7
7
|
* is a deterministic uid-scoped path — the app-server's rollout dir, so this runs
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { SessionInteractionResolution } from "@rynx-ai/core";
|
|
1
2
|
import type { AskForApproval, ClientInfo, CollaborationModeListResponse, GetAuthStatusParams, GetAuthStatusResponse, InitializeResponse, ModelListParams, ModelListResponse, ReviewStartParams, ReviewStartResponse, SandboxMode, ThreadForkParams, ThreadGoalClearParams, ThreadGoalGetParams, ThreadGoalGetResponse, ThreadGoalSetParams, ThreadListParams, ThreadListResponse, ResumedThread, ThreadResumeParams, ThreadSettingsUpdateParams, ThreadStartParams, TurnInterruptParams, TurnStartParams, TurnSteerParams, UserInput } from "./protocol.js";
|
|
2
3
|
import { CodexAppServerTransport, type CodexAppServerProcessSpawner, type RpcChannel, type TransportLogger } from "./transport.js";
|
|
4
|
+
import type { ResolveInteractionResult, RuntimeInteractionListener } from "../interactions.js";
|
|
3
5
|
export type ApprovalDecisionPolicy = "auto-approve-session" | "auto-decline" | "auto-cancel";
|
|
4
6
|
export type CodexNotificationListener = (method: string, params: unknown) => void;
|
|
5
7
|
export interface CodexAppServerClientOptions {
|
|
@@ -16,36 +18,21 @@ export interface CodexAppServerClientOptions {
|
|
|
16
18
|
* prompting a human.
|
|
17
19
|
*/
|
|
18
20
|
approvalDecisionPolicy?: ApprovalDecisionPolicy;
|
|
19
|
-
/**
|
|
20
|
-
* Surface approvals to a user instead of auto-deciding. When true and an
|
|
21
|
-
* approval listener is set, each request blocks until {@link
|
|
22
|
-
* CodexAppServerClient.resolveApproval} is called (or a timeout falls back to
|
|
23
|
-
* {@link approvalDecisionPolicy}).
|
|
24
|
-
*/
|
|
25
|
-
interactiveApprovals?: boolean;
|
|
26
|
-
}
|
|
27
|
-
/** A codex approval decision (superset of exec + patch decision enums). */
|
|
28
|
-
export type ApprovalDecision = "acceptForSession" | "accept" | "decline" | "cancel";
|
|
29
|
-
/** A pending approval surfaced to the user, awaiting {@link CodexAppServerClient.resolveApproval}. */
|
|
30
|
-
export interface ApprovalRequest {
|
|
31
|
-
approvalId: string;
|
|
32
|
-
kind: "exec" | "patch";
|
|
33
|
-
command?: string;
|
|
34
|
-
cwd?: string;
|
|
35
|
-
diff?: string;
|
|
36
21
|
}
|
|
37
22
|
export declare class CodexAppServerClient {
|
|
38
23
|
readonly transport: CodexAppServerTransport;
|
|
39
24
|
private readonly logger;
|
|
40
25
|
private readonly clientInfo;
|
|
41
26
|
private readonly approvalDecisionPolicy;
|
|
42
|
-
private readonly interactiveApprovals;
|
|
43
27
|
private readonly channel;
|
|
44
28
|
private readonly notificationSubscribers;
|
|
45
|
-
private
|
|
46
|
-
private
|
|
29
|
+
private interactionListener;
|
|
30
|
+
private connectionListener;
|
|
31
|
+
private connectionState;
|
|
32
|
+
private readonly pendingInteractions;
|
|
33
|
+
private readonly settledInteractions;
|
|
47
34
|
private initializeResponse;
|
|
48
|
-
constructor({ spawner, channel, logger, clientInfo, approvalDecisionPolicy,
|
|
35
|
+
constructor({ spawner, channel, logger, clientInfo, approvalDecisionPolicy, }: CodexAppServerClientOptions);
|
|
49
36
|
/**
|
|
50
37
|
* The multi-client endpoint a `codex --remote` TUI can attach to, when this
|
|
51
38
|
* client runs over a {@link WsRpcChannel}. `undefined` for the default stdio
|
|
@@ -101,27 +88,26 @@ export declare class CodexAppServerClient {
|
|
|
101
88
|
private dispatchNotification;
|
|
102
89
|
private handleServerRequest;
|
|
103
90
|
/**
|
|
104
|
-
* Register the
|
|
105
|
-
* the
|
|
106
|
-
*
|
|
107
|
-
*/
|
|
108
|
-
setApprovalRequestListener(listener: ((request: ApprovalRequest) => void) | null): void;
|
|
109
|
-
/**
|
|
110
|
-
* Deliver a user's decision for a pending interactive approval. Returns false
|
|
111
|
-
* if the approval id is unknown (already resolved, timed out, or auto-decided).
|
|
112
|
-
*/
|
|
113
|
-
resolveApproval(approvalId: string, decision: ApprovalDecision): boolean;
|
|
114
|
-
/**
|
|
115
|
-
* Interactive approval path: surface the request and block the codex
|
|
116
|
-
* server-request until the user decides (or the timeout falls back to the
|
|
117
|
-
* auto policy). When interactive approvals are off, decide immediately.
|
|
91
|
+
* Register the provider-neutral interaction listener. A request is inserted
|
|
92
|
+
* into the pending map before the listener is invoked, so a synchronous
|
|
93
|
+
* resolver still wins correctly.
|
|
118
94
|
*/
|
|
119
|
-
|
|
95
|
+
setInteractionListener(listener: RuntimeInteractionListener | null): void;
|
|
96
|
+
/** Observe the underlying app-server connection independently from any one
|
|
97
|
+
* interaction. A disconnected client that never received the duplicate
|
|
98
|
+
* native request still has to count as unavailable during host failover. */
|
|
99
|
+
setConnectionListener(listener: ((state: "connected" | "disconnected") => void) | null): void;
|
|
100
|
+
private setConnectionState;
|
|
101
|
+
resolveInteraction(interactionId: string, resolution: SessionInteractionResolution): ResolveInteractionResult;
|
|
102
|
+
/** Cancel every pending request owned by this connection without replying. */
|
|
103
|
+
cancelInteractions(reason?: string): void;
|
|
104
|
+
private handleInteraction;
|
|
120
105
|
private autoApprovalDecision;
|
|
121
|
-
private
|
|
122
|
-
private
|
|
123
|
-
private
|
|
124
|
-
private
|
|
106
|
+
private resolveByProvider;
|
|
107
|
+
private handleServerRequestResponseDelivery;
|
|
108
|
+
private cancelPendingInteractions;
|
|
109
|
+
private emitInteraction;
|
|
110
|
+
private rememberSettled;
|
|
125
111
|
}
|
|
126
112
|
export interface BuildSandboxPolicyOptions {
|
|
127
113
|
mode: SandboxMode;
|