@pilotiq/pilotiq 0.6.1 → 0.7.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 (212) hide show
  1. package/.turbo/turbo-build.log +6 -2
  2. package/CHANGELOG.md +614 -0
  3. package/CLAUDE.md +6 -5
  4. package/dist/Column.d.ts +35 -0
  5. package/dist/Column.d.ts.map +1 -1
  6. package/dist/Column.js +41 -0
  7. package/dist/Column.js.map +1 -1
  8. package/dist/Page.d.ts +13 -4
  9. package/dist/Page.d.ts.map +1 -1
  10. package/dist/Page.js +9 -2
  11. package/dist/Page.js.map +1 -1
  12. package/dist/Pilotiq.d.ts +84 -0
  13. package/dist/Pilotiq.d.ts.map +1 -1
  14. package/dist/Pilotiq.js +66 -0
  15. package/dist/Pilotiq.js.map +1 -1
  16. package/dist/Resource.d.ts +26 -0
  17. package/dist/Resource.d.ts.map +1 -1
  18. package/dist/Resource.js +9 -0
  19. package/dist/Resource.js.map +1 -1
  20. package/dist/actions/exportFactory.js +1 -1
  21. package/dist/actions/exportFactory.js.map +1 -1
  22. package/dist/columns/SelectColumn.d.ts +32 -5
  23. package/dist/columns/SelectColumn.d.ts.map +1 -1
  24. package/dist/columns/SelectColumn.js +37 -7
  25. package/dist/columns/SelectColumn.js.map +1 -1
  26. package/dist/defaultPages.d.ts.map +1 -1
  27. package/dist/defaultPages.js +3 -0
  28. package/dist/defaultPages.js.map +1 -1
  29. package/dist/elements/Form.d.ts +17 -0
  30. package/dist/elements/Form.d.ts.map +1 -1
  31. package/dist/elements/Form.js +17 -0
  32. package/dist/elements/Form.js.map +1 -1
  33. package/dist/elements/Table.d.ts +26 -0
  34. package/dist/elements/Table.d.ts.map +1 -1
  35. package/dist/elements/Table.js +15 -1
  36. package/dist/elements/Table.js.map +1 -1
  37. package/dist/elements/TableGroup.d.ts +84 -0
  38. package/dist/elements/TableGroup.d.ts.map +1 -1
  39. package/dist/elements/TableGroup.js +103 -0
  40. package/dist/elements/TableGroup.js.map +1 -1
  41. package/dist/elements/dispatchForm.d.ts.map +1 -1
  42. package/dist/elements/dispatchForm.js +36 -6
  43. package/dist/elements/dispatchForm.js.map +1 -1
  44. package/dist/elements/dispatchTable.d.ts +12 -0
  45. package/dist/elements/dispatchTable.d.ts.map +1 -1
  46. package/dist/elements/dispatchTable.js +104 -29
  47. package/dist/elements/dispatchTable.js.map +1 -1
  48. package/dist/fields/Field.d.ts +7 -2
  49. package/dist/fields/Field.d.ts.map +1 -1
  50. package/dist/fields/Field.js +8 -3
  51. package/dist/fields/Field.js.map +1 -1
  52. package/dist/fields/RepeaterField.d.ts +65 -0
  53. package/dist/fields/RepeaterField.d.ts.map +1 -1
  54. package/dist/fields/RepeaterField.js +48 -0
  55. package/dist/fields/RepeaterField.js.map +1 -1
  56. package/dist/orm/modelDefaults.d.ts.map +1 -1
  57. package/dist/orm/modelDefaults.js +19 -0
  58. package/dist/orm/modelDefaults.js.map +1 -1
  59. package/dist/pageData.d.ts +20 -0
  60. package/dist/pageData.d.ts.map +1 -1
  61. package/dist/pageData.js +242 -34
  62. package/dist/pageData.js.map +1 -1
  63. package/dist/react/AppShell.d.ts +17 -1
  64. package/dist/react/AppShell.d.ts.map +1 -1
  65. package/dist/react/AppShell.js +34 -3
  66. package/dist/react/AppShell.js.map +1 -1
  67. package/dist/react/PendingSuggestionApplierRegistry.d.ts +34 -0
  68. package/dist/react/PendingSuggestionApplierRegistry.d.ts.map +1 -0
  69. package/dist/react/PendingSuggestionApplierRegistry.js +51 -0
  70. package/dist/react/PendingSuggestionApplierRegistry.js.map +1 -0
  71. package/dist/react/PendingSuggestionOverlayRegistry.d.ts +46 -0
  72. package/dist/react/PendingSuggestionOverlayRegistry.d.ts.map +1 -0
  73. package/dist/react/PendingSuggestionOverlayRegistry.js +16 -0
  74. package/dist/react/PendingSuggestionOverlayRegistry.js.map +1 -0
  75. package/dist/react/PendingSuggestionsContext.d.ts +153 -0
  76. package/dist/react/PendingSuggestionsContext.d.ts.map +1 -0
  77. package/dist/react/PendingSuggestionsContext.js +46 -0
  78. package/dist/react/PendingSuggestionsContext.js.map +1 -0
  79. package/dist/react/SchemaRenderer.d.ts.map +1 -1
  80. package/dist/react/SchemaRenderer.js +312 -39
  81. package/dist/react/SchemaRenderer.js.map +1 -1
  82. package/dist/react/cells/EditableCell.d.ts +8 -0
  83. package/dist/react/cells/EditableCell.d.ts.map +1 -1
  84. package/dist/react/cells/EditableCell.js +6 -2
  85. package/dist/react/cells/EditableCell.js.map +1 -1
  86. package/dist/react/fields/CheckboxListInput.d.ts.map +1 -1
  87. package/dist/react/fields/CheckboxListInput.js +29 -2
  88. package/dist/react/fields/CheckboxListInput.js.map +1 -1
  89. package/dist/react/fields/ColorInput.d.ts.map +1 -1
  90. package/dist/react/fields/ColorInput.js +28 -2
  91. package/dist/react/fields/ColorInput.js.map +1 -1
  92. package/dist/react/fields/DateTimeInput.d.ts.map +1 -1
  93. package/dist/react/fields/DateTimeInput.js +28 -2
  94. package/dist/react/fields/DateTimeInput.js.map +1 -1
  95. package/dist/react/fields/FieldShell.d.ts.map +1 -1
  96. package/dist/react/fields/FieldShell.js +161 -3
  97. package/dist/react/fields/FieldShell.js.map +1 -1
  98. package/dist/react/fields/FileUploadInput.d.ts.map +1 -1
  99. package/dist/react/fields/FileUploadInput.js +27 -2
  100. package/dist/react/fields/FileUploadInput.js.map +1 -1
  101. package/dist/react/fields/KeyValueInput.d.ts.map +1 -1
  102. package/dist/react/fields/KeyValueInput.js +33 -2
  103. package/dist/react/fields/KeyValueInput.js.map +1 -1
  104. package/dist/react/fields/RadioInput.d.ts.map +1 -1
  105. package/dist/react/fields/RadioInput.js +28 -2
  106. package/dist/react/fields/RadioInput.js.map +1 -1
  107. package/dist/react/fields/SelectFieldInput.d.ts.map +1 -1
  108. package/dist/react/fields/SelectFieldInput.js +31 -2
  109. package/dist/react/fields/SelectFieldInput.js.map +1 -1
  110. package/dist/react/fields/SliderInput.d.ts.map +1 -1
  111. package/dist/react/fields/SliderInput.js +26 -2
  112. package/dist/react/fields/SliderInput.js.map +1 -1
  113. package/dist/react/fields/TagsInput.d.ts.map +1 -1
  114. package/dist/react/fields/TagsInput.js +26 -2
  115. package/dist/react/fields/TagsInput.js.map +1 -1
  116. package/dist/react/fields/ToggleFieldInput.d.ts.map +1 -1
  117. package/dist/react/fields/ToggleFieldInput.js +29 -2
  118. package/dist/react/fields/ToggleFieldInput.js.map +1 -1
  119. package/dist/react/index.d.ts +3 -0
  120. package/dist/react/index.d.ts.map +1 -1
  121. package/dist/react/index.js +3 -0
  122. package/dist/react/index.js.map +1 -1
  123. package/dist/routes.d.ts.map +1 -1
  124. package/dist/routes.js +55 -2
  125. package/dist/routes.js.map +1 -1
  126. package/dist/schema/Html.d.ts +2 -2
  127. package/dist/schema/Html.d.ts.map +1 -1
  128. package/dist/schema/Html.js +2 -2
  129. package/dist/schema/Html.js.map +1 -1
  130. package/dist/schema/Markdown.d.ts +2 -2
  131. package/dist/schema/Markdown.d.ts.map +1 -1
  132. package/dist/schema/Markdown.js +2 -2
  133. package/dist/schema/Markdown.js.map +1 -1
  134. package/dist/schema/Section.d.ts +16 -0
  135. package/dist/schema/Section.d.ts.map +1 -1
  136. package/dist/schema/Section.js +16 -0
  137. package/dist/schema/Section.js.map +1 -1
  138. package/dist/schema/Wizard.d.ts +45 -0
  139. package/dist/schema/Wizard.d.ts.map +1 -1
  140. package/dist/schema/Wizard.js +50 -0
  141. package/dist/schema/Wizard.js.map +1 -1
  142. package/dist/schema/resolveSchema.d.ts +8 -0
  143. package/dist/schema/resolveSchema.d.ts.map +1 -1
  144. package/dist/schema/resolveSchema.js +70 -1
  145. package/dist/schema/resolveSchema.js.map +1 -1
  146. package/dist/schema/sanitize.d.ts +3 -3
  147. package/dist/schema/sanitize.d.ts.map +1 -1
  148. package/dist/schema/sanitize.js +10 -3
  149. package/dist/schema/sanitize.js.map +1 -1
  150. package/dist/sessionFilters.d.ts.map +1 -1
  151. package/dist/sessionFilters.js +12 -1
  152. package/dist/sessionFilters.js.map +1 -1
  153. package/dist/styles/file-upload.css +13 -0
  154. package/dist/vite.d.ts.map +1 -1
  155. package/dist/vite.js +9 -2
  156. package/dist/vite.js.map +1 -1
  157. package/package.json +6 -4
  158. package/src/Column.test.ts +36 -0
  159. package/src/Column.ts +54 -0
  160. package/src/Page.ts +13 -4
  161. package/src/Pilotiq.ts +109 -0
  162. package/src/Resource.ts +29 -0
  163. package/src/actions/exportFactory.ts +1 -1
  164. package/src/columns/SelectColumn.ts +46 -8
  165. package/src/columns/editableColumns.test.ts +45 -0
  166. package/src/defaultPages.ts +3 -0
  167. package/src/elements/Form.ts +19 -0
  168. package/src/elements/Table.ts +35 -1
  169. package/src/elements/TableGroup.test.ts +111 -0
  170. package/src/elements/TableGroup.ts +135 -0
  171. package/src/elements/dispatchForm.ts +34 -7
  172. package/src/elements/dispatchTable.test.ts +267 -0
  173. package/src/elements/dispatchTable.ts +112 -33
  174. package/src/fields/Field.test.ts +15 -0
  175. package/src/fields/Field.ts +8 -3
  176. package/src/fields/RepeaterField.ts +104 -0
  177. package/src/fields/RepeaterRelationship.test.ts +173 -0
  178. package/src/nestedRelationManagerData.test.ts +21 -0
  179. package/src/orm/modelDefaults.ts +21 -0
  180. package/src/pageData.ts +267 -47
  181. package/src/react/AppShell.tsx +55 -4
  182. package/src/react/PendingSuggestionApplierRegistry.ts +80 -0
  183. package/src/react/PendingSuggestionOverlayRegistry.ts +54 -0
  184. package/src/react/PendingSuggestionsContext.tsx +172 -0
  185. package/src/react/SchemaRenderer.tsx +504 -95
  186. package/src/react/cells/EditableCell.tsx +11 -2
  187. package/src/react/fields/CheckboxListInput.tsx +23 -2
  188. package/src/react/fields/ColorInput.tsx +22 -2
  189. package/src/react/fields/DateTimeInput.tsx +22 -2
  190. package/src/react/fields/FieldShell.tsx +167 -3
  191. package/src/react/fields/FileUploadInput.tsx +21 -2
  192. package/src/react/fields/KeyValueInput.tsx +32 -2
  193. package/src/react/fields/RadioInput.tsx +23 -2
  194. package/src/react/fields/SelectFieldInput.tsx +25 -2
  195. package/src/react/fields/SliderInput.tsx +20 -2
  196. package/src/react/fields/TagsInput.tsx +20 -2
  197. package/src/react/fields/ToggleFieldInput.tsx +23 -2
  198. package/src/react/index.ts +18 -0
  199. package/src/relationManagerData.test.ts +451 -2
  200. package/src/routes.ts +58 -2
  201. package/src/schema/Html.ts +2 -2
  202. package/src/schema/Markdown.ts +2 -2
  203. package/src/schema/Section.ts +17 -0
  204. package/src/schema/Wizard.ts +67 -0
  205. package/src/schema/containers.test.ts +90 -0
  206. package/src/schema/resolveSchema.test.ts +50 -0
  207. package/src/schema/resolveSchema.ts +79 -1
  208. package/src/schema/sanitize.ts +13 -4
  209. package/src/sessionFilters.test.ts +23 -0
  210. package/src/sessionFilters.ts +11 -1
  211. package/src/styles/file-upload.css +13 -0
  212. package/src/vite.ts +9 -2
@@ -0,0 +1,54 @@
1
+ import type { ComponentType } from 'react'
2
+ import type { PendingSuggestion } from './PendingSuggestionsContext.js'
3
+ import type { ElementMeta } from '../schema/Element.js'
4
+
5
+ /**
6
+ * Props the per-field overlay component receives from `FieldShell` when
7
+ * one or more pending suggestions target the field.
8
+ *
9
+ * The overlay is responsible for both rendering AND applying the
10
+ * suggestion. On Approve, call `onApprove()` (which dismisses the
11
+ * suggestion from the queue) AFTER mutating the form's field value to
12
+ * `suggestion.suggestedValue` — the queue is just a notification surface,
13
+ * applying is the renderer's job.
14
+ *
15
+ * The Tiptap `RichTextField` renderer skips this slot entirely — it
16
+ * mirrors suggestions into the editor's inline AiSuggestion extension
17
+ * instead. Other field types (Text / Textarea / Select / Number / …)
18
+ * render the registered overlay below their input.
19
+ */
20
+ export interface PendingSuggestionOverlayProps {
21
+ /** First suggestion targeting this field. Aggregate UIs handle stacks. */
22
+ suggestion: PendingSuggestion
23
+ /** Drop from queue (callable after applying). */
24
+ onApprove: () => void
25
+ /** Drop from queue without applying. */
26
+ onReject: () => void
27
+ /** Field type string (`text` / `select` / `toggle` / `slider` / `color` /
28
+ * …) so per-fieldType overlay renderers can branch. Sparse — older
29
+ * hosts may omit. Phase C of ai-review-mode. */
30
+ fieldType?: string
31
+ /** Resolved field meta — gives the overlay access to per-field config
32
+ * (`options` for Select, `min/max` for Slider, etc.) needed to render
33
+ * human-friendly comparisons rather than raw values. Sparse — older
34
+ * hosts may omit. */
35
+ el?: ElementMeta
36
+ }
37
+
38
+ let _component: ComponentType<PendingSuggestionOverlayProps> | null = null
39
+
40
+ /**
41
+ * Register a component to render below any `FieldShell` whose field has at
42
+ * least one matching pending suggestion in the
43
+ * `<PendingSuggestionsContext>` queue. Called once at boot by a plugin
44
+ * (e.g. `@pilotiq-pro/ai`). No-op when no plugin registers — `FieldShell`
45
+ * skips the overlay slot.
46
+ */
47
+ export function registerPendingSuggestionOverlay(C: ComponentType<PendingSuggestionOverlayProps>): void {
48
+ _component = C
49
+ }
50
+
51
+ /** Returns the registered overlay component, or `null`. */
52
+ export function getPendingSuggestionOverlay(): ComponentType<PendingSuggestionOverlayProps> | null {
53
+ return _component
54
+ }
@@ -0,0 +1,172 @@
1
+ import React, { createContext, useContext, useMemo } from 'react'
2
+
3
+ /**
4
+ * One AI- (or extension-) sourced suggested field-value change. Sits in a
5
+ * unified queue read by:
6
+ *
7
+ * - the Tiptap `RichTextField` renderer — for `richtext` fields, the
8
+ * suggestion is mirrored into the editor's `AiSuggestion` extension as
9
+ * an inline diff with per-hunk Approve/Reject chips
10
+ * - `FieldShell`'s overlay slot — for any other field type, a registered
11
+ * overlay component renders a `currentValue` vs `suggestedValue` diff
12
+ * card below the input
13
+ * - aggregate "Pending suggestions" pills (e.g. in a chat sidebar) — read
14
+ * the full list to show counts + bulk approve / reject affordances
15
+ *
16
+ * The shape is intentionally generic — the `meta` bag carries field-type-
17
+ * specific extras (e.g. `editorRange: { from, to }` for `richtext`).
18
+ *
19
+ * Pilotiq core does NOT push or apply suggestions itself. The provider
20
+ * implementation + push paths live in plugin packages (e.g.
21
+ * `@pilotiq-pro/ai`); core just owns the type, context, and hooks so any
22
+ * field renderer can subscribe through one open-core seam.
23
+ */
24
+ /**
25
+ * Where a suggestion came from. Lets aggregate consumers (pill UIs)
26
+ * filter the shared queue by surface — e.g. a popover-chat scoped pill
27
+ * shows only suggestions produced by its own session, while the
28
+ * sidebar pill shows everything. Sparse on push; consumers treat
29
+ * absence as "unknown origin, include in unfiltered views".
30
+ */
31
+ export interface PendingSuggestionOrigin {
32
+ /**
33
+ * Which UI surface initiated the agent run that produced this
34
+ * suggestion. `'field-action'` covers the `✦` per-field dropdown.
35
+ */
36
+ surface: 'sidebar' | 'popover' | 'field-action'
37
+ /**
38
+ * Stable id of the agent run / chat turn that produced this
39
+ * suggestion. Popover pills filter on this so they only see their
40
+ * own session's output even when the panel-wide queue holds many.
41
+ */
42
+ runId?: string
43
+ /** Slug of the agent whose tool call produced the suggestion. */
44
+ agentSlug?: string
45
+ }
46
+
47
+ export interface PendingSuggestion {
48
+ /** Stable id; the producer is responsible for uniqueness. */
49
+ id: string
50
+ /** Field name this suggestion targets. Matched verbatim in the renderer. */
51
+ fieldName: string
52
+ /**
53
+ * Form scope. Multi-form pages (Plan #5 reactive fields) stamp the form's
54
+ * id here so a renderer in form A doesn't pick up a suggestion meant for
55
+ * form B. Optional — when both producer and consumer omit it, suggestions
56
+ * are global.
57
+ */
58
+ formId?: string
59
+ /** Snapshot of the field's value at the time the suggestion was produced. */
60
+ currentValue: unknown
61
+ /** Proposed replacement. */
62
+ suggestedValue: unknown
63
+ /** Optional attribution surfaced on the diff overlay / inline chip. */
64
+ source?: {
65
+ agentSlug?: string
66
+ agentLabel?: string
67
+ }
68
+ /**
69
+ * Provenance hint for cross-surface filtering. Sparse — pushed when
70
+ * the producer knows which agent run / chat surface it's running
71
+ * inside (e.g. the popover-chat tagging its turn id so its scoped
72
+ * pill can filter the shared queue). Aggregate consumers that don't
73
+ * care just leave the field unread.
74
+ */
75
+ origin?: PendingSuggestionOrigin
76
+ /** Wallclock ms when produced. Producers fill this in on `push`. */
77
+ createdAt: number
78
+ /** Field-type-specific extras (e.g. `editorRange: { from, to }`). Sparse. */
79
+ meta?: Record<string, unknown>
80
+ }
81
+
82
+ export interface PendingSuggestionsApi {
83
+ /** Full list across every field + form. Aggregate consumers read this. */
84
+ list: readonly PendingSuggestion[]
85
+ /** Add a suggestion to the queue. Returns the (possibly producer-supplied) id. */
86
+ push: (suggestion: Omit<PendingSuggestion, 'createdAt'> & { createdAt?: number }) => string
87
+ /**
88
+ * Drop the suggestion from the queue. Used by both inline approval
89
+ * paths (where the renderer applies directly and just notifies the
90
+ * queue) AND by Reject. For aggregate consumers (e.g. a chat-pill
91
+ * "Approve all" button) that live outside the form's React tree, see
92
+ * `approve` below — it looks up a registered applier and calls it
93
+ * before dismissing.
94
+ */
95
+ dismiss: (id: string) => void
96
+ /**
97
+ * Apply + dismiss. Resolves the suggestion's `(formId, fieldName)`
98
+ * pair against `PendingSuggestionApplierRegistry`; if an applier is
99
+ * registered (FieldShell + Tiptap bridge auto-register on mount),
100
+ * runs it and then dismisses. If no applier is registered (or the
101
+ * applier throws), falls through to a plain `dismiss` so the queue
102
+ * still clears — never strands an entry.
103
+ *
104
+ * Use this from cross-tree surfaces (chat-sidebar pending-pill).
105
+ * Inline surfaces (FieldShell overlay, Tiptap chip) apply via their
106
+ * own React-tree-local mutators and call `dismiss` directly.
107
+ */
108
+ approve: (id: string) => void
109
+ /**
110
+ * Drop every suggestion matching the optional filter. With no filter,
111
+ * empties the entire queue.
112
+ */
113
+ dismissAll: (filter?: { fieldName?: string; formId?: string }) => void
114
+ /**
115
+ * Apply + dismiss every suggestion matching the optional filter.
116
+ * Calls `approve(id)` per entry — same fall-through semantics if an
117
+ * applier is missing or throws.
118
+ */
119
+ approveAll: (filter?: { fieldName?: string; formId?: string }) => void
120
+ }
121
+
122
+ const NOOP_API: PendingSuggestionsApi = Object.freeze({
123
+ list: Object.freeze([]) as readonly PendingSuggestion[],
124
+ push: () => '',
125
+ dismiss: () => {},
126
+ approve: () => {},
127
+ dismissAll: () => {},
128
+ approveAll: () => {},
129
+ })
130
+
131
+ /**
132
+ * Context default is a no-op API — fields that subscribe in trees without a
133
+ * real provider mounted (e.g. the marketing site's preview, headless tests)
134
+ * see an empty list and no-op approval methods. Never throws.
135
+ */
136
+ export const PendingSuggestionsContext = createContext<PendingSuggestionsApi>(NOOP_API)
137
+
138
+ /** Read the full queue + producer methods. Used by aggregate UIs. */
139
+ export function usePendingSuggestions(): PendingSuggestionsApi {
140
+ return useContext(PendingSuggestionsContext)
141
+ }
142
+
143
+ /**
144
+ * Subscribe a single field-renderer to its slice of the queue. Returns
145
+ * `list` already filtered + a `dismiss` callback that the renderer wires
146
+ * to its Approve / Reject buttons.
147
+ *
148
+ * Matching rules:
149
+ * - `s.fieldName === fieldName` (verbatim)
150
+ * - if both `formId` args are non-`undefined`, they must match; otherwise
151
+ * the entry passes (so global suggestions reach scoped readers and
152
+ * vice-versa)
153
+ *
154
+ * The list reference is stable across renders unless the underlying
155
+ * filtered slice actually changes — useful for `useEffect` dependencies
156
+ * in renderers that mirror suggestions into their own state.
157
+ */
158
+ export function usePendingSuggestionsForField(
159
+ fieldName: string,
160
+ formId?: string,
161
+ ): {
162
+ list: readonly PendingSuggestion[]
163
+ dismiss: (id: string) => void
164
+ } {
165
+ const api = useContext(PendingSuggestionsContext)
166
+ const list = useMemo(() => api.list.filter(s => {
167
+ if (s.fieldName !== fieldName) return false
168
+ if (formId === undefined || s.formId === undefined) return true
169
+ return s.formId === formId
170
+ }), [api.list, fieldName, formId])
171
+ return { list, dismiss: api.dismiss }
172
+ }