import { a as AggregateOperation, b as AggregateFilter, D as DashboardBlockKind, c as AggregateMeasure, A as AggregateBucket, S as SubscriptionCadence } from './subscription-BRwuydeh.cjs'; import { U as UseCase, a as UseCaseTable, b as UseCaseField, c as UseCaseRow, d as UseCaseForm, e as UseCaseFormField, f as UseCaseNotificationTrigger, N as NotificationChannel, g as UseCaseProvenance } from './types-BkxyKhsg.cjs'; declare const TABLE_KERNEL_ID = "11111111-0000-4000-8000-000000000001"; type ConfidentialLevel = "viewer" | "commenter" | "editor"; interface TemplateConfidentialReader { /** A member / person field of the table whose value names the reader. */ field: string; level: ConfidentialLevel; /** The row's own condition, flat saved-view filter: { "cycle_manager_status": "Submitted" }. */ when?: Record; } interface TemplateConfidential { table: string; readers: TemplateConfidentialReader[]; /** true: the person who installs it is only a reader (the organization owns the table). */ makerIsReader: boolean; /** One sentence for the chair and for Arman: why this table is Confidential. */ why: string; } interface TemplateTableSettings { confidential?: TemplateConfidential[]; membersAddRows?: string[]; } /** One request the chair runs after install (the SQL is the exact call; words are the chair's). */ interface ConfidentialRequest { table: string; tableId: string; readers: Array<{ field: string; level: ConfidentialLevel; when?: Record; }>; makerIsReader: boolean; why: string; /** `select custom.set_table_confidential_arman_explicitly_approved(…)` with `:'arman_words'` left for the chair. */ sql: string; } /** What a spec's confidential / membersAddRows say is wrong, in plain sentences ([] = fine). */ declare function tableSettingsProblems(spec: TemplateSpec & TemplateTableSettings): string[]; /** The plan steps that set members_add_rows (custom.record_change_many on the Table kernel, as the person). */ declare function membersAddRowsSteps(spec: TemplateTableSettings, tableRef: (token: string) => string): { label: string; door: "record_change_many"; args: { p_organization_id: string; p_table_id: string; p_changes: { op: string; record_id: string; patch: { members_add_rows: boolean; }; }[]; }; }[]; /** The chair's requests for one install: table ids from the install answer's `made`. */ declare function confidentialRequests(spec: TemplateTableSettings, made: Array<{ kind: string; ref: string; id: string | null; }>): ConfidentialRequest[]; /** * A reader's `when`, as the store asks it. The flat saved-view map compiles against the row's STORED * document only (custom.record_filter_sql reads r.data), so a lookup — "both sides are submitted", * read through the review cycle — would never be true there. A Rule expression is evaluated over * custom.record_values_of(r), which works lookups and roll-ups out on read; so every condition is * written as a Rule over the installed fields' ids (REC-17: a Rule points at a Field by id). */ declare function whenRule(table: string, when: Record, made: Array<{ kind: string; ref: string; id: string | null; }>): Record; /** True while any of the template's Confidential tables is not Confidential yet (hold its forms). */ declare function confidentialPending(spec: TemplateTableSettings, levels: Record): boolean; /** The schema version of this file format. Bumped only when the SHAPE changes. */ declare const TEMPLATE_SPEC_VERSION: 1; /** * THE RELATIVE-DATE GRAMMAR. A seed date is written relative to the day the template is * installed, so a calendar installed in March shows this week's work, not last year's: * * ANCHOR @today the install day * @mon … @sun that weekday of the install week (weeks start Monday) * @last-mon … @next-sun that weekday of the week before / after * OFFSET +3d -2w +1m -1y days / weeks / months / years (N ≤ 9999) * +2b -5b BUSINESS days (Monday–Friday): never lands on a weekend * SNAP ~b if the result is a Saturday or Sunday, move to Monday * TIME " 09:30" a moment that day, 24-hour local time in the business's * zone, written out with its offset * * "@today-3b 08:30" "@today~b 10:00" "@next-tue" "@mon+1d 14:00" * * Closed: anything else in a date field is an absolute date, which only a field flagged * `absoluteDates` (a date of birth) may hold. `resolveRelativeDates` (./validate) turns * every token into the store's own date or moment text. * * Groups: 1 anchor, 2 sign, 3 count, 4 unit, 5 snap, 6 hour, 7 minute. */ declare const RELATIVE_DATE: RegExp; /** * BUTTON-STAMPS: the words a row-action step (and a row template) may carry for "the moment of use". "@now" on a date / * datetime column is the instant of the press in the organization's day zone; "@me" on a person column is whoever * presses. The day words above ("@today", "@today+3d", "@next-fri") are filled at press time too. The store keeps * the word as written (custom._stamp_token is the one resolver); the memory preview fills them from world.today and * world.user_id. */ declare const STAMP_NOW = "@now"; declare const STAMP_ME = "@me"; /** A day word the press-time resolver knows: "@now" or the template seed-date grammar. */ declare const isPressDayWord: (word: string) => boolean; /** The day the validator resolves relative dates against, so every check is deterministic. */ declare const TEMPLATE_REFERENCE_DATE = "2026-10-05"; /** The 20 industry groups of the catalog (handoff §5 table). The quota per group is in CATALOGUE_QUOTAS. */ declare const INDUSTRY_GROUPS: readonly ["healthcare", "legal_professional", "construction_trades", "real_estate_property", "hospitality_food", "agencies_creative", "field_home_services", "retail_ecommerce", "manufacturing_logistics", "education", "nonprofit_community", "software_it", "fitness_beauty_wellness", "media_creators", "staffing_hr_recruiting", "personal_family", "events_weddings", "automotive", "agriculture_environment", "cross_industry"]; type IndustryGroup = (typeof INDUSTRY_GROUPS)[number]; /** The first 1,000 rows' quota per group (sums to 1,000). G3 enforces it at 1,000 and proportionally before. */ declare const CATALOGUE_QUOTAS: Readonly>; /** The 12 jobs a template does for a business. */ declare const TEMPLATE_JOBS: readonly ["intake", "scheduling", "crm_pipeline", "work_orders", "inventory", "billing", "team_hr", "projects", "content", "compliance_quality", "customer_service", "reporting"]; type TemplateJob = (typeof TEMPLATE_JOBS)[number]; /** The 16 features a template can teach. Each is taught by at least 40 of the first 1,000. */ declare const TEACHES_FEATURES: readonly ["relations_rollups", "dimensions", "kanban", "calendar", "timeline", "gallery", "forms", "bookings", "portals", "dashboards", "drill_down", "agents", "field_governance", "import_upsert", "checklists", "documents_esign"]; type TeachesFeature = (typeof TEACHES_FEATURES)[number]; /** * The five places we beat the champions (ADV-P §4). Each is shown in at least 100 of the first 1,000. * * S1 — governed columns: every column says who sees it and whether AI may read it. * S2 — agents inside the data: an agent works on the table's own records. * S3 — every front door on one table: form, booking, portal, digest, webhook all land in one table. * S4 — a column can point at anything on the platform (entity reference). * S5 — imports and edits cannot lose data: an upsert import that updates and adds, or * archive → Trash → restore, shown in the walk. */ declare const STRENGTHS: readonly ["S1", "S2", "S3", "S4", "S5"]; type Strength = (typeof STRENGTHS)[number]; /** Who installs it: a business, or a person for their own life. */ declare const TEMPLATE_AUDIENCES: readonly ["organization", "individual"]; type TemplateAudience = (typeof TEMPLATE_AUDIENCES)[number]; /** * THE CAPABILITY WORDS a template may `require`. Closed: a word not here is a typo, and a * word the template does not use is refused. Whether each is PROVIDED today is derived by * `capabilityStatus` (./validate) from the store's registry and the records-ui layouts, so a * word flips to provided the day its lane lands, with no edit to this list. */ declare const CAPABILITY_WORDS: readonly ["view.grid", "view.kanban", "view.kanban.swimlanes", "view.calendar", "view.calendar.month", "view.timeline", "view.gallery", "view.map", "view.orgchart", "view.pivot", "field.select", "field.multi_select", "field.datetime", "field.currency", "field.percent", "field.email", "field.phone", "field.url", "field.checkbox", "field.attachment", "field.member", "field.lookup", "field.rollup", "field.formula", "field.entity_reference", "field.signature", "field.rating", "choice.colors", "seed.attachments", "form", "form.question_text", "booking", "portal", "dashboard", "dashboard.multi_table", "drill_down", "dimensions", "digest", "checklist", "document", "document.esign", "notification", "stage_rules", "row_action", "import.upsert", "archive.restore", "agent", "automation"]; type CapabilityWord = (typeof CAPABILITY_WORDS)[number]; /** * The platform kinds an entity_reference column may point at — custom.entity_reference_kinds(), * read on the clone 2026-10-02 (the TEMPLATES lane refreshes it the way it refreshes the agent * snapshot). A word outside it is refused: the store would refuse the column. */ declare const ENTITY_REFERENCE_KINDS: readonly ["agent", "agent_shortcut", "agent_template", "ai_api", "ai_endpoint", "ai_model", "ai_provider", "ai_setting", "anon_form", "app", "assessment", "canvas_comment", "canvas_item", "canvas_score", "category", "code_file", "code_folder", "code_repository", "comparison_set", "contact_submission", "content_ir_kind", "content_ir_kind_instance", "context_item", "conversation", "crm_deal", "crm_outreach_list", "cx_agent_memory", "data_store", "fc_set", "feature_doc", "folder", "game_result", "heatmap_save", "hr_asset", "hr_candidate", "hr_careers_portal", "hr_checklist_template", "hr_course", "hr_crew", "hr_deduction_code", "hr_department", "hr_earning_code", "hr_employee", "hr_holiday_calendar", "hr_interview_kit", "hr_job_title", "hr_jurisdiction", "hr_jurisdiction_rule_class", "hr_leave_policy", "hr_location", "hr_pay_group", "hr_posting", "hr_record_class", "hr_requisition", "hr_schedule", "hr_schedule_template", "hr_survey", "league_membership", "learn_doc", "mandate", "marketing_initiative", "meet_meeting", "message_template", "note", "note_folder", "organization", "page_extraction_job", "party", "pc_article", "pc_episode", "pc_show", "pc_studio_run", "processed_document", "project", "quiz_session", "research_template", "research_topic", "rulebook", "sch_task", "scope_type", "seo_topic", "shared_canvas_item", "skill", "studio_session", "study_goal", "study_media", "study_plan", "study_plan_block", "surface", "task", "thread", "tool", "tool_bundle", "transcript", "udt_document", "user_markdown_sample", "voice", "war_room", "wbx_pattern", "web_analysis_item", "web_brand", "web_provider", "web_site", "workbook", "workflow", "workflow_template", "workflow_trigger", "working_document"]; /** The colors a choice may wear — the palette `display_format.options.choices[].color` holds (design-system STYLE_COLORS). */ declare const CHOICE_COLORS: readonly ["slate", "green", "amber", "red", "blue", "violet", "teal", "orange", "yellow", "pink", "brown", "gray"]; /** The colors a list of choices must use distinct ones of (the original seven; the five added for Notion are extra). */ declare const CHOICE_COLORS_DISTINCT_UP_TO = 7; type ChoiceColor = (typeof CHOICE_COLORS)[number]; /** * TEMPLATE-GAPS R3 (4): NOTION'S COLOR NAMES. Notion's ten (default, gray, brown, orange, yellow, green, blue, * purple, pink, red) and the common spellings land on the grid's own palette; a pack may write either. */ declare const CHOICE_COLOR_ALIASES: { readonly purple: "violet"; readonly grey: "gray"; readonly default: "slate"; readonly lightgray: "slate"; readonly light_gray: "slate"; }; type ChoiceColorAlias = keyof typeof CHOICE_COLOR_ALIASES; /** The palette color a written color means (case-insensitive), or undefined when it is none. */ declare function canonicalChoiceColor(color: unknown): ChoiceColor | undefined; interface SharedBlockField { key: string; label: string; parityType: UseCaseField["parityType"]; sensitivity: UseCaseField["sensitivity"]; contextPolicy: UseCaseField["contextPolicy"]; required?: boolean; /** Labels and keys that mean this field, for the copy check (normalized, lower-case words). */ sameAs: readonly string[]; } interface SharedBlock { /** The table's token in every organization: one table, shared by every template that uses it. */ table: string; name: string; labelSingular: string; labelPlural: string; titleField: string; describes: string; fields: readonly SharedBlockField[]; /** A template table matching this many of the block's fields (by type and meaning) has copied it. */ copyThreshold: number; } /** * THE SHARED BLOCKS. The scope templates carried 26 byte-identical copies of a team-member * block (312 of 846 fields). Now the block is ONE seeded table per organization; a template * lists the block in `sharedBlocks` with the rows it seeds (its own people), and points its * "assigned to" columns at the block's table with an ordinary relation field — so the * column is filled, and no template declares those fields again. */ declare const SHARED_BLOCKS: { readonly team_member: { readonly table: "team_member"; readonly name: "Team"; readonly labelSingular: "Team member"; readonly labelPlural: "Team"; readonly titleField: "full_name"; readonly describes: "The people on the business's own team — who is assigned, who answers, who signs."; readonly fields: readonly [{ readonly key: "full_name"; readonly label: "Name"; readonly parityType: "text"; readonly sensitivity: "internal"; readonly contextPolicy: "include"; readonly required: true; readonly sameAs: readonly ["name", "full name", "employee name", "staff name"]; }, { readonly key: "role"; readonly label: "Role"; readonly parityType: "text"; readonly sensitivity: "internal"; readonly contextPolicy: "include"; readonly sameAs: readonly ["role", "job title", "title", "position"]; }, { readonly key: "work_email"; readonly label: "Work email"; readonly parityType: "email"; readonly sensitivity: "confidential"; readonly contextPolicy: "summarize"; readonly sameAs: readonly ["email", "work email", "email address"]; }, { readonly key: "mobile"; readonly label: "Mobile"; readonly parityType: "phone"; readonly sensitivity: "confidential"; readonly contextPolicy: "exclude"; readonly sameAs: readonly ["phone", "mobile", "work phone", "cell", "phone number"]; }, { readonly key: "start_date"; readonly label: "Start date"; readonly parityType: "datetime"; readonly sensitivity: "internal"; readonly contextPolicy: "include"; readonly sameAs: readonly ["start date", "hire date", "started", "date hired"]; }]; readonly copyThreshold: 3; }; }; type SharedBlockId = keyof typeof SHARED_BLOCKS; declare const SHARED_BLOCK_IDS: SharedBlockId[]; /** One shared block this template uses, with the rows it seeds into the block's table. */ interface SharedBlockUse { block: SharedBlockId; /** Keyed by the block's field keys. Relation fields elsewhere point at these row keys. */ rows: UseCaseRow[]; } interface TemplateField extends UseCaseField { /** Every choice of a select/multi_select wears a color: choice word → color. */ choiceColors?: Record; /** * THE COLUMN'S LOOK ("Shows as", kept on the Field as `display_format`): a plug-in look the * records screens draw — `{ id: "color_pair", options: { contrastWith: {...} } }`, `{ id: "measure", * options: { unit: "px", measurePreview: "spacing" } }`, `type_style`, `shadow`, or any format id in * `custom.display_format_ids()`. A choice's colors (`choiceColors`) win over it. */ look?: { id: string; options?: Record; }; /** For an `entity_reference` field (S4): the platform kinds it may point at. */ allowedTypes?: string[]; /** For a lookup / rollup: the relation field it reads through. */ via?: string; /** Lookup: the field picked on the far side. Rollup: the field aggregated. */ pick?: string; /** Rollup: the aggregate along the relation. */ agg?: AggregateOperation; /** * Rollup: WHICH linked records it adds up — "sessions booked", "unpaid balance", "open requests" * per parent. The saved view's own filter grammar, written against the far table: a flat map of * far-side column keys (`{ status: "open" }`) or a Rule expression over far-side field IDs. The * store refuses an unknown column or op at install (custom.field_declare). */ filter?: Record; /** * For a `formula` field: the formula text custom.field_declare parses (`formula_text`, through * custom.formula_parse) — fields named by LABEL in braces, functions from * custom.formula_node_kinds(): `{Total} - {Paid}`, `DATEDIFF({Starts}, {Ends}, 'minutes') / 60`. * The store computes it on read; seeds never write it. */ formula?: string; /** * TEMPLATE-GAPS (c): a `status` column's groups (Notion's Status): choice word → "todo" | "in_progress" | * "done" (custom.status_groups_of). Every choice sits in exactly one group. */ statusGroups?: Record; /** * TEMPLATE-GAPS (e): a `button` column (Notion's Button property; custom.button_press) — what a press does: * open a link with `{{field_key}}` filled from the row, run one of this table's row actions (`row_action` * extra token) or one of its automations (`automation` extra token). Holds no value; never seeded. */ button?: { do: "open_url"; url: string; color?: ChoiceColor; } | { do: "run_action"; action: string; color?: ChoiceColor; } | { do: "run_automation"; automation: string; color?: ChoiceColor; } /** * TEMPLATE-GAPS R3 (1): ADD A ROW ("Log workout", "New 1:1"): a new row in `table` (a table token; absent = this * table), starting from that table's row template named `template`, with `prefill` on top: new row's field key → * this row's field key, or "@row" for this row itself (a link column back to this table). */ | { do: "add_row"; table?: string; template?: string; prefill?: Record; color?: ChoiceColor; }; /** * ELIGIBILITY across tables, on a relation field: the record this field points at must hold a * row in `table` (linked back by `relation`) matching `where`, whose `until` date is on or after * this row's `onDate` — a shift's staff member holds an unexpired food-handler card on the * shift's day. Checked on the seed and on the walk's state after every step. */ eligible?: { table: string; relation: string; where?: Record; until: string; onDate: string; }; /** * A date field whose values are history, not schedule (a date of birth, a founding * date): its seed rows hold absolute dates. Every other date field is written in the * relative grammar (RELATIVE_DATE). */ absoluteDates?: boolean; /** * A schedule date for a weekday-only business: every seed value must resolve to Monday– * Friday on EVERY install weekday (write it with business-day offsets "+2b" or the "~b" snap). */ businessDays?: boolean; /** The value a new record gets when nobody gives one — lets a form or an import leave a required field out. */ default?: unknown; /** * A public form may ask a confidential / restricted field only when it is the asker's OWN * data (a patient's member id on her own intake). Flag it here; never for anyone else's. */ askOfSubject?: boolean; /** A parent or guardian answers this on a public form for a minor (youth league, school, pediatrics). */ askOfGuardian?: boolean; /** * Required with `absoluteDates`: why these dates are history ("date of birth", "the year * the firm was founded"). A field flagged absolute may never drive a calendar, a timeline, * a booking, a digest, a stage rule, the Q6 question or a walk step — those are schedule. */ historicalReason?: string; } /** One row template of a table (TemplateTable.rowTemplates). */ interface TemplateRowTemplate { /** What a person picks it by: "Weekly 1:1", "Bug report". Unique on its table. */ name: string; /** Preset values by field key; never a computed field. */ values?: Record; /** The page body a new row's page starts from: a page snapshot `{ v: 1, blocks: [...] }`. */ body?: { v: 1; blocks: unknown[]; }; /** The table's default template: every new row's page starts from it. */ default?: boolean; } interface TemplateTable extends UseCaseTable { fields: TemplateField[]; /** * REUSE, NEVER DUPLICATE (CHAIR-DESCRIBE-2): this template table IS one the organization already has. * The install makes no table for it — `tables.` is the existing table's id from the first step — * declares only the fields it lacks (`fields` = the keys it already has), never resets its Dimensions, and * links the template's new tables to it. Uninstall archives only what the install added (its new fields, * views, forms), never the table. * * ITS ROWS (a sample row is never dropped whole): by default it seeds none, and a new table's value that * points at one of its sample rows is left empty. `seedRows` - the caller found the table EMPTY - writes * the template's sample rows into it, so every link to them lands. `rowIds` - the table HAS rows - maps a * sample row's key to the id of the existing row it means; a link to a mapped key lands on that row, a link * to any other key is left empty (and the field stops being required, so the new row still installs). */ bindsTo?: { tableId: string; fields: string[]; seedRows?: boolean; rowIds?: Record; }; /** * TEMPLATE-GAPS (a): ROW TEMPLATES (custom.row_template_declare) — what a new row starts as: preset * values (field key → value, e.g. `{ "status": "Draft" }`) and the page body every new row's page opens * with (`{ "v": 1, "blocks": [...] }`, Space blocks without ids — the Spaces row page reads the table's * `default` template). At most one is `default`. */ rowTemplates?: TemplateRowTemplate[]; /** * Ordered date pairs that hold on every seed row: [earlier, later]. A side is a field of * this table ("sent_on") or a field reached through one of its relations ("patient.date_of_birth"). * A table with two or more schedule date fields declares its order here, or says why the * dates are independent (`datesIndependent`). */ before?: [string, string][]; datesIndependent?: string; /** * A roster of recurring slots (weekly shifts, standing roles): rows may share a title when * they differ in a date and in who or what they are for (a relation). */ schedule?: boolean; /** * Date coherence across relations, declared: on every seed row `earlier` is on or before * `later`. A side is a field of this table ("invoice_date") or one reached through a relation * ("engagement.start_date"). `onlyWhen` limits the pair to rows whose field holds one of the * values (a report is due only on an Awarded grant). A billing or grants template declares at * least one pair that crosses a relation. */ datePairs?: { earlier: string; later: string; onlyWhen?: { field: string; values: string[]; }; }[]; /** * CROSS-TABLE REALISM, stated once on the CHILD table (the one holding the relation) and * enforced on every seed row. A relation whose two sides both carry a schedule date needs a * childDates entry; both a status, a statusAgrees entry. * * childDates: this row's date is on or after its parent's ("start_on" ≥ "requisition.opened_on"). */ childDates?: { relation: string; field: string; parentField: string; }[]; /** withinParent: this row's number stays within its parent's (deal.price ≤ client.budget_max) unless a status says otherwise. */ withinParent?: { relation: string; field: string; op: "<=" | ">="; parentField: string; unless?: { field: string; values: string[]; }; }[]; /** * statusAgrees: a child in one of `childStatus` means its parent's `parentField` is one of * `parentStatus` (deal Closed ⇒ listing Sold); `maxPerParent` caps how many children of one * parent may sit in those statuses (one accepted offer per listing). */ statusAgrees?: { relation: string; field: string; childStatus: string[]; parentField: string; parentStatus: string[]; maxPerParent?: number; }[]; /** countMatches: a stored count equals the number of linked rows. Prefer a rollup, which the store computes. */ countMatches?: { field: string; childTable: string; childRelation: string; }[]; /** * STATUS IMPLIES FIELDS: a row in one of `when` (on `field`) has every `filled` field filled * and every `equals` field at that value — Paid ⇒ paid_on set and balance 0; Signed ⇒ the * signature filled. Checked on every seed row and after every walk step that changes a row. */ statusImplies?: { field: string; when: string[]; filled?: string[]; equals?: Record; }[]; /** * DATE-DRIVEN STATUS: `field` follows `dateField` measured from the install day, on every * install weekday — bands in days from today, `from` inclusive, `to` exclusive: * [{status: "Expired", to: 0}, {status: "Renewal due", from: 0, to: 61}, {status: "Current", from: 61}]. * A row whose status is one of the bands' statuses sits in the band its date says. (A status the * store should compute is better a formula: IF(DATEDIFF(TODAY(), {Expires on}, 'days') < 0, …).) */ statusByDate?: { field: string; dateField: string; bands: { status: string; from?: number; to?: number; }[]; }; /** Relations (by field key) whose two sides' dates and statuses truly do not constrain each other, each with the reason. */ independentOf?: Record; /** * What one row is: a person, an animal or a thing. The personal-data floors (date of birth, * allergies, diagnoses, medications, member ids) bind people only — a dog's birthday is not * personal data. Undeclared, a table holds people when it has a name and a phone or email. */ subject?: "person" | "animal" | "thing"; /** * Lane 10 FD. An echo of the template's `foundation` list (R13), which is the ONE source the * installers read. Optional; when present the validator requires it to agree with the list. */ foundation?: boolean; } declare const TEMPLATE_VIEW_KINDS: readonly ["grid", "kanban", "calendar", "gallery", "timeline", "map", "orgchart", "pivot"]; type TemplateViewKind = (typeof TEMPLATE_VIEW_KINDS)[number]; interface TemplateViewSort { field: string; direction: "asc" | "desc"; } /** The day ranges custom.relative_window_for_reader knows. `n` (1–3660) only with next_days / past_days. */ declare const TEMPLATE_RELATIVE_DAYS: readonly ["today", "tomorrow", "yesterday", "this_week", "next_week", "last_week", "this_month", "next_month", "last_month", "before_today", "next_days", "past_days"]; type TemplateRelativeDay = (typeof TEMPLATE_RELATIVE_DAYS)[number]; interface TemplateRelativeWindow { relative: TemplateRelativeDay; n?: number; } interface TemplateViewBase { /** snake_case, unique within the template. */ token: string; /** What a person clicks: "Today's chairs", "Intake board". */ name: string; /** The table token it looks at. */ table: string; /** The view the table opens on (at most one per table). */ isDefault?: boolean; /** custom.view_declare `filters`: Field key → value (scalar equality, null = unset, object = window). */ filters?: Record; /** * Any-of conditions: Field key → the values a row may hold ("Open requests" = New, In progress, * Waiting). The store's flat `filters` map is equality only; this is declared as the view's * `where` Rule expression (S2-PRIME) — `{op: "and", args: [{op: "or", args: [{op: "eq", args: * [{field: }, {const: }]}, …]}, …]}`, Fields by id — which custom.record_filter_sql * compiles for the grid and the board. Digests and the notifier read only `filters`, never this. */ anyOf?: Record; /** * TEMPLATE-GAPS (b): RELATIVE DAY WINDOWS — date field key → a window counted from the READER's * today (the store's `within` Rule node; custom.relative_window_for_reader): "Due this week" = * `{ "due": { "relative": "this_week" } }`, "Next 7 days" = `{ "due": { "relative": "next_days", "n": 7 } }`, * "Overdue" = `{ "due": { "relative": "before_today" } }` (with an anyOf on the open statuses). * Declared into the view's `where`, beside anyOf. */ within?: Record; /** * TEMPLATE-GAPS (b): "ASSIGNED TO ME" — person field keys (a `member`, `created_by` or `modified_by` * column) that must hold the person reading the view (`eq(field, {me: true})`), so one shared * "My tasks" view shows each member their own rows. */ me?: string[]; sorts?: TemplateViewSort[]; /** Field keys hidden on this view (presentation.hiddenFields). */ hiddenFields?: string[]; } interface TemplateGridView extends TemplateViewBase { kind: "grid"; groupBy?: string; } interface TemplateKanbanView extends TemplateViewBase { kind: "kanban"; /** `group_field`: the choice field whose values are the columns. */ groupBy: string; /** `swimlane_field`: never the column field itself. */ swimlaneBy?: string; /** `measure`: a number field totalled under each column heading. */ measure?: string; } interface TemplateCalendarView extends TemplateViewBase { kind: "calendar"; /** `date_field`: a datetime, so every card has a time on the day. */ dateField: string; /** The records are whole-day by intent (a deadline, a due date). */ allDay?: boolean; /** "month" needs `view.calendar.month` (lane 10). */ span?: "month" | "week"; } interface TemplateGalleryView extends TemplateViewBase { kind: "gallery"; /** `image_field`: the file field shown as each card's picture. Needs `seed.attachments`. */ coverField: string; } interface TemplateTimelineView extends TemplateViewBase { kind: "timeline"; startField: string; endField: string; groupBy?: string; } /** W2-A: a map — `map_field` places each record (an address, a place, or a latitude with `mapLngField`). */ interface TemplateMapView extends TemplateViewBase { kind: "map"; mapField: string; /** `map_lng_field`: the longitude number field when `mapField` is a latitude. */ mapLngField?: string; } /** W2-A: an org chart — `parent_field` is the link to the same table saying who a record reports to. */ interface TemplateOrgChartView extends TemplateViewBase { kind: "orgchart"; parentField: string; } /** PIVOT-VIEW: a cross-tab — `group_field` rows, optional `column_field` columns, one measure per cell. */ interface TemplatePivotView extends TemplateViewBase { kind: "pivot"; /** `group_field`: the field whose values are the rows. */ rowField: string; /** `column_field`: the field whose values are the columns. Absent, one total column. */ columnField?: string; /** `measure`: the number field sum, avg, min and max read. */ measure?: string; /** `pivot_measure`: what a cell shows. Absent, a count. */ op?: "count" | "sum" | "avg" | "min" | "max"; } type TemplateView = TemplateGridView | TemplateKanbanView | TemplateCalendarView | TemplateGalleryView | TemplateTimelineView | TemplateMapView | TemplateOrgChartView | TemplatePivotView; interface TemplateFormField extends UseCaseFormField { /** * The question as it is ASKED: "What brings you in today?" — not the column label. * Sent as the question's `ask` to custom.form_declare / booking_declare (`help` rides beside it). */ ask: string; } interface TemplateForm extends UseCaseForm { fields: TemplateFormField[]; } interface TemplateDimensionOverride { /** An inferred dimension key (custom._table_dimensions_infer): a single choice, a single relation, a tick box, a date, created_at or updated_at. */ key: string; label?: string; hidden?: boolean; } interface TemplateMeasureOverride { /** An inferred measure key (count, sum_x, avg_x, min_x, max_x, filled_x) — rename/hide only — or a NEW key. */ key: string; label?: string; hidden?: boolean; /** A NEW measure only: one of custom.agg_operations() except count. */ op?: Exclude; /** A NEW measure only: the column it reads. */ of?: string; } interface TemplateDrillPath { key: string; /** Dimension keys, coarsest first; a date takes ":year" | ":quarter" | ":month" | ":week" | ":day". */ levels: string[]; } interface TemplateDimensions { table: string; dimensions?: TemplateDimensionOverride[]; measures?: TemplateMeasureOverride[]; paths?: TemplateDrillPath[]; default?: { by?: string[]; show?: string[]; }; } interface TemplateBookingWindow { /** 0 = Sunday … 6 = Saturday. */ weekday: number; /** "09:00". */ from: string; /** "17:00", later than `from`. */ to: string; } interface TemplateBooking { kind: "booking"; token: string; title: string; table: string; questions: TemplateFormField[]; availability: { timezone?: string; slotMinutes: number; bufferMinutes?: number; leadMinutes?: number; maxPerDay?: number; days?: number; windows: TemplateBookingWindow[]; }; slug?: string; /** * The statuses of rows that came through (or wait on) this booking page. Only those rows must * sit in its windows; rows that reached later stages by other routes (a same-day emergency * dispatch) do not. Default: Booked, Confirmed, Requested, Held, Pending, Scheduled, Canceled. */ bookedStages?: string[]; } interface TemplatePortalTable { table: string; /** The relation field of `table` that points at the portal's client table — "only theirs". */ namesVia: string; /** Never empty; never a restricted / confidential field or one the AI is kept from. */ visibleFields: string[]; editableFields?: string[]; comments?: boolean; } interface TemplatePortal { kind: "portal"; token: string; title: string; /** The table whose records are the portal's clients (patients, owners, tenants). */ clientTable: string; tables: TemplatePortalTable[]; /** Form tokens offered inside the portal. */ forms?: string[]; slug?: string; } interface TemplateDashboardBlock { title: string; kind: DashboardBlockKind; /** Absent = the dashboard's own table. */ table?: string; groupBy?: string[]; measures?: AggregateMeasure[]; bucket?: { key: string; by: AggregateBucket; }; filter?: Record; span?: number; /** `stuck` only. */ stateKey?: string; days?: number; } interface TemplateDashboard { kind: "dashboard"; token: string; name: string; table: string; /** At least two charts: bar, column, line or donut (`number`, `table` and `stuck` are not charts). */ blocks: TemplateDashboardBlock[]; } interface TemplateDrillDown { kind: "drill_down"; token: string; name: string; table: string; /** A `paths[].key` of this table's `dimensions` entry. */ path: string; } interface TemplateDigest { kind: "digest"; token: string; name: string; /** The view token whose records the digest sends. */ view: string; cadence: SubscriptionCadence; /** "monday 08:00". */ schedule?: string; channel?: "in_app" | "email" | "sms"; } interface TemplateChecklistStep { ref: string; title: string; role?: string; dueDays?: number; dependsOn?: string[]; requires?: { kind: "none" | "note"; } | { kind: "answer"; key: string; label: string; } | { kind: "record_field"; key: string; label?: string; } | { kind: "form"; form: string; } | { kind: "document"; document: string; }; } interface TemplateChecklist { kind: "checklist"; token: string; name: string; aboutTable: string; roles?: { role: string; label?: string; }[]; trigger?: { kind: "manual"; } | { kind: "record_created"; table: string; } | { kind: "status_reached"; table: string; status: string; }; steps: TemplateChecklistStep[]; } interface TemplateDocument { kind: "document"; token: string; name: string; describes: string; table: string; /** The subject or title line; merge fields allowed. */ title: string; /** * Prose with {{field_key}} merge fields, each a field of `table` (the installer writes * {{field:}}, the only token custom.doc_render_body resolves). No {{today}}, no * {{business.x}}, no signature field (a signature never merges into the body). */ body: string; /** Sent for e-signature (needs `document.esign`). */ signature?: boolean; } interface TemplateNotification { kind: "notification"; token: string; name: string; describes: string; when: UseCaseNotificationTrigger; /** Who it goes to, in the business's own words: "the assigned hygienist". */ audience: string; channel: NotificationChannel; /** The message; {{field_key}} merge fields of the watched table only. */ message: string; } interface TemplateStageRules { kind: "stage_rules"; token: string; /** "Route board" — the lifecycle's own name. */ name: string; table: string; /** The choice field holding the stage. */ stageField: string; /** Stage → what is true of a record sitting there, in the staff's words (every stage). */ stages: Record; transitions?: { from: string; to: string; }[]; /** Stage → field keys that must be filled to land there. */ requires?: Record; /** Stage → how many cards may sit there at once. */ limits?: Record; movesMessage?: string; /** * Status ↔ date coherence, enforced on every seed row for every install weekday: the date * field, and per stage whether its date is in the past (on or before install day), today, * or the future (on or after install day). A stage left out is unconstrained. */ dateField?: string; /** Every stage is listed once a dateField is declared; "any" says a stage's date is unconstrained, on purpose. */ /** "none": this stage has no date yet ("New call", "Draft") — its date field is EMPTY. */ stageDates?: Record; /** Why a time-bound stage ("No-show", "Completed", "Scheduled"…) is "any": one real sentence (≥ 6 words) per such stage. */ anyBecause?: Record; /** * Moves OUT of a terminal stage (Canceled, No-show, Lost, Declined, Closed, Withdrawn…) are * refused unless declared here with the business reason — a reopened deal, a rebooked guest. */ reopen?: { from: string; to: string; because: string; }[]; /** * A stage that needs a linked child: "First pickup booked" ⇒ at least `min` (default 1) row of * `table` whose `relation` points at this row and whose `field` is one of `in`. Checked on the * seed and on the walk's state after every step. */ requiresChild?: Record; } interface TemplateRowAction { kind: "row_action"; token: string; table: string; name: string; actionKind: "update" | "agent"; confirm?: boolean; color?: ChoiceColor; /** `update`: what it writes. Fields by key; the installer resolves ids. */ steps?: ({ field: string; set: "value"; value: unknown; } | { field: string; set: "clear"; })[]; /** `agent`: what the record chat opens with. */ prompt?: string; } /** When a template automation runs: the reminder events, plus `becomes` (a choice takes `value`) and `assigned` (a Person column fills). */ interface TemplateAutomationWhen extends Omit { event: UseCaseNotificationTrigger["event"] | "becomes" | "assigned"; /** For `becomes`: the choice the column must take. */ value?: string; } interface TemplateAutomation { kind: "automation"; token: string; name: string; /** * When it runs (custom.automation_declare): `created` → row_added; `due` → date_arrives on `field` * `daysBefore` days ahead ("remind me 2 days before"); `overdue` → date_arrives the day after `field`. * `updated` and `stage_entered` are not automation triggers a template installs (use a notification). */ when: TemplateAutomationWhen; /** * AT-TPLAUTO: `becomes` → property_edited on `field` with `to: value`; its action sets the date column `setsToday` * to today ("when Status becomes Done, set Done date to today"). `assigned` → tells whoever is put in the Person * column `field` (the two automations custom.field_notify_on_assign declares: an edit, and a new row with someone in it). */ setsToday?: string; /** What happens, in the business's words: "text the owner the pickup window". */ then: string; /** The reminder's words as the person reads them (≤ 600 chars); defaults to `then`. */ message?: string; /** Time of day a date reminder fires, HH:MM on a 24-hour clock; defaults to 09:00. */ at?: string; } type TemplateExtra = TemplateBooking | TemplatePortal | TemplateDashboard | TemplateDrillDown | TemplateDigest | TemplateChecklist | TemplateDocument | TemplateNotification | TemplateStageRules | TemplateRowAction | TemplateAutomation; type TemplateExtraKind = TemplateExtra["kind"]; declare const TEMPLATE_EXTRA_KINDS: readonly TemplateExtraKind[]; interface TemplateAgentVariable { /** One of the platform agent's own variable names (templates/AGENTS.snapshot.json). */ name: string; /** The table token bound to it at install. */ table: string; describes: string; /** * Optional (Kits → Template merge): the full merge-field binding instead of the whole-table * default. Its `table` must equal `table` above. */ binding?: TemplateMergeBinding; } /** * Q6: one question, and the exact `custom.record_aggregate` answer it must give. The * validator recomputes the answer from the seed rows with the store's own semantics * (text-equality filters, half-open date windows, sum over nothing is null, no rounding). */ interface TemplateAgentQuestion { ask: string; /** Why the owner asks it — what they do differently depending on the answer. */ whyItMatters: string; expect: { table: string; measure: AggregateMeasure; /** * Scalar equality, null = unset, or a {from, to} window on a date field whose bounds are * relative tokens WITH a time ("@today-7d 00:00"), never a bare or absolute date. The * filter may not match 90% or more of the table's rows (that is "how many are there"). */ filter?: Record; /** Never 0 and never null. */ answer: number; unit: string; }; } /** The platform agent every template copies unless it says why not (`agentReason`). */ declare const DEFAULT_TEMPLATE_AGENT: { readonly id: "4cd676c6-f55d-4426-b7eb-a9d0273566ec"; readonly name: "Answers From Your Tables"; }; interface TemplateAgent { /** The platform agent copied — id AND name, as the committed catalog snapshot has them. */ platformAgent: { id: string; name: string; }; /** Required when platformAgent is not DEFAULT_TEMPLATE_AGENT: why this template needs another agent. */ agentReason?: string; /** The copy's name in the installed org. */ name: string; variables: TemplateAgentVariable[]; question: TemplateAgentQuestion; /** Optional (Kits → Template merge): what "Try it" sends the copy. */ tryIt?: TemplateTryIt; } /** * The merge-field binding, with the two ids replaced by template-local handles the host resolves * at install: `table` (a table token) and `rowIndex` (the index of a seed row of that table). * `collection` = the table's rows (one text, via `transform`); `reference` = one row (`rowIndex`); * `value` = one field (`field`) of one row (`rowIndex`). */ interface TemplateMergeBinding { semantic: "collection" | "reference" | "value"; table: string; rowIndex?: number; field?: string; transform?: { name: "list"; template?: string; join?: string; max?: number; header?: string; }; limit?: number; sort?: { field: string; dir: "asc" | "desc"; }; match?: Record; /** What the agent sees when nothing matches (default "absent"). */ missing?: string; } /** What "Try it" sends a template's agent copy: the user's message and/or its other variables. */ interface TemplateTryIt { userInput?: string; variables?: Record; } interface TemplateExtraAgentVariable { /** One of the platform agent's own variable names (templates/AGENTS.snapshot.json). */ name: string; describes: string; binding: TemplateMergeBinding; } /** One more agent a template copies (no Q6: its question is the primary agent's). */ interface TemplateExtraAgent { /** Template-local handle: guide highlights and workflow `{{agent:key}}` placeholders use it. */ key: string; platformAgent: { id: string; name: string; }; /** Why this template carries this agent — a full sentence (agents never author agents). */ agentReason: string; name: string; variables: TemplateExtraAgentVariable[]; tryIt?: TemplateTryIt; } /** A workflow made at install through aidream `POST /workflows`; `{{table:}}` / `{{agent:}}` are resolved. */ interface TemplateWorkflow { key: string; name: string; description: string; definition: unknown; } /** One display step of how the template works (NOT the gated `walk`). */ interface TemplateGuideStep { title: string; body: string; /** `agent` key "agent" names the primary agent. */ highlight?: { kind: "table" | "agent" | "workflow" | "binding"; key: string; }; } /** One CSV-shaped import: a header of field keys and the rows under it, as the file holds them. */ interface WalkImport { kind: "import"; table: string; /** What the file is called: "October customer list.csv". */ sourceName: string; /** The field that makes a row the same row (`p_dedupe_key`); it carries a `unique` rule. */ dedupeKey: string; /** The header row: field keys (the mapping is identity). */ columns: string[]; /** The data rows, cell by cell, as text — at least one updates a seed row and one is new. */ rows: string[][]; } /** One row's move inside a grouped `moves` step. */ interface WalkMove { table: string; row: string; field: string; to: string; set?: Record; } type WalkAction = { kind: "open"; surface: string; } /** * A stage move, optionally landing with the fields that stage requires or implies (`set`: * "mark Paid" writes paid_on and balance in the same step). Judged as ONE step: stage * requires, statusImplies, date pairs and the stage's date rule are checked on the result. * A checker or installer runs it as ONE store call, as the person: * `pipeline_move(p_record_id, p_to, p_also => set)` — the door writes `p_also` with the * stage in the same record write, judged by the same Rules (the board's "this move needs * these fields" prompt makes the same call). Never record_update first: that leaves a * half-moved row if the move is then refused. */ | { kind: "move"; table: string; row: string; field: string; to: string; set?: Record; } /** * A GROUPED step: 2–3 linked moves made together ("accept the quote AND move its lead to * Agreement signed"). Each move is judged against its own table's transitions, requires, * statusImplies and date rules; the template's cross-table rules (statusAgrees, * withinParent, childDates) are judged on the state after the WHOLE group. A checker runs it * as one `pipeline_move(p_record_id, p_to, p_also => set)` per row, in the listed order, as * the person; the expect asserts where one of the moved rows landed. */ | { kind: "moves"; moves: WalkMove[]; } /** * One field (`field` + `value`) or several at once (`set: {field: value, …}` — "mark paid" * sets status, paid and balance together); the coherence rules judge the whole result. */ | { kind: "edit"; table: string; row: string; field?: string; value?: unknown; set?: Record; } | { kind: "submit_form"; form: string; values: Record; } | { kind: "archive"; table: string; row: string; } | { kind: "restore"; table: string; row: string; } | WalkImport | { kind: "ask_agent"; }; type WalkAssertion = /** The surface renders with at least `minItems` (≥ 1) records. */ /** * The surface renders with at least `minItems` (≥ 1) records. `within` is the date window the * step talks about ("the next three weeks"): relative tokens on the view's date field, checked * on every install weekday. A step that names a span on a calendar or timeline must carry it. */ { kind: "renders"; surface: string; minItems: number; within?: { from?: string; to?: string; }; } /** Over the walk's state after this step; never 0. */ | { kind: "count"; table: string; where?: Record; equals: number; } | { kind: "value"; table: string; row: string; field: string; equals: unknown; } | { kind: "aggregate"; table: string; measure: AggregateMeasure; where?: Record; equals: number; } /** After `ask_agent`: the exact number the agent must answer (= agent.question.expect.answer). */ | { kind: "agent_answer"; equals: number; } /** After `archive` / `restore`: the row it acted on is (or is no longer) archived. */ | { kind: "archived"; table: string; row: string; equals: boolean; }; interface WalkStep { /** What the person does, in plain words: "Drag Rosa to Scheduled". */ says: string; action: WalkAction; expect: WalkAssertion; } /** A table marked as day-one foundation data (R13): kept for the reason given. */ interface TemplateFoundation { table: string; keptFor: string; } interface TemplateSource { title: string; url?: string; /** What was taken: structure ideas only — never text, data or a real person. */ took: string; } interface TemplateProvenance extends UseCaseProvenance { sources: TemplateSource[]; /** Every domain an email, website or url in the file uses. Each must not resolve in DNS (G6). */ fictionalDomains: string[]; /** Every street a numbered address in the file is on: invented, never a real street. */ fictionalStreets: string[]; } /** The five singular artefacts a UseCase carries; a template derives them (toUseCase). */ type UseCaseSingulars = "form" | "pipeline" | "dashboardQuestion" | "documentTemplate" | "notificationRule"; /** * ONE TEMPLATE: the UseCase's business, tables and relationships, with the singulars * replaced by their plural, installable forms (forms[], stage_rules / document / * notification extras, the agent's question). */ interface TemplateSpec extends Omit { /** The schema version of this file (TEMPLATE_SPEC_VERSION). */ specVersion: typeof TEMPLATE_SPEC_VERSION; /** The CATALOGUE.json row this realizes: "T0042". Stable, never positional. */ catalogueId: string; industry: IndustryGroup; /** The practitioner's own vertical: "Dental practice", "Residential HVAC". */ vertical: string; job: TemplateJob; audience: TemplateAudience; teaches: TeachesFeature; strengths: Strength[]; requires: CapabilityWord[]; tables: TemplateTable[]; sharedBlocks: SharedBlockUse[]; views: TemplateView[]; forms: TemplateForm[]; /** * Whether the forms this template installs are PUBLISHED on install (default true: a form the box * builds works the moment it is built). `false` leaves them as drafts for the owner to open. */ publishForms?: boolean; dimensions: TemplateDimensions[]; extras: TemplateExtra[]; /** * The template's agent: a copy of a platform agent. Optional ONLY when `mandateKey` is given. */ agent?: TemplateAgent; /** * A template that presents a MANDATE instead of an agent copy (design packs: `design_system.build`). The install * copies no agent and records the key on the install (custom.template_install.mandate_key, answered as * `mandate_key`); the surface that opens the installed template presents that mandate. `agent` becomes optional. */ mandateKey?: string; /** Three teaching steps, plus an optional fourth that is the ask_agent step. */ walk: [WalkStep, WalkStep, WalkStep] | [WalkStep, WalkStep, WalkStep, WalkStep]; foundation: TemplateFoundation[]; provenance: TemplateProvenance; /** The gallery card's picture (lane 2), relative to the template file. */ previewImage?: string; /** Content version: an integer, bumped on every published change. */ version: number; /** * Lane 12 P7: tables that are Confidential (asked of the chair after install — a template never * sets the level itself) and tables whose members add their own rows. See ./confidential. */ confidential?: TemplateConfidential[]; membersAddRows?: string[]; /** Kits → Template merge: more agents the install copies, after `agent`. */ extraAgents?: TemplateExtraAgent[]; /** Kits → Template merge: workflows the install creates. */ workflows?: TemplateWorkflow[]; /** Kits → Template merge: how-it-works steps, shown only (the gated teaching steps are `walk`). */ guide?: TemplateGuideStep[]; } /** "3 tables · 2 views · 1 form · 1 booking" plus the counts it is made of — what uninstall takes back. */ interface TemplateFootprint { tables: number; /** Shared-block tables it seeds rows into (not owned: uninstall archives its rows only). */ sharedBlocks: number; views: number; forms: number; dimensions: number; extras: Partial>; agents: number; /** Workflows an install creates (host step). */ workflows: number; /** * custom.portal_declare opens the organization's outside sign-in. Q7: uninstall restores * the setting it found (the installer records the before-value). */ opensOutsideSignIn: boolean; line: string; } /** The footprint, DERIVED from the spec — never written by hand, so it cannot drift. */ declare function footprintOf(spec: Pick & Partial>): TemplateFootprint; declare const CATALOGUE_STATUSES: readonly ["planned", "authoring", "checking", "waiting_on_lane_10", "ready", "published", "retired"]; type CatalogueStatus = (typeof CATALOGUE_STATUSES)[number]; interface CatalogueRow { /** Stable forever: a retired row keeps its id with status "retired"; ids are never reused. */ catalogueId: string; industry: IndustryGroup; /** The vertical within the group: "Dental practice". */ vertical: string; job: TemplateJob; teaches: TeachesFeature; strengths: Strength[]; audience: TemplateAudience; /** One sentence the writer starts from: who, what business, what job. */ personaSeed: string; ownerLane: string; status: CatalogueStatus; /** "scope-template:" | "use-case:" | "new". */ source: string; /** Why a retired row was retired ("duplicate of T0009"). */ retiredBecause?: string; /** The gallery card's picture, once the template has one. */ previewImage?: string; /** Capabilities this row will need that may still be held (seed.attachments, automation), so batches can skip held rows. */ requires?: CapabilityWord[]; /** * The real install check of the CURRENT file (scripts/templates-publish.ts verify): installed through * the template family on the clone as a person, then uninstalled. `fileHash` pins which file passed. */ installCheck?: { result: "pass" | "fail"; /** Where the install ran: "live" since 2026-10-04 (Arman 2026-10-03: checks run on live; the clone is for destructive rehearsals only). */ target: "clone" | "live"; checkedAt: string; fileHash: string; wallMs: number; installMs?: number; steps?: number; calls?: number; orgId?: string; /** The refusal verbatim (store sentence, validator problem, or uninstall leftover). */ refusal?: string; }; /** Set by scripts/templates-publish.ts publish once declared for everyone on production. */ published?: { templateId: string; version: number; steps: number; publishedAt: string; fileHash: string; }; } /** One platform agent a template may copy (templates/AGENTS.snapshot.json). */ interface AgentSnapshotRow { id: string; name: string; variables: string[]; } /** One entry of templates/RETIRED_IDS.json — append-only. */ interface RetiredId { catalogueId: string; retiredOn: string; because: string; } export { CATALOGUE_QUOTAS as B, CATALOGUE_STATUSES as D, CHOICE_COLORS as E, CHOICE_COLORS_DISTINCT_UP_TO as F, CHOICE_COLOR_ALIASES as G, DEFAULT_TEMPLATE_AGENT as O, ENTITY_REFERENCE_KINDS as P, INDUSTRY_GROUPS as Q, RELATIVE_DATE as R, SHARED_BLOCKS as V, SHARED_BLOCK_IDS as W, STAMP_ME as X, STAMP_NOW as Y, STRENGTHS as Z, TABLE_KERNEL_ID as a2, TEACHES_FEATURES as a3, TEMPLATE_AUDIENCES as a4, TEMPLATE_EXTRA_KINDS as a5, TEMPLATE_JOBS as a6, TEMPLATE_REFERENCE_DATE as a7, TEMPLATE_RELATIVE_DAYS as a8, TEMPLATE_SPEC_VERSION as a9, canonicalChoiceColor as aP, confidentialPending as aQ, confidentialRequests as aR, footprintOf as aS, isPressDayWord as aT, membersAddRowsSteps as aU, tableSettingsProblems as aV, whenRule as aW, TEMPLATE_VIEW_KINDS as aa, CAPABILITY_WORDS as z }; export type { SharedBlockField as $, AgentSnapshotRow as A, CapabilityWord as C, CatalogueRow as H, IndustryGroup as I, CatalogueStatus as J, ChoiceColor as K, ChoiceColorAlias as L, ConfidentialLevel as M, ConfidentialRequest as N, SharedBlockId as S, TemplateSpec as T, RetiredId as U, SharedBlock as _, TemplateTable as a, SharedBlockUse as a0, Strength as a1, TemplatePortalTable as aA, TemplateProvenance as aB, TemplateRelativeDay as aC, TemplateRelativeWindow as aD, TemplateRowTemplate as aE, TemplateSource as aF, TemplateTableSettings as aG, TemplateTimelineView as aH, TemplateViewSort as aI, UseCaseSingulars as aJ, WalkAction as aK, WalkAssertion as aL, WalkImport as aM, WalkMove as aN, WalkStep as aO, TemplateAgentQuestion as ab, TemplateAgentVariable as ac, TemplateAudience as ad, TemplateAutomationWhen as ae, TemplateCalendarView as af, TemplateChecklistStep as ag, TemplateConfidential as ah, TemplateConfidentialReader as ai, TemplateDashboardBlock as aj, TemplateDimensionOverride as ak, TemplateDrillPath as al, TemplateExtra as am, TemplateExtraAgent as an, TemplateExtraAgentVariable as ao, TemplateExtraKind as ap, TemplateFormField as aq, TemplateFoundation as ar, TemplateGalleryView as as, TemplateGridView as at, TemplateGuideStep as au, TemplateKanbanView as av, TemplateMapView as aw, TemplateMeasureOverride as ax, TemplateOrgChartView as ay, TemplatePivotView as az, TemplateField as b, TemplateAgent as c, TemplateAutomation as d, TemplateBooking as e, TemplateChecklist as f, TemplateDashboard as g, TemplateDigest as h, TemplateDocument as i, TemplateDrillDown as j, TemplateDimensions as k, TemplateForm as l, TemplateNotification as m, TemplatePortal as n, TemplateRowAction as o, TemplateStageRules as p, TemplateView as q, TemplateMergeBinding as r, TemplateTryIt as s, TemplateWorkflow as t, TemplateFootprint as u, TemplateJob as v, TeachesFeature as w, TemplateViewKind as x, TemplateBookingWindow as y };