@fluencypassdevs/cycle 1.17.0 → 1.18.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/bin/cli.mjs CHANGED
@@ -12,6 +12,8 @@ const command = process.argv[2]
12
12
 
13
13
  if (command === "mcp") {
14
14
  await import("./mcp.mjs")
15
+ } else if (command === "propose") {
16
+ await import("./propose.mjs")
15
17
  } else if (command === "init" || !command) {
16
18
  await import("./init.mjs")
17
19
  } else {
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * `npx cycle propose <arquivo>` — propõe um componente ao Design System a partir
5
+ * do PRÓPRIO projeto do dev, sem abrir o GitHub na mão.
6
+ *
7
+ * Lê o componente (idealmente de `src/components/ds-proposals/`), pergunta o
8
+ * contexto, e abre a issue "Proposta de Componente" no repo do DS via `gh`
9
+ * (login do próprio dev — todos são da org). Se o `gh` não existir, cai num
10
+ * fallback: salva o corpo num arquivo + imprime um link pré-preenchido.
11
+ *
12
+ * Flags: --name, --what, --where, --preview (não-interativo) · --dry-run (só imprime).
13
+ */
14
+
15
+ import fs from "fs"
16
+ import path from "path"
17
+ import { execFileSync, spawnSync } from "child_process"
18
+ import { createInterface } from "readline"
19
+
20
+ // ── Config específica do DS (o pulse tem a sua) ──
21
+ const DS = {
22
+ label: "Cycle",
23
+ repo: "Fluencypass/Cycle",
24
+ surfaceHint: "Tela de produto (app logado, painel, aula)",
25
+ }
26
+
27
+ const argv = process.argv.slice(2)
28
+ const flags = {}
29
+ const positionals = []
30
+ for (let i = 0; i < argv.length; i++) {
31
+ const a = argv[i]
32
+ if (a === "--dry-run") flags.dryRun = true
33
+ else if (a.startsWith("--")) flags[a.slice(2)] = argv[++i]
34
+ else positionals.push(a)
35
+ }
36
+
37
+ function fail(msg) {
38
+ console.error(`\n ✗ ${msg}\n`)
39
+ process.exit(1)
40
+ }
41
+
42
+ // 1. Arquivo do componente
43
+ let file = positionals[0]
44
+ if (!file) {
45
+ // tenta achar candidatos em ds-proposals/
46
+ const dir = path.join(process.cwd(), "src/components/ds-proposals")
47
+ const found = fs.existsSync(dir) ? fs.readdirSync(dir).filter((f) => /\.(tsx|jsx|ts)$/.test(f)) : []
48
+ if (found.length === 1) file = path.join(dir, found[0])
49
+ else if (found.length > 1) fail(`Vários candidatos em ds-proposals/. Especifique: npx cycle propose <arquivo>\n ${found.join("\n ")}`)
50
+ else fail("Uso: npx cycle propose <caminho-do-componente> (ex.: src/components/ds-proposals/meu-card.tsx)")
51
+ }
52
+ if (!fs.existsSync(file)) fail(`Arquivo não encontrado: ${file}`)
53
+ const code = fs.readFileSync(file, "utf-8")
54
+
55
+ // 2. Metadados (flags ou prompt)
56
+ const rl = createInterface({ input: process.stdin, output: process.stdout })
57
+ const ask = (q, def) =>
58
+ new Promise((res) => rl.question(` ${q}${def ? ` (${def})` : ""}: `, (a) => res(a.trim() || def || "")))
59
+
60
+ const name = flags.name || path.basename(file).replace(/\.(tsx|jsx|ts)$/, "")
61
+
62
+ console.log(`\n Propor componente ao ${DS.label} Design System\n ─────────────────────────────────────────────\n`)
63
+
64
+ const what = flags.what || (await ask("O que ele faz? (1 frase)"))
65
+ const where = flags.where || (await ask("Onde ele aparece?", DS.surfaceHint))
66
+ const preview = flags.preview || (await ask("Link de preview ou screenshot (opcional)"))
67
+ rl.close()
68
+
69
+ // 3. Corpo da issue
70
+ const title = `[Proposta] ${name}`
71
+ const body = `## Componente
72
+ **${name}**
73
+
74
+ ## O que faz
75
+ ${what || "(não informado)"}
76
+
77
+ ## Onde aparece
78
+ ${where}
79
+
80
+ ## Preview
81
+ ${preview || "(anexar print/link)"}
82
+
83
+ ## Código
84
+ \`\`\`tsx
85
+ ${code}
86
+ \`\`\`
87
+
88
+ ---
89
+ _Proposto via \`npx cycle propose\` a partir de um projeto consumidor._`
90
+
91
+ // 4. dry-run
92
+ if (flags.dryRun) {
93
+ console.log(`\n [dry-run] Issue que seria criada em ${DS.repo}:\n`)
94
+ console.log(` Título: ${title}`)
95
+ console.log(` Label: ds-proposal\n`)
96
+ console.log(body.split("\n").map((l) => " │ " + l).join("\n"))
97
+ console.log("")
98
+ process.exit(0)
99
+ }
100
+
101
+ // 5. Cria a issue via gh (ou fallback)
102
+ const hasGh = spawnSync("gh", ["--version"], { stdio: "ignore" }).status === 0
103
+ if (hasGh) {
104
+ const tmp = path.join(process.cwd(), `.ds-proposal-${name}.md`)
105
+ fs.writeFileSync(tmp, body)
106
+ try {
107
+ const url = execFileSync(
108
+ "gh",
109
+ ["issue", "create", "--repo", DS.repo, "--title", title, "--label", "ds-proposal", "--body-file", tmp],
110
+ { encoding: "utf-8" }
111
+ ).trim()
112
+ fs.unlinkSync(tmp)
113
+ console.log(`\n ✓ Proposta enviada! ${url}\n Você será notificado quando for revisada.\n`)
114
+ } catch (err) {
115
+ fs.unlinkSync(tmp)
116
+ fail(`Falha ao criar a issue via gh (${err.message}). Rode \`gh auth login\` e tente de novo, ou use o fallback abaixo.`)
117
+ }
118
+ } else {
119
+ const out = path.join(process.cwd(), `ds-proposal-${name}.md`)
120
+ fs.writeFileSync(out, body)
121
+ const url = `https://github.com/${DS.repo}/issues/new?labels=ds-proposal&title=${encodeURIComponent(title)}`
122
+ console.log(`\n 'gh' não encontrado. Fallback:\n`)
123
+ console.log(` 1. Corpo salvo em: ${out}`)
124
+ console.log(` 2. Abra: ${url}`)
125
+ console.log(` 3. Cole o conteúdo do arquivo no corpo da issue.\n`)
126
+ console.log(` (Instale o GitHub CLI — https://cli.github.com — pra automatizar isso.)\n`)
127
+ }
@@ -157,6 +157,24 @@ Todos importados de `@fluencypassdevs/cycle`:
157
157
  | ProductLogo, ClassLogo, PrivateTalkLogo, GroupTalkLogo | Logos dos produtos |
158
158
  | CycleIcon | Wrapper para icones Lucide |
159
159
 
160
+ ## Precisa de um componente que o DS nao tem?
161
+
162
+ O DS **nao trava** o projeto. Se um componente REALMENTE nao existe (confirme antes com
163
+ `cycle_search_component` ou o catalogo), voce pode cria-lo — seguindo estas regras:
164
+
165
+ 1. Crie em **`src/components/ds-proposals/`** (marcador de "candidato ao DS"), NAO em
166
+ `components/ui/`. O componente ja funciona e pode ser usado no projeto.
167
+ 2. Componha com os atomos que ja existem (Button, Input...) e use SO tokens semanticos
168
+ (`bg-brand`, `text-muted-foreground`) — nunca cor/spacing hardcoded.
169
+ 3. Se for reutilizavel por outros projetos, **proponha a entrada no DS** rodando no projeto:
170
+ \`npx cycle propose src/components/ds-proposals/<arquivo>\` (abre a issue automaticamente via
171
+ gh). Fallback manual: https://github.com/Fluencypass/Cycle/issues/new/choose. Guia:
172
+ https://design.fluencypass.com/cycle/contribuir
173
+
174
+ **Regra de superficie**: o DS certo depende de ONDE o componente renderiza — tela de produto
175
+ (app logado) = **Cycle**; landing/campanha de marketing = **Pulse**. Nunca misture os dois no
176
+ mesmo render; um componente que falta flui pra camada certa por triagem, sem cross-import.
177
+
160
178
  ## MCP Server (Claude Code)
161
179
 
162
180
  Se o projeto tem `.mcp.json` configurado, o Claude Code tera acesso a tools do Cycle:
@@ -174,5 +192,7 @@ Para configurar: `npx cycle init`
174
192
 
175
193
  ## Documentacao
176
194
 
177
- - **Componentes**: https://cycle-design.fluencypass.com/docs/components
178
- - **Tokens**: https://cycle-design.fluencypass.com/docs/tokens
195
+ - **Portal**: https://design.fluencypass.com (escolha Cycle ou Pulse)
196
+ - **Componentes (Cycle)**: https://design.fluencypass.com/cycle/components
197
+ - **Tokens (Cycle)**: https://design.fluencypass.com/cycle/tokens
198
+ - **Contribuir (propor componente)**: https://design.fluencypass.com/cycle/contribuir
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluencypassdevs/cycle",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "Cycle Design System — UI component library by Fluencypass (produto)",
5
5
  "license": "MIT",
6
6
  "repository": {