@1agh/maude 0.19.1 → 0.21.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 (105) hide show
  1. package/README.md +7 -0
  2. package/cli/bin/maude.mjs +5 -1
  3. package/cli/commands/design-link.test.mjs +207 -0
  4. package/cli/commands/design.mjs +42 -12
  5. package/cli/commands/doctor.mjs +350 -0
  6. package/cli/commands/doctor.test.mjs +185 -0
  7. package/cli/commands/help.mjs +24 -0
  8. package/cli/commands/hub.mjs +231 -0
  9. package/cli/commands/hub.test.mjs +87 -0
  10. package/cli/lib/config-lint.mjs +141 -0
  11. package/cli/lib/config-lint.test.mjs +117 -0
  12. package/cli/lib/design-link.mjs +216 -0
  13. package/cli/lib/hubs-config.mjs +123 -0
  14. package/cli/lib/hubs-config.test.mjs +100 -0
  15. package/cli/lib/preflight.mjs +232 -0
  16. package/cli/lib/stack-detect.mjs +344 -0
  17. package/cli/lib/stack-detect.test.mjs +121 -0
  18. package/package.json +17 -9
  19. package/plugins/design/dependencies.json +147 -0
  20. package/plugins/design/dependencies.schema.json +107 -0
  21. package/plugins/design/dev-server/ai-banner.tsx +188 -0
  22. package/plugins/design/dev-server/annotations-context-toolbar.tsx +115 -41
  23. package/plugins/design/dev-server/annotations-layer.tsx +256 -107
  24. package/plugins/design/dev-server/api.ts +17 -1
  25. package/plugins/design/dev-server/artboard-marquee.tsx +10 -6
  26. package/plugins/design/dev-server/bin/asset-sweep.sh +180 -0
  27. package/plugins/design/dev-server/bin/preflight.sh +32 -0
  28. package/plugins/design/dev-server/bin/runtime-health.sh +169 -0
  29. package/plugins/design/dev-server/bin/visual-sanity.sh +221 -0
  30. package/plugins/design/dev-server/canvas-lib.tsx +534 -32
  31. package/plugins/design/dev-server/canvas-shell.tsx +479 -29
  32. package/plugins/design/dev-server/client/app.jsx +72 -0
  33. package/plugins/design/dev-server/client/hmr.mjs +28 -0
  34. package/plugins/design/dev-server/collab/ai-activity.ts +127 -0
  35. package/plugins/design/dev-server/collab/git-lifecycle.ts +124 -0
  36. package/plugins/design/dev-server/collab/index.ts +47 -0
  37. package/plugins/design/dev-server/collab/persistence.ts +123 -0
  38. package/plugins/design/dev-server/collab/protocol.ts +108 -0
  39. package/plugins/design/dev-server/collab/registry.ts +110 -0
  40. package/plugins/design/dev-server/collab/room.ts +215 -0
  41. package/plugins/design/dev-server/commands/annotation-strokes-command.ts +127 -0
  42. package/plugins/design/dev-server/commands/equal-spacing-command.ts +28 -0
  43. package/plugins/design/dev-server/commands/move-artboards-command.ts +158 -0
  44. package/plugins/design/dev-server/comments-overlay.tsx +41 -4
  45. package/plugins/design/dev-server/contextual-toolbar.tsx +241 -0
  46. package/plugins/design/dev-server/cursors-overlay.tsx +296 -0
  47. package/plugins/design/dev-server/dist/client.bundle.js +75 -3
  48. package/plugins/design/dev-server/dist/runtime/motion.js +165 -0
  49. package/plugins/design/dev-server/dist/runtime/motion_react.js +409 -0
  50. package/plugins/design/dev-server/dist/runtime/y-protocols_awareness.js +587 -0
  51. package/plugins/design/dev-server/dist/runtime/y-protocols_sync.js +257 -0
  52. package/plugins/design/dev-server/dist/runtime/yjs.js +7107 -0
  53. package/plugins/design/dev-server/equal-spacing-detector.ts +98 -0
  54. package/plugins/design/dev-server/equal-spacing-handles.tsx +289 -0
  55. package/plugins/design/dev-server/export-dialog.tsx +1 -1
  56. package/plugins/design/dev-server/handoff.ts +24 -0
  57. package/plugins/design/dev-server/hmr-broadcast.ts +15 -2
  58. package/plugins/design/dev-server/http.ts +91 -1
  59. package/plugins/design/dev-server/input-router.tsx +52 -2
  60. package/plugins/design/dev-server/marquee-overlay.tsx +282 -0
  61. package/plugins/design/dev-server/participants-chrome.tsx +261 -0
  62. package/plugins/design/dev-server/runtime-bundle.ts +15 -0
  63. package/plugins/design/dev-server/server.ts +78 -11
  64. package/plugins/design/dev-server/test/ai-activity.test.ts +113 -0
  65. package/plugins/design/dev-server/test/annotation-strokes-command.test.ts +149 -0
  66. package/plugins/design/dev-server/test/annotations-layer.test.ts +44 -0
  67. package/plugins/design/dev-server/test/canvas-lib-motion.test.ts +131 -0
  68. package/plugins/design/dev-server/test/collab-annotations-bridge.test.ts +55 -0
  69. package/plugins/design/dev-server/test/collab-bridge.test.ts +81 -0
  70. package/plugins/design/dev-server/test/collab-loopback.test.ts +63 -0
  71. package/plugins/design/dev-server/test/collab-protocol.test.ts +146 -0
  72. package/plugins/design/dev-server/test/collab-room.test.ts +182 -0
  73. package/plugins/design/dev-server/test/collab-stress.test.ts +121 -0
  74. package/plugins/design/dev-server/test/equal-spacing-detector.test.ts +93 -0
  75. package/plugins/design/dev-server/test/git-lifecycle.test.ts +101 -0
  76. package/plugins/design/dev-server/test/input-router.test.ts +87 -1
  77. package/plugins/design/dev-server/test/marquee-overlay.test.ts +94 -0
  78. package/plugins/design/dev-server/test/move-artboards-command.test.ts +108 -0
  79. package/plugins/design/dev-server/test/participants-chrome.test.ts +30 -0
  80. package/plugins/design/dev-server/test/undo-stack.test.ts +211 -0
  81. package/plugins/design/dev-server/test/use-collab.test.ts +71 -0
  82. package/plugins/design/dev-server/test/use-cursor-modifiers.test.ts +59 -0
  83. package/plugins/design/dev-server/test/use-keyboard-discipline.test.ts +27 -0
  84. package/plugins/design/dev-server/test/use-undo-stack.test.tsx +193 -0
  85. package/plugins/design/dev-server/tool-palette.tsx +7 -7
  86. package/plugins/design/dev-server/undo-hud.tsx +95 -0
  87. package/plugins/design/dev-server/undo-stack.ts +240 -0
  88. package/plugins/design/dev-server/use-annotation-resize.tsx +1 -1
  89. package/plugins/design/dev-server/use-artboard-drag.tsx +6 -3
  90. package/plugins/design/dev-server/use-collab.tsx +478 -0
  91. package/plugins/design/dev-server/use-cursor-modifiers.tsx +122 -0
  92. package/plugins/design/dev-server/use-keyboard-discipline.tsx +125 -0
  93. package/plugins/design/dev-server/use-undo-stack.tsx +355 -0
  94. package/plugins/design/dev-server/ws.ts +123 -7
  95. package/plugins/design/templates/_shell.html +51 -6
  96. package/plugins/design/templates/design-system-inspiration/SUB-AGENT-PROMPTS.md +245 -0
  97. package/plugins/design/templates/design-system-inspiration/_MAPPING.md +2 -2
  98. package/plugins/design/templates/design-system-inspiration/core/preview/_components.css.tpl +129 -0
  99. package/plugins/design/templates/design-system-inspiration/core/preview/_motion-readme.md.tpl +63 -0
  100. package/plugins/design/templates/design-system-inspiration/core/preview/motion.css.tpl +106 -0
  101. package/plugins/design/templates/design-system-inspiration/core/preview/motion.tsx.tpl +208 -0
  102. package/plugins/flow/.claude-plugin/config.schema.json +12 -0
  103. package/plugins/flow/dependencies.json +143 -0
  104. package/plugins/flow/dependencies.schema.json +107 -0
  105. /package/plugins/design/templates/design-system-inspiration/core/preview/{motion.html → .archive/motion.html} +0 -0
@@ -0,0 +1,208 @@
1
+ /**
2
+ * @canvas motion — motion vocabulary (Phase 3.7 / DDR-049 playground).
3
+ * 8 role tiles looping on first paint, 4 token-derived playback
4
+ * chips, 2 easing-curve SVGs derived from token cubic-bezier
5
+ * control points. Reduced-motion toggle for in-browser
6
+ * inspection without OS settings.
7
+ * @ds {{ds_dirname}}
8
+ * @platform desktop
9
+ * @opt_out none
10
+ * @artboards primary
11
+ * @brief MDCC-DSN/01.motion / {{project_label}}
12
+ * @stack React 19 · TSX · Bun.build · css_mode=inline
13
+ * @history .design/_history/motion/
14
+ * @handoff bunx shadcn add file://./motion.registry.json
15
+ *
16
+ * SPECIMEN: motion
17
+ * DEMONSTRATES: --dur-flip · --dur-panel · --dur-route · --dur-soft ·
18
+ * --ease-out · --ease-in-out · prefers-reduced-motion guard ·
19
+ * <MotionDemo role> 8-role vocabulary · TokenPlayback chips
20
+ * COMPOSITION: 8 role tiles looping always · 4 token chips · 2 curve SVGs ·
21
+ * reduced-motion toggle · inline a11y note
22
+ * COPY VOICE: role-named ("Flip", "Panel slide", "Route enter", ...)
23
+ * WHEN SCAFFOLDED: always (Core, gated on motion ∈ activeFamilies which is
24
+ * default-on)
25
+ *
26
+ * BOUNDED GEOMETRY (ANIMATION SAFETY, SUB-AGENT-PROMPTS.md):
27
+ * Every <MotionDemo> root has overflow: hidden inline (set in canvas-lib).
28
+ * Sparkle / pulse / twinkle keyframes (scale 0→1→0) are demonstrated ONLY
29
+ * on the 32×32 sparkle chip inside the "presence" tile — NEVER on the full
30
+ * tile. The bounding box of a rotating element extends √2× at 45°; tile
31
+ * chrome would overflow without the explicit clip.
32
+ *
33
+ * REDUCED-MOTION:
34
+ * <ReducedMotionToggle/> on the chrome row flips data-reduced-motion="true"
35
+ * on <html>. The motion specimen is the documented exception to the
36
+ * OS-level prefers-reduced-motion contract — reviewers need both branches
37
+ * visible side-by-side. <MotionDemo> programmatically short-circuits its
38
+ * animate prop when useReducedMotion() returns true (the contract is
39
+ * enforced in two places: CSS --dur-*: 1ms collapse + JS short-circuit).
40
+ */
41
+ import "../colors_and_type.css";
42
+ import "./_layout.css";
43
+ import "./motion.css";
44
+ import {
45
+ MotionDemo,
46
+ MotionTrack,
47
+ TokenPlayback,
48
+ ReducedMotionToggle,
49
+ useMotionTokens,
50
+ } from "@maude/canvas-lib";
51
+
52
+ export default function Motion() {
53
+ return (
54
+ <>
55
+ <header className="specimen-hd">
56
+ <span className="sku">MDCC-DSN/01.motion</span>
57
+ <span className="crumbs">{{project_label}} · motion vocabulary · 8 roles · 4 tokens</span>
58
+ <span className="theme-toggle-slot">
59
+ <ReducedMotionToggle />
60
+ </span>
61
+ </header>
62
+
63
+ <main className="specimen">
64
+ <section className="specimen-title">
65
+ <h1>Motion</h1>
66
+ <p className="lede">
67
+ Eight roles. Four durations × two eases. Every animation in the
68
+ system maps to one role; <code>&lt;MotionDemo role="…"&gt;</code>{" "}
69
+ from <code>@maude/canvas-lib</code> is the only legal authoring
70
+ surface (CSS-only escape hatch via <code>.motion-*</code> classes).
71
+ Roles loop on first paint — hover not required.
72
+ </p>
73
+ </section>
74
+
75
+ <section className="motion-roles">
76
+ <h2>Roles</h2>
77
+ <div className="motion-grid">
78
+ <RoleTile name="Flip" role="flip" token="--dur-flip" ease="--ease-out" note="Press-down, hover lift, single-card flip." />
79
+ <RoleTile name="Panel slide" role="panel" token="--dur-panel" ease="--ease-in-out" note="Drawer / sidebar / segmented." />
80
+ <RoleTile name="Route enter" role="route" token="--dur-route" ease="--ease-out" note="Page transition. Opacity + tiny scale." />
81
+ <RoleTile name="Soft fade" role="soft" token="--dur-soft" ease="--ease-out" note="Toast, tooltip, soft reveal." />
82
+ <RoleTile name="Spring snap" role="spring" token="--dur-panel" ease="spring" note="Use only when brief asks for tactile/playful." />
83
+ <RoleTile name="Scroll link" role="scroll" token="--dur-route" ease="--ease-in-out" note="Scroll-progress-bound entry." />
84
+ <RoleTile name="Drag spring" role="drag" token="--dur-flip" ease="--ease-out" note="Pick up + release rotational settle." />
85
+ <RoleTile name="Presence" role="presence" token="--dur-soft" ease="--ease-out" sparkle note="Sparkle demo — 32×32 chip ONLY." />
86
+ </div>
87
+ </section>
88
+
89
+ <section className="motion-tokens">
90
+ <h2>Token playback (click to replay)</h2>
91
+ <p className="lede">
92
+ Each chip fires its token verbatim once. The numeric ms value
93
+ is the live <code>getComputedStyle</code> read, so token edits to{" "}
94
+ <code>colors_and_type.css</code> reflect here without a rebuild.
95
+ </p>
96
+ <MotionTrack>
97
+ <TokenPlayback duration="--dur-flip" easing="--ease-out" label="--dur-flip" />
98
+ <TokenPlayback duration="--dur-soft" easing="--ease-out" label="--dur-soft" />
99
+ <TokenPlayback duration="--dur-panel" easing="--ease-in-out" label="--dur-panel" />
100
+ <TokenPlayback duration="--dur-route" easing="--ease-out" label="--dur-route" />
101
+ </MotionTrack>
102
+ </section>
103
+
104
+ <section className="motion-curves">
105
+ <h2>Easing curves</h2>
106
+ <p className="lede">
107
+ Both curves derived from the token's live{" "}
108
+ <code>cubic-bezier(x1, y1, x2, y2)</code> value — not hand-drawn.
109
+ Edit the token in <code>colors_and_type.css</code>; the curve
110
+ redraws.
111
+ </p>
112
+ <div className="motion-curves__row">
113
+ <EasingCurve label="--ease-out" cssVar="--ease-out" />
114
+ <EasingCurve label="--ease-in-out" cssVar="--ease-in-out" />
115
+ </div>
116
+ </section>
117
+
118
+ <section className="motion-a11y">
119
+ <h2>Reduced motion</h2>
120
+ <p className="lede">
121
+ OS-level <code>@media (prefers-reduced-motion: reduce)</code>{" "}
122
+ collapses every <code>--dur-*</code> to <code>1ms</code> at the CSS
123
+ layer. <code>&lt;MotionDemo&gt;</code> additionally short-circuits
124
+ its <code>animate</code> prop via{" "}
125
+ <code>useReducedMotion()</code> from <code>motion/react</code>{" "}
126
+ (belt + suspenders — the a11y invariant deserves both). The toggle
127
+ on the chrome row above flips{" "}
128
+ <code>data-reduced-motion="true"</code> on <code>&lt;html&gt;</code>{" "}
129
+ for in-browser inspection without OS settings; specimen chrome is
130
+ the documented exception to OS-level honor.
131
+ </p>
132
+ </section>
133
+ </main>
134
+ </>
135
+ );
136
+ }
137
+
138
+ interface RoleTileProps {
139
+ name: string;
140
+ role:
141
+ | "flip"
142
+ | "panel"
143
+ | "route"
144
+ | "soft"
145
+ | "spring"
146
+ | "scroll"
147
+ | "drag"
148
+ | "presence";
149
+ token: string;
150
+ ease: string;
151
+ note: string;
152
+ sparkle?: boolean;
153
+ }
154
+
155
+ function RoleTile({ name, role, token, ease, note, sparkle = false }: RoleTileProps) {
156
+ return (
157
+ <div className="motion-card">
158
+ <strong>{name}</strong>
159
+ <div className="motion-card__stage">
160
+ <MotionDemo role={role} loop="always" small={sparkle} label={`${role} demo`} />
161
+ </div>
162
+ <code className="motion-card__tokens">
163
+ {token} · {ease}
164
+ </code>
165
+ <span className="motion-card__note">{note}</span>
166
+ </div>
167
+ );
168
+ }
169
+
170
+ /**
171
+ * Derives a Bezier path from a CSS easing token's live cubic-bezier(x1, y1,
172
+ * x2, y2) value. Falls back to a sane default when the token isn't readable
173
+ * (SSR, detached). The path is fitted to a 100×100 viewBox; y-axis is
174
+ * flipped so progress goes bottom-left to top-right the way curves are read
175
+ * in editor previews.
176
+ */
177
+ function EasingCurve({ label, cssVar }: { label: string; cssVar: string }) {
178
+ const tokens = useMotionTokens();
179
+ const live = tokens.easings[cssVar] ?? "";
180
+ const match = live.match(/cubic-bezier\(([^)]+)\)/);
181
+ const [x1, y1, x2, y2] = match
182
+ ? match[1].split(",").map((s) => parseFloat(s.trim()))
183
+ : cssVar === "--ease-in-out"
184
+ ? [0.4, 0, 0.2, 1]
185
+ : [0, 0, 0.2, 1];
186
+ const path = `M 0 100 C ${x1 * 100} ${100 - y1 * 100} ${x2 * 100} ${100 - y2 * 100} 100 0`;
187
+ return (
188
+ <figure className="motion-curve">
189
+ <svg viewBox="0 0 100 100" width="120" height="120" aria-hidden="true">
190
+ <rect x="0" y="0" width="100" height="100" fill="var(--bg-1)" />
191
+ <path
192
+ d="M 0 100 L 100 100 M 0 100 L 0 0"
193
+ stroke="var(--border-default, currentColor)"
194
+ strokeWidth="1"
195
+ fill="none"
196
+ opacity="0.4"
197
+ />
198
+ <path d={path} stroke="var(--accent)" strokeWidth="2" fill="none" />
199
+ </svg>
200
+ <figcaption>
201
+ <code>{label}</code>
202
+ <span className="motion-curve__values">
203
+ {x1.toFixed(2)}, {y1.toFixed(2)}, {x2.toFixed(2)}, {y2.toFixed(2)}
204
+ </span>
205
+ </figcaption>
206
+ </figure>
207
+ );
208
+ }
@@ -6,6 +6,10 @@
6
6
  "additionalProperties": false,
7
7
  "required": ["name"],
8
8
  "properties": {
9
+ "$schema": {
10
+ "type": "string",
11
+ "description": "Pointer to this schema (editor support). Stripped at consumption time."
12
+ },
9
13
  "name": {
10
14
  "type": "string",
11
15
  "description": "Short project / product name. Resolves the `<project>` placeholder in commands and file paths (e.g. `.ai/<project>-prd.md` → `.ai/<name>-prd.md`)."
@@ -304,6 +308,14 @@
304
308
  }
305
309
  }
306
310
  },
311
+ "quality": {
312
+ "type": "object",
313
+ "description": "Map of gate name → shell command string. Gate names are free-form (conventional names: `lint`, `format`, `typecheck`, `tests`, `build`). Each command is executed as-is via `eval` by the slash command that consumes the gate. Missing gate → slash command emits a one-line warning and skips (never fabricates a command). v1 deliberately keeps this a flat string map — no per-gate object shape, no `order`, no `scope`. Populate via `maude doctor --fix`, which detects from `package.json` scripts + tool presence. Existing user values are never overwritten — additions only.",
314
+ "additionalProperties": {
315
+ "type": "string",
316
+ "minLength": 1
317
+ }
318
+ },
307
319
  "integrations": {
308
320
  "type": "object",
309
321
  "additionalProperties": false,
@@ -0,0 +1,143 @@
1
+ {
2
+ "$schema": "./dependencies.schema.json",
3
+ "version": "1",
4
+ "plugin": "flow",
5
+ "dependencies": [
6
+ {
7
+ "id": "node",
8
+ "type": "cli",
9
+ "hardness": "hard",
10
+ "check": {
11
+ "command": "node --version",
12
+ "expectExit": 0,
13
+ "minVersion": "20.0.0"
14
+ },
15
+ "install": {
16
+ "preferred": "https://nodejs.org/en/download",
17
+ "darwin": "brew install node@22"
18
+ },
19
+ "autoInstall": false,
20
+ "usedBy": ["commands/init.md"],
21
+ "docsUrl": "https://nodejs.org"
22
+ },
23
+ {
24
+ "id": "git",
25
+ "type": "cli",
26
+ "hardness": "hard",
27
+ "check": {
28
+ "command": "git --version",
29
+ "expectExit": 0
30
+ },
31
+ "install": {
32
+ "darwin": "brew install git",
33
+ "linux": "apt-get install -y git || dnf install -y git"
34
+ },
35
+ "autoInstall": false,
36
+ "usedBy": ["commands/init.md", "commands/done.md", "commands/quick.md"],
37
+ "docsUrl": "https://git-scm.com"
38
+ },
39
+ {
40
+ "id": "maude",
41
+ "type": "cli",
42
+ "hardness": "soft",
43
+ "check": {
44
+ "command": "maude --version",
45
+ "expectExit": 0
46
+ },
47
+ "install": {
48
+ "preferred": "npm i -g @1agh/maude"
49
+ },
50
+ "autoInstall": false,
51
+ "fallbackBehavior": "/flow:init and /flow:done work without maude CLI but cannot read/write workflows.config.json via `maude config`.",
52
+ "usedBy": ["commands/init.md"],
53
+ "docsUrl": "https://github.com/1aGh/maude"
54
+ },
55
+ {
56
+ "id": "agent-browser",
57
+ "type": "cli",
58
+ "hardness": "soft",
59
+ "check": {
60
+ "command": "agent-browser --version",
61
+ "expectExit": 0
62
+ },
63
+ "install": {
64
+ "preferred": "npm i -g @anthropic-ai/agent-browser"
65
+ },
66
+ "autoInstall": true,
67
+ "fallbackBehavior": "/flow:scenario and a11y-auditor degrade to screenshot-less reports. Web scenarios cannot run.",
68
+ "usedBy": [
69
+ "commands/scenario.md",
70
+ "commands/validate.md",
71
+ "commands/utils-verify.md",
72
+ "agents/scenario-runner.md",
73
+ "agents/a11y-auditor.md",
74
+ "skills/agent-browser/SKILL.md"
75
+ ],
76
+ "docsUrl": "https://github.com/anthropics/agent-browser"
77
+ },
78
+ {
79
+ "id": "agent-device",
80
+ "type": "cli",
81
+ "hardness": "soft",
82
+ "check": {
83
+ "command": "agent-device --version",
84
+ "expectExit": 0
85
+ },
86
+ "install": {
87
+ "preferred": "Requires Xcode + Android SDK. See agent-device docs."
88
+ },
89
+ "autoInstall": false,
90
+ "fallbackBehavior": "/flow:scenario skips native (iOS/Android) variants. Web variants still run via agent-browser.",
91
+ "usedBy": [
92
+ "commands/scenario.md",
93
+ "agents/scenario-runner.md",
94
+ "skills/agent-device/SKILL.md"
95
+ ],
96
+ "docsUrl": "https://github.com/anthropics/agent-device"
97
+ },
98
+ {
99
+ "id": "jq",
100
+ "type": "system-tool",
101
+ "hardness": "soft",
102
+ "check": {
103
+ "command": "jq --version",
104
+ "expectExit": 0
105
+ },
106
+ "install": {
107
+ "darwin": "brew install jq",
108
+ "linux": "apt-get install -y jq || dnf install -y jq",
109
+ "win32": "winget install jqlang.jq"
110
+ },
111
+ "autoInstall": false,
112
+ "fallbackBehavior": "Slash commands' bash blocks that read .ai/workflows.config.json via jq cannot run. /flow:validate and /flow:utils-verify quality gates need this.",
113
+ "usedBy": [
114
+ "commands/validate.md",
115
+ "commands/utils-verify.md",
116
+ "commands/quick.md",
117
+ "commands/done.md"
118
+ ]
119
+ },
120
+ {
121
+ "id": "askuserquestion-mcp",
122
+ "type": "mcp",
123
+ "hardness": "soft",
124
+ "check": {
125
+ "mcp": "AskUserQuestion",
126
+ "tool": "ask"
127
+ },
128
+ "fallbackBehavior": "Question prompts fall back to numbered-prose chat. No multi-select UI.",
129
+ "usedBy": ["skills/question-protocol/SKILL.md"]
130
+ },
131
+ {
132
+ "id": "terminal-skills-mcp",
133
+ "type": "mcp",
134
+ "hardness": "soft",
135
+ "check": {
136
+ "mcp": "terminal-skills",
137
+ "tool": "search_skills"
138
+ },
139
+ "fallbackBehavior": "skill-loader falls back to built-in plugin skills → matching agents → WebFetch on library docs.",
140
+ "usedBy": ["skills/skill-loader/SKILL.md"]
141
+ }
142
+ ]
143
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "maude plugin — runtime dependency manifest",
4
+ "description": "Declares CLI binaries, MCP servers, and runtime packages the plugin's commands / agents / skills shell out to. Consumed by maude doctor (cli/commands/doctor.mjs) and preflight.sh / preflight.mjs. Schema is shared between plugins — each plugin ships its own dependencies.json + (symlink to) this schema.",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["version", "plugin", "dependencies"],
8
+ "properties": {
9
+ "version": {
10
+ "type": "string",
11
+ "const": "1",
12
+ "description": "Manifest schema version. Bumped when the dependency entry shape changes incompatibly."
13
+ },
14
+ "plugin": {
15
+ "type": "string",
16
+ "minLength": 1,
17
+ "description": "Plugin name (matches plugins/<plugin>/.claude-plugin/plugin.json `name`)."
18
+ },
19
+ "dependencies": {
20
+ "type": "array",
21
+ "minItems": 0,
22
+ "items": { "$ref": "#/$defs/Dependency" }
23
+ }
24
+ },
25
+ "$defs": {
26
+ "Dependency": {
27
+ "type": "object",
28
+ "additionalProperties": false,
29
+ "required": ["id", "type", "hardness", "check"],
30
+ "properties": {
31
+ "id": {
32
+ "type": "string",
33
+ "pattern": "^[a-z0-9][a-z0-9._-]*$",
34
+ "description": "Unique identifier within the manifest. Lowercase, hyphenated."
35
+ },
36
+ "type": {
37
+ "type": "string",
38
+ "enum": ["cli", "mcp", "node-package", "bun-package", "system-tool"],
39
+ "description": "What kind of dependency. `cli` = on PATH; `mcp` = MCP server / tool; `node-package` / `bun-package` = installed via npm/bun; `system-tool` = OS-provided (curl, jq)."
40
+ },
41
+ "hardness": {
42
+ "type": "string",
43
+ "enum": ["hard", "soft"],
44
+ "description": "`hard` = missing blocks plugin use; `soft` = graceful degradation possible (fallback path, warning only)."
45
+ },
46
+ "check": {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "description": "How to detect presence. For CLI/system-tool/package: shell command + expected exit. For MCP: tool name to probe.",
50
+ "properties": {
51
+ "command": {
52
+ "type": "string",
53
+ "description": "Shell command executed via `bash -c`. Pipes allowed. Defaults to `<id> --version`."
54
+ },
55
+ "expectExit": {
56
+ "type": "integer",
57
+ "default": 0,
58
+ "description": "Expected exit code. Anything else = missing/broken."
59
+ },
60
+ "minVersion": {
61
+ "type": "string",
62
+ "description": "Minimum semver. Comparator extracts `vX.Y.Z` from check.command stdout."
63
+ },
64
+ "mcp": {
65
+ "type": "string",
66
+ "description": "MCP server name. For type=mcp only."
67
+ },
68
+ "tool": {
69
+ "type": "string",
70
+ "description": "Specific tool name on the MCP server. For type=mcp only."
71
+ }
72
+ }
73
+ },
74
+ "install": {
75
+ "type": "object",
76
+ "additionalProperties": false,
77
+ "description": "Install commands per platform. `preferred` is OS-agnostic / fallback; per-platform keys override.",
78
+ "properties": {
79
+ "preferred": { "type": "string" },
80
+ "darwin": { "type": "string" },
81
+ "linux": { "type": "string" },
82
+ "win32": { "type": "string" }
83
+ }
84
+ },
85
+ "autoInstall": {
86
+ "type": "boolean",
87
+ "default": false,
88
+ "description": "If true, `maude doctor --fix` may run install.preferred after per-dep confirmation prompt."
89
+ },
90
+ "fallbackBehavior": {
91
+ "type": "string",
92
+ "description": "What the plugin does when this soft dep is missing. Human-readable; surfaces in maude doctor's report."
93
+ },
94
+ "usedBy": {
95
+ "type": "array",
96
+ "items": { "type": "string" },
97
+ "description": "Repo-relative paths (or path globs) of plugin files that reference this dependency. Aids debugging — doctor surfaces this when explaining a miss."
98
+ },
99
+ "docsUrl": {
100
+ "type": "string",
101
+ "format": "uri",
102
+ "description": "Where to read more."
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }