sdtk-kit 0.3.9 → 1.0.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 (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -177
  3. package/package.json +52 -46
  4. package/scripts/postinstall.js +40 -0
  5. package/assets/manifest/toolkit-bundle.manifest.json +0 -473
  6. package/assets/manifest/toolkit-bundle.sha256.txt +0 -93
  7. package/assets/toolkit/toolkit/AGENTS.md +0 -131
  8. package/assets/toolkit/toolkit/install.ps1 +0 -310
  9. package/assets/toolkit/toolkit/runtimes/claude/CLAUDE_TEMPLATE.md +0 -54
  10. package/assets/toolkit/toolkit/runtimes/codex/CODEX_TEMPLATE.md +0 -32
  11. package/assets/toolkit/toolkit/scripts/init-feature.ps1 +0 -261
  12. package/assets/toolkit/toolkit/scripts/install-claude-skills.ps1 +0 -169
  13. package/assets/toolkit/toolkit/scripts/install-codex-skills.ps1 +0 -189
  14. package/assets/toolkit/toolkit/scripts/uninstall-claude-skills.ps1 +0 -139
  15. package/assets/toolkit/toolkit/scripts/uninstall-codex-skills.ps1 +0 -116
  16. package/assets/toolkit/toolkit/sdtk.config.json +0 -28
  17. package/assets/toolkit/toolkit/sdtk.config.profiles.example.json +0 -50
  18. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/SKILL.md +0 -84
  19. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/references/API_DESIGN_CREATION_RULES.md +0 -22
  20. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/references/API_DESIGN_FLOWCHART_CREATION_RULES.md +0 -468
  21. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/references/FLOWCHART_CREATION_RULES.md +0 -20
  22. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/scripts/generate_api_design_detail.py +0 -732
  23. package/assets/toolkit/toolkit/skills/sdtk-api-doc/SKILL.md +0 -43
  24. package/assets/toolkit/toolkit/skills/sdtk-api-doc/references/API_DESIGN_FLOWCHART_CREATION_RULES.md +0 -468
  25. package/assets/toolkit/toolkit/skills/sdtk-api-doc/references/FLOWCHART_CREATION_RULES.md +0 -20
  26. package/assets/toolkit/toolkit/skills/sdtk-api-doc/references/YAML_CREATION_RULES.md +0 -128
  27. package/assets/toolkit/toolkit/skills/sdtk-arch/SKILL.md +0 -83
  28. package/assets/toolkit/toolkit/skills/sdtk-arch/references/API_DESIGN_CREATION_RULES.md +0 -22
  29. package/assets/toolkit/toolkit/skills/sdtk-arch/references/API_DESIGN_FLOWCHART_CREATION_RULES.md +0 -468
  30. package/assets/toolkit/toolkit/skills/sdtk-arch/references/FLOWCHART_CREATION_RULES.md +0 -20
  31. package/assets/toolkit/toolkit/skills/sdtk-arch/references/FLOW_ACTION_SPEC_CREATION_RULES.md +0 -220
  32. package/assets/toolkit/toolkit/skills/sdtk-arch/references/YAML_CREATION_RULES.md +0 -128
  33. package/assets/toolkit/toolkit/skills/sdtk-ba/SKILL.md +0 -29
  34. package/assets/toolkit/toolkit/skills/sdtk-design-layout/SKILL.md +0 -52
  35. package/assets/toolkit/toolkit/skills/sdtk-design-layout/scripts/render_design_layout_images.py +0 -246
  36. package/assets/toolkit/toolkit/skills/sdtk-dev/SKILL.md +0 -90
  37. package/assets/toolkit/toolkit/skills/sdtk-dev/prompts/code-quality-reviewer.md +0 -35
  38. package/assets/toolkit/toolkit/skills/sdtk-dev/prompts/implementer.md +0 -61
  39. package/assets/toolkit/toolkit/skills/sdtk-dev/prompts/spec-reviewer.md +0 -42
  40. package/assets/toolkit/toolkit/skills/sdtk-dev-backend/SKILL.md +0 -21
  41. package/assets/toolkit/toolkit/skills/sdtk-dev-frontend/SKILL.md +0 -19
  42. package/assets/toolkit/toolkit/skills/sdtk-orchestrator/SKILL.md +0 -80
  43. package/assets/toolkit/toolkit/skills/sdtk-pm/SKILL.md +0 -30
  44. package/assets/toolkit/toolkit/skills/sdtk-qa/SKILL.md +0 -53
  45. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/SKILL.md +0 -86
  46. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/FLOW_ACTION_SPEC_CREATION_RULES.md +0 -220
  47. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/excel-image-export.md +0 -51
  48. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/figma-mcp.md +0 -54
  49. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/numbering-rules.md +0 -28
  50. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/scripts/renumber_flow_action_spec_global.py +0 -136
  51. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/scripts/validate_flow_action_spec_numbering.py +0 -414
  52. package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/SKILL.md +0 -74
  53. package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/references/TEST_CASE_CREATION_RULES.md +0 -129
  54. package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/scripts/validate_test_case_spec.py +0 -97
  55. package/assets/toolkit/toolkit/skills/skills.catalog.yaml +0 -302
  56. package/assets/toolkit/toolkit/skills-claude/api-design-spec/SKILL.md +0 -90
  57. package/assets/toolkit/toolkit/skills-claude/api-doc/SKILL.md +0 -47
  58. package/assets/toolkit/toolkit/skills-claude/arch/SKILL.md +0 -59
  59. package/assets/toolkit/toolkit/skills-claude/ba/SKILL.md +0 -50
  60. package/assets/toolkit/toolkit/skills-claude/design-layout/SKILL.md +0 -57
  61. package/assets/toolkit/toolkit/skills-claude/dev/SKILL.md +0 -45
  62. package/assets/toolkit/toolkit/skills-claude/dev-backend/SKILL.md +0 -20
  63. package/assets/toolkit/toolkit/skills-claude/dev-frontend/SKILL.md +0 -18
  64. package/assets/toolkit/toolkit/skills-claude/orchestrator/SKILL.md +0 -63
  65. package/assets/toolkit/toolkit/skills-claude/pm/SKILL.md +0 -52
  66. package/assets/toolkit/toolkit/skills-claude/qa/SKILL.md +0 -48
  67. package/assets/toolkit/toolkit/skills-claude/screen-design-spec/SKILL.md +0 -90
  68. package/assets/toolkit/toolkit/skills-claude/test-case-spec/SKILL.md +0 -61
  69. package/assets/toolkit/toolkit/templates/QUALITY_CHECKLIST.md +0 -124
  70. package/assets/toolkit/toolkit/templates/README.md +0 -63
  71. package/assets/toolkit/toolkit/templates/SHARED_PLANNING.md +0 -80
  72. package/assets/toolkit/toolkit/templates/docs/api/API_DESIGN_CREATION_RULES.md +0 -22
  73. package/assets/toolkit/toolkit/templates/docs/api/API_DESIGN_DETAIL_TEMPLATE.md +0 -67
  74. package/assets/toolkit/toolkit/templates/docs/api/API_DESIGN_FLOWCHART_CREATION_RULES.md +0 -468
  75. package/assets/toolkit/toolkit/templates/docs/api/API_ENDPOINTS_TEMPLATE.md +0 -229
  76. package/assets/toolkit/toolkit/templates/docs/api/FEATURE_API_TEMPLATE.yaml +0 -20
  77. package/assets/toolkit/toolkit/templates/docs/api/FLOWCHART_CREATION_RULES.md +0 -20
  78. package/assets/toolkit/toolkit/templates/docs/api/YAML_CREATION_RULES.md +0 -128
  79. package/assets/toolkit/toolkit/templates/docs/api/feature_api_flow_list_TEMPLATE.txt +0 -12
  80. package/assets/toolkit/toolkit/templates/docs/architecture/ARCH_DESIGN_TEMPLATE.md +0 -109
  81. package/assets/toolkit/toolkit/templates/docs/database/DATABASE_SPEC_TEMPLATE.md +0 -175
  82. package/assets/toolkit/toolkit/templates/docs/design/DESIGN_LAYOUT_TEMPLATE.md +0 -60
  83. package/assets/toolkit/toolkit/templates/docs/dev/FEATURE_IMPL_PLAN_TEMPLATE.md +0 -73
  84. package/assets/toolkit/toolkit/templates/docs/product/BACKLOG_TEMPLATE.md +0 -50
  85. package/assets/toolkit/toolkit/templates/docs/product/PRD_TEMPLATE.md +0 -66
  86. package/assets/toolkit/toolkit/templates/docs/product/PROJECT_INITIATION_TEMPLATE.md +0 -98
  87. package/assets/toolkit/toolkit/templates/docs/qa/QA_RELEASE_REPORT_TEMPLATE.md +0 -61
  88. package/assets/toolkit/toolkit/templates/docs/qa/TEST_CASE_CREATION_RULES.md +0 -129
  89. package/assets/toolkit/toolkit/templates/docs/qa/TEST_CASE_TEMPLATE.md +0 -104
  90. package/assets/toolkit/toolkit/templates/docs/specs/BA_SPEC_TEMPLATE.md +0 -139
  91. package/assets/toolkit/toolkit/templates/docs/specs/FLOW_ACTION_SPEC_CREATION_RULES.md +0 -220
  92. package/assets/toolkit/toolkit/templates/docs/specs/FLOW_ACTION_SPEC_TEMPLATE.md +0 -197
  93. package/assets/toolkit/toolkit/templates/handoffs/ARCH_TO_DEV.md +0 -31
  94. package/assets/toolkit/toolkit/templates/handoffs/BA_TO_ARCH.md +0 -28
  95. package/assets/toolkit/toolkit/templates/handoffs/DEV_STAGE1_SPEC_REVIEW.md +0 -26
  96. package/assets/toolkit/toolkit/templates/handoffs/DEV_STAGE2_CODE_QUALITY_REVIEW.md +0 -20
  97. package/assets/toolkit/toolkit/templates/handoffs/DEV_TO_QA.md +0 -23
  98. package/assets/toolkit/toolkit/templates/handoffs/PM_TO_BA.md +0 -26
  99. package/assets/toolkit/toolkit/templates/handoffs/QA_RELEASE_DECISION.md +0 -21
  100. package/bin/sdtk.js +0 -15
  101. package/src/commands/auth.js +0 -85
  102. package/src/commands/generate.js +0 -177
  103. package/src/commands/help.js +0 -101
  104. package/src/commands/init.js +0 -97
  105. package/src/commands/runtime.js +0 -217
  106. package/src/index.js +0 -59
  107. package/src/lib/args.js +0 -116
  108. package/src/lib/errors.js +0 -41
  109. package/src/lib/github-access.js +0 -68
  110. package/src/lib/powershell.js +0 -85
  111. package/src/lib/scope.js +0 -68
  112. package/src/lib/state.js +0 -83
  113. package/src/lib/toolkit-payload.js +0 -99
@@ -1,414 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import argparse
4
- import re
5
- import sys
6
- from dataclasses import dataclass
7
- from pathlib import Path
8
-
9
-
10
- TABLE_ROW_RE = re.compile(r"^\|.*\|\s*$")
11
- TABLE_SEP_RE = re.compile(r"^\|\s*:?-+:?\s*(\|\s*:?-+:?\s*)+\|\s*$")
12
- HEADING_RE = re.compile(r"^(#{1,6})\s+(.*\S)\s*$")
13
- SCREEN_SECTION_HEADING_RE = re.compile(r"^###\s+(.*\S)\s*$", re.MULTILINE)
14
- VI_DIACRITIC_RE = re.compile(r"[À-ỹ]")
15
- VI_PHRASE_RE = re.compile(
16
- r"\b("
17
- r"thuc thi|hien thi|cap nhat|bo sung|can xac nhan|trong anh|"
18
- r"duoc tra kem|tao lich|theo user|muc global|thay the cho|bao gom"
19
- r")\b",
20
- re.IGNORECASE,
21
- )
22
- INLINE_HEADING_RE = re.compile(r".+\s#{2,}\s+\S")
23
- IMAGE_LINK_RE = re.compile(r"!\[[^\]]*\]\(([^)]+)\)")
24
- PLANTUML_FENCE_START_RE = re.compile(r"^\s*```plantuml\s*$", re.IGNORECASE)
25
- NEW_STYLE_ACTIVITY_LINE_RE = re.compile(
26
- r"^\s*(start|stop|partition\s+\"|if\s*\(|fork(?:\s+again)?\b|end\s+fork\b|note\s+(?:right|left|top|bottom)\b|:[^;\n]+;)",
27
- re.IGNORECASE,
28
- )
29
- LEGACY_ACTIVITY_START_RE = re.compile(r"\(\*\)")
30
- LEGACY_EDGE_LABEL_RE = re.compile(r"-->\s*\[")
31
- MIXED_ACTIVITY_ARROW_RE = re.compile(r":[^;\n]+;\s*-->")
32
-
33
-
34
- @dataclass(frozen=True)
35
- class Occurrence:
36
- number: int
37
- section: str
38
- line_no: int
39
- raw_line: str
40
-
41
-
42
- def _split_table_row(line: str) -> list[str]:
43
- # Keep it simple: markdown tables in our spec are plain and don't escape pipes.
44
- parts = [p.strip() for p in line.strip().strip("|").split("|")]
45
- return parts
46
-
47
-
48
- def _read_text(path: Path) -> str:
49
- # Prefer UTF-8; fallback to cp1252-ish if user saved without UTF-8.
50
- for enc in ("utf-8", "utf-8-sig", "cp1252"):
51
- try:
52
- return path.read_text(encoding=enc)
53
- except UnicodeDecodeError:
54
- continue
55
- return path.read_text(errors="replace")
56
-
57
-
58
- def collect_hygiene_issues(md_text: str, *, en_check: bool) -> dict[str, list[tuple[int, str]]]:
59
- issues: dict[str, list[tuple[int, str]]] = {
60
- "encoding": [],
61
- "vi_diacritic": [],
62
- "vi_phrase": [],
63
- "inline_heading": [],
64
- }
65
- lines = md_text.splitlines()
66
- in_code_block = False
67
-
68
- for idx, line in enumerate(lines, start=1):
69
- stripped = line.strip()
70
- if stripped.startswith("```"):
71
- in_code_block = not in_code_block
72
- continue
73
- if in_code_block:
74
- continue
75
-
76
- if "�" in line or "ↁE" in line:
77
- issues["encoding"].append((idx, line))
78
-
79
- # A common corruption symptom: merged headings inside normal text lines.
80
- if INLINE_HEADING_RE.search(line) and not stripped.startswith("#"):
81
- issues["inline_heading"].append((idx, line))
82
-
83
- if en_check:
84
- lowered = stripped.lower()
85
- if "original text" in lowered:
86
- continue
87
- if VI_DIACRITIC_RE.search(line):
88
- issues["vi_diacritic"].append((idx, line))
89
- elif VI_PHRASE_RE.search(line):
90
- issues["vi_phrase"].append((idx, line))
91
-
92
- return issues
93
-
94
-
95
- def _is_root_relative_docs_href(href: str) -> bool:
96
- normalized = href.strip().replace("\\", "/").lower()
97
- if not normalized:
98
- return False
99
- if re.match(r"^[a-z][a-z0-9+.-]*://", normalized):
100
- return False
101
- if normalized.startswith(("mailto:", "tel:", "data:", "#")):
102
- return False
103
- return normalized.startswith(("docs/", "./docs/", "/docs/"))
104
-
105
-
106
- def collect_screen_image_path_issues(md_text: str) -> list[tuple[int, str]]:
107
- issues: list[tuple[int, str]] = []
108
- lines = md_text.splitlines()
109
- in_code_block = False
110
- expecting_image_line = False
111
-
112
- for idx, line in enumerate(lines, start=1):
113
- stripped = line.strip()
114
- if stripped.startswith("```"):
115
- in_code_block = not in_code_block
116
- expecting_image_line = False
117
- continue
118
- if in_code_block:
119
- continue
120
- if not stripped:
121
- continue
122
-
123
- if stripped.lower().startswith("screen image:"):
124
- expecting_image_line = stripped.lower() == "screen image:"
125
- hrefs = IMAGE_LINK_RE.findall(stripped)
126
- elif expecting_image_line and stripped.startswith("!["):
127
- expecting_image_line = False
128
- hrefs = IMAGE_LINK_RE.findall(stripped)
129
- else:
130
- hrefs = []
131
- if not stripped.startswith("<!--"):
132
- expecting_image_line = False
133
-
134
- for href in hrefs:
135
- if _is_root_relative_docs_href(href):
136
- issues.append((idx, href))
137
-
138
- return issues
139
-
140
-
141
- def collect_plantuml_activity_syntax_issues(md_text: str) -> list[tuple[int, str]]:
142
- issues: list[tuple[int, str]] = []
143
- lines = md_text.splitlines()
144
- in_plantuml_block = False
145
- block_start_line = 0
146
- block_lines: list[str] = []
147
-
148
- def flush_block() -> None:
149
- nonlocal issues, block_lines, block_start_line
150
- if not block_lines:
151
- return
152
- has_new_style = any(NEW_STYLE_ACTIVITY_LINE_RE.search(line) for line in block_lines)
153
- if not has_new_style:
154
- block_lines = []
155
- block_start_line = 0
156
- return
157
-
158
- for offset, line in enumerate(block_lines, start=0):
159
- line_no = block_start_line + offset
160
- if LEGACY_ACTIVITY_START_RE.search(line):
161
- issues.append(
162
- (line_no, "Legacy activity start marker `(*)` is not allowed in new-style activity diagrams.")
163
- )
164
- if MIXED_ACTIVITY_ARROW_RE.search(line):
165
- issues.append(
166
- (line_no, "Do not append legacy `-->` transitions after a new-style `:Activity;` action line.")
167
- )
168
- elif LEGACY_EDGE_LABEL_RE.search(line):
169
- issues.append(
170
- (line_no, "Legacy edge labels like `--> [label]` are not allowed in new-style activity diagrams.")
171
- )
172
-
173
- block_lines = []
174
- block_start_line = 0
175
-
176
- for idx, line in enumerate(lines, start=1):
177
- if not in_plantuml_block and PLANTUML_FENCE_START_RE.match(line):
178
- in_plantuml_block = True
179
- block_start_line = idx + 1
180
- block_lines = []
181
- continue
182
-
183
- if in_plantuml_block and line.strip().startswith("```"):
184
- flush_block()
185
- in_plantuml_block = False
186
- continue
187
-
188
- if in_plantuml_block:
189
- block_lines.append(line)
190
-
191
- if in_plantuml_block:
192
- flush_block()
193
-
194
- return issues
195
-
196
-
197
- def collect_wireframe_mapping_issues(md_text: str) -> list[tuple[int, str]]:
198
- issues: list[tuple[int, str]] = []
199
- sections = list(SCREEN_SECTION_HEADING_RE.finditer(md_text))
200
- for idx, match in enumerate(sections):
201
- start = match.start()
202
- end = sections[idx + 1].start() if idx + 1 < len(sections) else len(md_text)
203
- section_text = md_text[start:end]
204
-
205
- if "Design Source Type: generated-draft" not in section_text:
206
- continue
207
- if "> Screen image not rendered in this environment." in section_text:
208
- continue
209
- if "Screen image:" not in section_text or "![" not in section_text:
210
- continue
211
- if "#### Wireframe Marker Mapping" in section_text:
212
- continue
213
-
214
- line_no = md_text.count("\n", 0, start) + 1
215
- section_name = match.group(1).strip()
216
- issues.append(
217
- (line_no, f"{section_name}: missing `Wireframe Marker Mapping` table for generated-draft screen.")
218
- )
219
-
220
- return issues
221
-
222
-
223
- def parse_action_tables(md_text: str) -> list[Occurrence]:
224
- occurrences: list[Occurrence] = []
225
- current_section = ""
226
- lines = md_text.splitlines()
227
-
228
- i = 0
229
- while i < len(lines):
230
- line = lines[i]
231
-
232
- m = HEADING_RE.match(line)
233
- if m:
234
- current_section = m.group(2).strip()
235
-
236
- # Detect table header
237
- if i + 1 < len(lines) and TABLE_ROW_RE.match(line) and TABLE_ROW_RE.match(lines[i + 1]):
238
- header = _split_table_row(line)
239
- sep = lines[i + 1]
240
-
241
- if not TABLE_SEP_RE.match(sep):
242
- i += 1
243
- continue
244
-
245
- # Only validate action tables: must contain No + Action + Description
246
- lowered = [h.lower() for h in header]
247
- if "no" not in lowered and "no." not in lowered:
248
- i += 1
249
- continue
250
- if "action" not in lowered or "description" not in lowered:
251
- i += 1
252
- continue
253
-
254
- try:
255
- no_index = lowered.index("no")
256
- except ValueError:
257
- no_index = lowered.index("no.")
258
-
259
- # Consume rows until table ends
260
- j = i + 2
261
- while j < len(lines) and TABLE_ROW_RE.match(lines[j]):
262
- row = _split_table_row(lines[j])
263
- if len(row) <= no_index:
264
- j += 1
265
- continue
266
- raw_no = row[no_index]
267
- try:
268
- number = int(raw_no)
269
- except ValueError:
270
- j += 1
271
- continue
272
- occurrences.append(
273
- Occurrence(
274
- number=number,
275
- section=current_section or "(unknown section)",
276
- line_no=j + 1, # 1-based
277
- raw_line=lines[j],
278
- )
279
- )
280
- j += 1
281
-
282
- i = j
283
- continue
284
-
285
- i += 1
286
-
287
- return occurrences
288
-
289
-
290
- def main() -> int:
291
- parser = argparse.ArgumentParser(description="Validate numbering in flow-action spec tables.")
292
- parser.add_argument("--spec", required=True, help="Path to *_FLOW_ACTION_SPEC.md")
293
- parser.add_argument(
294
- "--en-check",
295
- action="store_true",
296
- help="Enable EN artifact hygiene checks (Vietnamese leftovers + encoding corruption).",
297
- )
298
- args = parser.parse_args()
299
-
300
- try:
301
- sys.stdout.reconfigure(encoding="utf-8") # type: ignore[attr-defined]
302
- sys.stderr.reconfigure(encoding="utf-8") # type: ignore[attr-defined]
303
- except Exception:
304
- pass
305
-
306
- spec_path = Path(args.spec)
307
- if not spec_path.exists():
308
- print(f"[ERROR] Not found: {spec_path}", file=sys.stderr)
309
- return 2
310
-
311
- text = _read_text(spec_path)
312
- occ = parse_action_tables(text)
313
-
314
- by_number: dict[int, list[Occurrence]] = {}
315
- for o in occ:
316
- by_number.setdefault(o.number, []).append(o)
317
-
318
- duplicates = {n: os for n, os in by_number.items() if len(os) > 1}
319
-
320
- max_seen = -1
321
- decreases: list[tuple[Occurrence, int]] = []
322
- for o in occ:
323
- if o.number < max_seen:
324
- decreases.append((o, max_seen))
325
- max_seen = max(max_seen, o.number)
326
-
327
- has_issues = bool(duplicates or decreases)
328
- hygiene = collect_hygiene_issues(text, en_check=args.en_check)
329
- image_path_issues = collect_screen_image_path_issues(text)
330
- plantuml_activity_issues = collect_plantuml_activity_syntax_issues(text)
331
- wireframe_mapping_issues = collect_wireframe_mapping_issues(text)
332
- if hygiene["encoding"] or hygiene["inline_heading"]:
333
- has_issues = True
334
- if args.en_check and (hygiene["vi_diacritic"] or hygiene["vi_phrase"]):
335
- has_issues = True
336
- if image_path_issues:
337
- has_issues = True
338
- if plantuml_activity_issues:
339
- has_issues = True
340
- if wireframe_mapping_issues:
341
- has_issues = True
342
-
343
- print(f"Checked: {spec_path}")
344
- print(f"- Total numbered rows: {len(occ)}")
345
- print(f"- Unique numbers: {len(by_number)}")
346
- print(f"- EN hygiene check enabled: {args.en_check}")
347
-
348
- if not occ:
349
- print("[WARN] No action tables detected (| No | Action | Description | ... |).")
350
-
351
- if duplicates:
352
- print("\n[FAIL] Duplicate numbers found:")
353
- for n in sorted(duplicates.keys()):
354
- print(f"- No {n}:")
355
- for o in duplicates[n]:
356
- print(f" - {o.section} (line {o.line_no})")
357
-
358
- if decreases:
359
- print("\n[FAIL] Numbering decreases/resets detected (global numbering policy):")
360
- for o, prev_max in decreases:
361
- print(f"- No {o.number} after max {prev_max}: {o.section} (line {o.line_no})")
362
-
363
- if hygiene["encoding"]:
364
- print("\n[FAIL] Encoding/mojibake markers detected:")
365
- for line_no, line in hygiene["encoding"][:20]:
366
- print(f"- line {line_no}: {line.strip()}")
367
-
368
- if hygiene["inline_heading"]:
369
- print("\n[FAIL] Inline/merged heading patterns detected:")
370
- for line_no, line in hygiene["inline_heading"][:20]:
371
- print(f"- line {line_no}: {line.strip()}")
372
-
373
- if args.en_check and hygiene["vi_diacritic"]:
374
- print("\n[FAIL] Vietnamese diacritic text detected in EN artifact:")
375
- for line_no, line in hygiene["vi_diacritic"][:20]:
376
- print(f"- line {line_no}: {line.strip()}")
377
-
378
- if args.en_check and hygiene["vi_phrase"]:
379
- print("\n[FAIL] Vietnamese phrase patterns detected in EN artifact:")
380
- for line_no, line in hygiene["vi_phrase"][:20]:
381
- print(f"- line {line_no}: {line.strip()}")
382
-
383
- if image_path_issues:
384
- print("\n[FAIL] Screen image markdown paths must be file-relative, not docs-root-relative:")
385
- for line_no, href in image_path_issues[:20]:
386
- print(f"- line {line_no}: {href}")
387
-
388
- if plantuml_activity_issues:
389
- print("\n[FAIL] Mixed or legacy PlantUML activity syntax detected in a new-style screen-flow block:")
390
- for line_no, message in plantuml_activity_issues[:20]:
391
- print(f"- line {line_no}: {message}")
392
-
393
- if wireframe_mapping_issues:
394
- print("\n[FAIL] Missing wireframe-marker mapping tables for generated-draft screens:")
395
- for line_no, message in wireframe_mapping_issues[:20]:
396
- print(f"- line {line_no}: {message}")
397
-
398
- if not has_issues:
399
- print("\n[OK] Numbering and text hygiene checks passed.")
400
- return 0
401
-
402
- print("\nHint: Use global numbering across the full document.")
403
- print("- Do not repeat No values in any action table.")
404
- print("- Do not reset numbering per screen/dialog.")
405
- print("- Use file-relative screen image paths such as assets/<feature>/screens/<screen>.svg.")
406
- print("- Use new-style PlantUML activity syntax only for screen-flow diagrams.")
407
- print("- Add a `Wireframe Marker Mapping` table when a generated-draft screen embeds a wireframe image.")
408
- print("- Keep EN artifacts free of Vietnamese leftovers and encoding corruption.")
409
- print("- Keep headings/sections on separate lines (avoid merged markdown blocks).")
410
- return 1
411
-
412
-
413
- if __name__ == "__main__":
414
- raise SystemExit(main())
@@ -1,74 +0,0 @@
1
- ---
2
- name: sdtk-test-case-spec
3
- description: Generate screen-based QA test-case markdown (`[FEATURE_KEY]_TEST_CASE.md`) in Excel-aligned layout (Statistic + per-screen UTC/ITC worksheets). Use when QA needs reusable test design artifacts before or during execution.
4
- ---
5
-
6
- # SDTK Test Case Spec
7
-
8
- ## Critical Constraints
9
- - I do not invent test coverage beyond BA, flow-action, and API sources.
10
- - I do not let test totals drift away from worksheet rows or the QA baseline.
11
-
12
- ## Outputs
13
- - `docs/qa/[FEATURE_KEY]_TEST_CASE.md`
14
- - Optional project variant:
15
- - `docs/en/qa/[FEATURE_KEY]_TEST_CASE.md` (only when project uses `docs/en/**`)
16
-
17
- ## Required Inputs
18
- - Feature key (`FEATURE_KEY`)
19
- - Screen/flow references:
20
- - `docs/specs/[FEATURE_KEY]_FLOW_ACTION_SPEC.md`
21
- - `docs/specs/BA_SPEC_[FEATURE_KEY].md`
22
- - API reference:
23
- - `docs/api/[FEATURE_KEY]_ENDPOINTS.md`
24
- - (optional) `docs/api/[FeaturePascal]_API.yaml`
25
- - Clarification source:
26
- - `docs/specs/Q&A.md` or `docs/en/specs/Q&A.md` when available
27
-
28
- ## Core Rules
29
- 1. Apply `./references/TEST_CASE_CREATION_RULES.md` first.
30
- 2. Keep section order fixed (Statistic -> Abbreviations -> Scope -> References -> Environment -> Coverage -> Screen-based UTC/ITC -> OQ -> STC/UAT note).
31
- 3. Use screen-first layout to mirror worksheet structure.
32
- 4. Keep one unified 18-column schema for UTC/ITC rows.
33
- 5. Keep stable case IDs; do not renumber only because of regrouping.
34
- 6. Track unresolved decisions via `OQ-xx` and keep benchmark-expected OQs explicitly OPEN per `governance/ai/core/SDTK_BENCHMARK_OQ_POLICY.md`.
35
- 7. Quote exact BA, API, or flow-action requirement text when a testcase or coverage claim depends on that requirement.
36
-
37
- ## Procedure
38
- 1. Resolve output path:
39
- - default `docs/qa/[FEATURE_KEY]_TEST_CASE.md`
40
- - use `docs/en/qa/...` only if the repo already follows `docs/en/**`.
41
- 2. Build/refresh `Statistic Summary (Excel-aligned)` with UT total, IT total, and grand total.
42
- 3. Build `Feature Coverage Matrix` from flow/action and API docs.
43
- 4. Split UTC/ITC by screen sections (`screen-first`), not by test type only.
44
- 5. Fill conflict/permission/error-path cases from Q&A decisions and API contracts.
45
- 6. Record unresolved items in section `Open Questions`.
46
- 7. Validate:
47
- - counts in summary match table rows
48
- - structured TEST_CASE total stays aligned with the QA release-report baseline; if E2E is tracked separately, label it separately instead of inflating grand total
49
- - no placeholder tokens like `??`
50
- - out-of-scope boundaries are explicit
51
-
52
- ## Specification Quoting
53
- When a testcase, coverage note, or defect check depends on a requirement, quote the exact source text before stating coverage or mismatch.
54
-
55
- Use this format:
56
- - `Spec says: "[exact quote]" -> Evidence: [covered/not covered + file reference]`
57
-
58
- ## Role Integration
59
- - Primary owner: `/qa`.
60
- - `/qa` uses this skill to design/update reusable test-case specs.
61
- - `sdtk-qa` still owns release decision artifact (`QA_RELEASE_REPORT_*`).
62
-
63
- ## Notes
64
- - This skill is for test-case specification artifacts, not test execution logs.
65
- - For release approval and defect triage, continue with `sdtk-qa`.
66
-
67
- ## Validator Script
68
- - `scripts/validate_test_case_spec.py`
69
-
70
- ### Typical command
71
- ```powershell
72
- python "toolkit/skills/sdtk-test-case-spec/scripts/validate_test_case_spec.py" `
73
- --file "docs/qa/[FEATURE_KEY]_TEST_CASE.md"
74
- ```
@@ -1,129 +0,0 @@
1
- # TEST CASE CREATION RULES
2
- ## Canonical rules for `[FEATURE_KEY]_TEST_CASE.md`
3
-
4
- **Version:** 1.0.0
5
- **Last Updated:** 2026-02-25
6
-
7
- ---
8
-
9
- ## 1. Purpose
10
- - Standardize creation of feature test-case documents in markdown.
11
- - Mirror Excel-style worksheet layout while keeping output reviewable in `.md`.
12
- - Keep QA artifacts reusable across projects, domains, and screen sets.
13
-
14
- ---
15
-
16
- ## 2. Output Contract
17
- - Primary output file:
18
- - `docs/qa/[FEATURE_KEY]_TEST_CASE.md`
19
- - Optional language/project variant:
20
- - `docs/en/qa/[FEATURE_KEY]_TEST_CASE.md` (only when the project explicitly uses `docs/en/**`).
21
-
22
- ---
23
-
24
- ## 3. Required Section Order
25
- 1. Document metadata (`Document ID`, `Version`, `Date`, `Author`, `Status`)
26
- 2. `Statistic Summary (Excel-aligned)`
27
- 3. `Abbreviations`
28
- 4. `1. Scope`
29
- 5. `2. References`
30
- 6. `3. Test Environment and Common Data`
31
- 7. `4. Feature Coverage Matrix`
32
- 8. `5. Screen-based Test Cases (Excel-aligned)`
33
- 9. `6. Open Questions (for final freeze)`
34
- 10. `7. STC/UAT Note`
35
-
36
- Do not reorder these sections unless the user requests a different contract.
37
-
38
- ---
39
-
40
- ## 4. Statistic Summary Rules
41
- - Place summary near the top of the file (before detailed UTC/ITC tables).
42
- - Keep columns aligned with Excel `Statistic` logic:
43
- - `Num of Case`
44
- - `OK`
45
- - `NG`
46
- - `Not tested yet`
47
- - `Done (%)`
48
- - `Updated Date`
49
- - Compute:
50
- - `Not tested yet = Num of Case - (OK + NG)`
51
- - `Done (%) = (OK + NG) / Num of Case`
52
- - Include subtotal rows at minimum:
53
- - `Unit Test Total`
54
- - `Integration Test Total`
55
- - `Grand Total`
56
-
57
- ---
58
-
59
- ## 5. Screen-Based Worksheet Mapping
60
- - Use `screen-first` layout to mirror Excel tabs:
61
- - Each functional screen has a section (for example `SCH01`, `SCH02`, ...).
62
- - Each screen section can have 2 sub-sections:
63
- - `UTC` worksheet (name pattern: `[SCREEN_KEY]_UTC`)
64
- - `ITC` worksheet (name pattern: `[SCREEN_KEY]_ITC`)
65
- - Add one mapping table in section 5 that lists:
66
- - `Screen`
67
- - `Suggested Worksheet Pair`
68
- - `UTC Cases`
69
- - `ITC Cases`
70
- - `Notes`
71
-
72
- ---
73
-
74
- ## 6. Test Case Table Schema (Mandatory)
75
- - Use one unified 18-column schema for both UTC and ITC tables:
76
- - `No`
77
- - `Test Type`
78
- - `Test Perspective`
79
- - `Test Item`
80
- - `Precondition`
81
- - `Test Steps`
82
- - `Expected Result`
83
- - `Browser`
84
- - `Test Execution Result`
85
- - `Remarks`
86
- - `Reviewer`
87
- - `Review Date`
88
- - `OK/NG`
89
- - `Cause`
90
- - `Countermeasure`
91
- - `Owner`
92
- - `Completion Date`
93
- - `Confirmation`
94
-
95
- ---
96
-
97
- ## 7. Numbering and ID Policy
98
- - Keep a stable `No` for each test case row.
99
- - Do not renumber existing case IDs only for visual regrouping.
100
- - In screen-split sections, case IDs may be non-contiguous; this is allowed.
101
- - Summary/helper tables must keep contiguous `No` (`1,2,3,...`).
102
-
103
- ---
104
-
105
- ## 8. Open Questions (OQ) Policy
106
- - If expected behavior is unclear, create `OQ-xx` entries in section 6.
107
- - Do not assume behavior for:
108
- - permission matrix
109
- - conflict dialog/action semantics
110
- - API contract ambiguities
111
- - release-scope boundary
112
- - When resolved, keep question row and set status/remarks to resolved.
113
-
114
- ---
115
-
116
- ## 9. Language and Encoding
117
- - Default artifact language: English.
118
- - Keep original JP/VI labels when required by business/UI traceability (for example button labels).
119
- - File encoding must be UTF-8.
120
- - Avoid mojibake and placeholder tokens (`??`, `?????`) in final output.
121
-
122
- ---
123
-
124
- ## 10. Final Validation Checklist
125
- - Required sections exist and are in correct order.
126
- - Statistic totals equal sum of UTC/ITC rows.
127
- - Screen mapping table case counts match actual UTC/ITC table counts.
128
- - Scope explicitly states in-scope and out-of-scope boundaries.
129
- - Open questions are explicitly tracked with owner and impact.