@isarai/maestro 0.1.0 → 0.1.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.
package/dist/server.js CHANGED
@@ -461,7 +461,6 @@ function findCoveringSelfMount(requestedPath) {
461
461
  return best;
462
462
  }
463
463
  function getSharedAgentPaths(home) {
464
- const maestroDir = path.join(home, ".maestro");
465
464
  const codexDir = path.join(home, ".codex");
466
465
  const claudeDir = path.join(home, ".claude");
467
466
  const claudeProjectsDir = path.join(claudeDir, "projects");
@@ -469,11 +468,10 @@ function getSharedAgentPaths(home) {
469
468
  const gitconfig = path.join(home, ".gitconfig");
470
469
  const ghConfigDir = path.join(home, ".config", "gh");
471
470
  return {
472
- // Codex, Claude, and gh may all persist runtime/session state under their
473
- // home config paths when started inside a sandbox. Keep those writable so
474
- // the CLIs can boot and authenticate normally while leaving gitconfig
475
- // itself read-only.
476
- readwrite: [maestroDir, codexDir, claudeDir, claudeProjectsDir, claudeJson, ghConfigDir].filter(fs.existsSync),
471
+ // Keep only CLI/runtime config writable here. Maestro's own server state
472
+ // stays outside the generic sandbox mount set and terminal sandboxes use
473
+ // a dedicated isolated HOME under ~/.maestro/sandboxes/terminals/<id>.
474
+ readwrite: [codexDir, claudeDir, claudeProjectsDir, claudeJson, ghConfigDir].filter(fs.existsSync),
477
475
  readonly: [gitconfig].filter(fs.existsSync)
478
476
  };
479
477
  }
@@ -1191,27 +1189,76 @@ var init_terminal_replica = __esm({
1191
1189
  }
1192
1190
  });
1193
1191
 
1194
- // ../server/src/agents/worktree.ts
1192
+ // ../server/src/state/files.ts
1195
1193
  import * as fs4 from "fs";
1196
1194
  import * as os4 from "os";
1197
1195
  import * as path4 from "path";
1196
+ function ensureDataDir() {
1197
+ fs4.mkdirSync(MAESTRO_DATA_DIR, { recursive: true });
1198
+ return MAESTRO_DATA_DIR;
1199
+ }
1200
+ function ensureDir(dirPath) {
1201
+ fs4.mkdirSync(dirPath, { recursive: true });
1202
+ return dirPath;
1203
+ }
1204
+ function readJsonFile(filePath, fallback) {
1205
+ try {
1206
+ if (!fs4.existsSync(filePath)) {
1207
+ return fallback;
1208
+ }
1209
+ const raw = fs4.readFileSync(filePath, "utf-8");
1210
+ return JSON.parse(raw);
1211
+ } catch {
1212
+ return fallback;
1213
+ }
1214
+ }
1215
+ function writeJsonFile(filePath, value, options) {
1216
+ ensureDir(path4.dirname(filePath));
1217
+ const tempPath = `${filePath}.tmp`;
1218
+ fs4.writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}
1219
+ `, {
1220
+ mode: options?.mode
1221
+ });
1222
+ fs4.renameSync(tempPath, filePath);
1223
+ if (options?.mode != null) {
1224
+ fs4.chmodSync(filePath, options.mode);
1225
+ }
1226
+ }
1227
+ function nowIso() {
1228
+ return (/* @__PURE__ */ new Date()).toISOString();
1229
+ }
1230
+ var MAESTRO_DATA_DIR, MAESTRO_PROJECTS_DIR, MAESTRO_SANDBOXES_DIR, MAESTRO_SANDBOX_TERMINALS_DIR, MAESTRO_SANDBOX_WORKTREES_DIR;
1231
+ var init_files = __esm({
1232
+ "../server/src/state/files.ts"() {
1233
+ "use strict";
1234
+ MAESTRO_DATA_DIR = path4.join(os4.homedir(), ".maestro");
1235
+ MAESTRO_PROJECTS_DIR = path4.join(MAESTRO_DATA_DIR, "projects");
1236
+ MAESTRO_SANDBOXES_DIR = path4.join(MAESTRO_DATA_DIR, "sandboxes");
1237
+ MAESTRO_SANDBOX_TERMINALS_DIR = path4.join(MAESTRO_SANDBOXES_DIR, "terminals");
1238
+ MAESTRO_SANDBOX_WORKTREES_DIR = path4.join(MAESTRO_SANDBOXES_DIR, "worktrees");
1239
+ }
1240
+ });
1241
+
1242
+ // ../server/src/agents/worktree.ts
1243
+ import * as fs5 from "fs";
1244
+ import * as path5 from "path";
1198
1245
  import { execSync as execSync2 } from "child_process";
1199
1246
  function createTerminalWorktree(projectPath, terminalId, startPoint = "HEAD") {
1200
- const worktreeDir = path4.join(WORKTREE_BASE, terminalId);
1247
+ const worktreeDir = path5.join(WORKTREE_BASE, terminalId);
1201
1248
  const branchName = `agent/${terminalId}`;
1202
- fs4.mkdirSync(WORKTREE_BASE, { recursive: true });
1249
+ fs5.mkdirSync(WORKTREE_BASE, { recursive: true });
1203
1250
  try {
1204
1251
  execSync2("git worktree prune", { cwd: projectPath, stdio: "ignore" });
1205
1252
  } catch {
1206
1253
  }
1207
- if (fs4.existsSync(worktreeDir)) {
1254
+ if (fs5.existsSync(worktreeDir)) {
1208
1255
  try {
1209
1256
  execSync2(`git worktree remove --force ${JSON.stringify(worktreeDir)}`, {
1210
1257
  cwd: projectPath,
1211
1258
  stdio: "ignore"
1212
1259
  });
1213
1260
  } catch {
1214
- fs4.rmSync(worktreeDir, { recursive: true, force: true });
1261
+ fs5.rmSync(worktreeDir, { recursive: true, force: true });
1215
1262
  }
1216
1263
  }
1217
1264
  try {
@@ -1231,16 +1278,16 @@ function createTerminalWorktree(projectPath, terminalId, startPoint = "HEAD") {
1231
1278
  return worktreeDir;
1232
1279
  }
1233
1280
  function removeTerminalWorktree(projectPath, terminalId) {
1234
- const worktreeDir = path4.join(WORKTREE_BASE, terminalId);
1281
+ const worktreeDir = path5.join(WORKTREE_BASE, terminalId);
1235
1282
  const branchName = `agent/${terminalId}`;
1236
- if (fs4.existsSync(worktreeDir)) {
1283
+ if (fs5.existsSync(worktreeDir)) {
1237
1284
  try {
1238
1285
  execSync2(
1239
1286
  `git worktree remove --force ${JSON.stringify(worktreeDir)}`,
1240
1287
  { cwd: projectPath, stdio: "ignore" }
1241
1288
  );
1242
1289
  } catch {
1243
- fs4.rmSync(worktreeDir, { recursive: true, force: true });
1290
+ fs5.rmSync(worktreeDir, { recursive: true, force: true });
1244
1291
  }
1245
1292
  }
1246
1293
  try {
@@ -1271,82 +1318,82 @@ var DEFAULT_WORKTREE_BASE, WORKTREE_BASE;
1271
1318
  var init_worktree = __esm({
1272
1319
  "../server/src/agents/worktree.ts"() {
1273
1320
  "use strict";
1274
- DEFAULT_WORKTREE_BASE = path4.join(os4.homedir(), ".maestro", "worktrees");
1321
+ init_files();
1322
+ DEFAULT_WORKTREE_BASE = MAESTRO_SANDBOX_WORKTREES_DIR;
1275
1323
  WORKTREE_BASE = process.env.MAESTRO_WORKTREE_BASE?.trim() || DEFAULT_WORKTREE_BASE;
1276
1324
  }
1277
1325
  });
1278
1326
 
1279
1327
  // ../server/src/agents/terminal-isolation.ts
1280
- import * as fs5 from "fs";
1328
+ import * as fs6 from "fs";
1329
+ import * as path6 from "path";
1281
1330
  import * as os5 from "os";
1282
- import * as path5 from "path";
1283
1331
  function getGlobalHome() {
1284
1332
  return os5.homedir();
1285
1333
  }
1286
1334
  function getTerminalIsolationPaths(terminalId) {
1287
- const rootDir = path5.join(TERMINAL_STATE_BASE, terminalId);
1335
+ const rootDir = path6.join(TERMINAL_STATE_BASE, terminalId);
1288
1336
  return {
1289
1337
  rootDir,
1290
- homeDir: path5.join(rootDir, "home")
1338
+ homeDir: path6.join(rootDir, "home")
1291
1339
  };
1292
1340
  }
1293
1341
  function copyPathIfPresent(source, target) {
1294
- if (!fs5.existsSync(source) || fs5.existsSync(target)) {
1342
+ if (!fs6.existsSync(source) || fs6.existsSync(target)) {
1295
1343
  return;
1296
1344
  }
1297
- const stat = fs5.statSync(source);
1298
- fs5.mkdirSync(path5.dirname(target), { recursive: true });
1345
+ const stat = fs6.statSync(source);
1346
+ fs6.mkdirSync(path6.dirname(target), { recursive: true });
1299
1347
  if (stat.isDirectory()) {
1300
- fs5.cpSync(source, target, {
1348
+ fs6.cpSync(source, target, {
1301
1349
  recursive: true,
1302
1350
  errorOnExist: false
1303
1351
  });
1304
1352
  return;
1305
1353
  }
1306
- fs5.copyFileSync(source, target);
1354
+ fs6.copyFileSync(source, target);
1307
1355
  }
1308
1356
  function bootstrapTerminalHome(homeDir) {
1309
- const markerPath = path5.join(homeDir, BOOTSTRAP_MARKER);
1310
- if (fs5.existsSync(markerPath)) {
1357
+ const markerPath = path6.join(homeDir, BOOTSTRAP_MARKER);
1358
+ if (fs6.existsSync(markerPath)) {
1311
1359
  return;
1312
1360
  }
1313
1361
  const globalHome = getGlobalHome();
1314
1362
  const copies = [
1315
- [path5.join(globalHome, ".gitconfig"), path5.join(homeDir, ".gitconfig")],
1316
- [path5.join(globalHome, ".claude.json"), path5.join(homeDir, ".claude.json")],
1317
- [path5.join(globalHome, ".config", "gh"), path5.join(homeDir, ".config", "gh")],
1318
- [path5.join(globalHome, ".claude"), path5.join(homeDir, ".claude")],
1319
- [path5.join(globalHome, ".codex"), path5.join(homeDir, ".codex")]
1363
+ [path6.join(globalHome, ".gitconfig"), path6.join(homeDir, ".gitconfig")],
1364
+ [path6.join(globalHome, ".claude.json"), path6.join(homeDir, ".claude.json")],
1365
+ [path6.join(globalHome, ".config", "gh"), path6.join(homeDir, ".config", "gh")],
1366
+ [path6.join(globalHome, ".claude"), path6.join(homeDir, ".claude")],
1367
+ [path6.join(globalHome, ".codex"), path6.join(homeDir, ".codex")]
1320
1368
  ];
1321
1369
  for (const [source, target] of copies) {
1322
1370
  copyPathIfPresent(source, target);
1323
1371
  }
1324
- fs5.writeFileSync(path5.join(homeDir, ".bash_history"), "", { flag: "a" });
1325
- fs5.writeFileSync(markerPath, (/* @__PURE__ */ new Date()).toISOString());
1372
+ fs6.writeFileSync(path6.join(homeDir, ".bash_history"), "", { flag: "a" });
1373
+ fs6.writeFileSync(markerPath, (/* @__PURE__ */ new Date()).toISOString());
1326
1374
  }
1327
1375
  function ensureTerminalIsolationHome(terminalId) {
1328
1376
  const paths = getTerminalIsolationPaths(terminalId);
1329
- fs5.mkdirSync(paths.homeDir, { recursive: true });
1377
+ fs6.mkdirSync(paths.homeDir, { recursive: true });
1330
1378
  bootstrapTerminalHome(paths.homeDir);
1331
1379
  return paths;
1332
1380
  }
1333
1381
  function removeTerminalIsolationState(terminalId) {
1334
1382
  const paths = getTerminalIsolationPaths(terminalId);
1335
- fs5.rmSync(paths.rootDir, { recursive: true, force: true });
1383
+ fs6.rmSync(paths.rootDir, { recursive: true, force: true });
1336
1384
  }
1337
1385
  var DEFAULT_TERMINAL_STATE_BASE, TERMINAL_STATE_BASE, BOOTSTRAP_MARKER;
1338
1386
  var init_terminal_isolation = __esm({
1339
1387
  "../server/src/agents/terminal-isolation.ts"() {
1340
1388
  "use strict";
1341
- DEFAULT_TERMINAL_STATE_BASE = path5.join(os5.homedir(), ".maestro", "terminals");
1389
+ init_files();
1390
+ DEFAULT_TERMINAL_STATE_BASE = MAESTRO_SANDBOX_TERMINALS_DIR;
1342
1391
  TERMINAL_STATE_BASE = process.env.MAESTRO_TERMINAL_STATE_BASE?.trim() || DEFAULT_TERMINAL_STATE_BASE;
1343
1392
  BOOTSTRAP_MARKER = ".bootstrap-complete";
1344
1393
  }
1345
1394
  });
1346
1395
 
1347
1396
  // ../server/src/agents/dind.ts
1348
- import * as os6 from "os";
1349
- import * as path6 from "path";
1350
1397
  import { execFileSync as execFileSync2 } from "child_process";
1351
1398
  function getTerminalDockerResourceSuffix(terminalId) {
1352
1399
  return terminalId.toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
@@ -1369,8 +1416,8 @@ function getTerminalDockerRuntime(terminalId) {
1369
1416
  }
1370
1417
  function getSharedTerminalRuntimeMounts() {
1371
1418
  const requestedPaths = [
1372
- path6.join(os6.homedir(), ".maestro"),
1373
- path6.join(os6.homedir(), "maestro-projects")
1419
+ MAESTRO_SANDBOXES_DIR,
1420
+ MAESTRO_PROJECTS_DIR
1374
1421
  ];
1375
1422
  return requestedPaths.flatMap((requestedPath) => {
1376
1423
  const mount = resolveDockerMountForPath(requestedPath, false);
@@ -1496,6 +1543,7 @@ var DEFAULT_DIND_IMAGE, DEFAULT_DIND_READY_TIMEOUT_MS, DIND_SOCKET_DIR, DIND_SOC
1496
1543
  var init_dind = __esm({
1497
1544
  "../server/src/agents/dind.ts"() {
1498
1545
  "use strict";
1546
+ init_files();
1499
1547
  init_sandbox();
1500
1548
  DEFAULT_DIND_IMAGE = process.env.MAESTRO_DIND_IMAGE || "docker:29-dind";
1501
1549
  DEFAULT_DIND_READY_TIMEOUT_MS = Number(
@@ -1507,8 +1555,8 @@ var init_dind = __esm({
1507
1555
  });
1508
1556
 
1509
1557
  // ../server/src/integrations/cli-auth.ts
1510
- import * as fs6 from "node:fs";
1511
- import * as os7 from "node:os";
1558
+ import * as fs7 from "node:fs";
1559
+ import * as os6 from "node:os";
1512
1560
  import * as path7 from "node:path";
1513
1561
  import { execFileSync as execFileSync3 } from "node:child_process";
1514
1562
  import * as pty2 from "node-pty";
@@ -1518,7 +1566,7 @@ function stripAnsi(text) {
1518
1566
  function getCredentialHomes() {
1519
1567
  const candidates = [
1520
1568
  process.env.HOME,
1521
- os7.homedir(),
1569
+ os6.homedir(),
1522
1570
  "/root",
1523
1571
  "/home/sandbox"
1524
1572
  ];
@@ -1570,13 +1618,13 @@ function getClaudeAuthStatusFromCredentials() {
1570
1618
  let bestExpiresAt = -Infinity;
1571
1619
  for (const home of getClaudeCredentialHomes()) {
1572
1620
  const credentialsPath = path7.join(home, ".claude", ".credentials.json");
1573
- if (!fs6.existsSync(credentialsPath)) {
1621
+ if (!fs7.existsSync(credentialsPath)) {
1574
1622
  logClaudeAuth(`credentials file not found at ${credentialsPath}`);
1575
1623
  continue;
1576
1624
  }
1577
1625
  logClaudeAuth(`found credentials file at ${credentialsPath}`);
1578
1626
  try {
1579
- const raw = fs6.readFileSync(credentialsPath, "utf8");
1627
+ const raw = fs7.readFileSync(credentialsPath, "utf8");
1580
1628
  const data = JSON.parse(raw);
1581
1629
  const oauth = data.claudeAiOauth;
1582
1630
  if (!oauth?.accessToken) {
@@ -1684,9 +1732,9 @@ function getCodexAuthStatusFromFile() {
1684
1732
  let bestScore = -Infinity;
1685
1733
  for (const home of getCredentialHomes()) {
1686
1734
  const authPath = path7.join(home, ".codex", "auth.json");
1687
- if (!fs6.existsSync(authPath)) continue;
1735
+ if (!fs7.existsSync(authPath)) continue;
1688
1736
  try {
1689
- const raw = fs6.readFileSync(authPath, "utf8");
1737
+ const raw = fs7.readFileSync(authPath, "utf8");
1690
1738
  const data = JSON.parse(raw);
1691
1739
  const apiKey = data.OPENAI_API_KEY?.trim();
1692
1740
  const tokens = data.tokens;
@@ -1808,55 +1856,9 @@ var init_cli_auth = __esm({
1808
1856
  }
1809
1857
  });
1810
1858
 
1811
- // ../server/src/state/files.ts
1812
- import * as fs7 from "fs";
1813
- import * as os8 from "os";
1814
- import * as path8 from "path";
1815
- function ensureDataDir() {
1816
- fs7.mkdirSync(MAESTRO_DATA_DIR, { recursive: true });
1817
- return MAESTRO_DATA_DIR;
1818
- }
1819
- function ensureDir(dirPath) {
1820
- fs7.mkdirSync(dirPath, { recursive: true });
1821
- return dirPath;
1822
- }
1823
- function readJsonFile(filePath, fallback) {
1824
- try {
1825
- if (!fs7.existsSync(filePath)) {
1826
- return fallback;
1827
- }
1828
- const raw = fs7.readFileSync(filePath, "utf-8");
1829
- return JSON.parse(raw);
1830
- } catch {
1831
- return fallback;
1832
- }
1833
- }
1834
- function writeJsonFile(filePath, value, options) {
1835
- ensureDir(path8.dirname(filePath));
1836
- const tempPath = `${filePath}.tmp`;
1837
- fs7.writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}
1838
- `, {
1839
- mode: options?.mode
1840
- });
1841
- fs7.renameSync(tempPath, filePath);
1842
- if (options?.mode != null) {
1843
- fs7.chmodSync(filePath, options.mode);
1844
- }
1845
- }
1846
- function nowIso() {
1847
- return (/* @__PURE__ */ new Date()).toISOString();
1848
- }
1849
- var MAESTRO_DATA_DIR;
1850
- var init_files = __esm({
1851
- "../server/src/state/files.ts"() {
1852
- "use strict";
1853
- MAESTRO_DATA_DIR = path8.join(os8.homedir(), ".maestro");
1854
- }
1855
- });
1856
-
1857
1859
  // ../server/src/integrations/github.ts
1858
1860
  import * as fs8 from "fs";
1859
- import * as path9 from "path";
1861
+ import * as path8 from "path";
1860
1862
  import { execFileSync as execFileSync4 } from "node:child_process";
1861
1863
  function readStoredGitHubConnection() {
1862
1864
  const record = readJsonFile(
@@ -2048,7 +2050,7 @@ var init_github = __esm({
2048
2050
  "../server/src/integrations/github.ts"() {
2049
2051
  "use strict";
2050
2052
  init_files();
2051
- GITHUB_CONNECTION_PATH = path9.join(ensureDataDir(), "github-connection.json");
2053
+ GITHUB_CONNECTION_PATH = path8.join(ensureDataDir(), "github-connection.json");
2052
2054
  }
2053
2055
  });
2054
2056
 
@@ -2110,7 +2112,7 @@ var init_auth_status_checker = __esm({
2110
2112
  });
2111
2113
 
2112
2114
  // ../server/src/state/sqlite.ts
2113
- import * as path10 from "path";
2115
+ import * as path9 from "path";
2114
2116
  import { randomUUID } from "crypto";
2115
2117
  import { DatabaseSync } from "node:sqlite";
2116
2118
  function parseJson(value, fallback) {
@@ -2431,7 +2433,7 @@ var init_sqlite = __esm({
2431
2433
  "../server/src/state/sqlite.ts"() {
2432
2434
  "use strict";
2433
2435
  init_files();
2434
- dbPath = path10.join(ensureDataDir(), "state.sqlite");
2436
+ dbPath = path9.join(ensureDataDir(), "state.sqlite");
2435
2437
  db = new DatabaseSync(dbPath);
2436
2438
  db.exec(`
2437
2439
  CREATE TABLE IF NOT EXISTS scheduled_tasks (
@@ -2626,7 +2628,7 @@ var init_auto_spawn_provider = __esm({
2626
2628
 
2627
2629
  // ../server/src/state/terminals.ts
2628
2630
  import * as fs9 from "fs";
2629
- import * as path11 from "path";
2631
+ import * as path10 from "path";
2630
2632
  import { randomUUID as randomUUID2 } from "crypto";
2631
2633
  function readTerminals() {
2632
2634
  return readJsonFile(TERMINALS_PATH, []);
@@ -2635,13 +2637,13 @@ function writeTerminals(terminals) {
2635
2637
  writeJsonFile(TERMINALS_PATH, terminals);
2636
2638
  }
2637
2639
  function terminalDir(terminalId) {
2638
- return ensureDir(path11.join(TERMINAL_HISTORY_DIR, terminalId));
2640
+ return ensureDir(path10.join(TERMINAL_HISTORY_DIR, terminalId));
2639
2641
  }
2640
2642
  function terminalSnapshotPath(terminalId) {
2641
- return path11.join(terminalDir(terminalId), "snapshot.json");
2643
+ return path10.join(terminalDir(terminalId), "snapshot.json");
2642
2644
  }
2643
2645
  function syncTerminalMeta(terminal) {
2644
- writeJsonFile(path11.join(terminalDir(terminal.id), "meta.json"), terminal);
2646
+ writeJsonFile(path10.join(terminalDir(terminal.id), "meta.json"), terminal);
2645
2647
  }
2646
2648
  function listTerminalRecords() {
2647
2649
  return readTerminals().sort((a, b) => b.createdAt.localeCompare(a.createdAt));
@@ -2689,7 +2691,7 @@ function deleteTerminalState(terminalId) {
2689
2691
  fs9.rmSync(terminalDir(terminalId), { recursive: true, force: true });
2690
2692
  }
2691
2693
  async function appendTerminalHistoryBatch(terminalId, data) {
2692
- const historyPath = path11.join(terminalDir(terminalId), "transcript.log");
2694
+ const historyPath = path10.join(terminalDir(terminalId), "transcript.log");
2693
2695
  await fs9.promises.appendFile(historyPath, data);
2694
2696
  }
2695
2697
  function readTerminalSnapshot(terminalId) {
@@ -2714,7 +2716,7 @@ function trimPartialTerminalTail(content) {
2714
2716
  return content.slice(firstNewline + 1);
2715
2717
  }
2716
2718
  function readTerminalHistory(terminalId, maxBytes = 2 * 1024 * 1024) {
2717
- const historyPath = path11.join(terminalDir(terminalId), "transcript.log");
2719
+ const historyPath = path10.join(terminalDir(terminalId), "transcript.log");
2718
2720
  if (!fs9.existsSync(historyPath)) return "";
2719
2721
  const stat = fs9.statSync(historyPath);
2720
2722
  if (stat.size === 0) return "";
@@ -2732,13 +2734,13 @@ var init_terminals = __esm({
2732
2734
  "../server/src/state/terminals.ts"() {
2733
2735
  "use strict";
2734
2736
  init_files();
2735
- TERMINALS_PATH = path11.join(ensureDataDir(), "agents.json");
2736
- TERMINAL_HISTORY_DIR = path11.join(ensureDataDir(), "agents");
2737
+ TERMINALS_PATH = path10.join(ensureDataDir(), "agents.json");
2738
+ TERMINAL_HISTORY_DIR = path10.join(ensureDataDir(), "agents");
2737
2739
  }
2738
2740
  });
2739
2741
 
2740
2742
  // ../server/src/state/projects.ts
2741
- import * as path12 from "path";
2743
+ import * as path11 from "path";
2742
2744
  import { randomUUID as randomUUID3 } from "crypto";
2743
2745
  function readProjects() {
2744
2746
  return readJsonFile(PROJECTS_PATH, []);
@@ -2801,14 +2803,14 @@ var init_projects = __esm({
2801
2803
  "../server/src/state/projects.ts"() {
2802
2804
  "use strict";
2803
2805
  init_files();
2804
- PROJECTS_PATH = path12.join(ensureDataDir(), "projects.json");
2806
+ PROJECTS_PATH = path11.join(ensureDataDir(), "projects.json");
2805
2807
  }
2806
2808
  });
2807
2809
 
2808
2810
  // ../server/src/state/kanban.ts
2809
2811
  import { randomUUID as randomUUID4 } from "crypto";
2810
2812
  import { execFileSync as execFileSync5 } from "node:child_process";
2811
- import * as path13 from "path";
2813
+ import * as path12 from "path";
2812
2814
  function readOverlays() {
2813
2815
  return readJsonFile(TASK_OVERLAYS_PATH, {});
2814
2816
  }
@@ -3575,8 +3577,8 @@ var init_kanban = __esm({
3575
3577
  init_projects();
3576
3578
  init_github();
3577
3579
  init_terminals();
3578
- TASK_OVERLAYS_PATH = path13.join(ensureDataDir(), "kanban-overlays.json");
3579
- LOCAL_TASKS_PATH = path13.join(ensureDataDir(), "local-kanban-tasks.json");
3580
+ TASK_OVERLAYS_PATH = path12.join(ensureDataDir(), "kanban-overlays.json");
3581
+ LOCAL_TASKS_PATH = path12.join(ensureDataDir(), "local-kanban-tasks.json");
3580
3582
  STATUS_LABELS = {
3581
3583
  planned: "maestro:planned",
3582
3584
  ongoing: "maestro:ongoing",
@@ -3613,16 +3615,16 @@ function readCommandError(error, fallback) {
3613
3615
  }
3614
3616
  return error instanceof Error && error.message ? error.message : fallback;
3615
3617
  }
3616
- function runGit2(path20, args) {
3618
+ function runGit2(path19, args) {
3617
3619
  return execFileSync6("git", args, {
3618
- cwd: path20,
3620
+ cwd: path19,
3619
3621
  encoding: "utf8",
3620
3622
  stdio: ["ignore", "pipe", "pipe"]
3621
3623
  }).trim();
3622
3624
  }
3623
- function tryRunGit(path20, args) {
3625
+ function tryRunGit(path19, args) {
3624
3626
  try {
3625
- return { ok: true, output: runGit2(path20, args) };
3627
+ return { ok: true, output: runGit2(path19, args) };
3626
3628
  } catch (error) {
3627
3629
  return {
3628
3630
  ok: false,
@@ -3733,20 +3735,20 @@ function decideAutoWorktreeStartPoint(input) {
3733
3735
  reason: "Using local HEAD in a fresh worktree because no remote tracking branch was available."
3734
3736
  };
3735
3737
  }
3736
- function resolveUpstreamRef(path20, currentBranch) {
3737
- const upstream = tryRunGit(path20, ["rev-parse", "--abbrev-ref", "@{upstream}"]);
3738
+ function resolveUpstreamRef(path19, currentBranch) {
3739
+ const upstream = tryRunGit(path19, ["rev-parse", "--abbrev-ref", "@{upstream}"]);
3738
3740
  if (upstream.ok && upstream.output) {
3739
3741
  return upstream.output;
3740
3742
  }
3741
3743
  const originBranch = `refs/remotes/origin/${currentBranch}`;
3742
- const remoteBranch = tryRunGit(path20, ["show-ref", "--verify", "--quiet", originBranch]);
3744
+ const remoteBranch = tryRunGit(path19, ["show-ref", "--verify", "--quiet", originBranch]);
3743
3745
  if (remoteBranch.ok) {
3744
3746
  return `origin/${currentBranch}`;
3745
3747
  }
3746
3748
  return null;
3747
3749
  }
3748
- function hasGitRef(path20, ref) {
3749
- return tryRunGit(path20, ["show-ref", "--verify", "--quiet", ref]).ok;
3750
+ function hasGitRef(path19, ref) {
3751
+ return tryRunGit(path19, ["show-ref", "--verify", "--quiet", ref]).ok;
3750
3752
  }
3751
3753
  async function resolveAutoWorktreeStartPoint(input) {
3752
3754
  const project = resolveProjectRecord(input);
@@ -5180,8 +5182,8 @@ async function registerTerminalRoutes(app) {
5180
5182
  init_terminal_manager();
5181
5183
  init_github();
5182
5184
  import * as fs12 from "fs";
5183
- import * as os9 from "os";
5184
- import * as path14 from "path";
5185
+ import * as os7 from "os";
5186
+ import * as path13 from "path";
5185
5187
  import { execFileSync as execFileSync7 } from "node:child_process";
5186
5188
 
5187
5189
  // ../server/src/scheduler/scheduler.ts
@@ -5270,7 +5272,9 @@ init_terminals();
5270
5272
  init_kanban();
5271
5273
  init_projects();
5272
5274
  init_sqlite();
5273
- var MANAGED_PROJECTS_DIR = path14.join(os9.homedir(), "maestro-projects");
5275
+ init_files();
5276
+ var LEGACY_MANAGED_PROJECTS_DIR = path13.join(os7.homedir(), "maestro-projects");
5277
+ var MANAGED_PROJECTS_DIR = MAESTRO_PROJECTS_DIR;
5274
5278
  function slugify(input) {
5275
5279
  return input.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "project";
5276
5280
  }
@@ -5317,11 +5321,26 @@ function getUniqueSlug(name) {
5317
5321
  }
5318
5322
  return slug;
5319
5323
  }
5324
+ function ensureManagedProjectsDir() {
5325
+ if (fs12.existsSync(MANAGED_PROJECTS_DIR)) {
5326
+ return MANAGED_PROJECTS_DIR;
5327
+ }
5328
+ if (fs12.existsSync(LEGACY_MANAGED_PROJECTS_DIR)) {
5329
+ fs12.mkdirSync(path13.dirname(MANAGED_PROJECTS_DIR), { recursive: true });
5330
+ fs12.renameSync(LEGACY_MANAGED_PROJECTS_DIR, MANAGED_PROJECTS_DIR);
5331
+ console.log(
5332
+ `Migrated managed projects directory from ${LEGACY_MANAGED_PROJECTS_DIR} to ${MANAGED_PROJECTS_DIR}`
5333
+ );
5334
+ return MANAGED_PROJECTS_DIR;
5335
+ }
5336
+ fs12.mkdirSync(MANAGED_PROJECTS_DIR, { recursive: true });
5337
+ return MANAGED_PROJECTS_DIR;
5338
+ }
5320
5339
  function deriveLocalPath(localPath, name) {
5321
5340
  if (localPath?.trim()) {
5322
- return path14.resolve(localPath.trim());
5341
+ return path13.resolve(localPath.trim());
5323
5342
  }
5324
- return path14.join(MANAGED_PROJECTS_DIR, slugify(name));
5343
+ return path13.join(ensureManagedProjectsDir(), slugify(name));
5325
5344
  }
5326
5345
  function runGitCommand(args) {
5327
5346
  try {
@@ -5354,7 +5373,7 @@ function cloneRepository(repo, localPath, defaultBranch) {
5354
5373
  if (!repo.repoUrl) {
5355
5374
  return;
5356
5375
  }
5357
- const parentDir = path14.dirname(localPath);
5376
+ const parentDir = path13.dirname(localPath);
5358
5377
  fs12.mkdirSync(parentDir, { recursive: true });
5359
5378
  ensureProjectPathAvailable(localPath);
5360
5379
  const branch = defaultBranch?.trim();
@@ -5650,17 +5669,17 @@ init_terminal_manager();
5650
5669
 
5651
5670
  // ../server/src/setup/setup-manager.ts
5652
5671
  import * as fs13 from "fs";
5653
- import * as path15 from "path";
5654
- import * as os10 from "os";
5672
+ import * as path14 from "path";
5673
+ import * as os8 from "os";
5655
5674
  import * as pty3 from "node-pty";
5656
- var FLAG_DIR = path15.join(os10.homedir(), ".maestro");
5657
- var FLAG_FILE = path15.join(FLAG_DIR, "setup-complete");
5675
+ var FLAG_DIR = path14.join(os8.homedir(), ".maestro");
5676
+ var FLAG_FILE = path14.join(FLAG_DIR, "setup-complete");
5658
5677
  var SENTINEL = "__MAESTRO_SETUP_DONE__";
5659
5678
  var URL_RE = /https?:\/\/[^\s"'<>]+/g;
5660
5679
  var ANSI_RE2 = /\x1b(?:\][^\x07\x1b]*(?:\x07|\x1b\\)?|\[[0-9;]*[A-Za-z])/g;
5661
5680
  var STEP_BOUNDARY_RE = /(?:Running:|Checking|Do you want|Enter|Paste|Token)/i;
5662
5681
  var INSTALL_ROOT = process.env.MAESTRO_INSTALL_ROOT?.trim();
5663
- var SCRIPT_PATH = INSTALL_ROOT ? path15.resolve(INSTALL_ROOT, "assets/setup.sh") : path15.resolve(
5682
+ var SCRIPT_PATH = INSTALL_ROOT ? path14.resolve(INSTALL_ROOT, "assets/setup.sh") : path14.resolve(
5664
5683
  import.meta.dirname ?? __dirname,
5665
5684
  "../../scripts/setup.sh"
5666
5685
  );
@@ -5701,7 +5720,7 @@ function startSetupPty(io3, cols, rows) {
5701
5720
  name: "xterm-256color",
5702
5721
  cols: cols ?? 120,
5703
5722
  rows: rows ?? 30,
5704
- cwd: os10.homedir(),
5723
+ cwd: os8.homedir(),
5705
5724
  env: process.env
5706
5725
  });
5707
5726
  console.log(`[setup] PTY spawned, pid: ${activePty.pid}`);
@@ -6424,19 +6443,17 @@ function renderTemplate(template, item) {
6424
6443
  }
6425
6444
 
6426
6445
  // ../server/src/auth/auth.ts
6446
+ init_files();
6427
6447
  import * as crypto2 from "crypto";
6428
6448
  import * as fs14 from "fs";
6429
- import * as os11 from "os";
6430
- import * as path16 from "path";
6449
+ import * as path15 from "path";
6431
6450
  import jwt from "jsonwebtoken";
6432
- var MAESTRO_DIR = path16.join(os11.homedir(), ".maestro");
6433
- var SECRET_PATH = path16.join(MAESTRO_DIR, "jwt-secret");
6434
- var TOKEN_PATH = path16.join(MAESTRO_DIR, "api-token");
6451
+ var MAESTRO_DIR = MAESTRO_DATA_DIR;
6452
+ var SECRET_PATH = path15.join(MAESTRO_DIR, "jwt-secret");
6453
+ var TOKEN_PATH = path15.join(MAESTRO_DIR, "api-token");
6435
6454
  var jwtSecret;
6436
6455
  function initAuth() {
6437
- if (!fs14.existsSync(MAESTRO_DIR)) {
6438
- fs14.mkdirSync(MAESTRO_DIR, { recursive: true });
6439
- }
6456
+ ensureDataDir();
6440
6457
  if (fs14.existsSync(SECRET_PATH)) {
6441
6458
  jwtSecret = fs14.readFileSync(SECRET_PATH, "utf-8").trim();
6442
6459
  } else {
@@ -6928,11 +6945,11 @@ function stopAutoUpdater() {
6928
6945
  }
6929
6946
 
6930
6947
  // ../server/src/services/ollama.ts
6931
- import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5, readFileSync as readFileSync6, existsSync as existsSync15 } from "node:fs";
6932
- import { join as join17 } from "node:path";
6933
- import { homedir as homedir12 } from "node:os";
6948
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync5, readFileSync as readFileSync6, existsSync as existsSync15 } from "node:fs";
6949
+ import { join as join16 } from "node:path";
6950
+ import { homedir as homedir9 } from "node:os";
6934
6951
  var OLLAMA_HOST = process.env.OLLAMA_HOST || "http://localhost:11434";
6935
- var PI_MODELS_PATH = join17(homedir12(), ".pi", "agent", "models.json");
6952
+ var PI_MODELS_PATH = join16(homedir9(), ".pi", "agent", "models.json");
6936
6953
  async function getOllamaStatus() {
6937
6954
  try {
6938
6955
  const res = await fetch(`${OLLAMA_HOST}/api/version`);
@@ -7022,8 +7039,8 @@ async function pullOllamaModel(modelName) {
7022
7039
  }
7023
7040
  }
7024
7041
  function writePiModelsConfig(modelId) {
7025
- const dir = join17(homedir12(), ".pi", "agent");
7026
- mkdirSync7(dir, { recursive: true });
7042
+ const dir = join16(homedir9(), ".pi", "agent");
7043
+ mkdirSync6(dir, { recursive: true });
7027
7044
  let existing = {};
7028
7045
  if (existsSync15(PI_MODELS_PATH)) {
7029
7046
  try {
@@ -7111,12 +7128,12 @@ function getDisabledStatus(message) {
7111
7128
  latestRelease: null
7112
7129
  };
7113
7130
  }
7114
- async function requestUpdater(path20, init) {
7131
+ async function requestUpdater(path19, init) {
7115
7132
  const config = getUpdaterConfig();
7116
7133
  if (!config) {
7117
7134
  throw new Error("Deployment updater is not configured");
7118
7135
  }
7119
- const res = await fetch(`${config.url}${path20}`, {
7136
+ const res = await fetch(`${config.url}${path19}`, {
7120
7137
  ...init,
7121
7138
  headers: {
7122
7139
  ...config.token ? { Authorization: `Bearer ${config.token}` } : {},
@@ -7271,8 +7288,8 @@ You are a friendly, conversational AI assistant. You communicate via messaging (
7271
7288
  }
7272
7289
 
7273
7290
  // ../pi/src/channels/whatsapp/whatsapp.ts
7274
- import * as os12 from "os";
7275
- import * as path17 from "path";
7291
+ import * as os9 from "os";
7292
+ import * as path16 from "path";
7276
7293
  import makeWASocket, {
7277
7294
  useMultiFileAuthState,
7278
7295
  DisconnectReason,
@@ -7280,8 +7297,8 @@ import makeWASocket, {
7280
7297
  makeCacheableSignalKeyStore
7281
7298
  } from "@whiskeysockets/baileys";
7282
7299
  import * as QRCode from "qrcode";
7283
- var DATA_DIR = path17.join(os12.homedir(), ".maestro");
7284
- var AUTH_DIR = path17.join(DATA_DIR, "whatsapp-auth");
7300
+ var DATA_DIR = path16.join(os9.homedir(), ".maestro");
7301
+ var AUTH_DIR = path16.join(DATA_DIR, "whatsapp-auth");
7285
7302
  var sock = null;
7286
7303
  var io = null;
7287
7304
  var connectionStatus = "disconnected";
@@ -7436,13 +7453,13 @@ import {
7436
7453
 
7437
7454
  // ../pi/src/channels/whatsapp/store.ts
7438
7455
  import * as fs15 from "fs";
7439
- import * as os13 from "os";
7440
- import * as path18 from "path";
7456
+ import * as os10 from "os";
7457
+ import * as path17 from "path";
7441
7458
  import { randomUUID as randomUUID5 } from "crypto";
7442
7459
  import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
7443
- var DATA_DIR2 = path18.join(os13.homedir(), ".maestro");
7460
+ var DATA_DIR2 = path17.join(os10.homedir(), ".maestro");
7444
7461
  fs15.mkdirSync(DATA_DIR2, { recursive: true });
7445
- var dbPath2 = path18.join(DATA_DIR2, "pi.sqlite");
7462
+ var dbPath2 = path17.join(DATA_DIR2, "pi.sqlite");
7446
7463
  var db2 = new DatabaseSync2(dbPath2);
7447
7464
  db2.exec(`
7448
7465
  CREATE TABLE IF NOT EXISTS whatsapp_messages (
@@ -7858,13 +7875,13 @@ import {
7858
7875
 
7859
7876
  // ../pi/src/channels/telegram/store.ts
7860
7877
  import * as fs16 from "fs";
7861
- import * as os14 from "os";
7862
- import * as path19 from "path";
7878
+ import * as os11 from "os";
7879
+ import * as path18 from "path";
7863
7880
  import { randomUUID as randomUUID6 } from "crypto";
7864
7881
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
7865
- var DATA_DIR3 = path19.join(os14.homedir(), ".maestro");
7882
+ var DATA_DIR3 = path18.join(os11.homedir(), ".maestro");
7866
7883
  fs16.mkdirSync(DATA_DIR3, { recursive: true });
7867
- var dbPath3 = path19.join(DATA_DIR3, "pi.sqlite");
7884
+ var dbPath3 = path18.join(DATA_DIR3, "pi.sqlite");
7868
7885
  var db3 = new DatabaseSync3(dbPath3);
7869
7886
  db3.exec(`
7870
7887
  CREATE TABLE IF NOT EXISTS telegram_messages (