underwritten-mcp 0.0.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/README.md +212 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -0
- package/dist/contract.d.ts +179 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +97 -0
- package/dist/contract.js.map +1 -0
- package/dist/contract.test.d.ts +2 -0
- package/dist/contract.test.d.ts.map +1 -0
- package/dist/contract.test.js +35 -0
- package/dist/contract.test.js.map +1 -0
- package/dist/http-server.d.ts +4 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +174 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +4 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +216 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/service.d.ts +30 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +308 -0
- package/dist/service.js.map +1 -0
- package/dist/service.test.d.ts +2 -0
- package/dist/service.test.d.ts.map +1 -0
- package/dist/service.test.js +239 -0
- package/dist/service.test.js.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Underwritten MCP Bridge
|
|
2
|
+
|
|
3
|
+
`underwritten-mcp` is the local MCP companion for `underwritten.app`.
|
|
4
|
+
|
|
5
|
+
It is the MCP server. The browser app is not.
|
|
6
|
+
|
|
7
|
+
## Why this package exists
|
|
8
|
+
|
|
9
|
+
`underwritten.app` is a PWA and the editor state lives in the browser. External MCP clients need a local process that can:
|
|
10
|
+
|
|
11
|
+
- speak MCP over `stdio`
|
|
12
|
+
- bind a localhost API
|
|
13
|
+
- coordinate with the live browser editor session
|
|
14
|
+
|
|
15
|
+
This package provides that bridge while the PWA remains the source of truth for document and workspace state.
|
|
16
|
+
|
|
17
|
+
## Monorepo layout
|
|
18
|
+
|
|
19
|
+
- `apps/mcp`: publishable MCP server package and localhost bridge
|
|
20
|
+
- `apps/mcp/src/contract.ts`: shared browser-safe protocol types and markdown edit helpers
|
|
21
|
+
- `apps/website`: PWA integration, bridge discovery, session registration, polling, and settings UI
|
|
22
|
+
|
|
23
|
+
## User setup
|
|
24
|
+
|
|
25
|
+
The intended end-user MCP config is:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"underwritten": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "underwritten-mcp"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
After that:
|
|
39
|
+
|
|
40
|
+
1. The MCP client starts `underwritten-mcp`.
|
|
41
|
+
2. The bridge binds a localhost API on `127.0.0.1`.
|
|
42
|
+
3. The PWA discovers the bridge automatically and pairs without a manual token-copy step.
|
|
43
|
+
4. The active editor tab registers itself and starts polling for pending actions.
|
|
44
|
+
|
|
45
|
+
## Running locally
|
|
46
|
+
|
|
47
|
+
Install dependencies first:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
vp install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Run the website in one terminal:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
vp run website#dev
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Run the MCP bridge from source in another terminal:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
vp dlx tsx apps/mcp/src/cli.ts
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If you want to run the built output instead:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
vp exec tsc -p apps/mcp/tsconfig.build.json
|
|
69
|
+
node apps/mcp/dist/cli.js
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If you want to test the user-facing bootstrap shape locally, the equivalent MCP client entry is still:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"underwritten": {
|
|
78
|
+
"command": "npx",
|
|
79
|
+
"args": ["-y", "underwritten-mcp"]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Validation
|
|
86
|
+
|
|
87
|
+
Repo-level validation:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
vp check
|
|
91
|
+
vp test
|
|
92
|
+
vp run test:e2e
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
MCP package build only:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
vp exec tsc -p apps/mcp/tsconfig.build.json
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Discovery and pairing
|
|
102
|
+
|
|
103
|
+
By default the PWA scans a reserved localhost port range and probes `GET /discover`.
|
|
104
|
+
|
|
105
|
+
- Reserved range: `45261-45271`
|
|
106
|
+
- Bind address: `127.0.0.1`
|
|
107
|
+
- Pairing: automatic `POST /pair` from an approved Underwritten origin
|
|
108
|
+
- Session sync: `POST /session/sync`
|
|
109
|
+
- Status: `GET /status`
|
|
110
|
+
|
|
111
|
+
For test isolation and local debugging, the browser also honors a `localStorage` override at `underwritten.mcp.bridgePorts` with an explicit JSON array of ports to probe.
|
|
112
|
+
|
|
113
|
+
## Browser session model
|
|
114
|
+
|
|
115
|
+
Each tab registers as a distinct session with:
|
|
116
|
+
|
|
117
|
+
- `sessionId`
|
|
118
|
+
- `activeFilePath`
|
|
119
|
+
- `title`
|
|
120
|
+
- `markdown`
|
|
121
|
+
- `dirty`
|
|
122
|
+
- `storageMode`
|
|
123
|
+
- `nativeFolderSelected`
|
|
124
|
+
- `revision`
|
|
125
|
+
- `lastHeartbeatAt`
|
|
126
|
+
- `lastFocusAt`
|
|
127
|
+
- `visibilityState`
|
|
128
|
+
- `pageUrl`
|
|
129
|
+
- `windowLabel`
|
|
130
|
+
|
|
131
|
+
The browser polls the bridge, receives queued actions, applies them through the existing `EditorPage` editor/workspace code paths, and posts the result back in the next sync.
|
|
132
|
+
|
|
133
|
+
## Tool surface
|
|
134
|
+
|
|
135
|
+
Workspace tools:
|
|
136
|
+
|
|
137
|
+
- `get_workspace_status`
|
|
138
|
+
- `list_files`
|
|
139
|
+
- `read_file`
|
|
140
|
+
- `open_file`
|
|
141
|
+
- `create_file`
|
|
142
|
+
- `create_folder`
|
|
143
|
+
- `move_path`
|
|
144
|
+
- `delete_path`
|
|
145
|
+
- `save_document`
|
|
146
|
+
|
|
147
|
+
Markdown tools:
|
|
148
|
+
|
|
149
|
+
- `get_current_document`
|
|
150
|
+
- `replace_current_document`
|
|
151
|
+
- `apply_markdown_edits`
|
|
152
|
+
|
|
153
|
+
### Markdown edit semantics
|
|
154
|
+
|
|
155
|
+
`apply_markdown_edits` operates on raw markdown text, not editor-internal node ids.
|
|
156
|
+
|
|
157
|
+
- Target matching is literal text matching.
|
|
158
|
+
- `occurrence` is 1-based when provided.
|
|
159
|
+
- If `occurrence` is omitted, the target text must match exactly once.
|
|
160
|
+
- Ambiguous or missing targets fail with a clear error.
|
|
161
|
+
- Edits apply sequentially to the updated markdown buffer.
|
|
162
|
+
|
|
163
|
+
## Deterministic routing
|
|
164
|
+
|
|
165
|
+
Current-document and workspace tools route to one live session:
|
|
166
|
+
|
|
167
|
+
1. Keep only live sessions. A live session has a fresh heartbeat within `15s` and has not disconnected.
|
|
168
|
+
2. Sort by most recent `lastFocusAt`.
|
|
169
|
+
3. Break ties with most recent `lastHeartbeatAt`.
|
|
170
|
+
4. Break remaining ties lexically by `sessionId`.
|
|
171
|
+
5. If no live session remains, return an explicit error instead of guessing.
|
|
172
|
+
|
|
173
|
+
This keeps tool routing deterministic across multiple open tabs while leaving room for future explicit `sessionId` targeting.
|
|
174
|
+
|
|
175
|
+
## Security model
|
|
176
|
+
|
|
177
|
+
- The HTTP bridge binds only to `127.0.0.1`.
|
|
178
|
+
- Requests are limited to Underwritten origins plus local dev origins (`localhost` and `127.0.0.1`).
|
|
179
|
+
- The browser must pair first and then present a bridge-issued bearer token.
|
|
180
|
+
- The bridge does not expose shell execution.
|
|
181
|
+
- Workspace operations are restricted to Underwritten’s real browser workspace model.
|
|
182
|
+
- Native folder access still depends on the browser-granted File System Access handle already chosen in the app.
|
|
183
|
+
|
|
184
|
+
### Threat model limits
|
|
185
|
+
|
|
186
|
+
- Pairing is automatic for approved origins, so trust is anchored in the origin allowlist and localhost-only binding.
|
|
187
|
+
- A malicious script running on an approved Underwritten origin would inherit the same bridge access as the app.
|
|
188
|
+
- Multiple simultaneous MCP bridge processes are supported, but the browser only probes the configured port list/range and pairs with bridges it can discover.
|
|
189
|
+
|
|
190
|
+
## Settings UI
|
|
191
|
+
|
|
192
|
+
The existing settings dialog now includes an `MCP Bridge` section with:
|
|
193
|
+
|
|
194
|
+
- reachability / connection status
|
|
195
|
+
- current session id
|
|
196
|
+
- detected localhost port
|
|
197
|
+
- known session count
|
|
198
|
+
- copyable MCP config snippet
|
|
199
|
+
- reconnect action
|
|
200
|
+
|
|
201
|
+
## Current limitations
|
|
202
|
+
|
|
203
|
+
- The public tool surface does not yet support explicit `sessionId` targeting.
|
|
204
|
+
- `delete_path.force` only bypasses unsaved-current-document protection; it is not a separate recursive-delete flag because the browser file APIs already define directory deletion behavior.
|
|
205
|
+
- The settings panel reports bridge/session status from the local browser’s perspective; it is not a multi-client admin console.
|
|
206
|
+
|
|
207
|
+
## Future improvements
|
|
208
|
+
|
|
209
|
+
- explicit `sessionId` tool targeting
|
|
210
|
+
- richer bridge diagnostics and per-session inspection
|
|
211
|
+
- optional Streamable HTTP exposure in addition to `stdio`
|
|
212
|
+
- stronger persisted pairing state if the product needs cross-restart trust continuity
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { underwrittenBridgePortRange } from "./contract.js";
|
|
3
|
+
import { startUnderwrittenBridge } from "./index.js";
|
|
4
|
+
const startedBridge = await startUnderwrittenBridge({
|
|
5
|
+
connectStdio: true,
|
|
6
|
+
portRange: underwrittenBridgePortRange,
|
|
7
|
+
});
|
|
8
|
+
const shutdown = async () => {
|
|
9
|
+
await startedBridge.close();
|
|
10
|
+
process.exit(0);
|
|
11
|
+
};
|
|
12
|
+
process.on("SIGINT", () => {
|
|
13
|
+
void shutdown();
|
|
14
|
+
});
|
|
15
|
+
process.on("SIGTERM", () => {
|
|
16
|
+
void shutdown();
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,aAAa,GAAG,MAAM,uBAAuB,CAAC;IAClD,YAAY,EAAE,IAAI;IAClB,SAAS,EAAE,2BAA2B;CACvC,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;IAC1B,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC;IAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,KAAK,QAAQ,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,KAAK,QAAQ,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
export declare const underwrittenBridgePortRange: {
|
|
2
|
+
readonly end: 45271;
|
|
3
|
+
readonly start: 45261;
|
|
4
|
+
};
|
|
5
|
+
export declare const underwrittenBridgeApiVersion = "2026-03-16";
|
|
6
|
+
export declare const underwrittenBridgeSessionTtlMs = 15000;
|
|
7
|
+
export declare const underwrittenBridgePollIntervalMs = 1000;
|
|
8
|
+
export declare const underwrittenBridgeActionTimeoutMs = 20000;
|
|
9
|
+
export type UnderwrittenStorageMode = "origin-private" | "native-folder";
|
|
10
|
+
export type MarkdownEditTarget = {
|
|
11
|
+
occurrence?: number;
|
|
12
|
+
text: string;
|
|
13
|
+
};
|
|
14
|
+
export type MarkdownEdit = {
|
|
15
|
+
newText?: string;
|
|
16
|
+
target: MarkdownEditTarget;
|
|
17
|
+
type: "delete" | "insert_after" | "insert_before" | "replace";
|
|
18
|
+
};
|
|
19
|
+
export type WorkspaceStatus = {
|
|
20
|
+
activeFilePath: string | null;
|
|
21
|
+
hasNativeFolderSelected: boolean;
|
|
22
|
+
hasUnsavedChanges: boolean;
|
|
23
|
+
storageMode: UnderwrittenStorageMode;
|
|
24
|
+
};
|
|
25
|
+
export type MarkdownOutlineItem = {
|
|
26
|
+
depth: number;
|
|
27
|
+
line: number;
|
|
28
|
+
text: string;
|
|
29
|
+
};
|
|
30
|
+
export type CurrentDocument = {
|
|
31
|
+
dirty: boolean;
|
|
32
|
+
filePath: string | null;
|
|
33
|
+
markdown: string;
|
|
34
|
+
outline?: MarkdownOutlineItem[];
|
|
35
|
+
storageMode: UnderwrittenStorageMode;
|
|
36
|
+
title: string;
|
|
37
|
+
};
|
|
38
|
+
export type BridgeSessionCapabilities = {
|
|
39
|
+
supportsDirectoryAccess: boolean;
|
|
40
|
+
};
|
|
41
|
+
export type BridgeSessionState = {
|
|
42
|
+
activeFilePath: string | null;
|
|
43
|
+
appCapabilities: BridgeSessionCapabilities;
|
|
44
|
+
dirty: boolean;
|
|
45
|
+
lastFocusAt: number | null;
|
|
46
|
+
lastHeartbeatAt: number;
|
|
47
|
+
markdown: string;
|
|
48
|
+
nativeFolderSelected: boolean;
|
|
49
|
+
pageUrl: string | null;
|
|
50
|
+
revision: string | null;
|
|
51
|
+
sessionId: string;
|
|
52
|
+
storageMode: UnderwrittenStorageMode;
|
|
53
|
+
title: string;
|
|
54
|
+
visibilityState: "hidden" | "visible";
|
|
55
|
+
windowLabel: string | null;
|
|
56
|
+
};
|
|
57
|
+
export type GetWorkspaceStatusAction = {
|
|
58
|
+
id: string;
|
|
59
|
+
type: "get_workspace_status";
|
|
60
|
+
};
|
|
61
|
+
export type ListFilesAction = {
|
|
62
|
+
id: string;
|
|
63
|
+
includeDirectories?: boolean;
|
|
64
|
+
path?: string;
|
|
65
|
+
recursive?: boolean;
|
|
66
|
+
type: "list_files";
|
|
67
|
+
};
|
|
68
|
+
export type ReadFileAction = {
|
|
69
|
+
id: string;
|
|
70
|
+
path: string;
|
|
71
|
+
type: "read_file";
|
|
72
|
+
};
|
|
73
|
+
export type OpenFileAction = {
|
|
74
|
+
discardUnsavedChanges?: boolean;
|
|
75
|
+
id: string;
|
|
76
|
+
path: string;
|
|
77
|
+
type: "open_file";
|
|
78
|
+
};
|
|
79
|
+
export type CreateFileAction = {
|
|
80
|
+
content?: string;
|
|
81
|
+
id: string;
|
|
82
|
+
openAfterCreate?: boolean;
|
|
83
|
+
path: string;
|
|
84
|
+
type: "create_file";
|
|
85
|
+
};
|
|
86
|
+
export type CreateFolderAction = {
|
|
87
|
+
id: string;
|
|
88
|
+
path: string;
|
|
89
|
+
type: "create_folder";
|
|
90
|
+
};
|
|
91
|
+
export type MovePathAction = {
|
|
92
|
+
destinationPath: string;
|
|
93
|
+
id: string;
|
|
94
|
+
sourcePath: string;
|
|
95
|
+
type: "move_path";
|
|
96
|
+
};
|
|
97
|
+
export type DeletePathAction = {
|
|
98
|
+
force?: boolean;
|
|
99
|
+
id: string;
|
|
100
|
+
path: string;
|
|
101
|
+
type: "delete_path";
|
|
102
|
+
};
|
|
103
|
+
export type SaveDocumentAction = {
|
|
104
|
+
id: string;
|
|
105
|
+
path?: string;
|
|
106
|
+
type: "save_document";
|
|
107
|
+
};
|
|
108
|
+
export type GetCurrentDocumentAction = {
|
|
109
|
+
id: string;
|
|
110
|
+
includeOutline?: boolean;
|
|
111
|
+
type: "get_current_document";
|
|
112
|
+
};
|
|
113
|
+
export type ReplaceCurrentDocumentAction = {
|
|
114
|
+
id: string;
|
|
115
|
+
markdown: string;
|
|
116
|
+
type: "replace_current_document";
|
|
117
|
+
};
|
|
118
|
+
export type ApplyMarkdownEditsAction = {
|
|
119
|
+
edits: MarkdownEdit[];
|
|
120
|
+
id: string;
|
|
121
|
+
type: "apply_markdown_edits";
|
|
122
|
+
};
|
|
123
|
+
export type UnderwrittenBridgeAction = ApplyMarkdownEditsAction | CreateFileAction | CreateFolderAction | DeletePathAction | GetCurrentDocumentAction | GetWorkspaceStatusAction | ListFilesAction | MovePathAction | OpenFileAction | ReadFileAction | ReplaceCurrentDocumentAction | SaveDocumentAction;
|
|
124
|
+
export type UnderwrittenBridgeActionResult = {
|
|
125
|
+
actionId: string;
|
|
126
|
+
error: {
|
|
127
|
+
code: string;
|
|
128
|
+
message: string;
|
|
129
|
+
};
|
|
130
|
+
ok: false;
|
|
131
|
+
} | {
|
|
132
|
+
actionId: string;
|
|
133
|
+
ok: true;
|
|
134
|
+
result: unknown;
|
|
135
|
+
};
|
|
136
|
+
export type UnderwrittenBridgeDiscoveryResponse = {
|
|
137
|
+
apiVersion: string;
|
|
138
|
+
appName: "underwritten";
|
|
139
|
+
bridgeId: string;
|
|
140
|
+
port: number;
|
|
141
|
+
};
|
|
142
|
+
export type UnderwrittenBridgePairRequest = {
|
|
143
|
+
pageUrl?: string | null;
|
|
144
|
+
sessionId: string;
|
|
145
|
+
};
|
|
146
|
+
export type UnderwrittenBridgePairResponse = {
|
|
147
|
+
apiVersion: string;
|
|
148
|
+
browserToken: string;
|
|
149
|
+
bridgeId: string;
|
|
150
|
+
pollIntervalMs: number;
|
|
151
|
+
sessionTtlMs: number;
|
|
152
|
+
};
|
|
153
|
+
export type UnderwrittenBridgeSessionSyncRequest = {
|
|
154
|
+
completedActions?: UnderwrittenBridgeActionResult[];
|
|
155
|
+
session: BridgeSessionState;
|
|
156
|
+
};
|
|
157
|
+
export type UnderwrittenBridgeSessionSyncResponse = {
|
|
158
|
+
pendingActions: UnderwrittenBridgeAction[];
|
|
159
|
+
serverTime: number;
|
|
160
|
+
};
|
|
161
|
+
export type UnderwrittenBridgeDisconnectRequest = {
|
|
162
|
+
sessionId: string;
|
|
163
|
+
};
|
|
164
|
+
export type UnderwrittenBridgeStatusResponse = {
|
|
165
|
+
activeSessionId: string | null;
|
|
166
|
+
bridgeId: string;
|
|
167
|
+
pairings: number;
|
|
168
|
+
port: number;
|
|
169
|
+
resolvedBy: "lastFocusAt,lastHeartbeatAt,sessionId" | "none";
|
|
170
|
+
sessions: Array<BridgeSessionState & {
|
|
171
|
+
connectedAt: number;
|
|
172
|
+
disconnectedAt: number | null;
|
|
173
|
+
origin: string;
|
|
174
|
+
}>;
|
|
175
|
+
};
|
|
176
|
+
export declare function createSessionId(): string;
|
|
177
|
+
export declare function applyMarkdownTextEdits(markdown: string, edits: MarkdownEdit[]): string;
|
|
178
|
+
export declare function buildMarkdownOutline(markdown: string): MarkdownOutlineItem[];
|
|
179
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B;;;CAG9B,CAAC;AAEX,eAAO,MAAM,4BAA4B,eAAe,CAAC;AACzD,eAAO,MAAM,8BAA8B,QAAS,CAAC;AACrD,eAAO,MAAM,gCAAgC,OAAQ,CAAC;AACtD,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAExD,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAEzE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,QAAQ,GAAG,cAAc,GAAG,eAAe,GAAG,SAAS,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,uBAAuB,EAAE,OAAO,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,EAAE,uBAAuB,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAChC,WAAW,EAAE,uBAAuB,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,uBAAuB,EAAE,OAAO,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,yBAAyB,CAAC;IAC3C,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,uBAAuB,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,sBAAsB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,sBAAsB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,0BAA0B,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,sBAAsB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAChC,wBAAwB,GACxB,gBAAgB,GAChB,kBAAkB,GAClB,gBAAgB,GAChB,wBAAwB,GACxB,wBAAwB,GACxB,eAAe,GACf,cAAc,GACd,cAAc,GACd,cAAc,GACd,4BAA4B,GAC5B,kBAAkB,CAAC;AAEvB,MAAM,MAAM,8BAA8B,GACtC;IACE,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,EAAE,EAAE,KAAK,CAAC;CACX,GACD;IACE,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEN,MAAM,MAAM,mCAAmC,GAAG;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,gBAAgB,CAAC,EAAE,8BAA8B,EAAE,CAAC;IACpD,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAAG;IAClD,cAAc,EAAE,wBAAwB,EAAE,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,uCAAuC,GAAG,MAAM,CAAC;IAC7D,QAAQ,EAAE,KAAK,CACb,kBAAkB,GAAG;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,MAAM,EAAE,MAAM,CAAC;KAChB,CACF,CAAC;CACH,CAAC;AAEF,wBAAgB,eAAe,WAE9B;AAmDD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,UA2C7E;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAe5E"}
|
package/dist/contract.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export const underwrittenBridgePortRange = {
|
|
2
|
+
end: 45271,
|
|
3
|
+
start: 45261,
|
|
4
|
+
};
|
|
5
|
+
export const underwrittenBridgeApiVersion = "2026-03-16";
|
|
6
|
+
export const underwrittenBridgeSessionTtlMs = 15_000;
|
|
7
|
+
export const underwrittenBridgePollIntervalMs = 1_000;
|
|
8
|
+
export const underwrittenBridgeActionTimeoutMs = 20_000;
|
|
9
|
+
export function createSessionId() {
|
|
10
|
+
return `uw-session-${Math.random().toString(36).slice(2, 10)}-${Date.now().toString(36)}`;
|
|
11
|
+
}
|
|
12
|
+
function findAllOccurrences(haystack, needle) {
|
|
13
|
+
if (needle.length === 0) {
|
|
14
|
+
throw new Error("Markdown edit targets must not be empty.");
|
|
15
|
+
}
|
|
16
|
+
const positions = [];
|
|
17
|
+
let fromIndex = 0;
|
|
18
|
+
while (fromIndex <= haystack.length) {
|
|
19
|
+
const index = haystack.indexOf(needle, fromIndex);
|
|
20
|
+
if (index < 0)
|
|
21
|
+
break;
|
|
22
|
+
positions.push(index);
|
|
23
|
+
fromIndex = index + needle.length;
|
|
24
|
+
}
|
|
25
|
+
return positions;
|
|
26
|
+
}
|
|
27
|
+
function resolveOccurrence(markdown, target) {
|
|
28
|
+
const positions = findAllOccurrences(markdown, target.text);
|
|
29
|
+
if (positions.length === 0) {
|
|
30
|
+
throw new Error(`Target text not found: ${JSON.stringify(target.text)}`);
|
|
31
|
+
}
|
|
32
|
+
if (typeof target.occurrence === "number") {
|
|
33
|
+
if (!Number.isInteger(target.occurrence) || target.occurrence < 1) {
|
|
34
|
+
throw new Error("Target occurrence must be a positive integer.");
|
|
35
|
+
}
|
|
36
|
+
const position = positions[target.occurrence - 1];
|
|
37
|
+
if (typeof position !== "number") {
|
|
38
|
+
throw new Error(`Target occurrence ${target.occurrence} was not found for ${JSON.stringify(target.text)}.`);
|
|
39
|
+
}
|
|
40
|
+
return position;
|
|
41
|
+
}
|
|
42
|
+
if (positions.length > 1) {
|
|
43
|
+
throw new Error(`Target text is ambiguous without an occurrence: ${JSON.stringify(target.text)}.`);
|
|
44
|
+
}
|
|
45
|
+
return positions[0] ?? 0;
|
|
46
|
+
}
|
|
47
|
+
export function applyMarkdownTextEdits(markdown, edits) {
|
|
48
|
+
let nextMarkdown = markdown;
|
|
49
|
+
for (const edit of edits) {
|
|
50
|
+
const start = resolveOccurrence(nextMarkdown, edit.target);
|
|
51
|
+
const end = start + edit.target.text.length;
|
|
52
|
+
switch (edit.type) {
|
|
53
|
+
case "replace": {
|
|
54
|
+
if (typeof edit.newText !== "string") {
|
|
55
|
+
throw new Error("Replace edits require newText.");
|
|
56
|
+
}
|
|
57
|
+
nextMarkdown = `${nextMarkdown.slice(0, start)}${edit.newText}${nextMarkdown.slice(end)}`;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "insert_before": {
|
|
61
|
+
if (typeof edit.newText !== "string") {
|
|
62
|
+
throw new Error("insert_before edits require newText.");
|
|
63
|
+
}
|
|
64
|
+
nextMarkdown = `${nextMarkdown.slice(0, start)}${edit.newText}${nextMarkdown.slice(start)}`;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case "insert_after": {
|
|
68
|
+
if (typeof edit.newText !== "string") {
|
|
69
|
+
throw new Error("insert_after edits require newText.");
|
|
70
|
+
}
|
|
71
|
+
nextMarkdown = `${nextMarkdown.slice(0, end)}${edit.newText}${nextMarkdown.slice(end)}`;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "delete": {
|
|
75
|
+
nextMarkdown = `${nextMarkdown.slice(0, start)}${nextMarkdown.slice(end)}`;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return nextMarkdown;
|
|
81
|
+
}
|
|
82
|
+
export function buildMarkdownOutline(markdown) {
|
|
83
|
+
return markdown.split("\n").flatMap((line, index) => {
|
|
84
|
+
const match = /^(#{1,6})\s+(.*\S)\s*$/.exec(line);
|
|
85
|
+
if (!match) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
depth: match[1].length,
|
|
91
|
+
line: index + 1,
|
|
92
|
+
text: match[2],
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.test.d.ts","sourceRoot":"","sources":["../src/contract.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, test } from "vite-plus/test";
|
|
2
|
+
import { applyMarkdownTextEdits, buildMarkdownOutline } from "./contract.js";
|
|
3
|
+
describe("contract helpers", () => {
|
|
4
|
+
test("applies sequential markdown edits", () => {
|
|
5
|
+
const markdown = "# Title\n\nAlpha\nBeta\n";
|
|
6
|
+
expect(applyMarkdownTextEdits(markdown, [
|
|
7
|
+
{
|
|
8
|
+
newText: "Intro\n",
|
|
9
|
+
target: { text: "Alpha" },
|
|
10
|
+
type: "insert_before",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
newText: "Gamma",
|
|
14
|
+
target: { text: "Beta" },
|
|
15
|
+
type: "replace",
|
|
16
|
+
},
|
|
17
|
+
])).toBe("# Title\n\nIntro\nAlpha\nGamma\n");
|
|
18
|
+
});
|
|
19
|
+
test("requires occurrence when the target text is ambiguous", () => {
|
|
20
|
+
expect(() => applyMarkdownTextEdits("repeat\nrepeat\n", [
|
|
21
|
+
{
|
|
22
|
+
target: { text: "repeat" },
|
|
23
|
+
type: "delete",
|
|
24
|
+
},
|
|
25
|
+
])).toThrow("ambiguous");
|
|
26
|
+
});
|
|
27
|
+
test("builds a markdown outline with heading depth and line numbers", () => {
|
|
28
|
+
expect(buildMarkdownOutline("# Title\n\n## First\nBody\n### Nested\n")).toEqual([
|
|
29
|
+
{ depth: 1, line: 1, text: "Title" },
|
|
30
|
+
{ depth: 2, line: 3, text: "First" },
|
|
31
|
+
{ depth: 3, line: 5, text: "Nested" },
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.test.js","sourceRoot":"","sources":["../src/contract.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE7E,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC7C,MAAM,QAAQ,GAAG,0BAA0B,CAAC;QAE5C,MAAM,CACJ,sBAAsB,CAAC,QAAQ,EAAE;YAC/B;gBACE,OAAO,EAAE,SAAS;gBAClB,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;gBACzB,IAAI,EAAE,eAAe;aACtB;YACD;gBACE,OAAO,EAAE,OAAO;gBAChB,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBACxB,IAAI,EAAE,SAAS;aAChB;SACF,CAAC,CACH,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,uDAAuD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAG,EAAE,CACV,sBAAsB,CAAC,kBAAkB,EAAE;YACzC;gBACE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC1B,IAAI,EAAE,QAAQ;aACf;SACF,CAAC,CACH,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,oBAAoB,CAAC,yCAAyC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9E,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;YACpC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;YACpC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE;SACtC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
2
|
+
import { type UnderwrittenBridgeService } from "./service.js";
|
|
3
|
+
export declare function createHttpServer(service: UnderwrittenBridgeService, port: number): Promise<import("http").Server<typeof IncomingMessage, typeof ServerResponse>>;
|
|
4
|
+
//# sourceMappingURL=http-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAUpF,OAAO,EAEL,KAAK,yBAAyB,EAE/B,MAAM,cAAc,CAAC;AAqItB,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,MAAM,iFA4FtF"}
|