Skip to content

Commit 88f16f7

Browse files
committed
chore: push npm
1 parent 6add074 commit 88f16f7

6 files changed

Lines changed: 86 additions & 80 deletions

File tree

‎codev-cli/README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# codev-cli
1+
# codev-ai
22

3-
A CLI tool to install and configure coding agents (Claude Code, OpenCode).
3+
CoDev — AI Coding Agent Hub. Install, configure, and launch AI coding agents (Claude Code, OpenCode) from a single CLI.
44

55
## Install
66

77
```bash
8-
npm install -g codev-cli
8+
npm install -g codev-ai
99
```
1010

1111
Then run:

‎codev-cli/package.json‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "codev-cli",
2+
"name": "codev-ai",
33
"version": "0.1.0",
44
"type": "module",
55
"bin": {
@@ -15,7 +15,8 @@
1515
"test": "bun test",
1616
"typecheck": "bunx --bun tsc --noEmit",
1717
"check": "bunx --bun @biomejs/biome check",
18-
"fix": "bunx --bun @biomejs/biome check --write"
18+
"fix": "bunx --bun @biomejs/biome check --write",
19+
"prepublishOnly": "bun run check && bun run typecheck && bun test && bun run build"
1920
},
2021
"dependencies": {
2122
"ink": "^7.0.0",

‎codev-cli/src/App.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function App() {
6161
return (
6262
<Box flexDirection="column" padding={1}>
6363
<Banner />
64-
<Frame tag="codev">
64+
<Frame tag="CoDev">
6565
<Step
6666
active={step === "select"}
6767
title={toolSelectTitle(step !== "select")}

‎codev-cli/src/auth.ts‎

Lines changed: 76 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
unlinkSync,
77
writeFileSync,
88
} from "node:fs";
9+
import { createServer } from "node:http";
10+
import type { AddressInfo } from "node:net";
911
import { homedir } from "node:os";
1012
import { dirname, join } from "node:path";
1113
import { BASE_URL } from "@/const.js";
@@ -222,83 +224,85 @@ async function getAuthCode(
222224
}
223225
};
224226

225-
const server = Bun.serve({
226-
port: 0,
227-
hostname: "127.0.0.1",
228-
fetch(req) {
229-
const url = new URL(req.url);
230-
if (url.pathname !== "/callback") {
231-
return new Response("Not found", { status: 404 });
232-
}
233-
234-
const code = url.searchParams.get("code");
235-
const error = url.searchParams.get("error");
236-
const returnedState = url.searchParams.get("state");
237-
238-
if (error) {
239-
const desc = url.searchParams.get("error_description") || error;
240-
finish();
241-
server.stop();
242-
reject(new Error(`SSO login failed: ${desc}`));
243-
return new Response(loginResultHtml(false, desc), {
244-
headers: { "Content-Type": "text/html" },
245-
});
246-
}
247-
248-
if (!code) {
249-
finish();
250-
server.stop();
251-
reject(new Error("No authorization code received"));
252-
return new Response(
253-
loginResultHtml(false, "No authorization code received"),
254-
{ headers: { "Content-Type": "text/html" } },
255-
);
256-
}
257-
258-
if (returnedState !== expectedState) {
259-
finish();
260-
server.stop();
261-
reject(new Error("State mismatch (possible CSRF attack)"));
262-
return new Response(loginResultHtml(false, "State mismatch"), {
263-
headers: { "Content-Type": "text/html" },
264-
});
265-
}
227+
const server = createServer((req, res) => {
228+
const host = req.headers.host ?? "127.0.0.1";
229+
const url = new URL(req.url ?? "/", `http://${host}`);
266230

231+
if (url.pathname !== "/callback") {
232+
res.writeHead(404, { "Content-Type": "text/plain" });
233+
res.end("Not found");
234+
return;
235+
}
236+
237+
const code = url.searchParams.get("code");
238+
const error = url.searchParams.get("error");
239+
const returnedState = url.searchParams.get("state");
240+
241+
const respond = (ok: boolean, msg?: string) => {
242+
res.writeHead(ok ? 200 : 400, { "Content-Type": "text/html" });
243+
res.end(loginResultHtml(ok, msg));
244+
};
245+
246+
if (error) {
247+
const desc = url.searchParams.get("error_description") || error;
248+
respond(false, desc);
267249
finish();
268-
server.stop();
269-
resolve({
270-
code,
271-
redirectUri: `http://127.0.0.1:${server.port}/callback`,
272-
});
273-
274-
return new Response(loginResultHtml(true), {
275-
headers: { "Content-Type": "text/html" },
276-
});
277-
},
278-
});
250+
server.close();
251+
reject(new Error(`SSO login failed: ${desc}`));
252+
return;
253+
}
279254

280-
const redirectUri = `http://127.0.0.1:${server.port}/callback`;
281-
const authorizeUrl =
282-
`${SSO_BASE_URL}/authorize?` +
283-
`response_type=code` +
284-
`&client_id=${encodeURIComponent(CLIENT_ID)}` +
285-
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
286-
`&scope=openid%20profile%20email%20offline_access` +
287-
`&state=${expectedState}` +
288-
`&nonce=${nonce}` +
289-
`&code_challenge=${codeChallenge}` +
290-
`&code_challenge_method=S256`;
291-
292-
onReady(() => {
293-
onLog("Opening browser for SSO login...");
294-
openBrowser(authorizeUrl);
255+
if (!code) {
256+
respond(false, "No authorization code received");
257+
finish();
258+
server.close();
259+
reject(new Error("No authorization code received"));
260+
return;
261+
}
262+
263+
if (returnedState !== expectedState) {
264+
respond(false, "State mismatch");
265+
finish();
266+
server.close();
267+
reject(new Error("State mismatch (possible CSRF attack)"));
268+
return;
269+
}
270+
271+
const { port } = server.address() as AddressInfo;
272+
respond(true);
273+
finish();
274+
server.close();
275+
resolve({
276+
code,
277+
redirectUri: `http://127.0.0.1:${port}/callback`,
278+
});
295279
});
296280

297-
timeoutHandle = setTimeout(() => {
298-
timeoutHandle = null;
299-
server.stop();
300-
reject(new Error("Login timed out after 120 seconds"));
301-
}, 120_000);
281+
server.listen(0, "127.0.0.1", () => {
282+
const { port } = server.address() as AddressInfo;
283+
const redirectUri = `http://127.0.0.1:${port}/callback`;
284+
const authorizeUrl =
285+
`${SSO_BASE_URL}/authorize?` +
286+
`response_type=code` +
287+
`&client_id=${encodeURIComponent(CLIENT_ID)}` +
288+
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
289+
`&scope=openid%20profile%20email%20offline_access` +
290+
`&state=${expectedState}` +
291+
`&nonce=${nonce}` +
292+
`&code_challenge=${codeChallenge}` +
293+
`&code_challenge_method=S256`;
294+
295+
onReady(() => {
296+
onLog("Opening browser for SSO login...");
297+
openBrowser(authorizeUrl);
298+
});
299+
300+
timeoutHandle = setTimeout(() => {
301+
timeoutHandle = null;
302+
server.close();
303+
reject(new Error("Login timed out after 120 seconds"));
304+
}, 120_000);
305+
});
302306
});
303307
}
304308

‎codev-cli/src/components/Configure.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ export function Configure({ tools, apiKey, onDone }: ConfigureProps) {
134134
<Text key={`cfg-${i.toString()}`}>{log}</Text>
135135
))}
136136
{phase === "done" && (
137-
<Box marginTop={1} marginBottom={1}>
137+
<Box marginTop={1} marginBottom={1} flexDirection="column">
138+
<Text dimColor>{"Run `codev --help` to see all commands."}</Text>
138139
<Text bold color="magenta">
139140
{"🎉 Happy coding!"}
140141
</Text>

‎codev-cli/src/help.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ function link(url: string): string {
66
}
77

88
export function printHelp() {
9-
console.log(`codev v${VERSION} — AI Coding Agent Hub
9+
console.log(`CoDev v${VERSION} — AI Coding Agent Hub
1010
1111
Usage:
1212
codev install Install and configure AI coding agents

0 commit comments

Comments
 (0)