deepclause-sdk 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +72 -3
  2. package/dist/agent.d.ts +17 -0
  3. package/dist/agent.d.ts.map +1 -1
  4. package/dist/agent.js +148 -42
  5. package/dist/agent.js.map +1 -1
  6. package/dist/cli/config.d.ts +12 -12
  7. package/dist/cli/repl.d.ts +13 -1
  8. package/dist/cli/repl.d.ts.map +1 -1
  9. package/dist/cli/repl.js +145 -4
  10. package/dist/cli/repl.js.map +1 -1
  11. package/dist/forms/index.d.ts +3 -0
  12. package/dist/forms/index.d.ts.map +1 -0
  13. package/dist/forms/index.js +3 -0
  14. package/dist/forms/index.js.map +1 -0
  15. package/dist/forms/registry.d.ts +119 -0
  16. package/dist/forms/registry.d.ts.map +1 -0
  17. package/dist/forms/registry.js +256 -0
  18. package/dist/forms/registry.js.map +1 -0
  19. package/dist/forms/spec.d.ts +193 -0
  20. package/dist/forms/spec.d.ts.map +1 -0
  21. package/dist/forms/spec.js +295 -0
  22. package/dist/forms/spec.js.map +1 -0
  23. package/dist/index.d.ts +7 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +7 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/prolog/loader.d.ts +18 -0
  28. package/dist/prolog/loader.d.ts.map +1 -1
  29. package/dist/prolog/loader.js +26 -1
  30. package/dist/prolog/loader.js.map +1 -1
  31. package/dist/prolog-src/deepclause_mi.pl +619 -28
  32. package/dist/repl/agent.d.ts +4 -0
  33. package/dist/repl/agent.d.ts.map +1 -1
  34. package/dist/repl/agent.js +2 -0
  35. package/dist/repl/agent.js.map +1 -1
  36. package/dist/repl/form-widget.d.ts +56 -0
  37. package/dist/repl/form-widget.d.ts.map +1 -0
  38. package/dist/repl/form-widget.js +289 -0
  39. package/dist/repl/form-widget.js.map +1 -0
  40. package/dist/repl/harness-tools.d.ts +3 -1
  41. package/dist/repl/harness-tools.d.ts.map +1 -1
  42. package/dist/repl/harness-tools.js +13 -56
  43. package/dist/repl/harness-tools.js.map +1 -1
  44. package/dist/repl/history.d.ts +2 -1
  45. package/dist/repl/history.d.ts.map +1 -1
  46. package/dist/repl/history.js +34 -8
  47. package/dist/repl/history.js.map +1 -1
  48. package/dist/repl/index.d.ts +14 -2
  49. package/dist/repl/index.d.ts.map +1 -1
  50. package/dist/repl/index.js +6 -0
  51. package/dist/repl/index.js.map +1 -1
  52. package/dist/repl/process-backend.d.ts +2 -2
  53. package/dist/repl/process-backend.d.ts.map +1 -1
  54. package/dist/repl/process-executor.d.ts +11 -2
  55. package/dist/repl/process-executor.d.ts.map +1 -1
  56. package/dist/repl/process-executor.js +67 -18
  57. package/dist/repl/process-executor.js.map +1 -1
  58. package/dist/repl/process-worker.d.ts +35 -4
  59. package/dist/repl/process-worker.d.ts.map +1 -1
  60. package/dist/repl/process-worker.js +78 -38
  61. package/dist/repl/process-worker.js.map +1 -1
  62. package/dist/repl/processes.d.ts +4 -0
  63. package/dist/repl/processes.d.ts.map +1 -1
  64. package/dist/repl/processes.js +20 -0
  65. package/dist/repl/processes.js.map +1 -1
  66. package/dist/repl/render.d.ts +17 -0
  67. package/dist/repl/render.d.ts.map +1 -1
  68. package/dist/repl/render.js +50 -0
  69. package/dist/repl/render.js.map +1 -1
  70. package/dist/repl/session.d.ts +105 -7
  71. package/dist/repl/session.d.ts.map +1 -1
  72. package/dist/repl/session.js +219 -15
  73. package/dist/repl/session.js.map +1 -1
  74. package/dist/repl/tui/form-view.d.ts +17 -0
  75. package/dist/repl/tui/form-view.d.ts.map +1 -0
  76. package/dist/repl/tui/form-view.js +25 -0
  77. package/dist/repl/tui/form-view.js.map +1 -0
  78. package/dist/repl/tui/renderer.d.ts +4 -0
  79. package/dist/repl/tui/renderer.d.ts.map +1 -1
  80. package/dist/repl/tui/renderer.js +12 -0
  81. package/dist/repl/tui/renderer.js.map +1 -1
  82. package/dist/repl/worker-host.d.ts +16 -2
  83. package/dist/repl/worker-host.d.ts.map +1 -1
  84. package/dist/repl/worker-host.js +38 -6
  85. package/dist/repl/worker-host.js.map +1 -1
  86. package/dist/repl/worker-protocol.d.ts +14 -0
  87. package/dist/repl/worker-protocol.d.ts.map +1 -1
  88. package/dist/repl/worker-protocol.js +8 -1
  89. package/dist/repl/worker-protocol.js.map +1 -1
  90. package/dist/runner.d.ts +63 -1
  91. package/dist/runner.d.ts.map +1 -1
  92. package/dist/runner.js +350 -40
  93. package/dist/runner.js.map +1 -1
  94. package/dist/sdk.d.ts.map +1 -1
  95. package/dist/sdk.js +12 -0
  96. package/dist/sdk.js.map +1 -1
  97. package/dist/system/assets/docs/AGENT_PROMPT.md +387 -18
  98. package/dist/system/assets/docs/CHAT_PROMPT.md +28 -0
  99. package/dist/system/assets/docs/DML_AUTHORING.md +1 -1
  100. package/dist/system/assets/docs/DML_FORMS.md +740 -0
  101. package/dist/system/assets/docs/DML_REFERENCE.md +180 -4
  102. package/dist/system/assets/docs/HARNESS_EXAMPLES.md +94 -0
  103. package/dist/system/assets/index.d.ts +2 -2
  104. package/dist/system/assets/index.d.ts.map +1 -1
  105. package/dist/system/assets/index.js +4 -0
  106. package/dist/system/assets/index.js.map +1 -1
  107. package/dist/system/environment.d.ts +6 -0
  108. package/dist/system/environment.d.ts.map +1 -1
  109. package/dist/system/environment.js +5 -4
  110. package/dist/system/environment.js.map +1 -1
  111. package/dist/types.d.ts +35 -1
  112. package/dist/types.d.ts.map +1 -1
  113. package/package.json +4 -2
  114. package/src/prolog-src/deepclause_mi.pl +619 -28
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The form registry: the host-owned state a form lives in.
3
+ *
4
+ * One registry per root session. It owns the spec, the values, a monotonic
5
+ * revision, and the waiters. `submit`/`close` (a *UI action*) produce a
6
+ * `FormChange`; `update`/`setIssues` (an *agent edit*) bump the revision for
7
+ * rendering but never wake a waiter — otherwise the agent's own edit would
8
+ * resolve its own `await_form`. See `docs/DML_FORMS.md` §7.
9
+ */
10
+ import { type FormChange, type FormIssue, type FormSpec, type Json, type JsonObject } from './spec.js';
11
+ export type FormOp = 'open' | 'update' | 'close';
12
+ export interface FormEvent {
13
+ type: 'form';
14
+ op: FormOp;
15
+ formId: string;
16
+ revision: number;
17
+ spec?: FormSpec;
18
+ patch?: JsonObject;
19
+ values?: JsonObject;
20
+ issues?: FormIssue[];
21
+ state?: 'open' | 'submitted' | 'cancelled';
22
+ reason?: string;
23
+ source?: {
24
+ name?: string;
25
+ pid?: string;
26
+ };
27
+ }
28
+ export interface FormRecord {
29
+ formId: string;
30
+ spec: FormSpec;
31
+ values: JsonObject;
32
+ issues: FormIssue[];
33
+ revision: number;
34
+ /** Revision at which the form was opened; see `awaitingForms()`. */
35
+ openRevision: number;
36
+ state: 'open' | 'submitted' | 'cancelled';
37
+ changed?: string[];
38
+ source?: {
39
+ name?: string;
40
+ pid?: string;
41
+ };
42
+ }
43
+ export interface OpenOptions {
44
+ formId?: string;
45
+ values?: JsonObject;
46
+ source?: {
47
+ name?: string;
48
+ pid?: string;
49
+ };
50
+ }
51
+ export interface WaitOptions {
52
+ timeoutMs?: number;
53
+ signal?: AbortSignal;
54
+ }
55
+ export interface FormRegistryOptions {
56
+ onEvent?: (event: FormEvent) => void;
57
+ }
58
+ export declare class FormRegistry {
59
+ private readonly options;
60
+ private readonly forms;
61
+ private readonly waiters;
62
+ private readonly lastChange;
63
+ /** Per-form cursor: the last revision delivered to (or consumed by) a caller. */
64
+ private readonly delivered;
65
+ private counter;
66
+ constructor(options?: FormRegistryOptions);
67
+ /** Open (or replace) a form. Returns its id and revision. */
68
+ open(spec: FormSpec, options?: OpenOptions): {
69
+ formId: string;
70
+ revision: number;
71
+ values: JsonObject;
72
+ };
73
+ /** Merge-patch a form (agent edit). Bumps the revision; does not wake waiters. */
74
+ update(formId: string, patch: JsonObject): {
75
+ revision: number;
76
+ values: JsonObject;
77
+ } | undefined;
78
+ /** Attach per-field messages (agent edit). An empty list clears them. */
79
+ setIssues(formId: string, issues: FormIssue[]): {
80
+ revision: number;
81
+ } | undefined;
82
+ /**
83
+ * A UI action: record it, wake the waiters, and return the change. This is the
84
+ * only path that produces a change for `wait`.
85
+ */
86
+ submit(formId: string, action: string, values?: JsonObject, errors?: FormIssue[]): FormChange | undefined;
87
+ /** Close a form. Pending waiters resolve with `closed`. */
88
+ close(formId: string, state?: 'submitted' | 'cancelled', reason?: string): void;
89
+ /** Resolve every pending waiter (turn abort). */
90
+ cancelPending(action?: string): void;
91
+ /**
92
+ * Wait for a UI change. `since` defaults to the form's delivered cursor (set
93
+ * at open, advanced per delivery), so a caller need not track revisions and a
94
+ * submit that raced the wait is still delivered.
95
+ */
96
+ wait(formId: string, since?: number, options?: WaitOptions): Promise<FormChange>;
97
+ get(formId: string): FormRecord | undefined;
98
+ /**
99
+ * Forms that are open and left with a **change nobody has read**.
100
+ *
101
+ * That is either a form the model put in front of the person and never waited
102
+ * on (no change delivered since it was opened), or one it changed *after* the
103
+ * last delivery — showing errors for a rejected value, patching a computed
104
+ * field — which asks the person for another action nobody is waiting for.
105
+ *
106
+ * A conversational turn uses this so it cannot end with a form the person is
107
+ * still filling in: the submission would have nowhere to go.
108
+ */
109
+ awaitingForms(): FormRecord[];
110
+ list(): FormRecord[];
111
+ private wake;
112
+ private settle;
113
+ private removeWaiter;
114
+ private emit;
115
+ }
116
+ export declare function mergePatch(target: Json, patch: Json): Json;
117
+ /** Dotted paths that differ between two value trees. */
118
+ export declare function diffPaths(before: JsonObject, after: JsonObject, prefix?: string): string[];
119
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/forms/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * The form registry: the host-owned state a form lives in.
3
+ *
4
+ * One registry per root session. It owns the spec, the values, a monotonic
5
+ * revision, and the waiters. `submit`/`close` (a *UI action*) produce a
6
+ * `FormChange`; `update`/`setIssues` (an *agent edit*) bump the revision for
7
+ * rendering but never wake a waiter — otherwise the agent's own edit would
8
+ * resolve its own `await_form`. See `docs/DML_FORMS.md` §7.
9
+ */
10
+ import { applyDefaults, isPlainObject, } from './spec.js';
11
+ export class FormRegistry {
12
+ options;
13
+ forms = new Map();
14
+ waiters = new Map();
15
+ lastChange = new Map();
16
+ /** Per-form cursor: the last revision delivered to (or consumed by) a caller. */
17
+ delivered = new Map();
18
+ counter = 0;
19
+ constructor(options = {}) {
20
+ this.options = options;
21
+ }
22
+ /** Open (or replace) a form. Returns its id and revision. */
23
+ open(spec, options = {}) {
24
+ const formId = options.formId ?? spec.id ?? `form_${++this.counter}`;
25
+ const existing = this.forms.get(formId);
26
+ const revision = (existing?.revision ?? 0) + 1;
27
+ const values = applyDefaults(spec, options.values ?? existing?.values ?? {});
28
+ const record = {
29
+ formId,
30
+ spec,
31
+ values,
32
+ issues: [],
33
+ revision,
34
+ openRevision: revision,
35
+ state: 'open',
36
+ source: options.source ?? existing?.source,
37
+ };
38
+ this.forms.set(formId, record);
39
+ this.delivered.set(formId, revision);
40
+ this.emit({ type: 'form', op: 'open', formId, revision, spec, values, issues: [], source: record.source });
41
+ return { formId, revision, values };
42
+ }
43
+ /** Merge-patch a form (agent edit). Bumps the revision; does not wake waiters. */
44
+ update(formId, patch) {
45
+ const record = this.forms.get(formId);
46
+ if (!record)
47
+ return undefined;
48
+ record.values = mergePatch(record.values, patch);
49
+ record.revision += 1;
50
+ this.emit({ type: 'form', op: 'update', formId, revision: record.revision, patch, values: record.values, issues: record.issues });
51
+ return { revision: record.revision, values: record.values };
52
+ }
53
+ /** Attach per-field messages (agent edit). An empty list clears them. */
54
+ setIssues(formId, issues) {
55
+ const record = this.forms.get(formId);
56
+ if (!record)
57
+ return undefined;
58
+ record.issues = issues;
59
+ record.revision += 1;
60
+ this.emit({
61
+ type: 'form',
62
+ op: 'update',
63
+ formId,
64
+ revision: record.revision,
65
+ values: record.values,
66
+ issues,
67
+ });
68
+ return { revision: record.revision };
69
+ }
70
+ /**
71
+ * A UI action: record it, wake the waiters, and return the change. This is the
72
+ * only path that produces a change for `wait`.
73
+ */
74
+ submit(formId, action, values = {}, errors = []) {
75
+ const record = this.forms.get(formId);
76
+ if (!record)
77
+ return undefined;
78
+ const previous = record.values;
79
+ record.values = { ...values };
80
+ record.revision += 1;
81
+ const changed = diffPaths(previous, record.values);
82
+ const change = {
83
+ formId,
84
+ revision: record.revision,
85
+ action,
86
+ values: record.values,
87
+ changed,
88
+ errors,
89
+ };
90
+ record.changed = changed;
91
+ this.lastChange.set(formId, change);
92
+ this.wake(formId, change);
93
+ return change;
94
+ }
95
+ /** Close a form. Pending waiters resolve with `closed`. */
96
+ close(formId, state = 'submitted', reason) {
97
+ const record = this.forms.get(formId);
98
+ if (!record)
99
+ return;
100
+ record.state = state;
101
+ record.revision += 1;
102
+ const change = { formId, revision: record.revision, action: 'closed', values: record.values };
103
+ this.lastChange.set(formId, change);
104
+ this.emit({ type: 'form', op: 'close', formId, revision: record.revision, state, values: record.values, reason });
105
+ this.wake(formId, change);
106
+ }
107
+ /** Resolve every pending waiter (turn abort). */
108
+ cancelPending(action = 'cancelled') {
109
+ for (const [formId, list] of this.waiters) {
110
+ const record = this.forms.get(formId);
111
+ const change = {
112
+ formId,
113
+ revision: record?.revision ?? 0,
114
+ action,
115
+ values: record?.values ?? {},
116
+ };
117
+ for (const waiter of list.splice(0))
118
+ this.settle(waiter, change);
119
+ }
120
+ }
121
+ /**
122
+ * Wait for a UI change. `since` defaults to the form's delivered cursor (set
123
+ * at open, advanced per delivery), so a caller need not track revisions and a
124
+ * submit that raced the wait is still delivered.
125
+ */
126
+ wait(formId, since, options = {}) {
127
+ const record = this.forms.get(formId);
128
+ if (!record) {
129
+ return Promise.resolve({ formId, revision: 0, action: 'unavailable', values: {} });
130
+ }
131
+ const cursor = since !== undefined && since >= 0 ? since : this.delivered.get(formId) ?? 0;
132
+ const existing = this.lastChange.get(formId);
133
+ if (existing && existing.revision > cursor) {
134
+ this.delivered.set(formId, existing.revision);
135
+ return Promise.resolve(existing);
136
+ }
137
+ if (record.state !== 'open') {
138
+ return Promise.resolve({ formId, revision: record.revision, action: 'closed', values: record.values });
139
+ }
140
+ return new Promise((resolve) => {
141
+ const waiter = { since: cursor, resolve };
142
+ if (options.timeoutMs !== undefined && options.timeoutMs > 0) {
143
+ waiter.timer = setTimeout(() => {
144
+ this.removeWaiter(formId, waiter);
145
+ this.settle(waiter, { formId, revision: record.revision, action: 'timeout', values: record.values });
146
+ }, options.timeoutMs);
147
+ waiter.timer.unref?.();
148
+ }
149
+ if (options.signal) {
150
+ const onAbort = () => {
151
+ this.removeWaiter(formId, waiter);
152
+ this.settle(waiter, { formId, revision: record.revision, action: 'cancelled', values: record.values });
153
+ };
154
+ if (options.signal.aborted) {
155
+ onAbort();
156
+ return;
157
+ }
158
+ waiter.onAbort = onAbort;
159
+ waiter.signal = options.signal;
160
+ options.signal.addEventListener('abort', onAbort, { once: true });
161
+ }
162
+ const list = this.waiters.get(formId) ?? [];
163
+ list.push(waiter);
164
+ this.waiters.set(formId, list);
165
+ });
166
+ }
167
+ get(formId) {
168
+ return this.forms.get(formId);
169
+ }
170
+ /**
171
+ * Forms that are open and left with a **change nobody has read**.
172
+ *
173
+ * That is either a form the model put in front of the person and never waited
174
+ * on (no change delivered since it was opened), or one it changed *after* the
175
+ * last delivery — showing errors for a rejected value, patching a computed
176
+ * field — which asks the person for another action nobody is waiting for.
177
+ *
178
+ * A conversational turn uses this so it cannot end with a form the person is
179
+ * still filling in: the submission would have nowhere to go.
180
+ */
181
+ awaitingForms() {
182
+ return [...this.forms.values()].filter((record) => {
183
+ if (record.state !== 'open')
184
+ return false;
185
+ const delivered = this.delivered.get(record.formId) ?? 0;
186
+ return delivered <= record.openRevision || record.revision > delivered;
187
+ });
188
+ }
189
+ list() {
190
+ return [...this.forms.values()];
191
+ }
192
+ // -------------------------------------------------------------------------
193
+ wake(formId, change) {
194
+ const list = this.waiters.get(formId);
195
+ if (!list)
196
+ return;
197
+ this.delivered.set(formId, change.revision);
198
+ for (const waiter of list.splice(0))
199
+ this.settle(waiter, change);
200
+ }
201
+ settle(waiter, change) {
202
+ if (waiter.timer) {
203
+ clearTimeout(waiter.timer);
204
+ waiter.timer = undefined;
205
+ }
206
+ // Detach the abort hook; a successful wake must not also cancel the waiter.
207
+ // (Calling `onAbort` here resolved every submitted form as `cancelled`.)
208
+ if (waiter.signal && waiter.onAbort) {
209
+ waiter.signal.removeEventListener('abort', waiter.onAbort);
210
+ }
211
+ waiter.onAbort = undefined;
212
+ waiter.resolve(change);
213
+ }
214
+ removeWaiter(formId, waiter) {
215
+ const list = this.waiters.get(formId);
216
+ if (!list)
217
+ return;
218
+ const index = list.indexOf(waiter);
219
+ if (index >= 0)
220
+ list.splice(index, 1);
221
+ }
222
+ emit(event) {
223
+ this.options.onEvent?.(event);
224
+ }
225
+ }
226
+ // ---------------------------------------------------------------------------
227
+ // Merge patch (RFC 7386) and a shallow path diff
228
+ // ---------------------------------------------------------------------------
229
+ export function mergePatch(target, patch) {
230
+ if (!isPlainObject(patch))
231
+ return patch;
232
+ const base = isPlainObject(target) ? { ...target } : {};
233
+ for (const [key, value] of Object.entries(patch)) {
234
+ if (value === null)
235
+ delete base[key];
236
+ else
237
+ base[key] = mergePatch(base[key], value);
238
+ }
239
+ return base;
240
+ }
241
+ /** Dotted paths that differ between two value trees. */
242
+ export function diffPaths(before, after, prefix = '') {
243
+ const out = [];
244
+ const keys = [...new Set([...Object.keys(before), ...Object.keys(after)])].sort();
245
+ for (const key of keys) {
246
+ const path = prefix ? `${prefix}.${key}` : key;
247
+ const a = before[key];
248
+ const b = after[key];
249
+ if (isPlainObject(a) && isPlainObject(b))
250
+ out.push(...diffPaths(a, b, path));
251
+ else if (JSON.stringify(a) !== JSON.stringify(b))
252
+ out.push(path);
253
+ }
254
+ return out;
255
+ }
256
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/forms/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,aAAa,EACb,aAAa,GAMd,MAAM,WAAW,CAAC;AAsDnB,MAAM,OAAO,YAAY;IAQM;IAPZ,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtC,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IACtC,UAAU,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC5D,iFAAiF;IAChE,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,OAAO,GAAG,CAAC,CAAC;IAEpB,YAA6B,UAA+B,EAAE;QAAjC,YAAO,GAAP,OAAO,CAA0B;IAAG,CAAC;IAElE,6DAA6D;IAC7D,IAAI,CAAC,IAAc,EAAE,UAAuB,EAAE;QAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,IAAI,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;QAC7E,MAAM,MAAM,GAAe;YACzB,MAAM;YACN,IAAI;YACJ,MAAM;YACN,MAAM,EAAE,EAAE;YACV,QAAQ;YACR,YAAY,EAAE,QAAQ;YACtB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ,EAAE,MAAM;SAC3C,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3G,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;IAED,kFAAkF;IAClF,MAAM,CAAC,MAAc,EAAE,KAAiB;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAe,CAAC;QAC/D,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAClI,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC9D,CAAC;IAED,yEAAyE;IACzE,SAAS,CAAC,MAAc,EAAE,MAAmB;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,MAAM;YACZ,EAAE,EAAE,QAAQ;YACZ,MAAM;YACN,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM;SACP,CAAC,CAAC;QACH,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAc,EAAE,MAAc,EAAE,SAAqB,EAAE,EAAE,SAAsB,EAAE;QACtF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QAC/B,MAAM,CAAC,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;QAC9B,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QACrB,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,MAAM,GAAe;YACzB,MAAM;YACN,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM;YACN,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO;YACP,MAAM;SACP,CAAC;QACF,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,MAAc,EAAE,QAAmC,WAAW,EAAE,MAAe;QACnF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QACrB,MAAM,MAAM,GAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1G,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAClH,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC;IAED,iDAAiD;IACjD,aAAa,CAAC,MAAM,GAAG,WAAW;QAChC,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,MAAM,GAAe;gBACzB,MAAM;gBACN,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,CAAC;gBAC/B,MAAM;gBACN,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE;aAC7B,CAAC;YACF,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,IAAI,CAAC,MAAc,EAAE,KAAc,EAAE,UAAuB,EAAE;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACrF,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,GAAG,MAAM,EAAE,CAAC;YAC3C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC9C,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACzG,CAAC;QAED,OAAO,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;YACzC,MAAM,MAAM,GAAW,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;YAClD,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;gBAC7D,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC7B,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBAClC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;gBACvG,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;gBACtB,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YACzB,CAAC;YACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,OAAO,GAAG,GAAS,EAAE;oBACzB,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBAClC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;gBACzG,CAAC,CAAC;gBACF,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;oBAC3B,OAAO,EAAE,CAAC;oBACV,OAAO;gBACT,CAAC;gBACD,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;gBACzB,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;gBAC/B,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED;;;;;;;;;;OAUG;IACH,aAAa;QACX,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE;YAChD,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM;gBAAE,OAAO,KAAK,CAAC;YAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACzD,OAAO,SAAS,IAAI,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,QAAQ,GAAG,SAAS,CAAC;QACzE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,4EAA4E;IAEpE,IAAI,CAAC,MAAc,EAAE,MAAkB;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5C,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnE,CAAC;IAEO,MAAM,CAAC,MAAc,EAAE,MAAkB;QAC/C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3B,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC;QAC3B,CAAC;QACD,4EAA4E;QAC5E,yEAAyE;QACzE,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;QAC3B,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAEO,YAAY,CAAC,MAAc,EAAE,MAAc;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACnC,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IAEO,IAAI,CAAC,KAAgB;QAC3B,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;CACF;AAED,8EAA8E;AAC9E,iDAAiD;AACjD,8EAA8E;AAE9E,MAAM,UAAU,UAAU,CAAC,MAAY,EAAE,KAAW;IAClD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,IAAI,GAAe,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,GAAI,MAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;;YAChC,IAAI,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,SAAS,CAAC,MAAkB,EAAE,KAAiB,EAAE,MAAM,GAAG,EAAE;IAC1E,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/C,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAe,EAAE,CAAe,EAAE,IAAI,CAAC,CAAC,CAAC;aACpG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * The form representation: the declarative spec a harness (or a model) produces,
3
+ * the values a UI collects, and the two validators.
4
+ *
5
+ * Pure functions and types — no runtime, no registry, no events. See
6
+ * `docs/DML_FORMS.md` §5.
7
+ */
8
+ export type Json = string | number | boolean | null | Json[] | {
9
+ [key: string]: Json;
10
+ };
11
+ export type JsonObject = {
12
+ [key: string]: Json;
13
+ };
14
+ /** Presentation hint only; validation never reads it. */
15
+ export type Widget = 'text' | 'textarea' | 'number' | 'slider' | 'select' | 'radio' | 'multiselect' | 'checkbox' | 'switch' | 'date' | 'time' | 'datetime' | 'file' | 'hidden';
16
+ export type FieldType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null';
17
+ export interface FieldOption {
18
+ value: string;
19
+ title?: string;
20
+ description?: string;
21
+ }
22
+ interface FieldBase {
23
+ /** Unique within its parent. The contract: rules and patches address fields by path. */
24
+ name: string;
25
+ type: FieldType;
26
+ required?: boolean;
27
+ default?: Json;
28
+ title?: string;
29
+ description?: string;
30
+ widget?: Widget;
31
+ }
32
+ export interface StringField extends FieldBase {
33
+ type: 'string';
34
+ format?: 'date' | 'time' | 'datetime' | 'email' | 'uri' | 'media';
35
+ enum?: string[];
36
+ options?: FieldOption[];
37
+ minLength?: number;
38
+ maxLength?: number;
39
+ pattern?: string;
40
+ }
41
+ export interface NumberField extends FieldBase {
42
+ type: 'number' | 'integer';
43
+ minimum?: number;
44
+ maximum?: number;
45
+ multipleOf?: number;
46
+ }
47
+ export interface BooleanField extends FieldBase {
48
+ type: 'boolean';
49
+ }
50
+ export interface ObjectField extends FieldBase {
51
+ type: 'object';
52
+ properties: Field[];
53
+ }
54
+ export interface ArrayField extends FieldBase {
55
+ type: 'array';
56
+ items: Field;
57
+ minItems?: number;
58
+ maxItems?: number;
59
+ }
60
+ export interface NullField extends FieldBase {
61
+ type: 'null';
62
+ }
63
+ export type Field = StringField | NumberField | BooleanField | ObjectField | ArrayField | NullField;
64
+ export interface LayoutBase {
65
+ /** Grid columns this node occupies. */
66
+ span?: number;
67
+ }
68
+ export interface LayoutRow extends LayoutBase {
69
+ kind: 'row';
70
+ children: LayoutNode[];
71
+ gap?: number;
72
+ align?: 'start' | 'center' | 'end' | 'stretch';
73
+ wrap?: boolean;
74
+ }
75
+ export interface LayoutColumn extends LayoutBase {
76
+ kind: 'column';
77
+ children: LayoutNode[];
78
+ gap?: number;
79
+ }
80
+ export interface LayoutGrid extends LayoutBase {
81
+ kind: 'grid';
82
+ columns: number;
83
+ gap?: number;
84
+ children: LayoutNode[];
85
+ }
86
+ export interface LayoutBox extends LayoutBase {
87
+ kind: 'box';
88
+ title?: string;
89
+ description?: string;
90
+ variant?: 'plain' | 'card' | 'fieldset';
91
+ children: LayoutNode[];
92
+ }
93
+ export interface LayoutTabs extends LayoutBase {
94
+ kind: 'tabs';
95
+ tabs: Array<{
96
+ title: string;
97
+ children: LayoutNode[];
98
+ }>;
99
+ }
100
+ export interface LayoutField extends LayoutBase {
101
+ kind: 'field';
102
+ /** Path of a declared field. */
103
+ field: string;
104
+ widget?: Widget;
105
+ label?: string;
106
+ help?: string;
107
+ }
108
+ export interface LayoutText extends LayoutBase {
109
+ kind: 'text';
110
+ text: string;
111
+ variant?: 'body' | 'caption' | 'heading';
112
+ }
113
+ export interface LayoutDivider extends LayoutBase {
114
+ kind: 'divider';
115
+ }
116
+ export interface LayoutSpacer extends LayoutBase {
117
+ kind: 'spacer';
118
+ size?: number;
119
+ }
120
+ export type LayoutNode = LayoutRow | LayoutColumn | LayoutGrid | LayoutBox | LayoutTabs | LayoutField | LayoutText | LayoutDivider | LayoutSpacer;
121
+ export interface FormAction {
122
+ name: string;
123
+ title: string;
124
+ kind?: 'primary' | 'default' | 'danger' | 'link';
125
+ confirm?: string;
126
+ /** Paths to validate before the action is allowed, or `hard`/`all`. */
127
+ validates?: 'all' | 'hard' | string[];
128
+ }
129
+ export interface FormSpec {
130
+ version: 1;
131
+ id?: string;
132
+ title?: string;
133
+ description?: string;
134
+ fields: Field[];
135
+ layout?: LayoutNode[];
136
+ initial?: JsonObject;
137
+ actions?: FormAction[];
138
+ ui?: {
139
+ submitOnEnter?: boolean;
140
+ dense?: boolean;
141
+ };
142
+ meta?: JsonObject;
143
+ }
144
+ /** A per-field message, from the host (shape) or the harness (domain). */
145
+ export interface FormIssue {
146
+ path: string;
147
+ level: 'error' | 'warning';
148
+ message: string;
149
+ }
150
+ /** What a UI sends back when the user acts. */
151
+ export interface FormChange {
152
+ formId: string;
153
+ /** Monotonic; the race-free cursor. */
154
+ revision: number;
155
+ action: string;
156
+ values: JsonObject;
157
+ changed?: string[];
158
+ errors?: FormIssue[];
159
+ }
160
+ export declare const DEFAULT_ACTIONS: FormAction[];
161
+ export declare function actionsOf(spec: FormSpec): FormAction[];
162
+ export interface FieldRef {
163
+ path: string;
164
+ field: Field;
165
+ }
166
+ /** Every field, depth-first, with its dotted path (`a.b`, `items[0].c` is the value form). */
167
+ export declare function walkFields(fields: Field[], prefix?: string): FieldRef[];
168
+ /** The declared fields, keyed by path. */
169
+ export declare function fieldMap(spec: FormSpec): Map<string, Field>;
170
+ /** Resolve defaults into a complete value set (deepest-first). Never mutates input. */
171
+ export declare function applyDefaults(spec: FormSpec, values?: JsonObject): JsonObject;
172
+ export declare function isPlainObject(value: unknown): value is JsonObject;
173
+ /**
174
+ * Accept a spec the way a caller would naturally write one.
175
+ *
176
+ * `version` and a field's `type` are boilerplate: a model asked for "a form with
177
+ * an amount and a reason" should be able to answer `{title: "Refund", fields:
178
+ * [{name: "amount", type: "number"}, {name: "reason"}]}` and have it work.
179
+ * A bare string field is shorthand for a `string` field of that name.
180
+ *
181
+ * This only fills gaps. Anything genuinely broken (no fields, a duplicate or
182
+ * illegal name, a layout that references an unknown field) is still reported by
183
+ * `validateSpec`.
184
+ */
185
+ export declare function normalizeSpec(raw: unknown): FormSpec;
186
+ /** True when `type` is one this runtime knows. */
187
+ export declare function isFieldType(type: unknown): type is FieldType;
188
+ export declare function validateSpec(spec: FormSpec): FormIssue[];
189
+ export declare function validateValues(spec: FormSpec, values: JsonObject): FormIssue[];
190
+ /** Read a dotted field path out of a value tree. */
191
+ export declare function valueAtPath(values: JsonObject, path: string): Json | undefined;
192
+ export {};
193
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../src/forms/spec.ts"],"names":[],"mappings":"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"}