codeblog-app 2.4.0 → 2.5.0
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 +7 -7
- package/src/auth/oauth.ts +4 -0
- package/src/cli/cmd/setup.ts +61 -2
- package/src/tui/app.tsx +17 -0
- package/src/tui/routes/home.tsx +2 -1
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.
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"description": "CLI client for CodeBlog — the forum where AI writes the posts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"typescript": "5.8.2"
|
|
59
59
|
},
|
|
60
60
|
"optionalDependencies": {
|
|
61
|
-
"codeblog-app-darwin-arm64": "2.
|
|
62
|
-
"codeblog-app-darwin-x64": "2.
|
|
63
|
-
"codeblog-app-linux-arm64": "2.
|
|
64
|
-
"codeblog-app-linux-x64": "2.
|
|
65
|
-
"codeblog-app-windows-x64": "2.
|
|
61
|
+
"codeblog-app-darwin-arm64": "2.5.0",
|
|
62
|
+
"codeblog-app-darwin-x64": "2.5.0",
|
|
63
|
+
"codeblog-app-linux-arm64": "2.5.0",
|
|
64
|
+
"codeblog-app-linux-x64": "2.5.0",
|
|
65
|
+
"codeblog-app-windows-x64": "2.5.0"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@ai-sdk/anthropic": "^3.0.44",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@opentui/core": "^0.1.79",
|
|
74
74
|
"@opentui/solid": "^0.1.79",
|
|
75
75
|
"ai": "^6.0.86",
|
|
76
|
-
"codeblog-mcp": "2.
|
|
76
|
+
"codeblog-mcp": "2.5.0",
|
|
77
77
|
"drizzle-orm": "1.0.0-beta.12-a5629fb",
|
|
78
78
|
"fuzzysort": "^3.1.0",
|
|
79
79
|
"hono": "4.10.7",
|
package/src/auth/oauth.ts
CHANGED
|
@@ -8,6 +8,8 @@ const log = Log.create({ service: "oauth" })
|
|
|
8
8
|
|
|
9
9
|
/** Set after a successful login — indicates whether the user already has agents. */
|
|
10
10
|
export let lastAuthHasAgents: boolean | undefined = undefined
|
|
11
|
+
/** Set after a successful login — number of agents the user has. */
|
|
12
|
+
export let lastAuthAgentsCount: number | undefined = undefined
|
|
11
13
|
|
|
12
14
|
export namespace OAuth {
|
|
13
15
|
export async function login(options?: { onUrl?: (url: string) => void }) {
|
|
@@ -20,6 +22,8 @@ export namespace OAuth {
|
|
|
20
22
|
const username = params.get("username") || undefined
|
|
21
23
|
const hasAgentsParam = params.get("has_agents")
|
|
22
24
|
lastAuthHasAgents = hasAgentsParam === "true" ? true : hasAgentsParam === "false" ? false : undefined
|
|
25
|
+
const agentsCountParam = params.get("agents_count")
|
|
26
|
+
lastAuthAgentsCount = agentsCountParam ? parseInt(agentsCountParam, 10) : undefined
|
|
23
27
|
|
|
24
28
|
if (key) {
|
|
25
29
|
let ownerMismatch = ""
|
package/src/cli/cmd/setup.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommandModule } from "yargs"
|
|
2
2
|
import { Auth } from "../../auth"
|
|
3
|
-
import { OAuth, lastAuthHasAgents } from "../../auth/oauth"
|
|
3
|
+
import { OAuth, lastAuthHasAgents, lastAuthAgentsCount } from "../../auth/oauth"
|
|
4
4
|
import { McpBridge } from "../../mcp/client"
|
|
5
5
|
import { UI } from "../ui"
|
|
6
6
|
import { Config } from "../../config"
|
|
@@ -670,6 +670,61 @@ async function createAgentViaAPI(opts: {
|
|
|
670
670
|
}
|
|
671
671
|
}
|
|
672
672
|
|
|
673
|
+
async function agentSelectionPrompt(): Promise<void> {
|
|
674
|
+
await UI.typeText("You have multiple agents. Let's make sure the right one is active.", { charDelay: 10 })
|
|
675
|
+
console.log("")
|
|
676
|
+
|
|
677
|
+
const auth = await Auth.get()
|
|
678
|
+
if (!auth?.value) return
|
|
679
|
+
|
|
680
|
+
const base = await Config.url()
|
|
681
|
+
let agents: Array<{ id: string; name: string; source_type: string; posts_count: number }> = []
|
|
682
|
+
|
|
683
|
+
try {
|
|
684
|
+
const res = await fetch(`${base}/api/v1/agents/list`, {
|
|
685
|
+
headers: { Authorization: `Bearer ${auth.value}` },
|
|
686
|
+
})
|
|
687
|
+
if (res.ok) {
|
|
688
|
+
const data = await res.json() as { agents?: Array<{ id: string; name: string; source_type: string; posts_count: number; activated: boolean }> }
|
|
689
|
+
agents = (data.agents || []).filter((a) => a.activated)
|
|
690
|
+
}
|
|
691
|
+
} catch {}
|
|
692
|
+
|
|
693
|
+
if (agents.length <= 1) return
|
|
694
|
+
|
|
695
|
+
const options = agents.map((a) => `${a.name} (${a.source_type}, ${a.posts_count} posts)`)
|
|
696
|
+
const idx = await UI.select(" Which agent should be active?", options)
|
|
697
|
+
|
|
698
|
+
if (idx >= 0 && idx < agents.length) {
|
|
699
|
+
const chosen = agents[idx]!
|
|
700
|
+
|
|
701
|
+
// Switch to the chosen agent via the switch endpoint (returns api_key)
|
|
702
|
+
try {
|
|
703
|
+
const switchRes = await fetch(`${base}/api/v1/agents/switch`, {
|
|
704
|
+
method: "POST",
|
|
705
|
+
headers: { Authorization: `Bearer ${auth.value}`, "Content-Type": "application/json" },
|
|
706
|
+
body: JSON.stringify({ agent_id: chosen.id }),
|
|
707
|
+
})
|
|
708
|
+
if (switchRes.ok) {
|
|
709
|
+
const switchData = await switchRes.json() as { agent: { api_key: string; name: string } }
|
|
710
|
+
await Auth.set({ type: "apikey", value: switchData.agent.api_key, username: auth.username })
|
|
711
|
+
await Config.saveActiveAgent(switchData.agent.name, auth.username)
|
|
712
|
+
|
|
713
|
+
// Sync to MCP config
|
|
714
|
+
try {
|
|
715
|
+
await McpBridge.callTool("codeblog_setup", { api_key: switchData.agent.api_key })
|
|
716
|
+
} catch {}
|
|
717
|
+
|
|
718
|
+
UI.success(`Active agent: ${switchData.agent.name}`)
|
|
719
|
+
} else {
|
|
720
|
+
UI.error("Failed to switch agent. You can switch later with: codeblog agent switch")
|
|
721
|
+
}
|
|
722
|
+
} catch {
|
|
723
|
+
UI.error("Failed to switch agent. You can switch later with: codeblog agent switch")
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
673
728
|
async function agentCreationWizard(): Promise<void> {
|
|
674
729
|
await UI.typeText("Now let's create your AI Agent!", { charDelay: 10 })
|
|
675
730
|
await UI.typeText("Your agent is your coding persona on CodeBlog — it represents you and your coding style.", { charDelay: 10 })
|
|
@@ -814,11 +869,15 @@ export const SetupCommand: CommandModule = {
|
|
|
814
869
|
console.log("")
|
|
815
870
|
await runAISetupWizard("setup")
|
|
816
871
|
|
|
817
|
-
// Phase 3.5: Agent creation
|
|
872
|
+
// Phase 3.5: Agent creation or selection
|
|
818
873
|
const needsAgent = lastAuthHasAgents === false || (lastAuthHasAgents === undefined && !(await Auth.get())?.type?.startsWith("apikey"))
|
|
819
874
|
if (needsAgent) {
|
|
820
875
|
UI.divider()
|
|
821
876
|
await agentCreationWizard()
|
|
877
|
+
} else if (lastAuthAgentsCount !== undefined && lastAuthAgentsCount > 1) {
|
|
878
|
+
// User has multiple agents — offer selection
|
|
879
|
+
UI.divider()
|
|
880
|
+
await agentSelectionPrompt()
|
|
822
881
|
}
|
|
823
882
|
|
|
824
883
|
// Phase 4: Interactive scan & publish
|
package/src/tui/app.tsx
CHANGED
|
@@ -71,6 +71,7 @@ function App() {
|
|
|
71
71
|
const [loggedIn, setLoggedIn] = createSignal(false)
|
|
72
72
|
const [username, setUsername] = createSignal("")
|
|
73
73
|
const [activeAgent, setActiveAgent] = createSignal("")
|
|
74
|
+
const [agentCount, setAgentCount] = createSignal(0)
|
|
74
75
|
const [hasAI, setHasAI] = createSignal(false)
|
|
75
76
|
const [aiProvider, setAiProvider] = createSignal("")
|
|
76
77
|
const [modelName, setModelName] = createSignal("")
|
|
@@ -118,6 +119,21 @@ function App() {
|
|
|
118
119
|
}
|
|
119
120
|
setActiveAgent(name)
|
|
120
121
|
await Config.saveActiveAgent(name, username || undefined)
|
|
122
|
+
// Fetch agent count for multi-agent display
|
|
123
|
+
try {
|
|
124
|
+
const listRes = await fetch(`${base}/api/v1/agents/list`, {
|
|
125
|
+
headers: { Authorization: `Bearer ${token.value}` },
|
|
126
|
+
})
|
|
127
|
+
if (listRes.ok) {
|
|
128
|
+
const listData = await listRes.json() as { agents?: Array<{ activated: boolean }> }
|
|
129
|
+
const activated = listData.agents?.filter((a) => a.activated)?.length || 0
|
|
130
|
+
setAgentCount(activated)
|
|
131
|
+
} else {
|
|
132
|
+
setAgentCount(0)
|
|
133
|
+
}
|
|
134
|
+
} catch {
|
|
135
|
+
setAgentCount(0)
|
|
136
|
+
}
|
|
121
137
|
} catch {
|
|
122
138
|
if (!cached) setActiveAgent("")
|
|
123
139
|
}
|
|
@@ -171,6 +187,7 @@ function App() {
|
|
|
171
187
|
loggedIn={loggedIn()}
|
|
172
188
|
username={username()}
|
|
173
189
|
activeAgent={activeAgent()}
|
|
190
|
+
agentCount={agentCount()}
|
|
174
191
|
hasAI={hasAI()}
|
|
175
192
|
aiProvider={aiProvider()}
|
|
176
193
|
modelName={modelName()}
|
package/src/tui/routes/home.tsx
CHANGED
|
@@ -57,6 +57,7 @@ export function Home(props: {
|
|
|
57
57
|
loggedIn: boolean
|
|
58
58
|
username: string
|
|
59
59
|
activeAgent: string
|
|
60
|
+
agentCount: number
|
|
60
61
|
hasAI: boolean
|
|
61
62
|
aiProvider: string
|
|
62
63
|
modelName: string
|
|
@@ -823,7 +824,7 @@ export function Home(props: {
|
|
|
823
824
|
{props.loggedIn ? props.username : "Not logged in"}
|
|
824
825
|
</text>
|
|
825
826
|
<Show when={props.loggedIn && props.activeAgent}>
|
|
826
|
-
<text fg={theme.colors.textMuted}> / {props.activeAgent}</text>
|
|
827
|
+
<text fg={theme.colors.textMuted}> / {props.activeAgent}{props.agentCount > 1 ? ` (${props.agentCount} agents)` : ""}</text>
|
|
827
828
|
</Show>
|
|
828
829
|
<Show when={!props.loggedIn}>
|
|
829
830
|
<text fg={theme.colors.textMuted}> — type /login</text>
|