@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.
- package/dist/cli/consoleServe.d.ts.map +1 -1
- package/dist/cli.js +309 -163
- package/dist/config/load.d.ts +2 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/persist.d.ts +2 -6
- package/dist/config/persist.d.ts.map +1 -1
- package/dist/config/schema.d.ts +3 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/index.d.ts +0 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +144 -185
- package/dist/storage/httpStorageProvider.d.ts +21 -0
- package/dist/storage/httpStorageProvider.d.ts.map +1 -0
- package/dist/telemetry/read.d.ts +2 -5
- package/dist/telemetry/read.d.ts.map +1 -1
- package/dist/web/server.d.ts +6 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/start.d.ts +3 -0
- package/dist/web/start.d.ts.map +1 -1
- package/dist/web/storageRoute.d.ts +36 -0
- package/dist/web/storageRoute.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -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,
|
|
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 {
|
|
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
|
|
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,
|
|
2305
|
+
response.writeHead(200, JSON_HEADERS3).end(await stateJson(deps));
|
|
2043
2306
|
return;
|
|
2044
2307
|
}
|
|
2045
2308
|
if (path === "/healthz") {
|
|
2046
|
-
response.writeHead(200,
|
|
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,
|
|
3987
|
-
|
|
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 =
|
|
4465
|
-
const opencodePath =
|
|
4466
|
-
const agentPath =
|
|
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(
|
|
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(
|
|
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 =
|
|
4648
|
-
|
|
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
|
-
|
|
4666
|
-
|
|
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
|
-
|
|
4697
|
-
|
|
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
|
|
4708
|
-
|
|
4709
|
-
`, "utf8");
|
|
4871
|
+
await storage.write(path, `${JSON.stringify(config, null, 2)}
|
|
4872
|
+
`);
|
|
4710
4873
|
},
|
|
4711
4874
|
writeOrchestratorAgent: async (contents, path) => {
|
|
4712
|
-
await
|
|
4713
|
-
await writeFile3(path, contents, "utf8");
|
|
4875
|
+
await storage.write(path, contents);
|
|
4714
4876
|
},
|
|
4715
4877
|
listAgentFiles: async (dir) => {
|
|
4716
|
-
|
|
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
|
|
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
|
|
4758
|
-
await writeFile3(path, contents, "utf8");
|
|
4911
|
+
await storage.write(path, contents);
|
|
4759
4912
|
},
|
|
4760
|
-
fileExists:
|
|
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() {
|
package/dist/config/load.d.ts
CHANGED
|
@@ -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":"
|
|
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"}
|
package/dist/config/persist.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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":"
|
|
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/config/schema.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
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/
|
|
202
|
-
import {
|
|
203
|
-
|
|
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,
|
|
313
|
-
|
|
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
|
-
|
|
2519
|
-
|
|
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
|
-
|
|
2530
|
-
|
|
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
|
|
2540
|
-
|
|
2541
|
-
`, "utf8");
|
|
2509
|
+
await storage.write(path, `${JSON.stringify(nextConfig, null, 2)}
|
|
2510
|
+
`);
|
|
2542
2511
|
},
|
|
2543
2512
|
writeOrchestratorAgent: async (contents, path) => {
|
|
2544
|
-
await
|
|
2545
|
-
await writeFile3(path, contents, "utf8");
|
|
2513
|
+
await storage.write(path, contents);
|
|
2546
2514
|
},
|
|
2547
2515
|
listAgentFiles: async (dir) => {
|
|
2548
|
-
|
|
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
|
|
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:
|
|
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"}
|
package/dist/telemetry/read.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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":"
|
|
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"}
|
package/dist/web/server.d.ts
CHANGED
|
@@ -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;
|
package/dist/web/server.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/web/start.d.ts
CHANGED
|
@@ -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>;
|
package/dist/web/start.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|