@lifeaitools/clauth 1.30.16 → 1.30.17
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.
|
@@ -494,20 +494,33 @@ export function runSurfaceAction(id, action, actor = "localhost") {
|
|
|
494
494
|
if (!command || command.length === 0) {
|
|
495
495
|
return operation(action, { surface_id: id }, surface, { ok: false, state: "command_missing" }, actor);
|
|
496
496
|
}
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
497
|
+
const execute = (selectedCommand) => {
|
|
498
|
+
const [cmd, ...args] = selectedCommand;
|
|
499
|
+
return spawnSync(cmd, args, {
|
|
500
|
+
cwd: surface.cwd || undefined,
|
|
501
|
+
env: { ...process.env, CLAUTH_PM2_HOME: getClauthPm2Home(), PM2_HOME: getClauthPm2Home() },
|
|
502
|
+
windowsHide: true,
|
|
503
|
+
encoding: "utf8",
|
|
504
|
+
timeout: Number(surface.timeoutMs || 30000),
|
|
505
|
+
});
|
|
506
|
+
};
|
|
507
|
+
let result = execute(command);
|
|
508
|
+
let fallbackUsed = false;
|
|
509
|
+
// PM2 restart returns non-zero when the process was deleted. Reconcile is
|
|
510
|
+
// allowed to fall back to the declared start command; explicit restart keeps
|
|
511
|
+
// its strict failure semantics for operator-requested actions.
|
|
512
|
+
if (action === "reconcile" && result.status !== 0 && Array.isArray(surface.start) && surface.start.length > 0 && command !== surface.start) {
|
|
513
|
+
const restartStatus = result.status;
|
|
514
|
+
result = execute(surface.start);
|
|
515
|
+
fallbackUsed = true;
|
|
516
|
+
result.stderr = `restart exited ${restartStatus}; start fallback attempted\n${result.stderr || ""}`;
|
|
517
|
+
}
|
|
505
518
|
return operation(action, { surface_id: id }, surface, {
|
|
506
519
|
ok: result.status === 0,
|
|
507
520
|
state: result.status === 0 ? "operation_completed" : "operation_failed",
|
|
508
521
|
status: result.status,
|
|
509
522
|
stderr: result.stderr?.slice(0, 2000),
|
|
510
|
-
evidence: [`CLAUTH_PM2_HOME=${getClauthPm2Home()}
|
|
523
|
+
evidence: [`CLAUTH_PM2_HOME=${getClauthPm2Home()}`, ...(fallbackUsed ? ["reconcile_start_fallback=true"] : [])],
|
|
511
524
|
}, actor);
|
|
512
525
|
}
|
|
513
526
|
|
|
@@ -174,6 +174,29 @@ test("surface actions use dedicated clauth PM2 home and keep CodeFlow observe-on
|
|
|
174
174
|
assert.equal(supervisorHealth().surfaces, 2);
|
|
175
175
|
}));
|
|
176
176
|
|
|
177
|
+
test("reconcile falls back to the declared start command when restart reports a missing process", () => withTempSupervisor((root) => {
|
|
178
|
+
const managed = path.join(root, "managed");
|
|
179
|
+
process.env.CLAUTH_MANAGED_PLUGIN_ROOTS = managed;
|
|
180
|
+
process.env.CLAUTH_USER_PLUGIN_ROOTS = path.join(root, "user");
|
|
181
|
+
writePlugin(root, "managed", "fallback-demo", baseManifest("fallback-demo", {
|
|
182
|
+
core: true,
|
|
183
|
+
enable_default: true,
|
|
184
|
+
surfaces: [{
|
|
185
|
+
id: "primary",
|
|
186
|
+
destination: "local/clauth/pm2",
|
|
187
|
+
lifecycle_owner: "clauth",
|
|
188
|
+
port: 39114,
|
|
189
|
+
health: "/health",
|
|
190
|
+
start: [process.execPath, "--version"],
|
|
191
|
+
restart: [process.execPath, "-e", "process.exit(1)"],
|
|
192
|
+
}],
|
|
193
|
+
}));
|
|
194
|
+
discoverPlugins();
|
|
195
|
+
const receipt = runSurfaceAction("fallback-demo:primary", "reconcile");
|
|
196
|
+
assert.equal(receipt.resulting_state.ok, true);
|
|
197
|
+
assert.equal(receipt.resulting_state.evidence.includes("reconcile_start_fallback=true"), true);
|
|
198
|
+
}));
|
|
199
|
+
|
|
177
200
|
test("surface promote and rollback never fall through to restart commands", () => withTempSupervisor((root) => {
|
|
178
201
|
const managed = path.join(root, "managed");
|
|
179
202
|
process.env.CLAUTH_MANAGED_PLUGIN_ROOTS = managed;
|