@worca/ui 0.1.0-rc.2 → 0.1.0-rc.4

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/bin/worca-ui.js CHANGED
@@ -44,7 +44,7 @@ export function parseArgs(argv) {
44
44
  port: 3400,
45
45
  host: '127.0.0.1',
46
46
  open: false,
47
- global: false,
47
+ global: true,
48
48
  // projects sub-command
49
49
  subAction: null, // 'list' | 'add' | 'remove'
50
50
  projectPath: null,
@@ -86,6 +86,11 @@ export function parseArgs(argv) {
86
86
  args.open = true;
87
87
  } else if (arg === '--global') {
88
88
  args.global = true;
89
+ } else if (arg === '--project') {
90
+ args.global = false;
91
+ if (argv[i + 1] && !argv[i + 1].startsWith('-')) {
92
+ args.projectPath = argv[++i];
93
+ }
89
94
  } else if (arg === '--scan' && argv[i + 1]) {
90
95
  args.scanDir = argv[++i];
91
96
  } else if (arg === '--dry-run') {
@@ -535,6 +540,6 @@ switch (args.command) {
535
540
  break;
536
541
  default:
537
542
  console.log(
538
- 'Usage: worca-ui [start|stop|restart|status|projects|migrate] [--port N] [--host H] [--open] [--global]',
543
+ 'Usage: worca-ui [start|stop|restart|status|projects|migrate] [--port N] [--host H] [--open] [--project [PATH]]',
539
544
  );
540
545
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worca/ui",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.0-rc.4",
4
4
  "description": "Pipeline monitoring UI for worca-cc",
5
5
  "license": "MIT",
6
6
  "author": "Sinisha Djukic",
package/server/index.js CHANGED
@@ -9,13 +9,14 @@ import { attachWsServer } from './ws.js';
9
9
  // Parse argv
10
10
  let port = parseInt(process.env.PORT, 10) || 3400;
11
11
  let host = process.env.HOST || '127.0.0.1';
12
- let isGlobal = false;
12
+ let isGlobal = true;
13
13
  for (let i = 0; i < process.argv.length; i++) {
14
14
  if (process.argv[i] === '--port' && process.argv[i + 1])
15
15
  port = parseInt(process.argv[++i], 10);
16
16
  if (process.argv[i] === '--host' && process.argv[i + 1])
17
17
  host = process.argv[++i];
18
18
  if (process.argv[i] === '--global') isGlobal = true;
19
+ if (process.argv[i] === '--project') isGlobal = false;
19
20
  }
20
21
 
21
22
  // Resolve project root: walk up from cwd until we find .claude/settings.json
@@ -31,6 +32,7 @@ function findProjectRoot(startDir) {
31
32
  return startDir; // fallback
32
33
  }
33
34
 
35
+ import { checkWorcaVersion } from './version-check.js';
34
36
  import { createInbox } from './webhook-inbox.js';
35
37
 
36
38
  let projectRoot, worcaDir, settingsPath;
@@ -102,6 +104,18 @@ app.locals.broadcast = broadcast;
102
104
  app.locals.scheduleRefresh = scheduleRefresh;
103
105
  app.locals.resolveRunProject = resolveRunProject;
104
106
 
107
+ // ─── worca-cc version check (non-blocking) ─────────────────────────────
108
+ checkWorcaVersion().then((result) => {
109
+ app.locals.worcaVersion = result;
110
+ if (result.ok) {
111
+ console.log(`[version] ${result.message}`);
112
+ } else if (result.installed) {
113
+ console.warn(`[version] ${result.message}`);
114
+ } else {
115
+ console.log(`[version] ${result.message}`);
116
+ }
117
+ });
118
+
105
119
  // ─── inotify budget check (Linux only) ─────────────────────────────────
106
120
  if (platform() === 'linux') {
107
121
  try {
@@ -1,7 +1,7 @@
1
1
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname } from 'node:path';
3
3
 
4
- const DEFAULTS = { theme: 'light' };
4
+ const DEFAULTS = { theme: 'light', source_repo: '' };
5
5
 
6
6
  export function readPreferences(path) {
7
7
  try {
@@ -16,9 +16,11 @@ import {
16
16
  unlinkSync,
17
17
  writeFileSync,
18
18
  } from 'node:fs';
19
+ import { homedir } from 'node:os';
19
20
  import { dirname, join } from 'node:path';
20
21
  import { Router } from 'express';
21
22
  import { dbExists, getIssue, listIssues } from './beads-reader.js';
23
+ import { readPreferences } from './preferences.js';
22
24
  import { ProcessManager } from './process-manager.js';
23
25
  import {
24
26
  readProjects,
@@ -1102,14 +1104,16 @@ export function createProjectScopedRoutes() {
1102
1104
 
1103
1105
  // POST /api/projects/:projectId/worca-setup — install or update worca
1104
1106
  router.post('/worca-setup', (req, res) => {
1105
- const { settingsPath, projectRoot } = req.project;
1107
+ const { projectRoot } = req.project;
1106
1108
  let source = req.body?.source;
1107
1109
 
1108
- // Fall back to worca.source_repo from merged settings
1109
- if (!source && settingsPath) {
1110
+ // Fall back to source_repo from global preferences
1111
+ if (!source) {
1110
1112
  try {
1111
- const settings = readMergedSettings(settingsPath);
1112
- source = settings?.worca?.source_repo;
1113
+ const prefs = readPreferences(
1114
+ join(homedir(), '.worca', 'preferences.json'),
1115
+ );
1116
+ source = prefs.source_repo || undefined;
1113
1117
  } catch {
1114
1118
  /* ignore — worca init will use its own resolution chain */
1115
1119
  }
@@ -0,0 +1,82 @@
1
+ // server/version-check.js — worca-cc version compatibility check
2
+ import { execFile } from 'node:child_process';
3
+
4
+ /** Minimum worca-cc version required by this @worca/ui release. */
5
+ export const MIN_WORCA_CC = '0.6.0';
6
+
7
+ /**
8
+ * Parse the version string from `worca --version` output.
9
+ * Expected format: "worca-cc X.Y.Z" or "worca-cc X.Y.Zrc3"
10
+ * @param {string} output - stdout from `worca --version`
11
+ * @returns {string|null} version string or null if unparseable
12
+ */
13
+ export function parseWorcaVersion(output) {
14
+ const match = output.trim().match(/^worca-cc\s+(\S+)/);
15
+ return match ? match[1] : null;
16
+ }
17
+
18
+ /**
19
+ * Compare two semver-ish versions, ignoring pre-release suffixes.
20
+ * "0.6.0rc3" satisfies ">= 0.6.0".
21
+ * @param {string} installed - installed version (e.g. "0.6.0rc3")
22
+ * @param {string} minimum - minimum required version (e.g. "0.6.0")
23
+ * @returns {boolean} true if installed >= minimum
24
+ */
25
+ export function meetsMinimum(installed, minimum) {
26
+ const parse = (v) =>
27
+ v.split('.').map((s) => {
28
+ const n = parseInt(s, 10);
29
+ return Number.isNaN(n) ? 0 : n;
30
+ });
31
+ const inst = parse(installed);
32
+ const min = parse(minimum);
33
+ const len = Math.max(inst.length, min.length);
34
+ for (let i = 0; i < len; i++) {
35
+ const a = inst[i] || 0;
36
+ const b = min[i] || 0;
37
+ if (a > b) return true;
38
+ if (a < b) return false;
39
+ }
40
+ return true; // equal
41
+ }
42
+
43
+ /**
44
+ * Run `worca --version` and check compatibility.
45
+ * @returns {Promise<{ok: boolean, installed: string|null, minimum: string, message: string}>}
46
+ */
47
+ export async function checkWorcaVersion() {
48
+ const minimum = MIN_WORCA_CC;
49
+ try {
50
+ const output = await new Promise((resolve, reject) => {
51
+ execFile('worca', ['--version'], { timeout: 5000 }, (err, stdout) => {
52
+ if (err) return reject(err);
53
+ resolve(stdout);
54
+ });
55
+ });
56
+ const installed = parseWorcaVersion(output);
57
+ if (!installed) {
58
+ return {
59
+ ok: false,
60
+ installed: null,
61
+ minimum,
62
+ message: `worca CLI not found — install with 'pip install worca-cc'`,
63
+ };
64
+ }
65
+ const ok = meetsMinimum(installed, minimum);
66
+ return {
67
+ ok,
68
+ installed,
69
+ minimum,
70
+ message: ok
71
+ ? `worca-cc ${installed} — compatible`
72
+ : `WARNING: worca-cc ${installed} found, minimum ${minimum} required — run 'pip install --upgrade worca-cc'`,
73
+ };
74
+ } catch {
75
+ return {
76
+ ok: false,
77
+ installed: null,
78
+ minimum,
79
+ message: `worca CLI not found — install with 'pip install worca-cc'`,
80
+ };
81
+ }
82
+ }