@worca/ui 0.1.0-rc.1 → 0.1.0-rc.3
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/app/protocol.js +93 -0
- package/app/utils/stage-order.js +40 -0
- package/package.json +3 -1
- package/server/index.js +13 -0
- package/server/version-check.js +82 -0
package/app/protocol.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol definitions for worca-ui WebSocket communication.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** @typedef {'subscribe-run'|'unsubscribe-run'|'subscribe-log'|'unsubscribe-log'|'list-runs'|'get-agent-prompt'|'get-preferences'|'set-preferences'|'stop-run'|'resume-run'|'list-beads-issues'|'start-beads-issue'|'list-beads-counts'|'list-beads-refs'|'list-beads-unlinked'|'run-snapshot'|'run-update'|'runs-list'|'log-line'|'log-bulk'|'preferences'|'run-started'|'run-stopped'|'stage-restarted'|'beads-update'} MessageType */
|
|
6
|
+
|
|
7
|
+
/** @type {MessageType[]} */
|
|
8
|
+
export const MESSAGE_TYPES = [
|
|
9
|
+
'subscribe-run',
|
|
10
|
+
'unsubscribe-run',
|
|
11
|
+
'subscribe-log',
|
|
12
|
+
'unsubscribe-log',
|
|
13
|
+
'list-runs',
|
|
14
|
+
'get-agent-prompt',
|
|
15
|
+
'get-preferences',
|
|
16
|
+
'set-preferences',
|
|
17
|
+
'stop-run',
|
|
18
|
+
'resume-run',
|
|
19
|
+
'list-beads-issues',
|
|
20
|
+
'start-beads-issue',
|
|
21
|
+
'list-beads-by-run',
|
|
22
|
+
'list-beads-counts',
|
|
23
|
+
'list-beads-refs',
|
|
24
|
+
'list-beads-unlinked',
|
|
25
|
+
// Webhook inbox
|
|
26
|
+
'get-webhook-inbox',
|
|
27
|
+
'set-webhook-control',
|
|
28
|
+
'clear-webhook-inbox',
|
|
29
|
+
// Protocol handshake
|
|
30
|
+
'hello',
|
|
31
|
+
'hello-ack',
|
|
32
|
+
// Parallel pipelines
|
|
33
|
+
'list-pipelines',
|
|
34
|
+
'subscribe-pipeline',
|
|
35
|
+
'unsubscribe-pipeline',
|
|
36
|
+
'pipeline-status-changed',
|
|
37
|
+
'pipelines-list',
|
|
38
|
+
// Server → Client events
|
|
39
|
+
'run-snapshot',
|
|
40
|
+
'run-update',
|
|
41
|
+
'runs-list',
|
|
42
|
+
'log-line',
|
|
43
|
+
'log-bulk',
|
|
44
|
+
'preferences',
|
|
45
|
+
'run-started',
|
|
46
|
+
'run-stopped',
|
|
47
|
+
'stage-restarted',
|
|
48
|
+
'beads-update',
|
|
49
|
+
'webhook-inbox-event',
|
|
50
|
+
'webhook-control-changed',
|
|
51
|
+
'webhook-inbox-cleared',
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
export function nextId() {
|
|
55
|
+
const now = Date.now().toString(36);
|
|
56
|
+
const rand = Math.random().toString(36).slice(2, 8);
|
|
57
|
+
return `${now}-${rand}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function makeRequest(type, payload, id = nextId()) {
|
|
61
|
+
return { id, type, payload };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function makeOk(req, payload) {
|
|
65
|
+
return { id: req.id, ok: true, type: req.type, payload };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function makeError(req, code, message, details) {
|
|
69
|
+
return {
|
|
70
|
+
id: req.id,
|
|
71
|
+
ok: false,
|
|
72
|
+
type: req.type,
|
|
73
|
+
error: { code, message, details },
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function isMessageType(value) {
|
|
78
|
+
return typeof value === 'string' && MESSAGE_TYPES.includes(value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isRecord(value) {
|
|
82
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function isRequest(value) {
|
|
86
|
+
if (!isRecord(value)) return false;
|
|
87
|
+
return typeof value.id === 'string' && typeof value.type === 'string';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function decodeRequest(json) {
|
|
91
|
+
if (!isRequest(json)) throw new Error('Invalid request envelope');
|
|
92
|
+
return json;
|
|
93
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical pipeline stage order — single source of truth for the UI.
|
|
3
|
+
* Mirrors stages.py STAGE_ORDER on the Python side.
|
|
4
|
+
*/
|
|
5
|
+
export const STAGE_ORDER = [
|
|
6
|
+
'preflight',
|
|
7
|
+
'plan',
|
|
8
|
+
'plan_review',
|
|
9
|
+
'coordinate',
|
|
10
|
+
'implement',
|
|
11
|
+
'test',
|
|
12
|
+
'review',
|
|
13
|
+
'pr',
|
|
14
|
+
'learn',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
/** Stage order with orchestrator prepended (for log display). */
|
|
18
|
+
export const STAGE_ORDER_WITH_ORCHESTRATOR = ['orchestrator', ...STAGE_ORDER];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Sort stage entries by canonical order. Unknown stages sort to the end.
|
|
22
|
+
*/
|
|
23
|
+
export function sortByStageOrder(entries) {
|
|
24
|
+
return [...entries].sort(([a], [b]) => {
|
|
25
|
+
const ai = STAGE_ORDER.indexOf(a);
|
|
26
|
+
const bi = STAGE_ORDER.indexOf(b);
|
|
27
|
+
return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Sort stage name strings by canonical order. Unknown stages sort to the end.
|
|
33
|
+
*/
|
|
34
|
+
export function sortStageNames(names) {
|
|
35
|
+
return [...names].sort((a, b) => {
|
|
36
|
+
const ai = STAGE_ORDER.indexOf(a);
|
|
37
|
+
const bi = STAGE_ORDER.indexOf(b);
|
|
38
|
+
return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi);
|
|
39
|
+
});
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@worca/ui",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.3",
|
|
4
4
|
"description": "Pipeline monitoring UI for worca-cc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sinisha Djukic",
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
"app/main.bundle.js.map",
|
|
32
32
|
"app/styles.css",
|
|
33
33
|
"app/vendor/",
|
|
34
|
+
"app/protocol.js",
|
|
35
|
+
"app/utils/stage-order.js",
|
|
34
36
|
"scripts/build-frontend.js"
|
|
35
37
|
],
|
|
36
38
|
"engines": {
|
package/server/index.js
CHANGED
|
@@ -31,6 +31,7 @@ function findProjectRoot(startDir) {
|
|
|
31
31
|
return startDir; // fallback
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
import { checkWorcaVersion } from './version-check.js';
|
|
34
35
|
import { createInbox } from './webhook-inbox.js';
|
|
35
36
|
|
|
36
37
|
let projectRoot, worcaDir, settingsPath;
|
|
@@ -102,6 +103,18 @@ app.locals.broadcast = broadcast;
|
|
|
102
103
|
app.locals.scheduleRefresh = scheduleRefresh;
|
|
103
104
|
app.locals.resolveRunProject = resolveRunProject;
|
|
104
105
|
|
|
106
|
+
// ─── worca-cc version check (non-blocking) ─────────────────────────────
|
|
107
|
+
checkWorcaVersion().then((result) => {
|
|
108
|
+
app.locals.worcaVersion = result;
|
|
109
|
+
if (result.ok) {
|
|
110
|
+
console.log(`[version] ${result.message}`);
|
|
111
|
+
} else if (result.installed) {
|
|
112
|
+
console.warn(`[version] ${result.message}`);
|
|
113
|
+
} else {
|
|
114
|
+
console.log(`[version] ${result.message}`);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
105
118
|
// ─── inotify budget check (Linux only) ─────────────────────────────────
|
|
106
119
|
if (platform() === 'linux') {
|
|
107
120
|
try {
|
|
@@ -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
|
+
}
|