@nimbalyst/extension-sdk 0.5.0 → 0.7.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 (51) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1 -1
  4. package/dist/__tests__/buildEmitStability.test.js +1 -1
  5. package/dist/__tests__/fileDirectoryTree.test.js +34 -0
  6. package/dist/__tests__/gitOperationLog.test.d.ts +2 -0
  7. package/dist/__tests__/gitOperationLog.test.d.ts.map +1 -0
  8. package/dist/__tests__/gitOperationLog.test.js +51 -0
  9. package/dist/agents/AgentProtocol.d.ts +16 -1
  10. package/dist/agents/AgentProtocol.d.ts.map +1 -1
  11. package/dist/agents/AgentProtocolHost.d.ts +1 -1
  12. package/dist/agents/AgentProtocolHost.d.ts.map +1 -1
  13. package/dist/createReadOnlyHost.d.ts +11 -1
  14. package/dist/createReadOnlyHost.d.ts.map +1 -1
  15. package/dist/createReadOnlyHost.js +3 -0
  16. package/dist/externalsPlugin.d.ts.map +1 -1
  17. package/dist/externalsPlugin.js +1 -5
  18. package/dist/fileDirectoryTree.d.ts +9 -2
  19. package/dist/fileDirectoryTree.d.ts.map +1 -1
  20. package/dist/fileDirectoryTree.js +82 -14
  21. package/dist/gitOperationLog.d.ts +104 -0
  22. package/dist/gitOperationLog.d.ts.map +1 -0
  23. package/dist/gitOperationLog.js +88 -0
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -0
  27. package/dist/manifestValidation.d.ts.map +1 -1
  28. package/dist/manifestValidation.js +1 -0
  29. package/dist/types/backendPanels.d.ts +27 -0
  30. package/dist/types/backendPanels.d.ts.map +1 -0
  31. package/dist/types/backendPanels.js +12 -0
  32. package/dist/types/backendSessions.d.ts +262 -0
  33. package/dist/types/backendSessions.d.ts.map +1 -0
  34. package/dist/types/backendSessions.js +21 -0
  35. package/dist/types/collab.d.ts +31 -2
  36. package/dist/types/collab.d.ts.map +1 -1
  37. package/dist/types/comments.d.ts +104 -0
  38. package/dist/types/comments.d.ts.map +1 -0
  39. package/dist/types/comments.js +2 -0
  40. package/dist/types/editor.d.ts +87 -0
  41. package/dist/types/editor.d.ts.map +1 -1
  42. package/dist/types/extension.d.ts +16 -0
  43. package/dist/types/extension.d.ts.map +1 -1
  44. package/dist/types/index.d.ts +3 -0
  45. package/dist/types/index.d.ts.map +1 -1
  46. package/dist/types/index.js +3 -0
  47. package/dist/types/panel.d.ts +112 -0
  48. package/dist/types/panel.d.ts.map +1 -1
  49. package/dist/types/permissions.d.ts +1 -1
  50. package/dist/types/permissions.d.ts.map +1 -1
  51. package/package.json +23 -12
package/CHANGELOG.md CHANGED
@@ -8,6 +8,8 @@ The SDK is versioned independently of the Nimbalyst app. Each release declares i
8
8
 
9
9
  | SDK version | Minimum Nimbalyst app version |
10
10
  | --- | --- |
11
+ | 0.7.0 | 0.79.0 |
12
+ | 0.6.0 | 0.78.0 |
11
13
  | 0.5.0 | 0.70.0 |
12
14
  | 0.4.0 | 0.70.0 |
13
15
  | 0.3.0 | 0.70.0 |
@@ -19,6 +21,45 @@ The SDK is versioned independently of the Nimbalyst app. Each release declares i
19
21
 
20
22
  ## [Unreleased]
21
23
 
24
+ ## [0.7.0] - 2026-10-09
25
+
26
+ Requires Nimbalyst 0.79.0.
27
+
28
+ ### Added
29
+
30
+ - `BackendSessionsService` lets an extension backend create and own agent sessions and workstreams, send prompts, read status, results and usage, notify the user, and react when a session settles; it needs the new `ai-sessions` permission.
31
+ - Backend extensions can define MCP tools (`BackendMcpToolDefinition`), and panels call them with `PanelHost.callBackendTool()`.
32
+ - `PanelHost.setGutterBadge()` and `BackendPanelsService` show a count or warning badge on a panel's gutter icon.
33
+ - `PanelHost.setPanes()` and `onPaneToggle()` give a panel resizable, hideable left and right panes like the built-in modes, and `PanelHostComponents` exposes the host's session transcript.
34
+ - Agent usage events can report `cache_read_input_tokens` and `cache_creation_input_tokens` separately from uncached input.
35
+
36
+ ### Changed
37
+
38
+ - The `yjs` peer dependency is pinned to 13.6.32, the version the app ships, so an extension cannot load a second copy.
39
+
40
+ ## [0.6.0] - 2026-09-14
41
+
42
+ Requires Nimbalyst 0.78.0, available on the alpha channel at publication, for the complete host API including native screenshots.
43
+
44
+ ### Added
45
+
46
+ - `CollaborationCommentsService`, `CommentAnchor`, and codec-level `commentAnchors` let collaborative editors mount the platform comment experience and resolve structured anchors both live and headlessly.
47
+ - `host.registerViewport()` and `EditorViewport` let an editor expose proportional scroll position to hosts that carry the reader's place between related documents; `createReadOnlyHost()` can receive those registrations.
48
+ - `contributions.customEditors[].collaboration.documentType` lets a host identify a collaborative document type from the manifest before its extension bundle and codec are loaded.
49
+ - `screenshotService` exposes host-provided element and file screenshots, including unopened documents.
50
+ - `PanelHost.getWorkspaceFolders()` and `getPrimaryFolderPath()` expose multiple workspace roots; file-tree helpers accept those roots.
51
+ - `EditorHost.getAssetUrl()` and the `assetUrls` capability let media editors stream local files through a host-provided URL.
52
+ - The `agents`, `types/editor`, and `git-operation-log` entry points expose agent contracts, editor types, and Git operation selectors.
53
+ - `ProtocolSession.appliedModel` and `deliveredMcpServerCount` report the model and MCP servers actually used by an agent.
54
+
55
+ ### Changed
56
+
57
+ - `CollabCodec` documents file-form fallback for headless agent edits when no structured patch pair exists, while recommending structured edits for minimal concurrent deltas.
58
+
59
+ ### Fixed
60
+
61
+ - Agent host declarations use a Node-compatible relative import for consumers using Node16 or NodeNext module resolution.
62
+
22
63
  ## [0.5.0]
23
64
 
24
65
  Still runs on Nimbalyst 0.70.0: a host that declares no capabilities is treated as fully capable, so an extension written against this release keeps working on older desktop builds.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Nimbalyst Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -179,5 +179,5 @@ export const aiTools: ExtensionAITool[] = [
179
179
  From the monorepo root:
180
180
 
181
181
  ```bash
182
- npm run extension-sdk:check-public
182
+ pnpm run extension-sdk:check-public
183
183
  ```
@@ -28,6 +28,6 @@ describe('extension-sdk build emit stability', () => {
28
28
  it('keeps a clean build available for publishing', () => {
29
29
  const { scripts } = readJsonc('package.json');
30
30
  expect(scripts['build:clean']).toMatch(/rmSync/);
31
- expect(scripts.prepublishOnly).toBe('npm run build:clean');
31
+ expect(scripts.prepublishOnly).toBe('pnpm run build:clean');
32
32
  });
33
33
  });
@@ -56,4 +56,38 @@ describe('buildFileDirectoryTree', () => {
56
56
  expect(tree.fileCount).toBe(1);
57
57
  expect(tree.files).toHaveLength(1);
58
58
  });
59
+ describe('multi-root workspaces', () => {
60
+ const ROOTS = ['/repo', '/other/collab'];
61
+ it('leaves primary-root paths bare and names the attached root', () => {
62
+ expect(getWorkspaceRelativeFilePath('/repo/src/index.ts', ROOTS)).toBe('src/index.ts');
63
+ expect(getWorkspaceRelativeFilePath('/other/collab/src/index.ts', ROOTS))
64
+ .toBe('collab/src/index.ts');
65
+ });
66
+ it('keeps same-named files in different roots in separate groups', () => {
67
+ const tree = buildTree(['/repo/src/index.ts', '/other/collab/src/index.ts'], ROOTS);
68
+ // `collab/src` is the collapsed single-child chain; the point is that the
69
+ // two `src` directories do not merge into one group.
70
+ expect(getFileDirectoryPaths(tree)).toEqual(['src', 'collab/src']);
71
+ expect(tree.subdirectories.get('src')?.fileCount).toBe(1);
72
+ expect(tree.subdirectories.get('collab')?.fileCount).toBe(1);
73
+ });
74
+ it('prefers the deepest root for a root nested inside another root', () => {
75
+ expect(getWorkspaceRelativeFilePath('/repo/vendor/lib/a.ts', ['/repo', '/repo/vendor/lib']))
76
+ .toBe('lib/a.ts');
77
+ });
78
+ it('falls back to the absolute path for a file in no root', () => {
79
+ expect(getWorkspaceRelativeFilePath('/elsewhere/a.ts', ROOTS)).toBe('/elsewhere/a.ts');
80
+ });
81
+ it('disambiguates attached roots that share a basename', () => {
82
+ // `/app/api` and `/infra/api` are an ordinary pair, and a bare basename
83
+ // would collapse both repos into one `api` group in the tree.
84
+ const roots = ['/repo', '/app/api', '/infra/api'];
85
+ expect(getWorkspaceRelativeFilePath('/app/api/src/a.ts', roots)).toBe('app/api/src/a.ts');
86
+ expect(getWorkspaceRelativeFilePath('/infra/api/src/a.ts', roots)).toBe('infra/api/src/a.ts');
87
+ });
88
+ it('matches single-root behaviour when given one root', () => {
89
+ expect(getWorkspaceRelativeFilePath('/repo/src/index.ts', ['/repo']))
90
+ .toBe(getWorkspaceRelativeFilePath('/repo/src/index.ts', '/repo'));
91
+ });
92
+ });
59
93
  });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gitOperationLog.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitOperationLog.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/gitOperationLog.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { mergeGitOperationEntries, normalizeGitOperationEntry, selectLatestRunningGitOperation, selectLatestTerminalGitOperation, selectRunningGitOperations, } from '../gitOperationLog';
3
+ function entry(overrides) {
4
+ return {
5
+ timestamp: 1000,
6
+ updatedAt: 1000,
7
+ command: 'git status',
8
+ executable: 'git',
9
+ args: ['status'],
10
+ cwd: '/repo',
11
+ status: 'running',
12
+ output: '',
13
+ stdout: '',
14
+ stderr: '',
15
+ ...overrides,
16
+ };
17
+ }
18
+ describe('git operation log selectors', () => {
19
+ it('keeps a live terminal event that landed while hydration was in flight', () => {
20
+ // The `git:operation-log:get` response is older than upserts that arrived
21
+ // after it was requested. Applying it blindly rewinds a finished push back
22
+ // to running, which is exactly the stale indicator this ordering prevents.
23
+ const hydrated = [entry({ id: 'a', status: 'running', updatedAt: 1000 })];
24
+ const live = [entry({ id: 'a', status: 'success', updatedAt: 2000 })];
25
+ expect(mergeGitOperationEntries(hydrated, live)[0].status).toBe('success');
26
+ expect(mergeGitOperationEntries(live, hydrated)[0].status).toBe('success');
27
+ });
28
+ it('names the newest running command and counts the rest', () => {
29
+ const entries = [
30
+ entry({ id: 'push', timestamp: 1000, command: 'git push' }),
31
+ entry({ id: 'fetch', timestamp: 3000, command: 'git fetch origin' }),
32
+ entry({ id: 'done', timestamp: 2000, status: 'success', updatedAt: 5000 }),
33
+ ];
34
+ expect(selectLatestRunningGitOperation(entries)?.id).toBe('fetch');
35
+ expect(selectRunningGitOperations(entries).map((e) => e.id)).toEqual(['push', 'fetch']);
36
+ expect(selectLatestTerminalGitOperation(entries)?.id).toBe('done');
37
+ });
38
+ it('reads a journal written before source metadata existed as app-owned direct git', () => {
39
+ const legacy = entry({ id: 'legacy' });
40
+ delete legacy.source;
41
+ delete legacy.executor;
42
+ const normalized = normalizeGitOperationEntry(legacy);
43
+ expect(normalized.source).toBe('nimbalyst');
44
+ expect(normalized.executor).toBe('git');
45
+ });
46
+ it('does not let an agent entry inherit the app-owned default', () => {
47
+ const agent = entry({ id: 'agent', source: 'agent', executor: 'shell', sessionId: 's1' });
48
+ expect(normalizeGitOperationEntry(agent).source).toBe('agent');
49
+ expect(normalizeGitOperationEntry(agent).executor).toBe('shell');
50
+ });
51
+ });
@@ -129,6 +129,14 @@ export interface ProtocolSession {
129
129
  platform: string;
130
130
  /** Platform-specific session data (for internal use) */
131
131
  raw?: RawProtocolSession;
132
+ /** Number of host-supplied MCP servers this protocol actually delivered. */
133
+ deliveredMcpServerCount?: number;
134
+ /**
135
+ * Model the agent is actually running, when the protocol can observe it.
136
+ * Absent means "the protocol has no say"; the host then reports the model it
137
+ * asked for. Never report a requested model a protocol knows was not applied.
138
+ */
139
+ appliedModel?: string;
132
140
  }
133
141
  /**
134
142
  * Event types emitted during message streaming
@@ -157,11 +165,18 @@ export interface ProtocolEvent {
157
165
  };
158
166
  /** Error message (for 'error' events) */
159
167
  error?: string;
160
- /** Token usage (for 'usage' or 'complete' events) */
168
+ /**
169
+ * Token usage (for 'usage' or 'complete' events). When the provider reports a
170
+ * prompt-cache split, `input_tokens` is uncached input only and the cache
171
+ * reads/writes go in their own fields (Anthropic's shape), so the three input
172
+ * counts never overlap. Omit the cache fields when the provider has no split.
173
+ */
161
174
  usage?: {
162
175
  input_tokens: number;
163
176
  output_tokens: number;
164
177
  total_tokens: number;
178
+ cache_read_input_tokens?: number;
179
+ cache_creation_input_tokens?: number;
165
180
  };
166
181
  /** Current context fill tokens for this turn (provider-reported snapshot) */
167
182
  contextFillTokens?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"AgentProtocol.d.ts","sourceRoot":"","sources":["../../src/agents/AgentProtocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AgentProtocol.d.ts","sourceRoot":"","sources":["../../src/agents/AgentProtocol.ts"],"names":[],"mappings":"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"}
@@ -39,7 +39,7 @@
39
39
  * See `docs/EXTENSION_ARCHITECTURE.md` and the Phase 4 SDK design doc
40
40
  * (Section 4.3) for the full host contract.
41
41
  */
42
- import type { MCPServerConfig } from './index';
42
+ import type { MCPServerConfig } from './index.js';
43
43
  /**
44
44
  * Permission posture the host has set for the current turn.
45
45
  *
@@ -1 +1 @@
1
- {"version":3,"file":"AgentProtocolHost.d.ts","sourceRoot":"","sources":["../../src/agents/AgentProtocolHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAGhC,uDAAuD;IACvD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IAExC;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAIjC,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAElC,yDAAyD;IACzD,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IAExC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC;IAEhD;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAI/C;;;;;;;;;;;OAWG;IACH,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,GAAG,QAAQ,EAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;;;OAQG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE3D;;;;;;;OAOG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAErD;;;;OAIG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErE;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D"}
1
+ {"version":3,"file":"AgentProtocolHost.d.ts","sourceRoot":"","sources":["../../src/agents/AgentProtocolHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAGhC,uDAAuD;IACvD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IAExC;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAIjC,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAElC,yDAAyD;IACzD,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IAExC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC;IAEhD;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAI/C;;;;;;;;;;;OAWG;IACH,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,GAAG,QAAQ,EAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;;;OAQG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE3D;;;;;;;OAOG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAErD;;;;OAIG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErE;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D"}
@@ -21,7 +21,7 @@
21
21
  * host.setTheme('light');
22
22
  * ```
23
23
  */
24
- import type { EditorHost } from './types/editor.js';
24
+ import type { EditorHost, EditorViewport } from './types/editor.js';
25
25
  export interface ReadOnlyHostOptions {
26
26
  /** Current theme name (e.g., 'dark', 'light') */
27
27
  theme: string;
@@ -34,6 +34,16 @@ export interface ReadOnlyHostOptions {
34
34
  * When true, extensions may suppress chrome that doesn't fit inline contexts.
35
35
  */
36
36
  embedded?: boolean;
37
+ /**
38
+ * Receives the editor's scroll viewport when it publishes one.
39
+ *
40
+ * Supplied only by a surface that shows several documents in sequence and
41
+ * wants to carry the reader's place between them -- the feedback detail
42
+ * popover comparing design alternatives. Absent, `registerViewport` is
43
+ * absent too, so an extension that checks before registering gets a straight
44
+ * answer rather than a silent no-op.
45
+ */
46
+ onViewportRegistered?(viewport: EditorViewport | null): void;
37
47
  }
38
48
  export interface ReadOnlyHost extends EditorHost {
39
49
  /** Update the theme (call from viewer chrome's theme toggle) */
@@ -1 +1 @@
1
- {"version":3,"file":"createReadOnlyHost.d.ts","sourceRoot":"","sources":["../src/createReadOnlyHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAiC,MAAM,mBAAmB,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IAEd,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IAEjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,GACxB,YAAY,CA8Dd"}
1
+ {"version":3,"file":"createReadOnlyHost.d.ts","sourceRoot":"","sources":["../src/createReadOnlyHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAEV,UAAU,EAEV,cAAc,EACf,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IAEd,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IAEjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;;;;OAQG;IACH,oBAAoB,CAAC,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;CAC9D;AAED,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,GACxB,YAAY,CAiEd"}
@@ -60,6 +60,9 @@ export function createReadOnlyHost(content, opts) {
60
60
  openHistory: () => { },
61
61
  registerMenuItems: (_items) => { },
62
62
  registerEditorAPI: () => { },
63
+ ...(opts.onViewportRegistered
64
+ ? { registerViewport: opts.onViewportRegistered }
65
+ : {}),
63
66
  setEditorContext: (_context) => { },
64
67
  setEditorContextItems: () => { },
65
68
  // -- Storage (in-memory, non-persistent) --
@@ -1 +1 @@
1
- {"version":3,"file":"externalsPlugin.d.ts","sourceRoot":"","sources":["../src/externalsPlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAqDnC;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAyDjD"}
1
+ {"version":3,"file":"externalsPlugin.d.ts","sourceRoot":"","sources":["../src/externalsPlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAoDnC;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAyDjD"}
@@ -45,7 +45,6 @@ const EXTERNALS_MAP = {
45
45
  '@nimbalyst/editor-context': '@nimbalyst/editor-context',
46
46
  '@nimbalyst/runtime/ui/icons/MaterialSymbol': '@nimbalyst/runtime/ui/icons/MaterialSymbol',
47
47
  '@nimbalyst/screenshot-service': '@nimbalyst/screenshot-service',
48
- '@nimbalyst/datamodel-platform-service': '@nimbalyst/datamodel-platform-service',
49
48
  // Shared libraries
50
49
  'pdfjs-dist': 'pdfjs-dist',
51
50
  virtua: 'virtua',
@@ -230,7 +229,7 @@ function generateCommonExports(externalKey) {
230
229
  }
231
230
  else if (externalKey === '@nimbalyst/runtime') {
232
231
  exports = [
233
- 'MaterialSymbol', 'useDocumentPath', 'useEditorLifecycle',
232
+ 'MaterialSymbol', 'useDocumentPath', 'useEditorLifecycle', 'screenshotService',
234
233
  'useCollaborativeEditor', 'COLLAB_INIT_ORIGIN',
235
234
  'setTranscriptMarkdownContributions', 'clearTranscriptMarkdownContributions',
236
235
  'MarkdownEditor', 'MonacoEditor', 'MonacoCodeEditor',
@@ -241,9 +240,6 @@ function generateCommonExports(externalKey) {
241
240
  else if (externalKey === '@nimbalyst/screenshot-service') {
242
241
  exports = ['screenshotService'];
243
242
  }
244
- else if (externalKey === '@nimbalyst/datamodel-platform-service') {
245
- exports = ['DataModelPlatformServiceImpl', 'getInstance'];
246
- }
247
243
  else if (externalKey === 'pdfjs-dist') {
248
244
  exports = ['getDocument', 'GlobalWorkerOptions', 'version'];
249
245
  }
@@ -11,9 +11,16 @@ export declare function getFilePathBasename(filePath: string): string;
11
11
  /**
12
12
  * Return a forward-slash path relative to the workspace when the file is inside it.
13
13
  * Windows drive paths are compared case-insensitively to match filesystem behavior.
14
+ *
15
+ * A multi-root workspace passes every root, primary first. The primary root
16
+ * still yields a bare relative path, so a single-folder workspace is unchanged;
17
+ * a file in an attached root is prefixed with that root's heading, which is
18
+ * what groups it under its own heading in the directory tree instead of
19
+ * spelling out an absolute path. Deepest matching root wins, so a root checked
20
+ * out inside another root keeps its own prefix.
14
21
  */
15
- export declare function getWorkspaceRelativeFilePath(filePath: string, workspacePath?: string): string;
22
+ export declare function getWorkspaceRelativeFilePath(filePath: string, workspacePath?: string | string[]): string;
16
23
  /** Build a collapsed directory tree for arbitrary file records. */
17
- export declare function buildFileDirectoryTree<T>(files: T[], getFilePath: (file: T) => string, workspacePath?: string): FileDirectoryNode<T>;
24
+ export declare function buildFileDirectoryTree<T>(files: T[], getFilePath: (file: T) => string, workspacePath?: string | string[]): FileDirectoryNode<T>;
18
25
  export declare function getFileDirectoryPaths<T>(node: FileDirectoryNode<T>): string[];
19
26
  //# sourceMappingURL=fileDirectoryTree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fileDirectoryTree.d.ts","sourceRoot":"","sources":["../src/fileDirectoryTree.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAkB7F;AA6BD,mEAAmE;AACnE,wBAAgB,sBAAsB,CAAC,CAAC,EACtC,KAAK,EAAE,CAAC,EAAE,EACV,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAChC,aAAa,CAAC,EAAE,MAAM,GACrB,iBAAiB,CAAC,CAAC,CAAC,CAwCtB;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAM7E"}
1
+ {"version":3,"file":"fileDirectoryTree.d.ts","sourceRoot":"","sources":["../src/fileDirectoryTree.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG5D;AAwDD;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAChC,MAAM,CAwBR;AA6BD,mEAAmE;AACnE,wBAAgB,sBAAsB,CAAC,CAAC,EACtC,KAAK,EAAE,CAAC,EAAE,EACV,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAChC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAChC,iBAAiB,CAAC,CAAC,CAAC,CAwCtB;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAM7E"}
@@ -6,27 +6,95 @@ export function getFilePathBasename(filePath) {
6
6
  const normalizedPath = normalizeFilePath(filePath).replace(/\/+$/, '');
7
7
  return normalizedPath.slice(normalizedPath.lastIndexOf('/') + 1);
8
8
  }
9
+ /** Relative to one root, or null when the file is not inside it. */
10
+ function relativeToRoot(normalizedFile, rootPath) {
11
+ const normalizedRoot = normalizeFilePath(rootPath).replace(/\/$/, '');
12
+ if (!normalizedRoot)
13
+ return null;
14
+ const windowsDrivePath = /^[A-Za-z]:\//.test(normalizedFile)
15
+ && /^[A-Za-z]:\//.test(normalizedRoot);
16
+ const comparableFile = windowsDrivePath ? normalizedFile.toLowerCase() : normalizedFile;
17
+ const comparableRoot = windowsDrivePath ? normalizedRoot.toLowerCase() : normalizedRoot;
18
+ if (comparableFile === comparableRoot)
19
+ return '';
20
+ if (comparableFile.startsWith(`${comparableRoot}/`)) {
21
+ return normalizedFile.slice(normalizedRoot.length + 1);
22
+ }
23
+ return null;
24
+ }
25
+ /**
26
+ * Heading for each attached root, unique within the root list.
27
+ *
28
+ * Two roots sharing a basename is ordinary -- `app/api` and `infra/api`, or two
29
+ * checkouts of the same repo -- and a bare basename would collapse both into
30
+ * one directory group. Colliding roots grow parent segments until they differ;
31
+ * everything else stays the bare folder name. The primary root has no heading,
32
+ * so it never competes.
33
+ */
34
+ function attachedRootLabels(roots) {
35
+ const segmentsPerRoot = roots.map((rootPath) => normalizeFilePath(rootPath).replace(/\/+$/, '').split('/').filter(Boolean));
36
+ const labels = roots.map((_, index) => segmentsPerRoot[index].slice(-1).join('/'));
37
+ // Grow every still-colliding label by one more parent segment per pass. A
38
+ // root can only run out of segments once it is the filesystem root, at which
39
+ // point its label is already unique.
40
+ for (let depth = 2; depth <= 16; depth++) {
41
+ const counts = new Map();
42
+ for (let index = 1; index < labels.length; index++) {
43
+ counts.set(labels[index], (counts.get(labels[index]) ?? 0) + 1);
44
+ }
45
+ if ([...counts.values()].every((count) => count < 2))
46
+ break;
47
+ let grew = false;
48
+ for (let index = 1; index < labels.length; index++) {
49
+ if ((counts.get(labels[index]) ?? 0) < 2)
50
+ continue;
51
+ if (segmentsPerRoot[index].length < depth)
52
+ continue;
53
+ labels[index] = segmentsPerRoot[index].slice(-depth).join('/');
54
+ grew = true;
55
+ }
56
+ if (!grew)
57
+ break;
58
+ }
59
+ return labels;
60
+ }
9
61
  /**
10
62
  * Return a forward-slash path relative to the workspace when the file is inside it.
11
63
  * Windows drive paths are compared case-insensitively to match filesystem behavior.
64
+ *
65
+ * A multi-root workspace passes every root, primary first. The primary root
66
+ * still yields a bare relative path, so a single-folder workspace is unchanged;
67
+ * a file in an attached root is prefixed with that root's heading, which is
68
+ * what groups it under its own heading in the directory tree instead of
69
+ * spelling out an absolute path. Deepest matching root wins, so a root checked
70
+ * out inside another root keeps its own prefix.
12
71
  */
13
72
  export function getWorkspaceRelativeFilePath(filePath, workspacePath) {
14
73
  const normalizedFile = normalizeFilePath(filePath);
15
- if (!workspacePath)
74
+ const roots = typeof workspacePath === 'string' ? [workspacePath] : workspacePath;
75
+ if (!roots || roots.length === 0)
16
76
  return normalizedFile;
17
- const normalizedWorkspace = normalizeFilePath(workspacePath).replace(/\/$/, '');
18
- const windowsDrivePath = /^[A-Za-z]:\//.test(normalizedFile)
19
- && /^[A-Za-z]:\//.test(normalizedWorkspace);
20
- const comparableFile = windowsDrivePath ? normalizedFile.toLowerCase() : normalizedFile;
21
- const comparableWorkspace = windowsDrivePath
22
- ? normalizedWorkspace.toLowerCase()
23
- : normalizedWorkspace;
24
- if (comparableFile === comparableWorkspace)
25
- return '';
26
- if (comparableFile.startsWith(`${comparableWorkspace}/`)) {
27
- return normalizedFile.slice(normalizedWorkspace.length + 1);
28
- }
29
- return normalizedFile;
77
+ let bestIndex = -1;
78
+ let bestRelative = null;
79
+ let bestRootLength = -1;
80
+ roots.forEach((rootPath, index) => {
81
+ const relative = relativeToRoot(normalizedFile, rootPath);
82
+ if (relative === null)
83
+ return;
84
+ const rootLength = normalizeFilePath(rootPath).replace(/\/$/, '').length;
85
+ if (rootLength <= bestRootLength)
86
+ return;
87
+ bestIndex = index;
88
+ bestRelative = relative;
89
+ bestRootLength = rootLength;
90
+ });
91
+ if (bestRelative === null)
92
+ return normalizedFile;
93
+ if (bestIndex === 0)
94
+ return bestRelative;
95
+ // Attached root: name it, so two files called `src/index.ts` in two repos do
96
+ // not collapse into one directory group.
97
+ return `${attachedRootLabels(roots)[bestIndex]}/${bestRelative}`;
30
98
  }
31
99
  function collapseDirectoryTree(node) {
32
100
  node.subdirectories.forEach((subdirectory, key) => {
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Wire contract and pure selectors for the host's Git operation journal.
3
+ *
4
+ * The journal lives in the Electron main process and is published over two host
5
+ * channels: `git:operation-log:get` (hydration) and `git:operation-log-changed`
6
+ * (live upsert/clear). Both the Git extension's Output tab and Nimbalyst's own
7
+ * menu-bar indicator project the same journal, so the merge and "what is running
8
+ * right now" rules have to agree exactly -- two surfaces disagreeing about
9
+ * whether a push is still in flight is the bug this module exists to prevent.
10
+ *
11
+ * Everything here is pure: no React, no IPC, no host runtime.
12
+ */
13
+ /** Terminal states are everything except `running`. */
14
+ export type GitOperationStatus = 'running' | 'success' | 'error' | 'interrupted';
15
+ /** Who started the command. Absent on journals written before agent activity existed. */
16
+ export type GitOperationSource = 'nimbalyst' | 'agent';
17
+ /**
18
+ * How the command reached Git. `git` is an app-owned direct invocation with a
19
+ * meaningful `args` array; `shell` is an observed command line whose Git segment
20
+ * we detected but did not spawn ourselves.
21
+ */
22
+ export type GitOperationExecutor = 'git' | 'shell';
23
+ /** An entry exactly as it crosses the IPC boundary (timestamps are epoch ms). */
24
+ export interface GitOperationLogWireEntry {
25
+ id: string;
26
+ timestamp: number;
27
+ updatedAt: number;
28
+ /** Redacted, display-ready command text. */
29
+ command: string;
30
+ executable: 'git';
31
+ args: string[];
32
+ cwd: string;
33
+ status: GitOperationStatus;
34
+ output: string;
35
+ stdout: string;
36
+ stderr: string;
37
+ error?: string;
38
+ exitCode?: number;
39
+ durationMs?: number;
40
+ source?: GitOperationSource;
41
+ executor?: GitOperationExecutor;
42
+ sessionId?: string;
43
+ provider?: string;
44
+ providerToolCallId?: string;
45
+ }
46
+ export type GitOperationLogEvent = {
47
+ workspacePath: string;
48
+ type: 'upsert';
49
+ entry: GitOperationLogWireEntry;
50
+ } | {
51
+ workspacePath: string;
52
+ type: 'clear';
53
+ };
54
+ /**
55
+ * Window CustomEvent the host dispatches when the user asks to see Git activity
56
+ * detail (for example from the menu-bar indicator's running-command row).
57
+ *
58
+ * The Git panel owns which tab is showing, and that state is private to the
59
+ * extension bundle. Rather than let the host reach into it, the host states the
60
+ * intent and the panel decides how to honour it. `detail.workspacePath` lets a
61
+ * panel bound to a different workspace ignore the request.
62
+ */
63
+ export declare const GIT_SHOW_OUTPUT_REQUEST_EVENT = "nimbalyst:git-show-output";
64
+ export interface GitShowOutputRequestDetail {
65
+ workspacePath: string;
66
+ }
67
+ /** The minimum shape the selectors below need. */
68
+ interface MergeableEntry {
69
+ id: string;
70
+ timestamp: number | Date;
71
+ updatedAt: number;
72
+ status: GitOperationStatus;
73
+ }
74
+ /**
75
+ * Fill in metadata that predates the field. A journal written before agent
76
+ * activity existed only ever recorded app-owned direct `git` invocations, so
77
+ * that is what an absent `source`/`executor` means -- resolved here at the
78
+ * projection boundary rather than by rewriting the persisted journal.
79
+ */
80
+ export declare function normalizeGitOperationEntry(entry: GitOperationLogWireEntry): GitOperationLogWireEntry & {
81
+ source: GitOperationSource;
82
+ executor: GitOperationExecutor;
83
+ };
84
+ /**
85
+ * Fold incoming entries into the current list, newest write per id wins.
86
+ *
87
+ * `updatedAt` is the tiebreak rather than arrival order because hydration and
88
+ * the live subscription race: a `git:operation-log:get` response can land after
89
+ * upserts it predates, and applying it blindly would rewind a finished
90
+ * operation back to `running`.
91
+ */
92
+ export declare function mergeGitOperationEntries<T extends MergeableEntry>(current: T[], incoming: T[]): T[];
93
+ /** Every entry still in flight, oldest first. */
94
+ export declare function selectRunningGitOperations<T extends MergeableEntry>(entries: T[]): T[];
95
+ /**
96
+ * The entry a single-line indicator should name. Newest start wins: when an
97
+ * agent kicks off a fetch while a push is already running, the thing the user
98
+ * just caused is the more informative label.
99
+ */
100
+ export declare function selectLatestRunningGitOperation<T extends MergeableEntry>(entries: T[]): T | undefined;
101
+ /** The most recently updated entry that has already settled, if any. */
102
+ export declare function selectLatestTerminalGitOperation<T extends MergeableEntry>(entries: T[]): T | undefined;
103
+ export {};
104
+ //# sourceMappingURL=gitOperationLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitOperationLog.d.ts","sourceRoot":"","sources":["../src/gitOperationLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,uDAAuD;AACvD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEjF,yFAAyF;AACzF,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,OAAO,CAAC;AAEvD;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,OAAO,CAAC;AAEnD,iFAAiF;AACjF,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,KAAK,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC1E;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7C;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,8BAA8B,CAAC;AAEzE,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,kDAAkD;AAClD,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAMD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,wBAAwB,GAC9B,wBAAwB,GAAG;IAC5B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,oBAAoB,CAAC;CAChC,CAMA;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,cAAc,EAC/D,OAAO,EAAE,CAAC,EAAE,EACZ,QAAQ,EAAE,CAAC,EAAE,GACZ,CAAC,EAAE,CAWL;AAED,iDAAiD;AACjD,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,cAAc,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAEtF;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,CAAC,SAAS,cAAc,EACtE,OAAO,EAAE,CAAC,EAAE,GACX,CAAC,GAAG,SAAS,CASf;AAED,wEAAwE;AACxE,wBAAgB,gCAAgC,CAAC,CAAC,SAAS,cAAc,EACvE,OAAO,EAAE,CAAC,EAAE,GACX,CAAC,GAAG,SAAS,CASf"}