@worca/ui 0.15.3 → 0.17.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 +3 -1
- package/server/process-manager.js +10 -0
- package/server/project-routes.js +10 -1
- package/server/run-dir-resolver.js +35 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@worca/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Pipeline monitoring UI for worca-cc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sinisha Djukic",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"prepublishOnly": "npm run build && npm test",
|
|
51
51
|
"test": "vitest run",
|
|
52
52
|
"test:watch": "vitest",
|
|
53
|
+
"test:coverage": "vitest run --coverage",
|
|
53
54
|
"test:browser": "playwright test",
|
|
54
55
|
"test:browser:ui": "playwright test --ui",
|
|
55
56
|
"lint": "biome check",
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"devDependencies": {
|
|
71
72
|
"@biomejs/biome": "^2.2.4",
|
|
72
73
|
"@playwright/test": "^1.58.2",
|
|
74
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
73
75
|
"esbuild": "^0.27.1",
|
|
74
76
|
"jsdom": "^29.0.1",
|
|
75
77
|
"vitest": "^4.0.15"
|
|
@@ -431,6 +431,16 @@ export class ProcessManager {
|
|
|
431
431
|
const statusDir = resumeCtx ? resumeCtx.worcaDir : this.worcaDir;
|
|
432
432
|
args.push('--status-dir', statusDir);
|
|
433
433
|
|
|
434
|
+
// Worktree runs: registry lives in the parent project's .worca, not
|
|
435
|
+
// the worktree's. run_worktree.py passes --registry-base on initial
|
|
436
|
+
// launch; resume must do the same so update_pipeline() lands on the
|
|
437
|
+
// right registry entry. Without this, the runner's terminal /
|
|
438
|
+
// resume-flip-to-running registry updates silently no-op against a
|
|
439
|
+
// non-existent <worktree>/.worca/multi/pipelines.d/<id>.json.
|
|
440
|
+
if (resumeCtx && resumeCtx.worcaDir !== this.worcaDir) {
|
|
441
|
+
args.push('--registry-base', this.worcaDir);
|
|
442
|
+
}
|
|
443
|
+
|
|
434
444
|
// _find_active_runs filters out runs whose pipeline_status is in
|
|
435
445
|
// {completed, interrupted}. To resume an interrupted/failed run, flip
|
|
436
446
|
// the top-level status to "resuming" so the runner can pick it up;
|
package/server/project-routes.js
CHANGED
|
@@ -71,7 +71,11 @@ function validateRunId(runId) {
|
|
|
71
71
|
// Re-exported from run-dir-resolver so callers (including older tests) can
|
|
72
72
|
// continue importing from project-routes. The implementation now overlays
|
|
73
73
|
// worktree runs registered in <worcaDir>/multi/pipelines.d/.
|
|
74
|
-
import {
|
|
74
|
+
import {
|
|
75
|
+
findRunStatusPath,
|
|
76
|
+
readPipelineOverlay,
|
|
77
|
+
updatePipelineStatus,
|
|
78
|
+
} from './run-dir-resolver.js';
|
|
75
79
|
export { findRunStatusPath };
|
|
76
80
|
|
|
77
81
|
/** Validate a branch name — alphanumeric, dots, hyphens, underscores, slashes */
|
|
@@ -1086,6 +1090,11 @@ export function createProjectScopedRoutes({
|
|
|
1086
1090
|
st.completed_at = new Date().toISOString();
|
|
1087
1091
|
writeFileSync(statusPath, `${JSON.stringify(st, null, 2)}\n`, 'utf8');
|
|
1088
1092
|
|
|
1093
|
+
// Mirror into the multi-pipeline registry so global-mode views don't
|
|
1094
|
+
// keep reporting the run as "running". Best-effort — the registry entry
|
|
1095
|
+
// only exists for worktree runs.
|
|
1096
|
+
updatePipelineStatus(worcaDir, runId, 'cancelled');
|
|
1097
|
+
|
|
1089
1098
|
const { broadcast, scheduleRefresh } = req.app.locals;
|
|
1090
1099
|
if (broadcast) broadcast('run-cancelled', { runId });
|
|
1091
1100
|
if (scheduleRefresh) scheduleRefresh(req.project?.name);
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 3. `<worcaDir>/multi/pipelines.d/<runId>.json` → `<worktree_path>/.worca/runs/<runId>/`
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
+
import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -77,3 +77,37 @@ export function readPipelineOverlay(worcaDir, runId) {
|
|
|
77
77
|
return null;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Update the multi-pipeline registry entry's status field.
|
|
83
|
+
*
|
|
84
|
+
* Mirrors src/worca/orchestrator/registry.py:update_pipeline() — terminal
|
|
85
|
+
* status (cancelled/completed/failed/interrupted) only. The Python runner
|
|
86
|
+
* updates the registry on its own terminal paths; this helper exists for
|
|
87
|
+
* callers (the UI cancel route) that write status.json directly without
|
|
88
|
+
* going through the runner.
|
|
89
|
+
*
|
|
90
|
+
* Returns true when the registry entry existed and was updated, false when
|
|
91
|
+
* there's no registry entry for this runId (e.g. local in-place run).
|
|
92
|
+
*
|
|
93
|
+
* @param {string} worcaDir - the parent project's .worca directory
|
|
94
|
+
* @param {string} runId
|
|
95
|
+
* @param {string} status - new status value (e.g. 'cancelled')
|
|
96
|
+
*/
|
|
97
|
+
export function updatePipelineStatus(worcaDir, runId, status) {
|
|
98
|
+
const regPath = join(worcaDir, 'multi', 'pipelines.d', `${runId}.json`);
|
|
99
|
+
if (!existsSync(regPath)) return false;
|
|
100
|
+
try {
|
|
101
|
+
const data = JSON.parse(readFileSync(regPath, 'utf8'));
|
|
102
|
+
data.status = status;
|
|
103
|
+
data.updated_at = new Date().toISOString();
|
|
104
|
+
// Match Python's atomic write: write to .tmp + rename. Avoids partial
|
|
105
|
+
// writes if the process crashes mid-write.
|
|
106
|
+
const tmpPath = `${regPath}.tmp`;
|
|
107
|
+
writeFileSync(tmpPath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
|
|
108
|
+
renameSync(tmpPath, regPath);
|
|
109
|
+
return true;
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|