@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.
- package/.cargo/config.toml +2 -0
- package/.claude-plugin/marketplace.json +18 -0
- package/.coderabbit.yaml +8 -0
- package/.codex/skills/gwt-fix-issue/scripts/inspect_issue.py +833 -0
- package/.dockerignore +63 -0
- package/.gitattributes +27 -0
- package/.husky/commit-msg +2 -0
- package/.husky/pre-commit +9 -0
- package/.husky/pre-push +12 -0
- package/.markdownlint.json +18 -0
- package/.markdownlintignore +2 -0
- package/Dockerfile +58 -0
- package/README.ja.md +161 -484
- package/README.md +164 -444
- package/cliff.toml +56 -0
- package/clippy.toml +2 -0
- package/cmake/ci-disable-native.cmake +16 -0
- package/codecov.yml +16 -0
- package/commitlint.config.cjs +107 -0
- package/deny.toml +35 -0
- package/docker-compose.yml +59 -0
- package/messages/errors.toml +52 -0
- package/package.json +12 -22
- package/rustfmt.toml +8 -0
- package/scripts/check-e2e-coverage-threshold.mjs +238 -0
- package/scripts/entrypoint.sh +36 -25
- package/scripts/install-linux-deps.sh +46 -0
- package/scripts/postinstall.js +79 -227
- package/scripts/release_issue_refs.py +317 -0
- package/scripts/run-local-backend-tests-on-commit.sh +15 -0
- package/scripts/run-local-e2e-coverage-on-commit.sh +69 -0
- package/scripts/run-local-e2e-on-commit.sh +60 -0
- package/scripts/test-all.sh +13 -0
- package/scripts/test_release_issue_refs.py +257 -0
- package/scripts/validate-skill-frontmatter.sh +108 -0
- package/scripts/verify-ci-node-toolchain.sh +76 -0
- package/scripts/verify-husky-hooks.sh +6 -0
- package/scripts/voice-eval.sh +48 -0
- package/tests/voice_eval/README.md +53 -0
- package/tests/voice_eval/manifest.template.json +55 -0
- package/tests/voice_eval/samples/.gitkeep +1 -0
- package/tests/voice_eval/script-ja.txt +10 -0
- package/vendor/ratatui-core/src/backend/test.rs +1077 -0
- package/vendor/ratatui-core/src/backend.rs +405 -0
- package/vendor/ratatui-core/src/buffer/assert.rs +71 -0
- package/vendor/ratatui-core/src/buffer/buffer.rs +1388 -0
- package/vendor/ratatui-core/src/buffer/cell.rs +377 -0
- package/vendor/ratatui-core/src/buffer.rs +9 -0
- package/vendor/ratatui-core/src/layout/alignment.rs +89 -0
- package/vendor/ratatui-core/src/layout/constraint.rs +526 -0
- package/vendor/ratatui-core/src/layout/direction.rs +63 -0
- package/vendor/ratatui-core/src/layout/flex.rs +212 -0
- package/vendor/ratatui-core/src/layout/layout.rs +2838 -0
- package/vendor/ratatui-core/src/layout/margin.rs +79 -0
- package/vendor/ratatui-core/src/layout/offset.rs +66 -0
- package/vendor/ratatui-core/src/layout/position.rs +253 -0
- package/vendor/ratatui-core/src/layout/rect/iter.rs +356 -0
- package/vendor/ratatui-core/src/layout/rect/ops.rs +136 -0
- package/vendor/ratatui-core/src/layout/rect.rs +1114 -0
- package/vendor/ratatui-core/src/layout/size.rs +147 -0
- package/vendor/ratatui-core/src/layout.rs +333 -0
- package/vendor/ratatui-core/src/lib.rs +82 -0
- package/vendor/ratatui-core/src/style/anstyle.rs +348 -0
- package/vendor/ratatui-core/src/style/color.rs +788 -0
- package/vendor/ratatui-core/src/style/palette/material.rs +608 -0
- package/vendor/ratatui-core/src/style/palette/tailwind.rs +653 -0
- package/vendor/ratatui-core/src/style/palette.rs +6 -0
- package/vendor/ratatui-core/src/style/palette_conversion.rs +82 -0
- package/vendor/ratatui-core/src/style/stylize.rs +668 -0
- package/vendor/ratatui-core/src/style.rs +1069 -0
- package/vendor/ratatui-core/src/symbols/bar.rs +51 -0
- package/vendor/ratatui-core/src/symbols/block.rs +51 -0
- package/vendor/ratatui-core/src/symbols/border.rs +709 -0
- package/vendor/ratatui-core/src/symbols/braille.rs +21 -0
- package/vendor/ratatui-core/src/symbols/half_block.rs +3 -0
- package/vendor/ratatui-core/src/symbols/line.rs +259 -0
- package/vendor/ratatui-core/src/symbols/marker.rs +82 -0
- package/vendor/ratatui-core/src/symbols/merge.rs +748 -0
- package/vendor/ratatui-core/src/symbols/pixel.rs +30 -0
- package/vendor/ratatui-core/src/symbols/scrollbar.rs +46 -0
- package/vendor/ratatui-core/src/symbols/shade.rs +5 -0
- package/vendor/ratatui-core/src/symbols.rs +15 -0
- package/vendor/ratatui-core/src/terminal/frame.rs +192 -0
- package/vendor/ratatui-core/src/terminal/terminal.rs +926 -0
- package/vendor/ratatui-core/src/terminal/viewport.rs +58 -0
- package/vendor/ratatui-core/src/terminal.rs +40 -0
- package/vendor/ratatui-core/src/text/grapheme.rs +84 -0
- package/vendor/ratatui-core/src/text/line.rs +1678 -0
- package/vendor/ratatui-core/src/text/masked.rs +149 -0
- package/vendor/ratatui-core/src/text/span.rs +904 -0
- package/vendor/ratatui-core/src/text/text.rs +1434 -0
- package/vendor/ratatui-core/src/text.rs +64 -0
- package/vendor/ratatui-core/src/widgets/stateful_widget.rs +193 -0
- package/vendor/ratatui-core/src/widgets/widget.rs +174 -0
- package/vendor/ratatui-core/src/widgets.rs +9 -0
- package/bin/gwt.js +0 -131
- package/scripts/postinstall.test.js +0 -71
- 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. 機能追加の前に要件とテストを更新してください。
|