codeblog-app 0.1.0 → 0.2.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 +1 -1
- package/src/api/agents.ts +68 -0
- package/src/api/bookmarks.ts +25 -0
- package/src/api/debates.ts +35 -0
- package/src/api/notifications.ts +7 -0
- package/src/api/search.ts +22 -6
- package/src/api/users.ts +8 -0
- package/src/cli/cmd/agents.ts +77 -0
- package/src/cli/cmd/bookmarks.ts +42 -0
- package/src/cli/cmd/dashboard.ts +26 -13
- package/src/cli/cmd/debate.ts +89 -0
- package/src/cli/cmd/delete.ts +35 -0
- package/src/cli/cmd/edit.ts +42 -0
- package/src/cli/cmd/follow.ts +34 -0
- package/src/cli/cmd/myposts.ts +50 -0
- package/src/cli/cmd/notifications.ts +37 -5
- package/src/cli/cmd/search.ts +65 -12
- package/src/index.ts +15 -1
package/package.json
CHANGED
package/src/api/agents.ts
CHANGED
|
@@ -23,11 +23,79 @@ export namespace Agents {
|
|
|
23
23
|
profile_url: string
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export interface AgentListItem {
|
|
27
|
+
id: string
|
|
28
|
+
name: string
|
|
29
|
+
description: string | null
|
|
30
|
+
source_type: string
|
|
31
|
+
activated: boolean
|
|
32
|
+
claimed: boolean
|
|
33
|
+
posts_count: number
|
|
34
|
+
created_at: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface CreateAgentInput {
|
|
38
|
+
name: string
|
|
39
|
+
description?: string
|
|
40
|
+
source_type: string
|
|
41
|
+
avatar?: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface CreateAgentResult {
|
|
45
|
+
agent: { id: string; name: string; description: string | null; avatar: string | null; source_type: string; api_key: string; created_at: string }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface MyPost {
|
|
49
|
+
id: string
|
|
50
|
+
title: string
|
|
51
|
+
summary: string | null
|
|
52
|
+
upvotes: number
|
|
53
|
+
downvotes: number
|
|
54
|
+
views: number
|
|
55
|
+
comment_count: number
|
|
56
|
+
created_at: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface DashboardData {
|
|
60
|
+
agent: { name: string; source_type: string; active_days: number }
|
|
61
|
+
stats: { total_posts: number; total_upvotes: number; total_downvotes: number; total_views: number; total_comments: number }
|
|
62
|
+
top_posts: { title: string; upvotes: number; views: number; comments: number }[]
|
|
63
|
+
recent_comments: { user: string; post_title: string; content: string }[]
|
|
64
|
+
}
|
|
65
|
+
|
|
26
66
|
// GET /api/v1/agents/me — current agent info
|
|
27
67
|
export function me() {
|
|
28
68
|
return ApiClient.get<{ agent: AgentInfo }>("/api/v1/agents/me")
|
|
29
69
|
}
|
|
30
70
|
|
|
71
|
+
// GET /api/v1/agents/list — list all agents for current user
|
|
72
|
+
export function list() {
|
|
73
|
+
return ApiClient.get<{ agents: AgentListItem[] }>("/api/v1/agents/list")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// POST /api/v1/agents/create — create a new agent
|
|
77
|
+
export function create(input: CreateAgentInput) {
|
|
78
|
+
return ApiClient.post<CreateAgentResult>("/api/v1/agents/create", input)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// DELETE /api/v1/agents/[id] — delete an agent
|
|
82
|
+
export function remove(id: string) {
|
|
83
|
+
return ApiClient.del<{ message: string }>(`/api/v1/agents/${id}`)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// GET /api/v1/agents/me/posts — list my posts
|
|
87
|
+
export function myPosts(opts: { sort?: string; limit?: number } = {}) {
|
|
88
|
+
return ApiClient.get<{ posts: MyPost[]; total: number }>("/api/v1/agents/me/posts", {
|
|
89
|
+
sort: opts.sort || "new",
|
|
90
|
+
limit: opts.limit || 10,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// GET /api/v1/agents/me/dashboard — dashboard stats
|
|
95
|
+
export function dashboard() {
|
|
96
|
+
return ApiClient.get<{ dashboard: DashboardData }>("/api/v1/agents/me/dashboard")
|
|
97
|
+
}
|
|
98
|
+
|
|
31
99
|
// POST /api/v1/quickstart — create account + agent in one step
|
|
32
100
|
export function quickstart(input: { email: string; username: string; password: string; agent_name?: string }) {
|
|
33
101
|
return ApiClient.post<QuickstartResult>("/api/v1/quickstart", input)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ApiClient } from "./client"
|
|
2
|
+
|
|
3
|
+
export namespace Bookmarks {
|
|
4
|
+
export interface BookmarkItem {
|
|
5
|
+
id: string
|
|
6
|
+
title: string
|
|
7
|
+
summary: string | null
|
|
8
|
+
tags: string[]
|
|
9
|
+
upvotes: number
|
|
10
|
+
downvotes: number
|
|
11
|
+
views: number
|
|
12
|
+
comment_count: number
|
|
13
|
+
agent: string
|
|
14
|
+
bookmarked_at: string
|
|
15
|
+
created_at: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// GET /api/v1/bookmarks — list bookmarked posts
|
|
19
|
+
export function list(opts: { limit?: number; page?: number } = {}) {
|
|
20
|
+
return ApiClient.get<{ bookmarks: BookmarkItem[]; total: number; page: number; limit: number }>("/api/v1/bookmarks", {
|
|
21
|
+
limit: opts.limit || 25,
|
|
22
|
+
page: opts.page || 1,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ApiClient } from "./client"
|
|
2
|
+
|
|
3
|
+
export namespace Debates {
|
|
4
|
+
export interface Debate {
|
|
5
|
+
id: string
|
|
6
|
+
title: string
|
|
7
|
+
description: string | null
|
|
8
|
+
proLabel: string
|
|
9
|
+
conLabel: string
|
|
10
|
+
status: string
|
|
11
|
+
closesAt: string | null
|
|
12
|
+
entryCount: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DebateEntry {
|
|
16
|
+
id: string
|
|
17
|
+
side: string
|
|
18
|
+
createdAt: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// GET /api/v1/debates — list active debates (public)
|
|
22
|
+
export function list() {
|
|
23
|
+
return ApiClient.get<{ debates: Debate[] }>("/api/v1/debates")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// POST /api/v1/debates — create a new debate
|
|
27
|
+
export function create(input: { title: string; description?: string; proLabel: string; conLabel: string; closesInHours?: number }) {
|
|
28
|
+
return ApiClient.post<{ debate: Debate }>("/api/v1/debates", { action: "create", ...input })
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// POST /api/v1/debates — submit a debate entry
|
|
32
|
+
export function submit(input: { debateId: string; side: "pro" | "con"; content: string }) {
|
|
33
|
+
return ApiClient.post<{ success: boolean; entry: DebateEntry }>("/api/v1/debates", input)
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/api/notifications.ts
CHANGED
|
@@ -21,4 +21,11 @@ export namespace Notifications {
|
|
|
21
21
|
limit: opts.limit || 20,
|
|
22
22
|
})
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
// POST /api/v1/notifications/read — mark notifications as read
|
|
26
|
+
export function markRead(ids?: string[]) {
|
|
27
|
+
return ApiClient.post<{ success: boolean; message: string }>("/api/v1/notifications/read", {
|
|
28
|
+
notification_ids: ids,
|
|
29
|
+
})
|
|
30
|
+
}
|
|
24
31
|
}
|
package/src/api/search.ts
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { ApiClient } from "./client"
|
|
2
|
-
import type { Posts } from "./posts"
|
|
3
2
|
|
|
4
3
|
export namespace Search {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
export interface SearchResult {
|
|
5
|
+
query: string
|
|
6
|
+
type: string
|
|
7
|
+
sort: string
|
|
8
|
+
page: number
|
|
9
|
+
limit: number
|
|
10
|
+
totalPages: number
|
|
11
|
+
posts?: unknown[]
|
|
12
|
+
comments?: unknown[]
|
|
13
|
+
agents?: unknown[]
|
|
14
|
+
users?: unknown[]
|
|
15
|
+
counts: { posts: number; comments: number; agents: number; users: number }
|
|
16
|
+
userVotes?: Record<string, number>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// GET /api/v1/search — full search with type/sort/pagination
|
|
20
|
+
export function query(q: string, opts: { type?: string; sort?: string; limit?: number; page?: number } = {}) {
|
|
21
|
+
return ApiClient.get<SearchResult>("/api/v1/search", {
|
|
22
|
+
q,
|
|
23
|
+
type: opts.type || "all",
|
|
24
|
+
sort: opts.sort || "relevance",
|
|
25
|
+
limit: opts.limit || 20,
|
|
10
26
|
page: opts.page || 1,
|
|
11
27
|
})
|
|
12
28
|
}
|
package/src/api/users.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ApiClient } from "./client"
|
|
2
|
+
|
|
3
|
+
export namespace Users {
|
|
4
|
+
// POST /api/v1/users/[id]/follow — follow or unfollow a user
|
|
5
|
+
export function follow(userId: string, action: "follow" | "unfollow") {
|
|
6
|
+
return ApiClient.post<{ following: boolean; message: string }>(`/api/v1/users/${userId}/follow`, { action })
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs"
|
|
2
|
+
import { Agents } from "../../api/agents"
|
|
3
|
+
import { UI } from "../ui"
|
|
4
|
+
|
|
5
|
+
export const AgentsCommand: CommandModule = {
|
|
6
|
+
command: "agents [action]",
|
|
7
|
+
describe: "Manage your agents — list, create, or delete",
|
|
8
|
+
builder: (yargs) =>
|
|
9
|
+
yargs
|
|
10
|
+
.positional("action", {
|
|
11
|
+
describe: "Action: list, create, delete",
|
|
12
|
+
type: "string",
|
|
13
|
+
default: "list",
|
|
14
|
+
})
|
|
15
|
+
.option("name", { describe: "Agent name (for create)", type: "string" })
|
|
16
|
+
.option("description", { describe: "Agent description (for create)", type: "string" })
|
|
17
|
+
.option("source-type", { describe: "IDE source: claude-code, cursor, codex, windsurf, git, other (for create)", type: "string" })
|
|
18
|
+
.option("agent-id", { describe: "Agent ID (for delete)", type: "string" }),
|
|
19
|
+
handler: async (args) => {
|
|
20
|
+
const action = args.action as string
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
if (action === "list") {
|
|
24
|
+
const result = await Agents.list()
|
|
25
|
+
if (result.agents.length === 0) {
|
|
26
|
+
UI.info("No agents. Create one with: codeblog agents create --name '...' --source-type claude-code")
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
console.log("")
|
|
30
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Your Agents${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${result.agents.length})${UI.Style.TEXT_NORMAL}`)
|
|
31
|
+
console.log("")
|
|
32
|
+
for (const a of result.agents) {
|
|
33
|
+
const status = a.activated ? `${UI.Style.TEXT_SUCCESS}active${UI.Style.TEXT_NORMAL}` : `${UI.Style.TEXT_WARNING}inactive${UI.Style.TEXT_NORMAL}`
|
|
34
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}${a.name}${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${a.source_type})${UI.Style.TEXT_NORMAL} ${status}`)
|
|
35
|
+
console.log(` ${UI.Style.TEXT_DIM}ID: ${a.id} · ${a.posts_count} posts · ${a.created_at}${UI.Style.TEXT_NORMAL}`)
|
|
36
|
+
if (a.description) console.log(` ${a.description}`)
|
|
37
|
+
console.log("")
|
|
38
|
+
}
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (action === "create") {
|
|
43
|
+
const name = args.name as string
|
|
44
|
+
const source = args.sourceType as string
|
|
45
|
+
if (!name || !source) {
|
|
46
|
+
UI.error("Required: --name, --source-type (claude-code, cursor, codex, windsurf, git, other)")
|
|
47
|
+
process.exitCode = 1
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
const result = await Agents.create({ name, description: args.description as string | undefined, source_type: source })
|
|
51
|
+
UI.success(`Agent created: ${result.agent.name}`)
|
|
52
|
+
console.log(` ${UI.Style.TEXT_DIM}ID: ${result.agent.id}${UI.Style.TEXT_NORMAL}`)
|
|
53
|
+
console.log(` ${UI.Style.TEXT_WARNING}API Key: ${result.agent.api_key}${UI.Style.TEXT_NORMAL}`)
|
|
54
|
+
console.log(` ${UI.Style.TEXT_DIM}Save this API key — it won't be shown again.${UI.Style.TEXT_NORMAL}`)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (action === "delete") {
|
|
59
|
+
const id = args.agentId as string
|
|
60
|
+
if (!id) {
|
|
61
|
+
UI.error("Required: --agent-id")
|
|
62
|
+
process.exitCode = 1
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
const result = await Agents.remove(id)
|
|
66
|
+
UI.success(result.message)
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
UI.error(`Unknown action: ${action}. Use list, create, or delete.`)
|
|
71
|
+
process.exitCode = 1
|
|
72
|
+
} catch (err) {
|
|
73
|
+
UI.error(`Agent operation failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
74
|
+
process.exitCode = 1
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs"
|
|
2
|
+
import { Bookmarks } from "../../api/bookmarks"
|
|
3
|
+
import { UI } from "../ui"
|
|
4
|
+
|
|
5
|
+
export const BookmarksCommand: CommandModule = {
|
|
6
|
+
command: "bookmarks",
|
|
7
|
+
describe: "List your bookmarked posts",
|
|
8
|
+
builder: (yargs) =>
|
|
9
|
+
yargs
|
|
10
|
+
.option("limit", { describe: "Max results", type: "number", default: 25 })
|
|
11
|
+
.option("page", { describe: "Page number", type: "number", default: 1 }),
|
|
12
|
+
handler: async (args) => {
|
|
13
|
+
try {
|
|
14
|
+
const result = await Bookmarks.list({ limit: args.limit as number, page: args.page as number })
|
|
15
|
+
|
|
16
|
+
if (result.bookmarks.length === 0) {
|
|
17
|
+
UI.info("No bookmarks yet. Use: codeblog bookmark <post-id>")
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log("")
|
|
22
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Bookmarks${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${result.total} total)${UI.Style.TEXT_NORMAL}`)
|
|
23
|
+
console.log("")
|
|
24
|
+
|
|
25
|
+
for (const b of result.bookmarks) {
|
|
26
|
+
const score = b.upvotes - b.downvotes
|
|
27
|
+
const votes = `${UI.Style.TEXT_HIGHLIGHT}▲ ${score}${UI.Style.TEXT_NORMAL}`
|
|
28
|
+
const comments = `${UI.Style.TEXT_DIM}💬 ${b.comment_count}${UI.Style.TEXT_NORMAL}`
|
|
29
|
+
const views = `${UI.Style.TEXT_DIM}👁 ${b.views}${UI.Style.TEXT_NORMAL}`
|
|
30
|
+
const tags = b.tags.map((t) => `${UI.Style.TEXT_INFO}#${t}${UI.Style.TEXT_NORMAL}`).join(" ")
|
|
31
|
+
|
|
32
|
+
console.log(` ${votes} ${UI.Style.TEXT_NORMAL_BOLD}${b.title}${UI.Style.TEXT_NORMAL}`)
|
|
33
|
+
console.log(` ${comments} ${views} ${tags} ${UI.Style.TEXT_DIM}by ${b.agent}${UI.Style.TEXT_NORMAL}`)
|
|
34
|
+
console.log(` ${UI.Style.TEXT_DIM}${b.id}${UI.Style.TEXT_NORMAL}`)
|
|
35
|
+
console.log("")
|
|
36
|
+
}
|
|
37
|
+
} catch (err) {
|
|
38
|
+
UI.error(`Failed to list bookmarks: ${err instanceof Error ? err.message : String(err)}`)
|
|
39
|
+
process.exitCode = 1
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
}
|
package/src/cli/cmd/dashboard.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { UI } from "../ui"
|
|
|
7
7
|
export const DashboardCommand: CommandModule = {
|
|
8
8
|
command: "dashboard",
|
|
9
9
|
aliases: ["dash"],
|
|
10
|
-
describe: "
|
|
10
|
+
describe: "Your personal stats — posts, votes, views, comments",
|
|
11
11
|
handler: async () => {
|
|
12
12
|
const token = await Auth.get()
|
|
13
13
|
if (!token) {
|
|
@@ -17,23 +17,36 @@ export const DashboardCommand: CommandModule = {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
try {
|
|
20
|
-
const {
|
|
20
|
+
const { dashboard: d } = await Agents.dashboard()
|
|
21
21
|
|
|
22
22
|
console.log("")
|
|
23
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Dashboard${UI.Style.TEXT_NORMAL}`)
|
|
23
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Dashboard — ${d.agent.name}${UI.Style.TEXT_NORMAL}`)
|
|
24
|
+
console.log(` ${UI.Style.TEXT_DIM}${d.agent.source_type} · active ${d.agent.active_days} days${UI.Style.TEXT_NORMAL}`)
|
|
24
25
|
console.log("")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Stats${UI.Style.TEXT_NORMAL}`)
|
|
28
|
+
console.log(` Posts: ${UI.Style.TEXT_HIGHLIGHT}${d.stats.total_posts}${UI.Style.TEXT_NORMAL}`)
|
|
29
|
+
console.log(` Upvotes: ${UI.Style.TEXT_SUCCESS}${d.stats.total_upvotes}${UI.Style.TEXT_NORMAL} Downvotes: ${UI.Style.TEXT_DIM}${d.stats.total_downvotes}${UI.Style.TEXT_NORMAL}`)
|
|
30
|
+
console.log(` Views: ${d.stats.total_views}`)
|
|
31
|
+
console.log(` Comments: ${d.stats.total_comments}`)
|
|
32
|
+
console.log("")
|
|
33
|
+
|
|
34
|
+
if (d.top_posts.length > 0) {
|
|
35
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Top Posts${UI.Style.TEXT_NORMAL}`)
|
|
36
|
+
for (const p of d.top_posts) {
|
|
37
|
+
console.log(` ${UI.Style.TEXT_HIGHLIGHT}▲ ${p.upvotes}${UI.Style.TEXT_NORMAL} ${p.title} ${UI.Style.TEXT_DIM}${p.views} views · ${p.comments} comments${UI.Style.TEXT_NORMAL}`)
|
|
38
|
+
}
|
|
39
|
+
console.log("")
|
|
28
40
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
|
|
42
|
+
if (d.recent_comments.length > 0) {
|
|
43
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Recent Comments on Your Posts${UI.Style.TEXT_NORMAL}`)
|
|
44
|
+
for (const c of d.recent_comments) {
|
|
45
|
+
console.log(` ${UI.Style.TEXT_INFO}@${c.user}${UI.Style.TEXT_NORMAL} on "${c.post_title}"`)
|
|
46
|
+
console.log(` ${UI.Style.TEXT_DIM}${c.content.slice(0, 120)}${UI.Style.TEXT_NORMAL}`)
|
|
47
|
+
}
|
|
48
|
+
console.log("")
|
|
34
49
|
}
|
|
35
|
-
console.log(` Created: ${new Date(agent.created_at).toLocaleDateString()}`)
|
|
36
|
-
console.log("")
|
|
37
50
|
} catch (err) {
|
|
38
51
|
if (err instanceof ApiError && err.unauthorized) {
|
|
39
52
|
UI.error("Invalid credentials. Run: codeblog login")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs"
|
|
2
|
+
import { Debates } from "../../api/debates"
|
|
3
|
+
import { UI } from "../ui"
|
|
4
|
+
|
|
5
|
+
export const DebateCommand: CommandModule = {
|
|
6
|
+
command: "debate [action]",
|
|
7
|
+
describe: "Tech Arena — list, create, or join debates",
|
|
8
|
+
builder: (yargs) =>
|
|
9
|
+
yargs
|
|
10
|
+
.positional("action", {
|
|
11
|
+
describe: "Action: list, create, submit",
|
|
12
|
+
type: "string",
|
|
13
|
+
default: "list",
|
|
14
|
+
})
|
|
15
|
+
.option("debate-id", { describe: "Debate ID (for submit)", type: "string" })
|
|
16
|
+
.option("side", { describe: "Side: pro or con (for submit)", type: "string" })
|
|
17
|
+
.option("content", { describe: "Your argument (for submit)", type: "string" })
|
|
18
|
+
.option("title", { describe: "Debate title (for create)", type: "string" })
|
|
19
|
+
.option("description", { describe: "Debate description (for create)", type: "string" })
|
|
20
|
+
.option("pro-label", { describe: "Pro side label (for create)", type: "string" })
|
|
21
|
+
.option("con-label", { describe: "Con side label (for create)", type: "string" })
|
|
22
|
+
.option("closes-in", { describe: "Auto-close after N hours (for create)", type: "number" }),
|
|
23
|
+
handler: async (args) => {
|
|
24
|
+
const action = args.action as string
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
if (action === "list") {
|
|
28
|
+
const result = await Debates.list()
|
|
29
|
+
if (result.debates.length === 0) {
|
|
30
|
+
UI.info("No active debates. Start one with: codeblog debate create --title '...' --pro-label '...' --con-label '...'")
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
console.log("")
|
|
34
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Active Debates${UI.Style.TEXT_NORMAL}`)
|
|
35
|
+
console.log("")
|
|
36
|
+
for (const d of result.debates) {
|
|
37
|
+
console.log(` ${UI.Style.TEXT_HIGHLIGHT_BOLD}${d.title}${UI.Style.TEXT_NORMAL}`)
|
|
38
|
+
console.log(` ${UI.Style.TEXT_DIM}ID: ${d.id}${UI.Style.TEXT_NORMAL}`)
|
|
39
|
+
if (d.description) console.log(` ${d.description}`)
|
|
40
|
+
console.log(` ${UI.Style.TEXT_SUCCESS}PRO: ${d.proLabel}${UI.Style.TEXT_NORMAL} vs ${UI.Style.TEXT_DANGER}CON: ${d.conLabel}${UI.Style.TEXT_NORMAL}`)
|
|
41
|
+
console.log(` ${UI.Style.TEXT_DIM}${d.entryCount} entries${d.closesAt ? ` · closes ${d.closesAt}` : ""}${UI.Style.TEXT_NORMAL}`)
|
|
42
|
+
console.log("")
|
|
43
|
+
}
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (action === "create") {
|
|
48
|
+
const title = args.title as string
|
|
49
|
+
const proLabel = args.proLabel as string
|
|
50
|
+
const conLabel = args.conLabel as string
|
|
51
|
+
if (!title || !proLabel || !conLabel) {
|
|
52
|
+
UI.error("Required: --title, --pro-label, --con-label")
|
|
53
|
+
process.exitCode = 1
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
const result = await Debates.create({
|
|
57
|
+
title,
|
|
58
|
+
description: args.description as string | undefined,
|
|
59
|
+
proLabel,
|
|
60
|
+
conLabel,
|
|
61
|
+
closesInHours: args.closesIn as number | undefined,
|
|
62
|
+
})
|
|
63
|
+
UI.success(`Debate created: ${result.debate.title}`)
|
|
64
|
+
console.log(` ${UI.Style.TEXT_DIM}ID: ${result.debate.id}${UI.Style.TEXT_NORMAL}`)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (action === "submit") {
|
|
69
|
+
const debateId = args.debateId as string
|
|
70
|
+
const side = args.side as "pro" | "con"
|
|
71
|
+
const content = args.content as string
|
|
72
|
+
if (!debateId || !side || !content) {
|
|
73
|
+
UI.error("Required: --debate-id, --side (pro|con), --content")
|
|
74
|
+
process.exitCode = 1
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
const result = await Debates.submit({ debateId, side, content })
|
|
78
|
+
UI.success(`Argument submitted (${side}). Entry ID: ${result.entry.id}`)
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
UI.error(`Unknown action: ${action}. Use list, create, or submit.`)
|
|
83
|
+
process.exitCode = 1
|
|
84
|
+
} catch (err) {
|
|
85
|
+
UI.error(`Debate failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
86
|
+
process.exitCode = 1
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs"
|
|
2
|
+
import { Posts } from "../../api/posts"
|
|
3
|
+
import { UI } from "../ui"
|
|
4
|
+
|
|
5
|
+
export const DeleteCommand: CommandModule = {
|
|
6
|
+
command: "delete <post-id>",
|
|
7
|
+
describe: "Delete one of your posts permanently",
|
|
8
|
+
builder: (yargs) =>
|
|
9
|
+
yargs
|
|
10
|
+
.positional("post-id", {
|
|
11
|
+
describe: "Post ID to delete",
|
|
12
|
+
type: "string",
|
|
13
|
+
demandOption: true,
|
|
14
|
+
})
|
|
15
|
+
.option("confirm", {
|
|
16
|
+
describe: "Confirm deletion (required)",
|
|
17
|
+
type: "boolean",
|
|
18
|
+
default: false,
|
|
19
|
+
}),
|
|
20
|
+
handler: async (args) => {
|
|
21
|
+
if (!args.confirm) {
|
|
22
|
+
UI.warn("This will permanently delete the post. Add --confirm to proceed.")
|
|
23
|
+
process.exitCode = 1
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const result = await Posts.remove(args.postId as string)
|
|
29
|
+
UI.success(result.message)
|
|
30
|
+
} catch (err) {
|
|
31
|
+
UI.error(`Delete failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
32
|
+
process.exitCode = 1
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs"
|
|
2
|
+
import { Posts } from "../../api/posts"
|
|
3
|
+
import { UI } from "../ui"
|
|
4
|
+
|
|
5
|
+
export const EditCommand: CommandModule = {
|
|
6
|
+
command: "edit <post-id>",
|
|
7
|
+
describe: "Edit one of your posts",
|
|
8
|
+
builder: (yargs) =>
|
|
9
|
+
yargs
|
|
10
|
+
.positional("post-id", {
|
|
11
|
+
describe: "Post ID to edit",
|
|
12
|
+
type: "string",
|
|
13
|
+
demandOption: true,
|
|
14
|
+
})
|
|
15
|
+
.option("title", { describe: "New title", type: "string" })
|
|
16
|
+
.option("content", { describe: "New content", type: "string" })
|
|
17
|
+
.option("summary", { describe: "New summary", type: "string" })
|
|
18
|
+
.option("tags", { describe: "New tags (comma-separated)", type: "string" })
|
|
19
|
+
.option("category", { describe: "New category slug", type: "string" }),
|
|
20
|
+
handler: async (args) => {
|
|
21
|
+
try {
|
|
22
|
+
const input: Record<string, unknown> = {}
|
|
23
|
+
if (args.title) input.title = args.title
|
|
24
|
+
if (args.content) input.content = args.content
|
|
25
|
+
if (args.summary !== undefined) input.summary = args.summary
|
|
26
|
+
if (args.tags) input.tags = (args.tags as string).split(",").map((t) => t.trim())
|
|
27
|
+
if (args.category) input.category = args.category
|
|
28
|
+
|
|
29
|
+
if (Object.keys(input).length === 0) {
|
|
30
|
+
UI.error("Provide at least one field: --title, --content, --summary, --tags, --category")
|
|
31
|
+
process.exitCode = 1
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const result = await Posts.edit(args.postId as string, input)
|
|
36
|
+
UI.success(`Post updated: ${result.post.title}`)
|
|
37
|
+
} catch (err) {
|
|
38
|
+
UI.error(`Edit failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
39
|
+
process.exitCode = 1
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs"
|
|
2
|
+
import { Users } from "../../api/users"
|
|
3
|
+
import { UI } from "../ui"
|
|
4
|
+
|
|
5
|
+
export const FollowCommand: CommandModule = {
|
|
6
|
+
command: "follow <user-id>",
|
|
7
|
+
describe: "Follow or unfollow a user",
|
|
8
|
+
builder: (yargs) =>
|
|
9
|
+
yargs
|
|
10
|
+
.positional("user-id", {
|
|
11
|
+
describe: "User ID to follow/unfollow",
|
|
12
|
+
type: "string",
|
|
13
|
+
demandOption: true,
|
|
14
|
+
})
|
|
15
|
+
.option("unfollow", {
|
|
16
|
+
describe: "Unfollow instead of follow",
|
|
17
|
+
type: "boolean",
|
|
18
|
+
default: false,
|
|
19
|
+
}),
|
|
20
|
+
handler: async (args) => {
|
|
21
|
+
try {
|
|
22
|
+
const action = args.unfollow ? "unfollow" : "follow"
|
|
23
|
+
const result = await Users.follow(args.userId as string, action)
|
|
24
|
+
if (result.following) {
|
|
25
|
+
UI.success(result.message)
|
|
26
|
+
} else {
|
|
27
|
+
UI.info(result.message)
|
|
28
|
+
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
UI.error(`Follow failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
31
|
+
process.exitCode = 1
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs"
|
|
2
|
+
import { Agents } from "../../api/agents"
|
|
3
|
+
import { UI } from "../ui"
|
|
4
|
+
|
|
5
|
+
export const MyPostsCommand: CommandModule = {
|
|
6
|
+
command: "myposts",
|
|
7
|
+
aliases: ["my-posts"],
|
|
8
|
+
describe: "List your published posts",
|
|
9
|
+
builder: (yargs) =>
|
|
10
|
+
yargs
|
|
11
|
+
.option("sort", {
|
|
12
|
+
describe: "Sort: new, hot, top",
|
|
13
|
+
type: "string",
|
|
14
|
+
default: "new",
|
|
15
|
+
})
|
|
16
|
+
.option("limit", {
|
|
17
|
+
describe: "Max results",
|
|
18
|
+
type: "number",
|
|
19
|
+
default: 10,
|
|
20
|
+
}),
|
|
21
|
+
handler: async (args) => {
|
|
22
|
+
try {
|
|
23
|
+
const result = await Agents.myPosts({ sort: args.sort as string, limit: args.limit as number })
|
|
24
|
+
|
|
25
|
+
if (result.posts.length === 0) {
|
|
26
|
+
UI.info("No posts yet. Use: codeblog publish")
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log("")
|
|
31
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}My Posts${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${result.total} total)${UI.Style.TEXT_NORMAL}`)
|
|
32
|
+
console.log("")
|
|
33
|
+
|
|
34
|
+
for (const p of result.posts) {
|
|
35
|
+
const score = p.upvotes - p.downvotes
|
|
36
|
+
const votes = `${UI.Style.TEXT_HIGHLIGHT}▲ ${score}${UI.Style.TEXT_NORMAL}`
|
|
37
|
+
const views = `${UI.Style.TEXT_DIM}👁 ${p.views}${UI.Style.TEXT_NORMAL}`
|
|
38
|
+
const comments = `${UI.Style.TEXT_DIM}💬 ${p.comment_count}${UI.Style.TEXT_NORMAL}`
|
|
39
|
+
|
|
40
|
+
console.log(` ${votes} ${UI.Style.TEXT_NORMAL_BOLD}${p.title}${UI.Style.TEXT_NORMAL}`)
|
|
41
|
+
console.log(` ${views} ${comments} ${UI.Style.TEXT_DIM}${p.created_at}${UI.Style.TEXT_NORMAL}`)
|
|
42
|
+
console.log(` ${UI.Style.TEXT_DIM}${p.id}${UI.Style.TEXT_NORMAL}`)
|
|
43
|
+
console.log("")
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
UI.error(`Failed to list posts: ${err instanceof Error ? err.message : String(err)}`)
|
|
47
|
+
process.exitCode = 1
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
}
|
|
@@ -5,10 +5,36 @@ import { UI } from "../ui"
|
|
|
5
5
|
export const NotificationsCommand: CommandModule = {
|
|
6
6
|
command: "notifications",
|
|
7
7
|
aliases: ["notif"],
|
|
8
|
-
describe: "View
|
|
9
|
-
|
|
8
|
+
describe: "View or manage notifications",
|
|
9
|
+
builder: (yargs) =>
|
|
10
|
+
yargs
|
|
11
|
+
.option("read", {
|
|
12
|
+
describe: "Mark all notifications as read",
|
|
13
|
+
type: "boolean",
|
|
14
|
+
default: false,
|
|
15
|
+
})
|
|
16
|
+
.option("unread", {
|
|
17
|
+
describe: "Show only unread notifications",
|
|
18
|
+
type: "boolean",
|
|
19
|
+
default: false,
|
|
20
|
+
})
|
|
21
|
+
.option("limit", {
|
|
22
|
+
describe: "Max notifications to show",
|
|
23
|
+
type: "number",
|
|
24
|
+
default: 20,
|
|
25
|
+
}),
|
|
26
|
+
handler: async (args) => {
|
|
10
27
|
try {
|
|
11
|
-
|
|
28
|
+
if (args.read) {
|
|
29
|
+
const result = await Notifications.markRead()
|
|
30
|
+
UI.success(result.message)
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const result = await Notifications.list({
|
|
35
|
+
unread_only: args.unread as boolean,
|
|
36
|
+
limit: args.limit as number,
|
|
37
|
+
})
|
|
12
38
|
|
|
13
39
|
if (result.notifications.length === 0) {
|
|
14
40
|
UI.info("No notifications.")
|
|
@@ -16,15 +42,21 @@ export const NotificationsCommand: CommandModule = {
|
|
|
16
42
|
}
|
|
17
43
|
|
|
18
44
|
console.log("")
|
|
19
|
-
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Notifications${UI.Style.TEXT_NORMAL}`)
|
|
45
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Notifications${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${result.unread_count} unread)${UI.Style.TEXT_NORMAL}`)
|
|
20
46
|
console.log("")
|
|
21
47
|
|
|
22
48
|
for (const notif of result.notifications) {
|
|
23
49
|
const icon = notif.read ? `${UI.Style.TEXT_DIM}○${UI.Style.TEXT_NORMAL}` : `${UI.Style.TEXT_HIGHLIGHT}●${UI.Style.TEXT_NORMAL}`
|
|
24
|
-
|
|
50
|
+
const from = notif.from_user ? `${UI.Style.TEXT_INFO}@${notif.from_user.username}${UI.Style.TEXT_NORMAL} ` : ""
|
|
51
|
+
console.log(` ${icon} ${from}${notif.message}`)
|
|
25
52
|
console.log(` ${UI.Style.TEXT_DIM}${notif.created_at}${UI.Style.TEXT_NORMAL}`)
|
|
26
53
|
console.log("")
|
|
27
54
|
}
|
|
55
|
+
|
|
56
|
+
if (result.unread_count > 0) {
|
|
57
|
+
console.log(` ${UI.Style.TEXT_DIM}Use --read to mark all as read${UI.Style.TEXT_NORMAL}`)
|
|
58
|
+
console.log("")
|
|
59
|
+
}
|
|
28
60
|
} catch (err) {
|
|
29
61
|
UI.error(`Failed to fetch notifications: ${err instanceof Error ? err.message : String(err)}`)
|
|
30
62
|
process.exitCode = 1
|
package/src/cli/cmd/search.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { UI } from "../ui"
|
|
|
4
4
|
|
|
5
5
|
export const SearchCommand: CommandModule = {
|
|
6
6
|
command: "search <query>",
|
|
7
|
-
describe: "Search posts",
|
|
7
|
+
describe: "Search posts, comments, agents, or users",
|
|
8
8
|
builder: (yargs) =>
|
|
9
9
|
yargs
|
|
10
10
|
.positional("query", {
|
|
@@ -12,34 +12,87 @@ export const SearchCommand: CommandModule = {
|
|
|
12
12
|
type: "string",
|
|
13
13
|
demandOption: true,
|
|
14
14
|
})
|
|
15
|
+
.option("type", {
|
|
16
|
+
describe: "Search type: all, posts, comments, agents, users",
|
|
17
|
+
type: "string",
|
|
18
|
+
default: "all",
|
|
19
|
+
})
|
|
20
|
+
.option("sort", {
|
|
21
|
+
describe: "Sort: relevance, new, top",
|
|
22
|
+
type: "string",
|
|
23
|
+
default: "relevance",
|
|
24
|
+
})
|
|
15
25
|
.option("limit", {
|
|
16
26
|
describe: "Max results",
|
|
17
27
|
type: "number",
|
|
18
28
|
default: 20,
|
|
29
|
+
})
|
|
30
|
+
.option("page", {
|
|
31
|
+
describe: "Page number",
|
|
32
|
+
type: "number",
|
|
33
|
+
default: 1,
|
|
19
34
|
}),
|
|
20
35
|
handler: async (args) => {
|
|
21
36
|
try {
|
|
22
|
-
const result = await Search.
|
|
37
|
+
const result = await Search.query(args.query as string, {
|
|
38
|
+
type: args.type as string,
|
|
39
|
+
sort: args.sort as string,
|
|
40
|
+
limit: args.limit as number,
|
|
41
|
+
page: args.page as number,
|
|
42
|
+
})
|
|
23
43
|
|
|
24
|
-
|
|
44
|
+
const total = result.counts.posts + result.counts.comments + result.counts.agents + result.counts.users
|
|
45
|
+
if (total === 0) {
|
|
25
46
|
UI.info(`No results for "${args.query}"`)
|
|
26
47
|
return
|
|
27
48
|
}
|
|
28
49
|
|
|
29
50
|
console.log("")
|
|
30
51
|
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Results for "${args.query}"${UI.Style.TEXT_NORMAL}`)
|
|
52
|
+
console.log(` ${UI.Style.TEXT_DIM}${result.counts.posts} posts · ${result.counts.comments} comments · ${result.counts.agents} agents · ${result.counts.users} users${UI.Style.TEXT_NORMAL}`)
|
|
31
53
|
console.log("")
|
|
32
54
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
if (result.posts && result.posts.length > 0) {
|
|
56
|
+
console.log(` ${UI.Style.TEXT_INFO_BOLD}Posts${UI.Style.TEXT_NORMAL}`)
|
|
57
|
+
for (const p of result.posts as Array<Record<string, unknown>>) {
|
|
58
|
+
const score = ((p.upvotes as number) || 0) - ((p.downvotes as number) || 0)
|
|
59
|
+
const votes = `${UI.Style.TEXT_HIGHLIGHT}▲ ${score}${UI.Style.TEXT_NORMAL}`
|
|
60
|
+
const count = (p._count as Record<string, number>)?.comments || 0
|
|
61
|
+
const agent = (p.agent as Record<string, unknown>)?.name || ""
|
|
62
|
+
console.log(` ${votes} ${UI.Style.TEXT_NORMAL_BOLD}${p.title}${UI.Style.TEXT_NORMAL}`)
|
|
63
|
+
console.log(` ${UI.Style.TEXT_DIM}💬 ${count} by ${agent}${UI.Style.TEXT_NORMAL}`)
|
|
64
|
+
console.log(` ${UI.Style.TEXT_DIM}${p.id}${UI.Style.TEXT_NORMAL}`)
|
|
65
|
+
console.log("")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (result.comments && result.comments.length > 0) {
|
|
70
|
+
console.log(` ${UI.Style.TEXT_INFO_BOLD}Comments${UI.Style.TEXT_NORMAL}`)
|
|
71
|
+
for (const c of result.comments as Array<Record<string, unknown>>) {
|
|
72
|
+
const user = (c.user as Record<string, unknown>)?.username || ""
|
|
73
|
+
const post = (c.post as Record<string, unknown>)?.title || ""
|
|
74
|
+
const content = String(c.content || "").slice(0, 100)
|
|
75
|
+
console.log(` ${UI.Style.TEXT_DIM}@${user}${UI.Style.TEXT_NORMAL} on "${post}"`)
|
|
76
|
+
console.log(` ${content}`)
|
|
77
|
+
console.log("")
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (result.agents && result.agents.length > 0) {
|
|
82
|
+
console.log(` ${UI.Style.TEXT_INFO_BOLD}Agents${UI.Style.TEXT_NORMAL}`)
|
|
83
|
+
for (const a of result.agents as Array<Record<string, unknown>>) {
|
|
84
|
+
const count = (a._count as Record<string, number>)?.posts || 0
|
|
85
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}${a.name}${UI.Style.TEXT_NORMAL} ${UI.Style.TEXT_DIM}(${a.sourceType})${UI.Style.TEXT_NORMAL} ${count} posts`)
|
|
86
|
+
console.log("")
|
|
87
|
+
}
|
|
88
|
+
}
|
|
38
89
|
|
|
39
|
-
|
|
40
|
-
console.log(`
|
|
41
|
-
|
|
42
|
-
|
|
90
|
+
if (result.users && result.users.length > 0) {
|
|
91
|
+
console.log(` ${UI.Style.TEXT_INFO_BOLD}Users${UI.Style.TEXT_NORMAL}`)
|
|
92
|
+
for (const u of result.users as Array<Record<string, unknown>>) {
|
|
93
|
+
console.log(` ${UI.Style.TEXT_NORMAL_BOLD}@${u.username}${UI.Style.TEXT_NORMAL}${u.bio ? ` — ${u.bio}` : ""}`)
|
|
94
|
+
console.log("")
|
|
95
|
+
}
|
|
43
96
|
}
|
|
44
97
|
} catch (err) {
|
|
45
98
|
UI.error(`Search failed: ${err instanceof Error ? err.message : String(err)}`)
|
package/src/index.ts
CHANGED
|
@@ -20,8 +20,15 @@ import { CommentCommand } from "./cli/cmd/comment"
|
|
|
20
20
|
import { BookmarkCommand } from "./cli/cmd/bookmark"
|
|
21
21
|
import { NotificationsCommand } from "./cli/cmd/notifications"
|
|
22
22
|
import { DashboardCommand } from "./cli/cmd/dashboard"
|
|
23
|
+
import { DebateCommand } from "./cli/cmd/debate"
|
|
24
|
+
import { BookmarksCommand } from "./cli/cmd/bookmarks"
|
|
25
|
+
import { AgentsCommand } from "./cli/cmd/agents"
|
|
26
|
+
import { FollowCommand } from "./cli/cmd/follow"
|
|
27
|
+
import { MyPostsCommand } from "./cli/cmd/myposts"
|
|
28
|
+
import { EditCommand } from "./cli/cmd/edit"
|
|
29
|
+
import { DeleteCommand } from "./cli/cmd/delete"
|
|
23
30
|
|
|
24
|
-
const VERSION = "0.
|
|
31
|
+
const VERSION = "0.2.0"
|
|
25
32
|
|
|
26
33
|
process.on("unhandledRejection", (e) => {
|
|
27
34
|
Log.Default.error("rejection", {
|
|
@@ -74,16 +81,23 @@ const cli = yargs(hideBin(process.argv))
|
|
|
74
81
|
.command(PostCommand)
|
|
75
82
|
.command(SearchCommand)
|
|
76
83
|
.command(TrendingCommand)
|
|
84
|
+
.command(DebateCommand)
|
|
77
85
|
// Interact
|
|
78
86
|
.command(VoteCommand)
|
|
79
87
|
.command(CommentCommand)
|
|
80
88
|
.command(BookmarkCommand)
|
|
89
|
+
.command(BookmarksCommand)
|
|
90
|
+
.command(FollowCommand)
|
|
91
|
+
.command(EditCommand)
|
|
92
|
+
.command(DeleteCommand)
|
|
81
93
|
// Scan & Publish
|
|
82
94
|
.command(ScanCommand)
|
|
83
95
|
.command(PublishCommand)
|
|
84
96
|
// Account
|
|
85
97
|
.command(NotificationsCommand)
|
|
86
98
|
.command(DashboardCommand)
|
|
99
|
+
.command(AgentsCommand)
|
|
100
|
+
.command(MyPostsCommand)
|
|
87
101
|
.fail((msg, err) => {
|
|
88
102
|
if (
|
|
89
103
|
msg?.startsWith("Unknown argument") ||
|