@jmanuelcorral/openteam 0.1.29 → 0.1.31

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 +1 @@
1
- {"version":3,"file":"consoleServe.d.ts","sourceRoot":"","sources":["../../src/cli/consoleServe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvE,gEAAgE;AAChE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACtD,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACtD,oEAAoE;IACpE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,yDAAyD;IACzD,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;IAC1D,oDAAoD;IACpD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;IAClD,yDAAyD;IACzD,YAAY,CAAC,EAAE,CACb,IAAI,EAAE,kBAAkB,KACrB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9C,sEAAsE;IACtE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IAC9D,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf,CAMA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAwE7B"}
1
+ {"version":3,"file":"consoleServe.d.ts","sourceRoot":"","sources":["../../src/cli/consoleServe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvE,gEAAgE;AAChE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACtD,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACtD,oEAAoE;IACpE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,yDAAyD;IACzD,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;IAC1D,oDAAoD;IACpD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;IAClD,yDAAyD;IACzD,YAAY,CAAC,EAAE,CACb,IAAI,EAAE,kBAAkB,KACrB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9C,sEAAsE;IACtE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IAC9D,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf,CAMA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA+F7B"}
package/dist/cli.js CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { execFile, spawn } from "node:child_process";
5
- import { access, mkdir as mkdir3, readdir as readdir2, readFile as readFile2, writeFile as writeFile3 } from "node:fs/promises";
6
- import { dirname as dirname3, join as join3 } from "node:path";
5
+ import { dirname as dirname2 } from "node:path";
7
6
  import { promisify } from "node:util";
8
7
 
9
8
  // src/cli/consoleServe.ts
@@ -1272,6 +1271,7 @@ var ConsoleConfigSchema = z3.object({
1272
1271
  refreshMs: z3.number().int().min(250).default(2000),
1273
1272
  recentRoutes: z3.number().int().positive().default(50),
1274
1273
  openBrowser: z3.boolean().default(false),
1274
+ remoteStorage: z3.boolean().default(false),
1275
1275
  terminal: z3.object({
1276
1276
  enabled: z3.boolean().default(true),
1277
1277
  pty: z3.boolean().optional()
@@ -1283,6 +1283,7 @@ var ConsoleConfigSchema = z3.object({
1283
1283
  refreshMs: 2000,
1284
1284
  recentRoutes: 50,
1285
1285
  openBrowser: false,
1286
+ remoteStorage: false,
1286
1287
  terminal: { enabled: true }
1287
1288
  });
1288
1289
  var defaultLocalModel = {
@@ -1439,6 +1440,101 @@ var OpenTeamEventSchema = z4.discriminatedUnion("type", [
1439
1440
  SessionEndpointEventSchema
1440
1441
  ]);
1441
1442
 
1443
+ // src/storage/fsStorageProvider.ts
1444
+ import {
1445
+ appendFile,
1446
+ mkdir,
1447
+ readdir,
1448
+ readFile,
1449
+ rm,
1450
+ stat,
1451
+ writeFile
1452
+ } from "node:fs/promises";
1453
+ import { dirname, join } from "node:path";
1454
+ function isMissing(error) {
1455
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
1456
+ }
1457
+ function createFsStorageProvider(root) {
1458
+ function toDisk(path) {
1459
+ return join(root, ...splitVirtualPath(path));
1460
+ }
1461
+ return {
1462
+ async read(path) {
1463
+ try {
1464
+ return await readFile(toDisk(path), "utf8");
1465
+ } catch (error) {
1466
+ if (isMissing(error)) {
1467
+ return;
1468
+ }
1469
+ throw error;
1470
+ }
1471
+ },
1472
+ async write(path, content) {
1473
+ const disk = toDisk(path);
1474
+ await mkdir(dirname(disk), { recursive: true });
1475
+ await writeFile(disk, content, "utf8");
1476
+ },
1477
+ async append(path, content) {
1478
+ const disk = toDisk(path);
1479
+ await mkdir(dirname(disk), { recursive: true });
1480
+ await appendFile(disk, content, "utf8");
1481
+ },
1482
+ async exists(path) {
1483
+ try {
1484
+ await stat(toDisk(path));
1485
+ return true;
1486
+ } catch (error) {
1487
+ if (isMissing(error)) {
1488
+ return false;
1489
+ }
1490
+ throw error;
1491
+ }
1492
+ },
1493
+ async list(dir) {
1494
+ try {
1495
+ const names = await readdir(toDisk(dir));
1496
+ return names.sort();
1497
+ } catch (error) {
1498
+ if (isMissing(error)) {
1499
+ return [];
1500
+ }
1501
+ throw error;
1502
+ }
1503
+ },
1504
+ async isDirectory(path) {
1505
+ try {
1506
+ return (await stat(toDisk(path))).isDirectory();
1507
+ } catch (error) {
1508
+ if (isMissing(error)) {
1509
+ return false;
1510
+ }
1511
+ throw error;
1512
+ }
1513
+ },
1514
+ async mkdir(dir) {
1515
+ await mkdir(toDisk(dir), { recursive: true });
1516
+ },
1517
+ async delete(path) {
1518
+ await rm(toDisk(path), { force: true });
1519
+ },
1520
+ async stat(path) {
1521
+ try {
1522
+ const stats = await stat(toDisk(path));
1523
+ return {
1524
+ size: stats.size,
1525
+ mtimeMs: stats.mtimeMs,
1526
+ isDirectory: stats.isDirectory()
1527
+ };
1528
+ } catch (error) {
1529
+ if (isMissing(error)) {
1530
+ return;
1531
+ }
1532
+ throw error;
1533
+ }
1534
+ }
1535
+ };
1536
+ }
1537
+
1442
1538
  // src/telemetry/types.ts
1443
1539
  import { z as z5 } from "zod";
1444
1540
  var CostRecordSchema = z5.object({
@@ -1959,13 +2055,177 @@ async function handleConsoleRoute(request, response, url, deps) {
1959
2055
  return true;
1960
2056
  }
1961
2057
 
2058
+ // src/web/storageRoute.ts
2059
+ var JSON_HEADERS2 = { "content-type": "application/json" };
2060
+ var READ_OPS = new Set(["read", "exists", "list", "isDirectory", "stat"]);
2061
+ var WRITE_OPS = new Set(["write", "append", "mkdir", "delete"]);
2062
+ function bearerFromHeader2(request) {
2063
+ const header = request.headers.authorization;
2064
+ if (typeof header !== "string" || !header.startsWith("Bearer ")) {
2065
+ return;
2066
+ }
2067
+ const value = header.slice("Bearer ".length).trim();
2068
+ return value.length === 0 ? undefined : value;
2069
+ }
2070
+ function authorized2(request, query, token) {
2071
+ const provided = tokenFromQuery(query) ?? bearerFromHeader2(request);
2072
+ return provided !== undefined && safeEqualToken(provided, token);
2073
+ }
2074
+ function pathAllowed(path, allowPrefixes) {
2075
+ if (allowPrefixes === undefined) {
2076
+ return true;
2077
+ }
2078
+ return allowPrefixes.some((rawPrefix) => {
2079
+ const prefix = normalizeVirtualPath(rawPrefix);
2080
+ if (prefix === "") {
2081
+ return true;
2082
+ }
2083
+ return path === prefix || path.startsWith(`${prefix}/`);
2084
+ });
2085
+ }
2086
+ async function readJsonBody2(request, limit) {
2087
+ return new Promise((resolve) => {
2088
+ let raw = "";
2089
+ let aborted = false;
2090
+ request.on("data", (chunk) => {
2091
+ if (aborted) {
2092
+ return;
2093
+ }
2094
+ raw += chunk.toString("utf8");
2095
+ if (raw.length > limit) {
2096
+ aborted = true;
2097
+ resolve(undefined);
2098
+ }
2099
+ });
2100
+ request.on("end", () => {
2101
+ if (!aborted) {
2102
+ try {
2103
+ resolve(JSON.parse(raw));
2104
+ } catch {
2105
+ resolve(undefined);
2106
+ }
2107
+ }
2108
+ });
2109
+ request.on("error", () => resolve(undefined));
2110
+ });
2111
+ }
2112
+ function sendJson(response, status, body) {
2113
+ response.writeHead(status, JSON_HEADERS2).end(JSON.stringify(body));
2114
+ }
2115
+ async function handleRead(response, op, path, storage) {
2116
+ if (op === "read") {
2117
+ sendJson(response, 200, { content: await storage.read(path) ?? null });
2118
+ return;
2119
+ }
2120
+ if (op === "list") {
2121
+ sendJson(response, 200, { entries: await storage.list(path) });
2122
+ return;
2123
+ }
2124
+ if (op === "exists") {
2125
+ sendJson(response, 200, { value: await storage.exists(path) });
2126
+ return;
2127
+ }
2128
+ if (op === "isDirectory") {
2129
+ sendJson(response, 200, { value: await storage.isDirectory(path) });
2130
+ return;
2131
+ }
2132
+ sendJson(response, 200, { stat: await storage.stat(path) ?? null });
2133
+ }
2134
+ async function handleWrite(request, response, op, deps) {
2135
+ if (deps.readOnly === true) {
2136
+ sendJson(response, 403, { error: "read-only" });
2137
+ return;
2138
+ }
2139
+ const body = await readJsonBody2(request, 8 * 1024 * 1024);
2140
+ const record = typeof body === "object" && body !== null ? body : undefined;
2141
+ const rawPath = record?.path;
2142
+ if (typeof rawPath !== "string") {
2143
+ sendJson(response, 400, { error: "invalid path" });
2144
+ return;
2145
+ }
2146
+ let path;
2147
+ try {
2148
+ path = normalizeVirtualPath(rawPath);
2149
+ } catch (error) {
2150
+ if (error instanceof StoragePathError) {
2151
+ sendJson(response, 400, { error: "invalid path" });
2152
+ return;
2153
+ }
2154
+ throw error;
2155
+ }
2156
+ if (!pathAllowed(path, deps.allowPrefixes)) {
2157
+ sendJson(response, 403, { error: "path not allowed" });
2158
+ return;
2159
+ }
2160
+ if (op === "write" || op === "append") {
2161
+ const content = record?.content;
2162
+ if (typeof content !== "string") {
2163
+ sendJson(response, 400, { error: "invalid content" });
2164
+ return;
2165
+ }
2166
+ if (op === "write") {
2167
+ await deps.storage.write(path, content);
2168
+ } else {
2169
+ await deps.storage.append(path, content);
2170
+ }
2171
+ } else if (op === "mkdir") {
2172
+ await deps.storage.mkdir(path);
2173
+ } else {
2174
+ await deps.storage.delete(path);
2175
+ }
2176
+ sendJson(response, 200, { ok: true });
2177
+ }
2178
+ async function handleStorageRoute(request, response, url, deps) {
2179
+ if (!url.pathname.startsWith("/storage/")) {
2180
+ return false;
2181
+ }
2182
+ const op = url.pathname.slice("/storage/".length);
2183
+ if (!READ_OPS.has(op) && !WRITE_OPS.has(op)) {
2184
+ sendJson(response, 404, { error: "not found" });
2185
+ return true;
2186
+ }
2187
+ if (!authorized2(request, url.searchParams, deps.token)) {
2188
+ sendJson(response, 401, { error: "unauthorized" });
2189
+ return true;
2190
+ }
2191
+ if (READ_OPS.has(op)) {
2192
+ if (request.method !== "GET") {
2193
+ sendJson(response, 405, { error: "method not allowed" });
2194
+ return true;
2195
+ }
2196
+ const rawPath = url.searchParams.get("path") ?? "";
2197
+ let path;
2198
+ try {
2199
+ path = normalizeVirtualPath(rawPath);
2200
+ } catch (error) {
2201
+ if (error instanceof StoragePathError) {
2202
+ sendJson(response, 400, { error: "invalid path" });
2203
+ return true;
2204
+ }
2205
+ throw error;
2206
+ }
2207
+ if (!pathAllowed(path, deps.allowPrefixes)) {
2208
+ sendJson(response, 403, { error: "path not allowed" });
2209
+ return true;
2210
+ }
2211
+ await handleRead(response, op, path, deps.storage);
2212
+ return true;
2213
+ }
2214
+ if (request.method !== "POST") {
2215
+ sendJson(response, 405, { error: "method not allowed" });
2216
+ return true;
2217
+ }
2218
+ await handleWrite(request, response, op, deps);
2219
+ return true;
2220
+ }
2221
+
1962
2222
  // src/web/server.ts
1963
2223
  var SSE_HEADERS2 = {
1964
2224
  "content-type": "text/event-stream",
1965
2225
  "cache-control": "no-cache",
1966
2226
  connection: "keep-alive"
1967
2227
  };
1968
- var JSON_HEADERS2 = { "content-type": "application/json" };
2228
+ var JSON_HEADERS3 = { "content-type": "application/json" };
1969
2229
  var HTML_HEADERS = { "content-type": "text/html; charset=utf-8" };
1970
2230
  function isAddressInUse(error) {
1971
2231
  return typeof error === "object" && error !== null && "code" in error && error.code === "EADDRINUSE";
@@ -2029,6 +2289,9 @@ async function createConsoleServer(deps) {
2029
2289
  if (consoleDeps !== undefined && await handleConsoleRoute(request, response, url2, consoleDeps)) {
2030
2290
  return;
2031
2291
  }
2292
+ if (deps.storageApi !== undefined && await handleStorageRoute(request, response, url2, deps.storageApi)) {
2293
+ return;
2294
+ }
2032
2295
  if (request.method !== "GET") {
2033
2296
  response.writeHead(405).end("method not allowed");
2034
2297
  return;
@@ -2039,11 +2302,11 @@ async function createConsoleServer(deps) {
2039
2302
  return;
2040
2303
  }
2041
2304
  if (path === "/api/state") {
2042
- response.writeHead(200, JSON_HEADERS2).end(await stateJson(deps));
2305
+ response.writeHead(200, JSON_HEADERS3).end(await stateJson(deps));
2043
2306
  return;
2044
2307
  }
2045
2308
  if (path === "/healthz") {
2046
- response.writeHead(200, JSON_HEADERS2).end(JSON.stringify({ ok: true }));
2309
+ response.writeHead(200, JSON_HEADERS3).end(JSON.stringify({ ok: true }));
2047
2310
  return;
2048
2311
  }
2049
2312
  if (path === "/favicon.ico") {
@@ -2424,7 +2687,8 @@ async function createConsoleRuntime(deps) {
2424
2687
  readSnapshot,
2425
2688
  config: deps.config,
2426
2689
  ...deps.log !== undefined ? { log: deps.log } : {},
2427
- ...deps.console !== undefined ? { console: deps.console } : {}
2690
+ ...deps.console !== undefined ? { console: deps.console } : {},
2691
+ ...deps.storageApi !== undefined ? { storageApi: deps.storageApi } : {}
2428
2692
  });
2429
2693
  const watchFn = deps.watch ?? ((path, listener) => fsWatch(path, { persistent: false }, listener));
2430
2694
  const watcher = watchSources([deps.sessionsDir, decisionsPath, backlogPath, deps.agentDir], () => {
@@ -2482,6 +2746,20 @@ async function runConsoleServe(deps, options) {
2482
2746
  createClient: makeClient,
2483
2747
  createPtyClient: makePtyClient
2484
2748
  },
2749
+ ...config.console.remoteStorage ? {
2750
+ storageApi: {
2751
+ storage: deps.storage,
2752
+ token,
2753
+ readOnly: true,
2754
+ allowPrefixes: [
2755
+ deps.sessionsDir,
2756
+ deps.decisionsPath,
2757
+ deps.backlogPath,
2758
+ deps.agentDir,
2759
+ ...deps.legacyTelemetryPath !== undefined ? [deps.legacyTelemetryPath] : []
2760
+ ]
2761
+ }
2762
+ } : {},
2485
2763
  log: deps.log
2486
2764
  });
2487
2765
  } catch (error) {
@@ -2490,6 +2768,9 @@ async function runConsoleServe(deps, options) {
2490
2768
  return { exitCode: 1 };
2491
2769
  }
2492
2770
  deps.log("Escuchando en loopback. Pulsa Ctrl+C para parar.");
2771
+ if (config.console.remoteStorage) {
2772
+ deps.log("Storage remoto expuesto en /storage/* (read-only, requiere token).");
2773
+ }
2493
2774
  if (options.open && deps.openBrowser !== undefined) {
2494
2775
  try {
2495
2776
  await deps.openBrowser(runtime.url);
@@ -3972,22 +4253,17 @@ ${HELP}`
3972
4253
  }
3973
4254
 
3974
4255
  // src/commands/setup.ts
3975
- import { join } from "node:path";
4256
+ import { join as join2 } from "node:path";
3976
4257
 
3977
4258
  // src/config/persist.ts
3978
- import { mkdir, writeFile } from "node:fs/promises";
3979
- import { dirname } from "node:path";
3980
4259
  var DEFAULT_CONFIG_PATH = ".opencode/openteam.json";
3981
4260
  function serializeOpenTeamConfig(config) {
3982
4261
  const validated = OpenTeamConfigSchema.parse(config);
3983
4262
  return `${JSON.stringify(validated, null, 2)}
3984
4263
  `;
3985
4264
  }
3986
- async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, deps = {}) {
3987
- const mkdirFn = deps.mkdir ?? mkdir;
3988
- const writeFileFn = deps.writeFile ?? writeFile;
3989
- await mkdirFn(dirname(path), { recursive: true });
3990
- await writeFileFn(path, serializeOpenTeamConfig(config), "utf8");
4265
+ async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, storage = createFsStorageProvider(process.cwd())) {
4266
+ await storage.write(path, serializeOpenTeamConfig(config));
3991
4267
  }
3992
4268
 
3993
4269
  // src/commands/slashCommand.ts
@@ -4461,9 +4737,9 @@ async function runSetup(deps) {
4461
4737
  const opencodeConfig = buildOpencodeConfig(answers);
4462
4738
  const orchestratorAgent = buildOrchestratorAgent(frontier, { yolo });
4463
4739
  const slashCommands = buildOpenteamCommands();
4464
- const openTeamPath = join(deps.cwd, DEFAULT_CONFIG_PATH);
4465
- const opencodePath = join(deps.cwd, OPENCODE_CONFIG_PATH);
4466
- const agentPath = join(deps.cwd, ORCHESTRATOR_AGENT_PATH);
4740
+ const openTeamPath = join2(deps.cwd, DEFAULT_CONFIG_PATH);
4741
+ const opencodePath = join2(deps.cwd, OPENCODE_CONFIG_PATH);
4742
+ const agentPath = join2(deps.cwd, ORCHESTRATOR_AGENT_PATH);
4467
4743
  const existing = [];
4468
4744
  if (await deps.fileExists(openTeamPath)) {
4469
4745
  existing.push(DEFAULT_CONFIG_PATH);
@@ -4475,7 +4751,7 @@ async function runSetup(deps) {
4475
4751
  existing.push(ORCHESTRATOR_AGENT_PATH);
4476
4752
  }
4477
4753
  for (const command of slashCommands) {
4478
- if (await deps.fileExists(join(deps.cwd, command.path))) {
4754
+ if (await deps.fileExists(join2(deps.cwd, command.path))) {
4479
4755
  existing.push(command.path);
4480
4756
  }
4481
4757
  }
@@ -4493,7 +4769,7 @@ async function runSetup(deps) {
4493
4769
  await deps.writeFile(opencodePath, serializeOpencodeConfig(opencodeConfig));
4494
4770
  await deps.writeFile(agentPath, orchestratorAgent);
4495
4771
  for (const command of slashCommands) {
4496
- await deps.writeFile(join(deps.cwd, command.path), command.contents);
4772
+ await deps.writeFile(join2(deps.cwd, command.path), command.contents);
4497
4773
  }
4498
4774
  const enabledSummary = runtimes.filter((runtime) => runtime.enabled).map((runtime) => {
4499
4775
  const remote = runtime.baseURL !== undefined && !runtime.baseURL.includes("localhost") && !runtime.baseURL.includes("127.0.0.1") ? ` @ ${runtime.baseURL}` : "";
@@ -4528,101 +4804,6 @@ function loadOpenTeamConfig(raw) {
4528
4804
  return OpenTeamConfigSchema.parse(raw ?? {});
4529
4805
  }
4530
4806
 
4531
- // src/storage/fsStorageProvider.ts
4532
- import {
4533
- appendFile,
4534
- mkdir as mkdir2,
4535
- readdir,
4536
- readFile,
4537
- rm,
4538
- stat,
4539
- writeFile as writeFile2
4540
- } from "node:fs/promises";
4541
- import { dirname as dirname2, join as join2 } from "node:path";
4542
- function isMissing(error) {
4543
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
4544
- }
4545
- function createFsStorageProvider(root) {
4546
- function toDisk(path) {
4547
- return join2(root, ...splitVirtualPath(path));
4548
- }
4549
- return {
4550
- async read(path) {
4551
- try {
4552
- return await readFile(toDisk(path), "utf8");
4553
- } catch (error) {
4554
- if (isMissing(error)) {
4555
- return;
4556
- }
4557
- throw error;
4558
- }
4559
- },
4560
- async write(path, content) {
4561
- const disk = toDisk(path);
4562
- await mkdir2(dirname2(disk), { recursive: true });
4563
- await writeFile2(disk, content, "utf8");
4564
- },
4565
- async append(path, content) {
4566
- const disk = toDisk(path);
4567
- await mkdir2(dirname2(disk), { recursive: true });
4568
- await appendFile(disk, content, "utf8");
4569
- },
4570
- async exists(path) {
4571
- try {
4572
- await stat(toDisk(path));
4573
- return true;
4574
- } catch (error) {
4575
- if (isMissing(error)) {
4576
- return false;
4577
- }
4578
- throw error;
4579
- }
4580
- },
4581
- async list(dir) {
4582
- try {
4583
- const names = await readdir(toDisk(dir));
4584
- return names.sort();
4585
- } catch (error) {
4586
- if (isMissing(error)) {
4587
- return [];
4588
- }
4589
- throw error;
4590
- }
4591
- },
4592
- async isDirectory(path) {
4593
- try {
4594
- return (await stat(toDisk(path))).isDirectory();
4595
- } catch (error) {
4596
- if (isMissing(error)) {
4597
- return false;
4598
- }
4599
- throw error;
4600
- }
4601
- },
4602
- async mkdir(dir) {
4603
- await mkdir2(toDisk(dir), { recursive: true });
4604
- },
4605
- async delete(path) {
4606
- await rm(toDisk(path), { force: true });
4607
- },
4608
- async stat(path) {
4609
- try {
4610
- const stats = await stat(toDisk(path));
4611
- return {
4612
- size: stats.size,
4613
- mtimeMs: stats.mtimeMs,
4614
- isDirectory: stats.isDirectory()
4615
- };
4616
- } catch (error) {
4617
- if (isMissing(error)) {
4618
- return;
4619
- }
4620
- throw error;
4621
- }
4622
- }
4623
- };
4624
- }
4625
-
4626
4807
  // src/web/git.ts
4627
4808
  function createGitLastCommit(exec) {
4628
4809
  return async () => {
@@ -4644,10 +4825,8 @@ function createGitLastCommit(exec) {
4644
4825
 
4645
4826
  // src/cli.ts
4646
4827
  var execFileAsync = promisify(execFile);
4647
- var AGENT_DIR = dirname3(ORCHESTRATOR_AGENT_PATH);
4648
- function isMissingFile(error) {
4649
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
4650
- }
4828
+ var AGENT_DIR = dirname2(ORCHESTRATOR_AGENT_PATH);
4829
+ var storage = createFsStorageProvider(process.cwd());
4651
4830
  var nodeExec = async (command, args) => {
4652
4831
  try {
4653
4832
  const { stdout, stderr } = await execFileAsync(command, [...args]);
@@ -4662,17 +4841,9 @@ var nodeExec = async (command, args) => {
4662
4841
  }
4663
4842
  };
4664
4843
  async function loadConfig(path) {
4665
- try {
4666
- const content = await readFile2(path, "utf8");
4667
- return loadOpenTeamConfig(JSON.parse(content));
4668
- } catch (error) {
4669
- if (isMissingFile(error)) {
4670
- return loadOpenTeamConfig({});
4671
- }
4672
- throw error;
4673
- }
4844
+ const content = await storage.read(path);
4845
+ return content === undefined ? loadOpenTeamConfig({}) : loadOpenTeamConfig(JSON.parse(content));
4674
4846
  }
4675
- var storage = createFsStorageProvider(process.cwd());
4676
4847
  async function openBrowser(url) {
4677
4848
  if (process.platform === "win32") {
4678
4849
  await nodeExec("cmd", ["/c", "start", "", url]);
@@ -4691,41 +4862,24 @@ function waitForSignal() {
4691
4862
  }
4692
4863
  var deps = {
4693
4864
  loadConfig,
4694
- saveConfig: (config, path) => writeOpenTeamConfigFile(config, path),
4865
+ saveConfig: (config, path) => writeOpenTeamConfigFile(config, path, storage),
4695
4866
  readOpencodeConfig: async (path) => {
4696
- try {
4697
- const content = await readFile2(path, "utf8");
4698
- return JSON.parse(content);
4699
- } catch (error) {
4700
- if (isMissingFile(error)) {
4701
- return;
4702
- }
4703
- throw error;
4704
- }
4867
+ const content = await storage.read(path);
4868
+ return content === undefined ? undefined : JSON.parse(content);
4705
4869
  },
4706
4870
  writeOpencodeConfig: async (config, path) => {
4707
- await mkdir3(dirname3(path), { recursive: true });
4708
- await writeFile3(path, `${JSON.stringify(config, null, 2)}
4709
- `, "utf8");
4871
+ await storage.write(path, `${JSON.stringify(config, null, 2)}
4872
+ `);
4710
4873
  },
4711
4874
  writeOrchestratorAgent: async (contents, path) => {
4712
- await mkdir3(dirname3(path), { recursive: true });
4713
- await writeFile3(path, contents, "utf8");
4875
+ await storage.write(path, contents);
4714
4876
  },
4715
4877
  listAgentFiles: async (dir) => {
4716
- let entries;
4717
- try {
4718
- entries = await readdir2(dir);
4719
- } catch (error) {
4720
- if (isMissingFile(error)) {
4721
- return [];
4722
- }
4723
- throw error;
4724
- }
4878
+ const entries = await storage.list(dir);
4725
4879
  const mdFiles = entries.filter((entry) => entry.endsWith(".md"));
4726
4880
  return Promise.all(mdFiles.map(async (entry) => ({
4727
4881
  name: entry.replace(/\.md$/, ""),
4728
- contents: await readFile2(join3(dir, entry), "utf8")
4882
+ contents: await storage.read(joinVirtualPath(dir, entry)) ?? ""
4729
4883
  })));
4730
4884
  },
4731
4885
  probe: (config) => {
@@ -4754,17 +4908,9 @@ function createSetupDeps() {
4754
4908
  loadFrontierProfiles: createLoadFrontierProfiles(),
4755
4909
  prompt: clackPrompter,
4756
4910
  writeFile: async (path, contents) => {
4757
- await mkdir3(dirname3(path), { recursive: true });
4758
- await writeFile3(path, contents, "utf8");
4911
+ await storage.write(path, contents);
4759
4912
  },
4760
- fileExists: async (path) => {
4761
- try {
4762
- await access(path);
4763
- return true;
4764
- } catch {
4765
- return false;
4766
- }
4767
- }
4913
+ fileExists: (path) => storage.exists(path)
4768
4914
  };
4769
4915
  }
4770
4916
  async function main() {
@@ -1,4 +1,5 @@
1
+ import type { StorageProvider } from "../storage/provider";
1
2
  import { type OpenTeamConfig } from "./schema";
2
3
  export declare function loadOpenTeamConfig(raw: unknown): OpenTeamConfig;
3
- export declare function readOpenTeamConfigFile(path?: string): Promise<OpenTeamConfig>;
4
+ export declare function readOpenTeamConfigFile(path?: string, storage?: StorageProvider): Promise<OpenTeamConfig>;
4
5
  //# sourceMappingURL=load.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,UAAU,CAAC;AAErE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAE/D;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,SAA4B,GAC/B,OAAO,CAAC,cAAc,CAAC,CAGzB"}
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,UAAU,CAAC;AAErE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAE/D;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,SAA4B,EAChC,OAAO,GAAE,eAAwD,GAChE,OAAO,CAAC,cAAc,CAAC,CAMzB"}
@@ -1,4 +1,4 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
1
+ import type { StorageProvider } from "../storage/provider";
2
2
  import { type OpenTeamConfig } from "./schema";
3
3
  export declare const DEFAULT_CONFIG_PATH = ".opencode/openteam.json";
4
4
  /**
@@ -6,9 +6,5 @@ export declare const DEFAULT_CONFIG_PATH = ".opencode/openteam.json";
6
6
  * Pure: no filesystem access.
7
7
  */
8
8
  export declare function serializeOpenTeamConfig(config: OpenTeamConfig): string;
9
- export type WriteConfigDeps = {
10
- mkdir?: typeof mkdir;
11
- writeFile?: typeof writeFile;
12
- };
13
- export declare function writeOpenTeamConfigFile(config: OpenTeamConfig, path?: string, deps?: WriteConfigDeps): Promise<void>;
9
+ export declare function writeOpenTeamConfigFile(config: OpenTeamConfig, path?: string, storage?: StorageProvider): Promise<void>;
14
10
  //# sourceMappingURL=persist.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/config/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,UAAU,CAAC;AAErE,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAE7D;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAGtE;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;CAC9B,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,cAAc,EACtB,IAAI,SAAsB,EAC1B,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CAMf"}
1
+ {"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/config/persist.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,UAAU,CAAC;AAErE,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAE7D;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAGtE;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,cAAc,EACtB,IAAI,SAAsB,EAC1B,OAAO,GAAE,eAAwD,GAChE,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -31,6 +31,7 @@ export declare const ConsoleConfigSchema: z.ZodDefault<z.ZodObject<{
31
31
  refreshMs: z.ZodDefault<z.ZodNumber>;
32
32
  recentRoutes: z.ZodDefault<z.ZodNumber>;
33
33
  openBrowser: z.ZodDefault<z.ZodBoolean>;
34
+ remoteStorage: z.ZodDefault<z.ZodBoolean>;
34
35
  terminal: z.ZodDefault<z.ZodObject<{
35
36
  enabled: z.ZodDefault<z.ZodBoolean>;
36
37
  pty: z.ZodOptional<z.ZodBoolean>;
@@ -123,6 +124,7 @@ export declare const OpenTeamConfigObjectSchema: z.ZodObject<{
123
124
  refreshMs: z.ZodDefault<z.ZodNumber>;
124
125
  recentRoutes: z.ZodDefault<z.ZodNumber>;
125
126
  openBrowser: z.ZodDefault<z.ZodBoolean>;
127
+ remoteStorage: z.ZodDefault<z.ZodBoolean>;
126
128
  terminal: z.ZodDefault<z.ZodObject<{
127
129
  enabled: z.ZodDefault<z.ZodBoolean>;
128
130
  pty: z.ZodOptional<z.ZodBoolean>;
@@ -199,6 +201,7 @@ export declare const OpenTeamConfigSchema: z.ZodObject<{
199
201
  refreshMs: z.ZodDefault<z.ZodNumber>;
200
202
  recentRoutes: z.ZodDefault<z.ZodNumber>;
201
203
  openBrowser: z.ZodDefault<z.ZodBoolean>;
204
+ remoteStorage: z.ZodDefault<z.ZodBoolean>;
202
205
  terminal: z.ZodDefault<z.ZodObject<{
203
206
  enabled: z.ZodDefault<z.ZodBoolean>;
204
207
  pty: z.ZodOptional<z.ZodBoolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;iBAGzB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;EAA6C,CAAC;AAC3E,eAAO,MAAM,iBAAiB;;;;EAI5B,CAAC;AACH,eAAO,MAAM,kBAAkB;;;EAA6B,CAAC;AAE7D,eAAO,MAAM,iBAAiB;;;EAAqC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;kBA4B5B,CAAC;AAeL,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;iBAM7B,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2DrC,CAAC;AAEH,gDAAgD;AAChD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA6B,CAAC;AAE/D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;iBAGzB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;EAA6C,CAAC;AAC3E,eAAO,MAAM,iBAAiB;;;;EAI5B,CAAC;AACH,eAAO,MAAM,kBAAkB;;;EAA6B,CAAC;AAE7D,eAAO,MAAM,iBAAiB;;;EAAqC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;kBAmC5B,CAAC;AAeL,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;iBAM7B,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2DrC,CAAC;AAEH,gDAAgD;AAChD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA6B,CAAC;AAE/D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,21 +1,11 @@
1
- import { appendFile, mkdir } from "node:fs/promises";
2
1
  import type { Plugin, PluginModule } from "@opencode-ai/plugin";
3
2
  import type { CliDeps } from "./commands/dispatch";
4
3
  import type { OpenTeamConfig } from "./config/schema";
5
4
  import { RuntimeRegistry } from "./local/registry";
6
5
  import type { StorageProvider } from "./storage/provider";
7
6
  import { type EventSink } from "./telemetry/eventLog";
8
- type FileAppenderDeps = {
9
- mkdir?: typeof mkdir;
10
- appendFile?: typeof appendFile;
11
- };
12
7
  export declare function logAvailabilityRefreshError(error: unknown): void;
13
8
  export declare function logTelemetryError(error: unknown): void;
14
- export declare function createFileAppender(filePath: string, deps?: FileAppenderDeps): (line: string) => Promise<void>;
15
- /**
16
- * Crea el sink de eventos por sesión (`<sessionsDir>/<sessionID>.jsonl`). Si la
17
- * telemetría está desactivada devuelve un sink no-op.
18
- */
19
9
  export declare function createEventSink(rawOptions: unknown, storage?: StorageProvider): EventSink;
20
10
  export declare function isMissingFile(error: unknown): boolean;
21
11
  export declare function createCliDeps(config: OpenTeamConfig, registry: RuntimeRegistry, telemetryPath: string, sessionsDir?: string, storage?: StorageProvider): CliDeps;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,EAIN,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EAAE,MAAM,EAAe,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAKnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAWnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAS9B,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,UAAU,CAAC;CAChC,CAAC;AAcF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAGhE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAGtD;AAgCD,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,gBAAqB,GAC1B,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAQjC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,OAAO,EACnB,OAAO,GAAE,eAAwD,GAChE,SAAS,CAYX;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOrD;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,eAAe,EACzB,aAAa,EAAE,MAAM,EACrB,WAAW,GAAE,MAA6B,EAC1C,OAAO,GAAE,eAAwD,GAChE,OAAO,CAgET;AAED,eAAO,MAAM,MAAM,EAAE,MA0EpB,CAAC;AAEF,QAAA,MAAM,MAAM,EAAE,YAGb,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAe,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAKnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAYnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAqB9B,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAGhE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAGtD;AAgCD,wBAAgB,eAAe,CAC7B,UAAU,EAAE,OAAO,EACnB,OAAO,GAAE,eAAwD,GAChE,SAAS,CAYX;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOrD;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,eAAe,EACzB,aAAa,EAAE,MAAM,EACrB,WAAW,GAAE,MAA6B,EAC1C,OAAO,GAAE,eAAwD,GAChE,OAAO,CA4CT;AAED,eAAO,MAAM,MAAM,EAAE,MA0EpB,CAAC;AAEF,QAAA,MAAM,MAAM,EAAE,YAGb,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js CHANGED
@@ -1,12 +1,5 @@
1
1
  // src/index.ts
2
- import {
3
- appendFile as appendFile2,
4
- mkdir as mkdir3,
5
- readdir as readdir2,
6
- readFile as readFile2,
7
- writeFile as writeFile3
8
- } from "node:fs/promises";
9
- import { dirname as dirname3, join as join2 } from "node:path";
2
+ import { dirname as dirname2 } from "node:path";
10
3
 
11
4
  // src/commands/orchestratorAgent.ts
12
5
  var ORCHESTRATOR_AGENT_PATH = ".opencode/agent/openteam.md";
@@ -198,9 +191,134 @@ function buildOrchestratorAgent(frontier, options = {}) {
198
191
  ${body}`;
199
192
  }
200
193
 
201
- // src/config/persist.ts
202
- import { mkdir, writeFile } from "node:fs/promises";
203
- import { dirname } from "node:path";
194
+ // src/storage/fsStorageProvider.ts
195
+ import {
196
+ appendFile,
197
+ mkdir,
198
+ readdir,
199
+ readFile,
200
+ rm,
201
+ stat,
202
+ writeFile
203
+ } from "node:fs/promises";
204
+ import { dirname, join } from "node:path";
205
+
206
+ // src/storage/path.ts
207
+ class StoragePathError extends Error {
208
+ constructor(message) {
209
+ super(message);
210
+ this.name = "StoragePathError";
211
+ }
212
+ }
213
+ function normalizeVirtualPath(input) {
214
+ const segments = [];
215
+ for (const rawSegment of input.split(/[\\/]+/)) {
216
+ if (rawSegment === "" || rawSegment === ".") {
217
+ continue;
218
+ }
219
+ if (rawSegment === "..") {
220
+ if (segments.length === 0) {
221
+ throw new StoragePathError(`la ruta "${input}" escapa por encima de la raíz`);
222
+ }
223
+ segments.pop();
224
+ continue;
225
+ }
226
+ segments.push(rawSegment);
227
+ }
228
+ return segments.join("/");
229
+ }
230
+ function joinVirtualPath(...segments) {
231
+ return normalizeVirtualPath(segments.join("/"));
232
+ }
233
+ function splitVirtualPath(path) {
234
+ const normalized = normalizeVirtualPath(path);
235
+ return normalized === "" ? [] : normalized.split("/");
236
+ }
237
+
238
+ // src/storage/fsStorageProvider.ts
239
+ function isMissing(error) {
240
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
241
+ }
242
+ function createFsStorageProvider(root) {
243
+ function toDisk(path) {
244
+ return join(root, ...splitVirtualPath(path));
245
+ }
246
+ return {
247
+ async read(path) {
248
+ try {
249
+ return await readFile(toDisk(path), "utf8");
250
+ } catch (error) {
251
+ if (isMissing(error)) {
252
+ return;
253
+ }
254
+ throw error;
255
+ }
256
+ },
257
+ async write(path, content) {
258
+ const disk = toDisk(path);
259
+ await mkdir(dirname(disk), { recursive: true });
260
+ await writeFile(disk, content, "utf8");
261
+ },
262
+ async append(path, content) {
263
+ const disk = toDisk(path);
264
+ await mkdir(dirname(disk), { recursive: true });
265
+ await appendFile(disk, content, "utf8");
266
+ },
267
+ async exists(path) {
268
+ try {
269
+ await stat(toDisk(path));
270
+ return true;
271
+ } catch (error) {
272
+ if (isMissing(error)) {
273
+ return false;
274
+ }
275
+ throw error;
276
+ }
277
+ },
278
+ async list(dir) {
279
+ try {
280
+ const names = await readdir(toDisk(dir));
281
+ return names.sort();
282
+ } catch (error) {
283
+ if (isMissing(error)) {
284
+ return [];
285
+ }
286
+ throw error;
287
+ }
288
+ },
289
+ async isDirectory(path) {
290
+ try {
291
+ return (await stat(toDisk(path))).isDirectory();
292
+ } catch (error) {
293
+ if (isMissing(error)) {
294
+ return false;
295
+ }
296
+ throw error;
297
+ }
298
+ },
299
+ async mkdir(dir) {
300
+ await mkdir(toDisk(dir), { recursive: true });
301
+ },
302
+ async delete(path) {
303
+ await rm(toDisk(path), { force: true });
304
+ },
305
+ async stat(path) {
306
+ try {
307
+ const stats = await stat(toDisk(path));
308
+ return {
309
+ size: stats.size,
310
+ mtimeMs: stats.mtimeMs,
311
+ isDirectory: stats.isDirectory()
312
+ };
313
+ } catch (error) {
314
+ if (isMissing(error)) {
315
+ return;
316
+ }
317
+ throw error;
318
+ }
319
+ }
320
+ };
321
+ }
204
322
 
205
323
  // src/config/schema.ts
206
324
  import { z } from "zod";
@@ -223,6 +341,7 @@ var ConsoleConfigSchema = z.object({
223
341
  refreshMs: z.number().int().min(250).default(2000),
224
342
  recentRoutes: z.number().int().positive().default(50),
225
343
  openBrowser: z.boolean().default(false),
344
+ remoteStorage: z.boolean().default(false),
226
345
  terminal: z.object({
227
346
  enabled: z.boolean().default(true),
228
347
  pty: z.boolean().optional()
@@ -234,6 +353,7 @@ var ConsoleConfigSchema = z.object({
234
353
  refreshMs: 2000,
235
354
  recentRoutes: 50,
236
355
  openBrowser: false,
356
+ remoteStorage: false,
237
357
  terminal: { enabled: true }
238
358
  });
239
359
  var defaultLocalModel = {
@@ -309,11 +429,8 @@ function serializeOpenTeamConfig(config) {
309
429
  return `${JSON.stringify(validated, null, 2)}
310
430
  `;
311
431
  }
312
- async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, deps = {}) {
313
- const mkdirFn = deps.mkdir ?? mkdir;
314
- const writeFileFn = deps.writeFile ?? writeFile;
315
- await mkdirFn(dirname(path), { recursive: true });
316
- await writeFileFn(path, serializeOpenTeamConfig(config), "utf8");
432
+ async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, storage = createFsStorageProvider(process.cwd())) {
433
+ await storage.write(path, serializeOpenTeamConfig(config));
317
434
  }
318
435
 
319
436
  // src/commands/setup.ts
@@ -2042,38 +2159,6 @@ function toCostRecord(decision2, context) {
2042
2159
  return record;
2043
2160
  }
2044
2161
 
2045
- // src/storage/path.ts
2046
- class StoragePathError extends Error {
2047
- constructor(message) {
2048
- super(message);
2049
- this.name = "StoragePathError";
2050
- }
2051
- }
2052
- function normalizeVirtualPath(input) {
2053
- const segments = [];
2054
- for (const rawSegment of input.split(/[\\/]+/)) {
2055
- if (rawSegment === "" || rawSegment === ".") {
2056
- continue;
2057
- }
2058
- if (rawSegment === "..") {
2059
- if (segments.length === 0) {
2060
- throw new StoragePathError(`la ruta "${input}" escapa por encima de la raíz`);
2061
- }
2062
- segments.pop();
2063
- continue;
2064
- }
2065
- segments.push(rawSegment);
2066
- }
2067
- return segments.join("/");
2068
- }
2069
- function joinVirtualPath(...segments) {
2070
- return normalizeVirtualPath(segments.join("/"));
2071
- }
2072
- function splitVirtualPath(path) {
2073
- const normalized = normalizeVirtualPath(path);
2074
- return normalized === "" ? [] : normalized.split("/");
2075
- }
2076
-
2077
2162
  // src/telemetry/types.ts
2078
2163
  import { z as z4 } from "zod";
2079
2164
  var CostRecordSchema = z4.object({
@@ -2365,101 +2450,6 @@ function createToolcallTracker(deps) {
2365
2450
  };
2366
2451
  }
2367
2452
 
2368
- // src/storage/fsStorageProvider.ts
2369
- import {
2370
- appendFile,
2371
- mkdir as mkdir2,
2372
- readdir,
2373
- readFile,
2374
- rm,
2375
- stat,
2376
- writeFile as writeFile2
2377
- } from "node:fs/promises";
2378
- import { dirname as dirname2, join } from "node:path";
2379
- function isMissing(error) {
2380
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
2381
- }
2382
- function createFsStorageProvider(root) {
2383
- function toDisk(path) {
2384
- return join(root, ...splitVirtualPath(path));
2385
- }
2386
- return {
2387
- async read(path) {
2388
- try {
2389
- return await readFile(toDisk(path), "utf8");
2390
- } catch (error) {
2391
- if (isMissing(error)) {
2392
- return;
2393
- }
2394
- throw error;
2395
- }
2396
- },
2397
- async write(path, content) {
2398
- const disk = toDisk(path);
2399
- await mkdir2(dirname2(disk), { recursive: true });
2400
- await writeFile2(disk, content, "utf8");
2401
- },
2402
- async append(path, content) {
2403
- const disk = toDisk(path);
2404
- await mkdir2(dirname2(disk), { recursive: true });
2405
- await appendFile(disk, content, "utf8");
2406
- },
2407
- async exists(path) {
2408
- try {
2409
- await stat(toDisk(path));
2410
- return true;
2411
- } catch (error) {
2412
- if (isMissing(error)) {
2413
- return false;
2414
- }
2415
- throw error;
2416
- }
2417
- },
2418
- async list(dir) {
2419
- try {
2420
- const names = await readdir(toDisk(dir));
2421
- return names.sort();
2422
- } catch (error) {
2423
- if (isMissing(error)) {
2424
- return [];
2425
- }
2426
- throw error;
2427
- }
2428
- },
2429
- async isDirectory(path) {
2430
- try {
2431
- return (await stat(toDisk(path))).isDirectory();
2432
- } catch (error) {
2433
- if (isMissing(error)) {
2434
- return false;
2435
- }
2436
- throw error;
2437
- }
2438
- },
2439
- async mkdir(dir) {
2440
- await mkdir2(toDisk(dir), { recursive: true });
2441
- },
2442
- async delete(path) {
2443
- await rm(toDisk(path), { force: true });
2444
- },
2445
- async stat(path) {
2446
- try {
2447
- const stats = await stat(toDisk(path));
2448
- return {
2449
- size: stats.size,
2450
- mtimeMs: stats.mtimeMs,
2451
- isDirectory: stats.isDirectory()
2452
- };
2453
- } catch (error) {
2454
- if (isMissing(error)) {
2455
- return;
2456
- }
2457
- throw error;
2458
- }
2459
- }
2460
- };
2461
- }
2462
-
2463
2453
  // src/index.ts
2464
2454
  function createShellExec($) {
2465
2455
  return async (command, args) => {
@@ -2490,14 +2480,6 @@ function telemetryOptions(rawOptions) {
2490
2480
  sessionsDir: configuredSessionsDir
2491
2481
  };
2492
2482
  }
2493
- function createFileAppender(filePath, deps = {}) {
2494
- const mkdirFn = deps.mkdir ?? mkdir3;
2495
- const appendFileFn = deps.appendFile ?? appendFile2;
2496
- return async (line) => {
2497
- await mkdirFn(dirname3(filePath), { recursive: true });
2498
- await appendFileFn(filePath, line, "utf8");
2499
- };
2500
- }
2501
2483
  function createEventSink(rawOptions, storage = createFsStorageProvider(process.cwd())) {
2502
2484
  const options = telemetryOptions(rawOptions);
2503
2485
  if (!options.enabled) {
@@ -2515,49 +2497,27 @@ function isMissingFile(error) {
2515
2497
  function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SESSIONS_DIR, storage = createFsStorageProvider(process.cwd())) {
2516
2498
  return {
2517
2499
  loadConfig: async (path) => {
2518
- try {
2519
- return loadOpenTeamConfig(JSON.parse(await readFile2(path, "utf8")));
2520
- } catch (error) {
2521
- if (isMissingFile(error)) {
2522
- return config;
2523
- }
2524
- throw error;
2525
- }
2500
+ const content = await storage.read(path);
2501
+ return content === undefined ? config : loadOpenTeamConfig(JSON.parse(content));
2526
2502
  },
2527
- saveConfig: (nextConfig, path) => writeOpenTeamConfigFile(nextConfig, path),
2503
+ saveConfig: (nextConfig, path) => writeOpenTeamConfigFile(nextConfig, path, storage),
2528
2504
  readOpencodeConfig: async (path) => {
2529
- try {
2530
- return JSON.parse(await readFile2(path, "utf8"));
2531
- } catch (error) {
2532
- if (isMissingFile(error)) {
2533
- return;
2534
- }
2535
- throw error;
2536
- }
2505
+ const content = await storage.read(path);
2506
+ return content === undefined ? undefined : JSON.parse(content);
2537
2507
  },
2538
2508
  writeOpencodeConfig: async (nextConfig, path) => {
2539
- await mkdir3(dirname3(path), { recursive: true });
2540
- await writeFile3(path, `${JSON.stringify(nextConfig, null, 2)}
2541
- `, "utf8");
2509
+ await storage.write(path, `${JSON.stringify(nextConfig, null, 2)}
2510
+ `);
2542
2511
  },
2543
2512
  writeOrchestratorAgent: async (contents, path) => {
2544
- await mkdir3(dirname3(path), { recursive: true });
2545
- await writeFile3(path, contents, "utf8");
2513
+ await storage.write(path, contents);
2546
2514
  },
2547
2515
  listAgentFiles: async (dir) => {
2548
- let entries;
2549
- try {
2550
- entries = await readdir2(dir);
2551
- } catch (error) {
2552
- if (isMissingFile(error)) {
2553
- return [];
2554
- }
2555
- throw error;
2556
- }
2516
+ const entries = await storage.list(dir);
2557
2517
  const mdFiles = entries.filter((entry) => entry.endsWith(".md"));
2558
2518
  return Promise.all(mdFiles.map(async (entry) => ({
2559
2519
  name: entry.replace(/\.md$/, ""),
2560
- contents: await readFile2(join2(dir, entry), "utf8")
2520
+ contents: await storage.read(joinVirtualPath(dir, entry)) ?? ""
2561
2521
  })));
2562
2522
  },
2563
2523
  probe: (nextConfig) => registry.probe(nextConfig.local.runtimes),
@@ -2569,7 +2529,7 @@ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SE
2569
2529
  telemetryPath,
2570
2530
  opencodeConfigPath: OPENCODE_CONFIG_PATH,
2571
2531
  orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
2572
- agentDir: dirname3(ORCHESTRATOR_AGENT_PATH)
2532
+ agentDir: dirname2(ORCHESTRATOR_AGENT_PATH)
2573
2533
  };
2574
2534
  }
2575
2535
  var server = async (ctx, rawOptions) => {
@@ -2649,7 +2609,6 @@ export {
2649
2609
  logAvailabilityRefreshError,
2650
2610
  isMissingFile,
2651
2611
  src_default as default,
2652
- createFileAppender,
2653
2612
  createEventSink,
2654
2613
  createCliDeps
2655
2614
  };
@@ -0,0 +1,21 @@
1
+ import type { StorageProvider } from "./provider";
2
+ /**
3
+ * `createHttpStorageProvider` — adapter remoto del `StorageProvider` (§ Fase 4).
4
+ *
5
+ * Habla con el endpoint `/storage/...` servido por la Console (ver
6
+ * `web/storageRoute.ts`) para leer/escribir el estado del equipo a través del
7
+ * tunnel. Es un proxy transparente del contrato: cada operación se traduce a una
8
+ * petición HTTP autenticada con el token efímero de la Console.
9
+ *
10
+ * `fetch` es inyectable para tests deterministas; en producción usa el global.
11
+ */
12
+ export type HttpStorageProviderOptions = {
13
+ /** Origen del endpoint, p. ej. `http://127.0.0.1:4599`. Sin barra final. */
14
+ baseUrl: string;
15
+ /** Token efímero de la Console (bearer). */
16
+ token: string;
17
+ /** Implementación de `fetch` (inyectable). Por defecto el global. */
18
+ fetch?: typeof fetch;
19
+ };
20
+ export declare function createHttpStorageProvider(options: HttpStorageProviderOptions): StorageProvider;
21
+ //# sourceMappingURL=httpStorageProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpStorageProvider.d.ts","sourceRoot":"","sources":["../../src/storage/httpStorageProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,YAAY,CAAC;AAE/D;;;;;;;;;GASG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,CAAC;AAOF,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,eAAe,CA2CjB"}
@@ -1,4 +1,4 @@
1
- import { readFile } from "node:fs/promises";
1
+ import type { StorageProvider } from "../storage/provider";
2
2
  import { type CostRecord } from "./types";
3
3
  export declare const DEFAULT_TELEMETRY_PATH = ".opencode/openteam-telemetry.jsonl";
4
4
  /**
@@ -7,8 +7,5 @@ export declare const DEFAULT_TELEMETRY_PATH = ".opencode/openteam-telemetry.json
7
7
  * so a partially corrupted telemetry file never throws.
8
8
  */
9
9
  export declare function parseCostRecordsJsonl(text: string): CostRecord[];
10
- export type ReadCostRecordsDeps = {
11
- readFile?: typeof readFile;
12
- };
13
- export declare function readCostRecords(path: string, deps?: ReadCostRecordsDeps): Promise<CostRecord[]>;
10
+ export declare function readCostRecords(path: string, storage?: StorageProvider): Promise<CostRecord[]>;
14
11
  //# sourceMappingURL=read.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/telemetry/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,SAAS,CAAC;AAE5D,eAAO,MAAM,sBAAsB,uCAAuC,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAuBhE;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC;CAC5B,CAAC;AAWF,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,UAAU,EAAE,CAAC,CAYvB"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/telemetry/read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,SAAS,CAAC;AAE5D,eAAO,MAAM,sBAAsB,uCAAuC,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAuBhE;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,eAAwD,GAChE,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvB"}
@@ -3,6 +3,7 @@ import type { ConsoleConfig } from "../config/schema";
3
3
  import type { ConsoleClient } from "../console/opencodeClient";
4
4
  import type { PtyClient } from "../console/pty";
5
5
  import type { ConsoleInputs } from "../console/state";
6
+ import { type StorageRouteDeps } from "./storageRoute";
6
7
  export type ConsoleServerDeps = {
7
8
  /** Relee las fuentes y produce los inputs crudos del console. */
8
9
  readSnapshot: () => Promise<ConsoleInputs>;
@@ -20,6 +21,11 @@ export type ConsoleServerDeps = {
20
21
  createClient: (endpoint: string) => ConsoleClient;
21
22
  createPtyClient?: (endpoint: string) => PtyClient;
22
23
  };
24
+ /**
25
+ * Endpoint remoto de storage (`/storage/*`). Opcional y opt-in: expone el
26
+ * estado del equipo autenticado con token para una Console remota vía tunnel.
27
+ */
28
+ storageApi?: StorageRouteDeps;
23
29
  };
24
30
  export type ConsoleServer = {
25
31
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,IAAI,gBAAgB,EAIjC,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAatD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iEAAiE;IACjE,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,EAAE,aAAa,CAAC;IACtB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,gBAAgB,CAAC;IACvC,sCAAsC;IACtC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,8EAA8E;IAC9E,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,OAAO,CAAC;QACzB,+DAA+D;QAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;QAClD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;KACnD,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AA2DF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,aAAa,CAAC,CA4HxB"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,IAAI,gBAAgB,EAIjC,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAW3E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iEAAiE;IACjE,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,EAAE,aAAa,CAAC;IACtB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,gBAAgB,CAAC;IACvC,sCAAsC;IACtC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,8EAA8E;IAC9E,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,OAAO,CAAC;QACzB,+DAA+D;QAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;QAClD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;KACnD,CAAC;IACF;;;OAGG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AA2DF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,aAAa,CAAC,CAmIxB"}
@@ -5,6 +5,7 @@ import type { ConsoleClient } from "../console/opencodeClient";
5
5
  import type { PtyClient } from "../console/pty";
6
6
  import type { CommitView } from "../console/types";
7
7
  import type { StorageProvider } from "../storage/provider";
8
+ import type { StorageRouteDeps } from "./storageRoute";
8
9
  export type ConsoleRuntimeDeps = {
9
10
  config: ConsoleConfig;
10
11
  /** Directorio de logs de sesión (`sessions/*.jsonl`). */
@@ -31,6 +32,8 @@ export type ConsoleRuntimeDeps = {
31
32
  createClient: (endpoint: string) => ConsoleClient;
32
33
  createPtyClient?: (endpoint: string) => PtyClient;
33
34
  };
35
+ /** Endpoint remoto de storage (`/storage/*`). Opcional y opt-in. */
36
+ storageApi?: StorageRouteDeps;
34
37
  /** Inyectables para tests. */
35
38
  serve?: typeof import("./server").createConsoleServer;
36
39
  watch?: (path: string, listener: () => void) => ReturnType<typeof fsWatch>;
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/web/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAM3D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACtD,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACtD,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,sEAAsE;IACtE,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;QAClD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;KACnD,CAAC;IACF,8BAA8B;IAC9B,KAAK,CAAC,EAAE,cAAc,UAAU,EAAE,mBAAmB,CAAC;IACtD,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;IAC3E,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,cAAc,CAAC,CAEzB"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/web/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACtD,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACtD,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,sEAAsE;IACtE,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;QAClD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;KACnD,CAAC;IACF,oEAAoE;IACpE,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,cAAc,UAAU,EAAE,mBAAmB,CAAC;IACtD,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;IAC3E,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,cAAc,CAAC,CAEzB"}
@@ -0,0 +1,36 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { StorageProvider } from "../storage/provider";
3
+ /**
4
+ * Endpoint HTTP que expone un `StorageProvider` sobre la red (§ Fase 4). Permite
5
+ * que una Console/sesión remota lea el estado del equipo a través del tunnel ya
6
+ * existente, reutilizando el token efímero de la Console.
7
+ *
8
+ * Seguridad:
9
+ * - Exige el token (bearer `Authorization` o `?token=`), como el resto de la
10
+ * Console. Sin token válido → 401.
11
+ * - `readOnly` (por defecto activo cuando se expone remoto) rechaza cualquier
12
+ * mutación (`write`/`append`/`mkdir`/`delete`) con 403.
13
+ * - `allowPrefixes` restringe las rutas accesibles a un allowlist normalizado;
14
+ * fuera de él → 403. Así solo se expone lo pactado (sessions/decisions/backlog/
15
+ * agentes), nunca ficheros arbitrarios del disco.
16
+ *
17
+ * El storage de openteam solo contiene telemetría hasheada y artefactos Markdown
18
+ * del equipo: nunca prompts crudos ni PII.
19
+ */
20
+ export type StorageRouteDeps = {
21
+ storage: StorageProvider;
22
+ token: string;
23
+ /** Si es `true`, rechaza toda mutación con 403. Por defecto `false`. */
24
+ readOnly?: boolean;
25
+ /**
26
+ * Allowlist de prefijos virtuales accesibles. Si es `undefined`, se permite
27
+ * cualquier ruta (útil en tests). En producción se acota al estado del equipo.
28
+ */
29
+ allowPrefixes?: readonly string[];
30
+ };
31
+ /**
32
+ * Enruta las peticiones de `/storage/...`. Devuelve `true` si la petición fue
33
+ * atendida (y respondida), `false` para que el servidor siga con sus rutas.
34
+ */
35
+ export declare function handleStorageRoute(request: IncomingMessage, response: ServerResponse, url: URL, deps: StorageRouteDeps): Promise<boolean>;
36
+ //# sourceMappingURL=storageRoute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storageRoute.d.ts","sourceRoot":"","sources":["../../src/web/storageRoute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAgKF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,OAAO,CAAC,CA4ClB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmanuelcorral/openteam",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "description": "Plugin opencode de routing coste-consciente local-first con orquestación Squad.",
5
5
  "license": "MIT",
6
6
  "author": "Jose Manuel Corral",