setup-cc-room 0.2.2 → 0.2.3
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.
- package/dist/chunk-3AMPTQ5K.js +20 -0
- package/dist/chunk-DXODI3WA.js +151 -0
- package/dist/chunk-EF2H256X.js +131 -0
- package/dist/chunk-URM67EVS.js +123 -0
- package/dist/chunk-Z3DH4ZOT.js +125 -0
- package/dist/daemon-resolver.d.ts +1 -2
- package/dist/daemon-resolver.js +1 -3
- package/dist/index.js +7 -7
- package/dist/installer.js +5 -5
- package/dist/register-service.d.ts +3 -1
- package/dist/register-service.js +5 -2
- package/dist/settings-merger.d.ts +31 -1
- package/dist/settings-merger.js +8 -1
- package/dist/uninstaller.js +3 -3
- package/package.json +1 -1
- package/vendor/daemon/dist/index.js +20 -0
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
|
|
18
|
+
export {
|
|
19
|
+
resolveDaemonSource
|
|
20
|
+
};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
t
|
|
3
|
+
} from "./chunk-OYW7MM4W.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveCcRoomDir
|
|
6
|
+
} from "./chunk-WCEABGOA.js";
|
|
7
|
+
|
|
8
|
+
// src/settings-merger.ts
|
|
9
|
+
import { readFileSync, writeFileSync, existsSync, copyFileSync, mkdirSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
import { execFileSync } from "child_process";
|
|
13
|
+
var SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
|
|
14
|
+
function resolveDaemonCommand(env = process.env) {
|
|
15
|
+
const bundled = join(resolveCcRoomDir(env), "bin", "cc-room-daemon");
|
|
16
|
+
if (existsSync(bundled)) return bundled;
|
|
17
|
+
try {
|
|
18
|
+
const which = execFileSync("which", ["cc-room-daemon"], {
|
|
19
|
+
encoding: "utf-8",
|
|
20
|
+
stdio: "pipe"
|
|
21
|
+
}).trim();
|
|
22
|
+
if (which) return which;
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
return bundled;
|
|
26
|
+
}
|
|
27
|
+
function isCcRoomHookCommand(command) {
|
|
28
|
+
if (!command) return false;
|
|
29
|
+
return command.includes("cc-room-daemon") && command.includes("hook");
|
|
30
|
+
}
|
|
31
|
+
function buildCcRoomHooks(daemonBin) {
|
|
32
|
+
return {
|
|
33
|
+
UserPromptSubmit: [
|
|
34
|
+
{
|
|
35
|
+
hooks: [
|
|
36
|
+
{
|
|
37
|
+
type: "command",
|
|
38
|
+
command: `${daemonBin} hook user-prompt-submit`
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
PostToolUse: [
|
|
44
|
+
{
|
|
45
|
+
matcher: "Write|Edit",
|
|
46
|
+
hooks: [
|
|
47
|
+
{
|
|
48
|
+
type: "command",
|
|
49
|
+
command: `${daemonBin} hook post-tool-use`
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
Stop: [
|
|
55
|
+
{
|
|
56
|
+
hooks: [
|
|
57
|
+
{
|
|
58
|
+
type: "command",
|
|
59
|
+
command: `${daemonBin} hook session-stop`
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function buildCcRoomMcp(daemonBin) {
|
|
67
|
+
return {
|
|
68
|
+
"cc-room": {
|
|
69
|
+
type: "stdio",
|
|
70
|
+
command: daemonBin,
|
|
71
|
+
args: ["mcp"]
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function mergeSettings() {
|
|
76
|
+
let settings = {};
|
|
77
|
+
mkdirSync(join(homedir(), ".claude"), { recursive: true });
|
|
78
|
+
if (existsSync(SETTINGS_PATH)) {
|
|
79
|
+
try {
|
|
80
|
+
settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
|
|
81
|
+
} catch {
|
|
82
|
+
console.log(t("settings.parse_fail_backup"));
|
|
83
|
+
copyFileSync(SETTINGS_PATH, SETTINGS_PATH + ".backup");
|
|
84
|
+
settings = {};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const daemonBin = resolveDaemonCommand();
|
|
88
|
+
const ccRoomHooks = buildCcRoomHooks(daemonBin);
|
|
89
|
+
const ccRoomMcp = buildCcRoomMcp(daemonBin);
|
|
90
|
+
const existingHooks = settings.hooks ?? {};
|
|
91
|
+
const mergedHooks = { ...existingHooks };
|
|
92
|
+
for (const [event, newEntries] of Object.entries(ccRoomHooks)) {
|
|
93
|
+
const existing = mergedHooks[event] ?? [];
|
|
94
|
+
const filtered = existing.filter((e) => {
|
|
95
|
+
const entry = e;
|
|
96
|
+
return !entry.hooks?.some((h) => isCcRoomHookCommand(h.command));
|
|
97
|
+
});
|
|
98
|
+
mergedHooks[event] = [...filtered, ...newEntries];
|
|
99
|
+
}
|
|
100
|
+
const existingMcp = settings.mcpServers ?? {};
|
|
101
|
+
const mergedMcp = { ...existingMcp, ...ccRoomMcp };
|
|
102
|
+
settings.hooks = mergedHooks;
|
|
103
|
+
settings.mcpServers = mergedMcp;
|
|
104
|
+
writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n", { mode: 420 });
|
|
105
|
+
console.log(t("settings.updated", { path: SETTINGS_PATH }));
|
|
106
|
+
}
|
|
107
|
+
function stripCcRoomFromSettings(settings) {
|
|
108
|
+
const next = { ...settings };
|
|
109
|
+
const existingHooks = settings.hooks ?? {};
|
|
110
|
+
const strippedHooks = {};
|
|
111
|
+
for (const [event, entries] of Object.entries(existingHooks)) {
|
|
112
|
+
strippedHooks[event] = (entries ?? []).filter((e) => {
|
|
113
|
+
const entry = e;
|
|
114
|
+
return !entry.hooks?.some((h) => isCcRoomHookCommand(h.command));
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (Object.keys(existingHooks).length > 0 || Object.keys(strippedHooks).length > 0) {
|
|
118
|
+
next.hooks = strippedHooks;
|
|
119
|
+
}
|
|
120
|
+
const existingMcp = settings.mcpServers ?? {};
|
|
121
|
+
if (Object.keys(existingMcp).length > 0) {
|
|
122
|
+
const { ["cc-room"]: _removed, ...rest } = existingMcp;
|
|
123
|
+
next.mcpServers = rest;
|
|
124
|
+
}
|
|
125
|
+
return next;
|
|
126
|
+
}
|
|
127
|
+
function unmergeSettings() {
|
|
128
|
+
if (!existsSync(SETTINGS_PATH)) {
|
|
129
|
+
console.log(t("settings.skip_missing", { path: SETTINGS_PATH }));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let settings;
|
|
133
|
+
try {
|
|
134
|
+
settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
|
|
135
|
+
} catch {
|
|
136
|
+
console.log(t("settings.parse_fail_skip"));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const next = stripCcRoomFromSettings(settings);
|
|
140
|
+
writeFileSync(SETTINGS_PATH, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
|
|
141
|
+
console.log(t("settings.stripped", { path: SETTINGS_PATH }));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export {
|
|
145
|
+
resolveDaemonCommand,
|
|
146
|
+
buildCcRoomHooks,
|
|
147
|
+
buildCcRoomMcp,
|
|
148
|
+
mergeSettings,
|
|
149
|
+
stripCcRoomFromSettings,
|
|
150
|
+
unmergeSettings
|
|
151
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveDaemonCommand
|
|
3
|
+
} from "./chunk-DXODI3WA.js";
|
|
4
|
+
import {
|
|
5
|
+
t
|
|
6
|
+
} from "./chunk-OYW7MM4W.js";
|
|
7
|
+
import {
|
|
8
|
+
resolveCcRoomDir
|
|
9
|
+
} from "./chunk-WCEABGOA.js";
|
|
10
|
+
|
|
11
|
+
// src/register-service.ts
|
|
12
|
+
import { writeFileSync, mkdirSync, existsSync } from "fs";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { homedir, platform } from "os";
|
|
15
|
+
import { execFileSync } from "child_process";
|
|
16
|
+
var CC_ROOM_DIR = resolveCcRoomDir();
|
|
17
|
+
function escapeXml(text) {
|
|
18
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
19
|
+
}
|
|
20
|
+
function ccRoomHomeEnvXml() {
|
|
21
|
+
if (!process.env.CC_ROOM_HOME) return "";
|
|
22
|
+
return `
|
|
23
|
+
<key>CC_ROOM_HOME</key>
|
|
24
|
+
<string>${escapeXml(process.env.CC_ROOM_HOME)}</string>`;
|
|
25
|
+
}
|
|
26
|
+
function registerLaunchd() {
|
|
27
|
+
const plistDir = join(homedir(), "Library", "LaunchAgents");
|
|
28
|
+
const plistPath = join(plistDir, "dev.ccroom.daemon.plist");
|
|
29
|
+
const daemonBin = resolveDaemonCommand();
|
|
30
|
+
const logPath = join(CC_ROOM_DIR, "logs", "daemon.log");
|
|
31
|
+
mkdirSync(join(CC_ROOM_DIR, "logs"), { recursive: true });
|
|
32
|
+
mkdirSync(plistDir, { recursive: true });
|
|
33
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
34
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
35
|
+
<plist version="1.0">
|
|
36
|
+
<dict>
|
|
37
|
+
<key>Label</key>
|
|
38
|
+
<string>dev.ccroom.daemon</string>
|
|
39
|
+
<key>ProgramArguments</key>
|
|
40
|
+
<array>
|
|
41
|
+
<string>${escapeXml(daemonBin)}</string>
|
|
42
|
+
</array>
|
|
43
|
+
<key>KeepAlive</key>
|
|
44
|
+
<true/>
|
|
45
|
+
<key>RunAtLoad</key>
|
|
46
|
+
<true/>
|
|
47
|
+
<key>StandardOutPath</key>
|
|
48
|
+
<string>${escapeXml(logPath)}</string>
|
|
49
|
+
<key>StandardErrorPath</key>
|
|
50
|
+
<string>${escapeXml(logPath)}</string>
|
|
51
|
+
<key>EnvironmentVariables</key>
|
|
52
|
+
<dict>
|
|
53
|
+
<key>PATH</key>
|
|
54
|
+
<string>/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin</string>${ccRoomHomeEnvXml()}
|
|
55
|
+
</dict>
|
|
56
|
+
</dict>
|
|
57
|
+
</plist>
|
|
58
|
+
`;
|
|
59
|
+
writeFileSync(plistPath, plist, { mode: 420 });
|
|
60
|
+
try {
|
|
61
|
+
execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
execFileSync("launchctl", ["load", plistPath], { stdio: "pipe" });
|
|
66
|
+
console.log(t("svc.launchd_ok", { path: plistPath }));
|
|
67
|
+
} catch (err) {
|
|
68
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
69
|
+
console.log(t("svc.launchd_fail", { msg }));
|
|
70
|
+
console.log(t("svc.launchd_manual", { path: plistPath }));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function registerSystemd() {
|
|
74
|
+
const serviceDir = join(homedir(), ".config", "systemd", "user");
|
|
75
|
+
const servicePath = join(serviceDir, "cc-room-daemon.service");
|
|
76
|
+
const daemonBin = resolveDaemonCommand();
|
|
77
|
+
const logPath = join(CC_ROOM_DIR, "logs", "daemon.log");
|
|
78
|
+
mkdirSync(join(CC_ROOM_DIR, "logs"), { recursive: true });
|
|
79
|
+
mkdirSync(serviceDir, { recursive: true });
|
|
80
|
+
const envLine = process.env.CC_ROOM_HOME ? `Environment="CC_ROOM_HOME=${process.env.CC_ROOM_HOME}"
|
|
81
|
+
` : "";
|
|
82
|
+
const unit = `[Unit]
|
|
83
|
+
Description=cc-room daemon
|
|
84
|
+
After=network.target
|
|
85
|
+
|
|
86
|
+
[Service]
|
|
87
|
+
ExecStart=${daemonBin}
|
|
88
|
+
Restart=on-failure
|
|
89
|
+
RestartSec=5
|
|
90
|
+
${envLine}StandardOutput=append:${logPath}
|
|
91
|
+
StandardError=append:${logPath}
|
|
92
|
+
|
|
93
|
+
[Install]
|
|
94
|
+
WantedBy=default.target
|
|
95
|
+
`;
|
|
96
|
+
writeFileSync(servicePath, unit, { mode: 420 });
|
|
97
|
+
try {
|
|
98
|
+
execFileSync("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
|
|
99
|
+
execFileSync("systemctl", ["--user", "enable", "--now", "cc-room-daemon"], { stdio: "pipe" });
|
|
100
|
+
console.log(t("svc.systemd_ok", { path: servicePath }));
|
|
101
|
+
} catch (err) {
|
|
102
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
103
|
+
console.log(t("svc.systemd_fail", { msg }));
|
|
104
|
+
console.log(t("svc.systemd_manual"));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function registerService() {
|
|
108
|
+
const os = platform();
|
|
109
|
+
if (os === "darwin") {
|
|
110
|
+
registerLaunchd();
|
|
111
|
+
} else if (os === "linux") {
|
|
112
|
+
registerSystemd();
|
|
113
|
+
} else {
|
|
114
|
+
console.log(t("svc.unsupported", { os }));
|
|
115
|
+
}
|
|
116
|
+
const pidPath = join(CC_ROOM_DIR, "daemon.pid");
|
|
117
|
+
if (!existsSync(pidPath)) {
|
|
118
|
+
console.log(t("svc.waiting"));
|
|
119
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
120
|
+
}
|
|
121
|
+
if (existsSync(pidPath)) {
|
|
122
|
+
console.log(t("svc.started"));
|
|
123
|
+
} else {
|
|
124
|
+
console.log(t("svc.start_unconfirmed"));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
escapeXml,
|
|
130
|
+
registerService
|
|
131
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
unmergeSettings
|
|
3
|
+
} from "./chunk-DXODI3WA.js";
|
|
4
|
+
import {
|
|
5
|
+
t
|
|
6
|
+
} from "./chunk-OYW7MM4W.js";
|
|
7
|
+
import {
|
|
8
|
+
resolveCcRoomDir
|
|
9
|
+
} from "./chunk-WCEABGOA.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
|
+
if (platform() === "win32") {
|
|
88
|
+
spawnSync("taskkill", ["/F", "/IM", "cc-room-daemon.exe"], { stdio: "pipe" });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
spawnSync("pkill", ["-f", "cc-room-daemon"], { stdio: "pipe" });
|
|
92
|
+
}
|
|
93
|
+
async function uninstall() {
|
|
94
|
+
const ccRoomDir = resolveCcRoomDir();
|
|
95
|
+
const commandsDir = join(homedir(), ".claude", "commands");
|
|
96
|
+
const os = platform();
|
|
97
|
+
console.log(t("un.step1"));
|
|
98
|
+
if (os === "darwin") {
|
|
99
|
+
stopLaunchd(getLaunchdPlistPath());
|
|
100
|
+
} else if (os === "linux") {
|
|
101
|
+
stopSystemd(getSystemdUnitPath());
|
|
102
|
+
} else {
|
|
103
|
+
console.log(t("un.os_manual", { os }));
|
|
104
|
+
}
|
|
105
|
+
stopOrphanDaemon();
|
|
106
|
+
console.log(t("un.step2"));
|
|
107
|
+
removeCommandFiles(commandsDir);
|
|
108
|
+
console.log(t("un.step3"));
|
|
109
|
+
unmergeSettings();
|
|
110
|
+
console.log(t("un.step4"));
|
|
111
|
+
removeCcRoomData(ccRoomDir);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export {
|
|
115
|
+
getLaunchdPlistPath,
|
|
116
|
+
getSystemdUnitPath,
|
|
117
|
+
stopLaunchd,
|
|
118
|
+
stopSystemd,
|
|
119
|
+
removeCommandFiles,
|
|
120
|
+
removeCcRoomData,
|
|
121
|
+
stopOrphanDaemon,
|
|
122
|
+
uninstall
|
|
123
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveDaemonSource
|
|
3
|
+
} from "./chunk-3AMPTQ5K.js";
|
|
4
|
+
import {
|
|
5
|
+
registerService
|
|
6
|
+
} from "./chunk-EF2H256X.js";
|
|
7
|
+
import {
|
|
8
|
+
mergeSettings
|
|
9
|
+
} from "./chunk-DXODI3WA.js";
|
|
10
|
+
import {
|
|
11
|
+
t
|
|
12
|
+
} from "./chunk-OYW7MM4W.js";
|
|
13
|
+
import {
|
|
14
|
+
resolveCcRoomDir
|
|
15
|
+
} from "./chunk-WCEABGOA.js";
|
|
16
|
+
|
|
17
|
+
// src/installer.ts
|
|
18
|
+
import {
|
|
19
|
+
mkdirSync,
|
|
20
|
+
writeFileSync,
|
|
21
|
+
existsSync,
|
|
22
|
+
copyFileSync,
|
|
23
|
+
chmodSync,
|
|
24
|
+
unlinkSync
|
|
25
|
+
} from "fs";
|
|
26
|
+
import { join, dirname } from "path";
|
|
27
|
+
import { homedir } from "os";
|
|
28
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
29
|
+
import { fileURLToPath } from "url";
|
|
30
|
+
import { stringify } from "yaml";
|
|
31
|
+
var CC_ROOM_DIR = resolveCcRoomDir();
|
|
32
|
+
var BIN_DIR = join(CC_ROOM_DIR, "bin");
|
|
33
|
+
var CONFIG_PATH = join(CC_ROOM_DIR, "config.yaml");
|
|
34
|
+
var COMMANDS_DIR = join(homedir(), ".claude", "commands");
|
|
35
|
+
var THIS_DIR = dirname(fileURLToPath(import.meta.url));
|
|
36
|
+
var SETUP_PACKAGE_ROOT = join(THIS_DIR, "..");
|
|
37
|
+
function getGitUserName() {
|
|
38
|
+
try {
|
|
39
|
+
return execFileSync("git", ["config", "user.name"], { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
40
|
+
} catch {
|
|
41
|
+
return "unknown";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function resolveCommandSources(setupPackageRoot, locale) {
|
|
45
|
+
const candidates = [
|
|
46
|
+
join(setupPackageRoot, "vendor", "commands", "room", locale),
|
|
47
|
+
join(setupPackageRoot, "..", "commands", "room", locale),
|
|
48
|
+
// legacy flat layout (pre-i18n)
|
|
49
|
+
join(setupPackageRoot, "vendor", "commands", "room"),
|
|
50
|
+
join(setupPackageRoot, "..", "commands", "room")
|
|
51
|
+
];
|
|
52
|
+
for (const dir of candidates) {
|
|
53
|
+
if (existsSync(join(dir, "room.md"))) return dir;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
async function install(locale = "en") {
|
|
58
|
+
console.log(t("install.step1", { dir: CC_ROOM_DIR }));
|
|
59
|
+
mkdirSync(BIN_DIR, { recursive: true });
|
|
60
|
+
const daemonSrc = resolveDaemonSource(SETUP_PACKAGE_ROOT);
|
|
61
|
+
const daemonDest = join(BIN_DIR, "cc-room-daemon");
|
|
62
|
+
if (daemonSrc) {
|
|
63
|
+
copyFileSync(daemonSrc, daemonDest);
|
|
64
|
+
chmodSync(daemonDest, 493);
|
|
65
|
+
console.log(t("install.copied", { path: daemonDest }));
|
|
66
|
+
} else {
|
|
67
|
+
const globalBin = spawnSync("which", ["cc-room-daemon"], { encoding: "utf-8" });
|
|
68
|
+
if (globalBin.status === 0) {
|
|
69
|
+
console.log(t("install.global_ok", { path: globalBin.stdout.trim() }));
|
|
70
|
+
} else {
|
|
71
|
+
console.log(` \x1B[33m\u26A0 ${t("daemon.missing")}\x1B[0m`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
console.log(t("install.step2", { path: CONFIG_PATH }));
|
|
75
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
76
|
+
const identity = getGitUserName();
|
|
77
|
+
const config = {
|
|
78
|
+
identity: { name: identity },
|
|
79
|
+
ui: { locale },
|
|
80
|
+
network: { port: 7331, http_port: 7332 },
|
|
81
|
+
trust: [],
|
|
82
|
+
sessions: { default_mode: "approve", share_files: true, share_context: true },
|
|
83
|
+
privacy: {
|
|
84
|
+
public_tools: ["room_context", "room_messages", "room_files", "room_status", "room_invite", "room_share"],
|
|
85
|
+
private_patterns: [],
|
|
86
|
+
redact_after_private_tool: true
|
|
87
|
+
},
|
|
88
|
+
summarizer: { model: "claude-haiku-4-5-20251001", interval_turns: 5, interval_seconds: 30 },
|
|
89
|
+
storage: { max_bytes: 524288e3, artifact_ttl_days: 30, context_ttl_days: 7, message_ttl_days: 14 }
|
|
90
|
+
};
|
|
91
|
+
writeFileSync(CONFIG_PATH, stringify(config), { mode: 384 });
|
|
92
|
+
console.log(t("install.config_created", { path: CONFIG_PATH, identity }));
|
|
93
|
+
} else {
|
|
94
|
+
console.log(t("install.config_skip", { path: CONFIG_PATH }));
|
|
95
|
+
}
|
|
96
|
+
console.log(t("install.step3", { locale }));
|
|
97
|
+
mkdirSync(COMMANDS_DIR, { recursive: true });
|
|
98
|
+
const commandFiles = ["room.md", "private.md", "show.md"];
|
|
99
|
+
const legacyFiles = ["invite.md", "join.md", "leave.md", "files.md", "remember.md", "share.md"];
|
|
100
|
+
const commandsSrcDir = resolveCommandSources(SETUP_PACKAGE_ROOT, locale);
|
|
101
|
+
if (!commandsSrcDir) {
|
|
102
|
+
throw new Error(`Command source directory not found for locale=${locale}`);
|
|
103
|
+
}
|
|
104
|
+
for (const cmd of commandFiles) {
|
|
105
|
+
const src = join(commandsSrcDir, cmd);
|
|
106
|
+
if (!existsSync(src)) throw new Error(`Command source file not found: ${src}`);
|
|
107
|
+
copyFileSync(src, join(COMMANDS_DIR, cmd));
|
|
108
|
+
}
|
|
109
|
+
for (const legacy of legacyFiles) {
|
|
110
|
+
const dest = join(COMMANDS_DIR, legacy);
|
|
111
|
+
if (existsSync(dest)) {
|
|
112
|
+
unlinkSync(dest);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
console.log(t("install.commands_ok", { count: commandFiles.length, dir: COMMANDS_DIR }));
|
|
116
|
+
console.log(t("install.step4"));
|
|
117
|
+
mergeSettings();
|
|
118
|
+
console.log(t("install.step5"));
|
|
119
|
+
await registerService();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
resolveCommandSources,
|
|
124
|
+
install
|
|
125
|
+
};
|
|
@@ -3,6 +3,5 @@
|
|
|
3
3
|
* 優先: vendor 同梱(npm / pack:vendor)→ ローカル dist-bundle
|
|
4
4
|
*/
|
|
5
5
|
declare function resolveDaemonSource(setupPackageRoot: string): string | null;
|
|
6
|
-
declare const 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.";
|
|
7
6
|
|
|
8
|
-
export {
|
|
7
|
+
export { resolveDaemonSource };
|
package/dist/daemon-resolver.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -5,23 +5,23 @@ import {
|
|
|
5
5
|
} from "./chunk-RYVZHEHF.js";
|
|
6
6
|
import {
|
|
7
7
|
install
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-Z3DH4ZOT.js";
|
|
9
|
+
import "./chunk-3AMPTQ5K.js";
|
|
10
|
+
import "./chunk-EF2H256X.js";
|
|
11
11
|
import {
|
|
12
12
|
uninstall
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-MVD6RIS2.js";
|
|
13
|
+
} from "./chunk-URM67EVS.js";
|
|
14
|
+
import "./chunk-DXODI3WA.js";
|
|
16
15
|
import {
|
|
17
16
|
getLocale,
|
|
18
17
|
resolveLocale,
|
|
19
18
|
setLocale,
|
|
20
19
|
t
|
|
21
20
|
} from "./chunk-OYW7MM4W.js";
|
|
21
|
+
import "./chunk-WCEABGOA.js";
|
|
22
22
|
|
|
23
23
|
// src/index.ts
|
|
24
|
-
var VERSION = "0.2.
|
|
24
|
+
var VERSION = "0.2.3";
|
|
25
25
|
function stripLangArgs(argv) {
|
|
26
26
|
const out = [];
|
|
27
27
|
for (let i = 0; i < argv.length; i++) {
|
package/dist/installer.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
install,
|
|
3
3
|
resolveCommandSources
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-MVD6RIS2.js";
|
|
4
|
+
} from "./chunk-Z3DH4ZOT.js";
|
|
5
|
+
import "./chunk-3AMPTQ5K.js";
|
|
6
|
+
import "./chunk-EF2H256X.js";
|
|
7
|
+
import "./chunk-DXODI3WA.js";
|
|
9
8
|
import "./chunk-OYW7MM4W.js";
|
|
9
|
+
import "./chunk-WCEABGOA.js";
|
|
10
10
|
export {
|
|
11
11
|
install,
|
|
12
12
|
resolveCommandSources
|
package/dist/register-service.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
+
escapeXml,
|
|
2
3
|
registerService
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-EF2H256X.js";
|
|
5
|
+
import "./chunk-DXODI3WA.js";
|
|
5
6
|
import "./chunk-OYW7MM4W.js";
|
|
7
|
+
import "./chunk-WCEABGOA.js";
|
|
6
8
|
export {
|
|
9
|
+
escapeXml,
|
|
7
10
|
registerService
|
|
8
11
|
};
|
|
@@ -1,6 +1,36 @@
|
|
|
1
|
+
/** Claude Code hooks / MCP から呼ぶ daemon の絶対パスを解決する */
|
|
2
|
+
declare function resolveDaemonCommand(env?: NodeJS.ProcessEnv): string;
|
|
3
|
+
declare function buildCcRoomHooks(daemonBin: string): {
|
|
4
|
+
UserPromptSubmit: {
|
|
5
|
+
hooks: {
|
|
6
|
+
type: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
}[];
|
|
10
|
+
PostToolUse: {
|
|
11
|
+
matcher: string;
|
|
12
|
+
hooks: {
|
|
13
|
+
type: string;
|
|
14
|
+
command: string;
|
|
15
|
+
}[];
|
|
16
|
+
}[];
|
|
17
|
+
Stop: {
|
|
18
|
+
hooks: {
|
|
19
|
+
type: string;
|
|
20
|
+
command: string;
|
|
21
|
+
}[];
|
|
22
|
+
}[];
|
|
23
|
+
};
|
|
24
|
+
declare function buildCcRoomMcp(daemonBin: string): {
|
|
25
|
+
"cc-room": {
|
|
26
|
+
type: string;
|
|
27
|
+
command: string;
|
|
28
|
+
args: string[];
|
|
29
|
+
};
|
|
30
|
+
};
|
|
1
31
|
declare function mergeSettings(): void;
|
|
2
32
|
/** settings.json から cc-room の hooks / mcpServers を除去(他設定は保持) */
|
|
3
33
|
declare function stripCcRoomFromSettings(settings: Record<string, unknown>): Record<string, unknown>;
|
|
4
34
|
declare function unmergeSettings(): void;
|
|
5
35
|
|
|
6
|
-
export { mergeSettings, stripCcRoomFromSettings, unmergeSettings };
|
|
36
|
+
export { buildCcRoomHooks, buildCcRoomMcp, mergeSettings, resolveDaemonCommand, stripCcRoomFromSettings, unmergeSettings };
|
package/dist/settings-merger.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
buildCcRoomHooks,
|
|
3
|
+
buildCcRoomMcp,
|
|
2
4
|
mergeSettings,
|
|
5
|
+
resolveDaemonCommand,
|
|
3
6
|
stripCcRoomFromSettings,
|
|
4
7
|
unmergeSettings
|
|
5
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-DXODI3WA.js";
|
|
6
9
|
import "./chunk-OYW7MM4W.js";
|
|
10
|
+
import "./chunk-WCEABGOA.js";
|
|
7
11
|
export {
|
|
12
|
+
buildCcRoomHooks,
|
|
13
|
+
buildCcRoomMcp,
|
|
8
14
|
mergeSettings,
|
|
15
|
+
resolveDaemonCommand,
|
|
9
16
|
stripCcRoomFromSettings,
|
|
10
17
|
unmergeSettings
|
|
11
18
|
};
|
package/dist/uninstaller.js
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
stopOrphanDaemon,
|
|
8
8
|
stopSystemd,
|
|
9
9
|
uninstall
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-MVD6RIS2.js";
|
|
10
|
+
} from "./chunk-URM67EVS.js";
|
|
11
|
+
import "./chunk-DXODI3WA.js";
|
|
13
12
|
import "./chunk-OYW7MM4W.js";
|
|
13
|
+
import "./chunk-WCEABGOA.js";
|
|
14
14
|
export {
|
|
15
15
|
getLaunchdPlistPath,
|
|
16
16
|
getSystemdUnitPath,
|
package/package.json
CHANGED
|
@@ -48778,6 +48778,18 @@ var PeerConnector = class extends import_node_events3.EventEmitter {
|
|
|
48778
48778
|
const conn = this.connections.get(key);
|
|
48779
48779
|
return conn?.ws.readyState === wrapper_default.OPEN || false;
|
|
48780
48780
|
}
|
|
48781
|
+
/** 退室時: 再接続せずに当該ルームの outbound を切る */
|
|
48782
|
+
disconnectRoom(roomId) {
|
|
48783
|
+
for (const [key, conn] of [...this.connections.entries()]) {
|
|
48784
|
+
if (conn.roomId !== roomId) continue;
|
|
48785
|
+
conn.skipReconnect = true;
|
|
48786
|
+
this.cleanupConnection(conn);
|
|
48787
|
+
if (conn.ws.readyState === wrapper_default.OPEN || conn.ws.readyState === wrapper_default.CONNECTING) {
|
|
48788
|
+
conn.ws.close(1e3, "Left room");
|
|
48789
|
+
}
|
|
48790
|
+
this.connections.delete(key);
|
|
48791
|
+
}
|
|
48792
|
+
}
|
|
48781
48793
|
cleanupConnection(conn) {
|
|
48782
48794
|
if (conn.pingInterval) {
|
|
48783
48795
|
clearInterval(conn.pingInterval);
|
|
@@ -51252,6 +51264,12 @@ ${conversationText}`
|
|
|
51252
51264
|
const error2 = err && typeof err === "object" ? err : {};
|
|
51253
51265
|
const status = typeof error2.status === "number" ? error2.status : void 0;
|
|
51254
51266
|
const headers = error2.headers && typeof error2.headers === "object" ? error2.headers : void 0;
|
|
51267
|
+
if (status === 401 || status === 403) {
|
|
51268
|
+
log9.warn({ err, status }, "Auth failed, entering fallback mode");
|
|
51269
|
+
this.fallbackMode = true;
|
|
51270
|
+
this.fallbackUntil = Date.now() + SUMMARIZER_FALLBACK_DURATION_MS;
|
|
51271
|
+
return this.localFallbackSummary(turns);
|
|
51272
|
+
}
|
|
51255
51273
|
if (attempt === SUMMARIZER_MAX_RETRIES) {
|
|
51256
51274
|
log9.warn({ err }, "All retries exhausted, entering fallback mode");
|
|
51257
51275
|
this.fallbackMode = true;
|
|
@@ -53167,7 +53185,9 @@ async function main() {
|
|
|
53167
53185
|
if (!meta) {
|
|
53168
53186
|
return { ok: false, message: "Room not found" };
|
|
53169
53187
|
}
|
|
53188
|
+
peerConnector.disconnectRoom(body.room_id);
|
|
53170
53189
|
server.unregisterRoom(body.room_id);
|
|
53190
|
+
discovery.removeRoomAdvertisement(body.room_id);
|
|
53171
53191
|
notifier.notify({ type: "room_closed", room: meta.name });
|
|
53172
53192
|
const remaining = storage.listRooms().filter((r2) => r2.id !== body.room_id).map((r2) => r2.id);
|
|
53173
53193
|
showState.onRoomLeave(body.room_id, remaining);
|