@company-semantics/contracts 1.15.0 → 1.16.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
2
- export const SPEC_HASH = 'b15100bf7771' as const;
3
- export const SPEC_HASH_FULL = 'b15100bf7771682644b63942432a672ffee7d4fdb1237201f491b4d8d3c6b238' as const;
2
+ export const SPEC_HASH = 'e337542ea39d' as const;
3
+ export const SPEC_HASH_FULL = 'e337542ea39de6f11b03f87d300e3e4c842825267c6918b1a37f2f86502124f8' as const;
@@ -647,38 +647,38 @@ export interface paths {
647
647
  patch?: never;
648
648
  trace?: never;
649
649
  };
650
- "/api/rbac/roles": {
650
+ "/api/workspace/members/{id}/role": {
651
651
  parameters: {
652
652
  query?: never;
653
653
  header?: never;
654
654
  path?: never;
655
655
  cookie?: never;
656
656
  };
657
- /** List RBAC roles catalog (system + custom) with scopes and member counts */
658
- get: operations["getRbacRoles"];
657
+ get?: never;
659
658
  put?: never;
660
659
  post?: never;
661
660
  delete?: never;
662
661
  options?: never;
663
662
  head?: never;
664
- patch?: never;
663
+ /** Change member role */
664
+ patch: operations["changeMemberRole"];
665
665
  trace?: never;
666
666
  };
667
- "/api/workspace/members/{id}/role": {
667
+ "/api/rbac/roles": {
668
668
  parameters: {
669
669
  query?: never;
670
670
  header?: never;
671
671
  path?: never;
672
672
  cookie?: never;
673
673
  };
674
- get?: never;
674
+ /** List RBAC roles catalog (system + custom) with scopes and member counts */
675
+ get: operations["getRbacRoles"];
675
676
  put?: never;
676
677
  post?: never;
677
678
  delete?: never;
678
679
  options?: never;
679
680
  head?: never;
680
- /** Change member role */
681
- patch: operations["changeMemberRole"];
681
+ patch?: never;
682
682
  trace?: never;
683
683
  };
684
684
  "/api/user/orgs": {
@@ -2355,49 +2355,26 @@ export interface components {
2355
2355
  WorkspaceHandleRequest: {
2356
2356
  handle: string;
2357
2357
  };
2358
- WorkspaceMemberUnitSummary: {
2359
- unitId: string;
2360
- unitName: string;
2361
- unitPath: string;
2362
- /** @enum {string} */
2363
- role: "owner" | "manager" | "member";
2364
- };
2365
- WorkspaceMember: {
2366
- id: string;
2367
- name: string;
2368
- email: string;
2369
- /** @enum {string} */
2370
- role: "owner" | "admin" | "member" | "auditor";
2371
- roleNames: string[];
2372
- joinedAt: string;
2373
- lastActiveAt: string | null;
2374
- unitMemberships: components["schemas"]["WorkspaceMemberUnitSummary"][];
2375
- unitMembershipsTruncated: boolean;
2376
- inviteStatus: ("active" | "pending" | "expired") | null;
2377
- };
2378
- MemberRecentAction: {
2379
- id: string;
2380
- timestamp: string;
2381
- action: string;
2382
- summary: string;
2383
- };
2384
- WorkspaceMemberDetail: components["schemas"]["WorkspaceMember"] & {
2385
- effectiveScopes: string[];
2386
- recentActions: components["schemas"]["MemberRecentAction"][];
2387
- };
2388
- RoleCatalogEntry: {
2389
- name: string;
2390
- /** @enum {string} */
2391
- type: "system" | "custom";
2392
- description: string;
2393
- scopes: string[];
2394
- memberCount: number;
2395
- };
2396
- RoleCatalogResponse: {
2397
- roles: components["schemas"]["RoleCatalogEntry"][];
2398
- };
2399
2358
  WorkspaceMembersResponse: {
2400
- items: components["schemas"]["WorkspaceMember"][];
2359
+ items: {
2360
+ id: string;
2361
+ name: string;
2362
+ email: string;
2363
+ /** @enum {string} */
2364
+ role: "owner" | "admin" | "member" | "auditor";
2365
+ roleNames: string[];
2366
+ joinedAt: string;
2367
+ lastActiveAt: string | null;
2368
+ unitMemberships: {
2369
+ unitId: string;
2370
+ unitName: string;
2371
+ unitPath: string;
2372
+ /** @enum {string} */
2373
+ role: "owner" | "manager" | "member";
2374
+ }[];
2375
+ unitMembershipsTruncated: boolean;
2376
+ inviteStatus: ("active" | "pending" | "expired") | null;
2377
+ }[];
2401
2378
  nextCursor: string | null;
2402
2379
  hasMore: boolean;
2403
2380
  };
@@ -2566,6 +2543,32 @@ export interface components {
2566
2543
  /** @enum {string} */
2567
2544
  errorCode?: "IDENTITY_CONFLICT" | "DOMAIN_MISMATCH" | "ISSUER_MISMATCH" | "CALLBACK_ERROR";
2568
2545
  };
2546
+ WorkspaceMemberDetail: {
2547
+ id: string;
2548
+ name: string;
2549
+ email: string;
2550
+ /** @enum {string} */
2551
+ role: "owner" | "admin" | "member" | "auditor";
2552
+ roleNames: string[];
2553
+ joinedAt: string;
2554
+ lastActiveAt: string | null;
2555
+ unitMemberships: {
2556
+ unitId: string;
2557
+ unitName: string;
2558
+ unitPath: string;
2559
+ /** @enum {string} */
2560
+ role: "owner" | "manager" | "member";
2561
+ }[];
2562
+ unitMembershipsTruncated: boolean;
2563
+ inviteStatus: ("active" | "pending" | "expired") | null;
2564
+ effectiveScopes: string[];
2565
+ recentActions: {
2566
+ id: string;
2567
+ timestamp: string;
2568
+ action: string;
2569
+ summary: string;
2570
+ }[];
2571
+ };
2569
2572
  RemoveMemberResponse: {
2570
2573
  success: boolean;
2571
2574
  memberId: string;
@@ -2584,6 +2587,16 @@ export interface components {
2584
2587
  /** @enum {string} */
2585
2588
  newRole: "admin" | "member";
2586
2589
  };
2590
+ RoleCatalogResponse: {
2591
+ roles: {
2592
+ name: string;
2593
+ /** @enum {string} */
2594
+ type: "system" | "custom";
2595
+ description: string;
2596
+ scopes: string[];
2597
+ memberCount: number;
2598
+ }[];
2599
+ };
2587
2600
  UserOrgsResponse: {
2588
2601
  orgs: {
2589
2602
  userId: string;
@@ -2802,6 +2815,7 @@ export interface components {
2802
2815
  target: {
2803
2816
  type: string;
2804
2817
  workspaceId?: string;
2818
+ service?: string;
2805
2819
  };
2806
2820
  connectionId?: string;
2807
2821
  returnUrl?: string;
@@ -4467,48 +4481,48 @@ export interface operations {
4467
4481
  };
4468
4482
  };
4469
4483
  };
4470
- getRbacRoles: {
4484
+ changeMemberRole: {
4471
4485
  parameters: {
4472
4486
  query?: never;
4473
4487
  header?: never;
4474
- path?: never;
4488
+ path: {
4489
+ id: string;
4490
+ };
4475
4491
  cookie?: never;
4476
4492
  };
4477
- requestBody?: never;
4493
+ requestBody: {
4494
+ content: {
4495
+ "application/json": components["schemas"]["ChangeMemberRoleRequest"];
4496
+ };
4497
+ };
4478
4498
  responses: {
4479
- /** @description Role catalog */
4499
+ /** @description Role changed successfully */
4480
4500
  200: {
4481
4501
  headers: {
4482
4502
  [name: string]: unknown;
4483
4503
  };
4484
4504
  content: {
4485
- "application/json": components["schemas"]["RoleCatalogResponse"];
4505
+ "application/json": components["schemas"]["ChangeMemberRoleResponse"];
4486
4506
  };
4487
4507
  };
4488
4508
  };
4489
4509
  };
4490
- changeMemberRole: {
4510
+ getRbacRoles: {
4491
4511
  parameters: {
4492
4512
  query?: never;
4493
4513
  header?: never;
4494
- path: {
4495
- id: string;
4496
- };
4514
+ path?: never;
4497
4515
  cookie?: never;
4498
4516
  };
4499
- requestBody: {
4500
- content: {
4501
- "application/json": components["schemas"]["ChangeMemberRoleRequest"];
4502
- };
4503
- };
4517
+ requestBody?: never;
4504
4518
  responses: {
4505
- /** @description Role changed successfully */
4519
+ /** @description Role catalog */
4506
4520
  200: {
4507
4521
  headers: {
4508
4522
  [name: string]: unknown;
4509
4523
  };
4510
4524
  content: {
4511
- "application/json": components["schemas"]["ChangeMemberRoleResponse"];
4525
+ "application/json": components["schemas"]["RoleCatalogResponse"];
4512
4526
  };
4513
4527
  };
4514
4528
  };
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Dispatch-deny vocabulary.
3
+ *
4
+ * The four deny paths on the agent-action dispatch flow — consent missing,
5
+ * write-tier disabled, per-provider kill switch, and execution-budget
6
+ * exhausted — all return the canonical `ErrorResponse` envelope with one of
7
+ * the codes defined below plus a per-code `meta` payload. The shapes are
8
+ * shared between the backend (which emits) and the app (which renders a
9
+ * recovery affordance), so they live in contracts per the promotion rule.
10
+ *
11
+ * HTTP status is carried by the envelope, not duplicated here; conventional
12
+ * mapping in the backend:
13
+ * - `incremental_consent_required` → 402 (grant required to proceed)
14
+ * - `write_tier_disabled` → 403
15
+ * - `provider_access_denied` → 403
16
+ * - `execution_budget_exceeded` → 429
17
+ *
18
+ * @see ../errors/index.ts for the `ErrorResponse` envelope.
19
+ * @see PRD-00519/00521/00522 — the PRDs that introduced these denies.
20
+ */
21
+
22
+ export const DISPATCH_DENY_CODES = [
23
+ 'incremental_consent_required',
24
+ 'write_tier_disabled',
25
+ 'provider_access_denied',
26
+ 'execution_budget_exceeded',
27
+ ] as const;
28
+
29
+ export type DispatchDenyCode = (typeof DISPATCH_DENY_CODES)[number];
30
+
31
+ export type ActionTier = 'SAFE' | 'EXTERNAL' | 'DESTRUCTIVE';
32
+
33
+ /**
34
+ * The user has no active grant row in `incremental_consents` for the
35
+ * `(user_id, org_id, action_id)` triple. Recoverable by the user: they
36
+ * POST `grantPath` to create the grant, then retry the original action.
37
+ */
38
+ export interface IncrementalConsentRequiredMeta {
39
+ actionId: string;
40
+ tier: ActionTier;
41
+ requiredScopes: string[];
42
+ /** HTTP path the app can POST to with `{ actionId }` to create the grant. */
43
+ grantPath: string;
44
+ }
45
+
46
+ /**
47
+ * The global `WRITE_TIER_ENABLED[tier]` kill switch is off. Recoverable
48
+ * only by an operator flipping the config — not user-actionable.
49
+ */
50
+ export interface WriteTierDisabledMeta {
51
+ actionId: string;
52
+ tier: ActionTier;
53
+ }
54
+
55
+ /**
56
+ * Distinct reasons `ProviderAccessGate.canDispatchAction` can deny.
57
+ * Kept separate from the global `WRITE_TIER_ENABLED` codes so the app
58
+ * can phrase the message by cause (provider paused vs. org override vs.
59
+ * tier paused for this provider).
60
+ */
61
+ export type ProviderAccessDenyReason =
62
+ | 'provider-disabled'
63
+ | 'org-override'
64
+ | 'tier-SAFE-disabled'
65
+ | 'tier-EXTERNAL-disabled'
66
+ | 'tier-DESTRUCTIVE-disabled'
67
+ | 'write-tier-SAFE-globally-disabled'
68
+ | 'write-tier-EXTERNAL-globally-disabled'
69
+ | 'write-tier-DESTRUCTIVE-globally-disabled';
70
+
71
+ export interface ProviderAccessDeniedMeta {
72
+ reason: ProviderAccessDenyReason;
73
+ provider: string;
74
+ tier: ActionTier;
75
+ actionType: string;
76
+ }
77
+
78
+ /**
79
+ * The signed execution has hit one of its atomic per-run caps. `kind` tells
80
+ * the app which cap tripped so it can phrase the message correctly; the
81
+ * recovery is always "start a new session / execution".
82
+ */
83
+ export interface ExecutionBudgetExceededMeta {
84
+ kind: 'token_uses' | 'time_window' | 'provider_calls' | 'rows_returned';
85
+ executionId: string;
86
+ }
87
+
88
+ /** Type-level map: deny code → meta shape. Drives the app's deny renderer. */
89
+ export interface DispatchDenyMetaByCode {
90
+ incremental_consent_required: IncrementalConsentRequiredMeta;
91
+ write_tier_disabled: WriteTierDisabledMeta;
92
+ provider_access_denied: ProviderAccessDeniedMeta;
93
+ execution_budget_exceeded: ExecutionBudgetExceededMeta;
94
+ }
95
+
96
+ /** Narrow `unknown` to a `DispatchDenyCode` for error-code dispatch switches. */
97
+ export function isDispatchDenyCode(code: unknown): code is DispatchDenyCode {
98
+ return typeof code === 'string' && (DISPATCH_DENY_CODES as readonly string[]).includes(code);
99
+ }
package/src/index.ts CHANGED
@@ -166,6 +166,22 @@ export type {
166
166
  export type { AuthStartMode, AuthStartResponse } from './auth/index'
167
167
  export { OTPErrorCode } from './auth/index'
168
168
 
169
+ // Dispatch deny vocabulary (PRD-00519/00521/00522)
170
+ export {
171
+ DISPATCH_DENY_CODES,
172
+ isDispatchDenyCode,
173
+ } from './dispatch/index'
174
+ export type {
175
+ ActionTier,
176
+ DispatchDenyCode,
177
+ DispatchDenyMetaByCode,
178
+ ExecutionBudgetExceededMeta,
179
+ IncrementalConsentRequiredMeta,
180
+ ProviderAccessDenyReason,
181
+ ProviderAccessDeniedMeta,
182
+ WriteTierDisabledMeta,
183
+ } from './dispatch/index'
184
+
169
185
  // Email domain types
170
186
  // @see ADR-CONT-034 for design rationale
171
187
  export type {