sdtk-design-kit 0.1.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.
- package/README.md +123 -0
- package/bin/sdtk-design.js +14 -0
- package/package.json +43 -0
- package/src/commands/brief.js +198 -0
- package/src/commands/handoff.js +173 -0
- package/src/commands/help.js +67 -0
- package/src/commands/init.js +166 -0
- package/src/commands/review.js +176 -0
- package/src/commands/screens.js +208 -0
- package/src/commands/start.js +121 -0
- package/src/commands/status.js +131 -0
- package/src/commands/system.js +189 -0
- package/src/commands/wireframe.js +245 -0
- package/src/index.js +88 -0
- package/src/lib/args.js +47 -0
- package/src/lib/design-paths.js +72 -0
- package/src/lib/errors.js +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# SDTK-DESIGN Kit
|
|
2
|
+
|
|
3
|
+
`sdtk-design-kit` is the standalone SDTK-DESIGN Foundation Beta package.
|
|
4
|
+
|
|
5
|
+
SDTK-DESIGN is a local-first MVP design planner and reviewer for solo founders. It turns a rough MVP idea into reviewable design artifacts and a deterministic handoff for SDTK-CODE.
|
|
6
|
+
|
|
7
|
+
It is not a Figma clone, Lovable clone, v0 clone, full app builder, or production code generator.
|
|
8
|
+
|
|
9
|
+
## Beginner Flow
|
|
10
|
+
|
|
11
|
+
Use this five-command flow for a clean project:
|
|
12
|
+
|
|
13
|
+
```powershell
|
|
14
|
+
sdtk-design init
|
|
15
|
+
sdtk-design start --idea "I want to build a lightweight CRM for solo consultants to track leads, follow-ups, notes, and simple revenue pipeline without using a complex enterprise CRM."
|
|
16
|
+
sdtk-design review --artifact docs/design/wireframes/LANDING.md
|
|
17
|
+
sdtk-design handoff
|
|
18
|
+
sdtk-design status
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
What each command does:
|
|
22
|
+
|
|
23
|
+
- `init`: creates the local design workspace.
|
|
24
|
+
- `start`: creates the design brief, screen map, required wireframes, and design system.
|
|
25
|
+
- `review`: reviews a local markdown design artifact.
|
|
26
|
+
- `handoff`: converts the generated design package into SDTK-CODE handoff guidance.
|
|
27
|
+
- `status`: reports complete artifacts, missing artifacts, and the next recommended command.
|
|
28
|
+
|
|
29
|
+
## Available Commands
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
sdtk-design --help
|
|
33
|
+
sdtk-design --version
|
|
34
|
+
sdtk-design init [--project-path <path>] [--force] [--no-state]
|
|
35
|
+
sdtk-design start --idea "<idea>" [--project-path <path>] [--force]
|
|
36
|
+
sdtk-design brief --idea "<idea>" [--project-path <path>] [--force]
|
|
37
|
+
sdtk-design screens [--project-path <path>] [--force]
|
|
38
|
+
sdtk-design wireframe --screen landing [--project-path <path>] [--force]
|
|
39
|
+
sdtk-design wireframe --screen all [--project-path <path>] [--force]
|
|
40
|
+
sdtk-design system [--project-path <path>] [--force]
|
|
41
|
+
sdtk-design review --artifact docs/design/wireframes/LANDING.md [--project-path <path>] [--force]
|
|
42
|
+
sdtk-design handoff [--project-path <path>] [--force]
|
|
43
|
+
sdtk-design status [--project-path <path>]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Generated Artifacts
|
|
47
|
+
|
|
48
|
+
Human-facing output is written under `docs/design/`:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
docs/design/
|
|
52
|
+
README.md
|
|
53
|
+
DESIGN_BRIEF.md
|
|
54
|
+
SCREEN_MAP.md
|
|
55
|
+
DESIGN_SYSTEM.md
|
|
56
|
+
DESIGN_HANDOFF.md
|
|
57
|
+
wireframes/
|
|
58
|
+
LANDING.md
|
|
59
|
+
ONBOARDING.md
|
|
60
|
+
DASHBOARD.md
|
|
61
|
+
reviews/
|
|
62
|
+
DESIGN_REVIEW_YYYYMMDD.md
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Internal state may live under `.sdtk/design/`. SDTK-DESIGN must not create or mutate `.sdtk/atlas`.
|
|
66
|
+
|
|
67
|
+
## Command Details
|
|
68
|
+
|
|
69
|
+
### `init`
|
|
70
|
+
|
|
71
|
+
Creates `docs/design/`, `docs/design/wireframes/`, `docs/design/reviews/`, `docs/design/README.md`, and `.sdtk/design/manifest.json`.
|
|
72
|
+
|
|
73
|
+
Existing managed init files are skipped by default. Use `--force` only when you explicitly want to refresh managed init files. Use `--no-state` to skip `.sdtk/design`.
|
|
74
|
+
|
|
75
|
+
### `start`
|
|
76
|
+
|
|
77
|
+
Runs:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
brief -> screens -> wireframe --screen all -> system
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This is the beginner facade for the core design package. It does not run review or handoff. Existing managed core outputs are not overwritten unless `--force` is explicit.
|
|
84
|
+
|
|
85
|
+
### `review`
|
|
86
|
+
|
|
87
|
+
Reviews a local markdown artifact, for example:
|
|
88
|
+
|
|
89
|
+
```powershell
|
|
90
|
+
sdtk-design review --artifact docs/design/wireframes/LANDING.md
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The review report is written to `docs/design/reviews/DESIGN_REVIEW_YYYYMMDD.md`.
|
|
94
|
+
|
|
95
|
+
Current review support is local markdown artifact review only. No URL, browser, screenshot, vision, or DOM review is implemented in Foundation Beta.
|
|
96
|
+
|
|
97
|
+
### `handoff`
|
|
98
|
+
|
|
99
|
+
Reads the generated brief, screen map, required wireframes, and design system, then writes `docs/design/DESIGN_HANDOFF.md`.
|
|
100
|
+
|
|
101
|
+
The handoff is planning input for SDTK-CODE. It includes screen-to-component mapping, screen-to-user-story mapping, design decisions, implementation notes, acceptance criteria, and a readiness verdict. It does not generate production app code.
|
|
102
|
+
|
|
103
|
+
### `status`
|
|
104
|
+
|
|
105
|
+
Read-only command. It reports complete artifacts, missing artifacts, and the next recommended command.
|
|
106
|
+
|
|
107
|
+
## Non-Goals And Deferred Features
|
|
108
|
+
|
|
109
|
+
Foundation Beta does not provide:
|
|
110
|
+
|
|
111
|
+
- Figma, Lovable, v0, or full app-builder replacement behavior.
|
|
112
|
+
- Production app code generation.
|
|
113
|
+
- URL, browser, screenshot, vision, or DOM review.
|
|
114
|
+
- Network calls by default.
|
|
115
|
+
- Pro entitlement gates.
|
|
116
|
+
- `.sdtk/atlas` creation or mutation.
|
|
117
|
+
- SDTK-WIKI output mutation.
|
|
118
|
+
- Landing-site updates.
|
|
119
|
+
- npm publish or maintainer packaging checks without separate maintainer approval.
|
|
120
|
+
|
|
121
|
+
## SDTK-CODE Handoff
|
|
122
|
+
|
|
123
|
+
After `sdtk-design handoff`, pass `docs/design/DESIGN_HANDOFF.md` to SDTK-CODE as implementation planning input. SDTK-CODE should still plan, implement, and verify code changes separately.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { run } = require("../src/index");
|
|
6
|
+
|
|
7
|
+
run(process.argv.slice(2))
|
|
8
|
+
.then((exitCode) => {
|
|
9
|
+
process.exitCode = Number.isInteger(exitCode) ? exitCode : 0;
|
|
10
|
+
})
|
|
11
|
+
.catch((error) => {
|
|
12
|
+
console.error(`sdtk-design: ${error.message}`);
|
|
13
|
+
process.exitCode = typeof error.exitCode === "number" ? error.exitCode : 4;
|
|
14
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sdtk-design-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local-first MVP design planner and reviewer for SDTK workspaces.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"sdtk-design": "bin/sdtk-design.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "src/index.js",
|
|
9
|
+
"type": "commonjs",
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"src/",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "powershell -ExecutionPolicy Bypass -Command \"$ErrorActionPreference = 'Stop'; Set-Location '..\\..\\..\\..'; python -m pytest tests/test_sdtk_design_cli.py -q\"",
|
|
17
|
+
"pack:smoke": "npm pack --dry-run"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18.13.0"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"sdtk-design",
|
|
24
|
+
"design",
|
|
25
|
+
"mvp",
|
|
26
|
+
"wireframe",
|
|
27
|
+
"cli",
|
|
28
|
+
"toolkit"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/codexsdtk/sdtk-toolkit.git",
|
|
34
|
+
"directory": "products/sdtk-design/distribution/sdtk-design-kit"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/codexsdtk/sdtk-toolkit/tree/main/products/sdtk-design/distribution/sdtk-design-kit",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/codexsdtk/sdtk-toolkit/issues"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { parseFlags } = require("../lib/args");
|
|
6
|
+
const { describeDesignPaths, resolveProjectPath } = require("../lib/design-paths");
|
|
7
|
+
const { ValidationError } = require("../lib/errors");
|
|
8
|
+
const { runDesignInit } = require("./init");
|
|
9
|
+
|
|
10
|
+
const BRIEF_FLAG_DEFS = {
|
|
11
|
+
help: { type: "boolean" },
|
|
12
|
+
idea: { type: "string" },
|
|
13
|
+
"project-path": { type: "string" },
|
|
14
|
+
force: { type: "boolean" },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function cmdBriefHelp() {
|
|
18
|
+
console.log(`SDTK-DESIGN Brief
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
sdtk-design brief --idea "<rough MVP idea>" [--project-path <path>] [--force]
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
sdtk-design brief --idea "I want to build a lightweight CRM for solo consultants."
|
|
25
|
+
|
|
26
|
+
Creates:
|
|
27
|
+
docs/design/DESIGN_BRIEF.md
|
|
28
|
+
|
|
29
|
+
Safety:
|
|
30
|
+
Local files only.
|
|
31
|
+
Existing DESIGN_BRIEF.md is not overwritten unless --force is explicit.
|
|
32
|
+
No .sdtk/atlas creation or mutation.
|
|
33
|
+
No SDTK-WIKI output mutation.
|
|
34
|
+
No network call, Pro entitlement, or production app code generation.`);
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function normalizeIdea(idea) {
|
|
39
|
+
return String(idea || "").replace(/\s+/g, " ").trim();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function extractFirstMatch(text, pattern) {
|
|
43
|
+
const match = text.match(pattern);
|
|
44
|
+
return match ? match[1].trim().replace(/[.]+$/, "") : "";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function sentenceCase(value) {
|
|
48
|
+
const clean = normalizeIdea(value);
|
|
49
|
+
if (!clean) return clean;
|
|
50
|
+
return clean.charAt(0).toUpperCase() + clean.slice(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function inferBriefFields(idea) {
|
|
54
|
+
const lowerIdea = idea.toLowerCase();
|
|
55
|
+
const targetUser = extractFirstMatch(idea, /\bfor\s+(.+?)\s+to\s+/i) || "solo founders validating a focused MVP";
|
|
56
|
+
const outcome = extractFirstMatch(idea, /\bto\s+(.+?)(?:\s+without\b|$)/i) || "complete the primary MVP workflow with less friction";
|
|
57
|
+
const constraint = extractFirstMatch(idea, /\bwithout\s+(.+?)$/i);
|
|
58
|
+
const isCrm = lowerIdea.includes("crm") || lowerIdea.includes("lead") || lowerIdea.includes("pipeline");
|
|
59
|
+
|
|
60
|
+
const productType = isCrm ? "lightweight CRM" : "focused MVP workspace";
|
|
61
|
+
const primaryCta = isCrm ? "Add first lead" : "Start first workflow";
|
|
62
|
+
const successMetric = isCrm
|
|
63
|
+
? "A solo consultant can add a lead, schedule a follow-up, record a note, and see the simple pipeline status in under 5 minutes."
|
|
64
|
+
: "A first-time user can complete the primary workflow and understand the next action in under 5 minutes.";
|
|
65
|
+
|
|
66
|
+
const painPoint = constraint
|
|
67
|
+
? `${sentenceCase(targetUser)} need to ${outcome}, but ${constraint} creates too much friction for the first version.`
|
|
68
|
+
: `${sentenceCase(targetUser)} need to ${outcome}, but the current alternative is too slow, scattered, or hard to adopt for an MVP.`;
|
|
69
|
+
|
|
70
|
+
const nonGoals = isCrm
|
|
71
|
+
? [
|
|
72
|
+
"Enterprise CRM automation, complex custom fields, territory management, and multi-team permissions.",
|
|
73
|
+
"Heavy analytics, forecasting, billing, marketing automation, or third-party CRM synchronization.",
|
|
74
|
+
"A production app implementation or database schema generated by SDTK-DESIGN.",
|
|
75
|
+
]
|
|
76
|
+
: [
|
|
77
|
+
"Enterprise workflow automation, broad admin settings, and deep customization.",
|
|
78
|
+
"Advanced analytics, billing, integrations, or multi-role governance beyond the MVP path.",
|
|
79
|
+
"A production app implementation or database schema generated by SDTK-DESIGN.",
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
targetUser,
|
|
84
|
+
outcome,
|
|
85
|
+
productType,
|
|
86
|
+
primaryCta,
|
|
87
|
+
painPoint,
|
|
88
|
+
successMetric,
|
|
89
|
+
nonGoals,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function designBriefContent(idea) {
|
|
94
|
+
const fields = inferBriefFields(idea);
|
|
95
|
+
return [
|
|
96
|
+
"# Design Brief",
|
|
97
|
+
"",
|
|
98
|
+
"## Source Idea",
|
|
99
|
+
"",
|
|
100
|
+
idea,
|
|
101
|
+
"",
|
|
102
|
+
"## Target User",
|
|
103
|
+
"",
|
|
104
|
+
`- ${sentenceCase(fields.targetUser)}.`,
|
|
105
|
+
"",
|
|
106
|
+
"## Problem / Pain Point",
|
|
107
|
+
"",
|
|
108
|
+
`- ${fields.painPoint}`,
|
|
109
|
+
"",
|
|
110
|
+
"## MVP Promise",
|
|
111
|
+
"",
|
|
112
|
+
`- A ${fields.productType} that helps ${fields.targetUser} ${fields.outcome} without the weight of a complex tool.`,
|
|
113
|
+
"",
|
|
114
|
+
"## Primary CTA",
|
|
115
|
+
"",
|
|
116
|
+
`- ${fields.primaryCta}`,
|
|
117
|
+
"",
|
|
118
|
+
"## Non-Goals",
|
|
119
|
+
"",
|
|
120
|
+
...fields.nonGoals.map((item) => `- ${item}`),
|
|
121
|
+
"",
|
|
122
|
+
"## Success Metric",
|
|
123
|
+
"",
|
|
124
|
+
`- ${fields.successMetric}`,
|
|
125
|
+
"",
|
|
126
|
+
"## Assumptions",
|
|
127
|
+
"",
|
|
128
|
+
"- The first release is for one primary user role and one primary workflow.",
|
|
129
|
+
"- The MVP should favor fast capture, clear next action, and readable status over deep configuration.",
|
|
130
|
+
"- Human-facing design artifacts stay under `docs/design`; internal state may stay under `.sdtk/design`.",
|
|
131
|
+
"",
|
|
132
|
+
"## Open Questions",
|
|
133
|
+
"",
|
|
134
|
+
"- What is the single highest-value action the user must complete on day one?",
|
|
135
|
+
"- Which information is required versus optional during first-use setup?",
|
|
136
|
+
"- What empty state copy should guide a user before any records exist?",
|
|
137
|
+
"- Which manual workarounds are acceptable for the Foundation Beta MVP?",
|
|
138
|
+
"",
|
|
139
|
+
"## Next Design Steps",
|
|
140
|
+
"",
|
|
141
|
+
"- Run `sdtk-design screens` to create the screen map.",
|
|
142
|
+
"- Run `sdtk-design wireframe --screen landing` after the screen map exists.",
|
|
143
|
+
"",
|
|
144
|
+
].join("\n");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function runDesignBrief({ idea, projectPath, force = false }) {
|
|
148
|
+
const normalizedIdea = normalizeIdea(idea);
|
|
149
|
+
if (!normalizedIdea) {
|
|
150
|
+
throw new ValidationError('Missing required --idea "<rough MVP idea>". No project files were changed.');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const resolvedProjectPath = resolveProjectPath(projectPath || process.cwd());
|
|
154
|
+
if (!fs.existsSync(resolvedProjectPath) || !fs.statSync(resolvedProjectPath).isDirectory()) {
|
|
155
|
+
throw new ValidationError(`--project-path is not a valid directory: ${resolvedProjectPath}. No project files were changed.`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const paths = describeDesignPaths(resolvedProjectPath);
|
|
159
|
+
if (fs.existsSync(paths.designBriefPath) && !force) {
|
|
160
|
+
throw new ValidationError("docs/design/DESIGN_BRIEF.md already exists. Re-run with --force to replace this managed brief.");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
runDesignInit({ projectPath: resolvedProjectPath, force: false, state: true });
|
|
164
|
+
fs.mkdirSync(path.dirname(paths.designBriefPath), { recursive: true });
|
|
165
|
+
fs.writeFileSync(paths.designBriefPath, designBriefContent(normalizedIdea), "utf-8");
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
projectPath: resolvedProjectPath,
|
|
169
|
+
briefPath: paths.designBriefPath,
|
|
170
|
+
relativeBriefPath: "docs/design/DESIGN_BRIEF.md",
|
|
171
|
+
forced: Boolean(force),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function cmdBrief(args) {
|
|
176
|
+
const { flags } = parseFlags(args || [], BRIEF_FLAG_DEFS);
|
|
177
|
+
if (flags.help) return cmdBriefHelp();
|
|
178
|
+
|
|
179
|
+
const result = runDesignBrief({
|
|
180
|
+
idea: flags.idea,
|
|
181
|
+
projectPath: flags["project-path"],
|
|
182
|
+
force: Boolean(flags.force),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
console.log(`[design] Wrote ${result.relativeBriefPath}: ${result.projectPath}`);
|
|
186
|
+
console.log(`[design] Overwrite: ${result.forced ? "enabled by --force" : "not needed"}`);
|
|
187
|
+
console.log("[design] No .sdtk/atlas, SDTK-WIKI output, source files, network, or app code was modified.");
|
|
188
|
+
console.log("[design] Next: sdtk-design screens");
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = {
|
|
193
|
+
cmdBrief,
|
|
194
|
+
cmdBriefHelp,
|
|
195
|
+
designBriefContent,
|
|
196
|
+
inferBriefFields,
|
|
197
|
+
runDesignBrief,
|
|
198
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { parseFlags } = require("../lib/args");
|
|
6
|
+
const { describeDesignPaths, resolveProjectPath } = require("../lib/design-paths");
|
|
7
|
+
const { ValidationError } = require("../lib/errors");
|
|
8
|
+
|
|
9
|
+
const HANDOFF_FLAG_DEFS = {
|
|
10
|
+
help: { type: "boolean" },
|
|
11
|
+
"project-path": { type: "string" },
|
|
12
|
+
force: { type: "boolean" },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const REQUIRED_WIREFRAMES = ["LANDING.md", "ONBOARDING.md", "DASHBOARD.md"];
|
|
16
|
+
|
|
17
|
+
function cmdHandoffHelp() {
|
|
18
|
+
console.log(`SDTK-DESIGN Handoff
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
sdtk-design handoff [--project-path <path>] [--force]
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
sdtk-design handoff
|
|
25
|
+
|
|
26
|
+
Reads:
|
|
27
|
+
docs/design/DESIGN_BRIEF.md
|
|
28
|
+
docs/design/SCREEN_MAP.md
|
|
29
|
+
docs/design/wireframes/LANDING.md
|
|
30
|
+
docs/design/wireframes/ONBOARDING.md
|
|
31
|
+
docs/design/wireframes/DASHBOARD.md
|
|
32
|
+
docs/design/DESIGN_SYSTEM.md
|
|
33
|
+
|
|
34
|
+
Creates:
|
|
35
|
+
docs/design/DESIGN_HANDOFF.md
|
|
36
|
+
|
|
37
|
+
Safety:
|
|
38
|
+
Local files only.
|
|
39
|
+
Existing DESIGN_HANDOFF.md is not overwritten unless --force is explicit.
|
|
40
|
+
No .sdtk/atlas creation or mutation.
|
|
41
|
+
No SDTK-WIKI output mutation.
|
|
42
|
+
No network call, Pro entitlement, or production app code generation.`);
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function requiredArtifacts(paths) {
|
|
47
|
+
return [
|
|
48
|
+
{ label: "Design brief", relativePath: "docs/design/DESIGN_BRIEF.md", filePath: paths.designBriefPath },
|
|
49
|
+
{ label: "Screen map", relativePath: "docs/design/SCREEN_MAP.md", filePath: paths.screenMapPath },
|
|
50
|
+
{ label: "Design system", relativePath: "docs/design/DESIGN_SYSTEM.md", filePath: paths.designSystemPath },
|
|
51
|
+
...REQUIRED_WIREFRAMES.map((fileName) => ({
|
|
52
|
+
label: `${fileName.replace(".md", "")} wireframe`,
|
|
53
|
+
relativePath: `docs/design/wireframes/${fileName}`,
|
|
54
|
+
filePath: path.join(paths.wireframesPath, fileName),
|
|
55
|
+
})),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function handoffContent() {
|
|
60
|
+
return [
|
|
61
|
+
"# Design Handoff",
|
|
62
|
+
"",
|
|
63
|
+
"## Readiness Verdict",
|
|
64
|
+
"",
|
|
65
|
+
"- Verdict: READY_FOR_SDTK_CODE",
|
|
66
|
+
"- Rationale: Required Phase A design artifacts exist and provide enough screen, component, state, and design-system context for implementation planning.",
|
|
67
|
+
"",
|
|
68
|
+
"## Source Artifacts",
|
|
69
|
+
"",
|
|
70
|
+
"- `docs/design/DESIGN_BRIEF.md`",
|
|
71
|
+
"- `docs/design/SCREEN_MAP.md`",
|
|
72
|
+
"- `docs/design/wireframes/LANDING.md`",
|
|
73
|
+
"- `docs/design/wireframes/ONBOARDING.md`",
|
|
74
|
+
"- `docs/design/wireframes/DASHBOARD.md`",
|
|
75
|
+
"- `docs/design/DESIGN_SYSTEM.md`",
|
|
76
|
+
"",
|
|
77
|
+
"## Screen-To-Component Mapping",
|
|
78
|
+
"",
|
|
79
|
+
"| Screen | Design artifact | Component direction |",
|
|
80
|
+
"|---|---|---|",
|
|
81
|
+
"| Landing | `docs/design/wireframes/LANDING.md` | Header, hero copy, primary CTA, workflow preview, benefit bullets |",
|
|
82
|
+
"| Onboarding | `docs/design/wireframes/ONBOARDING.md` | Progress indicator, setup form, segmented sample-data control, inline validation, continue CTA |",
|
|
83
|
+
"| Dashboard | `docs/design/wireframes/DASHBOARD.md` | Summary counters, lead list, status pill, quick-add action, empty-state panel, recoverable error alert |",
|
|
84
|
+
"",
|
|
85
|
+
"## Screen-To-User-Story Mapping",
|
|
86
|
+
"",
|
|
87
|
+
"| Screen | User story | Acceptance signal |",
|
|
88
|
+
"|---|---|---|",
|
|
89
|
+
"| Landing | As a solo consultant, I want to understand the lightweight CRM promise so I can decide whether to start. | Primary CTA is visible and routes to onboarding. |",
|
|
90
|
+
"| Onboarding | As a new user, I want a short setup path so I can create my first lead without enterprise configuration. | Required fields are clear, validation is inline, and entered values are preserved on error. |",
|
|
91
|
+
"| Dashboard | As a solo consultant, I want to see active leads and follow-ups so I can choose my next action. | Leads, next actions, notes, and simple pipeline status are scannable with empty and error states. |",
|
|
92
|
+
"",
|
|
93
|
+
"## Design Decisions",
|
|
94
|
+
"",
|
|
95
|
+
"- Keep the MVP to three core screens: Landing, Onboarding, and Dashboard.",
|
|
96
|
+
"- Optimize for repeated action and scan speed over decorative presentation.",
|
|
97
|
+
"- Use a restrained operational design system with stable controls, clear form states, and accessible status language.",
|
|
98
|
+
"- Preserve `docs/design` as the human-facing design output boundary.",
|
|
99
|
+
"",
|
|
100
|
+
"## Implementation Notes For SDTK-CODE",
|
|
101
|
+
"",
|
|
102
|
+
"- Treat the markdown artifacts as planning input, not generated production code.",
|
|
103
|
+
"- Implement screens in this order: Landing, Onboarding, Dashboard.",
|
|
104
|
+
"- Keep user data capture minimal until the first useful workflow is complete.",
|
|
105
|
+
"- Preserve empty, success, and error states from the screen map and wireframes.",
|
|
106
|
+
"- Apply typography, color, spacing, button, card, form, tone, and accessibility rules from `DESIGN_SYSTEM.md`.",
|
|
107
|
+
"",
|
|
108
|
+
"## Acceptance Criteria",
|
|
109
|
+
"",
|
|
110
|
+
"- Landing renders the product promise, workflow preview, and a single dominant primary CTA.",
|
|
111
|
+
"- Onboarding captures only required setup data and keeps validation inline.",
|
|
112
|
+
"- Dashboard shows active work, next action, simple pipeline status, empty state, and recoverable error state.",
|
|
113
|
+
"- Components follow the design system tokens and accessibility baseline.",
|
|
114
|
+
"- No production app code, network integration, Pro entitlement, `.sdtk/atlas`, or SDTK-WIKI mutation is implied by this handoff.",
|
|
115
|
+
"",
|
|
116
|
+
"## Non-Goals",
|
|
117
|
+
"",
|
|
118
|
+
"- Figma, Lovable, v0, or full app-builder replacement behavior.",
|
|
119
|
+
"- Enterprise CRM automation, complex analytics, billing, or multi-team administration.",
|
|
120
|
+
"- Package publish or deployment.",
|
|
121
|
+
"",
|
|
122
|
+
].join("\n");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function runDesignHandoff({ projectPath, force = false }) {
|
|
126
|
+
const resolvedProjectPath = resolveProjectPath(projectPath || process.cwd());
|
|
127
|
+
if (!fs.existsSync(resolvedProjectPath) || !fs.statSync(resolvedProjectPath).isDirectory()) {
|
|
128
|
+
throw new ValidationError(`--project-path is not a valid directory: ${resolvedProjectPath}. No project files were changed.`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const paths = describeDesignPaths(resolvedProjectPath);
|
|
132
|
+
const missing = requiredArtifacts(paths).filter((artifact) => !fs.existsSync(artifact.filePath));
|
|
133
|
+
if (missing.length > 0) {
|
|
134
|
+
const missingList = missing.map((artifact) => artifact.relativePath).join(", ");
|
|
135
|
+
throw new ValidationError(`Missing required design artifacts: ${missingList}. Run the previous SDTK-DESIGN commands first. No project files were changed.`);
|
|
136
|
+
}
|
|
137
|
+
if (fs.existsSync(paths.designHandoffPath) && !force) {
|
|
138
|
+
throw new ValidationError("docs/design/DESIGN_HANDOFF.md already exists. Re-run with --force to replace this managed handoff.");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fs.mkdirSync(path.dirname(paths.designHandoffPath), { recursive: true });
|
|
142
|
+
fs.writeFileSync(paths.designHandoffPath, handoffContent(), "utf-8");
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
projectPath: resolvedProjectPath,
|
|
146
|
+
relativeDesignHandoffPath: "docs/design/DESIGN_HANDOFF.md",
|
|
147
|
+
forced: Boolean(force),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function cmdHandoff(args) {
|
|
152
|
+
const { flags } = parseFlags(args || [], HANDOFF_FLAG_DEFS);
|
|
153
|
+
if (flags.help) return cmdHandoffHelp();
|
|
154
|
+
|
|
155
|
+
const result = runDesignHandoff({
|
|
156
|
+
projectPath: flags["project-path"],
|
|
157
|
+
force: Boolean(flags.force),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
console.log(`[design] Wrote ${result.relativeDesignHandoffPath}: ${result.projectPath}`);
|
|
161
|
+
console.log(`[design] Verdict: READY_FOR_SDTK_CODE`);
|
|
162
|
+
console.log(`[design] Overwrite: ${result.forced ? "enabled by --force" : "not needed"}`);
|
|
163
|
+
console.log("[design] No .sdtk/atlas, SDTK-WIKI output, source files, network, or app code was modified.");
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
cmdHandoff,
|
|
169
|
+
cmdHandoffHelp,
|
|
170
|
+
handoffContent,
|
|
171
|
+
requiredArtifacts,
|
|
172
|
+
runDesignHandoff,
|
|
173
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
function cmdHelp() {
|
|
4
|
+
console.log(`SDTK-DESIGN Kit
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
sdtk-design --help
|
|
8
|
+
sdtk-design --version
|
|
9
|
+
sdtk-design init
|
|
10
|
+
sdtk-design start --idea "<idea>"
|
|
11
|
+
sdtk-design brief --idea "<idea>"
|
|
12
|
+
sdtk-design screens
|
|
13
|
+
sdtk-design wireframe --screen landing
|
|
14
|
+
sdtk-design system
|
|
15
|
+
sdtk-design review --artifact docs/design/wireframes/LANDING.md
|
|
16
|
+
sdtk-design handoff
|
|
17
|
+
sdtk-design status
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
sdtk-design start --idea "I want to build a lightweight CRM for solo consultants to track leads."
|
|
21
|
+
sdtk-design review --artifact docs/design/wireframes/LANDING.md
|
|
22
|
+
sdtk-design handoff
|
|
23
|
+
sdtk-design status
|
|
24
|
+
|
|
25
|
+
Foundation Beta purpose:
|
|
26
|
+
SDTK-DESIGN is a local-first MVP design planner and reviewer for solo founders.
|
|
27
|
+
It turns a rough MVP idea into reviewable design artifacts and a deterministic SDTK-CODE handoff.
|
|
28
|
+
|
|
29
|
+
Required human-facing output:
|
|
30
|
+
docs/design/DESIGN_BRIEF.md
|
|
31
|
+
docs/design/SCREEN_MAP.md
|
|
32
|
+
docs/design/DESIGN_SYSTEM.md
|
|
33
|
+
docs/design/wireframes/LANDING.md
|
|
34
|
+
docs/design/wireframes/ONBOARDING.md
|
|
35
|
+
docs/design/wireframes/DASHBOARD.md
|
|
36
|
+
docs/design/reviews/DESIGN_REVIEW_YYYYMMDD.md
|
|
37
|
+
docs/design/DESIGN_HANDOFF.md
|
|
38
|
+
|
|
39
|
+
Command status:
|
|
40
|
+
help, --version Available.
|
|
41
|
+
init Available.
|
|
42
|
+
brief Available.
|
|
43
|
+
screens Available.
|
|
44
|
+
wireframe Available.
|
|
45
|
+
system Available.
|
|
46
|
+
handoff Available.
|
|
47
|
+
review Available for local markdown artifacts.
|
|
48
|
+
start Available beginner facade.
|
|
49
|
+
status Available.
|
|
50
|
+
|
|
51
|
+
Deferred:
|
|
52
|
+
URL/browser/screenshot/vision review is not implemented in Foundation Beta.
|
|
53
|
+
Publishing checks are maintainer-controlled and are not part of normal CLI usage.
|
|
54
|
+
|
|
55
|
+
Safety boundaries:
|
|
56
|
+
No production app code generation.
|
|
57
|
+
No Figma, Lovable, v0, or full app-builder replacement claim.
|
|
58
|
+
No network call or Pro entitlement requirement by default.
|
|
59
|
+
No .sdtk/atlas creation or mutation.
|
|
60
|
+
No SDTK-WIKI output mutation.
|
|
61
|
+
No overwrite of user files unless a command explicitly supports --force and tests cover it.`);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
cmdHelp,
|
|
67
|
+
};
|