@sitar_fiercer4c/skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +75 -0
  3. package/bin/install.js +45 -0
  4. package/package.json +29 -0
  5. package/skills/architecture-walkthrough/SKILL.md +223 -0
  6. package/skills/architecture-walkthrough/references/sections.md +29 -0
  7. package/skills/architecture-walkthrough/scripts/check_structure.py +200 -0
  8. package/skills/autotest-webapp-ui/SKILL.md +58 -0
  9. package/skills/backend-code-review/SKILL.md +386 -0
  10. package/skills/backend-code-review/references/report-format.md +333 -0
  11. package/skills/backend-code-review/scripts/list_routes.py +269 -0
  12. package/skills/backend-code-review/scripts/sweep.py +550 -0
  13. package/skills/backend-code-review/scripts/verify_citations.py +201 -0
  14. package/skills/be-brief/SKILL.md +18 -0
  15. package/skills/clarke-list-excel/SKILL.md +51 -0
  16. package/skills/clarke-list-excel/references/output-schema.md +125 -0
  17. package/skills/clarke-list-excel/scripts/clarke_common.py +251 -0
  18. package/skills/clarke-list-excel/scripts/clarke_extract.py +487 -0
  19. package/skills/clarke-list-excel/scripts/load_clarke.py +322 -0
  20. package/skills/clarke-list-excel/scripts/run_all.py +63 -0
  21. package/skills/datalab-api/SKILL.md +163 -0
  22. package/skills/datalab-api/references/parameters-and-payload.md +121 -0
  23. package/skills/datalab-api/references/table-selection.md +35 -0
  24. package/skills/datalab-api/scripts/datalab_tables.py +365 -0
  25. package/skills/find-test-seam/SKILL.md +41 -0
  26. package/skills/frontend-code-review/SKILL.md +247 -0
  27. package/skills/frontend-code-review-2/SKILL.md +192 -0
  28. package/skills/frontend-code-review-2/scripts/fetch_pr_comments.py +65 -0
  29. package/skills/frontend-code-review-2/scripts/render_report.py +139 -0
  30. package/skills/murtaza-breif/SKILL.md +143 -0
  31. package/skills/murtaza-breif/scripts/save_brief.py +128 -0
  32. package/skills/pdf-to-json/SKILL.md +42 -0
  33. package/skills/pdf-to-json/references/output-schema.md +168 -0
  34. package/skills/pdf-to-json/scripts/extract_figures.py +319 -0
  35. package/skills/pdf-to-json/scripts/load_mongo.py +287 -0
  36. package/skills/pdf-to-json/scripts/pdf_extract.py +1313 -0
  37. package/skills/record-api-traffic/SKILL.md +434 -0
  38. package/skills/record-api-traffic/references/reading-recordings.md +224 -0
  39. package/skills/record-api-traffic/scripts/check-schema.mjs +184 -0
  40. package/skills/record-api-traffic/scripts/dump-quotation.mjs +67 -0
  41. package/skills/record-api-traffic/scripts/dump-source-excel.mjs +75 -0
  42. package/skills/record-api-traffic/scripts/lib/repo.mjs +109 -0
  43. package/skills/record-api-traffic/scripts/preflight.py +528 -0
  44. package/skills/record-api-traffic/scripts/record-api-traffic.py +720 -0
  45. package/skills/refac-wrt-business-goal/SKILL.md +305 -0
  46. package/skills/refac-wrt-business-goal/references/critic.md +170 -0
  47. package/skills/system-resource-triage/SKILL.md +180 -0
  48. package/skills/system-resource-triage/scripts/reap.sh +116 -0
  49. package/skills/system-resource-triage/scripts/triage.sh +111 -0
  50. package/skills/using-git-worktrees/SKILL.md +167 -0
package/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Copyright (c) 2026 thenextepisode-stealth. All rights reserved.
2
+
3
+ This software is proprietary and confidential. Unauthorized copying,
4
+ distribution, or use of this software, in whole or in part, is prohibited
5
+ without prior written permission from the copyright holder.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # skills
2
+
3
+ Agent skills for Claude Code, distributed as the private npm package `@sitar_fiercer4c/skills`.
4
+
5
+ Installing the package copies every skill into the `.claude/skills` directory of the project where `npm install` is run.
6
+
7
+ ## Install
8
+
9
+ You need an npm account that has been added as a collaborator on this private package.
10
+
11
+ ```sh
12
+ npm login # or add a read-only token to .npmrc (see below)
13
+ npm install -D @sitar_fiercer4c/skills
14
+ ```
15
+
16
+ The skills land in `./.claude/skills/<skill-name>/`.
17
+
18
+ For CI, add this to the project's `.npmrc` and set `NPM_TOKEN` to a read-only token:
19
+
20
+ ```
21
+ //registry.npmjs.org/:_authToken=${NPM_TOKEN}
22
+ ```
23
+
24
+ ### If install scripts are disabled
25
+
26
+ With `--ignore-scripts`, pnpm, or bun, the postinstall copy may not run. Copy the skills manually from the project root:
27
+
28
+ ```sh
29
+ npx @sitar_fiercer4c/skills
30
+ ```
31
+
32
+ ## Update
33
+
34
+ ```sh
35
+ npm install -D @sitar_fiercer4c/skills@latest
36
+ ```
37
+
38
+ Skills shipped by this package are replaced whenever npm installs a new copy of the package (a fresh `node_modules` or a new version), so local edits to them are overwritten. Other skills in `.claude/skills` are left alone.
39
+
40
+ npm skips the copy when the installed version is unchanged. To restore the skills in that case, run `npx @sitar_fiercer4c/skills`.
41
+
42
+ ## Uninstall
43
+
44
+ `npm uninstall` does not remove the copied skills. Delete their folders from `.claude/skills` manually.
45
+
46
+ ## Skills
47
+
48
+ - architecture-walkthrough
49
+ - autotest-webapp-ui
50
+ - backend-code-review
51
+ - be-brief
52
+ - clarke-list-excel
53
+ - datalab-api
54
+ - find-test-seam
55
+ - frontend-code-review
56
+ - frontend-code-review-2
57
+ - murtaza-breif
58
+ - pdf-to-json
59
+ - record-api-traffic
60
+ - refac-wrt-business-goal
61
+ - system-resource-triage
62
+ - using-git-worktrees
63
+
64
+ ## Development
65
+
66
+ Each skill lives in `skills/<name>/` with a `SKILL.md`. `evals/` folders are kept in the repo but excluded from the published package.
67
+
68
+ To publish, load the token from `.env.local` and run:
69
+
70
+ ```sh
71
+ set -a && . ./.env.local && set +a
72
+ npm version patch
73
+ npm publish
74
+ git push --follow-tags
75
+ ```
package/bin/install.js ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Copies the bundled skills into <project>/.claude/skills.
5
+ // Runs as a postinstall hook, or manually via `npx @sitar_fiercer4c/skills`.
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const pkgRoot = path.resolve(__dirname, '..');
11
+ const srcDir = path.join(pkgRoot, 'skills');
12
+ const isPostinstall = process.env.npm_lifecycle_event === 'postinstall';
13
+
14
+ // INIT_CWD is the directory npm was invoked from, i.e. the consumer project.
15
+ const projectRoot = path.resolve(process.env.INIT_CWD || process.cwd());
16
+
17
+ function main() {
18
+ // Skip when installing dependencies inside this repo, or for global installs.
19
+ if (isPostinstall && (projectRoot === pkgRoot || process.env.npm_config_global === 'true')) {
20
+ return;
21
+ }
22
+
23
+ const destDir = path.join(projectRoot, '.claude', 'skills');
24
+ fs.mkdirSync(destDir, { recursive: true });
25
+
26
+ const installed = [];
27
+ for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
28
+ if (!entry.isDirectory()) continue;
29
+ const dest = path.join(destDir, entry.name);
30
+ // Replace only skills this package ships; other skills in the folder are untouched.
31
+ fs.rmSync(dest, { recursive: true, force: true });
32
+ fs.cpSync(path.join(srcDir, entry.name), dest, { recursive: true });
33
+ installed.push(entry.name);
34
+ }
35
+
36
+ console.log(`skills: installed ${installed.length} skills into ${destDir}`);
37
+ }
38
+
39
+ try {
40
+ main();
41
+ } catch (err) {
42
+ console.error(`skills: failed to install skills: ${err.message}`);
43
+ // Never break the consumer's `npm install`; the manual npx command can be rerun.
44
+ process.exitCode = isPostinstall ? 0 : 1;
45
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@sitar_fiercer4c/skills",
3
+ "version": "0.1.0",
4
+ "description": "Claude Code agent skills, installed into the project's .claude/skills directory",
5
+ "license": "UNLICENSED",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/thenextepisode-stealth/skills.git"
9
+ },
10
+ "bin": {
11
+ "skills": "bin/install.js"
12
+ },
13
+ "scripts": {
14
+ "postinstall": "node bin/install.js"
15
+ },
16
+ "files": [
17
+ "bin/",
18
+ "skills/",
19
+ "!skills/*/evals/**",
20
+ "!skills/*/datalab_raw/**",
21
+ "!**/__pycache__/**"
22
+ ],
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "publishConfig": {
27
+ "access": "restricted"
28
+ }
29
+ }
@@ -0,0 +1,223 @@
1
+ ---
2
+ name: architecture-walkthrough
3
+ description: Build up Backend/ARCHITECTURE.md for the murtaza-hotel-project backend one section at a time, tracing real code and walking each section through in chat before writing it. Use this skill whenever the user wants to understand, document, trace, or explain any part of that backend — asks about a workflow (login, Outlook OAuth, inbox, attachment preview, extraction pipeline, quotation editing, Excel/PDF export), asks to fill in or continue ARCHITECTURE.md, asks "how does X work" about that repo, or asks what files run for a given feature. Also use it when adding a new section to that doc, revising one already written, or refreshing sections after the backend code has changed.
4
+ ---
5
+
6
+ # Architecture walkthrough
7
+
8
+ ## What this builds
9
+
10
+ `/home/dev/workspaces/murtaza-workspaces/murtaza-hotel-project/Backend/ARCHITECTURE.md` — a
11
+ workflow-organised map of that backend, written for someone learning the codebase.
12
+
13
+ The doc is organised by workflow, not by layer. Each **H2 is a business workflow** (what the user is
14
+ trying to do); each **H3 under it is a technical workflow** that implements part of it. It was
15
+ created deliberately empty — introduction plus headings — and is filled in one H3 at a time.
16
+
17
+ Read `references/sections.md` for the current section list, the file inventory for each, and the
18
+ findings already verified against source.
19
+
20
+ ## The protocol
21
+
22
+ This is the part that matters most. The doc is how the reader learns the codebase, so **the chat
23
+ pass is the review and the file is the record.** Writing first inverts that: prose the reader never
24
+ validated accumulates in the doc, and they lose the chance to say "explain that better" or "that
25
+ level is wrong for me" before it sets.
26
+
27
+ For each section:
28
+
29
+ 1. **Trace the real code.** Open every file in the section's inventory and follow the actual call
30
+ chain. See "Tracing" below — this is where the section's accuracy is won or lost.
31
+ 2. **Draft the section in chat**, complete and in the template format below. Not a summary of what
32
+ you'll write — the section itself.
33
+ 3. **Stop and wait.** Do not touch ARCHITECTURE.md. The user reads it and responds.
34
+ 4. **Revise in chat** until they approve. Their questions during this pass are where the section's
35
+ Notes come from — see "What goes in Notes".
36
+ 5. **Then write it** to the doc, as approved.
37
+
38
+ If the user pre-authorises writing ("just write it", "draft and add 3.5 straight in"), skip the gate
39
+ — but still trace before drafting. The gate is about their review, not about being cautious.
40
+
41
+ Take one section per pass. Section 3.4, the extraction pipeline, is large enough that it is worth
42
+ splitting across several passes and saying so before starting.
43
+
44
+ ## Updating a section after the code changes
45
+
46
+ A written section is a claim about code that may have moved on since. When the user says the code
47
+ changed and the doc needs to catch up, do not re-derive the section from scratch and do not trust
48
+ what it currently says.
49
+
50
+ Work one section at a time, through the same gate as writing a new one:
51
+
52
+ 1. **Read the section as it stands**, then re-trace its inventory files in the current source.
53
+ 2. **Work out what actually differs** — citations that no longer land on the code they name, claims
54
+ about the flow that no longer hold, and code the section never mentioned.
55
+ 3. **Draft the revised section in chat**, complete and in the template format, and say plainly what
56
+ changed and what you are leaving alone.
57
+ 4. **Stop and wait**, revise until approved, then write it.
58
+
59
+ Keep the gate here rather than rewriting straight in. A section that has been through the user's
60
+ review carries their decisions about depth and emphasis, and a silent rewrite discards them where
61
+ the reader has no way to notice. Showing the diff in chat is also what tells them whether the change
62
+ is a line number or a change in how the system works.
63
+
64
+ If the trace turns up code with no home in the doc — a new service, a step no section covers —
65
+ propose where it belongs rather than filing it silently or leaving it out.
66
+
67
+ ## Tracing
68
+
69
+ Every claim in a section must come from source you opened. Three things in this repo will mislead
70
+ you if you trust them:
71
+
72
+ - **Doc comments in the code.** Most comments in `email.controller.js` and `email.service.js` say
73
+ the routes are `/api/email/...`. They are wrong — `app.js:92` mounts that router at `/api`, so
74
+ the real path is `/api/inbox`. A whole section was drafted incorrectly from these comments before
75
+ anyone opened `app.js`.
76
+ - **The repo's other docs.** `README.md`, `QUOTATION.md`, `ATTACHMENT_TO_EXCEL_FLOW.md` and
77
+ `CODE_REVIEW.md` all predate the 2026-08-30 extraction refactors. They describe Datalab as an
78
+ optional step after OfficeCLI; it now runs in parallel with bounding-box merging.
79
+ - **A subagent's summary.** Subagents are useful for locating files and listing importers. They read
80
+ excerpts, so their narrative of a flow is a lead to verify, not a source to quote.
81
+
82
+ Cite `file.js:LINE` for every function you name, and confirm the line still holds what you say it
83
+ does before writing it down.
84
+
85
+ ## The section template
86
+
87
+ Read sections 3.1–3.3 in ARCHITECTURE.md before drafting. **They are the format specification** — if
88
+ they and this skill ever disagree on shape or voice, the doc wins, because it reflects the most
89
+ recent round of the user's feedback.
90
+
91
+ Their Notes blocks are the one thing not to copy the scale of. Those notes accumulated over several
92
+ rounds of the reader asking questions, so a written section holds more of them than any draft of it
93
+ did. Match their voice, not their length.
94
+
95
+ ````markdown
96
+ ### 3.N Section name
97
+
98
+ **What this does for the business workflow:** 15–30 words, plain English, from the operator's point
99
+ of view. What they are trying to accomplish, and what this step contributes.
100
+
101
+ `METHOD /path` — or, when a section covers more than one endpoint, a sentence naming each.
102
+
103
+ **Input:** what arrives — auth state, URL params, query flags, body.
104
+
105
+ **Output:** what goes back, plus side effects (documents written, jobs started).
106
+
107
+ **Files:** the files whose code actually runs, comma-separated, backticked.
108
+
109
+ ```
110
+ [ASCII diagram]
111
+ ```
112
+
113
+ **Notes** (optional)
114
+
115
+ Unnumbered paragraphs, one idea each. See "What goes in Notes" — often absent on a first draft.
116
+ ````
117
+
118
+ **Do not add a Steps block by default.** The diagram, plus whatever notes the diagram cannot hold,
119
+ is the finished shape. The diagram already carries the sequence, so prose that walks the same stages
120
+ again is the same information twice and buries the notes that are actually load-bearing.
121
+
122
+ Add **Steps** only when the reader asks for more — "explain each step a little more", "I can't
123
+ follow the diagram here". Then write one bold imperative title per stage, numbered to match the
124
+ diagram's `(1)…(N)`, two to four sentences each:
125
+
126
+ ```markdown
127
+ **Steps**
128
+
129
+ **(1) Imperative title.** Two to four sentences expanding that stage of the diagram.
130
+ ```
131
+
132
+ Section 3.3 in the doc carries Steps because the reader asked for them there. Do not read that as
133
+ the default.
134
+
135
+ ## What goes in Notes
136
+
137
+ Every note costs the reader a detour away from the diagram, so a note has to earn its place, and
138
+ there are only two ways it can.
139
+
140
+ **One: the fact has no shape in a flow.** The diagram is where every fact goes first — as a node, a
141
+ label beside a node, a branch condition, an error exit, an annotation stacked to the right. Before
142
+ keeping a note, try to draw it; if it fits in the diagram, move it there and cut the note. What is
143
+ left over is the material with no arrow: an inconsistency between two files, a reason stated in a
144
+ code comment, a constraint that lives outside the call chain the diagram traces.
145
+
146
+ **Two: the reader asked.** When they read the draft and ask "what does `.lean()` do here?" or "why
147
+ two round trips?", that question is the section telling you what it is missing. Answer in chat, then
148
+ fold the answer into Notes when you write the section, in the doc's own voice — not "you asked
149
+ about X", just the explanation.
150
+
151
+ The second source is why a first draft's Notes should be thin. Two or three notes is a normal draft;
152
+ none at all is a legitimate draft and the block can be left out entirely. Resist explaining the Node
153
+ and JS idioms up front, even though the reader is weak there and a diagram cannot hold them: you
154
+ cannot tell which ones they already know, and a draft that answers eight guessed questions buries
155
+ the one or two notes that are actually load-bearing. The questions they do ask are better evidence
156
+ than your guess at them, and the review gate exists to collect them.
157
+
158
+ When you revise a written section after the code changes, treat the notes already in it as answers
159
+ the reader once asked for. Keep them unless the code they describe is gone.
160
+
161
+ ## Diagram conventions
162
+
163
+ The diagram carries the flow; the prose carries what a diagram cannot express. Follow the diagrams
164
+ already in the doc:
165
+
166
+ - Flow runs downward with `│` and `▼`, starting at ` client`.
167
+ - A node is `path/file.js:LINE` and, where useful, the function name beside it.
168
+ - External calls go right with `──►`, with the URL and its query parameters stacked to the right.
169
+ - Error exits go on the same line as their cause: `none → 400 "Outlook is not connected"`.
170
+ - Branches use `├─` and `└─`, with the condition first and the outcome after `──►`.
171
+ - A box `┌─┐` expands a sub-sequence inlined at that point.
172
+ - Numbered stages `(1)`, `(2)` label branch points inside the diagram. They stand on their own; they
173
+ do not oblige you to write a Steps block, but they supply its numbering if one is asked for later.
174
+ - One diagram per endpoint. A section covering two endpoints gets two diagrams.
175
+
176
+ ## Writing style
177
+
178
+ **Do not editorialize.** Explain what the code does; do not offer a verdict on it. Phrasings like
179
+ "the interesting bit", "this looks wasteful", "one thing to not mix up" were called out and removed.
180
+
181
+ When the code has a reason, attribute it to the comment that states it rather than presenting it as
182
+ your own reading:
183
+
184
+ > The comment at `email.service.js:416` gives the reason: locating the attachment inside a message
185
+ > fetched with this user's own token confirms it belongs to them.
186
+
187
+ State anomalies as facts and let the reader draw the conclusion:
188
+
189
+ > `getInbox` inlines the load-refresh-retry sequence that `withGraph()` (line 321) exists to hold.
190
+
191
+ not "this is duplicated code that should be refactored."
192
+
193
+ **Pitch to the reader.** They are strong in Python, SQL, Linux, relational and NoSQL databases,
194
+ system design, data flow and ETL pipelines; weak in JavaScript, Node, npm and anything frontend.
195
+
196
+ So when an explanation is called for — they asked, or you are writing Steps — the Node and JS idioms
197
+ are what to spend it on: a promise deliberately not awaited, Mongoose `select: false`, a callback
198
+ passed to a wrapper function, ESM default-export objects. Never spend it on database indexes, atomic
199
+ updates, HTTP status codes or what a pipeline stage is; they know those better than you do.
200
+
201
+ This tells you which explanations are worth writing, not that a draft should pre-empt them — see
202
+ "What goes in Notes".
203
+
204
+ Prefer short paragraphs over long ones, and concrete nouns over abstractions. Ordinary sentences,
205
+ not bullet fragments, in Steps and Notes.
206
+
207
+ ## Before presenting
208
+
209
+ Run the structure check on your draft:
210
+
211
+ ```bash
212
+ python3 scripts/check_structure.py <path-to-ARCHITECTURE.md> # all sections
213
+ python3 scripts/check_structure.py <path-to-ARCHITECTURE.md> --section 3.5
214
+ ```
215
+
216
+ It verifies the template is complete — description present and 15–35 words, Input/Output/Files,
217
+ at least one diagram and `file:line` citations, with no banned editorializing phrases. Notes and
218
+ Steps are both optional: a missing Notes block is reported as a warning rather than a failure, and a
219
+ missing Steps block is not reported at all. If Steps are present their numbering must match the
220
+ diagram. The check is shape only; accuracy is on you.
221
+
222
+ Empty headings are reported as `empty` and are not failures — the doc is meant to be filled in
223
+ gradually.
@@ -0,0 +1,29 @@
1
+ # Sections, file inventories, and verified findings
2
+
3
+ Paths below are relative to
4
+ `/home/dev/workspaces/murtaza-workspaces/murtaza-hotel-project/Backend/src/`.
5
+
6
+ ## Doc state
7
+
8
+ | Section | Title | Status |
9
+ |---|---|---|
10
+ | 1.1 | Registration | written |
11
+ | 1.2 | Login | written |
12
+ | 1.3 | Password reset | written |
13
+ | 1.4 | Session validation | written |
14
+ | 2.1 | Starting the connection | written |
15
+ | 2.2 | OAuth callback and token storage | written |
16
+ | 2.3 | Silent token refresh | written |
17
+ | 2.4 | Connection status and disconnect | written |
18
+ | 3.1 | Browsing the inbox | written |
19
+ | 3.2 | Previewing an attachment | written |
20
+ | 3.3 | Triggering extraction | written |
21
+ | 3.4 | The extraction pipeline | written — spine plus 3.4.1–3.4.5 |
22
+ | 3.5 | Reading a quotation | written |
23
+ | 3.6 | Editing a quotation | written |
24
+ | 3.7 | Exporting to Excel | written |
25
+ | 3.8 | Exporting to PDF | written |
26
+ | 3.9 | Sending the quotation by email | written |
27
+ | — | Known issues (H2 at the end of the doc) | written |
28
+
29
+ Re-derive this table from the doc rather than trusting it; sections get filled in between uses.
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env python3
2
+ """Check that ARCHITECTURE.md sections follow the walkthrough template.
3
+
4
+ Shape only — it cannot tell you whether a section is accurate. Empty headings are
5
+ reported as `empty` and never fail, because the doc is filled in gradually. Notes and
6
+ Steps are both optional; a missing Notes block is a warning, not a failure.
7
+
8
+ python3 check_structure.py path/to/ARCHITECTURE.md
9
+ python3 check_structure.py path/to/ARCHITECTURE.md --section 3.5
10
+ python3 check_structure.py path/to/ARCHITECTURE.md --json
11
+ """
12
+
13
+ import argparse
14
+ import json
15
+ import re
16
+ import sys
17
+
18
+ DESC_LABEL = "**What this does for the business workflow:**"
19
+ DESC_MIN, DESC_MAX = 15, 35
20
+
21
+ ENDPOINT_RE = re.compile(r"`(GET|POST|PUT|PATCH|DELETE)\s+/")
22
+ CITATION_RE = re.compile(r"[\w./-]+\.(?:js|mjs|json):\d+")
23
+ STAGE_RE = re.compile(r"\((\d+)\)")
24
+ STEP_RE = re.compile(r"^\*\*\((\d+)\)")
25
+ FENCE_RE = re.compile(r"^```")
26
+
27
+ # Phrasings the reader has asked to keep out: verdicts on the code rather than
28
+ # descriptions of it.
29
+ BANNED = [
30
+ "interesting bit",
31
+ "the interesting",
32
+ "looks wasteful",
33
+ "seems wasteful",
34
+ "not mix up",
35
+ "should be refactored",
36
+ "code smell",
37
+ "in my opinion",
38
+ "i think",
39
+ "arguably",
40
+ "unfortunately",
41
+ "sadly",
42
+ "cleverly",
43
+ "elegantly",
44
+ "surprisingly",
45
+ "oddly enough",
46
+ "the good news",
47
+ "the bad news",
48
+ "worth noting that",
49
+ ]
50
+
51
+
52
+ def split_sections(text):
53
+ """Yield (number, title, body_lines) for every H3 heading."""
54
+ lines = text.splitlines()
55
+ starts = [
56
+ (i, m.group(1), m.group(2).strip())
57
+ for i, line in enumerate(lines)
58
+ if (m := re.match(r"^###\s+([\d.]+)\s+(.*)$", line))
59
+ ]
60
+ for pos, (idx, number, title) in enumerate(starts):
61
+ end = len(lines)
62
+ for j in range(idx + 1, len(lines)):
63
+ if lines[j].startswith("### ") or lines[j].startswith("## "):
64
+ end = j
65
+ break
66
+ if pos + 1 < len(starts):
67
+ end = min(end, starts[pos + 1][0])
68
+ yield number, title, lines[idx + 1 : end]
69
+
70
+
71
+ def fenced_blocks(body):
72
+ blocks, current, inside = [], [], False
73
+ for line in body:
74
+ if FENCE_RE.match(line):
75
+ if inside:
76
+ blocks.append(current)
77
+ current, inside = [], False
78
+ else:
79
+ inside = True
80
+ continue
81
+ if inside:
82
+ current.append(line)
83
+ return blocks
84
+
85
+
86
+ def description_words(body):
87
+ for i, line in enumerate(body):
88
+ if line.strip().startswith(DESC_LABEL):
89
+ para = [line.strip()[len(DESC_LABEL) :]]
90
+ for nxt in body[i + 1 :]:
91
+ if not nxt.strip():
92
+ break
93
+ para.append(nxt)
94
+ return len(re.findall(r"[A-Za-z0-9][\w'`./:-]*", " ".join(para)))
95
+ return None
96
+
97
+
98
+ def check(number, title, body):
99
+ text = "\n".join(body)
100
+ prose = "\n".join(
101
+ line for line in body if not line.startswith("```")
102
+ ) # banned-phrase scan includes diagrams; harmless
103
+
104
+ if not text.strip():
105
+ return {"section": number, "title": title, "status": "empty", "checks": []}
106
+
107
+ blocks = fenced_blocks(body)
108
+ words = description_words(body)
109
+ stages = sorted({int(n) for b in blocks for n in STAGE_RE.findall("\n".join(b))})
110
+ steps = sorted(int(m.group(1)) for line in body if (m := STEP_RE.match(line)))
111
+ lowered = prose.lower()
112
+ hits = [p for p in BANNED if p in lowered]
113
+
114
+ checks = [
115
+ ("business description present", "required", words is not None,
116
+ "add the `**What this does for the business workflow:**` line"),
117
+ (f"description is {DESC_MIN}-{DESC_MAX} words", "required",
118
+ words is not None and DESC_MIN <= words <= DESC_MAX,
119
+ f"description is {words} words"),
120
+ ("endpoint named", "required", bool(ENDPOINT_RE.search(text)),
121
+ "name the route as `METHOD /path`"),
122
+ ("Input stated", "required", "**Input:**" in text, "add an `**Input:**` line"),
123
+ ("Output stated", "required", "**Output:**" in text, "add an `**Output:**` line"),
124
+ ("Files listed", "required", "**Files:**" in text, "add a `**Files:**` line"),
125
+ ("diagram present", "required", len(blocks) > 0, "add the ASCII flow diagram"),
126
+ ("file:line citations", "required", bool(CITATION_RE.search(text)),
127
+ "cite file.js:LINE for the functions named"),
128
+ # Advisory, not required: Notes carry only what the diagram cannot and what the reader
129
+ # asked about, so a section with neither has nothing to say here. Failing the check would
130
+ # buy a filler paragraph.
131
+ ("Notes section", "advisory", "**Notes**" in text,
132
+ "no `**Notes**` block — fine if nothing qualified"),
133
+ ("no editorializing", "required", not hits,
134
+ f"banned phrasing: {', '.join(hits)}" if hits else ""),
135
+ # A Steps block is optional — the diagram plus Notes is the finished shape, and Steps are
136
+ # added only when the reader asks for more. So absence is fine; a mismatch is not.
137
+ ("Steps, if present, match the diagram numbering", "required",
138
+ (not steps) or (steps == stages),
139
+ f"diagram stages {stages} vs Steps {steps}"),
140
+ ]
141
+
142
+ results = [
143
+ {"name": name, "level": level, "passed": bool(ok), "detail": detail if not ok else ""}
144
+ for name, level, ok, detail in checks
145
+ ]
146
+ failed = any(r["level"] == "required" and not r["passed"] for r in results)
147
+ return {
148
+ "section": number,
149
+ "title": title,
150
+ "status": "fail" if failed else "pass",
151
+ "checks": results,
152
+ }
153
+
154
+
155
+ def main():
156
+ ap = argparse.ArgumentParser()
157
+ ap.add_argument("path")
158
+ ap.add_argument("--section", help="check one section, e.g. 3.5")
159
+ ap.add_argument("--json", action="store_true")
160
+ args = ap.parse_args()
161
+
162
+ with open(args.path, encoding="utf-8") as fh:
163
+ text = fh.read()
164
+
165
+ results = [
166
+ check(num, title, body)
167
+ for num, title, body in split_sections(text)
168
+ if not args.section or num == args.section
169
+ ]
170
+
171
+ if not results:
172
+ print(f"no section matched {args.section!r}", file=sys.stderr)
173
+ return 2
174
+
175
+ if args.json:
176
+ print(json.dumps(results, indent=2))
177
+ else:
178
+ for r in results:
179
+ if r["status"] == "empty":
180
+ print(f" ~ {r['section']} {r['title']} (empty)")
181
+ continue
182
+ mark = "OK " if r["status"] == "pass" else "FAIL"
183
+ print(f"{mark:>4} {r['section']} {r['title']}")
184
+ for c in r["checks"]:
185
+ if c["passed"]:
186
+ continue
187
+ tag = "fail" if c["level"] == "required" else "warn"
188
+ detail = f" — {c['detail']}" if c["detail"] else ""
189
+ print(f" [{tag}] {c['name']}{detail}")
190
+
191
+ written = [r for r in results if r["status"] != "empty"]
192
+ bad = [r for r in written if r["status"] == "fail"]
193
+ print(f"\n{len(written) - len(bad)}/{len(written)} written sections pass "
194
+ f"({len(results) - len(written)} still empty)")
195
+
196
+ return 1 if any(r["status"] == "fail" for r in results) else 0
197
+
198
+
199
+ if __name__ == "__main__":
200
+ sys.exit(main())
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: autotest-webapp-ui
3
+ description: Automatically test webapp by controlling a chrome browser via CDP
4
+ ---
5
+
6
+ # Permissions
7
+ You have permission to:
8
+ - start servers in a shell
9
+
10
+ # Steps
11
+
12
+ ## Inform user
13
+ - open inspect panel since CDP doesnt have tooling for it
14
+
15
+ ## Start servers
16
+ - Start frontend & backend server
17
+
18
+ ## Inputs from user
19
+ - CDP port - The port on which CDP listens for instructions to control chrome on another machine
20
+ - screenshot frequency (default: last page) - as specified by user.
21
+ - screenshot save path (default: skills/autotest-webapp-ui/autotest-webapp-ui-workspace/<YYYYMMDD-HHMMSS>/<path-n>) - save every run in a timestamped folder where each screenshot name is of format <screenshot-index>-<screenshot-slug> (eg: 01-login_page, 02-email_page)
22
+ - save commands issued to CDP (default: no) - The raw commands sent to CDP to control chrome
23
+ - save the logs from any of the Inspect panel subtabs (default: no): Logs from panels specified by user (Console, Network, Sources, Application, etc)
24
+
25
+ ## Preflight checks
26
+ - Check Chrome control over CDP is working by opening google.com and closing it later
27
+
28
+ ## Traverse happy paths
29
+
30
+ ### Path-1
31
+ - login with email `admin@gmail.com`, password `admin@123`
32
+ - open emails
33
+ - then click on the latest email
34
+ - click on preview, wait for the preview to load
35
+ - close the preview
36
+ - click view quotation, wait for the next page to load
37
+ - scroll the full page and come back to the top
38
+
39
+ ## Output
40
+ - Create a .md file in the screenshot directory with following sections
41
+ - Path-n bullet points: copy paste these from above
42
+ - Path-n user flow diagram: Mermaid flowchart. Eg:
43
+ ```mermaid
44
+ graph LR
45
+ A(Start) -->B["<img src='<screenhot-01-path>' width='100' hegiht='100'/>"] -->C["<img src='<screenhot-02-path>' width='100' hegiht='100'/>"] -->D(End)
46
+ ```
47
+ - Share screenshot path
48
+ - Share paths for other inputs user said yes to
49
+
50
+ ## Ask user
51
+ - what path they want to try next
52
+
53
+ ## Cleanup
54
+ - Stop frontend & backend server
55
+
56
+ # Constraints & alternatives
57
+ - Do not write intermediate scripts to execute steps. Drive with one-shot commands
58
+ - Do not make any changes to CDP port (eg: killing it, stopping it)