@jmanuelcorral/openteam 0.1.28 → 0.1.30

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.
@@ -3,6 +3,7 @@ import type { OpenTeamConfig } from "../config/schema";
3
3
  import { type ConsoleClient } from "../console/opencodeClient";
4
4
  import { type PtyClient } from "../console/pty";
5
5
  import type { CommitView } from "../console/types";
6
+ import type { StorageProvider } from "../storage/provider";
6
7
  import type { ConsoleRuntime, ConsoleRuntimeDeps } from "../web/start";
7
8
  /** Dependencias inyectables del launcher `openteam console`. */
8
9
  export type ConsoleServeDeps = {
@@ -15,8 +16,8 @@ export type ConsoleServeDeps = {
15
16
  agentDir: string;
16
17
  /** Telemetry legacy a fusionar como route events. Opcional. */
17
18
  legacyTelemetryPath?: string;
18
- readText: (path: string) => Promise<string | undefined>;
19
- listFiles: (dir: string) => Promise<string[]>;
19
+ /** Backend de persistencia (logs de sesión, decisiones, backlog). */
20
+ storage: StorageProvider;
20
21
  listAgentFiles: (dir: string) => Promise<AgentFile[]>;
21
22
  now: () => string;
22
23
  gitLastCommit?: () => Promise<CommitView | undefined>;
@@ -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,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,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,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,CAyE7B"}
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"}
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 mkdir2, readdir, readFile, writeFile as writeFile2 } from "node:fs/promises";
6
- import { dirname as dirname2, join as join2 } 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
@@ -1181,6 +1180,38 @@ function aggregateEvents(events) {
1181
1180
  };
1182
1181
  }
1183
1182
 
1183
+ // src/storage/path.ts
1184
+ class StoragePathError extends Error {
1185
+ constructor(message) {
1186
+ super(message);
1187
+ this.name = "StoragePathError";
1188
+ }
1189
+ }
1190
+ function normalizeVirtualPath(input) {
1191
+ const segments = [];
1192
+ for (const rawSegment of input.split(/[\\/]+/)) {
1193
+ if (rawSegment === "" || rawSegment === ".") {
1194
+ continue;
1195
+ }
1196
+ if (rawSegment === "..") {
1197
+ if (segments.length === 0) {
1198
+ throw new StoragePathError(`la ruta "${input}" escapa por encima de la raíz`);
1199
+ }
1200
+ segments.pop();
1201
+ continue;
1202
+ }
1203
+ segments.push(rawSegment);
1204
+ }
1205
+ return segments.join("/");
1206
+ }
1207
+ function joinVirtualPath(...segments) {
1208
+ return normalizeVirtualPath(segments.join("/"));
1209
+ }
1210
+ function splitVirtualPath(path) {
1211
+ const normalized = normalizeVirtualPath(path);
1212
+ return normalized === "" ? [] : normalized.split("/");
1213
+ }
1214
+
1184
1215
  // src/telemetry/events.ts
1185
1216
  import { z as z4 } from "zod";
1186
1217
 
@@ -1407,6 +1438,101 @@ var OpenTeamEventSchema = z4.discriminatedUnion("type", [
1407
1438
  SessionEndpointEventSchema
1408
1439
  ]);
1409
1440
 
1441
+ // src/storage/fsStorageProvider.ts
1442
+ import {
1443
+ appendFile,
1444
+ mkdir,
1445
+ readdir,
1446
+ readFile,
1447
+ rm,
1448
+ stat,
1449
+ writeFile
1450
+ } from "node:fs/promises";
1451
+ import { dirname, join } from "node:path";
1452
+ function isMissing(error) {
1453
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
1454
+ }
1455
+ function createFsStorageProvider(root) {
1456
+ function toDisk(path) {
1457
+ return join(root, ...splitVirtualPath(path));
1458
+ }
1459
+ return {
1460
+ async read(path) {
1461
+ try {
1462
+ return await readFile(toDisk(path), "utf8");
1463
+ } catch (error) {
1464
+ if (isMissing(error)) {
1465
+ return;
1466
+ }
1467
+ throw error;
1468
+ }
1469
+ },
1470
+ async write(path, content) {
1471
+ const disk = toDisk(path);
1472
+ await mkdir(dirname(disk), { recursive: true });
1473
+ await writeFile(disk, content, "utf8");
1474
+ },
1475
+ async append(path, content) {
1476
+ const disk = toDisk(path);
1477
+ await mkdir(dirname(disk), { recursive: true });
1478
+ await appendFile(disk, content, "utf8");
1479
+ },
1480
+ async exists(path) {
1481
+ try {
1482
+ await stat(toDisk(path));
1483
+ return true;
1484
+ } catch (error) {
1485
+ if (isMissing(error)) {
1486
+ return false;
1487
+ }
1488
+ throw error;
1489
+ }
1490
+ },
1491
+ async list(dir) {
1492
+ try {
1493
+ const names = await readdir(toDisk(dir));
1494
+ return names.sort();
1495
+ } catch (error) {
1496
+ if (isMissing(error)) {
1497
+ return [];
1498
+ }
1499
+ throw error;
1500
+ }
1501
+ },
1502
+ async isDirectory(path) {
1503
+ try {
1504
+ return (await stat(toDisk(path))).isDirectory();
1505
+ } catch (error) {
1506
+ if (isMissing(error)) {
1507
+ return false;
1508
+ }
1509
+ throw error;
1510
+ }
1511
+ },
1512
+ async mkdir(dir) {
1513
+ await mkdir(toDisk(dir), { recursive: true });
1514
+ },
1515
+ async delete(path) {
1516
+ await rm(toDisk(path), { force: true });
1517
+ },
1518
+ async stat(path) {
1519
+ try {
1520
+ const stats = await stat(toDisk(path));
1521
+ return {
1522
+ size: stats.size,
1523
+ mtimeMs: stats.mtimeMs,
1524
+ isDirectory: stats.isDirectory()
1525
+ };
1526
+ } catch (error) {
1527
+ if (isMissing(error)) {
1528
+ return;
1529
+ }
1530
+ throw error;
1531
+ }
1532
+ }
1533
+ };
1534
+ }
1535
+
1410
1536
  // src/telemetry/types.ts
1411
1537
  import { z as z5 } from "zod";
1412
1538
  var CostRecordSchema = z5.object({
@@ -1453,9 +1579,6 @@ function parseCostRecordsJsonl(text) {
1453
1579
  // src/telemetry/eventLog.ts
1454
1580
  var DEFAULT_SESSIONS_DIR = ".opencode/openteam/sessions";
1455
1581
  var LEGACY_SESSION_ID = "legacy";
1456
- function defaultJoin(dir, file) {
1457
- return dir.endsWith("/") ? `${dir}${file}` : `${dir}/${file}`;
1458
- }
1459
1582
  function parseEventsJsonl(text) {
1460
1583
  const events = [];
1461
1584
  for (const line of text.split(`
@@ -1536,15 +1659,14 @@ async function readRouteCostRecords(dir, deps) {
1536
1659
  return records;
1537
1660
  }
1538
1661
  async function readSessionEvents(dir, deps) {
1539
- const join = deps.join ?? defaultJoin;
1540
- const files = (await deps.listFiles(dir)).filter((file) => file.endsWith(".jsonl"));
1662
+ const files = (await deps.storage.list(dir)).filter((file) => file.endsWith(".jsonl"));
1541
1663
  const perFile = await Promise.all(files.map(async (file) => {
1542
- const text = await deps.readText(join(dir, file));
1664
+ const text = await deps.storage.read(joinVirtualPath(dir, file));
1543
1665
  return text === undefined ? [] : parseEventsJsonl(text);
1544
1666
  }));
1545
1667
  const events = perFile.flat();
1546
1668
  if (deps.legacyTelemetryPath !== undefined) {
1547
- const legacyText = await deps.readText(deps.legacyTelemetryPath);
1669
+ const legacyText = await deps.storage.read(deps.legacyTelemetryPath);
1548
1670
  if (legacyText !== undefined) {
1549
1671
  for (const record of parseCostRecordsJsonl(legacyText)) {
1550
1672
  events.push(costRecordToRouteEvent(record));
@@ -2297,15 +2419,14 @@ function parseDecisionsMarkdown(text, options = {}) {
2297
2419
  // src/web/snapshot.ts
2298
2420
  function createSnapshotReader(deps, paths, context = {}) {
2299
2421
  const readEventsDeps = {
2300
- listFiles: deps.listFiles,
2301
- readText: deps.readText,
2422
+ storage: deps.storage,
2302
2423
  ...paths.legacyTelemetryPath !== undefined ? { legacyTelemetryPath: paths.legacyTelemetryPath } : {}
2303
2424
  };
2304
2425
  return async () => {
2305
2426
  const [sessionEvents, decisionsText, backlogText, agentFiles, lastCommit] = await Promise.all([
2306
2427
  readSessionEvents(paths.sessionsDir, readEventsDeps),
2307
- deps.readText(paths.decisionsPath),
2308
- deps.readText(paths.backlogPath),
2428
+ deps.storage.read(paths.decisionsPath),
2429
+ deps.storage.read(paths.backlogPath),
2309
2430
  deps.listAgentFiles(paths.agentDir),
2310
2431
  deps.gitLastCommit?.() ?? Promise.resolve(undefined)
2311
2432
  ]);
@@ -2378,8 +2499,7 @@ async function createConsoleRuntime(deps) {
2378
2499
  const backlogPath = deps.backlogPath ?? DEFAULT_BACKLOG_PATH;
2379
2500
  const decisionsPath = deps.decisionsPath ?? DEFAULT_DECISIONS_PATH;
2380
2501
  const readSnapshot = createSnapshotReader({
2381
- readText: deps.readText,
2382
- listFiles: deps.listFiles,
2502
+ storage: deps.storage,
2383
2503
  listAgentFiles: deps.listAgentFiles,
2384
2504
  now: deps.now,
2385
2505
  ...deps.gitLastCommit !== undefined ? { gitLastCommit: deps.gitLastCommit } : {}
@@ -2445,8 +2565,7 @@ async function runConsoleServe(deps, options) {
2445
2565
  backlogPath: deps.backlogPath,
2446
2566
  agentDir: deps.agentDir,
2447
2567
  ...deps.legacyTelemetryPath !== undefined ? { legacyTelemetryPath: deps.legacyTelemetryPath } : {},
2448
- readText: deps.readText,
2449
- listFiles: deps.listFiles,
2568
+ storage: deps.storage,
2450
2569
  listAgentFiles: deps.listAgentFiles,
2451
2570
  now: deps.now,
2452
2571
  ...deps.gitLastCommit !== undefined ? { gitLastCommit: deps.gitLastCommit } : {},
@@ -3947,22 +4066,17 @@ ${HELP}`
3947
4066
  }
3948
4067
 
3949
4068
  // src/commands/setup.ts
3950
- import { join } from "node:path";
4069
+ import { join as join2 } from "node:path";
3951
4070
 
3952
4071
  // src/config/persist.ts
3953
- import { mkdir, writeFile } from "node:fs/promises";
3954
- import { dirname } from "node:path";
3955
4072
  var DEFAULT_CONFIG_PATH = ".opencode/openteam.json";
3956
4073
  function serializeOpenTeamConfig(config) {
3957
4074
  const validated = OpenTeamConfigSchema.parse(config);
3958
4075
  return `${JSON.stringify(validated, null, 2)}
3959
4076
  `;
3960
4077
  }
3961
- async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, deps = {}) {
3962
- const mkdirFn = deps.mkdir ?? mkdir;
3963
- const writeFileFn = deps.writeFile ?? writeFile;
3964
- await mkdirFn(dirname(path), { recursive: true });
3965
- await writeFileFn(path, serializeOpenTeamConfig(config), "utf8");
4078
+ async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, storage = createFsStorageProvider(process.cwd())) {
4079
+ await storage.write(path, serializeOpenTeamConfig(config));
3966
4080
  }
3967
4081
 
3968
4082
  // src/commands/slashCommand.ts
@@ -4436,9 +4550,9 @@ async function runSetup(deps) {
4436
4550
  const opencodeConfig = buildOpencodeConfig(answers);
4437
4551
  const orchestratorAgent = buildOrchestratorAgent(frontier, { yolo });
4438
4552
  const slashCommands = buildOpenteamCommands();
4439
- const openTeamPath = join(deps.cwd, DEFAULT_CONFIG_PATH);
4440
- const opencodePath = join(deps.cwd, OPENCODE_CONFIG_PATH);
4441
- const agentPath = join(deps.cwd, ORCHESTRATOR_AGENT_PATH);
4553
+ const openTeamPath = join2(deps.cwd, DEFAULT_CONFIG_PATH);
4554
+ const opencodePath = join2(deps.cwd, OPENCODE_CONFIG_PATH);
4555
+ const agentPath = join2(deps.cwd, ORCHESTRATOR_AGENT_PATH);
4442
4556
  const existing = [];
4443
4557
  if (await deps.fileExists(openTeamPath)) {
4444
4558
  existing.push(DEFAULT_CONFIG_PATH);
@@ -4450,7 +4564,7 @@ async function runSetup(deps) {
4450
4564
  existing.push(ORCHESTRATOR_AGENT_PATH);
4451
4565
  }
4452
4566
  for (const command of slashCommands) {
4453
- if (await deps.fileExists(join(deps.cwd, command.path))) {
4567
+ if (await deps.fileExists(join2(deps.cwd, command.path))) {
4454
4568
  existing.push(command.path);
4455
4569
  }
4456
4570
  }
@@ -4468,7 +4582,7 @@ async function runSetup(deps) {
4468
4582
  await deps.writeFile(opencodePath, serializeOpencodeConfig(opencodeConfig));
4469
4583
  await deps.writeFile(agentPath, orchestratorAgent);
4470
4584
  for (const command of slashCommands) {
4471
- await deps.writeFile(join(deps.cwd, command.path), command.contents);
4585
+ await deps.writeFile(join2(deps.cwd, command.path), command.contents);
4472
4586
  }
4473
4587
  const enabledSummary = runtimes.filter((runtime) => runtime.enabled).map((runtime) => {
4474
4588
  const remote = runtime.baseURL !== undefined && !runtime.baseURL.includes("localhost") && !runtime.baseURL.includes("127.0.0.1") ? ` @ ${runtime.baseURL}` : "";
@@ -4525,9 +4639,7 @@ function createGitLastCommit(exec) {
4525
4639
  // src/cli.ts
4526
4640
  var execFileAsync = promisify(execFile);
4527
4641
  var AGENT_DIR = dirname2(ORCHESTRATOR_AGENT_PATH);
4528
- function isMissingFile(error) {
4529
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
4530
- }
4642
+ var storage = createFsStorageProvider(process.cwd());
4531
4643
  var nodeExec = async (command, args) => {
4532
4644
  try {
4533
4645
  const { stdout, stderr } = await execFileAsync(command, [...args]);
@@ -4542,35 +4654,8 @@ var nodeExec = async (command, args) => {
4542
4654
  }
4543
4655
  };
4544
4656
  async function loadConfig(path) {
4545
- try {
4546
- const content = await readFile(path, "utf8");
4547
- return loadOpenTeamConfig(JSON.parse(content));
4548
- } catch (error) {
4549
- if (isMissingFile(error)) {
4550
- return loadOpenTeamConfig({});
4551
- }
4552
- throw error;
4553
- }
4554
- }
4555
- async function readTextOptional(path) {
4556
- try {
4557
- return await readFile(path, "utf8");
4558
- } catch (error) {
4559
- if (isMissingFile(error)) {
4560
- return;
4561
- }
4562
- throw error;
4563
- }
4564
- }
4565
- async function listDirFiles(dir) {
4566
- try {
4567
- return await readdir(dir);
4568
- } catch (error) {
4569
- if (isMissingFile(error)) {
4570
- return [];
4571
- }
4572
- throw error;
4573
- }
4657
+ const content = await storage.read(path);
4658
+ return content === undefined ? loadOpenTeamConfig({}) : loadOpenTeamConfig(JSON.parse(content));
4574
4659
  }
4575
4660
  async function openBrowser(url) {
4576
4661
  if (process.platform === "win32") {
@@ -4590,41 +4675,24 @@ function waitForSignal() {
4590
4675
  }
4591
4676
  var deps = {
4592
4677
  loadConfig,
4593
- saveConfig: (config, path) => writeOpenTeamConfigFile(config, path),
4678
+ saveConfig: (config, path) => writeOpenTeamConfigFile(config, path, storage),
4594
4679
  readOpencodeConfig: async (path) => {
4595
- try {
4596
- const content = await readFile(path, "utf8");
4597
- return JSON.parse(content);
4598
- } catch (error) {
4599
- if (isMissingFile(error)) {
4600
- return;
4601
- }
4602
- throw error;
4603
- }
4680
+ const content = await storage.read(path);
4681
+ return content === undefined ? undefined : JSON.parse(content);
4604
4682
  },
4605
4683
  writeOpencodeConfig: async (config, path) => {
4606
- await mkdir2(dirname2(path), { recursive: true });
4607
- await writeFile2(path, `${JSON.stringify(config, null, 2)}
4608
- `, "utf8");
4684
+ await storage.write(path, `${JSON.stringify(config, null, 2)}
4685
+ `);
4609
4686
  },
4610
4687
  writeOrchestratorAgent: async (contents, path) => {
4611
- await mkdir2(dirname2(path), { recursive: true });
4612
- await writeFile2(path, contents, "utf8");
4688
+ await storage.write(path, contents);
4613
4689
  },
4614
4690
  listAgentFiles: async (dir) => {
4615
- let entries;
4616
- try {
4617
- entries = await readdir(dir);
4618
- } catch (error) {
4619
- if (isMissingFile(error)) {
4620
- return [];
4621
- }
4622
- throw error;
4623
- }
4691
+ const entries = await storage.list(dir);
4624
4692
  const mdFiles = entries.filter((entry) => entry.endsWith(".md"));
4625
4693
  return Promise.all(mdFiles.map(async (entry) => ({
4626
4694
  name: entry.replace(/\.md$/, ""),
4627
- contents: await readFile(join2(dir, entry), "utf8")
4695
+ contents: await storage.read(joinVirtualPath(dir, entry)) ?? ""
4628
4696
  })));
4629
4697
  },
4630
4698
  probe: (config) => {
@@ -4636,8 +4704,7 @@ var deps = {
4636
4704
  return registry.probe(config.local.runtimes);
4637
4705
  },
4638
4706
  readTelemetry: (path) => readRouteCostRecords(DEFAULT_SESSIONS_DIR, {
4639
- listFiles: listDirFiles,
4640
- readText: readTextOptional,
4707
+ storage,
4641
4708
  legacyTelemetryPath: path
4642
4709
  }),
4643
4710
  configPath: DEFAULT_CONFIG_PATH,
@@ -4654,17 +4721,9 @@ function createSetupDeps() {
4654
4721
  loadFrontierProfiles: createLoadFrontierProfiles(),
4655
4722
  prompt: clackPrompter,
4656
4723
  writeFile: async (path, contents) => {
4657
- await mkdir2(dirname2(path), { recursive: true });
4658
- await writeFile2(path, contents, "utf8");
4724
+ await storage.write(path, contents);
4659
4725
  },
4660
- fileExists: async (path) => {
4661
- try {
4662
- await access(path);
4663
- return true;
4664
- } catch {
4665
- return false;
4666
- }
4667
- }
4726
+ fileExists: (path) => storage.exists(path)
4668
4727
  };
4669
4728
  }
4670
4729
  async function main() {
@@ -4689,8 +4748,7 @@ async function main() {
4689
4748
  backlogPath: DEFAULT_BACKLOG_PATH,
4690
4749
  agentDir: AGENT_DIR,
4691
4750
  legacyTelemetryPath: DEFAULT_TELEMETRY_PATH,
4692
- readText: readTextOptional,
4693
- listFiles: listDirFiles,
4751
+ storage,
4694
4752
  listAgentFiles: deps.listAgentFiles,
4695
4753
  now: () => new Date().toISOString(),
4696
4754
  gitLastCommit: createGitLastCommit(nodeExec),
@@ -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"}
package/dist/index.d.ts CHANGED
@@ -1,25 +1,14 @@
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";
5
+ import type { StorageProvider } from "./storage/provider";
6
6
  import { type EventSink } from "./telemetry/eventLog";
7
- type FileAppenderDeps = {
8
- mkdir?: typeof mkdir;
9
- appendFile?: typeof appendFile;
10
- };
11
7
  export declare function logAvailabilityRefreshError(error: unknown): void;
12
8
  export declare function logTelemetryError(error: unknown): void;
13
- export declare function createFileAppender(filePath: string, deps?: FileAppenderDeps): (line: string) => Promise<void>;
14
- /** Appender genérico: crea el directorio destino y añade una línea al fichero. */
15
- export declare function createPathAppender(deps?: FileAppenderDeps): (path: string, line: string) => Promise<void>;
16
- /**
17
- * Crea el sink de eventos por sesión (`<sessionsDir>/<sessionID>.jsonl`). Si la
18
- * telemetría está desactivada devuelve un sink no-op.
19
- */
20
- export declare function createEventSink(rawOptions: unknown): EventSink;
9
+ export declare function createEventSink(rawOptions: unknown, storage?: StorageProvider): EventSink;
21
10
  export declare function isMissingFile(error: unknown): boolean;
22
- export declare function createCliDeps(config: OpenTeamConfig, registry: RuntimeRegistry, telemetryPath: string, sessionsDir?: string): CliDeps;
11
+ export declare function createCliDeps(config: OpenTeamConfig, registry: RuntimeRegistry, telemetryPath: string, sessionsDir?: string, storage?: StorageProvider): CliDeps;
23
12
  export declare const server: Plugin;
24
13
  declare const plugin: PluginModule;
25
14
  export default plugin;
@@ -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;AAUnD,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,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,IAAI,GAAE,gBAAqB,GAC1B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAQ/C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,OAAO,GAAG,SAAS,CAa9D;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,GACzC,OAAO,CAmFT;AAED,eAAO,MAAM,MAAM,EAAE,MAmEpB,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,
4
- mkdir as mkdir2,
5
- readdir,
6
- readFile,
7
- writeFile as writeFile2
8
- } from "node:fs/promises";
9
- import { dirname as dirname2, join } 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";
@@ -309,11 +427,8 @@ function serializeOpenTeamConfig(config) {
309
427
  return `${JSON.stringify(validated, null, 2)}
310
428
  `;
311
429
  }
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");
430
+ async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, storage = createFsStorageProvider(process.cwd())) {
431
+ await storage.write(path, serializeOpenTeamConfig(config));
317
432
  }
318
433
 
319
434
  // src/commands/setup.ts
@@ -2092,17 +2207,13 @@ function sessionFileName(sessionID) {
2092
2207
  const safe = sessionID.replace(/[^A-Za-z0-9._-]/g, "_");
2093
2208
  return `${safe}.jsonl`;
2094
2209
  }
2095
- function defaultJoin(dir, file) {
2096
- return dir.endsWith("/") ? `${dir}${file}` : `${dir}/${file}`;
2097
- }
2098
2210
  function createEventLogSink(deps) {
2099
- const join = deps.join ?? defaultJoin;
2100
2211
  return {
2101
2212
  emit: async (event) => {
2102
2213
  try {
2103
2214
  const parsed = OpenTeamEventSchema.parse(event);
2104
- const path = join(deps.dir, sessionFileName(parsed.sessionID));
2105
- await deps.appendLine(path, `${JSON.stringify(parsed)}
2215
+ const path = joinVirtualPath(deps.dir, sessionFileName(parsed.sessionID));
2216
+ await deps.storage.append(path, `${JSON.stringify(parsed)}
2106
2217
  `);
2107
2218
  } catch (error) {
2108
2219
  deps.onError?.(error);
@@ -2193,15 +2304,14 @@ async function readRouteCostRecords(dir, deps) {
2193
2304
  return records;
2194
2305
  }
2195
2306
  async function readSessionEvents(dir, deps) {
2196
- const join = deps.join ?? defaultJoin;
2197
- const files = (await deps.listFiles(dir)).filter((file) => file.endsWith(".jsonl"));
2307
+ const files = (await deps.storage.list(dir)).filter((file) => file.endsWith(".jsonl"));
2198
2308
  const perFile = await Promise.all(files.map(async (file) => {
2199
- const text = await deps.readText(join(dir, file));
2309
+ const text = await deps.storage.read(joinVirtualPath(dir, file));
2200
2310
  return text === undefined ? [] : parseEventsJsonl(text);
2201
2311
  }));
2202
2312
  const events = perFile.flat();
2203
2313
  if (deps.legacyTelemetryPath !== undefined) {
2204
- const legacyText = await deps.readText(deps.legacyTelemetryPath);
2314
+ const legacyText = await deps.storage.read(deps.legacyTelemetryPath);
2205
2315
  if (legacyText !== undefined) {
2206
2316
  for (const record of parseCostRecordsJsonl(legacyText)) {
2207
2317
  events.push(costRecordToRouteEvent(record));
@@ -2368,107 +2478,49 @@ function telemetryOptions(rawOptions) {
2368
2478
  sessionsDir: configuredSessionsDir
2369
2479
  };
2370
2480
  }
2371
- function createFileAppender(filePath, deps = {}) {
2372
- const mkdirFn = deps.mkdir ?? mkdir2;
2373
- const appendFileFn = deps.appendFile ?? appendFile;
2374
- return async (line) => {
2375
- await mkdirFn(dirname2(filePath), { recursive: true });
2376
- await appendFileFn(filePath, line, "utf8");
2377
- };
2378
- }
2379
- function createPathAppender(deps = {}) {
2380
- const mkdirFn = deps.mkdir ?? mkdir2;
2381
- const appendFileFn = deps.appendFile ?? appendFile;
2382
- return async (path, line) => {
2383
- await mkdirFn(dirname2(path), { recursive: true });
2384
- await appendFileFn(path, line, "utf8");
2385
- };
2386
- }
2387
- function createEventSink(rawOptions) {
2481
+ function createEventSink(rawOptions, storage = createFsStorageProvider(process.cwd())) {
2388
2482
  const options = telemetryOptions(rawOptions);
2389
2483
  if (!options.enabled) {
2390
2484
  return createNullEventSink();
2391
2485
  }
2392
2486
  return createEventLogSink({
2393
2487
  dir: options.sessionsDir,
2394
- appendLine: createPathAppender(),
2395
- join,
2488
+ storage,
2396
2489
  onError: logTelemetryError
2397
2490
  });
2398
2491
  }
2399
2492
  function isMissingFile(error) {
2400
2493
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
2401
2494
  }
2402
- function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SESSIONS_DIR) {
2495
+ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SESSIONS_DIR, storage = createFsStorageProvider(process.cwd())) {
2403
2496
  return {
2404
2497
  loadConfig: async (path) => {
2405
- try {
2406
- return loadOpenTeamConfig(JSON.parse(await readFile(path, "utf8")));
2407
- } catch (error) {
2408
- if (isMissingFile(error)) {
2409
- return config;
2410
- }
2411
- throw error;
2412
- }
2498
+ const content = await storage.read(path);
2499
+ return content === undefined ? config : loadOpenTeamConfig(JSON.parse(content));
2413
2500
  },
2414
- saveConfig: (nextConfig, path) => writeOpenTeamConfigFile(nextConfig, path),
2501
+ saveConfig: (nextConfig, path) => writeOpenTeamConfigFile(nextConfig, path, storage),
2415
2502
  readOpencodeConfig: async (path) => {
2416
- try {
2417
- return JSON.parse(await readFile(path, "utf8"));
2418
- } catch (error) {
2419
- if (isMissingFile(error)) {
2420
- return;
2421
- }
2422
- throw error;
2423
- }
2503
+ const content = await storage.read(path);
2504
+ return content === undefined ? undefined : JSON.parse(content);
2424
2505
  },
2425
2506
  writeOpencodeConfig: async (nextConfig, path) => {
2426
- await mkdir2(dirname2(path), { recursive: true });
2427
- await writeFile2(path, `${JSON.stringify(nextConfig, null, 2)}
2428
- `, "utf8");
2507
+ await storage.write(path, `${JSON.stringify(nextConfig, null, 2)}
2508
+ `);
2429
2509
  },
2430
2510
  writeOrchestratorAgent: async (contents, path) => {
2431
- await mkdir2(dirname2(path), { recursive: true });
2432
- await writeFile2(path, contents, "utf8");
2511
+ await storage.write(path, contents);
2433
2512
  },
2434
2513
  listAgentFiles: async (dir) => {
2435
- let entries;
2436
- try {
2437
- entries = await readdir(dir);
2438
- } catch (error) {
2439
- if (isMissingFile(error)) {
2440
- return [];
2441
- }
2442
- throw error;
2443
- }
2514
+ const entries = await storage.list(dir);
2444
2515
  const mdFiles = entries.filter((entry) => entry.endsWith(".md"));
2445
2516
  return Promise.all(mdFiles.map(async (entry) => ({
2446
2517
  name: entry.replace(/\.md$/, ""),
2447
- contents: await readFile(join(dir, entry), "utf8")
2518
+ contents: await storage.read(joinVirtualPath(dir, entry)) ?? ""
2448
2519
  })));
2449
2520
  },
2450
2521
  probe: (nextConfig) => registry.probe(nextConfig.local.runtimes),
2451
2522
  readTelemetry: (path) => readRouteCostRecords(sessionsDir, {
2452
- listFiles: async (dir) => {
2453
- try {
2454
- return await readdir(dir);
2455
- } catch (error) {
2456
- if (isMissingFile(error)) {
2457
- return [];
2458
- }
2459
- throw error;
2460
- }
2461
- },
2462
- readText: async (filePath) => {
2463
- try {
2464
- return await readFile(filePath, "utf8");
2465
- } catch (error) {
2466
- if (isMissingFile(error)) {
2467
- return;
2468
- }
2469
- throw error;
2470
- }
2471
- },
2523
+ storage,
2472
2524
  legacyTelemetryPath: path
2473
2525
  }),
2474
2526
  configPath: DEFAULT_CONFIG_PATH,
@@ -2493,9 +2545,10 @@ var server = async (ctx, rawOptions) => {
2493
2545
  cache.refresh();
2494
2546
  const telemetryPath = telemetryOptions(rawOptions).path;
2495
2547
  const sessionsDir = telemetryOptions(rawOptions).sessionsDir;
2496
- const sink = createEventSink(rawOptions);
2548
+ const storage = createFsStorageProvider(process.cwd());
2549
+ const sink = createEventSink(rawOptions, storage);
2497
2550
  const hooks = createHooks(config, cache.get, { sink });
2498
- const cliDeps = createCliDeps(config, registry, telemetryPath, sessionsDir);
2551
+ const cliDeps = createCliDeps(config, registry, telemetryPath, sessionsDir, storage);
2499
2552
  const toolcalls = createToolcallTracker({ sink });
2500
2553
  const now = () => Date.now();
2501
2554
  const announcedSessions = new Set;
@@ -2554,8 +2607,6 @@ export {
2554
2607
  logAvailabilityRefreshError,
2555
2608
  isMissingFile,
2556
2609
  src_default as default,
2557
- createPathAppender,
2558
- createFileAppender,
2559
2610
  createEventSink,
2560
2611
  createCliDeps
2561
2612
  };
@@ -1,3 +1,4 @@
1
+ import type { StorageProvider } from "../storage/provider";
1
2
  import { type OpenTeamEvent, type RouteEvent } from "./events";
2
3
  import type { CostRecord } from "./types";
3
4
  /** Directorio por defecto de los logs de sesión que alimentan el console. */
@@ -13,10 +14,8 @@ export declare function sessionFileName(sessionID: string): string;
13
14
  export type EventLogSinkDeps = {
14
15
  /** Directorio destino (`sessions/`). */
15
16
  dir: string;
16
- /** Añade una línea al fichero indicado (crea dir/fichero si hace falta). */
17
- appendLine: (path: string, line: string) => Promise<void> | void;
18
- /** Une segmentos de ruta (por defecto `node:path.join`). Inyectable en tests. */
19
- join?: (dir: string, file: string) => string;
17
+ /** Backend de persistencia (escribe con `append`). */
18
+ storage: StorageProvider;
20
19
  onError?: (error: unknown) => void;
21
20
  };
22
21
  /**
@@ -46,11 +45,8 @@ export declare function routeEventToCostRecord(event: RouteEvent): CostRecord;
46
45
  */
47
46
  export declare function readRouteCostRecords(dir: string, deps: ReadSessionEventsDeps): Promise<CostRecord[]>;
48
47
  export type ReadSessionEventsDeps = {
49
- /** Lista los ficheros del directorio; `[]` si no existe. */
50
- listFiles: (dir: string) => Promise<string[]>;
51
- /** Lee texto; `undefined` si el fichero no existe. */
52
- readText: (path: string) => Promise<string | undefined>;
53
- join?: (dir: string, file: string) => string;
48
+ /** Backend de persistencia (lista con `list`, lee con `read`). */
49
+ storage: StorageProvider;
54
50
  /** Telemetry legacy a fusionar como `route` events. Opcional. */
55
51
  legacyTelemetryPath?: string;
56
52
  };
@@ -1 +1 @@
1
- {"version":3,"file":"eventLog.d.ts","sourceRoot":"","sources":["../../src/telemetry/eventLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAElB,KAAK,UAAU,EAChB,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAElE,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,sEAAsE;AACtE,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACtD,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,4EAA4E;IAC5E,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjE,iFAAiF;IACjF,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,CAAC;AAMF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAapE;AAED,wBAAgB,mBAAmB,IAAI,SAAS,CAE/C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAmB9D;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAwBrE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAsBpE;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,UAAU,EAAE,CAAC,CASvB;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,4DAA4D;IAC5D,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,sDAAsD;IACtD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,aAAa,EAAE,CAAC,CAyB1B"}
1
+ {"version":3,"file":"eventLog.d.ts","sourceRoot":"","sources":["../../src/telemetry/eventLog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAEL,KAAK,aAAa,EAElB,KAAK,UAAU,EAChB,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAElE,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,sEAAsE;AACtE,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACtD,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAepE;AAED,wBAAgB,mBAAmB,IAAI,SAAS,CAE/C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAmB9D;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAwBrE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAsBpE;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,UAAU,EAAE,CAAC,CASvB;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,kEAAkE;IAClE,OAAO,EAAE,eAAe,CAAC;IACzB,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,aAAa,EAAE,CAAC,CAwB1B"}
@@ -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"}
@@ -1,12 +1,11 @@
1
1
  import type { AgentFile } from "../commands/agents";
2
2
  import type { ConsoleInputs } from "../console/state";
3
3
  import type { CommitView } from "../console/types";
4
+ import type { StorageProvider } from "../storage/provider";
4
5
  /** Dependencias de I/O que el driver inyecta para leer las fuentes del console. */
5
6
  export type SnapshotDeps = {
6
- /** Lee un fichero de texto; devuelve `undefined` si no existe (ENOENT). */
7
- readText: (path: string) => Promise<string | undefined>;
8
- /** Lista los nombres de fichero de un directorio; `[]` si no existe. */
9
- listFiles: (dir: string) => Promise<string[]>;
7
+ /** Backend de persistencia (logs de sesión, decisiones, backlog). */
8
+ storage: StorageProvider;
10
9
  /** Lista los ficheros `.md` de `.opencode/agent/`. */
11
10
  listAgentFiles: (dir: string) => Promise<AgentFile[]>;
12
11
  /** Reloj: ISO-8601. Fuera del core puro. */
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/web/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,oBAAoB,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQnD,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG;IACzB,2EAA2E;IAC3E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,wEAAwE;IACxE,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,sDAAsD;IACtD,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACtD,4CAA4C;IAC5C,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,aAAa,EACpB,OAAO,GAAE,eAAoB,GAC5B,MAAM,OAAO,CAAC,aAAa,CAAC,CAiD9B"}
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/web/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,oBAAoB,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAQ3D,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG;IACzB,qEAAqE;IACrE,OAAO,EAAE,eAAe,CAAC;IACzB,sDAAsD;IACtD,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACtD,4CAA4C;IAC5C,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,aAAa,EACpB,OAAO,GAAE,eAAoB,GAC5B,MAAM,OAAO,CAAC,aAAa,CAAC,CAgD9B"}
@@ -4,6 +4,7 @@ import type { ConsoleConfig } from "../config/schema";
4
4
  import type { ConsoleClient } from "../console/opencodeClient";
5
5
  import type { PtyClient } from "../console/pty";
6
6
  import type { CommitView } from "../console/types";
7
+ import type { StorageProvider } from "../storage/provider";
7
8
  export type ConsoleRuntimeDeps = {
8
9
  config: ConsoleConfig;
9
10
  /** Directorio de logs de sesión (`sessions/*.jsonl`). */
@@ -13,8 +14,8 @@ export type ConsoleRuntimeDeps = {
13
14
  backlogPath?: string;
14
15
  /** Telemetry legacy a fusionar como route events. Opcional. */
15
16
  legacyTelemetryPath?: string;
16
- readText: (path: string) => Promise<string | undefined>;
17
- listFiles: (dir: string) => Promise<string[]>;
17
+ /** Backend de persistencia (logs de sesión, decisiones, backlog). */
18
+ storage: StorageProvider;
18
19
  listAgentFiles: (dir: string) => Promise<AgentFile[]>;
19
20
  now: () => string;
20
21
  gitLastCommit?: () => Promise<CommitView | undefined>;
@@ -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;AAMnD,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,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,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;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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmanuelcorral/openteam",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
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",