kiri-mcp-server 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.
- package/LICENSE +21 -0
- package/README.md +399 -0
- package/config/default.example.yml +12 -0
- package/config/denylist.yml +15 -0
- package/config/scoring-profiles.yml +37 -0
- package/config/security.yml +10 -0
- package/dist/client/cli.js +68 -0
- package/dist/client/cli.js.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/config/default.example.yml +12 -0
- package/dist/config/denylist.yml +15 -0
- package/dist/config/scoring-profiles.yml +37 -0
- package/dist/config/security.yml +10 -0
- package/dist/eval/metrics.js +47 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/indexer/cli.js +362 -0
- package/dist/indexer/cli.js.map +1 -0
- package/dist/indexer/codeintel.js +182 -0
- package/dist/indexer/codeintel.js.map +1 -0
- package/dist/indexer/git.js +30 -0
- package/dist/indexer/git.js.map +1 -0
- package/dist/indexer/language.js +34 -0
- package/dist/indexer/language.js.map +1 -0
- package/dist/indexer/pipeline/filters/denylist.js +71 -0
- package/dist/indexer/pipeline/filters/denylist.js.map +1 -0
- package/dist/indexer/schema.js +101 -0
- package/dist/indexer/schema.js.map +1 -0
- package/dist/package.json +93 -0
- package/dist/server/bootstrap.js +19 -0
- package/dist/server/bootstrap.js.map +1 -0
- package/dist/server/context.js +2 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/fallbacks/degradeController.js +69 -0
- package/dist/server/fallbacks/degradeController.js.map +1 -0
- package/dist/server/handlers.js +800 -0
- package/dist/server/handlers.js.map +1 -0
- package/dist/server/main.js +151 -0
- package/dist/server/main.js.map +1 -0
- package/dist/server/observability/metrics.js +56 -0
- package/dist/server/observability/metrics.js.map +1 -0
- package/dist/server/observability/tracing.js +58 -0
- package/dist/server/observability/tracing.js.map +1 -0
- package/dist/server/rpc.js +477 -0
- package/dist/server/rpc.js.map +1 -0
- package/dist/server/runtime.js +47 -0
- package/dist/server/runtime.js.map +1 -0
- package/dist/server/scoring.js +111 -0
- package/dist/server/scoring.js.map +1 -0
- package/dist/server/stdio.js +76 -0
- package/dist/server/stdio.js.map +1 -0
- package/dist/shared/duckdb.js +121 -0
- package/dist/shared/duckdb.js.map +1 -0
- package/dist/shared/embedding.js +85 -0
- package/dist/shared/embedding.js.map +1 -0
- package/dist/shared/index.js +9 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/security/config.js +64 -0
- package/dist/shared/security/config.js.map +1 -0
- package/dist/shared/security/masker.js +56 -0
- package/dist/shared/security/masker.js.map +1 -0
- package/dist/shared/tokenizer.js +5 -0
- package/dist/shared/tokenizer.js.map +1 -0
- package/dist/shared/utils/simpleYaml.js +90 -0
- package/dist/shared/utils/simpleYaml.js.map +1 -0
- package/dist/sql/schema.sql +6 -0
- package/dist/src/client/cli.d.ts +3 -0
- package/dist/src/client/cli.d.ts.map +1 -0
- package/dist/src/client/cli.js +68 -0
- package/dist/src/client/cli.js.map +1 -0
- package/dist/src/client/index.d.ts +5 -0
- package/dist/src/client/index.d.ts.map +1 -0
- package/dist/src/client/index.js +5 -0
- package/dist/src/client/index.js.map +1 -0
- package/dist/src/client/proxy.d.ts +9 -0
- package/dist/src/client/proxy.d.ts.map +1 -0
- package/dist/src/client/proxy.js +198 -0
- package/dist/src/client/proxy.js.map +1 -0
- package/dist/src/client/start-daemon.d.ts +30 -0
- package/dist/src/client/start-daemon.d.ts.map +1 -0
- package/dist/src/client/start-daemon.js +175 -0
- package/dist/src/client/start-daemon.js.map +1 -0
- package/dist/src/daemon/daemon.d.ts +9 -0
- package/dist/src/daemon/daemon.d.ts.map +1 -0
- package/dist/src/daemon/daemon.js +149 -0
- package/dist/src/daemon/daemon.js.map +1 -0
- package/dist/src/daemon/lifecycle.d.ts +101 -0
- package/dist/src/daemon/lifecycle.d.ts.map +1 -0
- package/dist/src/daemon/lifecycle.js +266 -0
- package/dist/src/daemon/lifecycle.js.map +1 -0
- package/dist/src/daemon/socket.d.ts +26 -0
- package/dist/src/daemon/socket.d.ts.map +1 -0
- package/dist/src/daemon/socket.js +132 -0
- package/dist/src/daemon/socket.js.map +1 -0
- package/dist/src/eval/metrics.d.ts +23 -0
- package/dist/src/eval/metrics.d.ts.map +1 -0
- package/dist/src/eval/metrics.js +47 -0
- package/dist/src/eval/metrics.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/indexer/cli.d.ts +9 -0
- package/dist/src/indexer/cli.d.ts.map +1 -0
- package/dist/src/indexer/cli.js +402 -0
- package/dist/src/indexer/cli.js.map +1 -0
- package/dist/src/indexer/codeintel.d.ts +28 -0
- package/dist/src/indexer/codeintel.d.ts.map +1 -0
- package/dist/src/indexer/codeintel.js +451 -0
- package/dist/src/indexer/codeintel.js.map +1 -0
- package/dist/src/indexer/git.d.ts +4 -0
- package/dist/src/indexer/git.d.ts.map +1 -0
- package/dist/src/indexer/git.js +30 -0
- package/dist/src/indexer/git.js.map +1 -0
- package/dist/src/indexer/language.d.ts +2 -0
- package/dist/src/indexer/language.d.ts.map +1 -0
- package/dist/src/indexer/language.js +34 -0
- package/dist/src/indexer/language.js.map +1 -0
- package/dist/src/indexer/pipeline/filters/denylist.d.ts +10 -0
- package/dist/src/indexer/pipeline/filters/denylist.d.ts.map +1 -0
- package/dist/src/indexer/pipeline/filters/denylist.js +71 -0
- package/dist/src/indexer/pipeline/filters/denylist.js.map +1 -0
- package/dist/src/indexer/schema.d.ts +9 -0
- package/dist/src/indexer/schema.d.ts.map +1 -0
- package/dist/src/indexer/schema.js +125 -0
- package/dist/src/indexer/schema.js.map +1 -0
- package/dist/src/indexer/watch.d.ts +97 -0
- package/dist/src/indexer/watch.d.ts.map +1 -0
- package/dist/src/indexer/watch.js +264 -0
- package/dist/src/indexer/watch.js.map +1 -0
- package/dist/src/server/bootstrap.d.ts +11 -0
- package/dist/src/server/bootstrap.d.ts.map +1 -0
- package/dist/src/server/bootstrap.js +19 -0
- package/dist/src/server/bootstrap.js.map +1 -0
- package/dist/src/server/context.d.ts +9 -0
- package/dist/src/server/context.d.ts.map +1 -0
- package/dist/src/server/context.js +2 -0
- package/dist/src/server/context.js.map +1 -0
- package/dist/src/server/fallbacks/degradeController.d.ts +24 -0
- package/dist/src/server/fallbacks/degradeController.d.ts.map +1 -0
- package/dist/src/server/fallbacks/degradeController.js +135 -0
- package/dist/src/server/fallbacks/degradeController.js.map +1 -0
- package/dist/src/server/handlers.d.ts +105 -0
- package/dist/src/server/handlers.d.ts.map +1 -0
- package/dist/src/server/handlers.js +954 -0
- package/dist/src/server/handlers.js.map +1 -0
- package/dist/src/server/indexBootstrap.d.ts +13 -0
- package/dist/src/server/indexBootstrap.d.ts.map +1 -0
- package/dist/src/server/indexBootstrap.js +109 -0
- package/dist/src/server/indexBootstrap.js.map +1 -0
- package/dist/src/server/main.d.ts +10 -0
- package/dist/src/server/main.d.ts.map +1 -0
- package/dist/src/server/main.js +217 -0
- package/dist/src/server/main.js.map +1 -0
- package/dist/src/server/observability/metrics.d.ts +35 -0
- package/dist/src/server/observability/metrics.d.ts.map +1 -0
- package/dist/src/server/observability/metrics.js +70 -0
- package/dist/src/server/observability/metrics.js.map +1 -0
- package/dist/src/server/observability/tracing.d.ts +3 -0
- package/dist/src/server/observability/tracing.d.ts.map +1 -0
- package/dist/src/server/observability/tracing.js +58 -0
- package/dist/src/server/observability/tracing.js.map +1 -0
- package/dist/src/server/rpc.d.ts +39 -0
- package/dist/src/server/rpc.d.ts.map +1 -0
- package/dist/src/server/rpc.js +551 -0
- package/dist/src/server/rpc.js.map +1 -0
- package/dist/src/server/runtime.d.ts +21 -0
- package/dist/src/server/runtime.d.ts.map +1 -0
- package/dist/src/server/runtime.js +59 -0
- package/dist/src/server/runtime.js.map +1 -0
- package/dist/src/server/scoring.d.ts +20 -0
- package/dist/src/server/scoring.d.ts.map +1 -0
- package/dist/src/server/scoring.js +112 -0
- package/dist/src/server/scoring.js.map +1 -0
- package/dist/src/server/stdio.d.ts +4 -0
- package/dist/src/server/stdio.d.ts.map +1 -0
- package/dist/src/server/stdio.js +88 -0
- package/dist/src/server/stdio.js.map +1 -0
- package/dist/src/shared/duckdb.d.ts +16 -0
- package/dist/src/shared/duckdb.d.ts.map +1 -0
- package/dist/src/shared/duckdb.js +121 -0
- package/dist/src/shared/duckdb.js.map +1 -0
- package/dist/src/shared/embedding.d.ts +19 -0
- package/dist/src/shared/embedding.d.ts.map +1 -0
- package/dist/src/shared/embedding.js +85 -0
- package/dist/src/shared/embedding.js.map +1 -0
- package/dist/src/shared/index.d.ts +3 -0
- package/dist/src/shared/index.d.ts.map +1 -0
- package/dist/src/shared/index.js +9 -0
- package/dist/src/shared/index.js.map +1 -0
- package/dist/src/shared/security/config.d.ts +23 -0
- package/dist/src/shared/security/config.d.ts.map +1 -0
- package/dist/src/shared/security/config.js +66 -0
- package/dist/src/shared/security/config.js.map +1 -0
- package/dist/src/shared/security/masker.d.ts +10 -0
- package/dist/src/shared/security/masker.d.ts.map +1 -0
- package/dist/src/shared/security/masker.js +56 -0
- package/dist/src/shared/security/masker.js.map +1 -0
- package/dist/src/shared/tokenizer.d.ts +2 -0
- package/dist/src/shared/tokenizer.d.ts.map +1 -0
- package/dist/src/shared/tokenizer.js +5 -0
- package/dist/src/shared/tokenizer.js.map +1 -0
- package/dist/src/shared/utils/lockfile.d.ts +46 -0
- package/dist/src/shared/utils/lockfile.d.ts.map +1 -0
- package/dist/src/shared/utils/lockfile.js +136 -0
- package/dist/src/shared/utils/lockfile.js.map +1 -0
- package/dist/src/shared/utils/simpleYaml.d.ts +6 -0
- package/dist/src/shared/utils/simpleYaml.d.ts.map +1 -0
- package/dist/src/shared/utils/simpleYaml.js +90 -0
- package/dist/src/shared/utils/simpleYaml.js.map +1 -0
- package/package.json +91 -0
- package/sql/schema.sql +6 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* KIRI Daemon Main Process
|
|
4
|
+
*
|
|
5
|
+
* Single daemon per database, handles multiple client connections via Unix socket.
|
|
6
|
+
* Manages DuckDB connection, watch mode, and graceful lifecycle.
|
|
7
|
+
*/
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { parseArgs } from "util";
|
|
10
|
+
import { ensureDatabaseIndexed } from "../server/indexBootstrap.js";
|
|
11
|
+
import { createRpcHandler } from "../server/rpc.js";
|
|
12
|
+
import { createServerRuntime } from "../server/runtime.js";
|
|
13
|
+
import { DaemonLifecycle } from "./lifecycle.js";
|
|
14
|
+
import { createSocketServer } from "./socket.js";
|
|
15
|
+
/**
|
|
16
|
+
* CLI引数をパース
|
|
17
|
+
*/
|
|
18
|
+
function parseDaemonArgs() {
|
|
19
|
+
const { values } = parseArgs({
|
|
20
|
+
options: {
|
|
21
|
+
repo: { type: "string" },
|
|
22
|
+
db: { type: "string" },
|
|
23
|
+
"socket-path": { type: "string" },
|
|
24
|
+
watch: { type: "boolean", default: false },
|
|
25
|
+
"daemon-timeout": { type: "string", default: "5" },
|
|
26
|
+
"allow-degrade": { type: "boolean", default: false },
|
|
27
|
+
"security-config": { type: "string" },
|
|
28
|
+
"security-lock": { type: "string" },
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
const repoRoot = path.resolve(values.repo || process.cwd());
|
|
32
|
+
const databasePath = path.resolve(values.db || path.join(repoRoot, "var", "index.duckdb"));
|
|
33
|
+
const socketPath = values["socket-path"]
|
|
34
|
+
? path.resolve(values["socket-path"])
|
|
35
|
+
: `${databasePath}.sock`;
|
|
36
|
+
return {
|
|
37
|
+
repoRoot,
|
|
38
|
+
databasePath,
|
|
39
|
+
socketPath,
|
|
40
|
+
watchMode: values.watch || false,
|
|
41
|
+
idleTimeoutMinutes: parseInt(values["daemon-timeout"] || "5", 10),
|
|
42
|
+
allowDegrade: values["allow-degrade"] || false,
|
|
43
|
+
securityConfigPath: values["security-config"],
|
|
44
|
+
securityLockPath: values["security-lock"],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* メイン関数:デーモンプロセスを起動
|
|
49
|
+
*/
|
|
50
|
+
async function main() {
|
|
51
|
+
const options = parseDaemonArgs();
|
|
52
|
+
const lifecycle = new DaemonLifecycle(options.databasePath, options.idleTimeoutMinutes);
|
|
53
|
+
try {
|
|
54
|
+
// スタートアップロックを取得
|
|
55
|
+
const lockAcquired = await lifecycle.acquireStartupLock();
|
|
56
|
+
if (!lockAcquired) {
|
|
57
|
+
console.error("[Daemon] Another daemon is starting up. Exiting to avoid race condition.");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
await lifecycle.log(`Starting daemon for database: ${options.databasePath}`);
|
|
61
|
+
// PIDファイルを作成
|
|
62
|
+
await lifecycle.createPidFile();
|
|
63
|
+
console.error(`[Daemon] PID: ${process.pid}`);
|
|
64
|
+
// データベースが存在しない場合、自動的にインデックスを作成
|
|
65
|
+
await ensureDatabaseIndexed(options.repoRoot, options.databasePath, options.allowDegrade, false);
|
|
66
|
+
// ServerRuntimeを作成(DuckDB接続、メトリクス、デグレード制御など)
|
|
67
|
+
let runtime = null;
|
|
68
|
+
try {
|
|
69
|
+
const runtimeOptions = {
|
|
70
|
+
repoRoot: options.repoRoot,
|
|
71
|
+
databasePath: options.databasePath,
|
|
72
|
+
allowDegrade: options.allowDegrade,
|
|
73
|
+
allowWriteLock: true, // Daemon mode should auto-create security lock
|
|
74
|
+
};
|
|
75
|
+
if (options.securityConfigPath) {
|
|
76
|
+
runtimeOptions.securityConfigPath = options.securityConfigPath;
|
|
77
|
+
}
|
|
78
|
+
if (options.securityLockPath) {
|
|
79
|
+
runtimeOptions.securityLockPath = options.securityLockPath;
|
|
80
|
+
}
|
|
81
|
+
runtime = await createServerRuntime(runtimeOptions);
|
|
82
|
+
await lifecycle.log(`Runtime initialized for repo: ${options.repoRoot}`);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
const error = err;
|
|
86
|
+
await lifecycle.log(`Failed to create runtime: ${error.message}`);
|
|
87
|
+
console.error(`[Daemon] Failed to create runtime: ${error.message}`);
|
|
88
|
+
await lifecycle.removePidFile();
|
|
89
|
+
await lifecycle.releaseStartupLock();
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
// RPCハンドラを作成(既存のロジックを再利用)
|
|
93
|
+
const rpcHandler = createRpcHandler(runtime);
|
|
94
|
+
// Unixソケットサーバーを作成
|
|
95
|
+
const closeServer = await createSocketServer({
|
|
96
|
+
socketPath: options.socketPath || `${options.databasePath}.sock`,
|
|
97
|
+
onRequest: async (request) => {
|
|
98
|
+
lifecycle.incrementConnections();
|
|
99
|
+
try {
|
|
100
|
+
return await rpcHandler(request);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
lifecycle.decrementConnections();
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
onError: async (error) => {
|
|
107
|
+
await lifecycle.log(`Connection error: ${error.message}`);
|
|
108
|
+
console.error(`[Daemon] Connection error: ${error.message}`);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
await lifecycle.log(`Socket server listening on: ${options.socketPath || `${options.databasePath}.sock`}`);
|
|
112
|
+
// スタートアップロックを解放(起動完了)
|
|
113
|
+
await lifecycle.releaseStartupLock();
|
|
114
|
+
// ウォッチモードの設定
|
|
115
|
+
if (options.watchMode) {
|
|
116
|
+
lifecycle.setWatchModeActive(true);
|
|
117
|
+
await lifecycle.log("Watch mode enabled (daemon will not auto-stop)");
|
|
118
|
+
console.error("[Daemon] Watch mode enabled (daemon will not auto-stop)");
|
|
119
|
+
// TODO: IndexWatcherの統合
|
|
120
|
+
}
|
|
121
|
+
// グレースフルシャットダウンの設定
|
|
122
|
+
lifecycle.onShutdown(async () => {
|
|
123
|
+
await lifecycle.log("Shutting down daemon...");
|
|
124
|
+
console.error("[Daemon] Closing server...");
|
|
125
|
+
await closeServer();
|
|
126
|
+
console.error("[Daemon] Closing runtime...");
|
|
127
|
+
if (runtime) {
|
|
128
|
+
await runtime.close();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
lifecycle.setupGracefulShutdown();
|
|
132
|
+
await lifecycle.log("Daemon started successfully");
|
|
133
|
+
console.error("[Daemon] Ready to accept connections");
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
const error = err;
|
|
137
|
+
await lifecycle.log(`Fatal error: ${error.message}`);
|
|
138
|
+
console.error(`[Daemon] Fatal error: ${error.message}`);
|
|
139
|
+
await lifecycle.removePidFile();
|
|
140
|
+
await lifecycle.releaseStartupLock();
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// エントリーポイント
|
|
145
|
+
main().catch(async (err) => {
|
|
146
|
+
console.error(`[Daemon] Unhandled error: ${err}`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/daemon/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Lifecycle Management
|
|
3
|
+
*
|
|
4
|
+
* Handles PID file creation, idle timeout, health checks, and graceful shutdown.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* PIDファイルとスタートアップロックを管理する
|
|
8
|
+
*/
|
|
9
|
+
export declare class DaemonLifecycle {
|
|
10
|
+
private readonly databasePath;
|
|
11
|
+
private readonly idleTimeoutMinutes;
|
|
12
|
+
private readonly pidFilePath;
|
|
13
|
+
private readonly startupLockPath;
|
|
14
|
+
private readonly logFilePath;
|
|
15
|
+
private idleTimer;
|
|
16
|
+
private activeConnections;
|
|
17
|
+
private watchModeActive;
|
|
18
|
+
private shutdownCallback?;
|
|
19
|
+
private readonly maxLogSizeBytes;
|
|
20
|
+
private readonly maxLogBackups;
|
|
21
|
+
constructor(databasePath: string, idleTimeoutMinutes?: number);
|
|
22
|
+
/**
|
|
23
|
+
* PIDファイルパスを取得
|
|
24
|
+
*/
|
|
25
|
+
getPidFilePath(): string;
|
|
26
|
+
/**
|
|
27
|
+
* スタートアップロックファイルパスを取得
|
|
28
|
+
*/
|
|
29
|
+
getStartupLockPath(): string;
|
|
30
|
+
/**
|
|
31
|
+
* ログファイルパスを取得
|
|
32
|
+
*/
|
|
33
|
+
getLogFilePath(): string;
|
|
34
|
+
/**
|
|
35
|
+
* スタートアップロックを取得(排他的作成)
|
|
36
|
+
*
|
|
37
|
+
* @returns ロック取得に成功した場合はtrue、他のプロセスが既にロック中の場合はfalse
|
|
38
|
+
*/
|
|
39
|
+
acquireStartupLock(): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* スタートアップロックを解放
|
|
42
|
+
*/
|
|
43
|
+
releaseStartupLock(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* PIDファイルを作成
|
|
46
|
+
*/
|
|
47
|
+
createPidFile(): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* PIDファイルを削除
|
|
50
|
+
*/
|
|
51
|
+
removePidFile(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* デーモンが実行中かチェック(PIDファイルとプロセスの存在確認)
|
|
54
|
+
*
|
|
55
|
+
* @returns デーモンが実行中の場合はPID、それ以外はnull
|
|
56
|
+
*/
|
|
57
|
+
checkRunning(): Promise<number | null>;
|
|
58
|
+
/**
|
|
59
|
+
* ウォッチモードの状態を設定
|
|
60
|
+
*/
|
|
61
|
+
setWatchModeActive(active: boolean): void;
|
|
62
|
+
/**
|
|
63
|
+
* アクティブ接続数を増やす
|
|
64
|
+
*/
|
|
65
|
+
incrementConnections(): void;
|
|
66
|
+
/**
|
|
67
|
+
* アクティブ接続数を減らす
|
|
68
|
+
*/
|
|
69
|
+
decrementConnections(): void;
|
|
70
|
+
/**
|
|
71
|
+
* シャットダウンコールバックを登録
|
|
72
|
+
*/
|
|
73
|
+
onShutdown(callback: () => Promise<void>): void;
|
|
74
|
+
/**
|
|
75
|
+
* アイドルタイマーをリセット
|
|
76
|
+
*/
|
|
77
|
+
private resetIdleTimer;
|
|
78
|
+
/**
|
|
79
|
+
* アイドルタイマーを開始
|
|
80
|
+
*
|
|
81
|
+
* ウォッチモードが有効でなく、タイムアウトが0でない場合のみ開始
|
|
82
|
+
*/
|
|
83
|
+
private startIdleTimer;
|
|
84
|
+
/**
|
|
85
|
+
* グレースフルシャットダウンを設定
|
|
86
|
+
*/
|
|
87
|
+
setupGracefulShutdown(): void;
|
|
88
|
+
/**
|
|
89
|
+
* ログファイルをローテーション
|
|
90
|
+
*
|
|
91
|
+
* ファイルサイズが maxLogSizeBytes を超えた場合、古いログをバックアップして新しいログを開始
|
|
92
|
+
*/
|
|
93
|
+
private rotateLogIfNeeded;
|
|
94
|
+
/**
|
|
95
|
+
* ログファイルにメッセージを書き込む
|
|
96
|
+
*
|
|
97
|
+
* ファイルサイズが制限を超えた場合、自動的にローテーションを実行
|
|
98
|
+
*/
|
|
99
|
+
log(message: string): Promise<void>;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/daemon/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,qBAAa,eAAe;IAYxB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAZrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAAC,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAC5D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAa;gBAGxB,YAAY,EAAE,MAAM,EACpB,kBAAkB,GAAE,MAAU;IAOjD;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAc5C;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAWzC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAWpC;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAsB5C;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAQzC;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAO5B;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI/C;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAuBtB;;OAEG;IACH,qBAAqB,IAAI,IAAI;IAoB7B;;;;OAIG;YACW,iBAAiB;IAmC/B;;;;OAIG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAc1C"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Lifecycle Management
|
|
3
|
+
*
|
|
4
|
+
* Handles PID file creation, idle timeout, health checks, and graceful shutdown.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from "fs/promises";
|
|
7
|
+
/**
|
|
8
|
+
* PIDファイルとスタートアップロックを管理する
|
|
9
|
+
*/
|
|
10
|
+
export class DaemonLifecycle {
|
|
11
|
+
databasePath;
|
|
12
|
+
idleTimeoutMinutes;
|
|
13
|
+
pidFilePath;
|
|
14
|
+
startupLockPath;
|
|
15
|
+
logFilePath;
|
|
16
|
+
idleTimer = null;
|
|
17
|
+
activeConnections = 0;
|
|
18
|
+
watchModeActive = false;
|
|
19
|
+
shutdownCallback;
|
|
20
|
+
maxLogSizeBytes = 10 * 1024 * 1024; // 10MB
|
|
21
|
+
maxLogBackups = 3;
|
|
22
|
+
constructor(databasePath, idleTimeoutMinutes = 5) {
|
|
23
|
+
this.databasePath = databasePath;
|
|
24
|
+
this.idleTimeoutMinutes = idleTimeoutMinutes;
|
|
25
|
+
this.pidFilePath = `${databasePath}.daemon.pid`;
|
|
26
|
+
this.startupLockPath = `${databasePath}.daemon.starting`;
|
|
27
|
+
this.logFilePath = `${databasePath}.daemon.log`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* PIDファイルパスを取得
|
|
31
|
+
*/
|
|
32
|
+
getPidFilePath() {
|
|
33
|
+
return this.pidFilePath;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* スタートアップロックファイルパスを取得
|
|
37
|
+
*/
|
|
38
|
+
getStartupLockPath() {
|
|
39
|
+
return this.startupLockPath;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* ログファイルパスを取得
|
|
43
|
+
*/
|
|
44
|
+
getLogFilePath() {
|
|
45
|
+
return this.logFilePath;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* スタートアップロックを取得(排他的作成)
|
|
49
|
+
*
|
|
50
|
+
* @returns ロック取得に成功した場合はtrue、他のプロセスが既にロック中の場合はfalse
|
|
51
|
+
*/
|
|
52
|
+
async acquireStartupLock() {
|
|
53
|
+
try {
|
|
54
|
+
await fs.writeFile(this.startupLockPath, String(process.pid), {
|
|
55
|
+
flag: "wx", // 排他的作成
|
|
56
|
+
});
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (err.code === "EEXIST") {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* スタートアップロックを解放
|
|
68
|
+
*/
|
|
69
|
+
async releaseStartupLock() {
|
|
70
|
+
try {
|
|
71
|
+
await fs.unlink(this.startupLockPath);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
// ファイルが存在しない場合は無視
|
|
75
|
+
if (err.code !== "ENOENT") {
|
|
76
|
+
console.error(`Failed to release startup lock: ${err}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* PIDファイルを作成
|
|
82
|
+
*/
|
|
83
|
+
async createPidFile() {
|
|
84
|
+
await fs.writeFile(this.pidFilePath, String(process.pid), "utf-8");
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* PIDファイルを削除
|
|
88
|
+
*/
|
|
89
|
+
async removePidFile() {
|
|
90
|
+
try {
|
|
91
|
+
await fs.unlink(this.pidFilePath);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
// ファイルが存在しない場合は無視
|
|
95
|
+
if (err.code !== "ENOENT") {
|
|
96
|
+
console.error(`Failed to remove PID file: ${err}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* デーモンが実行中かチェック(PIDファイルとプロセスの存在確認)
|
|
102
|
+
*
|
|
103
|
+
* @returns デーモンが実行中の場合はPID、それ以外はnull
|
|
104
|
+
*/
|
|
105
|
+
async checkRunning() {
|
|
106
|
+
try {
|
|
107
|
+
const pidStr = await fs.readFile(this.pidFilePath, "utf-8");
|
|
108
|
+
const pid = parseInt(pidStr.trim(), 10);
|
|
109
|
+
// プロセスが実際に存在するかチェック
|
|
110
|
+
try {
|
|
111
|
+
process.kill(pid, 0); // シグナル0は存在チェック
|
|
112
|
+
return pid;
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
114
|
+
}
|
|
115
|
+
catch (_err) {
|
|
116
|
+
// プロセスが存在しない場合、PIDファイルは古い
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
if (err.code === "ENOENT") {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* ウォッチモードの状態を設定
|
|
129
|
+
*/
|
|
130
|
+
setWatchModeActive(active) {
|
|
131
|
+
this.watchModeActive = active;
|
|
132
|
+
if (active) {
|
|
133
|
+
// ウォッチモードが有効な場合、アイドルタイマーをキャンセル
|
|
134
|
+
this.resetIdleTimer();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* アクティブ接続数を増やす
|
|
139
|
+
*/
|
|
140
|
+
incrementConnections() {
|
|
141
|
+
this.activeConnections++;
|
|
142
|
+
this.resetIdleTimer();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* アクティブ接続数を減らす
|
|
146
|
+
*/
|
|
147
|
+
decrementConnections() {
|
|
148
|
+
this.activeConnections = Math.max(0, this.activeConnections - 1);
|
|
149
|
+
if (this.activeConnections === 0) {
|
|
150
|
+
this.startIdleTimer();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* シャットダウンコールバックを登録
|
|
155
|
+
*/
|
|
156
|
+
onShutdown(callback) {
|
|
157
|
+
this.shutdownCallback = callback;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* アイドルタイマーをリセット
|
|
161
|
+
*/
|
|
162
|
+
resetIdleTimer() {
|
|
163
|
+
if (this.idleTimer) {
|
|
164
|
+
clearTimeout(this.idleTimer);
|
|
165
|
+
this.idleTimer = null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* アイドルタイマーを開始
|
|
170
|
+
*
|
|
171
|
+
* ウォッチモードが有効でなく、タイムアウトが0でない場合のみ開始
|
|
172
|
+
*/
|
|
173
|
+
startIdleTimer() {
|
|
174
|
+
if (this.watchModeActive || this.idleTimeoutMinutes === 0) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.resetIdleTimer();
|
|
178
|
+
this.idleTimer = setTimeout(async () => {
|
|
179
|
+
// タイマー発火時に再度チェック(レースコンディション対策)
|
|
180
|
+
if (this.activeConnections === 0 && !this.watchModeActive) {
|
|
181
|
+
console.error(`[Daemon] Idle timeout (${this.idleTimeoutMinutes} minutes) reached. Shutting down...`);
|
|
182
|
+
if (this.shutdownCallback) {
|
|
183
|
+
await this.shutdownCallback();
|
|
184
|
+
}
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|
|
187
|
+
}, this.idleTimeoutMinutes * 60 * 1000);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* グレースフルシャットダウンを設定
|
|
191
|
+
*/
|
|
192
|
+
setupGracefulShutdown() {
|
|
193
|
+
const shutdown = async (signal) => {
|
|
194
|
+
console.error(`[Daemon] Received ${signal}. Shutting down gracefully...`);
|
|
195
|
+
this.resetIdleTimer();
|
|
196
|
+
if (this.shutdownCallback) {
|
|
197
|
+
await this.shutdownCallback();
|
|
198
|
+
}
|
|
199
|
+
await this.removePidFile();
|
|
200
|
+
await this.releaseStartupLock();
|
|
201
|
+
process.exit(0);
|
|
202
|
+
};
|
|
203
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
204
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* ログファイルをローテーション
|
|
208
|
+
*
|
|
209
|
+
* ファイルサイズが maxLogSizeBytes を超えた場合、古いログをバックアップして新しいログを開始
|
|
210
|
+
*/
|
|
211
|
+
async rotateLogIfNeeded() {
|
|
212
|
+
try {
|
|
213
|
+
const stats = await fs.stat(this.logFilePath);
|
|
214
|
+
if (stats.size < this.maxLogSizeBytes) {
|
|
215
|
+
return; // ローテーション不要
|
|
216
|
+
}
|
|
217
|
+
// 既存のバックアップをシフト (.log.3 -> .log.4 は削除, .log.2 -> .log.3, etc.)
|
|
218
|
+
for (let i = this.maxLogBackups; i > 0; i--) {
|
|
219
|
+
const oldBackup = `${this.logFilePath}.${i}`;
|
|
220
|
+
const newBackup = `${this.logFilePath}.${i + 1}`;
|
|
221
|
+
try {
|
|
222
|
+
await fs.access(oldBackup);
|
|
223
|
+
if (i === this.maxLogBackups) {
|
|
224
|
+
// 最古のバックアップは削除
|
|
225
|
+
await fs.unlink(oldBackup);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
// バックアップをリネーム
|
|
229
|
+
await fs.rename(oldBackup, newBackup);
|
|
230
|
+
}
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
232
|
+
}
|
|
233
|
+
catch (_err) {
|
|
234
|
+
// ファイルが存在しない場合は無視
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// 現在のログファイルを .log.1 にリネーム
|
|
238
|
+
await fs.rename(this.logFilePath, `${this.logFilePath}.1`);
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
if (err.code !== "ENOENT") {
|
|
242
|
+
console.error(`Failed to rotate log file: ${err}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* ログファイルにメッセージを書き込む
|
|
248
|
+
*
|
|
249
|
+
* ファイルサイズが制限を超えた場合、自動的にローテーションを実行
|
|
250
|
+
*/
|
|
251
|
+
async log(message) {
|
|
252
|
+
// ローテーションチェック(非同期だがログ書き込みはブロックしない)
|
|
253
|
+
this.rotateLogIfNeeded().catch((err) => {
|
|
254
|
+
console.error(`Log rotation failed: ${err}`);
|
|
255
|
+
});
|
|
256
|
+
const timestamp = new Date().toISOString();
|
|
257
|
+
const logMessage = `${timestamp} ${message}\n`;
|
|
258
|
+
try {
|
|
259
|
+
await fs.appendFile(this.logFilePath, logMessage, "utf-8");
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
console.error(`Failed to write to log file: ${err}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/daemon/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unix Socket Transport Layer for KIRI Daemon
|
|
3
|
+
*
|
|
4
|
+
* Provides IPC communication between daemon and clients via Unix domain sockets.
|
|
5
|
+
* Handles multiple concurrent client connections with newline-delimited JSON-RPC protocol.
|
|
6
|
+
*/
|
|
7
|
+
import type { JsonRpcRequest, RpcHandleResult } from "../server/rpc.js";
|
|
8
|
+
/**
|
|
9
|
+
* Unix socket server configuration
|
|
10
|
+
*/
|
|
11
|
+
export interface SocketServerOptions {
|
|
12
|
+
/** Unix socket file path (e.g., /path/to/database.duckdb.sock) */
|
|
13
|
+
socketPath: string;
|
|
14
|
+
/** Handler function for JSON-RPC requests */
|
|
15
|
+
onRequest: (request: JsonRpcRequest) => Promise<RpcHandleResult | null>;
|
|
16
|
+
/** Optional error handler for connection errors */
|
|
17
|
+
onError?: (error: Error) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* ソケットサーバーを作成し、複数クライアント接続を処理する
|
|
21
|
+
*
|
|
22
|
+
* @param options - サーバー設定
|
|
23
|
+
* @returns クリーンアップ用のcloseハンドラ
|
|
24
|
+
*/
|
|
25
|
+
export declare function createSocketServer(options: SocketServerOptions): Promise<() => Promise<void>>;
|
|
26
|
+
//# sourceMappingURL=socket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../../src/daemon/socket.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACxE,mDAAmD;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CA4C9B"}
|