iterate 0.2.7 → 0.3.0

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.
Files changed (218) hide show
  1. package/README.md +86 -76
  2. package/THIRD_PARTY_NOTICES.md +55 -0
  3. package/bin/iterate.js +11 -3
  4. package/dist/api-url-B6404M82.mjs +17 -0
  5. package/dist/api-url-B6404M82.mjs.map +1 -0
  6. package/dist/app-ref-BipL0feU.mjs +35 -0
  7. package/dist/app-ref-BipL0feU.mjs.map +1 -0
  8. package/dist/app-ref-C1CrgXqX.mjs +7 -0
  9. package/dist/app-ref-C1CrgXqX.mjs.map +1 -0
  10. package/dist/app-ref-DYai_om1.mjs +7 -0
  11. package/dist/app-ref-DYai_om1.mjs.map +1 -0
  12. package/dist/cli-D0c-pDL_.mjs +1010 -0
  13. package/dist/cli-D0c-pDL_.mjs.map +1 -0
  14. package/dist/client.d.ts +3 -0
  15. package/dist/client.mjs +4 -0
  16. package/dist/cloudflare-BTm90gQ4.mjs +951 -0
  17. package/dist/cloudflare-BTm90gQ4.mjs.map +1 -0
  18. package/dist/contract-s4FW4eES.mjs +309 -0
  19. package/dist/contract-s4FW4eES.mjs.map +1 -0
  20. package/dist/document-review/index.d.ts +5 -0
  21. package/dist/document-review/types.d.ts +107 -0
  22. package/dist/document-review.mjs +7015 -0
  23. package/dist/document-review.mjs.map +1 -0
  24. package/dist/durable-object-processor-durability-CNsTjAJS.mjs +205 -0
  25. package/dist/durable-object-processor-durability-CNsTjAJS.mjs.map +1 -0
  26. package/dist/idempotency-DleloJNt.mjs +28 -0
  27. package/dist/idempotency-DleloJNt.mjs.map +1 -0
  28. package/dist/index.mjs +1 -1
  29. package/dist/itx/api-url.d.ts +6 -0
  30. package/dist/itx/itx-node-client.d.ts +65 -0
  31. package/dist/itx/itx-session.d.ts +215 -0
  32. package/dist/itx/owned-rpc-session.d.ts +14 -0
  33. package/dist/itx/query-client.d.ts +10 -0
  34. package/dist/itx-api.generated.d.ts +6195 -0
  35. package/dist/itx-session-sjud8GiT.mjs +534 -0
  36. package/dist/itx-session-sjud8GiT.mjs.map +1 -0
  37. package/dist/live-state-BJNqOwFw.mjs +299 -0
  38. package/dist/live-state-BJNqOwFw.mjs.map +1 -0
  39. package/dist/next/api.d.ts +479 -0
  40. package/dist/next/api.mjs +0 -0
  41. package/dist/next/app-server.d.ts +44 -0
  42. package/dist/next/app-server.mjs +479 -0
  43. package/dist/next/app-server.mjs.map +1 -0
  44. package/dist/next/app-session.d.ts +49 -0
  45. package/dist/next/app-session.mjs +238 -0
  46. package/dist/next/app-session.mjs.map +1 -0
  47. package/dist/next/app.d.ts +29 -0
  48. package/dist/next/app.mjs +141 -0
  49. package/dist/next/app.mjs.map +1 -0
  50. package/dist/next/client/live-state.d.ts +63 -0
  51. package/dist/next/client/oauth.d.ts +12 -0
  52. package/dist/next/client/react.d.ts +109 -0
  53. package/dist/next/client/socket.d.ts +6 -0
  54. package/dist/next/client.mjs +156 -0
  55. package/dist/next/client.mjs.map +1 -0
  56. package/dist/next/expression.d.ts +146 -0
  57. package/dist/next/expression.mjs +399 -0
  58. package/dist/next/expression.mjs.map +1 -0
  59. package/dist/next/lib.d.ts +56 -0
  60. package/dist/next/lib.mjs +199 -0
  61. package/dist/next/lib.mjs.map +1 -0
  62. package/dist/next/oauth-scopes.d.ts +32 -0
  63. package/dist/next/oauth-scopes.mjs +40 -0
  64. package/dist/next/oauth-scopes.mjs.map +1 -0
  65. package/dist/next/oauth.mjs +29 -0
  66. package/dist/next/oauth.mjs.map +1 -0
  67. package/dist/next/principal.d.ts +64 -0
  68. package/dist/next/principal.mjs +98 -0
  69. package/dist/next/principal.mjs.map +1 -0
  70. package/dist/next/project-ingress.d.ts +37 -0
  71. package/dist/next/project-ingress.mjs +75 -0
  72. package/dist/next/project-ingress.mjs.map +1 -0
  73. package/dist/next/react.mjs +285 -0
  74. package/dist/next/react.mjs.map +1 -0
  75. package/dist/next/sdk/auth.d.ts +5 -0
  76. package/dist/next/sdk/index.d.ts +112 -0
  77. package/dist/next/sdk.mjs +139 -0
  78. package/dist/next/sdk.mjs.map +1 -0
  79. package/dist/next/stream/processor.d.ts +378 -0
  80. package/dist/next/stream/processor.mjs +582 -0
  81. package/dist/next/stream/processor.mjs.map +1 -0
  82. package/dist/next/stream/run.d.ts +58 -0
  83. package/dist/next/stream/run.mjs +40 -0
  84. package/dist/next/stream/run.mjs.map +1 -0
  85. package/dist/next-node.d.ts +15 -0
  86. package/dist/next-node.mjs +51 -0
  87. package/dist/next-node.mjs.map +1 -0
  88. package/dist/node.d.ts +3 -0
  89. package/dist/node.mjs +185 -0
  90. package/dist/node.mjs.map +1 -0
  91. package/dist/processor-host-capabilities-BMFH3KTM.mjs +56 -0
  92. package/dist/processor-host-capabilities-BMFH3KTM.mjs.map +1 -0
  93. package/dist/processors/cloudflare.d.ts +3 -0
  94. package/dist/processors/durable-object-processor-durability.d.ts +79 -0
  95. package/dist/processors/event-consumption-metrics.d.ts +82 -0
  96. package/dist/processors/idempotency.d.ts +13 -0
  97. package/dist/processors/index.d.ts +12 -0
  98. package/dist/processors/processor-contracts.d.ts +342 -0
  99. package/dist/processors/processor-facet.d.ts +186 -0
  100. package/dist/processors/processor-host-capabilities.d.ts +60 -0
  101. package/dist/processors/prompt-sections.d.ts +17 -0
  102. package/dist/processors/rpc-types.d.ts +515 -0
  103. package/dist/processors/schemas.d.ts +102 -0
  104. package/dist/processors/stream-handle.d.ts +45 -0
  105. package/dist/processors/stream-processor-keepalive.d.ts +95 -0
  106. package/dist/processors/stream-processor-registry.d.ts +233 -0
  107. package/dist/processors/stream-processor-runner.d.ts +289 -0
  108. package/dist/processors/stream-processor.d.ts +339 -0
  109. package/dist/processors/stream-runtime-metrics.d.ts +107 -0
  110. package/dist/processors/testing.d.ts +302 -0
  111. package/dist/processors-BoNyeBfQ.mjs +10 -0
  112. package/dist/processors-BoNyeBfQ.mjs.map +1 -0
  113. package/dist/processors-cloudflare.mjs +3 -0
  114. package/dist/processors-testing.mjs +435 -0
  115. package/dist/processors-testing.mjs.map +1 -0
  116. package/dist/processors.mjs +52 -0
  117. package/dist/processors.mjs.map +1 -0
  118. package/dist/protocol-DnK_f2m6.mjs +251 -0
  119. package/dist/protocol-DnK_f2m6.mjs.map +1 -0
  120. package/dist/sdk/capnweb/index.d.ts +2 -0
  121. package/dist/sdk/capnweb/live-state/compact.d.ts +5 -0
  122. package/dist/sdk/capnweb/live-state/diff.d.ts +41 -0
  123. package/dist/sdk/capnweb/live-state/engine.d.ts +44 -0
  124. package/dist/sdk/capnweb/live-state/index.d.ts +41 -0
  125. package/dist/sdk/capnweb/live-state/protocol.d.ts +87 -0
  126. package/dist/sdk/capnweb/live-state/retain.d.ts +23 -0
  127. package/dist/sdk/capnweb/live-state/store.d.ts +20 -0
  128. package/dist/sdk/capnweb/live-state/types.d.ts +11 -0
  129. package/dist/sdk/capnweb/react.d.ts +45 -0
  130. package/dist/sdk/capnweb/react.mjs +316 -0
  131. package/dist/sdk/capnweb/react.mjs.map +1 -0
  132. package/dist/sdk/capnweb.mjs +4 -0
  133. package/dist/sdk/itx/react.d.ts +191 -0
  134. package/dist/sdk/itx/react.mjs +383 -0
  135. package/dist/sdk/itx/react.mjs.map +1 -0
  136. package/dist/sdk-DMB-IM11.mjs +933 -0
  137. package/dist/sdk-DMB-IM11.mjs.map +1 -0
  138. package/dist/sdk.d.ts +339 -0
  139. package/dist/sdk.mjs +2 -0
  140. package/dist/serve-itx.d.ts +46 -0
  141. package/dist/starter-apps/flake-dashboard/app-ref.d.ts +31 -0
  142. package/dist/starter-apps/flake-dashboard/configured-worker.mjs +1055 -0
  143. package/dist/starter-apps/flake-dashboard/configured-worker.mjs.map +1 -0
  144. package/dist/starter-apps/flake-dashboard/contract.d.ts +4839 -0
  145. package/dist/starter-apps/flake-dashboard/contract.mjs +2 -0
  146. package/dist/starter-apps/flake-dashboard/index.d.ts +17 -0
  147. package/dist/starter-apps/flake-dashboard/index.mjs +56 -0
  148. package/dist/starter-apps/flake-dashboard/index.mjs.map +1 -0
  149. package/dist/starter-apps/flake-dashboard/worker.d.ts +4607 -0
  150. package/dist/starter-apps/github-ai-linter/ai-linter.d.ts +8914 -0
  151. package/dist/starter-apps/github-ai-linter/configured-worker.mjs +17987 -0
  152. package/dist/starter-apps/github-ai-linter/configured-worker.mjs.map +1 -0
  153. package/dist/starter-apps/github-ai-linter/contract.d.ts +9193 -0
  154. package/dist/starter-apps/github-ai-linter/index.d.ts +10 -0
  155. package/dist/starter-apps/github-ai-linter/index.mjs +36 -0
  156. package/dist/starter-apps/github-ai-linter/index.mjs.map +1 -0
  157. package/dist/starter-apps/github-ai-linter/prompt.d.ts +13 -0
  158. package/dist/starter-apps/github-ai-linter/review-bot.d.ts +808 -0
  159. package/dist/starter-apps/github-ai-linter/rules.d.ts +34 -0
  160. package/dist/starter-apps/github-ai-linter/worker-ref.d.ts +19 -0
  161. package/dist/starter-apps/github-ai-linter/worker.d.ts +19 -0
  162. package/dist/starter-apps/github-ai-linter/worker.mjs +947 -0
  163. package/dist/starter-apps/github-ai-linter/worker.mjs.map +1 -0
  164. package/dist/starter-apps/guestbook/app-ref.d.ts +27 -0
  165. package/dist/starter-apps/guestbook/client.d.ts +7 -0
  166. package/dist/starter-apps/guestbook/client.mjs +59 -0
  167. package/dist/starter-apps/guestbook/configured-worker.mjs +205 -0
  168. package/dist/starter-apps/guestbook/configured-worker.mjs.map +1 -0
  169. package/dist/starter-apps/guestbook/index.d.ts +9 -0
  170. package/dist/starter-apps/guestbook/index.mjs +31 -0
  171. package/dist/starter-apps/guestbook/index.mjs.map +1 -0
  172. package/dist/starter-apps/guestbook/processor.d.ts +2267 -0
  173. package/dist/starter-apps/guestbook/worker.d.ts +26 -0
  174. package/dist/starter-apps/guestbook/worker.mjs +191 -0
  175. package/dist/starter-apps/guestbook/worker.mjs.map +1 -0
  176. package/dist/starter-apps/media/configured-worker.mjs +577 -0
  177. package/dist/starter-apps/media/configured-worker.mjs.map +1 -0
  178. package/dist/starter-apps/media/index.mjs +36 -0
  179. package/dist/starter-apps/media/index.mjs.map +1 -0
  180. package/dist/starter-apps/media/ref.mjs +20 -0
  181. package/dist/starter-apps/media/ref.mjs.map +1 -0
  182. package/dist/starter-apps/media/worker.mjs +579 -0
  183. package/dist/starter-apps/media/worker.mjs.map +1 -0
  184. package/dist/starter-apps/notes/configured-worker.mjs +6134 -0
  185. package/dist/starter-apps/notes/configured-worker.mjs.map +1 -0
  186. package/dist/starter-apps/notes/index.mjs +23 -0
  187. package/dist/starter-apps/notes/index.mjs.map +1 -0
  188. package/dist/starter-apps/notes/ref.mjs +21 -0
  189. package/dist/starter-apps/notes/ref.mjs.map +1 -0
  190. package/dist/starter-apps/notes/worker.mjs +427 -0
  191. package/dist/starter-apps/notes/worker.mjs.map +1 -0
  192. package/dist/starter-apps/todo/client.mjs +59 -0
  193. package/dist/starter-apps/todo/configured-worker.mjs +2864 -0
  194. package/dist/starter-apps/todo/configured-worker.mjs.map +1 -0
  195. package/dist/starter-apps/todo/index.d.ts +8 -0
  196. package/dist/starter-apps/todo/index.mjs +29 -0
  197. package/dist/starter-apps/todo/index.mjs.map +1 -0
  198. package/dist/stream-processor-keepalive-DAQTP6m3.mjs +2082 -0
  199. package/dist/stream-processor-keepalive-DAQTP6m3.mjs.map +1 -0
  200. package/dist/usingCtx-inzbY1Qz.mjs +57 -0
  201. package/dist/usingCtx-mZx5nsAW.mjs +11800 -0
  202. package/dist/usingCtx-mZx5nsAW.mjs.map +1 -0
  203. package/dist/worker-ref-DZxPDmb_.mjs +390 -0
  204. package/dist/worker-ref-DZxPDmb_.mjs.map +1 -0
  205. package/menubar/Iterate.entitlements +12 -0
  206. package/menubar/Iterate.swift +914 -0
  207. package/menubar/IterateIcon.swift +145 -0
  208. package/menubar/README.md +28 -0
  209. package/menubar/build-menubar-app.sh +59 -0
  210. package/package.json +235 -18
  211. package/dist/cli-DMS4kJph.mjs +0 -868
  212. package/dist/cli-DMS4kJph.mjs.map +0 -1
  213. package/dist/config-DtnR7Lv7.mjs +0 -170
  214. package/dist/config-DtnR7Lv7.mjs.map +0 -1
  215. package/dist/index.d.mts.map +0 -1
  216. package/dist/stream-tui/agent-chat-terminal.d.mts +0 -1
  217. package/dist/stream-tui/agent-chat-terminal.mjs +0 -933
  218. package/dist/stream-tui/agent-chat-terminal.mjs.map +0 -1
@@ -1,868 +0,0 @@
1
- import { a as removeConfigSession, c as connectItx, i as readConfigFile, n as Config, o as updateConfigSession, r as readConfig, s as writeConfigFile, t as CONFIG_PATH } from "./config-DtnR7Lv7.mjs";
2
- import { existsSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { z } from "zod/v4";
5
- import { spawn } from "node:child_process";
6
- import { createHash, randomBytes } from "node:crypto";
7
- import { createServer } from "node:http";
8
- import process from "node:process";
9
- import * as prompts from "@clack/prompts";
10
- import { createORPCClient } from "@orpc/client";
11
- import { RPCLink } from "@orpc/client/fetch";
12
- import { os } from "@orpc/server";
13
- import { createCli, parseRouter, yamlTableConsoleLogger } from "trpc-cli";
14
- //#region src/cli.ts
15
- const OAUTH_REFRESH_SKEW_MS = 6e4;
16
- const DEFAULT_CHAT_AGENT_PATH = "/agents/onboarding";
17
- const isAgent = process.env.AGENT === "1" || process.env.OPENCODE === "1" || Boolean(process.env.OPENCODE_SESSION) || Boolean(process.env.CLAUDE_CODE);
18
- /** Global override set by --config flag before CLI commands run. */
19
- let configFlagOverride;
20
- /**
21
- * We strip host-level flags before handing argv to `trpc-cli`,
22
- * That keeps router-local help/validation focused on the mounted
23
- * procedures instead of teaching every command about iterate-specific flags.
24
- *
25
- * Example: `iterate --config dev doctor`
26
- */
27
- const consumeCliStringFlag = (flagName) => {
28
- const args = process.argv.slice(2);
29
- const flagIndex = args.indexOf(flagName);
30
- if (flagIndex === -1) return void 0;
31
- const value = args[flagIndex + 1];
32
- if (!value || value.startsWith("-")) throw new Error(`${flagName} requires a value`);
33
- process.argv.splice(flagIndex + 2, 2);
34
- return value;
35
- };
36
- const firstNonFlagArgument = (args) => {
37
- for (const arg of args) {
38
- if (arg === "--") return void 0;
39
- if (!arg.startsWith("-")) return arg;
40
- }
41
- };
42
- const defaultBareInvocationToChat = (args) => args.length === 0 ? ["chat"] : args;
43
- const applyDefaultBareInvocation = () => {
44
- const args = process.argv.slice(2);
45
- const nextArgs = defaultBareInvocationToChat(args);
46
- if (nextArgs !== args) process.argv.splice(2, args.length, ...nextArgs);
47
- };
48
- const resolveStreamTuiEntrypointPath = () => {
49
- const moduleDir = import.meta.dirname;
50
- const candidates = [
51
- join(moduleDir, "stream-tui/agent-chat-terminal.tsx"),
52
- join(moduleDir, "stream-tui/agent-chat-terminal.mjs"),
53
- join(moduleDir, "stream-tui/agent-chat-terminal.js")
54
- ];
55
- for (const candidate of candidates) if (existsSync(candidate)) return candidate;
56
- throw new Error("Could not find the Iterate stream TUI entrypoint.");
57
- };
58
- const buildChatCommand = (input) => ({
59
- command: "bun",
60
- args: [
61
- input.entrypointPath,
62
- "--base-url",
63
- input.osBaseUrl,
64
- "--project-id",
65
- input.projectId,
66
- "--agent-path",
67
- input.agentPath
68
- ]
69
- });
70
- const runInheritedProcess = async (input) => {
71
- const child = spawn(input.command, input.args, {
72
- stdio: "inherit",
73
- env: {
74
- ...process.env,
75
- ...input.env
76
- }
77
- });
78
- const result = await new Promise((resolve, reject) => {
79
- child.on("error", reject);
80
- child.on("exit", (code, signal) => resolve({
81
- code,
82
- signal
83
- }));
84
- });
85
- if (result.signal) throw new Error(`${input.command} exited with signal ${result.signal}.`);
86
- if (result.code !== 0) throw new Error(`${input.command} exited with code ${result.code ?? "unknown"}.`);
87
- };
88
- const hasConfig = (configFile, name) => name === "prd" || Boolean(configFile.configs?.[name]);
89
- /**
90
- * Resolve which config name to use.
91
- * Priority: --config flag > workspace match (walk up from cwd) > default > single-config auto > built-in prd
92
- */
93
- const resolveConfigName = (workspacePath) => {
94
- const configFile = readConfigFile();
95
- if (configFlagOverride) {
96
- if (!hasConfig(configFile, configFlagOverride)) return /* @__PURE__ */ new Error(`Config "${configFlagOverride}" not found. Available: ${Object.keys(configFile.configs || {}).join(", ") || "(none)"}`);
97
- return configFlagOverride;
98
- }
99
- let dir = workspacePath;
100
- while (dir && dir !== "/") {
101
- const match = configFile.workspaces?.[dir];
102
- if (match) {
103
- if (!hasConfig(configFile, match)) return /* @__PURE__ */ new Error(`Workspace "${dir}" maps to config "${match}" which doesn't exist.`);
104
- return match;
105
- }
106
- dir = dirname(dir);
107
- }
108
- if (configFile.default) {
109
- if (!hasConfig(configFile, configFile.default)) return /* @__PURE__ */ new Error(`Default config "${configFile.default}" doesn't exist. Available: ${Object.keys(configFile.configs || {}).join(", ") || "(none)"}`);
110
- return configFile.default;
111
- }
112
- const configNames = Object.keys(configFile.configs || {});
113
- if (configNames.length === 1) return configNames[0];
114
- return "prd";
115
- };
116
- function resolveConfig(workspacePath, options) {
117
- const result = (() => {
118
- const name = resolveConfigName(workspacePath);
119
- if (name instanceof Error) return name;
120
- const config = readConfig(name);
121
- if (config instanceof Error) return config;
122
- return {
123
- name,
124
- config
125
- };
126
- })();
127
- if (result instanceof Error && options?.throw) throw result;
128
- return result;
129
- }
130
- var StoredOsSessionError = class extends Error {
131
- reason;
132
- constructor(reason, message) {
133
- super(message);
134
- this.reason = reason;
135
- this.name = "StoredOsSessionError";
136
- }
137
- };
138
- /**
139
- * Get auth headers for OS API calls based on the resolved config's stored session.
140
- * OAuth sessions are refreshed when possible.
141
- */
142
- const getOsAuthHeaders = async (config, configName) => {
143
- let session = config.session;
144
- if (!session) throw new StoredOsSessionError("missing", `Not logged in to ${config.osBaseUrl}. Run \`iterate login\` first.`);
145
- if (sessionNeedsRefresh(session)) if (session.refreshToken && session.clientId) session = await refreshOAuthSession({
146
- config,
147
- configName,
148
- session
149
- });
150
- else throw new StoredOsSessionError("expired", `Session expired for ${config.osBaseUrl}. Run \`iterate login\` again.`);
151
- if (session.token) return { authorization: `Bearer ${session.token}` };
152
- if (session.cookie) return { cookie: session.cookie };
153
- throw new Error(`Stored session for ${config.osBaseUrl} has no token or cookie.`);
154
- };
155
- const osAuthFromHeaders = (headers) => {
156
- if (headers.authorization) {
157
- const match = /^Bearer\s+(.+)$/i.exec(headers.authorization);
158
- if (!match) throw new Error("Stored OS authorization header is not a bearer token.");
159
- return { credentials: {
160
- type: "bearer",
161
- token: match[1]
162
- } };
163
- }
164
- if (headers.cookie) return {
165
- credentials: { type: "from-server-cookie" },
166
- requestHeaders: { cookie: headers.cookie }
167
- };
168
- throw new Error("No OS auth credentials available.");
169
- };
170
- const osAuthFromEnvironment = () => {
171
- const adminSecret = process.env.APP_CONFIG_ADMIN_API_SECRET?.trim();
172
- if (adminSecret) return { credentials: {
173
- type: "admin-secret",
174
- secret: adminSecret
175
- } };
176
- const bearerToken = process.env.ITERATE_BEARER_TOKEN?.trim();
177
- if (bearerToken) return { credentials: {
178
- type: "bearer",
179
- token: bearerToken
180
- } };
181
- };
182
- const disposeRpc = (stub) => {
183
- try {
184
- stub?.[Symbol.dispose]?.();
185
- } catch {}
186
- };
187
- const errorMessage = (error) => error instanceof Error ? error.message : String(error);
188
- const headersRecord = (headers) => {
189
- if (headers === void 0) return void 0;
190
- return Object.fromEntries(new Headers(headers).entries());
191
- };
192
- const withAuthenticatedOsSession = async (input) => {
193
- const session = input.createSession?.({
194
- auth: input.auth,
195
- baseUrl: input.baseUrl
196
- }) ?? connectItx({
197
- auth: input.auth.credentials,
198
- baseUrl: input.baseUrl,
199
- headers: headersRecord(input.auth.requestHeaders)
200
- });
201
- try {
202
- return await input.run(session);
203
- } finally {
204
- disposeRpc(session);
205
- }
206
- };
207
- const verifyOsSession = async (input) => {
208
- return await withAuthenticatedOsSession({
209
- auth: osAuthFromHeaders(input.authHeaders),
210
- baseUrl: input.baseUrl,
211
- createSession: input.createSession,
212
- run: async (session) => await session.__describe()
213
- });
214
- };
215
- const setupMissingProjectForChat = async (session, project) => {
216
- let projectItx;
217
- let agentStream;
218
- try {
219
- projectItx = await session.projects.create({
220
- projectId: project.id,
221
- slug: project.slug,
222
- ...project.organizationSlug ? { organizationSlug: project.organizationSlug } : {},
223
- waitUntilCreated: false
224
- });
225
- agentStream = projectItx.streams.get(DEFAULT_CHAT_AGENT_PATH);
226
- await agentStream.waitForEvent({
227
- afterOffset: 0,
228
- eventTypes: ["events.iterate.com/agent/llm-provider-selected"],
229
- timeoutMs: 15e3
230
- });
231
- } catch (error) {
232
- throw new Error(`Project "${project.slug}" (${project.id}) exists in auth but is missing in OS. Failed to set it up for chat: ${errorMessage(error)}`);
233
- } finally {
234
- disposeRpc(agentStream);
235
- disposeRpc(projectItx);
236
- }
237
- return project.id;
238
- };
239
- const accessibleProjectsMessage = (projects) => projects.length === 0 ? "No accessible projects found." : `Accessible projects: ${projects.map((project) => `${project.slug} (${project.id}, ${project.deploymentStatus})`).join(", ")}.`;
240
- const resolveChatProject = async (input) => {
241
- const configured = input.explicitProject || input.configuredDefaultProject;
242
- return await withAuthenticatedOsSession({
243
- auth: input.auth,
244
- baseUrl: input.baseUrl,
245
- createSession: input.createSession,
246
- run: async (session) => {
247
- let projects;
248
- try {
249
- projects = await session.projects.list();
250
- } catch (error) {
251
- if (configured) throw new Error(`Failed to resolve project "${configured}" for config "${input.configName}" in ${input.configPath}. The CLI could not list accessible projects, so it cannot resolve slugs or recover auth-known projects that are missing in OS: ${errorMessage(error)}`);
252
- throw new Error(`No project specified. Pass --project or set "defaultProject" on config "${input.configName}" in ${input.configPath}. Failed to list accessible projects: ${errorMessage(error)}`);
253
- }
254
- if (configured) {
255
- const project = projects.find((candidate) => candidate.id === configured || candidate.slug === configured);
256
- if (!project) {
257
- if (configured.startsWith("prj_")) return configured;
258
- throw new Error(`Project "${configured}" was not found among accessible projects for config "${input.configName}" in ${input.configPath}. ${accessibleProjectsMessage(projects)}`);
259
- }
260
- if (project.deploymentStatus === "missing") return await setupMissingProjectForChat(session, project);
261
- return project.id;
262
- }
263
- const readyProjects = projects.filter((project) => project.deploymentStatus === "ready");
264
- const candidates = readyProjects.length > 0 ? readyProjects : projects;
265
- if (candidates.length === 1) {
266
- const project = candidates[0];
267
- if (project.deploymentStatus === "missing") return await setupMissingProjectForChat(session, project);
268
- return project.id;
269
- }
270
- throw new Error(`No project specified. Pass --project or set "defaultProject" on config "${input.configName}" in ${input.configPath}. ${accessibleProjectsMessage(projects)}`);
271
- }
272
- });
273
- };
274
- const sessionNeedsRefresh = (session) => {
275
- if (!session.expiresAt) return false;
276
- const expiresAt = Date.parse(session.expiresAt);
277
- return Number.isFinite(expiresAt) && expiresAt <= Date.now() + OAUTH_REFRESH_SKEW_MS;
278
- };
279
- const getAuthWorkerHeaders = async (config) => {
280
- const session = config.session;
281
- if (!session) throw new Error(`Not logged in to ${config.authBaseUrl}. Run \`iterate login\` first.`);
282
- if (session.expiresAt && new Date(session.expiresAt) < /* @__PURE__ */ new Date()) throw new Error(`Session expired for ${config.authBaseUrl}. Run \`iterate login\` again.`);
283
- if (session.token) return { authorization: `Bearer ${session.token}` };
284
- if (session.cookie) return { cookie: session.cookie };
285
- throw new Error(`Stored session for ${config.authBaseUrl} has no token or cookie.`);
286
- };
287
- const getAuthWorkerClient = async (config) => {
288
- const baseURL = config.authBaseUrl;
289
- const headers = await getAuthWorkerHeaders(config);
290
- return createORPCClient(new RPCLink({
291
- url: `${baseURL}/api/orpc/`,
292
- fetch: async (request, init) => {
293
- const reqHeaders = new Headers(request instanceof Request ? request.headers : init?.headers);
294
- if (headers.cookie) reqHeaders.set("cookie", headers.cookie);
295
- if (headers.authorization) reqHeaders.set("authorization", headers.authorization);
296
- return fetch(request, {
297
- ...init,
298
- headers: reqHeaders
299
- });
300
- }
301
- }));
302
- };
303
- const OAUTH_SCOPE = "openid profile email offline_access project";
304
- const LOOPBACK_HOST = "localhost";
305
- const LOOPBACK_CALLBACK_PATH = "/callback";
306
- const OAUTH_CALLBACK_TIMEOUT_MS = 300 * 1e3;
307
- const base64Url = (buffer) => buffer.toString("base64url");
308
- const randomBase64Url = (byteLength = 32) => base64Url(randomBytes(byteLength));
309
- const oauthResourceForOsBaseUrl = (osBaseUrl) => {
310
- const url = new URL(osBaseUrl);
311
- if (new Set([
312
- "localhost",
313
- "127.0.0.1",
314
- "[::1]",
315
- "::1"
316
- ]).has(url.hostname)) return `${url.protocol}//${url.hostname}`;
317
- url.search = "";
318
- url.hash = "";
319
- url.pathname = url.pathname.replace(/\/+$/, "") || "/";
320
- return url.toString().replace(/\/$/, "");
321
- };
322
- const openUrlInBrowser = async (url) => {
323
- try {
324
- const { execFile } = await import("node:child_process");
325
- if (process.platform === "darwin") {
326
- execFile("open", [url]);
327
- return;
328
- }
329
- if (process.platform === "win32") {
330
- execFile("cmd", [
331
- "/c",
332
- "start",
333
- "",
334
- url
335
- ]);
336
- return;
337
- }
338
- execFile("xdg-open", [url]);
339
- } catch {}
340
- };
341
- const readErrorBody = async (response) => {
342
- const text = await response.text();
343
- return text.length > 300 ? `${text.slice(0, 300)}...` : text;
344
- };
345
- const registerOAuthClient = async (input) => {
346
- const response = await fetch(`${input.authBaseUrl}/api/auth/oauth2/register`, {
347
- method: "POST",
348
- headers: {
349
- "content-type": "application/json",
350
- origin: input.authBaseUrl
351
- },
352
- body: JSON.stringify({
353
- client_name: "Iterate CLI",
354
- redirect_uris: [input.redirectUri],
355
- token_endpoint_auth_method: "none",
356
- grant_types: ["authorization_code", "refresh_token"],
357
- response_types: ["code"],
358
- scope: OAUTH_SCOPE,
359
- type: "native",
360
- require_pkce: true
361
- })
362
- });
363
- if (!response.ok) throw new Error(`OAuth client registration failed (${response.status}): ${await readErrorBody(response)}`);
364
- const client = await response.json();
365
- if (!client.client_id) throw new Error("OAuth client registration did not return client_id.");
366
- return client.client_id;
367
- };
368
- const startOAuthCallbackServer = async () => {
369
- let settled = false;
370
- let resolveCallback;
371
- let rejectCallback;
372
- const callbackPromise = new Promise((resolve, reject) => {
373
- resolveCallback = resolve;
374
- rejectCallback = reject;
375
- });
376
- const server = createServer((request, response) => {
377
- if (settled) {
378
- response.writeHead(409, { "content-type": "text/plain; charset=utf-8" });
379
- response.end("OAuth callback already received.");
380
- return;
381
- }
382
- const url = new URL(request.url ?? "/", `http://${LOOPBACK_HOST}`);
383
- if (url.pathname !== LOOPBACK_CALLBACK_PATH) {
384
- response.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
385
- response.end("Not found.");
386
- return;
387
- }
388
- const error = url.searchParams.get("error");
389
- if (error) {
390
- settled = true;
391
- response.writeHead(400, { "content-type": "text/html; charset=utf-8" });
392
- response.end("<h1>Iterate login failed</h1><p>You can return to the terminal.</p>");
393
- rejectCallback?.(/* @__PURE__ */ new Error(`OAuth authorization failed: ${error}${url.searchParams.get("error_description") ? ` (${url.searchParams.get("error_description")})` : ""}`));
394
- return;
395
- }
396
- const code = url.searchParams.get("code");
397
- const state = url.searchParams.get("state");
398
- if (!code || !state) {
399
- settled = true;
400
- response.writeHead(400, { "content-type": "text/html; charset=utf-8" });
401
- response.end("<h1>Iterate login failed</h1><p>Missing code or state.</p>");
402
- rejectCallback?.(/* @__PURE__ */ new Error("OAuth callback was missing code or state."));
403
- return;
404
- }
405
- settled = true;
406
- response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
407
- response.end("<h1>Iterate login complete</h1><p>You can close this tab.</p>");
408
- const address = server.address();
409
- const port = typeof address === "object" && address ? address.port : 0;
410
- resolveCallback?.({
411
- code,
412
- state,
413
- redirectUri: `http://${LOOPBACK_HOST}:${port}${LOOPBACK_CALLBACK_PATH}`
414
- });
415
- });
416
- await new Promise((resolve, reject) => {
417
- server.once("error", reject);
418
- server.listen(0, LOOPBACK_HOST, () => resolve());
419
- });
420
- const timeout = setTimeout(() => {
421
- if (!settled) {
422
- settled = true;
423
- rejectCallback?.(/* @__PURE__ */ new Error("Timed out waiting for OAuth callback."));
424
- }
425
- }, OAUTH_CALLBACK_TIMEOUT_MS);
426
- timeout.unref();
427
- const address = server.address();
428
- return {
429
- redirectUri: `http://${LOOPBACK_HOST}:${typeof address === "object" && address ? address.port : 0}${LOOPBACK_CALLBACK_PATH}`,
430
- wait: () => callbackPromise.finally(() => clearTimeout(timeout)),
431
- close: () => new Promise((resolve) => server.close(() => resolve()))
432
- };
433
- };
434
- const exchangeOAuthCode = async (input) => {
435
- const body = new URLSearchParams({
436
- grant_type: "authorization_code",
437
- client_id: input.clientId,
438
- code: input.code,
439
- redirect_uri: input.redirectUri,
440
- code_verifier: input.codeVerifier,
441
- resource: input.resource
442
- });
443
- const response = await fetch(`${input.authBaseUrl}/api/auth/oauth2/token`, {
444
- method: "POST",
445
- headers: {
446
- "content-type": "application/x-www-form-urlencoded",
447
- origin: input.authBaseUrl
448
- },
449
- body
450
- });
451
- if (!response.ok) throw new Error(`OAuth token exchange failed (${response.status}): ${await readErrorBody(response)}`);
452
- const token = await response.json();
453
- if (!token.access_token) throw new Error("OAuth token exchange did not return access_token.");
454
- return token;
455
- };
456
- const oauthTokenToSession = (token, existing) => {
457
- const expiresAtMs = token.expires_at ? token.expires_at * 1e3 : token.expires_in ? Date.now() + token.expires_in * 1e3 : void 0;
458
- return {
459
- token: token.access_token,
460
- refreshToken: token.refresh_token ?? existing?.refreshToken,
461
- clientId: existing?.clientId,
462
- scope: token.scope,
463
- tokenType: token.token_type,
464
- expiresAt: expiresAtMs ? new Date(expiresAtMs).toISOString() : void 0
465
- };
466
- };
467
- const refreshOAuthSession = async (input) => {
468
- if (!input.session.refreshToken || !input.session.clientId) throw new Error(`Session expired for ${input.config.osBaseUrl}. Run \`iterate login\` again.`);
469
- const authBaseUrl = input.config.authBaseUrl;
470
- const body = new URLSearchParams({
471
- grant_type: "refresh_token",
472
- client_id: input.session.clientId,
473
- refresh_token: input.session.refreshToken,
474
- resource: oauthResourceForOsBaseUrl(input.config.osBaseUrl)
475
- });
476
- if (input.session.scope) body.set("scope", input.session.scope);
477
- const response = await fetch(`${authBaseUrl}/api/auth/oauth2/token`, {
478
- method: "POST",
479
- headers: {
480
- "content-type": "application/x-www-form-urlencoded",
481
- origin: authBaseUrl
482
- },
483
- body
484
- });
485
- if (!response.ok) throw new Error(`OAuth refresh failed (${response.status}). Run \`iterate login\` again.`);
486
- const refreshedSession = oauthTokenToSession(await response.json(), input.session);
487
- refreshedSession.clientId = input.session.clientId;
488
- input.config.session = refreshedSession;
489
- if (input.configName) updateConfigSession(input.configName, refreshedSession);
490
- return refreshedSession;
491
- };
492
- const oauthLogin = async (config) => {
493
- const authBaseUrl = config.authBaseUrl;
494
- const resource = oauthResourceForOsBaseUrl(config.osBaseUrl);
495
- const codeVerifier = randomBase64Url(48);
496
- const state = randomBase64Url(32);
497
- const callback = await startOAuthCallbackServer();
498
- const clientId = await registerOAuthClient({
499
- authBaseUrl,
500
- redirectUri: callback.redirectUri
501
- });
502
- const authorizeUrl = new URL(`${authBaseUrl}/api/auth/oauth2/authorize`);
503
- authorizeUrl.searchParams.set("response_type", "code");
504
- authorizeUrl.searchParams.set("client_id", clientId);
505
- authorizeUrl.searchParams.set("redirect_uri", callback.redirectUri);
506
- authorizeUrl.searchParams.set("scope", OAUTH_SCOPE);
507
- authorizeUrl.searchParams.set("resource", resource);
508
- authorizeUrl.searchParams.set("state", state);
509
- authorizeUrl.searchParams.set("code_challenge", base64Url(createHash("sha256").update(codeVerifier).digest()));
510
- authorizeUrl.searchParams.set("code_challenge_method", "S256");
511
- console.error(`\nOpening browser to authenticate with Iterate:\n`);
512
- console.error(` ${authorizeUrl.href}\n`);
513
- if (!isAgent && process.env.ITERATE_SKIP_BROWSER_OPEN !== "1") await openUrlInBrowser(authorizeUrl.href);
514
- let callbackResult;
515
- try {
516
- callbackResult = await callback.wait();
517
- } finally {
518
- await callback.close().catch(() => {});
519
- }
520
- if (callbackResult.state !== state) throw new Error("OAuth callback state did not match. Please try again.");
521
- const session = oauthTokenToSession(await exchangeOAuthCode({
522
- authBaseUrl,
523
- clientId,
524
- code: callbackResult.code,
525
- codeVerifier,
526
- redirectUri: callbackResult.redirectUri,
527
- resource
528
- }), {
529
- clientId,
530
- refreshToken: void 0
531
- });
532
- session.clientId = clientId;
533
- return session;
534
- };
535
- const loginToResolvedConfig = async (resolved) => {
536
- const { config } = resolved;
537
- console.error(`Logging in to ${config.authBaseUrl}...`);
538
- const oauthResult = await oauthLogin(config);
539
- updateConfigSession(resolved.name, oauthResult);
540
- config.session = oauthResult;
541
- await verifyOsSession({
542
- authHeaders: await getOsAuthHeaders(config, resolved.name),
543
- baseUrl: config.osBaseUrl
544
- }).catch((error) => {
545
- throw new Error(`Failed to verify OS session: ${errorMessage(error)}`);
546
- });
547
- return oauthResult;
548
- };
549
- const shouldAutoLoginForChat = (error) => error instanceof StoredOsSessionError && (error.reason === "missing" || error.reason === "expired");
550
- const ensureBearerAuthHeadersForChat = async (input) => {
551
- let authHeaders = await input.getAuthHeaders();
552
- if (authHeaders.authorization) return authHeaders;
553
- console.error(`Stored session for ${input.osBaseUrl} cannot be used for chat. Starting browser login...`);
554
- await input.login();
555
- authHeaders = await input.getAuthHeaders();
556
- if (authHeaders.authorization) return authHeaders;
557
- throw new Error(`Stored session for ${input.osBaseUrl} has no bearer token. Run \`iterate login\` again.`);
558
- };
559
- const loadRemoteProcedures = async (params) => {
560
- const url = `${params.baseUrl}/api/trpc-cli-procedures`;
561
- const response = await fetch(url);
562
- if (!response.ok) {
563
- let text = await response.text();
564
- if (text.includes("<title>")) text = "HTML with title: " + text.split("<title>")[1].split("</title>")[0];
565
- else if ([
566
- "<html>",
567
- "<body>",
568
- "<head>",
569
- "!DOCTYPE html"
570
- ].some((s) => text.includes(s))) text = "<html>...</html>";
571
- else {
572
- text = text.split("\n")[0];
573
- if (text.length > 50) text = text.slice(0, 50) + "...";
574
- }
575
- throw new Error(`${url} got ${response.status}: ${text}`);
576
- }
577
- let router;
578
- try {
579
- router = await response.json();
580
- } catch (e) {
581
- const message = e instanceof Error ? e.message : String(e);
582
- throw new Error(`${url} returned invalid router: ${message}`);
583
- }
584
- if (!Array.isArray(router?.procedures)) throw new Error(`${url} returned invalid router: ${JSON.stringify(router)}`);
585
- return router;
586
- };
587
- /** Wraps an oRPC client so `wrapper[dotPath].query(input)` and `.mutate(input)` work (for trpc-cli proxify compat) */
588
- const orpcToTrpcStyleClient = (orpcClient) => {
589
- return new Proxy({}, { get: (_target, prop) => {
590
- const parts = prop.split(".");
591
- let current = orpcClient;
592
- for (const part of parts) current = current[part];
593
- return {
594
- query: (input) => current(input),
595
- mutate: (input) => current(input)
596
- };
597
- } });
598
- };
599
- const getOsProcedures = async (params) => {
600
- return proxifyOrpc((await loadRemoteProcedures(params)).procedures, () => {
601
- return orpcToTrpcStyleClient(createORPCClient(new RPCLink({
602
- url: `${params.baseUrl}/api/orpc/`,
603
- fetch: async (request, init) => {
604
- const authHeaders = await getOsAuthHeaders(params.config, params.configName);
605
- const headers = new Headers(request instanceof Request ? request.headers : init?.headers);
606
- if (authHeaders.cookie) headers.set("cookie", authHeaders.cookie);
607
- if (authHeaders.authorization) headers.set("authorization", authHeaders.authorization);
608
- return fetch(request, {
609
- ...init,
610
- headers
611
- });
612
- }
613
- })));
614
- });
615
- };
616
- const launcherProcedures = {
617
- ping: os.input(z.object({})).handler(async () => {
618
- const resolved = resolveConfig(process.cwd(), { throw: true });
619
- const { config } = resolved;
620
- return {
621
- message: "OS session valid",
622
- principal: (await verifyOsSession({
623
- authHeaders: await getOsAuthHeaders(config, resolved.name),
624
- baseUrl: config.osBaseUrl
625
- }).catch((error) => {
626
- throw new Error(`Failed to verify OS session: ${errorMessage(error)}`);
627
- })).principal
628
- };
629
- }),
630
- login: os.input(z.object({})).meta({ description: "Authenticate with the OS server via browser-based OAuth" }).handler(async () => {
631
- const oauthResult = await loginToResolvedConfig(resolveConfig(process.cwd(), { throw: true }));
632
- return {
633
- message: "Logged in successfully",
634
- expiresAt: oauthResult.expiresAt,
635
- scope: oauthResult.scope
636
- };
637
- }),
638
- logout: os.input(z.object({})).meta({ description: "Remove stored session for the current config" }).handler(async () => {
639
- const resolved = resolveConfig(process.cwd(), { throw: true });
640
- removeConfigSession(resolved.name);
641
- return { message: `Logged out from ${resolved.name} (${resolved.config.osBaseUrl})` };
642
- }),
643
- chat: os.input(z.object({
644
- project: z.string().trim().min(1).optional().describe("OS project id (prj_…) or slug. Defaults to the active config's defaultProject."),
645
- agentPath: z.string().trim().min(1).startsWith("/agents/").optional().default(DEFAULT_CHAT_AGENT_PATH).describe("Agent stream path to chat with (default: /agents/onboarding)")
646
- })).meta({ description: "Open the Iterate agent chat terminal UI" }).handler(async ({ input }) => {
647
- const resolved = resolveConfig(process.cwd(), { throw: true });
648
- const envAuth = osAuthFromEnvironment();
649
- let storedAuthHeaders;
650
- let didAutoLogin = false;
651
- const loginForChat = async () => {
652
- didAutoLogin = true;
653
- storedAuthHeaders = void 0;
654
- await loginToResolvedConfig(resolved);
655
- };
656
- const getStoredAuthHeaders = async () => {
657
- if (storedAuthHeaders) return storedAuthHeaders;
658
- try {
659
- storedAuthHeaders = await getOsAuthHeaders(resolved.config, resolved.name);
660
- } catch (error) {
661
- if (didAutoLogin || !shouldAutoLoginForChat(error)) throw error;
662
- console.error(`No active session for ${resolved.config.osBaseUrl}. Starting browser login...`);
663
- await loginForChat();
664
- storedAuthHeaders = await getOsAuthHeaders(resolved.config, resolved.name);
665
- }
666
- return storedAuthHeaders;
667
- };
668
- const getStoredBearerAuthHeaders = () => ensureBearerAuthHeadersForChat({
669
- getAuthHeaders: getStoredAuthHeaders,
670
- login: loginForChat,
671
- osBaseUrl: resolved.config.osBaseUrl
672
- });
673
- const project = await resolveChatProject({
674
- auth: envAuth ?? osAuthFromHeaders(await getStoredBearerAuthHeaders()),
675
- baseUrl: resolved.config.osBaseUrl,
676
- configName: resolved.name,
677
- configPath: CONFIG_PATH,
678
- configuredDefaultProject: resolved.config.defaultProject,
679
- explicitProject: input.project
680
- });
681
- const command = buildChatCommand({
682
- osBaseUrl: resolved.config.osBaseUrl,
683
- projectId: project,
684
- agentPath: input.agentPath,
685
- entrypointPath: resolveStreamTuiEntrypointPath()
686
- });
687
- const env = { ITERATE_CONFIG_NAME: resolved.name };
688
- if (!envAuth) {
689
- const token = (await getStoredBearerAuthHeaders()).authorization?.replace(/^Bearer /, "");
690
- if (!token) throw new Error(`Stored session for ${resolved.config.osBaseUrl} has no bearer token. Run \`iterate login\` again.`);
691
- env.ITERATE_BEARER_TOKEN = token;
692
- }
693
- await runInheritedProcess({
694
- ...command,
695
- env
696
- });
697
- }),
698
- orgs: { list: os.input(z.object({})).meta({ description: "List organizations from the auth worker" }).handler(async () => {
699
- return await (await getAuthWorkerClient(resolveConfig(process.cwd(), { throw: true }).config)).user.myOrganizations();
700
- }) },
701
- config: {
702
- get: os.input(z.object({})).meta({
703
- default: true,
704
- description: "Show config, resolved target, and session status"
705
- }).handler(async () => {
706
- const configFile = readConfigFile();
707
- const resolved = resolveConfig(process.cwd());
708
- const configs = configFile.configs || {};
709
- const sessions = Object.fromEntries(Object.entries(configs).map(([name, cfg]) => {
710
- if (!cfg.session) return [name, null];
711
- return [name, {
712
- hasToken: Boolean(cfg.session?.token),
713
- hasCookie: Boolean(cfg.session?.cookie),
714
- expiresAt: cfg.session?.expiresAt,
715
- expired: cfg.session?.expiresAt ? new Date(cfg.session.expiresAt) < /* @__PURE__ */ new Date() : false
716
- }];
717
- }));
718
- if (resolved instanceof Error) return {
719
- configPath: CONFIG_PATH,
720
- error: resolved.message
721
- };
722
- return {
723
- configPath: CONFIG_PATH,
724
- config: resolved.name,
725
- ...resolved.config,
726
- session: sessions[resolved.name]
727
- };
728
- }),
729
- list: os.input(z.object({})).meta({ description: "List all named configs" }).handler(async () => {
730
- const configFile = readConfigFile();
731
- const currentName = resolveConfigName(process.cwd());
732
- const configs = {
733
- ["prd"]: {},
734
- ...configFile.configs || {}
735
- };
736
- return {
737
- configs: Object.fromEntries(Object.entries(configs).map(([name, cfg]) => [name, {
738
- osBaseUrl: Config.parse(cfg).osBaseUrl,
739
- active: name === currentName ? true : void 0
740
- }])),
741
- default: configFile.default
742
- };
743
- }),
744
- set: os.input(z.object({
745
- name: z.string().describe("Config name (e.g. dev, prd, preview)"),
746
- osBaseUrl: z.string().optional().describe("Base URL for OS API (e.g. https://os.iterate.com)"),
747
- authBaseUrl: z.string().optional().describe("Base URL for auth API (e.g. https://auth.iterate.com)"),
748
- setDefault: z.boolean().optional().describe("Set as the default config"),
749
- setWorkspace: z.boolean().optional().describe("Map current directory to this config")
750
- })).meta({
751
- prompt: true,
752
- description: "Create or update a named config"
753
- }).handler(async ({ input }) => {
754
- const configFile = readConfigFile();
755
- configFile.configs ||= {};
756
- configFile.configs[input.name] ||= {};
757
- if (input.osBaseUrl) configFile.configs[input.name].osBaseUrl = input.osBaseUrl;
758
- if (input.authBaseUrl) configFile.configs[input.name].authBaseUrl = input.authBaseUrl;
759
- if (input.setDefault) configFile.default = input.name;
760
- if (input.setWorkspace) {
761
- configFile.workspaces ||= {};
762
- configFile.workspaces[process.cwd()] = input.name;
763
- }
764
- writeConfigFile(configFile);
765
- return {
766
- configPath: CONFIG_PATH,
767
- config: configFile.configs[input.name]
768
- };
769
- }),
770
- use: os.input(z.object({ name: z.string().meta({ positional: true }).describe("Config name to set as default") })).meta({ description: "Set the default config" }).handler(async ({ input }) => {
771
- const configFile = readConfigFile();
772
- if (input.name !== "prd" && !configFile.configs?.[input.name]) throw new Error(`Config "${input.name}" not found. Available: ${Object.keys(configFile.configs || {}).join(", ") || "(none)"}`);
773
- configFile.default = input.name;
774
- writeConfigFile(configFile);
775
- return { default: input.name };
776
- }),
777
- current: os.input(z.object({})).meta({ description: "Show which config is active and why" }).handler(async () => {
778
- const resolved = resolveConfig(process.cwd(), { throw: true });
779
- return {
780
- name: resolved.name,
781
- config: resolved.config,
782
- resolvedAuthBaseUrl: resolved.config.authBaseUrl,
783
- resolvedVia: configFlagOverride ? "--config flag" : "workspace mapping or default"
784
- };
785
- })
786
- }
787
- };
788
- const getCli = async () => {
789
- configFlagOverride = consumeCliStringFlag("--config");
790
- applyDefaultBareInvocation();
791
- const requestedRootCommand = firstNonFlagArgument(process.argv.slice(2));
792
- const shouldLoadRemoteRouters = !requestedRootCommand || !Object.prototype.hasOwnProperty.call(launcherProcedures, requestedRootCommand);
793
- const errorProcedure = (problem) => (e) => {
794
- const message = `${problem}: ${e.message}`;
795
- return os.meta({ description: message }).handler(() => {
796
- throw new Error(problem, { cause: e });
797
- });
798
- };
799
- const routers = [launcherProcedures];
800
- if (shouldLoadRemoteRouters) {
801
- const resolved = resolveConfig(process.cwd());
802
- if (resolved instanceof Error) {
803
- const procedure = errorProcedure(`Invalid config`)(resolved);
804
- routers.push({
805
- os: procedure,
806
- daemon: procedure
807
- });
808
- } else {
809
- const { config } = resolved;
810
- const [osProcedures] = await Promise.allSettled([getOsProcedures({
811
- baseUrl: config.osBaseUrl,
812
- config,
813
- configName: resolved.name
814
- })]);
815
- if (osProcedures.status === "fulfilled") routers.push({ os: osProcedures.value });
816
- else {
817
- const message = `Couldn't connect to os at ${config.osBaseUrl}`;
818
- routers.push({ os: errorProcedure(message)(osProcedures.reason) });
819
- }
820
- }
821
- }
822
- return {
823
- cli: createCli({
824
- router: Object.assign({}, ...routers),
825
- name: "iterate",
826
- version: "0.0.1",
827
- description: "Iterate CLI"
828
- }),
829
- prompts: isAgent ? void 0 : prompts
830
- };
831
- };
832
- const runCli = async () => {
833
- const { cli, prompts: cliPrompts } = await getCli();
834
- await cli.run({
835
- prompts: cliPrompts,
836
- logger: yamlTableConsoleLogger
837
- });
838
- };
839
- const proxifyOrpc = (router, getClient) => {
840
- const parsed = Array.isArray(router) ? router : parseRouter({ router });
841
- const outputRouterRecord = {};
842
- for (const [procedurePath, info] of parsed) {
843
- const parts = procedurePath.split(".");
844
- let currentRouter = outputRouterRecord;
845
- for (const part of parts.slice(0, -1)) currentRouter = currentRouter[part] ||= {};
846
- const schemas = info.inputSchemas.success ? info.inputSchemas.value : [];
847
- const standardSchema = {
848
- "~standard": {
849
- vendor: "trpc-cli",
850
- version: 1,
851
- validate: (value) => ({ value })
852
- },
853
- toJsonSchema: () => {
854
- if (schemas.length === 0) return {};
855
- if (schemas.length === 1) return schemas[0];
856
- return { allOf: schemas };
857
- }
858
- };
859
- currentRouter[parts[parts.length - 1]] = os.input(standardSchema).handler(async ({ input }) => {
860
- return (await getClient(procedurePath))[procedurePath].query(input);
861
- });
862
- }
863
- return outputRouterRecord;
864
- };
865
- //#endregion
866
- export { runCli };
867
-
868
- //# sourceMappingURL=cli-DMS4kJph.mjs.map