yarramate 0.18.0 → 0.20.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.
Files changed (70) hide show
  1. package/README.md +9 -1
  2. package/catalogues/core-enrichment.yaml +52 -1
  3. package/dist/adapters/graphify-cli.js +0 -0
  4. package/dist/adapters/likec4-cli.js +0 -0
  5. package/dist/adapters/likec4-export.d.ts +1 -1
  6. package/dist/adapters/likec4-export.js +32 -0
  7. package/dist/adapters/mcp-cli.js +0 -0
  8. package/dist/adapters/visual/client.js +0 -1
  9. package/dist/adapters/visual/protocol-contract.d.ts +118 -35
  10. package/dist/adapters/visual/protocol-contract.js +1 -11
  11. package/dist/adapters/visual/protocol.d.ts +8 -1
  12. package/dist/adapters/visual/protocol.js +86 -46
  13. package/dist/adapters/visual/request.d.ts +37 -0
  14. package/dist/adapters/visual/request.js +131 -0
  15. package/dist/adapters/visual/session-server.d.ts +12 -14
  16. package/dist/adapters/visual/session-server.js +641 -283
  17. package/dist/adapters/visual/session-store.d.ts +31 -29
  18. package/dist/adapters/visual/session-store.js +94 -94
  19. package/dist/adapters/visual/wire.d.ts +36 -10
  20. package/dist/adapters/visual-cli.d.ts +3 -0
  21. package/dist/adapters/visual-cli.js +66 -1
  22. package/dist/apply-command.d.ts +10 -0
  23. package/dist/apply-command.js +399 -247
  24. package/dist/cli.js +0 -0
  25. package/dist/compiler.d.ts +66 -0
  26. package/dist/compiler.js +209 -89
  27. package/dist/graph-projection.d.ts +62 -0
  28. package/dist/graph-projection.js +222 -0
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +1 -1
  31. package/dist/interrogate-command.d.ts +2 -0
  32. package/dist/interrogate-command.js +22 -0
  33. package/dist/kind-label.d.ts +8 -0
  34. package/dist/kind-label.js +8 -0
  35. package/dist/operations.d.ts +139 -0
  36. package/dist/operations.js +11 -0
  37. package/dist/projection.d.ts +2 -0
  38. package/dist/projection.js +8 -2
  39. package/dist/reconciliation.js +8 -7
  40. package/dist/source-document.d.ts +10 -0
  41. package/dist/source-document.js +21 -1
  42. package/dist/visual-app/assets/index-6oSR9RGM.js +354 -0
  43. package/dist/visual-app/assets/index-dwA9AOr5.css +1 -0
  44. package/dist/visual-app/index.html +2 -2
  45. package/docs/CONSUMING-YARRAMATE.md +25 -19
  46. package/package.json +9 -4
  47. package/schema/yarramate-adapter-mapping.schema.json +1 -1
  48. package/schema/yarramate-apply-result.schema.json +8 -2
  49. package/schema/yarramate-document.schema.json +1 -1
  50. package/schema/yarramate-likec4-diagnostic-result.schema.json +1 -1
  51. package/schema/yarramate-operations.schema.json +203 -1
  52. package/schema/yarramate-projection.schema.json +12 -3
  53. package/schema/yarramate-question-catalogue.schema.json +15 -2
  54. package/schema/yarramate-visual-event.schema.json +143 -0
  55. package/schema/yarramate-visual-graph.schema.json +272 -0
  56. package/schema/yarramate-visual-layout.schema.json +41 -0
  57. package/schema/yarramate-visual-model.schema.json +6 -44
  58. package/schema/yarramate-visual-response.schema.json +170 -19
  59. package/schema/yarramate-visual-session-descriptor.schema.json +1 -1
  60. package/schema/yarramate-visual-session-request.schema.json +0 -70
  61. package/schema/yarramate-visual-session-started.schema.json +2 -9
  62. package/schema/yarramate-visual-status.schema.json +3 -2
  63. package/skills/yarramate-architecture/SKILL.md +20 -13
  64. package/skills/yarramate-architecture/references/journey-checklists.md +4 -2
  65. package/skills/yarramate-architecture/references/native-authoring.md +30 -0
  66. package/skills/yarramate-architecture/references/visual-conversations.md +149 -150
  67. package/dist/adapters/visual/likec4-compiler.d.ts +0 -55
  68. package/dist/adapters/visual/likec4-compiler.js +0 -460
  69. package/dist/visual-app/assets/index-CGvC8e3R.css +0 -1
  70. package/dist/visual-app/assets/index-CXuW1tOj.js +0 -209
@@ -1,12 +1,22 @@
1
1
  import { posix } from 'node:path';
2
2
  import Ajv2020Module from 'ajv/dist/2020.js';
3
- import { describeSchemaViolation } from '../../source-document.js';
3
+ import { describeSchemaViolation, readableSchemaErrors, } from '../../source-document.js';
4
4
  import visualDiagnosticResultSchema from '../../../schema/yarramate-visual-diagnostic-result.schema.json' with { type: 'json'
5
5
  };
6
6
  import visualEventSchema from '../../../schema/yarramate-visual-event.schema.json' with { type: 'json'
7
7
  };
8
+ import visualGraphSchema from '../../../schema/yarramate-visual-graph.schema.json' with { type: 'json'
9
+ };
10
+ import applyResultSchema from '../../../schema/yarramate-apply-result.schema.json' with { type: 'json'
11
+ };
12
+ import operationsSchema from '../../../schema/yarramate-operations.schema.json' with { type: 'json'
13
+ };
14
+ import projectionSchema from '../../../schema/yarramate-projection.schema.json' with { type: 'json'
15
+ };
8
16
  import visualHandoffSchema from '../../../schema/yarramate-visual-handoff.schema.json' with { type: 'json'
9
17
  };
18
+ import visualLayoutSchema from '../../../schema/yarramate-visual-layout.schema.json' with { type: 'json'
19
+ };
10
20
  import visualModelSchema from '../../../schema/yarramate-visual-model.schema.json' with { type: 'json'
11
21
  };
12
22
  import visualResponseSchema from '../../../schema/yarramate-visual-response.schema.json' with { type: 'json'
@@ -24,17 +34,28 @@ import { VISUAL_LIMITS, } from './protocol-contract.js';
24
34
  // validates travel with the validators.
25
35
  export * from './protocol-contract.js';
26
36
  const Ajv2020 = Ajv2020Module.default;
27
- const ajv = new Ajv2020({ allErrors: true });
37
+ // `discriminator` on Core's operation union routes a staged edit to the branch
38
+ // its `op` names, so a browser changeset reports the fault the reviewer made
39
+ // rather than one near-miss per operation kind.
40
+ const ajv = new Ajv2020({ allErrors: true, discriminator: true });
28
41
  ajv.addSchema([
29
42
  visualDiagnosticResultSchema,
30
- visualModelSchema,
31
43
  visualEventSchema,
44
+ visualGraphSchema,
45
+ visualHandoffSchema,
46
+ visualModelSchema,
32
47
  visualResponseSchema,
48
+ visualSessionDescriptorSchema,
33
49
  visualSessionRequestSchema,
34
50
  visualSessionStartedSchema,
35
- visualSessionDescriptorSchema,
36
- visualHandoffSchema,
37
51
  visualStatusSchema,
52
+ visualLayoutSchema,
53
+ projectionSchema,
54
+ // The commit path's event and response documents reference Core's operations
55
+ // and apply-result shapes rather than restating them, so Ajv needs both
56
+ // resolvable before it compiles the visual validators.
57
+ operationsSchema,
58
+ applyResultSchema,
38
59
  ]);
39
60
  // Diagnostics report the document they came from rather than a source file,
40
61
  // because visual protocol documents arrive as parsed JSON over the wire.
@@ -50,7 +71,22 @@ const validateVisualModel = visualValidator('visual-model/v1');
50
71
  const validateVisualSessionRequest = visualValidator('visual-session-request/v1');
51
72
  const validateVisualSessionStarted = visualValidator('visual-session-started/v1');
52
73
  const validateVisualSessionDescriptor = visualValidator('visual-session-descriptor/v1');
53
- const validateVisualBrowserInput = visualValidator('visual-browser-input/v1', 'https://yarramate.org/schema/visual-event/v1#/$defs/browserInput');
74
+ const BROWSER_INPUT_REFERENCE = 'https://yarramate.org/schema/visual-event/v1#/$defs/browserInput';
75
+ const validateVisualBrowserInput = visualValidator('visual-browser-input/v1', BROWSER_INPUT_REFERENCE);
76
+ /**
77
+ * One validator per input type, keyed by the `type` its branch fixes.
78
+ *
79
+ * The union reports every branch it tried, so a `changeset.commit` that gets
80
+ * one field wrong arrives as that one violation buried under seven other
81
+ * types' missing properties - unreadable, and it is the reviewer who has to
82
+ * read it. An input that names a type the protocol knows is answered against
83
+ * that type alone. The vocabulary is read off the schema rather than restated
84
+ * here, so a new input type cannot be added without one.
85
+ */
86
+ const browserInputBranches = new Map(visualEventSchema.$defs.browserInput.oneOf.map((branch, index) => [
87
+ branch.properties.type.const,
88
+ visualValidator('visual-browser-input/v1', `${BROWSER_INPUT_REFERENCE}/oneOf/${index}`),
89
+ ]));
54
90
  const validateVisualEvent = visualValidator('visual-event/v1');
55
91
  const validateVisualResponse = visualValidator('visual-response/v1');
56
92
  const validateVisualHandoff = visualValidator('visual-handoff/v1');
@@ -83,13 +119,12 @@ const jsonBytes = (value) => {
83
119
  return 0;
84
120
  return Buffer.byteLength(encoded, 'utf8');
85
121
  };
86
- const MODEL_ROOT_CONFIG = 'likec4.config.json';
87
- const MODEL_SOURCE_EXTENSIONS = ['.c4', '.likec4'];
88
122
  /**
89
123
  * Relative POSIX path confined to the candidate root. Absolute paths, parent
90
- * traversal, empty segments, dot-prefixed segments (how a staged symlink or
91
- * metadata entry would be smuggled in), Windows separators, and NUL bytes are
92
- * all rejected.
124
+ * traversal, empty segments, `.`/`..` segments, Windows separators, and NUL
125
+ * bytes are all rejected. A dot-prefixed directory is not an escape and is
126
+ * kept: every workspace keeps its documents under `.yarramate/`, so the
127
+ * digests of a canonical model are unrepresentable without it.
93
128
  */
94
129
  const isConfinedRelativePath = (candidate) => {
95
130
  if (candidate.length === 0 || candidate.length > 1024)
@@ -102,35 +137,11 @@ const isConfinedRelativePath = (candidate) => {
102
137
  return false;
103
138
  return candidate
104
139
  .split('/')
105
- .every((segment) => segment.length > 0 && !segment.startsWith('.'));
106
- };
107
- export const isSafeVisualModelPath = (candidate) => {
108
- if (!isConfinedRelativePath(candidate))
109
- return false;
110
- if (candidate === MODEL_ROOT_CONFIG)
111
- return true;
112
- const extension = posix.extname(candidate);
113
- return MODEL_SOURCE_EXTENSIONS.some((allowed) => allowed === extension);
140
+ .every((segment) => segment.length > 0 && segment !== '.' && segment !== '..');
114
141
  };
115
142
  const modelSemantics = (input, path, prefix) => {
116
143
  const fields = documentFields(input);
117
144
  const diagnostics = [];
118
- const files = documentFields(fields.files);
119
- const fileKeys = Object.keys(files);
120
- if (fileKeys.length > 0) {
121
- let sources = 0;
122
- for (const key of fileKeys) {
123
- if (!isSafeVisualModelPath(key)) {
124
- diagnostics.push(visualDiagnostic('YMVS113', `Model file "${key}" escapes the candidate root or is not a LikeC4 source`, path, `${prefix}/files/${pointerSegment(key)}`));
125
- continue;
126
- }
127
- if (key !== MODEL_ROOT_CONFIG)
128
- sources += 1;
129
- }
130
- if (sources === 0) {
131
- diagnostics.push(visualDiagnostic('YMVS114', 'A visual model requires at least one .c4 or .likec4 source file', path, `${prefix}/files`));
132
- }
133
- }
134
145
  const digestKeys = Object.keys(documentFields(fields.sourceDigests));
135
146
  for (const key of digestKeys) {
136
147
  if (isConfinedRelativePath(key))
@@ -140,9 +151,6 @@ const modelSemantics = (input, path, prefix) => {
140
151
  if (fields.authority === 'canonical' && digestKeys.length === 0) {
141
152
  diagnostics.push(visualDiagnostic('YMVS112', 'A canonical visual model must record the source digests it was derived from', path, `${prefix}/sourceDigests`));
142
153
  }
143
- if (fields.authority === 'ad-hoc' && digestKeys.length > 0) {
144
- diagnostics.push(visualDiagnostic('YMVS112', 'An ad-hoc visual model must not claim canonical source digests', path, `${prefix}/sourceDigests`));
145
- }
146
154
  if (jsonBytes(input) > VISUAL_LIMITS.modelBytes) {
147
155
  diagnostics.push(visualDiagnostic('YMVS115', `A visual model must not exceed ${VISUAL_LIMITS.modelBytes} bytes`, path, prefix === '' ? '/' : prefix));
148
156
  }
@@ -182,9 +190,6 @@ const responseSemantics = (input, path) => {
182
190
  if (fields.type === 'chat.response') {
183
191
  return chatTextSemantics(fields.payload, path, '/payload');
184
192
  }
185
- if (fields.type === 'model.replace') {
186
- return modelSemantics(documentFields(fields.payload).model, path, '/payload/model');
187
- }
188
193
  return [];
189
194
  };
190
195
  /**
@@ -233,15 +238,30 @@ const schemaDiagnostics = (errors, code, path) => errors.map((error) => {
233
238
  ? `Property "${property}" is not allowed`
234
239
  : `${path} schema violation: ${describeSchemaViolation(error)}`, path, pointer);
235
240
  });
241
+ /**
242
+ * The same violation, reported once.
243
+ *
244
+ * A union reports the branches it tried, and sibling branches that share a
245
+ * requirement each raise it - the reviewer reads one document, not the
246
+ * validator's search. Diagnostics are already sorted, so identical neighbours
247
+ * are adjacent; nothing that differs in code, pointer, or message is lost.
248
+ */
249
+ const distinct = (diagnostics) => diagnostics.filter((diagnostic, index) => {
250
+ if (index === 0)
251
+ return true;
252
+ const previous = diagnostics[index - 1];
253
+ return (previous === undefined ||
254
+ visualDiagnosticOrder(previous, diagnostic) !== 0);
255
+ });
236
256
  const parseWith = (validate, input, code) => {
237
257
  const path = documentPaths.get(validate) ?? 'visual-document';
238
258
  const semantics = semanticsByDocument[path];
239
- const diagnostics = [
259
+ const diagnostics = distinct([
240
260
  ...(validate(input)
241
261
  ? []
242
- : schemaDiagnostics(validate.errors ?? [], code, path)),
262
+ : schemaDiagnostics(readableSchemaErrors(validate.errors ?? []), code, path)),
243
263
  ...(semantics ? semantics(input, path) : []),
244
- ].sort(visualDiagnosticOrder);
264
+ ].sort(visualDiagnosticOrder));
245
265
  if (diagnostics.length > 0)
246
266
  return { ok: false, diagnostics };
247
267
  return { ok: true, value: input };
@@ -250,7 +270,27 @@ export const parseVisualModel = (input) => parseWith(validateVisualModel, input,
250
270
  export const parseVisualSessionRequest = (input) => parseWith(validateVisualSessionRequest, input, 'YMVS101');
251
271
  export const parseVisualSessionStarted = (input) => parseWith(validateVisualSessionStarted, input, 'YMVS102');
252
272
  export const parseVisualSessionDescriptor = (input) => parseWith(validateVisualSessionDescriptor, input, 'YMVS103');
253
- export const parseVisualBrowserInput = (input) => parseWith(validateVisualBrowserInput, input, 'YMVS109');
273
+ /**
274
+ * The type an untrusted frame claims to be, when the protocol has that type.
275
+ *
276
+ * A refusal has to say what it refused, and the browser is holding a control
277
+ * open until it does. The claim is worth reporting before the document is
278
+ * known to be valid because the frame that named it is the one that failed.
279
+ */
280
+ export const visualBrowserInputType = (input) => {
281
+ const claimed = documentFields(input).type;
282
+ return typeof claimed === 'string' && browserInputBranches.has(claimed)
283
+ ? claimed
284
+ : undefined;
285
+ };
286
+ export const parseVisualBrowserInput = (input) => {
287
+ const claimed = visualBrowserInputType(input);
288
+ const validate = claimed === undefined
289
+ ? validateVisualBrowserInput
290
+ : // The branch is in the map because `claimed` came out of it.
291
+ browserInputBranches.get(claimed);
292
+ return parseWith(validate, input, 'YMVS109');
293
+ };
254
294
  export const parseVisualEvent = (input) => parseWith(validateVisualEvent, input, 'YMVS104');
255
295
  export const parseVisualResponse = (input) => parseWith(validateVisualResponse, input, 'YMVS105');
256
296
  export const parseVisualHandoff = (input) => parseWith(validateVisualHandoff, input, 'YMVS107');
@@ -0,0 +1,37 @@
1
+ import type { VisualDiagnostic, VisualSessionRequest } from './protocol-contract.js';
2
+ export interface VisualSessionRequestOptions {
3
+ readonly cwd: string;
4
+ /** Defaults to the workspace id. */
5
+ readonly title?: string;
6
+ /** Defaults to a line naming the workspace and its manifest. */
7
+ readonly description?: string;
8
+ /** Defaults to the first projection the workspace declares. */
9
+ readonly initialView?: string;
10
+ /** Defaults to `false`: a diagram-only session needs no model provider. */
11
+ readonly chatEnabled?: boolean;
12
+ }
13
+ export type VisualSessionRequestResult = {
14
+ readonly ok: true;
15
+ readonly request: VisualSessionRequest;
16
+ } | {
17
+ readonly ok: false;
18
+ readonly diagnostics: readonly VisualDiagnostic[];
19
+ };
20
+ /**
21
+ * Builds the `yarramate/visual-session-request/v1` document that `start`
22
+ * consumes, from the workspace on disk.
23
+ *
24
+ * The request carries a whole compiled model — 247 nodes and 338 edges for this
25
+ * repository's own architecture — so it is a machine's transcription of the
26
+ * workspace, never something an agent can honestly hand-author. Every input the
27
+ * document needs is already derivable: the graph from the native compiler, the
28
+ * digests from the same sources that compiled, and the view list from the
29
+ * workspace's declared projections.
30
+ *
31
+ * The result is validated through `parseVisualSessionRequest` before it is
32
+ * returned, so the byte ceiling, digest confinement, and authority agreement
33
+ * are the protocol's own rules rather than a second set restated here. A
34
+ * builder that cannot produce a valid document refuses instead of handing a
35
+ * session something it would reject at start.
36
+ */
37
+ export declare const buildVisualSessionRequest: (options: VisualSessionRequestOptions) => VisualSessionRequestResult;
@@ -0,0 +1,131 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { loadProjection } from '../../projection.js';
5
+ import { loadWorkspaceManifest } from '../../workspace.js';
6
+ import { parseVisualSessionRequest } from './protocol.js';
7
+ import { buildVisualModelGraph } from './session-store.js';
8
+ /**
9
+ * The one manifest a session can serve. `startVisualServer` resolves exactly
10
+ * this path relative to its own working directory, so the builder reads the
11
+ * same file rather than accepting a path that could name a different workspace
12
+ * than the session about to render it.
13
+ */
14
+ const MANIFEST_PATH = '.yarramate/workspace.yaml';
15
+ const requestDiagnostic = (code, message, path = MANIFEST_PATH) => ({
16
+ severity: 'error',
17
+ code,
18
+ message,
19
+ path,
20
+ pointer: '/',
21
+ line: 1,
22
+ column: 1,
23
+ });
24
+ const digestOf = (source) => createHash('sha256').update(source).digest('hex');
25
+ /**
26
+ * Builds the `yarramate/visual-session-request/v1` document that `start`
27
+ * consumes, from the workspace on disk.
28
+ *
29
+ * The request carries a whole compiled model — 247 nodes and 338 edges for this
30
+ * repository's own architecture — so it is a machine's transcription of the
31
+ * workspace, never something an agent can honestly hand-author. Every input the
32
+ * document needs is already derivable: the graph from the native compiler, the
33
+ * digests from the same sources that compiled, and the view list from the
34
+ * workspace's declared projections.
35
+ *
36
+ * The result is validated through `parseVisualSessionRequest` before it is
37
+ * returned, so the byte ceiling, digest confinement, and authority agreement
38
+ * are the protocol's own rules rather than a second set restated here. A
39
+ * builder that cannot produce a valid document refuses instead of handing a
40
+ * session something it would reject at start.
41
+ */
42
+ export const buildVisualSessionRequest = (options) => {
43
+ const manifestPath = resolve(options.cwd, MANIFEST_PATH);
44
+ let manifestSource;
45
+ try {
46
+ manifestSource = readFileSync(manifestPath, 'utf8');
47
+ }
48
+ catch {
49
+ return {
50
+ ok: false,
51
+ diagnostics: [
52
+ requestDiagnostic('YMVS410', `Workspace manifest ${manifestPath} cannot be read`),
53
+ ],
54
+ };
55
+ }
56
+ const loaded = loadWorkspaceManifest({ path: manifestPath, source: manifestSource }, options.cwd);
57
+ if (!loaded.ok) {
58
+ return { ok: false, diagnostics: loaded.diagnostics };
59
+ }
60
+ const workspace = loaded.workspace;
61
+ // Same order the session's own recompile uses, so the request's graph and
62
+ // every graph the session rebuilds after a commit come from one input list.
63
+ const sourcePaths = [...workspace.profiles, ...workspace.documents];
64
+ const sources = [];
65
+ for (const path of sourcePaths) {
66
+ try {
67
+ sources.push({ path, source: readFileSync(resolve(options.cwd, path), 'utf8') });
68
+ }
69
+ catch {
70
+ return {
71
+ ok: false,
72
+ diagnostics: [
73
+ requestDiagnostic('YMVS411', `Workspace source ${path} cannot be read`, path),
74
+ ],
75
+ };
76
+ }
77
+ }
78
+ const built = buildVisualModelGraph(sources);
79
+ if (!built.ok)
80
+ return { ok: false, diagnostics: built.diagnostics };
81
+ // A projection that does not load is skipped by the session too: the request
82
+ // names a view the browser will actually be able to open.
83
+ const viewIds = workspace.projections.flatMap((projectionPath) => {
84
+ try {
85
+ const projection = loadProjection({
86
+ path: projectionPath,
87
+ source: readFileSync(resolve(options.cwd, projectionPath), 'utf8'),
88
+ });
89
+ return projection.ok ? [projection.projection.id] : [];
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ });
95
+ const initialView = options.initialView ?? viewIds[0];
96
+ if (initialView === undefined) {
97
+ return {
98
+ ok: false,
99
+ diagnostics: [
100
+ requestDiagnostic('YMVS412', `Workspace ${workspace.id} declares no loadable projection, so a session has no view to open`),
101
+ ],
102
+ };
103
+ }
104
+ if (!viewIds.includes(initialView)) {
105
+ return {
106
+ ok: false,
107
+ diagnostics: [
108
+ requestDiagnostic('YMVS413', `Workspace ${workspace.id} declares no projection "${initialView}": ${viewIds.length === 0 ? 'it declares none' : viewIds.join(', ')}`),
109
+ ],
110
+ };
111
+ }
112
+ const request = {
113
+ format: 'yarramate/visual-session-request/v1',
114
+ authority: 'canonical',
115
+ title: options.title ?? workspace.id,
116
+ description: options.description ??
117
+ `Native rendering of workspace ${workspace.id} from ${MANIFEST_PATH}`,
118
+ chatEnabled: options.chatEnabled ?? false,
119
+ initialModel: {
120
+ format: 'yarramate/visual-model/v1',
121
+ authority: 'canonical',
122
+ initialView,
123
+ sourceDigests: Object.fromEntries(sources.map(({ path, source }) => [path, digestOf(source)])),
124
+ graph: built.graph,
125
+ },
126
+ };
127
+ const parsed = parseVisualSessionRequest(request);
128
+ if (!parsed.ok)
129
+ return { ok: false, diagnostics: parsed.diagnostics };
130
+ return { ok: true, request: parsed.value };
131
+ };
@@ -1,6 +1,6 @@
1
- import { type VisualDiagnostic, type VisualEvent, type VisualFreezeReason, type VisualHandoff, type VisualLifecycle, type VisualSessionRequest, type VisualSessionStarted, type VisualStatus, type VisualTerminationReason } from './protocol.js';
2
- import { type TerminalEventDependencies, type VisualSessionPaths } from './session-store.js';
3
- import type { VisualRenderedModel, VisualServerFrame, VisualSessionSnapshot, VisualTranscriptRecord } from './wire.js';
1
+ import { type VisualDiagnostic, type VisualEvent, type VisualFreezeReason, type VisualHandoff, type VisualLifecycle, type VisualSessionRequest, type VisualSessionStarted, type VisualStatus, type VisualTerminationReason } from "./protocol.js";
2
+ import { type TerminalEventDependencies, type VisualSessionPaths } from "./session-store.js";
3
+ import type { VisualRenderedModel, VisualServerFrame, VisualSessionSnapshot, VisualTranscriptRecord } from "./wire.js";
4
4
  export type { VisualRenderedModel, VisualServerFrame, VisualSessionSnapshot, VisualTranscriptRecord, };
5
5
  /**
6
6
  * Document name reported by diagnostics the server itself raises — a refused
@@ -14,9 +14,9 @@ export declare const VISUAL_SERVER_DOCUMENT = "visual-session-server";
14
14
  * and the page can be neither framed nor used as a base for relative fetches.
15
15
  */
16
16
  export declare const VISUAL_BROWSER_HEADERS: {
17
- readonly 'Referrer-Policy': 'no-referrer';
18
- readonly 'X-Content-Type-Options': 'nosniff';
19
- readonly 'Cache-Control': 'no-store';
17
+ readonly "Referrer-Policy": "no-referrer";
18
+ readonly "X-Content-Type-Options": "nosniff";
19
+ readonly "Cache-Control": "no-store";
20
20
  };
21
21
  /**
22
22
  * This session's content policy. Every source stays `'self'`; the one addition
@@ -52,7 +52,6 @@ export type VisualResponseAcceptance = {
52
52
  readonly accepted: true;
53
53
  readonly duplicate: boolean;
54
54
  readonly lastSequence: number;
55
- readonly model?: VisualRenderedModel;
56
55
  readonly diagnostics: readonly VisualDiagnostic[];
57
56
  } | {
58
57
  readonly accepted: false;
@@ -67,6 +66,8 @@ export interface VisualServerOptions {
67
66
  readonly request: VisualSessionRequest;
68
67
  /** Directory that holds one directory per live session. */
69
68
  readonly baseDir: string;
69
+ /** Working directory for resolving .yarramate/workspace.yaml and projections. */
70
+ readonly cwd: string;
70
71
  /** Root of the self-contained browser application. */
71
72
  readonly assetRoot?: string;
72
73
  readonly now?: () => Date;
@@ -98,8 +99,6 @@ export interface VisualServerHandle {
98
99
  export interface ActiveVisualSession {
99
100
  readonly paths: VisualSessionPaths;
100
101
  lifecycle: VisualLifecycle;
101
- /** Cancels whatever the trusted compiler is doing for this session. */
102
- readonly compilerAbort: AbortController;
103
102
  /** Records why the browser stopped being able to speak. */
104
103
  readonly freeze: (reason: VisualFreezeReason) => void;
105
104
  /** Settles work already admitted, so recovery reads a quiet journal. */
@@ -115,11 +114,10 @@ export interface ActiveVisualSession {
115
114
  * that failed, a browser that never came back, a cancelling main agent, or a
116
115
  * runtime shutting itself down.
117
116
  *
118
- * The order is the invariant. Input freezes before anything is read; the
119
- * compiler is cancelled rather than waited out; work already admitted is still
120
- * allowed to finish; exactly one terminal event is journaled; and the handoff
121
- * is recovered without deleting anything, so `stop` — and only `stop` — is what
122
- * removes the session directory.
117
+ * The order is the invariant. Input freezes before anything is read; work
118
+ * already admitted is still allowed to finish; exactly one terminal event is
119
+ * journaled; and the handoff is recovered without deleting anything, so
120
+ * `stop` — and only `stop` — is what removes the session directory.
123
121
  */
124
122
  export declare const terminateVisualSession: (session: ActiveVisualSession, reason: VisualTerminationReason) => Promise<VisualHandoff>;
125
123
  /**