opencode-resolve 0.1.12 → 0.1.16

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.
@@ -0,0 +1,867 @@
1
+ // Internationalized hook messages + dynamic agent brand.
2
+ //
3
+ // All session-time nudges and role-play narrations route through `t()` so they
4
+ // can be rendered in Korean or English. The brand prefix is the *current
5
+ // agent's name* (e.g. `[resolver]`, `[coder]`) — that gives the role-play feel
6
+ // the user wants. For plugin-level notices unrelated to an agent (auto-update,
7
+ // tool-definition hints loaded once), use `PLUGIN_BRAND` instead.
8
+ export const PLUGIN_BRAND = "opencode-resolve";
9
+ const LOCALE_FALLBACK = "en";
10
+ const KOREAN_LANG_RE = /^ko(?:[_-]|$)/i;
11
+ /** Resolve a Locale from explicit config (`"ko"|"en"|"auto"`) or env. */
12
+ export function resolveLocale(configured, envLang) {
13
+ if (configured === "ko" || configured === "en")
14
+ return configured;
15
+ if (envLang && KOREAN_LANG_RE.test(envLang))
16
+ return "ko";
17
+ return LOCALE_FALLBACK;
18
+ }
19
+ /** Bracketed brand for the currently-active agent. */
20
+ export function brand(agent) {
21
+ const name = agent && agent.length > 0 ? agent : PLUGIN_BRAND;
22
+ return `[${name}]`;
23
+ }
24
+ /** Friendly display name per agent (used in role-play narration). */
25
+ export function agentDisplayName(agent, locale) {
26
+ if (!agent)
27
+ return PLUGIN_BRAND;
28
+ const map = AGENT_DISPLAY[locale];
29
+ return map[agent] ?? agent;
30
+ }
31
+ const AGENT_DISPLAY = {
32
+ en: {
33
+ resolver: "resolver",
34
+ coder: "coder",
35
+ reviewer: "reviewer",
36
+ "deep-reviewer": "deep-reviewer",
37
+ explorer: "explorer",
38
+ planner: "planner",
39
+ architect: "architect",
40
+ researcher: "researcher",
41
+ debugger: "debugger",
42
+ codex: "codex",
43
+ glm: "glm",
44
+ gpt: "gpt",
45
+ "gpt-coder": "gpt-coder",
46
+ },
47
+ ko: {
48
+ resolver: "리졸버",
49
+ coder: "코더",
50
+ reviewer: "리뷰어",
51
+ "deep-reviewer": "딥리뷰어",
52
+ explorer: "익스플로러",
53
+ planner: "플래너",
54
+ architect: "아키텍트",
55
+ researcher: "리서처",
56
+ debugger: "디버거",
57
+ codex: "코덱스",
58
+ glm: "GLM",
59
+ gpt: "GPT",
60
+ "gpt-coder": "GPT 코더",
61
+ },
62
+ };
63
+ let variantCounter = 0;
64
+ function nextVariantSeed() {
65
+ variantCounter = (variantCounter + 1) >>> 0;
66
+ return variantCounter;
67
+ }
68
+ const MESSAGES = {
69
+ en: {
70
+ "reminder.verify": "Reminder: verify your changes (run resolve-verify — typecheck/lint/test) before reporting completion.",
71
+ "reminder.ralphLoopText": "🔄 Ralph Loop: heavy iteration detected. Check resolve-diagnostics (current LSP errors snapshot) and pivot the approach before the next attempt.",
72
+ "system.driveResolution": "Drive to verified resolution. Classify intent, dispatch focused subagents, verify after each, iterate on failure. Report completion only when verified.",
73
+ "system.projectKnowledge": ({ files }) => `Project knowledge: ${files}. Read when relevant before modifying code.`,
74
+ "system.contextDocs": ({ files }) => `Context docs: ${files}. MVI: load only task-relevant docs.`,
75
+ "system.verifyCommands": ({ commands }) => `Verify commands: ${commands}. Run after changes.`,
76
+ "system.typescriptMandatory": "TypeScript project — type safety is mandatory. No `as any` or `@ts-ignore`.",
77
+ "system.failuresHeader": "⚠️ Recurring failures detected:",
78
+ "system.failuresFooter": "Keep going — try a different approach for the same goal. The Ralph Loop should drive to completion.",
79
+ "system.strategyPivotHeader": ({ count }) => `🔀 STRATEGY PIVOT: ${count} total failures detected.`,
80
+ "system.strategyPivotBody": "The current approach is not working. Dispatch ARCHITECT to analyze the problem from scratch and propose a fundamentally different strategy.",
81
+ "system.strategyPivotTail": "Then apply the new strategy. Do NOT keep retrying the same approach.",
82
+ "system.ralphHeader": "🔄 Ralph Loop: heavy editing detected on same file(s):",
83
+ "system.ralphKeepGoing": "Keep driving — the Ralph Loop should keep iterating until verified resolution.",
84
+ "system.sessionStats": ({ edits, calls, elapsed }) => `📊 Session stats: ${edits} edits, ${calls} tool calls, ${elapsed}s elapsed.`,
85
+ "system.iterationWarning": "Significant iteration with failures. Consider a fundamentally different approach — but keep going.",
86
+ "compaction.contextHeader": ({ body }) => `Project context (preserve): ${body}`,
87
+ "tool.edit": "Read the file first. Make the smallest correct change. Verify after editing.",
88
+ "tool.write": "Only write new files when explicitly needed. Prefer editing existing files.",
89
+ "tool.bash": "Commands run in non-interactive mode. No interactive editors, pagers, or REPLs. Use -c flags for scripting.",
90
+ "tool.task": "Dispatch subagents with: TASK (atomic goal), OUTCOME (success criteria), MUST DO, MUST NOT DO, CONTEXT.",
91
+ "tool.glob": "Use specific patterns. Avoid '**/*' unless genuinely needed — prefer scoped searches.",
92
+ "tool.grep": "Use specific regex patterns. Combine with include filter for targeted search.",
93
+ "tool.read": "Read only what you need. Use offset/limit for large files. Check file-info tool for quick metadata.",
94
+ "tool.webfetch": "Only fetch URLs when you genuinely need external information. Prefer local docs and code first.",
95
+ "tool.todowrite": "Keep todos current. Mark completed immediately. One in_progress at a time.",
96
+ "dispatch.toSubagent": [
97
+ ({ from, to, goal }) => goal ? `🎯 ${from} → ${to}: ${goal}` : `🎯 ${from} → ${to}: dispatching subtask`,
98
+ ({ from, to, goal }) => goal ? `▶ ${from} hands off to ${to}: ${goal}` : `▶ ${from} hands off to ${to}`,
99
+ ({ from, to, goal }) => goal ? `📡 ${from} → ${to} | ${goal}` : `📡 ${from} → ${to} (subtask)`,
100
+ ({ from, to, goal }) => goal ? `🤝 ${from} delegates "${goal}" to ${to}` : `🤝 ${from} delegates to ${to}`,
101
+ ],
102
+ "dispatch.fromResolver": [
103
+ ({ to }) => `🎯 dispatching ${to} subagent`,
104
+ ({ to }) => `▶ spinning up ${to}`,
105
+ ({ to }) => `📡 ${to} on deck`,
106
+ ],
107
+ "dispatch.coder": [
108
+ ({ goal }) => goal ? `🔧 coder is on it: ${goal}` : "🔧 coder picks up the implementation work",
109
+ ({ goal }) => goal ? `🔧 handing the patch over to coder — ${goal}` : "🔧 coder takes the wheel for the edit",
110
+ ({ goal }) => goal ? `🔧 coder: smallest correct change for "${goal}"` : "🔧 coder: smallest correct change incoming",
111
+ ({ goal }) => goal ? `🛠 coder cracks knuckles — ${goal}` : "🛠 coder cracks knuckles. Patch time.",
112
+ ({ goal }) => goal ? `🧰 coder enters the chat. Job: ${goal}` : "🧰 coder enters the chat. Time to do the boring correct thing.",
113
+ ({ goal }) => goal ? `⌨️ coder pinning down: ${goal}` : "⌨️ coder pinning down the exact lines",
114
+ ({ goal }) => goal ? `🪛 coder turning the screw on ${goal}` : "🪛 coder turning the screws carefully",
115
+ ({ goal }) => goal ? `🔧 coder takes the ticket — ${goal}` : "🔧 coder takes the ticket. No heroics, just the fix.",
116
+ ({ goal }) => goal ? `🎯 coder, target: ${goal}` : "🎯 coder locked on the next change",
117
+ ({ goal }) => goal ? `🧑‍💻 coder rolls up the sleeves — ${goal}` : "🧑‍💻 coder rolls up the sleeves",
118
+ ({ goal }) => goal ? `🚧 coder on site: ${goal}` : "🚧 coder on site. Hard hat goes on.",
119
+ ({ goal }) => goal ? `⚙️ coder warming the engine — ${goal}` : "⚙️ coder warming the engine",
120
+ ({ goal }) => goal ? `🤝 baton to coder: ${goal}` : "🤝 baton passes to coder",
121
+ ({ goal }) => goal ? `✍️ coder ready to type — ${goal}` : "✍️ coder ready to type the boring correct fix",
122
+ ({ goal }) => goal ? `🧪 coder will measure twice for "${goal}"` : "🧪 coder will measure twice, cut once",
123
+ ({ goal }) => goal ? `📎 coder pulls the relevant context for ${goal}` : "📎 coder pulls the relevant context first",
124
+ ({ goal }) => goal ? `🏃 coder off to the keys — ${goal}` : "🏃 coder off to the keys",
125
+ ({ goal }) => goal ? `🧱 coder lays one brick: ${goal}` : "🧱 coder lays one brick at a time",
126
+ ({ goal }) => goal ? `🔨 coder, hammer time on "${goal}"` : "🔨 coder, hammer time",
127
+ ({ goal }) => goal ? `🛟 coder rescues the diff — ${goal}` : "🛟 coder rescues the diff",
128
+ ],
129
+ "dispatch.reviewer": [
130
+ ({ goal }) => goal ? `🔎 reviewer takes a look: ${goal}` : "🔎 reviewer reads the diff (no edits)",
131
+ ({ goal }) => goal ? `🔎 reviewer auditing — ${goal}` : "🔎 reviewer auditing the change",
132
+ ({ goal }) => goal ? `🔎 reviewer cross-checking "${goal}"` : "🔎 reviewer cross-checking quality",
133
+ ({ goal }) => goal ? `👓 reviewer puts on the glasses — ${goal}` : "👓 reviewer puts on the glasses. Quiet for a sec.",
134
+ ({ goal }) => goal ? `🧐 reviewer skeptical-but-fair pass on ${goal}` : "🧐 reviewer doing the skeptical-but-fair pass",
135
+ ({ goal }) => goal ? `🔎 reviewer hunts the silent regression in ${goal}` : "🔎 reviewer hunting silent regressions",
136
+ ({ goal }) => goal ? `📝 reviewer marking margins on "${goal}"` : "📝 reviewer marking the margins",
137
+ ],
138
+ "dispatch.deepReviewer": [
139
+ ({ goal }) => goal ? `🛡 deep-reviewer: rigorous pass on ${goal}` : "🛡 deep-reviewer doing a rigorous read-only pass",
140
+ ({ goal }) => goal ? `🛡 deep-reviewer engaged for "${goal}"` : "🛡 deep-reviewer engaged for risky surface area",
141
+ ({ goal }) => goal ? `⚖️ deep-reviewer weighing every edge of ${goal}` : "⚖️ deep-reviewer weighing every edge case",
142
+ ({ goal }) => goal ? `🛡 deep-reviewer slow-reads the diff — ${goal}` : "🛡 deep-reviewer slow-reads the diff",
143
+ ({ goal }) => goal ? `🔬 deep-reviewer dissecting "${goal}" line by line` : "🔬 deep-reviewer dissecting line by line",
144
+ ],
145
+ "dispatch.explorer": [
146
+ ({ goal }) => goal ? `🧭 explorer scouts the code: ${goal}` : "🧭 explorer scouts the codebase",
147
+ ({ goal }) => goal ? `🧭 explorer mapping "${goal}"` : "🧭 explorer mapping the territory",
148
+ ({ goal }) => goal ? `🧭 explorer hunts for: ${goal}` : "🧭 explorer hunts for relevant files",
149
+ ({ goal }) => goal ? `🗺 explorer sketching the lay of the land for ${goal}` : "🗺 explorer sketching the lay of the land",
150
+ ({ goal }) => goal ? `🔭 explorer takes a wide read on ${goal}` : "🔭 explorer takes a wide read",
151
+ ({ goal }) => goal ? `🧭 explorer tailing references for "${goal}"` : "🧭 explorer tailing references",
152
+ ({ goal }) => goal ? `🌲 explorer wandering into the codebase — ${goal}` : "🌲 explorer wandering into the codebase",
153
+ ],
154
+ "dispatch.planner": [
155
+ ({ goal }) => goal ? `🗺 planner sketches a plan for: ${goal}` : "🗺 planner sketches the approach",
156
+ ({ goal }) => goal ? `🗺 planner laying out steps — ${goal}` : "🗺 planner laying out the steps",
157
+ ({ goal }) => goal ? `📐 planner blueprinting ${goal}` : "📐 planner blueprinting the approach",
158
+ ({ goal }) => goal ? `🗂 planner ordering the moves for "${goal}"` : "🗂 planner ordering the moves",
159
+ ({ goal }) => goal ? `🪜 planner stacking phases for ${goal}` : "🪜 planner stacking phases",
160
+ ],
161
+ "dispatch.architect": [
162
+ ({ goal }) => goal ? `🏛 architect reframes the problem: ${goal}` : "🏛 architect reframes the problem",
163
+ ({ goal }) => goal ? `🏛 architect proposing a new design for ${goal}` : "🏛 architect proposing a new design",
164
+ ({ goal }) => goal ? `🏗 architect zooming out on ${goal}` : "🏗 architect zooming out",
165
+ ({ goal }) => goal ? `🏛 architect: 'let's draw it first' — ${goal}` : "🏛 architect: 'let's draw it first'",
166
+ ({ goal }) => goal ? `📐 architect cross-cutting concerns on "${goal}"` : "📐 architect cross-cutting concerns",
167
+ ],
168
+ "dispatch.researcher": [
169
+ ({ goal }) => goal ? `📚 researcher digs into the docs for ${goal}` : "📚 researcher digs into docs and code",
170
+ ({ goal }) => goal ? `📚 researcher pulling references for "${goal}"` : "📚 researcher pulling references",
171
+ ({ goal }) => goal ? `🔬 researcher reading the upstream for ${goal}` : "🔬 researcher reading the upstream",
172
+ ({ goal }) => goal ? `🗃 researcher cross-referencing "${goal}"` : "🗃 researcher cross-referencing prior art",
173
+ ],
174
+ "dispatch.debugger": [
175
+ ({ goal }) => goal ? `🐛 debugger tracking the root cause of ${goal}` : "🐛 debugger tracking the root cause",
176
+ ({ goal }) => goal ? `🐛 debugger reproducing "${goal}"` : "🐛 debugger reproducing the failure",
177
+ ({ goal }) => goal ? `🔦 debugger flashlight on ${goal}` : "🔦 debugger flashlight on the stack",
178
+ ({ goal }) => goal ? `🪤 debugger setting a trap for "${goal}"` : "🪤 debugger setting a trap",
179
+ ({ goal }) => goal ? `🧪 debugger isolating ${goal} in a minimal repro` : "🧪 debugger isolating the failure",
180
+ ],
181
+ "dispatch.codex": [
182
+ ({ goal }) => goal ? `🧠 codex tackles ${goal}` : "🧠 codex tackles a hard reasoning task",
183
+ ({ goal }) => goal ? `🧠 codex chewing on "${goal}"` : "🧠 codex chewing on a thorny piece",
184
+ ({ goal }) => goal ? `📚 codex consults its tomes for ${goal}` : "📚 codex consults its tomes",
185
+ ],
186
+ "dispatch.glm": [
187
+ ({ goal }) => goal ? `⚡ glm handles ${goal}` : "⚡ glm handles the next slice",
188
+ ({ goal }) => goal ? `⚡ glm sprinting through "${goal}"` : "⚡ glm sprinting through the next slice",
189
+ ({ goal }) => goal ? `🐎 glm fast lane on ${goal}` : "🐎 glm fast lane",
190
+ ],
191
+ "dispatch.gpt": [
192
+ ({ goal }) => goal ? `🚀 gpt drives ${goal}` : "🚀 gpt drives the next slice",
193
+ ({ goal }) => goal ? `🚀 gpt boosting through "${goal}"` : "🚀 gpt boosting through",
194
+ ({ goal }) => goal ? `🎯 gpt locked on ${goal}` : "🎯 gpt locked on the target",
195
+ ],
196
+ "dispatch.gptCoder": [
197
+ ({ goal }) => goal ? `🧠 gpt-coder handles a tough patch: ${goal}` : "🧠 gpt-coder handles a tough patch",
198
+ ({ goal }) => goal ? `🧠 gpt-coder taking the hard one — ${goal}` : "🧠 gpt-coder taking the hard one",
199
+ ({ goal }) => goal ? `🛠 gpt-coder splicing the gnarly part of "${goal}"` : "🛠 gpt-coder splicing the gnarly part",
200
+ ],
201
+ "dispatch.completed": [
202
+ ({ to }) => `✅ ${to} done — control back to resolver`,
203
+ ({ to }) => `✅ ${to} reported back — resolver resumes`,
204
+ ({ to }) => `✅ ${to} wrapped — resolver picks up the result`,
205
+ ({ to }) => `🏁 ${to} cleared — back to the main thread`,
206
+ ({ to }) => `📬 ${to} dropped the result. Resolver picks it up.`,
207
+ ({ to }) => `👌 ${to} closed it out`,
208
+ ({ to }) => `✅ ${to} returns with a clean report`,
209
+ ({ to }) => `🎬 ${to} cuts. Scene returns to resolver.`,
210
+ ({ to }) => `📦 ${to} delivered — resolver opens the box`,
211
+ ({ to }) => `🎤 ${to} hands the mic back to resolver`,
212
+ ({ to }) => `🛬 ${to} touchdown — back to taxi`,
213
+ ({ to }) => `🧾 ${to} files the report`,
214
+ ({ to }) => `🪃 ${to} comes back with the answer`,
215
+ ({ to }) => `🛎 ${to} rings the done bell`,
216
+ ({ to }) => `🤝 ${to} → resolver: handed off cleanly`,
217
+ ],
218
+ "dispatch.failed": [
219
+ ({ to }) => `⚠️ ${to} hit a snag — resolver inspecting`,
220
+ ({ to }) => `⚠️ ${to} couldn't close it — resolver retries with a different plan`,
221
+ ({ to }) => `💥 ${to} stumbled — diagnosing root cause now`,
222
+ ({ to }) => `🩹 ${to} bounced — resolver picking a new angle`,
223
+ ({ to }) => `⛔️ ${to} reports trouble. Time for a different approach.`,
224
+ ({ to }) => `😬 ${to} ran into a wall — let's not bang harder, let's go around`,
225
+ ({ to }) => `🧯 ${to} hit smoke — resolver puts it out and re-plans`,
226
+ ({ to }) => `🔁 ${to} retry needed — same goal, new path`,
227
+ ({ to }) => `🥲 ${to} came back empty — diagnosing`,
228
+ ({ to }) => `🪤 ${to} caught in a trap — resolver freeing it`,
229
+ ],
230
+ "narration.editing": [
231
+ "✏️ shaping the patch",
232
+ "✏️ making the change",
233
+ "✏️ rewriting the relevant lines",
234
+ "🖋 putting it on paper",
235
+ "🛠 tightening the bolts",
236
+ "✏️ surgical edit incoming",
237
+ "✏️ small precise change — measure twice",
238
+ "🪡 stitching the lines together",
239
+ "🔧 nudging the bits into place",
240
+ "✂️ snipping the wrong line, splicing the right one",
241
+ "✏️ keystroke by keystroke",
242
+ "🪚 trimming the dead code",
243
+ "🧷 pinning the right value",
244
+ "🩹 small patch on the bleed",
245
+ "🎚 dialing in the value",
246
+ "🪛 minor adjustment, major payoff",
247
+ "🖌 brushstroke on the patch",
248
+ "🎯 landing the change exactly",
249
+ "🪞 mirroring the existing style",
250
+ "🧼 quiet refactor in passing",
251
+ ],
252
+ "narration.searching": [
253
+ "🔍 grepping the codebase",
254
+ "🔍 looking for the right hook",
255
+ "🔍 scanning for the pattern",
256
+ "🕵 sniffing out the call sites",
257
+ "🔎 tracing the symbol",
258
+ "🔍 casting a wide net",
259
+ "🧭 narrowing the search",
260
+ "🪤 setting filters on the search",
261
+ "🔍 walking the references",
262
+ "🔭 zooming in on a suspect file",
263
+ "🕸 following the import graph",
264
+ "🔍 finding the needle",
265
+ "🗺 cross-referencing locations",
266
+ "🧲 magnet on the symbol name",
267
+ "🕯 holding up the candle to the dark module",
268
+ ],
269
+ "narration.reading": [
270
+ "📖 reading the file",
271
+ "📖 loading context",
272
+ "📖 checking what's already there",
273
+ "📚 doing the reading first",
274
+ "📖 absorbing the surrounding code",
275
+ "👀 skimming for relevant bits",
276
+ "📖 not skipping the comments",
277
+ "📃 paging through the function",
278
+ "📖 'measure first' phase",
279
+ "🔍 reading the contract before signing",
280
+ "📑 catching up with the file",
281
+ "📖 reading the whole thing — no shortcuts",
282
+ "🧠 building the mental model first",
283
+ "📖 picking up the thread",
284
+ "📕 RTFM on this module",
285
+ "🪟 looking through the window of the function",
286
+ ],
287
+ "narration.thinking": [
288
+ "🧠 thinking through the next move",
289
+ "🧠 weighing the options",
290
+ "🧠 picking the smallest correct path",
291
+ "💭 mulling it over",
292
+ "🧠 connecting the dots",
293
+ "🧠 sleeping on it for a half-second",
294
+ "🤔 considering the boring option (it usually wins)",
295
+ "🧠 running the trade-offs",
296
+ "🪙 flipping the option coin... but with reasons",
297
+ "🧠 picturing the call graph",
298
+ "🤨 asking 'what would break?' before acting",
299
+ "🧠 simulating it in my head first",
300
+ "💡 small idea forming",
301
+ "🧠 narrowing it to one move",
302
+ "🪑 sitting with the design for a beat",
303
+ "🧠 'do nothing' is also an option, considering it",
304
+ "🤔 looking for the cheaper fix",
305
+ "🧠 if X then Y else Z — walking the branches",
306
+ ],
307
+ "narration.bashing": [
308
+ "💻 running a shell step",
309
+ "💻 executing the command",
310
+ "💻 firing the script",
311
+ "🐚 dropping into the shell",
312
+ "💻 letting the command speak",
313
+ "📟 piping bits around",
314
+ "🖥 talking to the OS",
315
+ "💻 a quick subprocess",
316
+ "🛎 ringing the bell on a CLI",
317
+ "🚀 launching the command",
318
+ "🐚 from /bin with love",
319
+ "⌨️ shelling out",
320
+ "💻 expect-non-interactive mode engaged",
321
+ ],
322
+ "narration.compacting": [
323
+ "🗑 dropping the older context to keep momentum",
324
+ "🗑 trimming the transcript — we keep driving",
325
+ "🗑 sweeping up old chatter",
326
+ "🗑 making room for the next stretch",
327
+ "🗑 archive the noise, keep the signal",
328
+ ],
329
+ "narration.writing": [
330
+ "📝 writing the new file",
331
+ "📝 fresh file going down",
332
+ "📝 putting it in writing",
333
+ "📜 laying out the new module",
334
+ "📝 first draft hitting disk",
335
+ "🆕 brand-new file on the way",
336
+ "📝 scaffolding the file",
337
+ ],
338
+ "narration.testing": [
339
+ "🧪 running the tests",
340
+ "🧪 letting the suite speak",
341
+ "🧪 test runner — the only honest reviewer",
342
+ "🧪 spinning up the tests",
343
+ "🧪 watching the green/red verdict",
344
+ "🧪 tests get to vote",
345
+ "🧪 burning some CPU on truth",
346
+ ],
347
+ "narration.typechecking": [
348
+ "🧬 type-checking",
349
+ "🧬 letting tsc do its job",
350
+ "🧬 chasing red squigglies",
351
+ "🧬 type narrowing pass",
352
+ "🧬 making the compiler happy",
353
+ "🧬 fighting it out with the type system",
354
+ ],
355
+ "narration.linting": [
356
+ "🧹 running the linter",
357
+ "🧹 tidying up the styling",
358
+ "🧹 letting the linter complain",
359
+ "🧹 dusting off the formatting",
360
+ "🧹 polishing — fast pass",
361
+ "🧹 letting the rules talk",
362
+ ],
363
+ "narration.git": [
364
+ "🌳 talking to git",
365
+ "🌳 checking the tree",
366
+ "🌳 reading the history",
367
+ "🌳 quick git glance",
368
+ "🌳 reading the blame",
369
+ "🌳 inspecting the diff",
370
+ "🌳 listening to git",
371
+ ],
372
+ "narration.fetch": [
373
+ "🌐 fetching from the web",
374
+ "🌐 grabbing the docs",
375
+ "🌐 stepping out to the network",
376
+ "🌐 quick trip to the docs",
377
+ "🌐 reading the upstream",
378
+ "🛰 satellite link to the web",
379
+ ],
380
+ "narration.todo": [
381
+ "📋 updating the todo board",
382
+ "📋 marking progress",
383
+ "📋 keeping the list honest",
384
+ "📋 ticking the box",
385
+ "📋 next item, please",
386
+ "📋 keeping the tasks honest",
387
+ ],
388
+ "narration.diagnostics": [
389
+ "📡 pulling LSP diagnostics",
390
+ "📡 reading the current errors",
391
+ "📡 letting the language server tell us where it hurts",
392
+ "📡 LSP says...",
393
+ "📡 listening for the squigglies",
394
+ "📡 reading what the IDE already knows",
395
+ ],
396
+ "narration.context": [
397
+ "📦 loading project context",
398
+ "📦 gathering the relevant docs",
399
+ "📦 priming the working set",
400
+ "📦 stocking up on context",
401
+ "📦 collecting the relevant files",
402
+ "📦 minimum-viable context, loading",
403
+ ],
404
+ "narration.verifyPass": [
405
+ "✅ green build — onward",
406
+ "✅ verification passed",
407
+ "✅ the tests are happy",
408
+ "🟢 all checks green",
409
+ "✅ clean run — moving on",
410
+ "🎉 verify clear",
411
+ "✅ build sane, tests happy",
412
+ ],
413
+ "narration.verifyFail": [
414
+ "❌ verification failed — diagnosing",
415
+ "❌ red build — finding the bite",
416
+ "❌ tests are unhappy. Reading the output.",
417
+ "🔴 verify says no — reading the failure",
418
+ "❌ something's biting — let's find the tooth",
419
+ "❌ red light. Pulling logs.",
420
+ ],
421
+ "narration.idle": [
422
+ "☕ catching breath, then back to it",
423
+ "🧘 brief pause — gathering the next step",
424
+ "🪑 sitting with the problem for a beat",
425
+ "🌬 short exhale before the next move",
426
+ "🪑 brief regroup",
427
+ ],
428
+ "strategy.smallerPieces": "Break the problem into smaller pieces. Edit one function at a time, verify between each.",
429
+ "strategy.differentFile": "Check if the error is actually in a DIFFERENT file — the real issue may be upstream.",
430
+ "strategy.readTest": "Read the test file if it exists — the test often reveals the expected behavior.",
431
+ "strategy.checkImports": "Check imports — missing or wrong imports are a common cause of cascading errors.",
432
+ "strategy.searchSimilar": "Use resolve-search to find similar patterns elsewhere in the codebase.",
433
+ "strategy.rereadFile": "Re-read the file carefully. You may be missing existing code that conflicts with your edit.",
434
+ "strategy.tryDifferent": "Try a completely different approach — revert your last change and try a different fix.",
435
+ "strategy.useDiagnostics": "Use resolve-diagnostics to check current LSP errors before the next edit.",
436
+ "strategy.suggestionLabel": "Strategy suggestion",
437
+ },
438
+ ko: {
439
+ "reminder.verify": [
440
+ "리마인더: 완료 보고 전에 변경사항을 검증하세요 (resolve-verify).",
441
+ "잠깐 — typecheck/lint/test 가 통과하기 전에는 완료 보고 금지.",
442
+ "확인: 검증 명령은 실제로 돌렸어요? 'diff 가 그럴듯해 보임' 은 증거가 아니에요.",
443
+ "마무리 전에: 검증 게이트를 통과시키세요. 컴파일된다 ≠ 동작한다.",
444
+ "리마인더: 빌드가 초록색이어야 완료입니다. resolve-verify 실행하세요.",
445
+ "주의: 검증이 통과했을 때 알려주세요. diff 가 좋아 보일 때 말고요.",
446
+ ],
447
+ "reminder.ralphLoopText": [
448
+ "🔄 Ralph Loop: 반복이 많이 감지됐어요. resolve-diagnostics 로 현재 상태를 확인하고, 다른 접근을 시도해보세요. 멈추지 말고 끝까지 갑니다.",
449
+ "🔄 Ralph Loop 진행 중. 같은 자리에서 맴돌고 있어요 — 다음 시도 전에 접근을 바꾸세요.",
450
+ "🔄 Ralph Loop: 휘청거리는 느낌이에요. 진단부터 읽고, 새 각도로 가세요.",
451
+ ],
452
+ "system.driveResolution": "검증된 해결까지 끌고 가세요. 의도를 분류하고, 집중된 서브에이전트를 위임하고, 각 단계 후 검증하고, 실패 시 반복하세요. 검증이 끝났을 때만 완료를 보고합니다.",
453
+ "system.projectKnowledge": ({ files }) => `프로젝트 지식 문서: ${files}. 코드 수정 전에 필요하면 먼저 읽으세요.`,
454
+ "system.contextDocs": ({ files }) => `컨텍스트 문서: ${files}. MVI 원칙: 작업에 관련 있는 문서만 로드합니다.`,
455
+ "system.verifyCommands": ({ commands }) => `검증 명령: ${commands}. 변경 후 실행하세요.`,
456
+ "system.typescriptMandatory": "TypeScript 프로젝트입니다 — 타입 안전성 필수. `as any` 와 `@ts-ignore` 금지.",
457
+ "system.failuresHeader": "⚠️ 반복되는 실패가 감지됐어요:",
458
+ "system.failuresFooter": "멈추지 마세요 — 같은 목표를 다른 접근으로 시도하세요. Ralph Loop 는 완료까지 끌고 가는 게 일입니다.",
459
+ "system.strategyPivotHeader": ({ count }) => `🔀 전략 전환: 총 ${count}회의 실패가 감지됐어요.`,
460
+ "system.strategyPivotBody": "지금 접근은 통하지 않아요. ARCHITECT 를 위임해서 문제를 처음부터 분석하고 근본적으로 다른 전략을 제안받으세요.",
461
+ "system.strategyPivotTail": "그 다음 새 전략을 적용하세요. 같은 접근을 다시 시도하지 마세요.",
462
+ "system.ralphHeader": "🔄 Ralph Loop: 같은 파일을 너무 자주 수정 중이에요:",
463
+ "system.ralphKeepGoing": "계속 진행하세요 — Ralph Loop 는 검증된 해결이 나올 때까지 반복합니다.",
464
+ "system.sessionStats": ({ edits, calls, elapsed }) => `📊 세션 통계: ${edits}회 편집, ${calls}회 도구 호출, ${elapsed}초 경과.`,
465
+ "system.iterationWarning": "실패와 함께 반복이 많아졌어요. 근본적으로 다른 접근을 고려하세요 — 하지만 멈추지는 마세요.",
466
+ "compaction.contextHeader": ({ body }) => `프로젝트 컨텍스트 (보존): ${body}`,
467
+ "tool.edit": "먼저 파일을 읽으세요. 가장 작은 정확한 변경을 만드세요. 편집 후 검증하세요.",
468
+ "tool.write": "명시적으로 필요할 때만 새 파일을 만드세요. 기존 파일 편집을 우선합니다.",
469
+ "tool.bash": "명령은 비대화형으로 실행됩니다. 대화형 에디터, 페이저, REPL 금지. 스크립팅용 -c 플래그 사용.",
470
+ "tool.task": "서브에이전트 위임 시: TASK(원자적 목표), OUTCOME(성공 기준), MUST DO, MUST NOT DO, CONTEXT 를 명시하세요.",
471
+ "tool.glob": "구체적인 패턴을 쓰세요. 정말 필요할 때 외엔 '**/*' 피하기 — 범위가 좁은 검색을 선호합니다.",
472
+ "tool.grep": "구체적인 정규식을 쓰세요. include 필터와 조합해 대상을 좁히세요.",
473
+ "tool.read": "필요한 만큼만 읽으세요. 큰 파일은 offset/limit 사용. 메타정보가 필요하면 file-info 도구를 먼저 확인하세요.",
474
+ "tool.webfetch": "정말 외부 정보가 필요할 때만 URL 을 가져오세요. 로컬 문서와 코드를 먼저 살핍니다.",
475
+ "tool.todowrite": "할 일을 최신 상태로 유지하세요. 완료 즉시 표시. in_progress 는 한 번에 하나만.",
476
+ "dispatch.toSubagent": [
477
+ ({ from, to, goal }) => goal ? `🎯 ${from} → ${to}: ${goal}` : `🎯 ${from} → ${to}: 서브에이전트에 작업 위임`,
478
+ ({ from, to, goal }) => goal ? `▶ ${from} 가 ${to} 에게 넘김 — ${goal}` : `▶ ${from} 가 ${to} 에게 작업을 넘깁니다`,
479
+ ({ from, to, goal }) => goal ? `📡 ${from} → ${to} | ${goal}` : `📡 ${from} → ${to} (서브태스크)`,
480
+ ({ from, to, goal }) => goal ? `🤝 ${from} 가 "${goal}" 를 ${to} 에게 위임` : `🤝 ${from} 가 ${to} 에게 위임`,
481
+ ],
482
+ "dispatch.fromResolver": [
483
+ ({ to }) => `🎯 ${to} 서브에이전트 호출`,
484
+ ({ to }) => `▶ ${to} 가동`,
485
+ ({ to }) => `📡 ${to} 출동 준비`,
486
+ ],
487
+ "dispatch.coder": [
488
+ ({ goal }) => goal ? `🔧 코더 출동: ${goal}` : "🔧 코더가 구현 작업을 받았어요",
489
+ ({ goal }) => goal ? `🔧 코더에게 패치 위임 — ${goal}` : "🔧 코더가 편집을 맡습니다",
490
+ ({ goal }) => goal ? `🔧 코더: "${goal}" 에 대해 가장 작은 정확한 변경 진행` : "🔧 코더: 가장 작은 정확한 변경 들어갑니다",
491
+ ({ goal }) => goal ? `🛠 코더가 손가락 풀고 — ${goal}` : "🛠 코더가 손가락 풀고 시작합니다",
492
+ ({ goal }) => goal ? `🧰 코더 등판. 작업: ${goal}` : "🧰 코더 등판. 화려한 거 없이 정확한 거 하나 박습니다.",
493
+ ({ goal }) => goal ? `⌨️ 코더가 정확히 어느 줄인지 짚는 중 — ${goal}` : "⌨️ 코더가 정확히 어느 줄인지 짚는 중",
494
+ ({ goal }) => goal ? `🪛 코더가 "${goal}" 의 나사 조이는 중` : "🪛 코더가 나사 조이는 중",
495
+ ({ goal }) => goal ? `🔧 코더가 티켓을 받음 — ${goal}` : "🔧 코더가 티켓을 받았습니다. 영웅놀이 없이 정공법으로.",
496
+ ({ goal }) => goal ? `🎯 코더, 타겟: ${goal}` : "🎯 코더가 다음 변경에 락온",
497
+ ({ goal }) => goal ? `🧑‍💻 코더가 소매 걷어붙임 — ${goal}` : "🧑‍💻 코더가 소매 걷어붙입니다",
498
+ ({ goal }) => goal ? `🚧 코더 현장 도착: ${goal}` : "🚧 코더 현장 도착. 안전모 착용.",
499
+ ({ goal }) => goal ? `⚙️ 코더 엔진 워밍업 — ${goal}` : "⚙️ 코더 엔진 워밍업",
500
+ ({ goal }) => goal ? `🤝 바통 코더에게: ${goal}` : "🤝 바통이 코더에게 넘어갑니다",
501
+ ({ goal }) => goal ? `✍️ 코더가 타이핑 준비 — ${goal}` : "✍️ 코더가 지루하지만 정확한 수정을 타이핑할 준비",
502
+ ({ goal }) => goal ? `🧪 코더는 "${goal}" 두 번 잴 거예요` : "🧪 코더는 두 번 재고 한 번 자릅니다",
503
+ ({ goal }) => goal ? `📎 코더가 ${goal} 관련 컨텍스트 끌어오는 중` : "📎 코더가 관련 컨텍스트부터 끌어옵니다",
504
+ ({ goal }) => goal ? `🏃 코더가 키보드로 — ${goal}` : "🏃 코더가 키보드로 달려갑니다",
505
+ ({ goal }) => goal ? `🧱 코더가 벽돌 한 장씩: ${goal}` : "🧱 코더가 벽돌을 한 장씩 쌓습니다",
506
+ ({ goal }) => goal ? `🔨 코더, "${goal}" 망치 타임` : "🔨 코더, 망치 타임",
507
+ ({ goal }) => goal ? `🛟 코더가 diff 구조 — ${goal}` : "🛟 코더가 diff 를 구조합니다",
508
+ ({ goal }) => goal ? `🐢 코더가 천천히, 그러나 정확히 — ${goal}` : "🐢 코더가 천천히, 그러나 정확히",
509
+ ({ goal }) => goal ? `🍵 코더가 한 모금 마시고 ${goal} 들어갑니다` : "🍵 코더가 한 모금 마시고 들어갑니다",
510
+ ],
511
+ "dispatch.reviewer": [
512
+ ({ goal }) => goal ? `🔎 리뷰어 확인: ${goal}` : "🔎 리뷰어가 변경사항을 읽습니다 (편집 없음)",
513
+ ({ goal }) => goal ? `🔎 리뷰어 감사 — ${goal}` : "🔎 리뷰어가 변경을 감사 중",
514
+ ({ goal }) => goal ? `🔎 리뷰어 교차 검증 "${goal}"` : "🔎 리뷰어 품질 교차 검증",
515
+ ({ goal }) => goal ? `👓 리뷰어가 안경 올리고 — ${goal}` : "👓 리뷰어가 안경 올리는 중. 잠깐 조용히.",
516
+ ({ goal }) => goal ? `🧐 리뷰어가 "${goal}" 에 까칠하게 한 번 봅니다` : "🧐 리뷰어가 까칠하지만 공정하게 한 번 봅니다",
517
+ ({ goal }) => goal ? `🔎 리뷰어가 ${goal} 의 조용한 회귀 버그를 사냥 중` : "🔎 리뷰어가 조용한 회귀 버그를 사냥 중",
518
+ ({ goal }) => goal ? `📝 리뷰어가 "${goal}" 여백에 메모를 다는 중` : "📝 리뷰어가 여백에 메모를 다는 중",
519
+ ],
520
+ "dispatch.deepReviewer": [
521
+ ({ goal }) => goal ? `🛡 딥리뷰어: ${goal} 엄격 검토` : "🛡 딥리뷰어가 엄격 읽기 전용 검토를 진행",
522
+ ({ goal }) => goal ? `🛡 딥리뷰어 투입 — "${goal}"` : "🛡 위험 영역에 딥리뷰어 투입",
523
+ ({ goal }) => goal ? `⚖️ 딥리뷰어가 ${goal} 의 모든 엣지를 저울질` : "⚖️ 딥리뷰어가 모든 엣지 케이스를 저울질",
524
+ ({ goal }) => goal ? `🛡 딥리뷰어가 diff 를 천천히 — ${goal}` : "🛡 딥리뷰어가 diff 를 천천히 읽는 중",
525
+ ({ goal }) => goal ? `🔬 딥리뷰어가 "${goal}" 를 한 줄씩 해부 중` : "🔬 딥리뷰어가 한 줄씩 해부 중",
526
+ ],
527
+ "dispatch.explorer": [
528
+ ({ goal }) => goal ? `🧭 익스플로러 탐색: ${goal}` : "🧭 익스플로러가 코드베이스를 탐색합니다",
529
+ ({ goal }) => goal ? `🧭 익스플로러 지도 작성 "${goal}"` : "🧭 익스플로러가 영역을 매핑합니다",
530
+ ({ goal }) => goal ? `🧭 익스플로러 추적: ${goal}` : "🧭 익스플로러가 관련 파일을 추적합니다",
531
+ ({ goal }) => goal ? `🗺 익스플로러가 ${goal} 의 지형을 그리는 중` : "🗺 익스플로러가 지형을 그리는 중",
532
+ ({ goal }) => goal ? `🔭 익스플로러가 ${goal} 를 넓게 읽는 중` : "🔭 익스플로러가 넓게 읽는 중",
533
+ ({ goal }) => goal ? `🧭 익스플로러가 "${goal}" 의 참조를 따라가는 중` : "🧭 익스플로러가 참조를 따라가는 중",
534
+ ({ goal }) => goal ? `🌲 익스플로러가 코드베이스 속으로 — ${goal}` : "🌲 익스플로러가 코드베이스 속으로 들어갑니다",
535
+ ],
536
+ "dispatch.planner": [
537
+ ({ goal }) => goal ? `🗺 플래너 설계: ${goal}` : "🗺 플래너가 접근 방안을 그립니다",
538
+ ({ goal }) => goal ? `🗺 플래너 단계 정리 — ${goal}` : "🗺 플래너가 단계를 정리합니다",
539
+ ({ goal }) => goal ? `📐 플래너가 ${goal} 청사진 작성 중` : "📐 플래너가 청사진을 작성 중",
540
+ ({ goal }) => goal ? `🗂 플래너가 "${goal}" 의 순서를 정리 중` : "🗂 플래너가 순서를 정리 중",
541
+ ({ goal }) => goal ? `🪜 플래너가 ${goal} 단계를 쌓는 중` : "🪜 플래너가 단계를 쌓는 중",
542
+ ],
543
+ "dispatch.architect": [
544
+ ({ goal }) => goal ? `🏛 아키텍트가 ${goal} 문제를 재정의` : "🏛 아키텍트가 문제를 재정의합니다",
545
+ ({ goal }) => goal ? `🏛 아키텍트가 ${goal} 의 새 설계 제안` : "🏛 아키텍트가 새로운 설계를 제안합니다",
546
+ ({ goal }) => goal ? `🏗 아키텍트가 ${goal} 를 줌아웃해서 보는 중` : "🏗 아키텍트가 줌아웃해서 보는 중",
547
+ ({ goal }) => goal ? `🏛 아키텍트: '먼저 그림부터' — ${goal}` : "🏛 아키텍트: '먼저 그림부터 그리자'",
548
+ ({ goal }) => goal ? `📐 아키텍트가 "${goal}" 의 횡단 관심사를 정리` : "📐 아키텍트가 횡단 관심사를 정리",
549
+ ],
550
+ "dispatch.researcher": [
551
+ ({ goal }) => goal ? `📚 리서처가 ${goal} 관련 문서 조사` : "📚 리서처가 문서와 코드를 조사합니다",
552
+ ({ goal }) => goal ? `📚 리서처가 "${goal}" 참고자료 수집` : "📚 리서처가 참고자료를 수집합니다",
553
+ ({ goal }) => goal ? `🔬 리서처가 ${goal} 의 업스트림을 읽는 중` : "🔬 리서처가 업스트림을 읽는 중",
554
+ ({ goal }) => goal ? `🗃 리서처가 "${goal}" 의 선행 사례 교차 참조` : "🗃 리서처가 선행 사례 교차 참조",
555
+ ],
556
+ "dispatch.debugger": [
557
+ ({ goal }) => goal ? `🐛 디버거가 ${goal} 의 근본 원인 추적` : "🐛 디버거가 근본 원인을 추적합니다",
558
+ ({ goal }) => goal ? `🐛 디버거가 "${goal}" 재현 중` : "🐛 디버거가 실패를 재현합니다",
559
+ ({ goal }) => goal ? `🔦 디버거가 ${goal} 에 손전등을 비춤` : "🔦 디버거가 스택에 손전등을 비추는 중",
560
+ ({ goal }) => goal ? `🪤 디버거가 "${goal}" 함정 설치 중` : "🪤 디버거가 함정을 설치하는 중",
561
+ ({ goal }) => goal ? `🧪 디버거가 ${goal} 를 최소 재현으로 격리` : "🧪 디버거가 최소 재현으로 격리 중",
562
+ ],
563
+ "dispatch.codex": [
564
+ ({ goal }) => goal ? `🧠 코덱스가 ${goal} 처리` : "🧠 코덱스가 까다로운 추론 작업을 받습니다",
565
+ ({ goal }) => goal ? `🧠 코덱스가 "${goal}" 를 곱씹는 중` : "🧠 코덱스가 까다로운 부분을 곱씹는 중",
566
+ ({ goal }) => goal ? `📚 코덱스가 ${goal} 의 비전을 들춰보는 중` : "📚 코덱스가 비전을 들춰보는 중",
567
+ ],
568
+ "dispatch.glm": [
569
+ ({ goal }) => goal ? `⚡ GLM 이 ${goal} 처리` : "⚡ GLM 이 다음 슬라이스를 처리합니다",
570
+ ({ goal }) => goal ? `⚡ GLM 이 "${goal}" 를 빠르게 통과 중` : "⚡ GLM 이 다음 슬라이스를 빠르게 통과 중",
571
+ ({ goal }) => goal ? `🐎 GLM 패스트레인 — ${goal}` : "🐎 GLM 패스트레인",
572
+ ],
573
+ "dispatch.gpt": [
574
+ ({ goal }) => goal ? `🚀 GPT 가 ${goal} 진행` : "🚀 GPT 가 다음 슬라이스를 끌고 갑니다",
575
+ ({ goal }) => goal ? `🚀 GPT 가 "${goal}" 부스팅` : "🚀 GPT 가 부스팅 중",
576
+ ({ goal }) => goal ? `🎯 GPT 가 ${goal} 에 락온` : "🎯 GPT 가 타겟에 락온",
577
+ ],
578
+ "dispatch.gptCoder": [
579
+ ({ goal }) => goal ? `🧠 GPT 코더가 까다로운 패치: ${goal}` : "🧠 GPT 코더가 까다로운 패치를 받습니다",
580
+ ({ goal }) => goal ? `🧠 GPT 코더가 어려운 거 — ${goal}` : "🧠 GPT 코더가 어려운 거 맡습니다",
581
+ ({ goal }) => goal ? `🛠 GPT 코더가 "${goal}" 의 까다로운 부분을 봉합` : "🛠 GPT 코더가 까다로운 부분을 봉합 중",
582
+ ],
583
+ "dispatch.completed": [
584
+ ({ to }) => `✅ ${to} 완료 — 리졸버에게 제어 반환`,
585
+ ({ to }) => `✅ ${to} 보고 도착 — 리졸버가 이어 받음`,
586
+ ({ to }) => `✅ ${to} 마무리 — 리졸버가 결과를 회수`,
587
+ ({ to }) => `🏁 ${to} 정리됨 — 메인 스레드 복귀`,
588
+ ({ to }) => `📬 ${to} 결과 도착. 리졸버가 받습니다.`,
589
+ ({ to }) => `👌 ${to} 깔끔하게 종료`,
590
+ ({ to }) => `✅ ${to} 가 깨끗한 리포트로 복귀`,
591
+ ({ to }) => `🎬 ${to} 컷. 씬은 리졸버로 복귀.`,
592
+ ({ to }) => `📦 ${to} 배달 완료 — 리졸버가 박스 열어봅니다`,
593
+ ({ to }) => `🎤 ${to} 가 리졸버에게 마이크 반환`,
594
+ ({ to }) => `🛬 ${to} 착륙 — 게이트로 이동`,
595
+ ({ to }) => `🧾 ${to} 리포트 제출`,
596
+ ({ to }) => `🪃 ${to} 가 답 가지고 돌아옴`,
597
+ ({ to }) => `🛎 ${to} 가 종 울림 — 완료`,
598
+ ({ to }) => `🤝 ${to} → 리졸버: 깔끔하게 인수인계`,
599
+ ({ to }) => `🎁 ${to} 결과물 도착`,
600
+ ],
601
+ "dispatch.failed": [
602
+ ({ to }) => `⚠️ ${to} 가 걸렸어요 — 리졸버 확인 중`,
603
+ ({ to }) => `⚠️ ${to} 가 마무리를 못 했어요 — 리졸버가 다른 계획으로 재시도`,
604
+ ({ to }) => `💥 ${to} 가 헛디뎠어요 — 근본 원인 진단 중`,
605
+ ({ to }) => `🩹 ${to} 가 튕겼어요 — 리졸버가 다른 각도를 잡습니다`,
606
+ ({ to }) => `⛔️ ${to} 가 곤란해 하는군요. 다른 접근 갑니다.`,
607
+ ({ to }) => `😬 ${to} 가 벽에 부딪힘 — 더 세게 박지 말고 돌아갑시다`,
608
+ ({ to }) => `🧯 ${to} 연기 발생 — 리졸버가 진화하고 재계획`,
609
+ ({ to }) => `🔁 ${to} 재시도 필요 — 같은 목표, 다른 경로`,
610
+ ({ to }) => `🥲 ${to} 빈손으로 복귀 — 진단 중`,
611
+ ({ to }) => `🪤 ${to} 가 함정에 빠짐 — 리졸버가 빼내는 중`,
612
+ ({ to }) => `🤷 ${to} 가 이번엔 안 통했네요 — 다음 카드`,
613
+ ],
614
+ "narration.editing": [
615
+ "✏️ 패치 작성 중",
616
+ "✏️ 변경 적용 중",
617
+ "✏️ 관련 라인 재작성 중",
618
+ "🖋 종이에 옮기는 중",
619
+ "🛠 볼트를 조이는 중",
620
+ "✏️ 외과적 편집 들어갑니다",
621
+ "✏️ 작고 정확하게 — 두 번 재고 한 번 자르기",
622
+ "🪡 라인들을 꿰매는 중",
623
+ "🔧 비트를 제자리에 살짝 밀어 넣는 중",
624
+ "✂️ 잘못된 줄 잘라내고 옳은 줄 붙이는 중",
625
+ "✏️ 키 하나하나 정성껏",
626
+ "🪚 죽은 코드 다듬는 중",
627
+ "🧷 올바른 값으로 고정 중",
628
+ "🩹 출혈 부위에 작은 패치",
629
+ "🎚 값 미세 조정 중",
630
+ "🪛 작은 조정, 큰 보상",
631
+ "🖌 패치에 한 획",
632
+ "🎯 정확히 그 자리에 변경 안착",
633
+ "🪞 기존 스타일 그대로 미러링",
634
+ "🧼 지나가며 조용히 리팩터",
635
+ "📐 줄 맞추는 중",
636
+ "🧩 퍼즐 한 조각 끼우는 중",
637
+ ],
638
+ "narration.searching": [
639
+ "🔍 코드베이스 grep 중",
640
+ "🔍 적절한 훅 위치 탐색",
641
+ "🔍 패턴 스캔 중",
642
+ "🕵 호출 지점 추적 중",
643
+ "🔎 심볼 따라가는 중",
644
+ "🔍 그물 넓게 던지는 중",
645
+ "🧭 검색 범위 좁히는 중",
646
+ "🪤 검색 필터 거는 중",
647
+ "🔍 참조 따라 걸어가는 중",
648
+ "🔭 의심 가는 파일 확대",
649
+ "🕸 import 그래프 따라가는 중",
650
+ "🔍 바늘 찾는 중",
651
+ "🗺 위치 교차 참조 중",
652
+ "🧲 심볼 이름에 자석 대는 중",
653
+ "🕯 어두운 모듈에 촛불 비추는 중",
654
+ "🐕 단서 냄새 추적 중",
655
+ "🧐 잘 숨어 있는 호출자 찾는 중",
656
+ ],
657
+ "narration.reading": [
658
+ "📖 파일을 읽는 중",
659
+ "📖 컨텍스트 로딩",
660
+ "📖 기존 코드 확인 중",
661
+ "📚 일단 읽기부터",
662
+ "📖 주변 코드를 흡수 중",
663
+ "👀 관련 부분 훑는 중",
664
+ "📖 주석도 빼먹지 않고",
665
+ "📃 함수 페이지 넘기는 중",
666
+ "📖 '먼저 재기' 단계",
667
+ "🔍 사인하기 전에 계약서 읽는 중",
668
+ "📑 파일 따라잡는 중",
669
+ "📖 통째로 읽기 — 지름길 없이",
670
+ "🧠 머릿속에 모델 먼저 세우는 중",
671
+ "📖 끊긴 실 줍는 중",
672
+ "📕 이 모듈은 매뉴얼대로",
673
+ "🪟 함수의 창문 너머 보는 중",
674
+ "🛋 차분히 앉아서 읽는 중",
675
+ "📖 한 단락씩 찬찬히",
676
+ ],
677
+ "narration.thinking": [
678
+ "🧠 다음 수를 고민 중",
679
+ "🧠 옵션을 비교 중",
680
+ "🧠 가장 작은 정확한 길을 고르는 중",
681
+ "💭 곰곰이 굴려보는 중",
682
+ "🧠 점들을 연결 중",
683
+ "🧠 0.5초 정도 묵혀두는 중",
684
+ "🤔 지루한 옵션 고민 중 (보통 그게 이김)",
685
+ "🧠 트레이드오프 굴려보는 중",
686
+ "🪙 옵션 동전 던지는 중... 단, 근거와 함께",
687
+ "🧠 콜 그래프 머릿속에 그리는 중",
688
+ "🤨 행동 전에 '뭐가 깨지지?' 자문 중",
689
+ "🧠 머리속에서 먼저 시뮬레이션",
690
+ "💡 작은 아이디어 생기는 중",
691
+ "🧠 한 수로 좁히는 중",
692
+ "🪑 잠깐 디자인이랑 마주 앉기",
693
+ "🧠 '아무것도 안 하기'도 옵션, 고려 중",
694
+ "🤔 더 싼 수정 찾는 중",
695
+ "🧠 if X면 Y, 아니면 Z — 가지치기 중",
696
+ "🧠 옛날 비슷한 거 떠올리는 중",
697
+ "🤔 흠... 이거 트랩 있는 부분이지",
698
+ "🧠 정공법으로 갈지 우회로 갈지",
699
+ ],
700
+ "narration.bashing": [
701
+ "💻 쉘 단계 실행 중",
702
+ "💻 명령 실행 중",
703
+ "💻 스크립트 발사",
704
+ "🐚 쉘에 내려가는 중",
705
+ "💻 명령에 말을 시키는 중",
706
+ "📟 비트 파이핑 중",
707
+ "🖥 OS 한테 말 거는 중",
708
+ "💻 잠깐 서브프로세스",
709
+ "🛎 CLI 종 치는 중",
710
+ "🚀 명령 발사",
711
+ "🐚 /bin 에서 사랑을 담아",
712
+ "⌨️ 쉘 아웃",
713
+ "💻 비대화형 모드 가동",
714
+ ],
715
+ "narration.compacting": [
716
+ "🗑 흐름 유지하려고 오래된 컨텍스트 비우는 중",
717
+ "🗑 트랜스크립트 정리 — 멈추지 않고 계속 갑니다",
718
+ "🗑 옛 잡담 쓸어 담는 중",
719
+ "🗑 다음 구간 자리 마련 중",
720
+ "🗑 노이즈는 보내고 시그널만 남깁니다",
721
+ ],
722
+ "narration.writing": [
723
+ "📝 새 파일 작성 중",
724
+ "📝 새 파일 들어갑니다",
725
+ "📝 문서화 — 글로 남기는 중",
726
+ "📜 새 모듈 펼치는 중",
727
+ "📝 첫 초안 디스크로",
728
+ "🆕 따끈한 새 파일",
729
+ "📝 파일 스캐폴딩",
730
+ ],
731
+ "narration.testing": [
732
+ "🧪 테스트 실행 중",
733
+ "🧪 스위트에게 말을 시키는 중",
734
+ "🧪 테스트 러너 — 유일하게 정직한 리뷰어",
735
+ "🧪 테스트 돌리는 중",
736
+ "🧪 초록/빨강 판결 기다리는 중",
737
+ "🧪 테스트가 투표할 차례",
738
+ "🧪 진실에 CPU 좀 태우는 중",
739
+ ],
740
+ "narration.typechecking": [
741
+ "🧬 타입 체크 중",
742
+ "🧬 tsc 에게 일을 시키는 중",
743
+ "🧬 빨간 물결선 사냥 중",
744
+ "🧬 타입 좁히기 패스",
745
+ "🧬 컴파일러 비위 맞추는 중",
746
+ "🧬 타입 시스템과 한 판",
747
+ ],
748
+ "narration.linting": [
749
+ "🧹 린터 실행 중",
750
+ "🧹 스타일 정리 중",
751
+ "🧹 린터가 잔소리하게 두는 중",
752
+ "🧹 포매팅 먼지 털기",
753
+ "🧹 빠르게 광내는 중",
754
+ "🧹 규칙이 말하게 두기",
755
+ ],
756
+ "narration.git": [
757
+ "🌳 git 과 대화 중",
758
+ "🌳 트리 점검 중",
759
+ "🌳 히스토리 읽는 중",
760
+ "🌳 git 한 번 흘끔",
761
+ "🌳 blame 읽는 중",
762
+ "🌳 diff 점검 중",
763
+ "🌳 git 말 듣는 중",
764
+ ],
765
+ "narration.fetch": [
766
+ "🌐 웹에서 가져오는 중",
767
+ "🌐 문서 끌어오는 중",
768
+ "🌐 네트워크로 잠깐 외출",
769
+ "🌐 문서 보러 잠깐 다녀옴",
770
+ "🌐 업스트림 읽는 중",
771
+ "🛰 위성 링크로 웹에 접속",
772
+ ],
773
+ "narration.todo": [
774
+ "📋 할 일 보드 업데이트",
775
+ "📋 진행 표시 중",
776
+ "📋 리스트를 정직하게 유지",
777
+ "📋 체크 박스 채우기",
778
+ "📋 다음 항목으로",
779
+ "📋 태스크 정직하게 유지",
780
+ ],
781
+ "narration.diagnostics": [
782
+ "📡 LSP 진단 가져오는 중",
783
+ "📡 현재 에러 읽는 중",
784
+ "📡 언어 서버에게 어디 아픈지 물어보는 중",
785
+ "📡 LSP 가 말하길...",
786
+ "📡 물결선 청취 중",
787
+ "📡 IDE 가 이미 아는 거 읽는 중",
788
+ ],
789
+ "narration.context": [
790
+ "📦 프로젝트 컨텍스트 로딩",
791
+ "📦 관련 문서 모으는 중",
792
+ "📦 작업 셋 준비 중",
793
+ "📦 컨텍스트 비축 중",
794
+ "📦 관련 파일 모으는 중",
795
+ "📦 최소 유효 컨텍스트 로딩",
796
+ ],
797
+ "narration.verifyPass": [
798
+ "✅ 빌드 초록색 — 전진",
799
+ "✅ 검증 통과",
800
+ "✅ 테스트가 만족하네요",
801
+ "🟢 모든 체크 그린",
802
+ "✅ 깨끗하게 통과 — 다음",
803
+ "🎉 검증 클리어",
804
+ "✅ 빌드 멀쩡, 테스트 만족",
805
+ ],
806
+ "narration.verifyFail": [
807
+ "❌ 검증 실패 — 진단 중",
808
+ "❌ 빨간 빌드 — 어디가 물렸는지 찾는 중",
809
+ "❌ 테스트가 화났어요. 출력 읽는 중.",
810
+ "🔴 검증이 NO 라네요 — 실패 읽는 중",
811
+ "❌ 뭔가 물고 있어요 — 이빨 찾는 중",
812
+ "❌ 빨간불. 로그 펴는 중.",
813
+ ],
814
+ "narration.idle": [
815
+ "☕ 한 숨 돌리고 다시",
816
+ "🧘 잠시 멈춤 — 다음 수 고르는 중",
817
+ "🪑 문제와 잠깐 마주 앉아 있는 중",
818
+ "🌬 다음 수 전에 잠깐 호흡",
819
+ "🪑 잠깐 정비",
820
+ ],
821
+ "strategy.smallerPieces": "문제를 더 작은 단위로 쪼개세요. 한 번에 함수 하나씩 편집하고, 각 사이에 검증하세요.",
822
+ "strategy.differentFile": "에러가 실제로는 다른 파일에 있는지 확인하세요 — 진짜 원인은 상류일 수 있습니다.",
823
+ "strategy.readTest": "테스트 파일이 있으면 먼저 읽으세요 — 기대 동작이 거기에 드러나 있을 때가 많습니다.",
824
+ "strategy.checkImports": "import 를 확인하세요 — 누락되거나 잘못된 import 가 연쇄 에러의 흔한 원인입니다.",
825
+ "strategy.searchSimilar": "resolve-search 로 코드베이스 내 유사 패턴을 찾으세요.",
826
+ "strategy.rereadFile": "파일을 다시 차분히 읽으세요. 편집과 충돌하는 기존 코드를 놓쳤을 수 있습니다.",
827
+ "strategy.tryDifferent": "완전히 다른 접근을 시도하세요 — 마지막 변경을 되돌리고 다른 방법으로 고치세요.",
828
+ "strategy.useDiagnostics": "다음 편집 전에 resolve-diagnostics 로 현재 LSP 에러를 확인하세요.",
829
+ "strategy.suggestionLabel": "전략 제안",
830
+ },
831
+ };
832
+ /** Render a message in the requested locale. Picks a random variant if multiple are defined. */
833
+ export function t(key, locale, params = {}) {
834
+ const localeTable = MESSAGES[locale] ?? MESSAGES[LOCALE_FALLBACK];
835
+ const template = localeTable[key] ?? MESSAGES[LOCALE_FALLBACK][key];
836
+ const picked = Array.isArray(template)
837
+ ? template[nextVariantSeed() % template.length]
838
+ : template;
839
+ return typeof picked === "function" ? picked(params) : picked;
840
+ }
841
+ /** Compose `[agent] message` for session-time nudges. */
842
+ export function brandedMessage(agent, locale, key, params = {}) {
843
+ return `${brand(agent)} ${t(key, locale, params)}`;
844
+ }
845
+ /** Compose `[opencode-resolve] message` for plugin-level notices. */
846
+ export function pluginMessage(locale, key, params = {}) {
847
+ return `[${PLUGIN_BRAND}] ${t(key, locale, params)}`;
848
+ }
849
+ /**
850
+ * Render a context-bound message — always English, regardless of session locale.
851
+ * Use for everything that lands in LLM context (system reminders, tool definitions,
852
+ * end-of-turn reminders that become part of conversation history).
853
+ */
854
+ export function contextMessage(agent, key, params = {}) {
855
+ return `${brand(agent)} ${t(key, "en", params)}`;
856
+ }
857
+ /**
858
+ * Print a terminal-only narration. Uses session locale (Korean if configured).
859
+ * Does NOT enter LLM context — only the user sees it in the OpenCode UI/log.
860
+ * Free to be playful, varied, and bilingual.
861
+ */
862
+ export function narrate(state, key, params = {}) {
863
+ const line = `${brand(state.currentAgent)} ${t(key, state.locale, params)}`;
864
+ console.log(line);
865
+ }
866
+ /** All registered message keys, derived from the English table. */
867
+ export const ALL_MESSAGE_KEYS = Object.keys(MESSAGES.en);