@rubytech/taskmaster 1.0.53 → 1.0.55

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.
@@ -6,7 +6,7 @@
6
6
  <title>Taskmaster Control</title>
7
7
  <meta name="color-scheme" content="dark light" />
8
8
  <link rel="icon" type="image/png" href="./favicon.png" />
9
- <script type="module" crossorigin src="./assets/index-BY1YsAT8.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-DC6oJyqi.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-Cgt8wQ9f.css">
11
11
  </head>
12
12
  <body>
@@ -140,6 +140,9 @@ export const updateHandlers = {
140
140
  const ok = step.exitCode === 0 || step.exitCode === null;
141
141
  const logFn = ok ? log.info.bind(log) : log.error.bind(log);
142
142
  logFn(`update step ${step.index + 1}/${step.total}: ${step.name} ${ok ? "ok" : `FAILED (exit ${step.exitCode})`} (${step.durationMs}ms)`);
143
+ if (!ok && step.stderrTail) {
144
+ log.error(`update step ${step.name} stderr:\n${step.stderrTail}`);
145
+ }
143
146
  context.broadcast("update.progress", {
144
147
  phase: "step-done",
145
148
  name: step.name,
@@ -147,6 +150,7 @@ export const updateHandlers = {
147
150
  total: step.total,
148
151
  durationMs: step.durationMs,
149
152
  ok,
153
+ ...(ok ? {} : { error: step.stderrTail ?? null }),
150
154
  });
151
155
  },
152
156
  };
@@ -76,10 +76,11 @@ export async function detectGlobalInstallManagerByPresence(runCommand, timeoutMs
76
76
  return "bun";
77
77
  return null;
78
78
  }
79
- export function globalInstallArgs(manager, spec) {
79
+ export function globalInstallArgs(manager, spec, needsSudo = false) {
80
+ const prefix = needsSudo ? ["sudo"] : [];
80
81
  if (manager === "pnpm")
81
- return ["pnpm", "add", "-g", spec];
82
+ return [...prefix, "pnpm", "add", "-g", spec];
82
83
  if (manager === "bun")
83
- return ["bun", "add", "-g", spec];
84
- return ["npm", "i", "-g", spec];
84
+ return [...prefix, "bun", "add", "-g", spec];
85
+ return [...prefix, "npm", "i", "-g", spec];
85
86
  }
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { runCommandWithTimeout } from "../process/exec.js";
5
5
  import { compareSemverStrings } from "./update-check.js";
6
6
  import { DEV_BRANCH, isBetaTag, isStableTag } from "./update-channels.js";
7
- import { detectGlobalInstallManagerForRoot, globalInstallArgs } from "./update-global.js";
7
+ import { detectGlobalInstallManagerForRoot, globalInstallArgs, resolveGlobalRoot, } from "./update-global.js";
8
8
  import { trimLogTail } from "./restart-sentinel.js";
9
9
  const DEFAULT_TIMEOUT_MS = 20 * 60_000;
10
10
  const MAX_LOG_CHARS = 8000;
@@ -439,11 +439,24 @@ export async function runGatewayUpdate(opts = {}) {
439
439
  const beforeVersion = await readPackageVersion(pkgRoot);
440
440
  const globalManager = await detectGlobalInstallManagerForRoot(runCommand, pkgRoot, timeoutMs);
441
441
  if (globalManager) {
442
+ // Check if the global prefix is writable — if not, use sudo (common on Linux/Pi)
443
+ let needsSudo = false;
444
+ if (os.platform() !== "win32") {
445
+ const globalRoot = await resolveGlobalRoot(globalManager, runCommand, timeoutMs);
446
+ if (globalRoot) {
447
+ try {
448
+ await fs.access(globalRoot, fs.constants.W_OK);
449
+ }
450
+ catch {
451
+ needsSudo = true;
452
+ }
453
+ }
454
+ }
442
455
  const spec = `@rubytech/taskmaster@${normalizeTag(opts.tag)}`;
443
456
  const updateStep = await runStep({
444
457
  runCommand,
445
458
  name: "global update",
446
- argv: globalInstallArgs(globalManager, spec),
459
+ argv: globalInstallArgs(globalManager, spec, needsSudo),
447
460
  cwd: pkgRoot,
448
461
  timeoutMs,
449
462
  env: { PATH: augmentedPath },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.0.53",
3
+ "version": "1.0.55",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"