brand-intent 0.1.5 → 0.1.7

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/cli/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
3
+ import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
4
4
  import { join, dirname, resolve } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { createInterface } from 'readline';
@@ -44,6 +44,45 @@ function ask(q) {
44
44
  return new Promise((res) => rl().question(q, res));
45
45
  }
46
46
 
47
+ // ── File operations ──
48
+
49
+ function copyDirRecursive(src, dest) {
50
+ mkdirSync(dest, { recursive: true });
51
+ for (const entry of readdirSync(src)) {
52
+ const srcPath = join(src, entry);
53
+ const destPath = join(dest, entry);
54
+ if (statSync(srcPath).isDirectory()) {
55
+ copyDirRecursive(srcPath, destPath);
56
+ } else {
57
+ copyFileSync(srcPath, destPath);
58
+ }
59
+ }
60
+ }
61
+
62
+ function scaffoldExample(targetDir) {
63
+ const brandSrc = join(PKG_ROOT, 'brands', 'krume');
64
+ const exampleDest = join(targetDir, 'examples', 'krume');
65
+
66
+ copyDirRecursive(brandSrc, exampleDest);
67
+
68
+ const layers = [
69
+ { layer: 'formats', file: 'instagram-4-5-feed-portrait.format' },
70
+ { layer: 'purposes', file: 'daily-bread.purpose' },
71
+ { layer: 'compositions', file: 'editorial.composition' },
72
+ ];
73
+
74
+ for (const { layer, file } of layers) {
75
+ const src = join(PKG_ROOT, layer, file);
76
+ if (existsSync(src)) {
77
+ const dest = join(exampleDest, layer, file);
78
+ mkdirSync(dirname(dest), { recursive: true });
79
+ copyFileSync(src, dest);
80
+ }
81
+ }
82
+
83
+ console.log(' \u2713 examples/krume/ \u2014 reference implementation (identity, brand, format, purpose, composition)');
84
+ }
85
+
47
86
  // ── Install skill ──
48
87
 
49
88
  async function installSkills(cwd) {
@@ -107,30 +146,25 @@ if (!command || command === '--help' || command === '-h') {
107
146
  process.exit(0);
108
147
  }
109
148
 
110
- // Both "init" and "install-skills" do the same thing now
111
- const installed = await installSkills(cwd);
112
- closeRl();
149
+ // Ask for project folder
150
+ console.log(' Brand Intent \u2014 What a brand means. Authored, structured, shared.\n');
151
+ const folder = await ask(' Project folder (. for current directory): ');
152
+ const targetDir = resolve(cwd, folder.trim() || '.');
153
+ if (targetDir !== cwd) {
154
+ mkdirSync(targetDir, { recursive: true });
155
+ }
156
+ console.log('');
113
157
 
114
- // Show next steps with skill-specific commands
115
- const hasClaudeCode = installed.some(h => h.id === 'claude');
116
- const hasCursor = installed.some(h => h.id === 'cursor');
158
+ scaffoldExample(targetDir);
159
+ await installSkills(targetDir);
160
+ closeRl();
117
161
 
118
162
  console.log('\n Done. Now open your AI agent and try:\n');
119
163
  console.log(' "Onboard my brand"');
120
164
  console.log(' "Show me the Krume bakery example"');
121
-
122
- if (hasClaudeCode || hasCursor) {
123
- console.log('\n Or use the skill directly:\n');
124
- if (hasClaudeCode) {
125
- console.log(' /brand-intent onboard Create your brand through a guided interview');
126
- console.log(' /brand-intent example Scaffold the Krume reference implementation');
127
- console.log(' /brand-intent validate Validate content against your brand rules');
128
- console.log(' /brand-intent Discover brand files and available purposes');
129
- }
130
- if (hasCursor) {
131
- console.log(' @brand-intent onboard Create your brand through a guided interview');
132
- console.log(' @brand-intent example Scaffold the Krume reference implementation');
133
- }
134
- }
135
-
165
+ console.log('\n Skill commands:\n');
166
+ console.log(' /brand-intent onboard Create your brand through a guided interview');
167
+ console.log(' /brand-intent example Scaffold the Krume reference implementation');
168
+ console.log(' /brand-intent validate Validate content against your brand rules');
169
+ console.log(' /brand-intent Discover brand files and available purposes');
136
170
  console.log('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brand-intent",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "An open file format specification for making brand intent machine-readable.",
5
5
  "author": "Christophe Stoll <christophe@stoll.studio>",
6
6
  "license": "MIT",
@@ -216,30 +216,16 @@ Once confirmed, generate these files at the project root:
216
216
  - **Typography sizes use `cqmin` units.** Use these sensible defaults unless the user specified otherwise: headline 6, body 2.8, caption 2.2, label 2.
217
217
  - **Spacing defaults:** unit cqmin, xs 1.5, s 2, m 3, l 5, xl 6.5.
218
218
 
219
- ## Example: Scaffold the Krume Reference
220
-
221
- When `$ARGUMENTS` is "example", copy the Krume bakery reference files into `examples/krume/` in the current project. The Krume files are distributed with the npm package.
222
-
223
- Run this shell command to copy them:
224
-
225
- ```bash
226
- node -e "
227
- const pkg = require.resolve('brand-intent/package.json');
228
- const root = require('path').dirname(pkg);
229
- const { cpSync, mkdirSync } = require('fs');
230
- const dest = 'examples/krume';
231
- mkdirSync(dest, { recursive: true });
232
- for (const d of ['brands/krume', 'formats', 'purposes', 'compositions']) {
233
- const src = require('path').join(root, d);
234
- try { cpSync(src, require('path').join(dest, d.replace('brands/krume', '')), { recursive: true }); } catch {}
235
- }
236
- console.log('Krume example scaffolded into examples/krume/');
237
- "
238
- ```
219
+ ## Example: Explore the Krume Reference
220
+
221
+ When `$ARGUMENTS` is "example", the Krume bakery reference is already in `examples/krume/` (copied there by `npx brand-intent init`).
222
+
223
+ Read the files and walk the user through them:
224
+
225
+ - **`krume.identity`** — the strategic layer: essence, voice, values, audiences. Start here.
226
+ - **`krume.brand`** — derived expression: colors, themes, typography, spacing. Every decision traces back to identity.
227
+ - **`formats/`** — canvas dimensions, safe zones, grid. Where content appears.
228
+ - **`purposes/`** — content type with semantic slots, samples, constraints. What content does.
229
+ - **`compositions/`** — spatial arrangement of slots. How elements are placed.
239
230
 
240
- Then explain to the user what each file does:
241
- - **`.identity`** — the strategic layer: essence, voice, values, audiences. Read this first.
242
- - **`.brand`** — derived expression: colors, themes, typography, spacing. Every decision traces back to identity.
243
- - **`.format`** — canvas dimensions, safe zones, grid. Where content appears.
244
- - **`.purpose`** — content type with semantic slots, samples, constraints. What content does.
245
- - **`.composition`** — spatial arrangement of slots. How elements are placed.
231
+ If `examples/krume/` doesn't exist, tell the user to run `npx brand-intent init` first.