1688-cli 0.1.42 → 0.1.43
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/ARCHITECTURE.md +3 -2
- package/CHANGELOG.md +79 -0
- package/README.md +102 -24
- package/dist/cli.js +33 -25
- package/dist/cli.js.map +1 -1
- package/dist/commands/checkout-confirm.js +8 -8
- package/dist/commands/checkout-confirm.js.map +1 -1
- package/dist/commands/doctor.js +46 -43
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/inbox.js +1 -1
- package/dist/commands/inbox.js.map +1 -1
- package/dist/commands/login.js +14 -14
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +6 -4
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/profile.js +25 -9
- package/dist/commands/profile.js.map +1 -1
- package/dist/commands/seller-chat.js +1 -1
- package/dist/commands/seller-chat.js.map +1 -1
- package/dist/commands/seller-inquire.js +1 -1
- package/dist/commands/seller-inquire.js.map +1 -1
- package/dist/commands/seller-messages.js +1 -1
- package/dist/commands/seller-messages.js.map +1 -1
- package/dist/commands/whoami.js +6 -3
- package/dist/commands/whoami.js.map +1 -1
- package/dist/daemon/client.js +10 -6
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.js +53 -37
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/server.js +26 -22
- package/dist/daemon/server.js.map +1 -1
- package/dist/session/context.js +1 -1
- package/dist/session/context.js.map +1 -1
- package/dist/session/dispatch.js +23 -22
- package/dist/session/dispatch.js.map +1 -1
- package/dist/session/lock.js +14 -14
- package/dist/session/lock.js.map +1 -1
- package/dist/session/paths.js +39 -18
- package/dist/session/paths.js.map +1 -1
- package/dist/session/shared.js +17 -7
- package/dist/session/shared.js.map +1 -1
- package/dist/session/state.js +7 -7
- package/dist/session/state.js.map +1 -1
- package/docs/COMMANDS.md +9 -3
- package/docs/JSON_CONTRACTS.md +86 -0
- package/docs/QUALITY_SCORE.md +2 -1
- package/docs/README.md +1 -0
- package/docs/RELIABILITY.md +13 -5
- package/docs/SAFETY.md +1 -2
- package/docs/exec-plans/completed/2026-06-16-profile-daemon.md +146 -0
- package/docs/generated/command-index.md +5 -5
- package/docs/generated/json-shapes.md +1 -1
- package/docs/generated/test-index.md +1 -1
- package/docs/playbooks/update-cli-release.md +56 -6
- package/docs/records/release-omissions.md +34 -0
- package/docs/specs/index.md +9 -0
- package/docs/specs/profile-daemon.md +114 -0
- package/package.json +11 -4
- package/scripts/check_agent_map.mjs +2 -1
- package/scripts/check_release.mjs +40 -0
package/dist/session/lock.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
2
|
import lockfile from 'proper-lockfile';
|
|
4
|
-
import { lockFile,
|
|
3
|
+
import { defaultProfileName, ensureProfileRuntimeDir, lockFile, pidFile, } from './paths.js';
|
|
5
4
|
import { CliError } from '../io/errors.js';
|
|
6
|
-
export async function acquireLock() {
|
|
7
|
-
|
|
5
|
+
export async function acquireLock(profile) {
|
|
6
|
+
const profileName = defaultProfileName(profile);
|
|
7
|
+
await ensureProfileRuntimeDir(profileName);
|
|
8
|
+
const target = lockFile(profileName);
|
|
8
9
|
// proper-lockfile requires the target file to exist
|
|
9
|
-
await fs.writeFile(
|
|
10
|
+
await fs.writeFile(target, '', { flag: 'a' });
|
|
10
11
|
const lockOpts = { retries: 0, stale: 5 * 60 * 1000 };
|
|
11
12
|
try {
|
|
12
|
-
return await lockfile.lock(
|
|
13
|
+
return await lockfile.lock(target, lockOpts);
|
|
13
14
|
}
|
|
14
15
|
catch (e) {
|
|
15
16
|
if (e.code !== 'ELOCKED')
|
|
@@ -18,22 +19,21 @@ export async function acquireLock() {
|
|
|
18
19
|
// a stale dir left over by an abruptly-killed process (Ctrl+C in
|
|
19
20
|
// --headed flow, SIGKILL on the daemon, etc.). If no daemon is running,
|
|
20
21
|
// we can safely clean up and retry — the dead process can't be using it.
|
|
21
|
-
if (await daemonIsAlive()) {
|
|
22
|
-
throw new CliError(5, 'LOCK_BUSY',
|
|
22
|
+
if (await daemonIsAlive(profileName)) {
|
|
23
|
+
throw new CliError(5, 'LOCK_BUSY', `Another 1688 command is running for profile "${profileName}". Close it and retry.`);
|
|
23
24
|
}
|
|
24
|
-
await fs.rm(
|
|
25
|
+
await fs.rm(target + '.lock', { recursive: true, force: true });
|
|
25
26
|
try {
|
|
26
|
-
return await lockfile.lock(
|
|
27
|
+
return await lockfile.lock(target, lockOpts);
|
|
27
28
|
}
|
|
28
29
|
catch {
|
|
29
|
-
throw new CliError(5, 'LOCK_BUSY',
|
|
30
|
+
throw new CliError(5, 'LOCK_BUSY', `Another 1688 command is running for profile "${profileName}". Close it and retry.`);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
async function daemonIsAlive() {
|
|
34
|
-
const pidFile = path.join(root(), 'daemon.pid');
|
|
34
|
+
async function daemonIsAlive(profile) {
|
|
35
35
|
try {
|
|
36
|
-
const pid = parseInt((await fs.readFile(pidFile, 'utf8')).trim(), 10);
|
|
36
|
+
const pid = parseInt((await fs.readFile(pidFile(profile), 'utf8')).trim(), 10);
|
|
37
37
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
38
38
|
return false;
|
|
39
39
|
try {
|
package/dist/session/lock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/session/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,
|
|
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,EACL,kBAAkB,EAClB,uBAAuB,EACvB,QAAQ,EACR,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAgB;IAChD,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,uBAAuB,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IACrC,oDAAoD;IACpD,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAE9C,MAAM,QAAQ,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAEtD,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAK,CAAuB,CAAC,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,CAAC;QAEzD,mEAAmE;QACnE,iEAAiE;QACjE,wEAAwE;QACxE,yEAAyE;QACzE,IAAI,MAAM,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,QAAQ,CAChB,CAAC,EACD,WAAW,EACX,gDAAgD,WAAW,wBAAwB,CACpF,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,QAAQ,CAChB,CAAC,EACD,WAAW,EACX,gDAAgD,WAAW,wBAAwB,CACpF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,OAAgB;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACpD,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,6CAA6C;YACnE,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/dist/session/paths.js
CHANGED
|
@@ -8,24 +8,35 @@ export function root() {
|
|
|
8
8
|
export function profilesDir() {
|
|
9
9
|
return path.join(root(), 'profiles');
|
|
10
10
|
}
|
|
11
|
-
export function
|
|
12
|
-
|
|
11
|
+
export function defaultProfileName(profile) {
|
|
12
|
+
const name = profile?.trim();
|
|
13
|
+
return name ? name : 'default';
|
|
13
14
|
}
|
|
14
|
-
export function
|
|
15
|
-
|
|
15
|
+
export function profileRuntimeDir(profile) {
|
|
16
|
+
const name = defaultProfileName(profile);
|
|
17
|
+
return name === 'default' ? root() : profilePath(name);
|
|
16
18
|
}
|
|
17
|
-
export function
|
|
18
|
-
return
|
|
19
|
+
export function stateFile(profile) {
|
|
20
|
+
return path.join(profileRuntimeDir(profile), 'state.json');
|
|
19
21
|
}
|
|
20
|
-
export function
|
|
22
|
+
export function lockFile(profile) {
|
|
23
|
+
return path.join(profileRuntimeDir(profile), '.lock');
|
|
24
|
+
}
|
|
25
|
+
export function socketPath(profile) {
|
|
26
|
+
return socketPathForPlatform(process.platform, root(), profile);
|
|
27
|
+
}
|
|
28
|
+
export function socketPathForPlatform(platform, rootPath, profile) {
|
|
29
|
+
const name = defaultProfileName(profile);
|
|
21
30
|
// Windows: Node's net.listen()/createConnection() can't bind a Unix-style
|
|
22
31
|
// filesystem path on win32 (EACCES). Use a named pipe instead. Include a
|
|
23
|
-
// stable root hash so different users
|
|
24
|
-
//
|
|
32
|
+
// stable root hash so different users and BB1688_HOME values do not collide,
|
|
33
|
+
// and include the profile hash so profiles under one root can run together.
|
|
25
34
|
if (platform === 'win32') {
|
|
26
|
-
|
|
35
|
+
const base = `\\\\.\\pipe\\1688-cli-daemon-${rootHash(rootPath)}`;
|
|
36
|
+
return name === 'default' ? base : `${base}-${profileHash(name)}`;
|
|
27
37
|
}
|
|
28
|
-
|
|
38
|
+
const dir = name === 'default' ? rootPath : path.join(rootPath, 'profiles', name);
|
|
39
|
+
return path.join(dir, 'daemon.sock');
|
|
29
40
|
}
|
|
30
41
|
export function rootHash(rootPath) {
|
|
31
42
|
return crypto
|
|
@@ -34,14 +45,21 @@ export function rootHash(rootPath) {
|
|
|
34
45
|
.digest('hex')
|
|
35
46
|
.slice(0, 12);
|
|
36
47
|
}
|
|
37
|
-
export function
|
|
38
|
-
return
|
|
48
|
+
export function profileHash(profile) {
|
|
49
|
+
return crypto
|
|
50
|
+
.createHash('sha1')
|
|
51
|
+
.update(defaultProfileName(profile).toLowerCase())
|
|
52
|
+
.digest('hex')
|
|
53
|
+
.slice(0, 12);
|
|
54
|
+
}
|
|
55
|
+
export function pidFile(profile) {
|
|
56
|
+
return path.join(profileRuntimeDir(profile), 'daemon.pid');
|
|
39
57
|
}
|
|
40
|
-
export function daemonVersionFile() {
|
|
41
|
-
return path.join(
|
|
58
|
+
export function daemonVersionFile(profile) {
|
|
59
|
+
return path.join(profileRuntimeDir(profile), 'daemon.version');
|
|
42
60
|
}
|
|
43
|
-
export function daemonLogFile() {
|
|
44
|
-
return path.join(
|
|
61
|
+
export function daemonLogFile(profile) {
|
|
62
|
+
return path.join(profileRuntimeDir(profile), 'daemon.log');
|
|
45
63
|
}
|
|
46
64
|
export function runsDir() {
|
|
47
65
|
return path.join(root(), 'runs');
|
|
@@ -56,9 +74,12 @@ export function loginQrFile() {
|
|
|
56
74
|
return path.join(root(), 'login-qr.png');
|
|
57
75
|
}
|
|
58
76
|
export function profilePath(name = 'default') {
|
|
59
|
-
return path.join(profilesDir(), name);
|
|
77
|
+
return path.join(profilesDir(), defaultProfileName(name));
|
|
60
78
|
}
|
|
61
79
|
export async function ensureRoot() {
|
|
62
80
|
await fs.mkdir(root(), { recursive: true });
|
|
63
81
|
}
|
|
82
|
+
export async function ensureProfileRuntimeDir(profile) {
|
|
83
|
+
await fs.mkdir(profileRuntimeDir(profile), { recursive: true });
|
|
84
|
+
}
|
|
64
85
|
//# sourceMappingURL=paths.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/session/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,UAAU,IAAI;IAClB,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,UAAU,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/session/paths.ts"],"names":[],"mappings":"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"}
|
package/dist/session/shared.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import fs from 'node:fs/promises';
|
|
5
5
|
import { chromium } from 'playwright-extra';
|
|
6
6
|
import stealth from 'puppeteer-extra-plugin-stealth';
|
|
7
|
-
import { profilePath } from './paths.js';
|
|
7
|
+
import { defaultProfileName, profilePath } from './paths.js';
|
|
8
8
|
import { acquireLock } from './lock.js';
|
|
9
9
|
import { CliError } from '../io/errors.js';
|
|
10
10
|
import { clearStaleSingleton } from './context.js';
|
|
@@ -22,14 +22,21 @@ const LAUNCH_OPTS = {
|
|
|
22
22
|
let sharedCtx = null;
|
|
23
23
|
let lockRelease = null;
|
|
24
24
|
let opChain = Promise.resolve();
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
let sharedProfile = null;
|
|
26
|
+
export async function getSharedContext(profile) {
|
|
27
|
+
const profileName = defaultProfileName(profile);
|
|
28
|
+
if (sharedCtx) {
|
|
29
|
+
if (sharedProfile !== profileName) {
|
|
30
|
+
throw new CliError(5, 'DAEMON_PROFILE_MISMATCH', `Daemon shared context is bound to profile "${sharedProfile}", not "${profileName}".`);
|
|
31
|
+
}
|
|
27
32
|
return sharedCtx;
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
}
|
|
34
|
+
lockRelease = await acquireLock(profileName);
|
|
35
|
+
const dir = profilePath(profileName);
|
|
30
36
|
await fs.mkdir(dir, { recursive: true });
|
|
31
37
|
await clearStaleSingleton(dir);
|
|
32
38
|
sharedCtx = await launchPreferringChrome(dir, true);
|
|
39
|
+
sharedProfile = profileName;
|
|
33
40
|
await sharedCtx.addInitScript(() => {
|
|
34
41
|
try {
|
|
35
42
|
Object.defineProperty(navigator, 'languages', {
|
|
@@ -42,7 +49,7 @@ export async function getSharedContext() {
|
|
|
42
49
|
});
|
|
43
50
|
return sharedCtx;
|
|
44
51
|
}
|
|
45
|
-
export async function runOnSharedCtx(fn, meta) {
|
|
52
|
+
export async function runOnSharedCtx(fn, meta, profile) {
|
|
46
53
|
// Append to serial queue. Each op waits for the previous one to finish.
|
|
47
54
|
const prev = opChain;
|
|
48
55
|
let resolveOp;
|
|
@@ -53,7 +60,7 @@ export async function runOnSharedCtx(fn, meta) {
|
|
|
53
60
|
});
|
|
54
61
|
opChain = prev.then(async () => {
|
|
55
62
|
try {
|
|
56
|
-
const ctx = await getSharedContext();
|
|
63
|
+
const ctx = await getSharedContext(profile);
|
|
57
64
|
resolveOp(await fn(ctx));
|
|
58
65
|
}
|
|
59
66
|
catch (e) {
|
|
@@ -71,6 +78,7 @@ export async function runOnSharedCtx(fn, meta) {
|
|
|
71
78
|
export async function getSharedContextStatus() {
|
|
72
79
|
if (!sharedCtx) {
|
|
73
80
|
return {
|
|
81
|
+
profile: sharedProfile,
|
|
74
82
|
browserAlive: false,
|
|
75
83
|
pageCount: 0,
|
|
76
84
|
currentUrl: null,
|
|
@@ -82,6 +90,7 @@ export async function getSharedContextStatus() {
|
|
|
82
90
|
const page = pages.at(-1) ?? null;
|
|
83
91
|
const pageState = page ? await detectPageState(page).catch(() => null) : null;
|
|
84
92
|
return {
|
|
93
|
+
profile: sharedProfile,
|
|
85
94
|
browserAlive: true,
|
|
86
95
|
pageCount: pages.length,
|
|
87
96
|
currentUrl: page?.url() ?? null,
|
|
@@ -100,6 +109,7 @@ export async function releaseSharedContext() {
|
|
|
100
109
|
await sharedCtx.close().catch(() => { });
|
|
101
110
|
sharedCtx = null;
|
|
102
111
|
}
|
|
112
|
+
sharedProfile = null;
|
|
103
113
|
if (lockRelease) {
|
|
104
114
|
await lockRelease().catch(() => { });
|
|
105
115
|
lockRelease = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/session/shared.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,0EAA0E;AAC1E,mCAAmC;AAEnC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,OAAO,MAAM,gCAAgC,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/session/shared.ts"],"names":[],"mappings":"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"}
|
package/dist/session/state.js
CHANGED
|
@@ -2,9 +2,9 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { stateFile, ensureRoot } from './paths.js';
|
|
4
4
|
const EMPTY = { version: 1 };
|
|
5
|
-
export async function readState() {
|
|
5
|
+
export async function readState(profile) {
|
|
6
6
|
try {
|
|
7
|
-
const buf = await fs.readFile(stateFile(), 'utf8');
|
|
7
|
+
const buf = await fs.readFile(stateFile(profile), 'utf8');
|
|
8
8
|
const parsed = JSON.parse(buf);
|
|
9
9
|
if (parsed?.version !== 1)
|
|
10
10
|
return { ...EMPTY };
|
|
@@ -16,12 +16,12 @@ export async function readState() {
|
|
|
16
16
|
throw e;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
export async function writeState(s) {
|
|
19
|
+
export async function writeState(s, profile) {
|
|
20
20
|
await ensureRoot();
|
|
21
|
-
await fs.mkdir(path.dirname(stateFile()), { recursive: true });
|
|
22
|
-
await fs.writeFile(stateFile(), JSON.stringify(s, null, 2));
|
|
21
|
+
await fs.mkdir(path.dirname(stateFile(profile)), { recursive: true });
|
|
22
|
+
await fs.writeFile(stateFile(profile), JSON.stringify(s, null, 2));
|
|
23
23
|
}
|
|
24
|
-
export async function clearState() {
|
|
25
|
-
await writeState({ ...EMPTY });
|
|
24
|
+
export async function clearState(profile) {
|
|
25
|
+
await writeState({ ...EMPTY }, profile);
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/session/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAUnD,MAAM,KAAK,GAAU,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,SAAS;
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/session/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAUnD,MAAM,KAAK,GAAU,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;QACjD,IAAI,MAAM,EAAE,OAAO,KAAK,CAAC;YAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QAC/C,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAK,CAA2B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QACxE,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAQ,EAAE,OAAgB;IACzD,MAAM,UAAU,EAAE,CAAC;IACnB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtE,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAgB;IAC/C,MAAM,UAAU,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC"}
|
package/docs/COMMANDS.md
CHANGED
|
@@ -148,11 +148,17 @@ given.
|
|
|
148
148
|
1688 login --force
|
|
149
149
|
1688 logout [--yes]
|
|
150
150
|
1688 whoami [--verify]
|
|
151
|
-
1688 doctor [--no-launch]
|
|
152
|
-
1688 daemon start | stop | status | reload
|
|
153
|
-
1688 serve
|
|
151
|
+
1688 doctor [--no-launch] [--profile <name>]
|
|
152
|
+
1688 daemon start | stop | status | reload [--profile <name>]
|
|
153
|
+
1688 serve [--profile <name>]
|
|
154
|
+
1688 profile list
|
|
155
|
+
1688 profile status [name]
|
|
154
156
|
```
|
|
155
157
|
|
|
158
|
+
All account, browser, daemon, and buyer-workflow commands default to the
|
|
159
|
+
`default` profile. Passing `--profile <name>` uses that profile's persistent
|
|
160
|
+
browser directory, state file, daemon process, lock, and daemon artifacts.
|
|
161
|
+
|
|
156
162
|
## Output Flags
|
|
157
163
|
|
|
158
164
|
Every command supports:
|
package/docs/JSON_CONTRACTS.md
CHANGED
|
@@ -20,6 +20,92 @@ without an explicit breaking-change decision.
|
|
|
20
20
|
{ loggedIn: false }
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## `daemon status`
|
|
24
|
+
|
|
25
|
+
`daemon status` is profile-scoped. When `--profile` is omitted, `profile` is
|
|
26
|
+
`default`.
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
{
|
|
30
|
+
profile: string,
|
|
31
|
+
running: boolean,
|
|
32
|
+
pid?: number,
|
|
33
|
+
reachable?: boolean,
|
|
34
|
+
version?: string | null,
|
|
35
|
+
expectedVersion?: string,
|
|
36
|
+
versionMatches?: boolean,
|
|
37
|
+
stats?: {
|
|
38
|
+
profile: string,
|
|
39
|
+
version: string,
|
|
40
|
+
startedAt: string,
|
|
41
|
+
pid: number,
|
|
42
|
+
commandCount: number,
|
|
43
|
+
lastRequestAt: string | null,
|
|
44
|
+
lastError: string | null,
|
|
45
|
+
uptimeMs: number,
|
|
46
|
+
activeClients: number,
|
|
47
|
+
browser: {
|
|
48
|
+
profile: string | null,
|
|
49
|
+
browserAlive: boolean,
|
|
50
|
+
pageCount: number,
|
|
51
|
+
currentUrl: string | null,
|
|
52
|
+
pageState: object | null,
|
|
53
|
+
loggedIn: boolean | null,
|
|
54
|
+
},
|
|
55
|
+
health: object,
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## `profile status`
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
{
|
|
64
|
+
profile: {
|
|
65
|
+
name: string,
|
|
66
|
+
path: string,
|
|
67
|
+
exists: boolean,
|
|
68
|
+
locked: boolean,
|
|
69
|
+
loggedIn: boolean,
|
|
70
|
+
recentRequestId: string | null,
|
|
71
|
+
recentStatus: string | null,
|
|
72
|
+
recentErrorCode: string | null,
|
|
73
|
+
daemon: {
|
|
74
|
+
profile: string,
|
|
75
|
+
running: boolean,
|
|
76
|
+
pid?: number,
|
|
77
|
+
reachable?: boolean,
|
|
78
|
+
version?: string | null,
|
|
79
|
+
expectedVersion?: string,
|
|
80
|
+
versionMatches?: boolean,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
state: {
|
|
84
|
+
version: 1,
|
|
85
|
+
memberId?: string,
|
|
86
|
+
nick?: string,
|
|
87
|
+
loggedInAt?: string,
|
|
88
|
+
lastVerifiedAt?: string,
|
|
89
|
+
} | null,
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## `doctor`
|
|
94
|
+
|
|
95
|
+
`doctor --profile <name>` checks that profile's directory, lock, state,
|
|
96
|
+
daemon, and live daemon socket. JSON output includes the selected `profile` and
|
|
97
|
+
the matching profile-scoped daemon status.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
{
|
|
101
|
+
ok: boolean,
|
|
102
|
+
profile: string,
|
|
103
|
+
checks: Array<{ name: string, status: "ok" | "warn" | "fail", message: string, fix?: string }>,
|
|
104
|
+
version: VersionInfo,
|
|
105
|
+
daemon: DaemonStatus | null,
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
23
109
|
## `search`, `similar`, `image-search`
|
|
24
110
|
|
|
25
111
|
```ts
|
package/docs/QUALITY_SCORE.md
CHANGED
|
@@ -14,7 +14,8 @@ Overall: 6 / 10
|
|
|
14
14
|
- Commands expose JSON automatically when piped and support `--json`,
|
|
15
15
|
`--pretty`, `--get`, and `--pick`.
|
|
16
16
|
- Real browser/session behavior is centralized under `src/session`.
|
|
17
|
-
-
|
|
17
|
+
- Profile-scoped daemons give agents warm browser contexts without forcing
|
|
18
|
+
unrelated profiles through one global lock.
|
|
18
19
|
- Checkout and feedback write actions already have explicit safety protocols.
|
|
19
20
|
- Deterministic Vitest coverage exists for output, mtop parsing, recovery,
|
|
20
21
|
page-state, inbox cards, and fixtures through `pnpm test:unit`.
|
package/docs/README.md
CHANGED
|
@@ -20,6 +20,7 @@ This directory is the canonical knowledge base for agents and humans working on
|
|
|
20
20
|
|
|
21
21
|
- Specs: [`specs/`](specs/)
|
|
22
22
|
- Repeatable playbooks: [`playbooks/`](playbooks/)
|
|
23
|
+
- Records and postmortems: [`records/`](records/)
|
|
23
24
|
- Generated repository indexes: [`generated/`](generated/)
|
|
24
25
|
- Long-running plans: [`exec-plans/`](exec-plans/)
|
|
25
26
|
|
package/docs/RELIABILITY.md
CHANGED
|
@@ -6,20 +6,28 @@ and recoverable for agents.
|
|
|
6
6
|
|
|
7
7
|
## Daemon
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Each daemon routes commands for one profile through one persistent Chromium
|
|
10
|
+
context. Different profiles use different daemon processes, locks, sockets or
|
|
11
|
+
named pipes, pid/version/log files, state files, and persistent browser
|
|
12
|
+
directories.
|
|
10
13
|
|
|
11
14
|
Benefits:
|
|
12
15
|
|
|
13
16
|
- Saves Chrome cold-start time.
|
|
14
|
-
- Keeps one continuous logged-in session.
|
|
17
|
+
- Keeps one continuous logged-in session per profile.
|
|
15
18
|
- Adds inter-command jitter.
|
|
19
|
+
- Allows different profiles to run at the same time without sharing one
|
|
20
|
+
process lock.
|
|
16
21
|
|
|
17
22
|
Use `1688 daemon start` near the beginning of a session with multiple 1688
|
|
18
|
-
commands.
|
|
19
|
-
after
|
|
23
|
+
commands. Use `1688 daemon start --profile <name>` for a non-default profile.
|
|
24
|
+
The daemon auto-stops after inactivity. Run `1688 daemon reload --profile
|
|
25
|
+
<name>` after package updates or after manually resolving profile-specific
|
|
26
|
+
browser issues.
|
|
20
27
|
|
|
21
28
|
`login`, `logout`, and `doctor` stay inline because they need interactive UI,
|
|
22
|
-
browser windows, or environment checks.
|
|
29
|
+
browser windows, or environment checks. `login --profile <name>` can
|
|
30
|
+
auto-start that profile daemon after the login state is available.
|
|
23
31
|
|
|
24
32
|
## Watch Mode
|
|
25
33
|
|
package/docs/SAFETY.md
CHANGED
|
@@ -12,7 +12,7 @@ place orders. Treat write actions as explicit user-authorized operations.
|
|
|
12
12
|
| 2 | Bad invocation | Fix arguments or report the bad input. |
|
|
13
13
|
| 3 | Not logged in / session expired | Tell the user to run `1688 login`; do not loop. |
|
|
14
14
|
| 4 | Risk control / slider verification | Tell the user to rerun once with `--headed`; do not silently retry. |
|
|
15
|
-
| 5 | Another 1688 command is running | Wait only if the task naturally allows it; otherwise report lock busy. |
|
|
15
|
+
| 5 | Another 1688 command is running for the selected profile | Wait only if the task naturally allows it; otherwise report lock busy. |
|
|
16
16
|
| 6 | Chromium missing | Report dependency issue. |
|
|
17
17
|
| 7 | Login wait timeout | Report timeout. |
|
|
18
18
|
| 8 | Login finished but cookies missing | Report login cookie issue. |
|
|
@@ -97,4 +97,3 @@ Rules:
|
|
|
97
97
|
command.
|
|
98
98
|
- In non-interactive loops, do not upgrade automatically.
|
|
99
99
|
- After an approved package update, run `1688 daemon reload`.
|
|
100
|
-
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Plan: Profile Daemon
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Deliver profile-scoped daemon mode for `1688-cli`: one daemon, persistent
|
|
6
|
+
browser context, lock, and runtime artifact set per profile, with default
|
|
7
|
+
profile compatibility and deterministic verification.
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
- Source spec: `docs/specs/profile-daemon.md`.
|
|
12
|
+
- Read first:
|
|
13
|
+
- `AGENTS.md`
|
|
14
|
+
- `ARCHITECTURE.md`
|
|
15
|
+
- `docs/WORKFLOW.md`
|
|
16
|
+
- `docs/COMMANDS.md`
|
|
17
|
+
- `docs/JSON_CONTRACTS.md`
|
|
18
|
+
- `docs/SAFETY.md`
|
|
19
|
+
- `docs/RELIABILITY.md`
|
|
20
|
+
- `docs/playbooks/add-command.md`
|
|
21
|
+
- `src/session/paths.ts`
|
|
22
|
+
- `src/session/lock.ts`
|
|
23
|
+
- `src/session/context.ts`
|
|
24
|
+
- `src/session/shared.ts`
|
|
25
|
+
- `src/session/dispatch.ts`
|
|
26
|
+
- `src/daemon/client.ts`
|
|
27
|
+
- `src/daemon/manager.ts`
|
|
28
|
+
- `src/daemon/server.ts`
|
|
29
|
+
- `src/commands/login.ts`
|
|
30
|
+
- `src/commands/doctor.ts`
|
|
31
|
+
- `src/commands/profile.ts`
|
|
32
|
+
- `src/cli.ts`
|
|
33
|
+
- `tests/paths.test.ts`
|
|
34
|
+
- `tests/profile.test.ts`
|
|
35
|
+
- `tests/doctor.test.ts`
|
|
36
|
+
|
|
37
|
+
## Non-goals
|
|
38
|
+
|
|
39
|
+
- Do not implement a multi-profile daemon process.
|
|
40
|
+
- Do not change checkout confirmation safety.
|
|
41
|
+
- Do not run external live login/search/browser flows during verification.
|
|
42
|
+
- Do not introduce new dependencies.
|
|
43
|
+
- Do not refactor unrelated command behavior.
|
|
44
|
+
|
|
45
|
+
## Design
|
|
46
|
+
|
|
47
|
+
Use one profile-bound daemon process per profile. The profile is resolved to
|
|
48
|
+
`default` at the edge and then passed through path helpers, locks, daemon
|
|
49
|
+
client/manager/server, shared context, dispatch, login, doctor, and profile
|
|
50
|
+
status.
|
|
51
|
+
|
|
52
|
+
Runtime artifacts become profile-scoped via centralized helpers. Non-Windows
|
|
53
|
+
sockets live under a profile runtime directory; Windows named pipes include the
|
|
54
|
+
root hash plus a profile-derived hash/slug so profiles do not collide.
|
|
55
|
+
|
|
56
|
+
`dispatch` no longer treats `opts.profile` as a daemon skip condition. It
|
|
57
|
+
connects to the selected profile daemon, auto-starts or refreshes only that
|
|
58
|
+
daemon, and falls back inline only for that profile. Headed mode, `noDaemon`,
|
|
59
|
+
and `BB1688_NO_DAEMON=1` still skip daemon dispatch.
|
|
60
|
+
|
|
61
|
+
Inline fallback pauses only the selected profile daemon before opening an
|
|
62
|
+
inline context on that profile. Other profile daemons continue running.
|
|
63
|
+
|
|
64
|
+
`login --profile` writes profile-scoped state and attempts to start that
|
|
65
|
+
profile daemon unless `--no-daemon` is set. `doctor --profile` and
|
|
66
|
+
`profile status <name>` read profile-scoped state, lock, and daemon status.
|
|
67
|
+
|
|
68
|
+
Docs and generated indexes are updated because command flags, daemon behavior,
|
|
69
|
+
and source/test layout behavior changed.
|
|
70
|
+
|
|
71
|
+
## Checklist
|
|
72
|
+
|
|
73
|
+
- [x] Create spec/index and active ExecPlan for profile-scoped daemon work.
|
|
74
|
+
- [x] Implement profile-scoped path helpers and lock acquisition.
|
|
75
|
+
- [x] Thread profile through session context, shared daemon context, daemon
|
|
76
|
+
client, daemon manager, and daemon server.
|
|
77
|
+
- [x] Update dispatch so explicit `--profile` uses the corresponding daemon and
|
|
78
|
+
inline fallback pauses only that profile daemon.
|
|
79
|
+
- [x] Update CLI daemon/serve commands, login auto-start, doctor checks, and
|
|
80
|
+
profile status to use selected profile state and diagnostics.
|
|
81
|
+
- [x] Update deterministic tests for paths, profile status, doctor, and daemon
|
|
82
|
+
profile plumbing.
|
|
83
|
+
- [x] Update durable docs and regenerate generated context.
|
|
84
|
+
- [x] Run focused and final verification, review diff, and record results.
|
|
85
|
+
|
|
86
|
+
## Verification
|
|
87
|
+
|
|
88
|
+
- `pnpm typecheck`
|
|
89
|
+
- `pnpm test:unit`
|
|
90
|
+
- `pnpm agent-context`
|
|
91
|
+
- `pnpm docs-check`
|
|
92
|
+
- `pnpm agent-map-check`
|
|
93
|
+
- `pnpm agent-verify`
|
|
94
|
+
|
|
95
|
+
## Decisions
|
|
96
|
+
|
|
97
|
+
- 2026-06-16: Use one daemon process per profile instead of one daemon managing
|
|
98
|
+
many browser contexts, matching the request and current daemon architecture.
|
|
99
|
+
- 2026-06-16: Keep `checkout-confirm` daemon-blocked; profile daemon support
|
|
100
|
+
does not weaken checkout safety.
|
|
101
|
+
- 2026-06-16: Use deterministic local verification only; live 1688 browser
|
|
102
|
+
checks require user/session state and are out of scope for automated tests.
|
|
103
|
+
|
|
104
|
+
## Progress Log
|
|
105
|
+
|
|
106
|
+
- 2026-06-16: `/to-done` readiness path selected: clear complex request with no
|
|
107
|
+
existing matching durable spec or active plan, so create full spec and full
|
|
108
|
+
active ExecPlan before implementation.
|
|
109
|
+
- 2026-06-16: `/run` execution strategy selected. Goal tracking preference:
|
|
110
|
+
prefer Codex /goal. Goal tracking result: Codex /goal. Delegation: none.
|
|
111
|
+
Reason: the active plan has one objective, scoped non-goals, deterministic
|
|
112
|
+
verification, and an adaptive validation loop. Subagents skipped because the
|
|
113
|
+
core daemon/session files are tightly coupled and should be edited/reviewed
|
|
114
|
+
by the primary agent. Completed checklist item: durable spec/index and active
|
|
115
|
+
ExecPlan created.
|
|
116
|
+
- 2026-06-16: Implemented profile-scoped runtime helpers for socket, pid,
|
|
117
|
+
version, log, state, and lock artifacts. Default artifacts remain compatible
|
|
118
|
+
at the historical root paths; non-default profiles use their profile runtime
|
|
119
|
+
directory. Windows daemon pipes now include a profile hash.
|
|
120
|
+
- 2026-06-16: Threaded profile through locks, inline sessions, shared daemon
|
|
121
|
+
browser context, daemon client/manager/server, dispatch, login auto-start,
|
|
122
|
+
doctor, profile status, whoami state writes, seller/inbox state reads, and
|
|
123
|
+
checkout-confirm daemon pause/resume.
|
|
124
|
+
- 2026-06-16: Updated durable docs (`ARCHITECTURE.md`, `docs/COMMANDS.md`,
|
|
125
|
+
`docs/JSON_CONTRACTS.md`, `docs/RELIABILITY.md`, `docs/SAFETY.md`,
|
|
126
|
+
`docs/QUALITY_SCORE.md`) and refreshed generated context with
|
|
127
|
+
`pnpm agent-context`.
|
|
128
|
+
- 2026-06-16: Review result: diff stayed within the profile daemon spec and
|
|
129
|
+
plan; checkout confirmation remains daemon-blocked and approval behavior is
|
|
130
|
+
unchanged. A small doctor indentation/readability issue found during diff
|
|
131
|
+
review was fixed before final verification.
|
|
132
|
+
- 2026-06-16: Verification passed:
|
|
133
|
+
`pnpm typecheck`;
|
|
134
|
+
`pnpm vitest run tests/paths.test.ts tests/state.test.ts tests/profile.test.ts tests/doctor.test.ts --exclude tests/doctor-live.test.ts`;
|
|
135
|
+
`pnpm test:unit`;
|
|
136
|
+
`pnpm agent-context`;
|
|
137
|
+
`pnpm agent-verify`.
|
|
138
|
+
Final `pnpm agent-verify` passed with 27 test files and 174 deterministic
|
|
139
|
+
tests, fresh generated context, passing agent-map check, and passing release
|
|
140
|
+
check. No blockers or new open questions remain.
|
|
141
|
+
|
|
142
|
+
## Rollback
|
|
143
|
+
|
|
144
|
+
Revert the profile daemon changes in `src/session`, `src/daemon`,
|
|
145
|
+
`src/commands`, `src/cli.ts`, tests, and docs. Existing profile browser data
|
|
146
|
+
under `~/.1688/profiles/<name>` is not modified by rollback.
|