Skip to content

feat(parity): close hashline and TUI slash-command parity gaps#154

Merged
junhoyeo merged 16 commits intomainfrom
feat/hashline-native-edit-read
Feb 25, 2026
Merged

feat(parity): close hashline and TUI slash-command parity gaps#154
junhoyeo merged 16 commits intomainfrom
feat/hashline-native-edit-read

Conversation

@junhoyeo
Copy link
Copy Markdown
Owner

@junhoyeo junhoyeo commented Feb 23, 2026

Summary

  • add hashline-native utilities and migrate Read output to include file_hash, range, and LINE#ID | content tags
  • upgrade Edit to support hashline edit ops (replace/append/prepend) with required expected_file_hash, while preserving legacy old_string/new_string behavior
  • update comment and recovery hooks to understand hashline edit payloads and improve mismatch/error handling

Validation

  • cargo fmt --all
  • cargo test -p uira-orchestration
  • cargo build -p uira-orchestration

Summary by cubic

Adds a hashline-native Read/Edit flow anchored to LINE#ID with stale-safe hashing and standardized output sections. Wires todo continuation into the agent stop path and hardens guards, comment hooks, and recovery to make edits safer and more reliable.

  • New Features

    • Read returns file_hash, range (Lstart–Lend), and per-line tags as LINE#ID | text; supports around_line with before/after; truncates long lines; outputs METADATA and CONTENT sections; adds binary/size/ignore guards.
    • Edit supports hashline ops (replace/append/prepend) with expected_file_hash; validates LINE#ID anchors (rejects L0); preserves newline style; at most one anchored edit per call; legacy old_string/new_string still works; outputs a DIFF section; removes unsupported oneOf schema at top level (runtime validation handles mode).
    • Edit errors include fuzzy suggestions when exact matches fail; recovery patterns now cover hashline/file-hash mismatches and invalid pos/end/op; handles long and RTL text.
    • Comment hooks reuse a shared hashline parser across Edit/MultiEdit, strip only valid hashline prefixes, ignore non-hashline “|”, gate by file type, and de-dup using normalized text.
    • Hash utilities compute stable file and line hashes (xxhash32); guards add should_ignore_file(path, cwd); fuzzy module adds Levenshtein similarity search.
    • Agent injects todo continuations when stopping with pending work (system/user injections, capped per run).
    • CI validates @uiradev/uira-* optionalDependencies use platform-tagged npm aliases; release smoke tests cover scoped/unscoped npx and running agent/hook binaries; README recommends npx uira@latest.
    • TUI shows accurate Write diffs by reading existing file content; adds parity slash commands (e.g., /new, /render, /think) and Shift+Enter for multi-line input; README documents these.
  • Migration

    • Run Read to get file_hash and LINE#ID, then call Edit with expected_file_hash and an edits array. replace requires pos and end; lines can be raw text or "LINE#ID | text"; only one anchored edit per call; anchors must be valid LINE#ID (not L0).
    • Optionally use around_line with before/after to fetch focused context. On mismatches, re-run Read and retry; legacy usage remains unchanged.

Written for commit e9e07e0. Summary will update on new commits.

Copy link
Copy Markdown

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

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: 2af88581cd

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

5 issues found across 9 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="crates/uira-orchestration/src/tools/builtins/edit.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/builtins/edit.rs:87">
P1: Sequential multi-edit application with position-based LINE#ID refs is broken: after the first edit mutates the `lines` vec, subsequent edits' LINE#IDs reference stale positions. `verify_line_ref` will report a confusing "hashline mismatch" rather than the real cause (shifted indices). Consider either (a) applying edits in reverse order by position, (b) resolving all LINE#ID refs to indices *before* any mutations, or (c) documenting that only single-edit payloads (or position-less appends/prepends) are supported when using LINE#IDs.</violation>
</file>

<file name="crates/uira-orchestration/src/tools/comment_hook.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/comment_hook.rs:99">
P2: Guard hashline edit-line detection with the same supported-file check used by check_edit/check_write; otherwise unsupported files now trigger comment warnings.</violation>
</file>

<file name="crates/uira-orchestration/src/hooks/hooks/comment_checker.rs">

<violation number="1" location="crates/uira-orchestration/src/hooks/hooks/comment_checker.rs:82">
P2: This adds a second copy of the hashline line-parsing logic that already exists in tools/comment_hook.rs. Consider extracting the shared functionality into a common helper (or reusing the existing one) to avoid divergence and simplify maintenance.</violation>
</file>

<file name="crates/uira-orchestration/src/tools/builtins/read.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/builtins/read.rs:40">
P2: The per-line 2000-character truncation guard from the previous implementation was removed. A single very long line (common in minified JS/JSON or lockfiles) can now produce multi-megabyte tool output from a single `Read` call, causing excessive token consumption and potential context-limit failures. Restore the per-line truncation alongside hashline tagging.</violation>
</file>

<file name="crates/uira-orchestration/src/tools/builtins/hashline.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/builtins/hashline.rs:72">
P1: `right.trim_start()` strips ALL leading whitespace from the content portion, destroying indentation. For a line like `2#AB |     return x`, this returns `"return x"` instead of `"    return x"`. Since the hashline format uses `LINE#ID | content` (single space after `|`), only strip one leading space character to preserve the user's original indentation. This will corrupt indentation-sensitive files (Python, YAML, etc.).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 7 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="crates/uira-orchestration/src/tools/comment_shared.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/comment_shared.rs:47">
P3: Duplicate hashline parsing logic; `parse_edit_line_content` mirrors `hashline::parse_line_content`, which makes future format changes easy to miss. Consider reusing `hashline::parse_line_content` (and its `parse_line_ref`) to keep behavior in one place.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="crates/uira-orchestration/src/tools/comment_shared.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/comment_shared.rs:27">
P3: parse_edit_line_content now strips prefixes for invalid hashline tags like "0#AB | ..." because parse_line_content treats line 0 as valid. This can remove legitimate content during comment detection. Consider rejecting line_number == 0 in parse_line_ref or in parse_line_content before stripping.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Read existing file content in spawn_approval_handler before generating
diff preview, so Write tool shows correct diff when overwriting files.

Also remove oneOf schema constraint from Edit tool that Anthropic API
does not support at top level - runtime validation handles mode detection.
…rameter

Wave 1 of code-editing-agent adaptations:
- Add Levenshtein fuzzy matching module (fuzzy.rs) with similarity search
- Add file read guards module (guards.rs) with binary detection and ignore patterns
- Add around_line parameter to Read tool for centered line reads
- 38 new unit tests across all three modules
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="crates/uira-orchestration/src/tools/builtins/guards.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/builtins/guards.rs:73">
P2: `is_ignored_path` only matches `/` separators, so ignored directories won’t be detected on Windows paths. Normalize path separators (or inspect `Path` components) before applying the substring checks.</violation>
</file>

<file name="crates/uira-orchestration/src/tools/builtins/fuzzy.rs">

<violation number="1" location="crates/uira-orchestration/src/tools/builtins/fuzzy.rs:2">
P3: This module is currently unused in the crate and suppresses the dead-code lint, which leaves a block of unreferenced functionality in production. Consider removing it until it’s used or integrating it where needed instead of silencing the warning.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

///
/// Returns `true` if the path should be ignored, `false` otherwise.
pub fn is_ignored_path(path: &Path) -> bool {
let path_str = path.to_string_lossy();
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Feb 24, 2026

Choose a reason for hiding this comment

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

P2: is_ignored_path only matches / separators, so ignored directories won’t be detected on Windows paths. Normalize path separators (or inspect Path components) before applying the substring checks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/uira-orchestration/src/tools/builtins/guards.rs, line 73:

<comment>`is_ignored_path` only matches `/` separators, so ignored directories won’t be detected on Windows paths. Normalize path separators (or inspect `Path` components) before applying the substring checks.</comment>

<file context>
@@ -0,0 +1,341 @@
+///
+/// Returns `true` if the path should be ignored, `false` otherwise.
+pub fn is_ignored_path(path: &Path) -> bool {
+    let path_str = path.to_string_lossy();
+
+    // Check for node_modules
</file context>
Fix with Cubic

@@ -0,0 +1,391 @@
//! Levenshtein fuzzy matching for finding similar strings in content.
#![allow(dead_code)]
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Feb 24, 2026

Choose a reason for hiding this comment

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

P3: This module is currently unused in the crate and suppresses the dead-code lint, which leaves a block of unreferenced functionality in production. Consider removing it until it’s used or integrating it where needed instead of silencing the warning.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/uira-orchestration/src/tools/builtins/fuzzy.rs, line 2:

<comment>This module is currently unused in the crate and suppresses the dead-code lint, which leaves a block of unreferenced functionality in production. Consider removing it until it’s used or integrating it where needed instead of silencing the warning.</comment>

<file context>
@@ -0,0 +1,391 @@
+//! Levenshtein fuzzy matching for finding similar strings in content.
+#![allow(dead_code)]
+//!
+//! This module provides utilities for finding similar strings when exact matches fail,
</file context>
Fix with Cubic

…tion

Wave 2 of code-editing-agent adaptations:
- Enhance Edit tool error messages with fuzzy matching suggestions (Task 4)
- Add standardized tool output formatting trait at tools/output.rs (Task 5)
- Add todo continuation injection in agent loop (Task 6)
- 15 new tests across all three features
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 6 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="crates/uira-agent/src/continuation.rs">

<violation number="1" location="crates/uira-agent/src/continuation.rs:30">
P2: `is_completion_signal` treats negated phrases like "not finished" or "not all tasks" as completion signals because it only checks for raw substrings. This can incorrectly inject a continuation when the response explicitly says work is not complete. Consider guarding against negated forms when matching phrases.</violation>
</file>

<file name="crates/uira-agent/src/agent.rs">

<violation number="1" location="crates/uira-agent/src/agent.rs:960">
P2: continuation_count is meant to be per-run but is never reset. After hitting max_continuations once, future runs in the same agent instance will never inject a todo continuation, even when incomplete todos remain. Reset continuation_count at the start of each run (e.g., when run_prompt_owned/run_message begins).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

"all tasks",
"work is complete",
];
completion_phrases.iter().any(|phrase| lower.contains(phrase))
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Feb 24, 2026

Choose a reason for hiding this comment

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

P2: is_completion_signal treats negated phrases like "not finished" or "not all tasks" as completion signals because it only checks for raw substrings. This can incorrectly inject a continuation when the response explicitly says work is not complete. Consider guarding against negated forms when matching phrases.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/uira-agent/src/continuation.rs, line 30:

<comment>`is_completion_signal` treats negated phrases like "not finished" or "not all tasks" as completion signals because it only checks for raw substrings. This can incorrectly inject a continuation when the response explicitly says work is not complete. Consider guarding against negated forms when matching phrases.</comment>

<file context>
@@ -0,0 +1,106 @@
+        "all tasks",
+        "work is complete",
+    ];
+    completion_phrases.iter().any(|phrase| lower.contains(phrase))
+}
+
</file context>
Fix with Cubic


// Check if we should inject a continuation message
if self.continuation_enabled
&& self.continuation_count < self.max_continuations
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Feb 24, 2026

Choose a reason for hiding this comment

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

P2: continuation_count is meant to be per-run but is never reset. After hitting max_continuations once, future runs in the same agent instance will never inject a todo continuation, even when incomplete todos remain. Reset continuation_count at the start of each run (e.g., when run_prompt_owned/run_message begins).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/uira-agent/src/agent.rs, line 960:

<comment>continuation_count is meant to be per-run but is never reset. After hitting max_continuations once, future runs in the same agent instance will never inject a todo continuation, even when incomplete todos remain. Reset continuation_count at the start of each run (e.g., when run_prompt_owned/run_message begins).</comment>

<file context>
@@ -938,22 +947,63 @@ impl Agent {
+
+                // Check if we should inject a continuation message
+                if self.continuation_enabled
+                    && self.continuation_count < self.max_continuations
+                    && crate::continuation::is_completion_signal(&output)
+                    && self
</file context>
Fix with Cubic

…tests

Wave 3 of code-editing-agent adaptations:
- Apply standardized output sections to Read and Edit tools (Task 7)
- Add 7 fuzzy Edit integration tests including Unicode and performance (Task 8)
- Read output now has METADATA and CONTENT sections
- Edit output now has DIFF section
- guards.rs: add should_ignore_file(path, cwd) matching plan Task 3 signature
- edit.rs: extract format_error_with_suggestions() helper per plan Task 4
- edit.rs: fix long string test to >1000 chars, add RTL Unicode test per Task 8
- continuation.rs: add check_todo_continuation() per plan Task 6
- continuation.rs: populate system_injection in ContinuationMessage
- All 72+ new tests pass, clippy clean
@junhoyeo junhoyeo changed the title feat(orchestration): add hashline-native read/edit flow with stale-safe hooks feat(parity): close hashline and TUI slash-command parity gaps Feb 24, 2026
@junhoyeo junhoyeo merged commit ba58a9b into main Feb 25, 2026
7 checks passed
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