@rubytech/taskmaster 1.22.0 → 1.22.1

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.22.0",
3
- "commit": "9d1f55fc9452c09c88a79e294df7c30387fdbd3f",
4
- "builtAt": "2026-03-07T05:55:37.155Z"
2
+ "version": "1.22.1",
3
+ "commit": "b35175198e3fe48ac4c26829a281478a72e0e622",
4
+ "builtAt": "2026-03-07T06:05:58.594Z"
5
5
  }
@@ -1,5 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
2
  import fs from "node:fs";
3
+ import os from "node:os";
3
4
  import path from "node:path";
4
5
  import { Logger as TsLogger } from "tslog";
5
6
  import { levelToMinLevel, normalizeLogLevel } from "./levels.js";
@@ -66,8 +67,34 @@ export function isFileLogLevelEnabled(level) {
66
67
  return false;
67
68
  return levelToMinLevel(level) <= levelToMinLevel(settings.level);
68
69
  }
70
+ function ensureWritableLogDir(dir) {
71
+ fs.mkdirSync(dir, { recursive: true });
72
+ try {
73
+ fs.accessSync(dir, fs.constants.W_OK);
74
+ return dir;
75
+ }
76
+ catch {
77
+ // Directory exists but is not writable (e.g. created by root, daemon runs as non-root).
78
+ // Try to fix permissions.
79
+ try {
80
+ fs.chmodSync(dir, 0o1777);
81
+ fs.accessSync(dir, fs.constants.W_OK);
82
+ return dir;
83
+ }
84
+ catch {
85
+ // chmod also failed — fall back to ~/.taskmaster/logs/
86
+ const fallback = path.join(os.homedir(), ".taskmaster", "logs");
87
+ fs.mkdirSync(fallback, { recursive: true });
88
+ process.stderr.write(`[taskmaster] log dir ${dir} is not writable, falling back to ${fallback}\n`);
89
+ return fallback;
90
+ }
91
+ }
92
+ }
69
93
  function buildLogger(settings) {
70
- fs.mkdirSync(path.dirname(settings.file), { recursive: true });
94
+ const logDir = ensureWritableLogDir(path.dirname(settings.file));
95
+ if (logDir !== path.dirname(settings.file)) {
96
+ settings = { ...settings, file: path.join(logDir, path.basename(settings.file)) };
97
+ }
71
98
  // Clean up stale rolling logs when using a dated log filename.
72
99
  if (isRollingPath(settings.file)) {
73
100
  pruneOldRollingLogs(path.dirname(settings.file));
@@ -81,9 +108,10 @@ function buildLogger(settings) {
81
108
  // rollover targets today's file — even for child loggers cached by
82
109
  // subsystem loggers that outlive a parent logger rebuild.
83
110
  const fixedFile = isRollingPath(settings.file) ? null : settings.file;
111
+ const resolvedLogDir = path.dirname(settings.file);
84
112
  logger.attachTransport((logObj) => {
85
113
  try {
86
- const file = fixedFile ?? defaultRollingPathForToday();
114
+ const file = fixedFile ?? rollingPathForToday(resolvedLogDir);
87
115
  const time = logObj.date?.toISOString?.() ?? new Date().toISOString();
88
116
  const line = JSON.stringify({ ...logObj, time });
89
117
  fs.appendFileSync(file, `${line}\n`, { encoding: "utf8" });
@@ -165,9 +193,12 @@ function formatLocalDate(date) {
165
193
  const day = String(date.getDate()).padStart(2, "0");
166
194
  return `${year}-${month}-${day}`;
167
195
  }
168
- function defaultRollingPathForToday() {
196
+ function rollingPathForToday(dir) {
169
197
  const today = formatLocalDate(new Date());
170
- return path.join(DEFAULT_LOG_DIR, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
198
+ return path.join(dir, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
199
+ }
200
+ function defaultRollingPathForToday() {
201
+ return rollingPathForToday(DEFAULT_LOG_DIR);
171
202
  }
172
203
  function isRollingPath(file) {
173
204
  const base = path.basename(file);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.22.0",
3
+ "version": "1.22.1",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"