@pollit/twin-dev-bot 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +415 -0
  3. package/bin/twindevbot.js +22 -0
  4. package/dist/action-payload-store.d.ts +22 -0
  5. package/dist/action-payload-store.js +54 -0
  6. package/dist/active-runners.d.ts +44 -0
  7. package/dist/active-runners.js +114 -0
  8. package/dist/channel-store.d.ts +16 -0
  9. package/dist/channel-store.js +91 -0
  10. package/dist/claude/active-runners.d.ts +44 -0
  11. package/dist/claude/active-runners.js +114 -0
  12. package/dist/claude/claude-runner.d.ts +57 -0
  13. package/dist/claude/claude-runner.js +210 -0
  14. package/dist/claude/session-manager.d.ts +62 -0
  15. package/dist/claude/session-manager.js +247 -0
  16. package/dist/claude-runner.d.ts +57 -0
  17. package/dist/claude-runner.js +210 -0
  18. package/dist/cli.d.ts +2 -0
  19. package/dist/cli.js +271 -0
  20. package/dist/config.d.ts +9 -0
  21. package/dist/config.js +49 -0
  22. package/dist/conversation-store.d.ts +53 -0
  23. package/dist/conversation-store.js +173 -0
  24. package/dist/core/config.d.ts +9 -0
  25. package/dist/core/config.js +49 -0
  26. package/dist/core/logger.d.ts +34 -0
  27. package/dist/core/logger.js +110 -0
  28. package/dist/core/paths.d.ts +11 -0
  29. package/dist/core/paths.js +18 -0
  30. package/dist/core/platform.d.ts +18 -0
  31. package/dist/core/platform.js +33 -0
  32. package/dist/daemon/index.d.ts +3 -0
  33. package/dist/daemon/index.js +14 -0
  34. package/dist/daemon/macos.d.ts +8 -0
  35. package/dist/daemon/macos.js +150 -0
  36. package/dist/daemon/types.d.ts +9 -0
  37. package/dist/daemon/types.js +1 -0
  38. package/dist/daemon/windows.d.ts +8 -0
  39. package/dist/daemon/windows.js +137 -0
  40. package/dist/handlers/claude-command.d.ts +2 -0
  41. package/dist/handlers/claude-command.js +634 -0
  42. package/dist/handlers/claude-runner-setup.d.ts +16 -0
  43. package/dist/handlers/claude-runner-setup.js +445 -0
  44. package/dist/handlers/index.d.ts +3 -0
  45. package/dist/handlers/index.js +3 -0
  46. package/dist/handlers/init-handlers.d.ts +2 -0
  47. package/dist/handlers/init-handlers.js +189 -0
  48. package/dist/handlers/question-handlers.d.ts +2 -0
  49. package/dist/handlers/question-handlers.js +835 -0
  50. package/dist/i18n/en.d.ts +150 -0
  51. package/dist/i18n/en.js +163 -0
  52. package/dist/i18n/index.d.ts +20 -0
  53. package/dist/i18n/index.js +31 -0
  54. package/dist/i18n/ko.d.ts +1 -0
  55. package/dist/i18n/ko.js +141 -0
  56. package/dist/logger.d.ts +34 -0
  57. package/dist/logger.js +110 -0
  58. package/dist/multi-select-state.d.ts +58 -0
  59. package/dist/multi-select-state.js +151 -0
  60. package/dist/paths.d.ts +11 -0
  61. package/dist/paths.js +18 -0
  62. package/dist/pending-questions.d.ts +53 -0
  63. package/dist/pending-questions.js +139 -0
  64. package/dist/platform.d.ts +18 -0
  65. package/dist/platform.js +33 -0
  66. package/dist/progress-tracker.d.ts +47 -0
  67. package/dist/progress-tracker.js +218 -0
  68. package/dist/question-blocks.d.ts +27 -0
  69. package/dist/question-blocks.js +235 -0
  70. package/dist/server.d.ts +1 -0
  71. package/dist/server.js +83 -0
  72. package/dist/session-manager.d.ts +62 -0
  73. package/dist/session-manager.js +247 -0
  74. package/dist/setup.d.ts +5 -0
  75. package/dist/setup.js +132 -0
  76. package/dist/slack/progress-tracker.d.ts +47 -0
  77. package/dist/slack/progress-tracker.js +218 -0
  78. package/dist/slack/question-blocks.d.ts +27 -0
  79. package/dist/slack/question-blocks.js +235 -0
  80. package/dist/stores/action-payload-store.d.ts +22 -0
  81. package/dist/stores/action-payload-store.js +54 -0
  82. package/dist/stores/channel-store.d.ts +16 -0
  83. package/dist/stores/channel-store.js +91 -0
  84. package/dist/stores/multi-select-state.d.ts +58 -0
  85. package/dist/stores/multi-select-state.js +151 -0
  86. package/dist/stores/pending-questions.d.ts +53 -0
  87. package/dist/stores/pending-questions.js +139 -0
  88. package/dist/stores/workspace-store.d.ts +27 -0
  89. package/dist/stores/workspace-store.js +160 -0
  90. package/dist/templates.d.ts +23 -0
  91. package/dist/templates.js +292 -0
  92. package/dist/types/claude-stream.d.ts +116 -0
  93. package/dist/types/claude-stream.js +3 -0
  94. package/dist/types/conversation.d.ts +16 -0
  95. package/dist/types/conversation.js +4 -0
  96. package/dist/types/index.d.ts +2 -0
  97. package/dist/types/index.js +2 -0
  98. package/dist/types/slack.d.ts +51 -0
  99. package/dist/types/slack.js +1 -0
  100. package/dist/utils/display-width.d.ts +8 -0
  101. package/dist/utils/display-width.js +33 -0
  102. package/dist/utils/safe-async.d.ts +6 -0
  103. package/dist/utils/safe-async.js +14 -0
  104. package/dist/utils/slack-message.d.ts +73 -0
  105. package/dist/utils/slack-message.js +220 -0
  106. package/dist/utils/slack-rate-limit.d.ts +5 -0
  107. package/dist/utils/slack-rate-limit.js +49 -0
  108. package/dist/workspace-store.d.ts +27 -0
  109. package/dist/workspace-store.js +160 -0
  110. package/package.json +51 -0
@@ -0,0 +1,150 @@
1
+ declare const _en: {
2
+ readonly "question.header": "Question";
3
+ readonly "question.headerCompleted": "Question (Answered)";
4
+ readonly "question.submitSelection": "Submit Selection";
5
+ readonly "question.textInput": "✏️ Custom Input";
6
+ readonly "question.currentSelection": "_Current selection: {{labels}}_";
7
+ readonly "question.selectHint": "_Select options then press 'Submit Selection'_";
8
+ readonly "question.truncatedOptions": "_Showing {{shown}} of {{total}} options. Use 'Custom Input' for others._";
9
+ readonly "modal.title": "Enter Answer";
10
+ readonly "modal.submit": "Submit";
11
+ readonly "modal.cancel": "Cancel";
12
+ readonly "modal.prompt": "Enter your answer:";
13
+ readonly "modal.label": "Answer";
14
+ readonly "modal.placeholder": "Type your answer...";
15
+ readonly "session.expired": "Session for *{{projectName}}* expired. Use `/twindevbot task` to start a new session.";
16
+ readonly "session.expiredUnknown": "Session expired. Use `/twindevbot task` to start a new session.";
17
+ readonly "session.notFound": "Session not found. Use `/twindevbot task` to start a new session.";
18
+ readonly "multiSelect.noneSelected": "Please select at least one option before pressing 'Submit Selection'.";
19
+ readonly "error.actionFailed": ":x: Something went wrong processing your action. Please try again.";
20
+ readonly "error.alreadyProcessing": ":hourglass: Already processing. Please wait for the current task to finish.";
21
+ readonly "error.resumeFailed": ":x: Your answer was received, but failed to resume Claude. Please send a new message to try again.";
22
+ readonly "command.autopilotNotice": "(Autopilot mode is active.\nA single thread message starts and completes the task.\nAll questions during the process will be auto-answered.\nFor best results, please provide detailed and clear instructions.)";
23
+ readonly "command.newUsage": ":warning: Usage:\n`/twindevbot new <directory> --empty`\n`/twindevbot new <directory> --template react`\n\nAvailable templates:\n{{templates}}";
24
+ readonly "command.newOptionsRequired": ":warning: Please specify an option:\n`/twindevbot new {{dirName}} --empty`\n`/twindevbot new {{dirName}} --template react`\n\nAvailable templates:\n{{templates}}";
25
+ readonly "command.invalidDirName": ":x: `{{dirName}}` is not a valid directory name. Only letters, numbers, hyphens (`-`), underscores (`_`), and dots (`.`) are allowed.";
26
+ readonly "command.dirAlreadyExists": ":x: Directory `{{dirName}}` already exists. Please choose a different name.";
27
+ readonly "command.errorOccurred": ":rotating_light: An error occurred, please try again.\n```{{error}}```";
28
+ readonly "command.emptyDirCreated": ":white_check_mark: Created empty directory `{{dirName}}`.";
29
+ readonly "command.templateNotFound": ":x: Template `{{templateKey}}` not found.\n\nAvailable templates:\n{{templates}}";
30
+ readonly "command.creatingProject": ":hourglass_flowing_sand: Creating `{{templateName}}` project...\nThis may take a moment. I'll let you know when it's done.\n`{{command}}`";
31
+ readonly "command.projectCreated": ":white_check_mark: `{{templateName}}` project created at `{{dirName}}`.";
32
+ readonly "command.autopilotInterruptConfirm": "Interrupting will stop autopilot mode. Would you like to proceed?";
33
+ readonly "command.autopilotInterruptYes": "Yes";
34
+ readonly "command.autopilotInterruptNo": "No";
35
+ readonly "command.autopilotInterruptedYes": "Autopilot mode stopped. Starting work on your message in normal mode.";
36
+ readonly "command.autopilotContinue": "Continuing in autopilot mode.";
37
+ readonly "command.normalInterruptConfirm": "The previous task is still in progress. Would you like to stop it and start a new task? (Not Recommended)";
38
+ readonly "command.normalInterruptYes": "Yes";
39
+ readonly "command.normalInterruptNo": "No";
40
+ readonly "command.normalInterruptedYes": "Previous task stopped. Starting new task now.";
41
+ readonly "command.normalInterruptContinue": "Continuing the previous task. Please send your new command after the current task completes.";
42
+ readonly "interrupt.taskAlreadyCompleted": "The previous task has already completed. Send a new message to start a new task.";
43
+ readonly "interrupt.payloadExpired": ":warning: Your previous message is no longer available. Please resend your instruction.";
44
+ readonly "command.baseDirNotFound": ":x: Project base directory (`{{baseDir}}`) not found.";
45
+ readonly "command.postFailed": "Failed to start the session. Please try again.";
46
+ readonly "command.didYouMean": "Unknown command. Did you mean `/twindevbot {{suggestion}}`?";
47
+ readonly "command.stopped": "Task cancelled.";
48
+ readonly "command.noActiveTask": "No active task to cancel.";
49
+ readonly "command.initSelectDir": "Select a working directory for this channel:";
50
+ readonly "command.initEmpty": ":open_file_folder: No directories found in `{{baseDir}}`.\nUse the button below to enter a path manually, or create a project with `/twindevbot new`.";
51
+ readonly "command.initCustomInput": "✏️ Enter path manually";
52
+ readonly "command.initSuccess": ":white_check_mark: `{{dirName}}` has been set as this channel's working directory.\nUse `/twindevbot task` to start working.";
53
+ readonly "command.initInvalidDir": ":x: Directory `{{directory}}` does not exist.";
54
+ readonly "command.initModalTitle": "Enter Directory";
55
+ readonly "command.initModalLabel": "Directory path";
56
+ readonly "command.initModalPlaceholder": "e.g. my-project or /absolute/path";
57
+ readonly "command.initModalDirNotExist": "Directory does not exist.";
58
+ readonly "command.taskNoDir": ":warning: No working directory configured for this channel.\nUse `/twindevbot init` to set one up.";
59
+ readonly "command.taskStarted": ":file_folder: `{{dirName}}` session started.\nContinue in the thread.";
60
+ readonly "command.taskSuccess": ":file_folder: Working on `{{dirName}}`.\nWhat would you like to work on?";
61
+ readonly "command.help": ":robot_face: *TwinDevBot Commands*\nDevelop with Claude Code from anywhere.\n\n:warning: *Before you start:* Invite the bot to this channel first (`/invite @TwinDevBot`). The bot must be a channel member to receive your messages.\n\n\n:wrench: *Set up channel*\n`/twindevbot init`\nSelect or enter a working directory for this channel.\n\n\n:rocket: *Start a task*\n`/twindevbot task`\n`/twindevbot task --autopilot`\nStart a new Claude session in the channel's working directory.\n\n\n:hammer_and_wrench: *Create project*\n`/twindevbot new <directory> --empty`\n`/twindevbot new <directory> --template <framework>`\n`/twindevbot new <directory> --template <framework> --autopilot`\n{{templates}}\n\n\n:octagonal_sign: *Stop running task*\n`/twindevbot stop`\nCancel the currently running Claude task.\n\n\n:bulb: *Notes*\n* Use `init` once per channel to link it to a project directory.\n* Use `task` to start a new task thread.\n* `--autopilot` mode: twindevbot automatically answers all questions and develops on its own.";
62
+ readonly "slack.answered": "Answer submitted";
63
+ readonly "slack.question": "Question";
64
+ readonly "progress.tool.Read": "Reading file";
65
+ readonly "progress.tool.Write": "Writing file";
66
+ readonly "progress.tool.Edit": "Editing file";
67
+ readonly "progress.tool.Bash": "Running command";
68
+ readonly "progress.tool.Grep": "Searching code";
69
+ readonly "progress.tool.Glob": "Finding files";
70
+ readonly "progress.tool.Task": "Processing subtask";
71
+ readonly "progress.tool.WebSearch": "Searching the web";
72
+ readonly "progress.tool.WebFetch": "Fetching web page";
73
+ readonly "progress.tool.NotebookEdit": "Editing notebook";
74
+ readonly "progress.tool.default": "Running tool";
75
+ readonly "progress.working": ":gear: Starting work...";
76
+ readonly "progress.completed": ":white_check_mark: Completed ({{elapsed}})";
77
+ readonly "progress.error": ":x: Error occurred: {{error}}";
78
+ readonly "progress.planApproved": ":thumbsup: Plan approved. Starting implementation...";
79
+ readonly "progress.autopilotContinue": ":robot_face: Auto-responded, continuing... ({{elapsed}})";
80
+ readonly "progress.askUser": ":raised_hand: Question sent. Waiting for answer.";
81
+ readonly "progress.lessThanOneSecond": "<1s";
82
+ readonly "progress.seconds": "{{n}}s";
83
+ readonly "progress.minutesSeconds": "{{m}}m {{s}}s";
84
+ readonly "runner.questionArrived": "Claude Code question arrived";
85
+ readonly "runner.autopilotAnswer": ":robot_face: Autopilot: auto-selected {{answer}}";
86
+ readonly "runner.errorOccurred": "Error: {{error}}";
87
+ readonly "runner.claudeNotFound": "Claude CLI is not installed or not found in PATH. Please install it with `npm install -g @anthropic-ai/claude-code`.";
88
+ readonly "runner.exitError": ":x: Claude process exited abnormally (code: {{code}}). Check logs for details.";
89
+ readonly "runner.autopilotResumeFailed": ":x: Autopilot: Failed to resume Claude.";
90
+ readonly "runner.autopilotNoSession": ":x: Autopilot: No session ID available, cannot resume.";
91
+ readonly "runner.emptyQuestions": ":warning: Claude sent a question with no content. The session has been terminated. Please send a new message to retry.";
92
+ readonly "runner.inactivityTimeout": ":warning: Claude process was terminated after {{minutes}} minutes of inactivity. Send a new message to restart.";
93
+ readonly "runner.planApproved": "Plan approved. Start implementing.";
94
+ readonly "template.frontend": "*Frontend:* ";
95
+ readonly "template.backend": "*Backend:* ";
96
+ readonly "cli.description": "Develop with Claude Code from anywhere.";
97
+ readonly "cli.usage": "Usage:";
98
+ readonly "cli.commands": "Commands:";
99
+ readonly "cli.cmd.start": "Start server (foreground)";
100
+ readonly "cli.cmd.startDaemon": "Register and start as background service (macOS launchd / Windows Task Scheduler)";
101
+ readonly "cli.cmd.stop": "Stop and unregister background service";
102
+ readonly "cli.cmd.status": "Check background service status";
103
+ readonly "cli.cmd.show": "Show saved sessions";
104
+ readonly "cli.cmd.clear": "Delete data files (sessions.json, workspaces.json)";
105
+ readonly "cli.cmd.help": "Show help";
106
+ readonly "cli.notes": "Notes:";
107
+ readonly "cli.notes.daemon": "twindevbot must be running for remote work. Use --daemon so you don't have to restart it every time.";
108
+ readonly "cli.notes.errorLog": "If something seems wrong with the twindevbot server, check the error log.";
109
+ readonly "cli.warning.title": "WARNING";
110
+ readonly "cli.warning.text": "twindevbot launches claude with the --dangerously-skip-permissions flag. Only use twindevbot if you fully understand what this means. The source code is fully open on GitHub. No one is responsible for any incidents caused by using twindevbot.";
111
+ readonly "cli.setup.banner": "twindevbot server setup";
112
+ readonly "cli.setup.promptAppToken": "Enter your SLACK_APP_TOKEN (xapp-...)";
113
+ readonly "cli.setup.promptBotToken": "Enter your SLACK_BOT_TOKEN (xoxb-...)";
114
+ readonly "cli.setup.promptBaseDir": "Enter the parent directory path for project directories";
115
+ readonly "cli.setup.required": "This field is required.";
116
+ readonly "cli.setup.saved": "Configuration saved: {{path}}";
117
+ readonly "cli.setup.startMessage": "Starting server.\n Open Slack and type /twindevbot to get started.";
118
+ readonly "cli.setup.startDaemonMessage": "Starting server as a background service so it stays running.\n Open Slack and type /twindevbot to get started.";
119
+ readonly "cli.daemon.plistCreated": "Created launchd plist: {{path}}";
120
+ readonly "cli.daemon.started": "Background service started successfully.";
121
+ readonly "cli.daemon.failedToStart": "Failed to start service:";
122
+ readonly "cli.daemon.notInstalled": "Background service is not installed.";
123
+ readonly "cli.daemon.stopped": "Background service stopped and unregistered.";
124
+ readonly "cli.status.notInstalled": "Background service: not installed";
125
+ readonly "cli.status.notInstalledHint": "Run 'twindevbot start --daemon' to install.";
126
+ readonly "cli.status.running": "Background service: running (PID {{pid}})";
127
+ readonly "cli.status.registered": "Background service: registered";
128
+ readonly "cli.status.notRunning": "Background service: installed but not running";
129
+ readonly "cli.status.checkLogs": "It may have crashed. Check logs:";
130
+ readonly "cli.daemonUnsupportedPlatform": "Daemon features (start --daemon, stop, status) are supported on macOS and Windows only. Current platform: {{platform}}";
131
+ readonly "cli.daemon.taskCreated": "Created Windows scheduled task: {{name}}";
132
+ readonly "cli.unknownCommand": "Unknown command: {{command}}";
133
+ readonly "cli.show.title": "twindevbot sessions ({{count}})";
134
+ readonly "cli.show.sessionCount": "({{count}} sessions)";
135
+ readonly "cli.show.noSessions": "No saved sessions found.";
136
+ readonly "cli.show.parseError": "Failed to parse sessions.json.";
137
+ readonly "cli.show.daysAgo": "{{n}}d ago";
138
+ readonly "cli.show.hoursAgo": "{{n}}h ago";
139
+ readonly "cli.show.minutesAgo": "{{n}}m ago";
140
+ readonly "cli.show.justNow": "just now";
141
+ readonly "cli.clear.header": "Files to delete:";
142
+ readonly "cli.clear.confirm": "Delete the above files?";
143
+ readonly "cli.clear.noData": "No data files to delete.";
144
+ readonly "cli.clear.cancelled": "Cancelled.";
145
+ readonly "cli.clear.done": "βœ” Data files deleted.";
146
+ readonly "cli.clear.daemonRunning": "⚠ The daemon is currently running. Please stop it first with `twindevbot stop` before clearing data.";
147
+ };
148
+ export type TranslationKey = keyof typeof _en;
149
+ export declare const en: Record<TranslationKey, string>;
150
+ export {};
@@ -0,0 +1,163 @@
1
+ const _en = {
2
+ // question-blocks.ts
3
+ "question.header": "Question",
4
+ "question.headerCompleted": "Question (Answered)",
5
+ "question.submitSelection": "Submit Selection",
6
+ "question.textInput": "✏️ Custom Input",
7
+ "question.currentSelection": "_Current selection: {{labels}}_",
8
+ "question.selectHint": "_Select options then press 'Submit Selection'_",
9
+ "question.truncatedOptions": "_Showing {{shown}} of {{total}} options. Use 'Custom Input' for others._",
10
+ // question-handlers.ts (modal)
11
+ "modal.title": "Enter Answer",
12
+ "modal.submit": "Submit",
13
+ "modal.cancel": "Cancel",
14
+ "modal.prompt": "Enter your answer:",
15
+ "modal.label": "Answer",
16
+ "modal.placeholder": "Type your answer...",
17
+ // question-handlers.ts (session)
18
+ "session.expired": "Session for *{{projectName}}* expired. Use `/twindevbot task` to start a new session.",
19
+ "session.expiredUnknown": "Session expired. Use `/twindevbot task` to start a new session.",
20
+ "session.notFound": "Session not found. Use `/twindevbot task` to start a new session.",
21
+ "multiSelect.noneSelected": "Please select at least one option before pressing 'Submit Selection'.",
22
+ "error.actionFailed": ":x: Something went wrong processing your action. Please try again.",
23
+ "error.alreadyProcessing": ":hourglass: Already processing. Please wait for the current task to finish.",
24
+ "error.resumeFailed": ":x: Your answer was received, but failed to resume Claude. Please send a new message to try again.",
25
+ // claude-command.ts
26
+ "command.autopilotNotice": "(Autopilot mode is active.\nA single thread message starts and completes the task.\nAll questions during the process will be auto-answered.\nFor best results, please provide detailed and clear instructions.)",
27
+ "command.newUsage": ":warning: Usage:\n`/twindevbot new <directory> --empty`\n`/twindevbot new <directory> --template react`\n\nAvailable templates:\n{{templates}}",
28
+ "command.newOptionsRequired": ":warning: Please specify an option:\n`/twindevbot new {{dirName}} --empty`\n`/twindevbot new {{dirName}} --template react`\n\nAvailable templates:\n{{templates}}",
29
+ "command.invalidDirName": ":x: `{{dirName}}` is not a valid directory name. Only letters, numbers, hyphens (`-`), underscores (`_`), and dots (`.`) are allowed.",
30
+ "command.dirAlreadyExists": ":x: Directory `{{dirName}}` already exists. Please choose a different name.",
31
+ "command.errorOccurred": ":rotating_light: An error occurred, please try again.\n```{{error}}```",
32
+ "command.emptyDirCreated": ":white_check_mark: Created empty directory `{{dirName}}`.",
33
+ "command.templateNotFound": ":x: Template `{{templateKey}}` not found.\n\nAvailable templates:\n{{templates}}",
34
+ "command.creatingProject": ":hourglass_flowing_sand: Creating `{{templateName}}` project...\nThis may take a moment. I'll let you know when it's done.\n`{{command}}`",
35
+ "command.projectCreated": ":white_check_mark: `{{templateName}}` project created at `{{dirName}}`.",
36
+ "command.autopilotInterruptConfirm": "Interrupting will stop autopilot mode. Would you like to proceed?",
37
+ "command.autopilotInterruptYes": "Yes",
38
+ "command.autopilotInterruptNo": "No",
39
+ "command.autopilotInterruptedYes": "Autopilot mode stopped. Starting work on your message in normal mode.",
40
+ "command.autopilotContinue": "Continuing in autopilot mode.",
41
+ "command.normalInterruptConfirm": "The previous task is still in progress. Would you like to stop it and start a new task? (Not Recommended)",
42
+ "command.normalInterruptYes": "Yes",
43
+ "command.normalInterruptNo": "No",
44
+ "command.normalInterruptedYes": "Previous task stopped. Starting new task now.",
45
+ "command.normalInterruptContinue": "Continuing the previous task. Please send your new command after the current task completes.",
46
+ "interrupt.taskAlreadyCompleted": "The previous task has already completed. Send a new message to start a new task.",
47
+ "interrupt.payloadExpired": ":warning: Your previous message is no longer available. Please resend your instruction.",
48
+ "command.baseDirNotFound": ":x: Project base directory (`{{baseDir}}`) not found.",
49
+ "command.postFailed": "Failed to start the session. Please try again.",
50
+ "command.didYouMean": "Unknown command. Did you mean `/twindevbot {{suggestion}}`?",
51
+ "command.stopped": "Task cancelled.",
52
+ "command.noActiveTask": "No active task to cancel.",
53
+ // init μ»€λ§¨λ“œ
54
+ "command.initSelectDir": "Select a working directory for this channel:",
55
+ "command.initEmpty": ":open_file_folder: No directories found in `{{baseDir}}`.\nUse the button below to enter a path manually, or create a project with `/twindevbot new`.",
56
+ "command.initCustomInput": "✏️ Enter path manually",
57
+ "command.initSuccess": ":white_check_mark: `{{dirName}}` has been set as this channel's working directory.\nUse `/twindevbot task` to start working.",
58
+ "command.initInvalidDir": ":x: Directory `{{directory}}` does not exist.",
59
+ "command.initModalTitle": "Enter Directory",
60
+ "command.initModalLabel": "Directory path",
61
+ "command.initModalPlaceholder": "e.g. my-project or /absolute/path",
62
+ "command.initModalDirNotExist": "Directory does not exist.",
63
+ // task μ»€λ§¨λ“œ
64
+ "command.taskNoDir": ":warning: No working directory configured for this channel.\nUse `/twindevbot init` to set one up.",
65
+ "command.taskStarted": ":file_folder: `{{dirName}}` session started.\nContinue in the thread.",
66
+ "command.taskSuccess": ":file_folder: Working on `{{dirName}}`.\nWhat would you like to work on?",
67
+ // help
68
+ "command.help": ":robot_face: *TwinDevBot Commands*\nDevelop with Claude Code from anywhere.\n\n:warning: *Before you start:* Invite the bot to this channel first (`/invite @TwinDevBot`). The bot must be a channel member to receive your messages.\n\n\n:wrench: *Set up channel*\n`/twindevbot init`\nSelect or enter a working directory for this channel.\n\n\n:rocket: *Start a task*\n`/twindevbot task`\n`/twindevbot task --autopilot`\nStart a new Claude session in the channel's working directory.\n\n\n:hammer_and_wrench: *Create project*\n`/twindevbot new <directory> --empty`\n`/twindevbot new <directory> --template <framework>`\n`/twindevbot new <directory> --template <framework> --autopilot`\n{{templates}}\n\n\n:octagonal_sign: *Stop running task*\n`/twindevbot stop`\nCancel the currently running Claude task.\n\n\n:bulb: *Notes*\n* Use `init` once per channel to link it to a project directory.\n* Use `task` to start a new task thread.\n* `--autopilot` mode: twindevbot automatically answers all questions and develops on its own.",
69
+ // slack-message.ts
70
+ "slack.answered": "Answer submitted",
71
+ "slack.question": "Question",
72
+ // progress-tracker.ts
73
+ "progress.tool.Read": "Reading file",
74
+ "progress.tool.Write": "Writing file",
75
+ "progress.tool.Edit": "Editing file",
76
+ "progress.tool.Bash": "Running command",
77
+ "progress.tool.Grep": "Searching code",
78
+ "progress.tool.Glob": "Finding files",
79
+ "progress.tool.Task": "Processing subtask",
80
+ "progress.tool.WebSearch": "Searching the web",
81
+ "progress.tool.WebFetch": "Fetching web page",
82
+ "progress.tool.NotebookEdit": "Editing notebook",
83
+ "progress.tool.default": "Running tool",
84
+ "progress.working": ":gear: Starting work...",
85
+ "progress.completed": ":white_check_mark: Completed ({{elapsed}})",
86
+ "progress.error": ":x: Error occurred: {{error}}",
87
+ "progress.planApproved": ":thumbsup: Plan approved. Starting implementation...",
88
+ "progress.autopilotContinue": ":robot_face: Auto-responded, continuing... ({{elapsed}})",
89
+ "progress.askUser": ":raised_hand: Question sent. Waiting for answer.",
90
+ "progress.lessThanOneSecond": "<1s",
91
+ "progress.seconds": "{{n}}s",
92
+ "progress.minutesSeconds": "{{m}}m {{s}}s",
93
+ // claude-runner-setup.ts
94
+ "runner.questionArrived": "Claude Code question arrived",
95
+ "runner.autopilotAnswer": ":robot_face: Autopilot: auto-selected {{answer}}",
96
+ "runner.errorOccurred": "Error: {{error}}",
97
+ "runner.claudeNotFound": "Claude CLI is not installed or not found in PATH. Please install it with `npm install -g @anthropic-ai/claude-code`.",
98
+ "runner.exitError": ":x: Claude process exited abnormally (code: {{code}}). Check logs for details.",
99
+ "runner.autopilotResumeFailed": ":x: Autopilot: Failed to resume Claude.",
100
+ "runner.autopilotNoSession": ":x: Autopilot: No session ID available, cannot resume.",
101
+ "runner.emptyQuestions": ":warning: Claude sent a question with no content. The session has been terminated. Please send a new message to retry.",
102
+ "runner.inactivityTimeout": ":warning: Claude process was terminated after {{minutes}} minutes of inactivity. Send a new message to restart.",
103
+ "runner.planApproved": "Plan approved. Start implementing.",
104
+ // templates.ts
105
+ "template.frontend": "*Frontend:* ",
106
+ "template.backend": "*Backend:* ",
107
+ // cli.ts
108
+ "cli.description": "Develop with Claude Code from anywhere.",
109
+ "cli.usage": "Usage:",
110
+ "cli.commands": "Commands:",
111
+ "cli.cmd.start": "Start server (foreground)",
112
+ "cli.cmd.startDaemon": "Register and start as background service (macOS launchd / Windows Task Scheduler)",
113
+ "cli.cmd.stop": "Stop and unregister background service",
114
+ "cli.cmd.status": "Check background service status",
115
+ "cli.cmd.show": "Show saved sessions",
116
+ "cli.cmd.clear": "Delete data files (sessions.json, workspaces.json)",
117
+ "cli.cmd.help": "Show help",
118
+ "cli.notes": "Notes:",
119
+ "cli.notes.daemon": "twindevbot must be running for remote work. Use --daemon so you don't have to restart it every time.",
120
+ "cli.notes.errorLog": "If something seems wrong with the twindevbot server, check the error log.",
121
+ "cli.warning.title": "WARNING",
122
+ "cli.warning.text": "twindevbot launches claude with the --dangerously-skip-permissions flag. Only use twindevbot if you fully understand what this means. The source code is fully open on GitHub. No one is responsible for any incidents caused by using twindevbot.",
123
+ // setup.ts
124
+ "cli.setup.banner": "twindevbot server setup",
125
+ "cli.setup.promptAppToken": "Enter your SLACK_APP_TOKEN (xapp-...)",
126
+ "cli.setup.promptBotToken": "Enter your SLACK_BOT_TOKEN (xoxb-...)",
127
+ "cli.setup.promptBaseDir": "Enter the parent directory path for project directories",
128
+ "cli.setup.required": "This field is required.",
129
+ "cli.setup.saved": "Configuration saved: {{path}}",
130
+ "cli.setup.startMessage": "Starting server.\n Open Slack and type /twindevbot to get started.",
131
+ "cli.setup.startDaemonMessage": "Starting server as a background service so it stays running.\n Open Slack and type /twindevbot to get started.",
132
+ "cli.daemon.plistCreated": "Created launchd plist: {{path}}",
133
+ "cli.daemon.started": "Background service started successfully.",
134
+ "cli.daemon.failedToStart": "Failed to start service:",
135
+ "cli.daemon.notInstalled": "Background service is not installed.",
136
+ "cli.daemon.stopped": "Background service stopped and unregistered.",
137
+ "cli.status.notInstalled": "Background service: not installed",
138
+ "cli.status.notInstalledHint": "Run 'twindevbot start --daemon' to install.",
139
+ "cli.status.running": "Background service: running (PID {{pid}})",
140
+ "cli.status.registered": "Background service: registered",
141
+ "cli.status.notRunning": "Background service: installed but not running",
142
+ "cli.status.checkLogs": "It may have crashed. Check logs:",
143
+ "cli.daemonUnsupportedPlatform": "Daemon features (start --daemon, stop, status) are supported on macOS and Windows only. Current platform: {{platform}}",
144
+ "cli.daemon.taskCreated": "Created Windows scheduled task: {{name}}",
145
+ "cli.unknownCommand": "Unknown command: {{command}}",
146
+ // cli.ts - show
147
+ "cli.show.title": "twindevbot sessions ({{count}})",
148
+ "cli.show.sessionCount": "({{count}} sessions)",
149
+ "cli.show.noSessions": "No saved sessions found.",
150
+ "cli.show.parseError": "Failed to parse sessions.json.",
151
+ "cli.show.daysAgo": "{{n}}d ago",
152
+ "cli.show.hoursAgo": "{{n}}h ago",
153
+ "cli.show.minutesAgo": "{{n}}m ago",
154
+ "cli.show.justNow": "just now",
155
+ // cli.ts - clear
156
+ "cli.clear.header": "Files to delete:",
157
+ "cli.clear.confirm": "Delete the above files?",
158
+ "cli.clear.noData": "No data files to delete.",
159
+ "cli.clear.cancelled": "Cancelled.",
160
+ "cli.clear.done": "βœ” Data files deleted.",
161
+ "cli.clear.daemonRunning": "⚠ The daemon is currently running. Please stop it first with `twindevbot stop` before clearing data.",
162
+ };
163
+ export const en = _en;
@@ -0,0 +1,20 @@
1
+ import { type TranslationKey } from "./en.js";
2
+ export type { TranslationKey };
3
+ type Locale = "en";
4
+ /**
5
+ * Initialize locale. Currently only "en" is supported.
6
+ *
7
+ * To add a new locale:
8
+ * 1. Create a new translation file (e.g. ko.ts).
9
+ * 2. Extend the Locale union type.
10
+ * 3. Add parsing logic here to detect the locale (e.g. from an env var).
11
+ */
12
+ export declare function initLocale(): void;
13
+ export declare function getCurrentLocale(): Locale;
14
+ /**
15
+ * Look up a translation key for the current locale.
16
+ * Replaces {{param}} placeholders with values from params.
17
+ *
18
+ * Fallback chain: current locale -> en -> raw key string.
19
+ */
20
+ export declare function t(key: TranslationKey, params?: Record<string, string | number>): string;
@@ -0,0 +1,31 @@
1
+ import { en } from "./en.js";
2
+ const translations = { en };
3
+ let currentLocale = "en";
4
+ /**
5
+ * Initialize locale. Currently only "en" is supported.
6
+ *
7
+ * To add a new locale:
8
+ * 1. Create a new translation file (e.g. ko.ts).
9
+ * 2. Extend the Locale union type.
10
+ * 3. Add parsing logic here to detect the locale (e.g. from an env var).
11
+ */
12
+ export function initLocale() {
13
+ // no-op while only "en" is supported
14
+ }
15
+ export function getCurrentLocale() {
16
+ return currentLocale;
17
+ }
18
+ /**
19
+ * Look up a translation key for the current locale.
20
+ * Replaces {{param}} placeholders with values from params.
21
+ *
22
+ * Fallback chain: current locale -> en -> raw key string.
23
+ */
24
+ export function t(key, params) {
25
+ const map = translations[currentLocale];
26
+ let text = map[key] ?? translations.en[key] ?? key;
27
+ if (params) {
28
+ text = text.replace(/\{\{(\w+)\}\}/g, (match, k) => k in params ? String(params[k]) : match);
29
+ }
30
+ return text;
31
+ }
@@ -0,0 +1 @@
1
+ export declare const ko: Record<string, string>;
@@ -0,0 +1,141 @@
1
+ export const ko = {
2
+ // question-blocks.ts
3
+ "question.header": "질문",
4
+ "question.headerCompleted": "질문 (λ‹΅λ³€ μ™„λ£Œ)",
5
+ "question.submitSelection": "선택 μ™„λ£Œ",
6
+ "question.textInput": "✏️ 직접 μž…λ ₯",
7
+ "question.currentSelection": "_ν˜„μž¬ 선택: {{labels}}_",
8
+ "question.selectHint": "_μ˜΅μ…˜μ„ μ„ νƒν•œ ν›„ '선택 μ™„λ£Œ' λ²„νŠΌμ„ λˆŒλŸ¬μ£Όμ„Έμš”_",
9
+ "question.truncatedOptions": "_{{total}}개 쀑 {{shown}}개 μ˜΅μ…˜λ§Œ ν‘œμ‹œλ©λ‹ˆλ‹€. λ‚˜λ¨Έμ§€λŠ” '직접 μž…λ ₯'을 μ΄μš©ν•΄μ£Όμ„Έμš”._",
10
+ // question-handlers.ts (modal)
11
+ "modal.title": "λ‹΅λ³€ μž…λ ₯",
12
+ "modal.submit": "전솑",
13
+ "modal.cancel": "μ·¨μ†Œ",
14
+ "modal.prompt": "닡변을 μž…λ ₯ν•˜μ„Έμš”:",
15
+ "modal.label": "λ‹΅λ³€",
16
+ "modal.placeholder": "닡변을 μž…λ ₯ν•˜μ„Έμš”...",
17
+ // question-handlers.ts (session)
18
+ "session.expired": "μ„Έμ…˜μ΄ λ§Œλ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€. `/twindevbot goto ν”„λ‘œμ νŠΈλͺ…`으둜 μƒˆ μ„Έμ…˜μ„ μ‹œμž‘ν•˜μ„Έμš”.",
19
+ "multiSelect.noneSelected": "μ˜΅μ…˜μ„ ν•˜λ‚˜ 이상 μ„ νƒν•œ ν›„ '선택 μ™„λ£Œ' λ²„νŠΌμ„ λˆŒλŸ¬μ£Όμ„Έμš”.",
20
+ // claude-command.ts
21
+ "command.gotoUsage": ":warning: μ‚¬μš©λ²•: `/twindevbot goto <디렉토리λͺ…>`\n예: `/twindevbot goto my-project`",
22
+ "command.dirNotFound": ":x: `{{dirName}}` 디렉토리가 μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.\n`/twindevbot new {{dirName}} --empty` λ˜λŠ” `/twindevbot new {{dirName}} --template <templateName>` λͺ…령을 λ¨Όμ € μ‹€ν–‰ν•΄μ£Όμ„Έμš”.\n\nμ‚¬μš© κ°€λŠ₯ν•œ ν…œν”Œλ¦Ώ:\n{{templates}}",
23
+ "command.sessionStarted": ":file_folder: `{{dirName}}` λ””λ ‰ν† λ¦¬μ—μ„œ μƒˆ μ„Έμ…˜μ΄ μ‹œμž‘λμŠ΅λ‹ˆλ‹€.\nμŠ€λ ˆλ“œμ—μ„œ μž‘μ—…μ„ μ§„ν–‰ν•˜μ„Έμš”.",
24
+ "command.gotoSuccess": ":file_folder: `{{dirName}}`(으)둜 μ΄λ™ν–ˆμŠ΅λ‹ˆλ‹€.\n무슨 μž‘μ—…μ„ μ‹œμž‘ν• κΉŒμš”?",
25
+ "command.autopilotNotice": "(ν˜„μž¬ autopilot λͺ¨λ“œμž…λ‹ˆλ‹€.\nν•œλ²ˆμ˜ μŠ€λ ˆλ“œ λ©”μ‹œμ§€ μž…λ ₯만으둜 μž‘μ—…μ΄ μ‹œμž‘~μ™„λ£Œλ˜κ³ \nμž‘μ—… 도쀑 λ°œμƒν•˜λŠ” λͺ¨λ“  μ§ˆλ¬Έλ“€μ€ μžλ™ 응닡 μ²˜λ¦¬λ©λ‹ˆλ‹€.\nλ”°λΌμ„œ 쒋은 κ²°κ³Όλ₯Ό μœ„ν•΄ μ΅œλŒ€ν•œ μΉœμ ˆν•˜κ³  μžμ„Έν•œ λ‚΄μš©μ˜ λ©”μ‹œμ§€λ‘œ\nλͺ…령을 λ‚΄λ €μ£Όμ„Έμš”.)",
26
+ "command.newUsage": ":warning: μ‚¬μš©λ²•:\n`/twindevbot new <디렉토리λͺ…> --empty`\n`/twindevbot new <디렉토리λͺ…> --template <templateName>`\n\nμ‚¬μš© κ°€λŠ₯ν•œ ν…œν”Œλ¦Ώ:\n{{templates}}",
27
+ "command.newOptionsRequired": ":warning: μ˜΅μ…˜μ„ μ§€μ •ν•΄μ£Όμ„Έμš”:\n`/twindevbot new {{dirName}} --empty`\n`/twindevbot new {{dirName}} --template react`\n\nμ‚¬μš© κ°€λŠ₯ν•œ ν…œν”Œλ¦Ώ:\n{{templates}}",
28
+ "command.invalidDirName": ":x: `{{dirName}}`은(λŠ”) μœ νš¨ν•˜μ§€ μ•Šμ€ 디렉토리λͺ…μž…λ‹ˆλ‹€. 영문, 숫자, ν•˜μ΄ν”ˆ(`-`), 밑쀄(`_`), λ§ˆμΉ¨ν‘œ(`.`)만 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.",
29
+ "command.dirAlreadyExists": ":x: `{{dirName}}` 디렉토리가 이미 μ‘΄μž¬ν•©λ‹ˆλ‹€. λ‹€λ₯Έ μ΄λ¦„μœΌλ‘œ 디렉토리λ₯Ό μƒμ„±ν•˜μ„Έμš”.",
30
+ "command.errorOccurred": ":rotating_light: 이런 μ—λŸ¬κ°€ λ°œμƒν–ˆμ–΄μš”, λ‹€μ‹œ μ‹œλ„ν•΄λ³΄μ„Έμš”.\n```{{error}}```",
31
+ "command.emptyDirCreated": ":white_check_mark: `{{dirName}}` 빈 디렉토리λ₯Ό μƒμ„±ν–ˆμŠ΅λ‹ˆλ‹€.",
32
+ "command.templateNotFound": ":x: `{{templateKey}}` ν…œν”Œλ¦Ώμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.\n\nμ‚¬μš© κ°€λŠ₯ν•œ ν…œν”Œλ¦Ώ:\n{{templates}}",
33
+ "command.creatingProject": ":hourglass_flowing_sand: `{{templateName}}` ν”„λ‘œμ νŠΈλ₯Ό 생성 μ€‘μž…λ‹ˆλ‹€...\nμ‹œκ°„μ΄ 쑰금 걸릴 수 μžˆμŠ΅λ‹ˆλ‹€. λͺ¨λ‘ μ™„λ£Œλ˜λ©΄ λ‹€μ‹œ λ‹΅λ³€λ“œλ¦΄κ²Œμš”.\n`{{command}}`",
34
+ "command.projectCreated": ":white_check_mark: `{{templateName}}` ν”„λ‘œμ νŠΈκ°€ `{{dirName}}`에 μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.",
35
+ "command.autopilotInterruptConfirm": "쀑간에 κ°œμž…ν•˜μ‹œλ©΄ autopilot λͺ¨λ“œλŠ” μ€‘λ‹¨λ©λ‹ˆλ‹€. κ·Έλ ‡κ²Œ ν• κΉŒμš”?",
36
+ "command.autopilotInterruptYes": "λ„€",
37
+ "command.autopilotInterruptNo": "μ•„λ‹ˆμš”",
38
+ "command.autopilotInterruptedYes": "autopilot λͺ¨λ“œλ₯Ό μ€‘λ‹¨ν•©λ‹ˆλ‹€. λ§μ”€ν•˜μ‹  λ‚΄μš©μ„ 일반 λͺ¨λ“œλ‘œ μž‘μ—… μ‹œμž‘ν•©λ‹ˆλ‹€.",
39
+ "command.autopilotContinue": "autopilot λͺ¨λ“œλ‘œ 계속 μ§„ν–‰ν•©λ‹ˆλ‹€.",
40
+ "command.normalInterruptConfirm": "아직 μž‘μ—…μ΄ μ™„λ£Œλ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. 이전 μž‘μ—…μ„ μ€‘λ‹¨ν•˜κ³  λ°”λ‘œ μƒˆ μž‘μ—…μ„ μ‹œμž‘ν• κΉŒμš”? (Not Recommended)",
41
+ "command.normalInterruptYes": "예",
42
+ "command.normalInterruptNo": "μ•„λ‹ˆμ˜€",
43
+ "command.normalInterruptedYes": "이전 μž‘μ—…μ„ μ€‘λ‹¨ν–ˆκ³  μƒˆ μž‘μ—…μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.",
44
+ "command.normalInterruptContinue": "이전 μž‘μ—…μ„ 계속 μ§„ν–‰ν•©λ‹ˆλ‹€, μƒˆ λͺ…령은 μž‘μ—… μ™„λ£Œ 후에 λ‚΄λ €μ£Όμ„Έμš”.",
45
+ "command.listResult": ":file_folder: `{{baseDir}}`에 ν˜„μž¬ λ‹€μŒκ³Ό 같은 디렉토리듀이 μžˆμŠ΅λ‹ˆλ‹€.\n\n{{dirList}}\n\n`/twindevbot goto <디렉토리λͺ…>`으둜 μž‘μ—…μ„ μ‹œμž‘ν•΄λ³΄μ„Έμš”.",
46
+ "command.listEmpty": ":open_file_folder: `{{baseDir}}`에 ν˜„μž¬ 디렉토리가 μ—†μŠ΅λ‹ˆλ‹€.\n`/twindevbot new <디렉토리λͺ…> --empty` λ˜λŠ” `/twindevbot new <디렉토리λͺ…> --template <templateName>`으둜 ν”„λ‘œμ νŠΈλ₯Ό μƒμ„±ν•΄λ³΄μ„Έμš”.",
47
+ "command.baseDirNotFound": ":x: ν”„λ‘œμ νŠΈ λΆ€λͺ¨ 디렉토리(`{{baseDir}}`)λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.",
48
+ "command.help": ":robot_face: *TwinDevBot λͺ…λ Ήμ–΄*\nμ–Έμ œ μ–΄λ””μ„œλ“  Claude Code둜 κ°œλ°œν•˜μ„Έμš”.\n\n━━━━━━━━━━━━━━━━━━━━\n\n:rocket: *ν”„λ‘œμ νŠΈ 이동*\n`/twindevbot goto <디렉토리λͺ…>`\n`/twindevbot goto <디렉토리λͺ…> --autopilot`\n\n━━━━━━━━━━━━━━━━━━━━\n\n:mag: *ν”„λ‘œμ νŠΈ λͺ©λ‘*\n`/twindevbot list`\n\n━━━━━━━━━━━━━━━━━━━━\n\n:hammer_and_wrench: *ν”„λ‘œμ νŠΈ 생성*\n`/twindevbot new <디렉토리λͺ…> --empty`\n`/twindevbot new <디렉토리λͺ…> --template <ν”„λ ˆμž„μ›Œν¬>`\n{{templates}}\n\n━━━━━━━━━━━━━━━━━━━━\n\n:bulb: *참고사항*\n* λͺ¨λ“  κ²½λ‘œλŠ” `{{baseDir}}` κΈ°μ€€μž…λ‹ˆλ‹€.\n* ν•˜λ‚˜μ˜ Claude Session 속 λŒ€ν™”λŠ” 동일 λ©”μ‹œμ§€ 속 μŠ€λ ˆλ“œλ“€λ‘œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.\n* ν”„λ‘œμ νŠΈ 디렉토리 μƒμ„±λ§ŒνΌμ€ `twindevbot new` λͺ…λ ΉμœΌλ‘œ ν•˜κΈ°λ³΄λ‹€λŠ” 본인 λ…ΈνŠΈλΆμ—μ„œ ν”„λ‘œμ νŠΈ 디렉토리λ₯Ό μ›ν•˜λŠ” λͺ¨μŠ΅μœΌλ‘œ 직접 μƒμ„±ν•˜κ³ , 각쒅 μ»¨ν…μŠ€νŠΈ λ£°(ex. `CLAUDE.md`, `.claude/rules/*`) νŒŒμΌμ„ μ μš©ν•΄λ‘” λ’€, `twindevbot goto`둜 μž‘μ—…ν•˜μ‹œκΈ°λ₯Ό μΆ”μ²œλ“œλ¦½λ‹ˆλ‹€.\n\n* `--autopilot` λͺ¨λ“œ: twindevbot이 λͺ¨λ“  μ§ˆλ¬Έμ— μžλ™μœΌλ‘œ λ‹΅ν•˜λ©° μ•Œμ•„μ„œ κ°œλ°œν•©λ‹ˆλ‹€. κ°€λ²Όμš΄ ν”„λ‘œμ νŠΈλ₯Ό μž‘μ—…ν•˜κ±°λ‚˜, μž λ“€κΈ° 전에 μ‚¬μš©ν•΄λ³΄μ„Έμš”.",
49
+ // slack-message.ts
50
+ "slack.answered": "λ‹΅λ³€ μ™„λ£Œ",
51
+ "slack.question": "질문",
52
+ // progress-tracker.ts
53
+ "progress.tool.Read": "νŒŒμΌμ„ 읽고 μžˆμŠ΅λ‹ˆλ‹€",
54
+ "progress.tool.Write": "νŒŒμΌμ„ μž‘μ„±ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
55
+ "progress.tool.Edit": "νŒŒμΌμ„ μˆ˜μ •ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
56
+ "progress.tool.Bash": "λͺ…λ Ήμ–΄λ₯Ό μ‹€ν–‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
57
+ "progress.tool.Grep": "μ½”λ“œλ₯Ό κ²€μƒ‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
58
+ "progress.tool.Glob": "νŒŒμΌμ„ μ°Ύκ³  μžˆμŠ΅λ‹ˆλ‹€",
59
+ "progress.tool.Task": "ν•˜μœ„ μž‘μ—…μ„ μ²˜λ¦¬ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
60
+ "progress.tool.WebSearch": "웹을 κ²€μƒ‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
61
+ "progress.tool.WebFetch": "μ›Ή νŽ˜μ΄μ§€λ₯Ό κ°€μ Έμ˜€κ³  μžˆμŠ΅λ‹ˆλ‹€",
62
+ "progress.tool.NotebookEdit": "λ…ΈνŠΈλΆμ„ μˆ˜μ •ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
63
+ "progress.tool.default": "도ꡬλ₯Ό μ‹€ν–‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€",
64
+ "progress.working": ":gear: μž‘μ—…μ„ μ‹œμž‘ν•©λ‹ˆλ‹€...",
65
+ "progress.completed": ":white_check_mark: μž‘μ—… μ™„λ£Œ ({{elapsed}})",
66
+ "progress.error": ":x: 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {{error}}",
67
+ "progress.planApproved": ":thumbsup: κ³„νšμ΄ μŠΉμΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€. κ΅¬ν˜„μ„ μ‹œμž‘ν•©λ‹ˆλ‹€...",
68
+ "progress.autopilotContinue": ":robot_face: μžλ™ 응닡 μ™„λ£Œ, 계속 μ§„ν–‰ 쀑... ({{elapsed}})",
69
+ "progress.askUser": ":raised_hand: μ§ˆλ¬Έμ„ μ „μ†‘ν–ˆμŠ΅λ‹ˆλ‹€. 닡변을 기닀리고 μžˆμŠ΅λ‹ˆλ‹€.",
70
+ "progress.lessThanOneSecond": "1초 미만",
71
+ "progress.seconds": "{{n}}초",
72
+ "progress.minutesSeconds": "{{m}}λΆ„ {{s}}초",
73
+ // claude-runner-setup.ts
74
+ "runner.questionArrived": "Claude Code 질문이 λ„μ°©ν–ˆμŠ΅λ‹ˆλ‹€",
75
+ "runner.autopilotAnswer": ":robot_face: Autopilot: *{{answer}}* μžλ™ 선택",
76
+ "runner.errorOccurred": "였λ₯˜ λ°œμƒ: {{error}}",
77
+ "runner.claudeNotFound": "Claude CLIκ°€ μ„€μΉ˜λ˜μ–΄ μžˆμ§€ μ•Šκ±°λ‚˜ PATH에 λ“±λ‘λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. `npm install -g @anthropic-ai/claude-code` λͺ…λ ΉμœΌλ‘œ μ„€μΉ˜ν•΄μ£Όμ„Έμš”.",
78
+ "runner.exitError": ":x: Claude ν”„λ‘œμ„ΈμŠ€κ°€ 비정상 μ’…λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€ (μ½”λ“œ: {{code}})",
79
+ "runner.autopilotResumeFailed": ":x: Autopilot: Claude μž¬μ‹œμž‘μ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.",
80
+ "runner.autopilotNoSession": ":x: Autopilot: μ„Έμ…˜ IDλ₯Ό 찾을 수 μ—†μ–΄ μž¬μ‹œμž‘ν•  수 μ—†μŠ΅λ‹ˆλ‹€.",
81
+ "runner.inactivityTimeout": ":warning: Claude ν”„λ‘œμ„ΈμŠ€κ°€ 30λΆ„κ°„ 응닡이 μ—†μ–΄ μžλ™ μ’…λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€. μƒˆ λ©”μ‹œμ§€λ₯Ό 보내 λ‹€μ‹œ μ‹œμž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€.",
82
+ "runner.planApproved": "κ³„νšμ΄ μŠΉμΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€. κ΅¬ν˜„μ„ μ‹œμž‘ν•˜μ„Έμš”.",
83
+ // templates.ts
84
+ "template.frontend": "*Frontend:* ",
85
+ "template.backend": "*Backend:* ",
86
+ // cli.ts
87
+ "cli.description": "μ–Έμ œ μ–΄λ””μ„œλ“  Claude Code둜 κ°œλ°œν•˜μ„Έμš”.",
88
+ "cli.usage": "μ‚¬μš©λ²•:",
89
+ "cli.commands": "λͺ…λ Ήμ–΄:",
90
+ "cli.cmd.start": "μ„œλ²„ μ‹œμž‘ (ν¬κ·ΈλΌμš΄λ“œ)",
91
+ "cli.cmd.startDaemon": "μ„œλ²„λ₯Ό λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€λ‘œ 등둝 및 μ‹œμž‘ (macOS launchd / Windows μž‘μ—… μŠ€μΌ€μ€„λŸ¬)",
92
+ "cli.cmd.stop": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€ 쀑지 및 ν•΄μ œ",
93
+ "cli.cmd.status": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€ μƒνƒœ 확인",
94
+ "cli.cmd.show": "μ €μž₯된 μ„Έμ…˜ λͺ©λ‘ 쑰회",
95
+ "cli.cmd.clear": "μ €μž₯된 데이터 파일 μ‚­μ œ (sessions.json, workspaces.json)",
96
+ "cli.cmd.help": "도움말 ν‘œμ‹œ",
97
+ "cli.notes": "μ£Όμ˜μ‚¬ν•­:",
98
+ "cli.notes.daemon": "twindevbot이 μ‹€ν–‰λœ μƒνƒœμ—¬μ•Ό 원격 μž‘μ—…μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€. --daemon μ˜΅μ…˜μœΌλ‘œ μ‹€ν–‰ν•΄λ‘μ‹œλ©΄ 맀번 λ‹€μ‹œ μ‹€ν–‰ν•  ν•„μš”κ°€ μ—†μ–΄μš”.",
99
+ "cli.notes.errorLog": "twindevbot μ„œλ²„μ— λ¬Έμ œκ°€ μžˆλŠ” 것 κ°™λ‹€λ©΄, μ—λŸ¬ 둜그λ₯Ό ν™•μΈν•΄λ³΄μ„Έμš”.",
100
+ "cli.warning.title": "κ²½κ³ ",
101
+ "cli.warning.text": "twindevbot을 μ‚¬μš©ν•˜λ©΄ claudeκ°€ --dangerously-skip-permissions μ˜΅μ…˜μœΌλ‘œ μ‹œμž‘λ©λ‹ˆλ‹€. μ΄κ²ƒμ˜ 의미λ₯Ό λΆ„λͺ…νžˆ μ•„λŠ” λΆ„λ“€λ§Œ twindevbot을 μ‚¬μš©ν•˜μ„Έμš”. twindevbot의 μ½”λ“œλŠ” GitHub에 λͺ¨λ‘ κ³΅κ°œλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. twindevbot μ‚¬μš©μœΌλ‘œ 인해 μ–΄λ–€ 사고가 λ°œμƒν•˜λ”λΌλ„ 아무도 μ±…μž„μ§€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.",
102
+ // setup.ts
103
+ "cli.setup.banner": "twindevbot μ„œλ²„ μ„€μ •",
104
+ "cli.setup.promptAppToken": "SLACK_APP_TOKEN을 μž…λ ₯ν•˜μ„Έμš” (xapp-...)",
105
+ "cli.setup.promptBotToken": "SLACK_BOT_TOKEN을 μž…λ ₯ν•˜μ„Έμš” (xoxb-...)",
106
+ "cli.setup.promptBaseDir": "ν”„λ‘œμ νŠΈ 디렉토리듀을 λ§Œλ“€ λΆ€λͺ¨ 디렉토리 경둜λ₯Ό μž‘μ„±ν•˜μ„Έμš”",
107
+ "cli.setup.promptLang": "μ–Έμ–΄λ₯Ό μ„ νƒν•˜μ„Έμš”",
108
+ "cli.setup.required": "값을 μž…λ ₯ν•΄μ£Όμ„Έμš”.",
109
+ "cli.setup.saved": "섀정이 μ €μž₯λ˜μ—ˆμŠ΅λ‹ˆλ‹€: {{path}}",
110
+ "cli.setup.startMessage": "μ„œλ²„λ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€.\n 이제 μŠ¬λž™μ—μ„œ /twindevbot이라고 μ“°κ³  μž‘μ—…ν•΄λ³΄μ„Έμš”.",
111
+ "cli.setup.startDaemonMessage": "μ„œλ²„λ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€. μ–Έμ œλ‚˜ μ‹€ν–‰λ˜μ–΄ μžˆλ„λ‘ λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€λ‘œ λ“±λ‘ν•©λ‹ˆλ‹€.\n 이제 μŠ¬λž™μ—μ„œ /twindevbot이라고 μ“°κ³  μž‘μ—…ν•΄λ³΄μ„Έμš”.",
112
+ "cli.daemon.plistCreated": "launchd plist 생성: {{path}}",
113
+ "cli.daemon.started": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€κ°€ μ‹œμž‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€.",
114
+ "cli.daemon.failedToStart": "μ„œλΉ„μŠ€ μ‹œμž‘ μ‹€νŒ¨:",
115
+ "cli.daemon.notInstalled": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€κ°€ μ„€μΉ˜λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€.",
116
+ "cli.daemon.stopped": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€κ°€ 쀑지 및 ν•΄μ œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.",
117
+ "cli.status.notInstalled": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€: λ―Έμ„€μΉ˜",
118
+ "cli.status.notInstalledHint": "'twindevbot start --daemon'으둜 μ„€μΉ˜ν•˜μ„Έμš”.",
119
+ "cli.status.running": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€: μ‹€ν–‰ 쀑 (PID {{pid}})",
120
+ "cli.status.registered": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€: 등둝됨",
121
+ "cli.status.notRunning": "λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€: μ„€μΉ˜λ˜μ—ˆμœΌλ‚˜ μ‹€ν–‰ 쀑이 μ•„λ‹™λ‹ˆλ‹€",
122
+ "cli.status.checkLogs": "ν¬λž˜μ‹œν–ˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. 둜그λ₯Ό ν™•μΈν•˜μ„Έμš”:",
123
+ "cli.daemonUnsupportedPlatform": "daemon κΈ°λŠ₯(start --daemon, stop, status)은 macOS와 Windowsμ—μ„œλ§Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν˜„μž¬ ν”Œλž«νΌ: {{platform}}",
124
+ "cli.daemon.taskCreated": "Windows μ˜ˆμ•½ μž‘μ—… 생성: {{name}}",
125
+ "cli.unknownCommand": "μ•Œ 수 μ—†λŠ” λͺ…λ Ήμ–΄: {{command}}",
126
+ // cli.ts - show
127
+ "cli.show.title": "twindevbot sessions ({{count}})",
128
+ "cli.show.sessionCount": "({{count}}개 μ„Έμ…˜)",
129
+ "cli.show.noSessions": "μ €μž₯된 μ„Έμ…˜μ΄ μ—†μŠ΅λ‹ˆλ‹€.",
130
+ "cli.show.parseError": "sessions.json νŒŒμΌμ„ νŒŒμ‹±ν•  수 μ—†μŠ΅λ‹ˆλ‹€.",
131
+ "cli.show.daysAgo": "{{n}}일 μ „",
132
+ "cli.show.hoursAgo": "{{n}}μ‹œκ°„ μ „",
133
+ "cli.show.minutesAgo": "{{n}}λΆ„ μ „",
134
+ "cli.show.justNow": "방금 μ „",
135
+ // cli.ts - clear
136
+ "cli.clear.header": "μ‚­μ œν•  파일:",
137
+ "cli.clear.confirm": "μœ„ νŒŒμΌλ“€μ„ μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?",
138
+ "cli.clear.noData": "μ‚­μ œν•  데이터 파일이 μ—†μŠ΅λ‹ˆλ‹€.",
139
+ "cli.clear.cancelled": "μ·¨μ†Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.",
140
+ "cli.clear.done": "βœ” 데이터 파일이 μ‚­μ œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.",
141
+ };
@@ -0,0 +1,34 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error";
2
+ declare class Logger {
3
+ private level;
4
+ private context?;
5
+ private static logStream;
6
+ constructor(level?: LogLevel, context?: string);
7
+ static enableFileLogging(filePath: string): void;
8
+ private shouldLog;
9
+ private formatMessage;
10
+ private output;
11
+ debug(message: string, data?: unknown): void;
12
+ info(message: string, data?: unknown): void;
13
+ warn(message: string, data?: unknown): void;
14
+ error(message: string, error?: unknown): void;
15
+ child(context: string): Logger;
16
+ }
17
+ export declare const logger: Logger;
18
+ export declare function createLogger(context: string): Logger;
19
+ export declare function enableFileLogging(filePath: string): void;
20
+ /**
21
+ * Slack Bolt용 둜거 μ–΄λŒ‘ν„°.
22
+ * Bolt λ‚΄λΆ€ 둜그λ₯Ό μ»€μŠ€ν…€ 둜거둜 λΌμš°νŒ…ν•˜μ—¬
23
+ * νƒ€μž„μŠ€νƒ¬ν”„ + stderr 좜λ ₯을 μΌκ΄€λ˜κ²Œ μœ μ§€ν•œλ‹€.
24
+ */
25
+ export declare function createBoltLogger(): {
26
+ debug(...msg: unknown[]): void;
27
+ info(...msg: unknown[]): void;
28
+ warn(...msg: unknown[]): void;
29
+ error(...msg: unknown[]): void;
30
+ setLevel(level: string): void;
31
+ getLevel(): string;
32
+ setName(name: string): void;
33
+ };
34
+ export {};