1688-cli 0.1.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/AGENTS.md +118 -0
- package/README.md +48 -0
- package/dist/auth/cookies.js +31 -0
- package/dist/auth/cookies.js.map +1 -0
- package/dist/auth/verify.js +25 -0
- package/dist/auth/verify.js.map +1 -0
- package/dist/cli.js +373 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cart-add.js +199 -0
- package/dist/commands/cart-add.js.map +1 -0
- package/dist/commands/cart-list.js +168 -0
- package/dist/commands/cart-list.js.map +1 -0
- package/dist/commands/cart-remove.js +119 -0
- package/dist/commands/cart-remove.js.map +1 -0
- package/dist/commands/checkout-confirm.js +407 -0
- package/dist/commands/checkout-confirm.js.map +1 -0
- package/dist/commands/checkout-prepare.js +244 -0
- package/dist/commands/checkout-prepare.js.map +1 -0
- package/dist/commands/doctor.js +246 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/image-search.js +210 -0
- package/dist/commands/image-search.js.map +1 -0
- package/dist/commands/login.js +209 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +59 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/offer.js +185 -0
- package/dist/commands/offer.js.map +1 -0
- package/dist/commands/order-get.js +76 -0
- package/dist/commands/order-get.js.map +1 -0
- package/dist/commands/order-list.js +176 -0
- package/dist/commands/order-list.js.map +1 -0
- package/dist/commands/order-logistics.js +152 -0
- package/dist/commands/order-logistics.js.map +1 -0
- package/dist/commands/search.js +250 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/seller-chat.js +213 -0
- package/dist/commands/seller-chat.js.map +1 -0
- package/dist/commands/seller-inquire.js +110 -0
- package/dist/commands/seller-inquire.js.map +1 -0
- package/dist/commands/seller-lookup-ww.js +6 -0
- package/dist/commands/seller-lookup-ww.js.map +1 -0
- package/dist/commands/seller-messages.js +181 -0
- package/dist/commands/seller-messages.js.map +1 -0
- package/dist/commands/whoami.js +53 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/commands/workflows.js +264 -0
- package/dist/commands/workflows.js.map +1 -0
- package/dist/daemon/client.js +75 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/manager.js +128 -0
- package/dist/daemon/manager.js.map +1 -0
- package/dist/daemon/protocol.js +5 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/server.js +197 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/throttle.js +17 -0
- package/dist/daemon/throttle.js.map +1 -0
- package/dist/io/errors.js +10 -0
- package/dist/io/errors.js.map +1 -0
- package/dist/io/output.js +17 -0
- package/dist/io/output.js.map +1 -0
- package/dist/io/prompt.js +17 -0
- package/dist/io/prompt.js.map +1 -0
- package/dist/session/context.js +91 -0
- package/dist/session/context.js.map +1 -0
- package/dist/session/dispatch.js +50 -0
- package/dist/session/dispatch.js.map +1 -0
- package/dist/session/lock.js +23 -0
- package/dist/session/lock.js.map +1 -0
- package/dist/session/paths.js +31 -0
- package/dist/session/paths.js.map +1 -0
- package/dist/session/shared.js +104 -0
- package/dist/session/shared.js.map +1 -0
- package/dist/session/state.js +27 -0
- package/dist/session/state.js.map +1 -0
- package/dist/util/time.js +17 -0
- package/dist/util/time.js.map +1 -0
- package/package.json +44 -0
- package/scripts/postinstall.mjs +49 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { pidFile, socketPath, daemonLogFile, ensureRoot, } from '../session/paths.js';
|
|
6
|
+
import { daemonCall, isDaemonReachable } from './client.js';
|
|
7
|
+
import { CliError } from '../io/errors.js';
|
|
8
|
+
export async function status() {
|
|
9
|
+
const pid = await readPid();
|
|
10
|
+
if (pid === null)
|
|
11
|
+
return { running: false };
|
|
12
|
+
const alive = isProcessAlive(pid);
|
|
13
|
+
if (!alive)
|
|
14
|
+
return { running: false };
|
|
15
|
+
const reachable = await isDaemonReachable();
|
|
16
|
+
let stats = undefined;
|
|
17
|
+
if (reachable) {
|
|
18
|
+
try {
|
|
19
|
+
stats = await daemonCall('status', {});
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
/* ignore */
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { running: true, pid, reachable, stats };
|
|
26
|
+
}
|
|
27
|
+
export async function start() {
|
|
28
|
+
await ensureRoot();
|
|
29
|
+
const existing = await status();
|
|
30
|
+
if (existing.running) {
|
|
31
|
+
throw new CliError(5, 'DAEMON_RUNNING', `Daemon already running (pid ${existing.pid}).`);
|
|
32
|
+
}
|
|
33
|
+
// Locate the CLI entrypoint to re-exec as "1688 serve".
|
|
34
|
+
// When installed via npm link, this module sits at dist/daemon/manager.js,
|
|
35
|
+
// and the CLI is at dist/cli.js.
|
|
36
|
+
const here = fileURLToPath(import.meta.url);
|
|
37
|
+
const cliPath = path.join(path.dirname(here), '..', 'cli.js');
|
|
38
|
+
// Detach from the parent; redirect output to a log file.
|
|
39
|
+
const logFd = await fs.open(daemonLogFile(), 'a');
|
|
40
|
+
const child = spawn(process.execPath, [cliPath, 'serve'], {
|
|
41
|
+
detached: true,
|
|
42
|
+
stdio: ['ignore', logFd.fd, logFd.fd],
|
|
43
|
+
env: { ...process.env, BB1688_DAEMON_BG: '1' },
|
|
44
|
+
});
|
|
45
|
+
child.unref();
|
|
46
|
+
await logFd.close();
|
|
47
|
+
// Wait until socket is reachable (max ~15s).
|
|
48
|
+
const deadline = Date.now() + 15000;
|
|
49
|
+
while (Date.now() < deadline) {
|
|
50
|
+
if (await isDaemonReachable()) {
|
|
51
|
+
const pid = (await readPid()) ?? child.pid ?? -1;
|
|
52
|
+
return { pid };
|
|
53
|
+
}
|
|
54
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
55
|
+
}
|
|
56
|
+
throw new CliError(9, 'DAEMON_START_TIMEOUT', 'Daemon did not start within 15s. Check ~/.1688/daemon.log.');
|
|
57
|
+
}
|
|
58
|
+
export async function stop() {
|
|
59
|
+
const pid = await readPid();
|
|
60
|
+
if (pid === null || !isProcessAlive(pid)) {
|
|
61
|
+
await cleanupArtifacts();
|
|
62
|
+
return { stopped: false };
|
|
63
|
+
}
|
|
64
|
+
// Prefer asking via socket; fall back to SIGTERM.
|
|
65
|
+
if (await isDaemonReachable()) {
|
|
66
|
+
try {
|
|
67
|
+
await daemonCall('shutdown', {});
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* will fall through to SIGTERM */
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
try {
|
|
75
|
+
process.kill(pid, 'SIGTERM');
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
/* already dead */
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Wait up to 10s for clean exit.
|
|
82
|
+
const deadline = Date.now() + 10000;
|
|
83
|
+
while (Date.now() < deadline) {
|
|
84
|
+
if (!isProcessAlive(pid))
|
|
85
|
+
break;
|
|
86
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
87
|
+
}
|
|
88
|
+
if (isProcessAlive(pid)) {
|
|
89
|
+
try {
|
|
90
|
+
process.kill(pid, 'SIGKILL');
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
/* ignore */
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
await cleanupArtifacts();
|
|
97
|
+
return { stopped: true };
|
|
98
|
+
}
|
|
99
|
+
async function cleanupArtifacts() {
|
|
100
|
+
for (const p of [socketPath(), pidFile()]) {
|
|
101
|
+
try {
|
|
102
|
+
await fs.unlink(p);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
/* ignore */
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function readPid() {
|
|
110
|
+
try {
|
|
111
|
+
const s = await fs.readFile(pidFile(), 'utf8');
|
|
112
|
+
const n = parseInt(s.trim(), 10);
|
|
113
|
+
return Number.isInteger(n) ? n : null;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function isProcessAlive(pid) {
|
|
120
|
+
try {
|
|
121
|
+
process.kill(pid, 0);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/daemon/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/daemon/protocol.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAwBhF,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { socketPath, pidFile, ensureRoot, } from '../session/paths.js';
|
|
4
|
+
import { getSharedContext, releaseSharedContext, runOnSharedCtx, } from '../session/shared.js';
|
|
5
|
+
import { loadExecutor } from '../session/dispatch.js';
|
|
6
|
+
import { CliError } from '../io/errors.js';
|
|
7
|
+
import { throttle } from './throttle.js';
|
|
8
|
+
const stats = {
|
|
9
|
+
startedAt: new Date().toISOString(),
|
|
10
|
+
pid: process.pid,
|
|
11
|
+
commandCount: 0,
|
|
12
|
+
lastRequestAt: null,
|
|
13
|
+
lastError: null,
|
|
14
|
+
};
|
|
15
|
+
let activeClients = 0;
|
|
16
|
+
let lastActivityMs = Date.now();
|
|
17
|
+
let server = null;
|
|
18
|
+
let shuttingDown = false;
|
|
19
|
+
export async function start(opts = {}) {
|
|
20
|
+
const idleMs = opts.idleTimeoutMs ?? 30 * 60 * 1000;
|
|
21
|
+
await ensureRoot();
|
|
22
|
+
// Clean any stale socket. If pidfile points to a live process, refuse.
|
|
23
|
+
await refuseIfAlive();
|
|
24
|
+
try {
|
|
25
|
+
await fs.unlink(socketPath());
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
/* not present, fine */
|
|
29
|
+
}
|
|
30
|
+
await fs.writeFile(pidFile(), String(process.pid));
|
|
31
|
+
log(`pid ${process.pid}, socket ${socketPath()}`);
|
|
32
|
+
if (opts.prewarm) {
|
|
33
|
+
log('prewarming Chromium...');
|
|
34
|
+
await getSharedContext();
|
|
35
|
+
log('Chromium ready');
|
|
36
|
+
}
|
|
37
|
+
server = net.createServer((sock) => handleClient(sock));
|
|
38
|
+
await new Promise((resolve, reject) => {
|
|
39
|
+
server.once('error', reject);
|
|
40
|
+
server.listen(socketPath(), () => {
|
|
41
|
+
server.off('error', reject);
|
|
42
|
+
resolve();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
log('listening');
|
|
46
|
+
const idleTimer = setInterval(() => {
|
|
47
|
+
if (!shuttingDown &&
|
|
48
|
+
activeClients === 0 &&
|
|
49
|
+
Date.now() - lastActivityMs > idleMs) {
|
|
50
|
+
log(`idle for ${Math.round(idleMs / 60000)}min — shutting down`);
|
|
51
|
+
void shutdown();
|
|
52
|
+
}
|
|
53
|
+
}, 10_000);
|
|
54
|
+
idleTimer.unref();
|
|
55
|
+
for (const sig of ['SIGTERM', 'SIGINT']) {
|
|
56
|
+
process.on(sig, () => {
|
|
57
|
+
log(`received ${sig}`);
|
|
58
|
+
void shutdown();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function handleClient(sock) {
|
|
63
|
+
activeClients++;
|
|
64
|
+
lastActivityMs = Date.now();
|
|
65
|
+
sock.setEncoding('utf8');
|
|
66
|
+
let buf = '';
|
|
67
|
+
sock.on('data', (chunk) => {
|
|
68
|
+
buf += chunk;
|
|
69
|
+
let nl;
|
|
70
|
+
while ((nl = buf.indexOf('\n')) !== -1) {
|
|
71
|
+
const line = buf.slice(0, nl).trim();
|
|
72
|
+
buf = buf.slice(nl + 1);
|
|
73
|
+
if (!line)
|
|
74
|
+
continue;
|
|
75
|
+
let req;
|
|
76
|
+
try {
|
|
77
|
+
req = JSON.parse(line);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
sock.write(JSON.stringify({
|
|
81
|
+
id: '?',
|
|
82
|
+
ok: false,
|
|
83
|
+
exitCode: 1,
|
|
84
|
+
code: 'BAD_REQUEST',
|
|
85
|
+
message: 'invalid JSON',
|
|
86
|
+
}) + '\n');
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
void handleRequest(req).then((resp) => {
|
|
90
|
+
if (!sock.writable)
|
|
91
|
+
return;
|
|
92
|
+
sock.write(JSON.stringify(resp) + '\n');
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
sock.on('error', () => {
|
|
97
|
+
/* swallow client errors */
|
|
98
|
+
});
|
|
99
|
+
sock.on('close', () => {
|
|
100
|
+
activeClients--;
|
|
101
|
+
lastActivityMs = Date.now();
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async function handleRequest(req) {
|
|
105
|
+
lastActivityMs = Date.now();
|
|
106
|
+
stats.lastRequestAt = new Date().toISOString();
|
|
107
|
+
stats.commandCount++;
|
|
108
|
+
try {
|
|
109
|
+
if (req.cmd === 'status') {
|
|
110
|
+
return {
|
|
111
|
+
id: req.id,
|
|
112
|
+
ok: true,
|
|
113
|
+
data: {
|
|
114
|
+
...stats,
|
|
115
|
+
uptimeMs: Date.now() - new Date(stats.startedAt).getTime(),
|
|
116
|
+
activeClients,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (req.cmd === 'shutdown') {
|
|
121
|
+
setTimeout(() => void shutdown(), 50);
|
|
122
|
+
return { id: req.id, ok: true, data: { stopping: true } };
|
|
123
|
+
}
|
|
124
|
+
await throttle(req.cmd);
|
|
125
|
+
const fn = await loadExecutor(req.cmd);
|
|
126
|
+
const data = await runOnSharedCtx((ctx) => fn(ctx, req.args));
|
|
127
|
+
return { id: req.id, ok: true, data };
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
stats.lastError = e.message ?? String(e);
|
|
131
|
+
if (e instanceof CliError) {
|
|
132
|
+
return {
|
|
133
|
+
id: req.id,
|
|
134
|
+
ok: false,
|
|
135
|
+
exitCode: e.exitCode,
|
|
136
|
+
code: e.code,
|
|
137
|
+
message: e.message,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
id: req.id,
|
|
142
|
+
ok: false,
|
|
143
|
+
exitCode: 1,
|
|
144
|
+
code: 'INTERNAL',
|
|
145
|
+
message: e.message ?? String(e),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function refuseIfAlive() {
|
|
150
|
+
let pidStr;
|
|
151
|
+
try {
|
|
152
|
+
pidStr = await fs.readFile(pidFile(), 'utf8');
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const pid = parseInt(pidStr.trim(), 10);
|
|
158
|
+
if (!Number.isInteger(pid))
|
|
159
|
+
return;
|
|
160
|
+
try {
|
|
161
|
+
process.kill(pid, 0); // probe — throws if not alive
|
|
162
|
+
throw new CliError(5, 'DAEMON_RUNNING', `Daemon already running (pid ${pid}). Use \`1688 daemon stop\` first.`);
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
if (e.code === 'DAEMON_RUNNING')
|
|
166
|
+
throw e;
|
|
167
|
+
// ESRCH — stale pidfile, ignore.
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async function shutdown() {
|
|
171
|
+
if (shuttingDown)
|
|
172
|
+
return;
|
|
173
|
+
shuttingDown = true;
|
|
174
|
+
log('shutting down');
|
|
175
|
+
if (server) {
|
|
176
|
+
await new Promise((r) => server.close(() => r()));
|
|
177
|
+
}
|
|
178
|
+
await releaseSharedContext();
|
|
179
|
+
try {
|
|
180
|
+
await fs.unlink(socketPath());
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
/* ignore */
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
await fs.unlink(pidFile());
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* ignore */
|
|
190
|
+
}
|
|
191
|
+
log('bye');
|
|
192
|
+
process.exit(0);
|
|
193
|
+
}
|
|
194
|
+
function log(msg) {
|
|
195
|
+
process.stderr.write(`[daemon ${new Date().toISOString()}] ${msg}\n`);
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Per-command-type rate limiter + jittered minimum gap between operations.
|
|
2
|
+
// Keeps daemon behavior from looking like a hammering bot.
|
|
3
|
+
const lastInvokedAt = new Map();
|
|
4
|
+
const MIN_GAP_MS = 1200;
|
|
5
|
+
const JITTER_MS = 1800;
|
|
6
|
+
export async function throttle(cmd) {
|
|
7
|
+
const last = lastInvokedAt.get(cmd) ?? 0;
|
|
8
|
+
const minNextAt = last + MIN_GAP_MS;
|
|
9
|
+
const jitter = Math.floor(Math.random() * JITTER_MS);
|
|
10
|
+
const targetAt = minNextAt + jitter;
|
|
11
|
+
const wait = targetAt - Date.now();
|
|
12
|
+
if (wait > 0) {
|
|
13
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
14
|
+
}
|
|
15
|
+
lastInvokedAt.set(cmd, Date.now());
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=throttle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttle.js","sourceRoot":"","sources":["../../src/daemon/throttle.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,2DAA2D;AAE3D,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;AAChD,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW;IACxC,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,GAAG,UAAU,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACnC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;QACb,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/io/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IACA;IAFlB,YACkB,QAAgB,EAChB,IAAY,EAC5B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,aAAQ,GAAR,QAAQ,CAAQ;QAChB,SAAI,GAAJ,IAAI,CAAQ;IAI9B,CAAC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const jsonMode = !process.stdout.isTTY || process.env.BB1688_JSON === '1';
|
|
2
|
+
export function isJson() {
|
|
3
|
+
return jsonMode;
|
|
4
|
+
}
|
|
5
|
+
export function emit(opts) {
|
|
6
|
+
if (jsonMode) {
|
|
7
|
+
process.stdout.write(JSON.stringify(opts.data) + '\n');
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
opts.human();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function info(msg) {
|
|
14
|
+
if (!jsonMode)
|
|
15
|
+
process.stderr.write(`${msg}\n`);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/io/output.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,CAAC;AAE1E,MAAM,UAAU,MAAM;IACpB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAA0C;IAC7D,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACzD,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,IAAI,CAAC,QAAQ;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import readline from 'node:readline/promises';
|
|
2
|
+
export async function confirm(msg) {
|
|
3
|
+
if (!process.stdin.isTTY)
|
|
4
|
+
return false;
|
|
5
|
+
const rl = readline.createInterface({
|
|
6
|
+
input: process.stdin,
|
|
7
|
+
output: process.stderr,
|
|
8
|
+
});
|
|
9
|
+
try {
|
|
10
|
+
const ans = await rl.question(`${msg} [y/N] `);
|
|
11
|
+
return /^y(es)?$/i.test(ans.trim());
|
|
12
|
+
}
|
|
13
|
+
finally {
|
|
14
|
+
rl.close();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/io/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,wBAAwB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW;IACvC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;QAC/C,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { chromium } from 'playwright-extra';
|
|
4
|
+
import stealth from 'puppeteer-extra-plugin-stealth';
|
|
5
|
+
import { profilePath } from './paths.js';
|
|
6
|
+
import { acquireLock } from './lock.js';
|
|
7
|
+
import { CliError } from '../io/errors.js';
|
|
8
|
+
/**
|
|
9
|
+
* Remove Chrome's stale SingletonLock / SingletonCookie / SingletonSocket files
|
|
10
|
+
* from our profile dir. Safe because our `proper-lockfile` already guarantees
|
|
11
|
+
* no other 1688 process is using this profile.
|
|
12
|
+
*/
|
|
13
|
+
export async function clearStaleSingleton(profileDir) {
|
|
14
|
+
for (const name of ['SingletonLock', 'SingletonCookie', 'SingletonSocket']) {
|
|
15
|
+
await fs.unlink(path.join(profileDir, name)).catch(() => { });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Apply stealth evasions once at module load.
|
|
19
|
+
// Disable a couple of evasions that can cause issues with newer Chromium.
|
|
20
|
+
const stealthPlugin = stealth();
|
|
21
|
+
stealthPlugin.enabledEvasions.delete('iframe.contentWindow');
|
|
22
|
+
stealthPlugin.enabledEvasions.delete('media.codecs');
|
|
23
|
+
chromium.use(stealthPlugin);
|
|
24
|
+
const LAUNCH_OPTS = {
|
|
25
|
+
viewport: { width: 1440, height: 900 },
|
|
26
|
+
locale: 'zh-CN',
|
|
27
|
+
timezoneId: 'Asia/Shanghai',
|
|
28
|
+
};
|
|
29
|
+
export async function withSession(opts, fn) {
|
|
30
|
+
const release = await acquireLock();
|
|
31
|
+
const dir = profilePath(opts.profile);
|
|
32
|
+
await fs.mkdir(dir, { recursive: true });
|
|
33
|
+
await clearStaleSingleton(dir);
|
|
34
|
+
let ctx = null;
|
|
35
|
+
try {
|
|
36
|
+
ctx = await launchContext(dir, opts.headless);
|
|
37
|
+
// Stealth plugin defaults navigator.languages to en-US — override back to
|
|
38
|
+
// Chinese so we look like a real CN user.
|
|
39
|
+
await ctx.addInitScript(() => {
|
|
40
|
+
try {
|
|
41
|
+
Object.defineProperty(navigator, 'languages', {
|
|
42
|
+
get: () => ['zh-CN', 'zh', 'en'],
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
/* ignore */
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return await fn(ctx);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
if (ctx)
|
|
53
|
+
await ctx.close().catch(() => { });
|
|
54
|
+
await release().catch(() => { });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function launchContext(dir, headless) {
|
|
58
|
+
// Prefer real Chrome — best fingerprint match (real UA, real GPU, real
|
|
59
|
+
// plugins). Falls back to bundled Chromium if Chrome isn't installed.
|
|
60
|
+
const preferChrome = process.env.BB1688_FORCE_CHROMIUM !== '1';
|
|
61
|
+
if (preferChrome) {
|
|
62
|
+
try {
|
|
63
|
+
return (await chromium.launchPersistentContext(dir, {
|
|
64
|
+
...LAUNCH_OPTS,
|
|
65
|
+
headless,
|
|
66
|
+
channel: 'chrome',
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
const msg = e.message ?? '';
|
|
71
|
+
// Re-throw unknown errors; only fall through if Chrome is missing.
|
|
72
|
+
if (!/Chromium\?|channel|Executable doesn't exist|chrome.*not found/i.test(msg)) {
|
|
73
|
+
throw e;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
return (await chromium.launchPersistentContext(dir, {
|
|
79
|
+
...LAUNCH_OPTS,
|
|
80
|
+
headless,
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
const msg = e.message ?? '';
|
|
85
|
+
if (/Executable doesn't exist/i.test(msg)) {
|
|
86
|
+
throw new CliError(6, 'CHROMIUM_MISSING', 'Chromium not installed. Run: npx playwright install chromium');
|
|
87
|
+
}
|
|
88
|
+
throw e;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/session/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,OAAO,MAAM,gCAAgC,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,UAAkB;IAC1D,KAAK,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,EAAE,CAAC;QAC3E,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED,8CAA8C;AAC9C,0EAA0E;AAC1E,MAAM,aAAa,GAAG,OAAO,EAAE,CAAC;AAChC,aAAa,CAAC,eAAe,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAC7D,aAAa,CAAC,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AACrD,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AAO5B,MAAM,WAAW,GAAG;IAClB,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IACtC,MAAM,EAAE,OAAO;IACf,UAAU,EAAE,eAAe;CAC5B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAiB,EACjB,EAAuC;IAEvC,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAE/B,IAAI,GAAG,GAA0B,IAAI,CAAC;IACtC,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9C,0EAA0E;QAC1E,0CAA0C;QAC1C,MAAM,GAAG,CAAC,aAAa,CAAC,GAAG,EAAE;YAC3B,IAAI,CAAC;gBACH,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE;oBAC5C,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;iBACjC,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,IAAI,GAAG;YAAE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,GAAW,EACX,QAAiB;IAEjB,uEAAuE;IACvE,sEAAsE;IACtE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,GAAG,CAAC;IAC/D,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,QAAQ,CAAC,uBAAuB,CAAC,GAAG,EAAE;gBAClD,GAAG,WAAW;gBACd,QAAQ;gBACR,OAAO,EAAE,QAAQ;aAClB,CAAC,CAAmB,CAAC;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,GAAG,GAAI,CAAW,CAAC,OAAO,IAAI,EAAE,CAAC;YACvC,mEAAmE;YACnE,IACE,CAAC,gEAAgE,CAAC,IAAI,CACpE,GAAG,CACJ,EACD,CAAC;gBACD,MAAM,CAAC,CAAC;YACV,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,QAAQ,CAAC,uBAAuB,CAAC,GAAG,EAAE;YAClD,GAAG,WAAW;YACd,QAAQ;SACT,CAAC,CAAmB,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,GAAG,GAAI,CAAW,CAAC,OAAO,IAAI,EAAE,CAAC;QACvC,IAAI,2BAA2B,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,QAAQ,CAChB,CAAC,EACD,kBAAkB,EAClB,8DAA8D,CAC/D,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Routes a command either through the daemon (fast) or inline (slow but
|
|
2
|
+
// self-contained). Headed mode and explicit `--profile` always go inline.
|
|
3
|
+
import { withSession } from './context.js';
|
|
4
|
+
import { isDaemonReachable, daemonCall } from '../daemon/client.js';
|
|
5
|
+
// Lazy-imported registry of command executors. Each entry must export `execute`.
|
|
6
|
+
// login/logout are deliberately omitted — they have interactive flows (QR render,
|
|
7
|
+
// stdin confirmation) that don't transit cleanly through a socket; they stay inline.
|
|
8
|
+
const REGISTRY = {
|
|
9
|
+
search: () => import('../commands/search.js').then((m) => m.execute),
|
|
10
|
+
whoami: () => import('../commands/whoami.js').then((m) => m.execute),
|
|
11
|
+
'order-list': () => import('../commands/order-list.js').then((m) => m.execute),
|
|
12
|
+
'order-get': () => import('../commands/order-get.js').then((m) => m.execute),
|
|
13
|
+
'order-logistics': () => import('../commands/order-logistics.js').then((m) => m.execute),
|
|
14
|
+
offer: () => import('../commands/offer.js').then((m) => m.execute),
|
|
15
|
+
'image-search': () => import('../commands/image-search.js').then((m) => m.execute),
|
|
16
|
+
'cart-list': () => import('../commands/cart-list.js').then((m) => m.execute),
|
|
17
|
+
'cart-remove': () => import('../commands/cart-remove.js').then((m) => m.execute),
|
|
18
|
+
'cart-add': () => import('../commands/cart-add.js').then((m) => m.execute),
|
|
19
|
+
'checkout-prepare': () => import('../commands/checkout-prepare.js').then((m) => m.execute),
|
|
20
|
+
'checkout-confirm': () => import('../commands/checkout-confirm.js').then((m) => m.execute),
|
|
21
|
+
'seller-chat': () => import('../commands/seller-chat.js').then((m) => m.execute),
|
|
22
|
+
'seller-messages': () => import('../commands/seller-messages.js').then((m) => m.execute),
|
|
23
|
+
'detail-feglobals': () => import('../commands/seller-inquire.js').then((m) => m.scrapeFeGlobals),
|
|
24
|
+
};
|
|
25
|
+
export async function loadExecutor(name) {
|
|
26
|
+
const loader = REGISTRY[name];
|
|
27
|
+
if (!loader)
|
|
28
|
+
throw new Error(`Unknown command: ${name}`);
|
|
29
|
+
return (await loader());
|
|
30
|
+
}
|
|
31
|
+
export async function dispatch(name, args, opts = {}) {
|
|
32
|
+
const skipDaemon = opts.headed === true ||
|
|
33
|
+
!!opts.profile ||
|
|
34
|
+
opts.noDaemon === true ||
|
|
35
|
+
process.env.BB1688_NO_DAEMON === '1';
|
|
36
|
+
if (!skipDaemon && (await isDaemonReachable())) {
|
|
37
|
+
try {
|
|
38
|
+
return await daemonCall(name, args);
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
// Network/protocol errors fall through to inline. Real CliErrors propagate.
|
|
42
|
+
const code = e.code;
|
|
43
|
+
if (code && code !== 'ECONNREFUSED' && code !== 'ENOENT')
|
|
44
|
+
throw e;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const fn = await loadExecutor(name);
|
|
48
|
+
return withSession({ headless: !opts.headed, profile: opts.profile }, (ctx) => fn(ctx, args));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/session/dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import lockfile from 'proper-lockfile';
|
|
3
|
+
import { lockFile, ensureRoot } from './paths.js';
|
|
4
|
+
import { CliError } from '../io/errors.js';
|
|
5
|
+
export async function acquireLock() {
|
|
6
|
+
await ensureRoot();
|
|
7
|
+
// proper-lockfile requires the target file to exist
|
|
8
|
+
await fs.writeFile(lockFile(), '', { flag: 'a' });
|
|
9
|
+
try {
|
|
10
|
+
const release = await lockfile.lock(lockFile(), {
|
|
11
|
+
retries: 0,
|
|
12
|
+
stale: 5 * 60 * 1000,
|
|
13
|
+
});
|
|
14
|
+
return release;
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
if (e.code === 'ELOCKED') {
|
|
18
|
+
throw new CliError(5, 'LOCK_BUSY', 'Another 1688 command is running. Close it and retry.');
|
|
19
|
+
}
|
|
20
|
+
throw e;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/session/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,UAAU,EAAE,CAAC;IACnB,oDAAoD;IACpD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;YAC9C,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;SACrB,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAK,CAAuB,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAChD,MAAM,IAAI,QAAQ,CAChB,CAAC,EACD,WAAW,EACX,sDAAsD,CACvD,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
export function root() {
|
|
5
|
+
return process.env.BB1688_HOME ?? path.join(os.homedir(), '.1688');
|
|
6
|
+
}
|
|
7
|
+
export function profilesDir() {
|
|
8
|
+
return path.join(root(), 'profiles');
|
|
9
|
+
}
|
|
10
|
+
export function stateFile() {
|
|
11
|
+
return path.join(root(), 'state.json');
|
|
12
|
+
}
|
|
13
|
+
export function lockFile() {
|
|
14
|
+
return path.join(root(), '.lock');
|
|
15
|
+
}
|
|
16
|
+
export function socketPath() {
|
|
17
|
+
return path.join(root(), 'daemon.sock');
|
|
18
|
+
}
|
|
19
|
+
export function pidFile() {
|
|
20
|
+
return path.join(root(), 'daemon.pid');
|
|
21
|
+
}
|
|
22
|
+
export function daemonLogFile() {
|
|
23
|
+
return path.join(root(), 'daemon.log');
|
|
24
|
+
}
|
|
25
|
+
export function profilePath(name = 'default') {
|
|
26
|
+
return path.join(profilesDir(), name);
|
|
27
|
+
}
|
|
28
|
+
export async function ensureRoot() {
|
|
29
|
+
await fs.mkdir(root(), { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=paths.js.map
|