@principal-ai/principal-view-core 0.28.12 → 0.28.13
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/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/opencode/agent-sessions.d.ts +4 -4
- package/dist/opencode/agent-sessions.d.ts.map +1 -1
- package/dist/opencode/agent-sessions.js +40 -0
- package/dist/opencode/agent-sessions.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/subsystem-graph.d.ts +259 -0
- package/dist/types/subsystem-graph.d.ts.map +1 -0
- package/dist/types/subsystem-graph.js +35 -0
- package/dist/types/subsystem-graph.js.map +1 -0
- package/package.json +3 -3
- package/schemas/auxiliary.manifest.schema.json +13 -5
- package/schemas/subsystem-graph.schema.json +762 -0
- package/src/index.ts +22 -0
- package/src/opencode/agent-sessions.ts +45 -3
- package/src/types/index.ts +1 -0
- package/src/types/subsystem-graph.ts +346 -0
package/src/index.ts
CHANGED
|
@@ -55,11 +55,33 @@ export type {
|
|
|
55
55
|
JsonObject,
|
|
56
56
|
ProjectArea,
|
|
57
57
|
AuxiliaryManifest,
|
|
58
|
+
SubsystemConstruct,
|
|
59
|
+
SubsystemComponentRole,
|
|
60
|
+
SubsystemFramework,
|
|
61
|
+
SubsystemStereotype,
|
|
62
|
+
SubsystemEdgeMechanism,
|
|
63
|
+
SubsystemCapture,
|
|
64
|
+
SubsystemDeclarationProvenance,
|
|
65
|
+
SubsystemDeclTokenKind,
|
|
66
|
+
SubsystemDeclToken,
|
|
67
|
+
SubsystemDeclarationRef,
|
|
68
|
+
SubsystemConstructDeclaration,
|
|
69
|
+
SubsystemComponent,
|
|
70
|
+
SubsystemComponentEdge,
|
|
71
|
+
SubsystemThroughlineStep,
|
|
72
|
+
SubsystemThroughline,
|
|
73
|
+
SubsystemRepoRef,
|
|
74
|
+
SubsystemGraphDocument,
|
|
75
|
+
SubsystemGraphHostBinding,
|
|
76
|
+
SubsystemGraphHydrated,
|
|
58
77
|
} from './types';
|
|
59
78
|
|
|
60
79
|
// Auxiliary manifest type guard (browser-safe runtime helper)
|
|
61
80
|
export { isAuxiliaryManifest } from './types/auxiliary';
|
|
62
81
|
|
|
82
|
+
// Subsystem graph type guard (browser-safe runtime helper)
|
|
83
|
+
export { isSubsystemGraphDocument } from './types/subsystem-graph';
|
|
84
|
+
|
|
63
85
|
// Export path-based configuration types (browser-safe)
|
|
64
86
|
export type { PathBasedGraphConfiguration } from './types/path-based-config';
|
|
65
87
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClineSessionReader,
|
|
3
3
|
CodexSessionReader,
|
|
4
|
+
CursorSessionReader,
|
|
4
5
|
GrokSessionReader,
|
|
5
6
|
PiSessionReader,
|
|
6
7
|
type UniversalAgentSessionEvent,
|
|
@@ -36,6 +37,7 @@ export {
|
|
|
36
37
|
export type SupportedSessionAgent =
|
|
37
38
|
| "cline"
|
|
38
39
|
| "codex"
|
|
40
|
+
| "cursor"
|
|
39
41
|
| "opencode"
|
|
40
42
|
| "pi"
|
|
41
43
|
| "grok"
|
|
@@ -62,6 +64,7 @@ const clineReader = new ClineSessionReader();
|
|
|
62
64
|
const piReader = new PiSessionReader();
|
|
63
65
|
const grokReader = new GrokSessionReader();
|
|
64
66
|
const codexReader = new CodexSessionReader();
|
|
67
|
+
const cursorReader = new CursorSessionReader();
|
|
65
68
|
|
|
66
69
|
function isClineSession(sessionId: string): boolean {
|
|
67
70
|
return clineReader.readSession(sessionId) !== null;
|
|
@@ -79,6 +82,10 @@ function isCodexSession(sessionId: string): boolean {
|
|
|
79
82
|
return codexReader.readSession(sessionId) !== null;
|
|
80
83
|
}
|
|
81
84
|
|
|
85
|
+
function isCursorSession(sessionId: string): boolean {
|
|
86
|
+
return cursorReader.readSession(sessionId) !== null;
|
|
87
|
+
}
|
|
88
|
+
|
|
82
89
|
/** List Cline CLI sessions from the durable on-disk transcript. */
|
|
83
90
|
function listClineSessions(): AgentSessionSummary[] {
|
|
84
91
|
return clineReader.listSessions().map((record) => {
|
|
@@ -154,6 +161,18 @@ function listCodexSessions(): AgentSessionSummary[] {
|
|
|
154
161
|
}));
|
|
155
162
|
}
|
|
156
163
|
|
|
164
|
+
/** List Cursor IDE agent chats from ~/.cursor/chats. */
|
|
165
|
+
function listCursorSessions(): AgentSessionSummary[] {
|
|
166
|
+
return cursorReader.listSessions().map((record) => ({
|
|
167
|
+
agent: "cursor" as const,
|
|
168
|
+
sessionId: record.sessionId,
|
|
169
|
+
title: record.title || "Cursor session",
|
|
170
|
+
createdAt: record.createdAt || new Date(record.lastActivity).toISOString(),
|
|
171
|
+
eventCount: record.messageCount,
|
|
172
|
+
isFinished: false,
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
|
|
157
176
|
/**
|
|
158
177
|
* List opencode sessions, top-level only by default. Delegates to the store's
|
|
159
178
|
* grouped `listSessionsWithSummaries()` which excludes subagent (child) sessions.
|
|
@@ -220,6 +239,11 @@ export function listAgentSessions(
|
|
|
220
239
|
} catch (err) {
|
|
221
240
|
if (!firstError) firstError = err as Error;
|
|
222
241
|
}
|
|
242
|
+
try {
|
|
243
|
+
all.push(...listCursorSessions());
|
|
244
|
+
} catch (err) {
|
|
245
|
+
if (!firstError) firstError = err as Error;
|
|
246
|
+
}
|
|
223
247
|
if (all.length === 0 && firstError) {
|
|
224
248
|
throw firstError;
|
|
225
249
|
}
|
|
@@ -229,11 +253,12 @@ export function listAgentSessions(
|
|
|
229
253
|
/** Detect which agent a session id belongs to. */
|
|
230
254
|
export function detectAgent(
|
|
231
255
|
sessionId: string,
|
|
232
|
-
): "cline" | "opencode" | "pi" | "grok" | "codex" {
|
|
256
|
+
): "cline" | "opencode" | "pi" | "grok" | "codex" | "cursor" {
|
|
233
257
|
if (isClineSession(sessionId)) return "cline";
|
|
234
258
|
if (isPiSession(sessionId)) return "pi";
|
|
235
259
|
if (isGrokSession(sessionId)) return "grok";
|
|
236
260
|
if (isCodexSession(sessionId)) return "codex";
|
|
261
|
+
if (isCursorSession(sessionId)) return "cursor";
|
|
237
262
|
return "opencode";
|
|
238
263
|
}
|
|
239
264
|
|
|
@@ -243,11 +268,11 @@ export function detectAgent(
|
|
|
243
268
|
export function fetchRawEvents(
|
|
244
269
|
sessionId: string,
|
|
245
270
|
options: {
|
|
246
|
-
agent?: "cline" | "codex" | "opencode" | "pi" | "grok";
|
|
271
|
+
agent?: "cline" | "codex" | "cursor" | "opencode" | "pi" | "grok";
|
|
247
272
|
dbPath?: string;
|
|
248
273
|
} = {},
|
|
249
274
|
): {
|
|
250
|
-
agent: "cline" | "codex" | "opencode" | "pi" | "grok";
|
|
275
|
+
agent: "cline" | "codex" | "cursor" | "opencode" | "pi" | "grok";
|
|
251
276
|
events: UniversalAgentSessionEvent[];
|
|
252
277
|
sessionMeta: AgentSessionMeta;
|
|
253
278
|
} {
|
|
@@ -313,6 +338,23 @@ export function fetchRawEvents(
|
|
|
313
338
|
},
|
|
314
339
|
};
|
|
315
340
|
}
|
|
341
|
+
if (agent === "cursor") {
|
|
342
|
+
const record = cursorReader.readSession(sessionId);
|
|
343
|
+
const promptText = (record?.firstPrompt ?? "").trim();
|
|
344
|
+
return {
|
|
345
|
+
agent,
|
|
346
|
+
events: cursorReader.toUniversalEvents(sessionId),
|
|
347
|
+
sessionMeta: {
|
|
348
|
+
sessionName: "cursor",
|
|
349
|
+
sessionTask:
|
|
350
|
+
record?.title ||
|
|
351
|
+
(promptText.length > 80 ? `${promptText.slice(0, 80)}…` : promptText) ||
|
|
352
|
+
"Cursor session",
|
|
353
|
+
workingDirectory: record?.cwd ?? "",
|
|
354
|
+
createdAt: record?.createdAt,
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
}
|
|
316
358
|
const store = new OpenCodeEventStore({ dbPath: options.dbPath });
|
|
317
359
|
try {
|
|
318
360
|
const { events } = store.readAggregate(sessionId, { limit: 10000 });
|
package/src/types/index.ts
CHANGED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subsystem Graph Types
|
|
3
|
+
*
|
|
4
|
+
* Two layers — do not conflate them:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Portable document** (`SubsystemGraphDocument`) — the shareable standard.
|
|
7
|
+
* Schema: `schemas/subsystem-graph.schema.json`
|
|
8
|
+
* (`https://principal-ai.dev/schemas/subsystem-graph.schema.json`).
|
|
9
|
+
*
|
|
10
|
+
* 2. **Hydrated envelope** (`SubsystemGraphHydrated`) — portable document plus
|
|
11
|
+
* host/machine binding (local roots, provenance, store ids, verification).
|
|
12
|
+
* Used by viewers and stores; not part of the portable standard.
|
|
13
|
+
*
|
|
14
|
+
* Ontology: construct = what a node is, framework + stereotype = which
|
|
15
|
+
* framework pattern it plays, role = where it sits, process = where it runs.
|
|
16
|
+
* `symbol` is the code identity; `name` is the display label.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** What the node IS as a declaration. `module` is not an authored construct —
|
|
20
|
+
* a module is its own subsystem. */
|
|
21
|
+
export type SubsystemConstruct =
|
|
22
|
+
| 'class'
|
|
23
|
+
| 'function'
|
|
24
|
+
| 'method'
|
|
25
|
+
| 'interface'
|
|
26
|
+
| 'type_alias'
|
|
27
|
+
| 'enum'
|
|
28
|
+
| 'store'
|
|
29
|
+
| 'external';
|
|
30
|
+
|
|
31
|
+
/** Where the node sits in the topology, orthogonal to construct. */
|
|
32
|
+
export type SubsystemComponentRole = 'entry' | 'service';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Framework that owns a stereotype vocabulary (open string).
|
|
36
|
+
* Examples: `react`, `vue`, `nestjs`, `django`, `spring`.
|
|
37
|
+
* Empty when the node is language-only / framework-agnostic.
|
|
38
|
+
*/
|
|
39
|
+
export type SubsystemFramework = string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Framework-level pattern stamped on a language construct (open string).
|
|
43
|
+
* Examples: `component`, `hook`, `middleware`, `controller`, `guard`.
|
|
44
|
+
* Empty when no framework pattern applies. Pair with `framework` when set.
|
|
45
|
+
*/
|
|
46
|
+
export type SubsystemStereotype = string;
|
|
47
|
+
|
|
48
|
+
/** How `from` relates to `to` on an edge. */
|
|
49
|
+
export type SubsystemEdgeMechanism =
|
|
50
|
+
| 'imports'
|
|
51
|
+
| 'imports_from'
|
|
52
|
+
| 're_exports'
|
|
53
|
+
| 'defines'
|
|
54
|
+
| 'calls'
|
|
55
|
+
| 'extends'
|
|
56
|
+
| 'inherits'
|
|
57
|
+
| 'implements'
|
|
58
|
+
| 'mixes_in'
|
|
59
|
+
| 'uses'
|
|
60
|
+
| 'method'
|
|
61
|
+
| 'references'
|
|
62
|
+
| 'contains'
|
|
63
|
+
| 'feeds'
|
|
64
|
+
| 'produces'
|
|
65
|
+
| 'writes'
|
|
66
|
+
| 'reads'
|
|
67
|
+
| 'watches'
|
|
68
|
+
| 'registers-into';
|
|
69
|
+
|
|
70
|
+
export type SubsystemCapture = 'edited' | 'analyzed' | 'referenced';
|
|
71
|
+
|
|
72
|
+
export type SubsystemDeclarationProvenance = 'verified' | 'authored';
|
|
73
|
+
|
|
74
|
+
export type SubsystemDeclTokenKind =
|
|
75
|
+
| 'keyword'
|
|
76
|
+
| 'name'
|
|
77
|
+
| 'member'
|
|
78
|
+
| 'type'
|
|
79
|
+
| 'punctuation'
|
|
80
|
+
| 'string'
|
|
81
|
+
| 'newline';
|
|
82
|
+
|
|
83
|
+
export interface SubsystemDeclToken {
|
|
84
|
+
text: string;
|
|
85
|
+
kind: SubsystemDeclTokenKind;
|
|
86
|
+
/** Optional foreground when pre-tokenized for a theme. */
|
|
87
|
+
color?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Anchored declaration location (usually from verify tooling). */
|
|
91
|
+
export interface SubsystemDeclarationRef {
|
|
92
|
+
file: string;
|
|
93
|
+
startLine: number;
|
|
94
|
+
lineHash: string;
|
|
95
|
+
graphifyNodeId?: string;
|
|
96
|
+
capturedAt: string;
|
|
97
|
+
revision?: {
|
|
98
|
+
headSha: string;
|
|
99
|
+
dirtyHash?: string | null;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface SubsystemParamInfo {
|
|
104
|
+
name?: string;
|
|
105
|
+
type: string;
|
|
106
|
+
ref?: SubsystemReferenceInfo;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface SubsystemPropertyInfo {
|
|
110
|
+
name: string;
|
|
111
|
+
type?: string;
|
|
112
|
+
typeRef?: SubsystemReferenceInfo;
|
|
113
|
+
nodeId?: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface SubsystemMethodInfo {
|
|
117
|
+
nodeId: string;
|
|
118
|
+
name: string;
|
|
119
|
+
parameters?: SubsystemParamInfo[];
|
|
120
|
+
returnType?: string;
|
|
121
|
+
returnTypeRef?: SubsystemReferenceInfo;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface SubsystemCallInfo {
|
|
125
|
+
nodeId: string;
|
|
126
|
+
name: string;
|
|
127
|
+
source_location?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface SubsystemReferenceInfo {
|
|
131
|
+
nodeId: string;
|
|
132
|
+
name: string;
|
|
133
|
+
context?: string;
|
|
134
|
+
source_location?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface SubsystemImportInfo {
|
|
138
|
+
nodeId: string;
|
|
139
|
+
name: string;
|
|
140
|
+
relation?: string;
|
|
141
|
+
source_location?: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface SubsystemClassDeclaration {
|
|
145
|
+
kind: 'class';
|
|
146
|
+
methods: SubsystemMethodInfo[];
|
|
147
|
+
properties: SubsystemPropertyInfo[];
|
|
148
|
+
extends: string[];
|
|
149
|
+
implements: string[];
|
|
150
|
+
instantiations: SubsystemCallInfo[];
|
|
151
|
+
references: SubsystemReferenceInfo[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface SubsystemFunctionDeclaration {
|
|
155
|
+
kind: 'function';
|
|
156
|
+
parameters: SubsystemParamInfo[];
|
|
157
|
+
returnType?: string;
|
|
158
|
+
returnTypeRef?: SubsystemReferenceInfo;
|
|
159
|
+
callers: SubsystemCallInfo[];
|
|
160
|
+
callees: SubsystemCallInfo[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface SubsystemMethodDeclaration {
|
|
164
|
+
kind: 'method';
|
|
165
|
+
hostClass: string;
|
|
166
|
+
parameters?: SubsystemParamInfo[];
|
|
167
|
+
returnType?: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface SubsystemTypeDeclaration {
|
|
171
|
+
kind: 'type';
|
|
172
|
+
properties: SubsystemPropertyInfo[];
|
|
173
|
+
usedBy: SubsystemReferenceInfo[];
|
|
174
|
+
implementors: string[];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface SubsystemModuleDeclaration {
|
|
178
|
+
kind: 'module';
|
|
179
|
+
exports: string[];
|
|
180
|
+
imports: SubsystemImportInfo[];
|
|
181
|
+
symbols: string[];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface SubsystemExternalDeclaration {
|
|
185
|
+
kind: 'external';
|
|
186
|
+
label: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface SubsystemStoreDeclaration {
|
|
190
|
+
kind: 'store';
|
|
191
|
+
properties: SubsystemPropertyInfo[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Structured declaration shape of a construct. */
|
|
195
|
+
export type SubsystemConstructDeclaration =
|
|
196
|
+
| SubsystemClassDeclaration
|
|
197
|
+
| SubsystemFunctionDeclaration
|
|
198
|
+
| SubsystemMethodDeclaration
|
|
199
|
+
| SubsystemTypeDeclaration
|
|
200
|
+
| SubsystemModuleDeclaration
|
|
201
|
+
| SubsystemExternalDeclaration
|
|
202
|
+
| SubsystemStoreDeclaration;
|
|
203
|
+
|
|
204
|
+
/** A component node — the named unit, construct-tagged. */
|
|
205
|
+
export interface SubsystemComponent {
|
|
206
|
+
id: string;
|
|
207
|
+
/** Display label. Prefer aligning with `symbol` when present. */
|
|
208
|
+
name: string;
|
|
209
|
+
construct: SubsystemConstruct;
|
|
210
|
+
/** Repo-root-relative source path. */
|
|
211
|
+
file: string;
|
|
212
|
+
/** PURL for repo/package grouping. */
|
|
213
|
+
purl: string;
|
|
214
|
+
purpose?: string;
|
|
215
|
+
role?: SubsystemComponentRole;
|
|
216
|
+
/**
|
|
217
|
+
* Framework that owns the stereotype (e.g. `react`, `nestjs`).
|
|
218
|
+
* Orthogonal to `construct` — a React component is still `construct: function`.
|
|
219
|
+
*/
|
|
220
|
+
framework?: SubsystemFramework;
|
|
221
|
+
/**
|
|
222
|
+
* Framework pattern this declaration plays (e.g. `component`, `hook`).
|
|
223
|
+
* Prefer this over inventing framework-specific constructs.
|
|
224
|
+
*/
|
|
225
|
+
stereotype?: SubsystemStereotype;
|
|
226
|
+
process?: string;
|
|
227
|
+
/** Code identity — real declaration in `file` when set. */
|
|
228
|
+
symbol?: string;
|
|
229
|
+
layer?: number;
|
|
230
|
+
capture?: SubsystemCapture;
|
|
231
|
+
/** Structured declaration shape of the construct (params, members, …). */
|
|
232
|
+
declaration?: SubsystemConstructDeclaration;
|
|
233
|
+
declarationProvenance?: SubsystemDeclarationProvenance;
|
|
234
|
+
tokens?: SubsystemDeclToken[];
|
|
235
|
+
/** Location anchor (file/line/hash) — distinct from `declaration` (shape). */
|
|
236
|
+
declarationRef?: SubsystemDeclarationRef;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** A cross-component edge. */
|
|
240
|
+
export interface SubsystemComponentEdge {
|
|
241
|
+
id: string;
|
|
242
|
+
/** Source component id. */
|
|
243
|
+
from: string;
|
|
244
|
+
/** Target component id (or external label). */
|
|
245
|
+
to: string;
|
|
246
|
+
mechanism: SubsystemEdgeMechanism;
|
|
247
|
+
/** Concrete file/symbol evidence (often purls). */
|
|
248
|
+
refs?: string[];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface SubsystemThroughlineStep {
|
|
252
|
+
edgeId: string;
|
|
253
|
+
file: string;
|
|
254
|
+
/** 1-based line within `file`. */
|
|
255
|
+
line: number;
|
|
256
|
+
/** Frame name for this hop (function/method/symbol). Optional. */
|
|
257
|
+
symbol?: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Ordered execution story over existing edges (one per flow). */
|
|
261
|
+
export interface SubsystemThroughline {
|
|
262
|
+
id: string;
|
|
263
|
+
title: string;
|
|
264
|
+
steps: SubsystemThroughlineStep[];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface SubsystemRepoRef {
|
|
268
|
+
owner: string;
|
|
269
|
+
name: string;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Portable subsystem graph — the shareable standard.
|
|
274
|
+
* No host paths, provenance, document-level repo, store ids, or verification.
|
|
275
|
+
* Repo identity lives on each component's `purl`.
|
|
276
|
+
*/
|
|
277
|
+
export interface SubsystemGraphDocument {
|
|
278
|
+
/**
|
|
279
|
+
* Optional pointer to the JSON Schema that describes this file. Lets editors
|
|
280
|
+
* give autocomplete and validation when the field is set.
|
|
281
|
+
*/
|
|
282
|
+
$schema?: string;
|
|
283
|
+
|
|
284
|
+
title: string;
|
|
285
|
+
description?: string;
|
|
286
|
+
components: SubsystemComponent[];
|
|
287
|
+
edges: SubsystemComponentEdge[];
|
|
288
|
+
throughlines?: SubsystemThroughline[];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Host/machine fields layered onto a portable document for local use.
|
|
293
|
+
* Not part of the portable standard — viewers and stores own this envelope.
|
|
294
|
+
*/
|
|
295
|
+
export interface SubsystemGraphHostBinding {
|
|
296
|
+
/** Provenance of the graph (e.g. `agent:<name>`, `manual`). */
|
|
297
|
+
source?: string;
|
|
298
|
+
/**
|
|
299
|
+
* Optional document-level repo summary for host indexes/listings.
|
|
300
|
+
* Portable identity lives on each component's `purl`.
|
|
301
|
+
*/
|
|
302
|
+
repo?: SubsystemRepoRef;
|
|
303
|
+
/**
|
|
304
|
+
* Local filesystem root component `file` paths resolve against.
|
|
305
|
+
* Opt-in; sandboxed reads for single-repo graphs.
|
|
306
|
+
*/
|
|
307
|
+
repoRoot?: string;
|
|
308
|
+
/**
|
|
309
|
+
* Per-repo local roots for multi-repo graphs, keyed by purl repo key
|
|
310
|
+
* (`pkg:github/owner/name`, fragment stripped).
|
|
311
|
+
*/
|
|
312
|
+
repoRoots?: Record<string, string>;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Hydrated graph: portable document + host binding + optional store metadata.
|
|
317
|
+
* Shape used after a host accepts/persists a graph for viewing on a machine.
|
|
318
|
+
*/
|
|
319
|
+
export interface SubsystemGraphHydrated
|
|
320
|
+
extends SubsystemGraphDocument, SubsystemGraphHostBinding {
|
|
321
|
+
/** Store-assigned id when persisted. */
|
|
322
|
+
id?: string;
|
|
323
|
+
createdAt?: string;
|
|
324
|
+
updatedAt?: string;
|
|
325
|
+
/** Host verification result; shape is host-defined. */
|
|
326
|
+
verification?: unknown;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Type guard: true when the value plausibly conforms to a portable
|
|
331
|
+
* subsystem graph. Shallow check — full validation belongs to the schema /
|
|
332
|
+
* host validator.
|
|
333
|
+
*/
|
|
334
|
+
export function isSubsystemGraphDocument(value: unknown): value is SubsystemGraphDocument {
|
|
335
|
+
if (!value || typeof value !== 'object') return false;
|
|
336
|
+
const v = value as {
|
|
337
|
+
title?: unknown;
|
|
338
|
+
components?: unknown;
|
|
339
|
+
edges?: unknown;
|
|
340
|
+
};
|
|
341
|
+
return (
|
|
342
|
+
typeof v.title === 'string' &&
|
|
343
|
+
Array.isArray(v.components) &&
|
|
344
|
+
Array.isArray(v.edges)
|
|
345
|
+
);
|
|
346
|
+
}
|