setup-cc-room 0.2.1 → 0.2.2

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,22 @@
1
+ // src/daemon-resolver.ts
2
+ import { existsSync } from "fs";
3
+ import { join } from "path";
4
+ function resolveDaemonSource(setupPackageRoot) {
5
+ const candidates = [
6
+ join(setupPackageRoot, "vendor", "daemon", "dist", "index.js"),
7
+ join(setupPackageRoot, "..", "daemon", "dist-bundle", "index.js"),
8
+ // モノレポ開発時のフォールバック(チャンク分割あり・単体コピーでは動かないことがある)
9
+ join(setupPackageRoot, "..", "daemon", "dist", "index.js"),
10
+ join(setupPackageRoot, "..", "..", "node_modules", "@cc-room", "daemon", "dist", "index.js")
11
+ ];
12
+ for (const c of candidates) {
13
+ if (existsSync(c)) return c;
14
+ }
15
+ return null;
16
+ }
17
+ var DAEMON_MISSING_HINT = "cc-room-daemon not found. In the repo run `pnpm --filter setup-cc-room run pack:vendor`, or use the npm setup-cc-room package.";
18
+
19
+ export {
20
+ resolveDaemonSource,
21
+ DAEMON_MISSING_HINT
22
+ };
@@ -0,0 +1,119 @@
1
+ import {
2
+ resolveCcRoomDir
3
+ } from "./chunk-WCEABGOA.js";
4
+ import {
5
+ unmergeSettings
6
+ } from "./chunk-MVD6RIS2.js";
7
+ import {
8
+ t
9
+ } from "./chunk-OYW7MM4W.js";
10
+
11
+ // src/uninstaller.ts
12
+ import {
13
+ existsSync,
14
+ mkdirSync,
15
+ rmSync,
16
+ unlinkSync
17
+ } from "fs";
18
+ import { join } from "path";
19
+ import { homedir, platform } from "os";
20
+ import { execFileSync, spawnSync } from "child_process";
21
+ var COMMAND_FILES = ["room.md", "private.md", "show.md"];
22
+ function getLaunchdPlistPath(home = homedir()) {
23
+ return join(home, "Library", "LaunchAgents", "dev.ccroom.daemon.plist");
24
+ }
25
+ function getSystemdUnitPath(home = homedir()) {
26
+ return join(home, ".config", "systemd", "user", "cc-room-daemon.service");
27
+ }
28
+ function stopLaunchd(plistPath) {
29
+ if (!existsSync(plistPath)) {
30
+ console.log(t("un.launchd_none"));
31
+ return;
32
+ }
33
+ try {
34
+ execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
35
+ } catch {
36
+ }
37
+ try {
38
+ unlinkSync(plistPath);
39
+ console.log(t("un.launchd_ok", { path: plistPath }));
40
+ } catch (err) {
41
+ const msg = err instanceof Error ? err.message : String(err);
42
+ console.log(t("un.plist_fail", { msg }));
43
+ }
44
+ }
45
+ function stopSystemd(unitPath) {
46
+ try {
47
+ execFileSync("systemctl", ["--user", "disable", "--now", "cc-room-daemon"], { stdio: "pipe" });
48
+ } catch {
49
+ }
50
+ if (existsSync(unitPath)) {
51
+ try {
52
+ unlinkSync(unitPath);
53
+ console.log(t("un.systemd_ok", { path: unitPath }));
54
+ } catch (err) {
55
+ const msg = err instanceof Error ? err.message : String(err);
56
+ console.log(t("un.unit_fail", { msg }));
57
+ }
58
+ } else {
59
+ console.log(t("un.systemd_none"));
60
+ }
61
+ try {
62
+ execFileSync("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
63
+ } catch {
64
+ }
65
+ }
66
+ function removeCommandFiles(commandsDir) {
67
+ mkdirSync(commandsDir, { recursive: true });
68
+ let removed = 0;
69
+ for (const name of COMMAND_FILES) {
70
+ const path = join(commandsDir, name);
71
+ if (existsSync(path)) {
72
+ unlinkSync(path);
73
+ removed++;
74
+ }
75
+ }
76
+ console.log(t("un.commands_ok", { count: removed, dir: commandsDir }));
77
+ }
78
+ function removeCcRoomData(ccRoomDir) {
79
+ if (!existsSync(ccRoomDir)) {
80
+ console.log(t("un.data_skip", { dir: ccRoomDir }));
81
+ return;
82
+ }
83
+ rmSync(ccRoomDir, { recursive: true, force: true });
84
+ console.log(t("un.data_ok", { dir: ccRoomDir }));
85
+ }
86
+ function stopOrphanDaemon() {
87
+ spawnSync("pkill", ["-f", "cc-room-daemon"], { stdio: "pipe" });
88
+ }
89
+ async function uninstall() {
90
+ const ccRoomDir = resolveCcRoomDir();
91
+ const commandsDir = join(homedir(), ".claude", "commands");
92
+ const os = platform();
93
+ console.log(t("un.step1"));
94
+ if (os === "darwin") {
95
+ stopLaunchd(getLaunchdPlistPath());
96
+ } else if (os === "linux") {
97
+ stopSystemd(getSystemdUnitPath());
98
+ } else {
99
+ console.log(t("un.os_manual", { os }));
100
+ }
101
+ stopOrphanDaemon();
102
+ console.log(t("un.step2"));
103
+ removeCommandFiles(commandsDir);
104
+ console.log(t("un.step3"));
105
+ unmergeSettings();
106
+ console.log(t("un.step4"));
107
+ removeCcRoomData(ccRoomDir);
108
+ }
109
+
110
+ export {
111
+ getLaunchdPlistPath,
112
+ getSystemdUnitPath,
113
+ stopLaunchd,
114
+ stopSystemd,
115
+ removeCommandFiles,
116
+ removeCcRoomData,
117
+ stopOrphanDaemon,
118
+ uninstall
119
+ };
@@ -0,0 +1,120 @@
1
+ import {
2
+ t
3
+ } from "./chunk-OYW7MM4W.js";
4
+
5
+ // src/settings-merger.ts
6
+ import { readFileSync, writeFileSync, existsSync, copyFileSync, mkdirSync } from "fs";
7
+ import { join } from "path";
8
+ import { homedir } from "os";
9
+ var SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
10
+ var CC_ROOM_HOOKS = {
11
+ UserPromptSubmit: [
12
+ {
13
+ hooks: [
14
+ {
15
+ type: "command",
16
+ command: "cc-room-daemon hook user-prompt-submit"
17
+ }
18
+ ]
19
+ }
20
+ ],
21
+ PostToolUse: [
22
+ {
23
+ matcher: "Write|Edit",
24
+ hooks: [
25
+ {
26
+ type: "command",
27
+ command: "cc-room-daemon hook post-tool-use"
28
+ }
29
+ ]
30
+ }
31
+ ],
32
+ Stop: [
33
+ {
34
+ hooks: [
35
+ {
36
+ type: "command",
37
+ command: "cc-room-daemon hook session-stop"
38
+ }
39
+ ]
40
+ }
41
+ ]
42
+ };
43
+ var CC_ROOM_MCP = {
44
+ "cc-room": {
45
+ type: "stdio",
46
+ command: "cc-room-daemon",
47
+ args: ["mcp"]
48
+ }
49
+ };
50
+ function mergeSettings() {
51
+ let settings = {};
52
+ mkdirSync(join(homedir(), ".claude"), { recursive: true });
53
+ if (existsSync(SETTINGS_PATH)) {
54
+ try {
55
+ settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
56
+ } catch {
57
+ console.log(t("settings.parse_fail_backup"));
58
+ copyFileSync(SETTINGS_PATH, SETTINGS_PATH + ".backup");
59
+ settings = {};
60
+ }
61
+ }
62
+ const existingHooks = settings.hooks ?? {};
63
+ const mergedHooks = { ...existingHooks };
64
+ for (const [event, newEntries] of Object.entries(CC_ROOM_HOOKS)) {
65
+ const existing = mergedHooks[event] ?? [];
66
+ const filtered = existing.filter((e) => {
67
+ const entry = e;
68
+ return !entry.hooks?.some((h) => h.command?.startsWith("cc-room-daemon hook"));
69
+ });
70
+ mergedHooks[event] = [...filtered, ...newEntries];
71
+ }
72
+ const existingMcp = settings.mcpServers ?? {};
73
+ const mergedMcp = { ...existingMcp, ...CC_ROOM_MCP };
74
+ settings.hooks = mergedHooks;
75
+ settings.mcpServers = mergedMcp;
76
+ writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n", { mode: 420 });
77
+ console.log(t("settings.updated", { path: SETTINGS_PATH }));
78
+ }
79
+ function stripCcRoomFromSettings(settings) {
80
+ const next = { ...settings };
81
+ const existingHooks = settings.hooks ?? {};
82
+ const strippedHooks = {};
83
+ for (const [event, entries] of Object.entries(existingHooks)) {
84
+ strippedHooks[event] = (entries ?? []).filter((e) => {
85
+ const entry = e;
86
+ return !entry.hooks?.some((h) => h.command?.startsWith("cc-room-daemon hook"));
87
+ });
88
+ }
89
+ if (Object.keys(existingHooks).length > 0 || Object.keys(strippedHooks).length > 0) {
90
+ next.hooks = strippedHooks;
91
+ }
92
+ const existingMcp = settings.mcpServers ?? {};
93
+ if (Object.keys(existingMcp).length > 0) {
94
+ const { ["cc-room"]: _removed, ...rest } = existingMcp;
95
+ next.mcpServers = rest;
96
+ }
97
+ return next;
98
+ }
99
+ function unmergeSettings() {
100
+ if (!existsSync(SETTINGS_PATH)) {
101
+ console.log(t("settings.skip_missing", { path: SETTINGS_PATH }));
102
+ return;
103
+ }
104
+ let settings;
105
+ try {
106
+ settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
107
+ } catch {
108
+ console.log(t("settings.parse_fail_skip"));
109
+ return;
110
+ }
111
+ const next = stripCcRoomFromSettings(settings);
112
+ writeFileSync(SETTINGS_PATH, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
113
+ console.log(t("settings.stripped", { path: SETTINGS_PATH }));
114
+ }
115
+
116
+ export {
117
+ mergeSettings,
118
+ stripCcRoomFromSettings,
119
+ unmergeSettings
120
+ };
@@ -0,0 +1,278 @@
1
+ // src/i18n.ts
2
+ function resolveLocale(argv = process.argv, env = process.env) {
3
+ const langFlagIdx = argv.findIndex((a) => a === "--lang" || a === "--locale");
4
+ if (langFlagIdx >= 0 && argv[langFlagIdx + 1]) {
5
+ return normalizeLocale(argv[langFlagIdx + 1]);
6
+ }
7
+ const inline = argv.find((a) => a.startsWith("--lang=") || a.startsWith("--locale="));
8
+ if (inline) {
9
+ return normalizeLocale(inline.split("=")[1] ?? "en");
10
+ }
11
+ if (env.CC_ROOM_LANG) {
12
+ return normalizeLocale(env.CC_ROOM_LANG);
13
+ }
14
+ return "en";
15
+ }
16
+ function normalizeLocale(raw) {
17
+ const v = raw.trim().toLowerCase();
18
+ if (v === "ja" || v === "jp" || v === "japanese" || v.startsWith("ja-")) return "ja";
19
+ return "en";
20
+ }
21
+ var en = {
22
+ "cli.running_preflight": " Running preflight checks...",
23
+ "cli.preflight_failed": " \x1B[31mPrerequisites not met. Fix the issues above and try again.\x1B[0m\n",
24
+ "cli.preflight_ok": " \x1B[32mAll checks passed. Starting install...\x1B[0m\n",
25
+ "cli.install_done": " \x1B[32m\u2705 Setup complete!\x1B[0m",
26
+ "cli.uninstall_done": " \x1B[32m\u2705 Uninstall complete.\x1B[0m",
27
+ "cli.restart_claude": " Restart Claude Code so hooks / MCP take effect.",
28
+ "cli.unknown_arg": " Unknown argument: {arg}",
29
+ "cli.error": " \x1B[31mError:\x1B[0m",
30
+ "cli.help": `
31
+ \u{1F3E0} setup-cc-room v{version}
32
+
33
+ Usage:
34
+ npx setup-cc-room Install cc-room (English by default)
35
+ npx setup-cc-room --lang ja Install with Japanese UI / commands
36
+ npx setup-cc-room uninstall Remove cc-room
37
+ npx setup-cc-room --help Show this help
38
+
39
+ Language: --lang en|ja or CC_ROOM_LANG=ja
40
+ `,
41
+ "cli.install_guide": `
42
+ How to use cc-room:
43
+
44
+ [Open a room]
45
+ 1. Restart Claude Code (enable MCP and Hooks)
46
+ 2. /room open <name> \u2190 creates a room (PIN issued)
47
+ 3. Tell teammates the room name and PIN
48
+ 4. They run /room join <name> <PIN>
49
+
50
+ [If invited]
51
+ 1. Restart Claude Code
52
+ 2. /room join <name> <PIN>
53
+
54
+ [Daily]
55
+ /room \u2026 view the whiteboard
56
+ /private \u2026 status / local vs public (on|off|share|drop)
57
+
58
+ \u26A0\uFE0F cc-room does not notify others automatically.
59
+ Share the room name and PIN yourself.
60
+
61
+ You need to be on the same Wi\u2011Fi (LAN).
62
+ (A VPN that creates a shared LAN also works.)
63
+
64
+ Uninstall: npx setup-cc-room uninstall
65
+ Japanese UI: npx setup-cc-room --lang ja
66
+
67
+ Docs: https://github.com/takanorisuzuki/cc-room
68
+ `,
69
+ "install.step1": " [1/5] Setting up {dir}/bin/...",
70
+ "install.copied": " Copied: {path}",
71
+ "install.global_ok": " Found global binary: {path}",
72
+ "install.step2": " [2/5] Writing {path}...",
73
+ "install.config_created": " Created: {path} (identity: {identity})",
74
+ "install.config_skip": " Skip: {path} already exists",
75
+ "install.step3": " [3/5] Installing slash commands ({locale})...",
76
+ "install.commands_ok": " Installed {count} files into {dir}",
77
+ "install.step4": " [4/5] Updating .claude/settings.json...",
78
+ "install.step5": " [5/5] Registering OS auto-start...",
79
+ "daemon.missing": "cc-room-daemon not found. In the repo run `pnpm --filter setup-cc-room run pack:vendor`, or use the npm setup-cc-room package.",
80
+ "settings.updated": " Updated {path}",
81
+ "settings.parse_fail_backup": " \x1B[33m\u26A0 Failed to parse settings.json. Creating a backup and overwriting.\x1B[0m",
82
+ "settings.skip_missing": " Skip: {path} does not exist",
83
+ "settings.parse_fail_skip": " \x1B[33m\u26A0 Failed to parse settings.json; skipped removing hooks/MCP.\x1B[0m",
84
+ "settings.stripped": " Removed cc-room from {path}",
85
+ "svc.launchd_ok": " Registered with launchd: {path}",
86
+ "svc.launchd_fail": " \x1B[33m\u26A0 launchd registration failed: {msg}\x1B[0m",
87
+ "svc.launchd_manual": " Manual: launchctl load {path}",
88
+ "svc.systemd_ok": " Registered with systemd: {path}",
89
+ "svc.systemd_fail": " \x1B[33m\u26A0 systemd registration failed: {msg}\x1B[0m",
90
+ "svc.systemd_manual": " Manual: systemctl --user enable --now cc-room-daemon",
91
+ "svc.unsupported": " \x1B[33m\u26A0 Auto-start is not supported on {os}. Start cc-room-daemon manually.\x1B[0m",
92
+ "svc.waiting": " Waiting for daemon to start...",
93
+ "svc.started": " Daemon started",
94
+ "svc.start_unconfirmed": " \x1B[33m\u26A0 Could not confirm daemon start. Run cc-room-daemon manually.\x1B[0m",
95
+ "un.step1": " [1/4] Stopping OS service...",
96
+ "un.launchd_none": " launchd: not registered",
97
+ "un.launchd_ok": " Unregistered launchd: {path}",
98
+ "un.plist_fail": " \x1B[33m\u26A0 Failed to remove plist: {msg}\x1B[0m",
99
+ "un.systemd_ok": " Unregistered systemd: {path}",
100
+ "un.unit_fail": " \x1B[33m\u26A0 Failed to remove unit: {msg}\x1B[0m",
101
+ "un.systemd_none": " systemd: not registered",
102
+ "un.os_manual": " {os}: unregister auto-start manually",
103
+ "un.step2": " [2/4] Removing slash commands...",
104
+ "un.commands_ok": " Removed {count} command files ({dir})",
105
+ "un.step3": " [3/4] Removing cc-room from .claude/settings.json...",
106
+ "un.step4": " [4/4] Removing data directory...",
107
+ "un.data_skip": " Skip: {dir} does not exist",
108
+ "un.data_ok": " Deleted: {dir}",
109
+ "val.node_bad": "Node.js {version} (20+ required)",
110
+ "val.node_hint": "Upgrade to Node.js 20+: https://nodejs.org/",
111
+ "val.claude_ok": "Claude Code is installed",
112
+ "val.claude_missing": "Claude Code not found",
113
+ "val.claude_hint": "Install Claude Code: https://claude.ai/code",
114
+ "val.claude_dir_ok": "~/.claude/ directory exists",
115
+ "val.claude_dir_missing": "~/.claude/ not found",
116
+ "val.claude_dir_hint": "Start Claude Code once to create a session",
117
+ "val.settings_writable": "settings.json is writable",
118
+ "val.settings_not_writable": "No write permission for settings.json",
119
+ "val.settings_chmod": "Run chmod 644 {path}",
120
+ "val.settings_creatable": "Can create settings.json",
121
+ "val.claude_dir_not_writable": "No write permission for ~/.claude/",
122
+ "val.claude_dir_chmod": "Run chmod 755 {path}",
123
+ "val.hooks_unset": "Hooks: unrestricted (no settings.json yet)",
124
+ "val.hooks_disabled": "Hooks are disabled",
125
+ "val.hooks_disabled_hint": "cc-room needs the PostToolUse hook. Remove the hooks disable setting from settings.json",
126
+ "val.hooks_ok": "Hooks: enabled",
127
+ "val.hooks_unrestricted": "Hooks: unrestricted",
128
+ "val.mcp_ok": "MCP Server: can register",
129
+ "val.mcp_disabled": "MCP Server registration is disabled",
130
+ "val.mcp_disabled_hint": "cc-room talks to Claude Code via MCP. Remove the MCP disable setting from settings.json",
131
+ "val.session_ok": "Session directory exists",
132
+ "val.session_pending": "Session directory not created yet (appears after first session)",
133
+ "val.git_ok": "Git user: {name}",
134
+ "val.git_no_name": "git user.name is not set",
135
+ "val.git_no_name_hint": 'Set with git config --global user.name "Your Name" (used as cc-room identity)',
136
+ "val.git_missing": "git not found",
137
+ "val.git_hint": "Install git"
138
+ };
139
+ var ja = {
140
+ "cli.running_preflight": " Preflight checks \u3092\u5B9F\u884C\u4E2D...",
141
+ "cli.preflight_failed": " \x1B[31m\u524D\u63D0\u6761\u4EF6\u3092\u6E80\u305F\u3057\u3066\u3044\u307E\u305B\u3093\u3002\u4E0A\u8A18\u306E\u554F\u984C\u3092\u89E3\u6C7A\u3057\u3066\u304B\u3089\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\x1B[0m\n",
142
+ "cli.preflight_ok": " \x1B[32m\u5168\u30C1\u30A7\u30C3\u30AF\u901A\u904E\u3002\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3092\u958B\u59CB\u3057\u307E\u3059\u3002\x1B[0m\n",
143
+ "cli.install_done": " \x1B[32m\u2705 \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\uFF01\x1B[0m",
144
+ "cli.uninstall_done": " \x1B[32m\u2705 \u30A2\u30F3\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\x1B[0m",
145
+ "cli.restart_claude": " Claude Code \u3092\u518D\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\uFF08hooks / MCP \u306E\u53CD\u6620\uFF09\u3002",
146
+ "cli.unknown_arg": " \u4E0D\u660E\u306A\u5F15\u6570: {arg}",
147
+ "cli.error": " \x1B[31m\u30A8\u30E9\u30FC:\x1B[0m",
148
+ "cli.help": `
149
+ \u{1F3E0} setup-cc-room v{version}
150
+
151
+ \u4F7F\u3044\u65B9:
152
+ npx setup-cc-room \u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\u306F\u82F1\u8A9E\uFF09
153
+ npx setup-cc-room --lang ja \u65E5\u672C\u8A9E UI / \u30B3\u30DE\u30F3\u30C9\u3067\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB
154
+ npx setup-cc-room uninstall \u30A2\u30F3\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB
155
+ npx setup-cc-room --help \u30D8\u30EB\u30D7
156
+
157
+ \u8A00\u8A9E: --lang en|ja \u307E\u305F\u306F CC_ROOM_LANG=ja
158
+ `,
159
+ "cli.install_guide": `
160
+ cc-room \u306E\u4F7F\u3044\u65B9:
161
+
162
+ \u3010\u4F1A\u8B70\u5BA4\u3092\u958B\u304F\u5834\u5408\u3011
163
+ 1. Claude Code \u3092\u518D\u8D77\u52D5\uFF08MCP \u3068 Hooks \u3092\u6709\u52B9\u5316\uFF09
164
+ 2. /room open <name> \u2190 \u4F1A\u8B70\u5BA4\u3092\u958B\u304F\uFF08PIN \u767A\u884C\uFF09
165
+ 3. \u8868\u793A\u3055\u308C\u308B\u90E8\u5C4B\u540D\u3068 PIN \u3092\u76F8\u624B\u306B\u53E3\u982D\u3084 DM \u3067\u4F1D\u3048\u308B
166
+ 4. \u76F8\u624B\u304C /room join <name> <PIN> \u3092\u5B9F\u884C\u3059\u308C\u3070\u53C2\u52A0\u5B8C\u4E86
167
+
168
+ \u3010\u62DB\u5F85\u3055\u308C\u305F\u5834\u5408\u3011
169
+ 1. Claude Code \u3092\u518D\u8D77\u52D5
170
+ 2. /room join <name> <PIN> \u2190 \u76F8\u624B\u304B\u3089\u53D7\u3051\u53D6\u3063\u305F\u5024\u3092\u5165\u529B
171
+
172
+ \u3010\u65E5\u5E38\u64CD\u4F5C\u3011
173
+ /room \u2026 \u30DB\u30EF\u30A4\u30C8\u30DC\u30FC\u30C9\u3092\u898B\u308B
174
+ /private \u2026 \u72B6\u614B\u8868\u793A\u3001\u624B\u5143/\u516C\u958B\u306E\u5207\u66FF\uFF08on|off|share|drop\uFF09
175
+
176
+ \u26A0\uFE0F cc-room \u306F\u81EA\u52D5\u3067\u76F8\u624B\u306B\u901A\u77E5\u3057\u307E\u305B\u3093\u3002
177
+ \u90E8\u5C4B\u540D\u3068 PIN \u306F\u81EA\u5206\u3067\u76F8\u624B\u306B\u4F1D\u3048\u3066\u304F\u3060\u3055\u3044\u3002
178
+
179
+ \u63A5\u7D9A\u5F8C\u306F\u540C\u3058 WiFi\uFF08LAN\uFF09\u5185\u306B\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002
180
+ \uFF08VPN \u3067\u540C\u4E00 LAN \u76F8\u5F53\u306B\u306A\u308C\u3070\u30EA\u30E2\u30FC\u30C8\u3067\u3082\u4F7F\u3048\u307E\u3059\uFF09
181
+
182
+ \u30A2\u30F3\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB: npx setup-cc-room uninstall
183
+
184
+ \u30C9\u30AD\u30E5\u30E1\u30F3\u30C8: https://github.com/takanorisuzuki/cc-room
185
+ `,
186
+ "install.step1": " [1/5] {dir}/bin/ \u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7...",
187
+ "install.copied": " \u30B3\u30D4\u30FC\u5B8C\u4E86: {path}",
188
+ "install.global_ok": " \u30B0\u30ED\u30FC\u30D0\u30EB\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u78BA\u8A8D\u6E08\u307F: {path}",
189
+ "install.step2": " [2/5] {path} \u306E\u751F\u6210...",
190
+ "install.config_created": " \u751F\u6210\u5B8C\u4E86: {path} (identity: {identity})",
191
+ "install.config_skip": " \u30B9\u30AD\u30C3\u30D7: {path} \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059",
192
+ "install.step3": " [3/5] \u30B3\u30DE\u30F3\u30C9\u30D5\u30A1\u30A4\u30EB\u306E\u914D\u7F6E ({locale})...",
193
+ "install.commands_ok": " {count} \u30D5\u30A1\u30A4\u30EB\u3092 {dir} \u306B\u914D\u7F6E\u3057\u307E\u3057\u305F",
194
+ "install.step4": " [4/5] .claude/settings.json \u306E\u66F4\u65B0...",
195
+ "install.step5": " [5/5] OS\u81EA\u52D5\u8D77\u52D5\u306E\u767B\u9332...",
196
+ "daemon.missing": "cc-room-daemon \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u30EA\u30DD\u30B8\u30C8\u30EA\u3067\u306F `pnpm --filter setup-cc-room run pack:vendor` \u3092\u5B9F\u884C\u3059\u308B\u304B\u3001npm \u306E setup-cc-room \u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002",
197
+ "settings.updated": " {path} \u3092\u66F4\u65B0\u3057\u307E\u3057\u305F",
198
+ "settings.parse_fail_backup": " \x1B[33m\u26A0 settings.json \u306E\u30D1\u30FC\u30B9\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3092\u4F5C\u6210\u3057\u3066\u4E0A\u66F8\u304D\u3057\u307E\u3059\u3002\x1B[0m",
199
+ "settings.parse_fail_skip": " \x1B[33m\u26A0 settings.json \u306E\u30D1\u30FC\u30B9\u306B\u5931\u6557\u3057\u305F\u305F\u3081\u3001hooks/MCP \u306E\u9664\u53BB\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3059\u3002\x1B[0m",
200
+ "settings.skip_missing": " \u30B9\u30AD\u30C3\u30D7: {path} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093",
201
+ "settings.stripped": " {path} \u304B\u3089 cc-room \u3092\u9664\u53BB\u3057\u307E\u3057\u305F",
202
+ "svc.launchd_ok": " launchd \u306B\u767B\u9332\u3057\u307E\u3057\u305F: {path}",
203
+ "svc.launchd_fail": " \x1B[33m\u26A0 launchd \u767B\u9332\u306B\u5931\u6557\u3057\u307E\u3057\u305F: {msg}\x1B[0m",
204
+ "svc.launchd_manual": " \u624B\u52D5\u3067\u767B\u9332: launchctl load {path}",
205
+ "svc.systemd_ok": " systemd \u306B\u767B\u9332\u3057\u307E\u3057\u305F: {path}",
206
+ "svc.systemd_fail": " \x1B[33m\u26A0 systemd \u767B\u9332\u306B\u5931\u6557\u3057\u307E\u3057\u305F: {msg}\x1B[0m",
207
+ "svc.systemd_manual": " \u624B\u52D5\u3067\u767B\u9332: systemctl --user enable --now cc-room-daemon",
208
+ "svc.unsupported": " \x1B[33m\u26A0 {os} \u3067\u306E\u81EA\u52D5\u8D77\u52D5\u767B\u9332\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u624B\u52D5\u3067 cc-room-daemon \u3092\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002\x1B[0m",
209
+ "svc.waiting": " daemon \u306E\u8D77\u52D5\u3092\u5F85\u6A5F\u4E2D...",
210
+ "svc.started": " daemon \u304C\u8D77\u52D5\u3057\u307E\u3057\u305F",
211
+ "svc.start_unconfirmed": " \x1B[33m\u26A0 daemon \u306E\u81EA\u52D5\u8D77\u52D5\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u624B\u52D5\u3067 cc-room-daemon \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\x1B[0m",
212
+ "un.step1": " [1/4] OS \u30B5\u30FC\u30D3\u30B9\u3092\u505C\u6B62...",
213
+ "un.launchd_none": " launchd: \u672A\u767B\u9332",
214
+ "un.launchd_ok": " launchd \u3092\u89E3\u9664: {path}",
215
+ "un.plist_fail": " \x1B[33m\u26A0 plist \u524A\u9664\u306B\u5931\u6557: {msg}\x1B[0m",
216
+ "un.systemd_ok": " systemd \u3092\u89E3\u9664: {path}",
217
+ "un.unit_fail": " \x1B[33m\u26A0 unit \u524A\u9664\u306B\u5931\u6557: {msg}\x1B[0m",
218
+ "un.systemd_none": " systemd: \u672A\u767B\u9332",
219
+ "un.os_manual": " {os}: \u81EA\u52D5\u8D77\u52D5\u306E\u89E3\u9664\u306F\u624B\u52D5\u3067\u884C\u3063\u3066\u304F\u3060\u3055\u3044",
220
+ "un.step2": " [2/4] Slash commands \u3092\u524A\u9664...",
221
+ "un.commands_ok": " \u30B3\u30DE\u30F3\u30C9\u30D5\u30A1\u30A4\u30EB\u3092 {count} \u4EF6\u524A\u9664 ({dir})",
222
+ "un.step3": " [3/4] .claude/settings.json \u304B\u3089 cc-room \u3092\u9664\u53BB...",
223
+ "un.step4": " [4/4] \u30C7\u30FC\u30BF\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u524A\u9664...",
224
+ "un.data_skip": " \u30B9\u30AD\u30C3\u30D7: {dir} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093",
225
+ "un.data_ok": " \u524A\u9664: {dir}",
226
+ "val.node_bad": "Node.js {version} (20+ \u304C\u5FC5\u8981)",
227
+ "val.node_hint": "Node.js 20 \u4EE5\u4E0A\u306B\u30A2\u30C3\u30D7\u30B0\u30EC\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044: https://nodejs.org/",
228
+ "val.claude_ok": "Claude Code \u304C\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u6E08\u307F",
229
+ "val.claude_missing": "Claude Code \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
230
+ "val.claude_hint": "Claude Code \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044: https://claude.ai/code",
231
+ "val.claude_dir_ok": "~/.claude/ \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728",
232
+ "val.claude_dir_missing": "~/.claude/ \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
233
+ "val.claude_dir_hint": "Claude Code \u3092\u4E00\u5EA6\u8D77\u52D5\u3057\u3066\u30BB\u30C3\u30B7\u30E7\u30F3\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044",
234
+ "val.settings_writable": "settings.json \u306B\u66F8\u304D\u8FBC\u307F\u53EF\u80FD",
235
+ "val.settings_not_writable": "settings.json \u306B\u66F8\u304D\u8FBC\u307F\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093",
236
+ "val.settings_chmod": "chmod 644 {path} \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044",
237
+ "val.settings_creatable": "settings.json \u3092\u4F5C\u6210\u53EF\u80FD",
238
+ "val.claude_dir_not_writable": "~/.claude/ \u306B\u66F8\u304D\u8FBC\u307F\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093",
239
+ "val.claude_dir_chmod": "chmod 755 {path} \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044",
240
+ "val.hooks_unset": "Hooks: \u5236\u9650\u306A\u3057\uFF08settings.json \u672A\u4F5C\u6210\uFF09",
241
+ "val.hooks_disabled": "Hooks \u304C\u7121\u52B9\u5316\u3055\u308C\u3066\u3044\u307E\u3059",
242
+ "val.hooks_disabled_hint": "cc-room \u306F\u30D5\u30A1\u30A4\u30EB\u5171\u6709\u306B PostToolUse hook \u3092\u4F7F\u7528\u3057\u307E\u3059\u3002settings.json \u304B\u3089 hooks \u306E\u7121\u52B9\u5316\u8A2D\u5B9A\u3092\u524A\u9664\u3057\u3066\u304F\u3060\u3055\u3044",
243
+ "val.hooks_ok": "Hooks: \u6709\u52B9",
244
+ "val.hooks_unrestricted": "Hooks: \u5236\u9650\u306A\u3057",
245
+ "val.mcp_ok": "MCP Server: \u767B\u9332\u53EF\u80FD",
246
+ "val.mcp_disabled": "MCP Server \u306E\u767B\u9332\u304C\u7121\u52B9\u5316\u3055\u308C\u3066\u3044\u307E\u3059",
247
+ "val.mcp_disabled_hint": "cc-room \u306F MCP Server \u7D4C\u7531\u3067 Claude Code \u3068\u9023\u643A\u3057\u307E\u3059\u3002settings.json \u304B\u3089 MCP \u306E\u7121\u52B9\u5316\u8A2D\u5B9A\u3092\u524A\u9664\u3057\u3066\u304F\u3060\u3055\u3044",
248
+ "val.session_ok": "\u30BB\u30C3\u30B7\u30E7\u30F3\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728",
249
+ "val.session_pending": "\u30BB\u30C3\u30B7\u30E7\u30F3\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u672A\u4F5C\u6210\uFF08\u521D\u56DE\u30BB\u30C3\u30B7\u30E7\u30F3\u5F8C\u306B\u751F\u6210\u3055\u308C\u308B\uFF09",
250
+ "val.git_ok": "Git \u30E6\u30FC\u30B6\u30FC: {name}",
251
+ "val.git_no_name": "git user.name \u304C\u672A\u8A2D\u5B9A",
252
+ "val.git_no_name_hint": 'git config --global user.name "Your Name" \u3067\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\uFF08cc-room \u306E identity \u306B\u4F7F\u7528\uFF09',
253
+ "val.git_missing": "git \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
254
+ "val.git_hint": "git \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044"
255
+ };
256
+ var catalogs = { en, ja };
257
+ var activeLocale = "en";
258
+ function setLocale(locale) {
259
+ activeLocale = locale;
260
+ }
261
+ function getLocale() {
262
+ return activeLocale;
263
+ }
264
+ function t(key, vars = {}) {
265
+ const catalog = catalogs[activeLocale] ?? catalogs.en;
266
+ let template = catalog[key] ?? catalogs.en[key] ?? key;
267
+ for (const [k, v] of Object.entries(vars)) {
268
+ template = template.replaceAll(`{${k}}`, String(v));
269
+ }
270
+ return template;
271
+ }
272
+
273
+ export {
274
+ resolveLocale,
275
+ setLocale,
276
+ getLocale,
277
+ t
278
+ };