@syrin/iris 0.4.0 → 0.5.0
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.js +1112 -234
- package/dist/index.js +5 -0
- package/dist/server.d.ts +10 -1
- package/dist/server.js +718 -215
- package/dist/test.js +542 -222
- package/package.json +9 -9
package/dist/test.js
CHANGED
|
@@ -191,12 +191,12 @@ ${body}
|
|
|
191
191
|
</${JUnit.SUITE}>
|
|
192
192
|
`;
|
|
193
193
|
}
|
|
194
|
-
async function writeJUnit(
|
|
195
|
-
await
|
|
194
|
+
async function writeJUnit(fs2, path, results, opts) {
|
|
195
|
+
await fs2.writeFile(path, toJUnitXml(results, opts));
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
// ../test/dist/boot.js
|
|
199
|
-
import { join as
|
|
199
|
+
import { join as join6 } from "path";
|
|
200
200
|
|
|
201
201
|
// ../protocol/dist/constants.js
|
|
202
202
|
var IRIS_DEFAULT_PORT = 4400;
|
|
@@ -243,6 +243,7 @@ var CRAWL_DEFAULTS = {
|
|
|
243
243
|
/** HTTP status at/above which a response counts as a failed request. */
|
|
244
244
|
FAILED_STATUS: 400
|
|
245
245
|
};
|
|
246
|
+
var UpdateCheckIntervalMs = 24 * 60 * 60 * 1e3;
|
|
246
247
|
var CONTRACT_FILE_VERSION = 1;
|
|
247
248
|
var FROM_DISK_ARG = "fromDisk";
|
|
248
249
|
var ContractReadError = {
|
|
@@ -846,10 +847,22 @@ var AnnotationSchema = z2.discriminatedUnion("kind", [
|
|
|
846
847
|
]);
|
|
847
848
|
|
|
848
849
|
// ../server/dist/index.js
|
|
849
|
-
import { join as
|
|
850
|
+
import { join as join5 } from "path";
|
|
850
851
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
851
852
|
|
|
853
|
+
// ../server/dist/http-server.js
|
|
854
|
+
import * as http from "http";
|
|
855
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
856
|
+
|
|
857
|
+
// ../server/dist/log.js
|
|
858
|
+
function log(event, fields = {}) {
|
|
859
|
+
const line = JSON.stringify({ event, ...fields });
|
|
860
|
+
process.stderr.write(`${line}
|
|
861
|
+
`);
|
|
862
|
+
}
|
|
863
|
+
|
|
852
864
|
// ../server/dist/bridge.js
|
|
865
|
+
import * as http2 from "http";
|
|
853
866
|
import { WebSocketServer } from "ws";
|
|
854
867
|
|
|
855
868
|
// ../server/dist/events/ring-buffer.js
|
|
@@ -1271,7 +1284,16 @@ var SessionManager = class {
|
|
|
1271
1284
|
}
|
|
1272
1285
|
/**
|
|
1273
1286
|
* Resolve the target session. With an explicit id, returns it. With none and exactly
|
|
1274
|
-
* one connected, returns that.
|
|
1287
|
+
* one connected, returns that.
|
|
1288
|
+
*
|
|
1289
|
+
* With none and multiple connected, applies smart auto-selection:
|
|
1290
|
+
* 1. Prefer non-throttled sessions (not hidden + recently heard from).
|
|
1291
|
+
* 2. Within each tier, prefer lowest lastSeenMs (most recently active SDK heartbeat).
|
|
1292
|
+
* 3. If two or more non-throttled sessions are within 1 s of each other, throw —
|
|
1293
|
+
* genuinely ambiguous, agent must specify sessionId.
|
|
1294
|
+
* 4. If ALL sessions are throttled (e.g. user is working in their editor on another
|
|
1295
|
+
* desktop), skip the gap check and pick the freshest heartbeat. This lets the agent
|
|
1296
|
+
* keep working in the background without requiring sessionId every time.
|
|
1275
1297
|
*/
|
|
1276
1298
|
resolve(sessionId) {
|
|
1277
1299
|
if (sessionId !== void 0) {
|
|
@@ -1285,25 +1307,33 @@ var SessionManager = class {
|
|
|
1285
1307
|
if (this.#sessions.size === 0) {
|
|
1286
1308
|
throw new Error("no browser session connected \u2014 is your app running with @syrin/iris-browser enabled?");
|
|
1287
1309
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1310
|
+
const all = [...this.#sessions.values()];
|
|
1311
|
+
if (all.length === 1) {
|
|
1312
|
+
const [only] = all;
|
|
1313
|
+
if (only === void 0)
|
|
1314
|
+
throw new Error("session lookup failed");
|
|
1315
|
+
only.markAgentActivity();
|
|
1316
|
+
return only;
|
|
1291
1317
|
}
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1318
|
+
const scored = all.map((s) => ({ s, score: s.throttled() ? 1 : 0, ms: s.lastSeenMs() }));
|
|
1319
|
+
const bestScore = Math.min(...scored.map((x) => x.score));
|
|
1320
|
+
const candidates = scored.filter((x) => x.score === bestScore);
|
|
1321
|
+
candidates.sort((a, b) => a.ms - b.ms);
|
|
1322
|
+
const [best, runnerUp] = candidates;
|
|
1323
|
+
if (best === void 0)
|
|
1294
1324
|
throw new Error("session lookup failed");
|
|
1295
|
-
|
|
1296
|
-
|
|
1325
|
+
const allThrottled = bestScore === 1;
|
|
1326
|
+
const RECENCY_GAP_MS = allThrottled ? 0 : 1e3;
|
|
1327
|
+
const clearWinner = runnerUp === void 0 || best.ms + RECENCY_GAP_MS < runnerUp.ms;
|
|
1328
|
+
if (!clearWinner) {
|
|
1329
|
+
const detail = all.map((s) => `${s.id} (${s.throttled() ? "throttled" : "active"}, lastSeenMs=${s.lastSeenMs()})`).join(", ");
|
|
1330
|
+
throw new Error(`multiple sessions connected \u2014 pass sessionId to target one: ${detail}`);
|
|
1331
|
+
}
|
|
1332
|
+
best.s.markAgentActivity();
|
|
1333
|
+
return best.s;
|
|
1297
1334
|
}
|
|
1298
1335
|
};
|
|
1299
1336
|
|
|
1300
|
-
// ../server/dist/log.js
|
|
1301
|
-
function log(event, fields = {}) {
|
|
1302
|
-
const line = JSON.stringify({ event, ...fields });
|
|
1303
|
-
process.stderr.write(`${line}
|
|
1304
|
-
`);
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
1337
|
// ../server/dist/bridge.js
|
|
1308
1338
|
function rawToString(raw) {
|
|
1309
1339
|
if (typeof raw === "string")
|
|
@@ -1322,16 +1352,30 @@ var Bridge = class {
|
|
|
1322
1352
|
#clock;
|
|
1323
1353
|
constructor(options) {
|
|
1324
1354
|
this.#clock = options.clock ?? (() => Date.now());
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1355
|
+
if (options.server !== void 0) {
|
|
1356
|
+
const srv = options.server;
|
|
1357
|
+
this.#wss = new WebSocketServer({ server: srv, path: IRIS_WS_PATH });
|
|
1358
|
+
this.ready = new Promise((resolve) => {
|
|
1359
|
+
if (srv.listening) {
|
|
1360
|
+
resolve(srv.address().port);
|
|
1361
|
+
} else {
|
|
1362
|
+
srv.once("listening", () => {
|
|
1363
|
+
resolve(srv.address().port);
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1333
1366
|
});
|
|
1334
|
-
}
|
|
1367
|
+
} else {
|
|
1368
|
+
this.#wss = new WebSocketServer({
|
|
1369
|
+
port: options.port,
|
|
1370
|
+
host: options.host ?? "127.0.0.1",
|
|
1371
|
+
path: IRIS_WS_PATH
|
|
1372
|
+
});
|
|
1373
|
+
this.ready = new Promise((resolve) => {
|
|
1374
|
+
this.#wss.on("listening", () => {
|
|
1375
|
+
resolve(this.#wss.address().port);
|
|
1376
|
+
});
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1335
1379
|
this.#wss.on("connection", (socket) => {
|
|
1336
1380
|
this.#onConnection(socket);
|
|
1337
1381
|
});
|
|
@@ -1530,7 +1574,13 @@ var IrisTool = {
|
|
|
1530
1574
|
/** Navigate the connected browser tab to a URL. */
|
|
1531
1575
|
NAVIGATE: "iris_navigate",
|
|
1532
1576
|
/** Reload the connected browser tab (soft or hard). */
|
|
1533
|
-
REFRESH: "iris_refresh"
|
|
1577
|
+
REFRESH: "iris_refresh",
|
|
1578
|
+
/** Report running version, latest available, changelog, and breaking changes. */
|
|
1579
|
+
VERSION_INFO: "iris_version_info",
|
|
1580
|
+
/** Install the latest server version and restart (Claude Code reconnects automatically). */
|
|
1581
|
+
APPLY_UPDATE: "iris_apply_update",
|
|
1582
|
+
/** Restore the previous server version and restart. */
|
|
1583
|
+
ROLLBACK: "iris_rollback"
|
|
1534
1584
|
};
|
|
1535
1585
|
|
|
1536
1586
|
// ../server/dist/project/iris-dir.js
|
|
@@ -1557,11 +1607,11 @@ function flowPath(root, name) {
|
|
|
1557
1607
|
function isValidFlowName(name) {
|
|
1558
1608
|
return FLOW_NAME_PATTERN.test(name) && !name.includes("..");
|
|
1559
1609
|
}
|
|
1560
|
-
async function ensureIrisDir(
|
|
1610
|
+
async function ensureIrisDir(fs2, root) {
|
|
1561
1611
|
const p = irisDirPaths(root);
|
|
1562
|
-
await
|
|
1563
|
-
await
|
|
1564
|
-
await
|
|
1612
|
+
await fs2.mkdir(p.root);
|
|
1613
|
+
await fs2.mkdir(p.flows);
|
|
1614
|
+
await fs2.mkdir(p.baselines);
|
|
1565
1615
|
}
|
|
1566
1616
|
var JSON_INDENT = 2;
|
|
1567
1617
|
function stableSerialize(capabilities, generatedAt) {
|
|
@@ -1578,21 +1628,21 @@ function stableSerialize(capabilities, generatedAt) {
|
|
|
1578
1628
|
return `${JSON.stringify(envelope, null, JSON_INDENT)}
|
|
1579
1629
|
`;
|
|
1580
1630
|
}
|
|
1581
|
-
async function writeContract(
|
|
1582
|
-
await ensureIrisDir(
|
|
1583
|
-
await
|
|
1631
|
+
async function writeContract(fs2, root, capabilities, now) {
|
|
1632
|
+
await ensureIrisDir(fs2, root);
|
|
1633
|
+
await fs2.writeFile(irisDirPaths(root).contract, stableSerialize(capabilities, now()));
|
|
1584
1634
|
}
|
|
1585
|
-
async function readContract(
|
|
1635
|
+
async function readContract(fs2, root) {
|
|
1586
1636
|
const path = irisDirPaths(root).contract;
|
|
1587
|
-
if (!await
|
|
1637
|
+
if (!await fs2.exists(path))
|
|
1588
1638
|
return { ok: false, reason: ContractReadError.MISSING };
|
|
1589
1639
|
let text;
|
|
1590
1640
|
try {
|
|
1591
|
-
text = await
|
|
1641
|
+
text = await fs2.readFile(path);
|
|
1592
1642
|
} catch (error) {
|
|
1593
1643
|
return {
|
|
1594
1644
|
ok: false,
|
|
1595
|
-
reason:
|
|
1645
|
+
reason: fs2.isNotFound(error) ? ContractReadError.MISSING : ContractReadError.MALFORMED
|
|
1596
1646
|
};
|
|
1597
1647
|
}
|
|
1598
1648
|
let parsed;
|
|
@@ -1679,8 +1729,8 @@ var FlowStore = class {
|
|
|
1679
1729
|
#fs;
|
|
1680
1730
|
#root;
|
|
1681
1731
|
#clock;
|
|
1682
|
-
constructor(
|
|
1683
|
-
this.#fs =
|
|
1732
|
+
constructor(fs2, root, clock) {
|
|
1733
|
+
this.#fs = fs2;
|
|
1684
1734
|
this.#root = root;
|
|
1685
1735
|
this.#clock = clock;
|
|
1686
1736
|
}
|
|
@@ -1826,8 +1876,8 @@ var ProjectStore = class {
|
|
|
1826
1876
|
#fs;
|
|
1827
1877
|
#root;
|
|
1828
1878
|
#clock;
|
|
1829
|
-
constructor(
|
|
1830
|
-
this.#fs =
|
|
1879
|
+
constructor(fs2, root, clock) {
|
|
1880
|
+
this.#fs = fs2;
|
|
1831
1881
|
this.#root = root;
|
|
1832
1882
|
this.#clock = clock;
|
|
1833
1883
|
}
|
|
@@ -2006,10 +2056,10 @@ function createNodeFileSystem() {
|
|
|
2006
2056
|
|
|
2007
2057
|
// ../server/dist/mcp.js
|
|
2008
2058
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2009
|
-
import { z as
|
|
2059
|
+
import { z as z16 } from "zod";
|
|
2010
2060
|
|
|
2011
2061
|
// ../server/dist/tools/tools.js
|
|
2012
|
-
import { z as
|
|
2062
|
+
import { z as z15 } from "zod";
|
|
2013
2063
|
|
|
2014
2064
|
// ../server/dist/input/real-input.js
|
|
2015
2065
|
var DriveError = class extends Error {
|
|
@@ -3618,8 +3668,8 @@ async function diffPng(baselineBytes, currentBytes, opts = {}) {
|
|
|
3618
3668
|
var VisualStore = class {
|
|
3619
3669
|
#fs;
|
|
3620
3670
|
#root;
|
|
3621
|
-
constructor(
|
|
3622
|
-
this.#fs =
|
|
3671
|
+
constructor(fs2, root) {
|
|
3672
|
+
this.#fs = fs2;
|
|
3623
3673
|
this.#root = root;
|
|
3624
3674
|
}
|
|
3625
3675
|
/** The absolute baseline path for `name` (for echoing back to the agent). */
|
|
@@ -4245,6 +4295,266 @@ function withControl(session, result) {
|
|
|
4245
4295
|
return control === void 0 ? result : { ...result, control };
|
|
4246
4296
|
}
|
|
4247
4297
|
|
|
4298
|
+
// ../server/dist/update/update-tools.js
|
|
4299
|
+
import { z as z14 } from "zod";
|
|
4300
|
+
|
|
4301
|
+
// ../server/dist/update/update-checker.js
|
|
4302
|
+
import * as fs from "fs";
|
|
4303
|
+
import * as https from "https";
|
|
4304
|
+
import { join as join2 } from "path";
|
|
4305
|
+
import { homedir } from "os";
|
|
4306
|
+
var IRIS_HOME = join2(homedir(), ".iris");
|
|
4307
|
+
var MANIFEST_PATH = join2(IRIS_HOME, "update-manifest.json");
|
|
4308
|
+
var NPM_REGISTRY = "https://registry.npmjs.org/@syrin/iris/latest";
|
|
4309
|
+
function loadManifest() {
|
|
4310
|
+
if (!fs.existsSync(MANIFEST_PATH))
|
|
4311
|
+
return null;
|
|
4312
|
+
try {
|
|
4313
|
+
const raw = fs.readFileSync(MANIFEST_PATH, "utf8");
|
|
4314
|
+
return JSON.parse(raw);
|
|
4315
|
+
} catch {
|
|
4316
|
+
return null;
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
function saveManifest(manifest) {
|
|
4320
|
+
fs.mkdirSync(IRIS_HOME, { recursive: true });
|
|
4321
|
+
fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2), "utf8");
|
|
4322
|
+
}
|
|
4323
|
+
function isCacheFresh(manifest) {
|
|
4324
|
+
const checked = new Date(manifest.lastChecked).getTime();
|
|
4325
|
+
return Date.now() - checked < UpdateCheckIntervalMs;
|
|
4326
|
+
}
|
|
4327
|
+
function fetchNpmInfo() {
|
|
4328
|
+
return new Promise((resolve, reject) => {
|
|
4329
|
+
const req = https.get(NPM_REGISTRY, (res) => {
|
|
4330
|
+
let body = "";
|
|
4331
|
+
res.setEncoding("utf8");
|
|
4332
|
+
res.on("data", (chunk) => {
|
|
4333
|
+
body += chunk;
|
|
4334
|
+
});
|
|
4335
|
+
res.on("end", () => {
|
|
4336
|
+
try {
|
|
4337
|
+
resolve(JSON.parse(body));
|
|
4338
|
+
} catch (err) {
|
|
4339
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4340
|
+
}
|
|
4341
|
+
});
|
|
4342
|
+
res.on("error", reject);
|
|
4343
|
+
});
|
|
4344
|
+
req.setTimeout(5e3, () => {
|
|
4345
|
+
req.destroy();
|
|
4346
|
+
reject(new Error("npm registry request timed out"));
|
|
4347
|
+
});
|
|
4348
|
+
req.on("error", reject);
|
|
4349
|
+
});
|
|
4350
|
+
}
|
|
4351
|
+
async function checkForUpdate(currentVersion) {
|
|
4352
|
+
const cached = loadManifest();
|
|
4353
|
+
if (cached !== null && cached.currentVersion === currentVersion && isCacheFresh(cached)) {
|
|
4354
|
+
return cached;
|
|
4355
|
+
}
|
|
4356
|
+
try {
|
|
4357
|
+
const info = await fetchNpmInfo();
|
|
4358
|
+
const updateAvailable = info.version !== currentVersion;
|
|
4359
|
+
const manifest = {
|
|
4360
|
+
currentVersion,
|
|
4361
|
+
latestVersion: info.version,
|
|
4362
|
+
updateAvailable,
|
|
4363
|
+
lastChecked: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4364
|
+
...info.iris?.changelog !== void 0 ? { changelog: info.iris.changelog } : {},
|
|
4365
|
+
...info.iris?.breakingChanges !== void 0 ? { breakingChanges: info.iris.breakingChanges } : {},
|
|
4366
|
+
...cached?.previousVersion !== void 0 ? { previousVersion: cached.previousVersion } : {}
|
|
4367
|
+
};
|
|
4368
|
+
saveManifest(manifest);
|
|
4369
|
+
return manifest;
|
|
4370
|
+
} catch (err) {
|
|
4371
|
+
log("iris_update_check_failed", {
|
|
4372
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4373
|
+
});
|
|
4374
|
+
if (cached !== null)
|
|
4375
|
+
return { ...cached, currentVersion };
|
|
4376
|
+
return {
|
|
4377
|
+
currentVersion,
|
|
4378
|
+
updateAvailable: false,
|
|
4379
|
+
lastChecked: (/* @__PURE__ */ new Date()).toISOString()
|
|
4380
|
+
};
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
|
|
4384
|
+
// ../server/dist/update/updater.js
|
|
4385
|
+
import { execFile } from "child_process";
|
|
4386
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4387
|
+
import { platform } from "os";
|
|
4388
|
+
import { dirname, join as join3 } from "path";
|
|
4389
|
+
var NPM_BIN = platform() === "win32" ? "npm.cmd" : "npm";
|
|
4390
|
+
var NPM_TIMEOUT_MS = 12e4;
|
|
4391
|
+
var ExecutionKind = {
|
|
4392
|
+
/** Launched via `npx @syrin/iris` — npm re-resolves the package on restart. */
|
|
4393
|
+
NPX: "npx",
|
|
4394
|
+
/** Installed globally via `npm install -g`. */
|
|
4395
|
+
GLOBAL: "global",
|
|
4396
|
+
/** Installed as a local project dependency. */
|
|
4397
|
+
LOCAL: "local"
|
|
4398
|
+
};
|
|
4399
|
+
function detectExecutionKind() {
|
|
4400
|
+
const script = process.argv[1] ?? "";
|
|
4401
|
+
if (script.includes("/_npx/") || script.includes("\\_npx\\"))
|
|
4402
|
+
return ExecutionKind.NPX;
|
|
4403
|
+
if (script.includes("/node_modules/") || script.includes("\\node_modules\\")) {
|
|
4404
|
+
return ExecutionKind.LOCAL;
|
|
4405
|
+
}
|
|
4406
|
+
return ExecutionKind.GLOBAL;
|
|
4407
|
+
}
|
|
4408
|
+
function findLocalProjectRoot() {
|
|
4409
|
+
let dir = process.cwd();
|
|
4410
|
+
for (; ; ) {
|
|
4411
|
+
if (existsSync2(join3(dir, "package.json")))
|
|
4412
|
+
return dir;
|
|
4413
|
+
const parent = dirname(dir);
|
|
4414
|
+
if (parent === dir)
|
|
4415
|
+
return null;
|
|
4416
|
+
dir = parent;
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
function runNpm(args, opts = {}) {
|
|
4420
|
+
return new Promise((resolve, reject) => {
|
|
4421
|
+
execFile(NPM_BIN, args, { timeout: NPM_TIMEOUT_MS, ...opts.cwd !== void 0 ? { cwd: opts.cwd } : {} }, (err, _stdout, stderr) => {
|
|
4422
|
+
if (err !== null) {
|
|
4423
|
+
reject(new Error(`npm ${args.join(" ")} failed: ${stderr !== "" ? stderr : err.message}`));
|
|
4424
|
+
} else {
|
|
4425
|
+
resolve();
|
|
4426
|
+
}
|
|
4427
|
+
});
|
|
4428
|
+
});
|
|
4429
|
+
}
|
|
4430
|
+
async function installVersion(version, kind) {
|
|
4431
|
+
const pkg = `@syrin/iris@${version}`;
|
|
4432
|
+
if (kind === ExecutionKind.NPX) {
|
|
4433
|
+
log("iris_update_npx_strategy", {
|
|
4434
|
+
note: "Running via npx \u2014 exiting so Claude Code restarts and npx fetches the new version"
|
|
4435
|
+
});
|
|
4436
|
+
return;
|
|
4437
|
+
}
|
|
4438
|
+
if (kind === ExecutionKind.LOCAL) {
|
|
4439
|
+
const root = findLocalProjectRoot();
|
|
4440
|
+
if (root !== null) {
|
|
4441
|
+
await runNpm(["install", pkg], { cwd: root });
|
|
4442
|
+
return;
|
|
4443
|
+
}
|
|
4444
|
+
log("iris_update_local_no_root", { fallback: "global" });
|
|
4445
|
+
}
|
|
4446
|
+
await runNpm(["install", "-g", pkg]);
|
|
4447
|
+
}
|
|
4448
|
+
async function installVersionRollback(version, kind) {
|
|
4449
|
+
if (kind === ExecutionKind.NPX) {
|
|
4450
|
+
log("iris_rollback_npx_strategy", {
|
|
4451
|
+
note: "Running via npx \u2014 update your .mcp.json args to pin the version you want to restore"
|
|
4452
|
+
});
|
|
4453
|
+
return;
|
|
4454
|
+
}
|
|
4455
|
+
await installVersion(version, kind);
|
|
4456
|
+
}
|
|
4457
|
+
async function applyUpdate(targetVersion) {
|
|
4458
|
+
const manifest = loadManifest();
|
|
4459
|
+
if (manifest !== null) {
|
|
4460
|
+
saveManifest({ ...manifest, previousVersion: manifest.currentVersion });
|
|
4461
|
+
}
|
|
4462
|
+
const kind = detectExecutionKind();
|
|
4463
|
+
log("iris_update_applying", { version: targetVersion, executionKind: kind });
|
|
4464
|
+
await installVersion(targetVersion, kind);
|
|
4465
|
+
log("iris_update_applied", { version: targetVersion, executionKind: kind });
|
|
4466
|
+
process.exit(0);
|
|
4467
|
+
}
|
|
4468
|
+
async function rollback() {
|
|
4469
|
+
const manifest = loadManifest();
|
|
4470
|
+
if (manifest === null || manifest.previousVersion === void 0) {
|
|
4471
|
+
throw new Error("No previous version available for rollback");
|
|
4472
|
+
}
|
|
4473
|
+
const prev = manifest.previousVersion;
|
|
4474
|
+
const kind = detectExecutionKind();
|
|
4475
|
+
log("iris_rollback_applying", { version: prev, executionKind: kind });
|
|
4476
|
+
await installVersionRollback(prev, kind);
|
|
4477
|
+
log("iris_rollback_applied", { version: prev, executionKind: kind });
|
|
4478
|
+
process.exit(0);
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4481
|
+
// ../server/dist/server-version.js
|
|
4482
|
+
import { createRequire } from "module";
|
|
4483
|
+
var _pkg = createRequire(import.meta.url)("../package.json");
|
|
4484
|
+
var SERVER_VERSION = _pkg.version;
|
|
4485
|
+
|
|
4486
|
+
// ../server/dist/update/update-tools.js
|
|
4487
|
+
var UPDATE_TOOLS = [
|
|
4488
|
+
{
|
|
4489
|
+
name: IrisTool.VERSION_INFO,
|
|
4490
|
+
description: "Returns the running Iris version, latest available version, release changelog, and any breaking changes. Call this at the start of a session or when unexpected tool behavior suggests a version mismatch.",
|
|
4491
|
+
inputSchema: {},
|
|
4492
|
+
outputSchema: {
|
|
4493
|
+
currentVersion: z14.string().describe("The Iris server version currently running."),
|
|
4494
|
+
latestVersion: z14.string().optional().describe("Latest published version on npm."),
|
|
4495
|
+
updateAvailable: z14.boolean().describe("True when a newer version is available to install."),
|
|
4496
|
+
executionKind: z14.string().describe('How iris was launched: "npx" (no install needed \u2014 restart applies update), "global" (npm install -g), or "local" (project node_modules).'),
|
|
4497
|
+
changelog: z14.string().optional().describe("Release notes for the latest version."),
|
|
4498
|
+
breakingChanges: z14.array(z14.string()).optional().describe("Breaking changes in the latest version that may affect your scripts."),
|
|
4499
|
+
rollbackAvailable: z14.boolean().describe("True when a previous version is stored and can be restored."),
|
|
4500
|
+
previousVersion: z14.string().optional().describe("The version that would be restored on rollback.")
|
|
4501
|
+
},
|
|
4502
|
+
handler: async (_deps) => {
|
|
4503
|
+
const manifest = await checkForUpdate(SERVER_VERSION);
|
|
4504
|
+
return {
|
|
4505
|
+
currentVersion: manifest.currentVersion,
|
|
4506
|
+
...manifest.latestVersion !== void 0 ? { latestVersion: manifest.latestVersion } : {},
|
|
4507
|
+
updateAvailable: manifest.updateAvailable,
|
|
4508
|
+
executionKind: detectExecutionKind(),
|
|
4509
|
+
...manifest.changelog !== void 0 ? { changelog: manifest.changelog } : {},
|
|
4510
|
+
...manifest.breakingChanges !== void 0 ? { breakingChanges: manifest.breakingChanges } : {},
|
|
4511
|
+
rollbackAvailable: manifest.previousVersion !== void 0,
|
|
4512
|
+
...manifest.previousVersion !== void 0 ? { previousVersion: manifest.previousVersion } : {}
|
|
4513
|
+
};
|
|
4514
|
+
}
|
|
4515
|
+
},
|
|
4516
|
+
{
|
|
4517
|
+
name: IrisTool.APPLY_UPDATE,
|
|
4518
|
+
description: 'Install the latest Iris server version and restart. Strategy depends on how iris was launched (check executionKind from iris_version_info): "global" and "local" installs run npm install then exit; "npx" just exits \u2014 Claude Code restarts and npx re-resolves the latest version from npm automatically. The MCP connection briefly drops during restart.',
|
|
4519
|
+
inputSchema: {
|
|
4520
|
+
confirm: z14.boolean().describe("Set to true to confirm the update should be applied. Required to prevent accidental upgrades.")
|
|
4521
|
+
},
|
|
4522
|
+
outputSchema: {
|
|
4523
|
+
ok: z14.boolean(),
|
|
4524
|
+
message: z14.string().optional()
|
|
4525
|
+
},
|
|
4526
|
+
handler: async (_deps, args) => {
|
|
4527
|
+
if (args["confirm"] !== true) {
|
|
4528
|
+
return { ok: false, message: "Set confirm:true to apply the update" };
|
|
4529
|
+
}
|
|
4530
|
+
const manifest = await checkForUpdate(SERVER_VERSION);
|
|
4531
|
+
if (!manifest.updateAvailable || manifest.latestVersion === void 0) {
|
|
4532
|
+
return { ok: false, message: "No update available \u2014 already on the latest version" };
|
|
4533
|
+
}
|
|
4534
|
+
await applyUpdate(manifest.latestVersion);
|
|
4535
|
+
return { ok: true };
|
|
4536
|
+
}
|
|
4537
|
+
},
|
|
4538
|
+
{
|
|
4539
|
+
name: IrisTool.ROLLBACK,
|
|
4540
|
+
description: "Restore the previous Iris server version and restart. Use when an update introduced a regression. The MCP connection will briefly drop \u2014 Claude Code restarts the process automatically with the restored binary.",
|
|
4541
|
+
inputSchema: {
|
|
4542
|
+
confirm: z14.boolean().describe("Set to true to confirm the rollback. Required to prevent accidental downgrades.")
|
|
4543
|
+
},
|
|
4544
|
+
outputSchema: {
|
|
4545
|
+
ok: z14.boolean(),
|
|
4546
|
+
message: z14.string().optional()
|
|
4547
|
+
},
|
|
4548
|
+
handler: async (_deps, args) => {
|
|
4549
|
+
if (args["confirm"] !== true) {
|
|
4550
|
+
return { ok: false, message: "Set confirm:true to apply the rollback" };
|
|
4551
|
+
}
|
|
4552
|
+
await rollback();
|
|
4553
|
+
return { ok: true };
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
];
|
|
4557
|
+
|
|
4248
4558
|
// ../server/dist/tools/tools.js
|
|
4249
4559
|
async function snapshotTree(deps, sessionId) {
|
|
4250
4560
|
const session = deps.sessions.resolve(sessionId);
|
|
@@ -4255,7 +4565,7 @@ async function snapshotTree(deps, sessionId) {
|
|
|
4255
4565
|
return { lines: normalizeLines(snap.tree ?? ""), route: snap.status?.route ?? "" };
|
|
4256
4566
|
}
|
|
4257
4567
|
var sessionIdShape6 = {
|
|
4258
|
-
sessionId:
|
|
4568
|
+
sessionId: z15.string().optional().describe("Active session ID from iris_sessions. Omit when only one browser session is open \u2014 Iris resolves it automatically.")
|
|
4259
4569
|
};
|
|
4260
4570
|
async function commandOrThrow3(deps, sessionId, name, args) {
|
|
4261
4571
|
const session = deps.sessions.resolve(sessionId);
|
|
@@ -4332,17 +4642,17 @@ var TOOLS = [
|
|
|
4332
4642
|
description: "List connected browser sessions (tab url/title, sessionId, last-seen, health: hidden/focused/throttled, and `realInputAvailable` \u2014 true when native CDP/launched real input is driving this tab), plus a `recommendation` pointing to `iris drive` when a tab is hidden/throttled and may be un-scriptable from here.",
|
|
4333
4643
|
inputSchema: {},
|
|
4334
4644
|
outputSchema: {
|
|
4335
|
-
sessions:
|
|
4336
|
-
sessionId:
|
|
4337
|
-
url:
|
|
4338
|
-
title:
|
|
4339
|
-
lastSeenMs:
|
|
4340
|
-
throttled:
|
|
4341
|
-
focused:
|
|
4342
|
-
hidden:
|
|
4343
|
-
realInputAvailable:
|
|
4344
|
-
stale:
|
|
4345
|
-
recommendation:
|
|
4645
|
+
sessions: z15.array(z15.object({
|
|
4646
|
+
sessionId: z15.string(),
|
|
4647
|
+
url: z15.string(),
|
|
4648
|
+
title: z15.string().optional(),
|
|
4649
|
+
lastSeenMs: z15.number(),
|
|
4650
|
+
throttled: z15.boolean(),
|
|
4651
|
+
focused: z15.boolean(),
|
|
4652
|
+
hidden: z15.boolean(),
|
|
4653
|
+
realInputAvailable: z15.boolean().optional(),
|
|
4654
|
+
stale: z15.boolean().optional(),
|
|
4655
|
+
recommendation: z15.string().optional()
|
|
4346
4656
|
})).describe("Connected browser sessions with health state.")
|
|
4347
4657
|
},
|
|
4348
4658
|
handler: async (deps) => {
|
|
@@ -4358,13 +4668,13 @@ var TOOLS = [
|
|
|
4358
4668
|
name: IrisTool.SNAPSHOT,
|
|
4359
4669
|
description: "Semantic accessibility snapshot of the page or a subtree. mode: full|interactive|status. Use to see what is on screen right now.",
|
|
4360
4670
|
inputSchema: {
|
|
4361
|
-
scope:
|
|
4362
|
-
mode:
|
|
4671
|
+
scope: z15.string().optional().describe("CSS selector or element ref to restrict the snapshot to a subtree. Omit to snapshot the whole page."),
|
|
4672
|
+
mode: z15.nativeEnum(SnapshotMode).optional().describe("full = all elements; interactive = only clickable/focusable elements; status = only route + title. Default: full."),
|
|
4363
4673
|
...sessionIdShape6
|
|
4364
4674
|
},
|
|
4365
4675
|
outputSchema: {
|
|
4366
|
-
tree:
|
|
4367
|
-
status:
|
|
4676
|
+
tree: z15.string().optional().describe("Indented ARIA tree of every element on the page (or the scoped subtree)."),
|
|
4677
|
+
status: z15.object({ route: z15.string(), title: z15.string().optional() }).optional()
|
|
4368
4678
|
},
|
|
4369
4679
|
handler: (deps, args) => commandOrThrow3(deps, asString4(args["sessionId"]), IrisCommand.SNAPSHOT, {
|
|
4370
4680
|
scope: args["scope"],
|
|
@@ -4375,25 +4685,25 @@ var TOOLS = [
|
|
|
4375
4685
|
name: IrisTool.QUERY,
|
|
4376
4686
|
description: "Find elements by Testing-Library semantics. Pass `by` (role|text|label|placeholder|testid|alt) and `value` (the query string). Returns matching refs + descriptors + visibility. On zero matches, also returns hint:{ route, presentTestids[], knownEmptyState } so you can distinguish an empty state from a missing element WITHOUT taking a snapshot.",
|
|
4377
4687
|
inputSchema: {
|
|
4378
|
-
by:
|
|
4379
|
-
value:
|
|
4380
|
-
name:
|
|
4381
|
-
scope:
|
|
4688
|
+
by: z15.string().describe("Query strategy: role | text | label | placeholder | testid | alt"),
|
|
4689
|
+
value: z15.string().describe("Query value for the selected strategy (e.g. by=role value=button, or by=testid value=submit-btn)."),
|
|
4690
|
+
name: z15.string().optional().describe("Accessible name filter \u2014 narrows results when `by` is role and the page has many elements of that role."),
|
|
4691
|
+
scope: z15.string().optional().describe("CSS selector or element ref to restrict the search to a subtree."),
|
|
4382
4692
|
...sessionIdShape6
|
|
4383
4693
|
},
|
|
4384
4694
|
outputSchema: {
|
|
4385
|
-
elements:
|
|
4386
|
-
ref:
|
|
4387
|
-
role:
|
|
4388
|
-
name:
|
|
4389
|
-
value:
|
|
4390
|
-
states:
|
|
4391
|
-
visible:
|
|
4695
|
+
elements: z15.array(z15.object({
|
|
4696
|
+
ref: z15.string(),
|
|
4697
|
+
role: z15.string(),
|
|
4698
|
+
name: z15.string(),
|
|
4699
|
+
value: z15.string().optional(),
|
|
4700
|
+
states: z15.array(z15.string()),
|
|
4701
|
+
visible: z15.boolean()
|
|
4392
4702
|
})),
|
|
4393
|
-
hint:
|
|
4394
|
-
route:
|
|
4395
|
-
presentTestids:
|
|
4396
|
-
knownEmptyState:
|
|
4703
|
+
hint: z15.object({
|
|
4704
|
+
route: z15.string(),
|
|
4705
|
+
presentTestids: z15.array(z15.string()),
|
|
4706
|
+
knownEmptyState: z15.boolean()
|
|
4397
4707
|
}).optional().describe("Present only on zero matches \u2014 tells you what IS on the page so you can diagnose the miss.")
|
|
4398
4708
|
},
|
|
4399
4709
|
handler: (deps, args) => commandOrThrow3(deps, asString4(args["sessionId"]), IrisCommand.QUERY, {
|
|
@@ -4407,18 +4717,18 @@ var TOOLS = [
|
|
|
4407
4717
|
name: IrisTool.INSPECT,
|
|
4408
4718
|
description: "Deep info on one element by ref: full a11y props, visibility, box, and (with @syrin/iris-react) component stack + source file.",
|
|
4409
4719
|
inputSchema: {
|
|
4410
|
-
ref:
|
|
4720
|
+
ref: z15.string().describe("Element ref from iris_snapshot or iris_query (e.g. 'e42')."),
|
|
4411
4721
|
...sessionIdShape6
|
|
4412
4722
|
},
|
|
4413
4723
|
outputSchema: {
|
|
4414
|
-
ref:
|
|
4415
|
-
role:
|
|
4416
|
-
name:
|
|
4417
|
-
value:
|
|
4418
|
-
states:
|
|
4419
|
-
visible:
|
|
4420
|
-
box:
|
|
4421
|
-
component:
|
|
4724
|
+
ref: z15.string(),
|
|
4725
|
+
role: z15.string(),
|
|
4726
|
+
name: z15.string(),
|
|
4727
|
+
value: z15.string().optional(),
|
|
4728
|
+
states: z15.array(z15.string()),
|
|
4729
|
+
visible: z15.boolean(),
|
|
4730
|
+
box: z15.object({ x: z15.number(), y: z15.number(), width: z15.number(), height: z15.number() }).optional(),
|
|
4731
|
+
component: z15.object({ name: z15.string().optional(), sourceFile: z15.string().optional() }).optional()
|
|
4422
4732
|
},
|
|
4423
4733
|
handler: (deps, args) => commandOrThrow3(deps, asString4(args["sessionId"]), IrisCommand.INSPECT, {
|
|
4424
4734
|
ref: args["ref"]
|
|
@@ -4428,19 +4738,19 @@ var TOOLS = [
|
|
|
4428
4738
|
name: IrisTool.ACT,
|
|
4429
4739
|
description: 'Execute one action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView. Returns immediately with a `since` cursor \u2014 observe the reaction with iris_observe. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. occluded=true means the click point is covered by another element (a real user could not click it) \u2014 synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured \u2014 pass args.native:true to force a trusted native click (file pickers, clipboard). inputModeReason explains any real\u2192synthetic choice so it is never silent. Full model (real-input, throttled tabs, `iris drive`): docs/usage.md \xA718.',
|
|
4430
4740
|
inputSchema: {
|
|
4431
|
-
ref:
|
|
4432
|
-
action:
|
|
4433
|
-
args:
|
|
4434
|
-
refuseWhenThrottled:
|
|
4741
|
+
ref: z15.string().describe("Element ref from iris_snapshot or iris_query (e.g. 'e42')."),
|
|
4742
|
+
action: z15.string().describe("Action to perform: click | dblclick | hover | focus | fill | type | clear | select | check | uncheck | submit | press | scrollIntoView"),
|
|
4743
|
+
args: z15.record(z15.unknown()).optional().describe("Action-specific arguments: { value } for fill/select, { text } for type/press, { native: true } to force a trusted native click."),
|
|
4744
|
+
refuseWhenThrottled: z15.boolean().optional().describe("Throw instead of silently sending synthetic events when the tab is throttled/backgrounded. Default: false (synthetic events are still sent)."),
|
|
4435
4745
|
...sessionIdShape6
|
|
4436
4746
|
},
|
|
4437
4747
|
outputSchema: {
|
|
4438
|
-
since:
|
|
4439
|
-
dispatched:
|
|
4440
|
-
settled:
|
|
4441
|
-
inputMode:
|
|
4442
|
-
result:
|
|
4443
|
-
session:
|
|
4748
|
+
since: z15.number().describe("Cursor \u2014 pass to iris_observe/iris_wait_for/iris_assert to scope reaction queries to this act."),
|
|
4749
|
+
dispatched: z15.boolean(),
|
|
4750
|
+
settled: z15.boolean().nullable(),
|
|
4751
|
+
inputMode: z15.string(),
|
|
4752
|
+
result: z15.unknown().optional(),
|
|
4753
|
+
session: z15.object({ lastSeenMs: z15.number(), throttled: z15.boolean(), focused: z15.boolean() }).optional()
|
|
4444
4754
|
},
|
|
4445
4755
|
handler: async (deps, args) => {
|
|
4446
4756
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4496,14 +4806,14 @@ var TOOLS = [
|
|
|
4496
4806
|
name: IrisTool.ACT_SEQUENCE,
|
|
4497
4807
|
description: "Run multiple actions in order (fill -> fill -> submit) in one round-trip. Returns per-step effects[] (see iris_act).",
|
|
4498
4808
|
inputSchema: {
|
|
4499
|
-
steps:
|
|
4809
|
+
steps: z15.array(z15.record(z15.unknown())).describe("Ordered list of { ref, action, args? } objects. Each step is equivalent to one iris_act call."),
|
|
4500
4810
|
...sessionIdShape6
|
|
4501
4811
|
},
|
|
4502
4812
|
outputSchema: {
|
|
4503
|
-
since:
|
|
4504
|
-
dispatched:
|
|
4505
|
-
result:
|
|
4506
|
-
session:
|
|
4813
|
+
since: z15.number(),
|
|
4814
|
+
dispatched: z15.boolean(),
|
|
4815
|
+
result: z15.unknown().optional(),
|
|
4816
|
+
session: z15.object({ lastSeenMs: z15.number(), throttled: z15.boolean(), focused: z15.boolean() }).optional()
|
|
4507
4817
|
},
|
|
4508
4818
|
handler: async (deps, args) => {
|
|
4509
4819
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4531,23 +4841,23 @@ var TOOLS = [
|
|
|
4531
4841
|
name: IrisTool.ACT_AND_WAIT,
|
|
4532
4842
|
description: "Act on a ref, then wait for a predicate to hold \u2014 one hop for the act->observe->assert loop. Returns { effect } (the action result), { verdict } (predicate pass/evidence/near-miss), and { trace } (the reaction report of everything the app did after the action). timeout_ms 0 evaluates the predicate once without waiting.",
|
|
4533
4843
|
inputSchema: {
|
|
4534
|
-
ref:
|
|
4535
|
-
action:
|
|
4536
|
-
args:
|
|
4844
|
+
ref: z15.string().describe("Element ref from iris_snapshot or iris_query."),
|
|
4845
|
+
action: z15.string().describe("Action to perform: click | dblclick | hover | focus | fill | type | clear | select | check | uncheck | submit | press | scrollIntoView"),
|
|
4846
|
+
args: z15.record(z15.unknown()).optional().describe("Action-specific arguments: { value } for fill/select, { text } for type/press."),
|
|
4537
4847
|
until: PredicateSchema.describe("Predicate to wait for after the action completes. Same shape accepted by iris_assert."),
|
|
4538
|
-
timeout_ms:
|
|
4539
|
-
refuseWhenThrottled:
|
|
4848
|
+
timeout_ms: z15.number().optional().describe("Maximum wait time in milliseconds. 0 = evaluate once without waiting. Default: 4000."),
|
|
4849
|
+
refuseWhenThrottled: z15.boolean().optional().describe("Throw if the tab is throttled. Default: false."),
|
|
4540
4850
|
...sessionIdShape6
|
|
4541
4851
|
},
|
|
4542
4852
|
outputSchema: {
|
|
4543
|
-
effect:
|
|
4544
|
-
verdict:
|
|
4545
|
-
pass:
|
|
4546
|
-
evidence:
|
|
4547
|
-
failureReason:
|
|
4853
|
+
effect: z15.unknown().describe("The iris_act result (dispatched, settled, inputMode, etc.)."),
|
|
4854
|
+
verdict: z15.object({
|
|
4855
|
+
pass: z15.boolean(),
|
|
4856
|
+
evidence: z15.unknown().optional(),
|
|
4857
|
+
failureReason: z15.string().optional()
|
|
4548
4858
|
}),
|
|
4549
|
-
trace:
|
|
4550
|
-
session:
|
|
4859
|
+
trace: z15.unknown().describe("Reaction report (same shape as iris_observe summary)."),
|
|
4860
|
+
session: z15.object({ lastSeenMs: z15.number(), throttled: z15.boolean(), focused: z15.boolean() }).optional()
|
|
4551
4861
|
},
|
|
4552
4862
|
handler: async (deps, args) => {
|
|
4553
4863
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4580,31 +4890,31 @@ var TOOLS = [
|
|
|
4580
4890
|
name: IrisTool.OBSERVE,
|
|
4581
4891
|
description: "Return the timeline of everything the app did in a window (DOM/network/route/console/animation/signal), with a summary. Use after an action. Pass `max_events` to cap the timeline to the most recent N (older events are dropped and counted in cost.droppedOldest). Every result carries a `cost:{events,bytes}` hint so you can self-budget your next call.",
|
|
4582
4892
|
inputSchema: {
|
|
4583
|
-
window_ms:
|
|
4584
|
-
since:
|
|
4585
|
-
filters:
|
|
4586
|
-
max_events:
|
|
4893
|
+
window_ms: z15.number().optional().describe("Time window to look back. Default: 2000ms. Ignored when `since` is provided."),
|
|
4894
|
+
since: z15.number().optional().describe("Cursor from a prior iris_act or iris_observe call. Scopes the event window to exactly that span."),
|
|
4895
|
+
filters: z15.array(z15.string()).optional().describe("Event type allowlist: dom | net | route | console | animation | signal. Omit to return all types."),
|
|
4896
|
+
max_events: z15.number().optional().describe("Cap the timeline to the most recent N events. Older events are counted in cost.droppedOldest."),
|
|
4587
4897
|
...sessionIdShape6
|
|
4588
4898
|
},
|
|
4589
4899
|
outputSchema: {
|
|
4590
|
-
events:
|
|
4591
|
-
summary:
|
|
4592
|
-
total:
|
|
4593
|
-
network:
|
|
4594
|
-
domAdded:
|
|
4595
|
-
domRemoved:
|
|
4596
|
-
domChanged:
|
|
4597
|
-
routeChanges:
|
|
4598
|
-
consoleErrors:
|
|
4599
|
-
animations:
|
|
4600
|
-
signals:
|
|
4900
|
+
events: z15.array(z15.unknown()),
|
|
4901
|
+
summary: z15.object({
|
|
4902
|
+
total: z15.number(),
|
|
4903
|
+
network: z15.number(),
|
|
4904
|
+
domAdded: z15.number(),
|
|
4905
|
+
domRemoved: z15.number(),
|
|
4906
|
+
domChanged: z15.number(),
|
|
4907
|
+
routeChanges: z15.number(),
|
|
4908
|
+
consoleErrors: z15.number(),
|
|
4909
|
+
animations: z15.number(),
|
|
4910
|
+
signals: z15.number()
|
|
4601
4911
|
}),
|
|
4602
|
-
cost:
|
|
4603
|
-
events:
|
|
4604
|
-
bytes:
|
|
4605
|
-
droppedOldest:
|
|
4912
|
+
cost: z15.object({
|
|
4913
|
+
events: z15.number(),
|
|
4914
|
+
bytes: z15.number(),
|
|
4915
|
+
droppedOldest: z15.number().optional()
|
|
4606
4916
|
}),
|
|
4607
|
-
session:
|
|
4917
|
+
session: z15.object({ lastSeenMs: z15.number(), throttled: z15.boolean(), focused: z15.boolean() }).optional()
|
|
4608
4918
|
},
|
|
4609
4919
|
handler: (deps, args) => {
|
|
4610
4920
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4627,15 +4937,15 @@ var TOOLS = [
|
|
|
4627
4937
|
description: "Block until a predicate is satisfied (or already true in the recent buffer), else time out. Returns matching evidence or a near-miss diagnosis. By default it only counts events since your last act, so a signal buffered BEFORE the action can never fake a pass; pass `since` (an observe/act cursor) to widen or narrow that window explicitly.",
|
|
4628
4938
|
inputSchema: {
|
|
4629
4939
|
predicate: PredicateSchema.describe("Predicate to wait for: { signal }, { net }, { element } or a combination."),
|
|
4630
|
-
timeout_ms:
|
|
4631
|
-
since:
|
|
4940
|
+
timeout_ms: z15.number().optional().describe("Maximum wait in milliseconds. Default: 4000."),
|
|
4941
|
+
since: z15.number().optional().describe("Cursor from a prior iris_act \u2014 scopes the wait to events after that act."),
|
|
4632
4942
|
...sessionIdShape6
|
|
4633
4943
|
},
|
|
4634
4944
|
outputSchema: {
|
|
4635
|
-
pass:
|
|
4636
|
-
evidence:
|
|
4637
|
-
failureReason:
|
|
4638
|
-
session:
|
|
4945
|
+
pass: z15.boolean(),
|
|
4946
|
+
evidence: z15.unknown().optional(),
|
|
4947
|
+
failureReason: z15.string().optional(),
|
|
4948
|
+
session: z15.object({ lastSeenMs: z15.number(), throttled: z15.boolean(), focused: z15.boolean() }).optional()
|
|
4639
4949
|
},
|
|
4640
4950
|
handler: async (deps, args) => {
|
|
4641
4951
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4650,15 +4960,15 @@ var TOOLS = [
|
|
|
4650
4960
|
description: "Evaluate a predicate (optionally waiting up to timeout_ms). Returns { pass, evidence, failureReason? }. The end of every verify loop. By default it only counts events since your last act, so a stale buffered signal can never fake a pass; pass `since` (an observe/act cursor) to set the window explicitly.",
|
|
4651
4961
|
inputSchema: {
|
|
4652
4962
|
predicate: PredicateSchema.describe("Predicate to evaluate: { signal }, { net }, { element } or a combination."),
|
|
4653
|
-
timeout_ms:
|
|
4654
|
-
since:
|
|
4963
|
+
timeout_ms: z15.number().optional().describe("If > 0, wait up to this many milliseconds before failing. Default: 0 (evaluate once)."),
|
|
4964
|
+
since: z15.number().optional().describe("Cursor from a prior iris_act \u2014 scopes the assertion to events after that act."),
|
|
4655
4965
|
...sessionIdShape6
|
|
4656
4966
|
},
|
|
4657
4967
|
outputSchema: {
|
|
4658
|
-
pass:
|
|
4659
|
-
evidence:
|
|
4660
|
-
failureReason:
|
|
4661
|
-
session:
|
|
4968
|
+
pass: z15.boolean(),
|
|
4969
|
+
evidence: z15.unknown().optional(),
|
|
4970
|
+
failureReason: z15.string().optional(),
|
|
4971
|
+
session: z15.object({ lastSeenMs: z15.number(), throttled: z15.boolean(), focused: z15.boolean() }).optional()
|
|
4662
4972
|
},
|
|
4663
4973
|
handler: async (deps, args) => {
|
|
4664
4974
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4673,15 +4983,15 @@ var TOOLS = [
|
|
|
4673
4983
|
name: IrisTool.NETWORK,
|
|
4674
4984
|
description: 'Filtered list of network calls. Fast path for "did POST /x return 200?". A zero-match filter returns a `hint` { totalInWindow, present[] } of the calls that DID fire, so a miss is diagnosable.',
|
|
4675
4985
|
inputSchema: {
|
|
4676
|
-
since:
|
|
4677
|
-
method:
|
|
4678
|
-
urlContains:
|
|
4679
|
-
status:
|
|
4986
|
+
since: z15.number().optional().describe("Cursor from a prior iris_act \u2014 scopes the query to requests fired after that act."),
|
|
4987
|
+
method: z15.string().optional().describe("HTTP method filter: GET | POST | PUT | DELETE | PATCH etc."),
|
|
4988
|
+
urlContains: z15.string().optional().describe("Substring that the request URL must contain."),
|
|
4989
|
+
status: z15.number().optional().describe("HTTP status code filter (e.g. 200, 404, 500)."),
|
|
4680
4990
|
...sessionIdShape6
|
|
4681
4991
|
},
|
|
4682
4992
|
outputSchema: {
|
|
4683
|
-
calls:
|
|
4684
|
-
hint:
|
|
4993
|
+
calls: z15.array(z15.unknown()),
|
|
4994
|
+
hint: z15.object({ totalInWindow: z15.number(), present: z15.array(z15.string()) }).optional()
|
|
4685
4995
|
},
|
|
4686
4996
|
handler: (deps, args) => {
|
|
4687
4997
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4701,13 +5011,13 @@ var TOOLS = [
|
|
|
4701
5011
|
name: IrisTool.CONSOLE,
|
|
4702
5012
|
description: 'Console/error log. Fast path for "were there any errors during this flow?". When a level filter matches nothing, returns a `hint` { totalInWindow, byLevel } so 0 errors is distinguishable from a silent page.',
|
|
4703
5013
|
inputSchema: {
|
|
4704
|
-
level:
|
|
4705
|
-
since:
|
|
5014
|
+
level: z15.string().optional().describe("Log level filter: error | warn | info | log. Omit to return all levels."),
|
|
5015
|
+
since: z15.number().optional().describe("Cursor from a prior iris_act \u2014 scopes the query to log entries after that act."),
|
|
4706
5016
|
...sessionIdShape6
|
|
4707
5017
|
},
|
|
4708
5018
|
outputSchema: {
|
|
4709
|
-
logs:
|
|
4710
|
-
hint:
|
|
5019
|
+
logs: z15.array(z15.unknown()),
|
|
5020
|
+
hint: z15.object({ totalInWindow: z15.number(), byLevel: z15.record(z15.number()) }).optional()
|
|
4711
5021
|
},
|
|
4712
5022
|
handler: (deps, args) => {
|
|
4713
5023
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4726,7 +5036,7 @@ var TOOLS = [
|
|
|
4726
5036
|
description: "Currently running + recently completed animations with targets/timing.",
|
|
4727
5037
|
inputSchema: { ...sessionIdShape6 },
|
|
4728
5038
|
outputSchema: {
|
|
4729
|
-
animations:
|
|
5039
|
+
animations: z15.array(z15.unknown())
|
|
4730
5040
|
},
|
|
4731
5041
|
handler: (deps, args) => commandOrThrow3(deps, asString4(args["sessionId"]), IrisCommand.ANIMATIONS, {})
|
|
4732
5042
|
},
|
|
@@ -4734,12 +5044,12 @@ var TOOLS = [
|
|
|
4734
5044
|
name: IrisTool.BASELINE_SAVE,
|
|
4735
5045
|
description: "Snapshot the current semantic state under a name, to diff against later (regression detection).",
|
|
4736
5046
|
inputSchema: {
|
|
4737
|
-
name:
|
|
5047
|
+
name: z15.string().describe('Label for this baseline snapshot (e.g. "dashboard-initial"). Use the same name in iris_diff to compare.'),
|
|
4738
5048
|
...sessionIdShape6
|
|
4739
5049
|
},
|
|
4740
5050
|
outputSchema: {
|
|
4741
|
-
baseline:
|
|
4742
|
-
lineCount:
|
|
5051
|
+
baseline: z15.string().describe("Saved baseline name \u2014 pass to iris_diff to compare."),
|
|
5052
|
+
lineCount: z15.number()
|
|
4743
5053
|
},
|
|
4744
5054
|
handler: async (deps, args) => {
|
|
4745
5055
|
const name = asString4(args["name"]) ?? "default";
|
|
@@ -4753,7 +5063,7 @@ var TOOLS = [
|
|
|
4753
5063
|
description: "List saved baseline names.",
|
|
4754
5064
|
inputSchema: {},
|
|
4755
5065
|
outputSchema: {
|
|
4756
|
-
baselines:
|
|
5066
|
+
baselines: z15.array(z15.string())
|
|
4757
5067
|
},
|
|
4758
5068
|
handler: (deps) => Promise.resolve({ baselines: deps.baselines.list() })
|
|
4759
5069
|
},
|
|
@@ -4761,15 +5071,15 @@ var TOOLS = [
|
|
|
4761
5071
|
name: IrisTool.DIFF,
|
|
4762
5072
|
description: 'Diff current semantic state vs a saved baseline: REMOVED/ADDED elements + console-error count. Call iris_baseline_list to list saved baselines, iris_baseline_save to create one. Pass `baseline` (name from iris_baseline_list). Answers "did anything silently go missing/break?".',
|
|
4763
5073
|
inputSchema: {
|
|
4764
|
-
baseline:
|
|
5074
|
+
baseline: z15.string().describe("Baseline name to compare against. Call iris_baseline_list to get available names; names are created by iris_baseline_save."),
|
|
4765
5075
|
...sessionIdShape6
|
|
4766
5076
|
},
|
|
4767
5077
|
outputSchema: {
|
|
4768
|
-
baseline:
|
|
4769
|
-
removed:
|
|
4770
|
-
added:
|
|
4771
|
-
consoleErrors:
|
|
4772
|
-
routeChanged:
|
|
5078
|
+
baseline: z15.string(),
|
|
5079
|
+
removed: z15.array(z15.string()),
|
|
5080
|
+
added: z15.array(z15.string()),
|
|
5081
|
+
consoleErrors: z15.number(),
|
|
5082
|
+
routeChanged: z15.boolean()
|
|
4773
5083
|
},
|
|
4774
5084
|
handler: async (deps, args) => {
|
|
4775
5085
|
const name = asString4(args["baseline"]) ?? "default";
|
|
@@ -4787,12 +5097,12 @@ var TOOLS = [
|
|
|
4787
5097
|
name: IrisTool.RECORD_START,
|
|
4788
5098
|
description: "Start recording the event timeline under a name (for replay / a flow report).",
|
|
4789
5099
|
inputSchema: {
|
|
4790
|
-
recordingName:
|
|
5100
|
+
recordingName: z15.string().describe("Identifier for this recording. Pass the same name to iris_record_stop and iris_replay."),
|
|
4791
5101
|
...sessionIdShape6
|
|
4792
5102
|
},
|
|
4793
5103
|
outputSchema: {
|
|
4794
|
-
recordingName:
|
|
4795
|
-
since:
|
|
5104
|
+
recordingName: z15.string(),
|
|
5105
|
+
since: z15.number()
|
|
4796
5106
|
},
|
|
4797
5107
|
handler: (deps, args) => {
|
|
4798
5108
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4806,13 +5116,13 @@ var TOOLS = [
|
|
|
4806
5116
|
name: IrisTool.RECORD_STOP,
|
|
4807
5117
|
description: "Stop the recording identified by `recordingName` and return both the reaction report for the span and a compiled, replayable { program: { version, steps:[{tool,args,stable}] } } of the agent acts captured during it.",
|
|
4808
5118
|
inputSchema: {
|
|
4809
|
-
recordingName:
|
|
5119
|
+
recordingName: z15.string().describe("Identifier of an active recording started with iris_record_start."),
|
|
4810
5120
|
...sessionIdShape6
|
|
4811
5121
|
},
|
|
4812
5122
|
outputSchema: {
|
|
4813
|
-
recordingName:
|
|
4814
|
-
program:
|
|
4815
|
-
warning:
|
|
5123
|
+
recordingName: z15.string(),
|
|
5124
|
+
program: z15.unknown(),
|
|
5125
|
+
warning: z15.string().optional()
|
|
4816
5126
|
},
|
|
4817
5127
|
handler: (deps, args) => {
|
|
4818
5128
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4844,17 +5154,17 @@ var TOOLS = [
|
|
|
4844
5154
|
name: IrisTool.REPLAY,
|
|
4845
5155
|
description: "Re-execute a previously recorded program by recordingName. Re-resolves each step to its element by testid (falling back to the stored ref for unstable steps) and runs the actions in order against the live session. Stops at the first failure. Returns { ok, steps:[{tool,ok,error?,note?}] }.",
|
|
4846
5156
|
inputSchema: {
|
|
4847
|
-
recordingName:
|
|
5157
|
+
recordingName: z15.string().describe("Name of a compiled recording (from iris_record_stop) to re-execute."),
|
|
4848
5158
|
...sessionIdShape6
|
|
4849
5159
|
},
|
|
4850
5160
|
outputSchema: {
|
|
4851
|
-
recordingName:
|
|
4852
|
-
ok:
|
|
4853
|
-
steps:
|
|
4854
|
-
tool:
|
|
4855
|
-
ok:
|
|
4856
|
-
error:
|
|
4857
|
-
note:
|
|
5161
|
+
recordingName: z15.string(),
|
|
5162
|
+
ok: z15.boolean(),
|
|
5163
|
+
steps: z15.array(z15.object({
|
|
5164
|
+
tool: z15.string(),
|
|
5165
|
+
ok: z15.boolean(),
|
|
5166
|
+
error: z15.string().optional(),
|
|
5167
|
+
note: z15.string().optional()
|
|
4858
5168
|
}))
|
|
4859
5169
|
},
|
|
4860
5170
|
handler: async (deps, args) => {
|
|
@@ -4872,30 +5182,31 @@ var TOOLS = [
|
|
|
4872
5182
|
name: IrisTool.NARRATE,
|
|
4873
5183
|
description: "Narrate your intent on the page (presenter HUD) so the human watching sees what you are about to do and why. Use a short sentence before a meaningful action.",
|
|
4874
5184
|
inputSchema: {
|
|
4875
|
-
text:
|
|
4876
|
-
level:
|
|
5185
|
+
text: z15.string().describe("Short sentence describing your next action, shown on the presenter HUD for the developer watching."),
|
|
5186
|
+
level: z15.string().optional().describe("Display severity: info | warn | error. Default: info."),
|
|
4877
5187
|
...sessionIdShape6
|
|
4878
5188
|
},
|
|
4879
|
-
outputSchema: {
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
5189
|
+
outputSchema: { ok: z15.boolean() },
|
|
5190
|
+
handler: async (deps, args) => {
|
|
5191
|
+
const result = await commandOrThrow3(deps, asString4(args["sessionId"]), IrisCommand.NARRATE, {
|
|
5192
|
+
text: args["text"],
|
|
5193
|
+
level: args["level"]
|
|
5194
|
+
});
|
|
5195
|
+
return { ok: true, ...result };
|
|
5196
|
+
}
|
|
4886
5197
|
},
|
|
4887
5198
|
{
|
|
4888
5199
|
name: IrisTool.CLOCK,
|
|
4889
5200
|
description: "Control a fake clock: { freeze:true } to freeze time, { advanceMs:N } to fast-forward timers (toasts, debounces, auto-dismiss), { reset:true } to restore. Lets you test time-gated UI deterministically.",
|
|
4890
5201
|
inputSchema: {
|
|
4891
|
-
freeze:
|
|
4892
|
-
advanceMs:
|
|
4893
|
-
reset:
|
|
5202
|
+
freeze: z15.boolean().optional().describe("Freeze the fake clock. Time stops advancing until advanceMs or reset."),
|
|
5203
|
+
advanceMs: z15.number().optional().describe("Fast-forward time by this many milliseconds \u2014 triggers debounces, toasts, auto-dismiss timers."),
|
|
5204
|
+
reset: z15.boolean().optional().describe("Restore the real clock."),
|
|
4894
5205
|
...sessionIdShape6
|
|
4895
5206
|
},
|
|
4896
5207
|
outputSchema: {
|
|
4897
|
-
ok:
|
|
4898
|
-
elapsed:
|
|
5208
|
+
ok: z15.boolean().optional(),
|
|
5209
|
+
elapsed: z15.number().optional()
|
|
4899
5210
|
},
|
|
4900
5211
|
handler: (deps, args) => commandOrThrow3(deps, asString4(args["sessionId"]), IrisCommand.CLOCK, {
|
|
4901
5212
|
freeze: args["freeze"],
|
|
@@ -4907,18 +5218,18 @@ var TOOLS = [
|
|
|
4907
5218
|
name: IrisTool.STATE,
|
|
4908
5219
|
description: "Read live framework state without the app pre-broadcasting it. PREFERRED/RELIABLE: `store` reads a registered store (e.g. 'workspace'); omit `store` to read all stores. To avoid paying for a huge store, scope the read: `path` extracts a dot-path sub-tree (e.g. 'captionCache.v3', with numeric array indices), and `depth` collapses anything deeper than N levels to a size marker. A wrong `path` returns { found:false, availableKeys } so it is diagnosable. `ref` attempts a best-effort read of the nearest React component's hook state and is BOUNDED \u2014 on failure it returns component: { ok: false, reason: 'component-state-unavailable' }. Without path/depth: returns { stores, storeNames, component? }.",
|
|
4909
5220
|
inputSchema: {
|
|
4910
|
-
ref:
|
|
4911
|
-
store:
|
|
4912
|
-
path:
|
|
4913
|
-
depth:
|
|
5221
|
+
ref: z15.string().optional().describe("Element ref \u2014 attempts a best-effort read of the nearest React component's hook state."),
|
|
5222
|
+
store: z15.string().optional().describe("Registered store name (e.g. 'workspace'). Omit to read all stores."),
|
|
5223
|
+
path: z15.string().optional().describe("Dot-path into the store (e.g. 'captionCache.v3'). Numeric array indices are supported."),
|
|
5224
|
+
depth: z15.number().optional().describe("Collapse anything deeper than N levels to a size marker \u2014 avoids huge outputs for large stores."),
|
|
4914
5225
|
...sessionIdShape6
|
|
4915
5226
|
},
|
|
4916
5227
|
outputSchema: {
|
|
4917
|
-
stores:
|
|
4918
|
-
storeNames:
|
|
4919
|
-
found:
|
|
4920
|
-
value:
|
|
4921
|
-
component:
|
|
5228
|
+
stores: z15.record(z15.unknown()).optional(),
|
|
5229
|
+
storeNames: z15.array(z15.string()).optional(),
|
|
5230
|
+
found: z15.boolean().optional(),
|
|
5231
|
+
value: z15.unknown().optional(),
|
|
5232
|
+
component: z15.object({ ok: z15.boolean(), reason: z15.string().optional(), state: z15.unknown().optional() }).optional()
|
|
4922
5233
|
},
|
|
4923
5234
|
handler: async (deps, args) => {
|
|
4924
5235
|
const store = asString4(args["store"]);
|
|
@@ -4947,13 +5258,13 @@ var TOOLS = [
|
|
|
4947
5258
|
name: IrisTool.EXPLORE,
|
|
4948
5259
|
description: "Autonomous-exploration helper: list interactive elements (with refs) + current console-error count, so the agent can drive the app and report anomalies.",
|
|
4949
5260
|
inputSchema: {
|
|
4950
|
-
scope:
|
|
5261
|
+
scope: z15.string().optional().describe("CSS selector or element ref to restrict the interactive element list to a subtree."),
|
|
4951
5262
|
...sessionIdShape6
|
|
4952
5263
|
},
|
|
4953
5264
|
outputSchema: {
|
|
4954
|
-
interactive:
|
|
4955
|
-
consoleErrors:
|
|
4956
|
-
hint:
|
|
5265
|
+
interactive: z15.array(z15.unknown()),
|
|
5266
|
+
consoleErrors: z15.number(),
|
|
5267
|
+
hint: z15.string()
|
|
4957
5268
|
},
|
|
4958
5269
|
handler: async (deps, args) => {
|
|
4959
5270
|
const session = deps.sessions.resolve(asString4(args["sessionId"]));
|
|
@@ -4991,7 +5302,9 @@ var TOOLS = [
|
|
|
4991
5302
|
// Live-control: iris_end_session / iris_resume / iris_messages. See live-control-tools.ts.
|
|
4992
5303
|
...LIVE_CONTROL_TOOLS,
|
|
4993
5304
|
// iris_navigate / iris_refresh — browser navigation tools. See browser-tools.ts.
|
|
4994
|
-
...BROWSER_TOOLS
|
|
5305
|
+
...BROWSER_TOOLS,
|
|
5306
|
+
// iris_version_info / iris_apply_update / iris_rollback — update lifecycle tools.
|
|
5307
|
+
...UPDATE_TOOLS
|
|
4995
5308
|
];
|
|
4996
5309
|
|
|
4997
5310
|
// ../server/dist/tools/profiles.js
|
|
@@ -5137,7 +5450,7 @@ async function runTool(tool, deps, args) {
|
|
|
5137
5450
|
}
|
|
5138
5451
|
|
|
5139
5452
|
// ../server/dist/mcp.js
|
|
5140
|
-
var SERVER_INFO = { name: "iris", version:
|
|
5453
|
+
var SERVER_INFO = { name: "iris", version: SERVER_VERSION };
|
|
5141
5454
|
var ENCODING_ENV = "IRIS_ENCODING";
|
|
5142
5455
|
var TOON_VALUE = "toon";
|
|
5143
5456
|
function encodeResult(result, useToon) {
|
|
@@ -5251,6 +5564,13 @@ function createToolInvoker(deps) {
|
|
|
5251
5564
|
};
|
|
5252
5565
|
}
|
|
5253
5566
|
|
|
5567
|
+
// ../server/dist/daemon.js
|
|
5568
|
+
import { join as join4 } from "path";
|
|
5569
|
+
import { homedir as homedir2 } from "os";
|
|
5570
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3, unlinkSync, openSync } from "fs";
|
|
5571
|
+
import { spawn } from "child_process";
|
|
5572
|
+
var IRIS_HOME2 = join4(homedir2(), ".iris");
|
|
5573
|
+
|
|
5254
5574
|
// ../server/dist/index.js
|
|
5255
5575
|
async function start(options = {}) {
|
|
5256
5576
|
const port = options.port ?? IRIS_DEFAULT_PORT;
|
|
@@ -5283,11 +5603,11 @@ async function start(options = {}) {
|
|
|
5283
5603
|
}
|
|
5284
5604
|
}
|
|
5285
5605
|
if (options.mcp !== false) {
|
|
5286
|
-
const
|
|
5287
|
-
const irisRoot = options.irisRoot ??
|
|
5606
|
+
const fs2 = createNodeFileSystem();
|
|
5607
|
+
const irisRoot = options.irisRoot ?? join5(process.cwd(), IrisDir.ROOT);
|
|
5288
5608
|
const now = options.now ?? (() => Date.now());
|
|
5289
|
-
const flows = new FlowStore(
|
|
5290
|
-
const project = new ProjectStore(
|
|
5609
|
+
const flows = new FlowStore(fs2, irisRoot, { now });
|
|
5610
|
+
const project = new ProjectStore(fs2, irisRoot, { now });
|
|
5291
5611
|
const annotations = new AnnotationStore();
|
|
5292
5612
|
const deps = {
|
|
5293
5613
|
sessions: bridge.sessions,
|
|
@@ -5296,7 +5616,7 @@ async function start(options = {}) {
|
|
|
5296
5616
|
annotations,
|
|
5297
5617
|
flows,
|
|
5298
5618
|
project,
|
|
5299
|
-
fs,
|
|
5619
|
+
fs: fs2,
|
|
5300
5620
|
irisRoot,
|
|
5301
5621
|
now
|
|
5302
5622
|
};
|
|
@@ -5321,17 +5641,17 @@ async function start(options = {}) {
|
|
|
5321
5641
|
|
|
5322
5642
|
// ../test/dist/boot.js
|
|
5323
5643
|
function defaultBuildDeps(server, opts) {
|
|
5324
|
-
const
|
|
5325
|
-
const irisRoot = opts.irisRoot ??
|
|
5644
|
+
const fs2 = createNodeFileSystem();
|
|
5645
|
+
const irisRoot = opts.irisRoot ?? join6(process.cwd(), IrisDir.ROOT);
|
|
5326
5646
|
const now = opts.now ?? (() => Date.now());
|
|
5327
5647
|
const base = {
|
|
5328
5648
|
sessions: server.bridge.sessions,
|
|
5329
5649
|
baselines: new BaselineStore(),
|
|
5330
5650
|
recordings: new RecordingStore(),
|
|
5331
|
-
flows: new FlowStore(
|
|
5332
|
-
project: new ProjectStore(
|
|
5651
|
+
flows: new FlowStore(fs2, irisRoot, { now }),
|
|
5652
|
+
project: new ProjectStore(fs2, irisRoot, { now }),
|
|
5333
5653
|
annotations: new AnnotationStore(),
|
|
5334
|
-
fs,
|
|
5654
|
+
fs: fs2,
|
|
5335
5655
|
irisRoot,
|
|
5336
5656
|
now
|
|
5337
5657
|
};
|