tandem-editor 0.2.11 → 0.3.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 +161 -117
- package/README.md +201 -201
- package/dist/channel/index.js +45 -2
- package/dist/channel/index.js.map +1 -1
- package/dist/cli/index.js +7 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/client/assets/index-BXWLR51Y.js +308 -0
- package/dist/client/index.html +13 -13
- package/dist/server/index.js +54 -25
- package/dist/server/index.js.map +1 -1
- package/package.json +5 -1
- package/sample/demo-script.md +23 -23
- package/sample/welcome.md +21 -21
- package/dist/client/assets/index-CfGlbY9B.js +0 -297
package/dist/client/index.html
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Tandem - Collaborative Editor</title>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Tandem - Collaborative Editor</title>
|
|
7
7
|
<style>
|
|
8
8
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
9
|
html, body, #root { height: 100%; }
|
|
10
10
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
|
|
11
|
-
</style>
|
|
12
|
-
<script type="module" crossorigin src="/assets/index-
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<div id="root"></div>
|
|
16
|
-
</body>
|
|
17
|
-
</html>
|
|
11
|
+
</style>
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-BXWLR51Y.js"></script>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div id="root"></div>
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
package/dist/server/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var __export = (target, all) => {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
// src/shared/constants.ts
|
|
12
|
-
var DEFAULT_WS_PORT, DEFAULT_MCP_PORT, SUPPORTED_EXTENSIONS, MAX_FILE_SIZE, MAX_WS_PAYLOAD, IDLE_TIMEOUT, SESSION_MAX_AGE,
|
|
12
|
+
var DEFAULT_WS_PORT, DEFAULT_MCP_PORT, SUPPORTED_EXTENSIONS, MAX_FILE_SIZE, MAX_WS_PAYLOAD, IDLE_TIMEOUT, SESSION_MAX_AGE, TANDEM_MODE_DEFAULT, SELECTION_DWELL_DEFAULT_MS, CHARS_PER_PAGE, LARGE_FILE_PAGE_THRESHOLD, VERY_LARGE_FILE_PAGE_THRESHOLD, CTRL_ROOM, Y_MAP_ANNOTATIONS, Y_MAP_AWARENESS, Y_MAP_USER_AWARENESS, Y_MAP_MODE, Y_MAP_CHAT, Y_MAP_DOCUMENT_META, Y_MAP_SAVED_AT_VERSION, NOTIFICATION_BUFFER_SIZE, TUTORIAL_ANNOTATION_PREFIX, CHANNEL_EVENT_BUFFER_SIZE, CHANNEL_EVENT_BUFFER_AGE_MS, CHANNEL_SSE_KEEPALIVE_MS;
|
|
13
13
|
var init_constants = __esm({
|
|
14
14
|
"src/shared/constants.ts"() {
|
|
15
15
|
"use strict";
|
|
@@ -20,7 +20,8 @@ var init_constants = __esm({
|
|
|
20
20
|
MAX_WS_PAYLOAD = 10 * 1024 * 1024;
|
|
21
21
|
IDLE_TIMEOUT = 30 * 60 * 1e3;
|
|
22
22
|
SESSION_MAX_AGE = 30 * 24 * 60 * 60 * 1e3;
|
|
23
|
-
|
|
23
|
+
TANDEM_MODE_DEFAULT = "tandem";
|
|
24
|
+
SELECTION_DWELL_DEFAULT_MS = 1e3;
|
|
24
25
|
CHARS_PER_PAGE = 3e3;
|
|
25
26
|
LARGE_FILE_PAGE_THRESHOLD = 50;
|
|
26
27
|
VERY_LARGE_FILE_PAGE_THRESHOLD = 100;
|
|
@@ -28,6 +29,7 @@ var init_constants = __esm({
|
|
|
28
29
|
Y_MAP_ANNOTATIONS = "annotations";
|
|
29
30
|
Y_MAP_AWARENESS = "awareness";
|
|
30
31
|
Y_MAP_USER_AWARENESS = "userAwareness";
|
|
32
|
+
Y_MAP_MODE = "mode";
|
|
31
33
|
Y_MAP_CHAT = "chat";
|
|
32
34
|
Y_MAP_DOCUMENT_META = "documentMeta";
|
|
33
35
|
Y_MAP_SAVED_AT_VERSION = "savedAtVersion";
|
|
@@ -1640,7 +1642,7 @@ var init_positions2 = __esm({
|
|
|
1640
1642
|
|
|
1641
1643
|
// src/shared/types.ts
|
|
1642
1644
|
import { z } from "zod";
|
|
1643
|
-
var AnnotationTypeSchema, AnnotationStatusSchema, AnnotationPrioritySchema,
|
|
1645
|
+
var AnnotationTypeSchema, AnnotationStatusSchema, AnnotationPrioritySchema, HighlightColorSchema, SeveritySchema, TandemModeSchema, AuthorSchema, AnnotationActionSchema, ExportFormatSchema, DocumentFormatSchema, ToolErrorCodeSchema;
|
|
1644
1646
|
var init_types2 = __esm({
|
|
1645
1647
|
"src/shared/types.ts"() {
|
|
1646
1648
|
"use strict";
|
|
@@ -1655,9 +1657,9 @@ var init_types2 = __esm({
|
|
|
1655
1657
|
]);
|
|
1656
1658
|
AnnotationStatusSchema = z.enum(["pending", "accepted", "dismissed"]);
|
|
1657
1659
|
AnnotationPrioritySchema = z.enum(["normal", "urgent"]);
|
|
1658
|
-
InterruptionModeSchema = z.enum(["all", "urgent-only", "paused"]);
|
|
1659
1660
|
HighlightColorSchema = z.enum(["yellow", "red", "green", "blue", "purple"]);
|
|
1660
1661
|
SeveritySchema = z.enum(["info", "warning", "error", "success"]);
|
|
1662
|
+
TandemModeSchema = z.enum(["solo", "tandem"]);
|
|
1661
1663
|
AuthorSchema = z.enum(["user", "claude", "import"]);
|
|
1662
1664
|
AnnotationActionSchema = z.enum(["accept", "dismiss"]);
|
|
1663
1665
|
ExportFormatSchema = z.enum(["markdown", "json"]);
|
|
@@ -3569,26 +3571,37 @@ function attachObservers(docName, doc) {
|
|
|
3569
3571
|
annotationsMap.observe(annotationsObs);
|
|
3570
3572
|
cleanups.push(() => annotationsMap.unobserve(annotationsObs));
|
|
3571
3573
|
const userAwareness = doc.getMap(Y_MAP_USER_AWARENESS);
|
|
3574
|
+
let selectionDwellTimer = null;
|
|
3572
3575
|
const awarenessObs = (event, txn) => {
|
|
3573
3576
|
if (txn.origin === MCP_ORIGIN) return;
|
|
3574
3577
|
if (event.keysChanged.has("selection")) {
|
|
3575
3578
|
const selection = userAwareness.get("selection");
|
|
3579
|
+
if (selectionDwellTimer) {
|
|
3580
|
+
clearTimeout(selectionDwellTimer);
|
|
3581
|
+
selectionDwellTimer = null;
|
|
3582
|
+
}
|
|
3576
3583
|
if (!selection || selection.from === selection.to) return;
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3584
|
+
selectionDwellTimer = setTimeout(() => {
|
|
3585
|
+
selectionDwellTimer = null;
|
|
3586
|
+
pushEvent({
|
|
3587
|
+
id: generateEventId(),
|
|
3588
|
+
type: "selection:changed",
|
|
3589
|
+
timestamp: Date.now(),
|
|
3590
|
+
documentId: docName,
|
|
3591
|
+
payload: {
|
|
3592
|
+
from: selection.from,
|
|
3593
|
+
to: selection.to,
|
|
3594
|
+
selectedText: selection.selectedText ?? ""
|
|
3595
|
+
}
|
|
3596
|
+
});
|
|
3597
|
+
}, SELECTION_DWELL_DEFAULT_MS);
|
|
3588
3598
|
}
|
|
3589
3599
|
};
|
|
3590
3600
|
userAwareness.observe(awarenessObs);
|
|
3591
|
-
cleanups.push(() =>
|
|
3601
|
+
cleanups.push(() => {
|
|
3602
|
+
userAwareness.unobserve(awarenessObs);
|
|
3603
|
+
if (selectionDwellTimer) clearTimeout(selectionDwellTimer);
|
|
3604
|
+
});
|
|
3592
3605
|
docObservers.set(docName, cleanups);
|
|
3593
3606
|
console.error(`[EventQueue] Attached observers for document: ${docName}`);
|
|
3594
3607
|
}
|
|
@@ -4298,15 +4311,12 @@ function registerDocumentTools(server) {
|
|
|
4298
4311
|
withErrorBoundary("tandem_status", async () => {
|
|
4299
4312
|
const activeId = getActiveDocId();
|
|
4300
4313
|
const active = activeId ? openDocs2.get(activeId) : null;
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
const awareness = doc.getMap(Y_MAP_USER_AWARENESS);
|
|
4305
|
-
interruptionMode = awareness.get("interruptionMode") ?? INTERRUPTION_MODE_DEFAULT;
|
|
4306
|
-
}
|
|
4314
|
+
const ctrlDoc = getOrCreateDocument(CTRL_ROOM);
|
|
4315
|
+
const ctrlAwareness = ctrlDoc.getMap(Y_MAP_USER_AWARENESS);
|
|
4316
|
+
const mode = TandemModeSchema.catch(TANDEM_MODE_DEFAULT).parse(ctrlAwareness.get(Y_MAP_MODE));
|
|
4307
4317
|
return mcpSuccess({
|
|
4308
4318
|
running: true,
|
|
4309
|
-
|
|
4319
|
+
mode,
|
|
4310
4320
|
activeDocument: active ? { documentId: active.id, filePath: active.filePath, format: active.format } : null,
|
|
4311
4321
|
openDocuments: Array.from(openDocs2.values()).map((d) => ({
|
|
4312
4322
|
documentId: d.id,
|
|
@@ -4467,6 +4477,15 @@ function createAnnotation(map, ydoc, type, anchored, content, extras) {
|
|
|
4467
4477
|
...extras
|
|
4468
4478
|
};
|
|
4469
4479
|
ydoc.transact(() => map.set(id, annotation), MCP_ORIGIN);
|
|
4480
|
+
const snippet = annotation.textSnapshot ? `: "${annotation.textSnapshot.slice(0, 60)}${annotation.textSnapshot.length > 60 ? "\u2026" : ""}"` : "";
|
|
4481
|
+
pushNotification({
|
|
4482
|
+
id: generateNotificationId(),
|
|
4483
|
+
type: "review-pending",
|
|
4484
|
+
severity: "info",
|
|
4485
|
+
message: `New ${type[0].toUpperCase() + type.slice(1)}${snippet}`,
|
|
4486
|
+
dedupKey: `review-pending:${type}`,
|
|
4487
|
+
timestamp: Date.now()
|
|
4488
|
+
});
|
|
4470
4489
|
return id;
|
|
4471
4490
|
}
|
|
4472
4491
|
function collectAnnotations(map) {
|
|
@@ -4781,6 +4800,7 @@ function registerAnnotationTools(server) {
|
|
|
4781
4800
|
|
|
4782
4801
|
// src/server/mcp/api-routes.ts
|
|
4783
4802
|
init_constants();
|
|
4803
|
+
init_types2();
|
|
4784
4804
|
init_document_model();
|
|
4785
4805
|
init_file_opener();
|
|
4786
4806
|
init_document_service();
|
|
@@ -4968,6 +4988,7 @@ function registerApplyTools(server) {
|
|
|
4968
4988
|
}
|
|
4969
4989
|
|
|
4970
4990
|
// src/server/mcp/api-routes.ts
|
|
4991
|
+
init_provider();
|
|
4971
4992
|
function isHostAllowed(host) {
|
|
4972
4993
|
const reqHost = (host ?? "").split(":")[0];
|
|
4973
4994
|
return reqHost === "localhost" || reqHost === "127.0.0.1";
|
|
@@ -5169,6 +5190,12 @@ function registerApiRoutes(app, largeBody) {
|
|
|
5169
5190
|
sendApiError(res, err);
|
|
5170
5191
|
}
|
|
5171
5192
|
});
|
|
5193
|
+
app.get("/api/mode", apiMiddleware, (_req, res) => {
|
|
5194
|
+
const ctrlDoc = getOrCreateDocument(CTRL_ROOM);
|
|
5195
|
+
const awareness = ctrlDoc.getMap(Y_MAP_USER_AWARENESS);
|
|
5196
|
+
const mode = TandemModeSchema.catch(TANDEM_MODE_DEFAULT).parse(awareness.get(Y_MAP_MODE));
|
|
5197
|
+
res.json({ mode });
|
|
5198
|
+
});
|
|
5172
5199
|
app.options("/api/apply-changes", apiMiddleware);
|
|
5173
5200
|
app.post("/api/apply-changes", apiMiddleware, largeBody, async (req, res) => {
|
|
5174
5201
|
const { documentId, author, backupPath } = req.body ?? {};
|
|
@@ -5200,6 +5227,7 @@ function registerApiRoutes(app, largeBody) {
|
|
|
5200
5227
|
// src/server/mcp/awareness.ts
|
|
5201
5228
|
init_provider();
|
|
5202
5229
|
import { z as z5 } from "zod";
|
|
5230
|
+
init_types2();
|
|
5203
5231
|
init_utils();
|
|
5204
5232
|
init_constants();
|
|
5205
5233
|
init_queue();
|
|
@@ -5307,7 +5335,8 @@ function registerAwarenessTools(server) {
|
|
|
5307
5335
|
const userAwareness = doc.getMap(Y_MAP_USER_AWARENESS);
|
|
5308
5336
|
const selection = userAwareness.get("selection");
|
|
5309
5337
|
const activity = userAwareness.get("activity");
|
|
5310
|
-
const
|
|
5338
|
+
const ctrlAwareness = ctrlDoc.getMap(Y_MAP_USER_AWARENESS);
|
|
5339
|
+
const mode = TandemModeSchema.catch(TANDEM_MODE_DEFAULT).parse(ctrlAwareness.get(Y_MAP_MODE));
|
|
5311
5340
|
const hasSelection = selection && selection.from !== selection.to;
|
|
5312
5341
|
const selectedText = hasSelection ? safeSlice2(fullText, selection.from, selection.to) : null;
|
|
5313
5342
|
const parts = [];
|
|
@@ -5335,7 +5364,7 @@ function registerAwarenessTools(server) {
|
|
|
5335
5364
|
return mcpSuccess({
|
|
5336
5365
|
summary,
|
|
5337
5366
|
hasNew,
|
|
5338
|
-
|
|
5367
|
+
mode,
|
|
5339
5368
|
userActions,
|
|
5340
5369
|
userResponses,
|
|
5341
5370
|
chatMessages,
|