@hegemonart/get-design-done 1.59.3 → 1.59.4
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +31 -0
- package/SKILL.md +2 -0
- package/figma-plugin/README.md +61 -0
- package/figma-plugin/code.ts +36 -0
- package/figma-plugin/manifest.json +12 -0
- package/figma-plugin/package-lock.json +35 -0
- package/figma-plugin/package.json +12 -0
- package/figma-plugin/src/export-variables.ts +144 -0
- package/figma-plugin/src/payload-schema.ts +250 -0
- package/figma-plugin/tsconfig.json +16 -0
- package/figma-plugin/ui.html +44 -0
- package/hooks/gdd-intel-trigger.js +3 -3
- package/package.json +6 -1
- package/reference/DEPRECATIONS.md +3 -3
- package/reference/live-mode-integration.md +1 -1
- package/reference/registry.json +1 -1
- package/reference/skill-metadata.md +4 -4
- package/reference/skill-placeholders.md +2 -2
- package/scripts/build-skills.cjs +146 -0
- package/scripts/generate-skill-frontmatter.cjs +243 -0
- package/scripts/lib/manifest/scaffolder.cjs +1 -1
- package/scripts/lib/manifest/schemas/skills.schema.json +1 -1
- package/scripts/lib/manifest/skills.json +1 -1
- package/scripts/lib/new-addendum.cjs +1 -1
- package/scripts/skill-templates/README.md +90 -0
- package/scripts/skill-templates/add-backlog/SKILL.md +48 -0
- package/scripts/skill-templates/analyze-dependencies/SKILL.md +95 -0
- package/scripts/skill-templates/apply-reflections/SKILL.md +109 -0
- package/scripts/skill-templates/apply-reflections/apply-reflections-procedure.md +170 -0
- package/scripts/skill-templates/audit/SKILL.md +79 -0
- package/scripts/skill-templates/bandit-reset/SKILL.md +91 -0
- package/scripts/skill-templates/bandit-status/SKILL.md +94 -0
- package/scripts/skill-templates/benchmark/SKILL.md +65 -0
- package/scripts/skill-templates/bootstrap-ds/SKILL.md +43 -0
- package/scripts/skill-templates/brief/SKILL.md +145 -0
- package/scripts/skill-templates/budget/SKILL.md +45 -0
- package/scripts/skill-templates/cache-manager/SKILL.md +66 -0
- package/scripts/skill-templates/cache-manager/cache-policy.md +126 -0
- package/scripts/skill-templates/check-update/SKILL.md +98 -0
- package/scripts/skill-templates/compare/SKILL.md +82 -0
- package/scripts/skill-templates/compare/compare-rubric.md +171 -0
- package/scripts/skill-templates/complete-cycle/SKILL.md +81 -0
- package/scripts/skill-templates/connections/SKILL.md +71 -0
- package/scripts/skill-templates/connections/connections-onboarding.md +608 -0
- package/scripts/skill-templates/context/SKILL.md +137 -0
- package/scripts/skill-templates/continue/SKILL.md +24 -0
- package/scripts/skill-templates/darkmode/SKILL.md +76 -0
- package/scripts/skill-templates/darkmode/darkmode-audit-procedure.md +258 -0
- package/scripts/skill-templates/debug/SKILL.md +41 -0
- package/scripts/skill-templates/debug/debug-feedback-loops.md +119 -0
- package/scripts/skill-templates/design/SKILL.md +118 -0
- package/scripts/skill-templates/design/design-procedure.md +304 -0
- package/scripts/skill-templates/discuss/SKILL.md +96 -0
- package/scripts/skill-templates/do/SKILL.md +45 -0
- package/scripts/skill-templates/explore/SKILL.md +118 -0
- package/scripts/skill-templates/explore/explore-procedure.md +267 -0
- package/scripts/skill-templates/export/SKILL.md +30 -0
- package/scripts/skill-templates/extract-learnings/SKILL.md +114 -0
- package/scripts/skill-templates/fast/SKILL.md +91 -0
- package/scripts/skill-templates/figma-extract/SKILL.md +64 -0
- package/scripts/skill-templates/figma-write/SKILL.md +50 -0
- package/scripts/skill-templates/graphify/SKILL.md +49 -0
- package/scripts/skill-templates/health/SKILL.md +99 -0
- package/scripts/skill-templates/health/health-mcp-detection.md +44 -0
- package/scripts/skill-templates/health/health-skill-length-report.md +69 -0
- package/scripts/skill-templates/help/SKILL.md +60 -0
- package/scripts/skill-templates/instinct/SKILL.md +111 -0
- package/scripts/skill-templates/list-assumptions/SKILL.md +61 -0
- package/scripts/skill-templates/list-pins/SKILL.md +27 -0
- package/scripts/skill-templates/live/SKILL.md +98 -0
- package/scripts/skill-templates/locale/SKILL.md +51 -0
- package/scripts/skill-templates/map/SKILL.md +89 -0
- package/scripts/skill-templates/migrate/SKILL.md +70 -0
- package/scripts/skill-templates/migrate-context/SKILL.md +123 -0
- package/scripts/skill-templates/new-addendum/SKILL.md +81 -0
- package/scripts/skill-templates/new-cycle/SKILL.md +37 -0
- package/scripts/skill-templates/new-project/SKILL.md +53 -0
- package/scripts/skill-templates/new-skill/SKILL.md +90 -0
- package/scripts/skill-templates/next/SKILL.md +68 -0
- package/scripts/skill-templates/note/SKILL.md +48 -0
- package/scripts/skill-templates/openrouter-status/SKILL.md +86 -0
- package/scripts/skill-templates/optimize/SKILL.md +97 -0
- package/scripts/skill-templates/override/SKILL.md +86 -0
- package/scripts/skill-templates/paper-write/SKILL.md +54 -0
- package/scripts/skill-templates/pause/SKILL.md +77 -0
- package/scripts/skill-templates/peer-cli-add/SKILL.md +88 -0
- package/scripts/skill-templates/peer-cli-add/peer-cli-protocol.md +161 -0
- package/scripts/skill-templates/peer-cli-customize/SKILL.md +89 -0
- package/scripts/skill-templates/peers/SKILL.md +96 -0
- package/scripts/skill-templates/pencil-write/SKILL.md +54 -0
- package/scripts/skill-templates/pin/SKILL.md +37 -0
- package/scripts/skill-templates/plan/SKILL.md +105 -0
- package/scripts/skill-templates/plan/plan-procedure.md +278 -0
- package/scripts/skill-templates/plant-seed/SKILL.md +48 -0
- package/scripts/skill-templates/pr-branch/SKILL.md +32 -0
- package/scripts/skill-templates/progress/SKILL.md +107 -0
- package/scripts/skill-templates/quality-gate/SKILL.md +90 -0
- package/scripts/skill-templates/quality-gate/threat-modeling.md +101 -0
- package/scripts/skill-templates/quick/SKILL.md +44 -0
- package/scripts/skill-templates/reapply-patches/SKILL.md +32 -0
- package/scripts/skill-templates/recall/SKILL.md +75 -0
- package/scripts/skill-templates/reflect/SKILL.md +85 -0
- package/scripts/skill-templates/reflect/procedures/capability-gap-scan.md +119 -0
- package/scripts/skill-templates/report-issue/SKILL.md +53 -0
- package/scripts/skill-templates/report-issue/report-issue-procedure.md +119 -0
- package/scripts/skill-templates/resume/SKILL.md +93 -0
- package/scripts/skill-templates/review-backlog/SKILL.md +46 -0
- package/scripts/skill-templates/review-decisions/SKILL.md +42 -0
- package/scripts/skill-templates/roi/SKILL.md +54 -0
- package/scripts/skill-templates/rollout-status/SKILL.md +35 -0
- package/scripts/skill-templates/router/SKILL.md +89 -0
- package/scripts/skill-templates/router/capability-gap-emitter.md +65 -0
- package/scripts/skill-templates/router/router-pick-emitter.md +78 -0
- package/scripts/skill-templates/router/router-rules.md +84 -0
- package/scripts/skill-templates/settings/SKILL.md +87 -0
- package/scripts/skill-templates/ship/SKILL.md +48 -0
- package/scripts/skill-templates/sketch/SKILL.md +78 -0
- package/scripts/skill-templates/sketch-wrap-up/SKILL.md +92 -0
- package/scripts/skill-templates/skill-manifest/SKILL.md +79 -0
- package/scripts/skill-templates/spike/SKILL.md +67 -0
- package/scripts/skill-templates/spike-wrap-up/SKILL.md +86 -0
- package/scripts/skill-templates/start/SKILL.md +67 -0
- package/scripts/skill-templates/start/start-procedure.md +115 -0
- package/scripts/skill-templates/state/SKILL.md +106 -0
- package/scripts/skill-templates/stats/SKILL.md +51 -0
- package/scripts/skill-templates/style/SKILL.md +71 -0
- package/scripts/skill-templates/style/style-doc-procedure.md +150 -0
- package/scripts/skill-templates/synthesize/SKILL.md +94 -0
- package/scripts/skill-templates/timeline/SKILL.md +66 -0
- package/scripts/skill-templates/todo/SKILL.md +64 -0
- package/scripts/skill-templates/turn-closeout/SKILL.md +95 -0
- package/scripts/skill-templates/undo/SKILL.md +31 -0
- package/scripts/skill-templates/unlock-decision/SKILL.md +54 -0
- package/scripts/skill-templates/unpin/SKILL.md +31 -0
- package/scripts/skill-templates/update/SKILL.md +56 -0
- package/scripts/skill-templates/using-gdd/SKILL.md +78 -0
- package/scripts/skill-templates/verify/SKILL.md +113 -0
- package/scripts/skill-templates/verify/verify-procedure.md +511 -0
- package/scripts/skill-templates/warm-cache/SKILL.md +81 -0
- package/scripts/skill-templates/watch-authorities/SKILL.md +82 -0
- package/scripts/skill-templates/zoom-out/SKILL.md +26 -0
- package/sdk/cli/commands/build.ts +2 -2
- package/sdk/cli/index.js +2 -2
- package/sdk/cli/index.ts +1 -1
- package/skills/README.md +22 -14
- package/skills/help/SKILL.md +28 -55
- package/skills/new-skill/SKILL.md +5 -5
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
},
|
|
6
6
|
"metadata": {
|
|
7
7
|
"description": "Get Design Done — 5-stage agent-orchestrated design pipeline (Brief → Explore → Plan → Design → Verify) for AI coding agents. 64 agents, 95 skills, 39 connection integrations, two MCP servers, opt-in SQLite state backbone, bidirectional Figma write-back, and a reflector-driven self-improvement loop. Cross-runtime install for Claude Code, Codex, Cursor, OpenCode, Gemini, and more.",
|
|
8
|
-
"version": "1.59.
|
|
8
|
+
"version": "1.59.4"
|
|
9
9
|
},
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "get-design-done",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"description": "Agent-orchestrated 5-stage design pipeline (Brief → Explore → Plan → Design → Verify) for AI coding agents. 64 specialized agents, 95 skills, 39 connection integrations (Figma, Refero, Preview, Storybook, Chromatic, Graphify, Linear, Jira, Notion, …), bidirectional Figma write-back, queryable intel store, opt-in SQLite state backbone, and a reflector-driven self-improvement loop. Two MCP servers (gdd-state for typed STATE mutators, gdd-mcp for 13 read-only project-priming tools), tier-aware routing with cost telemetry, and defense-in-depth hooks (protected paths, MCP circuit breaker, injection scanner, budget enforcer). Cross-runtime install for Claude Code, Codex, Cursor, OpenCode, Gemini, Copilot, and more.",
|
|
15
|
-
"version": "1.59.
|
|
15
|
+
"version": "1.59.4",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "hegemonart"
|
|
18
18
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "get-design-done",
|
|
3
3
|
"short_name": "gdd",
|
|
4
|
-
"version": "1.59.
|
|
4
|
+
"version": "1.59.4",
|
|
5
5
|
"description": "Agent-orchestrated 5-stage design pipeline (Brief → Explore → Plan → Design → Verify) for AI coding agents. 64 specialized agents, 95 skills, 39 connection integrations (Figma, Refero, Preview, Storybook, Chromatic, Graphify, Linear, Jira, Notion, …), bidirectional Figma write-back, queryable intel store for O(1) design-surface lookups, opt-in SQLite state backbone, and a reflector-driven self-improvement loop. Two MCP servers (`gdd-state` for typed STATE mutators, `gdd-mcp` for 13 read-only project-priming tools), tier-aware agent routing with cost telemetry, defense-in-depth hooks (protected paths, MCP circuit breaker, injection scanner, budget enforcer), and a cross-runtime install layer for Claude Code, Codex, Cursor, OpenCode, Gemini, Copilot, and more.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "hegemonart",
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,37 @@ All notable changes to get-design-done are documented here. Versions follow [sem
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.59.4] - 2026-06-04
|
|
8
|
+
|
|
9
|
+
Fourth point release of the **v1.59 "Audit Closeout & Honesty Pass"** milestone. Skill-surface + build hygiene.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **`skill-templates/` relocated to `scripts/skill-templates/`** (source-dir move, git history preserved; 36 reference updates). The committed `skills/` build output is unchanged, so the `build:skills:check` drift gate stays meaningful.
|
|
14
|
+
- **`/gdd:help` is now complete and dynamic.** It reads `scripts/lib/manifest/skills.json` and renders every skill, replacing a hardcoded ~41-command subset (of 95). Root SKILL.md Jump Mode now notes it is a curated subset and points to `/gdd:help` for the full manifest-rendered reference.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **npm-installed users can now author skills.** `package.json#files[]` ships `scripts/skill-templates/`, `scripts/build-skills.cjs`, and `scripts/generate-skill-frontmatter.cjs` (so `/gdd:new-skill` + rebuild work off an `npm install`), plus the figma plugin source (`figma-plugin/`).
|
|
19
|
+
- **`codegen:schemas:check` drift gate** (EOL-agnostic) wired into CI, closing the one previously un-gated generator (`reference/schemas/generated.d.ts`).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **Stale "gitignored" README claims** corrected: `skills/` has been a committed build artifact since v1.58.1, not gitignored.
|
|
24
|
+
- Pre-existing stale `source/skills` regex in `hooks/gdd-intel-trigger.js` repointed to `scripts/skill-templates`.
|
|
25
|
+
|
|
26
|
+
### Note
|
|
27
|
+
|
|
28
|
+
- The "7 Phase-28.8 baseline regen pending" skips named in the plan were already resolved by earlier phases (no such markers remain), so there was nothing to burn down.
|
|
29
|
+
|
|
30
|
+
### Breaking changes
|
|
31
|
+
|
|
32
|
+
None.
|
|
33
|
+
|
|
34
|
+
5,049/5,049 tests pass.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
7
38
|
## [1.59.3] - 2026-06-04
|
|
8
39
|
|
|
9
40
|
Third point release of the **v1.59 "Audit Closeout & Honesty Pass"** milestone. A routing-coherence pass on agent model/tier declarations.
|
package/SKILL.md
CHANGED
|
@@ -199,6 +199,8 @@ Use `[✓]` for complete, `[→]` for current, `[ ]` for pending, `[!]` for gaps
|
|
|
199
199
|
|
|
200
200
|
If `$ARGUMENTS` is a stage or command name - invoke it directly, no state check:
|
|
201
201
|
|
|
202
|
+
> This table lists the common stage and shortcut routes. Every skill in `scripts/lib/manifest/skills.json` is auto-resolvable as `/gdd:<name>`; run `/gdd:help` for the complete, always-current command reference (rendered from the manifest, never a hardcoded subset).
|
|
203
|
+
|
|
202
204
|
```
|
|
203
205
|
/gdd:brief → Skill("get-design-done:gdd-brief")
|
|
204
206
|
/gdd:explore → Skill("get-design-done:gdd-explore")
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# GDD Sync — Figma plugin
|
|
2
|
+
|
|
3
|
+
`GDD Sync` is the Figma-side half of GDD's design-system extractor (Path C). It reads
|
|
4
|
+
your file's **local Figma variables** from inside Figma and POSTs them as JSON to a
|
|
5
|
+
GDD extract receiver listening on `localhost:5179`.
|
|
6
|
+
|
|
7
|
+
## Why this exists
|
|
8
|
+
|
|
9
|
+
GDD's extractor pulls a design system from the Figma REST API into a compact local
|
|
10
|
+
digest. The Variables REST API, however, is **Enterprise-only** — it returns `403` on
|
|
11
|
+
Free/Pro/Org plans. A Figma plugin has full `figma.variables` access on **any** plan, so
|
|
12
|
+
this plugin fills that gap: it reads what the API cannot and ships it to GDD locally.
|
|
13
|
+
|
|
14
|
+
## Security
|
|
15
|
+
|
|
16
|
+
The plugin can talk to **localhost only**. `manifest.json` declares
|
|
17
|
+
`networkAccess.allowedDomains` as exactly:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
["http://localhost:5179", "http://127.0.0.1:5179"]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
No wildcard, no external host. This is the single hard security boundary of Path C
|
|
24
|
+
(decision D-06): the plugin has no exfiltration surface — it can reach the local GDD
|
|
25
|
+
receiver and nothing else.
|
|
26
|
+
|
|
27
|
+
## Development
|
|
28
|
+
|
|
29
|
+
This is a standalone TypeScript package (decision D-05). It is **not** part of the root
|
|
30
|
+
`get-design-done` package.
|
|
31
|
+
|
|
32
|
+
### Build
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cd figma-plugin
|
|
36
|
+
npm install
|
|
37
|
+
npm run build # runs tsc → emits code.js next to code.ts
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`code.ts` (sandbox entry) and `src/*.ts` compile under `tsconfig.json` against
|
|
41
|
+
`@figma/plugin-typings` into `code.js`, which `manifest.json` references via `main`.
|
|
42
|
+
|
|
43
|
+
### Dev-install (Figma desktop)
|
|
44
|
+
|
|
45
|
+
1. Build (`npm run build`) so `code.js` exists.
|
|
46
|
+
2. In the **Figma desktop app**: **Plugins → Development → Import plugin from manifest…**
|
|
47
|
+
3. Select `figma-plugin/manifest.json`.
|
|
48
|
+
|
|
49
|
+
### Usage
|
|
50
|
+
|
|
51
|
+
1. Start a GDD extract run so the receiver is listening on `localhost:5179`.
|
|
52
|
+
2. Open the Figma file whose variables you want to export.
|
|
53
|
+
3. Run **GDD Sync** (Plugins → Development → GDD Sync).
|
|
54
|
+
4. Click **Export to GDD**. The plugin reads the file's local variables and POSTs them
|
|
55
|
+
to the receiver, which writes them into the extract cache.
|
|
56
|
+
|
|
57
|
+
## Distribution
|
|
58
|
+
|
|
59
|
+
Community submission is **deferred** (decision D-07). For v1.31.0 the supported path is
|
|
60
|
+
**dev-install** via the manifest, as documented above. Publishing to the Figma Community
|
|
61
|
+
is a follow-up that will not block the version cut.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// GDD Sync — Figma plugin sandbox entry (main thread).
|
|
2
|
+
//
|
|
3
|
+
// SCAFFOLD (Plan 31-04): this is the shell only. It opens the single-button UI
|
|
4
|
+
// (ui.html) and wires the message plumbing that routes the "export" action to
|
|
5
|
+
// exportVariables(). The actual variables-read + POST logic lives in
|
|
6
|
+
// ./src/export-variables (a compiling PLACEHOLDER in this plan; Plan 31-05
|
|
7
|
+
// replaces it with the real implementation).
|
|
8
|
+
//
|
|
9
|
+
// Message contract (the seam 31-05 builds on):
|
|
10
|
+
// ui.html -- parent.postMessage({ pluginMessage: { type: 'export' } }) --> code.ts
|
|
11
|
+
// code.ts -- figma.ui.onmessage receives { type: 'export' } --> exportVariables()
|
|
12
|
+
// exportVariables() (31-05) reads figma.variables, builds the payload, and
|
|
13
|
+
// POSTs it to http://localhost:5179/variables (the GDD receiver, Plan 31-06).
|
|
14
|
+
//
|
|
15
|
+
// Security: the only network destination the manifest permits is localhost:5179
|
|
16
|
+
// (manifest.networkAccess.allowedDomains, D-06). code.ts itself opens no sockets.
|
|
17
|
+
|
|
18
|
+
import { exportVariables } from './src/export-variables';
|
|
19
|
+
|
|
20
|
+
// Messages the UI may post to the sandbox. 31-05 may extend this union.
|
|
21
|
+
interface ExportMessage {
|
|
22
|
+
type: 'export';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type UiMessage = ExportMessage;
|
|
26
|
+
|
|
27
|
+
figma.showUI(__html__, { width: 280, height: 160 });
|
|
28
|
+
|
|
29
|
+
figma.ui.onmessage = (msg: UiMessage): void => {
|
|
30
|
+
if (msg && msg.type === 'export') {
|
|
31
|
+
// Delegate to the export entry point. 31-05 supplies the real logic;
|
|
32
|
+
// this scaffold ships a notify-only placeholder so code.ts compiles
|
|
33
|
+
// standalone in Wave B.1.
|
|
34
|
+
void exportVariables();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "GDD Sync",
|
|
3
|
+
"id": "gdd-sync-figma-variables-export",
|
|
4
|
+
"api": "1.0.0",
|
|
5
|
+
"main": "code.js",
|
|
6
|
+
"ui": "ui.html",
|
|
7
|
+
"editorType": ["figma"],
|
|
8
|
+
"networkAccess": {
|
|
9
|
+
"allowedDomains": ["http://localhost:5179", "http://127.0.0.1:5179"],
|
|
10
|
+
"reasoning": "GDD Sync POSTs locally-read Figma variables to an ephemeral GDD extract receiver bound to 127.0.0.1:5179 ONLY (Path C, decision D-06). The plugin has NO other network surface: no external host, no wildcard. This is the security boundary that prevents design-data exfiltration."
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gdd-figma-sync-plugin",
|
|
3
|
+
"lockfileVersion": 3,
|
|
4
|
+
"requires": true,
|
|
5
|
+
"packages": {
|
|
6
|
+
"": {
|
|
7
|
+
"name": "gdd-figma-sync-plugin",
|
|
8
|
+
"devDependencies": {
|
|
9
|
+
"@figma/plugin-typings": "^1.109.0",
|
|
10
|
+
"typescript": "^5.7.2"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"node_modules/@figma/plugin-typings": {
|
|
14
|
+
"version": "1.127.0",
|
|
15
|
+
"resolved": "https://registry.npmjs.org/@figma/plugin-typings/-/plugin-typings-1.127.0.tgz",
|
|
16
|
+
"integrity": "sha512-Y8fjfUCdWN6bUTs1wsd9GFZ3zF4USDVNmmxfUo/4Ia7NmFemSK2nBxOu7BKcusEHCERwiO7N8iOqw5jwvbL80g==",
|
|
17
|
+
"dev": true,
|
|
18
|
+
"license": "MIT License"
|
|
19
|
+
},
|
|
20
|
+
"node_modules/typescript": {
|
|
21
|
+
"version": "5.9.3",
|
|
22
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
|
23
|
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
24
|
+
"dev": true,
|
|
25
|
+
"license": "Apache-2.0",
|
|
26
|
+
"bin": {
|
|
27
|
+
"tsc": "bin/tsc",
|
|
28
|
+
"tsserver": "bin/tsserver"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=14.17"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gdd-figma-sync-plugin",
|
|
3
|
+
"private": true,
|
|
4
|
+
"description": "GDD Sync — Figma plugin that reads local Figma variables and POSTs them to the GDD extract receiver on localhost:5179 (Path C for non-Enterprise token extraction).",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc"
|
|
7
|
+
},
|
|
8
|
+
"devDependencies": {
|
|
9
|
+
"@figma/plugin-typings": "^1.109.0",
|
|
10
|
+
"typescript": "^5.7.2"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// figma-plugin/src/export-variables.ts — Plan 31-05 (Wave B.2)
|
|
2
|
+
//
|
|
3
|
+
// Path C of the three-path token extraction (D-04). The Variables REST API is
|
|
4
|
+
// Enterprise-only (the spike hit a 403); the in-Figma sandbox Variables API
|
|
5
|
+
// (figma.variables.*) works on ANY plan. This module reads the local variable
|
|
6
|
+
// collections + variables from inside Figma, resolves aliases, includes mode
|
|
7
|
+
// metadata, emits ALL local variables (D-13 — no published filter), builds a
|
|
8
|
+
// payload conforming to the receiver's payload-schema.json (31-06), and POSTs it
|
|
9
|
+
// to the ephemeral localhost receiver (D-06: 127.0.0.1:5179 ONLY).
|
|
10
|
+
//
|
|
11
|
+
// Replaces the 31-04 placeholder. Contract preserved: `export async function
|
|
12
|
+
// exportVariables(): Promise<void>` is what code.ts calls on the { type:'export' }
|
|
13
|
+
// message. The PURE builder (buildPayload, re-exported from ./payload-schema) is
|
|
14
|
+
// kept network-free so the offline test drives it against a figma.variables mock.
|
|
15
|
+
//
|
|
16
|
+
// Reading strategy: the async API (getLocalVariableCollectionsAsync /
|
|
17
|
+
// getLocalVariablesAsync / getVariableByIdAsync) is used rather than the
|
|
18
|
+
// deprecated sync variants — the sync methods throw under
|
|
19
|
+
// `"documentAccess":"dynamic-page"` manifests, and async is the documented,
|
|
20
|
+
// future-proof surface. The pure buildPayload stays synchronous so the data
|
|
21
|
+
// gathering (async, Figma-bound) and the shaping (sync, testable) are separated.
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
buildPayload,
|
|
25
|
+
type GddSyncPayload,
|
|
26
|
+
type RawCollectionLike,
|
|
27
|
+
type RawVariableLike,
|
|
28
|
+
type VariableNameResolver,
|
|
29
|
+
} from './payload-schema';
|
|
30
|
+
|
|
31
|
+
// Re-export the pure builder + payload type so code.ts / tests have one import
|
|
32
|
+
// site for the plugin-side contract.
|
|
33
|
+
export {
|
|
34
|
+
buildPayload,
|
|
35
|
+
isGddSyncPayload,
|
|
36
|
+
type GddSyncPayload,
|
|
37
|
+
} from './payload-schema';
|
|
38
|
+
|
|
39
|
+
// D-06: the ONE permitted network destination. Matches the receiver's bind host
|
|
40
|
+
// (127.0.0.1 — receiver.cjs RECEIVER_HOST) and manifest.networkAccess.allowedDomains.
|
|
41
|
+
// Using the explicit loopback IP (not `localhost`) avoids any IPv6 `::1`
|
|
42
|
+
// resolution surprise and matches the receiver's 127.0.0.1 bind exactly.
|
|
43
|
+
export const RECEIVER_URL = 'http://127.0.0.1:5179/variables';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Read local collections + variables from the Figma sandbox and shape them into
|
|
47
|
+
* a GddSyncPayload via the pure buildPayload. Async because the non-deprecated
|
|
48
|
+
* Variables API is async. Emits ALL local variables (D-13). Alias targets are
|
|
49
|
+
* resolved to names (via getVariableByIdAsync) so the digest can render the
|
|
50
|
+
* alias chain like the spike's `{alias}` form.
|
|
51
|
+
*
|
|
52
|
+
* Separated from exportVariables() so the network POST is the only impure part.
|
|
53
|
+
*/
|
|
54
|
+
export async function gatherPayload(): Promise<GddSyncPayload> {
|
|
55
|
+
// getLocalVariableCollectionsAsync(): VariableCollection[] — { id, name, modes:[{modeId,name}] }
|
|
56
|
+
const rawCollections = await figma.variables.getLocalVariableCollectionsAsync();
|
|
57
|
+
// getLocalVariablesAsync(): Variable[] — ALL locals (D-13; no type filter).
|
|
58
|
+
const rawVariables = await figma.variables.getLocalVariablesAsync();
|
|
59
|
+
|
|
60
|
+
const collections: RawCollectionLike[] = rawCollections.map((c) => ({
|
|
61
|
+
id: c.id,
|
|
62
|
+
name: c.name,
|
|
63
|
+
modes: c.modes.map((m) => ({ modeId: m.modeId, name: m.name })),
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
const variables: RawVariableLike[] = rawVariables.map((v) => ({
|
|
67
|
+
id: v.id,
|
|
68
|
+
name: v.name,
|
|
69
|
+
resolvedType: v.resolvedType,
|
|
70
|
+
variableCollectionId: v.variableCollectionId,
|
|
71
|
+
// valuesByMode is { [modeId]: VariableValue }; pass through — buildPayload
|
|
72
|
+
// resolves alias markers + renders the flat tokens[].
|
|
73
|
+
valuesByMode: v.valuesByMode as RawVariableLike['valuesByMode'],
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
// Pre-resolve every alias target name once (async), then hand buildPayload a
|
|
77
|
+
// synchronous resolver. We gather the set of alias target ids first to avoid
|
|
78
|
+
// N awaits inside the pure builder.
|
|
79
|
+
const aliasIds = new Set<string>();
|
|
80
|
+
for (const v of rawVariables) {
|
|
81
|
+
for (const modeId of Object.keys(v.valuesByMode)) {
|
|
82
|
+
const value = v.valuesByMode[modeId] as unknown;
|
|
83
|
+
if (
|
|
84
|
+
value &&
|
|
85
|
+
typeof value === 'object' &&
|
|
86
|
+
(value as { type?: string }).type === 'VARIABLE_ALIAS' &&
|
|
87
|
+
typeof (value as { id?: string }).id === 'string'
|
|
88
|
+
) {
|
|
89
|
+
aliasIds.add((value as { id: string }).id);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const nameById = new Map<string, string>();
|
|
95
|
+
for (const id of aliasIds) {
|
|
96
|
+
try {
|
|
97
|
+
const target = await figma.variables.getVariableByIdAsync(id);
|
|
98
|
+
if (target) nameById.set(id, target.name);
|
|
99
|
+
} catch {
|
|
100
|
+
// A missing/unreadable alias target is non-fatal — buildPayload falls back
|
|
101
|
+
// to `{id}` so the reference is still recorded.
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const resolveName: VariableNameResolver = (id) => nameById.get(id);
|
|
105
|
+
|
|
106
|
+
return buildPayload(collections, variables, {
|
|
107
|
+
fileKey: figma.fileKey,
|
|
108
|
+
exportedAt: new Date().toISOString(),
|
|
109
|
+
resolveName,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The export entry point code.ts calls on the { type:'export' } message. Builds
|
|
115
|
+
* the payload then POSTs it to the receiver. Network failures + non-2xx
|
|
116
|
+
* responses are surfaced via figma.notify and NEVER crash the sandbox.
|
|
117
|
+
*/
|
|
118
|
+
export async function exportVariables(): Promise<void> {
|
|
119
|
+
let payload: GddSyncPayload;
|
|
120
|
+
try {
|
|
121
|
+
payload = await gatherPayload();
|
|
122
|
+
} catch (e) {
|
|
123
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
124
|
+
figma.notify('GDD Sync: failed to read variables — ' + msg);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const res = await fetch(RECEIVER_URL, {
|
|
130
|
+
method: 'POST',
|
|
131
|
+
headers: { 'Content-Type': 'application/json' },
|
|
132
|
+
body: JSON.stringify(payload),
|
|
133
|
+
});
|
|
134
|
+
if (!res.ok) {
|
|
135
|
+
figma.notify('GDD Sync: receiver rejected payload (' + res.status + ')');
|
|
136
|
+
} else {
|
|
137
|
+
figma.notify('GDD Sync: exported ' + payload.variables.length + ' variables');
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
// No receiver listening (the common case when no extract run is active),
|
|
141
|
+
// or any other network error. Guide the user; do not throw.
|
|
142
|
+
figma.notify('GDD Sync: no receiver on 127.0.0.1:5179 — start a GDD extract run first');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// figma-plugin/src/payload-schema.ts — Plan 31-05 (Wave B.2)
|
|
2
|
+
//
|
|
3
|
+
// Single plugin-side definition of the GDD Sync payload: the TS mirror of
|
|
4
|
+
// scripts/lib/figma-extract/payload-schema.json (31-06), the shared Path C
|
|
5
|
+
// contract (D-04, D-13). code.ts + export-variables.ts import the payload type
|
|
6
|
+
// from here; buildPayload below is the PURE, network-free core the offline test
|
|
7
|
+
// drives against a figma.variables mock.
|
|
8
|
+
//
|
|
9
|
+
// Two consumers, one payload (the make-or-break interop requirement):
|
|
10
|
+
// 1. Receiver (31-06) validates source + collections[] + variables[] against
|
|
11
|
+
// payload-schema.json before writing variables.json.
|
|
12
|
+
// 2. The digest's normalizePluginPayload (31-02) reads a FLAT tokens[] array
|
|
13
|
+
// (preferred) or payload.meta.* — it does NOT read top-level variables[].
|
|
14
|
+
// So the payload ALSO carries tokens[] (colors->hex, aliases->{name}, modes
|
|
15
|
+
// keyed by mode NAME) so plugin variables surface in DESIGN.md.
|
|
16
|
+
// additionalProperties:true permits the extra tokens[]. One object, both ends.
|
|
17
|
+
//
|
|
18
|
+
// D-13: ALL local variables are emitted — no published-only filter here; the
|
|
19
|
+
// digest filters.
|
|
20
|
+
|
|
21
|
+
/** Figma colour: 0..1 floats. `a` optional (RGB vs RGBA). */
|
|
22
|
+
export interface GddRgba {
|
|
23
|
+
r: number;
|
|
24
|
+
g: number;
|
|
25
|
+
b: number;
|
|
26
|
+
a?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Alias marker — kept resolvable: target id always, target name when looked up. */
|
|
30
|
+
export interface GddVariableAlias {
|
|
31
|
+
type: 'VARIABLE_ALIAS';
|
|
32
|
+
id: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** A per-mode value in the receiver-facing variables[] (raw, unrendered). */
|
|
37
|
+
export type GddVariableValue =
|
|
38
|
+
| number
|
|
39
|
+
| string
|
|
40
|
+
| boolean
|
|
41
|
+
| GddRgba
|
|
42
|
+
| GddVariableAlias;
|
|
43
|
+
|
|
44
|
+
// ── Receiver-facing shapes (validated against payload-schema.json) ────────────
|
|
45
|
+
|
|
46
|
+
export interface GddSyncMode {
|
|
47
|
+
modeId: string;
|
|
48
|
+
name: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface GddSyncCollection {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
modes: GddSyncMode[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface GddSyncVariable {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
/** COLOR | FLOAT | STRING | BOOLEAN (schema enum). */
|
|
61
|
+
resolvedType: string;
|
|
62
|
+
collectionId: string;
|
|
63
|
+
/** Keyed by modeId. Raw value or alias marker (digest renders later). */
|
|
64
|
+
valuesByMode: Record<string, GddVariableValue>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── Digest-interop shape: the FLAT tokens[] normalizePluginPayload reads ───────
|
|
68
|
+
// Matches digest.cjs extractTokensFromVariables() output so DESIGN.md is
|
|
69
|
+
// identical across paths: { name, type, collection, modes:{ <modeName>: rendered } }
|
|
70
|
+
// where rendered = hex for colours, `{targetName}` for aliases, primitive otherwise.
|
|
71
|
+
|
|
72
|
+
export interface GddSyncToken {
|
|
73
|
+
name: string;
|
|
74
|
+
type: string;
|
|
75
|
+
/** Collection NAME (not id) — matches digest Path A. */
|
|
76
|
+
collection?: string;
|
|
77
|
+
/** Keyed by mode NAME → rendered value. */
|
|
78
|
+
modes: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface GddSyncPayload {
|
|
82
|
+
/** Path C marker the digest/receiver key on. Literal — never anything else. */
|
|
83
|
+
source: 'gdd-plugin';
|
|
84
|
+
fileKey?: string;
|
|
85
|
+
exportedAt?: string;
|
|
86
|
+
collections: GddSyncCollection[];
|
|
87
|
+
/** ALL local variables, raw values (D-13). */
|
|
88
|
+
variables: GddSyncVariable[];
|
|
89
|
+
/** Flat rendered tokens the digest consumes (variables[] is ignored there). */
|
|
90
|
+
tokens: GddSyncToken[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── Pure value rendering (shared by the flat tokens[] builder) ────────────────
|
|
94
|
+
|
|
95
|
+
function isRgba(v: unknown): v is GddRgba {
|
|
96
|
+
return (
|
|
97
|
+
typeof v === 'object' &&
|
|
98
|
+
v !== null &&
|
|
99
|
+
typeof (v as GddRgba).r === 'number' &&
|
|
100
|
+
typeof (v as GddRgba).g === 'number' &&
|
|
101
|
+
typeof (v as GddRgba).b === 'number'
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isAlias(v: unknown): v is GddVariableAlias {
|
|
106
|
+
return (
|
|
107
|
+
typeof v === 'object' &&
|
|
108
|
+
v !== null &&
|
|
109
|
+
(v as GddVariableAlias).type === 'VARIABLE_ALIAS' &&
|
|
110
|
+
typeof (v as GddVariableAlias).id === 'string'
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Render Figma {r,g,b,a?} (0..1) to hex — mirrors digest.cjs rgbToHex. */
|
|
115
|
+
export function rgbToHex({ r, g, b, a }: GddRgba): string {
|
|
116
|
+
const to = (v: number): string =>
|
|
117
|
+
Math.round(v * 255)
|
|
118
|
+
.toString(16)
|
|
119
|
+
.padStart(2, '0');
|
|
120
|
+
const hex = `#${to(r)}${to(g)}${to(b)}`;
|
|
121
|
+
return a !== undefined && a < 1 ? `${hex}${to(a)}` : hex;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** colour→hex, alias→`{targetName}` (or `{id}`), else primitive passthrough. */
|
|
125
|
+
export function renderTokenValue(raw: GddVariableValue): unknown {
|
|
126
|
+
if (isRgba(raw)) return rgbToHex(raw);
|
|
127
|
+
if (isAlias(raw)) return `{${raw.name || raw.id}}`;
|
|
128
|
+
return raw;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ── The single pure builder (network-free; the testable core) ─────────────────
|
|
132
|
+
|
|
133
|
+
/** Minimal collection shape buildPayload needs (mirrors VariableCollection). */
|
|
134
|
+
export interface RawCollectionLike {
|
|
135
|
+
id: string;
|
|
136
|
+
name: string;
|
|
137
|
+
modes: ReadonlyArray<{ modeId: string; name: string }>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Minimal variable shape buildPayload needs (mirrors Variable). */
|
|
141
|
+
export interface RawVariableLike {
|
|
142
|
+
id: string;
|
|
143
|
+
name: string;
|
|
144
|
+
resolvedType: string;
|
|
145
|
+
variableCollectionId: string;
|
|
146
|
+
valuesByMode: Record<string, GddVariableValue>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Resolve a variable id → name (Figma's getVariableById(...)?.name). */
|
|
150
|
+
export type VariableNameResolver = (id: string) => string | undefined;
|
|
151
|
+
|
|
152
|
+
export interface BuildPayloadOptions {
|
|
153
|
+
fileKey?: string;
|
|
154
|
+
exportedAt?: string;
|
|
155
|
+
resolveName?: VariableNameResolver;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Build a GddSyncPayload from raw collections + variables. PURE: no Figma
|
|
160
|
+
* globals, no network. Emits ALL variables passed in (D-13). Produces BOTH the
|
|
161
|
+
* receiver-facing variables[] (raw values, alias markers retained with resolved
|
|
162
|
+
* name) AND the flat rendered tokens[] the digest consumes.
|
|
163
|
+
*/
|
|
164
|
+
export function buildPayload(
|
|
165
|
+
rawCollections: ReadonlyArray<RawCollectionLike>,
|
|
166
|
+
rawVariables: ReadonlyArray<RawVariableLike>,
|
|
167
|
+
opts: BuildPayloadOptions = {}
|
|
168
|
+
): GddSyncPayload {
|
|
169
|
+
const resolveName: VariableNameResolver = opts.resolveName || (() => undefined);
|
|
170
|
+
|
|
171
|
+
const collections: GddSyncCollection[] = rawCollections.map((c) => ({
|
|
172
|
+
id: c.id,
|
|
173
|
+
name: c.name,
|
|
174
|
+
modes: c.modes.map((m) => ({ modeId: m.modeId, name: m.name })),
|
|
175
|
+
}));
|
|
176
|
+
const collectionById = new Map<string, GddSyncCollection>(
|
|
177
|
+
collections.map((c) => [c.id, c])
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const variables: GddSyncVariable[] = [];
|
|
181
|
+
const tokens: GddSyncToken[] = [];
|
|
182
|
+
|
|
183
|
+
for (const v of rawVariables) {
|
|
184
|
+
// Receiver-facing valuesByMode: raw values, but resolve alias targets to a
|
|
185
|
+
// name (keep id + type) so it stays auditable. Keyed by modeId (schema).
|
|
186
|
+
const rawValuesByMode: Record<string, GddVariableValue> = {};
|
|
187
|
+
for (const modeId of Object.keys(v.valuesByMode)) {
|
|
188
|
+
const value = v.valuesByMode[modeId];
|
|
189
|
+
rawValuesByMode[modeId] = isAlias(value)
|
|
190
|
+
? { type: 'VARIABLE_ALIAS', id: value.id, name: resolveName(value.id) }
|
|
191
|
+
: value;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
variables.push({
|
|
195
|
+
id: v.id,
|
|
196
|
+
name: v.name,
|
|
197
|
+
resolvedType: v.resolvedType,
|
|
198
|
+
collectionId: v.variableCollectionId,
|
|
199
|
+
valuesByMode: rawValuesByMode,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Flat token for the digest: rendered values keyed by mode NAME so a
|
|
203
|
+
// multi-mode (light/dark) variable round-trips.
|
|
204
|
+
const collection = collectionById.get(v.variableCollectionId);
|
|
205
|
+
const modesByName: Record<string, unknown> = {};
|
|
206
|
+
const modeList = collection ? collection.modes : [];
|
|
207
|
+
if (modeList.length > 0) {
|
|
208
|
+
for (const mode of modeList) {
|
|
209
|
+
const raw = rawValuesByMode[mode.modeId];
|
|
210
|
+
if (raw !== undefined) modesByName[mode.name] = renderTokenValue(raw);
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
// No collection metadata — fall back to modeId so nothing is dropped.
|
|
214
|
+
for (const modeId of Object.keys(rawValuesByMode)) {
|
|
215
|
+
modesByName[modeId] = renderTokenValue(rawValuesByMode[modeId]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
tokens.push({
|
|
220
|
+
name: v.name,
|
|
221
|
+
type: v.resolvedType,
|
|
222
|
+
collection: collection ? collection.name : undefined,
|
|
223
|
+
modes: modesByName,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const payload: GddSyncPayload = {
|
|
228
|
+
source: 'gdd-plugin',
|
|
229
|
+
collections,
|
|
230
|
+
variables,
|
|
231
|
+
tokens,
|
|
232
|
+
};
|
|
233
|
+
if (opts.fileKey) payload.fileKey = opts.fileKey;
|
|
234
|
+
if (opts.exportedAt) payload.exportedAt = opts.exportedAt;
|
|
235
|
+
return payload;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Narrow an unknown to GddSyncPayload: the literal source marker + the two
|
|
240
|
+
* required arrays. Cheap structural check (the receiver validates fully).
|
|
241
|
+
*/
|
|
242
|
+
export function isGddSyncPayload(x: unknown): x is GddSyncPayload {
|
|
243
|
+
if (typeof x !== 'object' || x === null) return false;
|
|
244
|
+
const p = x as Partial<GddSyncPayload>;
|
|
245
|
+
return (
|
|
246
|
+
p.source === 'gdd-plugin' &&
|
|
247
|
+
Array.isArray(p.collections) &&
|
|
248
|
+
Array.isArray(p.variables)
|
|
249
|
+
);
|
|
250
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"module": "amd",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"lib": ["ES2017"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"outFile": "code.js",
|
|
9
|
+
"noEmitOnError": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"typeRoots": ["./node_modules/@types", "./node_modules/@figma"]
|
|
14
|
+
},
|
|
15
|
+
"include": ["code.ts", "src/**/*.ts"]
|
|
16
|
+
}
|