@tea-agent/loop-agent 0.33.0 → 0.33.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/dist/worker/console/operator-surface-health.js +1 -0
- package/dist/worker/console/static/assets/index-CnUXAqxG.css +1 -0
- package/dist/worker/console/static/assets/{index-3R-GT3a_.js → index-PzYzcuFG.js} +17 -17
- package/dist/worker/console/static/index.html +3 -2
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +3 -2
- package/dist/worker/observe/routes.js +3 -8
- package/dist/worker/observe/static/app.js +11 -0
- package/dist/worker/observe/static/index.html +11 -43
- package/dist/worker/observe/static/kpi.js +2 -24
- package/dist/worker/observe/static/operator-chrome.css +480 -0
- package/dist/worker/observe/static/operator-chrome.d.ts +82 -0
- package/dist/worker/observe/static/operator-chrome.js +554 -0
- package/dist/worker/observe/static/shell-chrome.js +1 -11
- package/dist/worker/observe/static/styles.css +62 -269
- package/dist/worker/observe/static/views/dashboard.js +52 -4
- package/dist/workflows/dag/retry-policy.js +5 -0
- package/package.json +1 -1
- package/skills/analyze-product-dependencies/SKILL.md +74 -33
- package/skills/analyze-product-dependencies/references/api-documentation-schema.md +16 -11
- package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +20 -10
- package/skills/analyze-product-dependencies/references/example.md +9 -9
- package/skills/analyze-product-dependencies/references/forward-test-cases.md +93 -18
- package/skills/analyze-product-dependencies/references/input-contract.md +27 -4
- package/skills/analyze-product-dependencies/references/kb-integration.md +64 -0
- package/skills/analyze-product-dependencies/references/scouting-rules.md +25 -10
- package/skills/analyze-product-dependencies/scripts/test-validators.mjs +247 -54
- package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +122 -29
- package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +94 -36
- package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +37 -23
- package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +35 -43
- package/skills/analyze-product-requirements/SKILL.md +98 -43
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +8 -12
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +28 -14
- package/skills/analyze-product-requirements/references/example.md +24 -6
- package/skills/analyze-product-requirements/references/forward-test-cases.md +87 -9
- package/skills/analyze-product-requirements/references/kb-integration.md +56 -0
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +19 -10
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +21 -12
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +45 -14
- package/skills/analyze-product-requirements/scripts/compute-source-identity.mjs +35 -0
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +337 -29
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +38 -7
- package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +41 -29
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +33 -22
- package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +43 -24
- package/dist/worker/console/static/assets/index-B0EQt_yq.css +0 -1
- package/skills/analyze-product-dependencies/agents/openai.yaml +0 -4
- package/skills/analyze-product-requirements/agents/openai.yaml +0 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
-
import { dirname,
|
|
5
|
-
import { acceptanceBlocks, assertHeadings,
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { acceptanceBlocks, assertHeadings, field, loadMarkdown, metadata, outputSpecBlocks, printResult, section, storyBlocks, validateAcceptance, validateArtifactLocation, validateFrontmatter, validateNoImplementationLeakage, validateStorySpecCoverage } from "./validation-helpers.mjs";
|
|
6
6
|
|
|
7
7
|
const args = process.argv.slice(2);
|
|
8
8
|
const allowPending = args.includes("--allow-pending");
|
|
@@ -20,10 +20,11 @@ catch (error) { console.error(error.message); process.exit(2); }
|
|
|
20
20
|
|
|
21
21
|
const { path, text } = artifact;
|
|
22
22
|
const errors = [];
|
|
23
|
+
validateFrontmatter(text, ["artifact_version", "artifact_type", "requirement_id", "requirement_status", "analysis_scope"], errors, "Product Requirement");
|
|
23
24
|
validateArtifactLocation(artifact, errors, "product-requirement.md");
|
|
24
25
|
const scope = metadata(text, "analysis_scope");
|
|
25
26
|
const status = metadata(text, "requirement_status");
|
|
26
|
-
if (metadata(text, "artifact_version") !== "
|
|
27
|
+
if (metadata(text, "artifact_version") !== "4.0") errors.push("artifact_version must be 4.0.");
|
|
27
28
|
if (metadata(text, "artifact_type") !== "product-requirement") errors.push("artifact_type must be product-requirement.");
|
|
28
29
|
if (!["frontend", "backend", "both"].includes(scope)) errors.push("analysis_scope must be frontend, backend, or both.");
|
|
29
30
|
if (targetIndex >= 0 && !["frontend", "backend", "both"].includes(expectedTarget)) errors.push("--target must be frontend, backend, or both.");
|
|
@@ -31,27 +32,20 @@ else if (expectedTarget && scope !== expectedTarget) errors.push(`analysis_scope
|
|
|
31
32
|
if (!["pending", "complete"].includes(status)) errors.push("requirement_status must be pending or complete.");
|
|
32
33
|
if (!allowPending && status !== "complete") errors.push("Final Product Requirement must be complete.");
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
const value = metadata(text, name);
|
|
36
|
-
if (!value || ["inline", "none"].includes(value)) return value;
|
|
37
|
-
return resolve(dirname(path), value);
|
|
38
|
-
}
|
|
39
|
-
for (const name of ["source_requirement", "source_product_analysis", "source_clarification"]) {
|
|
40
|
-
const value = sourcePath(name);
|
|
41
|
-
if (!value) errors.push(`${name} is required.`);
|
|
42
|
-
else if (!["inline", "none"].includes(value) && !existsSync(value)) errors.push(`${name} does not exist: ${value}`);
|
|
43
|
-
}
|
|
44
|
-
for (const name of ["source_product_analysis", "source_clarification"]) {
|
|
45
|
-
const value = sourcePath(name);
|
|
46
|
-
if (value && !["inline", "none"].includes(value) && dirname(value) !== dirname(path)) errors.push(`${name} must reference an artifact in the same requirement directory.`);
|
|
47
|
-
}
|
|
48
|
-
|
|
35
|
+
validateNoImplementationLeakage(text, errors);
|
|
49
36
|
assertHeadings(text, 2, ["需求概述", "业务目标", "需求范围", "业务规则", "决策追溯"], errors, "Product Requirement");
|
|
50
37
|
const range = section(text, 2, "需求范围") ?? "";
|
|
51
|
-
assertHeadings(range, 3, ["
|
|
52
|
-
if (
|
|
53
|
-
|
|
38
|
+
assertHeadings(range, 3, ["已确认范围", "非目标"], errors, "需求范围");
|
|
39
|
+
if (/^###\s+(?:\d+(?:\.\d+)*[.、]?\s*)?默认假设\s*$/m.test(range)) errors.push("Product Requirement must not contain 默认假设.");
|
|
40
|
+
const pendingSection = section(range, 3, "未决事项");
|
|
41
|
+
if (status === "complete" && pendingSection) errors.push("Complete Product Requirement must not contain 未决事项.");
|
|
42
|
+
if (status === "pending") assertHeadings(range, 3, ["未决事项"], errors, "Pending Product Requirement");
|
|
43
|
+
if (status === "complete" && /(?:pending-(?:blocking|non-blocking)|未形成|尚未确认|未决)/i.test(text)) errors.push("Complete Product Requirement must not contain unconfirmed product behavior.");
|
|
44
|
+
if (/^##\s+(?:\d+[.、]?\s*)?(?:用户角色|验收标准汇总|前后端契约|Open Questions|测试建议|边界 case|边界Case)\s*$/im.test(text)) {
|
|
45
|
+
errors.push("Product Requirement must not contain standalone 用户角色, 验收标准汇总, 前后端契约, Open Questions, 测试建议, or 边界 case sections.");
|
|
46
|
+
}
|
|
54
47
|
|
|
48
|
+
const acceptanceIds = new Set();
|
|
55
49
|
function validateDomain(domain) {
|
|
56
50
|
const frontend = domain === "frontend";
|
|
57
51
|
const title = frontend ? "前端" : "后端";
|
|
@@ -65,16 +59,29 @@ function validateDomain(domain) {
|
|
|
65
59
|
if (!stories.length) errors.push(`${storyHeading} must contain at least one ${prefix}-* story.`);
|
|
66
60
|
validateStorySpecCoverage(stories, specs, errors, `${title} scope`);
|
|
67
61
|
const storyFields = frontend ? ["角色", "目标", "价值", "入口", "验收标准"] : ["系统能力", "使用方", "业务价值", "触发方式", "验收标准"];
|
|
68
|
-
const specFields = frontend ? ["页面/组件", "展示内容", "交互动作", "UI 状态", "表单校验", "权限可见性", "边界处理"] : ["输入语义", "输出语义", "数据读写", "权限规则", "业务规则", "安全要求", "幂等与并发", "错误与边界"];
|
|
62
|
+
const specFields = frontend ? ["页面/组件", "页面路由", "展示内容", "交互动作", "UI 状态", "表单校验", "权限可见性", "边界处理"] : ["输入语义", "输出语义", "数据读写", "权限规则", "业务规则", "安全要求", "幂等与并发", "错误与边界"];
|
|
69
63
|
for (const story of stories) {
|
|
70
64
|
for (const name of storyFields) if (!field(story.text, name)) errors.push(`${story.id} is missing story field ${name}.`);
|
|
71
|
-
|
|
65
|
+
const trigger = field(story.text, "触发方式") ?? "";
|
|
66
|
+
const apiTrigger = /^API[((](?:Web|Remote|Web\s*\+\s*Remote)[))]$/i.test(trigger);
|
|
67
|
+
if (!frontend && !apiTrigger && !/^(?:定时任务|事件|消息|内部调用|数据迁移)$/i.test(trigger)) errors.push(`${story.id} 触发方式 is invalid; API must declare Web, Remote, or Web + Remote.`);
|
|
72
68
|
const spec = specs.find((item) => item.id === story.id);
|
|
73
69
|
if (!spec) continue;
|
|
74
70
|
for (const name of specFields) if (!field(spec.text, name)) errors.push(`${spec.id} output specification is missing field ${name}.`);
|
|
71
|
+
if (frontend) {
|
|
72
|
+
const route = field(spec.text, "页面路由") ?? "";
|
|
73
|
+
const directRoute = /^`?\/[^`\s]+`?(?:\s|$|[;;,,])/.test(route);
|
|
74
|
+
const embeddedRoute = /^不适用;.+`?\/[^`\s]+`?.*页面/.test(route);
|
|
75
|
+
if (!directRoute && !embeddedRoute) errors.push(`${spec.id} 页面路由 must start with / or use 不适用; and name its containing page.`);
|
|
76
|
+
if (/(?:route config|middleware|路由注册文件|路由组件)/i.test(route)) errors.push(`${spec.id} 页面路由 must describe product routing, not implementation files or framework components.`);
|
|
77
|
+
}
|
|
75
78
|
const criteria = acceptanceBlocks(spec, acPrefix);
|
|
76
79
|
if (!criteria.length) errors.push(`${spec.id} output specification must contain at least one ${acPrefix}-* acceptance criterion.`);
|
|
77
|
-
for (const item of criteria)
|
|
80
|
+
for (const item of criteria) {
|
|
81
|
+
if (acceptanceIds.has(item.id)) errors.push(`Duplicate acceptance criterion ID: ${item.id}.`);
|
|
82
|
+
acceptanceIds.add(item.id);
|
|
83
|
+
validateAcceptance(item.text, item.id, errors);
|
|
84
|
+
}
|
|
78
85
|
const referenced = [...(field(story.text, "验收标准") ?? "").matchAll(new RegExp(`${acPrefix}-\\d{3,}`, "g"))].map((item) => item[0]).sort();
|
|
79
86
|
const actual = criteria.map((item) => item.id).sort();
|
|
80
87
|
if (referenced.join() !== actual.join()) errors.push(`${story.id} acceptance references must match its output specification criteria.`);
|
|
@@ -86,12 +93,17 @@ if (scope === "backend" || scope === "both") validateDomain("backend");
|
|
|
86
93
|
if (scope === "frontend" && /(?:^##\s+.*后端|^###\s+BE-US-)/m.test(text)) errors.push("frontend scope must not contain backend sections or stories.");
|
|
87
94
|
if (scope === "backend" && /(?:^##\s+.*前端|^###\s+FE-US-)/m.test(text)) errors.push("backend scope must not contain frontend sections or stories.");
|
|
88
95
|
|
|
89
|
-
const clarificationSource =
|
|
90
|
-
if (
|
|
96
|
+
const clarificationSource = join(dirname(path), "requirement-clarification.md");
|
|
97
|
+
if (!existsSync(clarificationSource)) {
|
|
98
|
+
errors.push("Product Requirement requires requirement-clarification.md in the same requirement directory.");
|
|
99
|
+
} else {
|
|
91
100
|
const clarification = readFileSync(clarificationSource, "utf8");
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
const clarificationStatus = metadata(clarification, "clarification_status");
|
|
102
|
+
if (clarificationStatus !== status) errors.push("Product Requirement and source clarification must have the same pending/complete status.");
|
|
103
|
+
if (status === "complete") {
|
|
104
|
+
const markers = [...clarification.matchAll(/^-\s*决策标记[::]\s*(DEC-Q-\d{3,})/gm)].map((item) => item[1]);
|
|
105
|
+
for (const marker of markers) if (!text.includes(marker)) errors.push(`${marker} from source clarification is missing from Product Requirement.`);
|
|
106
|
+
}
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
printResult("Product Requirement", path, errors);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { assertHeadings, canonical, field, headings, loadMarkdown, metadata, printResult, section, validateArtifactLocation } from "./validation-helpers.mjs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { assertHeadings, canonical, field, headings, loadMarkdown, metadata, printResult, section, validateArtifactLocation, validateFrontmatter } from "./validation-helpers.mjs";
|
|
6
5
|
|
|
7
6
|
const args = process.argv.slice(2);
|
|
8
7
|
const allowPending = args.includes("--allow-pending");
|
|
@@ -20,46 +19,55 @@ try {
|
|
|
20
19
|
} catch (error) { console.error(error.message); process.exit(2); }
|
|
21
20
|
|
|
22
21
|
const errors = [];
|
|
22
|
+
validateFrontmatter(clarification.text, ["artifact_version", "artifact_type", "requirement_id", "analysis_scope", "clarification_status", "clarification_rounds"], errors, "Requirement Clarification");
|
|
23
23
|
validateArtifactLocation(clarification, errors, "requirement-clarification.md");
|
|
24
24
|
const scope = metadata(clarification.text, "analysis_scope");
|
|
25
25
|
const status = metadata(clarification.text, "clarification_status");
|
|
26
26
|
const clarificationRounds = Number(metadata(clarification.text, "clarification_rounds"));
|
|
27
|
-
if (metadata(clarification.text, "artifact_version") !== "
|
|
27
|
+
if (metadata(clarification.text, "artifact_version") !== "4.0") errors.push("artifact_version must be 4.0.");
|
|
28
28
|
if (metadata(clarification.text, "artifact_type") !== "requirement-clarification") errors.push("artifact_type must be requirement-clarification.");
|
|
29
29
|
if (!["frontend", "backend", "both"].includes(scope)) errors.push("analysis_scope must be frontend, backend, or both.");
|
|
30
30
|
if (!["pending", "complete"].includes(status)) errors.push("clarification_status must be pending or complete.");
|
|
31
|
-
if (!Number.isInteger(clarificationRounds) || clarificationRounds < 0
|
|
31
|
+
if (!Number.isInteger(clarificationRounds) || clarificationRounds < 0) errors.push("clarification_rounds must be a non-negative integer.");
|
|
32
32
|
if (!allowPending && status !== "complete") errors.push("Final Requirement Clarification must be complete.");
|
|
33
|
+
const requirementStatus = metadata(requirement.text, "requirement_status");
|
|
34
|
+
if (status !== requirementStatus) errors.push("Requirement Clarification and Product Requirement must have the same pending/complete status.");
|
|
33
35
|
if (scope !== metadata(analysis.text, "analysis_scope")) errors.push("analysis_scope must match Product Analysis.");
|
|
36
|
+
if (scope !== metadata(requirement.text, "analysis_scope")) errors.push("analysis_scope must match Product Requirement.");
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
if (resolveRef(source) !== analysis.path) errors.push("source_product_analysis must reference the supplied Product Analysis.");
|
|
39
|
-
if (resolveRef(target) !== requirement.path) errors.push("target_product_requirement must reference the supplied Product Requirement.");
|
|
40
|
-
if (source && dirname(resolveRef(source)) !== dirname(clarification.path)) errors.push("source_product_analysis must be in the same requirement directory.");
|
|
41
|
-
if (target && dirname(resolveRef(target)) !== dirname(clarification.path)) errors.push("target_product_requirement must be in the same requirement directory.");
|
|
42
|
-
if (source && !existsSync(resolveRef(source))) errors.push(`source_product_analysis does not exist: ${resolveRef(source)}`);
|
|
43
|
-
if (target && !existsSync(resolveRef(target))) errors.push(`target_product_requirement does not exist: ${resolveRef(target)}`);
|
|
38
|
+
if (dirname(analysis.path) !== dirname(clarification.path) || dirname(requirement.path) !== dirname(clarification.path)) errors.push("All requirement artifacts must be in the same requirement directory.");
|
|
39
|
+
const requirementId = metadata(clarification.text, "requirement_id");
|
|
40
|
+
if (requirementId !== metadata(analysis.text, "requirement_id") || requirementId !== metadata(requirement.text, "requirement_id")) errors.push("requirement_id must match across all requirement artifacts.");
|
|
44
41
|
|
|
45
42
|
const analysisStatus = metadata(analysis.text, "analysis_status");
|
|
46
43
|
const questionBlocks = headings(clarification.text, 3).filter((item) => /^Q-\d{3,}\s+/.test(item.title));
|
|
44
|
+
const sourceSection = section(clarification.text, 2, questionBlocks.length ? "澄清来源" : "来源") ?? "";
|
|
45
|
+
const recordedSourceIdentity = field(sourceSection, "原始需求身份") ?? "";
|
|
46
|
+
const analysisSourceIdentity = field(section(analysis.text, 2, "原始需求") ?? "", "原始需求身份") ?? "";
|
|
47
|
+
if (!/^(?:inline|file):sha256:[a-f0-9]{64}$/.test(recordedSourceIdentity)) errors.push("Clarification source must contain a valid 原始需求身份.");
|
|
48
|
+
else if (recordedSourceIdentity !== analysisSourceIdentity) errors.push("原始需求身份 must match Product Analysis.");
|
|
49
|
+
if (/(?:default-confirmed|confirmed-default)/.test(clarification.text)) errors.push("Requirement Clarification must not use default-confirmed or confirmed-default.");
|
|
47
50
|
|
|
48
51
|
if (!questionBlocks.length) {
|
|
52
|
+
if (status !== "complete") errors.push("Compact no-clarification-required artifacts must be complete.");
|
|
49
53
|
if (clarificationRounds !== 0) errors.push("Compact clarification must set clarification_rounds to 0.");
|
|
50
54
|
if (analysisStatus !== "no-clarification-required") errors.push("Compact clarification is allowed only when Product Analysis is no-clarification-required.");
|
|
51
55
|
const required = ["澄清结论", "来源", "合并结果"];
|
|
52
56
|
assertHeadings(clarification.text, 2, required, errors, "Compact Requirement Clarification");
|
|
53
57
|
for (const heading of headings(clarification.text, 2)) if (!required.includes(canonical(heading.title))) errors.push(`Compact Requirement Clarification must not contain section ${canonical(heading.title)}.`);
|
|
54
|
-
|
|
58
|
+
const conclusion = section(clarification.text, 2, "澄清结论") ?? "";
|
|
59
|
+
if (!/状态[::]\s*no-clarification-required/.test(conclusion)) errors.push("Compact clarification must declare no-clarification-required.");
|
|
60
|
+
if (status === "complete" && !/^[ \t]*-[ \t]*内容补充[::][ \t]*用户已确认无需补充\s*$/m.test(conclusion)) {
|
|
61
|
+
errors.push("Complete compact clarification must record 内容补充:用户已确认无需补充.");
|
|
62
|
+
}
|
|
55
63
|
if (/\b(?:BR|Q|DEC-Q)-\d{3,}\b/.test(clarification.text)) errors.push("Compact clarification must not fabricate BR, Q, or DEC-Q markers.");
|
|
56
64
|
} else {
|
|
57
|
-
if (clarificationRounds < 1
|
|
65
|
+
if (clarificationRounds < 1) errors.push("Question-based clarification must set clarification_rounds to a positive integer.");
|
|
58
66
|
if (analysisStatus !== "ready-for-clarification") errors.push("Question records require Product Analysis status ready-for-clarification.");
|
|
59
67
|
assertHeadings(clarification.text, 2, ["澄清来源", "决策分支", "问题记录", "决策索引"], errors, "Requirement Clarification");
|
|
60
68
|
const branchSection = section(clarification.text, 2, "决策分支") ?? "";
|
|
61
69
|
const branchIds = [...new Set(branchSection.match(/\bBR-\d{3,}\b/g) ?? [])];
|
|
62
|
-
if (branchIds.length <
|
|
70
|
+
if (branchIds.length < 1) errors.push("Question-based clarification must define at least one top-level BR-* branch.");
|
|
63
71
|
if (status === "complete") {
|
|
64
72
|
const unresolved = branchSection.split(/\r?\n/).filter((line) => /\|\s*BR-\d{3,}\s*\|/.test(line) && !/\|\s*resolved\s*\|\s*$/.test(line));
|
|
65
73
|
if (unresolved.length) errors.push("Complete clarification requires every branch to be resolved.");
|
|
@@ -74,25 +82,28 @@ if (!questionBlocks.length) {
|
|
|
74
82
|
const priority = field(block.text, "优先级");
|
|
75
83
|
const impactScope = field(block.text, "影响范围");
|
|
76
84
|
const answer = field(block.text, "用户回答");
|
|
85
|
+
const finalDecision = field(block.text, "最终决策");
|
|
77
86
|
const decisionStatus = field(block.text, "状态");
|
|
78
87
|
const decisionSource = field(block.text, "决策来源");
|
|
79
88
|
if (!branchIds.includes(branch)) errors.push(`${id} 分支 must reference a defined BR-* branch.`);
|
|
80
89
|
if (!Number.isInteger(round) || round < 1 || round > clarificationRounds) errors.push(`${id} 澄清轮次 must be between 1 and clarification_rounds.`);
|
|
81
90
|
if (!["P0", "P1", "P2"].includes(priority)) errors.push(`${id} 优先级 must be P0, P1, or P2.`);
|
|
82
91
|
if (!["common", "frontend", "backend", "both"].includes(impactScope)) errors.push(`${id} 影响范围 is invalid.`);
|
|
83
|
-
if (!["confirmed", "
|
|
84
|
-
if (
|
|
92
|
+
if (!["confirmed", "pending-blocking", "pending-non-blocking"].includes(decisionStatus)) errors.push(`${id} 状态 is invalid.`);
|
|
93
|
+
if (decisionSource !== "user") errors.push(`${id} 决策来源 must be user; source requirements and code facts must not be represented as Q-* decisions.`);
|
|
85
94
|
const marker = field(block.text, "决策标记");
|
|
86
95
|
if (marker !== `DEC-${id}`) errors.push(`${id} 决策标记 must be DEC-${id}.`);
|
|
87
96
|
if (markers.has(marker)) errors.push(`Duplicate decision marker: ${marker}.`);
|
|
88
97
|
markers.add(marker);
|
|
89
|
-
if (decisionSource === "code-evidence" && !field(block.text, "代码证据")) errors.push(`${id} code-evidence decision requires 代码证据.`);
|
|
90
98
|
if (decisionStatus === "pending-non-blocking" && !field(block.text, "未确认影响")) errors.push(`${id} pending-non-blocking decision requires 未确认影响.`);
|
|
91
|
-
if (status === "complete" &&
|
|
99
|
+
if (status === "complete" && (decisionStatus !== "confirmed" || decisionSource !== "user" || /^(?:未回答|待确认|无)$/.test(answer ?? ""))) errors.push(`${id} must be confirmed by an explicit user answer before clarification can be complete.`);
|
|
100
|
+
if (status === "complete" && /^(?:未形成|未回答|待确认|尚未确认|无)$/.test(finalDecision ?? "")) errors.push(`${id} must contain a formed final decision before clarification can be complete.`);
|
|
92
101
|
if (status === "complete" && marker && !requirement.text.includes(marker)) errors.push(`${marker} is missing from Product Requirement decision traceability.`);
|
|
93
102
|
if (!(section(clarification.text, 2, "决策索引") ?? "").includes(marker ?? "__missing__")) errors.push(`${marker ?? id} is missing from 决策索引.`);
|
|
94
103
|
}
|
|
104
|
+
if (status === "complete" && !/^[ \t]*-[ \t]*共同理解[::][ \t]*已确认\s*$/m.test(section(clarification.text, 2, "决策索引") ?? "")) {
|
|
105
|
+
errors.push("Complete question-based clarification must record 共同理解:已确认 in 决策索引.");
|
|
106
|
+
}
|
|
95
107
|
}
|
|
96
108
|
|
|
97
|
-
if (status === "complete" && metadata(requirement.text, "requirement_status") !== "complete") errors.push("Complete clarification requires a complete Product Requirement.");
|
|
98
109
|
printResult("Requirement Clarification", clarification.path, errors);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { basename, dirname,
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
export function loadMarkdown(fileArg, label = "artifact") {
|
|
5
5
|
const path = resolve(fileArg);
|
|
@@ -14,6 +14,29 @@ export function frontmatter(text) {
|
|
|
14
14
|
return text.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] ?? "";
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
export function validateFrontmatter(text, allowedKeys, errors, owner) {
|
|
18
|
+
const block = frontmatter(text);
|
|
19
|
+
if (!block) {
|
|
20
|
+
errors.push(`${owner} must contain YAML frontmatter.`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const keys = [];
|
|
24
|
+
for (const line of block.split(/\r?\n/)) {
|
|
25
|
+
if (!line.trim()) continue;
|
|
26
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_-]*):[ \t]*(.*)$/);
|
|
27
|
+
if (!match) {
|
|
28
|
+
errors.push(`${owner} frontmatter must contain only top-level scalar fields.`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
keys.push(match[1]);
|
|
32
|
+
}
|
|
33
|
+
for (const key of new Set(keys)) {
|
|
34
|
+
if (keys.filter((value) => value === key).length > 1) errors.push(`${owner} frontmatter contains duplicate field ${key}.`);
|
|
35
|
+
if (!allowedKeys.includes(key)) errors.push(`${owner} frontmatter contains unsupported field ${key}.`);
|
|
36
|
+
}
|
|
37
|
+
for (const key of allowedKeys) if (!keys.includes(key)) errors.push(`${owner} frontmatter is missing field ${key}.`);
|
|
38
|
+
}
|
|
39
|
+
|
|
17
40
|
export function metadata(text, name) {
|
|
18
41
|
const block = frontmatter(text);
|
|
19
42
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -100,17 +123,21 @@ export function validateAcceptance(block, owner, errors) {
|
|
|
100
123
|
if (!/(?:不得|不应|禁止|保留|恢复|重试|兜底|回滚|disabled)/.test(block)) {
|
|
101
124
|
errors.push(`${owner} must include an observable protection or recovery result.`);
|
|
102
125
|
}
|
|
126
|
+
if (/(?:功能正常|应正常展示|展示正确|接口可用|数据正确|符合预期|妥善处理|合理处理|无异常情况|没有需要处理的异常场景|无需处理失败)/.test(block)) {
|
|
127
|
+
errors.push(`${owner} must not use vague acceptance language.`);
|
|
128
|
+
}
|
|
103
129
|
}
|
|
104
130
|
|
|
105
|
-
export function
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
131
|
+
export function validateNoImplementationLeakage(text, errors, owner = "Product Requirement") {
|
|
132
|
+
if (/\bKB-FACT-\d+\b/.test(text)) errors.push(`${owner} must not contain KB-FACT-* markers.`);
|
|
133
|
+
if (/\bCODE-FACT-\d+\b/.test(text)) errors.push(`${owner} must not contain CODE-FACT-* markers.`);
|
|
134
|
+
if (/(?:^|[\s`'(])(?:\.\/|\.\.\/)?(?:src|app|packages|lib|internal|cmd|pkg)\/[^\s`')]+/m.test(text)) {
|
|
135
|
+
errors.push(`${owner} must not contain repository file paths.`);
|
|
136
|
+
}
|
|
137
|
+
if (/\b[A-Z][A-Za-z0-9]*(?:Controller|Service|Repository|Handler|Middleware)\b/.test(text)) {
|
|
138
|
+
errors.push(`${owner} must not contain code-level class or component symbols.`);
|
|
139
|
+
}
|
|
140
|
+
if (/证据位置/.test(text)) errors.push(`${owner} must not contain 证据位置.`);
|
|
114
141
|
}
|
|
115
142
|
|
|
116
143
|
export function assertHeadings(text, level, required, errors, owner) {
|
|
@@ -132,23 +159,15 @@ export function printResult(label, path, errors) {
|
|
|
132
159
|
|
|
133
160
|
export function validateArtifactLocation(artifact, errors, expectedName) {
|
|
134
161
|
const requirementId = metadata(artifact.text, "requirement_id");
|
|
135
|
-
const projectRootValue = metadata(artifact.text, "project_root");
|
|
136
162
|
if (!requirementId || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(requirementId)) {
|
|
137
163
|
errors.push("requirement_id must use lowercase letters, digits, and single hyphens.");
|
|
138
164
|
return;
|
|
139
165
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (!existsSync(projectRoot) || !statSync(projectRoot).isDirectory()) {
|
|
146
|
-
errors.push(`project_root does not resolve to an existing directory: ${projectRoot}`);
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
const expected = resolve(join(projectRoot, "docs", "product-analysis", requirementId));
|
|
150
|
-
if (dirname(artifact.path) !== expected) {
|
|
151
|
-
errors.push(`Artifact must be located under ${expected}.`);
|
|
166
|
+
const artifactDir = dirname(artifact.path);
|
|
167
|
+
const productAnalysisDir = dirname(artifactDir);
|
|
168
|
+
const docsDir = dirname(productAnalysisDir);
|
|
169
|
+
if (basename(artifactDir) !== requirementId || basename(productAnalysisDir) !== "product-analysis" || basename(docsDir) !== "docs") {
|
|
170
|
+
errors.push(`Artifact must be located under <project-root>/docs/product-analysis/${requirementId}.`);
|
|
152
171
|
}
|
|
153
172
|
if (expectedName && basename(artifact.path) !== expectedName) {
|
|
154
173
|
errors.push(`Artifact filename must be ${expectedName}.`);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--canvas: #f7f7f4;--canvas-soft: #fafaf7;--surface: #ffffff;--surface-muted: #f0efe9;--ink: #26251e;--body: #5a5852;--muted: #807d72;--muted-soft: #a09c92;--hairline: #e6e5e0;--hairline-strong: #cfcdc4;--orange: #f54e00;--orange-active: #d04200;--orange-soft: color-mix(in srgb, var(--orange) 12%, white);--blue: #3f6ea4;--green: #1f8a65;--amber: #a66a00;--red: #c72d53;--peach: #f1d8cb;--mint: #d8ead5;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-5: 20px;--space-6: 24px;--space-8: 32px;--space-12: 48px;--radius-sm: 6px;--radius-md: 8px;--radius-lg: 12px;--radius-xl: 16px;--radius-pill: 999px;--transition-fast: .16s ease;--transition-base: .22s ease;--ease-out: cubic-bezier(.22, 1, .36, 1);--shadow-sm: 0 1px 2px rgb(38 37 30 / 5%);--shadow-panel: 0 1px 2px rgb(38 37 30 / 4%), 0 8px 24px rgb(38 37 30 / 3%);--shadow-soft: 0 10px 30px rgb(38 37 30 / 6%);--shadow-lg: 0 16px 44px rgb(38 37 30 / 10%);--shell-max: 1680px;--text-xs: 11px;--text-sm: 12px;--text-md: 13px;--text-base: 14px;--text-lg: 16px;--text-xl: 20px;--text-2xl: 26px;--font-mono: "JetBrains Mono", "SFMono-Regular", Consolas, "Segoe UI Mono", monospace;--bg: var(--canvas);--border: var(--hairline);--accent: var(--orange);--accent-active: var(--orange-active);--danger: var(--red);--success: var(--green);--warning: var(--amber);--info: var(--blue);--text-muted: var(--muted);--surface-raised: var(--surface);--surface-hover: var(--surface-muted);--surface-sunken: var(--canvas-soft);--oc-tree-guide: 14px;color-scheme:light;font-family:Segoe UI,PingFang SC,Hiragino Sans GB,Noto Sans SC,system-ui,-apple-system,sans-serif;line-height:1.5}*{box-sizing:border-box}html{background:radial-gradient(1200px 480px at 8% -10%,rgb(241 216 203 / 45%),transparent 55%),radial-gradient(900px 420px at 100% 0%,rgb(216 234 213 / 35%),transparent 50%),var(--canvas);min-height:100%}body{margin:0;min-height:100vh;min-width:320px;background:transparent;color:var(--ink);font-size:14px}button,input,select,textarea{font:inherit}a{color:inherit}::selection{background:color-mix(in srgb,var(--orange) 18%,white)}.oc-messages,.oc-session-scroll,.oc-tree-scroll,.oc-process-timeline,.oc-tools-catalog-body,.oc-runtime-context-body,.inspect-split-panel{scrollbar-width:thin;scrollbar-color:var(--hairline-strong) transparent}.oc-messages::-webkit-scrollbar,.oc-session-scroll::-webkit-scrollbar,.oc-tree-scroll::-webkit-scrollbar,.oc-process-timeline::-webkit-scrollbar,.oc-tools-catalog-body::-webkit-scrollbar,.oc-runtime-context-body::-webkit-scrollbar,.inspect-split-panel::-webkit-scrollbar{width:8px;height:8px}.oc-messages::-webkit-scrollbar-thumb,.oc-session-scroll::-webkit-scrollbar-thumb,.oc-tree-scroll::-webkit-scrollbar-thumb,.oc-process-timeline::-webkit-scrollbar-thumb,.oc-tools-catalog-body::-webkit-scrollbar-thumb,.oc-runtime-context-body::-webkit-scrollbar-thumb,.inspect-split-panel::-webkit-scrollbar-thumb{background:var(--hairline-strong);border-radius:999px;border:2px solid transparent;background-clip:content-box}.oc-messages::-webkit-scrollbar-track,.oc-session-scroll::-webkit-scrollbar-track,.oc-tree-scroll::-webkit-scrollbar-track,.oc-process-timeline::-webkit-scrollbar-track,.oc-tools-catalog-body::-webkit-scrollbar-track,.oc-runtime-context-body::-webkit-scrollbar-track,.inspect-split-panel::-webkit-scrollbar-track{background:transparent}code,.cmd,.kv dd code{font-family:var(--font-mono)}.embedded-operator-nav{position:sticky;top:0;z-index:40;display:flex;gap:6px;align-items:center;margin:0;padding:8px max(24px,calc((100vw - var(--shell-max)) / 2));border-bottom:1px solid var(--hairline);background:color-mix(in srgb,var(--canvas) 92%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);font-size:13px;font-weight:700;flex-shrink:0}.console-app{display:flex;flex-direction:column;min-height:100dvh}html:has(.console-app.is-chat-focus),body:has(.console-app.is-chat-focus){height:100%;overflow:hidden}.console-app.is-chat-focus{height:100dvh;max-height:100dvh;overflow:hidden}.console-shell{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;width:min(100% - 48px,var(--shell-max));margin:0 auto;padding:var(--space-5) 0 var(--space-12, 48px)}.embedded-operator-nav a,.embedded-operator-nav span{padding:6px 12px;border-radius:var(--radius-pill);text-decoration:none;color:var(--ink)}.embedded-operator-nav a:hover,.embedded-operator-nav a:focus-visible{background:var(--surface);color:var(--orange-active);outline:none}.embedded-operator-nav [aria-current=page]{background:var(--ink);color:#fff}.top-nav{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2);margin:0 0 var(--space-5);padding:6px;border:1px solid var(--hairline);border-radius:var(--radius-pill);background:color-mix(in srgb,var(--surface) 88%,transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);box-shadow:var(--shadow-panel)}.nav-link{appearance:none;display:inline-flex;align-items:center;min-height:34px;padding:0 14px;border:1px solid transparent;border-radius:var(--radius-pill);background:transparent;color:var(--body);font-size:13px;font-weight:600;text-decoration:none;cursor:pointer;transition:background-color var(--transition-fast),color var(--transition-fast),border-color var(--transition-fast),transform var(--transition-fast)}.nav-link:hover:not(:disabled),.nav-link:focus-visible:not(:disabled){background:var(--surface);color:var(--ink);outline:none}.nav-link-active{background:var(--ink);color:#fff}.nav-link-active:hover:not(:disabled),.nav-link-active:focus-visible:not(:disabled){background:var(--ink);color:#fff}.nav-link-external{margin-left:auto;border-color:var(--hairline);background:var(--surface);color:var(--orange-active)}.nav-link-external:hover:not(:disabled){border-color:var(--orange);background:var(--orange-soft);color:var(--orange-active)}.readiness{appearance:none;position:relative;display:inline-flex;align-items:center;gap:6px;margin-left:auto;min-height:34px;padding:0 28px 0 12px;border:1px solid var(--hairline);border-radius:var(--radius-pill);background:var(--surface);color:var(--ink);text-decoration:none;cursor:pointer;box-shadow:none;transition:background-color var(--transition-fast),border-color var(--transition-fast)}.readiness:hover{border-color:color-mix(in srgb,var(--ink) 18%,var(--hairline));background:color-mix(in srgb,var(--surface) 70%,var(--bg))}.readiness:focus-visible{outline:2px solid color-mix(in srgb,var(--orange) 45%,transparent);outline-offset:2px}.readiness:before{content:"";position:absolute;top:50%;right:10px;width:7px;height:7px;border-radius:50%;transform:translateY(-50%);background:var(--muted-soft)}.readiness[data-state=setup-required]{border-color:var(--hairline);background:var(--surface)}.readiness[data-state=setup-required]:before{background:var(--amber)}.readiness[data-state=ready]{border-color:var(--hairline);background:var(--surface)}.readiness[data-state=ready]:before{background:color-mix(in srgb,var(--green) 72%,white);box-shadow:0 0 0 3px color-mix(in srgb,var(--green) 12%,transparent)}.readiness[data-state=degraded]{border-color:var(--hairline);background:var(--surface)}.readiness[data-state=degraded]:before{background:var(--amber);box-shadow:0 0 0 3px color-mix(in srgb,var(--amber) 12%,transparent)}.readiness-label{margin:0;color:var(--muted);font-size:11px;font-weight:600;line-height:1;letter-spacing:.02em;text-transform:uppercase}.readiness strong{color:var(--ink);font-size:12px;font-weight:700;line-height:1}.readiness[data-state=ready] strong,.readiness[data-state=setup-required] strong,.readiness[data-state=degraded] strong{color:var(--ink)}.flash{display:flex;gap:var(--space-3);align-items:flex-start;margin:0 0 var(--space-4);padding:12px 16px;border:1px solid var(--hairline);border-left:3px solid var(--hairline-strong);border-radius:var(--radius-md);background:var(--surface);box-shadow:var(--shadow-panel);animation:flash-in .22s var(--ease-out)}.flash-error{border-color:color-mix(in srgb,var(--red) 35%,var(--hairline));border-left-color:var(--red);background:color-mix(in srgb,var(--red) 6%,var(--surface));color:var(--red)}.flash-info{border-color:color-mix(in srgb,var(--blue) 30%,var(--hairline));border-left-color:var(--blue);background:color-mix(in srgb,var(--blue) 6%,var(--surface));color:var(--body)}.flash-label{flex:0 0 auto;min-width:3.5rem;font-size:var(--text-xs);font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding-top:1px}.flash-body{margin:0;overflow-wrap:anywhere;font-size:var(--text-md);line-height:1.55}.muted{color:var(--muted)}.console-main{display:grid;gap:var(--space-4)}.console-main--fill{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:var(--space-3)}.console-shell.is-chat-focus{flex:1 1 auto;min-height:0;overflow:hidden;padding-bottom:var(--space-3)}.console-shell.is-chat-focus .top-nav{margin-bottom:var(--space-3);flex-shrink:0}.console-shell.is-chat-focus .console-main--fill{flex:1 1 auto;min-height:0;overflow:hidden}.panel--chat{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;padding:var(--space-3);overflow:hidden}.panel--chat .oc-shell{flex:1 1 auto;min-height:0;height:auto;overflow:hidden}.console-shell.is-chat-focus .panel--chat{padding:var(--space-2)}.console-shell.is-chat-focus .panel--chat .oc-shell{min-height:0;gap:var(--space-2);overflow:hidden}.inspect-split-panel{position:fixed;z-index:50;top:16px;right:16px;bottom:16px;width:min(420px,calc(100vw - 32px));display:grid;align-content:start;gap:var(--space-4);padding:var(--space-5);overflow:auto;border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface);box-shadow:var(--shadow-soft)}.inspect-split-nodes{display:grid;gap:6px;margin:0;padding:0;list-style:none;max-height:220px;overflow:auto}.inspect-split-nodes li{display:grid;grid-template-columns:1fr auto;gap:var(--space-2);align-items:center;padding:6px 8px;border:1px solid var(--hairline);border-radius:var(--radius-sm);background:var(--canvas-soft);font-size:12px}.inspect-split-nodes li.is-active{border-color:var(--orange);background:var(--orange-soft)}.inspect-split-nodes code{color:var(--muted);font-size:11px}.inspect-split-header{display:flex;align-items:start;justify-content:space-between;gap:var(--space-3)}.inspect-split-header h2,.inspect-split-panel h3{margin:0}.inspect-split-kicker,.inspect-split-id{margin:0;color:var(--muted);font-size:12px}.inspect-split-facts{display:grid;gap:var(--space-2);margin:0}.inspect-split-facts div{display:grid;grid-template-columns:7rem 1fr;gap:var(--space-2);padding-bottom:var(--space-2);border-bottom:1px solid var(--hairline)}.inspect-split-facts dt{color:var(--muted)}.inspect-split-facts dd{margin:0;overflow-wrap:anywhere}.inspect-split-events{display:grid;gap:8px;margin:0;padding-left:18px;color:var(--body);font-size:12px}.panel{min-width:0;border:1px solid var(--hairline);background:color-mix(in srgb,var(--surface) 96%,transparent);border-radius:var(--radius-lg);padding:var(--space-6);box-shadow:var(--shadow-panel)}.panel h2{margin:0 0 var(--space-2);color:var(--ink);font-size:var(--text-xl);font-weight:700;letter-spacing:-.02em}.panel-lead{margin:0 0 var(--space-5);color:var(--muted);font-size:var(--text-md);line-height:1.55}.panel h3{margin:0 0 var(--space-3);color:var(--ink);font-size:15px;font-weight:700;letter-spacing:-.01em}.empty-state{border:1px dashed var(--hairline-strong);border-radius:var(--radius-lg);padding:var(--space-8) var(--space-6);background:var(--canvas-soft);color:var(--body);text-align:center}.empty-state .cta-row{justify-content:center}.empty-title{margin:0 0 var(--space-2);color:var(--ink);font-size:var(--text-lg);font-weight:700;letter-spacing:-.01em}.empty-state .muted{max-width:52ch;margin-left:auto;margin-right:auto}.checklist{margin:0 0 var(--space-4);padding:var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft);list-style:none;color:var(--body)}.checklist li{position:relative;padding:6px 0 6px 22px}.checklist li:before{content:"";position:absolute;left:0;top:12px;width:8px;height:8px;border-radius:50%;background:var(--orange);opacity:.75}.kv{display:grid;gap:var(--space-1);margin:0}.kv div{display:grid;grid-template-columns:9rem 1fr;gap:var(--space-3);padding:10px 0;border-bottom:1px solid var(--hairline)}.kv div:last-child{border-bottom:none}.kv dt{color:var(--muted);font-size:var(--text-sm);font-weight:600}.kv dd{margin:0;color:var(--ink);overflow-wrap:anywhere;font-variant-numeric:tabular-nums}code{font-size:.85rem;color:var(--ink)}.cmd{display:block;width:100%;margin:0;padding:var(--space-3) var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft);color:var(--ink);font-size:var(--text-sm);line-height:1.55;overflow-x:auto;white-space:pre-wrap;word-break:break-word;max-height:280px}.external-link{color:var(--orange);text-decoration:none;font-weight:600}.external-link:hover{text-decoration:underline}.error{color:var(--red)}.wizard-steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:var(--space-2);list-style:none;padding:0;margin:0 0 var(--space-5)}.wizard-steps li{position:relative;min-height:54px;display:grid;align-content:center;gap:3px;border:1px solid var(--hairline);border-radius:var(--radius-md);padding:9px 12px;background:var(--canvas-soft);color:var(--muted);font-size:var(--text-sm);font-weight:600;transition:border-color var(--transition-fast),background-color var(--transition-fast),color var(--transition-fast),box-shadow var(--transition-fast),transform var(--transition-fast)}.wizard-steps li[data-done=true]{border-color:color-mix(in srgb,var(--green) 35%,var(--hairline));background:color-mix(in srgb,var(--mint) 45%,var(--surface));color:var(--green)}.wizard-steps li[data-active=true]{border-color:var(--orange);background:var(--surface);color:var(--ink);box-shadow:0 0 0 3px var(--orange-soft),var(--shadow-panel);transform:translateY(-1px)}.wizard-steps .step-index{font-size:10px;font-weight:700;letter-spacing:.06em;font-variant-numeric:tabular-nums;color:var(--muted-soft)}.wizard-steps li[data-active=true] .step-index{color:var(--orange);opacity:1}.wizard-steps li[data-done=true] .step-index{color:inherit;opacity:.8}.wizard-steps .step-label{line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.field{display:grid;gap:var(--space-1);margin:0 0 var(--space-4);width:min(100%,520px)}.field span{font-size:12px;font-weight:600;color:var(--muted)}.field input,.field textarea,.field select{width:100%;border:1px solid var(--hairline-strong);border-radius:var(--radius-md);background:var(--surface);color:var(--ink);transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.field input{min-height:40px;padding:0 var(--space-3)}.field select{min-height:40px;padding:0 var(--space-3);cursor:pointer}.field textarea{min-height:120px;padding:var(--space-3);resize:vertical}.field input:focus-visible,.field textarea:focus-visible,.field select:focus-visible{outline:none;border-color:var(--orange);box-shadow:0 0 0 3px var(--orange-soft)}.field input:disabled,.field textarea:disabled,.field select:disabled{background:var(--surface-muted);color:var(--muted);cursor:not-allowed}.workflow-hint{margin:calc(var(--space-1) * -1) 0 var(--space-3);color:var(--muted);font-size:12px}.prd-drop-zone{position:relative;width:min(100%,720px);margin:0 0 var(--space-3);padding:var(--space-3);border:1px dashed var(--hairline-strong);border-radius:var(--radius-md);background:var(--surface);transition:border-color var(--transition-fast),background-color var(--transition-fast),box-shadow var(--transition-fast)}.prd-drop-zone.is-dragover{border-color:var(--orange);background:var(--orange-soft);box-shadow:0 0 0 3px var(--orange-soft)}.prd-upload-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2) var(--space-3);margin:0 0 var(--space-3)}.prd-upload-btn{display:inline-flex;align-items:center;cursor:pointer;margin:0}.prd-upload-btn.is-disabled,.prd-upload-btn:has(input:disabled){opacity:.55;cursor:not-allowed;pointer-events:none}.prd-upload-btn:focus-within{outline:none;box-shadow:0 0 0 3px var(--orange-soft)}.prd-upload-hint{font-size:12px}.prd-file-meta{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2) var(--space-3);margin:0 0 var(--space-3);padding:var(--space-2) var(--space-3);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface-muted);font-size:12px;color:var(--ink)}.prd-file-list{list-style:none;margin:0 0 var(--space-3);padding:0;display:grid;gap:var(--space-2)}.prd-file-list li{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--space-2);padding:var(--space-2) var(--space-3);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface-muted);font-size:12px}.prd-file-list li.is-primary{border-color:color-mix(in srgb,var(--orange) 40%,var(--hairline-strong))}.prd-file-item-name{display:inline-flex;flex-wrap:wrap;align-items:center;gap:var(--space-1);min-width:0}.prd-file-primary-tag{display:inline-flex;align-items:center;padding:0 6px;border-radius:999px;background:var(--orange-soft);color:var(--orange);font-size:11px;font-weight:700}.prd-file-item-actions{display:inline-flex;flex-wrap:wrap;gap:var(--space-1)}.prd-file-item-actions .btn,.prd-file-clear{min-height:28px;padding:0 var(--space-2);font-size:12px}.prd-drop-hint{margin:0 0 var(--space-3);font-size:13px;font-weight:600;color:var(--orange)}.prd-text-field{width:100%;margin-bottom:0}.prd-file-error{width:min(100%,720px);margin:0 0 var(--space-3);padding:var(--space-2) var(--space-3);border:1px solid color-mix(in srgb,var(--orange) 45%,var(--hairline-strong));border-radius:var(--radius-md);background:var(--orange-soft);color:var(--ink);font-size:13px}.meta-row{display:grid;gap:6px;margin:0 0 var(--space-4);padding:var(--space-3) var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft);font-size:13px}.meta-row code{font-size:12px}.cta-row,.recovery-cta-row{display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:center}.cta-row{margin-top:var(--space-3)}.cta-row .cmd{flex:1 1 100%}.wizard-body{display:grid;gap:var(--space-3);justify-items:stretch;animation:panel-in .24s ease}.wizard-body>div{display:grid;gap:var(--space-3);justify-items:stretch}.wizard-body .field{width:100%;max-width:640px}.wizard-body .cta-row{margin-top:var(--space-1)}.interview-card{width:100%;padding:var(--space-5);border:1px solid var(--hairline);border-radius:var(--radius-lg);background:linear-gradient(180deg,var(--surface),var(--canvas-soft));box-shadow:var(--shadow-panel)}.interview-q{margin:0 0 var(--space-2);color:var(--ink)}.btn,button{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:34px;padding:0 14px;border:1px solid var(--hairline-strong);border-radius:var(--radius-md);background:var(--surface);color:var(--ink);font-size:var(--text-md);font-weight:600;letter-spacing:.01em;cursor:pointer;transition:border-color var(--transition-fast),background-color var(--transition-fast),color var(--transition-fast),box-shadow var(--transition-fast),transform var(--transition-fast)}.btn:hover:not(:disabled),button:hover:not(:disabled){border-color:color-mix(in srgb,var(--ink) 18%,var(--hairline-strong));background:var(--canvas-soft);outline:none}.btn:focus-visible:not(:disabled),button:focus-visible:not(:disabled){outline:none;box-shadow:0 0 0 3px var(--orange-soft)}.btn:active:not(:disabled),button:active:not(:disabled){transform:translateY(1px)}.btn:disabled,button:disabled{opacity:.48;cursor:not-allowed;transform:none}.btn-primary,button.btn-primary{border-color:var(--orange);background:linear-gradient(180deg,var(--orange),var(--orange-active));color:#fff;font-weight:650;box-shadow:inset 0 1px #ffffff2e,0 6px 16px #f54e002e}.btn-primary:hover:not(:disabled),button.btn-primary:hover:not(:disabled){border-color:var(--orange-active);background:var(--orange-active);color:#fff;box-shadow:inset 0 1px #ffffff1f,0 8px 20px #f54e003d;transform:translateY(-1px)}.btn-primary:active:not(:disabled),button.btn-primary:active:not(:disabled){transform:translateY(0);box-shadow:0 2px 8px #f54e0033}.btn-secondary,button.btn-secondary{border-color:var(--hairline-strong);background:var(--surface);color:var(--ink);box-shadow:var(--shadow-sm)}.btn-secondary:hover:not(:disabled),button.btn-secondary:hover:not(:disabled){background:var(--canvas-soft)}.btn-ghost,button.btn-ghost{border-color:transparent;background:transparent;color:var(--body)}.btn-ghost:hover:not(:disabled),button.btn-ghost:hover:not(:disabled){background:var(--surface-muted);color:var(--ink)}.recovery-cta-row{margin-top:var(--space-3)}.recovery-confirm{margin-top:var(--space-3);padding:var(--space-4);border:1px solid color-mix(in srgb,var(--orange) 40%,var(--hairline));border-radius:var(--radius-md);background:color-mix(in srgb,var(--orange-soft) 55%,var(--surface))}.recovery-confirm h3{margin:0 0 var(--space-2);font-size:15px}.recovery-confirm .cta-row{margin-top:var(--space-3)}.recovery-report{margin-top:var(--space-3);padding:var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface)}.recovery-report-header{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);margin-bottom:var(--space-3)}.recovery-report-header h3{margin:0;font-size:15px}.recovery-report-facts{display:grid;gap:var(--space-2);margin:0 0 var(--space-3)}.recovery-report-facts div{display:grid;grid-template-columns:5.5rem 1fr;gap:var(--space-2)}.recovery-report-facts dt{color:var(--muted);font-size:12px}.recovery-report-facts dd{margin:0;overflow-wrap:anywhere}.recovery-steps{margin:.5rem 0 .75rem 1.25rem;padding:0;line-height:1.5}.recovery-lane{margin-top:var(--space-4);padding-top:var(--space-3);border-top:1px solid var(--hairline)}.recovery-lane h3{margin:0 0 .35rem;font-size:1rem}.recovery-cta-row button[disabled]{opacity:.4}@keyframes flash-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}@keyframes panel-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}@media(max-width:800px){.console-shell{width:min(100% - 24px,var(--shell-max));padding-top:var(--space-5)}.readiness,.nav-link-external{margin-left:0}.inspect-split-panel{inset:auto 0 0;width:100%;max-height:min(76vh,680px);border-radius:var(--radius-lg) var(--radius-lg) 0 0}.kv div{grid-template-columns:1fr}.wizard-steps{grid-template-columns:repeat(2,minmax(0,1fr))}}.oc-shell{display:flex;flex-direction:column;height:100%;min-height:0;gap:var(--space-3);position:relative;overflow:hidden}.oc-workspace{display:flex;flex:1 1 auto;min-height:0;gap:0;position:relative;overflow:hidden}.oc-main{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0;overflow:hidden}.oc-sidebar{flex:0 0 280px;width:280px;min-width:0;display:flex;flex-direction:column;gap:var(--space-2);margin-right:var(--space-3);padding:var(--space-2);overflow:hidden;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface)}.oc-sidebar.is-collapsed{flex:0 0 36px;width:36px;padding:6px;overflow:visible;align-items:center}.oc-sidebar-header-actions{display:inline-flex;align-items:center;gap:2px}.oc-sidebar-toggle{appearance:none;display:inline-grid;place-items:center;width:28px;height:28px;padding:0;border:1px solid transparent;border-radius:var(--radius-sm);background:transparent;color:var(--muted);cursor:pointer;transition:background-color var(--transition-fast),color var(--transition-fast),border-color var(--transition-fast)}.oc-sidebar-toggle:hover{color:var(--ink);background:color-mix(in srgb,var(--orange) 8%,var(--surface));border-color:var(--hairline)}.oc-sidebar-toggle:focus-visible{outline:2px solid color-mix(in srgb,var(--orange) 45%,transparent);outline-offset:1px}.oc-sidebar-toggle.is-collapsed{width:100%;height:28px}.oc-sidebar-section{display:flex;flex-direction:column;gap:6px;min-height:0}.oc-sidebar-section>header{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:13px;flex-shrink:0}.oc-sessions{flex:0 1 auto;max-height:min(34vh,320px)}.oc-session-scroll{min-height:0;max-height:min(28vh,260px);overflow:auto;padding:4px;border:1px solid var(--hairline);border-radius:var(--radius-md);background:linear-gradient(180deg,color-mix(in srgb,var(--canvas-soft) 70%,white),var(--canvas-soft))}.oc-session-group{display:flex;flex-direction:column;gap:2px}.oc-session-group>small{margin:4px 6px 2px;color:var(--muted-soft);font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.oc-session-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px;align-items:center;border-radius:6px;transition:background-color var(--transition-fast)}.oc-session-item:hover,.oc-session-item:focus-within{background:color-mix(in srgb,var(--orange) 8%,var(--surface))}.oc-session-item.is-active{background:var(--orange-soft)}.oc-session-main{min-width:0;padding:5px 6px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer}.oc-session-main strong,.oc-session-main span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.oc-session-main strong{font-size:12.5px;font-weight:650;line-height:1.25}.oc-session-main span{color:var(--muted-soft);font-size:10px;margin-top:1px;font-variant-numeric:tabular-nums}.oc-session-actions{display:none;align-items:center;gap:0;padding-right:2px}.oc-session-item:hover .oc-session-actions,.oc-session-item:focus-within .oc-session-actions,.oc-session-item.is-active .oc-session-actions{display:inline-flex}.oc-session-menu{padding:3px 4px;border:0;background:transparent;color:var(--muted);cursor:pointer;font:inherit;font-size:10px;white-space:nowrap}.oc-session-menu:hover{color:var(--ink)}.oc-session-delete{color:color-mix(in srgb,var(--red) 75%,var(--muted))}.oc-session-delete:hover{color:var(--red)}.oc-explorer{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--hairline);padding-top:var(--space-3);margin-top:2px}.oc-explorer-hint{margin:0 2px;color:var(--muted-soft);font-size:10.5px;letter-spacing:.01em}.oc-tree-scroll{flex:1 1 auto;min-height:120px;max-height:min(52vh,560px);overflow:auto;padding:4px;border:1px solid var(--hairline);border-radius:var(--radius-md);background:linear-gradient(180deg,color-mix(in srgb,var(--canvas-soft) 70%,white),var(--canvas-soft))}.oc-tree,.oc-tree ul{list-style:none;padding:0;margin:0}.oc-tree-node{position:relative}.oc-tree-row{appearance:none;display:grid;grid-template-columns:12px 14px minmax(0,1fr);align-items:center;gap:6px;width:100%;min-height:28px;margin:0;padding:3px 8px;border:0;border-radius:6px;background:transparent;color:var(--ink);text-align:left;cursor:pointer;transition:background-color var(--transition-fast),color var(--transition-fast)}.oc-tree-row:hover{background:color-mix(in srgb,var(--orange) 8%,var(--surface))}.oc-tree-row:focus-visible{outline:2px solid color-mix(in srgb,var(--orange) 45%,transparent);outline-offset:1px}.oc-tree-chevron{color:var(--muted-soft);transition:transform var(--transition-fast);transform:rotate(0)}.oc-tree-chevron.is-open{transform:rotate(90deg)}.oc-tree-chevron-spacer{width:12px;height:12px}.oc-tree-glyph{flex-shrink:0;color:var(--amber)}.oc-tree-glyph.is-folder-open{color:color-mix(in srgb,var(--orange) 70%,var(--amber))}.oc-tree-glyph.is-file{color:var(--muted)}.oc-tree-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12.5px;line-height:1.25;font-variant-numeric:tabular-nums}.oc-tree-dir .oc-tree-label{font-weight:650;color:var(--ink)}.oc-tree-file .oc-tree-label{font-family:JetBrains Mono,SFMono-Regular,Consolas,Segoe UI Mono,monospace;font-size:11.5px;font-weight:500;color:var(--body)}.oc-tree-node.is-dot .oc-tree-label{color:var(--muted-soft);font-weight:500}.oc-tree-node.is-dot .oc-tree-glyph{opacity:.7}.oc-tree-children{position:relative;margin:0}.oc-tree-children:before{content:"";position:absolute;top:0;bottom:2px;left:var(--oc-tree-guide, 14px);width:1px;background:color-mix(in srgb,var(--hairline-strong) 55%,transparent);pointer-events:none}.oc-tree-empty,.oc-sidebar-error{margin:8px 6px;color:var(--muted);font-size:12px;line-height:1.45}.oc-sidebar-error{color:var(--red)}.oc-governance{margin-top:auto;border-top:1px solid var(--hairline);padding-top:8px}.oc-governance-links{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px}.oc-governance-links button{min-height:28px;padding:4px 6px;border:1px solid var(--hairline);border-radius:var(--radius-sm);background:var(--surface);color:var(--muted);cursor:pointer;font:inherit;font-size:11px;font-weight:600;text-align:center}.oc-governance-links button:hover{color:var(--ink);border-color:color-mix(in srgb,var(--ink) 18%,var(--hairline))}.oc-governance-panel button{border:0;background:transparent;color:var(--muted);cursor:pointer;font:inherit;font-size:11px}.oc-governance-panel{position:absolute;z-index:10;left:282px;bottom:0;width:min(440px,calc(100vw - 320px));max-height:75%;overflow:auto;padding:12px;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface);box-shadow:var(--shadow-panel)}.oc-governance-panel header,.oc-governance-panel article,.oc-governance-panel label{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:5px 0}.oc-governance-panel small,.oc-governance-panel span{color:var(--muted);font-size:11px}.oc-governance-panel button:disabled{cursor:wait;opacity:.5}.oc-governance-error{color:var(--red);font-size:var(--text-sm)}.oc-model-provider{display:block!important;border-bottom:1px solid var(--hairline)}.oc-model-provider>div,.oc-model-row,.oc-model-row>div{display:flex;align-items:center;justify-content:space-between;gap:8px}.oc-model-row{padding:4px 0 4px 10px}.oc-model-form{display:grid;gap:6px;margin-top:10px}.oc-model-form input{min-width:0;border:1px solid var(--hairline);border-radius:var(--radius-sm);background:var(--surface);color:var(--ink);padding:6px 8px;font:inherit;font-size:12px}.oc-model-form button{justify-self:start}.oc-model-test-result{padding:6px 8px;border-radius:var(--radius-sm);background:var(--surface-muted);font-size:12px}.oc-file-preview{position:absolute;z-index:4;inset:0;display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface);box-shadow:var(--shadow-panel)}.oc-file-preview header{display:flex;align-items:center;gap:var(--space-2);padding:10px 12px;border-bottom:1px solid var(--hairline)}.oc-file-tabs{display:flex;min-width:0;gap:2px;overflow-x:auto}.oc-file-tabs button{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--muted);padding:4px 7px;cursor:pointer}.oc-file-tabs button.is-active{background:var(--surface-muted);color:var(--ink);font-weight:650}.oc-file-preview header span{flex:1;color:var(--muted);font-size:11px}.oc-file-preview pre{flex:1;min-height:0;margin:0;padding:var(--space-3);overflow:auto;font-size:12px;line-height:1.5;white-space:pre-wrap}.oc-file-preview-loading{position:absolute;z-index:5;right:12px;top:12px;padding:6px 8px;border-radius:var(--radius-sm);background:var(--surface-muted);color:var(--muted);font-size:12px}.oc-process{display:flex;flex-direction:column;flex:0 0 min(360px,42%);width:min(360px,42%);min-width:280px;min-height:0;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface);box-shadow:var(--shadow-panel);margin-left:var(--space-3);overflow:hidden;animation:panel-in .18s ease}.oc-turn-group{display:flex;flex-direction:column;gap:8px;margin-bottom:12px}.oc-process-inline{margin:0 0 4px 44px;max-width:min(720px,100%)}.oc-process-inline-summary{display:inline-flex;align-items:center;gap:6px;min-height:24px;padding:2px 0;border:none;background:transparent;color:var(--muted);cursor:pointer;font-size:12px;text-align:left}.oc-process-inline-summary:hover,.oc-process-inline-summary.is-open{color:var(--ink)}.oc-process-inline-summary.is-running{color:var(--accent, #2563eb)}.oc-process-inline-summary.is-error{color:var(--danger, #dc2626)}.oc-process-inline-summary .oc-tool-chevron{width:12px;height:12px;flex-shrink:0;transition:transform .15s ease}.oc-process-inline-summary.is-open .oc-tool-chevron{transform:rotate(90deg)}.oc-process-inline-body{display:flex;flex-direction:column;gap:8px;margin-top:8px}.oc-tool-duration{flex-shrink:0;font-size:11px;font-variant-numeric:tabular-nums;color:var(--muted)}.oc-tool-expand-result{margin-top:4px;font-size:12px}.oc-process-head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);padding:10px 12px;border-bottom:1px solid var(--hairline);flex-shrink:0}.oc-process-title{display:inline-flex;align-items:center;gap:8px;font-weight:700;font-size:13px;color:var(--ink)}.oc-process-title-mark{width:8px;height:8px;border-radius:50%;background:var(--orange)}.oc-process-count{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:18px;padding:0 6px;border-radius:var(--radius-pill);background:var(--surface-muted);color:var(--muted);font-size:11px;font-weight:650}.oc-process-close{font-size:12px}.oc-process-timeline{flex:1 1 auto;min-height:0;overflow-y:auto;padding:var(--space-3);display:flex;flex-direction:column;gap:0}.oc-process-empty{padding:var(--space-4);color:var(--muted);font-size:12.5px;line-height:1.5;text-align:center}.oc-process-item{display:grid;grid-template-columns:20px 52px minmax(0,1fr);gap:8px;align-items:start;padding:4px 0}.oc-process-rail{position:relative;display:grid;place-items:center;min-height:34px}.oc-process-rail:before{position:absolute;top:0;bottom:0;width:1px;background:var(--hairline);content:""}.oc-process-item.is-first .oc-process-rail:before{top:50%}.oc-process-item.is-last .oc-process-rail:before{bottom:50%}.oc-process-dot{position:relative;z-index:1;width:8px;height:8px;border-radius:50%;background:var(--surface);border:2px solid color-mix(in srgb,var(--orange) 55%,var(--hairline))}.oc-process-item.is-running .oc-process-dot{border-color:var(--orange-active);background:var(--orange-soft)}.oc-process-item.is-error .oc-process-dot{border-color:var(--red);background:color-mix(in srgb,var(--red) 18%,var(--surface))}.oc-process-time{padding-top:10px;font-size:11px;color:var(--muted-soft);font-variant-numeric:tabular-nums;white-space:nowrap}.oc-process-body{min-width:0}.oc-process-toggle{cursor:pointer;font:inherit}.oc-process-toggle.is-active{border-color:color-mix(in srgb,var(--orange) 40%,var(--hairline));background:color-mix(in srgb,var(--orange) 10%,var(--surface));color:var(--orange-active)}.oc-process-toggle.is-running{border-color:color-mix(in srgb,var(--orange) 40%,var(--hairline));color:var(--orange-active)}.oc-process-toggle.is-error{border-color:color-mix(in srgb,var(--red) 35%,var(--hairline));background:color-mix(in srgb,var(--red) 8%,var(--surface));color:var(--red)}.oc-process-summary{display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border:1px solid var(--hairline);border-radius:var(--radius-pill);background:var(--surface);color:var(--muted);font-size:11.5px;font-weight:650;cursor:pointer;font:inherit;max-width:min(420px,100%);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.oc-process-summary:hover,.oc-process-summary.is-open{border-color:color-mix(in srgb,var(--orange) 35%,var(--hairline));color:var(--orange-active)}.oc-process-summary.is-running{color:var(--orange-active);border-color:color-mix(in srgb,var(--orange) 40%,var(--hairline));background:var(--orange-soft)}.oc-process-summary.is-error{color:var(--red);border-color:color-mix(in srgb,var(--red) 35%,var(--hairline));background:color-mix(in srgb,var(--red) 8%,var(--surface))}.oc-process-summary.is-ok{color:var(--green);border-color:color-mix(in srgb,var(--green) 30%,var(--hairline))}@media(max-width:900px){.oc-sidebar{position:absolute;inset:0 auto 0 0;z-index:7;width:min(300px,calc(100% - 24px));margin-right:0;box-shadow:var(--shadow-soft)}.oc-sidebar.is-collapsed{position:static;width:auto}.oc-workspace.has-process .oc-process{position:absolute;top:0;right:0;bottom:0;z-index:8;width:min(360px,calc(100% - 24px));min-width:0;flex:none;margin-left:0;border-radius:var(--radius-md) 0 0 var(--radius-md);box-shadow:var(--shadow-soft)}}.oc-banner{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2) var(--space-3);padding:10px 14px;border:1px solid var(--hairline);border-radius:var(--radius-md);background:color-mix(in srgb,var(--surface) 94%,transparent);box-shadow:var(--shadow-panel)}.oc-shell>.oc-alert:first-child{margin-top:0}.oc-banner-title{display:inline-flex;align-items:center;gap:6px;font-weight:700;color:var(--ink)}.oc-banner-dot{width:8px;height:8px;border-radius:50%;background:var(--orange)}.oc-banner-body{color:var(--body);font-size:12.5px;line-height:1.45}.oc-banner-body strong{color:var(--ink)}.oc-cap-chips{display:inline-flex;flex-wrap:wrap;gap:6px;margin-left:auto;align-items:center}.oc-cap-chip{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border:1px solid color-mix(in srgb,var(--green) 30%,var(--hairline));border-radius:var(--radius-pill);background:color-mix(in srgb,var(--mint) 50%,var(--surface));color:var(--green);font-size:11.5px;font-weight:650}button.oc-cap-chip{font:inherit;cursor:pointer}.oc-tools-menu{position:relative}.oc-tools-menu--composer .oc-tools-catalog{top:auto;bottom:calc(100% + 8px)}.oc-tools-toggle.is-active{border-color:color-mix(in srgb,var(--orange) 40%,var(--hairline));background:color-mix(in srgb,var(--orange) 10%,var(--surface));color:var(--orange-active)}.oc-tools-catalog{position:absolute;top:calc(100% + 8px);right:0;z-index:20;width:min(420px,calc(100vw - 48px));max-height:min(480px,60vh);display:flex;flex-direction:column;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface);box-shadow:var(--shadow-soft);animation:panel-in .16s ease;overflow:hidden}.oc-tools-catalog-head{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--hairline);flex-shrink:0}.oc-tools-catalog-head strong{font-size:13px;color:var(--ink)}.oc-tools-catalog-meta{font-size:11.5px;color:var(--muted-soft)}.oc-tools-catalog-close{margin-left:auto;font-size:12px}.oc-tools-catalog-body{overflow-y:auto;padding:var(--space-3);display:flex;flex-direction:column;gap:var(--space-3)}.oc-tools-group-title{margin:0 0 8px;font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted-soft)}.oc-tools-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.oc-tools-item{padding:8px 10px;border:1px solid var(--hairline);border-radius:var(--radius-sm);background:color-mix(in srgb,var(--surface-muted) 55%,var(--surface))}.oc-tools-item-head{display:flex;align-items:center;gap:8px;margin-bottom:4px}.oc-tools-name{font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;font-size:12.5px;font-weight:650;color:var(--ink)}.oc-tools-kind{margin-left:auto;font-size:10.5px;font-weight:650;padding:1px 7px;border-radius:var(--radius-pill);color:var(--muted);background:var(--surface);border:1px solid var(--hairline)}.oc-tools-kind.is-explore,.oc-tools-kind.is-read{color:var(--green);border-color:color-mix(in srgb,var(--green) 28%,var(--hairline));background:color-mix(in srgb,var(--mint) 45%,transparent)}.oc-tools-kind.is-mutation{color:var(--orange-active);border-color:color-mix(in srgb,var(--orange) 35%,var(--hairline));background:var(--orange-soft)}.oc-tools-kind.is-long-running{color:var(--amber);border-color:color-mix(in srgb,var(--amber) 35%,var(--hairline));background:color-mix(in srgb,var(--amber) 10%,var(--surface))}.oc-tools-desc{margin:0;font-size:12px;line-height:1.45;color:var(--body)}.oc-tools-cli{margin:4px 0 0;font-size:11px;color:var(--muted-soft)}.oc-tools-cli code{font-size:11px;color:var(--muted)}.oc-alert{padding:10px 14px;border-radius:var(--radius-md);font-size:var(--text-md);line-height:1.5;animation:panel-in .18s var(--ease-out)}.oc-alert-warning{border:1px solid color-mix(in srgb,var(--amber) 35%,var(--hairline));border-left:3px solid var(--amber);background:color-mix(in srgb,var(--amber) 8%,var(--surface));color:var(--amber)}.oc-alert-error{border:1px solid color-mix(in srgb,var(--red) 35%,var(--hairline));border-left:3px solid var(--red);background:color-mix(in srgb,var(--red) 7%,var(--surface));color:var(--red)}.oc-messages{flex:1 1 auto;min-height:0;overflow-y:auto;padding:var(--space-3) var(--space-3) var(--space-2);display:flex;flex-direction:column;gap:var(--space-3)}.oc-messages.has-thread:before{content:"";flex:1 1 auto;min-height:0}.oc-messages.is-empty{justify-content:center;align-items:center;padding:var(--space-5) var(--space-4) var(--space-4);background:radial-gradient(640px 300px at 50% 28%,rgb(241 216 203 / 34%),transparent 68%),radial-gradient(520px 240px at 78% 78%,rgb(216 234 213 / 26%),transparent 62%)}.oc-main.is-landing{position:relative}.oc-day-sep{display:flex;align-items:center;gap:var(--space-3);color:var(--muted-soft);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;margin:var(--space-2) 0}.oc-day-sep:before,.oc-day-sep:after{content:"";flex:1;height:1px;background:var(--hairline)}.oc-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:0 1 auto;gap:var(--space-5);text-align:center;width:min(100%,680px);padding:var(--space-2) var(--space-2) var(--space-4);animation:oc-empty-in .28s ease both}@keyframes oc-empty-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@media(prefers-reduced-motion:reduce){.oc-empty{animation:none}}.oc-empty-hero{display:flex;flex-direction:column;align-items:center;gap:var(--space-3)}.oc-empty-icon{display:grid;place-items:center;width:56px;height:56px;border-radius:50%;background:linear-gradient(145deg,color-mix(in srgb,var(--orange) 18%,white),color-mix(in srgb,var(--mint) 35%,white));color:var(--orange-active);font-size:26px;font-weight:800;font-family:var(--font-mono, "JetBrains Mono", monospace);box-shadow:0 0 0 1px color-mix(in srgb,var(--orange) 18%,transparent)}.oc-empty-copy{display:flex;flex-direction:column;align-items:center;gap:var(--space-2)}.oc-empty h3{margin:0;font-size:20px;font-weight:700;letter-spacing:-.02em;color:var(--ink)}.oc-empty p{margin:0;max-width:48ch;color:var(--muted);font-size:13px;line-height:1.55}.oc-suggestions{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-2);width:100%}@media(max-width:560px){.oc-suggestions{grid-template-columns:1fr}}.oc-suggestion{appearance:none;display:flex;flex-direction:column;gap:5px;text-align:left;min-height:0;padding:14px 16px;border:1px solid var(--hairline);border-radius:var(--radius-lg);background:color-mix(in srgb,var(--surface) 88%,transparent);color:var(--ink);cursor:pointer;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);transition:border-color var(--transition-fast),background var(--transition-fast),transform var(--transition-fast),box-shadow var(--transition-fast)}.oc-suggestion:hover:not(:disabled){border-color:color-mix(in srgb,var(--orange) 45%,var(--hairline));background:var(--surface);box-shadow:0 0 0 3px var(--orange-soft),var(--shadow-panel);transform:translateY(-1px)}.oc-suggestion:disabled{opacity:.55;cursor:not-allowed}.oc-suggestion strong{font-size:var(--text-md);font-weight:700}.oc-suggestion span{color:var(--muted);font-size:var(--text-sm);line-height:1.45}.oc-empty-tips{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-2) var(--space-3);margin:0;padding:0;list-style:none;color:var(--muted-soft);font-size:12px}.oc-empty-tips li{display:inline-flex;align-items:center;gap:6px}.oc-empty-tips kbd{display:inline-grid;place-items:center;min-width:1.4em;padding:1px 6px;border:1px solid var(--hairline);border-radius:5px;background:var(--surface);color:var(--body);font-family:var(--font-mono, "JetBrains Mono", monospace);font-size:11px;font-weight:600;line-height:1.4}.oc-empty-cta{margin-top:calc(var(--space-1) * -1)}.oc-row{display:flex;flex-direction:column;gap:4px;max-width:100%}.oc-row.is-user{align-self:flex-end;align-items:flex-end;width:auto;max-width:min(100%,720px)}.oc-row.is-assistant,.oc-row.is-tool{align-self:stretch;align-items:stretch;width:100%;max-width:100%}.oc-meta{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--muted-soft)}.oc-row.is-assistant .oc-meta,.oc-row.is-user .oc-meta{width:100%;max-width:100%}.oc-message-copy{appearance:none;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:26px;height:26px;margin-left:auto;padding:0;border:1px solid transparent;border-radius:var(--radius-sm);background:transparent;color:var(--muted-soft);cursor:pointer;opacity:0;transition:opacity var(--transition-fast),background var(--transition-fast),color var(--transition-fast),border-color var(--transition-fast)}.oc-row:hover .oc-message-copy,.oc-row:focus-within .oc-message-copy,.oc-message-copy:focus-visible{opacity:1}.oc-message-copy:hover{color:var(--body);background:color-mix(in srgb,var(--ink) 6%,transparent);border-color:var(--hairline)}.oc-message-copy.is-copied{opacity:1;color:var(--green, #1a7f37);border-color:color-mix(in srgb,var(--green, #1a7f37) 35%,transparent)}@media(hover:none){.oc-message-copy{opacity:.5}}.oc-avatar{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;font-size:11px;font-weight:700;flex-shrink:0}.oc-avatar-user{background:var(--ink);color:#fff}.oc-avatar-assistant{background:var(--orange);color:#fff}.oc-role{font-weight:700;color:var(--body)}.oc-time{font-variant-numeric:tabular-nums}.oc-bubble{padding:10px 14px;border-radius:var(--radius-lg);font-size:14px;line-height:1.6;overflow-wrap:anywhere;word-break:break-word;animation:bubble-in .16s ease}@keyframes bubble-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.oc-bubble-user{background:var(--ink);color:#fff;border-bottom-right-radius:4px;box-shadow:0 4px 14px #26251e1f}.oc-bubble-assistant{background:var(--surface);color:var(--ink);border:1px solid var(--hairline);border-bottom-left-radius:4px}.oc-bubble-tool{background:var(--canvas-soft);color:var(--body);border:1px solid var(--hairline)}.oc-bubble-error{border-color:color-mix(in srgb,var(--red) 40%,var(--hairline));background:color-mix(in srgb,var(--red) 7%,var(--surface));color:var(--red)}.oc-md{display:flex;flex-direction:column;gap:var(--space-2)}.oc-md>*:first-child{margin-top:0}.oc-md>*:last-child{margin-bottom:0}.oc-md p{margin:0}.oc-md h1,.oc-md h2,.oc-md h3,.oc-md h4{margin:var(--space-3) 0 var(--space-2);color:inherit;font-weight:700;line-height:1.3}.oc-md h1{font-size:1.3em}.oc-md h2{font-size:1.18em}.oc-md h3{font-size:1.06em}.oc-md h4{font-size:1em}.oc-md ul,.oc-md ol{margin:0;padding-left:1.4em;display:flex;flex-direction:column;gap:2px}.oc-md li{margin:0}.oc-md blockquote{margin:0;padding:2px 0 2px 12px;border-left:3px solid var(--hairline-strong);color:var(--body)}.oc-bubble-user .oc-md blockquote{border-left-color:#ffffff59;color:#ffffffd1}.oc-md code{font-size:.86em;padding:1px 5px;border-radius:4px;background:color-mix(in srgb,var(--ink) 8%,transparent)}.oc-bubble-user .oc-md code{background:#ffffff29}.oc-md pre{margin:0;padding:0;background:transparent}.oc-codeblock{margin:0;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface-muted);overflow:hidden}.oc-bubble-assistant .oc-codeblock{background:#f3efe8}.oc-codeblock-head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);padding:5px 6px 5px 10px;border-bottom:1px solid var(--hairline);font-size:11px;color:var(--muted);background:color-mix(in srgb,var(--ink) 4%,transparent)}.oc-codeblock-lang{font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;font-weight:600;text-transform:lowercase}.oc-codeblock-copy{appearance:none;display:inline-flex;align-items:center;gap:5px;min-height:26px;padding:0 9px;border:1px solid transparent;border-radius:var(--radius-sm);background:transparent;color:var(--muted);font-size:11px;font-weight:600;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast),border-color var(--transition-fast)}.oc-codeblock-copy:hover{background:var(--surface);color:var(--ink);border-color:var(--hairline-strong)}.oc-codeblock pre{margin:0;padding:var(--space-3) var(--space-4);overflow-x:auto;font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;font-size:12.5px;line-height:1.55;white-space:pre;color:var(--ink)}.oc-md a{color:var(--orange);text-decoration:none;border-bottom:1px solid color-mix(in srgb,var(--orange) 40%,transparent)}.oc-md a:hover{border-bottom-color:var(--orange)}.oc-md hr{margin:var(--space-2) 0;border:none;border-top:1px solid var(--hairline-strong)}.oc-stream{white-space:pre-wrap;font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;font-size:13px;line-height:1.55}.oc-cursor{display:inline-block;width:7px;height:1.05em;margin-left:2px;vertical-align:text-bottom;background:var(--orange);animation:oc-blink 1s steps(2,start) infinite;border-radius:1px}@keyframes oc-blink{to{opacity:0}}.oc-tool{border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft);overflow:hidden;animation:panel-in .16s ease;transition:border-color var(--transition-fast),background-color var(--transition-fast)}.oc-tool:hover{border-color:var(--hairline-strong);background:var(--surface)}.oc-tool.is-error{border-color:color-mix(in srgb,var(--red) 38%,var(--hairline))}.oc-tool.is-running{border-color:color-mix(in srgb,var(--orange) 40%,var(--hairline))}.oc-tool-head{display:flex;align-items:center;gap:var(--space-2);width:100%;padding:7px 12px;border:none;background:transparent;text-align:left;cursor:pointer;font:inherit;color:var(--ink)}.oc-tool-head:hover{background:var(--surface-muted)}.oc-tool-chevron{flex-shrink:0;width:12px;height:12px;transition:transform var(--transition-fast)}.oc-tool-head[aria-expanded=true] .oc-tool-chevron{transform:rotate(90deg)}.oc-tool-icon{display:grid;place-items:center;width:22px;height:22px;border-radius:6px;background:var(--surface-muted);color:var(--orange-active);flex-shrink:0}.oc-tool-name{font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;font-size:12.5px;font-weight:650;flex-shrink:0}.oc-tool-args{color:var(--muted);font-size:11.5px;font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-right:8px;min-width:0}.oc-tool-status{margin-left:auto;flex-shrink:0;font-size:11px;font-weight:650;padding:2px 8px;border-radius:var(--radius-pill)}.oc-tool-waiting{color:var(--muted);font-size:12px;animation:pulse 1.5s infinite}.oc-tool-status.is-running{color:var(--orange-active);background:var(--orange-soft)}.oc-tool-status.is-ok{color:var(--green);background:color-mix(in srgb,var(--mint) 60%,transparent)}.oc-tool-status.is-error{color:var(--red);background:color-mix(in srgb,var(--red) 10%,transparent)}.oc-tool-body{padding:0 var(--space-4) var(--space-3);border-top:1px solid var(--hairline)}.oc-tool-section{display:flex;flex-direction:column;gap:4px;padding-top:var(--space-3)}.oc-tool-label{font-size:11px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--muted-soft)}.oc-tool-code{margin:0;padding:var(--space-3);border-radius:var(--radius-sm);background:var(--surface-muted);font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:260px;overflow-y:auto;color:var(--body)}.oc-composer{flex:0 0 auto;flex-shrink:0;border-top:1px solid var(--hairline);padding:var(--space-2) var(--space-3) var(--space-3);background:color-mix(in srgb,var(--canvas) 92%,transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:2}.oc-composer-inner{display:flex;flex-direction:column;gap:var(--space-2);max-width:1080px;margin:0 auto;position:relative}.console-shell.is-chat-focus .oc-composer-inner{max-width:none}.oc-composer-shell{position:relative;display:flex;align-items:flex-end;gap:var(--space-2);padding:8px 8px 8px 14px;border:1px solid var(--hairline-strong);border-radius:var(--radius-lg);background:var(--surface);box-shadow:var(--shadow-panel);transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.oc-composer-shell:focus-within{border-color:var(--orange);box-shadow:0 0 0 3px var(--orange-soft)}.oc-composer-shell.is-busy{opacity:.78}.oc-textarea{flex:1 1 auto;min-width:0;min-height:52px;max-height:280px;padding:8px 0;border:none;background:transparent;color:var(--ink);font:inherit;font-size:14px;line-height:1.5;resize:none;outline:none}.oc-textarea::placeholder{color:var(--muted-soft)}.oc-send{appearance:none;display:grid;place-items:center;width:38px;height:38px;flex-shrink:0;padding:0;border:1px solid var(--orange);border-radius:50%;background:linear-gradient(180deg,var(--orange),var(--orange-active));color:#fff;cursor:pointer;box-shadow:inset 0 1px #fff3,0 4px 12px #f54e003d;transition:background var(--transition-fast),border-color var(--transition-fast),box-shadow var(--transition-fast),transform var(--transition-fast)}.oc-send:hover:not(:disabled){background:var(--orange-active);border-color:var(--orange-active);box-shadow:0 6px 16px #f54e004d;transform:translateY(-1px)}.oc-send:active:not(:disabled){transform:scale(.94)}.oc-send:disabled{opacity:.4;cursor:not-allowed}.oc-stop{appearance:none;display:grid;place-items:center;width:38px;height:38px;flex-shrink:0;padding:0;border:1px solid var(--hairline-strong);border-radius:50%;background:var(--surface);color:var(--red);cursor:pointer;transition:background var(--transition-fast),border-color var(--transition-fast)}.oc-stop:hover{background:color-mix(in srgb,var(--red) 8%,var(--surface));border-color:var(--red)}.oc-composer-foot{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap;font-size:11.5px;color:var(--muted)}.oc-composer-hint{display:inline-flex;align-items:center;gap:5px}.oc-kbd{display:inline-block;padding:1px 6px;border:1px solid var(--hairline-strong);border-bottom-width:2px;border-radius:4px;background:var(--surface);color:var(--body);font-family:JetBrains Mono,SFMono-Regular,Consolas,monospace;font-size:10.5px;line-height:1.4}.oc-operation-card{width:min(720px,calc(100% - 42px));margin:var(--space-3) auto;padding:var(--space-4) var(--space-5);border:1px solid var(--hairline-strong);border-left:4px solid var(--blue);border-radius:var(--radius-lg);background:color-mix(in srgb,var(--surface) 96%,var(--blue) 4%);box-shadow:var(--shadow-panel)}.oc-operation-card.is-succeeded{border-left-color:var(--green)}.oc-operation-card.is-failed,.oc-operation-card.is-timed-out{border-left-color:var(--red)}.oc-operation-card.is-needs-reconcile{border-left-color:var(--orange)}.oc-operation-head,.oc-operation-actions{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3)}.oc-operation-kicker{margin-bottom:2px;color:var(--muted);font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase}.oc-operation-state{padding:3px 9px;border-radius:999px;background:color-mix(in srgb,var(--blue) 12%,transparent);color:var(--blue);font-size:11px;font-weight:700}.oc-operation-state.is-succeeded{background:color-mix(in srgb,var(--green) 12%,transparent);color:var(--green)}.oc-operation-state.is-failed,.oc-operation-state.is-timed-out{background:color-mix(in srgb,var(--red) 12%,transparent);color:var(--red)}.oc-operation-state.is-needs-reconcile{background:color-mix(in srgb,var(--orange) 14%,transparent);color:var(--orange-active)}.oc-operation-id,.oc-operation-controller{margin-top:var(--space-2);color:var(--muted);font-size:12px;overflow-wrap:anywhere}.oc-operation-identities{display:flex;flex-wrap:wrap;gap:6px;margin-top:var(--space-3)}.oc-operation-identities span{padding:3px 8px;border:1px solid var(--hairline);border-radius:var(--radius-pill);background:var(--surface);color:var(--muted);font-size:var(--text-xs);font-weight:600}.oc-operation-identities b{color:var(--body)}.oc-operation-preview{max-height:150px;margin:var(--space-3) 0 0;padding:var(--space-2) var(--space-3);overflow:auto;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft);color:var(--body);font-family:var(--font-mono);font-size:var(--text-xs);line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere}.oc-operation-preview.is-error{border-color:color-mix(in srgb,var(--red) 30%,var(--hairline));color:var(--red)}.oc-operation-actions{justify-content:flex-start;margin-top:var(--space-3)}.oc-operation-actions time{margin-left:auto;color:var(--muted-soft);font-size:11px}.oc-interview-start{margin:var(--space-3) auto}.oc-draft-card{width:min(720px,calc(100% - 42px));margin:var(--space-3) auto;padding:var(--space-4) var(--space-5);border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface);box-shadow:var(--shadow-panel)}.oc-draft-card>header{display:flex;align-items:center;gap:var(--space-3);justify-content:space-between}.oc-draft-card>header strong{font-size:15px;font-weight:700;letter-spacing:-.01em}.oc-draft-card>header span{padding:3px 10px;border-radius:var(--radius-pill);background:var(--surface-muted);color:var(--muted);font-size:var(--text-xs);font-weight:700;letter-spacing:.05em;text-transform:uppercase}.oc-interview-bubble{margin:var(--space-3) 0;padding:var(--space-3) var(--space-4);border-left:3px solid var(--orange);border-radius:0 var(--radius-md) var(--radius-md) 0;background:var(--canvas-soft)}.oc-interview-bubble textarea{width:100%;min-height:72px;margin:var(--space-2) 0;resize:vertical;border:1px solid var(--hairline-strong);border-radius:var(--radius-md);padding:var(--space-2) var(--space-3);font:inherit;font-size:var(--text-md)}.oc-interview-bubble textarea:focus-visible{outline:none;border-color:var(--orange);box-shadow:0 0 0 3px var(--orange-soft)}.oc-interview-bubble .btn+.btn{margin-left:var(--space-2)}.oc-draft-card pre{max-height:300px;overflow:auto;white-space:pre-wrap;font-size:var(--text-xs)}.oc-assessment{margin:var(--space-3) 0;color:var(--orange);font-size:var(--text-md)}.oc-assessment.is-fresh,.oc-task-kind-card.is-confirmed{color:var(--green)}.oc-task-kind-card{display:flex;align-items:center;gap:var(--space-3);justify-content:space-between;flex-wrap:wrap;margin-top:var(--space-3);padding:var(--space-3) var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft)}.oc-task-kind-card small{color:var(--muted)}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}.oc-human-gate-card{position:relative;width:min(720px,calc(100% - 42px));margin:var(--space-3) auto;padding:var(--space-4) var(--space-5);border:1px solid color-mix(in srgb,var(--orange) 38%,var(--hairline));border-left:4px solid var(--orange);border-radius:var(--radius-lg);background:linear-gradient(180deg,color-mix(in srgb,var(--orange) 4%,var(--surface)),var(--surface) 40%);box-shadow:var(--shadow-soft);animation:panel-in .2s var(--ease-out)}.oc-human-gate-card.is-prepared,.oc-human-gate-card.is-confirmed{position:sticky;bottom:var(--space-2);z-index:6}.oc-human-gate-card header,.oc-human-gate-card footer{display:flex;justify-content:space-between;align-items:center;gap:var(--space-3)}.oc-human-gate-card header div{display:grid;gap:3px}.oc-human-gate-card header small{color:var(--muted);font-size:var(--text-xs);font-weight:600;letter-spacing:.04em}.oc-human-gate-card header strong{font-size:15px;font-weight:700;letter-spacing:-.01em}.oc-human-gate-card header>span{flex-shrink:0;padding:3px 10px;border-radius:var(--radius-pill);font-size:var(--text-xs);font-weight:700;letter-spacing:.06em;text-transform:uppercase;border:1px solid transparent}.oc-human-gate-card.is-prepared header>span{color:var(--orange-active);background:var(--orange-soft);border-color:color-mix(in srgb,var(--orange) 35%,transparent)}.oc-human-gate-card.is-confirmed header>span,.oc-human-gate-card.is-dispatched header>span{color:var(--blue);background:color-mix(in srgb,var(--blue) 10%,transparent);border-color:color-mix(in srgb,var(--blue) 30%,transparent)}.oc-human-gate-card.is-consumed header>span{color:var(--green);background:color-mix(in srgb,var(--green) 10%,transparent);border-color:color-mix(in srgb,var(--green) 30%,transparent)}.oc-human-gate-card.is-stale header>span,.oc-human-gate-card.is-expired header>span,.oc-human-gate-card.is-error header>span{color:var(--red);background:color-mix(in srgb,var(--red) 8%,transparent);border-color:color-mix(in srgb,var(--red) 30%,transparent)}.oc-human-gate-card>p{margin:var(--space-3) 0 0;color:var(--body);font-size:var(--text-md);line-height:1.55}.oc-human-gate-card>div:has(>b){margin-top:var(--space-3);padding:var(--space-2) var(--space-3);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft);font-size:var(--text-sm)}.oc-human-gate-challenges,.oc-human-gate-card ol{max-height:160px;overflow:auto}.oc-human-gate-card ul,.oc-human-gate-card ol{margin:var(--space-2) 0 0;padding-left:1.3em;color:var(--body)}.oc-human-gate-card footer{margin-top:var(--space-4);padding-top:var(--space-3);border-top:1px solid var(--hairline)}.oc-human-gate-card footer a{color:var(--muted);font-size:var(--text-sm);font-weight:600;text-decoration:none}.oc-human-gate-card footer a:hover{color:var(--orange-active);text-decoration:underline}.oc-human-gate-error{margin-top:var(--space-2);padding:var(--space-2) var(--space-3);border-radius:var(--radius-sm);background:color-mix(in srgb,var(--red) 8%,transparent);color:var(--red);font-size:var(--text-sm);font-weight:600}.oc-human-gate-card.is-confirmed{border-left-color:var(--blue)}.oc-human-gate-card.is-consumed{border-left-color:var(--green);box-shadow:var(--shadow-panel)}.oc-human-gate-card.is-stale,.oc-human-gate-card.is-expired,.oc-human-gate-card.is-error{border-left-color:var(--red)}.oc-task-context{margin:var(--space-3);padding:var(--space-3);border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface)}.oc-task-context>header{display:flex;justify-content:space-between;gap:var(--space-2);align-items:center}.oc-task-context>header div{display:grid;gap:2px}.oc-task-context>header small,.oc-task-context>header span,.oc-task-context-empty{color:var(--muted)}.oc-task-context-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-2);margin-top:var(--space-3)}.oc-task-context-grid>div{display:grid;gap:4px;min-width:0;padding:var(--space-2);border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--canvas-soft)}.oc-task-context-grid span,.oc-task-context-grid small{overflow-wrap:anywhere}.oc-shortcut-palette{position:absolute;z-index:12;left:0;right:0;bottom:calc(100% + 8px);display:grid;padding:6px;border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface);box-shadow:var(--shadow-soft)}.oc-shortcut-palette button{display:flex;gap:var(--space-3);align-items:center;border:0;border-radius:var(--radius-md);padding:9px 10px;color:inherit;background:transparent;text-align:left;min-height:0}.oc-shortcut-palette button:hover,.oc-shortcut-palette button.is-active{background:var(--surface-muted)}.oc-shortcut-palette button span{display:grid;gap:2px}.oc-shortcut-palette button small{color:var(--muted)}.oc-composer-inner{position:relative}@media(max-width:800px){.oc-task-context-grid{grid-template-columns:1fr}}.oc-file-palette{position:absolute;z-index:13;left:0;right:0;bottom:calc(100% + 8px);display:grid;max-height:240px;overflow:auto;padding:6px;border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface);box-shadow:var(--shadow-soft)}.oc-file-palette button{border:0;padding:8px 10px;color:inherit;background:transparent;text-align:left;border-radius:var(--radius-md);min-height:0}.oc-file-palette button:hover{background:var(--surface-muted)}.oc-runtime-controls{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px}.oc-runtime-controls select{max-width:220px;min-height:30px;border:1px solid var(--hairline);border-radius:var(--radius-md);padding:0 var(--space-2);color:var(--body);background:var(--surface);font-size:var(--text-sm);transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.oc-runtime-controls select:hover{border-color:var(--hairline-strong)}.oc-runtime-controls select:focus-visible{outline:none;border-color:var(--orange);box-shadow:0 0 0 3px var(--orange-soft)}.oc-runtime-controls select.oc-model-select{max-width:min(100%,360px);font-family:var(--font-mono);font-size:var(--text-sm)}.oc-runtime-controls .oc-process-summary{margin-left:0}.oc-usage{color:var(--muted);font-size:var(--text-sm);font-variant-numeric:tabular-nums}.oc-runtime-context-menu{position:relative;margin-left:auto;flex-shrink:0}.oc-runtime-context-toggle.is-active{color:var(--orange-active);background:color-mix(in srgb,var(--orange) 10%,var(--surface))}.oc-runtime-context-panel{position:absolute;right:0;bottom:calc(100% + 8px);z-index:16;width:min(760px,calc(100vw - 24px));max-height:min(72vh,720px);display:flex;flex-direction:column;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface);box-shadow:var(--shadow-soft);animation:panel-in .16s ease;overflow:hidden}.oc-runtime-context-head{display:flex;align-items:flex-start;gap:12px;flex-shrink:0;padding:12px 14px;border-bottom:1px solid var(--hairline);background:var(--surface-raised)}.oc-runtime-context-head-copy{flex:1;min-width:0;display:grid;gap:2px}.oc-runtime-context-head strong{font-size:14px}.oc-runtime-context-meta{font-size:11px;color:var(--muted)}.oc-runtime-context-close{flex-shrink:0;min-height:28px;padding:0 8px;font-size:12px}.oc-runtime-context-body{flex:1;min-height:0;overflow:auto;padding:12px 14px 14px;display:grid;gap:14px}.oc-runtime-context-chips{display:flex;flex-wrap:wrap;gap:6px}.oc-runtime-context-chip{display:inline-flex;align-items:center;gap:4px;max-width:100%;padding:4px 8px;border:1px solid var(--hairline);border-radius:999px;background:var(--canvas-soft);color:var(--body);font-size:11px;line-height:1.3}.oc-runtime-context-chip code{font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.oc-runtime-context-section{display:grid;gap:8px;min-width:0}.oc-runtime-context-section-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.oc-runtime-context-section-head strong{font-size:12px}.oc-runtime-context-hash{display:inline-block;margin-left:6px;font-size:11px;color:var(--muted)}.oc-runtime-context-text{margin:0;max-height:min(36vh,360px);overflow:auto;padding:10px 12px;border:1px solid var(--hairline);border-radius:var(--radius-sm);background:var(--canvas-soft);color:var(--body);font-size:12px;line-height:1.55;white-space:pre-wrap;overflow-wrap:anywhere}.oc-runtime-context-empty{margin:0;color:var(--muted);font-size:12px}.oc-runtime-context-skill-cards{margin:0;padding:0;list-style:none;display:grid;gap:8px}.oc-runtime-context-skill-cards details{border:1px solid var(--hairline);border-radius:var(--radius-sm);background:var(--surface-raised);overflow:hidden}.oc-runtime-context-skill-cards summary{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 10px;cursor:pointer;-webkit-user-select:none;user-select:none;font-size:12px}.oc-runtime-context-skill-cards summary span{color:var(--muted);font-variant-numeric:tabular-nums}.oc-runtime-context-skill-desc{margin:0;padding:0 10px 8px;color:var(--muted);font-size:12px;line-height:1.45}.oc-runtime-context-skill-cards .oc-runtime-context-text{max-height:min(28vh,280px);border-left:none;border-right:none;border-bottom:none;border-radius:0}.oc-runtime-context-tools{margin:0;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:6px}.oc-runtime-context-tools li code{display:inline-block;padding:3px 7px;border:1px solid var(--hairline);border-radius:6px;background:var(--canvas-soft);font-size:11px}.oc-runtime-context-raw{padding-top:10px;border-top:1px solid var(--hairline);font-size:12px;color:var(--muted)}.oc-runtime-context-raw summary{cursor:pointer;-webkit-user-select:none;user-select:none}.oc-runtime-context-raw pre{margin:8px 0 0;max-height:180px;overflow:auto;padding:8px;border:1px solid var(--hairline);border-radius:var(--radius-sm);background:var(--canvas-soft);font-size:11px;line-height:1.45;white-space:pre-wrap;overflow-wrap:anywhere}@media(max-width:800px){.oc-runtime-context-menu{margin-left:0;width:100%}.oc-runtime-context-panel{left:0;right:0;width:auto;max-height:min(78vh,680px)}}.oc-artifact-card{max-width:100%;margin:var(--space-3) 0;padding:var(--space-4);overflow:hidden;border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface);box-shadow:var(--shadow-panel)}.oc-artifact-card header{display:flex;justify-content:space-between;align-items:center;gap:var(--space-3)}.oc-artifact-card header strong{font-size:var(--text-md);font-weight:700}.oc-artifact-card header>span{padding:2px 9px;border-radius:var(--radius-pill);background:var(--surface-muted);color:var(--muted);font-size:var(--text-xs);font-weight:700;letter-spacing:.05em;text-transform:uppercase}.oc-artifact-card pre{max-height:320px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font-size:var(--text-xs)}.oc-artifact-card iframe{width:100%;min-height:280px;border:1px solid var(--hairline);border-radius:var(--radius-md);background:#fff}.oc-load-history{display:block;margin:var(--space-2) auto}.oc-attach-button{display:inline-flex;min-height:26px;align-items:center;padding:0 var(--space-2);border:1px solid var(--hairline);border-radius:var(--radius-pill);background:var(--surface);color:var(--muted);cursor:pointer;font-size:var(--text-sm);font-weight:600;transition:border-color var(--transition-fast),color var(--transition-fast),background-color var(--transition-fast)}.oc-attach-button:hover{border-color:var(--orange);color:var(--orange-active);background:var(--orange-soft)}.oc-composer-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:10px 14px;margin-bottom:6px;font-size:11.5px;color:var(--muted)}.oc-composer-toolbar .oc-attach-button{margin-bottom:0}.oc-attachment-list{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.oc-attachment-list span{display:inline-flex;align-items:center;gap:5px;max-width:100%;padding:4px 8px;border:1px solid var(--hairline);border-radius:999px;overflow-wrap:anywhere}.oc-attachment-list button{border:0;color:inherit;background:transparent;cursor:pointer}@media(max-width:640px){.oc-runtime-controls,.oc-composer-foot{align-items:stretch;flex-direction:column}.oc-runtime-controls select,.oc-runtime-controls button{width:100%;max-width:100%;min-height:44px}.oc-artifact-card{width:100%}.oc-composer{padding-inline:8px}}.night-workbench .night-health{margin:var(--space-4) 0;padding:var(--space-3) var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface);box-shadow:var(--shadow-sm)}.night-health-main{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2) var(--space-3)}.night-health-pill{display:inline-flex;align-items:center;gap:6px;padding:3px 12px;border-radius:var(--radius-pill);background:color-mix(in srgb,var(--green) 14%,white);color:var(--green);font-size:var(--text-sm);font-weight:700;letter-spacing:.02em}.night-health-pill:before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}.night-health-pill.is-bad{background:color-mix(in srgb,var(--red) 14%,white);color:var(--red)}.night-health-hint{margin:var(--space-2) 0 0}.night-aux-ticker{margin-top:var(--space-3);padding-top:var(--space-3);border-top:1px solid var(--hairline)}.night-aux-ticker-label{margin:0;color:var(--body);font-size:var(--text-md)}.night-doctor-list{margin:var(--space-2) 0 0;padding-left:1.2em;color:var(--body);font-size:12.5px}.night-kpi{display:flex;flex-wrap:wrap;gap:var(--space-2);margin:var(--space-3) 0;color:var(--body);font-size:var(--text-md)}.night-kpi span{padding:4px 12px;border:1px solid var(--hairline);border-radius:var(--radius-pill);background:var(--canvas-soft);font-variant-numeric:tabular-nums;font-weight:600}.night-board,.night-wizard,.night-discard-card,.night-advanced{margin-top:var(--space-5)}.night-schedule-list{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3)}.night-schedule-row{padding:var(--space-3) var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-lg);background:var(--surface);transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.night-schedule-row:hover{border-color:var(--hairline-strong);box-shadow:var(--shadow-panel)}.night-schedule-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--space-2)}.night-status-chip{padding:2px 10px;border-radius:var(--radius-pill);background:color-mix(in srgb,var(--blue) 10%,transparent);border:1px solid color-mix(in srgb,var(--blue) 25%,transparent);font-size:var(--text-xs);color:var(--blue);font-weight:700;letter-spacing:.03em}.night-schedule-row[data-status=failed] .night-status-chip,.night-schedule-row[data-status=human_required] .night-status-chip{color:var(--red);background:color-mix(in srgb,var(--red) 8%,transparent);border-color:color-mix(in srgb,var(--red) 28%,transparent)}.night-schedule-row[data-status=succeeded] .night-status-chip{color:var(--green);background:color-mix(in srgb,var(--green) 10%,transparent);border-color:color-mix(in srgb,var(--green) 28%,transparent)}.night-schedule-row[data-status=running] .night-status-chip,.night-schedule-row[data-status=dispatching] .night-status-chip{color:var(--orange-active);background:var(--orange-soft);border-color:color-mix(in srgb,var(--orange) 30%,transparent)}.night-next-action{font-size:var(--text-sm);overflow-wrap:anywhere}.night-review-card,.night-discard-card{padding:var(--space-4) var(--space-5);border:1px solid var(--hairline-strong);border-radius:var(--radius-lg);background:var(--canvas-soft)}.night-writeset{margin:0;padding-left:1.1em}.night-advanced{border-top:1px solid var(--hairline);padding-top:var(--space-3)}.night-advanced summary{cursor:pointer;color:var(--body);font-weight:600}.checkbox-field{display:flex;align-items:center;gap:var(--space-2)}.models-page .panel-lead{margin-top:var(--space-2)}.models-header{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2) var(--space-3)}.models-header h2{margin:0}.models-status-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 14px;border-radius:var(--radius-pill);font-size:var(--text-sm);font-weight:700;letter-spacing:.02em}.models-status-pill:before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}.models-status-pill[data-state=ready]{background:color-mix(in srgb,var(--green) 14%,white);color:var(--green)}.models-status-pill[data-state=setup-required]{background:color-mix(in srgb,var(--red) 14%,white);color:var(--red)}.models-status-pill[data-state=degraded]{background:color-mix(in srgb,var(--orange) 16%,white);color:var(--orange-active)}.models-status-pill[data-state=unknown]{background:var(--canvas-soft);color:var(--muted)}.models-subtitle{margin:0 0 var(--space-2);font-size:var(--text-md);font-weight:700;color:var(--ink)}.models-probe-card,.models-setup-card,.models-blocked-card{margin-top:var(--space-4);padding:var(--space-3) var(--space-4);border:1px solid var(--hairline);border-radius:var(--radius-md);background:color-mix(in srgb,var(--surface) 55%,transparent)}.models-probe-list{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-2)}.models-probe-item{display:grid;grid-template-columns:28px 1fr;gap:var(--space-2);align-items:start;padding:var(--space-2) 0;border-bottom:1px solid var(--hairline)}.models-probe-item:last-child{border-bottom:none;padding-bottom:0}.models-probe-badge{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;font-size:14px;font-weight:800;line-height:1;background:var(--canvas-soft);color:var(--muted)}.models-probe-item.is-ok .models-probe-badge{background:color-mix(in srgb,var(--green) 16%,white);color:var(--green)}.models-probe-item.is-bad .models-probe-badge{background:color-mix(in srgb,var(--red) 14%,white);color:var(--red)}.models-probe-body{display:grid;gap:2px;min-width:0}.models-probe-body strong{font-size:var(--text-md);color:var(--ink)}.models-probe-body .muted{font-size:var(--text-sm)}.models-probe-detail{margin:var(--space-1) 0 0;font-size:var(--text-sm);color:var(--body);line-height:1.45}.models-setup-steps{margin:0 0 var(--space-3);padding-left:1.25em;color:var(--body);font-size:var(--text-md);line-height:1.5}.models-setup-steps li+li{margin-top:var(--space-2)}.models-degraded-note{margin:var(--space-4) 0 0;padding:var(--space-3) var(--space-4);border-radius:var(--radius-md);border:1px solid color-mix(in srgb,var(--orange) 35%,var(--hairline));background:color-mix(in srgb,var(--orange) 8%,white);color:var(--body);font-size:var(--text-md)}.models-blocked-list{margin:0;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:var(--space-2)}.models-blocked-list li{padding:4px 10px;border-radius:var(--radius-pill);border:1px solid var(--hairline);background:var(--surface)}.models-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-3);margin-top:var(--space-4)}.models-generated-at{font-size:var(--text-sm)}.models-raw-details{margin-top:var(--space-4);font-size:var(--text-sm);color:var(--muted)}.models-raw-details summary{cursor:pointer;font-weight:600;color:var(--body)}.models-raw-json{margin-top:var(--space-2);max-height:240px;overflow:auto}
|