vibe-coding-master 0.4.10 → 0.4.12
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/dist/backend/api/task-routes.js +4 -4
- package/dist/backend/gateway/gateway-service.js +4 -4
- package/dist/backend/services/claude-hook-service.js +9 -6
- package/dist/backend/services/session-service.js +178 -8
- package/dist-frontend/assets/{index-C3HtJs-w.js → index-DEz0--de.js} +25 -25
- package/dist-frontend/index.html +1 -1
- package/package.json +1 -1
|
@@ -32,7 +32,7 @@ export function registerTaskRoutes(app, deps) {
|
|
|
32
32
|
const project = await requireCurrentProject(deps.projectService);
|
|
33
33
|
const task = await deps.taskService.loadTask(project.repoRoot, request.params.taskSlug);
|
|
34
34
|
await stopRunningRoleSessions(deps, project.repoRoot, request.params.taskSlug);
|
|
35
|
-
await
|
|
35
|
+
await moveProjectToolSessionsToSafeCwd(deps, project.repoRoot);
|
|
36
36
|
await deps.translationService.stopTask(getTaskRuntimeRepoRoot(task), request.params.taskSlug, { clearCache: true });
|
|
37
37
|
deps.roundService.stopTask(request.params.taskSlug);
|
|
38
38
|
return deps.taskService.cleanupTask(project.repoRoot, request.params.taskSlug, request.body ?? {});
|
|
@@ -46,10 +46,10 @@ async function stopRunningRoleSessions(deps, repoRoot, taskSlug) {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
async function
|
|
49
|
+
async function moveProjectToolSessionsToSafeCwd(deps, repoRoot) {
|
|
50
50
|
await Promise.all([
|
|
51
|
-
ignoreMissingSession(deps.sessionService.
|
|
52
|
-
ignoreMissingSession(deps.sessionService.
|
|
51
|
+
ignoreMissingSession(deps.sessionService.moveProjectTranslatorSessionToSafeCwd(repoRoot)),
|
|
52
|
+
ignoreMissingSession(deps.sessionService.moveProjectHarnessEngineerSessionToSafeCwd(repoRoot))
|
|
53
53
|
]);
|
|
54
54
|
}
|
|
55
55
|
async function ignoreMissingSession(operation) {
|
|
@@ -526,7 +526,7 @@ export function createGatewayService(deps) {
|
|
|
526
526
|
}
|
|
527
527
|
const task = await deps.taskService.loadTask(project.repoRoot, taskSlug);
|
|
528
528
|
await stopRunningRoleSessions(project.repoRoot, taskSlug);
|
|
529
|
-
await
|
|
529
|
+
await moveProjectToolSessionsToSafeCwd(project.repoRoot);
|
|
530
530
|
await deps.translationService.stopTask(getTaskRuntimeRepoRoot(task), taskSlug, { clearCache: true });
|
|
531
531
|
deps.roundService.stopTask(taskSlug);
|
|
532
532
|
const result = await deps.taskService.cleanupTask(project.repoRoot, taskSlug, {
|
|
@@ -561,10 +561,10 @@ export function createGatewayService(deps) {
|
|
|
561
561
|
}
|
|
562
562
|
}
|
|
563
563
|
}
|
|
564
|
-
async function
|
|
564
|
+
async function moveProjectToolSessionsToSafeCwd(repoRoot) {
|
|
565
565
|
await Promise.all([
|
|
566
|
-
ignoreMissingSession(deps.sessionService.
|
|
567
|
-
ignoreMissingSession(deps.sessionService.
|
|
566
|
+
ignoreMissingSession(deps.sessionService.moveProjectTranslatorSessionToSafeCwd(repoRoot)),
|
|
567
|
+
ignoreMissingSession(deps.sessionService.moveProjectHarnessEngineerSessionToSafeCwd(repoRoot))
|
|
568
568
|
]);
|
|
569
569
|
}
|
|
570
570
|
async function ignoreMissingSession(operation) {
|
|
@@ -62,7 +62,7 @@ export function createClaudeHookService(deps) {
|
|
|
62
62
|
eventName,
|
|
63
63
|
sessionId: stringOrUndefined(input.event.session_id),
|
|
64
64
|
transcriptPath: stringOrUndefined(input.event.transcript_path),
|
|
65
|
-
cwd: stringOrUndefined(input.event.cwd)
|
|
65
|
+
cwd: stringOrUndefined(input.event.cwd) ?? stringOrUndefined(input.event.new_cwd)
|
|
66
66
|
});
|
|
67
67
|
await deps.translationWorkerService?.handleTranslatorHook(context.project.repoRoot, eventName, input.taskSlug);
|
|
68
68
|
return {
|
|
@@ -81,7 +81,7 @@ export function createClaudeHookService(deps) {
|
|
|
81
81
|
eventName,
|
|
82
82
|
sessionId: stringOrUndefined(input.event.session_id),
|
|
83
83
|
transcriptPath: stringOrUndefined(input.event.transcript_path),
|
|
84
|
-
cwd: stringOrUndefined(input.event.cwd)
|
|
84
|
+
cwd: stringOrUndefined(input.event.cwd) ?? stringOrUndefined(input.event.new_cwd)
|
|
85
85
|
});
|
|
86
86
|
await deps.harnessService?.recordHarnessBootstrapHook(context.project.repoRoot, {
|
|
87
87
|
eventName,
|
|
@@ -129,7 +129,7 @@ export function createClaudeHookService(deps) {
|
|
|
129
129
|
eventName,
|
|
130
130
|
claudeSessionId: stringOrUndefined(input.event.session_id),
|
|
131
131
|
transcriptPath: stringOrUndefined(input.event.transcript_path),
|
|
132
|
-
cwd: stringOrUndefined(input.event.cwd)
|
|
132
|
+
cwd: stringOrUndefined(input.event.cwd) ?? stringOrUndefined(input.event.new_cwd)
|
|
133
133
|
});
|
|
134
134
|
await deps.roundService.recordClaudeHookEvent({
|
|
135
135
|
repoRoot: context.project.repoRoot,
|
|
@@ -250,7 +250,7 @@ export function createClaudeHookService(deps) {
|
|
|
250
250
|
eventName,
|
|
251
251
|
claudeSessionId: stringOrUndefined(input.event.session_id),
|
|
252
252
|
transcriptPath: stringOrUndefined(input.event.transcript_path),
|
|
253
|
-
cwd: stringOrUndefined(input.event.cwd)
|
|
253
|
+
cwd: stringOrUndefined(input.event.cwd) ?? stringOrUndefined(input.event.new_cwd)
|
|
254
254
|
});
|
|
255
255
|
return {
|
|
256
256
|
ok: true,
|
|
@@ -270,7 +270,7 @@ export function createClaudeHookService(deps) {
|
|
|
270
270
|
eventName,
|
|
271
271
|
claudeSessionId: stringOrUndefined(input.event.session_id),
|
|
272
272
|
transcriptPath: stringOrUndefined(input.event.transcript_path),
|
|
273
|
-
cwd: stringOrUndefined(input.event.cwd)
|
|
273
|
+
cwd: stringOrUndefined(input.event.cwd) ?? stringOrUndefined(input.event.new_cwd)
|
|
274
274
|
});
|
|
275
275
|
await deps.roundService.recordClaudeHookEvent({
|
|
276
276
|
repoRoot: context.project.repoRoot,
|
|
@@ -448,7 +448,10 @@ export function createClaudeHookService(deps) {
|
|
|
448
448
|
};
|
|
449
449
|
}
|
|
450
450
|
function parseHookEvent(value) {
|
|
451
|
-
if (value === "UserPromptSubmit"
|
|
451
|
+
if (value === "UserPromptSubmit"
|
|
452
|
+
|| value === "Stop"
|
|
453
|
+
|| value === "StopFailure"
|
|
454
|
+
|| value === "PostCompact") {
|
|
452
455
|
return value;
|
|
453
456
|
}
|
|
454
457
|
throw new VcmError({
|
|
@@ -209,7 +209,7 @@ export function createSessionService(deps) {
|
|
|
209
209
|
const taskContext = await resolveProjectToolTaskContext(repoRoot, input, "Translator");
|
|
210
210
|
const live = toRoleSessionRecordView(getRegisteredProjectTranslatorSession(deps.registry, deps.runtime), deps.runtime);
|
|
211
211
|
if (live && live.status === "running") {
|
|
212
|
-
return withHarnessRevisionView(repoRoot, live);
|
|
212
|
+
return withHarnessRevisionView(repoRoot, await migrateRunningProjectToolSessionCwd(repoRoot, live, taskContext.taskRepoRoot));
|
|
213
213
|
}
|
|
214
214
|
const config = await deps.projectService.loadConfig(repoRoot);
|
|
215
215
|
const persisted = await loadPersistedTranslatorSession(deps.fs, repoRoot);
|
|
@@ -228,10 +228,15 @@ export function createSessionService(deps) {
|
|
|
228
228
|
});
|
|
229
229
|
}
|
|
230
230
|
await deps.fs.ensureDir(resolveRepoPath(repoRoot, TRANSLATION_DIR));
|
|
231
|
-
const
|
|
231
|
+
const launchCwd = launchMode === "resume"
|
|
232
|
+
? persisted?.cwd ?? taskContext.taskRepoRoot
|
|
233
|
+
: taskContext.taskRepoRoot;
|
|
234
|
+
const transcriptPath = launchMode === "resume" && persisted?.transcriptPath
|
|
235
|
+
? persisted.transcriptPath
|
|
236
|
+
: claudeTranscriptPath(launchCwd, claudeSessionId);
|
|
232
237
|
const startCommand = {
|
|
233
238
|
...deps.claude.buildRoleStartCommand(TRANSLATOR_ROLE, config.claudeCommand, permissionMode, claudeSessionId, launchMode === "resume", model, effort),
|
|
234
|
-
cwd:
|
|
239
|
+
cwd: launchCwd
|
|
235
240
|
};
|
|
236
241
|
const runtimeSession = await deps.runtime.createSession({
|
|
237
242
|
taskSlug: PROJECT_TRANSLATOR_SCOPE,
|
|
@@ -274,13 +279,13 @@ export function createSessionService(deps) {
|
|
|
274
279
|
};
|
|
275
280
|
deps.registry.upsert(record);
|
|
276
281
|
await persistTranslatorSession(deps.fs, repoRoot, record);
|
|
277
|
-
return withHarnessRevisionView(repoRoot, record);
|
|
282
|
+
return withHarnessRevisionView(repoRoot, await migrateRunningProjectToolSessionCwd(repoRoot, record, taskContext.taskRepoRoot));
|
|
278
283
|
}
|
|
279
284
|
async function launchProjectHarnessEngineerSession(repoRoot, input, launchMode) {
|
|
280
285
|
const taskContext = await resolveProjectToolTaskContext(repoRoot, input, "Harness Engineer");
|
|
281
286
|
const live = toRoleSessionRecordView(getRegisteredProjectHarnessEngineerSession(deps.registry, deps.runtime), deps.runtime);
|
|
282
287
|
if (live && live.status === "running") {
|
|
283
|
-
return withHarnessRevisionView(repoRoot, live);
|
|
288
|
+
return withHarnessRevisionView(repoRoot, await migrateRunningProjectToolSessionCwd(repoRoot, live, taskContext.taskRepoRoot));
|
|
284
289
|
}
|
|
285
290
|
const config = await deps.projectService.loadConfig(repoRoot);
|
|
286
291
|
const persisted = await loadPersistedHarnessEngineerSession(deps.fs, repoRoot);
|
|
@@ -299,10 +304,15 @@ export function createSessionService(deps) {
|
|
|
299
304
|
});
|
|
300
305
|
}
|
|
301
306
|
await deps.fs.ensureDir(resolveRepoPath(repoRoot, HARNESS_ENGINEER_DIR));
|
|
302
|
-
const
|
|
307
|
+
const launchCwd = launchMode === "resume"
|
|
308
|
+
? persisted?.cwd ?? taskContext.taskRepoRoot
|
|
309
|
+
: taskContext.taskRepoRoot;
|
|
310
|
+
const transcriptPath = launchMode === "resume" && persisted?.transcriptPath
|
|
311
|
+
? persisted.transcriptPath
|
|
312
|
+
: claudeTranscriptPath(launchCwd, claudeSessionId);
|
|
303
313
|
const startCommand = {
|
|
304
314
|
...deps.claude.buildRoleStartCommand(HARNESS_ENGINEER_ROLE, config.claudeCommand, permissionMode, claudeSessionId, launchMode === "resume", model, effort),
|
|
305
|
-
cwd:
|
|
315
|
+
cwd: launchCwd
|
|
306
316
|
};
|
|
307
317
|
const runtimeSession = await deps.runtime.createSession({
|
|
308
318
|
taskSlug: PROJECT_HARNESS_ENGINEER_SCOPE,
|
|
@@ -345,7 +355,7 @@ export function createSessionService(deps) {
|
|
|
345
355
|
};
|
|
346
356
|
deps.registry.upsert(record);
|
|
347
357
|
await persistHarnessEngineerSession(deps.fs, repoRoot, record);
|
|
348
|
-
return withHarnessRevisionView(repoRoot, record);
|
|
358
|
+
return withHarnessRevisionView(repoRoot, await migrateRunningProjectToolSessionCwd(repoRoot, record, taskContext.taskRepoRoot));
|
|
349
359
|
}
|
|
350
360
|
async function resolveProjectToolTaskContext(repoRoot, input, roleLabel) {
|
|
351
361
|
const taskSlug = input.taskSlug?.trim();
|
|
@@ -363,6 +373,100 @@ export function createSessionService(deps) {
|
|
|
363
373
|
taskRepoRoot: getTaskRuntimeRepoRoot(task)
|
|
364
374
|
};
|
|
365
375
|
}
|
|
376
|
+
async function migrateRunningProjectToolSessionCwd(repoRoot, session, targetCwd) {
|
|
377
|
+
if (session.role !== TRANSLATOR_ROLE
|
|
378
|
+
&& session.role !== HARNESS_ENGINEER_ROLE
|
|
379
|
+
&& session.role !== GATE_REVIEWER_ROLE) {
|
|
380
|
+
return session;
|
|
381
|
+
}
|
|
382
|
+
if (samePath(session.cwd, targetCwd)) {
|
|
383
|
+
return session;
|
|
384
|
+
}
|
|
385
|
+
const runtimeSession = deps.runtime.getSession(session.id);
|
|
386
|
+
if (!runtimeSession || runtimeSession.status !== "running") {
|
|
387
|
+
return session;
|
|
388
|
+
}
|
|
389
|
+
assertSafeCwdTarget(targetCwd);
|
|
390
|
+
const timestamp = now();
|
|
391
|
+
await submitTerminalInput(deps.runtime, session.id, `/cd ${targetCwd}`);
|
|
392
|
+
const updated = {
|
|
393
|
+
...session,
|
|
394
|
+
cwd: targetCwd,
|
|
395
|
+
previousCwd: session.cwd,
|
|
396
|
+
transcriptPath: claudeTranscriptPath(targetCwd, session.claudeSessionId),
|
|
397
|
+
updatedAt: timestamp
|
|
398
|
+
};
|
|
399
|
+
deps.registry.upsert(normalizeProjectScopedRecordForPersistence(updated));
|
|
400
|
+
await persistProjectScopedToolSession(repoRoot, updated);
|
|
401
|
+
return updated;
|
|
402
|
+
}
|
|
403
|
+
async function resumeProjectToolSessionAtCwd(repoRoot, session, targetCwd) {
|
|
404
|
+
const live = toRoleSessionRecordView(session.role === TRANSLATOR_ROLE
|
|
405
|
+
? getRegisteredProjectTranslatorSession(deps.registry, deps.runtime)
|
|
406
|
+
: session.role === HARNESS_ENGINEER_ROLE
|
|
407
|
+
? getRegisteredProjectHarnessEngineerSession(deps.registry, deps.runtime)
|
|
408
|
+
: getRegisteredProjectGateReviewerSession(deps.registry, deps.runtime), deps.runtime);
|
|
409
|
+
if (live?.status === "running") {
|
|
410
|
+
return migrateRunningProjectToolSessionCwd(repoRoot, live, targetCwd);
|
|
411
|
+
}
|
|
412
|
+
const config = await deps.projectService.loadConfig(repoRoot);
|
|
413
|
+
const permissionMode = normalizeClaudePermissionMode(session.permissionMode);
|
|
414
|
+
const model = normalizeClaudeModel(session.model);
|
|
415
|
+
const effort = normalizeClaudeEffort(session.effort);
|
|
416
|
+
const launchCwd = session.cwd || targetCwd;
|
|
417
|
+
const startCommand = {
|
|
418
|
+
...deps.claude.buildRoleStartCommand(session.role, config.claudeCommand, permissionMode, session.claudeSessionId, true, model, effort),
|
|
419
|
+
cwd: launchCwd
|
|
420
|
+
};
|
|
421
|
+
const runtimeSession = await deps.runtime.createSession({
|
|
422
|
+
taskSlug: normalizeProjectScopedRecordForPersistence(session).taskSlug,
|
|
423
|
+
role: session.role,
|
|
424
|
+
command: startCommand.command,
|
|
425
|
+
args: startCommand.args,
|
|
426
|
+
cwd: startCommand.cwd,
|
|
427
|
+
env: {
|
|
428
|
+
VCM_API_URL: deps.apiUrl,
|
|
429
|
+
VCM_TASK_REPO_ROOT: targetCwd,
|
|
430
|
+
VCM_TASK_SLUG: normalizeProjectScopedRecordForPersistence(session).taskSlug,
|
|
431
|
+
VCM_ROLE: session.role,
|
|
432
|
+
VCM_SESSION_ID: session.claudeSessionId
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
const timestamp = now();
|
|
436
|
+
const resumed = {
|
|
437
|
+
...session,
|
|
438
|
+
id: runtimeSession.id,
|
|
439
|
+
status: runtimeSession.status,
|
|
440
|
+
activityStatus: "idle",
|
|
441
|
+
command: startCommand.display,
|
|
442
|
+
permissionMode,
|
|
443
|
+
model,
|
|
444
|
+
effort,
|
|
445
|
+
cwd: launchCwd,
|
|
446
|
+
pid: runtimeSession.pid,
|
|
447
|
+
startedAt: runtimeSession.startedAt,
|
|
448
|
+
updatedAt: timestamp,
|
|
449
|
+
lastOutputAt: runtimeSession.lastOutputAt,
|
|
450
|
+
exitCode: runtimeSession.exitCode,
|
|
451
|
+
transcriptPath: session.transcriptPath ?? claudeTranscriptPath(launchCwd, session.claudeSessionId)
|
|
452
|
+
};
|
|
453
|
+
deps.registry.upsert(normalizeProjectScopedRecordForPersistence(resumed));
|
|
454
|
+
await persistProjectScopedToolSession(repoRoot, resumed);
|
|
455
|
+
return migrateRunningProjectToolSessionCwd(repoRoot, resumed, targetCwd);
|
|
456
|
+
}
|
|
457
|
+
async function persistProjectScopedToolSession(repoRoot, session) {
|
|
458
|
+
if (session.role === GATE_REVIEWER_ROLE) {
|
|
459
|
+
await persistProjectGateReviewerSession(deps.fs, repoRoot, session);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (session.role === TRANSLATOR_ROLE) {
|
|
463
|
+
await persistTranslatorSession(deps.fs, repoRoot, session);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (session.role === HARNESS_ENGINEER_ROLE) {
|
|
467
|
+
await persistHarnessEngineerSession(deps.fs, repoRoot, session);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
366
470
|
async function notifyHarnessUpdatedForSession(repoRoot, session) {
|
|
367
471
|
const runtimeSession = deps.runtime.getSession(session.id);
|
|
368
472
|
if (!runtimeSession || runtimeSession.status !== "running") {
|
|
@@ -505,6 +609,23 @@ export function createSessionService(deps) {
|
|
|
505
609
|
await persistTranslatorSession(deps.fs, repoRoot, updated);
|
|
506
610
|
return updated;
|
|
507
611
|
},
|
|
612
|
+
async moveProjectTranslatorSessionToSafeCwd(repoRoot) {
|
|
613
|
+
const existing = await this.getProjectTranslatorSession(repoRoot);
|
|
614
|
+
if (!existing) {
|
|
615
|
+
throw new VcmError({
|
|
616
|
+
code: "SESSION_MISSING",
|
|
617
|
+
message: "Translator session has not been started.",
|
|
618
|
+
statusCode: 404
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
if (samePath(existing.cwd, repoRoot)) {
|
|
622
|
+
return existing;
|
|
623
|
+
}
|
|
624
|
+
return withHarnessRevisionView(repoRoot, await resumeProjectToolSessionAtCwd(repoRoot, {
|
|
625
|
+
...existing,
|
|
626
|
+
taskSlug: PROJECT_TRANSLATOR_SCOPE
|
|
627
|
+
}, repoRoot));
|
|
628
|
+
},
|
|
508
629
|
async restartProjectTranslatorSession(repoRoot, input = {}) {
|
|
509
630
|
const existing = await this.getProjectTranslatorSession(repoRoot);
|
|
510
631
|
if (!existing) {
|
|
@@ -525,6 +646,16 @@ export function createSessionService(deps) {
|
|
|
525
646
|
async ensureProjectTranslatorSession(repoRoot, input = {}) {
|
|
526
647
|
const existing = await this.getProjectTranslatorSession(repoRoot);
|
|
527
648
|
if (existing?.status === "running") {
|
|
649
|
+
if (input.taskSlug) {
|
|
650
|
+
return this.resumeProjectTranslatorSession(repoRoot, {
|
|
651
|
+
taskSlug: input.taskSlug,
|
|
652
|
+
permissionMode: input.permissionMode ?? existing.permissionMode,
|
|
653
|
+
model: input.model ?? existing.model,
|
|
654
|
+
effort: input.effort ?? existing.effort,
|
|
655
|
+
cols: input.cols,
|
|
656
|
+
rows: input.rows
|
|
657
|
+
});
|
|
658
|
+
}
|
|
528
659
|
return existing;
|
|
529
660
|
}
|
|
530
661
|
if (existing?.claudeSessionId) {
|
|
@@ -602,6 +733,23 @@ export function createSessionService(deps) {
|
|
|
602
733
|
await persistHarnessEngineerSession(deps.fs, repoRoot, updated);
|
|
603
734
|
return updated;
|
|
604
735
|
},
|
|
736
|
+
async moveProjectHarnessEngineerSessionToSafeCwd(repoRoot) {
|
|
737
|
+
const existing = await this.getProjectHarnessEngineerSession(repoRoot);
|
|
738
|
+
if (!existing) {
|
|
739
|
+
throw new VcmError({
|
|
740
|
+
code: "SESSION_MISSING",
|
|
741
|
+
message: "Harness Engineer session has not been started.",
|
|
742
|
+
statusCode: 404
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
if (samePath(existing.cwd, repoRoot)) {
|
|
746
|
+
return existing;
|
|
747
|
+
}
|
|
748
|
+
return withHarnessRevisionView(repoRoot, await resumeProjectToolSessionAtCwd(repoRoot, {
|
|
749
|
+
...existing,
|
|
750
|
+
taskSlug: PROJECT_HARNESS_ENGINEER_SCOPE
|
|
751
|
+
}, repoRoot));
|
|
752
|
+
},
|
|
605
753
|
async restartProjectHarnessEngineerSession(repoRoot, input = {}) {
|
|
606
754
|
const existing = await this.getProjectHarnessEngineerSession(repoRoot);
|
|
607
755
|
if (!existing) {
|
|
@@ -622,6 +770,16 @@ export function createSessionService(deps) {
|
|
|
622
770
|
async ensureProjectHarnessEngineerSession(repoRoot, input = {}) {
|
|
623
771
|
const existing = await this.getProjectHarnessEngineerSession(repoRoot);
|
|
624
772
|
if (existing?.status === "running") {
|
|
773
|
+
if (input.taskSlug) {
|
|
774
|
+
return this.resumeProjectHarnessEngineerSession(repoRoot, {
|
|
775
|
+
taskSlug: input.taskSlug,
|
|
776
|
+
permissionMode: input.permissionMode ?? existing.permissionMode,
|
|
777
|
+
model: input.model ?? existing.model,
|
|
778
|
+
effort: input.effort ?? existing.effort,
|
|
779
|
+
cols: input.cols,
|
|
780
|
+
rows: input.rows
|
|
781
|
+
});
|
|
782
|
+
}
|
|
625
783
|
return existing;
|
|
626
784
|
}
|
|
627
785
|
if (existing?.claudeSessionId) {
|
|
@@ -1003,6 +1161,18 @@ function getRecoverableStatus(record) {
|
|
|
1003
1161
|
}
|
|
1004
1162
|
return "resumable";
|
|
1005
1163
|
}
|
|
1164
|
+
function samePath(left, right) {
|
|
1165
|
+
return path.resolve(left) === path.resolve(right);
|
|
1166
|
+
}
|
|
1167
|
+
function assertSafeCwdTarget(targetCwd) {
|
|
1168
|
+
if (!targetCwd.trim() || /[\r\n]/.test(targetCwd)) {
|
|
1169
|
+
throw new VcmError({
|
|
1170
|
+
code: "SESSION_CWD_INVALID",
|
|
1171
|
+
message: "Session cwd target is invalid.",
|
|
1172
|
+
statusCode: 400
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1006
1176
|
function getHandoffArtifactPath(paths, role) {
|
|
1007
1177
|
if (role === "architect") {
|
|
1008
1178
|
return paths.architecturePlanPath;
|