@kevin5251984/guild 0.2.12

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 (70) hide show
  1. package/LICENSE +21 -0
  2. package/bin/guildd.mjs +20 -0
  3. package/cordis.yml +24 -0
  4. package/package.json +52 -0
  5. package/src/agent-file.ts +125 -0
  6. package/src/browser.ts +668 -0
  7. package/src/catalog/default-bots.ts +263 -0
  8. package/src/catalog/skills.ts +128 -0
  9. package/src/catalog/subagents.ts +70 -0
  10. package/src/chat-parts.ts +71 -0
  11. package/src/cli-args.ts +75 -0
  12. package/src/cli.ts +60 -0
  13. package/src/compact.ts +355 -0
  14. package/src/cordis.d.ts +40 -0
  15. package/src/db.ts +653 -0
  16. package/src/generate.ts +673 -0
  17. package/src/handlers.ts +1623 -0
  18. package/src/harness.ts +326 -0
  19. package/src/host-agents.ts +137 -0
  20. package/src/host-browse.ts +199 -0
  21. package/src/host-skills.ts +150 -0
  22. package/src/image-gen.ts +270 -0
  23. package/src/index.ts +12 -0
  24. package/src/llm.ts +993 -0
  25. package/src/mcp.ts +563 -0
  26. package/src/memory.ts +159 -0
  27. package/src/mention.ts +176 -0
  28. package/src/oauth.ts +1474 -0
  29. package/src/plugins/api.ts +8 -0
  30. package/src/plugins/chat.ts +31 -0
  31. package/src/plugins/harness.ts +77 -0
  32. package/src/plugins/llm.ts +50 -0
  33. package/src/plugins/mcp.ts +58 -0
  34. package/src/plugins/memory.ts +42 -0
  35. package/src/plugins/oauth.ts +47 -0
  36. package/src/plugins/server.ts +126 -0
  37. package/src/plugins/store.ts +29 -0
  38. package/src/plugins/tools.ts +79 -0
  39. package/src/public/buddy.js +432 -0
  40. package/src/public/chat.css +3045 -0
  41. package/src/public/chat.html +5834 -0
  42. package/src/public/favicon-16.png +0 -0
  43. package/src/public/favicon-16.svg +10 -0
  44. package/src/public/favicon-32.png +0 -0
  45. package/src/public/favicon.ico +0 -0
  46. package/src/public/favicon.svg +13 -0
  47. package/src/public/i18n.js +663 -0
  48. package/src/public/index.html +143 -0
  49. package/src/public/library.html +678 -0
  50. package/src/public/mcp-add.html +126 -0
  51. package/src/public/md.js +332 -0
  52. package/src/public/rpg/inn-street.jpg +0 -0
  53. package/src/public/settings.html +795 -0
  54. package/src/public/skills-add.html +212 -0
  55. package/src/public/studio.html +1181 -0
  56. package/src/public/style.css +1678 -0
  57. package/src/public/subagents-add.html +152 -0
  58. package/src/router.ts +978 -0
  59. package/src/send-budget.ts +52 -0
  60. package/src/server.ts +1 -0
  61. package/src/skill-import.ts +250 -0
  62. package/src/slash.ts +15 -0
  63. package/src/start.ts +103 -0
  64. package/src/store.ts +1208 -0
  65. package/src/subagent.ts +355 -0
  66. package/src/tools.ts +818 -0
  67. package/src/trajectory.ts +339 -0
  68. package/src/usage.ts +111 -0
  69. package/vendor/protocol/package.json +19 -0
  70. package/vendor/protocol/src/index.ts +159 -0
@@ -0,0 +1,663 @@
1
+ /** Guild UI strings. Default follows the browser; packs are zh-Hant and en. */
2
+ var I18N_ROWS = [
3
+ ["title.chat", "Guild — 大廳", "Guild — Hall"],
4
+ ["title.library", "Guild — 技能庫", "Guild — Skills"],
5
+ ["title.subagents", "Guild — 子代理", "Guild — Subagents"],
6
+ ["title.subagentsAdd", "Guild — 新增子代理", "Guild — Add subagent"],
7
+ ["title.mcp", "Guild — MCP", "Guild — MCP"],
8
+ ["title.mcpAdd", "Guild — 連接 MCP", "Guild — Add MCP"],
9
+ ["title.settings", "Guild — 模型", "Guild — Models"],
10
+ ["title.studio", "Guild — 編制", "Guild — Roster"],
11
+ ["title.skillsAdd", "Guild — 追加技能", "Guild — Add skill"],
12
+ ["nav.chat", "大廳", "Hall"],
13
+ ["nav.studio", "編制", "Roster"],
14
+ ["nav.library", "工坊", "Workshop"],
15
+ ["nav.subagents", "子代理", "Subagents"],
16
+ ["nav.mcp", "MCP", "MCP"],
17
+ ["library.sub.skills", "技能", "Skills"],
18
+ ["nav.settings", "模型", "Models"],
19
+ ["settings.sub.main", "主模型", "Default"],
20
+ ["settings.sub.subs", "訂閱", "Subscriptions"],
21
+ ["settings.sub.keys", "API Key", "API Key"],
22
+ ["search", "搜尋", "Search"],
23
+ ["search.skills", "搜尋技能", "Search skills"],
24
+ ["search.subagents", "搜尋子代理", "Search subagents"],
25
+ ["search.mcp", "搜尋 MCP", "Search MCP"],
26
+ ["search.models", "搜尋全部模型", "Search all models"],
27
+ ["search.traj", "搜尋 system / tool / spawn / 子代理 / 結果", "Search system / tool / spawn / subagent / result"],
28
+ ["channels", "委託", "Channels"],
29
+ ["dms", "密談", "Whispers"],
30
+ ["newChannel", "新委託", "New channel"],
31
+ ["newChannelName", "委託名稱", "Channel name"],
32
+ ["create", "建立", "Create"],
33
+ ["delete", "刪除", "Delete"],
34
+ ["deleteFailed", "刪除失敗", "Couldn't delete"],
35
+ ["msg.deleteConfirm", "刪除這則訊息?", "Delete this message?"],
36
+ ["channel.delete", "刪除委託", "Delete channel"],
37
+ ["channel.deleteConfirm", "刪除 #{name}?紀錄和委託書會一併刪掉。", "Delete #{name}? The log and Channel.md go with it."],
38
+ ["channel.keepGeneral", "#general 不能刪。", "Can't delete #general."],
39
+ ["channel.nameRequired", "委託要有名稱", "Channel needs a name"],
40
+ ["bot.delete", "請這名冒險者離席", "Drop this adventurer"],
41
+ ["bot.deleteConfirm", "讓 @{handle} 離席?密談與記憶會一併刪掉。", "Drop @{handle}? Their whispers and memory go with them."],
42
+ ["members", "編制", "Roster"],
43
+ ["members.in", "在這個據點", "In this hall"],
44
+ ["members.out", "不在這個據點", "Not in this hall"],
45
+ ["members.empty", "還沒有冒險者。", "No adventurers yet."],
46
+ ["members.allIn", "編制裡的冒險者都在這個據點了。", "Everyone on the roster is already in this hall."],
47
+ ["members.kick", "移出", "Remove"],
48
+ ["members.add", "加入", "Add"],
49
+ ["members.addDisabled", "滿席", "Full"],
50
+ ["members.cap", "{used}/{max}", "{used}/{max}"],
51
+ ["members.full", "這個據點最多 {max} 席。先移出一位,或改 @ 現有編制。", "This hall is full (max {max} seats). Remove someone, or @ a bot already here."],
52
+ ["invite.title", "拉冒險者進據點", "Add adventurers"],
53
+ ["invite.body", "先重用編制裡的人。一個據點最多 6 席,用 @handle 叫他們。", "Reuse the roster first. A hall holds 6 seats; @handle them here."],
54
+ ["invite.save", "加入", "Add"],
55
+ ["assign.title", "要誰做?", "Who should do this?"],
56
+ ["assign.hint", "這則提到好幾個人。選一個去跑。", "Several people are named here. Pick one to run."],
57
+ ["cancel", "取消", "Cancel"],
58
+ ["save", "儲存", "Save"],
59
+ ["saveFailed", "儲存失敗", "Couldn't save"],
60
+ ["close", "關閉", "Close"],
61
+ ["copy", "複製", "Copy"],
62
+ ["copied", "已複製", "Copied"],
63
+ ["edit", "編輯", "Edit"],
64
+ ["reply", "回覆", "Reply"],
65
+ ["retry", "重問", "Retry"],
66
+ ["stats", "統計", "Stats"],
67
+ ["stats.title", "回應統計", "Response statistics"],
68
+ ["stats.tokens", "Token", "Tokens"],
69
+ ["stats.time", "時間", "Time"],
70
+ ["stats.model", "模型", "Model"],
71
+ ["stats.rounds", "模型回合", "Agent rounds"],
72
+ ["stats.cost", "費用", "Cost"],
73
+ ["stats.estimated", "估算", "Estimated"],
74
+ ["stats.inOut", "輸入 {in} · 快取命中 {cache} · 輸出 {out}", "in {in} · cache {cache} · out {out}"],
75
+ ["askAgain", "重新詢問", "Ask again"],
76
+ ["send", "送出", "Send"],
77
+ ["jumpBottom", "滾到最新", "Jump to latest"],
78
+ ["promptRail", "你發過的位置", "Your prompts"],
79
+ ["promptJump", "你的訊息", "Your message"],
80
+ ["stop", "停止", "Stop"],
81
+ ["steer.hint", "Enter 排隊 · {mod}↩ 插入這輪", "Enter to queue · {mod}↩ to steer this turn"],
82
+ ["live.stop", "停止", "Stop"],
83
+ ["live.steer", "插入這輪", "Insert into turn"],
84
+ ["steer.queue", "排隊", "Queue"],
85
+ ["steer.insert", "插入引導", "Steer"],
86
+ ["steer.remove", "取消排隊", "Remove from queue"],
87
+ ["steer.tag", "已插入這輪", "Inserted into this turn"],
88
+ ["steer.tagTo", "已插入 {who} 這輪", "Inserted into {who}'s turn"],
89
+ ["steer.inserted", "已插入", "Inserted for"],
90
+ ["steer.waiting", "排隊中,這輪結束後送出", "Queued. Sends when this turn finishes."],
91
+ ["steer.waitingTo", "排隊給 {who},這輪結束後送出", "Queued for {who}. Sends when this turn finishes."],
92
+ ["steer.done", "已插入這輪,做完這步就會接著看", "Inserted. It will pick this up after the current step."],
93
+ ["steer.live", "引導", "Steer"],
94
+ ["handoff", "交棒", "Handoff"],
95
+ ["busy", "忙碌中", "Busy"],
96
+ ["unread", "未讀", "Unread"],
97
+ ["noMessages", "還沒有紀錄。寫一句話開始。據點裡記得 @handle。", "No log yet. Say something. In a hall, @handle an adventurer."],
98
+ ["setup.kicker", "第一步", "Step 1"],
99
+ ["setup.needModel", "還沒接模型。Guild 不能想、也不能跑工具。", "No model yet. Guild cannot think or run tools."],
100
+ ["setup.needModelBody", "先連接訂閱或填 API key,套用主模型,再回來點名。", "Connect a subscription or paste an API key, apply a default, then come back to @mention someone."],
101
+ ["setup.subs", "連接訂閱", "Connect a subscription"],
102
+ ["setup.keys", "填 API key", "Add an API key"],
103
+ ["dm", "密談", "Whisper"],
104
+ ["justNow", "剛剛", "Just now"],
105
+ ["minutesAgo", "{n} 分鐘前", "{n} min ago"],
106
+ ["today", "今天", "Today"],
107
+ ["yesterday", "昨天", "Yesterday"],
108
+ ["noActivity", "尚無紀錄", "No log"],
109
+ ["local", "本地", "Local"],
110
+ ["you", "你", "You"],
111
+ ["emptyParen", "(空)", "(empty)"],
112
+ ["reason.min", "最低", "Min"],
113
+ ["reason.low", "低", "Low"],
114
+ ["reason.mid", "中", "Mid"],
115
+ ["reason.high", "高", "High"],
116
+ ["speed.normal", "標準", "Standard"],
117
+ ["speed.fast", "快速", "Fast"],
118
+ ["model", "模型", "Model"],
119
+ ["reasoning", "推理強度", "Reasoning"],
120
+ ["speed", "速度", "Speed"],
121
+ ["advanced", "進階", "Advanced"],
122
+ ["model.settings", "狀態欄", "Status"],
123
+ ["switchModel", "切換模型", "Switch model"],
124
+ ["modelSwitchFailed", "切換模型失敗", "Couldn't switch model"],
125
+ ["recent", "最近使用", "Recently used"],
126
+ ["allModels", "全部模型", "All models"],
127
+ ["searchResults", "搜尋結果", "Results"],
128
+ ["noModels", "沒有模型。到進階連接訂閱或填 API key。", "No models. Connect a subscription or add an API key in Advanced."],
129
+ ["askAnything", "Ask anything", "Ask anything"],
130
+ ["askName", "Ask {name}", "Ask {name}"],
131
+ ["add", "加入", "Add"],
132
+ ["attach.upload", "上傳檔案", "Upload file"],
133
+ ["attach.drop", "放到這裡", "Drop files here"],
134
+ ["attach.files", "檔案", "Files"],
135
+ ["attach.dirs", "資料夾", "Folders"],
136
+ ["attach.skills", "技能", "Skills"],
137
+ ["attach.agents", "子代理", "Subagents"],
138
+ ["attach.conv", "對話", "Chats"],
139
+ ["attach.git", "Git", "Git"],
140
+ ["attach.rules", "規則", "Rules"],
141
+ ["attach.term", "終端", "Terminal"],
142
+ ["attach.tree", "工作區", "Workspace"],
143
+ ["attach.slash", "指令", "Commands"],
144
+ ["insert", "插入 {name}", "Insert {name}"],
145
+ ["remove", "移除", "Remove"],
146
+ ["cancelReply", "取消回覆", "Cancel reply"],
147
+ ["replying", "回覆…", "Replying…"],
148
+ ["trace", "軌跡", "Trajectory"],
149
+ ["trace.steps", "步驟", "Steps"],
150
+ ["trace.long", "長輸出", "Long output"],
151
+ ["trace.pick", "選一筆事件。", "Select an event."],
152
+ ["trace.empty", "沒有事件。送一則訊息後會開始記錄。", "No events yet. Send a message to start the log."],
153
+ ["trace.log", "只追加紀錄", "append-only log"],
154
+ ["trace.derived", "由訊息還原", "rebuilt from messages"],
155
+ ["trace.live", "進行中", "in progress"],
156
+ ["trace.loading", "讀取中…", "Loading…"],
157
+ ["trace.filter.all", "全部", "All"],
158
+ ["html.preview", "預覽", "Preview"],
159
+ ["html.code", "原始碼", "Code"],
160
+ ["html.expand", "放大預覽", "Expand preview"],
161
+ ["html.zoom", "HTML 預覽", "HTML preview"],
162
+ ["fence.toInput", "加入輸入框", "Insert into composer"],
163
+ ["channel.md", "委託書", "Channel.md"],
164
+ ["channel.mdHelp", "這個據點的委託書。用 @handle 叫冒險者時會讀到。密談沒有委託書。", "Brief for this hall. Adventurers see it when you @ them. Whispers have no Channel.md."],
165
+ ["memory.bot", "MEMORY.md", "MEMORY.md"],
166
+ ["memory.botHelp", "這名冒險者學會的站立筆記。有用的回合後會自動更新。", "Standing notes this adventurer has learned. Auto-updated after useful turns."],
167
+ ["memory.channel", "據點 MEMORY.md", "Hall MEMORY.md"],
168
+ ["memory.channelHelp", "這個據點共享的站立筆記。有用的回合後會自動更新。人寫的委託書優先。", "Shared notes for this hall. Auto-updated. The written Channel.md wins if they conflict."],
169
+ ["bot.message", "密談", "Whisper"],
170
+ ["bot.settings", "狀態欄", "Status"],
171
+ ["notInChannel", "不在這個據點", "Not in this hall"],
172
+ ["deepDiving", "Deep diving...", "Deep diving..."],
173
+ ["think", "Think", "Think"],
174
+ ["skill", "Skill", "Skill"],
175
+ ["bash", "Bash", "Bash"],
176
+ ["read", "Read", "Read"],
177
+ ["write", "Write", "Write"],
178
+ ["list", "List", "List"],
179
+ ["imageGen", "生圖", "Image"],
180
+ ["spawn", "子代理", "Subagent"],
181
+ ["attach.empty", "沒有可加入的項目。", "Nothing to add."],
182
+ ["attach.parent", "↑ 上一層", "↑ Parent folder"],
183
+ ["attach.addTree", "加入這個工作區地圖", "Attach this workspace map"],
184
+ ["attach.addDir", "加入這個資料夾", "Attach this folder"],
185
+ ["attach.truncated", "(已截斷)", " (truncated)"],
186
+ ["attach.run", "請用 run 在本機執行:`{cmd}`", "Run this on the host: `{cmd}`"],
187
+ ["attach.listDir", "請用 list 看這個資料夾:`{path}`", "List this folder: `{path}`"],
188
+ ["attach.readFile", "請用 read 看這個檔案:`{path}`({err})", "Read this file: `{path}` ({err})"],
189
+ ["attach.fileBody", "檔案 `{path}`{trunc}:", "File `{path}`{trunc}:"],
190
+ ["attach.treeBody", "工作區地圖:", "Workspace map:"],
191
+ ["attach.gitBody", "Git 狀態:", "Git status:"],
192
+ ["attach.convBody", "對話摘錄 {title}:", "Chat excerpt {title}:"],
193
+ ["attach.skillBody", "請使用 skill `{name}`。", "Use skill `{name}`."],
194
+ ["attach.agentBody", "請 spawn 子代理 `{name}`。", "Spawn subagent `{name}`."],
195
+ ["attach.preview", "預覽 {name}", "Preview {name}"],
196
+ ["attach.imageBody", "使用者附上圖片 `{name}`({type}, {size} bytes)。以 {token} 引用。", "User attached image `{name}` ({type}, {size} bytes). Refer to it as {token}."],
197
+ ["attach.uploadNoPath", "使用者上傳了檔案 `{name}`({type}, {size} bytes)。瀏覽器沒有本機路徑,請改用「檔案」從磁碟選,或請我用 list/read 找。", "User uploaded `{name}` ({type}, {size} bytes). The browser has no host path — pick it from Files, or list/read for it."],
198
+ ["attach.tooBig", "檔案 `{name}` 太大,沒有嵌進對話。請用「檔案」選本機路徑讓我 read。", "`{name}` is too large to embed. Pick it from Files so I can read the path."],
199
+ ["attach.uploadText", "上傳檔案 `{name}`:", "Uploaded `{name}`:"],
200
+ ["attach.noChannelMd", "這個據點還沒有委託書。請先在據點 icon 寫一份。", "This hall has no Channel.md yet. Write one from the hall icon."],
201
+ ["attach.botRulesTitle", "@{handle} 規則", "@{handle} rules"],
202
+ ["attach.noPersona", "這名冒險者還沒有人設。", "This adventurer has no persona yet."],
203
+ ["slash.editMd", "編輯委託書", "Edit Channel.md"],
204
+ ["slash.editMdHint", "委託說明", "Channel brief"],
205
+ ["slash.rules", "附上規則", "Attach rules"],
206
+ ["slash.rulesHint", "委託書 / 人設", "Channel.md / persona"],
207
+ ["slash.git", "附上 Git", "Attach Git"],
208
+ ["slash.here", "叫所有人", "Ping everyone"],
209
+ ["slash.hereHint", "通知這個據點上的所有冒險者。通常是錯的:出活仍點名一人。", "Notify every adventurer in this hall. Usually wrong: call one @handle."],
210
+ ["slash.library", "開工坊", "Open workshop"],
211
+ ["slash.sec.skill", "技能", "Skills"],
212
+ ["slash.sec.agent", "子代理", "Subagents"],
213
+ ["slash.sec.cmd", "指令", "Commands"],
214
+ ["slash.loading", "讀取技能與子代理…", "Loading skills and subagents…"],
215
+ ["slash.empty", "沒有符合的技能或子代理。", "No matching skills or subagents."],
216
+ ["mention.channel", "@所有人", "@everyone"],
217
+ ["mention.channelHint", "通知這個據點上的所有冒險者。通常是錯的:出活仍點名一人。", "Notify every adventurer in this hall. Usually wrong: call one @handle."],
218
+ ["mention.here", "@這裡", "@here"],
219
+ ["mention.hereHint", "通知這個據點上的每個冒險者。通常是錯的:出活仍點名一人。", "Notify every adventurer here. Usually wrong: call one @handle."],
220
+ ["library.eyebrow", "共用工具箱", "Shared toolbox"],
221
+ ["library.title", "技能庫", "Skills"],
222
+ ["library.lede", "公會自己的技能,加上本機 Claude、Codex、Pi、Grok、Cursor 留下的 SKILL.md。安裝走 <a href=\"/skills/add\">追加技能</a>;編制裡可以直接勾本機 CLI 技能。", "Guild skills plus SKILL.md left on this machine by Claude, Codex, Pi, Grok, and Cursor. Install via <a href=\"/skills/add\">Add skill</a>; staff them from the roster."],
223
+ ["library.install", "安裝新技能", "Install skill"],
224
+ ["library.add", "追加技能", "Add skill"],
225
+ ["library.all", "全部", "All"],
226
+ ["library.host", "本機技能,尚未裝進公會", "On disk, not staffed in the guild"],
227
+ ["library.unused", "還沒有冒險者勾選", "No adventurer selected this yet"],
228
+ ["library.catalog", "系統預裝", "Bundled"],
229
+ ["library.user", "自行安裝", "Installed"],
230
+ ["library.found", "找到 {n} 項 · 共 {total} 項", "{n} matches · {total} total"],
231
+ ["library.count", "{n} 項(含本機工具)· 點卡片可看 SKILL.md", "{n} skills (including local tools) · click a card for SKILL.md"],
232
+ ["library.emptyHtml", "沒有符合的技能。到 <a href=\"/skills/add\">追加技能</a> 安裝。", "No matching skills. Install one from <a href=\"/skills/add\">Add skill</a>."],
233
+ ["subagents.title", "子代理庫", "Subagents"],
234
+ ["subagents.lede", "Guild 內建 explorer / worker / reviewer,加上本機 Codex、Grok、Claude 留下的 agent 檔。對話裡用 spawn 叫它們;自己建的走 <a href=\"/subagents/add\">新增子代理</a>。", "Bundled explorer / worker / reviewer, plus Codex, Grok, and Claude agent files on this machine. Chat calls them with spawn; create your own from <a href=\"/subagents/add\">Add subagent</a>."],
235
+ ["subagents.install", "新增子代理", "Add subagent"],
236
+ ["subagents.host", "本機 CLI 定義,spawn 可直接用", "On disk; spawn can use it as-is"],
237
+ ["subagents.spawnHint", "對話裡 spawn 這個名字", "Spawn this name from chat"],
238
+ ["subagents.count", "{n} 個子代理 · 點卡片看 TOML / 指令", "{n} subagents · click a card for TOML / instructions"],
239
+ ["subagents.emptyHtml", "沒有符合的子代理。到 <a href=\"/subagents/add\">新增子代理</a>,或把 TOML 放到 ~/.codex/agents/。", "No matching subagents. Create one from <a href=\"/subagents/add\">Add subagent</a>, or drop TOML in ~/.codex/agents/."],
240
+ ["subagentsAdd.title", "新增子代理", "Add subagent"],
241
+ ["subagentsAdd.lede", "寫成 Codex 相容的 TOML(name / description / developer_instructions)。存進 Guild 之後,對話裡 spawn 那個名字即可。也可把檔案放到 ~/.codex/agents/ 給 Codex 用。", "Write Codex-compatible TOML (name / description / developer_instructions). After it is in Guild, spawn that name from chat. You can also copy the file to ~/.codex/agents/ for Codex."],
242
+ ["subagentsAdd.tabPaste", "貼上 TOML", "Paste TOML"],
243
+ ["subagentsAdd.aiTitle", "描述角色,請 AI 生成 TOML", "Describe the role, then generate TOML"],
244
+ ["subagentsAdd.what", "這個子代理要做什麼?", "What should this subagent do?"],
245
+ ["subagentsAdd.whatPh", "唯讀搜尋 auth 流程,回絕對路徑", "Read-only search for the auth flow; return absolute paths"],
246
+ ["subagentsAdd.gen", "用 AI 生成 SUBAGENT.toml", "Generate SUBAGENT.toml"],
247
+ ["subagentsAdd.pasteTitle", "貼上現成的 Codex / Grok agent", "Paste a Codex / Grok agent"],
248
+ ["subagentsAdd.pasteHint", "TOML(Codex ~/.codex/agents)或 Markdown frontmatter(Grok / Claude agents)。", "TOML from ~/.codex/agents, or Markdown frontmatter from Grok / Claude agents."],
249
+ ["subagentsAdd.save", "加入子代理庫", "Add to library"],
250
+ ["subagentsAdd.saved", "已加入 {name}", "Added {name}"],
251
+ ["mcp.title", "MCP", "MCP"],
252
+ ["mcp.lede", "連接器,不是技能。Skill 是說明書;MCP 是工具伺服器。本機 Codex / Claude / Cursor 的 MCP 會直接進對話,不必匯入。", "Connectors, not skills. Skills are instructions; MCP is a tool server. Codex / Claude / Cursor MCP configs on this machine are live in chat — no import step."],
253
+ ["mcp.install", "連接伺服器", "Add server"],
254
+ ["mcp.count", "{n} 個 MCP · 點卡片看啟動指令", "{n} MCP servers · click a card for the launch command"],
255
+ ["mcp.emptyHtml", "還沒有 MCP。到 <a href=\"/mcp/add\">連接伺服器</a>,或在本機 Codex / Claude / Cursor 配好。", "No MCP yet. Add one from <a href=\"/mcp/add\">Add server</a>, or configure Codex / Claude / Cursor on this machine."],
256
+ ["mcp.host", "本機 CLI,對話可直接用", "On disk; available in chat as-is"],
257
+ ["mcp.guildHint", "已寫進公會。這個據點裡的冒險者都能用這些 tools。", "Saved in the guild. Adventurers in this hall can call these tools."],
258
+ ["mcp.import", "匯入 Guild", "Import to Guild"],
259
+ ["mcp.delete", "移除", "Remove"],
260
+ ["mcpAdd.title", "連接 MCP", "Add MCP"],
261
+ ["mcpAdd.lede", "stdio 伺服器(command + args),跟 Codex config.toml / Claude MCP JSON 同一套。這不是技能,不要寫進技能庫。", "stdio servers (command + args), same shape as Codex config.toml / Claude MCP JSON. This is not a skill. Do not put it in the skills library."],
262
+ ["mcpAdd.name", "名稱", "Name"],
263
+ ["mcpAdd.command", "命令", "Command"],
264
+ ["mcpAdd.args", "參數(空白分隔)", "Args (space-separated)"],
265
+ ["mcpAdd.env", "環境變數 KEY=value,一行一個", "Env KEY=value, one per line"],
266
+ ["mcpAdd.save", "連接", "Connect"],
267
+ ["mcpAdd.saved", "已連接 {name}", "Connected {name}"],
268
+ ["mcpAdd.imported", "已匯入 {name}", "Imported {name}"],
269
+ ["mcpAdd.needName", "名稱和命令都要有", "Name and command are both required"],
270
+ ["mcpAdd.hostTitle", "本機已發現", "Already on this machine"],
271
+ ["mcpAdd.noHost", "這台機器上還沒掃到 Codex / Claude / Cursor 的 MCP。", "No Codex / Claude / Cursor MCP configs found on this machine."],
272
+ ["library.local", "本機", "Host"],
273
+ ["settings.eyebrow", "Hermes-style", "Hermes-style"],
274
+ ["settings.title", "模型", "Models"],
275
+ ["settings.lede", "第一次:先連訂閱或填 API key,再套用主模型。沒有模型就不能用。訂閱走 OAuth;API key 寫入 ~/.guild/models.json。", "First time: connect a subscription or paste an API key, then apply a default. Guild does not run without a model. Subscriptions use OAuth. API keys go in ~/.guild/models.json."],
276
+ ["settings.accounts", "連接帳號", "Accounts"],
277
+ ["settings.accountsHint", "用訂閱登入,不必複製金鑰。瀏覽器完成授權後會自動刷新 token。", "Subscription login, no key paste. Tokens refresh after the browser handshake."],
278
+ ["settings.connect", "連接", "Connect"],
279
+ ["settings.logout", "登出", "Log out"],
280
+ ["settings.connected", "已連接", "Connected"],
281
+ ["settings.pending", "登入中", "Signing in"],
282
+ ["settings.keys", "API 金鑰供應商", "API key providers"],
283
+ ["settings.keysHint", "點名稱切換供應商。要加新的,點「+ 新增」。金鑰可用 $ENV 或直接貼上。", "Tap a name to switch. Tap “+ Add” for a new provider. Keys can be $ENV or pasted."],
284
+ ["settings.noProviders", "還沒有供應商。點「+ 新增」選一家模板。", "No providers yet. Tap “+ Add” and pick a template."],
285
+ ["settings.addProvider", "新增供應商", "Add provider"],
286
+ ["settings.addChip", "+ 新增", "+ Add"],
287
+ ["settings.pickTemplate", "選一家模板,會帶好 endpoint 與環境變數名稱。", "Pick a template. Endpoint and env var name come filled in."],
288
+ ["settings.saveKey", "儲存", "Save"],
289
+ ["settings.saveKeyHint", "只寫入這家供應商的 ID、endpoint 與金鑰", "Writes this provider's id, endpoint, and key"],
290
+ ["settings.main", "主模型", "Default model"],
291
+ ["settings.mainHint", "新對話預設用這個。下面每一列會寫出實際在跑的模型。", "New chats use this. Each row below shows the model that actually runs."],
292
+ ["settings.provider", "供應商", "Provider"],
293
+ ["settings.apply", "套用", "Apply"],
294
+ ["settings.aux", "輔助模型", "Auxiliary models"],
295
+ ["settings.auxHint", "只有 Vision、Web extract、SubAgent 可以另選模型。其餘用途一律跟主模型。", "Only Vision, web extract, and SubAgent can use a different model. Everything else follows the default."],
296
+ ["settings.auxReset", "全部改回主模型", "Reset all to default"],
297
+ ["settings.useMain", "改回跟主模型", "Follow default"],
298
+ ["settings.change", "更改", "Change"],
299
+ ["settings.task", "用途", "Task"],
300
+ ["settings.using", "目前使用", "In use"],
301
+ ["settings.inherited", "跟主模型", "Follows default"],
302
+ ["settings.override", "自訂", "Override"],
303
+ ["settings.noDefault", "尚未設定主模型", "No default model"],
304
+ ["settings.currentMain", "目前主模型:{name}", "Default: {name}"],
305
+ ["settings.delete", "刪除", "Delete"],
306
+ ["settings.locale", "介面語言", "Language"],
307
+ ["settings.localeHint", "寫進這個瀏覽器。大廳、編制、工坊、模型共用。", "Saved in this browser. Shared by Hall, Roster, Workshop, and Models."],
308
+ ["settings.oauthCode", "在瀏覽器開啟授權頁,輸入代碼:", "Open the auth page and enter this code:"],
309
+ ["settings.oauthBrowser", "在瀏覽器完成授權。若 popup 被擋,用下面的連結。", "Finish in the browser. If the popup is blocked, use the link below."],
310
+ ["settings.openAuth", "開啟授權頁", "Open auth page"],
311
+ ["settings.pasteHint", "若瀏覽器在別台機器,貼上導向網址或 code", "If the browser is on another machine, paste the redirect URL or code"],
312
+ ["settings.finishLogin", "完成登入", "Finish login"],
313
+ ["settings.custom", "自訂 endpoint", "Custom endpoint"],
314
+ ["settings.notLoggedIn", "(未登入)", " (signed out)"],
315
+ ["settings.filled", "已填", "Set"],
316
+ ["settings.emptyKey", "未填", "Empty"],
317
+ ["settings.displayName", "顯示名稱", "Display name"],
318
+ ["settings.addModel", "+ 模型", "+ model"],
319
+ ["settings.thisProvider", "這個供應商", "this provider"],
320
+ ["settings.notReady", "這個供應商還沒登入或沒有 API key", "This provider is not signed in and has no API key"],
321
+ ["settings.applied", "已套用 {name}", "Applied {name}"],
322
+ ["settings.appliedDefault", "預設", "default"],
323
+ ["settings.auxChange", "更改輔助模型", "Change auxiliary model"],
324
+ ["settings.auxChangeName", "更改 {name}", "Change {name}"],
325
+ ["settings.connectFirst", "先連接這個供應商", "Connect this provider first"],
326
+ ["settings.waitingAuth", "授權後這個頁面會自動偵測", "This page watches for the handshake"],
327
+ ["settings.connectedId", "已連接 {id}", "Connected {id}"],
328
+ ["settings.savedKeyFlash", "已儲存 {name} 金鑰", "Saved {name} key"],
329
+ ["settings.autoMain", "跟主模型", "auto · use main model"],
330
+ ["settings.name", "名稱", "Name"],
331
+ ["studio.enter", "進酒館", "Enter the inn"],
332
+ ["studio.streetAlt", "Guild 酒館門口", "Guild inn door"],
333
+ ["studio.leave", "出門", "Leave"],
334
+ ["studio.inn", "酒館", "Inn"],
335
+ ["studio.idle", "待命", "idle"],
336
+ ["studio.diving", "潛水", "diving"],
337
+ ["studio.streetLine", "夜晚的酒館還開著。點那扇門進去。", "The inn is still open. Tap the door."],
338
+ ["studio.tonight", "今晚", "Tonight"],
339
+ ["studio.hire", "招募冒險者", "Recruit an adventurer"],
340
+ ["studio.hireLede", "寫好 Soul / Agent / Position,勾技能(含本機 Codex、Grok 等 CLI),請他入座。", "Write Soul / Agent / Position, staff skills (including local Codex, Grok, and other CLI skills), then seat them."],
341
+ ["studio.oneLiner", "一句話", "One-liner"],
342
+ ["studio.oneLinerPh", "這名冒險者在編制裡做什麼", "What this adventurer does on the roster"],
343
+ ["studio.soulHint", "性格、聲音、邊界。", "Voice, character, boundaries."],
344
+ ["studio.desc", "描述", "Prompt"],
345
+ ["studio.soulPh", "謹慎、少廢話的資深工程師", "A careful senior engineer who talks little"],
346
+ ["studio.genMd", "用 AI 生成 Markdown", "Generate markdown"],
347
+ ["studio.agentHint", "怎麼做事的 SOP。", "How they work."],
348
+ ["studio.agentPh", "先寫測試,再改最小程式", "Tests first, then the smallest change"],
349
+ ["studio.posHint", "職位職責與完成定義。", "Role and definition of done."],
350
+ ["studio.posPh", "這個專案的 Engineer", "Engineer on this project"],
351
+ ["studio.botSkills", "這名冒險者的技能(含本機 CLI)", "This adventurer's skills (including local CLI)"],
352
+ ["studio.botSkillsHint", "公會技能庫,加上本機 Claude、Codex、Pi、Grok、Cursor、DSH 的 SKILL.md。勾或取消會立刻存檔,拷進公會再配給這名冒險者。沒有的可到 <a href=\"/skills/add\">追加技能</a> 安裝,不影響其他人。", "The guild library plus SKILL.md on disk from Claude, Codex, Pi, Grok, Cursor, and DSH. Checks save immediately and copy a host skill into the guild for this adventurer. Missing ones go through <a href=\"/skills/add\">Add skill</a>."],
353
+ ["studio.searchSkills", "搜尋技能庫", "Search skills"],
354
+ ["studio.pickSkills", "用 AI 挑選", "Pick with AI"],
355
+ ["studio.picking", "挑選中…", "Picking…"],
356
+ ["studio.needMdForPick", "先寫 Soul / Agent / Position", "Write Soul / Agent / Position first"],
357
+ ["studio.pickNone", "沒有對上的技能", "No matching skills"],
358
+ ["studio.pickedDone", "已勾選 {n} 項", "Checked {n}"],
359
+ ["studio.nonePicked", "尚未勾選", "None selected"],
360
+ ["studio.more", "查看更多", "Show more"],
361
+ ["studio.seat", "請他入座", "Seat them"],
362
+ ["studio.editEyebrow", "Edit", "Edit"],
363
+ ["studio.editTitle", "改這名冒險者的設定", "Edit this adventurer"],
364
+ ["studio.editLede", "每個 Markdown 自己儲存。技能勾了或取消會立刻生效。", "Each markdown block saves on its own. Skill checks save immediately."],
365
+ ["studio.saveMd", "儲存 {file}", "Save {file}"],
366
+ ["studio.savedMd", "已儲存 {file}", "Saved {file}"],
367
+ ["studio.saveIdentity", "儲存名字", "Save name"],
368
+ ["studio.savedIdentity", "已儲存名字", "Name saved"],
369
+ ["studio.skillsSaved", "技能已儲存", "Skills saved"],
370
+ ["studio.needSkill", "至少要留一項技能", "Keep at least one skill"],
371
+ ["studio.editDocTitle", "Guild — 設定冒險者", "Guild — Edit adventurer"],
372
+ ["studio.picked", "這名冒險者勾了 {n} 項 · 公會 {guild} · 本機 CLI {host}", "This adventurer has {n} selected · {guild} guild · {host} local CLI"],
373
+ ["studio.pickedChip", "已勾選", "Selected"],
374
+ ["studio.hostFail", "本機 CLI 技能讀取失敗,先顯示 Guild 技能庫。", "Could not read local CLI skills; showing the Guild library only."],
375
+ ["studio.skillLoading", "讀取 SKILL.md…", "Loading SKILL.md…"],
376
+ ["studio.checkSkill", "勾選 {name}", "Select {name}"],
377
+ ["studio.emptyLib", "還沒列出技能。Guild 會掃本機 Claude / Codex / Grok 的 SKILL.md;沒有的話先到追加技能安裝。", "No skills listed. Guild scans Claude / Codex / Grok SKILL.md on this machine; otherwise install one first."],
378
+ ["studio.noMatch", "沒有符合的技能。", "No matching skills."],
379
+ ["studio.moreN", "查看其餘 {n} 項", "Show {n} more"],
380
+ ["studio.needPrompt", "先寫一句 {kind} 描述", "Write a {kind} prompt first"],
381
+ ["studio.generating", "生成中…", "Generating…"],
382
+ ["studio.generated", "{kind} Markdown 已生成(模型)", "{kind} markdown generated (model)"],
383
+ ["studio.generatedLocal", "{kind} Markdown 已生成(本地稿)", "{kind} markdown generated (local draft)"],
384
+ ["studio.generatedSaved", "已生成並儲存 {file}", "Generated and saved {file}"],
385
+ ["studio.generatedSavedLocal", "已生成並儲存 {file}(本地稿)", "Generated and saved {file} (local draft)"],
386
+ ["studio.savedHtml", "已儲存 @{handle} — 到 <a href=\"{href}\">大廳</a> 找他。", "Saved @{handle} — find them in the <a href=\"{href}\">hall</a>."],
387
+ ["studio.seatedHtml", "已入座 @{handle} — 到 <a href=\"{href}\">大廳</a> 找他。", "Seated @{handle} — find them in the <a href=\"{href}\">hall</a>."],
388
+ ["studio.editToast", "設定改好了。", "Saved."],
389
+ ["studio.hireToast", "新冒險者入席。", "New adventurer seated."],
390
+ ["studio.keeper", "掌櫃", "Keep"],
391
+ ["studio.keeperLine", "進來坐。點裡面的人可以密談或改設定。", "Come in. Tap someone to whisper or edit."],
392
+ ["studio.vacant", "空位", "Vacant"],
393
+ ["studio.vacantLine", "空座位。要招冒險者進來嗎?", "Empty seat. Recruit someone?"],
394
+ ["studio.hireChip", "招募", "Hire"],
395
+ ["studio.genLook", "生成形象", "Generate look"],
396
+ ["studio.genLookBusy", "畫臉中…", "Drawing…"],
397
+ ["studio.genLookDone", "新形象好了。", "New look ready."],
398
+ ["studio.genLookFail", "生圖失敗。到模型頁接 Grok 訂閱或填金鑰再試。", "Image failed. Connect a Grok subscription or add a key on the models page."],
399
+ ["studio.drink", "……今晚在這兒喝酒。", "…drinking here tonight."],
400
+ ["studio.notFound", "找不到這名冒險者", "Adventurer not found"],
401
+ ["studio.editing", "正在編輯 @{handle} · 勾選只屬於這名冒險者", "Editing @{handle} · skills are only for this adventurer"],
402
+ ["skillsAdd.eyebrow", "Skills", "Skills"],
403
+ ["skillsAdd.title", "追加技能", "Add skill"],
404
+ ["skillsAdd.lede", "這裡才是安裝入口。裝進技能庫之後,再到編制點每名冒險者,各自勾選要用的技能。", "This is the install door. After it is in the library, staff each adventurer from the roster."],
405
+ ["skillsAdd.tabAi", "AI 生成", "AI generate"],
406
+ ["skillsAdd.tabUrl", "網址下載", "From URL"],
407
+ ["skillsAdd.tabGh", "GitHub repo", "GitHub repo"],
408
+ ["skillsAdd.aiTitle", "自行輸入,請 AI 生成", "Describe it, then generate"],
409
+ ["skillsAdd.what", "這項技能要做什麼?", "What should this skill do?"],
410
+ ["skillsAdd.whatPh", "審查 PR 的安全風險,並寫成可執行的修法", "Review a PR for security risk and write a fix"],
411
+ ["skillsAdd.gen", "用 AI 生成 SKILL.md", "Generate SKILL.md"],
412
+ ["skillsAdd.name", "名稱", "Name"],
413
+ ["skillsAdd.save", "加入技能庫", "Add to library"],
414
+ ["skillsAdd.urlTitle", "從網上下載", "Download from the web"],
415
+ ["skillsAdd.urlHint", "貼 SKILL.md 的直接連結(raw 檔或 GitHub blob)。", "Paste a direct SKILL.md link (raw file or GitHub blob)."],
416
+ ["skillsAdd.urlImport", "下載並加入", "Download and add"],
417
+ ["skillsAdd.ghTitle", "載入 GitHub repo", "Load a GitHub repo"],
418
+ ["skillsAdd.ghHint", "掃描 repo 內所有 SKILL.md。例:owner/repo 或完整 GitHub 網址。", "Scan every SKILL.md in the repo. Example: owner/repo or a GitHub URL."],
419
+ ["skillsAdd.ghImport", "掃描並加入", "Scan and add"],
420
+ ["skillsAdd.recent", "剛裝進技能庫的會出現在下面", "Newly installed skills show up below"],
421
+ ["skillsAdd.recentHint", "完整清單在 <a href=\"/library\">技能庫</a>。要讓冒險者帶上,到 <a href=\"/studio\">編制</a> 點那個人勾選。", "Full list is in <a href=\"/library\">Skills</a>. Staff an adventurer from the <a href=\"/studio\">roster</a>."],
422
+ ["skillsAdd.needDesc", "先寫技能描述", "Write a skill prompt first"],
423
+ ["skillsAdd.generated", "已生成(模型)", "Generated (model)"],
424
+ ["skillsAdd.generatedLocal", "已生成(本地稿),可再改", "Generated (local draft), editable"],
425
+ ["skillsAdd.needName", "名稱與 SKILL.md 都要有", "Name and SKILL.md are both required"],
426
+ ["skillsAdd.added", "已加入技能庫:{name}", "Added to library: {name}"],
427
+ ["skillsAdd.imported", "已加入 {n} 項:{names}", "Added {n}: {names}"],
428
+ ["skillsAdd.needUrl", "貼上 SKILL.md 網址", "Paste a SKILL.md URL"],
429
+ ["skillsAdd.empty", "還沒有技能。用上面三種方式安裝。", "No skills yet. Use one of the three install paths."],
430
+ ["skillsAdd.catalog", "系統", "Bundled"],
431
+ ["skillsAdd.needRepo", "填 owner/repo 或 GitHub 網址", "Fill owner/repo or a GitHub URL"],
432
+ ["tag.development", "開發", "Dev"],
433
+ ["tag.design", "設計", "Design"],
434
+ ["tag.code-review", "Code Review", "Code Review"],
435
+ ["tag.testing", "測試", "Test"],
436
+ ["tag.browser", "瀏覽器", "Browser"],
437
+ ["tag.research", "研究", "Research"],
438
+ ["tag.git", "Git", "Git"],
439
+ ["tag.security", "安全", "Security"],
440
+ ["tag.document", "文件", "Docs"],
441
+ ["tag.api", "API", "API"],
442
+ ["tag.product", "產品", "Product"],
443
+ ["tag.communication", "溝通", "Comms"],
444
+ ["tag.data-analysis", "數據", "Data"],
445
+ ["tag.qa", "QA", "QA"],
446
+ ["tag.claude", "Claude", "Claude"],
447
+ ["tag.codex", "Codex", "Codex"],
448
+ ["tag.pi", "Pi", "Pi"],
449
+ ["tag.grok", "Grok", "Grok"],
450
+ ["tag.cursor", "Cursor", "Cursor"],
451
+ ["tag.dsh", "DSH", "DSH"],
452
+ ["tag.guild", "Guild", "Guild"],
453
+ ["tag.explore", "探索", "Explore"],
454
+ ["tag.implement", "實作", "Implement"],
455
+ ["tag.review", "審查", "Review"],
456
+ ["tag.read-only", "唯讀", "Read-only"],
457
+ ["lang.zh", "中", "中"],
458
+ ["lang.en", "EN", "EN"],
459
+ ["nav.menu", "委託與密談", "Channels and whispers"],
460
+ ["sidebar.resize", "拖曳調整寬度", "Drag to resize"],
461
+ ];
462
+
463
+ var I18N = { "zh-Hant": {}, en: {} };
464
+ I18N_ROWS.forEach(function (row) {
465
+ I18N["zh-Hant"][row[0]] = row[1];
466
+ I18N.en[row[0]] = row[2];
467
+ });
468
+
469
+ var currentLocale = "";
470
+
471
+ function guildLocale() {
472
+ if (currentLocale && I18N[currentLocale]) return currentLocale;
473
+ try {
474
+ var saved = localStorage.getItem("guild-locale");
475
+ if (saved && I18N[saved]) {
476
+ currentLocale = saved;
477
+ return saved;
478
+ }
479
+ } catch (err) {
480
+ /* ignore */
481
+ }
482
+ var nav = String(
483
+ (typeof navigator !== "undefined" && (navigator.language || navigator.userLanguage)) ||
484
+ "",
485
+ ).toLowerCase();
486
+ currentLocale = nav.indexOf("zh") === 0 ? "zh-Hant" : "en";
487
+ return currentLocale;
488
+ }
489
+
490
+ function t(key, vars) {
491
+ var locale = guildLocale();
492
+ var dict = I18N[locale] || I18N["zh-Hant"];
493
+ var text = (dict && dict[key]) || (I18N["zh-Hant"] && I18N["zh-Hant"][key]) || key;
494
+ if (vars) {
495
+ Object.keys(vars).forEach(function (name) {
496
+ text = String(text).split("{" + name + "}").join(String(vars[name]));
497
+ });
498
+ }
499
+ return text;
500
+ }
501
+
502
+ function tagLabel(tag) {
503
+ var key = "tag." + tag;
504
+ var locale = guildLocale();
505
+ var dict = I18N[locale] || I18N["zh-Hant"];
506
+ if (dict && dict[key]) return dict[key];
507
+ if (I18N["zh-Hant"] && I18N["zh-Hant"][key]) return I18N["zh-Hant"][key];
508
+ return tag;
509
+ }
510
+
511
+ function applyI18n(root) {
512
+ var scope = root || (typeof document !== "undefined" ? document : null);
513
+ if (!scope || !scope.querySelectorAll) return;
514
+ var locale = guildLocale();
515
+ if (typeof document !== "undefined" && document.documentElement) {
516
+ document.documentElement.lang = locale === "en" ? "en" : "zh-Hant";
517
+ var page = document.body && document.body.getAttribute("data-i18n-page");
518
+ if (page) document.title = t("title." + page);
519
+ }
520
+ scope.querySelectorAll("[data-i18n]").forEach(function (el) {
521
+ el.textContent = t(el.getAttribute("data-i18n"));
522
+ });
523
+ scope.querySelectorAll("[data-i18n-html]").forEach(function (el) {
524
+ el.innerHTML = t(el.getAttribute("data-i18n-html"));
525
+ });
526
+ scope.querySelectorAll("[data-i18n-placeholder]").forEach(function (el) {
527
+ el.setAttribute("placeholder", t(el.getAttribute("data-i18n-placeholder")));
528
+ });
529
+ scope.querySelectorAll("[data-i18n-title]").forEach(function (el) {
530
+ el.setAttribute("title", t(el.getAttribute("data-i18n-title")));
531
+ });
532
+ scope.querySelectorAll("[data-i18n-aria]").forEach(function (el) {
533
+ el.setAttribute("aria-label", t(el.getAttribute("data-i18n-aria")));
534
+ });
535
+ scope.querySelectorAll("[data-i18n-drop]").forEach(function (el) {
536
+ el.setAttribute("data-drop-hint", t(el.getAttribute("data-i18n-drop")));
537
+ });
538
+ scope.querySelectorAll("[data-locale]").forEach(function (el) {
539
+ el.classList.toggle("on", el.getAttribute("data-locale") === locale);
540
+ });
541
+ }
542
+
543
+ function setGuildLocale(locale) {
544
+ if (!I18N[locale]) return;
545
+ currentLocale = locale;
546
+ try {
547
+ localStorage.setItem("guild-locale", locale);
548
+ } catch (err) {
549
+ /* ignore */
550
+ }
551
+ applyI18n();
552
+ if (typeof window !== "undefined" && typeof Event === "function") {
553
+ window.dispatchEvent(new Event("guild-locale"));
554
+ }
555
+ }
556
+
557
+ function bindLocaleSwitch(root) {
558
+ var scope = root || (typeof document !== "undefined" ? document : null);
559
+ if (!scope || !scope.addEventListener) return;
560
+ scope.addEventListener("click", function (event) {
561
+ var btn = event.target.closest("[data-locale]");
562
+ if (!btn) return;
563
+ event.preventDefault();
564
+ setGuildLocale(btn.getAttribute("data-locale"));
565
+ });
566
+ }
567
+
568
+ var SIDEBAR_MIN = 200;
569
+ var SIDEBAR_DEFAULT = 292;
570
+ var SIDEBAR_KEY = "guild-sidebar-w";
571
+
572
+ function sidebarMax() {
573
+ var vw = typeof window !== "undefined" ? window.innerWidth : 1200;
574
+ return Math.min(560, Math.max(SIDEBAR_MIN, Math.floor(vw * 0.55)));
575
+ }
576
+
577
+ function sidebarWidth() {
578
+ try {
579
+ var n = Number(localStorage.getItem(SIDEBAR_KEY));
580
+ if (n >= SIDEBAR_MIN && n <= 800) return Math.min(n, sidebarMax());
581
+ } catch (err) {
582
+ /* ignore */
583
+ }
584
+ return SIDEBAR_DEFAULT;
585
+ }
586
+
587
+ function applySidebarWidth(px) {
588
+ var max = sidebarMax();
589
+ var w = Math.round(Math.min(max, Math.max(SIDEBAR_MIN, Number(px) || SIDEBAR_DEFAULT)));
590
+ if (typeof document !== "undefined" && document.documentElement) {
591
+ document.documentElement.style.setProperty("--sidebar-w", w + "px");
592
+ }
593
+ return w;
594
+ }
595
+
596
+ function bindSidebarResize() {
597
+ if (typeof document === "undefined") return;
598
+ applySidebarWidth(sidebarWidth());
599
+ var handle = document.querySelector(".sidebar-resizer");
600
+ if (!handle) return;
601
+ var dragging = false;
602
+ function onMove(ev) {
603
+ if (!dragging) return;
604
+ applySidebarWidth(ev.clientX);
605
+ }
606
+ function onUp(ev) {
607
+ if (!dragging) return;
608
+ dragging = false;
609
+ if (document.body) document.body.classList.remove("resizing-sidebar");
610
+ try {
611
+ localStorage.setItem(SIDEBAR_KEY, String(applySidebarWidth(ev.clientX)));
612
+ } catch (err) {
613
+ /* ignore */
614
+ }
615
+ window.removeEventListener("pointermove", onMove);
616
+ window.removeEventListener("pointerup", onUp);
617
+ }
618
+ handle.addEventListener("pointerdown", function (ev) {
619
+ if (ev.button != null && ev.button !== 0) return;
620
+ ev.preventDefault();
621
+ dragging = true;
622
+ if (document.body) document.body.classList.add("resizing-sidebar");
623
+ window.addEventListener("pointermove", onMove);
624
+ window.addEventListener("pointerup", onUp);
625
+ });
626
+ handle.addEventListener("dblclick", function () {
627
+ applySidebarWidth(SIDEBAR_DEFAULT);
628
+ try {
629
+ localStorage.setItem(SIDEBAR_KEY, String(SIDEBAR_DEFAULT));
630
+ } catch (err) {
631
+ /* ignore */
632
+ }
633
+ });
634
+ }
635
+
636
+ if (typeof document !== "undefined") {
637
+ applySidebarWidth(sidebarWidth());
638
+ if (document.readyState === "loading") {
639
+ document.addEventListener("DOMContentLoaded", function () {
640
+ applyI18n();
641
+ bindLocaleSwitch(document);
642
+ bindSidebarResize();
643
+ });
644
+ } else {
645
+ applyI18n();
646
+ bindLocaleSwitch(document);
647
+ bindSidebarResize();
648
+ }
649
+ }
650
+
651
+ if (typeof module !== "undefined" && module.exports) {
652
+ module.exports = {
653
+ I18N,
654
+ I18N_ROWS,
655
+ t,
656
+ tagLabel,
657
+ guildLocale,
658
+ applyI18n,
659
+ setGuildLocale,
660
+ applySidebarWidth,
661
+ sidebarWidth,
662
+ };
663
+ }