@adrata/adrata-mcp 1.0.8 → 1.0.30
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/access/oauth.js +27 -0
- package/access/tiers.js +14 -0
- package/api-bridge.js +26 -0
- package/governance/governed-args.js +7 -2
- package/http/edge-block.js +16 -7
- package/http/rate-limit.js +69 -6
- package/package.json +3 -3
- package/security.js +167 -14
- package/server.js +35 -23
- package/server.json +2 -2
- package/skills/qa-the-card/SKILL.md +40 -4
- package/tool-annotations.js +23 -0
- package/tools/provisioning/onboarding-tools.js +730 -0
- package/tools/source-control/connection-tools.js +117 -1
- package/tools/work-board-tools.js +441 -25
- package/tools/work-hub/audit.js +74 -8
- package/tools/work-hub/criteria-quality.js +212 -0
- package/toolsets/communications.js +42 -64
- package/toolsets/spaces.js +10 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** Read-only, product-visible health for Starfield's source-control ingestion. */
|
|
2
|
-
export function registerSourceControlTools(
|
|
2
|
+
export function registerSourceControlTools(
|
|
3
|
+
server,
|
|
4
|
+
{ z, api, ok, validateApiBridgeRequest, buildMutationHeaders, getGrantedScope }
|
|
5
|
+
) {
|
|
3
6
|
server.tool(
|
|
4
7
|
'list_source_control_connections',
|
|
5
8
|
'List source-control connections with repository binding count, last durably acknowledged delivery, rejection state, actionable health, and the exact webhook events that are safe to enable.',
|
|
@@ -23,9 +26,122 @@ export function registerSourceControlTools(server, { z, api, ok }) {
|
|
|
23
26
|
return ok({ events: response?.data ?? response ?? [] });
|
|
24
27
|
}
|
|
25
28
|
);
|
|
29
|
+
|
|
30
|
+
server.tool(
|
|
31
|
+
'bind_repository_to_board',
|
|
32
|
+
'Bind one repository to one board, so a merged pull request carrying a card id moves that card by itself.'
|
|
33
|
+
+ ' Until a board is bound, every merge on it advances nothing and the column timestamps are hand-typed,'
|
|
34
|
+
+ ' which is the input every cycle-time and control chart is built from.'
|
|
35
|
+
+ ' Name BOTH mergeFromColumnId and mergeToColumnId or neither: one end alone is a half-configured rule'
|
|
36
|
+
+ ' that silently does nothing, and the database CHECK constraint refuses it.'
|
|
37
|
+
+ ' Governed write: previews by default. A live write requires dryRun:false plus approved:true, a reason,'
|
|
38
|
+
+ ' and an idempotencyKey (reuse the SAME key on retry — a duplicate bind is refused as a 409).',
|
|
39
|
+
{
|
|
40
|
+
connectionId: z.string().describe('Source-control connection id, from list_source_control_connections.'),
|
|
41
|
+
boardId: z.string().describe('Board id from list_work_boards. One board binds once per connection.'),
|
|
42
|
+
externalRepoId: z.string().describe('The vendor’s own repository id, not its name.'),
|
|
43
|
+
externalFullName: z.string().describe('owner/name, e.g. adrata/adrata.'),
|
|
44
|
+
mergeFromColumnId: z
|
|
45
|
+
.string()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe('Where a merged pull request’s card must be coming FROM. Both ends or neither.'),
|
|
48
|
+
mergeToColumnId: z
|
|
49
|
+
.string()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Where it goes on merge. Both ends or neither.'),
|
|
52
|
+
onMergeAction: z
|
|
53
|
+
.enum(['advance', 'suggest', 'ignore'])
|
|
54
|
+
.optional()
|
|
55
|
+
.describe('Defaults to advance. `suggest` records the proposal without moving the card.'),
|
|
56
|
+
branchSample: z
|
|
57
|
+
.array(z.string())
|
|
58
|
+
.optional()
|
|
59
|
+
.describe(
|
|
60
|
+
'Recent branch names, newest first. NOT stored: the server measures how many already carry a card'
|
|
61
|
+
+ ' reference and seeds the link strategies from what the repository actually does, rather than from'
|
|
62
|
+
+ ' a form somebody filled in. Omitting it means the strategies are chosen without that evidence.'
|
|
63
|
+
),
|
|
64
|
+
advanceOnlyWhenAllMerged: z
|
|
65
|
+
.boolean()
|
|
66
|
+
.optional()
|
|
67
|
+
.describe('Advance only when no linked change request is still open. Defaults true.'),
|
|
68
|
+
openPullsCardIntoProgress: z
|
|
69
|
+
.boolean()
|
|
70
|
+
.optional()
|
|
71
|
+
.describe('Does an OPENED pull request pull its card into In progress? Defaults false.'),
|
|
72
|
+
stagingEnvironmentName: z
|
|
73
|
+
.string()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe('Exact vendor environment name. Absence means that evidence is not configured; never infer a role from a word like "staging".'),
|
|
76
|
+
productionEnvironmentName: z.string().optional().describe('Exact vendor environment name.'),
|
|
77
|
+
dryRun: z.boolean().optional().default(true),
|
|
78
|
+
approved: z.boolean().optional().default(false),
|
|
79
|
+
reason: z.string().optional(),
|
|
80
|
+
idempotencyKey: z.string().optional(),
|
|
81
|
+
},
|
|
82
|
+
async (args) => {
|
|
83
|
+
// Refused HERE rather than at the API, because the 400 this produces reads
|
|
84
|
+
// as a validation error about a column and the actual mistake is that only
|
|
85
|
+
// one end was named. `scm_repositories_move_shape_chk` enforces the same
|
|
86
|
+
// shape in the database; this says why before the round trip.
|
|
87
|
+
const from = args.mergeFromColumnId;
|
|
88
|
+
const to = args.mergeToColumnId;
|
|
89
|
+
if (Boolean(from) !== Boolean(to)) {
|
|
90
|
+
return ok({
|
|
91
|
+
error: true,
|
|
92
|
+
message:
|
|
93
|
+
'Name both mergeFromColumnId and mergeToColumnId, or neither. One end alone is a half-configured'
|
|
94
|
+
+ ' move rule: it is accepted nowhere, and if it were, it would silently never fire — the failure'
|
|
95
|
+
+ ' mode that takes longest to notice.',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const path = `/api/v1/scm/connections/${encodeURIComponent(args.connectionId)}/repositories`;
|
|
100
|
+
const body = {
|
|
101
|
+
boardId: args.boardId,
|
|
102
|
+
externalRepoId: args.externalRepoId,
|
|
103
|
+
externalFullName: args.externalFullName,
|
|
104
|
+
mergeFromColumnId: from,
|
|
105
|
+
mergeToColumnId: to,
|
|
106
|
+
onMergeAction: args.onMergeAction,
|
|
107
|
+
branchSample: args.branchSample,
|
|
108
|
+
advanceOnlyWhenAllMerged: args.advanceOnlyWhenAllMerged,
|
|
109
|
+
openPullsCardIntoProgress: args.openPullsCardIntoProgress,
|
|
110
|
+
stagingEnvironmentName: args.stagingEnvironmentName,
|
|
111
|
+
productionEnvironmentName: args.productionEnvironmentName,
|
|
112
|
+
};
|
|
113
|
+
const preview = validateApiBridgeRequest({
|
|
114
|
+
method: 'POST',
|
|
115
|
+
path,
|
|
116
|
+
body,
|
|
117
|
+
dryRun: args.dryRun,
|
|
118
|
+
approved: args.approved,
|
|
119
|
+
reason: args.reason,
|
|
120
|
+
idempotencyKey: args.idempotencyKey,
|
|
121
|
+
grantedScope: getGrantedScope(),
|
|
122
|
+
});
|
|
123
|
+
if (preview.dryRun) {
|
|
124
|
+
return ok({
|
|
125
|
+
dryRun: true,
|
|
126
|
+
action: `Bind ${args.externalFullName} to board ${args.boardId}`,
|
|
127
|
+
movesCardsOnMerge:
|
|
128
|
+
to === undefined
|
|
129
|
+
? 'No. Without both column ends this binding records deliveries but advances nothing.'
|
|
130
|
+
: `Yes: a merged pull request moves its card ${from} -> ${to}.`,
|
|
131
|
+
note: 'Nothing was written. Confirm to create the binding.',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const data = await api('POST', path, {
|
|
135
|
+
body,
|
|
136
|
+
headers: buildMutationHeaders(args),
|
|
137
|
+
});
|
|
138
|
+
return ok({ bound: true, repository: data?.data ?? data });
|
|
139
|
+
}
|
|
140
|
+
);
|
|
26
141
|
}
|
|
27
142
|
|
|
28
143
|
export const SOURCE_CONTROL_TOOL_NAMES = [
|
|
29
144
|
'list_source_control_connections',
|
|
30
145
|
'get_source_control_connection_events',
|
|
146
|
+
'bind_repository_to_board',
|
|
31
147
|
];
|