@lightcone-ai/daemon 0.14.10 → 0.14.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightcone-ai/daemon",
3
- "version": "0.14.10",
3
+ "version": "0.14.12",
4
4
  "type": "module",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -7,6 +7,7 @@ import { KuaishouAdapter } from '../mcp-servers/publisher/adapters/kuaishou.js';
7
7
  import { callOfficialTool } from '../mcp-servers/publisher/official-tool-client.js';
8
8
  import { runPublishPrecheck } from '../mcp-servers/publisher/precheck.js';
9
9
  import { withProfileLock } from './profile-lock.js';
10
+ import { profileDir as getBrowserProfileDir } from './browser-login.js';
10
11
 
11
12
  const PLATFORM_ENV_KEYS = {
12
13
  xhs: 'XHS_PROFILE_DIR',
@@ -36,10 +37,53 @@ function asObject(value) {
36
37
  return {};
37
38
  }
38
39
 
39
- function getProfileDir(platform) {
40
- const key = PLATFORM_ENV_KEYS[platform];
41
- if (!key) return null;
42
- return process.env[key] ?? null;
40
+ export function resolveProfileDir(platform, { ownerId } = {}) {
41
+ const envKey = PLATFORM_ENV_KEYS[platform];
42
+ const envValue = normalizeText(envKey ? process.env[envKey] : null);
43
+ if (envValue) {
44
+ return {
45
+ profileDir: envValue,
46
+ source: 'env',
47
+ envKey,
48
+ ownerId: normalizeText(ownerId),
49
+ };
50
+ }
51
+
52
+ const normalizedOwnerId = normalizeText(ownerId);
53
+ if (normalizedOwnerId) {
54
+ return {
55
+ profileDir: getBrowserProfileDir(platform, normalizedOwnerId),
56
+ source: 'owner',
57
+ envKey,
58
+ ownerId: normalizedOwnerId,
59
+ };
60
+ }
61
+
62
+ return {
63
+ profileDir: null,
64
+ source: 'missing_owner',
65
+ envKey,
66
+ ownerId: null,
67
+ };
68
+ }
69
+
70
+ export function resolveExistingProfileDir(platform, { ownerId } = {}) {
71
+ const resolved = resolveProfileDir(platform, { ownerId });
72
+ if (!resolved.profileDir) {
73
+ throw new Error('publish:job missing owner_id; server must include it for cross-machine profile resolution');
74
+ }
75
+
76
+ if (!existsSync(resolved.profileDir)) {
77
+ if (resolved.source === 'env') {
78
+ throw new Error(`Profile dir from ${resolved.envKey} not found: ${resolved.profileDir}`);
79
+ }
80
+ throw new Error(
81
+ `Profile dir for ${platform} not found at ${resolved.profileDir}; ` +
82
+ 'user must complete browser-login on this machine first'
83
+ );
84
+ }
85
+
86
+ return resolved.profileDir;
43
87
  }
44
88
 
45
89
  function getAdapterClass(platform) {
@@ -53,22 +97,16 @@ function createStaticAdapter(platform) {
53
97
  return new AdapterClass(null);
54
98
  }
55
99
 
56
- async function getAdapter(platform) {
57
- const profileDir = getProfileDir(platform);
58
- if (!profileDir) {
59
- throw new Error(`No profile dir for platform="${platform}". Has the user logged in and authorized this machine?`);
60
- }
61
- const cdp = await getSession(platform, profileDir);
100
+ async function getAdapter(platform, { ownerId } = {}) {
101
+ const resolvedProfileDir = resolveExistingProfileDir(platform, { ownerId });
102
+ const cdp = await getSession(platform, resolvedProfileDir);
62
103
  const AdapterClass = getAdapterClass(platform);
63
104
  return new AdapterClass(cdp);
64
105
  }
65
106
 
66
- async function withPublisherProfile(platform, fn) {
67
- const profileDir = getProfileDir(platform);
68
- if (!profileDir) {
69
- throw new Error(`No profile dir for platform="${platform}". Has the user logged in and authorized this machine?`);
70
- }
71
- return withProfileLock(platform, profileDir, {
107
+ async function withPublisherProfile(platform, { ownerId } = {}, fn) {
108
+ const resolvedProfileDir = resolveExistingProfileDir(platform, { ownerId });
109
+ return withProfileLock(platform, resolvedProfileDir, {
72
110
  owner: `publisher:${platform}`,
73
111
  timeoutMs: 30_000,
74
112
  staleMs: 20 * 60 * 1000,
@@ -92,19 +130,20 @@ function decodeWorkspaceContent(content) {
92
130
  return Buffer.from(decodeURIComponent(body), 'utf8');
93
131
  }
94
132
 
95
- async function internalApi({ serverUrl, machineApiKey, agentId, method, endpoint, body }) {
96
- const url = `${String(serverUrl).replace(/\/$/, '')}/internal/agent/${encodeURIComponent(agentId)}${endpoint}`;
133
+ export async function fetchPublishJobWorkspaceFile({ serverUrl, machineApiKey, jobId, relPath }) {
134
+ const normalizedJobId = String(jobId ?? '').trim();
135
+ if (!normalizedJobId) {
136
+ throw new Error('publish job id is required to fetch workspace files');
137
+ }
138
+ const url = `${String(serverUrl).replace(/\/$/, '')}/internal/agent/publish-jobs/${encodeURIComponent(normalizedJobId)}/workspace-files?path=${encodeURIComponent(relPath)}`;
97
139
  const res = await fetch(url, {
98
- method,
99
140
  headers: {
100
- 'Content-Type': 'application/json',
101
141
  Authorization: `Bearer ${machineApiKey}`,
102
142
  },
103
- body: body != null ? JSON.stringify(body) : undefined,
104
143
  });
105
144
  if (!res.ok) {
106
145
  const text = await res.text();
107
- throw new Error(`internal API ${method} ${endpoint} failed (${res.status}): ${text}`);
146
+ throw new Error(`publish-jobs workspace-files GET failed (${res.status}): ${text}`);
108
147
  }
109
148
  return res.json();
110
149
  }
@@ -135,7 +174,15 @@ export function workspacePathFromMediaPath(filePath, workspaceId) {
135
174
  return null;
136
175
  }
137
176
 
138
- async function materializeWorkspaceMedia({ filePath, workspaceId, workspaceRootDir, serverUrl, machineApiKey, agentId }) {
177
+ export async function materializeWorkspaceMedia({
178
+ filePath,
179
+ workspaceId,
180
+ workspaceRootDir,
181
+ serverUrl,
182
+ machineApiKey,
183
+ jobId,
184
+ fetchWorkspaceFile = fetchPublishJobWorkspaceFile,
185
+ }) {
139
186
  if (!filePath || existsSync(filePath)) return filePath;
140
187
 
141
188
  const workspacePath = workspacePathFromMediaPath(filePath, workspaceId);
@@ -149,12 +196,11 @@ async function materializeWorkspaceMedia({ filePath, workspaceId, workspaceRootD
149
196
 
150
197
  if (existsSync(localPath)) return localPath;
151
198
 
152
- const data = await internalApi({
199
+ const data = await fetchWorkspaceFile({
153
200
  serverUrl,
154
201
  machineApiKey,
155
- agentId,
156
- method: 'GET',
157
- endpoint: `/workspace-memory?path=${encodeURIComponent(workspacePath.relPath)}&workspaceId=${encodeURIComponent(workspacePath.workspaceId)}`,
202
+ jobId,
203
+ relPath: workspacePath.relPath,
158
204
  });
159
205
  mkdirSync(path.dirname(localPath), { recursive: true });
160
206
  writeFileSync(localPath, decodeWorkspaceContent(data.content));
@@ -169,7 +215,7 @@ async function materializeMedia({
169
215
  workspaceRootDir,
170
216
  serverUrl,
171
217
  machineApiKey,
172
- agentId,
218
+ jobId,
173
219
  }) {
174
220
  return {
175
221
  images: await Promise.all(images.map(filePath => materializeWorkspaceMedia({
@@ -178,7 +224,7 @@ async function materializeMedia({
178
224
  workspaceRootDir,
179
225
  serverUrl,
180
226
  machineApiKey,
181
- agentId,
227
+ jobId,
182
228
  }))),
183
229
  video: video ? await materializeWorkspaceMedia({
184
230
  filePath: video,
@@ -186,7 +232,7 @@ async function materializeMedia({
186
232
  workspaceRootDir,
187
233
  serverUrl,
188
234
  machineApiKey,
189
- agentId,
235
+ jobId,
190
236
  }) : video,
191
237
  cover: cover ? await materializeWorkspaceMedia({
192
238
  filePath: cover,
@@ -194,7 +240,7 @@ async function materializeMedia({
194
240
  workspaceRootDir,
195
241
  serverUrl,
196
242
  machineApiKey,
197
- agentId,
243
+ jobId,
198
244
  }) : cover,
199
245
  };
200
246
  }
@@ -360,6 +406,7 @@ export async function runPublishJob({ serverUrl, machineApiKey, agentId, workspa
360
406
  video,
361
407
  cover,
362
408
  } = buildJobInput(job);
409
+ const ownerId = normalizeText(job?.owner_id ?? job?.ownerId);
363
410
 
364
411
  if (!platform) throw new Error('publish job missing platform');
365
412
  if (!contentType) throw new Error('publish job missing content_type');
@@ -404,7 +451,7 @@ export async function runPublishJob({ serverUrl, machineApiKey, agentId, workspa
404
451
  workspaceRootDir,
405
452
  serverUrl,
406
453
  machineApiKey,
407
- agentId,
454
+ jobId: job?.id,
408
455
  });
409
456
  const staticAdapter = createStaticAdapter(platform);
410
457
  const req = staticAdapter.getRequirements(contentType);
@@ -420,8 +467,8 @@ export async function runPublishJob({ serverUrl, machineApiKey, agentId, workspa
420
467
  });
421
468
 
422
469
  try {
423
- const { publishResult, healthCheck } = await withPublisherProfile(platform, async () => {
424
- const adapter = await getAdapter(platform);
470
+ const { publishResult, healthCheck } = await withPublisherProfile(platform, { ownerId }, async () => {
471
+ const adapter = await getAdapter(platform, { ownerId });
425
472
  const prePublishLogin = await adapter.checkLoginStatus();
426
473
  if (prePublishLogin?.loggedIn === false) {
427
474
  throw new Error(`LOGIN_EXPIRED:${platform}`);