@draig/lexis-two 1.0.2 → 1.0.4
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/package.json +7 -1
- package/.agents/plugins/marketplace.json +0 -21
- package/.claude-plugin/marketplace.json +0 -29
- package/.claude-plugin/plugin.json +0 -9
- package/.clinerules/lexis-two.md +0 -163
- package/.codex-plugin/plugin.json +0 -31
- package/.cursor/rules/lexis-two.mdc +0 -169
- package/.env.example +0 -8
- package/.github/FUNDING.yml +0 -1
- package/.github/copilot-instructions.md +0 -47
- package/.github/plugin/marketplace.json +0 -20
- package/.github/plugin/plugin.json +0 -16
- package/.github/workflows/deploy-site.yml +0 -53
- package/.github/workflows/test.yml +0 -29
- package/.kiro/steering/lexis-two.md +0 -167
- package/.nojekyll +0 -0
- package/.windsurf/rules/lexis-two.md +0 -163
- package/AGENTS.md +0 -163
- package/AUDIT.md +0 -74
- package/CNAME +0 -1
- package/SPECXIS.md +0 -576
- package/assets/benchmark-3model.svg +0 -21
- package/assets/lexis-two-complete.webp +0 -0
- package/assets/lexis-two-nobg.png +0 -0
- package/assets/logo.png +0 -0
- package/assets/social-preview.png +0 -0
- package/benchmarks/README.md +0 -114
- package/benchmarks/arms/baseline.js +0 -2
- package/benchmarks/arms/caveman-SKILL.md +0 -67
- package/benchmarks/arms/caveman.js +0 -8
- package/benchmarks/arms/lexis-two.js +0 -10
- package/benchmarks/arms/ponytail.js +0 -6
- package/benchmarks/behavior.js +0 -58
- package/benchmarks/behavior.yaml +0 -40
- package/benchmarks/benchmark-local.py +0 -156
- package/benchmarks/benchmark-opencode-go.js +0 -294
- package/benchmarks/correctness.js +0 -294
- package/benchmarks/lib/aggregate-opencode-go.js +0 -103
- package/benchmarks/lib/load-env.js +0 -31
- package/benchmarks/lib/opencode-go-client.js +0 -151
- package/benchmarks/loc.js +0 -13
- package/benchmarks/opencode-go-models.json +0 -31
- package/benchmarks/promptfooconfig.yaml +0 -41
- package/benchmarks/prompts.json +0 -15
- package/benchmarks/render-opencode-go-report.js +0 -28
- package/benchmarks/results/2026-06-15-llama3.2-local.md +0 -76
- package/benchmarks/results/2026-06-16-opencode-go.md +0 -56
- package/benchmarks/results/opencode-go-2026-06-16-report.html +0 -226
- package/benchmarks/results/opencode-go-2026-06-16.json +0 -1339
- package/commands/lexis-two-audit.toml +0 -3
- package/commands/lexis-two-debt.toml +0 -3
- package/commands/lexis-two-help.toml +0 -3
- package/commands/lexis-two-plan.toml +0 -3
- package/commands/lexis-two-review.toml +0 -3
- package/commands/lexis-two-security.toml +0 -3
- package/commands/lexis-two.toml +0 -3
- package/docs/assets/lexis-two-nobg.png +0 -0
- package/docs/assets/logo.png +0 -0
- package/docs/assets/logo.svg +0 -4
- package/docs/portability.md +0 -147
- package/docs/site.md +0 -52
- package/examples/api-endpoint.md +0 -68
- package/examples/caching.md +0 -74
- package/examples/date-picker.md +0 -48
- package/examples/email-validation.md +0 -51
- package/examples/sorting.md +0 -42
- package/gemini-extension.json +0 -7
- package/opencode.json +0 -4
- package/pi-extension/index.js +0 -161
- package/pi-extension/package.json +0 -8
- package/pi-extension/test/extension.test.js +0 -89
- package/pi-extension/test/helpers.test.js +0 -35
- package/scripts/check-rule-copies.js +0 -82
- package/site/astro.config.mjs +0 -18
- package/site/package-lock.json +0 -4913
- package/site/package.json +0 -14
- package/site/public/CNAME +0 -1
- package/site/public/assets/lexis-two-nobg.png +0 -0
- package/site/public/assets/logo.png +0 -0
- package/site/public/assets/logo.svg +0 -4
- package/site/public/robots.txt +0 -4
- package/site/src/components/Adapt.astro +0 -33
- package/site/src/components/Benchmarks.astro +0 -232
- package/site/src/components/Commands.astro +0 -33
- package/site/src/components/Ecosystem.astro +0 -30
- package/site/src/components/Example.astro +0 -77
- package/site/src/components/Footer.astro +0 -28
- package/site/src/components/Header.astro +0 -87
- package/site/src/components/Hero.astro +0 -58
- package/site/src/components/Home.astro +0 -46
- package/site/src/components/Hosts.astro +0 -62
- package/site/src/components/Install.astro +0 -139
- package/site/src/components/LanguageSwitcher.astro +0 -82
- package/site/src/components/Philosophy.astro +0 -23
- package/site/src/components/Stacks.astro +0 -33
- package/site/src/components/Suggested.astro +0 -39
- package/site/src/data/opencode-go-benchmark.json +0 -230
- package/site/src/i18n/en.ts +0 -155
- package/site/src/i18n/es.ts +0 -158
- package/site/src/i18n/index.ts +0 -14
- package/site/src/layouts/Layout.astro +0 -114
- package/site/src/pages/benchmarks.astro +0 -4
- package/site/src/pages/es/benchmarks.astro +0 -4
- package/site/src/pages/es/index.astro +0 -10
- package/site/src/pages/index.astro +0 -10
- package/site/src/styles/global.css +0 -780
- package/site/tsconfig.json +0 -3
- package/tests/behavior.test.js +0 -80
- package/tests/commands.test.js +0 -40
- package/tests/copilot-plugin.test.js +0 -33
- package/tests/correctness.test.js +0 -191
- package/tests/gemini-extension.test.js +0 -78
- package/tests/hooks-windows.test.js +0 -48
- package/tests/hooks.test.js +0 -177
- package/tests/opencode-plugin.test.js +0 -64
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
name = "lexis-two-help"
|
|
2
|
-
description = "Quick reference for lexis-two levels, skills, and commands"
|
|
3
|
-
prompt = "Show the lexis-two quick reference. One shot, change nothing: do not switch mode, write flag files, or persist anything. Levels: /lexis-two lite, /lexis-two (full, default), /lexis-two ultra. Commands: /lexis-two-review, /lexis-two-audit, /lexis-two-debt, /lexis-two-plan, /lexis-two-security, /lexis-two-help."
|
package/commands/lexis-two.toml
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
name = "lexis-two"
|
|
2
|
-
description = "Switch lexis-two intensity level (lite/full/ultra/off)"
|
|
3
|
-
prompt = "Switch to lexis-two {{args}} mode. If no level specified, use full. Lazy senior dev mode, before any code: does it need to exist at all (YAGNI)? Does the standard library do it? A native platform feature? Can it be one line? Build the minimum that works. No unrequested abstractions, no avoidable dependencies, no boilerplate. Mark intentional simplifications with a lexis: comment."
|
|
Binary file
|
package/docs/assets/logo.png
DELETED
|
Binary file
|
package/docs/assets/logo.svg
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 48" role="img" aria-label="Lexis-Two">
|
|
2
|
-
<rect x="0" y="8" width="220" height="32" rx="4" fill="#141816" stroke="#7cba8a" stroke-width="1.5"/>
|
|
3
|
-
<text x="110" y="30" fill="#7cba8a" font-family="ui-monospace, monospace" font-size="14" font-weight="600" text-anchor="middle" letter-spacing="0.12em">LEXIS-TWO</text>
|
|
4
|
-
</svg>
|
package/docs/portability.md
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# Agent Portability
|
|
2
|
-
|
|
3
|
-
Lexis-Two is an agent-portable ecosystem. The `skills/` folder holds the core behavior.
|
|
4
|
-
Host-specific files are thin adapters that point to those skills.
|
|
5
|
-
|
|
6
|
-
**Site (live target):** [lexis-two.excelso.xyz](https://lexis-two.excelso.xyz) — built from `site/` and deployed via GitHub Actions. See [site.md](./site.md) for hosting.
|
|
7
|
-
|
|
8
|
-
## Naming
|
|
9
|
-
|
|
10
|
-
| Name | What it is |
|
|
11
|
-
| ---- | ---------- |
|
|
12
|
-
| `lexis` | Base prefix — `// lexis:` comments, shared philosophy |
|
|
13
|
-
| `lexis-two` | This repo — public portable rules, skills, commands, adapters |
|
|
14
|
-
| `lexis-one` | Private agent configuration (not published) |
|
|
15
|
-
| `lexis-zero` | Future orchestrator-style agent (not shipped yet) |
|
|
16
|
-
|
|
17
|
-
Slash commands and skill folders use the `lexis-two-*` prefix. Plugin manifests use `"name": "lexis-two"`.
|
|
18
|
-
|
|
19
|
-
## Supported Hosts
|
|
20
|
-
|
|
21
|
-
| Host | Files | Level |
|
|
22
|
-
| ---- | ----- | ----- |
|
|
23
|
-
| OpenCode | `.opencode/plugins/lexis-two.mjs`, `.opencode/command/`, `hooks/`, `skills/` | Full — plugin + mode switches + commands |
|
|
24
|
-
| Claude Code | `.claude-plugin/`, `hooks/hooks.json`, `commands/`, `skills/` | **Coming soon** (v0.3) — files in repo, not verified |
|
|
25
|
-
| GitHub Copilot (IDE plugin) | `.github/plugin/plugin.json`, `hooks/copilot-hooks.json`, `commands/`, `skills/` | **Coming soon** (v0.3) — files in repo, not verified |
|
|
26
|
-
| Gemini CLI | `gemini-extension.json`, `AGENTS.md`, `commands/`, `skills/` | Full — extension manifest + commands |
|
|
27
|
-
| pi | `pi-extension/`, `skills/` (via `package.json` `"pi"`) | Full — extension + commands |
|
|
28
|
-
| Codex | `.codex-plugin/plugin.json`, `hooks/hooks.json`, `AGENTS.md` | Full — plugin + hooks |
|
|
29
|
-
| Cursor | `.cursor/rules/lexis-two.mdc` | Rules — always-on project rule |
|
|
30
|
-
| Windsurf | `.windsurf/rules/lexis-two.md` | Rules — project rule |
|
|
31
|
-
| Cline | `.clinerules/lexis-two.md` | Rules — project rule |
|
|
32
|
-
| GitHub Copilot (repo) | `.github/copilot-instructions.md` | Rules — repository instruction |
|
|
33
|
-
| GitHub Copilot CLI | `AGENTS.md` or `~/.copilot/copilot-instructions.md` | Rules — no mode switches |
|
|
34
|
-
| Kiro | `.kiro/steering/lexis-two.md` | Rules — steering rule |
|
|
35
|
-
| VS Code + Codex | `AGENTS.md` or `~/.codex/AGENTS.md` | Rules — instruction tier |
|
|
36
|
-
| Antigravity | `AGENTS.md` or `.agents/rules/` | Rules — instruction tier |
|
|
37
|
-
| Generic agents | `AGENTS.md` or `skills/*/SKILL.md` | Rules — copy and load |
|
|
38
|
-
|
|
39
|
-
### Adapter rule
|
|
40
|
-
|
|
41
|
-
Keep adapters thin. When a host supports skills or hooks, point it at the
|
|
42
|
-
existing `skills/` and `hooks/` files. When a host only supports project
|
|
43
|
-
instructions, keep its rule text aligned with `AGENTS.md`.
|
|
44
|
-
|
|
45
|
-
Run `node scripts/check-rule-copies.js` after editing `AGENTS.md` to verify
|
|
46
|
-
instruction-tier copies (Cursor, Windsurf, Cline, Kiro) have not drifted.
|
|
47
|
-
|
|
48
|
-
## Slash Commands
|
|
49
|
-
|
|
50
|
-
Available on hosts that ship `commands/` and/or `.opencode/command/` today: OpenCode, Gemini CLI, pi. Claude Code and Copilot plugin: v0.3.
|
|
51
|
-
|
|
52
|
-
| Command | Skill / behavior |
|
|
53
|
-
| ------- | ---------------- |
|
|
54
|
-
| `/lexis-two` | Mode switch — `lite`, `full` (default), `ultra`, `off` |
|
|
55
|
-
| `/lexis-two-review` | `skills/lexis-two-review/` — diff review for over-engineering |
|
|
56
|
-
| `/lexis-two-audit` | `skills/lexis-two-audit/` — full repo audit |
|
|
57
|
-
| `/lexis-two-debt` | `skills/lexis-two-debt/` — harvest `// lexis:` comments |
|
|
58
|
-
| `/lexis-two-plan` | `skills/lexis-two-plan/` — plan before coding |
|
|
59
|
-
| `/lexis-two-security` | `skills/lexis-two-security/` — security audit (Node/TS stack default) |
|
|
60
|
-
| `/lexis-two-help` | Quick reference card |
|
|
61
|
-
|
|
62
|
-
Gemini CLI: `commands/lexis-two*.toml`. OpenCode: `.opencode/command/lexis-two*.md`.
|
|
63
|
-
|
|
64
|
-
## Portable Skills
|
|
65
|
-
|
|
66
|
-
| Skill | What it does |
|
|
67
|
-
| ----- | ------------ |
|
|
68
|
-
| `skills/lexis-two/` | Core ruleset + intensity levels |
|
|
69
|
-
| `skills/lexis-two-review/` | Diff review for over-engineering |
|
|
70
|
-
| `skills/lexis-two-audit/` | Full repo audit |
|
|
71
|
-
| `skills/lexis-two-debt/` | Harvest `// lexis:` comments into debt ledger |
|
|
72
|
-
| `skills/lexis-two-plan/` | Feature planning before coding |
|
|
73
|
-
| `skills/lexis-two-security/` | Security audit (default: Node.js / Next.js / MongoDB) |
|
|
74
|
-
|
|
75
|
-
Adapt skill shell commands for other stacks — see README **Adapting Lexis-Two to Any Stack**.
|
|
76
|
-
|
|
77
|
-
## Project Install
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
git clone https://github.com/nitdraig/lexis-two.git ~/lexis-two
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### OpenCode
|
|
84
|
-
|
|
85
|
-
Add to `opencode.json` in the project (or `~/.config/opencode/opencode.json` globally):
|
|
86
|
-
|
|
87
|
-
```jsonc
|
|
88
|
-
{
|
|
89
|
-
"plugin": ["~/lexis-two/.opencode/plugins/lexis-two.mjs"],
|
|
90
|
-
"instructions": ["~/lexis-two/AGENTS.md"]
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Cursor
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
cp ~/lexis-two/.cursor/rules/lexis-two.mdc .cursor/rules/lexis-two.mdc
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Windsurf / Cline / Kiro
|
|
101
|
-
|
|
102
|
-
Copy the matching rule file into your project:
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
cp ~/lexis-two/.windsurf/rules/lexis-two.md .windsurf/rules/
|
|
106
|
-
cp ~/lexis-two/.clinerules/lexis-two.md .clinerules/
|
|
107
|
-
cp ~/lexis-two/.kiro/steering/lexis-two.md .kiro/steering/
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Gemini CLI
|
|
111
|
-
|
|
112
|
-
Run from the cloned repo root (manifest auto-discovers `commands/` and `AGENTS.md`):
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
cd ~/lexis-two
|
|
116
|
-
# Follow Gemini CLI extension install for gemini-extension.json
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### pi
|
|
120
|
-
|
|
121
|
-
Install as a pi package from the repo root (`package.json` declares `"pi"` extensions and skills).
|
|
122
|
-
|
|
123
|
-
## Global Install (rules-only hosts)
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
# Cursor (global)
|
|
127
|
-
cp ~/lexis-two/.cursor/rules/lexis-two.mdc ~/.cursor/rules/lexis-two.mdc
|
|
128
|
-
|
|
129
|
-
# GitHub Copilot CLI (global)
|
|
130
|
-
cp ~/lexis-two/AGENTS.md ~/.copilot/copilot-instructions.md
|
|
131
|
-
|
|
132
|
-
# VS Code + Codex (global)
|
|
133
|
-
cp ~/lexis-two/AGENTS.md ~/.codex/AGENTS.md
|
|
134
|
-
|
|
135
|
-
# OpenCode (global) — add to ~/.config/opencode/opencode.json:
|
|
136
|
-
# { "plugin": ["~/lexis-two/.opencode/plugins/lexis-two.mjs"] }
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Config
|
|
140
|
-
|
|
141
|
-
Default mode resolution (hooks + pi + OpenCode plugin):
|
|
142
|
-
|
|
143
|
-
1. `LEXIS_TWO_DEFAULT_MODE` env var (`off` \| `lite` \| `full` \| `ultra`)
|
|
144
|
-
2. Config file: `~/.config/lexis-two/config.json` (Windows: `%APPDATA%\lexis-two\config.json`) with `{ "defaultMode": "full" }`
|
|
145
|
-
3. Fallback: `full`
|
|
146
|
-
|
|
147
|
-
Active mode flag (Claude Code): `~/.claude/.lexis-two-active`. OpenCode: `~/.config/opencode/.lexis-two-active`.
|
package/docs/site.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Site — lexis-two.excelso.xyz
|
|
2
|
-
|
|
3
|
-
Astro static site in `site/`. Deployed to GitHub Pages via `.github/workflows/deploy-site.yml`.
|
|
4
|
-
|
|
5
|
-
**Primary goal:** showcase the project and drive clones/stars.
|
|
6
|
-
**Secondary goal:** publish benchmark charts at `/benchmarks/`.
|
|
7
|
-
|
|
8
|
-
## Local dev
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm run site:dev
|
|
12
|
-
# → http://localhost:4321
|
|
13
|
-
|
|
14
|
-
# After a benchmark run:
|
|
15
|
-
npm run benchmark:report # syncs JSON → site/src/data/
|
|
16
|
-
npm run site:build
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Hosting
|
|
20
|
-
|
|
21
|
-
GitHub Pages + custom domain `lexis-two.excelso.xyz`.
|
|
22
|
-
|
|
23
|
-
| Piece | Location |
|
|
24
|
-
| ----- | -------- |
|
|
25
|
-
| Astro app | `site/` |
|
|
26
|
-
| Build output | `site/dist/` |
|
|
27
|
-
| CNAME | `site/public/CNAME` |
|
|
28
|
-
| CI deploy | `.github/workflows/deploy-site.yml` (push to `main` under `site/**`) |
|
|
29
|
-
|
|
30
|
-
DNS: CNAME `lexis-two` → `<user>.github.io`.
|
|
31
|
-
|
|
32
|
-
## Content map
|
|
33
|
-
|
|
34
|
-
| Section | Source |
|
|
35
|
-
| ------- | ------ |
|
|
36
|
-
| Hero + benchmarks CTA | `site/src/components/Home.astro` + i18n |
|
|
37
|
-
| Philosophy ladder | `site/src/i18n/*.ts` |
|
|
38
|
-
| Hosts / commands / install | i18n dictionaries |
|
|
39
|
-
| Benchmark charts | `site/src/pages/benchmarks.astro` + `site/src/data/opencode-go-benchmark.json` |
|
|
40
|
-
| Portability docs | `docs/portability.md` on GitHub (linked, not duplicated) |
|
|
41
|
-
|
|
42
|
-
## Checklist
|
|
43
|
-
|
|
44
|
-
- [x] Astro site in `site/`
|
|
45
|
-
- [x] `site/public/CNAME` → `lexis-two.excelso.xyz`
|
|
46
|
-
- [x] Benchmark page at `/benchmarks/`
|
|
47
|
-
- [ ] GitHub Pages enabled (Settings → Pages → deploy from Actions / gh-pages branch)
|
|
48
|
-
- [ ] DNS CNAME live; HTTPS green
|
|
49
|
-
|
|
50
|
-
## Legacy
|
|
51
|
-
|
|
52
|
-
`docs/index.html` and `docs/styles.css` were removed — use `site/` instead. `docs/portability.md` stays in repo for GitHub linking.
|
package/examples/api-endpoint.md
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# API Endpoint
|
|
2
|
-
|
|
3
|
-
**Task:** "Add an endpoint that returns a user by id."
|
|
4
|
-
|
|
5
|
-
## Without Lexis
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
app/
|
|
9
|
-
├── controllers/user_controller.py
|
|
10
|
-
├── services/user_service.py
|
|
11
|
-
├── repositories/user_repository.py
|
|
12
|
-
├── schemas/user_schemas.py
|
|
13
|
-
└── exceptions/user_exceptions.py
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
```python
|
|
17
|
-
# schemas/user_schemas.py
|
|
18
|
-
class UserResponseDTO(BaseModel):
|
|
19
|
-
id: int
|
|
20
|
-
name: str
|
|
21
|
-
email: str
|
|
22
|
-
|
|
23
|
-
# repositories/user_repository.py
|
|
24
|
-
class UserRepository:
|
|
25
|
-
def __init__(self, db: Session):
|
|
26
|
-
self.db = db
|
|
27
|
-
def find_by_id(self, user_id: int) -> User | None:
|
|
28
|
-
return self.db.get(User, user_id)
|
|
29
|
-
|
|
30
|
-
# services/user_service.py
|
|
31
|
-
class UserService:
|
|
32
|
-
def __init__(self, repo: UserRepository):
|
|
33
|
-
self.repo = repo
|
|
34
|
-
def get_user(self, user_id: int) -> User:
|
|
35
|
-
user = self.repo.find_by_id(user_id)
|
|
36
|
-
if user is None:
|
|
37
|
-
raise UserNotFoundError(user_id)
|
|
38
|
-
return user
|
|
39
|
-
|
|
40
|
-
# controllers/user_controller.py
|
|
41
|
-
@router.get("/users/{user_id}", response_model=UserResponseDTO)
|
|
42
|
-
def get_user(user_id: int, service: UserService = Depends(get_user_service)):
|
|
43
|
-
try:
|
|
44
|
-
return service.get_user(user_id)
|
|
45
|
-
except UserNotFoundError:
|
|
46
|
-
raise HTTPException(status_code=404, detail="User not found")
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Five files, three classes, a custom exception, and a dependency-injection chain, wrapping one database call.
|
|
50
|
-
|
|
51
|
-
## With Lexis
|
|
52
|
-
|
|
53
|
-
```python
|
|
54
|
-
# lexis: drop the layers; keep the response schema, it whitelists what leaves the API
|
|
55
|
-
class UserOut(BaseModel):
|
|
56
|
-
id: int
|
|
57
|
-
name: str
|
|
58
|
-
email: str
|
|
59
|
-
|
|
60
|
-
@app.get("/users/{user_id}", response_model=UserOut)
|
|
61
|
-
def get_user(user_id: int, db: Session = Depends(get_db)):
|
|
62
|
-
user = db.get(User, user_id)
|
|
63
|
-
if not user:
|
|
64
|
-
raise HTTPException(404)
|
|
65
|
-
return user
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
**5 files → 9 lines.** The repository, service, and custom exception were ceremony. The response schema was not: it whitelists which fields leave the API, so it stays. Returning the raw ORM model (`return user`) would leak every column, including the ones you never meant to expose. That is the line Lexis draws, and it is the same one the skill draws in "when NOT to be lazy": cut the layers, keep the trust boundary. Add a service layer when a second caller shows up, if it ever does.
|
package/examples/caching.md
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Caching System
|
|
2
|
-
|
|
3
|
-
**Task:** "We should cache these API responses."
|
|
4
|
-
|
|
5
|
-
## Without Lexis
|
|
6
|
-
|
|
7
|
-
```python
|
|
8
|
-
import time
|
|
9
|
-
import threading
|
|
10
|
-
from collections import OrderedDict
|
|
11
|
-
from dataclasses import dataclass
|
|
12
|
-
from typing import Any, Optional
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@dataclass
|
|
16
|
-
class CacheEntry:
|
|
17
|
-
value: Any
|
|
18
|
-
expires_at: float
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class TTLCache:
|
|
22
|
-
"""Thread-safe LRU cache with per-entry TTL and max size."""
|
|
23
|
-
|
|
24
|
-
def __init__(self, max_size: int = 1000, default_ttl: float = 300.0):
|
|
25
|
-
self._store: OrderedDict[str, CacheEntry] = OrderedDict()
|
|
26
|
-
self._lock = threading.Lock()
|
|
27
|
-
self.max_size = max_size
|
|
28
|
-
self.default_ttl = default_ttl
|
|
29
|
-
self.hits = 0
|
|
30
|
-
self.misses = 0
|
|
31
|
-
|
|
32
|
-
def get(self, key: str) -> Optional[Any]:
|
|
33
|
-
with self._lock:
|
|
34
|
-
entry = self._store.get(key)
|
|
35
|
-
if entry is None or entry.expires_at < time.monotonic():
|
|
36
|
-
self.misses += 1
|
|
37
|
-
self._store.pop(key, None)
|
|
38
|
-
return None
|
|
39
|
-
self._store.move_to_end(key)
|
|
40
|
-
self.hits += 1
|
|
41
|
-
return entry.value
|
|
42
|
-
|
|
43
|
-
def set(self, key: str, value: Any, ttl: Optional[float] = None) -> None:
|
|
44
|
-
with self._lock:
|
|
45
|
-
if len(self._store) >= self.max_size:
|
|
46
|
-
self._store.popitem(last=False)
|
|
47
|
-
self._store[key] = CacheEntry(
|
|
48
|
-
value, time.monotonic() + (ttl or self.default_ttl)
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
# ... plus invalidation, stats endpoint, and unit tests for all of it
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
120 lines of custom infrastructure for a problem nobody has measured yet.
|
|
55
|
-
|
|
56
|
-
## With Lexis
|
|
57
|
-
|
|
58
|
-
First question: **do you actually need a cache?**
|
|
59
|
-
|
|
60
|
-
- **Unsure?** Ship without it. Add it when you measure the problem. (YAGNI)
|
|
61
|
-
- **Pure function, hot path?** The standard library has it:
|
|
62
|
-
|
|
63
|
-
```python
|
|
64
|
-
# lexis: stdlib covers this
|
|
65
|
-
from functools import lru_cache
|
|
66
|
-
|
|
67
|
-
@lru_cache(maxsize=1000)
|
|
68
|
-
def fetch(key): ...
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
- **Real distributed caching needs?** Use Redis / memcached / your platform's
|
|
72
|
-
cache. Infrastructure problems get infrastructure, not a homemade class.
|
|
73
|
-
|
|
74
|
-
**120 lines → 0–3 lines.** The fastest cache is the one you didn't have to debug.
|
package/examples/date-picker.md
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Date Picker
|
|
2
|
-
|
|
3
|
-
**Task:** "Add a date picker to this form."
|
|
4
|
-
|
|
5
|
-
## Without Lexis
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install flatpickr
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
```jsx
|
|
12
|
-
import flatpickr from "flatpickr";
|
|
13
|
-
import "flatpickr/dist/flatpickr.min.css";
|
|
14
|
-
import { useEffect, useRef } from "react";
|
|
15
|
-
|
|
16
|
-
export default function DatePicker({ value, onChange, minDate, maxDate }) {
|
|
17
|
-
const inputRef = useRef(null);
|
|
18
|
-
const instanceRef = useRef(null);
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
instanceRef.current = flatpickr(inputRef.current, {
|
|
22
|
-
defaultDate: value,
|
|
23
|
-
minDate,
|
|
24
|
-
maxDate,
|
|
25
|
-
dateFormat: "Y-m-d",
|
|
26
|
-
onChange: ([date]) => onChange(date),
|
|
27
|
-
});
|
|
28
|
-
return () => instanceRef.current?.destroy();
|
|
29
|
-
}, []);
|
|
30
|
-
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
instanceRef.current?.setDate(value, false);
|
|
33
|
-
}, [value]);
|
|
34
|
-
|
|
35
|
-
return <input ref={inputRef} className="date-picker" />;
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
One dependency, one wrapper component, two `useEffect` hooks, a cleanup function, and a CSS import, to pick a date.
|
|
40
|
-
|
|
41
|
-
## With Lexis
|
|
42
|
-
|
|
43
|
-
```html
|
|
44
|
-
<!-- lexis: browser has one -->
|
|
45
|
-
<input type="date">
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**1 dependency + 30 lines → 0 dependencies + 1 line.** Native, accessible, localized, keyboard-navigable, mobile-friendly. The browser team already did the work.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Email Validation
|
|
2
|
-
|
|
3
|
-
**Task:** "Validate an email address in Python."
|
|
4
|
-
|
|
5
|
-
## Without Lexis
|
|
6
|
-
|
|
7
|
-
```python
|
|
8
|
-
import re
|
|
9
|
-
|
|
10
|
-
EMAIL_PATTERN = re.compile(
|
|
11
|
-
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
class EmailValidator:
|
|
15
|
-
"""Validates email addresses against RFC-like rules."""
|
|
16
|
-
|
|
17
|
-
def __init__(self, pattern: re.Pattern = EMAIL_PATTERN):
|
|
18
|
-
self.pattern = pattern
|
|
19
|
-
|
|
20
|
-
def validate(self, email: str) -> bool:
|
|
21
|
-
if not isinstance(email, str):
|
|
22
|
-
raise TypeError("email must be a string")
|
|
23
|
-
email = email.strip()
|
|
24
|
-
if not email:
|
|
25
|
-
return False
|
|
26
|
-
return bool(self.pattern.match(email))
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def validate_email(email: str) -> bool:
|
|
30
|
-
"""Convenience wrapper around EmailValidator."""
|
|
31
|
-
return EmailValidator().validate(email)
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
A class, a wrapper, a regex that still rejects valid addresses and accepts invalid ones. Regex cannot validate email. Only a delivery attempt can.
|
|
35
|
-
|
|
36
|
-
## With Lexis
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
# lexis: good enough, real validation is sending the mail
|
|
40
|
-
"@" in email and "." in email.split("@")[-1]
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Or, if it must be thorough, the standard library has it:
|
|
44
|
-
|
|
45
|
-
```python
|
|
46
|
-
# lexis: stdlib covers this
|
|
47
|
-
from email.utils import parseaddr
|
|
48
|
-
"@" in parseaddr(email)[1]
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**27 lines → 1 line.** And the honest answer: let the confirmation email reject it. That's what confirmation emails are for.
|
package/examples/sorting.md
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Sorting
|
|
2
|
-
|
|
3
|
-
**Task:** "Sort this array of numbers."
|
|
4
|
-
|
|
5
|
-
## Without Lexis
|
|
6
|
-
|
|
7
|
-
```js
|
|
8
|
-
function quickSort(arr, compareFn = (a, b) => a - b) {
|
|
9
|
-
if (arr.length <= 1) return arr;
|
|
10
|
-
|
|
11
|
-
const pivot = arr[Math.floor(arr.length / 2)];
|
|
12
|
-
const left = [];
|
|
13
|
-
const right = [];
|
|
14
|
-
const equal = [];
|
|
15
|
-
|
|
16
|
-
for (const item of arr) {
|
|
17
|
-
const cmp = compareFn(item, pivot);
|
|
18
|
-
if (cmp < 0) left.push(item);
|
|
19
|
-
else if (cmp > 0) right.push(item);
|
|
20
|
-
else equal.push(item);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return [
|
|
24
|
-
...quickSort(left, compareFn),
|
|
25
|
-
...equal,
|
|
26
|
-
...quickSort(right, compareFn),
|
|
27
|
-
];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const sorted = quickSort(numbers);
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
A hand-rolled quicksort. It allocates three arrays per recursion level, blows the stack on large inputs, and replaces an engine-optimized native sort with homework.
|
|
34
|
-
|
|
35
|
-
## With Lexis
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
// lexis: this exists
|
|
39
|
-
numbers.sort((a, b) => a - b)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**24 lines → 1 line.** Every runtime ships a sort tuned by people whose whole job is sorting. Use it.
|
package/gemini-extension.json
DELETED
package/opencode.json
DELETED