vibe-coding-master 0.8.4 → 0.8.5
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/README.md +9 -4
- package/dist/backend/api/task-routes.js +6 -0
- package/dist/backend/gateway/gateway-service.js +18 -3
- package/dist/backend/server.js +4 -1
- package/dist/backend/services/claude-hook-service.js +16 -1
- package/dist/backend/services/gate-review-service.js +4 -1
- package/dist/backend/services/translation-service.js +49 -1
- package/dist/backend/services/user-question-reply.js +10 -0
- package/dist/backend/services/workflow-control-service.js +47 -1
- package/dist/backend/templates/harness/project-manager-agent.js +1 -1
- package/dist/backend/templates/harness/vcm-ask-user-skill.js +2 -2
- package/dist/backend/templates/harness/vcm-workflow-review-skill.js +1 -1
- package/dist-frontend/assets/index-BIFZPhDN.css +32 -0
- package/dist-frontend/assets/{index-ClaVB8jM.js → index-c2YwYw6n.js} +3 -3
- package/dist-frontend/index.html +2 -2
- package/package.json +1 -1
- package/dist-frontend/assets/index-Dc0_KSf4.css +0 -32
package/README.md
CHANGED
|
@@ -192,13 +192,18 @@ artifacts, Gate Review state, Round/Turn state, and the role rules remain
|
|
|
192
192
|
authoritative.
|
|
193
193
|
|
|
194
194
|
Whenever Project Manager asks the user a question, it first uses
|
|
195
|
-
`vcm-ask-user
|
|
196
|
-
|
|
195
|
+
`vcm-ask-user` with the complete question and necessary context. VCM records the
|
|
196
|
+
wait and cancels any pending role dispatch in one state update. Stop Hook then
|
|
197
|
+
ends the PM turn without route scanning and records the question as the official
|
|
198
|
+
reply. The existing Pause Alert displays it even when translation is off; the
|
|
199
|
+
translation panel and Gateway reuse that same reply instead of PM's separate
|
|
200
|
+
closing text. While waiting, new dispatches, Gate requests/retries, and workflow
|
|
201
|
+
completion are blocked; already-running roles may still return results. Only
|
|
197
202
|
a new direct user message clears the wait, and the next role dispatch requires
|
|
198
203
|
a fresh Workflow Review. PM treats text emitted while a Round continues as
|
|
199
204
|
intermediate output, not as delivered user communication. When the Round pauses
|
|
200
|
-
or completes, its Round Final Reply
|
|
201
|
-
question without relying on earlier PM output.
|
|
205
|
+
or completes, its Round Final Reply contains the complete user-facing result or
|
|
206
|
+
registered question without relying on earlier PM output.
|
|
202
207
|
|
|
203
208
|
Typical flow:
|
|
204
209
|
|
|
@@ -65,6 +65,12 @@ export function registerTaskRoutes(app, deps) {
|
|
|
65
65
|
taskSlug
|
|
66
66
|
}) ?? Promise.resolve(degradedWorkflowState(taskSlug))
|
|
67
67
|
]);
|
|
68
|
+
if (roundState.flowPause?.paused && deps.workflowControlService) {
|
|
69
|
+
const workflow = await deps.workflowControlService.getState(context);
|
|
70
|
+
const reply = workflow.userQuestionReplies?.find((item) => item.requestedAt === workflow.awaitingUser?.requestedAt);
|
|
71
|
+
if (reply)
|
|
72
|
+
roundState.flowPause = { ...roundState.flowPause, message: reply.question };
|
|
73
|
+
}
|
|
68
74
|
const displayedRoundState = await delayFlowPauseForTranslation(deps, {
|
|
69
75
|
repoRoot: project.repoRoot,
|
|
70
76
|
taskRepoRoot,
|
|
@@ -2,6 +2,7 @@ import { getRoleDefinition, isVcmRoleName, VCM_ROLE_NAMES } from "../../shared/c
|
|
|
2
2
|
import { VcmError } from "../errors.js";
|
|
3
3
|
import { submitTerminalInput } from "../runtime/terminal-submit.js";
|
|
4
4
|
import { getTaskRuntimeRepoRoot } from "../services/task-service.js";
|
|
5
|
+
import { findUserQuestionReply } from "../services/user-question-reply.js";
|
|
5
6
|
import { resolveExistingClaudeTranscriptPath } from "../services/claude-transcript-service.js";
|
|
6
7
|
import { isFinalTurnTextEvent, readTranscriptTextEvents } from "../services/claude-transcript-reply.js";
|
|
7
8
|
import { parseGatewayCommand } from "./gateway-command-parser.js";
|
|
@@ -1162,11 +1163,16 @@ export function createGatewayService(deps) {
|
|
|
1162
1163
|
|| settings.targetRole !== role) {
|
|
1163
1164
|
return;
|
|
1164
1165
|
}
|
|
1166
|
+
const questionReply = role === "project-manager" && deps.workflowControlService
|
|
1167
|
+
? await readRegisteredQuestionReply(input)
|
|
1168
|
+
: undefined;
|
|
1165
1169
|
const transcriptPath = resolveExistingClaudeTranscriptPath(input.session);
|
|
1166
|
-
if (!transcriptPath)
|
|
1170
|
+
if (!questionReply && !transcriptPath)
|
|
1167
1171
|
return;
|
|
1168
|
-
|
|
1169
|
-
|
|
1172
|
+
const events = questionReply ? [{
|
|
1173
|
+
id: questionReply.id, timestamp: questionReply.completedAt,
|
|
1174
|
+
text: questionReply.question, stopReason: "end_turn"
|
|
1175
|
+
}] : await readTranscriptTextEvents(transcriptPath);
|
|
1170
1176
|
const round = await waitForGatewayRoundFinal(input.repoRoot, input.taskSlug, role);
|
|
1171
1177
|
if (!round) {
|
|
1172
1178
|
return;
|
|
@@ -1285,6 +1291,15 @@ export function createGatewayService(deps) {
|
|
|
1285
1291
|
};
|
|
1286
1292
|
}
|
|
1287
1293
|
};
|
|
1294
|
+
async function readRegisteredQuestionReply(input) {
|
|
1295
|
+
const task = await deps.taskService.loadTask(input.repoRoot, input.taskSlug);
|
|
1296
|
+
const config = await deps.projectService.loadConfig(input.repoRoot);
|
|
1297
|
+
const state = await deps.workflowControlService.getState({
|
|
1298
|
+
taskRepoRoot: getTaskRuntimeRepoRoot(task), taskSlug: input.taskSlug,
|
|
1299
|
+
stateRoot: config.stateRoot, handoffDir: task.handoffDir
|
|
1300
|
+
});
|
|
1301
|
+
return findUserQuestionReply(state, input.session.id, input.session.lastTurnEndedAt ?? input.session.updatedAt);
|
|
1302
|
+
}
|
|
1288
1303
|
function getLatestRoleReply(settings) {
|
|
1289
1304
|
if (!settings.currentProjectId || !settings.currentTaskSlug) {
|
|
1290
1305
|
return undefined;
|
package/dist/backend/server.js
CHANGED
|
@@ -136,7 +136,8 @@ export async function createServer(deps, options = {}) {
|
|
|
136
136
|
roundService: deps.roundService,
|
|
137
137
|
taskWorkflowService: deps.taskWorkflowService,
|
|
138
138
|
architectRestartService: deps.architectRestartService,
|
|
139
|
-
translationService: deps.translationService
|
|
139
|
+
translationService: deps.translationService,
|
|
140
|
+
workflowControlService: deps.workflowControlService
|
|
140
141
|
});
|
|
141
142
|
registerSessionRoutes(app, {
|
|
142
143
|
projectService: deps.projectService,
|
|
@@ -353,6 +354,7 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
353
354
|
});
|
|
354
355
|
const transcripts = createClaudeTranscriptService();
|
|
355
356
|
const translationService = createTranslationService({
|
|
357
|
+
workflowControlService,
|
|
356
358
|
runtime,
|
|
357
359
|
sessionRegistry: registry,
|
|
358
360
|
transcripts,
|
|
@@ -388,6 +390,7 @@ export function createDefaultServerDeps(options = {}) {
|
|
|
388
390
|
roleContextRestartService
|
|
389
391
|
});
|
|
390
392
|
const gatewayService = createGatewayService({
|
|
393
|
+
workflowControlService,
|
|
391
394
|
fs,
|
|
392
395
|
settings: gatewaySettings,
|
|
393
396
|
audit: gatewayAudit,
|
|
@@ -352,7 +352,7 @@ export function createClaudeHookService(deps) {
|
|
|
352
352
|
dispatchedCount: 0,
|
|
353
353
|
stopDecision: {
|
|
354
354
|
behavior: "block",
|
|
355
|
-
reason: `Possible unregistered user question: ${JSON.stringify(question.slice(0, 600))}. If you are asking the user, use vcm-ask-user with the
|
|
355
|
+
reason: `Possible unregistered user question: ${JSON.stringify(question.slice(0, 600))}. If you are asking the user, use vcm-ask-user with the complete question and necessary context, then end the turn without advancing or routing the workflow. VCM delivers the registered question. If this only reports or quotes another question, clarify that context and end normally; do not invent a user question or register a false wait.`
|
|
356
356
|
}
|
|
357
357
|
};
|
|
358
358
|
}
|
|
@@ -507,6 +507,21 @@ export function createClaudeHookService(deps) {
|
|
|
507
507
|
if (!session) {
|
|
508
508
|
return completedHookResult(input, eventName);
|
|
509
509
|
}
|
|
510
|
+
if (eventName === "Stop" && input.role === "project-manager") {
|
|
511
|
+
const reply = await deps.workflowControlService?.completeUserQuestion?.(createWorkflowControlContext(context), {
|
|
512
|
+
sessionId: session.id,
|
|
513
|
+
startedAt: session.lastTurnStartedAt ?? session.updatedAt,
|
|
514
|
+
endedAt: session.lastTurnEndedAt ?? session.updatedAt
|
|
515
|
+
});
|
|
516
|
+
if (reply) {
|
|
517
|
+
await deps.translationService.recordUserQuestionReply?.({
|
|
518
|
+
repoRoot: context.project.repoRoot,
|
|
519
|
+
taskRepoRoot: context.taskRepoRoot,
|
|
520
|
+
taskSlug: context.taskSlug,
|
|
521
|
+
reply
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
510
525
|
const boundToTask = await isHookSessionBoundToTask(context, input.role);
|
|
511
526
|
if (boundToTask) {
|
|
512
527
|
await deps.roundService.recordClaudeHookEvent({
|
|
@@ -72,7 +72,10 @@ export function createGateReviewService(deps) {
|
|
|
72
72
|
}
|
|
73
73
|
async function requestReviewGateInternal(repoRoot, taskSlug, gate, options = {}) {
|
|
74
74
|
const context = await getContext(repoRoot, taskSlug);
|
|
75
|
-
|
|
75
|
+
const run = () => withGateStateLock(context, () => requestReviewGateLocked(context, gate, options));
|
|
76
|
+
return deps.workflowControlService?.runWhileNotAwaitingUser
|
|
77
|
+
? deps.workflowControlService.runWhileNotAwaitingUser(context, run)
|
|
78
|
+
: run();
|
|
76
79
|
}
|
|
77
80
|
async function requestReviewGateLocked(context, gate, options) {
|
|
78
81
|
let index = await loadIndex(deps.fs, context, now());
|
|
@@ -5,6 +5,7 @@ import { VcmError } from "../errors.js";
|
|
|
5
5
|
import { submitTerminalInput } from "../runtime/terminal-submit.js";
|
|
6
6
|
import { readLatestRoleTurnReply } from "./claude-transcript-reply.js";
|
|
7
7
|
import { createTranslationQueueRegistry } from "./translation-queue.js";
|
|
8
|
+
import { findUserQuestionReply, isPendingUserQuestion } from "./user-question-reply.js";
|
|
8
9
|
const TRANSLATION_SOURCE_LANGUAGE = "auto";
|
|
9
10
|
const TRANSLATION_INPUT_MODE = "review-before-send";
|
|
10
11
|
const TRANSLATION_CONTEXT_ENABLED = false;
|
|
@@ -25,6 +26,7 @@ export function createTranslationService(deps) {
|
|
|
25
26
|
async function loadConfig() {
|
|
26
27
|
const preferences = await deps.appSettings.getPreferences();
|
|
27
28
|
return {
|
|
29
|
+
enabled: preferences.translationEnabled,
|
|
28
30
|
sourceLanguage: TRANSLATION_SOURCE_LANGUAGE,
|
|
29
31
|
targetLanguage: preferences.translationTargetLanguage,
|
|
30
32
|
inputMode: TRANSLATION_INPUT_MODE,
|
|
@@ -239,6 +241,22 @@ export function createTranslationService(deps) {
|
|
|
239
241
|
return;
|
|
240
242
|
}
|
|
241
243
|
const config = await loadConfig();
|
|
244
|
+
if (state.role === "project-manager" && event.kind === "text" && event.stopReason === "end_turn"
|
|
245
|
+
&& !event.isSidechain && state.repoRoot && state.taskSlug && deps.workflowControlService && deps.projectService) {
|
|
246
|
+
const projectConfig = await deps.projectService.loadConfig(state.baseRepoRoot ?? state.repoRoot);
|
|
247
|
+
const workflow = await deps.workflowControlService.getState({
|
|
248
|
+
taskRepoRoot: state.repoRoot, taskSlug: state.taskSlug,
|
|
249
|
+
stateRoot: projectConfig.stateRoot, handoffDir: projectConfig.handoffRoot
|
|
250
|
+
});
|
|
251
|
+
const reply = findUserQuestionReply(workflow, sessionId, event.timestamp);
|
|
252
|
+
if (reply) {
|
|
253
|
+
publishUserQuestionReply(reply, config);
|
|
254
|
+
state.seenTranscriptIds.add(event.id);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (isPendingUserQuestion(workflow, event.timestamp))
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
242
260
|
let displayed = false;
|
|
243
261
|
if (event.kind === "text") {
|
|
244
262
|
const shouldTranslate = shouldTranslateTextTranscriptEvent(state, event, config);
|
|
@@ -281,6 +299,20 @@ export function createTranslationService(deps) {
|
|
|
281
299
|
}
|
|
282
300
|
return true;
|
|
283
301
|
}
|
|
302
|
+
function publishUserQuestionReply(reply, config) {
|
|
303
|
+
const state = getState(reply.sessionId);
|
|
304
|
+
if (state.seenTranscriptIds.has(reply.id))
|
|
305
|
+
return;
|
|
306
|
+
const metadata = { transcriptStopReason: "end_turn", transcriptTimestamp: reply.completedAt };
|
|
307
|
+
// Claim before scheduling translation so Stop and transcript replay share one entry/job.
|
|
308
|
+
state.seenTranscriptIds.add(reply.id);
|
|
309
|
+
if (config.enabled === false || config.outputMode === "round-final") {
|
|
310
|
+
pushPreservedProseEntry(reply.sessionId, reply.id, reply.question, config, metadata);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
processClaudeOutputText(reply.sessionId, reply.question, config, reply.id, { flushImmediately: true, metadata });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
284
316
|
function processClaudeOutputText(sessionId, rawText, config, entryId, options = {}) {
|
|
285
317
|
return startClaudeOutputTranslation(sessionId, rawText, config, {
|
|
286
318
|
entryId,
|
|
@@ -647,6 +679,12 @@ export function createTranslationService(deps) {
|
|
|
647
679
|
return state;
|
|
648
680
|
}
|
|
649
681
|
return {
|
|
682
|
+
async recordUserQuestionReply(input) {
|
|
683
|
+
await prepareCache({ repoRoot: input.taskRepoRoot, baseRepoRoot: input.repoRoot,
|
|
684
|
+
taskSlug: input.taskSlug, role: "project-manager", sessionId: input.reply.sessionId });
|
|
685
|
+
publishUserQuestionReply(input.reply, await loadConfig());
|
|
686
|
+
await persistEvents(getState(input.reply.sessionId));
|
|
687
|
+
},
|
|
650
688
|
async startSession(input) {
|
|
651
689
|
const roleSession = await deps.sessionService.getRoleSession(input.repoRoot, input.taskSlug, input.role);
|
|
652
690
|
if (!roleSession || roleSession.status !== "running") {
|
|
@@ -720,6 +758,16 @@ export function createTranslationService(deps) {
|
|
|
720
758
|
status: state.status
|
|
721
759
|
});
|
|
722
760
|
}
|
|
761
|
+
if (deps.workflowControlService && deps.projectService) {
|
|
762
|
+
const projectConfig = await deps.projectService.loadConfig(input.repoRoot);
|
|
763
|
+
const workflow = await deps.workflowControlService.getState({ ...input,
|
|
764
|
+
stateRoot: projectConfig.stateRoot, handoffDir: projectConfig.handoffRoot });
|
|
765
|
+
for (const reply of workflow.userQuestionReplies ?? []) {
|
|
766
|
+
if (feedSessions.some((session) => session.role === "project-manager" && session.sessionId === reply.sessionId)) {
|
|
767
|
+
publishUserQuestionReply(reply, config);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
723
771
|
if (config.outputMode === "round-final") {
|
|
724
772
|
await translateRoundFinalReplyIfReady(input, config);
|
|
725
773
|
}
|
|
@@ -1173,7 +1221,7 @@ export function createTranslationService(deps) {
|
|
|
1173
1221
|
}
|
|
1174
1222
|
};
|
|
1175
1223
|
async function translateRoundFinalReplyIfReady(input, config) {
|
|
1176
|
-
if (!deps.roundService || !deps.projectService) {
|
|
1224
|
+
if (config.enabled === false || !deps.roundService || !deps.projectService) {
|
|
1177
1225
|
return;
|
|
1178
1226
|
}
|
|
1179
1227
|
const projectConfig = await deps.projectService.loadConfig(input.repoRoot);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Use the recorded turn window, not the current wait flag: replies must survive
|
|
2
|
+
// the user's answer and transcript replay without becoming a second message.
|
|
3
|
+
export function findUserQuestionReply(state, sessionId, timestamp) {
|
|
4
|
+
return state.userQuestionReplies?.slice().reverse().find((reply) => reply.sessionId === sessionId
|
|
5
|
+
&& timestamp >= reply.turnStartedAt && timestamp <= reply.completedAt);
|
|
6
|
+
}
|
|
7
|
+
export function isPendingUserQuestion(state, timestamp) {
|
|
8
|
+
return Boolean(state.awaitingUser && timestamp >= state.awaitingUser.requestedAt
|
|
9
|
+
&& !state.userQuestionReplies?.some((reply) => reply.requestedAt === state.awaitingUser?.requestedAt));
|
|
10
|
+
}
|
|
@@ -317,6 +317,8 @@ export function createWorkflowControlService(deps) {
|
|
|
317
317
|
},
|
|
318
318
|
requestUserInput,
|
|
319
319
|
resolveUserInput,
|
|
320
|
+
completeUserQuestion,
|
|
321
|
+
runWhileNotAwaitingUser,
|
|
320
322
|
submitProgress,
|
|
321
323
|
assertDocsArtifactAllowed,
|
|
322
324
|
assertRouteAuthorized,
|
|
@@ -409,6 +411,37 @@ export function createWorkflowControlService(deps) {
|
|
|
409
411
|
return next;
|
|
410
412
|
});
|
|
411
413
|
}
|
|
414
|
+
async function runWhileNotAwaitingUser(input, run) {
|
|
415
|
+
return withLock(statePath(input), async () => {
|
|
416
|
+
const state = await getState(input);
|
|
417
|
+
failWhileAwaitingUser(state);
|
|
418
|
+
return run();
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
async function completeUserQuestion(input, turn) {
|
|
422
|
+
return withLock(statePath(input), async () => {
|
|
423
|
+
const state = await getState(input);
|
|
424
|
+
failOnStateWarnings(state);
|
|
425
|
+
const question = state.awaitingUser;
|
|
426
|
+
if (!question)
|
|
427
|
+
return undefined;
|
|
428
|
+
const replies = state.userQuestionReplies ?? [];
|
|
429
|
+
const existing = replies.find((reply) => reply.requestedAt === question.requestedAt);
|
|
430
|
+
if (existing)
|
|
431
|
+
return existing.sessionId === turn.sessionId ? existing : undefined;
|
|
432
|
+
if (question.requestedAt > turn.endedAt)
|
|
433
|
+
return undefined;
|
|
434
|
+
const reply = {
|
|
435
|
+
...question,
|
|
436
|
+
id: `user-question:${turn.sessionId}:${question.requestedAt}`,
|
|
437
|
+
sessionId: turn.sessionId,
|
|
438
|
+
turnStartedAt: turn.startedAt,
|
|
439
|
+
completedAt: turn.endedAt
|
|
440
|
+
};
|
|
441
|
+
await saveState(input, { ...state, userQuestionReplies: [...replies, reply], updatedAt: now() });
|
|
442
|
+
return reply;
|
|
443
|
+
});
|
|
444
|
+
}
|
|
412
445
|
async function saveState(input, state) {
|
|
413
446
|
await deps.fs.writeJsonAtomic(statePath(input), state);
|
|
414
447
|
}
|
|
@@ -1343,18 +1376,24 @@ function normalizeState(value, taskSlug, timestamp) {
|
|
|
1343
1376
|
const awaitingUser = value.awaitingUser === undefined || value.awaitingUser === null
|
|
1344
1377
|
? null
|
|
1345
1378
|
: isAwaitingUser(value.awaitingUser) ? value.awaitingUser : undefined;
|
|
1379
|
+
const validQuestionReplies = value.userQuestionReplies === undefined
|
|
1380
|
+
|| (Array.isArray(value.userQuestionReplies) && value.userQuestionReplies.every(isUserQuestionReply));
|
|
1346
1381
|
if (pendingDispatch === undefined
|
|
1347
1382
|
|| activeDispatch === undefined
|
|
1348
1383
|
|| flowRun === undefined
|
|
1349
1384
|
|| userAuthorizations === undefined
|
|
1350
1385
|
|| userApprovedFollowUps === undefined
|
|
1351
|
-
|| awaitingUser === undefined
|
|
1386
|
+
|| awaitingUser === undefined
|
|
1387
|
+
|| !validQuestionReplies) {
|
|
1352
1388
|
return { ...emptyState(taskSlug, timestamp), warnings: ["Workflow control state has an unsupported shape."] };
|
|
1353
1389
|
}
|
|
1354
1390
|
return {
|
|
1355
1391
|
version: 1,
|
|
1356
1392
|
taskSlug,
|
|
1357
1393
|
awaitingUser,
|
|
1394
|
+
...(Array.isArray(value.userQuestionReplies) ? {
|
|
1395
|
+
userQuestionReplies: value.userQuestionReplies
|
|
1396
|
+
} : {}),
|
|
1358
1397
|
pendingDispatch,
|
|
1359
1398
|
activeDispatch,
|
|
1360
1399
|
flowRun,
|
|
@@ -1364,6 +1403,13 @@ function normalizeState(value, taskSlug, timestamp) {
|
|
|
1364
1403
|
updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : timestamp
|
|
1365
1404
|
};
|
|
1366
1405
|
}
|
|
1406
|
+
function isUserQuestionReply(value) {
|
|
1407
|
+
if (!value || typeof value !== "object")
|
|
1408
|
+
return false;
|
|
1409
|
+
const reply = value;
|
|
1410
|
+
return [reply.id, reply.sessionId, reply.question, reply.requestedAt, reply.turnStartedAt, reply.completedAt]
|
|
1411
|
+
.every((field) => typeof field === "string" && field.length > 0);
|
|
1412
|
+
}
|
|
1367
1413
|
function emptyState(taskSlug, timestamp) {
|
|
1368
1414
|
return {
|
|
1369
1415
|
version: 1,
|
|
@@ -21,7 +21,7 @@ ${renderRoleMemoryRules("project-manager")}
|
|
|
21
21
|
- Assistant text emitted before a tool call or role dispatch while the current Round continues is not user communication. Do not use intermediate text to deliver status, findings, decisions, questions, or required actions to the user.
|
|
22
22
|
- The user is informed only by PM's Round Final Reply when the Round pauses for user input or reaches a terminal result.
|
|
23
23
|
- The Round Final Reply must be self-contained. Restate every result, blocker, decision, risk, and required user action needed to understand the current state. Never rely on earlier PM text in the same Round.
|
|
24
|
-
- When asking the user a question,
|
|
24
|
+
- When asking the user a question, submit the complete user-facing question and its necessary context through \`vcm-ask-user\`, then end the turn. VCM delivers the registered question as the Round Final Reply; do not rely on a separate final message to supply missing context.
|
|
25
25
|
- Explain task status, blockers, role results, and decisions in user-facing language.
|
|
26
26
|
- Prefer plain logic over code-level detail: describe what changed, why it matters, what risk remains, and what decision is needed.
|
|
27
27
|
- Exclude irrelevant implementation detail, but retain the technical facts needed to explain the cause, evidence, impact, and unresolved state. Plain language means translating technical detail, not deleting it.
|
|
@@ -5,13 +5,13 @@ Use this skill whenever Project Manager asks the user a question.
|
|
|
5
5
|
|
|
6
6
|
## Ask And Wait
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Submit the complete user-facing question, including the context needed to answer:
|
|
9
9
|
|
|
10
10
|
\`\`\`bash
|
|
11
11
|
.ai/tools/vcm-ask-user --question "<exact question>"
|
|
12
12
|
\`\`\`
|
|
13
13
|
|
|
14
|
-
After the tool returns \`awaiting_user\`,
|
|
14
|
+
After the tool returns \`awaiting_user\`, end the turn. VCM delivers the registered question as the Round Final Reply through the existing display, translation, and Gateway paths. Do not rely on a separate final message to supply missing context. Do not request Workflow Review, write a route message, run a Gate, or advance the workflow in the same turn.
|
|
15
15
|
|
|
16
16
|
Every question pauses the workflow. PM may defer a question by not asking it; once PM asks, only a new direct user message resumes the workflow. The previous workflow approval is canceled, so request a fresh approval before the next dispatch.
|
|
17
17
|
`;
|
|
@@ -52,7 +52,7 @@ Only the user's explicit instruction may authorize a rejected transition.
|
|
|
52
52
|
|
|
53
53
|
If the current user instruction already explicitly authorizes the exact rejected transition, reuse that instruction verbatim as \`Authorization Text\`. Do not ask the user to confirm it again.
|
|
54
54
|
|
|
55
|
-
If no such instruction exists, use \`vcm-ask-user\` with the
|
|
55
|
+
If no such instruction exists, use \`vcm-ask-user\` with the complete authorization question and end the turn.
|
|
56
56
|
|
|
57
57
|
Resubmit the unchanged transition with:
|
|
58
58
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
+
* https://github.com/chjj/term.js
|
|
5
|
+
* @license MIT
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
* Originally forked from (with the author's permission):
|
|
26
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
+
* http://bellard.org/jslinux/
|
|
28
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
+
* The original design remains. The terminal itself
|
|
30
|
+
* has been extended to include xterm CSI codes, among
|
|
31
|
+
* other features.
|
|
32
|
+
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{color-scheme:light;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;background:#f5f2ea;color:#1c2024;line-height:1.5}html,body,#root{height:100%}*{box-sizing:border-box}body{margin:0;min-width:320px;min-height:100vh;background:#f5f2ea}button,input,select,textarea{font:inherit}button{border:1px solid #9ba6ad;background:#f8f7f2;color:#1d252b;border-radius:6px;min-height:34px;padding:6px 10px;cursor:pointer}button:hover:not(:disabled){background:#eef4f2;border-color:#607d74}button:disabled{cursor:not-allowed;opacity:.55}.danger-button{border-color:#b84a45;background:#fff1ee;color:#8d211d;font-weight:750}.danger-button:hover:not(:disabled){border-color:#8d211d;background:#ffe2dc}input,select,textarea:not(.xterm-helper-textarea){width:100%;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:8px 10px}textarea:not(.xterm-helper-textarea){min-height:240px;resize:vertical;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px}h1,h2,p{margin-top:0}h1{margin-bottom:4px;font-size:26px;line-height:1.15}h2{margin-bottom:10px;font-size:14px;letter-spacing:0}.app-shell{display:grid;grid-template-columns:minmax(280px,320px) minmax(0,1fr);height:100vh;min-height:0;overflow:hidden}.app-shell.is-sidebar-collapsed{grid-template-columns:46px minmax(0,1fr)}.app-sidebar{position:relative;display:flex;flex-direction:column;min-width:0;border-right:1px solid #d3c9b8;background:#fbfaf6;padding:14px;overflow:auto}.app-shell.is-sidebar-collapsed .app-sidebar{overflow:hidden;padding:8px}.sidebar-toggle{position:absolute;top:10px;right:10px;z-index:2;display:grid;place-items:center;width:28px;min-height:28px;padding:0;background:#fffdf8}.sidebar-toggle:before{width:8px;height:8px;border-color:currentColor;border-style:solid;border-width:0 2px 2px 0;content:"";transform:translate(2px) rotate(135deg)}.app-shell.is-sidebar-collapsed .sidebar-toggle{left:9px;right:auto}.app-shell.is-sidebar-collapsed .sidebar-toggle:before{transform:translate(-2px) rotate(-45deg)}.sidebar-content{display:flex;flex:1;min-width:0;min-height:0}.project-dashboard{display:flex;flex:1;flex-direction:column;width:100%;min-height:100%}.app-shell.is-sidebar-collapsed .sidebar-content{width:0;opacity:0;pointer-events:none}.app-main{min-width:0;height:100%;padding:14px 16px;overflow:auto}.brand-header{display:flex;gap:12px;align-items:baseline;margin-bottom:10px;padding-right:34px}.brand-header strong{font-size:18px}.brand-header span,.muted{color:#667071;font-size:13px}.sidebar-section{margin-bottom:8px;border:1px solid #e0d6c7;border-radius:8px;background:#fffdfa;overflow:hidden}.sidebar-section-toggle{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;min-height:34px;border:0;border-radius:0;background:transparent;color:#1c2024;font-size:13px;font-weight:750;text-align:left}.sidebar-section-toggle:hover{background:#f5f1e8}.sidebar-section-toggle[aria-expanded=true]{border-bottom:1px solid #ece5d9}.sidebar-section-chevron{width:8px;height:8px;border-color:currentColor;border-style:solid;border-width:0 2px 2px 0;transform:rotate(45deg)}.sidebar-section-toggle[aria-expanded=true] .sidebar-section-chevron{transform:rotate(-135deg)}.sidebar-section-content{padding:8px}.repo-connect,.project-summary,.repository-panel,.gateway-panel,.harness-panel,.task-create{margin:0}.repository-panel{display:grid;gap:10px}.repository-panel .project-summary{padding-top:10px;border-top:1px solid #ece5d9}.inline-form{display:grid;grid-template-columns:minmax(0,1fr);gap:8px}.inline-form.has-recent-paths{grid-template-columns:minmax(0,1fr) auto}.inline-form>input{grid-column:1 / -1}.inline-form>button{justify-self:end}.inline-form.has-recent-paths>button{justify-self:auto}.repo-recent-select{min-width:0;max-width:none}.project-summary dl{display:grid;gap:8px;margin:0}.project-summary div{min-width:0}.project-summary dt{color:#6c6255;font-size:12px}.project-summary dd{margin:0;overflow-wrap:anywhere;font-size:13px}.connected-repo-actions{display:flex;align-items:center;gap:8px;margin-top:10px}.connected-repo-actions button{min-height:30px}.gateway-actions{display:grid;gap:8px;margin-top:10px}.gateway-actions button{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;text-align:left}.gateway-actions .settings-toggle.is-active{border-color:#2f6f73;background:#e8f1ef}.gateway-panel .compact-field,.gateway-lark-settings{display:grid;gap:6px}.gateway-panel .compact-field{font-size:12px;color:#6c6255}.gateway-panel .compact-field input,.gateway-panel .compact-field select{width:100%;min-width:0}.gateway-lark-settings{margin-top:10px}.gateway-lark-settings button{width:100%}.gateway-qr{display:grid;gap:6px;margin-top:10px}.gateway-qr img{width:100%;max-width:180px;border:1px solid #d3c9b8;border-radius:6px;background:#fff;padding:6px}.gateway-qr code{overflow-wrap:anywhere;font-size:11px}.warnings{border:1px solid #c87b54;background:#fff4ed;color:#6f3218;border-radius:6px;padding:10px 12px}.success-banner{border:1px solid #2ea043;background:#eefbf0;color:#165c26;border-radius:6px;padding:10px 12px}.flow-pause-alert-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:100;display:grid;place-items:center;background:#1f242b85;padding:20px}.flow-pause-alert{display:grid;gap:12px;width:min(460px,100%);max-height:calc(100dvh - 40px);overflow-y:auto;border:1px solid #2f6f73;border-radius:8px;background:#e8f4f2;color:#123f43;box-shadow:0 28px 72px #1f242b47;padding:22px}.flow-pause-alert-kicker{margin:0;color:#2f6f73;font-size:12px;font-weight:700;text-transform:uppercase}.flow-pause-alert h2{margin:0;font-size:24px;line-height:1.15}.flow-pause-alert p{margin:0;font-size:14px;line-height:1.5;overflow-wrap:anywhere}#flow-pause-alert-body{white-space:pre-wrap}.flow-pause-alert-hint{color:#49666a}.flow-pause-alert button{justify-self:end;min-width:110px;border:1px solid #2f6f73;background:#2f6f73;color:#fffdf8}.flow-pause-alert button:hover{background:#245c60}.ui-error-center{position:fixed;top:14px;right:14px;z-index:95;display:grid;gap:8px;width:min(520px,calc(100vw - 28px));max-height:min(58vh,540px);border:1px solid #c87b54;border-radius:8px;background:#fff4ed;color:#6f3218;box-shadow:0 18px 50px #1f242b33;padding:10px}.ui-error-center-header{display:flex;align-items:center;justify-content:space-between;gap:10px}.ui-error-center-header h2{margin:0;font-size:14px;line-height:1.2}.ui-error-center-header p{margin:2px 0 0;color:#8b4a28;font-size:11px;font-weight:700}.ui-error-center button{border-color:#c87b54;color:#6f3218;min-height:28px;padding:4px 8px;font-size:12px}.ui-error-list{display:grid;gap:8px;margin:0;padding:0;overflow:auto;list-style:none}.ui-error-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:start;border-top:1px solid rgba(200,123,84,.32);padding-top:8px}.ui-error-list p{margin:0;font-size:12px;font-weight:700;line-height:1.4;overflow-wrap:anywhere}.ui-error-list span{display:block;margin-top:4px;color:#8b4a28;font-size:11px;font-weight:700}.role-recovery-toast{position:fixed;left:50%;bottom:18px;z-index:90;display:flex;align-items:center;gap:12px;max-width:calc(100vw - 32px);border:1px solid #b7791f;border-radius:8px;background:#fff8e6;color:#5f3b00;box-shadow:0 14px 42px #1f242b2e;padding:10px 12px;transform:translate(-50%)}.role-recovery-toast span{font-size:13px;font-weight:700;white-space:nowrap}.role-recovery-toast button{border-color:#b7791f;color:#5f3b00}.warnings{margin:12px 0 0;padding-left:26px;font-size:13px}.harness-panel{display:grid;gap:10px}.harness-stage{display:grid;gap:8px}.harness-panel-header{display:flex;justify-content:space-between;gap:8px;align-items:center}.harness-panel-header h2,.harness-panel-header p,.harness-result p{margin-bottom:0}.harness-actions{display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.harness-review-diff-button{width:100%}.harness-file-list-title{margin:0;font-size:12px}.harness-file-list{display:grid;gap:6px;margin:0;padding:0;list-style:none}.harness-file-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;border:1px solid #ece5d9;border-radius:6px;padding:6px 8px;background:#fffdfa}.harness-file-list span{overflow:hidden;font-size:12px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.harness-changes,.harness-result{border:1px solid #e0d6c7;border-radius:6px;padding:8px;background:#f8f7f2;font-size:12px}.harness-changes h3{margin:0 0 4px;font-size:12px}.harness-changes ul,.harness-result ul{margin:0;padding-left:18px}.harness-bootstrap-modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);background:#1f242b94;padding:14px}.harness-bootstrap-modal-surface{min-width:0;min-height:0;display:grid;grid-template-rows:auto auto minmax(0,1fr);gap:10px;border:1px solid #b9b0a1;border-radius:8px;background:#fffdf8;box-shadow:0 22px 64px #1f242b47;padding:10px}.harness-bootstrap-modal-header{display:flex;gap:12px;align-items:center;justify-content:space-between;min-width:0}.harness-bootstrap-modal-header p{max-width:min(720px,70vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.harness-bootstrap-modal-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}.harness-bootstrap-controls{display:grid;grid-template-columns:minmax(180px,.8fr) minmax(180px,.9fr) minmax(140px,.7fr) auto;gap:8px;align-items:end;min-width:0}.harness-bootstrap-controls label{display:grid;gap:4px;min-width:0}.harness-bootstrap-controls label span{color:#5f6a6c;font-size:11px;font-weight:650}.harness-bootstrap-controls select{width:100%;min-width:0;min-height:30px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:3px 8px;font-size:12px}.harness-bootstrap-control-actions{display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.harness-bootstrap-control-actions button{min-height:30px;padding:4px 9px;font-size:12px}.harness-bootstrap-terminal{min-width:0;min-height:0;display:grid}.task-create form{display:grid;gap:8px}.task-panel{display:grid;gap:10px}.task-panel-actions{display:grid;gap:8px;padding-top:10px;border-top:1px solid #ece5d9}.task-panel-actions .danger-button{width:100%;text-align:center}.task-create-preview{display:grid;gap:2px;border:1px solid #e0d6c7;border-radius:6px;background:#f8f7f2;padding:6px 8px}.task-create-option{display:flex;align-items:center;gap:8px;color:#1f242b;font-size:13px;font-weight:700}.task-create-option input{width:16px;height:16px;margin:0}.task-create-preview span{color:#255f3d;font-size:12px;font-weight:700}.task-create-preview small{overflow:hidden;color:#687273;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.task-nav{display:grid;gap:8px}.task-nav-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;text-align:left}.task-nav-item.is-active,.role-tab.is-active{border-color:#2f6f73;background:#e8f1ef}.sidebar-settings{display:grid;gap:8px}.gate-review-setting{display:grid;gap:6px}.sidebar-settings button{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;text-align:left}.sidebar-settings .settings-toggle.is-active{border-color:#2f6f73;background:#e8f1ef}.switch-control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:center;min-height:34px;border:1px solid #b9c0c4;border-radius:7px;background:#fffefa;color:#3f474a;padding:5px 8px;text-align:left}.switch-control:hover:not(:disabled){border-color:#2f7e84;background:#f2faf8}.switch-control:disabled{opacity:.6;cursor:not-allowed}.switch-control-label{min-width:0;overflow:hidden;font-weight:700;text-overflow:ellipsis;white-space:nowrap}.switch-control-track{position:relative;justify-self:end;width:38px;height:20px;border-radius:999px;background:#b9c0c4;transition:background .16s ease}.switch-control-thumb{position:absolute;top:3px;left:3px;width:14px;height:14px;border-radius:999px;background:#fffefa;box-shadow:0 1px 3px #12161838;transition:transform .16s ease}.switch-control.is-on{border-color:#2f7e84;background:#e8f4f2;color:#145e64}.switch-control.is-on .switch-control-track{background:#2f7e84}.switch-control.is-on .switch-control-thumb{transform:translate(18px)}.sidebar-settings .switch-control,.gateway-actions .switch-control{width:100%}.sidebar-settings .theme-mode-toggle span:last-child{font-weight:750}.settings-select-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;font-size:13px;color:#5f6a6c}.settings-select-row select{min-height:30px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326}.codex-bridge-settings{display:grid;gap:8px;border-top:1px solid #d4cec3;padding-top:8px}.codex-bridge-api-key-form{display:grid;gap:5px;color:#5f6a6c;font-size:13px}.codex-bridge-api-key-form>div,.codex-bridge-actions{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px}.codex-bridge-api-key-form input{min-width:0;min-height:30px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:4px 7px}.codex-bridge-actions button{display:block;text-align:center}.settings-status-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;min-height:30px;border:1px solid #d4cec3;border-radius:6px;background:#fffdf8;padding:6px 10px;color:#5f6a6c;font-size:13px}.settings-status-row strong{color:#202326;font-size:12px}.settings-help-text{margin:0;color:#7b5e00;font-size:12px;line-height:1.35}.task-status-dock{display:grid;gap:10px;margin-top:auto;border-top:1px solid #d3c9b8;padding-top:10px}.task-status-dock-title,.current-round-title{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center}.task-status-dock-title strong{overflow:hidden;font-size:13px;line-height:1.25;text-overflow:ellipsis;white-space:nowrap}.task-status-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;margin:0}.task-status-stats div,.current-round-status{min-width:0;border:1px solid #e0d6c7;border-radius:6px;background:#fffdfa}.task-status-stats div{padding:6px 7px}.task-status-stats dt{color:#6c6255;font-size:10px;font-weight:700;text-transform:uppercase}.task-status-stats dd{margin:0;overflow:hidden;color:#1f242b;font-size:12px;font-weight:750;text-overflow:ellipsis;white-space:nowrap}.current-round-status{display:grid;gap:8px;padding:8px}.current-round-title span:first-child{color:#3a4647;font-size:12px;font-weight:750}.workspace-header{display:grid;grid-template-columns:minmax(120px,max-content) minmax(0,1fr);gap:10px;align-items:center;margin-bottom:6px}.workspace-title-line{display:grid;gap:2px;max-width:260px;min-width:0}.workspace-title-line h1{margin-bottom:0;overflow:hidden;font-size:18px;line-height:1.15;text-overflow:ellipsis;white-space:nowrap}.workspace-workflow-state{display:flex;gap:5px;min-width:0;color:#66717c;font-size:10px;line-height:1.2}.workspace-workflow-state span,.workspace-workflow-state strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.workspace-workflow-state strong{color:#34434b;font-weight:700}.workspace-workflow-state strong:before{content:"/";margin-right:5px;color:#8b959d}.role-tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:6px;margin-bottom:8px;min-width:0}.workspace-header .role-tabs{margin-bottom:0}.role-tab{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;align-items:center;min-height:30px;padding:4px 8px;text-align:left}.workspace-grid{display:grid;grid-template-columns:minmax(0,1fr);flex:1;gap:10px;align-items:stretch;min-height:0}.workspace-main{min-width:0;min-height:0;display:flex;flex-direction:column;gap:8px}.role-console-stack{min-width:0;min-height:0;flex:1;display:flex;flex-direction:column}.role-console-panel{min-width:0;min-height:0;flex:1;display:none}.role-console-panel.is-active{display:flex;flex-direction:column}.session-console,.message-panel,.event-log,.empty-workspace{border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:10px}.task-workspace{display:flex;flex-direction:column;gap:8px;height:100%;min-height:0}.workspace-runtime-warning{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:10px;align-items:center;border:1px solid #c87b54;border-radius:6px;background:#fff4ed;color:#6f3218;padding:8px 12px;font-size:13px}.workspace-runtime-warning span{min-width:0;overflow-wrap:anywhere}.workspace-runtime-warning code{font-size:11px}.session-console{display:flex;flex-direction:column;flex:1;height:100%;min-height:0}.session-controls{display:flex;flex-wrap:nowrap;gap:6px;align-items:center;justify-content:flex-start;min-width:0;margin:0;overflow:hidden}.session-option-field{display:grid;grid-template-columns:auto minmax(120px,1fr);flex:0 1 210px;gap:5px;align-items:center;min-width:0}.permission-mode-field{flex-basis:250px}.model-field{flex-basis:220px}.effort-field{grid-template-columns:auto minmax(92px,1fr);flex-basis:150px}.session-option-field span{color:#5f6a6c;font-size:11px;font-weight:650;line-height:1;white-space:nowrap}.session-option-field small{display:block;color:#7b8587;font-size:11px;font-weight:500;line-height:1.2}.session-option-field select{width:100%;min-width:0;min-height:26px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:2px 7px;font-size:12px}.session-toolbar{display:flex;flex:0 0 auto;flex-wrap:nowrap;gap:5px;margin-left:auto;justify-content:flex-end}.session-toolbar button{min-height:26px;padding:2px 8px;font-size:12px}.session-harness-notice{display:inline-flex;flex:0 0 auto;gap:6px;align-items:center;min-width:0;border:1px solid #c4a34e;border-radius:6px;background:#fff8dd;color:#604e16;padding:2px 5px;font-size:11px}.session-harness-notice span:not(.status-badge){white-space:nowrap}.session-harness-notice button{min-height:24px;padding:1px 7px;font-size:11px}.session-console-body{display:grid;grid-template-columns:minmax(0,1fr);flex:1;min-width:0;min-height:0;height:100%}.session-console-body.has-translation{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;align-items:stretch}.terminal-pane,.translation-pane{display:grid;min-width:0;min-height:0;height:100%}.terminal-pane{grid-template-rows:auto minmax(0,1fr);gap:8px}.translation-pane{grid-template-rows:minmax(0,1fr)}.terminal-frame-shell,.terminal-empty{width:100%;height:100%;min-height:0;border-radius:6px;overflow:hidden;background:#111316}.terminal-frame-shell{position:relative}.terminal-frame{width:100%;height:100%;min-height:0}.terminal-copy-button{position:absolute;top:8px;right:8px;z-index:5;min-height:24px;border-color:#8b949e8c;border-radius:6px;background:#161b22db;color:#c9d1d9;padding:2px 8px;font-size:11px;font-weight:650;opacity:.72}.terminal-copy-button:hover:not(:disabled),.terminal-copy-button:focus-visible{background:#21262df5;border-color:#58a6ff;color:#f0f6fc;opacity:1}.terminal-copy-button.is-copied{border-color:#2ea043;color:#b7f7c4}.terminal-copy-button.is-ready{border-color:#58a6ff;color:#c9e4ff}.terminal-copy-button.is-empty,.terminal-copy-button.is-failed{border-color:#d29922;color:#ffe8a3}.terminal-empty{display:grid;place-items:center;align-content:center;gap:8px;color:#d6d0c6;border:1px solid #292d31}.translation-panel{display:flex;flex-direction:column;gap:8px;height:100%;min-height:0;border:1px solid #292d31;border-radius:6px;background:#0d1117;color:#d6deeb;padding:8px;min-width:0;width:100%;overflow:hidden;font-family:Menlo,Monaco,Consolas,monospace}.file-translation-backdrop{background:#010409b8}.translation-file-browser-backdrop{z-index:24}.file-translation-modal{display:grid;grid-template-rows:auto auto minmax(0,1fr);gap:12px;width:95vw;height:95vh;min-height:0;min-width:0;overflow:hidden;border:1px solid #30363d;border-radius:8px;background:#0d1117;color:#d6deeb;padding:14px;box-shadow:0 28px 80px #0000008f;font-family:Menlo,Monaco,Consolas,monospace}.file-translation-header{display:flex;flex-wrap:wrap;gap:12px;align-items:center;justify-content:space-between;min-width:0}.file-translation-header h2,.file-translation-header p{margin-bottom:0}.file-translation-header h2{font-size:18px}.file-translation-header p{color:#8b949e;font-size:12px}.file-translation-toolbar{display:flex;flex-wrap:wrap;gap:6px}.file-translation-toolbar button{border-color:#3a4149;background:#161b22;color:#d6deeb;min-height:26px;padding:2px 8px;font-size:12px}.file-translation-layout{display:grid;grid-template-columns:minmax(220px,300px) minmax(0,1fr);gap:10px;min-height:0;min-width:0;overflow:hidden}.file-translation-list,.file-translation-preview{min-height:0;min-width:0;overflow:auto;border:1px solid #292d31;border-radius:6px;background:#0b0f14;padding:8px}.file-translation-list{display:grid;align-content:start;gap:6px}.file-translation-item{display:grid;gap:3px;width:100%;min-width:0;border:1px solid #292d31;border-radius:6px;background:#111820;color:#d6deeb;padding:6px;text-align:left}.file-translation-item strong,.file-translation-item span{overflow-wrap:anywhere}.file-translation-item span{color:#8b949e;font-size:11px}.file-translation-item.is-active{border-color:#58a6ff;background:#142033}.file-translation-preview header{display:flex;flex-wrap:wrap;justify-content:space-between;gap:6px;margin-bottom:8px;color:#8b949e;font-size:12px}.file-translation-preview{display:grid;grid-template-rows:auto minmax(0,1fr);overflow:hidden;padding:10px}.file-translation-preview .translation-markdown{min-height:0;overflow:auto;padding-right:4px;font-size:13px;line-height:1.62}.file-translation-preview>.muted{align-self:center;justify-self:center;text-align:center}.translation-file-browser-modal{display:grid;grid-template-rows:auto auto minmax(0,1fr);gap:12px;width:min(880px,calc(100vw - 32px));max-height:min(760px,calc(100vh - 48px));min-height:520px;min-width:0;overflow:hidden;border:1px solid #30363d;border-radius:8px;background:#0d1117;color:#d6deeb;padding:14px;box-shadow:0 24px 70px #0000007a;font-family:Menlo,Monaco,Consolas,monospace}.translation-file-browser-modal header,.translation-file-browser-controls,.translation-file-browser-nav,.translation-file-browser-search{display:flex;flex-wrap:wrap;gap:8px;align-items:center;min-width:0}.translation-file-browser-modal header{justify-content:space-between}.translation-file-browser-modal h2,.translation-file-browser-modal h3,.translation-file-browser-modal p{margin-bottom:0}.translation-file-browser-modal h2{font-size:17px}.translation-file-browser-modal h3{color:#8b949e;font-size:12px;font-weight:600}.translation-file-browser-modal p{color:#8b949e;font-size:12px;overflow-wrap:anywhere}.translation-file-browser-controls{justify-content:space-between}.translation-file-browser-search{flex:1 1 320px;justify-content:flex-end}.translation-file-browser-search input{flex:1 1 180px;min-width:0}.translation-file-browser-modal button,.translation-file-browser-modal input{border:1px solid #3a4149;border-radius:6px;background:#111820;color:#d6deeb;min-height:30px;padding:4px 8px;font:inherit;font-size:12px}.translation-file-browser-modal button:hover:not(:disabled){border-color:#58a6ff;background:#162235}.translation-file-browser-layout{display:grid;grid-template-columns:minmax(260px,1fr) minmax(220px,.42fr);gap:10px;min-height:0;min-width:0;overflow:hidden}.translation-file-browser-list,.translation-file-browser-selection{min-height:0;min-width:0;overflow:auto;border:1px solid #292d31;border-radius:6px;background:#0b0f14;padding:10px}.translation-file-browser-group{display:grid;align-content:start;gap:6px;margin-bottom:12px}.translation-file-browser-entry{display:grid;grid-template-columns:38px minmax(0,1fr);gap:3px 8px;width:100%;min-width:0;text-align:left}.translation-file-browser-entry span{grid-row:span 2;align-self:center;color:#8b949e;font-size:11px}.translation-file-browser-entry strong,.translation-file-browser-entry small{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.translation-file-browser-entry small{color:#8b949e}.translation-file-browser-entry.is-selected{border-color:#58a6ff;background:#142033}.translation-file-browser-selection{display:grid;align-content:start;gap:12px}.translation-file-browser-selection label{display:grid;gap:5px}.translation-file-browser-selection span{color:#8b949e;font-size:12px}.translation-file-browser-selection input{width:100%;min-width:0}.translation-panel-header{display:grid;flex:0 0 auto;gap:3px}.translation-panel-titlebar,.translation-panel-actions,.translation-status-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:space-between}.translation-panel-header h2,.translation-panel-header p{margin-bottom:0}.translation-panel-titlebar h2{font-size:16px}.translation-panel-header p,.translation-composer span{color:#8b949e;font-size:12px}.translation-panel-actions button{border-color:#3a4149;background:#161b22;color:#d6deeb;min-height:26px;padding:2px 8px;font-size:12px}.translation-panel-actions button:hover:not(:disabled),.translation-composer-actions button:hover:not(:disabled){border-color:#58a6ff;background:#1f2937}.translation-panel-actions{justify-content:flex-end}.translation-entry-list{display:grid;flex:1 1 auto;align-content:start;gap:8px;min-height:0;min-width:0;overflow-x:hidden;overflow-y:auto;scrollbar-color:#4b5563 #0d1117}.translation-entry{border:0;border-radius:0;background:transparent;min-width:0;max-width:100%;padding:0}.translation-conversation-boundary{display:grid;grid-template-columns:minmax(18px,1fr) auto auto auto minmax(18px,1fr);gap:8px;align-items:center;color:#8b949e;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.4;white-space:nowrap}.translation-boundary-dash{min-width:0;border-top:1px dashed #3a4149}.translation-entry.is-user-input{border-top:4px solid #3a4149;margin-top:14px;padding-top:14px}.translation-entry.is-user-input:first-child{margin-top:0}.translation-entry pre{box-sizing:border-box;margin:0;max-height:none;max-width:100%;min-width:0;overflow:visible;white-space:pre-wrap;overflow-wrap:anywhere;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.45;color:#d6deeb}.translation-markdown{max-width:100%;min-width:0;color:#d6deeb;font-size:12px;line-height:1.55;overflow-wrap:anywhere}.translation-markdown>:first-child{margin-top:0}.translation-markdown>:last-child{margin-bottom:0}.translation-markdown p,.translation-markdown ul,.translation-markdown ol,.translation-markdown blockquote,.translation-markdown pre,.translation-markdown table{margin:0 0 8px}.translation-markdown h1,.translation-markdown h2,.translation-markdown h3,.translation-markdown h4,.translation-markdown h5,.translation-markdown h6{margin:10px 0 6px;color:#f0f6fc;font-weight:700;line-height:1.25}.translation-markdown h1{font-size:17px}.translation-markdown h2{font-size:15px}.translation-markdown h3,.translation-markdown h4,.translation-markdown h5,.translation-markdown h6{font-size:13px}.translation-markdown ul,.translation-markdown ol{padding-left:22px}.translation-markdown li{margin:2px 0}.translation-markdown .task-list-item{list-style:none}.translation-markdown input[type=checkbox]{width:13px;height:13px;margin:0 6px 0 0;accent-color:#56d364}.translation-markdown blockquote{border-left:3px solid #3a4149;color:#b7c0ca;padding-left:10px}.translation-markdown a{color:#79c0ff}.translation-markdown code{border-radius:4px;background:#161b22;color:#f0f6fc;padding:1px 4px;font-family:Menlo,Monaco,Consolas,monospace;font-size:.95em}.translation-markdown pre{overflow-x:auto;border:1px solid #292d31;border-radius:6px;background:#111316;padding:8px;white-space:pre}.translation-markdown pre code{background:transparent;padding:0}.translation-markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse}.translation-markdown img{max-width:100%;border-radius:4px}.translation-markdown th,.translation-markdown td{border:1px solid #30363d;padding:4px 6px;text-align:left;vertical-align:top}.translation-markdown hr{border:0;border-top:1px solid #292d31;margin:10px 0}.translation-entry.is-tool-output pre{display:block;overflow:hidden;color:#7d8590;text-overflow:ellipsis;white-space:nowrap;width:100%}.translation-entry-note{margin:2px 0 0;color:#6e7681;font-size:10px;line-height:1.35}.translation-entry-note.is-error{color:#a3715f}.translation-manual-panel{display:grid;flex:0 0 auto;gap:6px;border-bottom:1px solid #292d31;padding-bottom:8px}.translation-composer{display:grid;flex:0 0 auto;gap:6px;border-top:1px solid #292d31;padding-top:8px}.translation-composer-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:stretch}.translation-manual-panel textarea,.translation-composer textarea{width:100%;min-height:38px;max-height:88px;border-color:#3a4149;background:#0d1117;color:#d6deeb;font-family:inherit;font-size:12px;line-height:1.35;resize:vertical}.translation-manual-panel textarea::placeholder,.translation-composer textarea::placeholder{color:#7d8590}.translation-manual-panel textarea::selection,.translation-composer textarea::selection{background:#8b949e59;color:#fff}.translation-manual-panel textarea:focus,.translation-manual-panel textarea:focus-visible,.translation-composer textarea:focus,.translation-composer textarea:focus-visible{border-color:#4b5563;outline:none;box-shadow:none}.translation-composer-actions{display:grid;align-content:start;gap:6px;min-width:104px}.translation-composer-actions button{border-color:#3a4149;background:#161b22;color:#d6deeb;width:100%;min-height:38px;padding:4px 9px;font-size:12px}.translation-panel .muted{color:#8b949e}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:20;display:grid;place-items:center;background:#181c1f61;padding:18px}.translator-session-backdrop{background:#010409b8}.translator-session-modal{display:grid;grid-template-rows:auto auto minmax(0,1fr);gap:10px;width:95vw;height:92vh;min-width:0;min-height:0;border:1px solid #30363d;border-radius:8px;background:#0d1117;color:#d6deeb;padding:10px}.translator-session-header{display:flex;gap:10px;align-items:center;justify-content:space-between;min-width:0}.translator-session-header h2,.translator-session-header p{margin-bottom:0}.translator-session-header p{color:#8b949e;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px}.translator-session-terminal{min-width:0;min-height:0;border-radius:6px;overflow:hidden;background:#111316}.usage-analytics-backdrop{background:#181c1f85}.usage-analytics-modal{display:grid;grid-template-rows:auto auto minmax(0,1fr);gap:12px;width:min(94vw,1280px);height:min(90vh,900px);min-width:0;min-height:0;overflow:hidden;border:1px solid #c8c0b4;border-radius:8px;background:#fffdfa;color:#1c2024;padding:14px;box-shadow:0 22px 64px #23282b3d}.usage-analytics-header,.usage-analytics-header-actions,.usage-analytics-meta{display:flex;align-items:center}.usage-analytics-header{justify-content:space-between;gap:16px}.usage-analytics-header h2,.usage-analytics-header p{margin-bottom:0}.usage-analytics-header p,.usage-analytics-meta,.usage-analytics-table small,.usage-analytics-no-models,.usage-analytics-empty{color:#667071}.usage-analytics-header-actions{gap:8px}.usage-analytics-content{min-width:0;min-height:0;overflow:auto;padding-right:2px}.usage-analytics-meta{justify-content:space-between;gap:12px;margin-bottom:14px;font-size:12px}.usage-analytics-section+.usage-analytics-section{margin-top:18px}.usage-analytics-section h3{margin:0 0 8px;font-size:13px}.usage-totals-grid{display:grid;grid-template-columns:repeat(5,minmax(140px,1fr));gap:8px;margin:0}.usage-totals-grid div{min-width:0;border:1px solid #ddd5c8;border-radius:6px;background:#f8f7f2;padding:10px}.usage-totals-grid dt{color:#667071;font-size:11px;font-weight:650}.usage-totals-grid dd{margin:3px 0 0;color:#1c2024;font-family:Menlo,Monaco,Consolas,monospace;font-size:16px;font-weight:750}.usage-analytics-table-wrap{width:100%;overflow-x:auto;border:1px solid #ddd5c8;border-radius:6px}.usage-analytics-table{width:100%;min-width:860px;border-collapse:collapse;font-size:12px}.usage-analytics-table th,.usage-analytics-table td{border-bottom:1px solid #e7e0d5;padding:8px 10px;text-align:right;white-space:nowrap}.usage-analytics-table thead th{background:#f2efe8;color:#596365;font-size:11px;font-weight:700}.usage-analytics-table th:first-child{position:sticky;left:0;z-index:1;min-width:190px;background:#fffdfa;text-align:left}.usage-analytics-table thead th:first-child{z-index:2;background:#f2efe8}.usage-analytics-table tbody tr:last-child th,.usage-analytics-table tbody tr:last-child td{border-bottom:0}.usage-analytics-table tbody th span,.usage-analytics-table tbody th small{display:block}.usage-analytics-table tbody th small{margin-top:2px;font-weight:500}.usage-analytics-table td{font-family:Menlo,Monaco,Consolas,monospace}.usage-analytics-error{margin:0}.usage-analytics-no-models,.usage-analytics-empty{margin:0;padding:24px 8px;text-align:center}@media(max-width:900px){.usage-analytics-modal{width:96vw;height:94vh;padding:10px}.usage-analytics-header,.usage-analytics-meta{align-items:flex-start;flex-direction:column}.usage-totals-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}.harness-studio-backdrop{background:#010409b8}.harness-studio-modal{display:grid;grid-template-rows:auto minmax(0,1fr);gap:12px;width:96vw;height:94vh;min-width:0;min-height:0;overflow:hidden;border:1px solid #30363d;border-radius:8px;background:#0d1117;color:#d6deeb;padding:12px}.harness-studio-header{display:flex;gap:12px;align-items:center;justify-content:space-between;min-width:0}.harness-studio-header h2,.harness-studio-header p{margin-bottom:0}.harness-studio-header p{color:#8b949e}.harness-studio-header-actions{display:flex;gap:8px;align-items:center}.harness-studio-layout{display:grid;grid-template-columns:minmax(340px,.85fr) minmax(640px,1.55fr);gap:12px;height:100%;min-width:0;min-height:0;overflow:hidden}.harness-studio-left{display:grid;grid-template-rows:minmax(0,1fr);min-width:0;min-height:0;height:100%;max-height:100%;overflow:hidden}.harness-studio-left-scroll{display:grid;grid-auto-rows:max-content;align-content:start;gap:10px;min-width:0;min-height:0;height:100%;max-height:100%;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable;padding-right:2px}.harness-studio-left-preview{grid-template-rows:minmax(0,1fr);height:100%;align-content:stretch;overflow:hidden;padding-right:0}.harness-studio-section{min-width:0;border:1px solid #30363d;border-radius:6px;background:#0b1017;padding:10px}.harness-studio-section h3{margin-bottom:8px;font-size:14px}.harness-studio-collapsible-section{padding:0;overflow:hidden}.harness-studio-collapsible-section summary{display:flex;gap:8px;align-items:center;justify-content:space-between;padding:10px;cursor:pointer;list-style:none}.harness-studio-collapsible-section summary::-webkit-details-marker{display:none}.harness-studio-collapsible-section summary h3{margin:0}.harness-studio-collapsible-section summary span{color:#8b949e;font-size:11px}.harness-studio-collapsible-section[open] summary span{color:#d6deeb}.harness-studio-collapsible-content{padding:0 10px 10px}.harness-studio-engineer{display:grid;grid-template-rows:auto auto minmax(0,1fr);gap:8px;min-height:0}.harness-studio-engineer-header{display:flex;gap:10px;align-items:flex-start;justify-content:space-between;min-width:0}.harness-studio-engineer-header p{margin-bottom:0}.harness-studio-file-preview{display:grid;grid-template-rows:auto auto auto minmax(0,1fr);gap:10px;height:100%;min-width:0;min-height:0;overflow:hidden}.harness-studio-file-editor-header{display:flex;gap:10px;align-items:flex-start;justify-content:space-between;min-width:0}.harness-studio-file-editor-header p{margin-bottom:0}.harness-studio-file-editor-header h3,.harness-studio-file-editor-header p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.harness-studio-file-editor-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;align-items:center}.harness-studio-file-textarea{grid-row:4;align-self:stretch;height:100%;width:100%;min-width:0;min-height:0;overflow:auto;resize:none;border:1px solid #30363d;border-radius:6px;background:#090d13;color:#d6deeb;padding:10px;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.55}.harness-studio-file-textarea:read-only{background:#080c12;color:#8b949e;cursor:default}.harness-studio-file-textarea.is-editing{background:#090d13;color:#d6deeb;cursor:text}.harness-studio-file-textarea:disabled{opacity:.72}.harness-engineer-terminal{min-width:0;min-height:0;overflow:hidden;border-radius:6px;background:#111316}.harness-studio-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px}.harness-studio-metric{display:grid;gap:4px;min-width:0;border:1px solid #30363d;border-radius:6px;padding:8px}.harness-studio-metric span{color:#8b949e;font-size:11px}.harness-studio-metric strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.harness-studio-file-list,.harness-studio-doc-list{display:grid;gap:6px;margin:0;padding:0;list-style:none}.harness-studio-file-list li,.harness-studio-doc-list li{display:grid;gap:8px;align-items:center;min-width:0;border:1px solid #30363d;border-radius:6px;padding:8px}.harness-studio-file-list li,.harness-studio-doc-list li{grid-template-columns:minmax(0,1fr) auto auto}.harness-studio-code-intelligence-list li{grid-template-columns:minmax(0,.7fr) minmax(0,.8fr) minmax(0,.7fr) auto minmax(0,1.5fr)}.harness-studio-code-intelligence-list code{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.harness-studio-code-intelligence-detail{min-width:0;color:#8b949e;overflow-wrap:anywhere}.harness-studio-doc-list button{padding:4px 8px}.harness-studio-file-list li.selected{border-color:#58a6ff;background:#0f1b2d}.harness-studio-file-list button{min-width:0;overflow:hidden;border:0;background:transparent;color:inherit;padding:0;text-align:left;text-overflow:ellipsis;white-space:nowrap}.harness-studio-file-list .harness-studio-file-copy-button{border:1px solid #30363d;border-radius:5px;background:#161b22;color:#d6deeb;padding:4px 8px;text-align:center}.harness-studio-file-list .harness-studio-file-copy-button:hover{border-color:#58a6ff}.harness-studio-file-list span:first-child,.harness-studio-doc-list span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.harness-memory-status{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:10px}.harness-memory-status .warnings{flex-basis:100%;margin:0}.harness-memory-runs{margin-top:12px}.harness-memory-runs h4{margin:0 0 8px;font-size:12px}.harness-studio-file-list .harness-memory-action-button,.harness-memory-action-button{border:1px solid #3d444d;border-radius:5px;background:#161b22;padding:4px 8px;text-align:center}.repository-diff-backdrop{background:#010409b8}.repository-diff-modal{display:grid;grid-template-rows:auto auto auto minmax(0,1fr);gap:10px;width:96vw;height:94vh;min-width:0;min-height:0;overflow:hidden;border:1px solid #30363d;border-radius:8px;background:#0d1117;color:#d6deeb;padding:12px}.repository-diff-header{display:flex;gap:12px;align-items:center;justify-content:space-between;min-width:0}.repository-diff-header h2,.repository-diff-header p,.repository-diff-file-header h3,.repository-diff-file-header p{margin-bottom:0}.repository-diff-header p,.repository-diff-file-header p{color:#8b949e}.repository-diff-header-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}.repository-diff-commit-picker{display:inline-flex;gap:8px;align-items:center;min-width:280px}.repository-diff-commit-picker span{color:#8b949e;font-size:12px;font-weight:700}.repository-diff-commit-picker select{min-width:260px;max-width:520px}.repository-diff-warnings{margin-top:0}.repository-diff-body{display:grid;grid-template-columns:minmax(280px,.32fr) minmax(0,1fr);gap:10px;min-width:0;min-height:0}.repository-diff-sidebar,.repository-diff-main{min-width:0;min-height:0;border:1px solid #30363d;border-radius:6px;background:#0b1017}.repository-diff-sidebar{display:grid;grid-template-rows:auto minmax(0,1fr);overflow:hidden}.repository-diff-summary{display:grid;gap:4px;border-bottom:1px solid #30363d;padding:10px;font-size:12px}.repository-diff-summary span{color:#8b949e}.repository-diff-file-list{display:grid;align-content:start;gap:6px;min-width:0;margin:0;padding:10px;overflow:auto;list-style:none}.repository-diff-file-list li{min-width:0}.repository-diff-file-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;align-items:stretch;min-width:0}.repository-diff-file-list button{display:grid;gap:4px;width:100%;min-width:0;border:1px solid #30363d;border-radius:6px;background:transparent;color:inherit;padding:8px;text-align:left}.repository-diff-file-list li.selected .repository-diff-file-select,.repository-diff-file-list li.task-diff-selected .repository-diff-task-file-button{border-color:#58a6ff;background:#0f1b2d}.repository-diff-task-file-button{align-content:center;min-width:78px;font-size:12px;text-align:center}.repository-diff-file-list span,.repository-diff-file-list small{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.repository-diff-file-list small{color:#8b949e}.repository-diff-empty{color:#8b949e;font-size:13px}.repository-diff-main{display:grid;grid-template-rows:auto auto auto minmax(0,1fr);gap:8px;overflow:hidden;padding:10px}.repository-diff-file-header{display:flex;gap:10px;align-items:flex-start;justify-content:space-between;min-width:0}.repository-diff-file-header h3{overflow-wrap:anywhere;font-size:15px}.repository-diff-stats{flex:0 0 auto;color:#7ee787;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px}.repository-diff-task-file-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}.repository-diff-code{min-width:0;min-height:0;margin:0;overflow:auto;border:1px solid #30363d;border-radius:6px;background:#090d13;color:#d6deeb;padding:0;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre}.repository-diff-line{display:block;min-width:max-content;border-left:3px solid transparent;padding:0 12px}.repository-diff-line-context{color:#c9d1d9}.repository-diff-line-added{border-left-color:#3fb950;background:#2ea04333;color:#aff5b4}.repository-diff-line-deleted{border-left-color:#f85149;background:#f851492e;color:#ffdcd7}.repository-diff-line-hunk{border-left-color:#58a6ff;background:#388bfd29;color:#79c0ff}.repository-diff-placeholder{display:grid;place-items:center;min-height:240px;color:#8b949e}.gateway-qr-modal{display:grid;grid-template-rows:auto minmax(0,1fr);gap:14px;width:min(520px,100%);max-height:min(720px,92vh);overflow:auto;border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:16px}.message-modal,.event-modal{display:grid;grid-template-rows:auto minmax(0,1fr);gap:12px;width:min(980px,100%);max-height:min(760px,92vh);overflow:hidden;border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:14px}.gateway-qr-modal header,.message-modal header,.event-modal header{display:flex;gap:8px;align-items:center;justify-content:space-between}.gateway-qr-modal h2,.gateway-qr-modal p{margin-bottom:0}.gateway-qr-modal-body{display:grid;gap:14px;justify-items:center}.gateway-qr-code-frame{display:grid;place-items:center;width:min(360px,100%);aspect-ratio:1;border:1px solid #d6d0c6;border-radius:8px;background:#fff;padding:18px}.gateway-qr-code-frame img{display:block;width:100%;height:auto}.gateway-qr-actions{display:flex;justify-content:flex-end;width:min(360px,100%)}.gateway-qr-placeholder{color:#667071;text-align:center}.gateway-qr-meta{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;width:100%;margin:0}.gateway-qr-meta div{min-width:0;border:1px solid #ece5d9;border-radius:6px;padding:8px}.gateway-qr-meta dt{color:#6c6255;font-size:11px;font-weight:700;text-transform:uppercase}.gateway-qr-meta dd{margin:0;overflow-wrap:anywhere;font-size:13px}.gateway-manual-bind{display:grid;grid-template-columns:repeat(2,minmax(0,1fr)) auto;align-items:end;gap:10px;width:100%;border-top:1px solid #ece5d9;padding-top:12px}.gateway-manual-bind div{display:grid;gap:4px}.gateway-manual-bind label{color:#6c6255;font-size:12px;font-weight:700}.gateway-manual-bind input{width:100%;border:1px solid #d6d0c6;border-radius:6px;background:#fff;color:#191713;padding:8px 10px;font:inherit}.form-error{grid-column:1 / -1;color:#b42318;font-size:13px}.message-modal h2,.message-modal p,.event-modal h2,.event-modal p{margin-bottom:0}.translation-test-result{border-radius:6px;padding:8px;font-size:13px}.translation-test-result.is-ok{border:1px solid #6ea77e;background:#e6f3e9;color:#245334}.translation-test-result.is-error{border:1px solid #c46e5f;background:#fae9e6;color:#6f2b21}.message-panel{display:grid;gap:8px}.message-modal .message-panel,.event-modal .event-log{min-height:0;overflow:auto;border:0;background:transparent;padding:0}.message-panel-header{display:flex;justify-content:space-between;gap:12px;align-items:center}.message-panel-header h2,.message-panel-header p{margin-bottom:0}.message-controls,.message-mode-toggle,.modal-actions,.message-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.message-mode-toggle{width:auto;min-width:220px;font-size:13px}.message-list{display:grid;gap:8px;margin:0;padding:0;list-style:none}.message-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:start;border:1px solid #ece5d9;border-radius:6px;padding:8px;background:#fffdfa}.message-meta{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:4px}.message-meta time,.message-meta span:not(.status-badge),.message-reason,.message-path{color:#667071;font-size:12px}.message-sequence{min-width:32px;color:#1f242b;font-weight:800}.message-actions button{min-height:30px;padding:4px 10px}.message-item p{display:-webkit-box;margin-bottom:4px;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:2}.message-reason,.message-path{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.event-log ol{margin:0;padding-left:22px;font-size:13px}.event-log{max-height:92px;overflow:auto}.event-log h2{margin-bottom:4px;font-size:13px}.event-log p{margin-bottom:0}.event-log li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-badge{display:inline-flex;align-items:center;justify-content:center;min-width:66px;min-height:20px;border-radius:999px;padding:2px 8px;border:1px solid #c7c1b8;background:#f2eee7;color:#4f5558;font-size:11px;white-space:nowrap}.status-active,.status-running,.status-ok{border-color:#6ea77e;background:#e6f3e9;color:#245334}.status-created,.status-idle,.status-disabled{border-color:#9aa3a8;background:#edf0f1;color:#465056}.status-blocked,.status-crashed,.status-missing,.status-empty,.status-delete{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.status-waiting,.status-starting,.status-incomplete,.status-outdated{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-exited,.status-done,.status-stopped,.status-resumable,.status-skipped,.status-overridden,.status-not_required{border-color:#7b98b8;background:#e9f0f8;color:#2e4e70}.status-queued,.status-translating,.status-ready,.status-create,.status-insert,.status-update{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-rejected,.status-failed,.status-delivery_failed,.status-response_ready_missing_result,.status-cancelled,.status-blocked{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.status-pending{border-color:#c7c1b8;background:#f2eee7;color:#4f5558}.status-translated,.status-preserved{border-color:#7b98b8;background:#e9f0f8;color:#2e4e70}.empty-workspace{max-width:680px}@media(max-width:980px){.app-shell,.workspace-grid{grid-template-columns:1fr}.app-sidebar{border-right:0;border-bottom:1px solid #d3c9b8}.role-tabs{grid-template-columns:repeat(2,minmax(0,1fr))}.session-console-body.has-translation,.translation-file-browser-layout{grid-template-columns:1fr}.session-controls,.session-toolbar{flex-wrap:wrap;overflow:visible}.harness-studio-code-intelligence-list li{grid-template-columns:minmax(0,1fr) auto}.harness-studio-code-intelligence-list code,.harness-studio-code-intelligence-detail{grid-column:1 / -1}.file-translation-modal{width:95vw;height:95vh;padding:10px}.file-translation-layout{grid-template-columns:minmax(180px,240px) minmax(0,1fr)}.translation-file-browser-modal{min-height:0}}@media(max-width:700px){.workspace-runtime-warning{grid-template-columns:1fr;gap:4px}.file-translation-layout{grid-template-columns:1fr;grid-template-rows:minmax(140px,28vh) minmax(0,1fr)}.file-translation-header{align-items:stretch}.file-translation-toolbar{width:100%}.file-translation-toolbar button{flex:1 1 auto}}@media(max-width:560px){.app-main,.app-sidebar{padding:12px}.workspace-header,.inline-form,.inline-form.has-recent-paths{grid-template-columns:1fr;display:grid}.role-tabs{grid-template-columns:1fr}.terminal-frame-shell,.terminal-empty{min-height:300px;height:54vh}.session-option-field{grid-template-columns:1fr;width:100%}.translation-file-browser-modal{width:calc(100vw - 20px);max-height:calc(100vh - 20px);padding:10px}.file-translation-modal{width:calc(100vw - 12px);height:calc(100vh - 12px)}.translation-file-browser-controls,.translation-file-browser-search{display:grid;grid-template-columns:1fr}.gateway-manual-bind{grid-template-columns:1fr}.gateway-manual-bind button{justify-self:stretch}}.harness-bootstrap-terminal .terminal-frame-shell{height:100%;min-height:0}:root[data-theme=dark]{color-scheme:dark;background:#0d1117;color:#e6edf3}:root[data-theme=dark] body,:root[data-theme=dark] .app-main{background:#0d1117;color:#e6edf3}:root[data-theme=dark] button{border-color:#3d4652;background:#161b22;color:#e6edf3}:root[data-theme=dark] button:hover:not(:disabled){border-color:#58a6ff;background:#1f2937}:root[data-theme=dark] input,:root[data-theme=dark] select,:root[data-theme=dark] textarea:not(.xterm-helper-textarea){border-color:#3d4652;background:#0d1117;color:#e6edf3}:root[data-theme=dark] input::placeholder,:root[data-theme=dark] textarea::placeholder{color:#7d8590}:root[data-theme=dark] .danger-button{border-color:#da7b72;background:#2d1518;color:#ffdcd7}:root[data-theme=dark] .danger-button:hover:not(:disabled){border-color:#ffa198;background:#3d1f23}:root[data-theme=dark] .app-sidebar{border-color:#30363d;background:#0f141b}:root[data-theme=dark] .sidebar-toggle{background:#161b22}:root[data-theme=dark] .brand-header span,:root[data-theme=dark] .muted,:root[data-theme=dark] .message-meta time,:root[data-theme=dark] .message-meta span:not(.status-badge),:root[data-theme=dark] .message-reason,:root[data-theme=dark] .message-path{color:#8b949e}:root[data-theme=dark] .sidebar-section,:root[data-theme=dark] .session-console,:root[data-theme=dark] .message-panel,:root[data-theme=dark] .event-log,:root[data-theme=dark] .empty-workspace,:root[data-theme=dark] .gateway-qr-modal,:root[data-theme=dark] .message-modal,:root[data-theme=dark] .event-modal{border-color:#30363d;background:#11161d}:root[data-theme=dark] .gateway-qr-code-frame,:root[data-theme=dark] .gateway-qr-meta div,:root[data-theme=dark] .gateway-manual-bind input{border-color:#30363d;background:#0d1117}:root[data-theme=dark] .gateway-qr-code-frame{background:#f6f8fa}:root[data-theme=dark] .gateway-qr-meta dt,:root[data-theme=dark] .gateway-qr-placeholder,:root[data-theme=dark] .gateway-manual-bind label{color:#8b949e}:root[data-theme=dark] .sidebar-section-toggle{color:#e6edf3}:root[data-theme=dark] .sidebar-section-toggle:hover{background:#161b22}:root[data-theme=dark] .sidebar-section-toggle[aria-expanded=true]{border-color:#30363d}:root[data-theme=dark] .project-summary dt,:root[data-theme=dark] .session-option-field span,:root[data-theme=dark] .message-mode-toggle{color:#b7c0ca}:root[data-theme=dark] .session-option-field small,:root[data-theme=dark] .task-create-preview small{color:#8b949e}:root[data-theme=dark] .warnings{border-color:#da7b72;background:#2d1518;color:#ffdcd7}:root[data-theme=dark] .workspace-runtime-warning{border-color:#da7b72;background:#2d1518;color:#ffdcd7}:root[data-theme=dark] .ui-error-center{border-color:#da7b72;background:#2d1518;color:#ffdcd7;box-shadow:0 18px 50px #0104098f}:root[data-theme=dark] .ui-error-center-header p,:root[data-theme=dark] .ui-error-list span{color:#ffb4ab}:root[data-theme=dark] .ui-error-center button{border-color:#da7b72;color:#ffdcd7}:root[data-theme=dark] .ui-error-list li{border-top-color:#da7b7257}:root[data-theme=dark] .success-banner{border-color:#3fb950;background:#112718;color:#aff5b4}:root[data-theme=dark] .flow-pause-alert-backdrop{background:#010409b8}:root[data-theme=dark] .flow-pause-alert{border-color:#56d4dd;background:#10262b;color:#d6fbff;box-shadow:0 28px 72px #0104099e}:root[data-theme=dark] .flow-pause-alert-kicker,:root[data-theme=dark] .flow-pause-alert-hint{color:#9debf2}:root[data-theme=dark] .flow-pause-alert button{border-color:#56d4dd;background:#56d4dd;color:#061114}:root[data-theme=dark] .flow-pause-alert button:hover{background:#84f3fa}:root[data-theme=dark] .role-recovery-toast{border-color:#d29922;background:#2d230d;color:#ffdf8b;box-shadow:0 14px 42px #01040985}:root[data-theme=dark] .role-recovery-toast button{border-color:#d29922;color:#ffdf8b}:root[data-theme=dark] .harness-file-list li,:root[data-theme=dark] .harness-changes,:root[data-theme=dark] .harness-result,:root[data-theme=dark] .gateway-qr img,:root[data-theme=dark] .task-create-preview,:root[data-theme=dark] .task-status-stats div,:root[data-theme=dark] .current-round-status,:root[data-theme=dark] .message-item{border-color:#30363d;background:#0d1117}:root[data-theme=dark] .harness-bootstrap-modal{background:#010409b8}:root[data-theme=dark] .harness-bootstrap-modal-surface{border-color:#30363d;background:#0d1117;box-shadow:0 22px 64px #0104099e}:root[data-theme=dark] .harness-bootstrap-controls label span{color:#b7c0ca}:root[data-theme=dark] .harness-bootstrap-controls select{border-color:#3a4149;background:#0d1117;color:#d6deeb}:root[data-theme=dark] .task-create-option{color:#e6edf3}:root[data-theme=dark] .task-status-dock{border-color:#30363d}:root[data-theme=dark] .task-create-preview span{color:#7ee787}:root[data-theme=dark] .task-status-stats dt{color:#8b949e}:root[data-theme=dark] .task-status-stats dd,:root[data-theme=dark] .current-round-title span:first-child{color:#e6edf3}:root[data-theme=dark] .message-sequence{color:#f0f6fc}:root[data-theme=dark] .settings-help-text{color:#d29922}:root[data-theme=dark] .task-nav-item.is-active,:root[data-theme=dark] .role-tab.is-active,:root[data-theme=dark] .sidebar-settings .settings-toggle.is-active,:root[data-theme=dark] .gateway-actions .settings-toggle.is-active{border-color:#56d4dd;background:#10262b;color:#d6fbff}:root[data-theme=dark] .switch-control{border-color:#3d4652;background:#161b22;color:#d6deeb}:root[data-theme=dark] .switch-control:hover:not(:disabled){border-color:#56d4dd;background:#1a2530}:root[data-theme=dark] .switch-control-track{background:#3d4652}:root[data-theme=dark] .switch-control-thumb{background:#e6edf3;box-shadow:0 1px 4px #0104097a}:root[data-theme=dark] .switch-control.is-on{border-color:#56d4dd;background:#10262b;color:#d6fbff}:root[data-theme=dark] .switch-control.is-on .switch-control-track{background:#56d4dd}:root[data-theme=dark] .session-option-field select,:root[data-theme=dark] .settings-select-row select,:root[data-theme=dark] .codex-bridge-api-key-form input{border-color:#3d4652;background:#0d1117;color:#e6edf3}:root[data-theme=dark] .settings-select-row{color:#b7c0ca}:root[data-theme=dark] .codex-bridge-settings{border-top-color:#30363d}:root[data-theme=dark] .codex-bridge-api-key-form{color:#b7c0ca}:root[data-theme=dark] .settings-status-row{border-color:#3d4652;background:#161b22;color:#d6deeb}:root[data-theme=dark] .settings-status-row strong{color:#e6edf3}:root[data-theme=dark] .terminal-empty{border-color:#30363d}:root[data-theme=dark] .modal-backdrop{background:#010409b8}:root[data-theme=dark] .message-modal .message-panel,:root[data-theme=dark] .event-modal .event-log{background:transparent}:root[data-theme=dark] .usage-analytics-modal{border-color:#30363d;background:#0d1117;color:#e6edf3;box-shadow:0 22px 64px #0104099e}:root[data-theme=dark] .usage-analytics-header p,:root[data-theme=dark] .usage-analytics-meta,:root[data-theme=dark] .usage-analytics-table small,:root[data-theme=dark] .usage-analytics-no-models,:root[data-theme=dark] .usage-analytics-empty,:root[data-theme=dark] .usage-totals-grid dt{color:#8b949e}:root[data-theme=dark] .usage-totals-grid div,:root[data-theme=dark] .usage-analytics-table-wrap{border-color:#30363d;background:#161b22}:root[data-theme=dark] .usage-totals-grid dd{color:#f0f6fc}:root[data-theme=dark] .usage-analytics-table th,:root[data-theme=dark] .usage-analytics-table td{border-bottom-color:#30363d}:root[data-theme=dark] .usage-analytics-table thead th,:root[data-theme=dark] .usage-analytics-table thead th:first-child{background:#161b22;color:#b7c0ca}:root[data-theme=dark] .usage-analytics-table tbody th:first-child{background:#0d1117}:root[data-theme=dark] .status-badge{border-color:#3d4652;background:#161b22;color:#d6deeb}:root[data-theme=dark] .translation-test-result.is-ok,:root[data-theme=dark] .status-active,:root[data-theme=dark] .status-running,:root[data-theme=dark] .status-ok{border-color:#3fb950;background:#12261a;color:#aff5b4}:root[data-theme=dark] .status-created,:root[data-theme=dark] .status-idle,:root[data-theme=dark] .status-disabled{border-color:#69717d;background:#20262f;color:#d6deeb}:root[data-theme=dark] .translation-test-result.is-error,:root[data-theme=dark] .status-blocked,:root[data-theme=dark] .status-crashed,:root[data-theme=dark] .status-missing,:root[data-theme=dark] .status-empty,:root[data-theme=dark] .status-delete,:root[data-theme=dark] .status-rejected,:root[data-theme=dark] .status-failed,:root[data-theme=dark] .status-delivery_failed,:root[data-theme=dark] .status-response_ready_missing_result,:root[data-theme=dark] .status-cancelled{border-color:#f85149;background:#2d1518;color:#ffdcd7}:root[data-theme=dark] .status-waiting,:root[data-theme=dark] .status-starting,:root[data-theme=dark] .status-incomplete,:root[data-theme=dark] .status-queued,:root[data-theme=dark] .status-translating,:root[data-theme=dark] .status-ready,:root[data-theme=dark] .status-create,:root[data-theme=dark] .status-insert,:root[data-theme=dark] .status-update{border-color:#d29922;background:#2d2208;color:#f8e3a1}:root[data-theme=dark] .status-exited,:root[data-theme=dark] .status-done,:root[data-theme=dark] .status-stopped,:root[data-theme=dark] .status-resumable,:root[data-theme=dark] .status-skipped,:root[data-theme=dark] .status-overridden,:root[data-theme=dark] .status-not_required,:root[data-theme=dark] .status-translated,:root[data-theme=dark] .status-preserved{border-color:#388bfd;background:#10223a;color:#c9e2ff}:root[data-theme=dark] .status-pending{border-color:#3d4652;background:#161b22;color:#d6deeb}
|