@bastani/atomic 0.5.25 → 0.5.26-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 (51) hide show
  1. package/.agents/skills/ado-commit/SKILL.md +92 -0
  2. package/.agents/skills/ado-create-pr/SKILL.md +209 -0
  3. package/.claude/settings.json +1 -0
  4. package/.mcp.json +5 -0
  5. package/.opencode/opencode.json +7 -1
  6. package/README.md +150 -116
  7. package/assets/settings.schema.json +2 -2
  8. package/dist/sdk/runtime/executor.d.ts.map +1 -1
  9. package/dist/sdk/workflows/builtin/open-claude-design/claude/index.d.ts +46 -0
  10. package/dist/sdk/workflows/builtin/open-claude-design/claude/index.d.ts.map +1 -0
  11. package/dist/sdk/workflows/builtin/open-claude-design/copilot/index.d.ts +34 -0
  12. package/dist/sdk/workflows/builtin/open-claude-design/copilot/index.d.ts.map +1 -0
  13. package/dist/sdk/workflows/builtin/open-claude-design/helpers/constants.d.ts +72 -0
  14. package/dist/sdk/workflows/builtin/open-claude-design/helpers/constants.d.ts.map +1 -0
  15. package/dist/sdk/workflows/builtin/open-claude-design/helpers/design-system.d.ts +46 -0
  16. package/dist/sdk/workflows/builtin/open-claude-design/helpers/design-system.d.ts.map +1 -0
  17. package/dist/sdk/workflows/builtin/open-claude-design/helpers/export.d.ts +32 -0
  18. package/dist/sdk/workflows/builtin/open-claude-design/helpers/export.d.ts.map +1 -0
  19. package/dist/sdk/workflows/builtin/open-claude-design/helpers/import.d.ts +33 -0
  20. package/dist/sdk/workflows/builtin/open-claude-design/helpers/import.d.ts.map +1 -0
  21. package/dist/sdk/workflows/builtin/open-claude-design/helpers/prompts.d.ts +106 -0
  22. package/dist/sdk/workflows/builtin/open-claude-design/helpers/prompts.d.ts.map +1 -0
  23. package/dist/sdk/workflows/builtin/open-claude-design/helpers/scan.d.ts +50 -0
  24. package/dist/sdk/workflows/builtin/open-claude-design/helpers/scan.d.ts.map +1 -0
  25. package/dist/sdk/workflows/builtin/open-claude-design/helpers/validation.d.ts +12 -0
  26. package/dist/sdk/workflows/builtin/open-claude-design/helpers/validation.d.ts.map +1 -0
  27. package/dist/sdk/workflows/builtin/open-claude-design/opencode/index.d.ts +36 -0
  28. package/dist/sdk/workflows/builtin/open-claude-design/opencode/index.d.ts.map +1 -0
  29. package/dist/services/config/atomic-config.d.ts +6 -0
  30. package/dist/services/config/atomic-config.d.ts.map +1 -1
  31. package/dist/services/config/scm-sync.d.ts +37 -0
  32. package/dist/services/config/scm-sync.d.ts.map +1 -0
  33. package/package.json +7 -7
  34. package/src/cli.ts +2 -2
  35. package/src/commands/cli/chat/index.ts +8 -1
  36. package/src/commands/cli/config.ts +34 -10
  37. package/src/commands/cli/init/index.ts +9 -0
  38. package/src/sdk/runtime/executor.ts +13 -0
  39. package/src/sdk/workflows/builtin/open-claude-design/claude/index.ts +499 -0
  40. package/src/sdk/workflows/builtin/open-claude-design/copilot/index.ts +507 -0
  41. package/src/sdk/workflows/builtin/open-claude-design/helpers/constants.ts +159 -0
  42. package/src/sdk/workflows/builtin/open-claude-design/helpers/design-system.ts +88 -0
  43. package/src/sdk/workflows/builtin/open-claude-design/helpers/export.ts +193 -0
  44. package/src/sdk/workflows/builtin/open-claude-design/helpers/import.ts +52 -0
  45. package/src/sdk/workflows/builtin/open-claude-design/helpers/prompts.ts +1110 -0
  46. package/src/sdk/workflows/builtin/open-claude-design/helpers/scan.ts +117 -0
  47. package/src/sdk/workflows/builtin/open-claude-design/helpers/validation.ts +38 -0
  48. package/src/sdk/workflows/builtin/open-claude-design/opencode/index.ts +570 -0
  49. package/src/services/config/atomic-config.ts +12 -0
  50. package/src/services/config/scm-sync.ts +174 -0
  51. package/src/services/config/settings.ts +19 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Design.md persistence — loading, saving, and reading design system data.
3
+ *
4
+ * The Design.md file is a structured markdown document containing design
5
+ * tokens (colors, typography, spacing, components) extracted from the
6
+ * codebase and approved by the user via HIL. It serves as the single
7
+ * source of truth for all generation and refinement stages.
8
+ */
9
+
10
+ import { readFile } from "node:fs/promises";
11
+ import path from "node:path";
12
+ import { DESIGN_SYSTEM_FILENAME, IMPECCABLE_FILENAME } from "./constants.ts";
13
+
14
+ /** Structured representation of the design system data. */
15
+ export interface DesignSystemData {
16
+ /** Raw markdown content of Design.md. */
17
+ raw: string;
18
+ /** Absolute path to the Design.md file. */
19
+ path: string;
20
+ }
21
+
22
+ /**
23
+ * Load an existing Design.md from the given path.
24
+ * Used when the user provides `--design-system=<path>`.
25
+ */
26
+ export async function loadDesignSystem(
27
+ designSystemPath: string,
28
+ ): Promise<DesignSystemData> {
29
+ const resolved = path.resolve(designSystemPath);
30
+ const raw = await readFile(resolved, "utf-8");
31
+ return { raw, path: resolved };
32
+ }
33
+
34
+ /**
35
+ * Persist the design system builder's output as Design.md in the project root.
36
+ *
37
+ * The builder stage produces a visible session where the agent constructs
38
+ * the Design.md content interactively with the user. We read the transcript
39
+ * and extract the final Design.md content that the agent wrote.
40
+ *
41
+ * For simplicity, the agent in the builder stage is instructed to write
42
+ * Design.md directly to disk. This function reads it back to populate
43
+ * the DesignSystemData for downstream stages.
44
+ */
45
+ export async function persistDesignSystem(
46
+ root: string,
47
+ ): Promise<DesignSystemData> {
48
+ const designPath = path.join(root, DESIGN_SYSTEM_FILENAME);
49
+ const raw = await readFile(designPath, "utf-8");
50
+ return { raw, path: designPath };
51
+ }
52
+
53
+ /**
54
+ * Read the existing .impeccable.md brand context file, if present.
55
+ * Returns empty string if the file does not exist.
56
+ */
57
+ export async function readImpeccableMd(root: string): Promise<string> {
58
+ try {
59
+ return await readFile(path.join(root, IMPECCABLE_FILENAME), "utf-8");
60
+ } catch {
61
+ return "";
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Derive a URL-safe slug from the user's prompt for directory naming.
67
+ */
68
+ export function slugifyPrompt(prompt: string): string {
69
+ const slug = prompt
70
+ .toLowerCase()
71
+ .replace(/[^a-z0-9\s-]/g, "")
72
+ .split(/\s+/)
73
+ .filter(Boolean)
74
+ .slice(0, 6)
75
+ .join("-")
76
+ .substring(0, 60);
77
+ return slug || "design";
78
+ }
79
+
80
+ /**
81
+ * Ensure the scratch directory exists for intermediate workflow outputs.
82
+ */
83
+ export async function ensureScratchDir(root: string): Promise<string> {
84
+ const { mkdir } = await import("node:fs/promises");
85
+ const scratchDir = path.join(root, "research", "designs", ".scratch");
86
+ await mkdir(scratchDir, { recursive: true });
87
+ return scratchDir;
88
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Export engine — handoff bundle packaging.
3
+ *
4
+ * Writes the deterministic parts of the handoff bundle (no LLM call):
5
+ * - handoff-prompt.md — ready-to-use prompt for Claude Code
6
+ * - README.md — how to use the bundle
7
+ *
8
+ * The exporter stage (LLM) handles copying design files, writing
9
+ * design-intent.md and component-specs.md since those require
10
+ * understanding the generated design content.
11
+ */
12
+
13
+ import { writeFile, mkdir, copyFile } from "node:fs/promises";
14
+ import path from "node:path";
15
+ import type { DesignSystemData } from "./design-system.ts";
16
+
17
+ export interface HandoffBundleOptions {
18
+ designSystem: DesignSystemData;
19
+ prompt: string;
20
+ outputType: string;
21
+ }
22
+
23
+ /**
24
+ * Write the deterministic handoff bundle files.
25
+ *
26
+ * The exporter stage is responsible for:
27
+ * - Copying design files (index.html, styles.css, script.js) to design/
28
+ * - Writing design-intent.md from transcript analysis
29
+ * - Writing component-specs.md from design analysis
30
+ *
31
+ * This function writes the remaining deterministic files:
32
+ * - Design.md (copy of the design system)
33
+ * - handoff-prompt.md (ready-to-use implementation prompt)
34
+ * - README.md (bundle documentation)
35
+ */
36
+ export async function writeHandoffBundle(
37
+ finalDesignDir: string,
38
+ opts: HandoffBundleOptions,
39
+ ): Promise<void> {
40
+ await mkdir(finalDesignDir, { recursive: true });
41
+ await mkdir(path.join(finalDesignDir, "design"), { recursive: true });
42
+
43
+ // Copy Design.md
44
+ await copyFile(
45
+ opts.designSystem.path,
46
+ path.join(finalDesignDir, "Design.md"),
47
+ );
48
+
49
+ // Write handoff-prompt.md
50
+ const handoffPrompt = buildHandoffPrompt(opts);
51
+ await writeFile(
52
+ path.join(finalDesignDir, "handoff-prompt.md"),
53
+ handoffPrompt,
54
+ "utf-8",
55
+ );
56
+
57
+ // Write README.md
58
+ const readme = buildReadme(opts);
59
+ await writeFile(
60
+ path.join(finalDesignDir, "README.md"),
61
+ readme,
62
+ "utf-8",
63
+ );
64
+ }
65
+
66
+ function buildHandoffPrompt(opts: HandoffBundleOptions): string {
67
+ return `# Design Handoff — Implementation Prompt
68
+
69
+ Use this prompt with Claude Code to implement the design in this bundle.
70
+
71
+ ## Original Design Request
72
+
73
+ ${opts.prompt}
74
+
75
+ ## Output Type
76
+
77
+ ${opts.outputType}
78
+
79
+ ## Instructions
80
+
81
+ 1. Read \`Design.md\` for the complete design system (colors, typography, spacing, components).
82
+ 2. Open \`design/index.html\` in a browser to see the reference design.
83
+ 3. Read \`design-intent.md\` for the design rationale and key decisions.
84
+ 4. Read \`component-specs.md\` for individual component specifications.
85
+ 5. Implement the design using the design system tokens from Design.md.
86
+ 6. Match the reference design in \`design/\` as closely as possible.
87
+ 7. Use semantic HTML, CSS custom properties for tokens, and progressive enhancement.
88
+
89
+ ## Design System Tokens
90
+
91
+ The design tokens are defined in \`Design.md\`. Use CSS custom properties:
92
+
93
+ \`\`\`css
94
+ :root {
95
+ /* Import all tokens from Design.md as custom properties */
96
+ }
97
+ \`\`\`
98
+
99
+ ## Quality Checklist
100
+
101
+ - [ ] All colors match Design.md tokens
102
+ - [ ] Typography follows the defined scale
103
+ - [ ] Spacing uses the defined base unit
104
+ - [ ] Components match the identified patterns
105
+ - [ ] No AI slop anti-patterns (gradient text, side-stripe borders, reflex fonts)
106
+ - [ ] Responsive at common breakpoints
107
+ - [ ] Accessible (WCAG 2.1 AA)
108
+ `;
109
+ }
110
+
111
+ function buildReadme(opts: HandoffBundleOptions): string {
112
+ const extraFileRows = buildExtraFileRows(opts.outputType);
113
+ const previewSection = buildPreviewSection(opts.outputType);
114
+
115
+ return `# Design Handoff Bundle
116
+
117
+ Generated by the \`open-claude-design\` workflow.
118
+
119
+ Output type: **${opts.outputType}**
120
+
121
+ ## Contents
122
+
123
+ | File | Description |
124
+ |------|-------------|
125
+ | \`design/index.html\` | Generated HTML |
126
+ | \`design/styles.css\` | Generated CSS styles |
127
+ | \`design/script.js\` | Generated JavaScript |${extraFileRows}
128
+ | \`Design.md\` | Design system tokens (colors, typography, spacing) |
129
+ | \`design-intent.md\` | Design rationale and key decisions |
130
+ | \`component-specs.md\` | Component / page / wireframe / component-anatomy specs |
131
+ | \`handoff-prompt.md\` | Ready-to-use prompt for Claude Code |
132
+
133
+ ## Usage
134
+
135
+ ${previewSection}
136
+
137
+ ### Implement with Claude Code
138
+
139
+ \`\`\`bash
140
+ # From the project root, run:
141
+ claude "$(cat ${opts.outputType === "component" ? "component-specs.md" : "handoff-prompt.md"})"
142
+ \`\`\`
143
+
144
+ ### Design System Reference
145
+
146
+ All design tokens are in \`Design.md\`. Use these tokens when implementing
147
+ to ensure visual consistency with the generated design.
148
+
149
+ ## Original Request
150
+
151
+ ${opts.prompt}
152
+ `;
153
+ }
154
+
155
+ function buildExtraFileRows(outputType: string): string {
156
+ if (outputType === "prototype") {
157
+ return `
158
+ | \`design/server.ts\` | Zero-dependency Bun static-file server (port 4173) |
159
+ | \`design/package.json\` | Defines the \`start\` script |`;
160
+ }
161
+ if (outputType === "component") {
162
+ return `
163
+ | \`design/snippet.html\` | Isolated component markup for copy-paste into a host app |`;
164
+ }
165
+ return "";
166
+ }
167
+
168
+ function buildPreviewSection(outputType: string): string {
169
+ if (outputType === "prototype") {
170
+ return `### Preview the Prototype
171
+
172
+ The prototype ships with a runnable Bun server.
173
+
174
+ \`\`\`bash
175
+ cd design
176
+ bun run start
177
+ # → Prototype running at http://localhost:4173
178
+ \`\`\`
179
+
180
+ Override the port with \`PORT=3000 bun run start\` if 4173 is taken.`;
181
+ }
182
+ if (outputType === "component") {
183
+ return `### Preview the Component
184
+
185
+ Open \`design/index.html\` in a browser to view the component showcase
186
+ (all variants and states). Use \`design/snippet.html\` as a minimal
187
+ copy-paste target for dropping the component into a host application.`;
188
+ }
189
+ // page, wireframe, and any other future single-view output types
190
+ return `### Preview the Design
191
+
192
+ Open \`design/index.html\` directly in a browser — no server required.`;
193
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Import handler — input type detection and aggregation.
3
+ *
4
+ * Classifies the user's `--reference` input as a URL, file path, or
5
+ * neither, and aggregates all import sources into a structured context
6
+ * object that the generator consumes.
7
+ */
8
+
9
+ /** Aggregated import context passed to the generator stage. */
10
+ export interface ImportContext {
11
+ /** The user's free-form design prompt. */
12
+ prompt: string;
13
+ /** Raw reference string (URL, file path, or empty). */
14
+ reference: string;
15
+ /** Extracted content from a web URL capture, or null. */
16
+ webCapture: string | null;
17
+ /** Extracted content from a parsed file, or null. */
18
+ fileParse: string | null;
19
+ }
20
+
21
+ /** Check whether the reference string looks like a URL. */
22
+ export function isUrl(reference: string): boolean {
23
+ if (!reference.trim()) return false;
24
+ return /^https?:\/\//i.test(reference.trim());
25
+ }
26
+
27
+ /** Check whether the reference string looks like a file path. */
28
+ export function isFilePath(reference: string): boolean {
29
+ const trimmed = reference.trim();
30
+ if (!trimmed) return false;
31
+ if (isUrl(trimmed)) return false;
32
+ // Looks like a path: starts with /, ./, ~/, or contains file extension
33
+ return /^[./~]/.test(trimmed) || /\.\w{1,6}$/.test(trimmed);
34
+ }
35
+
36
+ /**
37
+ * Aggregate all import results into a single context object.
38
+ * Pure deterministic function — no LLM call.
39
+ */
40
+ export function aggregateImportResults(opts: {
41
+ prompt: string;
42
+ reference: string;
43
+ webCapture: string | null;
44
+ fileParse: string | null;
45
+ }): ImportContext {
46
+ return {
47
+ prompt: opts.prompt,
48
+ reference: opts.reference,
49
+ webCapture: opts.webCapture,
50
+ fileParse: opts.fileParse,
51
+ };
52
+ }