kumo-cli 1.0.0 → 1.0.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/README.md +21 -32
- package/dist/auth/credentialsStore.js +41 -0
- package/dist/auth/credentialsStore.js.map +1 -0
- package/dist/claude/generateHookSettings.js +23 -0
- package/dist/claude/generateHookSettings.js.map +1 -0
- package/dist/claude/hookServer.js +33 -0
- package/dist/claude/hookServer.js.map +1 -0
- package/dist/claude/sessionScanner.js +250 -0
- package/dist/claude/sessionScanner.js.map +1 -0
- package/dist/config.js +40 -0
- package/dist/config.js.map +1 -0
- package/dist/core/config.js +48 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/loadDotEnv.js +46 -0
- package/dist/core/loadDotEnv.js.map +1 -0
- package/dist/core/logger.js +29 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/handlers/messageRouter.js +223 -0
- package/dist/handlers/messageRouter.js.map +1 -0
- package/dist/http/httpClient.js +41 -0
- package/dist/http/httpClient.js.map +1 -0
- package/dist/index.js +141 -1090
- package/dist/index.js.map +1 -1
- package/dist/logger.js +29 -0
- package/dist/logger.js.map +1 -0
- package/dist/pty/ansiCodes.js +14 -0
- package/dist/pty/ansiCodes.js.map +1 -0
- package/dist/pty/ptyMenuParser.js +357 -0
- package/dist/pty/ptyMenuParser.js.map +1 -0
- package/dist/pty/ptySnapshotRenderer.js +71 -0
- package/dist/pty/ptySnapshotRenderer.js.map +1 -0
- package/dist/pty/spawn.js +77 -0
- package/dist/pty/spawn.js.map +1 -0
- package/dist/pty/terminalManager.js +66 -0
- package/dist/pty/terminalManager.js.map +1 -0
- package/dist/services/claudeService.js +218 -0
- package/dist/services/claudeService.js.map +1 -0
- package/dist/services/effortService.js +89 -0
- package/dist/services/effortService.js.map +1 -0
- package/dist/services/fileService.js +127 -0
- package/dist/services/fileService.js.map +1 -0
- package/dist/services/modelService.js +84 -0
- package/dist/services/modelService.js.map +1 -0
- package/dist/services/pairingService.js +129 -0
- package/dist/services/pairingService.js.map +1 -0
- package/dist/services/sessionService.js +168 -0
- package/dist/services/sessionService.js.map +1 -0
- package/dist/services/tunnelService.js +47 -0
- package/dist/services/tunnelService.js.map +1 -0
- package/dist/sessionScanner.js +131 -5
- package/dist/sessionScanner.js.map +1 -1
- package/dist/snapshotScanner.js +3 -1
- package/dist/snapshotScanner.js.map +1 -1
- package/dist/spawn.js +12 -2
- package/dist/spawn.js.map +1 -1
- package/dist/transport/directWsServer.js +135 -0
- package/dist/transport/directWsServer.js.map +1 -0
- package/dist/transport/wsClient.js +87 -0
- package/dist/transport/wsClient.js.map +1 -0
- package/dist/utils/ignorePaths.js +54 -0
- package/dist/utils/ignorePaths.js.map +1 -0
- package/dist/utils/ptyBuffer.js +46 -0
- package/dist/utils/ptyBuffer.js.map +1 -0
- package/dist/utils/safePath.js +43 -0
- package/dist/utils/safePath.js.map +1 -0
- package/package.json +2 -4
package/README.md
CHANGED
|
@@ -1,52 +1,40 @@
|
|
|
1
1
|
# Kumo CLI
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/kumo-cli)
|
|
6
|
-
[](https://nodejs.org)
|
|
7
|
-
[](./LICENSE)
|
|
8
|
-
|
|
9
|
-
**Kumo CLI** is the desktop companion for the [Kumo app](https://github.com/kumo-app/kumo). It pairs your terminal with the mobile/desktop client over a secure WebSocket bridge so you can drive Claude Code (and any PTY session) from anywhere — without giving up the comfort of your local shell.
|
|
3
|
+
A lightweight companion CLI for Kumo that connects your local terminal sessions to the Kumo app.
|
|
10
4
|
|
|
11
5
|
---
|
|
12
6
|
|
|
13
7
|
## ✨ Features
|
|
14
8
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- 🌐 **Bonjour discovery** — optional local discovery for zero-config LAN setups.
|
|
21
|
-
- 🔒 **Local credentials** — device tokens are stored under your user config dir, never echoed.
|
|
9
|
+
- Pair once with a short code from the app
|
|
10
|
+
- Resume and manage Claude Code sessions remotely
|
|
11
|
+
- Stream PTY output over WebSocket
|
|
12
|
+
- Auto-sync Claude session state and transcript events
|
|
13
|
+
- Optional local hook server integration for Claude session discovery
|
|
22
14
|
|
|
23
15
|
---
|
|
24
16
|
|
|
25
|
-
##
|
|
17
|
+
## 📦 Installation
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
# run on demand (no install)
|
|
29
|
-
npx kumo-cli@latest
|
|
19
|
+
### Global install
|
|
30
20
|
|
|
31
|
-
|
|
21
|
+
```bash
|
|
32
22
|
npm install -g kumo-cli
|
|
33
|
-
kumo
|
|
34
23
|
```
|
|
35
24
|
|
|
36
|
-
|
|
25
|
+
### One-off via npx
|
|
37
26
|
|
|
27
|
+
```bash
|
|
28
|
+
npx kumo-cli@latest
|
|
38
29
|
```
|
|
39
|
-
✦ pairing code › ___
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Open the **Kumo app**, sign in, tap **"generate"** on the pairing tab, and type the 9 digits back. That's it — your CLI is paired and a session is live.
|
|
43
30
|
|
|
44
31
|
---
|
|
45
32
|
|
|
46
|
-
##
|
|
33
|
+
## ✅ Requirements
|
|
47
34
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
35
|
+
- Node.js **18+**
|
|
36
|
+
- Internet access to reach your Kumo backend
|
|
37
|
+
- Native build prerequisites for `node-pty`:
|
|
50
38
|
- **Windows:** Visual Studio Build Tools + Python 3
|
|
51
39
|
- **macOS:** Xcode Command Line Tools (`xcode-select --install`)
|
|
52
40
|
- **Linux:** `build-essential`, `python3`, `make`, `gcc`
|
|
@@ -56,11 +44,11 @@ Open the **Kumo app**, sign in, tap **"generate"** on the pairing tab, and type
|
|
|
56
44
|
|
|
57
45
|
## 🛠️ Configuration
|
|
58
46
|
|
|
59
|
-
Kumo CLI is configured via environment variables.
|
|
47
|
+
Kumo CLI is configured via environment variables. Export them in your shell or load them explicitly with `--env-file path/to/.env`.
|
|
60
48
|
|
|
61
49
|
| Variable | Default | Description |
|
|
62
50
|
| --- | --- | --- |
|
|
63
|
-
| `KUMO_SERVER_URL` | `
|
|
51
|
+
| `KUMO_SERVER_URL` | `https://kumocli.com/` | Base URL of the Kumo backend. Auto-derives HTTP & WS endpoints. |
|
|
64
52
|
| `KUMO_SERVER_HTTP_URL` | derived | Override the HTTP endpoint explicitly. |
|
|
65
53
|
| `KUMO_SERVER_WS_URL` | derived | Override the WebSocket endpoint explicitly. |
|
|
66
54
|
| `KUMO_PORT` | `3579` | Local port hint (used by some discovery flows). |
|
|
@@ -72,8 +60,9 @@ Credentials are persisted to your OS config dir (e.g. `%APPDATA%\kumo\credential
|
|
|
72
60
|
## 🧭 Usage
|
|
73
61
|
|
|
74
62
|
```bash
|
|
75
|
-
kumo
|
|
76
|
-
kumo --
|
|
63
|
+
kumo --env-file .env
|
|
64
|
+
kumo --env-file .env.local
|
|
65
|
+
kumo --help
|
|
77
66
|
```
|
|
78
67
|
|
|
79
68
|
To unpair, simply delete the credentials file printed on first pairing, or run:
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
const CRED_DIR = path.join(os.homedir(), '.kumo');
|
|
5
|
+
const CRED_FILE = path.join(CRED_DIR, 'credentials.json');
|
|
6
|
+
// load credentials from ~/.kumo/credentials.json if present
|
|
7
|
+
export function loadCredentials() {
|
|
8
|
+
try {
|
|
9
|
+
if (!fs.existsSync(CRED_FILE))
|
|
10
|
+
return null;
|
|
11
|
+
const parsed = JSON.parse(fs.readFileSync(CRED_FILE, 'utf-8'));
|
|
12
|
+
if (!parsed.deviceUuid || !parsed.deviceToken)
|
|
13
|
+
return null;
|
|
14
|
+
return parsed;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// persist credentials with restrictive 0600 mode on posix
|
|
21
|
+
export function saveCredentials(creds) {
|
|
22
|
+
if (!fs.existsSync(CRED_DIR))
|
|
23
|
+
fs.mkdirSync(CRED_DIR, { recursive: true });
|
|
24
|
+
fs.writeFileSync(CRED_FILE, JSON.stringify(creds, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
25
|
+
}
|
|
26
|
+
// remove credentials file; called by `kumo reset`
|
|
27
|
+
export function clearCredentials() {
|
|
28
|
+
try {
|
|
29
|
+
if (!fs.existsSync(CRED_FILE))
|
|
30
|
+
return false;
|
|
31
|
+
fs.unlinkSync(CRED_FILE);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function credentialsPath() {
|
|
39
|
+
return CRED_FILE;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=credentialsStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentialsStore.js","sourceRoot":"","sources":["../../src/auth/credentialsStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAS7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AAE1D,4DAA4D;AAC5D,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAoB,CAAC;QAClF,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAC3D,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,eAAe,CAAC,KAAsB;IACpD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAClG,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5C,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
// generate a temporary claude settings file pointing SessionStart hook to our local forwarder
|
|
7
|
+
export function generateHookSettingsFile(hookPort) {
|
|
8
|
+
const forwarderPath = path.resolve(moduleDir, '..', '..', 'scripts', 'session_hook_forwarder.cjs');
|
|
9
|
+
const settingsDir = path.join(os.tmpdir(), 'kumo-hooks');
|
|
10
|
+
fs.mkdirSync(settingsDir, { recursive: true });
|
|
11
|
+
const settingsPath = path.join(settingsDir, `settings-${Date.now()}.json`);
|
|
12
|
+
const command = `node "${forwarderPath}" --port ${hookPort}`;
|
|
13
|
+
const settings = {
|
|
14
|
+
hooks: {
|
|
15
|
+
SessionStart: [
|
|
16
|
+
{ matcher: '', hooks: [{ type: 'command', command }] },
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
21
|
+
return settingsPath;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=generateHookSettings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateHookSettings.js","sourceRoot":"","sources":["../../src/claude/generateHookSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,8FAA8F;AAC9F,MAAM,UAAU,wBAAwB,CAAC,QAAgB;IACvD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,4BAA4B,CAAC,CAAC;IACnG,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC;IACzD,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,SAAS,aAAa,YAAY,QAAQ,EAAE,CAAC;IAC7D,MAAM,QAAQ,GAAG;QACf,KAAK,EAAE;YACL,YAAY,EAAE;gBACZ,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;aACvD;SACF;KACF,CAAC;IACF,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC3E,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
// start a tiny http server on an ephemeral port that claude will post sessionStart to
|
|
3
|
+
export function startHookServer(onSessionFound) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const server = http.createServer((req, res) => {
|
|
6
|
+
if (req.method === 'POST' && req.url === '/hook/session-start') {
|
|
7
|
+
let body = '';
|
|
8
|
+
req.on('data', (chunk) => { body += chunk; });
|
|
9
|
+
req.on('end', () => {
|
|
10
|
+
try {
|
|
11
|
+
const data = JSON.parse(body);
|
|
12
|
+
if (data.sessionId)
|
|
13
|
+
onSessionFound(data.sessionId);
|
|
14
|
+
}
|
|
15
|
+
catch { }
|
|
16
|
+
res.writeHead(200);
|
|
17
|
+
res.end('ok');
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
res.writeHead(404);
|
|
22
|
+
res.end();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
server.listen(0, '127.0.0.1', () => {
|
|
26
|
+
const addr = server.address();
|
|
27
|
+
const port = typeof addr === 'object' && addr ? addr.port : 0;
|
|
28
|
+
resolve({ port, close: () => server.close() });
|
|
29
|
+
});
|
|
30
|
+
server.on('error', reject);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=hookServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hookServer.js","sourceRoot":"","sources":["../../src/claude/hookServer.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAO7B,sFAAsF;AACtF,MAAM,UAAU,eAAe,CAAC,cAA2C;IACzE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,qBAAqB,EAAE,CAAC;gBAC/D,IAAI,IAAI,GAAG,EAAE,CAAC;gBACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACjB,IAAI,CAAC;wBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA2B,CAAC;wBACxD,IAAI,IAAI,CAAC,SAAS;4BAAE,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACrD,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;oBACV,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
import { EventEmitter } from 'node:events';
|
|
6
|
+
const NOISE_TAGS_RE = /<local-command-|<\/local-command-|<command-name>|<command-message>|<command-args>/i;
|
|
7
|
+
const NOISE_INTERRUPT_RE = /request interrupted by user|interrupted by user|interrupted the running process/i;
|
|
8
|
+
const UUID_LINE_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\s*$/i;
|
|
9
|
+
// scans claude session jsonl + subagent transcripts incrementally and emits parsed messages
|
|
10
|
+
export class SessionScanner extends EventEmitter {
|
|
11
|
+
sessionId;
|
|
12
|
+
startAtEnd;
|
|
13
|
+
filePath = null;
|
|
14
|
+
sessionDir = null;
|
|
15
|
+
offset = 0;
|
|
16
|
+
watcher = null;
|
|
17
|
+
subagentWatcher = null;
|
|
18
|
+
seenUuids = new Set();
|
|
19
|
+
pollTimer = null;
|
|
20
|
+
subagentScanTimer = null;
|
|
21
|
+
subagentOffsets = new Map();
|
|
22
|
+
subagentWatchers = new Map();
|
|
23
|
+
constructor(sessionId, startAtEnd = false) {
|
|
24
|
+
super();
|
|
25
|
+
this.sessionId = sessionId;
|
|
26
|
+
this.startAtEnd = startAtEnd;
|
|
27
|
+
}
|
|
28
|
+
start() {
|
|
29
|
+
this.filePath = this.findJsonlFile();
|
|
30
|
+
if (!this.filePath) {
|
|
31
|
+
this.pollTimer = setInterval(() => {
|
|
32
|
+
const found = this.findJsonlFile();
|
|
33
|
+
if (found) {
|
|
34
|
+
this.filePath = found;
|
|
35
|
+
clearInterval(this.pollTimer);
|
|
36
|
+
this.pollTimer = null;
|
|
37
|
+
this.watchFile();
|
|
38
|
+
}
|
|
39
|
+
}, 500);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.watchFile();
|
|
43
|
+
}
|
|
44
|
+
stop() {
|
|
45
|
+
this.watcher?.close();
|
|
46
|
+
this.subagentWatcher?.close();
|
|
47
|
+
for (const w of this.subagentWatchers.values())
|
|
48
|
+
w.close();
|
|
49
|
+
this.subagentWatchers.clear();
|
|
50
|
+
if (this.pollTimer)
|
|
51
|
+
clearInterval(this.pollTimer);
|
|
52
|
+
if (this.subagentScanTimer)
|
|
53
|
+
clearInterval(this.subagentScanTimer);
|
|
54
|
+
}
|
|
55
|
+
findJsonlFile() {
|
|
56
|
+
const projectsDir = path.join(os.homedir(), '.claude', 'projects');
|
|
57
|
+
if (!fs.existsSync(projectsDir))
|
|
58
|
+
return null;
|
|
59
|
+
for (const entry of fs.readdirSync(projectsDir, { withFileTypes: true })) {
|
|
60
|
+
if (!entry.isDirectory())
|
|
61
|
+
continue;
|
|
62
|
+
const candidate = path.join(projectsDir, entry.name, `${this.sessionId}.jsonl`);
|
|
63
|
+
if (fs.existsSync(candidate)) {
|
|
64
|
+
this.sessionDir = path.join(projectsDir, entry.name, this.sessionId);
|
|
65
|
+
return candidate;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
watchFile() {
|
|
71
|
+
if (!this.filePath)
|
|
72
|
+
return;
|
|
73
|
+
if (this.startAtEnd) {
|
|
74
|
+
try {
|
|
75
|
+
this.offset = fs.statSync(this.filePath).size;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
this.offset = 0;
|
|
79
|
+
}
|
|
80
|
+
this.startAtEnd = false;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.readIncremental();
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
this.watcher = fs.watch(this.filePath, () => this.readIncremental());
|
|
87
|
+
}
|
|
88
|
+
catch { }
|
|
89
|
+
this.watchSubagents();
|
|
90
|
+
}
|
|
91
|
+
watchSubagents() {
|
|
92
|
+
if (!this.sessionDir)
|
|
93
|
+
return;
|
|
94
|
+
const subagentsDir = path.join(this.sessionDir, 'subagents');
|
|
95
|
+
const scanSubagents = () => {
|
|
96
|
+
if (!fs.existsSync(subagentsDir))
|
|
97
|
+
return;
|
|
98
|
+
for (const file of fs.readdirSync(subagentsDir).filter((f) => f.endsWith('.jsonl'))) {
|
|
99
|
+
const filePath = path.join(subagentsDir, file);
|
|
100
|
+
if (!this.subagentWatchers.has(filePath)) {
|
|
101
|
+
this.readSubagentFile(filePath);
|
|
102
|
+
try {
|
|
103
|
+
this.subagentWatchers.set(filePath, fs.watch(filePath, () => this.readSubagentFile(filePath)));
|
|
104
|
+
}
|
|
105
|
+
catch { }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
scanSubagents();
|
|
110
|
+
this.subagentScanTimer = setInterval(() => {
|
|
111
|
+
if (fs.existsSync(subagentsDir)) {
|
|
112
|
+
if (!this.subagentWatcher) {
|
|
113
|
+
try {
|
|
114
|
+
this.subagentWatcher = fs.watch(subagentsDir, () => scanSubagents());
|
|
115
|
+
}
|
|
116
|
+
catch { }
|
|
117
|
+
}
|
|
118
|
+
scanSubagents();
|
|
119
|
+
}
|
|
120
|
+
}, 1000);
|
|
121
|
+
}
|
|
122
|
+
// read newly appended bytes from a jsonl file using a tracked offset
|
|
123
|
+
readDelta(filePath, getOffset, setOffset) {
|
|
124
|
+
try {
|
|
125
|
+
const stat = fs.statSync(filePath);
|
|
126
|
+
const offset = getOffset();
|
|
127
|
+
if (stat.size <= offset)
|
|
128
|
+
return;
|
|
129
|
+
const fd = fs.openSync(filePath, 'r');
|
|
130
|
+
const buf = Buffer.alloc(stat.size - offset);
|
|
131
|
+
fs.readSync(fd, buf, 0, buf.length, offset);
|
|
132
|
+
fs.closeSync(fd);
|
|
133
|
+
setOffset(stat.size);
|
|
134
|
+
for (const line of buf.toString('utf-8').split('\n')) {
|
|
135
|
+
if (!line.trim())
|
|
136
|
+
continue;
|
|
137
|
+
try {
|
|
138
|
+
this.processMessage(JSON.parse(line));
|
|
139
|
+
}
|
|
140
|
+
catch { }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch { }
|
|
144
|
+
}
|
|
145
|
+
readSubagentFile(filePath) {
|
|
146
|
+
this.readDelta(filePath, () => this.subagentOffsets.get(filePath) ?? 0, (n) => this.subagentOffsets.set(filePath, n));
|
|
147
|
+
}
|
|
148
|
+
readIncremental() {
|
|
149
|
+
if (!this.filePath)
|
|
150
|
+
return;
|
|
151
|
+
this.readDelta(this.filePath, () => this.offset, (n) => { this.offset = n; });
|
|
152
|
+
}
|
|
153
|
+
processMessage(msg) {
|
|
154
|
+
if (msg.type !== 'user' && msg.type !== 'assistant')
|
|
155
|
+
return;
|
|
156
|
+
if (!msg.message)
|
|
157
|
+
return;
|
|
158
|
+
if (msg.isMeta || msg.sourceToolUseID)
|
|
159
|
+
return;
|
|
160
|
+
const role = msg.message.role;
|
|
161
|
+
if (!role || role === 'system')
|
|
162
|
+
return;
|
|
163
|
+
if (msg.uuid && this.seenUuids.has(msg.uuid))
|
|
164
|
+
return;
|
|
165
|
+
if (msg.uuid)
|
|
166
|
+
this.seenUuids.add(msg.uuid);
|
|
167
|
+
let content = '';
|
|
168
|
+
const toolUses = [];
|
|
169
|
+
if (typeof msg.message.content === 'string') {
|
|
170
|
+
content = msg.message.content;
|
|
171
|
+
}
|
|
172
|
+
else if (Array.isArray(msg.message.content)) {
|
|
173
|
+
content = msg.message.content
|
|
174
|
+
.filter((b) => b.type === 'text' && b.text && (b.text ?? '').trim() !== 'No response requested.')
|
|
175
|
+
.map((b) => b.text ?? '')
|
|
176
|
+
.join('');
|
|
177
|
+
for (const b of msg.message.content) {
|
|
178
|
+
if (b.type === 'tool_use' && b.name) {
|
|
179
|
+
const tu = { toolName: b.name, input: b.input ?? {} };
|
|
180
|
+
if (b.name === 'Write')
|
|
181
|
+
this.enrichWriteWithOldContent(tu);
|
|
182
|
+
toolUses.push(tu);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (!content && toolUses.length === 0)
|
|
187
|
+
return;
|
|
188
|
+
if (content && this.isNoiseTranscript(content))
|
|
189
|
+
return;
|
|
190
|
+
this.emit('message', {
|
|
191
|
+
role, content,
|
|
192
|
+
id: msg.uuid,
|
|
193
|
+
timestamp: new Date().toISOString(),
|
|
194
|
+
toolUses: toolUses.length > 0 ? toolUses : undefined,
|
|
195
|
+
stopReason: msg.message.stop_reason,
|
|
196
|
+
agentId: msg.agentId,
|
|
197
|
+
isSidechain: msg.isSidechain,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// inject old_content into write tool use by reading previous version from file-history
|
|
201
|
+
enrichWriteWithOldContent(tu) {
|
|
202
|
+
const fp = tu.input['file_path'] ?? tu.input['path'] ?? '';
|
|
203
|
+
if (!fp)
|
|
204
|
+
return;
|
|
205
|
+
const oldContent = readFileHistoryPrev(this.sessionId, fp);
|
|
206
|
+
if (oldContent !== null)
|
|
207
|
+
tu.input['old_content'] = oldContent;
|
|
208
|
+
}
|
|
209
|
+
isNoiseTranscript(content) {
|
|
210
|
+
if (/<local-command-stdout>/.test(content))
|
|
211
|
+
return false;
|
|
212
|
+
if (NOISE_TAGS_RE.test(content))
|
|
213
|
+
return true;
|
|
214
|
+
if (NOISE_INTERRUPT_RE.test(content))
|
|
215
|
+
return true;
|
|
216
|
+
if (UUID_LINE_RE.test(content.trim()))
|
|
217
|
+
return true;
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// convert unix-style drive path (/e/Data/...) to windows path (E:\Data\...) on windows
|
|
222
|
+
function toNativePath(p) {
|
|
223
|
+
if (process.platform === 'win32') {
|
|
224
|
+
const m = p.match(/^\/([a-zA-Z])\//);
|
|
225
|
+
if (m)
|
|
226
|
+
return m[1].toUpperCase() + ':\\' + p.slice(3).replace(/\//g, '\\');
|
|
227
|
+
}
|
|
228
|
+
return p;
|
|
229
|
+
}
|
|
230
|
+
// read the previous version of a file from ~/.claude/file-history; returns null if not found or first write
|
|
231
|
+
export function readFileHistoryPrev(sessionId, filePath) {
|
|
232
|
+
try {
|
|
233
|
+
const native = toNativePath(filePath);
|
|
234
|
+
const resolved = path.resolve(native);
|
|
235
|
+
const hash = crypto.createHash('sha256').update(resolved).digest('hex').slice(0, 16);
|
|
236
|
+
const histDir = path.join(os.homedir(), '.claude', 'file-history', sessionId);
|
|
237
|
+
if (!fs.existsSync(histDir))
|
|
238
|
+
return null;
|
|
239
|
+
const versions = fs.readdirSync(histDir)
|
|
240
|
+
.filter((f) => f.startsWith(hash + '@v'))
|
|
241
|
+
.sort((a, b) => parseInt(a.split('@v')[1], 10) - parseInt(b.split('@v')[1], 10));
|
|
242
|
+
if (versions.length < 2)
|
|
243
|
+
return null;
|
|
244
|
+
return fs.readFileSync(path.join(histDir, versions[versions.length - 2]), 'utf-8');
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=sessionScanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionScanner.js","sourceRoot":"","sources":["../../src/claude/sessionScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAuB3C,MAAM,aAAa,GAAG,oFAAoF,CAAC;AAC3G,MAAM,kBAAkB,GAAG,kFAAkF,CAAC;AAC9G,MAAM,YAAY,GAAG,oEAAoE,CAAC;AAE1F,4FAA4F;AAC5F,MAAM,OAAO,cAAe,SAAQ,YAAY;IAY1B;IAA2B;IAXvC,QAAQ,GAAkB,IAAI,CAAC;IAC/B,UAAU,GAAkB,IAAI,CAAC;IACjC,MAAM,GAAG,CAAC,CAAC;IACX,OAAO,GAAwB,IAAI,CAAC;IACpC,eAAe,GAAwB,IAAI,CAAC;IAC5C,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,SAAS,GAA0B,IAAI,CAAC;IACxC,iBAAiB,GAA0B,IAAI,CAAC;IAChD,eAAe,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,gBAAgB,GAAG,IAAI,GAAG,EAAwB,CAAC;IAE3D,YAAoB,SAAiB,EAAU,aAAa,KAAK;QAC/D,KAAK,EAAE,CAAC;QADU,cAAS,GAAT,SAAS,CAAQ;QAAU,eAAU,GAAV,UAAU,CAAQ;IAEjE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;gBAChC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnC,IAAI,KAAK,EAAE,CAAC;oBACV,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;oBACtB,aAAa,CAAC,IAAI,CAAC,SAAU,CAAC,CAAC;oBAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;oBACtB,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,CAAC;YACH,CAAC,EAAE,GAAG,CAAC,CAAC;YACR,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE;YAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QAC1D,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,SAAS;YAAE,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,IAAI,CAAC,iBAAiB;YAAE,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACpE,CAAC;IAEO,aAAa;QACnB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;QACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7C,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACzE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YACnC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,QAAQ,CAAC,CAAC;YAChF,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBACrE,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC;gBAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;YAAC,CAAC;YACjF,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;QACD,IAAI,CAAC;YAAC,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACtF,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC7D,MAAM,aAAa,GAAG,GAAS,EAAE;YAC/B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;gBAAE,OAAO;YACzC,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;gBACpF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;gBAC/C,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACzC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;oBAChC,IAAI,CAAC;wBACH,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;oBACjG,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,aAAa,EAAE,CAAC;QAChB,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;YACxC,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;oBAC1B,IAAI,CAAC;wBAAC,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC;oBAAC,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACxF,CAAC;gBACD,aAAa,EAAE,CAAC;YAClB,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,CAAC;IACX,CAAC;IAED,qEAAqE;IAC7D,SAAS,CAAC,QAAgB,EAAE,SAAuB,EAAE,SAA8B;QACzF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,IAAI,IAAI,MAAM;gBAAE,OAAO;YAChC,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;YAC7C,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC5C,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrD,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;oBAAE,SAAS;gBAC3B,IAAI,CAAC;oBAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACzE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAEO,gBAAgB,CAAC,QAAgB;QACvC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACxH,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChF,CAAC;IAEO,cAAc,CAAC,GAAiB;QACtC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO;QAC5D,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,eAAe;YAAE,OAAO;QAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;QAC9B,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO;QACvC,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QACrD,IAAI,GAAG,CAAC,IAAI;YAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAE3C,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAkB,EAAE,CAAC;QACnC,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;QAChC,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9C,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO;iBAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,wBAAwB,CAAC;iBAChG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;iBACxB,IAAI,CAAC,EAAE,CAAC,CAAC;YACZ,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpC,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;oBACpC,MAAM,EAAE,GAAgB,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;oBACnE,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;wBAAE,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;oBAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACpB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC9C,IAAI,OAAO,IAAI,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC;YAAE,OAAO;QAEvD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YACnB,IAAI,EAAE,OAAO;YACb,EAAE,EAAE,GAAG,CAAC,IAAI;YACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YACpD,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,WAAW;YACnC,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC,CAAC;IACL,CAAC;IAED,uFAAuF;IAC/E,yBAAyB,CAAC,EAAe;QAC/C,MAAM,EAAE,GAAI,EAAE,CAAC,KAAK,CAAC,WAAW,CAAY,IAAK,EAAE,CAAC,KAAK,CAAC,MAAM,CAAY,IAAI,EAAE,CAAC;QACnF,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,UAAU,KAAK,IAAI;YAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC;IAChE,CAAC;IAEO,iBAAiB,CAAC,OAAe;QACvC,IAAI,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC;QACzD,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7C,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QAClD,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QACnD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,uFAAuF;AACvF,SAAS,YAAY,CAAC,CAAS;IAC7B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACrC,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,QAAgB;IACrE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;QAC9E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,QAAQ,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC;aACrC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;aACxC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACnF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
// normalize raw user-supplied url into an http/https origin (no trailing /ws)
|
|
4
|
+
export function normalizeServerHttpUrl(input) {
|
|
5
|
+
const u = new URL(input);
|
|
6
|
+
if (u.protocol === 'ws:')
|
|
7
|
+
u.protocol = 'http:';
|
|
8
|
+
if (u.protocol === 'wss:')
|
|
9
|
+
u.protocol = 'https:';
|
|
10
|
+
if (u.pathname === '/ws')
|
|
11
|
+
u.pathname = '/';
|
|
12
|
+
if (u.pathname.endsWith('/ws'))
|
|
13
|
+
u.pathname = u.pathname.slice(0, -3) || '/';
|
|
14
|
+
return u.toString().replace(/\/$/, '');
|
|
15
|
+
}
|
|
16
|
+
// normalize raw user-supplied url into a ws/wss endpoint pointing to /ws
|
|
17
|
+
export function normalizeServerWsUrl(input) {
|
|
18
|
+
const u = new URL(input);
|
|
19
|
+
if (u.protocol === 'http:')
|
|
20
|
+
u.protocol = 'ws:';
|
|
21
|
+
if (u.protocol === 'https:')
|
|
22
|
+
u.protocol = 'wss:';
|
|
23
|
+
if (u.pathname === '/' || u.pathname === '')
|
|
24
|
+
u.pathname = '/ws';
|
|
25
|
+
return u.toString().replace(/\/$/, '');
|
|
26
|
+
}
|
|
27
|
+
const serverUrl = process.env.KUMO_SERVER_URL;
|
|
28
|
+
export const SERVER_HTTP = normalizeServerHttpUrl(process.env.KUMO_SERVER_HTTP_URL ?? serverUrl ?? 'https://kumocli.com');
|
|
29
|
+
export const SERVER_WS = normalizeServerWsUrl(process.env.KUMO_SERVER_WS_URL ?? serverUrl ?? 'wss://kumocli.com/ws');
|
|
30
|
+
export const SERVER_PORT = parseInt(process.env.KUMO_PORT ?? '443', 10);
|
|
31
|
+
// resolve project-relative directories from this module's compiled location
|
|
32
|
+
const moduleDir = path.resolve(fileURLToPath(import.meta.url), '..');
|
|
33
|
+
export const PROJECT_TMP_DIR = path.resolve(moduleDir, '..', 'tmp');
|
|
34
|
+
export const LOGS_DIR = path.resolve(moduleDir, '..', 'logs');
|
|
35
|
+
export const SNAPSHOT_DIR = path.resolve(moduleDir, '..', '..', 'claude-data-snapshot');
|
|
36
|
+
// constants for pty buffering and file watcher debounce
|
|
37
|
+
export const PTY_FLUSH_MS = 120;
|
|
38
|
+
export const PTY_MAX_CHUNK = 8000;
|
|
39
|
+
export const FILE_WATCH_DEBOUNCE_MS = 300;
|
|
40
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,8EAA8E;AAC9E,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK;QAAE,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC/C,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM;QAAE,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACjD,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK;QAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC;IAC3C,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IAC5E,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO;QAAE,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;IAC/C,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CAAC;IACjD,IAAI,CAAC,CAAC,QAAQ,KAAK,GAAG,IAAI,CAAC,CAAC,QAAQ,KAAK,EAAE;QAAE,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;IAChE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAC9C,MAAM,CAAC,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,SAAS,IAAI,qBAAqB,CAAC,CAAC;AAC1H,MAAM,CAAC,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,SAAS,IAAI,sBAAsB,CAAC,CAAC;AACrH,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC;AAExE,4EAA4E;AAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC9D,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,sBAAsB,CAAC,CAAC;AAExF,wDAAwD;AACxD,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAChC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
// normalize raw user-supplied url into an http/https origin (no trailing /ws)
|
|
4
|
+
export function normalizeServerHttpUrl(input) {
|
|
5
|
+
const u = new URL(input);
|
|
6
|
+
if (u.protocol === 'ws:')
|
|
7
|
+
u.protocol = 'http:';
|
|
8
|
+
if (u.protocol === 'wss:')
|
|
9
|
+
u.protocol = 'https:';
|
|
10
|
+
if (u.pathname === '/ws')
|
|
11
|
+
u.pathname = '/';
|
|
12
|
+
if (u.pathname.endsWith('/ws'))
|
|
13
|
+
u.pathname = u.pathname.slice(0, -3) || '/';
|
|
14
|
+
return u.toString().replace(/\/$/, '');
|
|
15
|
+
}
|
|
16
|
+
// normalize raw user-supplied url into a ws/wss endpoint pointing to /ws
|
|
17
|
+
export function normalizeServerWsUrl(input) {
|
|
18
|
+
const u = new URL(input);
|
|
19
|
+
if (u.protocol === 'http:')
|
|
20
|
+
u.protocol = 'ws:';
|
|
21
|
+
if (u.protocol === 'https:')
|
|
22
|
+
u.protocol = 'wss:';
|
|
23
|
+
if (u.pathname === '/' || u.pathname === '')
|
|
24
|
+
u.pathname = '/ws';
|
|
25
|
+
return u.toString().replace(/\/$/, '');
|
|
26
|
+
}
|
|
27
|
+
// lazy-evaluated so env vars injected via --env-file are available
|
|
28
|
+
let _serverHttp = null;
|
|
29
|
+
let _serverWs = null;
|
|
30
|
+
export function SERVER_HTTP() {
|
|
31
|
+
if (!_serverHttp)
|
|
32
|
+
_serverHttp = normalizeServerHttpUrl(process.env.KUMO_SERVER_HTTP_URL ?? process.env.KUMO_SERVER_URL ?? 'https://kumocli.com');
|
|
33
|
+
return _serverHttp;
|
|
34
|
+
}
|
|
35
|
+
export function SERVER_WS() {
|
|
36
|
+
if (!_serverWs)
|
|
37
|
+
_serverWs = normalizeServerWsUrl(process.env.KUMO_SERVER_WS_URL ?? process.env.KUMO_SERVER_URL ?? 'wss://kumocli.com/ws');
|
|
38
|
+
return _serverWs;
|
|
39
|
+
}
|
|
40
|
+
// resolve project-relative directories from this module's compiled location (dist/core/config.js)
|
|
41
|
+
const moduleDir = path.resolve(fileURLToPath(import.meta.url), '..');
|
|
42
|
+
export const PROJECT_TMP_DIR = path.resolve(moduleDir, '..', '..', 'tmp');
|
|
43
|
+
export const LOGS_DIR = path.resolve(moduleDir, '..', '..', 'logs');
|
|
44
|
+
// constants for pty buffering and file watcher debounce
|
|
45
|
+
export const PTY_FLUSH_MS = 120;
|
|
46
|
+
export const PTY_MAX_CHUNK = 8000;
|
|
47
|
+
export const FILE_WATCH_DEBOUNCE_MS = 300;
|
|
48
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,8EAA8E;AAC9E,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK;QAAE,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC/C,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM;QAAE,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACjD,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK;QAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC;IAC3C,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IAC5E,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO;QAAE,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;IAC/C,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CAAC;IACjD,IAAI,CAAC,CAAC,QAAQ,KAAK,GAAG,IAAI,CAAC,CAAC,QAAQ,KAAK,EAAE;QAAE,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;IAChE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,mEAAmE;AACnE,IAAI,WAAW,GAAkB,IAAI,CAAC;AACtC,IAAI,SAAS,GAAkB,IAAI,CAAC;AAEpC,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC,WAAW;QAAE,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,qBAAqB,CAAC,CAAC;IACjJ,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,SAAS;QAAE,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,sBAAsB,CAAC,CAAC;IAC1I,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kGAAkG;AAClG,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAC1E,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAEpE,wDAAwD;AACxD,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAChC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
function parseDotEnv(text) {
|
|
4
|
+
const out = {};
|
|
5
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
6
|
+
const line = rawLine.trim();
|
|
7
|
+
if (!line || line.startsWith('#'))
|
|
8
|
+
continue;
|
|
9
|
+
const normalized = line.startsWith('export ') ? line.slice('export '.length).trimStart() : line;
|
|
10
|
+
const eqIdx = normalized.indexOf('=');
|
|
11
|
+
if (eqIdx <= 0)
|
|
12
|
+
continue;
|
|
13
|
+
const key = normalized.slice(0, eqIdx).trim();
|
|
14
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|
|
15
|
+
continue;
|
|
16
|
+
let value = normalized.slice(eqIdx + 1).trim();
|
|
17
|
+
if (!value) {
|
|
18
|
+
out[key] = '';
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const first = value[0];
|
|
22
|
+
if (first === '"' || first === "'") {
|
|
23
|
+
const quote = first;
|
|
24
|
+
const rest = value.slice(1);
|
|
25
|
+
const endIdx = rest.lastIndexOf(quote);
|
|
26
|
+
const inner = endIdx >= 0 ? rest.slice(0, endIdx) : rest;
|
|
27
|
+
out[key] = quote === '"'
|
|
28
|
+
? inner.replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\t/g, '\t').replace(/\\\\/g, '\\').replace(/\\"/g, '"')
|
|
29
|
+
: inner;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
out[key] = value.replace(/\s+#.*$/, '').trim();
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
export function loadDotEnv(envFilePath) {
|
|
37
|
+
const fullPath = path.resolve(envFilePath);
|
|
38
|
+
if (!fs.existsSync(fullPath)) {
|
|
39
|
+
throw new Error(`[kumo-cli] env file not found: ${fullPath}`);
|
|
40
|
+
}
|
|
41
|
+
const parsed = parseDotEnv(fs.readFileSync(fullPath, 'utf-8'));
|
|
42
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
43
|
+
process.env[k] = v;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=loadDotEnv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadDotEnv.js","sourceRoot":"","sources":["../../src/core/loadDotEnv.ts"],"names":[],"mappings":"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"}
|