@bendyline/gilde 0.1.4 → 0.1.5

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 (141) hide show
  1. package/README.md +1 -0
  2. package/data/chat-models/de/deepseek-v4-flash-284b-q2/manifest.json +4 -3
  3. package/data/chat-models/de/deepseek-v4-flash-284b-q4/manifest.json +4 -3
  4. package/data/chat-models/ge/gemma4-12b-q4/manifest.json +20 -11
  5. package/data/chat-models/ge/gemma4-12b-q4/versions/1.1.0/manifest.json +2 -8
  6. package/data/chat-models/ge/gemma4-12b-q4/versions/1.1.2/manifest.json +78 -0
  7. package/data/chat-models/ge/gemma4-12b-q8/manifest.json +23 -14
  8. package/data/chat-models/ge/gemma4-12b-q8/versions/1.0.0/manifest.json +2 -8
  9. package/data/chat-models/ge/gemma4-12b-q8/versions/1.0.2/manifest.json +78 -0
  10. package/data/chat-models/ge/gemma4-26b-q4/manifest.json +55 -46
  11. package/data/chat-models/ge/gemma4-26b-q4/versions/1.2.0/manifest.json +2 -8
  12. package/data/chat-models/ge/gemma4-26b-q4/versions/1.2.1/manifest.json +81 -0
  13. package/data/chat-models/ge/gemma4-31b-q4/manifest.json +36 -28
  14. package/data/chat-models/ge/gemma4-31b-q4/versions/1.2.0/manifest.json +2 -8
  15. package/data/chat-models/ge/gemma4-31b-q4/versions/1.2.1/manifest.json +87 -0
  16. package/data/chat-models/ge/gemma4-e2b-q8/manifest.json +76 -69
  17. package/data/chat-models/ge/gemma4-e2b-q8/versions/1.1.0/manifest.json +2 -8
  18. package/data/chat-models/ge/gemma4-e2b-q8/versions/1.1.2/manifest.json +71 -0
  19. package/data/chat-models/ge/gemma4-e4b-q8/manifest.json +71 -78
  20. package/data/chat-models/ge/gemma4-e4b-q8/versions/1.1.0/manifest.json +3 -9
  21. package/data/chat-models/ge/gemma4-e4b-q8/versions/1.1.2/manifest.json +71 -0
  22. package/data/chat-models/index.json +1 -1
  23. package/data/chat-models/la/laguna-s-2.1-118b-q4/manifest.json +17 -17
  24. package/data/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.1/manifest.json +124 -0
  25. package/data/chat-models/la/laguna-s-2.1-118b-q8/manifest.json +7 -7
  26. package/data/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.1/manifest.json +174 -0
  27. package/data/chat-models/mi/mistral-medium-3.5-128b-q4/manifest.json +4 -17
  28. package/data/chat-models/mi/mistral-medium-3.5-128b-q4/versions/1.0.0/manifest.json +2 -12
  29. package/data/chat-models/ne/nemotron3-nano-30b-q4/manifest.json +5 -0
  30. package/data/chat-models/qw/qwen3.5-122b-a10b-q4/manifest.json +27 -19
  31. package/data/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.1/manifest.json +164 -0
  32. package/data/chat-models/qw/qwen3.5-2b-q4/manifest.json +79 -77
  33. package/data/chat-models/qw/qwen3.5-2b-q4/versions/1.1.0/manifest.json +2 -8
  34. package/data/chat-models/qw/qwen3.5-2b-q4/versions/1.1.2/manifest.json +76 -0
  35. package/data/chat-models/qw/qwen3.5-4b-q4/manifest.json +79 -77
  36. package/data/chat-models/qw/qwen3.5-4b-q4/versions/1.1.0/manifest.json +2 -8
  37. package/data/chat-models/qw/qwen3.5-4b-q4/versions/1.1.2/manifest.json +76 -0
  38. package/data/chat-models/qw/qwen3.5-9b-q4/manifest.json +87 -85
  39. package/data/chat-models/qw/qwen3.5-9b-q4/versions/1.1.0/manifest.json +2 -8
  40. package/data/chat-models/qw/qwen3.5-9b-q4/versions/1.1.2/manifest.json +81 -0
  41. package/data/chat-models/qw/qwen3.6-27b-q4/manifest.json +99 -97
  42. package/data/chat-models/qw/qwen3.6-27b-q4/versions/1.1.0/manifest.json +2 -8
  43. package/data/chat-models/qw/qwen3.6-27b-q4/versions/1.1.4/manifest.json +91 -0
  44. package/data/chat-models/qw/qwen3.6-27b-q8/manifest.json +16 -12
  45. package/data/chat-models/qw/qwen3.6-27b-q8/versions/1.0.0/manifest.json +2 -8
  46. package/data/chat-models/qw/qwen3.6-27b-q8/versions/1.0.2/manifest.json +103 -0
  47. package/data/chat-models/qw/qwen3.6-35b-a3b-q4/manifest.json +18 -14
  48. package/data/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.0/manifest.json +2 -8
  49. package/data/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.1/manifest.json +93 -0
  50. package/data/chat-models/qw/qwen3.6-35b-a3b-q8/manifest.json +16 -12
  51. package/data/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.0/manifest.json +2 -8
  52. package/data/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.1/manifest.json +113 -0
  53. package/data/craftbook-templates/bu/bug-fix-tdd/versions/1.0.1/test.json +0 -5
  54. package/data/craftbook-templates/bu/build-loop/versions/1.1.0/craftbook.json +65 -0
  55. package/data/craftbook-templates/bu/build-loop/versions/1.1.0/test.json +121 -0
  56. package/data/craftbook-templates/ch/character-sheet/versions/1.0.0/test.json +1 -2
  57. package/data/craftbook-templates/ch/character-turnaround/versions/1.0.0/test.json +1 -2
  58. package/data/craftbook-templates/cl/cli-tool/versions/1.1.0/craftbook.json +139 -0
  59. package/data/craftbook-templates/cl/cli-tool/versions/1.1.0/test.json +128 -0
  60. package/data/craftbook-templates/cr/crossword-forge/manifest.json +1 -2
  61. package/data/craftbook-templates/de/deep-security-review/versions/1.1.0/craftbook.json +201 -0
  62. package/data/craftbook-templates/de/deep-security-review/versions/1.1.0/test.json +157 -0
  63. package/data/craftbook-templates/do/dockerize-app/versions/1.0.0/test.json +0 -5
  64. package/data/craftbook-templates/fr/freeze-scope/manifest.json +1 -2
  65. package/data/craftbook-templates/fr/freeze-scope/versions/{1.0.1 → 1.1.0}/craftbook.json +5 -17
  66. package/data/craftbook-templates/gr/graphql-api/versions/1.0.1/test.json +0 -5
  67. package/data/craftbook-templates/gr/grpc-service/versions/1.0.0/test.json +0 -5
  68. package/data/craftbook-templates/ho/hotfix-flow/versions/1.0.0/test.json +0 -5
  69. package/data/craftbook-templates/in/investigate/versions/1.1.0/craftbook.json +81 -0
  70. package/data/craftbook-templates/in/investigate/versions/1.1.0/test.json +122 -0
  71. package/data/craftbook-templates/in/invoice-run/manifest.json +1 -2
  72. package/data/craftbook-templates/in/invoice-run/versions/{1.0.1 → 1.1.0}/craftbook.json +4 -4
  73. package/data/craftbook-templates/index.json +1 -1
  74. package/data/craftbook-templates/li/library-package/versions/1.0.0/test.json +0 -5
  75. package/data/craftbook-templates/me/memory-prompt-session/manifest.json +1 -2
  76. package/data/craftbook-templates/me/message-queue-consumer/versions/1.0.0/test.json +0 -5
  77. package/data/craftbook-templates/of/office-hours/versions/1.1.0/craftbook.json +48 -0
  78. package/data/craftbook-templates/of/office-hours/versions/1.1.0/test.json +118 -0
  79. package/data/craftbook-templates/pa/page-spread/manifest.json +1 -2
  80. package/data/craftbook-templates/pa/parser-grammar/versions/1.0.0/test.json +0 -5
  81. package/data/craftbook-templates/pe/perf-optimization/versions/1.0.0/test.json +0 -5
  82. package/data/craftbook-templates/pl/plan/manifest.json +1 -2
  83. package/data/craftbook-templates/po/powerpoint-deck/versions/1.1.0/craftbook.json +128 -0
  84. package/data/craftbook-templates/{ro/root-cause-investigation/versions/1.0.1 → po/powerpoint-deck/versions/1.1.0}/test.json +6 -6
  85. package/data/craftbook-templates/pu/pull-request-review/versions/1.1.0/craftbook.json +118 -0
  86. package/data/craftbook-templates/pu/pull-request-review/versions/1.1.0/test.json +160 -0
  87. package/data/craftbook-templates/re/refactor-module/versions/1.0.1/test.json +0 -5
  88. package/data/craftbook-templates/re/regex-builder/versions/1.0.0/test.json +0 -5
  89. package/data/craftbook-templates/re/research-to-document/versions/1.1.0/craftbook.json +158 -0
  90. package/data/craftbook-templates/re/research-to-document/versions/1.1.0/test.json +97 -0
  91. package/data/craftbook-templates/ro/root-cause-investigation/manifest.json +1 -2
  92. package/data/craftbook-templates/sd/sdk-wrapper/versions/1.0.1/test.json +0 -5
  93. package/data/craftbook-templates/se/security-architecture-review/versions/1.1.0/craftbook.json +28 -0
  94. package/data/craftbook-templates/{te/technical-documentation/versions/1.0.1 → se/security-architecture-review/versions/1.1.0}/test.json +7 -7
  95. package/data/craftbook-templates/sh/ship/versions/1.1.0/craftbook.json +137 -0
  96. package/data/craftbook-templates/sh/ship/versions/1.1.0/test.json +225 -0
  97. package/data/craftbook-templates/st/state-machine/versions/1.0.0/test.json +0 -5
  98. package/data/craftbook-templates/te/technical-documentation/manifest.json +1 -2
  99. package/data/craftbook-templates/te/test-suite-backfill/versions/1.0.0/test.json +0 -5
  100. package/data/craftbook-templates/ti/tileset-batch/versions/1.0.0/test.json +1 -2
  101. package/data/craftbook-templates/ty/type-safety-pass/versions/1.0.0/test.json +0 -5
  102. package/data/craftbook-templates/ve/version-bump/versions/1.0.0/test.json +0 -5
  103. package/data/gezel-templates/ch/chess-player/manifest.json +20 -0
  104. package/data/gezel-templates/ch/chess-player/versions/1.0.0/about.md +21 -0
  105. package/data/gezel-templates/ch/chess-player/versions/1.0.0/manifest.json +10 -0
  106. package/data/gezel-templates/go/go-player/manifest.json +22 -0
  107. package/data/gezel-templates/go/go-player/versions/1.0.0/about.md +22 -0
  108. package/data/gezel-templates/go/go-player/versions/1.0.0/manifest.json +10 -0
  109. package/data/gezel-templates/index.json +1 -1
  110. package/data/project-types/ch/chess/manifest.json +20 -0
  111. package/data/project-types/ch/chess/versions/1.0.0/about.md +9 -0
  112. package/data/project-types/ch/chess/versions/1.0.0/game.json +127 -0
  113. package/data/project-types/ch/chess/versions/1.0.0/manifest.json +180 -0
  114. package/data/project-types/ch/chess/versions/1.0.0/mission.md +8 -0
  115. package/data/project-types/ch/chess/versions/1.0.0/pages/board/index.html +574 -0
  116. package/data/project-types/go/go/manifest.json +22 -0
  117. package/data/project-types/go/go/versions/1.0.0/about.md +9 -0
  118. package/data/project-types/go/go/versions/1.0.0/game.json +103 -0
  119. package/data/project-types/go/go/versions/1.0.0/manifest.json +166 -0
  120. package/data/project-types/go/go/versions/1.0.0/mission.md +8 -0
  121. package/data/project-types/go/go/versions/1.0.0/pages/board/index.html +637 -0
  122. package/data/project-types/index.json +1 -1
  123. package/package.json +2 -1
  124. package/schemas/chat-model-version.schema.json +22 -0
  125. package/schemas/craftbook-doc.schema.json +12 -0
  126. package/schemas/craftbook-template-version.schema.json +12 -0
  127. package/schemas/craftbook-test.schema.json +12 -0
  128. package/data/chat-models/gl/glm-5.2-754b-q2/manifest.json +0 -66
  129. package/data/chat-models/gl/glm-5.2-754b-q2/versions/1.0.0/manifest.json +0 -18
  130. package/data/craftbook-templates/cr/crossword-forge/versions/1.0.1/craftbook.json +0 -147
  131. package/data/craftbook-templates/cr/crossword-forge/versions/1.0.1/test.json +0 -135
  132. package/data/craftbook-templates/me/memory-prompt-session/versions/1.0.1/craftbook.json +0 -116
  133. package/data/craftbook-templates/me/memory-prompt-session/versions/1.0.1/test.json +0 -112
  134. package/data/craftbook-templates/pa/page-spread/versions/1.0.1/craftbook.json +0 -94
  135. package/data/craftbook-templates/pa/page-spread/versions/1.0.1/test.json +0 -133
  136. package/data/craftbook-templates/pl/plan/versions/1.0.1/craftbook.json +0 -104
  137. package/data/craftbook-templates/pl/plan/versions/1.0.1/test.json +0 -91
  138. package/data/craftbook-templates/ro/root-cause-investigation/versions/1.0.1/craftbook.json +0 -126
  139. package/data/craftbook-templates/te/technical-documentation/versions/1.0.1/craftbook.json +0 -152
  140. /package/data/craftbook-templates/fr/freeze-scope/versions/{1.0.1 → 1.1.0}/test.json +0 -0
  141. /package/data/craftbook-templates/in/invoice-run/versions/{1.0.1 → 1.1.0}/test.json +0 -0
@@ -0,0 +1,637 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Go</title>
7
+ <style>
8
+ :root {
9
+ color-scheme: light dark;
10
+ --bg: #faf7f2;
11
+ --card: #fff;
12
+ --ink: #2b2620;
13
+ --muted: #7a7166;
14
+ --accent: #9a5928;
15
+ --track: #e8dfd2;
16
+ --wood-a: #d4a45f;
17
+ --wood-b: #b97d3f;
18
+ --wood-edge: #694322;
19
+ --line: rgba(49, 30, 18, 0.78);
20
+ --black-stone-a: #4a4540;
21
+ --black-stone-b: #171411;
22
+ --white-stone-a: #fffdf6;
23
+ --white-stone-b: #d8d0c3;
24
+ --last-move: #c55e32;
25
+ --legal: #52745a;
26
+ }
27
+ @media (prefers-color-scheme: dark) {
28
+ :root {
29
+ --bg: #1c1a17;
30
+ --card: #262320;
31
+ --ink: #efe9e0;
32
+ --muted: #a59a8c;
33
+ --accent: #e0894a;
34
+ --track: #3a352f;
35
+ --wood-a: #a7733c;
36
+ --wood-b: #744a29;
37
+ --wood-edge: #2b1a10;
38
+ --line: rgba(28, 18, 12, 0.88);
39
+ --last-move: #f19a5f;
40
+ --legal: #7da486;
41
+ }
42
+ }
43
+ * { box-sizing: border-box; }
44
+ body {
45
+ margin: 0;
46
+ padding: 1.25rem;
47
+ background: var(--bg);
48
+ color: var(--ink);
49
+ font: 15px/1.5 system-ui, -apple-system, 'Segoe UI', sans-serif;
50
+ }
51
+ main { max-width: 820px; margin: 0 auto; }
52
+ header {
53
+ display: flex;
54
+ align-items: baseline;
55
+ justify-content: space-between;
56
+ gap: 0.75rem;
57
+ flex-wrap: wrap;
58
+ }
59
+ h1 {
60
+ margin: 0;
61
+ font-family: Georgia, 'PT Serif', 'Times New Roman', serif;
62
+ font-size: 1.35rem;
63
+ }
64
+ button { font: inherit; }
65
+ .newgame,
66
+ .pass-button {
67
+ border: 1px solid var(--track);
68
+ border-radius: 6px;
69
+ padding: 0.32rem 0.7rem;
70
+ background: var(--card);
71
+ color: var(--ink);
72
+ cursor: pointer;
73
+ }
74
+ .newgame:hover,
75
+ .pass-button:hover { border-color: var(--accent); }
76
+ .pass-button:disabled { cursor: default; opacity: 0.55; }
77
+ .status { min-height: 1.5em; margin: 0.15rem 0 0.9rem; color: var(--muted); }
78
+ .status.thinking { color: var(--accent); }
79
+ .banner {
80
+ display: none;
81
+ margin-bottom: 0.75rem;
82
+ padding: 0.45rem 0.7rem;
83
+ border: 1px solid var(--accent);
84
+ border-radius: 6px;
85
+ font-size: 0.85rem;
86
+ }
87
+ .banner.show { display: block; }
88
+ .table { display: grid; grid-template-columns: minmax(0, 1fr) 220px; gap: 0.9rem; }
89
+ .boardwrap {
90
+ min-width: 0;
91
+ padding: clamp(0.8rem, 3vw, 1.35rem);
92
+ border: 1px solid var(--wood-edge);
93
+ border-radius: 14px;
94
+ background:
95
+ linear-gradient(95deg, rgba(255,255,255,0.08), transparent 35%, rgba(74,37,16,0.08)),
96
+ linear-gradient(145deg, var(--wood-a), var(--wood-b));
97
+ box-shadow:
98
+ inset 0 1px 0 rgba(255, 255, 255, 0.22),
99
+ inset 0 -5px 9px rgba(74, 37, 16, 0.24),
100
+ 0 10px 24px rgba(31, 21, 15, 0.22);
101
+ }
102
+ .board {
103
+ display: grid;
104
+ grid-template-columns: repeat(var(--board-size), 1fr);
105
+ aspect-ratio: 1;
106
+ user-select: none;
107
+ }
108
+ .point {
109
+ position: relative;
110
+ display: grid;
111
+ min-width: 0;
112
+ min-height: 0;
113
+ place-items: center;
114
+ padding: 0;
115
+ border: 0;
116
+ background: transparent;
117
+ color: inherit;
118
+ }
119
+ .point::before,
120
+ .point::after {
121
+ position: absolute;
122
+ z-index: 0;
123
+ background: var(--line);
124
+ content: '';
125
+ pointer-events: none;
126
+ }
127
+ .point::before {
128
+ top: calc(50% - 0.5px);
129
+ right: var(--right-edge, 0);
130
+ left: var(--left-edge, 0);
131
+ height: 1px;
132
+ }
133
+ .point::after {
134
+ top: var(--top-edge, 0);
135
+ bottom: var(--bottom-edge, 0);
136
+ left: calc(50% - 0.5px);
137
+ width: 1px;
138
+ }
139
+ .point.star:not(.occupied) .star-dot {
140
+ position: relative;
141
+ z-index: 1;
142
+ width: clamp(3px, 14%, 7px);
143
+ aspect-ratio: 1;
144
+ border-radius: 50%;
145
+ background: var(--line);
146
+ }
147
+ .point.legal { cursor: pointer; }
148
+ .point.legal:not(.occupied):hover .star-dot {
149
+ position: relative;
150
+ z-index: 2;
151
+ width: 30%;
152
+ aspect-ratio: 1;
153
+ border-radius: 50%;
154
+ background: var(--legal);
155
+ box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.16);
156
+ }
157
+ .stone {
158
+ position: relative;
159
+ z-index: 2;
160
+ width: 88%;
161
+ aspect-ratio: 1;
162
+ border: 1px solid rgba(32, 22, 16, 0.45);
163
+ border-radius: 50%;
164
+ box-shadow:
165
+ inset 0 4px 5px rgba(255, 255, 255, 0.2),
166
+ inset 0 -5px 7px rgba(0, 0, 0, 0.28),
167
+ 0 3px 5px rgba(45, 27, 15, 0.35);
168
+ transition: transform 140ms ease-out;
169
+ }
170
+ .stone.black { background: radial-gradient(circle at 34% 27%, var(--black-stone-a), var(--black-stone-b) 72%); }
171
+ .stone.white { background: radial-gradient(circle at 34% 27%, var(--white-stone-a), var(--white-stone-b) 72%); }
172
+ .point.last .stone::after {
173
+ position: absolute;
174
+ inset: 34%;
175
+ border-radius: 50%;
176
+ background: var(--last-move);
177
+ content: '';
178
+ }
179
+ .coord {
180
+ position: absolute;
181
+ z-index: 3;
182
+ color: rgba(44, 27, 16, 0.72);
183
+ font-size: clamp(0.38rem, 1vw, 0.62rem);
184
+ font-weight: 700;
185
+ line-height: 1;
186
+ pointer-events: none;
187
+ }
188
+ .coord.rank { top: 4%; left: 4%; }
189
+ .coord.file { right: 4%; bottom: 4%; }
190
+ .aside { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
191
+ .panel {
192
+ padding: 0.7rem 0.85rem;
193
+ border: 1px solid var(--track);
194
+ border-radius: 10px;
195
+ background: var(--card);
196
+ font-size: 0.85rem;
197
+ }
198
+ .panel h2 {
199
+ margin: 0 0 0.35rem;
200
+ color: var(--muted);
201
+ font-size: 0.72rem;
202
+ letter-spacing: 0.05em;
203
+ text-transform: uppercase;
204
+ }
205
+ .move-thought { font-style: italic; }
206
+ .move-thought .who {
207
+ display: block;
208
+ margin-bottom: 0.15rem;
209
+ color: var(--muted);
210
+ font-size: 0.78rem;
211
+ font-style: normal;
212
+ }
213
+ .game-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
214
+ .capture-count { color: var(--muted); font-size: 0.78rem; }
215
+ .log { max-height: 210px; margin: 0; padding-left: 1.2rem; overflow-y: auto; }
216
+ .log li { margin: 0.12rem 0; color: var(--muted); }
217
+ .log li.latest { color: var(--ink); }
218
+ dialog {
219
+ width: min(430px, calc(100vw - 2rem));
220
+ padding: 0;
221
+ border: 1px solid var(--track);
222
+ border-radius: 10px;
223
+ background: var(--card);
224
+ color: var(--ink);
225
+ box-shadow: 0 18px 55px rgba(0, 0, 0, 0.35);
226
+ }
227
+ dialog::backdrop { background: rgba(20, 17, 14, 0.62); }
228
+ .dialog-content { padding: 1rem; }
229
+ .dialog-content h2 {
230
+ margin: 0;
231
+ font-family: Georgia, 'PT Serif', serif;
232
+ font-size: 1.1rem;
233
+ }
234
+ .dialog-intro { margin: 0.2rem 0 0.85rem; color: var(--muted); font-size: 0.85rem; }
235
+ fieldset { margin: 0 0 0.75rem; padding: 0; border: 0; }
236
+ legend {
237
+ margin-bottom: 0.35rem;
238
+ color: var(--muted);
239
+ font-size: 0.72rem;
240
+ font-weight: 700;
241
+ letter-spacing: 0.05em;
242
+ text-transform: uppercase;
243
+ }
244
+ .key-tray {
245
+ display: grid;
246
+ grid-template-columns: repeat(3, 1fr);
247
+ gap: 0.35rem;
248
+ padding: 0.35rem;
249
+ border: 1px solid var(--track);
250
+ border-radius: 10px;
251
+ background: var(--track);
252
+ }
253
+ .key-tray.two { grid-template-columns: repeat(2, 1fr); }
254
+ .rule-key {
255
+ padding: 0.45rem;
256
+ border: 1px solid transparent;
257
+ border-radius: 6px;
258
+ background: var(--card);
259
+ color: var(--ink);
260
+ cursor: pointer;
261
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.14);
262
+ }
263
+ .rule-key:hover { border-color: var(--accent); }
264
+ .rule-key[aria-checked='true'] {
265
+ border-color: var(--accent);
266
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
267
+ transform: translateY(1px);
268
+ }
269
+ .rule-key strong { display: block; font-size: 0.88rem; }
270
+ .rule-key span { display: block; color: var(--muted); font-size: 0.72rem; }
271
+ .dialog-actions { display: flex; justify-content: flex-end; gap: 0.45rem; margin-top: 0.9rem; }
272
+ .dialog-button {
273
+ padding: 0.4rem 0.75rem;
274
+ border: 1px solid var(--accent);
275
+ border-radius: 6px;
276
+ background: var(--accent);
277
+ color: var(--bg);
278
+ cursor: pointer;
279
+ }
280
+ .dialog-button.secondary { border-color: var(--track); background: var(--card); color: var(--ink); }
281
+ @media (max-width: 660px) {
282
+ .table { grid-template-columns: 1fr; }
283
+ .aside { display: grid; grid-template-columns: 1fr 1fr; }
284
+ }
285
+ @media (prefers-reduced-motion: reduce) {
286
+ .stone { transition: none; }
287
+ }
288
+ </style>
289
+ </head>
290
+ <body>
291
+ <main>
292
+ <div class="banner" id="banner"></div>
293
+ <header>
294
+ <h1>Go</h1>
295
+ <button type="button" class="newgame" id="newgame">New game</button>
296
+ </header>
297
+ <p class="status" id="status">Setting up the board…</p>
298
+ <div class="table">
299
+ <div class="boardwrap"><div class="board" id="board" aria-label="Go board"></div></div>
300
+ <div class="aside">
301
+ <div class="panel move-thought" id="move-thought-panel" hidden>
302
+ <span class="who">Go-speler says</span>
303
+ <span id="move-thought"></span>
304
+ </div>
305
+ <div class="panel game-actions">
306
+ <button type="button" class="pass-button" id="pass">Pass</button>
307
+ <span class="capture-count" id="captures">Captures — 0 / 0</span>
308
+ </div>
309
+ <div class="panel">
310
+ <h2>Moves</h2>
311
+ <ol class="log" id="log"><li>No moves yet — black opens.</li></ol>
312
+ </div>
313
+ </div>
314
+ </div>
315
+ <dialog id="new-game-dialog" aria-labelledby="new-game-title">
316
+ <div class="dialog-content">
317
+ <h2 id="new-game-title">New game</h2>
318
+ <p class="dialog-intro">Choose a board and scoring balance.</p>
319
+ <fieldset>
320
+ <legend>Board size</legend>
321
+ <div class="key-tray" role="radiogroup" aria-label="Board size">
322
+ <button type="button" class="rule-key size-key" role="radio" aria-checked="true" data-size="9">
323
+ <strong>9 × 9</strong><span>Quick</span>
324
+ </button>
325
+ <button type="button" class="rule-key size-key" role="radio" aria-checked="false" data-size="13">
326
+ <strong>13 × 13</strong><span>Medium</span>
327
+ </button>
328
+ <button type="button" class="rule-key size-key" role="radio" aria-checked="false" data-size="19">
329
+ <strong>19 × 19</strong><span>Full</span>
330
+ </button>
331
+ </div>
332
+ </fieldset>
333
+ <fieldset>
334
+ <legend>Komi</legend>
335
+ <div class="key-tray two" role="radiogroup" aria-label="Komi">
336
+ <button type="button" class="rule-key komi-key" role="radio" aria-checked="true" data-komi="6.5">
337
+ <strong>6.5 points</strong><span>Standard balance</span>
338
+ </button>
339
+ <button type="button" class="rule-key komi-key" role="radio" aria-checked="false" data-komi="0">
340
+ <strong>No komi</strong><span>Even score</span>
341
+ </button>
342
+ </div>
343
+ </fieldset>
344
+ <div class="dialog-actions">
345
+ <button type="button" class="dialog-button secondary" id="cancel-new-game">Cancel</button>
346
+ <button type="button" class="dialog-button" id="start-new-game">Start game</button>
347
+ </div>
348
+ </div>
349
+ </dialog>
350
+ </main>
351
+ <script>
352
+ (function () {
353
+ 'use strict';
354
+
355
+ var gezelPage = (function () {
356
+ var seq = 0;
357
+ var pending = {};
358
+ window.addEventListener('message', function (event) {
359
+ var data = event.data;
360
+ if (!data || data.__gezelPageResult !== true || typeof data.id !== 'string') return;
361
+ var entry = pending[data.id];
362
+ if (!entry) return;
363
+ delete pending[data.id];
364
+ clearTimeout(entry.timer);
365
+ if (data.ok) entry.resolve(data);
366
+ else entry.reject(new Error(data.error || 'invoke failed'));
367
+ });
368
+ return {
369
+ embedded: function () { return window.parent !== window; },
370
+ invoke: function (tool, input) {
371
+ return new Promise(function (resolve, reject) {
372
+ if (window.parent === window) return reject(new Error('not embedded in Gezel'));
373
+ seq += 1;
374
+ var id = 'pi-' + Date.now() + '-' + seq;
375
+ pending[id] = {
376
+ resolve: resolve,
377
+ reject: reject,
378
+ timer: setTimeout(function () {
379
+ delete pending[id];
380
+ reject(new Error('invoke timed out'));
381
+ }, 45000),
382
+ };
383
+ window.parent.postMessage(
384
+ { __gezelPageInvoke: true, id: id, tool: tool, input: input || {} },
385
+ '*',
386
+ );
387
+ });
388
+ },
389
+ refresh: function () {
390
+ if (window.parent !== window) window.parent.postMessage({ __gezelPageRefresh: true }, '*');
391
+ },
392
+ };
393
+ })();
394
+
395
+ var parts = location.pathname.split('/').filter(Boolean);
396
+ var typeIndex = parts.indexOf('type');
397
+ var capability = typeIndex > 0 ? parts[typeIndex - 1] : null;
398
+ var projectId = typeIndex >= 0 ? parts[typeIndex + 1] : null;
399
+ var GO_FILES = 'ABCDEFGHJKLMNOPQRST';
400
+ var state = null;
401
+ var busy = false;
402
+ var pollTimer = null;
403
+ var failedPolls = 0;
404
+ var newBoardSize = 9;
405
+ var newKomi = 6.5;
406
+
407
+ function pointName(x, y, size) { return GO_FILES[x] + String(size - y); }
408
+ function isStar(x, y, size) {
409
+ var points =
410
+ size === 9 ? [2, 4, 6] :
411
+ size === 13 ? [3, 6, 9] :
412
+ [3, 9, 15];
413
+ if (size === 9) return (x === 4 && y === 4) || (x !== 4 && y !== 4 && points.includes(x) && points.includes(y));
414
+ return points.includes(x) && points.includes(y);
415
+ }
416
+ function setBanner(text) {
417
+ var banner = document.getElementById('banner');
418
+ banner.textContent = text || '';
419
+ banner.className = text ? 'banner show' : 'banner';
420
+ }
421
+ function scoreText() {
422
+ if (!state || !state.score) return '';
423
+ if (state.score.winner === 'draw') return 'The final score is even.';
424
+ var color = state.score.winner === 'user' ? 'Black' : 'White';
425
+ return color + ' wins by ' + state.score.margin + ' points.';
426
+ }
427
+ function statusLine() {
428
+ if (!state) return 'Setting up the board…';
429
+ if (state.status !== 'playing') return scoreText() + ' Ready for another game?';
430
+ if (busy) return 'Sending your move…';
431
+ if (state.turn === 'ai') return 'Go-speler is thinking…';
432
+ return 'Your move — place black, or pass.';
433
+ }
434
+ function render() {
435
+ var status = document.getElementById('status');
436
+ status.textContent = statusLine();
437
+ status.className =
438
+ state && state.turn === 'ai' && state.status === 'playing'
439
+ ? 'status thinking'
440
+ : 'status';
441
+
442
+ var thoughtPanel = document.getElementById('move-thought-panel');
443
+ if (state && state.lastMoveThought) {
444
+ thoughtPanel.hidden = false;
445
+ document.getElementById('move-thought').textContent = state.lastMoveThought;
446
+ } else {
447
+ thoughtPanel.hidden = true;
448
+ }
449
+ document.getElementById('captures').textContent = state
450
+ ? 'Captures — black ' + state.captures.user + ' / white ' + state.captures.ai
451
+ : 'Captures — 0 / 0';
452
+ document.getElementById('pass').disabled =
453
+ !state || state.turn !== 'user' || state.status !== 'playing' || busy;
454
+
455
+ var log = document.getElementById('log');
456
+ if (state && state.moveLog.length) {
457
+ log.innerHTML = '';
458
+ state.moveLog.forEach(function (entry, index) {
459
+ var item = document.createElement('li');
460
+ var captures = entry.captures && entry.captures.length
461
+ ? ' (captures ' + entry.captures.length + ')'
462
+ : '';
463
+ item.textContent = (entry.by === 'user' ? 'Black ' : 'White ') + entry.move + captures;
464
+ if (index === state.moveLog.length - 1) item.className = 'latest';
465
+ log.appendChild(item);
466
+ });
467
+ log.scrollTop = log.scrollHeight;
468
+ } else {
469
+ log.innerHTML = '<li>No moves yet — black opens.</li>';
470
+ }
471
+
472
+ var board = document.getElementById('board');
473
+ board.innerHTML = '';
474
+ var size = state ? state.boardSize : 9;
475
+ board.style.setProperty('--board-size', size);
476
+ var legal = {};
477
+ if (state) state.legalMoves.forEach(function (move) { legal[move] = true; });
478
+ var myTurn = state && state.turn === 'user' && state.status === 'playing' && !busy;
479
+ for (var y = 0; y < size; y += 1) {
480
+ for (var x = 0; x < size; x += 1) {
481
+ var name = pointName(x, y, size);
482
+ var stone = state ? state.squares[y * size + x] : '.';
483
+ var point = document.createElement('button');
484
+ point.type = 'button';
485
+ point.className = 'point';
486
+ point.dataset.point = name;
487
+ point.setAttribute('aria-label', name + (stone === '.' ? ', empty' : stone === 'X' ? ', black' : ', white'));
488
+ if (x === 0) point.style.setProperty('--left-edge', '50%');
489
+ if (x === size - 1) point.style.setProperty('--right-edge', '50%');
490
+ if (y === 0) point.style.setProperty('--top-edge', '50%');
491
+ if (y === size - 1) point.style.setProperty('--bottom-edge', '50%');
492
+ if (isStar(x, y, size)) point.className += ' star';
493
+ if (stone !== '.') point.className += ' occupied';
494
+ if (myTurn && legal[name]) point.className += ' legal';
495
+ if (state && state.lastMove && state.lastMove.move === name) point.className += ' last';
496
+
497
+ if (x === 0) {
498
+ var rank = document.createElement('span');
499
+ rank.className = 'coord rank';
500
+ rank.textContent = String(size - y);
501
+ point.appendChild(rank);
502
+ }
503
+ if (y === size - 1) {
504
+ var file = document.createElement('span');
505
+ file.className = 'coord file';
506
+ file.textContent = GO_FILES[x];
507
+ point.appendChild(file);
508
+ }
509
+ if (stone === '.') {
510
+ var dot = document.createElement('span');
511
+ dot.className = 'star-dot';
512
+ point.appendChild(dot);
513
+ } else {
514
+ var piece = document.createElement('span');
515
+ piece.className = 'stone ' + (stone === 'X' ? 'black' : 'white');
516
+ point.appendChild(piece);
517
+ }
518
+ point.addEventListener('click', onPointClick);
519
+ board.appendChild(point);
520
+ }
521
+ }
522
+ }
523
+
524
+ function onPointClick(event) {
525
+ if (!state || state.turn !== 'user' || state.status !== 'playing' || busy) return;
526
+ var move = event.currentTarget.dataset.point;
527
+ if (!state.legalMoves.includes(move)) return;
528
+ submitMove(move);
529
+ }
530
+ function submitMove(move) {
531
+ busy = true;
532
+ render();
533
+ gezelPage
534
+ .invoke('user_move', { move: move })
535
+ .then(function (result) {
536
+ busy = false;
537
+ if (
538
+ result.reaction &&
539
+ result.reaction.delivered === false &&
540
+ result.reaction.reason === 'engagement-off'
541
+ ) {
542
+ setBanner('Move played — but AI engagement is off, so the Go-speler cannot reply.');
543
+ }
544
+ return poll();
545
+ })
546
+ .catch(function (error) {
547
+ busy = false;
548
+ setBanner(String(error && error.message ? error.message : error));
549
+ render();
550
+ });
551
+ }
552
+ function syncDialog() {
553
+ document.querySelectorAll('.size-key').forEach(function (button) {
554
+ button.setAttribute('aria-checked', String(Number(button.dataset.size) === newBoardSize));
555
+ });
556
+ document.querySelectorAll('.komi-key').forEach(function (button) {
557
+ button.setAttribute('aria-checked', String(Number(button.dataset.komi) === newKomi));
558
+ });
559
+ }
560
+ function openNewGame() {
561
+ if (!gezelPage.embedded() || busy) return;
562
+ newBoardSize = state ? state.boardSize : 9;
563
+ newKomi = state ? state.komi : 6.5;
564
+ syncDialog();
565
+ document.getElementById('new-game-dialog').showModal();
566
+ }
567
+ function newGame() {
568
+ busy = true;
569
+ render();
570
+ gezelPage
571
+ .invoke('new_game', { boardSize: newBoardSize, komi: newKomi })
572
+ .then(function () {
573
+ busy = false;
574
+ setBanner('');
575
+ return poll();
576
+ })
577
+ .catch(function (error) {
578
+ busy = false;
579
+ setBanner(String(error && error.message ? error.message : error));
580
+ render();
581
+ });
582
+ }
583
+ function poll() {
584
+ if (!capability || !projectId) return Promise.resolve();
585
+ return fetch(
586
+ '/preview/' + encodeURIComponent(capability) + '/workspace/' + encodeURIComponent(projectId) + '/game.json',
587
+ { cache: 'no-store' },
588
+ )
589
+ .then(function (response) {
590
+ if (!response.ok) throw new Error('poll ' + response.status);
591
+ return response.json();
592
+ })
593
+ .then(function (next) {
594
+ failedPolls = 0;
595
+ state = next;
596
+ render();
597
+ })
598
+ .catch(function () {
599
+ failedPolls += 1;
600
+ if (failedPolls === 3) gezelPage.refresh();
601
+ });
602
+ }
603
+ function schedule() {
604
+ if (pollTimer) clearTimeout(pollTimer);
605
+ var wait = state && state.turn === 'ai' && state.status === 'playing' ? 1500 : 5000;
606
+ pollTimer = setTimeout(function () { poll().then(schedule, schedule); }, wait);
607
+ }
608
+
609
+ document.getElementById('pass').addEventListener('click', function () { submitMove('pass'); });
610
+ document.getElementById('newgame').addEventListener('click', openNewGame);
611
+ document.getElementById('cancel-new-game').addEventListener('click', function () {
612
+ document.getElementById('new-game-dialog').close();
613
+ });
614
+ document.getElementById('start-new-game').addEventListener('click', function () {
615
+ document.getElementById('new-game-dialog').close();
616
+ newGame();
617
+ });
618
+ document.querySelectorAll('.size-key').forEach(function (button) {
619
+ button.addEventListener('click', function () {
620
+ newBoardSize = Number(button.dataset.size);
621
+ syncDialog();
622
+ });
623
+ });
624
+ document.querySelectorAll('.komi-key').forEach(function (button) {
625
+ button.addEventListener('click', function () {
626
+ newKomi = Number(button.dataset.komi);
627
+ syncDialog();
628
+ });
629
+ });
630
+ if (!gezelPage.embedded()) {
631
+ setBanner('Read-only view — moves need the Gezel app (open this project and use the Output tab).');
632
+ }
633
+ poll().then(schedule, schedule);
634
+ })();
635
+ </script>
636
+ </body>
637
+ </html>