@silo-code/sdk 0.31.0 → 0.32.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 (55) hide show
  1. package/dist/ActivityGlyph.d.ts +25 -0
  2. package/dist/ActivityGlyph.d.ts.map +1 -0
  3. package/dist/ActivityGlyph.js +25 -0
  4. package/dist/ActivityGlyph.js.map +1 -0
  5. package/dist/IconButton.d.ts +23 -6
  6. package/dist/IconButton.d.ts.map +1 -1
  7. package/dist/IconButton.js +14 -5
  8. package/dist/IconButton.js.map +1 -1
  9. package/dist/activity.d.ts +36 -0
  10. package/dist/activity.d.ts.map +1 -0
  11. package/dist/activity.js +33 -0
  12. package/dist/activity.js.map +1 -0
  13. package/dist/editor-service.d.ts +5 -1
  14. package/dist/editor-service.d.ts.map +1 -1
  15. package/dist/icon-button-classes.d.ts +10 -2
  16. package/dist/icon-button-classes.d.ts.map +1 -1
  17. package/dist/icon-button-classes.js +9 -5
  18. package/dist/icon-button-classes.js.map +1 -1
  19. package/dist/index.d.ts +7 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/phosphor-icon.d.ts +15 -0
  24. package/dist/phosphor-icon.d.ts.map +1 -0
  25. package/dist/phosphor-icon.js +2 -0
  26. package/dist/phosphor-icon.js.map +1 -0
  27. package/dist/tab-adornment.d.ts +193 -0
  28. package/dist/tab-adornment.d.ts.map +1 -0
  29. package/dist/tab-adornment.js +2 -0
  30. package/dist/tab-adornment.js.map +1 -0
  31. package/dist/terminal-service.d.ts +18 -35
  32. package/dist/terminal-service.d.ts.map +1 -1
  33. package/dist/toolbar-items.d.ts +171 -0
  34. package/dist/toolbar-items.d.ts.map +1 -0
  35. package/dist/toolbar-items.js +2 -0
  36. package/dist/toolbar-items.js.map +1 -0
  37. package/dist/types.d.ts +15 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/workspace-service.d.ts +66 -45
  40. package/dist/workspace-service.d.ts.map +1 -1
  41. package/package.json +1 -1
  42. package/src/ActivityGlyph.tsx +43 -0
  43. package/src/IconButton.tsx +28 -6
  44. package/src/activity.test.ts +35 -0
  45. package/src/activity.ts +57 -0
  46. package/src/editor-service.ts +5 -1
  47. package/src/icon-button-classes.test.ts +10 -0
  48. package/src/icon-button-classes.ts +18 -5
  49. package/src/index.ts +32 -1
  50. package/src/phosphor-icon.ts +14 -0
  51. package/src/tab-adornment.ts +208 -0
  52. package/src/terminal-service.ts +21 -35
  53. package/src/toolbar-items.ts +190 -0
  54. package/src/types.ts +17 -0
  55. package/src/workspace-service.ts +72 -45
@@ -0,0 +1,43 @@
1
+ import type { HTMLAttributes } from "react";
2
+ import {
3
+ activityClass,
4
+ type Activity as ActivityKind,
5
+ type ActivitySize,
6
+ } from "./activity";
7
+
8
+ /**
9
+ * Host-painted activity glyph — same look on workspace rows, CenterDock tabs,
10
+ * and extension UI. Pick an {@link Activity}; the host owns color and motion
11
+ * (ADR 0030). Omit `activity` only for the workspace-row neutral gray fallback.
12
+ *
13
+ * Styled purely via host-provided `.silo-activity*` classes — no stylesheet
14
+ * import is needed in the extension.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <ActivityGlyph activity="working" size="md" />
19
+ * <ActivityGlyph activity="ready" />
20
+ * <ActivityGlyph size="sm" /> // workspace neutral (omit)
21
+ * ```
22
+ *
23
+ * @category Consumer Services
24
+ * @public
25
+ */
26
+ export function ActivityGlyph({
27
+ activity,
28
+ size = "sm",
29
+ className,
30
+ ...rest
31
+ }: {
32
+ activity?: ActivityKind;
33
+ size?: ActivitySize;
34
+ } & Omit<HTMLAttributes<HTMLSpanElement>, "children">) {
35
+ const classes = activityClass(activity, size);
36
+ return (
37
+ <span
38
+ className={className ? `${classes} ${className}` : classes}
39
+ aria-hidden={rest["aria-label"] == null ? true : undefined}
40
+ {...rest}
41
+ />
42
+ );
43
+ }
@@ -1,7 +1,11 @@
1
1
  import type { ButtonHTMLAttributes, ReactNode } from "react";
2
- import { iconButtonClass, type IconButtonSize } from "./icon-button-classes";
2
+ import {
3
+ iconButtonClass,
4
+ type IconButtonSize,
5
+ type IconButtonVariant,
6
+ } from "./icon-button-classes";
3
7
 
4
- export type { IconButtonSize };
8
+ export type { IconButtonSize, IconButtonVariant };
5
9
 
6
10
  /**
7
11
  * A square icon-only button — the kit's one answer for ✕, ⋮, ↻, ✏️, and
@@ -9,18 +13,27 @@ export type { IconButtonSize };
9
13
  * label is the accessible name. Pair with {@link Tooltip} so sighted users
10
14
  * get the same label on hover.
11
15
  *
16
+ * Sized in terms of `--silo-font-size-base` so the hit target and child SVGs
17
+ * scale with Silo's UI zoom (`uiFontSize`). Prefer Phosphor `size="1em"`
18
+ * (or omit a fixed px size) so the glyph tracks the button.
19
+ *
12
20
  * Styled purely via host-provided `.silo-icon-button*` classes — no
13
21
  * stylesheet import is needed in the extension.
14
22
  *
15
23
  * @example
16
24
  * ```tsx
17
25
  * <IconButton aria-label="Refresh" onClick={refresh}>
18
- * <RefreshIcon />
26
+ * <RefreshIcon size="1em" />
19
27
  * </IconButton>
20
28
  *
21
29
  * // compact — e.g. in a ListRow's trailing slot
22
30
  * <IconButton size="sm" aria-label="Pin" onClick={pin}>
23
- * <PinIcon />
31
+ * <PinIcon size="1em" />
32
+ * </IconButton>
33
+ *
34
+ * // panel / breadcrumb toolbar (local-web-viewer tone)
35
+ * <IconButton size="sm" variant="toolbar" aria-label="Mark">
36
+ * <FlagIcon size="1em" weight="bold" />
24
37
  * </IconButton>
25
38
  * ```
26
39
  *
@@ -29,19 +42,28 @@ export type { IconButtonSize };
29
42
  */
30
43
  export function IconButton({
31
44
  size = "normal",
45
+ variant = "normal",
32
46
  className,
33
47
  type = "button",
34
48
  children,
35
49
  "aria-label": ariaLabel,
36
50
  ...rest
37
51
  }: {
38
- /** 32px standalone / 26px for tight or inline contexts. */
52
+ /**
53
+ * Hit-target size in `em` of `--silo-font-size-base` (tracks Zoom In/Out).
54
+ * `normal` = 2.5em, `sm` = 2em (local-web-viewer toolbar buttons).
55
+ */
39
56
  size?: IconButtonSize;
57
+ /**
58
+ * `"toolbar"` — black/white toolbar-text icons, hover fill only, no
59
+ * press-scale. Use on editor/terminal breadcrumb clusters and panel bars.
60
+ */
61
+ variant?: IconButtonVariant;
40
62
  /** Required — the icon is the only visual. */
41
63
  "aria-label": string;
42
64
  children?: ReactNode;
43
65
  } & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | "aria-label">) {
44
- const classes = iconButtonClass(size);
66
+ const classes = iconButtonClass(size, variant);
45
67
  return (
46
68
  <button
47
69
  type={type}
@@ -0,0 +1,35 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { activityClass, activityFromAgent } from "./activity";
3
+
4
+ describe("activityClass", () => {
5
+ it("maps kinds and sizes", () => {
6
+ expect(activityClass("working", "md")).toBe(
7
+ "silo-activity silo-activity-working silo-activity-md",
8
+ );
9
+ expect(activityClass("ready")).toBe(
10
+ "silo-activity silo-activity-ready silo-activity-sm",
11
+ );
12
+ expect(activityClass("warn", "sm")).toBe(
13
+ "silo-activity silo-activity-warn silo-activity-sm",
14
+ );
15
+ expect(activityClass("error")).toBe(
16
+ "silo-activity silo-activity-error silo-activity-sm",
17
+ );
18
+ });
19
+
20
+ it("uses none fallback when activity is omitted", () => {
21
+ expect(activityClass(undefined)).toBe(
22
+ "silo-activity silo-activity-none silo-activity-sm",
23
+ );
24
+ });
25
+ });
26
+
27
+ describe("activityFromAgent", () => {
28
+ it("maps overlapping agent states", () => {
29
+ expect(activityFromAgent("working")).toBe("working");
30
+ expect(activityFromAgent("idle")).toBe("ready");
31
+ expect(activityFromAgent("error")).toBe("error");
32
+ expect(activityFromAgent("none")).toBeNull();
33
+ expect(activityFromAgent("dead")).toBeNull();
34
+ });
35
+ });
@@ -0,0 +1,57 @@
1
+ import type { AgentActivity } from "./agents-service";
2
+
3
+ /**
4
+ * Host-owned activity state for chrome (workspace rows, CenterDock tabs,
5
+ * SideDock tabs, and the public {@link Activity} glyph). Extensions pick a
6
+ * kind only — never an icon, color, or motion. See ADR 0030.
7
+ *
8
+ * @category Core Types
9
+ * @public
10
+ */
11
+ export type Activity = "working" | "ready" | "warn" | "error";
12
+
13
+ /**
14
+ * Glyph size for {@link Activity}. `"sm"` matches workspace status rows (~6px);
15
+ * `"md"` is slightly larger for CenterDock / SideDock tabs.
16
+ *
17
+ * @category Core Types
18
+ * @public
19
+ */
20
+ export type ActivitySize = "sm" | "md";
21
+
22
+ /**
23
+ * Map {@link AgentActivity} onto UI {@link Activity}. Returns `null` when there
24
+ * is nothing to paint (`none` / `dead` — callers may map `dead` → `"error"`
25
+ * themselves if they want chrome).
26
+ *
27
+ * @category Core Types
28
+ * @public
29
+ */
30
+ export function activityFromAgent(a: AgentActivity): Activity | null {
31
+ switch (a) {
32
+ case "working":
33
+ return "working";
34
+ case "idle":
35
+ return "ready";
36
+ case "error":
37
+ return "error";
38
+ case "none":
39
+ case "dead":
40
+ return null;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Resolve the host `.silo-activity*` class string. Pinned by unit tests
46
+ * (RFC 0016 class-contract pattern). When `activity` is omitted, uses the
47
+ * neutral workspace fallback (gray “none” look).
48
+ *
49
+ * @internal
50
+ */
51
+ export function activityClass(
52
+ activity: Activity | undefined,
53
+ size: ActivitySize = "sm",
54
+ ): string {
55
+ const kind = activity ?? "none";
56
+ return `silo-activity silo-activity-${kind} silo-activity-${size}`;
57
+ }
@@ -1,6 +1,7 @@
1
1
  import type { Disposable } from "./types";
2
2
  import type { Event } from "./event";
3
3
  import type { EditorMode } from "./domain-types";
4
+ import type { TabAdornmentMethods } from "./tab-adornment";
4
5
 
5
6
  // `ctx.editors` — the editor & document domain (public contract). Opening files
6
7
  // into editor tabs, the active-editor save/close commands, the diff-content
@@ -225,10 +226,13 @@ export interface EditorSaveEvent {
225
226
  * editors register save handlers. The single entry point for opening editors —
226
227
  * prefer it over reaching into workspace/editor state.
227
228
  *
229
+ * Tab chrome adornments (`setIcon` / `setIndicator` / …) take an **editor id**
230
+ * as the target — see {@link TabAdornmentMethods}.
231
+ *
228
232
  * @category Consumer Services
229
233
  * @public
230
234
  */
231
- export interface EditorService {
235
+ export interface EditorService extends TabAdornmentMethods {
232
236
  /**
233
237
  * Open a file in an editor tab. Promotes an existing preview, focuses an
234
238
  * already-open tab, or opens a new one.
@@ -5,9 +5,19 @@ describe("iconButtonClass", () => {
5
5
  it("defaults to silo-icon-button", () => {
6
6
  expect(iconButtonClass()).toBe("silo-icon-button");
7
7
  expect(iconButtonClass("normal")).toBe("silo-icon-button");
8
+ expect(iconButtonClass("normal", "normal")).toBe("silo-icon-button");
8
9
  });
9
10
 
10
11
  it("adds the sm modifier", () => {
11
12
  expect(iconButtonClass("sm")).toBe("silo-icon-button silo-icon-button-sm");
12
13
  });
14
+
15
+ it("adds the toolbar variant", () => {
16
+ expect(iconButtonClass("normal", "toolbar")).toBe(
17
+ "silo-icon-button silo-icon-button-toolbar",
18
+ );
19
+ expect(iconButtonClass("sm", "toolbar")).toBe(
20
+ "silo-icon-button silo-icon-button-sm silo-icon-button-toolbar",
21
+ );
22
+ });
13
23
  });
@@ -6,14 +6,27 @@
6
6
  */
7
7
  export type IconButtonSize = "normal" | "sm";
8
8
 
9
+ /**
10
+ * Visual tone for {@link IconButton}. `"toolbar"` matches the local-web-viewer
11
+ * bar buttons (toolbar-text icons, hover fill only, no press-scale).
12
+ *
13
+ * @internal
14
+ */
15
+ export type IconButtonVariant = "normal" | "toolbar";
16
+
9
17
  /**
10
18
  * Resolve the host `.silo-icon-button*` class string for an IconButton's
11
- * `size`. Default is the 32px standalone size; `sm` adds the 26px modifier.
19
+ * `size` + `variant`. Default is the standalone size; `sm` adds the compact
20
+ * modifier; `toolbar` swaps in the breadcrumb/panel-toolbar tone.
12
21
  *
13
22
  * @internal
14
23
  */
15
- export function iconButtonClass(size: IconButtonSize = "normal"): string {
16
- return size === "sm"
17
- ? "silo-icon-button silo-icon-button-sm"
18
- : "silo-icon-button";
24
+ export function iconButtonClass(
25
+ size: IconButtonSize = "normal",
26
+ variant: IconButtonVariant = "normal",
27
+ ): string {
28
+ const parts = ["silo-icon-button"];
29
+ if (size === "sm") parts.push("silo-icon-button-sm");
30
+ if (variant === "toolbar") parts.push("silo-icon-button-toolbar");
31
+ return parts.join(" ");
19
32
  }
package/src/index.ts CHANGED
@@ -110,6 +110,37 @@ export type {
110
110
  TerminalTabDecorationProvider,
111
111
  OscEvent,
112
112
  } from "./terminal-service";
113
+ export type {
114
+ TabAdornmentColor,
115
+ TabIconAdornment,
116
+ TabIndicatorAdornment,
117
+ TabIndicatorFlash,
118
+ TabActivityAdornment,
119
+ TabActivityFlash,
120
+ TabIconContribution,
121
+ TabIndicatorContribution,
122
+ TabActivityContribution,
123
+ TabIconBinder,
124
+ TabIndicatorBinder,
125
+ TabActivityBinder,
126
+ TabAdornmentMethods,
127
+ } from "./tab-adornment";
128
+ export type { Activity, ActivitySize } from "./activity";
129
+ export { activityFromAgent } from "./activity";
130
+ export { ActivityGlyph } from "./ActivityGlyph";
131
+ export type { PhosphorIconName } from "./phosphor-icon";
132
+ export type {
133
+ ToolbarSurface,
134
+ ToolbarItemContext,
135
+ ToolbarItemFields,
136
+ ToolbarCommandItemContribution,
137
+ ToolbarMenuItemContribution,
138
+ ToolbarChromeFields,
139
+ ToolbarSeparatorContribution,
140
+ ToolbarSpacerSize,
141
+ ToolbarSpacerContribution,
142
+ ToolbarItemContribution,
143
+ } from "./toolbar-items";
113
144
  export type {
114
145
  FileService,
115
146
  FileMeta,
@@ -226,7 +257,7 @@ export { Tooltip } from "./Tooltip";
226
257
  export { Button } from "./Button";
227
258
  export type { ButtonVariant, ButtonSize } from "./Button";
228
259
  export { IconButton } from "./IconButton";
229
- export type { IconButtonSize } from "./IconButton";
260
+ export type { IconButtonSize, IconButtonVariant } from "./IconButton";
230
261
  export { Input } from "./Input";
231
262
  export { Textarea } from "./Textarea";
232
263
  export { SearchInput } from "./SearchInput";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Export name of an icon from `@phosphor-icons/react` — e.g. `"Flag"`,
3
+ * `"ArrowClockwise"`, `"PushPin"`. The host resolves the name and paints it:
4
+ * toolbar chrome uses `weight="bold"`; tab decorations use `weight="regular"`
5
+ * by default (`filled: true` → `weight="fill"`); both use `size="1em"` so
6
+ * glyphs track UI zoom.
7
+ *
8
+ * Use the PascalCase component name from
9
+ * [Phosphor](https://phosphoricons.com), not a kebab-case path.
10
+ *
11
+ * @category Registration
12
+ * @public
13
+ */
14
+ export type PhosphorIconName = string;
@@ -0,0 +1,208 @@
1
+ import type { ReactNode } from "react";
2
+ import type { Activity } from "./activity";
3
+ import type { PhosphorIconName } from "./phosphor-icon";
4
+ import type { Disposable } from "./types";
5
+
6
+ /**
7
+ * Semantic color for a CenterDock tab trailing {@link TabIndicatorAdornment}
8
+ * (and optional chip background).
9
+ *
10
+ * @category Consumer Services
11
+ * @public
12
+ */
13
+ export type TabAdornmentColor = "accent" | "warn" | "ok" | "error" | "muted";
14
+
15
+ /**
16
+ * Leading identity adornment on a CenterDock tab — arbitrary React artwork
17
+ * (e.g. an app logo). Set via {@link EditorService.setIcon} /
18
+ * {@link TerminalService.setIcon}.
19
+ *
20
+ * @category Consumer Services
21
+ * @public
22
+ */
23
+ export interface TabIconAdornment {
24
+ /** Extension-owned key; stacking + {@link EditorService.clearIcon} target. */
25
+ id: string;
26
+ /** Leading glyph / logo rendered before the tab title. */
27
+ icon: ReactNode;
28
+ }
29
+
30
+ /**
31
+ * Trailing status adornment on a CenterDock tab — static Phosphor glyph.
32
+ * For busy/ready/warn/error chrome use {@link TabActivityAdornment} instead
33
+ * (ADR 0030).
34
+ *
35
+ * Set via {@link EditorService.setIndicator} /
36
+ * {@link TerminalService.setIndicator}.
37
+ *
38
+ * @category Consumer Services
39
+ * @public
40
+ */
41
+ export interface TabIndicatorAdornment {
42
+ /** Extension-owned key; stacking + clear target. */
43
+ id: string;
44
+ /**
45
+ * Glyph as a {@link PhosphorIconName} (e.g. `"Flag"`). The host resolves
46
+ * and paints it at 1em in regular weight by default. Set
47
+ * {@link TabIndicatorAdornment.filled | filled} for Phosphor fill weight;
48
+ * {@link TabIndicatorAdornment.color | color} tints the glyph; set
49
+ * {@link TabIndicatorAdornment.chip | chip} for a soft tinted background.
50
+ */
51
+ icon: PhosphorIconName;
52
+ /** Tooltip shown when hovering the indicator. */
53
+ tooltip?: string;
54
+ /** Semantic color for the glyph (and chip fill). */
55
+ color?: TabAdornmentColor;
56
+ /**
57
+ * When true, paint a soft tinted chip behind the icon. Default is
58
+ * glyph-only — no background.
59
+ */
60
+ chip?: boolean;
61
+ /**
62
+ * When true, paint the glyph with Phosphor `weight="fill"`. Default is
63
+ * regular weight (outline).
64
+ */
65
+ filled?: boolean;
66
+ }
67
+
68
+ /**
69
+ * Host-owned {@link Activity} on a CenterDock tab. Extensions pick the kind
70
+ * (+ optional tooltip); never an icon or color (ADR 0030).
71
+ *
72
+ * @category Consumer Services
73
+ * @public
74
+ */
75
+ export interface TabActivityAdornment {
76
+ /** Extension-owned key; stacking + clear target. */
77
+ id: string;
78
+ activity: Activity;
79
+ tooltip?: string;
80
+ }
81
+
82
+ /**
83
+ * Payload for {@link EditorService.flashIndicator} /
84
+ * {@link TerminalService.flashIndicator} — timed one-shot; no stable `id`
85
+ * (auto-cleared after `durationMs`).
86
+ *
87
+ * @category Consumer Services
88
+ * @public
89
+ */
90
+ export type TabIndicatorFlash = TabIndicatorContribution & {
91
+ /** How long to show the flash. Defaults to host choice (typically ~800ms). */
92
+ durationMs?: number;
93
+ };
94
+
95
+ /**
96
+ * Payload for {@link EditorService.flashActivity} /
97
+ * {@link TerminalService.flashActivity}.
98
+ *
99
+ * @category Consumer Services
100
+ * @public
101
+ */
102
+ export type TabActivityFlash = TabActivityContribution & {
103
+ durationMs?: number;
104
+ };
105
+
106
+ /**
107
+ * Fields contributed by a {@link TabIconBinder.provide} call (the binder’s
108
+ * own `id` is applied by the host).
109
+ *
110
+ * @category Consumer Services
111
+ * @public
112
+ */
113
+ export type TabIconContribution = Omit<TabIconAdornment, "id">;
114
+
115
+ /**
116
+ * Fields contributed by a {@link TabIndicatorBinder.provide} call.
117
+ *
118
+ * @category Consumer Services
119
+ * @public
120
+ */
121
+ export type TabIndicatorContribution = Omit<TabIndicatorAdornment, "id">;
122
+
123
+ /**
124
+ * Fields contributed by a {@link TabActivityBinder.provide} call.
125
+ *
126
+ * @category Consumer Services
127
+ * @public
128
+ */
129
+ export type TabActivityContribution = Omit<TabActivityAdornment, "id">;
130
+
131
+ /**
132
+ * Keep a leading-icon projection in sync for every editor/terminal tab.
133
+ * Prefer over repeatedly calling {@link EditorService.setIcon}.
134
+ *
135
+ * @category Consumer Services
136
+ * @public
137
+ */
138
+ export interface TabIconBinder {
139
+ /** Extension-owned key — conventionally `"<extension-id>.tab-icon"`. */
140
+ id: string;
141
+ /**
142
+ * Called synchronously per tab during render. Return `null` to contribute
143
+ * nothing for this target id (editor id or terminal session id).
144
+ */
145
+ provide(targetId: string): TabIconContribution | null;
146
+ }
147
+
148
+ /**
149
+ * Keep a trailing-indicator projection in sync for every editor/terminal tab.
150
+ *
151
+ * @category Consumer Services
152
+ * @public
153
+ */
154
+ export interface TabIndicatorBinder {
155
+ /** Extension-owned key — conventionally `"<extension-id>.tab-indicator"`. */
156
+ id: string;
157
+ /**
158
+ * Called synchronously per tab during render. Return `null` to contribute
159
+ * nothing for this target id.
160
+ */
161
+ provide(targetId: string): TabIndicatorContribution | null;
162
+ }
163
+
164
+ /**
165
+ * Keep a trailing-activity projection in sync for every editor/terminal tab.
166
+ *
167
+ * @category Consumer Services
168
+ * @public
169
+ */
170
+ export interface TabActivityBinder {
171
+ /** Extension-owned key — conventionally `"<extension-id>.tab-activity"`. */
172
+ id: string;
173
+ provide(targetId: string): TabActivityContribution | null;
174
+ }
175
+
176
+ /**
177
+ * Shared adorn verbs for CenterDock editor and terminal tabs. Implemented by
178
+ * {@link EditorService} and {@link TerminalService} (target id is the editor
179
+ * or terminal session id respectively).
180
+ *
181
+ * @category Consumer Services
182
+ * @public
183
+ */
184
+ export interface TabAdornmentMethods {
185
+ setIcon(targetId: string, adornment: TabIconAdornment): void;
186
+ clearIcon(targetId: string, adornmentId: string): void;
187
+ bindIcon(binder: TabIconBinder): Disposable;
188
+
189
+ setIndicator(targetId: string, adornment: TabIndicatorAdornment): void;
190
+ clearIndicator(targetId: string, adornmentId: string): void;
191
+ flashIndicator(targetId: string, flash: TabIndicatorFlash): void;
192
+ bindIndicator(binder: TabIndicatorBinder): Disposable;
193
+
194
+ setActivity(targetId: string, adornment: TabActivityAdornment): void;
195
+ clearActivity(targetId: string, adornmentId: string): void;
196
+ flashActivity(targetId: string, flash: TabActivityFlash): void;
197
+ bindActivity(binder: TabActivityBinder): Disposable;
198
+
199
+ /** All leading icons for `targetId`, in set/bind order. */
200
+ getIcons(targetId: string): TabIconAdornment[];
201
+ /** All trailing indicators for `targetId`, in set/bind/flash order. */
202
+ getIndicators(targetId: string): TabIndicatorAdornment[];
203
+ /** All trailing activities for `targetId`, in set/bind/flash order. */
204
+ getActivities(targetId: string): TabActivityAdornment[];
205
+ /** Signal that binder data changed — re-query `provide` and re-render. */
206
+ invalidateTabAdornments(): void;
207
+ subscribeTabAdornments(listener: () => void): Disposable;
208
+ }
@@ -1,6 +1,9 @@
1
- import type React from "react";
2
1
  import type { Disposable } from "./types";
3
2
  import type { TerminalKind, TerminalRecord } from "./domain-types";
3
+ import type {
4
+ TabAdornmentMethods,
5
+ TabIndicatorContribution,
6
+ } from "./tab-adornment";
4
7
 
5
8
  /**
6
9
  * A parsed OSC (Operating System Command) escape sequence emitted by a
@@ -26,32 +29,18 @@ export interface OscEvent {
26
29
  export type { TerminalKind, TerminalRecord } from "./domain-types";
27
30
 
28
31
  /**
29
- * A decoration that an extension can attach to a terminal tab — a small icon
30
- * with an optional tooltip and semantic color. Registered via
31
- * {@link TerminalService.registerTabDecoration}.
32
+ * @deprecated Prefer {@link TerminalService.setIndicator} /
33
+ * {@link TerminalService.bindIndicator}. Alias for a trailing indicator
34
+ * contribution (no `id` — the provider id supplies it).
32
35
  *
33
36
  * @category Consumer Services
34
37
  * @public
35
38
  */
36
- export interface TerminalTabDecoration {
37
- /**
38
- * Small React node rendered as a decoration badge on the tab (≤16 px).
39
- * The extension supplies the shape; the host applies `color` via a CSS
40
- * data attribute mapped to design tokens.
41
- */
42
- icon: React.ReactNode;
43
- /** Tooltip shown when hovering the decoration icon. */
44
- tooltip?: string;
45
- /**
46
- * Semantic color applied to the icon element. The host maps this to the
47
- * matching `--silo-color-*` design token so themes control the exact shade.
48
- */
49
- color?: "accent" | "warn" | "ok" | "error" | "muted";
50
- }
39
+ export type TerminalTabDecoration = TabIndicatorContribution;
51
40
 
52
41
  /**
53
- * A decoration provider for terminal tabs. Register via
54
- * {@link TerminalService.registerTabDecoration}.
42
+ * @deprecated Prefer {@link TerminalService.bindIndicator}. Terminal-only
43
+ * trailing-indicator provider kept as a shim over the adornment registry.
55
44
  *
56
45
  * @category Consumer Services
57
46
  * @public
@@ -61,8 +50,7 @@ export interface TerminalTabDecorationProvider {
61
50
  id: string;
62
51
  /**
63
52
  * Called synchronously for each terminal tab during render. Return `null`
64
- * to contribute nothing for this terminal. When multiple providers are
65
- * registered, the first non-null result wins.
53
+ * to contribute nothing for this terminal.
66
54
  */
67
55
  provide(terminalId: string): TerminalTabDecoration | null;
68
56
  }
@@ -92,10 +80,13 @@ export interface CreateTerminalInput {
92
80
  * deleting the workspace. The tab itself is rendered by the core dock from the
93
81
  * workspace's terminal records.
94
82
  *
83
+ * Tab chrome adornments (`setIcon` / `setIndicator` / …) take a **terminal
84
+ * session id** as the target — see {@link TabAdornmentMethods}.
85
+ *
95
86
  * @category Consumer Services
96
87
  * @public
97
88
  */
98
- export interface TerminalService {
89
+ export interface TerminalService extends TabAdornmentMethods {
99
90
  /**
100
91
  * Open a new terminal in a workspace (defaults to the active one). Returns the
101
92
  * created {@link TerminalRecord}; the PTY session spawns lazily when its tab
@@ -156,29 +147,24 @@ export interface TerminalService {
156
147
  focus(terminalId: string): void;
157
148
 
158
149
  /**
159
- * Register a decoration provider for terminal tabs. The first registered
160
- * provider that returns a non-null decoration for a terminal wins; subsequent
161
- * providers are not consulted. Returns a {@link Disposable} that unregisters
162
- * the provider.
150
+ * @deprecated Prefer {@link TerminalService.bindIndicator}. Thin shim that
151
+ * registers a trailing-indicator binder for terminal tabs only.
163
152
  */
164
153
  registerTabDecoration(provider: TerminalTabDecorationProvider): Disposable;
165
154
 
166
155
  /**
167
- * Get the current decoration for a terminal tab. Returns the first non-null
168
- * result from registered providers, or `null` if none apply.
156
+ * @deprecated Prefer {@link TerminalService.getIndicators}. Returns the first
157
+ * trailing indicator for a terminal tab, or `null`.
169
158
  */
170
159
  getTabDecoration(terminalId: string): TerminalTabDecoration | null;
171
160
 
172
161
  /**
173
- * Signal that tab decoration data has changed. Fires all listeners registered
174
- * via {@link TerminalService.subscribeTabDecorations}, causing terminal tabs
175
- * to re-query providers and re-render their decoration.
162
+ * @deprecated Prefer {@link TerminalService.invalidateTabAdornments}.
176
163
  */
177
164
  invalidateTabDecorations(): void;
178
165
 
179
166
  /**
180
- * Subscribe to tab decoration invalidations. Returns a {@link Disposable}
181
- * that cancels the subscription.
167
+ * @deprecated Prefer {@link TerminalService.subscribeTabAdornments}.
182
168
  */
183
169
  subscribeTabDecorations(listener: () => void): Disposable;
184
170