prodboard 0.2.1 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # prodboard
2
2
 
3
+ ## 0.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`62ef4b0`](https://github.com/G4brym/prodboard/commit/62ef4b0a1f6969e3d06f549635ebfd337b84403c) Thanks [@G4brym](https://github.com/G4brym)! - Show config warnings (tmux availability, webui dependencies) on every CLI command. Improved webui dependency messages with actionable install commands.
8
+
3
9
  ## 0.2.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -166,6 +166,7 @@ prodboard schedule stats --days 7 # Statistics
166
166
  prodboard daemon # Start (foreground)
167
167
  prodboard daemon --dry-run # Preview schedules
168
168
  prodboard daemon status # Check if running
169
+ prodboard daemon restart # Restart via systemd
169
170
  ```
170
171
 
171
172
  ### Other
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prodboard",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Self-hosted, CLI-first issue tracker and cron scheduler for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -2,7 +2,7 @@ import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import * as os from "os";
4
4
  import { ensureDb } from "../db.ts";
5
- import { loadConfig, loadConfigRaw, validateConfig, checkWebuiDependencies, PRODBOARD_DIR } from "../config.ts";
5
+ import { loadConfig, PRODBOARD_DIR } from "../config.ts";
6
6
  import { listSchedules } from "../queries/schedules.ts";
7
7
  import { getNextFire } from "../cron.ts";
8
8
  import { formatDate } from "../format.ts";
@@ -114,34 +114,6 @@ export async function daemonStatus(args: string[]): Promise<void> {
114
114
  }
115
115
 
116
116
  export async function daemonRestart(_args: string[]): Promise<void> {
117
- // Validate config
118
- let config;
119
- try {
120
- const { config: cfg, rawParsed } = loadConfigRaw();
121
- config = cfg;
122
- const { errors, warnings } = validateConfig(rawParsed);
123
- for (const e of errors) {
124
- console.error(`✗ Config: ${e}`);
125
- }
126
- if (errors.length > 0) {
127
- process.exit(1);
128
- }
129
- for (const w of warnings) {
130
- console.warn(`⚠ Config: ${w}`);
131
- }
132
- } catch (err: any) {
133
- console.error(`Config error: ${err.message}`);
134
- process.exit(1);
135
- }
136
-
137
- // Check webui dependencies
138
- if (config.webui.enabled) {
139
- const depWarnings = await checkWebuiDependencies();
140
- for (const w of depWarnings) {
141
- console.warn(`⚠ ${w}`);
142
- }
143
- }
144
-
145
117
  // Check systemd availability
146
118
  if (!(await systemctlAvailable())) {
147
119
  console.error("systemd is not available. daemon restart requires systemd.");
@@ -1,7 +1,7 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import * as os from "os";
4
- import { loadConfigRaw, validateConfig, checkWebuiDependencies } from "../config.ts";
4
+
5
5
 
6
6
  const SERVICE_NAME = "prodboard";
7
7
  const SERVICE_DIR = path.join(os.homedir(), ".config", "systemd", "user");
@@ -63,24 +63,6 @@ WantedBy=default.target
63
63
  export async function install(args: string[]): Promise<void> {
64
64
  const { flags } = parseArgs(args);
65
65
 
66
- // Validate config before proceeding
67
- try {
68
- const { config, rawParsed } = loadConfigRaw();
69
- const { warnings } = validateConfig(rawParsed);
70
- for (const w of warnings) {
71
- console.warn(`⚠ Config: ${w}`);
72
- }
73
- if (config.webui.enabled) {
74
- const depWarnings = await checkWebuiDependencies();
75
- for (const w of depWarnings) {
76
- console.warn(`⚠ ${w}`);
77
- }
78
- }
79
- } catch (err: any) {
80
- console.error(`Config error: ${err.message}`);
81
- process.exit(1);
82
- }
83
-
84
66
  if (!(await systemctlAvailable())) {
85
67
  console.error("systemd is not available on this system.");
86
68
  console.error("The install command requires systemd (Linux).");
package/src/config.ts CHANGED
@@ -240,15 +240,64 @@ export async function checkWebuiDependencies(): Promise<string[]> {
240
240
  try {
241
241
  await import("hono");
242
242
  } catch {
243
- warnings.push("webui is enabled but 'hono' is not installed. Run: bun install");
243
+ warnings.push(
244
+ "webui is enabled but 'hono' is not installed. " +
245
+ "Run: bun install hono (or bun install -g hono if prodboard is installed globally)"
246
+ );
247
+ return warnings; // skip JSX check if hono itself is missing
244
248
  }
245
249
  try {
246
250
  await import("hono/jsx/jsx-runtime");
247
251
  } catch {
248
252
  warnings.push(
249
253
  "webui is enabled but the Hono JSX runtime could not be loaded. " +
250
- "If prodboard is installed globally, you may need to install hono in the global package directory."
254
+ "Run: bun install hono (or bun install -g hono if prodboard is installed globally)"
251
255
  );
252
256
  }
253
257
  return warnings;
254
258
  }
259
+
260
+ export async function checkTmuxAvailable(): Promise<string | null> {
261
+ try {
262
+ const proc = Bun.spawn(["tmux", "-V"], { stdout: "ignore", stderr: "ignore" });
263
+ const code = await proc.exited;
264
+ if (code !== 0) {
265
+ return "daemon.useTmux is enabled but tmux is not installed. Install it (e.g. apt install tmux) or set useTmux to false.";
266
+ }
267
+ return null;
268
+ } catch {
269
+ return "daemon.useTmux is enabled but tmux is not installed. Install it (e.g. apt install tmux) or set useTmux to false.";
270
+ }
271
+ }
272
+
273
+ export async function printConfigWarnings(): Promise<void> {
274
+ let config: Config;
275
+ let rawParsed: any;
276
+ try {
277
+ const result = loadConfigRaw();
278
+ config = result.config;
279
+ rawParsed = result.rawParsed;
280
+ } catch (err: any) {
281
+ console.warn(`⚠ Config: ${err.message}`);
282
+ return;
283
+ }
284
+
285
+ const { warnings } = validateConfig(rawParsed);
286
+ for (const w of warnings) {
287
+ console.warn(`⚠ Config: ${w}`);
288
+ }
289
+
290
+ if (config.daemon.useTmux) {
291
+ const tmuxWarning = await checkTmuxAvailable();
292
+ if (tmuxWarning) {
293
+ console.warn(`⚠ ${tmuxWarning}`);
294
+ }
295
+ }
296
+
297
+ if (config.webui.enabled) {
298
+ const depWarnings = await checkWebuiDependencies();
299
+ for (const w of depWarnings) {
300
+ console.warn(`⚠ ${w}`);
301
+ }
302
+ }
303
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from "fs";
2
- import { PRODBOARD_DIR } from "./config.ts";
2
+ import { PRODBOARD_DIR, printConfigWarnings } from "./config.ts";
3
3
 
4
4
  export class NotInitializedError extends Error {
5
5
  constructor() {
@@ -36,6 +36,17 @@ export async function main(): Promise<void> {
36
36
  return;
37
37
  }
38
38
 
39
+ // Show config warnings for commands that use the config
40
+ const skipWarnings = ["init", "mcp", "version", "--version", "help", "--help", "uninstall"];
41
+ if (!skipWarnings.includes(command)) {
42
+ try {
43
+ ensureInitialized();
44
+ await printConfigWarnings();
45
+ } catch {
46
+ // ensureInitialized will throw again inside the switch if needed
47
+ }
48
+ }
49
+
39
50
  try {
40
51
  switch (command) {
41
52
  case "init": {