@nimbalyst/extension-sdk 0.3.0 → 0.5.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.
- package/CHANGELOG.md +24 -0
- package/dist/__tests__/buildEmitStability.test.d.ts +2 -0
- package/dist/__tests__/buildEmitStability.test.d.ts.map +1 -0
- package/dist/__tests__/buildEmitStability.test.js +33 -0
- package/dist/__tests__/createTextCollabContentAdapter.test.js +1 -0
- package/dist/__tests__/editorHostCapabilities.test.d.ts +2 -0
- package/dist/__tests__/editorHostCapabilities.test.d.ts.map +1 -0
- package/dist/__tests__/editorHostCapabilities.test.js +24 -0
- package/dist/__tests__/fileDirectoryTree.test.js +1 -0
- package/dist/__tests__/fileMask.test.d.ts +2 -0
- package/dist/__tests__/fileMask.test.d.ts.map +1 -0
- package/dist/__tests__/fileMask.test.js +33 -0
- package/dist/__tests__/manifestValidation.agentProviders.test.js +1 -0
- package/dist/__tests__/textReplacement.test.d.ts +2 -0
- package/dist/__tests__/textReplacement.test.d.ts.map +1 -0
- package/dist/__tests__/textReplacement.test.js +31 -0
- package/dist/__tests__/useCollaborativeEditor.offline.test.d.ts +2 -0
- package/dist/__tests__/useCollaborativeEditor.offline.test.d.ts.map +1 -0
- package/dist/__tests__/useCollaborativeEditor.offline.test.js +76 -0
- package/dist/__tests__/useEditorLifecycle.test.d.ts +2 -0
- package/dist/__tests__/useEditorLifecycle.test.d.ts.map +1 -0
- package/dist/__tests__/useEditorLifecycle.test.js +60 -0
- package/dist/agents/AgentProtocol.d.ts +12 -0
- package/dist/agents/AgentProtocol.d.ts.map +1 -1
- package/dist/collab/index.d.ts +14 -0
- package/dist/collab/index.d.ts.map +1 -0
- package/dist/collab/index.js +13 -0
- package/dist/collab/origins.d.ts +15 -0
- package/dist/collab/origins.d.ts.map +1 -0
- package/dist/collab/origins.js +14 -0
- package/dist/collab/textReplacement.d.ts +7 -0
- package/dist/collab/textReplacement.d.ts.map +1 -0
- package/dist/collab/textReplacement.js +27 -0
- package/dist/editorHostCapabilities.d.ts +31 -0
- package/dist/editorHostCapabilities.d.ts.map +1 -0
- package/dist/editorHostCapabilities.js +35 -0
- package/dist/electronMain.d.ts +12 -0
- package/dist/electronMain.d.ts.map +1 -0
- package/dist/electronMain.js +11 -0
- package/dist/fileMask.d.ts +17 -0
- package/dist/fileMask.d.ts.map +1 -0
- package/dist/fileMask.js +45 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/types/editor.d.ts +126 -2
- package/dist/types/editor.d.ts.map +1 -1
- package/dist/types/extension.d.ts +50 -5
- package/dist/types/extension.d.ts.map +1 -1
- package/dist/types/panel.d.ts +43 -0
- package/dist/types/panel.d.ts.map +1 -1
- package/dist/useCollaborativeEditor.d.ts +22 -29
- package/dist/useCollaborativeEditor.d.ts.map +1 -1
- package/dist/useCollaborativeEditor.js +105 -95
- package/dist/useEditorLifecycle.d.ts.map +1 -1
- package/dist/useEditorLifecycle.js +2 -0
- package/package.json +12 -3
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.5.0 | 0.70.0 |
|
|
12
|
+
| 0.4.0 | 0.70.0 |
|
|
11
13
|
| 0.3.0 | 0.70.0 |
|
|
12
14
|
| 0.2.2 | 0.58.5 |
|
|
13
15
|
| 0.2.1 | 0.58.5 |
|
|
@@ -17,6 +19,28 @@ The SDK is versioned independently of the Nimbalyst app. Each release declares i
|
|
|
17
19
|
|
|
18
20
|
## [Unreleased]
|
|
19
21
|
|
|
22
|
+
## [0.5.0]
|
|
23
|
+
|
|
24
|
+
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.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `host.capabilities` plus `editorHostSupports()` and `editorHostCapabilityGap()` let one editor bundle run in hosts that cannot honour every part of `EditorHost` — check a capability before calling instead of discovering the gap at runtime.
|
|
29
|
+
- `AiAgentProviderContribution` declares `supportsSlashCommands`, `supportsSkills`, and `compaction` instead of having the app infer them; all three default to off, so an unclaimed affordance is hidden rather than offered and silently broken.
|
|
30
|
+
- `AgentProtocol.compactSession()` is the optional real compaction entry point for a transport that has one.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- `host.filePath` is documented as an opaque document identifier — an absolute path on the desktop host, a synthetic URI on a host with no filesystem. Gate anything that touches disk on the `localFileSave` / `projectFileSystem` capabilities.
|
|
35
|
+
|
|
36
|
+
## [0.4.0]
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- `applyTextDiff()` and `replaceYText()` reduce a whole-string replacement to one contiguous `Y.Text` edit, so a binding no longer has to hand-write the prefix/suffix diff.
|
|
41
|
+
- `@nimbalyst/extension-sdk/collab` is a React-free entry point for the collaborative-document helpers, for codecs and codec tests that have no React installed.
|
|
42
|
+
- `host.onFindRequested()` routes the app's Find command (Cmd+F) to a custom editor's own find UI.
|
|
43
|
+
|
|
20
44
|
## [0.3.0]
|
|
21
45
|
|
|
22
46
|
Requires Nimbalyst 0.70.0 for the new host-provided selection, filesystem, and visibility APIs.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildEmitStability.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/buildEmitStability.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* The renderer resolves `@nimbalyst/extension-sdk` to `dist/`, so every file the
|
|
6
|
+
* SDK build emits lives in the dev server's module graph. When the build wiped
|
|
7
|
+
* dist and re-emitted all 114 files, the pre-push gate (`typecheck:prepush`,
|
|
8
|
+
* which builds the SDK on every push) made Vite full-reload every open Electron
|
|
9
|
+
* window -- several times an hour across parallel agent sessions, with no SDK
|
|
10
|
+
* source change involved. These assertions keep the emit stable.
|
|
11
|
+
*/
|
|
12
|
+
const sdkRoot = resolve(__dirname, '../..');
|
|
13
|
+
function readJsonc(relativePath) {
|
|
14
|
+
const text = readFileSync(resolve(sdkRoot, relativePath), 'utf8');
|
|
15
|
+
return JSON.parse(text.replace(/^\s*\/\/.*$/gm, ''));
|
|
16
|
+
}
|
|
17
|
+
describe('extension-sdk build emit stability', () => {
|
|
18
|
+
it('does not wipe dist on the default build', () => {
|
|
19
|
+
const { scripts } = readJsonc('package.json');
|
|
20
|
+
expect(scripts.build).toBe('tsc');
|
|
21
|
+
expect(scripts.build).not.toMatch(/rmSync|rm -rf/);
|
|
22
|
+
});
|
|
23
|
+
it('emits incrementally so unchanged sources produce no file writes', () => {
|
|
24
|
+
const { compilerOptions } = readJsonc('tsconfig.json');
|
|
25
|
+
expect(compilerOptions.incremental).toBe(true);
|
|
26
|
+
expect(compilerOptions.tsBuildInfoFile).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
it('keeps a clean build available for publishing', () => {
|
|
29
|
+
const { scripts } = readJsonc('package.json');
|
|
30
|
+
expect(scripts['build:clean']).toMatch(/rmSync/);
|
|
31
|
+
expect(scripts.prepublishOnly).toBe('npm run build:clean');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editorHostCapabilities.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/editorHostCapabilities.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { editorHostCapabilityGap, editorHostSupports, } from '../editorHostCapabilities.js';
|
|
4
|
+
const browserCapabilities = {
|
|
5
|
+
environment: 'browser',
|
|
6
|
+
unavailable: [{ capability: 'localFileSave', reason: 'No file to write.' }],
|
|
7
|
+
supports: (capability) => capability !== 'localFileSave',
|
|
8
|
+
};
|
|
9
|
+
describe('editorHostSupports', () => {
|
|
10
|
+
it('treats a host that makes no claim as fully capable', () => {
|
|
11
|
+
// The Electron renderer predates this contract and implements every
|
|
12
|
+
// member. Answering false there would make every portable extension
|
|
13
|
+
// silently drop features on desktop.
|
|
14
|
+
expect(editorHostSupports({}, 'localFileSave')).toBe(true);
|
|
15
|
+
expect(editorHostCapabilityGap({}, 'localFileSave')).toBeNull();
|
|
16
|
+
});
|
|
17
|
+
it('defers to a host that does declare capabilities', () => {
|
|
18
|
+
const host = { capabilities: browserCapabilities };
|
|
19
|
+
expect(editorHostSupports(host, 'collaboration')).toBe(true);
|
|
20
|
+
expect(editorHostSupports(host, 'localFileSave')).toBe(false);
|
|
21
|
+
expect(editorHostCapabilityGap(host, 'localFileSave')).toBe('No file to write.');
|
|
22
|
+
expect(editorHostCapabilityGap(host, 'collaboration')).toBeNull();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
1
2
|
import { describe, expect, it } from 'vitest';
|
|
2
3
|
import { buildFileDirectoryTree, getFileDirectoryPaths, getFilePathBasename, getWorkspaceRelativeFilePath, } from '../fileDirectoryTree';
|
|
3
4
|
const buildTree = (files, workspacePath) => buildFileDirectoryTree(files.map(filePath => ({ filePath })), file => file.filePath, workspacePath);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileMask.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fileMask.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { parseFileMask, matchesFileMask } from '../fileMask';
|
|
4
|
+
describe('fileMask', () => {
|
|
5
|
+
it('matches a name glob against Windows back-slashed paths', () => {
|
|
6
|
+
// #1196: main returns `path.normalize`d paths, so on Windows the mask sees
|
|
7
|
+
// `C:\...\Ch01.md`. Before the separator normalization only `*.md` matched
|
|
8
|
+
// (the whole path has no `/`), which read as "the mask filters by
|
|
9
|
+
// extension only".
|
|
10
|
+
const winPath = 'C:\\Users\\me\\book\\Ch01.md';
|
|
11
|
+
expect(matchesFileMask(winPath, parseFileMask('Ch0*.md'))).toBe(true);
|
|
12
|
+
expect(matchesFileMask(winPath, parseFileMask('*.md'))).toBe(true);
|
|
13
|
+
expect(matchesFileMask(winPath, parseFileMask('Notes*.md'))).toBe(false);
|
|
14
|
+
expect(matchesFileMask('C:\\Users\\me\\book\\notes.txt', parseFileMask('Ch0*.md'))).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
it('matches names, directory globs and comma-separated lists on posix paths', () => {
|
|
17
|
+
const patterns = parseFileMask('Ch0*.md, *.ts');
|
|
18
|
+
expect(matchesFileMask('/Users/me/book/Ch01.md', patterns)).toBe(true);
|
|
19
|
+
expect(matchesFileMask('/Users/me/book/index.ts', patterns)).toBe(true);
|
|
20
|
+
expect(matchesFileMask('/Users/me/book/index.tsx', patterns)).toBe(false);
|
|
21
|
+
// `*` stops at a separator, `**` crosses them, `?` is a single character.
|
|
22
|
+
expect(matchesFileMask('src/a/b.test.ts', parseFileMask('src/*.test.ts'))).toBe(false);
|
|
23
|
+
expect(matchesFileMask('src/a/b.test.ts', parseFileMask('src/**/*.test.ts'))).toBe(true);
|
|
24
|
+
expect(matchesFileMask('src\\a\\b.test.ts', parseFileMask('src/**/*.test.ts'))).toBe(true);
|
|
25
|
+
expect(matchesFileMask('Ch1.md', parseFileMask('Ch?.md'))).toBe(true);
|
|
26
|
+
expect(matchesFileMask('Ch12.md', parseFileMask('Ch?.md'))).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
it('treats an empty or absent mask as no filter', () => {
|
|
29
|
+
expect(parseFileMask(undefined)).toEqual([]);
|
|
30
|
+
expect(parseFileMask(' , ')).toEqual([]);
|
|
31
|
+
expect(matchesFileMask('anything.bin', [])).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textReplacement.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/textReplacement.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import * as Y from 'yjs';
|
|
4
|
+
import { applyTextDiff, replaceYText } from '../collab/textReplacement';
|
|
5
|
+
describe('text replacement', () => {
|
|
6
|
+
it('reduces whole-string replacements to one range edit', () => {
|
|
7
|
+
const cases = [
|
|
8
|
+
{ name: 'insert-only', previous: 'abcd', next: 'abXcd', edit: [2, 2, 'X'] },
|
|
9
|
+
{ name: 'delete-only', previous: 'abcd', next: 'acd', edit: [1, 2, ''] },
|
|
10
|
+
{ name: 'replace-in-the-middle', previous: 'abcde', next: 'abXYde', edit: [2, 3, 'XY'] },
|
|
11
|
+
{ name: 'identical', previous: 'same', next: 'same', edit: null },
|
|
12
|
+
{ name: 'empty-to-nonempty', previous: '', next: 'new', edit: [0, 0, 'new'] },
|
|
13
|
+
];
|
|
14
|
+
for (const { name, previous, next, edit } of cases) {
|
|
15
|
+
const applyEdit = vi.fn();
|
|
16
|
+
applyTextDiff(previous, next, applyEdit);
|
|
17
|
+
if (edit === null) {
|
|
18
|
+
expect(applyEdit, name).not.toHaveBeenCalled();
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
expect(applyEdit, name).toHaveBeenCalledOnce();
|
|
22
|
+
expect(applyEdit, name).toHaveBeenCalledWith(...edit);
|
|
23
|
+
}
|
|
24
|
+
const yText = new Y.Text(previous);
|
|
25
|
+
const doc = new Y.Doc();
|
|
26
|
+
doc.getMap('root').set('text', yText);
|
|
27
|
+
replaceYText(yText, next);
|
|
28
|
+
expect(yText.toString(), name).toBe(next);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCollaborativeEditor.offline.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/useCollaborativeEditor.offline.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
2
|
+
import { Awareness } from 'y-protocols/awareness';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import * as Y from 'yjs';
|
|
5
|
+
import { useCollaborativeEditor } from '../useCollaborativeEditor.js';
|
|
6
|
+
describe('useCollaborativeEditor offline replica binding', () => {
|
|
7
|
+
it('binds an already-hydrated Y.Doc without waiting for the transport', async () => {
|
|
8
|
+
const yDoc = new Y.Doc();
|
|
9
|
+
yDoc.getMap('nodes').set('node_root', 'persisted');
|
|
10
|
+
const awareness = new Awareness(yDoc);
|
|
11
|
+
const loadInitialContent = vi.fn(async () => 'must not seed offline');
|
|
12
|
+
const bind = vi.fn(() => ({ destroy: vi.fn() }));
|
|
13
|
+
const host = {
|
|
14
|
+
collaboration: {
|
|
15
|
+
yDoc,
|
|
16
|
+
awareness,
|
|
17
|
+
user: { id: 'offline-user', name: 'Offline User', color: '#123456' },
|
|
18
|
+
getStatus: () => 'disconnected',
|
|
19
|
+
onStatusChange: () => () => { },
|
|
20
|
+
loadInitialContent,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const { unmount } = renderHook(() => useCollaborativeEditor(host, {
|
|
24
|
+
isEmpty: doc => doc.getMap('nodes').size === 0,
|
|
25
|
+
initializeFromContent: vi.fn(),
|
|
26
|
+
createBinding: bind,
|
|
27
|
+
}));
|
|
28
|
+
await waitFor(() => expect(bind).toHaveBeenCalledTimes(1));
|
|
29
|
+
expect(loadInitialContent).not.toHaveBeenCalled();
|
|
30
|
+
unmount();
|
|
31
|
+
awareness.destroy();
|
|
32
|
+
yDoc.destroy();
|
|
33
|
+
});
|
|
34
|
+
it('does not start a second binding while the first async bind is unresolved', async () => {
|
|
35
|
+
const yDoc = new Y.Doc();
|
|
36
|
+
yDoc.getMap('nodes').set('node_root', 'persisted');
|
|
37
|
+
const awareness = new Awareness(yDoc);
|
|
38
|
+
let notifyStatusChange = () => { };
|
|
39
|
+
let finishBind = () => { };
|
|
40
|
+
const bindReady = new Promise((resolve) => {
|
|
41
|
+
finishBind = resolve;
|
|
42
|
+
});
|
|
43
|
+
const destroy = vi.fn();
|
|
44
|
+
const bind = vi.fn(async () => {
|
|
45
|
+
await bindReady;
|
|
46
|
+
return { destroy };
|
|
47
|
+
});
|
|
48
|
+
const host = {
|
|
49
|
+
collaboration: {
|
|
50
|
+
yDoc,
|
|
51
|
+
awareness,
|
|
52
|
+
user: { id: 'offline-user', name: 'Offline User', color: '#123456' },
|
|
53
|
+
getStatus: () => 'disconnected',
|
|
54
|
+
onStatusChange: (callback) => {
|
|
55
|
+
notifyStatusChange = callback;
|
|
56
|
+
return () => { };
|
|
57
|
+
},
|
|
58
|
+
loadInitialContent: vi.fn(async () => 'must not seed offline'),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
const { result, unmount } = renderHook(() => useCollaborativeEditor(host, {
|
|
62
|
+
isEmpty: doc => doc.getMap('nodes').size === 0,
|
|
63
|
+
initializeFromContent: vi.fn(),
|
|
64
|
+
createBinding: bind,
|
|
65
|
+
}));
|
|
66
|
+
await waitFor(() => expect(bind).toHaveBeenCalledTimes(1));
|
|
67
|
+
act(() => notifyStatusChange());
|
|
68
|
+
expect(bind).toHaveBeenCalledTimes(1);
|
|
69
|
+
finishBind();
|
|
70
|
+
await waitFor(() => expect(result.current.binding).not.toBeNull());
|
|
71
|
+
unmount();
|
|
72
|
+
expect(destroy).toHaveBeenCalledTimes(1);
|
|
73
|
+
awareness.destroy();
|
|
74
|
+
yDoc.destroy();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEditorLifecycle.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/useEditorLifecycle.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { useEditorLifecycle } from '../useEditorLifecycle.js';
|
|
4
|
+
function createHost(loadContent) {
|
|
5
|
+
let fileChanged;
|
|
6
|
+
const host = {
|
|
7
|
+
filePath: '/workspace/plans/example.mockup.html',
|
|
8
|
+
fileName: 'example.mockup.html',
|
|
9
|
+
isActive: true,
|
|
10
|
+
theme: 'dark',
|
|
11
|
+
loadContent,
|
|
12
|
+
loadBinaryContent: vi.fn(),
|
|
13
|
+
saveContent: vi.fn(),
|
|
14
|
+
setDirty: vi.fn(),
|
|
15
|
+
onSaveRequested: () => () => { },
|
|
16
|
+
onFileChanged: (callback) => {
|
|
17
|
+
fileChanged = callback;
|
|
18
|
+
return () => {
|
|
19
|
+
fileChanged = undefined;
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
onThemeChanged: () => () => { },
|
|
23
|
+
registerMenuItems: vi.fn(),
|
|
24
|
+
registerEditorAPI: vi.fn(),
|
|
25
|
+
setEditorContext: vi.fn(),
|
|
26
|
+
setEditorContextItems: vi.fn(),
|
|
27
|
+
storage: {
|
|
28
|
+
get: vi.fn(),
|
|
29
|
+
set: vi.fn(),
|
|
30
|
+
delete: vi.fn(),
|
|
31
|
+
getGlobal: vi.fn(),
|
|
32
|
+
setGlobal: vi.fn(),
|
|
33
|
+
deleteGlobal: vi.fn(),
|
|
34
|
+
getSecret: vi.fn(),
|
|
35
|
+
setSecret: vi.fn(),
|
|
36
|
+
deleteSecret: vi.fn(),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
host,
|
|
41
|
+
notifyFileChanged(content) {
|
|
42
|
+
fileChanged?.(content);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
describe('useEditorLifecycle', () => {
|
|
47
|
+
it('recovers when a missing file appears after the initial load fails', async () => {
|
|
48
|
+
const applyContent = vi.fn();
|
|
49
|
+
const { host, notifyFileChanged } = createHost(() => Promise.reject(new Error('File not found')));
|
|
50
|
+
const { result } = renderHook(() => useEditorLifecycle(host, { applyContent }));
|
|
51
|
+
await waitFor(() => {
|
|
52
|
+
expect(result.current.error?.message).toBe('File not found');
|
|
53
|
+
});
|
|
54
|
+
act(() => {
|
|
55
|
+
notifyFileChanged('<html>created later</html>');
|
|
56
|
+
});
|
|
57
|
+
expect(applyContent).toHaveBeenCalledWith('<html>created later</html>');
|
|
58
|
+
expect(result.current.error).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -229,5 +229,17 @@ export interface AgentProtocol {
|
|
|
229
229
|
* @param session - Session to clean up
|
|
230
230
|
*/
|
|
231
231
|
cleanupSession(session: ProtocolSession): void;
|
|
232
|
+
/**
|
|
233
|
+
* Compact the session's context in-place, if the transport supports it.
|
|
234
|
+
*
|
|
235
|
+
* Optional: a transport that cannot compact simply omits this, and callers
|
|
236
|
+
* must check for it before offering the action. Do NOT emulate compaction by
|
|
237
|
+
* sending a `/compact` string as a user turn -- for transports without a real
|
|
238
|
+
* compaction RPC that reaches the model as literal prompt text and silently
|
|
239
|
+
* does nothing (#1252).
|
|
240
|
+
*
|
|
241
|
+
* @param session - Session whose context should be compacted
|
|
242
|
+
*/
|
|
243
|
+
compactSession?(session: ProtocolSession): Promise<void>;
|
|
232
244
|
}
|
|
233
245
|
//# sourceMappingURL=AgentProtocol.d.ts.map
|
|
@@ -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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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React-free public entry for the collaborative-document helpers.
|
|
3
|
+
*
|
|
4
|
+
* The package root re-exports everything here, but the root barrel also pulls
|
|
5
|
+
* in `useEditorLifecycle` and therefore `react` — a peer dependency the host
|
|
6
|
+
* injects at runtime. A codec or a codec test that only touches `Y.Doc` has no
|
|
7
|
+
* React installed, so importing the root barrel fails to resolve for it.
|
|
8
|
+
* `@nimbalyst/extension-sdk/collab` is the entry those consumers import
|
|
9
|
+
* instead, so nobody has to reach into `dist/` by path.
|
|
10
|
+
*/
|
|
11
|
+
export { COLLAB_INIT_ORIGIN } from './origins.js';
|
|
12
|
+
export { createTextCollabContentAdapter, reconstructCollabContentAdapterFromDescriptor, TEXT_COLLAB_DEFAULT_FIELD, type TextCollabContentAdapterOptions, } from './createTextCollabContentAdapter.js';
|
|
13
|
+
export { applyTextDiff, replaceYText, type ApplyTextEdit, } from './textReplacement.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collab/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EACL,8BAA8B,EAC9B,6CAA6C,EAC7C,yBAAyB,EACzB,KAAK,+BAA+B,GACrC,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACL,aAAa,EACb,YAAY,EACZ,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React-free public entry for the collaborative-document helpers.
|
|
3
|
+
*
|
|
4
|
+
* The package root re-exports everything here, but the root barrel also pulls
|
|
5
|
+
* in `useEditorLifecycle` and therefore `react` — a peer dependency the host
|
|
6
|
+
* injects at runtime. A codec or a codec test that only touches `Y.Doc` has no
|
|
7
|
+
* React installed, so importing the root barrel fails to resolve for it.
|
|
8
|
+
* `@nimbalyst/extension-sdk/collab` is the entry those consumers import
|
|
9
|
+
* instead, so nobody has to reach into `dist/` by path.
|
|
10
|
+
*/
|
|
11
|
+
export { COLLAB_INIT_ORIGIN } from './origins.js';
|
|
12
|
+
export { createTextCollabContentAdapter, reconstructCollabContentAdapterFromDescriptor, TEXT_COLLAB_DEFAULT_FIELD, } from './createTextCollabContentAdapter.js';
|
|
13
|
+
export { applyTextDiff, replaceYText, } from './textReplacement.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origin tag used when the SDK wraps `initializeFromContent` in a Y.Doc
|
|
3
|
+
* transaction. Extension bindings can compare a transaction's origin
|
|
4
|
+
* against this to suppress their own change handlers during seeding
|
|
5
|
+
* (otherwise the binding would echo the seed back into local-edit state).
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* yDoc.on('update', (update, origin) => {
|
|
9
|
+
* if (origin === COLLAB_INIT_ORIGIN) return;
|
|
10
|
+
* // ... apply remote change
|
|
11
|
+
* });
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare const COLLAB_INIT_ORIGIN: unique symbol;
|
|
15
|
+
//# sourceMappingURL=origins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origins.d.ts","sourceRoot":"","sources":["../../src/collab/origins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,eAAkC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origin tag used when the SDK wraps `initializeFromContent` in a Y.Doc
|
|
3
|
+
* transaction. Extension bindings can compare a transaction's origin
|
|
4
|
+
* against this to suppress their own change handlers during seeding
|
|
5
|
+
* (otherwise the binding would echo the seed back into local-edit state).
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* yDoc.on('update', (update, origin) => {
|
|
9
|
+
* if (origin === COLLAB_INIT_ORIGIN) return;
|
|
10
|
+
* // ... apply remote change
|
|
11
|
+
* });
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export const COLLAB_INIT_ORIGIN = Symbol('nimbalyst:collab-init');
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type * as Y from 'yjs';
|
|
2
|
+
export type ApplyTextEdit = (start: number, end: number, inserted: string) => void;
|
|
3
|
+
/** Reduce a whole-string replacement to one contiguous range edit. */
|
|
4
|
+
export declare function applyTextDiff(previous: string, next: string, applyEdit: ApplyTextEdit): void;
|
|
5
|
+
/** Apply a whole-string replacement to a Y.Text as one contiguous edit. */
|
|
6
|
+
export declare function replaceYText(target: Y.Text, next: string): void;
|
|
7
|
+
//# sourceMappingURL=textReplacement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textReplacement.d.ts","sourceRoot":"","sources":["../../src/collab/textReplacement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,CAAC,MAAM,KAAK,CAAC;AAE9B,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAEnF,sEAAsE;AACtE,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,aAAa,GACvB,IAAI,CAmBN;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM/D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Reduce a whole-string replacement to one contiguous range edit. */
|
|
2
|
+
export function applyTextDiff(previous, next, applyEdit) {
|
|
3
|
+
if (previous === next)
|
|
4
|
+
return;
|
|
5
|
+
let prefix = 0;
|
|
6
|
+
const prefixLimit = Math.min(previous.length, next.length);
|
|
7
|
+
while (prefix < prefixLimit && previous.charCodeAt(prefix) === next.charCodeAt(prefix)) {
|
|
8
|
+
prefix += 1;
|
|
9
|
+
}
|
|
10
|
+
let suffix = 0;
|
|
11
|
+
const suffixLimit = Math.min(previous.length - prefix, next.length - prefix);
|
|
12
|
+
while (suffix < suffixLimit
|
|
13
|
+
&& previous.charCodeAt(previous.length - 1 - suffix) === next.charCodeAt(next.length - 1 - suffix)) {
|
|
14
|
+
suffix += 1;
|
|
15
|
+
}
|
|
16
|
+
applyEdit(prefix, previous.length - suffix, next.slice(prefix, next.length - suffix));
|
|
17
|
+
}
|
|
18
|
+
/** Apply a whole-string replacement to a Y.Text as one contiguous edit. */
|
|
19
|
+
export function replaceYText(target, next) {
|
|
20
|
+
applyTextDiff(target.toString(), next, (start, end, inserted) => {
|
|
21
|
+
const removeLength = end - start;
|
|
22
|
+
if (removeLength > 0)
|
|
23
|
+
target.delete(start, removeLength);
|
|
24
|
+
if (inserted.length > 0)
|
|
25
|
+
target.insert(start, inserted);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading `EditorHost.capabilities`.
|
|
3
|
+
*
|
|
4
|
+
* One function so the "host makes no claim" case is decided once instead of in
|
|
5
|
+
* every extension. See {@link EditorHostCapabilities}.
|
|
6
|
+
*/
|
|
7
|
+
import type { EditorHost, EditorHostCapability } from './types/editor.js';
|
|
8
|
+
/**
|
|
9
|
+
* Whether `host` really provides `capability`.
|
|
10
|
+
*
|
|
11
|
+
* A host with no `capabilities` block is treated as fully capable. That is not
|
|
12
|
+
* an optimistic guess: the only such host is the Electron renderer, which
|
|
13
|
+
* predates this contract and does implement every member. Any host that cannot
|
|
14
|
+
* -- the browser collaborative host, and anything after it -- is required to
|
|
15
|
+
* populate `capabilities`, so "absent" and "incapable" never overlap.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* if (editorHostSupports(host, 'localFileSave')) {
|
|
19
|
+
* await host.saveContent(serialize());
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function editorHostSupports(host: Pick<EditorHost, 'capabilities'>, capability: EditorHostCapability): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The host's stated reason for withholding `capability`, or null when it is
|
|
26
|
+
* available (or the host makes no claim). For diagnostics and degraded-mode
|
|
27
|
+
* copy -- never branch on the string itself, branch on
|
|
28
|
+
* {@link editorHostSupports}.
|
|
29
|
+
*/
|
|
30
|
+
export declare function editorHostCapabilityGap(host: Pick<EditorHost, 'capabilities'>, capability: EditorHostCapability): string | null;
|
|
31
|
+
//# sourceMappingURL=editorHostCapabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editorHostCapabilities.d.ts","sourceRoot":"","sources":["../src/editorHostCapabilities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EACtC,UAAU,EAAE,oBAAoB,GAC/B,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EACtC,UAAU,EAAE,oBAAoB,GAC/B,MAAM,GAAG,IAAI,CAIf"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading `EditorHost.capabilities`.
|
|
3
|
+
*
|
|
4
|
+
* One function so the "host makes no claim" case is decided once instead of in
|
|
5
|
+
* every extension. See {@link EditorHostCapabilities}.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Whether `host` really provides `capability`.
|
|
9
|
+
*
|
|
10
|
+
* A host with no `capabilities` block is treated as fully capable. That is not
|
|
11
|
+
* an optimistic guess: the only such host is the Electron renderer, which
|
|
12
|
+
* predates this contract and does implement every member. Any host that cannot
|
|
13
|
+
* -- the browser collaborative host, and anything after it -- is required to
|
|
14
|
+
* populate `capabilities`, so "absent" and "incapable" never overlap.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* if (editorHostSupports(host, 'localFileSave')) {
|
|
18
|
+
* await host.saveContent(serialize());
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function editorHostSupports(host, capability) {
|
|
23
|
+
return host.capabilities ? host.capabilities.supports(capability) : true;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The host's stated reason for withholding `capability`, or null when it is
|
|
27
|
+
* available (or the host makes no claim). For diagnostics and degraded-mode
|
|
28
|
+
* copy -- never branch on the string itself, branch on
|
|
29
|
+
* {@link editorHostSupports}.
|
|
30
|
+
*/
|
|
31
|
+
export function editorHostCapabilityGap(host, capability) {
|
|
32
|
+
const gap = host.capabilities?.unavailable
|
|
33
|
+
.find((entry) => entry.capability === capability);
|
|
34
|
+
return gap ? gap.reason : null;
|
|
35
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrow Extension SDK entry used by the Electron main-process bundle.
|
|
3
|
+
*
|
|
4
|
+
* The public SDK barrel includes renderer hooks and components. Main-process
|
|
5
|
+
* code only needs manifest validation, tracker-importer constants, and the
|
|
6
|
+
* serializable collaboration adapter factory.
|
|
7
|
+
*/
|
|
8
|
+
export { effectiveModulePermissions, validateBackendModules, } from './manifestValidation';
|
|
9
|
+
export { TRACKER_IMPORTER_RPC_METHODS } from './types/trackerImporter';
|
|
10
|
+
export { createTextCollabContentAdapter, reconstructCollabContentAdapterFromDescriptor, } from './collab/createTextCollabContentAdapter';
|
|
11
|
+
export { COLLAB_INIT_ORIGIN } from './collab/origins';
|
|
12
|
+
//# sourceMappingURL=electronMain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"electronMain.d.ts","sourceRoot":"","sources":["../src/electronMain.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EACL,8BAA8B,EAC9B,6CAA6C,GAC9C,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrow Extension SDK entry used by the Electron main-process bundle.
|
|
3
|
+
*
|
|
4
|
+
* The public SDK barrel includes renderer hooks and components. Main-process
|
|
5
|
+
* code only needs manifest validation, tracker-importer constants, and the
|
|
6
|
+
* serializable collaboration adapter factory.
|
|
7
|
+
*/
|
|
8
|
+
export { effectiveModulePermissions, validateBackendModules, } from './manifestValidation';
|
|
9
|
+
export { TRACKER_IMPORTER_RPC_METHODS } from './types/trackerImporter';
|
|
10
|
+
export { createTextCollabContentAdapter, reconstructCollabContentAdapterFromDescriptor, } from './collab/createTextCollabContentAdapter';
|
|
11
|
+
export { COLLAB_INIT_ORIGIN } from './collab/origins';
|