claudeck 1.4.0 → 1.4.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/README.md +6 -6
- package/package.json +1 -1
- package/plugins/claude-editor/manifest.json +10 -0
- package/plugins/linear/manifest.json +10 -0
- package/plugins/repos/manifest.json +10 -0
- package/public/css/ui/right-panel.css +207 -0
- package/public/css/ui/settings.css +75 -0
- package/public/index.html +7 -0
- package/public/js/components/settings-modal.js +65 -0
- package/public/js/core/events.js +11 -0
- package/public/js/core/plugin-loader.js +96 -11
- package/public/js/core/store.js +11 -0
- package/public/js/main.js +1 -0
- package/public/js/panels/assistant-bot.js +16 -0
- package/public/js/panels/dev-docs.js +2 -2
- package/public/js/panels/memory.js +1 -0
- package/public/js/ui/context-gauge.js +10 -1
- package/public/js/ui/header-dropdowns.js +30 -0
- package/public/js/ui/input-meta.js +13 -6
- package/public/js/ui/max-turns.js +6 -3
- package/public/js/ui/model-selector.js +1 -0
- package/public/js/ui/permissions.js +1 -0
- package/public/js/ui/tab-sdk.js +395 -176
- package/public/style.css +1 -0
- package/server/memory-optimizer.js +17 -13
- package/server/routes/marketplace.js +316 -0
- package/server/ws-handler.js +22 -15
- package/server.js +18 -0
- package/plugins/event-stream/client.css +0 -207
- package/plugins/event-stream/client.js +0 -271
- package/plugins/sudoku/client.css +0 -196
- package/plugins/sudoku/client.js +0 -329
- package/plugins/tasks/client.css +0 -414
- package/plugins/tasks/client.js +0 -394
- package/plugins/tasks/server.js +0 -116
- package/plugins/tic-tac-toe/client.css +0 -167
- package/plugins/tic-tac-toe/client.js +0 -241
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
// Tic Tac Toe — Tab SDK plugin
|
|
2
|
-
// A classic tic-tac-toe game vs AI or a friend
|
|
3
|
-
import { registerTab } from '/js/ui/tab-sdk.js';
|
|
4
|
-
|
|
5
|
-
registerTab({
|
|
6
|
-
id: 'tic-tac-toe',
|
|
7
|
-
title: 'Tic Tac Toe',
|
|
8
|
-
icon: '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="2" x2="8" y2="22"/><line x1="16" y1="2" x2="16" y2="22"/><line x1="2" y1="8" x2="22" y2="8"/><line x1="2" y1="16" x2="22" y2="16"/></svg>',
|
|
9
|
-
lazy: true,
|
|
10
|
-
|
|
11
|
-
init(ctx) {
|
|
12
|
-
const root = document.createElement('div');
|
|
13
|
-
root.className = 'tic-tac-toe-tab';
|
|
14
|
-
root.style.cssText = 'display:flex;flex-direction:column;flex:1;overflow:hidden;';
|
|
15
|
-
|
|
16
|
-
// ── State ──
|
|
17
|
-
let board = Array(9).fill(null); // 'X', 'O', or null
|
|
18
|
-
let currentPlayer = 'X'; // X always goes first
|
|
19
|
-
const mode = 'ai';
|
|
20
|
-
let difficulty = 'hard'; // 'easy', 'medium', 'hard'
|
|
21
|
-
let gameOver = false;
|
|
22
|
-
let winLine = null;
|
|
23
|
-
let scores = { X: 0, O: 0, draw: 0 };
|
|
24
|
-
|
|
25
|
-
const WIN_COMBOS = [
|
|
26
|
-
[0,1,2],[3,4,5],[6,7,8], // rows
|
|
27
|
-
[0,3,6],[1,4,7],[2,5,8], // cols
|
|
28
|
-
[0,4,8],[2,4,6], // diags
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
function checkWin(b) {
|
|
32
|
-
for (const combo of WIN_COMBOS) {
|
|
33
|
-
const [a, c, d] = combo;
|
|
34
|
-
if (b[a] && b[a] === b[c] && b[a] === b[d]) return combo;
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function isDraw(b) {
|
|
40
|
-
return b.every(cell => cell !== null) && !checkWin(b);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ── AI (minimax) ──
|
|
44
|
-
function minimax(b, isMax, depth) {
|
|
45
|
-
const win = checkWin(b);
|
|
46
|
-
if (win) return b[win[0]] === 'O' ? 10 - depth : depth - 10;
|
|
47
|
-
if (b.every(c => c !== null)) return 0;
|
|
48
|
-
|
|
49
|
-
if (isMax) {
|
|
50
|
-
let best = -Infinity;
|
|
51
|
-
for (let i = 0; i < 9; i++) {
|
|
52
|
-
if (!b[i]) { b[i] = 'O'; best = Math.max(best, minimax(b, false, depth + 1)); b[i] = null; }
|
|
53
|
-
}
|
|
54
|
-
return best;
|
|
55
|
-
} else {
|
|
56
|
-
let best = Infinity;
|
|
57
|
-
for (let i = 0; i < 9; i++) {
|
|
58
|
-
if (!b[i]) { b[i] = 'X'; best = Math.min(best, minimax(b, true, depth + 1)); b[i] = null; }
|
|
59
|
-
}
|
|
60
|
-
return best;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function getAiMove() {
|
|
65
|
-
const empty = board.map((v, i) => v === null ? i : -1).filter(i => i >= 0);
|
|
66
|
-
if (empty.length === 0) return -1;
|
|
67
|
-
|
|
68
|
-
if (difficulty === 'easy') {
|
|
69
|
-
// Random move
|
|
70
|
-
return empty[Math.floor(Math.random() * empty.length)];
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (difficulty === 'medium') {
|
|
74
|
-
// 50% chance of optimal, 50% random
|
|
75
|
-
if (Math.random() < 0.5) return empty[Math.floor(Math.random() * empty.length)];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Hard: full minimax
|
|
79
|
-
let bestScore = -Infinity;
|
|
80
|
-
let bestMove = empty[0];
|
|
81
|
-
for (const i of empty) {
|
|
82
|
-
board[i] = 'O';
|
|
83
|
-
const score = minimax(board, false, 0);
|
|
84
|
-
board[i] = null;
|
|
85
|
-
if (score > bestScore) { bestScore = score; bestMove = i; }
|
|
86
|
-
}
|
|
87
|
-
return bestMove;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// ── Game logic ──
|
|
91
|
-
function makeMove(index) {
|
|
92
|
-
if (board[index] || gameOver) return;
|
|
93
|
-
board[index] = currentPlayer;
|
|
94
|
-
const win = checkWin(board);
|
|
95
|
-
if (win) {
|
|
96
|
-
winLine = win;
|
|
97
|
-
gameOver = true;
|
|
98
|
-
scores[currentPlayer]++;
|
|
99
|
-
render();
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (isDraw(board)) {
|
|
103
|
-
gameOver = true;
|
|
104
|
-
scores.draw++;
|
|
105
|
-
render();
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
|
|
109
|
-
render();
|
|
110
|
-
|
|
111
|
-
// AI turn
|
|
112
|
-
if (mode === 'ai' && currentPlayer === 'O' && !gameOver) {
|
|
113
|
-
setTimeout(() => {
|
|
114
|
-
const move = getAiMove();
|
|
115
|
-
if (move >= 0) makeMove(move);
|
|
116
|
-
}, 200);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function resetBoard() {
|
|
121
|
-
board = Array(9).fill(null);
|
|
122
|
-
currentPlayer = 'X';
|
|
123
|
-
gameOver = false;
|
|
124
|
-
winLine = null;
|
|
125
|
-
render();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function resetScores() {
|
|
129
|
-
scores = { X: 0, O: 0, draw: 0 };
|
|
130
|
-
resetBoard();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// ── Render ──
|
|
134
|
-
function getStatusText() {
|
|
135
|
-
if (gameOver) {
|
|
136
|
-
const win = checkWin(board);
|
|
137
|
-
if (win) {
|
|
138
|
-
const winner = board[win[0]];
|
|
139
|
-
return winner === 'X' ? 'You win!' : 'AI wins!';
|
|
140
|
-
}
|
|
141
|
-
return "It's a draw!";
|
|
142
|
-
}
|
|
143
|
-
return currentPlayer === 'X' ? 'Your turn (X)' : 'AI thinking...';
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function render() {
|
|
147
|
-
const gridEl = root.querySelector('.ttt-grid');
|
|
148
|
-
const statusEl = root.querySelector('.ttt-status');
|
|
149
|
-
const scoreEl = root.querySelector('.ttt-scores');
|
|
150
|
-
|
|
151
|
-
if (!gridEl) return;
|
|
152
|
-
|
|
153
|
-
// Grid
|
|
154
|
-
gridEl.innerHTML = '';
|
|
155
|
-
for (let i = 0; i < 9; i++) {
|
|
156
|
-
const cell = document.createElement('div');
|
|
157
|
-
cell.className = 'ttt-cell';
|
|
158
|
-
cell.dataset.index = i;
|
|
159
|
-
if (board[i]) {
|
|
160
|
-
cell.textContent = board[i];
|
|
161
|
-
cell.classList.add(board[i] === 'X' ? 'is-x' : 'is-o');
|
|
162
|
-
}
|
|
163
|
-
if (winLine && winLine.includes(i)) cell.classList.add('winner');
|
|
164
|
-
if (!board[i] && !gameOver) cell.classList.add('empty');
|
|
165
|
-
gridEl.appendChild(cell);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Status
|
|
169
|
-
if (statusEl) {
|
|
170
|
-
statusEl.textContent = getStatusText();
|
|
171
|
-
statusEl.className = 'ttt-status';
|
|
172
|
-
if (gameOver) {
|
|
173
|
-
const win = checkWin(board);
|
|
174
|
-
if (win) {
|
|
175
|
-
const w = board[win[0]];
|
|
176
|
-
statusEl.classList.add(w === 'X' ? 'status-win' : 'status-lose');
|
|
177
|
-
} else {
|
|
178
|
-
statusEl.classList.add('status-draw');
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Scores
|
|
184
|
-
if (scoreEl) {
|
|
185
|
-
scoreEl.innerHTML = `
|
|
186
|
-
<span class="ttt-score-item"><span class="ttt-score-x">You</span> ${scores.X}</span>
|
|
187
|
-
<span class="ttt-score-sep">·</span>
|
|
188
|
-
<span class="ttt-score-item"><span class="ttt-score-draw">Draw</span> ${scores.draw}</span>
|
|
189
|
-
<span class="ttt-score-sep">·</span>
|
|
190
|
-
<span class="ttt-score-item"><span class="ttt-score-o">AI</span> ${scores.O}</span>
|
|
191
|
-
`;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// ── Build DOM ──
|
|
196
|
-
root.innerHTML = `
|
|
197
|
-
<div class="ttt-header">
|
|
198
|
-
<div class="ttt-diff-btns">
|
|
199
|
-
<button class="ttt-diff-btn" data-diff="easy">Easy</button>
|
|
200
|
-
<button class="ttt-diff-btn" data-diff="medium">Med</button>
|
|
201
|
-
<button class="ttt-diff-btn active" data-diff="hard">Hard</button>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
<div class="ttt-status">Your turn (X)</div>
|
|
205
|
-
<div class="ttt-board-wrap">
|
|
206
|
-
<div class="ttt-grid"></div>
|
|
207
|
-
</div>
|
|
208
|
-
<div class="ttt-scores"></div>
|
|
209
|
-
<div class="ttt-actions">
|
|
210
|
-
<button class="ttt-action-btn" data-action="restart">New Round</button>
|
|
211
|
-
<button class="ttt-action-btn" data-action="reset">Reset Scores</button>
|
|
212
|
-
</div>
|
|
213
|
-
`;
|
|
214
|
-
|
|
215
|
-
// ── Events ──
|
|
216
|
-
root.querySelector('.ttt-grid').addEventListener('click', (e) => {
|
|
217
|
-
const cell = e.target.closest('.ttt-cell');
|
|
218
|
-
if (!cell) return;
|
|
219
|
-
if (currentPlayer === 'O') return; // AI's turn
|
|
220
|
-
makeMove(+cell.dataset.index);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
root.querySelector('.ttt-diff-btns').addEventListener('click', (e) => {
|
|
224
|
-
const btn = e.target.closest('.ttt-diff-btn');
|
|
225
|
-
if (!btn) return;
|
|
226
|
-
difficulty = btn.dataset.diff;
|
|
227
|
-
root.querySelectorAll('.ttt-diff-btn').forEach(b => b.classList.toggle('active', b === btn));
|
|
228
|
-
resetBoard();
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
root.querySelector('.ttt-actions').addEventListener('click', (e) => {
|
|
232
|
-
const btn = e.target.closest('.ttt-action-btn');
|
|
233
|
-
if (!btn) return;
|
|
234
|
-
if (btn.dataset.action === 'restart') resetBoard();
|
|
235
|
-
else if (btn.dataset.action === 'reset') resetScores();
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
render();
|
|
239
|
-
return root;
|
|
240
|
-
},
|
|
241
|
-
});
|