Skip to content

feat(cli): two-pane home screen with session resume#240

Open
oxoxDev wants to merge 11 commits into
tinyhumansai:mainfrom
oxoxDev:feat/tui-session-history
Open

feat(cli): two-pane home screen with session resume#240
oxoxDev wants to merge 11 commits into
tinyhumansai:mainfrom
oxoxDev:feat/tui-session-history

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Bare tinyplace now opens a two-pane home screen: the action list on the left and a recent-session resume list on the right — the same picker experience Claude Code gives you, but spanning both agents. Pick a past session and it relaunches with the right resume flag, in its original folder, on the same OpenHuman thread.

Motivation

The home menu could only start a fresh Codex/Claude session. To continue yesterday's work you had to remember the agent's own resume incantation and run it outside tinyplace, which also broke the OpenHuman bridge's thread continuity. This puts "resume where I left off" one keystroke away and keeps the bridge attached.

What changed

New read model — session-history.ts

  • listRecentSessions(env, cwd) scans the agents' own session dirs (~/.claude/projects, ~/.codex/sessions) — the very files the harness tailer streams — so the list is always accurate with no separate store to keep in sync.
  • Ordered current-folder-first, then most-recent.
  • Cost-bounded: only the newest N files are opened, and only their first 64 KiB parsed (enough for session meta + the first prompt).
  • Label = the first human prompt, skipping <…>-wrapped system turns (codex environment/permissions context, claude command/tool wrappers) and text-less tool-result turns.

Home UI — tui.ts

  • Two panes; Tab and ←/→ move the cursor between them; the focused pane takes the cyan border + live row highlight. ↑↓ move within it, Enter activates.
  • Resume relaunches with claude --resume <id> / codex resume <id> in the session's original cwd.
  • The resumed bridge pins a stable, per-session OpenHuman scope (tp-<agent>-resume-<id>) so re-resuming the same session continues the same thread regardless of folder; fresh launches keep the default folder scope.
  • Launch cwd is threaded through the pty/child/tmux paths and the session monitor via a new effectiveCwd(), so a resumed session is located and bridged in the folder it actually runs in.
  • The non-TTY home snapshot gains a recent-sessions section.

Testing

  • New tests/session-history.test.ts (5 cases): label extraction for both agents, folder-first ordering, limit, single-line truncation, empty-dirs.
  • pnpm --filter @tinyhumansai/tinyplace build — clean.
  • Full SDK vitest: 469 passed, 1 failing is pre-existing and unrelated (Home mode ignores a provider-specific recipient reads the real ~/.tinyplace/config.json; fails identically on clean main, passes in CI's isolated env).
  • Manual non-TTY home snapshot verified: sessions listed with agent tag, relative time, and first-prompt label.

Notes

Summary by CodeRabbit

  • New Features
    • Added a home-screen “recent sessions” resume experience with a split layout (actions left, scrollable resume list right).
    • Resuming now preserves the original working directory and uses session-aware launch for both supported agents.
    • Home mode includes improved pane/selection navigation, plus non-interrupting resume on Enter.
  • Bug Fixes
    • Recent-session discovery is more resilient and produces cleaner, correctly ordered labels.
    • Resumed streaming now starts at the correct transcript offset (no replay of prior lines).
    • Added stronger safeguards against concurrent resume conflicts.
  • Tests
    • Added coverage for recent-session listing, session locking, and resume tailing behavior.

oxoxDev added 2 commits July 10, 2026 01:48
Scan the agents' own session dirs (~/.claude/projects, ~/.codex/sessions)
into a ranked list of resumable sessions — the same files the harness
tailer streams, so the list stays accurate with no separate store to
keep in sync. Each row resolves to { agent, id, cwd, label, lastActive }.

- Order current-folder-first, then most-recent, so resuming from where
  you stand is at the top.
- Cost-bounded: only the newest N files are opened, and only their first
  64 KiB parsed (enough for session meta + the first prompt).
- Label = the first human prompt, skipping <...>-wrapped system turns
  (codex environment/permissions context, claude command/tool wrappers)
  and tool-result turns that carry no text.

Covered by tests: label extraction for both agents, folder-first order,
limit, and single-line truncation.
Bare `tinyplace` now shows a two-pane home: the action list on the left
(Start Codex / Start Claude / Connect OpenHuman / Settings / Quit) and a
recent-session resume list on the right, the way Claude Code offers a
resume picker. Tab and the arrow keys move the cursor between panes; the
focused pane takes the cyan border and the live row highlight.

Selecting a session relaunches its agent with the resume flag
(`claude --resume <id>` / `codex resume <id>`) in the session's original
working directory, so its files and OpenHuman folder-thread line up. The
resumed bridge pins a stable, per-session OpenHuman scope
(`tp-<agent>-resume-<id>`) so re-resuming the same session continues the
same thread regardless of folder — fresh launches keep folder scope.

Launch cwd is now threaded through the pty/child/tmux paths and the
session monitor via effectiveCwd() so a resumed session is located and
bridged in the folder it actually runs in. The non-TTY home snapshot
gains a recent-sessions section too.
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

@oxoxDev is attempting to deploy a commit to the Vezures Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ba185fb6-9d37-4241-b5ea-f629b79a901b

📥 Commits

Reviewing files that changed from the base of the PR and between 2f118ca and ea39f42.

📒 Files selected for processing (5)
  • sdk/typescript/src/cli/harness-wrapper.ts
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/src/cli/tui.ts
  • sdk/typescript/tests/harness-resume-tail.test.ts
  • sdk/typescript/tests/session-lock.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • sdk/typescript/tests/harness-resume-tail.test.ts
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/src/cli/tui.ts

📝 Walkthrough

Walkthrough

Adds recent-session discovery for Claude and Codex, a two-pane TUI resume flow, provider-specific resumed launches with session locking and cwd preservation, resumed-session tailing support, and tests for history parsing, locking, and tail offsets.

Changes

Session resume feature

Layer / File(s) Summary
Session history scanning and validation
sdk/typescript/src/cli/session-history.ts, sdk/typescript/tests/session-history.test.ts
Discovers, parses, sanitizes, orders, deduplicates, and tests recent Claude and Codex sessions.
TUI resume state and navigation
sdk/typescript/src/cli/tui.ts
Loads sessions into home mode, adds pane navigation and selection, and starts the selected resume flow.
Per-session locking
sdk/typescript/src/cli/session-lock.ts, sdk/typescript/tests/session-lock.test.ts, sdk/typescript/src/cli/tui.ts
Adds atomic locks, stale-lock recovery, release handling, and lifecycle integration.
Resume-aware launch and tailing
sdk/typescript/src/cli/tui.ts, sdk/typescript/src/cli/harness-wrapper.ts, sdk/typescript/tests/harness-resume-tail.test.ts
Adds provider-specific resume arguments, preserves cwd and transcript paths, and streams only post-resume lines.
Home rendering and snapshots
sdk/typescript/src/cli/tui.ts
Renders recent sessions in a scrollable pane and non-TTY resume snapshots.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Poem

I hopped through logs and found a trail,
Claude and Codex in a leafy tale.
Tab to choose, resume with care,
The right cwd follows everywhere. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a two-pane CLI home screen with session resume support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d43c33a892

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return;
}
this.setProfile(session.agent, session.id);
this.launchCwd = session.cwd;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Tail the selected resume file

When resuming a session that appends to its existing JSONL file (Claude resumes do this, and Codex can as well), this code only carries the session cwd forward and drops session.path. The bridge tailer created later calls HarnessSessionTailer.start(), which snapshots all existing session files into ignoredSessionFiles and then only locates files not in that set, so it never tails the selected resumed file and OpenHuman continuity silently stops unless the agent creates a brand-new file. Please pass the selected path through as config.sessionFile or otherwise bypass the ignored-file filter for resume launches.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 5ae0b0c — a resumed file predates the tailer's start snapshot, so it was in ignoredSessionFiles and never streamed. Threaded it through a new config.resumeSessionFile that un-ignores exactly that file (chose un-ignore over pinning sessionFile so a resume that instead spawns a fresh file is still located normally — codex can do that).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
sdk/typescript/src/cli/tui.ts (1)

1117-1188: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Split the longer helpers to satisfy the 20-line function limit.

renderHomePanes, renderHomeActionsContent, and buildAgentProfile now exceed the repository limit; extract pane construction, OpenHuman status rendering, and resume-arg building into small helpers. As per coding guidelines, "Limit functions to a maximum of 20 lines of code; extract longer logic into separate helper functions".

Also applies to: 1492-1540

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/src/cli/tui.ts` around lines 1117 - 1188, The home screen
rendering helpers are too long and need to be split to satisfy the 20-line
limit. Refactor renderHomePanes, renderHomeActionsContent, and buildAgentProfile
by extracting the pane construction, OpenHuman status formatting, and
resume-argument assembly into small helper methods with clear names, then keep
the original methods as thin orchestrators. Use the existing symbols
renderHomePanes, renderHomeActionsContent, buildAgentProfile, and the
OpenHuman-related state fields to preserve behavior while reducing each
function’s length.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/typescript/src/cli/session-history.ts`:
- Around line 119-136: Add JSDoc comments to the exported functions
claudeSessionsDir and codexSessionsDir in session-history.ts, matching the style
used on listRecentSessions. Briefly describe each function’s purpose and its env
parameter/return value so all public exports in this module are documented.

In `@sdk/typescript/src/cli/tui.ts`:
- Around line 1984-1989: Session labels are rendered directly in the recent
sessions list and can carry unsafe terminal control bytes. Update the rendering
in the session list builder that maps over sessions (and the same logic in the
other resume view referenced by the review) to sanitize `session.label` before
interpolating it, while still preserving Blessed tag escaping. Use the existing
session rendering path around `relativeTime(...)` and `session.label` to strip
control characters at display time.
- Around line 1979-1980: The non-TTY snapshot session ordering is using the
wrong working directory, causing `renderSnapshotSessions` to ignore the
configured cwd when `options.cwd` differs. Update `renderSnapshotSessions` to
use the same cwd source as interactive home mode, specifically
`this.effectiveCwd()` or an equivalent context-derived cwd, instead of
`process.cwd()`, so the “current folder first” ordering matches both TTY and
piped output paths.

In `@sdk/typescript/tests/session-history.test.ts`:
- Around line 86-94: The `writeSession` helper is using a dynamic `import()` for
`utimes`, which should be replaced with a top-level import to match the existing
`node:fs/promises` usage in this test file. Update the imports at the top of the
module to include `utimes` alongside `mkdtemp`, `mkdir`, and `writeFile`, then
remove the ներպ-function import inside `writeSession` and keep the rest of the
helper unchanged.

---

Nitpick comments:
In `@sdk/typescript/src/cli/tui.ts`:
- Around line 1117-1188: The home screen rendering helpers are too long and need
to be split to satisfy the 20-line limit. Refactor renderHomePanes,
renderHomeActionsContent, and buildAgentProfile by extracting the pane
construction, OpenHuman status formatting, and resume-argument assembly into
small helper methods with clear names, then keep the original methods as thin
orchestrators. Use the existing symbols renderHomePanes,
renderHomeActionsContent, buildAgentProfile, and the OpenHuman-related state
fields to preserve behavior while reducing each function’s length.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab22ea32-9b13-4fd1-a26e-1e940ee2064a

📥 Commits

Reviewing files that changed from the base of the PR and between 253b408 and d43c33a.

📒 Files selected for processing (3)
  • sdk/typescript/src/cli/session-history.ts
  • sdk/typescript/src/cli/tui.ts
  • sdk/typescript/tests/session-history.test.ts

Comment thread sdk/typescript/src/cli/session-history.ts
Comment thread sdk/typescript/src/cli/tui.ts Outdated
Comment thread sdk/typescript/src/cli/tui.ts
Comment thread sdk/typescript/tests/session-history.test.ts
oxoxDev added 2 commits July 10, 2026 02:20
Address review on tinyhumansai#240:
- Strip C0/DEL/C1 control bytes from labels at the source (truncateLabel),
  so a prompt carrying an escape sequence can't move the cursor or recolor
  the pane — covers every consumer (TTY rows, non-TTY snapshot, tests) in
  one place instead of at each render site.
- Add the missing JSDoc on the exported claudeSessionsDir/codexSessionsDir.
- Test file: import utimes at top level instead of a dynamic import().
- New test asserts control bytes are stripped from the label.
Address review on tinyhumansai#240:
- A resumed session appends to a file that already existed when the tailer
  started, so it was swept into ignoredSessionFiles and never streamed —
  breaking OpenHuman continuity on resume. Thread the resumed file through
  a new HarnessWrapperConfig.resumeSessionFile that un-ignores just that
  file (without pinning, so a resume that spawns a fresh file still locates
  normally).
- renderHomeSnapshot now takes the caller's cwd so the non-TTY 'current
  folder first' ordering matches interactive home mode instead of always
  using process.cwd().

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 653-660: The resumed session replay starts from the wrong offset
because `poll()` resets `lineOffset` to 0 when `resumeSessionFile` is found,
causing already-existing transcript lines to be reread and republished. Update
the resume path in `harness-wrapper.ts`, especially the `start()` setup and the
`poll()` logic around `resumeSessionFile` and `lineOffset`, so the resumed
file’s initial `lineOffset` is seeded from its current line count before tailing
continues.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 72393c2a-8425-4614-a02a-a00e1e94bbe2

📥 Commits

Reviewing files that changed from the base of the PR and between d43c33a and 5ae0b0c.

📒 Files selected for processing (4)
  • sdk/typescript/src/cli/harness-wrapper.ts
  • sdk/typescript/src/cli/session-history.ts
  • sdk/typescript/src/cli/tui.ts
  • sdk/typescript/tests/session-history.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • sdk/typescript/tests/session-history.test.ts
  • sdk/typescript/src/cli/tui.ts
  • sdk/typescript/src/cli/session-history.ts

Comment thread sdk/typescript/src/cli/harness-wrapper.ts
oxoxDev added 2 commits July 10, 2026 10:39
Resuming pins a stable OpenHuman thread id (tp-<agent>-resume-<sessionId>)
so re-resuming continues the same conversation. But two tinyplace instances
resuming the SAME session at once share one wallet + one thread key: they
double-stream into a single OpenHuman thread and two '<agent> --resume <id>'
processes scribble into the same session JSONL.

Fix is mutual exclusion, not key-uniqueness (uniqueness would defeat the
resume continuity): take a per-session lockfile (agent+sessionId, under
<config-dir>/locks) before launch and release it on teardown. A second
instance sees it held and stays on the home screen with a notice; a dead
holder's lock is reclaimed via a PID-liveness probe so a crash never wedges
a resume. Lock filesystem errors degrade to 'allowed' rather than blocking.

The deeper shared-wallet risks (two instances → one Signal ratchet + one
inbox) predate this feature and any concurrent instance; tracked separately.
Address review on tinyhumansai#240: un-ignoring the resumed file made the tailer locate
it, but poll() reset lineOffset to 0, so it re-read the whole file and
republished every prior turn to OpenHuman on resume. Record the file's line
count at tailer start as resumeStartOffset and seed lineOffset from it when
the located path is the resumed file, so only turns appended after resume
stream. Regression test drives the tailer over a pre-populated file + one
appended turn and asserts only the new turn is emitted.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
sdk/typescript/tests/session-lock.test.ts (1)

38-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for reclaiming a lock whose holder PID is dead.

The suite covers corrupt/unreadable reclamation and a live-holder refusal, but not the primary isStale path: a lock stamped with a valid-but-dead numeric pid should be reclaimed. A stamp with an unused high pid (which makes process.kill(pid, 0) throw ESRCH) exercises that branch directly.

🧪 Suggested test
it("reclaims a lock whose holder process is dead", async () => {
  const dir = await lockDir();
  const path = join(dir, "claude-sess-1.lock");
  // A pid that is almost certainly not a running process → ESRCH on kill(pid, 0).
  await writeFile(path, JSON.stringify({ pid: 2 ** 22, at: Date.now() }));

  const lock = acquireSessionLock(dir, "claude", "sess-1");
  expect(lock).toBeDefined();
  const stamped = JSON.parse(await readFile(lock!.path, "utf8"));
  expect(stamped.pid).toBe(process.pid);
  await rm(dir, { recursive: true, force: true });
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/session-lock.test.ts` around lines 38 - 46, Add a test
beside the existing corrupt-lock case that writes a valid JSON lock with an
unused high numeric pid and current timestamp, then calls acquireSessionLock for
the same lock. Assert the lock is reclaimed, its stamped pid equals process.pid,
and clean up the temporary directory; import or use readFile as needed to
inspect lock.path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/typescript/src/cli/session-lock.ts`:
- Around line 44-55: Replace the non-atomic unlinkSync() followed by writeLock()
sequence in the stale-lock branch of the session-lock acquisition logic with a
single atomic reclaim/handoff operation, updating the relevant lock helper such
as writeLock() to safely replace only the stale lock. Ensure competing
contenders cannot both successfully reclaim the same session, while preserving
the existing { path } return and failure behavior.

---

Nitpick comments:
In `@sdk/typescript/tests/session-lock.test.ts`:
- Around line 38-46: Add a test beside the existing corrupt-lock case that
writes a valid JSON lock with an unused high numeric pid and current timestamp,
then calls acquireSessionLock for the same lock. Assert the lock is reclaimed,
its stamped pid equals process.pid, and clean up the temporary directory; import
or use readFile as needed to inspect lock.path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2451c02b-1164-4d2b-903c-590cceb88fab

📥 Commits

Reviewing files that changed from the base of the PR and between 5ae0b0c and bbbde11.

📒 Files selected for processing (3)
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/src/cli/tui.ts
  • sdk/typescript/tests/session-lock.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdk/typescript/src/cli/tui.ts

Comment thread sdk/typescript/src/cli/session-lock.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
sdk/typescript/tests/harness-resume-tail.test.ts (4)

20-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the fixture helper within the 20-line function limit.

resumeConfig spans Lines 20-48. Extract the shared configuration into a constant and leave this helper responsible only for applying the session-file overrides.

As per coding guidelines, functions must be limited to 20 lines and longer logic should be extracted into helpers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/harness-resume-tail.test.ts` around lines 20 - 48,
resumeConfig exceeds the 20-line function limit. Extract its shared
HarnessWrapperConfig fields into a module-level constant, then have resumeConfig
return that configuration with only sessionFile and resumeSessionFile overrides
applied, preserving the existing values and behavior.

Source: Coding guidelines


84-122: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the async test callback with the repository rules.

The async Vitest callback has no explicit Promise<void> return type and no try/catch error handling. Add both, or explicitly document an exemption for test callbacks.

As per coding guidelines, all TypeScript functions require explicit return types and async functions require try/catch handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/harness-resume-tail.test.ts` around lines 84 - 122,
Update the async test callback in “skips the existing transcript and emits only
the post-resume turn” to explicitly return Promise<void> and wrap its body in
try/catch error handling, preserving the existing assertions and cleanup
behavior.

Source: Coding guidelines


20-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use compliant TypeScript identifier names.

This file introduces non-camelCase or abbreviated identifiers: EXISTING, resumeConfig, dirs, dir, out, _enc, and cb. Rename them to descriptive camelCase names such as existingTranscript, createResumeConfiguration, directories, temporaryDirectory, outputStream, encoding, and callback.

As per coding guidelines, TypeScript variables, functions, and parameters must use camelCase and abbreviations must be avoided unless explicitly excepted.

Also applies to: 50-50, 76-76, 85-87, 90-100

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/harness-resume-tail.test.ts` at line 20, The identifiers
in the resume test harness violate the project’s naming conventions. Rename
EXISTING, resumeConfig, dirs, dir, out, _enc, and cb to descriptive camelCase
names such as existingTranscript, createResumeConfiguration, directories,
temporaryDirectory, outputStream, encoding, and callback, updating all
references across the affected functions and test cases.

Source: Coding guidelines


35-39: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Also test the non-pinned resume-discovery path.

Because sessionFile is set, HarnessSessionTailer.locateSession() returns through its explicit-file branch and does not consult ignoredSessionFiles. This test therefore passes even if resumeSessionFile is never un-ignored. Add a separate case without sessionFile that discovers the resumed file from sessionsDir.

Also applies to: 97-104

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/harness-resume-tail.test.ts` around lines 35 - 39, Add a
separate test case in the harness resume-tail tests that omits `sessionFile`
while setting `resumeSessionFile`, allowing
`HarnessSessionTailer.locateSession()` to discover the file from `sessionsDir`
and verify it is removed from `ignoredSessionFiles`; retain the existing
pinned-file case for explicit-file behavior.
sdk/typescript/src/cli/harness-wrapper.ts (1)

659-666: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep start() within the 20-line limit.

Extract the resume-offset initialization or polling setup into helpers. As per coding guidelines, functions are limited to a maximum of 20 lines; start() exceeds that limit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/src/cli/harness-wrapper.ts` around lines 659 - 666, Reduce the
length of start() to 20 lines or fewer by extracting the resume-session offset
initialization and/or polling setup into focused private helper methods.
Preserve the existing behavior involving ignoredSessionFiles, resumeStartOffset,
and transcript streaming, and invoke the helpers from start().

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 661-665: Canonicalize the configured resume session path in the
resume handling around resumeStartOffset, using the same canonical path for
ignoredSessionFiles deletion and the located.path comparison in the session-file
tailing logic. Ensure equivalent relative, absolute, and symlink paths resolve
identically, and add tests covering path aliases plus a competing fresh file so
resumed history is not replayed.

In `@sdk/typescript/tests/harness-resume-tail.test.ts`:
- Around line 118-121: In the resume-tail test, replace the containment
assertions for v1Texts(chunks) with an exact sequence assertion, verifying that
the emitted texts equal only the expected “fresh turn after resume” message in
the correct order and contain no additional or duplicate messages.

---

Nitpick comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 659-666: Reduce the length of start() to 20 lines or fewer by
extracting the resume-session offset initialization and/or polling setup into
focused private helper methods. Preserve the existing behavior involving
ignoredSessionFiles, resumeStartOffset, and transcript streaming, and invoke the
helpers from start().

In `@sdk/typescript/tests/harness-resume-tail.test.ts`:
- Around line 20-48: resumeConfig exceeds the 20-line function limit. Extract
its shared HarnessWrapperConfig fields into a module-level constant, then have
resumeConfig return that configuration with only sessionFile and
resumeSessionFile overrides applied, preserving the existing values and
behavior.
- Around line 84-122: Update the async test callback in “skips the existing
transcript and emits only the post-resume turn” to explicitly return
Promise<void> and wrap its body in try/catch error handling, preserving the
existing assertions and cleanup behavior.
- Line 20: The identifiers in the resume test harness violate the project’s
naming conventions. Rename EXISTING, resumeConfig, dirs, dir, out, _enc, and cb
to descriptive camelCase names such as existingTranscript,
createResumeConfiguration, directories, temporaryDirectory, outputStream,
encoding, and callback, updating all references across the affected functions
and test cases.
- Around line 35-39: Add a separate test case in the harness resume-tail tests
that omits `sessionFile` while setting `resumeSessionFile`, allowing
`HarnessSessionTailer.locateSession()` to discover the file from `sessionsDir`
and verify it is removed from `ignoredSessionFiles`; retain the existing
pinned-file case for explicit-file behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e1b6f763-0b6b-4bed-bc7c-a64d2f7e3b08

📥 Commits

Reviewing files that changed from the base of the PR and between bbbde11 and 2f118ca.

📒 Files selected for processing (2)
  • sdk/typescript/src/cli/harness-wrapper.ts
  • sdk/typescript/tests/harness-resume-tail.test.ts

Comment thread sdk/typescript/src/cli/harness-wrapper.ts Outdated
Comment thread sdk/typescript/tests/harness-resume-tail.test.ts Outdated
oxoxDev added 2 commits July 10, 2026 11:53
Delete-then-create let two contenders both reclaim a stale lock, and the
second unlink could wipe the first winner's fresh lock, leaving two holders.
Steal the stale file via an atomic renameSync (only one racer wins; the loser
gets ENOENT) and publish with the existing exclusive wx create, so at most one
holder survives. Adds a dead-pid reclaim test covering the isStale liveness path.
The resume path comes from session discovery, a different origin than
listSessionFiles, so a symlinked/relative/absolute alias of the same file was
compared by raw string equality. A mismatch left the file in the ignore set
(never tailed) or failed the offset-seed check (replaying the whole transcript
to OpenHuman). Resolve both the ignore-set removal and the located-path check
through a canonical (realpath) identity. Tightens the resume-tail assertion to
an exact sequence and adds symlink-alias + competing-fresh coverage.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
sdk/typescript/src/cli/harness-wrapper.ts (2)

663-681: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract resume initialization from start().

The added canonicalization, ignore-set reconciliation, and offset setup make this public method exceed the repository’s 20-line limit. Move that block into a private helper so start() remains focused on lifecycle setup.

As per coding guidelines, TypeScript/JavaScript functions must be limited to a maximum of 20 lines; extract longer logic into separate helper functions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/src/cli/harness-wrapper.ts` around lines 663 - 681, Extract
the resume-session canonicalization, ignored-file reconciliation, and offset
calculation from start() into a private helper method, such as
initializeResumeSession(). Invoke it from start() at the same lifecycle point,
preserving resumeSessionPath, ignoredSessionFiles, and resumeStartOffset
behavior while keeping start() within the 20-line limit.

Source: Coding guidelines


676-680: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid loading the entire transcript just to count lines.

readAllLines(...).length performs synchronous full-file parsing and retains all existing lines during resume startup. Use a streaming newline counter or a helper that returns only the count to bound memory usage for large session transcripts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/src/cli/harness-wrapper.ts` around lines 676 - 680, Replace
the full-array `readAllLines(...).length` call in the resume initialization with
a memory-bounded line-counting helper or streaming newline counter that returns
only the transcript line count, and assign that result to
`this.resumeStartOffset`.
sdk/typescript/tests/harness-resume-tail.test.ts (2)

136-137: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace abbreviations with descriptive identifiers.

Names such as dir, dirs, out, config, _enc, and cb violate the repository’s abbreviation rule. Prefer names such as temporaryDirectory, output, tailerConfig, encoding, and callback.

As per coding guidelines: “Avoid abbreviations (unicorn/prevent-abbreviations) — exceptions: db, arg, args, env, fn, prop, props, ref, refs.”

Also applies to: 179-192

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/harness-resume-tail.test.ts` around lines 136 - 137,
Replace abbreviated identifiers throughout the test, including dir/dirs, out,
config, _enc, and cb, with descriptive names such as temporaryDirectory,
directories, output, tailerConfig, encoding, and callback; update all
declarations and references consistently in the affected test helpers and
callbacks.

Source: Coding guidelines


192-192: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the unnecessary double type assertion.

TinyPlaceCliOptions only has optional properties, so this can preserve type checking:

-    const options = { env: {} } as unknown as TinyPlaceCliOptions;
+    const options: TinyPlaceCliOptions = { env: {} };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/harness-resume-tail.test.ts` at line 192, In the test
setup, remove the unnecessary `unknown` intermediary from the `options`
declaration and use a directly typed empty object, preserving TypeScript’s
checking for the optional properties of `TinyPlaceCliOptions`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/typescript/tests/harness-resume-tail.test.ts`:
- Around line 201-214: Make transcript selection deterministic in the test
before invoking HarnessSessionTailer.start(): set fixed, distinct mtimes for
both transcript files using timestamps after the fixed startedAt, with real as
the newest. Remove the post-start utimesSync(real, new Date(), new Date()) call
and retain the append after start.
- Around line 135-219: Refactor the async test callback in “resolves a symlinked
resume path and ignores a competing fresh file” to stay under 20 lines: extract
fixture/configuration setup and tailer execution/assertions into named helpers.
Add explicit return types, including Promise<void> for every async helper and
the test callback, and wrap each async operation in try-catch handling
consistent with the test suite.

In `@sdk/typescript/tests/session-lock.test.ts`:
- Around line 51-52: Update the “reclaims a lock whose holder process is dead”
test callback to explicitly return Promise<void>, rename the dir variable to
directory, wrap the test body in the required try/catch handling, and move
cleanup into a finally block so it always runs.
- Around line 54-56: Replace the probabilistic PID fixture in the session-lock
test with a deterministic stale-process setup: spawn a child process, wait for
it to exit, and write its PID into the lock data, or mock the liveness probe
used by isStale. Keep the test focused on the primary liveness branch rather
than the corrupt-data path.

---

Nitpick comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 663-681: Extract the resume-session canonicalization, ignored-file
reconciliation, and offset calculation from start() into a private helper
method, such as initializeResumeSession(). Invoke it from start() at the same
lifecycle point, preserving resumeSessionPath, ignoredSessionFiles, and
resumeStartOffset behavior while keeping start() within the 20-line limit.
- Around line 676-680: Replace the full-array `readAllLines(...).length` call in
the resume initialization with a memory-bounded line-counting helper or
streaming newline counter that returns only the transcript line count, and
assign that result to `this.resumeStartOffset`.

In `@sdk/typescript/tests/harness-resume-tail.test.ts`:
- Around line 136-137: Replace abbreviated identifiers throughout the test,
including dir/dirs, out, config, _enc, and cb, with descriptive names such as
temporaryDirectory, directories, output, tailerConfig, encoding, and callback;
update all declarations and references consistently in the affected test helpers
and callbacks.
- Line 192: In the test setup, remove the unnecessary `unknown` intermediary
from the `options` declaration and use a directly typed empty object, preserving
TypeScript’s checking for the optional properties of `TinyPlaceCliOptions`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 711c4a41-b186-4452-9106-8741cd545764

📥 Commits

Reviewing files that changed from the base of the PR and between 2f118ca and b99f3e8.

📒 Files selected for processing (4)
  • sdk/typescript/src/cli/harness-wrapper.ts
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/tests/harness-resume-tail.test.ts
  • sdk/typescript/tests/session-lock.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdk/typescript/src/cli/session-lock.ts

Comment thread sdk/typescript/tests/harness-resume-tail.test.ts
Comment thread sdk/typescript/tests/harness-resume-tail.test.ts Outdated
Comment thread sdk/typescript/tests/session-lock.test.ts
Comment thread sdk/typescript/tests/session-lock.test.ts Outdated
oxoxDev added 3 commits July 10, 2026 12:19
Pin the resume-tail transcript mtimes before start() (which polls immediately)
so session selection never depends on the wall clock, and replace the
probabilistic high-pid stale-lock fixture with a reaped child pid that reliably
reports dead.
…story

# Conflicts:
#	sdk/typescript/src/cli/tui.ts
…not the agent prompt

The agents run inline (no alternate screen) inside the native tmux relay,
so with tmux mouse capture off the scroll wheel bypassed tmux and reached
the agent, scrolling its own prompt up and down instead of the scrollback.
Enable `mouse on` so the wheel drives tmux copy-mode scrollback and the
prompt stays anchored. Trade-off: drag-select now yields a tmux selection
(still copies) rather than the host terminal's native selection.
@oxoxDev

oxoxDev commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai can you review once more and approve.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

@oxoxDev Sure, I'll re-review the PR and approve it.

✅ Action performed

Comments resolved and changes approved.


Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
sdk/typescript/src/cli/harness-wrapper.ts (1)

1189-1206: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add JSDoc for the exported envelope helpers.

envelopeRole and envelopeText are public exports without JSDoc contracts.

As per coding guidelines, public functions must always have JSDoc comments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/src/cli/harness-wrapper.ts` around lines 1189 - 1206, The
exported envelopeRole and envelopeText helpers lack required JSDoc contracts.
Add concise JSDoc comments directly above both functions describing their
purpose, input envelope, and returned role or text value, preserving the
existing implementations.

Source: Coding guidelines

sdk/typescript/tests/session-lock.test.ts (1)

64-77: 🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy lift

Add a concurrent stale-lock contention test.

This verifies single-process reclamation, but not the atomic rename and exclusive-create guarantee introduced to prevent two contenders from acquiring the same stale lock. Run two contenders against one stale lock and assert exactly one succeeds.

Based on the PR objectives, concurrent stale-lock reclamation is a core behavior of this change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/session-lock.test.ts` around lines 64 - 77, Add a test
alongside the existing “reclaims a lock whose holder process is dead” case that
creates one stale lock, starts two concurrent acquireSessionLock contenders for
the same directory and session, and asserts exactly one returns a defined lock
while the other fails. Verify the winning lock is stamped with the current
process and clean up the lock directory afterward, exercising atomic stale-lock
reclamation and exclusive creation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 1005-1053: The echo suppression currently stores only one expiry
per text, so multiple envelopes from one injection or overlapping identical
injections are not tracked correctly. Update SessionEnvelopePublisher’s
injectedEchoes and markInjected to maintain multiple tokens per echoKey (such as
a count or expiry queue), and change isInjectedEcho to consume exactly one
unexpired token per matching envelope while pruning expired tokens.

---

Nitpick comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 1189-1206: The exported envelopeRole and envelopeText helpers lack
required JSDoc contracts. Add concise JSDoc comments directly above both
functions describing their purpose, input envelope, and returned role or text
value, preserving the existing implementations.

In `@sdk/typescript/tests/session-lock.test.ts`:
- Around line 64-77: Add a test alongside the existing “reclaims a lock whose
holder process is dead” case that creates one stale lock, starts two concurrent
acquireSessionLock contenders for the same directory and session, and asserts
exactly one returns a defined lock while the other fails. Verify the winning
lock is stamped with the current process and clean up the lock directory
afterward, exercising atomic stale-lock reclamation and exclusive creation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ba185fb6-9d37-4241-b5ea-f629b79a901b

📥 Commits

Reviewing files that changed from the base of the PR and between 2f118ca and ea39f42.

📒 Files selected for processing (5)
  • sdk/typescript/src/cli/harness-wrapper.ts
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/src/cli/tui.ts
  • sdk/typescript/tests/harness-resume-tail.test.ts
  • sdk/typescript/tests/session-lock.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • sdk/typescript/tests/harness-resume-tail.test.ts
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/src/cli/tui.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🧹 Nitpick comments (2)
sdk/typescript/src/cli/harness-wrapper.ts (1)

1189-1206: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add JSDoc for the exported envelope helpers.

envelopeRole and envelopeText are public exports without JSDoc contracts.

As per coding guidelines, public functions must always have JSDoc comments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/src/cli/harness-wrapper.ts` around lines 1189 - 1206, The
exported envelopeRole and envelopeText helpers lack required JSDoc contracts.
Add concise JSDoc comments directly above both functions describing their
purpose, input envelope, and returned role or text value, preserving the
existing implementations.

Source: Coding guidelines

sdk/typescript/tests/session-lock.test.ts (1)

64-77: 🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy lift

Add a concurrent stale-lock contention test.

This verifies single-process reclamation, but not the atomic rename and exclusive-create guarantee introduced to prevent two contenders from acquiring the same stale lock. Run two contenders against one stale lock and assert exactly one succeeds.

Based on the PR objectives, concurrent stale-lock reclamation is a core behavior of this change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/tests/session-lock.test.ts` around lines 64 - 77, Add a test
alongside the existing “reclaims a lock whose holder process is dead” case that
creates one stale lock, starts two concurrent acquireSessionLock contenders for
the same directory and session, and asserts exactly one returns a defined lock
while the other fails. Verify the winning lock is stamped with the current
process and clean up the lock directory afterward, exercising atomic stale-lock
reclamation and exclusive creation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 1005-1053: The echo suppression currently stores only one expiry
per text, so multiple envelopes from one injection or overlapping identical
injections are not tracked correctly. Update SessionEnvelopePublisher’s
injectedEchoes and markInjected to maintain multiple tokens per echoKey (such as
a count or expiry queue), and change isInjectedEcho to consume exactly one
unexpired token per matching envelope while pruning expired tokens.

---

Nitpick comments:
In `@sdk/typescript/src/cli/harness-wrapper.ts`:
- Around line 1189-1206: The exported envelopeRole and envelopeText helpers lack
required JSDoc contracts. Add concise JSDoc comments directly above both
functions describing their purpose, input envelope, and returned role or text
value, preserving the existing implementations.

In `@sdk/typescript/tests/session-lock.test.ts`:
- Around line 64-77: Add a test alongside the existing “reclaims a lock whose
holder process is dead” case that creates one stale lock, starts two concurrent
acquireSessionLock contenders for the same directory and session, and asserts
exactly one returns a defined lock while the other fails. Verify the winning
lock is stamped with the current process and clean up the lock directory
afterward, exercising atomic stale-lock reclamation and exclusive creation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ba185fb6-9d37-4241-b5ea-f629b79a901b

📥 Commits

Reviewing files that changed from the base of the PR and between 2f118ca and ea39f42.

📒 Files selected for processing (5)
  • sdk/typescript/src/cli/harness-wrapper.ts
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/src/cli/tui.ts
  • sdk/typescript/tests/harness-resume-tail.test.ts
  • sdk/typescript/tests/session-lock.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • sdk/typescript/tests/harness-resume-tail.test.ts
  • sdk/typescript/src/cli/session-lock.ts
  • sdk/typescript/src/cli/tui.ts
🛑 Comments failed to post (1)
sdk/typescript/src/cli/harness-wrapper.ts (1)

1005-1053: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Track one suppression token per emitted echo.

injectedEchoes stores one expiry per text. With emitV2, one injected session line can produce both v1 and v2 envelopes; two identical inbound prompts can also overlap. The first matching envelope consumes the only token, so the next is forwarded and may re-enter the auto-reply loop. Store a count or expiry queue and consume one token per matching envelope.

Based on the supplied tailer/publisher flow, one injected session line can produce multiple outbound envelopes.

Also applies to: 1065-1068

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn as spawnChild } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/typescript/src/cli/harness-wrapper.ts` around lines 1005 - 1053, The echo
suppression currently stores only one expiry per text, so multiple envelopes
from one injection or overlapping identical injections are not tracked
correctly. Update SessionEnvelopePublisher’s injectedEchoes and markInjected to
maintain multiple tokens per echoKey (such as a count or expiry queue), and
change isInjectedEcho to consume exactly one unexpired token per matching
envelope while pruning expired tokens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant