@worca/ui 0.15.1 → 0.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worca/ui",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "Pipeline monitoring UI for worca-cc",
5
5
  "license": "MIT",
6
6
  "author": "Sinisha Djukic",
@@ -371,7 +371,21 @@ export class ProcessManager {
371
371
  * @returns {Promise<{ pid: number }>}
372
372
  */
373
373
  async startPipeline(opts = {}) {
374
- const cwd = opts.projectRoot || this.projectRoot;
374
+ // Resume must spawn inside the run's own working tree. Worktree-hosted
375
+ // runs live under <worktree>/.worca/runs/<id>; if we spawn from the parent
376
+ // project root, git operations and relative settings paths target the
377
+ // wrong tree and the resumed pipeline corrupts state on the parent
378
+ // branch. Worktree wins over opts.projectRoot for resume — callers
379
+ // routinely pass proj.projectRoot without knowing whether the run is
380
+ // worktree-hosted. Mirrors the cwd derivation in restartStage.
381
+ let resumeCtx = null;
382
+ if (opts.resume && opts.runId) {
383
+ resumeCtx = this.resolveRunContext(opts.runId);
384
+ }
385
+ const cwd =
386
+ resumeCtx && resumeCtx.worcaDir !== this.worcaDir
387
+ ? join(resumeCtx.worcaDir, '..')
388
+ : opts.projectRoot || this.projectRoot;
375
389
  const pipelineScriptRel = '.claude/worca/scripts/run_pipeline.py';
376
390
  const worktreeScriptRel = '.claude/worca/scripts/run_worktree.py';
377
391
 
@@ -408,9 +422,8 @@ export class ProcessManager {
408
422
  if (opts.resume) {
409
423
  args.push('--resume');
410
424
  if (opts.runId) {
411
- const ctx = this.resolveRunContext(opts.runId);
412
- const statusDir = ctx
413
- ? ctx.runDir
425
+ const statusDir = resumeCtx
426
+ ? resumeCtx.runDir
414
427
  : join(this.worcaDir, 'runs', opts.runId);
415
428
  args.push('--status-dir', statusDir);
416
429
  }
@@ -71,7 +71,7 @@ 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 { findRunStatusPath } from './run-dir-resolver.js';
74
+ import { findRunStatusPath, readPipelineOverlay } from './run-dir-resolver.js';
75
75
  export { findRunStatusPath };
76
76
 
77
77
  /** Validate a branch name — alphanumeric, dots, hyphens, underscores, slashes */
@@ -686,8 +686,14 @@ export function createProjectScopedRoutes({
686
686
  }
687
687
  try {
688
688
  let status = JSON.parse(readFileSync(statusPath, 'utf8'));
689
- // Reconcile stale "running" status when no process is alive
690
- if (status.pipeline_status === 'running' && pm && !pm.getRunningPid()) {
689
+ // Reconcile stale "running" status when no process is alive.
690
+ // Pass runId so worktree-hosted pipelines (PID lives under
691
+ // <worktree>/.worca/runs/<id>/pipeline.pid) are detected correctly.
692
+ if (
693
+ status.pipeline_status === 'running' &&
694
+ pm &&
695
+ !pm.getRunningPid(runId)
696
+ ) {
691
697
  try {
692
698
  pm.reconcileStatus();
693
699
  status = JSON.parse(readFileSync(statusPath, 'utf8'));
@@ -1337,7 +1343,7 @@ export function createProjectScopedRoutes({
1337
1343
  .json({ ok: false, error: `Run "${runId}" not found` });
1338
1344
  }
1339
1345
 
1340
- const running = req.project.pm.getRunningPid();
1346
+ const running = req.project.pm.getRunningPid(runId);
1341
1347
  if (running) {
1342
1348
  return res.status(409).json({
1343
1349
  ok: false,
@@ -1366,7 +1372,11 @@ export function createProjectScopedRoutes({
1366
1372
  }
1367
1373
  }
1368
1374
 
1369
- const cwd = projectRoot || process.cwd();
1375
+ // Worktree-hosted runs live outside the parent project. Spawn the learner
1376
+ // inside the worktree so its default --status-dir=.worca and any git
1377
+ // operations land on the right tree, mirroring run_pipeline.py resume.
1378
+ const overlay = readPipelineOverlay(worcaDir, runId);
1379
+ const cwd = overlay?.worktree_path || projectRoot || process.cwd();
1370
1380
  const env = { ...process.env };
1371
1381
  delete env.CLAUDECODE;
1372
1382