@sagmans/dsh-tui 0.10.0 → 0.11.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.
Files changed (50) hide show
  1. package/.agents/skills/dsh-tui-dogfood/SKILL.md +6 -1
  2. package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +2 -2
  3. package/README.md +23 -16
  4. package/cordis.patch.yml +23 -100
  5. package/lib/agent/presets.d.ts.map +1 -1
  6. package/lib/agent/presets.js +8 -3
  7. package/lib/agent/presets.js.map +1 -1
  8. package/lib/compat/probe.js +1 -1
  9. package/lib/compat/probe.js.map +1 -1
  10. package/lib/compat/section.d.ts +8 -1
  11. package/lib/compat/section.d.ts.map +1 -1
  12. package/lib/compat/section.js +3 -2
  13. package/lib/compat/section.js.map +1 -1
  14. package/lib/host/preset-files.d.ts +27 -0
  15. package/lib/host/preset-files.d.ts.map +1 -0
  16. package/lib/host/preset-files.js +40 -0
  17. package/lib/host/preset-files.js.map +1 -0
  18. package/lib/host/roster.d.ts +17 -0
  19. package/lib/host/roster.d.ts.map +1 -0
  20. package/lib/host/roster.js +42 -0
  21. package/lib/host/roster.js.map +1 -0
  22. package/lib/host/runner.d.ts +15 -0
  23. package/lib/host/runner.d.ts.map +1 -0
  24. package/lib/host/runner.js +17 -0
  25. package/lib/host/runner.js.map +1 -0
  26. package/lib/index.d.ts +4 -1
  27. package/lib/index.d.ts.map +1 -1
  28. package/lib/index.js +5 -2
  29. package/lib/index.js.map +1 -1
  30. package/lib/surface/appearance-preferences.d.ts.map +1 -1
  31. package/lib/surface/appearance-preferences.js +3 -2
  32. package/lib/surface/appearance-preferences.js.map +1 -1
  33. package/lib/surface/preset-choice.d.ts.map +1 -1
  34. package/lib/surface/preset-choice.js +38 -2
  35. package/lib/surface/preset-choice.js.map +1 -1
  36. package/lib/todo-guard.d.ts +17 -0
  37. package/lib/todo-guard.d.ts.map +1 -1
  38. package/lib/todo-guard.js +3 -1
  39. package/lib/todo-guard.js.map +1 -1
  40. package/lib/transcript/tool-calls.d.ts.map +1 -1
  41. package/lib/transcript/tool-calls.js +16 -2
  42. package/lib/transcript/tool-calls.js.map +1 -1
  43. package/package.json +40 -29
  44. package/presets/cordis.patch.yml +14 -0
  45. package/presets/minimal.patch.yml +14 -0
  46. package/presets/ptc.patch.yml +24 -0
  47. package/presets/standard.patch.yml +14 -0
  48. package/themes/marine-static.yaml +201 -0
  49. package/themes/pine-slope.yaml +203 -0
  50. package/themes/wine-thicket.yaml +205 -0
@@ -0,0 +1,24 @@
1
+ # Agent preset ptc: the mode this bundle's roster registers, and the whole
2
+ # of what it declares.
3
+ #
4
+ # A mode is a selection, not a composition. The rows that make up an agent's
5
+ # tools, prompt sections, skills and planning live in the bundle each of them
6
+ # belongs to, so listing them here would register a plugin this bundle does not
7
+ # own a second time and fail composition in a profile that already has it.
8
+ #
9
+ # The presentation is the one row a mode does own: it declares which form of its
10
+ # tools this agent's model sees, for the mounting scope rather than for a
11
+ # session, so it belongs to the preset and nowhere else. Without it `ptc` names a
12
+ # mode that presents exactly like `standard` — every tool called directly, none
13
+ # of them reached through a program.
14
+ - insert:
15
+ - id: preset-ptc
16
+ name: '@deepseek-ai/dsh-agent-preset'
17
+ config:
18
+ id: ptc
19
+ order: 2
20
+ plugins:
21
+ - id: tool-presentation
22
+ name: '@deepseek-ai/dsh-agent-tool-presentation'
23
+ config:
24
+ mode: ptc
@@ -0,0 +1,14 @@
1
+ # Agent preset standard: the mode this bundle's roster registers, and the whole
2
+ # of what it declares.
3
+ #
4
+ # A mode is a selection, not a composition. The rows that make up an agent's
5
+ # tools, prompt sections, skills and planning live in the bundle each of them
6
+ # belongs to, so listing them here would register a plugin this bundle does not
7
+ # own a second time and fail composition in a profile that already has it.
8
+ - insert:
9
+ - id: preset-standard
10
+ name: '@deepseek-ai/dsh-agent-preset'
11
+ config:
12
+ id: standard
13
+ order: 1
14
+ plugins: []
@@ -0,0 +1,201 @@
1
+ # marine-static — the shipped table, anchored on the deep teal #041F21.
2
+ #
3
+ # The anchor is a fill weight rather than a text weight: at 1.08:1 against a dark
4
+ # terminal it marks the row a picker has selected by its hue and adds almost no
5
+ # contrast of its own, which is why the accent is that same hue lifted to where
6
+ # text reads. Every neutral is the anchor's hue at a low saturation, so the surface
7
+ # reads as one family rather than as grey rows with a teal link on them.
8
+ #
9
+ # The shades hold the shipped table's own ladder — each role takes the same share
10
+ # of the theme's text luminance (muted 0.63, faint 0.42, arg 0.25, accent 0.57,
11
+ # warn 0.61, added 0.56, removed 0.25) — so this theme is dimmer in absolute terms
12
+ # and identical in structure to any other, and a reader who knows one knows this
13
+ # one. Only the level and the chroma are its own.
14
+ #
15
+ # This family stands in the same water as polar-drift's cyan, so the accent is held
16
+ # well back from the neon: the same hue with far less chroma at a lower level is
17
+ # what keeps the two from reading as one theme drawn twice. Green and amber sit far
18
+ # from the family and stay where every surface keeps them.
19
+ #
20
+ # Every element below names a palette entry rather than a shade of its own, so
21
+ # the anchor and the accent it lifts to are one line each to move. The three that
22
+ # name a literal say why there.
23
+ #
24
+ # This file is a reference and a layer, not a workspace: it ships inside the
25
+ # package and a new version replaces it. /theme export marine-static writes a full copy
26
+ # into your own themes directory to edit.
27
+
28
+ palette:
29
+ default: '#adbbbc' # the anchor's hue at 10% saturation: the level every other shade is a share of
30
+ muted: '#809a9b' # 0.63 of the text's luminance: labels and scaffolding
31
+ faint: '#638184' # 0.42: reasoning, which is meant to recede
32
+ accent: '#2e9ca4' # 0.56: the anchor's hue lifted to text weight for headings, links, code, frames
33
+ arg: '#3f686a' # 0.25: an argument recedes under the label of the call it belongs to
34
+ warn: '#bf8a1f' # 0.61, in amber: a call that has not answered
35
+ added: '#3b9f65' # 0.56, in green: something that arrived
36
+ removed: '#b03236' # 0.25, in red: something taken away
37
+ user: '#041f21' # the anchor itself: the band under a selected row, and one panel border
38
+ assistant: '#adbbbc' # the reply's text stays plain, so the frame is what marks it
39
+
40
+ tokens:
41
+ # A row of the conversation. The reader's own turn keeps its frame and carries
42
+ # no band: a filled row inside that frame reads as a selected row, and the
43
+ # anchor's own weight would swallow the text it is meant to hold.
44
+ transcript.user: { fg: default }
45
+ # A sent prompt keeps the accent shade without inheriting the editor's setting.
46
+ transcript.user.border: { fg: accent }
47
+ # The reply's own frame. It holds the family's hue at container weight rather
48
+ # than the accent the prompt is framed in: the two frames then differ by how
49
+ # loud they are instead of by hue, and a long answer never wears the shade that
50
+ # means "this is what you typed".
51
+ transcript.assistant.border: { fg: '#416265' }
52
+ transcript.notice: { fg: muted }
53
+ transcript.marker: { fg: muted }
54
+ transcript.reasoning.summary: { fg: faint, italic: true }
55
+ transcript.reasoning.body: { fg: faint }
56
+ transcript.reasoning.hint: { fg: faint, italic: true }
57
+ # A tool card, drawn in layers: every card, then one kind of card.
58
+ # A call is not a warning, so the label takes the accent rather than the amber
59
+ # the surface reserves for a call that has not answered — the label is the
60
+ # loudest thing on the row, and loudness is what the accent is for.
61
+ tool.title: { fg: accent }
62
+ tool.glyph: { fg: accent } # follows the label it sits beside
63
+ tool.skill: { fg: accent } # follows the label it sits beside
64
+ tool.args: { fg: arg } # below the reasoning shade: an argument is quieter than what the call is doing
65
+ tool.stat.added: { fg: added }
66
+ tool.stat.changed: { fg: warn }
67
+ tool.stat.removed: { fg: removed }
68
+ tool.stat.size: { fg: muted }
69
+ tool.stat.separator: { fg: muted }
70
+ tool.detail: { fg: muted }
71
+ tool.hint: { fg: muted }
72
+ tool.failed.title: { fg: removed }
73
+ tool.failed.glyph: { fg: removed }
74
+ # A call still in flight is state, which is amber's job here; the failed row
75
+ # stays red so the two can never be read as each other.
76
+ tool.running.title: { fg: warn }
77
+ tool.running.elapsed: { fg: warn }
78
+ tool.elapsed.done: { fg: muted, italic: true }
79
+ tool.subcall.title: { fg: muted }
80
+ tool.subcall.running: { fg: warn }
81
+ tool.subcall.args: { fg: arg }
82
+ tool.diff.header: { fg: muted }
83
+ tool.diff.hunk: { fg: muted }
84
+ tool.diff.added: { fg: added }
85
+ tool.diff.removed: { fg: removed }
86
+ tool.read.header: { fg: muted }
87
+ tool.read.lineNumber: { fg: muted }
88
+ tool.read.line: { fg: muted }
89
+ tool.search.path: { fg: muted }
90
+ tool.search.lineNumber: { fg: muted }
91
+ tool.search.match: { fg: muted }
92
+ tool.search.truncated: { fg: muted }
93
+ tool.terminal.cwd: { fg: muted }
94
+ tool.terminal.status: { fg: muted }
95
+ tool.terminal.output: { fg: muted }
96
+ tool.web.url: { fg: muted }
97
+ tool.web.source: { fg: muted }
98
+ tool.web.truncated: { fg: muted }
99
+ tool.generic.detail: { fg: muted }
100
+ # A reply, which is markdown, and the diagrams in it.
101
+ markdown.heading: { fg: accent, bold: true }
102
+ markdown.link: { fg: accent, underline: true }
103
+ markdown.linkUrl: { fg: muted }
104
+ markdown.code: { fg: accent }
105
+ markdown.codeBlock: {}
106
+ markdown.codeBlockBorder: { fg: muted }
107
+ markdown.quote: { fg: muted }
108
+ markdown.quoteBorder: { fg: muted }
109
+ markdown.hr: { fg: muted }
110
+ markdown.listBullet: { fg: accent }
111
+ markdown.bold: { bold: true }
112
+ markdown.italic: { italic: true }
113
+ markdown.strikethrough: { strike: true }
114
+ markdown.underline: { underline: true }
115
+ # A fenced diff: the scaffolding recedes, the rows carry the semantic shades,
116
+ # and the characters that changed sit on a band of the row's own colour. The
117
+ # band is a shade derived from that colour rather than a palette entry, so it
118
+ # stays a literal, and the foreground inherits so a palette move carries both.
119
+ markdown.diff.header: { fg: muted }
120
+ markdown.diff.hunk: { fg: muted }
121
+ markdown.diff.context: {}
122
+ markdown.diff.added: { fg: added }
123
+ markdown.diff.removed: { fg: removed }
124
+ markdown.diff.addedEmphasis: { inherit: markdown.diff.added, bg: '#11291b' }
125
+ markdown.diff.removedEmphasis: { inherit: markdown.diff.removed, bg: '#301415' }
126
+ markdown.diagram.border: { fg: muted }
127
+ markdown.diagram.text: {}
128
+ markdown.diagram.edge: { fg: accent }
129
+ markdown.diagram.edgeLabel: { fg: muted }
130
+ markdown.diagram.title: { fg: accent, bold: true }
131
+ markdown.diagram.warning: { fg: warn }
132
+ # A list drawn over the transcript.
133
+ picker.title: { bold: true }
134
+ picker.glyph: { bold: true }
135
+ picker.note: { bold: true }
136
+ picker.filter: { fg: muted }
137
+ # A list is read by moving one row, so the rows the cursor is not on recede:
138
+ # the selected row is then found by its own shade rather than by hunting for
139
+ # the mark in front of it, which is what a bold row alone leaves a reader doing.
140
+ picker.row: { fg: muted }
141
+ picker.rowCurrent: { fg: accent, bold: true, bg: user }
142
+ picker.scrollNewer: { fg: muted }
143
+ picker.scrollOlder: { fg: muted }
144
+ picker.hint: { fg: muted }
145
+ picker.cursor: {}
146
+ picker.border: { fg: muted }
147
+ # A question or an approval, which stops the turn until it is answered.
148
+ gate.title: { bold: true }
149
+ gate.glyphApproval: { bold: true }
150
+ gate.glyphQuestion: { bold: true }
151
+ gate.detail: { fg: muted }
152
+ gate.option: {}
153
+ gate.optionCurrent: { bold: true }
154
+ gate.cursor: {}
155
+ gate.hint: { fg: muted }
156
+ # The work panel above the editor. Each panel is a bordered box, so the border
157
+ # is what says which panel a row belongs to and the rows themselves stay quiet.
158
+ dock.goal: { bold: true }
159
+ dock.planMode: { bold: true }
160
+ dock.todos.border: { fg: accent }
161
+ dock.todos.heading: { bold: true }
162
+ dock.todos.pending: { fg: muted }
163
+ dock.todos.inProgress: { fg: muted }
164
+ dock.todos.overflow: { fg: muted }
165
+ dock.subagents.border: { fg: user }
166
+ dock.subagents.heading: { bold: true }
167
+ dock.subagents.running: { fg: muted }
168
+ dock.subagents.overflow: { fg: muted }
169
+ dock.jobs.border: { fg: warn }
170
+ dock.jobs.heading: { bold: true }
171
+ dock.jobs.running: { fg: muted }
172
+ dock.jobs.overflow: { fg: muted }
173
+ # The footer.
174
+ status.prefix: { fg: accent }
175
+ status.back: { fg: accent }
176
+ # A turn in flight is the one state a reader waits on, so it takes the accent
177
+ # and the weight; ready stays quiet because it is where the surface rests.
178
+ status.activity.working: { fg: accent, bold: true }
179
+ status.activity.ready: { fg: muted }
180
+ status.elapsed: { fg: muted }
181
+ status.agentPreset: { fg: muted }
182
+ status.model: { fg: muted }
183
+ status.effort: { fg: muted }
184
+ status.permission: { fg: muted }
185
+ status.context: { fg: muted }
186
+ status.cache: { fg: muted }
187
+ status.stash: { fg: accent }
188
+ status.cwd: { fg: muted }
189
+ status.separator: { fg: muted }
190
+ # The prompt bar.
191
+ # The one border in the surface that is not a divider: it holds what the reader
192
+ # is writing, which is where the brand belongs on a send affordance.
193
+ editor.border: { fg: accent }
194
+ editor.queued: { dim: true, italic: true }
195
+ editor.queued.more: { fg: muted }
196
+ editor.ghost: { dim: true }
197
+ editor.selectList.selectedPrefix: { fg: accent }
198
+ editor.selectList.selectedText: { bold: true }
199
+ editor.selectList.description: { fg: muted }
200
+ editor.selectList.scrollInfo: { fg: muted }
201
+ editor.selectList.noMatch: { fg: muted }
@@ -0,0 +1,203 @@
1
+ # pine-slope — the shipped table, anchored on the pine #173802.
2
+ #
3
+ # The anchor is a fill weight rather than a text weight: at 1.41:1 against a dark
4
+ # terminal it paints the band under a selected row and the one panel border that
5
+ # names it, and the accent is that same hue lifted to where text reads. Every
6
+ # neutral is the anchor's hue at a low saturation, so the surface reads as one
7
+ # family rather than as grey rows with a green link on them.
8
+ #
9
+ # The shades hold the shipped table's own ladder — each role takes the same share
10
+ # of the theme's text luminance (muted 0.63, faint 0.42, arg 0.25, accent 0.57,
11
+ # warn 0.61, added 0.56, removed 0.25) — so this theme is dimmer in absolute terms
12
+ # and identical in structure to any other, and a reader who knows one knows this
13
+ # one. Only the level and the chroma are its own, which is what keeps it soft
14
+ # beside a bright terminal instead of competing with it.
15
+ #
16
+ # Green is the family here, and green is also what an added line means. The
17
+ # accent therefore stays a lime while the semantic green is pushed toward grass:
18
+ # a reader never has to ask whether a green row is the theme or the change. Red
19
+ # and amber stay where every surface keeps them — something removed, a call that
20
+ # has not answered.
21
+ #
22
+ # Every element below names a palette entry rather than a shade of its own, so
23
+ # the anchor and the accent it lifts to are one line each to move. The three that
24
+ # name a literal say why there.
25
+ #
26
+ # This file is a reference and a layer, not a workspace: it ships inside the
27
+ # package and a new version replaces it. /theme export pine-slope writes a full
28
+ # copy into your own themes directory to edit.
29
+
30
+ palette:
31
+ default: '#bac1b3' # the anchor's hue at 7% saturation: the level every other shade is a share of
32
+ muted: '#939f89' # 0.63 of the text's luminance: labels and scaffolding
33
+ faint: '#738768' # 0.42: reasoning, which is meant to recede
34
+ accent: '#69a33a' # 0.57: the anchor's hue lifted to text weight for headings, links, code, frames
35
+ arg: '#506d3c' # 0.25: an argument recedes under the label of the call it belongs to
36
+ warn: '#c59021' # 0.61, in amber: a call that has not answered
37
+ added: '#41a477' # 0.56, pushed toward grass: a change is not the theme's own green
38
+ removed: '#b43937' # 0.25, in red: something taken away
39
+ user: '#173802' # the anchor itself: the band under a selected row, and one panel border
40
+ assistant: '#bac1b3' # the reply's text stays plain, so the frame is what marks it
41
+
42
+ tokens:
43
+ # A row of the conversation. The reader's own turn keeps its frame and carries
44
+ # no band: a filled row inside that frame reads as a selected row, and the
45
+ # anchor's own weight would swallow the text it is meant to hold.
46
+ transcript.user: { fg: default }
47
+ # A sent prompt keeps the accent shade without inheriting the editor's setting.
48
+ transcript.user.border: { fg: accent }
49
+ # The reply's own frame. It holds the family's hue at container weight rather
50
+ # than the accent the prompt is framed in: the two frames then differ by how
51
+ # loud they are instead of by hue, and a long answer never wears the shade that
52
+ # means "this is what you typed".
53
+ transcript.assistant.border: { fg: '#526646' }
54
+ transcript.notice: { fg: muted }
55
+ transcript.marker: { fg: muted }
56
+ transcript.reasoning.summary: { fg: faint, italic: true }
57
+ transcript.reasoning.body: { fg: faint }
58
+ transcript.reasoning.hint: { fg: faint, italic: true }
59
+ # A tool card, drawn in layers: every card, then one kind of card.
60
+ # A call is not a warning, so the label takes the accent rather than the amber
61
+ # the surface reserves for a call that has not answered — the label is the
62
+ # loudest thing on the row, and loudness is what the accent is for.
63
+ tool.title: { fg: accent }
64
+ tool.glyph: { fg: accent } # follows the label it sits beside
65
+ tool.skill: { fg: accent } # follows the label it sits beside
66
+ tool.args: { fg: arg } # below the reasoning shade: an argument is quieter than what the call is doing
67
+ tool.stat.added: { fg: added }
68
+ tool.stat.changed: { fg: warn }
69
+ tool.stat.removed: { fg: removed }
70
+ tool.stat.size: { fg: muted }
71
+ tool.stat.separator: { fg: muted }
72
+ tool.detail: { fg: muted }
73
+ tool.hint: { fg: muted }
74
+ tool.failed.title: { fg: removed }
75
+ tool.failed.glyph: { fg: removed }
76
+ # A call still in flight is state, which is amber's job here; the failed row
77
+ # stays red so the two can never be read as each other.
78
+ tool.running.title: { fg: warn }
79
+ tool.running.elapsed: { fg: warn }
80
+ tool.elapsed.done: { fg: muted, italic: true }
81
+ tool.subcall.title: { fg: muted }
82
+ tool.subcall.running: { fg: warn }
83
+ tool.subcall.args: { fg: arg }
84
+ tool.diff.header: { fg: muted }
85
+ tool.diff.hunk: { fg: muted }
86
+ tool.diff.added: { fg: added }
87
+ tool.diff.removed: { fg: removed }
88
+ tool.read.header: { fg: muted }
89
+ tool.read.lineNumber: { fg: muted }
90
+ tool.read.line: { fg: muted }
91
+ tool.search.path: { fg: muted }
92
+ tool.search.lineNumber: { fg: muted }
93
+ tool.search.match: { fg: muted }
94
+ tool.search.truncated: { fg: muted }
95
+ tool.terminal.cwd: { fg: muted }
96
+ tool.terminal.status: { fg: muted }
97
+ tool.terminal.output: { fg: muted }
98
+ tool.web.url: { fg: muted }
99
+ tool.web.source: { fg: muted }
100
+ tool.web.truncated: { fg: muted }
101
+ tool.generic.detail: { fg: muted }
102
+ # A reply, which is markdown, and the diagrams in it.
103
+ markdown.heading: { fg: accent, bold: true }
104
+ markdown.link: { fg: accent, underline: true }
105
+ markdown.linkUrl: { fg: muted }
106
+ markdown.code: { fg: accent }
107
+ markdown.codeBlock: {}
108
+ markdown.codeBlockBorder: { fg: muted }
109
+ markdown.quote: { fg: muted }
110
+ markdown.quoteBorder: { fg: muted }
111
+ markdown.hr: { fg: muted }
112
+ markdown.listBullet: { fg: accent }
113
+ markdown.bold: { bold: true }
114
+ markdown.italic: { italic: true }
115
+ markdown.strikethrough: { strike: true }
116
+ markdown.underline: { underline: true }
117
+ # A fenced diff: the scaffolding recedes, the rows carry the semantic shades,
118
+ # and the characters that changed sit on a band of the row's own colour. The
119
+ # band is a shade derived from that colour rather than a palette entry, so it
120
+ # stays a literal, and the foreground inherits so a palette move carries both.
121
+ markdown.diff.header: { fg: muted }
122
+ markdown.diff.hunk: { fg: muted }
123
+ markdown.diff.context: {}
124
+ markdown.diff.added: { fg: added }
125
+ markdown.diff.removed: { fg: removed }
126
+ markdown.diff.addedEmphasis: { inherit: markdown.diff.added, bg: '#112a1f' }
127
+ markdown.diff.removedEmphasis: { inherit: markdown.diff.removed, bg: '#381211' }
128
+ markdown.diagram.border: { fg: muted }
129
+ markdown.diagram.text: {}
130
+ markdown.diagram.edge: { fg: accent }
131
+ markdown.diagram.edgeLabel: { fg: muted }
132
+ markdown.diagram.title: { fg: accent, bold: true }
133
+ markdown.diagram.warning: { fg: warn }
134
+ # A list drawn over the transcript.
135
+ picker.title: { bold: true }
136
+ picker.glyph: { bold: true }
137
+ picker.note: { bold: true }
138
+ picker.filter: { fg: muted }
139
+ # A list is read by moving one row, so the rows the cursor is not on recede:
140
+ # the selected row is then found by its own shade rather than by hunting for
141
+ # the mark in front of it, which is what a bold row alone leaves a reader doing.
142
+ picker.row: { fg: muted }
143
+ picker.rowCurrent: { fg: accent, bold: true, bg: user }
144
+ picker.scrollNewer: { fg: muted }
145
+ picker.scrollOlder: { fg: muted }
146
+ picker.hint: { fg: muted }
147
+ picker.cursor: {}
148
+ picker.border: { fg: muted }
149
+ # A question or an approval, which stops the turn until it is answered.
150
+ gate.title: { bold: true }
151
+ gate.glyphApproval: { bold: true }
152
+ gate.glyphQuestion: { bold: true }
153
+ gate.detail: { fg: muted }
154
+ gate.option: {}
155
+ gate.optionCurrent: { bold: true }
156
+ gate.cursor: {}
157
+ gate.hint: { fg: muted }
158
+ # The work panel above the editor. Each panel is a bordered box, so the border
159
+ # is what says which panel a row belongs to and the rows themselves stay quiet.
160
+ dock.goal: { bold: true }
161
+ dock.planMode: { bold: true }
162
+ dock.todos.border: { fg: accent }
163
+ dock.todos.heading: { bold: true }
164
+ dock.todos.pending: { fg: muted }
165
+ dock.todos.inProgress: { fg: muted }
166
+ dock.todos.overflow: { fg: muted }
167
+ dock.subagents.border: { fg: user }
168
+ dock.subagents.heading: { bold: true }
169
+ dock.subagents.running: { fg: muted }
170
+ dock.subagents.overflow: { fg: muted }
171
+ dock.jobs.border: { fg: warn }
172
+ dock.jobs.heading: { bold: true }
173
+ dock.jobs.running: { fg: muted }
174
+ dock.jobs.overflow: { fg: muted }
175
+ # The footer.
176
+ status.prefix: { fg: accent }
177
+ status.back: { fg: accent }
178
+ # A turn in flight is the one state a reader waits on, so it takes the accent
179
+ # and the weight; ready stays quiet because it is where the surface rests.
180
+ status.activity.working: { fg: accent, bold: true }
181
+ status.activity.ready: { fg: muted }
182
+ status.elapsed: { fg: muted }
183
+ status.agentPreset: { fg: muted }
184
+ status.model: { fg: muted }
185
+ status.effort: { fg: muted }
186
+ status.permission: { fg: muted }
187
+ status.context: { fg: muted }
188
+ status.cache: { fg: muted }
189
+ status.stash: { fg: accent }
190
+ status.cwd: { fg: muted }
191
+ status.separator: { fg: muted }
192
+ # The prompt bar.
193
+ # The one border in the surface that is not a divider: it holds what the reader
194
+ # is writing, which is where the brand belongs on a send affordance.
195
+ editor.border: { fg: accent }
196
+ editor.queued: { dim: true, italic: true }
197
+ editor.queued.more: { fg: muted }
198
+ editor.ghost: { dim: true }
199
+ editor.selectList.selectedPrefix: { fg: accent }
200
+ editor.selectList.selectedText: { bold: true }
201
+ editor.selectList.description: { fg: muted }
202
+ editor.selectList.scrollInfo: { fg: muted }
203
+ editor.selectList.noMatch: { fg: muted }
@@ -0,0 +1,205 @@
1
+ # wine-thicket — the shipped table, anchored on the plum #240413.
2
+ #
3
+ # The anchor is a fill weight rather than a text weight, and at 1.03:1 against a
4
+ # dark terminal it is almost exactly the weight of the background itself: it marks
5
+ # the row a picker has selected by its hue rather than by any contrast it could
6
+ # add, which is why the level starts a step lower than the other themes' — the
7
+ # chroma is all this family offers, and the quiet has to come from the neutrals.
8
+ # The whole table is drawn on that one hue, the accent included. Every
9
+ # neutral is the anchor's hue at a low saturation, so the surface reads as one
10
+ # family rather than as grey rows with a pink link on them.
11
+ #
12
+ # The shades hold the shipped table's own ladder — each role takes the same share
13
+ # of the theme's text luminance (muted 0.63, faint 0.42, arg 0.25, accent 0.57,
14
+ # warn 0.61, added 0.56, removed 0.25) — so this theme is dimmer in absolute terms
15
+ # and identical in structure to any other, and a reader who knows one knows this
16
+ # one. Only the level and the chroma are its own.
17
+ #
18
+ # A rose accent sits 25 degrees from the red the surface already means by removed.
19
+ # The two are told apart by weight instead of by hue: the accent is nearly twice
20
+ # that red's luminance and is the only one of them that ever frames text, which is
21
+ # what keeps a diff from reading as chrome. Green and amber sit far from the family
22
+ # and stay where every surface keeps them.
23
+ #
24
+ # Every element below names a palette entry rather than a shade of its own, so
25
+ # the anchor and the accent it lifts to are one line each to move. The three that
26
+ # name a literal say why there.
27
+ #
28
+ # This file is a reference and a layer, not a workspace: it ships inside the
29
+ # package and a new version replaces it. /theme export wine-thicket writes a full copy
30
+ # into your own themes directory to edit.
31
+
32
+ palette:
33
+ default: '#beb0b6' # the anchor's hue at 10% saturation: the level every other shade is a share of
34
+ muted: '#a38b96' # 0.63 of the text's luminance: labels and scaffolding
35
+ faint: '#926f7f' # 0.42: reasoning, which is meant to recede
36
+ accent: '#d56398' # 0.56: the anchor's hue lifted to text weight for headings, links, code, frames
37
+ arg: '#844e67' # 0.25: an argument recedes under the label of the call it belongs to
38
+ warn: '#ba861e' # 0.61, in amber: a call that has not answered
39
+ added: '#399a67' # 0.55, in green: something that arrived
40
+ removed: '#ab3037' # 0.24, in red: something taken away
41
+ user: '#240413' # the anchor itself: the band under a selected row, and one panel border
42
+ assistant: '#beb0b6' # the reply's text stays plain, so the frame is what marks it
43
+
44
+ tokens:
45
+ # A row of the conversation. The reader's own turn keeps its frame and carries
46
+ # no band: a filled row inside that frame reads as a selected row, and the
47
+ # anchor's own weight would swallow the text it is meant to hold.
48
+ transcript.user: { fg: default }
49
+ # A sent prompt keeps the accent shade without inheriting the editor's setting.
50
+ transcript.user.border: { fg: accent }
51
+ # The reply's own frame. It holds the family's hue at container weight rather
52
+ # than the accent the prompt is framed in: the two frames then differ by how
53
+ # loud they are instead of by hue, and a long answer never wears the shade that
54
+ # means "this is what you typed".
55
+ transcript.assistant.border: { fg: '#784c61' }
56
+ transcript.notice: { fg: muted }
57
+ transcript.marker: { fg: muted }
58
+ transcript.reasoning.summary: { fg: faint, italic: true }
59
+ transcript.reasoning.body: { fg: faint }
60
+ transcript.reasoning.hint: { fg: faint, italic: true }
61
+ # A tool card, drawn in layers: every card, then one kind of card.
62
+ # A call is not a warning, so the label takes the accent rather than the amber
63
+ # the surface reserves for a call that has not answered — the label is the
64
+ # loudest thing on the row, and loudness is what the accent is for.
65
+ tool.title: { fg: accent }
66
+ tool.glyph: { fg: accent } # follows the label it sits beside
67
+ tool.skill: { fg: accent } # follows the label it sits beside
68
+ tool.args: { fg: arg } # below the reasoning shade: an argument is quieter than what the call is doing
69
+ tool.stat.added: { fg: added }
70
+ tool.stat.changed: { fg: warn }
71
+ tool.stat.removed: { fg: removed }
72
+ tool.stat.size: { fg: muted }
73
+ tool.stat.separator: { fg: muted }
74
+ tool.detail: { fg: muted }
75
+ tool.hint: { fg: muted }
76
+ tool.failed.title: { fg: removed }
77
+ tool.failed.glyph: { fg: removed }
78
+ # A call still in flight is state, which is amber's job here; the failed row
79
+ # stays red so the two can never be read as each other.
80
+ tool.running.title: { fg: warn }
81
+ tool.running.elapsed: { fg: warn }
82
+ tool.elapsed.done: { fg: muted, italic: true }
83
+ tool.subcall.title: { fg: muted }
84
+ tool.subcall.running: { fg: warn }
85
+ tool.subcall.args: { fg: arg }
86
+ tool.diff.header: { fg: muted }
87
+ tool.diff.hunk: { fg: muted }
88
+ tool.diff.added: { fg: added }
89
+ tool.diff.removed: { fg: removed }
90
+ tool.read.header: { fg: muted }
91
+ tool.read.lineNumber: { fg: muted }
92
+ tool.read.line: { fg: muted }
93
+ tool.search.path: { fg: muted }
94
+ tool.search.lineNumber: { fg: muted }
95
+ tool.search.match: { fg: muted }
96
+ tool.search.truncated: { fg: muted }
97
+ tool.terminal.cwd: { fg: muted }
98
+ tool.terminal.status: { fg: muted }
99
+ tool.terminal.output: { fg: muted }
100
+ tool.web.url: { fg: muted }
101
+ tool.web.source: { fg: muted }
102
+ tool.web.truncated: { fg: muted }
103
+ tool.generic.detail: { fg: muted }
104
+ # A reply, which is markdown, and the diagrams in it.
105
+ markdown.heading: { fg: accent, bold: true }
106
+ markdown.link: { fg: accent, underline: true }
107
+ markdown.linkUrl: { fg: muted }
108
+ markdown.code: { fg: accent }
109
+ markdown.codeBlock: {}
110
+ markdown.codeBlockBorder: { fg: muted }
111
+ markdown.quote: { fg: muted }
112
+ markdown.quoteBorder: { fg: muted }
113
+ markdown.hr: { fg: muted }
114
+ markdown.listBullet: { fg: accent }
115
+ markdown.bold: { bold: true }
116
+ markdown.italic: { italic: true }
117
+ markdown.strikethrough: { strike: true }
118
+ markdown.underline: { underline: true }
119
+ # A fenced diff: the scaffolding recedes, the rows carry the semantic shades,
120
+ # and the characters that changed sit on a band of the row's own colour. The
121
+ # band is a shade derived from that colour rather than a palette entry, so it
122
+ # stays a literal, and the foreground inherits so a palette move carries both.
123
+ markdown.diff.header: { fg: muted }
124
+ markdown.diff.hunk: { fg: muted }
125
+ markdown.diff.context: {}
126
+ markdown.diff.added: { fg: added }
127
+ markdown.diff.removed: { fg: removed }
128
+ markdown.diff.addedEmphasis: { inherit: markdown.diff.added, bg: '#10261b' }
129
+ markdown.diff.removedEmphasis: { inherit: markdown.diff.removed, bg: '#2e1314' }
130
+ markdown.diagram.border: { fg: muted }
131
+ markdown.diagram.text: {}
132
+ markdown.diagram.edge: { fg: accent }
133
+ markdown.diagram.edgeLabel: { fg: muted }
134
+ markdown.diagram.title: { fg: accent, bold: true }
135
+ markdown.diagram.warning: { fg: warn }
136
+ # A list drawn over the transcript.
137
+ picker.title: { bold: true }
138
+ picker.glyph: { bold: true }
139
+ picker.note: { bold: true }
140
+ picker.filter: { fg: muted }
141
+ # A list is read by moving one row, so the rows the cursor is not on recede:
142
+ # the selected row is then found by its own shade rather than by hunting for
143
+ # the mark in front of it, which is what a bold row alone leaves a reader doing.
144
+ picker.row: { fg: muted }
145
+ picker.rowCurrent: { fg: accent, bold: true, bg: user }
146
+ picker.scrollNewer: { fg: muted }
147
+ picker.scrollOlder: { fg: muted }
148
+ picker.hint: { fg: muted }
149
+ picker.cursor: {}
150
+ picker.border: { fg: muted }
151
+ # A question or an approval, which stops the turn until it is answered.
152
+ gate.title: { bold: true }
153
+ gate.glyphApproval: { bold: true }
154
+ gate.glyphQuestion: { bold: true }
155
+ gate.detail: { fg: muted }
156
+ gate.option: {}
157
+ gate.optionCurrent: { bold: true }
158
+ gate.cursor: {}
159
+ gate.hint: { fg: muted }
160
+ # The work panel above the editor. Each panel is a bordered box, so the border
161
+ # is what says which panel a row belongs to and the rows themselves stay quiet.
162
+ dock.goal: { bold: true }
163
+ dock.planMode: { bold: true }
164
+ dock.todos.border: { fg: accent }
165
+ dock.todos.heading: { bold: true }
166
+ dock.todos.pending: { fg: muted }
167
+ dock.todos.inProgress: { fg: muted }
168
+ dock.todos.overflow: { fg: muted }
169
+ dock.subagents.border: { fg: user }
170
+ dock.subagents.heading: { bold: true }
171
+ dock.subagents.running: { fg: muted }
172
+ dock.subagents.overflow: { fg: muted }
173
+ dock.jobs.border: { fg: warn }
174
+ dock.jobs.heading: { bold: true }
175
+ dock.jobs.running: { fg: muted }
176
+ dock.jobs.overflow: { fg: muted }
177
+ # The footer.
178
+ status.prefix: { fg: accent }
179
+ status.back: { fg: accent }
180
+ # A turn in flight is the one state a reader waits on, so it takes the accent
181
+ # and the weight; ready stays quiet because it is where the surface rests.
182
+ status.activity.working: { fg: accent, bold: true }
183
+ status.activity.ready: { fg: muted }
184
+ status.elapsed: { fg: muted }
185
+ status.agentPreset: { fg: muted }
186
+ status.model: { fg: muted }
187
+ status.effort: { fg: muted }
188
+ status.permission: { fg: muted }
189
+ status.context: { fg: muted }
190
+ status.cache: { fg: muted }
191
+ status.stash: { fg: accent }
192
+ status.cwd: { fg: muted }
193
+ status.separator: { fg: muted }
194
+ # The prompt bar.
195
+ # The one border in the surface that is not a divider: it holds what the reader
196
+ # is writing, which is where the brand belongs on a send affordance.
197
+ editor.border: { fg: accent }
198
+ editor.queued: { dim: true, italic: true }
199
+ editor.queued.more: { fg: muted }
200
+ editor.ghost: { dim: true }
201
+ editor.selectList.selectedPrefix: { fg: accent }
202
+ editor.selectList.selectedText: { bold: true }
203
+ editor.selectList.description: { fg: muted }
204
+ editor.selectList.scrollInfo: { fg: muted }
205
+ editor.selectList.noMatch: { fg: muted }