@mulmoclaude/core 0.2.9 → 0.2.11

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 (113) hide show
  1. package/dist/collection/core/actionVisible.d.ts +34 -0
  2. package/dist/collection/core/calendarGrid.d.ts +120 -0
  3. package/dist/collection/core/deriveAll.d.ts +38 -0
  4. package/dist/collection/core/derivedFormula.d.ts +18 -0
  5. package/dist/collection/core/draft.d.ts +18 -0
  6. package/dist/collection/core/enumColors.d.ts +33 -0
  7. package/dist/collection/core/errorMessage.d.ts +4 -0
  8. package/dist/collection/core/itemLabel.d.ts +12 -0
  9. package/dist/collection/core/presentCollection.d.ts +13 -0
  10. package/dist/collection/core/promptSafety.d.ts +1 -0
  11. package/dist/collection/core/schema.d.ts +403 -0
  12. package/dist/collection/core/shortHexId.d.ts +8 -0
  13. package/dist/collection/core/sortItems.d.ts +29 -0
  14. package/dist/collection/core/uiTypes.d.ts +106 -0
  15. package/dist/collection/index.cjs +794 -0
  16. package/dist/collection/index.cjs.map +1 -0
  17. package/dist/collection/index.d.ts +14 -0
  18. package/dist/collection/paths.cjs +56 -0
  19. package/dist/collection/paths.cjs.map +1 -0
  20. package/dist/collection/paths.js +12 -1
  21. package/dist/collection/paths.js.map +1 -1
  22. package/dist/collection/server/atomic.d.ts +1 -0
  23. package/dist/collection/server/delete.d.ts +38 -0
  24. package/dist/collection/server/derive.d.ts +8 -0
  25. package/dist/collection/server/discoveredCollection.d.ts +18 -0
  26. package/dist/collection/server/discovery.d.ts +240 -0
  27. package/dist/collection/server/host.d.ts +77 -0
  28. package/dist/collection/server/index.cjs +53 -0
  29. package/dist/collection/server/index.js +3 -3
  30. package/dist/collection/server/io.d.ts +147 -0
  31. package/dist/collection/server/paths.d.ts +52 -0
  32. package/dist/collection/server/spawn.d.ts +55 -0
  33. package/dist/collection/server/templatePath.d.ts +9 -0
  34. package/dist/collection/server/util.d.ts +3 -0
  35. package/dist/collection/server/validate.d.ts +19 -0
  36. package/dist/collection/server/views.d.ts +20 -0
  37. package/dist/collection-watchers/config.d.ts +49 -0
  38. package/dist/collection-watchers/index.cjs +553 -0
  39. package/dist/collection-watchers/index.cjs.map +1 -0
  40. package/dist/collection-watchers/index.d.ts +3 -0
  41. package/dist/collection-watchers/index.js +1 -1
  42. package/dist/collection-watchers/reconciler.d.ts +33 -0
  43. package/dist/collection-watchers/watcher.d.ts +34 -0
  44. package/dist/deriveAll-VRWrs3SF.cjs +413 -0
  45. package/dist/deriveAll-VRWrs3SF.cjs.map +1 -0
  46. package/dist/deriveAll-vzIhhKBK.js.map +1 -1
  47. package/dist/feeds/index.cjs +8 -0
  48. package/dist/feeds/index.d.ts +1 -0
  49. package/dist/feeds/ingestTypes.d.ts +57 -0
  50. package/dist/feeds/paths.cjs +48 -0
  51. package/dist/feeds/paths.cjs.map +1 -0
  52. package/dist/feeds/paths.d.ts +22 -0
  53. package/dist/feeds/server/fetch/httpClient.d.ts +8 -0
  54. package/dist/feeds/server/fetch/rssParser.d.ts +12 -0
  55. package/dist/feeds/server/index.cjs +839 -0
  56. package/dist/feeds/server/index.cjs.map +1 -0
  57. package/dist/feeds/server/index.js +5 -6
  58. package/dist/feeds/server/index.js.map +1 -1
  59. package/dist/feeds/server/pathResolver.d.ts +6 -0
  60. package/dist/feeds/server/projectItem.d.ts +8 -0
  61. package/dist/feeds/server/refreshResult.d.ts +17 -0
  62. package/dist/feeds/server/retrievers/httpJson.d.ts +3 -0
  63. package/dist/feeds/server/retrievers/index.d.ts +12 -0
  64. package/dist/feeds/server/retrievers/registerAll.d.ts +0 -0
  65. package/dist/feeds/server/retrievers/rss.d.ts +3 -0
  66. package/dist/feeds/server/scheduledRefresh.d.ts +1 -1
  67. package/dist/file-change/index.cjs +72 -0
  68. package/dist/file-change/index.cjs.map +1 -0
  69. package/dist/file-change/index.d.ts +43 -0
  70. package/dist/ingestTypes-DDOVhOYC.cjs +32 -0
  71. package/dist/ingestTypes-DDOVhOYC.cjs.map +1 -0
  72. package/dist/notifier/engine.d.ts +72 -0
  73. package/dist/notifier/index.cjs +21 -0
  74. package/dist/notifier/index.d.ts +3 -0
  75. package/dist/notifier/store.d.ts +18 -0
  76. package/dist/notifier/types.d.ts +118 -0
  77. package/dist/notifier/validate.d.ts +17 -0
  78. package/dist/notifier-bS8IEeLA.cjs +577 -0
  79. package/dist/notifier-bS8IEeLA.cjs.map +1 -0
  80. package/dist/rolldown-runtime-D6vf50IK.cjs +28 -0
  81. package/dist/scheduler/adapter.d.ts +48 -0
  82. package/dist/scheduler/index.cjs +352 -0
  83. package/dist/scheduler/index.cjs.map +1 -0
  84. package/dist/scheduler/index.d.ts +2 -0
  85. package/dist/scheduler/task-manager.d.ts +51 -0
  86. package/dist/{server-q4WPXtbU.js → server-D2QZuMS2.js} +54 -4
  87. package/dist/server-D2QZuMS2.js.map +1 -0
  88. package/dist/server-DAyIQ5rT.cjs +2049 -0
  89. package/dist/server-DAyIQ5rT.cjs.map +1 -0
  90. package/dist/skill-bridge/index.cjs +88 -0
  91. package/dist/skill-bridge/index.cjs.map +1 -0
  92. package/dist/skill-bridge/index.d.ts +30 -0
  93. package/dist/whisper/client.cjs +241 -0
  94. package/dist/whisper/client.cjs.map +1 -0
  95. package/dist/whisper/client.d.ts +35 -0
  96. package/dist/whisper/ffmpeg.d.ts +6 -0
  97. package/dist/whisper/index.cjs +433 -0
  98. package/dist/whisper/index.cjs.map +1 -0
  99. package/dist/whisper/index.d.ts +5 -0
  100. package/dist/whisper/internal.d.ts +11 -0
  101. package/dist/whisper/models.d.ts +49 -0
  102. package/dist/whisper/sidecar.d.ts +8 -0
  103. package/dist/whisper/whisper.d.ts +28 -0
  104. package/dist/workspace-setup/assets.d.ts +10 -0
  105. package/dist/workspace-setup/index.d.ts +3 -0
  106. package/dist/workspace-setup/index.js +560 -0
  107. package/dist/workspace-setup/index.js.map +1 -0
  108. package/dist/workspace-setup/slug.d.ts +6 -0
  109. package/dist/workspace-setup/slug.js +13 -0
  110. package/dist/workspace-setup/slug.js.map +1 -0
  111. package/dist/workspace-setup/sync.d.ts +94 -0
  112. package/package.json +1 -1
  113. package/dist/server-q4WPXtbU.js.map +0 -1
@@ -0,0 +1,403 @@
1
+ /** Minimal "this collection is a feed" descriptor carried on the schema.
2
+ * Deliberately narrow — the canonical collection contract stays
3
+ * independent of the host's feeds subsystem. The host's richer retrieval
4
+ * spec (`IngestSpec` in `server/workspace/feeds/ingestTypes.ts`)
5
+ * `extends CollectionIngest`, so feed code reads the extra fields by
6
+ * typing feed schemas with that subtype; collection rendering only needs
7
+ * these three + the presence check. */
8
+ export interface CollectionIngest {
9
+ kind: string;
10
+ schedule: string;
11
+ /** Optional time-of-day anchor for `schedule: "daily"` — the hour (0–23) to
12
+ * refresh around (the host ticks hourly, so the run lands within that hour).
13
+ * Ignored for non-daily schedules. Absent ⇒ elapsed-based daily ("≥24 h since
14
+ * the last run"). NOTE: **UTC**, not local — compared via `getUTCHours()` for
15
+ * an unambiguous, DST-free check (matching the rest of the scheduler), so
16
+ * convert local times before writing (e.g. 07:00 JST → `atHour: 22`). */
17
+ atHour?: number;
18
+ /** Declarative retrievers (`rss`/`atom`/`http-json`) only — the host fetches
19
+ * this URL on the schedule. Absent for `kind: "agent"`, where the agent owns
20
+ * retrieval. */
21
+ url?: string;
22
+ /** `kind: "agent"` only: role id the scheduled hidden worker runs in. */
23
+ role?: string;
24
+ /** `kind: "agent"` only: skill-relative template path (under `templates/`)
25
+ * whose prose tells the worker how to refresh the records. */
26
+ template?: string;
27
+ }
28
+ /** Declarative retriever kinds a Feed's `ingest.kind` may declare. The host's
29
+ * feeds engine dispatches on these; they live here (with the schema contract)
30
+ * so the schema validator can enforce them. The host re-exports these from
31
+ * `server/workspace/feeds/ingestTypes.ts`. */
32
+ export declare const INGEST_KINDS: readonly ["rss", "atom", "http-json"];
33
+ export type IngestKind = (typeof INGEST_KINDS)[number];
34
+ /** The agent-performed ingest kind. Instead of a declarative fetch, the host
35
+ * dispatches a hidden background chat (origin `system`) in `ingest.role`,
36
+ * seeded with `ingest.template` + a summary of every record, on the
37
+ * `ingest.schedule` cadence; the worker edits records via the collections io
38
+ * layer. Kept separate from {@link INGEST_KINDS} (which the declarative
39
+ * retriever registry keys on) so the schema validator can model `ingest` as a
40
+ * discriminated union without the feeds engine gaining an "agent" retriever. */
41
+ export declare const AGENT_INGEST_KIND: "agent";
42
+ export type AgentIngestKind = typeof AGENT_INGEST_KIND;
43
+ /** Refresh cadences a Feed's `ingest.schedule` may declare. */
44
+ export declare const FEED_SCHEDULES: readonly ["hourly", "daily", "weekly", "on-demand"];
45
+ export type FeedSchedule = (typeof FEED_SCHEDULES)[number];
46
+ export type CollectionFieldType = "string" | "text" | "email" | "number" | "date" | "datetime" | "boolean" | "markdown" | "ref" | "money" | "enum" | "table" | "derived" | "embed" | "image" | "file" | "toggle";
47
+ export type CollectionSource = "user" | "project" | "feed";
48
+ /** Recurrence unit for a `spawn.every` advance. */
49
+ export type CollectionRecurUnit = "day" | "week" | "month" | "year";
50
+ /** How a `spawn` advances the source item's `triggerField` date to
51
+ * produce the successor's. All arithmetic is done on the civil
52
+ * (year, month, day) triple — never by adding milliseconds — so month
53
+ * lengths and leap years are handled correctly. */
54
+ export interface CollectionEvery {
55
+ unit: CollectionRecurUnit;
56
+ /** Number of `unit`s to advance (≥ 1). `interval: 3` + `unit: "month"`
57
+ * = quarterly; `interval: 1` + `unit: "year"` = annual. */
58
+ interval: number;
59
+ /** Day-of-month anchor for `month`/`year` units. The CANONICAL day —
60
+ * read from the rule, never re-derived from the prior concrete date,
61
+ * so "31st of every month" yields 31 → 28/29 → 31 → 30 … with no
62
+ * drift (it is clamped per-month at compute time, not stored
63
+ * clamped). `"last"` always means the last day of the target month.
64
+ * Omitted ⇒ preserve the source date's day (safe for days ≤ 28).
65
+ * Ignored for `day`/`week` units. */
66
+ dayOfMonth?: number | "last";
67
+ }
68
+ /** Field-driven recurrence: the advance interval is selected PER RECORD by
69
+ * the value of an `enum` field (`fromField`), looked up in `map`. Lets one
70
+ * collection mix daily / weekly / monthly obligations in a single list — the
71
+ * host reads `record[fromField]`, finds the matching `CollectionEvery`, and
72
+ * advances by it. `fromField` must point at a top-level `enum` field whose
73
+ * `values` the `map` keys exactly cover (validated at discovery), and must
74
+ * itself be carried/`set` onto the successor so the chain keeps recurring. */
75
+ export interface CollectionEveryFieldDriven {
76
+ /** Top-level `enum` field whose value selects the interval. */
77
+ fromField: string;
78
+ /** Interval per enum value. Keys exactly cover `fromField`'s `values`;
79
+ * each value is a literal {@link CollectionEvery}. */
80
+ map: Record<string, CollectionEvery>;
81
+ }
82
+ /** The `every` of a `spawn`: either a single literal interval applied to
83
+ * every record, or a per-record interval selected by an `enum` field. The
84
+ * literal arm is what `advanceTriggerDate` consumes — the field-driven arm
85
+ * is resolved down to one of its `map` values before the date math runs. */
86
+ export type CollectionSpawnEvery = CollectionEvery | CollectionEveryFieldDriven;
87
+ /** Narrowing guard: true when `every` is the field-driven arm. */
88
+ export declare function isFieldDrivenEvery(every: CollectionSpawnEvery): every is CollectionEveryFieldDriven;
89
+ /** Host-driven recurrence: when a record satisfies `when`, the host
90
+ * creates the next record with a forward-advanced `triggerField` date.
91
+ * The successor's id and contents are a pure function of (source
92
+ * record, this rule); creation is create-if-absent, so the mechanism
93
+ * stays convergent — observing the predicate N times writes one
94
+ * successor. Requires the schema to declare `triggerField`. */
95
+ export interface CollectionSpawn {
96
+ /** Predicate that fires the spawn (a `CollectionWhen`). Defaults to
97
+ * "`completionField` value ∈ `completionDoneValues`" (i.e. spawn the
98
+ * next instance when this one is done). */
99
+ when?: CollectionWhen;
100
+ /** How to advance `triggerField` from the source to the successor —
101
+ * either a single literal interval or a per-record, field-driven map. */
102
+ every: CollectionSpawnEvery;
103
+ /** Record fields copied verbatim onto the successor. Fields not listed
104
+ * here, not in `set`, and not the trigger / primary keys start
105
+ * blank. */
106
+ carry?: string[];
107
+ /** Fields forced to fixed values on the successor (typically resetting
108
+ * the status field to its pending value). */
109
+ set?: Record<string, unknown>;
110
+ }
111
+ /** The kind of work an action kicks off. v1 ships only `"chat"` —
112
+ * start a new chat in a role with a templated seed prompt. The enum
113
+ * reserves room for a future `"mutate"` (status transitions) without
114
+ * another schema-shape change. */
115
+ export type CollectionActionKind = "chat";
116
+ /** Optional visibility predicate: the target (an action button or a
117
+ * field) renders only when the open record's `field` (stringified) is
118
+ * one of `in`. Generic and domain-free — the host evaluates it against
119
+ * the record with no knowledge of what the field means. Absent ⇒
120
+ * always shown. */
121
+ export interface CollectionWhen {
122
+ /** Top-level record field key whose value gates visibility. */
123
+ field: string;
124
+ /** Allowed values; the target shows when `String(record[field])` is
125
+ * one of these. Non-empty. */
126
+ in: string[];
127
+ }
128
+ /** @deprecated Name retained for back-compat; use {@link CollectionWhen}.
129
+ * Both actions and fields share the same predicate shape. */
130
+ export type CollectionActionWhen = CollectionWhen;
131
+ /** What a custom view's capability token is allowed to do against the
132
+ * collection's data endpoint. `read` returns enriched records (getItems
133
+ * semantics); `write` validates-and-stores rows (putItems semantics).
134
+ * There is deliberately no `delete` — a view can never do more than the
135
+ * agent's own `manageCollection` tool. */
136
+ export type CollectionViewCapability = "read" | "write";
137
+ /** A custom (LLM-authored) HTML view for a collection. The host renders
138
+ * `file` in a sandboxed iframe over the collection's records; the view
139
+ * reaches its data only through a slug- and capability-scoped token (see
140
+ * `server/api/auth/viewToken.ts`). Pure data — the host holds no
141
+ * view-specific code; meaning lives in the HTML file + this registration. */
142
+ export interface CollectionCustomView {
143
+ /** Stable id; the view-mode selector key (`custom:<id>`) and the
144
+ * capability-token clamp key. Must be a valid slug. */
145
+ id: string;
146
+ /** Button label in the view-mode selector (author-authored, like field
147
+ * labels — not run through i18n). */
148
+ label: string;
149
+ /** Optional Material-icon name for the selector button. */
150
+ icon?: string;
151
+ /** Skill-relative path to the HTML file under `views/` (e.g.
152
+ * `views/year.html`). Path-safe, must end in `.html`. */
153
+ file: string;
154
+ /** Optional skill-relative path to a JSON translation dictionary co-located
155
+ * with the view (e.g. `views/year.i18n.json`). Shape mirrors **vue-i18n
156
+ * locale messages** so an author can lift their app's locale JSON
157
+ * verbatim:
158
+ *
159
+ * ```json
160
+ * { "en": { "next": "Next", "hello": "Hello, {name}" },
161
+ * "ja": { "next": "次へ", "hello": "{name} さん、こんにちは" } }
162
+ * ```
163
+ *
164
+ * The host picks the block matching the active app locale (fallback
165
+ * `"en"`, else `{}`) and injects ONLY that flat string map into
166
+ * `window.__MC_VIEW.dict`. The iframe-side helper
167
+ * `__MC_VIEW.t(key, named?)` mirrors vue-i18n's `t('msg', { name: 'x' })`
168
+ * signature — named-interpolation only (no pluralization / linked
169
+ * messages in v1; shipping vue-i18n's full runtime into every sandboxed
170
+ * iframe would dominate page weight). The view never sees other locales'
171
+ * strings. Constrained to `views/*.i18n.json` so authors keep the
172
+ * translation file next to the HTML it translates. Absent ⇒ host-side
173
+ * no-op (an i18n-less view keeps working; `t(key)` echoes the key). */
174
+ i18n?: string;
175
+ /** What the view may do with the data endpoint. Defaults to `["read"]`
176
+ * (least privilege); declare `["read","write"]` only for views that
177
+ * edit records. The mint endpoint clamps any requested caps to this. */
178
+ capabilities?: CollectionViewCapability[];
179
+ }
180
+ /** A schema-declared, per-record action rendered as a button in the
181
+ * read-only detail view. Pure UI/behaviour directive — never stored,
182
+ * never validated against record data. All domain specifics (label,
183
+ * role, template) live here in the schema / skill folder, so the host
184
+ * stays generic. */
185
+ export interface CollectionAction {
186
+ /** Stable id (used in the dispatch route + testids). */
187
+ id: string;
188
+ /** Button text (English, like field labels). */
189
+ label: string;
190
+ /** Material-icon name shown on the button. */
191
+ icon?: string;
192
+ /** What the action does. v1: `"chat"`. */
193
+ kind: CollectionActionKind;
194
+ /** `kind: "chat"`: the role id the new chat runs in. */
195
+ role: string;
196
+ /** `kind: "chat"`: skill-relative path to the template file whose
197
+ * text becomes the seed prompt body (e.g. `templates/invoice.md`). */
198
+ template: string;
199
+ /** Optional visibility predicate; the button renders only when the
200
+ * open record matches (see CollectionWhen). Absent ⇒ always
201
+ * shown. */
202
+ when?: CollectionWhen;
203
+ }
204
+ export interface CollectionFieldSpec {
205
+ type: CollectionFieldType;
206
+ label: string;
207
+ /** True for the field whose value is the record's filename (no
208
+ * separate auto-id). Exactly one field per schema may set this. */
209
+ primary?: boolean;
210
+ required?: boolean;
211
+ /** When `type === "ref"` or `type === "embed"`: the slug of the
212
+ * target collection. For `ref` the record stores the target
213
+ * item's primary-key slug and the host renders a clickable link
214
+ * + dropdown picker. For `embed` the host pulls a *fixed* record
215
+ * (see `id`) from the target and renders its fields read-only in
216
+ * the detail view. Required for both; ignored on every other
217
+ * type. */
218
+ to?: string;
219
+ /** When `type === "embed"`: the primary-key value of the fixed
220
+ * record to pull from the `to` collection (e.g. `me` for the
221
+ * singleton mc-profile). Nothing is stored on this record — the
222
+ * embed is a display-only directive resolved at render time, so
223
+ * it never appears in the list table or the edit form. Required
224
+ * when type is `embed`; ignored on every other type. */
225
+ id?: string;
226
+ /** When `type === "money"` (or `type === "derived"` with
227
+ * `display: "money"`): a literal ISO 4217 currency code passed to
228
+ * `Intl.NumberFormat` for display — fixed for every record. The
229
+ * stored value is always a plain decimal number; currency is
230
+ * presentation only. Mutually substitutable with `currencyField`:
231
+ * a money field must declare at least one of the two. */
232
+ currency?: string;
233
+ /** When `type === "money"` (or `type === "derived"` with
234
+ * `display: "money"`): the name of a sibling record field whose
235
+ * value holds the ISO 4217 code, letting currency vary per record
236
+ * (e.g. an invoice's `currency` enum). The renderer reads
237
+ * `record[currencyField]` and falls back to the literal `currency`
238
+ * (then "USD") when the field is absent or empty. Resolved against
239
+ * the top-level record even for money sub-fields inside a table. */
240
+ currencyField?: string;
241
+ /** When `type === "enum"`: the closed set of allowed string
242
+ * values. The form renders a `<select>` populated from this
243
+ * list; storage is a plain string. Required when type is
244
+ * `enum`; ignored on every other type. */
245
+ values?: readonly string[];
246
+ /** When `type === "table"`: the sub-schema for each row (a flat
247
+ * record of non-table / non-derived field specs). Required when
248
+ * type is `table`. v0 disallows nested tables and derived
249
+ * columns to keep the editor + evaluator simple. */
250
+ of?: Record<string, CollectionFieldSpec>;
251
+ /** When `type === "derived"`: a tiny expression evaluated against
252
+ * the record. Supports `+ - * /`, parens, identifier refs to
253
+ * top-level fields, `sum(tableField[].col)`, and
254
+ * `sum(tableField[].col * tableField[].col)`. See
255
+ * `src/utils/collections/derivedFormula.ts`. Required when type
256
+ * is `derived`. */
257
+ formula?: string;
258
+ /** When `type === "derived"`: an inner field type the computed
259
+ * value should be rendered as (e.g. `"money"` so $1,234.56 is
260
+ * formatted). Defaults to `"number"`. */
261
+ display?: CollectionFieldType;
262
+ /** Optional visibility predicate: this field renders only when the
263
+ * record matches (e.g. hide a `rating` field until `visited` is
264
+ * `true` via `{ field: "visited", in: ["true"] }`). Applies to the
265
+ * list cell (blank when hidden), the edit form (hidden live as the
266
+ * gating field changes), and the detail view. Purely presentational
267
+ * — a hidden field's stored value is never cleared. `when.field`
268
+ * must name another top-level field. Absent ⇒ always shown. Only
269
+ * honoured on top-level fields, not inside a `table`'s `of`. */
270
+ when?: CollectionWhen;
271
+ /** When `type === "toggle"`: the name of the top-level `enum` field this
272
+ * checkbox projects. The toggle stores nothing itself — it reads and
273
+ * writes this field. Required when type is `toggle`; ignored otherwise.
274
+ * Must name a real `enum` field. */
275
+ field?: string;
276
+ /** When `type === "toggle"`: the enum value that means "checked". The
277
+ * box is checked when the projected `field` equals this; checking writes
278
+ * it. Required when type is `toggle`; must be one of the enum's `values`. */
279
+ onValue?: string;
280
+ /** When `type === "toggle"`: the enum value written when the box is
281
+ * unchecked. Required when type is `toggle`; must be one of the enum's
282
+ * `values`. */
283
+ offValue?: string;
284
+ }
285
+ export interface CollectionSchema {
286
+ /** Human-facing collection name (sidebar, header). */
287
+ title: string;
288
+ /** Material-icon name shown next to the title. */
289
+ icon: string;
290
+ /** Workspace-relative folder holding one-JSON-per-record. Validated
291
+ * to live under the workspace root at load time. */
292
+ dataPath: string;
293
+ /** Field name whose value doubles as the record's filename. */
294
+ primaryKey: string;
295
+ /** When set, the collection is a singleton: at most one record,
296
+ * whose primary key is fixed to this value (e.g. `me` for the
297
+ * business profile). The host pre-fills + locks the create form's
298
+ * primary key and hides Add once the record exists. */
299
+ singleton?: string;
300
+ /** Ordered map: insertion order = column order in the table view. */
301
+ fields: Record<string, CollectionFieldSpec>;
302
+ /** Optional per-record actions rendered as buttons in the detail
303
+ * view (e.g. "Generate PDF"). Order = button order. */
304
+ actions?: CollectionAction[];
305
+ /** Optional collection-level actions rendered as buttons in the
306
+ * collection header (e.g. "Extend the course"). Unlike `actions`,
307
+ * these carry no record context: the seed prompt injects a compact
308
+ * progress summary of every record instead. The `when` predicate is
309
+ * not evaluated (there is no record to gate on). Order = button order. */
310
+ collectionActions?: CollectionAction[];
311
+ /** Name of the field whose value marks an item as "done". When set,
312
+ * a notification fires on item create (unless the item is born done)
313
+ * and clears when the field's value transitions into
314
+ * `completionDoneValues`. Must name a real field in `fields`. */
315
+ completionField?: string;
316
+ /** The set of values for `completionField` that count as "done"
317
+ * (e.g. `["Done"]` for a todo status field, `["paid"]` for an
318
+ * invoice). Non-empty. Compared as strings. */
319
+ completionDoneValues?: readonly string[];
320
+ /** Name of the field whose value is shown as the human-readable
321
+ * label in a completion notification's title (e.g. a `name` field,
322
+ * so the bell reads `Contacts: Jane Doe` instead of the opaque
323
+ * primaryKey). Must name a real field in `fields`. When unset — or
324
+ * when the record's value for it is empty — the title falls back to
325
+ * the record's primaryKey value. Display-only; never stored. */
326
+ displayField?: string;
327
+ /** Name of a `date` field that gates this item's completion
328
+ * notification: the bell is suppressed until the clock reaches that
329
+ * date (compared at day-granularity in the server's local timezone),
330
+ * instead of firing on create. Requires `completionField` /
331
+ * `completionDoneValues` (the bell still clears via the done value).
332
+ * Must name a real `date` field. Absent ⇒ fire on create, as before. */
333
+ triggerField?: string;
334
+ /** Lead time in whole days: fire the bell this many days BEFORE
335
+ * `triggerField` (so `10` shows the reminder 10 days early). The lead
336
+ * is applied at fire time, not stored, so it composes with `spawn` —
337
+ * every recurred cycle fires the same number of days before its own
338
+ * trigger. Non-negative integer; requires `triggerField`. Default 0
339
+ * (fire on the trigger date). */
340
+ triggerLeadDays?: number;
341
+ /** Host-driven recurrence. When set, requires `triggerField`. See
342
+ * {@link CollectionSpawn}. */
343
+ spawn?: CollectionSpawn;
344
+ /** Name of a `date` field that anchors the optional calendar view: a
345
+ * month grid where each record lands on the day cell matching this
346
+ * field's value. When unset, the calendar toggle still appears if the
347
+ * schema has any `date` field (the first one, in declaration order, is
348
+ * used by default and is switchable in-view). Set this to pin a specific
349
+ * anchor. Must name a real `date` field. */
350
+ calendarField?: string;
351
+ /** Name of a second `date` field marking the END of a multi-day span on
352
+ * the calendar: the record renders from `calendarField` through this
353
+ * date inclusive. Requires `calendarField`. Must name a real `date`
354
+ * field. Absent ⇒ single-day placement. */
355
+ calendarEndField?: string;
356
+ /** Name of a string field holding a free-form time or time-range
357
+ * (e.g. "14:00-17:00", "17:00-", "16:30") that places records on the
358
+ * calendar's day (time-allocation) view. Consulted only when the calendar
359
+ * date fields are date-only. Requires `calendarField`. */
360
+ calendarTimeField?: string;
361
+ /** Name of an `enum` field that groups records into columns on the
362
+ * optional Kanban board: each record lands in the column matching its
363
+ * value, with empty/unknown values collected in an "Uncategorized"
364
+ * column. When unset, the Kanban toggle still appears if the schema has
365
+ * any `enum` field (the first one, in declaration order, is used by
366
+ * default and is switchable in-view). Set this to pin a specific group
367
+ * field. Must name a real `enum` field. */
368
+ kanbanField?: string;
369
+ /** Optional custom (LLM-authored) HTML views, each rendered in a
370
+ * sandboxed iframe over the records. Absent ⇒ only the built-in
371
+ * field-derived views (table / calendar / kanban / dashboard). See
372
+ * {@link CollectionCustomView}. */
373
+ views?: CollectionCustomView[];
374
+ /** Optional predicate that gates the completion bell: when set, the bell
375
+ * fires only for records whose `String(record[notifyWhen.field])` is one
376
+ * of `notifyWhen.in` (e.g. notify only `high`/`urgent` priority todos).
377
+ * Reuses the `when` predicate shape. Requires `completionField` — it
378
+ * narrows that bell rather than introducing a second one. The bell still
379
+ * clears on done / delete / when the predicate stops matching. Absent ⇒
380
+ * notify for every open record (the prior behaviour). `notifyWhen.field`
381
+ * must name a real top-level field. */
382
+ notifyWhen?: CollectionWhen;
383
+ /** Optional scheduled-retrieval config. When present, the host refreshes
384
+ * this collection on `ingest.schedule`. Two flavours: a declarative Feed
385
+ * (`kind: rss/atom/http-json`) periodically fetches `ingest.url`, maps the
386
+ * response into records, and upserts them by `primaryKey` — only feeds
387
+ * discovered from the `<workspace>/feeds/` registry carry this. Or
388
+ * `kind: "agent"`, valid on any (incl. skill-backed) collection: the host
389
+ * dispatches a hidden background worker in `ingest.role` seeded with
390
+ * `ingest.template`, and the worker edits the records itself. The host's
391
+ * feeds subsystem narrows this to its richer `IngestSpec`. */
392
+ ingest?: CollectionIngest;
393
+ }
394
+ export interface CollectionSummary {
395
+ slug: string;
396
+ title: string;
397
+ icon: string;
398
+ source: CollectionSource;
399
+ }
400
+ export interface CollectionDetail extends CollectionSummary {
401
+ schema: CollectionSchema;
402
+ }
403
+ export type CollectionItem = Record<string, unknown>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 8-char hex id — short, slug-safe, and editable. Produces the same id *shape*
3
+ * as the server's `generateItemId()` (8 hex chars) so a UI-created collection
4
+ * record looks like one the server would have generated for a form submitted
5
+ * with a blank primary key. The source of randomness differs (UUID-derived here
6
+ * vs `randomBytes` on the server); only the shape is intentionally shared.
7
+ */
8
+ export declare function shortHexId(): string;
@@ -0,0 +1,29 @@
1
+ import { CollectionItem, CollectionFieldSpec } from './schema';
2
+ export type SortDirection = "asc" | "desc";
3
+ export interface SortState {
4
+ /** Field key of the single active sort column. */
5
+ field: string;
6
+ direction: SortDirection;
7
+ }
8
+ /** A row's comparable value for the active field. Exactly one of `num` /
9
+ * `str` is set when not empty; `empty` rows always sort last. */
10
+ export interface SortValue {
11
+ empty: boolean;
12
+ num?: number;
13
+ str?: string;
14
+ }
15
+ export declare function isSortableField(field: CollectionFieldSpec): boolean;
16
+ /** Cycle one column's state: none → asc → desc → none. */
17
+ export declare function nextSortDirection(current: SortDirection | null): SortDirection | null;
18
+ export declare function numericSortValue(raw: unknown): SortValue;
19
+ export declare function stringSortValue(raw: unknown): SortValue;
20
+ export declare function dateSortValue(raw: unknown): SortValue;
21
+ /** Enum sorts by the value's index in the declared `values` list. A value
22
+ * outside the list (or unset) is treated as empty → last. */
23
+ export declare function enumSortValue(values: readonly string[] | undefined, raw: unknown): SortValue;
24
+ /** Boolean / toggle: false < true, never empty (unset reads as false). */
25
+ export declare function boolSortValue(checked: boolean): SortValue;
26
+ export declare function compareSortValues(left: SortValue, right: SortValue): number;
27
+ /** Stable sort of `items` by `valueOf`. Empties always last; ties hold
28
+ * source order. Returns a new array (does not mutate `items`). */
29
+ export declare function sortItems(items: readonly CollectionItem[], direction: SortDirection, valueOf: (item: CollectionItem) => SortValue): CollectionItem[];
@@ -0,0 +1,106 @@
1
+ import { CollectionDetail, CollectionItem, CollectionSchema, CollectionSummary } from './schema';
2
+ /** A record file the server couldn't load or that violates the schema —
3
+ * silently skipped at read time (mirror of the server `RecordIssue`). */
4
+ export interface CollectionRecordIssue {
5
+ /** Record filename, e.g. `lesson-003.json`. */
6
+ file: string;
7
+ /** Human-readable problem, written to be actionable by the LLM. */
8
+ problem: string;
9
+ }
10
+ export interface CollectionDetailResponse {
11
+ collection: CollectionDetail;
12
+ items: CollectionItem[];
13
+ /** Record files that failed validation; drives the in-view Repair prompt. */
14
+ issues?: CollectionRecordIssue[];
15
+ }
16
+ export interface ItemMutationResponse {
17
+ itemId: string;
18
+ item: CollectionItem;
19
+ }
20
+ /** One row of a `table`-typed field, in draft form. */
21
+ export interface TableRowDraft {
22
+ text: Record<string, string>;
23
+ bool: Record<string, boolean>;
24
+ boolOriginallyPresent: Record<string, boolean>;
25
+ boolTouched: Record<string, boolean>;
26
+ }
27
+ export interface EditState {
28
+ mode: "create" | "edit";
29
+ text: Record<string, string>;
30
+ bool: Record<string, boolean>;
31
+ boolOriginallyPresent: Record<string, boolean>;
32
+ boolTouched: Record<string, boolean>;
33
+ table: Record<string, TableRowDraft[]>;
34
+ /** For edit mode: the original item id pinned to the URL. */
35
+ originalId: string | null;
36
+ }
37
+ /** Per-target-collection cache: an item's primary-key slug → display label. */
38
+ export type RefDisplayMap = Record<string, string>;
39
+ export type RefCache = Record<string, RefDisplayMap>;
40
+ /** Per-target-collection cache of full referenced records, for `<field>.<col>`
41
+ * derefs in derived formulas. */
42
+ export type RefRecordMap = Record<string, CollectionItem>;
43
+ export type RefRecordCache = Record<string, RefRecordMap>;
44
+ /** Per-target cache for `embed` fields: the target collection's schema + items. */
45
+ export interface EmbedTargetData {
46
+ schema: CollectionSchema;
47
+ items: CollectionItem[];
48
+ }
49
+ export type EmbedCache = Record<string, EmbedTargetData>;
50
+ /** Option shown in a `ref` field's `<select>` dropdown. */
51
+ export interface RefOption {
52
+ slug: string;
53
+ display: string;
54
+ }
55
+ export interface EmbedRow {
56
+ /** Sub-field key (used for `:key` + testids). */
57
+ key: string;
58
+ label: string;
59
+ /** Sub-field type — the renderer branches on "boolean" / "markdown". */
60
+ type: string;
61
+ /** Raw value, used only for the boolean check / em-dash. */
62
+ value: unknown;
63
+ /** Pre-formatted string for every non-boolean render path. */
64
+ display: string;
65
+ }
66
+ export interface EmbedView {
67
+ /** False when the target collection has no record with the embed's `id`
68
+ * (or the target couldn't be loaded) — the renderer shows a "missing"
69
+ * message + a link to create it. */
70
+ found: boolean;
71
+ rows: EmbedRow[];
72
+ /** Target collection slug, for the "create it" link + message. */
73
+ targetSlug: string;
74
+ /** The fixed record id the embed points at, for the message. */
75
+ recordId: string;
76
+ }
77
+ /** Active-notification severity for a record, used to accent flagged cards
78
+ * (kanban left-stripe, etc.). The host computes these from its notifier and
79
+ * passes them in; this is the structural type the view layer accepts. The host's
80
+ * own `NotifierSeverity` is the identical union, so its maps pass through. */
81
+ export type CollectionNotifySeverity = "info" | "nudge" | "urgent";
82
+ /** Response of the collections list endpoint (`API_ROUTES.collections.list`). */
83
+ export interface CollectionsListResponse {
84
+ collections: CollectionSummary[];
85
+ }
86
+ /** A row in the feeds index — a data-source collection from the workspace's
87
+ * `feeds/` registry. */
88
+ export interface FeedSummary {
89
+ slug: string;
90
+ title: string;
91
+ icon: string;
92
+ kind: string;
93
+ schedule: string;
94
+ lastFetchedAt: string | null;
95
+ }
96
+ /** Response of the feeds list endpoint (`API_ROUTES.feeds.list`). */
97
+ export interface FeedsListResponse {
98
+ feeds: FeedSummary[];
99
+ }
100
+ /** The `{slug,title,icon}` triple the index pages reconcile pinned shortcuts
101
+ * against (prune dead slugs, refresh stale labels). */
102
+ export interface CollectionShortcutInfo {
103
+ slug: string;
104
+ title: string;
105
+ icon: string;
106
+ }