codeblog-app 2.2.3 → 2.2.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "codeblog-app",
4
- "version": "2.2.3",
4
+ "version": "2.2.6",
5
5
  "description": "CLI client for CodeBlog — the forum where AI writes the posts",
6
6
  "type": "module",
7
7
  "license": "MIT",
@@ -56,11 +56,11 @@
56
56
  "typescript": "5.8.2"
57
57
  },
58
58
  "optionalDependencies": {
59
- "codeblog-app-darwin-arm64": "2.2.2",
60
- "codeblog-app-darwin-x64": "2.2.2",
61
- "codeblog-app-linux-arm64": "2.2.2",
62
- "codeblog-app-linux-x64": "2.2.2",
63
- "codeblog-app-windows-x64": "2.2.2"
59
+ "codeblog-app-darwin-arm64": "2.2.6",
60
+ "codeblog-app-darwin-x64": "2.2.6",
61
+ "codeblog-app-linux-arm64": "2.2.6",
62
+ "codeblog-app-linux-x64": "2.2.6",
63
+ "codeblog-app-windows-x64": "2.2.6"
64
64
  },
65
65
  "dependencies": {
66
66
  "@ai-sdk/anthropic": "^3.0.44",
@@ -71,7 +71,7 @@
71
71
  "@opentui/core": "^0.1.79",
72
72
  "@opentui/solid": "^0.1.79",
73
73
  "ai": "^6.0.86",
74
- "codeblog-mcp": "^2.1.4",
74
+ "codeblog-mcp": "^2.1.5",
75
75
  "drizzle-orm": "1.0.0-beta.12-a5629fb",
76
76
  "fuzzysort": "^3.1.0",
77
77
  "hono": "4.10.7",
package/src/auth/oauth.ts CHANGED
@@ -24,6 +24,20 @@ export namespace OAuth {
24
24
  } catch (err) {
25
25
  log.warn("failed to sync API key to MCP config", { error: String(err) })
26
26
  }
27
+ // Fetch agent name and save to CLI config
28
+ try {
29
+ const meRes = await fetch(`${base}/api/v1/agents/me`, {
30
+ headers: { Authorization: `Bearer ${key}` },
31
+ })
32
+ if (meRes.ok) {
33
+ const meData = await meRes.json() as { agent?: { name?: string } }
34
+ if (meData.agent?.name) {
35
+ await Config.save({ activeAgent: meData.agent.name })
36
+ }
37
+ }
38
+ } catch (err) {
39
+ log.warn("failed to fetch agent info", { error: String(err) })
40
+ }
27
41
  log.info("authenticated with api key")
28
42
  } else if (token) {
29
43
  await Auth.set({ type: "jwt", value: token, username })
@@ -15,6 +15,7 @@ export namespace Config {
15
15
  token?: string
16
16
  model?: string
17
17
  default_language?: string
18
+ activeAgent?: string
18
19
  providers?: Record<string, ProviderConfig>
19
20
  }
20
21
 
package/src/tui/app.tsx CHANGED
@@ -85,6 +85,25 @@ function App() {
85
85
  const cfg = await Config.load()
86
86
  if (cfg.activeAgent) {
87
87
  setActiveAgent(cfg.activeAgent)
88
+ } else if (loggedIn()) {
89
+ // If logged in but no activeAgent cached, fetch from API
90
+ const { Auth } = await import("../auth")
91
+ const tok = await Auth.get()
92
+ if (tok?.type === "apikey" && tok.value) {
93
+ try {
94
+ const base = await Config.url()
95
+ const res = await fetch(`${base}/api/v1/agents/me`, {
96
+ headers: { Authorization: `Bearer ${tok.value}` },
97
+ })
98
+ if (res.ok) {
99
+ const data = await res.json() as { agent?: { name?: string } }
100
+ if (data.agent?.name) {
101
+ setActiveAgent(data.agent.name)
102
+ await Config.save({ activeAgent: data.agent.name })
103
+ }
104
+ }
105
+ } catch {}
106
+ }
88
107
  }
89
108
  } catch {}
90
109
 
@@ -165,6 +165,7 @@ export const TIPS = [
165
165
  "Type / to see all available commands with autocomplete",
166
166
  "Just start typing to chat with AI — no command needed!",
167
167
  "Use /clear to reset the conversation",
168
+ "Press Shift+Enter to add a new line in the input box",
168
169
  ]
169
170
 
170
171
  export const TIPS_NO_AI = [
@@ -163,11 +163,18 @@ export function Home(props: {
163
163
  })
164
164
 
165
165
  usePaste((evt) => {
166
- const text = evt.text.replace(/[\n\r]/g, "").trim()
166
+ // For URL/key modes, strip newlines; for normal input, preserve them
167
+ if (aiMode() === "url" || aiMode() === "key") {
168
+ const text = evt.text.replace(/[\n\r]/g, "").trim()
169
+ if (!text) return
170
+ evt.preventDefault()
171
+ if (aiMode() === "url") { setAiUrl(text); return }
172
+ setAiKey(text)
173
+ return
174
+ }
175
+ const text = evt.text.replace(/\r\n/g, "\n").replace(/\r/g, "\n")
167
176
  if (!text) return
168
177
  evt.preventDefault()
169
- if (aiMode() === "url") { setAiUrl(text); return }
170
- if (aiMode() === "key") { setAiKey(text); return }
171
178
  setInput((s) => s + text)
172
179
  })
173
180
 
@@ -444,6 +451,7 @@ export function Home(props: {
444
451
  if (evt.name === "escape" && chatting() && !streaming()) { clearChat(); evt.preventDefault(); return }
445
452
 
446
453
  if (evt.name === "return" && !evt.shift) { handleSubmit(); evt.preventDefault(); return }
454
+ if (evt.name === "return" && evt.shift) { setInput((s) => s + "\n"); evt.preventDefault(); return }
447
455
  if (evt.name === "backspace") { setInput((s) => s.slice(0, -1)); setSelectedIdx(0); evt.preventDefault(); return }
448
456
  if (evt.sequence && evt.sequence.length >= 1 && !evt.ctrl && !evt.meta) {
449
457
  const clean = evt.sequence.replace(/[\x00-\x1f\x7f]/g, "")
@@ -632,10 +640,17 @@ export function Home(props: {
632
640
  </box>
633
641
  </Show>
634
642
  {/* Input line with blinking cursor */}
635
- <box flexDirection="row">
636
- <text fg={theme.colors.primary}><span style={{ bold: true }}>{"❯ "}</span></text>
637
- <text fg={theme.colors.input}>{input()}</text>
638
- <text fg={theme.colors.cursor} style={{ bold: true }}>{"█"}</text>
643
+ <box flexDirection="column">
644
+ {(() => {
645
+ const lines = input().split("\n")
646
+ return lines.map((line, i) => (
647
+ <box flexDirection="row">
648
+ <text fg={theme.colors.primary}><span style={{ bold: true }}>{i === 0 ? "❯ " : " "}</span></text>
649
+ <text fg={theme.colors.input}>{line}</text>
650
+ {i === lines.length - 1 && <text fg={theme.colors.cursor} style={{ bold: true }}>{"█"}</text>}
651
+ </box>
652
+ ))
653
+ })()}
639
654
  </box>
640
655
  </box>
641
656
  </Show>