simframe 0.11.0 → 0.12.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/README.md +44 -0
- package/native/simframed/Sources/PrivateAPI/CoreSimulatorPlatform.swift +29 -1
- package/native/simframed/Sources/SimframeCore/CaptureRecovery.swift +19 -0
- package/native/simframed/Sources/simframed/main.swift +20 -2
- package/native/simframed/Tests/SimframeCoreTests/HashingTests.swift +41 -0
- package/native/supervise.swift +41 -6
- package/package.json +1 -1
- package/scripts/check-private.mjs +9 -0
- package/scripts/ci-integration-local.sh +79 -0
- package/scripts/collect-rulings.mjs +312 -0
- package/scripts/eval-fingerprint.mjs +100 -23
- package/scripts/probe-network.mjs +118 -0
- package/scripts/score-rulings.mjs +107 -0
- package/scripts/soak-capture.mjs +72 -0
- package/skills/simframe/SKILL.md +20 -2
- package/src/actions.js +108 -9
- package/src/cli.js +85 -5
- package/src/fingerprint.js +25 -1
- package/src/graph.js +47 -0
- package/src/index.js +41 -0
- package/src/localhelper.js +8 -2
- package/src/mcp.js +16 -7
- package/src/metrics.js +116 -0
- package/src/platform/android.js +23 -0
- package/src/platform/index.js +11 -1
- package/src/platform/ios.js +70 -2
- package/src/regions.js +105 -0
- package/src/supervisor.js +51 -7
- package/src/view.js +40 -4
package/src/view.js
CHANGED
|
@@ -22,10 +22,10 @@ import * as matching from './matching.js';
|
|
|
22
22
|
const REGION_ORDER = ['nav-bar', 'content', 'tab-bar', 'keyboard', 'status-bar'];
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* Which regions the map will not offer now lives in `regions.js`, because it is
|
|
26
|
+
* not only a presentation rule — see `regions.offerable`. A target this hides
|
|
27
|
+
* must also be one nothing resolves onto behind the caller's back.
|
|
27
28
|
*/
|
|
28
|
-
const HIDDEN_REGIONS = new Set(['status-bar']);
|
|
29
29
|
|
|
30
30
|
/** A keyboard is 30-odd keys nobody refers to by name. One line says it. */
|
|
31
31
|
const COLLAPSE_REGIONS = new Set(['keyboard']);
|
|
@@ -249,7 +249,7 @@ export function rowsFor(entry, { screen, filter, interactive, all = false, limit
|
|
|
249
249
|
if (!isNum(t.x) || !isNum(t.y)) return false;
|
|
250
250
|
// Off-screen elements are real in the tree and untappable in fact.
|
|
251
251
|
if (regions.offViewport(t, screen)) return false;
|
|
252
|
-
if (!all &&
|
|
252
|
+
if (!all && !regions.offerable(t.region)) return false;
|
|
253
253
|
if (!all && isNoise(t)) return false;
|
|
254
254
|
return true;
|
|
255
255
|
});
|
|
@@ -329,6 +329,28 @@ export function recalledNote(identity, now = Date.now()) {
|
|
|
329
329
|
return `elements recalled from ${ago} ago — pass refresh for what is there now`;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
/**
|
|
333
|
+
* How old the frame behind this reading is, and whether that is a problem.
|
|
334
|
+
*
|
|
335
|
+
* Two thresholds, because "slightly behind" and "possibly a different screen"
|
|
336
|
+
* are different messages. Under `FRAME_FRESH_MS` nothing is said: a map that
|
|
337
|
+
* announced "42ms old" on every call would train a reader to skip the line that
|
|
338
|
+
* matters. Over `FRAME_STALE_MS` it shouts, because at that age the app may have
|
|
339
|
+
* moved on entirely and the whole element list is then a description of the past.
|
|
340
|
+
*/
|
|
341
|
+
export const FRAME_FRESH_MS = 1500;
|
|
342
|
+
export const FRAME_STALE_MS = 4000;
|
|
343
|
+
|
|
344
|
+
export function frameAgeNote(identity, now = Date.now()) {
|
|
345
|
+
const at = identity?.state?.capturedAt;
|
|
346
|
+
if (!Number.isFinite(at)) return null;
|
|
347
|
+
const age = Math.max(0, now - at);
|
|
348
|
+
if (age < FRAME_FRESH_MS) return null;
|
|
349
|
+
if (age < FRAME_STALE_MS) return `frame ${(age / 1000).toFixed(1)}s old`;
|
|
350
|
+
return `WARNING this frame is ${(age / 1000).toFixed(1)}s old — the screen may have moved on `
|
|
351
|
+
+ 'since, so treat the elements below as a description of the past and pass refresh';
|
|
352
|
+
}
|
|
353
|
+
|
|
332
354
|
/**
|
|
333
355
|
* What a control *contains*, from the sensor that actually knows.
|
|
334
356
|
*
|
|
@@ -702,6 +724,20 @@ export function render({ device, identity, rows, truncated, collapsed, screen, n
|
|
|
702
724
|
identity?.settled === false ? 'STILL MOVING' : null,
|
|
703
725
|
// Still and finished are not the same thing.
|
|
704
726
|
identity?.loading === true ? 'STILL LOADING' : null,
|
|
727
|
+
// How old the *frame* this map was read from is.
|
|
728
|
+
//
|
|
729
|
+
// `sim_look` and `sim_state` have printed this since they existed, and this
|
|
730
|
+
// map never has — so the one tool an agent is told to start with was the one
|
|
731
|
+
// that could not say how old its evidence was. Reported from the field: a
|
|
732
|
+
// complete 20-element map of a screen the app was not on, and *"a wrong
|
|
733
|
+
// answer is worse than an error here, because nothing downstream knows to
|
|
734
|
+
// doubt it"*. `ensureDaemon` will hand back a frame up to 30s old, so this
|
|
735
|
+
// was reachable without anything being broken.
|
|
736
|
+
//
|
|
737
|
+
// `recalledNote` below is a different claim — that the *element map* came
|
|
738
|
+
// from memory — and having one was what made the absence of the other easy
|
|
739
|
+
// to miss.
|
|
740
|
+
frameAgeNote(identity),
|
|
705
741
|
recalledNote(identity),
|
|
706
742
|
].filter(Boolean).join(' · ');
|
|
707
743
|
|