@1agh/maude 0.15.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/LICENSE +21 -0
- package/README.md +166 -0
- package/cli/bin/maude.exe +15 -0
- package/cli/bin/maude.mjs +45 -0
- package/cli/bin/mdcc.exe +10 -0
- package/cli/bin/mdcc.mjs +7 -0
- package/cli/cli-wrapper.cjs +67 -0
- package/cli/commands/config.mjs +94 -0
- package/cli/commands/design.mjs +386 -0
- package/cli/commands/help.mjs +57 -0
- package/cli/commands/init.mjs +178 -0
- package/cli/commands/version.mjs +7 -0
- package/cli/install.cjs +113 -0
- package/cli/lib/argv.mjs +37 -0
- package/cli/lib/argv.test.mjs +46 -0
- package/cli/lib/copy-tree.mjs +78 -0
- package/package.json +94 -0
- package/plugins/design/dev-server/annotations-context-toolbar.tsx +397 -0
- package/plugins/design/dev-server/annotations-layer.tsx +1717 -0
- package/plugins/design/dev-server/api.ts +674 -0
- package/plugins/design/dev-server/bin/_screenshot-playwright.mjs +50 -0
- package/plugins/design/dev-server/bin/bootstrap-check.sh +83 -0
- package/plugins/design/dev-server/bin/canvas-edit.sh +48 -0
- package/plugins/design/dev-server/bin/handoff.sh +27 -0
- package/plugins/design/dev-server/bin/screenshot.sh +232 -0
- package/plugins/design/dev-server/bin/server-up.sh +135 -0
- package/plugins/design/dev-server/bin/slug.sh +22 -0
- package/plugins/design/dev-server/bin/smoke.sh +272 -0
- package/plugins/design/dev-server/build.ts +267 -0
- package/plugins/design/dev-server/canvas-build.ts +219 -0
- package/plugins/design/dev-server/canvas-edit.ts +388 -0
- package/plugins/design/dev-server/canvas-header.ts +165 -0
- package/plugins/design/dev-server/canvas-icons.tsx +131 -0
- package/plugins/design/dev-server/canvas-lib-inline.ts +260 -0
- package/plugins/design/dev-server/canvas-lib-resolver.ts +85 -0
- package/plugins/design/dev-server/canvas-lib.tsx +1995 -0
- package/plugins/design/dev-server/canvas-meta.schema.json +181 -0
- package/plugins/design/dev-server/canvas-pipeline.ts +270 -0
- package/plugins/design/dev-server/canvas-shell.tsx +813 -0
- package/plugins/design/dev-server/client/app.jsx +2027 -0
- package/plugins/design/dev-server/client/hmr.mjs +85 -0
- package/plugins/design/dev-server/client/iframe-lazy.mjs +121 -0
- package/plugins/design/dev-server/client/index.html +15 -0
- package/plugins/design/dev-server/client/styles/0-reset.css +18 -0
- package/plugins/design/dev-server/client/styles/1-tokens.css +297 -0
- package/plugins/design/dev-server/client/styles/2-layout.css +35 -0
- package/plugins/design/dev-server/client/styles/3-shell.css +906 -0
- package/plugins/design/dev-server/client/styles/4-components.css +1268 -0
- package/plugins/design/dev-server/client/styles/5-utilities.css +4 -0
- package/plugins/design/dev-server/client/styles/_index.css +24 -0
- package/plugins/design/dev-server/client/styles.css +1419 -0
- package/plugins/design/dev-server/config.schema.json +147 -0
- package/plugins/design/dev-server/context-menu.tsx +343 -0
- package/plugins/design/dev-server/context.ts +173 -0
- package/plugins/design/dev-server/dist/client.bundle.js +20323 -0
- package/plugins/design/dev-server/dist/styles.css +2875 -0
- package/plugins/design/dev-server/examples/README.md +9 -0
- package/plugins/design/dev-server/examples/perf-100-artboards.tsx +113 -0
- package/plugins/design/dev-server/fs-watch.ts +63 -0
- package/plugins/design/dev-server/handoff.ts +721 -0
- package/plugins/design/dev-server/history.ts +125 -0
- package/plugins/design/dev-server/hmr-broadcast.ts +114 -0
- package/plugins/design/dev-server/http.ts +413 -0
- package/plugins/design/dev-server/input-router.tsx +485 -0
- package/plugins/design/dev-server/inspect.ts +365 -0
- package/plugins/design/dev-server/locator.ts +159 -0
- package/plugins/design/dev-server/mem.ts +97 -0
- package/plugins/design/dev-server/runtime-bundle.ts +235 -0
- package/plugins/design/dev-server/server.mjs +1246 -0
- package/plugins/design/dev-server/server.ts +131 -0
- package/plugins/design/dev-server/test/_helpers.ts +81 -0
- package/plugins/design/dev-server/test/active-state.test.ts +145 -0
- package/plugins/design/dev-server/test/annotations-api.test.ts +146 -0
- package/plugins/design/dev-server/test/annotations-layer.test.ts +419 -0
- package/plugins/design/dev-server/test/binary-smoke.test.ts +47 -0
- package/plugins/design/dev-server/test/bundle-smoke.test.ts +29 -0
- package/plugins/design/dev-server/test/canvas-build.test.ts +78 -0
- package/plugins/design/dev-server/test/canvas-edit.test.ts +139 -0
- package/plugins/design/dev-server/test/canvas-header.test.ts +127 -0
- package/plugins/design/dev-server/test/canvas-lib-inline.test.ts +146 -0
- package/plugins/design/dev-server/test/canvas-lib-resolver.test.ts +112 -0
- package/plugins/design/dev-server/test/canvas-meta-api.test.ts +236 -0
- package/plugins/design/dev-server/test/canvas-pipeline.test.ts +180 -0
- package/plugins/design/dev-server/test/canvas-route.test.ts +176 -0
- package/plugins/design/dev-server/test/fs-watch.test.ts +41 -0
- package/plugins/design/dev-server/test/handoff-static-frames.test.ts +215 -0
- package/plugins/design/dev-server/test/handoff.test.ts +281 -0
- package/plugins/design/dev-server/test/history-rollback.test.ts +62 -0
- package/plugins/design/dev-server/test/hmr-broadcast.test.ts +108 -0
- package/plugins/design/dev-server/test/input-router.test.ts +316 -0
- package/plugins/design/dev-server/test/locator.test.ts +214 -0
- package/plugins/design/dev-server/test/perf-harness.ts +193 -0
- package/plugins/design/dev-server/test/phase-3.6-smoke.test.ts +77 -0
- package/plugins/design/dev-server/test/runtime-bundle.test.ts +69 -0
- package/plugins/design/dev-server/test/server-lifecycle.test.ts +28 -0
- package/plugins/design/dev-server/test/tool-palette.test.tsx +55 -0
- package/plugins/design/dev-server/test/use-annotation-selection.test.tsx +77 -0
- package/plugins/design/dev-server/test/use-artboard-drag.test.ts +325 -0
- package/plugins/design/dev-server/test/use-selection-set.test.tsx +166 -0
- package/plugins/design/dev-server/test/use-snap-guides.test.ts +190 -0
- package/plugins/design/dev-server/test/use-tool-mode.test.tsx +93 -0
- package/plugins/design/dev-server/test/ws-handshake.test.ts +33 -0
- package/plugins/design/dev-server/tool-palette.tsx +278 -0
- package/plugins/design/dev-server/tsconfig.json +26 -0
- package/plugins/design/dev-server/use-annotation-selection.tsx +92 -0
- package/plugins/design/dev-server/use-annotations-visibility.tsx +43 -0
- package/plugins/design/dev-server/use-artboard-drag.tsx +445 -0
- package/plugins/design/dev-server/use-selection-set.tsx +224 -0
- package/plugins/design/dev-server/use-snap-guides.tsx +215 -0
- package/plugins/design/dev-server/use-tool-mode.tsx +114 -0
- package/plugins/design/dev-server/ws.ts +90 -0
- package/plugins/design/templates/_shell.html +177 -0
- package/plugins/design/templates/canvas.tsx.template +54 -0
- package/plugins/design/templates/design-system-inspiration/_MAPPING.md +277 -0
- package/plugins/design/templates/design-system-inspiration/_README.md +71 -0
- package/plugins/design/templates/design-system-inspiration/audience-consumer/components-banner.html +68 -0
- package/plugins/design/templates/design-system-inspiration/audience-consumer/components-empty-state-generous.html +39 -0
- package/plugins/design/templates/design-system-inspiration/audience-consumer/components-feature-grid.html +62 -0
- package/plugins/design/templates/design-system-inspiration/audience-consumer/components-marketing-card.html +63 -0
- package/plugins/design/templates/design-system-inspiration/audience-consumer/components-testimonial.html +80 -0
- package/plugins/design/templates/design-system-inspiration/audience-developer/components-code-block.html +71 -0
- package/plugins/design/templates/design-system-inspiration/audience-developer/components-diff-view.html +65 -0
- package/plugins/design/templates/design-system-inspiration/audience-developer/components-log-stream.html +62 -0
- package/plugins/design/templates/design-system-inspiration/audience-developer/components-monospace-table.html +57 -0
- package/plugins/design/templates/design-system-inspiration/audience-developer/components-terminal-pane.html +67 -0
- package/plugins/design/templates/design-system-inspiration/audience-developer/type-mono.html +57 -0
- package/plugins/design/templates/design-system-inspiration/audience-pro/colors-presence.html +74 -0
- package/plugins/design/templates/design-system-inspiration/audience-pro/components-command-palette.html +90 -0
- package/plugins/design/templates/design-system-inspiration/audience-pro/components-keyboard.html +51 -0
- package/plugins/design/templates/design-system-inspiration/audience-pro/components-list.html +89 -0
- package/plugins/design/templates/design-system-inspiration/audience-pro/components-shortcuts-overlay.html +85 -0
- package/plugins/design/templates/design-system-inspiration/audience-pro/components-toast-menu.html +80 -0
- package/plugins/design/templates/design-system-inspiration/core/INDEX.md.tpl +25 -0
- package/plugins/design/templates/design-system-inspiration/core/README.orchestration.md.tpl +71 -0
- package/plugins/design/templates/design-system-inspiration/core/README.philosophy.md.tpl +77 -0
- package/plugins/design/templates/design-system-inspiration/core/SKILL.md.tpl +50 -0
- package/plugins/design/templates/design-system-inspiration/core/colors_and_type.css.tpl +111 -0
- package/plugins/design/templates/design-system-inspiration/core/config.json.tpl +28 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/_layout.css +113 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/colors-accent.html +48 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/colors-surfaces.html +49 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/colors-text.html +52 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/components-buttons.html +83 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/components-cards.html +79 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/components-inputs.html +82 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/motion.html +66 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/spacing-scale.html +53 -0
- package/plugins/design/templates/design-system-inspiration/core/preview/type-scale.html +62 -0
- package/plugins/design/templates/design-system-inspiration/foundations/borders.html +39 -0
- package/plugins/design/templates/design-system-inspiration/foundations/elevation.html +46 -0
- package/plugins/design/templates/design-system-inspiration/foundations/focus.html +48 -0
- package/plugins/design/templates/design-system-inspiration/foundations/grid.html +51 -0
- package/plugins/design/templates/design-system-inspiration/foundations/iconography.html +73 -0
- package/plugins/design/templates/design-system-inspiration/foundations/opacity.html +45 -0
- package/plugins/design/templates/design-system-inspiration/foundations/radii.html +40 -0
- package/plugins/design/templates/design-system-inspiration/foundations/selection.html +45 -0
- package/plugins/design/templates/design-system-inspiration/meta/accessibility.html +62 -0
- package/plugins/design/templates/design-system-inspiration/meta/i18n.html +73 -0
- package/plugins/design/templates/design-system-inspiration/meta/presence-multiplayer.html +71 -0
- package/plugins/design/templates/design-system-inspiration/meta/tokens-index.html +80 -0
- package/plugins/design/templates/design-system-inspiration/patterns/patterns-auth.html +78 -0
- package/plugins/design/templates/design-system-inspiration/patterns/patterns-data-density.html +61 -0
- package/plugins/design/templates/design-system-inspiration/patterns/patterns-error-pages.html +70 -0
- package/plugins/design/templates/design-system-inspiration/patterns/patterns-form-layouts.html +70 -0
- package/plugins/design/templates/design-system-inspiration/patterns/patterns-onboarding.html +71 -0
- package/plugins/design/templates/design-system-inspiration/patterns/patterns-pricing.html +83 -0
- package/plugins/design/templates/design-system-inspiration/platform-desktop/components-resize-panels.html +63 -0
- package/plugins/design/templates/design-system-inspiration/platform-desktop/ui_kits-desktop-index.html +55 -0
- package/plugins/design/templates/design-system-inspiration/platform-desktop/ui_kits-desktop-showcase.html +302 -0
- package/plugins/design/templates/design-system-inspiration/platform-mobile/components-bottom-sheet.html +63 -0
- package/plugins/design/templates/design-system-inspiration/platform-mobile/components-pull-to-refresh.html +74 -0
- package/plugins/design/templates/design-system-inspiration/platform-mobile/components-segmented-control.html +51 -0
- package/plugins/design/templates/design-system-inspiration/platform-mobile/components-tab-bar.html +57 -0
- package/plugins/design/templates/design-system-inspiration/platform-mobile/ui_kits-mobile-index.html +58 -0
- package/plugins/design/templates/design-system-inspiration/platform-mobile/ui_kits-mobile-showcase.html +237 -0
- package/plugins/design/templates/design-system-inspiration/status/colors-status.html +49 -0
- package/plugins/design/templates/design-system-inspiration/status/components-status.html +63 -0
- package/plugins/design/templates/design-system-inspiration/status/skeletons.html +74 -0
- package/plugins/design/templates/design-system-inspiration/theme-both/colors-themes-side-by-side.html +59 -0
- package/plugins/design/templates/design-system-inspiration/universal/components-callout.html +74 -0
- package/plugins/design/templates/design-system-inspiration/universal/components-dialogs.html +81 -0
- package/plugins/design/templates/design-system-inspiration/universal/components-tables.html +101 -0
- package/plugins/design/templates/design-system-inspiration/universal/components-toggles.html +74 -0
- package/plugins/design/templates/design-system-inspiration/universal/components-tooltips.html +74 -0
- package/plugins/design/templates/design-system-inspiration/universal/empty-state.html.tpl +34 -0
- package/plugins/design/templates/design-system-inspiration/universal/logo.html +42 -0
- package/plugins/design/templates/ds-specimen.tsx.template +59 -0
- package/plugins/flow/.claude-plugin/config.schema.json +398 -0
- package/plugins/flow/README.md +45 -0
- package/plugins/flow/templates/ai-skeleton/INDEX.md +50 -0
- package/plugins/flow/templates/ai-skeleton/README.md +46 -0
- package/plugins/flow/templates/ai-skeleton/browser/har/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/browser/snapshots/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/business/README.md +12 -0
- package/plugins/flow/templates/ai-skeleton/context/README.md +12 -0
- package/plugins/flow/templates/ai-skeleton/decisions/README.md +20 -0
- package/plugins/flow/templates/ai-skeleton/design-import/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/dev-logs/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/device/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/docs/README.md +5 -0
- package/plugins/flow/templates/ai-skeleton/logs/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/logs/README.md +13 -0
- package/plugins/flow/templates/ai-skeleton/plans/README.md +16 -0
- package/plugins/flow/templates/ai-skeleton/plans/archive/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/release-guide.md +35 -0
- package/plugins/flow/templates/ai-skeleton/reviews/README.md +15 -0
- package/plugins/flow/templates/ai-skeleton/scenarios/README.md +26 -0
- package/plugins/flow/templates/ai-skeleton/scenarios/_lib/.gitkeep +0 -0
- package/plugins/flow/templates/ai-skeleton/state/STATE.md +25 -0
- package/plugins/flow/templates/ai-skeleton/templates/HANDOFF.md +32 -0
- package/plugins/flow/templates/ai-skeleton/workflows.config.json +74 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { basename, join, resolve } from 'node:path';
|
|
4
|
+
import { parseArgs } from '../lib/argv.mjs';
|
|
5
|
+
|
|
6
|
+
const SUBCOMMANDS = new Set(['serve', 'init', 'help']);
|
|
7
|
+
|
|
8
|
+
export async function run({ args, pkgRoot }) {
|
|
9
|
+
const { positional } = parseArgs(args);
|
|
10
|
+
const sub = positional[0];
|
|
11
|
+
|
|
12
|
+
if (!sub || sub === 'help') {
|
|
13
|
+
process.stdout.write(usage());
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!SUBCOMMANDS.has(sub)) {
|
|
18
|
+
process.stderr.write(`maude design: unknown subcommand "${sub}"\n${usage()}`);
|
|
19
|
+
process.exit(2);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (sub === 'serve') {
|
|
23
|
+
return runServe({ args, pkgRoot });
|
|
24
|
+
}
|
|
25
|
+
if (sub === 'init') {
|
|
26
|
+
return runInit({ args, pkgRoot });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function usage() {
|
|
31
|
+
return `maude design <serve|init> [options]
|
|
32
|
+
|
|
33
|
+
serve [--port N] [--root PATH]
|
|
34
|
+
Start the design plugin's dev server in the current repo. Equivalent
|
|
35
|
+
to invoking 'claude-design-server'. Forwards all remaining args.
|
|
36
|
+
|
|
37
|
+
init [--name <slug>] [--ds <name>] [--force] [--dry-run]
|
|
38
|
+
[--no-discovery | --discovery-payload <path>]
|
|
39
|
+
Non-interactive scaffold helper. Writes Core files from the
|
|
40
|
+
design-system-inspiration library into .design/ in the current repo.
|
|
41
|
+
Refuses to run without --no-discovery or --discovery-payload (interactive
|
|
42
|
+
bootstrap requires Claude Code: use /design:setup-ds <name> there).
|
|
43
|
+
|
|
44
|
+
--no-discovery scaffolds Core only (~10 files) with default tokens.
|
|
45
|
+
--discovery-payload <path> reads a JSON file with answers + tokens and
|
|
46
|
+
scaffolds Core + the derived specimens deterministically (this is the
|
|
47
|
+
path skill 'design-system' uses when shelling out from Claude Code).
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function runServe({ args, pkgRoot }) {
|
|
52
|
+
const forwarded = args.slice(args.indexOf('serve') + 1);
|
|
53
|
+
|
|
54
|
+
// Resolution order:
|
|
55
|
+
// 1. Side-channel from postinstall (cli/.platform-binary-path) — direct
|
|
56
|
+
// native exec, zero Node startup tax. DDR-015.
|
|
57
|
+
// 2. Bun + server.ts (local dev or postinstall-skipped install).
|
|
58
|
+
// 3. Legacy server.mjs on Node — last-resort fallback for boxes without
|
|
59
|
+
// bun. Should only fire mid-migration; removed in v1.0.
|
|
60
|
+
const sideChannel = resolve(pkgRoot, 'cli', '.platform-binary-path');
|
|
61
|
+
let binPath = null;
|
|
62
|
+
try {
|
|
63
|
+
const { readFileSync, existsSync } = await import('node:fs');
|
|
64
|
+
if (existsSync(sideChannel)) {
|
|
65
|
+
const candidate = readFileSync(sideChannel, 'utf8').trim();
|
|
66
|
+
if (candidate && existsSync(candidate)) binPath = candidate;
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
/* fall through */
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (binPath) {
|
|
73
|
+
const child = spawn(binPath, forwarded, { stdio: 'inherit', env: process.env });
|
|
74
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
75
|
+
child.on('error', (err) => {
|
|
76
|
+
process.stderr.write(`maude design serve (binary ${binPath}): ${err.message}\n`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const tsEntry = resolve(pkgRoot, 'plugins', 'design', 'dev-server', 'server.ts');
|
|
83
|
+
const mjsEntry = resolve(pkgRoot, 'plugins', 'design', 'dev-server', 'server.mjs');
|
|
84
|
+
|
|
85
|
+
const hasBun = await new Promise((res) => {
|
|
86
|
+
const probe = spawn('bun', ['--version'], { stdio: 'ignore' });
|
|
87
|
+
probe.on('error', () => res(false));
|
|
88
|
+
probe.on('exit', (code) => res(code === 0));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const child = hasBun
|
|
92
|
+
? spawn('bun', ['run', tsEntry, ...forwarded], { stdio: 'inherit', env: process.env })
|
|
93
|
+
: spawn(process.execPath, [mjsEntry, ...forwarded], { stdio: 'inherit', env: process.env });
|
|
94
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
95
|
+
child.on('error', (err) => {
|
|
96
|
+
process.stderr.write(`maude design serve: ${err.message}\n`);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function runInit({ args, pkgRoot }) {
|
|
102
|
+
const subArgs = args.slice(args.indexOf('init') + 1);
|
|
103
|
+
const { flags } = parseArgs(subArgs, {
|
|
104
|
+
booleans: ['force', 'dry-run', 'help', 'no-discovery'],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (flags.help) {
|
|
108
|
+
process.stdout.write(usage());
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const cwd = process.cwd();
|
|
113
|
+
const designDir = resolve(cwd, '.design');
|
|
114
|
+
const inspirationRoot = resolve(
|
|
115
|
+
pkgRoot,
|
|
116
|
+
'plugins',
|
|
117
|
+
'design',
|
|
118
|
+
'templates',
|
|
119
|
+
'design-system-inspiration'
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
if (!(await pathExists(inspirationRoot))) {
|
|
123
|
+
throw new Error(`inspiration library not found at ${inspirationRoot}. Reinstall maude.`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!flags['no-discovery'] && !flags['discovery-payload']) {
|
|
127
|
+
process.stderr.write(
|
|
128
|
+
`maude design init: interactive bootstrap requires Claude Code.
|
|
129
|
+
|
|
130
|
+
Inside Claude Code:
|
|
131
|
+
/design:setup-ds <name> — full discovery + scaffold (recommended)
|
|
132
|
+
/design:init — just prepare the env (no DS yet)
|
|
133
|
+
|
|
134
|
+
From the CLI (non-interactive only):
|
|
135
|
+
maude design init --no-discovery [--name <slug>]
|
|
136
|
+
scaffold Core only with default tokens
|
|
137
|
+
|
|
138
|
+
maude design init --discovery-payload <path>
|
|
139
|
+
read JSON answers + tokens, scaffold Core + derived specimens
|
|
140
|
+
`
|
|
141
|
+
);
|
|
142
|
+
process.exit(2);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const dsName = (flags.ds || 'project').trim();
|
|
146
|
+
if (!isValidSlug(dsName)) {
|
|
147
|
+
throw new Error(`invalid --ds "${dsName}" (must match ^[a-z][a-z0-9-]*$)`);
|
|
148
|
+
}
|
|
149
|
+
const projectName = (flags.name || basename(cwd)).trim();
|
|
150
|
+
if (!isValidName(projectName)) {
|
|
151
|
+
throw new Error(`invalid --name "${projectName}" (must match [a-z0-9._-]+)`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Refuse to scaffold over an existing DS unless --force.
|
|
155
|
+
const dsDir = resolve(designDir, 'system', dsName);
|
|
156
|
+
if ((await pathExists(dsDir)) && !flags.force) {
|
|
157
|
+
process.stderr.write(
|
|
158
|
+
`maude design init: ${dsDir} already exists. Pass --force to overwrite, or use a different --ds.\n`
|
|
159
|
+
);
|
|
160
|
+
process.exit(2);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Resolve the discovery payload.
|
|
164
|
+
const payload = flags['discovery-payload']
|
|
165
|
+
? await readPayload(flags['discovery-payload'])
|
|
166
|
+
: defaultPayload({ projectName, dsName });
|
|
167
|
+
|
|
168
|
+
process.stdout.write('maude design init\n');
|
|
169
|
+
process.stdout.write(` project name: ${projectName}\n`);
|
|
170
|
+
process.stdout.write(` ds name: ${dsName}\n`);
|
|
171
|
+
process.stdout.write(` scaffold target: ${designDir}\n`);
|
|
172
|
+
process.stdout.write(
|
|
173
|
+
` mode: ${flags['discovery-payload'] ? `--discovery-payload ${flags['discovery-payload']}` : '--no-discovery (Recommended defaults, Core only)'}\n`
|
|
174
|
+
);
|
|
175
|
+
if (flags['dry-run']) process.stdout.write(' mode: dry-run\n');
|
|
176
|
+
if (flags.force) process.stdout.write(' mode: force (overwrites)\n');
|
|
177
|
+
|
|
178
|
+
// Build explicit copy plan: [srcPath, destPath, transform?]
|
|
179
|
+
const plan = buildCorePlan({ inspirationRoot, designDir, dsName });
|
|
180
|
+
const previewFiles = await readdir(join(inspirationRoot, 'core', 'preview'));
|
|
181
|
+
for (const f of previewFiles) {
|
|
182
|
+
plan.push({
|
|
183
|
+
src: resolve(inspirationRoot, 'core', 'preview', f),
|
|
184
|
+
dest: resolve(designDir, 'system', dsName, 'preview', f),
|
|
185
|
+
transform: f.endsWith('.tpl') ? 'placeholder' : null,
|
|
186
|
+
stripTpl: f.endsWith('.tpl'),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const stats = { created: [], replaced: [], skipped: [] };
|
|
191
|
+
for (const item of plan) {
|
|
192
|
+
let destPath = item.dest;
|
|
193
|
+
if (item.stripTpl && destPath.endsWith('.tpl')) {
|
|
194
|
+
destPath = destPath.slice(0, -4);
|
|
195
|
+
}
|
|
196
|
+
const exists = await pathExists(destPath);
|
|
197
|
+
if (exists && !flags.force) {
|
|
198
|
+
stats.skipped.push(rel(designDir, destPath));
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const contents = await readFile(item.src, 'utf8');
|
|
202
|
+
const out =
|
|
203
|
+
item.transform === 'placeholder' ? substitutePlaceholders(contents, payload) : contents;
|
|
204
|
+
if (!flags['dry-run']) {
|
|
205
|
+
await mkdir(resolve(destPath, '..'), { recursive: true });
|
|
206
|
+
await writeFile(destPath, out);
|
|
207
|
+
}
|
|
208
|
+
if (exists) stats.replaced.push(rel(designDir, destPath));
|
|
209
|
+
else stats.created.push(rel(designDir, destPath));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
printSummary(stats);
|
|
213
|
+
printNextSteps({ dsName, payloadProvided: !!flags['discovery-payload'] });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function buildCorePlan({ inspirationRoot, designDir, dsName }) {
|
|
217
|
+
const src = (p) => resolve(inspirationRoot, 'core', p);
|
|
218
|
+
const dsRoot = resolve(designDir, 'system', dsName);
|
|
219
|
+
return [
|
|
220
|
+
{
|
|
221
|
+
src: src('README.orchestration.md.tpl'),
|
|
222
|
+
dest: resolve(designDir, 'README.md'),
|
|
223
|
+
transform: 'placeholder',
|
|
224
|
+
},
|
|
225
|
+
{ src: src('INDEX.md.tpl'), dest: resolve(designDir, 'INDEX.md'), transform: 'placeholder' },
|
|
226
|
+
{
|
|
227
|
+
src: src('config.json.tpl'),
|
|
228
|
+
dest: resolve(designDir, 'config.json'),
|
|
229
|
+
transform: 'placeholder',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
src: src('README.philosophy.md.tpl'),
|
|
233
|
+
dest: resolve(dsRoot, 'README.md'),
|
|
234
|
+
transform: 'placeholder',
|
|
235
|
+
},
|
|
236
|
+
{ src: src('SKILL.md.tpl'), dest: resolve(dsRoot, 'SKILL.md'), transform: 'placeholder' },
|
|
237
|
+
{
|
|
238
|
+
src: src('colors_and_type.css.tpl'),
|
|
239
|
+
dest: resolve(dsRoot, 'colors_and_type.css'),
|
|
240
|
+
transform: 'placeholder',
|
|
241
|
+
},
|
|
242
|
+
];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function rel(root, p) {
|
|
246
|
+
return p.startsWith(root) ? p.slice(root.length + 1) : p;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function substitutePlaceholders(contents, payload) {
|
|
250
|
+
let out = contents;
|
|
251
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
252
|
+
const token = new RegExp(`\\{\\{${escapeReg(key)}\\}\\}`, 'g');
|
|
253
|
+
out = out.replace(token, value);
|
|
254
|
+
}
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function escapeReg(s) {
|
|
259
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function defaultPayload({ projectName, dsName }) {
|
|
263
|
+
return {
|
|
264
|
+
project_name: projectName,
|
|
265
|
+
project_label: titleCase(projectName),
|
|
266
|
+
ds_dirname: dsName,
|
|
267
|
+
ds_skill_name: `${dsName}-design`,
|
|
268
|
+
ds_description: `Default design system for ${projectName}.`,
|
|
269
|
+
root_class: 'app',
|
|
270
|
+
theme_default: 'dark',
|
|
271
|
+
theme_extra: '',
|
|
272
|
+
handoff_targets: '[]',
|
|
273
|
+
active_families: JSON.stringify(['accent']),
|
|
274
|
+
active_families_csv: 'accent',
|
|
275
|
+
active_families_block: '- **accent** — the single accent family used for primary actions.',
|
|
276
|
+
purpose_one_liner: `${titleCase(projectName)} — design system.`,
|
|
277
|
+
audience_summary: 'general',
|
|
278
|
+
platforms_summary: 'desktop',
|
|
279
|
+
platforms_first: 'desktop',
|
|
280
|
+
platform_hard_rules: '',
|
|
281
|
+
content_tone: 'direct-terse',
|
|
282
|
+
mood_references_block: '_(not specified — extend during the next /design:setup-ds run)_',
|
|
283
|
+
type_scale_summary: '8-step ladder, 12–36px.',
|
|
284
|
+
voice_tone_block: 'Direct, terse. Action verbs. No marketing puffery.',
|
|
285
|
+
voice_tone_summary: 'direct-terse',
|
|
286
|
+
iconography_summary: 'Lucide, 1.5px stroke.',
|
|
287
|
+
hard_rules_from_system_readme: '_(see system/<ds>/README.md Hard rules section)_',
|
|
288
|
+
hard_rules_block:
|
|
289
|
+
'- WCAG 2.1 AA contrast\n- No off-token colors / radii / spacings\n- Real product strings only — no placeholder copy',
|
|
290
|
+
iso_timestamp: new Date().toISOString(),
|
|
291
|
+
// Token defaults (dark theme, neutral indigo accent)
|
|
292
|
+
bg_0_oklch: 'oklch(16% 0.012 245)',
|
|
293
|
+
bg_1_oklch: 'oklch(20% 0.014 245)',
|
|
294
|
+
bg_2_oklch: 'oklch(24% 0.014 245)',
|
|
295
|
+
bg_3_oklch: 'oklch(28% 0.013 245)',
|
|
296
|
+
bg_4_oklch: 'oklch(33% 0.013 245)',
|
|
297
|
+
fg_0_oklch: 'oklch(96% 0.008 245)',
|
|
298
|
+
fg_1_oklch: 'oklch(78% 0.012 245)',
|
|
299
|
+
fg_2_oklch: 'oklch(60% 0.012 245)',
|
|
300
|
+
fg_3_oklch: 'oklch(42% 0.010 245)',
|
|
301
|
+
accent_oklch: 'oklch(64% 0.18 264)',
|
|
302
|
+
accent_fg_oklch: 'oklch(98% 0.008 264)',
|
|
303
|
+
radius_xs: '4px',
|
|
304
|
+
radius_sm: '6px',
|
|
305
|
+
radius_md: '8px',
|
|
306
|
+
radius_lg: '12px',
|
|
307
|
+
radius_xl: '16px',
|
|
308
|
+
font_display: '"Inter", system-ui, sans-serif',
|
|
309
|
+
font_body: '"Inter", system-ui, sans-serif',
|
|
310
|
+
font_mono: '"JetBrains Mono", ui-monospace, monospace',
|
|
311
|
+
dur_flip: '140ms',
|
|
312
|
+
dur_panel: '220ms',
|
|
313
|
+
dur_route: '260ms',
|
|
314
|
+
dur_soft: '320ms',
|
|
315
|
+
// Empty-state template fields
|
|
316
|
+
empty_subject: 'items',
|
|
317
|
+
empty_supporting: "When you create your first one, it'll show up here.",
|
|
318
|
+
empty_cta: 'Create',
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function readPayload(p) {
|
|
323
|
+
const abs = resolve(process.cwd(), p);
|
|
324
|
+
try {
|
|
325
|
+
const raw = await readFile(abs, 'utf8');
|
|
326
|
+
return JSON.parse(raw);
|
|
327
|
+
} catch (err) {
|
|
328
|
+
throw new Error(`could not read --discovery-payload ${abs}: ${err.message}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function titleCase(s) {
|
|
333
|
+
return s
|
|
334
|
+
.split(/[-_\s]+/)
|
|
335
|
+
.filter(Boolean)
|
|
336
|
+
.map((w) => w[0].toUpperCase() + w.slice(1))
|
|
337
|
+
.join(' ');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function isValidName(s) {
|
|
341
|
+
return /^[a-z0-9._-]+$/i.test(s);
|
|
342
|
+
}
|
|
343
|
+
function isValidSlug(s) {
|
|
344
|
+
return /^[a-z][a-z0-9-]*$/.test(s);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
async function pathExists(p) {
|
|
348
|
+
try {
|
|
349
|
+
await stat(p);
|
|
350
|
+
return true;
|
|
351
|
+
} catch {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function printSummary({ created, replaced, skipped }) {
|
|
357
|
+
process.stdout.write(`\n ${created.length} created`);
|
|
358
|
+
if (replaced.length) process.stdout.write(`, ${replaced.length} replaced`);
|
|
359
|
+
if (skipped.length) process.stdout.write(`, ${skipped.length} skipped`);
|
|
360
|
+
process.stdout.write('\n');
|
|
361
|
+
if (process.env.MAUDE_DEBUG || process.env.MDCC_DEBUG) {
|
|
362
|
+
for (const c of created) process.stdout.write(` + ${c}\n`);
|
|
363
|
+
for (const r of replaced) process.stdout.write(` ~ ${r}\n`);
|
|
364
|
+
for (const s of skipped) process.stdout.write(` = ${s}\n`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function printNextSteps({ dsName, payloadProvided }) {
|
|
369
|
+
process.stdout.write('\nNext steps:\n');
|
|
370
|
+
if (!payloadProvided) {
|
|
371
|
+
process.stdout.write(
|
|
372
|
+
' This is the Core-only scaffold (~10 files) using Recommended defaults.\n'
|
|
373
|
+
);
|
|
374
|
+
process.stdout.write(' For audience-specific specimens, use Claude Code:\n');
|
|
375
|
+
process.stdout.write(` cd ${process.cwd()} && claude\n`);
|
|
376
|
+
process.stdout.write(
|
|
377
|
+
` /design:setup-ds ${dsName} "<one-line product brief>" — full 8-question discovery\n`
|
|
378
|
+
);
|
|
379
|
+
} else {
|
|
380
|
+
process.stdout.write(' Scaffold complete from --discovery-payload.\n');
|
|
381
|
+
}
|
|
382
|
+
process.stdout.write(
|
|
383
|
+
` Then: /design:edit "<feedback>" to iterate on a specimen, or /design:new "<Name>" "<brief>" --ds=${dsName} for a canvas.\n`
|
|
384
|
+
);
|
|
385
|
+
process.stdout.write(' Browse: maude design serve\n');
|
|
386
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export function run() {
|
|
2
|
+
const text = `maude — Maude CLI (legacy alias: mdcc)
|
|
3
|
+
|
|
4
|
+
USAGE
|
|
5
|
+
maude <command> [options]
|
|
6
|
+
|
|
7
|
+
COMMANDS
|
|
8
|
+
init [--name <project>] [--force] [--dry-run]
|
|
9
|
+
Scaffold the .ai/ second-brain workspace into the current repo from
|
|
10
|
+
the flow plugin skeleton. Idempotent — never overwrites existing
|
|
11
|
+
files unless --force. --name sets the project name in
|
|
12
|
+
workflows.config.json (defaults to the current directory basename).
|
|
13
|
+
Does NOT write CLAUDE.md — use Claude Code's built-in /init for that.
|
|
14
|
+
|
|
15
|
+
config show
|
|
16
|
+
config get <dotted.key>
|
|
17
|
+
config set <dotted.key> <value>
|
|
18
|
+
Read or write keys in .ai/workflows.config.json. Validates known keys
|
|
19
|
+
against the flow plugin's config.schema.json. Values that parse as
|
|
20
|
+
JSON (numbers, booleans, arrays, objects) are stored typed.
|
|
21
|
+
|
|
22
|
+
design serve [--port N] [--root PATH]
|
|
23
|
+
Start the design plugin's dev server in the current repo. Equivalent
|
|
24
|
+
to invoking 'claude-design-server'. Forwards all remaining args.
|
|
25
|
+
|
|
26
|
+
design init [--name <slug>] [--ds <name>] [--force] [--dry-run]
|
|
27
|
+
[--no-discovery | --discovery-payload <path>]
|
|
28
|
+
Non-interactive scaffold helper for the design plugin. Writes Core
|
|
29
|
+
files into .design/ using the design-system-inspiration library.
|
|
30
|
+
Refuses to run interactively — use Claude Code's /design:setup-ds for
|
|
31
|
+
full discovery. --no-discovery uses Recommended defaults; --discovery-
|
|
32
|
+
payload reads pre-computed answers from JSON.
|
|
33
|
+
|
|
34
|
+
help Print this help.
|
|
35
|
+
version Print the installed version.
|
|
36
|
+
|
|
37
|
+
EXAMPLES
|
|
38
|
+
maude init --name acme-app
|
|
39
|
+
maude config set platforms '["web-desktop","web-mobile"]'
|
|
40
|
+
maude config get motion.complex
|
|
41
|
+
maude design serve --port 4399
|
|
42
|
+
maude design init --no-discovery --name acme-app
|
|
43
|
+
|
|
44
|
+
NOTES
|
|
45
|
+
'maude init' does mechanical scaffolding of .ai/ only.
|
|
46
|
+
For interactive stack detection and workflows.config.json population,
|
|
47
|
+
run '/flow:init' inside Claude Code — it calls 'maude init' as
|
|
48
|
+
its first step. For CLAUDE.md, run Anthropic's built-in '/init'.
|
|
49
|
+
|
|
50
|
+
The legacy 'mdcc' alias still works (prints a deprecation warning).
|
|
51
|
+
It will be removed in v0.17.x.
|
|
52
|
+
|
|
53
|
+
DOCS
|
|
54
|
+
https://github.com/1aGh/maude
|
|
55
|
+
`;
|
|
56
|
+
process.stdout.write(text);
|
|
57
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { basename, resolve } from 'node:path';
|
|
3
|
+
import { parseArgs } from '../lib/argv.mjs';
|
|
4
|
+
import { copyTree } from '../lib/copy-tree.mjs';
|
|
5
|
+
|
|
6
|
+
const PLACEHOLDER = 'PROJECT_NAME';
|
|
7
|
+
// Files in the skeleton that contain the project-name placeholder and should
|
|
8
|
+
// be templated on copy.
|
|
9
|
+
const TEMPLATED = ['workflows.config.json', 'README.md', 'INDEX.md', 'release-guide.md'];
|
|
10
|
+
|
|
11
|
+
// Per-provider command substitutions for release-guide.md. Keys map to the
|
|
12
|
+
// `# CHANGELOG_PROVIDER_*_CMD` placeholders inside the skeleton's bash blocks.
|
|
13
|
+
// `null` = leave the placeholder + a "# TODO" comment in place.
|
|
14
|
+
const CHANGELOG_STUBS = {
|
|
15
|
+
changesets: {
|
|
16
|
+
VERSION:
|
|
17
|
+
'pnpm changeset version # bumps package.json versions + writes CHANGELOG.md from .changeset/*.md',
|
|
18
|
+
TAG: 'git tag "v$(jq -r .version package.json)" && git push --follow-tags',
|
|
19
|
+
PUBLISH:
|
|
20
|
+
'pnpm changeset publish # or: CI handles publish on tag — see .github/workflows/publish.yml',
|
|
21
|
+
},
|
|
22
|
+
'git-cliff': {
|
|
23
|
+
VERSION: 'git cliff --bump --tag --output CHANGELOG.md',
|
|
24
|
+
TAG: 'git push --follow-tags',
|
|
25
|
+
PUBLISH: '# TODO: fill in your publish command (npm publish / cargo publish / …)',
|
|
26
|
+
},
|
|
27
|
+
conventional: {
|
|
28
|
+
VERSION:
|
|
29
|
+
'npm version <major|minor|patch> # writes CHANGELOG.md if conventional-changelog wired',
|
|
30
|
+
TAG: 'git push --follow-tags',
|
|
31
|
+
PUBLISH: 'npm publish',
|
|
32
|
+
},
|
|
33
|
+
custom: null,
|
|
34
|
+
none: null,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const VALID_PROVIDERS = new Set(['changesets', 'git-cliff', 'conventional', 'custom', 'none']);
|
|
38
|
+
|
|
39
|
+
export async function run({ args, pkgRoot }) {
|
|
40
|
+
const { flags } = parseArgs(args, { booleans: ['force', 'dry-run', 'help'] });
|
|
41
|
+
if (flags.help) {
|
|
42
|
+
process.stdout.write(
|
|
43
|
+
'maude init [--name <project>] [--provider <changesets|git-cliff|conventional|custom|none>] [--force] [--dry-run]\n'
|
|
44
|
+
);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
const aiDir = resolve(cwd, '.ai');
|
|
50
|
+
const skeleton = resolve(pkgRoot, 'plugins', 'flow', 'templates', 'ai-skeleton');
|
|
51
|
+
const projectName = (flags.name || basename(cwd)).trim();
|
|
52
|
+
if (!isValidName(projectName)) {
|
|
53
|
+
throw new Error(`invalid --name "${projectName}" (must match [a-z0-9._-]+)`);
|
|
54
|
+
}
|
|
55
|
+
const provider = (flags.provider || 'none').trim();
|
|
56
|
+
if (!VALID_PROVIDERS.has(provider)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`invalid --provider "${provider}" (must be one of: ${[...VALID_PROVIDERS].join(', ')})`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const skeletonExists = await pathExists(skeleton);
|
|
63
|
+
if (!skeletonExists) {
|
|
64
|
+
throw new Error(`skeleton not found at ${skeleton}. Reinstall maude.`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
process.stdout.write('maude init\n');
|
|
68
|
+
process.stdout.write(` project name: ${projectName}\n`);
|
|
69
|
+
process.stdout.write(` scaffold target: ${aiDir}\n`);
|
|
70
|
+
process.stdout.write(` changelog provider: ${provider}\n`);
|
|
71
|
+
if (flags['dry-run']) process.stdout.write(' mode: dry-run\n');
|
|
72
|
+
if (flags.force) process.stdout.write(' mode: force (overwrites)\n');
|
|
73
|
+
|
|
74
|
+
const result = await copyTree(skeleton, aiDir, {
|
|
75
|
+
force: !!flags.force,
|
|
76
|
+
dryRun: !!flags['dry-run'],
|
|
77
|
+
transformMatch: (p) => TEMPLATED.some((t) => p.endsWith(t)),
|
|
78
|
+
transform: ({ srcPath, contents }) => {
|
|
79
|
+
let out = contents.replaceAll(PLACEHOLDER, projectName);
|
|
80
|
+
// workflows.config.json — also rewrite the relative schema path,
|
|
81
|
+
// since after install the schema lives in the published package's
|
|
82
|
+
// plugins/flow/.claude-plugin/ rather than at a fixed relative path
|
|
83
|
+
// from .ai/ in the user's repo.
|
|
84
|
+
if (srcPath.endsWith('workflows.config.json')) {
|
|
85
|
+
out = out.replace(
|
|
86
|
+
'"$schema": "../../plugins/flow/.claude-plugin/config.schema.json"',
|
|
87
|
+
'"$schema": "https://raw.githubusercontent.com/1aGh/maude/main/plugins/flow/.claude-plugin/config.schema.json"'
|
|
88
|
+
);
|
|
89
|
+
// Propagate --provider into integrations.changelog.provider so the
|
|
90
|
+
// first /flow:init run doesn't have to ask for what the user
|
|
91
|
+
// already told us at CLI time.
|
|
92
|
+
if (provider !== 'none') {
|
|
93
|
+
out = out.replace(
|
|
94
|
+
'"changelog": { "provider": "none" }',
|
|
95
|
+
`"changelog": { "provider": "${provider}" }`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// release-guide.md — swap in provider-specific bash for the version /
|
|
100
|
+
// tag / publish steps. `custom` / `none` leave the placeholders + TODO
|
|
101
|
+
// comments intact so the user fills them in by hand.
|
|
102
|
+
if (srcPath.endsWith('release-guide.md')) {
|
|
103
|
+
const stub = CHANGELOG_STUBS[provider];
|
|
104
|
+
if (stub) {
|
|
105
|
+
out = out
|
|
106
|
+
.replace('# CHANGELOG_PROVIDER_VERSION_CMD', stub.VERSION)
|
|
107
|
+
.replace('# CHANGELOG_PROVIDER_TAG_CMD', stub.TAG)
|
|
108
|
+
.replace('# CHANGELOG_PROVIDER_PUBLISH_CMD', stub.PUBLISH);
|
|
109
|
+
} else {
|
|
110
|
+
// custom / none — keep placeholders, append explicit TODO
|
|
111
|
+
out = out.replaceAll(
|
|
112
|
+
/# CHANGELOG_PROVIDER_(\w+)_CMD/g,
|
|
113
|
+
'# CHANGELOG_PROVIDER_$1_CMD\n# TODO: fill in for your project'
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Note: we do NOT scaffold CLAUDE.md here. That's the job of Claude Code's
|
|
122
|
+
// built-in `/init` command, which analyzes the codebase and writes a
|
|
123
|
+
// <200-line CLAUDE.md tailored to the project. `mdcc init` only owns
|
|
124
|
+
// .ai/ — the second-brain workspace. Legacy `mdcc init` alias still works.
|
|
125
|
+
|
|
126
|
+
const claudeMdExists =
|
|
127
|
+
(await pathExists(resolve(cwd, 'CLAUDE.md'))) ||
|
|
128
|
+
(await pathExists(resolve(cwd, '.claude', 'CLAUDE.md')));
|
|
129
|
+
|
|
130
|
+
printSummary(result);
|
|
131
|
+
printNextSteps(projectName, claudeMdExists);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isValidName(s) {
|
|
135
|
+
return /^[a-z0-9._-]+$/i.test(s);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function pathExists(p) {
|
|
139
|
+
try {
|
|
140
|
+
await stat(p);
|
|
141
|
+
return true;
|
|
142
|
+
} catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function printSummary({ created, replaced, skipped }) {
|
|
148
|
+
process.stdout.write(`\n ${created.length} created`);
|
|
149
|
+
if (replaced.length) process.stdout.write(`, ${replaced.length} replaced`);
|
|
150
|
+
if (skipped.length) process.stdout.write(`, ${skipped.length} skipped`);
|
|
151
|
+
process.stdout.write('\n');
|
|
152
|
+
if (process.env.MAUDE_DEBUG || process.env.MDCC_DEBUG) {
|
|
153
|
+
for (const c of created) process.stdout.write(` + ${c}\n`);
|
|
154
|
+
for (const r of replaced) process.stdout.write(` ~ ${r}\n`);
|
|
155
|
+
for (const s of skipped) process.stdout.write(` = ${s}\n`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function printNextSteps(name, claudeMdExists) {
|
|
160
|
+
process.stdout.write('\nNext steps:\n');
|
|
161
|
+
process.stdout.write(' 1. In Claude Code: /plugin marketplace add 1aGh/maude\n');
|
|
162
|
+
process.stdout.write(' /plugin install flow@maude\n');
|
|
163
|
+
if (!claudeMdExists) {
|
|
164
|
+
process.stdout.write(' 2. /init — generate a CLAUDE.md tailored to your codebase\n');
|
|
165
|
+
process.stdout.write(
|
|
166
|
+
` (Anthropic's built-in command — analyzes stack, writes <200 lines).\n`
|
|
167
|
+
);
|
|
168
|
+
process.stdout.write(' 3. /flow:init — populates .ai/workflows.config.json with detected\n');
|
|
169
|
+
process.stdout.write(' stack (platforms, tracker, language, …).\n');
|
|
170
|
+
} else {
|
|
171
|
+
process.stdout.write(' 2. /flow:init — populates .ai/workflows.config.json with detected\n');
|
|
172
|
+
process.stdout.write(
|
|
173
|
+
' stack. CLAUDE.md already exists; /init would suggest improvements.\n'
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
process.stdout.write(` 4. Create .ai/${name}-prd.md with your product brief.\n`);
|
|
177
|
+
process.stdout.write(' 5. /flow:status to see where you are; /flow:plan to start work.\n');
|
|
178
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
export async function run({ pkgRoot }) {
|
|
5
|
+
const pkg = JSON.parse(await readFile(resolve(pkgRoot, 'package.json'), 'utf8'));
|
|
6
|
+
process.stdout.write(`maude ${pkg.version} (${pkg.name})\n`);
|
|
7
|
+
}
|