vibe-coding-master 0.0.5 → 0.0.7
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 +168 -63
- package/dist/backend/adapters/translation-provider.js +145 -0
- package/dist/backend/api/artifact-routes.js +3 -0
- package/dist/backend/api/harness-routes.js +22 -0
- package/dist/backend/api/project-routes.js +3 -8
- package/dist/backend/api/translation-routes.js +70 -0
- package/dist/backend/runtime/node-pty-runtime.js +20 -18
- package/dist/backend/server.js +31 -1
- package/dist/backend/services/app-settings-service.js +128 -0
- package/dist/backend/services/artifact-service.js +7 -4
- package/dist/backend/services/claude-transcript-service.js +509 -0
- package/dist/backend/services/harness-service.js +178 -0
- package/dist/backend/services/project-service.js +4 -0
- package/dist/backend/services/session-service.js +7 -5
- package/dist/backend/services/status-service.js +76 -0
- package/dist/backend/services/translation-prompts.js +173 -0
- package/dist/backend/services/translation-queue.js +39 -0
- package/dist/backend/services/translation-service.js +546 -0
- package/dist/backend/templates/handoff.js +32 -0
- package/dist/backend/templates/harness/architect-agent.js +12 -0
- package/dist/backend/templates/harness/claude-root.js +14 -0
- package/dist/backend/templates/harness/coder-agent.js +11 -0
- package/dist/backend/templates/harness/project-manager-agent.js +14 -0
- package/dist/backend/templates/harness/reviewer-agent.js +13 -0
- package/dist/backend/ws/translation-ws.js +35 -0
- package/dist/shared/types/harness.js +1 -0
- package/dist/shared/types/translation.js +5 -0
- package/dist/shared/validation/artifact-check.js +15 -1
- package/dist/shared/validation/language-detect.js +46 -0
- package/dist-frontend/assets/index-BNASqKEK.css +32 -0
- package/dist-frontend/assets/index-Bp49_End.js +58 -0
- package/dist-frontend/index.html +2 -2
- package/docs/cc-best-practices.md +93 -36
- package/docs/product-design.md +313 -1408
- package/docs/v1-architecture-design.md +500 -1153
- package/docs/v1-implementation-plan.md +783 -1604
- package/package.json +3 -1
- package/scripts/verify-package.mjs +121 -0
- package/dist/backend/templates/role-messaging-context.js +0 -44
- package/dist-frontend/assets/index-Bah6k-Ix.css +0 -32
- package/dist-frontend/assets/index-EMaQuIB6.js +0 -58
- package/docs/v1-message-bus-orchestration-design.md +0 -534
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-coding-master",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Local GUI session cockpit for Claude Code role sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
"clean": "node scripts/clean-build.mjs",
|
|
25
25
|
"fix:node-pty": "node scripts/fix-node-pty-spawn-helper.mjs",
|
|
26
26
|
"postinstall": "node scripts/fix-node-pty-spawn-helper.mjs",
|
|
27
|
+
"verify:package": "node scripts/verify-package.mjs",
|
|
28
|
+
"prepack": "npm run build && npm run verify:package",
|
|
27
29
|
"dev": "tsx src/main.ts --dev",
|
|
28
30
|
"build": "npm run clean && tsc -p tsconfig.node.json && vite build",
|
|
29
31
|
"start": "node dist/main.js",
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const appRoot = process.cwd();
|
|
5
|
+
const requiredFiles = [
|
|
6
|
+
"README.md",
|
|
7
|
+
"package.json",
|
|
8
|
+
"scripts/fix-node-pty-spawn-helper.mjs",
|
|
9
|
+
"dist/main.js",
|
|
10
|
+
"dist/cli/vcmctl.js",
|
|
11
|
+
"dist/backend/server.js",
|
|
12
|
+
"dist/backend/api/harness-routes.js",
|
|
13
|
+
"dist/backend/runtime/node-pty-runtime.js",
|
|
14
|
+
"dist/backend/ws/terminal-ws.js",
|
|
15
|
+
"dist/backend/services/harness-service.js",
|
|
16
|
+
"dist/backend/services/session-service.js",
|
|
17
|
+
"dist/backend/services/project-service.js",
|
|
18
|
+
"dist/backend/services/message-service.js",
|
|
19
|
+
"dist/backend/templates/harness/claude-root.js",
|
|
20
|
+
"dist/backend/templates/harness/project-manager-agent.js",
|
|
21
|
+
"dist/backend/templates/harness/architect-agent.js",
|
|
22
|
+
"dist/backend/templates/harness/coder-agent.js",
|
|
23
|
+
"dist/backend/templates/harness/reviewer-agent.js",
|
|
24
|
+
"dist/shared/constants.js",
|
|
25
|
+
"dist/shared/types/harness.js",
|
|
26
|
+
"dist/shared/validation/slug-check.js",
|
|
27
|
+
"dist/shared/validation/artifact-check.js",
|
|
28
|
+
"dist-frontend/index.html"
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const requiredFileEntries = [
|
|
32
|
+
"dist",
|
|
33
|
+
"dist-frontend",
|
|
34
|
+
"docs",
|
|
35
|
+
"scripts",
|
|
36
|
+
"README.md"
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
async function main() {
|
|
40
|
+
const pkg = JSON.parse(await readText("package.json"));
|
|
41
|
+
assertArrayIncludes(pkg.files, requiredFileEntries, "package.json files");
|
|
42
|
+
assertEqual(pkg.bin?.vcm, "dist/main.js", "package.json bin.vcm");
|
|
43
|
+
assertEqual(pkg.bin?.vcmctl, "dist/cli/vcmctl.js", "package.json bin.vcmctl");
|
|
44
|
+
|
|
45
|
+
for (const file of requiredFiles) {
|
|
46
|
+
await assertFile(file);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await assertStartsWith("dist/main.js", "#!/usr/bin/env node", "vcm bin shebang");
|
|
50
|
+
await assertStartsWith("dist/cli/vcmctl.js", "#!/usr/bin/env node", "vcmctl bin shebang");
|
|
51
|
+
|
|
52
|
+
const server = await readText("dist/backend/server.js");
|
|
53
|
+
assertIncludes(server, 'path.join(getAppRoot(), "dist-frontend")', "packaged static dir must resolve from app root");
|
|
54
|
+
assertNotIncludes(server, 'path.resolve("dist-frontend")', "packaged static dir must not resolve from caller cwd");
|
|
55
|
+
|
|
56
|
+
const indexHtml = await readText("dist-frontend/index.html");
|
|
57
|
+
const assetPaths = [...indexHtml.matchAll(/(?:src|href)="\/([^"]+)"/g)].map((match) => match[1]);
|
|
58
|
+
if (assetPaths.length === 0) {
|
|
59
|
+
fail("dist-frontend/index.html does not reference any built assets");
|
|
60
|
+
}
|
|
61
|
+
for (const assetPath of assetPaths) {
|
|
62
|
+
await assertFile(path.join("dist-frontend", assetPath));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`Package verification passed: ${requiredFiles.length + assetPaths.length} required files checked.`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function readText(relativePath) {
|
|
69
|
+
return fs.readFile(path.join(appRoot, relativePath), "utf8");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function assertFile(relativePath) {
|
|
73
|
+
const absolutePath = path.join(appRoot, relativePath);
|
|
74
|
+
const stat = await fs.stat(absolutePath).catch(() => null);
|
|
75
|
+
if (!stat?.isFile()) {
|
|
76
|
+
fail(`Missing required package file: ${relativePath}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function assertStartsWith(relativePath, expected, label) {
|
|
81
|
+
const content = await readText(relativePath);
|
|
82
|
+
if (!content.startsWith(expected)) {
|
|
83
|
+
fail(`${label} failed for ${relativePath}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function assertArrayIncludes(actual, expectedEntries, label) {
|
|
88
|
+
if (!Array.isArray(actual)) {
|
|
89
|
+
fail(`${label} must be an array`);
|
|
90
|
+
}
|
|
91
|
+
for (const entry of expectedEntries) {
|
|
92
|
+
if (!actual.includes(entry)) {
|
|
93
|
+
fail(`${label} missing ${entry}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function assertEqual(actual, expected, label) {
|
|
99
|
+
if (actual !== expected) {
|
|
100
|
+
fail(`${label} expected ${expected}, got ${actual}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function assertIncludes(content, expected, label) {
|
|
105
|
+
if (!content.includes(expected)) {
|
|
106
|
+
fail(`${label}: missing ${expected}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function assertNotIncludes(content, unexpected, label) {
|
|
111
|
+
if (content.includes(unexpected)) {
|
|
112
|
+
fail(`${label}: found ${unexpected}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function fail(message) {
|
|
117
|
+
console.error(`Package verification failed: ${message}`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
await main();
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export function renderRoleMessagingContext(task, paths, role, vcmctlCommand = "vcmctl") {
|
|
2
|
-
if (role === "project-manager") {
|
|
3
|
-
return `VCM messaging context
|
|
4
|
-
|
|
5
|
-
Task slug: ${task.taskSlug}
|
|
6
|
-
Canonical handoff directory: ${task.handoffDir}
|
|
7
|
-
|
|
8
|
-
You are the orchestration hub for this task.
|
|
9
|
-
|
|
10
|
-
Use VCM messaging instead of asking the user to copy commands:
|
|
11
|
-
- Send work to architect/coder/reviewer with: ${vcmctlCommand} send --to <role> --type task --body-file <file>
|
|
12
|
-
- Ask a question with: ${vcmctlCommand} send --to <role> --type question --body "..."
|
|
13
|
-
- Check pending messages with: ${vcmctlCommand} inbox
|
|
14
|
-
|
|
15
|
-
Canonical role command files still exist for durable handoff:
|
|
16
|
-
- architect: ${paths.roleCommandPaths.architect}
|
|
17
|
-
- coder: ${paths.roleCommandPaths.coder}
|
|
18
|
-
- reviewer: ${paths.roleCommandPaths.reviewer}
|
|
19
|
-
|
|
20
|
-
Hard rules:
|
|
21
|
-
- Use only ${task.handoffDir} for this task.
|
|
22
|
-
- Do not create or write .ai/handoffs/<other-task>/ for this task.
|
|
23
|
-
- Non-trivial blockers or high-risk decisions must be escalated to the user.
|
|
24
|
-
- In manual orchestration mode, sent messages wait for user approval before the target role executes them.
|
|
25
|
-
`;
|
|
26
|
-
}
|
|
27
|
-
return `VCM messaging context
|
|
28
|
-
|
|
29
|
-
Task slug: ${task.taskSlug}
|
|
30
|
-
Canonical handoff directory: ${task.handoffDir}
|
|
31
|
-
Current role: ${role}
|
|
32
|
-
|
|
33
|
-
When complete, blocked, or unclear, reply to project-manager through VCM:
|
|
34
|
-
- ${vcmctlCommand} reply --type result --body-file <file>
|
|
35
|
-
- ${vcmctlCommand} reply --type blocked --body "..."
|
|
36
|
-
- ${vcmctlCommand} reply --type question --body "..."
|
|
37
|
-
|
|
38
|
-
Hard rules:
|
|
39
|
-
- Only reply to project-manager. Do not message other roles directly.
|
|
40
|
-
- Use only ${task.handoffDir} for this task.
|
|
41
|
-
- Do not create or write .ai/handoffs/<other-task>/ for this task.
|
|
42
|
-
- In manual orchestration mode, your replies wait for user approval before project-manager receives them.
|
|
43
|
-
`;
|
|
44
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
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,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}input,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;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{min-width:0}.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;justify-content:space-between;gap:12px;align-items:baseline;margin-bottom:16px;padding-right:34px}.brand-header strong{font-size:18px}.brand-header span,.muted,.workspace-branch{color:#667071;font-size:13px}.repo-connect,.project-summary,.task-create,.project-dashboard section{margin-bottom:16px}.repo-connect label{display:block;margin-bottom:8px;font-size:13px;font-weight:650}.inline-form{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px}.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}.warnings,.error-banner{border:1px solid #c87b54;background:#fff4ed;color:#6f3218;border-radius:6px;padding:10px 12px}.warnings{margin:12px 0 0;padding-left:26px;font-size:13px}.task-create form,.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}.workspace-header{display:flex;justify-content:space-between;gap:16px;align-items:center;margin-bottom:6px}.workspace-title-line{display:flex;flex-wrap:wrap;gap:10px;align-items:baseline;min-width:0}.workspace-title-line h1{margin-bottom:0;font-size:18px;line-height:1.15}.workspace-branch{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.eyebrow{color:#7a5c2f;font-size:12px;font-weight:700;text-transform:uppercase}.role-tabs{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin-bottom:8px}.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);gap:10px;align-items:start}.workspace-main{min-width:0;display:grid;gap:8px}.role-console-stack{min-width:0}.role-console-panel{min-width:0;display:none}.role-console-panel.is-active{display:block}.session-console,.message-panel,.event-log,.empty-workspace{border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:10px}.session-controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between;margin:0 0 8px}.permission-mode-field{display:grid;grid-template-columns:auto minmax(180px,260px);gap:8px;align-items:center;width:fit-content;max-width:100%}.permission-mode-field span{color:#5f6a6c;font-size:13px;font-weight:650}.permission-mode-field small{display:block;color:#7b8587;font-size:11px;font-weight:500;line-height:1.2}.permission-mode-field select{width:100%;min-height:30px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:4px 8px}.session-toolbar{display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.session-toolbar button{min-height:30px;padding:4px 9px}.terminal-frame,.terminal-empty{height:clamp(560px,calc(100vh - 210px),960px);min-height:520px;border-radius:6px;overflow:hidden;background:#111316}.terminal-empty{display:grid;place-items:center;align-content:center;gap:8px;color:#d6d0c6;border:1px solid #292d31}.message-panel{display:grid;gap:8px}.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,.message-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.message-mode-toggle{color:#4f5558;font-size:13px;font-weight:650}.message-mode-toggle input{width:auto}.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 span:not(.status-badge),.message-path{color:#667071;font-size:12px}.message-item p{display:-webkit-box;margin-bottom:4px;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:2}.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-running,.status-ok{border-color:#6ea77e;background:#e6f3e9;color:#245334}.status-blocked,.status-crashed,.status-missing,.status-empty{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.status-waiting,.status-starting,.status-incomplete{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-exited,.status-done,.status-resumable,.status-staged,.status-delivered,.status-acknowledged{border-color:#7b98b8;background:#e9f0f8;color:#2e4e70}.status-pending_approval,.status-queued{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-rejected,.status-failed,.status-cancelled{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.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))}}@media(max-width:560px){.app-main,.app-sidebar{padding:12px}.workspace-header,.inline-form{grid-template-columns:1fr;display:grid}.role-tabs{grid-template-columns:1fr}.terminal-frame,.terminal-empty{min-height:300px;height:54vh}.permission-mode-field{grid-template-columns:1fr;width:100%}}
|