@draig/lexis-two 1.0.2 → 1.0.3
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 +1 -1
- package/.claude-plugin/marketplace.json +0 -29
- package/.claude-plugin/plugin.json +0 -9
- package/.codex-plugin/plugin.json +0 -31
- 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/AUDIT.md +0 -74
- package/SPECXIS.md +0 -576
- 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/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/gemini-extension.json +0 -7
- 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
|
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/gemini-extension.json
DELETED
package/pi-extension/index.js
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
|
|
3
|
-
const require = createRequire(import.meta.url);
|
|
4
|
-
const {
|
|
5
|
-
DEFAULT_MODE,
|
|
6
|
-
getDefaultMode,
|
|
7
|
-
normalizeMode,
|
|
8
|
-
normalizeConfigMode,
|
|
9
|
-
normalizePersistedMode,
|
|
10
|
-
writeDefaultMode,
|
|
11
|
-
} = require("../hooks/lexis-two-config.js");
|
|
12
|
-
const { getLexisInstructions, filterSkillBodyForMode } = require("../hooks/lexis-two-instructions.js");
|
|
13
|
-
|
|
14
|
-
export { filterSkillBodyForMode };
|
|
15
|
-
export const readDefaultMode = getDefaultMode;
|
|
16
|
-
|
|
17
|
-
export function resolveSessionMode(entries, fallbackMode = DEFAULT_MODE) {
|
|
18
|
-
const fallback = normalizePersistedMode(fallbackMode) || DEFAULT_MODE;
|
|
19
|
-
if (!Array.isArray(entries)) return fallback;
|
|
20
|
-
|
|
21
|
-
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
22
|
-
const entry = entries[i];
|
|
23
|
-
if (entry?.type !== "custom" || entry?.customType !== "lexis-two-mode") continue;
|
|
24
|
-
|
|
25
|
-
const mode = normalizePersistedMode(entry?.data?.mode);
|
|
26
|
-
if (mode) return mode;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return fallback;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function parseLexisCommand(text, defaultMode = DEFAULT_MODE) {
|
|
33
|
-
const fallback = normalizePersistedMode(defaultMode) || DEFAULT_MODE;
|
|
34
|
-
const normalizedText = String(text || "").trim().toLowerCase();
|
|
35
|
-
|
|
36
|
-
if (!normalizedText) {
|
|
37
|
-
return { type: "set-mode", mode: fallback === "off" ? "full" : fallback };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const [primary, secondary] = normalizedText.split(/\s+/);
|
|
41
|
-
|
|
42
|
-
if (primary === "status") return { type: "status" };
|
|
43
|
-
|
|
44
|
-
if (primary === "default") {
|
|
45
|
-
const mode = normalizeConfigMode(secondary);
|
|
46
|
-
return mode ? { type: "set-default", mode } : { type: "invalid", reason: "invalid-default-mode" };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const mode = normalizeMode(primary);
|
|
50
|
-
return mode ? { type: "set-mode", mode } : { type: "invalid", reason: "invalid-mode", mode: primary };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export { writeDefaultMode };
|
|
54
|
-
|
|
55
|
-
export default function lexisExtension(pi) {
|
|
56
|
-
let currentMode = DEFAULT_MODE;
|
|
57
|
-
let configuredDefaultMode = getDefaultMode();
|
|
58
|
-
|
|
59
|
-
const setMode = (mode, ctx) => {
|
|
60
|
-
const normalized = normalizePersistedMode(mode);
|
|
61
|
-
if (!normalized) return;
|
|
62
|
-
|
|
63
|
-
currentMode = normalized;
|
|
64
|
-
pi.appendEntry("lexis-two-mode", { mode: normalized });
|
|
65
|
-
ctx?.ui?.notify?.(`Lexis-Two mode set to ${normalized}.`, "info");
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const sendAlias = (skillName, args, ctx) => {
|
|
69
|
-
const normalized = String(args || "").trim();
|
|
70
|
-
const message = normalized ? `${skillName} ${normalized}` : skillName;
|
|
71
|
-
|
|
72
|
-
if (ctx?.isIdle?.() === false) {
|
|
73
|
-
pi.sendUserMessage(message, { deliverAs: "followUp" });
|
|
74
|
-
ctx?.ui?.notify?.(`${skillName} queued as follow-up.`, "info");
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
pi.sendUserMessage(message);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
pi.registerCommand("lexis-two", {
|
|
82
|
-
description: "Set or report Lexis-Two mode",
|
|
83
|
-
handler: async (args, ctx) => {
|
|
84
|
-
const parsed = parseLexisCommand(args, configuredDefaultMode);
|
|
85
|
-
|
|
86
|
-
if (parsed.type === "status") {
|
|
87
|
-
ctx?.ui?.notify?.(`Lexis-Two: current ${currentMode} • default ${configuredDefaultMode}`, "info");
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (parsed.type === "set-default") {
|
|
92
|
-
const written = writeDefaultMode(parsed.mode);
|
|
93
|
-
if (written) {
|
|
94
|
-
configuredDefaultMode = getDefaultMode();
|
|
95
|
-
const message = configuredDefaultMode === written
|
|
96
|
-
? `Default Lexis-Two mode set to ${written}.`
|
|
97
|
-
: `Saved default ${written}, but env override keeps default at ${configuredDefaultMode}.`;
|
|
98
|
-
ctx?.ui?.notify?.(message, "info");
|
|
99
|
-
}
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (parsed.type === "set-mode") {
|
|
104
|
-
setMode(parsed.mode, ctx);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
ctx?.ui?.notify?.("Unknown or unsupported /lexis-two mode.", "warning");
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
pi.registerCommand("lexis-two-review", {
|
|
113
|
-
description: "Run /skill:lexis-two-review",
|
|
114
|
-
handler: (_args, ctx) => sendAlias("/skill:lexis-two-review", "", ctx),
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
pi.registerCommand("lexis-two-audit", {
|
|
118
|
-
description: "Run /skill:lexis-two-audit",
|
|
119
|
-
handler: (_args, ctx) => sendAlias("/skill:lexis-two-audit", "", ctx),
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
pi.registerCommand("lexis-two-debt", {
|
|
123
|
-
description: "Run /skill:lexis-two-debt",
|
|
124
|
-
handler: (_args, ctx) => sendAlias("/skill:lexis-two-debt", "", ctx),
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
pi.registerCommand("lexis-two-plan", {
|
|
128
|
-
description: "Run /skill:lexis-two-plan",
|
|
129
|
-
handler: (_args, ctx) => sendAlias("/skill:lexis-two-plan", "", ctx),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
pi.registerCommand("lexis-two-security", {
|
|
133
|
-
description: "Run /skill:lexis-two-security",
|
|
134
|
-
handler: (_args, ctx) => sendAlias("/skill:lexis-two-security", "", ctx),
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
pi.registerCommand("lexis-two-help", {
|
|
138
|
-
description: "Run /skill:lexis-two-help",
|
|
139
|
-
handler: (_args, ctx) => sendAlias("/skill:lexis-two-help", "", ctx),
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
pi.on("input", async (event) => {
|
|
143
|
-
if (event?.source === "extension") return;
|
|
144
|
-
|
|
145
|
-
const text = String(event?.text || "");
|
|
146
|
-
if (currentMode !== "off" && /\b(stop lexis|normal mode)\b/i.test(text)) {
|
|
147
|
-
setMode("off");
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
152
|
-
const entries = ctx?.sessionManager?.getBranch?.() || ctx?.sessionManager?.getEntries?.() || [];
|
|
153
|
-
configuredDefaultMode = getDefaultMode();
|
|
154
|
-
currentMode = resolveSessionMode(entries, configuredDefaultMode);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
pi.on("before_agent_start", async (event) => {
|
|
158
|
-
if (!currentMode || currentMode === "off") return;
|
|
159
|
-
return { systemPrompt: `${event.systemPrompt}\n\n${getLexisInstructions(currentMode)}` };
|
|
160
|
-
});
|
|
161
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import lexisExtension from "../index.js";
|
|
4
|
-
|
|
5
|
-
class MockPi {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.commands = {};
|
|
8
|
-
this.listeners = {};
|
|
9
|
-
this.entries = [];
|
|
10
|
-
this.userMessages = [];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
registerCommand(name, config) {
|
|
14
|
-
this.commands[name] = config;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
on(event, handler) {
|
|
18
|
-
this.listeners[event] = handler;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
appendEntry(type, data) {
|
|
22
|
-
this.entries.push({ type, data });
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
sendUserMessage(text, options) {
|
|
26
|
-
this.userMessages.push({ text, options });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
test("lexisExtension registers commands and listeners", () => {
|
|
31
|
-
const pi = new MockPi();
|
|
32
|
-
lexisExtension(pi);
|
|
33
|
-
|
|
34
|
-
assert.ok(pi.commands["lexis-two"]);
|
|
35
|
-
assert.ok(pi.commands["lexis-two-review"]);
|
|
36
|
-
assert.ok(pi.commands["lexis-two-audit"]);
|
|
37
|
-
assert.ok(pi.commands["lexis-two-debt"]);
|
|
38
|
-
assert.ok(pi.commands["lexis-two-plan"]);
|
|
39
|
-
assert.ok(pi.commands["lexis-two-security"]);
|
|
40
|
-
assert.ok(pi.commands["lexis-two-help"]);
|
|
41
|
-
|
|
42
|
-
assert.ok(pi.listeners["input"]);
|
|
43
|
-
assert.ok(pi.listeners["session_start"]);
|
|
44
|
-
assert.ok(pi.listeners["before_agent_start"]);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("lexisExtension command handlers trigger correctly", async () => {
|
|
48
|
-
const pi = new MockPi();
|
|
49
|
-
lexisExtension(pi);
|
|
50
|
-
|
|
51
|
-
let notified = null;
|
|
52
|
-
const ctx = {
|
|
53
|
-
ui: {
|
|
54
|
-
notify: (msg, type) => {
|
|
55
|
-
notified = { msg, type };
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
await pi.commands["lexis-two"].handler("lite", ctx);
|
|
61
|
-
assert.equal(pi.entries[0].type, "lexis-two-mode");
|
|
62
|
-
assert.equal(pi.entries[0].data.mode, "lite");
|
|
63
|
-
assert.equal(notified.msg, "Lexis-Two mode set to lite.");
|
|
64
|
-
|
|
65
|
-
pi.commands["lexis-two-review"].handler("", ctx);
|
|
66
|
-
assert.equal(pi.userMessages[0].text, "/skill:lexis-two-review");
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("lexisExtension input listener detects deactivation", async () => {
|
|
70
|
-
const pi = new MockPi();
|
|
71
|
-
lexisExtension(pi);
|
|
72
|
-
|
|
73
|
-
let notified = null;
|
|
74
|
-
const ctx = {
|
|
75
|
-
ui: {
|
|
76
|
-
notify: (msg, type) => {
|
|
77
|
-
notified = { msg, type };
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
// Set mode to full first
|
|
83
|
-
await pi.commands["lexis-two"].handler("full", ctx);
|
|
84
|
-
assert.equal(pi.entries[0].data.mode, "full");
|
|
85
|
-
|
|
86
|
-
// Send input "stop lexis"
|
|
87
|
-
await pi.listeners["input"]({ text: "Please stop lexis now" });
|
|
88
|
-
assert.equal(pi.entries[1].data.mode, "off");
|
|
89
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { resolveSessionMode, parseLexisCommand } from "../index.js";
|
|
4
|
-
|
|
5
|
-
test("resolveSessionMode resolves mode from branch entries", () => {
|
|
6
|
-
const entries = [
|
|
7
|
-
{ type: "user-message", text: "hello" },
|
|
8
|
-
{ type: "custom", customType: "lexis-two-mode", data: { mode: "lite" } },
|
|
9
|
-
{ type: "assistant-message", text: "world" },
|
|
10
|
-
];
|
|
11
|
-
assert.equal(resolveSessionMode(entries, "full"), "lite");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test("resolveSessionMode falls back to default mode if no entries", () => {
|
|
15
|
-
assert.equal(resolveSessionMode([], "lite"), "lite");
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test("parseLexisCommand parses empty command as default toggle", () => {
|
|
19
|
-
assert.deepEqual(parseLexisCommand("", "full"), { type: "set-mode", mode: "full" });
|
|
20
|
-
assert.deepEqual(parseLexisCommand(" ", "off"), { type: "set-mode", mode: "full" });
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test("parseLexisCommand parses status command", () => {
|
|
24
|
-
assert.deepEqual(parseLexisCommand("status"), { type: "status" });
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("parseLexisCommand parses default command", () => {
|
|
28
|
-
assert.deepEqual(parseLexisCommand("default lite"), { type: "set-default", mode: "lite" });
|
|
29
|
-
assert.deepEqual(parseLexisCommand("default invalid"), { type: "invalid", reason: "invalid-default-mode" });
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("parseLexisCommand parses mode command", () => {
|
|
33
|
-
assert.deepEqual(parseLexisCommand("ultra"), { type: "set-mode", mode: "ultra" });
|
|
34
|
-
assert.deepEqual(parseLexisCommand("invalid"), { type: "invalid", reason: "invalid-mode", mode: "invalid" });
|
|
35
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// lexis-two — rule copy integrity check
|
|
3
|
-
//
|
|
4
|
-
// To avoid runtime overhead, instruction-tier hosts (Windsurf, Cline, Kiro,
|
|
5
|
-
// Cursor) load static copies of the rules. This script acts as a build/CI guard
|
|
6
|
-
// to ensure those copies never drift from the canonical source (AGENTS.md).
|
|
7
|
-
//
|
|
8
|
-
// It asserts that:
|
|
9
|
-
// 1. Every rule copy file exists.
|
|
10
|
-
// 2. Every copy is completely identical to AGENTS.md (ignoring host-specific frontmatter).
|
|
11
|
-
// 3. The canonical AGENTS.md itself contains the load-bearing Lexis-Two rules.
|
|
12
|
-
|
|
13
|
-
const fs = require('fs');
|
|
14
|
-
const path = require('path');
|
|
15
|
-
|
|
16
|
-
const root = path.join(__dirname, '..');
|
|
17
|
-
|
|
18
|
-
// Canonical source of truth
|
|
19
|
-
const SOURCE_FILE = 'AGENTS.md';
|
|
20
|
-
|
|
21
|
-
// Static copies to validate
|
|
22
|
-
const COPIES = [
|
|
23
|
-
'.windsurf/rules/lexis-two.md',
|
|
24
|
-
'.clinerules/lexis-two.md',
|
|
25
|
-
'.kiro/steering/lexis-two.md',
|
|
26
|
-
'.cursor/rules/lexis-two.mdc',
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
// Load-bearing phrases that MUST exist in the source of truth. If these are
|
|
30
|
-
// missing, the source file has been gutted, and the copies are validating
|
|
31
|
-
// against an empty shell.
|
|
32
|
-
const INVARIANTS = [
|
|
33
|
-
'lazy senior',
|
|
34
|
-
'Input validation at trust boundaries',
|
|
35
|
-
'YAGNI',
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
function read(relPath) {
|
|
39
|
-
try {
|
|
40
|
-
return fs.readFileSync(path.join(root, relPath), 'utf8');
|
|
41
|
-
} catch (e) {
|
|
42
|
-
console.error(`Error: failed to read ${relPath}`);
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 1. Validate canonical source
|
|
48
|
-
const source = read(SOURCE_FILE);
|
|
49
|
-
for (const phrase of INVARIANTS) {
|
|
50
|
-
if (!source.includes(phrase)) {
|
|
51
|
-
console.error(`Error: canonical source (${SOURCE_FILE}) is missing load-bearing rule: "${phrase}"`);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Helper to strip frontmatter (metadata blocks between '---' at start of file)
|
|
57
|
-
function stripFrontmatter(content) {
|
|
58
|
-
return content.replace(/^---[\s\S]*?---\s*/, '');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// 2. Validate copies
|
|
62
|
-
let failed = false;
|
|
63
|
-
const canonicalBody = stripFrontmatter(source).trim();
|
|
64
|
-
|
|
65
|
-
for (const copyPath of COPIES) {
|
|
66
|
-
const copyContent = read(copyPath);
|
|
67
|
-
const copyBody = stripFrontmatter(copyContent).trim();
|
|
68
|
-
|
|
69
|
-
if (copyBody !== canonicalBody) {
|
|
70
|
-
console.error(`Drift detected: ${copyPath} does not match ${SOURCE_FILE}`);
|
|
71
|
-
failed = true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (failed) {
|
|
76
|
-
console.error('\nIntegrity check FAILED. Rule copies have drifted from AGENTS.md.');
|
|
77
|
-
console.error('To fix, copy AGENTS.md content into the drifted files, preserving their frontmatter if any.');
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
console.log('Rule copy integrity check PASSED.');
|
|
82
|
-
process.exit(0);
|
package/site/astro.config.mjs
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "astro/config";
|
|
2
|
-
import sitemap from "@astrojs/sitemap";
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
site: "https://lexis-two.excelso.xyz",
|
|
6
|
-
output: "static",
|
|
7
|
-
i18n: {
|
|
8
|
-
defaultLocale: "en",
|
|
9
|
-
locales: ["en", "es"],
|
|
10
|
-
routing: {
|
|
11
|
-
prefixDefaultLocale: false,
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
build: {
|
|
15
|
-
format: "directory",
|
|
16
|
-
},
|
|
17
|
-
integrations: [sitemap()],
|
|
18
|
-
});
|