@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.35 → 0.1.46
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/bin/adl +2 -2
- package/bin/reconcile +3 -11
- package/bin/setup +15 -15
- package/package.json +1 -1
- package/packages/agent-hooks/deploy-profile.json +1 -1
- package/packages/agent-hooks/package.json +1 -1
- package/packages/agent-hooks/src/main.ts +23 -2
- package/packages/agent-hooks/src/pre-tool-use/handler.ts +2 -2
- package/packages/agent-hooks/src/rules/impl/adl-build-run-role.ts +116 -0
- package/packages/agent-hooks/src/rules/impl/adl-git-user-override-block.ts +159 -0
- package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +22 -12
- package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +9 -9
- package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +6 -5
- package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +11 -5
- package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +18 -5
- package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +30 -25
- package/packages/agent-hooks/src/rules/impl/git-core.ts +4 -8
- package/packages/agent-hooks/src/rules/impl/git-target.ts +5 -0
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +4 -2
- package/packages/agent-hooks/src/rules/impl/tool-frontend.ts +230 -11
- package/packages/agent-hooks/src/rules/registry.ts +11 -2
- package/packages/agent-hooks/src/rules/shell/git-identity.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/invocation.ts +14 -2
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +10 -7
- package/packages/agent-settings/assets/TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md +2 -2
- package/packages/agent-settings/package.json +1 -1
- package/packages/agent-settings/src/deploy/agents-deploy.ts +19 -1
- package/packages/agent-settings/src/deploy/index.ts +1 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +4 -6
- package/packages/agent-skills/assets/code-review/SKILL.md +84 -66
- package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +23 -2
- package/packages/agent-skills/assets/diagnosing-bugs/references/FEEDBACK-LOOP-TACTICS.md +1 -1
- package/packages/agent-skills/assets/explore-codebase/SKILL.md +3 -2
- package/packages/agent-skills/assets/finalize-feature/SKILL.md +63 -0
- package/packages/agent-skills/assets/fix-ci/SKILL.md +58 -0
- package/packages/agent-skills/assets/handoff/SKILL.md +1 -1
- package/packages/agent-skills/assets/implement-feature/SKILL.md +150 -0
- package/packages/agent-skills/assets/implement-feature/references/briefs.md +94 -0
- package/packages/agent-skills/assets/implement-item/SKILL.md +71 -0
- package/packages/agent-skills/assets/mechanics/SKILL.md +38 -0
- package/packages/agent-skills/assets/plan-feature/SKILL.md +141 -0
- package/packages/agent-skills/assets/prepare-promotion/SKILL.md +90 -0
- package/packages/agent-skills/assets/ralplan/SKILL.md +149 -0
- package/packages/agent-skills/assets/refactor-safely/SKILL.md +4 -3
- package/packages/agent-skills/assets/report-bug/SKILL.md +72 -0
- package/packages/agent-skills/assets/review-change/SKILL.md +82 -0
- package/packages/agent-skills/assets/review-plan/SKILL.md +124 -0
- package/packages/agent-skills/assets/triage-workitems/SKILL.md +99 -0
- package/packages/agent-skills/assets/ultragoal/SKILL.md +77 -0
- package/packages/agent-skills/assets/validate-design/SKILL.md +64 -0
- package/packages/agent-skills/assets/verify-item/SKILL.md +71 -0
- package/packages/agent-skills/assets/wayfinder/SKILL.md +1 -1
- package/packages/agent-skills/assets/workitems-process/SKILL.md +145 -0
- package/packages/agent-skills/assets/workitems-process/references/ado-and-git.md +227 -0
- package/packages/agent-skills/assets/workitems-process/references/evidence.md +74 -0
- package/packages/agent-skills/assets/workitems-process/references/workitem-states.md +92 -0
- package/packages/agent-skills/assets/write-feature/SKILL.md +94 -0
- package/packages/agent-skills/dist/deploy.d.ts +52 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
- package/packages/agent-skills/dist/deploy.js +218 -7
- package/packages/agent-skills/dist/deploy.js.map +1 -1
- package/packages/agent-skills/dist/index.d.ts +1 -1
- package/packages/agent-skills/dist/index.d.ts.map +1 -1
- package/packages/agent-skills/dist/index.js +1 -1
- package/packages/agent-skills/dist/index.js.map +1 -1
- package/packages/agent-skills/package.json +1 -1
- package/packages/agent-skills/src/deploy.ts +288 -6
- package/packages/agent-skills/src/index.ts +10 -1
- package/packages/azdo/README.md +13 -4
- package/packages/azdo/bunfig.toml +6 -0
- package/packages/azdo/package.json +1 -1
- package/packages/azdo/scripts/probe-ado-rules.ts +1 -1
- package/packages/azdo/src/activity-log.ts +118 -0
- package/packages/azdo/src/azdo-attachments.ts +109 -0
- package/packages/azdo/src/azdo-pl.ts +100 -3
- package/packages/azdo/src/azdo-pr.ts +376 -17
- package/packages/azdo/src/azdo-wit.ts +594 -34
- package/packages/azdo/src/cli.ts +119 -12
- package/packages/azdo/src/lib/client.ts +95 -17
- package/packages/azdo/src/lib/validate-pr-metadata.ts +14 -5
- package/packages/azdo/src/mcp-server.ts +121 -8
- package/packages/azdo/src/tool-dispatch.ts +107 -23
- package/packages/azdo/src/workflow-ladder.csv +125 -107
- package/packages/azdo/src/workflow-rules.ts +254 -97
- package/packages/fleet/src/install-adl-package.ts +4 -3
- package/packages/repo-controls/README.md +12 -4
- package/packages/repo-controls/assets/promote.ts +1 -0
- package/packages/repo-controls/assets/scaffold/docs/AGENTS.md +5 -5
- package/packages/repo-controls/assets/scaffold/plans/AGENTS.md +42 -13
- package/packages/repo-controls/assets/scaffold/root/CONTRIBUTING.md +5 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +4 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +1 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/no-type.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-experiment.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-research.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-last-update.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +3 -22
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +39 -182
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/features/az601-clean/intent.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +90 -321
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +31 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +282 -54
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/design.md +35 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/file-map-reference.md +19 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/intent.md +25 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +25 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/requirements.md +44 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/requirements.md +44 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +646 -53
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +3 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +1 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +1 -1
- package/packages/repo-controls/package.json +1 -1
- package/packages/repo-controls/src/config.ts +21 -2
- package/packages/repo-controls/src/doctor.ts +9 -14
- package/packages/repo-controls/src/findings-ratchet.ts +12 -0
- package/packages/repo-controls/src/hook.ts +61 -4
package/packages/azdo/src/cli.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { dispatchTool, type ToolArguments } from './tool-dispatch.ts';
|
|
|
3
3
|
type Option = {
|
|
4
4
|
flag: string;
|
|
5
5
|
key: string;
|
|
6
|
-
type: 'string' | 'integer' | 'integer-list' | 'json-object' | 'date' | 'boolean';
|
|
6
|
+
type: 'string' | 'integer' | 'number' | 'integer-list' | 'json-object' | 'date' | 'boolean';
|
|
7
7
|
values?: readonly string[];
|
|
8
8
|
};
|
|
9
9
|
|
|
@@ -45,6 +45,9 @@ const commands: readonly Command[] = [
|
|
|
45
45
|
{ flag: '--no-auto-complete', key: 'autoComplete', type: 'boolean' },
|
|
46
46
|
{ flag: '--merge-strategy', key: 'mergeStrategy', type: 'string', values: ['Squash'] },
|
|
47
47
|
{ flag: '--delete-source-branch', key: 'deleteSourceBranch', type: 'boolean' },
|
|
48
|
+
{ flag: '--attachment-content', key: 'attachmentContent', type: 'string' },
|
|
49
|
+
{ flag: '--add-work-items', key: 'addWorkItems', type: 'integer-list' },
|
|
50
|
+
{ flag: '--remove-work-items', key: 'removeWorkItems', type: 'integer-list' },
|
|
48
51
|
{ flag: '--repository', key: 'repository', type: 'string' },
|
|
49
52
|
],
|
|
50
53
|
validate: requirePullRequestWrite,
|
|
@@ -85,26 +88,108 @@ const commands: readonly Command[] = [
|
|
|
85
88
|
options: [{ flag: '--id', key: 'id', type: 'integer' }, { flag: '--ids', key: 'ids', type: 'string' }, { flag: '--type', key: 'type', type: 'string', values: WORK_ITEM_TYPES }, { flag: '--state', key: 'state', type: 'string' }, { flag: '--assigned-to', key: 'assignedTo', type: 'string' }, { flag: '--limit', key: 'limit', type: 'integer' }, { flag: '--raw', key: 'raw', type: 'boolean' }],
|
|
86
89
|
},
|
|
87
90
|
{
|
|
88
|
-
name: 'workitem-create-or-update',
|
|
89
|
-
tool: '
|
|
91
|
+
name: 'workitem-create-or-update-feature',
|
|
92
|
+
tool: 'workitem_create_or_update_feature',
|
|
90
93
|
options: [
|
|
91
94
|
{ flag: '--id', key: 'id', type: 'integer' },
|
|
92
|
-
{ flag: '--type', key: 'type', type: 'string', values: WORK_ITEM_TYPES },
|
|
93
95
|
{ flag: '--title', key: 'title', type: 'string' },
|
|
94
96
|
{ flag: '--description', key: 'description', type: 'string' },
|
|
95
97
|
{ flag: '--parent-id', key: 'parentId', type: 'integer' },
|
|
96
98
|
{ flag: '--predecessors', key: 'predecessors', type: 'integer-list' },
|
|
97
99
|
{ flag: '--related', key: 'related', type: 'integer-list' },
|
|
100
|
+
{ flag: '--remove-predecessor', key: 'removePredecessor', type: 'integer' },
|
|
101
|
+
{ flag: '--remove-related', key: 'removeRelated', type: 'integer' },
|
|
98
102
|
{ flag: '--fields', key: 'fields', type: 'json-object' },
|
|
99
103
|
{ flag: '--state', key: 'state', type: 'string' },
|
|
100
104
|
{ flag: '--comment', key: 'comment', type: 'string' },
|
|
101
105
|
{ flag: '--assigned-to', key: 'assignedTo', type: 'string' },
|
|
102
106
|
{ flag: '--acceptance-criteria', key: 'acceptanceCriteria', type: 'string' },
|
|
103
|
-
{ flag: '--priority', key: 'priority', type: 'integer' },
|
|
107
|
+
{ flag: '--priority', key: 'priority', type: 'integer', values: ['1', '2', '3', '4'] },
|
|
104
108
|
{ flag: '--start-date', key: 'startDate', type: 'date' },
|
|
105
109
|
{ flag: '--target-date', key: 'targetDate', type: 'date' },
|
|
110
|
+
{ flag: '--plan-revision', key: 'planRevision', type: 'integer' },
|
|
111
|
+
{ flag: '--plan-hash', key: 'planHash', type: 'string' },
|
|
112
|
+
{ flag: '--baseline-sha', key: 'baselineSha', type: 'string' },
|
|
106
113
|
],
|
|
107
|
-
validate: (args) => { if (args.id === undefined) requireKeys(args, ['
|
|
114
|
+
validate: (args) => { if (args.id === undefined) requireKeys(args, ['title', 'parentId', 'priority', 'description']); },
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'workitem-create-or-update-pbi',
|
|
118
|
+
tool: 'workitem_create_or_update_pbi',
|
|
119
|
+
options: [
|
|
120
|
+
{ flag: '--id', key: 'id', type: 'integer' },
|
|
121
|
+
{ flag: '--title', key: 'title', type: 'string' },
|
|
122
|
+
{ flag: '--description', key: 'description', type: 'string' },
|
|
123
|
+
{ flag: '--parent-id', key: 'parentId', type: 'integer' },
|
|
124
|
+
{ flag: '--related', key: 'related', type: 'integer-list' },
|
|
125
|
+
{ flag: '--remove-related', key: 'removeRelated', type: 'integer' },
|
|
126
|
+
{ flag: '--fields', key: 'fields', type: 'json-object' },
|
|
127
|
+
{ flag: '--state', key: 'state', type: 'string' },
|
|
128
|
+
{ flag: '--comment', key: 'comment', type: 'string' },
|
|
129
|
+
{ flag: '--assigned-to', key: 'assignedTo', type: 'string' },
|
|
130
|
+
{ flag: '--acceptance-criteria', key: 'acceptanceCriteria', type: 'string' },
|
|
131
|
+
{ flag: '--priority', key: 'priority', type: 'integer', values: ['1', '2', '3', '4'] },
|
|
132
|
+
{ flag: '--effort', key: 'effort', type: 'number' },
|
|
133
|
+
{ flag: '--start-date', key: 'startDate', type: 'date' },
|
|
134
|
+
{ flag: '--target-date', key: 'targetDate', type: 'date' },
|
|
135
|
+
],
|
|
136
|
+
validate: (args) => { if (args.id === undefined) requireKeys(args, ['title', 'parentId', 'description', 'effort']); },
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'workitem-create-or-update-bug',
|
|
140
|
+
tool: 'workitem_create_or_update_bug',
|
|
141
|
+
options: [
|
|
142
|
+
{ flag: '--id', key: 'id', type: 'integer' },
|
|
143
|
+
{ flag: '--title', key: 'title', type: 'string' },
|
|
144
|
+
{ flag: '--description', key: 'description', type: 'string' },
|
|
145
|
+
{ flag: '--parent-id', key: 'parentId', type: 'integer' },
|
|
146
|
+
{ flag: '--predecessors', key: 'predecessors', type: 'integer-list' },
|
|
147
|
+
{ flag: '--related', key: 'related', type: 'integer-list' },
|
|
148
|
+
{ flag: '--remove-predecessor', key: 'removePredecessor', type: 'integer' },
|
|
149
|
+
{ flag: '--remove-related', key: 'removeRelated', type: 'integer' },
|
|
150
|
+
{ flag: '--fields', key: 'fields', type: 'json-object' },
|
|
151
|
+
{ flag: '--state', key: 'state', type: 'string' },
|
|
152
|
+
{ flag: '--comment', key: 'comment', type: 'string' },
|
|
153
|
+
{ flag: '--assigned-to', key: 'assignedTo', type: 'string' },
|
|
154
|
+
{ flag: '--acceptance-criteria', key: 'acceptanceCriteria', type: 'string' },
|
|
155
|
+
{ flag: '--priority', key: 'priority', type: 'integer', values: ['1', '2', '3', '4'] },
|
|
156
|
+
{ flag: '--effort', key: 'effort', type: 'number' },
|
|
157
|
+
{ flag: '--start-date', key: 'startDate', type: 'date' },
|
|
158
|
+
{ flag: '--target-date', key: 'targetDate', type: 'date' },
|
|
159
|
+
],
|
|
160
|
+
validate: (args) => { if (args.id === undefined) requireKeys(args, ['title', 'parentId', 'description', 'effort']); },
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'workitem-comments-read',
|
|
164
|
+
tool: 'workitem_comments_read',
|
|
165
|
+
options: [{ flag: '--id', key: 'id', type: 'integer' }],
|
|
166
|
+
validate: (args) => requireKeys(args, ['id']),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'workitem-attachments',
|
|
170
|
+
tool: 'workitem_attachments',
|
|
171
|
+
options: [
|
|
172
|
+
{ flag: '--id', key: 'id', type: 'integer' },
|
|
173
|
+
{ flag: '--action', key: 'action', type: 'string', values: ['read', 'upload', 'delete'] },
|
|
174
|
+
{ flag: '--file-name', key: 'fileName', type: 'string' },
|
|
175
|
+
{ flag: '--content', key: 'content', type: 'string' },
|
|
176
|
+
],
|
|
177
|
+
validate: (args) => {
|
|
178
|
+
requireKeys(args, ['id', 'action']);
|
|
179
|
+
if (args.action === 'upload' || args.action === 'delete') requireKeys(args, ['fileName']);
|
|
180
|
+
if (args.action === 'upload') requireKeys(args, ['content']);
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'activity-add',
|
|
185
|
+
tool: 'activity_add',
|
|
186
|
+
options: [{ flag: '--note', key: 'note', type: 'string' }],
|
|
187
|
+
validate: (args) => requireKeys(args, ['note']),
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'activity-list',
|
|
191
|
+
tool: 'activity_list',
|
|
192
|
+
options: [],
|
|
108
193
|
},
|
|
109
194
|
];
|
|
110
195
|
|
|
@@ -112,12 +197,18 @@ const help = `Usage: adl mcp cli <command> [options]
|
|
|
112
197
|
|
|
113
198
|
Commands:
|
|
114
199
|
pr-list-or-get [--id ID] [--status active|completed|abandoned|all] [--repository REPOSITORY]
|
|
115
|
-
pr-create-or-update --action create|update [--pull-request-id ID] [--title TITLE] [--description DESCRIPTION] [--auto-complete|--no-auto-complete] [--merge-strategy Squash] [--delete-source-branch] [--repository REPOSITORY]
|
|
200
|
+
pr-create-or-update --action create|update [--pull-request-id ID] [--title TITLE] [--description DESCRIPTION] [--auto-complete|--no-auto-complete] [--merge-strategy Squash] [--delete-source-branch] [--attachment-content TEXT] [--add-work-items ID[,ID...]] [--remove-work-items ID[,ID...]] [--repository REPOSITORY]
|
|
116
201
|
pr-review --pull-request-id ID [--comment TEXT] [--vote approve|approve-with-suggestions|reset|wait-for-author|reject] [--target-branch BRANCH] [--repository REPOSITORY]
|
|
117
202
|
build-list-or-get [--build-id ID] [--branch BRANCH] [--top N] [--tail N]
|
|
118
203
|
build-run --id ID [--branch BRANCH]
|
|
119
204
|
workitem-list-or-get [--id ID] [--ids IDS] [--type TYPE] [--state STATE] [--assigned-to IDENTITY] [--limit N] [--raw]
|
|
120
|
-
workitem-create-or-update [--id ID]
|
|
205
|
+
workitem-create-or-update-feature [--id ID] --title TITLE --parent-id ID --priority 1|2|3|4 --description DESCRIPTION [--predecessors ID[,ID...]] [--related ID[,ID...]] [--remove-predecessor ID] [--remove-related ID] [--fields JSON_OBJECT] [--state STATE] [--comment TEXT] [--assigned-to IDENTITY] [--acceptance-criteria TEXT] [--start-date YYYY-MM-DD] [--target-date YYYY-MM-DD] [--plan-revision N] [--plan-hash SHA256] [--baseline-sha SHA]
|
|
206
|
+
workitem-create-or-update-pbi [--id ID] --title TITLE --parent-id ID --description DESCRIPTION --effort DAYS [--related ID[,ID...]] [--remove-related ID] [--fields JSON_OBJECT] [--state STATE] [--comment TEXT] [--assigned-to IDENTITY] [--acceptance-criteria TEXT] [--priority 1|2|3|4] [--start-date YYYY-MM-DD] [--target-date YYYY-MM-DD]
|
|
207
|
+
workitem-create-or-update-bug [--id ID] --title TITLE --parent-id ID --description DESCRIPTION --effort DAYS [--predecessors ID[,ID...]] [--related ID[,ID...]] [--remove-predecessor ID] [--remove-related ID] [--fields JSON_OBJECT] [--state STATE] [--comment TEXT] [--assigned-to IDENTITY] [--acceptance-criteria TEXT] [--priority 1|2|3|4] [--start-date YYYY-MM-DD] [--target-date YYYY-MM-DD]
|
|
208
|
+
workitem-comments-read --id ID
|
|
209
|
+
workitem-attachments --id ID --action read|upload|delete [--file-name NAME] [--content TEXT]
|
|
210
|
+
activity-add --note TEXT
|
|
211
|
+
activity-list
|
|
121
212
|
`;
|
|
122
213
|
|
|
123
214
|
function requireKeys(args: ToolArguments, keys: string[]): void {
|
|
@@ -137,6 +228,12 @@ function requirePullRequestWrite(args: ToolArguments): void {
|
|
|
137
228
|
if (args.deleteSourceBranch !== undefined) {
|
|
138
229
|
throw new Error('--delete-source-branch is only valid for pr-create-or-update update');
|
|
139
230
|
}
|
|
231
|
+
if (args.addWorkItems !== undefined) {
|
|
232
|
+
throw new Error('--add-work-items is only valid for pr-create-or-update update');
|
|
233
|
+
}
|
|
234
|
+
if (args.removeWorkItems !== undefined) {
|
|
235
|
+
throw new Error('--remove-work-items is only valid for pr-create-or-update update');
|
|
236
|
+
}
|
|
140
237
|
requireKeys(args, ['title', 'description']);
|
|
141
238
|
return;
|
|
142
239
|
}
|
|
@@ -147,12 +244,16 @@ function requirePullRequestWrite(args: ToolArguments): void {
|
|
|
147
244
|
throw new Error('--target-branch is not supported; PRs always target integration');
|
|
148
245
|
}
|
|
149
246
|
requireKeys(args, ['pullRequestId']);
|
|
247
|
+
const hasAdd = Array.isArray(args.addWorkItems) && (args.addWorkItems as unknown[]).length > 0;
|
|
248
|
+
const hasRemove = Array.isArray(args.removeWorkItems) && (args.removeWorkItems as unknown[]).length > 0;
|
|
150
249
|
if (
|
|
151
250
|
args.title === undefined &&
|
|
152
251
|
args.description === undefined &&
|
|
153
252
|
args.autoComplete !== true &&
|
|
154
253
|
args.mergeStrategy === undefined &&
|
|
155
|
-
args.deleteSourceBranch !== true
|
|
254
|
+
args.deleteSourceBranch !== true &&
|
|
255
|
+
!hasAdd &&
|
|
256
|
+
!hasRemove
|
|
156
257
|
) {
|
|
157
258
|
throw new Error('pr-create-or-update update requires metadata or completion options');
|
|
158
259
|
}
|
|
@@ -210,9 +311,18 @@ function parseOptions(command: Command, tokens: readonly string[]): ToolArgument
|
|
|
210
311
|
const value = tokens[index + 1];
|
|
211
312
|
if (value === undefined || value.startsWith('--')) throw new Error(`Option requires a value: ${token}`);
|
|
212
313
|
index += 1;
|
|
314
|
+
// An allowed-values list applies to every option that takes one, not just strings — `--priority 5` is refused here rather than at the board.
|
|
315
|
+
if (option.values && !option.values.includes(value)) {
|
|
316
|
+
throw new Error(`Invalid value for ${token}: ${value}; expected ${option.values.join(', ')}`);
|
|
317
|
+
}
|
|
213
318
|
if (option.type === 'integer') {
|
|
214
319
|
if (!/^[1-9][0-9]*$/.test(value)) throw new Error(`Option requires a positive integer: ${token}`);
|
|
215
320
|
args[option.key] = Number(value);
|
|
321
|
+
} else if (option.type === 'number') {
|
|
322
|
+
// Effort is days: a fraction is a normal value, a negative is not.
|
|
323
|
+
const days = Number(value);
|
|
324
|
+
if (!Number.isFinite(days) || days < 0) throw new Error(`Option requires a non-negative number of days: ${token}`);
|
|
325
|
+
args[option.key] = days;
|
|
216
326
|
} else if (option.type === 'integer-list') {
|
|
217
327
|
args[option.key] = parsePositiveIntegerList(token, value);
|
|
218
328
|
} else if (option.type === 'json-object') {
|
|
@@ -221,9 +331,6 @@ function parseOptions(command: Command, tokens: readonly string[]): ToolArgument
|
|
|
221
331
|
args[option.key] = parseDate(token, value);
|
|
222
332
|
} else {
|
|
223
333
|
if (value.trim() === '') throw new Error(`Option requires a non-empty value: ${token}`);
|
|
224
|
-
if (option.values && !option.values.includes(value)) {
|
|
225
|
-
throw new Error(`Invalid value for ${token}: ${value}; expected ${option.values.join(', ')}`);
|
|
226
|
-
}
|
|
227
334
|
if (option.key === 'ids') {
|
|
228
335
|
args[option.key] = parsePositiveIntegerList('--ids', value);
|
|
229
336
|
} else {
|
|
@@ -15,18 +15,29 @@ export interface AdoClientConfig {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* Azure DevOps organization, project and PR target are NEVER hardcoded.
|
|
19
|
+
* `resolveOrg` / `resolveProject` derive org and project at call time from
|
|
20
|
+
* the checkout's git remote (the canonical source of truth —
|
|
21
|
+
* `parseAzureRemote` reads `git remote get-url origin`) and throw with a
|
|
22
|
+
* "what is missing" message when the remote is not Azure-shaped.
|
|
23
|
+
* `PR_TARGET_BRANCH` is the one exception: every PR in this fleet opens
|
|
24
|
+
* into `integration` and `azdo-pr.ts`'s create path refuses any caller
|
|
25
|
+
* override, so it lives as a constant.
|
|
20
26
|
*
|
|
21
|
-
* `enact-webview` is a REPOSITORY inside the
|
|
22
|
-
*
|
|
23
|
-
* different URL than the PR and build calls in the same process.
|
|
24
|
-
*
|
|
27
|
+
* `enact-webview` is a REPOSITORY inside the live project, not a project —
|
|
28
|
+
* an earlier version of this file defaulted the project to it, so work-item
|
|
29
|
+
* calls hit a different URL than the PR and build calls in the same process.
|
|
30
|
+
* That drift is the bug the explicit-resolver shape is meant to prevent.
|
|
31
|
+
*
|
|
32
|
+
* `resolveRepository` keeps an `AZURE_DEVOPS_REPO` env leg as a test
|
|
33
|
+
* affordance: many existing tests in this package set the env var to drive
|
|
34
|
+
* the resolver without standing up a fixture. The production contract is
|
|
35
|
+
* the same as the rest — the git remote is the source of truth — but the
|
|
36
|
+
* env leg stays because removing it would cascade into ~14 test files. The
|
|
37
|
+
* test preload's `setTestDefaults` is the long-term replacement; the env leg
|
|
38
|
+
* can be retired when those tests are migrated to fixture-driven cwd
|
|
39
|
+
* arguments.
|
|
25
40
|
*/
|
|
26
|
-
export const DEFAULT_ORG = 'amsterdamdatalabs';
|
|
27
|
-
export const DEFAULT_PROJECT = 'Enact';
|
|
28
|
-
/** The one PR target this opinionated tool opens against. */
|
|
29
|
-
export const PR_TARGET_BRANCH = 'integration';
|
|
30
41
|
|
|
31
42
|
/** Current checkout branch, or undefined when git cannot determine it. */
|
|
32
43
|
export function currentBranch(cwd?: string): string | undefined {
|
|
@@ -99,6 +110,18 @@ export function parseAzureRemote(url: string): AzureRemote | null {
|
|
|
99
110
|
* every tool call.
|
|
100
111
|
*/
|
|
101
112
|
let remoteCache: AzureRemote | null | undefined;
|
|
113
|
+
/** Test seam: forget the cached remote. The remote cannot change under a real run, but a test process running multiple files in the same bun test invocation sees the cached value from the first file that called `currentRemote()` without a cwd. */
|
|
114
|
+
export function resetRemoteCacheForTests(): void {
|
|
115
|
+
remoteCache = undefined;
|
|
116
|
+
}
|
|
117
|
+
/** Test seam: install defaults that `resolveOrg` / `resolveProject` / `resolveRepository` use when no argument and no git remote are available. Real runs never call this — the working directory's git remote is the canonical source of truth. Tests call it once from a `bunfig.toml` preload so every test file inherits the same values without per-file boilerplate. */
|
|
118
|
+
let testDefaults: AzureRemote | null = null;
|
|
119
|
+
export function setTestDefaults(remote: AzureRemote): void {
|
|
120
|
+
testDefaults = remote;
|
|
121
|
+
}
|
|
122
|
+
export function resetTestDefaults(): void {
|
|
123
|
+
testDefaults = null;
|
|
124
|
+
}
|
|
102
125
|
export function currentRemote(cwd?: string): AzureRemote | null {
|
|
103
126
|
if (cwd !== undefined) {
|
|
104
127
|
const probe = spawnSync('git', ['remote', 'get-url', 'origin'], { cwd, encoding: 'utf8', timeout: 5000 });
|
|
@@ -110,14 +133,51 @@ export function currentRemote(cwd?: string): AzureRemote | null {
|
|
|
110
133
|
return remoteCache;
|
|
111
134
|
}
|
|
112
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Resolve the Azure DevOps organization. Order: env `AZURE_DEVOPS_ORG` →
|
|
138
|
+
* cwd's git remote → testDefaults → throw.
|
|
139
|
+
*
|
|
140
|
+
* The env leg is a test affordance: many existing tests in this package set
|
|
141
|
+
* `AZURE_DEVOPS_ORG` and `AZURE_DEVOPS_PROJECT` in `beforeAll` to drive the
|
|
142
|
+
* resolver against fixtures whose identity names are coupled to a specific
|
|
143
|
+
* project string (e.g. `'Enact Build Service (amsterdamdatalabs)'`).
|
|
144
|
+
* Production runs always hit the cwd branch; the env leg never fires
|
|
145
|
+
* because real runs never set it.
|
|
146
|
+
*/
|
|
113
147
|
export function resolveOrg(cwd?: string): string {
|
|
114
|
-
|
|
148
|
+
const org = configured(process.env.AZURE_DEVOPS_ORG) ?? currentRemote(cwd)?.org ?? testDefaults?.org;
|
|
149
|
+
if (org !== undefined) return org;
|
|
150
|
+
throw new Error(
|
|
151
|
+
'Cannot determine the Azure DevOps organization: AZURE_DEVOPS_ORG is not set, ' +
|
|
152
|
+
'and `git remote get-url origin` in this working directory is not an Azure DevOps remote. ' +
|
|
153
|
+
'Set AZURE_DEVOPS_ORG or run from a checkout of the target repo.',
|
|
154
|
+
);
|
|
115
155
|
}
|
|
116
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the Azure DevOps project. Order: env `AZURE_DEVOPS_PROJECT` →
|
|
159
|
+
* cwd's git remote → testDefaults → throw. See `resolveOrg` for why the env
|
|
160
|
+
* leg is preserved.
|
|
161
|
+
*/
|
|
117
162
|
export function resolveProject(cwd?: string): string {
|
|
118
|
-
|
|
163
|
+
const project = configured(process.env.AZURE_DEVOPS_PROJECT) ?? currentRemote(cwd)?.project ?? testDefaults?.project;
|
|
164
|
+
if (project !== undefined) return project;
|
|
165
|
+
throw new Error(
|
|
166
|
+
'Cannot determine the Azure DevOps project: AZURE_DEVOPS_PROJECT is not set, ' +
|
|
167
|
+
'and `git remote get-url origin` in this working directory is not an Azure DevOps remote. ' +
|
|
168
|
+
'Set AZURE_DEVOPS_PROJECT or run from a checkout of the target repo.',
|
|
169
|
+
);
|
|
119
170
|
}
|
|
120
171
|
|
|
172
|
+
/**
|
|
173
|
+
* The branch a PR is opened against. Every PR in this fleet targets
|
|
174
|
+
* `integration` so promotion through G2 is uniform; `azdo-pr.ts`'s create
|
|
175
|
+
* path enforces this by rejecting any caller-supplied `targetBranch`
|
|
176
|
+
* argument before the body is built. This is a design rule, not a value
|
|
177
|
+
* resolved at runtime, so it lives as a constant.
|
|
178
|
+
*/
|
|
179
|
+
export const PR_TARGET_BRANCH = 'integration';
|
|
180
|
+
|
|
121
181
|
/**
|
|
122
182
|
* Which repository a call addresses: the explicit per-call argument first (one
|
|
123
183
|
* session can span repos), then `AZURE_DEVOPS_REPO` as an override, then the
|
|
@@ -135,10 +195,18 @@ export function resolveProject(cwd?: string): string {
|
|
|
135
195
|
* writing somewhere real.
|
|
136
196
|
*/
|
|
137
197
|
export function resolveRepository(repository?: string, cwd?: string): string {
|
|
138
|
-
|
|
198
|
+
// Order: explicit argument > AZURE_DEVOPS_REPO env > cwd's git remote > testDefaults > throw.
|
|
199
|
+
// The AZURE_DEVOPS_REPO env leg is a test affordance: many existing tests in
|
|
200
|
+
// this package set the env var to drive the resolver without standing up a
|
|
201
|
+
// fixture. The production contract is the same as the rest — the git remote
|
|
202
|
+
// is the source of truth — but the env leg stays because removing it would
|
|
203
|
+
// cascade into ~14 test files. The test preload's testDefaults is the
|
|
204
|
+
// long-term replacement; the env leg can be retired when those tests are
|
|
205
|
+
// migrated to fixture-driven cwd arguments.
|
|
206
|
+
const resolved = configured(repository) ?? configured(process.env.AZURE_DEVOPS_REPO) ?? currentRemote(cwd)?.repository ?? testDefaults?.repository;
|
|
139
207
|
if (resolved === undefined) {
|
|
140
208
|
throw new Error(
|
|
141
|
-
'Cannot determine the Azure DevOps repository: no `repository` argument,
|
|
209
|
+
'Cannot determine the Azure DevOps repository: no `repository` argument, ' +
|
|
142
210
|
'and `git remote get-url origin` in this working directory is not an Azure DevOps remote. ' +
|
|
143
211
|
'Pass `repository` explicitly or run from a checkout of the target repo.',
|
|
144
212
|
);
|
|
@@ -151,9 +219,13 @@ export function resolveRepository(repository?: string, cwd?: string): string {
|
|
|
151
219
|
* segments are written. The REST base appends `/_apis`; human-facing links
|
|
152
220
|
* append `/_git/...`. Two builders restating this shape can disagree about
|
|
153
221
|
* where a project lives just as easily as two default constants could.
|
|
222
|
+
*
|
|
223
|
+
* `cwd` is the test seam: pass the path of a fixture whose `origin` is the
|
|
224
|
+
* URL under test. Production callers omit it and resolve against this
|
|
225
|
+
* process's own working directory.
|
|
154
226
|
*/
|
|
155
|
-
export function adoProjectUrl(): string {
|
|
156
|
-
return `https://dev.azure.com/${resolveOrg()}/${resolveProject()}`;
|
|
227
|
+
export function adoProjectUrl(cwd?: string): string {
|
|
228
|
+
return `https://dev.azure.com/${resolveOrg(cwd)}/${resolveProject(cwd)}`;
|
|
157
229
|
}
|
|
158
230
|
|
|
159
231
|
export class AdoClient {
|
|
@@ -205,7 +277,13 @@ export class AdoClient {
|
|
|
205
277
|
redirect: 'error',
|
|
206
278
|
method,
|
|
207
279
|
headers,
|
|
208
|
-
|
|
280
|
+
// JSON bodies are stringified; an octet-stream upload (T2
|
|
281
|
+
// attachments) is sent exactly as supplied.
|
|
282
|
+
body: options.body === undefined
|
|
283
|
+
? undefined
|
|
284
|
+
: contentType === 'application/octet-stream'
|
|
285
|
+
? (options.body as string | Uint8Array)
|
|
286
|
+
: JSON.stringify(options.body),
|
|
209
287
|
});
|
|
210
288
|
|
|
211
289
|
if (!resp.ok) {
|
|
@@ -2,10 +2,13 @@ import { BRANCH_PREFIXES } from './commit-types.ts'
|
|
|
2
2
|
|
|
3
3
|
// A PR title never carries the pipeline-reserved `release`, so its types are the branch prefixes.
|
|
4
4
|
const TITLE_PATTERN = new RegExp(`^(${BRANCH_PREFIXES.join('|')})(\\([a-z0-9][a-z0-9-]*\\))?: .+$`)
|
|
5
|
-
|
|
5
|
+
// P3 (azdo-git-process.md § PR body): every PR carries the same five sections; a planning PR may write the exact text "none (docs-only)" in the last two.
|
|
6
|
+
const REQUIRED_SECTIONS = ['Summary', 'Why', 'Changes', 'Test plan', 'Security impact considered']
|
|
7
|
+
const DOCS_ONLY_SECTIONS = new Set(['Test plan', 'Security impact considered'])
|
|
8
|
+
export const DOCS_ONLY = 'none (docs-only)'
|
|
6
9
|
|
|
7
|
-
export function validatePullRequestMetadata(title: string, description: string): string[] {
|
|
8
|
-
return [...validatePullRequestTitle(title), ...validatePullRequestDescription(description)]
|
|
10
|
+
export function validatePullRequestMetadata(title: string, description: string, docsOnlySections = false): string[] {
|
|
11
|
+
return [...validatePullRequestTitle(title), ...validatePullRequestDescription(description, { docsOnlySections })]
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
export function validatePullRequestTitle(title: string): string[] {
|
|
@@ -20,11 +23,17 @@ export function validatePullRequestTitle(title: string): string[] {
|
|
|
20
23
|
return errors
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
export function validatePullRequestDescription(description: string): string[] {
|
|
26
|
+
export function validatePullRequestDescription(description: string, options: { docsOnlySections?: boolean } = {}): string[] {
|
|
24
27
|
const errors: string[] = []
|
|
25
28
|
for (const section of REQUIRED_SECTIONS) {
|
|
26
29
|
const match = description.match(new RegExp(`(?:^|\\n)## ${section}[ \\t]*\\n([\\s\\S]*?)(?=\\n## |$)`, 'i'))
|
|
27
|
-
|
|
30
|
+
const text = match?.[1]?.trim()
|
|
31
|
+
if (!text) {
|
|
32
|
+
errors.push(`description requires a non-empty ## ${section} section`)
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
// P3: "none (docs-only)" is special only in the last two sections of a planning PR; anywhere else it is ordinary body text.
|
|
36
|
+
if (options.docsOnlySections && DOCS_ONLY_SECTIONS.has(section) && text === DOCS_ONLY) continue
|
|
28
37
|
}
|
|
29
38
|
return errors
|
|
30
39
|
}
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
import pkg from '../package.json' with { type: 'json' };
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* Builds a fresh, unconnected `Server` with the
|
|
32
|
+
* Builds a fresh, unconnected `Server` with the 14 public tools registered.
|
|
33
33
|
* Called by `runMcpServer()` below; also usable directly by tests that want
|
|
34
34
|
* to drive the server without stdio (e.g. via an in-memory transport).
|
|
35
35
|
*/
|
|
@@ -62,17 +62,20 @@ export function createServer(): Server {
|
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
name: 'pr_create_or_update',
|
|
65
|
-
description: 'Create a pull request from the current branch into integration, or update a pull request.',
|
|
65
|
+
description: 'Create a pull request from the current branch into integration, or update a pull request. The create path derives the PR kind from the source branch and the board (planning / implementation / ordinary), links the wireable work items, moves them at raise, attaches the kind\'s mandatory Feature attachment (attachmentContent) and arms auto-complete with the matching transitionWorkItems. The update path also accepts addWorkItems / removeWorkItems (update only, P5) — the only way to attach work items to a PR raised as kind: ordinary after the create call. The body must contain non-empty ## Summary, ## Why, ## Changes, ## Test plan and ## Security impact considered sections (a planning PR may write "none (docs-only)" in the last two).',
|
|
66
66
|
inputSchema: {
|
|
67
67
|
type: 'object',
|
|
68
68
|
properties: {
|
|
69
69
|
title: { type: 'string', description: 'Conventional lowercase title: <type>(<scope>): <subject>' },
|
|
70
|
-
description: { type: 'string', description: 'Must contain non-empty ## Summary, ## Why, and ##
|
|
70
|
+
description: { type: 'string', description: 'Must contain non-empty ## Summary, ## Why, ## Changes, ## Test plan and ## Security impact considered sections' },
|
|
71
71
|
action: { type: 'string', enum: ['create', 'update'] },
|
|
72
72
|
pullRequestId: { type: 'number' },
|
|
73
73
|
autoComplete: { type: 'boolean' },
|
|
74
74
|
mergeStrategy: { type: 'string', enum: ['Squash'] },
|
|
75
75
|
deleteSourceBranch: { type: 'boolean' },
|
|
76
|
+
attachmentContent: { type: 'string', description: 'Create only: the content of the kind\'s mandatory Feature attachment (plan-r<N>-<sha7>.md or impl-report-pr<id>.md); refused without it on planning/implementation PRs' },
|
|
77
|
+
addWorkItems: { type: 'array', items: { type: 'number' }, description: 'P5 update only: positive integer ids to link to the PR. For each id, JSON-PATCH `add /relations/-` against `/_apis/wit/workitems/{id}?api-version=7.1` with `application/json-patch+json` and an `ArtifactLink` of rel `Pull Request` pointing at `vstfs:///Git/PullRequestId/{projectId}%2F{repoId}%2F{prId}`. The relation is read back through `GET .../pullRequests/{prId}/workItems`. An id already linked is skipped (idempotent). An id in both addWorkItems and removeWorkItems is rejected (no PATCH issued).' },
|
|
78
|
+
removeWorkItems: { type: 'array', items: { type: 'number' }, description: 'P5 update only: positive integer ids to unlink from the PR. JSON-PATCH `remove /relations/{index}` against the work item, where {index} is the position of the matching `ArtifactLink` (matched by url). An id in both addWorkItems and removeWorkItems is rejected (no PATCH issued).' },
|
|
76
79
|
repository: { type: 'string', description: 'Repository name; defaults to AZURE_DEVOPS_REPO' },
|
|
77
80
|
},
|
|
78
81
|
required: ['action'],
|
|
@@ -124,7 +127,7 @@ export function createServer(): Server {
|
|
|
124
127
|
},
|
|
125
128
|
{
|
|
126
129
|
name: 'workitem_list_or_get',
|
|
127
|
-
description: 'Get one or many tracked work items, or query the scoped backlog. Each item carries effort
|
|
130
|
+
description: 'Get one or many tracked work items, or query the scoped backlog. Each item carries effort, priority, acceptanceCriteria, failureReason and the Feature plan fields planRevision, planHash and baselineSha (all null when unset).',
|
|
128
131
|
inputSchema: {
|
|
129
132
|
type: 'object',
|
|
130
133
|
properties: {
|
|
@@ -133,15 +136,125 @@ export function createServer(): Server {
|
|
|
133
136
|
},
|
|
134
137
|
},
|
|
135
138
|
{
|
|
136
|
-
name: '
|
|
137
|
-
description:
|
|
139
|
+
name: 'workitem_create_or_update_feature',
|
|
140
|
+
description: "Create a Feature under an Epic, or update an existing Feature. Mandatory: title, parentId (an Epic), priority (1=Very High, 2=High, 3=Medium, 4=Low) and a description carrying the intent.md sections Why / Outcome / Constraints / Non-goals — on create and while the Feature is at New; acceptanceCriteria (itemised per requirements.md) plus the three plan fields on the New → In Progress move; a comment on every update. Features are created only at New.",
|
|
138
141
|
inputSchema: {
|
|
139
142
|
type: 'object',
|
|
140
143
|
properties: {
|
|
141
|
-
id: { type: 'number' },
|
|
144
|
+
id: { type: 'number' },
|
|
145
|
+
title: { type: 'string' },
|
|
146
|
+
description: { type: 'string', description: 'Must carry the intent.md sections ## Why, ## Outcome, ## Constraints, ## Non-goals' },
|
|
147
|
+
parentId: { type: 'number', description: 'The Epic this Feature hangs under' },
|
|
148
|
+
predecessors: { type: 'array', items: { type: 'number' } },
|
|
149
|
+
related: { type: 'array', items: { type: 'number' } },
|
|
150
|
+
removePredecessor: { type: 'number', description: 'az698: drop a single predecessor link by id; idempotent on a missing link. Update path only.' },
|
|
151
|
+
removeRelated: { type: 'number', description: 'az698: drop a single related link by id; idempotent on a missing link. Update path only.' },
|
|
152
|
+
fields: { type: 'object' },
|
|
153
|
+
state: { type: 'string' },
|
|
154
|
+
comment: { type: 'string', description: 'Mandatory on every update' },
|
|
155
|
+
assignedTo: { type: 'string' },
|
|
156
|
+
acceptanceCriteria: { type: 'string', description: 'Required on the New → In Progress move, itemised per requirements.md' },
|
|
157
|
+
priority: { type: 'number', enum: [1, 2, 3, 4], description: '1=Very High, 2=High, 3=Medium, 4=Low (Microsoft.VSTS.Common.Priority)' },
|
|
158
|
+
startDate: { type: 'string' },
|
|
159
|
+
targetDate: { type: 'string' },
|
|
160
|
+
planRevision: { type: 'number', description: 'Required on the New → In Progress move: which plan revision G1 approves (Custom.PlanRevision)' },
|
|
161
|
+
planHash: { type: 'string', description: 'Required on the New → In Progress move: sha256 of requirements.md (Custom.PlanHash)' },
|
|
162
|
+
baselineSha: { type: 'string', description: 'Required on the New → In Progress move: the integration commit the plan was written against (Custom.BaselineSha)' },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'workitem_create_or_update_pbi',
|
|
168
|
+
description: "Create a PBI (Product Backlog Item) under a Feature, or update an existing PBI. Mandatory on create: title, parentId (a Feature), a description carrying the item file's What it delivers / Verification sections, and effort in days. A comment is mandatory on every update. Predecessor links are refused as a staged warning (L3); the Feature plan fields do not exist on a PBI.",
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
id: { type: 'number' },
|
|
142
173
|
title: { type: 'string' },
|
|
143
|
-
description: { type: 'string'
|
|
174
|
+
description: { type: 'string', description: "Must carry the item file's sections ## What it delivers and ## Verification" },
|
|
175
|
+
parentId: { type: 'number', description: 'The Feature this PBI hangs under' },
|
|
176
|
+
related: { type: 'array', items: { type: 'number' } },
|
|
177
|
+
removeRelated: { type: 'number', description: 'az698: drop a single related link by id; idempotent on a missing link. Update path only.' },
|
|
178
|
+
fields: { type: 'object' },
|
|
179
|
+
state: { type: 'string' },
|
|
180
|
+
comment: { type: 'string', description: 'Mandatory on every update' },
|
|
181
|
+
assignedTo: { type: 'string' },
|
|
182
|
+
acceptanceCriteria: { type: 'string' },
|
|
183
|
+
priority: { type: 'number', enum: [1, 2, 3, 4], description: '1=Very High, 2=High, 3=Medium, 4=Low' },
|
|
184
|
+
effort: { type: 'number', description: 'Mandatory on create: engineering days, >= 0, fractions accepted (Microsoft.VSTS.Scheduling.Effort)' },
|
|
185
|
+
startDate: { type: 'string' },
|
|
186
|
+
targetDate: { type: 'string' },
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'workitem_create_or_update_bug',
|
|
192
|
+
description: "Create a Bug under a Feature, or update an existing Bug. Mandatory on create: title, parentId (a Feature — usually a 'Fixes to closed Features' container), a description carrying the bug item file's Current behaviour / Expected behaviour / Behaviour that must not change / Responsible Feature / Verification sections, and effort in days. A Bug under the Fixes Feature also needs a related link to its Responsible Feature and a predecessor that is a sibling Bug (L4). A comment is mandatory on every update.",
|
|
193
|
+
inputSchema: {
|
|
194
|
+
type: 'object',
|
|
195
|
+
properties: {
|
|
196
|
+
id: { type: 'number' },
|
|
197
|
+
title: { type: 'string' },
|
|
198
|
+
description: { type: 'string', description: "Must carry the bug item file's sections ## Current behaviour, ## Expected behaviour, ## Behaviour that must not change, ## Responsible Feature, ## Verification" },
|
|
199
|
+
parentId: { type: 'number', description: 'The Feature this Bug hangs under' },
|
|
200
|
+
predecessors: { type: 'array', items: { type: 'number' }, description: 'At most one, and only a sibling Bug under a Fixes Feature (L4)' },
|
|
201
|
+
related: { type: 'array', items: { type: 'number' }, description: 'Required under a Fixes Feature: the Responsible Feature (L4)' },
|
|
202
|
+
removePredecessor: { type: 'number', description: 'az698: drop a single predecessor link by id; idempotent on a missing link. Update path only.' },
|
|
203
|
+
removeRelated: { type: 'number', description: 'az698: drop a single related link by id; idempotent on a missing link. Update path only.' },
|
|
204
|
+
fields: { type: 'object' },
|
|
205
|
+
state: { type: 'string' },
|
|
206
|
+
comment: { type: 'string', description: 'Mandatory on every update' },
|
|
207
|
+
assignedTo: { type: 'string' },
|
|
208
|
+
acceptanceCriteria: { type: 'string' },
|
|
209
|
+
priority: { type: 'number', enum: [1, 2, 3, 4], description: '1=Very High, 2=High, 3=Medium, 4=Low' },
|
|
210
|
+
effort: { type: 'number', description: 'Mandatory on create: engineering days, >= 0, fractions accepted (Microsoft.VSTS.Scheduling.Effort)' },
|
|
211
|
+
startDate: { type: 'string' },
|
|
212
|
+
targetDate: { type: 'string' },
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: 'workitem_comments_read',
|
|
218
|
+
description: "Read a work item's comments (Work Item Tracking Comments – List). This is the read path for the board's evidence: --raw on workitem_list_or_get shows only the latest System.History value.",
|
|
219
|
+
inputSchema: {
|
|
220
|
+
type: 'object',
|
|
221
|
+
properties: {
|
|
222
|
+
id: { type: 'number', description: 'The work item id whose comments are read' },
|
|
223
|
+
},
|
|
224
|
+
required: ['id'],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: 'workitem_attachments',
|
|
229
|
+
description: 'Read, upload or delete a work item\'s attachments (Feature attachments only, per board-rules.md § Attachments). Upload POSTs an octet-stream to the attachments endpoint and PATCHes an AttachedFile relation with a test/rev guard. Delete removes only the AttachedFile relation (the stored file stays; Attachments-Delete is 7.2-preview only) and refuses a plan-r* file once any item of the Feature has left Awaiting Approval.',
|
|
230
|
+
inputSchema: {
|
|
231
|
+
type: 'object',
|
|
232
|
+
properties: {
|
|
233
|
+
id: { type: 'number', description: 'The work item id (the Feature carrying the attachments)' },
|
|
234
|
+
action: { type: 'string', enum: ['read', 'upload', 'delete'] },
|
|
235
|
+
fileName: { type: 'string', description: 'upload/delete: the attachment file name' },
|
|
236
|
+
content: { type: 'string', description: 'upload: the file content, sent as an octet-stream body' },
|
|
144
237
|
},
|
|
238
|
+
required: ['id', 'action'],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: 'activity_add',
|
|
243
|
+
description: 'Append one entry to this repository\'s local agent activity log (.adl/agent-activity.sqlite, gitignored; A1, replaces docs/notes.md). Only the note is supplied — the server fills time (UTC ISO-8601), surface, agent identity and repository. Requires a resolvable agent identity, like every other tool.',
|
|
244
|
+
inputSchema: {
|
|
245
|
+
type: 'object',
|
|
246
|
+
properties: {
|
|
247
|
+
note: { type: 'string', description: 'The note text; non-empty' },
|
|
248
|
+
},
|
|
249
|
+
required: ['note'],
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: 'activity_list',
|
|
254
|
+
description: 'Read this repository\'s local agent activity log (.adl/agent-activity.sqlite): every entry, oldest first, each with time (UTC ISO-8601), surface, agent identity, repository and note.',
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: 'object',
|
|
257
|
+
properties: {},
|
|
145
258
|
},
|
|
146
259
|
},
|
|
147
260
|
],
|