@akiojin/gwt 6.30.3 → 9.0.1

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 (98) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.claude-plugin/marketplace.json +18 -0
  3. package/.coderabbit.yaml +8 -0
  4. package/.codex/skills/gwt-fix-issue/scripts/inspect_issue.py +833 -0
  5. package/.dockerignore +63 -0
  6. package/.gitattributes +27 -0
  7. package/.husky/commit-msg +2 -0
  8. package/.husky/pre-commit +9 -0
  9. package/.husky/pre-push +12 -0
  10. package/.markdownlint.json +18 -0
  11. package/.markdownlintignore +2 -0
  12. package/Dockerfile +58 -0
  13. package/README.ja.md +161 -484
  14. package/README.md +164 -444
  15. package/cliff.toml +56 -0
  16. package/clippy.toml +2 -0
  17. package/cmake/ci-disable-native.cmake +16 -0
  18. package/codecov.yml +16 -0
  19. package/commitlint.config.cjs +107 -0
  20. package/deny.toml +35 -0
  21. package/docker-compose.yml +59 -0
  22. package/messages/errors.toml +52 -0
  23. package/package.json +12 -22
  24. package/rustfmt.toml +8 -0
  25. package/scripts/check-e2e-coverage-threshold.mjs +238 -0
  26. package/scripts/entrypoint.sh +36 -25
  27. package/scripts/install-linux-deps.sh +46 -0
  28. package/scripts/postinstall.js +79 -227
  29. package/scripts/release_issue_refs.py +317 -0
  30. package/scripts/run-local-backend-tests-on-commit.sh +15 -0
  31. package/scripts/run-local-e2e-coverage-on-commit.sh +69 -0
  32. package/scripts/run-local-e2e-on-commit.sh +60 -0
  33. package/scripts/test-all.sh +13 -0
  34. package/scripts/test_release_issue_refs.py +257 -0
  35. package/scripts/validate-skill-frontmatter.sh +108 -0
  36. package/scripts/verify-ci-node-toolchain.sh +76 -0
  37. package/scripts/verify-husky-hooks.sh +6 -0
  38. package/scripts/voice-eval.sh +48 -0
  39. package/tests/voice_eval/README.md +53 -0
  40. package/tests/voice_eval/manifest.template.json +55 -0
  41. package/tests/voice_eval/samples/.gitkeep +1 -0
  42. package/tests/voice_eval/script-ja.txt +10 -0
  43. package/vendor/ratatui-core/src/backend/test.rs +1077 -0
  44. package/vendor/ratatui-core/src/backend.rs +405 -0
  45. package/vendor/ratatui-core/src/buffer/assert.rs +71 -0
  46. package/vendor/ratatui-core/src/buffer/buffer.rs +1388 -0
  47. package/vendor/ratatui-core/src/buffer/cell.rs +377 -0
  48. package/vendor/ratatui-core/src/buffer.rs +9 -0
  49. package/vendor/ratatui-core/src/layout/alignment.rs +89 -0
  50. package/vendor/ratatui-core/src/layout/constraint.rs +526 -0
  51. package/vendor/ratatui-core/src/layout/direction.rs +63 -0
  52. package/vendor/ratatui-core/src/layout/flex.rs +212 -0
  53. package/vendor/ratatui-core/src/layout/layout.rs +2838 -0
  54. package/vendor/ratatui-core/src/layout/margin.rs +79 -0
  55. package/vendor/ratatui-core/src/layout/offset.rs +66 -0
  56. package/vendor/ratatui-core/src/layout/position.rs +253 -0
  57. package/vendor/ratatui-core/src/layout/rect/iter.rs +356 -0
  58. package/vendor/ratatui-core/src/layout/rect/ops.rs +136 -0
  59. package/vendor/ratatui-core/src/layout/rect.rs +1114 -0
  60. package/vendor/ratatui-core/src/layout/size.rs +147 -0
  61. package/vendor/ratatui-core/src/layout.rs +333 -0
  62. package/vendor/ratatui-core/src/lib.rs +82 -0
  63. package/vendor/ratatui-core/src/style/anstyle.rs +348 -0
  64. package/vendor/ratatui-core/src/style/color.rs +788 -0
  65. package/vendor/ratatui-core/src/style/palette/material.rs +608 -0
  66. package/vendor/ratatui-core/src/style/palette/tailwind.rs +653 -0
  67. package/vendor/ratatui-core/src/style/palette.rs +6 -0
  68. package/vendor/ratatui-core/src/style/palette_conversion.rs +82 -0
  69. package/vendor/ratatui-core/src/style/stylize.rs +668 -0
  70. package/vendor/ratatui-core/src/style.rs +1069 -0
  71. package/vendor/ratatui-core/src/symbols/bar.rs +51 -0
  72. package/vendor/ratatui-core/src/symbols/block.rs +51 -0
  73. package/vendor/ratatui-core/src/symbols/border.rs +709 -0
  74. package/vendor/ratatui-core/src/symbols/braille.rs +21 -0
  75. package/vendor/ratatui-core/src/symbols/half_block.rs +3 -0
  76. package/vendor/ratatui-core/src/symbols/line.rs +259 -0
  77. package/vendor/ratatui-core/src/symbols/marker.rs +82 -0
  78. package/vendor/ratatui-core/src/symbols/merge.rs +748 -0
  79. package/vendor/ratatui-core/src/symbols/pixel.rs +30 -0
  80. package/vendor/ratatui-core/src/symbols/scrollbar.rs +46 -0
  81. package/vendor/ratatui-core/src/symbols/shade.rs +5 -0
  82. package/vendor/ratatui-core/src/symbols.rs +15 -0
  83. package/vendor/ratatui-core/src/terminal/frame.rs +192 -0
  84. package/vendor/ratatui-core/src/terminal/terminal.rs +926 -0
  85. package/vendor/ratatui-core/src/terminal/viewport.rs +58 -0
  86. package/vendor/ratatui-core/src/terminal.rs +40 -0
  87. package/vendor/ratatui-core/src/text/grapheme.rs +84 -0
  88. package/vendor/ratatui-core/src/text/line.rs +1678 -0
  89. package/vendor/ratatui-core/src/text/masked.rs +149 -0
  90. package/vendor/ratatui-core/src/text/span.rs +904 -0
  91. package/vendor/ratatui-core/src/text/text.rs +1434 -0
  92. package/vendor/ratatui-core/src/text.rs +64 -0
  93. package/vendor/ratatui-core/src/widgets/stateful_widget.rs +193 -0
  94. package/vendor/ratatui-core/src/widgets/widget.rs +174 -0
  95. package/vendor/ratatui-core/src/widgets.rs +9 -0
  96. package/bin/gwt.js +0 -131
  97. package/scripts/postinstall.test.js +0 -71
  98. package/scripts/release-download.js +0 -66
@@ -0,0 +1,257 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.util
4
+ import json
5
+ import sys
6
+ import unittest
7
+ from pathlib import Path
8
+ from textwrap import dedent
9
+
10
+ MODULE_PATH = Path(__file__).with_name("release_issue_refs.py")
11
+ MODULE_SPEC = importlib.util.spec_from_file_location("release_issue_refs", MODULE_PATH)
12
+ assert MODULE_SPEC is not None
13
+ assert MODULE_SPEC.loader is not None
14
+ release_issue_refs = importlib.util.module_from_spec(MODULE_SPEC)
15
+ sys.modules[MODULE_SPEC.name] = release_issue_refs
16
+ MODULE_SPEC.loader.exec_module(release_issue_refs)
17
+
18
+ PR_1585_BODY = dedent(
19
+ """\
20
+ ## Summary
21
+
22
+ - Refit and refresh the terminal when focus or visibility returns so Windows terminal corruption can recover without manual tab switching.
23
+
24
+ ## Closing Issues
25
+
26
+ None
27
+
28
+ ## Related Issues / Links
29
+
30
+ - #1457
31
+ """
32
+ )
33
+
34
+
35
+ class FakeRunner:
36
+ def __init__(self, outputs: dict[tuple[str, ...], str]) -> None:
37
+ self.outputs = outputs
38
+
39
+ def __call__(self, args: list[str] | tuple[str, ...]) -> str:
40
+ key = tuple(args)
41
+ if key not in self.outputs:
42
+ raise AssertionError(f"Unexpected command: {key!r}")
43
+ return self.outputs[key]
44
+
45
+
46
+ class ReleaseIssueRefsTests(unittest.TestCase):
47
+ def test_parse_pr_body_collects_keywords_and_closing_section(self) -> None:
48
+ body = dedent(
49
+ """\
50
+ ## Summary
51
+
52
+ This change resolves #2000 and keeps release notes aligned.
53
+
54
+ ## Closing Issues
55
+
56
+ #2001
57
+ Closes #2002
58
+
59
+ ## Related Issues / Links
60
+
61
+ - #2003
62
+ - https://example.com/task
63
+ """
64
+ )
65
+
66
+ result = release_issue_refs.parse_pr_body_refs(body, pr_number=1234)
67
+
68
+ self.assertEqual([2000, 2001, 2002], result.auto_close_issues)
69
+ self.assertEqual([2003], result.reference_only_issues)
70
+ self.assertEqual(
71
+ [
72
+ "PR #1234 references #2003 only in `Related Issues / Links`; "
73
+ "they will not auto-close on release."
74
+ ],
75
+ result.warnings,
76
+ )
77
+
78
+ def test_parse_pr_body_flags_related_only_refs(self) -> None:
79
+ result = release_issue_refs.parse_pr_body_refs(PR_1585_BODY, pr_number=1585)
80
+
81
+ self.assertEqual([], result.auto_close_issues)
82
+ self.assertEqual([1457], result.reference_only_issues)
83
+ self.assertEqual(
84
+ [
85
+ "PR #1585 references #1457 only in `Related Issues / Links`; "
86
+ "they will not auto-close on release."
87
+ ],
88
+ result.warnings,
89
+ )
90
+
91
+ def test_collect_release_issue_refs_keeps_reference_only_issues_visible(self) -> None:
92
+ runner = FakeRunner(
93
+ {
94
+ (
95
+ "git",
96
+ "log",
97
+ "--pretty=%s",
98
+ "--no-merges",
99
+ "v8.6.0..HEAD",
100
+ ): (
101
+ "fix(gui): refresh terminal when focus returns (#1585)\n"
102
+ "fix: hook error (#1589)\n"
103
+ ),
104
+ ("git", "log", "--merges", "--pretty=%s", "v8.6.0..HEAD"): "",
105
+ ("gh", "api", "repos/akiojin/gwt/issues/1585"): '{"pull_request":{"url":"https://example.com/pr/1585"}}',
106
+ (
107
+ "gh",
108
+ "pr",
109
+ "view",
110
+ "1585",
111
+ "--repo",
112
+ "akiojin/gwt",
113
+ "--json",
114
+ "body",
115
+ ): json.dumps({"body": PR_1585_BODY}),
116
+ ("gh", "api", "repos/akiojin/gwt/issues/1589"): "{}",
117
+ }
118
+ )
119
+
120
+ result = release_issue_refs.collect_release_issue_refs(
121
+ "v8.6.0..HEAD",
122
+ repo_slug="akiojin/gwt",
123
+ runner=runner,
124
+ )
125
+
126
+ self.assertEqual([1589], result.auto_close_issues)
127
+ self.assertEqual([1457], result.reference_only_issues)
128
+ self.assertEqual(
129
+ [
130
+ "Reference-only issues detected: #1457. Add them to `Closing Issues` if they should auto-close.",
131
+ "PR #1585 references #1457 only in `Related Issues / Links`; they will not auto-close on release.",
132
+ ],
133
+ result.warnings,
134
+ )
135
+ self.assertEqual(["pr", "issue"], [ref.kind for ref in result.refs])
136
+
137
+ def test_gwt_spec_direct_issue_moved_to_reference_only(self) -> None:
138
+ """Direct issue ref with gwt-spec label moves to reference_only."""
139
+ runner = FakeRunner(
140
+ {
141
+ (
142
+ "git",
143
+ "log",
144
+ "--pretty=%s",
145
+ "--no-merges",
146
+ "v8.14.0..HEAD",
147
+ ): "feat(spec): adopt artifact-first issue workflow (#1700)\n",
148
+ ("git", "log", "--merges", "--pretty=%s", "v8.14.0..HEAD"): "",
149
+ ("gh", "api", "repos/akiojin/gwt/issues/1700"): json.dumps(
150
+ {"labels": [{"name": "gwt-spec"}, {"name": "enhancement"}]}
151
+ ),
152
+ }
153
+ )
154
+
155
+ result = release_issue_refs.collect_release_issue_refs(
156
+ "v8.14.0..HEAD",
157
+ repo_slug="akiojin/gwt",
158
+ runner=runner,
159
+ )
160
+
161
+ self.assertEqual([], result.auto_close_issues)
162
+ self.assertEqual([1700], result.reference_only_issues)
163
+ self.assertIn(
164
+ "gwt-spec issues moved to reference-only: #1700. "
165
+ "gwt-spec issues are never auto-closed by releases.",
166
+ result.warnings,
167
+ )
168
+
169
+ def test_gwt_spec_issue_via_pr_closing_moved_to_reference_only(self) -> None:
170
+ """PR body `Closes #N` where N has gwt-spec label moves N to reference_only."""
171
+ pr_body = dedent(
172
+ """\
173
+ ## Closing Issues
174
+
175
+ #1700
176
+
177
+ ## Related Issues / Links
178
+
179
+ None"""
180
+ )
181
+ runner = FakeRunner(
182
+ {
183
+ (
184
+ "git",
185
+ "log",
186
+ "--pretty=%s",
187
+ "--no-merges",
188
+ "v8.14.0..HEAD",
189
+ ): "fix(spec): harden issue migration retries (#1701)\n",
190
+ ("git", "log", "--merges", "--pretty=%s", "v8.14.0..HEAD"): "",
191
+ ("gh", "api", "repos/akiojin/gwt/issues/1701"): json.dumps(
192
+ {"pull_request": {"url": "https://example.com/pr/1701"}}
193
+ ),
194
+ (
195
+ "gh",
196
+ "pr",
197
+ "view",
198
+ "1701",
199
+ "--repo",
200
+ "akiojin/gwt",
201
+ "--json",
202
+ "body",
203
+ ): json.dumps({"body": pr_body}),
204
+ ("gh", "api", "repos/akiojin/gwt/issues/1700"): json.dumps(
205
+ {"labels": [{"name": "gwt-spec"}]}
206
+ ),
207
+ }
208
+ )
209
+
210
+ result = release_issue_refs.collect_release_issue_refs(
211
+ "v8.14.0..HEAD",
212
+ repo_slug="akiojin/gwt",
213
+ runner=runner,
214
+ )
215
+
216
+ self.assertEqual([], result.auto_close_issues)
217
+ self.assertEqual([1700], result.reference_only_issues)
218
+ self.assertIn(
219
+ "gwt-spec issues moved to reference-only: #1700. "
220
+ "gwt-spec issues are never auto-closed by releases.",
221
+ result.warnings,
222
+ )
223
+
224
+ def test_non_gwt_spec_issue_stays_in_auto_close(self) -> None:
225
+ """Non-gwt-spec issue stays in auto_close."""
226
+ runner = FakeRunner(
227
+ {
228
+ (
229
+ "git",
230
+ "log",
231
+ "--pretty=%s",
232
+ "--no-merges",
233
+ "v8.14.0..HEAD",
234
+ ): "fix: hook error (#1589)\n",
235
+ ("git", "log", "--merges", "--pretty=%s", "v8.14.0..HEAD"): "",
236
+ ("gh", "api", "repos/akiojin/gwt/issues/1589"): json.dumps(
237
+ {"labels": [{"name": "bug"}]}
238
+ ),
239
+ }
240
+ )
241
+
242
+ result = release_issue_refs.collect_release_issue_refs(
243
+ "v8.14.0..HEAD",
244
+ repo_slug="akiojin/gwt",
245
+ runner=runner,
246
+ )
247
+
248
+ self.assertEqual([1589], result.auto_close_issues)
249
+ self.assertEqual([], result.reference_only_issues)
250
+ gwt_spec_warnings = [
251
+ w for w in result.warnings if "gwt-spec" in w
252
+ ]
253
+ self.assertEqual([], gwt_spec_warnings)
254
+
255
+
256
+ if __name__ == "__main__":
257
+ unittest.main()
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6
+ cd "$ROOT_DIR"
7
+
8
+ TMP_DIR="$(mktemp -d)"
9
+ trap 'rm -rf "$TMP_DIR"' EXIT
10
+
11
+ MANIFEST="$TMP_DIR/frontmatter-manifest.tsv"
12
+ FAILURES=0
13
+
14
+ extract_frontmatter() {
15
+ local input_file="$1"
16
+ local output_file="$2"
17
+
18
+ awk '
19
+ BEGIN {
20
+ state = 0
21
+ }
22
+ {
23
+ line = $0
24
+ sub(/\r$/, "", line)
25
+
26
+ if (NR == 1) {
27
+ if (line != "---") {
28
+ exit 2
29
+ }
30
+ state = 1
31
+ next
32
+ }
33
+
34
+ if (state == 1 && line == "---") {
35
+ state = 2
36
+ exit 0
37
+ }
38
+
39
+ if (state == 1) {
40
+ print line
41
+ }
42
+ }
43
+ END {
44
+ if (NR == 0) {
45
+ exit 2
46
+ }
47
+ if (state != 2) {
48
+ exit 3
49
+ }
50
+ }
51
+ ' "$input_file" > "$output_file"
52
+ }
53
+
54
+ SKILL_FILES=()
55
+ while IFS= read -r skill_file; do
56
+ SKILL_FILES+=("$skill_file")
57
+ done < <(git ls-files '*SKILL.md')
58
+
59
+ for index in "${!SKILL_FILES[@]}"; do
60
+ relative_path="${SKILL_FILES[$index]}"
61
+ if [ ! -f "$relative_path" ]; then
62
+ echo "$relative_path: tracked SKILL.md is missing from working tree" >&2
63
+ FAILURES=1
64
+ continue
65
+ fi
66
+ frontmatter_file="$TMP_DIR/frontmatter-$index.yaml"
67
+
68
+ if extract_frontmatter "$relative_path" "$frontmatter_file"; then
69
+ printf '%s\t%s\n' "$frontmatter_file" "$relative_path" >> "$MANIFEST"
70
+ continue
71
+ fi
72
+
73
+ case $? in
74
+ 2)
75
+ echo "$relative_path: missing YAML frontmatter block" >&2
76
+ ;;
77
+ 3)
78
+ echo "$relative_path: missing closing YAML frontmatter delimiter" >&2
79
+ ;;
80
+ *)
81
+ echo "$relative_path: failed to extract YAML frontmatter" >&2
82
+ ;;
83
+ esac
84
+
85
+ FAILURES=1
86
+ done
87
+
88
+ if [ -s "$MANIFEST" ]; then
89
+ if ! MANIFEST="$MANIFEST" pnpm dlx -s --package js-yaml -c '
90
+ status=0
91
+ while IFS="$(printf "\t")" read -r yaml_file source_path; do
92
+ if ! output=$(js-yaml -c "$yaml_file" 2>&1 >/dev/null); then
93
+ printf "%s: invalid YAML frontmatter: %s\n" "$source_path" "$output" >&2
94
+ status=1
95
+ fi
96
+ done < "$MANIFEST"
97
+ exit "$status"
98
+ '; then
99
+ FAILURES=1
100
+ fi
101
+ fi
102
+
103
+ if [ "$FAILURES" -ne 0 ]; then
104
+ echo "SKILL.md frontmatter validation failed." >&2
105
+ exit 1
106
+ fi
107
+
108
+ echo "Validated ${#SKILL_FILES[@]} SKILL.md frontmatter block(s)."
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6
+
7
+ fail() {
8
+ echo "CI node toolchain verification failed: $1" >&2
9
+ exit 1
10
+ }
11
+
12
+ require_file() {
13
+ if [ ! -f "$1" ]; then
14
+ fail "Missing file: $1"
15
+ fi
16
+ }
17
+
18
+ require_not_file() {
19
+ if [ -f "$1" ]; then
20
+ fail "Unexpected file exists: $1"
21
+ fi
22
+ }
23
+
24
+ require_contains() {
25
+ local file="$1"
26
+ local pattern="$2"
27
+ if ! grep -Fq "$pattern" "$file"; then
28
+ fail "Expected pattern not found in $file: $pattern"
29
+ fi
30
+ }
31
+
32
+ require_not_contains() {
33
+ local file="$1"
34
+ local pattern="$2"
35
+ if grep -Fq "$pattern" "$file"; then
36
+ fail "Unexpected pattern found in $file: $pattern"
37
+ fi
38
+ }
39
+
40
+ require_file "$ROOT_DIR/pnpm-lock.yaml"
41
+ require_not_file "$ROOT_DIR/package-lock.json"
42
+ require_file "$ROOT_DIR/package.json"
43
+
44
+ require_contains "$ROOT_DIR/package.json" "\"packageManager\": \"pnpm@10.29.2\""
45
+
46
+ require_file "$ROOT_DIR/gwt-gui/package.json"
47
+ require_contains "$ROOT_DIR/gwt-gui/package.json" "\"packageManager\": \"pnpm@10.29.2\""
48
+ require_file "$ROOT_DIR/gwt-gui/pnpm-lock.yaml"
49
+ require_not_file "$ROOT_DIR/gwt-gui/package-lock.json"
50
+ require_contains "$ROOT_DIR/.gitignore" "gwt-gui/package-lock.json"
51
+
52
+ WORKFLOW="$ROOT_DIR/.github/workflows/lint.yml"
53
+ require_file "$WORKFLOW"
54
+
55
+ require_not_contains "$WORKFLOW" "npm install -g"
56
+ require_contains "$WORKFLOW" "corepack prepare pnpm@10.29.2 --activate"
57
+ require_contains "$WORKFLOW" "pnpm lint:skills"
58
+ require_contains "$WORKFLOW" "pnpm dlx @commitlint/cli@20.4.1"
59
+
60
+ TEST_WORKFLOW="$ROOT_DIR/.github/workflows/test.yml"
61
+ require_file "$TEST_WORKFLOW"
62
+
63
+ require_not_contains "$TEST_WORKFLOW" "cd gwt-gui && npm ci"
64
+ require_not_contains "$TEST_WORKFLOW" "cd gwt-gui && npm run check"
65
+ require_not_contains "$TEST_WORKFLOW" "cd gwt-gui && npm run build"
66
+ require_contains "$TEST_WORKFLOW" "cd gwt-gui && pnpm install --frozen-lockfile"
67
+ require_contains "$TEST_WORKFLOW" "cd gwt-gui && pnpm run check"
68
+ require_contains "$TEST_WORKFLOW" "cd gwt-gui && pnpm run build"
69
+
70
+ RELEASE_WORKFLOW="$ROOT_DIR/.github/workflows/release.yml"
71
+ require_file "$RELEASE_WORKFLOW"
72
+
73
+ require_not_contains "$RELEASE_WORKFLOW" "cd gwt-gui && npm ci"
74
+ require_contains "$RELEASE_WORKFLOW" "cd gwt-gui && pnpm install --frozen-lockfile"
75
+
76
+ echo "CI node toolchain verification passed."
@@ -37,17 +37,23 @@ require_not_contains() {
37
37
 
38
38
  require_file "$PACKAGE_JSON"
39
39
  require_contains "$PACKAGE_JSON" '"prepare": "test -n \"$CI\" || bunx husky install"'
40
+ require_contains "$PACKAGE_JSON" "\"lint:skills\": \"bash scripts/validate-skill-frontmatter.sh\""
40
41
  require_contains "$PACKAGE_JSON" "\"lint:husky\": \"bash scripts/verify-husky-hooks.sh\""
41
42
 
42
43
  require_file "$PRE_PUSH"
43
44
  require_contains "$PRE_PUSH" "cargo clippy --all-targets --all-features -- -D warnings"
44
45
  require_contains "$PRE_PUSH" "cargo fmt --all -- --check"
45
46
  require_contains "$PRE_PUSH" "bunx --bun markdownlint-cli . --config .markdownlint.json --ignore target --ignore CHANGELOG.md"
47
+ require_contains "$PRE_PUSH" "pnpm lint:skills"
46
48
 
47
49
  require_file "$COMMIT_MSG"
48
50
  require_contains "$COMMIT_MSG" 'bunx --package @commitlint/cli commitlint --edit "$1"'
49
51
 
50
52
  if [ -f "$PRE_COMMIT" ]; then
53
+ require_contains "$PRE_COMMIT" "pnpm lint:skills"
54
+ require_contains "$PRE_COMMIT" "bash scripts/run-local-backend-tests-on-commit.sh"
55
+ require_contains "$PRE_COMMIT" "bash scripts/run-local-e2e-on-commit.sh"
56
+ require_contains "$PRE_COMMIT" "bash scripts/run-local-e2e-coverage-on-commit.sh"
51
57
  require_not_contains "$PRE_COMMIT" "cargo clippy --all-targets --all-features -- -D warnings"
52
58
  require_not_contains "$PRE_COMMIT" "cargo fmt --all -- --check"
53
59
  require_not_contains "$PRE_COMMIT" "markdownlint-cli"
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ MANIFEST_PATH="${GWT_VOICE_EVAL_MANIFEST:-$ROOT_DIR/tests/voice_eval/manifest.json}"
6
+ OUTPUT_PATH="${GWT_VOICE_EVAL_OUTPUT:-$ROOT_DIR/tests/voice_eval/latest-report.json}"
7
+ BASELINE_PATH="${GWT_VOICE_EVAL_BASELINE:-$ROOT_DIR/tests/voice_eval/baseline.json}"
8
+ QUALITIES="${GWT_VOICE_EVAL_QUALITIES:-fast,balanced,accurate}"
9
+ MODELS="${GWT_VOICE_EVAL_MODELS:-}"
10
+
11
+ if [[ ! -f "$MANIFEST_PATH" ]]; then
12
+ echo "voice-eval: manifest not found: $MANIFEST_PATH" >&2
13
+ echo "Create one from: $ROOT_DIR/tests/voice_eval/manifest.template.json" >&2
14
+ exit 1
15
+ fi
16
+
17
+ EXTRA_ARGS=()
18
+ if [[ -f "$BASELINE_PATH" ]]; then
19
+ EXTRA_ARGS+=(--baseline "$BASELINE_PATH")
20
+ fi
21
+
22
+ echo "[voice-eval] manifest: $MANIFEST_PATH"
23
+ echo "[voice-eval] output: $OUTPUT_PATH"
24
+ echo "[voice-eval] qualities: $QUALITIES"
25
+ if [[ -n "$MODELS" ]]; then
26
+ echo "[voice-eval] models: $MODELS"
27
+ fi
28
+
29
+ CMD=(
30
+ cargo run -p gwt-tauri --bin voice_eval --
31
+ --manifest "$MANIFEST_PATH"
32
+ --output "$OUTPUT_PATH"
33
+ )
34
+
35
+ if [[ -n "$QUALITIES" ]]; then
36
+ CMD+=(--qualities "$QUALITIES")
37
+ fi
38
+ if [[ -n "$MODELS" ]]; then
39
+ CMD+=(--models "$MODELS")
40
+ fi
41
+ if [[ ${#EXTRA_ARGS[@]} -gt 0 ]]; then
42
+ CMD+=("${EXTRA_ARGS[@]}")
43
+ fi
44
+ if [[ $# -gt 0 ]]; then
45
+ CMD+=("$@")
46
+ fi
47
+
48
+ "${CMD[@]}"
@@ -0,0 +1,53 @@
1
+ # Voice Evaluation Dataset
2
+
3
+ This directory contains local assets for offline voice accuracy checks.
4
+
5
+ ## Files
6
+
7
+ - `script-ja.txt`: Japanese recording script for consistent test utterances.
8
+ - `manifest.template.json`: template for your local `manifest.json`.
9
+ - `samples/`: place your recorded WAV files here.
10
+
11
+ ## Quick Start
12
+
13
+ 1. Copy template:
14
+ ```bash
15
+ cp tests/voice_eval/manifest.template.json tests/voice_eval/manifest.json
16
+ ```
17
+
18
+ 1. Record your voice using `tests/voice_eval/script-ja.txt` and place WAV files under:
19
+ - `tests/voice_eval/samples/001.wav`
20
+ - `tests/voice_eval/samples/002.wav`
21
+ - ...
22
+
23
+ 1. Run evaluation:
24
+ ```bash
25
+ scripts/voice-eval.sh
26
+ ```
27
+
28
+ 1. Run additional popular models:
29
+ ```bash
30
+ scripts/voice-eval.sh --models popular-lite
31
+ ```
32
+
33
+ 1. Run full-size popular models (large downloads):
34
+ ```bash
35
+ scripts/voice-eval.sh --models popular
36
+ ```
37
+
38
+ 1. Optional baseline update (after you approve current quality):
39
+ ```bash
40
+ cp tests/voice_eval/latest-report.json tests/voice_eval/baseline.json
41
+ ```
42
+
43
+ ## WAV Requirements
44
+
45
+ - PCM WAV
46
+ - mono or stereo (stereo will be downmixed)
47
+ - recommended sample rate: 16kHz or 48kHz
48
+
49
+ ## Notes
50
+
51
+ - `manifest.json`, `baseline.json`, `latest-report.json`, and `samples/*.wav` are ignored by git.
52
+ - The evaluator computes WER/CER and compares against baseline when available.
53
+ - A versioned summary snapshot is tracked at `docs/voice-eval-benchmarks.md`.
@@ -0,0 +1,55 @@
1
+ {
2
+ "default_language": "ja",
3
+ "samples": [
4
+ {
5
+ "id": "ja-001",
6
+ "audio_path": "samples/001.wav",
7
+ "reference": "おはようございます。今日の進捗を共有します。"
8
+ },
9
+ {
10
+ "id": "ja-002",
11
+ "audio_path": "samples/002.wav",
12
+ "reference": "新しいブランチを作成して、テストを先に追加します。"
13
+ },
14
+ {
15
+ "id": "ja-003",
16
+ "audio_path": "samples/003.wav",
17
+ "reference": "エラーの再現手順を確認してから修正に入ります。"
18
+ },
19
+ {
20
+ "id": "ja-004",
21
+ "audio_path": "samples/004.wav",
22
+ "reference": "ターミナルのログを保存して、原因を切り分けます。"
23
+ },
24
+ {
25
+ "id": "ja-005",
26
+ "audio_path": "samples/005.wav",
27
+ "reference": "プルリクエストには変更理由と影響範囲を明記します。"
28
+ },
29
+ {
30
+ "id": "ja-006",
31
+ "audio_path": "samples/006.wav",
32
+ "reference": "この仕様は後方互換性を維持しなければなりません。"
33
+ },
34
+ {
35
+ "id": "ja-007",
36
+ "audio_path": "samples/007.wav",
37
+ "reference": "ゼロダウンタイムでデプロイできるか検証しましょう。"
38
+ },
39
+ {
40
+ "id": "ja-008",
41
+ "audio_path": "samples/008.wav",
42
+ "reference": "明日のミーティングは午前九時に開始します。"
43
+ },
44
+ {
45
+ "id": "ja-009",
46
+ "audio_path": "samples/009.wav",
47
+ "reference": "ユーザーが迷わないように文言を短くします。"
48
+ },
49
+ {
50
+ "id": "ja-010",
51
+ "audio_path": "samples/010.wav",
52
+ "reference": "機能追加の前に要件とテストを更新してください。"
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,10 @@
1
+ 1. おはようございます。今日の進捗を共有します。
2
+ 2. 新しいブランチを作成して、テストを先に追加します。
3
+ 3. エラーの再現手順を確認してから修正に入ります。
4
+ 4. ターミナルのログを保存して、原因を切り分けます。
5
+ 5. プルリクエストには変更理由と影響範囲を明記します。
6
+ 6. この仕様は後方互換性を維持しなければなりません。
7
+ 7. ゼロダウンタイムでデプロイできるか検証しましょう。
8
+ 8. 明日のミーティングは午前九時に開始します。
9
+ 9. ユーザーが迷わないように文言を短くします。
10
+ 10. 機能追加の前に要件とテストを更新してください。