@h-rig/cli-surface-plugin 0.0.6-alpha.157 → 0.0.6-alpha.159
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/src/app/drone-ui.d.ts +0 -11
- package/dist/src/app/drone-ui.js +0 -114
- package/dist/src/commands/_async-ui.d.ts +1 -1
- package/dist/src/commands/_cli-format.d.ts +0 -29
- package/dist/src/commands/_cli-format.js +59 -113
- package/dist/src/commands/_connection-state.d.ts +6 -33
- package/dist/src/commands/_connection-state.js +654 -138
- package/dist/src/commands/_doctor-checks.d.ts +2 -5
- package/dist/src/commands/_doctor-checks.js +10 -9
- package/dist/src/commands/_help-catalog.d.ts +2 -1
- package/dist/src/commands/_help-catalog.js +654 -7
- package/dist/src/commands/_inprocess-services.d.ts +5 -5
- package/dist/src/commands/_inprocess-services.js +1 -1
- package/dist/src/commands/_parsers.js +651 -12
- package/dist/src/commands/_paths.d.ts +0 -2
- package/dist/src/commands/_paths.js +2 -10
- package/dist/src/commands/_pi-install.d.ts +2 -12
- package/dist/src/commands/_pi-install.js +3 -36
- package/dist/src/commands/_policy.js +659 -20
- package/dist/src/commands/agent.d.ts +1 -1
- package/dist/src/commands/agent.js +675 -24
- package/dist/src/commands/config.d.ts +1 -1
- package/dist/src/commands/config.js +656 -21
- package/dist/src/commands/dist.d.ts +1 -1
- package/dist/src/commands/dist.js +828 -102
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.js +658 -12
- package/dist/src/commands/github.d.ts +1 -1
- package/dist/src/commands/github.js +658 -19
- package/dist/src/commands/inbox.d.ts +12 -8
- package/dist/src/commands/inbox.js +741 -22
- package/dist/src/commands/init.d.ts +17 -19
- package/dist/src/commands/init.js +836 -306
- package/dist/src/commands/inspect.d.ts +5 -6
- package/dist/src/commands/inspect.js +754 -42
- package/dist/src/commands/pi.d.ts +1 -1
- package/dist/src/commands/pi.js +655 -16
- package/dist/src/commands/plugin.d.ts +9 -9
- package/dist/src/commands/plugin.js +652 -13
- package/dist/src/commands/profile-and-review.d.ts +1 -1
- package/dist/src/commands/profile-and-review.js +655 -16
- package/dist/src/commands/queue.d.ts +1 -1
- package/dist/src/commands/queue.js +871 -12
- package/dist/src/commands/remote-client.d.ts +152 -0
- package/dist/src/commands/remote-client.js +475 -0
- package/dist/src/commands/remote.d.ts +1 -1
- package/dist/src/commands/remote.js +1100 -29
- package/dist/src/commands/repo-git-harness.d.ts +1 -1
- package/dist/src/commands/repo-git-harness.js +2321 -47
- package/dist/src/commands/run.d.ts +10 -6
- package/dist/src/commands/run.js +830 -50
- package/dist/src/commands/server.d.ts +1 -1
- package/dist/src/commands/server.js +649 -11
- package/dist/src/commands/setup.d.ts +2 -2
- package/dist/src/commands/setup.js +829 -18
- package/dist/src/commands/stats.d.ts +2 -4
- package/dist/src/commands/stats.js +1299 -20
- package/dist/src/commands/test.d.ts +1 -1
- package/dist/src/commands/test.js +648 -9
- package/dist/src/commands/triage.d.ts +2 -3
- package/dist/src/commands/triage.js +657 -11
- package/dist/src/commands/workspace.d.ts +1 -1
- package/dist/src/commands/workspace.js +1280 -15
- package/dist/src/control-plane/agent-binary-build.d.ts +9 -0
- package/dist/src/control-plane/agent-binary-build.js +88 -0
- package/dist/src/control-plane/embedded-native-assets.d.ts +7 -0
- package/dist/src/control-plane/embedded-native-assets.js +6 -0
- package/dist/src/control-plane/guard.d.ts +17 -0
- package/dist/src/control-plane/guard.js +684 -0
- package/dist/src/control-plane/harness-cli.d.ts +12 -0
- package/dist/src/control-plane/harness-cli.js +1623 -0
- package/dist/src/control-plane/native/git-ops.d.ts +67 -0
- package/dist/src/control-plane/native/git-ops.js +1381 -0
- package/dist/src/control-plane/native/github-auth-env.d.ts +1 -0
- package/dist/src/control-plane/native/github-auth-env.js +21 -0
- package/dist/src/control-plane/native/host-git.d.ts +4 -0
- package/dist/src/control-plane/native/host-git.js +51 -0
- package/dist/src/control-plane/priority-queue.d.ts +22 -0
- package/dist/src/control-plane/priority-queue.js +212 -0
- package/dist/src/control-plane/rigfig.d.ts +9 -0
- package/dist/src/control-plane/rigfig.js +70 -0
- package/dist/src/control-plane/scope.d.ts +3 -0
- package/dist/src/control-plane/scope.js +58 -0
- package/dist/src/control-plane/setup-status.d.ts +44 -0
- package/dist/src/control-plane/setup-status.js +164 -0
- package/dist/src/control-plane/task-data.d.ts +2 -0
- package/dist/src/control-plane/task-data.js +12 -0
- package/dist/src/control-plane/workspace-ops.d.ts +79 -0
- package/dist/src/control-plane/workspace-ops.js +639 -0
- package/dist/src/help-catalog-data.d.ts +7 -0
- package/dist/src/help-catalog-data.js +660 -0
- package/dist/src/kernel-dispatch.js +1 -3
- package/dist/src/plugin.js +10072 -30
- package/dist/src/runner.d.ts +7 -9
- package/dist/src/runner.js +750 -30
- package/package.json +12 -13
- package/dist/src/commands/_json-output.d.ts +0 -11
- package/dist/src/commands/_json-output.js +0 -54
- package/dist/src/commands/_pi-frontend.d.ts +0 -35
- package/dist/src/commands/_pi-frontend.js +0 -64
- package/dist/src/commands/_run-driver-helpers.d.ts +0 -26
- package/dist/src/commands/_run-driver-helpers.js +0 -132
- package/dist/src/commands/task-run-driver.d.ts +0 -93
- package/dist/src/commands/task-run-driver.js +0 -136
- package/dist/src/commands/task.d.ts +0 -46
- package/dist/src/commands/task.js +0 -555
- package/dist/src/provider-model.d.ts +0 -34
- package/dist/src/provider-model.js +0 -56
- package/dist/src/rig-config-package-deps.d.ts +0 -10
- package/dist/src/rig-config-package-deps.js +0 -272
- package/dist/src/version.d.ts +0 -8
- package/dist/src/version.js +0 -47
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { type ManagedRemoteEndpoint } from "@rig/core/remote-config";
|
|
2
|
+
export { DEFAULT_REMOTE_PORT, REMOTES_CONFIG_PATH, listManagedRemoteEndpoints, loadRemotesConfig, RemoteCliError, removeManagedRemoteEndpoint, resolveOwnerNamespaceKey, resolveRegistryBaseUrl, resolveRelayUrl, resolveSelectedRemote, resolveSshTarget, upsertManagedRemoteEndpoint, } from "@rig/core/remote-config";
|
|
3
|
+
export type { ManagedRemoteEndpoint, SelectedRemote } from "@rig/core/remote-config";
|
|
4
|
+
type JsonRecord = Record<string, unknown>;
|
|
5
|
+
type OperationResult = {
|
|
6
|
+
type: "operation_result";
|
|
7
|
+
success: boolean;
|
|
8
|
+
error?: string;
|
|
9
|
+
} & JsonRecord;
|
|
10
|
+
type PromptPreviewResponse = {
|
|
11
|
+
type: "prompt_preview_response";
|
|
12
|
+
success: boolean;
|
|
13
|
+
prompt?: string;
|
|
14
|
+
source?: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
};
|
|
17
|
+
type IterationOutputResponse = {
|
|
18
|
+
type: "iteration_output_response";
|
|
19
|
+
success: boolean;
|
|
20
|
+
taskId?: string;
|
|
21
|
+
iteration?: number;
|
|
22
|
+
output?: string;
|
|
23
|
+
startedAt?: string;
|
|
24
|
+
endedAt?: string;
|
|
25
|
+
durationMs?: number;
|
|
26
|
+
isRunning?: boolean;
|
|
27
|
+
error?: string;
|
|
28
|
+
};
|
|
29
|
+
type StartOrchestrationResponse = {
|
|
30
|
+
type: "orchestrate:start_response";
|
|
31
|
+
success: boolean;
|
|
32
|
+
error?: string;
|
|
33
|
+
orchestrationId?: string;
|
|
34
|
+
totalTasks?: number;
|
|
35
|
+
totalGroups?: number;
|
|
36
|
+
maxParallelism?: number;
|
|
37
|
+
};
|
|
38
|
+
type OrchestrationStateResponse = {
|
|
39
|
+
type: "orchestrate:state_response";
|
|
40
|
+
success: boolean;
|
|
41
|
+
error?: string;
|
|
42
|
+
state?: unknown;
|
|
43
|
+
};
|
|
44
|
+
type StateResponse = {
|
|
45
|
+
type: "state_response";
|
|
46
|
+
state: unknown;
|
|
47
|
+
};
|
|
48
|
+
type TasksResponse = {
|
|
49
|
+
type: "tasks_response";
|
|
50
|
+
tasks: unknown;
|
|
51
|
+
};
|
|
52
|
+
export type RemoteMessage = {
|
|
53
|
+
type: string;
|
|
54
|
+
id?: string;
|
|
55
|
+
timestamp?: string;
|
|
56
|
+
} & JsonRecord;
|
|
57
|
+
export type RemoteEndpoint = {
|
|
58
|
+
source: "flags" | "alias" | "env";
|
|
59
|
+
alias?: string;
|
|
60
|
+
host: string;
|
|
61
|
+
port: number;
|
|
62
|
+
token: string;
|
|
63
|
+
configPath: string;
|
|
64
|
+
};
|
|
65
|
+
export type ResolveRemoteOptions = {
|
|
66
|
+
projectRoot?: string | undefined;
|
|
67
|
+
host?: string | undefined;
|
|
68
|
+
port?: string | undefined;
|
|
69
|
+
token?: string | undefined;
|
|
70
|
+
remoteAlias?: string | undefined;
|
|
71
|
+
env?: Record<string, string | undefined> | undefined;
|
|
72
|
+
};
|
|
73
|
+
export type RemoteEvent = {
|
|
74
|
+
receivedAt: string;
|
|
75
|
+
message: RemoteMessage;
|
|
76
|
+
};
|
|
77
|
+
export declare function resolveRemoteEndpoint(options: ResolveRemoteOptions): RemoteEndpoint;
|
|
78
|
+
export type RemoteClientOptions = {
|
|
79
|
+
connectTimeoutMs?: number;
|
|
80
|
+
authTimeoutMs?: number;
|
|
81
|
+
requestTimeoutMs?: number;
|
|
82
|
+
subscriptionTimeoutMs?: number;
|
|
83
|
+
onEvent?: (event: RemoteEvent) => void;
|
|
84
|
+
};
|
|
85
|
+
export declare class RemoteWsClient {
|
|
86
|
+
readonly endpoint: RemoteEndpoint;
|
|
87
|
+
private ws;
|
|
88
|
+
private connected;
|
|
89
|
+
private pending;
|
|
90
|
+
private onEvent;
|
|
91
|
+
private requestTimeoutMs;
|
|
92
|
+
private connectTimeoutMs;
|
|
93
|
+
private authTimeoutMs;
|
|
94
|
+
private subscriptionTimeoutMs;
|
|
95
|
+
private connectionToken;
|
|
96
|
+
private connectionTokenExpiresAt;
|
|
97
|
+
private tokenRefreshTimer;
|
|
98
|
+
constructor(endpoint: RemoteEndpoint, options?: RemoteClientOptions);
|
|
99
|
+
setEventHandler(handler: ((event: RemoteEvent) => void) | undefined): void;
|
|
100
|
+
connect(): Promise<void>;
|
|
101
|
+
disconnect(): void;
|
|
102
|
+
subscribe(eventTypes?: string[]): Promise<OperationResult>;
|
|
103
|
+
unsubscribe(): Promise<OperationResult>;
|
|
104
|
+
getState(): Promise<StateResponse>;
|
|
105
|
+
getTasks(): Promise<TasksResponse>;
|
|
106
|
+
pause(): Promise<OperationResult>;
|
|
107
|
+
resume(): Promise<OperationResult>;
|
|
108
|
+
interrupt(): Promise<OperationResult>;
|
|
109
|
+
continueExecution(): Promise<OperationResult>;
|
|
110
|
+
refreshTasks(): Promise<OperationResult>;
|
|
111
|
+
addIterations(count: number): Promise<OperationResult>;
|
|
112
|
+
removeIterations(count: number): Promise<OperationResult>;
|
|
113
|
+
getPromptPreview(taskId: string): Promise<PromptPreviewResponse>;
|
|
114
|
+
getIterationOutput(taskId: string): Promise<IterationOutputResponse>;
|
|
115
|
+
startOrchestration(options: {
|
|
116
|
+
maxWorkers?: number;
|
|
117
|
+
maxIterations?: number;
|
|
118
|
+
directMerge?: boolean;
|
|
119
|
+
}): Promise<StartOrchestrationResponse>;
|
|
120
|
+
pauseOrchestration(orchestrationId: string): Promise<OperationResult>;
|
|
121
|
+
resumeOrchestration(orchestrationId: string): Promise<OperationResult>;
|
|
122
|
+
stopOrchestration(orchestrationId: string): Promise<OperationResult>;
|
|
123
|
+
getOrchestrationState(orchestrationId: string): Promise<OrchestrationStateResponse>;
|
|
124
|
+
ping(): Promise<RemoteMessage>;
|
|
125
|
+
private request;
|
|
126
|
+
private routeMessage;
|
|
127
|
+
private scheduleTokenRefresh;
|
|
128
|
+
private clearTokenRefreshTimer;
|
|
129
|
+
private clearPending;
|
|
130
|
+
}
|
|
131
|
+
export declare function matchesEventFilter(message: RemoteMessage, expectedType?: string): boolean;
|
|
132
|
+
export declare function summarizeMessage(message: RemoteMessage): string;
|
|
133
|
+
export declare function migrateManagedRemoteEndpoints(projectRoot: string, legacyPath?: string): {
|
|
134
|
+
imported: number;
|
|
135
|
+
skipped: number;
|
|
136
|
+
sourcePath: string;
|
|
137
|
+
};
|
|
138
|
+
export declare function doctorManagedRemoteEndpoints(projectRoot: string): {
|
|
139
|
+
manifestPath: string;
|
|
140
|
+
secretsPath: string;
|
|
141
|
+
endpointCount: number;
|
|
142
|
+
missingSecrets: string[];
|
|
143
|
+
warnings: string[];
|
|
144
|
+
};
|
|
145
|
+
export declare function updateManagedRemoteEndpointInAuthority(projectRoot: string, input: {
|
|
146
|
+
endpointId?: string | undefined;
|
|
147
|
+
alias?: string | undefined;
|
|
148
|
+
host?: string | undefined;
|
|
149
|
+
port?: number | undefined;
|
|
150
|
+
token?: string | undefined;
|
|
151
|
+
autoConnect?: boolean | undefined;
|
|
152
|
+
}): ManagedRemoteEndpoint | null;
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli-surface-plugin/src/commands/remote-client.ts
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { resolveAuthorityPaths } from "@rig/core/server-paths";
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_REMOTE_PORT,
|
|
7
|
+
REMOTES_CONFIG_PATH,
|
|
8
|
+
doctorAuthorityRemoteEndpoints,
|
|
9
|
+
importLegacyRemoteEndpoints,
|
|
10
|
+
listAuthorityRemoteEndpoints,
|
|
11
|
+
loadRemotesConfig,
|
|
12
|
+
markAuthorityRemoteEndpointConnected,
|
|
13
|
+
normalizeString,
|
|
14
|
+
RemoteCliError,
|
|
15
|
+
updateAuthorityRemoteEndpoint
|
|
16
|
+
} from "@rig/core/remote-config";
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_REMOTE_PORT as DEFAULT_REMOTE_PORT2,
|
|
19
|
+
REMOTES_CONFIG_PATH as REMOTES_CONFIG_PATH2,
|
|
20
|
+
listManagedRemoteEndpoints,
|
|
21
|
+
loadRemotesConfig as loadRemotesConfig2,
|
|
22
|
+
RemoteCliError as RemoteCliError2,
|
|
23
|
+
removeManagedRemoteEndpoint,
|
|
24
|
+
resolveOwnerNamespaceKey,
|
|
25
|
+
resolveRegistryBaseUrl as resolveRegistryBaseUrl2,
|
|
26
|
+
resolveRelayUrl as resolveRelayUrl2,
|
|
27
|
+
resolveSelectedRemote,
|
|
28
|
+
resolveSshTarget,
|
|
29
|
+
upsertManagedRemoteEndpoint
|
|
30
|
+
} from "@rig/core/remote-config";
|
|
31
|
+
var DEFAULT_TIMEOUTS = {
|
|
32
|
+
connectMs: 5000,
|
|
33
|
+
authMs: 5000,
|
|
34
|
+
requestMs: 30000,
|
|
35
|
+
subscriptionMs: 1e4
|
|
36
|
+
};
|
|
37
|
+
function resolveRemoteEndpoint(options) {
|
|
38
|
+
const env = options.env ?? process.env;
|
|
39
|
+
const envHost = normalizeString(env.RIG_REMOTE_HOST);
|
|
40
|
+
const envToken = normalizeString(env.RIG_REMOTE_TOKEN);
|
|
41
|
+
const envPort = parsePort(normalizeString(env.RIG_REMOTE_PORT), "RIG_REMOTE_PORT");
|
|
42
|
+
const envAlias = normalizeString(env.RIG_REMOTE_ALIAS);
|
|
43
|
+
const explicitHost = normalizeString(options.host);
|
|
44
|
+
const explicitToken = normalizeString(options.token);
|
|
45
|
+
const explicitPort = parsePort(normalizeString(options.port), "--port");
|
|
46
|
+
const explicitProvided = Boolean(explicitHost || explicitToken || explicitPort !== null);
|
|
47
|
+
const requestedAlias = normalizeString(options.remoteAlias) || envAlias;
|
|
48
|
+
let endpoint = {
|
|
49
|
+
source: "env",
|
|
50
|
+
host: envHost || "",
|
|
51
|
+
port: envPort ?? DEFAULT_REMOTE_PORT,
|
|
52
|
+
token: envToken || "",
|
|
53
|
+
configPath: REMOTES_CONFIG_PATH
|
|
54
|
+
};
|
|
55
|
+
if (requestedAlias) {
|
|
56
|
+
if (options.projectRoot) {
|
|
57
|
+
const remote = listAuthorityRemoteEndpoints(options.projectRoot).find((entry) => entry.alias === requestedAlias);
|
|
58
|
+
if (!remote) {
|
|
59
|
+
const configPath = resolveAuthorityPaths(options.projectRoot).remoteEndpointsPath;
|
|
60
|
+
throw new RemoteCliError("RIG_REMOTE_ALIAS_NOT_FOUND", `Remote alias '${requestedAlias}' was not found in ${configPath}.`, 2, { alias: requestedAlias, configPath });
|
|
61
|
+
}
|
|
62
|
+
endpoint = {
|
|
63
|
+
source: "alias",
|
|
64
|
+
alias: requestedAlias,
|
|
65
|
+
host: remote.host,
|
|
66
|
+
port: remote.port,
|
|
67
|
+
token: remote.token,
|
|
68
|
+
configPath: resolveAuthorityPaths(options.projectRoot).remoteEndpointsPath
|
|
69
|
+
};
|
|
70
|
+
} else {
|
|
71
|
+
const config = loadRemotesConfig();
|
|
72
|
+
const remote = config.remotes?.[requestedAlias];
|
|
73
|
+
if (!remote) {
|
|
74
|
+
throw new RemoteCliError("RIG_REMOTE_ALIAS_NOT_FOUND", `Remote alias '${requestedAlias}' was not found in ${REMOTES_CONFIG_PATH}.`, 2, { alias: requestedAlias, configPath: REMOTES_CONFIG_PATH });
|
|
75
|
+
}
|
|
76
|
+
endpoint = {
|
|
77
|
+
source: "alias",
|
|
78
|
+
alias: requestedAlias,
|
|
79
|
+
host: normalizeString(remote.host) || "",
|
|
80
|
+
port: Number.isFinite(remote.port) ? Number(remote.port) : DEFAULT_REMOTE_PORT,
|
|
81
|
+
token: normalizeString(remote.token) || "",
|
|
82
|
+
configPath: REMOTES_CONFIG_PATH
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (explicitProvided) {
|
|
87
|
+
endpoint = {
|
|
88
|
+
...endpoint,
|
|
89
|
+
source: "flags",
|
|
90
|
+
host: explicitHost || endpoint.host,
|
|
91
|
+
port: explicitPort ?? endpoint.port,
|
|
92
|
+
token: explicitToken || endpoint.token
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (!endpoint.host) {
|
|
96
|
+
throw new RemoteCliError("RIG_REMOTE_HOST_REQUIRED", "Remote host is required. Pass --host, --remote <alias>, or set RIG_REMOTE_HOST.", 2);
|
|
97
|
+
}
|
|
98
|
+
if (!Number.isFinite(endpoint.port) || endpoint.port <= 0 || endpoint.port > 65535) {
|
|
99
|
+
throw new RemoteCliError("RIG_REMOTE_INVALID_PORT", `Invalid remote port: ${endpoint.port}.`, 2);
|
|
100
|
+
}
|
|
101
|
+
return endpoint;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
class RemoteWsClient {
|
|
105
|
+
endpoint;
|
|
106
|
+
ws = null;
|
|
107
|
+
connected = false;
|
|
108
|
+
pending = new Map;
|
|
109
|
+
onEvent;
|
|
110
|
+
requestTimeoutMs;
|
|
111
|
+
connectTimeoutMs;
|
|
112
|
+
authTimeoutMs;
|
|
113
|
+
subscriptionTimeoutMs;
|
|
114
|
+
connectionToken = null;
|
|
115
|
+
connectionTokenExpiresAt = null;
|
|
116
|
+
tokenRefreshTimer = null;
|
|
117
|
+
constructor(endpoint, options = {}) {
|
|
118
|
+
this.endpoint = endpoint;
|
|
119
|
+
this.onEvent = options.onEvent;
|
|
120
|
+
this.connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_TIMEOUTS.connectMs;
|
|
121
|
+
this.authTimeoutMs = options.authTimeoutMs ?? DEFAULT_TIMEOUTS.authMs;
|
|
122
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_TIMEOUTS.requestMs;
|
|
123
|
+
this.subscriptionTimeoutMs = options.subscriptionTimeoutMs ?? DEFAULT_TIMEOUTS.subscriptionMs;
|
|
124
|
+
}
|
|
125
|
+
setEventHandler(handler) {
|
|
126
|
+
this.onEvent = handler;
|
|
127
|
+
}
|
|
128
|
+
async connect() {
|
|
129
|
+
if (this.connected) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const url = `ws://${this.endpoint.host}:${this.endpoint.port}`;
|
|
133
|
+
await new Promise((resolve, reject) => {
|
|
134
|
+
let authResolved = false;
|
|
135
|
+
let connectTimer = setTimeout(() => {
|
|
136
|
+
connectTimer = null;
|
|
137
|
+
reject(new RemoteCliError("RIG_REMOTE_CONNECT_TIMEOUT", `Timed out connecting to ${url} after ${this.connectTimeoutMs}ms.`, 3, { host: this.endpoint.host, port: this.endpoint.port, timeoutMs: this.connectTimeoutMs }));
|
|
138
|
+
}, this.connectTimeoutMs);
|
|
139
|
+
const ws = new WebSocket(url);
|
|
140
|
+
this.ws = ws;
|
|
141
|
+
ws.onopen = () => {
|
|
142
|
+
const authMessage = {
|
|
143
|
+
type: "auth",
|
|
144
|
+
id: crypto.randomUUID(),
|
|
145
|
+
timestamp: new Date().toISOString(),
|
|
146
|
+
token: this.connectionToken || this.endpoint.token,
|
|
147
|
+
tokenType: this.connectionToken ? "connection" : "server"
|
|
148
|
+
};
|
|
149
|
+
let authTimer = setTimeout(() => {
|
|
150
|
+
authTimer = null;
|
|
151
|
+
reject(new RemoteCliError("RIG_REMOTE_AUTH_TIMEOUT", `Timed out waiting for auth response from ${url} after ${this.authTimeoutMs}ms.`, 3, { host: this.endpoint.host, port: this.endpoint.port, timeoutMs: this.authTimeoutMs }));
|
|
152
|
+
}, this.authTimeoutMs);
|
|
153
|
+
ws.send(JSON.stringify(authMessage));
|
|
154
|
+
const originalOnMessage = ws.onmessage;
|
|
155
|
+
ws.onmessage = (event) => {
|
|
156
|
+
const message = parseIncomingMessage(event.data);
|
|
157
|
+
if (!message) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (message.type === "auth_response" && !authResolved) {
|
|
161
|
+
authResolved = true;
|
|
162
|
+
if (connectTimer) {
|
|
163
|
+
clearTimeout(connectTimer);
|
|
164
|
+
connectTimer = null;
|
|
165
|
+
}
|
|
166
|
+
if (authTimer) {
|
|
167
|
+
clearTimeout(authTimer);
|
|
168
|
+
authTimer = null;
|
|
169
|
+
}
|
|
170
|
+
const auth = message;
|
|
171
|
+
if (!auth.success) {
|
|
172
|
+
reject(new RemoteCliError("RIG_REMOTE_AUTH_FAILED", auth.error || "Remote authentication failed.", 3, { host: this.endpoint.host, port: this.endpoint.port }));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (auth.connectionToken && auth.connectionTokenExpiresAt) {
|
|
176
|
+
this.connectionToken = auth.connectionToken;
|
|
177
|
+
this.connectionTokenExpiresAt = auth.connectionTokenExpiresAt;
|
|
178
|
+
this.scheduleTokenRefresh();
|
|
179
|
+
}
|
|
180
|
+
if (this.endpoint.configPath.endsWith("endpoints.toml")) {
|
|
181
|
+
const projectRoot = dirname(dirname(dirname(this.endpoint.configPath)));
|
|
182
|
+
try {
|
|
183
|
+
markAuthorityRemoteEndpointConnected(projectRoot, this.endpoint.alias ? listAuthorityRemoteEndpoints(projectRoot).find((entry) => entry.alias === this.endpoint.alias)?.id ?? "" : "");
|
|
184
|
+
} catch {}
|
|
185
|
+
}
|
|
186
|
+
this.connected = true;
|
|
187
|
+
ws.onmessage = (event2) => {
|
|
188
|
+
const next = parseIncomingMessage(event2.data);
|
|
189
|
+
if (!next) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
this.routeMessage(next);
|
|
193
|
+
};
|
|
194
|
+
resolve();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (typeof originalOnMessage === "function") {
|
|
198
|
+
originalOnMessage.call(ws, event);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
ws.onerror = () => {
|
|
203
|
+
if (connectTimer) {
|
|
204
|
+
clearTimeout(connectTimer);
|
|
205
|
+
connectTimer = null;
|
|
206
|
+
}
|
|
207
|
+
if (!authResolved) {
|
|
208
|
+
reject(new RemoteCliError("RIG_REMOTE_CONNECT_FAILED", `Failed to connect to ${url}.`, 3, { host: this.endpoint.host, port: this.endpoint.port }));
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
ws.onclose = () => {
|
|
212
|
+
this.connected = false;
|
|
213
|
+
this.clearPending("Connection closed");
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
disconnect() {
|
|
218
|
+
this.connected = false;
|
|
219
|
+
this.clearTokenRefreshTimer();
|
|
220
|
+
this.clearPending("Connection closed");
|
|
221
|
+
if (this.ws) {
|
|
222
|
+
try {
|
|
223
|
+
this.ws.close();
|
|
224
|
+
} catch {}
|
|
225
|
+
this.ws = null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async subscribe(eventTypes = []) {
|
|
229
|
+
const message = { type: "subscribe" };
|
|
230
|
+
if (eventTypes.length > 0) {
|
|
231
|
+
message.eventTypes = eventTypes;
|
|
232
|
+
}
|
|
233
|
+
const response = await this.request(message, this.subscriptionTimeoutMs);
|
|
234
|
+
return expectType(response, "operation_result");
|
|
235
|
+
}
|
|
236
|
+
async unsubscribe() {
|
|
237
|
+
return expectType(await this.request({ type: "unsubscribe" }), "operation_result");
|
|
238
|
+
}
|
|
239
|
+
async getState() {
|
|
240
|
+
return expectType(await this.request({ type: "get_state" }), "state_response");
|
|
241
|
+
}
|
|
242
|
+
async getTasks() {
|
|
243
|
+
return expectType(await this.request({ type: "get_tasks" }), "tasks_response");
|
|
244
|
+
}
|
|
245
|
+
async pause() {
|
|
246
|
+
return expectType(await this.request({ type: "pause" }), "operation_result");
|
|
247
|
+
}
|
|
248
|
+
async resume() {
|
|
249
|
+
return expectType(await this.request({ type: "resume" }), "operation_result");
|
|
250
|
+
}
|
|
251
|
+
async interrupt() {
|
|
252
|
+
return expectType(await this.request({ type: "interrupt" }), "operation_result");
|
|
253
|
+
}
|
|
254
|
+
async continueExecution() {
|
|
255
|
+
return expectType(await this.request({ type: "continue" }), "operation_result");
|
|
256
|
+
}
|
|
257
|
+
async refreshTasks() {
|
|
258
|
+
return expectType(await this.request({ type: "refresh_tasks" }), "operation_result");
|
|
259
|
+
}
|
|
260
|
+
async addIterations(count) {
|
|
261
|
+
return expectType(await this.request({ type: "add_iterations", count }), "operation_result");
|
|
262
|
+
}
|
|
263
|
+
async removeIterations(count) {
|
|
264
|
+
return expectType(await this.request({ type: "remove_iterations", count }), "operation_result");
|
|
265
|
+
}
|
|
266
|
+
async getPromptPreview(taskId) {
|
|
267
|
+
return expectType(await this.request({ type: "get_prompt_preview", taskId }), "prompt_preview_response");
|
|
268
|
+
}
|
|
269
|
+
async getIterationOutput(taskId) {
|
|
270
|
+
return expectType(await this.request({ type: "get_iteration_output", taskId }), "iteration_output_response");
|
|
271
|
+
}
|
|
272
|
+
async startOrchestration(options) {
|
|
273
|
+
return expectType(await this.request({
|
|
274
|
+
type: "orchestrate:start",
|
|
275
|
+
maxWorkers: options.maxWorkers,
|
|
276
|
+
maxIterations: options.maxIterations,
|
|
277
|
+
directMerge: options.directMerge
|
|
278
|
+
}), "orchestrate:start_response");
|
|
279
|
+
}
|
|
280
|
+
async pauseOrchestration(orchestrationId) {
|
|
281
|
+
return expectType(await this.request({ type: "orchestrate:pause", orchestrationId }), "operation_result");
|
|
282
|
+
}
|
|
283
|
+
async resumeOrchestration(orchestrationId) {
|
|
284
|
+
return expectType(await this.request({ type: "orchestrate:resume", orchestrationId }), "operation_result");
|
|
285
|
+
}
|
|
286
|
+
async stopOrchestration(orchestrationId) {
|
|
287
|
+
return expectType(await this.request({ type: "orchestrate:stop", orchestrationId }), "operation_result");
|
|
288
|
+
}
|
|
289
|
+
async getOrchestrationState(orchestrationId) {
|
|
290
|
+
return expectType(await this.request({ type: "orchestrate:get_state", orchestrationId }), "orchestrate:state_response");
|
|
291
|
+
}
|
|
292
|
+
async ping() {
|
|
293
|
+
return this.request({ type: "ping" });
|
|
294
|
+
}
|
|
295
|
+
async request(payload, timeoutMs = this.requestTimeoutMs) {
|
|
296
|
+
if (!this.connected || !this.ws) {
|
|
297
|
+
throw new RemoteCliError("RIG_REMOTE_NOT_CONNECTED", "Remote client is not connected.", 3);
|
|
298
|
+
}
|
|
299
|
+
const id = crypto.randomUUID();
|
|
300
|
+
const message = {
|
|
301
|
+
...payload,
|
|
302
|
+
id,
|
|
303
|
+
timestamp: new Date().toISOString()
|
|
304
|
+
};
|
|
305
|
+
return await new Promise((resolve, reject) => {
|
|
306
|
+
const timeout = setTimeout(() => {
|
|
307
|
+
this.pending.delete(id);
|
|
308
|
+
reject(new RemoteCliError("RIG_REMOTE_REQUEST_TIMEOUT", `Timed out waiting for response to '${String(payload.type)}' after ${timeoutMs}ms.`, 3, { requestType: payload.type, requestId: id, timeoutMs }));
|
|
309
|
+
}, timeoutMs);
|
|
310
|
+
this.pending.set(id, { resolve, reject, timeout });
|
|
311
|
+
this.ws?.send(JSON.stringify(message));
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
routeMessage(message) {
|
|
315
|
+
if (message.id && this.pending.has(message.id)) {
|
|
316
|
+
const pending = this.pending.get(message.id);
|
|
317
|
+
if (pending) {
|
|
318
|
+
clearTimeout(pending.timeout);
|
|
319
|
+
this.pending.delete(message.id);
|
|
320
|
+
pending.resolve(message);
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (message.type === "token_refresh_response") {
|
|
325
|
+
const token = normalizeString(message.connectionToken);
|
|
326
|
+
const expiresAt = normalizeString(message.connectionTokenExpiresAt);
|
|
327
|
+
if (token && expiresAt) {
|
|
328
|
+
this.connectionToken = token;
|
|
329
|
+
this.connectionTokenExpiresAt = expiresAt;
|
|
330
|
+
this.scheduleTokenRefresh();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
this.onEvent?.({ receivedAt: new Date().toISOString(), message });
|
|
334
|
+
}
|
|
335
|
+
scheduleTokenRefresh() {
|
|
336
|
+
this.clearTokenRefreshTimer();
|
|
337
|
+
if (!this.connectionToken || !this.connectionTokenExpiresAt || !this.ws || !this.connected) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const expiresAt = new Date(this.connectionTokenExpiresAt).getTime();
|
|
341
|
+
if (!Number.isFinite(expiresAt)) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const refreshAt = expiresAt - 60 * 60 * 1000;
|
|
345
|
+
const delay = Math.max(0, refreshAt - Date.now());
|
|
346
|
+
this.tokenRefreshTimer = setTimeout(() => {
|
|
347
|
+
if (!this.connected || !this.ws || !this.connectionToken) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const refreshMessage = {
|
|
351
|
+
type: "token_refresh",
|
|
352
|
+
id: crypto.randomUUID(),
|
|
353
|
+
timestamp: new Date().toISOString(),
|
|
354
|
+
connectionToken: this.connectionToken
|
|
355
|
+
};
|
|
356
|
+
this.ws.send(JSON.stringify(refreshMessage));
|
|
357
|
+
}, delay);
|
|
358
|
+
}
|
|
359
|
+
clearTokenRefreshTimer() {
|
|
360
|
+
if (this.tokenRefreshTimer) {
|
|
361
|
+
clearTimeout(this.tokenRefreshTimer);
|
|
362
|
+
this.tokenRefreshTimer = null;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
clearPending(reason) {
|
|
366
|
+
for (const [requestId, pending] of this.pending.entries()) {
|
|
367
|
+
clearTimeout(pending.timeout);
|
|
368
|
+
pending.reject(new RemoteCliError("RIG_REMOTE_REQUEST_CANCELLED", `${reason} (request ${requestId}).`, 3, { requestId }));
|
|
369
|
+
this.pending.delete(requestId);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function matchesEventFilter(message, expectedType) {
|
|
374
|
+
if (!expectedType) {
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
if (message.type === expectedType) {
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
if (message.type === "engine_event") {
|
|
381
|
+
const eventType = normalizeString(message.event?.type);
|
|
382
|
+
return eventType === expectedType;
|
|
383
|
+
}
|
|
384
|
+
if (message.type === "parallel_event") {
|
|
385
|
+
const eventType = normalizeString(message.event?.type);
|
|
386
|
+
return eventType === expectedType;
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
function summarizeMessage(message) {
|
|
391
|
+
if (message.type === "pong") {
|
|
392
|
+
return "pong";
|
|
393
|
+
}
|
|
394
|
+
if (message.type === "engine_event") {
|
|
395
|
+
const eventType = normalizeString(message.event?.type);
|
|
396
|
+
return eventType ? `engine_event:${eventType}` : "engine_event";
|
|
397
|
+
}
|
|
398
|
+
if (message.type === "parallel_event") {
|
|
399
|
+
const eventType = normalizeString(message.event?.type);
|
|
400
|
+
const orchestrationId = normalizeString(message.orchestrationId);
|
|
401
|
+
return orchestrationId ? `parallel_event:${eventType || "unknown"}:${orchestrationId}` : `parallel_event:${eventType || "unknown"}`;
|
|
402
|
+
}
|
|
403
|
+
return message.type;
|
|
404
|
+
}
|
|
405
|
+
function migrateManagedRemoteEndpoints(projectRoot, legacyPath = REMOTES_CONFIG_PATH) {
|
|
406
|
+
return importLegacyRemoteEndpoints(projectRoot, legacyPath);
|
|
407
|
+
}
|
|
408
|
+
function doctorManagedRemoteEndpoints(projectRoot) {
|
|
409
|
+
return doctorAuthorityRemoteEndpoints(projectRoot);
|
|
410
|
+
}
|
|
411
|
+
function updateManagedRemoteEndpointInAuthority(projectRoot, input) {
|
|
412
|
+
const updated = updateAuthorityRemoteEndpoint(projectRoot, input);
|
|
413
|
+
if (!updated)
|
|
414
|
+
return null;
|
|
415
|
+
return {
|
|
416
|
+
id: updated.id,
|
|
417
|
+
alias: updated.alias,
|
|
418
|
+
host: updated.host,
|
|
419
|
+
port: updated.port,
|
|
420
|
+
token: updated.token,
|
|
421
|
+
addedAt: updated.addedAt,
|
|
422
|
+
lastConnected: updated.lastConnectedAt
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function parsePort(value, label) {
|
|
426
|
+
if (!value) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
const parsed = Number.parseInt(value, 10);
|
|
430
|
+
if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 65535) {
|
|
431
|
+
throw new RemoteCliError("RIG_REMOTE_INVALID_PORT", `Invalid port for ${label}: ${value}.`, 2, { label, value });
|
|
432
|
+
}
|
|
433
|
+
return parsed;
|
|
434
|
+
}
|
|
435
|
+
function parseIncomingMessage(raw) {
|
|
436
|
+
if (typeof raw !== "string") {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
const parsed = JSON.parse(raw);
|
|
441
|
+
if (!parsed || typeof parsed !== "object" || typeof parsed.type !== "string") {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
return parsed;
|
|
445
|
+
} catch {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
function expectType(message, expectedType) {
|
|
450
|
+
if (message.type !== expectedType) {
|
|
451
|
+
throw new RemoteCliError("RIG_REMOTE_UNEXPECTED_RESPONSE", `Unexpected response type: ${message.type}. Expected ${expectedType}.`, 3, { expectedType, actualType: message.type, message });
|
|
452
|
+
}
|
|
453
|
+
return message;
|
|
454
|
+
}
|
|
455
|
+
export {
|
|
456
|
+
upsertManagedRemoteEndpoint,
|
|
457
|
+
updateManagedRemoteEndpointInAuthority,
|
|
458
|
+
summarizeMessage,
|
|
459
|
+
resolveSshTarget,
|
|
460
|
+
resolveSelectedRemote,
|
|
461
|
+
resolveRemoteEndpoint,
|
|
462
|
+
resolveRelayUrl2 as resolveRelayUrl,
|
|
463
|
+
resolveRegistryBaseUrl2 as resolveRegistryBaseUrl,
|
|
464
|
+
resolveOwnerNamespaceKey,
|
|
465
|
+
removeManagedRemoteEndpoint,
|
|
466
|
+
migrateManagedRemoteEndpoints,
|
|
467
|
+
matchesEventFilter,
|
|
468
|
+
loadRemotesConfig2 as loadRemotesConfig,
|
|
469
|
+
listManagedRemoteEndpoints,
|
|
470
|
+
doctorManagedRemoteEndpoints,
|
|
471
|
+
RemoteWsClient,
|
|
472
|
+
RemoteCliError2 as RemoteCliError,
|
|
473
|
+
REMOTES_CONFIG_PATH2 as REMOTES_CONFIG_PATH,
|
|
474
|
+
DEFAULT_REMOTE_PORT2 as DEFAULT_REMOTE_PORT
|
|
475
|
+
};
|