trellis 2.0.13 → 2.1.2
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/dist/cli/index.js +1 -1
- package/dist/embeddings/index.js +1 -1
- package/dist/{index-7gvjxt27.js → index-2917tjd8.js} +1 -1
- package/package.json +2 -10
- package/dist/transformers.node-bx3q9d7k.js +0 -33130
- package/src/cli/index.ts +0 -3356
- package/src/core/agents/harness.ts +0 -380
- package/src/core/agents/index.ts +0 -18
- package/src/core/agents/types.ts +0 -90
- package/src/core/index.ts +0 -118
- package/src/core/kernel/middleware.ts +0 -44
- package/src/core/kernel/trellis-kernel.ts +0 -593
- package/src/core/ontology/builtins.ts +0 -248
- package/src/core/ontology/index.ts +0 -34
- package/src/core/ontology/registry.ts +0 -209
- package/src/core/ontology/types.ts +0 -124
- package/src/core/ontology/validator.ts +0 -382
- package/src/core/persist/backend.ts +0 -74
- package/src/core/persist/sqlite-backend.ts +0 -298
- package/src/core/plugins/index.ts +0 -17
- package/src/core/plugins/registry.ts +0 -322
- package/src/core/plugins/types.ts +0 -126
- package/src/core/query/datalog.ts +0 -188
- package/src/core/query/engine.ts +0 -370
- package/src/core/query/index.ts +0 -34
- package/src/core/query/parser.ts +0 -481
- package/src/core/query/types.ts +0 -200
- package/src/core/store/eav-store.ts +0 -467
- package/src/decisions/auto-capture.ts +0 -136
- package/src/decisions/hooks.ts +0 -163
- package/src/decisions/index.ts +0 -261
- package/src/decisions/types.ts +0 -103
- package/src/embeddings/auto-embed.ts +0 -248
- package/src/embeddings/chunker.ts +0 -327
- package/src/embeddings/index.ts +0 -48
- package/src/embeddings/model.ts +0 -112
- package/src/embeddings/search.ts +0 -305
- package/src/embeddings/store.ts +0 -313
- package/src/embeddings/types.ts +0 -92
- package/src/engine.ts +0 -1125
- package/src/garden/cluster.ts +0 -330
- package/src/garden/garden.ts +0 -306
- package/src/garden/index.ts +0 -29
- package/src/git/git-exporter.ts +0 -286
- package/src/git/git-importer.ts +0 -329
- package/src/git/git-reader.ts +0 -189
- package/src/git/index.ts +0 -22
- package/src/identity/governance.ts +0 -211
- package/src/identity/identity.ts +0 -224
- package/src/identity/index.ts +0 -30
- package/src/identity/signing-middleware.ts +0 -97
- package/src/index.ts +0 -29
- package/src/links/index.ts +0 -49
- package/src/links/lifecycle.ts +0 -400
- package/src/links/parser.ts +0 -484
- package/src/links/ref-index.ts +0 -186
- package/src/links/resolver.ts +0 -314
- package/src/links/types.ts +0 -108
- package/src/mcp/index.ts +0 -22
- package/src/mcp/server.ts +0 -1278
- package/src/semantic/csharp-parser.ts +0 -493
- package/src/semantic/go-parser.ts +0 -585
- package/src/semantic/index.ts +0 -34
- package/src/semantic/java-parser.ts +0 -456
- package/src/semantic/python-parser.ts +0 -659
- package/src/semantic/ruby-parser.ts +0 -446
- package/src/semantic/rust-parser.ts +0 -784
- package/src/semantic/semantic-merge.ts +0 -210
- package/src/semantic/ts-parser.ts +0 -681
- package/src/semantic/types.ts +0 -175
- package/src/sync/http-transport.ts +0 -144
- package/src/sync/index.ts +0 -43
- package/src/sync/memory-transport.ts +0 -66
- package/src/sync/multi-repo.ts +0 -200
- package/src/sync/reconciler.ts +0 -237
- package/src/sync/sync-engine.ts +0 -258
- package/src/sync/types.ts +0 -104
- package/src/sync/ws-transport.ts +0 -145
- package/src/ui/client.html +0 -695
- package/src/ui/server.ts +0 -419
- package/src/vcs/blob-store.ts +0 -124
- package/src/vcs/branch.ts +0 -150
- package/src/vcs/checkpoint.ts +0 -64
- package/src/vcs/decompose.ts +0 -469
- package/src/vcs/diff.ts +0 -409
- package/src/vcs/engine-context.ts +0 -26
- package/src/vcs/index.ts +0 -23
- package/src/vcs/issue.ts +0 -800
- package/src/vcs/merge.ts +0 -425
- package/src/vcs/milestone.ts +0 -124
- package/src/vcs/ops.ts +0 -59
- package/src/vcs/types.ts +0 -213
- package/src/vcs/vcs-middleware.ts +0 -81
- package/src/watcher/fs-watcher.ts +0 -255
- package/src/watcher/index.ts +0 -9
- package/src/watcher/ingestion.ts +0 -116
package/src/semantic/types.ts
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Semantic Patching — Type Definitions
|
|
3
|
-
*
|
|
4
|
-
* DESIGN.md §4.1–4.4 — Pillar 2: Semantic Patching.
|
|
5
|
-
* Types for parser adapters, AST entities, parse results,
|
|
6
|
-
* semantic patches, and structured merge conflicts.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
// AST Entities
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
|
|
13
|
-
export interface ASTEntity {
|
|
14
|
-
/** Stable ID derived from structural signature (name + kind + scope path). */
|
|
15
|
-
id: string;
|
|
16
|
-
/** Entity type. */
|
|
17
|
-
kind: ASTEntityKind;
|
|
18
|
-
/** Human-readable name. */
|
|
19
|
-
name: string;
|
|
20
|
-
/** Scope path for disambiguation (e.g. 'MyClass.myMethod'). */
|
|
21
|
-
scopePath: string;
|
|
22
|
-
/** Byte range in source for roundtrip (start, end). */
|
|
23
|
-
span: [number, number];
|
|
24
|
-
/** Raw source text of this declaration. */
|
|
25
|
-
rawText: string;
|
|
26
|
-
/** Structural signature for identity matching (excludes whitespace/comments). */
|
|
27
|
-
signature: string;
|
|
28
|
-
/** Child entities (nested functions, inner classes, etc.). */
|
|
29
|
-
children: ASTEntity[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type ASTEntityKind =
|
|
33
|
-
| 'FunctionDef'
|
|
34
|
-
| 'ClassDef'
|
|
35
|
-
| 'InterfaceDef'
|
|
36
|
-
| 'TypeAlias'
|
|
37
|
-
| 'EnumDef'
|
|
38
|
-
| 'VariableDecl'
|
|
39
|
-
| 'MethodDef'
|
|
40
|
-
| 'PropertyDef'
|
|
41
|
-
| 'Constructor'
|
|
42
|
-
| 'Unknown';
|
|
43
|
-
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// Import / Export Relations
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
|
|
48
|
-
export interface ImportRelation {
|
|
49
|
-
source: string;
|
|
50
|
-
specifiers: string[];
|
|
51
|
-
isDefault: boolean;
|
|
52
|
-
isNamespace: boolean;
|
|
53
|
-
rawText: string;
|
|
54
|
-
span: [number, number];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface ExportRelation {
|
|
58
|
-
name: string;
|
|
59
|
-
isDefault: boolean;
|
|
60
|
-
source?: string;
|
|
61
|
-
rawText: string;
|
|
62
|
-
span: [number, number];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
|
-
// Parse Result
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
|
|
69
|
-
export interface ParseResult {
|
|
70
|
-
/** The file entity this parse belongs to. */
|
|
71
|
-
fileEntityId: string;
|
|
72
|
-
/** File path. */
|
|
73
|
-
filePath: string;
|
|
74
|
-
/** Language identifier. */
|
|
75
|
-
language: string;
|
|
76
|
-
/** Top-level declarations found in the file. */
|
|
77
|
-
declarations: ASTEntity[];
|
|
78
|
-
/** Import relationships. */
|
|
79
|
-
imports: ImportRelation[];
|
|
80
|
-
/** Export relationships. */
|
|
81
|
-
exports: ExportRelation[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
|
-
// Parser Adapter Interface
|
|
86
|
-
// ---------------------------------------------------------------------------
|
|
87
|
-
|
|
88
|
-
export interface ParserAdapter {
|
|
89
|
-
/** Languages this adapter supports. */
|
|
90
|
-
languages: string[];
|
|
91
|
-
/** Parse a source file into AST-level entities. */
|
|
92
|
-
parse(content: string, filePath: string): ParseResult;
|
|
93
|
-
/** Compute semantic patches between two parse results. */
|
|
94
|
-
diff(oldResult: ParseResult, newResult: ParseResult): SemanticPatch[];
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
// Semantic Patch Types
|
|
99
|
-
// ---------------------------------------------------------------------------
|
|
100
|
-
|
|
101
|
-
export type SemanticPatch =
|
|
102
|
-
| { kind: 'symbolAdd'; entity: ASTEntity }
|
|
103
|
-
| { kind: 'symbolRemove'; entityId: string; entityName: string }
|
|
104
|
-
| {
|
|
105
|
-
kind: 'symbolModify';
|
|
106
|
-
entityId: string;
|
|
107
|
-
entityName: string;
|
|
108
|
-
oldSignature: string;
|
|
109
|
-
newSignature: string;
|
|
110
|
-
oldRawText: string;
|
|
111
|
-
newRawText: string;
|
|
112
|
-
}
|
|
113
|
-
| {
|
|
114
|
-
kind: 'symbolRename';
|
|
115
|
-
entityId: string;
|
|
116
|
-
oldName: string;
|
|
117
|
-
newName: string;
|
|
118
|
-
}
|
|
119
|
-
| {
|
|
120
|
-
kind: 'symbolMove';
|
|
121
|
-
entityId: string;
|
|
122
|
-
entityName: string;
|
|
123
|
-
oldFile: string;
|
|
124
|
-
newFile: string;
|
|
125
|
-
}
|
|
126
|
-
| {
|
|
127
|
-
kind: 'importAdd';
|
|
128
|
-
fileId: string;
|
|
129
|
-
source: string;
|
|
130
|
-
specifiers: string[];
|
|
131
|
-
rawText: string;
|
|
132
|
-
}
|
|
133
|
-
| {
|
|
134
|
-
kind: 'importRemove';
|
|
135
|
-
fileId: string;
|
|
136
|
-
source: string;
|
|
137
|
-
}
|
|
138
|
-
| {
|
|
139
|
-
kind: 'importModify';
|
|
140
|
-
fileId: string;
|
|
141
|
-
source: string;
|
|
142
|
-
oldSpecifiers: string[];
|
|
143
|
-
newSpecifiers: string[];
|
|
144
|
-
}
|
|
145
|
-
| {
|
|
146
|
-
kind: 'exportAdd';
|
|
147
|
-
fileId: string;
|
|
148
|
-
name: string;
|
|
149
|
-
rawText: string;
|
|
150
|
-
}
|
|
151
|
-
| {
|
|
152
|
-
kind: 'exportRemove';
|
|
153
|
-
fileId: string;
|
|
154
|
-
name: string;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// ---------------------------------------------------------------------------
|
|
158
|
-
// Semantic Merge Conflict
|
|
159
|
-
// ---------------------------------------------------------------------------
|
|
160
|
-
|
|
161
|
-
export interface SemanticMergeConflict {
|
|
162
|
-
entityId: string;
|
|
163
|
-
entityName: string;
|
|
164
|
-
entityKind: string;
|
|
165
|
-
filePath: string;
|
|
166
|
-
ours: SemanticPatch;
|
|
167
|
-
theirs: SemanticPatch;
|
|
168
|
-
suggestion?: 'accept-ours' | 'accept-theirs' | 'combine';
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export interface SemanticMergeResult {
|
|
172
|
-
clean: boolean;
|
|
173
|
-
patches: SemanticPatch[];
|
|
174
|
-
conflicts: SemanticMergeConflict[];
|
|
175
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP Sync Transport
|
|
3
|
-
*
|
|
4
|
-
* Implements SyncTransport over HTTP for network-based peer sync.
|
|
5
|
-
* Uses a simple JSON REST protocol:
|
|
6
|
-
* POST /sync/message — send a sync message
|
|
7
|
-
* GET /sync/peers — list connected peers
|
|
8
|
-
*
|
|
9
|
-
* The server side is a lightweight Bun HTTP server.
|
|
10
|
-
* The client side uses fetch() for outbound messages.
|
|
11
|
-
*
|
|
12
|
-
* @module trellis/sync
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { SyncTransport, SyncMessage, PeerId } from './types.js';
|
|
16
|
-
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
// HTTP Transport (Client)
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
|
|
21
|
-
export class HttpSyncTransport implements SyncTransport {
|
|
22
|
-
private localPeerId: string;
|
|
23
|
-
private peerUrls: Map<string, string> = new Map();
|
|
24
|
-
private messageHandler: ((msg: SyncMessage) => void) | null = null;
|
|
25
|
-
private knownPeers: Map<string, PeerId> = new Map();
|
|
26
|
-
|
|
27
|
-
constructor(localPeerId: string) {
|
|
28
|
-
this.localPeerId = localPeerId;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Add a remote peer by URL (e.g. "http://192.168.1.10:4200").
|
|
33
|
-
*/
|
|
34
|
-
addPeer(peerId: string, url: string, name?: string): void {
|
|
35
|
-
this.peerUrls.set(peerId, url);
|
|
36
|
-
this.knownPeers.set(peerId, {
|
|
37
|
-
id: peerId,
|
|
38
|
-
name: name ?? peerId,
|
|
39
|
-
lastSeen: new Date().toISOString(),
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Remove a remote peer.
|
|
45
|
-
*/
|
|
46
|
-
removePeer(peerId: string): void {
|
|
47
|
-
this.peerUrls.delete(peerId);
|
|
48
|
-
this.knownPeers.delete(peerId);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async send(peerId: string, message: SyncMessage): Promise<void> {
|
|
52
|
-
const url = this.peerUrls.get(peerId);
|
|
53
|
-
if (!url) throw new Error(`Unknown peer "${peerId}". Add it with addPeer() first.`);
|
|
54
|
-
|
|
55
|
-
const resp = await fetch(`${url}/sync/message`, {
|
|
56
|
-
method: 'POST',
|
|
57
|
-
headers: { 'Content-Type': 'application/json' },
|
|
58
|
-
body: JSON.stringify(message),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
if (!resp.ok) {
|
|
62
|
-
throw new Error(`Sync message to ${peerId} failed: ${resp.status} ${resp.statusText}`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Check if the response contains a reply message
|
|
66
|
-
const contentType = resp.headers.get('content-type');
|
|
67
|
-
if (contentType?.includes('application/json')) {
|
|
68
|
-
const reply = await resp.json();
|
|
69
|
-
if (reply && reply.type && this.messageHandler) {
|
|
70
|
-
this.messageHandler(reply as SyncMessage);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
onMessage(handler: (message: SyncMessage) => void): void {
|
|
76
|
-
this.messageHandler = handler;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Receive a message (called by the HTTP server handler).
|
|
81
|
-
*/
|
|
82
|
-
receiveMessage(message: SyncMessage): void {
|
|
83
|
-
// Track peer
|
|
84
|
-
this.knownPeers.set(message.peerId, {
|
|
85
|
-
id: message.peerId,
|
|
86
|
-
name: message.peerId,
|
|
87
|
-
lastSeen: new Date().toISOString(),
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
if (this.messageHandler) {
|
|
91
|
-
this.messageHandler(message);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
peers(): PeerId[] {
|
|
96
|
-
return [...this.knownPeers.values()];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
getLocalPeerId(): string {
|
|
100
|
-
return this.localPeerId;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ---------------------------------------------------------------------------
|
|
105
|
-
// HTTP Sync Server (creates Bun.serve handler)
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
|
|
108
|
-
export interface HttpSyncServerConfig {
|
|
109
|
-
port: number;
|
|
110
|
-
transport: HttpSyncTransport;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Create a Bun-compatible HTTP request handler for sync messages.
|
|
115
|
-
* Can be used with Bun.serve() or as middleware.
|
|
116
|
-
*/
|
|
117
|
-
export function createSyncHandler(transport: HttpSyncTransport): (req: Request) => Response | null {
|
|
118
|
-
return (req: Request): Response | null => {
|
|
119
|
-
const url = new URL(req.url);
|
|
120
|
-
|
|
121
|
-
if (url.pathname === '/sync/message' && req.method === 'POST') {
|
|
122
|
-
// Handle async parsing synchronously for Bun
|
|
123
|
-
return new Response(
|
|
124
|
-
req.json().then((body: any) => {
|
|
125
|
-
transport.receiveMessage(body as SyncMessage);
|
|
126
|
-
return JSON.stringify({ ok: true });
|
|
127
|
-
}) as any,
|
|
128
|
-
{ headers: { 'Content-Type': 'application/json' } },
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (url.pathname === '/sync/peers' && req.method === 'GET') {
|
|
133
|
-
return new Response(
|
|
134
|
-
JSON.stringify({
|
|
135
|
-
localPeerId: transport.getLocalPeerId(),
|
|
136
|
-
peers: transport.peers(),
|
|
137
|
-
}),
|
|
138
|
-
{ headers: { 'Content-Type': 'application/json' } },
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return null; // Not a sync route
|
|
143
|
-
};
|
|
144
|
-
}
|
package/src/sync/index.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sync Module — Public Surface
|
|
3
|
-
*
|
|
4
|
-
* @module sync
|
|
5
|
-
*
|
|
6
|
-
* Re-exports the CRDT {@link reconcile|reconciler}, {@link SyncEngine} for
|
|
7
|
-
* the have→want→ops→ack protocol, and {@link MemoryTransport} for testing.
|
|
8
|
-
* Branch policies control whether sync uses linear (fast-forward) or
|
|
9
|
-
* CRDT (concurrent append) mode.
|
|
10
|
-
*
|
|
11
|
-
* @see DESIGN.md §3.5 for the branch concurrency model.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export type {
|
|
15
|
-
PeerId,
|
|
16
|
-
SyncMessage,
|
|
17
|
-
SyncHaveMessage,
|
|
18
|
-
SyncWantMessage,
|
|
19
|
-
SyncOpsMessage,
|
|
20
|
-
SyncAckMessage,
|
|
21
|
-
SyncState,
|
|
22
|
-
BranchPolicy,
|
|
23
|
-
SyncTransport,
|
|
24
|
-
} from './types.js';
|
|
25
|
-
|
|
26
|
-
export { reconcile, findForkPoint } from './reconciler.js';
|
|
27
|
-
|
|
28
|
-
export type { ReconcileResult, ReconcileConflict } from './reconciler.js';
|
|
29
|
-
|
|
30
|
-
export { SyncEngine } from './sync-engine.js';
|
|
31
|
-
|
|
32
|
-
export { MemoryTransport } from './memory-transport.js';
|
|
33
|
-
|
|
34
|
-
export { HttpSyncTransport, createSyncHandler } from './http-transport.js';
|
|
35
|
-
|
|
36
|
-
export { WebSocketSyncTransport } from './ws-transport.js';
|
|
37
|
-
|
|
38
|
-
export {
|
|
39
|
-
MultiRepoManager,
|
|
40
|
-
parseCrossRepoRef,
|
|
41
|
-
formatCrossRepoRef,
|
|
42
|
-
} from './multi-repo.js';
|
|
43
|
-
export type { LinkedRepo, CrossRepoRef } from './multi-repo.js';
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-Memory Sync Transport
|
|
3
|
-
*
|
|
4
|
-
* A simple in-memory transport for testing and local multi-engine sync.
|
|
5
|
-
* Messages are delivered synchronously between connected peers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { SyncTransport, SyncMessage, PeerId } from './types.js';
|
|
9
|
-
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// In-memory transport
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
export class MemoryTransport implements SyncTransport {
|
|
15
|
-
private peerId: string;
|
|
16
|
-
private peerName: string;
|
|
17
|
-
private handlers: ((message: SyncMessage) => void)[] = [];
|
|
18
|
-
private connectedPeers: Map<string, MemoryTransport> = new Map();
|
|
19
|
-
|
|
20
|
-
constructor(peerId: string, peerName: string = peerId) {
|
|
21
|
-
this.peerId = peerId;
|
|
22
|
-
this.peerName = peerName;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Connect two transports so they can exchange messages.
|
|
27
|
-
*/
|
|
28
|
-
static connect(a: MemoryTransport, b: MemoryTransport): void {
|
|
29
|
-
a.connectedPeers.set(b.peerId, b);
|
|
30
|
-
b.connectedPeers.set(a.peerId, a);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Disconnect two transports.
|
|
35
|
-
*/
|
|
36
|
-
static disconnect(a: MemoryTransport, b: MemoryTransport): void {
|
|
37
|
-
a.connectedPeers.delete(b.peerId);
|
|
38
|
-
b.connectedPeers.delete(a.peerId);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async send(peerId: string, message: SyncMessage): Promise<void> {
|
|
42
|
-
const peer = this.connectedPeers.get(peerId);
|
|
43
|
-
if (!peer) {
|
|
44
|
-
throw new Error(`Peer not connected: ${peerId}`);
|
|
45
|
-
}
|
|
46
|
-
// Deliver to peer's handlers
|
|
47
|
-
for (const handler of peer.handlers) {
|
|
48
|
-
handler(message);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
onMessage(handler: (message: SyncMessage) => void): void {
|
|
53
|
-
this.handlers.push(handler);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
peers(): PeerId[] {
|
|
57
|
-
return [...this.connectedPeers.entries()].map(([id, transport]) => ({
|
|
58
|
-
id,
|
|
59
|
-
name: transport.peerName,
|
|
60
|
-
}));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
getPeerId(): string {
|
|
64
|
-
return this.peerId;
|
|
65
|
-
}
|
|
66
|
-
}
|
package/src/sync/multi-repo.ts
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Multi-Repo Linking — Cross-repo entity references.
|
|
3
|
-
*
|
|
4
|
-
* Enables entities in one Trellis repo to reference entities in another.
|
|
5
|
-
* Linked repos are registered with a local alias and remote path/URL.
|
|
6
|
-
* Cross-repo references use the format: `@alias:entityId`
|
|
7
|
-
*
|
|
8
|
-
* @module trellis/sync
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { TrellisKernel } from '../core/kernel/trellis-kernel.js';
|
|
12
|
-
import type { Fact, Link } from '../core/store/eav-store.js';
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Types
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
export interface LinkedRepo {
|
|
19
|
-
/** Local alias for the remote repo (e.g. "backend", "shared-lib"). */
|
|
20
|
-
alias: string;
|
|
21
|
-
/** Path or URL to the remote repo. */
|
|
22
|
-
location: string;
|
|
23
|
-
/** Optional human-readable description. */
|
|
24
|
-
description?: string;
|
|
25
|
-
/** When this link was established. */
|
|
26
|
-
linkedAt: string;
|
|
27
|
-
/** Last sync timestamp. */
|
|
28
|
-
lastSyncedAt?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface CrossRepoRef {
|
|
32
|
-
/** The repo alias. */
|
|
33
|
-
repoAlias: string;
|
|
34
|
-
/** The entity ID in the remote repo. */
|
|
35
|
-
entityId: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
// Multi-Repo Manager
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
|
|
42
|
-
export class MultiRepoManager {
|
|
43
|
-
private kernel: TrellisKernel;
|
|
44
|
-
|
|
45
|
-
constructor(kernel: TrellisKernel) {
|
|
46
|
-
this.kernel = kernel;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Link a remote repository.
|
|
51
|
-
*/
|
|
52
|
-
async linkRepo(alias: string, location: string, description?: string): Promise<void> {
|
|
53
|
-
const id = `repo:${alias}`;
|
|
54
|
-
const existing = this.kernel.getEntity(id);
|
|
55
|
-
if (existing) {
|
|
56
|
-
throw new Error(`Repo alias "${alias}" is already linked to "${existing.facts.find(f => f.a === 'location')?.v}".`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
await this.kernel.createEntity(id, 'LinkedRepo', {
|
|
60
|
-
alias,
|
|
61
|
-
location,
|
|
62
|
-
...(description ? { description } : {}),
|
|
63
|
-
linkedAt: new Date().toISOString(),
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Unlink a remote repository.
|
|
69
|
-
*/
|
|
70
|
-
async unlinkRepo(alias: string): Promise<void> {
|
|
71
|
-
const id = `repo:${alias}`;
|
|
72
|
-
await this.kernel.deleteEntity(id);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* List all linked repos.
|
|
77
|
-
*/
|
|
78
|
-
listLinkedRepos(): LinkedRepo[] {
|
|
79
|
-
const entities = this.kernel.listEntities('LinkedRepo');
|
|
80
|
-
return entities.map((e) => {
|
|
81
|
-
const get = (a: string) => e.facts.find((f) => f.a === a)?.v;
|
|
82
|
-
return {
|
|
83
|
-
alias: String(get('alias') ?? ''),
|
|
84
|
-
location: String(get('location') ?? ''),
|
|
85
|
-
description: get('description') as string | undefined,
|
|
86
|
-
linkedAt: String(get('linkedAt') ?? ''),
|
|
87
|
-
lastSyncedAt: get('lastSyncedAt') as string | undefined,
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Get a linked repo by alias.
|
|
94
|
-
*/
|
|
95
|
-
getLinkedRepo(alias: string): LinkedRepo | null {
|
|
96
|
-
const entity = this.kernel.getEntity(`repo:${alias}`);
|
|
97
|
-
if (!entity) return null;
|
|
98
|
-
const get = (a: string) => entity.facts.find((f) => f.a === a)?.v;
|
|
99
|
-
return {
|
|
100
|
-
alias: String(get('alias') ?? ''),
|
|
101
|
-
location: String(get('location') ?? ''),
|
|
102
|
-
description: get('description') as string | undefined,
|
|
103
|
-
linkedAt: String(get('linkedAt') ?? ''),
|
|
104
|
-
lastSyncedAt: get('lastSyncedAt') as string | undefined,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Create a cross-repo link: entity in this repo → entity in remote repo.
|
|
110
|
-
*/
|
|
111
|
-
async addCrossRepoLink(
|
|
112
|
-
sourceEntityId: string,
|
|
113
|
-
attribute: string,
|
|
114
|
-
targetRepoAlias: string,
|
|
115
|
-
targetEntityId: string,
|
|
116
|
-
): Promise<void> {
|
|
117
|
-
const repo = this.getLinkedRepo(targetRepoAlias);
|
|
118
|
-
if (!repo) {
|
|
119
|
-
throw new Error(`Repo alias "${targetRepoAlias}" is not linked. Use linkRepo() first.`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const crossRef = `@${targetRepoAlias}:${targetEntityId}`;
|
|
123
|
-
await this.kernel.addLink(sourceEntityId, attribute, crossRef);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Remove a cross-repo link.
|
|
128
|
-
*/
|
|
129
|
-
async removeCrossRepoLink(
|
|
130
|
-
sourceEntityId: string,
|
|
131
|
-
attribute: string,
|
|
132
|
-
targetRepoAlias: string,
|
|
133
|
-
targetEntityId: string,
|
|
134
|
-
): Promise<void> {
|
|
135
|
-
const crossRef = `@${targetRepoAlias}:${targetEntityId}`;
|
|
136
|
-
await this.kernel.removeLink(sourceEntityId, attribute, crossRef);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Find all cross-repo references from a given entity.
|
|
141
|
-
*/
|
|
142
|
-
getCrossRepoLinks(entityId: string): Array<{ attribute: string; ref: CrossRepoRef }> {
|
|
143
|
-
const store = this.kernel.getStore();
|
|
144
|
-
const links = store.getLinksByEntity(entityId);
|
|
145
|
-
const results: Array<{ attribute: string; ref: CrossRepoRef }> = [];
|
|
146
|
-
|
|
147
|
-
for (const link of links) {
|
|
148
|
-
if (link.e1 !== entityId) continue;
|
|
149
|
-
const parsed = parseCrossRepoRef(link.e2);
|
|
150
|
-
if (parsed) {
|
|
151
|
-
results.push({ attribute: link.a, ref: parsed });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return results;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Find all cross-repo references pointing to a specific remote entity.
|
|
160
|
-
*/
|
|
161
|
-
findReferencesTo(repoAlias: string, entityId: string): Link[] {
|
|
162
|
-
const crossRef = `@${repoAlias}:${entityId}`;
|
|
163
|
-
const store = this.kernel.getStore();
|
|
164
|
-
return store.getAllLinks().filter((l) => l.e2 === crossRef);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Update the lastSyncedAt timestamp for a linked repo.
|
|
169
|
-
*/
|
|
170
|
-
async markSynced(alias: string): Promise<void> {
|
|
171
|
-
await this.kernel.updateEntity(`repo:${alias}`, {
|
|
172
|
-
lastSyncedAt: new Date().toISOString(),
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// ---------------------------------------------------------------------------
|
|
178
|
-
// Helpers
|
|
179
|
-
// ---------------------------------------------------------------------------
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Parse a cross-repo reference string.
|
|
183
|
-
* Format: `@alias:entityId`
|
|
184
|
-
*/
|
|
185
|
-
export function parseCrossRepoRef(ref: string): CrossRepoRef | null {
|
|
186
|
-
if (!ref.startsWith('@')) return null;
|
|
187
|
-
const colonIdx = ref.indexOf(':', 1);
|
|
188
|
-
if (colonIdx === -1) return null;
|
|
189
|
-
return {
|
|
190
|
-
repoAlias: ref.slice(1, colonIdx),
|
|
191
|
-
entityId: ref.slice(colonIdx + 1),
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Format a cross-repo reference string.
|
|
197
|
-
*/
|
|
198
|
-
export function formatCrossRepoRef(repoAlias: string, entityId: string): string {
|
|
199
|
-
return `@${repoAlias}:${entityId}`;
|
|
200
|
-
}
|