sinapse-ai 1.25.3 → 1.26.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.
@@ -10,8 +10,16 @@ not as a black-box library.
10
10
 
11
11
  ## Locate the corpus
12
12
 
13
- Resolve the SINAPSE package/repository root, then read
14
- `docs/framework/react-bits/index.md`. Read only the category needed:
13
+ Resolve the corpus in this exact order, then read `index.md` from the first
14
+ location that contains the complete corpus:
15
+
16
+ 1. `<project>/docs/framework/react-bits/`
17
+ 2. `<installed-package>/docs/framework/react-bits/`
18
+ 3. `~/.sinapse/docs/framework/react-bits/`
19
+
20
+ The project location wins so a project can pin or extend its installed research.
21
+ The package location supports package-managed runs, and the global SINAPSE home
22
+ supports `--global-only` installs. Read only the category needed:
15
23
 
16
24
  - `animations.md` for wrappers, cursors, trails, transitions and interactive effects.
17
25
  - `text-animations.md` for headline, counter, scramble, marquee and reveal work.
@@ -21,8 +29,9 @@ Resolve the SINAPSE package/repository root, then read
21
29
  - `audit-findings.md` when dependency, prop, variant or upstream accuracy matters.
22
30
  - `inventory.json` for exact machine-readable props, dependencies and variant state.
23
31
 
24
- If the corpus cannot be found, read `references/corpus-map.md`, then verify current
25
- facts against the official registry and source before implementation.
32
+ If none of those locations has all nine files, state which locations were checked,
33
+ ask the user to run the relevant SINAPSE install/update, then verify current facts
34
+ against the official registry and source before implementation.
26
35
 
27
36
  ## Workflow
28
37
 
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "version": 1,
3
3
  "skillIds": [
4
+ "react-bits-frontend",
4
5
  "sinapse",
5
6
  "sinapse-agent",
6
7
  "sinapse-analyst",
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: react-bits-frontend
3
+ description: Select, install, adapt, combine, optimize, and audit official React Bits components for React, Next.js, Vite, Astro islands, and SINAPSE frontend projects. Use for animated text, cursors, reveals, cards, navigation, galleries, WebGL backgrounds, shaders, particles, motion systems, React Bits CLI/MCP commands, component props/dependencies, or when improving an existing page with React Bits while preserving accessibility, mobile performance, lifecycle cleanup, design-system fit, and license compliance.
4
+ ---
5
+
6
+ # React Bits Frontend
7
+
8
+ Use the source-grounded SINAPSE corpus to implement React Bits as application code,
9
+ not as a black-box library.
10
+
11
+ ## Locate the corpus
12
+
13
+ Resolve the corpus in this exact order, then read `index.md` from the first
14
+ location that contains the complete corpus:
15
+
16
+ 1. `<project>/docs/framework/react-bits/`
17
+ 2. `<installed-package>/docs/framework/react-bits/`
18
+ 3. `~/.sinapse/docs/framework/react-bits/`
19
+
20
+ The project location wins so a project can pin or extend its installed research.
21
+ The package location supports package-managed runs, and the global SINAPSE home
22
+ supports `--global-only` installs. Read only the category needed:
23
+
24
+ - `animations.md` for wrappers, cursors, trails, transitions and interactive effects.
25
+ - `text-animations.md` for headline, counter, scramble, marquee and reveal work.
26
+ - `components.md` for cards, navigation, galleries, inputs and compound UI.
27
+ - `backgrounds.md` for Canvas/WebGL/shader/particle backgrounds.
28
+ - `implementation-playbook.md` for integration, composition, accessibility and tuning.
29
+ - `audit-findings.md` when dependency, prop, variant or upstream accuracy matters.
30
+ - `inventory.json` for exact machine-readable props, dependencies and variant state.
31
+
32
+ If none of those locations has all nine files, state which locations were checked,
33
+ ask the user to run the relevant SINAPSE install/update, then verify current facts
34
+ against the official registry and source before implementation.
35
+
36
+ ## Workflow
37
+
38
+ 1. Inspect the target stack, component architecture, design tokens, performance budget
39
+ and existing animation/scroll ownership.
40
+ 2. Translate the visual request into a user-experience function.
41
+ 3. Search the relevant catalog and shortlist at most three candidates.
42
+ 4. Compare visual fit, dependencies, runtime engine, props, interaction model,
43
+ accessibility, mobile cost and compatibility with existing effects.
44
+ 5. Open the official source for the selected variant. Treat source and registry as
45
+ authoritative when docs conflict.
46
+ 6. Run `npm view <package>` for every declared dependency before installing it.
47
+ 7. Prefer TS-TW or TS-CSS in TypeScript projects. Never use the three empty CurvedInput
48
+ variants recorded in the snapshot; use JS-CSS or verify that upstream fixed them.
49
+ 8. Install through shadcn/jsrepo or copy manually. Keep upstream provenance and the
50
+ required license notice for substantial copies.
51
+ 9. Wrap the imported component behind a local application component. Map design
52
+ tokens, content, breakpoints and quality presets at that boundary.
53
+ 10. Implement reduced-motion behavior, semantic fallback, keyboard/focus behavior,
54
+ cleanup and static/mobile fallback.
55
+ 11. Test load, resize, route unmount/remount, long scroll, coarse pointer, reduced
56
+ motion and low-power mobile. Measure frame time and memory.
57
+ 12. Report component, variant, source SHA/URL, dependencies, adaptations, fallbacks and
58
+ remaining risks.
59
+
60
+ ## Composition rules
61
+
62
+ - Use one dominant motion effect per viewport and no more than two support effects.
63
+ - Prefer the lowest-cost engine that satisfies the visual objective.
64
+ - Allow only one owner for smooth scroll, custom cursor and each render loop.
65
+ - Do not stack multiple heavy WebGL/physics backgrounds without an explicit budget.
66
+ - Pause offscreen/hidden loops and dispose GPU resources on unmount.
67
+ - Preserve content and interaction when animation is disabled or fails.
68
+
69
+ ## Accuracy rules
70
+
71
+ - Do not repeat the promotional “140+” as an exact count. The pinned snapshot has 139.
72
+ - Do not infer functional variants from registry names alone; inspect source bytes/code.
73
+ - Use registry JSON for install dependencies and source for actual API/behavior.
74
+ - Note documentation typos and per-variant divergences from `audit-findings.md`.
75
+ - Do not redistribute React Bits components as a standalone library, bundle, or port.
@@ -34,6 +34,10 @@ function isPathInside(parentPath, candidatePath) {
34
34
  return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
35
35
  }
36
36
 
37
+ function isSafeSkillId(skillId) {
38
+ return typeof skillId === 'string' && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(skillId);
39
+ }
40
+
37
41
  function readCanonicalSource(projectRoot, sourcePath) {
38
42
  if (!sourcePath) {
39
43
  throw new Error('Codex agent pointer does not declare a canonical source');
@@ -329,6 +333,14 @@ function readCodexCatalog(projectRoot = PROJECT_ROOT) {
329
333
  if (typeof catalog.genericAgentSkillId !== 'string' || !catalog.genericAgentSkillId.trim()) {
330
334
  throw new Error('Codex catalog does not declare genericAgentSkillId');
331
335
  }
336
+ const catalogSkillIds = [
337
+ ...catalog.expectedSkillIds,
338
+ ...catalog.publicAliasSkillIds,
339
+ catalog.genericAgentSkillId,
340
+ ];
341
+ if (catalogSkillIds.some((skillId) => !isSafeSkillId(skillId))) {
342
+ throw new Error('Codex catalog contains an unsafe skill ID');
343
+ }
332
344
  return catalog;
333
345
  }
334
346
 
@@ -7,7 +7,7 @@
7
7
  # - SHA256 hashes for change detection
8
8
  # - File types for categorization
9
9
  #
10
- version: 1.25.3
10
+ version: 1.26.0
11
11
  generator: scripts/generate-install-manifest.js
12
12
  file_count: 1156
13
13
  files:
package/CHANGELOG.md CHANGED
@@ -1,8 +1,17 @@
1
- ## [1.25.3](https://github.com/caioimori/sinapse-ai/compare/1.25.2...1.25.3) (2026-07-15)
1
+ ## [1.26.0](https://github.com/caioimori/sinapse-ai/compare/1.25.3...1.26.0) (2026-07-15)
2
+
3
+ ### Features
4
+
5
+ * deliver React Bits across providers [Story react-bits-distribution-parity] ([aa191f1](https://github.com/caioimori/sinapse-ai/commit/aa191f102dc417e3a0182c02661907e474226abb))
2
6
 
3
7
  ### Bug Fixes
4
8
 
5
- * **installer:** restore provider adapter parity ([#385](https://github.com/caioimori/sinapse-ai/issues/385)) ([4c5c9fb](https://github.com/caioimori/sinapse-ai/commit/4c5c9fb1a60e5d8610da08f25f6f01a67a85a063))
9
+ * **docs:** align provider skill metrics [Story react-bits-distribution-parity] ([729d120](https://github.com/caioimori/sinapse-ai/commit/729d120ee1735473d01971efdb746be59d2d19d8))
10
+ * **react-bits:** harden corpus delivery and orchestration [Story react-bits-distribution-parity] ([6456062](https://github.com/caioimori/sinapse-ai/commit/6456062cd756826e6bc14c698ebde07298d8a5eb))
11
+
12
+ ### Documentation
13
+
14
+ * close installer parity release evidence [Story hotfix-installer-provider-adapter-parity-1.25.3] ([#386](https://github.com/caioimori/sinapse-ai/issues/386)) ([ceafcb8](https://github.com/caioimori/sinapse-ai/commit/ceafcb8ac522835c264115e9ee16cba6e49e173c))
6
15
 
7
16
  # Changelog
8
17
 
package/README.en.md CHANGED
@@ -309,7 +309,7 @@ Both IDEs have access to all 17 squads, 172 agents, workflows, and knowledge bas
309
309
  | Native agents | 172 | 172 |
310
310
  | Direct activation | `@agent-name` | `$sinapse-agent agent-id` |
311
311
  | Primary routing | `@sinapse-orqx` | `$snps` |
312
- | Installed skills | 36 | 37 |
312
+ | Installed skills | 37 | 37 |
313
313
  | Registered hooks | 20 native registrations | 9 lifecycle events through the bridge |
314
314
  | Validation source | `npm run validate:providers` | `npm run validate:codex-native` |
315
315
 
package/README.md CHANGED
@@ -331,7 +331,7 @@ Ambas as IDEs têm acesso a todos os 17 squads, 172 agentes, workflows e knowled
331
331
  | Agentes nativos | 172 | 172 |
332
332
  | Ativação direta | `@agent-name` | `$sinapse-agent agent-id` |
333
333
  | Roteamento principal | `@sinapse-orqx` | `$snps` |
334
- | Skills instaladas | 36 | 37 |
334
+ | Skills instaladas | 37 | 37 |
335
335
  | Hooks registrados | 20 registros nativos | 9 eventos de lifecycle via bridge |
336
336
  | Fonte de validação | `npm run validate:providers` | `npm run validate:codex-native` |
337
337
 
@@ -50,6 +50,10 @@ const {
50
50
  } = require('../lib/command-generator');
51
51
  const { deliverGlobalProviderAdapters, getGlobalCommandStagingDir } = require('../lib/global-provider-adapters');
52
52
  const { assertProviderAdapterParity } = require('../lib/provider-parity');
53
+ const {
54
+ copyReactBitsCapabilitySync,
55
+ REACT_BITS_SKILL_RELATIVE_PATH,
56
+ } = require('../../packages/installer/src/installer/react-bits-corpus');
53
57
  // Follow-up #13 — wire the transactional backup/rollback engine into the
54
58
  // installer so an in-place UPGRADE (upsert) that fails mid-flight is restored
55
59
  // to its previous state instead of leaving ~/.sinapse half-updated.
@@ -317,7 +321,12 @@ async function cmdInstallGlobal(opts = {}) {
317
321
  // rich, frontmatter'd stubs are always the final word. Idempotent.
318
322
  try {
319
323
  const commandsDir = getGlobalCommandStagingDir({ llmChoice, sinapseHome: SINAPSE_HOME, claudeCommandsDir: CLAUDE_COMMANDS_DIR });
320
- const reconciled = deliverGlobalProviderAdapters({ llmChoice, home: HOME, commandsDir });
324
+ const reconciled = deliverGlobalProviderAdapters({
325
+ llmChoice,
326
+ home: HOME,
327
+ commandsDir,
328
+ reactBitsSkillPath: path.join(SINAPSE_HOME, REACT_BITS_SKILL_RELATIVE_PATH),
329
+ });
321
330
  const total = reconciled.claude.length + reconciled.codex.length + reconciled.skills.length;
322
331
  if (total) logger.always(` ${GREEN}OK${NC} Global provider adapters reconciled (${total} artifacts)`);
323
332
  } catch (e) {
@@ -557,6 +566,9 @@ function installFatalPhases({ squads, squadsDir, isUpsert, llmChoice, existing,
557
566
  logger.always(` ${GREEN}OK${NC} core development (${coreAgents} agents)`);
558
567
  }
559
568
 
569
+ const reactBits = copyReactBitsCapabilitySync(ROOT, SINAPSE_HOME);
570
+ if (reactBits.files.length) logger.always(` ${GREEN}OK${NC} React Bits corpus (${reactBits.files.length} files)`);
571
+
560
572
  // Phase 2: Generate agent commands (shared with `update` via command-generator).
561
573
  logger.always(`\n${CYAN}Phase 2:${NC} Generating agent commands`);
562
574
  const commandStagingDir = getGlobalCommandStagingDir({ llmChoice, sinapseHome: SINAPSE_HOME, claudeCommandsDir: CLAUDE_COMMANDS_DIR });
@@ -570,7 +582,12 @@ function installFatalPhases({ squads, squadsDir, isUpsert, llmChoice, existing,
570
582
  logger.always(` ${GREEN}OK${NC} ${writtenAgents.size} total command files`);
571
583
 
572
584
  // Phase 2b: Install global agents based on LLM choice
573
- const globalAdapters = deliverGlobalProviderAdapters({ llmChoice, home: HOME, commandsDir: commandStagingDir });
585
+ const globalAdapters = deliverGlobalProviderAdapters({
586
+ llmChoice,
587
+ home: HOME,
588
+ commandsDir: commandStagingDir,
589
+ reactBitsSkillPath: path.join(SINAPSE_HOME, REACT_BITS_SKILL_RELATIVE_PATH),
590
+ });
574
591
  const activeAgentCount = assertProviderAdapterParity(
575
592
  llmChoice,
576
593
  globalAdapters,
@@ -170,7 +170,7 @@ function removeOrqxAgentsFrom(dir) {
170
170
  return removeInstalledAgentsFrom(dir);
171
171
  }
172
172
 
173
- const MANAGED_GLOBAL_SKILL_IDS = ['snps', 'sinapse', 'snps-orqx', 'sinapse-orqx', 'sinapse-agent'];
173
+ const MANAGED_GLOBAL_SKILL_IDS = ['snps', 'sinapse', 'snps-orqx', 'sinapse-orqx', 'sinapse-agent', 'react-bits-frontend'];
174
174
  const MANAGED_GLOBAL_SKILL_MARKER = 'SINAPSE-MANAGED:global-skill';
175
175
 
176
176
  function removeManagedGlobalSkills(home = HOME, options = {}) {
@@ -36,6 +36,10 @@ const {
36
36
  } = require('./uninstall');
37
37
  const { regenerateAgentCommands } = require('../lib/command-generator');
38
38
  const { deliverGlobalProviderAdapters, getGlobalCommandStagingDir } = require('../lib/global-provider-adapters');
39
+ const {
40
+ copyReactBitsCapabilitySync,
41
+ REACT_BITS_SKILL_RELATIVE_PATH,
42
+ } = require('../../packages/installer/src/installer/react-bits-corpus');
39
43
  const { assertProviderAdapterParity } = require('../lib/provider-parity');
40
44
  const { execSync } = require('child_process');
41
45
 
@@ -164,6 +168,9 @@ async function cmdUpdateGlobal() {
164
168
  logger.always(` ${GREEN}OK${NC} core development`);
165
169
  }
166
170
 
171
+ const reactBits = copyReactBitsCapabilitySync(ROOT, SINAPSE_HOME);
172
+ if (reactBits.files.length) logger.always(` ${GREEN}OK${NC} React Bits corpus (${reactBits.files.length} files)`);
173
+
167
174
  // Phase 2: Regenerate commands — shared with `install` so `update` produces the
168
175
  // SAME complete set (every specialist command + the rich master Imperator stubs),
169
176
  // not just the `-orqx` subset it used to write.
@@ -180,7 +187,12 @@ async function cmdUpdateGlobal() {
180
187
  logger.always(` ${GREEN}OK${NC} ${writtenAgents.size} command files (${totalAgents} agents total)`);
181
188
 
182
189
  // Phase 2b: Install global agents based on LLM choice
183
- const globalAdapters = deliverGlobalProviderAdapters({ llmChoice, home: HOME, commandsDir: commandStagingDir });
190
+ const globalAdapters = deliverGlobalProviderAdapters({
191
+ llmChoice,
192
+ home: HOME,
193
+ commandsDir: commandStagingDir,
194
+ reactBitsSkillPath: path.join(SINAPSE_HOME, REACT_BITS_SKILL_RELATIVE_PATH),
195
+ });
184
196
  const activeAgentCount = assertProviderAdapterParity(
185
197
  llmChoice,
186
198
  globalAdapters,
@@ -6,6 +6,7 @@ const crypto = require('crypto');
6
6
  const {
7
7
  MASTER_ALIAS_ENTRY_POINTS,
8
8
  GLOBAL_PROVIDER_SKILL_IDS,
9
+ GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS,
9
10
  SUPREME_ORCHESTRATOR_ID,
10
11
  SUPREME_PUBLIC_ID,
11
12
  } = require('./provider-contract');
@@ -102,7 +103,11 @@ function markGlobalAgent(markdown, fileName = '') {
102
103
  return `${content.trimEnd()}\n\n<!-- SINAPSE-MANAGED:global-agent -->\n`;
103
104
  }
104
105
 
105
- function renderGlobalSkill(skillId) {
106
+ function renderGlobalSkill(skillId, sourceContent = null) {
107
+ if (skillId === 'react-bits-frontend') {
108
+ if (!sourceContent) throw new Error('React Bits global skill source is required');
109
+ return `${String(sourceContent).trimEnd()}\n\n<!-- SINAPSE-MANAGED:global-skill -->\n`;
110
+ }
106
111
  const generic = skillId === 'sinapse-agent';
107
112
  return [
108
113
  '---',
@@ -264,9 +269,9 @@ function writeGlobalSkillIfManaged(skillPath, content, home = path.dirname(skill
264
269
  }
265
270
  }
266
271
 
267
- function isValidGlobalSkill(skillId, skillPath) {
272
+ function isValidGlobalSkill(skillId, skillPath, sourceContent = null) {
268
273
  const content = readRegularFileNoFollowSync(skillPath, 'utf8');
269
- return content !== null && content === renderGlobalSkill(skillId);
274
+ return content !== null && content === renderGlobalSkill(skillId, sourceContent);
270
275
  }
271
276
 
272
277
  function removeStaleManagedAgents(targetDir, expectedFiles, extension, options = {}) {
@@ -318,7 +323,7 @@ function removeManagedFileWithBinding(home, filePath, beforeDelete) {
318
323
  }
319
324
  }
320
325
 
321
- function deliverGlobalProviderAdapters({ llmChoice, home, commandsDir, testHooks = {} }) {
326
+ function deliverGlobalProviderAdapters({ llmChoice, home, commandsDir, reactBitsSkillPath, testHooks = {} }) {
322
327
  let commandFiles = fs.existsSync(commandsDir)
323
328
  ? fs.readdirSync(commandsDir).filter((file) => file.endsWith('.md')).sort()
324
329
  : [];
@@ -334,6 +339,13 @@ function deliverGlobalProviderAdapters({ llmChoice, home, commandsDir, testHooks
334
339
  skills: [],
335
340
  availableSkills: [],
336
341
  };
342
+ let reactBitsSkillContent = null;
343
+ const providerSkillIds = [...GLOBAL_PROVIDER_SKILL_IDS];
344
+ if (reactBitsSkillPath) {
345
+ reactBitsSkillContent = readRegularFileNoFollowSync(reactBitsSkillPath, 'utf8');
346
+ if (reactBitsSkillContent === null) throw new Error(`React Bits global skill is missing: ${reactBitsSkillPath}`);
347
+ providerSkillIds.push(...GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS);
348
+ }
337
349
 
338
350
  if (llmChoice === 'claude-code' || llmChoice === 'both') {
339
351
  const targetDir = path.join(home, '.claude', 'agents');
@@ -345,12 +357,12 @@ function deliverGlobalProviderAdapters({ llmChoice, home, commandsDir, testHooks
345
357
  written.claude.push(file);
346
358
  }
347
359
  const skillsRoot = path.join(home, '.claude', 'skills');
348
- for (const skillId of GLOBAL_PROVIDER_SKILL_IDS) {
360
+ for (const skillId of providerSkillIds) {
349
361
  const skillPath = path.join(skillsRoot, skillId, 'SKILL.md');
350
- if (writeGlobalSkillIfManaged(skillPath, renderGlobalSkill(skillId), home, { beforePublish: testHooks.beforeSkillPublish })) {
362
+ if (writeGlobalSkillIfManaged(skillPath, renderGlobalSkill(skillId, reactBitsSkillContent), home, { beforePublish: testHooks.beforeSkillPublish })) {
351
363
  written.claudeSkills.push(skillId);
352
364
  }
353
- if (isValidGlobalSkill(skillId, skillPath)) written.claudeAvailableSkills.push(skillId);
365
+ if (isValidGlobalSkill(skillId, skillPath, reactBitsSkillContent)) written.claudeAvailableSkills.push(skillId);
354
366
  }
355
367
  }
356
368
  if (llmChoice === 'codex' || llmChoice === 'both') {
@@ -373,13 +385,13 @@ function deliverGlobalProviderAdapters({ llmChoice, home, commandsDir, testHooks
373
385
  written.codex.push(tomlName);
374
386
  }
375
387
  const skillsRoot = path.join(home, '.agents', 'skills');
376
- for (const skillId of GLOBAL_PROVIDER_SKILL_IDS) {
388
+ for (const skillId of providerSkillIds) {
377
389
  const skillDir = path.join(skillsRoot, skillId);
378
390
  const skillPath = path.join(skillDir, 'SKILL.md');
379
- if (writeGlobalSkillIfManaged(skillPath, renderGlobalSkill(skillId), home, { beforePublish: testHooks.beforeSkillPublish })) {
391
+ if (writeGlobalSkillIfManaged(skillPath, renderGlobalSkill(skillId, reactBitsSkillContent), home, { beforePublish: testHooks.beforeSkillPublish })) {
380
392
  written.skills.push(skillId);
381
393
  }
382
- if (isValidGlobalSkill(skillId, skillPath)) written.availableSkills.push(skillId);
394
+ if (isValidGlobalSkill(skillId, skillPath, reactBitsSkillContent)) written.availableSkills.push(skillId);
383
395
  }
384
396
  }
385
397
  return written;
@@ -13,6 +13,7 @@ const GLOBAL_PROVIDER_SKILL_IDS = Object.freeze([
13
13
  SUPREME_ORCHESTRATOR_ID,
14
14
  'sinapse-agent',
15
15
  ]);
16
+ const GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS = Object.freeze(['react-bits-frontend']);
16
17
 
17
18
  module.exports = {
18
19
  CANONICAL_AGENT_COUNT,
@@ -20,4 +21,5 @@ module.exports = {
20
21
  SUPREME_PUBLIC_ID,
21
22
  MASTER_ALIAS_ENTRY_POINTS,
22
23
  GLOBAL_PROVIDER_SKILL_IDS,
24
+ GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS,
23
25
  };
@@ -3,8 +3,14 @@
3
3
  const {
4
4
  CANONICAL_AGENT_COUNT,
5
5
  GLOBAL_PROVIDER_SKILL_IDS,
6
+ GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS,
6
7
  } = require('./provider-contract');
7
8
 
9
+ const REQUIRED_GLOBAL_PROVIDER_SKILL_IDS = Object.freeze([
10
+ ...GLOBAL_PROVIDER_SKILL_IDS,
11
+ ...GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS,
12
+ ]);
13
+
8
14
  function normalizeCanonicalCatalog(canonicalCatalog, extension) {
9
15
  if (!canonicalCatalog || typeof canonicalCatalog === 'number') {
10
16
  throw new Error('Provider adapter parity requires the canonical agent ID catalog');
@@ -55,14 +61,14 @@ function assertProviderAdapterParity(llmChoice, adapters, canonicalCatalog) {
55
61
  if (llmChoice === 'claude-code' || llmChoice === 'both') {
56
62
  problems.push(...describeCatalogDivergence('Claude Code', adapters.claude, claudeCatalog));
57
63
  const claudeSkills = new Set(adapters.claudeAvailableSkills || adapters.claudeSkills || []);
58
- const missingAliases = GLOBAL_PROVIDER_SKILL_IDS.filter((alias) => !claudeSkills.has(alias));
59
- if (missingAliases.length) problems.push(`Claude Code alias skills missing: ${missingAliases.join(', ')}`);
64
+ const missingSkills = REQUIRED_GLOBAL_PROVIDER_SKILL_IDS.filter((skillId) => !claudeSkills.has(skillId));
65
+ if (missingSkills.length) problems.push(`Claude Code global skills missing: ${missingSkills.join(', ')}`);
60
66
  }
61
67
  if (llmChoice === 'codex' || llmChoice === 'both') {
62
68
  problems.push(...describeCatalogDivergence('Codex', adapters.codex, codexCatalog));
63
69
  const codexSkills = new Set(adapters.availableSkills || adapters.skills || []);
64
- const missingAliases = GLOBAL_PROVIDER_SKILL_IDS.filter((alias) => !codexSkills.has(alias));
65
- if (missingAliases.length) problems.push(`Codex alias skills missing: ${missingAliases.join(', ')}`);
70
+ const missingSkills = REQUIRED_GLOBAL_PROVIDER_SKILL_IDS.filter((skillId) => !codexSkills.has(skillId));
71
+ if (missingSkills.length) problems.push(`Codex global skills missing: ${missingSkills.join(', ')}`);
66
72
  }
67
73
  if (problems.length) {
68
74
  throw new Error(`Provider adapter parity failed (${problems.join('; ')})`);
@@ -70,4 +76,4 @@ function assertProviderAdapterParity(llmChoice, adapters, canonicalCatalog) {
70
76
  return claudeCatalog.count;
71
77
  }
72
78
 
73
- module.exports = { assertProviderAdapterParity };
79
+ module.exports = { assertProviderAdapterParity, REQUIRED_GLOBAL_PROVIDER_SKILL_IDS };
@@ -32,7 +32,7 @@ Both providers expose native lifecycle surfaces. Their registration models diffe
32
32
  | Measured surface | Claude Code | Codex CLI |
33
33
  | --- | --- | --- |
34
34
  | Native agents | 172 | 172 |
35
- | Installed skills | 36 | 37 |
35
+ | Installed skills | 37 | 37 |
36
36
  | Registered hooks | 20 native registrations | 9 lifecycle events through the bridge |
37
37
  | Activation | `@agent-name` | `$snps` or `$sinapse-agent <id>` |
38
38
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sinapse-ai",
3
- "version": "1.25.3",
3
+ "version": "1.26.0",
4
4
  "description": "SINAPSE AI: Framework de orquestracao de IA — 17 squads, 172 agentes especializados",
5
5
  "bin": {
6
6
  "sinapse": "bin/sinapse.js",
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const REACT_BITS_CORPUS_RELATIVE_PATH = path.join('docs', 'framework', 'react-bits');
7
+ const REACT_BITS_SKILL_RELATIVE_PATH = path.join('.agents', 'skills', 'react-bits-frontend', 'SKILL.md');
8
+ const REQUIRED_REACT_BITS_CORPUS_FILES = Object.freeze([
9
+ 'animations.md',
10
+ 'audit-findings.md',
11
+ 'backgrounds.md',
12
+ 'catalog-summary.json',
13
+ 'components.md',
14
+ 'implementation-playbook.md',
15
+ 'index.md',
16
+ 'inventory.json',
17
+ 'text-animations.md',
18
+ ]);
19
+
20
+ function isRegularFile(filePath) {
21
+ try {
22
+ return fs.lstatSync(filePath).isFile();
23
+ } catch (error) {
24
+ if (error.code === 'ENOENT') return false;
25
+ throw error;
26
+ }
27
+ }
28
+
29
+ function listFilesRecursively(directory, root = directory) {
30
+ if (!fs.existsSync(directory)) return [];
31
+ return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
32
+ const sourcePath = path.join(directory, entry.name);
33
+ if (entry.isDirectory()) return listFilesRecursively(sourcePath, root);
34
+ return isRegularFile(sourcePath) ? [path.relative(root, sourcePath)] : [];
35
+ });
36
+ }
37
+
38
+ function getMissingReactBitsCorpusFiles(root) {
39
+ return REQUIRED_REACT_BITS_CORPUS_FILES.filter((file) => !isRegularFile(
40
+ path.join(root, REACT_BITS_CORPUS_RELATIVE_PATH, file),
41
+ ));
42
+ }
43
+
44
+ /**
45
+ * Copy only the shipped React Bits corpus. Existing destination-only files are
46
+ * intentionally left untouched so a project or global installation never
47
+ * deletes user research alongside the managed corpus.
48
+ */
49
+ function copyReactBitsCorpusSync(sourceRoot, destinationRoot) {
50
+ const source = path.join(sourceRoot, REACT_BITS_CORPUS_RELATIVE_PATH);
51
+ const destination = path.join(destinationRoot, REACT_BITS_CORPUS_RELATIVE_PATH);
52
+ const missingFiles = getMissingReactBitsCorpusFiles(sourceRoot);
53
+ if (missingFiles.length > 0) {
54
+ throw new Error(`Incomplete React Bits corpus source: ${missingFiles.join(', ')}`);
55
+ }
56
+ const files = listFilesRecursively(source);
57
+ for (const relativePath of files) {
58
+ const target = path.join(destination, relativePath);
59
+ fs.mkdirSync(path.dirname(target), { recursive: true });
60
+ fs.copyFileSync(path.join(source, relativePath), target);
61
+ }
62
+ return files.map((relativePath) => path.join(REACT_BITS_CORPUS_RELATIVE_PATH, relativePath));
63
+ }
64
+
65
+ function hasCompleteReactBitsCorpus(root) {
66
+ return getMissingReactBitsCorpusFiles(root).length === 0;
67
+ }
68
+
69
+ /** Copy the corpus plus its canonical skill into a global SINAPSE home. */
70
+ function copyReactBitsCapabilitySync(sourceRoot, destinationRoot) {
71
+ const files = copyReactBitsCorpusSync(sourceRoot, destinationRoot);
72
+ const sourceSkill = path.join(sourceRoot, REACT_BITS_SKILL_RELATIVE_PATH);
73
+ const destinationSkill = path.join(destinationRoot, REACT_BITS_SKILL_RELATIVE_PATH);
74
+ if (!fs.existsSync(sourceSkill)) throw new Error(`Missing React Bits skill: ${sourceSkill}`);
75
+ fs.mkdirSync(path.dirname(destinationSkill), { recursive: true });
76
+ fs.copyFileSync(sourceSkill, destinationSkill);
77
+ return { files, skillPath: destinationSkill };
78
+ }
79
+
80
+ module.exports = {
81
+ REACT_BITS_CORPUS_RELATIVE_PATH,
82
+ REACT_BITS_SKILL_RELATIVE_PATH,
83
+ REQUIRED_REACT_BITS_CORPUS_FILES,
84
+ isRegularFile,
85
+ listFilesRecursively,
86
+ getMissingReactBitsCorpusFiles,
87
+ copyReactBitsCorpusSync,
88
+ copyReactBitsCapabilitySync,
89
+ hasCompleteReactBitsCorpus,
90
+ };
@@ -14,6 +14,7 @@ const path = require('path');
14
14
  const crypto = require('crypto');
15
15
  const ora = require('ora');
16
16
  const { hashFile } = require('./file-hasher');
17
+ const { copyReactBitsCorpusSync } = require('./react-bits-corpus');
17
18
 
18
19
  const NOFOLLOW_READ_FLAGS = nativeFs.constants.O_RDONLY | (nativeFs.constants.O_NOFOLLOW || 0);
19
20
 
@@ -705,6 +706,13 @@ async function installSinapseCore(options = {}) {
705
706
  if (claudeSettings) result.installedFiles.push(claudeSettings);
706
707
  }
707
708
 
709
+ if (includeClaude || includeCodex) {
710
+ spinner.text = 'Copying React Bits corpus...';
711
+ const corpusFiles = copyReactBitsCorpusSync(pkgRoot, targetDir);
712
+ result.reactBitsCorpusFiles = corpusFiles.length;
713
+ result.installedFiles.push(...corpusFiles);
714
+ }
715
+
708
716
  // AGENTS.md is the Codex CLI's default context file (Imperator greeting +
709
717
  // the full agent roster). It lives at the package ROOT (not under .codex/ or
710
718
  // .sinapse-ai/), so neither loop above reaches it. Without it, a Codex user's
@@ -878,6 +886,7 @@ module.exports = {
878
886
  deliverClaudeNativeAdapters,
879
887
  getClaudeHookName,
880
888
  reconcileClaudeHookSettings,
889
+ copyReactBitsCorpusSync,
881
890
  FOLDERS_TO_COPY,
882
891
  ROOT_FILES_TO_COPY,
883
892
  CODEX_ROOT_FILES,
@@ -11,10 +11,12 @@ const {
11
11
  syncCodexNativeAgents,
12
12
  } = require('../.codex/scripts/sync-codex-native');
13
13
  const { resolveCodexAgent } = require('../.codex/scripts/resolve-codex-agent');
14
+ const { GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS } = require('../bin/lib/provider-contract');
14
15
 
15
16
  const PROJECT_ROOT = path.resolve(__dirname, '..');
16
17
  const CLAUDE_AGENTS_DIR = '.claude/agents';
17
18
  const CLAUDE_SKILLS_DIR = '.claude/skills';
19
+ const SUPPLEMENTAL_PROVIDER_SKILL_IDS = GLOBAL_SUPPLEMENTAL_PROVIDER_SKILL_IDS;
18
20
 
19
21
  function writeFileAtomically(filePath, content) {
20
22
  const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
@@ -136,11 +138,13 @@ function collectClaudeSkills(projectRoot = PROJECT_ROOT) {
136
138
  catalog.genericAgentSkillId,
137
139
  ])].sort();
138
140
 
139
- return skillIds.map((skillId) => {
141
+ return [...new Set([...skillIds, ...SUPPLEMENTAL_PROVIDER_SKILL_IDS])].sort().map((skillId) => {
140
142
  const nativePath = path.join(projectRoot, '.agents', 'skills', skillId, 'SKILL.md');
141
143
  const metadata = parseSkillMetadata(fs.readFileSync(nativePath, 'utf8'));
142
144
  let content;
143
- if (skillId === catalog.genericAgentSkillId) {
145
+ if (SUPPLEMENTAL_PROVIDER_SKILL_IDS.includes(skillId)) {
146
+ content = fs.readFileSync(nativePath, 'utf8');
147
+ } else if (skillId === catalog.genericAgentSkillId) {
144
148
  content = renderClaudeGenericSkill(skillId, metadata.description);
145
149
  } else if (skillId === 'sinapse-loop' || skillId === 'sinapse-spec-driven') {
146
150
  content = renderClaudeWorkflowSkill(skillId, metadata.description);
@@ -195,6 +199,7 @@ if (require.main === module) main();
195
199
  module.exports = {
196
200
  CLAUDE_AGENTS_DIR,
197
201
  CLAUDE_SKILLS_DIR,
202
+ SUPPLEMENTAL_PROVIDER_SKILL_IDS,
198
203
  claudeAgentFileName,
199
204
  renderClaudeAgent,
200
205
  collectClaudeSkills,
@@ -8,6 +8,11 @@ const yaml = require('js-yaml');
8
8
  const legacyClaudeCommandHashes = require('../packages/installer/src/migrations/legacy-claude-agent-command-hashes.json');
9
9
 
10
10
  const { validateNativeCodex } = require('../.codex/scripts/validate-codex-native');
11
+ const {
12
+ REACT_BITS_CORPUS_RELATIVE_PATH,
13
+ REQUIRED_REACT_BITS_CORPUS_FILES,
14
+ hasCompleteReactBitsCorpus,
15
+ } = require('../packages/installer/src/installer/react-bits-corpus');
11
16
 
12
17
  const PROJECT_ROOT = path.resolve(__dirname, '..');
13
18
 
@@ -125,10 +130,13 @@ function validateClaudeNative(projectRoot = PROJECT_ROOT) {
125
130
  try {
126
131
  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
127
132
  expectedSkills = (manifest.skillIds || []).map((skillId) => ({ skillId }));
128
- if (expectedSkills.length !== 36) errors.push(`Claude skill manifest must contain 36 IDs, found ${expectedSkills.length}`);
133
+ if (expectedSkills.length !== 37) errors.push(`Claude skill manifest must contain 37 IDs, found ${expectedSkills.length}`);
129
134
  for (const alias of ['sinapse', 'sinapse-orqx', 'snps', 'snps-orqx', 'sinapse-agent']) {
130
135
  if (!manifest.skillIds.includes(alias)) errors.push(`Claude skill manifest is missing public alias ${alias}`);
131
136
  }
137
+ if (!manifest.skillIds.includes('react-bits-frontend')) {
138
+ errors.push('Claude skill manifest is missing react-bits-frontend');
139
+ }
132
140
  } catch (error) {
133
141
  errors.push(`Claude skill manifest: ${error.message}`);
134
142
  }
@@ -209,6 +217,17 @@ function validateProviderAdapters(projectRoot = PROJECT_ROOT) {
209
217
  if (!pkg.files.includes(entry)) errors.push(`package.json files[] is missing ${entry}`);
210
218
  }
211
219
  if (pkg.files.includes('.codex/skills/')) errors.push('package.json must not publish the legacy .codex/skills root');
220
+ if (!hasCompleteReactBitsCorpus(projectRoot)) {
221
+ errors.push(`React Bits corpus is incomplete: expected ${REQUIRED_REACT_BITS_CORPUS_FILES.length} files under ${REACT_BITS_CORPUS_RELATIVE_PATH}`);
222
+ }
223
+ for (const relativePath of [
224
+ path.join('.agents', 'skills', 'react-bits-frontend', 'SKILL.md'),
225
+ path.join('.claude', 'skills', 'react-bits-frontend', 'SKILL.md'),
226
+ ]) {
227
+ if (!fs.existsSync(path.join(projectRoot, relativePath))) {
228
+ errors.push(`React Bits provider skill is missing: ${relativePath}`);
229
+ }
230
+ }
212
231
  return {
213
232
  ok: errors.length === 0,
214
233
  errors,
@@ -240,4 +259,5 @@ module.exports = {
240
259
  validateClaudeHookSettings,
241
260
  validateClaudeNative,
242
261
  validateProviderAdapters,
262
+ REQUIRED_REACT_BITS_CORPUS_FILES,
243
263
  };
@@ -28,6 +28,8 @@ Kinetic e o diretor da squad. Recebe os Animation Briefs do Decoder (animation-i
28
28
  - Garantir coesao entre animacoes de diferentes agentes
29
29
  - Orquestrar o workflow prompt-to-animation-cycle
30
30
  - Gerar relatorios de entrega
31
+ - Roteiar trabalho React Bits pelo task `orchestrate-react-bits-frontend` e pelo
32
+ corpus operacional antes de delegar implementacao
31
33
 
32
34
  ## Pipeline de Orquestracao
33
35
 
@@ -64,6 +66,7 @@ Kinetic → Review final → Entrega
64
66
  | Hover effects | css-motion-artist | shader-artist |
65
67
  | Loading animations | css-motion-artist | motion-choreographer |
66
68
  | Camera movements 3D | threejs-architect | motion-choreographer |
69
+ | React Bits frontend | orchestrate-react-bits-frontend | animation-performance-engineer |
67
70
 
68
71
  ## Criterios de Qualidade
69
72
 
@@ -86,6 +89,7 @@ Toda animacao deve passar por:
86
89
  | Definir timing e coreografia | motion-choreographer (Tempo) |
87
90
  | Implementar scroll animation | scroll-narrative-engineer (Parallax) |
88
91
  | Criar sistema de particulas | generative-particle-engineer (Cloud) |
92
+ | Orquestrar frontend React Bits | orchestrate-react-bits-frontend |
89
93
  | Otimizar performance | animation-performance-engineer (Benchmark) |
90
94
 
91
95
  ## NON-NEGOTIABLE: ORCHESTRATE, DON'T EXECUTE
@@ -135,6 +139,9 @@ integration:
135
139
  - agent: "animation-performance-engineer (Benchmark)"
136
140
  when: "Quality gate before delivery — perf audit, 60fps validation, mobile check"
137
141
  context_passed: "all built animations, target devices, perf budget"
142
+ - agent: "orchestrate-react-bits-frontend"
143
+ when: "Frontend request that needs React Bits discovery, selection, installation or implementation"
144
+ context_passed: "project stack, target surface, desired interaction, accessibility and performance constraints"
138
145
  receives_from:
139
146
  - agent: "@sinapse-orqx (Imperator)"
140
147
  when: "Animation/motion request routed from ecosystem"
@@ -23,7 +23,7 @@ metadata:
23
23
  total_files: 116
24
24
  agents: 9
25
25
  tasks: 76
26
- workflows: 0
26
+ workflows: 5
27
27
  knowledge_bases: 16
28
28
  checklists: 3
29
29
  templates: 5