skillgendev 0.1.0__py3-none-any.whl

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 (114) hide show
  1. skillgen/__init__.py +7 -0
  2. skillgen/_data/claude/agents/route-analyzer.md +26 -0
  3. skillgen/_data/claude/commands/command.md +23 -0
  4. skillgen/_data/claude/skills/driver/SKILL.md +76 -0
  5. skillgen/_data/hintpacks/README.md +85 -0
  6. skillgen/_data/hintpacks/folders/astro-pages.yml +13 -0
  7. skillgen/_data/hintpacks/folders/nextjs-app.yml +13 -0
  8. skillgen/_data/hintpacks/folders/nextjs-pages.yml +13 -0
  9. skillgen/_data/hintpacks/folders/nuxt-pages.yml +13 -0
  10. skillgen/_data/hintpacks/folders/sveltekit-routes.yml +13 -0
  11. skillgen/_data/hintpacks/routers/aspnet-attributes.yml +16 -0
  12. skillgen/_data/hintpacks/routers/django.yml +12 -0
  13. skillgen/_data/hintpacks/routers/express.yml +9 -0
  14. skillgen/_data/hintpacks/routers/flask.yml +21 -0
  15. skillgen/_data/hintpacks/routers/laravel.yml +12 -0
  16. skillgen/_data/hintpacks/routers/phoenix.yml +13 -0
  17. skillgen/_data/hintpacks/routers/rails.yml +14 -0
  18. skillgen/_data/hintpacks/routers/react-router-jsx.yml +13 -0
  19. skillgen/_data/hintpacks/routers/route-objects-js.yml +21 -0
  20. skillgen/_data/hintpacks/routers/route-objects.yml +21 -0
  21. skillgen/_data/hintpacks/routers/spring.yml +13 -0
  22. skillgen/analyze/__init__.py +1 -0
  23. skillgen/analyze/prompt.py +189 -0
  24. skillgen/analyze/runner.py +457 -0
  25. skillgen/assets.py +69 -0
  26. skillgen/cli.py +1678 -0
  27. skillgen/compile/__init__.py +1 -0
  28. skillgen/compile/assess.py +175 -0
  29. skillgen/compile/fields.py +320 -0
  30. skillgen/compile/layout.py +87 -0
  31. skillgen/compile/merge.py +560 -0
  32. skillgen/compile/unopened.py +114 -0
  33. skillgen/config.py +165 -0
  34. skillgen/drift/__init__.py +1 -0
  35. skillgen/drift/check.py +113 -0
  36. skillgen/drift/diff.py +120 -0
  37. skillgen/errors.py +114 -0
  38. skillgen/export.py +417 -0
  39. skillgen/generate/__init__.py +1 -0
  40. skillgen/generate/bundle.py +251 -0
  41. skillgen/generate/evals.py +144 -0
  42. skillgen/generate/examples.py +167 -0
  43. skillgen/generate/fill_engine.js +202 -0
  44. skillgen/generate/fill_script.py +253 -0
  45. skillgen/generate/folder.py +115 -0
  46. skillgen/generate/index_page.py +218 -0
  47. skillgen/generate/index_template.html +86 -0
  48. skillgen/generate/inline_setter.py +725 -0
  49. skillgen/generate/layout_reference.py +72 -0
  50. skillgen/generate/locators.py +270 -0
  51. skillgen/generate/manual_steps.py +165 -0
  52. skillgen/generate/skill_md.py +872 -0
  53. skillgen/generate/user_rules.py +129 -0
  54. skillgen/graph/__init__.py +1 -0
  55. skillgen/graph/codegraph.py +527 -0
  56. skillgen/graph/connections.py +335 -0
  57. skillgen/graph/hubs.py +84 -0
  58. skillgen/graph/slice.py +241 -0
  59. skillgen/handoff.py +217 -0
  60. skillgen/logs.py +121 -0
  61. skillgen/model/__init__.py +1 -0
  62. skillgen/model/confidence.py +83 -0
  63. skillgen/model/facts.py +66 -0
  64. skillgen/model/page.py +489 -0
  65. skillgen/model/probe.py +117 -0
  66. skillgen/model/route.py +183 -0
  67. skillgen/model/serialize.py +592 -0
  68. skillgen/pipeline.py +1551 -0
  69. skillgen/probe/__init__.py +1 -0
  70. skillgen/probe/capture.py +153 -0
  71. skillgen/probe/classify.py +136 -0
  72. skillgen/probe/extract.js +164 -0
  73. skillgen/probe/journal.py +281 -0
  74. skillgen/probe/measure.js +24 -0
  75. skillgen/probe/runner.py +1066 -0
  76. skillgen/py.typed +0 -0
  77. skillgen/routes/__init__.py +1 -0
  78. skillgen/routes/astgrep.py +415 -0
  79. skillgen/routes/folders.py +131 -0
  80. skillgen/routes/hintpacks.py +227 -0
  81. skillgen/routes/merge.py +208 -0
  82. skillgen/routes/naming.py +202 -0
  83. skillgen/routes/paths.py +150 -0
  84. skillgen/schema/__init__.py +97 -0
  85. skillgen/schema/cli/add-rule.schema.json +49 -0
  86. skillgen/schema/cli/answer.schema.json +43 -0
  87. skillgen/schema/cli/check.schema.json +61 -0
  88. skillgen/schema/cli/doctor.schema.json +65 -0
  89. skillgen/schema/cli/export-chatgpt.schema.json +52 -0
  90. skillgen/schema/cli/export.schema.json +53 -0
  91. skillgen/schema/cli/generate.schema.json +169 -0
  92. skillgen/schema/cli/index.schema.json +48 -0
  93. skillgen/schema/cli/init.schema.json +49 -0
  94. skillgen/schema/cli/install.schema.json +47 -0
  95. skillgen/schema/cli/login.schema.json +40 -0
  96. skillgen/schema/cli/logs.schema.json +49 -0
  97. skillgen/schema/cli/prepare.schema.json +68 -0
  98. skillgen/schema/cli/probe.schema.json +63 -0
  99. skillgen/schema/cli/questions.schema.json +74 -0
  100. skillgen/schema/cli/routes.schema.json +85 -0
  101. skillgen/schema/cli/validate.schema.json +66 -0
  102. skillgen/schema/page-analysis.schema.json +523 -0
  103. skillgen/schema/page.schema.json +561 -0
  104. skillgen/schema/route-listing.schema.json +22 -0
  105. skillgen/validate/__init__.py +1 -0
  106. skillgen/validate/model_checks.py +127 -0
  107. skillgen/validate/scan.py +119 -0
  108. skillgen/validate/spec.py +191 -0
  109. skillgen/workspace.py +301 -0
  110. skillgendev-0.1.0.dist-info/METADATA +796 -0
  111. skillgendev-0.1.0.dist-info/RECORD +114 -0
  112. skillgendev-0.1.0.dist-info/WHEEL +4 -0
  113. skillgendev-0.1.0.dist-info/entry_points.txt +2 -0
  114. skillgendev-0.1.0.dist-info/licenses/LICENSE +201 -0
skillgen/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """Compile an app's code into one Agent Skills folder per page."""
2
+
3
+ # The public name (PyPI package, command, workspace folder) lives here only; everything
4
+ # else derives from it. The import package stays `skillgen` (src/skillgen/).
5
+ TOOL_NAME = "skillgendev"
6
+
7
+ __version__ = "0.1.0"
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: {{tool}}-route-analyzer
3
+ description: Analyses one route of a web app for {{tool}}, reading its code read-only and writing the page-analysis JSON. Use one per route when generating several page skills.
4
+ tools: Read, Grep, Glob, Write
5
+ ---
6
+
7
+ You analyse one page of a web application so {{tool}} can write a skill that fills its form.
8
+
9
+ You receive a route, the path of a prompt file and the path where the analysis must be
10
+ written. Read the prompt file and follow it exactly. Read code only; never edit source
11
+ files. The only file you write is the analysis JSON at the path you were given.
12
+
13
+ The JSON must match `page-analysis.schema.json` (its path is in the prompt instructions
14
+ you received). Use the app's own words for labels and meanings. Mark every attribute you
15
+ deduced rather than read literally in `inferred`. Never copy real names, emails, numbers
16
+ or IDs from seeds, fixtures or tests.
17
+
18
+ Find every part of the form that is hidden until something is clicked: wizard steps behind
19
+ Next, tabs, accordion panels, dialogs opened by a button. Follow the state that shows each
20
+ part (a step counter, an active tab, an open flag) to the control that changes it, using
21
+ the imports the prompt's files point to. Describe each part as a view, in the order a
22
+ person fills them, with the click that reaches it from the part before. A field shown
23
+ because another field has a value is `visible_if`, not a view. You describe what to click;
24
+ {{tool}} does the clicking and checks it in a browser.
25
+
26
+ When done, reply with one line: the route, the number of fields, and any questions.
@@ -0,0 +1,23 @@
1
+ ---
2
+ description: Generate Agent Skills that fill this app's forms, one per route. Usage: /{{tool}} /some/route, /{{tool}} all, or /{{tool}} all --name acme
3
+ argument-hint: "/route | all [--name prefix]"
4
+ ---
5
+
6
+ Generate page skills with {{tool}} for: $ARGUMENTS
7
+
8
+ Follow the `{{tool}}` skill. In short:
9
+
10
+ 1. If `.{{tool}}/config.json` does not exist, run `{{tool}} init` (ask the user for the app's
11
+ display name and, if they have one, a dev URL).
12
+ 2. For `all`: run `{{tool}} routes --all --json`, show the routes, and let the user drop or
13
+ rename any before generating. For one route, use it as given.
14
+ 3. Run `{{tool}} generate --route <route> --json` (or `--all`), passing `--name` through
15
+ and `--xy` when the user wants x/y.
16
+ 4. Follow each result's `next`, as the `{{tool}}` skill says, until nothing is left:
17
+ `analyse` means you read the prompt and write the analysis yourself (one
18
+ `{{tool}}-route-analyzer` subagent per route for several); `ask` means you ask the user
19
+ its question in chat, run `run` on a yes, then run `then`. A result with status
20
+ `exists` asks before a skill is recreated.
21
+ 5. Report each skill folder and any open questions. Ask the user the open questions from
22
+ `{{tool}} questions --json`, record answers with `{{tool}} answer <id> "<answer>"`, then
23
+ generate again with `--overwrite`: the user is updating a skill they just made.
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: {{tool}}
3
+ description: "Drives the {{tool}} compiler, which turns a web app's code into one Agent Skill per page so Claude can fill that page's form. Use when the user asks to generate, update, check or export page or form skills for their app."
4
+ ---
5
+
6
+ # {{tool}}: generate page skills from an app's code
7
+
8
+ {{tool}} reads an app's code route by route and writes one skill folder per page
9
+ (`SKILL.md` + `scripts/fill.js`). Anyone can then fill that page in Claude or Cowork with
10
+ the built-in browser, with few tokens. It works for any framework and any app.
11
+
12
+ ## Commands
13
+ - `{{tool}} init [--app-name "Acme"] [--url http://localhost:3000] [--name acme]`
14
+ - `{{tool}} routes --all [--include "admin/*"] [--route /extra] --json`
15
+ - `{{tool}} generate --route /x [--name my-skill] [--overwrite] [--xy [--open STEP]] --json`
16
+ - `{{tool}} generate --all [--name acme] [--overwrite] [--xy] --json`
17
+ - `{{tool}} prepare --route /x --json` → writes the analysis prompt only, without generating.
18
+ - `{{tool}} questions --json`, `{{tool}} answer <id> "<answer>"`
19
+ - `{{tool}} login --url <page>` → opens a browser window; the user signs in and closes it.
20
+ - `{{tool}} add-rule <skill> "<rule>" [--check "key ^A"]`, or `--global`
21
+ - `{{tool}} validate`, `{{tool}} doctor [--fix]`
22
+ - `{{tool}} export [--zip] [--plugin]` → for Claude, Cowork or Claude Code;
23
+ `{{tool}} export-chatgpt [--zip] [--name acme]` → one ChatGPT plugin.
24
+
25
+ ## Naming
26
+ The user chooses skill names. With one route, `--name` is the exact skill name. With
27
+ `--all`, `--name` is the prefix for every skill (`acme` → `acme-signup`). Names must be
28
+ lowercase letters, digits and single hyphens, at most 64 characters.
29
+
30
+ ## Run, then follow `next` until nothing is left
31
+ {{tool}} never asks on its own; it has no terminal to ask from. When a route cannot
32
+ finish, its result has status `needs` (or `exists`) and a `next` object, and the exit
33
+ code is 3. Do what `next` says, then run its `then` command. Repeat until no result has
34
+ a `next`, or the user says no.
35
+
36
+ - `"action": "analyse"`: {{tool}} could not run the analysis itself (for example Claude
37
+ Code is not signed in). Do it yourself: read `prompt` and the files it lists, read-only,
38
+ following the imports they point to. Write one JSON object matching the schema in the
39
+ prompt to `write`. Then run `then`; {{tool}} uses your analysis while the code is
40
+ unchanged. For several routes, use one `{{tool}}-route-analyzer` subagent per route.
41
+ - `"action": "ask"`: only the user can decide or do this. Ask them `ask` in chat, as a
42
+ question, in your own words if that is clearer.
43
+ - On yes, run `run` when it is not empty, then run `then`.
44
+ - `need` `limit`: the AI's own limit is reached and `ask` says when it resets. Tell
45
+ the user, and stop. Do not read the code and write the analysis yourself: that
46
+ spends far more of the same limit. Run `then` once the limit has reset; the
47
+ analysis already done is reused.
48
+ - `need` `url`: their answer is the address; put it in place of `<url>` in `then`.
49
+ - `need` `login`: `run` opens a browser window and waits until the user signs in and
50
+ closes it, so give it a long timeout. Never type their password yourself.
51
+ - `need` `overwrite`: the skill exists; `then` recreates it. Notes in its user section
52
+ are kept.
53
+ - `need` `open`: the form's fields are hidden behind a click. Their answer is the
54
+ text of the button, tab or link; put it in place of `<label>` in `then`.
55
+ - `need` `server` or `probe`: the user starts their dev server or reinstalls; wait
56
+ until they say it is done, then run `then`.
57
+ - On no, stop that route and say what was left undone.
58
+
59
+ Answering open questions and generating again is the user updating a skill they made,
60
+ so pass `--overwrite` then.
61
+
62
+ ## Rules
63
+ - Never edit the app's source while analysing.
64
+ - Never copy real personal data or secrets into an analysis or a skill.
65
+ - Facts you deduce go in `inferred`; {{tool}} keeps uncertain facts out of skills until the
66
+ developer confirms them.
67
+ - When you analyse a page yourself, describe every part hidden until a click (wizard
68
+ steps, tabs, accordion panels, dialogs) as `views`, in fill order, each with the click
69
+ that reaches it from the part before; the prompt says how. You never write click code:
70
+ {{tool}} walks the views in Chromium with `--xy`, measures every field, and the skill
71
+ walks them the same way when it fills the page.
72
+ - A running app is optional. A normal `generate` reads code only. Add `--xy` to also
73
+ measure where each field sits (x/y) on the dev copy; it only adds and never removes a
74
+ field. If the form appears only after a click, add `--route … --open STEP` (a CSS
75
+ selector or `text:Label`); it is saved, and the skill makes the same click. Dev or
76
+ staging only; submits are intercepted.
@@ -0,0 +1,85 @@
1
+ # Hint packs
2
+
3
+ Hint packs are the only place framework knowledge lives. They are YAML data, read by
4
+ generic code; deleting this folder leaves a working tool that finds routes through the
5
+ other sources (your `--route`, the runtime crawl, Claude Code).
6
+
7
+ Every pack has an `id`, a `kind` and a short `about`. Three kinds exist.
8
+
9
+ ## `kind: folder` — folder-based routing
10
+
11
+ ```yaml
12
+ id: nextjs-app
13
+ kind: folder
14
+ about: Next.js app router (app/**/page.tsx)
15
+ roots: [app, src/app] # folders to scan, relative to each project root
16
+ requires_any: [next.config.js, package.json] # files that mark a project root
17
+ page_files: ["page.{tsx,jsx,ts,js,mdx}"] # file names that make a folder a page
18
+ route_from: folder # folder: route is the folder path; file: route is the file path
19
+ index_names: [index] # with route_from: file, these names map to their folder
20
+ skip_segments: ["^\\(.*\\)$", "^@"] # path parts dropped from the route (groups, slots)
21
+ skip_files: ["^_", "^api$"] # path parts that make the whole file not a page
22
+ params: # how parameter segments are written → :name
23
+ - "^\\[\\[?\\.\\.\\.(?P<name>\\w+)\\]?\\]$"
24
+ - "^\\[(?P<name>\\w+)\\]$"
25
+ ```
26
+
27
+ `requires_any` lets one repository hold several apps. Every folder that holds one
28
+ of these files, at any depth, is a project root, and `roots` is looked for inside
29
+ each. In a monorepo with `admin/next.config.js` and `site/package.json`, both
30
+ `admin/src/app` and `site/app` are scanned. Dependency and build folders
31
+ (`node_modules`, `dist`, hidden folders) are never searched. Without `requires_any`
32
+ the pack applies at the repository root only.
33
+
34
+ ## `kind: router` — route declarations found with ast-grep
35
+
36
+ ```yaml
37
+ id: react-router-jsx
38
+ kind: router
39
+ about: <Route path="/x" element={<Page />} />
40
+ language: tsx
41
+ globs: ["**/*.tsx", "**/*.jsx"]
42
+ rule: # any ast-grep rule
43
+ pattern: <Route path=$PATH element={<$COMPONENT $$$ />} $$$ />
44
+ captures:
45
+ path: PATH # metavariable holding the route path (a string literal)
46
+ component: COMPONENT # optional: metavariable naming the page component
47
+ prefix_from: none # reserved for nested routers
48
+ ```
49
+
50
+ The component name is resolved to a file through the code graph, so packs never
51
+ describe import syntax. When the captured text is not a plain name (Rails writes
52
+ `"registrations#new"`), two optional keys reshape it:
53
+
54
+ ```yaml
55
+ component_match: "^[\"']?(?P<name>[\\w/]+)#" # regex with a `name` group
56
+ component_format: "{pascal}Controller" # {name} or {pascal}: registrations → RegistrationsController
57
+ ```
58
+
59
+ Shipped router packs: React Router, route objects, Express, Flask, Django, Laravel,
60
+ Rails, Spring MVC, ASP.NET Core attributes and Phoenix. Each has a tiny sample app under
61
+ `tests/fixtures/hintpacks/<id>/` or `tests/fixtures/<app>/`.
62
+
63
+ When no pack matches, skillgendev asks Claude Code to read the code graph's likely router
64
+ files (`skillgendev routes --all --ask-claude`), so a missing pack never blocks anyone.
65
+
66
+ ## `kind: validator` — field constraints found with ast-grep
67
+
68
+ ```yaml
69
+ id: zod-string-min
70
+ kind: validator
71
+ about: z.string().min(n) inside an object schema
72
+ language: typescript
73
+ rule: { pattern: "$FIELD: z.string().min($MIN)" }
74
+ captures: { field: FIELD, min_length: MIN }
75
+ ```
76
+
77
+ Validator packs only add `EXTRACTED` facts that Claude Code would otherwise read
78
+ itself; they make analysis cheaper, never required.
79
+
80
+ ## Adding a pack
81
+
82
+ 1. Add the YAML file here.
83
+ 2. Add a tiny example under `tests/fixtures/hintpacks/<id>/` and a case in
84
+ `tests/test_hintpacks.py`.
85
+ 3. Run `uv run pytest tests/test_hintpacks.py`.
@@ -0,0 +1,13 @@
1
+ id: astro-pages
2
+ kind: folder
3
+ about: "Astro src/pages/**/*.astro"
4
+ roots: [src/pages]
5
+ page_files: ["*.astro"]
6
+ route_from: file
7
+ index_names: [index]
8
+ skip_segments: []
9
+ skip_files: ["^_"]
10
+ params:
11
+ - "^\\[\\.\\.\\.(?P<name>\\w+)\\]$"
12
+ - "^\\[(?P<name>\\w+)\\]$"
13
+ requires_any: ["astro.config.mjs", "astro.config.ts", "astro.config.js"]
@@ -0,0 +1,13 @@
1
+ id: nextjs-app
2
+ kind: folder
3
+ about: "Next.js app router (app/**/page.tsx)"
4
+ roots: [app, src/app]
5
+ # Where a Next.js project starts, so an app inside a monorepo is found too.
6
+ requires_any: ["next.config.js", "next.config.mjs", "next.config.ts", "package.json"]
7
+ page_files: ["page.tsx", "page.jsx", "page.ts", "page.js", "page.mdx"]
8
+ route_from: folder
9
+ skip_segments: ["^\\(.*\\)$", "^@"]
10
+ skip_files: ["^_", "^api$"]
11
+ params:
12
+ - "^\\[\\[?\\.\\.\\.(?P<name>\\w+)\\]?\\]$"
13
+ - "^\\[(?P<name>\\w+)\\]$"
@@ -0,0 +1,13 @@
1
+ id: nextjs-pages
2
+ kind: folder
3
+ about: "Next.js pages router (pages/**/*.tsx)"
4
+ roots: [pages, src/pages]
5
+ page_files: ["*.tsx", "*.jsx", "*.ts", "*.js", "*.mdx"]
6
+ route_from: file
7
+ index_names: [index]
8
+ skip_segments: []
9
+ skip_files: ["^_", "^api$"]
10
+ params:
11
+ - "^\\[\\[?\\.\\.\\.(?P<name>\\w+)\\]?\\]$"
12
+ - "^\\[(?P<name>\\w+)\\]$"
13
+ requires_any: ["next.config.js", "next.config.mjs", "next.config.ts"]
@@ -0,0 +1,13 @@
1
+ id: nuxt-pages
2
+ kind: folder
3
+ about: "Nuxt pages/ directory (pages/**/*.vue)"
4
+ roots: [pages, app/pages, src/pages]
5
+ page_files: ["*.vue"]
6
+ route_from: file
7
+ index_names: [index]
8
+ skip_segments: ["^\\(.*\\)$"]
9
+ skip_files: ["^_"]
10
+ params:
11
+ - "^\\[\\.\\.\\.(?P<name>\\w+)\\]$"
12
+ - "^\\[\\[?(?P<name>\\w+)\\]?\\]$"
13
+ requires_any: ["nuxt.config.ts", "nuxt.config.js"]
@@ -0,0 +1,13 @@
1
+ id: sveltekit-routes
2
+ kind: folder
3
+ about: "SvelteKit src/routes/**/+page.svelte"
4
+ roots: [src/routes]
5
+ # Where a SvelteKit project starts, so an app inside a monorepo is found too.
6
+ requires_any: ["svelte.config.js", "svelte.config.ts", "package.json"]
7
+ page_files: ["+page.svelte"]
8
+ route_from: folder
9
+ skip_segments: ["^\\(.*\\)$"]
10
+ skip_files: []
11
+ params:
12
+ - "^\\[\\[?\\.\\.\\.(?P<name>\\w+)\\]?\\]$"
13
+ - "^\\[\\[?(?P<name>\\w+)(=\\w+)?\\]?\\]$"
@@ -0,0 +1,16 @@
1
+ id: aspnet-attributes
2
+ kind: router
3
+ about: "ASP.NET Core [Route(\"…\")] and [HttpGet(\"…\")] attributes (conventional routes are left to Claude; Razor @page routes come from Graphify)"
4
+ language: csharp
5
+ globs: ["**/*.cs"]
6
+ rule:
7
+ kind: attribute
8
+ all:
9
+ - has: { field: name, regex: "^(HttpGet|Route)$" }
10
+ - has:
11
+ kind: attribute_argument_list
12
+ has:
13
+ kind: attribute_argument
14
+ has: { kind: string_literal, pattern: $PATH }
15
+ captures:
16
+ path: PATH
@@ -0,0 +1,12 @@
1
+ id: django
2
+ kind: router
3
+ about: "Django path('x/', view) entries in urls.py"
4
+ language: python
5
+ globs: ["**/urls.py"]
6
+ rule:
7
+ any:
8
+ - pattern: path($PATH, $VIEW)
9
+ - pattern: path($PATH, $VIEW, $$$REST)
10
+ captures:
11
+ path: PATH
12
+ component: VIEW
@@ -0,0 +1,9 @@
1
+ id: express
2
+ kind: router
3
+ about: "Express-style app.get('/x', handler) and router.get('/x', handler)"
4
+ language: javascript
5
+ globs: ["**/*.js", "**/*.mjs", "**/*.cjs"]
6
+ rule:
7
+ pattern: $APP.get($PATH, $$$HANDLERS)
8
+ captures:
9
+ path: PATH
@@ -0,0 +1,21 @@
1
+ id: flask
2
+ kind: router
3
+ about: "Flask-style @app.route('/x') and @blueprint.route('/x') decorators"
4
+ language: python
5
+ globs: ["**/*.py"]
6
+ rule:
7
+ kind: decorated_definition
8
+ has:
9
+ kind: decorator
10
+ has:
11
+ any:
12
+ - pattern: $APP.route($PATH)
13
+ - pattern: $APP.route($PATH, $$$ARGS)
14
+ - pattern: $APP.get($PATH)
15
+ all:
16
+ - has:
17
+ field: definition
18
+ has: { field: name, pattern: $COMPONENT }
19
+ captures:
20
+ path: PATH
21
+ component: COMPONENT
@@ -0,0 +1,12 @@
1
+ id: laravel
2
+ kind: router
3
+ about: "Laravel Route::get('/x', [Controller::class, 'action']) and Route::get('/x', ...) declarations"
4
+ language: php
5
+ globs: ["routes/**/*.php"]
6
+ rule:
7
+ any:
8
+ - pattern: "Route::get($PATH, [$COMPONENT::class, $ACTION])"
9
+ - pattern: "Route::get($PATH, $$$REST)"
10
+ captures:
11
+ path: PATH
12
+ component: COMPONENT
@@ -0,0 +1,13 @@
1
+ id: phoenix
2
+ kind: router
3
+ about: "Phoenix router: get \"/signup\", SignupController, :new and live \"/contact\", ContactLive"
4
+ language: elixir
5
+ globs: ["**/router.ex", "**/*_router.ex"]
6
+ rule:
7
+ any:
8
+ - pattern: "get $PATH, $COMPONENT, $ACTION"
9
+ - pattern: "live $PATH, $COMPONENT"
10
+ - pattern: "live $PATH, $COMPONENT, $ACTION"
11
+ captures:
12
+ path: PATH
13
+ component: COMPONENT
@@ -0,0 +1,14 @@
1
+ id: rails
2
+ kind: router
3
+ about: "Rails routes.rb: get \"/signup\", to: \"registrations#new\" (resources blocks are left to Claude)"
4
+ language: ruby
5
+ globs: ["config/routes.rb", "config/routes/**/*.rb"]
6
+ rule:
7
+ any:
8
+ - pattern: "get $PATH, to: $COMPONENT"
9
+ - pattern: "get $PATH, to: $COMPONENT, $$$REST"
10
+ captures:
11
+ path: PATH
12
+ component: COMPONENT
13
+ component_match: "^[\"']?(?P<name>[\\w/]+)#"
14
+ component_format: "{pascal}Controller"
@@ -0,0 +1,13 @@
1
+ id: react-router-jsx
2
+ kind: router
3
+ about: "React Router JSX routes, <Route path=\"/x\" element={<Page />} />"
4
+ language: tsx
5
+ globs: ["**/*.tsx", "**/*.jsx"]
6
+ rule:
7
+ pattern: <Route path="$PATH" $$$ATTRIBUTES />
8
+ has:
9
+ pattern: <$COMPONENT $$$PROPS />
10
+ stopBy: end
11
+ captures:
12
+ path: PATH
13
+ component: COMPONENT
@@ -0,0 +1,21 @@
1
+ id: route-objects-js
2
+ kind: router
3
+ about: "Route objects in JavaScript files, such as { path: '/x', component: Page } (Vue Router, React Router data routers)"
4
+ language: javascript
5
+ globs: ["**/*.js", "**/*.mjs", "**/*.cjs"]
6
+ rule:
7
+ kind: object
8
+ all:
9
+ - has:
10
+ kind: pair
11
+ all:
12
+ - has: { field: key, regex: "^path$" }
13
+ - has: { field: value, pattern: $PATH }
14
+ - has:
15
+ kind: pair
16
+ all:
17
+ - has: { field: key, regex: "^(component|element)$" }
18
+ - has: { field: value, pattern: $COMPONENT }
19
+ captures:
20
+ path: PATH
21
+ component: COMPONENT
@@ -0,0 +1,21 @@
1
+ id: route-objects
2
+ kind: router
3
+ about: "Route objects such as { path: '/x', component: Page } (Vue Router, Angular, React Router data routers)"
4
+ language: typescript
5
+ globs: ["**/*.ts", "**/*.mts", "**/*.cts"]
6
+ rule:
7
+ kind: object
8
+ all:
9
+ - has:
10
+ kind: pair
11
+ all:
12
+ - has: { field: key, regex: "^path$" }
13
+ - has: { field: value, pattern: $PATH }
14
+ - has:
15
+ kind: pair
16
+ all:
17
+ - has: { field: key, regex: "^(component|element)$" }
18
+ - has: { field: value, pattern: $COMPONENT }
19
+ captures:
20
+ path: PATH
21
+ component: COMPONENT
@@ -0,0 +1,13 @@
1
+ id: spring
2
+ kind: router
3
+ about: "Spring MVC @GetMapping(\"/signup\") and @RequestMapping(\"/signup\") on controller methods"
4
+ language: java
5
+ globs: ["**/*.java", "**/*.kt"]
6
+ rule:
7
+ any:
8
+ - pattern: "@GetMapping($PATH)"
9
+ - pattern: "@GetMapping(value = $PATH)"
10
+ - pattern: "@GetMapping(path = $PATH)"
11
+ - pattern: "@RequestMapping($PATH)"
12
+ captures:
13
+ path: PATH
@@ -0,0 +1 @@
1
+ """The analysis step: prompts, the page-analysis schema, and runners."""