simframe 0.15.0 → 0.15.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simframe",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "mcpName": "io.github.lvlrSajjad/simframe",
5
5
  "description": "Always-warm iOS Simulator and Android emulator frames: agents read the screen in ~20ms instead of waiting on screenshots. MCP server + CLI.",
6
6
  "keywords": [
@@ -186,11 +186,7 @@ const report = {
186
186
 
187
187
  console.log('\nflow runs agent p50 human p50 HPI_time step_ratio');
188
188
  for (const f of report.flows) {
189
- console.log(
190
- `${f.flow.padEnd(24)} ${String(f.runs).padStart(5)} ${`${f.agent_ms.p50}ms`.padStart(9)} ` +
191
- `${(f.human_median_ms ? `${f.human_median_ms}ms` : '—').padStart(9)} ` +
192
- `${String(f.hpi_time ?? '—').padStart(8)} ${String(f.step_ratio ?? '—').padStart(10)}`,
193
- );
189
+ console.log(metrics.flowRow(f));
194
190
  }
195
191
  report.overall.hpi_time_median_of_passes = passTimes.length ? Number(metrics.median(passTimes).toFixed(3)) : null;
196
192
  const o = report.overall;
package/src/cli.js CHANGED
@@ -1234,11 +1234,7 @@ async function main() {
1234
1234
  emit(flags, report, [
1235
1235
  flags.last ? `the last ${num(flags.last)} run(s) of each flow, of ${all.filter((f) => f.flow_name).length} named runs in the log` : null,
1236
1236
  'flow runs agent p50 human p50 HPI_time step_ratio turns esc',
1237
- ...report.flows.map((f) =>
1238
- `${f.flow.padEnd(24)} ${String(f.runs).padStart(5)} ${`${f.agent_ms.p50}ms`.padStart(9)} ` +
1239
- `${(f.human_median_ms ? `${f.human_median_ms}ms` : '—').padStart(9)} ` +
1240
- `${(f.hpi_time ?? '—').toString().padStart(8)} ${(f.step_ratio ?? '—').toString().padStart(10)} ` +
1241
- `${(f.model_turns ?? '—').toString().padStart(5)} ${String(f.escalations).padStart(3)}`),
1237
+ ...report.flows.map((f) => metrics.flowRow(f, { wide: true })),
1242
1238
  '',
1243
1239
  `HPI_accuracy ${report.overall.hpi_accuracy} (${report.overall.runs} runs, ` +
1244
1240
  `${report.overall.runs - runs.filter((r) => r.completed && !r.wrong_action_taken).length} not clean)`,
package/src/metrics.js CHANGED
@@ -601,6 +601,30 @@ export function harmonicMean(xs) {
601
601
  * a human baseline. A flow with no human baseline gets no HPI_time — reported
602
602
  * as null, never as 1.0, because a missing denominator is not parity.
603
603
  */
604
+ /**
605
+ * One flow's row in the HPI table, shared by `simframe hpi` and the bench
606
+ * script because they had the same row duplicated byte for byte.
607
+ *
608
+ * It lives here, next to the report it renders, for a reason the v0.15.0 tag
609
+ * paid for: making `agent_ms` null for a flow that timed nothing was correct,
610
+ * and both printers dereferenced `.p50` on it. `bench` died with exit 1 and no
611
+ * hpi.json, and `simframe hpi` would have done the same for any user whose
612
+ * flow never completed. The metric had a test; nothing rendered it. A format
613
+ * duplicated in two files is a format that gets fixed in one.
614
+ *
615
+ * `—` means "not measured", never zero.
616
+ */
617
+ export function flowRow(f, { wide = false } = {}) {
618
+ const cell = (v, unit = '') => (v === null || v === undefined ? '—' : `${v}${unit}`);
619
+ const row = `${f.flow.padEnd(24)} ${String(f.runs).padStart(5)} `
620
+ + `${cell(f.agent_ms?.p50, 'ms').padStart(9)} `
621
+ + `${cell(f.human_median_ms, 'ms').padStart(9)} `
622
+ + `${cell(f.hpi_time).padStart(8)} ${cell(f.step_ratio).padStart(10)}`;
623
+ return wide
624
+ ? `${row} ${cell(f.model_turns).padStart(5)} ${String(f.escalations).padStart(3)}`
625
+ : row;
626
+ }
627
+
604
628
  export function hpi({ flows, baselines = {} }) {
605
629
  const byName = new Map();
606
630
  for (const f of flows) {