@company-semantics/contracts 9.0.0 → 9.1.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": "9.0.0",
3
+ "version": "9.1.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -113,13 +113,13 @@
113
113
  "zod": "^4.4.3"
114
114
  },
115
115
  "devDependencies": {
116
- "@types/node": "^25.9.1",
116
+ "@types/node": "^22.19.19",
117
117
  "husky": "^9.1.7",
118
118
  "lint-staged": "^17.0.7",
119
119
  "markdownlint-cli2": "^0.22.1",
120
120
  "openapi-typescript": "^7.13.0",
121
121
  "tsx": "^4.22.4",
122
- "typescript": "^5",
122
+ "typescript": "^5.8.3",
123
123
  "vitest": "^4.1.8",
124
124
  "yaml": "^2.9.0"
125
125
  },
@@ -47,6 +47,7 @@ export const openApiRoutes = {
47
47
  '/api/executions/{executionId}/summary': ['GET'],
48
48
  '/api/executions/{executionId}/timeline': ['GET'],
49
49
  '/api/executions/{executionId}/undo': ['POST'],
50
+ '/api/factory/floor': ['GET'],
50
51
  '/api/internal-admin/impersonate/end': ['POST'],
51
52
  '/api/internal-admin/impersonate/session': ['GET'],
52
53
  '/api/internal-admin/impersonate/start': ['POST'],
package/src/mcp/index.ts CHANGED
@@ -209,6 +209,19 @@ export interface MCPToolDescriptor {
209
209
  * 'integration.connection' can only run after a tool that produces it.
210
210
  */
211
211
  consumes?: ResourceType[]
212
+ /**
213
+ * Mutation-capability gate (ADR-BE-241). When present, the tool is locked
214
+ * unless the viewer's resolved capabilities permit it — the SINGLE source of
215
+ * truth consumed by BOTH the backend execution gate and the frontend tool-lock
216
+ * UI (replacing the previously triplicated ACTION_TOOL_GATES / FIELD_GATES /
217
+ * ACTION_GATES maps).
218
+ * - kind 'field': `path` addresses a FieldCapability in CapabilitiesResponse
219
+ * (e.g. 'org.name', 'profile.fullName'); locked unless state === 'editable'.
220
+ * - kind 'action': `path` addresses an ActionCapability under `.actions`
221
+ * (e.g. 'members.invite', 'orgAdmins.manage'); locked unless 'allowed'.
222
+ * Absent ⇒ ungated (gating is additive).
223
+ */
224
+ capabilityGate?: { kind: 'field' | 'action'; path: string }
212
225
  }
213
226
 
214
227
  /**
package/src/org/index.ts CHANGED
@@ -288,6 +288,10 @@ export {
288
288
  CreateDelegationRequestSchema,
289
289
  UpdateDelegationRequestSchema,
290
290
  DelegationListResponseSchema,
291
+ // Mutation capabilities (GET /api/capabilities) — ADR-BE-241
292
+ FieldCapabilitySchema,
293
+ ActionCapabilitySchema,
294
+ CapabilitiesResponseSchema,
291
295
  } from './schemas';
292
296
  export type {
293
297
  AuthoritySource,
@@ -303,4 +307,7 @@ export type {
303
307
  CreateDelegationRequest,
304
308
  UpdateDelegationRequest,
305
309
  DelegationListResponse,
310
+ FieldCapability,
311
+ ActionCapability,
312
+ CapabilitiesResponse,
306
313
  } from './schemas';
@@ -1147,3 +1147,66 @@ export type OrgUnitPermissionsEntry = z.infer<typeof OrgUnitPermissionsEntrySche
1147
1147
  export type ListOrgUnitPermissionsResponse = z.infer<typeof ListOrgUnitPermissionsResponseSchema>;
1148
1148
  export type UpdateOrgUnitRequest = z.infer<typeof UpdateOrgUnitRequestSchema>;
1149
1149
  export type UpdateOrgUnitResponse = z.infer<typeof UpdateOrgUnitResponseSchema>;
1150
+
1151
+ // =============================================================================
1152
+ // Mutation Capabilities (GET /api/capabilities) — ADR-BE-241 / PRD-00707 F4
1153
+ // =============================================================================
1154
+ // Canonical home for the viewer's resolved mutation-capability projection. The
1155
+ // backend derives it (src/capabilities/derive.ts) and validates the response
1156
+ // against CapabilitiesResponseSchema via sendValidated; the frontend reads the
1157
+ // inferred types to render lock/allow affordances. Previously duplicated as a
1158
+ // backend-local Zod + hand-written frontend interfaces — unified here.
1159
+
1160
+ /** Scope identifiers are dot-namespaced strings (see backend trust/scopes.ts). */
1161
+ const RequiredScopeSchema = z.string();
1162
+
1163
+ /** A mutable field's gate: editable, or locked with attribution (sso vs rbac). */
1164
+ export const FieldCapabilitySchema = z.object({
1165
+ state: z.enum(['editable', 'locked']),
1166
+ reason: z.enum(['sso', 'rbac']).optional(),
1167
+ requiredScope: RequiredScopeSchema.optional(),
1168
+ });
1169
+
1170
+ /** An action's gate: allowed, or blocked with the scope that would unlock it. */
1171
+ export const ActionCapabilitySchema = z.object({
1172
+ state: z.enum(['allowed', 'blocked']),
1173
+ requiredScope: RequiredScopeSchema.optional(),
1174
+ });
1175
+
1176
+ /**
1177
+ * The single validated capability surface the UI reads. Every sub-object is
1178
+ * optional, matching the partial derivation in deriveCapabilities() (actions/org
1179
+ * are present only when scopes resolved).
1180
+ */
1181
+ export const CapabilitiesResponseSchema = z.object({
1182
+ profile: z
1183
+ .object({
1184
+ fullName: FieldCapabilitySchema,
1185
+ preferredName: FieldCapabilitySchema,
1186
+ })
1187
+ .optional(),
1188
+ org: z
1189
+ .object({
1190
+ name: FieldCapabilitySchema,
1191
+ })
1192
+ .optional(),
1193
+ actions: z
1194
+ .object({
1195
+ members: z.object({
1196
+ invite: ActionCapabilitySchema,
1197
+ remove: ActionCapabilitySchema,
1198
+ changeRole: ActionCapabilitySchema,
1199
+ }),
1200
+ orgAdmins: z.object({
1201
+ manage: ActionCapabilitySchema,
1202
+ }),
1203
+ orgUnit: z.object({
1204
+ manage: ActionCapabilitySchema,
1205
+ }),
1206
+ })
1207
+ .optional(),
1208
+ });
1209
+
1210
+ export type FieldCapability = z.infer<typeof FieldCapabilitySchema>;
1211
+ export type ActionCapability = z.infer<typeof ActionCapabilitySchema>;
1212
+ export type CapabilitiesResponse = z.infer<typeof CapabilitiesResponseSchema>;