guford-ui 0.1.0 → 0.2.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.
Files changed (2) hide show
  1. package/bin.mjs +72 -27
  2. package/package.json +1 -1
package/bin.mjs CHANGED
@@ -30,8 +30,9 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
30
30
  const ROOT = resolve(__dirname, '..'); // racine du dépôt guford-ui (mode local)
31
31
  const CONFIG_FILE = 'guford-ui.json';
32
32
 
33
- // Base distante par défaut (à adapter après publication : GitHub raw, host statique…).
34
- const DEFAULT_REMOTE = 'https://raw.githubusercontent.com/bekmarc/guford-ui/main';
33
+ // Dépôt GitHub par défaut (privé lu via l'API Contents avec token).
34
+ const DEFAULT_REPO = 'bekmarc/guford-ui';
35
+ const DEFAULT_REF = 'main';
35
36
 
36
37
  // --- couleurs ANSI ---------------------------------------------------------
37
38
  const c = {
@@ -48,42 +49,72 @@ function fail(msg) {
48
49
  process.exit(1);
49
50
  }
50
51
 
51
- // --- source du registry (local FS ou URL distante) -------------------------
52
+ // --- source du registry (local FS | URL statique | API GitHub privée) ------
52
53
  /**
53
- * @param {{registry?: string}} flags
54
- * @returns {{remote: boolean, base: string}}
54
+ * Résout la source du registry. 3 modes :
55
+ * - 'local' : fichiers du dépôt (exécution depuis quitus-ui/guford-ui)
56
+ * - 'url' : base HTTP statique (--registry / $GUFORD_UI_REGISTRY), token facultatif
57
+ * - 'github' : dépôt GitHub privé via l'API Contents (--repo/--ref + token requis)
55
58
  */
56
59
  function resolveSource(flags) {
60
+ const token = flags.token || process.env.GUFORD_UI_TOKEN || process.env.GITHUB_TOKEN;
57
61
  const explicit = flags.registry || process.env.GUFORD_UI_REGISTRY;
58
- if (explicit) return { remote: true, base: explicit.replace(/\/+$/, '') };
59
- if (existsSync(join(ROOT, 'registry.json'))) return { remote: false, base: ROOT };
60
- return { remote: true, base: DEFAULT_REMOTE };
62
+ if (explicit) return { kind: 'url', base: explicit.replace(/\/+$/, ''), token };
63
+ if (!flags.repo && existsSync(join(ROOT, 'registry.json'))) return { kind: 'local', base: ROOT };
64
+ return { kind: 'github', repo: flags.repo || DEFAULT_REPO, ref: flags.ref || DEFAULT_REF, token };
65
+ }
66
+
67
+ function sourceUrl(source, rel) {
68
+ if (source.kind === 'url') return `${source.base}/${rel}`;
69
+ // GitHub Contents API : renvoie le contenu brut (texte + binaire) avec Accept: raw
70
+ return `https://api.github.com/repos/${source.repo}/contents/${rel}?ref=${source.ref}`;
71
+ }
72
+
73
+ function sourceHeaders(source) {
74
+ const h = { 'User-Agent': 'guford-ui-cli' };
75
+ if (source.kind === 'github') {
76
+ if (!source.token)
77
+ fail(
78
+ 'Dépôt privé : un token est requis.\n' +
79
+ ' → crée un PAT GitHub (Contents: read) puis: set GUFORD_UI_TOKEN=<token>\n' +
80
+ ' (ou passe --token <token>, ou utilise --registry <url-publique>)',
81
+ );
82
+ h.Authorization = `Bearer ${source.token}`;
83
+ h.Accept = 'application/vnd.github.raw';
84
+ } else if (source.token) {
85
+ h.Authorization = `Bearer ${source.token}`;
86
+ }
87
+ return h;
88
+ }
89
+
90
+ async function fetchEntry(source, rel) {
91
+ const url = sourceUrl(source, rel);
92
+ const res = await fetch(url, { headers: sourceHeaders(source) });
93
+ if (!res.ok) {
94
+ const hint = res.status === 404 ? ' (introuvable, ou token sans accès au dépôt privé)' : '';
95
+ fail(`Téléchargement échoué (${res.status})${hint} : ${url}`);
96
+ }
97
+ return Buffer.from(await res.arrayBuffer());
61
98
  }
62
99
 
63
100
  /** Lit un fichier texte du registry (chemin relatif à la racine, ex: 'registry.json'). */
64
101
  async function readText(source, rel) {
65
- if (source.remote) {
66
- const url = `${source.base}/${rel}`;
67
- const res = await fetch(url);
68
- if (!res.ok) fail(`Téléchargement échoué (${res.status}) : ${url}`);
69
- return await res.text();
102
+ if (source.kind === 'local') {
103
+ const path = join(source.base, rel);
104
+ if (!existsSync(path)) fail(`Fichier introuvable: ${path}`);
105
+ return readFileSync(path, 'utf8');
70
106
  }
71
- const path = join(source.base, rel);
72
- if (!existsSync(path)) fail(`Fichier introuvable: ${path}`);
73
- return readFileSync(path, 'utf8');
107
+ return (await fetchEntry(source, rel)).toString('utf8');
74
108
  }
75
109
 
76
110
  /** Lit un fichier (texte ou binaire) du registry → Buffer. */
77
111
  async function readBuffer(source, rel) {
78
- if (source.remote) {
79
- const url = `${source.base}/${rel}`;
80
- const res = await fetch(url);
81
- if (!res.ok) fail(`Téléchargement échoué (${res.status}) : ${url}`);
82
- return Buffer.from(await res.arrayBuffer());
112
+ if (source.kind === 'local') {
113
+ const path = join(source.base, rel);
114
+ if (!existsSync(path)) fail(`Fichier introuvable: ${path}`);
115
+ return readFileSync(path);
83
116
  }
84
- const path = join(source.base, rel);
85
- if (!existsSync(path)) fail(`Fichier introuvable: ${path}`);
86
- return readFileSync(path);
117
+ return await fetchEntry(source, rel);
87
118
  }
88
119
 
89
120
  async function loadRegistry(source) {
@@ -122,7 +153,10 @@ function loadProjectConfig(cwd) {
122
153
  // --- parseur d'arguments ---------------------------------------------------
123
154
  function parseArgs(argv) {
124
155
  const positionals = [];
125
- const flags = { cwd: '.', dir: undefined, overwrite: false, dryRun: false, registry: undefined };
156
+ const flags = {
157
+ cwd: '.', dir: undefined, overwrite: false, dryRun: false,
158
+ registry: undefined, token: undefined, repo: undefined, ref: undefined,
159
+ };
126
160
  for (let i = 0; i < argv.length; i++) {
127
161
  const a = argv[i];
128
162
  if (a === '--overwrite') flags.overwrite = true;
@@ -130,6 +164,9 @@ function parseArgs(argv) {
130
164
  else if (a === '--cwd') flags.cwd = argv[++i];
131
165
  else if (a === '--dir') flags.dir = argv[++i];
132
166
  else if (a === '--registry') flags.registry = argv[++i];
167
+ else if (a === '--token') flags.token = argv[++i];
168
+ else if (a === '--repo') flags.repo = argv[++i];
169
+ else if (a === '--ref') flags.ref = argv[++i];
133
170
  else if (a.startsWith('--')) fail(`Option inconnue: ${a}`);
134
171
  else positionals.push(a);
135
172
  }
@@ -137,7 +174,9 @@ function parseArgs(argv) {
137
174
  }
138
175
 
139
176
  function sourceLabel(source) {
140
- return source.remote ? c.dim(`(registry distant: ${source.base})`) : c.dim('(registry local)');
177
+ if (source.kind === 'local') return c.dim('(registry local)');
178
+ if (source.kind === 'url') return c.dim(`(registry: ${source.base})`);
179
+ return c.dim(`(registry GitHub: ${source.repo}@${source.ref})`);
141
180
  }
142
181
 
143
182
  // --- commandes -------------------------------------------------------------
@@ -321,9 +360,15 @@ function help() {
321
360
  ${c.cyan('Options:')}
322
361
  --cwd <path> Projet cible (défaut: .)
323
362
  --dir <path> Racine d'installation (défaut: guford-ui.json puis src)
324
- --registry <url> Base distante du registry (sinon $GUFORD_UI_REGISTRY, sinon local)
363
+ --registry <url> Base HTTP statique du registry (sinon $GUFORD_UI_REGISTRY)
364
+ --repo <owner/repo> Dépôt GitHub (défaut: ${DEFAULT_REPO})
365
+ --ref <branch|tag> Réf GitHub (défaut: ${DEFAULT_REF}) — pin sur un tag pour reproductibilité
366
+ --token <token> Token GitHub pour dépôt privé (sinon $GUFORD_UI_TOKEN / $GITHUB_TOKEN)
325
367
  --overwrite Écrase les fichiers existants
326
368
  --dry-run Simule sans écrire
369
+
370
+ ${c.cyan('Dépôt privé:')} crée un PAT GitHub (Contents: read), puis
371
+ ${c.dim('set GUFORD_UI_TOKEN=<token> # Windows (cmd) | $env:GUFORD_UI_TOKEN="<token>" (PowerShell)')}
327
372
  `);
328
373
  }
329
374
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guford-ui",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "CLI pour installer les composants du registry guford-ui (façon shadcn).",
5
5
  "type": "module",
6
6
  "bin": {