@pruddiman/dispatch 1.5.0-beta.d367268-beta.59288b9 → 1.5.0-beta.e74ea4e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1760,13 +1760,18 @@ async function checkCopilotAuth() {
1760
1760
  return { status: "authenticated" };
1761
1761
  }
1762
1762
  try {
1763
- await exec3("gh", ["auth", "status"], { timeout: AUTH_PROBE_TIMEOUT_MS });
1763
+ await exec3("copilot", ["auth", "status"], { timeout: AUTH_PROBE_TIMEOUT_MS });
1764
1764
  return { status: "authenticated" };
1765
1765
  } catch {
1766
- return {
1767
- status: "not-configured",
1768
- hint: "Set GH_TOKEN or GITHUB_TOKEN, or run 'gh auth login'"
1769
- };
1766
+ try {
1767
+ await exec3("gh", ["auth", "status"], { timeout: AUTH_PROBE_TIMEOUT_MS });
1768
+ return { status: "authenticated" };
1769
+ } catch {
1770
+ return {
1771
+ status: "not-configured",
1772
+ hint: "Run 'copilot login' or set GITHUB_TOKEN"
1773
+ };
1774
+ }
1770
1775
  }
1771
1776
  }
1772
1777
  async function checkClaudeAuth() {
@@ -1779,7 +1784,7 @@ async function checkClaudeAuth() {
1779
1784
  } catch {
1780
1785
  return {
1781
1786
  status: "not-configured",
1782
- hint: "Set ANTHROPIC_API_KEY or run 'claude login'"
1787
+ hint: "Run 'claude auth login' or set ANTHROPIC_API_KEY"
1783
1788
  };
1784
1789
  }
1785
1790
  }
@@ -1787,19 +1792,32 @@ async function checkCodexAuth() {
1787
1792
  if (process.env.OPENAI_API_KEY) {
1788
1793
  return { status: "authenticated" };
1789
1794
  }
1790
- return {
1791
- status: "not-configured",
1792
- hint: "Set OPENAI_API_KEY environment variable"
1793
- };
1795
+ try {
1796
+ await exec3("codex", ["auth", "status"], { timeout: AUTH_PROBE_TIMEOUT_MS });
1797
+ return { status: "authenticated" };
1798
+ } catch {
1799
+ return {
1800
+ status: "not-configured",
1801
+ hint: "Run 'codex login --device-auth' or set OPENAI_API_KEY"
1802
+ };
1803
+ }
1794
1804
  }
1795
1805
  async function checkOpencodeAuth() {
1796
1806
  try {
1797
1807
  await exec3("opencode", ["--version"], { timeout: AUTH_PROBE_TIMEOUT_MS });
1808
+ } catch {
1809
+ return {
1810
+ status: "not-configured",
1811
+ hint: "Install OpenCode (https://opencode.ai)"
1812
+ };
1813
+ }
1814
+ try {
1815
+ await exec3("opencode", ["auth", "status"], { timeout: AUTH_PROBE_TIMEOUT_MS });
1798
1816
  return { status: "authenticated" };
1799
1817
  } catch {
1800
1818
  return {
1801
1819
  status: "not-configured",
1802
- hint: "Install and configure OpenCode (https://opencode.ai)"
1820
+ hint: "Run 'opencode auth login' or set provider API keys"
1803
1821
  };
1804
1822
  }
1805
1823
  }
@@ -2080,28 +2098,28 @@ async function setupCopilotAuth() {
2080
2098
  const method = await select({
2081
2099
  message: "How would you like to authenticate?",
2082
2100
  choices: [
2083
- { name: "GitHub CLI (gh auth login)", value: "gh-cli", description: "Uses the GitHub CLI's device flow" },
2084
- { name: "Environment variable", value: "env-var", description: "Set GITHUB_TOKEN or GH_TOKEN manually" }
2101
+ { name: "Copilot CLI login", value: "cli-login", description: "Run 'copilot login' \u2014 device code flow" },
2102
+ { name: "API key (environment variable)", value: "env-var", description: "Set GITHUB_TOKEN or GH_TOKEN manually" }
2085
2103
  ]
2086
2104
  });
2087
- if (method === "gh-cli") {
2105
+ if (method === "cli-login") {
2088
2106
  try {
2089
- log.info("Running 'gh auth login'...");
2107
+ log.info("Running 'copilot login'...");
2090
2108
  const { spawn } = await import("child_process");
2091
2109
  await new Promise((resolve5, reject) => {
2092
- const child = spawn("gh", ["auth", "login"], {
2110
+ const child = spawn("copilot", ["login"], {
2093
2111
  stdio: "inherit",
2094
2112
  timeout: AUTH_CMD_TIMEOUT_MS
2095
2113
  });
2096
2114
  child.on(
2097
2115
  "close",
2098
- (code) => code === 0 ? resolve5() : reject(new Error(`gh auth login exited with code ${code}`))
2116
+ (code) => code === 0 ? resolve5() : reject(new Error(`copilot login exited with code ${code}`))
2099
2117
  );
2100
2118
  child.on("error", reject);
2101
2119
  });
2102
2120
  return await verifyAuth("copilot");
2103
2121
  } catch (err) {
2104
- log.warn(`GitHub CLI auth failed: ${err instanceof Error ? err.message : String(err)}`);
2122
+ log.warn(`Copilot CLI auth failed: ${err instanceof Error ? err.message : String(err)}`);
2105
2123
  return false;
2106
2124
  }
2107
2125
  }
@@ -2118,28 +2136,28 @@ async function setupClaudeAuth() {
2118
2136
  const method = await select({
2119
2137
  message: "How would you like to authenticate?",
2120
2138
  choices: [
2121
- { name: "API key (ANTHROPIC_API_KEY)", value: "api-key", description: "Paste your Anthropic API key" },
2122
- { name: "Claude CLI login", value: "cli-login", description: "Run 'claude login' \u2014 opens a browser" }
2139
+ { name: "Claude CLI login", value: "cli-login", description: "Run 'claude auth login' \u2014 opens a browser" },
2140
+ { name: "API key (environment variable)", value: "env-var", description: "Set ANTHROPIC_API_KEY manually" }
2123
2141
  ]
2124
2142
  });
2125
2143
  if (method === "cli-login") {
2126
2144
  try {
2127
- log.info("Running 'claude login'...");
2145
+ log.info("Running 'claude auth login'...");
2128
2146
  const { spawn } = await import("child_process");
2129
2147
  await new Promise((resolve5, reject) => {
2130
- const child = spawn("claude", ["login"], {
2148
+ const child = spawn("claude", ["auth", "login"], {
2131
2149
  stdio: "inherit",
2132
2150
  timeout: AUTH_CMD_TIMEOUT_MS
2133
2151
  });
2134
2152
  child.on(
2135
2153
  "close",
2136
- (code) => code === 0 ? resolve5() : reject(new Error(`claude login exited with code ${code}`))
2154
+ (code) => code === 0 ? resolve5() : reject(new Error(`claude auth login exited with code ${code}`))
2137
2155
  );
2138
2156
  child.on("error", reject);
2139
2157
  });
2140
2158
  return await verifyAuth("claude");
2141
2159
  } catch (err) {
2142
- log.warn(`Claude login failed: ${err instanceof Error ? err.message : String(err)}`);
2160
+ log.warn(`Claude CLI auth failed: ${err instanceof Error ? err.message : String(err)}`);
2143
2161
  return false;
2144
2162
  }
2145
2163
  }
@@ -2152,6 +2170,34 @@ async function setupClaudeAuth() {
2152
2170
  async function setupCodexAuth() {
2153
2171
  log.info("OpenAI Codex Authentication");
2154
2172
  console.log();
2173
+ const method = await select({
2174
+ message: "How would you like to authenticate?",
2175
+ choices: [
2176
+ { name: "ChatGPT sign-in", value: "cli-login", description: "Run 'codex login --device-auth' \u2014 device code flow" },
2177
+ { name: "API key (environment variable)", value: "env-var", description: "Set OPENAI_API_KEY manually" }
2178
+ ]
2179
+ });
2180
+ if (method === "cli-login") {
2181
+ try {
2182
+ log.info("Running 'codex login --device-auth'...");
2183
+ const { spawn } = await import("child_process");
2184
+ await new Promise((resolve5, reject) => {
2185
+ const child = spawn("codex", ["login", "--device-auth"], {
2186
+ stdio: "inherit",
2187
+ timeout: AUTH_CMD_TIMEOUT_MS
2188
+ });
2189
+ child.on(
2190
+ "close",
2191
+ (code) => code === 0 ? resolve5() : reject(new Error(`codex login exited with code ${code}`))
2192
+ );
2193
+ child.on("error", reject);
2194
+ });
2195
+ return await verifyAuth("codex");
2196
+ } catch (err) {
2197
+ log.warn(`Codex CLI auth failed: ${err instanceof Error ? err.message : String(err)}`);
2198
+ return false;
2199
+ }
2200
+ }
2155
2201
  log.info("Set the following environment variable in your shell profile:");
2156
2202
  log.info(" OPENAI_API_KEY=<your API key>");
2157
2203
  console.log();
@@ -2161,10 +2207,40 @@ async function setupCodexAuth() {
2161
2207
  async function setupOpencodeAuth() {
2162
2208
  log.info("OpenCode Authentication");
2163
2209
  console.log();
2164
- log.info("OpenCode uses its own configuration system.");
2165
- log.info("Run 'opencode' to set up your providers and API keys.");
2210
+ const method = await select({
2211
+ message: "How would you like to authenticate?",
2212
+ choices: [
2213
+ { name: "OpenCode CLI login", value: "cli-login", description: "Run 'opencode auth login' interactively" },
2214
+ { name: "API key (environment variable)", value: "env-var", description: "Set provider API keys manually" }
2215
+ ]
2216
+ });
2217
+ if (method === "cli-login") {
2218
+ try {
2219
+ log.info("Running 'opencode auth login'...");
2220
+ const { spawn } = await import("child_process");
2221
+ await new Promise((resolve5, reject) => {
2222
+ const child = spawn("opencode", ["auth", "login"], {
2223
+ stdio: "inherit",
2224
+ timeout: AUTH_CMD_TIMEOUT_MS
2225
+ });
2226
+ child.on(
2227
+ "close",
2228
+ (code) => code === 0 ? resolve5() : reject(new Error(`opencode auth login exited with code ${code}`))
2229
+ );
2230
+ child.on("error", reject);
2231
+ });
2232
+ return await verifyAuth("opencode");
2233
+ } catch (err) {
2234
+ log.warn(`OpenCode CLI auth failed: ${err instanceof Error ? err.message : String(err)}`);
2235
+ return false;
2236
+ }
2237
+ }
2238
+ log.info("Set the relevant API key environment variable in your shell profile.");
2239
+ log.info("For example:");
2240
+ log.info(" ANTHROPIC_API_KEY=<your API key>");
2241
+ log.info(" OPENAI_API_KEY=<your API key>");
2166
2242
  console.log();
2167
- log.dim("After configuring OpenCode, re-run 'dispatch config'.");
2243
+ log.dim("After setting the variable, restart your terminal and re-run 'dispatch config'.");
2168
2244
  return false;
2169
2245
  }
2170
2246
  async function verifyAuth(name) {
@@ -2237,25 +2313,41 @@ async function runInteractiveConfigWizard(configDir) {
2237
2313
  console.log(`${indicator} ${ps.displayName.padEnd(18)} ${statusLabel} ${tierLabel}`);
2238
2314
  }
2239
2315
  console.log();
2240
- const unauthenticated = providerStatuses.filter(
2241
- (ps) => ps.authStatus.status !== "authenticated"
2242
- );
2243
- if (unauthenticated.length > 0) {
2244
- for (const ps of unauthenticated) {
2245
- const wantSetup = await confirm({
2246
- message: `Set up authentication for ${ps.displayName}?`,
2247
- default: false
2248
- });
2249
- if (wantSetup) {
2250
- console.log();
2251
- await setupProviderAuth(ps.name);
2252
- console.log();
2253
- }
2316
+ log.info("Select which providers you want to enable:");
2317
+ console.log();
2318
+ const selectedProviders = [];
2319
+ for (const ps of providerStatuses) {
2320
+ const isAuth = ps.authStatus.status === "authenticated";
2321
+ const suffix = !isAuth ? " (not yet authenticated)" : "";
2322
+ const enable = await confirm({
2323
+ message: `Enable ${ps.displayName}?${suffix}`,
2324
+ default: isAuth
2325
+ });
2326
+ if (enable) selectedProviders.push(ps.name);
2327
+ }
2328
+ if (selectedProviders.length === 0) {
2329
+ log.error("At least one provider must be enabled to use Dispatch.");
2330
+ log.dim("Re-run 'dispatch config' to enable providers.");
2331
+ return;
2332
+ }
2333
+ const needsAuth = selectedProviders.filter((name) => {
2334
+ const ps = providerStatuses.find((p) => p.name === name);
2335
+ return ps && ps.authStatus.status !== "authenticated";
2336
+ });
2337
+ if (needsAuth.length > 0) {
2338
+ console.log();
2339
+ for (const name of needsAuth) {
2340
+ console.log();
2341
+ await setupProviderAuth(name);
2342
+ console.log();
2254
2343
  }
2255
2344
  providerStatuses = await getProviderStatuses();
2256
2345
  }
2257
- const authenticatedProviders = providerStatuses.filter((ps) => ps.authStatus.status === "authenticated").map((ps) => ps.name);
2258
- if (authenticatedProviders.length === 0) {
2346
+ const enabledProviders = selectedProviders.filter((name) => {
2347
+ const ps = providerStatuses.find((p) => p.name === name);
2348
+ return ps && ps.authStatus.status === "authenticated";
2349
+ });
2350
+ if (enabledProviders.length === 0) {
2259
2351
  log.error("At least one provider must be authenticated to use Dispatch.");
2260
2352
  log.dim("Re-run 'dispatch config' after setting up provider credentials.");
2261
2353
  return;
@@ -2263,12 +2355,13 @@ async function runInteractiveConfigWizard(configDir) {
2263
2355
  console.log();
2264
2356
  log.info("Provider status:");
2265
2357
  for (const ps of providerStatuses) {
2266
- const indicator = ps.authStatus.status === "authenticated" ? "\u2713" : "\u2717";
2358
+ const isEnabled = enabledProviders.includes(ps.name);
2359
+ const indicator = isEnabled ? "\u2713" : "\u2717";
2267
2360
  console.log(` ${indicator} ${ps.displayName}`);
2268
2361
  }
2269
2362
  console.log();
2270
2363
  log.info(
2271
- `${authenticatedProviders.length} provider(s) ready. Dispatch will automatically route tasks to the best available provider.`
2364
+ `${enabledProviders.length} provider(s) enabled. Dispatch will automatically route tasks to the best available provider.`
2272
2365
  );
2273
2366
  console.log();
2274
2367
  const detectedSource = await detectDatasource(process.cwd());
@@ -2346,7 +2439,7 @@ async function runInteractiveConfigWizard(configDir) {
2346
2439
  const existingConfig = await loadConfig(configDir);
2347
2440
  const newConfig = {
2348
2441
  ...existingConfig,
2349
- enabledProviders: authenticatedProviders,
2442
+ enabledProviders,
2350
2443
  source
2351
2444
  };
2352
2445
  if (org !== void 0) newConfig.org = org;
@@ -8773,7 +8866,7 @@ async function main() {
8773
8866
  process.exit(0);
8774
8867
  }
8775
8868
  if (args.version) {
8776
- console.log(`dispatch v${"1.5.0-beta.d367268-beta.59288b9"}`);
8869
+ console.log(`dispatch v${"1.5.0-beta.e74ea4e"}`);
8777
8870
  process.exit(0);
8778
8871
  }
8779
8872
  const orchestrator = await boot5({ cwd: args.cwd });