clew-code 0.2.20 → 0.2.22
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/dist/main.js +1888 -1883
- package/docs/architecture.html +91 -148
- package/docs/assets/clew-agent-loop.png +0 -0
- package/docs/assets/clew-general-architecture.png +0 -0
- package/docs/assets/clew-mcp-architecture.png +0 -0
- package/docs/assets/clew-p2p-swarm.png +0 -0
- package/docs/changelog.html +150 -0
- package/docs/cli-reference.html +90 -0
- package/docs/commands.html +156 -265
- package/docs/configuration.html +85 -147
- package/docs/contributing.html +91 -0
- package/docs/css/styles.css +425 -425
- package/docs/daemon.html +62 -129
- package/docs/features/bridge-mode.html +61 -66
- package/docs/features/evals.html +57 -149
- package/docs/features/searxng-search.html +58 -118
- package/docs/features/sentry-setup.html +61 -124
- package/docs/index.html +137 -125
- package/docs/installation.html +77 -105
- package/docs/internals/growthbook-ab-testing.html +69 -91
- package/docs/internals/hidden-features.html +81 -143
- package/docs/js/main.js +29 -0
- package/docs/loop.html +69 -181
- package/docs/mcp.html +99 -247
- package/docs/models.html +69 -110
- package/docs/permission-model.html +86 -102
- package/docs/plugins.html +84 -102
- package/docs/providers.html +87 -127
- package/docs/quick-start.html +81 -93
- package/docs/research-memory.html +71 -102
- package/docs/security.html +71 -0
- package/docs/skills.html +67 -117
- package/docs/swarm.html +78 -236
- package/docs/tools.html +152 -151
- package/docs/troubleshooting.html +86 -106
- package/docs/voice-mode.html +79 -0
- package/package.json +1 -1
- package/docs/architecture.th.html +0 -79
- package/docs/clew-code-architecture.html +0 -1126
- package/docs/commands.th.html +0 -269
- package/docs/configuration.th.html +0 -108
- package/docs/daemon.th.html +0 -73
- package/docs/features/bridge-mode.th.html +0 -62
- package/docs/features/evals.th.html +0 -62
- package/docs/features/searxng-search.th.html +0 -67
- package/docs/features/sentry-setup.th.html +0 -69
- package/docs/features/swarm.html +0 -156
- package/docs/generated/providers.html +0 -625
- package/docs/generated/tools.html +0 -558
- package/docs/index.th.html +0 -292
- package/docs/installation.th.html +0 -105
- package/docs/internals/growthbook-ab-testing.th.html +0 -60
- package/docs/internals/hidden-features.th.html +0 -107
- package/docs/loop.th.html +0 -227
- package/docs/mcp.th.html +0 -207
- package/docs/models.th.html +0 -61
- package/docs/permission-model.th.html +0 -67
- package/docs/plugins.th.html +0 -79
- package/docs/prompts-and-features.html +0 -806
- package/docs/providers.th.html +0 -81
- package/docs/quick-start.th.html +0 -89
- package/docs/research-memory.th.html +0 -72
- package/docs/skills.th.html +0 -90
- package/docs/swarm.th.html +0 -280
- package/docs/tools.th.html +0 -84
- package/docs/troubleshooting.th.html +0 -85
package/docs/loop.th.html
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="th">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Agent Loop — Clew Code</title>
|
|
7
|
-
<meta name="description" content="Autonomous agent loop — task queue consumer, worker lifecycle, retry logic, dead-letter queue, lease-based concurrency">
|
|
8
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
-
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Noto+Sans+Thai:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
11
|
-
<link rel="stylesheet" href="css/styles.css">
|
|
12
|
-
<link rel="icon" type="image/svg+xml" href="./assets/clew.svg">
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<header class="header"></header>
|
|
16
|
-
<div class="app">
|
|
17
|
-
<aside class="sidebar" id="sidebar"></aside>
|
|
18
|
-
<div class="sidebar-overlay" id="sidebarOverlay"></div>
|
|
19
|
-
<div class="content-wrap">
|
|
20
|
-
<main class="content">
|
|
21
|
-
<div class="breadcrumbs"><a href="index.th.html">หน้าแรก</a><span class="sep">/</span><span>Agent Loop</span></div>
|
|
22
|
-
<h1>Autonomous Agent Loop</h1>
|
|
23
|
-
<p class="section-subtitle">Loop ที่รันอัตโนมัติ 24/7 — ดึงงานจากคิว, spawn worker, เช็คสถานะ, retry เมื่อ fail, dead-letter เมื่อเกิน max retry</p>
|
|
24
|
-
|
|
25
|
-
<p>Agent Loop อยู่ใน <code>src/services/autonomous/agentLoop.ts</code> — เป็น consumer ตัวเดียวที่อ่าน task queue และบริหาร lifecycle ของ worker process ทั้งหมด</p>
|
|
26
|
-
|
|
27
|
-
<h2>เทคนิคและหลักการ</h2>
|
|
28
|
-
|
|
29
|
-
<h3>ทำไมต้องเป็น Loop แทนที่จะเป็น Message Queue?</h3>
|
|
30
|
-
<p>ระบบ message queue แบบ RabbitMQ/Kafka มี overhead ในการ setup และ maintenance Agent Loop ใช้<strong>ไฟล์ JSON เป็น persistent queue</strong> — ทำงานได้โดยไม่ต้องมี external dependency:</p>
|
|
31
|
-
<ul>
|
|
32
|
-
<li><strong>Zero external deps</strong> — ใช้ <code>fs.watch</code> ตรวจจับการเปลี่ยนแปลงของไฟล์ queue</li>
|
|
33
|
-
<li><strong>File-based atomicity</strong> — อ่าน/เขียนไฟล์เดียวภายใต้ lock ทำให้หลาย process แข่งกัน consume ได้</li>
|
|
34
|
-
<li><strong>Self-debouncing</strong> — <code>ourWriteInProgress</code> flag ป้องกัน self-trigger เมื่อเราเป็นคนเขียนเอง</li>
|
|
35
|
-
<li><strong>Cross-platform</strong> — ไฟล์ JSON ทำงานได้ทุก OS ไม่ต้องติดตั้ง message broker</li>
|
|
36
|
-
</ul>
|
|
37
|
-
|
|
38
|
-
<h3>Lease-Based Concurrency — ป้องกัน Task Duplicate</h3>
|
|
39
|
-
<p>ปัญหาคลาสสิกของ distributed workers: มี 2 worker เห็น task เดียวกันและทำงานซ้ำ Lease แก้ปัญหานี้โดยไม่ต้องใช้ distributed lock:</p>
|
|
40
|
-
<pre><code>Main Loop Queue File (.json) Worker Process
|
|
41
|
-
│ │ │
|
|
42
|
-
│ getNextTask() │ │
|
|
43
|
-
│─────────────────────────────►│ │
|
|
44
|
-
│◄─── task {id, status:pending}│ │
|
|
45
|
-
│ │ │
|
|
46
|
-
│ leaseTask(id, agentId) │ │
|
|
47
|
-
│─────────────────────────────►│ │
|
|
48
|
-
│ (atomic: check no lease │ │
|
|
49
|
-
│ → write leaseOwner + │ │
|
|
50
|
-
│ leaseExpiresAt) │ │
|
|
51
|
-
│◄─────── true (leased) ──────│ │
|
|
52
|
-
│ │ │
|
|
53
|
-
│ spawnWorker(prompt) │ │
|
|
54
|
-
│─────────────────────────────────────────────────────────────►│
|
|
55
|
-
│◄──── WorkerSession {id, pid} │ │
|
|
56
|
-
│ │ │
|
|
57
|
-
│ ═══ LOOP ═══ │ │
|
|
58
|
-
│ while running: │ │
|
|
59
|
-
│ checkWorker(sessionId) │ │
|
|
60
|
-
│ ────────────────────────────────────────────────────────►│
|
|
61
|
-
│ ◄─── "running" / "completed" / "failed" │
|
|
62
|
-
│ │ │
|
|
63
|
-
│ │ (worker ทำงาน autonomously) │
|
|
64
|
-
│ │ │
|
|
65
|
-
│ [completed] → releaseLease │ │
|
|
66
|
-
│ → markCompleted │ │
|
|
67
|
-
│ │ │
|
|
68
|
-
│ [failed] → markFailed │ │
|
|
69
|
-
│ → retryTask() │ │
|
|
70
|
-
│ → stopWorker() │ │
|
|
71
|
-
│ │ │
|
|
72
|
-
│ [timeout 30m] → stopWorker │ │
|
|
73
|
-
│ → releaseLease│ │
|
|
74
|
-
│ → retryTask() │ │</code></pre>
|
|
75
|
-
<ul>
|
|
76
|
-
<li><strong>Lease owner</strong> — ระบุว่า worker ไหนกำลังทำ task นี้</li>
|
|
77
|
-
<li><strong>Lease expiry</strong> — ถ้า worker crash โดยไม่ release, lease จะหมดอายุเอง → worker อื่นรับงานต่อได้</li>
|
|
78
|
-
<li><strong>Startup recovery</strong> — ตอน <code>startLoop</code> จะรอ 2 วินาที (ให้ process เก่าตายแน่ๆ) แล้วเรียก <code>expireLeases()</code> ล้าง stale lease ทั้งหมด</li>
|
|
79
|
-
</ul>
|
|
80
|
-
|
|
81
|
-
<h3>Retry with Exponential Backoff</h3>
|
|
82
|
-
<p>Task ที่ fail ไม่ได้แปลว่าต้อง dead-letter ทันที:</p>
|
|
83
|
-
<pre><code>Retry attempt Backoff delay Cumulative wait
|
|
84
|
-
───────────── ───────────── ──────────────
|
|
85
|
-
1 base × 2¹ = 30s 30s
|
|
86
|
-
2 base × 2² = 60s 90s
|
|
87
|
-
3 base × 2³ = 120s 210s
|
|
88
|
-
4 base × 2⁴ = 240s 450s
|
|
89
|
-
5 (max) base × 2⁵ = 480s 930s (~15 min)
|
|
90
|
-
|
|
91
|
-
After max retries → dead_letter queue
|
|
92
|
-
Dead-letter preserves: title, description, lastError, errorLog, retryCount</code></pre>
|
|
93
|
-
<ul>
|
|
94
|
-
<li><strong>Exponential backoff</strong> — base = 15s, factor = 2 — ลดการถล่ม queue เมื่อ task fail ซ้ำๆ</li>
|
|
95
|
-
<li><strong>Max retries</strong> — default 5 ครั้งต่อ task</li>
|
|
96
|
-
<li><strong>Retry interval</strong> — <code>retryAfter</code> timestamp ป้องกันไม่ให้ retry ก่อนเวลาที่กำหนด</li>
|
|
97
|
-
<li><strong>Dead-letter queue</strong> — task ที่ใช้ retry หมดจะถูกย้ายไปสถานะ <code>dead_letter</code> พร้อม <code>deadLetterReason</code> และ <code>errorLog</code> — ไม่หายไปไหน ตรวจสอบย้อนหลังได้</li>
|
|
98
|
-
</ul>
|
|
99
|
-
|
|
100
|
-
<h3>Worker Lifecycle + Concurrent Cap</h3>
|
|
101
|
-
<p>Main loop มีกลไกจำกัดจำนวน worker พร้อมกัน:</p>
|
|
102
|
-
<ul>
|
|
103
|
-
<li><strong>MAX_CONCURRENT_WORKERS = 3</strong> — ป้องกันไม่ให้ spawn worker มากเกินไปจนเครื่องพัง</li>
|
|
104
|
-
<li><strong>Loop poll interval</strong> — ถ้า worker เต็ม → sleep <code>LOOP_SLEEP_MS</code> (5s) แล้วตรวจใหม่</li>
|
|
105
|
-
<li><strong>Worker timeout = 30 นาที</strong> — task ที่รันนานเกินจะถูก kill เพื่อคืน resource</li>
|
|
106
|
-
<li><strong>Worker poll = 10s</strong> — เช็คสถานะ worker ทุก 10 วินาทีผ่าน supervisor IPC</li>
|
|
107
|
-
</ul>
|
|
108
|
-
|
|
109
|
-
<h3>Supervisor Integration — Process Health</h3>
|
|
110
|
-
<p>Worker ไม่ได้ถูกรันโดยตรง แต่ spawn ผ่าน<strong>Supervisor process</strong> (child_process):</p>
|
|
111
|
-
<pre><code>Agent Loop Supervisor Worker
|
|
112
|
-
│ │ │
|
|
113
|
-
│ sendRequest({type:'spawn'}) │ │
|
|
114
|
-
│─────────────────────────────►│ │
|
|
115
|
-
│ │ spawn child_process │
|
|
116
|
-
│ │────────────────────────►│
|
|
117
|
-
│◄─── {ok:true, sessionId, pid}│ │
|
|
118
|
-
│ │ │
|
|
119
|
-
│ sendRequest({type:'attach'}) │ │
|
|
120
|
-
│─────────────────────────────►│ │
|
|
121
|
-
│ │ check process status │
|
|
122
|
-
│◄─── {status, isRunning} │ │
|
|
123
|
-
│ │ │
|
|
124
|
-
│ sendRequest({type:'stop'}) │ │
|
|
125
|
-
│─────────────────────────────►│ │
|
|
126
|
-
│ │ kill + cleanup │
|
|
127
|
-
│ │────────────────────────►│</code></pre>
|
|
128
|
-
<ul>
|
|
129
|
-
<li><strong>Crash isolation</strong> — worker crash ไม่ทำให้ loop crash — supervisor แยก process คนละตัว</li>
|
|
130
|
-
<li><strong>Output capture</strong> — supervisor เก็บ stdout/stderr ของ worker ไว้ใน <code>~/.clew/daemon/jobs/{sessionId}/output.log</code></li>
|
|
131
|
-
<li><strong>Health monitoring</strong> — loop เช็คผ่าน supervisor แทนที่จะ monitor PID โดยตรง (PID reuse problem)</li>
|
|
132
|
-
</ul>
|
|
133
|
-
|
|
134
|
-
<h3>Integration Points — Peer + Cron + Watch</h3>
|
|
135
|
-
<p>Agent Loop ไม่ได้อยู่เดี่ยวๆ — มัน integrate กับระบบอื่นของ Clew:</p>
|
|
136
|
-
<ul>
|
|
137
|
-
<li><strong>Peer todo listener</strong> — ฟัง <code>/peer-todo</code> HTTP endpoint → รับ task จาก remote peer → add เข้า queue</li>
|
|
138
|
-
<li><strong>Cron scheduler</strong> — <code>daemonCronScheduler</code> fire task ตาม schedule → add เข้า queue</li>
|
|
139
|
-
<li><strong>File watcher</strong> — <code>fs.watch</code> บน queue file → ตรวจจับ task ใหม่จาก process อื่น (เช่นจาก CLI <code>/task add</code>)</li>
|
|
140
|
-
</ul>
|
|
141
|
-
<p>architecture แบบนี้ทำให้ task เข้า queue ได้จากหลายช่องทาง — CLI, remote peer, cron — แต่มี consumer เดียว (loop) ที่คุมการ execute</p>
|
|
142
|
-
|
|
143
|
-
<h3>Task Log Persistence</h3>
|
|
144
|
-
<p>ทุก task มี log ของตัวเอง:</p>
|
|
145
|
-
<ul>
|
|
146
|
-
<li><strong>Per-task log</strong> — <code>~/.clew/daemon/logs/{taskId}.log</code> — 500 บรรทัดสุดท้ายของ worker output</li>
|
|
147
|
-
<li><strong>Error extraction</strong> — ตอน task fail, loop จะ extract non-noise lines (20 บรรทัดสุดท้าย) เก็บเป็น <code>errorLog[]</code> ใน queue entry</li>
|
|
148
|
-
<li><strong>Worker exit code</strong> — บันทึกว่า worker จบด้วย exit code 0 (success) หรือ 1 (failure)</li>
|
|
149
|
-
</ul>
|
|
150
|
-
|
|
151
|
-
<h3>Crash Recovery Flow</h3>
|
|
152
|
-
<p>ถ้า loop process ตาย (kill -9, power loss, OOM):</p>
|
|
153
|
-
<pre><code>Previous Run Crash
|
|
154
|
-
│
|
|
155
|
-
▼
|
|
156
|
-
startLoop() called
|
|
157
|
-
│
|
|
158
|
-
├── loadQueue() — อ่านไฟล์ queue จาก disk
|
|
159
|
-
│
|
|
160
|
-
├── sleep(2000ms) — รอให้แน่ใจว่า process เก่าตายแล้ว
|
|
161
|
-
│
|
|
162
|
-
├── expireLeases() — ล้าง lease ทั้งหมดที่หมดอายุ
|
|
163
|
-
│ (task ที่ถูก lease โดย processID เก่าจะถูก reset → pending)
|
|
164
|
-
│
|
|
165
|
-
├── start heartbeat (ทุก 60s)
|
|
166
|
-
│
|
|
167
|
-
├── start cron scheduler
|
|
168
|
-
│
|
|
169
|
-
├── start peer sharing
|
|
170
|
-
│
|
|
171
|
-
├── start file watcher
|
|
172
|
-
│
|
|
173
|
-
└── MAIN LOOP ──► getNextTask() → processTask() → loop</code></pre>
|
|
174
|
-
|
|
175
|
-
<h2>Task Lifecycle (State Machine)</h2>
|
|
176
|
-
<pre><code> ┌──────────┐
|
|
177
|
-
│ pending │◄──────────────────────────────┐
|
|
178
|
-
└────┬─────┘ │
|
|
179
|
-
│ leaseTask() │
|
|
180
|
-
▼ │
|
|
181
|
-
┌──────────┐ │
|
|
182
|
-
│in_progress│ │
|
|
183
|
-
└────┬─────┘ │
|
|
184
|
-
┌───────────┼───────────┐ │
|
|
185
|
-
▼ ▼ ▼ │
|
|
186
|
-
┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
187
|
-
│completed │ │ failed │ │cancelled │ │
|
|
188
|
-
└──────────┘ └────┬─────┘ └──────────┘ │
|
|
189
|
-
│ retryTask() │
|
|
190
|
-
├── retryCount < max → backoff → ────┘
|
|
191
|
-
│
|
|
192
|
-
└── retryCount ≥ max
|
|
193
|
-
│
|
|
194
|
-
▼
|
|
195
|
-
┌──────────────┐
|
|
196
|
-
│ dead_letter │
|
|
197
|
-
│ (preserved │
|
|
198
|
-
│ for review) │
|
|
199
|
-
└──────────────┘</code></pre>
|
|
200
|
-
|
|
201
|
-
<h2>ไฟล์ที่เกี่ยวข้อง</h2>
|
|
202
|
-
<table>
|
|
203
|
-
<tr><th>ไฟล์</th><th>หน้าที่</th></tr>
|
|
204
|
-
<tr><td><code>src/services/autonomous/agentLoop.ts</code></td><td>Main loop — start, stop, processTask, worker lifecycle</td></tr>
|
|
205
|
-
<tr><td><code>src/services/autonomous/taskQueue.ts</code></td><td>Queue CRUD, lease management, retry, dead-letter, file watcher</td></tr>
|
|
206
|
-
<tr><td><code>src/services/autonomous/daemonMode.ts</code></td><td>Daemon entry point — calls startLoop/stopLoop</td></tr>
|
|
207
|
-
<tr><td><code>src/Task.ts</code></td><td>Task type definitions, state machine, task ID generation</td></tr>
|
|
208
|
-
<tr><td><code>src/tasks/LocalAgentTask/</code></td><td>Local worker task — UI + lifecycle</td></tr>
|
|
209
|
-
<tr><td><code>src/tasks/RemoteAgentTask/</code></td><td>Remote worker task — UI + lifecycle</td></tr>
|
|
210
|
-
<tr><td><code>src/components/AutonomousExecutionAccordion.tsx</code></td><td>UI component สำหรับแสดง task queue ใน REPL</td></tr>
|
|
211
|
-
</table>
|
|
212
|
-
|
|
213
|
-
<footer class="footer">
|
|
214
|
-
<span>Clew Code — Open Source</span>
|
|
215
|
-
<div class="footer-links">
|
|
216
|
-
<a href="https://github.com/ClewCode/ClewCode">GitHub</a>
|
|
217
|
-
<a href="https://github.com/ClewCode/ClewCode/issues">Issues</a>
|
|
218
|
-
</div>
|
|
219
|
-
</footer>
|
|
220
|
-
</main>
|
|
221
|
-
<nav class="toc-sidebar"></nav>
|
|
222
|
-
</div>
|
|
223
|
-
</div>
|
|
224
|
-
<script src="js/main.js"></script>
|
|
225
|
-
</body>
|
|
226
|
-
</html>
|
|
227
|
-
|
package/docs/mcp.th.html
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="th">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>MCP — Clew Code</title>
|
|
7
|
-
<meta name="description" content="Model Context Protocol (MCP) — เชื่อมต่อเครื่องมือภายนอก, ทรัพยากร, และบริการ ผ่าน stdio, SSE, และ OAuth">
|
|
8
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
-
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Noto+Sans+Thai:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
11
|
-
<link rel="stylesheet" href="css/styles.css">
|
|
12
|
-
<link rel="icon" type="image/svg+xml" href="./assets/clew.svg">
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<header class="header"></header>
|
|
16
|
-
<div class="app">
|
|
17
|
-
<aside class="sidebar" id="sidebar"></aside>
|
|
18
|
-
<div class="sidebar-overlay" id="sidebarOverlay"></div>
|
|
19
|
-
<div class="content-wrap">
|
|
20
|
-
<main class="content">
|
|
21
|
-
<div class="breadcrumbs"><a href="index.th.html">หน้าแรก</a><span class="sep">/</span><span>MCP</span></div>
|
|
22
|
-
<h1>Model Context Protocol (MCP)</h1>
|
|
23
|
-
<p class="section-subtitle">เชื่อมต่อ Clew กับเครื่องมือภายนอก, แหล่งข้อมูล, และบริการผ่าน MCP — มาตรฐานเปิดสำหรับ AI-tool integration</p>
|
|
24
|
-
|
|
25
|
-
<p>MCP อยู่ใน <code>src/services/mcp/</code> — Clew ค้นหาเซิร์ฟเวอร์ MCP จาก <strong>settings.json</strong>, <strong>CLI flags</strong>, และ <strong>plugin manifests</strong> แล้วรวมเครื่องมือเข้าสู่ runtime</p>
|
|
26
|
-
|
|
27
|
-
<h2>สถาปัตยกรรม</h2>
|
|
28
|
-
<pre><code> ┌──────────────────────────────────────────────────────────────────────────┐
|
|
29
|
-
│ MCP — MODEL CONTEXT PROTOCOL │
|
|
30
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
31
|
-
|
|
32
|
-
┌──────────────────────────┐
|
|
33
|
-
│ Settings / CLI Config │
|
|
34
|
-
│ src/services/mcp/config │
|
|
35
|
-
└────────────┬─────────────┘
|
|
36
|
-
│
|
|
37
|
-
▼
|
|
38
|
-
┌──────────────────────────┐
|
|
39
|
-
│ MCPConnectionManager │
|
|
40
|
-
│ จัดการ lifecycle │
|
|
41
|
-
│ ของเซิร์ฟเวอร์ MCP ทั้งหมด │
|
|
42
|
-
└────────────┬─────────────┘
|
|
43
|
-
│
|
|
44
|
-
┌───────────────────┼───────────────────┐
|
|
45
|
-
▼ ▼ ▼
|
|
46
|
-
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
47
|
-
│ Stdio MCP │ │ SSE MCP │ │Direct Connect│
|
|
48
|
-
│ (subprocess) │ │ (remote) │ │ (in-process) │
|
|
49
|
-
│ npx/node/etc │ │ HTTP + SSE │ │ │
|
|
50
|
-
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
|
51
|
-
│ │ │
|
|
52
|
-
└──────────────────┼───────────────────┘
|
|
53
|
-
│
|
|
54
|
-
▼
|
|
55
|
-
┌──────────────────────┐
|
|
56
|
-
│ Client (JSON-RPC) │
|
|
57
|
-
│ tools/list │
|
|
58
|
-
│ tools/call │
|
|
59
|
-
│ resources/list │
|
|
60
|
-
└──────────┬───────────┘
|
|
61
|
-
│
|
|
62
|
-
▼
|
|
63
|
-
┌──────────────────────┐
|
|
64
|
-
│ assembleToolPool │
|
|
65
|
-
│ (MCP + built-in │
|
|
66
|
-
│ tools รวมกัน) │
|
|
67
|
-
└──────────┬───────────┘
|
|
68
|
-
│
|
|
69
|
-
▼
|
|
70
|
-
┌──────────────────────┐
|
|
71
|
-
│ Query Engine │
|
|
72
|
-
│ Model เห็น tools │
|
|
73
|
-
│ ทั้งหมดใน pool │
|
|
74
|
-
└──────────────────────┘</code></pre>
|
|
75
|
-
|
|
76
|
-
<h2>วิธีการทำงาน</h2>
|
|
77
|
-
|
|
78
|
-
<h3>การค้นหาเซิร์ฟเวอร์</h3>
|
|
79
|
-
<p>MCP servers ถูกค้นหาจาก 3 แหล่งเมื่อเริ่มต้น:</p>
|
|
80
|
-
<ol>
|
|
81
|
-
<li><strong><code>settings.json</code></strong> — คีย์ <code>mcpServers</code> กำหนด command, args, env</li>
|
|
82
|
-
<li><strong>CLI <code>--mcp-config</code></strong> — ไฟล์หรือ inline JSON</li>
|
|
83
|
-
<li><strong>Plugins</strong> — manifest ของ plugin สามารถประกาศ MCP server ได้; เริ่มเมื่อ plugin โหลด, หยุดเมื่อ unload</li>
|
|
84
|
-
</ol>
|
|
85
|
-
|
|
86
|
-
<h3>ประเภทการเชื่อมต่อ</h3>
|
|
87
|
-
<table>
|
|
88
|
-
<tr><th>ประเภท</th><th>Transport</th><th>วิธีการ</th></tr>
|
|
89
|
-
<tr>
|
|
90
|
-
<td><strong>Stdio</strong></td>
|
|
91
|
-
<td>stdin/stdout</td>
|
|
92
|
-
<td>Clew spawn subprocess (เช่น <code>npx @modelcontextprotocol/server-filesystem</code>) และสื่อสารผ่าน JSON-RPC ทาง stdin/stdout</td>
|
|
93
|
-
</tr>
|
|
94
|
-
<tr>
|
|
95
|
-
<td><strong>SSE</strong></td>
|
|
96
|
-
<td>HTTP + SSE</td>
|
|
97
|
-
<td>เชื่อมต่อ remote MCP server ผ่าน HTTP ใช้ SSE สำหรับ server→client, HTTP POST สำหรับ client→server รองรับ OAuth</td>
|
|
98
|
-
</tr>
|
|
99
|
-
<tr>
|
|
100
|
-
<td><strong>Direct Connect</strong></td>
|
|
101
|
-
<td>In-process</td>
|
|
102
|
-
<td>รัน MCP server ใน process เดียวกัน ใช้ InProcessTransport — ไม่มี network, ไม่มี subprocess ใช้ใน plugin-bundled servers</td>
|
|
103
|
-
</tr>
|
|
104
|
-
</table>
|
|
105
|
-
|
|
106
|
-
<h3>Tool Lifecycle</h3>
|
|
107
|
-
<pre><code> 1. CONNECT ──► MCPConnectionManager เชื่อมต่อ server
|
|
108
|
-
│
|
|
109
|
-
▼
|
|
110
|
-
2. DISCOVER ──► เรียก tools/list (รองรับ paginated)
|
|
111
|
-
│
|
|
112
|
-
▼
|
|
113
|
-
3. MERGE ──► assembleToolPool() รวม MCP tools
|
|
114
|
-
│ กับ built-in tools (sort + dedup)
|
|
115
|
-
▼
|
|
116
|
-
4. PRESENT ──► Model เห็น MCP tools เป็น native tools
|
|
117
|
-
│ (permission gating, hooks, logging)
|
|
118
|
-
▼
|
|
119
|
-
5. EXECUTE ──► Model เรียก tool → toolExecution.ts
|
|
120
|
-
│ route ไปยัง server ที่ถูกต้อง
|
|
121
|
-
▼
|
|
122
|
-
6. RESPOND ──► ผลลัพธ์กลับไปหา model</code></pre>
|
|
123
|
-
|
|
124
|
-
<h3>การยืนยันตัวตน (Authentication)</h3>
|
|
125
|
-
<ul>
|
|
126
|
-
<li><strong>OAuth 2.0</strong> — redirect flow สำหรับ remote MCP servers เปิด local HTTP port เพื่อรับ callback</li>
|
|
127
|
-
<li><strong>Bearer token</strong> — static API token ใน <code>Authorization</code> header</li>
|
|
128
|
-
<li><strong>XAA token</strong> — auth provider token สำหรับ MCP servers</li>
|
|
129
|
-
<li><strong>Credential vault</strong> — credentials ที่เก็บไว้ใน vault ถูก inject อัตโนมัติ</li>
|
|
130
|
-
</ul>
|
|
131
|
-
|
|
132
|
-
<h2>คำสั่ง MCP</h2>
|
|
133
|
-
<table>
|
|
134
|
-
<tr><th>คำสั่ง</th><th>คำอธิบาย</th></tr>
|
|
135
|
-
<tr><td><code>/mcp</code></td><td>เปิดเมนูจัดการ MCP — list servers, add, remove, reconnect</td></tr>
|
|
136
|
-
<tr><td><code>/mcp list</code></td><td>แสดงเซิร์ฟเวอร์ MCP ทั้งหมด พร้อม tools, resources, prompts</td></tr>
|
|
137
|
-
<tr><td><code>/mcp add <name> <command> [args...]</code></td><td>เพิ่ม stdio MCP server ใหม่</td></tr>
|
|
138
|
-
<tr><td><code>/mcp remove <name></code></td><td>ลบ MCP server</td></tr>
|
|
139
|
-
<tr><td><code>/mcp reconnect <name></code></td><td>เชื่อมต่อ MCP server ใหม่</td></tr>
|
|
140
|
-
</table>
|
|
141
|
-
|
|
142
|
-
<h2>รูปแบบ Config (settings.json)</h2>
|
|
143
|
-
<div class="code-block-wrap">
|
|
144
|
-
<div class="code-block-header"><span>json</span></div>
|
|
145
|
-
<pre><code>{
|
|
146
|
-
"mcpServers": {
|
|
147
|
-
"filesystem": {
|
|
148
|
-
"command": "npx",
|
|
149
|
-
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
|
|
150
|
-
"env": {}
|
|
151
|
-
},
|
|
152
|
-
"database": {
|
|
153
|
-
"command": "node",
|
|
154
|
-
"args": ["./mcp/db-server.js"],
|
|
155
|
-
"env": {
|
|
156
|
-
"DB_URL": "postgresql://localhost:5432/mydb"
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
"remote-api": {
|
|
160
|
-
"url": "https://mcp.example.com",
|
|
161
|
-
"headers": {
|
|
162
|
-
"Authorization": "Bearer sk-..."
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}</code></pre>
|
|
167
|
-
</div>
|
|
168
|
-
|
|
169
|
-
<h2>Plugin-Bundled MCP Servers</h2>
|
|
170
|
-
<p>Plugin สามารถประกาศ MCP server ใน manifest เมื่อ plugin โหลด Clew จะสร้าง DirectConnect session ให้อัตโนมัติ — ไม่ต้อง subprocess ไม่ต้อง network — server จะพร้อมใช้งานทันที</p>
|
|
171
|
-
|
|
172
|
-
<h2>เครื่องมือ Built-in ที่ใช้ MCP</h2>
|
|
173
|
-
<table>
|
|
174
|
-
<tr><th>Tool</th><th>MCP ใช้ทำอะไร</th></tr>
|
|
175
|
-
<tr><td><code>ListMcpResources</code></td><td>แสดง resources จาก MCP servers ทั้งหมด (resources/list)</td></tr>
|
|
176
|
-
<tr><td><code>ReadMcpResource</code></td><td>อ่าน resource ตาม URI จาก MCP server (resources/read)</td></tr>
|
|
177
|
-
</table>
|
|
178
|
-
|
|
179
|
-
<h2>ไฟล์สำคัญ</h2>
|
|
180
|
-
<table>
|
|
181
|
-
<tr><th>ไฟล์</th><th>หน้าที่</th></tr>
|
|
182
|
-
<tr><td><code>src/services/mcp/MCPConnectionManager.tsx</code></td><td>จัดการ lifecycle ของเซิร์ฟเวอร์ MCP</td></tr>
|
|
183
|
-
<tr><td><code>src/services/mcp/config.ts</code></td><td>โหลด config จาก settings.json และ CLI flags</td></tr>
|
|
184
|
-
<tr><td><code>src/services/mcp/client.ts</code></td><td>JSON-RPC client</td></tr>
|
|
185
|
-
<tr><td><code>src/services/mcp/auth.ts</code></td><td>OAuth + Bearer token authentication</td></tr>
|
|
186
|
-
<tr><td><code>src/services/mcp/oauthPort.ts</code></td><td>Local HTTP server สำหรับ OAuth callback</td></tr>
|
|
187
|
-
<tr><td><code>src/services/mcp/types.ts</code></td><td>Type definitions</td></tr>
|
|
188
|
-
<tr><td><code>src/services/mcp/InProcessTransport.ts</code></td><td>In-process transport สำหรับ DirectConnect</td></tr>
|
|
189
|
-
<tr><td><code>src/services/mcp/officialRegistry.ts</code></td><td>ทะเบียน MCP server ทางการ</td></tr>
|
|
190
|
-
<tr><td><code>src/tools.ts</code></td><td>assembleToolPool() รวม MCP tools</td></tr>
|
|
191
|
-
</table>
|
|
192
|
-
|
|
193
|
-
<footer class="footer">
|
|
194
|
-
<span>Clew Code — โอเพนซอร์ส</span>
|
|
195
|
-
<div class="footer-links">
|
|
196
|
-
<a href="https://github.com/ClewCode/ClewCode">GitHub</a>
|
|
197
|
-
<a href="https://github.com/ClewCode/ClewCode/issues">ปัญหา</a>
|
|
198
|
-
</div>
|
|
199
|
-
</footer>
|
|
200
|
-
</main>
|
|
201
|
-
<nav class="toc-sidebar"></nav>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
<script src="js/main.js"></script>
|
|
205
|
-
</body>
|
|
206
|
-
</html>
|
|
207
|
-
|
package/docs/models.th.html
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="th">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>โมเดล — Clew</title>
|
|
7
|
-
<meta name="description" content="คู่มือการเลือกโมเดลสำหรับ Clew — วิธีเลือก, สลับ, และจัดการโมเดลจาก 27 ผู้ให้บริการ">
|
|
8
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
-
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Noto+Sans+Thai:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
11
|
-
<link rel="stylesheet" href="css/styles.css">
|
|
12
|
-
<link rel="icon" type="image/svg+xml" href="./assets/clew.svg">
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<header class="header"></header>
|
|
16
|
-
<div class="app"><aside class="sidebar" id="sidebar"></aside><div class="sidebar-overlay" id="sidebarOverlay"></div>
|
|
17
|
-
<div class="content-wrap"><main class="content">
|
|
18
|
-
<div class="breadcrumbs"><a href="index.th.html">หน้าแรก</a><span class="sep">/</span><span>โมเดล</span></div>
|
|
19
|
-
<h1>โมเดล</h1>
|
|
20
|
-
<p class="section-subtitle">Clew รองรับ 100+ โมเดลจาก 27 ผู้ให้บริการ เลือกโมเดลที่เหมาะกับแต่ละงาน — จากการใช้เหตุผลระดับสูงไปจนถึงการอนุมานในเครื่องที่รวดเร็ว</p>
|
|
21
|
-
|
|
22
|
-
<h2>คู่มือการเลือกโมเดล</h2>
|
|
23
|
-
<table>
|
|
24
|
-
<tr><th>ลักษณะงาน</th><th>โมเดลแนะนำ</th><th>บริบท</th><th>หมายเหตุ</th></tr>
|
|
25
|
-
<tr><td>สถาปัตยกรรมซับซ้อนและแก้ไขขนาดใหญ่</td><td>claude-opus-4-7, claude-sonnet-4-6, gpt-5.5, deepseek-v4-pro</td><td>1M โทเค็น</td><td>การเรียกใช้เครื่องมือดีที่สุด, การใช้เหตุผลแข็งแกร่ง, บริบทใหญ่ที่สุด</td></tr>
|
|
26
|
-
<tr><td>รีวิวโค้ดและดีบัก</td><td>claude-sonnet-4-6, gpt-5.5, gemini-3.1-pro</td><td>1M-2M โทเค็น</td><td>ทำตามคำแนะนำดี, ผลลัพธ์เชื่อถือได้</td></tr>
|
|
27
|
-
<tr><td>ค้นหาและสรุปผลอย่างรวดเร็ว</td><td>claude-haiku-4-5, deepseek-v4-flash, mistral-small-4, groq/llama-3.3-70b</td><td>128K-200K</td><td>เร็ว, คุ้มค่า, หน่วงเวลาต่ำ</td></tr>
|
|
28
|
-
<tr><td>ออฟไลน์ / ไม่มีเครือข่าย</td><td>ollama/llama4:70b, ollama/llama3.3</td><td>131K โทเค็น</td><td>ในเครื่องทั้งหมด, ไม่ต้องใช้เครือข่าย</td></tr>
|
|
29
|
-
</table>
|
|
30
|
-
|
|
31
|
-
<h2>การสลับโมเดล</h2>
|
|
32
|
-
<pre><code>/model # ตัวเลือกแบบโต้ตอบ
|
|
33
|
-
/model list # แสดงโมเดลทั้งหมดจากผู้ให้บริการที่ใช้งาน
|
|
34
|
-
/model claude-sonnet-4-7 # สลับด้วย ID เต็ม
|
|
35
|
-
/model sonnet # สลับด้วย alias
|
|
36
|
-
--model opus # CLI flag ตอนเริ่ม</code></pre>
|
|
37
|
-
|
|
38
|
-
<h2>CLI Flags สำหรับโมเดล</h2>
|
|
39
|
-
<table>
|
|
40
|
-
<tr><th>Flag</th><th>คำอธิบาย</th></tr>
|
|
41
|
-
<tr><td><code>--model <name></code></td><td>ตั้งค่าโมเดลตอนเริ่ม</td></tr>
|
|
42
|
-
<tr><td><code>--effort <level></code></td><td>ตั้งค่าระดับการใช้เหตุผล: low, medium, high, max</td></tr>
|
|
43
|
-
<tr><td><code>--thinking <mode></code></td><td>โหมดการคิด: enabled, adaptive, disabled</td></tr>
|
|
44
|
-
<tr><td><code>--fallback-model <model></code></td><td>โมเดลสำรองเมื่อโมเดลหลักโอเวอร์โหลด</td></tr>
|
|
45
|
-
</table>
|
|
46
|
-
|
|
47
|
-
<footer class="footer">
|
|
48
|
-
<span>Clew 0.2.14 — โอเพนซอร์ส</span>
|
|
49
|
-
<div class="footer-links">
|
|
50
|
-
<a href="https://github.com/ClewCode/ClewCode">GitHub</a>
|
|
51
|
-
<a href="https://github.com/ClewCode/ClewCode/issues">ปัญหา</a>
|
|
52
|
-
</div>
|
|
53
|
-
</footer>
|
|
54
|
-
</main>
|
|
55
|
-
<nav class="toc-sidebar"></nav>
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
<script src="js/main.js"></script>
|
|
59
|
-
</body>
|
|
60
|
-
</html>
|
|
61
|
-
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="th">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>โมเดลสิทธิ์ — Clew</title>
|
|
7
|
-
<meta name="description" content="สิทธิ์การดำเนินการเครื่องมือใน Clew — โหมด, กฎ, และความปลอดภัย">
|
|
8
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
-
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Noto+Sans+Thai:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
11
|
-
<link rel="stylesheet" href="css/styles.css">
|
|
12
|
-
<link rel="icon" type="image/svg+xml" href="./assets/clew.svg">
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<header class="header"></header>
|
|
16
|
-
<div class="app"><aside class="sidebar" id="sidebar"></aside><div class="sidebar-overlay" id="sidebarOverlay"></div>
|
|
17
|
-
<div class="content-wrap"><main class="content">
|
|
18
|
-
<div class="breadcrumbs"><a href="index.th.html">หน้าแรก</a><span class="sep">/</span><span>โมเดลสิทธิ์</span></div>
|
|
19
|
-
<h1>โมเดลสิทธิ์</h1>
|
|
20
|
-
<p class="section-subtitle">Clew ควบคุมการดำเนินการเครื่องมือผ่านระบบสิทธิ์แบบหลายชั้นพร้อมหลายโหมด, กฎอนุญาต/ปฏิเสธ, และการตรวจสอบเฉพาะเครื่องมือ</p>
|
|
21
|
-
|
|
22
|
-
<h2>โหมดสิทธิ์</h2>
|
|
23
|
-
<p>กำหนดใน <code>src/types/permissions.ts</code> เจ็ดโหมดที่ผู้ใช้เข้าถึงได้:</p>
|
|
24
|
-
<table>
|
|
25
|
-
<tr><th>โหมด</th><th>พฤติกรรม</th></tr>
|
|
26
|
-
<tr><td><code>default</code></td><td>ถามก่อนดำเนินการเครื่องมือที่ละเอียดอ่อน (read/write/bash/network) ค่าเริ่มต้นที่ปลอดภัย</td></tr>
|
|
27
|
-
<tr><td><code>ask</code></td><td>ถามก่อนทุกการดำเนินการเครื่องมือ</td></tr>
|
|
28
|
-
<tr><td><code>plan</code></td><td>ชอบโหมดวางแผน — AI ต้องนำเสนอแผนก่อนดำเนินการ</td></tr>
|
|
29
|
-
<tr><td><code>auto</code></td><td>อนุมัติอัตโนมัติสำหรับการกระทำความเสี่ยงต่ำ ถามสำหรับการดำเนินการเสี่ยง</td></tr>
|
|
30
|
-
<tr><td><code>acceptEdits</code></td><td>อนุมัติอัตโนมัติสำหรับการแก้ไขไฟล์ มีประโยชน์สำหรับการพัฒนาที่รวดเร็ว</td></tr>
|
|
31
|
-
<tr><td><code>bypassPermissions</code></td><td>ข้ามการขอสิทธิ์ทั้งหมด ใช้ใน sandbox ที่เชื่อถือได้เท่านั้น</td></tr>
|
|
32
|
-
<tr><td><code>dontAsk</code></td><td>ไม่ถาม — ปฏิเสธอัตโนมัติทุกอย่างที่ต้องขอสิทธิ์</td></tr>
|
|
33
|
-
</table>
|
|
34
|
-
|
|
35
|
-
<h2>กฎสิทธิ์</h2>
|
|
36
|
-
<p>กฎอนุญาต/ปฏิเสธแบบละเอียดควบคุมเครื่องมือและอาร์กิวเมนต์เฉพาะ:</p>
|
|
37
|
-
<pre><code>/permissions # เปิดตัวจัดการกฎสิทธิ์แบบโต้ตอบ</code></pre>
|
|
38
|
-
<p>กฎสามารถกำหนดเป้าหมายเครื่องมือเฉพาะด้วยการจับคู่รูปแบบ:</p>
|
|
39
|
-
<ul>
|
|
40
|
-
<li><code>Bash(git *)</code> — อนุญาต/ปฏิเสธคำสั่ง git โดยเฉพาะ</li>
|
|
41
|
-
<li><code>Edit</code> — อนุญาต/ปฏิเสธการแก้ไขไฟล์ทั้งหมด</li>
|
|
42
|
-
<li><code>Bash(rm *)</code> — เตือน/บล็อกคำสั่ง shell ที่เป็นอันตราย</li>
|
|
43
|
-
</ul>
|
|
44
|
-
|
|
45
|
-
<h2>แนวทางปฏิบัติด้านความปลอดภัย</h2>
|
|
46
|
-
<ul>
|
|
47
|
-
<li><strong>โหมดค่าเริ่มต้น</strong> สำหรับการพัฒนาประจำวัน</li>
|
|
48
|
-
<li><strong>โหมดวางแผน</strong> สำหรับโครงสร้างพื้นฐานการผลิตหรือโค้ดที่ไม่คุ้นเคย</li>
|
|
49
|
-
<li><strong>โหมดข้าม</strong> เฉพาะใน worktrees ที่ใช้แล้วทิ้งหรือ Docker sandboxes</li>
|
|
50
|
-
<li>ใช้กฎอนุญาต/ปฏิเสธเพื่ออนุญาตรูปแบบที่ปลอดภัยขณะบล็อกรูปแบบอันตราย</li>
|
|
51
|
-
</ul>
|
|
52
|
-
|
|
53
|
-
<footer class="footer">
|
|
54
|
-
<span>Clew Code 0.2.14 — โอเพนซอร์ส</span>
|
|
55
|
-
<div class="footer-links">
|
|
56
|
-
<a href="https://github.com/ClewCode/ClewCode">GitHub</a>
|
|
57
|
-
<a href="https://github.com/ClewCode/ClewCode/issues">ปัญหา</a>
|
|
58
|
-
</div>
|
|
59
|
-
</footer>
|
|
60
|
-
</main>
|
|
61
|
-
<nav class="toc-sidebar"></nav>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
<script src="js/main.js"></script>
|
|
65
|
-
</body>
|
|
66
|
-
</html>
|
|
67
|
-
|