@company-semantics/contracts 9.1.0 → 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/package.json +4 -1
  2. package/src/__tests__/resource-keys.test.ts +30 -23
  3. package/src/admin/authz-simulate.ts +4 -4
  4. package/src/admin/direct-grants.ts +2 -2
  5. package/src/api/generated-spec-hash.ts +2 -2
  6. package/src/api/generated.ts +97 -0
  7. package/src/api/http/routes/ai-chat.ts +3 -3
  8. package/src/api/http/utils/resource-response.ts +5 -2
  9. package/src/api/index.ts +4 -4
  10. package/src/api/primitives.ts +6 -2
  11. package/src/auth/README.md +1 -0
  12. package/src/auth/index.ts +12 -5
  13. package/src/autotune.ts +5 -1
  14. package/src/billing/index.ts +1 -1
  15. package/src/billing/types.ts +1 -1
  16. package/src/chat/README.md +3 -0
  17. package/src/chat/__tests__/runtime-profile.test.ts +68 -48
  18. package/src/chat/index.ts +10 -4
  19. package/src/chat/runtime-profile.ts +25 -10
  20. package/src/chat/schemas.ts +49 -41
  21. package/src/chat/types.ts +48 -42
  22. package/src/ci-envelope/README.md +2 -0
  23. package/src/ci-envelope/__tests__/transitions.test.ts +56 -56
  24. package/src/ci-envelope/index.ts +2 -2
  25. package/src/ci-envelope/types.ts +20 -20
  26. package/src/ci-results/index.ts +2 -2
  27. package/src/ci-results/repo-ci-result.ts +15 -12
  28. package/src/compatibility.ts +6 -6
  29. package/src/content/index.ts +10 -4
  30. package/src/content/schemas.ts +42 -24
  31. package/src/dispatch/index.ts +18 -15
  32. package/src/email/__tests__/registry.test.ts +81 -77
  33. package/src/email/index.ts +3 -3
  34. package/src/email/registry.ts +25 -25
  35. package/src/email/types.ts +43 -43
  36. package/src/errors/index.ts +8 -8
  37. package/src/execution/__tests__/events.test.ts +42 -42
  38. package/src/execution/__tests__/lifecycle.test.ts +192 -190
  39. package/src/execution/__tests__/registry.test.ts +114 -114
  40. package/src/execution/audit-export.ts +4 -4
  41. package/src/execution/errors.ts +7 -7
  42. package/src/execution/event-metadata.ts +4 -4
  43. package/src/execution/events.ts +23 -21
  44. package/src/execution/expiry.ts +5 -5
  45. package/src/execution/hash-chain.ts +2 -2
  46. package/src/execution/index.ts +19 -28
  47. package/src/execution/kinds.ts +7 -7
  48. package/src/execution/lifecycle.ts +33 -33
  49. package/src/execution/registry.ts +63 -63
  50. package/src/execution/schemas.ts +31 -23
  51. package/src/execution/status.ts +45 -26
  52. package/src/execution/summary.ts +16 -17
  53. package/src/execution/timeline-ui.ts +9 -9
  54. package/src/execution/types.ts +31 -25
  55. package/src/generated/openapi-routes.ts +1 -0
  56. package/src/guards/config.ts +22 -18
  57. package/src/guards/index.ts +4 -4
  58. package/src/guards/types.ts +32 -24
  59. package/src/identity/__tests__/avatar.test.ts +68 -59
  60. package/src/identity/avatar.ts +8 -8
  61. package/src/identity/display-name.ts +3 -3
  62. package/src/identity/index.ts +8 -8
  63. package/src/identity/people-org-chart.ts +8 -4
  64. package/src/identity/schemas.ts +28 -18
  65. package/src/identity/types.ts +5 -5
  66. package/src/impersonation/index.ts +5 -5
  67. package/src/impersonation/schemas.ts +15 -9
  68. package/src/impersonation-events.ts +21 -21
  69. package/src/impersonation.ts +25 -24
  70. package/src/index.ts +118 -90
  71. package/src/interfaces/mcp/tools/help.ts +19 -19
  72. package/src/internal-admin.ts +6 -6
  73. package/src/mcp/README.md +2 -0
  74. package/src/mcp/__tests__/capability-graph.test.ts +290 -290
  75. package/src/mcp/capability-graph.ts +42 -40
  76. package/src/mcp/failure-context.ts +1 -3
  77. package/src/mcp/index.ts +57 -57
  78. package/src/mcp/resources.ts +9 -9
  79. package/src/meetings/index.ts +2 -2
  80. package/src/meetings/schemas.ts +51 -34
  81. package/src/message-parts/README.md +2 -0
  82. package/src/message-parts/__tests__/builder.test.ts +142 -142
  83. package/src/message-parts/__tests__/confirmation.test.ts +100 -86
  84. package/src/message-parts/__tests__/preview.test.ts +63 -63
  85. package/src/message-parts/__tests__/wire.test.ts +130 -124
  86. package/src/message-parts/builder.ts +23 -23
  87. package/src/message-parts/confirmation.ts +17 -14
  88. package/src/message-parts/execution.ts +7 -7
  89. package/src/message-parts/index.ts +10 -10
  90. package/src/message-parts/lifecycle.ts +25 -25
  91. package/src/message-parts/preview.ts +30 -30
  92. package/src/message-parts/types.ts +27 -27
  93. package/src/message-parts/wire.ts +24 -24
  94. package/src/mutations.ts +2 -2
  95. package/src/observability.ts +23 -11
  96. package/src/org/__tests__/org-units.test.ts +131 -96
  97. package/src/org/__tests__/tree-ordering.test.ts +57 -37
  98. package/src/org/__tests__/view-scopes.test.ts +40 -40
  99. package/src/org/domain.ts +9 -9
  100. package/src/org/index.ts +24 -21
  101. package/src/org/org-units.ts +34 -20
  102. package/src/org/schemas.ts +201 -127
  103. package/src/org/sharing.ts +17 -13
  104. package/src/org/tree-ordering.ts +3 -1
  105. package/src/org/types.ts +54 -47
  106. package/src/org/view-scopes.ts +9 -9
  107. package/src/permissions/access-levels.ts +7 -2
  108. package/src/permissions/access-source.ts +6 -6
  109. package/src/permissions/index.ts +5 -5
  110. package/src/permissions/orgchart-roles.ts +7 -7
  111. package/src/permissions/permission-introspection.ts +7 -5
  112. package/src/permissions/share-api.ts +19 -9
  113. package/src/pressure.ts +4 -4
  114. package/src/queryIntent.ts +21 -21
  115. package/src/ralph/__tests__/prd-groups.test.ts +159 -159
  116. package/src/ralph/__tests__/prd.test.ts +30 -30
  117. package/src/ralph/index.ts +3 -8
  118. package/src/ralph/prd.ts +33 -33
  119. package/src/ralph/progress.ts +1 -1
  120. package/src/rate-limit/README.md +4 -4
  121. package/src/rate-limit/index.ts +3 -3
  122. package/src/requests.ts +36 -8
  123. package/src/resource-keys.ts +207 -124
  124. package/src/resource-registry.ts +5 -5
  125. package/src/route-builder.ts +3 -3
  126. package/src/safe-mode.ts +2 -2
  127. package/src/security/index.ts +4 -4
  128. package/src/security/org-secrets.ts +13 -9
  129. package/src/security/secret.ts +3 -3
  130. package/src/sse.ts +3 -1
  131. package/src/system/README.md +3 -0
  132. package/src/system/capabilities.ts +22 -23
  133. package/src/system/diagram.ts +45 -45
  134. package/src/system/index.ts +14 -14
  135. package/src/tiers.ts +1 -1
  136. package/src/timeouts.ts +1 -1
  137. package/src/tracing.ts +30 -30
  138. package/src/types/analytics.ts +2 -2
  139. package/src/usage/README.md +3 -0
  140. package/src/usage/execution-types.ts +69 -69
  141. package/src/usage/types.ts +7 -3
@@ -1,6 +1,6 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { buildCapabilityGraph } from '../capability-graph'
3
- import type { MCPToolDescriptor } from '../index'
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildCapabilityGraph } from "../capability-graph";
3
+ import type { MCPToolDescriptor } from "../index";
4
4
 
5
5
  /**
6
6
  * Helper to create minimal MCPToolDescriptor for testing.
@@ -10,412 +10,412 @@ function makeTool(
10
10
  overrides: Partial<MCPToolDescriptor> & { id: string; name: string },
11
11
  ): MCPToolDescriptor {
12
12
  return {
13
- category: 'system',
14
- description: '',
15
- effectClass: 'pure',
16
- invocationMode: 'manual',
17
- visibility: 'user',
13
+ category: "system",
14
+ description: "",
15
+ effectClass: "pure",
16
+ invocationMode: "manual",
17
+ visibility: "user",
18
18
  requiresConfirmation: false,
19
- domain: 'system',
20
- risk: 'none',
21
- intent: 'read',
22
- stability: 'stable',
23
- complexity: 'trivial',
19
+ domain: "system",
20
+ risk: "none",
21
+ intent: "read",
22
+ stability: "stable",
23
+ complexity: "trivial",
24
24
  schemaVersion: 1,
25
25
  ...overrides,
26
- }
26
+ };
27
27
  }
28
28
 
29
- describe('buildCapabilityGraph', () => {
30
- it('returns empty graph for empty tools array', () => {
31
- const graph = buildCapabilityGraph([])
32
- expect(graph.edges).toEqual([])
33
- expect(graph.workflows).toEqual([])
34
- })
29
+ describe("buildCapabilityGraph", () => {
30
+ it("returns empty graph for empty tools array", () => {
31
+ const graph = buildCapabilityGraph([]);
32
+ expect(graph.edges).toEqual([]);
33
+ expect(graph.workflows).toEqual([]);
34
+ });
35
35
 
36
- it('produces no edges for tools with no produces/consumes', () => {
36
+ it("produces no edges for tools with no produces/consumes", () => {
37
37
  const tools = [
38
- makeTool({ id: 'a', name: 'a' }),
39
- makeTool({ id: 'b', name: 'b' }),
40
- ]
41
- const graph = buildCapabilityGraph(tools)
42
- expect(graph.edges).toEqual([])
43
- })
38
+ makeTool({ id: "a", name: "a" }),
39
+ makeTool({ id: "b", name: "b" }),
40
+ ];
41
+ const graph = buildCapabilityGraph(tools);
42
+ expect(graph.edges).toEqual([]);
43
+ });
44
44
 
45
- it('creates one edge for single producer → consumer with correct domain', () => {
45
+ it("creates one edge for single producer → consumer with correct domain", () => {
46
46
  const tools = [
47
- makeTool({ id: 'a', name: 'a', produces: ['integration.connection'] }),
48
- makeTool({ id: 'b', name: 'b', consumes: ['integration.connection'] }),
49
- ]
50
- const graph = buildCapabilityGraph(tools)
51
- expect(graph.edges).toHaveLength(1)
47
+ makeTool({ id: "a", name: "a", produces: ["integration.connection"] }),
48
+ makeTool({ id: "b", name: "b", consumes: ["integration.connection"] }),
49
+ ];
50
+ const graph = buildCapabilityGraph(tools);
51
+ expect(graph.edges).toHaveLength(1);
52
52
  expect(graph.edges[0]).toEqual({
53
- from: 'a',
54
- to: 'b',
55
- resource: 'integration.connection',
56
- domain: 'integration',
57
- })
58
- })
53
+ from: "a",
54
+ to: "b",
55
+ resource: "integration.connection",
56
+ domain: "integration",
57
+ });
58
+ });
59
59
 
60
- it('creates multiple edges for multiple producers of same resource', () => {
60
+ it("creates multiple edges for multiple producers of same resource", () => {
61
61
  const tools = [
62
- makeTool({ id: 'a', name: 'a', produces: ['integration.connection'] }),
63
- makeTool({ id: 'b', name: 'b', produces: ['integration.connection'] }),
64
- makeTool({ id: 'c', name: 'c', consumes: ['integration.connection'] }),
65
- ]
66
- const graph = buildCapabilityGraph(tools)
67
- expect(graph.edges).toHaveLength(2)
62
+ makeTool({ id: "a", name: "a", produces: ["integration.connection"] }),
63
+ makeTool({ id: "b", name: "b", produces: ["integration.connection"] }),
64
+ makeTool({ id: "c", name: "c", consumes: ["integration.connection"] }),
65
+ ];
66
+ const graph = buildCapabilityGraph(tools);
67
+ expect(graph.edges).toHaveLength(2);
68
68
  expect(graph.edges).toContainEqual({
69
- from: 'a',
70
- to: 'c',
71
- resource: 'integration.connection',
72
- domain: 'integration',
73
- })
69
+ from: "a",
70
+ to: "c",
71
+ resource: "integration.connection",
72
+ domain: "integration",
73
+ });
74
74
  expect(graph.edges).toContainEqual({
75
- from: 'b',
76
- to: 'c',
77
- resource: 'integration.connection',
78
- domain: 'integration',
79
- })
80
- })
75
+ from: "b",
76
+ to: "c",
77
+ resource: "integration.connection",
78
+ domain: "integration",
79
+ });
80
+ });
81
81
 
82
- it('derives workflow for linear chain > 2 steps', () => {
82
+ it("derives workflow for linear chain > 2 steps", () => {
83
83
  const tools = [
84
84
  makeTool({
85
- id: 'step1',
86
- name: 'step1',
87
- produces: ['integration.connection'],
85
+ id: "step1",
86
+ name: "step1",
87
+ produces: ["integration.connection"],
88
88
  }),
89
89
  makeTool({
90
- id: 'step2',
91
- name: 'step2',
92
- consumes: ['integration.connection'],
93
- produces: ['slack.channel'],
90
+ id: "step2",
91
+ name: "step2",
92
+ consumes: ["integration.connection"],
93
+ produces: ["slack.channel"],
94
94
  }),
95
95
  makeTool({
96
- id: 'step3',
97
- name: 'step3',
98
- consumes: ['slack.channel'],
99
- produces: ['slack.channel_scope'],
96
+ id: "step3",
97
+ name: "step3",
98
+ consumes: ["slack.channel"],
99
+ produces: ["slack.channel_scope"],
100
100
  }),
101
101
  makeTool({
102
- id: 'step4',
103
- name: 'step4',
104
- consumes: ['slack.channel_scope'],
102
+ id: "step4",
103
+ name: "step4",
104
+ consumes: ["slack.channel_scope"],
105
105
  }),
106
- ]
107
- const graph = buildCapabilityGraph(tools)
108
- expect(graph.workflows).toHaveLength(1)
106
+ ];
107
+ const graph = buildCapabilityGraph(tools);
108
+ expect(graph.workflows).toHaveLength(1);
109
109
  expect(graph.workflows[0].steps).toEqual([
110
- 'step1',
111
- 'step2',
112
- 'step3',
113
- 'step4',
114
- ])
115
- })
110
+ "step1",
111
+ "step2",
112
+ "step3",
113
+ "step4",
114
+ ]);
115
+ });
116
116
 
117
- it('does NOT derive workflow for short chain (2 steps, 1 edge)', () => {
117
+ it("does NOT derive workflow for short chain (2 steps, 1 edge)", () => {
118
118
  const tools = [
119
- makeTool({ id: 'a', name: 'a', produces: ['integration.connection'] }),
120
- makeTool({ id: 'b', name: 'b', consumes: ['integration.connection'] }),
121
- ]
122
- const graph = buildCapabilityGraph(tools)
123
- expect(graph.workflows).toEqual([])
124
- })
119
+ makeTool({ id: "a", name: "a", produces: ["integration.connection"] }),
120
+ makeTool({ id: "b", name: "b", consumes: ["integration.connection"] }),
121
+ ];
122
+ const graph = buildCapabilityGraph(tools);
123
+ expect(graph.workflows).toEqual([]);
124
+ });
125
125
 
126
- it('does not form single workflow from branching nodes', () => {
126
+ it("does not form single workflow from branching nodes", () => {
127
127
  const tools = [
128
128
  makeTool({
129
- id: 'root',
130
- name: 'root',
131
- produces: ['integration.connection'],
129
+ id: "root",
130
+ name: "root",
131
+ produces: ["integration.connection"],
132
132
  }),
133
133
  makeTool({
134
- id: 'branch1',
135
- name: 'branch1',
136
- consumes: ['integration.connection'],
137
- produces: ['slack.channel'],
134
+ id: "branch1",
135
+ name: "branch1",
136
+ consumes: ["integration.connection"],
137
+ produces: ["slack.channel"],
138
138
  }),
139
139
  makeTool({
140
- id: 'branch2',
141
- name: 'branch2',
142
- consumes: ['integration.connection'],
143
- produces: ['slack.coverage'],
140
+ id: "branch2",
141
+ name: "branch2",
142
+ consumes: ["integration.connection"],
143
+ produces: ["slack.coverage"],
144
144
  }),
145
- ]
146
- const graph = buildCapabilityGraph(tools)
145
+ ];
146
+ const graph = buildCapabilityGraph(tools);
147
147
  // root has 2 outgoing edges → not a linear chain
148
- expect(graph.workflows).toEqual([])
149
- })
148
+ expect(graph.workflows).toEqual([]);
149
+ });
150
150
 
151
- describe('full 17-tool integration test', () => {
151
+ describe("full 17-tool integration test", () => {
152
152
  const allTools: MCPToolDescriptor[] = [
153
153
  // Organization
154
154
  makeTool({
155
- id: 'cs_get_org_status',
156
- name: 'cs_get_org_status',
157
- domain: 'organization',
158
- produces: ['org.status'],
155
+ id: "cs_get_org_status",
156
+ name: "cs_get_org_status",
157
+ domain: "organization",
158
+ produces: ["org.status"],
159
159
  }),
160
160
  makeTool({
161
- id: 'cs_update_org',
162
- name: 'cs_update_org',
163
- domain: 'organization',
164
- intent: 'mutate',
161
+ id: "cs_update_org",
162
+ name: "cs_update_org",
163
+ domain: "organization",
164
+ intent: "mutate",
165
165
  }),
166
166
  // Identity
167
167
  makeTool({
168
- id: 'cs_update_profile',
169
- name: 'cs_update_profile',
170
- domain: 'identity',
171
- intent: 'mutate',
168
+ id: "cs_update_profile",
169
+ name: "cs_update_profile",
170
+ domain: "identity",
171
+ intent: "mutate",
172
172
  }),
173
173
  // Integrations
174
174
  makeTool({
175
- id: 'cs_start_slack_auth',
176
- name: 'cs_start_slack_auth',
177
- domain: 'integrations',
178
- integrations: ['slack'],
179
- produces: ['integration.connection'],
175
+ id: "cs_start_slack_auth",
176
+ name: "cs_start_slack_auth",
177
+ domain: "integrations",
178
+ integrations: ["slack"],
179
+ produces: ["integration.connection"],
180
180
  }),
181
181
  makeTool({
182
- id: 'cs_start_google_auth',
183
- name: 'cs_start_google_auth',
184
- domain: 'integrations',
185
- integrations: ['google'],
186
- produces: ['integration.connection'],
182
+ id: "cs_start_google_auth",
183
+ name: "cs_start_google_auth",
184
+ domain: "integrations",
185
+ integrations: ["google"],
186
+ produces: ["integration.connection"],
187
187
  }),
188
188
  makeTool({
189
- id: 'cs_start_zoom_auth',
190
- name: 'cs_start_zoom_auth',
191
- domain: 'integrations',
192
- integrations: ['zoom'],
193
- produces: ['integration.connection'],
189
+ id: "cs_start_zoom_auth",
190
+ name: "cs_start_zoom_auth",
191
+ domain: "integrations",
192
+ integrations: ["zoom"],
193
+ produces: ["integration.connection"],
194
194
  }),
195
195
  makeTool({
196
- id: 'cs_list_connections',
197
- name: 'cs_list_connections',
198
- domain: 'integrations',
199
- produces: ['integration.connection'],
196
+ id: "cs_list_connections",
197
+ name: "cs_list_connections",
198
+ domain: "integrations",
199
+ produces: ["integration.connection"],
200
200
  }),
201
201
  makeTool({
202
- id: 'cs_cleanup_connections',
203
- name: 'cs_cleanup_connections',
204
- domain: 'integrations',
205
- consumes: ['integration.connection'],
202
+ id: "cs_cleanup_connections",
203
+ name: "cs_cleanup_connections",
204
+ domain: "integrations",
205
+ consumes: ["integration.connection"],
206
206
  }),
207
207
  makeTool({
208
- id: 'cs_propose_integration_action',
209
- name: 'cs_propose_integration_action',
210
- domain: 'integrations',
211
- consumes: ['integration.connection'],
208
+ id: "cs_propose_integration_action",
209
+ name: "cs_propose_integration_action",
210
+ domain: "integrations",
211
+ consumes: ["integration.connection"],
212
212
  }),
213
213
  // Discovery
214
214
  makeTool({
215
- id: 'cs_discover_slack',
216
- name: 'cs_discover_slack',
217
- domain: 'discovery',
218
- integrations: ['slack'],
219
- produces: ['slack.channel'],
220
- consumes: ['integration.connection'],
215
+ id: "cs_discover_slack",
216
+ name: "cs_discover_slack",
217
+ domain: "discovery",
218
+ integrations: ["slack"],
219
+ produces: ["slack.channel"],
220
+ consumes: ["integration.connection"],
221
221
  }),
222
222
  makeTool({
223
- id: 'cs_get_slack_coverage',
224
- name: 'cs_get_slack_coverage',
225
- domain: 'discovery',
226
- integrations: ['slack'],
227
- produces: ['slack.coverage'],
228
- consumes: ['integration.connection'],
223
+ id: "cs_get_slack_coverage",
224
+ name: "cs_get_slack_coverage",
225
+ domain: "discovery",
226
+ integrations: ["slack"],
227
+ produces: ["slack.coverage"],
228
+ consumes: ["integration.connection"],
229
229
  }),
230
230
  makeTool({
231
- id: 'cs_list_fingerprints',
232
- name: 'cs_list_fingerprints',
233
- domain: 'discovery',
234
- produces: ['knowledge.fingerprint'],
231
+ id: "cs_list_fingerprints",
232
+ name: "cs_list_fingerprints",
233
+ domain: "discovery",
234
+ produces: ["knowledge.fingerprint"],
235
235
  }),
236
236
  // Ingestion
237
237
  makeTool({
238
- id: 'cs_manage_channel_scope',
239
- name: 'cs_manage_channel_scope',
240
- domain: 'ingestion',
241
- integrations: ['slack'],
242
- produces: ['slack.channel_scope'],
243
- consumes: ['slack.channel'],
238
+ id: "cs_manage_channel_scope",
239
+ name: "cs_manage_channel_scope",
240
+ domain: "ingestion",
241
+ integrations: ["slack"],
242
+ produces: ["slack.channel_scope"],
243
+ consumes: ["slack.channel"],
244
244
  }),
245
245
  makeTool({
246
- id: 'cs_ingest_slack_channel',
247
- name: 'cs_ingest_slack_channel',
248
- domain: 'ingestion',
249
- integrations: ['slack'],
250
- produces: ['ingestion.job'],
251
- consumes: ['slack.channel_scope'],
246
+ id: "cs_ingest_slack_channel",
247
+ name: "cs_ingest_slack_channel",
248
+ domain: "ingestion",
249
+ integrations: ["slack"],
250
+ produces: ["ingestion.job"],
251
+ consumes: ["slack.channel_scope"],
252
252
  }),
253
253
  makeTool({
254
- id: 'cs_get_ingestion_status',
255
- name: 'cs_get_ingestion_status',
256
- domain: 'ingestion',
257
- produces: ['ingestion.job'],
258
- consumes: ['ingestion.job'],
254
+ id: "cs_get_ingestion_status",
255
+ name: "cs_get_ingestion_status",
256
+ domain: "ingestion",
257
+ produces: ["ingestion.job"],
258
+ consumes: ["ingestion.job"],
259
259
  }),
260
260
  // System
261
261
  makeTool({
262
- id: 'cs_system_status',
263
- name: 'cs_system_status',
264
- domain: 'system',
265
- produces: ['system.status'],
262
+ id: "cs_system_status",
263
+ name: "cs_system_status",
264
+ domain: "system",
265
+ produces: ["system.status"],
266
266
  }),
267
267
  makeTool({
268
- id: 'cs_help',
269
- name: 'cs_help',
270
- domain: 'system',
268
+ id: "cs_help",
269
+ name: "cs_help",
270
+ domain: "system",
271
271
  }),
272
- ]
272
+ ];
273
273
 
274
- it('includes Slack ingestion chain edges', () => {
275
- const graph = buildCapabilityGraph(allTools)
274
+ it("includes Slack ingestion chain edges", () => {
275
+ const graph = buildCapabilityGraph(allTools);
276
276
 
277
277
  expect(graph.edges).toContainEqual({
278
- from: 'cs_start_slack_auth',
279
- to: 'cs_discover_slack',
280
- resource: 'integration.connection',
281
- domain: 'integration',
282
- })
278
+ from: "cs_start_slack_auth",
279
+ to: "cs_discover_slack",
280
+ resource: "integration.connection",
281
+ domain: "integration",
282
+ });
283
283
  expect(graph.edges).toContainEqual({
284
- from: 'cs_discover_slack',
285
- to: 'cs_manage_channel_scope',
286
- resource: 'slack.channel',
287
- domain: 'slack',
288
- })
284
+ from: "cs_discover_slack",
285
+ to: "cs_manage_channel_scope",
286
+ resource: "slack.channel",
287
+ domain: "slack",
288
+ });
289
289
  expect(graph.edges).toContainEqual({
290
- from: 'cs_manage_channel_scope',
291
- to: 'cs_ingest_slack_channel',
292
- resource: 'slack.channel_scope',
293
- domain: 'slack',
294
- })
290
+ from: "cs_manage_channel_scope",
291
+ to: "cs_ingest_slack_channel",
292
+ resource: "slack.channel_scope",
293
+ domain: "slack",
294
+ });
295
295
  expect(graph.edges).toContainEqual({
296
- from: 'cs_ingest_slack_channel',
297
- to: 'cs_get_ingestion_status',
298
- resource: 'ingestion.job',
299
- domain: 'ingestion',
300
- })
301
- })
296
+ from: "cs_ingest_slack_channel",
297
+ to: "cs_get_ingestion_status",
298
+ resource: "ingestion.job",
299
+ domain: "ingestion",
300
+ });
301
+ });
302
302
 
303
- it('produces correct total edge count', () => {
304
- const graph = buildCapabilityGraph(allTools)
303
+ it("produces correct total edge count", () => {
304
+ const graph = buildCapabilityGraph(allTools);
305
305
  // integration.connection: 4 producers × 4 consumers = 16 edges
306
306
  // slack.channel: 1 edge (discover_slack → manage_channel_scope)
307
307
  // slack.channel_scope: 1 edge (manage_channel_scope → ingest_slack_channel)
308
308
  // ingestion.job: 2 edges (ingest → status, status → status self-loop)
309
- expect(graph.edges).toHaveLength(20)
310
- })
309
+ expect(graph.edges).toHaveLength(20);
310
+ });
311
311
 
312
- it('does not derive workflows from branching graph', () => {
313
- const graph = buildCapabilityGraph(allTools)
312
+ it("does not derive workflows from branching graph", () => {
313
+ const graph = buildCapabilityGraph(allTools);
314
314
  // With all 17 tools, auth tools have 4 outgoing edges each (branching),
315
315
  // and consumers like discover_slack have 4 incoming edges.
316
316
  // No linear chain starts are walkable → no workflows.
317
- expect(graph.workflows).toEqual([])
318
- })
319
- })
317
+ expect(graph.workflows).toEqual([]);
318
+ });
319
+ });
320
320
 
321
- describe('slack_ingestion workflow derivation', () => {
322
- it('derives slack_ingestion workflow from Slack chain tools', () => {
321
+ describe("slack_ingestion workflow derivation", () => {
322
+ it("derives slack_ingestion workflow from Slack chain tools", () => {
323
323
  // Isolated Slack chain without branching from other auth tools
324
324
  const slackChainTools = [
325
325
  makeTool({
326
- id: 'cs_start_slack_auth',
327
- name: 'cs_start_slack_auth',
328
- integrations: ['slack'],
329
- produces: ['integration.connection'],
326
+ id: "cs_start_slack_auth",
327
+ name: "cs_start_slack_auth",
328
+ integrations: ["slack"],
329
+ produces: ["integration.connection"],
330
330
  }),
331
331
  makeTool({
332
- id: 'cs_discover_slack',
333
- name: 'cs_discover_slack',
334
- integrations: ['slack'],
335
- produces: ['slack.channel'],
336
- consumes: ['integration.connection'],
332
+ id: "cs_discover_slack",
333
+ name: "cs_discover_slack",
334
+ integrations: ["slack"],
335
+ produces: ["slack.channel"],
336
+ consumes: ["integration.connection"],
337
337
  }),
338
338
  makeTool({
339
- id: 'cs_manage_channel_scope',
340
- name: 'cs_manage_channel_scope',
341
- integrations: ['slack'],
342
- produces: ['slack.channel_scope'],
343
- consumes: ['slack.channel'],
339
+ id: "cs_manage_channel_scope",
340
+ name: "cs_manage_channel_scope",
341
+ integrations: ["slack"],
342
+ produces: ["slack.channel_scope"],
343
+ consumes: ["slack.channel"],
344
344
  }),
345
345
  makeTool({
346
- id: 'cs_ingest_slack_channel',
347
- name: 'cs_ingest_slack_channel',
348
- integrations: ['slack'],
349
- consumes: ['slack.channel_scope'],
346
+ id: "cs_ingest_slack_channel",
347
+ name: "cs_ingest_slack_channel",
348
+ integrations: ["slack"],
349
+ consumes: ["slack.channel_scope"],
350
350
  }),
351
- ]
352
- const graph = buildCapabilityGraph(slackChainTools)
353
- expect(graph.workflows).toHaveLength(1)
354
- expect(graph.workflows[0].name).toBe('slack_ingestion')
351
+ ];
352
+ const graph = buildCapabilityGraph(slackChainTools);
353
+ expect(graph.workflows).toHaveLength(1);
354
+ expect(graph.workflows[0].name).toBe("slack_ingestion");
355
355
  expect(graph.workflows[0].steps).toEqual([
356
- 'cs_start_slack_auth',
357
- 'cs_discover_slack',
358
- 'cs_manage_channel_scope',
359
- 'cs_ingest_slack_channel',
360
- ])
361
- expect(graph.workflows[0].description).toContain('start_slack_auth')
362
- expect(graph.workflows[0].description).toContain('ingest_slack_channel')
363
- })
356
+ "cs_start_slack_auth",
357
+ "cs_discover_slack",
358
+ "cs_manage_channel_scope",
359
+ "cs_ingest_slack_channel",
360
+ ]);
361
+ expect(graph.workflows[0].description).toContain("start_slack_auth");
362
+ expect(graph.workflows[0].description).toContain("ingest_slack_channel");
363
+ });
364
364
 
365
- it('extends Slack chain through cs_get_ingestion_status when isolated', () => {
365
+ it("extends Slack chain through cs_get_ingestion_status when isolated", () => {
366
366
  const slackChainWithStatus = [
367
367
  makeTool({
368
- id: 'cs_start_slack_auth',
369
- name: 'cs_start_slack_auth',
370
- integrations: ['slack'],
371
- produces: ['integration.connection'],
368
+ id: "cs_start_slack_auth",
369
+ name: "cs_start_slack_auth",
370
+ integrations: ["slack"],
371
+ produces: ["integration.connection"],
372
372
  }),
373
373
  makeTool({
374
- id: 'cs_discover_slack',
375
- name: 'cs_discover_slack',
376
- integrations: ['slack'],
377
- produces: ['slack.channel'],
378
- consumes: ['integration.connection'],
374
+ id: "cs_discover_slack",
375
+ name: "cs_discover_slack",
376
+ integrations: ["slack"],
377
+ produces: ["slack.channel"],
378
+ consumes: ["integration.connection"],
379
379
  }),
380
380
  makeTool({
381
- id: 'cs_manage_channel_scope',
382
- name: 'cs_manage_channel_scope',
383
- integrations: ['slack'],
384
- produces: ['slack.channel_scope'],
385
- consumes: ['slack.channel'],
381
+ id: "cs_manage_channel_scope",
382
+ name: "cs_manage_channel_scope",
383
+ integrations: ["slack"],
384
+ produces: ["slack.channel_scope"],
385
+ consumes: ["slack.channel"],
386
386
  }),
387
387
  makeTool({
388
- id: 'cs_ingest_slack_channel',
389
- name: 'cs_ingest_slack_channel',
390
- integrations: ['slack'],
391
- produces: ['ingestion.job'],
392
- consumes: ['slack.channel_scope'],
388
+ id: "cs_ingest_slack_channel",
389
+ name: "cs_ingest_slack_channel",
390
+ integrations: ["slack"],
391
+ produces: ["ingestion.job"],
392
+ consumes: ["slack.channel_scope"],
393
393
  }),
394
394
  makeTool({
395
- id: 'cs_get_ingestion_status',
396
- name: 'cs_get_ingestion_status',
397
- produces: ['ingestion.job'],
398
- consumes: ['ingestion.job'],
395
+ id: "cs_get_ingestion_status",
396
+ name: "cs_get_ingestion_status",
397
+ produces: ["ingestion.job"],
398
+ consumes: ["ingestion.job"],
399
399
  }),
400
- ]
401
- const graph = buildCapabilityGraph(slackChainWithStatus)
400
+ ];
401
+ const graph = buildCapabilityGraph(slackChainWithStatus);
402
402
 
403
- expect(graph.workflows).toHaveLength(1)
403
+ expect(graph.workflows).toHaveLength(1);
404
404
  // Chain stops at cs_ingest_slack_channel because cs_get_ingestion_status
405
405
  // has 2 incoming edges (from ingest + self-loop)
406
- expect(graph.workflows[0].steps).toContain('cs_start_slack_auth')
407
- expect(graph.workflows[0].steps).toContain('cs_discover_slack')
408
- expect(graph.workflows[0].steps).toContain('cs_manage_channel_scope')
409
- expect(graph.workflows[0].steps).toContain('cs_ingest_slack_channel')
410
- })
411
- })
406
+ expect(graph.workflows[0].steps).toContain("cs_start_slack_auth");
407
+ expect(graph.workflows[0].steps).toContain("cs_discover_slack");
408
+ expect(graph.workflows[0].steps).toContain("cs_manage_channel_scope");
409
+ expect(graph.workflows[0].steps).toContain("cs_ingest_slack_channel");
410
+ });
411
+ });
412
412
 
413
- it('extracts domain from resource namespace prefix', () => {
413
+ it("extracts domain from resource namespace prefix", () => {
414
414
  const tools = [
415
- makeTool({ id: 'a', name: 'a', produces: ['slack.channel'] }),
416
- makeTool({ id: 'b', name: 'b', consumes: ['slack.channel'] }),
417
- ]
418
- const graph = buildCapabilityGraph(tools)
419
- expect(graph.edges[0].domain).toBe('slack')
420
- })
421
- })
415
+ makeTool({ id: "a", name: "a", produces: ["slack.channel"] }),
416
+ makeTool({ id: "b", name: "b", consumes: ["slack.channel"] }),
417
+ ];
418
+ const graph = buildCapabilityGraph(tools);
419
+ expect(graph.edges[0].domain).toBe("slack");
420
+ });
421
+ });