@nowcrew/daemon 0.6.57 → 0.6.58

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.
@@ -236,6 +236,7 @@ export function createStorageMigrationRuntimeController(rawInput, injected = {})
236
236
  migrationId: operation.migrationId,
237
237
  platform: input.platform,
238
238
  userHome: input.userHome,
239
+ ...(input.uid === undefined ? {} : { uid: input.uid }),
239
240
  });
240
241
  workerLaunched = true;
241
242
  const outcome = await dependencies.monitorWorker({
@@ -58,9 +58,12 @@ function findSourceRecord(records, input) {
58
58
  return matches.length === 1 ? matches[0] : null;
59
59
  }
60
60
  export async function probeStorageMigrationRuntime(rawInput, injected = {}) {
61
- if (rawInput.platform !== "linux") {
61
+ if (rawInput.platform !== "darwin" && rawInput.platform !== "linux") {
62
62
  return notReady("platform_not_supported");
63
63
  }
64
+ if (rawInput.platform === "darwin" && rawInput.uid === undefined) {
65
+ return notReady("platform_identity_missing");
66
+ }
64
67
  const configuredNowworkHome = rawInput.environment.NOWWORK_HOME;
65
68
  if (configuredNowworkHome === undefined)
66
69
  return notReady("nowwork_home_missing");
@@ -62,6 +62,16 @@ function workerUnitName(migrationId) {
62
62
  function workerUnitPath(userHome, migrationId) {
63
63
  return resolve(userHome, ".config", "systemd", "user", workerUnitName(migrationId));
64
64
  }
65
+ function workerLaunchdLabel(migrationId) {
66
+ return `com.nowcrew.storage-migration.${migrationId}`;
67
+ }
68
+ function workerLaunchdPath(userHome, migrationId) {
69
+ return resolve(userHome, "Library", "LaunchAgents", `${workerLaunchdLabel(migrationId)}.plist`);
70
+ }
71
+ function xml(value) {
72
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
73
+ .replaceAll('"', "&quot;").replaceAll("'", "&apos;");
74
+ }
65
75
  function systemdArg(value) {
66
76
  if (/[\0\r\n]/u.test(value))
67
77
  throw new Error("storage worker service argument must be a single line");
@@ -77,9 +87,26 @@ export async function launchStorageMigrationWorker(input, runSupervisor = system
77
87
  AbsolutePathSchema.parse(input.handoffPath);
78
88
  AbsolutePathSchema.parse(input.userHome);
79
89
  const migrationId = z.string().uuid().parse(input.migrationId).toLowerCase();
80
- if (input.platform !== "linux")
81
- throw new Error("Persistent storage migration workers require Linux systemd");
82
90
  const worker = [process.execPath, input.entryPath, "storage-migration-worker", "--job", input.handoffPath];
91
+ if (input.platform === "darwin") {
92
+ if (input.uid === undefined || !Number.isSafeInteger(input.uid) || input.uid < 0) {
93
+ throw new Error("Persistent storage migration launchd worker requires a numeric uid");
94
+ }
95
+ const label = workerLaunchdLabel(migrationId);
96
+ const path = workerLaunchdPath(input.userHome, migrationId);
97
+ const args = worker.map((arg) => ` <string>${xml(arg)}</string>`).join("\n");
98
+ const descriptor = `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>Label</key><string>${xml(label)}</string>\n <key>ProgramArguments</key>\n <array>\n${args}\n </array>\n <key>RunAtLoad</key><true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key><false/>\n </dict>\n <key>ProcessType</key><string>Background</string>\n</dict>\n</plist>\n`;
99
+ await atomicPrivateWrite(path, descriptor);
100
+ try {
101
+ await checkedSupervisor(runSupervisor, "launchctl", ["bootstrap", `gui/${input.uid}`, path]);
102
+ }
103
+ catch (error) {
104
+ await runSupervisor("launchctl", ["bootout", `gui/${input.uid}/${label}`]).catch(() => undefined);
105
+ await rm(path, { force: true });
106
+ throw new Error("Storage migration persistent service launch failed", { cause: error });
107
+ }
108
+ return;
109
+ }
83
110
  const unit = workerUnitName(migrationId);
84
111
  const path = workerUnitPath(input.userHome, migrationId);
85
112
  const descriptor = `[Unit]\nDescription=NowWork storage migration ${migrationId}\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=exec\nExecStart=${worker.map(systemdArg).join(" ")}\nRestart=on-abnormal\nRestartSec=5\n\n[Install]\nWantedBy=default.target\n`;
@@ -97,9 +124,16 @@ export async function launchStorageMigrationWorker(input, runSupervisor = system
97
124
  }
98
125
  export async function completeStorageMigrationWorkerService(input, runSupervisor = systemSupervisorRun) {
99
126
  const migrationId = z.string().uuid().parse(input.migrationId).toLowerCase();
100
- if (input.platform !== "linux")
101
- return;
102
127
  AbsolutePathSchema.parse(input.userHome);
128
+ if (input.platform === "darwin") {
129
+ if (input.uid === undefined || !Number.isSafeInteger(input.uid) || input.uid < 0) {
130
+ throw new Error("Persistent storage migration launchd worker requires a numeric uid");
131
+ }
132
+ const label = workerLaunchdLabel(migrationId);
133
+ await rm(workerLaunchdPath(input.userHome, migrationId), { force: true });
134
+ await runSupervisor("launchctl", ["bootout", `gui/${input.uid}/${label}`]);
135
+ return;
136
+ }
103
137
  const unit = workerUnitName(migrationId);
104
138
  await checkedSupervisor(runSupervisor, "systemctl", ["--user", "disable", unit]);
105
139
  await rm(workerUnitPath(input.userHome, migrationId), { force: true });
@@ -112,5 +146,6 @@ export async function completeStorageMigrationWorkerServiceForHandoff(path) {
112
146
  migrationId: operation.migrationId,
113
147
  platform: operation.service.platform,
114
148
  userHome: operation.service.userHome,
149
+ ...(operation.service.uid === undefined ? {} : { uid: operation.service.uid }),
115
150
  });
116
151
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.57",
3
+ "version": "0.6.58",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",