skills-viewer 0.6.0 → 0.7.0
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/build/server/flow.js
CHANGED
|
@@ -47,6 +47,12 @@ const os = __importStar(require("node:os"));
|
|
|
47
47
|
const path = __importStar(require("node:path"));
|
|
48
48
|
const summary_1 = require("./summary");
|
|
49
49
|
const FLOW_FILE = path.join(os.homedir(), '.cache', 'skills-viewer', 'flows.json');
|
|
50
|
+
/*
|
|
51
|
+
* 抽出スキーマの世代。branches.to(ループ/スキップ)追加で 2。
|
|
52
|
+
* 旧世代キャッシュも表示には使い続ける(フローチャート描画は to 無しでも成立し、
|
|
53
|
+
* ループ矢印だけ出ない)が、再抽出時は stale 扱いして新スキーマで作り直す。
|
|
54
|
+
*/
|
|
55
|
+
const FLOW_SCHEMA_V = 2;
|
|
50
56
|
function loadFlows() {
|
|
51
57
|
try {
|
|
52
58
|
return JSON.parse(fs.readFileSync(FLOW_FILE, 'utf8'));
|
|
@@ -65,12 +71,13 @@ function buildPrompt(name, content, lang) {
|
|
|
65
71
|
'{"steps": [{"title": "ステップ名(10字程度)", "detail": "何をするか(25字程度)",\n' +
|
|
66
72
|
' "calls": ["このステップで起動/委譲する他の skill・コマンド名"],\n' +
|
|
67
73
|
' "gate": "human" | "auto" | null,\n' +
|
|
68
|
-
' "branches": [{"when": "分岐条件(15字程度)", "then": "その場合の挙動(20字程度)"}]}]}\n\n' +
|
|
74
|
+
' "branches": [{"when": "分岐条件(15字程度)", "then": "その場合の挙動(20字程度)", "to": 行き先ステップ番号}]}]}\n\n' +
|
|
69
75
|
'制約:\n' +
|
|
70
76
|
'- steps は実行順に 4〜8 個(単純な skill なら少なくてよい)\n' +
|
|
71
77
|
'- gate は人間の確認/承認を待つステップだけ "human"(自動で進むなら "auto"、該当なしは null)\n' +
|
|
72
78
|
'- calls は本文に実際に登場する名前のみ(幻覚禁止)\n' +
|
|
73
|
-
'- branches は中断・フォールバック等の分岐だけ(無ければ省略)
|
|
79
|
+
'- branches は中断・フォールバック等の分岐だけ(無ければ省略)。when は「テスト失敗」のような判定できる条件文にする\n' +
|
|
80
|
+
'- to は分岐が別ステップへ移るときだけ 1 始まりの番号で(リトライ/ループで前へ戻る場合が典型)。単なる中断・終了なら省略\n\n' +
|
|
74
81
|
'# skill: ' +
|
|
75
82
|
name +
|
|
76
83
|
'\n\n' +
|
|
@@ -80,12 +87,13 @@ function buildPrompt(name, content, lang) {
|
|
|
80
87
|
'{"steps": [{"title": "step name (2-4 words)", "detail": "what it does (about 10 words)",\n' +
|
|
81
88
|
' "calls": ["other skill/command names this step invokes or delegates to"],\n' +
|
|
82
89
|
' "gate": "human" | "auto" | null,\n' +
|
|
83
|
-
' "branches": [{"when": "branch condition (about 5 words)", "then": "behavior in that case (about 7 words)"}]}]}\n\n' +
|
|
90
|
+
' "branches": [{"when": "branch condition (about 5 words)", "then": "behavior in that case (about 7 words)", "to": target step number}]}]}\n\n' +
|
|
84
91
|
'Constraints:\n' +
|
|
85
92
|
'- 4 to 8 steps in execution order (fewer is fine for simple skills)\n' +
|
|
86
93
|
'- gate is "human" ONLY for steps that wait for human confirmation/approval ("auto" if it proceeds automatically, null otherwise)\n' +
|
|
87
94
|
'- calls may contain only names that actually appear in the body (no hallucination)\n' +
|
|
88
|
-
'- branches only for aborts / fallbacks / real forks (omit when none)\n
|
|
95
|
+
'- branches only for aborts / fallbacks / real forks (omit when none); "when" must be a checkable condition like "tests fail"\n' +
|
|
96
|
+
'- to is the 1-based step number ONLY when the branch jumps to another step (typically looping back for a retry); omit for plain aborts/exits\n\n' +
|
|
89
97
|
'# skill: ' +
|
|
90
98
|
name +
|
|
91
99
|
'\n\n' +
|
|
@@ -116,6 +124,7 @@ function parseFlow(text) {
|
|
|
116
124
|
.map((b) => ({
|
|
117
125
|
when: String(b.when).slice(0, 60),
|
|
118
126
|
then: String(b.then || '').slice(0, 80),
|
|
127
|
+
...(Number.isInteger(b.to) && b.to >= 1 ? { to: b.to } : {}),
|
|
119
128
|
}))
|
|
120
129
|
.slice(0, 4),
|
|
121
130
|
});
|
|
@@ -124,18 +133,30 @@ function parseFlow(text) {
|
|
|
124
133
|
}
|
|
125
134
|
if (!steps.length)
|
|
126
135
|
throw new Error('no steps in output');
|
|
136
|
+
// to の上限検証は全 step が出揃ってから(範囲外は to だけ捨てて分岐テキストは残す)
|
|
137
|
+
for (const st of steps)
|
|
138
|
+
for (const b of st.branches)
|
|
139
|
+
if (b.to !== undefined && b.to > steps.length)
|
|
140
|
+
delete b.to;
|
|
127
141
|
return { steps };
|
|
128
142
|
}
|
|
129
143
|
async function flowOne(realPath, name, lang, model = 'haiku') {
|
|
130
144
|
const hash = (0, summary_1.contentHash)(realPath);
|
|
131
145
|
const store = loadFlows();
|
|
132
146
|
const cached = store[realPath];
|
|
133
|
-
if (cached && cached.hash === hash && cached.lang === lang) {
|
|
147
|
+
if (cached && cached.hash === hash && cached.lang === lang && cached.v === FLOW_SCHEMA_V) {
|
|
134
148
|
return { steps: cached.steps };
|
|
135
149
|
}
|
|
136
150
|
const content = fs.readFileSync(realPath, 'utf8').slice(0, 12000);
|
|
137
151
|
const result = parseFlow(await (0, summary_1.runClaude)(buildPrompt(name, content, lang), model));
|
|
138
|
-
store[realPath] = {
|
|
152
|
+
store[realPath] = {
|
|
153
|
+
...result,
|
|
154
|
+
hash,
|
|
155
|
+
lang,
|
|
156
|
+
model,
|
|
157
|
+
v: FLOW_SCHEMA_V,
|
|
158
|
+
generatedAt: new Date().toISOString(),
|
|
159
|
+
};
|
|
139
160
|
saveFlows(store);
|
|
140
161
|
return result;
|
|
141
162
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{box-sizing:border-box}body{margin:0;background:#faf9f7;color:#1b1a17;font-family:Helvetica Neue,system-ui,-apple-system,Hiragino Sans,sans-serif}button{font-family:inherit}.mono{font-family:ui-monospace,SF Mono,Menlo,monospace}.wrap{margin:0 auto;min-height:100vh}.wrap.fixed{max-width:1200px}.wrap.fixed .grid{grid-template-columns:repeat(3,minmax(0,1fr))}@media(max-width:900px){.wrap.fixed .grid{grid-template-columns:repeat(2,minmax(0,1fr))}}.hd{padding:28px 32px 0}.hd .t-row{display:flex;align-items:baseline;gap:12px}.hd h1{font-size:22px;font-weight:700;letter-spacing:-.01em;margin:0}.hd h1 a{color:#1b1a17;text-decoration:none}.hd h1 a:hover{color:#57534a}.hd .sub{font-size:12px;color:#8a8579}.hd .count{margin-left:auto;font-size:12px;color:#8a8579}.hd input.q{margin-top:16px;width:100%;padding:11px 14px;border:1px solid #ddd8ce;border-radius:10px;font-size:13.5px;background:#fff;color:#1b1a17;outline:none;font-family:inherit}.controls{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap;align-items:center}.chip{padding:6px 14px;border-radius:999px;font-size:12px;cursor:pointer;background:#fff;border:1px solid #ddd8ce;color:#6b6558}.chip.on{background:#1b1a17;border-color:#1b1a17;color:#fff}.sec-h .g-emoji{font-size:13px;line-height:1;flex:none}.sec-h.sub{position:static;margin:10px 0 4px;padding:4px 0 2px}.sec-h.sub .lbl{text-transform:none;letter-spacing:.02em}.sub-grp{padding-left:14px}.left-col .sec-h.sub{padding-left:6px}.g-manual{font-size:10px;padding:1px 7px;border-radius:999px;border:1px solid #ddd8ce;color:#8a8579;cursor:default}.grp-bar{display:flex;align-items:center;gap:10px;padding-top:12px}.stale-note{font-size:12px;color:#a8720f}.grp-panel{text-align:center;padding:44px;font-size:13px;color:#6b6558}.grp-panel p{max-width:460px;margin:0 auto 16px;line-height:1.7}.grp-badge{background:#f1eee8;color:#57534a}.flow-tab{padding-top:14px}.fc-scroll{overflow-x:auto;padding:4px 0 8px}.fc{position:relative;display:grid;grid-template-columns:44px minmax(300px,1fr) auto;row-gap:26px;min-width:440px;max-width:640px;margin:4px 0 12px}.fc-wires{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;overflow:visible;pointer-events:none}.fc-wires text{font-family:inherit}.fc-l{min-height:1px}.fc-m{display:flex;justify-content:center;align-items:center}.fc-r{display:flex;align-items:center;padding-left:14px}.fc-start{width:12px;height:12px;border-radius:50%;background:#1b1a17;position:relative;z-index:1}.fc-proc{border:1.5px solid #cfc7b6;border-radius:10px;background:#fff;padding:8px 16px 9px;min-width:210px;max-width:320px;box-shadow:0 1px 3px #1b1a170d;position:relative;z-index:1}.fc-proc.human{border-color:#c9a227;background:#fdf9ee}.fc-head{display:flex;align-items:center;gap:8px}.fc-num{flex:none;width:19px;height:19px;border-radius:50%;background:#1b1a17;color:#fff;font-size:10.5px;font-weight:700;display:inline-flex;align-items:center;justify-content:center}.fc-proc.human .fc-num{background:#c9a227}.fc-title{font-size:13px;font-weight:700;color:#1b1a17}.fc-gate{margin-left:auto;padding-left:8px;font-size:10.5px;font-weight:700;color:#a8720f;white-space:nowrap}.fc-detail{font-size:11.5px;color:#6b6558;margin:3px 0 0 27px;line-height:1.5}.fc-calls{display:flex;flex-wrap:wrap;gap:5px;margin:6px 0 0 27px}.fc-dec{position:relative;width:224px;height:62px;z-index:1}.fc-dec .fc-shape{position:absolute;top:0;right:0;bottom:0;left:0;background:#b9ab8c;clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}.fc-dec .fc-shape:after{content:"";position:absolute;top:1.5px;right:1.5px;bottom:1.5px;left:1.5px;background:#fdfcf9;clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}.fc-dec .fc-q{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;padding:0 42px;font-size:11.5px;font-weight:700;text-align:center;line-height:1.3;color:#1b1a17;overflow:hidden}.fc-term{font-size:11.5px;font-weight:700;line-height:1.4;border-radius:999px;padding:4px 13px;white-space:nowrap;position:relative;z-index:1}.fc-term.abort{background:#f3e2de;color:#a8443a;border:1px solid #e0c3bd}.fc-term.done{background:#e6eee3;color:#47663f;border:1px solid #c8d8c1}.ctrl-sep{width:1px;height:18px;background:#ddd8ce;margin:0 4px;align-self:center}.sel{-moz-appearance:none;appearance:none;-webkit-appearance:none;font-family:inherit;font-size:12px;color:#6b6558;background:#fff;border:1px solid #ddd8ce;border-radius:999px;padding:6px 30px 6px 14px;cursor:pointer;outline:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%238a8579'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center}.sel:focus{border-color:#1b1a17}.sel.on{border-color:#1b1a17;color:#1b1a17;font-weight:600}.controls-r{margin-left:auto;display:inline-flex;gap:8px;align-items:center}.seg{display:inline-flex;border:1px solid #ddd8ce;border-radius:999px;overflow:hidden;background:#fff}.seg button{border:0;background:transparent;font-family:inherit;font-size:12px;color:#6b6558;padding:6px 13px;cursor:pointer}.seg button+button{border-left:1px solid #efede8}.seg button.on{background:#1b1a17;color:#fff}.set-label{font-size:12px;font-weight:600;color:#57534a;margin-bottom:10px}.set-options{display:flex;flex-direction:column;gap:8px;margin-bottom:20px}.set-option{display:flex;align-items:center;gap:9px;font-size:13px;cursor:pointer}.set-option input{accent-color:#1b1a17}.set-scheme{font-family:ui-monospace,Menlo,monospace;font-size:10.5px;color:#a39d90;margin-left:auto}.set-note{font-size:11px;color:#8a8579;line-height:1.6;padding:4px 2px 0}.set-input{font-family:ui-monospace,Menlo,monospace;font-size:12px;padding:8px 10px;border:1px solid #ddd8ce;border-radius:8px;outline:none;margin-left:24px}.set-input:focus{border-color:#1b1a17}.pbtn.primary{background:#1b1a17;border-color:#1b1a17;color:#fff}.pbtn.primary:hover{background:#3a372f;border-color:#3a372f}.sec-h{display:flex;align-items:center;gap:8px;margin:14px 0 6px;position:sticky;top:0;z-index:5;background:#faf9f7;padding:10px 0 8px}.sec-h .sq{width:8px;height:8px;border-radius:2px;flex:none}.sec-h .lbl{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#57534a}.sec-h .n{font-size:11px;color:#a39d90}.sec-h .ln{flex:1;height:1px;background:#e8e4dc}.sec-h.sm{margin:8px 0 4px;padding:8px 0 6px}.sec-h.sm .lbl{font-size:10.5px}.grid-pad{padding:6px 32px 32px}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.card{background:#fff;border:1px solid #e8e4dc;border-radius:10px;padding:18px 20px;display:flex;flex-direction:column;gap:10px;cursor:pointer;text-align:left;min-width:0}.card:hover{border-color:#b9b2a3;box-shadow:0 2px 8px #1b1a170f}.card .top{display:flex;align-items:baseline;gap:8px}.card .nm{font-size:15px;font-weight:600;color:#1b1a17;word-break:break-all}.card .ver{margin-left:auto;font-size:10.5px;color:#a39d90;font-family:ui-monospace,Menlo,monospace;white-space:nowrap}.card .desc{font-size:13px;line-height:1.65;color:#57534a;margin:0;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.card .usage{font-family:ui-monospace,Menlo,monospace;font-size:11.5px;background:#f4f1ea;border-radius:6px;padding:8px 10px;color:#6b6558;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card .meta{display:flex;gap:8px;font-size:10.5px;color:#8a8579}.card .meta span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.card .meta .meta-r{margin-left:auto;flex:none;display:inline-flex;gap:8px;align-items:center}.scope-mini{display:inline-flex;align-items:center;gap:5px;font-size:10px;font-weight:600;letter-spacing:.04em;color:#8a8579;margin-bottom:-4px}.dot5{width:6px;height:6px;border-radius:2px;flex:none}.empty{text-align:center;padding:44px;font-size:13px;color:#8a8579}.ai-mark{color:#b0836a;font-size:11px}.kbadge{font-size:9.5px;font-weight:700;padding:2px 8px;border-radius:999px;background:#f1efe9;color:#8a8579;white-space:nowrap;flex:none;vertical-align:3px;margin-left:8px}.same-actions{margin-left:auto;display:inline-flex;gap:6px}.pbtn.sm{font-size:11px;padding:3px 10px}.pbtn.sm.on{background:#1b1a17;border-color:#1b1a17;color:#fff}.diff-wrap{margin-top:10px}.diff-legend{display:flex;gap:14px;align-items:center;font-size:11px;margin-bottom:6px}.d-del-mark{color:#b0392e}.d-add-mark{color:#1f8a5b}.d-count{color:#8a8579;margin-left:auto}.diff{border:1px solid #e8e4dc;border-radius:8px;overflow-x:auto;background:#fff;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:1.7;max-height:480px;overflow-y:auto}.d-line{padding:0 12px;white-space:pre}.d-add{background:#1f8a5b14;color:#16603f}.d-del{background:#b0392e12;color:#8c2d24}.d-skip{padding:2px 12px;color:#a39d90;background:#faf9f7;text-align:center;border-top:1px solid #efede8;border-bottom:1px solid #efede8}.inv-badge{font-size:9.5px;font-weight:700;padding:2.5px 8px;border-radius:999px;white-space:nowrap;flex:none}.inv-human{color:#1f8a5b;background:#1f8a5b1a}.inv-agent{color:#7b5bd6;background:#7b5bd61a}.inv-both{color:#b8862f;background:#c07a1f21}.inv-ai{opacity:.85}.rel-chips{display:flex;flex-wrap:wrap;gap:8px}.rel-chip{display:inline-flex;align-items:center;gap:7px;background:#fff;border:1px solid #ddd8ce;border-radius:999px;padding:7px 12px;cursor:pointer}.rel-chip:hover{background:#f4f1ea}.rel-chip .rt{font-size:9.5px;font-weight:700;text-transform:uppercase;color:#8a8579}.rel-chip .rn{font-family:ui-monospace,Menlo,monospace;font-size:12px;color:#1b1a17}.rel-chip.missing{border-style:dashed;cursor:default}.rel-chip.missing .rn{color:#a39d90}.rel-chip.missing .rm{font-size:9.5px;color:#b0836a}.md-wrap{display:flex;align-items:stretch}.left-col{width:340px;flex:none;border-right:1px solid #eeeae2;padding:8px 20px 28px 32px;position:sticky;top:0;max-height:100vh;overflow-y:auto;overscroll-behavior:contain}.ccard{display:flex;flex-direction:column;gap:4px;width:100%;background:#fff;border:1px solid #e8e4dc;border-radius:10px;padding:12px 14px;cursor:pointer;text-align:left;margin-bottom:8px}.ccard:hover{border-color:#b9b2a3}.ccard.sel{border-color:#1b1a17;box-shadow:0 1px 5px #1b1a171a}.ccard .r1{display:flex;align-items:center;gap:7px}.ccard .dot7{width:7px;height:7px;border-radius:50%;flex:none}.ccard .nm{font-size:13.5px;font-weight:600;color:#1b1a17;word-break:break-all}.ccard .ver{margin-left:auto;font-size:10px;color:#a39d90;font-family:ui-monospace,Menlo,monospace}.ccard .d1{font-size:11.5px;color:#8a8579;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pane{flex:1;min-width:0;max-width:980px;padding:20px 36px 36px 32px}.back{background:#fff;border:1px solid #ddd8ce;border-radius:999px;font-size:12px;color:#6b6558;padding:7px 14px;cursor:pointer}.back:hover{background:#f4f1ea}.meta-row{display:flex;align-items:center;gap:10px;margin-top:20px;position:relative;flex-wrap:wrap}.badge{font-size:10.5px;font-weight:700;padding:4px 11px;border-radius:999px}.m-ver{font-size:11px;color:#8a8579;font-family:ui-monospace,Menlo,monospace}.m-upd{margin-left:auto;font-size:11px;color:#8a8579}.pbtn{background:#fff;border:1px solid #ddd8ce;border-radius:999px;font-size:12px;color:#6b6558;padding:6px 13px;cursor:pointer}.pbtn:hover{background:#f4f1ea}.pbtn.danger{color:#b0392e;border-color:#e4ccc7}.pbtn.danger:hover{background:#fbf1ef}.d-name{font-size:26px;font-weight:700;color:#1b1a17;margin:14px 0 0;word-break:break-all}.tabs{display:flex;gap:20px;margin-top:18px;border-bottom:1px solid #eeeae2}.tab{background:none;border:0;font-size:13px;color:#8a8579;padding:8px 2px 10px;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}.tab.on{color:#1b1a17;font-weight:600;border-bottom-color:#1b1a17}.sec-t{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:#8a8579;margin:26px 0 10px}.full-desc{font-size:13.5px;line-height:1.8;color:#57534a;margin:0;white-space:pre-wrap}.ex-block{font-family:ui-monospace,Menlo,monospace;font-size:12px;background:#f4f1ea;border-radius:8px;padding:10px 13px;color:#57534a;margin-bottom:8px;overflow-x:auto;white-space:pre}.f-row{display:flex;align-items:center;gap:9px;border-bottom:1px solid #eeeae2;padding:8px 4px}.f-row .sq6{width:6px;height:6px;border-radius:2px;background:#c5bfb2;flex:none}.f-row .p{font-family:ui-monospace,Menlo,monospace;font-size:12px;color:#57534a;word-break:break-all}.fm-box{font-family:ui-monospace,Menlo,monospace;font-size:10.5px;color:#8a8579;background:#faf9f7;border:1px solid #e8e4dc;border-radius:8px;padding:12px 14px;white-space:pre-wrap;word-break:break-word;margin:18px 0}.md-body{font-size:12.5px;line-height:1.9;color:#3a372f}.md-body h1,.md-body h2{border-bottom:1px solid #eeeae2;padding-bottom:6px}.md-body h1{font-size:19px;margin:26px 0 10px;color:#1b1a17}.md-body h2{font-size:16px;margin:24px 0 10px;color:#1b1a17}.md-body h3{font-size:14px;margin:20px 0 8px;color:#1b1a17}.md-body h4{font-size:13px;margin:16px 0 6px;color:#1b1a17}.md-body p{margin:8px 0}.md-body ul,.md-body ol{margin:8px 0;padding-left:22px}.md-body li{margin:3px 0}.md-body pre{background:#f4f1ea;border-radius:8px;padding:12px 14px;overflow-x:auto;font-family:ui-monospace,Menlo,monospace;font-size:11.5px;line-height:1.6}.md-body code{font-family:ui-monospace,Menlo,monospace;font-size:.9em;background:#f4f1ea;color:#8a5a2b;border-radius:4px;padding:1px 5px}.md-body pre code{background:none;color:inherit;padding:0}.md-body blockquote{border-left:3px solid #ddd8ce;margin:8px 0;padding:2px 0 2px 14px;color:#6b6558}.md-body hr{border:0;border-top:1px solid #eeeae2;margin:18px 0}.md-body a{color:#2a6fdb}.drop{position:absolute;top:calc(100% + 6px);right:0;width:260px;background:#fff;border:1px solid #ddd8ce;border-radius:10px;box-shadow:0 10px 28px #1b1a1724;z-index:30;padding:8px 0;max-height:320px;overflow-y:auto}.drop .dh{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:#8a8579;padding:6px 14px 4px}.drop .di{display:block;width:100%;text-align:left;background:none;border:0;padding:8px 14px;cursor:pointer}.drop .di:hover{background:#f4f1ea}.drop .di .l1{font-size:12.5px;font-weight:600;color:#1b1a17}.drop .di .l2{font-size:10.5px;color:#a39d90;font-family:ui-monospace,Menlo,monospace;word-break:break-all}.overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#1b1a1759;z-index:40;display:flex;align-items:center;justify-content:center}.modal{width:390px;max-width:90vw;background:#fff;border-radius:14px;padding:26px 28px}.modal h3{font-size:15px;font-weight:700;margin:0 0 10px;color:#1b1a17}.modal p{font-size:12.5px;line-height:1.7;color:#57534a;margin:0 0 20px}.modal .btns{display:flex;justify-content:flex-end;gap:8px}.modal .del{background:#b0392e;border:1px solid #b0392e;color:#fff;border-radius:999px;font-size:12px;padding:7px 16px;cursor:pointer}.modal .del:hover{background:#962f27}@media(max-width:900px){.grid{grid-template-columns:repeat(2,minmax(0,1fr))}.left-col{display:none}}@media(min-width:1480px){.grid{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:1960px){.grid{grid-template-columns:repeat(5,minmax(0,1fr))}}.unused-badge{font-size:9.5px;font-weight:700;padding:2.5px 8px;border-radius:999px;white-space:nowrap;flex:none;color:#5b7285;background:#5b72851f}.warn-badge{font-size:9.5px;font-weight:700;padding:2.5px 8px;border-radius:999px;white-space:nowrap;flex:none;color:#b0432f;background:#c848301a;position:relative;cursor:help}.card .top .top-r{margin-left:auto;display:inline-flex;align-items:center;gap:8px;flex:none}.card .top .top-r .ver{margin-left:0}.card .chips{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:-4px}.card .chips .kbadge{margin-left:0;vertical-align:0}.warn-badge .tip{display:none;position:absolute;top:calc(100% + 6px);right:-6px;z-index:40;width:250px;padding:10px 12px;border-radius:8px;background:#1b1a17;color:#f4f1ea;font-size:11.5px;font-weight:400;line-height:1.6;white-space:normal;text-align:left;box-shadow:0 4px 14px #1b1a1740}.warn-badge:hover .tip{display:block}.warn-badge .tip .tip-t{display:block;font-weight:700;margin-bottom:4px}.warn-badge .tip .tip-line{display:block;margin-top:3px;padding-left:12px;text-indent:-12px}.warn-badge .tip .tip-line:before{content:"· "}.card .meta .tok,.tok-total{font-family:ui-monospace,Menlo,monospace;white-space:nowrap}.hd .tok-total{cursor:help}.sec-h .sec-tok{font-size:11px;color:#a39d90;font-family:ui-monospace,Menlo,monospace;white-space:nowrap;cursor:help}.lint-row{display:flex;gap:8px;align-items:baseline;font-size:13px;line-height:1.65;color:#57534a;padding:2px 0}.lint-row .lint-mark{color:#b0432f;flex:none}.chg-banner{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:14px 0 -4px;padding:10px 14px;border:1px solid #e3ddd0;border-radius:10px;background:#faf7ef;font-size:12px;color:#57534a}.chg-title{font-weight:700;flex:none}.chg-group{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.chg-label{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}.chg-label.add{color:#1f8a5b;background:#1f8a5b1a}.chg-label.upd{color:#2a6fdb;background:#2a6fdb1a}.chg-label.del{color:#b0432f;background:#c848301a}.chg-chip{font-family:ui-monospace,Menlo,monospace;font-size:11.5px;padding:2px 8px;border-radius:6px;border:1px solid #ddd8ce;background:#fff;color:#57534a;cursor:pointer}.chg-chip:hover{border-color:#b9b2a3}.chg-chip.gone{cursor:default;text-decoration:line-through;color:#a39d90}.chg-more{font-size:11px;color:#8a8579}.chg-ack{margin-left:auto;flex:none}.spark-wrap{display:flex;align-items:flex-end;gap:10px;margin:2px 0 6px}.spark rect{fill:#e3ddd0}.spark rect.on{fill:#1f8a5b}.spark-label{font-size:10.5px;color:#8a8579;white-space:nowrap}.edit-bar{display:flex;justify-content:flex-end;gap:8px;margin:10px 0 12px}.md-editor{width:100%;min-height:480px;padding:14px 16px;border:1px solid #ddd8ce;border-radius:10px;background:#fff;color:#1b1a17;font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:12.5px;line-height:1.7;resize:vertical;outline:none;box-sizing:border-box}.md-editor:focus{border-color:#1b1a17}.diag-block{margin:8px 0 4px}.diag-box{border:1px solid #e8e4dc;border-radius:10px;background:#fff;padding:12px 14px;margin-bottom:10px}.diag-verdict{font-size:12.5px;font-weight:700;margin-bottom:4px}.diag-verdict.good{color:#1f8a5b}.diag-verdict.weak{color:#b8862f}.diag-imp-t{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#8a8579;margin:10px 0 4px}.diag-improved{font-size:13px;line-height:1.65;color:#57534a;margin:0 0 10px;background:#faf7ef;border-radius:8px;padding:10px 12px}
|