trove-cli 0.0.0-stage → 0.3.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.
- package/LICENSE +21 -0
- package/README.md +202 -2
- package/dist/adapters/file-source.d.ts +31 -0
- package/dist/adapters/file-source.js +97 -0
- package/dist/adapters/file-source.js.map +1 -0
- package/dist/adapters/index.d.ts +34 -0
- package/dist/adapters/index.js +146 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +30 -0
- package/dist/adapters/opencode.js +135 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/cli.d.ts +58 -0
- package/dist/cli.js +974 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +81 -0
- package/dist/config.js +99 -0
- package/dist/config.js.map +1 -0
- package/dist/core/archive.d.ts +27 -0
- package/dist/core/archive.js +101 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/chunker.d.ts +28 -0
- package/dist/core/chunker.js +67 -0
- package/dist/core/chunker.js.map +1 -0
- package/dist/core/clean.d.ts +36 -0
- package/dist/core/clean.js +182 -0
- package/dist/core/clean.js.map +1 -0
- package/dist/core/collect.d.ts +39 -0
- package/dist/core/collect.js +194 -0
- package/dist/core/collect.js.map +1 -0
- package/dist/core/concurrency.d.ts +2 -0
- package/dist/core/concurrency.js +16 -0
- package/dist/core/concurrency.js.map +1 -0
- package/dist/core/cursor.d.ts +31 -0
- package/dist/core/cursor.js +31 -0
- package/dist/core/cursor.js.map +1 -0
- package/dist/core/events/claude.d.ts +7 -0
- package/dist/core/events/claude.js +287 -0
- package/dist/core/events/claude.js.map +1 -0
- package/dist/core/events/codex.d.ts +6 -0
- package/dist/core/events/codex.js +149 -0
- package/dist/core/events/codex.js.map +1 -0
- package/dist/core/events/doubao.d.ts +9 -0
- package/dist/core/events/doubao.js +151 -0
- package/dist/core/events/doubao.js.map +1 -0
- package/dist/core/events/index.d.ts +6 -0
- package/dist/core/events/index.js +20 -0
- package/dist/core/events/index.js.map +1 -0
- package/dist/core/events/opencode.d.ts +7 -0
- package/dist/core/events/opencode.js +189 -0
- package/dist/core/events/opencode.js.map +1 -0
- package/dist/core/events/schema.d.ts +83 -0
- package/dist/core/events/schema.js +35 -0
- package/dist/core/events/schema.js.map +1 -0
- package/dist/core/layout.d.ts +26 -0
- package/dist/core/layout.js +122 -0
- package/dist/core/layout.js.map +1 -0
- package/dist/core/lessons/analyze.d.ts +40 -0
- package/dist/core/lessons/analyze.js +107 -0
- package/dist/core/lessons/analyze.js.map +1 -0
- package/dist/core/lessons/audit.d.ts +51 -0
- package/dist/core/lessons/audit.js +57 -0
- package/dist/core/lessons/audit.js.map +1 -0
- package/dist/core/lessons/compaction.d.ts +5 -0
- package/dist/core/lessons/compaction.js +58 -0
- package/dist/core/lessons/compaction.js.map +1 -0
- package/dist/core/lessons/config.d.ts +15 -0
- package/dist/core/lessons/config.js +31 -0
- package/dist/core/lessons/config.js.map +1 -0
- package/dist/core/lessons/existing.d.ts +4 -0
- package/dist/core/lessons/existing.js +22 -0
- package/dist/core/lessons/existing.js.map +1 -0
- package/dist/core/lessons/extract.d.ts +21 -0
- package/dist/core/lessons/extract.js +106 -0
- package/dist/core/lessons/extract.js.map +1 -0
- package/dist/core/lessons/frontmatter.d.ts +29 -0
- package/dist/core/lessons/frontmatter.js +87 -0
- package/dist/core/lessons/frontmatter.js.map +1 -0
- package/dist/core/lessons/graph.d.ts +256 -0
- package/dist/core/lessons/graph.js +86 -0
- package/dist/core/lessons/graph.js.map +1 -0
- package/dist/core/lessons/jev.d.ts +36 -0
- package/dist/core/lessons/jev.js +100 -0
- package/dist/core/lessons/jev.js.map +1 -0
- package/dist/core/lessons/layout.d.ts +2 -0
- package/dist/core/lessons/layout.js +56 -0
- package/dist/core/lessons/layout.js.map +1 -0
- package/dist/core/lessons/learn.d.ts +38 -0
- package/dist/core/lessons/learn.js +190 -0
- package/dist/core/lessons/learn.js.map +1 -0
- package/dist/core/lessons/llm.d.ts +42 -0
- package/dist/core/lessons/llm.js +106 -0
- package/dist/core/lessons/llm.js.map +1 -0
- package/dist/core/lessons/memo.d.ts +19 -0
- package/dist/core/lessons/memo.js +170 -0
- package/dist/core/lessons/memo.js.map +1 -0
- package/dist/core/lessons/merge.d.ts +39 -0
- package/dist/core/lessons/merge.js +79 -0
- package/dist/core/lessons/merge.js.map +1 -0
- package/dist/core/lessons/queue.d.ts +6 -0
- package/dist/core/lessons/queue.js +52 -0
- package/dist/core/lessons/queue.js.map +1 -0
- package/dist/core/lessons/recent.d.ts +21 -0
- package/dist/core/lessons/recent.js +111 -0
- package/dist/core/lessons/recent.js.map +1 -0
- package/dist/core/lessons/schema.d.ts +26 -0
- package/dist/core/lessons/schema.js +64 -0
- package/dist/core/lessons/schema.js.map +1 -0
- package/dist/core/lessons/select.d.ts +19 -0
- package/dist/core/lessons/select.js +55 -0
- package/dist/core/lessons/select.js.map +1 -0
- package/dist/core/lessons/sidecar.d.ts +23 -0
- package/dist/core/lessons/sidecar.js +171 -0
- package/dist/core/lessons/sidecar.js.map +1 -0
- package/dist/core/lessons/storage.d.ts +21 -0
- package/dist/core/lessons/storage.js +65 -0
- package/dist/core/lessons/storage.js.map +1 -0
- package/dist/core/lessons/usage.d.ts +31 -0
- package/dist/core/lessons/usage.js +91 -0
- package/dist/core/lessons/usage.js.map +1 -0
- package/dist/core/lessons/write.d.ts +18 -0
- package/dist/core/lessons/write.js +131 -0
- package/dist/core/lessons/write.js.map +1 -0
- package/dist/core/library/build.d.ts +22 -0
- package/dist/core/library/build.js +163 -0
- package/dist/core/library/build.js.map +1 -0
- package/dist/core/library/group.d.ts +14 -0
- package/dist/core/library/group.js +129 -0
- package/dist/core/library/group.js.map +1 -0
- package/dist/core/library/index-file.d.ts +7 -0
- package/dist/core/library/index-file.js +250 -0
- package/dist/core/library/index-file.js.map +1 -0
- package/dist/core/library/schema.d.ts +78 -0
- package/dist/core/library/schema.js +37 -0
- package/dist/core/library/schema.js.map +1 -0
- package/dist/core/library/skills.d.ts +26 -0
- package/dist/core/library/skills.js +168 -0
- package/dist/core/library/skills.js.map +1 -0
- package/dist/core/library/sync.d.ts +48 -0
- package/dist/core/library/sync.js +271 -0
- package/dist/core/library/sync.js.map +1 -0
- package/dist/core/lock.d.ts +6 -0
- package/dist/core/lock.js +56 -0
- package/dist/core/lock.js.map +1 -0
- package/dist/core/pull.d.ts +23 -0
- package/dist/core/pull.js +147 -0
- package/dist/core/pull.js.map +1 -0
- package/dist/core/push.d.ts +29 -0
- package/dist/core/push.js +170 -0
- package/dist/core/push.js.map +1 -0
- package/dist/core/remote-layout.d.ts +67 -0
- package/dist/core/remote-layout.js +94 -0
- package/dist/core/remote-layout.js.map +1 -0
- package/dist/core/sessions.d.ts +29 -0
- package/dist/core/sessions.js +96 -0
- package/dist/core/sessions.js.map +1 -0
- package/dist/core/state.d.ts +94 -0
- package/dist/core/state.js +62 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/sync.d.ts +48 -0
- package/dist/core/sync.js +140 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/time-window.d.ts +8 -0
- package/dist/core/time-window.js +36 -0
- package/dist/core/time-window.js.map +1 -0
- package/dist/daemon.d.ts +73 -0
- package/dist/daemon.js +272 -0
- package/dist/daemon.js.map +1 -0
- package/dist/format.d.ts +4 -0
- package/dist/format.js +28 -0
- package/dist/format.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +9 -0
- package/dist/main.js.map +1 -0
- package/dist/paths.d.ts +19 -0
- package/dist/paths.js +19 -0
- package/dist/paths.js.map +1 -0
- package/dist/progress-console.d.ts +12 -0
- package/dist/progress-console.js +42 -0
- package/dist/progress-console.js.map +1 -0
- package/dist/progress.d.ts +7 -0
- package/dist/progress.js +6 -0
- package/dist/progress.js.map +1 -0
- package/dist/remote/create-remote.d.ts +20 -0
- package/dist/remote/create-remote.js +86 -0
- package/dist/remote/create-remote.js.map +1 -0
- package/dist/remote/prompt.d.ts +17 -0
- package/dist/remote/prompt.js +111 -0
- package/dist/remote/prompt.js.map +1 -0
- package/dist/remote/s3-sigv4.d.ts +28 -0
- package/dist/remote/s3-sigv4.js +100 -0
- package/dist/remote/s3-sigv4.js.map +1 -0
- package/dist/remote/s3-store.d.ts +75 -0
- package/dist/remote/s3-store.js +438 -0
- package/dist/remote/s3-store.js.map +1 -0
- package/dist/remote/s3-vendors.d.ts +31 -0
- package/dist/remote/s3-vendors.js +47 -0
- package/dist/remote/s3-vendors.js.map +1 -0
- package/dist/remote/store.d.ts +44 -0
- package/dist/remote/store.js +2 -0
- package/dist/remote/store.js.map +1 -0
- package/dist/remote/webdav-store.d.ts +41 -0
- package/dist/remote/webdav-store.js +285 -0
- package/dist/remote/webdav-store.js.map +1 -0
- package/dist/sqlite.d.ts +3 -0
- package/dist/sqlite.js +12 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/status.d.ts +82 -0
- package/dist/status.js +162 -0
- package/dist/status.js.map +1 -0
- package/package.json +43 -4
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { open, readFile, rename, stat, unlink, writeFile, mkdir, appendFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import { isProcessAlive } from './core/lock.js';
|
|
5
|
+
import { execFileSync } from 'node:child_process';
|
|
6
|
+
export const isAlive = isProcessAlive;
|
|
7
|
+
async function readPidFile(paths) {
|
|
8
|
+
try {
|
|
9
|
+
const raw = await readFile(paths.daemonPid, 'utf8');
|
|
10
|
+
const v = JSON.parse(raw);
|
|
11
|
+
if (typeof v.pid !== 'number')
|
|
12
|
+
return null;
|
|
13
|
+
return { pid: v.pid, startedAt: v.startedAt ?? 0 };
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** 单实例锁:pid 文件不存在才创建;陈旧 pid(进程已死)自动接管。 */
|
|
20
|
+
export async function acquireDaemonPid(paths) {
|
|
21
|
+
await mkdir(dirname(paths.daemonPid), { recursive: true });
|
|
22
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
23
|
+
try {
|
|
24
|
+
const fh = await open(paths.daemonPid, 'wx');
|
|
25
|
+
await fh.writeFile(JSON.stringify({ pid: process.pid, startedAt: Date.now() }));
|
|
26
|
+
await fh.close();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (err.code !== 'EEXIST')
|
|
31
|
+
throw err;
|
|
32
|
+
const existing = await readPidFile(paths);
|
|
33
|
+
if (existing && isAlive(existing.pid)) {
|
|
34
|
+
throw new Error(`daemon 已在运行 (pid ${existing.pid})`);
|
|
35
|
+
}
|
|
36
|
+
await unlink(paths.daemonPid).catch(() => { });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
throw new Error('无法获取 daemon 单实例锁');
|
|
40
|
+
}
|
|
41
|
+
export async function releaseDaemonPid(paths) {
|
|
42
|
+
const existing = await readPidFile(paths);
|
|
43
|
+
if (!existing || existing.pid === process.pid) {
|
|
44
|
+
await unlink(paths.daemonPid).catch(() => { });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export async function readDaemonStatus(paths) {
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(await readFile(paths.daemonStatus, 'utf8'));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function writeDaemonStatus(paths, status) {
|
|
56
|
+
await mkdir(dirname(paths.daemonStatus), { recursive: true });
|
|
57
|
+
const tmp = `${paths.daemonStatus}.tmp`;
|
|
58
|
+
await writeFile(tmp, JSON.stringify(status, null, 2));
|
|
59
|
+
await rename(tmp, paths.daemonStatus);
|
|
60
|
+
}
|
|
61
|
+
/** 日志超过 10MB 轮转一份,避免 daemon 无限写。 */
|
|
62
|
+
export async function daemonLog(paths, text) {
|
|
63
|
+
await mkdir(dirname(paths.daemonLog), { recursive: true });
|
|
64
|
+
try {
|
|
65
|
+
const st = await stat(paths.daemonLog);
|
|
66
|
+
if (st.size > 10 * 1024 * 1024) {
|
|
67
|
+
await rename(paths.daemonLog, `${paths.daemonLog}.1`).catch(() => { });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// 日志还不存在
|
|
72
|
+
}
|
|
73
|
+
await appendFile(paths.daemonLog, `${new Date().toISOString()} ${text}\n`);
|
|
74
|
+
}
|
|
75
|
+
function logProgress(paths) {
|
|
76
|
+
let last = 0;
|
|
77
|
+
return {
|
|
78
|
+
phase(name, detail) {
|
|
79
|
+
void daemonLog(paths, `[${name}]${detail ? ` ${detail}` : ''}`);
|
|
80
|
+
},
|
|
81
|
+
item(label, current, total) {
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
if (now - last < 10_000 && current < total)
|
|
84
|
+
return;
|
|
85
|
+
last = now;
|
|
86
|
+
void daemonLog(paths, `[progress] ${current}/${total} ${label}`);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function sleep(ms, signal) {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
if (signal.aborted)
|
|
93
|
+
return resolve();
|
|
94
|
+
const t = setTimeout(resolve, ms);
|
|
95
|
+
signal.addEventListener('abort', () => {
|
|
96
|
+
clearTimeout(t);
|
|
97
|
+
resolve();
|
|
98
|
+
}, { once: true });
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* daemon 主循环:sync 与 learn 两个循环并发跑,共享 abort 信号;SIGTERM/abort 后清理 pid 退出。
|
|
103
|
+
* sync 循环每轮状态写 daemon.status.json,供 `trove daemon status` 读取;learn 循环只写日志。
|
|
104
|
+
*/
|
|
105
|
+
export async function runDaemon(runtime, signal) {
|
|
106
|
+
const { paths, intervalSeconds, since } = runtime;
|
|
107
|
+
await acquireDaemonPid(paths);
|
|
108
|
+
const status = {
|
|
109
|
+
running: true,
|
|
110
|
+
pid: process.pid,
|
|
111
|
+
startedAt: Date.now(),
|
|
112
|
+
intervalSeconds,
|
|
113
|
+
since,
|
|
114
|
+
};
|
|
115
|
+
await writeDaemonStatus(paths, status);
|
|
116
|
+
await daemonLog(paths, `daemon 启动 pid=${process.pid} interval=${intervalSeconds}s since=${since}`);
|
|
117
|
+
try {
|
|
118
|
+
const loops = [syncLoop(runtime, status, signal)];
|
|
119
|
+
if (runtime.learnTick)
|
|
120
|
+
loops.push(learnLoop(runtime, signal));
|
|
121
|
+
await Promise.all(loops);
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
status.running = false;
|
|
125
|
+
status.nextRunAt = undefined;
|
|
126
|
+
await writeDaemonStatus(paths, status);
|
|
127
|
+
await releaseDaemonPid(paths);
|
|
128
|
+
await daemonLog(paths, 'daemon 退出');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function syncLoop(runtime, status, signal) {
|
|
132
|
+
const { paths, intervalSeconds, runOnce } = runtime;
|
|
133
|
+
while (!signal.aborted) {
|
|
134
|
+
const started = Date.now();
|
|
135
|
+
status.lastRunAt = started;
|
|
136
|
+
await writeDaemonStatus(paths, status); // 让 status 命令能看到"正在跑"
|
|
137
|
+
try {
|
|
138
|
+
const report = await runOnce(logProgress(paths), signal);
|
|
139
|
+
status.lastResult = {
|
|
140
|
+
collected: report.collected,
|
|
141
|
+
pulled: report.pulled,
|
|
142
|
+
pushed: report.pushed,
|
|
143
|
+
};
|
|
144
|
+
status.lastError = undefined;
|
|
145
|
+
await daemonLog(paths, `同步完成:收集 ${report.collected.archived}/${report.collected.appended} · ` +
|
|
146
|
+
`拉取 ${report.pulled.downloadedItems} · 推送 ${report.pushed.uploadedItems} · ` +
|
|
147
|
+
`库拉取 ${report.library?.pulled.downloaded ?? 0} · 库推送 ${report.library?.pushed.uploaded ?? 0} · ` +
|
|
148
|
+
`${report.durationMs}ms`);
|
|
149
|
+
if (runtime.afterSync) {
|
|
150
|
+
try {
|
|
151
|
+
const note = await runtime.afterSync(report);
|
|
152
|
+
if (note)
|
|
153
|
+
await daemonLog(paths, note);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
await daemonLog(paths, `同步后处理失败: ${e.message}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
if (signal.aborted)
|
|
162
|
+
break; // 主动停止,不算同步失败
|
|
163
|
+
status.lastError = err.message;
|
|
164
|
+
await daemonLog(paths, `同步失败: ${status.lastError}`);
|
|
165
|
+
}
|
|
166
|
+
status.lastDurationMs = Date.now() - started;
|
|
167
|
+
status.nextRunAt = Date.now() + intervalSeconds * 1000;
|
|
168
|
+
await writeDaemonStatus(paths, status);
|
|
169
|
+
await sleep(intervalSeconds * 1000, signal);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** learn 循环:串行 tick(上一 tick 跑完 LLM 再睡),天然 single-flight,不会与自身重叠。 */
|
|
173
|
+
async function learnLoop(runtime, signal) {
|
|
174
|
+
const { paths, learnTick, intervalSeconds } = runtime;
|
|
175
|
+
const interval = runtime.learnIntervalSeconds ?? intervalSeconds;
|
|
176
|
+
while (!signal.aborted) {
|
|
177
|
+
try {
|
|
178
|
+
const note = await learnTick();
|
|
179
|
+
if (note)
|
|
180
|
+
await daemonLog(paths, note);
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
await daemonLog(paths, `经验提取失败: ${e.message}`);
|
|
184
|
+
}
|
|
185
|
+
await sleep(interval * 1000, signal);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/** 后台启动:spawn 一个独立进程,等待 pid 文件落盘后返回。 */
|
|
189
|
+
export async function startDaemon(opts) {
|
|
190
|
+
const existing = await readPidFile(opts.paths);
|
|
191
|
+
if (existing && isAlive(existing.pid)) {
|
|
192
|
+
throw new Error(`daemon 已在运行 (pid ${existing.pid})`);
|
|
193
|
+
}
|
|
194
|
+
await mkdir(dirname(opts.paths.daemonLog), { recursive: true });
|
|
195
|
+
const fd = await open(opts.paths.daemonLog, 'a');
|
|
196
|
+
const entry = opts.entry ?? process.argv[1];
|
|
197
|
+
const child = spawn(process.execPath, [
|
|
198
|
+
entry,
|
|
199
|
+
'daemon',
|
|
200
|
+
'run',
|
|
201
|
+
'--interval',
|
|
202
|
+
String(opts.intervalSeconds),
|
|
203
|
+
'--since',
|
|
204
|
+
opts.since,
|
|
205
|
+
...(opts.raw === true ? ['--raw'] : opts.raw === false ? ['--no-raw'] : []),
|
|
206
|
+
], { detached: true, stdio: ['ignore', fd.fd, fd.fd], env: { ...process.env, ...opts.env } });
|
|
207
|
+
child.unref();
|
|
208
|
+
await fd.close();
|
|
209
|
+
for (let i = 0; i < 60; i++) {
|
|
210
|
+
const pid = await readPidFile(opts.paths);
|
|
211
|
+
if (pid && isAlive(pid.pid))
|
|
212
|
+
return pid.pid;
|
|
213
|
+
if (child.exitCode !== null)
|
|
214
|
+
break;
|
|
215
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
216
|
+
}
|
|
217
|
+
throw new Error(`daemon 启动超时,请查看 ${opts.paths.daemonLog}`);
|
|
218
|
+
}
|
|
219
|
+
function processStartedAt(pid) {
|
|
220
|
+
try {
|
|
221
|
+
const out = execFileSync('ps', ['-p', String(pid), '-o', 'lstart='], {
|
|
222
|
+
encoding: 'utf8',
|
|
223
|
+
}).trim();
|
|
224
|
+
const t = Date.parse(out);
|
|
225
|
+
return Number.isFinite(t) ? t : null;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** 优雅停止:发 SIGTERM,最多等 5 秒;不做 SIGKILL,避免中断写入。 */
|
|
232
|
+
export async function stopDaemon(paths) {
|
|
233
|
+
const existing = await readPidFile(paths);
|
|
234
|
+
if (!existing || !isAlive(existing.pid)) {
|
|
235
|
+
await releaseDaemonPid(paths);
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
// pid 可能被系统复用:启动时间对不上就只清理陈旧锁,绝不误杀
|
|
239
|
+
const actualStart = processStartedAt(existing.pid);
|
|
240
|
+
if (existing.startedAt && actualStart && Math.abs(actualStart - existing.startedAt) > 5000) {
|
|
241
|
+
await releaseDaemonPid(paths);
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
process.kill(existing.pid, 'SIGTERM');
|
|
245
|
+
for (let i = 0; i < 50; i++) {
|
|
246
|
+
if (!isAlive(existing.pid)) {
|
|
247
|
+
await releaseDaemonPid(paths);
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* 重启:先优雅停止(没在跑就直接跳过),再按同样的参数后台拉起。
|
|
256
|
+
* 停止失败(进程没退)时 startDaemon 会因 pid 锁仍在而报错,不会起两个实例。
|
|
257
|
+
*/
|
|
258
|
+
export async function restartDaemon(opts) {
|
|
259
|
+
const stop = opts.stop ?? stopDaemon;
|
|
260
|
+
const wasRunning = await stop(opts.paths);
|
|
261
|
+
const pid = await startDaemon(opts);
|
|
262
|
+
return { pid, wasRunning };
|
|
263
|
+
}
|
|
264
|
+
export async function daemonState(paths) {
|
|
265
|
+
const pid = await readPidFile(paths);
|
|
266
|
+
return {
|
|
267
|
+
running: Boolean(pid && isAlive(pid.pid)),
|
|
268
|
+
...(pid ? { pid: pid.pid } : {}),
|
|
269
|
+
status: await readDaemonStatus(paths),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAgClD,MAAM,CAAC,MAAM,OAAO,GAAG,cAAc,CAAC;AAEtC,KAAK,UAAU,WAAW,CAAC,KAAiB;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyC,CAAC;QAClE,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3C,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,0CAA0C;AAC1C,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAiB;IACtD,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YAChF,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;YAChE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;YAC1C,IAAI,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtC,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAiB;IACtD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC;QAC9C,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAiB;IACtD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAqB,CAAC;IACpF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,KAAiB,EAAE,MAAwB;IAC1E,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,YAAY,MAAM,CAAC;IACxC,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;AACxC,CAAC;AAED,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAiB,EAAE,IAAY;IAC7D,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,EAAE,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;YAC/B,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IACD,MAAM,UAAU,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,WAAW,CAAC,KAAiB;IACpC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO;QACL,KAAK,CAAC,IAAI,EAAE,MAAM;YAChB,KAAK,SAAS,CAAC,KAAK,EAAE,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,IAAI,GAAG,GAAG,IAAI,GAAG,MAAM,IAAI,OAAO,GAAG,KAAK;gBAAE,OAAO;YACnD,IAAI,GAAG,GAAG,CAAC;YACX,KAAK,SAAS,CAAC,KAAK,EAAE,cAAc,OAAO,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,EAAU,EAAE,MAAmB;IAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,OAAO,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAClC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACpC,YAAY,CAAC,CAAC,CAAC,CAAC;YAChB,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAsB,EAAE,MAAmB;IACzE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAClD,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAE9B,MAAM,MAAM,GAAqB;QAC/B,OAAO,EAAE,IAAI;QACb,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,eAAe;QACf,KAAK;KACN,CAAC;IACF,MAAM,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,SAAS,CAAC,KAAK,EAAE,iBAAiB,OAAO,CAAC,GAAG,aAAa,eAAe,WAAW,KAAK,EAAE,CAAC,CAAC;IAEnG,IAAI,CAAC;QACH,MAAM,KAAK,GAAoB,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACnE,IAAI,OAAO,CAAC,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7B,MAAM,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,OAAsB,EAAE,MAAwB,EAAE,MAAmB;IAC3F,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACpD,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,CAAC,SAAS,GAAG,OAAO,CAAC;QAC3B,MAAM,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,sBAAsB;QAC9D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;YACzD,MAAM,CAAC,UAAU,GAAG;gBAClB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;YACF,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;YAC7B,MAAM,SAAS,CACb,KAAK,EACL,WAAW,MAAM,CAAC,SAAS,CAAC,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,QAAQ,KAAK;gBACpE,MAAM,MAAM,CAAC,MAAM,CAAC,eAAe,SAAS,MAAM,CAAC,MAAM,CAAC,aAAa,KAAK;gBAC5E,OAAO,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC,UAAU,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC,KAAK;gBAChG,GAAG,MAAM,CAAC,UAAU,IAAI,CAC3B,CAAC;YACF,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBACtB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;oBAC7C,IAAI,IAAI;wBAAE,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;gBACzC,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,MAAM,SAAS,CAAC,KAAK,EAAE,YAAa,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,MAAM,CAAC,OAAO;gBAAE,MAAM,CAAC,cAAc;YACzC,MAAM,CAAC,SAAS,GAAI,GAAa,CAAC,OAAO,CAAC;YAC1C,MAAM,SAAS,CAAC,KAAK,EAAE,SAAS,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;QAC7C,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,GAAG,IAAI,CAAC;QACvD,MAAM,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,KAAK,CAAC,eAAe,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,KAAK,UAAU,SAAS,CAAC,OAAsB,EAAE,MAAmB;IAClE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,oBAAoB,IAAI,eAAe,CAAC;IACjE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAU,EAAE,CAAC;YAChC,IAAI,IAAI;gBAAE,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,SAAS,CAAC,KAAK,EAAE,WAAY,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,KAAK,CAAC,QAAQ,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAcD,wCAAwC;AACxC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAwB;IACxD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,KAAK,CACjB,OAAO,CAAC,QAAQ,EAChB;QACE,KAAK;QACL,QAAQ;QACR,KAAK;QACL,YAAY;QACZ,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;QAC5B,SAAS;QACT,IAAI,CAAC,KAAK;QACV,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,EACD,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAC1F,CAAC;IACF,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC,GAAG,CAAC;QAC5C,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI;YAAE,MAAM;QACnC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE;YACnE,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1B,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAiB;IAChD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,kCAAkC;IAClC,MAAM,WAAW,GAAG,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,QAAQ,CAAC,SAAS,IAAI,WAAW,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,CAAC;QAC3F,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAOD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAA0B;IAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC;IACrC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAiB;IAKjD,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChC,MAAM,EAAE,MAAM,gBAAgB,CAAC,KAAK,CAAC;KACtC,CAAC;AACJ,CAAC"}
|
package/dist/format.d.ts
ADDED
package/dist/format.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** 字节数 → 人类可读字符串(如 "45 KB"、"1.2 MB"、"106 MB")。 */
|
|
2
|
+
export function humanSize(bytes) {
|
|
3
|
+
if (!Number.isFinite(bytes) || bytes < 0)
|
|
4
|
+
return '0 B';
|
|
5
|
+
if (bytes < 1024)
|
|
6
|
+
return `${bytes} B`;
|
|
7
|
+
const units = ['KB', 'MB', 'GB', 'TB', 'PB'];
|
|
8
|
+
let value = bytes;
|
|
9
|
+
let u = -1;
|
|
10
|
+
while (value >= 1024 && u < units.length - 1) {
|
|
11
|
+
value /= 1024;
|
|
12
|
+
u++;
|
|
13
|
+
}
|
|
14
|
+
const text = value >= 100 ? String(Math.round(value)) : value.toFixed(1).replace(/\.0$/, '');
|
|
15
|
+
return `${text} ${units[u]}`;
|
|
16
|
+
}
|
|
17
|
+
/** 时间跨度 → "42 秒 / 5 分钟 / 2 小时 / 3 天";调用方自行加「前 / 后」。 */
|
|
18
|
+
export function humanSpan(ms) {
|
|
19
|
+
const s = Math.max(0, Math.round(ms / 1000));
|
|
20
|
+
if (s < 60)
|
|
21
|
+
return `${s} 秒`;
|
|
22
|
+
if (s < 3600)
|
|
23
|
+
return `${Math.round(s / 60)} 分钟`;
|
|
24
|
+
if (s < 86400)
|
|
25
|
+
return `${Math.round(s / 3600)} 小时`;
|
|
26
|
+
return `${Math.round(s / 86400)} 天`;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACvD,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACX,OAAO,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,KAAK,IAAI,IAAI,CAAC;QACd,CAAC,EAAE,CAAC;IACN,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7F,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/B,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,SAAS,CAAC,EAAU;IAClC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IAC5B,IAAI,CAAC,GAAG,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;IAChD,IAAI,CAAC,GAAG,KAAK;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;IACnD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;AACtC,CAAC"}
|
package/dist/main.d.ts
ADDED
package/dist/main.js
ADDED
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACvB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KAClC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACX,OAAO,CAAC,KAAK,CAAC,OAAQ,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** trove 本地目录布局。 */
|
|
2
|
+
export interface TrovePaths {
|
|
3
|
+
base: string;
|
|
4
|
+
config: string;
|
|
5
|
+
vault: string;
|
|
6
|
+
/** 游标 + 推送/拉取水位(单文件,原子写) */
|
|
7
|
+
state: string;
|
|
8
|
+
/** 自身 LLM 调用的 token 用量台账(JSONL,只追加) */
|
|
9
|
+
usageLog: string;
|
|
10
|
+
logs: string;
|
|
11
|
+
tmp: string;
|
|
12
|
+
daemonPid: string;
|
|
13
|
+
daemonStatus: string;
|
|
14
|
+
daemonLog: string;
|
|
15
|
+
/** learn 待办队列(不在 vault 内,不参与同步) */
|
|
16
|
+
learnQueue: string;
|
|
17
|
+
}
|
|
18
|
+
/** 从 base 目录推导全部路径。默认 ~/.trove,可用 TROVE_HOME 覆盖;测试可注入临时 base。 */
|
|
19
|
+
export declare function trovePaths(base?: string): TrovePaths;
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/** 从 base 目录推导全部路径。默认 ~/.trove,可用 TROVE_HOME 覆盖;测试可注入临时 base。 */
|
|
4
|
+
export function trovePaths(base = process.env.TROVE_HOME || join(homedir(), '.trove')) {
|
|
5
|
+
return {
|
|
6
|
+
base,
|
|
7
|
+
config: join(base, 'config.json'),
|
|
8
|
+
vault: join(base, 'vault'),
|
|
9
|
+
state: join(base, 'state.json'),
|
|
10
|
+
usageLog: join(base, 'usage.jsonl'),
|
|
11
|
+
logs: join(base, 'logs'),
|
|
12
|
+
tmp: join(base, 'tmp'),
|
|
13
|
+
daemonPid: join(base, 'daemon.pid'),
|
|
14
|
+
daemonStatus: join(base, 'daemon.status.json'),
|
|
15
|
+
daemonLog: join(base, 'logs', 'daemon.log'),
|
|
16
|
+
learnQueue: join(base, 'learn-queue.json'),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoBjC,iEAAiE;AACjE,MAAM,UAAU,UAAU,CACxB,OAAe,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC;IAElE,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QACjC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC1B,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QACxB,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QACtB,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QACnC,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC;QAC9C,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC;QAC3C,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC;KAC3C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Progress } from './progress.js';
|
|
2
|
+
export interface ConsoleProgressOptions {
|
|
3
|
+
write: (s: string) => void;
|
|
4
|
+
tty?: boolean;
|
|
5
|
+
now?: () => number;
|
|
6
|
+
intervalMs?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 终端进度:TTY 用 \r 原地刷新,管道/日志按固定间隔输出,
|
|
10
|
+
* 避免一次 sync 刷出上万行。最后一项总是输出。
|
|
11
|
+
*/
|
|
12
|
+
export declare function createConsoleProgress(opts: ConsoleProgressOptions): Progress;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { humanSize } from './format.js';
|
|
2
|
+
/**
|
|
3
|
+
* 终端进度:TTY 用 \r 原地刷新,管道/日志按固定间隔输出,
|
|
4
|
+
* 避免一次 sync 刷出上万行。最后一项总是输出。
|
|
5
|
+
*/
|
|
6
|
+
export function createConsoleProgress(opts) {
|
|
7
|
+
const write = opts.write;
|
|
8
|
+
const tty = opts.tty ?? false;
|
|
9
|
+
const now = opts.now ?? Date.now;
|
|
10
|
+
const interval = opts.intervalMs ?? 1000;
|
|
11
|
+
let phase = '';
|
|
12
|
+
let lastPrint = 0;
|
|
13
|
+
let lastLen = 0;
|
|
14
|
+
const line = (text, final) => {
|
|
15
|
+
if (tty) {
|
|
16
|
+
const padded = text + ' '.repeat(Math.max(0, lastLen - text.length));
|
|
17
|
+
write(`\r${padded}${final ? '\n' : ''}`);
|
|
18
|
+
lastLen = final ? 0 : text.length;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
write(`${text}\n`);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
phase(name, detail) {
|
|
26
|
+
phase = name;
|
|
27
|
+
lastPrint = 0;
|
|
28
|
+
line(detail ? `[${name}] ${detail}` : `[${name}]`, true);
|
|
29
|
+
},
|
|
30
|
+
item(label, current, total, bytes = 0) {
|
|
31
|
+
const t = now();
|
|
32
|
+
const final = total > 0 && current >= total;
|
|
33
|
+
if (!tty && !final && t - lastPrint < interval)
|
|
34
|
+
return;
|
|
35
|
+
lastPrint = t;
|
|
36
|
+
const short = label.length > 64 ? `…${label.slice(-63)}` : label;
|
|
37
|
+
const size = bytes > 0 ? ` · ${humanSize(bytes)}` : '';
|
|
38
|
+
line(`[${phase}] ${current}/${total}${size} ${short}`, final);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=progress-console.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress-console.js","sourceRoot":"","sources":["../src/progress-console.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAUxC;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAA4B;IAChE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC;IACzC,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAC5C,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,MAAM,GAAG,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACrE,KAAK,CAAC,KAAK,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,IAAI,EAAE,MAAM;YAChB,KAAK,GAAG,IAAI,CAAC;YACb,SAAS,GAAG,CAAC,CAAC;YACd,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC;YACnC,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,IAAI,OAAO,IAAI,KAAK,CAAC;YAC5C,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,GAAG,QAAQ;gBAAE,OAAO;YACvD,SAAS,GAAG,CAAC,CAAC;YACd,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;YACjE,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;QAChE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** 进度上报:阶段 + 单项进度;CLI/TUI 各自实现,编排层只依赖此接口。 */
|
|
2
|
+
export interface Progress {
|
|
3
|
+
phase(name: string, detail?: string): void;
|
|
4
|
+
item(label: string, current: number, total: number, bytes?: number): void;
|
|
5
|
+
}
|
|
6
|
+
/** 测试/daemon 静默模式。 */
|
|
7
|
+
export declare const silentProgress: Progress;
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAMA,sBAAsB;AACtB,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,KAAK,KAAI,CAAC;IACV,IAAI,KAAI,CAAC;CACV,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RemoteConfig } from '../config.js';
|
|
2
|
+
import type { RemoteStore } from './store.js';
|
|
3
|
+
/**
|
|
4
|
+
* 按配置构造远端实现。这是 WebDAV 与 S3 唯一的分叉点:
|
|
5
|
+
* 上层(push/pull/library sync)只认 RemoteStore 接口。
|
|
6
|
+
*/
|
|
7
|
+
export declare function createRemoteFromConfig(config: RemoteConfig): RemoteStore;
|
|
8
|
+
/** 配置是否完整到可以连远端。 */
|
|
9
|
+
export declare function isRemoteConfigured(config: RemoteConfig): boolean;
|
|
10
|
+
/** 远端的可读描述,用于 status 输出。 */
|
|
11
|
+
export declare function describeRemote(config: RemoteConfig): string;
|
|
12
|
+
/**
|
|
13
|
+
* 远端身份指纹:用来判断"还是同一个远端吗"。
|
|
14
|
+
*
|
|
15
|
+
* 换后端(WebDAV → S3)后指纹会变,本地记录的推送/拉取水位自动作废,
|
|
16
|
+
* 从而把历史数据整份重推到新后端,而不是以为推过了。
|
|
17
|
+
*
|
|
18
|
+
* 不含凭证 —— 轮换密钥不该触发一次全量重推。
|
|
19
|
+
*/
|
|
20
|
+
export declare function remoteIdentity(config: RemoteConfig): string;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { resolveEndpoint } from './s3-vendors.js';
|
|
2
|
+
import { S3Store } from './s3-store.js';
|
|
3
|
+
import { WebDavStore } from './webdav-store.js';
|
|
4
|
+
/**
|
|
5
|
+
* 按配置构造远端实现。这是 WebDAV 与 S3 唯一的分叉点:
|
|
6
|
+
* 上层(push/pull/library sync)只认 RemoteStore 接口。
|
|
7
|
+
*/
|
|
8
|
+
export function createRemoteFromConfig(config) {
|
|
9
|
+
if (config.type === 's3') {
|
|
10
|
+
const endpoint = resolveEndpoint({
|
|
11
|
+
provider: config.provider,
|
|
12
|
+
region: config.region,
|
|
13
|
+
endpoint: config.endpoint,
|
|
14
|
+
});
|
|
15
|
+
return new S3Store({
|
|
16
|
+
endpoint,
|
|
17
|
+
region: config.region,
|
|
18
|
+
bucket: config.bucket,
|
|
19
|
+
accessKeyId: config.accessKeyId,
|
|
20
|
+
secretAccessKey: config.secretAccessKey,
|
|
21
|
+
forcePathStyle: config.forcePathStyle ?? false,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return new WebDavStore({
|
|
25
|
+
url: config.url,
|
|
26
|
+
username: config.username,
|
|
27
|
+
password: config.password,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/** 配置是否完整到可以连远端。 */
|
|
31
|
+
export function isRemoteConfigured(config) {
|
|
32
|
+
if (config.type === 's3') {
|
|
33
|
+
return Boolean(config.bucket &&
|
|
34
|
+
config.region &&
|
|
35
|
+
config.accessKeyId &&
|
|
36
|
+
config.secretAccessKey &&
|
|
37
|
+
(config.provider || config.endpoint));
|
|
38
|
+
}
|
|
39
|
+
return Boolean(config.url && config.password);
|
|
40
|
+
}
|
|
41
|
+
/** 远端的可读描述,用于 status 输出。 */
|
|
42
|
+
export function describeRemote(config) {
|
|
43
|
+
if (config.type === 's3') {
|
|
44
|
+
const endpoint = (() => {
|
|
45
|
+
try {
|
|
46
|
+
return resolveEndpoint({
|
|
47
|
+
provider: config.provider,
|
|
48
|
+
region: config.region,
|
|
49
|
+
endpoint: config.endpoint,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return config.endpoint ?? '(未配置)';
|
|
54
|
+
}
|
|
55
|
+
})();
|
|
56
|
+
return `${endpoint} · ${config.bucket || '(未配置 bucket)'}`;
|
|
57
|
+
}
|
|
58
|
+
return config.url;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 远端身份指纹:用来判断"还是同一个远端吗"。
|
|
62
|
+
*
|
|
63
|
+
* 换后端(WebDAV → S3)后指纹会变,本地记录的推送/拉取水位自动作废,
|
|
64
|
+
* 从而把历史数据整份重推到新后端,而不是以为推过了。
|
|
65
|
+
*
|
|
66
|
+
* 不含凭证 —— 轮换密钥不该触发一次全量重推。
|
|
67
|
+
*/
|
|
68
|
+
export function remoteIdentity(config) {
|
|
69
|
+
if (config.type === 's3') {
|
|
70
|
+
const endpoint = (() => {
|
|
71
|
+
try {
|
|
72
|
+
return resolveEndpoint({
|
|
73
|
+
provider: config.provider,
|
|
74
|
+
region: config.region,
|
|
75
|
+
endpoint: config.endpoint,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return config.endpoint ?? '';
|
|
80
|
+
}
|
|
81
|
+
})();
|
|
82
|
+
return `s3:${endpoint}/${config.bucket}`;
|
|
83
|
+
}
|
|
84
|
+
return `webdav:${config.url}`;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=create-remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-remote.js","sourceRoot":"","sources":["../../src/remote/create-remote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RemoteConfig } from '../config.js';
|
|
2
|
+
/**
|
|
3
|
+
* 远端后端的交互式配置引导。
|
|
4
|
+
*
|
|
5
|
+
* 顺序:先选后端类型,再按类型问对应字段 —— 用户不需要先知道要填 URL 还是 Bucket。
|
|
6
|
+
*/
|
|
7
|
+
export type RemoteType = 'webdav' | 's3';
|
|
8
|
+
export declare function isCancel(v: unknown): v is symbol;
|
|
9
|
+
/**
|
|
10
|
+
* 交互式引导远端配置。
|
|
11
|
+
*
|
|
12
|
+
* @param existing 当前配置,用作默认值
|
|
13
|
+
* @param interactive 是否交互
|
|
14
|
+
* @param forcedType 强制指定类型(init 的 --type flag)
|
|
15
|
+
* @returns 远端配置;非交互模式返回 undefined
|
|
16
|
+
*/
|
|
17
|
+
export declare function promptRemoteConfig(existing: RemoteConfig | undefined, interactive: boolean, forcedType?: RemoteType): Promise<RemoteConfig | undefined>;
|