refira-cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +153 -0
  2. package/dist/index.js +39 -11
  3. package/package.json +6 -7
package/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # Refira CLI
2
+
3
+ A command-line tool and deterministic AI Agent Harness for designing and previewing standalone HTML5 and Tailwind CSS prototypes in Refira workspaces.
4
+
5
+ Refira CLI enables autonomous coding agents (such as Google Antigravity, Claude Code, Cursor Agent, and Aider) and developers to interact directly with the Refira canvas, fetch design tokens, scaffold clean templates, and validate markup before publishing.
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ Refira is an AI design workspace that maintains persistent design context and renders prototypes inside sandboxed iframes. Refira CLI serves two purposes:
12
+ 1. **Developer & Agent CLI:** Manage sessions, pull design tokens, and push live page markup.
13
+ 2. **Deterministic Agent Harness:** Automatically lint markup with `htmlparser2` to enforce design consistency and prevent broken prototype states before code reaches the backend.
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ Run directly using NPX without installation:
20
+ ```bash
21
+ npx refira-cli --help
22
+ ```
23
+
24
+ Or install globally on your system:
25
+ ```bash
26
+ npm install --global refira-cli
27
+ ```
28
+
29
+ Verify installation:
30
+ ```bash
31
+ refira --version
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Command Reference
37
+
38
+ ### 1. Authentication
39
+
40
+ #### `refira auth login`
41
+ Authenticates against a Refira instance and stores credentials locally in `.refirarc` (or globally in `~/.refirarc`).
42
+
43
+ ```bash
44
+ refira auth login --api-url https://api.refira.dev --api-key rfr_your_api_key
45
+ ```
46
+
47
+ Options:
48
+ - `--api-url <url>`: Refira backend API endpoint (default: `http://localhost:3001`).
49
+ - `--api-key <key>`: Project-scoped API key with `rfr_` prefix.
50
+ - `-g, --global`: Save credentials globally in user home directory.
51
+
52
+ #### `refira auth status`
53
+ Verifies the current session and displays project and user identifiers.
54
+
55
+ ```bash
56
+ refira auth status
57
+ ```
58
+
59
+ ---
60
+
61
+ ### 2. Workspace Initialization
62
+
63
+ #### `refira init`
64
+ Connects to the project API, downloads design tokens, and deterministically generates operational guidelines for AI coding agents:
65
+ - `AGENTS.md`: Operational instructions for Antigravity, Codex, Gemini CLI, and other agents.
66
+ - `.cursorrules`: Rule definitions for Cursor.
67
+ - `.agents/skills/refira/SKILL.md`: Design craftsmanship skill focusing on high-aesthetic UI execution.
68
+
69
+ ```bash
70
+ refira init --project-id <project-uuid>
71
+ ```
72
+
73
+ ---
74
+
75
+ ### 3. Design Context & Tokens
76
+
77
+ #### `refira context`
78
+ Displays project design tokens (primary typography font, palette colors) and the existing page roster.
79
+
80
+ ```bash
81
+ refira context
82
+ ```
83
+
84
+ ---
85
+
86
+ ### 4. Page Scaffolding
87
+
88
+ #### `refira scaffold`
89
+ Generates a standalone HTML5 starter template pre-configured with:
90
+ - Google Fonts specified in project design tokens.
91
+ - Tailwind CSS CDN and theme extensions.
92
+ - Lucide Icons script.
93
+ - Body content slot marking where agent layout markup should be placed.
94
+
95
+ ```bash
96
+ refira scaffold --page checkout
97
+ ```
98
+
99
+ Options:
100
+ - `--page <slug>`: Required page slug (e.g., `checkout`, `dashboard`, `landing`).
101
+ - `--output <path>`: Custom destination file path (default: `<slug>.html`).
102
+
103
+ ---
104
+
105
+ ### 5. Live Preview & Harness Validation
106
+
107
+ #### `refira preview`
108
+ Inspects an HTML markup file using the Refira Agent Harness. If violations are detected, execution halts with Exit Code 1 and actionable remediation instructions. If valid, the markup is streamed directly to the Refira Canvas.
109
+
110
+ ```bash
111
+ refira preview checkout.html --page checkout
112
+ ```
113
+
114
+ Arguments:
115
+ - `<file>`: Path to the HTML file to inspect and preview.
116
+
117
+ Options:
118
+ - `--page <slug>`: Target page slug.
119
+
120
+ ---
121
+
122
+ ### 6. Agent Skill Installation
123
+
124
+ #### `refira skill install`
125
+ Installs the Refira design craftsmanship guide (`SKILL.md`) for AI agents.
126
+
127
+ ```bash
128
+ # Local project installation (.agents/skills/refira/SKILL.md)
129
+ refira skill install
130
+
131
+ # Global installation (~/.agents/skills/refira/SKILL.md)
132
+ refira skill install --global
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Agent Harness Invariants
138
+
139
+ All markup submitted via `refira preview` must conform to these strict architectural rules:
140
+
141
+ | Rule | Status | Description |
142
+ |---|---|---|
143
+ | **Standalone HTML5 + Tailwind** | Required | Markup must be valid native HTML5 with Tailwind CSS utility classes. |
144
+ | **No UI Frameworks** | Prohibited | React, Vue, Svelte, Angular, Solid, and JSX syntax (`className=`, `onClick={...}`, `<Component />`) are rejected. |
145
+ | **No External / Inter-Page Navigation** | Prohibited | Prototypes run inside sandboxed iframes. Anchors (`<a href="...">`) pointing to external URLs or relative pages (e.g. `/checkout`) are rejected. Only in-page anchors (`href="#section"`) or placeholders (`href="#"`) are allowed. |
146
+ | **No Raw Emojis in Markup** | Prohibited | Raw unicode emojis (e.g. rocket, fire, sparkles) in HTML text nodes or attributes are rejected to maintain professional aesthetic quality. Use Lucide Icons or Heroicons SVG elements instead. |
147
+ | **Graphics & Animation Libraries** | Permitted | Standalone CDN scripts such as Three.js, GSAP, Spline Viewer, and Lucide Icons are explicitly allowed in document `<head>` or `<script>`. |
148
+
149
+ ---
150
+
151
+ ## License
152
+
153
+ MIT License. Distributed as part of the Refira workspace ecosystem.
package/dist/index.js CHANGED
@@ -1892,6 +1892,23 @@ var {
1892
1892
  } = exports_commander;
1893
1893
 
1894
1894
  // src/api-client.ts
1895
+ function extractFontFamily(typography, fallback = "Inter") {
1896
+ if (!typography)
1897
+ return fallback;
1898
+ if (typeof typography.font_family === "string" && typography.font_family.trim().length > 0) {
1899
+ return typography.font_family;
1900
+ }
1901
+ if (typography.primary && typeof typography.primary.font_family === "string" && typography.primary.font_family.trim().length > 0) {
1902
+ return typography.primary.font_family;
1903
+ }
1904
+ for (const item of Object.values(typography)) {
1905
+ if (item && typeof item === "object" && typeof item.font_family === "string") {
1906
+ return item.font_family;
1907
+ }
1908
+ }
1909
+ return fallback;
1910
+ }
1911
+
1895
1912
  class CliApiClient {
1896
1913
  apiUrl;
1897
1914
  apiKey;
@@ -2047,18 +2064,22 @@ async function contextCommand(opts) {
2047
2064
  const client = new CliApiClient(config.apiUrl, config.apiKey);
2048
2065
  try {
2049
2066
  const data = await client.getProjectContext(projectId);
2067
+ const projectName = data.context?.project_name ?? data.context?.project?.name ?? "Refira Project";
2068
+ const resolvedProjectId = data.context?.project_id ?? data.context?.project?.id ?? projectId;
2050
2069
  console.log(`
2051
2070
  ======================================================================`);
2052
- console.log(`\uD83D\uDCE6 REFIRA DESIGN CONTEXT: ${data.context.project.name} (${data.context.project.id})`);
2071
+ console.log(`\uD83D\uDCE6 REFIRA DESIGN CONTEXT: ${projectName} (${resolvedProjectId})`);
2053
2072
  console.log("======================================================================");
2054
- const font = data.context.tokens?.typography?.font_family || data.context.project.fontFamily || "Inter";
2073
+ const font = extractFontFamily(data.context?.tokens?.typography, data.context?.project?.fontFamily ?? "Inter");
2055
2074
  console.log(`
2056
2075
  \uD83D\uDD24 Primary Typography: Google Fonts "${font}"`);
2057
- if (data.context.tokens?.color) {
2076
+ const colorTokens = data.context?.tokens?.colors ?? data.context?.tokens?.color;
2077
+ if (colorTokens) {
2058
2078
  console.log(`
2059
2079
  \uD83C\uDFA8 Design Color Tokens:`);
2060
- for (const [tokenName, tokenVal] of Object.entries(data.context.tokens.color)) {
2061
- console.log(` --${tokenName}: ${tokenVal}`);
2080
+ for (const [tokenName, tokenVal] of Object.entries(colorTokens)) {
2081
+ const displayVal = typeof tokenVal === "string" ? tokenVal : tokenVal?.hex ?? tokenVal?.oklch ?? JSON.stringify(tokenVal);
2082
+ console.log(` --${tokenName}: ${displayVal}`);
2062
2083
  }
2063
2084
  }
2064
2085
  console.log(`
@@ -2201,8 +2222,8 @@ async function initCommand(opts) {
2201
2222
  const client = new CliApiClient(apiUrl, apiKey);
2202
2223
  try {
2203
2224
  const data = await client.getProjectContext(projectId);
2204
- const projectName = data.context.project.name || "Refira Project";
2205
- const fontFamily = data.context.tokens?.typography?.font_family || data.context.project.fontFamily || "Inter";
2225
+ const projectName = data.context?.project_name ?? data.context?.project?.name ?? "Refira Project";
2226
+ const fontFamily = extractFontFamily(data.context?.tokens?.typography, data.context?.project?.fontFamily ?? "Inter");
2206
2227
  const agentsGuide = generateAgentsGuide({
2207
2228
  projectName,
2208
2229
  projectId,
@@ -3898,9 +3919,16 @@ async function scaffoldCommand(opts) {
3898
3919
  try {
3899
3920
  const client = new CliApiClient(config.apiUrl, config.apiKey);
3900
3921
  const data = await client.getProjectContext(config.projectId);
3901
- projectName = data.context.project.name || projectName;
3902
- fontFamily = data.context.tokens?.typography?.font_family || data.context.project.fontFamily || fontFamily;
3903
- colorTokens = data.context.tokens?.color;
3922
+ projectName = data.context?.project_name ?? data.context?.project?.name ?? projectName;
3923
+ fontFamily = extractFontFamily(data.context?.tokens?.typography, data.context?.project?.fontFamily ?? fontFamily);
3924
+ const colors = data.context?.tokens?.colors ?? data.context?.tokens?.color;
3925
+ if (colors) {
3926
+ const parsed = {};
3927
+ for (const [k, v] of Object.entries(colors)) {
3928
+ parsed[k] = typeof v === "string" ? v : v?.hex ?? v?.oklch ?? "";
3929
+ }
3930
+ colorTokens = parsed;
3931
+ }
3904
3932
  } catch {}
3905
3933
  }
3906
3934
  const pageName = pageSlug.replace(/-/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
@@ -3939,7 +3967,7 @@ AI coding agents will automatically recognize this skill for high-aesthetic prot
3939
3967
 
3940
3968
  // src/index.ts
3941
3969
  var program2 = new Command2;
3942
- program2.name("refira").description("Refira CLI tool and AI Agent Harness for deterministic prototype generation").version("0.1.0");
3970
+ program2.name("refira").description("Refira CLI tool and AI Agent Harness for deterministic prototype generation").version("0.1.2");
3943
3971
  var auth = program2.command("auth").description("Manage Refira API authentication and sessions");
3944
3972
  auth.command("login").description("Login to Refira using an API key").option("--api-url <url>", "Refira backend API base URL", "http://localhost:3001").option("--api-key <key>", "Project API key (rfr_...)").option("-g, --global", "Save credentials globally in user home directory", false).action(loginCommand);
3945
3973
  auth.command("status").description("Verify and display current Refira authentication session").action(statusCommand);
package/package.json CHANGED
@@ -1,26 +1,25 @@
1
1
  {
2
2
  "name": "refira-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Refira CLI tool and AI Agent Harness for deterministic prototype generation",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "refira": "./dist/index.js"
8
8
  },
9
9
  "main": "./dist/index.js",
10
- "files": ["dist"],
10
+ "files": ["dist", "README.md"],
11
11
  "scripts": {
12
12
  "build": "bun build src/index.ts --outfile dist/index.js --target node",
13
13
  "prepublishOnly": "bun run build",
14
14
  "test": "vitest run",
15
15
  "type-check": "tsc --noEmit"
16
16
  },
17
- "dependencies": {
18
- "@refira/shared": "workspace:*",
19
- "commander": "^12.1.0",
20
- "htmlparser2": "^9.1.0"
21
- },
17
+ "dependencies": {},
22
18
  "devDependencies": {
19
+ "@refira/shared": "workspace:*",
23
20
  "@types/node": "^20.14.0",
21
+ "commander": "^12.1.0",
22
+ "htmlparser2": "^9.1.0",
24
23
  "typescript": "^5.5.4",
25
24
  "vitest": "^2.0.5"
26
25
  }