agentme 0.35.2 → 0.37.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/.filedist-package.yml +1 -1
- package/.xdrs/agentme/bdrs/index.md +2 -1
- package/.xdrs/agentme/bdrs/operations/{401-epic-feature-story-planning.md → 401-plan-epic-feature-story.md} +2 -2
- package/.xdrs/agentme/bdrs/operations/402-digital-product-roles.md +15 -19
- package/.xdrs/agentme/bdrs/operations/403-product-team-composition.md +3 -0
- package/.xdrs/agentme/bdrs/operations/404-team-roles-and-specialists.md +61 -82
- package/.xdrs/agentme/bdrs/operations/405-digital-product-roles-raci.md +131 -0
- package/.xdrs/agentme/bdrs/principles/002-okr-framework.md +1 -1
- package/.xdrs/agentme/bdrs/principles/003-product-delivery-value-flow.md +3 -2
- package/.xdrs/agentme/edrs/application/101-javascript-project-tooling.md +1 -1
- package/.xdrs/agentme/edrs/application/102-golang-project-tooling.md +1 -1
- package/.xdrs/agentme/edrs/application/103-python-project-tooling.md +1 -1
- package/.xdrs/agentme/edrs/application/127-external-system-adapter-skills.md +2 -0
- package/.xdrs/agentme/edrs/application/skills/azure-devops-connector/SKILL.md +202 -0
- package/.xdrs/agentme/edrs/application/skills/azure-devops-connector/SKILL.test.md +114 -0
- package/.xdrs/agentme/edrs/application/skills/{051-create-golang-project → create-golang-project}/SKILL.md +1 -1
- package/.xdrs/agentme/edrs/application/skills/create-golang-project/SKILL.test.md +72 -0
- package/.xdrs/agentme/edrs/application/skills/{050-create-javascript-project → create-javascript-project}/SKILL.md +23 -24
- package/.xdrs/agentme/edrs/application/skills/create-javascript-project/SKILL.test.md +72 -0
- package/.xdrs/agentme/edrs/application/skills/{052-create-python-project → create-python-project}/SKILL.md +1 -1
- package/.xdrs/agentme/edrs/application/skills/create-python-project/SKILL.test.md +79 -0
- package/.xdrs/agentme/edrs/application/skills/github-connector/SKILL.md +184 -0
- package/.xdrs/agentme/edrs/application/skills/github-connector/SKILL.test.md +118 -0
- package/.xdrs/agentme/edrs/application/skills/{200-run-skill-tests → run-skill-tests}/SKILL.md +4 -4
- package/.xdrs/agentme/edrs/application/skills/{200-run-skill-tests → run-skill-tests}/SKILL.test.md +7 -7
- package/.xdrs/agentme/edrs/application/skills/{010-select-relevant-xdrs → select-relevant-xdrs}/SKILL.md +1 -1
- package/.xdrs/agentme/edrs/application/skills/select-relevant-xdrs/SKILL.test.md +73 -0
- package/.xdrs/agentme/edrs/governance/502-contributing-guide-requirements.md +1 -1
- package/.xdrs/agentme/edrs/index.md +16 -8
- package/.xdrs/agentme/edrs/operations/402-dora-metrics-framework.md +82 -0
- package/.xdrs/agentme/edrs/operations/403-dora-deployment-frequency.md +37 -0
- package/.xdrs/agentme/edrs/operations/404-dora-lead-time-for-changes.md +41 -0
- package/.xdrs/agentme/edrs/operations/405-dora-change-failure-rate.md +42 -0
- package/.xdrs/agentme/edrs/operations/406-dora-time-to-restore-service.md +42 -0
- package/.xdrs/agentme/edrs/platform/301-monorepo-structure.md +1 -1
- package/.xdrs/agentme/edrs/platform/skills/{053-monorepo-setup → monorepo-setup}/SKILL.md +15 -15
- package/.xdrs/agentme/edrs/platform/skills/monorepo-setup/SKILL.test.md +80 -0
- package/.xdrs/agentme/edrs/principles/012-continuous-xdr-enrichment.md +1 -1
- package/.xdrs/agentme/edrs/principles/017-skill-testing.md +7 -4
- package/.xdrs/agentme/edrs/principles/articles/001-continuous-xdr-improvement.md +1 -1
- package/.xdrs/agentme/edrs/principles/skills/{150-refine-plan-mode → refine-plan-mode}/SKILL.md +27 -16
- package/.xdrs/agentme/edrs/principles/skills/{150-refine-plan-mode → refine-plan-mode}/SKILL.test.md +28 -4
- package/.xdrs/agentme/edrs/principles/skills/{151-refine-user-story → refine-user-story}/SKILL.md +4 -11
- package/.xdrs/agentme/edrs/principles/skills/{151-refine-user-story → refine-user-story}/SKILL.test.md +17 -17
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/Makefile +8 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/SKILL.md +662 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/SKILL.test.md +165 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/scripts/post-replies-azure-devops.js +219 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/scripts/post-replies-azure-devops.test.js +253 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/scripts/post-replies-github.js +237 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/scripts/post-replies-github.test.js +272 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/scripts/update-section.js +327 -0
- package/.xdrs/agentme/edrs/principles/skills/resolve-pr-comments/scripts/update-section.test.js +306 -0
- package/package.json +2 -2
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: azure-devops-connector
|
|
3
|
+
description: >
|
|
4
|
+
Base connector providing authentication, read access, and write access to Azure DevOps
|
|
5
|
+
pull requests and their comment threads via the az CLI. Pure I/O -- no triage logic, no
|
|
6
|
+
business decisions. Activate when an agent or skill (such as resolve-pr-comments) needs to
|
|
7
|
+
fetch or post PR thread comments, change thread status, or check out a PR branch on Azure
|
|
8
|
+
DevOps.
|
|
9
|
+
metadata:
|
|
10
|
+
author: flaviostutz
|
|
11
|
+
version: "1.1"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
Reusable authentication and connection skill for Azure DevOps pull requests, per
|
|
17
|
+
[agentme-edr-127](../../127-external-system-adapter-skills.md) rule 06 (connector naming).
|
|
18
|
+
Wraps the `az` CLI (with the `azure-devops` extension) -- Azure DevOps's own supported API
|
|
19
|
+
client -- plus `az rest` for the handful of operations the extension does not expose as a
|
|
20
|
+
dedicated subcommand. Contains no business logic (per rule 05): it only reads and writes
|
|
21
|
+
data and normalizes it to the shape consumed by
|
|
22
|
+
[`resolve-pr-comments`](../../../principles/skills/resolve-pr-comments/SKILL.md).
|
|
23
|
+
|
|
24
|
+
## Instructions
|
|
25
|
+
|
|
26
|
+
### Authentication check
|
|
27
|
+
|
|
28
|
+
1. Verify the `az` CLI is installed (`az --version`); if missing, ask the human whether to
|
|
29
|
+
install it now via the appropriate package manager for their OS (e.g. `brew install
|
|
30
|
+
azure-cli` on macOS). Only run the install command after explicit confirmation; if the
|
|
31
|
+
human declines or the install fails, report the install requirement and stop.
|
|
32
|
+
2. Verify the `azure-devops` extension is present; if missing, install it with
|
|
33
|
+
`az extension add --name azure-devops` (auto-installs on first use in most `az` versions,
|
|
34
|
+
but check explicitly rather than assuming).
|
|
35
|
+
3. Run `az account show`. If authenticated, proceed -- prefer `az login`'s own session over
|
|
36
|
+
handling a token directly.
|
|
37
|
+
4. If not authenticated, check the OS keychain for a stored Azure DevOps PAT per
|
|
38
|
+
[agentme-edr-124](../../124-secrets-management.md) rather than any `.env` file, hardcoded
|
|
39
|
+
value, or shell profile export. If found, export it only transiently as
|
|
40
|
+
`AZURE_DEVOPS_EXT_PAT` for the current command invocation -- never persist it to disk.
|
|
41
|
+
5. If no session and no stored PAT exist, prompt the human to run `az login` interactively
|
|
42
|
+
or to store a PAT in the keychain first, per agentme-edr-124's `setup-secrets` pattern.
|
|
43
|
+
Do not proceed with a write operation without one of these. Unlike `gh auth login`, bare
|
|
44
|
+
`az login` already opens the browser directly with no preceding host/protocol/method
|
|
45
|
+
questions, so no extra flags are needed here to keep it non-interactive.
|
|
46
|
+
6. Set the default organization/project once per session
|
|
47
|
+
(`az devops configure --defaults organization=<url> project=<project>`) to shorten
|
|
48
|
+
subsequent commands.
|
|
49
|
+
7. Never substitute `az`/`az rest` with a direct HTTP call (`curl`, `fetch`, or any other
|
|
50
|
+
HTTP client) against the Azure DevOps REST API, and never scrape the PR's web UI as a
|
|
51
|
+
workaround -- this applies to reads as much as writes, and applies even when the target
|
|
52
|
+
data looks read-only. If `az`, the `azure-devops` extension, or a valid session/PAT is
|
|
53
|
+
missing, stop and resolve that first (steps 1-5 above); do not degrade to an alternative
|
|
54
|
+
retrieval method to route around it.
|
|
55
|
+
|
|
56
|
+
### Reading data
|
|
57
|
+
|
|
58
|
+
All read commands are exempt from HITL confirmation (per agentme-edr-127 rule 04, read-only
|
|
59
|
+
operations need no confirmation -- but they are not exempt from the CLI-only channel).
|
|
60
|
+
Every read below MUST go through `az`/`az rest`; never construct the equivalent REST call
|
|
61
|
+
with `curl`/another HTTP client, and never fetch or scrape the PR's web UI as a substitute.
|
|
62
|
+
|
|
63
|
+
- PR metadata: `az repos pr show --id <n> --output json`
|
|
64
|
+
- All comment threads (Azure DevOps has no separate "list comments" call -- threads are the
|
|
65
|
+
unit of data and already include every comment and their status):
|
|
66
|
+
`az rest --method GET --uri "https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/pullRequests/{n}/threads?api-version=7.1"`
|
|
67
|
+
There is no dedicated `az repos pr` subcommand for threads -- `az rest` is required for both
|
|
68
|
+
reads and writes; verify this generic-URI capability with `az rest --help` and a smoke-test
|
|
69
|
+
GET before first use in a new environment.
|
|
70
|
+
|
|
71
|
+
Normalize every thread's comments to the shared record shape (`id`, `kind`, `status`,
|
|
72
|
+
`can_reply`, `can_resolve`, `path`, `line`, `content`, `author`, `in_reply_to`, `diff_hunk`,
|
|
73
|
+
`url`):
|
|
74
|
+
- `id` is `"thread-comment/<threadId>.<commentId>"` -- Azure DevOps ids are scoped per PR, not
|
|
75
|
+
global, so always keep the PR number alongside when persisting.
|
|
76
|
+
- `kind` is always `"thread-comment"` -- Azure DevOps has no separate review-summary concept;
|
|
77
|
+
never emit a `"review-summary"` kind for this provider.
|
|
78
|
+
- `status` maps from the thread's `status` field: `"active"` -> `"open"`, `"fixed"` /
|
|
79
|
+
`"closed"` -> `"resolved"`, `"wontFix"` -> `"wontfix"`, `"pending"` -> `"open"`.
|
|
80
|
+
- `path`/`line` come from `threadContext.filePath` and the relevant line range; when
|
|
81
|
+
`threadContext` is `null`, this is a general (PR-level, not file-scoped) comment -- classify
|
|
82
|
+
it as a general comment, not a parsing error.
|
|
83
|
+
- `can_reply` and `can_resolve` are `true` for any non-deleted comment in a non-deleted
|
|
84
|
+
thread; Azure DevOps does not have GitHub's permission-driven resolve restriction in the
|
|
85
|
+
same way, but a 403 on write still means `can_resolve` should be treated as `false` for
|
|
86
|
+
that session (see Known Issues).
|
|
87
|
+
- `in_reply_to` is the thread's first comment id whenever the target is a reply within the
|
|
88
|
+
same thread -- Azure DevOps threads are flat, so there is no root-vs-reply distinction to
|
|
89
|
+
resolve.
|
|
90
|
+
- `diff_hunk` has no native equivalent in the Azure DevOps API -- `threadContext` exposes
|
|
91
|
+
only a file path and line range, not a unified-diff-style hunk string. Leave `diff_hunk`
|
|
92
|
+
null rather than fabricating one; `resolve-pr-comments` degrades to relying on
|
|
93
|
+
`source-lines` alone in that case, exactly as it does for a general (non-file-scoped)
|
|
94
|
+
comment.
|
|
95
|
+
- `url` has no direct field in the thread-comment response either. Synthesize a best-effort
|
|
96
|
+
permalink from the PR's own web URL plus a `?discussionId=<threadId>` anchor (Azure
|
|
97
|
+
DevOps' web UI convention for deep-linking to a thread); fall back to the PR's own URL
|
|
98
|
+
with no anchor when this convention cannot be confirmed reliable for the target
|
|
99
|
+
organization, rather than risking a broken or misleading link (see Known Issues).
|
|
100
|
+
|
|
101
|
+
### Writing data
|
|
102
|
+
|
|
103
|
+
Before any write below, show the mandatory confirmation (per agentme-edr-127 rule 04):
|
|
104
|
+
**System** (org/project/repo + PR number), **Operation**, **Fields** (exact verbatim text to
|
|
105
|
+
post), **Estimated impact** (visible to PR participants, triggers notifications). Wait for
|
|
106
|
+
explicit confirmation; never proceed on an assumed "yes."
|
|
107
|
+
|
|
108
|
+
- Reply within an existing thread:
|
|
109
|
+
`az rest --method POST --uri ".../pullRequests/{n}/threads/{threadId}/comments?api-version=7.1" --body '{"content": "...", "parentCommentId": <id>}'`
|
|
110
|
+
- Post a new general (non-file-scoped) comment as a new thread:
|
|
111
|
+
`az rest --method POST --uri ".../pullRequests/{n}/threads?api-version=7.1" --body '{"comments": [{"content": "..."}]}'`
|
|
112
|
+
- Change thread status (the resolve/won't-fix equivalent):
|
|
113
|
+
`az rest --method PATCH --uri ".../pullRequests/{n}/threads/{threadId}?api-version=7.1" --body '{"status": "fixed"}'` (use `"wontFix"` or `"closed"` as appropriate instead of `"fixed"`).
|
|
114
|
+
- Check out the PR branch: `az repos pr checkout --id <n>`.
|
|
115
|
+
|
|
116
|
+
### Constraints
|
|
117
|
+
|
|
118
|
+
- MUST use `az`/`az rest` for every read and write handled by this connector -- never fall
|
|
119
|
+
back to `curl`, another raw HTTP client, or scraping the PR's web UI, even when `az` is
|
|
120
|
+
missing, unauthenticated, or erroring, and even when the target data looks read-only.
|
|
121
|
+
- MUST stop and follow the Authentication check steps above when `az` cannot complete a
|
|
122
|
+
request, instead of silently degrading to an alternative retrieval method.
|
|
123
|
+
|
|
124
|
+
## Examples
|
|
125
|
+
|
|
126
|
+
**Input**: fetch all comments for
|
|
127
|
+
`https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029`
|
|
128
|
+
|
|
129
|
+
Runs `az repos pr show --id 1029` for metadata, then the single threads `az rest GET` call
|
|
130
|
+
above, and returns a single normalized list built from every thread's comments.
|
|
131
|
+
|
|
132
|
+
**Input**: reply to thread comment id `thread-comment/12.1` and set the thread to fixed
|
|
133
|
+
|
|
134
|
+
Shows the mandatory confirmation summary first. On explicit "yes," posts the reply via the
|
|
135
|
+
threads/comments `POST`, then updates thread status via the `PATCH` call.
|
|
136
|
+
|
|
137
|
+
## Edge Cases
|
|
138
|
+
|
|
139
|
+
- **Modern vs legacy URL formats**: recognize both
|
|
140
|
+
`dev.azure.com/{org}/{project}/_git/{repo}/pullrequest/{id}` and
|
|
141
|
+
`{org}.visualstudio.com/{project}/_git/{repo}/pullrequest/{id}` as valid Azure DevOps PR
|
|
142
|
+
URLs; extract org/project/repo/id from either shape.
|
|
143
|
+
- **`threadContext` is `null`**: classify as a general PR-level comment, never as a parse
|
|
144
|
+
failure.
|
|
145
|
+
- **PR-scoped ids**: never assume a thread or comment id is unique outside its PR; always
|
|
146
|
+
carry the PR number alongside when the tracking file persists an id.
|
|
147
|
+
|
|
148
|
+
## Known Issues
|
|
149
|
+
|
|
150
|
+
- **Symptom:** the `azure-devops` extension has no `az repos pr comment` or `az repos pr
|
|
151
|
+
thread` subcommand at all.
|
|
152
|
+
**Cause:** the extension only covers a subset of the Git PR API; thread and comment
|
|
153
|
+
operations were never added as first-class subcommands.
|
|
154
|
+
**Fix:** always use `az rest` with the documented REST endpoints above for every thread
|
|
155
|
+
and comment read or write; do not search for a nonexistent dedicated subcommand.
|
|
156
|
+
- **Symptom:** a thread that should be resolvable cannot be updated; the `PATCH` call returns
|
|
157
|
+
HTTP 403 despite `az account show` showing a valid, logged-in session.
|
|
158
|
+
**Cause:** the authenticated identity lacks the "Contribute to pull requests" permission
|
|
159
|
+
on the repository.
|
|
160
|
+
**Fix:** degrade to reply-only for that thread, report the permission gap plainly, and
|
|
161
|
+
never retry the same call silently.
|
|
162
|
+
- **Symptom:** `az rest` against a `dev.azure.com/.../_apis/...` URL fails most calls with
|
|
163
|
+
`TF400813: The user 'aaaaaaaa-aaaa-...' is not authorized`, or -- observed once, isolated
|
|
164
|
+
to a single call in an otherwise-failing batch -- exits 0 (looks successful) while the
|
|
165
|
+
write never actually appears when the thread is re-read.
|
|
166
|
+
**Cause:** `az rest` cannot always derive the correct Azure AD resource from the URL
|
|
167
|
+
alone and can silently fall back to an anonymous/placeholder identity; this has been
|
|
168
|
+
observed to be intermittent within a batch of otherwise-identical calls.
|
|
169
|
+
**Fix:** always pass `--resource 499b84ac-1321-427f-aa17-267ca6975798` (Azure DevOps'
|
|
170
|
+
well-known, tenant-agnostic AAD resource id) explicitly on every `az rest` call. Even
|
|
171
|
+
then, never treat a zero exit code alone as proof a write persisted -- read the thread
|
|
172
|
+
back afterward and verify the expected content/status is actually present before
|
|
173
|
+
reporting success. `resolve-pr-comments`'s `scripts/post-replies-azure-devops.js` does
|
|
174
|
+
this automatically for every write.
|
|
175
|
+
- **Symptom:** a fetched thread has no obvious "kind" like GitHub's review-summary.
|
|
176
|
+
**Cause:** Azure DevOps genuinely has no equivalent concept -- every comment lives inside a
|
|
177
|
+
thread.
|
|
178
|
+
**Fix:** never emit a `"review-summary"` kind for this connector; always normalize to
|
|
179
|
+
`"thread-comment"`.
|
|
180
|
+
- **Symptom:** an agent fetched PR metadata or thread comments via `curl`/direct REST calls
|
|
181
|
+
or by scraping the PR's web UI instead of using `az`/`az rest`.
|
|
182
|
+
**Cause:** `az` was missing, unauthenticated, or lacked the `azure-devops` extension, and
|
|
183
|
+
the agent treated a direct unauthenticated REST call or the rendered PR page as an
|
|
184
|
+
acceptable substitute since the target data looked read-only.
|
|
185
|
+
**Fix:** never substitute `az`/`az rest` with a direct HTTP call or a page scrape. Stop at
|
|
186
|
+
the Authentication check step, report the missing or failed `az` session plainly, and wait
|
|
187
|
+
for the human to install, extend, or authenticate `az` before retrying the same read or
|
|
188
|
+
write through `az`.
|
|
189
|
+
- **Symptom:** a synthesized comment permalink (`url`) 404s, or lands on the PR overview
|
|
190
|
+
instead of the specific thread, when opened.
|
|
191
|
+
**Cause:** Azure DevOps' web UI deep-link format for a specific thread
|
|
192
|
+
(`?discussionId=<threadId>`) is a UI convention, not a documented, versioned part of the
|
|
193
|
+
REST API, and can vary by organization or Azure DevOps version.
|
|
194
|
+
**Fix:** verify the `?discussionId=<threadId>` anchor against a live PR in the target
|
|
195
|
+
organization before relying on it; degrade to the PR's own URL with no anchor when
|
|
196
|
+
uncertain, rather than guessing at a format that might mislead the human.
|
|
197
|
+
|
|
198
|
+
## References
|
|
199
|
+
|
|
200
|
+
- [`resolve-pr-comments`](../../../principles/skills/resolve-pr-comments/SKILL.md) -- consumes this connector's normalized output.
|
|
201
|
+
- [`agentme-edr-127`](../../127-external-system-adapter-skills.md) -- external system adapter skill rules (connector naming, Known Issues format, HITL-before-write).
|
|
202
|
+
- [`agentme-edr-124`](../../124-secrets-management.md) -- credential storage and retrieval.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: azure-devops-connector
|
|
3
|
+
skill-version: "1.0"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Test Scenarios
|
|
7
|
+
|
|
8
|
+
### Scenario 1: Fetch and normalize thread comments, happy path
|
|
9
|
+
|
|
10
|
+
**Trigger / Input**
|
|
11
|
+
|
|
12
|
+
Fetch all comments for
|
|
13
|
+
`https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029`, a PR with one
|
|
14
|
+
active file-scoped thread and one active general (PR-level) thread.
|
|
15
|
+
|
|
16
|
+
**Expected Behaviour**
|
|
17
|
+
|
|
18
|
+
The connector: (1) confirms `az account show` is authenticated; (2) runs
|
|
19
|
+
`az repos pr show --id 1029`; (3) runs the single `az rest --method GET` threads call
|
|
20
|
+
(there is no separate "list comments" call); (4) returns a normalized list where the
|
|
21
|
+
file-scoped thread's comment has non-null `path`/`line` and `kind: "thread-comment"`, and
|
|
22
|
+
the general thread's comment has null `path`/`line` and is still classified as a normal
|
|
23
|
+
`"thread-comment"`, both with `status: "open"`.
|
|
24
|
+
|
|
25
|
+
**Assertions**
|
|
26
|
+
|
|
27
|
+
- [ ] Output normalizes every fetched comment to the shared record shape (id, kind, status,
|
|
28
|
+
can_reply, can_resolve, path, line, content, author, in_reply_to).
|
|
29
|
+
- [ ] Output maps the thread `status: "active"` field to the normalized `status: "open"`.
|
|
30
|
+
- [ ] Connector uses `az rest` for the threads read rather than searching for a dedicated
|
|
31
|
+
`az repos pr` comment subcommand.
|
|
32
|
+
|
|
33
|
+
### Scenario 2: Null threadContext classified as a general comment, not an error
|
|
34
|
+
|
|
35
|
+
**Trigger / Input**
|
|
36
|
+
|
|
37
|
+
A fetched thread has `threadContext: null` in the raw API response.
|
|
38
|
+
|
|
39
|
+
**Expected Behaviour**
|
|
40
|
+
|
|
41
|
+
Per the Reading data normalization rule and the matching Edge Cases entry, the connector
|
|
42
|
+
classifies this thread's comment as a general PR-level comment (`path`/`line` set to null in
|
|
43
|
+
the normalized record) rather than treating the missing `threadContext` as a parsing failure
|
|
44
|
+
or skipping the comment.
|
|
45
|
+
|
|
46
|
+
**Assertions**
|
|
47
|
+
|
|
48
|
+
- [ ] Connector includes the comment in its normalized output with `path`/`line` set to null.
|
|
49
|
+
- [ ] Connector does not raise a parse error or silently drop the comment because of the
|
|
50
|
+
null `threadContext`.
|
|
51
|
+
|
|
52
|
+
### Scenario 3: Thread status change writes via az rest PATCH with mandatory confirmation
|
|
53
|
+
|
|
54
|
+
**Trigger / Input**
|
|
55
|
+
|
|
56
|
+
Set thread id 12 on PR 1029 to resolved ("fixed") status after a fix was applied.
|
|
57
|
+
|
|
58
|
+
**Expected Behaviour**
|
|
59
|
+
|
|
60
|
+
The connector shows the mandatory System/Operation/Fields/Estimated impact confirmation
|
|
61
|
+
(naming org/project/repo + PR number and the target status), waits for explicit
|
|
62
|
+
confirmation, then issues
|
|
63
|
+
`az rest --method PATCH --uri ".../pullRequests/1029/threads/12?api-version=7.1" --body '{"status": "fixed"}'`.
|
|
64
|
+
No dedicated `az repos pr` subcommand is used for this operation.
|
|
65
|
+
|
|
66
|
+
**Assertions**
|
|
67
|
+
|
|
68
|
+
- [ ] Connector shows the mandatory confirmation before issuing the PATCH call.
|
|
69
|
+
- [ ] Connector does not issue the PATCH call before explicit human confirmation.
|
|
70
|
+
- [ ] Connector uses `az rest` rather than a nonexistent dedicated thread-status subcommand.
|
|
71
|
+
|
|
72
|
+
### Scenario 4: Legacy visualstudio.com URL parses the same as a modern dev.azure.com URL
|
|
73
|
+
|
|
74
|
+
**Trigger / Input**
|
|
75
|
+
|
|
76
|
+
`https://contoso.visualstudio.com/Widgets/_git/widgets-api/pullrequest/1029` (legacy format)
|
|
77
|
+
versus `https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029` (modern
|
|
78
|
+
format) for the same underlying PR.
|
|
79
|
+
|
|
80
|
+
**Expected Behaviour**
|
|
81
|
+
|
|
82
|
+
The connector extracts the same org (`contoso`), project (`Widgets`), repo
|
|
83
|
+
(`widgets-api`), and PR id (`1029`) from either URL shape and proceeds identically from
|
|
84
|
+
that point on.
|
|
85
|
+
|
|
86
|
+
**Assertions**
|
|
87
|
+
|
|
88
|
+
- [ ] Connector extracts identical org/project/repo/PR-id values from both URL formats.
|
|
89
|
+
- [ ] Connector does not require the human to reformat a legacy URL before use.
|
|
90
|
+
|
|
91
|
+
### Scenario 5: az unavailable or unauthenticated never triggers a curl/scrape fallback
|
|
92
|
+
|
|
93
|
+
**Trigger / Input**
|
|
94
|
+
|
|
95
|
+
Fetch PR metadata and thread comments for
|
|
96
|
+
`https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029` while `az account
|
|
97
|
+
show` reports no session and no PAT is stored in the keychain (or `az`/the `azure-devops`
|
|
98
|
+
extension is not installed).
|
|
99
|
+
|
|
100
|
+
**Expected Behaviour**
|
|
101
|
+
|
|
102
|
+
The connector does not issue any direct `curl`/HTTP request against the Azure DevOps REST
|
|
103
|
+
API, and does not fetch or scrape the PR's web UI as a substitute -- even if the project
|
|
104
|
+
looks publicly reachable. Instead it follows the Authentication check steps, reports the
|
|
105
|
+
missing session/PAT or missing installation plainly, and halts every read and write until
|
|
106
|
+
`az account show` succeeds or a keychain PAT is available.
|
|
107
|
+
|
|
108
|
+
**Assertions**
|
|
109
|
+
|
|
110
|
+
- [ ] Connector does not issue a `curl` or other raw HTTP request to any Azure DevOps
|
|
111
|
+
endpoint as a substitute for `az`/`az rest`.
|
|
112
|
+
- [ ] Connector does not fetch or scrape the PR's web UI as a fallback.
|
|
113
|
+
- [ ] Connector halts reads and writes and prompts for `az` installation/authentication
|
|
114
|
+
rather than degrading to an alternative retrieval method.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: create-golang-project
|
|
3
3
|
description: >
|
|
4
4
|
Scaffolds the initial boilerplate structure for a Go (Golang) CLI or library project following
|
|
5
5
|
the standard tooling and layout defined in agentme-edr-102. Activate this skill when the user
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: create-golang-project
|
|
3
|
+
skill-version: "1.0"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Test Scenarios
|
|
7
|
+
|
|
8
|
+
### Scenario 1: Create a new Go CLI project, happy path
|
|
9
|
+
|
|
10
|
+
**Trigger / Input**
|
|
11
|
+
|
|
12
|
+
"Create a Go CLI project. Module `github.com/acme/logscan`, binary name `logscan`, first feature
|
|
13
|
+
`scan`, first subcommand `scan`."
|
|
14
|
+
|
|
15
|
+
**Expected Behaviour**
|
|
16
|
+
|
|
17
|
+
1. Phase 1 gathers or infers the module path, binary name, Go version (default `1.24`), first
|
|
18
|
+
feature package name, and first CLI subcommand name.
|
|
19
|
+
2. Phase 2 creates `.mise.toml`, `go.mod`, a `main.go` that only dispatches to `adapters/cli`, the
|
|
20
|
+
root `Makefile` (exporting `GOCACHE`/`GOMODCACHE`/`GOLANGCI_LINT_CACHE`, with `build`,
|
|
21
|
+
`build-all`, `lint`, `test`, `test-coverage`, `benchmark`, and `clean` targets), `.golangci.yml`,
|
|
22
|
+
`.gitignore`, and `README.md`.
|
|
23
|
+
3. Phase 3 creates `app/scan/scan.go` and `app/scan/scan_test.go` with the `Options`/`Result`/`Run`
|
|
24
|
+
shape.
|
|
25
|
+
4. Phase 4 creates `adapters/cli/scan.go` that parses flags and calls into `app/scan`.
|
|
26
|
+
5. Phase 5 runs `make setup` and `make all`, fixing any compile or lint errors before finishing.
|
|
27
|
+
|
|
28
|
+
**Assertions**
|
|
29
|
+
|
|
30
|
+
- [ ] Output creates `main.go` containing only argument dispatch, with no business logic.
|
|
31
|
+
- [ ] Output places the `scan` domain logic in `app/scan/scan.go` and the flag parsing in
|
|
32
|
+
`adapters/cli/scan.go`, not the reverse.
|
|
33
|
+
- [ ] Output's root `Makefile` exports `GOCACHE`, `GOMODCACHE`, and `GOLANGCI_LINT_CACHE` under
|
|
34
|
+
`.cache/` and defines `build`, `lint`, and `test` targets.
|
|
35
|
+
- [ ] Output reports running `make setup` and `make all` and fixes any compile or lint errors
|
|
36
|
+
before declaring completion.
|
|
37
|
+
|
|
38
|
+
### Scenario 2: Business logic requested inside main.go is redirected to app/
|
|
39
|
+
|
|
40
|
+
**Trigger / Input**
|
|
41
|
+
|
|
42
|
+
"Put the scan logic directly inside `main.go` instead of a separate package, and use
|
|
43
|
+
`fmt.Println` to print debug output during scanning."
|
|
44
|
+
|
|
45
|
+
**Expected Behaviour**
|
|
46
|
+
|
|
47
|
+
Per the Conventions and reminders section, the skill keeps `main.go` as a thin dispatcher with no
|
|
48
|
+
business logic, places the scan logic in `app/scan/`, and uses `logrus` instead of `fmt.Println`
|
|
49
|
+
for diagnostic/debug output.
|
|
50
|
+
|
|
51
|
+
**Assertions**
|
|
52
|
+
|
|
53
|
+
- [ ] Output does not place business logic inside `main.go`.
|
|
54
|
+
- [ ] Output uses `logrus` rather than `fmt.Println` for diagnostic/debug output.
|
|
55
|
+
|
|
56
|
+
### Scenario 3: internal/ package is not created without explicit justification
|
|
57
|
+
|
|
58
|
+
**Trigger / Input**
|
|
59
|
+
|
|
60
|
+
"Create an `internal/` package for the scan helpers so other repositories can't import them."
|
|
61
|
+
|
|
62
|
+
**Expected Behaviour**
|
|
63
|
+
|
|
64
|
+
Per the Conventions and reminders section, the skill does not create an `internal/` package by
|
|
65
|
+
default — it keeps the helpers importable (e.g., under `app/scan/` or `shared/`) unless the user
|
|
66
|
+
gives an explicit justification for restricting importability.
|
|
67
|
+
|
|
68
|
+
**Assertions**
|
|
69
|
+
|
|
70
|
+
- [ ] Output does not create an `internal/` package without the user first providing an explicit
|
|
71
|
+
justification.
|
|
72
|
+
- [ ] Output keeps the scan helpers in an importable location such as `app/scan/` or `shared/`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: create-javascript-project
|
|
3
3
|
description: >
|
|
4
4
|
Scaffolds the initial boilerplate structure for a JavaScript/TypeScript project following
|
|
5
5
|
the standard tooling and layout defined in agentme-edr-101. Activate this skill when the user
|
|
@@ -48,16 +48,16 @@ MISE := mise exec --
|
|
|
48
48
|
%:
|
|
49
49
|
@echo ''
|
|
50
50
|
@echo '>>> Running /lib:$@...'
|
|
51
|
-
|
|
51
|
+
@$(MAKE) -C lib $@
|
|
52
52
|
@echo ''
|
|
53
53
|
@echo '>>> Running /examples:$@...'
|
|
54
|
-
|
|
54
|
+
@STAGE=dev $(MAKE) -C examples $@
|
|
55
55
|
|
|
56
56
|
publish:
|
|
57
|
-
|
|
57
|
+
@$(MAKE) -C lib publish
|
|
58
58
|
|
|
59
59
|
setup:
|
|
60
|
-
|
|
60
|
+
mise install
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
**`./.mise.toml`**
|
|
@@ -126,52 +126,52 @@ CACHE_DIR := .cache
|
|
|
126
126
|
|
|
127
127
|
build: install
|
|
128
128
|
@rm -rf dist
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
@mkdir -p $(CACHE_DIR)/tsc
|
|
130
|
+
$(MISE) pnpm exec tsc --incremental --tsBuildInfoFile $(CACHE_DIR)/tsc/tsconfig.tsbuildinfo --outDir dist
|
|
131
131
|
@-find ./dist \( -regex '.*\.test\..*' -o -regex '.*__tests.*' \) -exec rm -rf {} \; 2> /dev/null
|
|
132
132
|
@# Create pack for use by examples to simulate real external usage
|
|
133
|
-
|
|
133
|
+
$(MISE) pnpm pack --pack-destination dist
|
|
134
134
|
|
|
135
135
|
build-module: install
|
|
136
136
|
@rm -rf dist
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
@mkdir -p $(CACHE_DIR)/tsc
|
|
138
|
+
$(MISE) pnpm exec tsc --incremental --tsBuildInfoFile $(CACHE_DIR)/tsc/tsconfig.tsbuildinfo --outDir dist
|
|
139
139
|
@-find ./dist \( -regex '.*\.test\..*' -o -regex '.*__tests.*' \) -exec rm -rf {} \; 2> /dev/null
|
|
140
140
|
|
|
141
141
|
lint:
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
@mkdir -p $(CACHE_DIR)/eslint
|
|
143
|
+
$(MISE) pnpm exec eslint ./src --cache --cache-location $(CACHE_DIR)/eslint/.eslintcache
|
|
144
144
|
|
|
145
145
|
lint-fix:
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
@mkdir -p $(CACHE_DIR)/eslint
|
|
147
|
+
$(MISE) pnpm exec eslint ./src --fix --cache --cache-location $(CACHE_DIR)/eslint/.eslintcache
|
|
148
148
|
|
|
149
149
|
test-watch:
|
|
150
|
-
|
|
150
|
+
$(MISE) pnpm exec jest --watch
|
|
151
151
|
|
|
152
152
|
test:
|
|
153
|
-
|
|
153
|
+
$(MISE) pnpm exec jest --verbose
|
|
154
154
|
|
|
155
155
|
clean:
|
|
156
156
|
rm -rf node_modules
|
|
157
157
|
rm -rf dist
|
|
158
|
-
|
|
158
|
+
rm -rf .cache
|
|
159
159
|
|
|
160
160
|
all: build lint test
|
|
161
161
|
|
|
162
162
|
install:
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
mise install
|
|
164
|
+
$(MISE) pnpm install --frozen-lockfile --config.dedupe-peer-dependents=false
|
|
165
165
|
|
|
166
166
|
publish:
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
$(MISE) npx -y monotag@1.26.0 current --bump-action=latest --prefix=
|
|
168
|
+
@VERSION=$$($(MISE) node -p "require('./package.json').version"); \
|
|
169
169
|
if echo "$$VERSION" | grep -q '-'; then \
|
|
170
170
|
TAG=$$(echo "$$VERSION" | sed 's/[0-9]*\.[0-9]*\.[0-9]*-\([a-zA-Z][a-zA-Z0-9]*\).*/\1/'); \
|
|
171
171
|
echo "Prerelease version $$VERSION detected, publishing with --tag $$TAG"; \
|
|
172
|
-
|
|
172
|
+
$(MISE) npm publish --no-git-checks --provenance --tag "$$TAG"; \
|
|
173
173
|
else \
|
|
174
|
-
|
|
174
|
+
$(MISE) npm publish --no-git-checks --provenance; \
|
|
175
175
|
fi
|
|
176
176
|
```
|
|
177
177
|
|
|
@@ -283,7 +283,6 @@ export default [
|
|
|
283
283
|
},
|
|
284
284
|
},
|
|
285
285
|
];
|
|
286
|
-
];
|
|
287
286
|
```
|
|
288
287
|
|
|
289
288
|
Do not name this file `eslint.config.js` unless the generated package also opts into ESM with `"type": "module"`, because that produces Node.js warnings and conflicts with the recommended Jest CommonJS setup.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: create-javascript-project
|
|
3
|
+
skill-version: "1.0"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Test Scenarios
|
|
7
|
+
|
|
8
|
+
### Scenario 1: Create a new TypeScript library, happy path
|
|
9
|
+
|
|
10
|
+
**Trigger / Input**
|
|
11
|
+
|
|
12
|
+
"Create a new TypeScript library project called `retry-client`."
|
|
13
|
+
|
|
14
|
+
**Expected Behaviour**
|
|
15
|
+
|
|
16
|
+
1. Phase 1 gathers or infers the package name (`retry-client`), description, author, and Node.js
|
|
17
|
+
version (default `24`).
|
|
18
|
+
2. Phase 2 creates the root `Makefile` (delegating to `lib/` then `examples/`), `.mise.toml`, and
|
|
19
|
+
`.gitignore` ignoring `node_modules/`, `dist/`, and `.cache/`.
|
|
20
|
+
3. Phase 3 creates `lib/src/index.ts`, `lib/src/index.test.ts`, `lib/Makefile`, `lib/package.json`
|
|
21
|
+
(without `"type": "module"`), `lib/tsconfig.json`, `lib/jest.config.js`, and
|
|
22
|
+
`lib/eslint.config.mjs` pointing `parserOptions.project` at `tsconfig.json`.
|
|
23
|
+
4. Phase 4 creates `examples/Makefile` and `examples/usage-basic/` consuming the packed tarball
|
|
24
|
+
from `lib/dist/`.
|
|
25
|
+
5. Phase 5 creates the workspace `README.md` and `lib/README.md` with Quick Start first.
|
|
26
|
+
6. Phase 6 verifies the Phase 6 checklist, including that `lib/src/index.ts` exports at least one
|
|
27
|
+
symbol and all `[package-name]` placeholders are replaced with `retry-client`.
|
|
28
|
+
|
|
29
|
+
**Assertions**
|
|
30
|
+
|
|
31
|
+
- [ ] Output creates a root `Makefile` that delegates every target to `lib/` and then `examples/`.
|
|
32
|
+
- [ ] Output creates `lib/eslint.config.mjs` with `parserOptions.project` set to
|
|
33
|
+
`['./tsconfig.json']` and no duplicated closing syntax.
|
|
34
|
+
- [ ] Output keeps `lib/package.json` without `"type": "module"` while using `eslint.config.mjs` as
|
|
35
|
+
the ESLint entry point.
|
|
36
|
+
- [ ] Output replaces every `[package-name]` placeholder with `retry-client` across the generated
|
|
37
|
+
files.
|
|
38
|
+
|
|
39
|
+
### Scenario 2: CLI tool request adds a bin entry and bundling step
|
|
40
|
+
|
|
41
|
+
**Trigger / Input**
|
|
42
|
+
|
|
43
|
+
"Scaffold a JavaScript CLI tool called `snap-cli`."
|
|
44
|
+
|
|
45
|
+
**Expected Behaviour**
|
|
46
|
+
|
|
47
|
+
Per the Edge Cases entry for CLI tools, the skill adds a `"bin"` field to `lib/package.json`
|
|
48
|
+
pointing at the built output, creates `lib/src/main.ts` as the CLI entry point, and adds an
|
|
49
|
+
esbuild bundling step to `lib/Makefile` rather than relying on the plain `tsc` build alone.
|
|
50
|
+
|
|
51
|
+
**Assertions**
|
|
52
|
+
|
|
53
|
+
- [ ] Output adds a `"bin"` field to `lib/package.json` referencing the built CLI entry point.
|
|
54
|
+
- [ ] Output creates `lib/src/main.ts` as the CLI entry point and adds an esbuild bundle step to
|
|
55
|
+
`lib/Makefile`.
|
|
56
|
+
|
|
57
|
+
### Scenario 3: "No examples needed" removes the examples delegation cleanly
|
|
58
|
+
|
|
59
|
+
**Trigger / Input**
|
|
60
|
+
|
|
61
|
+
"Create a TypeScript library called `token-cache` but skip the examples project."
|
|
62
|
+
|
|
63
|
+
**Expected Behaviour**
|
|
64
|
+
|
|
65
|
+
Per the Edge Cases entry for omitting examples, the skill does not create the `examples/`
|
|
66
|
+
directory and removes the `examples` delegation step from the root `Makefile`, while still
|
|
67
|
+
creating the full `lib/` structure and root `README.md`.
|
|
68
|
+
|
|
69
|
+
**Assertions**
|
|
70
|
+
|
|
71
|
+
- [ ] Output does not create an `examples/` directory.
|
|
72
|
+
- [ ] Output's root `Makefile` does not include a delegation step to `examples/`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: create-python-project
|
|
3
3
|
description: >
|
|
4
4
|
Scaffolds the initial boilerplate structure for a Python project following the standard tooling
|
|
5
5
|
and layout defined in agentme-edr-103. Activate this skill when the user asks to create,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: create-python-project
|
|
3
|
+
skill-version: "1.0"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Test Scenarios
|
|
7
|
+
|
|
8
|
+
### Scenario 1: Create a new Python package, happy path
|
|
9
|
+
|
|
10
|
+
**Trigger / Input**
|
|
11
|
+
|
|
12
|
+
"Create a Python project called `event_tools`."
|
|
13
|
+
|
|
14
|
+
**Expected Behaviour**
|
|
15
|
+
|
|
16
|
+
1. Phase 1 gathers or infers package name (`event_tools`), description, author, Python version
|
|
17
|
+
(default `3.13`), and primary entry point.
|
|
18
|
+
2. Phase 2 creates root `.mise.toml`, root `Makefile` (exporting `UV_PROJECT_ENVIRONMENT`/
|
|
19
|
+
`UV_CACHE_DIR`, delegating `build`/`lint`/`test` to `lib/`, and running each `examples/*`
|
|
20
|
+
project against the built wheel), root `.gitignore` ignoring `.venv/`, `dist/`, `.cache/`, and
|
|
21
|
+
`__pycache__/`, and root `README.md` with Getting Started (`make setup` / `make test`) near the
|
|
22
|
+
top.
|
|
23
|
+
3. Phase 3 creates `lib/Makefile`, `lib/pyproject.toml` (Ruff, ty, pytest-cov, pip-audit
|
|
24
|
+
configured), and `lib/README.md` with Quick Start first.
|
|
25
|
+
4. Phase 4 creates `lib/src/event_tools/` with `app/`, `adapters/`, `shared/` following the
|
|
26
|
+
hexagonal layout, plus `lib/tests/hello_test.py`.
|
|
27
|
+
5. Phase 5 creates `examples/basic-usage/` as an independent consumer project that imports
|
|
28
|
+
`event_tools` rather than importing from `lib/src/`.
|
|
29
|
+
6. Phase 6 runs `make setup`, `make install`, `make lint-fix`, `make test`, and `make build`, and
|
|
30
|
+
fixes any failures before finishing.
|
|
31
|
+
|
|
32
|
+
**Assertions**
|
|
33
|
+
|
|
34
|
+
- [ ] Output creates `lib/src/event_tools/app/`, `lib/src/event_tools/adapters/`, and
|
|
35
|
+
`lib/src/event_tools/shared/` following the hexagonal layout.
|
|
36
|
+
- [ ] Output configures `lib/pyproject.toml` with Ruff, ty, pytest-cov, and pip-audit, and does
|
|
37
|
+
not add a separate `requirements.txt`, `setup.py`, `ruff.toml`, or `ty.toml`.
|
|
38
|
+
- [ ] Output creates `examples/basic-usage/` as its own project that imports the `event_tools`
|
|
39
|
+
package rather than reaching into `lib/src/` with a relative import.
|
|
40
|
+
- [ ] Output reports running `make lint-fix`, `make test`, and `make build` and fixes any
|
|
41
|
+
failures before declaring completion.
|
|
42
|
+
|
|
43
|
+
### Scenario 2: CLI package request adds an entry point, not a new baseline
|
|
44
|
+
|
|
45
|
+
**Trigger / Input**
|
|
46
|
+
|
|
47
|
+
"Scaffold a Python CLI package called `net_probe` with a command named `probe`."
|
|
48
|
+
|
|
49
|
+
**Expected Behaviour**
|
|
50
|
+
|
|
51
|
+
Per Phase 4 and the skill's own CLI example, the skill keeps the same baseline Makefile and
|
|
52
|
+
quality checks and adds the CLI entry point in `lib/src/net_probe/adapters/cli/__init__.py`,
|
|
53
|
+
adding `[project.scripts]` to `lib/pyproject.toml` only because the command name (`probe`)
|
|
54
|
+
differs from the module name (`net_probe`).
|
|
55
|
+
|
|
56
|
+
**Assertions**
|
|
57
|
+
|
|
58
|
+
- [ ] Output places the CLI entry point in `lib/src/net_probe/adapters/cli/__init__.py`, not in
|
|
59
|
+
`app/` or at the package root.
|
|
60
|
+
- [ ] Output adds a `[project.scripts]` entry in `lib/pyproject.toml` mapping `probe` to the CLI
|
|
61
|
+
entry point.
|
|
62
|
+
|
|
63
|
+
### Scenario 3: Example-only dependency stays in the example, not in lib/
|
|
64
|
+
|
|
65
|
+
**Trigger / Input**
|
|
66
|
+
|
|
67
|
+
"Add an example under `examples/` that calls a public HTTP API and therefore needs the `httpx`
|
|
68
|
+
library. The core `event_tools` package itself does not need `httpx`."
|
|
69
|
+
|
|
70
|
+
**Expected Behaviour**
|
|
71
|
+
|
|
72
|
+
Per the Edge Cases entry on example dependencies, the skill adds `httpx` to that example's own
|
|
73
|
+
`pyproject.toml` and does not add it to `lib/pyproject.toml`, since the library itself has no
|
|
74
|
+
need for it.
|
|
75
|
+
|
|
76
|
+
**Assertions**
|
|
77
|
+
|
|
78
|
+
- [ ] Output adds `httpx` only to the example's own `pyproject.toml`.
|
|
79
|
+
- [ ] Output does not add `httpx` to `lib/pyproject.toml`.
|