@fias/arche-sdk 1.1.4 → 1.1.6

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 (43) hide show
  1. package/dist/bridge.d.ts +11 -1
  2. package/dist/bridge.d.ts.map +1 -1
  3. package/dist/bridge.js +61 -2
  4. package/dist/bridge.js.map +1 -1
  5. package/dist/bridge.test.js +24 -7
  6. package/dist/bridge.test.js.map +1 -1
  7. package/dist/cli/create-plugin.js +4 -1
  8. package/dist/cli/create-plugin.js.map +1 -1
  9. package/dist/hooks.d.ts +18 -1
  10. package/dist/hooks.d.ts.map +1 -1
  11. package/dist/hooks.js +69 -2
  12. package/dist/hooks.js.map +1 -1
  13. package/dist/hooks.test.js +30 -6
  14. package/dist/hooks.test.js.map +1 -1
  15. package/dist/index.d.ts +7 -2
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +16 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +1966 -5
  20. package/dist/theme.d.ts +18 -0
  21. package/dist/theme.d.ts.map +1 -0
  22. package/dist/theme.js +85 -0
  23. package/dist/theme.js.map +1 -0
  24. package/dist/themes/catalog-data.d.ts +3 -0
  25. package/dist/themes/catalog-data.d.ts.map +1 -0
  26. package/dist/themes/catalog-data.js +1559 -0
  27. package/dist/themes/catalog-data.js.map +1 -0
  28. package/dist/themes/fonts.d.ts +17 -0
  29. package/dist/themes/fonts.d.ts.map +1 -0
  30. package/dist/themes/fonts.js +175 -0
  31. package/dist/themes/fonts.js.map +1 -0
  32. package/dist/themes/index.d.ts +20 -0
  33. package/dist/themes/index.d.ts.map +1 -0
  34. package/dist/themes/index.js +76 -0
  35. package/dist/themes/index.js.map +1 -0
  36. package/dist/types.d.ts +28 -2
  37. package/dist/types.d.ts.map +1 -1
  38. package/package.json +5 -4
  39. package/templates/default/.cursorrules +1 -0
  40. package/templates/default/.github/copilot-instructions.md +1 -0
  41. package/templates/default/AGENTS.md +359 -0
  42. package/templates/default/CLAUDE.md +359 -0
  43. package/templates/default/fias-plugin.json +2 -1
@@ -0,0 +1,359 @@
1
+ # FIAS Plugin Development Guide
2
+
3
+ This project is a FIAS platform plugin — a React application that runs in a sandboxed iframe within the FIAS marketplace. This file provides the context AI coding assistants need to build, test, and submit plugins effectively.
4
+
5
+ For other AI tool instruction files, see `CLAUDE.md` (identical content).
6
+
7
+ ## Project Structure
8
+
9
+ ```
10
+ fias-plugin.json # Plugin manifest (required) — name, permissions, pricing, AI configs
11
+ package.json # Dependencies and scripts
12
+ src/
13
+ index.tsx # Entry point — must render into #root with <FiasProvider> wrapper
14
+ App.tsx # Main component
15
+ vite.config.ts # Vite dev server config (port 3100)
16
+ ```
17
+
18
+ ## SDK API Reference
19
+
20
+ All hooks require the app to be wrapped in `<FiasProvider>`:
21
+
22
+ ```tsx
23
+ import { FiasProvider } from '@fias/arche-sdk';
24
+
25
+ ReactDOM.createRoot(document.getElementById('root')!).render(
26
+ <FiasProvider>
27
+ <App />
28
+ </FiasProvider>
29
+ );
30
+ ```
31
+
32
+ ### `useFiasTheme()` — Platform theme tokens
33
+
34
+ **Permission:** `theme:read`
35
+ **Returns:** `FiasTheme | null` (null while loading)
36
+
37
+ ```tsx
38
+ import { useFiasTheme } from '@fias/arche-sdk';
39
+
40
+ function MyComponent() {
41
+ const theme = useFiasTheme();
42
+ if (!theme) return null;
43
+
44
+ return (
45
+ <div style={{
46
+ color: theme.colors.text,
47
+ backgroundColor: theme.colors.background,
48
+ fontFamily: theme.fonts.body,
49
+ padding: theme.spacing.md,
50
+ borderRadius: theme.components.cardRadius,
51
+ }}>
52
+ {theme.mode === 'dark' ? 'Dark mode' : 'Light mode'}
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ **FiasTheme shape:**
59
+ - `mode`: `'light' | 'dark'`
60
+ - `colors`: `{ primary, primaryText, secondary, accent, background, surface, card, cardText, text, textSecondary, muted, mutedText, border, error, warning, success, info }`
61
+ - `spacing`: `{ xs, sm, md, lg, xl }` (CSS values like `'8px'`)
62
+ - `fonts`: `{ body, heading, mono }` (font-family strings)
63
+ - `components`: `{ borderRadius, buttonRadius, cardRadius, inputRadius, shadowSm, shadowMd, shadowLg, borderWidth }`
64
+
65
+ ### `useFiasUser()` — Current user profile
66
+
67
+ **Permission:** `user:profile:read`
68
+ **Returns:** `FiasUser | null`
69
+
70
+ ```tsx
71
+ import { useFiasUser } from '@fias/arche-sdk';
72
+
73
+ const user = useFiasUser();
74
+ // { userId: string, displayName: string, avatar: string | null }
75
+ ```
76
+
77
+ ### `useFiasStorage()` — Sandboxed file storage
78
+
79
+ **Permission:** `storage:sandbox`
80
+ **Returns:** `FiasStorageApi`
81
+
82
+ ```tsx
83
+ import { useFiasStorage } from '@fias/arche-sdk';
84
+
85
+ const { readFile, writeFile, listFiles, deleteFile } = useFiasStorage();
86
+
87
+ await writeFile('data/settings.json', JSON.stringify(settings));
88
+ const content = await readFile('data/settings.json'); // string | null
89
+ const files = await listFiles('data/'); // string[]
90
+ await deleteFile('data/old.json');
91
+ ```
92
+
93
+ ### `useEntityInvocation()` — Invoke AI entities
94
+
95
+ **Permission:** `entities:invoke`
96
+ **Returns:** `EntityInvocationApi`
97
+
98
+ ```tsx
99
+ import { useEntityInvocation } from '@fias/arche-sdk';
100
+
101
+ function AISummarizer() {
102
+ const { invoke, isLoading, result, error, streamingText } = useEntityInvocation();
103
+
104
+ async function summarize(text: string) {
105
+ await invoke({ entityId: 'ent_abc123', input: text });
106
+ }
107
+
108
+ return (
109
+ <div>
110
+ <button onClick={() => summarize('...')} disabled={isLoading}>
111
+ Summarize
112
+ </button>
113
+ {isLoading && <p>{streamingText}</p>}
114
+ {result && <p>{result.output}</p>}
115
+ {error && <p>Error: {error.message}</p>}
116
+ </div>
117
+ );
118
+ }
119
+ ```
120
+
121
+ The `entityId` references a published entity on the platform. Browse available entities with `npx fias-dev entities`.
122
+
123
+ ### `useFiasNavigation()` — In-plugin routing
124
+
125
+ **Permission:** None required
126
+ **Returns:** `FiasNavigationApi`
127
+
128
+ ```tsx
129
+ import { useFiasNavigation } from '@fias/arche-sdk';
130
+
131
+ const { navigateTo, currentPath } = useFiasNavigation();
132
+ navigateTo('/settings');
133
+ ```
134
+
135
+ ### `useStepNavigation()` — Multi-step workflows
136
+
137
+ **Returns:** `StepNavigationApi`
138
+
139
+ ```tsx
140
+ import { useStepNavigation } from '@fias/arche-sdk';
141
+
142
+ const { currentStep, setCurrentStep } = useStepNavigation('step-1');
143
+ ```
144
+
145
+ ### `usePersistentState()` — Auto-saving state
146
+
147
+ **Permission:** `storage:sandbox`
148
+
149
+ ```tsx
150
+ import { usePersistentState } from '@fias/arche-sdk';
151
+
152
+ const [count, setCount] = usePersistentState<number>('counter', 0);
153
+ // Automatically persists to storage on change
154
+ ```
155
+
156
+ ### `fias` — Imperative utilities
157
+
158
+ ```tsx
159
+ import { fias } from '@fias/arche-sdk';
160
+
161
+ fias.resize(800); // Resize iframe height
162
+ fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' | 'error'
163
+ ```
164
+
165
+ ## Manifest Reference (`fias-plugin.json`)
166
+
167
+ ```json
168
+ {
169
+ "name": "my-plugin",
170
+ "version": "1.0.0",
171
+ "description": "What this plugin does",
172
+ "main": "src/index.tsx",
173
+ "archeType": "tool",
174
+ "tags": ["utility"],
175
+ "pricing": { "model": "free", "currency": "usd" },
176
+ "permissions": ["theme:read", "entities:invoke"],
177
+ "sdk": "^1.0.0",
178
+ "dependencies": { "recharts": "2.15.0" },
179
+ "aiConfigs": [
180
+ {
181
+ "configId": "summarizer",
182
+ "label": "Text Summarizer",
183
+ "entityId": "ent_abc123",
184
+ "systemPrompt": "Summarize the input concisely.",
185
+ "parameters": { "temperature": 0.3, "maxTokens": 500 }
186
+ }
187
+ ]
188
+ }
189
+ ```
190
+
191
+ **Fields:**
192
+
193
+ | Field | Required | Description |
194
+ |----------------|----------|-------------|
195
+ | `name` | Yes | Plugin identifier (lowercase, hyphens) |
196
+ | `version` | Yes | Semver (e.g., `"1.0.0"`) |
197
+ | `description` | Yes | Short marketplace description |
198
+ | `main` | Yes | Entry point source file |
199
+ | `archeType` | Yes | `"tool"` or `"site"` |
200
+ | `tags` | No | Discovery tags |
201
+ | `pricing` | Yes | `{ model: "free" | "fixed" | "per_use" | "tiered" }` |
202
+ | `permissions` | Yes | Array of permission scopes |
203
+ | `sdk` | Yes | SDK version range |
204
+ | `dependencies` | No | npm packages with **exact** versions (max 20) |
205
+ | `aiConfigs` | No | AI entity configurations (see below) |
206
+
207
+ **Permissions:** `theme:read`, `user:profile:read`, `storage:sandbox`, `entities:invoke`
208
+
209
+ **AI Configs:** Declare entity invocations the plugin will use. Each config's `entityId` must reference a published prompt entity. Browse entities with `npx fias-dev entities`. Requires `entities:invoke` permission.
210
+
211
+ ## Plugin Constraints
212
+
213
+ These are hard limits enforced by the platform. Code that violates these will fail review or be blocked at runtime.
214
+
215
+ ### Sandboxing
216
+ - Plugins run in an iframe with `sandbox="allow-scripts allow-forms allow-same-origin"`
217
+ - **No `fetch()` or `XMLHttpRequest`** — all network access is blocked
218
+ - **No access** to parent DOM, cookies, or localStorage
219
+ - **No external scripts or stylesheets** — everything must be bundled
220
+ - All platform communication goes through the bridge (SDK hooks)
221
+
222
+ ### Size and File Limits
223
+ - **Bundle size:** Max 5 MB compressed
224
+ - **Dependencies:** Max 20, exact semver versions only (e.g., `"4.4.7"`, not `"^4.4.7"`)
225
+ - Platform packages (`react`, `react-dom`, `@fias/arche-sdk`) are provided — do not include in `dependencies`
226
+
227
+ ### Rate Limits
228
+ - `entity_invoke`: 60/minute
229
+ - `storage_write`: 120/minute
230
+ - `storage_read`: 300/minute
231
+ - `storage_list`, `storage_delete`: 60/minute
232
+
233
+ ### Security Rules (enforced during review)
234
+ - No `eval()`, `Function()`, `innerHTML`, or dynamic code execution
235
+ - No attempts to escape the iframe sandbox
236
+ - No credential collection or dark patterns
237
+ - No obfuscated code
238
+ - No accessing `window.parent`, `window.top`, or `document.cookie`
239
+
240
+ ## Styling Guidelines
241
+
242
+ - Always use `useFiasTheme()` for colors, fonts, and spacing — never hardcode
243
+ - Support both light and dark modes (check `theme.mode`)
244
+ - Use `theme.components.cardRadius`, `theme.components.shadowMd`, etc. for consistent component styling
245
+ - The plugin renders at full width inside the platform layout
246
+
247
+ ## Development Workflow
248
+
249
+ ```bash
250
+ # Terminal 1: Start plugin dev server (Vite, port 3100)
251
+ npm run dev
252
+
253
+ # Terminal 2: Start dev harness (mock mode, port 3200)
254
+ npm run dev:mock
255
+
256
+ # Open http://localhost:3200 in browser
257
+ ```
258
+
259
+ ### Authenticating with the FIAS Platform
260
+
261
+ ```bash
262
+ npx fias-dev login # Opens browser to authenticate (recommended)
263
+ npx fias-dev login --key fias_sk_... # Or paste an API key directly
264
+ ```
265
+
266
+ Running `npx fias-dev login` opens your browser to the FIAS platform. After signing in, an API key is created automatically and saved to `~/.fias/credentials`. No manual key copying needed.
267
+
268
+ ### Testing with Real AI Entities (costs credits)
269
+
270
+ ```bash
271
+ npm run dev:harness # Start harness in live mode (requires login first)
272
+ ```
273
+
274
+ ### Browsing Available Entities
275
+
276
+ ```bash
277
+ npx fias-dev entities # List all
278
+ npx fias-dev entities --search "text" # Search by keyword
279
+ npx fias-dev entities --type "prompt" # Filter by type
280
+ ```
281
+
282
+ ### Validating the Manifest
283
+
284
+ ```bash
285
+ npx fias-dev validate
286
+ ```
287
+
288
+ ### Submitting to the Arche Store
289
+
290
+ ```bash
291
+ npm run submit
292
+ # Builds, validates, packages, uploads, submits for AI review
293
+ # First listing: 5000 credits ($50). Re-submissions: 100 credits ($1).
294
+ ```
295
+
296
+ ## Common Patterns
297
+
298
+ ### Theme-Aware Card Component
299
+
300
+ ```tsx
301
+ function Card({ children }: { children: React.ReactNode }) {
302
+ const theme = useFiasTheme();
303
+ if (!theme) return null;
304
+
305
+ return (
306
+ <div style={{
307
+ backgroundColor: theme.colors.card,
308
+ color: theme.colors.cardText,
309
+ borderRadius: theme.components.cardRadius,
310
+ boxShadow: theme.components.shadowMd,
311
+ border: `${theme.components.borderWidth} solid ${theme.colors.border}`,
312
+ padding: theme.spacing.lg,
313
+ }}>
314
+ {children}
315
+ </div>
316
+ );
317
+ }
318
+ ```
319
+
320
+ ### Streaming AI Response
321
+
322
+ ```tsx
323
+ function AIChat() {
324
+ const { invoke, isLoading, streamingText, result } = useEntityInvocation();
325
+ const [input, setInput] = useState('');
326
+
327
+ return (
328
+ <div>
329
+ <textarea value={input} onChange={e => setInput(e.target.value)} />
330
+ <button onClick={() => invoke({ entityId: 'ent_abc', input })} disabled={isLoading}>
331
+ Send
332
+ </button>
333
+ <div>{isLoading ? streamingText : result?.output}</div>
334
+ </div>
335
+ );
336
+ }
337
+ ```
338
+
339
+ ### Persistent Settings
340
+
341
+ ```tsx
342
+ function Settings() {
343
+ const [settings, setSettings] = usePersistentState('settings', {
344
+ notifications: true,
345
+ fontSize: 14,
346
+ });
347
+
348
+ return (
349
+ <label>
350
+ <input
351
+ type="checkbox"
352
+ checked={settings.notifications}
353
+ onChange={e => setSettings({ ...settings, notifications: e.target.checked })}
354
+ />
355
+ Notifications
356
+ </label>
357
+ );
358
+ }
359
+ ```
@@ -0,0 +1,359 @@
1
+ # FIAS Plugin Development Guide
2
+
3
+ This project is a FIAS platform plugin — a React application that runs in a sandboxed iframe within the FIAS marketplace. This file provides the context AI coding assistants need to build, test, and submit plugins effectively.
4
+
5
+ For other AI tool instruction files, see `AGENTS.md` (identical content).
6
+
7
+ ## Project Structure
8
+
9
+ ```
10
+ fias-plugin.json # Plugin manifest (required) — name, permissions, pricing, AI configs
11
+ package.json # Dependencies and scripts
12
+ src/
13
+ index.tsx # Entry point — must render into #root with <FiasProvider> wrapper
14
+ App.tsx # Main component
15
+ vite.config.ts # Vite dev server config (port 3100)
16
+ ```
17
+
18
+ ## SDK API Reference
19
+
20
+ All hooks require the app to be wrapped in `<FiasProvider>`:
21
+
22
+ ```tsx
23
+ import { FiasProvider } from '@fias/arche-sdk';
24
+
25
+ ReactDOM.createRoot(document.getElementById('root')!).render(
26
+ <FiasProvider>
27
+ <App />
28
+ </FiasProvider>
29
+ );
30
+ ```
31
+
32
+ ### `useFiasTheme()` — Platform theme tokens
33
+
34
+ **Permission:** `theme:read`
35
+ **Returns:** `FiasTheme | null` (null while loading)
36
+
37
+ ```tsx
38
+ import { useFiasTheme } from '@fias/arche-sdk';
39
+
40
+ function MyComponent() {
41
+ const theme = useFiasTheme();
42
+ if (!theme) return null;
43
+
44
+ return (
45
+ <div style={{
46
+ color: theme.colors.text,
47
+ backgroundColor: theme.colors.background,
48
+ fontFamily: theme.fonts.body,
49
+ padding: theme.spacing.md,
50
+ borderRadius: theme.components.cardRadius,
51
+ }}>
52
+ {theme.mode === 'dark' ? 'Dark mode' : 'Light mode'}
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ **FiasTheme shape:**
59
+ - `mode`: `'light' | 'dark'`
60
+ - `colors`: `{ primary, primaryText, secondary, accent, background, surface, card, cardText, text, textSecondary, muted, mutedText, border, error, warning, success, info }`
61
+ - `spacing`: `{ xs, sm, md, lg, xl }` (CSS values like `'8px'`)
62
+ - `fonts`: `{ body, heading, mono }` (font-family strings)
63
+ - `components`: `{ borderRadius, buttonRadius, cardRadius, inputRadius, shadowSm, shadowMd, shadowLg, borderWidth }`
64
+
65
+ ### `useFiasUser()` — Current user profile
66
+
67
+ **Permission:** `user:profile:read`
68
+ **Returns:** `FiasUser | null`
69
+
70
+ ```tsx
71
+ import { useFiasUser } from '@fias/arche-sdk';
72
+
73
+ const user = useFiasUser();
74
+ // { userId: string, displayName: string, avatar: string | null }
75
+ ```
76
+
77
+ ### `useFiasStorage()` — Sandboxed file storage
78
+
79
+ **Permission:** `storage:sandbox`
80
+ **Returns:** `FiasStorageApi`
81
+
82
+ ```tsx
83
+ import { useFiasStorage } from '@fias/arche-sdk';
84
+
85
+ const { readFile, writeFile, listFiles, deleteFile } = useFiasStorage();
86
+
87
+ await writeFile('data/settings.json', JSON.stringify(settings));
88
+ const content = await readFile('data/settings.json'); // string | null
89
+ const files = await listFiles('data/'); // string[]
90
+ await deleteFile('data/old.json');
91
+ ```
92
+
93
+ ### `useEntityInvocation()` — Invoke AI entities
94
+
95
+ **Permission:** `entities:invoke`
96
+ **Returns:** `EntityInvocationApi`
97
+
98
+ ```tsx
99
+ import { useEntityInvocation } from '@fias/arche-sdk';
100
+
101
+ function AISummarizer() {
102
+ const { invoke, isLoading, result, error, streamingText } = useEntityInvocation();
103
+
104
+ async function summarize(text: string) {
105
+ await invoke({ entityId: 'ent_abc123', input: text });
106
+ }
107
+
108
+ return (
109
+ <div>
110
+ <button onClick={() => summarize('...')} disabled={isLoading}>
111
+ Summarize
112
+ </button>
113
+ {isLoading && <p>{streamingText}</p>}
114
+ {result && <p>{result.output}</p>}
115
+ {error && <p>Error: {error.message}</p>}
116
+ </div>
117
+ );
118
+ }
119
+ ```
120
+
121
+ The `entityId` references a published entity on the platform. Browse available entities with `npx fias-dev entities`.
122
+
123
+ ### `useFiasNavigation()` — In-plugin routing
124
+
125
+ **Permission:** None required
126
+ **Returns:** `FiasNavigationApi`
127
+
128
+ ```tsx
129
+ import { useFiasNavigation } from '@fias/arche-sdk';
130
+
131
+ const { navigateTo, currentPath } = useFiasNavigation();
132
+ navigateTo('/settings');
133
+ ```
134
+
135
+ ### `useStepNavigation()` — Multi-step workflows
136
+
137
+ **Returns:** `StepNavigationApi`
138
+
139
+ ```tsx
140
+ import { useStepNavigation } from '@fias/arche-sdk';
141
+
142
+ const { currentStep, setCurrentStep } = useStepNavigation('step-1');
143
+ ```
144
+
145
+ ### `usePersistentState()` — Auto-saving state
146
+
147
+ **Permission:** `storage:sandbox`
148
+
149
+ ```tsx
150
+ import { usePersistentState } from '@fias/arche-sdk';
151
+
152
+ const [count, setCount] = usePersistentState<number>('counter', 0);
153
+ // Automatically persists to storage on change
154
+ ```
155
+
156
+ ### `fias` — Imperative utilities
157
+
158
+ ```tsx
159
+ import { fias } from '@fias/arche-sdk';
160
+
161
+ fias.resize(800); // Resize iframe height
162
+ fias.showToast('Saved!', 'success'); // Toast: 'info' | 'success' | 'warning' | 'error'
163
+ ```
164
+
165
+ ## Manifest Reference (`fias-plugin.json`)
166
+
167
+ ```json
168
+ {
169
+ "name": "my-plugin",
170
+ "version": "1.0.0",
171
+ "description": "What this plugin does",
172
+ "main": "src/index.tsx",
173
+ "archeType": "tool",
174
+ "tags": ["utility"],
175
+ "pricing": { "model": "free", "currency": "usd" },
176
+ "permissions": ["theme:read", "entities:invoke"],
177
+ "sdk": "^1.0.0",
178
+ "dependencies": { "recharts": "2.15.0" },
179
+ "aiConfigs": [
180
+ {
181
+ "configId": "summarizer",
182
+ "label": "Text Summarizer",
183
+ "entityId": "ent_abc123",
184
+ "systemPrompt": "Summarize the input concisely.",
185
+ "parameters": { "temperature": 0.3, "maxTokens": 500 }
186
+ }
187
+ ]
188
+ }
189
+ ```
190
+
191
+ **Fields:**
192
+
193
+ | Field | Required | Description |
194
+ |----------------|----------|-------------|
195
+ | `name` | Yes | Plugin identifier (lowercase, hyphens) |
196
+ | `version` | Yes | Semver (e.g., `"1.0.0"`) |
197
+ | `description` | Yes | Short marketplace description |
198
+ | `main` | Yes | Entry point source file |
199
+ | `archeType` | Yes | `"tool"` or `"site"` |
200
+ | `tags` | No | Discovery tags |
201
+ | `pricing` | Yes | `{ model: "free" | "fixed" | "per_use" | "tiered" }` |
202
+ | `permissions` | Yes | Array of permission scopes |
203
+ | `sdk` | Yes | SDK version range |
204
+ | `dependencies` | No | npm packages with **exact** versions (max 20) |
205
+ | `aiConfigs` | No | AI entity configurations (see below) |
206
+
207
+ **Permissions:** `theme:read`, `user:profile:read`, `storage:sandbox`, `entities:invoke`
208
+
209
+ **AI Configs:** Declare entity invocations the plugin will use. Each config's `entityId` must reference a published prompt entity. Browse entities with `npx fias-dev entities`. Requires `entities:invoke` permission.
210
+
211
+ ## Plugin Constraints
212
+
213
+ These are hard limits enforced by the platform. Code that violates these will fail review or be blocked at runtime.
214
+
215
+ ### Sandboxing
216
+ - Plugins run in an iframe with `sandbox="allow-scripts allow-forms allow-same-origin"`
217
+ - **No `fetch()` or `XMLHttpRequest`** — all network access is blocked
218
+ - **No access** to parent DOM, cookies, or localStorage
219
+ - **No external scripts or stylesheets** — everything must be bundled
220
+ - All platform communication goes through the bridge (SDK hooks)
221
+
222
+ ### Size and File Limits
223
+ - **Bundle size:** Max 5 MB compressed
224
+ - **Dependencies:** Max 20, exact semver versions only (e.g., `"4.4.7"`, not `"^4.4.7"`)
225
+ - Platform packages (`react`, `react-dom`, `@fias/arche-sdk`) are provided — do not include in `dependencies`
226
+
227
+ ### Rate Limits
228
+ - `entity_invoke`: 60/minute
229
+ - `storage_write`: 120/minute
230
+ - `storage_read`: 300/minute
231
+ - `storage_list`, `storage_delete`: 60/minute
232
+
233
+ ### Security Rules (enforced during review)
234
+ - No `eval()`, `Function()`, `innerHTML`, or dynamic code execution
235
+ - No attempts to escape the iframe sandbox
236
+ - No credential collection or dark patterns
237
+ - No obfuscated code
238
+ - No accessing `window.parent`, `window.top`, or `document.cookie`
239
+
240
+ ## Styling Guidelines
241
+
242
+ - Always use `useFiasTheme()` for colors, fonts, and spacing — never hardcode
243
+ - Support both light and dark modes (check `theme.mode`)
244
+ - Use `theme.components.cardRadius`, `theme.components.shadowMd`, etc. for consistent component styling
245
+ - The plugin renders at full width inside the platform layout
246
+
247
+ ## Development Workflow
248
+
249
+ ```bash
250
+ # Terminal 1: Start plugin dev server (Vite, port 3100)
251
+ npm run dev
252
+
253
+ # Terminal 2: Start dev harness (mock mode, port 3200)
254
+ npm run dev:mock
255
+
256
+ # Open http://localhost:3200 in browser
257
+ ```
258
+
259
+ ### Authenticating with the FIAS Platform
260
+
261
+ ```bash
262
+ npx fias-dev login # Opens browser to authenticate (recommended)
263
+ npx fias-dev login --key fias_sk_... # Or paste an API key directly
264
+ ```
265
+
266
+ Running `npx fias-dev login` opens your browser to the FIAS platform. After signing in, an API key is created automatically and saved to `~/.fias/credentials`. No manual key copying needed.
267
+
268
+ ### Testing with Real AI Entities (costs credits)
269
+
270
+ ```bash
271
+ npm run dev:harness # Start harness in live mode (requires login first)
272
+ ```
273
+
274
+ ### Browsing Available Entities
275
+
276
+ ```bash
277
+ npx fias-dev entities # List all
278
+ npx fias-dev entities --search "text" # Search by keyword
279
+ npx fias-dev entities --type "prompt" # Filter by type
280
+ ```
281
+
282
+ ### Validating the Manifest
283
+
284
+ ```bash
285
+ npx fias-dev validate
286
+ ```
287
+
288
+ ### Submitting to the Arche Store
289
+
290
+ ```bash
291
+ npm run submit
292
+ # Builds, validates, packages, uploads, submits for AI review
293
+ # First listing: 5000 credits ($50). Re-submissions: 100 credits ($1).
294
+ ```
295
+
296
+ ## Common Patterns
297
+
298
+ ### Theme-Aware Card Component
299
+
300
+ ```tsx
301
+ function Card({ children }: { children: React.ReactNode }) {
302
+ const theme = useFiasTheme();
303
+ if (!theme) return null;
304
+
305
+ return (
306
+ <div style={{
307
+ backgroundColor: theme.colors.card,
308
+ color: theme.colors.cardText,
309
+ borderRadius: theme.components.cardRadius,
310
+ boxShadow: theme.components.shadowMd,
311
+ border: `${theme.components.borderWidth} solid ${theme.colors.border}`,
312
+ padding: theme.spacing.lg,
313
+ }}>
314
+ {children}
315
+ </div>
316
+ );
317
+ }
318
+ ```
319
+
320
+ ### Streaming AI Response
321
+
322
+ ```tsx
323
+ function AIChat() {
324
+ const { invoke, isLoading, streamingText, result } = useEntityInvocation();
325
+ const [input, setInput] = useState('');
326
+
327
+ return (
328
+ <div>
329
+ <textarea value={input} onChange={e => setInput(e.target.value)} />
330
+ <button onClick={() => invoke({ entityId: 'ent_abc', input })} disabled={isLoading}>
331
+ Send
332
+ </button>
333
+ <div>{isLoading ? streamingText : result?.output}</div>
334
+ </div>
335
+ );
336
+ }
337
+ ```
338
+
339
+ ### Persistent Settings
340
+
341
+ ```tsx
342
+ function Settings() {
343
+ const [settings, setSettings] = usePersistentState('settings', {
344
+ notifications: true,
345
+ fontSize: 14,
346
+ });
347
+
348
+ return (
349
+ <label>
350
+ <input
351
+ type="checkbox"
352
+ checked={settings.notifications}
353
+ onChange={e => setSettings({ ...settings, notifications: e.target.checked })}
354
+ />
355
+ Notifications
356
+ </label>
357
+ );
358
+ }
359
+ ```