mira-harness 0.2.6 → 0.2.7

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 CHANGED
@@ -434,6 +434,9 @@ function clearTitle() {
434
434
  // src/commands/report.ts
435
435
  import { readFileSync as readFileSync2, writeFileSync } from "node:fs";
436
436
  import { resolve as resolve3 } from "node:path";
437
+ function isRunRecord(x) {
438
+ return typeof x === "object" && x !== null && Array.isArray(x.messages) && typeof x.sent === "string";
439
+ }
437
440
  function loadRunRecords(inFile, category) {
438
441
  const path = inFile ? resolve3(process.cwd(), inFile) : RUNS_FILE;
439
442
  const raw = readFileSync2(path, "utf8");
@@ -444,7 +447,9 @@ function loadRunRecords(inFile, category) {
444
447
  if (!t)
445
448
  continue;
446
449
  try {
447
- records.push(JSON.parse(t));
450
+ const rec = JSON.parse(t);
451
+ if (isRunRecord(rec))
452
+ records.push(rec);
448
453
  } catch {}
449
454
  }
450
455
  return category ? records.filter((r) => r.category === category) : records;
@@ -867,7 +872,14 @@ function req(name) {
867
872
  return v;
868
873
  }
869
874
  var tgEnv = {
870
- apiId: () => Number(req("TG_API_ID")),
875
+ apiId: () => {
876
+ const raw = req("TG_API_ID");
877
+ const n = Number(raw);
878
+ if (!Number.isInteger(n) || n <= 0) {
879
+ throw new Error(`TG_API_ID must be a positive integer (got "${raw}") — see .env.example`);
880
+ }
881
+ return n;
882
+ },
871
883
  apiHash: () => req("TG_API_HASH"),
872
884
  session: () => process.env.TG_SESSION ?? "",
873
885
  miraPeer: process.env.MIRA_PEER ?? "mira",
@@ -1325,14 +1337,14 @@ async function send(rawMessage, opts = {}) {
1325
1337
  let verdict;
1326
1338
  try {
1327
1339
  const result = await withProgress(`@${peer}`, () => sendAndCollect(client, peer, message, collect), opts.quiet);
1340
+ if (opts.expect)
1341
+ verdict = evaluate(opts.expect, result);
1328
1342
  if (!opts.noLog)
1329
- await appendRun(result);
1343
+ await appendRun(result, verdict ? { assert: verdict } : {});
1330
1344
  if (!opts.quiet) {
1331
1345
  note(result.timedOut ? c.yellow("no reply (timed out)") : c.green(`${result.messages.length} message(s) · first reply ${((result.firstReplyMs ?? 0) / 1000).toFixed(1)}s`));
1332
1346
  }
1333
1347
  console.log(JSON.stringify(result, null, 2));
1334
- if (opts.expect)
1335
- verdict = evaluate(opts.expect, result);
1336
1348
  } finally {
1337
1349
  await client.disconnect();
1338
1350
  }
@@ -1634,10 +1646,19 @@ if (process.argv.length <= 2) {
1634
1646
  banner(version);
1635
1647
  console.log(` Drive @mira from your terminal — QA, learn, and assert on its behavior.
1636
1648
  `);
1637
- console.log(` Commands ${c.cyan("login · doctor · send · loop · catalog · watch")}`);
1638
- console.log(` ${c.cyan("report · stats · diff · assert · schema")}
1639
- `);
1640
- console.log(` Run ${c.bold("mira-harness --help")} for options + examples, or ${c.bold("mira-harness <command> --help")}.`);
1649
+ console.log(` ${c.bold("Commands")}`);
1650
+ const cmds = program.commands.filter((cmd) => cmd.name() !== "help");
1651
+ const pad = Math.max(...cmds.map((cmd) => cmd.name().length));
1652
+ for (const cmd of cmds) {
1653
+ console.log(` ${c.cyan(cmd.name().padEnd(pad))} ${c.dim(cmd.description())}`);
1654
+ }
1655
+ console.log(`
1656
+ ${c.bold("Quick start")}`);
1657
+ for (const ex of ["login", "doctor", 'send "What can you do?"', "loop --category core"]) {
1658
+ console.log(c.dim(` $ mira-harness ${ex}`));
1659
+ }
1660
+ console.log(`
1661
+ Run ${c.bold("mira-harness --help")} for all options + examples, or ${c.bold("mira-harness <command> --help")}.`);
1641
1662
  process.exit(0);
1642
1663
  }
1643
1664
  program.parseAsync(process.argv).then(() => process.exit(0)).catch((e) => {
@@ -7,9 +7,9 @@ export type RunRecord = ProbeResult & {
7
7
  assert?: Verdict;
8
8
  };
9
9
  /**
10
- * Read the JSONL run log into records (malformed lines skipped). Throws ENOENT when
11
- * the file is absent — callers decide how to surface that. Shared by `report` and
12
- * `stats` so the two stay in lockstep on the log format.
10
+ * Read the JSONL run log into records (malformed/wrong-shape lines skipped). Throws
11
+ * ENOENT when the file is absent — callers decide how to surface that. Shared by
12
+ * `report` and `stats` so the two stay in lockstep on the log format.
13
13
  */
14
14
  export declare function loadRunRecords(inFile?: string, category?: string): RunRecord[];
15
15
  export declare function buildReport(records: RunRecord[]): string;
package/dist/env.d.ts CHANGED
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import "dotenv/config";
9
9
  export declare const tgEnv: {
10
+ /** Telegram api_id — a positive integer. Reject non-numeric/zero up front so
11
+ * `doctor` flags a bad value instead of passing NaN into GramJS (cryptic later). */
10
12
  apiId: () => number;
11
13
  apiHash: () => string;
12
14
  /** Empty until `mira-harness login` mints it; required by send/loop. */
package/dist/index.js CHANGED
@@ -414,7 +414,14 @@ function req(name) {
414
414
  return v;
415
415
  }
416
416
  var tgEnv = {
417
- apiId: () => Number(req("TG_API_ID")),
417
+ apiId: () => {
418
+ const raw = req("TG_API_ID");
419
+ const n = Number(raw);
420
+ if (!Number.isInteger(n) || n <= 0) {
421
+ throw new Error(`TG_API_ID must be a positive integer (got "${raw}") — see .env.example`);
422
+ }
423
+ return n;
424
+ },
418
425
  apiHash: () => req("TG_API_HASH"),
419
426
  session: () => process.env.TG_SESSION ?? "",
420
427
  miraPeer: process.env.MIRA_PEER ?? "mira",
@@ -596,6 +603,9 @@ async function appendRun(result, meta = {}) {
596
603
  }
597
604
 
598
605
  // src/commands/report.ts
606
+ function isRunRecord(x) {
607
+ return typeof x === "object" && x !== null && Array.isArray(x.messages) && typeof x.sent === "string";
608
+ }
599
609
  function loadRunRecords(inFile, category) {
600
610
  const path = inFile ? resolve3(process.cwd(), inFile) : RUNS_FILE;
601
611
  const raw = readFileSync2(path, "utf8");
@@ -606,7 +616,9 @@ function loadRunRecords(inFile, category) {
606
616
  if (!t)
607
617
  continue;
608
618
  try {
609
- records.push(JSON.parse(t));
619
+ const rec = JSON.parse(t);
620
+ if (isRunRecord(rec))
621
+ records.push(rec);
610
622
  } catch {}
611
623
  }
612
624
  return category ? records.filter((r) => r.category === category) : records;
package/dist/mcp.js CHANGED
@@ -424,7 +424,14 @@ function req(name) {
424
424
  return v;
425
425
  }
426
426
  var tgEnv = {
427
- apiId: () => Number(req("TG_API_ID")),
427
+ apiId: () => {
428
+ const raw = req("TG_API_ID");
429
+ const n = Number(raw);
430
+ if (!Number.isInteger(n) || n <= 0) {
431
+ throw new Error(`TG_API_ID must be a positive integer (got "${raw}") — see .env.example`);
432
+ }
433
+ return n;
434
+ },
428
435
  apiHash: () => req("TG_API_HASH"),
429
436
  session: () => process.env.TG_SESSION ?? "",
430
437
  miraPeer: process.env.MIRA_PEER ?? "mira",
@@ -607,6 +614,9 @@ async function appendRun(result, meta = {}) {
607
614
  }
608
615
 
609
616
  // src/commands/report.ts
617
+ function isRunRecord(x) {
618
+ return typeof x === "object" && x !== null && Array.isArray(x.messages) && typeof x.sent === "string";
619
+ }
610
620
  function loadRunRecords(inFile, category) {
611
621
  const path = inFile ? resolve3(process.cwd(), inFile) : RUNS_FILE;
612
622
  const raw = readFileSync2(path, "utf8");
@@ -617,7 +627,9 @@ function loadRunRecords(inFile, category) {
617
627
  if (!t)
618
628
  continue;
619
629
  try {
620
- records.push(JSON.parse(t));
630
+ const rec = JSON.parse(t);
631
+ if (isRunRecord(rec))
632
+ records.push(rec);
621
633
  } catch {}
622
634
  }
623
635
  return category ? records.filter((r) => r.category === category) : records;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mira-harness",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "A CLI + MCP dev-tool for communicating with the @mira Telegram bot — capture its full reply (buttons/links/media) and run a self-driving experiment catalog.",
5
5
  "type": "module",
6
6
  "bin": {