@design-ai/cli 4.55.0 → 4.56.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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +39 -0
- package/README.ko.md +7 -7
- package/README.md +9 -9
- package/cli/lib/mcp-server.mjs +208 -10
- package/cli/lib/site-analysis.mjs +297 -0
- package/cli/lib/site-args.mjs +433 -0
- package/cli/lib/site-bundle-build.mjs +127 -0
- package/cli/lib/site-bundle-check.mjs +454 -0
- package/cli/lib/site-bundle-commands.mjs +95 -0
- package/cli/lib/site-bundle-compare.mjs +157 -0
- package/cli/lib/site-bundle-contract.mjs +79 -0
- package/cli/lib/site-bundle-files.mjs +87 -0
- package/cli/lib/site-bundle-handoff-runbook-actions.mjs +113 -0
- package/cli/lib/site-bundle-handoff-runbook-evidence-fields.mjs +164 -0
- package/cli/lib/site-bundle-handoff-runbook-evidence.mjs +334 -0
- package/cli/lib/site-bundle-handoff-runbook-format.mjs +31 -0
- package/cli/lib/site-bundle-handoff-runbook-stage-metadata.mjs +84 -0
- package/cli/lib/site-bundle-handoff-runbook.mjs +1331 -0
- package/cli/lib/site-bundle-handoff-summary.mjs +183 -0
- package/cli/lib/site-bundle-handoff.mjs +271 -0
- package/cli/lib/site-bundle-readme.mjs +98 -0
- package/cli/lib/site-bundle-repair-report.mjs +143 -0
- package/cli/lib/site-bundle-repair.mjs +68 -0
- package/cli/lib/site-content.mjs +399 -0
- package/cli/lib/site-evidence.mjs +35 -0
- package/cli/lib/site-mcp-commands.mjs +28 -0
- package/cli/lib/site-mcp-probes.mjs +159 -0
- package/cli/lib/site-mcp-readiness.mjs +157 -0
- package/cli/lib/site-mcp-report.mjs +324 -0
- package/cli/lib/site-next-actions.mjs +333 -0
- package/cli/lib/site-options.mjs +104 -0
- package/cli/lib/site-prompts.mjs +332 -0
- package/cli/lib/site-starter.mjs +153 -0
- package/cli/lib/site-strings.mjs +23 -0
- package/cli/lib/site-tasks.mjs +93 -0
- package/cli/lib/site-workflow-graph.mjs +309 -0
- package/cli/lib/site-workspace.mjs +492 -0
- package/cli/lib/site.mjs +108 -6617
- package/docs/DISTRIBUTION.ko.md +35 -6
- package/docs/DISTRIBUTION.md +35 -8
- package/docs/RELEASE-CHECKLIST.md +20 -3
- package/docs/ROADMAP.md +2179 -0
- package/docs/external-status.md +22 -7
- package/docs/integrations/design-ai-mcp-server.md +32 -0
- package/docs/integrations/vscode-walkthrough.ko.md +3 -3
- package/docs/integrations/vscode-walkthrough.md +3 -3
- package/docs/site-overrides/main.html +1 -1
- package/package.json +1 -1
- package/tools/audit/package-smoke.py +106 -0
- package/tools/audit/registry-smoke.py +378 -10
- package/tools/audit/smoke_assertions.py +83 -22
|
@@ -14,6 +14,7 @@ from doctor_assertions import EXPECTED_DOCTOR_PASS_LABELS, assert_doctor_report_
|
|
|
14
14
|
|
|
15
15
|
ANSI_ESCAPE_RE = re.compile(r"\x1b\[[0-?]*[ -/]*[@-~]")
|
|
16
16
|
ROOT = Path(__file__).resolve().parents[2]
|
|
17
|
+
PACKAGE_JSON = ROOT / "package.json"
|
|
17
18
|
PLUGIN_MANIFEST = ROOT / ".claude-plugin" / "plugin.json"
|
|
18
19
|
PLUGIN_INVENTORY_SECTIONS = (
|
|
19
20
|
("skills", "skill"),
|
|
@@ -21,6 +22,7 @@ PLUGIN_INVENTORY_SECTIONS = (
|
|
|
21
22
|
("agents", "agent"),
|
|
22
23
|
)
|
|
23
24
|
OUTPUT_FORCE_OVERWRITE_SENTINEL = "__design-ai-smoke-force-overwrite-sentinel__"
|
|
25
|
+
EXPECTED_MCP_INVALID_ARGUMENT_MESSAGE = "design_ai_search.limit must be an integer"
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
def load_plugin_manifest() -> dict[str, object]:
|
|
@@ -30,11 +32,70 @@ def load_plugin_manifest() -> dict[str, object]:
|
|
|
30
32
|
raise SystemExit(f"failed to load plugin manifest for smoke assertions: {PLUGIN_MANIFEST}") from error
|
|
31
33
|
|
|
32
34
|
|
|
35
|
+
def load_package_json() -> dict[str, object]:
|
|
36
|
+
try:
|
|
37
|
+
return json.loads(PACKAGE_JSON.read_text(encoding="utf-8"))
|
|
38
|
+
except (OSError, json.JSONDecodeError) as error:
|
|
39
|
+
raise SystemExit(f"failed to load package metadata for smoke assertions: {PACKAGE_JSON}") from error
|
|
40
|
+
|
|
41
|
+
|
|
33
42
|
def count_manifest_section(manifest: dict[str, object], section: str) -> int:
|
|
34
43
|
items = manifest.get(section)
|
|
35
44
|
return len(items) if isinstance(items, list) else 0
|
|
36
45
|
|
|
37
46
|
|
|
47
|
+
EXPECTED_RELEASE_VERSION = str(load_package_json().get("version", ""))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def mcp_smoke_input() -> str:
|
|
51
|
+
messages = [
|
|
52
|
+
{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-11-25"}},
|
|
53
|
+
{"jsonrpc": "2.0", "method": "notifications/initialized"},
|
|
54
|
+
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"},
|
|
55
|
+
{
|
|
56
|
+
"jsonrpc": "2.0",
|
|
57
|
+
"id": 3,
|
|
58
|
+
"method": "tools/call",
|
|
59
|
+
"params": {
|
|
60
|
+
"name": "design_ai_search",
|
|
61
|
+
"arguments": {"query": "Pretendard", "limit": "10"},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
return "".join(f"{json.dumps(message, separators=(',', ':'))}\n" for message in messages)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def assert_design_ai_mcp_protocol_responses(responses: list[object], *, context: str, cmd: list[str]) -> None:
|
|
69
|
+
by_id = {
|
|
70
|
+
response.get("id"): response
|
|
71
|
+
for response in responses
|
|
72
|
+
if isinstance(response, dict) and "id" in response
|
|
73
|
+
}
|
|
74
|
+
init = by_id.get(1)
|
|
75
|
+
tools = by_id.get(2)
|
|
76
|
+
invalid_call = by_id.get(3)
|
|
77
|
+
|
|
78
|
+
if not (isinstance(init, dict) and init.get("result", {}).get("serverInfo", {}).get("name") == "design-ai"):
|
|
79
|
+
raise SystemExit(f"{context}: MCP initialize response missing design-ai serverInfo")
|
|
80
|
+
|
|
81
|
+
tool_names = [
|
|
82
|
+
item.get("name")
|
|
83
|
+
for item in tools.get("result", {}).get("tools", [])
|
|
84
|
+
] if isinstance(tools, dict) else []
|
|
85
|
+
if "design_ai_route" not in tool_names or "design_ai_search" not in tool_names:
|
|
86
|
+
raise SystemExit(f"{context}: MCP tools/list response missing design-ai tools")
|
|
87
|
+
|
|
88
|
+
invalid_error = invalid_call.get("error", {}) if isinstance(invalid_call, dict) else {}
|
|
89
|
+
invalid_text = str(invalid_error.get("message", "")) if isinstance(invalid_error, dict) else ""
|
|
90
|
+
if not (
|
|
91
|
+
isinstance(invalid_call, dict)
|
|
92
|
+
and isinstance(invalid_error, dict)
|
|
93
|
+
and invalid_error.get("code") == -32602
|
|
94
|
+
and EXPECTED_MCP_INVALID_ARGUMENT_MESSAGE in invalid_text
|
|
95
|
+
):
|
|
96
|
+
raise SystemExit(f"{context}: MCP invalid argument response did not preserve invalid params validation")
|
|
97
|
+
|
|
98
|
+
|
|
38
99
|
def format_inventory_count(count: int, singular: str) -> str:
|
|
39
100
|
return f"{count} {singular}{'' if count == 1 else 's'}"
|
|
40
101
|
|
|
@@ -327,7 +388,7 @@ EXPECTED_MAIN_HELP_FRAGMENTS = (
|
|
|
327
388
|
EXPECTED_VERSION_FRAGMENTS = (
|
|
328
389
|
"design-ai CLI:",
|
|
329
390
|
"Plugin / corpus:",
|
|
330
|
-
|
|
391
|
+
EXPECTED_RELEASE_VERSION,
|
|
331
392
|
"Source:",
|
|
332
393
|
)
|
|
333
394
|
EXPECTED_INSTALL_OUTPUT_FRAGMENTS = (
|
|
@@ -367,7 +428,7 @@ EXPECTED_DOCTOR_STRICT_OUTPUT_FRAGMENTS = (
|
|
|
367
428
|
"Target:",
|
|
368
429
|
"Prefix:",
|
|
369
430
|
"Source layout: complete",
|
|
370
|
-
"Version alignment:
|
|
431
|
+
f"Version alignment: {EXPECTED_RELEASE_VERSION}",
|
|
371
432
|
"Manifest paths: 41 referenced artifact(s) exist",
|
|
372
433
|
"Node runtime:",
|
|
373
434
|
"Python runtime:",
|
|
@@ -1508,7 +1569,7 @@ def passing_list_catalog_output(kind: str = "skills") -> str:
|
|
|
1508
1569
|
"",
|
|
1509
1570
|
" design-ai catalog",
|
|
1510
1571
|
"",
|
|
1511
|
-
"Plugin: design-ai
|
|
1572
|
+
f"Plugin: design-ai v{EXPECTED_RELEASE_VERSION}",
|
|
1512
1573
|
"",
|
|
1513
1574
|
"",
|
|
1514
1575
|
f"{kind} ({len(items)})",
|
|
@@ -1540,7 +1601,7 @@ def passing_list_catalog_json(kind: str = "skills") -> str:
|
|
|
1540
1601
|
return json.dumps(
|
|
1541
1602
|
{
|
|
1542
1603
|
"name": "design-ai",
|
|
1543
|
-
"version":
|
|
1604
|
+
"version": EXPECTED_RELEASE_VERSION,
|
|
1544
1605
|
"kind": kind,
|
|
1545
1606
|
"sections": [
|
|
1546
1607
|
{
|
|
@@ -1961,7 +2022,7 @@ def passing_examples_human_output() -> str:
|
|
|
1961
2022
|
def passing_route_json() -> str:
|
|
1962
2023
|
return json.dumps({
|
|
1963
2024
|
"brief": EXPECTED_ROUTE_BRIEF,
|
|
1964
|
-
"version":
|
|
2025
|
+
"version": EXPECTED_RELEASE_VERSION,
|
|
1965
2026
|
"routes": [
|
|
1966
2027
|
{
|
|
1967
2028
|
"id": EXPECTED_ROUTE_ID,
|
|
@@ -2035,7 +2096,7 @@ def passing_route_explain_human_output() -> str:
|
|
|
2035
2096
|
f" {EXPECTED_ROUTE_BRIEF}",
|
|
2036
2097
|
"",
|
|
2037
2098
|
"Source: /tmp/design-ai",
|
|
2038
|
-
"Corpus version:
|
|
2099
|
+
f"Corpus version: {EXPECTED_RELEASE_VERSION}",
|
|
2039
2100
|
"",
|
|
2040
2101
|
f"1. {EXPECTED_ROUTE_LABEL} (high, score {len(EXPECTED_ROUTE_MATCHED_KEYWORDS)})",
|
|
2041
2102
|
f" id: {EXPECTED_ROUTE_ID}",
|
|
@@ -2124,7 +2185,7 @@ def passing_route_catalog_json() -> str:
|
|
|
2124
2185
|
routes.append(route)
|
|
2125
2186
|
|
|
2126
2187
|
return json.dumps({
|
|
2127
|
-
"version":
|
|
2188
|
+
"version": EXPECTED_RELEASE_VERSION,
|
|
2128
2189
|
"routes": routes,
|
|
2129
2190
|
})
|
|
2130
2191
|
|
|
@@ -2132,7 +2193,7 @@ def passing_route_catalog_json() -> str:
|
|
|
2132
2193
|
def passing_prompt_payload() -> dict:
|
|
2133
2194
|
return {
|
|
2134
2195
|
"brief": EXPECTED_ROUTE_BRIEF,
|
|
2135
|
-
"version":
|
|
2196
|
+
"version": EXPECTED_RELEASE_VERSION,
|
|
2136
2197
|
"route": {
|
|
2137
2198
|
"id": EXPECTED_ROUTE_ID,
|
|
2138
2199
|
"label": EXPECTED_ROUTE_LABEL,
|
|
@@ -2237,7 +2298,7 @@ def passing_prompt_markdown_output() -> str:
|
|
|
2237
2298
|
f" {EXPECTED_ROUTE_BRIEF}",
|
|
2238
2299
|
"",
|
|
2239
2300
|
"Source: /tmp/design",
|
|
2240
|
-
"Corpus version:
|
|
2301
|
+
f"Corpus version: {EXPECTED_RELEASE_VERSION}",
|
|
2241
2302
|
"",
|
|
2242
2303
|
"# design-ai task prompt",
|
|
2243
2304
|
f"Task: {EXPECTED_ROUTE_BRIEF}",
|
|
@@ -2263,7 +2324,7 @@ def passing_prompt_markdown_output() -> str:
|
|
|
2263
2324
|
def passing_pack_json() -> str:
|
|
2264
2325
|
return json.dumps({
|
|
2265
2326
|
"brief": EXPECTED_ROUTE_BRIEF,
|
|
2266
|
-
"version":
|
|
2327
|
+
"version": EXPECTED_RELEASE_VERSION,
|
|
2267
2328
|
"maxBytes": EXPECTED_PACK_MAX_BYTES,
|
|
2268
2329
|
"usedBytes": EXPECTED_PACK_MAX_BYTES,
|
|
2269
2330
|
"summary": {
|
|
@@ -2311,7 +2372,7 @@ def passing_pack_markdown_output() -> str:
|
|
|
2311
2372
|
f" {EXPECTED_ROUTE_BRIEF}",
|
|
2312
2373
|
"",
|
|
2313
2374
|
"Source: /tmp/design",
|
|
2314
|
-
"Corpus version:
|
|
2375
|
+
f"Corpus version: {EXPECTED_RELEASE_VERSION}",
|
|
2315
2376
|
f"Context: partial, {EXPECTED_PACK_MAX_BYTES}/{EXPECTED_PACK_MAX_BYTES} bytes, 2 warnings",
|
|
2316
2377
|
"",
|
|
2317
2378
|
"# design-ai prompt pack",
|
|
@@ -4181,8 +4242,8 @@ def passing_main_help_output() -> str:
|
|
|
4181
4242
|
|
|
4182
4243
|
def passing_version_output() -> str:
|
|
4183
4244
|
return "\n".join([
|
|
4184
|
-
"design-ai CLI:
|
|
4185
|
-
"Plugin / corpus:
|
|
4245
|
+
f"design-ai CLI: {EXPECTED_RELEASE_VERSION}",
|
|
4246
|
+
f"Plugin / corpus: {EXPECTED_RELEASE_VERSION}",
|
|
4186
4247
|
"Source: /tmp/design-ai",
|
|
4187
4248
|
"",
|
|
4188
4249
|
])
|
|
@@ -4195,8 +4256,8 @@ def passing_version_json() -> str:
|
|
|
4195
4256
|
"sourceRoot": "/tmp/design-ai",
|
|
4196
4257
|
},
|
|
4197
4258
|
"versions": {
|
|
4198
|
-
"cli":
|
|
4199
|
-
"plugin":
|
|
4259
|
+
"cli": EXPECTED_RELEASE_VERSION,
|
|
4260
|
+
"plugin": EXPECTED_RELEASE_VERSION,
|
|
4200
4261
|
"aligned": True,
|
|
4201
4262
|
},
|
|
4202
4263
|
},
|
|
@@ -4213,7 +4274,7 @@ def passing_workspace_json() -> str:
|
|
|
4213
4274
|
"root": "/tmp/project",
|
|
4214
4275
|
"sourceRoot": "/tmp/design-ai",
|
|
4215
4276
|
"packageName": "@design-ai/cli",
|
|
4216
|
-
"version":
|
|
4277
|
+
"version": EXPECTED_RELEASE_VERSION,
|
|
4217
4278
|
},
|
|
4218
4279
|
"git": {
|
|
4219
4280
|
"isRepo": False,
|
|
@@ -4267,7 +4328,7 @@ def passing_workspace_json() -> str:
|
|
|
4267
4328
|
"learningRestoreBackups": None,
|
|
4268
4329
|
"release": {
|
|
4269
4330
|
"packageName": "@design-ai/cli",
|
|
4270
|
-
"version":
|
|
4331
|
+
"version": EXPECTED_RELEASE_VERSION,
|
|
4271
4332
|
"scripts": {
|
|
4272
4333
|
"test": "node --test cli/lib/*.test.mjs",
|
|
4273
4334
|
"audit:strict": "python3 -B tools/audit/run-all.py --strict",
|
|
@@ -5568,7 +5629,7 @@ def passing_doctor_strict_output() -> str:
|
|
|
5568
5629
|
"ℹ Prefix: smoke-design-",
|
|
5569
5630
|
"",
|
|
5570
5631
|
"✓ Source layout: complete at /tmp/design-ai",
|
|
5571
|
-
"✓ Version alignment:
|
|
5632
|
+
f"✓ Version alignment: {EXPECTED_RELEASE_VERSION}",
|
|
5572
5633
|
"✓ Manifest paths: 41 referenced artifact(s) exist",
|
|
5573
5634
|
"✓ Node runtime: v24.13.1",
|
|
5574
5635
|
"✓ Python runtime: Python 3.12.12",
|
|
@@ -5593,7 +5654,7 @@ def passing_install_output() -> str:
|
|
|
5593
5654
|
return "\n".join([
|
|
5594
5655
|
"",
|
|
5595
5656
|
" design-ai installer",
|
|
5596
|
-
"
|
|
5657
|
+
f" v{EXPECTED_RELEASE_VERSION}",
|
|
5597
5658
|
"",
|
|
5598
5659
|
"Source: /tmp/design-ai",
|
|
5599
5660
|
"Target: /tmp/claude-home",
|
|
@@ -6022,7 +6083,7 @@ def assert_workspace_json(raw: str, *, context: str, cmd: list[str]) -> None:
|
|
|
6022
6083
|
)
|
|
6023
6084
|
if workspace_context.get("packageName") != "@design-ai/cli":
|
|
6024
6085
|
raise SystemExit(f"workspace JSON after {context} packageName differs from expected package")
|
|
6025
|
-
if workspace_context.get("version") !=
|
|
6086
|
+
if workspace_context.get("version") != EXPECTED_RELEASE_VERSION:
|
|
6026
6087
|
raise SystemExit(f"workspace JSON after {context} version differs from expected release version")
|
|
6027
6088
|
for key in ("cwd", "root", "sourceRoot"):
|
|
6028
6089
|
if not isinstance(workspace_context.get(key), str) or not workspace_context[key]:
|
|
@@ -6355,7 +6416,7 @@ def assert_workspace_json(raw: str, *, context: str, cmd: list[str]) -> None:
|
|
|
6355
6416
|
context=context,
|
|
6356
6417
|
command_label="workspace JSON",
|
|
6357
6418
|
)
|
|
6358
|
-
if release.get("packageName") != "@design-ai/cli" or release.get("version") !=
|
|
6419
|
+
if release.get("packageName") != "@design-ai/cli" or release.get("version") != EXPECTED_RELEASE_VERSION:
|
|
6359
6420
|
raise SystemExit(f"workspace JSON after {context} release package metadata differs from expected values")
|
|
6360
6421
|
if not isinstance(release.get("scripts"), dict):
|
|
6361
6422
|
raise SystemExit(f"workspace JSON after {context} release scripts is not an object")
|
|
@@ -10780,7 +10841,7 @@ def run_self_test() -> None:
|
|
|
10780
10841
|
)
|
|
10781
10842
|
expect_self_test_failure(
|
|
10782
10843
|
lambda: assert_version_json(
|
|
10783
|
-
passing_version_json().replace('"plugin": "
|
|
10844
|
+
passing_version_json().replace(f'"plugin": "{EXPECTED_RELEASE_VERSION}"', '"plugin": "unknown"'),
|
|
10784
10845
|
context=context,
|
|
10785
10846
|
cmd=[*version_cmd, "--json"],
|
|
10786
10847
|
),
|