mulmoterminal 2.5.1 → 2.5.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/README.md +1 -0
- package/common/decisionLog.ts +49 -0
- package/common/themeVars.ts +134 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-RjiYivmv-BHMJcX-D.js → abnfDiagram-VRR7QNED-RjiYivmv-CFwKVB03.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-0NsD2xW1-BEV01Wk-.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-3nWA91tG-izYrzJUx.js → architectureDiagram-ZJ3FMSHR-3nWA91tG-mE1s94XZ.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-BPuAJQRW-BD7LRmIw.js → blockDiagram-677ZJIJ3-BPuAJQRW-DBDXdKIt.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-C0LAqQso-daMFkQYF.js → c4Diagram-LMCZKHZV-C0LAqQso-RJl7QI1d.js} +1 -1
- package/dist/assets/channel-7wUqSdoX-Czd43Gvk.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-BRrYpgtb-Lp6IvDwQ.js → chunk-32BRIVSS-BRrYpgtb-C3OsDfXW.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-BJ-ss3Xr-CIA8l6cL.js → chunk-52WLFC77-BJ-ss3Xr-tZqd3bLR.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-BZEucKEL-DBfTQdYh.js → chunk-C7G6YPKG-BZEucKEL-B8NVLAkB.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-DLS6FBN1-CmqVBBJi.js → chunk-EX3LRPZG-DLS6FBN1-BdMYjq_3.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-DHLSFw1H-Br6MRw8l.js → chunk-FWX5IMBZ-DHLSFw1H-DbaszCXG.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-Bhlt8hXJ-BDsryiai.js → chunk-HOUHSVGY-Bhlt8hXJ-DZ4w7WP6.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-DwgHBX_g-Dtq6hkL5.js → chunk-ICXQ74PX-DwgHBX_g-DwfVM3-4.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-CMZRaeqt-xCxis4AD.js → chunk-MOJQB5TN-CMZRaeqt-DDn-QIzL.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-8Qy4a8b5-CEKkrNHl.js → chunk-OGEWGWER-8Qy4a8b5-DsrblYpm.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-DcrWQRYh-CNZIIdNp.js → chunk-PUDLZKDR-DcrWQRYh-Dz5x4gGU.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-ZXVGkG8Z-BfnUuIf2.js → chunk-Q4XR5HBZ-ZXVGkG8Z-Dg8P4fgN.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-DmGdheTX-Xhz9vrZQ.js → chunk-V7JOEXUC-DmGdheTX-CSESRbzZ.js} +1 -1
- package/dist/assets/{chunk-VAUOI2AC-CS9QJ4yz-CDhJXpTw.js → chunk-VAUOI2AC-CS9QJ4yz-r_1UiH65.js} +1 -1
- package/dist/assets/{chunk-VR4S4FIN-C6a91eNY-C6K2Be2R.js → chunk-VR4S4FIN-C6a91eNY-BiFSHZig.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-BlzOfotS-C6J_J8TJ.js → chunk-WYO6CB5R-BlzOfotS-DenoOpP3.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-BYwxNFTK-DM76gWAP.js → chunk-ZGVPDNZ5-BYwxNFTK-DIJf6S9Q.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-BYlRi6YQ-CNqTeJKX.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-BCHaYHxj-CNqTeJKX.js +1 -0
- package/dist/assets/cynefin-VYW2F7L2-CGYr2F6h-HnBHTRUw.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-DHA9iPo--CygDupfu.js → cynefinDiagram-TSTJHNR4-DHA9iPo--CMG2swe1.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB--oJKqXBZ-DKaBHoMD.js → dagre-VKFMJZFB--oJKqXBZ-DptBydHT.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-CcJCB9bG-BCdZM1XW.js → diagram-FQU43EPY-CcJCB9bG-Dzr4eBwY.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-C_o-WGG1-E50OCsch.js → diagram-G47NLZAW-C_o-WGG1-DyxwgGcN.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-CXJCYvY--CmG9YdUu.js → diagram-NH7WQ7WH-CXJCYvY--C7_0SJUX.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-BMzeJ87A-CxPVNELp.js → diagram-OA4YK3LP-BMzeJ87A-CQoIcPi7.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-D_93NKqo-lP3U0GxX.js → diagram-WEI45ONY-D_93NKqo-6c4HxiEH.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CVai1Ii9-DEA-ZvYv.js → ebnfDiagram-CCIWWBDH-CVai1Ii9-DJcz6F1R.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-CiABnA0s-uFB2JxeG.js → erDiagram-Q63AITRT-CiABnA0s-D-sOjz5Q.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-CWmqhm3a-BLoYpG_j.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-DKSB5AiY-7Y5BNJk8.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DQZvdFo1-CnuwHsCh.js → ganttDiagram-NO4QXBWP-DQZvdFo1-B8qQdIm8.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-BR9qPwdN-BbSOpldz.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-C2ovBouh-DMwS2Tlh.js → gitGraphDiagram-IHSO6WYX-C2ovBouh-DshsJsEP.js} +1 -1
- package/dist/assets/{index-CIUVcLpS.js → index-BAKRQHkN.js} +186 -186
- package/dist/assets/{index-BL1ivfaK.css → index-BAZX7G64.css} +1 -1
- package/dist/assets/info-DKCQHKI2-Dplx5kMp-BGK6F5n3.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-7UnoB5AP-D1UXK3im.js → infoDiagram-FWYZ7A6U-7UnoB5AP-8s4vJMqL.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-ByUDM_N2-eU53AoG2.js → ishikawaDiagram-FXEZZL3T-ByUDM_N2-z-9aPM5O.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-c5xIah9o-BQNy69_H.js → journeyDiagram-5HDEW3XC-c5xIah9o-Cgg8FxSO.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-Cnt6loYD-C3Ya6-uo.js → kanban-definition-HUTT4EX6-Cnt6loYD-BNCxCgbs.js} +1 -1
- package/dist/assets/{lib-XZe86Xbo.js → lib-IyO-7kbx.js} +1 -1
- package/dist/assets/{line-D7ziSjKi-DhimY3vn.js → line-D7ziSjKi-VRCegTMF.js} +1 -1
- package/dist/assets/{marp-DE0BYdnE.js → marp-CMroV6s8.js} +1 -1
- package/dist/assets/{mermaid-parser.core-DxEa8E3F-C43vNJPp.js → mermaid-parser.core-DxEa8E3F-DvKDRZGq.js} +2 -2
- package/dist/assets/{mermaid.core-V0OYwIz3-v8Oxyjlo.js → mermaid.core-V0OYwIz3-DU0Mr4W1.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-CexN3O6L-D3QMGDaH.js → mindmap-definition-LN4V7U3C-CexN3O6L-DMZlX-GZ.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-CQI3flND-Pi7SfNjX.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-BiM4G0cW-Bt6FgrWE.js → pegDiagram-2B236MQR-BiM4G0cW-CsQ2THPf.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-CnmKE2Wa-CCC7e9os.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-B_fBBS-2-CEmdDz9t.js → pieDiagram-ENE6RG2P-B_fBBS-2-BQVfIkOE.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-BigGVxCR-4kYUj0VK.js → quadrantDiagram-ABIIQ3AL-BigGVxCR-DWtRt8Ki.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-us6x-Z9R-CXlDDsf0.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-BKdz6pdN-CtqN4OYA.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-m_CSSIfd-Cx7DnzdQ.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-Nu3nAG7C-CZCUMFL6.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6--Y3mD4R_-DEZTHe61.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6--lNIlG64-BS12t8Yr.js → railroadDiagram-RFXS5EU6--lNIlG64-DhhBhlYi.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-D-B0Y5Wu-B1_SLwFo.js → requirementDiagram-TGXJPOKE-D-B0Y5Wu-CX6hh2lX.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-DlutaXDv-CFF-xYsd.js → sankeyDiagram-HTMAVEWB-DlutaXDv-D4lvqkh6.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BOLgtggH-DJXV6qUI.js → sequenceDiagram-DBY2YBRQ-BOLgtggH-DBzQDGiD.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-jf_dXUEU-BD6GsGtH.js → stateDiagram-2N3HPSRC-jf_dXUEU-DAoAJ2BI.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-CuzgCL2v-CZK_6dwu.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-CYjtALQH-CHqwZOyR.js → swimlanes-5IMT3BWC-CYjtALQH-DOQhVlBd.js} +1 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-3bmSBtKs-MQB8RGJN.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-DYJ4oUm8-Dsee2TjT.js → timeline-definition-FHXFAJF6-DYJ4oUm8-GXp4cKym.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-D27HWG6Q-DhjAUXqS.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-CmGIU3H5-C3IZTO8B.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-CdKAHoek-d0nAypXX.js → vennDiagram-L72KCM5P-CdKAHoek-BozSpm60.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-CbHWsb2k-BrvClPld.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-BF6c4_CW-BStK630L.js → wardleyDiagram-EHGQE667-BF6c4_CW-BhXZxWJk.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-CGiKngj7--qXz8KqF.js → xychartDiagram-FW5EYKEG-CGiKngj7-DG_02eZy.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/config/app-config.ts +31 -0
- package/server/config/config-body.ts +11 -1
- package/server/config/config-routes.ts +8 -0
- package/server/config/config-schema.ts +35 -1
- package/server/config/dir-config.ts +11 -1
- package/server/routes/app-routes.ts +5 -0
- package/server/routes/decision-routes.ts +126 -0
- package/server/session/decisions.ts +278 -0
- package/dist/assets/architecture-TIHT7OUA-0NsD2xW1-BQjHKl14.js +0 -1
- package/dist/assets/channel-7wUqSdoX-i1Oxds2I.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-BYlRi6YQ-w-oQvzN_.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-BCHaYHxj-w-oQvzN_.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-CGYr2F6h-BbR1aAzz.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-CWmqhm3a-DXHpv7ri.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DKSB5AiY-BAXt5ZcK.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-BR9qPwdN-C5VWobaj.js +0 -1
- package/dist/assets/info-DKCQHKI2-Dplx5kMp-dN3WlTdS.js +0 -1
- package/dist/assets/packet-7NZHBO7P-CQI3flND-0aWqmW17.js +0 -1
- package/dist/assets/pie-RZYD4A2V-CnmKE2Wa-BuudBowH.js +0 -1
- package/dist/assets/radar-I7S5WNFK-us6x-Z9R-CoI_TbnK.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-BKdz6pdN-D-Aq_3zs.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-m_CSSIfd-CYcDcmr_.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-Nu3nAG7C-D-PAMLpZ.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6--Y3mD4R_-CAkKdvRU.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-CuzgCL2v-CGUWQotU.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-3bmSBtKs-YHo-FlZ7.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-D27HWG6Q-XRfUQQF3.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-CmGIU3H5-DV-AlqRD.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-CbHWsb2k-Dvuabdt5.js +0 -1
package/README.md
CHANGED
|
@@ -1144,6 +1144,7 @@ same-origin-guarded.
|
|
|
1144
1144
|
| `GET /api/cost?cwd=&session=` | Estimated $ cost — session / today / month. |
|
|
1145
1145
|
| `GET /api/transcript/timeline?session=&cwd=` | Per-session activity timeline (tools run). |
|
|
1146
1146
|
| `GET /api/transcript/last-turn?session=&cwd=&agent=` | A session's last completed exchange (`prompt`, `reply`) plus the `text` to paste into another terminal. `agent=codex` reads the codex rollout instead of the Claude transcript. |
|
|
1147
|
+
| `GET /api/decisions?cwd=&limit=` | The decisions a human was asked to make in this project, newest first — each question with the options it offered, their descriptions, and the answer. `answerKind` says whether the answer was one of the options, text the user wrote instead (the question was wrong), or never given. Read out of Claude's own transcripts; writes nothing. `scanned` reports how many transcripts were read (the scan is capped) and `unreadable` how many could not be, so a partial answer is visible rather than implied. A `cwd` that is not an existing directory answers an empty response rather than falling back to the default workspace. |
|
|
1147
1148
|
|
|
1148
1149
|
**Git & worktrees**
|
|
1149
1150
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// A decision a human was asked to make, as it was actually asked and answered.
|
|
2
|
+
//
|
|
3
|
+
// The record is not something this app writes: Claude Code already stores every
|
|
4
|
+
// `AskUserQuestion` in its transcript, options and chosen answer included. These types are the
|
|
5
|
+
// shape we read it back in, shared because both the API and the UI decide from them (#997).
|
|
6
|
+
|
|
7
|
+
/** One option the user was offered, with the reasoning shown alongside it — this is where the
|
|
8
|
+
* consequence of the branch NOT taken is recorded. */
|
|
9
|
+
export interface DecisionOption {
|
|
10
|
+
label: string;
|
|
11
|
+
description: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Where the answer came from. `free-text` means the user declined every option and wrote their
|
|
15
|
+
* own answer, which is evidence about the QUESTION (wrong options, or a premise the asker and
|
|
16
|
+
* the user did not share) rather than about the choice. `unanswered` is a question that was
|
|
17
|
+
* asked and never resolved — the session was interrupted or abandoned. */
|
|
18
|
+
export type DecisionAnswerKind = "option" | "free-text" | "unanswered";
|
|
19
|
+
|
|
20
|
+
export interface DecisionQuestion {
|
|
21
|
+
question: string;
|
|
22
|
+
/** The short chip the UI showed above the question ("進め方", "Auth method"). */
|
|
23
|
+
header: string;
|
|
24
|
+
multiSelect: boolean;
|
|
25
|
+
options: DecisionOption[];
|
|
26
|
+
/** Verbatim, exactly as it came back. Null when nothing came back. */
|
|
27
|
+
answer: string | null;
|
|
28
|
+
answerKind: DecisionAnswerKind;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** One `AskUserQuestion` call: the questions it asked together, and what each got back. */
|
|
32
|
+
export interface DecisionRecord {
|
|
33
|
+
sessionId: string;
|
|
34
|
+
cwd: string | null;
|
|
35
|
+
/** ISO timestamp of the turn that asked. */
|
|
36
|
+
ts: string;
|
|
37
|
+
toolUseId: string;
|
|
38
|
+
questions: DecisionQuestion[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface DecisionsResponse {
|
|
42
|
+
decisions: DecisionRecord[];
|
|
43
|
+
/** How many transcripts were read successfully. Bounded, so a caller can tell a quiet project
|
|
44
|
+
* from a truncated scan. */
|
|
45
|
+
scanned: number;
|
|
46
|
+
/** How many could not be read at all. Reported rather than folded into `scanned`, because a
|
|
47
|
+
* read that failed is missing decisions — not a session that had none. */
|
|
48
|
+
unreadable: number;
|
|
49
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// A custom theme's colours, and the rules that turn a user's `themes` entry into something the
|
|
2
|
+
// app can paint with. Shared across the build boundary for the same reason THEME_COLOR_KEYS is
|
|
3
|
+
// (see themeColors.ts): the server VALIDATES a config against these keys and the client APPLIES
|
|
4
|
+
// it, so a key known to one side and not the other would be accepted and then silently ignored.
|
|
5
|
+
|
|
6
|
+
import { THEME_IDS, type ThemeId } from "./themeIds.js";
|
|
7
|
+
|
|
8
|
+
// The CSS custom properties one theme sets, mirroring the `:root[data-theme=...]` blocks in
|
|
9
|
+
// src/style.css. A theme with no `extends` has to supply every one of them — a half-painted
|
|
10
|
+
// theme is worse than none, because the missing half falls back to whatever the previous theme
|
|
11
|
+
// left on the element.
|
|
12
|
+
export const THEME_VAR_KEYS = [
|
|
13
|
+
"--bg-base",
|
|
14
|
+
"--bg-deep",
|
|
15
|
+
"--bg-panel",
|
|
16
|
+
"--bg-subtle",
|
|
17
|
+
"--bg-elevated",
|
|
18
|
+
"--bg-input",
|
|
19
|
+
"--bg-hover",
|
|
20
|
+
"--bg-selected",
|
|
21
|
+
"--bg-selected-hover",
|
|
22
|
+
"--border",
|
|
23
|
+
"--accent",
|
|
24
|
+
"--accent-bg",
|
|
25
|
+
"--accent-bg-hover",
|
|
26
|
+
"--on-accent",
|
|
27
|
+
"--text",
|
|
28
|
+
"--text-secondary",
|
|
29
|
+
"--text-muted",
|
|
30
|
+
"--text-dim",
|
|
31
|
+
"--term-fg",
|
|
32
|
+
"--term-selection",
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
export type ThemeVarKey = (typeof THEME_VAR_KEYS)[number];
|
|
36
|
+
export type ThemeVars = Record<ThemeVarKey, string>;
|
|
37
|
+
|
|
38
|
+
/** An id a user may give a custom theme: lowercase, digits and dashes, so it is safe both as a
|
|
39
|
+
* `data-theme` attribute value and as something to type into a `.mulmoterminal.json`. */
|
|
40
|
+
export const CUSTOM_THEME_ID_RE = /^[a-z][a-z0-9-]{0,31}$/;
|
|
41
|
+
|
|
42
|
+
/** Whether a value could name a theme — built-in OR user-defined.
|
|
43
|
+
*
|
|
44
|
+
* The result is `string`, deliberately NOT `ThemeId`: that is the CLOSED set of four built-ins,
|
|
45
|
+
* and a guard claiming it while custom ids flow through would let downstream code treat a
|
|
46
|
+
* four-way switch as exhaustive (Codex review on #996). Membership is not checked here — the
|
|
47
|
+
* server drops an id that resolves to nothing, and termThemeFor() resolves what survives. */
|
|
48
|
+
export function isThemeIdLike(value: unknown): value is string {
|
|
49
|
+
return typeof value === "string" && CUSTOM_THEME_ID_RE.test(value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function isBuiltinThemeId(id: string): id is ThemeId {
|
|
53
|
+
return (THEME_IDS as readonly string[]).includes(id);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Whether an id may be used for a CUSTOM theme. Built-in ids are refused rather than merged
|
|
57
|
+
* into: someone reading the guide's description of Midnight has to get Midnight. */
|
|
58
|
+
export function isUsableCustomThemeId(id: unknown): id is string {
|
|
59
|
+
return typeof id === "string" && CUSTOM_THEME_ID_RE.test(id) && !isBuiltinThemeId(id);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface CustomThemeInput {
|
|
63
|
+
id: string;
|
|
64
|
+
label: string;
|
|
65
|
+
/** A built-in theme to start from. Omitted means `colors` must be complete. */
|
|
66
|
+
extends?: ThemeId;
|
|
67
|
+
colors: Partial<ThemeVars>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The full variable set for a theme: the base it extends, with its own colours on top.
|
|
71
|
+
* `builtins` supplies the base sets so this stays pure — the client reads them from the
|
|
72
|
+
* stylesheet's source of truth, the specs from a fixture. */
|
|
73
|
+
export function resolveThemeVars(theme: CustomThemeInput, builtins: Record<ThemeId, ThemeVars>): ThemeVars | null {
|
|
74
|
+
const base = theme.extends ? builtins[theme.extends] : null;
|
|
75
|
+
const merged = { ...(base ?? {}), ...theme.colors } as Partial<ThemeVars>;
|
|
76
|
+
const missing = THEME_VAR_KEYS.filter((key) => !merged[key]);
|
|
77
|
+
// No base and an incomplete list is the one case we cannot paint: report it rather than
|
|
78
|
+
// leaving the gaps to whatever the previously applied theme put on the element.
|
|
79
|
+
return missing.length ? null : (merged as ThemeVars);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function channel(hex: string, at: number): number {
|
|
83
|
+
const value = parseInt(hex.slice(at, at + 2), 16) / 255;
|
|
84
|
+
return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** `#rgb` / `#rgba` / `#rrggbb` / `#rrggbbaa` as `#rrggbb`, or null. The config schema accepts
|
|
88
|
+
* every one of those forms, so anything reading a colour has to expand the short ones — a
|
|
89
|
+
* luminance check that understood only the six-digit form would read `#fff` as unmeasurable and
|
|
90
|
+
* call a white theme dark (Codex review on #996).
|
|
91
|
+
*
|
|
92
|
+
* Alpha is dropped rather than composited: what a translucent `--bg-base` ends up looking like
|
|
93
|
+
* depends on what is behind it, which nothing here can know. The opaque colour is the closest
|
|
94
|
+
* honest answer, and `--bg-base` is the one variable where translucency makes least sense. */
|
|
95
|
+
export function normalizeHexColor(color: string): string | null {
|
|
96
|
+
const hex = color.trim().toLowerCase();
|
|
97
|
+
if (!/^#[0-9a-f]{3,8}$/.test(hex)) return null;
|
|
98
|
+
const digits = hex.slice(1);
|
|
99
|
+
if (digits.length === 3 || digits.length === 4) {
|
|
100
|
+
return `#${[...digits.slice(0, 3)].map((d) => d + d).join("")}`;
|
|
101
|
+
}
|
|
102
|
+
if (digits.length === 6 || digits.length === 8) return `#${digits.slice(0, 6)}`;
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Relative luminance (WCAG) of any hex colour the config accepts. Null for anything else. */
|
|
107
|
+
export function relativeLuminance(color: string): number | null {
|
|
108
|
+
const hex = normalizeHexColor(color);
|
|
109
|
+
if (!hex) return null;
|
|
110
|
+
return 0.2126 * channel(hex, 1) + 0.7152 * channel(hex, 3) + 0.0722 * channel(hex, 5);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Above this, the chrome is treated as a light theme. The status pills (ok / warn / err) come in
|
|
114
|
+
// a dark-background set and a light-background set, and picking the wrong one leaves them
|
|
115
|
+
// unreadable — which is why this is derived rather than declared: a theme author who never
|
|
116
|
+
// thinks about it still gets legible pills.
|
|
117
|
+
const LIGHT_LUMINANCE_THRESHOLD = 0.4;
|
|
118
|
+
|
|
119
|
+
export function isLightTheme(vars: ThemeVars): boolean {
|
|
120
|
+
const luminance = relativeLuminance(vars["--bg-base"]);
|
|
121
|
+
return luminance !== null && luminance > LIGHT_LUMINANCE_THRESHOLD;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** The xterm palette a theme's variables imply. xterm draws on a canvas and cannot read CSS
|
|
125
|
+
* variables, so the same colours have to reach it as values — derived here rather than asked
|
|
126
|
+
* for twice, since two copies of one colour is two chances to change only one. The 16 ANSI
|
|
127
|
+
* colours are NOT derived: they come from the base theme, which is what `extends` is for. */
|
|
128
|
+
export function termThemeFromVars(vars: ThemeVars): { background: string; foreground: string; selectionBackground: string } {
|
|
129
|
+
return {
|
|
130
|
+
background: vars["--bg-base"],
|
|
131
|
+
foreground: vars["--term-fg"],
|
|
132
|
+
selectionBackground: vars["--term-selection"],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"./chunk-Y2CYZVJY-Bdt8pFDJ-DsF7k-Jl.js";import{f as t}from"./src-Brzfja-q-ch1VcTiG.js";import{_ as n,g as r}from"./mermaid-parser.core-DxEa8E3F-
|
|
1
|
+
import{n as e}from"./chunk-Y2CYZVJY-Bdt8pFDJ-DsF7k-Jl.js";import{f as t}from"./src-Brzfja-q-ch1VcTiG.js";import{_ as n,g as r}from"./mermaid-parser.core-DxEa8E3F-DvKDRZGq.js";import"./chunk-WYO6CB5R-BlzOfotS-DenoOpP3.js";import"./chunk-VAUOI2AC-CS9QJ4yz-r_1UiH65.js";import{n as i,r as a,t as o}from"./chunk-MOJQB5TN-CMZRaeqt-DDn-QIzL.js";import{t as s}from"./chunk-JWPE2WC7-BQ3zXr2k-DSd3Ct95.js";var c=r().RailroadAbnf.parser.LangiumParser,l=e(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=e(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=e(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=e(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=e(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=e(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=e(e=>{s(e,a),e.title&&a.setTitle(e.title),e.rules.map(e=>a.addRule(m(e)))},`populateDb`),g={parser:{parse:e(e=>{a.clear(),t.debug(`[ABNF Parser] Starting Langium parse`);let r=c.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new n(r);let i=r.value;t.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),t.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:a}},db:a,renderer:o,styles:i};export{g as diagram};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{f as e}from"./mermaid-parser.core-DxEa8E3F-DvKDRZGq.js";export{e as createArchitectureServices};
|