@ever-works/contracts 1.0.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.
@@ -0,0 +1,2171 @@
1
+ import { ItemData, ItemHealth } from '../item/index.cjs';
2
+ import { M as MergePolicyOverride, O as OrganizationConnectionPolicy, F as FeedNarrationDto } from '../feed.types-BWk3CHqj.cjs';
3
+
4
+ /**
5
+ * Method used for item generation
6
+ */
7
+ declare enum GenerationMethod {
8
+ CREATE_UPDATE = "create-update",
9
+ RECREATE = "recreate",
10
+ IMPORT = "import"
11
+ }
12
+ /**
13
+ * Method used for website repository creation
14
+ */
15
+ declare enum WebsiteRepositoryCreationMethod {
16
+ DUPLICATE = "duplicate",
17
+ CREATE_USING_TEMPLATE = "create-using-template"
18
+ }
19
+
20
+ /**
21
+ * Provider selection for each capability category
22
+ */
23
+ interface ProvidersDto {
24
+ /** Search provider plugin ID */
25
+ search?: string;
26
+ /** Screenshot provider plugin ID */
27
+ screenshot?: string;
28
+ /** AI provider plugin ID */
29
+ ai?: string;
30
+ /** Content extractor provider plugin ID */
31
+ contentExtractor?: string;
32
+ /** Pipeline provider plugin ID */
33
+ pipeline?: string;
34
+ }
35
+
36
+ /**
37
+ * Minimal core DTO for creating/triggering item generation.
38
+ * All pipeline-specific configuration is passed via pluginConfig.
39
+ */
40
+ interface CreateItemsGeneratorDto {
41
+ /** Work name */
42
+ name: string;
43
+ /** Generation prompt */
44
+ prompt: string;
45
+ /** Optional AI model override */
46
+ model?: string;
47
+ /** Method for generation (create-update or recreate) */
48
+ generation_method?: GenerationMethod;
49
+ /** Whether to update with pull request */
50
+ update_with_pull_request?: boolean;
51
+ /** Website repository creation method */
52
+ website_repository_creation_method?: WebsiteRepositoryCreationMethod;
53
+ /** Provider selection */
54
+ providers?: ProvidersDto;
55
+ /** Plugin-specific configuration - structure defined by selected pipeline plugin */
56
+ pluginConfig?: Record<string, unknown>;
57
+ }
58
+ /**
59
+ * DTO for updating items generator configuration
60
+ */
61
+ interface UpdateItemsGeneratorDto {
62
+ /** Optional AI model override */
63
+ model?: string;
64
+ /** Method for generation (create-update or recreate) */
65
+ generation_method?: GenerationMethod;
66
+ /** Whether to update with pull request */
67
+ update_with_pull_request?: boolean;
68
+ /** Provider overrides (pipeline, ai, search, etc.) */
69
+ providers?: ProvidersDto;
70
+ }
71
+
72
+ /**
73
+ * DTO for submitting a new item to a work
74
+ *
75
+ * Note: Either `category` (single) or `categories` (array) must be provided.
76
+ * The backend validates this with conditional validation.
77
+ */
78
+ interface SubmitItemDto {
79
+ /** Item name */
80
+ name: string;
81
+ /** Item description */
82
+ description: string;
83
+ /** Source URL for the item */
84
+ source_url: string;
85
+ /** Primary category (required if categories is not provided) */
86
+ category?: string;
87
+ /** Additional categories (required if category is not provided) */
88
+ categories?: string[];
89
+ /** Tags for the item */
90
+ tags?: string[];
91
+ /** Whether item is featured */
92
+ featured?: boolean;
93
+ /** Display order */
94
+ order?: number;
95
+ /** Whether to pay and publish immediately */
96
+ pay_and_publish_now?: boolean;
97
+ /** URL-friendly slug */
98
+ slug?: string;
99
+ /** Brand name */
100
+ brand?: string;
101
+ /** Brand logo URL */
102
+ brand_logo_url?: string;
103
+ /** Item images */
104
+ images?: string[];
105
+ /** Whether to create a pull request */
106
+ create_pull_request?: boolean;
107
+ /** Long-form markdown body. Written to `data/<slug>/<slug>.md` and mirrored
108
+ * on the YAML `markdown` field. When omitted, the generator falls back
109
+ * to a stub built from name + description + source_url. */
110
+ markdown?: string;
111
+ }
112
+
113
+ /**
114
+ * DTO for removing an item from a work
115
+ */
116
+ interface RemoveItemDto {
117
+ /** Slug of the item to remove */
118
+ item_slug: string;
119
+ /** Reason for removal */
120
+ reason?: string;
121
+ /** Whether to create a pull request */
122
+ create_pull_request?: boolean;
123
+ }
124
+
125
+ /**
126
+ * DTO for updating item metadata in a work
127
+ */
128
+ interface UpdateItemDto {
129
+ /** Slug of the item to update */
130
+ item_slug: string;
131
+ /** Source URL */
132
+ source_url?: string;
133
+ /** Whether item is featured */
134
+ featured?: boolean;
135
+ /** Display order */
136
+ order?: number;
137
+ /** Whether to create a pull request */
138
+ create_pull_request?: boolean;
139
+ /** Long-form markdown body. When provided, replaces the existing
140
+ * `data/<slug>/<slug>.md` file and mirrors onto the YAML `markdown` field. */
141
+ markdown?: string;
142
+ }
143
+
144
+ /**
145
+ * DTO for manually checking a single item's source URL health.
146
+ */
147
+ interface CheckItemHealthDto {
148
+ /** Slug of the item to check */
149
+ item_slug: string;
150
+ }
151
+ /**
152
+ * Response returned after checking a single item's source URL health.
153
+ */
154
+ interface CheckItemHealthResponseDto {
155
+ status: 'success' | 'error';
156
+ item_slug: string;
157
+ item_name: string;
158
+ message: string;
159
+ item?: ItemData;
160
+ health?: ItemHealth;
161
+ }
162
+
163
+ /**
164
+ * DTO for extracting item details from a URL
165
+ */
166
+ interface ExtractItemDetailsDto {
167
+ /** Source URL to extract details from */
168
+ source_url: string;
169
+ /** Optional work context for provider resolution and usage attribution */
170
+ workId?: string;
171
+ /** Existing categories in the work for matching */
172
+ existing_categories?: string[];
173
+ }
174
+
175
+ /**
176
+ * Cadence options for work scheduled updates
177
+ */
178
+ declare enum WorkScheduleCadence {
179
+ HOURLY = "hourly",
180
+ EVERY_3_HOURS = "every_3_hours",
181
+ EVERY_8_HOURS = "every_8_hours",
182
+ EVERY_12_HOURS = "every_12_hours",
183
+ DAILY = "daily",
184
+ WEEKLY = "weekly",
185
+ MONTHLY = "monthly"
186
+ }
187
+ /**
188
+ * Status options for work schedule
189
+ */
190
+ declare enum WorkScheduleStatus {
191
+ DISABLED = "disabled",
192
+ ACTIVE = "active",
193
+ PAUSED = "paused",
194
+ CANCELED = "canceled"
195
+ }
196
+ /**
197
+ * Billing mode options for scheduled updates
198
+ */
199
+ declare enum WorkScheduleBillingMode {
200
+ SUBSCRIPTION = "subscription",
201
+ USAGE = "usage"
202
+ }
203
+
204
+ /**
205
+ * Status types for work generation
206
+ */
207
+ declare enum GenerateStatusType {
208
+ GENERATING = "generating",
209
+ GENERATED = "generated",
210
+ ERROR = "error",
211
+ CANCELLED = "cancelled"
212
+ }
213
+
214
+ /**
215
+ * Allowed cadence configuration for a work
216
+ */
217
+ interface WorkScheduleAllowedCadence {
218
+ /** The cadence option */
219
+ cadence: WorkScheduleCadence;
220
+ /** Reason if not allowed */
221
+ reason?: string;
222
+ /** Whether this cadence uses pay-per-use billing */
223
+ payPerUse?: boolean;
224
+ /** Whether this cadence is allowed */
225
+ allowed: boolean;
226
+ }
227
+ /**
228
+ * Work schedule configuration and status
229
+ */
230
+ interface WorkScheduleDto {
231
+ /** Current schedule status */
232
+ status: WorkScheduleStatus;
233
+ /** Whether the scheduled updates feature is currently available */
234
+ featureEnabled: boolean;
235
+ /** Whether this work is currently eligible to enable scheduled updates */
236
+ canEnable: boolean;
237
+ /** Machine-readable reason the schedule cannot currently be enabled */
238
+ blockingCode?: 'SCHEDULED_UPDATES_DISABLED' | 'INITIAL_WORK_SETUP_REQUIRED' | 'SOURCE_SYNC_UNSUPPORTED' | 'CONFIG_UNAVAILABLE';
239
+ /** Human-readable reason the schedule cannot currently be enabled */
240
+ blockingReason?: string;
241
+ /** Selected cadence (null if disabled) */
242
+ cadence: WorkScheduleCadence | null;
243
+ /** Billing mode */
244
+ billingMode: WorkScheduleBillingMode;
245
+ /** Next scheduled run time (ISO string) */
246
+ nextRunAt: string | null;
247
+ /** Last run time (ISO string) */
248
+ lastRunAt: string | null;
249
+ /** Status of last run */
250
+ lastRunStatus: GenerateStatusType | null;
251
+ /** Number of consecutive failures */
252
+ failureCount: number;
253
+ /** Max failures before auto-pause */
254
+ maxFailureBeforePause: number;
255
+ /** Whether to always create pull request */
256
+ alwaysCreatePullRequest: boolean;
257
+ /** Available cadence options */
258
+ allowedCadences: WorkScheduleAllowedCadence[];
259
+ /** User's plan code */
260
+ planCode?: string;
261
+ /** Whether subscriptions are enabled */
262
+ subscriptionsEnabled: boolean;
263
+ /** Provider overrides for scheduled runs (pipeline, ai, search, etc.) */
264
+ providerOverrides?: ProvidersDto | null;
265
+ }
266
+ /**
267
+ * Payload for updating work schedule
268
+ */
269
+ interface UpdateWorkSchedulePayload {
270
+ /** Enable or disable schedule */
271
+ enable?: boolean;
272
+ /** Trigger an immediate run after saving the active schedule */
273
+ runImmediately?: boolean;
274
+ /** Schedule cadence */
275
+ cadence?: WorkScheduleCadence;
276
+ /** Billing mode */
277
+ billingMode?: WorkScheduleBillingMode;
278
+ /** Max failures before auto-pause */
279
+ maxFailureBeforePause?: number;
280
+ /** Always create pull request */
281
+ alwaysCreatePullRequest?: boolean;
282
+ /** Provider overrides for scheduled runs (pipeline, ai, search, etc.) */
283
+ providerOverrides?: ProvidersDto | null;
284
+ }
285
+
286
+ type WorkCurrentState = 'running' | 'paused' | 'idle';
287
+ type WorkDeploymentReadiness = 'ready' | 'pending' | 'unknown' | 'not_deployed';
288
+ type WorkDeploymentHealthSource = 'deployment_projection' | 'none';
289
+ interface WorkLastGenerationRunDto {
290
+ status: GenerateStatusType;
291
+ startedAt: string | null;
292
+ finishedAt: string | null;
293
+ }
294
+ interface WorkLastDeploymentRunDto {
295
+ status: string;
296
+ startedAt: string | null;
297
+ finishedAt: string | null;
298
+ }
299
+ interface WorkLastRunDto {
300
+ generation: WorkLastGenerationRunDto | null;
301
+ deployment: WorkLastDeploymentRunDto | null;
302
+ }
303
+ interface WorkCurrentDeploymentHealthDto {
304
+ readiness: WorkDeploymentReadiness;
305
+ source: WorkDeploymentHealthSource;
306
+ /** Null for legacy projections because they pre-date persisted probe timestamps. */
307
+ observedAt: string | null;
308
+ }
309
+ interface WorkCurrentHealthDto {
310
+ state: WorkCurrentState;
311
+ deployment: WorkCurrentDeploymentHealthDto;
312
+ }
313
+ interface WorkStatusProjectionDto {
314
+ lastRun: WorkLastRunDto;
315
+ currentHealth: WorkCurrentHealthDto;
316
+ }
317
+
318
+ /**
319
+ * Metrics from a generation run
320
+ */
321
+ interface GenerationMetrics {
322
+ /** Number of URLs scanned */
323
+ urls_scanned?: number;
324
+ /** Number of pages processed */
325
+ pages_processed?: number;
326
+ /** Items extracted in current run */
327
+ items_extracted_current_run?: number;
328
+ /** New items added to store */
329
+ new_items_added_to_store?: number;
330
+ /** Total items in store */
331
+ total_items_in_store?: number;
332
+ /** Total tokens used */
333
+ total_tokens_used?: number;
334
+ /** Total cost */
335
+ total_cost?: number;
336
+ }
337
+ declare enum WorkHistoryActivityType {
338
+ GENERATION = "generation",
339
+ ITEM_ADDED = "item_added",
340
+ ITEM_UPDATED = "item_updated",
341
+ ITEM_REMOVED = "item_removed",
342
+ COMPARISON_ADDED = "comparison_added",
343
+ COMPARISON_REMOVED = "comparison_removed",
344
+ CATEGORY_CHANGE = "category_change",
345
+ TAG_CHANGE = "tag_change",
346
+ COLLECTION_CHANGE = "collection_change",
347
+ COMMUNITY_PR_MERGED = "community_pr_merged"
348
+ }
349
+ type WorkHistoryChangeEntityType = 'item' | 'comparison' | 'category' | 'tag' | 'collection';
350
+ type WorkHistoryChangeAction = 'added' | 'updated' | 'removed';
351
+ interface WorkHistoryChangeEntry {
352
+ entityType: WorkHistoryChangeEntityType;
353
+ action: WorkHistoryChangeAction;
354
+ name: string;
355
+ slug?: string;
356
+ fieldsChanged?: string[];
357
+ }
358
+ type GenerationLogLevel = 'info' | 'warn' | 'error' | 'debug';
359
+ type GenerationLogSource = 'pipeline' | 'orchestrator' | 'claude-code' | 'system';
360
+ interface GenerationStepLog {
361
+ timestamp: string;
362
+ level: GenerationLogLevel;
363
+ source: GenerationLogSource;
364
+ stepIndex?: number | null;
365
+ stepName?: string | null;
366
+ event: 'step_started' | 'step_completed' | 'step_failed' | 'step_skipped' | 'message';
367
+ message: string;
368
+ durationMs?: number | null;
369
+ }
370
+ interface WorkChangelog {
371
+ summary?: string | null;
372
+ addedCount: number;
373
+ updatedCount: number;
374
+ removedCount: number;
375
+ entries: WorkHistoryChangeEntry[];
376
+ }
377
+ /**
378
+ * Entry in work generation history
379
+ */
380
+ interface WorkGenerationHistoryEntry {
381
+ /** History entry ID */
382
+ id: string;
383
+ /** Generation status */
384
+ status: GenerateStatusType;
385
+ /** Generation method used */
386
+ generationMethod?: GenerationMethod | null;
387
+ /** When generation started (ISO string) */
388
+ startedAt?: string | null;
389
+ /** When generation finished (ISO string) */
390
+ finishedAt?: string | null;
391
+ /** Duration in seconds */
392
+ durationInSeconds?: number | null;
393
+ /** Number of new items */
394
+ newItemsCount: number;
395
+ /** Number of updated items */
396
+ updatedItemsCount: number;
397
+ /** Total items count */
398
+ totalItemsCount: number;
399
+ /** Generation metrics */
400
+ metrics?: GenerationMetrics | null;
401
+ /** Error message if failed */
402
+ errorMessage?: string | null;
403
+ /** Generation parameters used */
404
+ parameters?: CreateItemsGeneratorDto | null;
405
+ /** Created timestamp (ISO string) */
406
+ createdAt: string;
407
+ /** Updated timestamp (ISO string) */
408
+ updatedAt: string;
409
+ /** Trigger.dev run ID */
410
+ triggerRunId?: string;
411
+ /** History activity type */
412
+ activityType: WorkHistoryActivityType;
413
+ /** Structured changelog details */
414
+ changelog?: WorkChangelog | null;
415
+ /** Step-level generation logs */
416
+ logs?: GenerationStepLog[] | null;
417
+ /** Warnings captured during generation */
418
+ warnings?: string[] | null;
419
+ /** What triggered this run */
420
+ triggeredBy?: 'user' | 'schedule' | 'api' | null;
421
+ }
422
+ /**
423
+ * Response for work generation history
424
+ */
425
+ interface WorkGenerationHistoryResponse {
426
+ /** History entries */
427
+ history: WorkGenerationHistoryEntry[];
428
+ /** Total count */
429
+ total: number;
430
+ /** Pagination limit */
431
+ limit: number;
432
+ /** Pagination offset */
433
+ offset: number;
434
+ }
435
+
436
+ interface UpdateSourceValidationPayload {
437
+ enabled: boolean;
438
+ cadence?: WorkScheduleCadence;
439
+ }
440
+ interface SourceValidationSettingsDto {
441
+ enabled: boolean;
442
+ cadence: WorkScheduleCadence | null;
443
+ nextRunAt: string | null;
444
+ lastRunAt: string | null;
445
+ allowedCadences: WorkScheduleAllowedCadence[];
446
+ }
447
+
448
+ declare const IMPORT_SOURCE_TYPES: readonly ["data_repo", "awesome_readme", "link_existing", "works_config"];
449
+ type ImportSourceType = (typeof IMPORT_SOURCE_TYPES)[number];
450
+ declare const AWESOME_README_IMPORT_MODES: readonly ["clone", "reuse_source"];
451
+ type AwesomeReadmeImportMode = (typeof AWESOME_README_IMPORT_MODES)[number];
452
+ type RepositoryRole = 'data' | 'work' | 'website';
453
+ interface RepositoryTarget {
454
+ owner?: string;
455
+ repo: string;
456
+ }
457
+ interface RelatedRepositories {
458
+ data?: RepositoryTarget;
459
+ work?: RepositoryTarget;
460
+ website?: RepositoryTarget;
461
+ }
462
+ interface WorksConfigSnapshot {
463
+ name?: string;
464
+ initialPrompt?: string;
465
+ model?: string;
466
+ websiteRepo?: string;
467
+ scheduleCadence?: WorkScheduleCadence | null;
468
+ providers?: ProvidersDto;
469
+ }
470
+ interface SourceRepository<TImportedAt = string> {
471
+ url: string;
472
+ owner: string;
473
+ repo: string;
474
+ type: ImportSourceType;
475
+ importedAt: TImportedAt;
476
+ relatedRepositories?: RelatedRepositories;
477
+ worksConfig?: WorksConfigSnapshot;
478
+ }
479
+ interface RepoVisibility {
480
+ data: boolean;
481
+ website: boolean;
482
+ work: boolean;
483
+ }
484
+ interface ImportEnrichmentConfig {
485
+ expansionFactor?: number;
486
+ }
487
+ interface AnalyzeRepositoryResponseDto {
488
+ sourceUrl: string;
489
+ owner: string;
490
+ repo: string;
491
+ detectedType: ImportSourceType | null;
492
+ isPublic: boolean;
493
+ requiresAuth: boolean;
494
+ structure?: {
495
+ hasDataFolder: boolean;
496
+ hasConfig: boolean;
497
+ hasReadme: boolean;
498
+ hasWorksConfig?: boolean;
499
+ isMultiFile?: boolean;
500
+ itemCount?: number;
501
+ categoryCount?: number;
502
+ };
503
+ worksConfig?: WorksConfigSnapshot;
504
+ relatedDataRepo?: {
505
+ name: string;
506
+ owner: string;
507
+ };
508
+ baseSlug?: string;
509
+ slugConflict?: {
510
+ hasConflict: boolean;
511
+ conflictingRepos: string[];
512
+ suggestedSlug: string;
513
+ };
514
+ hasDataRepoWriteAccess?: boolean;
515
+ error?: string;
516
+ }
517
+ interface ImportWorkDto {
518
+ sourceUrl: string;
519
+ sourceType: ImportSourceType;
520
+ awesomeReadmeImportMode?: AwesomeReadmeImportMode;
521
+ name: string;
522
+ owner?: string;
523
+ organization?: boolean;
524
+ gitProvider: string;
525
+ deployProvider?: string;
526
+ createMissingRepos?: boolean;
527
+ sync?: boolean;
528
+ providers?: ProvidersDto;
529
+ restoreWorksConfig?: boolean;
530
+ enrichmentConfig?: ImportEnrichmentConfig;
531
+ }
532
+
533
+ /**
534
+ * Public request shape for POST /api/register-work and the equivalent
535
+ * register_work MCP tool. The GitHub credential is NOT part of this body —
536
+ * it travels in the X-GitHub-Token header (REST) or as a sibling tool
537
+ * argument that is redacted from logs (MCP).
538
+ */
539
+ interface RegisterWorkRequest {
540
+ /** HTTPS GitHub repo URL containing .works/works.yml at root. */
541
+ repo: string;
542
+ /** Optional contact email. */
543
+ email?: string;
544
+ /** Optional opaque agent identifier (printable ASCII, ≤256 chars). */
545
+ agentId?: string;
546
+ /** Optional HTTPS URL for signed terminal-status webhooks. */
547
+ webhookUrl?: string;
548
+ /** Optional DNS-safe slug for the assigned subdomain. */
549
+ subdomain?: string;
550
+ /**
551
+ * Reserved for v2 paid plane — accepts x402, Skyfire, Crossmint, or
552
+ * Stripe Agent payment envelopes. Ignored at v1.
553
+ */
554
+ agentPayment?: Record<string, unknown>;
555
+ }
556
+ /**
557
+ * Item-source variants understood by the manifest at v1. Mirrors the YAML
558
+ * shape documented in docs/specs/features/agent-zero-friction-onboarding/manifest-schema.md.
559
+ */
560
+ type OnboardingRequestSource = OnboardingRequestSourceAwesomeReadme | OnboardingRequestSourceWebSearch | OnboardingRequestSourceDataRepo | OnboardingRequestSourceInline;
561
+ interface OnboardingRequestSourceAwesomeReadme {
562
+ type: 'awesome-readme';
563
+ url: string;
564
+ expansionFactor?: number;
565
+ }
566
+ interface OnboardingRequestSourceWebSearch {
567
+ type: 'web-search';
568
+ query: string;
569
+ max?: number;
570
+ }
571
+ interface OnboardingRequestSourceDataRepo {
572
+ type: 'data-repo';
573
+ url: string;
574
+ mode?: 'copy' | 'link';
575
+ }
576
+ interface OnboardingRequestSourceInline {
577
+ type: 'inline';
578
+ items: ReadonlyArray<{
579
+ name: string;
580
+ url?: string;
581
+ categories?: ReadonlyArray<string>;
582
+ tags?: ReadonlyArray<string>;
583
+ description?: string;
584
+ }>;
585
+ }
586
+
587
+ type OnboardingStatus = 'received' | 'validating' | 'validated' | 'queued' | 'generating' | 'deployed' | 'failed' | 'rejected';
588
+ declare const ONBOARDING_TERMINAL_STATUSES: ReadonlyArray<OnboardingStatus>;
589
+ /**
590
+ * Whether an {@link OnboardingStatus} marks the end of the onboarding
591
+ * flow — i.e. the status will not transition further. Currently
592
+ * `'deployed'` (success), `'failed'` (generic error), and `'rejected'`
593
+ * (input refused upfront) per {@link ONBOARDING_TERMINAL_STATUSES}.
594
+ * Callers polling for completion should stop polling once this returns
595
+ * `true`.
596
+ *
597
+ * @param status - The status to test.
598
+ * @returns `true` when the onboarding flow has ended for this status.
599
+ */
600
+ declare function isTerminalOnboardingStatus(status: OnboardingStatus): boolean;
601
+
602
+ type RegisterWorkStatus = OnboardingStatus;
603
+ interface RegisterWorkResponse {
604
+ onboardingId: string;
605
+ workId: string;
606
+ status: RegisterWorkStatus;
607
+ statusUrl: string;
608
+ subdomain: string;
609
+ deploymentUrl?: string;
610
+ warnings?: ReadonlyArray<string>;
611
+ }
612
+ type RegisterWorkErrorCode = 'validation_error' | 'gh_repo_access_denied' | 'gh_credential_invalid' | 'gh_insufficient_scope_for_repo_creation' | 'manifest_missing' | 'manifest_invalid' | 'unsupported_capability' | 'repo_already_owned' | 'subdomain_taken' | 'rate_limited' | 'internal_error';
613
+ interface ManifestValidationError {
614
+ path: string;
615
+ message: string;
616
+ subcode?: string;
617
+ }
618
+ interface RegisterWorkErrorBody {
619
+ statusCode: number;
620
+ code: RegisterWorkErrorCode;
621
+ message: string;
622
+ errors?: ReadonlyArray<ManifestValidationError>;
623
+ }
624
+
625
+ type WebhookEvent = WebhookEventTerminal | WebhookEventManifestChanged | WebhookEventDeployFailed;
626
+ interface WebhookEventTerminal {
627
+ event: 'onboarding.terminal';
628
+ deliveryId: string;
629
+ occurredAt: string;
630
+ onboardingId: string;
631
+ workId: string;
632
+ status: Extract<OnboardingStatus, 'deployed' | 'failed' | 'rejected'>;
633
+ subdomain: string;
634
+ deploymentUrl?: string;
635
+ failureCode?: string;
636
+ failureMessage?: string;
637
+ }
638
+ interface WebhookEventManifestChanged {
639
+ event: 'work.regenerated';
640
+ deliveryId: string;
641
+ occurredAt: string;
642
+ workId: string;
643
+ commitSha: string;
644
+ }
645
+ interface WebhookEventDeployFailed {
646
+ event: 'work.deploy_failed';
647
+ deliveryId: string;
648
+ occurredAt: string;
649
+ workId: string;
650
+ failureCode: string;
651
+ failureMessage: string;
652
+ }
653
+
654
+ interface WorksManifestMetadata {
655
+ name: string;
656
+ slug?: string;
657
+ description?: string;
658
+ subdomain?: string;
659
+ }
660
+ interface WorksManifestSpec {
661
+ pipeline: string;
662
+ domain: 'software' | 'ecommerce' | 'services' | 'general';
663
+ taxonomy?: {
664
+ categories?: ReadonlyArray<string>;
665
+ tags?: ReadonlyArray<string>;
666
+ lockTaxonomy?: boolean;
667
+ };
668
+ items: {
669
+ sources: ReadonlyArray<OnboardingRequestSource>;
670
+ };
671
+ generators?: {
672
+ aiProvider?: string;
673
+ searchProvider?: string;
674
+ screenshot?: string;
675
+ model?: string;
676
+ };
677
+ deployment?: {
678
+ target?: string;
679
+ customDomain?: string;
680
+ };
681
+ output?: WorksManifestOutput;
682
+ }
683
+ interface WorksManifestOutput {
684
+ repos?: {
685
+ website?: 'managed' | 'none';
686
+ awesomeList?: 'managed' | 'none';
687
+ };
688
+ llmsTxt?: boolean;
689
+ itemsJson?: boolean;
690
+ markerFile?: string;
691
+ }
692
+ interface WorksManifestV1 {
693
+ apiVersion: 'works.ever.works/v1';
694
+ kind: 'Work';
695
+ metadata: WorksManifestMetadata;
696
+ spec: WorksManifestSpec;
697
+ }
698
+
699
+ /**
700
+ * Wire format for the onboarding wizard's server-side state.
701
+ *
702
+ * Persisted on `users.onboarding_state` (jsonb / simple-json). The web
703
+ * wizard loads this on dashboard mount and PATCHes it on every step
704
+ * transition so progress survives a cookie wipe or device switch.
705
+ */
706
+ type OnboardingAiChoice = 'ever-works' | 'openrouter' | 'claude-code' | 'codex' | 'gemini' | 'grok';
707
+ type OnboardingStorageChoice = 'ever-works-git' | 'user-github' | 'user-gitlab' | 'user-git';
708
+ /**
709
+ * Where a Work's database lives: the platform-managed "Ever Works DB" (shared,
710
+ * auto-provisioned) or a bring-your-own custom database (connection details are
711
+ * entered on the Deploy page after the Work is created — never stored in this
712
+ * onboarding-state blob).
713
+ */
714
+ type OnboardingDbChoice = 'ever-works-db' | 'custom';
715
+ type OnboardingDeployChoice = 'ever-works' | 'vercel' | 'k8s';
716
+ /**
717
+ * A8 — where the user actually runs Ever Works, and therefore what their
718
+ * first run should look like.
719
+ *
720
+ * The other four buckets all ask "which provider": AI, storage, database,
721
+ * deployment. None of them ask the question a desktop-first user is actually
722
+ * living — "is this thing running on my machine, and are my machines part of
723
+ * it?" — so those users landed on a cloud-shaped first run and had to find
724
+ * Fleet and the node apps on their own.
725
+ *
726
+ * - `cloud` the hosted platform (default; unchanged behaviour)
727
+ * - `desktop` the all-in-one desktop app supervising a local stack
728
+ * - `own-nodes` the platform runs elsewhere, but this person's own
729
+ * machines execute the work (Fleet + node apps)
730
+ */
731
+ type OnboardingDesktopChoice = 'cloud' | 'desktop' | 'own-nodes';
732
+ /**
733
+ * Wave 11 — "What do you do" onboarding step. A generic option row:
734
+ * stable kebab-case id + English display label + one-line description.
735
+ * The web wizard renders these through i18n keys keyed by `id`; the
736
+ * label/description here are the canonical English fallback used by
737
+ * non-web surfaces (desktop embeds, API docs).
738
+ */
739
+ interface OnboardingProfileOption<Id extends string = string> {
740
+ readonly id: Id;
741
+ readonly label: string;
742
+ readonly description: string;
743
+ }
744
+ /**
745
+ * Roles for the "What do you do" step (multi-select — picking several
746
+ * or all is fine). Selections are hints for suggestion surfaces, never
747
+ * gates: nothing is hidden based on them.
748
+ */
749
+ declare const ROLE_OPTIONS: readonly [{
750
+ readonly id: "founder-ceo";
751
+ readonly label: "Founder / CEO";
752
+ readonly description: "I run the company and wear many hats";
753
+ }, {
754
+ readonly id: "engineering";
755
+ readonly label: "Engineering";
756
+ readonly description: "I build and ship software";
757
+ }, {
758
+ readonly id: "product";
759
+ readonly label: "Product";
760
+ readonly description: "I define what we build and why";
761
+ }, {
762
+ readonly id: "marketing";
763
+ readonly label: "Marketing";
764
+ readonly description: "I grow awareness, content, and campaigns";
765
+ }, {
766
+ readonly id: "sales";
767
+ readonly label: "Sales";
768
+ readonly description: "I find, pitch, and close customers";
769
+ }, {
770
+ readonly id: "consultant";
771
+ readonly label: "Consultant";
772
+ readonly description: "I deliver projects and advice for clients";
773
+ }, {
774
+ readonly id: "research";
775
+ readonly label: "Research";
776
+ readonly description: "I investigate, analyze, and synthesize";
777
+ }, {
778
+ readonly id: "operations";
779
+ readonly label: "Operations";
780
+ readonly description: "I keep the business running smoothly";
781
+ }, {
782
+ readonly id: "support";
783
+ readonly label: "Support";
784
+ readonly description: "I help customers succeed and resolve issues";
785
+ }, {
786
+ readonly id: "finance";
787
+ readonly label: "Finance";
788
+ readonly description: "I manage budgets, billing, and reporting";
789
+ }, {
790
+ readonly id: "hr";
791
+ readonly label: "HR";
792
+ readonly description: "I hire, onboard, and support our people";
793
+ }, {
794
+ readonly id: "legal";
795
+ readonly label: "Legal";
796
+ readonly description: "I handle contracts, compliance, and policy";
797
+ }, {
798
+ readonly id: "education";
799
+ readonly label: "Education";
800
+ readonly description: "I teach, train, or create learning content";
801
+ }, {
802
+ readonly id: "other";
803
+ readonly label: "Other";
804
+ readonly description: "Something else — tell us more later";
805
+ }];
806
+ type OnboardingRoleId = (typeof ROLE_OPTIONS)[number]['id'];
807
+ /** Team size for the "What do you do" step (single-select). */
808
+ declare const TEAM_SIZE_OPTIONS: readonly [{
809
+ readonly id: "solo";
810
+ readonly label: "Solo";
811
+ readonly description: "Just me";
812
+ }, {
813
+ readonly id: "small-2-10";
814
+ readonly label: "Small (2–10)";
815
+ readonly description: "2–10 people";
816
+ }, {
817
+ readonly id: "mid-11-50";
818
+ readonly label: "Mid (11–50)";
819
+ readonly description: "11–50 people";
820
+ }, {
821
+ readonly id: "large-51-200";
822
+ readonly label: "Large (51–200)";
823
+ readonly description: "51–200 people";
824
+ }, {
825
+ readonly id: "enterprise-200-plus";
826
+ readonly label: "Enterprise (200+)";
827
+ readonly description: "More than 200 people";
828
+ }];
829
+ type OnboardingTeamSizeId = (typeof TEAM_SIZE_OPTIONS)[number]['id'];
830
+ /**
831
+ * Wave 11 — persisted answers of the "What do you do" step. Values are
832
+ * plain strings (not the narrowed id unions) so older clients keep
833
+ * round-tripping payloads written by newer ones; consumers validate
834
+ * against ROLE_OPTIONS / TEAM_SIZE_OPTIONS and DROP unrecognised values
835
+ * (never default them).
836
+ */
837
+ interface OnboardingProfile {
838
+ readonly roles?: readonly string[];
839
+ readonly teamSize?: string;
840
+ }
841
+ interface OnboardingWizardStateV2 {
842
+ readonly version: 2;
843
+ readonly lastStep: number;
844
+ readonly ai: {
845
+ readonly choice: OnboardingAiChoice;
846
+ };
847
+ readonly storage: {
848
+ readonly choice: OnboardingStorageChoice;
849
+ };
850
+ readonly db: {
851
+ readonly choice: OnboardingDbChoice;
852
+ };
853
+ readonly deploy: {
854
+ readonly choice: OnboardingDeployChoice;
855
+ };
856
+ /**
857
+ * A8 — desktop-first bucket. Optional in the persisted shape so a state
858
+ * blob written before this bucket existed keeps round-tripping; readers
859
+ * fall back to {@link ONBOARDING_DEFAULT_STATE}'s `cloud`.
860
+ */
861
+ readonly desktop?: {
862
+ readonly choice: OnboardingDesktopChoice;
863
+ };
864
+ readonly skippedSteps: readonly string[];
865
+ readonly pluginsReviewed: boolean;
866
+ /**
867
+ * EW-617 G4: prompt carried over from the landing-page input
868
+ * (`ever.works/?prompt=…`) so the wizard's "Generate now" step can
869
+ * kick off generation without re-asking the user. Bounded by the
870
+ * same 5000-char limit as `CreateItemsGeneratorDto.prompt`.
871
+ */
872
+ readonly prompt?: string;
873
+ /** Wave 11 — optional "What do you do" answers (roles + team size). */
874
+ readonly profile?: OnboardingProfile;
875
+ }
876
+ /** Wire shape of `GET /api/onboarding/state`. */
877
+ interface OnboardingStateResponse {
878
+ readonly completedAt: string | null;
879
+ readonly dismissedAt: string | null;
880
+ readonly state: OnboardingWizardStateV2;
881
+ /**
882
+ * Audit item A53 — the ORGANIZATION-level mirror of the "What do you
883
+ * do" answers, persisted on `organization_onboarding_profiles`.
884
+ *
885
+ * `state.profile` above stays the per-user answer that drives the
886
+ * wizard UI; this field is the org-wide read model (last writer
887
+ * inside the organization wins) so team-shaped suggestion surfaces
888
+ * can reason about the whole organization rather than one member.
889
+ *
890
+ * `null` when the request resolved no organization scope (e.g. a
891
+ * user who has not created an Organization yet) or when nobody in
892
+ * the organization has answered the step. Optional so older clients
893
+ * and the web fallback payloads keep type-checking unchanged.
894
+ */
895
+ readonly organizationProfile?: OnboardingProfile | null;
896
+ }
897
+ /**
898
+ * Wire shape of `PATCH /api/onboarding/state`. All fields are optional;
899
+ * `state` accepts a partial object that the server deep-merges with the
900
+ * persisted version-2 shape (re-using existing values for missing keys).
901
+ *
902
+ * Security: `state.prompt` MUST be validated server-side with
903
+ * `@MaxLength(5000)` in `OnboardingStatePatchInnerDto` before it is
904
+ * persisted or forwarded to any LLM call. Do NOT wire user-controlled
905
+ * prompt text into agent generation without output constraints/sandboxing.
906
+ */
907
+ interface OnboardingStatePatchRequest {
908
+ readonly state?: Partial<{
909
+ readonly lastStep: number;
910
+ readonly ai: Partial<{
911
+ choice: OnboardingAiChoice;
912
+ }>;
913
+ readonly storage: Partial<{
914
+ choice: OnboardingStorageChoice;
915
+ }>;
916
+ readonly db: Partial<{
917
+ choice: OnboardingDbChoice;
918
+ }>;
919
+ readonly deploy: Partial<{
920
+ choice: OnboardingDeployChoice;
921
+ }>;
922
+ /** A8 — desktop-first bucket. */
923
+ readonly desktop: Partial<{
924
+ choice: OnboardingDesktopChoice;
925
+ }>;
926
+ readonly skippedSteps: readonly string[];
927
+ readonly pluginsReviewed: boolean;
928
+ /** Max 5 000 chars — enforced by `@MaxLength(5000)` in the server DTO. */
929
+ readonly prompt: string;
930
+ /**
931
+ * Wave 11 — "What do you do" answers. `roles` entries are validated
932
+ * server-side against ROLE_OPTIONS ids, `teamSize` against
933
+ * TEAM_SIZE_OPTIONS ids (unknown values are rejected with 400).
934
+ */
935
+ readonly profile: {
936
+ readonly roles?: readonly string[];
937
+ readonly teamSize?: string;
938
+ };
939
+ }>;
940
+ }
941
+ /** Wire shape of `GET /api/onboarding/catalog`. */
942
+ interface OnboardingCatalogResponse {
943
+ readonly ai: ReadonlyArray<OnboardingCard<OnboardingAiChoice>>;
944
+ readonly storage: ReadonlyArray<OnboardingCard<OnboardingStorageChoice>>;
945
+ readonly db: ReadonlyArray<OnboardingCard<OnboardingDbChoice>>;
946
+ readonly deploy: ReadonlyArray<OnboardingCard<OnboardingDeployChoice>>;
947
+ /** A8 — cards for the desktop-first bucket. */
948
+ readonly desktop: ReadonlyArray<OnboardingCard<OnboardingDesktopChoice>>;
949
+ /** Plugins to surface in the "Plugins & Integrations" wizard step. */
950
+ readonly plugins: ReadonlyArray<OnboardingPluginCard>;
951
+ }
952
+ interface OnboardingCard<Choice extends string> {
953
+ readonly choice: Choice;
954
+ readonly title: string;
955
+ readonly description: string;
956
+ readonly default: boolean;
957
+ readonly available: boolean;
958
+ readonly badges: ReadonlyArray<OnboardingCardBadge>;
959
+ /** Plugin id behind this card, when applicable. */
960
+ readonly pluginId?: string;
961
+ }
962
+ type OnboardingCardBadge = 'default' | 'byok' | 'planned';
963
+ interface OnboardingPluginCard {
964
+ readonly pluginId: string;
965
+ readonly name: string;
966
+ readonly category: string;
967
+ readonly description: string;
968
+ readonly onboardingPriority: number;
969
+ }
970
+ declare const ONBOARDING_DEFAULT_STATE: OnboardingWizardStateV2;
971
+ /**
972
+ * A8 — first-run guidance implied by the desktop bucket. Consumed by the web
973
+ * wizard's final step (and any other surface that wants to point a user at the
974
+ * right next thing) so "which shape am I running" actually changes what the
975
+ * user is told to do next, rather than being a stored preference nobody reads.
976
+ */
977
+ interface OnboardingDesktopNextStep {
978
+ readonly choice: OnboardingDesktopChoice;
979
+ readonly title: string;
980
+ readonly description: string;
981
+ /** In-app route to send the user to, when there is one. */
982
+ readonly href?: string;
983
+ }
984
+ declare const ONBOARDING_DESKTOP_NEXT_STEPS: Readonly<Record<OnboardingDesktopChoice, OnboardingDesktopNextStep>>;
985
+ /** The guidance for a bucket choice, defaulting to the cloud path. */
986
+ declare function desktopNextStep(choice: OnboardingDesktopChoice | undefined): OnboardingDesktopNextStep;
987
+
988
+ /**
989
+ * AW-20 P1 — the roster vocabulary shared by the API, the agent package
990
+ * and the web wizard step.
991
+ *
992
+ * A **roster** is not a new entity: it is the set of Agents the platform
993
+ * provisions for one person in one workspace scope, each carrying a
994
+ * **lane**. Everything here is a closed vocabulary so the wizard, the
995
+ * provisioning service and the DTO validators cannot drift apart — the
996
+ * same trick `ROLE_OPTIONS` / `TEAM_SIZE_OPTIONS` already use one file
997
+ * over.
998
+ */
999
+ /**
1000
+ * A lane is a short, stable key naming the area of work one Agent owns
1001
+ * (FR-26). Seven ship with the build, and the catalogue is capped at 12
1002
+ * (FR-30) so the "add a lane" menu stays a menu rather than a directory.
1003
+ *
1004
+ * 🛑 A lane is a **label, not a permission** (FR-27). It grants nothing,
1005
+ * restricts nothing, and must never be consulted by an authorization
1006
+ * decision. It exists so a surface can ask "who owns research here?" and
1007
+ * get a stable answer instead of grepping free-text titles.
1008
+ */
1009
+ declare const ROSTER_LANE_KEYS: readonly ["coordination", "research", "content", "outreach", "visibility", "social", "market-watch"];
1010
+ type RosterLaneKey = (typeof ROSTER_LANE_KEYS)[number];
1011
+ /**
1012
+ * Named starting rosters. Content that ships with the build, not data:
1013
+ * a blueprint changes when we deploy, never when a user acts, and it
1014
+ * must mean the same thing in a bug report as it does in production.
1015
+ */
1016
+ declare const ROSTER_BLUEPRINT_SLUGS: readonly ["general", "growth", "revenue", "insight", "solo-starter"];
1017
+ type RosterBlueprintSlug = (typeof ROSTER_BLUEPRINT_SLUGS)[number];
1018
+ /**
1019
+ * The most lanes one provisioning run will set up (FR-6). A blueprint
1020
+ * may declare at most this many, and a user adding lanes by hand stops
1021
+ * here too — more agents than this in one go is a fleet, not a start.
1022
+ */
1023
+ declare const ROSTER_MAX_LANES = 8;
1024
+ /** Longest agent name the roster step accepts, in characters (FR-7). */
1025
+ declare const ROSTER_NAME_MAX = 60;
1026
+
1027
+ /**
1028
+ * AW-20 — the first-hour vocabulary: what a new owner still has to do,
1029
+ * and what happened the last time we set their agents up.
1030
+ *
1031
+ * The milestone enum lands with P1 because the provisioning record it
1032
+ * sits beside is written by P1's roster run; the checklist surfaces that
1033
+ * read these milestones are P2. Nothing here is persisted twice: the
1034
+ * provisioning record is one JSON column on the checklist row.
1035
+ */
1036
+
1037
+ /**
1038
+ * The five first-hour milestones, in the order they are shown (FR-34).
1039
+ * Order is part of the contract — the card renders this array.
1040
+ */
1041
+ declare const ONBOARDING_MILESTONES: readonly ["connectProvider", "meetAgents", "shipTask", "resolveDecision", "scheduleJob"];
1042
+ type OnboardingMilestoneKey = (typeof ONBOARDING_MILESTONES)[number];
1043
+ /** `pending → done` is one-way; `pending ⇄ skipped` is reversible (FR-35, FR-40). */
1044
+ declare const MILESTONE_STATUSES: readonly ["pending", "done", "skipped"];
1045
+ type MilestoneStatus = (typeof MILESTONE_STATUSES)[number];
1046
+ /**
1047
+ * One milestone's state. A milestone is never marked done on the
1048
+ * client's word (FR-36): `evidenceKind` / `evidenceId` record which
1049
+ * platform fact satisfied it, so "how do I know this is true?" has an
1050
+ * answer that is not "the browser said so".
1051
+ */
1052
+ interface MilestoneRecord {
1053
+ readonly status: MilestoneStatus;
1054
+ readonly completedAt?: string | null;
1055
+ /** What satisfied it: 'connection' | 'roster' | 'run' | 'approval' | 'escalation' | 'schedule'. */
1056
+ readonly evidenceKind?: string | null;
1057
+ /** Opaque id of the satisfying object. Never rendered; used for the "what completed it" line. */
1058
+ readonly evidenceId?: string | null;
1059
+ /**
1060
+ * FR-59 degradation flag. True when this milestone's completion fact
1061
+ * could not be read on the last evaluation. The milestone stays
1062
+ * `pending` and the row renders a quiet "couldn't check" marker —
1063
+ * an unreadable fact must never be allowed to look like a done one,
1064
+ * and must never fail the whole checklist.
1065
+ */
1066
+ readonly unknown?: boolean;
1067
+ }
1068
+ /**
1069
+ * Provisioning run states (FR-10). There is no other state: a record
1070
+ * that is not one of these is a bug, not a new case to handle.
1071
+ */
1072
+ declare const ROSTER_PROVISION_STATES: readonly ["idle", "queued", "creating", "binding", "ready", "partial", "failed"];
1073
+ type RosterProvisionState = (typeof ROSTER_PROVISION_STATES)[number];
1074
+ /**
1075
+ * What happened to one lane (FR-11). `reused` is a success: the point of
1076
+ * idempotent provisioning is that a second run fills gaps rather than
1077
+ * creating a second "Research".
1078
+ */
1079
+ declare const LANE_OUTCOMES: readonly ["pending", "created", "reused", "skippedNoSeat", "failed"];
1080
+ type LaneOutcome = (typeof LANE_OUTCOMES)[number];
1081
+ /** Why one lane failed. Closed vocabulary — the UI maps each to its own copy. */
1082
+ declare const LANE_FAILURE_REASONS: readonly ["nameUnavailable", "noSeat", "permissionDenied", "timedOut", "unknown"];
1083
+ type LaneFailureReason = (typeof LANE_FAILURE_REASONS)[number];
1084
+ /** One lane's outcome inside a provisioning run. */
1085
+ interface RosterLaneResult {
1086
+ readonly laneKey: RosterLaneKey;
1087
+ readonly templateSlug: string;
1088
+ readonly requestedName: string;
1089
+ readonly outcome: LaneOutcome;
1090
+ readonly agentId?: string | null;
1091
+ /** Set when a numeric suffix was needed to find a free name (FR-18). */
1092
+ readonly finalName?: string | null;
1093
+ readonly failureReason?: LaneFailureReason | null;
1094
+ /** Skills that could not be attached (FR-23). A warning, never a failure. */
1095
+ readonly skillWarnings?: readonly string[];
1096
+ }
1097
+ /**
1098
+ * The current or last roster provisioning attempt. Persisted as one JSON
1099
+ * object on the checklist row rather than its own table: it is bounded,
1100
+ * one-to-one with a row that already exists, written only by
1101
+ * provisioning and read only in the moments around it.
1102
+ */
1103
+ interface RosterProvisionRecord {
1104
+ readonly runId: string;
1105
+ readonly blueprintSlug: RosterBlueprintSlug;
1106
+ readonly state: RosterProvisionState;
1107
+ readonly startedAt: string;
1108
+ readonly finishedAt?: string | null;
1109
+ readonly lanes: readonly RosterLaneResult[];
1110
+ }
1111
+
1112
+ /**
1113
+ * Role-driven starter seeding for the onboarding "What do you do" step.
1114
+ *
1115
+ * The first cut of this feature resolved suggestions IN THE BROWSER: the
1116
+ * step fetched the whole prebuilt-agent catalog and intersected
1117
+ * `suggestedRoles` client-side. Three things were wrong with that.
1118
+ *
1119
+ * 1. Coverage was accidental. Only the roles that happened to appear in
1120
+ * a go-to-market template's `suggestedRoles` produced anything —
1121
+ * 3 of the 14 roles the step actually offers. The other 11 selected
1122
+ * a role and were shown nothing, which reads as "we have nothing
1123
+ * for you" rather than "nobody wrote the mapping".
1124
+ * 2. It was Agents-only. A role implies a starting KIT — the agents to
1125
+ * activate AND the skills that make them useful — and the skills
1126
+ * half simply did not exist.
1127
+ * 3. The mapping lived in the client bundle, so every non-web surface
1128
+ * (desktop shell, chat, API consumers) had no way to ask "what
1129
+ * should a Marketing person start with?".
1130
+ *
1131
+ * The mapping is therefore server-side (`@ever-works/agent/agents`,
1132
+ * `role-seeding.ts`), exposed over `/api/onboarding/suggestions`, and
1133
+ * pinned by a spec that fails if ANY role in `ROLE_OPTIONS` is missing.
1134
+ * These are the wire shapes for that surface.
1135
+ */
1136
+ /** One prebuilt Agent template offered for the selected roles. */
1137
+ interface OnboardingSeedAgentSuggestion {
1138
+ /** Template slug — the id `POST /api/agents/from-template/:slug` takes. */
1139
+ readonly slug: string;
1140
+ readonly name: string;
1141
+ readonly title: string;
1142
+ readonly description: string;
1143
+ /** Template category, e.g. `marketing` / `sales` / `ops`. */
1144
+ readonly category: string;
1145
+ /** Role ids (from `ROLE_OPTIONS`) that caused this template to surface. */
1146
+ readonly matchedRoles: readonly string[];
1147
+ }
1148
+ /** One first-party Skill offered for the selected roles. */
1149
+ interface OnboardingSeedSkillSuggestion {
1150
+ /** Skill catalog slug. */
1151
+ readonly slug: string;
1152
+ readonly title: string;
1153
+ readonly description: string;
1154
+ /** Go-to-market stage the Skill powers. */
1155
+ readonly stage: string;
1156
+ /** Role ids (from `ROLE_OPTIONS`) that caused this Skill to surface. */
1157
+ readonly matchedRoles: readonly string[];
1158
+ }
1159
+ /**
1160
+ * Wire shape of `GET /api/onboarding/suggestions`.
1161
+ *
1162
+ * `roles` echoes the RECOGNISED subset of the request (unknown ids are
1163
+ * dropped, never defaulted, matching how the wizard state validates its
1164
+ * own `profile.roles`). An empty `roles` yields empty suggestion lists
1165
+ * rather than a "here is everything" dump.
1166
+ */
1167
+ interface OnboardingSeedSuggestionsResponse {
1168
+ readonly roles: readonly string[];
1169
+ /** Ids that were sent but are not in `ROLE_OPTIONS` — echoed so the caller can notice a typo. */
1170
+ readonly unknownRoles: readonly string[];
1171
+ readonly agents: readonly OnboardingSeedAgentSuggestion[];
1172
+ readonly skills: readonly OnboardingSeedSkillSuggestion[];
1173
+ }
1174
+ /**
1175
+ * Request body of `POST /api/onboarding/suggestions/seed`.
1176
+ *
1177
+ * `roles` is optional: omitted, the server uses the roles already saved
1178
+ * on the caller's onboarding state, so the client never has to be the
1179
+ * authority on what the user picked.
1180
+ */
1181
+ interface OnboardingSeedRequest {
1182
+ readonly roles?: readonly string[];
1183
+ }
1184
+ /** Per-template outcome of a seeding run. */
1185
+ type OnboardingSeedOutcome = 'created' | 'already-exists' | 'failed';
1186
+ interface OnboardingSeedResultEntry {
1187
+ readonly slug: string;
1188
+ readonly outcome: OnboardingSeedOutcome;
1189
+ /** Id of the Agent created by THIS run; null for every other outcome. */
1190
+ readonly agentId: string | null;
1191
+ /** Short, non-sensitive reason — present only for `failed`. */
1192
+ readonly reason?: string;
1193
+ }
1194
+ /**
1195
+ * Wire shape of `POST /api/onboarding/suggestions/seed`.
1196
+ *
1197
+ * Seeding is idempotent and best-effort per template: a template that
1198
+ * is already activated reports `already-exists` instead of failing the
1199
+ * whole call, so re-running the step never produces duplicates and a
1200
+ * single bad template never blocks the rest of the kit.
1201
+ */
1202
+ interface OnboardingSeedResponse {
1203
+ readonly roles: readonly string[];
1204
+ readonly agents: readonly OnboardingSeedResultEntry[];
1205
+ /** Skills recommended alongside the seeded agents (informational). */
1206
+ readonly skills: readonly OnboardingSeedSkillSuggestion[];
1207
+ readonly createdCount: number;
1208
+ readonly skippedCount: number;
1209
+ readonly failedCount: number;
1210
+ }
1211
+
1212
+ /**
1213
+ * EW-628 data-repo instant-sync — wire-format contract for the activity
1214
+ * row `details` payload emitted by the API and consumed by the web
1215
+ * `SyncEventRow` component.
1216
+ *
1217
+ * Spec: `docs/specs/features/data-repo-instant-sync/spec.md` §5.6.
1218
+ *
1219
+ * The discriminated union is the canonical source of truth for both
1220
+ * sides — `apps/api/src/data-sync/data-sync.service.ts` writes it into
1221
+ * `activity_log.details`, and `apps/web/src/components/works/detail/
1222
+ * activity/SyncEvent.types.ts` re-exports it as `SyncEvent` so the
1223
+ * row renderer's exhaustive switch stays in lock-step.
1224
+ *
1225
+ * `kind` (not `status`) discriminates row variants — the activity-feed
1226
+ * convention reserves `status` for HTTP / pipeline lifecycle values
1227
+ * (`COMPLETED` / `FAILED` / `CANCELLED`), which live on the parent
1228
+ * `activity_log` row.
1229
+ */
1230
+ /** Which transport surfaced the sync attempt. */
1231
+ type SyncEventSource = 'webhook' | 'poll' | 'manual';
1232
+ /**
1233
+ * Skip reasons the dispatcher or the three gates emit. Locked to a
1234
+ * small literal union so dashboards can pivot on it without parsing
1235
+ * free-form text.
1236
+ */
1237
+ type SyncEventSkipReason = 'retry-backoff' | 'sync-in-progress' | 'generation-in-progress' | 'no-changes' | 'app-not-installed-and-no-credentials';
1238
+ /**
1239
+ * Failure classes the render gate maps caught errors to. The set is
1240
+ * deliberately small — adding a new class is a deliberate schema
1241
+ * decision, not an autopilot fallback. `unknown` is the explicit
1242
+ * fallback when nothing matches.
1243
+ */
1244
+ type SyncEventErrorClass = 'data-repo-unreachable' | 'main-repo-push-rejected' | 'work-not-found' | 'timeout' | 'unknown';
1245
+ interface SyncEventSuccess {
1246
+ kind: 'success';
1247
+ source: SyncEventSource;
1248
+ beforeSha?: string;
1249
+ afterSha?: string;
1250
+ filesChanged: number;
1251
+ durationMs?: number;
1252
+ }
1253
+ interface SyncEventSkipped {
1254
+ kind: 'skipped';
1255
+ source: SyncEventSource;
1256
+ reason: SyncEventSkipReason;
1257
+ }
1258
+ interface SyncEventFailed {
1259
+ kind: 'failed';
1260
+ source: SyncEventSource;
1261
+ errorClass: SyncEventErrorClass;
1262
+ errorTail: string;
1263
+ }
1264
+ /**
1265
+ * The discriminated union the API writes into `activity_log.details`
1266
+ * for every `data_sync_*` row, and the web reads back to render the
1267
+ * `SyncEventRow`.
1268
+ */
1269
+ type SyncEventPayload = SyncEventSuccess | SyncEventSkipped | SyncEventFailed;
1270
+ /** Narrow `kind` values used as React keys + telemetry labels. */
1271
+ type SyncEventKind = SyncEventPayload['kind'];
1272
+
1273
+ /**
1274
+ * EW-658 (Tenants & Organizations Phase 6) — wire-types for the
1275
+ * Organization-create / list / update / upgrade-from-account API
1276
+ * surface.
1277
+ *
1278
+ * Plain TypeScript interfaces so the API package and the web package
1279
+ * speak the same shape over the wire without dragging NestJS / TypeORM
1280
+ * decorators across the workspace boundary.
1281
+ */
1282
+
1283
+ interface CreateOrganizationRequest {
1284
+ /** Display name. 1-200 chars. */
1285
+ name: string;
1286
+ /** Optional slug override. If omitted, allocated from `name`. */
1287
+ slug?: string;
1288
+ /**
1289
+ * PR-6 (domain-model evolution §23.5) — optional company vision
1290
+ * statement. Trimmed + capped at 5000 chars server-side; empty /
1291
+ * whitespace-only collapses to null.
1292
+ */
1293
+ vision?: string | null;
1294
+ }
1295
+ /**
1296
+ * EW-662 (Tenants & Organizations Phase 10) — body for
1297
+ * `POST /api/organizations/register-company`.
1298
+ *
1299
+ * Driven by the Company chip on `+ New`. The service hard-codes
1300
+ * `registrationProvider = 'manual'` and `registrationStatus =
1301
+ * 'registered'` for v1 (Stripe Atlas integration is deferred); the
1302
+ * client only supplies the user-visible fields.
1303
+ */
1304
+ interface RegisterCompanyRequest {
1305
+ /** Display name. 1-200 chars. */
1306
+ name: string;
1307
+ /** Registered legal name. Defaults to `name` when omitted. */
1308
+ legalName?: string;
1309
+ /** ISO 3166-1 alpha-2 country code (e.g. `'US'`). */
1310
+ countryCode?: string;
1311
+ /** Optional slug override. If omitted, allocated from `name`. */
1312
+ slug?: string;
1313
+ }
1314
+ interface UpdateOrganizationRequest {
1315
+ displayName?: string;
1316
+ legalName?: string;
1317
+ countryCode?: string;
1318
+ /**
1319
+ * PR-6 — company vision. Omit to leave unchanged; explicit `null`
1320
+ * clears it. Any present value (including `null`) bumps
1321
+ * `visionUpdatedAt` to now.
1322
+ */
1323
+ vision?: string | null;
1324
+ /**
1325
+ * Merge-policy matrix (Wave 3, D4) — the organization-scoped PARTIAL.
1326
+ * Omit to leave unchanged; explicit `null` clears the override so
1327
+ * everything inherits the tenant, then the platform default. Fields
1328
+ * omitted INSIDE the object inherit individually.
1329
+ */
1330
+ mergePolicy?: MergePolicyOverride | null;
1331
+ /**
1332
+ * AW-15 — connection safety settings. Omit to leave unchanged; explicit
1333
+ * `null` resets every setting to its default. Today one setting:
1334
+ * `requireHttpsForCredentials` ("Require https for connection
1335
+ * credentials", default off).
1336
+ */
1337
+ connectionPolicy?: OrganizationConnectionPolicy | null;
1338
+ }
1339
+ interface OrganizationResponse {
1340
+ id: string;
1341
+ tenantId: string;
1342
+ slug: string;
1343
+ legalName: string | null;
1344
+ displayName: string | null;
1345
+ countryCode: string | null;
1346
+ registrationProvider: string | null;
1347
+ registrationStatus: string | null;
1348
+ linkedWorkId: string | null;
1349
+ /** PR-6 — company vision statement (null = never set / cleared). */
1350
+ vision: string | null;
1351
+ /** PR-6 — ISO timestamp of the last vision change (null = never set). */
1352
+ visionUpdatedAt: string | null;
1353
+ /**
1354
+ * Merge-policy matrix (Wave 3, D4) — the PARTIAL stored on this row.
1355
+ * `null` means the organization declares nothing. OPTIONAL rather than
1356
+ * required: the field is additive, so a response from an API build that
1357
+ * predates it simply omits the key, and every consumer already has to
1358
+ * treat "absent" and "null" the same way (both mean "inherit").
1359
+ *
1360
+ * The EFFECTIVE policy is a fold of four scopes and is never derivable
1361
+ * from this field alone — read `GET /api/merge-policy/resolve` for that.
1362
+ */
1363
+ mergePolicy?: MergePolicyOverride | null;
1364
+ /**
1365
+ * AW-15 — the stored connection safety settings. `null` / absent = every
1366
+ * default (literal connection credentials over plain http are allowed,
1367
+ * with a warning).
1368
+ */
1369
+ connectionPolicy?: OrganizationConnectionPolicy | null;
1370
+ createdAt: string;
1371
+ updatedAt: string;
1372
+ }
1373
+ interface CheckSlugAvailabilityResponse {
1374
+ /** True iff the slug collides with neither `users.slug` nor `organizations.slug`. */
1375
+ available: boolean;
1376
+ /** Echo of the normalized form of the input (for the caller to display). */
1377
+ normalized: string;
1378
+ /** If unavailable, a next-free `-N` suggestion. Omitted when available. */
1379
+ suggestion?: string;
1380
+ }
1381
+ interface UpgradeFromAccountResponse {
1382
+ organizationId: string;
1383
+ tenantId: string;
1384
+ /** Total Tier A rows updated across all enumerated tables. */
1385
+ tierARowsUpdated: number;
1386
+ /** Total Tier B rows updated. */
1387
+ tierBRowsUpdated: number;
1388
+ /**
1389
+ * EW-663 (Phase 11 follow-up) — total Tier C rows backfilled via the
1390
+ * parent-FK join walk (e.g. `conversation_messages` whose parent
1391
+ * `conversations` belongs to the user). Zero before Phase 11 ships
1392
+ * and on second-call idempotency.
1393
+ */
1394
+ tierCRowsUpdated: number;
1395
+ }
1396
+ /**
1397
+ * Error code returned with 409 Conflict when `upgrade-from-account` is
1398
+ * called after the user has created additional Organizations (spec §5.2,
1399
+ * "first-Org guard"). The endpoint is only callable while the user has
1400
+ * **exactly one** Organization under their Tenant.
1401
+ */
1402
+ declare const UPGRADE_NOT_AVAILABLE_AFTER_MULTIPLE_ORGS: "UPGRADE_NOT_AVAILABLE_AFTER_MULTIPLE_ORGS";
1403
+
1404
+ /** Reserved transport contract; Organization slugs can never collide with this value. */
1405
+ declare const ACTIVE_SCOPE_PERSONAL_SENTINEL: "@personal";
1406
+ declare const ACTIVE_SCOPE_API_HEADER: "x-scope-slug";
1407
+ declare const ACTIVE_SCOPE_BROWSER_HEADER: "x-ever-workspace";
1408
+ declare const ACTIVE_SCOPE_RESPONSE_PROPERTIES: {
1409
+ tenantId: {
1410
+ type: "string";
1411
+ format: "uuid";
1412
+ nullable: true;
1413
+ };
1414
+ organizationId: {
1415
+ type: "string";
1416
+ format: "uuid";
1417
+ nullable: true;
1418
+ };
1419
+ organizationSlug: {
1420
+ type: "string";
1421
+ nullable: true;
1422
+ };
1423
+ };
1424
+ type ActiveScopeResponseKey = keyof typeof ACTIVE_SCOPE_RESPONSE_PROPERTIES;
1425
+ /** Runtime OpenAPI schema and source of truth for the active-scope response keys. */
1426
+ declare const ACTIVE_SCOPE_RESPONSE_SCHEMA: {
1427
+ type: "object";
1428
+ properties: {
1429
+ tenantId: {
1430
+ type: "string";
1431
+ format: "uuid";
1432
+ nullable: true;
1433
+ };
1434
+ organizationId: {
1435
+ type: "string";
1436
+ format: "uuid";
1437
+ nullable: true;
1438
+ };
1439
+ organizationSlug: {
1440
+ type: "string";
1441
+ nullable: true;
1442
+ };
1443
+ };
1444
+ required: ActiveScopeResponseKey[];
1445
+ };
1446
+ /** Wire response shared by the API and every active-scope consumer. */
1447
+ type ActiveScopeResponse = {
1448
+ [Key in ActiveScopeResponseKey]: string | null;
1449
+ };
1450
+
1451
+ /**
1452
+ * Dynamic plugin distribution (EW-693).
1453
+ *
1454
+ * Per-replica install lifecycle for a distributable plugin. Distinct
1455
+ * from `state` (load-lifecycle) and `enabled` (per-user/per-work) so
1456
+ * the UI can show all three independently.
1457
+ *
1458
+ * - `available`: known in the catalog but not yet installed on this node.
1459
+ * - `installing`: currently being resolved / downloaded / placed.
1460
+ * - `installed`: present on disk and importable; may or may not be enabled.
1461
+ * - `error`: last install attempt failed; `installError` carries the reason.
1462
+ */
1463
+ type PluginInstallState = 'available' | 'installing' | 'installed' | 'error';
1464
+ /**
1465
+ * Source the plugin's code came from on this deployment. Denormalised
1466
+ * onto the row for listing; the manifest's `distribution` is the
1467
+ * source of truth for "could this plugin ever be installed at runtime?"
1468
+ */
1469
+ type PluginInstallSource = 'bundled' | 'registry';
1470
+ /**
1471
+ * Wire payload describing where a plugin sits in the install lifecycle.
1472
+ * Returned by `GET /plugins/:id/install-status` and embedded in the
1473
+ * plugin list / catalog responses (see {@link PluginCatalogEntry}).
1474
+ */
1475
+ interface PluginInstallStateDto {
1476
+ readonly pluginId: string;
1477
+ readonly installState: PluginInstallState;
1478
+ readonly source: PluginInstallSource;
1479
+ /** npm spec actually installed, e.g. `@ever-works/notion-extractor-plugin@1.2.0`. */
1480
+ readonly registrySpec?: string;
1481
+ readonly installedVersion?: string;
1482
+ /** Integrity used to verify the install (sha512 from the registry). */
1483
+ readonly integrity?: string;
1484
+ /** Last error message if `installState === 'error'`. */
1485
+ readonly installError?: string;
1486
+ readonly updatedAt?: string;
1487
+ }
1488
+
1489
+ /**
1490
+ * Dynamic plugin distribution (EW-693).
1491
+ *
1492
+ * A single entry in `GET /plugins/catalog` — the listable set of
1493
+ * distributable plugins. Manifest summary only (id/name/category/...)
1494
+ * + the local install state so the UI can render an "available"
1495
+ * card before the plugin has ever been instantiated.
1496
+ */
1497
+ interface PluginCatalogEntry {
1498
+ readonly pluginId: string;
1499
+ readonly name: string;
1500
+ readonly description: string;
1501
+ readonly category: string;
1502
+ readonly capabilities: readonly string[];
1503
+ readonly version: string;
1504
+ readonly distribution: 'core' | 'registry';
1505
+ /** npm package name (e.g. `@ever-works/notion-extractor-plugin`). */
1506
+ readonly packageName?: string;
1507
+ /** Most recent version published to the registry (catalog-side). */
1508
+ readonly latestVersion?: string;
1509
+ readonly homepage?: string;
1510
+ readonly author?: string;
1511
+ readonly deprecated?: boolean;
1512
+ /** Per-replica install state, merged from the local DB. */
1513
+ readonly install: PluginInstallStateDto;
1514
+ }
1515
+ /**
1516
+ * Catalog response envelope. Errors fetching the upstream catalog are
1517
+ * surfaced via {@link PluginCatalogResponse.fetchedAt} being absent
1518
+ * and {@link PluginCatalogResponse.degraded} being true, so the UI
1519
+ * can show "registry unreachable — only locally-known plugins listed".
1520
+ */
1521
+ interface PluginCatalogResponse {
1522
+ readonly entries: readonly PluginCatalogEntry[];
1523
+ readonly fetchedAt?: string;
1524
+ /** True when the registry call failed and entries reflect local state only. */
1525
+ readonly degraded?: boolean;
1526
+ readonly degradedReason?: string;
1527
+ }
1528
+ /**
1529
+ * Request body for `POST /plugins/:id/install`.
1530
+ *
1531
+ * - `version` is optional; when omitted the server resolves the
1532
+ * latest matching version pinned via the allowlist (or the
1533
+ * `@ever-works/*` package's `latest` dist-tag for first-party).
1534
+ * - `integrity` is optional; when provided the server MUST refuse
1535
+ * if the downloaded integrity does not match (FR-10).
1536
+ * - `source` lets a self-hoster prefer `github-packages` over the
1537
+ * default public npm mirror, when both are configured.
1538
+ */
1539
+ interface PluginInstallRequestDto {
1540
+ readonly version?: string;
1541
+ readonly integrity?: string;
1542
+ readonly source?: 'npm' | 'github-packages';
1543
+ }
1544
+ /**
1545
+ * Response body for `POST /plugins/:id/install` (sync 202-accepted
1546
+ * envelope). The actual install runs asynchronously; clients poll
1547
+ * `GET /plugins/:id/install-status` for terminal state.
1548
+ */
1549
+ interface PluginInstallResponseDto {
1550
+ readonly pluginId: string;
1551
+ readonly install: PluginInstallStateDto;
1552
+ }
1553
+
1554
+ /**
1555
+ * Dynamic plugin distribution (EW-693).
1556
+ *
1557
+ * Admin-managed list of non-first-party packages permitted for
1558
+ * runtime install. First-party `@ever-works/*` is implicitly allowed
1559
+ * (no row required); everything else must match an enabled
1560
+ * `plugin_allowlist` row by name + version range, otherwise the
1561
+ * installer refuses the package BEFORE any network fetch (FR-11).
1562
+ */
1563
+ interface PluginAllowlistEntryDto {
1564
+ readonly id: string;
1565
+ /** Full npm package name, e.g. `@some-vendor/cool-plugin`. */
1566
+ readonly packageName: string;
1567
+ /** Semver range pinning what versions are allowed, e.g. `^2.0.0` or `2.1.3`. */
1568
+ readonly versionRange: string;
1569
+ /** Optional integrity (sha512); when set the install MUST match. */
1570
+ readonly integrity?: string;
1571
+ readonly source: 'npm' | 'github-packages';
1572
+ readonly enabled: boolean;
1573
+ readonly createdAt: string;
1574
+ }
1575
+ /** Body for `POST /admin/plugins/allowlist`. */
1576
+ interface CreatePluginAllowlistEntryDto {
1577
+ readonly packageName: string;
1578
+ readonly versionRange: string;
1579
+ readonly integrity?: string;
1580
+ readonly source?: 'npm' | 'github-packages';
1581
+ readonly enabled?: boolean;
1582
+ }
1583
+ /** Body for `PATCH /admin/plugins/allowlist/:id` (toggle / re-pin). */
1584
+ interface UpdatePluginAllowlistEntryDto {
1585
+ readonly versionRange?: string;
1586
+ readonly integrity?: string;
1587
+ readonly enabled?: boolean;
1588
+ }
1589
+ /** Response envelope for `GET /admin/plugins/allowlist`. */
1590
+ interface PluginAllowlistResponseDto {
1591
+ readonly entries: readonly PluginAllowlistEntryDto[];
1592
+ }
1593
+
1594
+ /**
1595
+ * What's new (AW-14) — closed vocabularies for product changelog entries.
1596
+ *
1597
+ * Nothing persists a category or a kind: entries come from a content source
1598
+ * that ships with the build, and only per-person read state is stored. These
1599
+ * tuples are therefore the single definition both the API and the web app
1600
+ * validate against.
1601
+ */
1602
+ /**
1603
+ * The product area an entry belongs to (spec FR-9). A closed set of six —
1604
+ * adding a seventh is a spec change, not an authoring decision. Drives the
1605
+ * filter chips in the What's new panel.
1606
+ */
1607
+ declare const CHANGELOG_CATEGORIES: readonly ["agents", "decisions", "knowledge", "connections", "costs", "platform"];
1608
+ type ChangelogCategory = (typeof CHANGELOG_CATEGORIES)[number];
1609
+ /**
1610
+ * What kind of change an entry describes (spec FR-10). Rendered as a badge
1611
+ * only — kind is never a filter dimension.
1612
+ */
1613
+ declare const CHANGELOG_KINDS: readonly ["new", "improved", "fixed", "security"];
1614
+ type ChangelogKind = (typeof CHANGELOG_KINDS)[number];
1615
+ /** Narrowing guard for a category read from an untrusted source (query string, content file). */
1616
+ declare function isChangelogCategory(value: unknown): value is ChangelogCategory;
1617
+ /** Narrowing guard for a kind read from an untrusted source. */
1618
+ declare function isChangelogKind(value: unknown): value is ChangelogKind;
1619
+ /**
1620
+ * Spec FR-39 — is `raw` an in-product path a call-to-action may navigate to?
1621
+ *
1622
+ * True only for a string that begins with exactly one `/` and carries no
1623
+ * backslash, whitespace or control character anywhere. That single rule
1624
+ * rejects every form FR-39 names: an absolute URL to another origin or any
1625
+ * scheme-bearing string (neither can start with `/`), a protocol-relative
1626
+ * `//host`, a backslash-obfuscated `/\host`, and `/<tab>/host`, which
1627
+ * browsers collapse to `//host` because they strip tabs and newlines from
1628
+ * URLs before parsing them.
1629
+ *
1630
+ * Shared so the API (which drops an unsafe call-to-action when it loads
1631
+ * entries) and every client (which re-checks before rendering the button)
1632
+ * apply the identical rule.
1633
+ */
1634
+ declare function isSafeInAppPath(raw: unknown): raw is string;
1635
+ /**
1636
+ * Stable entry identifier grammar (spec FR-6): a lowercase slug of 3–64
1637
+ * characters. It is the permalink and is never reused for a different entry.
1638
+ */
1639
+ declare const CHANGELOG_SLUG_PATTERN: RegExp;
1640
+ /** Authoring limits (spec FR-5, FR-17, FR-15, FR-26, FR-27). */
1641
+ declare const CHANGELOG_LIMITS: {
1642
+ readonly titleMaxLength: 80;
1643
+ readonly bodyMaxLength: 600;
1644
+ readonly bodyMaxParagraphs: 3;
1645
+ readonly ctaLabelMaxLength: 32;
1646
+ /** Most slugs one mark-read write may carry. */
1647
+ readonly markReadBatchMax: 25;
1648
+ /** The unread count only ever considers this many of the newest entries. */
1649
+ readonly unreadWindow: 50;
1650
+ /** Default page size for the panel and the full list. */
1651
+ readonly pageSize: 20;
1652
+ /** Largest page a client may request. */
1653
+ readonly pageSizeMax: 50;
1654
+ /** The deepest the list can be paged. */
1655
+ readonly listMax: 200;
1656
+ };
1657
+
1658
+ /**
1659
+ * What's new (AW-14) — wire contracts for `GET/POST /api/changelog/*`.
1660
+ *
1661
+ * Pure types, no decorators, so the API, the web app and any external client
1662
+ * can import them. Additive-only (these ship in a public package).
1663
+ */
1664
+ /** An in-product call-to-action: a button label and the app path it opens. */
1665
+ interface ChangelogCtaDto {
1666
+ label: string;
1667
+ /** Always an in-product path beginning with exactly one `/` (spec FR-39). */
1668
+ href: string;
1669
+ }
1670
+ /**
1671
+ * One product changelog entry as a reader sees it.
1672
+ *
1673
+ * Title and body are authored in English and are content, not interface
1674
+ * chrome — they are never passed through the translation layer (spec FR-11).
1675
+ */
1676
+ interface ChangelogEntryDto {
1677
+ /** Stable slug; the permalink (spec FR-6). */
1678
+ slug: string;
1679
+ /** ≤ 80 characters (spec FR-5). */
1680
+ title: string;
1681
+ /** Plain text, ≤ 600 characters, ≤ 3 paragraphs, line breaks preserved (spec FR-5). */
1682
+ body: string;
1683
+ category: ChangelogCategory;
1684
+ kind: ChangelogKind;
1685
+ /** ISO-8601 publish timestamp. Future-dated entries are never returned (spec FR-7). */
1686
+ publishedAt: string;
1687
+ /** At most one entry is pinned; it sorts first (spec FR-8). */
1688
+ pinned: boolean;
1689
+ /** `null` when the entry has no call-to-action OR its target is not a safe in-product path (spec FR-40). */
1690
+ cta: ChangelogCtaDto | null;
1691
+ /** Read for this person — explicitly, or because it predates their account (spec FR-14). */
1692
+ isRead: boolean;
1693
+ }
1694
+ /** `GET /api/changelog` */
1695
+ interface ChangelogListResponseDto {
1696
+ entries: ChangelogEntryDto[];
1697
+ /** Slug of the last returned entry when another page exists, otherwise `null`. */
1698
+ nextCursor: string | null;
1699
+ /** Visible entries in this build, ignoring any category filter. */
1700
+ total: number;
1701
+ /** Always the UNFILTERED unread count — a category filter never changes it (spec FR-38). */
1702
+ unreadCount: number;
1703
+ /** Categories that have at least one visible entry; the others render as disabled chips (spec FR-37). */
1704
+ categoriesWithEntries: ChangelogCategory[];
1705
+ }
1706
+ /** `GET /api/changelog/unread-count` */
1707
+ interface ChangelogUnreadCountResponseDto {
1708
+ count: number;
1709
+ }
1710
+ /** `POST /api/changelog/read` and `POST /api/changelog/read-all` */
1711
+ interface ChangelogMarkReadResponseDto {
1712
+ /** The reader's fresh unread count after the write (spec FR-18, FR-19). */
1713
+ unreadCount: number;
1714
+ }
1715
+ /** `POST /api/changelog/read` request body. */
1716
+ interface ChangelogMarkReadRequestDto {
1717
+ /** 1–25 entry slugs (spec FR-17). Slugs this build does not know are ignored. */
1718
+ slugs: string[];
1719
+ }
1720
+ /**
1721
+ * The authoring shape a changelog content source yields — what a person (or
1722
+ * a later non-file source) writes, before the API validates it and resolves
1723
+ * per-reader read state.
1724
+ *
1725
+ * Kept in contracts rather than inside the API so a content source that
1726
+ * lives outside `apps/api` can produce records of exactly this shape.
1727
+ */
1728
+ interface ChangelogSourceEntry {
1729
+ readonly slug: string;
1730
+ readonly title: string;
1731
+ readonly body: string;
1732
+ readonly category: ChangelogCategory;
1733
+ readonly kind: ChangelogKind;
1734
+ /** ISO-8601 date or date-time. */
1735
+ readonly publishedAt: string;
1736
+ readonly pinned?: boolean;
1737
+ readonly cta?: {
1738
+ readonly label: string;
1739
+ readonly href: string;
1740
+ };
1741
+ }
1742
+
1743
+ /**
1744
+ * AW-01 — wire-types for the workspace-wide search behind the dashboard
1745
+ * command palette (`GET /api/workspace-search`).
1746
+ *
1747
+ * Deliberately a different word from the existing `/api/search`, which means
1748
+ * "search the web through the configured search plugin". The two surfaces
1749
+ * never share a path, a controller or a type.
1750
+ */
1751
+ /**
1752
+ * Every record kind the palette can return. The first ten ship with the live
1753
+ * fan-out; the remaining kinds are reserved so a later index-backed read can
1754
+ * add them without a wire change.
1755
+ */
1756
+ declare const WORKSPACE_SEARCH_KINDS: readonly ["mission", "task", "agent", "work", "idea", "skill", "team", "knowledge", "run", "decision", "memory", "goal", "meeting", "node", "connection"];
1757
+ type WorkspaceSearchKind = (typeof WORKSPACE_SEARCH_KINDS)[number];
1758
+ /** How a hit matched the query — the band that produced its base score. */
1759
+ type WorkspaceSearchMatchReason = 'exact' | 'prefix' | 'wordPrefix' | 'contains' | 'identifier' | 'secondary' | 'fuzzy';
1760
+ /** Shortest trimmed query the server answers; shorter queries return no groups. */
1761
+ declare const WORKSPACE_SEARCH_MIN_QUERY_LENGTH = 2;
1762
+ /** Longest query the server matches; longer input is truncated, not rejected. */
1763
+ declare const WORKSPACE_SEARCH_MAX_QUERY_LENGTH = 128;
1764
+ /** Hard ceiling on rows across all groups in one response. */
1765
+ declare const WORKSPACE_SEARCH_MAX_TOTAL = 60;
1766
+ /** Default rows per group when no filter is applied. */
1767
+ declare const WORKSPACE_SEARCH_DEFAULT_PER_KIND = 5;
1768
+ /** Hard ceiling on rows for one group, reached when a group filter is applied. */
1769
+ declare const WORKSPACE_SEARCH_MAX_PER_KIND = 25;
1770
+ /** How many recently opened records a client may send to boost ranking. */
1771
+ declare const WORKSPACE_SEARCH_MAX_RECENT = 12;
1772
+ interface WorkspaceSearchHit {
1773
+ /** `${kind}:${sourceId}` — a stable client key. */
1774
+ id: string;
1775
+ kind: WorkspaceSearchKind;
1776
+ sourceId: string;
1777
+ title: string;
1778
+ /** Breadcrumb, path, identifier or owner. */
1779
+ subtitle: string | null;
1780
+ /** Raw status value of the source record (rendered as a badge). */
1781
+ statusLabel: string | null;
1782
+ /** Locale-agnostic dashboard route the row opens. */
1783
+ destination: string;
1784
+ /** Deterministic 0..100. */
1785
+ score: number;
1786
+ matchReason: WorkspaceSearchMatchReason;
1787
+ /** ISO 8601. */
1788
+ updatedAt: string | null;
1789
+ }
1790
+ interface WorkspaceSearchGroup {
1791
+ kind: WorkspaceSearchKind;
1792
+ /** Matches before the per-group cap — drives the "Show all" row. */
1793
+ total: number;
1794
+ hits: WorkspaceSearchHit[];
1795
+ }
1796
+ interface WorkspaceSearchResponse {
1797
+ query: string;
1798
+ groups: WorkspaceSearchGroup[];
1799
+ /** Kinds whose source failed; the client renders a partial-results notice. */
1800
+ degradedKinds: WorkspaceSearchKind[];
1801
+ servedBy: 'index' | 'fanout' | 'mixed';
1802
+ tookMs: number;
1803
+ }
1804
+
1805
+ /**
1806
+ * Help centre (AW-25) — closed vocabularies and the structured article grammar.
1807
+ *
1808
+ * The in-product manual renders pages of the documentation site (`docs/`) that
1809
+ * ship with the build. Nothing here is persisted: a build-time generator turns
1810
+ * those Markdown pages into the structured blocks below, and the web app renders
1811
+ * the blocks without ever injecting raw markup (spec FR-28). These tuples and
1812
+ * types are the one definition the generator, the renderer and any later API
1813
+ * surface agree on.
1814
+ */
1815
+ /**
1816
+ * The manual's sections, in reading order (spec FR-4). A closed set of six —
1817
+ * adding a seventh is a spec change, not an authoring decision.
1818
+ */
1819
+ declare const HELP_SECTIONS: readonly ["start-here", "running-the-loop", "your-agents", "setup-and-connections", "money-and-limits", "when-something-goes-wrong"];
1820
+ type HelpSection = (typeof HELP_SECTIONS)[number];
1821
+ /**
1822
+ * Every block kind an article body may contain (spec FR-27). Closed — the
1823
+ * renderer switches over this set without a default branch, so a new kind is a
1824
+ * compile error until it is rendered. `table` is part of the set because the
1825
+ * documentation pages the manual reuses present reference material as tables.
1826
+ */
1827
+ declare const HELP_BLOCK_KINDS: readonly ["paragraph", "heading", "orderedList", "unorderedList", "note", "shortcut", "code", "link", "table"];
1828
+ type HelpBlockKind = (typeof HELP_BLOCK_KINDS)[number];
1829
+ /** What a link may point at (spec FR-27a). Closed. */
1830
+ declare const HELP_LINK_TARGET_TYPES: readonly ["article", "screen", "external"];
1831
+ type HelpLinkTargetType = (typeof HELP_LINK_TARGET_TYPES)[number];
1832
+ /** Visual tone of a callout block. Closed. */
1833
+ declare const HELP_NOTE_TONES: readonly ["note", "tip", "info", "warning", "danger"];
1834
+ type HelpNoteTone = (typeof HELP_NOTE_TONES)[number];
1835
+ /**
1836
+ * Build-time limits (spec FR-3). Where the manual reuses an existing
1837
+ * documentation page, the body and heading ceilings are sized for those pages
1838
+ * rather than for short purpose-written articles.
1839
+ */
1840
+ declare const HELP_LIMITS: {
1841
+ readonly maxArticles: 200;
1842
+ readonly titleChars: 70;
1843
+ readonly summaryChars: 200;
1844
+ readonly bodyChars: 60000;
1845
+ readonly maxHeadings: 80;
1846
+ readonly headingIdMinChars: 2;
1847
+ readonly headingIdMaxChars: 96;
1848
+ readonly maxKeywords: 12;
1849
+ readonly keywordChars: 32;
1850
+ readonly maxDocuments: 8;
1851
+ readonly maxRelated: 5;
1852
+ readonly linkLabelChars: 80;
1853
+ readonly externalHrefChars: 2048;
1854
+ };
1855
+ /** Article identifier: lowercase letters, digits and hyphens, 3–64 characters (spec FR-3). */
1856
+ declare const HELP_ARTICLE_ID_PATTERN: RegExp;
1857
+ type HelpLinkTarget =
1858
+ /** Another article, optionally at a heading. Resolved like a help link (spec FR-22). */
1859
+ {
1860
+ type: 'article';
1861
+ articleId: string;
1862
+ headingId: string | null;
1863
+ }
1864
+ /** A KEY of the web app's route map — never a literal path (spec FR-5.2). */
1865
+ | {
1866
+ type: 'screen';
1867
+ routeKey: string;
1868
+ }
1869
+ /** Absolute `https:` URL with no embedded credentials (spec FR-27a). */
1870
+ | {
1871
+ type: 'external';
1872
+ href: string;
1873
+ };
1874
+ /** Inline content inside a paragraph, list item, heading or table cell. */
1875
+ type HelpInline = {
1876
+ type: 'text';
1877
+ text: string;
1878
+ } | {
1879
+ type: 'strong';
1880
+ children: HelpInline[];
1881
+ } | {
1882
+ type: 'emphasis';
1883
+ children: HelpInline[];
1884
+ } | {
1885
+ type: 'code';
1886
+ text: string;
1887
+ } | {
1888
+ type: 'link';
1889
+ children: HelpInline[];
1890
+ target: HelpLinkTarget;
1891
+ };
1892
+ interface HelpListItem {
1893
+ content: HelpInline[];
1894
+ /** Nested blocks — a sub-list, a code sample or a callout inside the item. */
1895
+ children: HelpBlock[];
1896
+ }
1897
+ interface HelpLinkBlock {
1898
+ kind: 'link';
1899
+ /** Plain text, 1–80 characters, no inline markup. */
1900
+ label: string;
1901
+ target: HelpLinkTarget;
1902
+ }
1903
+ type HelpBlock = {
1904
+ kind: 'paragraph';
1905
+ content: HelpInline[];
1906
+ } | {
1907
+ kind: 'heading';
1908
+ level: 2 | 3 | 4;
1909
+ id: string;
1910
+ content: HelpInline[];
1911
+ } | {
1912
+ kind: 'orderedList';
1913
+ items: HelpListItem[];
1914
+ } | {
1915
+ kind: 'unorderedList';
1916
+ items: HelpListItem[];
1917
+ } | {
1918
+ kind: 'note';
1919
+ tone: HelpNoteTone;
1920
+ title: string | null;
1921
+ blocks: HelpBlock[];
1922
+ } | {
1923
+ kind: 'shortcut';
1924
+ keys: string[];
1925
+ label: string;
1926
+ } | {
1927
+ kind: 'code';
1928
+ language: string | null;
1929
+ text: string;
1930
+ } | HelpLinkBlock | {
1931
+ kind: 'table';
1932
+ header: HelpInline[][];
1933
+ rows: HelpInline[][][];
1934
+ };
1935
+ /** The body file the generator emits for one article. */
1936
+ interface HelpArticleBody {
1937
+ /** Format version of this file; bumped only on an incompatible grammar change. */
1938
+ version: 1;
1939
+ id: string;
1940
+ blocks: HelpBlock[];
1941
+ }
1942
+ /** Narrowing guard for a section read from an untrusted source. */
1943
+ declare function isHelpSection(value: unknown): value is HelpSection;
1944
+ /** Narrowing guard for an article identifier read from an untrusted source (a URL segment). */
1945
+ declare function isHelpArticleId(value: unknown): value is string;
1946
+
1947
+ /**
1948
+ * Shared view — the owner-facing wire contracts behind Settings → Sharing and
1949
+ * the public share-link exchange.
1950
+ *
1951
+ * A Shared view is one Workspace's read-only published face: a live,
1952
+ * revocable projection of its Task board reached by a share link. It holds
1953
+ * WHAT may be read and BY WHICH token, never a copy of the content.
1954
+ *
1955
+ * Pure types plus closed vocabularies, so the API, the web app and any other
1956
+ * client import one definition. Additive-only (this ships in a public package).
1957
+ */
1958
+ /** `active` = the link resolves; `paused` = sharing is off but the link is kept. */
1959
+ type SharedViewStatus = 'active' | 'paused';
1960
+ declare const SHARED_VIEW_STATUSES: readonly SharedViewStatus[];
1961
+ declare function isSharedViewStatus(value: unknown): value is SharedViewStatus;
1962
+ /** Which sections a Shared view publishes. The board is on by default, knowledge off. */
1963
+ interface SharedViewSectionsDto {
1964
+ board: boolean;
1965
+ knowledge: boolean;
1966
+ }
1967
+ /** How a Shared view answers crawlers. `blocked` is the default. */
1968
+ type SharedViewIndexingMode = 'blocked' | 'allowed';
1969
+ /** Every number the Shared view contract promises, in one place. */
1970
+ declare const SHARED_VIEW_LIMITS: {
1971
+ /** 256 bits of randomness, base64url without padding. */
1972
+ readonly tokenBytes: 32;
1973
+ readonly tokenLength: 43;
1974
+ /** A view session lives this long before the client exchanges the token again. */
1975
+ readonly viewSessionTtlSeconds: number;
1976
+ /** Cards per published column. */
1977
+ readonly columnCardLimit: 50;
1978
+ /** Lines in the published activity strip. */
1979
+ readonly activityLineLimit: 20;
1980
+ /** Labels per published card. */
1981
+ readonly cardLabelLimit: 3;
1982
+ /** Exchanges and reads per token (or per view) per minute. */
1983
+ readonly requestsPerTokenPerMinute: 60;
1984
+ /** Public requests per client per hour. */
1985
+ readonly requestsPerClientPerHour: 600;
1986
+ /** Owner regenerations per Workspace per minute. */
1987
+ readonly regeneratePerMinute: 10;
1988
+ /** A client increments the view count at most once in this window. */
1989
+ readonly viewDedupeWindowSeconds: number;
1990
+ /** The `Retry-After` a throttled public request carries. */
1991
+ readonly retryAfterSeconds: 60;
1992
+ /** The live poll cadence of the published page. */
1993
+ readonly pollIntervalSeconds: 20;
1994
+ /** Knowledge class names a selection may hold. */
1995
+ readonly knowledgeClassLimit: 32;
1996
+ };
1997
+ /** The one error message every refused share-link request carries. */
1998
+ declare const SHARED_VIEW_NOT_ACTIVE = "shared_view_not_active";
1999
+ /** The share link, returned only to the Tenant owner. */
2000
+ interface SharedViewLinkDto {
2001
+ /** The 43-character share token. The web app builds `/share/<token>` from it. */
2002
+ token: string;
2003
+ }
2004
+ /**
2005
+ * `GET /api/organizations/:orgId/shared-view` and every owner write.
2006
+ *
2007
+ * Every member of the Workspace may read the settings; only the Tenant owner
2008
+ * receives `link`. `exists: false` means sharing has never been turned on.
2009
+ */
2010
+ interface SharedViewSettingsDto {
2011
+ exists: boolean;
2012
+ /** True when the caller is the Tenant owner and may change sharing. */
2013
+ canManage: boolean;
2014
+ status: SharedViewStatus | null;
2015
+ sections: SharedViewSectionsDto;
2016
+ /** Knowledge Base classes selected for publication. Empty publishes nothing. */
2017
+ knowledgeClasses: string[];
2018
+ searchIndexable: boolean;
2019
+ viewCount: number;
2020
+ /** ISO timestamp, or `null` when the link was never opened. */
2021
+ lastViewedAt: string | null;
2022
+ /** ISO timestamp of the last regenerate, or `null` when never regenerated. */
2023
+ tokenRotatedAt: string | null;
2024
+ rotationCount: number;
2025
+ /** ISO timestamp the Shared view was first turned on. */
2026
+ createdAt: string | null;
2027
+ /** Present only for the Tenant owner, and only when the stored token could be read. */
2028
+ link: SharedViewLinkDto | null;
2029
+ /** True for the owner when a stored token exists but could not be decrypted — regenerate to recover. */
2030
+ linkUnreadable: boolean;
2031
+ }
2032
+ /** `PATCH /api/organizations/:orgId/shared-view` — every field optional, one facet per field. */
2033
+ interface UpdateSharedViewDto {
2034
+ status?: SharedViewStatus;
2035
+ sections?: Partial<SharedViewSectionsDto>;
2036
+ knowledgeClasses?: string[];
2037
+ searchIndexable?: boolean;
2038
+ }
2039
+ /** `POST /api/public/shared-view/sessions` request body. The token never travels in a URL. */
2040
+ interface SharedViewSessionRequestDto {
2041
+ token: string;
2042
+ }
2043
+ /** `POST /api/public/shared-view/sessions` response. */
2044
+ interface SharedViewSessionDto {
2045
+ /** Opaque credential presented as `Authorization: Bearer <viewSession>` on every read. */
2046
+ viewSession: string;
2047
+ /** ISO timestamp after which the view session is refused. */
2048
+ expiresAt: string;
2049
+ /** Crawler posture of the resolved view, so the page can render its own robots directive. */
2050
+ searchIndexable: boolean;
2051
+ /** Sections the resolved view publishes. */
2052
+ sections: SharedViewSectionsDto;
2053
+ }
2054
+ /** Per-class publishable document counts for the knowledge confirm dialog. */
2055
+ interface SharedViewKnowledgeClassCountDto {
2056
+ documentClass: string;
2057
+ count: number;
2058
+ }
2059
+
2060
+ /**
2061
+ * Shared view — the published board: what a link visitor with no account is
2062
+ * allowed to read.
2063
+ *
2064
+ * Every type below is CLOSED: no index signature, no `Record<string, unknown>`
2065
+ * escape hatch, no optional passthrough. A field that is not declared here
2066
+ * cannot be serialised, so adding a field to a Task, an Agent or an activity
2067
+ * record can never leak it onto the published page.
2068
+ *
2069
+ * What is deliberately absent, and must stay absent: ids of any kind, costs,
2070
+ * budgets, token counts, model names, run references, error text, comments,
2071
+ * sub-tasks, the Mission / Work / Idea / Team / Goal a Task is filed against,
2072
+ * repositories, file paths, in-product URLs, and every human's name or email.
2073
+ */
2074
+ /** The four published columns — the private Task board's Focus layout, minus Cancelled. */
2075
+ type PublishedColumnKey = 'backlog' | 'in_flight' | 'needs_you' | 'done';
2076
+ declare const PUBLISHED_COLUMN_KEYS: readonly PublishedColumnKey[];
2077
+ /** `p0` (Urgent) … `p4` (Low). */
2078
+ type PublishedTaskPriority = 'p0' | 'p1' | 'p2' | 'p3' | 'p4';
2079
+ /** The Agent working a card: a display name only. The page draws the avatar from it. */
2080
+ interface PublishedAgentRefDto {
2081
+ name: string;
2082
+ }
2083
+ interface PublishedTaskCardDto {
2084
+ title: string;
2085
+ column: PublishedColumnKey;
2086
+ priority: PublishedTaskPriority;
2087
+ /** At most three labels. */
2088
+ labels: string[];
2089
+ /** ISO timestamp the work last moved. */
2090
+ lastProgressAt: string;
2091
+ /** True when the work has stopped moving (the private board's stall rule). */
2092
+ stale: boolean;
2093
+ agent: PublishedAgentRefDto | null;
2094
+ }
2095
+ interface PublishedColumnDto {
2096
+ key: PublishedColumnKey;
2097
+ /** Cards in the column, at most fifty, ordered exactly as on the private board. */
2098
+ cards: PublishedTaskCardDto[];
2099
+ /** Cards the column holds beyond the published ones — rendered as `+N more`. */
2100
+ moreCount: number;
2101
+ }
2102
+ /** `working` = has work in flight or a run going; `paused` = paused by its owner; otherwise `idle`. */
2103
+ type PublishedAgentStatus = 'working' | 'idle' | 'paused';
2104
+ interface PublishedAgentDto {
2105
+ name: string;
2106
+ status: PublishedAgentStatus;
2107
+ /** Published cards this Agent is working in the In flight column. */
2108
+ inFlightCount: number;
2109
+ }
2110
+ /** Who an activity line is about. Only an Agent is ever named. */
2111
+ type PublishedActorKind = 'agent' | 'person' | 'system';
2112
+ interface PublishedActivityLineDto {
2113
+ actorKind: PublishedActorKind;
2114
+ /** The Agent's display name. Always `null` for a person or the system. */
2115
+ actorName: string | null;
2116
+ /** The same narration the Live Feed renders, with the actor param never naming a person. */
2117
+ narration: FeedNarrationDto;
2118
+ /** ISO timestamp. */
2119
+ at: string;
2120
+ }
2121
+ /** `GET /api/public/shared-view/board` */
2122
+ interface PublishedBoardDto {
2123
+ workspaceName: string;
2124
+ sections: SharedViewSectionsDto;
2125
+ columns: PublishedColumnDto[];
2126
+ agents: PublishedAgentDto[];
2127
+ recent: PublishedActivityLineDto[];
2128
+ /** ISO timestamp the projection was computed. */
2129
+ generatedAt: string;
2130
+ }
2131
+
2132
+ /**
2133
+ * Shared view — the published knowledge library.
2134
+ *
2135
+ * Declared with the rest of the published contract so the shape is settled
2136
+ * once; the knowledge section itself stays off (and its endpoints answer the
2137
+ * not-active response) until it ships. Closed types, like the board's.
2138
+ *
2139
+ * Never published: git history, citations, the retrieval trail, embedding
2140
+ * state, uploads and original source files.
2141
+ */
2142
+ interface PublishedDocumentSummaryDto {
2143
+ /** An opaque, per-view document reference — never the stored document id. */
2144
+ ref: string;
2145
+ title: string;
2146
+ documentClass: string;
2147
+ wordCount: number;
2148
+ /** ISO timestamp. */
2149
+ updatedAt: string;
2150
+ }
2151
+ interface PublishedDocumentDto extends PublishedDocumentSummaryDto {
2152
+ /** The rendered document text. */
2153
+ body: string;
2154
+ }
2155
+
2156
+ /**
2157
+ * Shared view — the activity kinds the published strip may show.
2158
+ *
2159
+ * CLOSED BY DEFAULT: an activity kind is published only when it is named
2160
+ * here. A newly added kind stays off the published page until somebody adds
2161
+ * it deliberately; the agent-side classification spec fails until every kind
2162
+ * is on this list or on the never-publish list.
2163
+ *
2164
+ * Each entry is safe because its Live Feed narration reads nothing beyond a
2165
+ * Task title (already on a published card) or a status token: no path, no
2166
+ * repository, no Work name, no amount, no error text, no person.
2167
+ */
2168
+ declare const PUBLISHABLE_ACTIVITY_ACTIONS: readonly string[];
2169
+ declare function isPublishableActivityAction(actionType: unknown): boolean;
2170
+
2171
+ export { ACTIVE_SCOPE_API_HEADER, ACTIVE_SCOPE_BROWSER_HEADER, ACTIVE_SCOPE_PERSONAL_SENTINEL, ACTIVE_SCOPE_RESPONSE_SCHEMA, AWESOME_README_IMPORT_MODES, type ActiveScopeResponse, type AnalyzeRepositoryResponseDto, type AwesomeReadmeImportMode, CHANGELOG_CATEGORIES, CHANGELOG_KINDS, CHANGELOG_LIMITS, CHANGELOG_SLUG_PATTERN, type ChangelogCategory, type ChangelogCtaDto, type ChangelogEntryDto, type ChangelogKind, type ChangelogListResponseDto, type ChangelogMarkReadRequestDto, type ChangelogMarkReadResponseDto, type ChangelogSourceEntry, type ChangelogUnreadCountResponseDto, type CheckItemHealthDto, type CheckItemHealthResponseDto, type CheckSlugAvailabilityResponse, type CreateItemsGeneratorDto, type CreateOrganizationRequest, type CreatePluginAllowlistEntryDto, type ExtractItemDetailsDto, GenerateStatusType, type GenerationLogLevel, type GenerationLogSource, GenerationMethod, type GenerationMetrics, type GenerationStepLog, HELP_ARTICLE_ID_PATTERN, HELP_BLOCK_KINDS, HELP_LIMITS, HELP_LINK_TARGET_TYPES, HELP_NOTE_TONES, HELP_SECTIONS, type HelpArticleBody, type HelpBlock, type HelpBlockKind, type HelpInline, type HelpLinkBlock, type HelpLinkTarget, type HelpLinkTargetType, type HelpListItem, type HelpNoteTone, type HelpSection, IMPORT_SOURCE_TYPES, type ImportEnrichmentConfig, type ImportSourceType, type ImportWorkDto, LANE_FAILURE_REASONS, LANE_OUTCOMES, type LaneFailureReason, type LaneOutcome, MILESTONE_STATUSES, type ManifestValidationError, type MilestoneRecord, type MilestoneStatus, ONBOARDING_DEFAULT_STATE, ONBOARDING_DESKTOP_NEXT_STEPS, ONBOARDING_MILESTONES, ONBOARDING_TERMINAL_STATUSES, type OnboardingAiChoice, type OnboardingCard, type OnboardingCardBadge, type OnboardingCatalogResponse, type OnboardingDbChoice, type OnboardingDeployChoice, type OnboardingDesktopChoice, type OnboardingDesktopNextStep, type OnboardingMilestoneKey, type OnboardingPluginCard, type OnboardingProfile, type OnboardingProfileOption, type OnboardingRequestSource, type OnboardingRequestSourceAwesomeReadme, type OnboardingRequestSourceDataRepo, type OnboardingRequestSourceInline, type OnboardingRequestSourceWebSearch, type OnboardingRoleId, type OnboardingSeedAgentSuggestion, type OnboardingSeedOutcome, type OnboardingSeedRequest, type OnboardingSeedResponse, type OnboardingSeedResultEntry, type OnboardingSeedSkillSuggestion, type OnboardingSeedSuggestionsResponse, type OnboardingStatePatchRequest, type OnboardingStateResponse, type OnboardingStatus, type OnboardingStorageChoice, type OnboardingTeamSizeId, type OnboardingWizardStateV2, type OrganizationResponse, PUBLISHABLE_ACTIVITY_ACTIONS, PUBLISHED_COLUMN_KEYS, type PluginAllowlistEntryDto, type PluginAllowlistResponseDto, type PluginCatalogEntry, type PluginCatalogResponse, type PluginInstallRequestDto, type PluginInstallResponseDto, type PluginInstallSource, type PluginInstallState, type PluginInstallStateDto, type ProvidersDto, type PublishedActivityLineDto, type PublishedActorKind, type PublishedAgentDto, type PublishedAgentRefDto, type PublishedAgentStatus, type PublishedBoardDto, type PublishedColumnDto, type PublishedColumnKey, type PublishedDocumentDto, type PublishedDocumentSummaryDto, type PublishedTaskCardDto, type PublishedTaskPriority, ROLE_OPTIONS, ROSTER_BLUEPRINT_SLUGS, ROSTER_LANE_KEYS, ROSTER_MAX_LANES, ROSTER_NAME_MAX, ROSTER_PROVISION_STATES, type RegisterCompanyRequest, type RegisterWorkErrorBody, type RegisterWorkErrorCode, type RegisterWorkRequest, type RegisterWorkResponse, type RegisterWorkStatus, type RelatedRepositories, type RemoveItemDto, type RepoVisibility, type RepositoryRole, type RepositoryTarget, type RosterBlueprintSlug, type RosterLaneKey, type RosterLaneResult, type RosterProvisionRecord, type RosterProvisionState, SHARED_VIEW_LIMITS, SHARED_VIEW_NOT_ACTIVE, SHARED_VIEW_STATUSES, type SharedViewIndexingMode, type SharedViewKnowledgeClassCountDto, type SharedViewLinkDto, type SharedViewSectionsDto, type SharedViewSessionDto, type SharedViewSessionRequestDto, type SharedViewSettingsDto, type SharedViewStatus, type SourceRepository, type SourceValidationSettingsDto, type SubmitItemDto, type SyncEventErrorClass, type SyncEventFailed, type SyncEventKind, type SyncEventPayload, type SyncEventSkipReason, type SyncEventSkipped, type SyncEventSource, type SyncEventSuccess, TEAM_SIZE_OPTIONS, UPGRADE_NOT_AVAILABLE_AFTER_MULTIPLE_ORGS, type UpdateItemDto, type UpdateItemsGeneratorDto, type UpdateOrganizationRequest, type UpdatePluginAllowlistEntryDto, type UpdateSharedViewDto, type UpdateSourceValidationPayload, type UpdateWorkSchedulePayload, type UpgradeFromAccountResponse, WORKSPACE_SEARCH_DEFAULT_PER_KIND, WORKSPACE_SEARCH_KINDS, WORKSPACE_SEARCH_MAX_PER_KIND, WORKSPACE_SEARCH_MAX_QUERY_LENGTH, WORKSPACE_SEARCH_MAX_RECENT, WORKSPACE_SEARCH_MAX_TOTAL, WORKSPACE_SEARCH_MIN_QUERY_LENGTH, type WebhookEvent, type WebhookEventDeployFailed, type WebhookEventManifestChanged, type WebhookEventTerminal, WebsiteRepositoryCreationMethod, type WorkChangelog, type WorkCurrentDeploymentHealthDto, type WorkCurrentHealthDto, type WorkCurrentState, type WorkDeploymentHealthSource, type WorkDeploymentReadiness, type WorkGenerationHistoryEntry, type WorkGenerationHistoryResponse, WorkHistoryActivityType, type WorkHistoryChangeAction, type WorkHistoryChangeEntityType, type WorkHistoryChangeEntry, type WorkLastDeploymentRunDto, type WorkLastGenerationRunDto, type WorkLastRunDto, type WorkScheduleAllowedCadence, WorkScheduleBillingMode, WorkScheduleCadence, type WorkScheduleDto, WorkScheduleStatus, type WorkStatusProjectionDto, type WorksConfigSnapshot, type WorksManifestMetadata, type WorksManifestOutput, type WorksManifestSpec, type WorksManifestV1, type WorkspaceSearchGroup, type WorkspaceSearchHit, type WorkspaceSearchKind, type WorkspaceSearchMatchReason, type WorkspaceSearchResponse, desktopNextStep, isChangelogCategory, isChangelogKind, isHelpArticleId, isHelpSection, isPublishableActivityAction, isSafeInAppPath, isSharedViewStatus, isTerminalOnboardingStatus };