Skip to content

feat(fill): read text from stdin with --text-stdin - #3351

Merged
thymikee merged 12 commits into
callstack:mainfrom
Metehan-Bicer:feat/fill-text-stdin
Oct 11, 2026
Merged

thymikee merged 12 commits into
callstack:mainfrom
Metehan-Bicer:feat/fill-text-stdin

Conversation

@Metehan-Bicer

@Metehan-Bicer Metehan-Bicer commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

fill can now take its text from stdin, so a secret never appears in the CLI's argv:

printf %s "$PASSWORD" | agent-device fill @e3 --text-stdin
printf %s "$PASSWORD" | agent-device fill 'id="password"' --text-stdin --record-as PASSWORD
  • Reads at most 64 KiB and strips exactly one trailing \n or \r\n. A text argument, a TTY, empty input and invalid UTF-8 are INVALID_ARGS with typed reasons (fill_text_source_conflict, fill_text_stdin_*); no message echoes the input.
  • Uses the existing sensitivity contract: the value is registered as a diagnostics secret in the CLI and daemon scopes, and stays out of session.actions unless --record-as parameterizes it. While recording is armed, --text-stdin needs --record-as or --no-record (fill_text_stdin_unparameterized_recording). Happy to switch this to recording the step without its text if you prefer.
  • Batch steps, MCP tools and env/config defaults cannot set it.

25 files; scope stays within the fill family. Closes #3260.

Validation

Tested at 9d2bc90 (includes the review fixes): pnpm check:affected --run passed (all runnable checks; device and toolchain lanes are GitHub-authoritative). CI pending.

Live run on an iPhone 16 simulator (iOS 18.6, Settings search field): stdin fill succeeded; an armed recording refused it without --record-as and published ${PASSWORD} with it. The value was absent from the daemon log, session events and the .ad script. It still appears in the native XCTest session log, which is #3261 and out of scope here.

View guided diff

fill can take its text from stdin instead of argv so a secret never
appears in the CLI's process arguments. The read is bounded to 64 KiB
and strips exactly one trailing LF or CRLF; a text argument, a terminal,
empty input and invalid UTF-8 are refused with typed reasons that never
echo the input.

The value goes through the existing sensitivity contract: it is
registered as a diagnostics secret in the CLI and daemon scopes, and the
daemon keeps it out of recorded actions unless --record-as parameterizes
it. While recording is armed the flag needs --record-as or --no-record.
Batch steps, MCP tools and env/config defaults cannot set it.

Closes callstack#3260

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 25 files

Reply to a comment to ask cubic a question or push back. It learns from your replies.

View guided diff | Re-trigger cubic

Comment thread src/commands/interaction/interactions.ts Outdated
Comment thread website/docs/docs/commands.md Outdated
Comment thread src/commands/schema/cli-help.ts Outdated
Comment thread src/commands/interaction/fill-text-stdin.ts Outdated
Comment thread src/commands/interaction/fill-text-stdin.test.ts Outdated
Comment thread website/docs/docs/commands.md Outdated
Comment thread src/daemon/__tests__/session-action-recorder.test.ts Outdated
Comment thread src/commands/interaction/fill-text-stdin.ts Outdated
Comment thread src/commands/interaction/index.ts Outdated
Comment thread src/commands/batch/projection.ts Outdated
- Mask target parse failures under --text-stdin: a stray positional may be
  the secret, and the generic target error echoed it.
- Keep a leading byte order mark and refuse lone surrogates in string
  chunks instead of replacing them.
- Only refuse batch steps that set textStdin to true.
- Clarify help and docs: passing neither --record-as nor --no-record while
  recording is an error, invalid UTF-8 is refused, and printf %s is the
  verbatim way to pipe a value.
- Tighten tests to assert each case's own input is never echoed.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 10 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread src/commands/interaction/fill-text-stdin.ts Outdated
Comment thread src/commands/interaction/fill-text-stdin.ts Outdated
- A string stream may split a surrogate pair across chunks, and the
  per-chunk lone-surrogate check refused valid input. A trailing high
  surrogate is now held back until the next string chunk; a byte chunk
  or the end of input still refuses it as invalid UTF-8.
- Size a string chunk with Buffer.byteLength before encoding it, so an
  oversized chunk is refused without being copied first.
@thymikee

thymikee commented Oct 9, 2026

Copy link
Copy Markdown
Member

fill --text-stdin still returns the literal text in its result unless --record-as is set. This is a problem in 0964704. --record-as needs an armed recording, so an unrecorded stdin fill, or an armed one using --no-record, gets extra: { text: params.text } back from interaction-touch-fill.ts:234. parameterizeFillPayloads at interaction-common.ts:100 only redacts when recordAs is a string. So printf %s "$PW" | agent-device fill @e3 --text-stdin --json prints "text":"<secret>" on stdout, and the Node client result has the same field. The secret stays out of argv but lands in the output the caller reads, and #3260 asks for input that is not echoed in results. The rule to enforce is that a fill whose text is marked sensitive (recordAs set or textStdin true) never returns its literal on any surface: response data, result, recorded action or diagnostics. Please define that predicate once in interaction-recorded-input.ts. Have parameterizeFillPayloads, registerParameterizedFillDiagnosticValue (request-router.ts:502) and the recorder skip (session-action-recorder.ts:63) all call it. When there is no recordAs, redact text to a fixed marker and drop value-carrying selectorChain candidates through parameterizeRecordedFillPayload. Please add a router-level test showing that a textStdin fill response contains no literal.

Would it be simpler to treat textStdin in the daemon as a sensitivity trait, not a transport detail? Three predicates (request-router.ts:502, session-action-recorder.ts:63, and interaction-common.ts:100, which ignores textStdin) each re-derive "this fill text is sensitive". One owner such as isSensitiveFillText(flags) would replace them and close the problem above without adding new code. The rest looked necessary: the reader, the batch, config and env exclusions, and the operator field.

Not blocking, and you can take or leave it: the armed-recording refusal and the extended diagnostic-registration predicate are only tested by calling the helpers directly, so one router-level test that sends an armed textStdin fill and checks for fill_text_stdin_unparameterized_recording would help, and the same test can cover the response.

Two bot threads on fill-text-stdin.ts (surrogate pairs, byte length) and one on interactions.ts (target parse errors) are fixed at this head, so you can resolve them.

CI is green and there are no conflicts. This read of 0964704 is from the code only, and I did not run the CLI or the tests. The earlier live iOS run was at 9d2bc90 and did not show the --json response contents. I also did not check whether error responses can echo the fill text on failure paths after admission, such as selector or ref errors. Before merge, the response, recorder and diagnostics need to share one sensitivity predicate. Please prove it with a router test and a live fill --text-stdin --json run whose stdout contains no part of the value.

A fill whose text is sensitive (--record-as set or --text-stdin) now
decides it through one predicate, isSensitiveFillText, for the response
payloads, the recorder skip and diagnostics registration. Without
--record-as, the response and result text read [REDACTED] and
value-carrying selector candidates are dropped, so an unrecorded or
--no-record stdin fill no longer echoes the value in --json output or
the client result.

An error leaving the router now passes through the request's registered
sensitive values, so a backend message that echoes the value after
admission is redacted as well.
@Metehan-Bicer

Copy link
Copy Markdown
Contributor Author

Thanks for the careful read. Addressed in 19d3ffd:

  • One predicate, isSensitiveFillText(flags) (recordAs set or textStdin true). It sits next to the other recorded-input helpers in @agent-device/ad-script instead of interaction-recorded-input.ts: request-router.ts and session-action-recorder.ts can't import the interaction internal tree, and all three call sites already import ad-script, so it adds no import edges. parameterizeFillPayloads, registerParameterizedFillDiagnosticValue and the recorder skip all call it.
  • Without recordAs, the response and result text become [REDACTED], and value-carrying selectorChain candidates are dropped through parameterizeRecordedFillPayload.
  • Failure paths after admission: they could echo it. A backend error like could not type "<value>" came back verbatim. The router's error exit now passes the error through the request's registered sensitive values (redactRegisteredSensitiveValues in host-kit), the same set diagnostics already redact. Success payloads keep the field-aware parameterization only.
  • request-router-fill-text-stdin.test.ts sends fills through the real request handler to a web session: an unrecorded stdin fill, an armed --no-record one, an armed one without --record-as (refused with fill_text_stdin_unparameterized_recording, nothing typed), and a backend error that echoes the value. The two leak cases and the error case fail without the change.
  • Live run on an iOS 18.6 simulator, Settings search field, at this head:
$ printf %s 'stdinLiveCheck42' | agent-device fill @e3 --text-stdin --json
{
  "success": true,
  "data": {
    "x": 197, "y": 169,
    "text": "[REDACTED]",
    "message": "Filled 16 chars",
    "targetKind": "ref", "ref": "e3", "refLabel": "Arayın",
    "selectorChain": ["role=\"searchfield\" label=\"Arayın\" editable=true", "label=\"Arayın\" editable=true", "value=\"Arayın\" editable=true"],
    ...
  }
}

No part of the value is in stdout, and a follow-up snapshot -i shows the field holding it. pnpm check:affected --run passes.

One question: message still reports the character count (Filled 16 chars). That predates this PR; should a sensitive fill leave the length out too?

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 8 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread packages/ad-script/src/internal/recorded-input.ts
Comment thread src/daemon/__tests__/request-router-fill-text-stdin.test.ts
- recordAs and textStdin mark fill text as sensitive, but the request
  boundary only checks that flags is an object. A direct daemon request
  with textStdin: "true" was read as unmarked, so the value came back in
  data.text; recordAs: 42 failed later as an UNKNOWN TypeError. Both are
  now refused as INVALID_ARGS before any device work.
- Assert the --no-record response text is exactly [REDACTED].
@thymikee

Copy link
Copy Markdown
Member

The fixes from the earlier review at 0964704 are in at 68acc36, but one problem remains in the error path. The two earlier cubic-dev-ai threads are addressed at this commit: the malformed recordAs/textStdin refusal now runs before typing (#3351 (comment)), and the --no-record test now asserts data.text is [REDACTED] (#3351 (comment)). Please resolve both threads.

redactRegisteredSensitiveValues at https://github.com/callstack/agent-device/blob/68acc36/src/daemon/request-router.ts#L211 runs on every error response of every command. It replaces each value in the request's sensitive set across the whole error object: message, hint, details and logPath. That set is not limited to the stdin text. Maestro replay registers every inputText (daemon-runtime-port.ts#L134), and --record-as fills register their literal too. The replace is a plain substring replaceAll. So a Maestro flow with inputText: "1" that later fails, or a failing fill --record-as qty ... 1, now returns a message and a logPath with every "1" replaced by [REDACTED]. The user cannot open that path. This also changes behavior for all Maestro replays with inputText, and the PR does not list that or add a changelog or docs entry. The rule should be that an error response redacts only the text this request marked sensitive, and never rewrites daemon-owned identity fields. Please gate it on req.command === 'fill' && isSensitiveFillText(req.flags), redact only that fill's own text value, and leave logPath and diagnosticId untouched. A router test should cover a short registered value that appears in logPath, plus a non-fill (Maestro replay) error that comes back unchanged.

Not blocking, and fine to take or leave: in request-router-fill-text-stdin.test.ts the first import sits above the file's doc comment, so it can move below the header with the other imports.

CI is green, with the single reported check passing, and there are no conflicts. I read the code only and did not run the tests or a live replay. I also did not check whether nested batch steps that carry flags.textStdin get the router's per-request registration and the malformed-type refusal. That is outside this delta. Whether the "Filled N chars" message should drop the length is the maintainer's call, since #3260 only asks that the value not be echoed. Before merge, the error-response redaction needs the narrower scope described above.

- The error exit replaced every value registered for the request across
  the whole error. Maestro inputText and --record-as literals are
  registered too, so a short value such as "1" rewrote logPath,
  diagnosticId and the error of a non-fill replay. Only a fill marked
  sensitive is redacted now, only its own text, and only in message,
  hint, cause and details, with the same placeholder as the success
  path (${VAR} with --record-as, [REDACTED] otherwise).
- Refuse textStdin on a daemon batch step: a failed step returns its
  positionals, and the CLI already refuses it there.
- Remove redactRegisteredSensitiveValues from host-kit.
@Metehan-Bicer

Copy link
Copy Markdown
Contributor Author

Thanks. Addressed in 2230e33, which also merges main and resolves the commands.md conflict.

  • Error redaction scope. The error exit no longer reads the request's registered set. It redacts only when req.command === 'fill' && isSensitiveFillText(req.flags), only that fill's own text, and only in message, hint, cause and details. logPath, diagnosticId and diagnosticsRecord come back untouched. redactRegisteredSensitiveValues is removed from host-kit, so Maestro replays behave as they do on main. The placeholder matches the success path: ${VAR} with --record-as, [REDACTED] otherwise. Both paths now use one sensitiveFillPlaceholder in ad-script.

  • Tests.

    • A stdin fill whose short value (stdin) also appears in the request id keeps its logPath and diagnosticsRecord, and the file exists.
    • A Maestro replay that registers inputText: "1" and then fails comes back with no [REDACTED] and an openable logPath.
    • A --record-as backend error shows ${PASSWORD}.

    The first two fail at 68acc36.

  • Batch. I checked the case you left open. A daemon batch step carrying textStdin was admitted, and when that step failed, the batch error returned the value in details.positionals. validateAndNormalizeBatchSteps now refuses textStdin on any step, with the CLI's fill_text_stdin_in_batch reason, and a router test covers it. If you'd rather take this in a follow-up, I can split it out.

  • Moved the import below the header, and added one sentence to commands.md on how the value reads in output and errors.

Live check on an iOS 18.6 simulator (Settings), sending raw daemon requests, 68acc36 vs. this commit:

  • A Maestro flow that types inputText: "device" and then fails at assertVisible returned logPath: ~/.agent-[REDACTED]/dev/agent-[REDACTED]-… before. After, it returns the real path, and the file opens.
  • A batch fill step with textStdin: true against a missing ref returned the value in details.positionals before. After, it returns INVALID_ARGS (fill_text_stdin_in_batch), and nothing is typed.

pnpm check:affected --run passes.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 10 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread src/daemon/request-router.ts
Comment thread website/docs/docs/commands.md Outdated
Comment thread packages/command-registry/src/batch.ts Outdated
@thymikee

Copy link
Copy Markdown
Member

The earlier findings from 68acc36 are fixed in 2230e33, and CI is green, but two review points still need work before merge. There are no conflicts. I read the code only. I did not run the new router tests, a live device fill, or a replay. I also did not check whether the iOS runner, Android helper, or web backend echo the typed text in their errors; the router tests use a stub that throws a hand-written message.

The replayed --record-as fill still leaks. createReplayScopedActionInvoker (https://github.com/callstack/agent-device/blob/2230e33/src/daemon/request-router.ts#L396-L430) registers the sensitive fill but returns the inner error without redactSensitiveFillTextInError. The outer request is replay, so the resolved secret can reach the user in the replay error. The rule: every entry point that registers a sensitive fill must redact that fill's error. Today those are handleRequest and the scoped invoker. Please wrap the scoped invoker's finalized response the same way and add a scoped-replay test. This is the open P1 thread: #3351 (comment)

The commands.md:468 sentence says error messages show ${VAR}, which is not yet true on that route. Fix the P1, then add half a sentence that daemon-owned path and id fields are left unchanged: #3351 (comment)

The CLI guard at src/commands/batch/projection.ts:85 lets textStdin:false through, and the writer at src/commands/interaction/index.ts:694 puts it in step flags. The daemon validator at packages/command-registry/src/batch.ts:248 then rejects anything that is not undefined. Please make both sides use one rule, for example flags?.textStdin !== true in the validator, or refuse a non-boolean as malformed. The CLI test only checks the mocked call, so please assert the daemon result too. I did not check whether MCP or Node batch callers can produce textStdin:false. Thread: #3351 (comment)

Not blocking, and you can take or leave it: redactSensitiveFillTextInError at src/daemon/request-router.ts:547 does a plain replaceAll on each string leaf, while the success path uses parameterizeSensitiveString in packages/selectors/src/parameterized-recorded-fill.ts, which collapses a whitespace-only literal to the placeholder, skips segments that already hold it, and rewrites object keys. So a failing fill of ' ' or a value ending in a newline returns could[REDACTED]not[REDACTED]type..., and a details key equal to the literal stays unredacted. You could export that leaf rule and call it from replace, or note that the error path differs on purpose.

After the replay redaction and the batch rule are in, rerun the checks on this PR.

…in batch

- A same-session replay runs its fill through the replay-scoped invoker,
  which registers the sensitive value but returned the fill's error as
  is. It now redacts that error like handleRequest does, so the replay
  message carries the fill's placeholder.
- The daemon batch validator refuses only textStdin: true, matching the
  CLI guard; false is the ordinary argv path.
- The error path uses the success path's parameterizeSensitiveString for
  values and keys, so a whitespace-only value collapses the string.
- Docs: limit the redaction guarantee to value-bearing fields.
@Metehan-Bicer

Copy link
Copy Markdown
Contributor Author

Thanks. Addressed in 14eafc4, which also merges main.

  • Replayed --record-as fill. createReplayScopedActionInvoker now passes its finalized response through the same redaction as handleRequest, so both entry points that register a sensitive fill redact its error. From testing at 2230e33: the value itself didn't reach the replay response, because the replay error already scrubs every replay-scope value to <var:NAME> (scrubReplayVarValues), so the message read could not type "<var:PASSWORD>". The child error is now redacted at the source, and the message shows the fill's own placeholder, ${PASSWORD}. A new router test replays fill 10 20 "${PASSWORD}" with -e PASSWORD=… against a backend that echoes the value.
  • Docs. The commands.md sentence now limits the guarantee to success data and an error's message, hint, cause and details, and says daemon-owned fields such as logPath and diagnosticId are left unchanged.
  • Batch rule. The daemon validator refuses only textStdin: true, matching the CLI guard. A non-boolean is still refused per step by the router's malformed-flag check. A router test covers a textStdin: false batch fill that dispatches and types, and the CLI test now asserts the forwarded step flag. Live on the iOS simulator, the same CLI batch was refused with INVALID_ARGS at 2230e33 and fills the field now.
  • Leaf rule. I took it: parameterizeSensitiveString is exported from @agent-device/selectors/parameterized-recorded-fill, and the error path uses it for values and keys, so a whitespace-only value collapses the string. Test added.

The three new router tests fail at 2230e33. pnpm check:affected --run passes.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 6 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread src/daemon/request-router.ts
@thymikee

Copy link
Copy Markdown
Member

Thanks for the update. At 14eafc4, the scoped replay response is now redacted, the docs name the fields that are redacted, and the batch textStdin check now matches projection.ts. One problem remains: parameterizeSensitiveString can still return the secret unchanged, so the error path still echoes it.

If a stdin secret contains the placeholder (for example abc[REDACTED]xyz without --record-as, or a value containing ${VAR} with --record-as VAR), splitting on the placeholder gives no segment that contains the literal. The helper then returns the value as is, and the error response includes the whole secret. The same helper serves the success path, so the rule belongs in the helper: its output must never contain the literal. Please enforce that there, for example by collapsing to the placeholder when the result still contains the literal. Then add a router test that fills with such a secret and checks that neither the error nor the success response contains it.

The open Cubic P1 thread on this (#3351 (comment)) still stands. These threads are fixed at 14eafc4 and can be resolved: scoped replay redaction (#3351 (comment)), docs field list (#3351 (comment)), and the batch textStdin check (#3351 (comment)).

Both Smoke Tests jobs were still running when I checked, with no failure so far. The new changes only touch the error-redaction wrapper, the batch guard and one selectors export, so I expect little overlap with the smoke routes. I did not run the new router tests or a replay. I also did not check whether a real iOS, Android or web backend error echoes the typed text, since the tests use a stub error. Once the helper fix and its test are in and the checks finish green, this is ready for another look.

…sponses

parameterizeSensitiveString split its input on the placeholder before
looking for the value, so a value that contains the placeholder
(`abc[REDACTED]xyz`, or `${VAR}` inside a `--record-as VAR` value) was
never found and came back whole in a backend error. The helper now
collapses the whole string to the placeholder whenever the value still
occurs outside a placeholder. A value found only inside placeholders
(`$` in `${DOLLAR}`) stays as before.
@Metehan-Bicer

Copy link
Copy Markdown
Contributor Author

Thanks. Fixed in 6cdfbc7.

  • parameterizeSensitiveString now checks its own output. If the value still occurs outside a placeholder (one that contains the placeholder, like abc[REDACTED]xyz, or abc${PASSWORD}xyz with --record-as PASSWORD, or one that crosses a placeholder), the whole string collapses to the placeholder. A value found only inside placeholders stays, so the $ → ${DOLLAR} and PASSWORD → ${PASSWORD} stability cases in interaction-common.test.ts still pass; a plain includes check broke those two.
  • A new router test fills with both values, once succeeding and once with a backend error that echoes the value. Neither response nor the recorded actions contain it, and the error message comes back as the placeholder. Both cases fail without the helper change.

A real backend does echo the typed text: the iOS runner's TEXT_ENTRY_MISMATCH message quotes expected "…". I couldn't trigger a read-back mismatch on a stock simulator field, so that path is covered by the router test only. On an iOS 18.6 simulator, fill --text-stdin with abc[REDACTED]xyz into the Settings search field typed the value, and the response held only text: "[REDACTED]".

One thing this does not cover: the observed half of that mismatch message can be an altered form of the value (a field that formats or filters input). It is a different string, so it is not redacted. Fixing it would mean the runner not quoting the values for a sensitive fill, so I left it out of this PR. I can open an issue for it if you'd like.

@thymikee

Copy link
Copy Markdown
Member

This looks ready for maintainer review. At 6cdfbc7 both fixes from the earlier review are in: [REDACTED] inside a longer string now collapses, and the replay path wraps its response with the same redaction. The 16 checks are green, and the two doc and batch threads are also fixed at head. There are no conflicts.

Not blocking, and you can take or leave it: the web stub in request-router-fill-text-stdin.test.ts at line 174 never echoes the typed text on success, so the not.toContain(secret) check there would also pass before the fix, and only the error half guards the regression. A small unit test for the selectors helper (placeholder inside the text, and the crossing case) would pin collapseIfLiteralRemains directly.

I traced collapseIfLiteralRemains by hand and did not run the router test or interaction-common.test.ts. The live iOS simulator run has no attached artifact. The observed part of the iOS runner's TEXT_ENTRY_MISMATCH message can quote an altered form of the secret that no literal match redacts. You already name that gap, and a follow-up issue next to #3261 fits well.

The four earlier inline threads from cubic-dev-ai no longer apply, so please resolve them: the collapse of abc[REDACTED]xyz is fixed in parameterized-recorded-fill.ts #3351 (comment), the replay invoker response now goes through redactSensitiveFillResponse #3351 (comment), the commands.md guarantee now covers success data and message/hint/cause/details #3351 (comment), and the batch refusal now matches projection.ts #3351 (comment).

Nothing else stands in the way of maintainer merge review.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 10, 2026
…eString

Covers a value that contains the placeholder, a value that crosses a
placeholder already in the string, a value found only inside
placeholders, and a plain replace that is stable on a second pass.
@Metehan-Bicer

Copy link
Copy Markdown
Contributor Author

Thanks. Added packages/selectors/src/parameterized-recorded-fill.test.ts in b508271. It pins the collapse for a value that contains the placeholder ([REDACTED] and ${PASSWORD}) and for one that crosses a placeholder already in the string, plus two cases that must not change: a value found only inside placeholders, and a plain replace that is stable on a second pass. The first two fail with the helper before 6cdfbc7; all four pass now.

You're right about the success half of the router test: the web stub never echoes, so only the error half guards the regression.

The four cubic threads were already resolved when I checked.

Opened #3392 for the read-back gap. Besides observed in TEXT_ENTRY_MISMATCH, an unconfirmed fill's after can carry a formatted form of the value on success.

@thymikee

Copy link
Copy Markdown
Member

The new commit b508271 fixes the earlier concern, and I found no new problems in this change. The collapseIfLiteralRemains fix is now in parameterized-recorded-fill.ts, and the new unit test covers the abc[REDACTED]xyz case and the crossing case. By reading the old and new helper, both cases fail before the fix and pass after it. I did not run the new test file.

The four cubic-dev-ai threads are fixed at this head, so please resolve them: the replay redaction fix, the router error redaction, the docs wording for daemon-owned fields, and the batch check for textStdin. No other review threads still apply.

Smoke Tests is still running and has not failed. The new commit only adds a unit test file in packages/selectors, so it does not touch the device or daemon route that Smoke Tests runs. No conflicts are known. The PR can merge once Smoke Tests finishes green.

@thymikee
thymikee merged commit b404ab4 into callstack:main Oct 11, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support private stdin input for CLI fill without secret-bearing argv

2 participants