feat(aiturk): one-click sign-in for AITURK IDE (1.0.0-beta.14)
The onboarding and provider settings get a Sign in button: the IDE shows a short code, opens the turkservis.online approval page, and after approval saves the TurkServis provider itself and hands a separate member key to the AITURK CLI over stdin (aiturk login --key-stdin --keep-other-account). Keys never reach the renderer, logs, process arguments or URLs. Pasting an API key remains as the fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B8ppceaR5s6cvMnm7uGRnf
This commit is contained in:
1 parent
fe0a45a84f
commit
25d8c18c10
13 files changed
+1938
-15
No files matched your search
@@ -33,6 +33,7 @@ import {
|
||||
} from 'electron'
|
||||
|
||||
import { classifyActiveRuntime, needsPackagedRuntimeUpgrade } from './active-runtime-state'
|
||||
import { createAiturkCliRunner, createAiturkLogin } from './aiturk-login'
|
||||
import { describeVcRuntimeResult, ensureWindowsVcRuntime } from './windows-vc-runtime'
|
||||
import { destroyKeepaliveAgents, downloadAgentFor, jsonAgentFor, withRetry } from './api-transport'
|
||||
import { appIconCandidates, resolveAppIcon } from './app-icon'
|
||||
@@ -17231,6 +17232,53 @@ ipcMain.handle('hermes:openExternal', (_event, url) => {
|
||||
}
|
||||
})
|
||||
|
||||
// ── AITURK one-click sign-in (device code) ───────────────────────────────
|
||||
// The API keys returned by turkservis.online stay in THIS process: the
|
||||
// provider is saved through the same backend route hermes:api uses and the
|
||||
// CLI key is piped to `aiturk login --key-stdin`. The renderer only ever sees
|
||||
// the short user code, the approval URL and a status. See aiturk-login.ts.
|
||||
const aiturkLogin = createAiturkLogin({
|
||||
fetch: (url, init) => fetch(url, init),
|
||||
openExternal: url => openExternalUrl(url),
|
||||
hostname: () => os.hostname(),
|
||||
backendRequest: request => handleHermesApiRequest(request),
|
||||
runCli: createAiturkCliRunner({ spawn, existsSync: fs.existsSync, env: process.env }),
|
||||
now: () => Date.now()
|
||||
})
|
||||
|
||||
// Only the primary window's top-level frame may drive a sign-in.
|
||||
function assertAiturkLoginSender(event) {
|
||||
const contents = mainWindow && !mainWindow.isDestroyed() ? mainWindow.webContents : null
|
||||
|
||||
if (!contents || event.sender !== contents || (event.senderFrame && event.senderFrame !== contents.mainFrame)) {
|
||||
throw new Error('aiturk-login:unavailable')
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.handle('aiturk:login:start', async (event, scope) => {
|
||||
assertAiturkLoginSender(event)
|
||||
|
||||
return aiturkLogin.start(scope)
|
||||
})
|
||||
|
||||
ipcMain.handle('aiturk:login:poll', async event => {
|
||||
assertAiturkLoginSender(event)
|
||||
|
||||
return aiturkLogin.poll()
|
||||
})
|
||||
|
||||
ipcMain.handle('aiturk:login:cancel', async event => {
|
||||
assertAiturkLoginSender(event)
|
||||
|
||||
return aiturkLogin.cancel()
|
||||
})
|
||||
|
||||
ipcMain.handle('aiturk:login:overwrite-cli', async event => {
|
||||
assertAiturkLoginSender(event)
|
||||
|
||||
return aiturkLogin.overwriteCli()
|
||||
})
|
||||
|
||||
// ── Find-in-page (Ctrl/Cmd+F) ─────────────────────────────────────────────
|
||||
// The desktop supports multiple BrowserWindows (one primary plus any
|
||||
// per-session secondary windows spawned via `hermes:window:openSession`).
|
||||
|
||||
Reference in new issue
Block a user