sessionpipe-conformance 0.13.0 → 0.13.2
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.d.ts.map +1 -1
- package/dist/cli.js +135 -70
- package/dist/cli.js.map +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +119 -67
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAeA,gFAAgF;AAChF,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE;IAAE,MAAM,EAAE;QAAE,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;CAAY,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAeA,gFAAgF;AAChF,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE;IAAE,MAAM,EAAE;QAAE,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;CAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BnH"}
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// sessionpipe-conformance 0.13.
|
|
2
|
+
// sessionpipe-conformance 0.13.2 · Apache-2.0 · https://sessionpipe.org
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
5
|
import { readdirSync as readdirSync5, realpathSync as realpathSync2, statSync as statSync5 } from "node:fs";
|
|
@@ -16,7 +16,7 @@ var homeDir = () => os.homedir();
|
|
|
16
16
|
// ../core/src/adapters/claude-code.ts
|
|
17
17
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
18
18
|
import { createHash } from "node:crypto";
|
|
19
|
-
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2
|
|
19
|
+
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
20
20
|
import { userInfo } from "node:os";
|
|
21
21
|
import path3 from "node:path";
|
|
22
22
|
|
|
@@ -374,6 +374,41 @@ function readJson(file) {
|
|
|
374
374
|
const f = readJsonFile(file);
|
|
375
375
|
return f.ok ? f.value : {};
|
|
376
376
|
}
|
|
377
|
+
function refused(file, e, what, existed) {
|
|
378
|
+
const { code, syscall } = e;
|
|
379
|
+
const why = `can't ${what} it (${code ?? String(e)})`;
|
|
380
|
+
if (what === "remove" || syscall === "open" || syscall === "mkdir")
|
|
381
|
+
return { file, changed: false, skipped: true, note: `${why}; not touched` };
|
|
382
|
+
return {
|
|
383
|
+
file,
|
|
384
|
+
changed: true,
|
|
385
|
+
skipped: true,
|
|
386
|
+
...existed ? {} : { created: true },
|
|
387
|
+
note: `${why} part way; check the file before the harness reads it`
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function writeBack(file, text, existed = true) {
|
|
391
|
+
try {
|
|
392
|
+
mkdirSync(path2.dirname(file), { recursive: true });
|
|
393
|
+
writeFileSync(file, text);
|
|
394
|
+
return null;
|
|
395
|
+
} catch (e) {
|
|
396
|
+
return refused(file, e, "write", existed);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function removeEmptied(file, empty) {
|
|
400
|
+
try {
|
|
401
|
+
unlinkSync(file);
|
|
402
|
+
return { file, changed: true, note: "removed (sessionpipe created it)" };
|
|
403
|
+
} catch (e) {
|
|
404
|
+
const bad = refused(file, e, "remove", true);
|
|
405
|
+
return writeBack(file, empty) ?? {
|
|
406
|
+
file,
|
|
407
|
+
changed: true,
|
|
408
|
+
note: `emptied; ${bad.note.replace(/; not touched$/, "")}, so the empty file stays`
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
377
412
|
function entryFor(event, harness, cmd, o) {
|
|
378
413
|
const matcher = o.matcherFor(event);
|
|
379
414
|
return {
|
|
@@ -415,8 +450,8 @@ function installClaudeShaped(file, harness, events, cmd, o) {
|
|
|
415
450
|
}
|
|
416
451
|
if (changed) {
|
|
417
452
|
settings2.hooks = hooks;
|
|
418
|
-
|
|
419
|
-
|
|
453
|
+
const bad = writeBack(file, formatJson(settings2, f), f.existed);
|
|
454
|
+
if (bad) return bad;
|
|
420
455
|
}
|
|
421
456
|
return { file, changed, created: !f.existed && changed };
|
|
422
457
|
}
|
|
@@ -439,12 +474,8 @@ function uninstallClaudeShaped(file, events, opts = {}) {
|
|
|
439
474
|
}
|
|
440
475
|
if (!changed) return { file, changed: false };
|
|
441
476
|
if (!Object.keys(hooks).length) delete settings2.hooks;
|
|
442
|
-
if (opts.created && !Object.keys(settings2).length)
|
|
443
|
-
|
|
444
|
-
return { file, changed: true, note: "removed (sessionpipe created it)" };
|
|
445
|
-
}
|
|
446
|
-
writeFileSync(file, formatJson(settings2, f));
|
|
447
|
-
return { file, changed: true };
|
|
477
|
+
if (opts.created && !Object.keys(settings2).length) return removeEmptied(file, formatJson(settings2, f));
|
|
478
|
+
return writeBack(file, formatJson(settings2, f)) ?? { file, changed: true };
|
|
448
479
|
}
|
|
449
480
|
function installedClaudeShaped(file, harness, events, cmd, o) {
|
|
450
481
|
const f = readJsonFile(file);
|
|
@@ -523,7 +554,7 @@ var claudeCode = {
|
|
|
523
554
|
configFiles: (env = process.env) => claudeDirs(env).map(settingsIn),
|
|
524
555
|
install: (cmd, env = process.env, opts = {}) => claudeDirs(env).flatMap((d) => {
|
|
525
556
|
const hooks = installClaudeShaped(settingsIn(d), NAME, eventsFor(opts.lean), cmd, OPTS);
|
|
526
|
-
const line = opts.statusLine === void 0 ? null : statusLine(settingsIn(d), opts.statusLine, cmd);
|
|
557
|
+
const line = opts.statusLine === void 0 || hooks.skipped ? null : statusLine(settingsIn(d), opts.statusLine, cmd);
|
|
527
558
|
return line ? [hooks, line] : [hooks];
|
|
528
559
|
}),
|
|
529
560
|
uninstall: (env = process.env, opts = {}) => claudeDirs(env).map((d) => {
|
|
@@ -531,7 +562,9 @@ var claudeCode = {
|
|
|
531
562
|
const hooks = uninstallClaudeShaped(settingsIn(d), CLAUDE_EVENTS, {
|
|
532
563
|
created: opts.created?.includes(settingsIn(d))
|
|
533
564
|
});
|
|
534
|
-
|
|
565
|
+
if (line?.changed && !line.skipped && hooks.skipped)
|
|
566
|
+
return { ...hooks, note: `status line removed, hooks not: ${hooks.note?.replace(/; not touched$/, "")}` };
|
|
567
|
+
return line && !hooks.changed && !hooks.skipped ? line : hooks;
|
|
535
568
|
}),
|
|
536
569
|
installed: (cmd, env = process.env, opts = {}) => claudeDirs(env).map((d) => ({
|
|
537
570
|
file: settingsIn(d),
|
|
@@ -626,7 +659,8 @@ var claudeCode = {
|
|
|
626
659
|
attention_id: call_id ?? permissionId(),
|
|
627
660
|
kind: "permission",
|
|
628
661
|
tool,
|
|
629
|
-
message: tool ? `${tool}${describe(s.tool_input)}` : void 0
|
|
662
|
+
message: tool ? `${tool}${describe(s.tool_input)}` : void 0,
|
|
663
|
+
agent_id
|
|
630
664
|
})
|
|
631
665
|
);
|
|
632
666
|
break;
|
|
@@ -635,7 +669,8 @@ var claudeCode = {
|
|
|
635
669
|
ev("attention.needed", {
|
|
636
670
|
attention_id: `notif-${Date.now()}`,
|
|
637
671
|
kind: notifKind(s.notification_type),
|
|
638
|
-
message: typeof s.message === "string" ? s.message.slice(0, 200) : void 0
|
|
672
|
+
message: typeof s.message === "string" ? s.message.slice(0, 200) : void 0,
|
|
673
|
+
agent_id
|
|
639
674
|
})
|
|
640
675
|
);
|
|
641
676
|
break;
|
|
@@ -760,8 +795,11 @@ function statusLine(file, want, cmd) {
|
|
|
760
795
|
if (want ? ours && cur?.command === command && cur?.refreshInterval === LINE_REFRESH_S : !ours) return null;
|
|
761
796
|
if (want) f.value.statusLine = { type: "command", command, refreshInterval: LINE_REFRESH_S };
|
|
762
797
|
else delete f.value.statusLine;
|
|
763
|
-
|
|
764
|
-
|
|
798
|
+
return writeBack(file, formatJson(f.value, f), f.existed) ?? {
|
|
799
|
+
file,
|
|
800
|
+
changed: true,
|
|
801
|
+
note: want ? "status line written (account limits)" : "status line removed"
|
|
802
|
+
};
|
|
765
803
|
}
|
|
766
804
|
var epochIso = (t) => typeof t === "number" && t > 0 && t < 1e11 ? new Date(t * 1e3).toISOString() : void 0;
|
|
767
805
|
var WINDOW_MINUTES = { five_hour: 300, seven_day: 10080 };
|
|
@@ -1253,16 +1291,7 @@ function probe(bin, args) {
|
|
|
1253
1291
|
}
|
|
1254
1292
|
|
|
1255
1293
|
// ../core/src/adapters/antigravity.ts
|
|
1256
|
-
import {
|
|
1257
|
-
existsSync as existsSync3,
|
|
1258
|
-
mkdirSync as mkdirSync2,
|
|
1259
|
-
readdirSync as readdirSync3,
|
|
1260
|
-
readFileSync as readFileSync4,
|
|
1261
|
-
realpathSync,
|
|
1262
|
-
statSync as statSync4,
|
|
1263
|
-
unlinkSync as unlinkSync2,
|
|
1264
|
-
writeFileSync as writeFileSync3
|
|
1265
|
-
} from "node:fs";
|
|
1294
|
+
import { existsSync as existsSync3, readdirSync as readdirSync3, readFileSync as readFileSync4, realpathSync, statSync as statSync4 } from "node:fs";
|
|
1266
1295
|
import path5 from "node:path";
|
|
1267
1296
|
var NAME2 = "antigravity";
|
|
1268
1297
|
var HOOK_NAME = "sessionpipe";
|
|
@@ -1294,10 +1323,8 @@ var antigravity = {
|
|
|
1294
1323
|
const e = entry(cmd);
|
|
1295
1324
|
if (JSON.stringify(hooks[HOOK_NAME]) === JSON.stringify(e)) return [{ file, changed: false }];
|
|
1296
1325
|
hooks[HOOK_NAME] = e;
|
|
1297
|
-
mkdirSync2(path5.dirname(file), { recursive: true });
|
|
1298
|
-
writeFileSync3(file, formatJson(hooks, f));
|
|
1299
1326
|
return [
|
|
1300
|
-
{
|
|
1327
|
+
writeBack(file, formatJson(hooks, f), f.existed) ?? {
|
|
1301
1328
|
file,
|
|
1302
1329
|
changed: true,
|
|
1303
1330
|
created: !f.existed,
|
|
@@ -1313,12 +1340,8 @@ var antigravity = {
|
|
|
1313
1340
|
const hooks = f.value;
|
|
1314
1341
|
if (!(HOOK_NAME in hooks)) return [{ file, changed: false }];
|
|
1315
1342
|
delete hooks[HOOK_NAME];
|
|
1316
|
-
if (opts.created?.includes(file) && !Object.keys(hooks).length)
|
|
1317
|
-
|
|
1318
|
-
return [{ file, changed: true, note: "removed (sessionpipe created it)" }];
|
|
1319
|
-
}
|
|
1320
|
-
writeFileSync3(file, formatJson(hooks, f));
|
|
1321
|
-
return [{ file, changed: true }];
|
|
1343
|
+
if (opts.created?.includes(file) && !Object.keys(hooks).length) return [removeEmptied(file, formatJson(hooks, f))];
|
|
1344
|
+
return [writeBack(file, formatJson(hooks, f)) ?? { file, changed: true }];
|
|
1322
1345
|
},
|
|
1323
1346
|
installed(cmd, env = process.env) {
|
|
1324
1347
|
const file = hooksFile(env);
|
|
@@ -1541,7 +1564,7 @@ function antigravityFacts(file, opts) {
|
|
|
1541
1564
|
}
|
|
1542
1565
|
|
|
1543
1566
|
// ../core/src/adapters/codex.ts
|
|
1544
|
-
import { existsSync as existsSync4,
|
|
1567
|
+
import { existsSync as existsSync4, readdirSync as readdirSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
1545
1568
|
import path6 from "node:path";
|
|
1546
1569
|
|
|
1547
1570
|
// ../core/src/adapters/codex-config.ts
|
|
@@ -1694,29 +1717,30 @@ var configFile = (env) => path6.join(codexHome(env), "config.toml");
|
|
|
1694
1717
|
var sessionsDir = (env) => path6.join(codexHome(env), "sessions");
|
|
1695
1718
|
var validTool3 = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
|
|
1696
1719
|
var endReason2 = (r) => r === "clear" || r === "logout" || r === "exit" ? r : "other";
|
|
1720
|
+
var UNTIL_APPROVED = "Codex will report nothing until you approve the hooks: start `codex` and accept the hook review";
|
|
1697
1721
|
function installNotify(cmd, env) {
|
|
1698
1722
|
const file = configFile(env);
|
|
1699
1723
|
let text = "";
|
|
1724
|
+
let existed = true;
|
|
1700
1725
|
try {
|
|
1701
1726
|
text = readFileSync5(file, "utf8");
|
|
1702
|
-
} catch {
|
|
1727
|
+
} catch (e) {
|
|
1728
|
+
existed = e.code !== "ENOENT";
|
|
1703
1729
|
}
|
|
1704
1730
|
const argv = cmd([NAME3, "notify"]).argv;
|
|
1705
1731
|
const line = `notify = ${JSON.stringify(argv)}`;
|
|
1706
1732
|
const n = readNotify(text);
|
|
1707
|
-
const write = (next) => {
|
|
1708
|
-
|
|
1709
|
-
|
|
1733
|
+
const write = (next, note) => {
|
|
1734
|
+
const bad = writeBack(file, next, existed);
|
|
1735
|
+
return bad ? { ...bad, note: `${bad.note}. ${UNTIL_APPROVED}` } : { file, changed: true, note };
|
|
1710
1736
|
};
|
|
1711
1737
|
if (n && !n.other) {
|
|
1712
1738
|
if (!n.misplaced && JSON.stringify(n.argv) === JSON.stringify(argv))
|
|
1713
1739
|
return { file, changed: false, note: "notify current" };
|
|
1714
|
-
write(
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
note: n.misplaced ? "notify moved to the top level (it sat inside a [table], where Codex never reads it)" : "notify updated"
|
|
1719
|
-
};
|
|
1740
|
+
return write(
|
|
1741
|
+
withNotify(text, line),
|
|
1742
|
+
n.misplaced ? "notify moved to the top level (it sat inside a [table], where Codex never reads it)" : "notify updated"
|
|
1743
|
+
);
|
|
1720
1744
|
}
|
|
1721
1745
|
if (n?.other) {
|
|
1722
1746
|
const prev = previousNotify(n.argv);
|
|
@@ -1725,20 +1749,20 @@ function installNotify(cmd, env) {
|
|
|
1725
1749
|
if (JSON.stringify(prev) === JSON.stringify(argv))
|
|
1726
1750
|
return { file, changed: false, note: "notify current (after Codex Computer Use)" };
|
|
1727
1751
|
}
|
|
1728
|
-
if (!prev || OURS2.test(JSON.stringify(prev)))
|
|
1729
|
-
write(
|
|
1730
|
-
|
|
1731
|
-
|
|
1752
|
+
if (!prev || OURS2.test(JSON.stringify(prev)))
|
|
1753
|
+
return write(
|
|
1754
|
+
replaceNotify(text, n, `notify = ${withPreviousRaw(n.raw, argv)}`),
|
|
1755
|
+
"chained after Codex Computer Use (--previous-notify)"
|
|
1756
|
+
);
|
|
1732
1757
|
}
|
|
1733
1758
|
return {
|
|
1734
1759
|
file,
|
|
1735
1760
|
changed: false,
|
|
1736
1761
|
skipped: true,
|
|
1737
|
-
note: `notify belongs to ${(n.argv?.[0] ?? n.raw).replace(/^.*\//, "").slice(0, 40)}; left alone.
|
|
1762
|
+
note: `notify belongs to ${(n.argv?.[0] ?? n.raw).replace(/^.*\//, "").slice(0, 40)}; left alone. ${UNTIL_APPROVED}`
|
|
1738
1763
|
};
|
|
1739
1764
|
}
|
|
1740
|
-
write(withNotify(text, line));
|
|
1741
|
-
return { file, changed: true, note: "notify set at the top level" };
|
|
1765
|
+
return write(withNotify(text, line), "notify set at the top level");
|
|
1742
1766
|
}
|
|
1743
1767
|
function uninstallNotify(env) {
|
|
1744
1768
|
const file = configFile(env);
|
|
@@ -1750,15 +1774,13 @@ function uninstallNotify(env) {
|
|
|
1750
1774
|
}
|
|
1751
1775
|
const n = readNotify(text);
|
|
1752
1776
|
if (!n) return { file, changed: false };
|
|
1753
|
-
if (!n.other) {
|
|
1754
|
-
writeFileSync4(file, withoutNotify(text));
|
|
1755
|
-
return { file, changed: true };
|
|
1756
|
-
}
|
|
1777
|
+
if (!n.other) return writeBack(file, withoutNotify(text)) ?? { file, changed: true };
|
|
1757
1778
|
const prev = previousNotify(n.argv);
|
|
1758
|
-
if (isComputerUse(n.argv) && prev && OURS2.test(JSON.stringify(prev)))
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1779
|
+
if (isComputerUse(n.argv) && prev && OURS2.test(JSON.stringify(prev)))
|
|
1780
|
+
return writeBack(file, replaceNotify(text, n, `notify = ${stripPreviousRaw(n.raw)}`)) ?? {
|
|
1781
|
+
file,
|
|
1782
|
+
changed: true
|
|
1783
|
+
};
|
|
1762
1784
|
return { file, changed: false };
|
|
1763
1785
|
}
|
|
1764
1786
|
function findRollout(threadId, env = process.env) {
|
|
@@ -1790,8 +1812,12 @@ function rolloutMeta(file) {
|
|
|
1790
1812
|
return scanLines(file, (line) => parseLines([line])[0] ?? {});
|
|
1791
1813
|
}
|
|
1792
1814
|
function ofAnotherThread(file, id) {
|
|
1815
|
+
const other = threadOf(file);
|
|
1816
|
+
return !!other && other !== id.toLowerCase();
|
|
1817
|
+
}
|
|
1818
|
+
function threadOf(file) {
|
|
1793
1819
|
const m = /-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl(?:\.zst)?$/i.exec(file);
|
|
1794
|
-
return
|
|
1820
|
+
return m?.[1] ? m[1].toLowerCase() : null;
|
|
1795
1821
|
}
|
|
1796
1822
|
var codex = {
|
|
1797
1823
|
name: NAME3,
|
|
@@ -1870,6 +1896,8 @@ var codex = {
|
|
|
1870
1896
|
const turn_id = typeof s.turn_id === "string" ? s.turn_id : void 0;
|
|
1871
1897
|
const tool = validTool3(s.tool_name) ? s.tool_name : void 0;
|
|
1872
1898
|
const call_id = typeof s.tool_use_id === "string" ? s.tool_use_id : void 0;
|
|
1899
|
+
const thread = typeof s.transcript_path === "string" ? threadOf(s.transcript_path) : null;
|
|
1900
|
+
const agent_id = typeof s.agent_id === "string" && s.agent_id ? s.agent_id : typeof s.subagent_id === "string" && s.subagent_id ? s.subagent_id : thread && thread !== String(id).toLowerCase() ? thread : void 0;
|
|
1873
1901
|
const ev = (type, data) => ({ type, data: prune3(data), harnessEvent: event });
|
|
1874
1902
|
const events = [];
|
|
1875
1903
|
switch (event) {
|
|
@@ -1889,17 +1917,30 @@ var codex = {
|
|
|
1889
1917
|
);
|
|
1890
1918
|
break;
|
|
1891
1919
|
case "PreToolUse":
|
|
1892
|
-
if (tool) events.push(ev("tool.started", { tool, call_id, turn_id, input: s.tool_input }));
|
|
1920
|
+
if (tool) events.push(ev("tool.started", { tool, call_id, turn_id, agent_id, input: s.tool_input }));
|
|
1893
1921
|
break;
|
|
1894
1922
|
case "PostToolUse":
|
|
1895
1923
|
if (tool)
|
|
1896
1924
|
events.push(
|
|
1897
|
-
ev("tool.ended", {
|
|
1925
|
+
ev("tool.ended", {
|
|
1926
|
+
tool,
|
|
1927
|
+
call_id,
|
|
1928
|
+
turn_id,
|
|
1929
|
+
agent_id,
|
|
1930
|
+
ok: true,
|
|
1931
|
+
input: s.tool_input,
|
|
1932
|
+
output: s.tool_response
|
|
1933
|
+
})
|
|
1898
1934
|
);
|
|
1899
1935
|
break;
|
|
1900
1936
|
case "PermissionRequest":
|
|
1901
1937
|
events.push(
|
|
1902
|
-
ev("attention.needed", {
|
|
1938
|
+
ev("attention.needed", {
|
|
1939
|
+
attention_id: call_id ?? `perm-${Date.now()}`,
|
|
1940
|
+
kind: "permission",
|
|
1941
|
+
tool,
|
|
1942
|
+
agent_id
|
|
1943
|
+
})
|
|
1903
1944
|
);
|
|
1904
1945
|
break;
|
|
1905
1946
|
case "Stop":
|
|
@@ -2389,7 +2430,7 @@ var CHAIN_LIMIT = 4e3;
|
|
|
2389
2430
|
var CHAIN_SQL = `WITH RECURSIVE chain(node_id, parent_node_id, chat_message, created_at) AS (
|
|
2390
2431
|
SELECT node_id, parent_node_id, chat_message, created_at FROM message_nodes
|
|
2391
2432
|
WHERE session_id = ? AND node_id = (SELECT main_chain_id FROM sessions WHERE id = ?)
|
|
2392
|
-
UNION
|
|
2433
|
+
UNION
|
|
2393
2434
|
SELECT m.node_id, m.parent_node_id, m.chat_message, m.created_at FROM message_nodes m
|
|
2394
2435
|
JOIN chain c ON m.node_id = c.parent_node_id AND m.session_id = ? AND m.node_id >= ?
|
|
2395
2436
|
)
|
|
@@ -2681,7 +2722,18 @@ function matches(expect, got, pathStr = "") {
|
|
|
2681
2722
|
async function runAdapterFixtures(files) {
|
|
2682
2723
|
const results = [];
|
|
2683
2724
|
for (const file of files) {
|
|
2684
|
-
|
|
2725
|
+
let fx;
|
|
2726
|
+
try {
|
|
2727
|
+
fx = JSON.parse(readFileSync7(file, "utf8"));
|
|
2728
|
+
} catch (e) {
|
|
2729
|
+
const code = e.code;
|
|
2730
|
+
results.push({ file, ok: false, why: code ? `not readable: ${code}` : `not JSON: ${e.message}` });
|
|
2731
|
+
continue;
|
|
2732
|
+
}
|
|
2733
|
+
if (typeof fx?.harness !== "string" || !fx.input || !Array.isArray(fx.expect)) {
|
|
2734
|
+
results.push({ file, ok: false, why: "not an adapter fixture: it needs harness, input and expect" });
|
|
2735
|
+
continue;
|
|
2736
|
+
}
|
|
2685
2737
|
const adapter = adapterByName(fx.harness);
|
|
2686
2738
|
if (!adapter) {
|
|
2687
2739
|
results.push({ file, ok: false, why: `no adapter ${fx.harness}` });
|
|
@@ -2723,14 +2775,27 @@ var walk = (d) => readdirSync5(d).flatMap((n) => {
|
|
|
2723
2775
|
async function main(argv, io = process) {
|
|
2724
2776
|
const target = argv[0];
|
|
2725
2777
|
if (!target) {
|
|
2726
|
-
io.stdout.write("usage: sessionpipe-conformance <conformance/harness dir | https://receiver>\n");
|
|
2778
|
+
io.stdout.write("usage: sessionpipe-conformance <conformance/harness dir | fixture file | https://receiver>\n");
|
|
2727
2779
|
return 2;
|
|
2728
2780
|
}
|
|
2729
|
-
if (/^https
|
|
2781
|
+
if (/^https?:\/\//i.test(target)) {
|
|
2730
2782
|
io.stdout.write("receiver scenarios land in M3\n");
|
|
2731
2783
|
return 2;
|
|
2732
2784
|
}
|
|
2733
|
-
|
|
2785
|
+
let files;
|
|
2786
|
+
try {
|
|
2787
|
+
files = statSync5(target).isDirectory() ? walk(target) : [target];
|
|
2788
|
+
} catch (e) {
|
|
2789
|
+
io.stdout.write(`sessionpipe-conformance: ${e.message}
|
|
2790
|
+
`);
|
|
2791
|
+
return 2;
|
|
2792
|
+
}
|
|
2793
|
+
if (!files.length) {
|
|
2794
|
+
io.stdout.write(`sessionpipe-conformance: no .json fixtures under ${target}
|
|
2795
|
+
`);
|
|
2796
|
+
return 2;
|
|
2797
|
+
}
|
|
2798
|
+
const r = await runAdapterFixtures(files);
|
|
2734
2799
|
io.stdout.write(`${r.table}
|
|
2735
2800
|
${r.results.length - r.failed}/${r.results.length} passed
|
|
2736
2801
|
`);
|