Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cbcca07
fix(flow): raise the flow tree's depth cap and say why targeting failed
hubgan Aug 4, 2026
5306a0b
fix(flow): give a lone backgrounded target the foreground remedy, not…
Aug 4, 2026
bac02eb
fix(flow): stop the quoted cause clause chopping a dotted identifier
hubgan Aug 7, 2026
be1aba9
fix(flow): stop calling a suspended-but-connected app uninstrumented
hubgan Aug 7, 2026
fb29052
fix(flow): tell the ambiguous case to terminate, not background, the …
hubgan Aug 7, 2026
b4cce4c
fix(flow): name launch-app as the tool that foregrounds without termi…
hubgan Aug 7, 2026
4406f76
fix(flow): stop claiming the native-* tools dead-end for an injectabl…
hubgan Aug 7, 2026
3895603
perf(flow): cut the repeated targeting reason back down in size
hubgan Aug 7, 2026
d034b6a
fix(flow): flag a role-only capture instead of recording the downgrad…
hubgan Aug 7, 2026
297fce6
test(flow): pin what the targeting and depth changes only claimed
hubgan Aug 7, 2026
8f5b589
docs(flow): correct what the targeting and gate changes actually do
hubgan Aug 7, 2026
c7aef3e
fix(flow): stop asserting an Apple system app can never be instrumented
hubgan Aug 7, 2026
b64c91c
fix(flow): gate a com.apple.* launch on the connection, like any othe…
hubgan Aug 7, 2026
222c05e
fix(flow): name a command that exists for clearing the other connecte…
hubgan Aug 7, 2026
9531038
fix(flow): bound the targeting reasons that grew with the connected-a…
hubgan Aug 7, 2026
550df9b
docs(flow): correct what the depth cap costs, and pin it
hubgan Aug 7, 2026
77e4a6b
fix(flow): scope the refusal claim to the tools that actually refuse
hubgan Aug 7, 2026
9fcaee3
fix(flow): describe the disconnect race this branch actually reports
hubgan Aug 7, 2026
e2aa08a
docs(create-flow): stop the launch-app note asserting a rule the repo…
hubgan Aug 7, 2026
b158a64
style(flow): rewrap the launch clause in flow-execute's description
hubgan Aug 7, 2026
f6d759b
docs(flow): correct which compatibilityMissNote arm grows with the de…
hubgan Aug 9, 2026
eaee23c
fix(flow): address the terminate remedy to the device set the simulat…
hubgan Aug 9, 2026
be39d5e
fix(flow): make the system-app gate failure name a remedy that can run
hubgan Aug 9, 2026
e2285be
test(flow): pin the connected-app cap at its boundary
hubgan Aug 9, 2026
ffe7865
test(flow): pin the capture warning composition, not just each contri…
hubgan Aug 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/skills/skills/argent-create-flow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,5 +339,5 @@ Apply these when recording new flows to reduce future breakage:
- **Gate transitions with `await-ui-element`, not fixed delays.** After a tap that triggers a navigation, record an `await-ui-element` step that waits for the next screen's element to be `visible` (or a spinner to be `hidden`) before the following step — converted to an `await:` directive during polish. This removes the **Timing** failure mode in Diagnose (the element is in the tree but the tap fired before the screen settled) and is more reliable than `delayMs` or an extra `screenshot`. An unmet wait stops replay at that step, so a mistimed step can never run blind.
- **Add screenshot steps after critical navigation.** Insert `screenshot` steps after screen transitions. These produce images in the flow result you can inspect during diagnosis.
- **Write specific executionPrerequisites.** `"App on home tab, user logged in, simulator UDID is <X>"` — not `"App running"`. Verify with `screenshot` + `describe` before acknowledging.
- **Prefer launch-app / open-url over navigation chains.** Deep links are more resilient to layout changes than tap sequences.
- **Prefer open-url over navigation chains.** Deep links are more resilient to layout changes than tap sequences. To _start_ the app, record `restart-app` (which the recorder captures as a `launch:` step), not `launch-app`: `launch-app` does not terminate first, so against a copy already running it just foregrounds that process — and if that copy started before argent set up injection, selector steps have no view hierarchy to read. `restart-app` is the only one that guarantees a fresh instrumented process whatever was already running, which is why it is the tool the recorder rewrites into `launch:`. (`launch-app` is not inherently uninstrumented: argent sets `DYLD_INSERT_LIBRARIES` device-wide, so launching an app that is _not_ running injects it — that is the `nextLaunchWillBeInjected: true` case `native-devtools-status` reports. It is just not something a recorded step can count on.)
- **Echo accessibility labels for coordinate taps.** When recording a tap, add an echo with the target's label or testID: `"Tapping 'Submit' button (testID: submit-btn) at 0.5, 0.82"`. During repair, use `describe` to find the element by label and update coordinates. Only use `screenshot` for permission or system overlays when `describe` cannot expose the target reliably.
27 changes: 26 additions & 1 deletion packages/tool-server/src/tools/flows/flow-add-step.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,27 @@ async function probeAgainstRunnerTree(
};
}

/**
* `deriveSelector`'s last resort: the tapped node carried no identifier and no
* visibly-rendered text, so the step replays on role alone. That holds only
* while it stays the element of that role which wins `selectorToFrame`'s
* ranking — the re-resolve guard below proves that for the RECORDING screen,
* never for the screen replay meets. Say so, because the alternative is silent.
*
* Reachability rose with the iOS flow tree's depth cap: an unlabeled icon that
* used to be truncated away — leaving `nodeAtPoint` to elect its `testID`
* container — is now present and is the smaller frame under the tap.
*/
function roleOnlySelectorWarning(selector: Selector): string | undefined {
if (selector.role === undefined || selector.identifier !== undefined) return undefined;
if (selector.text !== undefined || selector.textMatches !== undefined) return undefined;
return (
`selector ${describeSelector(selector)} matches by role alone (the tapped element has no id ` +
`or visible text) — replay takes whichever element of that role ranks first, so re-record ` +
`against a labelled element if that is not reliably this one`
);
}

/**
* For a recorded `gesture-tap`, look up the element under the tapped point and
* record a portable `tap: { selector }` step instead of raw coordinates.
Expand Down Expand Up @@ -616,7 +637,11 @@ async function captureTapSelector(
warning: `selector ${describeSelector(selector)} resolves to a different element on this screen; kept coordinates (brittle)`,
};
}
return { selector, warning: fallbackSourceWarning(source, device.platform) };
const warnings = [
roleOnlySelectorWarning(selector),
fallbackSourceWarning(source, device.platform),
].filter((w) => w !== undefined);
return { selector, ...(warnings.length > 0 ? { warning: warnings.join("; ") } : {}) };
Comment thread
hubgan marked this conversation as resolved.
} catch (err) {
return {
warning: `selector capture failed (${err instanceof Error ? err.message : String(err)}); kept coordinates`,
Expand Down
Loading