codeblog-app 2.0.0 → 2.0.2

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.
Files changed (68) hide show
  1. package/package.json +8 -71
  2. package/drizzle/0000_init.sql +0 -34
  3. package/drizzle/meta/_journal.json +0 -13
  4. package/drizzle.config.ts +0 -10
  5. package/src/ai/__tests__/chat.test.ts +0 -110
  6. package/src/ai/__tests__/provider.test.ts +0 -184
  7. package/src/ai/__tests__/tools.test.ts +0 -90
  8. package/src/ai/chat.ts +0 -169
  9. package/src/ai/configure.ts +0 -89
  10. package/src/ai/provider.ts +0 -238
  11. package/src/ai/tools.ts +0 -321
  12. package/src/auth/index.ts +0 -47
  13. package/src/auth/oauth.ts +0 -93
  14. package/src/cli/__tests__/commands.test.ts +0 -225
  15. package/src/cli/__tests__/setup.test.ts +0 -57
  16. package/src/cli/cmd/agent.ts +0 -102
  17. package/src/cli/cmd/chat.ts +0 -190
  18. package/src/cli/cmd/comment.ts +0 -70
  19. package/src/cli/cmd/config.ts +0 -153
  20. package/src/cli/cmd/feed.ts +0 -57
  21. package/src/cli/cmd/forum.ts +0 -123
  22. package/src/cli/cmd/login.ts +0 -45
  23. package/src/cli/cmd/logout.ts +0 -12
  24. package/src/cli/cmd/me.ts +0 -202
  25. package/src/cli/cmd/post.ts +0 -29
  26. package/src/cli/cmd/publish.ts +0 -70
  27. package/src/cli/cmd/scan.ts +0 -80
  28. package/src/cli/cmd/search.ts +0 -40
  29. package/src/cli/cmd/setup.ts +0 -201
  30. package/src/cli/cmd/tui.ts +0 -20
  31. package/src/cli/cmd/update.ts +0 -78
  32. package/src/cli/cmd/vote.ts +0 -50
  33. package/src/cli/cmd/whoami.ts +0 -21
  34. package/src/cli/ui.ts +0 -124
  35. package/src/config/index.ts +0 -54
  36. package/src/flag/index.ts +0 -23
  37. package/src/global/index.ts +0 -38
  38. package/src/id/index.ts +0 -20
  39. package/src/index.ts +0 -186
  40. package/src/mcp/__tests__/client.test.ts +0 -149
  41. package/src/mcp/__tests__/e2e.ts +0 -327
  42. package/src/mcp/__tests__/integration.ts +0 -148
  43. package/src/mcp/client.ts +0 -148
  44. package/src/server/index.ts +0 -48
  45. package/src/storage/chat.ts +0 -92
  46. package/src/storage/db.ts +0 -85
  47. package/src/storage/schema.sql.ts +0 -39
  48. package/src/storage/schema.ts +0 -1
  49. package/src/tui/app.tsx +0 -163
  50. package/src/tui/commands.ts +0 -177
  51. package/src/tui/context/exit.tsx +0 -15
  52. package/src/tui/context/helper.tsx +0 -25
  53. package/src/tui/context/route.tsx +0 -24
  54. package/src/tui/context/theme.tsx +0 -470
  55. package/src/tui/routes/home.tsx +0 -490
  56. package/src/tui/routes/model.tsx +0 -209
  57. package/src/tui/routes/notifications.tsx +0 -85
  58. package/src/tui/routes/post.tsx +0 -108
  59. package/src/tui/routes/search.tsx +0 -104
  60. package/src/tui/routes/setup.tsx +0 -255
  61. package/src/tui/routes/trending.tsx +0 -107
  62. package/src/util/__tests__/context.test.ts +0 -31
  63. package/src/util/__tests__/lazy.test.ts +0 -37
  64. package/src/util/context.ts +0 -23
  65. package/src/util/error.ts +0 -46
  66. package/src/util/lazy.ts +0 -18
  67. package/src/util/log.ts +0 -142
  68. package/tsconfig.json +0 -11
@@ -1,201 +0,0 @@
1
- import type { CommandModule } from "yargs"
2
- import { Auth } from "../../auth"
3
- import { OAuth } from "../../auth/oauth"
4
- import { McpBridge } from "../../mcp/client"
5
- import { UI } from "../ui"
6
-
7
- function extractApiKey(text: string): string | null {
8
- const match = text.match(/^API-KEY:\s*(\S+)/m)
9
- return match ? match[1]! : null
10
- }
11
-
12
- function extractUsername(text: string): string | null {
13
- // Try "Account: username (email)" first (registration path)
14
- const acct = text.match(/^Account:\s*(\S+)/m)
15
- if (acct) return acct[1]!
16
- // Try "Owner: username" (api_key verification path)
17
- const owner = text.match(/^Owner:\s*(\S+)/m)
18
- if (owner) return owner[1]!
19
- return null
20
- }
21
-
22
- export { extractApiKey, extractUsername }
23
-
24
- async function authQuickSignup(): Promise<boolean> {
25
- const email = await UI.input(" Email: ")
26
- if (!email) { UI.error("Email is required."); return false }
27
-
28
- const username = await UI.input(" Username: ")
29
- if (!username) { UI.error("Username is required."); return false }
30
-
31
- const password = await UI.password(" Password: ")
32
- if (!password || password.length < 6) { UI.error("Password must be at least 6 characters."); return false }
33
-
34
- const lang = await UI.input(" Language (e.g. English/中文) [English]: ")
35
- const default_language = lang || "English"
36
-
37
- console.log("")
38
- UI.info("Creating your account...")
39
-
40
- try {
41
- const result = await McpBridge.callTool("codeblog_setup", {
42
- email, username, password, default_language,
43
- })
44
-
45
- const apiKey = extractApiKey(result)
46
- const user = extractUsername(result)
47
-
48
- if (apiKey) {
49
- await Auth.set({ type: "apikey", value: apiKey, username: user || username })
50
- } else {
51
- UI.warn("Account created but could not extract API key from response.")
52
- UI.info("Try: codeblog setup → option 3 to paste your API key manually.")
53
- return false
54
- }
55
-
56
- return true
57
- } catch (err) {
58
- UI.error(`Signup failed: ${err instanceof Error ? err.message : String(err)}`)
59
- return false
60
- }
61
- }
62
- async function authOAuth(): Promise<boolean> {
63
- const provider = await UI.input(" Choose provider (github/google) [github]: ")
64
- const chosen = (provider === "google" ? "google" : "github") as "github" | "google"
65
-
66
- try {
67
- await OAuth.login(chosen)
68
- return true
69
- } catch (err) {
70
- UI.error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`)
71
- return false
72
- }
73
- }
74
-
75
- async function authApiKey(): Promise<boolean> {
76
- const key = await UI.input(" Paste your API key (starts with cbk_): ")
77
- if (!key || !key.startsWith("cbk_")) {
78
- UI.error("Invalid API key. It should start with 'cbk_'.")
79
- return false
80
- }
81
-
82
- UI.info("Verifying API key...")
83
- try {
84
- const result = await McpBridge.callTool("codeblog_setup", { api_key: key })
85
- const username = extractUsername(result)
86
- await Auth.set({ type: "apikey", value: key, username: username || undefined })
87
- return true
88
- } catch (err) {
89
- UI.error(`Verification failed: ${err instanceof Error ? err.message : String(err)}`)
90
- return false
91
- }
92
- }
93
-
94
- async function postAuthFlow(): Promise<void> {
95
- console.log("")
96
-
97
- // Scan
98
- UI.info("Scanning your IDE sessions...")
99
- try {
100
- const text = await McpBridge.callTool("scan_sessions", { limit: 10 })
101
- let sessions: Array<{ id: string; source: string; project: string; title: string }>
102
- try {
103
- sessions = JSON.parse(text)
104
- } catch {
105
- console.log(text)
106
- return
107
- }
108
-
109
- if (sessions.length === 0) {
110
- UI.warn("No IDE sessions found. You can scan later with: codeblog scan")
111
- return
112
- }
113
-
114
- console.log(` Found ${UI.Style.TEXT_HIGHLIGHT}${sessions.length}${UI.Style.TEXT_NORMAL} sessions`)
115
- console.log("")
116
- for (const s of sessions.slice(0, 5)) {
117
- console.log(` ${UI.Style.TEXT_INFO}[${s.source}]${UI.Style.TEXT_NORMAL} ${s.project} — ${s.title.slice(0, 60)}`)
118
- }
119
- if (sessions.length > 5) {
120
- console.log(` ${UI.Style.TEXT_DIM}... and ${sessions.length - 5} more${UI.Style.TEXT_NORMAL}`)
121
- }
122
- console.log("")
123
-
124
- // Publish
125
- const answer = await UI.input(" Publish your latest session to CodeBlog? (y/n) [y]: ")
126
- if (answer.toLowerCase() === "n") {
127
- UI.info("Skipped. You can publish later with: codeblog publish")
128
- } else {
129
- UI.info("Publishing...")
130
- try {
131
- const result = await McpBridge.callTool("auto_post", { dry_run: false })
132
- console.log("")
133
- for (const line of result.split("\n")) {
134
- console.log(` ${line}`)
135
- }
136
- } catch (pubErr) {
137
- UI.error(`Publish failed: ${pubErr instanceof Error ? pubErr.message : String(pubErr)}`)
138
- }
139
- }
140
- } catch (err) {
141
- UI.error(`Scan failed: ${err instanceof Error ? err.message : String(err)}`)
142
- }
143
- }
144
- export const SetupCommand: CommandModule = {
145
- command: "setup",
146
- describe: "First-time setup wizard: authenticate → scan → publish",
147
- handler: async () => {
148
- console.log(UI.logo())
149
- console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Welcome to CodeBlog!${UI.Style.TEXT_NORMAL}`)
150
- console.log(` ${UI.Style.TEXT_DIM}The AI-powered coding forum${UI.Style.TEXT_NORMAL}`)
151
- console.log("")
152
-
153
- const alreadyAuthed = await Auth.authenticated()
154
- let authenticated = alreadyAuthed
155
-
156
- if (alreadyAuthed) {
157
- UI.success("Already authenticated!")
158
- } else {
159
- const choice = await UI.select(" How would you like to get started?", [
160
- "Quick signup (email + password)",
161
- "Login with GitHub / Google",
162
- "Paste existing API key",
163
- ])
164
-
165
- console.log("")
166
-
167
- switch (choice) {
168
- case 0:
169
- authenticated = await authQuickSignup()
170
- break
171
- case 1:
172
- authenticated = await authOAuth()
173
- break
174
- case 2:
175
- authenticated = await authApiKey()
176
- break
177
- }
178
- }
179
-
180
- if (!authenticated) {
181
- console.log("")
182
- UI.info("You can try again with: codeblog setup")
183
- return
184
- }
185
-
186
- const token = await Auth.get()
187
- UI.success(`Authenticated as ${token?.username || "user"}!`)
188
-
189
- await postAuthFlow()
190
-
191
- console.log("")
192
- UI.success("Setup complete!")
193
- console.log("")
194
- console.log(` ${UI.Style.TEXT_DIM}Useful commands:${UI.Style.TEXT_NORMAL}`)
195
- console.log(` codeblog feed ${UI.Style.TEXT_DIM}— Browse the forum${UI.Style.TEXT_NORMAL}`)
196
- console.log(` codeblog scan ${UI.Style.TEXT_DIM}— Scan IDE sessions${UI.Style.TEXT_NORMAL}`)
197
- console.log(` codeblog publish ${UI.Style.TEXT_DIM}— Publish sessions${UI.Style.TEXT_NORMAL}`)
198
- console.log(` codeblog chat ${UI.Style.TEXT_DIM}— AI chat${UI.Style.TEXT_NORMAL}`)
199
- console.log("")
200
- },
201
- }
@@ -1,20 +0,0 @@
1
- import type { CommandModule } from "yargs"
2
-
3
- export const TuiCommand: CommandModule = {
4
- command: "tui",
5
- aliases: ["ui"],
6
- describe: "Launch interactive TUI — browse feed, chat with AI, manage posts",
7
- builder: (yargs) =>
8
- yargs
9
- .option("model", {
10
- alias: "m",
11
- describe: "Default AI model",
12
- type: "string",
13
- }),
14
- handler: async (args) => {
15
- const { tui } = await import("../../tui/app")
16
- await tui({
17
- onExit: async () => {},
18
- })
19
- },
20
- }
@@ -1,78 +0,0 @@
1
- import type { CommandModule } from "yargs"
2
- import { UI } from "../ui"
3
-
4
- export const UpdateCommand: CommandModule = {
5
- command: "update",
6
- describe: "Update codeblog CLI to the latest version",
7
- builder: (yargs) =>
8
- yargs.option("force", {
9
- describe: "Force update even if already on latest",
10
- type: "boolean",
11
- default: false,
12
- }),
13
- handler: async (args) => {
14
- const pkg = await import("../../../package.json")
15
- const current = pkg.version
16
-
17
- UI.info(`Current version: v${current}`)
18
- UI.info("Checking for updates...")
19
-
20
- const res = await fetch("https://registry.npmjs.org/codeblog-app/latest")
21
- if (!res.ok) {
22
- UI.error("Failed to check for updates")
23
- process.exitCode = 1
24
- return
25
- }
26
-
27
- const data = await res.json() as { version: string }
28
- const latest = data.version
29
-
30
- if (current === latest && !args.force) {
31
- UI.success(`Already on latest version v${current}`)
32
- return
33
- }
34
-
35
- UI.info(`Updating v${current} → v${latest}...`)
36
-
37
- const os = process.platform === "win32" ? "windows" : process.platform === "darwin" ? "darwin" : "linux"
38
- const arch = process.arch === "arm64" ? "arm64" : "x64"
39
- const platform = `${os}-${arch}`
40
- const pkg_name = `codeblog-app-${platform}`
41
- const url = `https://registry.npmjs.org/${pkg_name}/-/${pkg_name}-${latest}.tgz`
42
-
43
- const tmpdir = (await import("os")).tmpdir()
44
- const path = await import("path")
45
- const fs = await import("fs/promises")
46
- const tmp = path.join(tmpdir, `codeblog-update-${Date.now()}`)
47
- await fs.mkdir(tmp, { recursive: true })
48
-
49
- const tgz = path.join(tmp, "pkg.tgz")
50
- const dlRes = await fetch(url)
51
- if (!dlRes.ok) {
52
- UI.error(`Failed to download update for ${platform}`)
53
- process.exitCode = 1
54
- return
55
- }
56
-
57
- await Bun.write(tgz, dlRes)
58
-
59
- const proc = Bun.spawn(["tar", "-xzf", tgz, "-C", tmp], { stdout: "ignore", stderr: "ignore" })
60
- await proc.exited
61
-
62
- const bin = process.execPath
63
- const ext = os === "windows" ? ".exe" : ""
64
- const src = path.join(tmp, "package", "bin", `codeblog${ext}`)
65
-
66
- await fs.copyFile(src, bin)
67
- if (os !== "windows") {
68
- await fs.chmod(bin, 0o755)
69
- }
70
- if (os === "darwin") {
71
- Bun.spawn(["codesign", "--sign", "-", "--force", bin], { stdout: "ignore", stderr: "ignore" })
72
- }
73
-
74
- await fs.rm(tmp, { recursive: true, force: true })
75
-
76
- UI.success(`Updated to v${latest}!`)
77
- },
78
- }
@@ -1,50 +0,0 @@
1
- import type { CommandModule } from "yargs"
2
- import { McpBridge } from "../../mcp/client"
3
- import { UI } from "../ui"
4
-
5
- export const VoteCommand: CommandModule = {
6
- command: "vote <post_id>",
7
- describe: "Vote on a post (up/down/remove)",
8
- builder: (yargs) =>
9
- yargs
10
- .positional("post_id", {
11
- describe: "Post ID to vote on",
12
- type: "string",
13
- demandOption: true,
14
- })
15
- .option("up", {
16
- alias: "u",
17
- describe: "Upvote",
18
- type: "boolean",
19
- })
20
- .option("down", {
21
- alias: "d",
22
- describe: "Downvote",
23
- type: "boolean",
24
- })
25
- .option("remove", {
26
- describe: "Remove existing vote",
27
- type: "boolean",
28
- })
29
- .conflicts("up", "down")
30
- .conflicts("up", "remove")
31
- .conflicts("down", "remove"),
32
- handler: async (args) => {
33
- let value = 1 // default upvote
34
- if (args.down) value = -1
35
- if (args.remove) value = 0
36
-
37
- try {
38
- const text = await McpBridge.callTool("vote_on_post", {
39
- post_id: args.post_id,
40
- value,
41
- })
42
- console.log("")
43
- console.log(` ${text}`)
44
- console.log("")
45
- } catch (err) {
46
- UI.error(`Vote failed: ${err instanceof Error ? err.message : String(err)}`)
47
- process.exitCode = 1
48
- }
49
- },
50
- }
@@ -1,21 +0,0 @@
1
- import type { CommandModule } from "yargs"
2
- import { McpBridge } from "../../mcp/client"
3
- import { UI } from "../ui"
4
-
5
- export const WhoamiCommand: CommandModule = {
6
- command: "whoami",
7
- describe: "Show current auth status",
8
- handler: async () => {
9
- try {
10
- const text = await McpBridge.callTool("codeblog_status")
11
- console.log("")
12
- for (const line of text.split("\n")) {
13
- console.log(` ${line}`)
14
- }
15
- console.log("")
16
- } catch (err) {
17
- UI.error(`Status check failed: ${err instanceof Error ? err.message : String(err)}`)
18
- process.exitCode = 1
19
- }
20
- },
21
- }
package/src/cli/ui.ts DELETED
@@ -1,124 +0,0 @@
1
- import { EOL } from "os"
2
-
3
- export namespace UI {
4
- export const Style = {
5
- TEXT_HIGHLIGHT: "\x1b[96m",
6
- TEXT_HIGHLIGHT_BOLD: "\x1b[96m\x1b[1m",
7
- TEXT_DIM: "\x1b[90m",
8
- TEXT_DIM_BOLD: "\x1b[90m\x1b[1m",
9
- TEXT_NORMAL: "\x1b[0m",
10
- TEXT_NORMAL_BOLD: "\x1b[1m",
11
- TEXT_WARNING: "\x1b[93m",
12
- TEXT_WARNING_BOLD: "\x1b[93m\x1b[1m",
13
- TEXT_DANGER: "\x1b[91m",
14
- TEXT_DANGER_BOLD: "\x1b[91m\x1b[1m",
15
- TEXT_SUCCESS: "\x1b[92m",
16
- TEXT_SUCCESS_BOLD: "\x1b[92m\x1b[1m",
17
- TEXT_INFO: "\x1b[94m",
18
- TEXT_INFO_BOLD: "\x1b[94m\x1b[1m",
19
- }
20
-
21
- export function println(...message: string[]) {
22
- print(...message)
23
- Bun.stderr.write(EOL)
24
- }
25
-
26
- export function print(...message: string[]) {
27
- Bun.stderr.write(message.join(" "))
28
- }
29
-
30
- export function logo() {
31
- const orange = "\x1b[38;5;214m"
32
- const cyan = "\x1b[36m"
33
- const reset = "\x1b[0m"
34
- return [
35
- "",
36
- `${orange} ██████╗ ██████╗ ██████╗ ███████╗${cyan}██████╗ ██╗ ██████╗ ██████╗ ${reset}`,
37
- `${orange} ██╔════╝██╔═══██╗██╔══██╗██╔════╝${cyan}██╔══██╗██║ ██╔═══██╗██╔════╝ ${reset}`,
38
- `${orange} ██║ ██║ ██║██║ ██║█████╗ ${cyan}██████╔╝██║ ██║ ██║██║ ███╗${reset}`,
39
- `${orange} ██║ ██║ ██║██║ ██║██╔══╝ ${cyan}██╔══██╗██║ ██║ ██║██║ ██║${reset}`,
40
- `${orange} ╚██████╗╚██████╔╝██████╔╝███████╗${cyan}██████╔╝███████╗╚██████╔╝╚██████╔╝${reset}`,
41
- `${orange} ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝${cyan}╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ${reset}`,
42
- "",
43
- ` ${Style.TEXT_DIM}The AI-powered coding forum in your terminal${Style.TEXT_NORMAL}`,
44
- "",
45
- ].join(EOL)
46
- }
47
-
48
- export function error(message: string) {
49
- println(Style.TEXT_DANGER_BOLD + "Error: " + Style.TEXT_NORMAL + message)
50
- }
51
-
52
- export function success(message: string) {
53
- println(Style.TEXT_SUCCESS_BOLD + "✓ " + Style.TEXT_NORMAL + message)
54
- }
55
-
56
- export function info(message: string) {
57
- println(Style.TEXT_INFO + "ℹ " + Style.TEXT_NORMAL + message)
58
- }
59
-
60
- export function warn(message: string) {
61
- println(Style.TEXT_WARNING + "⚠ " + Style.TEXT_NORMAL + message)
62
- }
63
-
64
- export async function input(prompt: string): Promise<string> {
65
- const readline = require("readline")
66
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
67
- return new Promise((resolve) => {
68
- rl.question(prompt, (answer: string) => {
69
- rl.close()
70
- resolve(answer.trim())
71
- })
72
- })
73
- }
74
-
75
- export async function password(prompt: string): Promise<string> {
76
- const readline = require("readline")
77
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr, terminal: true })
78
- return new Promise((resolve) => {
79
- // Disable echoing by writing the prompt manually and muting stdout
80
- process.stderr.write(prompt)
81
- const stdin = process.stdin
82
- const wasRaw = stdin.isRaw
83
- if (stdin.isTTY && stdin.setRawMode) stdin.setRawMode(true)
84
-
85
- let buf = ""
86
- const onData = (ch: Buffer) => {
87
- const c = ch.toString("utf8")
88
- if (c === "\n" || c === "\r" || c === "\u0004") {
89
- if (stdin.isTTY && stdin.setRawMode) stdin.setRawMode(wasRaw ?? false)
90
- stdin.removeListener("data", onData)
91
- process.stderr.write("\n")
92
- rl.close()
93
- resolve(buf.trim())
94
- } else if (c === "\u007f" || c === "\b") {
95
- // backspace
96
- if (buf.length > 0) buf = buf.slice(0, -1)
97
- } else if (c === "\u0003") {
98
- // Ctrl+C
99
- if (stdin.isTTY && stdin.setRawMode) stdin.setRawMode(wasRaw ?? false)
100
- stdin.removeListener("data", onData)
101
- rl.close()
102
- process.exit(130)
103
- } else {
104
- buf += c
105
- process.stderr.write("*")
106
- }
107
- }
108
- stdin.on("data", onData)
109
- })
110
- }
111
-
112
- export async function select(prompt: string, options: string[]): Promise<number> {
113
- console.log(prompt)
114
- for (let i = 0; i < options.length; i++) {
115
- console.log(` ${Style.TEXT_HIGHLIGHT}[${i + 1}]${Style.TEXT_NORMAL} ${options[i]}`)
116
- }
117
- console.log("")
118
- const answer = await input(` Choice [1]: `)
119
- const num = parseInt(answer, 10)
120
- if (!answer) return 0
121
- if (isNaN(num) || num < 1 || num > options.length) return 0
122
- return num - 1
123
- }
124
- }
@@ -1,54 +0,0 @@
1
- import path from "path"
2
- import { Global } from "../global"
3
-
4
- const CONFIG_FILE = path.join(Global.Path.config, "config.json")
5
-
6
- export namespace Config {
7
- export interface ProviderConfig {
8
- api_key: string
9
- base_url?: string
10
- }
11
-
12
- export interface CodeblogConfig {
13
- api_url: string
14
- api_key?: string
15
- token?: string
16
- model?: string
17
- default_language?: string
18
- providers?: Record<string, ProviderConfig>
19
- }
20
-
21
- const defaults: CodeblogConfig = {
22
- api_url: "https://codeblog.ai",
23
- }
24
-
25
- export const filepath = CONFIG_FILE
26
-
27
- export async function load(): Promise<CodeblogConfig> {
28
- const file = Bun.file(CONFIG_FILE)
29
- const data = await file.json().catch(() => ({}))
30
- return { ...defaults, ...data }
31
- }
32
-
33
- export async function save(config: Partial<CodeblogConfig>) {
34
- const current = await load()
35
- const merged = { ...current, ...config }
36
- await Bun.write(Bun.file(CONFIG_FILE, { mode: 0o600 }), JSON.stringify(merged, null, 2))
37
- }
38
-
39
- export async function url() {
40
- return process.env.CODEBLOG_URL || (await load()).api_url || "https://codeblog.ai"
41
- }
42
-
43
- export async function key() {
44
- return process.env.CODEBLOG_API_KEY || (await load()).api_key || ""
45
- }
46
-
47
- export async function token() {
48
- return process.env.CODEBLOG_TOKEN || (await load()).token || ""
49
- }
50
-
51
- export async function language() {
52
- return process.env.CODEBLOG_LANGUAGE || (await load()).default_language
53
- }
54
- }
package/src/flag/index.ts DELETED
@@ -1,23 +0,0 @@
1
- function truthy(key: string) {
2
- const value = process.env[key]?.toLowerCase()
3
- return value === "true" || value === "1"
4
- }
5
-
6
- export namespace Flag {
7
- export const CODEBLOG_URL = process.env["CODEBLOG_URL"]
8
- export const CODEBLOG_API_KEY = process.env["CODEBLOG_API_KEY"]
9
- export const CODEBLOG_TOKEN = process.env["CODEBLOG_TOKEN"]
10
- export const CODEBLOG_DEBUG = truthy("CODEBLOG_DEBUG")
11
- export const CODEBLOG_DISABLE_AUTOUPDATE = truthy("CODEBLOG_DISABLE_AUTOUPDATE")
12
- export const CODEBLOG_DISABLE_SCANNER_CACHE = truthy("CODEBLOG_DISABLE_SCANNER_CACHE")
13
- export const CODEBLOG_TEST_HOME = process.env["CODEBLOG_TEST_HOME"]
14
- export declare const CODEBLOG_CLIENT: string
15
- }
16
-
17
- Object.defineProperty(Flag, "CODEBLOG_CLIENT", {
18
- get() {
19
- return process.env["CODEBLOG_CLIENT"] ?? "cli"
20
- },
21
- enumerable: true,
22
- configurable: false,
23
- })
@@ -1,38 +0,0 @@
1
- import fs from "fs/promises"
2
- import { xdgData, xdgCache, xdgConfig, xdgState } from "xdg-basedir"
3
- import path from "path"
4
- import os from "os"
5
-
6
- const app = "codeblog"
7
-
8
- const home = process.env.CODEBLOG_TEST_HOME || os.homedir()
9
- const win = os.platform() === "win32"
10
- const appdata = process.env.APPDATA || path.join(home, "AppData", "Roaming")
11
- const localappdata = process.env.LOCALAPPDATA || path.join(home, "AppData", "Local")
12
-
13
- const data = win ? path.join(localappdata, app) : path.join(xdgData || path.join(home, ".local", "share"), app)
14
- const cache = win ? path.join(localappdata, app, "cache") : path.join(xdgCache || path.join(home, ".cache"), app)
15
- const config = win ? path.join(appdata, app) : path.join(xdgConfig || path.join(home, ".config"), app)
16
- const state = win ? path.join(localappdata, app, "state") : path.join(xdgState || path.join(home, ".local", "state"), app)
17
-
18
- export namespace Global {
19
- export const Path = {
20
- get home() {
21
- return process.env.CODEBLOG_TEST_HOME || os.homedir()
22
- },
23
- data,
24
- bin: path.join(data, "bin"),
25
- log: path.join(data, "log"),
26
- cache,
27
- config,
28
- state,
29
- }
30
- }
31
-
32
- await Promise.all([
33
- fs.mkdir(Global.Path.data, { recursive: true }),
34
- fs.mkdir(Global.Path.config, { recursive: true }),
35
- fs.mkdir(Global.Path.state, { recursive: true }),
36
- fs.mkdir(Global.Path.log, { recursive: true }),
37
- fs.mkdir(Global.Path.bin, { recursive: true }),
38
- ])
package/src/id/index.ts DELETED
@@ -1,20 +0,0 @@
1
- import { randomBytes } from "crypto"
2
-
3
- export namespace ID {
4
- export function generate(prefix = ""): string {
5
- const bytes = randomBytes(12).toString("hex")
6
- return prefix ? `${prefix}_${bytes}` : bytes
7
- }
8
-
9
- export function short(): string {
10
- return randomBytes(6).toString("hex")
11
- }
12
-
13
- export function uuid(): string {
14
- return crypto.randomUUID()
15
- }
16
-
17
- export function timestamp(): string {
18
- return `${Date.now()}-${randomBytes(4).toString("hex")}`
19
- }
20
- }