Skip to content

Commit d98fb4a

Browse files
committed
Overhaul onboarding routes and model controls
1 parent 6cc9c54 commit d98fb4a

20 files changed

Lines changed: 492 additions & 519 deletions

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,19 @@ Release tags use the form `vX.Y.Z` and match `package.json`. GitHub Releases car
99

1010
## [Unreleased]
1111

12+
## [0.5.5] - 2026-07-20
13+
14+
### Added
15+
16+
- Back navigation throughout onboarding with in-progress form and route state preserved.
17+
- All On and All Off controls for every connected account's model list.
18+
- Direct API-key links for OpenRouter and NVIDIA NIM connection forms.
19+
1220
### Changed
1321

22+
- Reworked Routes into a compact card grid with whole-card editing and a focused editor.
23+
- Added drag-and-drop route-member ordering alongside the existing accessible arrow controls.
24+
- Removed onboarding credential autodetection and its renderer, dashboard, CLI, and IPC paths.
1425
- Formalized project governance, release lifecycle, PR/release note expectations, and repository hygiene (branch cleanup, merge defaults, maintainer docs).
1526

1627
## [0.5.4] - 2026-07-18
@@ -63,7 +74,8 @@ Release tags use the form `vX.Y.Z` and match `package.json`. GitHub Releases car
6374

6475
See [GitHub Releases](https://github.com/gitcommit90/rerouted/releases) for artifact digests and notes prior to the Keep a Changelog narrative. Notable themes in late 0.4.x included signed/notarized distribution, in-app updates, named routes, OAuth account pools, OpenAI chat completions and Responses routing, and launch hardening.
6576

66-
[Unreleased]: https://github.com/gitcommit90/rerouted/compare/v0.5.4...HEAD
77+
[Unreleased]: https://github.com/gitcommit90/rerouted/compare/v0.5.5...HEAD
78+
[0.5.5]: https://github.com/gitcommit90/rerouted/releases/tag/v0.5.5
6779
[0.5.4]: https://github.com/gitcommit90/rerouted/releases/tag/v0.5.4
6880
[0.5.3]: https://github.com/gitcommit90/rerouted/releases/tag/v0.5.3
6981
[0.5.2]: https://github.com/gitcommit90/rerouted/releases/tag/v0.5.2

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@gitcommit90/rerouted",
33
"productName": "ReRouted",
4-
"version": "0.5.4",
4+
"version": "0.5.5",
55
"description": "A local AI router for connected accounts, models, named routes, and automatic fallback.",
66
"author": "gitcommit90",
77
"license": "MIT",

scripts/capture-ui.js

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -293,29 +293,6 @@ function registerIpc() {
293293
ipcMain.handle("app:set-admin-password", async () => ({ ok: true }));
294294
ipcMain.handle("app:verify-admin-password", async () => ({ ok: true }));
295295
ipcMain.handle("app:change-admin-password", async () => ({ ok: true }));
296-
ipcMain.handle("app:detect-providers", async () => ({
297-
ok: true,
298-
found: [
299-
{
300-
id: "det1",
301-
type: "chatgpt",
302-
name: "ChatGPT",
303-
source: "codex-cli",
304-
hasAccess: true,
305-
hasRefresh: true,
306-
},
307-
{
308-
id: "det2",
309-
type: "antigravity",
310-
name: "Antigravity (user@example.com)",
311-
source: "antigravity-file",
312-
email: "user@example.com",
313-
hasAccess: true,
314-
hasRefresh: true,
315-
},
316-
],
317-
}));
318-
ipcMain.handle("app:import-detected", async () => ({ ok: true }));
319296
ipcMain.handle("app:oauth-start", async () => {
320297
oauthStartsInFlight += 1;
321298
await new Promise((resolve) => setTimeout(resolve, 150));
@@ -432,7 +409,6 @@ const ONBOARD_STEPS = [
432409
"permissions",
433410
"admin-password",
434411
"welcome",
435-
"auto-detect",
436412
"oauth-providers",
437413
"api-keys",
438414
"endpoint-ready",
@@ -534,24 +510,18 @@ app.whenReady().then(async () => {
534510
})()
535511
`);
536512
await sleep(500);
537-
// For auto-detect, click scan to show results state
538-
if (step === "auto-detect") {
539-
await win.webContents.executeJavaScript(`
540-
(async () => {
541-
const b = document.getElementById("btn-scan");
542-
if (b) { b.click(); await new Promise(r => setTimeout(r, 400)); }
543-
const results = document.getElementById("detect-results");
544-
if (!results?.textContent.includes("use*@example.com")) {
545-
throw new Error("Detected account email was not privacy masked");
546-
}
547-
if (results.outerHTML.includes("user@example.com")) {
548-
throw new Error("Raw detected account email leaked into onboarding markup");
549-
}
550-
return true;
551-
})()
552-
`);
553-
await sleep(400);
554-
}
513+
await win.webContents.executeJavaScript(`
514+
(() => {
515+
const step = ${JSON.stringify(step)};
516+
if (step !== "permissions" && !document.querySelector("[data-onboarding-back], #btn-back")) {
517+
throw new Error("Missing onboarding Back control for " + step);
518+
}
519+
if (step === "permissions" && document.querySelector("[data-onboarding-back], #btn-back")) {
520+
throw new Error("First onboarding step must not show Back");
521+
}
522+
return true;
523+
})()
524+
`);
555525
await capture(`onboard-${step}.png`, "#view > *");
556526
}
557527

@@ -682,7 +652,7 @@ app.whenReady().then(async () => {
682652
await win.webContents.executeJavaScript(`
683653
(async () => {
684654
window.__rr_goto_page("combos");
685-
document.querySelector("button[data-edit]")?.click();
655+
document.querySelector("button[data-edit-index]")?.click();
686656
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
687657
let account = document.getElementById("c-add-account");
688658
let model = document.getElementById("c-add-model");
@@ -1151,7 +1121,7 @@ app.whenReady().then(async () => {
11511121
await win.webContents.executeJavaScript(`
11521122
(() => {
11531123
window.__rr_goto_page("combos");
1154-
document.querySelector("button[data-edit]")?.click();
1124+
document.querySelector("button[data-edit-index]")?.click();
11551125
return true;
11561126
})()
11571127
`);

src/cli/setup.js

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,6 @@ async function createPassword(prompts, invoke, output) {
3535
}
3636
}
3737

38-
async function importDetected(prompts, invoke, output) {
39-
if (!(await prompts.confirm("Scan this machine for supported provider credentials?"))) return;
40-
output.write("Scanning local credential files…\n");
41-
const result = await invoke("app:detect-providers");
42-
const found = result.found || [];
43-
if (!found.length) {
44-
output.write("No supported credentials were found.\n");
45-
return;
46-
}
47-
const indexes = await prompts.multiSelect(
48-
"Import detected accounts",
49-
found.map((item) => ({
50-
label: `${item.name || item.type}${item.email ? ` · ${item.email}` : ""} (${item.source})`,
51-
})),
52-
{ defaultAll: true }
53-
);
54-
if (!indexes.length) return;
55-
await invoke("app:import-detected", indexes.map((index) => found[index].id));
56-
output.write(`Imported ${indexes.length} account${indexes.length === 1 ? "" : "s"}.\n`);
57-
}
58-
5938
async function connectOauth(prompts, invoke, output) {
6039
output.write(`\n${OAUTH_NOTICE}\n`);
6140
while (await prompts.confirm("Connect an OAuth subscription account now?", { defaultValue: false })) {
@@ -172,8 +151,6 @@ async function runFirstSetup({ prompts, controlPlane, dashboardUrl, output = pro
172151

173152
await invoke("app:set-onboarding-step", "admin-password");
174153
await createPassword(prompts, invoke, output);
175-
await invoke("app:set-onboarding-step", "auto-detect");
176-
await importDetected(prompts, invoke, output);
177154
await invoke("app:set-onboarding-step", "oauth-providers");
178155
await connectOauth(prompts, invoke, output);
179156
await invoke("app:set-onboarding-step", "api-keys");

src/lib/constants.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ const ONBOARDING_STEPS = [
154154
"permissions",
155155
"admin-password",
156156
"welcome",
157-
"auto-detect",
158157
"oauth-providers",
159158
"api-keys",
160159
"endpoint-ready",

src/lib/control-plane.js

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const { hydrateUsageIdentity } = require("./usage");
44
const { hashPassword, verifyPassword, generateId, generateApiKey } = require("./password");
5-
const { detectAll, summarizeDetected } = require("./detect");
65
const { startOAuth, completeOAuth, oauthStatus, clearPending } = require("./oauth");
76
const {
87
canInvoke,
@@ -54,7 +53,6 @@ function createControlPlane({
5453
throw new TypeError("Control plane requires the ReRouted runtime services");
5554
}
5655

57-
let detectedCache = [];
5856
const handlers = new Map();
5957
const handle = (channel, handler) => {
6058
if (handlers.has(channel)) throw new Error(`Duplicate control-plane handler: ${channel}`);
@@ -173,9 +171,11 @@ function createControlPlane({
173171
});
174172

175173
handle("app:set-onboarding-step", async (_e, step) => {
174+
if (!ONBOARDING_STEPS.includes(step) || step === "done") {
175+
return { ok: false, error: "Unknown onboarding step" };
176+
}
176177
store.update((cfg) => {
177178
cfg.onboardingStep = step;
178-
if (step === "done") cfg.onboardingComplete = true;
179179
});
180180
return { ok: true };
181181
});
@@ -235,45 +235,6 @@ handle("app:change-admin-password", async (_e, { current, next }) => {
235235
return { ok: true };
236236
});
237237

238-
handle("app:detect-providers", async () => {
239-
detectedCache = await detectAll();
240-
return { ok: true, found: summarizeDetected(detectedCache) };
241-
});
242-
243-
handle("app:import-detected", async (_e, ids) => {
244-
const want = new Set(ids || []);
245-
const toImport = detectedCache.filter((d) => want.has(d.id));
246-
store.update((cfg) => {
247-
for (const d of toImport) {
248-
// Avoid duplicate by type+email/source path
249-
const exists = cfg.providers.some(
250-
(p) =>
251-
p.type === d.type &&
252-
((d.email && p.email === d.email) || (d.path && p.importPath === d.path))
253-
);
254-
if (exists) continue;
255-
cfg.providers.push({
256-
id: d.id || generateId("prov"),
257-
type: d.type,
258-
name: d.name,
259-
email: d.email,
260-
accessToken: d.accessToken,
261-
refreshToken: d.refreshToken,
262-
accountId: d.accountId,
263-
projectId: d.projectId,
264-
clientId: d.clientId,
265-
clientSecret: d.clientSecret,
266-
models: d.models,
267-
enabled: true,
268-
importPath: d.path,
269-
source: d.source,
270-
createdAt: Date.now(),
271-
});
272-
}
273-
});
274-
return { ok: true };
275-
});
276-
277238
handle("app:oauth-start", async (_e, type) => {
278239
try {
279240
logger.oauth(`UI requested OAuth start for ${type}`);
@@ -583,6 +544,21 @@ handle("app:set-model-enabled", async (_e, { providerId, modelId, enabled }) =>
583544
return { ok: true };
584545
});
585546

547+
handle("app:set-all-models-enabled", async (_e, { providerId, enabled }) => {
548+
let updated = 0;
549+
store.update((cfg) => {
550+
const provider = cfg.providers.find((item) => item.id === providerId);
551+
if (!provider || !Array.isArray(provider.models)) return;
552+
provider.models = provider.models.map((model) => {
553+
updated += 1;
554+
return typeof model === "string"
555+
? { id: model, name: model, enabled: !!enabled }
556+
: { ...model, enabled: !!enabled };
557+
});
558+
});
559+
return { ok: updated > 0, updated, enabled: !!enabled };
560+
});
561+
586562
handle("app:add-model", async (_e, { providerId, modelId }) => {
587563
const mid = String(modelId || "").trim();
588564
if (!mid) return { ok: false, error: "Model name required" };

src/lib/dashboard.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ const PUBLIC_ONBOARDING_CHANNELS = new Set([
1919
"app:get-state",
2020
"app:set-onboarding-step",
2121
"app:set-admin-password",
22-
"app:detect-providers",
23-
"app:import-detected",
2422
"app:oauth-start",
2523
"app:oauth-status",
2624
"app:oauth-cancel",

0 commit comments

Comments
 (0)