pennyrouter 0.3.32 → 0.3.33
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/package.json +1 -1
- package/src/cli.js +37 -14
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1595,9 +1595,7 @@ async function selectCodexFundingProviders(flags, selected) {
|
|
|
1595
1595
|
|
|
1596
1596
|
console.log("PennyRouter can use your ChatGPT subscription, an OpenAI API key, an OpenAI-compatible proxy, or an OpenRouter API key to run Codex.");
|
|
1597
1597
|
console.log("Choose one or more providers. PennyRouter will try them in order when available.");
|
|
1598
|
-
const options = CODEX_PROVIDER_OPTIONS
|
|
1599
|
-
({ id }) => id !== "subscription" || hasChatgptLogin,
|
|
1600
|
-
);
|
|
1598
|
+
const options = CODEX_PROVIDER_OPTIONS;
|
|
1601
1599
|
return promptFundingProviderCheckboxes(
|
|
1602
1600
|
options,
|
|
1603
1601
|
"Which funding source should PennyRouter use for Codex?",
|
|
@@ -1703,7 +1701,7 @@ async function configureUserFunding(flags, selected, claudeAnthropicAuth,
|
|
|
1703
1701
|
|| process.env.PENNYROUTER_ANTHROPIC_PROXY_API_KEY
|
|
1704
1702
|
|| process.env.PENNYROUTER_PROXY_API_KEY || "",
|
|
1705
1703
|
).trim();
|
|
1706
|
-
|
|
1704
|
+
let codexSubscriptionAuth = wantsCodex && codexProviders.has("subscription")
|
|
1707
1705
|
? await detectCodexChatgptAuth()
|
|
1708
1706
|
: false;
|
|
1709
1707
|
|
|
@@ -1729,9 +1727,15 @@ async function configureUserFunding(flags, selected, claudeAnthropicAuth,
|
|
|
1729
1727
|
}
|
|
1730
1728
|
}
|
|
1731
1729
|
if (wantsCodex && codexProviders.has("subscription") && !codexSubscriptionAuth) {
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1730
|
+
console.log("Codex needs to sign in to your ChatGPT account. Starting `codex login`...");
|
|
1731
|
+
const login = spawnSync("codex", ["login"], {
|
|
1732
|
+
stdio: "inherit",
|
|
1733
|
+
shell: process.platform === "win32",
|
|
1734
|
+
});
|
|
1735
|
+
if (login.error || login.status !== 0 || !(await detectCodexChatgptAuth())) {
|
|
1736
|
+
throw new Error("Codex login did not complete. Run `codex login`, then rerun `npx pennyrouter install`.");
|
|
1737
|
+
}
|
|
1738
|
+
codexSubscriptionAuth = true;
|
|
1735
1739
|
}
|
|
1736
1740
|
if (wantsCodex && codexProviders.has("openai-api") && !openaiApiKey) {
|
|
1737
1741
|
if (!interactive) throw new Error("OpenAI API was selected, but no key was provided.");
|
|
@@ -2129,14 +2133,17 @@ async function selectHarnesses(flags) {
|
|
|
2129
2133
|
}
|
|
2130
2134
|
|
|
2131
2135
|
const detected = [];
|
|
2136
|
+
const available = [];
|
|
2132
2137
|
for (const id of DEFAULT_INSTALL_HARNESS_IDS) {
|
|
2133
2138
|
const harness = HARNESS_BY_ID[id];
|
|
2134
|
-
|
|
2139
|
+
const installed = await safeDetect(harness);
|
|
2140
|
+
if (installed) detected.push(harness);
|
|
2141
|
+
available.push({ ...harness, installed });
|
|
2135
2142
|
}
|
|
2136
2143
|
|
|
2137
2144
|
if (flags.yes) return detected;
|
|
2138
2145
|
|
|
2139
|
-
return promptHarnessCheckboxes(detected);
|
|
2146
|
+
return promptHarnessCheckboxes(available, detected);
|
|
2140
2147
|
}
|
|
2141
2148
|
|
|
2142
2149
|
async function printAdditionalHarnessesHint(selected) {
|
|
@@ -2153,10 +2160,14 @@ async function printAdditionalHarnessesHint(selected) {
|
|
|
2153
2160
|
console.log(`To use PennyRouter with ${names}, install ${available.length === 1 ? "it" : "them"} and re-run \`npx pennyrouter install\`.`);
|
|
2154
2161
|
}
|
|
2155
2162
|
|
|
2156
|
-
async function promptHarnessCheckboxes(detected) {
|
|
2163
|
+
async function promptHarnessCheckboxes(available, detected) {
|
|
2157
2164
|
const detectedIds = new Set(detected.map((harness) => harness.id));
|
|
2158
2165
|
const selectedIds = new Set(detectedIds);
|
|
2159
|
-
const harnesses = orderedHarnessesForPrompt(
|
|
2166
|
+
const harnesses = orderedHarnessesForPrompt(new Set(available.map((harness) => harness.id)))
|
|
2167
|
+
.map((harness) => ({
|
|
2168
|
+
...harness,
|
|
2169
|
+
installed: available.find((item) => item.id === harness.id)?.installed ?? false,
|
|
2170
|
+
}));
|
|
2160
2171
|
if (!input.isTTY || !output.isTTY) return promptHarnessCheckboxesByText(harnesses, selectedIds);
|
|
2161
2172
|
|
|
2162
2173
|
return promptHarnessCheckboxesByKeys(harnesses, selectedIds);
|
|
@@ -2178,7 +2189,8 @@ async function promptHarnessCheckboxesByKeys(harnesses, selectedIds) {
|
|
|
2178
2189
|
harnesses.forEach((harness, index) => {
|
|
2179
2190
|
const pointer = index === cursor ? color(">", "cyan") : " ";
|
|
2180
2191
|
const checked = selectedIds.has(harness.id) ? color("x", "green") : " ";
|
|
2181
|
-
const
|
|
2192
|
+
const label = harness.installed ? harness.name : `${harness.name} (install ${harness.name} first)`;
|
|
2193
|
+
const name = harness.installed && index === cursor ? color(label, "cyan") : label;
|
|
2182
2194
|
output.write(` ${pointer} [${checked}] ${name}\n`);
|
|
2183
2195
|
});
|
|
2184
2196
|
output.write("\nEnter to continue.\n");
|
|
@@ -2215,7 +2227,12 @@ async function promptHarnessCheckboxesByKeys(harnesses, selectedIds) {
|
|
|
2215
2227
|
}
|
|
2216
2228
|
|
|
2217
2229
|
if (key.name === "space") {
|
|
2218
|
-
const
|
|
2230
|
+
const harness = harnesses[cursor];
|
|
2231
|
+
if (!harness.installed) {
|
|
2232
|
+
render();
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
2235
|
+
const id = harness.id;
|
|
2219
2236
|
if (selectedIds.has(id)) selectedIds.delete(id);
|
|
2220
2237
|
else selectedIds.add(id);
|
|
2221
2238
|
render();
|
|
@@ -2242,7 +2259,8 @@ async function promptHarnessCheckboxesByText(harnesses, selectedIds) {
|
|
|
2242
2259
|
console.log(color("Where should PennyRouter be installed?", "bold"));
|
|
2243
2260
|
for (const harness of harnesses) {
|
|
2244
2261
|
const checked = selectedIds.has(harness.id) ? color("x", "green") : " ";
|
|
2245
|
-
|
|
2262
|
+
const label = harness.installed ? harness.name : `${harness.name} (install ${harness.name} first)`;
|
|
2263
|
+
console.log(` [${checked}] ${label}`);
|
|
2246
2264
|
}
|
|
2247
2265
|
console.log("");
|
|
2248
2266
|
const answer = await rl.question(
|
|
@@ -2261,6 +2279,11 @@ async function promptHarnessCheckboxesByText(harnesses, selectedIds) {
|
|
|
2261
2279
|
console.log(`Unknown tool "${token}".`);
|
|
2262
2280
|
continue;
|
|
2263
2281
|
}
|
|
2282
|
+
if (!harnesses.find((harness) => harness.id === id)?.installed) {
|
|
2283
|
+
const unavailable = HARNESS_BY_ID[id];
|
|
2284
|
+
console.log(`Install ${unavailable.name} first to select it.`);
|
|
2285
|
+
continue;
|
|
2286
|
+
}
|
|
2264
2287
|
if (selectedIds.has(id)) selectedIds.delete(id);
|
|
2265
2288
|
else selectedIds.add(id);
|
|
2266
2289
|
}
|