@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 +2 -0
- package/bin/propose.mjs +127 -0
- package/cli/CLAUDE-section.md +22 -2
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
package/bin/propose.mjs
ADDED
|
@@ -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
|
+
}
|
package/cli/CLAUDE-section.md
CHANGED
|
@@ -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
|
-
- **
|
|
178
|
-
- **
|
|
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
|