@rubytech/taskmaster 1.44.2 → 1.44.3

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?v=2" />
9
- <script type="module" crossorigin src="./assets/index-QAV6uia0.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-Car9AOpb.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-CAu2PL0O.css">
11
11
  </head>
12
12
  <body>
@@ -197,7 +197,32 @@ export const channelsHandlers = {
197
197
  const accountsMap = payload.channelAccounts;
198
198
  const defaultAccountIdMap = payload.channelDefaultAccountId;
199
199
  for (const plugin of plugins) {
200
- const { accounts, defaultAccountId, defaultAccount, resolvedAccounts } = await buildChannelAccounts(plugin.id);
200
+ let didTimeout = false;
201
+ const pluginFallback = {
202
+ accounts: [],
203
+ defaultAccountId: DEFAULT_ACCOUNT_ID,
204
+ defaultAccount: undefined,
205
+ resolvedAccounts: {},
206
+ };
207
+ const buildPromise = buildChannelAccounts(plugin.id);
208
+ let timer = null;
209
+ const timeoutPromise = new Promise((resolve) => {
210
+ timer = setTimeout(() => {
211
+ didTimeout = true;
212
+ resolve(pluginFallback);
213
+ }, 10_000);
214
+ });
215
+ const { accounts, defaultAccountId, defaultAccount, resolvedAccounts } = await Promise.race([
216
+ buildPromise.then((result) => {
217
+ if (timer)
218
+ clearTimeout(timer);
219
+ return result;
220
+ }),
221
+ timeoutPromise,
222
+ ]);
223
+ if (didTimeout) {
224
+ context.logGateway.warn(`[${plugin.id}] channels.status timed out after 10s`);
225
+ }
201
226
  const fallbackAccount = resolvedAccounts[defaultAccountId] ?? plugin.config.resolveAccount(cfg, defaultAccountId);
202
227
  const summary = plugin.status?.buildChannelSummary
203
228
  ? await plugin.status.buildChannelSummary({
@@ -6,6 +6,7 @@ import { CONFIG_PATH_TASKMASTER, loadConfig, readConfigFileSnapshot, validateCon
6
6
  import { applyMergePatch } from "../../config/merge-patch.js";
7
7
  import { findTailscaleBinary, getTailnetHostname, readTailscaleStatusJson, } from "../../infra/tailscale.js";
8
8
  import { runExec } from "../../process/exec.js";
9
+ import { withTimeout as withTimeoutThrow } from "../../infra/archive.js";
9
10
  import { scheduleGatewaySigusr1Restart } from "../../infra/restart.js";
10
11
  import { formatDoctorNonInteractiveHint, writeRestartSentinel, } from "../../infra/restart-sentinel.js";
11
12
  import { ErrorCodes, errorShape } from "../protocol/index.js";
@@ -31,21 +32,21 @@ export const tailscaleHandlers = {
31
32
  let running = false;
32
33
  let loggedIn = false;
33
34
  try {
34
- const status = await readTailscaleStatusJson();
35
+ const status = await withTimeoutThrow(readTailscaleStatusJson(), 5_000, "tailscale status");
35
36
  running = true;
36
37
  // BackendState "Running" means logged in and connected to the tailnet
37
38
  loggedIn = status.BackendState === "Running";
38
39
  }
39
40
  catch {
40
- // Daemon not running or not logged in
41
+ // Daemon not running, not logged in, or timed out
41
42
  }
42
43
  let hostname = null;
43
44
  if (loggedIn) {
44
45
  try {
45
- hostname = await getTailnetHostname(runExec, binary);
46
+ hostname = await withTimeoutThrow(getTailnetHostname(runExec, binary), 5_000, "tailscale hostname");
46
47
  }
47
48
  catch {
48
- // Failed to resolve hostname
49
+ // Failed to resolve hostname or timed out
49
50
  }
50
51
  }
51
52
  const cfg = loadConfig();
@@ -6,6 +6,7 @@ import { loadConfig, readConfigFileSnapshot, validateConfigObjectWithPlugins, wr
6
6
  import { applyMergePatch } from "../../config/merge-patch.js";
7
7
  import { ErrorCodes, errorShape } from "../protocol/index.js";
8
8
  import { isCloudflaredInstalled, isCloudflaredAuthenticated, getCloudflaredVersion, getInstallInstructions, installCloudflared, startCloudflaredLogin, createTunnel, routeTunnelDns, listTunnels, getAuthorizedZoneName, } from "../../infra/cloudflared.js";
9
+ import { withTimeout as withTimeoutThrow } from "../../infra/archive.js";
9
10
  import { getTunnelStatus, enableTunnel, disableTunnel } from "../server-tunnel.js";
10
11
  export const tunnelHandlers = {
11
12
  /**
@@ -13,10 +14,10 @@ export const tunnelHandlers = {
13
14
  */
14
15
  "tunnel.status": async ({ respond, context }) => {
15
16
  try {
16
- const installed = await isCloudflaredInstalled();
17
- const version = installed ? await getCloudflaredVersion() : null;
18
- const authenticated = installed ? await isCloudflaredAuthenticated() : false;
19
- const authorizedDomain = authenticated ? await getAuthorizedZoneName() : null;
17
+ const installed = await withTimeoutThrow(isCloudflaredInstalled(), 5_000, "cloudflared install check").catch(() => false);
18
+ const version = installed ? await withTimeoutThrow(getCloudflaredVersion(), 5_000, "cloudflared version").catch(() => null) : null;
19
+ const authenticated = installed ? await withTimeoutThrow(isCloudflaredAuthenticated(), 5_000, "cloudflared auth check").catch(() => false) : false;
20
+ const authorizedDomain = authenticated ? await withTimeoutThrow(getAuthorizedZoneName(), 5_000, "cloudflared zone name").catch(() => null) : null;
20
21
  const processStatus = getTunnelStatus();
21
22
  const cfg = loadConfig();
22
23
  const tunnelCfg = cfg.gateway?.tunnel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.44.2",
3
+ "version": "1.44.3",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"