chatlab-cli 0.22.1 → 0.23.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/dist/{chunk-OC2W5Q5T.mjs → chunk-3MX7VF2B.mjs} +2 -2
- package/dist/chunk-5ADKYYNA.mjs +28 -0
- package/dist/chunk-5ADKYYNA.mjs.map +1 -0
- package/dist/{chunk-QRC3RSER.mjs → chunk-643S2N2U.mjs} +2 -2
- package/dist/{chunk-XPBPKH6B.mjs → chunk-D2BR3MFN.mjs} +107 -37
- package/dist/chunk-D2BR3MFN.mjs.map +1 -0
- package/dist/{chunk-6NB475AA.mjs → chunk-FJ35V3TE.mjs} +2 -17
- package/dist/chunk-FJ35V3TE.mjs.map +1 -0
- package/dist/{chunk-SQKT45MM.mjs → chunk-G7Q7EQ3V.mjs} +546 -84
- package/dist/chunk-G7Q7EQ3V.mjs.map +1 -0
- package/dist/{chunk-LZ3W6NS5.mjs → chunk-NTWDG52H.mjs} +66 -68
- package/dist/chunk-NTWDG52H.mjs.map +1 -0
- package/dist/{chunk-Z2LYMKCC.mjs → chunk-WTQ7LAZR.mjs} +2 -2
- package/dist/cli.mjs +4 -3
- package/dist/{http-O5P4BYXU.mjs → http-2DN3XOXO.mjs} +8 -7
- package/dist/{import-BDLL3DG7.mjs → import-LCBSBLYF.mjs} +4 -4
- package/dist/index.mjs +10 -9
- package/dist/{mcp-L2TPZFE7.mjs → mcp-AR7HBIK4.mjs} +8 -6
- package/dist/{mcp-L2TPZFE7.mjs.map → mcp-AR7HBIK4.mjs.map} +1 -1
- package/dist/service-WNEVPQ4N.mjs +258 -0
- package/dist/service-WNEVPQ4N.mjs.map +1 -0
- package/dist/{src-FVJL5ENA.mjs → src-EGXULYFQ.mjs} +2 -2
- package/dist/{stream-import-ZTEW3YVL.mjs → stream-import-QM5R5FDG.mjs} +3 -3
- package/dist/{update-checker-MQMQ6A4B.mjs → update-checker-JG5K67O2.mjs} +3 -2
- package/dist/{update-checker-MQMQ6A4B.mjs.map → update-checker-JG5K67O2.mjs.map} +1 -1
- package/dist-web/assets/{DebugToolsPanel-DkbsB6lr.css → DebugToolsPanel-D9O_4J04.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-hp9Mjpub.js +161 -0
- package/dist-web/assets/{EChartWordcloud-Ubal_aYg.js → EChartWordcloud-Cenbzcyj.js} +1 -1
- package/dist-web/assets/MessageExportModal-CvocO88D.js +1 -0
- package/dist-web/assets/electron-DpE69lO4.js +1 -0
- package/dist-web/assets/electron-SyPZX9OU.js +1 -0
- package/dist-web/assets/{fetch-BS4SlQjA.js → fetch-B7OBmANJ.js} +1 -1
- package/dist-web/assets/{fetch-o5NJ2uWE.js → fetch-BikSxuED.js} +1 -1
- package/dist-web/assets/fetch-BwMZFwbF.js +1 -0
- package/dist-web/assets/fetch-CfTcWxqG.js +1 -0
- package/dist-web/assets/fetch-DTP8Q782.js +17 -0
- package/dist-web/assets/{fetch-W43zfemj.js → fetch-LBHcBBkv.js} +1 -1
- package/dist-web/assets/http-C741fIwb.js +1 -0
- package/dist-web/assets/index-B6dkyIiA.js +2 -0
- package/dist-web/assets/index-CALU1QPF.js +163 -0
- package/dist-web/assets/{index-DOwQB7In.js → index-CHkXbqMb.js} +1 -1
- package/dist-web/assets/{index-DSpvXged.css → index-CvuHOeoU.css} +1 -1
- package/dist-web/assets/{index-BE64tUWq.css → index-CxMP0DNd.css} +1 -1
- package/dist-web/assets/index-DOS5o2_H.js +7 -0
- package/dist-web/assets/{index-CbQMfheg.css → index-DuepdDzz.css} +1 -1
- package/dist-web/assets/index-niwrSprs.js +173 -0
- package/dist-web/assets/model-catalog-DUuKjIVU.js +1 -0
- package/dist-web/assets/{vendor-nuxt-ui-7OAuiz_i.js → vendor-nuxt-ui-CuCZ1aRl.js} +2 -2
- package/dist-web/assets/vendor-reka-ui-BrTYuIfH.js +11 -0
- package/dist-web/assets/{web-Cx5APyCN.js → web-DGd63PrV.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-6NB475AA.mjs.map +0 -1
- package/dist/chunk-LZ3W6NS5.mjs.map +0 -1
- package/dist/chunk-SQKT45MM.mjs.map +0 -1
- package/dist/chunk-XPBPKH6B.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-CqacsKDU.js +0 -147
- package/dist-web/assets/MessageExportModal-D1GY6WSV.js +0 -1
- package/dist-web/assets/electron-8qi0d92j.js +0 -1
- package/dist-web/assets/electron-CsUM2O_Y.js +0 -1
- package/dist-web/assets/fetch-BOogCPfg.js +0 -1
- package/dist-web/assets/fetch-CclRWOHf.js +0 -1
- package/dist-web/assets/fetch-CxwnEEqk.js +0 -17
- package/dist-web/assets/http-CeXMt-Fv.js +0 -1
- package/dist-web/assets/index-CM29Kc4p.js +0 -173
- package/dist-web/assets/index-D183wYuz.js +0 -7
- package/dist-web/assets/index-DTxRy2FH.js +0 -163
- package/dist-web/assets/index-grds3iG-.js +0 -2
- package/dist-web/assets/vendor-reka-ui-CW2cIgMu.js +0 -11
- /package/dist/{chunk-OC2W5Q5T.mjs.map → chunk-3MX7VF2B.mjs.map} +0 -0
- /package/dist/{chunk-QRC3RSER.mjs.map → chunk-643S2N2U.mjs.map} +0 -0
- /package/dist/{chunk-Z2LYMKCC.mjs.map → chunk-WTQ7LAZR.mjs.map} +0 -0
- /package/dist/{http-O5P4BYXU.mjs.map → http-2DN3XOXO.mjs.map} +0 -0
- /package/dist/{import-BDLL3DG7.mjs.map → import-LCBSBLYF.mjs.map} +0 -0
- /package/dist/{src-FVJL5ENA.mjs.map → src-EGXULYFQ.mjs.map} +0 -0
- /package/dist/{stream-import-ZTEW3YVL.mjs.map → stream-import-QM5R5FDG.mjs.map} +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'module';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __pathDirname(__filename);
|
|
7
|
+
import {
|
|
8
|
+
resolveCliPath
|
|
9
|
+
} from "./chunk-FJ35V3TE.mjs";
|
|
10
|
+
import "./chunk-VSOWNKPA.mjs";
|
|
11
|
+
|
|
12
|
+
// src/daemon/service.ts
|
|
13
|
+
import * as fs from "fs";
|
|
14
|
+
import * as path from "path";
|
|
15
|
+
import * as os from "os";
|
|
16
|
+
import { execSync } from "child_process";
|
|
17
|
+
var SERVICE_LABEL = "fun.chatlab.daemon";
|
|
18
|
+
var PLIST_PATH = path.join(os.homedir(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
|
|
19
|
+
var SYSTEMD_DIR = path.join(os.homedir(), ".config", "systemd", "user");
|
|
20
|
+
var SYSTEMD_SERVICE = path.join(SYSTEMD_DIR, "chatlab.service");
|
|
21
|
+
var SYSTEM_DIR = path.join(os.homedir(), ".chatlab");
|
|
22
|
+
var LOG_FILE = path.join(SYSTEM_DIR, "logs", "daemon.log");
|
|
23
|
+
var META_FILE = path.join(SYSTEM_DIR, "daemon.json");
|
|
24
|
+
function writeMeta(meta) {
|
|
25
|
+
fs.mkdirSync(SYSTEM_DIR, { recursive: true });
|
|
26
|
+
fs.writeFileSync(META_FILE, JSON.stringify(meta, null, 2));
|
|
27
|
+
}
|
|
28
|
+
function readMeta() {
|
|
29
|
+
try {
|
|
30
|
+
if (!fs.existsSync(META_FILE)) return null;
|
|
31
|
+
return JSON.parse(fs.readFileSync(META_FILE, "utf-8"));
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function removeMeta() {
|
|
37
|
+
try {
|
|
38
|
+
fs.unlinkSync(META_FILE);
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function buildPlist(options) {
|
|
43
|
+
const port = options.port ?? 3110;
|
|
44
|
+
const host = options.host ?? "127.0.0.1";
|
|
45
|
+
const cliEntry = resolveCliPath("dist/cli.mjs");
|
|
46
|
+
const args = ["start", "--no-open", "--port", String(port), "--host", host];
|
|
47
|
+
if (options.token) args.push("--token", options.token);
|
|
48
|
+
if (options.headless) args.push("--headless");
|
|
49
|
+
const programArgs = [process.execPath, cliEntry, ...args].map((a) => ` <string>${a}</string>`).join("\n");
|
|
50
|
+
fs.mkdirSync(path.join(SYSTEM_DIR, "logs"), { recursive: true });
|
|
51
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
52
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
53
|
+
<plist version="1.0">
|
|
54
|
+
<dict>
|
|
55
|
+
<key>Label</key>
|
|
56
|
+
<string>${SERVICE_LABEL}</string>
|
|
57
|
+
<key>ProgramArguments</key>
|
|
58
|
+
<array>
|
|
59
|
+
${programArgs}
|
|
60
|
+
</array>
|
|
61
|
+
<key>RunAtLoad</key>
|
|
62
|
+
<true/>
|
|
63
|
+
<key>KeepAlive</key>
|
|
64
|
+
<true/>
|
|
65
|
+
<key>StandardOutPath</key>
|
|
66
|
+
<string>${LOG_FILE}</string>
|
|
67
|
+
<key>StandardErrorPath</key>
|
|
68
|
+
<string>${LOG_FILE}</string>
|
|
69
|
+
</dict>
|
|
70
|
+
</plist>
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
function getUid() {
|
|
74
|
+
return execSync("id -u", { encoding: "utf-8" }).trim();
|
|
75
|
+
}
|
|
76
|
+
function launchctlLoad(plistPath) {
|
|
77
|
+
try {
|
|
78
|
+
execSync(`launchctl bootstrap gui/${getUid()} "${plistPath}"`, { stdio: "pipe" });
|
|
79
|
+
} catch {
|
|
80
|
+
try {
|
|
81
|
+
execSync(`launchctl load "${plistPath}"`, { stdio: "pipe" });
|
|
82
|
+
} catch (err) {
|
|
83
|
+
throw new Error(`launchctl load failed: ${err instanceof Error ? err.message : err}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function launchctlUnload(plistPath) {
|
|
88
|
+
try {
|
|
89
|
+
execSync(`launchctl bootout gui/${getUid()}/${SERVICE_LABEL}`, { stdio: "pipe" });
|
|
90
|
+
} catch {
|
|
91
|
+
try {
|
|
92
|
+
execSync(`launchctl unload "${plistPath}"`, { stdio: "pipe" });
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function installMacos(options) {
|
|
98
|
+
fs.mkdirSync(path.dirname(PLIST_PATH), { recursive: true });
|
|
99
|
+
if (fs.existsSync(PLIST_PATH)) {
|
|
100
|
+
launchctlUnload(PLIST_PATH);
|
|
101
|
+
}
|
|
102
|
+
fs.writeFileSync(PLIST_PATH, buildPlist(options));
|
|
103
|
+
launchctlLoad(PLIST_PATH);
|
|
104
|
+
const port = options.port ?? 3110;
|
|
105
|
+
const host = options.host ?? "127.0.0.1";
|
|
106
|
+
writeMeta({ port, host, installedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
107
|
+
console.log(`
|
|
108
|
+
ChatLab is now running as a system service`);
|
|
109
|
+
console.log(` API: http://${host}:${port}`);
|
|
110
|
+
console.log(` Logs: ${LOG_FILE}`);
|
|
111
|
+
console.log(` Service: ${SERVICE_LABEL} (launchd)`);
|
|
112
|
+
console.log(`
|
|
113
|
+
Auto-starts on login. Use \`chatlab stop\` to remove.
|
|
114
|
+
`);
|
|
115
|
+
}
|
|
116
|
+
function uninstallMacos() {
|
|
117
|
+
if (!fs.existsSync(PLIST_PATH)) {
|
|
118
|
+
console.log("No system service found.");
|
|
119
|
+
removeMeta();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
launchctlUnload(PLIST_PATH);
|
|
123
|
+
fs.unlinkSync(PLIST_PATH);
|
|
124
|
+
removeMeta();
|
|
125
|
+
console.log(`ChatLab system service removed.`);
|
|
126
|
+
}
|
|
127
|
+
function statusMacos() {
|
|
128
|
+
if (!fs.existsSync(PLIST_PATH)) return { installed: false, running: false };
|
|
129
|
+
let running = false;
|
|
130
|
+
try {
|
|
131
|
+
const out = execSync(`launchctl list | grep ${SERVICE_LABEL}`, {
|
|
132
|
+
encoding: "utf-8",
|
|
133
|
+
stdio: "pipe"
|
|
134
|
+
}).trim();
|
|
135
|
+
running = out.length > 0 && !out.startsWith("-");
|
|
136
|
+
} catch {
|
|
137
|
+
running = false;
|
|
138
|
+
}
|
|
139
|
+
const meta = readMeta();
|
|
140
|
+
return { installed: true, running, port: meta?.port, host: meta?.host };
|
|
141
|
+
}
|
|
142
|
+
function escapeSystemdArg(arg) {
|
|
143
|
+
return '"' + arg.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
|
|
144
|
+
}
|
|
145
|
+
function buildUnit(options) {
|
|
146
|
+
const port = options.port ?? 3110;
|
|
147
|
+
const host = options.host ?? "127.0.0.1";
|
|
148
|
+
const cliEntry = resolveCliPath("dist/cli.mjs");
|
|
149
|
+
const args = ["start", "--no-open", "--port", String(port), "--host", host];
|
|
150
|
+
if (options.token) args.push("--token", options.token);
|
|
151
|
+
if (options.headless) args.push("--headless");
|
|
152
|
+
const execStart = [process.execPath, cliEntry, ...args].map(escapeSystemdArg).join(" ");
|
|
153
|
+
return `[Unit]
|
|
154
|
+
Description=ChatLab daemon
|
|
155
|
+
After=network.target
|
|
156
|
+
|
|
157
|
+
[Service]
|
|
158
|
+
ExecStart=${execStart}
|
|
159
|
+
Restart=always
|
|
160
|
+
RestartSec=5
|
|
161
|
+
StandardOutput=append:${LOG_FILE}
|
|
162
|
+
StandardError=append:${LOG_FILE}
|
|
163
|
+
|
|
164
|
+
[Install]
|
|
165
|
+
WantedBy=default.target
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
function installLinux(options) {
|
|
169
|
+
fs.mkdirSync(SYSTEMD_DIR, { recursive: true });
|
|
170
|
+
fs.mkdirSync(path.join(SYSTEM_DIR, "logs"), { recursive: true });
|
|
171
|
+
fs.writeFileSync(SYSTEMD_SERVICE, buildUnit(options));
|
|
172
|
+
try {
|
|
173
|
+
execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
174
|
+
execSync("systemctl --user enable --now chatlab.service", { stdio: "pipe" });
|
|
175
|
+
} catch (err) {
|
|
176
|
+
throw new Error(`systemctl failed: ${err instanceof Error ? err.message : err}`);
|
|
177
|
+
}
|
|
178
|
+
const port = options.port ?? 3110;
|
|
179
|
+
const host = options.host ?? "127.0.0.1";
|
|
180
|
+
writeMeta({ port, host, installedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
181
|
+
console.log(`
|
|
182
|
+
ChatLab is now running as a system service`);
|
|
183
|
+
console.log(` API: http://${host}:${port}`);
|
|
184
|
+
console.log(` Logs: ${LOG_FILE}`);
|
|
185
|
+
console.log(` Unit: ${SYSTEMD_SERVICE} (systemd)`);
|
|
186
|
+
console.log(`
|
|
187
|
+
Auto-starts on login. Use \`chatlab stop\` to remove.
|
|
188
|
+
`);
|
|
189
|
+
}
|
|
190
|
+
function uninstallLinux() {
|
|
191
|
+
if (!fs.existsSync(SYSTEMD_SERVICE)) {
|
|
192
|
+
console.log("No system service found.");
|
|
193
|
+
removeMeta();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
execSync("systemctl --user disable --now chatlab.service", { stdio: "pipe" });
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
fs.unlinkSync(SYSTEMD_SERVICE);
|
|
205
|
+
removeMeta();
|
|
206
|
+
console.log(`ChatLab system service removed.`);
|
|
207
|
+
}
|
|
208
|
+
function statusLinux() {
|
|
209
|
+
if (!fs.existsSync(SYSTEMD_SERVICE)) return { installed: false, running: false };
|
|
210
|
+
let running = false;
|
|
211
|
+
try {
|
|
212
|
+
execSync("systemctl --user is-active --quiet chatlab.service", { stdio: "pipe" });
|
|
213
|
+
running = true;
|
|
214
|
+
} catch {
|
|
215
|
+
running = false;
|
|
216
|
+
}
|
|
217
|
+
const meta = readMeta();
|
|
218
|
+
return { installed: true, running, port: meta?.port, host: meta?.host };
|
|
219
|
+
}
|
|
220
|
+
function serviceInstall(options) {
|
|
221
|
+
switch (process.platform) {
|
|
222
|
+
case "darwin":
|
|
223
|
+
return installMacos(options);
|
|
224
|
+
case "linux":
|
|
225
|
+
return installLinux(options);
|
|
226
|
+
default:
|
|
227
|
+
console.error("Windows is not yet supported for daemon mode.");
|
|
228
|
+
console.error("Please use `chatlab start` to run in the foreground instead.");
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function serviceUninstall() {
|
|
233
|
+
switch (process.platform) {
|
|
234
|
+
case "darwin":
|
|
235
|
+
return uninstallMacos();
|
|
236
|
+
case "linux":
|
|
237
|
+
return uninstallLinux();
|
|
238
|
+
default:
|
|
239
|
+
console.error("Windows is not yet supported for daemon mode.");
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function getServiceStatus() {
|
|
244
|
+
switch (process.platform) {
|
|
245
|
+
case "darwin":
|
|
246
|
+
return statusMacos();
|
|
247
|
+
case "linux":
|
|
248
|
+
return statusLinux();
|
|
249
|
+
default:
|
|
250
|
+
return { installed: false, running: false };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
export {
|
|
254
|
+
getServiceStatus,
|
|
255
|
+
serviceInstall,
|
|
256
|
+
serviceUninstall
|
|
257
|
+
};
|
|
258
|
+
//# sourceMappingURL=service-WNEVPQ4N.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon/service.ts"],"sourcesContent":["/**\n * System service management — register ChatLab as a launchd (macOS) or\n * systemd --user (Linux) service for auto-start on login and crash recovery.\n *\n * macOS : ~/Library/LaunchAgents/fun.chatlab.daemon.plist\n * Linux : ~/.config/systemd/user/chatlab.service\n * Meta : ~/.chatlab/daemon.json { port, host, installedAt }\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as os from 'os'\nimport { execSync } from 'child_process'\nimport { resolveCliPath } from '../paths'\n\nconst SERVICE_LABEL = 'fun.chatlab.daemon'\nconst PLIST_PATH = path.join(os.homedir(), 'Library', 'LaunchAgents', `${SERVICE_LABEL}.plist`)\nconst SYSTEMD_DIR = path.join(os.homedir(), '.config', 'systemd', 'user')\nconst SYSTEMD_SERVICE = path.join(SYSTEMD_DIR, 'chatlab.service')\nconst SYSTEM_DIR = path.join(os.homedir(), '.chatlab')\nconst LOG_FILE = path.join(SYSTEM_DIR, 'logs', 'daemon.log')\nconst META_FILE = path.join(SYSTEM_DIR, 'daemon.json')\n\ninterface DaemonMeta {\n port: number\n host: string\n installedAt: string\n}\n\nfunction writeMeta(meta: DaemonMeta): void {\n fs.mkdirSync(SYSTEM_DIR, { recursive: true })\n fs.writeFileSync(META_FILE, JSON.stringify(meta, null, 2))\n}\n\nfunction readMeta(): DaemonMeta | null {\n try {\n if (!fs.existsSync(META_FILE)) return null\n return JSON.parse(fs.readFileSync(META_FILE, 'utf-8')) as DaemonMeta\n } catch {\n return null\n }\n}\n\nfunction removeMeta(): void {\n try {\n fs.unlinkSync(META_FILE)\n } catch {\n // already removed, ignore\n }\n}\n\n// ── Public types ──────────────────────────────────────────────────────\n\nexport interface ServiceInstallOptions {\n port?: number\n host?: string\n token?: string\n headless?: boolean\n}\n\nexport interface ServiceStatus {\n installed: boolean\n running: boolean\n port?: number\n host?: string\n}\n\n// ── macOS (launchd) ───────────────────────────────────────────────────\n\nfunction buildPlist(options: ServiceInstallOptions): string {\n const port = options.port ?? 3110\n const host = options.host ?? '127.0.0.1'\n const cliEntry = resolveCliPath('dist/cli.mjs')\n const args = ['start', '--no-open', '--port', String(port), '--host', host]\n if (options.token) args.push('--token', options.token)\n if (options.headless) args.push('--headless')\n\n const programArgs = [process.execPath, cliEntry, ...args]\n .map((a) => ` <string>${a}</string>`)\n .join('\\n')\n\n fs.mkdirSync(path.join(SYSTEM_DIR, 'logs'), { recursive: true })\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${SERVICE_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n${programArgs}\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${LOG_FILE}</string>\n <key>StandardErrorPath</key>\n <string>${LOG_FILE}</string>\n</dict>\n</plist>\n`\n}\n\nfunction getUid(): string {\n return execSync('id -u', { encoding: 'utf-8' }).trim()\n}\n\nfunction launchctlLoad(plistPath: string): void {\n try {\n execSync(`launchctl bootstrap gui/${getUid()} \"${plistPath}\"`, { stdio: 'pipe' })\n } catch {\n try {\n execSync(`launchctl load \"${plistPath}\"`, { stdio: 'pipe' })\n } catch (err) {\n throw new Error(`launchctl load failed: ${err instanceof Error ? err.message : err}`)\n }\n }\n}\n\nfunction launchctlUnload(plistPath: string): void {\n try {\n execSync(`launchctl bootout gui/${getUid()}/${SERVICE_LABEL}`, { stdio: 'pipe' })\n } catch {\n try {\n execSync(`launchctl unload \"${plistPath}\"`, { stdio: 'pipe' })\n } catch {\n // already unloaded, ignore\n }\n }\n}\n\nfunction installMacos(options: ServiceInstallOptions): void {\n fs.mkdirSync(path.dirname(PLIST_PATH), { recursive: true })\n\n if (fs.existsSync(PLIST_PATH)) {\n launchctlUnload(PLIST_PATH)\n }\n\n fs.writeFileSync(PLIST_PATH, buildPlist(options))\n launchctlLoad(PLIST_PATH)\n\n const port = options.port ?? 3110\n const host = options.host ?? '127.0.0.1'\n writeMeta({ port, host, installedAt: new Date().toISOString() })\n\n console.log(`\\nChatLab is now running as a system service`)\n console.log(` API: http://${host}:${port}`)\n console.log(` Logs: ${LOG_FILE}`)\n console.log(` Service: ${SERVICE_LABEL} (launchd)`)\n console.log(`\\nAuto-starts on login. Use \\`chatlab stop\\` to remove.\\n`)\n}\n\nfunction uninstallMacos(): void {\n if (!fs.existsSync(PLIST_PATH)) {\n console.log('No system service found.')\n removeMeta()\n return\n }\n launchctlUnload(PLIST_PATH)\n fs.unlinkSync(PLIST_PATH)\n removeMeta()\n console.log(`ChatLab system service removed.`)\n}\n\nfunction statusMacos(): ServiceStatus {\n if (!fs.existsSync(PLIST_PATH)) return { installed: false, running: false }\n let running = false\n try {\n const out = execSync(`launchctl list | grep ${SERVICE_LABEL}`, {\n encoding: 'utf-8',\n stdio: 'pipe',\n }).trim()\n // launchctl list: PID Status Label — PID is '-' when not running\n running = out.length > 0 && !out.startsWith('-')\n } catch {\n running = false\n }\n const meta = readMeta()\n return { installed: true, running, port: meta?.port, host: meta?.host }\n}\n\n// ── Linux (systemd --user) ────────────────────────────────────────────\n\nfunction escapeSystemdArg(arg: string): string {\n return '\"' + arg.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"') + '\"'\n}\n\nfunction buildUnit(options: ServiceInstallOptions): string {\n const port = options.port ?? 3110\n const host = options.host ?? '127.0.0.1'\n const cliEntry = resolveCliPath('dist/cli.mjs')\n const args = ['start', '--no-open', '--port', String(port), '--host', host]\n if (options.token) args.push('--token', options.token)\n if (options.headless) args.push('--headless')\n const execStart = [process.execPath, cliEntry, ...args].map(escapeSystemdArg).join(' ')\n\n return `[Unit]\nDescription=ChatLab daemon\nAfter=network.target\n\n[Service]\nExecStart=${execStart}\nRestart=always\nRestartSec=5\nStandardOutput=append:${LOG_FILE}\nStandardError=append:${LOG_FILE}\n\n[Install]\nWantedBy=default.target\n`\n}\n\nfunction installLinux(options: ServiceInstallOptions): void {\n fs.mkdirSync(SYSTEMD_DIR, { recursive: true })\n fs.mkdirSync(path.join(SYSTEM_DIR, 'logs'), { recursive: true })\n\n fs.writeFileSync(SYSTEMD_SERVICE, buildUnit(options))\n\n try {\n execSync('systemctl --user daemon-reload', { stdio: 'pipe' })\n execSync('systemctl --user enable --now chatlab.service', { stdio: 'pipe' })\n } catch (err) {\n throw new Error(`systemctl failed: ${err instanceof Error ? err.message : err}`)\n }\n\n const port = options.port ?? 3110\n const host = options.host ?? '127.0.0.1'\n writeMeta({ port, host, installedAt: new Date().toISOString() })\n\n console.log(`\\nChatLab is now running as a system service`)\n console.log(` API: http://${host}:${port}`)\n console.log(` Logs: ${LOG_FILE}`)\n console.log(` Unit: ${SYSTEMD_SERVICE} (systemd)`)\n console.log(`\\nAuto-starts on login. Use \\`chatlab stop\\` to remove.\\n`)\n}\n\nfunction uninstallLinux(): void {\n if (!fs.existsSync(SYSTEMD_SERVICE)) {\n console.log('No system service found.')\n removeMeta()\n return\n }\n try {\n execSync('systemctl --user disable --now chatlab.service', { stdio: 'pipe' })\n } catch {\n // already stopped\n }\n try {\n execSync('systemctl --user daemon-reload', { stdio: 'pipe' })\n } catch {\n // ignore\n }\n fs.unlinkSync(SYSTEMD_SERVICE)\n removeMeta()\n console.log(`ChatLab system service removed.`)\n}\n\nfunction statusLinux(): ServiceStatus {\n if (!fs.existsSync(SYSTEMD_SERVICE)) return { installed: false, running: false }\n let running = false\n try {\n execSync('systemctl --user is-active --quiet chatlab.service', { stdio: 'pipe' })\n running = true\n } catch {\n running = false\n }\n const meta = readMeta()\n return { installed: true, running, port: meta?.port, host: meta?.host }\n}\n\n// ── Public API ────────────────────────────────────────────────────────\n\nexport function serviceInstall(options: ServiceInstallOptions): void {\n switch (process.platform) {\n case 'darwin':\n return installMacos(options)\n case 'linux':\n return installLinux(options)\n default:\n console.error('Windows is not yet supported for daemon mode.')\n console.error('Please use `chatlab start` to run in the foreground instead.')\n process.exit(1)\n }\n}\n\nexport function serviceUninstall(): void {\n switch (process.platform) {\n case 'darwin':\n return uninstallMacos()\n case 'linux':\n return uninstallLinux()\n default:\n console.error('Windows is not yet supported for daemon mode.')\n process.exit(1)\n }\n}\n\nexport function getServiceStatus(): ServiceStatus {\n switch (process.platform) {\n case 'darwin':\n return statusMacos()\n case 'linux':\n return statusLinux()\n default:\n return { installed: false, running: false }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -169,7 +169,7 @@ import {
|
|
|
169
169
|
verifyCliDataPath,
|
|
170
170
|
wasElectronUsed,
|
|
171
171
|
writeParseResultToDb
|
|
172
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-G7Q7EQ3V.mjs";
|
|
173
173
|
import "./chunk-VSOWNKPA.mjs";
|
|
174
174
|
export {
|
|
175
175
|
AIConversationManager,
|
|
@@ -337,4 +337,4 @@ export {
|
|
|
337
337
|
wasElectronUsed,
|
|
338
338
|
writeParseResultToDb
|
|
339
339
|
};
|
|
340
|
-
//# sourceMappingURL=src-
|
|
340
|
+
//# sourceMappingURL=src-EGXULYFQ.mjs.map
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
analyzeNewImport,
|
|
10
10
|
incrementalImport,
|
|
11
11
|
streamImport
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-643S2N2U.mjs";
|
|
13
13
|
import {
|
|
14
14
|
detectAllFormats,
|
|
15
15
|
detectFormat,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getFormatFeatureById,
|
|
18
18
|
getSupportedFormats,
|
|
19
19
|
scanMultiChatFile
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-G7Q7EQ3V.mjs";
|
|
21
21
|
import "./chunk-VSOWNKPA.mjs";
|
|
22
22
|
export {
|
|
23
23
|
analyzeIncrementalImport,
|
|
@@ -31,4 +31,4 @@ export {
|
|
|
31
31
|
scanMultiChatFile,
|
|
32
32
|
streamImport
|
|
33
33
|
};
|
|
34
|
-
//# sourceMappingURL=stream-import-
|
|
34
|
+
//# sourceMappingURL=stream-import-QM5R5FDG.mjs.map
|
|
@@ -6,7 +6,8 @@ const __filename = __fileURLToPath(import.meta.url);
|
|
|
6
6
|
const __dirname = __pathDirname(__filename);
|
|
7
7
|
import {
|
|
8
8
|
getVersion
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-5ADKYYNA.mjs";
|
|
10
|
+
import "./chunk-FJ35V3TE.mjs";
|
|
10
11
|
import "./chunk-VSOWNKPA.mjs";
|
|
11
12
|
|
|
12
13
|
// src/update-checker.ts
|
|
@@ -188,4 +189,4 @@ export {
|
|
|
188
189
|
checkForUpdatesInteractive,
|
|
189
190
|
startPeriodicUpdateCheck
|
|
190
191
|
};
|
|
191
|
-
//# sourceMappingURL=update-checker-
|
|
192
|
+
//# sourceMappingURL=update-checker-JG5K67O2.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/update-checker.ts"],"sourcesContent":["/**\n * CLI startup update checker — npm registry version comparison\n * with interactive prompt (Codex-style).\n *\n * Caches check results to avoid hitting npm on every invocation.\n * Respects user \"skip until next version\" preference.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as os from 'os'\nimport { execFile } from 'child_process'\nimport { getVersion } from './version'\n\nconst PACKAGE_NAME = 'chatlab-cli'\nconst CACHE_STALE_MS = 6 * 60 * 60 * 1000 // 6h — startup cache TTL\nconst PERIODIC_CHECK_MS = 24 * 60 * 60 * 1000 // 24h — long-running service interval\nconst CACHE_FILE = path.join(os.homedir(), '.chatlab', 'update-check.json')\n\ninterface UpdateCache {\n lastCheckTime: number\n latestVersion: string | null\n skippedVersion?: string\n}\n\nfunction readCache(): UpdateCache | null {\n try {\n if (fs.existsSync(CACHE_FILE)) {\n return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'))\n }\n } catch {\n // corrupted cache\n }\n return null\n}\n\nfunction writeCache(cache: UpdateCache): void {\n try {\n const dir = path.dirname(CACHE_FILE)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), 'utf-8')\n } catch {\n // non-critical\n }\n}\n\nfunction isNewerVersion(latest: string, current: string): boolean {\n const parse = (v: string) => {\n const [core, pre] = v.split('-', 2)\n const parts = core.split('.').map(Number)\n return { major: parts[0] || 0, minor: parts[1] || 0, patch: parts[2] || 0, pre }\n }\n const l = parse(latest)\n const c = parse(current)\n if (l.major !== c.major) return l.major > c.major\n if (l.minor !== c.minor) return l.minor > c.minor\n if (l.patch !== c.patch) return l.patch > c.patch\n // Design note: prerelease users are not prompted for prerelease-to-prerelease updates.\n // Only a stable release with the same core version should supersede a prerelease build.\n if (c.pre && !l.pre) return true\n return false\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const resp = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {\n headers: { Accept: 'application/json' },\n signal: AbortSignal.timeout(8_000),\n })\n if (!resp.ok) return null\n const data = (await resp.json()) as { version?: string }\n return data.version || null\n } catch {\n return null\n }\n}\n\nfunction promptUser(question: string, choices: string[]): Promise<number> {\n return new Promise((resolve) => {\n process.stderr.write(`${question}\\n\\n`)\n choices.forEach((c, i) => {\n process.stderr.write(i === 0 ? `› ${i + 1}. ${c}\\n` : ` ${i + 1}. ${c}\\n`)\n })\n process.stderr.write('\\n')\n\n if (!process.stdin.isTTY || !process.stdin.setRawMode) {\n resolve(2)\n return\n }\n\n process.stdin.setRawMode(true)\n process.stdin.resume()\n\n const onData = (data: Buffer) => {\n const key = data.toString()\n if (key === '\\x03') {\n process.stdin.setRawMode!(false)\n process.stdin.pause()\n process.exit(0)\n }\n // Only accept single-digit keys matching a valid choice;\n // ignore arrow keys (\\x1b[A/B/C/D), Enter, and other non-digit input.\n if (key.length === 1) {\n const num = parseInt(key)\n if (num >= 1 && num <= choices.length) {\n process.stdin.removeListener('data', onData)\n process.stdin.setRawMode!(false)\n process.stdin.pause()\n process.stderr.write('\\n')\n resolve(num)\n }\n }\n }\n process.stdin.on('data', onData)\n })\n}\n\nfunction runNpmUpdate(): Promise<{ success: boolean; error?: string }> {\n return new Promise((resolve) => {\n const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'\n process.stderr.write(`\\n Running: npm install -g ${PACKAGE_NAME}@latest\\n\\n`)\n\n const child = execFile(\n npmCmd,\n ['install', '-g', `${PACKAGE_NAME}@latest`],\n { timeout: 120_000 },\n (err, _stdout, stderr) => {\n if (err) {\n resolve({ success: false, error: stderr || err.message })\n } else {\n resolve({ success: true })\n }\n }\n )\n child.stdout?.pipe(process.stderr)\n child.stderr?.pipe(process.stderr)\n })\n}\n\nfunction isDevEnvironment(): boolean {\n if (process.env.CHATLAB_SKIP_UPDATE_CHECK) return true\n if (process.env.NODE_ENV === 'development') return true\n const entryFile = process.argv[1] || ''\n return entryFile.endsWith('.ts') || entryFile.endsWith('.mts')\n}\n\n/**\n * Fire-and-forget: fetch latest version from npm and update local cache.\n * Runs in background so CLI startup is never blocked by network IO.\n */\nfunction refreshCacheInBackground(existingCache: UpdateCache | null): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n writeCache({\n lastCheckTime: Date.now(),\n latestVersion,\n skippedVersion: existingCache?.skippedVersion,\n })\n })\n .catch(() => {})\n}\n\n/**\n * Start a periodic background cache refresh for long-running services.\n * Immediately refreshes once on startup, then every 24h thereafter.\n * The update prompt will appear on the *next* CLI startup.\n * The timer is unref'd so it won't prevent process exit.\n */\nexport function startPeriodicUpdateCheck(): void {\n if (isDevEnvironment()) return\n refreshCacheInBackground(readCache())\n const timer = setInterval(() => {\n refreshCacheInBackground(readCache())\n }, PERIODIC_CHECK_MS)\n timer.unref()\n}\n\n/**\n * Check for updates and prompt user interactively.\n *\n * Strategy (Codex-style):\n * - Read local cache synchronously (instant, no network).\n * - If cache is stale, kick off a background fetch for *next* run.\n * - Prompt is only shown when cache already contains a newer version.\n * - This means the first run after a new release sees no prompt;\n * the second run (with fresh cache) shows it — zero startup delay.\n */\nexport async function checkForUpdatesInteractive(): Promise<void> {\n if (!process.stdin.isTTY || process.env.CI || isDevEnvironment()) return\n\n const currentVersion = getVersion()\n const cache = readCache()\n\n // Kick off background refresh if cache is missing or stale\n if (!cache || Date.now() - cache.lastCheckTime >= CACHE_STALE_MS) {\n refreshCacheInBackground(cache)\n }\n\n // Prompt is based on cached data only — no network wait\n const latestVersion = cache?.latestVersion\n if (!latestVersion || !isNewerVersion(latestVersion, currentVersion)) return\n if (cache?.skippedVersion === latestVersion) return\n\n const choice = await promptUser(` ✨ Update available! ${currentVersion} → ${latestVersion}`, [\n `Update now (runs \\`npm install -g ${PACKAGE_NAME}\\`)`,\n 'Skip',\n 'Skip until next version',\n ])\n\n if (choice === 1) {\n const result = await runNpmUpdate()\n if (result.success) {\n process.stderr.write(\n ` \\x1b[32m🎉 Updated successfully! Please restart chatlab to use the new version.\\x1b[0m\\n\\n`\n )\n process.exit(0)\n } else {\n process.stderr.write(` ❌ Update failed: ${result.error}\\n\\n`)\n }\n } else if (choice === 3) {\n writeCache({\n lastCheckTime: Date.now(),\n latestVersion,\n skippedVersion: latestVersion,\n })\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/update-checker.ts"],"sourcesContent":["/**\n * CLI startup update checker — npm registry version comparison\n * with interactive prompt (Codex-style).\n *\n * Caches check results to avoid hitting npm on every invocation.\n * Respects user \"skip until next version\" preference.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as os from 'os'\nimport { execFile } from 'child_process'\nimport { getVersion } from './version'\n\nconst PACKAGE_NAME = 'chatlab-cli'\nconst CACHE_STALE_MS = 6 * 60 * 60 * 1000 // 6h — startup cache TTL\nconst PERIODIC_CHECK_MS = 24 * 60 * 60 * 1000 // 24h — long-running service interval\nconst CACHE_FILE = path.join(os.homedir(), '.chatlab', 'update-check.json')\n\ninterface UpdateCache {\n lastCheckTime: number\n latestVersion: string | null\n skippedVersion?: string\n}\n\nfunction readCache(): UpdateCache | null {\n try {\n if (fs.existsSync(CACHE_FILE)) {\n return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'))\n }\n } catch {\n // corrupted cache\n }\n return null\n}\n\nfunction writeCache(cache: UpdateCache): void {\n try {\n const dir = path.dirname(CACHE_FILE)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), 'utf-8')\n } catch {\n // non-critical\n }\n}\n\nfunction isNewerVersion(latest: string, current: string): boolean {\n const parse = (v: string) => {\n const [core, pre] = v.split('-', 2)\n const parts = core.split('.').map(Number)\n return { major: parts[0] || 0, minor: parts[1] || 0, patch: parts[2] || 0, pre }\n }\n const l = parse(latest)\n const c = parse(current)\n if (l.major !== c.major) return l.major > c.major\n if (l.minor !== c.minor) return l.minor > c.minor\n if (l.patch !== c.patch) return l.patch > c.patch\n // Design note: prerelease users are not prompted for prerelease-to-prerelease updates.\n // Only a stable release with the same core version should supersede a prerelease build.\n if (c.pre && !l.pre) return true\n return false\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const resp = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {\n headers: { Accept: 'application/json' },\n signal: AbortSignal.timeout(8_000),\n })\n if (!resp.ok) return null\n const data = (await resp.json()) as { version?: string }\n return data.version || null\n } catch {\n return null\n }\n}\n\nfunction promptUser(question: string, choices: string[]): Promise<number> {\n return new Promise((resolve) => {\n process.stderr.write(`${question}\\n\\n`)\n choices.forEach((c, i) => {\n process.stderr.write(i === 0 ? `› ${i + 1}. ${c}\\n` : ` ${i + 1}. ${c}\\n`)\n })\n process.stderr.write('\\n')\n\n if (!process.stdin.isTTY || !process.stdin.setRawMode) {\n resolve(2)\n return\n }\n\n process.stdin.setRawMode(true)\n process.stdin.resume()\n\n const onData = (data: Buffer) => {\n const key = data.toString()\n if (key === '\\x03') {\n process.stdin.setRawMode!(false)\n process.stdin.pause()\n process.exit(0)\n }\n // Only accept single-digit keys matching a valid choice;\n // ignore arrow keys (\\x1b[A/B/C/D), Enter, and other non-digit input.\n if (key.length === 1) {\n const num = parseInt(key)\n if (num >= 1 && num <= choices.length) {\n process.stdin.removeListener('data', onData)\n process.stdin.setRawMode!(false)\n process.stdin.pause()\n process.stderr.write('\\n')\n resolve(num)\n }\n }\n }\n process.stdin.on('data', onData)\n })\n}\n\nfunction runNpmUpdate(): Promise<{ success: boolean; error?: string }> {\n return new Promise((resolve) => {\n const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'\n process.stderr.write(`\\n Running: npm install -g ${PACKAGE_NAME}@latest\\n\\n`)\n\n const child = execFile(\n npmCmd,\n ['install', '-g', `${PACKAGE_NAME}@latest`],\n { timeout: 120_000 },\n (err, _stdout, stderr) => {\n if (err) {\n resolve({ success: false, error: stderr || err.message })\n } else {\n resolve({ success: true })\n }\n }\n )\n child.stdout?.pipe(process.stderr)\n child.stderr?.pipe(process.stderr)\n })\n}\n\nfunction isDevEnvironment(): boolean {\n if (process.env.CHATLAB_SKIP_UPDATE_CHECK) return true\n if (process.env.NODE_ENV === 'development') return true\n const entryFile = process.argv[1] || ''\n return entryFile.endsWith('.ts') || entryFile.endsWith('.mts')\n}\n\n/**\n * Fire-and-forget: fetch latest version from npm and update local cache.\n * Runs in background so CLI startup is never blocked by network IO.\n */\nfunction refreshCacheInBackground(existingCache: UpdateCache | null): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n writeCache({\n lastCheckTime: Date.now(),\n latestVersion,\n skippedVersion: existingCache?.skippedVersion,\n })\n })\n .catch(() => {})\n}\n\n/**\n * Start a periodic background cache refresh for long-running services.\n * Immediately refreshes once on startup, then every 24h thereafter.\n * The update prompt will appear on the *next* CLI startup.\n * The timer is unref'd so it won't prevent process exit.\n */\nexport function startPeriodicUpdateCheck(): void {\n if (isDevEnvironment()) return\n refreshCacheInBackground(readCache())\n const timer = setInterval(() => {\n refreshCacheInBackground(readCache())\n }, PERIODIC_CHECK_MS)\n timer.unref()\n}\n\n/**\n * Check for updates and prompt user interactively.\n *\n * Strategy (Codex-style):\n * - Read local cache synchronously (instant, no network).\n * - If cache is stale, kick off a background fetch for *next* run.\n * - Prompt is only shown when cache already contains a newer version.\n * - This means the first run after a new release sees no prompt;\n * the second run (with fresh cache) shows it — zero startup delay.\n */\nexport async function checkForUpdatesInteractive(): Promise<void> {\n if (!process.stdin.isTTY || process.env.CI || isDevEnvironment()) return\n\n const currentVersion = getVersion()\n const cache = readCache()\n\n // Kick off background refresh if cache is missing or stale\n if (!cache || Date.now() - cache.lastCheckTime >= CACHE_STALE_MS) {\n refreshCacheInBackground(cache)\n }\n\n // Prompt is based on cached data only — no network wait\n const latestVersion = cache?.latestVersion\n if (!latestVersion || !isNewerVersion(latestVersion, currentVersion)) return\n if (cache?.skippedVersion === latestVersion) return\n\n const choice = await promptUser(` ✨ Update available! ${currentVersion} → ${latestVersion}`, [\n `Update now (runs \\`npm install -g ${PACKAGE_NAME}\\`)`,\n 'Skip',\n 'Skip until next version',\n ])\n\n if (choice === 1) {\n const result = await runNpmUpdate()\n if (result.success) {\n process.stderr.write(\n ` \\x1b[32m🎉 Updated successfully! Please restart chatlab to use the new version.\\x1b[0m\\n\\n`\n )\n process.exit(0)\n } else {\n process.stderr.write(` ❌ Update failed: ${result.error}\\n\\n`)\n }\n } else if (choice === 3) {\n writeCache({\n lastCheckTime: Date.now(),\n latestVersion,\n skippedVersion: latestVersion,\n })\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.writing-vertical[data-v-19a25590]{writing-mode:vertical-rl;text-orientation:mixed}.data-flow-bg[data-v-19a25590]{background:repeating-linear-gradient(0deg,transparent,transparent 20px,currentColor 20px,currentColor 21px);animation:dataFlow-19a25590 20s linear infinite}@keyframes dataFlow-19a25590{0%{transform:translateY(0)}to{transform:translateY(-100px)}}.mention-menu-enter-active[data-v-0262c6da],.mention-menu-leave-active[data-v-0262c6da]{transition:opacity .16s ease,transform .16s ease}.mention-menu-enter-from[data-v-0262c6da],.mention-menu-leave-to[data-v-0262c6da]{transform:translateY(8px);opacity:0}.slash-menu-enter-active[data-v-0853b251],.slash-menu-leave-active[data-v-0853b251]{transition:opacity .16s ease,transform .16s ease}.slash-menu-enter-from[data-v-0853b251],.slash-menu-leave-to[data-v-0853b251]{transform:translateY(8px);opacity:0}.custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar{width:4px}.custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar-track{background:transparent}.custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar-thumb{border-radius:4px;background-color:#9ca3af4d}.dark .custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar-thumb{background-color:#9ca3af26}.slide-fade-enter-active[data-v-
|
|
1
|
+
.writing-vertical[data-v-19a25590]{writing-mode:vertical-rl;text-orientation:mixed}.data-flow-bg[data-v-19a25590]{background:repeating-linear-gradient(0deg,transparent,transparent 20px,currentColor 20px,currentColor 21px);animation:dataFlow-19a25590 20s linear infinite}@keyframes dataFlow-19a25590{0%{transform:translateY(0)}to{transform:translateY(-100px)}}.mention-menu-enter-active[data-v-0262c6da],.mention-menu-leave-active[data-v-0262c6da]{transition:opacity .16s ease,transform .16s ease}.mention-menu-enter-from[data-v-0262c6da],.mention-menu-leave-to[data-v-0262c6da]{transform:translateY(8px);opacity:0}.slash-menu-enter-active[data-v-0853b251],.slash-menu-leave-active[data-v-0853b251]{transition:opacity .16s ease,transform .16s ease}.slash-menu-enter-from[data-v-0853b251],.slash-menu-leave-to[data-v-0853b251]{transform:translateY(8px);opacity:0}.custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar{width:4px}.custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar-track{background:transparent}.custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar-thumb{border-radius:4px;background-color:#9ca3af4d}.dark .custom-scrollbar[data-v-94ffe515]::-webkit-scrollbar-thumb{background-color:#9ca3af26}.slide-fade-enter-active[data-v-e4cffe12],.slide-fade-leave-active[data-v-e4cffe12]{transition:all .3s ease-out}.slide-fade-enter-from[data-v-e4cffe12],.slide-fade-leave-to[data-v-e4cffe12]{transform:translate(20px);opacity:0}.slide-up-enter-active[data-v-e4cffe12],.slide-up-leave-active[data-v-e4cffe12]{transition:all .3s ease-out}.slide-up-enter-from[data-v-e4cffe12],.slide-up-leave-to[data-v-e4cffe12]{transform:translateY(10px);opacity:0}.fade-up-enter-active[data-v-e4cffe12],.fade-up-leave-active[data-v-e4cffe12]{transition:opacity .2s ease-out}.fade-up-enter-from[data-v-e4cffe12],.fade-up-leave-to[data-v-e4cffe12]{opacity:0}.fade-enter-active[data-v-0df46b7b],.fade-leave-active[data-v-0df46b7b]{transition:opacity .15s ease}.fade-enter-from[data-v-0df46b7b],.fade-leave-to[data-v-0df46b7b]{opacity:0}.fade-enter-active[data-v-d712cb76],.fade-leave-active[data-v-d712cb76]{transition:opacity .15s ease}.fade-enter-from[data-v-d712cb76],.fade-leave-to[data-v-d712cb76]{opacity:0}.titlebar-drag-cover[data-v-b3d2cc85]{position:absolute;left:0;right:0;z-index:50;top:calc(-1 * var(--titlebar-area-height));height:calc(var(--titlebar-area-height) + 1rem);-webkit-app-region:drag}
|