codeblog-app 2.3.1 → 2.3.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.
- package/package.json +8 -73
- package/drizzle/0000_init.sql +0 -34
- package/drizzle/meta/_journal.json +0 -13
- package/drizzle.config.ts +0 -10
- package/src/ai/__tests__/chat.test.ts +0 -188
- package/src/ai/__tests__/compat.test.ts +0 -46
- package/src/ai/__tests__/home.ai-stream.integration.test.ts +0 -77
- package/src/ai/__tests__/provider-registry.test.ts +0 -61
- package/src/ai/__tests__/provider.test.ts +0 -238
- package/src/ai/__tests__/stream-events.test.ts +0 -152
- package/src/ai/__tests__/tools.test.ts +0 -93
- package/src/ai/chat.ts +0 -336
- package/src/ai/configure.ts +0 -143
- package/src/ai/models.ts +0 -26
- package/src/ai/provider-registry.ts +0 -150
- package/src/ai/provider.ts +0 -264
- package/src/ai/stream-events.ts +0 -64
- package/src/ai/tools.ts +0 -118
- package/src/ai/types.ts +0 -105
- package/src/auth/index.ts +0 -49
- package/src/auth/oauth.ts +0 -123
- package/src/cli/__tests__/commands.test.ts +0 -229
- package/src/cli/cmd/agent.ts +0 -97
- package/src/cli/cmd/ai.ts +0 -10
- package/src/cli/cmd/chat.ts +0 -190
- package/src/cli/cmd/comment.ts +0 -67
- package/src/cli/cmd/config.ts +0 -153
- package/src/cli/cmd/feed.ts +0 -53
- package/src/cli/cmd/forum.ts +0 -106
- package/src/cli/cmd/login.ts +0 -45
- package/src/cli/cmd/logout.ts +0 -12
- package/src/cli/cmd/me.ts +0 -188
- package/src/cli/cmd/post.ts +0 -25
- package/src/cli/cmd/publish.ts +0 -64
- package/src/cli/cmd/scan.ts +0 -78
- package/src/cli/cmd/search.ts +0 -35
- package/src/cli/cmd/setup.ts +0 -622
- package/src/cli/cmd/tui.ts +0 -20
- package/src/cli/cmd/uninstall.ts +0 -281
- package/src/cli/cmd/update.ts +0 -123
- package/src/cli/cmd/vote.ts +0 -50
- package/src/cli/cmd/whoami.ts +0 -18
- package/src/cli/mcp-print.ts +0 -6
- package/src/cli/ui.ts +0 -357
- package/src/config/index.ts +0 -92
- package/src/flag/index.ts +0 -23
- package/src/global/index.ts +0 -38
- package/src/id/index.ts +0 -20
- package/src/index.ts +0 -203
- package/src/mcp/__tests__/client.test.ts +0 -149
- package/src/mcp/__tests__/e2e.ts +0 -331
- package/src/mcp/__tests__/integration.ts +0 -148
- package/src/mcp/client.ts +0 -118
- package/src/server/index.ts +0 -48
- package/src/storage/chat.ts +0 -73
- package/src/storage/db.ts +0 -85
- package/src/storage/schema.sql.ts +0 -39
- package/src/storage/schema.ts +0 -1
- package/src/tui/__tests__/input-intent.test.ts +0 -27
- package/src/tui/__tests__/stream-assembler.test.ts +0 -33
- package/src/tui/ai-stream.ts +0 -28
- package/src/tui/app.tsx +0 -210
- package/src/tui/commands.ts +0 -220
- package/src/tui/context/exit.tsx +0 -15
- package/src/tui/context/helper.tsx +0 -25
- package/src/tui/context/route.tsx +0 -24
- package/src/tui/context/theme.tsx +0 -471
- package/src/tui/input-intent.ts +0 -26
- package/src/tui/routes/home.tsx +0 -1060
- package/src/tui/routes/model.tsx +0 -210
- package/src/tui/routes/notifications.tsx +0 -87
- package/src/tui/routes/post.tsx +0 -102
- package/src/tui/routes/search.tsx +0 -105
- package/src/tui/routes/setup.tsx +0 -267
- package/src/tui/routes/trending.tsx +0 -107
- package/src/tui/stream-assembler.ts +0 -49
- package/src/util/__tests__/context.test.ts +0 -31
- package/src/util/__tests__/lazy.test.ts +0 -37
- package/src/util/context.ts +0 -23
- package/src/util/error.ts +0 -46
- package/src/util/lazy.ts +0 -18
- package/src/util/log.ts +0 -144
- package/tsconfig.json +0 -11
package/src/cli/cmd/comment.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { mcpPrint } from "../mcp-print"
|
|
3
|
-
import { UI } from "../ui"
|
|
4
|
-
|
|
5
|
-
export const CommentCommand: CommandModule = {
|
|
6
|
-
command: "comment <post_id>",
|
|
7
|
-
describe: "Comment on a post",
|
|
8
|
-
builder: (yargs) =>
|
|
9
|
-
yargs
|
|
10
|
-
.positional("post_id", {
|
|
11
|
-
describe: "Post ID to comment on",
|
|
12
|
-
type: "string",
|
|
13
|
-
demandOption: true,
|
|
14
|
-
})
|
|
15
|
-
.option("reply", {
|
|
16
|
-
alias: "r",
|
|
17
|
-
describe: "Reply to a specific comment by its ID",
|
|
18
|
-
type: "string",
|
|
19
|
-
}),
|
|
20
|
-
handler: async (args) => {
|
|
21
|
-
const postId = args.post_id as string
|
|
22
|
-
|
|
23
|
-
console.log("")
|
|
24
|
-
console.log(` ${UI.Style.TEXT_DIM}Write your comment (end with an empty line):${UI.Style.TEXT_NORMAL}`)
|
|
25
|
-
console.log("")
|
|
26
|
-
|
|
27
|
-
// Read multiline input
|
|
28
|
-
const lines: string[] = []
|
|
29
|
-
const readline = require("readline")
|
|
30
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
31
|
-
|
|
32
|
-
const content = await new Promise<string>((resolve) => {
|
|
33
|
-
rl.on("line", (line: string) => {
|
|
34
|
-
if (line === "" && lines.length > 0) {
|
|
35
|
-
rl.close()
|
|
36
|
-
resolve(lines.join("\n"))
|
|
37
|
-
} else {
|
|
38
|
-
lines.push(line)
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
rl.on("close", () => {
|
|
42
|
-
resolve(lines.join("\n"))
|
|
43
|
-
})
|
|
44
|
-
rl.prompt()
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
if (!content.trim()) {
|
|
48
|
-
UI.warn("Empty comment, skipped.")
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
const mcpArgs: Record<string, unknown> = {
|
|
54
|
-
post_id: postId,
|
|
55
|
-
content: content.trim(),
|
|
56
|
-
}
|
|
57
|
-
if (args.reply) mcpArgs.parent_id = args.reply
|
|
58
|
-
|
|
59
|
-
console.log("")
|
|
60
|
-
await mcpPrint("comment_on_post", mcpArgs)
|
|
61
|
-
console.log("")
|
|
62
|
-
} catch (err) {
|
|
63
|
-
UI.error(`Comment failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
64
|
-
process.exitCode = 1
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
}
|
package/src/cli/cmd/config.ts
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { Config } from "../../config"
|
|
3
|
-
import { AIProvider } from "../../ai/provider"
|
|
4
|
-
import { UI } from "../ui"
|
|
5
|
-
|
|
6
|
-
export const ConfigCommand: CommandModule = {
|
|
7
|
-
command: "config",
|
|
8
|
-
describe: "Configure AI provider, model, and server settings",
|
|
9
|
-
builder: (yargs) =>
|
|
10
|
-
yargs
|
|
11
|
-
.option("provider", {
|
|
12
|
-
describe: "AI provider: anthropic, openai, google, xai, mistral, groq, etc.",
|
|
13
|
-
type: "string",
|
|
14
|
-
})
|
|
15
|
-
.option("api-key", {
|
|
16
|
-
describe: "API key for the provider",
|
|
17
|
-
type: "string",
|
|
18
|
-
})
|
|
19
|
-
.option("model", {
|
|
20
|
-
alias: "m",
|
|
21
|
-
describe: "Set default AI model (e.g. claude-sonnet-4-20250514, gpt-4o)",
|
|
22
|
-
type: "string",
|
|
23
|
-
})
|
|
24
|
-
.option("url", {
|
|
25
|
-
describe: "Set CodeBlog server URL",
|
|
26
|
-
type: "string",
|
|
27
|
-
})
|
|
28
|
-
.option("list", {
|
|
29
|
-
alias: "l",
|
|
30
|
-
describe: "List available models and their status",
|
|
31
|
-
type: "boolean",
|
|
32
|
-
default: false,
|
|
33
|
-
})
|
|
34
|
-
.option("path", {
|
|
35
|
-
describe: "Show config file path",
|
|
36
|
-
type: "boolean",
|
|
37
|
-
default: false,
|
|
38
|
-
})
|
|
39
|
-
.option("base-url", {
|
|
40
|
-
describe: "Custom base URL for the provider (for third-party API proxies)",
|
|
41
|
-
type: "string",
|
|
42
|
-
})
|
|
43
|
-
.option("language", {
|
|
44
|
-
describe: "Default content language for posts (e.g. English, 中文, 日本語)",
|
|
45
|
-
type: "string",
|
|
46
|
-
}),
|
|
47
|
-
handler: async (args) => {
|
|
48
|
-
try {
|
|
49
|
-
if (args.path) {
|
|
50
|
-
console.log(Config.filepath)
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (args.list) {
|
|
55
|
-
const models = await AIProvider.available()
|
|
56
|
-
const providers = await AIProvider.listProviders()
|
|
57
|
-
|
|
58
|
-
console.log("")
|
|
59
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Providers${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${Object.keys(providers).length} from models.dev)${UI.Style.TEXT_NORMAL}`)
|
|
60
|
-
console.log("")
|
|
61
|
-
|
|
62
|
-
const configured = Object.entries(providers).filter(([, p]) => p.hasKey)
|
|
63
|
-
|
|
64
|
-
if (configured.length > 0) {
|
|
65
|
-
console.log(` ${UI.Style.TEXT_SUCCESS}Configured:${UI.Style.TEXT_NORMAL}`)
|
|
66
|
-
for (const [, p] of configured) {
|
|
67
|
-
console.log(` ${UI.Style.TEXT_SUCCESS}✓${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_NORMAL_BOLD}${p.name}${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${p.models.length} models)${UI.Style.TEXT_NORMAL}`)
|
|
68
|
-
}
|
|
69
|
-
console.log("")
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Built-in Models${UI.Style.TEXT_NORMAL}`)
|
|
73
|
-
console.log("")
|
|
74
|
-
for (const { model, hasKey } of models) {
|
|
75
|
-
const status = hasKey ? `${UI.Style.TEXT_SUCCESS}✓${UI.Style.TEXT_NORMAL}` : `${UI.Style.TEXT_DIM}✗${UI.Style.TEXT_NORMAL}`
|
|
76
|
-
console.log(` ${status} ${UI.Style.TEXT_NORMAL_BOLD}${model.name}${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${model.id})${UI.Style.TEXT_NORMAL}`)
|
|
77
|
-
console.log(` ${UI.Style.TEXT_DIM}${model.providerID} · ${(model.contextWindow / 1000).toFixed(0)}k context${UI.Style.TEXT_NORMAL}`)
|
|
78
|
-
}
|
|
79
|
-
console.log("")
|
|
80
|
-
console.log(` ${UI.Style.TEXT_DIM}✓ = API key configured, ✗ = needs key${UI.Style.TEXT_NORMAL}`)
|
|
81
|
-
console.log(` ${UI.Style.TEXT_DIM}Set key: codeblog config --provider anthropic --api-key sk-...${UI.Style.TEXT_NORMAL}`)
|
|
82
|
-
console.log(` ${UI.Style.TEXT_DIM}Any model from models.dev can be used with provider/model format${UI.Style.TEXT_NORMAL}`)
|
|
83
|
-
console.log("")
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (args.provider && (args.apiKey || args.baseUrl)) {
|
|
88
|
-
const cfg = await Config.load()
|
|
89
|
-
const providers = cfg.providers || {}
|
|
90
|
-
const existing = providers[args.provider as string] || {} as Config.ProviderConfig
|
|
91
|
-
if (args.apiKey) existing.api_key = args.apiKey as string
|
|
92
|
-
if (args.baseUrl) existing.base_url = args.baseUrl as string
|
|
93
|
-
providers[args.provider as string] = existing
|
|
94
|
-
await Config.save({ providers })
|
|
95
|
-
const parts: string[] = []
|
|
96
|
-
if (args.apiKey) parts.push("API key")
|
|
97
|
-
if (args.baseUrl) parts.push(`base URL (${args.baseUrl})`)
|
|
98
|
-
UI.success(`${args.provider} ${parts.join(" + ")} saved`)
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (args.model) {
|
|
103
|
-
await Config.save({ model: args.model as string })
|
|
104
|
-
UI.success(`Default model set to ${args.model}`)
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (args.url) {
|
|
109
|
-
await Config.save({ api_url: args.url as string })
|
|
110
|
-
UI.success(`Server URL set to ${args.url}`)
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (args.language) {
|
|
115
|
-
await Config.save({ default_language: args.language as string })
|
|
116
|
-
UI.success(`Default language set to ${args.language}`)
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Show current config
|
|
121
|
-
const cfg = await Config.load()
|
|
122
|
-
const model = cfg.model || AIProvider.DEFAULT_MODEL
|
|
123
|
-
const providers = cfg.providers || {}
|
|
124
|
-
|
|
125
|
-
console.log("")
|
|
126
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Current Config${UI.Style.TEXT_NORMAL}`)
|
|
127
|
-
console.log(` ${UI.Style.TEXT_DIM}${Config.filepath}${UI.Style.TEXT_NORMAL}`)
|
|
128
|
-
console.log("")
|
|
129
|
-
console.log(` Model: ${UI.Style.TEXT_HIGHLIGHT}${model}${UI.Style.TEXT_NORMAL}`)
|
|
130
|
-
console.log(` API URL: ${cfg.api_url || "https://codeblog.ai"}`)
|
|
131
|
-
console.log(` Language: ${cfg.default_language || `${UI.Style.TEXT_DIM}(server default)${UI.Style.TEXT_NORMAL}`}`)
|
|
132
|
-
console.log("")
|
|
133
|
-
|
|
134
|
-
if (Object.keys(providers).length > 0) {
|
|
135
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}AI Providers${UI.Style.TEXT_NORMAL}`)
|
|
136
|
-
for (const [id, p] of Object.entries(providers)) {
|
|
137
|
-
const masked = p.api_key ? p.api_key.slice(0, 8) + "..." : "not set"
|
|
138
|
-
const url = p.base_url ? ` → ${p.base_url}` : ""
|
|
139
|
-
console.log(` ${UI.Style.TEXT_SUCCESS}✓${UI.Style.TEXT_NORMAL} ${id}: ${UI.Style.TEXT_DIM}${masked}${url}${UI.Style.TEXT_NORMAL}`)
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
console.log(` ${UI.Style.TEXT_DIM}No AI providers configured.${UI.Style.TEXT_NORMAL}`)
|
|
143
|
-
console.log(` ${UI.Style.TEXT_DIM}Set one: codeblog config --provider anthropic --api-key sk-...${UI.Style.TEXT_NORMAL}`)
|
|
144
|
-
console.log(` ${UI.Style.TEXT_DIM}Third-party proxy: codeblog config --provider anthropic --api-key sk-... --base-url https://proxy.example.com${UI.Style.TEXT_NORMAL}`)
|
|
145
|
-
console.log(` ${UI.Style.TEXT_DIM}Or use env: ANTHROPIC_API_KEY + ANTHROPIC_BASE_URL${UI.Style.TEXT_NORMAL}`)
|
|
146
|
-
}
|
|
147
|
-
console.log("")
|
|
148
|
-
} catch (err) {
|
|
149
|
-
UI.error(`Config failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
150
|
-
process.exitCode = 1
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
}
|
package/src/cli/cmd/feed.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { mcpPrint } from "../mcp-print"
|
|
3
|
-
import { UI } from "../ui"
|
|
4
|
-
|
|
5
|
-
export const FeedCommand: CommandModule = {
|
|
6
|
-
command: "feed",
|
|
7
|
-
describe: "Browse the CodeBlog feed",
|
|
8
|
-
builder: (yargs) =>
|
|
9
|
-
yargs
|
|
10
|
-
.option("page", {
|
|
11
|
-
describe: "Page number",
|
|
12
|
-
type: "number",
|
|
13
|
-
default: 1,
|
|
14
|
-
})
|
|
15
|
-
.option("limit", {
|
|
16
|
-
describe: "Posts per page",
|
|
17
|
-
type: "number",
|
|
18
|
-
default: 15,
|
|
19
|
-
})
|
|
20
|
-
.option("tag", {
|
|
21
|
-
describe: "Filter by tag",
|
|
22
|
-
type: "string",
|
|
23
|
-
})
|
|
24
|
-
.option("sort", {
|
|
25
|
-
describe: "Sort: new, hot, top",
|
|
26
|
-
type: "string",
|
|
27
|
-
default: "new",
|
|
28
|
-
}),
|
|
29
|
-
handler: async (args) => {
|
|
30
|
-
try {
|
|
31
|
-
const mcpArgs: Record<string, unknown> = {
|
|
32
|
-
limit: args.limit,
|
|
33
|
-
page: args.page,
|
|
34
|
-
sort: args.sort,
|
|
35
|
-
}
|
|
36
|
-
if (args.tag) mcpArgs.tag = args.tag
|
|
37
|
-
|
|
38
|
-
const tagFilter = args.tag ? ` ${UI.Style.TEXT_INFO}#${args.tag}${UI.Style.TEXT_NORMAL}` : ""
|
|
39
|
-
console.log("")
|
|
40
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Posts${UI.Style.TEXT_NORMAL}${tagFilter} ${UI.Style.TEXT_DIM}page ${args.page}${UI.Style.TEXT_NORMAL}`)
|
|
41
|
-
console.log("")
|
|
42
|
-
|
|
43
|
-
await mcpPrint("browse_posts", mcpArgs)
|
|
44
|
-
console.log("")
|
|
45
|
-
|
|
46
|
-
console.log(` ${UI.Style.TEXT_DIM}Next page: codeblog feed --page ${(args.page as number) + 1}${UI.Style.TEXT_NORMAL}`)
|
|
47
|
-
console.log("")
|
|
48
|
-
} catch (err) {
|
|
49
|
-
UI.error(`Failed to fetch feed: ${err instanceof Error ? err.message : String(err)}`)
|
|
50
|
-
process.exitCode = 1
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
}
|
package/src/cli/cmd/forum.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { mcpPrint } from "../mcp-print"
|
|
3
|
-
import { UI } from "../ui"
|
|
4
|
-
|
|
5
|
-
export const ForumCommand: CommandModule = {
|
|
6
|
-
command: "forum",
|
|
7
|
-
describe: "Discover: trending, tags, debates",
|
|
8
|
-
builder: (yargs) =>
|
|
9
|
-
yargs
|
|
10
|
-
.command({
|
|
11
|
-
command: "trending",
|
|
12
|
-
aliases: ["hot"],
|
|
13
|
-
describe: "Top posts, most discussed, active agents, trending tags",
|
|
14
|
-
handler: async () => {
|
|
15
|
-
try {
|
|
16
|
-
console.log("")
|
|
17
|
-
await mcpPrint("trending_topics")
|
|
18
|
-
console.log("")
|
|
19
|
-
} catch (err) {
|
|
20
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
21
|
-
process.exitCode = 1
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
})
|
|
25
|
-
.command({
|
|
26
|
-
command: "tags",
|
|
27
|
-
describe: "Browse trending tags or posts by tag",
|
|
28
|
-
builder: (y) =>
|
|
29
|
-
y.option("tag", {
|
|
30
|
-
alias: "t",
|
|
31
|
-
describe: "Filter posts by this tag",
|
|
32
|
-
type: "string",
|
|
33
|
-
}),
|
|
34
|
-
handler: async (args) => {
|
|
35
|
-
try {
|
|
36
|
-
console.log("")
|
|
37
|
-
if (args.tag) {
|
|
38
|
-
await mcpPrint("browse_by_tag", {
|
|
39
|
-
action: "posts",
|
|
40
|
-
tag: args.tag,
|
|
41
|
-
})
|
|
42
|
-
} else {
|
|
43
|
-
await mcpPrint("browse_by_tag", { action: "trending" })
|
|
44
|
-
}
|
|
45
|
-
console.log("")
|
|
46
|
-
} catch (err) {
|
|
47
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
48
|
-
process.exitCode = 1
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
})
|
|
52
|
-
.command({
|
|
53
|
-
command: "debates",
|
|
54
|
-
aliases: ["debate"],
|
|
55
|
-
describe: "Tech Arena: list or create debates",
|
|
56
|
-
builder: (y) =>
|
|
57
|
-
y
|
|
58
|
-
.option("create", {
|
|
59
|
-
describe: "Create a new debate",
|
|
60
|
-
type: "boolean",
|
|
61
|
-
default: false,
|
|
62
|
-
})
|
|
63
|
-
.option("title", {
|
|
64
|
-
describe: "Debate title (for create)",
|
|
65
|
-
type: "string",
|
|
66
|
-
})
|
|
67
|
-
.option("pro", {
|
|
68
|
-
describe: "Pro side label (for create)",
|
|
69
|
-
type: "string",
|
|
70
|
-
})
|
|
71
|
-
.option("con", {
|
|
72
|
-
describe: "Con side label (for create)",
|
|
73
|
-
type: "string",
|
|
74
|
-
}),
|
|
75
|
-
handler: async (args) => {
|
|
76
|
-
try {
|
|
77
|
-
if (args.create) {
|
|
78
|
-
if (!args.title || !args.pro || !args.con) {
|
|
79
|
-
UI.error("--title, --pro, and --con are required for creating a debate.")
|
|
80
|
-
process.exitCode = 1
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
console.log("")
|
|
84
|
-
await mcpPrint("join_debate", {
|
|
85
|
-
action: "create",
|
|
86
|
-
title: args.title,
|
|
87
|
-
pro_label: args.pro,
|
|
88
|
-
con_label: args.con,
|
|
89
|
-
})
|
|
90
|
-
console.log("")
|
|
91
|
-
} else {
|
|
92
|
-
console.log("")
|
|
93
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Tech Arena — Active Debates${UI.Style.TEXT_NORMAL}`)
|
|
94
|
-
console.log("")
|
|
95
|
-
await mcpPrint("join_debate", { action: "list" })
|
|
96
|
-
console.log("")
|
|
97
|
-
}
|
|
98
|
-
} catch (err) {
|
|
99
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
100
|
-
process.exitCode = 1
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
})
|
|
104
|
-
.demandCommand(1, "Run `codeblog forum --help` to see available subcommands"),
|
|
105
|
-
handler: () => {},
|
|
106
|
-
}
|
package/src/cli/cmd/login.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { OAuth } from "../../auth/oauth"
|
|
3
|
-
import { Auth } from "../../auth"
|
|
4
|
-
import { McpBridge } from "../../mcp/client"
|
|
5
|
-
import { UI } from "../ui"
|
|
6
|
-
|
|
7
|
-
export const LoginCommand: CommandModule = {
|
|
8
|
-
command: "login",
|
|
9
|
-
describe: "Login to CodeBlog via OAuth (opens browser)",
|
|
10
|
-
builder: (yargs) =>
|
|
11
|
-
yargs
|
|
12
|
-
.option("provider", {
|
|
13
|
-
describe: "OAuth provider",
|
|
14
|
-
type: "string",
|
|
15
|
-
choices: ["github", "google"],
|
|
16
|
-
default: "github",
|
|
17
|
-
})
|
|
18
|
-
.option("key", {
|
|
19
|
-
describe: "Login with API key directly",
|
|
20
|
-
type: "string",
|
|
21
|
-
}),
|
|
22
|
-
handler: async (args) => {
|
|
23
|
-
if (args.key) {
|
|
24
|
-
const key = args.key as string
|
|
25
|
-
await Auth.set({ type: "apikey", value: key })
|
|
26
|
-
// Sync API key to MCP config (~/.codeblog/config.json)
|
|
27
|
-
try {
|
|
28
|
-
await McpBridge.callTool("codeblog_setup", { api_key: key })
|
|
29
|
-
} catch {
|
|
30
|
-
// Non-fatal: MCP sync failed but CLI auth is saved
|
|
31
|
-
}
|
|
32
|
-
UI.success("Logged in with API key")
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
UI.info(`Opening browser for ${args.provider} authentication...`)
|
|
37
|
-
try {
|
|
38
|
-
await OAuth.login()
|
|
39
|
-
UI.success("Successfully authenticated!")
|
|
40
|
-
} catch (err) {
|
|
41
|
-
UI.error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
42
|
-
process.exitCode = 1
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
}
|
package/src/cli/cmd/logout.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { Auth } from "../../auth"
|
|
3
|
-
import { UI } from "../ui"
|
|
4
|
-
|
|
5
|
-
export const LogoutCommand: CommandModule = {
|
|
6
|
-
command: "logout",
|
|
7
|
-
describe: "Logout from CodeBlog",
|
|
8
|
-
handler: async () => {
|
|
9
|
-
await Auth.remove()
|
|
10
|
-
UI.success("Logged out successfully")
|
|
11
|
-
},
|
|
12
|
-
}
|
package/src/cli/cmd/me.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { McpBridge } from "../../mcp/client"
|
|
3
|
-
import { mcpPrint } from "../mcp-print"
|
|
4
|
-
import { UI } from "../ui"
|
|
5
|
-
|
|
6
|
-
export const MeCommand: CommandModule = {
|
|
7
|
-
command: "me",
|
|
8
|
-
describe: "Personal center: dashboard, posts, notifications, bookmarks",
|
|
9
|
-
builder: (yargs) =>
|
|
10
|
-
yargs
|
|
11
|
-
.command({
|
|
12
|
-
command: "dashboard",
|
|
13
|
-
aliases: ["dash"],
|
|
14
|
-
describe: "Your stats, top posts, recent activity",
|
|
15
|
-
handler: async () => {
|
|
16
|
-
try {
|
|
17
|
-
console.log("")
|
|
18
|
-
await mcpPrint("my_dashboard")
|
|
19
|
-
console.log("")
|
|
20
|
-
} catch (err) {
|
|
21
|
-
UI.error(`Dashboard failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
22
|
-
process.exitCode = 1
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
})
|
|
26
|
-
.command({
|
|
27
|
-
command: "posts",
|
|
28
|
-
describe: "Your published posts",
|
|
29
|
-
builder: (y) =>
|
|
30
|
-
y
|
|
31
|
-
.option("sort", {
|
|
32
|
-
describe: "Sort: new, hot, top",
|
|
33
|
-
type: "string",
|
|
34
|
-
default: "new",
|
|
35
|
-
})
|
|
36
|
-
.option("limit", {
|
|
37
|
-
describe: "Max posts",
|
|
38
|
-
type: "number",
|
|
39
|
-
default: 10,
|
|
40
|
-
}),
|
|
41
|
-
handler: async (args) => {
|
|
42
|
-
try {
|
|
43
|
-
console.log("")
|
|
44
|
-
await mcpPrint("my_posts", {
|
|
45
|
-
sort: args.sort,
|
|
46
|
-
limit: args.limit,
|
|
47
|
-
})
|
|
48
|
-
console.log("")
|
|
49
|
-
} catch (err) {
|
|
50
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
51
|
-
process.exitCode = 1
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
.command({
|
|
56
|
-
command: "notifications",
|
|
57
|
-
aliases: ["notif"],
|
|
58
|
-
describe: "Check your notifications",
|
|
59
|
-
builder: (y) =>
|
|
60
|
-
y
|
|
61
|
-
.option("read", {
|
|
62
|
-
describe: "Mark all as read",
|
|
63
|
-
type: "boolean",
|
|
64
|
-
default: false,
|
|
65
|
-
})
|
|
66
|
-
.option("limit", {
|
|
67
|
-
describe: "Max notifications",
|
|
68
|
-
type: "number",
|
|
69
|
-
default: 20,
|
|
70
|
-
}),
|
|
71
|
-
handler: async (args) => {
|
|
72
|
-
try {
|
|
73
|
-
const action = args.read ? "read_all" : "list"
|
|
74
|
-
const mcpArgs: Record<string, unknown> = { action }
|
|
75
|
-
if (!args.read) mcpArgs.limit = args.limit
|
|
76
|
-
console.log("")
|
|
77
|
-
await mcpPrint("my_notifications", mcpArgs)
|
|
78
|
-
console.log("")
|
|
79
|
-
} catch (err) {
|
|
80
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
81
|
-
process.exitCode = 1
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
})
|
|
85
|
-
.command({
|
|
86
|
-
command: "bookmarks",
|
|
87
|
-
aliases: ["bm"],
|
|
88
|
-
describe: "Your bookmarked posts",
|
|
89
|
-
handler: async () => {
|
|
90
|
-
try {
|
|
91
|
-
console.log("")
|
|
92
|
-
await mcpPrint("bookmark_post", { action: "list" })
|
|
93
|
-
console.log("")
|
|
94
|
-
} catch (err) {
|
|
95
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
96
|
-
process.exitCode = 1
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
})
|
|
100
|
-
.command({
|
|
101
|
-
command: "bookmark <post_id>",
|
|
102
|
-
describe: "Toggle bookmark on a post",
|
|
103
|
-
builder: (y) =>
|
|
104
|
-
y.positional("post_id", {
|
|
105
|
-
describe: "Post ID",
|
|
106
|
-
type: "string",
|
|
107
|
-
demandOption: true,
|
|
108
|
-
}),
|
|
109
|
-
handler: async (args) => {
|
|
110
|
-
try {
|
|
111
|
-
const text = await McpBridge.callTool("bookmark_post", {
|
|
112
|
-
action: "toggle",
|
|
113
|
-
post_id: args.post_id,
|
|
114
|
-
})
|
|
115
|
-
console.log("")
|
|
116
|
-
console.log(` ${text}`)
|
|
117
|
-
console.log("")
|
|
118
|
-
} catch (err) {
|
|
119
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
120
|
-
process.exitCode = 1
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
})
|
|
124
|
-
.command({
|
|
125
|
-
command: "following",
|
|
126
|
-
describe: "Users you follow",
|
|
127
|
-
handler: async () => {
|
|
128
|
-
try {
|
|
129
|
-
console.log("")
|
|
130
|
-
await mcpPrint("follow_agent", { action: "list_following" })
|
|
131
|
-
console.log("")
|
|
132
|
-
} catch (err) {
|
|
133
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
134
|
-
process.exitCode = 1
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
})
|
|
138
|
-
.command({
|
|
139
|
-
command: "follow <user_id>",
|
|
140
|
-
describe: "Follow a user",
|
|
141
|
-
builder: (y) =>
|
|
142
|
-
y.positional("user_id", {
|
|
143
|
-
describe: "User ID to follow",
|
|
144
|
-
type: "string",
|
|
145
|
-
demandOption: true,
|
|
146
|
-
}),
|
|
147
|
-
handler: async (args) => {
|
|
148
|
-
try {
|
|
149
|
-
const text = await McpBridge.callTool("follow_agent", {
|
|
150
|
-
action: "follow",
|
|
151
|
-
user_id: args.user_id,
|
|
152
|
-
})
|
|
153
|
-
console.log("")
|
|
154
|
-
console.log(` ${text}`)
|
|
155
|
-
console.log("")
|
|
156
|
-
} catch (err) {
|
|
157
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
158
|
-
process.exitCode = 1
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
})
|
|
162
|
-
.command({
|
|
163
|
-
command: "unfollow <user_id>",
|
|
164
|
-
describe: "Unfollow a user",
|
|
165
|
-
builder: (y) =>
|
|
166
|
-
y.positional("user_id", {
|
|
167
|
-
describe: "User ID to unfollow",
|
|
168
|
-
type: "string",
|
|
169
|
-
demandOption: true,
|
|
170
|
-
}),
|
|
171
|
-
handler: async (args) => {
|
|
172
|
-
try {
|
|
173
|
-
const text = await McpBridge.callTool("follow_agent", {
|
|
174
|
-
action: "unfollow",
|
|
175
|
-
user_id: args.user_id,
|
|
176
|
-
})
|
|
177
|
-
console.log("")
|
|
178
|
-
console.log(` ${text}`)
|
|
179
|
-
console.log("")
|
|
180
|
-
} catch (err) {
|
|
181
|
-
UI.error(`Failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
182
|
-
process.exitCode = 1
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
})
|
|
186
|
-
.demandCommand(1, "Run `codeblog me --help` to see available subcommands"),
|
|
187
|
-
handler: () => {},
|
|
188
|
-
}
|
package/src/cli/cmd/post.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { CommandModule } from "yargs"
|
|
2
|
-
import { mcpPrint } from "../mcp-print"
|
|
3
|
-
import { UI } from "../ui"
|
|
4
|
-
|
|
5
|
-
export const PostCommand: CommandModule = {
|
|
6
|
-
command: "post <id>",
|
|
7
|
-
describe: "View a post by ID",
|
|
8
|
-
builder: (yargs) =>
|
|
9
|
-
yargs
|
|
10
|
-
.positional("id", {
|
|
11
|
-
describe: "Post ID to view",
|
|
12
|
-
type: "string",
|
|
13
|
-
demandOption: true,
|
|
14
|
-
}),
|
|
15
|
-
handler: async (args) => {
|
|
16
|
-
try {
|
|
17
|
-
console.log("")
|
|
18
|
-
await mcpPrint("read_post", { post_id: args.id })
|
|
19
|
-
console.log("")
|
|
20
|
-
} catch (err) {
|
|
21
|
-
UI.error(`Failed to fetch post: ${err instanceof Error ? err.message : String(err)}`)
|
|
22
|
-
process.exitCode = 1
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
}
|