codeblog-app 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "codeblog-app",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "description": "CLI client for CodeBlog — the forum where AI writes the posts",
6
6
  "type": "module",
7
7
  "license": "MIT",
@@ -289,6 +289,17 @@ export namespace AIProvider {
289
289
  return cfg.model
290
290
  }
291
291
 
292
+ // ---------------------------------------------------------------------------
293
+ // Check if any AI provider has a key configured
294
+ // ---------------------------------------------------------------------------
295
+ export async function hasAnyKey(): Promise<boolean> {
296
+ for (const providerID of Object.keys(PROVIDER_ENV)) {
297
+ const key = await getApiKey(providerID)
298
+ if (key) return true
299
+ }
300
+ return false
301
+ }
302
+
292
303
  // ---------------------------------------------------------------------------
293
304
  // List available models with key status (for codeblog config --list)
294
305
  // ---------------------------------------------------------------------------
@@ -1,5 +1,6 @@
1
1
  import type { CommandModule } from "yargs"
2
2
  import { AIChat } from "../../ai/chat"
3
+ import { AIProvider } from "../../ai/provider"
3
4
  import { Posts } from "../../api/posts"
4
5
  import { Config } from "../../config"
5
6
  import { scanAll, parseSession, registerAllScanners } from "../../scanner"
@@ -32,6 +33,21 @@ export const AIPublishCommand: CommandModule = {
32
33
  }),
33
34
  handler: async (args) => {
34
35
  try {
36
+ // Check AI key before scanning
37
+ const hasKey = await AIProvider.hasAnyKey()
38
+ if (!hasKey) {
39
+ console.log("")
40
+ UI.warn("No AI provider configured. ai-publish requires an AI API key to generate posts.")
41
+ console.log("")
42
+ console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Configure an AI provider first:${UI.Style.TEXT_NORMAL}`)
43
+ console.log(` ${UI.Style.TEXT_HIGHLIGHT}codeblog config --provider anthropic --api-key sk-ant-...${UI.Style.TEXT_NORMAL}`)
44
+ console.log("")
45
+ console.log(` ${UI.Style.TEXT_DIM}Run: codeblog config --list to see all supported providers${UI.Style.TEXT_NORMAL}`)
46
+ console.log("")
47
+ process.exitCode = 1
48
+ return
49
+ }
50
+
35
51
  UI.info("Scanning IDE sessions...")
36
52
  registerAllScanners()
37
53
  const sessions = scanAll(args.limit as number)
@@ -23,6 +23,25 @@ export const ChatCommand: CommandModule = {
23
23
  handler: async (args) => {
24
24
  const modelID = args.model as string | undefined
25
25
 
26
+ // Check AI key before doing anything
27
+ const hasKey = await AIProvider.hasAnyKey()
28
+ if (!hasKey) {
29
+ console.log("")
30
+ UI.warn("No AI provider configured. AI features require an API key.")
31
+ console.log("")
32
+ console.log(` ${UI.Style.TEXT_NORMAL_BOLD}Configure an AI provider:${UI.Style.TEXT_NORMAL}`)
33
+ console.log("")
34
+ console.log(` ${UI.Style.TEXT_HIGHLIGHT}codeblog config --provider anthropic --api-key sk-ant-...${UI.Style.TEXT_NORMAL}`)
35
+ console.log(` ${UI.Style.TEXT_HIGHLIGHT}codeblog config --provider openai --api-key sk-...${UI.Style.TEXT_NORMAL}`)
36
+ console.log(` ${UI.Style.TEXT_HIGHLIGHT}codeblog config --provider google --api-key AIza...${UI.Style.TEXT_NORMAL}`)
37
+ console.log("")
38
+ console.log(` ${UI.Style.TEXT_DIM}Or set an environment variable: ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.${UI.Style.TEXT_NORMAL}`)
39
+ console.log(` ${UI.Style.TEXT_DIM}Run: codeblog config --list to see all 15+ supported providers${UI.Style.TEXT_NORMAL}`)
40
+ console.log("")
41
+ process.exitCode = 1
42
+ return
43
+ }
44
+
26
45
  // Non-interactive: single prompt
27
46
  if (args.prompt) {
28
47
  try {
@@ -1,6 +1,7 @@
1
1
  import type { CommandModule } from "yargs"
2
2
  import { Auth } from "../../auth"
3
3
  import { OAuth } from "../../auth/oauth"
4
+ import { AIProvider } from "../../ai/provider"
4
5
  import { registerAllScanners, scanAll } from "../../scanner"
5
6
  import { Publisher } from "../../publisher"
6
7
  import { UI } from "../ui"
@@ -76,10 +77,26 @@ export const SetupCommand: CommandModule = {
76
77
  console.log("")
77
78
  UI.success("Setup complete! 🎉")
78
79
  console.log("")
80
+
81
+ // Check if AI is configured
82
+ const hasKey = await AIProvider.hasAnyKey()
83
+ if (!hasKey) {
84
+ console.log(` ${UI.Style.TEXT_WARNING}💡 Optional: Configure an AI provider to unlock AI features${UI.Style.TEXT_NORMAL}`)
85
+ console.log(` ${UI.Style.TEXT_DIM}(ai-publish, chat, and other AI-powered commands)${UI.Style.TEXT_NORMAL}`)
86
+ console.log("")
87
+ console.log(` ${UI.Style.TEXT_HIGHLIGHT}codeblog config --provider anthropic --api-key sk-ant-...${UI.Style.TEXT_NORMAL}`)
88
+ console.log(` ${UI.Style.TEXT_HIGHLIGHT}codeblog config --provider openai --api-key sk-...${UI.Style.TEXT_NORMAL}`)
89
+ console.log("")
90
+ console.log(` ${UI.Style.TEXT_DIM}Run: codeblog config --list to see all 15+ supported providers${UI.Style.TEXT_NORMAL}`)
91
+ console.log("")
92
+ }
93
+
79
94
  console.log(` ${UI.Style.TEXT_DIM}Useful commands:${UI.Style.TEXT_NORMAL}`)
80
95
  console.log(` codeblog feed ${UI.Style.TEXT_DIM}— Browse the forum${UI.Style.TEXT_NORMAL}`)
81
96
  console.log(` codeblog scan ${UI.Style.TEXT_DIM}— Scan IDE sessions${UI.Style.TEXT_NORMAL}`)
82
97
  console.log(` codeblog publish ${UI.Style.TEXT_DIM}— Publish sessions${UI.Style.TEXT_NORMAL}`)
98
+ console.log(` codeblog ai-publish ${UI.Style.TEXT_DIM}— AI writes a post from your session${UI.Style.TEXT_NORMAL}`)
99
+ console.log(` codeblog chat ${UI.Style.TEXT_DIM}— Interactive AI chat${UI.Style.TEXT_NORMAL}`)
83
100
  console.log(` codeblog dashboard ${UI.Style.TEXT_DIM}— Your stats${UI.Style.TEXT_NORMAL}`)
84
101
  console.log("")
85
102
  },
@@ -6,10 +6,14 @@ import os from "os"
6
6
  const app = "codeblog"
7
7
 
8
8
  const home = process.env.CODEBLOG_TEST_HOME || os.homedir()
9
- const data = path.join(xdgData || path.join(home, ".local", "share"), app)
10
- const cache = path.join(xdgCache || path.join(home, ".cache"), app)
11
- const config = path.join(xdgConfig || path.join(home, ".config"), app)
12
- const state = path.join(xdgState || path.join(home, ".local", "state"), app)
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)
13
17
 
14
18
  export namespace Global {
15
19
  export const Path = {
package/src/index.ts CHANGED
@@ -35,7 +35,7 @@ import { WeeklyDigestCommand } from "./cli/cmd/weekly-digest"
35
35
  import { TagsCommand } from "./cli/cmd/tags"
36
36
  import { ExploreCommand } from "./cli/cmd/explore"
37
37
 
38
- const VERSION = "0.4.3"
38
+ const VERSION = "1.1.0"
39
39
 
40
40
  process.on("unhandledRejection", (e) => {
41
41
  Log.Default.error("rejection", {