@mulmoclaude/core 5.3.0 → 5.4.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 (37) hide show
  1. package/README.md +17 -1
  2. package/dist/collection/core/viewChatPolicy.d.ts +15 -6
  3. package/dist/collection/firestore.cjs +2 -1
  4. package/dist/collection/firestore.cjs.map +1 -1
  5. package/dist/collection/firestore.js +3 -2
  6. package/dist/collection/firestore.js.map +1 -1
  7. package/dist/collection/index.cjs +15 -6
  8. package/dist/collection/index.cjs.map +1 -1
  9. package/dist/collection/index.js +15 -6
  10. package/dist/collection/index.js.map +1 -1
  11. package/dist/collection/registry/server/index.cjs +2 -2
  12. package/dist/collection/registry/server/index.js +2 -2
  13. package/dist/collection/server/firestoreDocs.d.ts +10 -0
  14. package/dist/collection/server/index.cjs +2 -2
  15. package/dist/collection/server/index.js +2 -2
  16. package/dist/collection-watchers/index.cjs +2 -2
  17. package/dist/collection-watchers/index.js +2 -2
  18. package/dist/{discovery-CDXYswtw.cjs → discovery-B79IxEM6.cjs} +2 -3
  19. package/dist/discovery-B79IxEM6.cjs.map +1 -0
  20. package/dist/{discovery-B_64PBZU.js → discovery-DIGau7M8.js} +2 -3
  21. package/dist/discovery-DIGau7M8.js.map +1 -0
  22. package/dist/feeds/server/index.cjs +2 -2
  23. package/dist/feeds/server/index.js +2 -2
  24. package/dist/google/index.cjs +1 -1
  25. package/dist/google/index.js +1 -1
  26. package/dist/remote-view/index.cjs +7 -5
  27. package/dist/remote-view/index.cjs.map +1 -1
  28. package/dist/remote-view/index.d.ts +2 -2
  29. package/dist/remote-view/index.js +7 -5
  30. package/dist/remote-view/index.js.map +1 -1
  31. package/dist/{server-DfYwSX8b.cjs → server-BUbU9G-J.cjs} +2 -2
  32. package/dist/{server-DfYwSX8b.cjs.map → server-BUbU9G-J.cjs.map} +1 -1
  33. package/dist/{server-7POrhHKv.js → server-DZ7Cq7s_.js} +2 -2
  34. package/dist/{server-7POrhHKv.js.map → server-DZ7Cq7s_.js.map} +1 -1
  35. package/package.json +1 -1
  36. package/dist/discovery-B_64PBZU.js.map +0 -1
  37. package/dist/discovery-CDXYswtw.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/collection/core/presentCollection.ts","../../src/collection/core/enumColors.ts","../../src/collection/core/draft.ts","../../src/collection/core/viewChatPolicy.ts","../../src/collection/core/chatSeed.ts","../../src/collection/core/shortcutInfo.ts","../../src/collection/core/sortItems.ts","../../src/collection/core/sortValueOf.ts","../../src/collection/core/textSearch.ts","../../src/collection/core/recordKeys.ts","../../src/collection/core/itemLabel.ts","../../src/collection/core/ontologyGraph.ts"],"sourcesContent":["// presentCollection tool — definition + pure server-side executor.\n//\n// Isomorphic (no Vue, no Node): bundled to the browser as the plugin's\n// `execute`, and run server-side via the host's plugin dispatch route. The\n// executor only validates + echoes the addressing; the live schema + items\n// are fetched client-side by the View through the host's /api/collections\n// routes, so a bad slug surfaces as the View's \"not found\" state.\n\nimport type { ToolContext, ToolDefinition, ToolResult } from \"gui-chat-protocol\";\n\nexport const TOOL_NAME = \"presentCollection\";\n\n/** Render payload carried in the tool result's `data` field; the View mounts\n * off these. Same shape as the tool args. */\nexport interface PresentCollectionData {\n /** Slug of the collection to display (e.g. \"clients\", \"invoices\"). */\n collectionSlug: string;\n /** Optional primary-key value of a single item to open on mount. */\n itemId?: string | undefined;\n /** Which ROOT this card's collection lives in, as a host-opaque scope token.\n *\n * A collection's identity is `(root, slug)`, but a card payload named only\n * the slug — so the host re-resolved it through whatever binding was current\n * when the card RENDERED, which in a multi-root host may be a different\n * project than the one the card was made in. A card built in project A could\n * then read project B's data.\n *\n * **Stamped by the HOST, never accepted from tool arguments.** The tool args\n * are a model-controlled channel: a model that could name the scope could\n * name another project's, and the card — and any token minted for it — would\n * address a project the user never opened in this conversation. So\n * `executePresentCollection` DROPS any `scope` it is handed, and a host adds\n * its own with {@link withCardScope} when it applies the result, where it\n * already knows which binding produced the call.\n *\n * Host-opaque: pass an opaque project id, NEVER an absolute path — this\n * payload reaches the browser and, through a view, an LLM-authored iframe.\n *\n * Absent — the single-workspace case — the payload and every reconciliation\n * decision are exactly what they were before this field existed. */\n scope?: string | undefined;\n}\n\n/** Stamp a host's opaque project scope onto a card payload. The ONLY way a\n * scope gets in: the executor refuses to take one from tool arguments (see\n * `PresentCollectionData.scope`). `undefined` returns the payload untouched,\n * so a single-workspace host calling this unconditionally still produces a\n * payload with no `scope` property at all. */\nexport function withCardScope(data: PresentCollectionData, scope: string | undefined): PresentCollectionData {\n const trimmed = typeof scope === \"string\" ? scope.trim() : \"\";\n return trimmed.length > 0 ? { ...data, scope: trimmed } : data;\n}\n\n/** A card's identity for reconciliation. Two cards match only when they name\n * the same collection IN THE SAME SCOPE, so two projects' `tasks` cards stay\n * two cards. With no scope on either side this is the slug, unchanged. */\nexport function collectionCardKey(data: Pick<PresentCollectionData, \"collectionSlug\" | \"scope\">): string {\n return data.scope === undefined ? data.collectionSlug : `${data.scope}\\u0000${data.collectionSlug}`;\n}\n\n/** Do two card payloads address the same card? The reconciliation predicate a\n * host should use instead of comparing slugs. */\nexport function sameCollectionCard(\n one: Pick<PresentCollectionData, \"collectionSlug\" | \"scope\">,\n other: Pick<PresentCollectionData, \"collectionSlug\" | \"scope\">,\n): boolean {\n return collectionCardKey(one) === collectionCardKey(other);\n}\n\nexport type PresentCollectionArgs = PresentCollectionData;\n\nexport const TOOL_DEFINITION: ToolDefinition = {\n type: \"function\",\n name: TOOL_NAME,\n description:\n \"Display a schema-driven collection inline in the chat as an interactive, editable card. Shows the collection's list of records. Pass `itemId` to open one specific record on mount.\",\n parameters: {\n type: \"object\",\n properties: {\n collectionSlug: {\n type: \"string\",\n description: \"The slug of the collection to display (e.g. 'clients', 'invoices', 'contacts').\",\n },\n itemId: {\n type: \"string\",\n description: \"Optional primary-key value of a single record to open in detail view on mount. Omit to show the full list.\",\n },\n },\n required: [\"collectionSlug\"],\n },\n prompt: `After making changes to schema-driven collections, use ${TOOL_NAME} to present either the collection or the item`,\n};\n\n/** A trimmed non-empty string, or undefined. The tool's args arrive from an\n * LLM (and `scope` from the host), so every field is validated the same way\n * rather than trusted. */\nconst cleaned = (value: unknown): string | undefined => (typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined);\n\n/** Normalise the tool args into the card payload, or `null` when the required\n * slug is missing. Pure and exported so the addressing rules are testable\n * without going through a `ToolResult`.\n *\n * `scope` is deliberately NOT read from the args — see\n * `PresentCollectionData.scope`. Everything here comes from a model-controlled\n * channel, and the scope decides which project the card reads; a host stamps\n * it afterwards with `withCardScope`.\n *\n * Keys are added one at a time rather than spread with `undefined` values, so\n * a payload with no `itemId` OMITS the property entirely — which is what keeps\n * a single-workspace card byte-identical to what it has always been, in both\n * `deepEqual` and JSON. */\nexport const toPresentCollectionData = (args: PresentCollectionArgs): PresentCollectionData | null => {\n const collectionSlug = cleaned(args?.collectionSlug);\n if (!collectionSlug) return null;\n const itemId = cleaned(args.itemId);\n return { collectionSlug, ...(itemId ? { itemId } : {}) };\n};\n\nexport const executePresentCollection = async (\n _context: ToolContext,\n args: PresentCollectionArgs,\n): Promise<ToolResult<PresentCollectionData, PresentCollectionData>> => {\n const data = toPresentCollectionData(args);\n if (!data) {\n return {\n message: \"presentCollection error: collectionSlug is required\",\n instructions: \"Tell the user you couldn't display the collection because no collection was specified, and ask which collection they mean.\",\n };\n }\n const { collectionSlug, itemId } = data;\n const target = itemId ? `${collectionSlug} / ${itemId}` : collectionSlug;\n return {\n message: `Presented collection ${target}`,\n // `data` is the view's source (also the host's render-eligibility signal);\n // `jsonData` is what the LLM sees. Same payload, two audiences.\n data,\n jsonData: data,\n // Phrased to stay correct for BOTH storage kinds without loading the\n // schema (this executor is deliberately pure/isomorphic): a writable\n // collection offers edit/create/delete in the card; a read-only\n // `dataSource` collection hides those and changes flow through its\n // data file instead.\n instructions:\n \"The collection has been presented to the user as an interactive card. They can browse and open records directly; on a writable collection they can also edit, create, and delete (a read-only dataSource collection shows no edit controls — its records change by editing the backing data file). No further action is needed unless they ask.\",\n };\n};\n","// A standard, ordered colour palette for `enum` field values, shared by every\n// collection surface (list, calendar, kanban). Each value in an\n// enum's `values` array is assigned the palette entry at its index — cycling\n// when an enum declares more values than the palette holds — so colouring is\n// automatic and consistent without any per-value schema config.\n//\n// Tailwind only detects class names that appear as complete string literals,\n// so every surface's classes are spelled out per colour below rather than\n// built from a colour name at runtime.\n//\n// One enum is special: the field a schema's `notifyWhen` targets (the\n// \"notification enum\"). Its flagged values read the notification severity\n// colours — the first flagged value (most urgent) red, the rest amber — and\n// every other value reads neutral grey, mirroring the notification bell\n// (red = urgent, amber = nudge) rather than the rotating palette.\n// `resolveEnumColor` encapsulates that rule.\n\nimport { fieldText, fieldTextOrNull } from \"./fieldText\";\nimport type { CollectionSchema } from \"./schema\";\n\nexport interface EnumColorClasses {\n /** Stat-card style: border + fill + text + hover. */\n card: string;\n /** Small status dot (kanban column header). */\n dot: string;\n /** Pill / badge / inline `<select>` fill + text (no border width). */\n badge: string;\n /** Border colour, paired with a `border` width class by the caller. */\n border: string;\n}\n\n// The palette deliberately EXCLUDES the warm warning band (red / orange /\n// amber): those are reserved for the notification-enum severity colours\n// (`ENUM_ALERT` red, `ENUM_NUDGE` amber), so a normal enum value can never\n// draw a colour that reads like a notification. Eight well-separated cool /\n// green / magenta hues keep enough variety for wide enums.\nconst PALETTE: readonly EnumColorClasses[] = [\n {\n card: \"border-indigo-200 bg-indigo-50 text-indigo-600 hover:bg-indigo-100\",\n dot: \"bg-indigo-500\",\n badge: \"bg-indigo-100 text-indigo-700\",\n border: \"border-indigo-200\",\n },\n { card: \"border-sky-200 bg-sky-50 text-sky-600 hover:bg-sky-100\", dot: \"bg-sky-500\", badge: \"bg-sky-100 text-sky-700\", border: \"border-sky-200\" },\n { card: \"border-cyan-200 bg-cyan-50 text-cyan-600 hover:bg-cyan-100\", dot: \"bg-cyan-500\", badge: \"bg-cyan-100 text-cyan-700\", border: \"border-cyan-200\" },\n { card: \"border-teal-200 bg-teal-50 text-teal-600 hover:bg-teal-100\", dot: \"bg-teal-500\", badge: \"bg-teal-100 text-teal-700\", border: \"border-teal-200\" },\n {\n card: \"border-emerald-200 bg-emerald-50 text-emerald-600 hover:bg-emerald-100\",\n dot: \"bg-emerald-500\",\n badge: \"bg-emerald-100 text-emerald-700\",\n border: \"border-emerald-200\",\n },\n { card: \"border-lime-200 bg-lime-50 text-lime-600 hover:bg-lime-100\", dot: \"bg-lime-500\", badge: \"bg-lime-100 text-lime-700\", border: \"border-lime-200\" },\n {\n card: \"border-violet-200 bg-violet-50 text-violet-600 hover:bg-violet-100\",\n dot: \"bg-violet-500\",\n badge: \"bg-violet-100 text-violet-700\",\n border: \"border-violet-200\",\n },\n {\n card: \"border-fuchsia-200 bg-fuchsia-50 text-fuchsia-600 hover:bg-fuchsia-100\",\n dot: \"bg-fuchsia-500\",\n badge: \"bg-fuchsia-100 text-fuchsia-700\",\n border: \"border-fuchsia-200\",\n },\n];\n\n/** Neutral styling for the empty / Uncategorized bucket — never a palette\n * colour, so an unset or unknown value reads grey across every surface. */\nexport const ENUM_NEUTRAL: EnumColorClasses = {\n card: \"border-slate-200 bg-slate-50 text-slate-500 hover:bg-slate-100\",\n dot: \"bg-slate-300\",\n badge: \"bg-slate-100 text-slate-500\",\n border: \"border-slate-200\",\n};\n\n/** The urgent notification colour (red), matching the bell's `urgent`\n * severity. The first value a schema's `notifyWhen` flags reads this. */\nexport const ENUM_ALERT: EnumColorClasses = {\n card: \"border-red-200 bg-red-50 text-red-600 hover:bg-red-100\",\n dot: \"bg-red-500\",\n badge: \"bg-red-100 text-red-700\",\n border: \"border-red-200\",\n};\n\n/** The nudge notification colour (amber), matching the bell's `nudge`\n * severity. Flagged `notifyWhen` values after the first read this. */\nexport const ENUM_NUDGE: EnumColorClasses = {\n card: \"border-amber-200 bg-amber-50 text-amber-600 hover:bg-amber-100\",\n dot: \"bg-amber-500\",\n badge: \"bg-amber-100 text-amber-700\",\n border: \"border-amber-200\",\n};\n\n/** Classes for the enum value at `index` in its field's `values` array. A\n * negative index (value unset or not among the declared values) reads\n * neutral. */\nexport function enumColorClasses(index: number): EnumColorClasses {\n if (index < 0) return ENUM_NEUTRAL;\n return PALETTE[index % PALETTE.length] ?? ENUM_NEUTRAL;\n}\n\n/** Index of `value` within an enum field's declared `values`, or -1 when the\n * value is empty / unknown (→ neutral). */\nexport function enumValueIndex(values: readonly string[] | undefined, value: unknown): number {\n // No text form (array/object) means no enum member — \"[object Object]\" must\n // not index into the palette.\n const text = fieldTextOrNull(value);\n if (text === null || text === \"\") return -1;\n return values?.indexOf(text) ?? -1;\n}\n\n/** The flagged values when `fieldKey` is the schema's `notifyWhen` target (the\n * \"notification enum\"); undefined for every other field. */\nfunction notifyValuesFor(schema: CollectionSchema, fieldKey: string): readonly string[] | undefined {\n const spec = schema.notifyWhen;\n return spec && spec.field === fieldKey ? spec.in : undefined;\n}\n\n/** Resolve a value's colour for enum field `fieldKey`:\n * - Notification enum (`notifyWhen` targets it): the first flagged value (in\n * `notifyWhen.in` order, the most urgent) reads notification red, the rest\n * amber, and every non-flagged value neutral grey.\n * - Any other enum: the standard palette by the value's declared index. */\nexport function resolveEnumColor(schema: CollectionSchema, fieldKey: string, value: unknown): EnumColorClasses {\n const notifyValues = notifyValuesFor(schema, fieldKey);\n if (notifyValues) {\n const str = fieldText(value);\n const rank = notifyValues.indexOf(str);\n if (rank < 0) return ENUM_NEUTRAL;\n return rank === 0 ? ENUM_ALERT : ENUM_NUDGE;\n }\n const spec = schema.fields[fieldKey];\n return enumColorClasses(enumValueIndex(spec?.type === \"enum\" ? spec.values : undefined, value));\n}\n","// Pure edit-draft logic for the collection record form, extracted from\n// CollectionView.vue so the parent (build draft / save / validate) and\n// the extracted CollectionRecordPanel (per-row table mutators) share one\n// implementation. No Vue, no I/O — every function maps a draft + schema\n// to a value, so the omission/validation semantics are unit-testable.\n\nimport { fieldText } from \"./fieldText\";\nimport { fieldVisible } from \"./actionVisible\";\nimport { COMPUTED_TYPES } from \"./schema\";\nimport type { CollectionFieldSpec as FieldSpec, CollectionFieldType as FieldType, CollectionItem, CollectionSchema } from \"./schema\";\nimport type { EditState, TableRowDraft } from \"./uiTypes\";\n\n/** Build a row draft, reading each sub-field's persisted value via\n * `readSub`. An empty row passes a reader that always returns\n * `undefined`; a row-from-item reads the source record. Boolean\n * presence uses `typeof raw === \"boolean\"` so an existing explicit\n * `false` is recorded as present and round-trips on a no-op save. */\nfunction buildTableRowDraft(subFields: Record<string, FieldSpec>, readSub: (subKey: string) => unknown): TableRowDraft {\n const text: Record<string, string> = {};\n const bool: Record<string, boolean> = {};\n const boolOriginallyPresent: Record<string, boolean> = {};\n const boolTouched: Record<string, boolean> = {};\n for (const [subKey, subField] of Object.entries(subFields)) {\n const raw = readSub(subKey);\n if (subField.type === \"boolean\") {\n bool[subKey] = raw === true;\n boolOriginallyPresent[subKey] = typeof raw === \"boolean\";\n boolTouched[subKey] = false;\n } else {\n text[subKey] = fieldText(raw);\n }\n }\n return { text, bool, boolOriginallyPresent, boolTouched };\n}\n\n/** A fresh, empty row draft for a `table` field's sub-schema. */\nexport function emptyRow(subFields: Record<string, FieldSpec>): TableRowDraft {\n return buildTableRowDraft(subFields, () => undefined);\n}\n\n/** Build a row draft from an existing persisted row. */\nexport function rowFromItem(item: Record<string, unknown>, subFields: Record<string, FieldSpec>): TableRowDraft {\n return buildTableRowDraft(subFields, (subKey) => item[subKey]);\n}\n\n/** Own-property boolean read: a field named `toString` / `constructor` /\n * `__proto__` must read `false` here, not inherit a truthy Object.prototype\n * member and force an untouched boolean into every saved record. */\nfunction ownFlag(flags: Record<string, boolean>, key: string): boolean {\n return Object.hasOwn(flags, key) && flags[key] === true;\n}\n\n/** Decide whether a boolean field's draft value should be emitted (vs.\n * omitted so a downstream default applies). */\nfunction shouldEmitBoolean(state: EditState, key: string, field: FieldSpec): boolean {\n return ownFlag(state.boolOriginallyPresent, key) || ownFlag(state.boolTouched, key) || Boolean(field.required);\n}\n\n/** Convert a scalar draft slot to its persisted form. `undefined` = omit. */\nfunction scalarDraftToValue(raw: string | undefined, fieldType: FieldType): unknown {\n if (raw === undefined || raw === \"\") return undefined;\n if (fieldType === \"number\" || fieldType === \"money\") {\n const num = Number(raw);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\n/** Convert one table row draft to its persisted record. */\nfunction rowDraftToRecord(rowDraft: TableRowDraft, subFields: Record<string, FieldSpec>): Record<string, unknown> {\n const row: Record<string, unknown> = {};\n for (const [subKey, subField] of Object.entries(subFields)) {\n if (subField.type === \"boolean\") {\n const value = ownFlag(rowDraft.bool, subKey);\n if (ownFlag(rowDraft.boolOriginallyPresent, subKey) || ownFlag(rowDraft.boolTouched, subKey) || value || subField.required) row[subKey] = value;\n continue;\n }\n const value = scalarDraftToValue(rowDraft.text[subKey], subField.type);\n if (value !== undefined) row[subKey] = value;\n }\n return row;\n}\n\n/** Convert a full edit draft to the record to persist.\n *\n * Collected as entries rather than assigned into an accumulator: a field may\n * be named `__proto__` (JSON.parse hands that over as an own key, so it\n * reaches here like any other), and `record[key] = value` would run the\n * prototype setter for that one name — the user's value would vanish between\n * the form and the save, with nothing to see. `fromEntries` defines an own\n * property whatever the name is. The read side of this file already guards the\n * same hazard with `ownFlag` (Codex review on #2910). */\nexport function draftToRecord(state: EditState, schema: CollectionSchema): CollectionItem {\n const entries: [string, unknown][] = [];\n for (const [key, field] of Object.entries(schema.fields)) {\n if (COMPUTED_TYPES.has(field.type)) continue; // never persisted (toggle projects an enum field)\n if (field.type === \"boolean\") {\n if (shouldEmitBoolean(state, key, field)) entries.push([key, ownFlag(state.bool, key)]);\n continue;\n }\n if (field.type === \"table\" && field.of) {\n const subFields = field.of;\n entries.push([key, (state.table[key] ?? []).map((rowDraft) => rowDraftToRecord(rowDraft, subFields))]);\n continue;\n }\n const value = scalarDraftToValue(state.text[key], field.type);\n if (value !== undefined) entries.push([key, value]);\n }\n return Object.fromEntries(entries);\n}\n\n/** Normalise a raw inline-edit input (table-cell checkbox/select) to its\n * persisted form. Mirrors `draftToRecord`'s boolean strictness; an empty\n * enum selection (the placeholder option) clears the field via `undefined`. */\nexport function coerceInlineValue(field: FieldSpec, raw: boolean | string): unknown {\n if (field.type === \"boolean\") return raw === true;\n return raw === \"\" ? undefined : raw;\n}\n\n/** Build the full record to PUT for a single-cell inline edit, without\n * mutating `item`. A `undefined` value omits the key (enum cleared),\n * matching `draftToRecord`'s omission semantics. */\nexport function buildUpdatedRecord(item: CollectionItem, key: string, value: unknown): CollectionItem {\n if (value === undefined) {\n const { [key]: __omit, ...rest } = item;\n return rest;\n }\n return { ...item, [key]: value };\n}\n\n/** Empty for required-field validation — NOT a truthiness check (a\n * numeric `0` is a filled value). */\nfunction isMissingDraftValue(value: unknown): boolean {\n return value === undefined || value === null || value === \"\";\n}\n\n/** Label of the first required table sub-field empty in any row, else null. */\nfunction firstMissingTableSubField(field: FieldSpec, rows: TableRowDraft[] | undefined): string | null {\n if (field.type !== \"table\" || !rows) return null;\n for (const [rowIdx, row] of rows.entries()) {\n for (const [subKey, subField] of Object.entries(field.of)) {\n if (!subField.required || subField.type === \"boolean\") continue;\n if (isMissingDraftValue(row.text[subKey])) return `${field.label} #${rowIdx + 1}: ${subField.label}`;\n }\n }\n return null;\n}\n\n/** Field types the required check never flags: booleans always hold a\n * value, and the computed/projected kinds (COMPUTED_TYPES — the shared\n * set, so a future computed type can't drift past this check) have no\n * draft input at all. */\nconst NEVER_MISSING_TYPES: ReadonlySet<FieldType> = new Set<FieldType>([\"boolean\", ...COMPUTED_TYPES]);\n\nfunction validateOneField(key: string, field: FieldSpec, draft: EditState, record: CollectionItem): string | null {\n // A `when`-hidden field has no input the user can fill — never missing.\n if (!fieldVisible(field, record)) return null;\n if (field.type === \"table\" && field.of) {\n const rows = draft.table[key];\n if (field.required && (!rows || rows.length === 0)) return field.label;\n return firstMissingTableSubField(field, rows);\n }\n if (!field.required) return null;\n if (draft.mode === \"create\" && field.primary === true) return null; // server auto-generates id\n if (NEVER_MISSING_TYPES.has(field.type)) return null;\n return isMissingDraftValue(draft.text[key]) ? field.label : null;\n}\n\n/** Human-readable label of the first missing required field, or null. */\nexport function firstMissingRequiredField(draft: EditState, schema: CollectionSchema): string | null {\n const record = draftToRecord(draft, schema);\n for (const [key, field] of Object.entries(schema.fields)) {\n const missing = validateOneField(key, field, draft, record);\n if (missing) return missing;\n }\n return null;\n}\n","// Whether a custom view's `__MC_VIEW.startChat` RUNS the prompt or leaves it as\n// an editable draft (#3062). Pure + its own module so the one reading of the\n// declaration is shared by every surface that renders a view, and is pinned by\n// unit tests rather than by driving an iframe.\n\nimport type { CollectionCustomView } from \"./schema\";\n\n/** True when this view's `startChat` should send. Default-deny: a view that does\n * not declare `allowSendChat` drafts, so upgrading the host can never turn an\n * already-shipped view's buttons into unreviewed agent turns.\n *\n * Read from the SCHEMA — never from the message the iframe posts up. The view's\n * code composes the prompt text; letting it also decide whether that text runs\n * would put both halves of the decision inside the sandbox.\n *\n * EVERY surface consults this, the phone included. The phone once always sent,\n * on the grounds that it has no Enter key to press — but that made the same\n * view behave differently depending on where it was opened, and it silently\n * overrode default-deny on a device the author never tested. The phone is\n * served the resolved flag in its view payload rather than re-reading the\n * schema, because it never sees the schema. */\nexport function customViewSendsChat(view: Pick<CollectionCustomView, \"allowSendChat\">): boolean {\n return view.allowSendChat === true;\n}\n","// The slash-command chat seed a collection view sends to the agent when the\n// user starts a chat from a skill-backed collection or one of its records.\n// Skill-backed collections have a `/<slug>` command, so seed that. (Feeds are\n// skill-less and seeded differently; that branch stays in the view because it\n// is i18n-driven.)\n\n/** `/<slug> <message>`, or `/<slug> id=<itemId> <message>` when a specific\n * record is addressed. The `id=` selector goes BEFORE the free-text message so\n * the skill's argument parser reads it as a flag rather than as prose. */\nexport function skillCommandSeed(slug: string, message: string, itemId?: string): string {\n return itemId ? `/${slug} id=${itemId} ${message}` : `/${slug} ${message}`;\n}\n","// The one place an index row becomes the `{slug,title,icon,color}` a pinned\n// shortcut reconciles against.\n//\n// Both the collections index and the feeds index did this inline, and the\n// awkward part is identical in each: `color` must be ADDED only when there is\n// one, never assigned as `undefined` — the shortcut shapes declare it narrow\n// (see `CollectionSummary.color`) because the remote-host handlers pass them\n// through `Jsonify`, which drops `undefined` from a member union. Writing that\n// out twice is how the two copies drift.\n\nimport type { CollectionShortcutInfo } from \"./uiTypes\";\n\n/** The fields an index row supplies. Both `CollectionSummary` and\n * `FeedSummary` satisfy it; `icon` is optional because a feed row may carry\n * an empty one and rely on the surface's default. */\nexport interface ShortcutInfoSource {\n slug: string;\n title: string;\n icon?: string | undefined;\n color?: string | undefined;\n}\n\n/** An index row as shortcut-reconcile input. `fallbackIcon` stands in when the\n * row names no icon (feeds do this); `color` is omitted entirely rather than\n * set to `undefined` when the row has none. */\nexport function toShortcutInfo(row: ShortcutInfoSource, fallbackIcon: string): CollectionShortcutInfo {\n return {\n slug: row.slug,\n title: row.title,\n icon: row.icon && row.icon.length > 0 ? row.icon : fallbackIcon,\n ...(row.color === undefined ? {} : { color: row.color }),\n };\n}\n","// Sorting for the collection list table. The header sort toggle (next to\n// each field title) cycles a single active column through none → asc →\n// desc → none; this module turns that state plus a per-field value\n// extractor into an ordered copy of the rows.\n//\n// Two invariants the comparator guarantees:\n// 1. Rows with an empty/missing value for the sorted field always sink\n// to the bottom, regardless of direction.\n// 2. Ties (and the empty group) keep their original order — the sort is\n// stable via the captured source index.\n//\n// Field-type → comparable mapping (see `isSortableField`):\n// string/text/email → string · number/money → numeric ·\n// date/datetime → epoch-ms · enum → declared-index · boolean/toggle/flag →\n// false<true · ref → display label · derived → its display type.\n// markdown/table/image/file/embed get no sort button.\n\nimport { fieldTextOrNull } from \"./fieldText\";\nimport type { CollectionItem, CollectionFieldSpec, CollectionFieldType } from \"./schema\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface SortState {\n /** Field key of the single active sort column. */\n field: string;\n direction: SortDirection;\n}\n\n/** A row's comparable value for the active field. Exactly one of `num` /\n * `str` is set when not empty; `empty` rows always sort last. */\nexport interface SortValue {\n empty: boolean;\n num?: number;\n str?: string;\n}\n\nconst EMPTY: SortValue = { empty: true };\n\n/** Field types that render no value text in the table, so offer no sort. */\nconst NON_SORTABLE: ReadonlySet<CollectionFieldType> = new Set<CollectionFieldType>([\"markdown\", \"table\", \"image\", \"file\", \"embed\", \"backlinks\", \"rollup\"]);\n\nexport function isSortableField(field: CollectionFieldSpec): boolean {\n return !NON_SORTABLE.has(field.type);\n}\n\n/** Cycle one column's state: none → asc → desc → none. */\nexport function nextSortDirection(current: SortDirection | null): SortDirection | null {\n if (current === null) return \"asc\";\n if (current === \"asc\") return \"desc\";\n return null;\n}\n\n// ── SortValue constructors (one per comparable kind) ────────────────\n\nexport function numericSortValue(raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const num = typeof raw === \"number\" ? raw : Number(raw);\n return Number.isFinite(num) ? { empty: false, num } : EMPTY;\n}\n\nexport function stringSortValue(raw: unknown): SortValue {\n // An array/object has no sort key — treat it as empty (sorts last) instead of\n // grouping every such record together under \"[object Object]\".\n const str = fieldTextOrNull(raw);\n if (str === null) return EMPTY;\n return str.trim() === \"\" ? EMPTY : { empty: false, str };\n}\n\nexport function dateSortValue(raw: unknown): SortValue {\n const text = fieldTextOrNull(raw);\n if (text === null || text === \"\") return EMPTY;\n const epoch = Date.parse(text);\n // Unparseable dates fall back to a lexical compare rather than vanishing.\n return Number.isNaN(epoch) ? stringSortValue(raw) : { empty: false, num: epoch };\n}\n\n/** Enum sorts by the value's index in the declared `values` list. A value\n * outside the list (or unset) is treated as empty → last. */\nexport function enumSortValue(values: readonly string[] | undefined, raw: unknown): SortValue {\n const text = fieldTextOrNull(raw);\n if (text === null || text === \"\") return EMPTY;\n const idx = values ? values.indexOf(text) : -1;\n return idx < 0 ? EMPTY : { empty: false, num: idx };\n}\n\n/** Boolean / toggle: false < true, never empty (unset reads as false). */\nexport function boolSortValue(checked: boolean): SortValue {\n return { empty: false, num: checked ? 1 : 0 };\n}\n\n// ── Comparator + driver ─────────────────────────────────────────────\n\nexport function compareSortValues(left: SortValue, right: SortValue): number {\n if (left.num !== undefined && right.num !== undefined) return left.num - right.num;\n const leftStr = left.str ?? String(left.num ?? \"\");\n const rightStr = right.str ?? String(right.num ?? \"\");\n return leftStr.localeCompare(rightStr);\n}\n\n/** Stable sort of `items` by `valueOf`. Empties always last; ties hold\n * source order. Returns a new array (does not mutate `items`). */\nexport function sortItems(items: readonly CollectionItem[], direction: SortDirection, valueOf: (item: CollectionItem) => SortValue): CollectionItem[] {\n const dir = direction === \"asc\" ? 1 : -1;\n return items\n .map((item, index) => ({ item, index, sv: valueOf(item) }))\n .sort((left, right) => {\n if (left.sv.empty || right.sv.empty) {\n if (left.sv.empty && right.sv.empty) return left.index - right.index;\n return left.sv.empty ? 1 : -1;\n }\n const base = compareSortValues(left.sv, right.sv);\n return base !== 0 ? base * dir : left.index - right.index;\n })\n .map((decorated) => decorated.item);\n}\n","// Field-type → comparable value for the collection list-table sort. Splits\n// the header sort's per-row value extraction out of the Vue view so the\n// dispatch (which field type maps to which SortValue constructor) is testable\n// on its own. The comparators live in `./sortItems`; this module only routes.\n//\n// A few field kinds can't be sorted from the raw cell alone — `toggle` and\n// `flag` are projected booleans, `derived` is a formula, and `ref` sorts by\n// its resolved display label. Those readers live in the view's rendering\n// composable, so they are passed in (dependency injection) rather than\n// imported, keeping this module pure and framework-free.\n\nimport { numericSortValue, stringSortValue, dateSortValue, enumSortValue, boolSortValue, type SortValue } from \"./sortItems\";\nimport type { CollectionItem, CollectionFieldSpec as FieldSpec } from \"./schema\";\n\n/** Resolve a `ref` cell to its human display label (target slug + item id). */\nexport type RefDisplayResolver = (targetSlug: string, itemSlug: string) => string;\n\n/** The row readers the view supplies for the field kinds that can't sort off\n * the raw cell value. All come from the rendering composable. */\nexport interface SortValueDeps {\n toggleChecked: (item: CollectionItem, field: FieldSpec) => boolean;\n flagValueOf: (key: string, item: CollectionItem) => boolean;\n evaluateDerived: (field: FieldSpec, key: string, item: CollectionItem) => number | null;\n deriveRecord: (item: CollectionItem) => CollectionItem;\n resolveRefDisplay: RefDisplayResolver;\n}\n\n/** Comparable value for scalar fields that key off the raw cell value. */\nexport function scalarSortValue(field: FieldSpec, raw: unknown, resolveRefDisplay: RefDisplayResolver): SortValue {\n switch (field.type) {\n case \"number\":\n case \"money\":\n return numericSortValue(raw);\n case \"date\":\n case \"datetime\":\n return dateSortValue(raw);\n case \"enum\":\n return enumSortValue(field.values, raw);\n case \"boolean\":\n return boolSortValue(raw === true);\n case \"ref\":\n return field.to && typeof raw === \"string\" && raw ? stringSortValue(resolveRefDisplay(field.to, raw)) : stringSortValue(raw);\n default:\n return stringSortValue(raw);\n }\n}\n\n/** Derived rows sort by their display type: money/number → numeric,\n * date → epoch, anything else → the enriched value as a string. */\nexport function derivedSortValue(\n field: FieldSpec,\n key: string,\n item: CollectionItem,\n deps: Pick<SortValueDeps, \"evaluateDerived\" | \"deriveRecord\">,\n): SortValue {\n const display = field.type === \"derived\" ? field.display : undefined;\n if (display === undefined || display === \"number\" || display === \"money\") {\n return numericSortValue(deps.evaluateDerived(field, key, item));\n }\n const enriched = deps.deriveRecord(item);\n if (display === \"date\") return dateSortValue(enriched[key]);\n return stringSortValue(enriched[key]);\n}\n\n/** Comparable value for one row under the active field. Toggle, flag, and\n * derived need the whole record; every other type keys off the raw cell. */\nexport function sortValueOf(field: FieldSpec, key: string, item: CollectionItem, deps: SortValueDeps): SortValue {\n if (field.type === \"toggle\") return boolSortValue(deps.toggleChecked(item, field));\n if (field.type === \"flag\") return boolSortValue(deps.flagValueOf(key, item));\n if (field.type === \"derived\") return derivedSortValue(field, key, item, deps);\n return scalarSortValue(field, item[key], deps.resolveRefDisplay);\n}\n","// Free-text record matching for the collection list search box. Pure and\n// framework-free so the view's `filteredItems` computed just calls it.\n\nimport { fieldTextOrNull } from \"./fieldText\";\nimport type { CollectionItem } from \"./schema\";\n\n/** Case-insensitive substring match across an item's scalar fields.\n * Object/array-valued fields (table rows, nested records) have no text\n * form (`fieldTextOrNull` → `null`) and are skipped — they don't render as\n * searchable text in the list table.\n *\n * `query` is matched against each cell's lower-cased text but is NOT\n * lower-cased here: callers pass an already-normalised (trimmed +\n * lower-cased) query, so an upper-case `query` intentionally matches\n * nothing. Keeping the normalisation at the call site avoids re-lowering\n * the same query once per row. */\nexport function itemMatchesQuery(item: CollectionItem, query: string): boolean {\n // An empty query matches every record — otherwise a row whose only fields are\n // object/array-valued (no scalar cell reaches `includes(\"\")`) would vanish\n // when the search box is cleared. The list caller already short-circuits the\n // empty case, so this only guards a future caller that doesn't.\n if (query === \"\") return true;\n return Object.values(item).some((value) => {\n const text = fieldTextOrNull(value);\n return text !== null && text.toLowerCase().includes(query);\n });\n}\n","// Composite cell keys for the list table's per-cell state maps, plus the\n// load-time \"which enum cells were empty\" snapshot the inline enum dropdown\n// reads. Pure and framework-free so the view keeps only the reactive refs.\n\nimport { fieldText } from \"./fieldText\";\nimport type { CollectionItem } from \"./schema\";\n\n/** The schema slice `snapshotEmptyEnums` reads — minimal structural shape so\n * both the client and server collection-schema types satisfy it as-is. */\nexport interface EnumSnapshotSchema {\n fields: Record<string, { type: string }>;\n primaryKey: string;\n}\n\n/** Stable key for one cell (`<rowId>:<fieldKey>`) in the per-cell state maps. */\nexport function cellKey(rowId: string, fieldKey: string): string {\n return `${rowId}:${fieldKey}`;\n}\n\n/** A row's stable identity: the primary-key value as text (`\"\"` when the schema\n * has no primary key, or the value is absent). Every per-row / per-cell state\n * map keys off this, and it is the SAME derivation `snapshotEmptyEnums` uses\n * for its record ids (`fieldText`), so `cellKey(rowIdOf(...), field)` and the\n * empty-enum snapshot always agree. A real primary key is a scalar, so this\n * matches its plain string form. */\nexport function rowIdOf(primaryKey: string | undefined, item: CollectionItem): string {\n return primaryKey ? fieldText(item[primaryKey]) : \"\";\n}\n\n/** The set of enum cells that were empty in the freshly-fetched records — the\n * only cells whose inline dropdown offers an empty option. */\nexport function snapshotEmptyEnums(schema: EnumSnapshotSchema, records: CollectionItem[]): Set<string> {\n const empty = new Set<string>();\n const enumKeys = Object.entries(schema.fields)\n .filter(([, field]) => field.type === \"enum\")\n .map(([fieldKey]) => fieldKey);\n if (enumKeys.length === 0) return empty;\n for (const record of records) {\n const recordId = fieldText(record[schema.primaryKey]);\n for (const fieldKey of enumKeys) {\n if (record[fieldKey] == null || record[fieldKey] === \"\") empty.add(cellKey(recordId, fieldKey));\n }\n }\n return empty;\n}\n","// Shared chip/label resolution for the collection calendar surfaces (month\n// grid + day view), so both label a record identically. Pure, type-only\n// dependency on the schema shape.\n\nimport { fieldText } from \"./fieldText\";\nimport type { CollectionItem, CollectionSchema } from \"./schema\";\n\n// Text-like field types that make a sensible human-readable label.\nconst LABEL_FIELD_TYPES = new Set([\"string\", \"text\", \"markdown\", \"email\"]);\n\n/** Which field labels a record: the schema's explicit `displayField`, else the\n * first non-primary text-like field (so a collection without a displayField\n * shows e.g. the title rather than the opaque primaryKey), else null → the\n * caller falls back to the primary-key value. */\nexport function labelFieldFor(schema: CollectionSchema): string | null {\n if (schema.displayField) return schema.displayField;\n for (const [key, spec] of Object.entries(schema.fields)) {\n if (key !== schema.primaryKey && LABEL_FIELD_TYPES.has(spec.type)) return key;\n }\n return null;\n}\n\n/** A record's primary-key value as a string. */\nexport function itemIdOf(item: CollectionItem, schema: CollectionSchema): string {\n return fieldText(item[schema.primaryKey]);\n}\n\n/** A record's display label: the resolved `labelField` value, else the\n * primary key. Pass the result of `labelFieldFor(schema)` as `labelField`\n * (compute it once per render rather than per item). */\nexport function itemLabelOf(item: CollectionItem, schema: CollectionSchema, labelField: string | null): string {\n if (labelField) {\n const value = item[labelField];\n // Accept any primitive (string / number / boolean) so a numeric or boolean\n // display field still labels the record; objects/arrays fall through to the\n // id rather than rendering as \"[object Object]\".\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n const text = String(value);\n if (text.length > 0) return text;\n }\n }\n return itemIdOf(item, schema);\n}\n","// Pure builder for the workspace ontology graph — the `/collections` Map\n// panel (phase 2 of plans/done/collection-ontology.md step ①; plan:\n// plans/done/feat-collection-ontology-graph.md). Consumes the per-collection\n// ontology entries `buildWorkspaceOntology` derives server-side and turns\n// them into a node/edge structure a graph view can render directly.\n// Browser-safe (no `node:*` imports) so the Vue plugin builds the same\n// graph from the raw entries — same parity discipline as `deriveAll` and\n// the sibling `wiki/graph.ts`.\n\n/** One relationship a schema declares: a `ref` (the record stores the\n * target's primaryKey slug) or `embed` (display-only pull) pointing at\n * collection `to`, or `backlinks` / `rollup` (display-only REVERSE\n * refs — `to` is the relation's source collection, i.e. its `from`,\n * and `via` names the exact ref field there being reversed).\n * A `ref` column inside a `table` field is reported with a dotted path\n * (`lines.clientId`). Whether `to` exists is NOT checked — resolution\n * is fail-soft at render. */\nexport interface OntologyRelation {\n field: string;\n kind: \"ref\" | \"embed\" | \"backlinks\" | \"rollup\";\n to: string;\n via?: string;\n}\n\nexport interface CollectionOntologyEntry {\n slug: string;\n title: string;\n icon: string;\n primaryKey: string;\n /** The effective display field: the schema's `displayField`, falling\n * back to the primaryKey exactly as render-time labelling does. */\n displayField: string;\n /** Records in the collection, or `null` when the backend couldn't be\n * reached to count them (an engine that failed to load, a closed\n * session). Deliberately not 0: an unreachable collection reported as\n * empty invites \"restoring\" data that is intact but out of reach. */\n recordCount: number | null;\n relations: OntologyRelation[];\n}\n\nexport interface OntologyGraphNode {\n slug: string;\n title: string;\n icon: string;\n recordCount: number | null;\n /** No discovered collection has this slug — the node exists only\n * because a relation points at it. Rendered as a ghost so the graph\n * doubles as a broken-ref lint surface (lint, not lock). */\n missing?: boolean;\n}\n\nexport interface OntologyGraphEdge {\n /** Tail: the collection whose records store (`ref`) or pull (`embed`)\n * the link — or, for an uncollapsed reverse relation, the collection\n * whose refs the `backlinks`/`rollup` field aggregates. */\n from: string;\n /** Head: the collection the link points at. */\n to: string;\n /** Field declaring the relation — on `from` for `ref`/`embed`, on\n * `to` for an uncollapsed `backlinks`/`rollup`. */\n field: string;\n kind: OntologyRelation[\"kind\"];\n /** `backlinks`/`rollup` field names on `to` that declare the reverse\n * of this `ref` edge, collapsed here so one link never draws twice. */\n reverseFields?: string[];\n}\n\nexport interface OntologyGraph {\n nodes: OntologyGraphNode[];\n edges: OntologyGraphEdge[];\n}\n\nconst isForwardKind = (kind: OntologyRelation[\"kind\"]): boolean => kind === \"ref\" || kind === \"embed\";\n\n/** Fold a reverse relation (`backlinks`/`rollup` declared on `owner`)\n * into the edge list: collapse onto the forward `ref` edge whose field\n * is the relation's declared `via` (several refs can link the same\n * pair — matches.homeTeam vs matches.awayTeam — so the pair alone is\n * ambiguous), else emit its own edge oriented in true data direction\n * (refs' source → owner). A `via` naming no forward edge stays\n * uncollapsed — fail-soft, like every other dangling reference. */\nconst addReverseRelation = (edges: OntologyGraphEdge[], owner: string, rel: OntologyRelation): void => {\n const forward = edges.find((edge) => edge.kind === \"ref\" && edge.from === rel.to && edge.to === owner && (rel.via === undefined || edge.field === rel.via));\n if (forward) {\n forward.reverseFields = [...(forward.reverseFields ?? []), rel.field];\n return;\n }\n edges.push({ from: rel.to, to: owner, field: rel.field, kind: rel.kind });\n};\n\n/** Two passes so every forward `ref` edge exists before any reverse\n * relation tries to collapse onto one — entry order must not matter. */\nconst collectEdges = (entries: CollectionOntologyEntry[]): OntologyGraphEdge[] => {\n const edges: OntologyGraphEdge[] = [];\n for (const entry of entries) {\n for (const rel of entry.relations) {\n if (isForwardKind(rel.kind)) edges.push({ from: entry.slug, to: rel.to, field: rel.field, kind: rel.kind });\n }\n }\n for (const entry of entries) {\n for (const rel of entry.relations) {\n if (!isForwardKind(rel.kind)) addReverseRelation(edges, entry.slug, rel);\n }\n }\n return edges;\n};\n\n/** Slugs referenced by an edge endpoint but backed by no discovered\n * collection, slug-sorted for deterministic node order. */\nconst ghostSlugs = (edges: OntologyGraphEdge[], known: ReadonlySet<string>): string[] => {\n const ghosts = new Set<string>();\n for (const edge of edges) {\n if (!known.has(edge.from)) ghosts.add(edge.from);\n if (!known.has(edge.to)) ghosts.add(edge.to);\n }\n return [...ghosts].sort();\n};\n\n/** Build the renderable graph: one node per discovered collection (in\n * the entries' slug-sorted order) plus ghost nodes for dangling\n * targets, one edge per underlying link. */\nexport const buildOntologyGraph = (entries: CollectionOntologyEntry[]): OntologyGraph => {\n const edges = collectEdges(entries);\n const known = new Set(entries.map((entry) => entry.slug));\n const nodes: OntologyGraphNode[] = entries.map(({ slug, title, icon, recordCount }) => ({ slug, title, icon, recordCount }));\n for (const slug of ghostSlugs(edges, known)) {\n // A ghost node has no collection behind it at all, so it genuinely holds\n // no records — 0, not the \"couldn't count\" null.\n nodes.push({ slug, title: slug, icon: \"\", recordCount: 0, missing: true });\n }\n return { nodes, edges };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/collection/core/presentCollection.ts","../../src/collection/core/enumColors.ts","../../src/collection/core/draft.ts","../../src/collection/core/viewChatPolicy.ts","../../src/collection/core/chatSeed.ts","../../src/collection/core/shortcutInfo.ts","../../src/collection/core/sortItems.ts","../../src/collection/core/sortValueOf.ts","../../src/collection/core/textSearch.ts","../../src/collection/core/recordKeys.ts","../../src/collection/core/itemLabel.ts","../../src/collection/core/ontologyGraph.ts"],"sourcesContent":["// presentCollection tool — definition + pure server-side executor.\n//\n// Isomorphic (no Vue, no Node): bundled to the browser as the plugin's\n// `execute`, and run server-side via the host's plugin dispatch route. The\n// executor only validates + echoes the addressing; the live schema + items\n// are fetched client-side by the View through the host's /api/collections\n// routes, so a bad slug surfaces as the View's \"not found\" state.\n\nimport type { ToolContext, ToolDefinition, ToolResult } from \"gui-chat-protocol\";\n\nexport const TOOL_NAME = \"presentCollection\";\n\n/** Render payload carried in the tool result's `data` field; the View mounts\n * off these. Same shape as the tool args. */\nexport interface PresentCollectionData {\n /** Slug of the collection to display (e.g. \"clients\", \"invoices\"). */\n collectionSlug: string;\n /** Optional primary-key value of a single item to open on mount. */\n itemId?: string | undefined;\n /** Which ROOT this card's collection lives in, as a host-opaque scope token.\n *\n * A collection's identity is `(root, slug)`, but a card payload named only\n * the slug — so the host re-resolved it through whatever binding was current\n * when the card RENDERED, which in a multi-root host may be a different\n * project than the one the card was made in. A card built in project A could\n * then read project B's data.\n *\n * **Stamped by the HOST, never accepted from tool arguments.** The tool args\n * are a model-controlled channel: a model that could name the scope could\n * name another project's, and the card — and any token minted for it — would\n * address a project the user never opened in this conversation. So\n * `executePresentCollection` DROPS any `scope` it is handed, and a host adds\n * its own with {@link withCardScope} when it applies the result, where it\n * already knows which binding produced the call.\n *\n * Host-opaque: pass an opaque project id, NEVER an absolute path — this\n * payload reaches the browser and, through a view, an LLM-authored iframe.\n *\n * Absent — the single-workspace case — the payload and every reconciliation\n * decision are exactly what they were before this field existed. */\n scope?: string | undefined;\n}\n\n/** Stamp a host's opaque project scope onto a card payload. The ONLY way a\n * scope gets in: the executor refuses to take one from tool arguments (see\n * `PresentCollectionData.scope`). `undefined` returns the payload untouched,\n * so a single-workspace host calling this unconditionally still produces a\n * payload with no `scope` property at all. */\nexport function withCardScope(data: PresentCollectionData, scope: string | undefined): PresentCollectionData {\n const trimmed = typeof scope === \"string\" ? scope.trim() : \"\";\n return trimmed.length > 0 ? { ...data, scope: trimmed } : data;\n}\n\n/** A card's identity for reconciliation. Two cards match only when they name\n * the same collection IN THE SAME SCOPE, so two projects' `tasks` cards stay\n * two cards. With no scope on either side this is the slug, unchanged. */\nexport function collectionCardKey(data: Pick<PresentCollectionData, \"collectionSlug\" | \"scope\">): string {\n return data.scope === undefined ? data.collectionSlug : `${data.scope}\\u0000${data.collectionSlug}`;\n}\n\n/** Do two card payloads address the same card? The reconciliation predicate a\n * host should use instead of comparing slugs. */\nexport function sameCollectionCard(\n one: Pick<PresentCollectionData, \"collectionSlug\" | \"scope\">,\n other: Pick<PresentCollectionData, \"collectionSlug\" | \"scope\">,\n): boolean {\n return collectionCardKey(one) === collectionCardKey(other);\n}\n\nexport type PresentCollectionArgs = PresentCollectionData;\n\nexport const TOOL_DEFINITION: ToolDefinition = {\n type: \"function\",\n name: TOOL_NAME,\n description:\n \"Display a schema-driven collection inline in the chat as an interactive, editable card. Shows the collection's list of records. Pass `itemId` to open one specific record on mount.\",\n parameters: {\n type: \"object\",\n properties: {\n collectionSlug: {\n type: \"string\",\n description: \"The slug of the collection to display (e.g. 'clients', 'invoices', 'contacts').\",\n },\n itemId: {\n type: \"string\",\n description: \"Optional primary-key value of a single record to open in detail view on mount. Omit to show the full list.\",\n },\n },\n required: [\"collectionSlug\"],\n },\n prompt: `After making changes to schema-driven collections, use ${TOOL_NAME} to present either the collection or the item`,\n};\n\n/** A trimmed non-empty string, or undefined. The tool's args arrive from an\n * LLM (and `scope` from the host), so every field is validated the same way\n * rather than trusted. */\nconst cleaned = (value: unknown): string | undefined => (typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined);\n\n/** Normalise the tool args into the card payload, or `null` when the required\n * slug is missing. Pure and exported so the addressing rules are testable\n * without going through a `ToolResult`.\n *\n * `scope` is deliberately NOT read from the args — see\n * `PresentCollectionData.scope`. Everything here comes from a model-controlled\n * channel, and the scope decides which project the card reads; a host stamps\n * it afterwards with `withCardScope`.\n *\n * Keys are added one at a time rather than spread with `undefined` values, so\n * a payload with no `itemId` OMITS the property entirely — which is what keeps\n * a single-workspace card byte-identical to what it has always been, in both\n * `deepEqual` and JSON. */\nexport const toPresentCollectionData = (args: PresentCollectionArgs): PresentCollectionData | null => {\n const collectionSlug = cleaned(args?.collectionSlug);\n if (!collectionSlug) return null;\n const itemId = cleaned(args.itemId);\n return { collectionSlug, ...(itemId ? { itemId } : {}) };\n};\n\nexport const executePresentCollection = async (\n _context: ToolContext,\n args: PresentCollectionArgs,\n): Promise<ToolResult<PresentCollectionData, PresentCollectionData>> => {\n const data = toPresentCollectionData(args);\n if (!data) {\n return {\n message: \"presentCollection error: collectionSlug is required\",\n instructions: \"Tell the user you couldn't display the collection because no collection was specified, and ask which collection they mean.\",\n };\n }\n const { collectionSlug, itemId } = data;\n const target = itemId ? `${collectionSlug} / ${itemId}` : collectionSlug;\n return {\n message: `Presented collection ${target}`,\n // `data` is the view's source (also the host's render-eligibility signal);\n // `jsonData` is what the LLM sees. Same payload, two audiences.\n data,\n jsonData: data,\n // Phrased to stay correct for BOTH storage kinds without loading the\n // schema (this executor is deliberately pure/isomorphic): a writable\n // collection offers edit/create/delete in the card; a read-only\n // `dataSource` collection hides those and changes flow through its\n // data file instead.\n instructions:\n \"The collection has been presented to the user as an interactive card. They can browse and open records directly; on a writable collection they can also edit, create, and delete (a read-only dataSource collection shows no edit controls — its records change by editing the backing data file). No further action is needed unless they ask.\",\n };\n};\n","// A standard, ordered colour palette for `enum` field values, shared by every\n// collection surface (list, calendar, kanban). Each value in an\n// enum's `values` array is assigned the palette entry at its index — cycling\n// when an enum declares more values than the palette holds — so colouring is\n// automatic and consistent without any per-value schema config.\n//\n// Tailwind only detects class names that appear as complete string literals,\n// so every surface's classes are spelled out per colour below rather than\n// built from a colour name at runtime.\n//\n// One enum is special: the field a schema's `notifyWhen` targets (the\n// \"notification enum\"). Its flagged values read the notification severity\n// colours — the first flagged value (most urgent) red, the rest amber — and\n// every other value reads neutral grey, mirroring the notification bell\n// (red = urgent, amber = nudge) rather than the rotating palette.\n// `resolveEnumColor` encapsulates that rule.\n\nimport { fieldText, fieldTextOrNull } from \"./fieldText\";\nimport type { CollectionSchema } from \"./schema\";\n\nexport interface EnumColorClasses {\n /** Stat-card style: border + fill + text + hover. */\n card: string;\n /** Small status dot (kanban column header). */\n dot: string;\n /** Pill / badge / inline `<select>` fill + text (no border width). */\n badge: string;\n /** Border colour, paired with a `border` width class by the caller. */\n border: string;\n}\n\n// The palette deliberately EXCLUDES the warm warning band (red / orange /\n// amber): those are reserved for the notification-enum severity colours\n// (`ENUM_ALERT` red, `ENUM_NUDGE` amber), so a normal enum value can never\n// draw a colour that reads like a notification. Eight well-separated cool /\n// green / magenta hues keep enough variety for wide enums.\nconst PALETTE: readonly EnumColorClasses[] = [\n {\n card: \"border-indigo-200 bg-indigo-50 text-indigo-600 hover:bg-indigo-100\",\n dot: \"bg-indigo-500\",\n badge: \"bg-indigo-100 text-indigo-700\",\n border: \"border-indigo-200\",\n },\n { card: \"border-sky-200 bg-sky-50 text-sky-600 hover:bg-sky-100\", dot: \"bg-sky-500\", badge: \"bg-sky-100 text-sky-700\", border: \"border-sky-200\" },\n { card: \"border-cyan-200 bg-cyan-50 text-cyan-600 hover:bg-cyan-100\", dot: \"bg-cyan-500\", badge: \"bg-cyan-100 text-cyan-700\", border: \"border-cyan-200\" },\n { card: \"border-teal-200 bg-teal-50 text-teal-600 hover:bg-teal-100\", dot: \"bg-teal-500\", badge: \"bg-teal-100 text-teal-700\", border: \"border-teal-200\" },\n {\n card: \"border-emerald-200 bg-emerald-50 text-emerald-600 hover:bg-emerald-100\",\n dot: \"bg-emerald-500\",\n badge: \"bg-emerald-100 text-emerald-700\",\n border: \"border-emerald-200\",\n },\n { card: \"border-lime-200 bg-lime-50 text-lime-600 hover:bg-lime-100\", dot: \"bg-lime-500\", badge: \"bg-lime-100 text-lime-700\", border: \"border-lime-200\" },\n {\n card: \"border-violet-200 bg-violet-50 text-violet-600 hover:bg-violet-100\",\n dot: \"bg-violet-500\",\n badge: \"bg-violet-100 text-violet-700\",\n border: \"border-violet-200\",\n },\n {\n card: \"border-fuchsia-200 bg-fuchsia-50 text-fuchsia-600 hover:bg-fuchsia-100\",\n dot: \"bg-fuchsia-500\",\n badge: \"bg-fuchsia-100 text-fuchsia-700\",\n border: \"border-fuchsia-200\",\n },\n];\n\n/** Neutral styling for the empty / Uncategorized bucket — never a palette\n * colour, so an unset or unknown value reads grey across every surface. */\nexport const ENUM_NEUTRAL: EnumColorClasses = {\n card: \"border-slate-200 bg-slate-50 text-slate-500 hover:bg-slate-100\",\n dot: \"bg-slate-300\",\n badge: \"bg-slate-100 text-slate-500\",\n border: \"border-slate-200\",\n};\n\n/** The urgent notification colour (red), matching the bell's `urgent`\n * severity. The first value a schema's `notifyWhen` flags reads this. */\nexport const ENUM_ALERT: EnumColorClasses = {\n card: \"border-red-200 bg-red-50 text-red-600 hover:bg-red-100\",\n dot: \"bg-red-500\",\n badge: \"bg-red-100 text-red-700\",\n border: \"border-red-200\",\n};\n\n/** The nudge notification colour (amber), matching the bell's `nudge`\n * severity. Flagged `notifyWhen` values after the first read this. */\nexport const ENUM_NUDGE: EnumColorClasses = {\n card: \"border-amber-200 bg-amber-50 text-amber-600 hover:bg-amber-100\",\n dot: \"bg-amber-500\",\n badge: \"bg-amber-100 text-amber-700\",\n border: \"border-amber-200\",\n};\n\n/** Classes for the enum value at `index` in its field's `values` array. A\n * negative index (value unset or not among the declared values) reads\n * neutral. */\nexport function enumColorClasses(index: number): EnumColorClasses {\n if (index < 0) return ENUM_NEUTRAL;\n return PALETTE[index % PALETTE.length] ?? ENUM_NEUTRAL;\n}\n\n/** Index of `value` within an enum field's declared `values`, or -1 when the\n * value is empty / unknown (→ neutral). */\nexport function enumValueIndex(values: readonly string[] | undefined, value: unknown): number {\n // No text form (array/object) means no enum member — \"[object Object]\" must\n // not index into the palette.\n const text = fieldTextOrNull(value);\n if (text === null || text === \"\") return -1;\n return values?.indexOf(text) ?? -1;\n}\n\n/** The flagged values when `fieldKey` is the schema's `notifyWhen` target (the\n * \"notification enum\"); undefined for every other field. */\nfunction notifyValuesFor(schema: CollectionSchema, fieldKey: string): readonly string[] | undefined {\n const spec = schema.notifyWhen;\n return spec && spec.field === fieldKey ? spec.in : undefined;\n}\n\n/** Resolve a value's colour for enum field `fieldKey`:\n * - Notification enum (`notifyWhen` targets it): the first flagged value (in\n * `notifyWhen.in` order, the most urgent) reads notification red, the rest\n * amber, and every non-flagged value neutral grey.\n * - Any other enum: the standard palette by the value's declared index. */\nexport function resolveEnumColor(schema: CollectionSchema, fieldKey: string, value: unknown): EnumColorClasses {\n const notifyValues = notifyValuesFor(schema, fieldKey);\n if (notifyValues) {\n const str = fieldText(value);\n const rank = notifyValues.indexOf(str);\n if (rank < 0) return ENUM_NEUTRAL;\n return rank === 0 ? ENUM_ALERT : ENUM_NUDGE;\n }\n const spec = schema.fields[fieldKey];\n return enumColorClasses(enumValueIndex(spec?.type === \"enum\" ? spec.values : undefined, value));\n}\n","// Pure edit-draft logic for the collection record form, extracted from\n// CollectionView.vue so the parent (build draft / save / validate) and\n// the extracted CollectionRecordPanel (per-row table mutators) share one\n// implementation. No Vue, no I/O — every function maps a draft + schema\n// to a value, so the omission/validation semantics are unit-testable.\n\nimport { fieldText } from \"./fieldText\";\nimport { fieldVisible } from \"./actionVisible\";\nimport { COMPUTED_TYPES } from \"./schema\";\nimport type { CollectionFieldSpec as FieldSpec, CollectionFieldType as FieldType, CollectionItem, CollectionSchema } from \"./schema\";\nimport type { EditState, TableRowDraft } from \"./uiTypes\";\n\n/** Build a row draft, reading each sub-field's persisted value via\n * `readSub`. An empty row passes a reader that always returns\n * `undefined`; a row-from-item reads the source record. Boolean\n * presence uses `typeof raw === \"boolean\"` so an existing explicit\n * `false` is recorded as present and round-trips on a no-op save. */\nfunction buildTableRowDraft(subFields: Record<string, FieldSpec>, readSub: (subKey: string) => unknown): TableRowDraft {\n const text: Record<string, string> = {};\n const bool: Record<string, boolean> = {};\n const boolOriginallyPresent: Record<string, boolean> = {};\n const boolTouched: Record<string, boolean> = {};\n for (const [subKey, subField] of Object.entries(subFields)) {\n const raw = readSub(subKey);\n if (subField.type === \"boolean\") {\n bool[subKey] = raw === true;\n boolOriginallyPresent[subKey] = typeof raw === \"boolean\";\n boolTouched[subKey] = false;\n } else {\n text[subKey] = fieldText(raw);\n }\n }\n return { text, bool, boolOriginallyPresent, boolTouched };\n}\n\n/** A fresh, empty row draft for a `table` field's sub-schema. */\nexport function emptyRow(subFields: Record<string, FieldSpec>): TableRowDraft {\n return buildTableRowDraft(subFields, () => undefined);\n}\n\n/** Build a row draft from an existing persisted row. */\nexport function rowFromItem(item: Record<string, unknown>, subFields: Record<string, FieldSpec>): TableRowDraft {\n return buildTableRowDraft(subFields, (subKey) => item[subKey]);\n}\n\n/** Own-property boolean read: a field named `toString` / `constructor` /\n * `__proto__` must read `false` here, not inherit a truthy Object.prototype\n * member and force an untouched boolean into every saved record. */\nfunction ownFlag(flags: Record<string, boolean>, key: string): boolean {\n return Object.hasOwn(flags, key) && flags[key] === true;\n}\n\n/** Decide whether a boolean field's draft value should be emitted (vs.\n * omitted so a downstream default applies). */\nfunction shouldEmitBoolean(state: EditState, key: string, field: FieldSpec): boolean {\n return ownFlag(state.boolOriginallyPresent, key) || ownFlag(state.boolTouched, key) || Boolean(field.required);\n}\n\n/** Convert a scalar draft slot to its persisted form. `undefined` = omit. */\nfunction scalarDraftToValue(raw: string | undefined, fieldType: FieldType): unknown {\n if (raw === undefined || raw === \"\") return undefined;\n if (fieldType === \"number\" || fieldType === \"money\") {\n const num = Number(raw);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\n/** Convert one table row draft to its persisted record. */\nfunction rowDraftToRecord(rowDraft: TableRowDraft, subFields: Record<string, FieldSpec>): Record<string, unknown> {\n const row: Record<string, unknown> = {};\n for (const [subKey, subField] of Object.entries(subFields)) {\n if (subField.type === \"boolean\") {\n const value = ownFlag(rowDraft.bool, subKey);\n if (ownFlag(rowDraft.boolOriginallyPresent, subKey) || ownFlag(rowDraft.boolTouched, subKey) || value || subField.required) row[subKey] = value;\n continue;\n }\n const value = scalarDraftToValue(rowDraft.text[subKey], subField.type);\n if (value !== undefined) row[subKey] = value;\n }\n return row;\n}\n\n/** Convert a full edit draft to the record to persist.\n *\n * Collected as entries rather than assigned into an accumulator: a field may\n * be named `__proto__` (JSON.parse hands that over as an own key, so it\n * reaches here like any other), and `record[key] = value` would run the\n * prototype setter for that one name — the user's value would vanish between\n * the form and the save, with nothing to see. `fromEntries` defines an own\n * property whatever the name is. The read side of this file already guards the\n * same hazard with `ownFlag` (Codex review on #2910). */\nexport function draftToRecord(state: EditState, schema: CollectionSchema): CollectionItem {\n const entries: [string, unknown][] = [];\n for (const [key, field] of Object.entries(schema.fields)) {\n if (COMPUTED_TYPES.has(field.type)) continue; // never persisted (toggle projects an enum field)\n if (field.type === \"boolean\") {\n if (shouldEmitBoolean(state, key, field)) entries.push([key, ownFlag(state.bool, key)]);\n continue;\n }\n if (field.type === \"table\" && field.of) {\n const subFields = field.of;\n entries.push([key, (state.table[key] ?? []).map((rowDraft) => rowDraftToRecord(rowDraft, subFields))]);\n continue;\n }\n const value = scalarDraftToValue(state.text[key], field.type);\n if (value !== undefined) entries.push([key, value]);\n }\n return Object.fromEntries(entries);\n}\n\n/** Normalise a raw inline-edit input (table-cell checkbox/select) to its\n * persisted form. Mirrors `draftToRecord`'s boolean strictness; an empty\n * enum selection (the placeholder option) clears the field via `undefined`. */\nexport function coerceInlineValue(field: FieldSpec, raw: boolean | string): unknown {\n if (field.type === \"boolean\") return raw === true;\n return raw === \"\" ? undefined : raw;\n}\n\n/** Build the full record to PUT for a single-cell inline edit, without\n * mutating `item`. A `undefined` value omits the key (enum cleared),\n * matching `draftToRecord`'s omission semantics. */\nexport function buildUpdatedRecord(item: CollectionItem, key: string, value: unknown): CollectionItem {\n if (value === undefined) {\n const { [key]: __omit, ...rest } = item;\n return rest;\n }\n return { ...item, [key]: value };\n}\n\n/** Empty for required-field validation — NOT a truthiness check (a\n * numeric `0` is a filled value). */\nfunction isMissingDraftValue(value: unknown): boolean {\n return value === undefined || value === null || value === \"\";\n}\n\n/** Label of the first required table sub-field empty in any row, else null. */\nfunction firstMissingTableSubField(field: FieldSpec, rows: TableRowDraft[] | undefined): string | null {\n if (field.type !== \"table\" || !rows) return null;\n for (const [rowIdx, row] of rows.entries()) {\n for (const [subKey, subField] of Object.entries(field.of)) {\n if (!subField.required || subField.type === \"boolean\") continue;\n if (isMissingDraftValue(row.text[subKey])) return `${field.label} #${rowIdx + 1}: ${subField.label}`;\n }\n }\n return null;\n}\n\n/** Field types the required check never flags: booleans always hold a\n * value, and the computed/projected kinds (COMPUTED_TYPES — the shared\n * set, so a future computed type can't drift past this check) have no\n * draft input at all. */\nconst NEVER_MISSING_TYPES: ReadonlySet<FieldType> = new Set<FieldType>([\"boolean\", ...COMPUTED_TYPES]);\n\nfunction validateOneField(key: string, field: FieldSpec, draft: EditState, record: CollectionItem): string | null {\n // A `when`-hidden field has no input the user can fill — never missing.\n if (!fieldVisible(field, record)) return null;\n if (field.type === \"table\" && field.of) {\n const rows = draft.table[key];\n if (field.required && (!rows || rows.length === 0)) return field.label;\n return firstMissingTableSubField(field, rows);\n }\n if (!field.required) return null;\n if (draft.mode === \"create\" && field.primary === true) return null; // server auto-generates id\n if (NEVER_MISSING_TYPES.has(field.type)) return null;\n return isMissingDraftValue(draft.text[key]) ? field.label : null;\n}\n\n/** Human-readable label of the first missing required field, or null. */\nexport function firstMissingRequiredField(draft: EditState, schema: CollectionSchema): string | null {\n const record = draftToRecord(draft, schema);\n for (const [key, field] of Object.entries(schema.fields)) {\n const missing = validateOneField(key, field, draft, record);\n if (missing) return missing;\n }\n return null;\n}\n","// Whether a custom view's `__MC_VIEW.startChat` RUNS the prompt or leaves it as\n// an editable draft (#3062). Pure + its own module so the one reading of the\n// declaration is shared by every surface that renders a view, and is pinned by\n// unit tests rather than by driving an iframe.\n\nimport type { CollectionCustomView } from \"./schema\";\n\n/** True when this view's `startChat` should send. Default-deny: a view that does\n * not declare `allowSendChat` drafts, so upgrading the host can never turn an\n * already-shipped view's buttons into unreviewed agent turns.\n *\n * Read from the SCHEMA — never from the message the iframe posts up. The view's\n * code composes the prompt text; letting it also decide whether that text runs\n * would put both halves of the decision inside the sandbox.\n *\n * EVERY surface honours this declaration, the phone included. The phone once\n * always sent, on the grounds that it has no Enter key to press — but that made\n * the same view behave differently depending on where it was opened, and it\n * silently overrode default-deny on a device the author never tested.\n *\n * The phone does not call THIS function: it reads `allowSendChat` out of the\n * collection schema it already receives (`toDetail` sends the schema whole) and\n * applies the same `=== true` rule in its own copy. Two reasons for that copy\n * have been written down and both were wrong, so this states none — if you are\n * touching it, check whether the phone can import this subpath and delete the\n * copy if it can. Until then, keep the two in step.\n *\n * It must also ask about the view whose document is RENDERED, not the selected\n * one — during a view switch those differ, and the selected view's flag would\n * decide for the previous view's still-running sandbox. */\nexport function customViewSendsChat(view: Pick<CollectionCustomView, \"allowSendChat\">): boolean {\n return view.allowSendChat === true;\n}\n","// The slash-command chat seed a collection view sends to the agent when the\n// user starts a chat from a skill-backed collection or one of its records.\n// Skill-backed collections have a `/<slug>` command, so seed that. (Feeds are\n// skill-less and seeded differently; that branch stays in the view because it\n// is i18n-driven.)\n\n/** `/<slug> <message>`, or `/<slug> id=<itemId> <message>` when a specific\n * record is addressed. The `id=` selector goes BEFORE the free-text message so\n * the skill's argument parser reads it as a flag rather than as prose. */\nexport function skillCommandSeed(slug: string, message: string, itemId?: string): string {\n return itemId ? `/${slug} id=${itemId} ${message}` : `/${slug} ${message}`;\n}\n","// The one place an index row becomes the `{slug,title,icon,color}` a pinned\n// shortcut reconciles against.\n//\n// Both the collections index and the feeds index did this inline, and the\n// awkward part is identical in each: `color` must be ADDED only when there is\n// one, never assigned as `undefined` — the shortcut shapes declare it narrow\n// (see `CollectionSummary.color`) because the remote-host handlers pass them\n// through `Jsonify`, which drops `undefined` from a member union. Writing that\n// out twice is how the two copies drift.\n\nimport type { CollectionShortcutInfo } from \"./uiTypes\";\n\n/** The fields an index row supplies. Both `CollectionSummary` and\n * `FeedSummary` satisfy it; `icon` is optional because a feed row may carry\n * an empty one and rely on the surface's default. */\nexport interface ShortcutInfoSource {\n slug: string;\n title: string;\n icon?: string | undefined;\n color?: string | undefined;\n}\n\n/** An index row as shortcut-reconcile input. `fallbackIcon` stands in when the\n * row names no icon (feeds do this); `color` is omitted entirely rather than\n * set to `undefined` when the row has none. */\nexport function toShortcutInfo(row: ShortcutInfoSource, fallbackIcon: string): CollectionShortcutInfo {\n return {\n slug: row.slug,\n title: row.title,\n icon: row.icon && row.icon.length > 0 ? row.icon : fallbackIcon,\n ...(row.color === undefined ? {} : { color: row.color }),\n };\n}\n","// Sorting for the collection list table. The header sort toggle (next to\n// each field title) cycles a single active column through none → asc →\n// desc → none; this module turns that state plus a per-field value\n// extractor into an ordered copy of the rows.\n//\n// Two invariants the comparator guarantees:\n// 1. Rows with an empty/missing value for the sorted field always sink\n// to the bottom, regardless of direction.\n// 2. Ties (and the empty group) keep their original order — the sort is\n// stable via the captured source index.\n//\n// Field-type → comparable mapping (see `isSortableField`):\n// string/text/email → string · number/money → numeric ·\n// date/datetime → epoch-ms · enum → declared-index · boolean/toggle/flag →\n// false<true · ref → display label · derived → its display type.\n// markdown/table/image/file/embed get no sort button.\n\nimport { fieldTextOrNull } from \"./fieldText\";\nimport type { CollectionItem, CollectionFieldSpec, CollectionFieldType } from \"./schema\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface SortState {\n /** Field key of the single active sort column. */\n field: string;\n direction: SortDirection;\n}\n\n/** A row's comparable value for the active field. Exactly one of `num` /\n * `str` is set when not empty; `empty` rows always sort last. */\nexport interface SortValue {\n empty: boolean;\n num?: number;\n str?: string;\n}\n\nconst EMPTY: SortValue = { empty: true };\n\n/** Field types that render no value text in the table, so offer no sort. */\nconst NON_SORTABLE: ReadonlySet<CollectionFieldType> = new Set<CollectionFieldType>([\"markdown\", \"table\", \"image\", \"file\", \"embed\", \"backlinks\", \"rollup\"]);\n\nexport function isSortableField(field: CollectionFieldSpec): boolean {\n return !NON_SORTABLE.has(field.type);\n}\n\n/** Cycle one column's state: none → asc → desc → none. */\nexport function nextSortDirection(current: SortDirection | null): SortDirection | null {\n if (current === null) return \"asc\";\n if (current === \"asc\") return \"desc\";\n return null;\n}\n\n// ── SortValue constructors (one per comparable kind) ────────────────\n\nexport function numericSortValue(raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const num = typeof raw === \"number\" ? raw : Number(raw);\n return Number.isFinite(num) ? { empty: false, num } : EMPTY;\n}\n\nexport function stringSortValue(raw: unknown): SortValue {\n // An array/object has no sort key — treat it as empty (sorts last) instead of\n // grouping every such record together under \"[object Object]\".\n const str = fieldTextOrNull(raw);\n if (str === null) return EMPTY;\n return str.trim() === \"\" ? EMPTY : { empty: false, str };\n}\n\nexport function dateSortValue(raw: unknown): SortValue {\n const text = fieldTextOrNull(raw);\n if (text === null || text === \"\") return EMPTY;\n const epoch = Date.parse(text);\n // Unparseable dates fall back to a lexical compare rather than vanishing.\n return Number.isNaN(epoch) ? stringSortValue(raw) : { empty: false, num: epoch };\n}\n\n/** Enum sorts by the value's index in the declared `values` list. A value\n * outside the list (or unset) is treated as empty → last. */\nexport function enumSortValue(values: readonly string[] | undefined, raw: unknown): SortValue {\n const text = fieldTextOrNull(raw);\n if (text === null || text === \"\") return EMPTY;\n const idx = values ? values.indexOf(text) : -1;\n return idx < 0 ? EMPTY : { empty: false, num: idx };\n}\n\n/** Boolean / toggle: false < true, never empty (unset reads as false). */\nexport function boolSortValue(checked: boolean): SortValue {\n return { empty: false, num: checked ? 1 : 0 };\n}\n\n// ── Comparator + driver ─────────────────────────────────────────────\n\nexport function compareSortValues(left: SortValue, right: SortValue): number {\n if (left.num !== undefined && right.num !== undefined) return left.num - right.num;\n const leftStr = left.str ?? String(left.num ?? \"\");\n const rightStr = right.str ?? String(right.num ?? \"\");\n return leftStr.localeCompare(rightStr);\n}\n\n/** Stable sort of `items` by `valueOf`. Empties always last; ties hold\n * source order. Returns a new array (does not mutate `items`). */\nexport function sortItems(items: readonly CollectionItem[], direction: SortDirection, valueOf: (item: CollectionItem) => SortValue): CollectionItem[] {\n const dir = direction === \"asc\" ? 1 : -1;\n return items\n .map((item, index) => ({ item, index, sv: valueOf(item) }))\n .sort((left, right) => {\n if (left.sv.empty || right.sv.empty) {\n if (left.sv.empty && right.sv.empty) return left.index - right.index;\n return left.sv.empty ? 1 : -1;\n }\n const base = compareSortValues(left.sv, right.sv);\n return base !== 0 ? base * dir : left.index - right.index;\n })\n .map((decorated) => decorated.item);\n}\n","// Field-type → comparable value for the collection list-table sort. Splits\n// the header sort's per-row value extraction out of the Vue view so the\n// dispatch (which field type maps to which SortValue constructor) is testable\n// on its own. The comparators live in `./sortItems`; this module only routes.\n//\n// A few field kinds can't be sorted from the raw cell alone — `toggle` and\n// `flag` are projected booleans, `derived` is a formula, and `ref` sorts by\n// its resolved display label. Those readers live in the view's rendering\n// composable, so they are passed in (dependency injection) rather than\n// imported, keeping this module pure and framework-free.\n\nimport { numericSortValue, stringSortValue, dateSortValue, enumSortValue, boolSortValue, type SortValue } from \"./sortItems\";\nimport type { CollectionItem, CollectionFieldSpec as FieldSpec } from \"./schema\";\n\n/** Resolve a `ref` cell to its human display label (target slug + item id). */\nexport type RefDisplayResolver = (targetSlug: string, itemSlug: string) => string;\n\n/** The row readers the view supplies for the field kinds that can't sort off\n * the raw cell value. All come from the rendering composable. */\nexport interface SortValueDeps {\n toggleChecked: (item: CollectionItem, field: FieldSpec) => boolean;\n flagValueOf: (key: string, item: CollectionItem) => boolean;\n evaluateDerived: (field: FieldSpec, key: string, item: CollectionItem) => number | null;\n deriveRecord: (item: CollectionItem) => CollectionItem;\n resolveRefDisplay: RefDisplayResolver;\n}\n\n/** Comparable value for scalar fields that key off the raw cell value. */\nexport function scalarSortValue(field: FieldSpec, raw: unknown, resolveRefDisplay: RefDisplayResolver): SortValue {\n switch (field.type) {\n case \"number\":\n case \"money\":\n return numericSortValue(raw);\n case \"date\":\n case \"datetime\":\n return dateSortValue(raw);\n case \"enum\":\n return enumSortValue(field.values, raw);\n case \"boolean\":\n return boolSortValue(raw === true);\n case \"ref\":\n return field.to && typeof raw === \"string\" && raw ? stringSortValue(resolveRefDisplay(field.to, raw)) : stringSortValue(raw);\n default:\n return stringSortValue(raw);\n }\n}\n\n/** Derived rows sort by their display type: money/number → numeric,\n * date → epoch, anything else → the enriched value as a string. */\nexport function derivedSortValue(\n field: FieldSpec,\n key: string,\n item: CollectionItem,\n deps: Pick<SortValueDeps, \"evaluateDerived\" | \"deriveRecord\">,\n): SortValue {\n const display = field.type === \"derived\" ? field.display : undefined;\n if (display === undefined || display === \"number\" || display === \"money\") {\n return numericSortValue(deps.evaluateDerived(field, key, item));\n }\n const enriched = deps.deriveRecord(item);\n if (display === \"date\") return dateSortValue(enriched[key]);\n return stringSortValue(enriched[key]);\n}\n\n/** Comparable value for one row under the active field. Toggle, flag, and\n * derived need the whole record; every other type keys off the raw cell. */\nexport function sortValueOf(field: FieldSpec, key: string, item: CollectionItem, deps: SortValueDeps): SortValue {\n if (field.type === \"toggle\") return boolSortValue(deps.toggleChecked(item, field));\n if (field.type === \"flag\") return boolSortValue(deps.flagValueOf(key, item));\n if (field.type === \"derived\") return derivedSortValue(field, key, item, deps);\n return scalarSortValue(field, item[key], deps.resolveRefDisplay);\n}\n","// Free-text record matching for the collection list search box. Pure and\n// framework-free so the view's `filteredItems` computed just calls it.\n\nimport { fieldTextOrNull } from \"./fieldText\";\nimport type { CollectionItem } from \"./schema\";\n\n/** Case-insensitive substring match across an item's scalar fields.\n * Object/array-valued fields (table rows, nested records) have no text\n * form (`fieldTextOrNull` → `null`) and are skipped — they don't render as\n * searchable text in the list table.\n *\n * `query` is matched against each cell's lower-cased text but is NOT\n * lower-cased here: callers pass an already-normalised (trimmed +\n * lower-cased) query, so an upper-case `query` intentionally matches\n * nothing. Keeping the normalisation at the call site avoids re-lowering\n * the same query once per row. */\nexport function itemMatchesQuery(item: CollectionItem, query: string): boolean {\n // An empty query matches every record — otherwise a row whose only fields are\n // object/array-valued (no scalar cell reaches `includes(\"\")`) would vanish\n // when the search box is cleared. The list caller already short-circuits the\n // empty case, so this only guards a future caller that doesn't.\n if (query === \"\") return true;\n return Object.values(item).some((value) => {\n const text = fieldTextOrNull(value);\n return text !== null && text.toLowerCase().includes(query);\n });\n}\n","// Composite cell keys for the list table's per-cell state maps, plus the\n// load-time \"which enum cells were empty\" snapshot the inline enum dropdown\n// reads. Pure and framework-free so the view keeps only the reactive refs.\n\nimport { fieldText } from \"./fieldText\";\nimport type { CollectionItem } from \"./schema\";\n\n/** The schema slice `snapshotEmptyEnums` reads — minimal structural shape so\n * both the client and server collection-schema types satisfy it as-is. */\nexport interface EnumSnapshotSchema {\n fields: Record<string, { type: string }>;\n primaryKey: string;\n}\n\n/** Stable key for one cell (`<rowId>:<fieldKey>`) in the per-cell state maps. */\nexport function cellKey(rowId: string, fieldKey: string): string {\n return `${rowId}:${fieldKey}`;\n}\n\n/** A row's stable identity: the primary-key value as text (`\"\"` when the schema\n * has no primary key, or the value is absent). Every per-row / per-cell state\n * map keys off this, and it is the SAME derivation `snapshotEmptyEnums` uses\n * for its record ids (`fieldText`), so `cellKey(rowIdOf(...), field)` and the\n * empty-enum snapshot always agree. A real primary key is a scalar, so this\n * matches its plain string form. */\nexport function rowIdOf(primaryKey: string | undefined, item: CollectionItem): string {\n return primaryKey ? fieldText(item[primaryKey]) : \"\";\n}\n\n/** The set of enum cells that were empty in the freshly-fetched records — the\n * only cells whose inline dropdown offers an empty option. */\nexport function snapshotEmptyEnums(schema: EnumSnapshotSchema, records: CollectionItem[]): Set<string> {\n const empty = new Set<string>();\n const enumKeys = Object.entries(schema.fields)\n .filter(([, field]) => field.type === \"enum\")\n .map(([fieldKey]) => fieldKey);\n if (enumKeys.length === 0) return empty;\n for (const record of records) {\n const recordId = fieldText(record[schema.primaryKey]);\n for (const fieldKey of enumKeys) {\n if (record[fieldKey] == null || record[fieldKey] === \"\") empty.add(cellKey(recordId, fieldKey));\n }\n }\n return empty;\n}\n","// Shared chip/label resolution for the collection calendar surfaces (month\n// grid + day view), so both label a record identically. Pure, type-only\n// dependency on the schema shape.\n\nimport { fieldText } from \"./fieldText\";\nimport type { CollectionItem, CollectionSchema } from \"./schema\";\n\n// Text-like field types that make a sensible human-readable label.\nconst LABEL_FIELD_TYPES = new Set([\"string\", \"text\", \"markdown\", \"email\"]);\n\n/** Which field labels a record: the schema's explicit `displayField`, else the\n * first non-primary text-like field (so a collection without a displayField\n * shows e.g. the title rather than the opaque primaryKey), else null → the\n * caller falls back to the primary-key value. */\nexport function labelFieldFor(schema: CollectionSchema): string | null {\n if (schema.displayField) return schema.displayField;\n for (const [key, spec] of Object.entries(schema.fields)) {\n if (key !== schema.primaryKey && LABEL_FIELD_TYPES.has(spec.type)) return key;\n }\n return null;\n}\n\n/** A record's primary-key value as a string. */\nexport function itemIdOf(item: CollectionItem, schema: CollectionSchema): string {\n return fieldText(item[schema.primaryKey]);\n}\n\n/** A record's display label: the resolved `labelField` value, else the\n * primary key. Pass the result of `labelFieldFor(schema)` as `labelField`\n * (compute it once per render rather than per item). */\nexport function itemLabelOf(item: CollectionItem, schema: CollectionSchema, labelField: string | null): string {\n if (labelField) {\n const value = item[labelField];\n // Accept any primitive (string / number / boolean) so a numeric or boolean\n // display field still labels the record; objects/arrays fall through to the\n // id rather than rendering as \"[object Object]\".\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n const text = String(value);\n if (text.length > 0) return text;\n }\n }\n return itemIdOf(item, schema);\n}\n","// Pure builder for the workspace ontology graph — the `/collections` Map\n// panel (phase 2 of plans/done/collection-ontology.md step ①; plan:\n// plans/done/feat-collection-ontology-graph.md). Consumes the per-collection\n// ontology entries `buildWorkspaceOntology` derives server-side and turns\n// them into a node/edge structure a graph view can render directly.\n// Browser-safe (no `node:*` imports) so the Vue plugin builds the same\n// graph from the raw entries — same parity discipline as `deriveAll` and\n// the sibling `wiki/graph.ts`.\n\n/** One relationship a schema declares: a `ref` (the record stores the\n * target's primaryKey slug) or `embed` (display-only pull) pointing at\n * collection `to`, or `backlinks` / `rollup` (display-only REVERSE\n * refs — `to` is the relation's source collection, i.e. its `from`,\n * and `via` names the exact ref field there being reversed).\n * A `ref` column inside a `table` field is reported with a dotted path\n * (`lines.clientId`). Whether `to` exists is NOT checked — resolution\n * is fail-soft at render. */\nexport interface OntologyRelation {\n field: string;\n kind: \"ref\" | \"embed\" | \"backlinks\" | \"rollup\";\n to: string;\n via?: string;\n}\n\nexport interface CollectionOntologyEntry {\n slug: string;\n title: string;\n icon: string;\n primaryKey: string;\n /** The effective display field: the schema's `displayField`, falling\n * back to the primaryKey exactly as render-time labelling does. */\n displayField: string;\n /** Records in the collection, or `null` when the backend couldn't be\n * reached to count them (an engine that failed to load, a closed\n * session). Deliberately not 0: an unreachable collection reported as\n * empty invites \"restoring\" data that is intact but out of reach. */\n recordCount: number | null;\n relations: OntologyRelation[];\n}\n\nexport interface OntologyGraphNode {\n slug: string;\n title: string;\n icon: string;\n recordCount: number | null;\n /** No discovered collection has this slug — the node exists only\n * because a relation points at it. Rendered as a ghost so the graph\n * doubles as a broken-ref lint surface (lint, not lock). */\n missing?: boolean;\n}\n\nexport interface OntologyGraphEdge {\n /** Tail: the collection whose records store (`ref`) or pull (`embed`)\n * the link — or, for an uncollapsed reverse relation, the collection\n * whose refs the `backlinks`/`rollup` field aggregates. */\n from: string;\n /** Head: the collection the link points at. */\n to: string;\n /** Field declaring the relation — on `from` for `ref`/`embed`, on\n * `to` for an uncollapsed `backlinks`/`rollup`. */\n field: string;\n kind: OntologyRelation[\"kind\"];\n /** `backlinks`/`rollup` field names on `to` that declare the reverse\n * of this `ref` edge, collapsed here so one link never draws twice. */\n reverseFields?: string[];\n}\n\nexport interface OntologyGraph {\n nodes: OntologyGraphNode[];\n edges: OntologyGraphEdge[];\n}\n\nconst isForwardKind = (kind: OntologyRelation[\"kind\"]): boolean => kind === \"ref\" || kind === \"embed\";\n\n/** Fold a reverse relation (`backlinks`/`rollup` declared on `owner`)\n * into the edge list: collapse onto the forward `ref` edge whose field\n * is the relation's declared `via` (several refs can link the same\n * pair — matches.homeTeam vs matches.awayTeam — so the pair alone is\n * ambiguous), else emit its own edge oriented in true data direction\n * (refs' source → owner). A `via` naming no forward edge stays\n * uncollapsed — fail-soft, like every other dangling reference. */\nconst addReverseRelation = (edges: OntologyGraphEdge[], owner: string, rel: OntologyRelation): void => {\n const forward = edges.find((edge) => edge.kind === \"ref\" && edge.from === rel.to && edge.to === owner && (rel.via === undefined || edge.field === rel.via));\n if (forward) {\n forward.reverseFields = [...(forward.reverseFields ?? []), rel.field];\n return;\n }\n edges.push({ from: rel.to, to: owner, field: rel.field, kind: rel.kind });\n};\n\n/** Two passes so every forward `ref` edge exists before any reverse\n * relation tries to collapse onto one — entry order must not matter. */\nconst collectEdges = (entries: CollectionOntologyEntry[]): OntologyGraphEdge[] => {\n const edges: OntologyGraphEdge[] = [];\n for (const entry of entries) {\n for (const rel of entry.relations) {\n if (isForwardKind(rel.kind)) edges.push({ from: entry.slug, to: rel.to, field: rel.field, kind: rel.kind });\n }\n }\n for (const entry of entries) {\n for (const rel of entry.relations) {\n if (!isForwardKind(rel.kind)) addReverseRelation(edges, entry.slug, rel);\n }\n }\n return edges;\n};\n\n/** Slugs referenced by an edge endpoint but backed by no discovered\n * collection, slug-sorted for deterministic node order. */\nconst ghostSlugs = (edges: OntologyGraphEdge[], known: ReadonlySet<string>): string[] => {\n const ghosts = new Set<string>();\n for (const edge of edges) {\n if (!known.has(edge.from)) ghosts.add(edge.from);\n if (!known.has(edge.to)) ghosts.add(edge.to);\n }\n return [...ghosts].sort();\n};\n\n/** Build the renderable graph: one node per discovered collection (in\n * the entries' slug-sorted order) plus ghost nodes for dangling\n * targets, one edge per underlying link. */\nexport const buildOntologyGraph = (entries: CollectionOntologyEntry[]): OntologyGraph => {\n const edges = collectEdges(entries);\n const known = new Set(entries.map((entry) => entry.slug));\n const nodes: OntologyGraphNode[] = entries.map(({ slug, title, icon, recordCount }) => ({ slug, title, icon, recordCount }));\n for (const slug of ghostSlugs(edges, known)) {\n // A ghost node has no collection behind it at all, so it genuinely holds\n // no records — 0, not the \"couldn't count\" null.\n nodes.push({ slug, title: slug, icon: \"\", recordCount: 0, missing: true });\n }\n return { nodes, edges };\n};\n"],"mappings":"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"}
@@ -4,9 +4,9 @@ const require_dist = require("../../../dist-Gj7ygaW2.cjs");
4
4
  const require_root = require("../../../root-BvwBUcol.cjs");
5
5
  const require_relPath = require("../../../relPath-CTAjGdCL.cjs");
6
6
  const require_utils_fetch = require("../../../utils/fetch.cjs");
7
- const require_discovery = require("../../../discovery-CDXYswtw.cjs");
7
+ const require_discovery = require("../../../discovery-B79IxEM6.cjs");
8
8
  const require_templatePath = require("../../../templatePath-27vUZowm.cjs");
9
- const require_server = require("../../../server-DfYwSX8b.cjs");
9
+ const require_server = require("../../../server-BUbU9G-J.cjs");
10
10
  const require_skill_bridge_index = require("../../../skill-bridge/index.cjs");
11
11
  const require_types = require("../../../types-CNqkLT4M.cjs");
12
12
  let node_fs = require("node:fs");
@@ -2,9 +2,9 @@ import { l as isUnknownArray, t as errorMessage } from "../../../dist-BzoA9pDR.j
2
2
  import { n as writeFileAtomic } from "../../../root-BcS4-Kge.js";
3
3
  import { n as toPosixRelPath } from "../../../relPath-DW8MC8VO.js";
4
4
  import { fetchWithTimeout } from "../../../utils/fetch.js";
5
- import { K as safeRecordId, et as collectionsRegistriesConfigPath, ht as skillsStagingDir, lt as projectSkillsDir, r as loadCollection, rt as getWorkspaceRoot, s as CollectionSchemaZ, st as log, t as acceptParsedSchema } from "../../../discovery-B_64PBZU.js";
5
+ import { K as safeRecordId, et as collectionsRegistriesConfigPath, ht as skillsStagingDir, lt as projectSkillsDir, r as loadCollection, rt as getWorkspaceRoot, s as CollectionSchemaZ, st as log, t as acceptParsedSchema } from "../../../discovery-DIGau7M8.js";
6
6
  import { t as isSafeActionTemplatePath } from "../../../templatePath-k_WNbL_Q.js";
7
- import { y as ONE_SECOND_MS } from "../../../server-7POrhHKv.js";
7
+ import { y as ONE_SECOND_MS } from "../../../server-DZ7Cq7s_.js";
8
8
  import { claudeSkillDir, dataSkillDir, mirrorSkillWrite } from "../../../skill-bridge/index.js";
9
9
  import { n as parseRegistryIndex, r as isRecord, t as OFFICIAL_REGISTRY_NAME } from "../../../types-BKVZrtyc.js";
10
10
  import { readFileSync } from "node:fs";
@@ -38,6 +38,16 @@ export interface FirestoreDocs {
38
38
  watch: (collectionPath: string, onChanged: (ids: string[], meta: {
39
39
  initial: boolean;
40
40
  }) => void, onError: (error: unknown) => void) => () => void;
41
+ /** Firestore's own instant, for a field the store must hand back as the type
42
+ * it was stored as.
43
+ *
44
+ * Here rather than in the store because this is the seam that owns the SDK:
45
+ * `firebase` is an OPTIONAL peer, and the store is reachable from
46
+ * `collection/server` (the factory registry in `store.ts` names it), so a
47
+ * top-level `import { Timestamp }` there makes the peer required for every
48
+ * consumer of that entry — including hosts with no Firestore at all. Typed
49
+ * `unknown` so no SDK type crosses back out. */
50
+ timestamp: (seconds: number, nanoseconds: number) => unknown;
41
51
  }
42
52
  /** The real implementation over the modular SDK.
43
53
  *
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_root = require("../../root-BvwBUcol.cjs");
3
3
  const require_itemId = require("../../itemId-CGT2J7YK.cjs");
4
- const require_discovery = require("../../discovery-CDXYswtw.cjs");
4
+ const require_discovery = require("../../discovery-B79IxEM6.cjs");
5
5
  const require_templatePath = require("../../templatePath-27vUZowm.cjs");
6
- const require_server = require("../../server-DfYwSX8b.cjs");
6
+ const require_server = require("../../server-BUbU9G-J.cjs");
7
7
  exports.APP_MANIFEST_FILE = require_discovery.APP_MANIFEST_FILE;
8
8
  exports.BackendUnavailableError = require_discovery.BackendUnavailableError;
9
9
  exports.COLLECTION_ROOT_REQUIRED = require_discovery.COLLECTION_ROOT_REQUIRED;
@@ -1,6 +1,6 @@
1
1
  import { t as canonicalRoot } from "../../root-BcS4-Kge.js";
2
2
  import { U as COMPUTED_TYPES } from "../../itemId-4P9S_ehz.js";
3
- import { $ as collectionChangePayload, A as readItem, B as SCHEMA_FILE, C as CollectionQueryZ, D as generateItemId, E as deleteItem, F as loadAppManifest, G as resolveTemplatePath, H as isUnderRealRoot, I as parseAppManifest, J as BackendUnavailableError, K as safeRecordId, L as sharedItemsPath, M as writeItem, N as APP_MANIFEST_FILE, O as isRegularFile, P as appManifestReason, Q as collectionChangeKey, R as pageFromFullRead, S as compileJsonlQuery, T as MAX_QUERY_ROWS, U as itemFilePath, V as isContainedInRoot, W as resolveDataDir, X as COLLECTION_ROOT_REQUIRED, Y as isBackendUnavailable, _ as dedupeByRecordId, a as toDetail, ct as peekWorkspaceRoot, d as storeFor, dt as setCollectionChangePublisher, ft as setFirestoreAccessor, g as decodeCsvRecordId, h as csvRowToItem, i as resolvePrimaryField, it as hostSupportsSharedCollections, j as resolveCreateItemId, k as listItems, l as collectionWritable, mt as sharedCollectionChangePayload, n as discoverCollections, nt as firestoreHandle, o as toSummary, ot as localCollectionKey, p as MAX_CSV_ROWS, pt as setSharedCollectionsSupport, q as safeSlugName, r as loadCollection, rt as getWorkspaceRoot, s as CollectionSchemaZ, st as log, t as acceptParsedSchema, tt as configureCollectionHost, u as readOnlyRefusal, ut as publishCollectionChange, v as encodeCsvRecordId, w as DEFAULT_QUERY_ROWS, x as compileCsvQuery, y as normalizeCsvValue, z as projectItemFields } from "../../discovery-B_64PBZU.js";
3
+ import { $ as collectionChangePayload, A as readItem, B as SCHEMA_FILE, C as CollectionQueryZ, D as generateItemId, E as deleteItem, F as loadAppManifest, G as resolveTemplatePath, H as isUnderRealRoot, I as parseAppManifest, J as BackendUnavailableError, K as safeRecordId, L as sharedItemsPath, M as writeItem, N as APP_MANIFEST_FILE, O as isRegularFile, P as appManifestReason, Q as collectionChangeKey, R as pageFromFullRead, S as compileJsonlQuery, T as MAX_QUERY_ROWS, U as itemFilePath, V as isContainedInRoot, W as resolveDataDir, X as COLLECTION_ROOT_REQUIRED, Y as isBackendUnavailable, _ as dedupeByRecordId, a as toDetail, ct as peekWorkspaceRoot, d as storeFor, dt as setCollectionChangePublisher, ft as setFirestoreAccessor, g as decodeCsvRecordId, h as csvRowToItem, i as resolvePrimaryField, it as hostSupportsSharedCollections, j as resolveCreateItemId, k as listItems, l as collectionWritable, mt as sharedCollectionChangePayload, n as discoverCollections, nt as firestoreHandle, o as toSummary, ot as localCollectionKey, p as MAX_CSV_ROWS, pt as setSharedCollectionsSupport, q as safeSlugName, r as loadCollection, rt as getWorkspaceRoot, s as CollectionSchemaZ, st as log, t as acceptParsedSchema, tt as configureCollectionHost, u as readOnlyRefusal, ut as publishCollectionChange, v as encodeCsvRecordId, w as DEFAULT_QUERY_ROWS, x as compileCsvQuery, y as normalizeCsvValue, z as projectItemFields } from "../../discovery-DIGau7M8.js";
4
4
  import { i as isSafeTemplatePath, n as isSafeCustomViewI18nPath, r as isSafeCustomViewPath, t as isSafeActionTemplatePath } from "../../templatePath-k_WNbL_Q.js";
5
- import { A as recordFieldProblem, B as stagedSkillDir, C as applyMutateAction, D as validateCollectionRecords, E as STORE_UNREADABLE, F as buildCollectionActionSeedPrompt, I as promptPathsFor, L as readCustomViewHtml, M as enrichItems, N as runQueryOverRows, O as validateRecordObject, P as buildActionSeedPrompt, R as readCustomViewI18n, S as schemaRelations, T as MAX_RECORD_ISSUES, _ as resolveEvery, a as MAX_UNSELECTIVE_ITEMS, b as computeCollectionIcon, c as deleteCollection, d as computeSuccessor, f as daysInMonth, g as parseCivil, h as maybeSpawnSuccessor, i as MAX_SCHEMA_ISSUES, j as runCollectionQuery, k as compileRecordZ, l as deleteCollectionRefusalMessage, m as isTriggerDue, n as MAX_PUT_ITEMS, o as makeManageCollectionTool, p as formatCivil, r as MAX_PUT_LINT, s as deleteCustomView, t as MAX_ITEMS_FILE_BYTES, u as advanceTriggerDate, v as successorId, w as firstMutateParamProblem, x as buildWorkspaceOntology, z as readSkillTemplate } from "../../server-7POrhHKv.js";
5
+ import { A as recordFieldProblem, B as stagedSkillDir, C as applyMutateAction, D as validateCollectionRecords, E as STORE_UNREADABLE, F as buildCollectionActionSeedPrompt, I as promptPathsFor, L as readCustomViewHtml, M as enrichItems, N as runQueryOverRows, O as validateRecordObject, P as buildActionSeedPrompt, R as readCustomViewI18n, S as schemaRelations, T as MAX_RECORD_ISSUES, _ as resolveEvery, a as MAX_UNSELECTIVE_ITEMS, b as computeCollectionIcon, c as deleteCollection, d as computeSuccessor, f as daysInMonth, g as parseCivil, h as maybeSpawnSuccessor, i as MAX_SCHEMA_ISSUES, j as runCollectionQuery, k as compileRecordZ, l as deleteCollectionRefusalMessage, m as isTriggerDue, n as MAX_PUT_ITEMS, o as makeManageCollectionTool, p as formatCivil, r as MAX_PUT_LINT, s as deleteCustomView, t as MAX_ITEMS_FILE_BYTES, u as advanceTriggerDate, v as successorId, w as firstMutateParamProblem, x as buildWorkspaceOntology, z as readSkillTemplate } from "../../server-DZ7Cq7s_.js";
6
6
  export { APP_MANIFEST_FILE, BackendUnavailableError, COLLECTION_ROOT_REQUIRED, COMPUTED_TYPES, CollectionQueryZ, CollectionSchemaZ, DEFAULT_QUERY_ROWS, MAX_CSV_ROWS, MAX_ITEMS_FILE_BYTES, MAX_PUT_ITEMS, MAX_PUT_LINT, MAX_QUERY_ROWS, MAX_RECORD_ISSUES, MAX_SCHEMA_ISSUES, MAX_UNSELECTIVE_ITEMS, SCHEMA_FILE, STORE_UNREADABLE, acceptParsedSchema, advanceTriggerDate, appManifestReason, applyMutateAction, buildActionSeedPrompt, buildCollectionActionSeedPrompt, buildWorkspaceOntology, canonicalRoot, collectionChangeKey, collectionChangePayload, collectionWritable, compileCsvQuery, compileJsonlQuery, compileRecordZ, computeCollectionIcon, computeSuccessor, configureCollectionHost, csvRowToItem, daysInMonth, decodeCsvRecordId, dedupeByRecordId, deleteCollection, deleteCollectionRefusalMessage, deleteCustomView, deleteItem, discoverCollections, encodeCsvRecordId, enrichItems, firestoreHandle, firstMutateParamProblem, formatCivil, generateItemId, getWorkspaceRoot, hostSupportsSharedCollections, isBackendUnavailable, isContainedInRoot, isRegularFile, isSafeActionTemplatePath, isSafeCustomViewI18nPath, isSafeCustomViewPath, isSafeTemplatePath, isTriggerDue, isUnderRealRoot, itemFilePath, listItems, loadAppManifest, loadCollection, localCollectionKey, log, makeManageCollectionTool, maybeSpawnSuccessor, normalizeCsvValue, pageFromFullRead, parseAppManifest, parseCivil, peekWorkspaceRoot, projectItemFields, promptPathsFor, publishCollectionChange, readCustomViewHtml, readCustomViewI18n, readItem, readOnlyRefusal, readSkillTemplate, recordFieldProblem, resolveCreateItemId, resolveDataDir, resolveEvery, resolvePrimaryField, resolveTemplatePath, runCollectionQuery, runQueryOverRows, safeRecordId, safeSlugName, schemaRelations, setCollectionChangePublisher, setFirestoreAccessor, setSharedCollectionsSupport, sharedCollectionChangePayload, sharedItemsPath, stagedSkillDir, storeFor, successorId, toDetail, toSummary, validateCollectionRecords, validateRecordObject, writeItem };
@@ -3,8 +3,8 @@ const require_root = require("../root-BvwBUcol.cjs");
3
3
  const require_itemId = require("../itemId-CGT2J7YK.cjs");
4
4
  const require_promptSafety = require("../promptSafety-caJWd1ZQ.cjs");
5
5
  require("../collection/index.cjs");
6
- const require_discovery = require("../discovery-CDXYswtw.cjs");
7
- const require_server = require("../server-DfYwSX8b.cjs");
6
+ const require_discovery = require("../discovery-B79IxEM6.cjs");
7
+ const require_server = require("../server-BUbU9G-J.cjs");
8
8
  const require_notifier = require("../notifier-B65Mvngb.cjs");
9
9
  let node_fs_promises = require("node:fs/promises");
10
10
  //#region src/collection-watchers/config.ts
@@ -2,8 +2,8 @@ import { t as canonicalRoot } from "../root-BcS4-Kge.js";
2
2
  import { X as fieldText, j as isValidCollectionName } from "../itemId-4P9S_ehz.js";
3
3
  import { E as whenMatches, f as itemIsDone } from "../promptSafety-BpBTh5xO.js";
4
4
  import "../collection/index.js";
5
- import { $ as collectionChangePayload, U as itemFilePath, ct as peekWorkspaceRoot, d as storeFor, mt as sharedCollectionChangePayload, n as discoverCollections, nt as firestoreHandle, r as loadCollection, ut as publishCollectionChange } from "../discovery-B_64PBZU.js";
6
- import { h as maybeSpawnSuccessor, m as isTriggerDue } from "../server-7POrhHKv.js";
5
+ import { $ as collectionChangePayload, U as itemFilePath, ct as peekWorkspaceRoot, d as storeFor, mt as sharedCollectionChangePayload, n as discoverCollections, nt as firestoreHandle, r as loadCollection, ut as publishCollectionChange } from "../discovery-DIGau7M8.js";
6
+ import { h as maybeSpawnSuccessor, m as isTriggerDue } from "../server-DZ7Cq7s_.js";
7
7
  import { d as publish, m as updateForPlugin, n as clear, s as listAll } from "../notifier-vAp5t6wL.js";
8
8
  import { access } from "node:fs/promises";
9
9
  //#region src/collection-watchers/config.ts
@@ -10,7 +10,6 @@ let node_path = require("node:path");
10
10
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
11
11
  let node_crypto = require("node:crypto");
12
12
  let node_fs_promises = require("node:fs/promises");
13
- let firebase_firestore = require("firebase/firestore");
14
13
  let node_os = require("node:os");
15
14
  let iconv_lite = require("iconv-lite");
16
15
  iconv_lite = require_rolldown_runtime.__toESM(iconv_lite, 1);
@@ -556,7 +555,7 @@ async function firestoreWrite(key, itemId, item, schema, opts) {
556
555
  itemId
557
556
  }), async (safeId, { docs, email }) => {
558
557
  const collectionPath = sharedItemsPath(key);
559
- const asTimestamp = (parts) => new firebase_firestore.Timestamp(parts.seconds, parts.nanoseconds);
558
+ const asTimestamp = (parts) => docs.timestamp(parts.seconds, parts.nanoseconds);
560
559
  if (opts.refuseOverwrite) {
561
560
  if (!await guarded(key, email, () => docs.create(collectionPath, safeId, require_itemId.encodeRecordTimes(item, null, asTimestamp)))) return {
562
561
  kind: "conflict",
@@ -3799,4 +3798,4 @@ Object.defineProperty(exports, "writeItem", {
3799
3798
  }
3800
3799
  });
3801
3800
 
3802
- //# sourceMappingURL=discovery-CDXYswtw.cjs.map
3801
+ //# sourceMappingURL=discovery-B79IxEM6.cjs.map