@h-rig/cli 0.0.6-alpha.45 → 0.0.6-alpha.46
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/bin/rig.js +50 -22
- package/dist/src/commands/_connection-state.js +11 -3
- package/dist/src/commands/_doctor-checks.js +51 -7
- package/dist/src/commands/_operator-view.js +53 -7
- package/dist/src/commands/_pi-frontend.js +53 -7
- package/dist/src/commands/_pi-remote-session.js +53 -7
- package/dist/src/commands/_pi-worker-bridge-extension.js +53 -7
- package/dist/src/commands/_preflight.js +51 -7
- package/dist/src/commands/_server-client.js +58 -22
- package/dist/src/commands/_snapshot-upload.js +51 -7
- package/dist/src/commands/connect.js +2 -1
- package/dist/src/commands/doctor.js +51 -7
- package/dist/src/commands/github.js +51 -7
- package/dist/src/commands/inbox.js +51 -7
- package/dist/src/commands/init.js +48 -22
- package/dist/src/commands/inspect.js +51 -7
- package/dist/src/commands/run.js +53 -7
- package/dist/src/commands/server.js +43 -7
- package/dist/src/commands/setup.js +51 -7
- package/dist/src/commands/task-run-driver.js +51 -7
- package/dist/src/commands/task.js +53 -7
- package/dist/src/commands.js +50 -22
- package/dist/src/index.js +50 -22
- package/package.json +6 -6
package/dist/bin/rig.js
CHANGED
|
@@ -2888,7 +2888,8 @@ function readRepoConnection(projectRoot) {
|
|
|
2888
2888
|
return {
|
|
2889
2889
|
selected,
|
|
2890
2890
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
2891
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
2891
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
2892
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
2892
2893
|
};
|
|
2893
2894
|
}
|
|
2894
2895
|
function writeRepoConnection(projectRoot, state) {
|
|
@@ -2899,13 +2900,19 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
2899
2900
|
if (!repo)
|
|
2900
2901
|
return null;
|
|
2901
2902
|
if (repo.selected === "local")
|
|
2902
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
2903
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
2903
2904
|
const global = readGlobalConnections(options);
|
|
2904
2905
|
const connection = global.connections[repo.selected];
|
|
2905
2906
|
if (!connection) {
|
|
2906
2907
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
2907
2908
|
}
|
|
2908
|
-
return { alias: repo.selected, connection };
|
|
2909
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
2910
|
+
}
|
|
2911
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
2912
|
+
const repo = readRepoConnection(projectRoot);
|
|
2913
|
+
if (!repo)
|
|
2914
|
+
return;
|
|
2915
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
2909
2916
|
}
|
|
2910
2917
|
|
|
2911
2918
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -2946,17 +2953,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
2946
2953
|
try {
|
|
2947
2954
|
const selected = resolveSelectedConnection(projectRoot);
|
|
2948
2955
|
if (selected?.connection.kind === "remote") {
|
|
2956
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
2957
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
2949
2958
|
return {
|
|
2950
2959
|
baseUrl: selected.connection.baseUrl,
|
|
2951
|
-
authToken
|
|
2952
|
-
connectionKind: "remote"
|
|
2960
|
+
authToken,
|
|
2961
|
+
connectionKind: "remote",
|
|
2962
|
+
serverProjectRoot
|
|
2953
2963
|
};
|
|
2954
2964
|
}
|
|
2955
2965
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
2956
2966
|
return {
|
|
2957
2967
|
baseUrl: connection.baseUrl,
|
|
2958
2968
|
authToken: connection.authToken,
|
|
2959
|
-
connectionKind: "local"
|
|
2969
|
+
connectionKind: "local",
|
|
2970
|
+
serverProjectRoot: resolve11(projectRoot)
|
|
2960
2971
|
};
|
|
2961
2972
|
} catch (error) {
|
|
2962
2973
|
if (error instanceof Error) {
|
|
@@ -2965,6 +2976,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
2965
2976
|
throw error;
|
|
2966
2977
|
}
|
|
2967
2978
|
}
|
|
2979
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
2980
|
+
const repo = readRepoConnection(projectRoot);
|
|
2981
|
+
const slug = repo?.project?.trim();
|
|
2982
|
+
if (!slug)
|
|
2983
|
+
return null;
|
|
2984
|
+
try {
|
|
2985
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
2986
|
+
headers: mergeHeaders(undefined, authToken)
|
|
2987
|
+
});
|
|
2988
|
+
if (!response.ok)
|
|
2989
|
+
return null;
|
|
2990
|
+
const payload = await response.json();
|
|
2991
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
2992
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
2993
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
2994
|
+
if (path)
|
|
2995
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
2996
|
+
return path;
|
|
2997
|
+
} catch {
|
|
2998
|
+
return null;
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
2968
3001
|
function appendTaskFilterParams(url, filters) {
|
|
2969
3002
|
if (filters.assignee)
|
|
2970
3003
|
url.searchParams.set("assignee", filters.assignee);
|
|
@@ -2999,9 +3032,12 @@ function diagnosticMessage(payload) {
|
|
|
2999
3032
|
}
|
|
3000
3033
|
async function requestServerJson(context, pathname, init = {}) {
|
|
3001
3034
|
const server = await ensureServerForCli(context.projectRoot);
|
|
3035
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
3036
|
+
if (server.serverProjectRoot)
|
|
3037
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
3002
3038
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
3003
3039
|
...init,
|
|
3004
|
-
headers
|
|
3040
|
+
headers
|
|
3005
3041
|
});
|
|
3006
3042
|
const text2 = await response.text();
|
|
3007
3043
|
const payload = text2.trim().length > 0 ? (() => {
|
|
@@ -3108,22 +3144,12 @@ async function switchServerProjectRootViaServer(context, projectRoot, options =
|
|
|
3108
3144
|
if (!switched) {
|
|
3109
3145
|
throw new CliError2(`Rig server did not accept project-root switch to ${projectRoot} before timeout (${lastError instanceof Error ? lastError.message : String(lastError ?? "no response")}).`, 1);
|
|
3110
3146
|
}
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
const record = status;
|
|
3116
|
-
if (record.projectRoot === projectRoot) {
|
|
3117
|
-
return { ok: true, switched, status: record };
|
|
3118
|
-
}
|
|
3119
|
-
lastError = `server projectRoot=${String(record.projectRoot ?? "unknown")}`;
|
|
3120
|
-
}
|
|
3121
|
-
} catch (error) {
|
|
3122
|
-
lastError = error;
|
|
3123
|
-
}
|
|
3124
|
-
await sleep(pollMs);
|
|
3147
|
+
const record = switched && typeof switched === "object" && !Array.isArray(switched) ? switched : {};
|
|
3148
|
+
if (record.ok === true) {
|
|
3149
|
+
writeRepoServerProjectRoot(context.projectRoot, projectRoot);
|
|
3150
|
+
return { ok: true, switched: record };
|
|
3125
3151
|
}
|
|
3126
|
-
throw new CliError2(`Rig server
|
|
3152
|
+
throw new CliError2(`Rig server rejected project-root scope ${projectRoot}: ${String(record.message ?? record.error ?? "unknown error")}`, 1);
|
|
3127
3153
|
}
|
|
3128
3154
|
async function listRunsViaServer(context, options = {}) {
|
|
3129
3155
|
const url = new URL("http://rig.local/api/runs");
|
|
@@ -3255,6 +3281,8 @@ async function buildRunPiEventsWebSocketUrl(context, runId) {
|
|
|
3255
3281
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
3256
3282
|
if (server.authToken)
|
|
3257
3283
|
url.searchParams.set("token", server.authToken);
|
|
3284
|
+
if (server.serverProjectRoot)
|
|
3285
|
+
url.searchParams.set("rigProjectRoot", server.serverProjectRoot);
|
|
3258
3286
|
return url.toString();
|
|
3259
3287
|
}
|
|
3260
3288
|
async function submitTaskRunViaServer(context, input) {
|
|
@@ -90,7 +90,8 @@ function readRepoConnection(projectRoot) {
|
|
|
90
90
|
return {
|
|
91
91
|
selected,
|
|
92
92
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
93
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
93
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
94
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
94
95
|
};
|
|
95
96
|
}
|
|
96
97
|
function writeRepoConnection(projectRoot, state) {
|
|
@@ -101,15 +102,22 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
101
102
|
if (!repo)
|
|
102
103
|
return null;
|
|
103
104
|
if (repo.selected === "local")
|
|
104
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
105
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
105
106
|
const global = readGlobalConnections(options);
|
|
106
107
|
const connection = global.connections[repo.selected];
|
|
107
108
|
if (!connection) {
|
|
108
109
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
109
110
|
}
|
|
110
|
-
return { alias: repo.selected, connection };
|
|
111
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
112
|
+
}
|
|
113
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
114
|
+
const repo = readRepoConnection(projectRoot);
|
|
115
|
+
if (!repo)
|
|
116
|
+
return;
|
|
117
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
111
118
|
}
|
|
112
119
|
export {
|
|
120
|
+
writeRepoServerProjectRoot,
|
|
113
121
|
writeRepoConnection,
|
|
114
122
|
writeGlobalConnections,
|
|
115
123
|
upsertGlobalConnection,
|
|
@@ -40,6 +40,11 @@ function readJsonFile(path) {
|
|
|
40
40
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
function writeJsonFile(path, value) {
|
|
44
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
45
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
46
|
+
`, "utf8");
|
|
47
|
+
}
|
|
43
48
|
function normalizeConnection(value) {
|
|
44
49
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
45
50
|
return null;
|
|
@@ -80,21 +85,31 @@ function readRepoConnection(projectRoot) {
|
|
|
80
85
|
return {
|
|
81
86
|
selected,
|
|
82
87
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
83
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
88
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
89
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
84
90
|
};
|
|
85
91
|
}
|
|
92
|
+
function writeRepoConnection(projectRoot, state) {
|
|
93
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
94
|
+
}
|
|
86
95
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
87
96
|
const repo = readRepoConnection(projectRoot);
|
|
88
97
|
if (!repo)
|
|
89
98
|
return null;
|
|
90
99
|
if (repo.selected === "local")
|
|
91
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
100
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
92
101
|
const global = readGlobalConnections(options);
|
|
93
102
|
const connection = global.connections[repo.selected];
|
|
94
103
|
if (!connection) {
|
|
95
104
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
96
105
|
}
|
|
97
|
-
return { alias: repo.selected, connection };
|
|
106
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
107
|
+
}
|
|
108
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
109
|
+
const repo = readRepoConnection(projectRoot);
|
|
110
|
+
if (!repo)
|
|
111
|
+
return;
|
|
112
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -130,17 +145,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
130
145
|
try {
|
|
131
146
|
const selected = resolveSelectedConnection(projectRoot);
|
|
132
147
|
if (selected?.connection.kind === "remote") {
|
|
148
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
149
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
133
150
|
return {
|
|
134
151
|
baseUrl: selected.connection.baseUrl,
|
|
135
|
-
authToken
|
|
136
|
-
connectionKind: "remote"
|
|
152
|
+
authToken,
|
|
153
|
+
connectionKind: "remote",
|
|
154
|
+
serverProjectRoot
|
|
137
155
|
};
|
|
138
156
|
}
|
|
139
157
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
140
158
|
return {
|
|
141
159
|
baseUrl: connection.baseUrl,
|
|
142
160
|
authToken: connection.authToken,
|
|
143
|
-
connectionKind: "local"
|
|
161
|
+
connectionKind: "local",
|
|
162
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
144
163
|
};
|
|
145
164
|
} catch (error) {
|
|
146
165
|
if (error instanceof Error) {
|
|
@@ -149,6 +168,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
149
168
|
throw error;
|
|
150
169
|
}
|
|
151
170
|
}
|
|
171
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
172
|
+
const repo = readRepoConnection(projectRoot);
|
|
173
|
+
const slug = repo?.project?.trim();
|
|
174
|
+
if (!slug)
|
|
175
|
+
return null;
|
|
176
|
+
try {
|
|
177
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
178
|
+
headers: mergeHeaders(undefined, authToken)
|
|
179
|
+
});
|
|
180
|
+
if (!response.ok)
|
|
181
|
+
return null;
|
|
182
|
+
const payload = await response.json();
|
|
183
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
184
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
185
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
186
|
+
if (path)
|
|
187
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
188
|
+
return path;
|
|
189
|
+
} catch {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
152
193
|
function mergeHeaders(headers, authToken) {
|
|
153
194
|
const merged = new Headers(headers);
|
|
154
195
|
if (authToken) {
|
|
@@ -173,9 +214,12 @@ function diagnosticMessage(payload) {
|
|
|
173
214
|
}
|
|
174
215
|
async function requestServerJson(context, pathname, init = {}) {
|
|
175
216
|
const server = await ensureServerForCli(context.projectRoot);
|
|
217
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
218
|
+
if (server.serverProjectRoot)
|
|
219
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
176
220
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
177
221
|
...init,
|
|
178
|
-
headers
|
|
222
|
+
headers
|
|
179
223
|
});
|
|
180
224
|
const text = await response.text();
|
|
181
225
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -38,6 +38,11 @@ function readJsonFile(path) {
|
|
|
38
38
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
function writeJsonFile(path, value) {
|
|
42
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
43
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
44
|
+
`, "utf8");
|
|
45
|
+
}
|
|
41
46
|
function normalizeConnection(value) {
|
|
42
47
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
43
48
|
return null;
|
|
@@ -78,21 +83,31 @@ function readRepoConnection(projectRoot) {
|
|
|
78
83
|
return {
|
|
79
84
|
selected,
|
|
80
85
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
81
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
86
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
87
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
82
88
|
};
|
|
83
89
|
}
|
|
90
|
+
function writeRepoConnection(projectRoot, state) {
|
|
91
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
92
|
+
}
|
|
84
93
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
85
94
|
const repo = readRepoConnection(projectRoot);
|
|
86
95
|
if (!repo)
|
|
87
96
|
return null;
|
|
88
97
|
if (repo.selected === "local")
|
|
89
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
98
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
90
99
|
const global = readGlobalConnections(options);
|
|
91
100
|
const connection = global.connections[repo.selected];
|
|
92
101
|
if (!connection) {
|
|
93
102
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
94
103
|
}
|
|
95
|
-
return { alias: repo.selected, connection };
|
|
104
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
105
|
+
}
|
|
106
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
107
|
+
const repo = readRepoConnection(projectRoot);
|
|
108
|
+
if (!repo)
|
|
109
|
+
return;
|
|
110
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
96
111
|
}
|
|
97
112
|
|
|
98
113
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -125,17 +140,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
125
140
|
try {
|
|
126
141
|
const selected = resolveSelectedConnection(projectRoot);
|
|
127
142
|
if (selected?.connection.kind === "remote") {
|
|
143
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
144
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
128
145
|
return {
|
|
129
146
|
baseUrl: selected.connection.baseUrl,
|
|
130
|
-
authToken
|
|
131
|
-
connectionKind: "remote"
|
|
147
|
+
authToken,
|
|
148
|
+
connectionKind: "remote",
|
|
149
|
+
serverProjectRoot
|
|
132
150
|
};
|
|
133
151
|
}
|
|
134
152
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
135
153
|
return {
|
|
136
154
|
baseUrl: connection.baseUrl,
|
|
137
155
|
authToken: connection.authToken,
|
|
138
|
-
connectionKind: "local"
|
|
156
|
+
connectionKind: "local",
|
|
157
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
139
158
|
};
|
|
140
159
|
} catch (error) {
|
|
141
160
|
if (error instanceof Error) {
|
|
@@ -144,6 +163,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
144
163
|
throw error;
|
|
145
164
|
}
|
|
146
165
|
}
|
|
166
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
167
|
+
const repo = readRepoConnection(projectRoot);
|
|
168
|
+
const slug = repo?.project?.trim();
|
|
169
|
+
if (!slug)
|
|
170
|
+
return null;
|
|
171
|
+
try {
|
|
172
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
173
|
+
headers: mergeHeaders(undefined, authToken)
|
|
174
|
+
});
|
|
175
|
+
if (!response.ok)
|
|
176
|
+
return null;
|
|
177
|
+
const payload = await response.json();
|
|
178
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
179
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
180
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
181
|
+
if (path)
|
|
182
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
183
|
+
return path;
|
|
184
|
+
} catch {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
147
188
|
function mergeHeaders(headers, authToken) {
|
|
148
189
|
const merged = new Headers(headers);
|
|
149
190
|
if (authToken) {
|
|
@@ -168,9 +209,12 @@ function diagnosticMessage(payload) {
|
|
|
168
209
|
}
|
|
169
210
|
async function requestServerJson(context, pathname, init = {}) {
|
|
170
211
|
const server = await ensureServerForCli(context.projectRoot);
|
|
212
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
213
|
+
if (server.serverProjectRoot)
|
|
214
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
171
215
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
172
216
|
...init,
|
|
173
|
-
headers
|
|
217
|
+
headers
|
|
174
218
|
});
|
|
175
219
|
const text = await response.text();
|
|
176
220
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -287,6 +331,8 @@ async function buildRunPiEventsWebSocketUrl(context, runId) {
|
|
|
287
331
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
288
332
|
if (server.authToken)
|
|
289
333
|
url.searchParams.set("token", server.authToken);
|
|
334
|
+
if (server.serverProjectRoot)
|
|
335
|
+
url.searchParams.set("rigProjectRoot", server.serverProjectRoot);
|
|
290
336
|
return url.toString();
|
|
291
337
|
}
|
|
292
338
|
|
|
@@ -48,6 +48,11 @@ function readJsonFile(path) {
|
|
|
48
48
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
function writeJsonFile(path, value) {
|
|
52
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
53
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
54
|
+
`, "utf8");
|
|
55
|
+
}
|
|
51
56
|
function normalizeConnection(value) {
|
|
52
57
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
53
58
|
return null;
|
|
@@ -88,21 +93,31 @@ function readRepoConnection(projectRoot) {
|
|
|
88
93
|
return {
|
|
89
94
|
selected,
|
|
90
95
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
91
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
96
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
97
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
92
98
|
};
|
|
93
99
|
}
|
|
100
|
+
function writeRepoConnection(projectRoot, state) {
|
|
101
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
102
|
+
}
|
|
94
103
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
95
104
|
const repo = readRepoConnection(projectRoot);
|
|
96
105
|
if (!repo)
|
|
97
106
|
return null;
|
|
98
107
|
if (repo.selected === "local")
|
|
99
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
108
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
100
109
|
const global = readGlobalConnections(options);
|
|
101
110
|
const connection = global.connections[repo.selected];
|
|
102
111
|
if (!connection) {
|
|
103
112
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
104
113
|
}
|
|
105
|
-
return { alias: repo.selected, connection };
|
|
114
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
115
|
+
}
|
|
116
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
117
|
+
const repo = readRepoConnection(projectRoot);
|
|
118
|
+
if (!repo)
|
|
119
|
+
return;
|
|
120
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
106
121
|
}
|
|
107
122
|
|
|
108
123
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -135,17 +150,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
135
150
|
try {
|
|
136
151
|
const selected = resolveSelectedConnection(projectRoot);
|
|
137
152
|
if (selected?.connection.kind === "remote") {
|
|
153
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
154
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
138
155
|
return {
|
|
139
156
|
baseUrl: selected.connection.baseUrl,
|
|
140
|
-
authToken
|
|
141
|
-
connectionKind: "remote"
|
|
157
|
+
authToken,
|
|
158
|
+
connectionKind: "remote",
|
|
159
|
+
serverProjectRoot
|
|
142
160
|
};
|
|
143
161
|
}
|
|
144
162
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
145
163
|
return {
|
|
146
164
|
baseUrl: connection.baseUrl,
|
|
147
165
|
authToken: connection.authToken,
|
|
148
|
-
connectionKind: "local"
|
|
166
|
+
connectionKind: "local",
|
|
167
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
149
168
|
};
|
|
150
169
|
} catch (error) {
|
|
151
170
|
if (error instanceof Error) {
|
|
@@ -154,6 +173,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
154
173
|
throw error;
|
|
155
174
|
}
|
|
156
175
|
}
|
|
176
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
177
|
+
const repo = readRepoConnection(projectRoot);
|
|
178
|
+
const slug = repo?.project?.trim();
|
|
179
|
+
if (!slug)
|
|
180
|
+
return null;
|
|
181
|
+
try {
|
|
182
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
183
|
+
headers: mergeHeaders(undefined, authToken)
|
|
184
|
+
});
|
|
185
|
+
if (!response.ok)
|
|
186
|
+
return null;
|
|
187
|
+
const payload = await response.json();
|
|
188
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
189
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
190
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
191
|
+
if (path)
|
|
192
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
193
|
+
return path;
|
|
194
|
+
} catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
157
198
|
function mergeHeaders(headers, authToken) {
|
|
158
199
|
const merged = new Headers(headers);
|
|
159
200
|
if (authToken) {
|
|
@@ -178,9 +219,12 @@ function diagnosticMessage(payload) {
|
|
|
178
219
|
}
|
|
179
220
|
async function requestServerJson(context, pathname, init = {}) {
|
|
180
221
|
const server = await ensureServerForCli(context.projectRoot);
|
|
222
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
223
|
+
if (server.serverProjectRoot)
|
|
224
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
181
225
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
182
226
|
...init,
|
|
183
|
-
headers
|
|
227
|
+
headers
|
|
184
228
|
});
|
|
185
229
|
const text = await response.text();
|
|
186
230
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -263,6 +307,8 @@ async function buildRunPiEventsWebSocketUrl(context, runId) {
|
|
|
263
307
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
264
308
|
if (server.authToken)
|
|
265
309
|
url.searchParams.set("token", server.authToken);
|
|
310
|
+
if (server.serverProjectRoot)
|
|
311
|
+
url.searchParams.set("rigProjectRoot", server.serverProjectRoot);
|
|
266
312
|
return url.toString();
|
|
267
313
|
}
|
|
268
314
|
|
|
@@ -41,6 +41,11 @@ function readJsonFile(path) {
|
|
|
41
41
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
function writeJsonFile(path, value) {
|
|
45
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
46
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
47
|
+
`, "utf8");
|
|
48
|
+
}
|
|
44
49
|
function normalizeConnection(value) {
|
|
45
50
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
46
51
|
return null;
|
|
@@ -81,21 +86,31 @@ function readRepoConnection(projectRoot) {
|
|
|
81
86
|
return {
|
|
82
87
|
selected,
|
|
83
88
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
84
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
89
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
90
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
85
91
|
};
|
|
86
92
|
}
|
|
93
|
+
function writeRepoConnection(projectRoot, state) {
|
|
94
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
95
|
+
}
|
|
87
96
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
88
97
|
const repo = readRepoConnection(projectRoot);
|
|
89
98
|
if (!repo)
|
|
90
99
|
return null;
|
|
91
100
|
if (repo.selected === "local")
|
|
92
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
101
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
93
102
|
const global = readGlobalConnections(options);
|
|
94
103
|
const connection = global.connections[repo.selected];
|
|
95
104
|
if (!connection) {
|
|
96
105
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
97
106
|
}
|
|
98
|
-
return { alias: repo.selected, connection };
|
|
107
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
108
|
+
}
|
|
109
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
110
|
+
const repo = readRepoConnection(projectRoot);
|
|
111
|
+
if (!repo)
|
|
112
|
+
return;
|
|
113
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -128,17 +143,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
128
143
|
try {
|
|
129
144
|
const selected = resolveSelectedConnection(projectRoot);
|
|
130
145
|
if (selected?.connection.kind === "remote") {
|
|
146
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
147
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
131
148
|
return {
|
|
132
149
|
baseUrl: selected.connection.baseUrl,
|
|
133
|
-
authToken
|
|
134
|
-
connectionKind: "remote"
|
|
150
|
+
authToken,
|
|
151
|
+
connectionKind: "remote",
|
|
152
|
+
serverProjectRoot
|
|
135
153
|
};
|
|
136
154
|
}
|
|
137
155
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
138
156
|
return {
|
|
139
157
|
baseUrl: connection.baseUrl,
|
|
140
158
|
authToken: connection.authToken,
|
|
141
|
-
connectionKind: "local"
|
|
159
|
+
connectionKind: "local",
|
|
160
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
142
161
|
};
|
|
143
162
|
} catch (error) {
|
|
144
163
|
if (error instanceof Error) {
|
|
@@ -147,6 +166,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
147
166
|
throw error;
|
|
148
167
|
}
|
|
149
168
|
}
|
|
169
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
170
|
+
const repo = readRepoConnection(projectRoot);
|
|
171
|
+
const slug = repo?.project?.trim();
|
|
172
|
+
if (!slug)
|
|
173
|
+
return null;
|
|
174
|
+
try {
|
|
175
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
176
|
+
headers: mergeHeaders(undefined, authToken)
|
|
177
|
+
});
|
|
178
|
+
if (!response.ok)
|
|
179
|
+
return null;
|
|
180
|
+
const payload = await response.json();
|
|
181
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
182
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
183
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
184
|
+
if (path)
|
|
185
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
186
|
+
return path;
|
|
187
|
+
} catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
150
191
|
function mergeHeaders(headers, authToken) {
|
|
151
192
|
const merged = new Headers(headers);
|
|
152
193
|
if (authToken) {
|
|
@@ -171,9 +212,12 @@ function diagnosticMessage(payload) {
|
|
|
171
212
|
}
|
|
172
213
|
async function requestServerJson(context, pathname, init = {}) {
|
|
173
214
|
const server = await ensureServerForCli(context.projectRoot);
|
|
215
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
216
|
+
if (server.serverProjectRoot)
|
|
217
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
174
218
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
175
219
|
...init,
|
|
176
|
-
headers
|
|
220
|
+
headers
|
|
177
221
|
});
|
|
178
222
|
const text = await response.text();
|
|
179
223
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -244,6 +288,8 @@ async function buildRunPiEventsWebSocketUrl(context, runId) {
|
|
|
244
288
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
245
289
|
if (server.authToken)
|
|
246
290
|
url.searchParams.set("token", server.authToken);
|
|
291
|
+
if (server.serverProjectRoot)
|
|
292
|
+
url.searchParams.set("rigProjectRoot", server.serverProjectRoot);
|
|
247
293
|
return url.toString();
|
|
248
294
|
}
|
|
249
295
|
|