setup-cc-room 0.2.0

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,78 @@
1
+ // src/settings-merger.ts
2
+ import { readFileSync, writeFileSync, existsSync, copyFileSync, mkdirSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ var SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
6
+ var CC_ROOM_HOOKS = {
7
+ UserPromptSubmit: [
8
+ {
9
+ hooks: [
10
+ {
11
+ type: "command",
12
+ command: "cc-room-daemon hook user-prompt-submit"
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ PostToolUse: [
18
+ {
19
+ matcher: "Write|Edit",
20
+ hooks: [
21
+ {
22
+ type: "command",
23
+ command: "cc-room-daemon hook post-tool-use"
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ Stop: [
29
+ {
30
+ hooks: [
31
+ {
32
+ type: "command",
33
+ command: "cc-room-daemon hook session-stop"
34
+ }
35
+ ]
36
+ }
37
+ ]
38
+ };
39
+ var CC_ROOM_MCP = {
40
+ "cc-room": {
41
+ type: "stdio",
42
+ command: "cc-room-daemon",
43
+ args: ["mcp"]
44
+ }
45
+ };
46
+ function mergeSettings() {
47
+ let settings = {};
48
+ mkdirSync(join(homedir(), ".claude"), { recursive: true });
49
+ if (existsSync(SETTINGS_PATH)) {
50
+ try {
51
+ settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
52
+ } catch {
53
+ console.log(" \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");
54
+ copyFileSync(SETTINGS_PATH, SETTINGS_PATH + ".backup");
55
+ settings = {};
56
+ }
57
+ }
58
+ const existingHooks = settings.hooks ?? {};
59
+ const mergedHooks = { ...existingHooks };
60
+ for (const [event, newEntries] of Object.entries(CC_ROOM_HOOKS)) {
61
+ const existing = mergedHooks[event] ?? [];
62
+ const filtered = existing.filter((e) => {
63
+ const entry = e;
64
+ return !entry.hooks?.some((h) => h.command?.startsWith("cc-room-daemon hook"));
65
+ });
66
+ mergedHooks[event] = [...filtered, ...newEntries];
67
+ }
68
+ const existingMcp = settings.mcpServers ?? {};
69
+ const mergedMcp = { ...existingMcp, ...CC_ROOM_MCP };
70
+ settings.hooks = mergedHooks;
71
+ settings.mcpServers = mergedMcp;
72
+ writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n", { mode: 420 });
73
+ console.log(` ${SETTINGS_PATH} \u3092\u66F4\u65B0\u3057\u307E\u3057\u305F`);
74
+ }
75
+
76
+ export {
77
+ mergeSettings
78
+ };
@@ -0,0 +1,111 @@
1
+ import {
2
+ registerService
3
+ } from "./chunk-XFCYRKG6.js";
4
+ import {
5
+ mergeSettings
6
+ } from "./chunk-5NTML4PF.js";
7
+
8
+ // src/installer.ts
9
+ import {
10
+ mkdirSync,
11
+ writeFileSync,
12
+ existsSync,
13
+ copyFileSync,
14
+ chmodSync,
15
+ unlinkSync
16
+ } from "fs";
17
+ import { join, dirname } from "path";
18
+ import { homedir } from "os";
19
+ import { execFileSync, spawnSync } from "child_process";
20
+ import { fileURLToPath } from "url";
21
+ import { stringify } from "yaml";
22
+ var CC_ROOM_DIR = join(homedir(), ".cc-room");
23
+ var BIN_DIR = join(CC_ROOM_DIR, "bin");
24
+ var CONFIG_PATH = join(CC_ROOM_DIR, "config.yaml");
25
+ var COMMANDS_DIR = join(homedir(), ".claude", "commands");
26
+ var THIS_DIR = dirname(fileURLToPath(import.meta.url));
27
+ function getGitUserName() {
28
+ try {
29
+ return execFileSync("git", ["config", "user.name"], { encoding: "utf-8", stdio: "pipe" }).trim();
30
+ } catch {
31
+ return "unknown";
32
+ }
33
+ }
34
+ function findDaemonBin() {
35
+ const candidates = [
36
+ join(THIS_DIR, "..", "vendor", "daemon", "dist", "index.js"),
37
+ join(THIS_DIR, "..", "..", "daemon", "dist", "index.js"),
38
+ join(THIS_DIR, "..", "..", "..", "node_modules", "@cc-room", "daemon", "dist", "index.js")
39
+ ];
40
+ for (const c of candidates) {
41
+ if (existsSync(c)) return c;
42
+ }
43
+ return null;
44
+ }
45
+ async function install() {
46
+ console.log(" [1/5] ~/.cc-room/bin/ \u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7...");
47
+ mkdirSync(BIN_DIR, { recursive: true });
48
+ const daemonSrc = findDaemonBin();
49
+ const daemonDest = join(BIN_DIR, "cc-room-daemon");
50
+ if (daemonSrc) {
51
+ copyFileSync(daemonSrc, daemonDest);
52
+ chmodSync(daemonDest, 493);
53
+ console.log(` \u30B3\u30D4\u30FC\u5B8C\u4E86: ${daemonDest}`);
54
+ } else {
55
+ const globalBin = spawnSync("which", ["cc-room-daemon"], { encoding: "utf-8" });
56
+ if (globalBin.status === 0) {
57
+ console.log(` \u30B0\u30ED\u30FC\u30D0\u30EB\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u78BA\u8A8D\u6E08\u307F: ${globalBin.stdout.trim()}`);
58
+ } else {
59
+ console.log(" \x1B[33m\u26A0 cc-room-daemon \u30D0\u30A4\u30CA\u30EA\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002npm install -g @cc-room/daemon \u3067\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044\u3002\x1B[0m");
60
+ }
61
+ }
62
+ console.log(" [2/5] ~/.cc-room/config.yaml \u306E\u751F\u6210...");
63
+ if (!existsSync(CONFIG_PATH)) {
64
+ const identity = getGitUserName();
65
+ const config = {
66
+ identity: { name: identity },
67
+ network: { port: 7331, http_port: 7332 },
68
+ trust: [],
69
+ sessions: { default_mode: "approve", share_files: true, share_context: true },
70
+ privacy: {
71
+ public_tools: ["room_context", "room_messages", "room_files", "room_status", "room_invite", "room_share"],
72
+ private_patterns: [],
73
+ redact_after_private_tool: true
74
+ },
75
+ summarizer: { model: "claude-haiku-4-5-20251001", interval_turns: 5, interval_seconds: 30 },
76
+ storage: { max_bytes: 524288e3, artifact_ttl_days: 30, context_ttl_days: 7, message_ttl_days: 14 }
77
+ };
78
+ writeFileSync(CONFIG_PATH, stringify(config), { mode: 384 });
79
+ console.log(` \u751F\u6210\u5B8C\u4E86: ${CONFIG_PATH} (identity: ${identity})`);
80
+ } else {
81
+ console.log(` \u30B9\u30AD\u30C3\u30D7: ${CONFIG_PATH} \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059`);
82
+ }
83
+ console.log(" [3/5] \u30B3\u30DE\u30F3\u30C9\u30D5\u30A1\u30A4\u30EB\u306E\u914D\u7F6E...");
84
+ mkdirSync(COMMANDS_DIR, { recursive: true });
85
+ const commandFiles = ["room.md", "private.md", "show.md"];
86
+ const legacyFiles = ["invite.md", "join.md", "leave.md", "files.md", "remember.md", "share.md"];
87
+ for (const cmd of commandFiles) {
88
+ const src = [
89
+ join(THIS_DIR, "..", "vendor", "commands", "room", cmd),
90
+ join(THIS_DIR, "..", "..", "commands", "room", cmd),
91
+ join(THIS_DIR, "..", "commands", "room", cmd)
92
+ ].find(existsSync);
93
+ if (!src) throw new Error(`Command source file not found: ${cmd}`);
94
+ copyFileSync(src, join(COMMANDS_DIR, cmd));
95
+ }
96
+ for (const legacy of legacyFiles) {
97
+ const dest = join(COMMANDS_DIR, legacy);
98
+ if (existsSync(dest)) {
99
+ unlinkSync(dest);
100
+ }
101
+ }
102
+ console.log(` ${commandFiles.length} \u30D5\u30A1\u30A4\u30EB\u3092 ${COMMANDS_DIR} \u306B\u914D\u7F6E\u3057\u307E\u3057\u305F`);
103
+ console.log(" [4/5] .claude/settings.json \u306E\u66F4\u65B0...");
104
+ mergeSettings();
105
+ console.log(" [5/5] OS\u81EA\u52D5\u8D77\u52D5\u306E\u767B\u9332...");
106
+ await registerService();
107
+ }
108
+
109
+ export {
110
+ install
111
+ };
@@ -0,0 +1,165 @@
1
+ // src/validators.ts
2
+ import { execFileSync } from "child_process";
3
+ import { existsSync, readFileSync, accessSync, constants } from "fs";
4
+ import { join } from "path";
5
+ import { homedir } from "os";
6
+ function validateAll() {
7
+ const checks = [
8
+ checkNodeVersion(),
9
+ checkClaudeCodeInstalled(),
10
+ checkClaudeDir(),
11
+ checkSettingsWritable(),
12
+ checkHooksNotDisabled(),
13
+ checkMcpNotBlocked(),
14
+ checkSessionDir(),
15
+ checkGitUser()
16
+ ];
17
+ const passed = checks.every((r) => r.ok);
18
+ return { passed, results: checks };
19
+ }
20
+ function printResults(results) {
21
+ console.log("\n Preflight checks:\n");
22
+ for (const r of results) {
23
+ const icon = r.ok ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
24
+ console.log(` ${icon} ${r.message}`);
25
+ if (!r.ok && r.hint) {
26
+ console.log(` \x1B[33m\u2192 ${r.hint}\x1B[0m`);
27
+ }
28
+ }
29
+ console.log("");
30
+ }
31
+ function checkNodeVersion() {
32
+ const major = parseInt(process.versions.node.split(".")[0], 10);
33
+ if (major >= 20) {
34
+ return { ok: true, message: `Node.js ${process.versions.node}` };
35
+ }
36
+ return {
37
+ ok: false,
38
+ message: `Node.js ${process.versions.node} (20+ \u304C\u5FC5\u8981)`,
39
+ hint: "Node.js 20 \u4EE5\u4E0A\u306B\u30A2\u30C3\u30D7\u30B0\u30EC\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044: https://nodejs.org/"
40
+ };
41
+ }
42
+ function checkClaudeCodeInstalled() {
43
+ try {
44
+ execFileSync("claude", ["--version"], { encoding: "utf-8", stdio: "pipe" });
45
+ return { ok: true, message: "Claude Code \u304C\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u6E08\u307F" };
46
+ } catch {
47
+ return {
48
+ ok: false,
49
+ message: "Claude Code \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
50
+ hint: "Claude Code \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044: https://claude.ai/code"
51
+ };
52
+ }
53
+ }
54
+ function checkClaudeDir() {
55
+ const claudeDir = join(homedir(), ".claude");
56
+ if (existsSync(claudeDir)) {
57
+ return { ok: true, message: "~/.claude/ \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728" };
58
+ }
59
+ return {
60
+ ok: false,
61
+ message: "~/.claude/ \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
62
+ hint: "Claude Code \u3092\u4E00\u5EA6\u8D77\u52D5\u3057\u3066\u30BB\u30C3\u30B7\u30E7\u30F3\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044"
63
+ };
64
+ }
65
+ function checkSettingsWritable() {
66
+ const settingsPath = join(homedir(), ".claude", "settings.json");
67
+ const settingsDir = join(homedir(), ".claude");
68
+ if (existsSync(settingsPath)) {
69
+ try {
70
+ accessSync(settingsPath, constants.W_OK);
71
+ return { ok: true, message: "settings.json \u306B\u66F8\u304D\u8FBC\u307F\u53EF\u80FD" };
72
+ } catch {
73
+ return {
74
+ ok: false,
75
+ message: "settings.json \u306B\u66F8\u304D\u8FBC\u307F\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093",
76
+ hint: `chmod 644 ${settingsPath} \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044`
77
+ };
78
+ }
79
+ }
80
+ try {
81
+ accessSync(settingsDir, constants.W_OK);
82
+ return { ok: true, message: "settings.json \u3092\u4F5C\u6210\u53EF\u80FD" };
83
+ } catch {
84
+ return {
85
+ ok: false,
86
+ message: "~/.claude/ \u306B\u66F8\u304D\u8FBC\u307F\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093",
87
+ hint: `chmod 755 ${settingsDir} \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044`
88
+ };
89
+ }
90
+ }
91
+ function checkHooksNotDisabled() {
92
+ const settingsPath = join(homedir(), ".claude", "settings.json");
93
+ if (!existsSync(settingsPath)) {
94
+ return { ok: true, message: "Hooks: \u5236\u9650\u306A\u3057\uFF08settings.json \u672A\u4F5C\u6210\uFF09" };
95
+ }
96
+ try {
97
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
98
+ if (settings.hooks === false || settings.disableHooks === true) {
99
+ return {
100
+ ok: false,
101
+ message: "Hooks \u304C\u7121\u52B9\u5316\u3055\u308C\u3066\u3044\u307E\u3059",
102
+ 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"
103
+ };
104
+ }
105
+ return { ok: true, message: "Hooks: \u6709\u52B9" };
106
+ } catch {
107
+ return { ok: true, message: "Hooks: \u5236\u9650\u306A\u3057" };
108
+ }
109
+ }
110
+ function checkMcpNotBlocked() {
111
+ const settingsPath = join(homedir(), ".claude", "settings.json");
112
+ if (!existsSync(settingsPath)) {
113
+ return { ok: true, message: "MCP Server: \u767B\u9332\u53EF\u80FD" };
114
+ }
115
+ try {
116
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
117
+ if (settings.mcpServers === false || settings.disableMcp === true) {
118
+ return {
119
+ ok: false,
120
+ message: "MCP Server \u306E\u767B\u9332\u304C\u7121\u52B9\u5316\u3055\u308C\u3066\u3044\u307E\u3059",
121
+ 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"
122
+ };
123
+ }
124
+ return { ok: true, message: "MCP Server: \u767B\u9332\u53EF\u80FD" };
125
+ } catch {
126
+ return { ok: true, message: "MCP Server: \u767B\u9332\u53EF\u80FD" };
127
+ }
128
+ }
129
+ function checkSessionDir() {
130
+ const projectsDir = join(homedir(), ".claude", "projects");
131
+ if (existsSync(projectsDir)) {
132
+ return { ok: true, message: "\u30BB\u30C3\u30B7\u30E7\u30F3\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728" };
133
+ }
134
+ return {
135
+ ok: true,
136
+ message: "\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"
137
+ };
138
+ }
139
+ function checkGitUser() {
140
+ try {
141
+ const name = execFileSync("git", ["config", "user.name"], {
142
+ encoding: "utf-8",
143
+ stdio: "pipe"
144
+ }).trim();
145
+ if (name) {
146
+ return { ok: true, message: `Git \u30E6\u30FC\u30B6\u30FC: ${name}` };
147
+ }
148
+ return {
149
+ ok: false,
150
+ message: "git user.name \u304C\u672A\u8A2D\u5B9A",
151
+ 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'
152
+ };
153
+ } catch {
154
+ return {
155
+ ok: false,
156
+ message: "git \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
157
+ hint: "git \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044"
158
+ };
159
+ }
160
+ }
161
+
162
+ export {
163
+ validateAll,
164
+ printResults
165
+ };
@@ -0,0 +1,105 @@
1
+ import {
2
+ DAEMON_MISSING_HINT,
3
+ resolveDaemonSource
4
+ } from "./chunk-R5BAC4BK.js";
5
+ import {
6
+ registerService
7
+ } from "./chunk-XFCYRKG6.js";
8
+ import {
9
+ mergeSettings
10
+ } from "./chunk-5NTML4PF.js";
11
+
12
+ // src/installer.ts
13
+ import {
14
+ mkdirSync,
15
+ writeFileSync,
16
+ existsSync,
17
+ copyFileSync,
18
+ chmodSync,
19
+ unlinkSync
20
+ } from "fs";
21
+ import { join, dirname } from "path";
22
+ import { homedir } from "os";
23
+ import { execFileSync, spawnSync } from "child_process";
24
+ import { fileURLToPath } from "url";
25
+ import { stringify } from "yaml";
26
+ var CC_ROOM_DIR = join(homedir(), ".cc-room");
27
+ var BIN_DIR = join(CC_ROOM_DIR, "bin");
28
+ var CONFIG_PATH = join(CC_ROOM_DIR, "config.yaml");
29
+ var COMMANDS_DIR = join(homedir(), ".claude", "commands");
30
+ var THIS_DIR = dirname(fileURLToPath(import.meta.url));
31
+ var SETUP_PACKAGE_ROOT = join(THIS_DIR, "..");
32
+ function getGitUserName() {
33
+ try {
34
+ return execFileSync("git", ["config", "user.name"], { encoding: "utf-8", stdio: "pipe" }).trim();
35
+ } catch {
36
+ return "unknown";
37
+ }
38
+ }
39
+ async function install() {
40
+ console.log(" [1/5] ~/.cc-room/bin/ \u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7...");
41
+ mkdirSync(BIN_DIR, { recursive: true });
42
+ const daemonSrc = resolveDaemonSource(SETUP_PACKAGE_ROOT);
43
+ const daemonDest = join(BIN_DIR, "cc-room-daemon");
44
+ if (daemonSrc) {
45
+ copyFileSync(daemonSrc, daemonDest);
46
+ chmodSync(daemonDest, 493);
47
+ console.log(` \u30B3\u30D4\u30FC\u5B8C\u4E86: ${daemonDest}`);
48
+ } else {
49
+ const globalBin = spawnSync("which", ["cc-room-daemon"], { encoding: "utf-8" });
50
+ if (globalBin.status === 0) {
51
+ console.log(` \u30B0\u30ED\u30FC\u30D0\u30EB\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u78BA\u8A8D\u6E08\u307F: ${globalBin.stdout.trim()}`);
52
+ } else {
53
+ console.log(` \x1B[33m\u26A0 ${DAEMON_MISSING_HINT}\x1B[0m`);
54
+ }
55
+ }
56
+ console.log(" [2/5] ~/.cc-room/config.yaml \u306E\u751F\u6210...");
57
+ if (!existsSync(CONFIG_PATH)) {
58
+ const identity = getGitUserName();
59
+ const config = {
60
+ identity: { name: identity },
61
+ network: { port: 7331, http_port: 7332 },
62
+ trust: [],
63
+ sessions: { default_mode: "approve", share_files: true, share_context: true },
64
+ privacy: {
65
+ public_tools: ["room_context", "room_messages", "room_files", "room_status", "room_invite", "room_share"],
66
+ private_patterns: [],
67
+ redact_after_private_tool: true
68
+ },
69
+ summarizer: { model: "claude-haiku-4-5-20251001", interval_turns: 5, interval_seconds: 30 },
70
+ storage: { max_bytes: 524288e3, artifact_ttl_days: 30, context_ttl_days: 7, message_ttl_days: 14 }
71
+ };
72
+ writeFileSync(CONFIG_PATH, stringify(config), { mode: 384 });
73
+ console.log(` \u751F\u6210\u5B8C\u4E86: ${CONFIG_PATH} (identity: ${identity})`);
74
+ } else {
75
+ console.log(` \u30B9\u30AD\u30C3\u30D7: ${CONFIG_PATH} \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059`);
76
+ }
77
+ console.log(" [3/5] \u30B3\u30DE\u30F3\u30C9\u30D5\u30A1\u30A4\u30EB\u306E\u914D\u7F6E...");
78
+ mkdirSync(COMMANDS_DIR, { recursive: true });
79
+ const commandFiles = ["room.md", "private.md", "show.md"];
80
+ const legacyFiles = ["invite.md", "join.md", "leave.md", "files.md", "remember.md", "share.md"];
81
+ for (const cmd of commandFiles) {
82
+ const src = [
83
+ join(THIS_DIR, "..", "vendor", "commands", "room", cmd),
84
+ join(THIS_DIR, "..", "..", "commands", "room", cmd),
85
+ join(THIS_DIR, "..", "commands", "room", cmd)
86
+ ].find(existsSync);
87
+ if (!src) throw new Error(`Command source file not found: ${cmd}`);
88
+ copyFileSync(src, join(COMMANDS_DIR, cmd));
89
+ }
90
+ for (const legacy of legacyFiles) {
91
+ const dest = join(COMMANDS_DIR, legacy);
92
+ if (existsSync(dest)) {
93
+ unlinkSync(dest);
94
+ }
95
+ }
96
+ console.log(` ${commandFiles.length} \u30D5\u30A1\u30A4\u30EB\u3092 ${COMMANDS_DIR} \u306B\u914D\u7F6E\u3057\u307E\u3057\u305F`);
97
+ console.log(" [4/5] .claude/settings.json \u306E\u66F4\u65B0...");
98
+ mergeSettings();
99
+ console.log(" [5/5] OS\u81EA\u52D5\u8D77\u52D5\u306E\u767B\u9332...");
100
+ await registerService();
101
+ }
102
+
103
+ export {
104
+ install
105
+ };
@@ -0,0 +1,108 @@
1
+ import {
2
+ DAEMON_MISSING_HINT,
3
+ resolveDaemonSource
4
+ } from "./chunk-R5BAC4BK.js";
5
+ import {
6
+ registerService
7
+ } from "./chunk-UWFC4FU6.js";
8
+ import {
9
+ resolveCcRoomDir
10
+ } from "./chunk-WCEABGOA.js";
11
+ import {
12
+ mergeSettings
13
+ } from "./chunk-5NTML4PF.js";
14
+
15
+ // src/installer.ts
16
+ import {
17
+ mkdirSync,
18
+ writeFileSync,
19
+ existsSync,
20
+ copyFileSync,
21
+ chmodSync,
22
+ unlinkSync
23
+ } from "fs";
24
+ import { join, dirname } from "path";
25
+ import { homedir } from "os";
26
+ import { execFileSync, spawnSync } from "child_process";
27
+ import { fileURLToPath } from "url";
28
+ import { stringify } from "yaml";
29
+ var CC_ROOM_DIR = resolveCcRoomDir();
30
+ var BIN_DIR = join(CC_ROOM_DIR, "bin");
31
+ var CONFIG_PATH = join(CC_ROOM_DIR, "config.yaml");
32
+ var COMMANDS_DIR = join(homedir(), ".claude", "commands");
33
+ var THIS_DIR = dirname(fileURLToPath(import.meta.url));
34
+ var SETUP_PACKAGE_ROOT = join(THIS_DIR, "..");
35
+ function getGitUserName() {
36
+ try {
37
+ return execFileSync("git", ["config", "user.name"], { encoding: "utf-8", stdio: "pipe" }).trim();
38
+ } catch {
39
+ return "unknown";
40
+ }
41
+ }
42
+ async function install() {
43
+ console.log(` [1/5] ${CC_ROOM_DIR}/bin/ \u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7...`);
44
+ mkdirSync(BIN_DIR, { recursive: true });
45
+ const daemonSrc = resolveDaemonSource(SETUP_PACKAGE_ROOT);
46
+ const daemonDest = join(BIN_DIR, "cc-room-daemon");
47
+ if (daemonSrc) {
48
+ copyFileSync(daemonSrc, daemonDest);
49
+ chmodSync(daemonDest, 493);
50
+ console.log(` \u30B3\u30D4\u30FC\u5B8C\u4E86: ${daemonDest}`);
51
+ } else {
52
+ const globalBin = spawnSync("which", ["cc-room-daemon"], { encoding: "utf-8" });
53
+ if (globalBin.status === 0) {
54
+ console.log(` \u30B0\u30ED\u30FC\u30D0\u30EB\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u78BA\u8A8D\u6E08\u307F: ${globalBin.stdout.trim()}`);
55
+ } else {
56
+ console.log(` \x1B[33m\u26A0 ${DAEMON_MISSING_HINT}\x1B[0m`);
57
+ }
58
+ }
59
+ console.log(` [2/5] ${CONFIG_PATH} \u306E\u751F\u6210...`);
60
+ if (!existsSync(CONFIG_PATH)) {
61
+ const identity = getGitUserName();
62
+ const config = {
63
+ identity: { name: identity },
64
+ network: { port: 7331, http_port: 7332 },
65
+ trust: [],
66
+ sessions: { default_mode: "approve", share_files: true, share_context: true },
67
+ privacy: {
68
+ public_tools: ["room_context", "room_messages", "room_files", "room_status", "room_invite", "room_share"],
69
+ private_patterns: [],
70
+ redact_after_private_tool: true
71
+ },
72
+ summarizer: { model: "claude-haiku-4-5-20251001", interval_turns: 5, interval_seconds: 30 },
73
+ storage: { max_bytes: 524288e3, artifact_ttl_days: 30, context_ttl_days: 7, message_ttl_days: 14 }
74
+ };
75
+ writeFileSync(CONFIG_PATH, stringify(config), { mode: 384 });
76
+ console.log(` \u751F\u6210\u5B8C\u4E86: ${CONFIG_PATH} (identity: ${identity})`);
77
+ } else {
78
+ console.log(` \u30B9\u30AD\u30C3\u30D7: ${CONFIG_PATH} \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059`);
79
+ }
80
+ console.log(" [3/5] \u30B3\u30DE\u30F3\u30C9\u30D5\u30A1\u30A4\u30EB\u306E\u914D\u7F6E...");
81
+ mkdirSync(COMMANDS_DIR, { recursive: true });
82
+ const commandFiles = ["room.md", "private.md", "show.md"];
83
+ const legacyFiles = ["invite.md", "join.md", "leave.md", "files.md", "remember.md", "share.md"];
84
+ for (const cmd of commandFiles) {
85
+ const src = [
86
+ join(THIS_DIR, "..", "vendor", "commands", "room", cmd),
87
+ join(THIS_DIR, "..", "..", "commands", "room", cmd),
88
+ join(THIS_DIR, "..", "commands", "room", cmd)
89
+ ].find(existsSync);
90
+ if (!src) throw new Error(`Command source file not found: ${cmd}`);
91
+ copyFileSync(src, join(COMMANDS_DIR, cmd));
92
+ }
93
+ for (const legacy of legacyFiles) {
94
+ const dest = join(COMMANDS_DIR, legacy);
95
+ if (existsSync(dest)) {
96
+ unlinkSync(dest);
97
+ }
98
+ }
99
+ console.log(` ${commandFiles.length} \u30D5\u30A1\u30A4\u30EB\u3092 ${COMMANDS_DIR} \u306B\u914D\u7F6E\u3057\u307E\u3057\u305F`);
100
+ console.log(" [4/5] .claude/settings.json \u306E\u66F4\u65B0...");
101
+ mergeSettings();
102
+ console.log(" [5/5] OS\u81EA\u52D5\u8D77\u52D5\u306E\u767B\u9332...");
103
+ await registerService();
104
+ }
105
+
106
+ export {
107
+ install
108
+ };
@@ -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 \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";
18
+
19
+ export {
20
+ resolveDaemonSource,
21
+ DAEMON_MISSING_HINT
22
+ };