@nebutra/design-sync 0.1.2 → 3.0.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 (36) hide show
  1. package/README.md +14 -31
  2. package/dist/cli/index.js +2 -2
  3. package/dist/detect.d.ts.map +1 -1
  4. package/dist/detect.js +2 -25
  5. package/dist/factory.d.ts +3 -14
  6. package/dist/factory.d.ts.map +1 -1
  7. package/dist/factory.js +6 -26
  8. package/dist/index.d.ts +1 -5
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +0 -6
  11. package/dist/io.js +2 -2
  12. package/dist/serialize/to-design-md.d.ts +7 -1
  13. package/dist/serialize/to-design-md.d.ts.map +1 -1
  14. package/dist/serialize/to-design-md.js +1 -1
  15. package/dist/serialize/to-design-md.prose.d.ts +2 -2
  16. package/dist/serialize/to-design-md.prose.d.ts.map +1 -1
  17. package/dist/serialize/to-design-md.prose.js +23 -7
  18. package/dist/serialize/to-preview-html.d.ts +7 -1
  19. package/dist/serialize/to-preview-html.d.ts.map +1 -1
  20. package/dist/serialize/to-preview-html.js +16 -10
  21. package/dist/serialize/to-preview-html.template.d.ts +2 -2
  22. package/dist/serialize/to-preview-html.template.js +2 -2
  23. package/dist/types.d.ts +4 -28
  24. package/dist/types.d.ts.map +1 -1
  25. package/package.json +7 -18
  26. package/src/cli/index.ts +2 -2
  27. package/dist/figma-config/index.d.ts +0 -37
  28. package/dist/figma-config/index.d.ts.map +0 -1
  29. package/dist/figma-config/index.js +0 -12
  30. package/dist/figma-config/tokens-studio.config.json +0 -34
  31. package/dist/providers/figma.d.ts +0 -21
  32. package/dist/providers/figma.d.ts.map +0 -1
  33. package/dist/providers/figma.js +0 -179
  34. package/dist/providers/penpot.d.ts +0 -21
  35. package/dist/providers/penpot.d.ts.map +0 -1
  36. package/dist/providers/penpot.js +0 -137
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- > **Status: Foundation** — provider interface, detection, git-only path, and CLI are complete. Figma + Penpot live pushes are intentionally guarded behind `dryRun` until the operator opts in. See `DESIGN.md` for the rollout plan.
1
+ > **Status: Foundation** — provider interface, detection, git-only path, and CLI are complete. See `DESIGN.md` for the design rationale.
2
2
 
3
3
  # @nebutra/design-sync
4
4
 
@@ -8,9 +8,8 @@ Provider-agnostic design-tool sync. The application code never imports a specifi
8
8
 
9
9
  | Provider | Customer profile | Cost | China-friendly | Status |
10
10
  |----------|------------------|------|----------------|--------|
11
- | `figma` | North-American / global teams with a Figma seat (Tokens Studio plugin) | Figma + Tokens Studio | No (Figma blocked) | dry-run, pull works |
12
- | `penpot` | Self-hosted / privacy-first / China compliance | Free / self-host | Yes (self-hostable) | dry-run scaffold |
13
11
  | `git-only` | Indie hackers, AI-driven dev workflows, "no designer" teams | Free | Yes | full |
12
+ | `design-md` | AI-native workflows — DESIGN.md as the design surface | Free | Yes | full |
14
13
  | `memory` | CI / unit tests | Free | n/a | full (test fixture) |
15
14
 
16
15
  ## Quick start
@@ -18,14 +17,14 @@ Provider-agnostic design-tool sync. The application code never imports a specifi
18
17
  ```ts
19
18
  import { getDesignSync } from "@nebutra/design-sync";
20
19
 
21
- // Auto-detects the provider from environment variables.
20
+ // Auto-detects the provider from environment variables (defaults to git-only).
22
21
  const sync = await getDesignSync();
23
22
 
24
23
  // Pull design-tool → repo (DTCG JSON files under packages/design/design-tokens/tokens).
25
24
  const result = await sync.pull();
26
25
  console.log(result.summary);
27
26
 
28
- // Push repo → design-tool. Defaults to dry-run on figma/penpot
27
+ // Push repo → design-tool. Defaults to dry-run on design-md
29
28
  // until you opt in by providing credentials.
30
29
  await sync.push({ dryRun: true });
31
30
 
@@ -37,10 +36,8 @@ const status = await sync.healthcheck();
37
36
 
38
37
  | Priority | Condition | Provider |
39
38
  |----------|-----------|----------|
40
- | 1 | `DESIGN_SYNC_PROVIDER` set to `figma` / `penpot` / `git-only` / `memory` | as specified |
41
- | 2 | `FIGMA_PERSONAL_ACCESS_TOKEN` **and** `FIGMA_FILE_ID` present | `figma` |
42
- | 3 | `PENPOT_API_URL` **and** `PENPOT_TOKEN` present | `penpot` |
43
- | 4 | fallback | `git-only` |
39
+ | 1 | `DESIGN_SYNC_PROVIDER` set to `git-only` / `design-md` / `memory` | as specified |
40
+ | 2 | fallback | `git-only` |
44
41
 
45
42
  `memory` is never auto-detected; it must be requested explicitly (used in tests).
46
43
 
@@ -48,19 +45,10 @@ const status = await sync.healthcheck();
48
45
 
49
46
  ```env
50
47
  # Optional — force a specific provider
51
- DESIGN_SYNC_PROVIDER="" # figma | penpot | git-only | memory
52
-
53
- # Figma
54
- FIGMA_PERSONAL_ACCESS_TOKEN="" # https://help.figma.com/hc/en-us/articles/8085703771159
55
- FIGMA_FILE_ID="" # the :file_key segment of the Figma URL
56
- FIGMA_GITHUB_REPO="Nebutra/Nebutra-Sailor"
57
- FIGMA_GITHUB_BRANCH="main"
58
-
59
- # Penpot
60
- PENPOT_API_URL="https://design.penpot.app/api" # or your self-host URL
61
- PENPOT_TOKEN=""
62
- PENPOT_FILE_ID=""
63
- PENPOT_TEAM_ID=""
48
+ DESIGN_SYNC_PROVIDER="" # git-only | design-md | memory
49
+
50
+ # design-md
51
+ DESIGN_MD_PATH="" # defaults to <cwd>/DESIGN.md
64
52
  ```
65
53
 
66
54
  ## CLI
@@ -77,7 +65,7 @@ pnpm --filter @nebutra/design-sync exec design-sync healthcheck
77
65
  # Pull design-tool → repo.
78
66
  pnpm --filter @nebutra/design-sync exec design-sync pull
79
67
 
80
- # Push repo → design-tool (defaults to dry-run on figma/penpot).
68
+ # Push repo → design-tool (defaults to dry-run on design-md).
81
69
  pnpm --filter @nebutra/design-sync exec design-sync push --dry-run
82
70
 
83
71
  # Restrict to specific token sets.
@@ -92,9 +80,8 @@ pnpm --filter @nebutra/design-sync exec design-sync detect --json
92
80
 
93
81
  ## Choosing a provider
94
82
 
95
- - **You have a Figma file + designers** → use `figma`. The Tokens Studio plugin owns the git transport (push/pull DTCG to a GitHub branch). The provider validates `.tokens-studio/` metadata and re-reads the DTCG mirror written by the plugin.
96
- - **You self-host or operate inside mainland China** → use `penpot`. It speaks DTCG natively and can be self-hosted; the provider exposes the same `pull/push/healthcheck` surface so you migrate by flipping one env var.
97
83
  - **You ship without a design tool (indie hacker, AI-first dev)** → use `git-only`. Zero config. The DTCG files under `packages/design/design-tokens/tokens` *are* the source of truth.
84
+ - **You want an AI-native design surface** → use `design-md`. Push/pull a `DESIGN.md` file (markdown + YAML front matter) that models and humans can both read and edit directly, with an official lint gate before writes.
98
85
  - **You write tests** → inject `MemoryProvider` directly via `setDesignSync(...)`.
99
86
 
100
87
  ## How DTCG flows through the package
@@ -104,14 +91,10 @@ packages/design/design-tokens/tokens/*.json ← single source of truth (W3C DT
104
91
  ▲
105
92
  │ pull() / push()
106
93
  ▼
107
- DesignSyncProvider (figma | penpot | git-only | memory)
94
+ DesignSyncProvider (git-only | design-md | memory)
108
95
  │
109
96
  ▼
110
- remote design tool (or local files for git-only)
97
+ DESIGN.md or local files (git-only)
111
98
  ```
112
99
 
113
100
  Every provider goes through the same DTCG validator (`validateDtcgTree`) before sending data anywhere; bad token files fail closed before they reach a remote API.
114
-
115
- ## Migration from `.tokens-studio/`
116
-
117
- The legacy Tokens Studio config (`.tokens-studio/{config,metadata,themes}.json`) is preserved at the repo root for the plugin to discover, **and** mirrored into `src/figma-config/tokens-studio.config.json` so the figma provider self-documents. Update both files in lock-step if the plugin schema changes.
package/dist/cli/index.js CHANGED
@@ -86,12 +86,12 @@ Commands:
86
86
  detect Print the resolved provider + env diagnostics
87
87
  healthcheck Run the provider's healthcheck()
88
88
  pull Pull design-tool → repo (DTCG JSON)
89
- push Push repo → design-tool (defaults to dry-run on figma/penpot/design-md)
89
+ push Push repo → design-tool (defaults to dry-run on design-md)
90
90
  brand Pull tokens then compile a Brand Package (Create Center)
91
91
  help Show this message
92
92
 
93
93
  Options:
94
- --provider <X> Override provider (figma|penpot|git-only|memory|design-md)
94
+ --provider <X> Override provider (git-only|memory|design-md)
95
95
  --themes a,b Restrict to specific token sets
96
96
  --id <id> Brand package id (for brand command)
97
97
  --name <name> Brand package display name
@@ -1 +1 @@
1
- {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAuBtD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,sBAAsB,GAAG,SAAS,CAOpC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,sBAAsB,CAa3F;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,sBAAsB,CAAC;CAClC,CA2BA"}
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAmBtD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,sBAAsB,GAAG,SAAS,CAOpC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,sBAAsB,CAK3F;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,sBAAsB,CAAC;CAClC,CAgBA"}
package/dist/detect.js CHANGED
@@ -3,16 +3,12 @@
3
3
  // =============================================================================
4
4
  // Resolution order (highest priority first):
5
5
  // 1. DESIGN_SYNC_PROVIDER env var (explicit)
6
- // 2. FIGMA_PERSONAL_ACCESS_TOKEN + FIGMA_FILE_ID → "figma"
7
- // 3. PENPOT_API_URL + PENPOT_TOKEN → "penpot"
8
- // 4. fallback → "git-only"
6
+ // 2. fallback → "git-only"
9
7
  //
10
8
  // `memory` and `design-md` are never auto-detected; they must be requested
11
9
  // explicitly via the DESIGN_SYNC_PROVIDER env var or a config object.
12
10
  // =============================================================================
13
11
  const VALID_PROVIDERS = new Set([
14
- "figma",
15
- "penpot",
16
12
  "git-only",
17
13
  "memory",
18
14
  "design-md",
@@ -38,14 +34,6 @@ export function detectProvider(env = process.env) {
38
34
  const explicit = readConfiguredProvider(env);
39
35
  if (explicit)
40
36
  return explicit;
41
- const figmaToken = env.FIGMA_PERSONAL_ACCESS_TOKEN?.trim();
42
- const figmaFileId = env.FIGMA_FILE_ID?.trim();
43
- if (figmaToken && figmaFileId)
44
- return "figma";
45
- const penpotUrl = env.PENPOT_API_URL?.trim();
46
- const penpotToken = env.PENPOT_TOKEN?.trim();
47
- if (penpotUrl && penpotToken)
48
- return "penpot";
49
37
  return "git-only";
50
38
  }
51
39
  /**
@@ -55,18 +43,7 @@ export function detectProvider(env = process.env) {
55
43
  export function describeEnv(env = process.env) {
56
44
  const detected = [];
57
45
  const missing = [];
58
- const known = [
59
- "DESIGN_SYNC_PROVIDER",
60
- "FIGMA_PERSONAL_ACCESS_TOKEN",
61
- "FIGMA_FILE_ID",
62
- "FIGMA_GITHUB_REPO",
63
- "FIGMA_GITHUB_BRANCH",
64
- "PENPOT_API_URL",
65
- "PENPOT_TOKEN",
66
- "PENPOT_FILE_ID",
67
- "PENPOT_TEAM_ID",
68
- "DESIGN_MD_PATH",
69
- ];
46
+ const known = ["DESIGN_SYNC_PROVIDER", "DESIGN_MD_PATH"];
70
47
  for (const key of known) {
71
48
  if (env[key]?.trim())
72
49
  detected.push(key);
package/dist/factory.d.ts CHANGED
@@ -7,22 +7,11 @@ import type { DesignSyncConfig, DesignSyncProvider } from "./types";
7
7
  * // Auto-detect from environment
8
8
  * const sync = await createDesignSync();
9
9
  *
10
- * // Explicit Figma
11
- * const sync = await createDesignSync({
12
- * provider: "figma",
13
- * personalAccessToken: process.env.FIGMA_PERSONAL_ACCESS_TOKEN,
14
- * fileId: "abc123",
15
- * });
16
- *
17
- * // Explicit Penpot
18
- * const sync = await createDesignSync({
19
- * provider: "penpot",
20
- * apiUrl: "https://design.penpot.app/api",
21
- * token: process.env.PENPOT_TOKEN,
22
- * });
23
- *
24
10
  * // Explicit git-only (zero config)
25
11
  * const sync = await createDesignSync({ provider: "git-only" });
12
+ *
13
+ * // Explicit design-md
14
+ * const sync = await createDesignSync({ provider: "design-md" });
26
15
  * ```
27
16
  */
28
17
  export declare function createDesignSync(config?: DesignSyncConfig): Promise<DesignSyncProvider>;
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAA0B,MAAM,SAAS,CAAC;AAe5F;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAuC7F;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAKjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAEhE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAA0B,MAAM,SAAS,CAAC;AAgB5F;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA2B7F;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAKjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAEhE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
package/dist/factory.js CHANGED
@@ -6,9 +6,10 @@ import { detectProvider } from "./detect";
6
6
  // The factory resolves the correct provider at runtime based on:
7
7
  // 1. Explicit config passed to `createDesignSync()`
8
8
  // 2. `DESIGN_SYNC_PROVIDER` environment variable
9
- // 3. Auto-detection from FIGMA_* / PENPOT_* env vars
9
+ // 3. fallback → git-only
10
10
  //
11
- // This lets customers switch design tools without changing application code.
11
+ // This lets customers switch between the git-only workflow and the AI-native
12
+ // DESIGN.md serialization without changing application code.
12
13
  // =============================================================================
13
14
  let defaultProvider = null;
14
15
  /**
@@ -19,38 +20,17 @@ let defaultProvider = null;
19
20
  * // Auto-detect from environment
20
21
  * const sync = await createDesignSync();
21
22
  *
22
- * // Explicit Figma
23
- * const sync = await createDesignSync({
24
- * provider: "figma",
25
- * personalAccessToken: process.env.FIGMA_PERSONAL_ACCESS_TOKEN,
26
- * fileId: "abc123",
27
- * });
28
- *
29
- * // Explicit Penpot
30
- * const sync = await createDesignSync({
31
- * provider: "penpot",
32
- * apiUrl: "https://design.penpot.app/api",
33
- * token: process.env.PENPOT_TOKEN,
34
- * });
35
- *
36
23
  * // Explicit git-only (zero config)
37
24
  * const sync = await createDesignSync({ provider: "git-only" });
25
+ *
26
+ * // Explicit design-md
27
+ * const sync = await createDesignSync({ provider: "design-md" });
38
28
  * ```
39
29
  */
40
30
  export async function createDesignSync(config) {
41
31
  const providerType = config?.provider ?? detectProvider();
42
32
  logger.info("[design-sync] Creating provider", { provider: providerType });
43
33
  switch (providerType) {
44
- case "figma": {
45
- const { FigmaProvider } = await import("./providers/figma");
46
- const figmaConfig = config?.provider === "figma" ? config : undefined;
47
- return new FigmaProvider(figmaConfig ?? { provider: "figma" });
48
- }
49
- case "penpot": {
50
- const { PenpotProvider } = await import("./providers/penpot");
51
- const penpotConfig = config?.provider === "penpot" ? config : undefined;
52
- return new PenpotProvider(penpotConfig ?? { provider: "penpot" });
53
- }
54
34
  case "git-only": {
55
35
  const { GitOnlyProvider } = await import("./providers/git-only");
56
36
  const gitConfig = config?.provider === "git-only" ? config : undefined;
package/dist/index.d.ts CHANGED
@@ -1,16 +1,12 @@
1
1
  export { describeEnv, detectProvider, readConfiguredProvider } from "./detect";
2
2
  export { createDesignSync, getDesignSync, resetDesignSync, setDesignSync, } from "./factory";
3
- export type { FigmaTokensStudioConfig } from "./figma-config/index";
4
- export { FIGMA_TOKENS_STUDIO_CONFIG } from "./figma-config/index";
5
3
  export { defaultTokensDir, defaultTokensStudioDir, readTokenSets, validateDtcgTree, writeTokenSet, } from "./io";
6
4
  export type { DesignMdProvider } from "./providers/design-md";
7
- export { FigmaProvider } from "./providers/figma";
8
5
  export { GitOnlyProvider } from "./providers/git-only";
9
6
  export { MemoryProvider } from "./providers/memory";
10
- export { PenpotProvider } from "./providers/penpot";
11
7
  export { compileBrandFromTokenSets, mergeTokenTrees, pullAndCompileBrand, serializeToBrandCss, type ToBrandPackageOptions, tokenSetsToReferoShape, } from "./serialize/to-brand-package";
12
8
  export { serializeToDesignMd, type ToDesignMdOptions } from "./serialize/to-design-md";
13
9
  export { serializeToPreviewHtml, type ToPreviewHtmlOptions, } from "./serialize/to-preview-html";
14
- export type { BaseProviderConfig, DesignMdProviderConfig, DesignSyncConfig, DesignSyncProvider, DesignSyncProviderType, DesignTokenLeaf, DesignTokenSet, DesignTokenTree, FigmaProviderConfig, GitOnlyProviderConfig, HealthStatus, MemoryProviderConfig, PenpotProviderConfig, PullOptions, PullResult, PushOptions, PushResult, } from "./types";
10
+ export type { BaseProviderConfig, DesignMdProviderConfig, DesignSyncConfig, DesignSyncProvider, DesignSyncProviderType, DesignTokenLeaf, DesignTokenSet, DesignTokenTree, GitOnlyProviderConfig, HealthStatus, MemoryProviderConfig, PullOptions, PullResult, PushOptions, PushResult, } from "./types";
15
11
  export { DesignTokenLeafSchema } from "./types";
16
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAE/E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEpE,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EAChB,aAAa,GACd,MAAM,MAAM,CAAC;AASd,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EACL,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EACL,sBAAsB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAE/E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EAChB,aAAa,GACd,MAAM,MAAM,CAAC;AASd,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EACL,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EACL,sBAAsB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -2,8 +2,6 @@
2
2
  // @nebutra/design-sync — Provider-agnostic design-tool sync
3
3
  // =============================================================================
4
4
  // Supports:
5
- // - Figma + Tokens Studio (DTCG via GitHub, plugin owns the transport)
6
- // - Penpot (REST API, self-hostable, China-friendly)
7
5
  // - git-only (zero-config default — DTCG files only)
8
6
  // - memory (test fixture)
9
7
  // - design-md (AI-native DESIGN.md, markdown + YAML front matter)
@@ -20,14 +18,10 @@
20
18
  export { describeEnv, detectProvider, readConfiguredProvider } from "./detect";
21
19
  // ── Factory ─────────────────────────────────────────────────────────────────
22
20
  export { createDesignSync, getDesignSync, resetDesignSync, setDesignSync, } from "./factory";
23
- // ── Figma config snapshot ───────────────────────────────────────────────────
24
- export { FIGMA_TOKENS_STUDIO_CONFIG } from "./figma-config/index";
25
21
  // ── DTCG I/O helpers (re-exported for advanced consumers) ───────────────────
26
22
  export { defaultTokensDir, defaultTokensStudioDir, readTokenSets, validateDtcgTree, writeTokenSet, } from "./io";
27
- export { FigmaProvider } from "./providers/figma";
28
23
  export { GitOnlyProvider } from "./providers/git-only";
29
24
  export { MemoryProvider } from "./providers/memory";
30
- export { PenpotProvider } from "./providers/penpot";
31
25
  // ── DTCG → Brand Package (Create Center) ───────────────────────────────────
32
26
  export { compileBrandFromTokenSets, mergeTokenTrees, pullAndCompileBrand, serializeToBrandCss, tokenSetsToReferoShape, } from "./serialize/to-brand-package";
33
27
  // ── DTCG → DESIGN.md serializer ────────────────────────────────────────────
package/dist/io.js CHANGED
@@ -5,8 +5,8 @@ import { DesignTokenLeafSchema } from "./types";
5
5
  // DTCG Filesystem I/O
6
6
  // =============================================================================
7
7
  // Shared helpers used by every provider. Reading and writing the canonical
8
- // W3C DTCG JSON tree on disk is identical across Figma / Penpot / git-only —
9
- // the only thing that differs is what the provider does AFTER it has the data.
8
+ // W3C DTCG JSON tree on disk is identical across every provider — the only
9
+ // thing that differs is what the provider does AFTER it has the data.
10
10
  // =============================================================================
11
11
  const TOKEN_FILE_EXT = ".json";
12
12
  /**
@@ -20,7 +20,13 @@
20
20
  */
21
21
  import type { DesignTokenSet } from "../types";
22
22
  export interface ToDesignMdOptions {
23
- /** Design system name. Default: "Nebutra" */
23
+ /**
24
+ * Design system name written into the exported artefact.
25
+ *
26
+ * Defaults to a generic label on purpose: this package is provider-agnostic
27
+ * and has no brand of its own, so naming one here would stamp it onto every
28
+ * downstream design system that did not pass this option.
29
+ */
24
30
  name?: string;
25
31
  /** One-line brand description for the front matter and prose Overview. */
26
32
  description?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"to-design-md.d.ts","sourceRoot":"","sources":["../../src/serialize/to-design-md.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAqB/C,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CA2C/F"}
1
+ {"version":3,"file":"to-design-md.d.ts","sourceRoot":"","sources":["../../src/serialize/to-design-md.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAqB/C,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CA2C/F"}
@@ -28,7 +28,7 @@ import { buildIndex, buildIndexForSet, buildRounded, buildSpacing, buildTypograp
28
28
  * @returns A deterministic DESIGN.md string (YAML front matter + markdown prose).
29
29
  */
30
30
  export function serializeToDesignMd(sets, options) {
31
- const name = options?.name ?? "Nebutra";
31
+ const name = options?.name ?? "Design System";
32
32
  const description = options?.description;
33
33
  // 1. Build a flat path→leaf index across ALL sets
34
34
  const index = buildIndex(sets);
@@ -38,7 +38,7 @@ export interface ContainerInfo {
38
38
  }
39
39
  export interface ProseArgs {
40
40
  name: string;
41
- /** Optional custom description. When provided, replaces the default Nebutra Overview paragraph. */
41
+ /** Optional custom description. Replaces the generated Overview paragraph. */
42
42
  description?: string;
43
43
  colors: ColorRoles;
44
44
  colorDescriptions: ColorDescriptions;
@@ -49,7 +49,7 @@ export interface ProseArgs {
49
49
  export declare const COLOR_ORDER: Array<keyof ColorRoles>;
50
50
  export declare const DESIGN_MD_GOVERNANCE: {
51
51
  readonly dos: readonly ["Use semantic tokens / CSS variables (`bg-primary`, `text-foreground`, `border-border`) — never raw hex values.", "Use the brand gradient (135° blue→cyan) for primary CTAs and gradient text effects.", "Use `AnimateIn` presets for entrance animations; never use raw `motion.div` with hardcoded transition values.", "Constrain layouts to the container width tiers; use the wide (1400px) container for feature sections.", "Give icon-only buttons an `aria-label`; rely on the global `:focus-visible` ring — do not add component-level focus rings."];
52
- readonly donts: readonly ["Don't hardcode brand or status hex values in components — use token aliases (`var(--brand-primary)`, etc.).", "Don't use `max-w-5xl` or `max-w-7xl` for feature sections — use the wide container (`max-w-[1400px]`).", "Don't reintroduce hardcoded focus rings (they double-render with the global `:focus-visible` rule).", "Don't use raw form controls (`<input>`, `<select>`, `<textarea>`) in app surfaces — use the primitives from `@nebutra/ui/primitives`."];
52
+ readonly donts: readonly ["Don't hardcode brand or status hex values in components — use token aliases (`var(--brand-primary)`, etc.).", "Don't use `max-w-5xl` or `max-w-7xl` for feature sections — use the wide container (`max-w-wide`).", "Don't reintroduce hardcoded focus rings (they double-render with the global `:focus-visible` rule).", "Don't use raw form controls (`<input>`, `<select>`, `<textarea>`) in app surfaces — use the primitives from `@nebutra/ui/primitives`."];
53
53
  };
54
54
  export declare function buildProse(args: ProseArgs): string;
55
55
  //# sourceMappingURL=to-design-md.prose.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"to-design-md.prose.d.ts","sourceRoot":"","sources":["../../src/serialize/to-design-md.prose.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,eAAe,CAAC;IACpB,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,aAAa,CAAC;CAC3B;AAID,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,MAAM,UAAU,CAS/C,CAAC;AAIF,eAAO,MAAM,oBAAoB;;;CAcvB,CAAC;AAIX,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAalD"}
1
+ {"version":3,"file":"to-design-md.prose.d.ts","sourceRoot":"","sources":["../../src/serialize/to-design-md.prose.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,eAAe,CAAC;IACpB,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,aAAa,CAAC;CAC3B;AAID,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,MAAM,UAAU,CAS/C,CAAC;AAIF,eAAO,MAAM,oBAAoB;;;CAcvB,CAAC;AAIX,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAalD"}
@@ -26,7 +26,7 @@ export const DESIGN_MD_GOVERNANCE = {
26
26
  ],
27
27
  donts: [
28
28
  "Don't hardcode brand or status hex values in components — use token aliases (`var(--brand-primary)`, etc.).",
29
- "Don't use `max-w-5xl` or `max-w-7xl` for feature sections — use the wide container (`max-w-[1400px]`).",
29
+ "Don't use `max-w-5xl` or `max-w-7xl` for feature sections — use the wide container (`max-w-wide`).",
30
30
  "Don't reintroduce hardcoded focus rings (they double-render with the global `:focus-visible` rule).",
31
31
  "Don't use raw form controls (`<input>`, `<select>`, `<textarea>`) in app surfaces — use the primitives from `@nebutra/ui/primitives`.",
32
32
  ],
@@ -34,7 +34,7 @@ export const DESIGN_MD_GOVERNANCE = {
34
34
  // ─── Prose builder ────────────────────────────────────────────────────────────
35
35
  export function buildProse(args) {
36
36
  const sections = [];
37
- sections.push(buildOverview(args.name, args.description));
37
+ sections.push(buildOverview(args.name, args.colors, args.description));
38
38
  sections.push(buildColors(args.colors, args.colorDescriptions));
39
39
  sections.push(buildTypographySection(args.typography));
40
40
  sections.push(buildLayout(args.containers));
@@ -45,11 +45,27 @@ export function buildProse(args) {
45
45
  return "\n" + sections.join("\n\n") + "\n";
46
46
  }
47
47
  // ─── Section helpers ──────────────────────────────────────────────────────────
48
- function buildOverview(name, description) {
49
- const paragraph = description ??
50
- `${name} is an AI-native SaaS design system built on the 云毓蓝 blue (#0033fe) → 云毓青 cyan (#0bf1c3) brand palette. ` +
51
- `It targets Vercel/Geist visual parity, enforces semantic tokens over raw hex values, and ships with ` +
52
- `a token-first architecture (DTCG W3C draft) that drives CSS variables, Tailwind utilities, and the Style Dictionary pipeline.`;
48
+ /**
49
+ * The fallback paragraph is generated from the caller's own tokens.
50
+ *
51
+ * It used to be Nebutra's: it named 云毓蓝 #0033fe and 云毓青 #0bf1c3 as "the
52
+ * brand palette" and asserted Vercel/Geist parity, so every downstream design
53
+ * system exported a document describing someone else's colours as its own.
54
+ */
55
+ function buildOverview(name, colors, description) {
56
+ if (description)
57
+ return `## Overview\n\n${description}`;
58
+ const palette = [
59
+ colors.primary ? `primary ${colors.primary}` : null,
60
+ colors.accent ? `accent ${colors.accent}` : null,
61
+ ]
62
+ .filter(Boolean)
63
+ .join(" → ");
64
+ const paragraph = `${name} is a token-first design system` +
65
+ (palette ? ` built on a ${palette} palette` : "") +
66
+ ". It favours semantic tokens over raw hex values and follows the DTCG " +
67
+ "(W3C draft) format, which drives CSS variables, Tailwind utilities and " +
68
+ "the Style Dictionary pipeline.";
53
69
  return `## Overview\n\n${paragraph}`;
54
70
  }
55
71
  const COLOR_LABELS = {
@@ -16,7 +16,13 @@
16
16
  */
17
17
  import type { DesignTokenSet } from "../types";
18
18
  export interface ToPreviewHtmlOptions {
19
- /** Design system name. Default: "Nebutra" */
19
+ /**
20
+ * Design system name written into the exported artefact.
21
+ *
22
+ * Defaults to a generic label on purpose: this package is provider-agnostic
23
+ * and has no brand of its own, so naming one here would stamp it onto every
24
+ * downstream design system that did not pass this option.
25
+ */
20
26
  name?: string;
21
27
  /**
22
28
  * Name of a theme token set (e.g. "themes/light") whose
@@ -1 +1 @@
1
- {"version":3,"file":"to-preview-html.d.ts","sourceRoot":"","sources":["../../src/serialize/to-preview-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAkB/C,MAAM,WAAW,oBAAoB;IACnC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,cAAc,EAAE,EACtB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,MAAM,CA2CR"}
1
+ {"version":3,"file":"to-preview-html.d.ts","sourceRoot":"","sources":["../../src/serialize/to-preview-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAkB/C,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,cAAc,EAAE,EACtB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,MAAM,CA2CR"}
@@ -14,6 +14,7 @@
14
14
  * PURE: no filesystem I/O, no @google/design.md dependency.
15
15
  * Only imports from `../types`, `./to-design-md.resolve`, and `./to-preview-html.template`.
16
16
  */
17
+ import { tokenColor } from "@nebutra/tokens/values";
17
18
  import { buildIndex, buildIndexForSet, buildRounded, buildTypography, resolveColorRoles, } from "./to-design-md.resolve";
18
19
  import { buildDocument, cssAttrValue, escapeHtml, } from "./to-preview-html.template";
19
20
  /**
@@ -24,7 +25,7 @@ import { buildDocument, cssAttrValue, escapeHtml, } from "./to-preview-html.temp
24
25
  * @returns A deterministic, self-contained HTML string.
25
26
  */
26
27
  export function serializeToPreviewHtml(sets, options) {
27
- const name = options?.name ?? "Nebutra";
28
+ const name = options?.name ?? "Design System";
28
29
  const escapedName = escapeHtml(name);
29
30
  // 1. Build flat indexes
30
31
  const index = buildIndex(sets);
@@ -61,16 +62,21 @@ export function serializeToPreviewHtml(sets, options) {
61
62
  });
62
63
  }
63
64
  // ─── CSS variable builder ──────────────────────────────────────────────────────
64
- function buildCssVars(colors, _mode) {
65
+ /**
66
+ * A role the DESIGN.md does not set falls back to the House token for that
67
+ * mode, read from @nebutra/tokens/values — the value the apps render — rather
68
+ * than a hex restated here (the old dark fallbacks were pre-House Slate).
69
+ */
70
+ function buildCssVars(colors, mode) {
65
71
  return {
66
- primary: colors.primary ?? "#0033fe",
67
- accent: colors.accent ?? "#0bf1c3",
68
- tertiary: colors.tertiary ?? "#8b5cf6",
69
- danger: colors.danger ?? "#ef4444",
70
- warning: colors.warning ?? "#f59e0b",
71
- success: colors.success ?? "#22c55e",
72
- background: colors.background ?? (_mode === "light" ? "#ffffff" : "#0a0a0a"),
73
- foreground: colors.foreground ?? (_mode === "light" ? "#0f172a" : "#fafafa"),
72
+ primary: colors.primary ?? tokenColor("--brand-primary", mode),
73
+ accent: colors.accent ?? tokenColor("--brand-accent", mode),
74
+ tertiary: colors.tertiary ?? tokenColor("--brand-tertiary", mode),
75
+ danger: colors.danger ?? tokenColor("--status-danger", mode),
76
+ warning: colors.warning ?? tokenColor("--status-warning", mode),
77
+ success: colors.success ?? tokenColor("--status-success", mode),
78
+ background: colors.background ?? tokenColor("--background", mode),
79
+ foreground: colors.foreground ?? tokenColor("--foreground", mode),
74
80
  };
75
81
  }
76
82
  // ─── Section builders ──────────────────────────────────────────────────────────
@@ -29,8 +29,8 @@ export declare function escapeHtml(value: string): string;
29
29
  * remaining angle brackets become `&lt;`/`&gt;`.
30
30
  *
31
31
  * Example:
32
- * cssAttrValue('"Geist", "Noto Sans SC", sans-serif')
33
- * → '&quot;Geist&quot;, &quot;Noto Sans SC&quot;, sans-serif'
32
+ * cssAttrValue('"Geist", "MiSans", sans-serif')
33
+ * → '&quot;Geist&quot;, &quot;MiSans&quot;, sans-serif'
34
34
  *
35
35
  * cssAttrValue('red;display:none')
36
36
  * → 'reddisplay:none' (semicolon stripped before HTML-escape)
@@ -37,8 +37,8 @@ export function escapeHtml(value) {
37
37
  * remaining angle brackets become `&lt;`/`&gt;`.
38
38
  *
39
39
  * Example:
40
- * cssAttrValue('"Geist", "Noto Sans SC", sans-serif')
41
- * → '&quot;Geist&quot;, &quot;Noto Sans SC&quot;, sans-serif'
40
+ * cssAttrValue('"Geist", "MiSans", sans-serif')
41
+ * → '&quot;Geist&quot;, &quot;MiSans&quot;, sans-serif'
42
42
  *
43
43
  * cssAttrValue('red;display:none')
44
44
  * → 'reddisplay:none' (semicolon stripped before HTML-escape)
package/dist/types.d.ts CHANGED
@@ -2,13 +2,11 @@ import { z } from "zod";
2
2
  /**
3
3
  * Supported design-sync backend providers.
4
4
  *
5
- * - `figma` — Figma + Tokens Studio plugin (DTCG via GitHub provider sync)
6
- * - `penpot` — Penpot REST API (self-hostable, China-friendly)
7
5
  * - `git-only` — No design tool; reads/writes local DTCG files directly
8
6
  * - `memory` — In-memory test fixture (CI / unit tests only)
9
7
  * - `design-md` — AI-native DESIGN.md format (@google/design.md) — markdown + YAML front matter
10
8
  */
11
- export type DesignSyncProviderType = "figma" | "penpot" | "git-only" | "memory" | "design-md";
9
+ export type DesignSyncProviderType = "git-only" | "memory" | "design-md";
12
10
  /**
13
11
  * A W3C Design Tokens Community Group (DTCG) leaf token.
14
12
  * Every leaf MUST carry both `$value` and `$type`.
@@ -43,7 +41,7 @@ export interface DesignTokenSet {
43
41
  export interface PullOptions {
44
42
  /**
45
43
  * Optional theme/token-set filter. When omitted, all sets are pulled.
46
- * Provider-specific naming applies (e.g. Figma collection IDs).
44
+ * Provider-specific naming applies.
47
45
  */
48
46
  themes?: string[];
49
47
  /**
@@ -59,7 +57,7 @@ export interface PushOptions {
59
57
  themes?: string[];
60
58
  /**
61
59
  * If true, the provider should compute the diff but NOT call the remote API.
62
- * `figma.push({ dryRun: true })` is the default until the user opts in.
60
+ * `design-md.push({ dryRun: true })` is the default until the user opts in.
63
61
  */
64
62
  dryRun?: boolean;
65
63
  /** Tenant scoping */
@@ -142,28 +140,6 @@ export interface BaseProviderConfig {
142
140
  */
143
141
  tokensStudioDir?: string;
144
142
  }
145
- export interface FigmaProviderConfig extends BaseProviderConfig {
146
- provider: "figma";
147
- /** Figma personal access token. Defaults to `process.env.FIGMA_PERSONAL_ACCESS_TOKEN`. */
148
- personalAccessToken?: string;
149
- /** Figma file ID (the `:file_key` segment in the URL). */
150
- fileId?: string;
151
- /** GitHub repo (owner/name) used by the Tokens Studio plugin sync. */
152
- githubRepo?: string;
153
- /** GitHub branch the plugin pushes to. Defaults to `main`. */
154
- githubBranch?: string;
155
- }
156
- export interface PenpotProviderConfig extends BaseProviderConfig {
157
- provider: "penpot";
158
- /** Penpot API URL — public cloud or self-hosted. */
159
- apiUrl?: string;
160
- /** Penpot personal access token. */
161
- token?: string;
162
- /** Penpot file ID. */
163
- fileId?: string;
164
- /** Penpot team / workspace ID. */
165
- teamId?: string;
166
- }
167
143
  export interface GitOnlyProviderConfig extends BaseProviderConfig {
168
144
  provider: "git-only";
169
145
  }
@@ -187,5 +163,5 @@ export interface DesignMdProviderConfig extends BaseProviderConfig {
187
163
  */
188
164
  description?: string;
189
165
  }
190
- export type DesignSyncConfig = FigmaProviderConfig | PenpotProviderConfig | GitOnlyProviderConfig | MemoryProviderConfig | DesignMdProviderConfig;
166
+ export type DesignSyncConfig = GitOnlyProviderConfig | MemoryProviderConfig | DesignMdProviderConfig;
191
167
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,27 +1,24 @@
1
1
  {
2
2
  "name": "@nebutra/design-sync",
3
- "version": "0.1.2",
4
- "description": "Provider-agnostic design-tool sync. Figma + Tokens Studio | Penpot | git-only | design-md | memory.",
3
+ "version": "3.0.0",
4
+ "description": "Provider-agnostic design-tool sync. git-only | design-md | memory.",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "nebutra": {
9
+ "graph": "core",
9
10
  "status": "foundation",
10
11
  "productionReady": false,
11
12
  "requires": [
12
- "FIGMA_PERSONAL_ACCESS_TOKEN + FIGMA_FILE_ID for Figma + Tokens Studio",
13
- "or PENPOT_API_URL + PENPOT_TOKEN for Penpot (self-hostable, China-friendly)",
14
- "or nothing — git-only is the zero-config default"
13
+ "nothing — git-only is the zero-config default"
15
14
  ],
16
15
  "gaps": [
17
- "Figma push (Variables REST API) is dry-run; manual enable required",
18
- "Penpot adapter implements healthcheck + pull; push is dry-run scaffolding",
19
16
  "No real-time webhook listeners (manual pull/push only)",
20
17
  "design-md provider depends on @google/design.md (alpha v0.x); pinned exactly — a 0.x bump may change linter rules and require re-validating the serializer output"
21
18
  ],
22
19
  "featureId": "design-sync",
23
20
  "category": "design",
24
- "summary": "Provider-agnostic design-tool sync (Figma | Penpot | git-only | design-md)"
21
+ "summary": "Provider-agnostic design-tool sync (git-only | design-md)"
25
22
  },
26
23
  "main": "./dist/index.js",
27
24
  "types": "./dist/index.d.ts",
@@ -38,14 +35,6 @@
38
35
  "types": "./dist/serialize/from-design-md.d.ts",
39
36
  "import": "./dist/serialize/from-design-md.js"
40
37
  },
41
- "./figma": {
42
- "types": "./dist/providers/figma.d.ts",
43
- "import": "./dist/providers/figma.js"
44
- },
45
- "./penpot": {
46
- "types": "./dist/providers/penpot.d.ts",
47
- "import": "./dist/providers/penpot.js"
48
- },
49
38
  "./git-only": {
50
39
  "types": "./dist/providers/git-only.d.ts",
51
40
  "import": "./dist/providers/git-only.js"
@@ -73,8 +62,8 @@
73
62
  "dependencies": {
74
63
  "@google/design.md": "0.2.0",
75
64
  "zod": "^4.3.6",
76
- "@nebutra/logger": "0.1.2",
77
- "@nebutra/tokens": "0.1.2"
65
+ "@nebutra/logger": "3.0.0",
66
+ "@nebutra/tokens": "3.0.0"
78
67
  },
79
68
  "devDependencies": {
80
69
  "@types/node": "^25.9.1",
package/src/cli/index.ts CHANGED
@@ -97,12 +97,12 @@ Commands:
97
97
  detect Print the resolved provider + env diagnostics
98
98
  healthcheck Run the provider's healthcheck()
99
99
  pull Pull design-tool → repo (DTCG JSON)
100
- push Push repo → design-tool (defaults to dry-run on figma/penpot/design-md)
100
+ push Push repo → design-tool (defaults to dry-run on design-md)
101
101
  brand Pull tokens then compile a Brand Package (Create Center)
102
102
  help Show this message
103
103
 
104
104
  Options:
105
- --provider <X> Override provider (figma|penpot|git-only|memory|design-md)
105
+ --provider <X> Override provider (git-only|memory|design-md)
106
106
  --themes a,b Restrict to specific token sets
107
107
  --id <id> Brand package id (for brand command)
108
108
  --name <name> Brand package display name
@@ -1,37 +0,0 @@
1
- import figmaPluginConfig from "./tokens-studio.config.json";
2
- export declare const FIGMA_TOKENS_STUDIO_CONFIG: {
3
- $schema: string;
4
- name: string;
5
- version: string;
6
- description: string;
7
- syncProvider: string;
8
- git: {
9
- repository: string;
10
- defaultBranch: string;
11
- syncBranchPrefix: string;
12
- tokenPath: string;
13
- themesPath: string;
14
- metadataPath: string;
15
- };
16
- format: {
17
- spec: string;
18
- indent: number;
19
- trailingNewline: boolean;
20
- useUiCompatibleTypes: boolean;
21
- };
22
- storage: {
23
- multiFile: boolean;
24
- tokenSetSeparator: string;
25
- };
26
- permissions: {
27
- allowDestructiveSync: boolean;
28
- requirePullRequest: boolean;
29
- protectedSets: string[];
30
- };
31
- ui: {
32
- language: string;
33
- showThemeMatrix: boolean;
34
- };
35
- };
36
- export type FigmaTokensStudioConfig = typeof figmaPluginConfig;
37
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/figma-config/index.ts"],"names":[],"mappings":"AAWA,OAAO,iBAAiB,MAAM,6BAA6B,CAAuB;AAElF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAoB,CAAC;AAE5D,MAAM,MAAM,uBAAuB,GAAG,OAAO,iBAAiB,CAAC"}
@@ -1,12 +0,0 @@
1
- // =============================================================================
2
- // Tokens Studio config — canonical copy owned by @nebutra/design-sync
3
- // =============================================================================
4
- // The original `.tokens-studio/config.json` lives at the repo root because the
5
- // Tokens Studio plugin pins its config-discovery path. We keep an in-package
6
- // canonical copy here so the figma provider can self-document and so a sync
7
- // CLI can scaffold the file when initialising a fresh repo.
8
- //
9
- // If the plugin's config schema changes, update both files in lock-step.
10
- // =============================================================================
11
- import figmaPluginConfig from "./tokens-studio.config.json" with { type: "json" };
12
- export const FIGMA_TOKENS_STUDIO_CONFIG = figmaPluginConfig;
@@ -1,34 +0,0 @@
1
- {
2
- "$schema": "https://raw.githubusercontent.com/tokens-studio/figma-plugin/main/schemas/tokens-studio-config.schema.json",
3
- "name": "Nebutra Design Tokens",
4
- "version": "0.1.0",
5
- "description": "Bidirectional sync between Tokens Studio for Figma and packages/design-tokens (W3C DTCG). Owned by @nebutra/design-sync's figma provider.",
6
- "syncProvider": "github",
7
- "git": {
8
- "repository": "Nebutra/Nebutra-Sailor",
9
- "defaultBranch": "main",
10
- "syncBranchPrefix": "tokens-studio/",
11
- "tokenPath": "packages/design/design-tokens/tokens",
12
- "themesPath": ".tokens-studio/themes.json",
13
- "metadataPath": ".tokens-studio/metadata.json"
14
- },
15
- "format": {
16
- "spec": "dtcg",
17
- "indent": 2,
18
- "trailingNewline": true,
19
- "useUiCompatibleTypes": true
20
- },
21
- "storage": {
22
- "multiFile": true,
23
- "tokenSetSeparator": "/"
24
- },
25
- "permissions": {
26
- "allowDestructiveSync": false,
27
- "requirePullRequest": true,
28
- "protectedSets": ["core", "semantic"]
29
- },
30
- "ui": {
31
- "language": "en",
32
- "showThemeMatrix": true
33
- }
34
- }
@@ -1,21 +0,0 @@
1
- import type { DesignSyncProvider, FigmaProviderConfig, HealthStatus, PullOptions, PullResult, PushOptions, PushResult } from "../types";
2
- export declare class FigmaProvider implements DesignSyncProvider {
3
- readonly name: "figma";
4
- private readonly tokensDir;
5
- private readonly tokensStudioDir;
6
- private readonly personalAccessToken;
7
- private readonly fileId;
8
- private readonly githubRepo;
9
- private readonly githubBranch;
10
- constructor(config: FigmaProviderConfig);
11
- pull(options?: PullOptions): Promise<PullResult>;
12
- push(options?: PushOptions): Promise<PushResult>;
13
- healthcheck(): Promise<HealthStatus>;
14
- /**
15
- * Assert that `.tokens-studio/{config,metadata,themes}.json` exist + parse.
16
- * The plugin refuses to load the design system if any of these are missing
17
- * or malformed; surfacing the failure here prevents silent drift.
18
- */
19
- private assertTokensStudioMetadata;
20
- }
21
- //# sourceMappingURL=figma.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"figma.d.ts","sourceRoot":"","sources":["../../src/providers/figma.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACX,MAAM,UAAU,CAAC;AAyBlB,qBAAa,aAAc,YAAW,kBAAkB;IACtD,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IAEjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,EAAE,mBAAmB;IAgBjC,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAiBpD,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAiDpD,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;IAwC1C;;;;OAIG;YACW,0BAA0B;CA+BzC"}
@@ -1,179 +0,0 @@
1
- import { readFile, stat } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { logger } from "@nebutra/logger";
4
- import { defaultTokensDir, defaultTokensStudioDir, readTokenSets, validateDtcgTree } from "../io";
5
- // =============================================================================
6
- // Figma Provider — Figma + Tokens Studio
7
- // =============================================================================
8
- // Architecture (matches the legacy `.tokens-studio/config.json` setup):
9
- //
10
- // Figma (Tokens Studio plugin) ──► GitHub branch ──► repo (DTCG JSON)
11
- // ▲ │
12
- // └─── pull from main ──────────┘
13
- //
14
- // The plugin owns the git transport. This provider:
15
- // - validates that the Tokens Studio config + DTCG tree are well-formed
16
- // - "pull" reads the DTCG files the plugin already wrote to git
17
- // - "push" is a dry-run scaffold for the Figma Variables REST API
18
- // (PATCH /v1/files/:file_key/variables) — the user must opt in by
19
- // providing FIGMA_PERSONAL_ACCESS_TOKEN + FIGMA_FILE_ID and removing
20
- // the early-exit guard.
21
- //
22
- // All Tokens Studio metadata that previously lived in `.tokens-studio/` is
23
- // still consumed from disk so the existing designer onboarding does not break.
24
- // =============================================================================
25
- const FIGMA_API_ROOT = "https://api.figma.com";
26
- export class FigmaProvider {
27
- name = "figma";
28
- tokensDir;
29
- tokensStudioDir;
30
- personalAccessToken;
31
- fileId;
32
- githubRepo;
33
- githubBranch;
34
- constructor(config) {
35
- this.tokensDir = config.tokensDir ?? defaultTokensDir();
36
- this.tokensStudioDir = config.tokensStudioDir ?? defaultTokensStudioDir();
37
- this.personalAccessToken =
38
- config.personalAccessToken ?? process.env.FIGMA_PERSONAL_ACCESS_TOKEN ?? undefined;
39
- this.fileId = config.fileId ?? process.env.FIGMA_FILE_ID ?? undefined;
40
- this.githubRepo = config.githubRepo ?? process.env.FIGMA_GITHUB_REPO ?? undefined;
41
- this.githubBranch = config.githubBranch ?? process.env.FIGMA_GITHUB_BRANCH ?? "main";
42
- logger.info("[design-sync:figma] Provider initialised", {
43
- tokensDir: this.tokensDir,
44
- hasToken: Boolean(this.personalAccessToken),
45
- hasFileId: Boolean(this.fileId),
46
- });
47
- }
48
- async pull(options = {}) {
49
- // Tokens Studio plugin already wrote DTCG files to git on `pull`.
50
- // We just re-read them from disk and (optionally) validate Tokens
51
- // Studio metadata so the result mirrors what the plugin would emit.
52
- const sets = await readTokenSets(this.tokensDir);
53
- const filtered = filterSets(sets, options.themes);
54
- await this.assertTokensStudioMetadata();
55
- return {
56
- sets: filtered,
57
- written: false,
58
- provider: "figma",
59
- pulledAt: new Date().toISOString(),
60
- summary: `figma: read ${filtered.length} DTCG token set(s) (Tokens Studio plugin owns the git transport)`,
61
- };
62
- }
63
- async push(options = {}) {
64
- // Pre-flight: validate DTCG before attempting any remote call.
65
- const all = await readTokenSets(this.tokensDir);
66
- const sets = filterSets(all, options.themes);
67
- for (const set of sets) {
68
- const errors = validateDtcgTree(set.tokens);
69
- if (errors.length > 0) {
70
- throw new Error(`[design-sync:figma] DTCG validation failed for ${set.relativePath}:\n - ${errors.join("\n - ")}`);
71
- }
72
- }
73
- const credsReady = Boolean(this.personalAccessToken && this.fileId);
74
- const explicitDryRun = options.dryRun ?? false;
75
- const dryRun = explicitDryRun || !credsReady;
76
- if (dryRun) {
77
- logger.warn("[design-sync:figma] push skipped (dry-run scaffold)", {
78
- reason: credsReady ? "explicit dryRun" : "missing credentials",
79
- sets: sets.length,
80
- });
81
- return {
82
- pushed: false,
83
- sets: sets.map((s) => s.relativePath),
84
- provider: "figma",
85
- pushedAt: new Date().toISOString(),
86
- summary: credsReady
87
- ? `figma: dry-run — would PATCH ${sets.length} set(s) to ${FIGMA_API_ROOT}/v1/files/${this.fileId}/variables`
88
- : "figma: dry-run — FIGMA_PERSONAL_ACCESS_TOKEN or FIGMA_FILE_ID not set",
89
- dryRun: true,
90
- };
91
- }
92
- // Real push placeholder — kept guarded until the user opts in.
93
- // The integration will call the Figma Variables REST API:
94
- // PATCH /v1/files/:file_key/variables
95
- // X-Figma-Token: <personalAccessToken>
96
- // See https://www.figma.com/developers/api#variables
97
- throw new Error("[design-sync:figma] live push to Figma Variables REST API is not yet implemented. " +
98
- "Use { dryRun: true } or unset FIGMA_PERSONAL_ACCESS_TOKEN until the integration is wired up. " +
99
- "See packages/design/design-sync/DESIGN.md for the rollout plan.");
100
- }
101
- async healthcheck() {
102
- const detected = [];
103
- const missing = [];
104
- if (this.personalAccessToken)
105
- detected.push("FIGMA_PERSONAL_ACCESS_TOKEN");
106
- else
107
- missing.push("FIGMA_PERSONAL_ACCESS_TOKEN");
108
- if (this.fileId)
109
- detected.push("FIGMA_FILE_ID");
110
- else
111
- missing.push("FIGMA_FILE_ID");
112
- if (this.githubRepo)
113
- detected.push("FIGMA_GITHUB_REPO");
114
- if (this.githubBranch)
115
- detected.push(`FIGMA_GITHUB_BRANCH=${this.githubBranch}`);
116
- let tokensStudioOk = true;
117
- let tokensStudioMessage = "";
118
- try {
119
- await this.assertTokensStudioMetadata();
120
- }
121
- catch (error) {
122
- tokensStudioOk = false;
123
- tokensStudioMessage = error.message;
124
- missing.push("tokens-studio metadata");
125
- }
126
- const ok = missing.length === 0 && tokensStudioOk;
127
- return {
128
- ok,
129
- provider: "figma",
130
- message: ok
131
- ? "figma: credentials present + Tokens Studio metadata valid"
132
- : `figma: not ready — ${[
133
- missing.length > 0 ? `missing ${missing.join(", ")}` : "",
134
- tokensStudioMessage,
135
- ]
136
- .filter(Boolean)
137
- .join("; ")}`,
138
- detectedEnv: detected,
139
- missingEnv: missing,
140
- };
141
- }
142
- /**
143
- * Assert that `.tokens-studio/{config,metadata,themes}.json` exist + parse.
144
- * The plugin refuses to load the design system if any of these are missing
145
- * or malformed; surfacing the failure here prevents silent drift.
146
- */
147
- async assertTokensStudioMetadata() {
148
- const required = ["config.json", "metadata.json", "themes.json"];
149
- const errors = [];
150
- try {
151
- const info = await stat(this.tokensStudioDir);
152
- if (!info.isDirectory()) {
153
- throw new Error(`${this.tokensStudioDir} is not a directory`);
154
- }
155
- }
156
- catch (error) {
157
- throw new Error(`[design-sync:figma] Tokens Studio metadata directory missing at ${this.tokensStudioDir}: ${error.message}`);
158
- }
159
- for (const file of required) {
160
- const path = join(this.tokensStudioDir, file);
161
- try {
162
- const raw = await readFile(path, "utf8");
163
- JSON.parse(raw);
164
- }
165
- catch (error) {
166
- errors.push(`${path}: ${error.message}`);
167
- }
168
- }
169
- if (errors.length > 0) {
170
- throw new Error(`[design-sync:figma] Tokens Studio metadata invalid:\n - ${errors.join("\n - ")}`);
171
- }
172
- }
173
- }
174
- function filterSets(sets, themes) {
175
- if (!themes || themes.length === 0)
176
- return sets;
177
- const wanted = new Set(themes);
178
- return sets.filter((s) => wanted.has(s.name) || wanted.has(s.relativePath));
179
- }
@@ -1,21 +0,0 @@
1
- import type { DesignSyncProvider, HealthStatus, PenpotProviderConfig, PullOptions, PullResult, PushOptions, PushResult } from "../types";
2
- export declare class PenpotProvider implements DesignSyncProvider {
3
- readonly name: "penpot";
4
- private readonly tokensDir;
5
- private readonly tokensStudioDir;
6
- private readonly apiUrl;
7
- private readonly token;
8
- private readonly fileId;
9
- private readonly teamId;
10
- constructor(config: PenpotProviderConfig);
11
- pull(options?: PullOptions): Promise<PullResult>;
12
- push(options?: PushOptions): Promise<PushResult>;
13
- healthcheck(): Promise<HealthStatus>;
14
- /**
15
- * Reserved for future use — exposes the configured tokens-studio directory
16
- * so consumers (e.g. CI workflows) can attach Penpot-side metadata mirrors.
17
- */
18
- getTokensStudioDir(): string;
19
- private credsReady;
20
- }
21
- //# sourceMappingURL=penpot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"penpot.d.ts","sourceRoot":"","sources":["../../src/providers/penpot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACX,MAAM,UAAU,CAAC;AAmBlB,qBAAa,cAAe,YAAW,kBAAkB;IACvD,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;gBAEhC,MAAM,EAAE,oBAAoB;IAelC,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IA0BpD,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IA8CpD,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;IAyB1C;;;OAGG;IACH,kBAAkB,IAAI,MAAM;IAI5B,OAAO,CAAC,UAAU;CAGnB"}
@@ -1,137 +0,0 @@
1
- import { logger } from "@nebutra/logger";
2
- import { defaultTokensDir, defaultTokensStudioDir, readTokenSets, validateDtcgTree } from "../io";
3
- // =============================================================================
4
- // Penpot Provider — China-friendly + self-hostable Figma alternative
5
- // =============================================================================
6
- // Penpot speaks DTCG natively (one of its differentiators) and exposes a
7
- // public REST API. The provider is wired with full surface area so customers
8
- // can swap providers without changing application code, but real network
9
- // calls stay behind a `dryRun || !credsReady` guard until the operator
10
- // explicitly provisions PENPOT_TOKEN.
11
- //
12
- // Why this matters:
13
- // - Penpot can be self-hosted, sidesteps the Figma block in mainland China.
14
- // - DTCG-native means we do not need a translation step like with Figma.
15
- // - Tokens Studio plugin also targets Penpot — designers keep the same UX.
16
- // =============================================================================
17
- const DEFAULT_PENPOT_API = "https://design.penpot.app/api";
18
- export class PenpotProvider {
19
- name = "penpot";
20
- tokensDir;
21
- tokensStudioDir;
22
- apiUrl;
23
- token;
24
- fileId;
25
- teamId;
26
- constructor(config) {
27
- this.tokensDir = config.tokensDir ?? defaultTokensDir();
28
- this.tokensStudioDir = config.tokensStudioDir ?? defaultTokensStudioDir();
29
- this.apiUrl = config.apiUrl ?? process.env.PENPOT_API_URL ?? DEFAULT_PENPOT_API;
30
- this.token = config.token ?? process.env.PENPOT_TOKEN ?? undefined;
31
- this.fileId = config.fileId ?? process.env.PENPOT_FILE_ID ?? undefined;
32
- this.teamId = config.teamId ?? process.env.PENPOT_TEAM_ID ?? undefined;
33
- logger.info("[design-sync:penpot] Provider initialised", {
34
- apiUrl: this.apiUrl,
35
- hasToken: Boolean(this.token),
36
- hasFileId: Boolean(this.fileId),
37
- });
38
- }
39
- async pull(options = {}) {
40
- if (!this.credsReady()) {
41
- // No credentials → fall through to local DTCG, mirroring git-only.
42
- const sets = await readTokenSets(this.tokensDir);
43
- const filtered = filterSets(sets, options.themes);
44
- logger.warn("[design-sync:penpot] pull falling back to local DTCG (no PENPOT_TOKEN)");
45
- return {
46
- sets: filtered,
47
- written: false,
48
- provider: "penpot",
49
- pulledAt: new Date().toISOString(),
50
- summary: `penpot: PENPOT_TOKEN missing — returned ${filtered.length} local DTCG set(s)`,
51
- };
52
- }
53
- // Real pull placeholder — when wired up, this calls:
54
- // GET {apiUrl}/rpc/command/get-file?id={fileId}
55
- // Authorization: Token {token}
56
- // and projects the design-tokens collection back into DTCG sets.
57
- // See https://design.penpot.app/api/docs for the full RPC catalogue.
58
- throw new Error("[design-sync:penpot] live pull is not yet implemented. " +
59
- "Unset PENPOT_TOKEN to fall back to local DTCG, or open packages/design/design-sync/DESIGN.md for the rollout plan.");
60
- }
61
- async push(options = {}) {
62
- const all = await readTokenSets(this.tokensDir);
63
- const sets = filterSets(all, options.themes);
64
- for (const set of sets) {
65
- const errors = validateDtcgTree(set.tokens);
66
- if (errors.length > 0) {
67
- throw new Error(`[design-sync:penpot] DTCG validation failed for ${set.relativePath}:\n - ${errors.join("\n - ")}`);
68
- }
69
- }
70
- const credsReady = this.credsReady();
71
- const explicitDryRun = options.dryRun ?? false;
72
- const dryRun = explicitDryRun || !credsReady;
73
- if (dryRun) {
74
- logger.warn("[design-sync:penpot] push skipped (dry-run scaffold)", {
75
- reason: credsReady ? "explicit dryRun" : "missing credentials",
76
- sets: sets.length,
77
- });
78
- return {
79
- pushed: false,
80
- sets: sets.map((s) => s.relativePath),
81
- provider: "penpot",
82
- pushedAt: new Date().toISOString(),
83
- summary: credsReady
84
- ? `penpot: dry-run — would POST ${sets.length} DTCG set(s) to ${this.apiUrl}/rpc/command/update-file-design-tokens`
85
- : "penpot: dry-run — PENPOT_TOKEN or PENPOT_FILE_ID missing",
86
- dryRun: true,
87
- };
88
- }
89
- // Real push placeholder — when wired up, this calls:
90
- // POST {apiUrl}/rpc/command/update-file-design-tokens
91
- // Authorization: Token {token}
92
- // body: { fileId, tokens: dtcgTree }
93
- throw new Error("[design-sync:penpot] live push is not yet implemented. " +
94
- "Use { dryRun: true } until the Penpot RPC integration is wired up.");
95
- }
96
- async healthcheck() {
97
- const detected = [];
98
- const missing = [];
99
- if (this.token)
100
- detected.push("PENPOT_TOKEN");
101
- else
102
- missing.push("PENPOT_TOKEN");
103
- if (this.fileId)
104
- detected.push("PENPOT_FILE_ID");
105
- else
106
- missing.push("PENPOT_FILE_ID");
107
- if (this.teamId)
108
- detected.push("PENPOT_TEAM_ID");
109
- detected.push(`PENPOT_API_URL=${this.apiUrl}`);
110
- const ok = missing.length === 0;
111
- return {
112
- ok,
113
- provider: "penpot",
114
- message: ok
115
- ? `penpot: credentials present (api=${this.apiUrl})`
116
- : `penpot: not ready — missing ${missing.join(", ")}`,
117
- detectedEnv: detected,
118
- missingEnv: missing,
119
- };
120
- }
121
- /**
122
- * Reserved for future use — exposes the configured tokens-studio directory
123
- * so consumers (e.g. CI workflows) can attach Penpot-side metadata mirrors.
124
- */
125
- getTokensStudioDir() {
126
- return this.tokensStudioDir;
127
- }
128
- credsReady() {
129
- return Boolean(this.token && this.fileId);
130
- }
131
- }
132
- function filterSets(sets, themes) {
133
- if (!themes || themes.length === 0)
134
- return sets;
135
- const wanted = new Set(themes);
136
- return sets.filter((s) => wanted.has(s.name) || wanted.has(s.relativePath));
137
- }