yarramate 0.23.0 → 1.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 +13 -4
- package/catalogues/core-enrichment.yaml +79 -55
- package/dist/adapter-mapping.js +6 -1
- package/dist/adapters/likec4-cli.js +36 -7
- package/dist/adapters/visual/client.d.ts +2 -2
- package/dist/adapters/visual/client.js +79 -10
- package/dist/adapters/visual/protocol-contract.d.ts +124 -10
- package/dist/adapters/visual/protocol-contract.js +12 -1
- package/dist/adapters/visual/protocol.d.ts +63 -0
- package/dist/adapters/visual/protocol.js +96 -5
- package/dist/adapters/visual/session-server.d.ts +1 -6
- package/dist/adapters/visual/session-server.js +243 -143
- package/dist/adapters/visual/session-store.d.ts +9 -0
- package/dist/adapters/visual/session-store.js +14 -5
- package/dist/adapters/visual/view-identity.d.ts +135 -0
- package/dist/adapters/visual/view-identity.js +200 -0
- package/dist/adapters/visual/wire.d.ts +19 -4
- package/dist/adapters/visual/workspace-model.d.ts +116 -0
- package/dist/adapters/visual/workspace-model.js +212 -0
- package/dist/adapters/visual-cli.d.ts +1 -1
- package/dist/adapters/visual-cli.js +30 -21
- package/dist/apply-cli.d.ts +2 -0
- package/dist/apply-cli.js +83 -0
- package/dist/apply-command.d.ts +84 -3
- package/dist/apply-command.js +218 -109
- package/dist/archimate-relationships.generated.d.ts +22 -0
- package/dist/archimate-relationships.generated.js +156 -0
- package/dist/ask-command.js +18 -6
- package/dist/attestation-staleness.js +2 -2
- package/dist/changed.js +1 -1
- package/dist/check-command.js +13 -5
- package/dist/cli-support.d.ts +1 -1
- package/dist/cli-support.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/compiler.d.ts +31 -3
- package/dist/compiler.js +321 -81
- package/dist/concept-drafting.d.ts +27 -0
- package/dist/concept-drafting.js +75 -0
- package/dist/core-contract.js +6 -1
- package/dist/deletion-drafting.d.ts +52 -0
- package/dist/deletion-drafting.js +100 -0
- package/dist/evidence.js +6 -1
- package/dist/graph-projection.d.ts +14 -0
- package/dist/graph-projection.js +4 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -1
- package/dist/interrogate-command.js +63 -17
- package/dist/kind-label.d.ts +4 -3
- package/dist/kind-label.js +4 -3
- package/dist/nesting.d.ts +15 -0
- package/dist/nesting.js +2 -0
- package/dist/notation/archimate.d.ts +1 -1
- package/dist/notation/archimate.js +108 -9
- package/dist/profile.d.ts +9 -12
- package/dist/profile.js +17 -26
- package/dist/projection.d.ts +62 -3
- package/dist/projection.js +127 -43
- package/dist/relationship-drafting.d.ts +51 -0
- package/dist/relationship-drafting.js +92 -0
- package/dist/relationship-matrix.d.ts +14 -0
- package/dist/relationship-matrix.js +74 -0
- package/dist/shipped-profile.d.ts +1 -1
- package/dist/shipped-profile.js +19 -5
- package/dist/source-store.d.ts +95 -0
- package/dist/source-store.js +170 -0
- package/dist/subject-references.js +1 -1
- package/dist/visual-app/assets/index-BLcpI8WN.js +394 -0
- package/dist/visual-app/assets/index-DLutIWES.css +1 -0
- package/dist/visual-app/index.html +2 -2
- package/dist/visual-app-lib/editor.d.ts +1 -0
- package/dist/visual-app-lib/editor.js +90968 -0
- package/dist/visual-app-lib/styles.css +2 -0
- package/dist/visual-app-lib/types/adapter-mapping.d.ts +40 -0
- package/dist/visual-app-lib/types/adapters/visual/protocol-contract.d.ts +455 -0
- package/dist/visual-app-lib/types/adapters/visual/view-identity.d.ts +135 -0
- package/dist/visual-app-lib/types/adapters/visual/wire.d.ts +141 -0
- package/dist/visual-app-lib/types/adapters/visual/workspace-model.d.ts +116 -0
- package/dist/visual-app-lib/types/apply-command.d.ts +93 -0
- package/dist/visual-app-lib/types/archimate-relationships.generated.d.ts +22 -0
- package/dist/visual-app-lib/types/brief.d.ts +5 -0
- package/dist/visual-app-lib/types/compiler.d.ts +155 -0
- package/dist/visual-app-lib/types/concept-drafting.d.ts +27 -0
- package/dist/visual-app-lib/types/deletion-drafting.d.ts +52 -0
- package/dist/visual-app-lib/types/evidence.d.ts +62 -0
- package/dist/visual-app-lib/types/graph-claims.d.ts +18 -0
- package/dist/visual-app-lib/types/graph-projection.d.ts +77 -0
- package/dist/visual-app-lib/types/kind-label.d.ts +9 -0
- package/dist/visual-app-lib/types/nesting.d.ts +15 -0
- package/dist/visual-app-lib/types/notation/archimate.d.ts +71 -0
- package/dist/visual-app-lib/types/operations.d.ts +157 -0
- package/dist/visual-app-lib/types/profile.d.ts +47 -0
- package/dist/visual-app-lib/types/projection.d.ts +113 -0
- package/dist/visual-app-lib/types/relationship-drafting.d.ts +51 -0
- package/dist/visual-app-lib/types/relationship-matrix.d.ts +14 -0
- package/dist/visual-app-lib/types/shipped-profile.d.ts +2 -0
- package/dist/visual-app-lib/types/source-document.d.ts +36 -0
- package/dist/visual-app-lib/types/source-store.d.ts +95 -0
- package/dist/visual-app-lib/types/subject-references.d.ts +92 -0
- package/dist/visual-app-lib/types/visual-app/App.d.ts +15 -0
- package/dist/visual-app-lib/types/visual-app/badges.d.ts +7 -0
- package/dist/visual-app-lib/types/visual-app/changeset-tray.d.ts +106 -0
- package/dist/visual-app-lib/types/visual-app/confirm-dialog.d.ts +14 -0
- package/dist/visual-app-lib/types/visual-app/connection-panel.d.ts +23 -0
- package/dist/visual-app-lib/types/visual-app/context-menu-model.d.ts +187 -0
- package/dist/visual-app-lib/types/visual-app/context-menu.d.ts +24 -0
- package/dist/visual-app-lib/types/visual-app/describe-query.d.ts +9 -0
- package/dist/visual-app-lib/types/visual-app/editor-host.d.ts +70 -0
- package/dist/visual-app-lib/types/visual-app/faults.d.ts +26 -0
- package/dist/visual-app-lib/types/visual-app/graph-canvas.d.ts +73 -0
- package/dist/visual-app-lib/types/visual-app/kind-icons.d.ts +3 -0
- package/dist/visual-app-lib/types/visual-app/local-host.d.ts +38 -0
- package/dist/visual-app-lib/types/visual-app/mount.d.ts +56 -0
- package/dist/visual-app-lib/types/visual-app/prompt-dialog.d.ts +24 -0
- package/dist/visual-app-lib/types/visual-app/query-fields.d.ts +69 -0
- package/dist/visual-app-lib/types/visual-app/query-panel.d.ts +142 -0
- package/dist/visual-app-lib/types/visual-app/quick-filter.d.ts +11 -0
- package/dist/visual-app-lib/types/visual-app/relationship-kind-options.d.ts +50 -0
- package/dist/visual-app-lib/types/visual-app/save-view.d.ts +86 -0
- package/dist/visual-app-lib/types/visual-app/section-stack.d.ts +59 -0
- package/dist/visual-app-lib/types/visual-app/session-client.d.ts +38 -0
- package/dist/visual-app-lib/types/visual-app/state.d.ts +328 -0
- package/dist/visual-app-lib/types/visual-app/subject-draft-panel.d.ts +22 -0
- package/dist/visual-app-lib/types/visual-app/subject-form.d.ts +42 -0
- package/dist/visual-app-lib/types/visual-app/view-tree-model.d.ts +122 -0
- package/dist/visual-app-lib/types/visual-app/view-tree.d.ts +32 -0
- package/dist/visual-app-lib/types/visual-app/workspace-state.d.ts +268 -0
- package/dist/visual-app-lib/types/workspace.d.ts +29 -0
- package/dist/workspace.js +7 -1
- package/docs/CONSUMING-YARRAMATE.md +51 -2
- package/package.json +9 -2
- package/schema/yarramate-adapter-mapping.schema.json +1 -1
- package/schema/yarramate-ask-result.schema.json +24 -3
- package/schema/yarramate-check-result.schema.json +9 -0
- package/schema/yarramate-diagnostic-result.schema.json +9 -0
- package/schema/yarramate-document.schema.json +6 -0
- package/schema/yarramate-evidence-report.schema.json +1 -1
- package/schema/yarramate-evidence.schema.json +1 -1
- package/schema/yarramate-graph-v2.schema.json +34 -9
- package/schema/yarramate-likec4-generated-project-v2.schema.json +1 -1
- package/schema/yarramate-likec4-generated-project.schema.json +1 -1
- package/schema/yarramate-likec4-project.schema.json +1 -1
- package/schema/yarramate-projection-result.schema.json +3 -7
- package/schema/yarramate-projection.schema.json +16 -16
- package/schema/yarramate-reconciliation-report.schema.json +2 -2
- package/schema/yarramate-rtm.schema.json +1 -1
- package/schema/yarramate-state-comparison.schema.json +1 -1
- package/schema/yarramate-visual-diagnostic-result.schema.json +9 -0
- package/schema/yarramate-visual-event.schema.json +40 -41
- package/schema/yarramate-visual-graph.schema.json +8 -0
- package/schema/yarramate-visual-handoff.schema.json +3 -3
- package/schema/yarramate-visual-session-descriptor.schema.json +6 -6
- package/schema/yarramate-visual-session-started.schema.json +10 -9
- package/schema/yarramate-visual-status.schema.json +3 -3
- package/skills/yarramate-architecture/SKILL.md +3 -3
- package/skills/yarramate-architecture/references/modelling-patterns.md +23 -44
- package/skills/yarramate-architecture/references/native-authoring.md +32 -49
- package/skills/yarramate-architecture/references/visual-conversations.md +13 -10
- package/dist/visual-app/assets/index-CRd1Khma.js +0 -354
- package/dist/visual-app/assets/index-tZSHlU-a.css +0 -1
|
@@ -10,8 +10,19 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { CanvasGraph } from "../../graph-projection.js";
|
|
12
12
|
import type { YarramateApplyResult, YarramateOperation } from "../../operations.js";
|
|
13
|
-
import type { ProjectionDefinition, ProjectionQuery } from "../../projection.js";
|
|
14
|
-
|
|
13
|
+
import type { ProjectionDefinition, ProjectionExclusion, ProjectionQuery } from "../../projection.js";
|
|
14
|
+
/**
|
|
15
|
+
* The wire this adapter speaks. v5 makes a view a staged change rather than an
|
|
16
|
+
* immediate write (ADR 0103): a commit carries `viewOperations` beside its
|
|
17
|
+
* model operations, a model frame carries the projection digests those
|
|
18
|
+
* operations pin against, and the `view.save` event that wrote a projection
|
|
19
|
+
* the moment it was composed is gone. A v4 peer and a v5 peer refuse each
|
|
20
|
+
* other at the first document exchanged.
|
|
21
|
+
*
|
|
22
|
+
* v4 retyped every path-carrying field from a bare native string to a
|
|
23
|
+
* canonical local `file:` URI (ADR 0096).
|
|
24
|
+
*/
|
|
25
|
+
export declare const VISUAL_PROTOCOL_VERSION: "yarramate/visual-protocol/v5";
|
|
15
26
|
export declare const VISUAL_LIMITS: {
|
|
16
27
|
readonly messageBytes: number;
|
|
17
28
|
readonly modelBytes: number;
|
|
@@ -29,6 +40,18 @@ export interface VisualDiagnostic {
|
|
|
29
40
|
readonly pointer: string;
|
|
30
41
|
readonly line: number;
|
|
31
42
|
readonly column: number;
|
|
43
|
+
/**
|
|
44
|
+
* The subjects this diagnostic is about, most relevant first, when its
|
|
45
|
+
* pointer names one (ADR 0102, extending the derivation Core added for
|
|
46
|
+
* exactly this consumer).
|
|
47
|
+
*
|
|
48
|
+
* Absence is meaningful and is not "not yet populated": a diagnostic with no
|
|
49
|
+
* subject belongs to no subject, such as a YAML parse failure, a
|
|
50
|
+
* whole-document schema violation, a projection's own definition, or a
|
|
51
|
+
* manifest. That is what lets a canvas route one to an element and the other
|
|
52
|
+
* to a lane of its own, rather than showing a failure with nothing marked.
|
|
53
|
+
*/
|
|
54
|
+
readonly subjects?: readonly string[];
|
|
32
55
|
}
|
|
33
56
|
export interface VisualDiagnosticResult {
|
|
34
57
|
readonly format: "yarramate/visual-diagnostic-result/v1";
|
|
@@ -56,7 +79,7 @@ export interface VisualSessionRequest {
|
|
|
56
79
|
readonly initialModel: VisualModel;
|
|
57
80
|
}
|
|
58
81
|
export interface VisualSessionStarted {
|
|
59
|
-
readonly format: "yarramate/visual-session-started/
|
|
82
|
+
readonly format: "yarramate/visual-session-started/v2";
|
|
60
83
|
readonly protocolVersion: typeof VISUAL_PROTOCOL_VERSION;
|
|
61
84
|
readonly sessionId: string;
|
|
62
85
|
readonly authority: VisualAuthority;
|
|
@@ -65,18 +88,25 @@ export interface VisualSessionStarted {
|
|
|
65
88
|
readonly browserUrl: string;
|
|
66
89
|
readonly webSocketUrl: string;
|
|
67
90
|
readonly origin: string;
|
|
91
|
+
/** Canonical local `file:` URI. Copy it back verbatim as the argument to
|
|
92
|
+
* `wait`/`respond`/`status`/`recover`/`stop`; it is never hand-typed as a
|
|
93
|
+
* native path. Minted by `toWireFileUri`, read by `fromWireFileUri`. */
|
|
68
94
|
readonly descriptorPath: string;
|
|
95
|
+
/** Canonical local `file:` URI, as `descriptorPath`. */
|
|
69
96
|
readonly sessionRoot: string;
|
|
70
97
|
readonly capabilities: VisualCapabilities;
|
|
71
98
|
readonly startedAt: string;
|
|
72
99
|
}
|
|
73
100
|
export interface VisualSessionDescriptor {
|
|
74
|
-
readonly format: "yarramate/visual-session-descriptor/
|
|
101
|
+
readonly format: "yarramate/visual-session-descriptor/v2";
|
|
75
102
|
readonly protocolVersion: typeof VISUAL_PROTOCOL_VERSION;
|
|
76
103
|
readonly sessionId: string;
|
|
77
104
|
readonly origin: string;
|
|
78
105
|
readonly agentCapability: string;
|
|
106
|
+
/** Canonical local `file:` URI. Proven against the session actually opened
|
|
107
|
+
* before `agentCapability` is ever spent. */
|
|
79
108
|
readonly sessionRoot: string;
|
|
109
|
+
/** Canonical local `file:` URI, as `sessionRoot`. */
|
|
80
110
|
readonly journalPath: string;
|
|
81
111
|
readonly createdAt: string;
|
|
82
112
|
}
|
|
@@ -97,10 +127,39 @@ export interface VisualViewSummary {
|
|
|
97
127
|
readonly description: string;
|
|
98
128
|
readonly query: ProjectionQuery;
|
|
99
129
|
readonly presentation: ProjectionDefinition["presentation"];
|
|
130
|
+
/**
|
|
131
|
+
* Manifest-relative path of the projection document this view was read from,
|
|
132
|
+
* as `VisualRenderedModel.documents` names a document — not the `file:` URI
|
|
133
|
+
* ADR 0096 mints for the descriptor and session root, which name things
|
|
134
|
+
* outside the workspace.
|
|
135
|
+
*
|
|
136
|
+
* The tree derives its folders from these paths, so a workspace that keeps
|
|
137
|
+
* `current/` and `target/` projections in directories gets a foldered view
|
|
138
|
+
* list without the projection format gaining a folder concept of its own.
|
|
139
|
+
*/
|
|
140
|
+
readonly path: string;
|
|
141
|
+
/**
|
|
142
|
+
* How many subjects this view's query matches, resolved by the runtime the
|
|
143
|
+
* way `filter.query` is: a `ProjectionQuery` needs the semantic graph, which
|
|
144
|
+
* the browser does not have. Recomputed and re-sent whenever the workspace
|
|
145
|
+
* recompiles, since landing a changeset moves these counts.
|
|
146
|
+
*/
|
|
147
|
+
readonly subjectCount: number;
|
|
100
148
|
}
|
|
101
149
|
export interface VisualKindOption {
|
|
102
150
|
readonly id: string;
|
|
103
151
|
readonly label: string;
|
|
152
|
+
/**
|
|
153
|
+
* The nearest core-profile kind this one descends from, as a label — the
|
|
154
|
+
* same resolution `CanvasNode.coreKindLabel` and `CanvasEdge.coreKindLabel`
|
|
155
|
+
* carry, for a kind nothing has been authored with yet.
|
|
156
|
+
*
|
|
157
|
+
* Without it a browser can read a palette but cannot judge it: the ArchiMate
|
|
158
|
+
* table is keyed on core kinds, so an editor offering an extension kind has
|
|
159
|
+
* no way to ask whether the pairing permits what that kind descends from,
|
|
160
|
+
* and can put a `YM404` one click away. Equal to `label` for a core kind.
|
|
161
|
+
*/
|
|
162
|
+
readonly coreLabel: string;
|
|
104
163
|
}
|
|
105
164
|
export interface VisualFilterQueryPayload {
|
|
106
165
|
readonly query: ProjectionQuery;
|
|
@@ -108,6 +167,23 @@ export interface VisualFilterQueryPayload {
|
|
|
108
167
|
export interface VisualFilterResultPayload {
|
|
109
168
|
readonly query: ProjectionQuery;
|
|
110
169
|
readonly matchedIds: readonly string[];
|
|
170
|
+
/**
|
|
171
|
+
* Every concept this query DROPPED, each with the facet that dropped it, as
|
|
172
|
+
* `explainProjection` reports it. The editor needs it to say why a subject
|
|
173
|
+
* is not on the canvas: a query that quietly drops the one subject the
|
|
174
|
+
* reviewer was looking for is otherwise indistinguishable from a model that
|
|
175
|
+
* does not hold it.
|
|
176
|
+
*
|
|
177
|
+
* A frame field, not a document field. `yarramate/projection-result/v1` is
|
|
178
|
+
* `additionalProperties: false` and this is a question about a query rather
|
|
179
|
+
* than part of what a projection IS, so the exclusions ride on the answer to
|
|
180
|
+
* the question that asked for them and nowhere else.
|
|
181
|
+
*
|
|
182
|
+
* Relationships are absent by construction: they enter a view through their
|
|
183
|
+
* endpoints rather than by matching a facet, so "why" for a relationship is
|
|
184
|
+
* a statement about the concepts it joins.
|
|
185
|
+
*/
|
|
186
|
+
readonly excluded: readonly ProjectionExclusion[];
|
|
111
187
|
}
|
|
112
188
|
export interface VisualViewSavePayload {
|
|
113
189
|
readonly id?: string;
|
|
@@ -122,8 +198,37 @@ export interface VisualLayoutPositions {
|
|
|
122
198
|
readonly y: number;
|
|
123
199
|
};
|
|
124
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* A change to a projection document, staged rather than written (ADR 0103).
|
|
203
|
+
*
|
|
204
|
+
* These ride beside the model's operations rather than inside them: Core holds
|
|
205
|
+
* that a projection is never an operation's own target, and a view is
|
|
206
|
+
* presentation rather than semantics. Atomicity does not come from sharing a
|
|
207
|
+
* list - it comes from the runtime planning both and issuing one
|
|
208
|
+
* `SourceStore.writeAll`, so a view and the subjects it shows land together or
|
|
209
|
+
* not at all.
|
|
210
|
+
*
|
|
211
|
+
* `path` is manifest-relative, the way `VisualViewSummary.path` names it. A
|
|
212
|
+
* `write-view` at a path the manifest's patterns do not cover is refused
|
|
213
|
+
* rather than written, because a projection nothing loads is worse than a
|
|
214
|
+
* refusal (ADR 0043).
|
|
215
|
+
*/
|
|
216
|
+
export type VisualViewOperation = {
|
|
217
|
+
readonly op: "write-view";
|
|
218
|
+
readonly path: string;
|
|
219
|
+
readonly projection: ProjectionDefinition;
|
|
220
|
+
} | {
|
|
221
|
+
readonly op: "delete-view";
|
|
222
|
+
readonly path: string;
|
|
223
|
+
};
|
|
125
224
|
export interface VisualChangesetCommitPayload {
|
|
126
225
|
readonly operations: readonly YarramateOperation[];
|
|
226
|
+
/**
|
|
227
|
+
* Projection writes and removals landing in the same batch as `operations`.
|
|
228
|
+
* Required, not optional, for the same reason `sourceDigests` is: a browser
|
|
229
|
+
* that may omit it is one whose commits mean two different things.
|
|
230
|
+
*/
|
|
231
|
+
readonly viewOperations: readonly VisualViewOperation[];
|
|
127
232
|
/**
|
|
128
233
|
* What the browser believed each targeted document held when the rows were
|
|
129
234
|
* staged — sha256 keyed by manifest-relative path, pinned at staging time and
|
|
@@ -134,6 +239,11 @@ export interface VisualChangesetCommitPayload {
|
|
|
134
239
|
* Required, not optional: a browser that omits it is exactly the browser that
|
|
135
240
|
* cannot detect the conflict, which is why this field is what makes the
|
|
136
241
|
* protocol `v3`.
|
|
242
|
+
*
|
|
243
|
+
* One map covers both lists. On the model frame the two are kept apart,
|
|
244
|
+
* because there they mean different things — what the graph was compiled
|
|
245
|
+
* from, and what the views are — but a pin means the same thing for either:
|
|
246
|
+
* what the browser expected to find on disk.
|
|
137
247
|
*/
|
|
138
248
|
readonly sourceDigests: Readonly<Record<string, string>>;
|
|
139
249
|
}
|
|
@@ -187,10 +297,6 @@ export type VisualBrowserInput = {
|
|
|
187
297
|
readonly type: "filter.query";
|
|
188
298
|
readonly lastAcknowledgedSequence: number;
|
|
189
299
|
readonly payload: VisualFilterQueryPayload;
|
|
190
|
-
} | {
|
|
191
|
-
readonly type: "view.save";
|
|
192
|
-
readonly lastAcknowledgedSequence: number;
|
|
193
|
-
readonly payload: VisualViewSavePayload;
|
|
194
300
|
} | {
|
|
195
301
|
readonly type: "changeset.commit";
|
|
196
302
|
readonly lastAcknowledgedSequence: number;
|
|
@@ -213,7 +319,7 @@ interface VisualEventEnvelope<Type extends string, Payload> {
|
|
|
213
319
|
readonly timestamp: string;
|
|
214
320
|
readonly payload: Payload;
|
|
215
321
|
}
|
|
216
|
-
export type VisualEvent = VisualEventEnvelope<"chat.message", VisualChatMessagePayload> | VisualEventEnvelope<"choice.selected", VisualChoiceSelectedPayload> | VisualEventEnvelope<"view.navigate", VisualViewNavigatePayload> | VisualEventEnvelope<"session.end", VisualSessionEndPayload> | VisualEventEnvelope<"browser.connected", VisualBrowserConnectedPayload> | VisualEventEnvelope<"browser.disconnected", VisualBrowserDisconnectedPayload> | VisualEventEnvelope<"filter.query", VisualFilterQueryPayload> | VisualEventEnvelope<"
|
|
322
|
+
export type VisualEvent = VisualEventEnvelope<"chat.message", VisualChatMessagePayload> | VisualEventEnvelope<"choice.selected", VisualChoiceSelectedPayload> | VisualEventEnvelope<"view.navigate", VisualViewNavigatePayload> | VisualEventEnvelope<"session.end", VisualSessionEndPayload> | VisualEventEnvelope<"browser.connected", VisualBrowserConnectedPayload> | VisualEventEnvelope<"browser.disconnected", VisualBrowserDisconnectedPayload> | VisualEventEnvelope<"filter.query", VisualFilterQueryPayload> | VisualEventEnvelope<"changeset.commit", VisualChangesetCommitPayload> | VisualEventEnvelope<"layout.save", VisualLayoutSavePayload>;
|
|
217
323
|
/**
|
|
218
324
|
* The filter a chat turn resolved to. The agent states `query` and nothing
|
|
219
325
|
* else: the runtime evaluates it against the same graph a `filter.query`
|
|
@@ -258,6 +364,13 @@ export type VisualViewSaveResultPayload = {
|
|
|
258
364
|
readonly ok: true;
|
|
259
365
|
readonly id: string;
|
|
260
366
|
readonly path: string;
|
|
367
|
+
/**
|
|
368
|
+
* What the saved query matches, stated by the side that can count it.
|
|
369
|
+
* The browser builds the new view's summary from what it sent plus this
|
|
370
|
+
* result, and a `ProjectionQuery` needs the semantic graph to resolve —
|
|
371
|
+
* without this the row would join the tree claiming zero subjects.
|
|
372
|
+
*/
|
|
373
|
+
readonly subjectCount: number;
|
|
261
374
|
} | {
|
|
262
375
|
readonly ok: false;
|
|
263
376
|
readonly diagnostics: readonly VisualDiagnostic[];
|
|
@@ -289,12 +402,13 @@ export type VisualResponse = VisualResponseEnvelope<"chat.response", VisualChatR
|
|
|
289
402
|
export type VisualHandoffDecision = "completed" | "cancelled" | "failed";
|
|
290
403
|
export type VisualTerminationReason = "user-ended" | "child-failed" | "browser-timeout" | "main-cancelled" | "server-failed" | "compiler-failed";
|
|
291
404
|
export interface VisualHandoff extends VisualHandoffSummary {
|
|
292
|
-
readonly format: "yarramate/visual-handoff/
|
|
405
|
+
readonly format: "yarramate/visual-handoff/v2";
|
|
293
406
|
readonly sessionId: string;
|
|
294
407
|
readonly authority: VisualAuthority;
|
|
295
408
|
readonly decision: VisualHandoffDecision;
|
|
296
409
|
readonly terminationReason: VisualTerminationReason;
|
|
297
410
|
readonly lastSequence: number;
|
|
411
|
+
/** Canonical local `file:` URI. */
|
|
298
412
|
readonly transcriptPath: string;
|
|
299
413
|
readonly transcript?: readonly (VisualEvent | VisualResponse)[];
|
|
300
414
|
readonly completedAt: string;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The wire this adapter speaks. v5 makes a view a staged change rather than an
|
|
3
|
+
* immediate write (ADR 0103): a commit carries `viewOperations` beside its
|
|
4
|
+
* model operations, a model frame carries the projection digests those
|
|
5
|
+
* operations pin against, and the `view.save` event that wrote a projection
|
|
6
|
+
* the moment it was composed is gone. A v4 peer and a v5 peer refuse each
|
|
7
|
+
* other at the first document exchanged.
|
|
8
|
+
*
|
|
9
|
+
* v4 retyped every path-carrying field from a bare native string to a
|
|
10
|
+
* canonical local `file:` URI (ADR 0096).
|
|
11
|
+
*/
|
|
12
|
+
export const VISUAL_PROTOCOL_VERSION = "yarramate/visual-protocol/v5";
|
|
2
13
|
export const VISUAL_LIMITS = {
|
|
3
14
|
messageBytes: 64 * 1024,
|
|
4
15
|
modelBytes: 5 * 1024 * 1024,
|
|
@@ -9,8 +9,71 @@ export * from './protocol-contract.js';
|
|
|
9
9
|
* mints them for the initial model, the session server re-mints them on every
|
|
10
10
|
* recompile and checks a commit's pins against the files on disk, and all three
|
|
11
11
|
* are the same hash by construction rather than by three matching literals.
|
|
12
|
+
*
|
|
13
|
+
* There is a fourth, and it is not by construction. A commit's pins become the
|
|
14
|
+
* `expected` revisions a `SourceStore` compares before it writes (ADR 0100),
|
|
15
|
+
* and a store's revision is opaque: what `createFileSystemStore` mints happens
|
|
16
|
+
* to be this same sha256, which is the only reason a pin can be handed to it
|
|
17
|
+
* directly. The visual runtime only ever addresses a local filesystem, so that
|
|
18
|
+
* coincidence is safe today and a protocol version spent on carrying opaque
|
|
19
|
+
* revisions instead would buy nothing. It is held by a test rather than by a
|
|
20
|
+
* comment: `visual-protocol.test.ts` asserts the two agree, so a change to
|
|
21
|
+
* either side fails rather than silently making every commit's precondition
|
|
22
|
+
* unsatisfiable. That failure is when the protocol bump earns its cost.
|
|
12
23
|
*/
|
|
13
24
|
export declare const digestOf: (source: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Encode a native absolute path for the wire.
|
|
27
|
+
*
|
|
28
|
+
* Every filesystem path a protocol document carries is a canonical local
|
|
29
|
+
* `file:` URI, minted by Node's own `pathToFileURL`. A URI is invertible
|
|
30
|
+
* where the forward-slash string transform it replaces was not: a POSIX
|
|
31
|
+
* directory whose own name contains a literal backslash percent-encodes to
|
|
32
|
+
* `%5C` and stays distinguishable from a Windows separator, and a UNC path
|
|
33
|
+
* grows a non-empty host rather than passing as an ordinary POSIX-rooted
|
|
34
|
+
* path.
|
|
35
|
+
*
|
|
36
|
+
* Encoding cannot fail. `pathToFileURL` has no error path for an
|
|
37
|
+
* already-absolute native string, and every caller holds a `resolve`/`join`
|
|
38
|
+
* result it produced itself. A relative path reaching here is a programming
|
|
39
|
+
* error rather than a protocol fault, and throws as one.
|
|
40
|
+
*/
|
|
41
|
+
export declare const toWireFileUri: (native: string) => string;
|
|
42
|
+
/** Why one wire path was refused. Each shape is reported as `YMVS414`. */
|
|
43
|
+
export type WireFileUriRefusal = 'malformed' | 'nonlocal' | 'noncanonical';
|
|
44
|
+
export type WireFileUriResult = {
|
|
45
|
+
readonly ok: true;
|
|
46
|
+
readonly value: string;
|
|
47
|
+
} | {
|
|
48
|
+
readonly ok: false;
|
|
49
|
+
readonly reason: WireFileUriRefusal;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Decode a wire path back to native, the way untrusted input has to be read.
|
|
53
|
+
*
|
|
54
|
+
* A descriptor's bearer capabilities are never spent on a document whose path
|
|
55
|
+
* fields have not passed this first, so the three refusals are checked in a
|
|
56
|
+
* fixed order and none of them is ever quietly repaired:
|
|
57
|
+
*
|
|
58
|
+
* - `malformed` — not a parseable `file:` URI, or one `fileURLToPath` itself
|
|
59
|
+
* rejects (`ERR_INVALID_URL`, `ERR_INVALID_URL_SCHEME`,
|
|
60
|
+
* `ERR_INVALID_FILE_URL_PATH`). A bare native path lands here too: it has
|
|
61
|
+
* no scheme, or, for a Windows drive root, one that is not `file:`.
|
|
62
|
+
* - `nonlocal` — a non-empty host, which `pathToFileURL` never produces for a
|
|
63
|
+
* local path: `file://server/share/x` names a network share. The host is
|
|
64
|
+
* read off the parsed URL rather than inferred from a `fileURLToPath`
|
|
65
|
+
* failure, because that call refuses a foreign host on POSIX but resolves
|
|
66
|
+
* one to a UNC path on Windows, and reading it directly is the only way one
|
|
67
|
+
* URI earns the same refusal on both.
|
|
68
|
+
* - `noncanonical` — decodes, host is empty, but re-encoding the decoded path
|
|
69
|
+
* does not reproduce the input byte-for-byte. Two spellings of one target is
|
|
70
|
+
* the aliasing this representation exists to close, so the other spelling is
|
|
71
|
+
* refused rather than normalized into the canonical one. `file://localhost/x`
|
|
72
|
+
* lands here rather than in `nonlocal`: WHATWG `URL` normalizes a
|
|
73
|
+
* `localhost` file host away, leaving a URI that is simply not the spelling
|
|
74
|
+
* this codec mints for `/x`.
|
|
75
|
+
*/
|
|
76
|
+
export declare const fromWireFileUri: (uri: string) => WireFileUriResult;
|
|
14
77
|
export declare const parseVisualModel: (input: unknown) => ParseResult<VisualModel>;
|
|
15
78
|
export declare const parseVisualSessionRequest: (input: unknown) => ParseResult<VisualSessionRequest>;
|
|
16
79
|
export declare const parseVisualSessionStarted: (input: unknown) => ParseResult<VisualSessionStarted>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { posix } from 'node:path';
|
|
2
|
+
import { isAbsolute, posix } from 'node:path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
3
4
|
import Ajv2020Module from 'ajv/dist/2020.js';
|
|
4
5
|
import { describeSchemaViolation, readableSchemaErrors, } from '../../source-document.js';
|
|
5
6
|
import visualDiagnosticResultSchema from '../../../schema/yarramate-visual-diagnostic-result.schema.json' with { type: 'json'
|
|
@@ -67,6 +68,17 @@ ajv.addSchema([
|
|
|
67
68
|
* mints them for the initial model, the session server re-mints them on every
|
|
68
69
|
* recompile and checks a commit's pins against the files on disk, and all three
|
|
69
70
|
* are the same hash by construction rather than by three matching literals.
|
|
71
|
+
*
|
|
72
|
+
* There is a fourth, and it is not by construction. A commit's pins become the
|
|
73
|
+
* `expected` revisions a `SourceStore` compares before it writes (ADR 0100),
|
|
74
|
+
* and a store's revision is opaque: what `createFileSystemStore` mints happens
|
|
75
|
+
* to be this same sha256, which is the only reason a pin can be handed to it
|
|
76
|
+
* directly. The visual runtime only ever addresses a local filesystem, so that
|
|
77
|
+
* coincidence is safe today and a protocol version spent on carrying opaque
|
|
78
|
+
* revisions instead would buy nothing. It is held by a test rather than by a
|
|
79
|
+
* comment: `visual-protocol.test.ts` asserts the two agree, so a change to
|
|
80
|
+
* either side fails rather than silently making every commit's precondition
|
|
81
|
+
* unsatisfiable. That failure is when the protocol bump earns its cost.
|
|
70
82
|
*/
|
|
71
83
|
export const digestOf = (source) => createHash('sha256').update(source).digest('hex');
|
|
72
84
|
// Diagnostics report the document they came from rather than a source file,
|
|
@@ -81,8 +93,8 @@ const visualValidator = (document, reference = `https://yarramate.org/schema/${d
|
|
|
81
93
|
};
|
|
82
94
|
const validateVisualModel = visualValidator('visual-model/v1');
|
|
83
95
|
const validateVisualSessionRequest = visualValidator('visual-session-request/v1');
|
|
84
|
-
const validateVisualSessionStarted = visualValidator('visual-session-started/
|
|
85
|
-
const validateVisualSessionDescriptor = visualValidator('visual-session-descriptor/
|
|
96
|
+
const validateVisualSessionStarted = visualValidator('visual-session-started/v2');
|
|
97
|
+
const validateVisualSessionDescriptor = visualValidator('visual-session-descriptor/v2');
|
|
86
98
|
const BROWSER_INPUT_REFERENCE = 'https://yarramate.org/schema/visual-event/v1#/$defs/browserInput';
|
|
87
99
|
const validateVisualBrowserInput = visualValidator('visual-browser-input/v1', BROWSER_INPUT_REFERENCE);
|
|
88
100
|
/**
|
|
@@ -101,7 +113,7 @@ const browserInputBranches = new Map(visualEventSchema.$defs.browserInput.oneOf.
|
|
|
101
113
|
]));
|
|
102
114
|
const validateVisualEvent = visualValidator('visual-event/v1');
|
|
103
115
|
const validateVisualResponse = visualValidator('visual-response/v1');
|
|
104
|
-
const validateVisualHandoff = visualValidator('visual-handoff/
|
|
116
|
+
const validateVisualHandoff = visualValidator('visual-handoff/v2');
|
|
105
117
|
const validateVisualStatus = visualValidator('visual-status/v1');
|
|
106
118
|
const validateVisualDiagnosticResult = visualValidator('visual-diagnostic-result/v1');
|
|
107
119
|
/**
|
|
@@ -151,6 +163,85 @@ const isConfinedRelativePath = (candidate) => {
|
|
|
151
163
|
.split('/')
|
|
152
164
|
.every((segment) => segment.length > 0 && segment !== '.' && segment !== '..');
|
|
153
165
|
};
|
|
166
|
+
/**
|
|
167
|
+
* Encode a native absolute path for the wire.
|
|
168
|
+
*
|
|
169
|
+
* Every filesystem path a protocol document carries is a canonical local
|
|
170
|
+
* `file:` URI, minted by Node's own `pathToFileURL`. A URI is invertible
|
|
171
|
+
* where the forward-slash string transform it replaces was not: a POSIX
|
|
172
|
+
* directory whose own name contains a literal backslash percent-encodes to
|
|
173
|
+
* `%5C` and stays distinguishable from a Windows separator, and a UNC path
|
|
174
|
+
* grows a non-empty host rather than passing as an ordinary POSIX-rooted
|
|
175
|
+
* path.
|
|
176
|
+
*
|
|
177
|
+
* Encoding cannot fail. `pathToFileURL` has no error path for an
|
|
178
|
+
* already-absolute native string, and every caller holds a `resolve`/`join`
|
|
179
|
+
* result it produced itself. A relative path reaching here is a programming
|
|
180
|
+
* error rather than a protocol fault, and throws as one.
|
|
181
|
+
*/
|
|
182
|
+
export const toWireFileUri = (native) => {
|
|
183
|
+
if (!isAbsolute(native)) {
|
|
184
|
+
throw new Error(`A visual wire path must be absolute, not "${native}"`);
|
|
185
|
+
}
|
|
186
|
+
return pathToFileURL(native).href;
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Decode a wire path back to native, the way untrusted input has to be read.
|
|
190
|
+
*
|
|
191
|
+
* A descriptor's bearer capabilities are never spent on a document whose path
|
|
192
|
+
* fields have not passed this first, so the three refusals are checked in a
|
|
193
|
+
* fixed order and none of them is ever quietly repaired:
|
|
194
|
+
*
|
|
195
|
+
* - `malformed` — not a parseable `file:` URI, or one `fileURLToPath` itself
|
|
196
|
+
* rejects (`ERR_INVALID_URL`, `ERR_INVALID_URL_SCHEME`,
|
|
197
|
+
* `ERR_INVALID_FILE_URL_PATH`). A bare native path lands here too: it has
|
|
198
|
+
* no scheme, or, for a Windows drive root, one that is not `file:`.
|
|
199
|
+
* - `nonlocal` — a non-empty host, which `pathToFileURL` never produces for a
|
|
200
|
+
* local path: `file://server/share/x` names a network share. The host is
|
|
201
|
+
* read off the parsed URL rather than inferred from a `fileURLToPath`
|
|
202
|
+
* failure, because that call refuses a foreign host on POSIX but resolves
|
|
203
|
+
* one to a UNC path on Windows, and reading it directly is the only way one
|
|
204
|
+
* URI earns the same refusal on both.
|
|
205
|
+
* - `noncanonical` — decodes, host is empty, but re-encoding the decoded path
|
|
206
|
+
* does not reproduce the input byte-for-byte. Two spellings of one target is
|
|
207
|
+
* the aliasing this representation exists to close, so the other spelling is
|
|
208
|
+
* refused rather than normalized into the canonical one. `file://localhost/x`
|
|
209
|
+
* lands here rather than in `nonlocal`: WHATWG `URL` normalizes a
|
|
210
|
+
* `localhost` file host away, leaving a URI that is simply not the spelling
|
|
211
|
+
* this codec mints for `/x`.
|
|
212
|
+
*/
|
|
213
|
+
export const fromWireFileUri = (uri) => {
|
|
214
|
+
let parsed;
|
|
215
|
+
try {
|
|
216
|
+
parsed = new URL(uri);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return { ok: false, reason: 'malformed' };
|
|
220
|
+
}
|
|
221
|
+
if (parsed.protocol !== 'file:')
|
|
222
|
+
return { ok: false, reason: 'malformed' };
|
|
223
|
+
if (parsed.hostname !== '')
|
|
224
|
+
return { ok: false, reason: 'nonlocal' };
|
|
225
|
+
let native;
|
|
226
|
+
try {
|
|
227
|
+
native = fileURLToPath(parsed);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return { ok: false, reason: 'malformed' };
|
|
231
|
+
}
|
|
232
|
+
let canonical;
|
|
233
|
+
try {
|
|
234
|
+
canonical = toWireFileUri(native);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// `fileURLToPath` answering with something this platform does not call
|
|
238
|
+
// absolute is not a path this runtime can act on, whatever the URI meant.
|
|
239
|
+
return { ok: false, reason: 'malformed' };
|
|
240
|
+
}
|
|
241
|
+
if (canonical !== uri)
|
|
242
|
+
return { ok: false, reason: 'noncanonical' };
|
|
243
|
+
return { ok: true, value: native };
|
|
244
|
+
};
|
|
154
245
|
const modelSemantics = (input, path, prefix) => {
|
|
155
246
|
const fields = documentFields(input);
|
|
156
247
|
const diagnostics = [];
|
|
@@ -237,7 +328,7 @@ const semanticsByDocument = {
|
|
|
237
328
|
'visual-browser-input/v1': chatCarryingSemantics,
|
|
238
329
|
'visual-event/v1': chatCarryingSemantics,
|
|
239
330
|
'visual-response/v1': responseSemantics,
|
|
240
|
-
'visual-handoff/
|
|
331
|
+
'visual-handoff/v2': handoffSemantics,
|
|
241
332
|
};
|
|
242
333
|
const schemaDiagnostics = (errors, code, path) => errors.map((error) => {
|
|
243
334
|
const property = error.keyword === 'additionalProperties'
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { type VisualDiagnostic, type VisualEvent, type VisualFreezeReason, type VisualHandoff, type VisualLifecycle, type VisualSessionRequest, type VisualSessionStarted, type VisualStatus, type VisualTerminationReason } from "./protocol.js";
|
|
2
2
|
import { type TerminalEventDependencies, type VisualSessionPaths } from "./session-store.js";
|
|
3
|
+
export { VISUAL_SERVER_DOCUMENT } from "./workspace-model.js";
|
|
3
4
|
import type { VisualRenderedModel, VisualServerFrame, VisualSessionSnapshot, VisualTranscriptRecord } from "./wire.js";
|
|
4
5
|
export type { VisualRenderedModel, VisualServerFrame, VisualSessionSnapshot, VisualTranscriptRecord, };
|
|
5
|
-
/**
|
|
6
|
-
* Document name reported by diagnostics the server itself raises — a refused
|
|
7
|
-
* frame, a frozen queue, or a transport violation that no protocol document
|
|
8
|
-
* owns.
|
|
9
|
-
*/
|
|
10
|
-
export declare const VISUAL_SERVER_DOCUMENT = "visual-session-server";
|
|
11
6
|
/**
|
|
12
7
|
* Returned on every response. The policy admits no external origin at all, so
|
|
13
8
|
* neither a compromised model nor a hostile chat message can reach the network,
|