@agentdeck/shared 0.1.0 → 0.2.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 (76) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapter.d.ts +16 -3
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +38 -0
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/command-builders.d.ts +30 -0
  7. package/dist/command-builders.d.ts.map +1 -0
  8. package/dist/command-builders.js +60 -0
  9. package/dist/command-builders.js.map +1 -0
  10. package/dist/eval-schema.d.ts +211 -0
  11. package/dist/eval-schema.d.ts.map +1 -0
  12. package/dist/eval-schema.js +23 -0
  13. package/dist/eval-schema.js.map +1 -0
  14. package/dist/format-utils.d.ts +27 -0
  15. package/dist/format-utils.d.ts.map +1 -0
  16. package/dist/format-utils.js +120 -0
  17. package/dist/format-utils.js.map +1 -0
  18. package/dist/gateway-protocol.d.ts +391 -0
  19. package/dist/gateway-protocol.d.ts.map +1 -0
  20. package/dist/gateway-protocol.js +19 -0
  21. package/dist/gateway-protocol.js.map +1 -0
  22. package/dist/index.d.ts +11 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +11 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/llm-settings.d.ts +52 -0
  27. package/dist/llm-settings.d.ts.map +1 -0
  28. package/dist/llm-settings.js +118 -0
  29. package/dist/llm-settings.js.map +1 -0
  30. package/dist/protocol.d.ts +326 -2
  31. package/dist/protocol.d.ts.map +1 -1
  32. package/dist/protocol.js +19 -0
  33. package/dist/protocol.js.map +1 -1
  34. package/dist/session-utils.d.ts +62 -0
  35. package/dist/session-utils.d.ts.map +1 -0
  36. package/dist/session-utils.js +109 -0
  37. package/dist/session-utils.js.map +1 -0
  38. package/dist/state-colors.d.ts +16 -0
  39. package/dist/state-colors.d.ts.map +1 -0
  40. package/dist/state-colors.js +46 -0
  41. package/dist/state-colors.js.map +1 -0
  42. package/dist/states.d.ts +1 -0
  43. package/dist/states.d.ts.map +1 -1
  44. package/dist/svg-renderers/agent-logos.d.ts +33 -0
  45. package/dist/svg-renderers/agent-logos.d.ts.map +1 -0
  46. package/dist/svg-renderers/agent-logos.js +100 -0
  47. package/dist/svg-renderers/agent-logos.js.map +1 -0
  48. package/dist/svg-renderers/index.d.ts +4 -0
  49. package/dist/svg-renderers/index.d.ts.map +1 -0
  50. package/dist/svg-renderers/index.js +4 -0
  51. package/dist/svg-renderers/index.js.map +1 -0
  52. package/dist/svg-renderers/session-slot-renderer.d.ts +25 -0
  53. package/dist/svg-renderers/session-slot-renderer.d.ts.map +1 -0
  54. package/dist/svg-renderers/session-slot-renderer.js +317 -0
  55. package/dist/svg-renderers/session-slot-renderer.js.map +1 -0
  56. package/dist/svg-renderers/text-utils.d.ts +15 -0
  57. package/dist/svg-renderers/text-utils.d.ts.map +1 -0
  58. package/dist/svg-renderers/text-utils.js +88 -0
  59. package/dist/svg-renderers/text-utils.js.map +1 -0
  60. package/dist/telemetry-envelope.d.ts +108 -0
  61. package/dist/telemetry-envelope.d.ts.map +1 -0
  62. package/dist/telemetry-envelope.js +34 -0
  63. package/dist/telemetry-envelope.js.map +1 -0
  64. package/dist/timeline-summarizer.d.ts +13 -0
  65. package/dist/timeline-summarizer.d.ts.map +1 -0
  66. package/dist/timeline-summarizer.js +83 -0
  67. package/dist/timeline-summarizer.js.map +1 -0
  68. package/dist/timeline.d.ts +65 -0
  69. package/dist/timeline.d.ts.map +1 -0
  70. package/dist/timeline.js +456 -0
  71. package/dist/timeline.js.map +1 -0
  72. package/dist/voice-paths.d.ts +4 -0
  73. package/dist/voice-paths.d.ts.map +1 -1
  74. package/dist/voice-paths.js +5 -0
  75. package/dist/voice-paths.js.map +1 -1
  76. package/package.json +9 -3
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Canonical state color palette — single source of truth for all platforms.
3
+ *
4
+ * TypeScript consumers import directly.
5
+ * Native platforms (Android/Apple/ESP32) reference these hex values in comments.
6
+ */
7
+ import { State } from './states.js';
8
+ // ===== State Colors =====
9
+ export const STATE_COLORS = {
10
+ [State.IDLE]: '#22c55e', // green
11
+ [State.PROCESSING]: '#3b82f6', // blue
12
+ [State.AWAITING_PERMISSION]: '#f59e0b', // amber
13
+ [State.AWAITING_OPTION]: '#f59e0b', // amber
14
+ [State.AWAITING_DIFF]: '#f59e0b', // amber
15
+ [State.DISCONNECTED]: '#6b7280', // gray
16
+ };
17
+ /** Look up state color by string key. No agent-type overrides — purely semantic. */
18
+ export function stateColor(state) {
19
+ if (!state)
20
+ return STATE_COLORS[State.DISCONNECTED];
21
+ return STATE_COLORS[state] ?? STATE_COLORS[State.IDLE];
22
+ }
23
+ // ===== Agent Brand Colors (for icons, not states) =====
24
+ export const AGENT_BRAND_COLORS = {
25
+ 'claude-code': '#C07058', // terracotta
26
+ 'openclaw': '#ff4d4d', // red
27
+ 'codex-cli': '#6366f1', // indigo
28
+ 'opencode': '#F1ECEC', // cream
29
+ 'monitor': '#94a3b8', // slate
30
+ };
31
+ /** Get agent brand color. Falls back to slate for unknown types. */
32
+ export function agentBrandColor(agentType) {
33
+ return AGENT_BRAND_COLORS[agentType ?? ''] ?? '#94a3b8';
34
+ }
35
+ // ===== Color Utilities =====
36
+ /** Mix a hex color toward black by ratio (0=original, 1=black). */
37
+ export function dimColor(hex, ratio) {
38
+ const r = parseInt(hex.slice(1, 3), 16);
39
+ const g = parseInt(hex.slice(3, 5), 16);
40
+ const b = parseInt(hex.slice(5, 7), 16);
41
+ const dr = Math.round(r * (1 - ratio));
42
+ const dg = Math.round(g * (1 - ratio));
43
+ const db = Math.round(b * (1 - ratio));
44
+ return `#${dr.toString(16).padStart(2, '0')}${dg.toString(16).padStart(2, '0')}${db.toString(16).padStart(2, '0')}`;
45
+ }
46
+ //# sourceMappingURL=state-colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-colors.js","sourceRoot":"","sources":["../src/state-colors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,2BAA2B;AAE3B,MAAM,CAAC,MAAM,YAAY,GAA0B;IACjD,CAAC,KAAK,CAAC,IAAI,CAAC,EAAiB,SAAS,EAAG,QAAQ;IACjD,CAAC,KAAK,CAAC,UAAU,CAAC,EAAW,SAAS,EAAG,OAAO;IAChD,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAG,QAAQ;IACjD,CAAC,KAAK,CAAC,eAAe,CAAC,EAAM,SAAS,EAAG,QAAQ;IACjD,CAAC,KAAK,CAAC,aAAa,CAAC,EAAQ,SAAS,EAAG,QAAQ;IACjD,CAAC,KAAK,CAAC,YAAY,CAAC,EAAS,SAAS,EAAG,OAAO;CACjD,CAAC;AAEF,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAC,KAAyB;IAClD,IAAI,CAAC,KAAK;QAAE,OAAO,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACpD,OAAQ,YAAuC,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACrF,CAAC;AAED,yDAAyD;AAEzD,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,aAAa,EAAE,SAAS,EAAG,aAAa;IACxC,UAAU,EAAK,SAAS,EAAG,MAAM;IACjC,WAAW,EAAI,SAAS,EAAG,SAAS;IACpC,UAAU,EAAK,SAAS,EAAG,QAAQ;IACnC,SAAS,EAAM,SAAS,EAAG,QAAQ;CACpC,CAAC;AAEF,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,SAA6B;IAC3D,OAAO,kBAAkB,CAAC,SAAS,IAAI,EAAE,CAAC,IAAI,SAAS,CAAC;AAC1D,CAAC;AAED,8BAA8B;AAE9B,mEAAmE;AACnE,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,KAAa;IACjD,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACvC,OAAO,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACtH,CAAC"}
package/dist/states.d.ts CHANGED
@@ -40,6 +40,7 @@ export interface StateSnapshot {
40
40
  cursorIndex: number;
41
41
  projectName: string | null;
42
42
  modelName: string | null;
43
+ effortLevel: string | null;
43
44
  billingType: import('./protocol.js').BillingType;
44
45
  sessionDurationSec: number;
45
46
  inputTokens: number;
@@ -1 +1 @@
1
- {"version":3,"file":"states.d.ts","sourceRoot":"","sources":["../src/states.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK;IACf,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,mBAAmB,wBAAwB;IAC3C,eAAe,oBAAoB;IACnC,aAAa,kBAAkB;CAChC;AAED,oBAAY,cAAc;IACxB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,YAAY,gBAAgB;IAC5B,QAAQ,YAAY;IACpB,kBAAkB,sBAAsB;CACzC;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,KAAK,GAAG,GAAG,CAAC;IAClB,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,EAAE,eAAe,EA4BxC,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,eAAe,EAAE,WAAW,CAAC;IACjD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
1
+ {"version":3,"file":"states.d.ts","sourceRoot":"","sources":["../src/states.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK;IACf,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,mBAAmB,wBAAwB;IAC3C,eAAe,oBAAoB;IACnC,aAAa,kBAAkB;CAChC;AAED,oBAAY,cAAc;IACxB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,YAAY,gBAAgB;IAC5B,QAAQ,YAAY;IACpB,kBAAkB,sBAAsB;CACzC;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,KAAK,GAAG,GAAG,CAAC;IAClB,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,EAAE,eAAe,EA4BxC,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,OAAO,eAAe,EAAE,WAAW,CAAC;IACjD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Agent logo SVG paths for icon and watermark rendering on session buttons.
3
+ *
4
+ * Each logo is a centered path designed for a 144x144 button canvas.
5
+ * Two rendering modes:
6
+ * agentLogoIcon() — prominent icon at top of button (primary identification)
7
+ * agentLogoWatermark() — low-opacity background mark
8
+ */
9
+ import type { AgentType } from '../adapter.js';
10
+ /** Claude Code creature asset: assets/logos/claude.svg. viewBox 0 0 24 24. */
11
+ export declare const CLAUDE_LOGO_PATH = "M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z";
12
+ /** Legacy OpenClaw paths kept for the Gateway preset mini-browser icon. */
13
+ export declare const OC_BODY = "M60 10 C30 10 15 35 15 55 C15 75 30 95 45 100 L45 110 L55 110 L55 100 C55 100 60 102 65 100 L65 110 L75 110 L75 100 C90 95 105 75 105 55 C105 35 90 10 60 10Z";
14
+ export declare const OC_CLAW_L = "M20 45 C5 40 0 50 5 60 C10 70 20 65 25 55 C28 48 25 45 20 45Z";
15
+ export declare const OC_CLAW_R = "M100 45 C115 40 120 50 115 60 C110 70 100 65 95 55 C92 48 95 45 100 45Z";
16
+ /** Codex CLI knot/clover — official SVG from codex brand assets. viewBox 0 0 24 24. */
17
+ export declare const CODEX_LOGO_PATH = "M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z";
18
+ /** OpenClaw creature asset: assets/logos/openclaw.svg. viewBox 0 0 24 24. */
19
+ export declare const OPENCLAW_LOGO_PATHS: string[];
20
+ /**
21
+ * Render agent logo as a visible icon at top-center of button.
22
+ * Uses agent brand color (not state color) for consistent identification.
23
+ * @param agent Agent type
24
+ * @param size Target size in px (default 48)
25
+ * @param opacity Icon opacity (default 0.7)
26
+ */
27
+ export declare function agentLogoIcon(agent: AgentType, size?: number, opacity?: number, cx?: number, cy?: number): string;
28
+ /**
29
+ * Render agent logo as a background watermark.
30
+ * Uses brand color dimmed for subtle identification.
31
+ */
32
+ export declare function agentLogoWatermark(agent: AgentType, _color?: string, opacity?: number): string;
33
+ //# sourceMappingURL=agent-logos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-logos.d.ts","sourceRoot":"","sources":["../../src/svg-renderers/agent-logos.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,g+CACk8C,CAAC;AAEh+C,2EAA2E;AAC3E,eAAO,MAAM,OAAO,kKAC6I,CAAC;AAClK,eAAO,MAAM,SAAS,kEAC2C,CAAC;AAClE,eAAO,MAAM,SAAS,4EACqD,CAAC;AAE5E,uFAAuF;AACvF,eAAO,MAAM,eAAe,goCACmmC,CAAC;AAEhoC,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,UAM/B,CAAC;AAkBF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,EAChB,IAAI,SAAK,EACT,OAAO,SAAM,EACb,EAAE,SAAK,EACP,EAAE,SAAgB,GACjB,MAAM,CAwBR;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,SAAO,GACb,MAAM,CAyBR"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Agent logo SVG paths for icon and watermark rendering on session buttons.
3
+ *
4
+ * Each logo is a centered path designed for a 144x144 button canvas.
5
+ * Two rendering modes:
6
+ * agentLogoIcon() — prominent icon at top of button (primary identification)
7
+ * agentLogoWatermark() — low-opacity background mark
8
+ */
9
+ import { dimColor, agentBrandColor } from '../state-colors.js';
10
+ /** Claude Code creature asset: assets/logos/claude.svg. viewBox 0 0 24 24. */
11
+ export const CLAUDE_LOGO_PATH = 'M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z';
12
+ /** Legacy OpenClaw paths kept for the Gateway preset mini-browser icon. */
13
+ export const OC_BODY = 'M60 10 C30 10 15 35 15 55 C15 75 30 95 45 100 L45 110 L55 110 L55 100 C55 100 60 102 65 100 L65 110 L75 110 L75 100 C90 95 105 75 105 55 C105 35 90 10 60 10Z';
14
+ export const OC_CLAW_L = 'M20 45 C5 40 0 50 5 60 C10 70 20 65 25 55 C28 48 25 45 20 45Z';
15
+ export const OC_CLAW_R = 'M100 45 C115 40 120 50 115 60 C110 70 100 65 95 55 C92 48 95 45 100 45Z';
16
+ /** Codex CLI knot/clover — official SVG from codex brand assets. viewBox 0 0 24 24. */
17
+ export const CODEX_LOGO_PATH = 'M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z';
18
+ /** OpenClaw creature asset: assets/logos/openclaw.svg. viewBox 0 0 24 24. */
19
+ export const OPENCLAW_LOGO_PATHS = [
20
+ 'M9.046 7.104a.527.527 0 110 1.055.527.527 0 010-1.055z',
21
+ 'M15.376 7.104a.528.528 0 110 1.056.528.528 0 010-1.056z',
22
+ 'M16.877 1.912c.58-.27 1.14-.323 1.616-.037a.317.317 0 01-.326.542c-.227-.136-.547-.153-1.022.068-.352.165-.765.45-1.234.866 2.683 1.17 4.4 3.5 5.148 5.921a6.421 6.421 0 00-.704.184c-.578.016-1.174.204-1.502.735-.338.55-.268 1.276.072 2.069l.005.012.007.014c.523 1.045 1.318 1.91 2.2 2.284-.912 3.274-3.44 6.144-5.972 6.988v2.109h-2.11v-2.11c-1.043.417-2.086.01-2.11 0v2.11h-2.11v-2.11c-2.531-.843-5.061-3.713-5.973-6.987.882-.373 1.678-1.238 2.2-2.284l.007-.014.006-.012c.34-.793.41-1.518.071-2.069-.327-.531-.923-.719-1.503-.735a6.409 6.409 0 00-.704-.183c.749-2.421 2.466-4.751 5.149-5.922-.47-.416-.88-.701-1.234-.866-.474-.221-.794-.204-1.021-.068a.318.318 0 01-.435-.109.317.317 0 01.109-.433c.476-.286 1.036-.233 1.615.037.49.229 1.031.628 1.621 1.182A9.924 9.924 0 0112 2.568c1.199 0 2.284.19 3.256.526.59-.554 1.13-.953 1.62-1.182zM8.835 6.577a1.266 1.266 0 100 2.532 1.266 1.266 0 000-2.532zm6.33 0a1.267 1.267 0 100 2.533 1.267 1.267 0 000-2.533z',
23
+ 'M.395 13.118c-.966-1.932-.163-3.863 2.41-3.365v-.001l.05.01c.084.018.17.038.26.06.033.009.067.017.1.027.084.022.168.048.255.076l.09.027c.528 0 .95.158 1.16.501.212.343.212.87-.105 1.61-.085.17-.178.333-.276.489l-.01.017a4.967 4.967 0 01-.62.791l-.019.02c-1.092 1.117-2.496 1.336-3.295-.262z',
24
+ 'M21.193 9.753c2.574-.5 3.378 1.433 2.411 3.365-.58 1.159-1.476 1.361-2.342.96l-.011-.005a2.419 2.419 0 01-.114-.056l-.019-.01a2.751 2.751 0 01-.115-.067l-.023-.014c-.035-.022-.071-.044-.106-.068l-.05-.035c-.55-.388-1.062-1.007-1.44-1.76-.276-.647-.311-1.132-.174-1.472.176-.439.636-.639 1.23-.639.032-.011.066-.02.099-.03.08-.026.16-.05.238-.072l.117-.03a5.502 5.502 0 01.3-.067z',
25
+ ];
26
+ function officialPathIcon(path, fill, size, opacity, cx, cy) {
27
+ const s = size / 24;
28
+ return `<g transform="translate(${cx},${cy}) scale(${s.toFixed(3)}) translate(-12,-12)" opacity="${opacity}"><path d="${path}" fill="${fill}" fill-rule="evenodd" clip-rule="evenodd"/></g>`;
29
+ }
30
+ function officialMultiPathIcon(paths, fill, size, opacity, cx, cy) {
31
+ const s = size / 24;
32
+ return [
33
+ `<g transform="translate(${cx},${cy}) scale(${s.toFixed(3)}) translate(-12,-12)" opacity="${opacity}" fill="${fill}" fill-rule="evenodd" clip-rule="evenodd">`,
34
+ ...paths.map((p) => `<path d="${p}"/>`),
35
+ `</g>`,
36
+ ].join('');
37
+ }
38
+ // ===== Prominent agent icon (top of button, primary identification) =====
39
+ /**
40
+ * Render agent logo as a visible icon at top-center of button.
41
+ * Uses agent brand color (not state color) for consistent identification.
42
+ * @param agent Agent type
43
+ * @param size Target size in px (default 48)
44
+ * @param opacity Icon opacity (default 0.7)
45
+ */
46
+ export function agentLogoIcon(agent, size = 48, opacity = 0.7, cx = 72, cy = size / 2 + 12) {
47
+ const brandColor = agentBrandColor(agent);
48
+ if (agent === 'claude-code') {
49
+ return officialPathIcon(CLAUDE_LOGO_PATH, brandColor, size, opacity, cx, cy);
50
+ }
51
+ if (agent === 'codex-cli') {
52
+ return officialPathIcon(CODEX_LOGO_PATH, brandColor, size, opacity, cx, cy);
53
+ }
54
+ if (agent === 'opencode') {
55
+ // Smaller icon for OpenCode (geometric squares are visually heavier)
56
+ const ocSize = Math.round(size * 0.75);
57
+ const half = ocSize / 2;
58
+ const ring = ocSize * 0.18;
59
+ const inner = ocSize * 0.5;
60
+ return [
61
+ `<g opacity="${opacity}">`,
62
+ `<rect x="${cx - half}" y="${cy - half}" width="${ocSize}" height="${ocSize}" rx="4" fill="${dimColor(brandColor, 0.3)}"/>`,
63
+ `<rect x="${cx - half + ring}" y="${cy - half + ring}" width="${ocSize - ring * 2}" height="${ocSize - ring * 2}" rx="2" fill="${dimColor('#4B4646', 0.2)}"/>`,
64
+ `<rect x="${cx - inner / 2}" y="${cy - inner / 2}" width="${inner}" height="${inner}" rx="2" fill="${dimColor('#4B4646', 0.2)}"/>`,
65
+ `</g>`,
66
+ ].join('');
67
+ }
68
+ return officialMultiPathIcon(OPENCLAW_LOGO_PATHS, brandColor, size, opacity, cx, cy);
69
+ }
70
+ // ===== Low-opacity watermark (background mark) =====
71
+ /**
72
+ * Render agent logo as a background watermark.
73
+ * Uses brand color dimmed for subtle identification.
74
+ */
75
+ export function agentLogoWatermark(agent, _color, opacity = 0.12) {
76
+ const brandColor = agentBrandColor(agent);
77
+ const markOpacity = Math.min(opacity * 4, 0.9);
78
+ const fill = dimColor(brandColor, 0.5);
79
+ if (agent === 'claude-code') {
80
+ return officialPathIcon(CLAUDE_LOGO_PATH, fill, 72, markOpacity, 72, 72);
81
+ }
82
+ if (agent === 'codex-cli') {
83
+ return officialPathIcon(CODEX_LOGO_PATH, fill, 72, markOpacity, 72, 72);
84
+ }
85
+ if (agent === 'opencode') {
86
+ const s = 72;
87
+ const half = s / 2;
88
+ const ring = s * 0.18;
89
+ const inner = s * 0.5;
90
+ return [
91
+ `<g opacity="${markOpacity}">`,
92
+ `<rect x="${72 - half}" y="${72 - half}" width="${s}" height="${s}" fill="${dimColor('#F1ECEC', 0.6)}"/>`,
93
+ `<rect x="${72 - half + ring}" y="${72 - half + ring}" width="${s - ring * 2}" height="${s - ring * 2}" fill="${dimColor('#4B4646', 0.5)}"/>`,
94
+ `<rect x="${72 - inner / 2}" y="${72 - inner / 2}" width="${inner}" height="${inner}" fill="${dimColor('#4B4646', 0.5)}"/>`,
95
+ `</g>`,
96
+ ].join('');
97
+ }
98
+ return officialMultiPathIcon(OPENCLAW_LOGO_PATHS, fill, 72, markOpacity, 72, 72);
99
+ }
100
+ //# sourceMappingURL=agent-logos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-logos.js","sourceRoot":"","sources":["../../src/svg-renderers/agent-logos.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './text-utils.js';
2
+ export * from './agent-logos.js';
3
+ export * from './session-slot-renderer.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svg-renderers/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './text-utils.js';
2
+ export * from './agent-logos.js';
3
+ export * from './session-slot-renderer.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/svg-renderers/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { SessionInfo } from '../protocol.js';
2
+ import type { PromptOption } from '../states.js';
3
+ import { State } from '../states.js';
4
+ /**
5
+ * Format "Model · effort" suffix for session tile / detail view.
6
+ * Skips neutral efforts ("medium" legacy, "default" is Claude Code 2.1+
7
+ * per-model default) so they don't clutter the tile. Truncates the model
8
+ * name preferentially so the effort label survives in tight pixel budgets.
9
+ */
10
+ export declare function formatModelEffort(modelName?: string, effortLevel?: string, maxLen?: number): string;
11
+ export declare function renderSessionSlot(session: SessionInfo, isActive: boolean, animFrame: number, displayName?: string, options?: {
12
+ animated?: boolean;
13
+ }): string;
14
+ export declare function renderEmptySlot(): string;
15
+ export declare function renderNoDaemonSlot(slot: number): string;
16
+ export declare function renderBackButton(): string;
17
+ export declare function renderNextPageButton(pageLabel: string): string;
18
+ export declare function renderEscButton(active?: boolean): string;
19
+ export declare function renderStopButton(active?: boolean): string;
20
+ export declare function renderDetailInfo(session: SessionInfo | undefined, state: State, tool?: string, modelName?: string, mode?: string, displayName?: string, effortLevel?: string): string;
21
+ export declare function renderOptionButton(option: PromptOption, index: number): string;
22
+ export declare function renderPresetButton(label: string, iconSvg: string, color: string, textColor: string, subtitle?: string, loading?: boolean): string;
23
+ export declare function renderInfoSlot(label: string, subtitle?: string): string;
24
+ export declare function svgFrame(bgColor: string, innerElements: string): string;
25
+ //# sourceMappingURL=session-slot-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-slot-renderer.d.ts","sourceRoot":"","sources":["../../src/svg-renderers/session-slot-renderer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAwCrC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAS/F;AAID,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/B,MAAM,CA8HR;AAID,wBAAgB,eAAe,IAAI,MAAM,CAGxC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUvD;AAID,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED,wBAAgB,eAAe,CAAC,MAAM,UAAO,GAAG,MAAM,CASrD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,UAAO,GAAG,MAAM,CAStD;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAiDrL;AAID,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAkB9E;AAID,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CASjJ;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAMvE;AAID,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAkBvE"}
@@ -0,0 +1,317 @@
1
+ import { stateColor } from '../state-colors.js';
2
+ import { agentLogoIcon } from './agent-logos.js';
3
+ import { wrapTextByWidth } from './text-utils.js';
4
+ const SIZE = 144;
5
+ const MAX_TEXT_PX = 124; // 144 - 10px padding each side
6
+ function stateLabel(state, agentType) {
7
+ if (!state)
8
+ return 'OFFLINE';
9
+ // OpenClaw-specific labels
10
+ if (agentType === 'openclaw') {
11
+ if (state === 'idle')
12
+ return 'STANDBY';
13
+ if (state === 'processing')
14
+ return 'ROUTING';
15
+ }
16
+ switch (state) {
17
+ case 'idle': return 'IDLE';
18
+ case 'processing': return 'WORKING';
19
+ case 'awaiting_option':
20
+ case 'awaiting_permission':
21
+ case 'awaiting_diff':
22
+ return 'AWAITING';
23
+ default: return state.toUpperCase();
24
+ }
25
+ }
26
+ function escXml(s) {
27
+ return s
28
+ .replace(/&/g, '&amp;')
29
+ .replace(/</g, '&lt;')
30
+ .replace(/>/g, '&gt;')
31
+ .replace(/"/g, '&quot;')
32
+ .replace(/'/g, '&apos;');
33
+ }
34
+ function truncate(s, max) {
35
+ if (s.length <= max)
36
+ return s;
37
+ return s.slice(0, max - 1) + '\u2026';
38
+ }
39
+ /**
40
+ * Format "Model · effort" suffix for session tile / detail view.
41
+ * Skips neutral efforts ("medium" legacy, "default" is Claude Code 2.1+
42
+ * per-model default) so they don't clutter the tile. Truncates the model
43
+ * name preferentially so the effort label survives in tight pixel budgets.
44
+ */
45
+ export function formatModelEffort(modelName, effortLevel, maxLen = 14) {
46
+ if (!modelName)
47
+ return '';
48
+ const showEffort = effortLevel && effortLevel !== 'medium' && effortLevel !== 'default';
49
+ if (!showEffort)
50
+ return truncate(modelName, maxLen);
51
+ const combined = `${modelName} · ${effortLevel}`;
52
+ if (combined.length <= maxLen)
53
+ return combined;
54
+ const effortSuffix = ` · ${effortLevel}`;
55
+ const modelBudget = Math.max(4, maxLen - effortSuffix.length);
56
+ return truncate(modelName, modelBudget) + effortSuffix;
57
+ }
58
+ // ---- Session List Button ----
59
+ export function renderSessionSlot(session, isActive, animFrame, displayName, options) {
60
+ const isWorking = session.state === 'processing';
61
+ const isAsking = session.state?.startsWith('awaiting') ?? false;
62
+ const isIdle = !isWorking && !isAsking;
63
+ // Stream Deck / SD+ run a 150ms tick — animated. D200H's TypeScript image
64
+ // pipeline (bridge/src/d200h/image-renderer.ts) has no such loop: passing
65
+ // animFrame=0 every time freezes dashed strokes and leaves the sin-based
66
+ // pulse at a dim phase. Callers without a loop should pass animated:false
67
+ // so we emit a motion-free visual (solid borders + badges) that still
68
+ // clearly distinguishes working vs awaiting vs idle.
69
+ const animated = options?.animated ?? true;
70
+ const agent = session.agentType || 'claude-code';
71
+ const nameForDisplay = displayName ?? session.projectName;
72
+ // Bottom line budget: tile width ~124px at 14px font ≈ 16 chars. Leave a
73
+ // little headroom so "Opus 4.7 · max" fits without running into the
74
+ // watermark on the right.
75
+ const modelText = formatModelEffort(session.modelName, session.effortLevel, 15);
76
+ // Custom palette mimicking the premium demo
77
+ const p1 = agent === 'claude-code' ? '#D97757' : agent === 'codex-cli' ? '#8BA4FF' : agent === 'openclaw' ? '#FF6B6B' : '#F1ECEC';
78
+ const p2 = agent === 'claude-code' ? '#BE6D52' : agent === 'codex-cli' ? '#5981FF' : agent === 'openclaw' ? '#CC3333' : '#AFAFAF';
79
+ const sColor = stateColor(session.state);
80
+ const fontFam = 'Inter, -apple-system, system-ui, Helvetica Neue, sans-serif';
81
+ const stateLbl = isWorking ? 'RUNNING' : isAsking ? 'PERMIT?' : 'IDLE';
82
+ const colorText = isWorking ? '#FDE68A' : isAsking ? '#FECACA' : p1;
83
+ const gradId = `sd-bg-${agent}-${session.state || 'idle'}`;
84
+ let defs = `
85
+ <linearGradient id="${gradId}" x1="0%" y1="0%" x2="0%" y2="100%">
86
+ <stop offset="0%" stop-color="#1C1C1E"/>
87
+ <stop offset="100%" stop-color="#0C0C0E"/>
88
+ </linearGradient>
89
+ `;
90
+ let glowBorder = '';
91
+ let askDot = '';
92
+ let runBadge = '';
93
+ const filterId = `pg-${animFrame}`;
94
+ const blurDef = `
95
+ <filter id="${filterId}" x="-10%" y="-10%" width="120%" height="120%">
96
+ <feGaussianBlur in="SourceGraphic" stdDeviation="2.4"/>
97
+ </filter>
98
+ `;
99
+ if (isAsking) {
100
+ // Animated callers pulse the opacity (0.55…1.0 over a sin wave). Static
101
+ // callers (D200H) pin to a near-peak value so the frozen snapshot reads
102
+ // as bright and attention-grabbing instead of dim.
103
+ const pulseOpacity = animated
104
+ ? 0.55 + 0.45 * Math.abs(Math.sin(animFrame * 0.15))
105
+ : 0.95;
106
+ defs += blurDef;
107
+ // Thick outer glow + crisp inner ring — distinct "breathing" solid border.
108
+ glowBorder =
109
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="none" stroke="${sColor}" stroke-width="4.5" opacity="${pulseOpacity.toFixed(2)}" filter="url(#${filterId})"/>` +
110
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="none" stroke="${sColor}" stroke-width="1.5" opacity="${(pulseOpacity * 0.9).toFixed(2)}"/>`;
111
+ askDot = `
112
+ <circle cx="114" cy="24" r="5" fill="#F5B942" filter="url(#${filterId})"/>
113
+ <circle cx="114" cy="24" r="3" fill="#ffffff" />
114
+ `;
115
+ }
116
+ else if (isWorking) {
117
+ if (animated) {
118
+ // Flowing-light dashed border — SD/SD+ 150ms tick advances animFrame
119
+ // → dashoffset drifts → chasing light.
120
+ const perimeter = 128 * 4;
121
+ const dashOffset = ((animFrame * 4) % perimeter).toFixed(0);
122
+ defs += blurDef;
123
+ glowBorder =
124
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="none" stroke="${sColor}" stroke-width="4.5" stroke-dasharray="22 14" stroke-dashoffset="-${dashOffset}" opacity="0.85" filter="url(#${filterId})"/>` +
125
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="none" stroke="${sColor}" stroke-width="1.5" stroke-dasharray="22 14" stroke-dashoffset="-${dashOffset}" opacity="0.95"/>`;
126
+ }
127
+ else {
128
+ // Non-animated callers (D200H still-image pipeline): render a solid
129
+ // glowing border + a play-chevron badge so WORKING is obvious without
130
+ // motion. The amber border is still the primary signal; the ▶ badge
131
+ // distinguishes this from the red awaiting state at a glance.
132
+ defs += blurDef;
133
+ glowBorder =
134
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="none" stroke="${sColor}" stroke-width="4.5" opacity="0.9" filter="url(#${filterId})"/>` +
135
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="none" stroke="${sColor}" stroke-width="1.5" opacity="0.95"/>`;
136
+ runBadge = `
137
+ <rect x="100" y="14" width="28" height="16" rx="8" fill="${sColor}" opacity="0.9" />
138
+ <text x="114" y="26" font-size="11" font-weight="800" text-anchor="middle" fill="#0C0C0E" font-family="${fontFam}">▶ RUN</text>
139
+ `;
140
+ }
141
+ }
142
+ // Simplified Agent watermark at bottom-right
143
+ // agentLogoIcon renders at x,y with given width/height
144
+ const watermark = `<g transform="translate(90, 86)" opacity="${isIdle ? '0.46' : '0.34'}">
145
+ ${agentLogoIcon(agent, 40, 1, 0, 0)}
146
+ </g>`;
147
+ // Left Edge Color Strip
148
+ const leftStrip = `<rect x="8" y="8" width="4" height="128" rx="2" fill="${isWorking ? '#F5B942' : isAsking ? '#F87171' : p1}"/>`;
149
+ // Border is now the primary working/awaiting signal — no tiny spinner glyph.
150
+ const spinner = '';
151
+ // ACT badge only on IDLE — WORKING has the flowing border, AWAITING has the pulse.
152
+ const badgeObj = isIdle ? `
153
+ <rect x="100" y="14" width="28" height="16" rx="8" fill="#ffffff" opacity="0.1" />
154
+ <text x="114" y="25" font-size="10" font-weight="700" text-anchor="middle" fill="#A1A1AA" font-family="${fontFam}">ACT</text>
155
+ ` : '';
156
+ const toolStr = isWorking ? 'Running task' : modelText;
157
+ const elements = [
158
+ `<defs>${defs}</defs>`,
159
+ `<rect width="${SIZE}" height="${SIZE}" rx="16" fill="url(#${gradId})"/>`,
160
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="#2C2C2E" opacity="0.8"/>`,
161
+ glowBorder,
162
+ leftStrip,
163
+ watermark,
164
+ spinner,
165
+ askDot,
166
+ runBadge,
167
+ badgeObj,
168
+ `<text x="20" y="32" font-size="17" font-weight="800" text-anchor="start" fill="${colorText}" font-family="${fontFam}">${escXml(stateLbl)}</text>`,
169
+ `<text x="20" y="52" font-size="13" font-weight="600" text-anchor="start" fill="#E2E8F0" font-family="${fontFam}">${escXml(truncate(nameForDisplay, 13))}</text>`,
170
+ `<text x="20" y="120" font-size="${isWorking ? '13' : '14'}" font-weight="500" text-anchor="start" fill="${colorText}" opacity="0.8" font-family="${fontFam}">${escXml(toolStr)}</text>`
171
+ ].join('');
172
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${SIZE}" height="${SIZE}" viewBox="0 0 ${SIZE} ${SIZE}">${elements}</svg>`;
173
+ }
174
+ // ---- Empty Slot ----
175
+ export function renderEmptySlot() {
176
+ const label = `<text x="72" y="76" text-anchor="middle" font-family="Arial,sans-serif" font-size="12" fill="#333333">Empty</text>`;
177
+ return svgFrame('#111111', label);
178
+ }
179
+ export function renderNoDaemonSlot(slot) {
180
+ if (slot === 0) {
181
+ // START button — launches macOS app
182
+ const elements = [
183
+ `<text x="72" y="56" text-anchor="middle" font-family="Arial,sans-serif" font-size="14" fill="#94a3b8">AgentDeck</text>`,
184
+ `<text x="72" y="96" text-anchor="middle" font-family="Arial,sans-serif" font-size="28" font-weight="bold" fill="#22c55e">\u25B6 START</text>`,
185
+ ].join('');
186
+ return svgFrame('#0f1a0f', elements);
187
+ }
188
+ return svgFrame('#111111', '');
189
+ }
190
+ // ---- Navigation Buttons ----
191
+ export function renderBackButton() {
192
+ const arrow = `<text x="72" y="76" text-anchor="middle" font-family="Arial,sans-serif" font-size="32" fill="#94a3b8">\u2190</text>`;
193
+ const label = `<text x="72" y="108" text-anchor="middle" font-family="Arial,sans-serif" font-size="16" font-weight="600" fill="#94a3b8">BACK</text>`;
194
+ return svgFrame('#1a1a1a', arrow + label);
195
+ }
196
+ export function renderNextPageButton(pageLabel) {
197
+ const arrow = `<text x="72" y="64" text-anchor="middle" font-family="Arial,sans-serif" font-size="28" fill="#60a5fa">\u25B6</text>`;
198
+ const label = `<text x="72" y="92" text-anchor="middle" font-family="Arial,sans-serif" font-size="14" font-weight="600" fill="#60a5fa">NEXT</text>`;
199
+ const page = `<text x="72" y="114" text-anchor="middle" font-family="Arial,sans-serif" font-size="11" fill="#64748b">${escXml(pageLabel)}</text>`;
200
+ return svgFrame('#1a1a2e', arrow + label + page);
201
+ }
202
+ export function renderEscButton(active = true) {
203
+ const c = active ? '#f97316' : '#a0855a';
204
+ const bg = active ? '#2d1810' : '#1a1308';
205
+ const op = active ? '' : ' opacity="0.45"';
206
+ const elements = [
207
+ `<text x="72" y="62" text-anchor="middle" font-family="Arial,sans-serif" font-size="32" fill="${c}"${op}>\u2716</text>`,
208
+ `<text x="72" y="100" text-anchor="middle" font-family="Arial,sans-serif" font-size="28" font-weight="bold" fill="${c}"${op}>ESC</text>`,
209
+ ].join('');
210
+ return svgFrame(bg, elements);
211
+ }
212
+ export function renderStopButton(active = true) {
213
+ const c = active ? '#ef4444' : '#666666';
214
+ const bg = active ? '#2d1010' : '#1a0a0a';
215
+ const op = active ? '' : ' opacity="0.4"';
216
+ const elements = [
217
+ `<text x="72" y="62" text-anchor="middle" font-family="Arial,sans-serif" font-size="32" fill="${c}"${op}>\u25A0</text>`,
218
+ `<text x="72" y="100" text-anchor="middle" font-family="Arial,sans-serif" font-size="28" font-weight="bold" fill="${c}"${op}>STOP</text>`,
219
+ ].join('');
220
+ return svgFrame(bg, elements);
221
+ }
222
+ // ---- Detail View: Session Info ----
223
+ export function renderDetailInfo(session, state, tool, modelName, mode, displayName, effortLevel) {
224
+ if (!session)
225
+ return renderEmptySlot();
226
+ const agent = session.agentType || 'claude-code';
227
+ const nameForDisplay = displayName ?? session.projectName;
228
+ const fontFam = 'Inter, -apple-system, system-ui, Helvetica Neue, sans-serif';
229
+ const sColor = stateColor(session.state);
230
+ const stateLbl = stateLabel(session.state, agent);
231
+ const gradId = `sd-bg-detail-${agent}`;
232
+ const defs = `
233
+ <linearGradient id="${gradId}" x1="0%" y1="0%" x2="0%" y2="100%">
234
+ <stop offset="0%" stop-color="#151720"/>
235
+ <stop offset="100%" stop-color="#0A0B10"/>
236
+ </linearGradient>
237
+ `;
238
+ const watermark = `<g transform="translate(90, 86)" opacity="0.36">
239
+ ${agentLogoIcon(agent, 40, 1, 0, 0)}
240
+ </g>`;
241
+ const leftStrip = `<rect x="8" y="8" width="4" height="128" rx="2" fill="${sColor}"/>`;
242
+ const badgeObj = `
243
+ <rect x="100" y="14" width="28" height="16" rx="8" fill="#ffffff" opacity="0.1" />
244
+ <text x="114" y="25" font-size="10" font-weight="700" text-anchor="middle" fill="#A1A1AA" font-family="${fontFam}">INFO</text>
245
+ `;
246
+ const toolDisplay = tool ? `\u25B6 ${truncate(tool, 18)}` : stateLbl;
247
+ const elements = [
248
+ `<defs>${defs}</defs>`,
249
+ `<rect width="${SIZE}" height="${SIZE}" rx="16" fill="url(#${gradId})"/>`,
250
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="#1C1F2E" opacity="0.8"/>`,
251
+ leftStrip,
252
+ watermark,
253
+ badgeObj,
254
+ // Title
255
+ `<text x="20" y="34" font-size="18" font-weight="800" text-anchor="start" fill="#ffffff" font-family="${fontFam}">${escXml(truncate(nameForDisplay, 10))}</text>`,
256
+ // Model/Mode — effort renders inline with model (e.g. "Opus 4.7 · max")
257
+ // so the permission-mode chip below keeps its y=74 slot.
258
+ (modelName && agent !== 'openclaw') ? `<text x="20" y="56" font-size="12" font-weight="600" text-anchor="start" fill="#94a3b8" font-family="${fontFam}">${escXml(formatModelEffort(modelName, effortLevel, 17))}</text>` : '',
259
+ (mode && mode !== 'default' && agent !== 'openclaw') ? `<text x="20" y="74" font-size="11" font-weight="700" text-anchor="start" fill="#a78bfa" font-family="${fontFam}">${escXml(mode.toUpperCase())}</text>` : '',
260
+ // Tool/State
261
+ `<text x="20" y="120" font-size="12" font-weight="700" text-anchor="start" fill="${tool ? '#fbbf24' : sColor}" font-family="${fontFam}">${escXml(toolDisplay)}</text>`,
262
+ ].join('');
263
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${SIZE}" height="${SIZE}" viewBox="0 0 ${SIZE} ${SIZE}">${elements}</svg>`;
264
+ }
265
+ // ---- Detail View: Option Button ----
266
+ export function renderOptionButton(option, index) {
267
+ const label = option.label || `Option ${index + 1}`;
268
+ const lines = wrapTextByWidth(label, MAX_TEXT_PX, 16);
269
+ const lineHeight = 20;
270
+ const startY = lines.length === 1 ? 76 : 76 - ((lines.length - 1) * lineHeight) / 2;
271
+ // Slot number (top-right)
272
+ const slotNum = `<text x="${SIZE - 10}" y="18" text-anchor="end" font-family="Arial,sans-serif" font-size="13" fill="#ffffff" opacity="0.25">${index + 1}</text>`;
273
+ const textEls = lines.slice(0, 3).map((line, i) => `<text x="72" y="${startY + i * lineHeight}" text-anchor="middle" font-family="Arial,sans-serif" font-size="16" font-weight="bold" fill="#ffffff">${escXml(line)}</text>`).join('');
274
+ // Use different bg colors for visual distinction
275
+ const colors = ['#1e3a5f', '#1e3a4a', '#2a1e4a', '#1e4a3a', '#3a1e2a'];
276
+ const bgColor = colors[index % colors.length];
277
+ return svgFrame(bgColor, slotNum + textEls);
278
+ }
279
+ // ---- Detail View: Preset Action Button ----
280
+ export function renderPresetButton(label, iconSvg, color, textColor, subtitle, loading) {
281
+ if (loading) {
282
+ return svgFrame(color, iconSvg);
283
+ }
284
+ const labelEl = `<text x="72" y="100" text-anchor="middle" font-family="Arial,sans-serif" font-size="16" font-weight="bold" fill="${textColor}">${escXml(label)}</text>`;
285
+ const subEl = subtitle
286
+ ? `<text x="72" y="118" text-anchor="middle" font-family="Arial,sans-serif" font-size="12" fill="${textColor}" opacity="0.7">${escXml(truncate(subtitle, 14))}</text>`
287
+ : '';
288
+ return svgFrame(color, iconSvg + labelEl + subEl);
289
+ }
290
+ // ---- Detail View: Info slot (tool, model/mode) ----
291
+ export function renderInfoSlot(label, subtitle) {
292
+ const mainEl = `<text x="72" y="${subtitle ? 68 : 76}" text-anchor="middle" font-family="Arial,sans-serif" font-size="16" font-weight="bold" fill="#94a3b8">${escXml(truncate(label, 18))}</text>`;
293
+ const subEl = subtitle
294
+ ? `<text x="72" y="92" text-anchor="middle" font-family="Arial,sans-serif" font-size="12" fill="#64748b">${escXml(truncate(subtitle, 22))}</text>`
295
+ : '';
296
+ return svgFrame('#1a1a1a', mainEl + subEl);
297
+ }
298
+ // ---- SVG Frame ----
299
+ export function svgFrame(bgColor, innerElements) {
300
+ // Use a random ID to prevent SVG constraint clashes
301
+ const gradId = 'frame-bg-' + Math.floor(Math.random() * 1000000);
302
+ const defs = `
303
+ <linearGradient id="${gradId}" x1="0%" y1="0%" x2="0%" y2="100%">
304
+ <stop offset="0%" stop-color="${bgColor}"/>
305
+ <stop offset="100%" stop-color="#0A0A0E"/>
306
+ </linearGradient>
307
+ `;
308
+ return [
309
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${SIZE}" height="${SIZE}" viewBox="0 0 ${SIZE} ${SIZE}">`,
310
+ `<defs>${defs}</defs>`,
311
+ `<rect width="${SIZE}" height="${SIZE}" rx="16" fill="url(#${gradId})"/>`,
312
+ `<rect x="8" y="8" width="128" height="128" rx="12" fill="#2C2C2E" opacity="0.6"/>`,
313
+ innerElements,
314
+ `</svg>`,
315
+ ].join('');
316
+ }
317
+ //# sourceMappingURL=session-slot-renderer.js.map