@hegemonart/get-design-done 1.13.3 → 1.14.1
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 +52 -7
- package/README.md +135 -40
- package/agents/design-component-generator.md +221 -0
- package/agents/design-context-builder.md +80 -3
- package/agents/design-paper-writer.md +131 -0
- package/agents/design-pencil-writer.md +99 -0
- package/agents/design-research-synthesizer.md +13 -1
- package/agents/design-verifier.md +51 -0
- package/connections/21st-dev.md +98 -0
- package/connections/connections.md +41 -11
- package/connections/magic-patterns.md +105 -0
- package/connections/paper-design.md +137 -0
- package/connections/pencil-dev.md +88 -0
- package/hooks/budget-enforcer.js +13 -2
- package/hooks/gdd-read-injection-scanner.js +4 -9
- package/hooks/update-check.sh +13 -0
- package/package.json +1 -1
- package/reference/ai-native-tool-interface.md +102 -0
- package/scripts/aggregate-agent-metrics.js +20 -0
- package/scripts/build-intel.cjs +13 -5
- package/scripts/injection-patterns.cjs +17 -0
- package/scripts/run-injection-scanner-ci.cjs +1 -10
- package/scripts/tests/test-authority-watcher-diff.sh +5 -1
- package/skills/check-update/SKILL.md +2 -0
- package/skills/explore/SKILL.md +53 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# AI-Native Design Tool Interface — Capability Contract
|
|
2
|
+
|
|
3
|
+
This file defines the capability-based contract that AI-native design tools must implement to integrate with the get-design-done pipeline. Two sub-categories are defined: **canvas** and **component-generator**. Future tools implement one sub-category and plug in via the same probe/read/write or probe/generate/adopt surface.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Sub-Categories
|
|
8
|
+
|
|
9
|
+
### Canvas Tools
|
|
10
|
+
|
|
11
|
+
Canvas tools treat the design canvas as both source AND destination. They expose a bidirectional read+write surface.
|
|
12
|
+
|
|
13
|
+
**Contract:**
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
probe() → { available | unavailable | not_configured }
|
|
17
|
+
|
|
18
|
+
read(selection) → {
|
|
19
|
+
jsx: string, // React JSX of component tree
|
|
20
|
+
styles: object, // computed CSS styles
|
|
21
|
+
screenshot: base64_png, // visual snapshot
|
|
22
|
+
metadata: object // component name, bounds, id
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
write(proposal) → { confirmed | rejected }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Implementations:**
|
|
29
|
+
- `connections/paper-design.md` — MCP-based; 24-tool server; budget: 100 calls/week (free)
|
|
30
|
+
- `connections/pencil-dev.md` — file-based; `.pen` YAML spec files; git-tracked; no MCP
|
|
31
|
+
|
|
32
|
+
**Pipeline stages:** `explore` (read) + `verify` (screenshot) + `design` (write via writer agent)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
### Component Generators
|
|
37
|
+
|
|
38
|
+
Component generators produce UI component code from a natural-language description and an optional design-system target. They expose a generative one-way (or roundtrip) surface.
|
|
39
|
+
|
|
40
|
+
**Contract:**
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
probe() → { available | unavailable | not_configured }
|
|
44
|
+
|
|
45
|
+
generate(description: string, ds: "shadcn"|"tailwind"|"mantine"|"chakra") → {
|
|
46
|
+
code: string, // component source code
|
|
47
|
+
preview_url: string, // hosted preview URL
|
|
48
|
+
variants: array, // multiple generated variations
|
|
49
|
+
component_id: string // for adopt/annotate operations
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
adopt(variant: object) → { confirmed | rejected }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Implementations:**
|
|
56
|
+
- `connections/21st-dev.md` — Magic MCP; `npx @21st-dev/magic@latest init`; marketplace prior-art gate
|
|
57
|
+
- `connections/magic-patterns.md` — Claude connector (`mcp__magic_patterns*`) + API key fallback; DS-aware generation
|
|
58
|
+
|
|
59
|
+
**Pipeline stages:** `explore` (prior-art gate for 21st.dev) + `design` (generate + adopt)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Shared Probe Pattern
|
|
64
|
+
|
|
65
|
+
All AI-native tools use the three-value status schema from `connections/connections.md`:
|
|
66
|
+
|
|
67
|
+
| Status | Meaning |
|
|
68
|
+
|--------|---------|
|
|
69
|
+
| `available` | Tool confirmed present and responsive |
|
|
70
|
+
| `unavailable` | Tool present but errored (rate-limited, auth failure) |
|
|
71
|
+
| `not_configured` | ToolSearch returned empty or no .pen files found |
|
|
72
|
+
|
|
73
|
+
STATE.md format: `<tool-name>: <status>` in the `<connections>` block.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Extending with Future Tools
|
|
78
|
+
|
|
79
|
+
To add a new AI-native design tool:
|
|
80
|
+
|
|
81
|
+
1. Determine sub-category: **canvas** (bidirectional design source) or **component-generator** (code generator).
|
|
82
|
+
2. Create `connections/<tool-name>.md` following the frozen template in `connections/figma.md`.
|
|
83
|
+
3. Implement `probe()` using ToolSearch or file-based check. Write status to STATE.md.
|
|
84
|
+
4. For **canvas**: expose `read()` and `write()` surfaces via the corresponding agent.
|
|
85
|
+
5. For **component-generator**: implement `generate()` and `adopt()` in `agents/design-component-generator.md` as a new `<!-- impl: <tool> -->` section.
|
|
86
|
+
6. Add a row to `connections/connections.md` capability matrix with `canvas` or `generator` column marked.
|
|
87
|
+
7. Append to `test-fixture/baselines/current/connection-list.txt` in sorted order.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Candidate Tools (Backlog)
|
|
92
|
+
|
|
93
|
+
| Tool | Sub-category | Priority | Notes |
|
|
94
|
+
|------|-------------|----------|-------|
|
|
95
|
+
| Subframe | canvas | high | MCP-based; production-ready components; check for `mcp__subframe*` |
|
|
96
|
+
| v0.dev | generator | high | Vercel product; generates shadcn/tailwind; check for `mcp__v0*` |
|
|
97
|
+
| Galileo AI | generator | medium | Enterprise DS generation; API key required |
|
|
98
|
+
| Builder.io Visual Copilot | canvas + generator | medium | Figma plugin + code export; check for `mcp__builder*` |
|
|
99
|
+
| Locofy | generator | low | Figma→React/Next.js; Figma plugin-based |
|
|
100
|
+
| Anima | canvas | low | Figma→React; Figma plugin-based |
|
|
101
|
+
| Plasmic | generator | medium | Headless CMS + visual builder; `mcp__plasmic*` |
|
|
102
|
+
| TeleportHQ | generator | low | Code export + collaboration |
|
|
@@ -25,6 +25,7 @@ const os = require('os');
|
|
|
25
25
|
const CWD = process.cwd();
|
|
26
26
|
const TELEMETRY_PATH = path.join(CWD, '.design', 'telemetry', 'costs.jsonl');
|
|
27
27
|
const METRICS_PATH = path.join(CWD, '.design', 'agent-metrics.json');
|
|
28
|
+
const PHASE_TOTALS_PATH = path.join(CWD, '.design', 'telemetry', 'phase-totals.json');
|
|
28
29
|
const AGENTS_DIR = path.join(CWD, 'agents');
|
|
29
30
|
|
|
30
31
|
// ---- frontmatter reader (no YAML dep) ----
|
|
@@ -124,6 +125,18 @@ function writeAtomic(filePath, content) {
|
|
|
124
125
|
fs.renameSync(tmp, filePath);
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
// ---- phase totals aggregator (WR-02: avoids full JSONL replay in budget enforcer) ----
|
|
129
|
+
function aggregateByPhase(rows) {
|
|
130
|
+
const byPhase = {};
|
|
131
|
+
for (const r of rows) {
|
|
132
|
+
const phase = r.phase || 'unknown';
|
|
133
|
+
byPhase[phase] = (byPhase[phase] || 0) + Number(r.est_cost_usd || 0);
|
|
134
|
+
}
|
|
135
|
+
// Round to 6dp to match per-agent precision
|
|
136
|
+
for (const k of Object.keys(byPhase)) byPhase[k] = Number(byPhase[k].toFixed(6));
|
|
137
|
+
return byPhase;
|
|
138
|
+
}
|
|
139
|
+
|
|
127
140
|
// ---- main ----
|
|
128
141
|
function main() {
|
|
129
142
|
const rows = readTelemetryRows();
|
|
@@ -133,6 +146,13 @@ function main() {
|
|
|
133
146
|
agents,
|
|
134
147
|
};
|
|
135
148
|
writeAtomic(METRICS_PATH, JSON.stringify(payload, null, 2) + '\n');
|
|
149
|
+
// Write lightweight phase-totals.json so budget-enforcer can read phase spend
|
|
150
|
+
// in O(1) without replaying the full JSONL on every agent spawn (WR-02).
|
|
151
|
+
const phaseTotals = {
|
|
152
|
+
generated_at: new Date().toISOString(),
|
|
153
|
+
totals: aggregateByPhase(rows),
|
|
154
|
+
};
|
|
155
|
+
writeAtomic(PHASE_TOTALS_PATH, JSON.stringify(phaseTotals, null, 2) + '\n');
|
|
136
156
|
}
|
|
137
157
|
|
|
138
158
|
try {
|
package/scripts/build-intel.cjs
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
|
-
const {
|
|
20
|
+
const { spawnSync } = require('child_process');
|
|
21
21
|
|
|
22
22
|
const ROOT = process.cwd();
|
|
23
23
|
const INTEL_DIR = path.join(ROOT, '.design', 'intel');
|
|
@@ -46,15 +46,23 @@ function writeSlice(name, data) {
|
|
|
46
46
|
|
|
47
47
|
function gitHash(filePath) {
|
|
48
48
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const r = spawnSync('git', ['log', '-1', '--format=%h', '--', filePath], {
|
|
50
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
51
|
+
encoding: 'utf8',
|
|
52
|
+
timeout: 5000,
|
|
53
|
+
});
|
|
54
|
+
return r.stdout.trim() || 'untracked';
|
|
51
55
|
} catch { return 'untracked'; }
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
function headHash() {
|
|
55
59
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
const r = spawnSync('git', ['rev-parse', '--short', 'HEAD'], {
|
|
61
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
62
|
+
encoding: 'utf8',
|
|
63
|
+
timeout: 5000,
|
|
64
|
+
});
|
|
65
|
+
return r.stdout.trim() || 'unknown';
|
|
58
66
|
} catch { return 'unknown'; }
|
|
59
67
|
}
|
|
60
68
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Shared prompt-injection patterns — single source of truth for both
|
|
3
|
+
// hooks/gdd-read-injection-scanner.js (runtime hook) and
|
|
4
|
+
// scripts/run-injection-scanner-ci.cjs (CI scanner).
|
|
5
|
+
// Add new patterns here; both consumers pick them up automatically.
|
|
6
|
+
|
|
7
|
+
const INJECTION_PATTERNS = [
|
|
8
|
+
{ name: 'ignore previous', re: /ignore\s+(all\s+)?(previous|prior|above)\s+instructions?/i },
|
|
9
|
+
{ name: 'disregard previous', re: /disregard\s+(all\s+)?(previous|prior|above)\s+instructions?/i },
|
|
10
|
+
{ name: 'you are now a different', re: /you\s+are\s+now\s+a\s+different/i },
|
|
11
|
+
{ name: 'system: you are', re: /system\s*:\s*you\s+are/i },
|
|
12
|
+
{ name: 'role tag injection', re: /<\s*\/?\s*(system|assistant|human)\s*>/i },
|
|
13
|
+
{ name: '[INST] fragment', re: /\[INST\]/i },
|
|
14
|
+
{ name: '### instruction fragment',re: /###\s*instruction/i },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
module.exports = { INJECTION_PATTERNS };
|
|
@@ -13,16 +13,7 @@ const path = require('path');
|
|
|
13
13
|
|
|
14
14
|
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
const INJECTION_PATTERNS = [
|
|
18
|
-
{ name: 'ignore previous', re: /ignore\s+(all\s+)?(previous|prior|above)\s+instructions?/i },
|
|
19
|
-
{ name: 'disregard previous', re: /disregard\s+(all\s+)?(previous|prior|above)\s+instructions?/i },
|
|
20
|
-
{ name: 'you are now a different', re: /you\s+are\s+now\s+a\s+different/i },
|
|
21
|
-
{ name: 'system: you are', re: /system\s*:\s*you\s+are/i },
|
|
22
|
-
{ name: 'role tag injection', re: /<\s*\/?\s*(system|assistant|human)\s*>/i },
|
|
23
|
-
{ name: '[INST] fragment', re: /\[INST\]/i },
|
|
24
|
-
{ name: '### instruction fragment', re: /###\s*instruction/i },
|
|
25
|
-
];
|
|
16
|
+
const { INJECTION_PATTERNS } = require('./injection-patterns.cjs');
|
|
26
17
|
|
|
27
18
|
function walkMd(dir, out) {
|
|
28
19
|
if (!fs.existsSync(dir)) return;
|
|
@@ -35,7 +35,11 @@ fi
|
|
|
35
35
|
|
|
36
36
|
# Count actual fixture files (should be 4 frozen feeds + 1 README; we only
|
|
37
37
|
# care that at least one XML/JSON fixture is present).
|
|
38
|
-
|
|
38
|
+
# Use null-delimited find to handle filenames with spaces/newlines (WR-05).
|
|
39
|
+
FIXTURE_COUNT=0
|
|
40
|
+
while IFS= read -r -d '' _f; do
|
|
41
|
+
FIXTURE_COUNT=$((FIXTURE_COUNT + 1))
|
|
42
|
+
done < <(find "$FIXTURE_DIR" -maxdepth 1 -type f \( -name '*.atom' -o -name '*.rss' -o -name '*.json' \) -print0)
|
|
39
43
|
if [ "$FIXTURE_COUNT" -lt 1 ]; then
|
|
40
44
|
echo "FAIL: $FIXTURE_DIR contains no feed fixtures (.atom/.rss/.json)." >&2
|
|
41
45
|
exit 1
|
|
@@ -35,6 +35,8 @@ Flags can be combined: `--refresh --prompt` is valid (re-fetch, then enrich). `-
|
|
|
35
35
|
- Print: `No cache. Network may be unreachable or the hook has not run yet. Try /gdd:check-update --refresh.`
|
|
36
36
|
- Exit.
|
|
37
37
|
|
|
38
|
+
<!-- markdownlint-disable MD025 -->
|
|
39
|
+
|
|
38
40
|
4. **Dismiss path** (if `--dismiss` in flags):
|
|
39
41
|
Compute new config contents and write atomically. The python heredoc receives CONFIG_PATH and LATEST_TAG via the ENVIRONMENT (env-prefix form — `KEY=VALUE python3 <<PY`), NOT via trailing argv. Passing `python3 -c '...' KEY=VALUE` makes Python treat the assignments as `sys.argv`, which the old draft did incorrectly; env-prefix form is the portable fix.
|
|
40
42
|
|
package/skills/explore/SKILL.md
CHANGED
|
@@ -31,7 +31,59 @@ Empty → refero: not_configured
|
|
|
31
31
|
Non-empty → refero: available
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
**C — 21st.dev probe:**
|
|
35
|
+
```
|
|
36
|
+
ToolSearch({ query: "mcp__21st", max_results: 5 })
|
|
37
|
+
Empty → 21st-dev: not_configured
|
|
38
|
+
Non-empty → 21st-dev: available
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**D — Magic Patterns probe:**
|
|
42
|
+
```
|
|
43
|
+
ToolSearch({ query: "mcp__magic_patterns", max_results: 5 })
|
|
44
|
+
Empty → magic-patterns: not_configured
|
|
45
|
+
Non-empty → magic-patterns: available
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**E — paper.design probe:**
|
|
49
|
+
```
|
|
50
|
+
ToolSearch({ query: "mcp__paper", max_results: 5 })
|
|
51
|
+
Empty → paper-design: not_configured
|
|
52
|
+
Non-empty → call mcp__paper-design__get_selection; success → available; error → unavailable
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**F — pencil.dev probe (file-based):**
|
|
56
|
+
```bash
|
|
57
|
+
find . -name "*.pen" -not -path "*/node_modules/*" 2>/dev/null | head -1
|
|
58
|
+
Empty → pencil-dev: not_configured
|
|
59
|
+
Found → pencil-dev: available
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Write all results to STATE.md `<connections>`.
|
|
63
|
+
|
|
64
|
+
## Step 1.5 — 21st.dev Prior-Art Check (when 21st-dev: available)
|
|
65
|
+
|
|
66
|
+
If `21st-dev: not_configured` in STATE.md: skip this step entirely.
|
|
67
|
+
|
|
68
|
+
When the explore stage identifies any greenfield component in scope (component name from BRIEF.md or user request that does not yet have an implementation file):
|
|
69
|
+
|
|
70
|
+
1. `21st_magic_component_search(component_name, limit: 3)`
|
|
71
|
+
2. Evaluate top result:
|
|
72
|
+
- **fit ≥ 80%**: add `<prior-art>` block to DESIGN.md:
|
|
73
|
+
```xml
|
|
74
|
+
<prior-art source="21st.dev" component="<name>" fit="<score>%" id="<component_id>">
|
|
75
|
+
Recommendation: adopt — do not build custom. Confirm with design-executor.
|
|
76
|
+
</prior-art>
|
|
77
|
+
```
|
|
78
|
+
- **fit < 80%**: note top candidate in DESIGN.md as a reference, proceed with custom build:
|
|
79
|
+
```xml
|
|
80
|
+
<prior-art source="21st.dev" component="<name>" fit="<score>%" id="<component_id>">
|
|
81
|
+
Low fit — noted for reference. Building custom component.
|
|
82
|
+
</prior-art>
|
|
83
|
+
```
|
|
84
|
+
3. If `svgl_get_brand_logo` is available and explore scope includes brand logo assets: call `svgl_get_brand_logo(brand_name)` for each required brand asset; add SVG results to `.design/assets/` and note in DESIGN.md.
|
|
85
|
+
|
|
86
|
+
If no greenfield components in scope: skip this step.
|
|
35
87
|
|
|
36
88
|
## Step 2 — Inventory scan (unless `--skip-scan`)
|
|
37
89
|
|