iterate 0.2.3 → 0.2.5
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/bin/iterate.js +31 -576
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +430 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +20 -5
package/bin/iterate.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// @ts-check
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { homedir } from "node:os";
|
|
3
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
7
4
|
import { dirname, join, resolve } from "node:path";
|
|
8
5
|
import process from "node:process";
|
|
9
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -28,23 +25,28 @@ const findUp = (relativePath, startDir = process.cwd()) => {
|
|
|
28
25
|
};
|
|
29
26
|
|
|
30
27
|
const __filename = fileURLToPath(import.meta.url);
|
|
28
|
+
const __dirname = dirname(__filename);
|
|
29
|
+
const pkgRoot = dirname(__dirname);
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* Find a local version of the iterate CLI that differs from the currently
|
|
33
|
+
* running script. Returns an importable module path, or null.
|
|
34
|
+
* @returns {string | null}
|
|
35
35
|
*/
|
|
36
|
-
const
|
|
37
|
-
if (process.env.__ITERATE_CLI_DELEGATED) return;
|
|
38
|
-
|
|
36
|
+
const findLocalModule = () => {
|
|
39
37
|
const selfReal = realpathSync(__filename);
|
|
40
38
|
|
|
41
39
|
// 1. Check if we're inside the iterate repo (has pnpm-workspace.yaml at root)
|
|
42
40
|
const repoRoot = findUp("pnpm-workspace.yaml");
|
|
43
41
|
if (repoRoot) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
const repoPkg = join(repoRoot, "packages/iterate");
|
|
43
|
+
const repoBin = join(repoPkg, "bin/iterate.js");
|
|
44
|
+
if (existsSync(repoBin) && realpathSync(repoBin) !== selfReal) {
|
|
45
|
+
// Prefer TS source in monorepo dev, fall back to dist
|
|
46
|
+
const repoSrc = join(repoPkg, "src/index.ts");
|
|
47
|
+
if (existsSync(repoSrc)) return repoSrc;
|
|
48
|
+
const repoDist = join(repoPkg, "dist/index.js");
|
|
49
|
+
if (existsSync(repoDist)) return repoDist;
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -53,572 +55,25 @@ const delegateToLocal = () => {
|
|
|
53
55
|
if (nmRoot) {
|
|
54
56
|
const nmScript = join(nmRoot, "node_modules/.bin/iterate");
|
|
55
57
|
if (existsSync(nmScript) && realpathSync(nmScript) !== selfReal) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
// Published package — use dist
|
|
59
|
+
const nmDist = join(nmRoot, "node_modules/iterate/dist/index.js");
|
|
60
|
+
if (existsSync(nmDist)) return nmDist;
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Re-exec into `scriptPath` with the same argv, never returning.
|
|
64
|
-
* @param {string} scriptPath
|
|
65
|
-
*/
|
|
66
|
-
const reExec = (scriptPath) => {
|
|
67
|
-
try {
|
|
68
|
-
execFileSync(process.execPath, [scriptPath, ...process.argv.slice(2)], {
|
|
69
|
-
stdio: "inherit",
|
|
70
|
-
env: { ...process.env, __ITERATE_CLI_DELEGATED: "1" },
|
|
71
|
-
});
|
|
72
|
-
} catch (e) {
|
|
73
|
-
process.exit(e && typeof e === "object" && "status" in e ? Number(e.status) || 1 : 1);
|
|
74
|
-
}
|
|
75
|
-
process.exit(0);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
delegateToLocal();
|
|
79
|
-
|
|
80
|
-
// --- Normal CLI startup (dynamic imports so delegation can short-circuit first) ---
|
|
81
|
-
|
|
82
|
-
const prompts = await import("@clack/prompts");
|
|
83
|
-
const { createTRPCClient, httpLink } = await import("@trpc/client");
|
|
84
|
-
const { initTRPC } = await import("@trpc/server");
|
|
85
|
-
const { createAuthClient } = await import("better-auth/client");
|
|
86
|
-
const { adminClient } = await import("better-auth/client/plugins");
|
|
87
|
-
const { default: superjson } = await import("superjson");
|
|
88
|
-
const { createCli } = await import("trpc-cli");
|
|
89
|
-
const { proxify } = await import("trpc-cli/dist/proxify.js");
|
|
90
|
-
const { z } = await import("zod/v4");
|
|
91
|
-
|
|
92
|
-
const XDG_CONFIG_PARENT = join(
|
|
93
|
-
process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join(homedir(), ".config"),
|
|
94
|
-
"iterate",
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const XDG_CONFIG_PATH = join(XDG_CONFIG_PARENT, "config.json");
|
|
98
|
-
const CONFIG_PATH = XDG_CONFIG_PATH;
|
|
99
|
-
// todo write json schema to file too - need to make everything zod first
|
|
100
|
-
// const CONFIG_SCHEMA_PATH = join(XDG_CONFIG_PARENT, "config-schema.json");
|
|
101
|
-
|
|
102
|
-
const SetupInput = z.object({
|
|
103
|
-
osBaseUrl: z
|
|
104
|
-
.string()
|
|
105
|
-
.describe(`Base URL for OS API (for example https://dev-yourname-os.dev.iterate.com)`),
|
|
106
|
-
daemonBaseUrl: z.string().describe(`Base URL for daemon API (for example http://localhost:3001)`),
|
|
107
|
-
adminPasswordEnvVarName: z.string().describe("Env var name containing admin password"),
|
|
108
|
-
userEmail: z.string().describe("User email to impersonate for OS calls"),
|
|
109
|
-
scope: z.enum(["workspace", "global"]).describe("Where to store launcher config"),
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const AuthConfig = z.object({
|
|
113
|
-
osBaseUrl: z.string(),
|
|
114
|
-
daemonBaseUrl: z.string(),
|
|
115
|
-
adminPasswordEnvVarName: z.string(),
|
|
116
|
-
userEmail: z.string(),
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const ConfigFile = z.object({
|
|
120
|
-
global: AuthConfig.partial().optional(),
|
|
121
|
-
workspaces: z.record(z.string(), AuthConfig).optional(),
|
|
122
|
-
/** a place where I put old/invalid configs I can't quite let go of */
|
|
123
|
-
rubbish: z.unknown().optional(),
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
/** @typedef {import('zod').infer<typeof AuthConfig>} AuthConfig */
|
|
127
|
-
/** @typedef {import('zod').infer<typeof ConfigFile>} ConfigFile */
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* @typedef {{
|
|
131
|
-
* command: string;
|
|
132
|
-
* args: string[];
|
|
133
|
-
* cwd?: string;
|
|
134
|
-
* env?: Record<string, string | undefined>;
|
|
135
|
-
* }} SpawnOptions
|
|
136
|
-
*/
|
|
137
|
-
|
|
138
|
-
const isAgent =
|
|
139
|
-
process.env.AGENT === "1" ||
|
|
140
|
-
process.env.OPENCODE === "1" ||
|
|
141
|
-
Boolean(process.env.OPENCODE_SESSION) ||
|
|
142
|
-
Boolean(process.env.CLAUDE_CODE);
|
|
143
|
-
|
|
144
|
-
const t = initTRPC.meta().create();
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* @param {unknown} value
|
|
148
|
-
* @returns {value is Record<string, unknown>}
|
|
149
|
-
*/
|
|
150
|
-
const isObject = (value) => {
|
|
151
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
/** @returns {ConfigFile} */
|
|
155
|
-
const readConfigFile = () => {
|
|
156
|
-
if (!existsSync(CONFIG_PATH)) {
|
|
157
|
-
return {};
|
|
158
|
-
}
|
|
159
|
-
const rawText = readFileSync(CONFIG_PATH, "utf8");
|
|
160
|
-
let parsed;
|
|
161
|
-
try {
|
|
162
|
-
parsed = JSON.parse(rawText);
|
|
163
|
-
} catch (error) {
|
|
164
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
165
|
-
throw new Error(`Invalid JSON in ${CONFIG_PATH}: ${detail}`);
|
|
166
|
-
}
|
|
167
63
|
|
|
168
|
-
return
|
|
64
|
+
return null;
|
|
169
65
|
};
|
|
170
66
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
*/
|
|
175
|
-
const getWorkspaceConfig = (configFile, workspacePath) => {
|
|
176
|
-
const workspaces = isObject(configFile.workspaces) ? configFile.workspaces : {};
|
|
177
|
-
const rawWorkspaceConfig = workspaces[workspacePath];
|
|
178
|
-
return isObject(rawWorkspaceConfig) ? rawWorkspaceConfig : {};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* @param {ConfigFile} configFile
|
|
183
|
-
* @param {string} workspacePath
|
|
184
|
-
*/
|
|
185
|
-
const getMergedWorkspaceConfig = (configFile, workspacePath) => {
|
|
186
|
-
return {
|
|
187
|
-
...configFile.global,
|
|
188
|
-
...getWorkspaceConfig(configFile, workspacePath),
|
|
189
|
-
};
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* @param {{ patch?: Partial<AuthConfig>; scope: "workspace" | "global"; workspacePath: string; }} options
|
|
194
|
-
* @returns {ConfigFile}
|
|
195
|
-
*/
|
|
196
|
-
const writeNewConfig = ({ patch, scope, workspacePath }) => {
|
|
197
|
-
patch = Object.fromEntries(
|
|
198
|
-
Object.entries(patch || {}).filter(([_key, value]) => value !== undefined),
|
|
199
|
-
);
|
|
200
|
-
const configFile = readConfigFile();
|
|
201
|
-
const cloned = structuredClone(configFile);
|
|
202
|
-
|
|
203
|
-
if (scope === "global") {
|
|
204
|
-
cloned.global = { ...configFile.global, ...patch };
|
|
205
|
-
}
|
|
206
|
-
if (scope === "workspace" && workspacePath) {
|
|
207
|
-
cloned.workspaces ||= {};
|
|
208
|
-
// @ts-expect-error - we know it's a string
|
|
209
|
-
cloned.workspaces[workspacePath] = {
|
|
210
|
-
...configFile.workspaces?.[workspacePath],
|
|
211
|
-
...patch,
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const parsed = ConfigFile.safeParse(cloned);
|
|
216
|
-
if (!parsed.success) {
|
|
217
|
-
throw new Error(`Invalid config file: ${z.prettifyError(parsed.error)}`);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
221
|
-
writeFileSync(CONFIG_PATH, `${JSON.stringify(parsed.data, null, 2)}\n`);
|
|
222
|
-
return cloned;
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
/** @param {string} workspacePath */
|
|
226
|
-
const readAuthConfig = (workspacePath) => {
|
|
227
|
-
const configFile = readConfigFile();
|
|
228
|
-
const mergedConfig = getMergedWorkspaceConfig(configFile, workspacePath);
|
|
229
|
-
const parsed = AuthConfig.safeParse(mergedConfig);
|
|
230
|
-
if (!parsed.success) {
|
|
231
|
-
return new Error(
|
|
232
|
-
`Invalid auth config for ${workspacePath} (in config file ${CONFIG_PATH}). Have you run \`iterate setup\`?\n${z.prettifyError(parsed.error)}`,
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
return parsed.data;
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
/** @param {string[] | undefined} setCookies */
|
|
239
|
-
const setCookiesToCookieHeader = (setCookies) => {
|
|
240
|
-
const byName = new Map();
|
|
241
|
-
for (const c of setCookies ?? []) {
|
|
242
|
-
const pair = c.split(";")[0]?.trim();
|
|
243
|
-
if (!pair) continue;
|
|
244
|
-
const eq = pair.indexOf("=");
|
|
245
|
-
if (eq === -1) continue;
|
|
246
|
-
byName.set(pair.slice(0, eq), pair.slice(eq + 1));
|
|
247
|
-
}
|
|
248
|
-
return [...byName.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
const impersonationUserIdCache = new Map();
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* @param {{
|
|
255
|
-
* superadminAuthClient: any;
|
|
256
|
-
* userEmail: string;
|
|
257
|
-
* baseUrl: string;
|
|
258
|
-
* }} options
|
|
259
|
-
*/
|
|
260
|
-
const resolveImpersonationUserId = async ({ superadminAuthClient, userEmail, baseUrl }) => {
|
|
261
|
-
const normalizedEmail = userEmail.trim().toLowerCase();
|
|
262
|
-
const cacheKey = `${baseUrl}::${normalizedEmail}`;
|
|
263
|
-
const cachedUserId = impersonationUserIdCache.get(cacheKey);
|
|
264
|
-
if (cachedUserId) {
|
|
265
|
-
return cachedUserId;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/** @type {any[]} */
|
|
269
|
-
let users = [];
|
|
270
|
-
|
|
271
|
-
try {
|
|
272
|
-
const result = await superadminAuthClient.admin.listUsers({
|
|
273
|
-
query: {
|
|
274
|
-
filterField: "email",
|
|
275
|
-
filterOperator: "eq",
|
|
276
|
-
filterValue: normalizedEmail,
|
|
277
|
-
limit: 10,
|
|
278
|
-
},
|
|
279
|
-
fetchOptions: {
|
|
280
|
-
throw: true,
|
|
281
|
-
},
|
|
282
|
-
});
|
|
283
|
-
users = Array.isArray(result?.users) ? result.users : [];
|
|
284
|
-
} catch {
|
|
285
|
-
const result = await superadminAuthClient.admin.listUsers({
|
|
286
|
-
query: {
|
|
287
|
-
searchField: "email",
|
|
288
|
-
searchOperator: "contains",
|
|
289
|
-
searchValue: normalizedEmail,
|
|
290
|
-
limit: 100,
|
|
291
|
-
},
|
|
292
|
-
fetchOptions: {
|
|
293
|
-
throw: true,
|
|
294
|
-
},
|
|
295
|
-
});
|
|
296
|
-
users = Array.isArray(result?.users) ? result.users : [];
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const exactMatches = users.filter(
|
|
300
|
-
(user) =>
|
|
301
|
-
user &&
|
|
302
|
-
typeof user === "object" &&
|
|
303
|
-
"email" in user &&
|
|
304
|
-
typeof user.email === "string" &&
|
|
305
|
-
user.email.toLowerCase() === normalizedEmail &&
|
|
306
|
-
"id" in user &&
|
|
307
|
-
typeof user.id === "string",
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
if (exactMatches.length === 0) {
|
|
311
|
-
throw new Error(`No user found with email ${userEmail}`);
|
|
312
|
-
}
|
|
313
|
-
if (exactMatches.length > 1) {
|
|
314
|
-
throw new Error(`Multiple users found with email ${userEmail}`);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const resolvedUserId = exactMatches[0].id;
|
|
318
|
-
impersonationUserIdCache.set(cacheKey, resolvedUserId);
|
|
319
|
-
return resolvedUserId;
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
/** @param {import('zod').infer<typeof AuthConfig>} authConfig */
|
|
323
|
-
const osAuthDance = async (authConfig) => {
|
|
324
|
-
/** @type {string[] | undefined} */
|
|
325
|
-
let superadminSetCookie;
|
|
326
|
-
const authClient = createAuthClient({
|
|
327
|
-
baseURL: authConfig.osBaseUrl,
|
|
328
|
-
fetchOptions: {
|
|
329
|
-
throw: true,
|
|
330
|
-
},
|
|
331
|
-
});
|
|
332
|
-
const password = process.env[authConfig.adminPasswordEnvVarName];
|
|
333
|
-
if (!password) {
|
|
334
|
-
throw new Error(`Password not found in env var ${authConfig.adminPasswordEnvVarName}`);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
await authClient.signIn.email({
|
|
338
|
-
email: "superadmin@nustom.com",
|
|
339
|
-
password,
|
|
340
|
-
fetchOptions: {
|
|
341
|
-
throw: true,
|
|
342
|
-
onResponse: (ctx) => {
|
|
343
|
-
superadminSetCookie = ctx.response.headers.getSetCookie();
|
|
344
|
-
},
|
|
345
|
-
},
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
const superadminAuthClient = createAuthClient({
|
|
349
|
-
baseURL: authConfig.osBaseUrl,
|
|
350
|
-
fetchOptions: {
|
|
351
|
-
throw: true,
|
|
352
|
-
onRequest: (ctx) => {
|
|
353
|
-
ctx.headers.set("origin", authConfig.osBaseUrl);
|
|
354
|
-
ctx.headers.set("cookie", setCookiesToCookieHeader(superadminSetCookie));
|
|
355
|
-
},
|
|
356
|
-
},
|
|
357
|
-
plugins: [adminClient()],
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
const userId = await resolveImpersonationUserId({
|
|
361
|
-
superadminAuthClient,
|
|
362
|
-
userEmail: authConfig.userEmail,
|
|
363
|
-
baseUrl: authConfig.osBaseUrl,
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
let impersonateSetCookie;
|
|
367
|
-
await superadminAuthClient.admin.impersonateUser({
|
|
368
|
-
userId,
|
|
369
|
-
fetchOptions: {
|
|
370
|
-
throw: true,
|
|
371
|
-
onResponse: (ctx) => {
|
|
372
|
-
impersonateSetCookie = ctx.response.headers.getSetCookie();
|
|
373
|
-
},
|
|
374
|
-
},
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
const userCookies = setCookiesToCookieHeader(impersonateSetCookie);
|
|
378
|
-
|
|
379
|
-
const userClient = createAuthClient({
|
|
380
|
-
baseURL: authConfig.osBaseUrl,
|
|
381
|
-
fetchOptions: {
|
|
382
|
-
throw: true,
|
|
383
|
-
onRequest: (ctx) => {
|
|
384
|
-
ctx.headers.set("origin", authConfig.osBaseUrl);
|
|
385
|
-
ctx.headers.set("cookie", userCookies);
|
|
386
|
-
},
|
|
387
|
-
},
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
return { userCookies, userClient };
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
/** @param {{baseUrl: string}} params */
|
|
394
|
-
const loadAppRouter = async (params) => {
|
|
395
|
-
const url = `${params.baseUrl}/api/trpc-cli-procedures`;
|
|
396
|
-
const response = await fetch(url);
|
|
397
|
-
if (!response.ok) {
|
|
398
|
-
throw new Error(`${url} got ${response.status}: ${await response.text()}`);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const router = await response.json().catch((e) => {
|
|
402
|
-
throw new Error(`${url} returned invalid router: ${e.message}`);
|
|
403
|
-
});
|
|
404
|
-
if (!Array.isArray(router?.procedures)) {
|
|
405
|
-
throw new Error(`${url} returned invalid router: ${JSON.stringify(router)}`);
|
|
406
|
-
}
|
|
407
|
-
/** @type {{procedures: any[]}} */
|
|
408
|
-
return router;
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
/** @param {{ baseUrl: string }} params */
|
|
412
|
-
const getOsProcedures = async (params) => {
|
|
413
|
-
const appRouter = await loadAppRouter(params);
|
|
414
|
-
/** @type {{}} */
|
|
415
|
-
const proxiedRouter = proxify(appRouter.procedures, async () => {
|
|
416
|
-
return createTRPCClient({
|
|
417
|
-
links: [
|
|
418
|
-
httpLink({
|
|
419
|
-
url: `${params.baseUrl}/api/trpc/`,
|
|
420
|
-
transformer: superjson,
|
|
421
|
-
fetch: async (request, init) => {
|
|
422
|
-
const authConfig = readAuthConfig(process.cwd());
|
|
423
|
-
if (authConfig instanceof Error) throw authConfig;
|
|
424
|
-
const { userCookies } = await osAuthDance(authConfig);
|
|
425
|
-
const headers = new Headers(init?.headers);
|
|
426
|
-
headers.set("cookie", userCookies);
|
|
427
|
-
return fetch(request, { ...init, headers });
|
|
428
|
-
},
|
|
429
|
-
}),
|
|
430
|
-
],
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
return proxiedRouter;
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Creates a fetch wrapper that calls /api/trpc-stream/* instead of /api/trpc/*.
|
|
439
|
-
* The streaming endpoint returns SSE: log lines as `event: log` and the final
|
|
440
|
-
* tRPC response as `event: response`, which we reassemble into a normal Response.
|
|
441
|
-
* @param {string} daemonBaseUrl
|
|
442
|
-
* @returns {typeof globalThis.fetch}
|
|
443
|
-
*/
|
|
444
|
-
const streamingFetch = (daemonBaseUrl) => {
|
|
445
|
-
return async (/** @type {any} */ input, /** @type {any} */ init) => {
|
|
446
|
-
// Rewrite URL from /api/trpc/X to /api/trpc-stream/X
|
|
447
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
448
|
-
const rewritten = url.replace(
|
|
449
|
-
`${daemonBaseUrl}/api/trpc/`,
|
|
450
|
-
`${daemonBaseUrl}/api/trpc-stream/`,
|
|
451
|
-
);
|
|
452
|
-
const res = await fetch(rewritten, init);
|
|
453
|
-
if (rewritten === url) return res;
|
|
454
|
-
|
|
455
|
-
const contentType = res.headers.get("content-type") || "";
|
|
456
|
-
// If the daemon didn't respond with SSE, pass through as-is (non-streaming endpoint)
|
|
457
|
-
if (!contentType.includes("text/event-stream")) return res;
|
|
458
|
-
// Parse SSE stream: print log events to stderr, collect the final response
|
|
459
|
-
const reader = res.body?.getReader();
|
|
460
|
-
if (!reader) return res;
|
|
461
|
-
const decoder = new TextDecoder();
|
|
462
|
-
let buffer = "";
|
|
463
|
-
/** @type {string | null} */
|
|
464
|
-
let responseBody = null;
|
|
465
|
-
while (true) {
|
|
466
|
-
const { done, value } = await reader.read();
|
|
467
|
-
if (done) break;
|
|
468
|
-
buffer += decoder.decode(value, { stream: true });
|
|
469
|
-
// Process complete SSE messages (double newline delimited)
|
|
470
|
-
const parts = buffer.split("\n\n");
|
|
471
|
-
buffer = parts.pop() || "";
|
|
472
|
-
for (const part of parts) {
|
|
473
|
-
const lines = part.split("\n");
|
|
474
|
-
const event = lines[0].split(": ")[1];
|
|
475
|
-
const data = lines[1].split(": ").slice(1).join(": ");
|
|
476
|
-
if (event === "log") {
|
|
477
|
-
/** @type {{level: "debug" | "info" | "warn" | "error"; args: unknown[]}} */
|
|
478
|
-
const detail = JSON.parse(data);
|
|
479
|
-
console[detail.level](...detail.args);
|
|
480
|
-
} else if (event === "response") {
|
|
481
|
-
responseBody = data;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
// Reconstruct a normal Response from the final payload so tRPC client is happy
|
|
486
|
-
return new Response(responseBody, {
|
|
487
|
-
status: res.status,
|
|
488
|
-
headers: { "content-type": "application/json" },
|
|
489
|
-
});
|
|
490
|
-
};
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
/** @param {{ daemonBaseUrl: string }} params */
|
|
494
|
-
const getDaemonProcedures = async (params) => {
|
|
495
|
-
const daemonRouter = await loadAppRouter({ baseUrl: params.daemonBaseUrl });
|
|
496
|
-
const proxiedRouter = proxify(daemonRouter.procedures, async () => {
|
|
497
|
-
return createTRPCClient({
|
|
498
|
-
links: [
|
|
499
|
-
httpLink({
|
|
500
|
-
url: `${params.daemonBaseUrl}/api/trpc/`,
|
|
501
|
-
fetch: streamingFetch(params.daemonBaseUrl),
|
|
502
|
-
}),
|
|
503
|
-
],
|
|
504
|
-
});
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
return proxiedRouter;
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
const launcherProcedures = {
|
|
511
|
-
doctor: t.procedure
|
|
512
|
-
.meta({ description: "Show launcher config and resolved runtime options" })
|
|
513
|
-
.mutation(async () => {
|
|
514
|
-
const configFile = readConfigFile();
|
|
515
|
-
const parsed = ConfigFile.safeParse(configFile);
|
|
516
|
-
if (!parsed.success) {
|
|
517
|
-
throw new Error(`Invalid config file ${CONFIG_PATH}: ${z.prettifyError(parsed.error)}`);
|
|
518
|
-
}
|
|
519
|
-
const current = readAuthConfig(process.cwd());
|
|
520
|
-
if (current instanceof Error) throw current;
|
|
521
|
-
return { configPath: CONFIG_PATH, current };
|
|
522
|
-
}),
|
|
523
|
-
setup: t.procedure
|
|
524
|
-
.input(SetupInput.partial())
|
|
525
|
-
.meta({ prompt: true, description: "Configure auth + launcher defaults for current workspace" })
|
|
526
|
-
.mutation(async ({ input }) => {
|
|
527
|
-
writeNewConfig({
|
|
528
|
-
scope: input.scope || "workspace",
|
|
529
|
-
patch: {
|
|
530
|
-
osBaseUrl: input.osBaseUrl,
|
|
531
|
-
daemonBaseUrl: input.daemonBaseUrl,
|
|
532
|
-
adminPasswordEnvVarName: input.adminPasswordEnvVarName,
|
|
533
|
-
userEmail: input.userEmail,
|
|
534
|
-
},
|
|
535
|
-
workspacePath: process.cwd(),
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
const current = readAuthConfig(process.cwd());
|
|
539
|
-
if (current instanceof Error) throw current;
|
|
540
|
-
return { configPath: CONFIG_PATH, current };
|
|
541
|
-
}),
|
|
542
|
-
|
|
543
|
-
whoami: t.procedure.mutation(async () => {
|
|
544
|
-
const authConfig = readAuthConfig(process.cwd());
|
|
545
|
-
if (authConfig instanceof Error) throw authConfig;
|
|
546
|
-
const { userClient } = await osAuthDance(authConfig);
|
|
547
|
-
return await userClient.getSession();
|
|
548
|
-
}),
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
const runCli = async () => {
|
|
552
|
-
const authConfig = readAuthConfig(process.cwd());
|
|
553
|
-
|
|
554
|
-
/** @type {(problem: string) => (e: Error) => {}} */
|
|
555
|
-
const errorProcedure = (problem) => (e) => {
|
|
556
|
-
const message = `${problem}: ${e.message}`;
|
|
557
|
-
return t.procedure.meta({ description: message }).mutation(() => {
|
|
558
|
-
throw new Error(problem, { cause: e });
|
|
559
|
-
});
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
/** @type {import("@trpc/server").AnyRouter[]} */
|
|
563
|
-
const routers = [t.router(launcherProcedures)];
|
|
564
|
-
|
|
565
|
-
if (authConfig instanceof Error) {
|
|
566
|
-
routers.push(
|
|
567
|
-
t.router({
|
|
568
|
-
os: errorProcedure(`Invalid auth config`)(authConfig),
|
|
569
|
-
daemon: errorProcedure(`Invalid auth config`)(authConfig),
|
|
570
|
-
}),
|
|
571
|
-
);
|
|
572
|
-
} else {
|
|
573
|
-
const [osProcedures, daemonProcedures] = await Promise.allSettled([
|
|
574
|
-
getOsProcedures({ baseUrl: authConfig.osBaseUrl }),
|
|
575
|
-
getDaemonProcedures({ daemonBaseUrl: authConfig.daemonBaseUrl }),
|
|
576
|
-
]);
|
|
577
|
-
|
|
578
|
-
if (osProcedures.status === "fulfilled") {
|
|
579
|
-
routers.push(t.router({ os: osProcedures.value }));
|
|
580
|
-
} else {
|
|
581
|
-
routers.push(
|
|
582
|
-
t.router({
|
|
583
|
-
os: errorProcedure(`Couldn't connect to os at ${authConfig.osBaseUrl}`)(
|
|
584
|
-
osProcedures.reason,
|
|
585
|
-
),
|
|
586
|
-
}),
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
|
-
if (daemonProcedures.status === "fulfilled") {
|
|
590
|
-
// don't nest daemon procedures under "daemon"
|
|
591
|
-
routers.push(daemonProcedures.value);
|
|
592
|
-
} else {
|
|
593
|
-
routers.push(
|
|
594
|
-
t.router({
|
|
595
|
-
daemon: errorProcedure(`Couldn't connect to daemon at ${authConfig.daemonBaseUrl}`)(
|
|
596
|
-
daemonProcedures.reason,
|
|
597
|
-
),
|
|
598
|
-
}),
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
const router = t.mergeRouters(...routers);
|
|
604
|
-
|
|
605
|
-
const cli = createCli({
|
|
606
|
-
router,
|
|
607
|
-
name: "iterate",
|
|
608
|
-
version: "0.0.1",
|
|
609
|
-
description: "Iterate CLI",
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
await cli.run({
|
|
613
|
-
prompts: isAgent ? undefined : prompts,
|
|
614
|
-
});
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
const main = async () => {
|
|
67
|
+
const localModule = findLocalModule();
|
|
68
|
+
if (localModule) {
|
|
69
|
+
const { runCli } = await import(localModule);
|
|
618
70
|
await runCli();
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
71
|
+
} else {
|
|
72
|
+
// No delegation — run our own copy.
|
|
73
|
+
// In monorepo dev: src/index.ts exists. Published: dist/index.js exists.
|
|
74
|
+
const srcPath = join(pkgRoot, "src/index.ts");
|
|
75
|
+
const distPath = join(pkgRoot, "dist/index.js");
|
|
76
|
+
const modulePath = existsSync(srcPath) ? srcPath : distPath;
|
|
77
|
+
const { runCli } = await import(modulePath);
|
|
78
|
+
await runCli();
|
|
79
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AA4b1C,eAAO,MAAM,MAAM;;;EA4DlB,CAAC;AAEF,eAAO,MAAM,MAAM,qBAGlB,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import * as prompts from "@clack/prompts";
|
|
6
|
+
import { createTRPCClient, httpLink } from "@trpc/client";
|
|
7
|
+
import { initTRPC } from "@trpc/server";
|
|
8
|
+
import { createAuthClient } from "better-auth/client";
|
|
9
|
+
import { adminClient } from "better-auth/client/plugins";
|
|
10
|
+
import superjson from "superjson";
|
|
11
|
+
import { createCli } from "trpc-cli";
|
|
12
|
+
import { proxify } from "trpc-cli/dist/proxify.js";
|
|
13
|
+
import { z } from "zod/v4";
|
|
14
|
+
const XDG_CONFIG_PARENT = join(process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join(homedir(), ".config"), "iterate");
|
|
15
|
+
const XDG_CONFIG_PATH = join(XDG_CONFIG_PARENT, "config.json");
|
|
16
|
+
const CONFIG_PATH = XDG_CONFIG_PATH;
|
|
17
|
+
const SetupInput = z.object({
|
|
18
|
+
osBaseUrl: z
|
|
19
|
+
.string()
|
|
20
|
+
.describe(`Base URL for OS API (for example https://dev-yourname-os.dev.iterate.com)`),
|
|
21
|
+
daemonBaseUrl: z.string().describe(`Base URL for daemon API (for example http://localhost:3001)`),
|
|
22
|
+
adminPasswordEnvVarName: z.string().describe("Env var name containing admin password"),
|
|
23
|
+
userEmail: z.string().describe("User email to impersonate for OS calls"),
|
|
24
|
+
scope: z.enum(["workspace", "global"]).describe("Where to store launcher config"),
|
|
25
|
+
});
|
|
26
|
+
const AuthConfig = z.object({
|
|
27
|
+
osBaseUrl: z.string(),
|
|
28
|
+
daemonBaseUrl: z.string(),
|
|
29
|
+
adminPasswordEnvVarName: z.string(),
|
|
30
|
+
userEmail: z.string(),
|
|
31
|
+
});
|
|
32
|
+
const ConfigFile = z.object({
|
|
33
|
+
global: AuthConfig.partial().optional(),
|
|
34
|
+
workspaces: z.record(z.string(), AuthConfig).optional(),
|
|
35
|
+
/** a place where I put old/invalid configs I can't quite let go of */
|
|
36
|
+
rubbish: z.unknown().optional(),
|
|
37
|
+
});
|
|
38
|
+
const isAgent = process.env.AGENT === "1" ||
|
|
39
|
+
process.env.OPENCODE === "1" ||
|
|
40
|
+
Boolean(process.env.OPENCODE_SESSION) ||
|
|
41
|
+
Boolean(process.env.CLAUDE_CODE);
|
|
42
|
+
const t = initTRPC.meta().create();
|
|
43
|
+
const readConfigFile = () => {
|
|
44
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
const rawText = readFileSync(CONFIG_PATH, "utf8");
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(rawText);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
54
|
+
throw new Error(`Invalid JSON in ${CONFIG_PATH}: ${detail}`);
|
|
55
|
+
}
|
|
56
|
+
return parsed;
|
|
57
|
+
};
|
|
58
|
+
const getMergedWorkspaceConfig = (configFile, workspacePath) => {
|
|
59
|
+
const configs = [];
|
|
60
|
+
while (workspacePath && workspacePath !== "/") {
|
|
61
|
+
if (workspacePath in (configFile.workspaces || {})) {
|
|
62
|
+
configs.push(configFile.workspaces?.[workspacePath]);
|
|
63
|
+
}
|
|
64
|
+
workspacePath = dirname(workspacePath);
|
|
65
|
+
}
|
|
66
|
+
configs.push(configFile.global);
|
|
67
|
+
return configs.reverse().reduce((acc, config) => {
|
|
68
|
+
return { ...acc, ...config };
|
|
69
|
+
}, {});
|
|
70
|
+
};
|
|
71
|
+
const writeNewConfig = ({ patch, scope, workspacePath, }) => {
|
|
72
|
+
patch = Object.fromEntries(Object.entries(patch || {}).filter(([_key, value]) => value !== undefined));
|
|
73
|
+
const configFile = readConfigFile();
|
|
74
|
+
const cloned = structuredClone(configFile);
|
|
75
|
+
if (scope === "global") {
|
|
76
|
+
cloned.global = { ...configFile.global, ...patch };
|
|
77
|
+
}
|
|
78
|
+
if (scope === "workspace" && workspacePath) {
|
|
79
|
+
cloned.workspaces ||= {};
|
|
80
|
+
cloned.workspaces[workspacePath] = {
|
|
81
|
+
...configFile.workspaces?.[workspacePath],
|
|
82
|
+
...patch,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const parsed = ConfigFile.safeParse(cloned);
|
|
86
|
+
if (!parsed.success) {
|
|
87
|
+
throw new Error(`Invalid config file: ${z.prettifyError(parsed.error)}`);
|
|
88
|
+
}
|
|
89
|
+
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
90
|
+
writeFileSync(CONFIG_PATH, `${JSON.stringify(parsed.data, null, 2)}\n`);
|
|
91
|
+
return cloned;
|
|
92
|
+
};
|
|
93
|
+
const readAuthConfig = (workspacePath) => {
|
|
94
|
+
const configFile = readConfigFile();
|
|
95
|
+
const mergedConfig = getMergedWorkspaceConfig(configFile, workspacePath);
|
|
96
|
+
const parsed = AuthConfig.safeParse(mergedConfig);
|
|
97
|
+
if (!parsed.success) {
|
|
98
|
+
return new Error(`Invalid auth config for ${workspacePath} (in config file ${CONFIG_PATH}). Have you run \`iterate setup\`?\n${z.prettifyError(parsed.error)}`);
|
|
99
|
+
}
|
|
100
|
+
return parsed.data;
|
|
101
|
+
};
|
|
102
|
+
const setCookiesToCookieHeader = (setCookies) => {
|
|
103
|
+
const byName = new Map();
|
|
104
|
+
for (const c of setCookies ?? []) {
|
|
105
|
+
const pair = c.split(";")[0]?.trim();
|
|
106
|
+
if (!pair)
|
|
107
|
+
continue;
|
|
108
|
+
const eq = pair.indexOf("=");
|
|
109
|
+
if (eq === -1)
|
|
110
|
+
continue;
|
|
111
|
+
byName.set(pair.slice(0, eq), pair.slice(eq + 1));
|
|
112
|
+
}
|
|
113
|
+
return [...byName.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
|
|
114
|
+
};
|
|
115
|
+
const impersonationUserIdCache = new Map();
|
|
116
|
+
const resolveImpersonationUserId = async ({ superadminAuthClient, userEmail, baseUrl, }) => {
|
|
117
|
+
const normalizedEmail = userEmail.trim().toLowerCase();
|
|
118
|
+
const cacheKey = `${baseUrl}::${normalizedEmail}`;
|
|
119
|
+
const cachedUserId = impersonationUserIdCache.get(cacheKey);
|
|
120
|
+
if (cachedUserId) {
|
|
121
|
+
return cachedUserId;
|
|
122
|
+
}
|
|
123
|
+
let users = [];
|
|
124
|
+
try {
|
|
125
|
+
const result = await superadminAuthClient.admin.listUsers({
|
|
126
|
+
query: {
|
|
127
|
+
filterField: "email",
|
|
128
|
+
filterOperator: "eq",
|
|
129
|
+
filterValue: normalizedEmail,
|
|
130
|
+
limit: 10,
|
|
131
|
+
},
|
|
132
|
+
fetchOptions: {
|
|
133
|
+
throw: true,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
users = Array.isArray(result?.users) ? result.users : [];
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
const result = await superadminAuthClient.admin.listUsers({
|
|
140
|
+
query: {
|
|
141
|
+
searchField: "email",
|
|
142
|
+
searchOperator: "contains",
|
|
143
|
+
searchValue: normalizedEmail,
|
|
144
|
+
limit: 100,
|
|
145
|
+
},
|
|
146
|
+
fetchOptions: {
|
|
147
|
+
throw: true,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
users = Array.isArray(result?.users) ? result.users : [];
|
|
151
|
+
}
|
|
152
|
+
const exactMatches = users.filter((user) => user &&
|
|
153
|
+
typeof user === "object" &&
|
|
154
|
+
"email" in user &&
|
|
155
|
+
typeof user.email === "string" &&
|
|
156
|
+
user.email.toLowerCase() === normalizedEmail &&
|
|
157
|
+
"id" in user &&
|
|
158
|
+
typeof user.id === "string");
|
|
159
|
+
if (exactMatches.length === 0) {
|
|
160
|
+
throw new Error(`No user found with email ${userEmail}`);
|
|
161
|
+
}
|
|
162
|
+
if (exactMatches.length > 1) {
|
|
163
|
+
throw new Error(`Multiple users found with email ${userEmail}`);
|
|
164
|
+
}
|
|
165
|
+
const resolvedUserId = exactMatches[0].id;
|
|
166
|
+
impersonationUserIdCache.set(cacheKey, resolvedUserId);
|
|
167
|
+
return resolvedUserId;
|
|
168
|
+
};
|
|
169
|
+
const osAuthDance = async (authConfig) => {
|
|
170
|
+
let superadminSetCookie;
|
|
171
|
+
const authClient = createAuthClient({
|
|
172
|
+
baseURL: authConfig.osBaseUrl,
|
|
173
|
+
fetchOptions: {
|
|
174
|
+
throw: true,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
const password = process.env[authConfig.adminPasswordEnvVarName];
|
|
178
|
+
if (!password) {
|
|
179
|
+
throw new Error(`Password not found in env var ${authConfig.adminPasswordEnvVarName}`);
|
|
180
|
+
}
|
|
181
|
+
await authClient.signIn.email({
|
|
182
|
+
email: "superadmin@nustom.com",
|
|
183
|
+
password,
|
|
184
|
+
fetchOptions: {
|
|
185
|
+
throw: true,
|
|
186
|
+
onResponse: (ctx) => {
|
|
187
|
+
superadminSetCookie = ctx.response.headers.getSetCookie();
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
const superadminAuthClient = createAuthClient({
|
|
192
|
+
baseURL: authConfig.osBaseUrl,
|
|
193
|
+
fetchOptions: {
|
|
194
|
+
throw: true,
|
|
195
|
+
onRequest: (ctx) => {
|
|
196
|
+
ctx.headers.set("origin", authConfig.osBaseUrl);
|
|
197
|
+
ctx.headers.set("cookie", setCookiesToCookieHeader(superadminSetCookie));
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
plugins: [adminClient()],
|
|
201
|
+
});
|
|
202
|
+
const userId = await resolveImpersonationUserId({
|
|
203
|
+
superadminAuthClient,
|
|
204
|
+
userEmail: authConfig.userEmail,
|
|
205
|
+
baseUrl: authConfig.osBaseUrl,
|
|
206
|
+
});
|
|
207
|
+
let impersonateSetCookie;
|
|
208
|
+
await superadminAuthClient.admin.impersonateUser({
|
|
209
|
+
userId,
|
|
210
|
+
fetchOptions: {
|
|
211
|
+
throw: true,
|
|
212
|
+
onResponse: (ctx) => {
|
|
213
|
+
impersonateSetCookie = ctx.response.headers.getSetCookie();
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
const userCookies = setCookiesToCookieHeader(impersonateSetCookie);
|
|
218
|
+
const userClient = createAuthClient({
|
|
219
|
+
baseURL: authConfig.osBaseUrl,
|
|
220
|
+
fetchOptions: {
|
|
221
|
+
throw: true,
|
|
222
|
+
onRequest: (ctx) => {
|
|
223
|
+
ctx.headers.set("origin", authConfig.osBaseUrl);
|
|
224
|
+
ctx.headers.set("cookie", userCookies);
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
return { userCookies, userClient };
|
|
229
|
+
};
|
|
230
|
+
const loadAppRouter = async (params) => {
|
|
231
|
+
const url = `${params.baseUrl}/api/trpc-cli-procedures`;
|
|
232
|
+
const response = await fetch(url);
|
|
233
|
+
if (!response.ok) {
|
|
234
|
+
throw new Error(`${url} got ${response.status}: ${await response.text()}`);
|
|
235
|
+
}
|
|
236
|
+
let router;
|
|
237
|
+
try {
|
|
238
|
+
router = await response.json();
|
|
239
|
+
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
242
|
+
throw new Error(`${url} returned invalid router: ${message}`);
|
|
243
|
+
}
|
|
244
|
+
if (!Array.isArray(router?.procedures)) {
|
|
245
|
+
throw new Error(`${url} returned invalid router: ${JSON.stringify(router)}`);
|
|
246
|
+
}
|
|
247
|
+
return router;
|
|
248
|
+
};
|
|
249
|
+
const getOsProcedures = async (params) => {
|
|
250
|
+
const appRouter = await loadAppRouter(params);
|
|
251
|
+
const proxiedRouter = proxify(appRouter.procedures, async () => {
|
|
252
|
+
return createTRPCClient({
|
|
253
|
+
links: [
|
|
254
|
+
httpLink({
|
|
255
|
+
url: `${params.baseUrl}/api/trpc/`,
|
|
256
|
+
transformer: superjson,
|
|
257
|
+
fetch: async (request, init) => {
|
|
258
|
+
const authConfig = readAuthConfig(process.cwd());
|
|
259
|
+
if (authConfig instanceof Error)
|
|
260
|
+
throw authConfig;
|
|
261
|
+
const { userCookies } = await osAuthDance(authConfig);
|
|
262
|
+
const headers = new Headers(init?.headers);
|
|
263
|
+
headers.set("cookie", userCookies);
|
|
264
|
+
return fetch(request, { ...init, headers });
|
|
265
|
+
},
|
|
266
|
+
}),
|
|
267
|
+
],
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
return proxiedRouter;
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Creates a fetch wrapper that calls /api/trpc-stream/* instead of /api/trpc/*.
|
|
274
|
+
* The streaming endpoint returns SSE: log lines as `event: log` and the final
|
|
275
|
+
* tRPC response as `event: response`, which we reassemble into a normal Response.
|
|
276
|
+
*/
|
|
277
|
+
const streamingFetch = (daemonBaseUrl) => {
|
|
278
|
+
return async (input, init) => {
|
|
279
|
+
// Rewrite URL from /api/trpc/X to /api/trpc-stream/X
|
|
280
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
281
|
+
const rewritten = url.replace(`${daemonBaseUrl}/api/trpc/`, `${daemonBaseUrl}/api/trpc-stream/`);
|
|
282
|
+
const res = await fetch(rewritten, init);
|
|
283
|
+
if (rewritten === url)
|
|
284
|
+
return res;
|
|
285
|
+
const contentType = res.headers.get("content-type") || "";
|
|
286
|
+
// If the daemon didn't respond with SSE, pass through as-is (non-streaming endpoint)
|
|
287
|
+
if (!contentType.includes("text/event-stream"))
|
|
288
|
+
return res;
|
|
289
|
+
// Parse SSE stream: print log events to stderr, collect the final response
|
|
290
|
+
const reader = res.body?.getReader();
|
|
291
|
+
if (!reader)
|
|
292
|
+
return res;
|
|
293
|
+
const decoder = new TextDecoder();
|
|
294
|
+
let buffer = "";
|
|
295
|
+
let responseBody = null;
|
|
296
|
+
while (true) {
|
|
297
|
+
const { done, value } = await reader.read();
|
|
298
|
+
if (done)
|
|
299
|
+
break;
|
|
300
|
+
buffer += decoder.decode(value, { stream: true });
|
|
301
|
+
// Process complete SSE messages (double newline delimited)
|
|
302
|
+
const parts = buffer.split("\n\n");
|
|
303
|
+
buffer = parts.pop() || "";
|
|
304
|
+
for (const part of parts) {
|
|
305
|
+
const lines = part.split("\n");
|
|
306
|
+
const event = lines[0].split(": ")[1];
|
|
307
|
+
const data = lines[1].split(": ").slice(1).join(": ");
|
|
308
|
+
if (event === "log") {
|
|
309
|
+
const detail = JSON.parse(data);
|
|
310
|
+
console[detail.level](...detail.args);
|
|
311
|
+
}
|
|
312
|
+
else if (event === "response") {
|
|
313
|
+
responseBody = data;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Reconstruct a normal Response from the final payload so tRPC client is happy
|
|
318
|
+
return new Response(responseBody, {
|
|
319
|
+
status: res.status,
|
|
320
|
+
headers: { "content-type": "application/json" },
|
|
321
|
+
});
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
const getDaemonProcedures = async (params) => {
|
|
325
|
+
const daemonRouter = await loadAppRouter({ baseUrl: params.daemonBaseUrl });
|
|
326
|
+
const proxiedRouter = proxify(daemonRouter.procedures, async () => {
|
|
327
|
+
return createTRPCClient({
|
|
328
|
+
links: [
|
|
329
|
+
httpLink({
|
|
330
|
+
url: `${params.daemonBaseUrl}/api/trpc/`,
|
|
331
|
+
fetch: streamingFetch(params.daemonBaseUrl),
|
|
332
|
+
}),
|
|
333
|
+
],
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
return proxiedRouter;
|
|
337
|
+
};
|
|
338
|
+
const launcherProcedures = {
|
|
339
|
+
doctor: t.procedure
|
|
340
|
+
.meta({ description: "Show launcher config and resolved runtime options" })
|
|
341
|
+
.mutation(async () => {
|
|
342
|
+
const configFile = readConfigFile();
|
|
343
|
+
const parsed = ConfigFile.safeParse(configFile);
|
|
344
|
+
if (!parsed.success) {
|
|
345
|
+
throw new Error(`Invalid config file ${CONFIG_PATH}: ${z.prettifyError(parsed.error)}`);
|
|
346
|
+
}
|
|
347
|
+
const current = readAuthConfig(process.cwd());
|
|
348
|
+
if (current instanceof Error)
|
|
349
|
+
throw current;
|
|
350
|
+
return { configPath: CONFIG_PATH, current };
|
|
351
|
+
}),
|
|
352
|
+
setup: t.procedure
|
|
353
|
+
.input(SetupInput.partial())
|
|
354
|
+
.meta({ prompt: true, description: "Configure auth + launcher defaults for current workspace" })
|
|
355
|
+
.mutation(async ({ input }) => {
|
|
356
|
+
writeNewConfig({
|
|
357
|
+
scope: input.scope || "workspace",
|
|
358
|
+
patch: {
|
|
359
|
+
osBaseUrl: input.osBaseUrl,
|
|
360
|
+
daemonBaseUrl: input.daemonBaseUrl,
|
|
361
|
+
adminPasswordEnvVarName: input.adminPasswordEnvVarName,
|
|
362
|
+
userEmail: input.userEmail,
|
|
363
|
+
},
|
|
364
|
+
workspacePath: process.cwd(),
|
|
365
|
+
});
|
|
366
|
+
const current = readAuthConfig(process.cwd());
|
|
367
|
+
if (current instanceof Error)
|
|
368
|
+
throw current;
|
|
369
|
+
return { configPath: CONFIG_PATH, current };
|
|
370
|
+
}),
|
|
371
|
+
whoami: t.procedure.mutation(async () => {
|
|
372
|
+
const authConfig = readAuthConfig(process.cwd());
|
|
373
|
+
if (authConfig instanceof Error)
|
|
374
|
+
throw authConfig;
|
|
375
|
+
const { userClient } = await osAuthDance(authConfig);
|
|
376
|
+
return await userClient.getSession();
|
|
377
|
+
}),
|
|
378
|
+
};
|
|
379
|
+
export const getCli = async () => {
|
|
380
|
+
const authConfig = readAuthConfig(process.cwd());
|
|
381
|
+
const errorProcedure = (problem) => (e) => {
|
|
382
|
+
const message = `${problem}: ${e.message}`;
|
|
383
|
+
return t.procedure.meta({ description: message }).mutation(() => {
|
|
384
|
+
throw new Error(problem, { cause: e });
|
|
385
|
+
});
|
|
386
|
+
};
|
|
387
|
+
const routers = [t.router(launcherProcedures)];
|
|
388
|
+
if (authConfig instanceof Error) {
|
|
389
|
+
routers.push(t.router({
|
|
390
|
+
os: errorProcedure(`Invalid auth config`)(authConfig),
|
|
391
|
+
daemon: errorProcedure(`Invalid auth config`)(authConfig),
|
|
392
|
+
}));
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
const [osProcedures, daemonProcedures] = await Promise.allSettled([
|
|
396
|
+
getOsProcedures({ baseUrl: authConfig.osBaseUrl }),
|
|
397
|
+
getDaemonProcedures({ daemonBaseUrl: authConfig.daemonBaseUrl }),
|
|
398
|
+
]);
|
|
399
|
+
if (osProcedures.status === "fulfilled") {
|
|
400
|
+
routers.push(t.router({ os: osProcedures.value }));
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
routers.push(t.router({
|
|
404
|
+
os: errorProcedure(`Couldn't connect to os at ${authConfig.osBaseUrl}`)(osProcedures.reason),
|
|
405
|
+
}));
|
|
406
|
+
}
|
|
407
|
+
if (daemonProcedures.status === "fulfilled") {
|
|
408
|
+
// don't nest daemon procedures under "daemon"
|
|
409
|
+
routers.push(daemonProcedures.value);
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
routers.push(t.router({
|
|
413
|
+
daemon: errorProcedure(`Couldn't connect to daemon at ${authConfig.daemonBaseUrl}`)(daemonProcedures.reason),
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const router = t.mergeRouters(...routers);
|
|
418
|
+
const cli = createCli({
|
|
419
|
+
router,
|
|
420
|
+
name: "iterate",
|
|
421
|
+
version: "0.0.1",
|
|
422
|
+
description: "Iterate CLI",
|
|
423
|
+
});
|
|
424
|
+
return { cli, prompts: isAgent ? undefined : prompts };
|
|
425
|
+
};
|
|
426
|
+
export const runCli = async () => {
|
|
427
|
+
const { cli, prompts: cliPrompts } = await getCli();
|
|
428
|
+
await cli.run({ prompts: cliPrompts });
|
|
429
|
+
};
|
|
430
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iterate",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "CLI for iterate",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -21,18 +21,30 @@
|
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=22"
|
|
23
23
|
},
|
|
24
|
-
"publishConfig": {
|
|
25
|
-
"access": "public"
|
|
26
|
-
},
|
|
27
24
|
"bin": {
|
|
28
25
|
"iterate": "./bin/iterate.js"
|
|
29
26
|
},
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./src/index.ts"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"import": "./dist/index.js",
|
|
35
|
+
"types": "./dist/index.d.ts"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
30
39
|
"files": [
|
|
31
40
|
"bin",
|
|
41
|
+
"dist",
|
|
32
42
|
"README.md"
|
|
33
43
|
],
|
|
34
44
|
"scripts": {
|
|
35
|
-
"
|
|
45
|
+
"build": "tsgo",
|
|
46
|
+
"typecheck": "tsgo --noEmit",
|
|
47
|
+
"prepack": "pnpm build"
|
|
36
48
|
},
|
|
37
49
|
"dependencies": {
|
|
38
50
|
"@clack/prompts": "^1.0.0",
|
|
@@ -42,5 +54,8 @@
|
|
|
42
54
|
"superjson": "^2.2.2",
|
|
43
55
|
"trpc-cli": "0.12.4",
|
|
44
56
|
"zod": "4.1.12"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^22.0.0"
|
|
45
60
|
}
|
|
46
61
|
}
|