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 +30 -9
- package/dist/commands/report.d.ts +3 -3
- package/dist/env.d.ts +2 -0
- package/dist/index.js +14 -2
- package/dist/mcp.js +14 -2
- package/package.json +1 -1
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
|
-
|
|
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: () =>
|
|
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(`
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
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
|
|
11
|
-
* the file is absent — callers decide how to surface that. Shared by
|
|
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: () =>
|
|
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
|
-
|
|
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: () =>
|
|
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
|
-
|
|
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.
|
|
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": {
|