@agentdeck/shared 0.1.0 → 0.2.3

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 (114) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapter.d.ts +18 -3
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +62 -0
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/command-builders.d.ts +35 -0
  7. package/dist/command-builders.d.ts.map +1 -0
  8. package/dist/command-builders.js +75 -0
  9. package/dist/command-builders.js.map +1 -0
  10. package/dist/connection-status.d.ts +42 -0
  11. package/dist/connection-status.d.ts.map +1 -0
  12. package/dist/connection-status.js +52 -0
  13. package/dist/connection-status.js.map +1 -0
  14. package/dist/d200h-layout.d.ts +131 -0
  15. package/dist/d200h-layout.d.ts.map +1 -0
  16. package/dist/d200h-layout.js +627 -0
  17. package/dist/d200h-layout.js.map +1 -0
  18. package/dist/design-tokens.d.ts +259 -0
  19. package/dist/design-tokens.d.ts.map +1 -0
  20. package/dist/design-tokens.js +156 -0
  21. package/dist/design-tokens.js.map +1 -0
  22. package/dist/eval-schema.d.ts +235 -0
  23. package/dist/eval-schema.d.ts.map +1 -0
  24. package/dist/eval-schema.js +23 -0
  25. package/dist/eval-schema.js.map +1 -0
  26. package/dist/format-utils.d.ts +52 -0
  27. package/dist/format-utils.d.ts.map +1 -0
  28. package/dist/format-utils.js +165 -0
  29. package/dist/format-utils.js.map +1 -0
  30. package/dist/gateway-protocol.d.ts +391 -0
  31. package/dist/gateway-protocol.d.ts.map +1 -0
  32. package/dist/gateway-protocol.js +19 -0
  33. package/dist/gateway-protocol.js.map +1 -0
  34. package/dist/index.d.ts +19 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +19 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/llm-settings.d.ts +52 -0
  39. package/dist/llm-settings.d.ts.map +1 -0
  40. package/dist/llm-settings.js +118 -0
  41. package/dist/llm-settings.js.map +1 -0
  42. package/dist/net-utils.d.ts +2 -1
  43. package/dist/net-utils.d.ts.map +1 -1
  44. package/dist/net-utils.js +100 -3
  45. package/dist/net-utils.js.map +1 -1
  46. package/dist/pricing.d.ts +45 -0
  47. package/dist/pricing.d.ts.map +1 -0
  48. package/dist/pricing.js +93 -0
  49. package/dist/pricing.js.map +1 -0
  50. package/dist/protocol.d.ts +496 -2
  51. package/dist/protocol.d.ts.map +1 -1
  52. package/dist/protocol.js +30 -1
  53. package/dist/protocol.js.map +1 -1
  54. package/dist/sample.d.ts +152 -0
  55. package/dist/sample.d.ts.map +1 -0
  56. package/dist/sample.js +22 -0
  57. package/dist/sample.js.map +1 -0
  58. package/dist/session-utils.d.ts +142 -0
  59. package/dist/session-utils.d.ts.map +1 -0
  60. package/dist/session-utils.js +304 -0
  61. package/dist/session-utils.js.map +1 -0
  62. package/dist/state-colors.d.ts +16 -0
  63. package/dist/state-colors.d.ts.map +1 -0
  64. package/dist/state-colors.js +48 -0
  65. package/dist/state-colors.js.map +1 -0
  66. package/dist/states.d.ts +2 -0
  67. package/dist/states.d.ts.map +1 -1
  68. package/dist/states.js +6 -1
  69. package/dist/states.js.map +1 -1
  70. package/dist/svg-renderers/agent-logos.d.ts +45 -0
  71. package/dist/svg-renderers/agent-logos.d.ts.map +1 -0
  72. package/dist/svg-renderers/agent-logos.js +238 -0
  73. package/dist/svg-renderers/agent-logos.js.map +1 -0
  74. package/dist/svg-renderers/index.d.ts +4 -0
  75. package/dist/svg-renderers/index.d.ts.map +1 -0
  76. package/dist/svg-renderers/index.js +4 -0
  77. package/dist/svg-renderers/index.js.map +1 -0
  78. package/dist/svg-renderers/session-slot-renderer.d.ts +78 -0
  79. package/dist/svg-renderers/session-slot-renderer.d.ts.map +1 -0
  80. package/dist/svg-renderers/session-slot-renderer.js +506 -0
  81. package/dist/svg-renderers/session-slot-renderer.js.map +1 -0
  82. package/dist/svg-renderers/text-utils.d.ts +29 -0
  83. package/dist/svg-renderers/text-utils.d.ts.map +1 -0
  84. package/dist/svg-renderers/text-utils.js +122 -0
  85. package/dist/svg-renderers/text-utils.js.map +1 -0
  86. package/dist/telemetry-envelope.d.ts +108 -0
  87. package/dist/telemetry-envelope.d.ts.map +1 -0
  88. package/dist/telemetry-envelope.js +34 -0
  89. package/dist/telemetry-envelope.js.map +1 -0
  90. package/dist/timeline-icons.d.ts +70 -0
  91. package/dist/timeline-icons.d.ts.map +1 -0
  92. package/dist/timeline-icons.js +161 -0
  93. package/dist/timeline-icons.js.map +1 -0
  94. package/dist/timeline-label.d.ts +38 -0
  95. package/dist/timeline-label.d.ts.map +1 -0
  96. package/dist/timeline-label.js +95 -0
  97. package/dist/timeline-label.js.map +1 -0
  98. package/dist/timeline-markdown.d.ts +80 -0
  99. package/dist/timeline-markdown.d.ts.map +1 -0
  100. package/dist/timeline-markdown.js +221 -0
  101. package/dist/timeline-markdown.js.map +1 -0
  102. package/dist/timeline-summarizer.d.ts +37 -0
  103. package/dist/timeline-summarizer.d.ts.map +1 -0
  104. package/dist/timeline-summarizer.js +125 -0
  105. package/dist/timeline-summarizer.js.map +1 -0
  106. package/dist/timeline.d.ts +135 -0
  107. package/dist/timeline.d.ts.map +1 -0
  108. package/dist/timeline.js +633 -0
  109. package/dist/timeline.js.map +1 -0
  110. package/dist/voice-paths.d.ts +4 -0
  111. package/dist/voice-paths.d.ts.map +1 -1
  112. package/dist/voice-paths.js +5 -0
  113. package/dist/voice-paths.js.map +1 -1
  114. package/package.json +9 -3
@@ -0,0 +1,152 @@
1
+ /**
2
+ * AgentDeck SessionSample — the canonical, evaluable unit of agent work.
3
+ *
4
+ * Inspired by Inspect AI's `EvalLog → Sample → Event → Scorer` model. A
5
+ * `SessionSample` is a bounded slice of an agent session (one "task") carrying
6
+ * a typed trajectory of message/tool/model/state events. It is the SINGLE
7
+ * source of truth: both the device-facing TIMELINE and the APME evaluation are
8
+ * projections of this object, rather than two parallel event emitters.
9
+ *
10
+ * Storage: the `tasks` row IS the sample header (id/run_id/index/boundary/…);
11
+ * the typed trajectory lives in the `sample_events` table. See
12
+ * `bridge/src/apme/store.ts`. Logical field names here are camelCase; the DAO
13
+ * maps to snake_case columns.
14
+ *
15
+ * Satisfies the HuggingFace "universal agent eval" requirements:
16
+ * #2 agent identity → SampleModelConfig (model, subagents, mcpServers)
17
+ * #5 trajectory → TrajectoryEvent[] (typed, ordered)
18
+ * #6 tool-use → ToolEvent
19
+ * #7 cost tracking → SampleCost + per-ModelEvent cost/latency
20
+ */
21
+ import type { AgentType } from './adapter.js';
22
+ import type { ResponseKind, TaskBoundarySignal } from './eval-schema.js';
23
+ export interface SampleModelConfig {
24
+ /** Real model id, e.g. "claude-opus-4-8", "gpt-5-codex", "mlx:qwen3-30b". */
25
+ modelId: string;
26
+ /** "anthropic" | "openai" | "mlx" | "openclaw" | "local" | … */
27
+ provider?: string | null;
28
+ /** Sub-agent names spawned during the sample (Task tool, delegations). */
29
+ subagents?: string[];
30
+ /** MCP server names the agent had access to. */
31
+ mcpServers?: string[];
32
+ }
33
+ export interface SampleCost {
34
+ inputTokens: number;
35
+ outputTokens: number;
36
+ /** Sum over the sample's ModelEvents (priced at ingestion). 0 for local. */
37
+ costUsd: number;
38
+ /** Sum of per-model-call latencies (ms). */
39
+ latencyMs: number;
40
+ }
41
+ export type TrajectoryEventKind = 'user_message' | 'assistant_message' | 'model' | 'tool' | 'state' | 'info';
42
+ export type ToolStatus = 'pending' | 'success' | 'error';
43
+ interface TrajectoryEventBase {
44
+ ts: number;
45
+ /** Index of the turn this event belongs to within the run. */
46
+ turnIndex: number;
47
+ }
48
+ /** A user prompt / message. */
49
+ export interface UserMessageEvent extends TrajectoryEventBase {
50
+ kind: 'user_message';
51
+ text: string;
52
+ }
53
+ /** An assistant response body. `responseKind` lets scorers skip silence. */
54
+ export interface AssistantMessageEvent extends TrajectoryEventBase {
55
+ kind: 'assistant_message';
56
+ text: string;
57
+ responseKind: ResponseKind;
58
+ }
59
+ /** A model invocation with usage + cost. The atom of cost tracking. */
60
+ export interface ModelEvent extends TrajectoryEventBase {
61
+ kind: 'model';
62
+ model: string;
63
+ inputTokens: number;
64
+ outputTokens: number;
65
+ /** Priced at ingestion via shared/src/pricing.ts. 0 for local models. */
66
+ costUsd: number;
67
+ latencyMs: number;
68
+ }
69
+ /** A single tool call. The PreToolUse/PostToolUse pair collapses into one row. */
70
+ export interface ToolEvent extends TrajectoryEventBase {
71
+ kind: 'tool';
72
+ name: string;
73
+ input?: unknown;
74
+ output?: unknown;
75
+ error?: string | null;
76
+ status?: ToolStatus;
77
+ }
78
+ /** An agent-state machine transition (idle → processing → awaiting …). */
79
+ export interface StateTransitionEvent extends TrajectoryEventBase {
80
+ kind: 'state';
81
+ from?: string | null;
82
+ to: string;
83
+ }
84
+ /** Free-form annotation: memory recall, errors, boundary markers. */
85
+ export interface InfoEvent extends TrajectoryEventBase {
86
+ kind: 'info';
87
+ label: string;
88
+ detail?: string | null;
89
+ }
90
+ export type TrajectoryEvent = UserMessageEvent | AssistantMessageEvent | ModelEvent | ToolEvent | StateTransitionEvent | InfoEvent;
91
+ export interface SampleScore {
92
+ /** Scorer name, e.g. "deterministic", "judge", "outcome", "trajectory". */
93
+ scorer: string;
94
+ /** Axis within the scorer, e.g. "tests_pass", "overall", "tool_efficiency". */
95
+ metric: string;
96
+ /** [0,1]. */
97
+ score: number;
98
+ reasoning?: string | null;
99
+ }
100
+ export interface SessionSample {
101
+ /** Equals tasks.id — the task row is the sample header. */
102
+ id: string;
103
+ runId: string;
104
+ sessionId: string;
105
+ agentType: AgentType;
106
+ /** task_index within the run. */
107
+ index: number;
108
+ boundarySignal: TaskBoundarySignal;
109
+ startedAt: number;
110
+ endedAt?: number | null;
111
+ /** req #2 — agent identity. */
112
+ model: SampleModelConfig;
113
+ projectName?: string | null;
114
+ projectPath?: string | null;
115
+ /** req #5 — the ordered typed trajectory. */
116
+ events: TrajectoryEvent[];
117
+ /** req #7 — aggregated cost, projected from ModelEvents. */
118
+ cost: SampleCost;
119
+ /** Scorer outputs (present once evaluated). */
120
+ scores?: SampleScore[];
121
+ summary?: string | null;
122
+ outcome?: string | null;
123
+ compositeScore?: number | null;
124
+ taskCategory?: string | null;
125
+ }
126
+ /** One typed trajectory event as stored. Logical (camelCase) mirror of the
127
+ * `sample_events` columns. `payload` is JSON: message text, tool input/output,
128
+ * state from/to, or info detail depending on `kind`. */
129
+ export interface ApmeSampleEventRow {
130
+ id?: number;
131
+ taskId: string;
132
+ runId: string;
133
+ turnIndex?: number | null;
134
+ /** Monotonic order within the task. */
135
+ seq: number;
136
+ ts: number;
137
+ kind: TrajectoryEventKind;
138
+ model?: string | null;
139
+ inputTokens?: number | null;
140
+ outputTokens?: number | null;
141
+ costUsd?: number | null;
142
+ latencyMs?: number | null;
143
+ toolName?: string | null;
144
+ toolStatus?: ToolStatus | string | null;
145
+ toolError?: string | null;
146
+ /** JSON payload (message text / tool input+output / info detail / state). */
147
+ payload?: string | null;
148
+ /** Storage-time dedup key: sha1(kind | turnIndex | semanticCore). UNIQUE per task. */
149
+ dedupKey?: string | null;
150
+ }
151
+ export {};
152
+ //# sourceMappingURL=sample.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../src/sample.ts"],"names":[],"mappings":"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"}
package/dist/sample.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * AgentDeck SessionSample — the canonical, evaluable unit of agent work.
3
+ *
4
+ * Inspired by Inspect AI's `EvalLog → Sample → Event → Scorer` model. A
5
+ * `SessionSample` is a bounded slice of an agent session (one "task") carrying
6
+ * a typed trajectory of message/tool/model/state events. It is the SINGLE
7
+ * source of truth: both the device-facing TIMELINE and the APME evaluation are
8
+ * projections of this object, rather than two parallel event emitters.
9
+ *
10
+ * Storage: the `tasks` row IS the sample header (id/run_id/index/boundary/…);
11
+ * the typed trajectory lives in the `sample_events` table. See
12
+ * `bridge/src/apme/store.ts`. Logical field names here are camelCase; the DAO
13
+ * maps to snake_case columns.
14
+ *
15
+ * Satisfies the HuggingFace "universal agent eval" requirements:
16
+ * #2 agent identity → SampleModelConfig (model, subagents, mcpServers)
17
+ * #5 trajectory → TrajectoryEvent[] (typed, ordered)
18
+ * #6 tool-use → ToolEvent
19
+ * #7 cost tracking → SampleCost + per-ModelEvent cost/latency
20
+ */
21
+ export {};
22
+ //# sourceMappingURL=sample.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample.js","sourceRoot":"","sources":["../src/sample.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * session-utils.ts — Shared session ordering, numbering, and tier grouping.
3
+ * Single source of truth used by: TUI renderer, Plugin, Android, Apple, MenuBarExtra.
4
+ */
5
+ /**
6
+ * Rank agent states by priority (lower = higher priority).
7
+ * processing=0, awaiting=1, idle=2, disconnected=3, unknown=4.
8
+ */
9
+ export declare function stateRank(state: string | undefined): number;
10
+ export type SessionTier = 'attention' | 'active' | 'idle';
11
+ export declare function sessionTier(state: string | undefined): SessionTier;
12
+ /**
13
+ * Rank agent types for stable ordering.
14
+ * openclaw=0 (always first), claude-code=1, codex-cli=2, codex-app=3, opencode=4, antigravity=5, others=6.
15
+ */
16
+ export declare function agentTypeRank(agentType: string | undefined): number;
17
+ export declare function naturalLabelCompare(a: string | undefined, b: string | undefined): number;
18
+ export interface GatewayVisibilityFlags {
19
+ /** TCP port 18789 reachable — a topology hint only, NOT proof commands route. */
20
+ gatewayAvailable?: boolean;
21
+ /** Gateway WS handshake + auth succeeded — proof commands can route. */
22
+ gatewayConnected?: boolean;
23
+ /** `openclaw doctor`/health reports an error. */
24
+ gatewayHasError?: boolean;
25
+ }
26
+ /**
27
+ * SSOT: the daemon injects the virtual `openclaw` session iff this holds.
28
+ *
29
+ * "Active" = authenticated / can-route = the Gateway WS handshake+auth
30
+ * succeeded (`gatewayConnected`). Reachability (`gatewayAvailable`) and health
31
+ * (`gatewayHasError`) are topology/status hints only and MUST NOT materialize a
32
+ * session — surfacing them as a session is what made OpenClaw "stick" on
33
+ * devices after it was effectively off.
34
+ *
35
+ * Hand-mirrored in Swift `DashboardDataRules.isOpenClawSessionActive`
36
+ * (apple/AgentDeck/Model/Protocol.swift) and Kotlin `isOpenClawSessionActive`
37
+ * (android/.../ui/eink/EinkFormatUtils.kt) — keep all three in lockstep.
38
+ */
39
+ export declare function isOpenClawSessionActive(flags: GatewayVisibilityFlags): boolean;
40
+ /**
41
+ * Consumer SSOT: render OpenClaw iff the daemon actually emitted the session.
42
+ * Consumers must NOT re-derive OpenClaw visibility from raw gateway flags;
43
+ * the daemon source is the single authority. Hand-mirrored in Swift/Kotlin.
44
+ */
45
+ export declare function hasOpenClawSession<T extends {
46
+ agentType?: string;
47
+ }>(sessions: readonly T[]): boolean;
48
+ /**
49
+ * Sort sessions with stable ordering that does NOT jump on state changes.
50
+ *
51
+ * Order: agentType (openclaw first → claude-code → codex → opencode → antigravity)
52
+ * → projectName alphabetically
53
+ * → startedAt ascending (oldest first) for stability
54
+ * → id as final tiebreaker
55
+ *
56
+ * Returns a new array (never mutates input).
57
+ */
58
+ export declare function sortSessions<T extends {
59
+ state?: string;
60
+ projectName?: string;
61
+ agentType?: string;
62
+ startedAt?: string;
63
+ id?: string;
64
+ }>(sessions: T[]): T[];
65
+ export interface FoldableSession {
66
+ id: string;
67
+ projectName?: string;
68
+ agentType?: string;
69
+ state?: string;
70
+ startedAt?: string;
71
+ currentTool?: string;
72
+ groupSize?: number;
73
+ foldedSessionIds?: string[];
74
+ }
75
+ /**
76
+ * Collapse Codex companion-task rows for the same project into one display
77
+ * session. Raw rows remain authoritative inside the daemon; every user-facing
78
+ * surface should count this folded shape so completed one-turn Codex threads do
79
+ * not look like simultaneously running sessions.
80
+ */
81
+ export declare function foldCodexSessionsForDisplay<T extends FoldableSession>(sessions: T[]): T[];
82
+ export interface SessionDisplayInfo {
83
+ /** Original session (unmodified) */
84
+ session: {
85
+ id: string;
86
+ projectName: string;
87
+ agentType?: string;
88
+ state?: string;
89
+ [key: string]: unknown;
90
+ };
91
+ /** Display name with optional #N suffix */
92
+ displayName: string;
93
+ /** Session tier for UI grouping */
94
+ tier: SessionTier;
95
+ }
96
+ /**
97
+ * Assign display names with #N suffixes for duplicate (projectName, agentType) tuples.
98
+ * Input is NOT mutated. Returns new display info objects.
99
+ *
100
+ * @param sessions - Already-sorted sessions array
101
+ */
102
+ export declare function assignDisplayNames<T extends {
103
+ id: string;
104
+ projectName: string;
105
+ agentType?: string;
106
+ state?: string;
107
+ }>(sessions: T[]): (SessionDisplayInfo & {
108
+ session: T;
109
+ })[];
110
+ /**
111
+ * Normalize a project name for grouping: strip any path to the basename and
112
+ * drop a trailing " #N" duplicate suffix so "Foo #1" / "Foo #2" compare equal.
113
+ * Mirrors office.cpp `normProject`.
114
+ */
115
+ export declare function normalizeProjectForGrouping(project: string | undefined): string;
116
+ /**
117
+ * When two normalized project names belong to the same work group, return the
118
+ * shared group key (the common stem); otherwise null. Mirrors office.cpp
119
+ * `sameProjectGroup`:
120
+ * - exact (case-insensitive) match → group
121
+ * - one extends the other at a delimiter ("foo-bar" + "foo-bar-1") or they
122
+ * diverge after a shared delimiter-aligned stem ("…-broken-a" + "…-broken-b")
123
+ * - conservative: only long multi-token stems fuse (stem ≥ 14 chars with
124
+ * ≥ 2 delimiters on both sides), so short siblings like "agentdeck-ios" /
125
+ * "agentdeck-android" stay separate.
126
+ */
127
+ export declare function projectGroupKey(a: string, b: string): string | null;
128
+ export interface ProjectGroup<T> {
129
+ /** Group label — the shared stem, or the (normalized) project name for singletons. */
130
+ key: string;
131
+ /** True when ≥2 members fused (render a group header); singletons render flat. */
132
+ grouped: boolean;
133
+ members: T[];
134
+ }
135
+ /**
136
+ * Cluster an ordered session list into project groups, preserving the input
137
+ * order (first member's position anchors the group; members keep relative
138
+ * order). Greedy pairwise fusion with a growing group key, exactly like the
139
+ * office.cpp huddle builder.
140
+ */
141
+ export declare function groupSessionsByProject<T>(items: readonly T[], projectOf: (item: T) => string | undefined): ProjectGroup<T>[];
142
+ //# sourceMappingURL=session-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-utils.d.ts","sourceRoot":"","sources":["../src/session-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,304 @@
1
+ /**
2
+ * session-utils.ts — Shared session ordering, numbering, and tier grouping.
3
+ * Single source of truth used by: TUI renderer, Plugin, Android, Apple, MenuBarExtra.
4
+ */
5
+ // ===== State Ranking =====
6
+ /**
7
+ * Rank agent states by priority (lower = higher priority).
8
+ * processing=0, awaiting=1, idle=2, disconnected=3, unknown=4.
9
+ */
10
+ export function stateRank(state) {
11
+ switch (state) {
12
+ case 'processing': return 0;
13
+ case 'awaiting_permission':
14
+ case 'awaiting_option':
15
+ case 'awaiting_diff': return 1;
16
+ case 'idle': return 2;
17
+ case 'disconnected': return 3;
18
+ default: return 4;
19
+ }
20
+ }
21
+ export function sessionTier(state) {
22
+ switch (state) {
23
+ case 'awaiting_permission':
24
+ case 'awaiting_option':
25
+ case 'awaiting_diff':
26
+ return 'attention';
27
+ case 'processing':
28
+ return 'active';
29
+ default:
30
+ return 'idle';
31
+ }
32
+ }
33
+ // ===== Agent Type Ranking (stable ordering by agent kind) =====
34
+ /**
35
+ * Rank agent types for stable ordering.
36
+ * openclaw=0 (always first), claude-code=1, codex-cli=2, codex-app=3, opencode=4, antigravity=5, others=6.
37
+ */
38
+ export function agentTypeRank(agentType) {
39
+ switch (agentType) {
40
+ case 'openclaw': return 0;
41
+ case 'claude-code': return 1;
42
+ case 'codex-cli': return 2;
43
+ case 'codex-app': return 3;
44
+ case 'opencode': return 4;
45
+ case 'antigravity': return 5;
46
+ default: return 6;
47
+ }
48
+ }
49
+ export function naturalLabelCompare(a, b) {
50
+ return (a || '').localeCompare(b || '', undefined, { numeric: true, sensitivity: 'base' });
51
+ }
52
+ /**
53
+ * SSOT: the daemon injects the virtual `openclaw` session iff this holds.
54
+ *
55
+ * "Active" = authenticated / can-route = the Gateway WS handshake+auth
56
+ * succeeded (`gatewayConnected`). Reachability (`gatewayAvailable`) and health
57
+ * (`gatewayHasError`) are topology/status hints only and MUST NOT materialize a
58
+ * session — surfacing them as a session is what made OpenClaw "stick" on
59
+ * devices after it was effectively off.
60
+ *
61
+ * Hand-mirrored in Swift `DashboardDataRules.isOpenClawSessionActive`
62
+ * (apple/AgentDeck/Model/Protocol.swift) and Kotlin `isOpenClawSessionActive`
63
+ * (android/.../ui/eink/EinkFormatUtils.kt) — keep all three in lockstep.
64
+ */
65
+ export function isOpenClawSessionActive(flags) {
66
+ return flags.gatewayConnected === true;
67
+ }
68
+ /**
69
+ * Consumer SSOT: render OpenClaw iff the daemon actually emitted the session.
70
+ * Consumers must NOT re-derive OpenClaw visibility from raw gateway flags;
71
+ * the daemon source is the single authority. Hand-mirrored in Swift/Kotlin.
72
+ */
73
+ export function hasOpenClawSession(sessions) {
74
+ return sessions.some(s => s.agentType === 'openclaw');
75
+ }
76
+ // ===== Sorting =====
77
+ /**
78
+ * Sort sessions with stable ordering that does NOT jump on state changes.
79
+ *
80
+ * Order: agentType (openclaw first → claude-code → codex → opencode → antigravity)
81
+ * → projectName alphabetically
82
+ * → startedAt ascending (oldest first) for stability
83
+ * → id as final tiebreaker
84
+ *
85
+ * Returns a new array (never mutates input).
86
+ */
87
+ export function sortSessions(sessions) {
88
+ return [...sessions].sort((a, b) => {
89
+ // 1. Agent type group (openclaw first, then by agent kind)
90
+ const typeRank = agentTypeRank(a.agentType) - agentTypeRank(b.agentType);
91
+ if (typeRank !== 0)
92
+ return typeRank;
93
+ // 2. Project name alphabetically with numeric chunks (Agent 2 before
94
+ // Agent 10). Must match Swift DashboardDataRules.naturalLabelCompare
95
+ // and Android naturalLabelCompare, otherwise numbered sessions render
96
+ // in different order on Stream Deck vs. Apple/Android.
97
+ const nameCompare = naturalLabelCompare(a.projectName, b.projectName);
98
+ if (nameCompare !== 0)
99
+ return nameCompare;
100
+ // 3. Start time ascending (oldest first = stable position)
101
+ if (a.startedAt && b.startedAt) {
102
+ const diff = new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime();
103
+ if (diff !== 0)
104
+ return diff;
105
+ }
106
+ // 4. Session ID as final tiebreaker
107
+ return naturalLabelCompare(a.id, b.id);
108
+ });
109
+ }
110
+ /**
111
+ * Collapse Codex companion-task rows for the same project into one display
112
+ * session. Raw rows remain authoritative inside the daemon; every user-facing
113
+ * surface should count this folded shape so completed one-turn Codex threads do
114
+ * not look like simultaneously running sessions.
115
+ */
116
+ export function foldCodexSessionsForDisplay(sessions) {
117
+ const passthrough = [];
118
+ const codexByProject = new Map();
119
+ for (const session of sessions) {
120
+ const project = session.projectName?.trim();
121
+ if (!isCodexSession(session) || !project) {
122
+ passthrough.push(session);
123
+ continue;
124
+ }
125
+ const key = `${codexDisplayKind(session)}:${project.toLocaleLowerCase()}`;
126
+ const group = codexByProject.get(key);
127
+ if (group)
128
+ group.push(session);
129
+ else
130
+ codexByProject.set(key, [session]);
131
+ }
132
+ for (const group of codexByProject.values()) {
133
+ passthrough.push(foldCodexProjectGroup(group));
134
+ }
135
+ return passthrough;
136
+ }
137
+ function isCodexSession(session) {
138
+ return session.agentType === 'codex-cli' || session.agentType === 'codex-app' || session.id.startsWith('codex:');
139
+ }
140
+ function codexDisplayKind(session) {
141
+ return session.agentType === 'codex-app' ? 'codex-app' : 'codex-cli';
142
+ }
143
+ function foldCodexProjectGroup(group) {
144
+ if (group.length <= 1)
145
+ return group[0];
146
+ const ranked = [...group].sort((a, b) => {
147
+ const rankDiff = stateRank(a.state) - stateRank(b.state);
148
+ if (rankDiff !== 0)
149
+ return rankDiff;
150
+ const aStarted = a.startedAt ? new Date(a.startedAt).getTime() : Number.NEGATIVE_INFINITY;
151
+ const bStarted = b.startedAt ? new Date(b.startedAt).getTime() : Number.NEGATIVE_INFINITY;
152
+ if (aStarted !== bStarted)
153
+ return bStarted - aStarted;
154
+ return a.id.localeCompare(b.id);
155
+ });
156
+ const representative = ranked[0];
157
+ const foldedIds = group.flatMap(s => s.foldedSessionIds ?? [s.id]);
158
+ const groupSize = group.reduce((total, s) => total + (s.groupSize ?? 1), 0);
159
+ const currentTool = ranked.find(s => stateRank(s.state) === 0 && s.currentTool?.trim())?.currentTool;
160
+ const folded = {
161
+ ...representative,
162
+ state: ranked[0].state,
163
+ groupSize,
164
+ foldedSessionIds: foldedIds,
165
+ };
166
+ if (currentTool) {
167
+ folded.currentTool = currentTool;
168
+ }
169
+ else {
170
+ delete folded.currentTool;
171
+ }
172
+ return folded;
173
+ }
174
+ /**
175
+ * Assign display names with #N suffixes for duplicate (projectName, agentType) tuples.
176
+ * Input is NOT mutated. Returns new display info objects.
177
+ *
178
+ * @param sessions - Already-sorted sessions array
179
+ */
180
+ export function assignDisplayNames(sessions) {
181
+ // Count occurrences of each (projectName, agentType) pair
182
+ const counts = new Map();
183
+ for (const s of sessions) {
184
+ const key = `${s.projectName}:${s.agentType || ''}`;
185
+ counts.set(key, (counts.get(key) || 0) + 1);
186
+ }
187
+ // Assign sequential numbers
188
+ const seq = new Map();
189
+ return sessions.map(s => {
190
+ const key = `${s.projectName}:${s.agentType || ''}`;
191
+ const n = (seq.get(key) || 0) + 1;
192
+ seq.set(key, n);
193
+ const needsSuffix = (counts.get(key) || 1) > 1;
194
+ const displayName = needsSuffix ? `${s.projectName} #${n}` : s.projectName;
195
+ return {
196
+ session: s,
197
+ displayName,
198
+ tier: sessionTier(s.state),
199
+ };
200
+ });
201
+ }
202
+ // ===== Project-Prefix Grouping (IPS10 office huddle port) =====
203
+ //
204
+ // The IPS10 terrarium (esp32/src/ui/terrarium/office.cpp — normProject /
205
+ // sameProjectGroup) clusters sessions whose project names share a long
206
+ // delimiter-aligned prefix into one "work huddle": worktree/task folders like
207
+ // `xteink-x3-x4-japanese-broken-claude-glm` / `…-broken-codex` read as one
208
+ // unit of work, not N unrelated sessions. This is the SSOT port so the other
209
+ // dashboards' session lists (Android tablet SessionListPanel.kt, Apple
210
+ // SessionListPanel.swift — hand-mirrored, keep in lockstep) group the same way.
211
+ function isProjectDelim(c) {
212
+ return c === '-' || c === '_' || c === ' ' || c === '.';
213
+ }
214
+ function trimProjectTail(s) {
215
+ let n = s.length;
216
+ while (n > 0 && (isProjectDelim(s[n - 1]) || s[n - 1] === '#'))
217
+ n--;
218
+ return s.slice(0, n);
219
+ }
220
+ function projectDelimCount(s, len) {
221
+ let count = 0;
222
+ for (let i = 0; i < len && i < s.length; i++)
223
+ if (isProjectDelim(s[i]))
224
+ count++;
225
+ return count;
226
+ }
227
+ /**
228
+ * Normalize a project name for grouping: strip any path to the basename and
229
+ * drop a trailing " #N" duplicate suffix so "Foo #1" / "Foo #2" compare equal.
230
+ * Mirrors office.cpp `normProject`.
231
+ */
232
+ export function normalizeProjectForGrouping(project) {
233
+ const raw = (project || '').trim();
234
+ const base = raw.split('/').filter(Boolean).pop() || raw;
235
+ const m = base.match(/^(.*?)\s*#\d+$/);
236
+ return trimProjectTail(m ? m[1] : base);
237
+ }
238
+ /**
239
+ * When two normalized project names belong to the same work group, return the
240
+ * shared group key (the common stem); otherwise null. Mirrors office.cpp
241
+ * `sameProjectGroup`:
242
+ * - exact (case-insensitive) match → group
243
+ * - one extends the other at a delimiter ("foo-bar" + "foo-bar-1") or they
244
+ * diverge after a shared delimiter-aligned stem ("…-broken-a" + "…-broken-b")
245
+ * - conservative: only long multi-token stems fuse (stem ≥ 14 chars with
246
+ * ≥ 2 delimiters on both sides), so short siblings like "agentdeck-ios" /
247
+ * "agentdeck-android" stay separate.
248
+ */
249
+ export function projectGroupKey(a, b) {
250
+ let i = 0;
251
+ let lastDelim = -1;
252
+ const n = Math.min(a.length, b.length);
253
+ while (i < n && a[i].toLowerCase() === b[i].toLowerCase()) {
254
+ if (isProjectDelim(a[i]))
255
+ lastDelim = i;
256
+ i++;
257
+ }
258
+ if (i === a.length && i === b.length)
259
+ return a;
260
+ let stemLen = -1;
261
+ if (i === a.length && i < b.length && isProjectDelim(b[i]))
262
+ stemLen = i;
263
+ else if (i === b.length && i < a.length && isProjectDelim(a[i]))
264
+ stemLen = i;
265
+ else if (lastDelim > 0)
266
+ stemLen = lastDelim;
267
+ if (stemLen < 14 || projectDelimCount(a, stemLen) < 2 || projectDelimCount(b, stemLen) < 2) {
268
+ return null;
269
+ }
270
+ const key = trimProjectTail(a.slice(0, stemLen));
271
+ return key.length > 0 ? key : null;
272
+ }
273
+ /**
274
+ * Cluster an ordered session list into project groups, preserving the input
275
+ * order (first member's position anchors the group; members keep relative
276
+ * order). Greedy pairwise fusion with a growing group key, exactly like the
277
+ * office.cpp huddle builder.
278
+ */
279
+ export function groupSessionsByProject(items, projectOf) {
280
+ const groups = [];
281
+ const done = new Array(items.length).fill(false);
282
+ for (let a = 0; a < items.length; a++) {
283
+ if (done[a])
284
+ continue;
285
+ const na = normalizeProjectForGrouping(projectOf(items[a]));
286
+ let key = na;
287
+ const members = [items[a]];
288
+ done[a] = true;
289
+ for (let b = a + 1; b < items.length; b++) {
290
+ if (done[b])
291
+ continue;
292
+ const nb = normalizeProjectForGrouping(projectOf(items[b]));
293
+ const nextKey = projectGroupKey(key, nb) ?? projectGroupKey(na, nb);
294
+ if (nextKey) {
295
+ key = nextKey;
296
+ members.push(items[b]);
297
+ done[b] = true;
298
+ }
299
+ }
300
+ groups.push({ key, grouped: members.length > 1, members });
301
+ }
302
+ return groups;
303
+ }
304
+ //# sourceMappingURL=session-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-utils.js","sourceRoot":"","sources":["../src/session-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,4BAA4B;AAE5B;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAyB;IACjD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC;QAC5B,KAAK,qBAAqB,CAAC;QAC3B,KAAK,iBAAiB,CAAC;QACvB,KAAK,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC;QAC/B,KAAK,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;QACtB,KAAK,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAMD,MAAM,UAAU,WAAW,CAAC,KAAyB;IACnD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,qBAAqB,CAAC;QAC3B,KAAK,iBAAiB,CAAC;QACvB,KAAK,eAAe;YAClB,OAAO,WAAW,CAAC;QACrB,KAAK,YAAY;YACf,OAAO,QAAQ,CAAC;QAClB;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC;AAED,iEAAiE;AAEjE;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,SAA6B;IACzD,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC;QAC1B,KAAK,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC;QAC7B,KAAK,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC;QAC3B,KAAK,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC;QAC3B,KAAK,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC;QAC1B,KAAK,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAqB,EAAE,CAAqB;IAC9E,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;AAC7F,CAAC;AAaD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAA6B;IACnE,OAAO,KAAK,CAAC,gBAAgB,KAAK,IAAI,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAmC,QAAsB;IACzF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC;AACxD,CAAC;AAED,sBAAsB;AAEtB;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAA0G,QAAa;IACjJ,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjC,2DAA2D;QAC3D,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACzE,IAAI,QAAQ,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC;QAEpC,qEAAqE;QACrE,qEAAqE;QACrE,sEAAsE;QACtE,uDAAuD;QACvD,MAAM,WAAW,GAAG,mBAAmB,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;QACtE,IAAI,WAAW,KAAK,CAAC;YAAE,OAAO,WAAW,CAAC;QAE1C,2DAA2D;QAC3D,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;YAC/E,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC9B,CAAC;QAED,oCAAoC;QACpC,OAAO,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC;AAeD;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAA4B,QAAa;IAClF,MAAM,WAAW,GAAQ,EAAE,CAAC;IAC5B,MAAM,cAAc,GAAG,IAAI,GAAG,EAAe,CAAC;IAE9C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACzC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;;YAC1B,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5C,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,cAAc,CAAC,OAAwB;IAC9C,OAAO,OAAO,CAAC,SAAS,KAAK,WAAW,IAAI,OAAO,CAAC,SAAS,KAAK,WAAW,IAAI,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACnH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAwB;IAChD,OAAO,OAAO,CAAC,SAAS,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;AACvE,CAAC;AAED,SAAS,qBAAqB,CAA4B,KAAU;IAClE,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,QAAQ,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC;QAEpC,MAAM,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAC1F,MAAM,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAC1F,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO,QAAQ,GAAG,QAAQ,CAAC;QAEtD,OAAO,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5E,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,CAAC;IAErG,MAAM,MAAM,GAAG;QACb,GAAG,cAAc;QACjB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QACtB,SAAS;QACT,gBAAgB,EAAE,SAAS;KACvB,CAAC;IACP,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,WAAW,GAAG,WAAW,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,OAAO,MAAM,CAAC,WAAW,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAaD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAa;IAEb,0DAA0D;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,4BAA4B;IAC5B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACtB,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAClC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAChB,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC3E,OAAO;YACL,OAAO,EAAE,CAAC;YACV,WAAW;YACX,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;SAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iEAAiE;AACjE,EAAE;AACF,yEAAyE;AACzE,uEAAuE;AACvE,8EAA8E;AAC9E,2EAA2E;AAC3E,6EAA6E;AAC7E,uEAAuE;AACvE,gFAAgF;AAEhF,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC;AAC1D,CAAC;AAED,SAAS,eAAe,CAAC,CAAS;IAChC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;QAAE,CAAC,EAAE,CAAC;IACpE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAS,EAAE,GAAW;IAC/C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,EAAE,CAAC;IAChF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAA2B;IACrE,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC;IACzD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACvC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,CAAS;IAClD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;IACnB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC1D,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,SAAS,GAAG,CAAC,CAAC;QACxC,CAAC,EAAE,CAAC;IACN,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IAE/C,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;IACjB,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC,CAAC;SACnE,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC,CAAC;SACxE,IAAI,SAAS,GAAG,CAAC;QAAE,OAAO,GAAG,SAAS,CAAC;IAE5C,IAAI,OAAO,GAAG,EAAE,IAAI,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3F,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAUD;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAmB,EACnB,SAA0C;IAE1C,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,CAAC,CAAC;YAAE,SAAS;QACtB,MAAM,EAAE,GAAG,2BAA2B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,IAAI,IAAI,CAAC,CAAC,CAAC;gBAAE,SAAS;YACtB,MAAM,EAAE,GAAG,2BAA2B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACpE,IAAI,OAAO,EAAE,CAAC;gBACZ,GAAG,GAAG,OAAO,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YACjB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}