create-issflow 1.9.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/cli.js +2 -2
- package/package.json +1 -1
- package/template/.issflow/README.md +1 -1
- package/template/.issflow/commands/design.md +12 -6
- package/template/.issflow/commands/phase.md +2 -0
- package/template/.issflow/hooks/approval-policy.js +78 -0
- package/template/.issflow/hooks/plan-gate.js +49 -56
- package/template/.issflow/hooks/verify-approval.js +43 -0
- package/template/.issflow/istartsoft-flow/METHODOLOGY.md +53 -5
- package/template/.issflow/skills/ui-ux-pro-max/LICENSE.upstream +21 -0
- package/template/.issflow/skills/ui-ux-pro-max/SKILL.md +70 -0
- package/template/.issflow/skills/ui-ux-pro-max/UPSTREAM.md +4 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/app-interface.csv +33 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/catalog-summary.json +78 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/colors.csv +193 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/data-provenance.json +1348 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/google-fonts.csv +1935 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/icons.csv +106 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/landing.csv +35 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/motion.csv +18 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/products.csv +193 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/angular.csv +51 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/avalonia.csv +57 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +60 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/javafx.csv +76 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/laravel.csv +51 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/nextjs.csv +62 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +77 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +68 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/react.csv +67 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/shadcn.csv +69 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/svelte.csv +56 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/threejs.csv +54 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/uno.csv +60 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/uwp.csv +56 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/winui.csv +60 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/stacks/wpf.csv +57 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/styles.csv +89 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/typography.csv +75 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/ui-reasoning.csv +193 -0
- package/template/.issflow/skills/ui-ux-pro-max/data/ux-guidelines.csv +120 -0
- package/template/.issflow/skills/ui-ux-pro-max/references/pro-rules.md +117 -0
- package/template/.issflow/skills/ui-ux-pro-max/references/quick-reference.md +256 -0
- package/template/.issflow/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/template/.issflow/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/template/.issflow/skills/ui-ux-pro-max/scripts/__pycache__/reasoning_contract.cpython-313.pyc +0 -0
- package/template/.issflow/skills/ui-ux-pro-max/scripts/core.py +993 -0
- package/template/.issflow/skills/ui-ux-pro-max/scripts/design_system.py +1668 -0
- package/template/.issflow/skills/ui-ux-pro-max/scripts/reasoning_contract.py +123 -0
- package/template/.issflow/skills/ui-ux-pro-max/scripts/search.py +177 -0
- package/template/.issflow/skills/ux-design/SKILL.md +3 -0
- package/template/.issflow/templates/PLAN-SCOPED.md +36 -0
- package/template/.issflow/templates/UX-PACK-template.md +1 -0
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ The portable kit (every tool) in `<project>/.issflow/`:
|
|
|
32
32
|
|
|
33
33
|
- `agents/` — planner · researcher · implementer · test-author · debugger · e2e-runner · synthesizer
|
|
34
34
|
- `commands/` — `/overview` `/feature` `/goal` `/propose` `/phase` `/sprint` `/ui-audit` `/qa-audit` `/security-audit` `/release` `/uat` `/change-request` `/replan` `/quick` `/synthesize` `/runbook` `/store-wisdom` `/log-issue` `/log-decision` `/unstuck`
|
|
35
|
-
- `skills/` — caveman · grill-me · karpathy-guidelines · ux-design · security · code-standards
|
|
35
|
+
- `skills/` — caveman · grill-me · karpathy-guidelines · ux-design · ui-ux-pro-max · security · code-standards
|
|
36
36
|
- `hooks/` — session-start · context-guard · plan-gate (rule-13 enforcement) · pre-compact · subagent-stop · feature-gate (Stop gate for `/feature`, artifact-verified)
|
|
37
37
|
- `istartsoft-flow/METHODOLOGY.md` — the full methodology (single source of truth)
|
|
38
38
|
|
package/bin/cli.js
CHANGED
|
@@ -227,8 +227,8 @@ function agentsMd() {
|
|
|
227
227
|
'`/change-request` · `/replan` · `/synthesize` · `/runbook` · `/store-wisdom` ·',
|
|
228
228
|
'`/log-issue` · `/log-decision` · `/unstuck`', '',
|
|
229
229
|
'## Skills — `.issflow/skills/` (loaded on demand)', '',
|
|
230
|
-
'caveman · grill-me · karpathy-guidelines · ux-design ·
|
|
231
|
-
'support-triage', '',
|
|
230
|
+
'caveman · grill-me · karpathy-guidelines · ux-design · ui-ux-pro-max · security ·',
|
|
231
|
+
'code-standards · support-triage', '',
|
|
232
232
|
'## Autonomy', '',
|
|
233
233
|
'Planning (`/overview` grill + plan approval) always asks — that input is cheap.',
|
|
234
234
|
'**AUTO (default)** governs the DEV loop: follow the plan, decide + log + continue,',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-issflow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Scaffold the iStartSoftFlow AI-coding workflow into a project. Stack-agnostic, tool-agnostic (Claude Code, Codex, Cursor, Gemini, Aider), non-destructive.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-issflow": "bin/cli.js"
|
|
@@ -14,7 +14,7 @@ This directory is the **portable workflow kit** (tool-agnostic). Every
|
|
|
14
14
|
|------|------|
|
|
15
15
|
| `agents/` | Fresh-context workers (planner, researcher, implementer, …) |
|
|
16
16
|
| `commands/` | Procedures — Default: `/overview` `/feature` `/quick`; Advanced: `/propose` `/design` `/support` … |
|
|
17
|
-
| `skills/` | On-demand cookbooks (ux-design, security, support-triage, …) |
|
|
17
|
+
| `skills/` | On-demand cookbooks (ux-design, ui-ux-pro-max, security, support-triage, …) |
|
|
18
18
|
| `hooks/` | Lifecycle enforcement scripts |
|
|
19
19
|
| `istartsoft-flow/` | METHODOLOGY.md — every hard rule lives here once |
|
|
20
20
|
| `templates/` | Proposal / UX pack / architecture / CR / FEATURE / automation |
|
|
@@ -24,13 +24,19 @@ and STOP. Write nothing.
|
|
|
24
24
|
Target: `$ARGUMENTS` → `ux` | `arch` | `both` (default **both**).
|
|
25
25
|
|
|
26
26
|
## STEP 1 — UX PACK (if ux|both)
|
|
27
|
-
1. Apply `ux-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
1. Apply `ui-ux-pro-max` (visual direction): run the kit engine
|
|
28
|
+
`.issflow/skills/ui-ux-pro-max/scripts/search.py --design-system` from
|
|
29
|
+
OVERVIEW product + industry. Fold into UX-PACK tokens — do not create a
|
|
30
|
+
parallel `design-system/` SoT. If Python 3 is missing, ask me to install it
|
|
31
|
+
(do not install tools yourself).
|
|
32
|
+
2. Apply `ux-design` skill (authoring mode): wireframe baseline + cookbook direction.
|
|
33
|
+
Catalogue output must still pass the cookbook (tokens, a11y, no emoji icons).
|
|
34
|
+
3. Scaffold or update `docs/UX-PACK.md` from `.issflow/templates/UX-PACK-template.md`.
|
|
35
|
+
4. Fill flows, screen inventory, tokens/frame, a11y notes from OVERVIEW + PLAN.
|
|
36
|
+
5. SHOW me UX-PACK.md. **STOP for approval.**
|
|
37
|
+
6. On approve: stamp `> Approval: approved <date> v<n>`; set `design: approved <date>`
|
|
32
38
|
in STATE.md; HISTORY line `design v<n> approved`.
|
|
33
|
-
|
|
39
|
+
7. On change request: revise and re-show; header stays PENDING.
|
|
34
40
|
|
|
35
41
|
## STEP 2 — ARCHITECTURE (if arch|both)
|
|
36
42
|
1. Dispatch `researcher` (DESIGN) only if open unknowns remain; else use OVERVIEW.
|
|
@@ -119,6 +119,8 @@ for the slice using the declared E2E runner (it brings the test stack up/down
|
|
|
119
119
|
itself). Then run the `ux-design` cookbook + wireframe check on the new UI
|
|
120
120
|
(hard rule 9): the UI must match the wireframe frame and pass the cookbook
|
|
121
121
|
(tokens, a11y/WCAG AA, states, breakpoints). A `ux-design` BLOCK is a GATE FAIL.
|
|
122
|
+
Do not re-run `ui-ux-pro-max` `--design-system` here — the look is locked in the
|
|
123
|
+
approved UX pack.
|
|
122
124
|
Non-frontend phase -> skip §3c.
|
|
123
125
|
|
|
124
126
|
PHASE GATE (rule 5) -> go to §4/§5/§6 (see GATE below).
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
function fail(message) {
|
|
8
|
+
return { ok: false, reason: message };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function within(root, relative) {
|
|
12
|
+
if (!relative || path.isAbsolute(relative)) return false;
|
|
13
|
+
const full = path.resolve(root, relative);
|
|
14
|
+
return full.startsWith(path.resolve(root) + path.sep);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function read(root, relative) {
|
|
18
|
+
if (!within(root, relative)) throw new Error('Path escapes repository');
|
|
19
|
+
return fs.readFileSync(path.join(root, relative), 'utf8');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function gitBlobSha(content) {
|
|
23
|
+
const bytes = Buffer.from(content, 'utf8');
|
|
24
|
+
return crypto.createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function activePlan(root, explicit) {
|
|
28
|
+
if (explicit) return explicit.replaceAll('\\', '/');
|
|
29
|
+
const pointer = path.join(root, 'docs', 'ACTIVE-PLAN');
|
|
30
|
+
if (fs.existsSync(pointer)) return fs.readFileSync(pointer, 'utf8').trim();
|
|
31
|
+
const plansDir = path.join(root, 'docs', 'plans');
|
|
32
|
+
if (fs.existsSync(plansDir) && fs.readdirSync(plansDir).some((name) => /^PLAN-.*\.md$/i.test(name))) {
|
|
33
|
+
throw new Error('docs/ACTIVE-PLAN is required when scoped plans exist');
|
|
34
|
+
}
|
|
35
|
+
return 'docs/PLAN.md'; // Legacy projects remain supported.
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function matchesPath(pattern, relative) {
|
|
39
|
+
if (pattern.endsWith('/**')) return relative.startsWith(pattern.slice(0, -2));
|
|
40
|
+
return relative === pattern;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function validate(root, { planFile, changedFiles = [] } = {}) {
|
|
44
|
+
try {
|
|
45
|
+
const relativePlan = activePlan(root, planFile);
|
|
46
|
+
if (!within(root, relativePlan)) return fail('Invalid plan path');
|
|
47
|
+
const plan = read(root, relativePlan);
|
|
48
|
+
if (relativePlan === 'docs/PLAN.md') {
|
|
49
|
+
const match = plan.match(/^>\s*Approval:\s*(.+)$/mi);
|
|
50
|
+
if (!match || !/^approved\b/i.test(match[1].trim())) return fail('Legacy PLAN.md is not approved');
|
|
51
|
+
return { ok: true, mode: 'legacy', planFile: relativePlan, warning: 'Legacy approval is not revision-scoped; migrate to docs/plans/' };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const id = plan.match(/^#\s+(PLAN-[A-Za-z0-9-]+)\b/m)?.[1];
|
|
55
|
+
const revision = Number(plan.match(/^>\s*Revision:\s*(\d+)\s*$/mi)?.[1]);
|
|
56
|
+
if (!id || !Number.isSafeInteger(revision) || revision < 1) return fail('Plan ID or revision missing');
|
|
57
|
+
const approvalFile = `docs/approvals/${id}.json`;
|
|
58
|
+
const approval = JSON.parse(read(root, approvalFile));
|
|
59
|
+
if (approval.planId !== id || approval.revision !== revision) return fail('Approval is for a different plan ID or revision');
|
|
60
|
+
if (approval.planBlobSha !== gitBlobSha(plan)) return fail('Plan changed after approval; request a new approval');
|
|
61
|
+
if (!approval.approvedBy || !approval.approvedAt || !approval.approvalSource) return fail('Approval provenance is incomplete');
|
|
62
|
+
if (!Array.isArray(approval.allowedPaths) || approval.allowedPaths.length === 0 ||
|
|
63
|
+
!approval.allowedPaths.every((p) => typeof p === 'string' && p.length > 0 && !p.includes('..') && !p.startsWith('/'))) {
|
|
64
|
+
return fail('Approved path boundaries are missing or invalid');
|
|
65
|
+
}
|
|
66
|
+
for (const file of changedFiles) {
|
|
67
|
+
const normalized = file.replaceAll('\\', '/');
|
|
68
|
+
if (!within(root, normalized) || !approval.allowedPaths.some((p) => matchesPath(p, normalized))) {
|
|
69
|
+
return fail(`File outside approved plan scope: ${file}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { ok: true, mode: 'scoped', planFile: relativePlan, planId: id, revision, approval };
|
|
73
|
+
} catch (error) {
|
|
74
|
+
return fail(`Approval verification failed: ${error.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = { validate, gitBlobSha, activePlan, matchesPath };
|
|
@@ -1,64 +1,57 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// PreToolUse plan gate — hard rule 13 as code. While docs/PLAN.md carries
|
|
3
|
-
// `> Approval: PENDING`, no SOURCE file may be created or edited: the plan
|
|
4
|
-
// needs a human sign-off before build work starts. Docs, kit config, and
|
|
5
|
-
// planning artifacts stay writable (planning is exactly what PENDING is for).
|
|
6
|
-
// An active feature lane is exempt — its doc approval is its own rule-13-scoped
|
|
7
|
-
// gate and it never touches the main PLAN. Fail-OPEN on any error: a hook bug
|
|
8
|
-
// must never wedge the tool loop. Pure Node, cross-platform, zero deps.
|
|
9
2
|
'use strict';
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const path = require('path');
|
|
12
3
|
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason },
|
|
17
|
-
}));
|
|
18
|
-
process.exit(0);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
let input = '';
|
|
22
|
-
process.stdin.setEncoding('utf8');
|
|
23
|
-
process.stdin.on('data', (d) => (input += d));
|
|
24
|
-
process.stdin.on('end', () => {
|
|
25
|
-
let evt;
|
|
26
|
-
try { evt = JSON.parse(input); } catch (_) { return silent(); }
|
|
27
|
-
try { run(evt); } catch (_) { silent(); }
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
function run(evt) {
|
|
31
|
-
const MUTATORS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
|
|
32
|
-
if (!MUTATORS.has(evt.tool_name || '')) return silent();
|
|
33
|
-
|
|
34
|
-
const projectDir = process.env.CLAUDE_PROJECT_DIR || evt.cwd || '.';
|
|
35
|
-
const read = (f) => { try { return fs.readFileSync(path.join(projectDir, f), 'utf8'); } catch (_) { return null; } };
|
|
36
|
-
|
|
37
|
-
const plan = read(path.join('docs', 'PLAN.md'));
|
|
38
|
-
if (!plan) return silent(); // no plan world (e.g. /quick-only repo)
|
|
39
|
-
const approval = plan.match(/^>\s*Approval:\s*(.+)$/m);
|
|
40
|
-
if (!approval) return silent(); // not our PLAN format — don't guess
|
|
41
|
-
if (!/pending/i.test(approval[1])) return silent(); // signed off — build away
|
|
4
|
+
// Claude PreToolUse guard. Shell commands and other hosts require the CLI/CI verifier.
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { validate } = require('./approval-policy');
|
|
42
7
|
|
|
43
|
-
|
|
44
|
-
const state = read(path.join('docs', 'STATE.md')) || '';
|
|
45
|
-
if (/^\s*feature:\s*\S+\s*\(active\)/m.test(state)) return silent();
|
|
8
|
+
const MUTATORS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
|
|
46
9
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
10
|
+
function deny(reason) {
|
|
11
|
+
process.stdout.write(JSON.stringify({
|
|
12
|
+
hookSpecificOutput: {
|
|
13
|
+
hookEventName: 'PreToolUse',
|
|
14
|
+
permissionDecision: 'deny',
|
|
15
|
+
permissionDecisionReason: reason,
|
|
16
|
+
},
|
|
17
|
+
}) + '\n');
|
|
18
|
+
}
|
|
50
19
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
/^docs
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (ALLOW.some((re) => re.test(rel))) return silent();
|
|
20
|
+
function safePlanningPath(relative) {
|
|
21
|
+
return /^docs\/plans\/PLAN-[\w-]+\.md$/.test(relative) ||
|
|
22
|
+
/^docs\/features\/[\w.-]+\/(PLAN|FEATURE)\.md$/.test(relative) ||
|
|
23
|
+
relative === 'docs/ACTIVE-PLAN';
|
|
24
|
+
}
|
|
57
25
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
26
|
+
function run(event) {
|
|
27
|
+
if (!MUTATORS.has(event.tool_name)) return;
|
|
28
|
+
const root = path.resolve(process.env.CLAUDE_PROJECT_DIR || event.cwd || process.cwd());
|
|
29
|
+
const input = event.tool_input || {};
|
|
30
|
+
const paths = event.tool_name === 'MultiEdit'
|
|
31
|
+
? [input.file_path]
|
|
32
|
+
: [input.file_path || input.notebook_path];
|
|
33
|
+
if (paths.some((p) => typeof p !== 'string' || !p.trim())) {
|
|
34
|
+
return deny('Approval gate cannot determine target path');
|
|
35
|
+
}
|
|
36
|
+
const relative = paths.map((p) => path.relative(root, path.resolve(root, p)).split(path.sep).join('/'));
|
|
37
|
+
if (relative.some((p) => p.startsWith('..') || path.isAbsolute(p))) {
|
|
38
|
+
return deny('Cannot edit outside repository');
|
|
39
|
+
}
|
|
40
|
+
if (relative.every(safePlanningPath)) return;
|
|
41
|
+
if (relative.some((p) => /^docs\/approvals\//.test(p))) {
|
|
42
|
+
return deny('Approval records require a separate owner-controlled action');
|
|
43
|
+
}
|
|
44
|
+
const result = validate(root, { changedFiles: relative });
|
|
45
|
+
if (!result.ok) deny(`Plan approval required: ${result.reason}`);
|
|
64
46
|
}
|
|
47
|
+
|
|
48
|
+
let raw = '';
|
|
49
|
+
process.stdin.setEncoding('utf8');
|
|
50
|
+
process.stdin.on('data', (chunk) => { raw += chunk; });
|
|
51
|
+
process.stdin.on('end', () => {
|
|
52
|
+
try {
|
|
53
|
+
run(JSON.parse(raw));
|
|
54
|
+
} catch (error) {
|
|
55
|
+
deny(`Approval gate error: ${error.message}`);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require('node:child_process');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { validate } = require('./approval-policy');
|
|
7
|
+
|
|
8
|
+
function main(args) {
|
|
9
|
+
const root = process.cwd();
|
|
10
|
+
const baseIndex = args.indexOf('--base');
|
|
11
|
+
const filesIndex = args.indexOf('--files');
|
|
12
|
+
const planIndex = args.indexOf('--plan');
|
|
13
|
+
if (baseIndex !== -1 && filesIndex !== -1) throw new Error('Choose --base or --files');
|
|
14
|
+
const planFile = planIndex < 0 ? undefined : args[planIndex + 1];
|
|
15
|
+
let changedFiles = [];
|
|
16
|
+
if (baseIndex >= 0) {
|
|
17
|
+
const base = args[baseIndex + 1];
|
|
18
|
+
if (!base || base.startsWith('--')) throw new Error('Missing --base value');
|
|
19
|
+
const mergeBase = execFileSync('git', ['merge-base', base, 'HEAD'], { cwd: root, encoding: 'utf8' }).trim();
|
|
20
|
+
const diff = execFileSync('git', ['diff', '--name-only', '--diff-filter=ACMRT', mergeBase, 'HEAD'], { cwd: root, encoding: 'utf8' });
|
|
21
|
+
changedFiles = diff.split(/\r?\n/).filter(Boolean);
|
|
22
|
+
} else if (filesIndex >= 0) {
|
|
23
|
+
const files = args[filesIndex + 1];
|
|
24
|
+
if (!files || files.startsWith('--')) throw new Error('Missing --files value');
|
|
25
|
+
changedFiles = files.split(',').map((f) => f.trim()).filter(Boolean);
|
|
26
|
+
}
|
|
27
|
+
const result = validate(root, { planFile, changedFiles });
|
|
28
|
+
if (!result.ok) {
|
|
29
|
+
console.error(`BLOCKED: ${result.reason}`);
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
console.log(`Approval verified: ${result.planId || 'legacy'}${result.revision ? ` revision ${result.revision}` : ''}`);
|
|
34
|
+
if (result.warning) console.warn(result.warning);
|
|
35
|
+
console.log(`Checked ${changedFiles.length} changed file(s)`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
main(process.argv.slice(2));
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(`BLOCKED: ${error.message}`);
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
}
|
|
@@ -34,10 +34,56 @@
|
|
|
34
34
|
|
|
35
35
|
Caveman ULTRA mode always on. Apply the `karpathy-guidelines` skill (engineering
|
|
36
36
|
discipline) on every coding and debugging task. Apply the `ux-design` skill (the UX
|
|
37
|
-
cookbook + wireframe baseline) on every UI-facing task.
|
|
38
|
-
|
|
39
|
-
and
|
|
40
|
-
|
|
37
|
+
cookbook + wireframe baseline) on every UI-facing task. When **authoring** a new
|
|
38
|
+
visual direction (`/design`, or no approved UX-PACK yet), apply `ui-ux-pro-max`
|
|
39
|
+
first and fold the look into the UX pack — do not re-roll styles at phase CLOSE.
|
|
40
|
+
Apply the `security` skill (the Secure SDLC cookbook) at design (threat model),
|
|
41
|
+
while coding (secure coding), and before any deploy. Apply the `code-standards`
|
|
42
|
+
skill (naming per the language's own idiom + the declared architecture) on every
|
|
43
|
+
coding task.
|
|
44
|
+
|
|
45
|
+
-----
|
|
46
|
+
|
|
47
|
+
## Plan-scoped approvals (new work)
|
|
48
|
+
|
|
49
|
+
For each new task, create one `docs/plans/PLAN-<id>.md` with a unique ID, revision,
|
|
50
|
+
scope, changed-file boundaries, acceptance criteria, tests, and risks. Set
|
|
51
|
+
`docs/ACTIVE-PLAN` to its relative path. One human approval authorizes exactly
|
|
52
|
+
one plan revision, not other plans or future edits to that plan.
|
|
53
|
+
|
|
54
|
+
Approval is recorded separately in `docs/approvals/PLAN-<id>.json` with
|
|
55
|
+
`planId`, `revision`, `planBlobSha` (Git blob SHA-1 of the exact Markdown),
|
|
56
|
+
`approvedBy`, `approvedAt`, `approvalSource`, and `allowedPaths`.
|
|
57
|
+
The approval record is created only after explicit human consent. Revisions,
|
|
58
|
+
including seemingly small edits, invalidate the old digest and require new approval.
|
|
59
|
+
Do not let an agent self-approve a plan.
|
|
60
|
+
|
|
61
|
+
Use `node .issflow/hooks/verify-approval.js --base origin/main` to check the
|
|
62
|
+
active plan and changed paths. Run `node --test tests/approval-policy.test.js`
|
|
63
|
+
when those tests are installed. For an existing project with only `docs/PLAN.md`,
|
|
64
|
+
the verifier retains legacy `> Approval: approved ...` compatibility and warns
|
|
65
|
+
that it is not revision-scoped. Migrate intentionally, not by silently rewriting
|
|
66
|
+
existing plans.
|
|
67
|
+
|
|
68
|
+
**Enforcement boundary:** The Claude PreToolUse hook protects supported file-edit
|
|
69
|
+
tools; it does not intercept shell commands, GitHub API writes, or every Codex
|
|
70
|
+
execution mode. The verifier checks the local checkout/PR diff, but a writable
|
|
71
|
+
approval JSON is not cryptographic proof of the human approver. Require protected
|
|
72
|
+
branches, required CI checks, and an actual human GitHub PR review for merge.
|
|
73
|
+
No tool can treat a self-edited approval file as owner authorization.
|
|
74
|
+
|
|
75
|
+
**Recovery:** If approval metadata is missing or malformed, stop implementation.
|
|
76
|
+
A human should inspect the plan, restore the correct pointer and approval record,
|
|
77
|
+
then rerun verification. Never bypass the gate by editing `STATE.md` or disabling
|
|
78
|
+
checks. A scoped feature lane does not inherit approval from another plan.
|
|
79
|
+
|
|
80
|
+
**Engineering:** Prefer feature-based modules and vertical slices. Keep route
|
|
81
|
+
adapters thin; put business rules near their feature. Use idiomatic names,
|
|
82
|
+
cohesive files, explicit contracts, and minimal abstractions. Comments explain
|
|
83
|
+
non-obvious intent, not line-by-line mechanics. Use concise Conventional Commit
|
|
84
|
+
subjects (`feat(scope): change`, `fix(scope): change`); avoid tool signatures
|
|
85
|
+
and promotional boilerplate while preserving truthful Git author/committer
|
|
86
|
+
metadata and any required disclosures.
|
|
41
87
|
|
|
42
88
|
-----
|
|
43
89
|
|
|
@@ -155,7 +201,7 @@ those gates, never the plan, the money, or the design/arch frame.
|
|
|
155
201
|
| House role | Kit surface |
|
|
156
202
|
|------------|-------------|
|
|
157
203
|
| BA / PM | `/overview` grill · `grill-me` · PLAN / PROPOSAL / CR gates |
|
|
158
|
-
| UX / UI | `/design` (UX pack) · `ux-design`
|
|
204
|
+
| UX / UI | `/design` (UX pack) · `ui-ux-pro-max` (look) · `ux-design` (frame + gate) · `/ui-audit` · rule 9 CLOSE |
|
|
159
205
|
| Architect | `/design` (ARCHITECTURE) · `researcher` DESIGN · `code-standards` · `/log-decision` |
|
|
160
206
|
| Developer | `implementer` · `/phase` · `/feature` · `/quick` |
|
|
161
207
|
| QA | `test-author` · `e2e-runner` · `/qa-audit` · `/uat` |
|
|
@@ -691,6 +737,8 @@ the KB. The kit works normally without a KB.
|
|
|
691
737
|
`scripts/regression.sh` (default mock; `--real` runs the real corpus).
|
|
692
738
|
- `.issflow/skills/ux-design/` — the UX cookbook + wireframe baseline (read on
|
|
693
739
|
demand for any UI work).
|
|
740
|
+
- `.issflow/skills/ui-ux-pro-max/` — visual direction for `/design` (vendored
|
|
741
|
+
search engine + catalogue; MIT upstream).
|
|
694
742
|
- `.issflow/skills/security/` — the Secure SDLC cookbook + threat-modeling /
|
|
695
743
|
secure-coding / pentest / standards references (read on demand for security work).
|
|
696
744
|
- `.issflow/skills/code-standards/` — naming-per-language + architecture cookbook
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Next Level Builder
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ui-ux-pro-max
|
|
3
|
+
description: >
|
|
4
|
+
Design intelligence for NEW visual direction — styles, palettes, type, landing
|
|
5
|
+
patterns. Use when authoring `/design` UX-PACK, setting OVERVIEW UX direction,
|
|
6
|
+
or the project has no approved UX pack yet. Triggers: "/design", "UX pack",
|
|
7
|
+
"visual direction", "design system", "palette", "typography", "landing pattern",
|
|
8
|
+
"ทิศทางดีไซน์", "โทนสี". Skip for backend, and skip re-rolling styles when an
|
|
9
|
+
approved UX-PACK already exists (follow that frame; validate with ux-design).
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ui-ux-pro-max — visual direction (authoring)
|
|
13
|
+
|
|
14
|
+
Vendored from [ui-ux-pro-max-skill](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill)
|
|
15
|
+
(MIT — see `LICENSE.upstream` + `UPSTREAM.md`). Engine lives **in this folder**.
|
|
16
|
+
|
|
17
|
+
`ux-design` remains the **gate** (hard rule 9 — wireframe + cookbook). This skill
|
|
18
|
+
picks the **look**. Do not let a catalogue restyle override an approved UX pack.
|
|
19
|
+
|
|
20
|
+
## When
|
|
21
|
+
|
|
22
|
+
- `/design` STEP 1 (author the UX pack) — **required** when UI is in scope.
|
|
23
|
+
- First visual direction (OVERVIEW UX / no approved `docs/UX-PACK.md`).
|
|
24
|
+
- Human explicitly asks to restyle — then re-run and wait for UX-PACK re-approve.
|
|
25
|
+
|
|
26
|
+
**Not** at `/phase` CLOSE. CLOSE = `ux-design` cookbook against the approved pack.
|
|
27
|
+
Do not run `--design-system` again per slice.
|
|
28
|
+
|
|
29
|
+
## Engine
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
python3 .issflow/skills/ui-ux-pro-max/scripts/search.py
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If this project's kit was mirrored for Claude Code, the same files exist under
|
|
36
|
+
`.claude/skills/ui-ux-pro-max/` — use whichever path is present.
|
|
37
|
+
|
|
38
|
+
Try `python3`, then `python`, then `py -3`. Stdlib only. If Python 3 is missing,
|
|
39
|
+
**ask the human** to install it (python.org / Homebrew / apt). Do not install
|
|
40
|
+
Python or npm yourself. Do not tell them to run `uipro init` — the catalogue
|
|
41
|
+
is already in the kit.
|
|
42
|
+
|
|
43
|
+
On-demand detail: `references/quick-reference.md`, `references/pro-rules.md`.
|
|
44
|
+
|
|
45
|
+
## Authoring workflow
|
|
46
|
+
|
|
47
|
+
1. Product / industry / keywords from OVERVIEW + PLAN (2–5 terms). Detect stack
|
|
48
|
+
from the project; never assume HTML+Tailwind.
|
|
49
|
+
2. Run:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
python3 .issflow/skills/ui-ux-pro-max/scripts/search.py "<product> <industry> <keywords>" --design-system -p "<project>" -f markdown
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Retry once if empty. Do not persist unverified output. Do **not** pass
|
|
56
|
+
`--persist` / do **not** write a parallel `design-system/` tree — fold into
|
|
57
|
+
`docs/UX-PACK.md` → Frame & tokens (style, palette, type, effects,
|
|
58
|
+
anti-patterns). Kit SoT stays UX-PACK.
|
|
59
|
+
3. Optional domain search only for a named gap:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
python3 .issflow/skills/ui-ux-pro-max/scripts/search.py "<query>" --domain ux|icons|chart|typography|style|color|landing
|
|
63
|
+
python3 .issflow/skills/ui-ux-pro-max/scripts/search.py "<query>" --stack <detected>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
4. Then apply `ux-design` authoring (wireframe + cookbook). Catalogue must still
|
|
67
|
+
pass: no emoji icons, tokens not raw hex in components, WCAG AA.
|
|
68
|
+
|
|
69
|
+
If UX-PACK is already **approved**, read it and stop — unless the human asked to
|
|
70
|
+
change the look.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
No,Category,Issue,Keywords,Platform,Description,Do,Don't,Code Example Good,Code Example Bad,Severity
|
|
2
|
+
1,Accessibility,Icon Button Labels,icon button accessibilityLabel,iOS/Android/React Native,Icon-only buttons must expose an accessible label,Set accessibilityLabel or label prop on icon buttons,Icon buttons without accessible names,"<Pressable accessibilityLabel=""Close""><XIcon /></Pressable>",<Pressable><XIcon /></Pressable>,Critical
|
|
3
|
+
2,Accessibility,Form Control Labels,form input label accessibilityLabel,iOS/Android/React Native,All inputs must have a visible label and an accessibility label,Pair Text label with input and set accessibilityLabel,Inputs with placeholder only,"<View><Text>Email</Text><TextInput accessibilityLabel=""Email address"" /></View>","<TextInput placeholder=""Email"" /></View>",Critical
|
|
4
|
+
3,Accessibility,Role & Traits,accessibilityRole accessibilityTraits,iOS/Android/React Native,Interactive elements must expose correct roles/traits,Use accessibilityRole/button/link/checkbox etc.,Rely on generic views with no roles,"<Pressable accessibilityRole=""button"">Submit</Pressable>",<View onTouchStart={submit}>Submit</View>,High
|
|
5
|
+
4,Accessibility,Dynamic Updates,accessibilityLiveRegion announce,iOS/Android/React Native,Async status updates should be announced to screen readers,Use accessibilityLiveRegion or announceForAccessibility,Update text silently with no announcement,"<Text accessibilityLiveRegion=""polite"">{status}</Text>",<Text>{status}</Text>,Medium
|
|
6
|
+
5,Accessibility,Decorative Icons,accessible={false} importantForAccessibility,iOS/Android/React Native,Decorative icons should be hidden from screen readers,Mark decorative icons as not accessible,Have screen reader read every icon,"<Icon accessible={false} importantForAccessibility=""no"" />",<Icon />,Medium
|
|
7
|
+
6,Touch,Touch Target Size,touch target size platform runtime arbitration iOS 44pt Android 48dp web 24 CSS px React Native hitSlop,iOS/Android/React Native,Native targets use 44pt on iOS and 48dp on Android; web WCAG 2.2 has a separate 24 by 24 CSS px minimum with exceptions,Select 44pt for iOS and 48dp for Android at runtime; evaluate web targets separately against WCAG 2.5.8 and its exceptions,"Collapse iOS 44pt, Android 48dp, and web 24 CSS px into one cross-platform number","Platform.select({ ios: 44, android: 48 }); // web: evaluate 24 CSS px + WCAG exceptions",<Pressable><Icon size={16} /></Pressable>,Critical
|
|
8
|
+
7,Touch,Touch Spacing,touch spacing gap 8px,iOS/Android/React Native,Adjacent touch targets need enough spacing,Keep at least 8dp spacing between touchables,Cluster many buttons with no gap,<View style={{ gap: 8 }}><Button ... /><Button ... /></View>,<View><Button ... /><Button ... /></View>,Medium
|
|
9
|
+
8,Touch,Gesture Conflicts,scroll swipe back gesture,iOS/Android/React Native,Custom gestures must not break system scroll/back,Reserve horizontal swipes for carousels,Full-screen custom swipe conflicting with back,HorizontalPager inside vertical ScrollView,PanResponder on full screen blocking back,High
|
|
10
|
+
9,Navigation,Back Behavior,back handler navigation stack,iOS/Android/React Native,Back navigation should be predictable and preserve state,Use navigation.goBack and keep screen state,Reset stack or exit app unexpectedly,onPress={() => navigation.goBack()},BackHandler.exitApp() on first press,Critical
|
|
11
|
+
10,Navigation,Bottom Tabs,tab bar max items,iOS/Android/React Native,Bottom tab bar should have at most 5 primary items,Use 3–5 tabs and move extras to More/Settings,Overloaded tab bar with many icons,Home/Explore/Profile/Settings,Home/Explore/Shop/Cart/Profile/Settings/More,Medium
|
|
12
|
+
11,Navigation,Modal Escape,modal dismiss close affordance,iOS/Android/React Native,Modals/sheets must have clear close actions,Provide close button and swipe-down where platform expects,Trapping users in modal with no obvious exit,"<Modal><Button title=""Close"" onPress={onClose} /></Modal>",<Modal><View>{children}</View></Modal>,High
|
|
13
|
+
12,State,Preserve Screen State,navigation preserve state,iOS/Android/React Native,Returning to a screen should restore its scroll and form state,Keep components mounted or persist state,Reset list scroll and form inputs on every visit,<Tab.Navigator screenOptions={{ unmountOnBlur: false }}>,<Tab.Screen options={{ unmountOnBlur: true }} />,Medium
|
|
14
|
+
13,Feedback,Loading Indicators,activity indicator skeleton,iOS/Android/React Native,Show visible feedback during network operations,Use ActivityIndicator or skeleton for >300ms operations,Leave button and screen frozen,"{loading ? <ActivityIndicator /> : <Button title=""Save"" />}"," ""<Button title=""""Save"""" onPress={submit} /> // no loading""",High
|
|
15
|
+
14,Feedback,Success Feedback,toast checkmark banner,iOS/Android/React Native,Confirm successful actions with brief feedback,Show toast/checkmark or banner,Complete actions silently with no confirmation,showToast('Saved successfully'),// silently update state only,Medium
|
|
16
|
+
15,Feedback,Error Feedback,inline error banner,iOS/Android/React Native,Show clear error messages near the problem,input-level error + summary banner,Only change border color with no explanation,<TextInput ... /><Text style={{color:'red'}}>{error}</Text>,<TextInput style={{borderColor:'red'}} />,High
|
|
17
|
+
16,Forms,Inline Validation,onBlur validation,iOS/Android/React Native,Validate inputs on blur or submit with clear messaging,Validate onBlur and onSubmit,Validate on every keystroke causing jank,onBlur={() => validateEmail(value)},onChangeText={v => validateEmail(v)} // every char,Medium
|
|
18
|
+
17,Forms,Keyboard Type,keyboardType returnKeyType,iOS/Android/React Native,Use appropriate keyboardType and returnKeyType,Match email/tel/number/search types,Use default keyboard for all inputs,"<TextInput keyboardType=""email-address"" />","<TextInput keyboardType=""default"" />",Medium
|
|
19
|
+
18,Forms,Auto Focus & Next,autoFocus blurOnSubmit onSubmitEditing,iOS/Android/React Native,Guide users through form fields with Next/Done flows,Use onSubmitEditing to focus next input,Force users to tap each field manually,onSubmitEditing={() => nextRef.current?.focus()},"// no onSubmitEditing, manual tap only",Low
|
|
20
|
+
19,Forms,Password Visibility,secureTextEntry toggle,iOS/Android/React Native,Allow toggling password visibility securely,Provide Show/Hide icon toggling secureTextEntry,Force users to type blind with no option,<TextInput secureTextEntry={secure} /><Icon onPress={toggle} />,<TextInput secureTextEntry /> // no toggle,Medium
|
|
21
|
+
20,Performance,Virtualize Long Lists,FlatList SectionList virtualization,iOS/Android/React Native,Use FlatList/SectionList for lists over ~50 items,Use keyExtractor and initialNumToRender appropriately,Render hundreds of items with ScrollView,<FlatList data={items} renderItem={...} />,<ScrollView>{items.map(renderItem)}</ScrollView>,High
|
|
22
|
+
21,Performance,Image Size & Cache,Image resize cache,iOS/Android/React Native,Use correctly sized and cached images,Use Image component with proper resizeMode and caching,Load full-resolution images everywhere,"<Image source={{uri}} resizeMode=""cover"" />",<Image source={require('4k.png')} /> // small avatar,Medium
|
|
23
|
+
22,Performance,Debounce High-Freq Events,debounce scroll search,iOS/Android/React Native,Debounce scroll/search callbacks to avoid jank,Wrap handlers with debounce/throttle,Run heavy logic on every event,onScroll={debouncedHandleScroll},onScroll={handleScrollHeavy},Medium
|
|
24
|
+
23,Animation,Duration & Easing,animation duration easing,iOS/Android/React Native,Micro-interactions should be 150–300ms with native-like easing,Use ease-out for enter/ease-in for exit,Use long or linear animations for core UI,"Animated.timing(..., { duration: 200, easing: Easing.out(Easing.quad) })","Animated.timing(..., { duration: 800, easing: Easing.linear })",Medium
|
|
25
|
+
24,Animation,Respect Reduced Motion,reduced motion accessibility,iOS/Android/React Native,Respect OS reduced-motion accessibility setting,Check reduceMotionEnabled and simplify animations,Ignore user motion preferences,if (reduceMotionEnabled) skipAnimation(),Always run complex parallax animations,Critical
|
|
26
|
+
25,Animation,Limited Continuous Motion,loop animation loader,iOS/Android/React Native,Reserve infinite animations for loaders and live data,Use looping only where necessary,Keep decorative elements looping forever,Animated.loop(loaderAnim) for ActivityIndicator,Animated.loop(bounceAnim) on background icons,Medium
|
|
27
|
+
26,Typography,Base Font Size,fontScale dynamic type,iOS/Android/React Native,Body text must be readable and support Dynamic Type,Use platform fontScale and at least 14–16pt base,Render critical text below 12pt,<Text style={{ fontSize: 16 }}>Body</Text>,<Text style={{ fontSize: 10 }}>Body</Text>,High
|
|
28
|
+
27,Typography,Dynamic Type Support,allowFontScaling adjustsFontSizeToFit,iOS/Android/React Native,Support system text scaling without breaking layout,Set allowFontScaling and test large text,Disable scaling on all text globally,<Text allowFontScaling>{label}</Text>,<Text allowFontScaling={false}>{label}</Text>,High
|
|
29
|
+
28,Safe Areas,Safe Area Insets,safe area insets notch gesture,iOS/Android/React Native,Content must not overlap notches/gesture bars,Wrap screens in SafeAreaView or apply insets,Place tappable content under system bars,<SafeAreaView style={{ flex: 1 }}><Screen /></SafeAreaView>,<View style={{ flex: 1 }}><Screen /></View>,High
|
|
30
|
+
29,Theming,Light/Dark Contrast,dark mode contrast tokens,iOS/Android/React Native,Ensure sufficient contrast in both light and dark themes,Use semantic tokens and test both themes,Reuse light-theme grays directly in dark mode,colors.textPrimaryDark = '#F9FAFB',colors.textPrimaryDark = '#9CA3AF' on '#111827',High
|
|
31
|
+
30,Anti-Pattern,No Gesture-Only Actions,gesture only hidden controls,iOS/Android/React Native,Don't rely solely on hidden gestures for core actions,Provide visible buttons in addition to gestures,Rely on swipe/shake only with no UI affordance,Swipe to delete + visible Delete button,Only shake device to undo with no UI,Critical
|
|
32
|
+
31,Accessibility,Dragging Alternatives,accessible drag interaction drag single pointer alternative keyboard drag alternative reorder resize move buttons React Native native runtime platform router arbitration iOS Android web,iOS/Android/React Native,React Native drag and reorder operations need a non-drag path selected for the active native runtime,Provide named Move up/down buttons or a position menu beside drag handles; route iOS and Android behavior through the runtime platform adapter,"Make drag, swipe, or a web-only pointer handler the only way to reorder native content","<Button title=""Move up"" onPress={() => moveItem(index, index - 1)} />",<DragHandle /> only,High
|
|
33
|
+
32,Forms,Authentication Reuse,password manager passkey paste redundant entry,iOS/Android/React Native,Authentication and multi-step flows should reuse prior values,Support password managers passkeys paste and prefilled confirmed values,Force users to retype credentials or the same data in one flow,"textContentType=""password"" autoComplete=""current-password""",onPaste disabled,Critical
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"verifiedAt": "2026-08-26",
|
|
4
|
+
"counts": {
|
|
5
|
+
"styles": {
|
|
6
|
+
"total": 88,
|
|
7
|
+
"searchable": 79,
|
|
8
|
+
"active": 50,
|
|
9
|
+
"supplemental": 29,
|
|
10
|
+
"deprecated": 9
|
|
11
|
+
},
|
|
12
|
+
"products": 192,
|
|
13
|
+
"palettes": 192,
|
|
14
|
+
"reasoningProfiles": 192,
|
|
15
|
+
"fontPairings": 74,
|
|
16
|
+
"googleFonts": 1934,
|
|
17
|
+
"curatedIcons": 105,
|
|
18
|
+
"upstreamPhosphorIcons": 1512,
|
|
19
|
+
"uxGuidelines": 119,
|
|
20
|
+
"motionPresets": 17,
|
|
21
|
+
"chartTypes": 25,
|
|
22
|
+
"stacks": 22,
|
|
23
|
+
"stackGuidelines": 1271
|
|
24
|
+
},
|
|
25
|
+
"snapshots": {
|
|
26
|
+
"google-fonts.csv": {
|
|
27
|
+
"sha256": "1c8c3b2ea1faf6a1012da463756def8b3889db33f2226f0343bb4daa80307d03"
|
|
28
|
+
},
|
|
29
|
+
"google-font-licenses.json": {
|
|
30
|
+
"sha256": "35688523f2955795caa1a47c53b83099e60c1708461476f9cc3a050cf3b0148a"
|
|
31
|
+
},
|
|
32
|
+
"icons.csv": {
|
|
33
|
+
"sha256": "50816c6012030178195a16ee481ebf58b47bd985d70e8ec58886cc83f6eddafc"
|
|
34
|
+
},
|
|
35
|
+
"phosphor-icons-upstream.json": {
|
|
36
|
+
"sha256": "2399325233b277b5c97a80e6a5e8941154f5d057beee4e7613db87c87d700236"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"promotionPolicy": {
|
|
40
|
+
"changedFamilySetRequiresExplicitApproval": true,
|
|
41
|
+
"relevanceGateRequired": true,
|
|
42
|
+
"unlicensedFamiliesExcluded": true
|
|
43
|
+
},
|
|
44
|
+
"pendingCandidates": [
|
|
45
|
+
{
|
|
46
|
+
"family": "Edu NSW ACT Cursive",
|
|
47
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"family": "Edu NSW ACT Hand Pre",
|
|
51
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"family": "Edu QLD Hand",
|
|
55
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"family": "Edu SA Hand",
|
|
59
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"family": "Edu VIC WA NT Hand",
|
|
63
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"family": "Edu VIC WA NT Hand Pre",
|
|
67
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"family": "Google Sans",
|
|
71
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"family": "Google Sans Flex",
|
|
75
|
+
"reason": "No exact-family METADATA.pb entry in the official google/fonts repository snapshot"
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|