@fringetools/cli 0.1.1 → 0.1.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/README.md +2 -2
- package/dist/bin.js +1 -1
- package/dist/{chunk-W23H5MXS.js → chunk-MOTRTP2I.js} +10 -7
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skill/fringe-debt/SKILL.md +17 -0
- package/skill/fringe-help/SKILL.md +33 -0
- /package/skill/{SKILL.md → fringe/SKILL.md} +0 -0
- /package/skill/{audit.md → fringe-audit/SKILL.md} +0 -0
- /package/skill/{review.md → fringe-review/SKILL.md} +0 -0
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Prefer a permanent command? `npm install -D @fringetools/cli`, then `npx fringe
|
|
|
27
27
|
| `fringe check --hook` | One-line `fringe/hook.v1` JSON for CI / pre-commit. Exits `1` on errors. Claude Code does **not** feed this back — use `--claude-hook` for agents. Wins over `--json`. |
|
|
28
28
|
| `fringe check --update-baseline` | Accept today's findings into `fringe.baseline.json` (commit it). Exit `0`. |
|
|
29
29
|
| `fringe check --record [--manifest <path>]` | Also append this run to `.fringe/ledger.jsonl`, optionally merging an agent flow manifest. |
|
|
30
|
-
| `fringe init [path]` | Add the Claude Code hook and install the
|
|
30
|
+
| `fringe init [path]` | Add the Claude Code hook and install the five skills. Safe to re-run; refuses to touch an invalid `settings.json`. |
|
|
31
31
|
| `fringe open [path] [--port <n>]` | Serve the ledger as a plain HTML page on `127.0.0.1:4173` (loopback only). Ctrl+C to stop. |
|
|
32
32
|
| `fringe --help` · `--version` | Usage / version. |
|
|
33
33
|
|
|
@@ -101,7 +101,7 @@ After each edit the hook runs; with errors it returns, for example:
|
|
|
101
101
|
|
|
102
102
|
This was verified end to end with real agent runs: the agent receives the findings and fixes them (see [docs/architecture.md](../../docs/architecture.md)). Why `--claude-hook` and not `--hook`: Claude Code only passes a hook's output to the agent as `decision`/`reason` JSON on exit 0 (or stderr on exit 2); the CI contract `--hook` exits 1 and is ignored.
|
|
103
103
|
|
|
104
|
-
**Skills** — `fringe init` installs
|
|
104
|
+
**Skills** — `fringe init` installs five into `.claude/skills/` (sources in [skill/](skill/), one folder each); the Claude Code plugin ships the same folders, namespaced `/fringe:…`: `fringe` (below), `fringe-review` ("review this page": ranked, plain-English findings with fixes), `fringe-audit` (whole-repo plan: top rules and files, a fix order, offers `--update-baseline`), `fringe-debt` (lists `fringe-ignore` suppressions and the baseline) and `fringe-help` (quick reference). Invoke as `/fringe-review` etc. Reviews run `fringe check`, so Claude Code will ask you to approve that command once (or allow `Bash(fringe:*)` / `Bash(npx:*)`).
|
|
105
105
|
|
|
106
106
|
**The main skill** (`.claude/skills/fringe/SKILL.md`) teaches the agent the ladder: *Flow* (cut what users don't need, with evidence in `.fringe/manifest.json`) → *Edges* (fix every hook finding, never silence a rule to get green) → *Polish* (tokens, scales, no AI look), then record the run. It is plain Markdown, so any agent platform that reads `AGENTS.md`/skill files can use it as-is.
|
|
107
107
|
|
package/dist/bin.js
CHANGED
|
@@ -4,7 +4,7 @@ import { readFileSync as readFileSync8 } from "fs";
|
|
|
4
4
|
import { resolve } from "path";
|
|
5
5
|
|
|
6
6
|
// src/version.ts
|
|
7
|
-
var VERSION = "0.1.
|
|
7
|
+
var VERSION = "0.1.3";
|
|
8
8
|
|
|
9
9
|
// src/check.ts
|
|
10
10
|
import { readFileSync as readFileSync5 } from "fs";
|
|
@@ -293,7 +293,11 @@ var fr206 = {
|
|
|
293
293
|
severity: "error",
|
|
294
294
|
check: (ctx) => {
|
|
295
295
|
const out = [];
|
|
296
|
-
|
|
296
|
+
const isBackdrop = (i) => {
|
|
297
|
+
const next = ctx.elems[i + 1], me = ctx.elems[i];
|
|
298
|
+
return !!next && next.parentTag === me.tag && next.loc.line >= me.loc.line && (/^(alert)?dialog$/.test(next.attrs.role ?? "") || next.attrs["aria-modal"] === "true");
|
|
299
|
+
};
|
|
300
|
+
for (const e of ctx.elems.filter((el, i) => ["div", "span"].includes(el.tag) && (el.attrs.onClick ?? el.attrs.onclick) !== void 0 && el.attrs.role === void 0 && (el.attrs.tabIndex ?? el.attrs.tabindex) === void 0 && !isBackdrop(i))) {
|
|
297
301
|
out.push({ rule: "FR-206", severity: "error", message: `onClick on non-interactive <${e.tag}>`, hint: `use a <button>/<a> or add role and tabIndex`, loc: e.loc, wcag: "2.1.1" });
|
|
298
302
|
}
|
|
299
303
|
return out;
|
|
@@ -1186,12 +1190,11 @@ function startBoard(root, port) {
|
|
|
1186
1190
|
}
|
|
1187
1191
|
|
|
1188
1192
|
// src/init.ts
|
|
1189
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync2, copyFileSync } from "fs";
|
|
1193
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync7, readdirSync as readdirSync3, writeFileSync as writeFileSync2, copyFileSync } from "fs";
|
|
1190
1194
|
import { dirname, join as join7 } from "path";
|
|
1191
1195
|
import { fileURLToPath } from "url";
|
|
1192
1196
|
var HOOK = "npx -y @fringetools/cli check --claude-hook";
|
|
1193
|
-
var
|
|
1194
|
-
var skillSrc = (file) => fileURLToPath(new URL(`../skill/${file}`, import.meta.url));
|
|
1197
|
+
var SKILL_DIR = fileURLToPath(new URL("../skill/", import.meta.url));
|
|
1195
1198
|
function initProject(root) {
|
|
1196
1199
|
const done = [];
|
|
1197
1200
|
const settingsPath = join7(root, ".claude", "settings.json");
|
|
@@ -1211,12 +1214,12 @@ function initProject(root) {
|
|
|
1211
1214
|
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1212
1215
|
done.push(`hook added to ${settingsPath}`);
|
|
1213
1216
|
}
|
|
1214
|
-
for (const
|
|
1217
|
+
for (const name of readdirSync3(SKILL_DIR)) {
|
|
1215
1218
|
const skillPath = join7(root, ".claude", "skills", name, "SKILL.md");
|
|
1216
1219
|
if (existsSync2(skillPath)) done.push(`skill ${name} already present`);
|
|
1217
1220
|
else {
|
|
1218
1221
|
mkdirSync2(dirname(skillPath), { recursive: true });
|
|
1219
|
-
copyFileSync(
|
|
1222
|
+
copyFileSync(join7(SKILL_DIR, name, "SKILL.md"), skillPath);
|
|
1220
1223
|
done.push(`skill ${name} installed`);
|
|
1221
1224
|
}
|
|
1222
1225
|
}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fringe-debt
|
|
3
|
+
description: Use when the user asks what Fringe findings have been silenced or deferred ("fringe debt", "what did we suppress", "what's in the baseline", /fringe-debt). One-shot report of suppressions and the baseline; changes nothing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fringe debt
|
|
7
|
+
|
|
8
|
+
Fringe has two ways to defer a finding: an inline `fringe-ignore` comment and the `fringe.baseline.json` file. This lists both so a deferral can't quietly become permanent.
|
|
9
|
+
|
|
10
|
+
Command: use `fringe` if it is on the PATH, otherwise `npx -y @fringetools/cli` in its place.
|
|
11
|
+
|
|
12
|
+
1. **Inline suppressions.** `git grep --no-index --exclude-standard -nE 'fringe-ignore +FR-[0-9]+'`. One row per hit: `<file>:<line>, <rule> — <why, if the comment or nearby code says>`. Skip hits that are only prose mentioning the convention.
|
|
13
|
+
2. **Baseline.** If `fringe.baseline.json` exists, count entries per rule (each entry is `rule|file|message`) and list the files with the most. If it is missing, say there is no baseline.
|
|
14
|
+
3. **Today's picture.** Run `fringe check --json .` and report the current counts by severity next to the baseline total, so the user sees whether the debt is shrinking.
|
|
15
|
+
4. Close with the single most valuable thing to pay down first (usually the rule with the most baselined entries that has a mechanical fix) and the command to shrink the baseline afterwards: `fringe check --update-baseline`.
|
|
16
|
+
|
|
17
|
+
Change nothing. Do not run `--update-baseline` unless the user asks.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fringe-help
|
|
3
|
+
description: Use when the user asks what Fringe can do or how to use it ("fringe help", "what commands does fringe have", /fringe-help). Quick reference; changes nothing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fringe help
|
|
7
|
+
|
|
8
|
+
Fringe checks agent-written frontends for accessibility, state, dark-pattern and "AI look" problems, gates the hard failures, and keeps a local history.
|
|
9
|
+
|
|
10
|
+
**Skills**
|
|
11
|
+
|
|
12
|
+
| Skill | Use it to |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `fringe` | The working rules: cut what users don't need, fix every hook finding, polish, record |
|
|
15
|
+
| `/fringe-review` | Review a page or component: ranked findings with plain-English fixes |
|
|
16
|
+
| `/fringe-audit` | Audit the whole repo: top rules and files, a fix order, offer a baseline |
|
|
17
|
+
| `/fringe-debt` | List silenced findings (`fringe-ignore`, baseline) |
|
|
18
|
+
| `/fringe-help` | This reference |
|
|
19
|
+
|
|
20
|
+
**Commands** (`fringe`, or `npx -y @fringetools/cli`)
|
|
21
|
+
|
|
22
|
+
| Command | What it does |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `check [dir]` | Scan and print findings and the health score; exit 1 on any error |
|
|
25
|
+
| `check --json` / `--hook` / `--claude-hook` | Machine output; CI gate; agent feedback form |
|
|
26
|
+
| `check --update-baseline` | Accept today's findings; only new ones gate |
|
|
27
|
+
| `check --record [--manifest f]` | Append the run to `.fringe/ledger.jsonl` |
|
|
28
|
+
| `init` | Add the hook and install the skills |
|
|
29
|
+
| `open` | View the ledger at 127.0.0.1:4173 |
|
|
30
|
+
|
|
31
|
+
**Escape hatch:** `// fringe-ignore FR-203` on or above the line, for a real false positive only; every run reports `N suppressed`.
|
|
32
|
+
|
|
33
|
+
Full reference: https://github.com/skc-learn/fringe/blob/main/packages/cli/README.md
|
|
File without changes
|
|
File without changes
|
|
File without changes
|