oh-my-customcode 0.99.1 → 0.99.2
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 +2 -2
- package/dist/cli/index.js +38 -2
- package/dist/index.js +36 -2
- package/package.json +1 -1
- package/templates/.claude/statusline.sh +7 -1
- package/templates/CLAUDE.md +1 -1
- package/templates/guides/claude-design/index.md +191 -0
- package/templates/guides/claude-design/index.yaml +15 -0
- package/templates/manifest.json +2 -2
package/README.md
CHANGED
|
@@ -222,7 +222,7 @@ Key rules: R010 (orchestrator never writes files), R009 (parallel execution mand
|
|
|
222
222
|
|
|
223
223
|
---
|
|
224
224
|
|
|
225
|
-
### Guides (
|
|
225
|
+
### Guides (39)
|
|
226
226
|
|
|
227
227
|
Reference documentation covering best practices, architecture decisions, and integration patterns. Located in `guides/` at project root, covering topics from agent design to CI/CD to observability.
|
|
228
228
|
|
|
@@ -279,7 +279,7 @@ your-project/
|
|
|
279
279
|
│ ├── specs/ # Extracted canonical specs
|
|
280
280
|
│ ├── contexts/ # 4 shared context files
|
|
281
281
|
│ └── ontology/ # Knowledge graph for RAG
|
|
282
|
-
└── guides/ #
|
|
282
|
+
└── guides/ # 39 reference documents
|
|
283
283
|
```
|
|
284
284
|
|
|
285
285
|
---
|
package/dist/cli/index.js
CHANGED
|
@@ -2334,7 +2334,7 @@ var init_package = __esm(() => {
|
|
|
2334
2334
|
workspaces: [
|
|
2335
2335
|
"packages/*"
|
|
2336
2336
|
],
|
|
2337
|
-
version: "0.99.
|
|
2337
|
+
version: "0.99.2",
|
|
2338
2338
|
description: "Batteries-included agent harness for Claude Code",
|
|
2339
2339
|
type: "module",
|
|
2340
2340
|
bin: {
|
|
@@ -28107,7 +28107,14 @@ async function installSettingsLocal(targetDir, result) {
|
|
|
28107
28107
|
await writeJsonFile(settingsPath, existing);
|
|
28108
28108
|
debug("install.settings_local_merged", {});
|
|
28109
28109
|
} else {
|
|
28110
|
-
|
|
28110
|
+
const sl = existing.statusLine;
|
|
28111
|
+
if (sl.refreshInterval === undefined) {
|
|
28112
|
+
sl.refreshInterval = statusLineConfig.statusLine.refreshInterval;
|
|
28113
|
+
await writeJsonFile(settingsPath, existing);
|
|
28114
|
+
debug("install.settings_local_refreshInterval_added", {});
|
|
28115
|
+
} else {
|
|
28116
|
+
debug("install.settings_local_skipped", { reason: "statusLine exists" });
|
|
28117
|
+
}
|
|
28111
28118
|
}
|
|
28112
28119
|
} catch {
|
|
28113
28120
|
result.warnings.push("Failed to parse existing settings.local.json, skipping statusLine config");
|
|
@@ -31008,6 +31015,32 @@ async function updateEntryDoc(targetDir, config, options) {
|
|
|
31008
31015
|
info("update.entry_doc_created", { path: layout.entryFile });
|
|
31009
31016
|
}
|
|
31010
31017
|
}
|
|
31018
|
+
async function backfillStatusLineRefreshInterval(targetDir, options) {
|
|
31019
|
+
if (options.dryRun) {
|
|
31020
|
+
return;
|
|
31021
|
+
}
|
|
31022
|
+
const layout = getProviderLayout();
|
|
31023
|
+
const settingsPath = join17(targetDir, layout.rootDir, "settings.local.json");
|
|
31024
|
+
if (!await fileExists(settingsPath)) {
|
|
31025
|
+
return;
|
|
31026
|
+
}
|
|
31027
|
+
try {
|
|
31028
|
+
const existing = await readJsonFile(settingsPath);
|
|
31029
|
+
if (!existing.statusLine) {
|
|
31030
|
+
return;
|
|
31031
|
+
}
|
|
31032
|
+
const sl = existing.statusLine;
|
|
31033
|
+
if (sl.refreshInterval === undefined) {
|
|
31034
|
+
sl.refreshInterval = 10;
|
|
31035
|
+
await writeJsonFile(settingsPath, existing);
|
|
31036
|
+
debug("update.settings_local_refreshInterval_backfilled", {});
|
|
31037
|
+
}
|
|
31038
|
+
} catch {
|
|
31039
|
+
warn("update.settings_local_backfill_failed", {
|
|
31040
|
+
path: settingsPath
|
|
31041
|
+
});
|
|
31042
|
+
}
|
|
31043
|
+
}
|
|
31011
31044
|
async function runFullUpdatePostProcessing(options, result, config) {
|
|
31012
31045
|
const isFullUpdate = !options.components || options.components.length === 0;
|
|
31013
31046
|
if (isFullUpdate) {
|
|
@@ -31017,6 +31050,7 @@ async function runFullUpdatePostProcessing(options, result, config) {
|
|
|
31017
31050
|
result.removedDeprecatedFiles = removed;
|
|
31018
31051
|
if (!options.dryRun) {
|
|
31019
31052
|
await updateEntryDoc(options.targetDir, config, options);
|
|
31053
|
+
await backfillStatusLineRefreshInterval(options.targetDir, options);
|
|
31020
31054
|
}
|
|
31021
31055
|
}
|
|
31022
31056
|
if (!options.dryRun) {
|
|
@@ -31597,7 +31631,9 @@ function reportProjectUpdateResult(project, result, currentVersion) {
|
|
|
31597
31631
|
}
|
|
31598
31632
|
async function updateAllProjects(options) {
|
|
31599
31633
|
const { findProjects: findProjects2 } = await Promise.resolve().then(() => (init_projects(), exports_projects));
|
|
31634
|
+
const { cleanRegistry: cleanRegistry2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
31600
31635
|
const currentVersion = package_default.version;
|
|
31636
|
+
await cleanRegistry2();
|
|
31601
31637
|
console.log(i18n.t("cli.update.allScanning"));
|
|
31602
31638
|
const projects = await findProjects2();
|
|
31603
31639
|
if (projects.length === 0) {
|
package/dist/index.js
CHANGED
|
@@ -1699,7 +1699,14 @@ async function installSettingsLocal(targetDir, result) {
|
|
|
1699
1699
|
await writeJsonFile(settingsPath, existing);
|
|
1700
1700
|
debug("install.settings_local_merged", {});
|
|
1701
1701
|
} else {
|
|
1702
|
-
|
|
1702
|
+
const sl = existing.statusLine;
|
|
1703
|
+
if (sl.refreshInterval === undefined) {
|
|
1704
|
+
sl.refreshInterval = statusLineConfig.statusLine.refreshInterval;
|
|
1705
|
+
await writeJsonFile(settingsPath, existing);
|
|
1706
|
+
debug("install.settings_local_refreshInterval_added", {});
|
|
1707
|
+
} else {
|
|
1708
|
+
debug("install.settings_local_skipped", { reason: "statusLine exists" });
|
|
1709
|
+
}
|
|
1703
1710
|
}
|
|
1704
1711
|
} catch {
|
|
1705
1712
|
result.warnings.push("Failed to parse existing settings.local.json, skipping statusLine config");
|
|
@@ -2007,7 +2014,7 @@ var package_default = {
|
|
|
2007
2014
|
workspaces: [
|
|
2008
2015
|
"packages/*"
|
|
2009
2016
|
],
|
|
2010
|
-
version: "0.99.
|
|
2017
|
+
version: "0.99.2",
|
|
2011
2018
|
description: "Batteries-included agent harness for Claude Code",
|
|
2012
2019
|
type: "module",
|
|
2013
2020
|
bin: {
|
|
@@ -4806,6 +4813,32 @@ async function updateEntryDoc(targetDir, config, options) {
|
|
|
4806
4813
|
info("update.entry_doc_created", { path: layout.entryFile });
|
|
4807
4814
|
}
|
|
4808
4815
|
}
|
|
4816
|
+
async function backfillStatusLineRefreshInterval(targetDir, options) {
|
|
4817
|
+
if (options.dryRun) {
|
|
4818
|
+
return;
|
|
4819
|
+
}
|
|
4820
|
+
const layout = getProviderLayout();
|
|
4821
|
+
const settingsPath = join7(targetDir, layout.rootDir, "settings.local.json");
|
|
4822
|
+
if (!await fileExists(settingsPath)) {
|
|
4823
|
+
return;
|
|
4824
|
+
}
|
|
4825
|
+
try {
|
|
4826
|
+
const existing = await readJsonFile(settingsPath);
|
|
4827
|
+
if (!existing.statusLine) {
|
|
4828
|
+
return;
|
|
4829
|
+
}
|
|
4830
|
+
const sl = existing.statusLine;
|
|
4831
|
+
if (sl.refreshInterval === undefined) {
|
|
4832
|
+
sl.refreshInterval = 10;
|
|
4833
|
+
await writeJsonFile(settingsPath, existing);
|
|
4834
|
+
debug("update.settings_local_refreshInterval_backfilled", {});
|
|
4835
|
+
}
|
|
4836
|
+
} catch {
|
|
4837
|
+
warn("update.settings_local_backfill_failed", {
|
|
4838
|
+
path: settingsPath
|
|
4839
|
+
});
|
|
4840
|
+
}
|
|
4841
|
+
}
|
|
4809
4842
|
async function runFullUpdatePostProcessing(options, result, config) {
|
|
4810
4843
|
const isFullUpdate = !options.components || options.components.length === 0;
|
|
4811
4844
|
if (isFullUpdate) {
|
|
@@ -4815,6 +4848,7 @@ async function runFullUpdatePostProcessing(options, result, config) {
|
|
|
4815
4848
|
result.removedDeprecatedFiles = removed;
|
|
4816
4849
|
if (!options.dryRun) {
|
|
4817
4850
|
await updateEntryDoc(options.targetDir, config, options);
|
|
4851
|
+
await backfillStatusLineRefreshInterval(options.targetDir, options);
|
|
4818
4852
|
}
|
|
4819
4853
|
}
|
|
4820
4854
|
if (!options.dryRun) {
|
package/package.json
CHANGED
|
@@ -246,7 +246,13 @@ if [[ -n "$git_branch" ]] && command -v gh >/dev/null 2>&1; then
|
|
|
246
246
|
pr_number="$cached_pr"
|
|
247
247
|
else
|
|
248
248
|
# Cache miss — query gh and update cache
|
|
249
|
-
|
|
249
|
+
# Timeout-guarded gh pr view (2 second limit)
|
|
250
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
251
|
+
pr_number="$(timeout 2 gh pr view --json number -q .number 2>/dev/null || echo "")"
|
|
252
|
+
else
|
|
253
|
+
pr_number="$( (gh pr view --json number -q .number 2>/dev/null &
|
|
254
|
+
_pid=$!; (sleep 2; kill $_pid 2>/dev/null) &; wait $_pid 2>/dev/null) || echo "" )"
|
|
255
|
+
fi
|
|
250
256
|
printf '%s\t%s\n' "$git_branch" "$pr_number" > "$cache_file"
|
|
251
257
|
fi
|
|
252
258
|
|
package/templates/CLAUDE.md
CHANGED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Claude Design Handoff Guide
|
|
2
|
+
|
|
3
|
+
Guide for connecting Claude Design (Anthropic's conversational design tool) outputs to Claude Code's `fe-design-expert` workflow.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. What is Claude Design?
|
|
8
|
+
|
|
9
|
+
Claude Design is Anthropic's conversational design tool that generates UI design specifications through natural language dialogue. It produces structured design artifacts — component specs, design tokens, layout definitions — intended for direct handoff to a coding workflow.
|
|
10
|
+
|
|
11
|
+
**Key distinction**: Claude Design produces *design intent* (what it should look like, why), not production code. The handoff to Claude Code is where intent becomes implementation.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Artifact Formats
|
|
16
|
+
|
|
17
|
+
Claude Design exports artifacts in two primary forms:
|
|
18
|
+
|
|
19
|
+
### Design Token JSON
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"tokens": {
|
|
24
|
+
"color": {
|
|
25
|
+
"brand-primary": { "value": "oklch(0.65 0.22 264)", "type": "color" },
|
|
26
|
+
"surface-base": { "value": "oklch(0.98 0.005 264)", "type": "color" },
|
|
27
|
+
"text-primary": { "value": "oklch(0.15 0.01 264)", "type": "color" }
|
|
28
|
+
},
|
|
29
|
+
"spacing": {
|
|
30
|
+
"xs": { "value": "4px", "type": "dimension" },
|
|
31
|
+
"sm": { "value": "8px", "type": "dimension" },
|
|
32
|
+
"md": { "value": "16px", "type": "dimension" },
|
|
33
|
+
"lg": { "value": "24px", "type": "dimension" },
|
|
34
|
+
"xl": { "value": "40px", "type": "dimension" }
|
|
35
|
+
},
|
|
36
|
+
"typography": {
|
|
37
|
+
"heading-xl": { "fontFamily": "Inter", "fontSize": "36px", "fontWeight": "700", "lineHeight": "1.15" },
|
|
38
|
+
"body-md": { "fontFamily": "Inter", "fontSize": "16px", "fontWeight": "400", "lineHeight": "1.6" }
|
|
39
|
+
},
|
|
40
|
+
"radius": {
|
|
41
|
+
"sm": { "value": "4px" },
|
|
42
|
+
"md": { "value": "8px" },
|
|
43
|
+
"lg": { "value": "16px" }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Component Specification
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"component": "PrimaryButton",
|
|
54
|
+
"intent": "High-emphasis action trigger",
|
|
55
|
+
"variants": ["default", "hover", "active", "disabled"],
|
|
56
|
+
"tokens": {
|
|
57
|
+
"background": "color.brand-primary",
|
|
58
|
+
"text": "color.surface-base",
|
|
59
|
+
"padding": "spacing.sm spacing.md",
|
|
60
|
+
"radius": "radius.md"
|
|
61
|
+
},
|
|
62
|
+
"motion": {
|
|
63
|
+
"hover": "background lightens 8%, 150ms ease-out",
|
|
64
|
+
"active": "scale(0.97), 80ms ease-in"
|
|
65
|
+
},
|
|
66
|
+
"states": {
|
|
67
|
+
"disabled": "opacity: 0.45, cursor: not-allowed"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 3. Claude Design → Claude Code Handoff Workflow
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Claude Design session
|
|
78
|
+
↓ Export artifacts (tokens JSON + component specs)
|
|
79
|
+
↓
|
|
80
|
+
fe-design-expert receives handoff
|
|
81
|
+
├── 1. Validate token structure and completeness
|
|
82
|
+
├── 2. Convert tokens to CSS custom properties
|
|
83
|
+
├── 3. Implement component specs as framework components
|
|
84
|
+
├── 4. Run AI Slop Test on generated output
|
|
85
|
+
└── 5. Verify motion specs are purposeful, not decorative
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Step 1 — Token Validation
|
|
89
|
+
|
|
90
|
+
Before implementing, `fe-design-expert` checks:
|
|
91
|
+
|
|
92
|
+
| Check | Pass Condition |
|
|
93
|
+
|-------|---------------|
|
|
94
|
+
| Color format | OKLCH preferred; hex acceptable with tinting |
|
|
95
|
+
| Typography completeness | At least 2 scale levels (heading + body) |
|
|
96
|
+
| Spacing system | Consistent multiplier (e.g., 4px base) |
|
|
97
|
+
| No pure values | No `#000`, `#fff`, `0px` radius everywhere |
|
|
98
|
+
|
|
99
|
+
### Step 2 — CSS Custom Properties Conversion
|
|
100
|
+
|
|
101
|
+
```css
|
|
102
|
+
:root {
|
|
103
|
+
/* Colors */
|
|
104
|
+
--color-brand-primary: oklch(0.65 0.22 264);
|
|
105
|
+
--color-surface-base: oklch(0.98 0.005 264);
|
|
106
|
+
--color-text-primary: oklch(0.15 0.01 264);
|
|
107
|
+
|
|
108
|
+
/* Spacing */
|
|
109
|
+
--spacing-xs: 4px;
|
|
110
|
+
--spacing-sm: 8px;
|
|
111
|
+
--spacing-md: 16px;
|
|
112
|
+
--spacing-lg: 24px;
|
|
113
|
+
--spacing-xl: 40px;
|
|
114
|
+
|
|
115
|
+
/* Typography */
|
|
116
|
+
--font-heading-xl-size: 36px;
|
|
117
|
+
--font-heading-xl-weight: 700;
|
|
118
|
+
--font-heading-xl-line-height: 1.15;
|
|
119
|
+
--font-body-md-size: 16px;
|
|
120
|
+
--font-body-md-line-height: 1.6;
|
|
121
|
+
|
|
122
|
+
/* Radius */
|
|
123
|
+
--radius-sm: 4px;
|
|
124
|
+
--radius-md: 8px;
|
|
125
|
+
--radius-lg: 16px;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Step 3 — Component Implementation
|
|
130
|
+
|
|
131
|
+
For each component spec, fe-design-expert maps design intent to framework idioms. The component spec drives the structure; the Impeccable design language guides the aesthetic decisions.
|
|
132
|
+
|
|
133
|
+
### Step 4 — Slop Test
|
|
134
|
+
|
|
135
|
+
All handoff implementations pass the [AI Slop Test](../impeccable-design/typography.md) before shipping. Common handoff failures:
|
|
136
|
+
|
|
137
|
+
- Generic gradient applied without contextual rationale from the spec
|
|
138
|
+
- Uniform border radius applied to all elements despite spec differentiation
|
|
139
|
+
- Motion added from spec but without checking `prefers-reduced-motion`
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 4. fe-design-expert Validation Checklist
|
|
144
|
+
|
|
145
|
+
When receiving a Claude Design handoff, fe-design-expert verifies:
|
|
146
|
+
|
|
147
|
+
**Token Integrity**
|
|
148
|
+
- [ ] Color values use OKLCH or intentionally tinted hex (no pure neutrals)
|
|
149
|
+
- [ ] Spacing values follow a consistent scale (not random)
|
|
150
|
+
- [ ] Typography has clear hierarchy (not all the same weight/size)
|
|
151
|
+
|
|
152
|
+
**Component Fidelity**
|
|
153
|
+
- [ ] All variant states from the spec are implemented (hover, active, disabled)
|
|
154
|
+
- [ ] Token references in code match the CSS custom property names
|
|
155
|
+
- [ ] No hardcoded values where a token exists in the spec
|
|
156
|
+
|
|
157
|
+
**Motion Verification**
|
|
158
|
+
- [ ] Each animation has a functional purpose from the spec intent
|
|
159
|
+
- [ ] `prefers-reduced-motion` media query wraps all transitions
|
|
160
|
+
- [ ] Duration follows the spec; no arbitrary values
|
|
161
|
+
|
|
162
|
+
**Slop Check**
|
|
163
|
+
- [ ] Would a developer immediately identify this as AI-generated? → Must be NO
|
|
164
|
+
- [ ] Are spacing increments varied intentionally, not uniformly 8px everywhere?
|
|
165
|
+
- [ ] Does the color palette have at least one intentional tinted neutral?
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 5. Common Handoff Issues
|
|
170
|
+
|
|
171
|
+
| Issue | Symptom | Resolution |
|
|
172
|
+
|-------|---------|------------|
|
|
173
|
+
| Token name mismatch | CSS var not found in component | Reconcile export names with implementation names |
|
|
174
|
+
| Missing states | Hover/disabled not specified | Ask Claude Design to complete the variant set before handoff |
|
|
175
|
+
| Motion without context | Animation in spec but no intent stated | Treat as decorative — remove or add functional justification |
|
|
176
|
+
| Incomplete spacing system | Gaps between spec tokens and layout needs | Interpolate from the existing scale; do not introduce arbitrary values |
|
|
177
|
+
| Font not available | Spec font not on system/CDN | Use the closest available weight/optical size from the same family |
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 6. Quick Reference
|
|
182
|
+
|
|
183
|
+
| Artifact | Format | Handled by |
|
|
184
|
+
|----------|--------|-----------|
|
|
185
|
+
| Design tokens | JSON → CSS custom properties | fe-design-expert |
|
|
186
|
+
| Component specs | JSON → framework components | fe-design-expert |
|
|
187
|
+
| Layout definitions | Spatial intent → CSS Grid/Flex | fe-design-expert |
|
|
188
|
+
| Motion specs | Timing intent → CSS transitions/animations | fe-design-expert |
|
|
189
|
+
| Accessibility requirements | WCAG notes → fe-vercel-agent / web-design-guidelines | fe-vercel-agent |
|
|
190
|
+
|
|
191
|
+
**Agent handoff**: `fe-design-expert` handles aesthetics and visual implementation. For accessibility compliance and semantic HTML, pass to `fe-vercel-agent` or invoke the `web-design-guidelines` skill.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: claude-design
|
|
2
|
+
description: Claude Design artifact handoff workflow — connecting Anthropic's conversational design tool outputs to Claude Code's fe-design-expert implementation pipeline
|
|
3
|
+
|
|
4
|
+
source:
|
|
5
|
+
type: internal
|
|
6
|
+
|
|
7
|
+
topics:
|
|
8
|
+
- design-token-export
|
|
9
|
+
- component-spec-handoff
|
|
10
|
+
- css-custom-properties
|
|
11
|
+
- slop-test-validation
|
|
12
|
+
- motion-verification
|
|
13
|
+
|
|
14
|
+
used_by:
|
|
15
|
+
- fe-design-expert
|
package/templates/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.99.
|
|
2
|
+
"version": "0.99.2",
|
|
3
3
|
"lastUpdated": "2026-04-18T00:00:00.000Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"name": "guides",
|
|
25
25
|
"path": "guides",
|
|
26
26
|
"description": "Reference documentation",
|
|
27
|
-
"files":
|
|
27
|
+
"files": 39
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"name": "hooks",
|