Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# Added by awf project-onboard
/target/
debug/
!extensions/debug/
!extensions/debug/**
**/*.rs.bk
*.swp
*.swo
Expand Down
8 changes: 8 additions & 0 deletions .tower/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ extensions = ["rs"]
format = "rustc-json"
target = "none"

[debug.rust]
command = "target/debug/fixture_debug_adapter"
args = []
extensions = ["rs"]
adapter_type = "fixture"
default_timeout_secs = 5
idle_ttl_secs = 300

[extensions]
# Plugin file stems to skip loading, e.g. ["ast"].
# A disabled extension gets no sandbox, no fuel, no tools, no watcher hooks.
Expand Down
34 changes: 34 additions & 0 deletions .zpm/kb/architecture/journal.wal
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,37 @@
{"ts":1782212312,"op":"assert","clause":"arch_convention('conv_daemon_wire', 'daemon socket protocol', 'daemon socket clients send one newline-delimited JSON handshake first, and protocol version changes require bumping PROTOCOL_VERSION', 'feature_f001_directory_listing')"}
{"ts":1782212313,"op":"retractall","clause":"arch_convention('conv_daemon_idle_config', _, _, _)"}
{"ts":1782212313,"op":"assert","clause":"arch_convention('conv_daemon_idle_config', 'daemon config', '[daemon].idle_timeout_secs defaults to 30 seconds and unknown daemon config keys are rejected', 'feature_f001_directory_listing')"}
{"ts":1782295005,"op":"retractall","clause":"arch_component(_,_,_,'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295005,"op":"retractall","clause":"arch_port(_,_,'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295006,"op":"retractall","clause":"arch_decision(_,_,_,_,'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295006,"op":"retractall","clause":"arch_convention(_,_,_,'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295006,"op":"retractall","clause":"arch_adr(_,_,'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295006,"op":"retractall","clause":"arch_feature('feature_f004_interactive_debug_session_sidecar',_,_)"}
{"ts":1782295007,"op":"retractall","clause":"arch_component('config', _, _, _)"}
{"ts":1782295007,"op":"assert","clause":"arch_component('config', infrastructure, '', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295007,"op":"retractall","clause":"arch_component('daemon', _, _, _)"}
{"ts":1782295007,"op":"assert","clause":"arch_component('daemon', infrastructure, '', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295007,"op":"retractall","clause":"arch_component('extension', _, _, _)"}
{"ts":1782295007,"op":"assert","clause":"arch_component('extension', infrastructure, '', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295007,"op":"retractall","clause":"arch_component('mcp', _, _, _)"}
{"ts":1782295007,"op":"assert","clause":"arch_component('mcp', infrastructure, '', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295008,"op":"retractall","clause":"arch_decision('dec_debug_sidecar_owned', _, _, _, _, _, _, _, _)"}
{"ts":1782295008,"op":"assert","clause":"arch_decision('dec_debug_sidecar_owned', 'debug runtime placement', 'keep DAP adapters, debuggee lifecycle, session state, output buffering, and cleanup inside the debug sidecar', 'preserves the host/domain boundary and uses existing extension supervision for fault isolation instead of moving debugger runtime state into core_engine', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295008,"op":"retractall","clause":"arch_decision('dec_debug_opt_in_host_config', _, _, _, _, _, _, _)"}
{"ts":1782295008,"op":"assert","clause":"arch_decision('dec_debug_opt_in_host_config', 'debug capability gating', 'make debug tools available only when host-parsed debug config exists and the extension is not disabled', 'debugging executes user code and process control, so capability discovery must be explicit, auditable, and absent by default', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295008,"op":"retractall","clause":"arch_decision('dec_extension_init_config_payload', _, _, _, _, _)"}
{"ts":1782295008,"op":"assert","clause":"arch_decision('dec_extension_init_config_payload', 'extension initialization config', 'add optional per-extension initialize config payloads serialized by the host', 'host-parsed config can reach sidecars without sidecars rereading workspace config, while omitting the field keeps existing extension initialize messages backward compatible', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295008,"op":"retractall","clause":"arch_decision('dec_shared_sidecar_harness', _, _, _, _, _, _, _)"}
{"ts":1782295008,"op":"assert","clause":"arch_decision('dec_shared_sidecar_harness', 'sidecar JSON-RPC loop reuse', 'extract shared JSON-RPC helpers for responses, HostCall ids, and queued inbound frames', 'F004 would otherwise be a third hand-rolled sidecar loop, and consistent queued-frame behavior avoids known HostCall multiplexing deadlocks', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295009,"op":"retractall","clause":"arch_decision('dec_debug_runtime_error_payloads', _, _, _, _)"}
{"ts":1782295009,"op":"assert","clause":"arch_decision('dec_debug_runtime_error_payloads', 'debug tool error handling', 'return expected runtime failures as successful tool payloads with stable debug error codes', 'clients can branch on predictable session and runtime states while malformed parameters still use protocol-level invalid-params errors', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295009,"op":"retractall","clause":"arch_convention('conv_debug_config_shape', _, _, _, _, _, _)"}
{"ts":1782295009,"op":"assert","clause":"arch_convention('conv_debug_config_shape', 'config/debug', 'parse debug adapter settings as strict per-language [debug.<language>] entries with non-empty command, adapter_type, extension names without leading dots, and positive timeout and idle TTL seconds', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295009,"op":"retractall","clause":"arch_convention('conv_debug_no_workspace_writes', _, _, _)"}
{"ts":1782295009,"op":"assert","clause":"arch_convention('conv_debug_no_workspace_writes', 'extensions/debug', 'debug extensions must not declare workspace mutation capabilities', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295009,"op":"retractall","clause":"arch_convention('conv_debug_sessions_ephemeral', _, _, _, _, _)"}
{"ts":1782295009,"op":"assert","clause":"arch_convention('conv_debug_sessions_ephemeral', 'extensions/debug', 'debug session ids are ephemeral and must return session-not-found after termination, expiry, or extension restart', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295010,"op":"retractall","clause":"arch_convention('conv_debug_inspection_requires_stop', _, _, _, _, _)"}
{"ts":1782295010,"op":"assert","clause":"arch_convention('conv_debug_inspection_requires_stop', 'extensions/debug', 'stack, variables, and evaluate require a stopped session and return not-stopped while the debuggee is running', 'feature_f004_interactive_debug_session_sidecar')"}
{"ts":1782295010,"op":"retractall","clause":"arch_convention('conv_sidecar_hostcall_queue', _, _, _)"}
{"ts":1782295010,"op":"assert","clause":"arch_convention('conv_sidecar_hostcall_queue', 'extension sidecars', 'sidecars that await HostCall responses must queue inbound host requests and replay them instead of discarding non-matching frames', 'feature_f004_interactive_debug_session_sidecar')"}
8 changes: 8 additions & 0 deletions .zpm/kb/feedback/journal.wal
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,11 @@
{"ts":1782237919,"op":"assert","clause":"rule(f003_apply_edits_stale_cas_behavioral_test, test, 'Adapter acceptance tests for workspace/applyEdits stale CAS must invoke dispatch_host_call with an ApplyEditsHostPort fake returning DomainError::VersionConflict; source scans for error-code strings are not sufficient.', high, 'F003 review remediation 2026-06-23')"}
{"ts":1782242326,"op":"assert","clause":"rule(f003_lint_sidecar_rebuild_before_e2e, test, 'Rebuild the lint_extension sidecar binary before rerunning core_engine sidecar e2e tests after changing extensions/lint/src; cargo test -p core_engine alone can reuse the previous target/debug/lint_extension binary.', medium, 'F003 T016 review remediation 2026-06-23')"}
{"ts":1782245172,"op":"assert","clause":"rule(apply_edits_defer_extension_callbacks, architecture, 'When workspace/applyEdits mutates through EngineApplyEditsHost, collect ExtensionHostPort change notifications and fan them out only after releasing EngineState/workspace/index locks; delivering fileChanged inline can re-enter the same sidecar instance and deadlock the original HostCall.', high, 'lint applyEdits reentrant validation 2026-06-23')"}
{"ts":1782257883,"op":"assert","clause":"rule(sidecar_initialize_failure_cleanup, pitfall, 'If SidecarHostAdapter initialize fails after starting the reader thread, kill and wait the child and join the reader before returning the fault; dropping Child is not cleanup.', high, 'F004 review remediation 2026-06-24')"}
{"ts":1782262491,"op":"assert","clause":"rule(debug_sidecar_rebuild_before_e2e, test, 'Rebuild the debug_extension sidecar binary before rerunning core_engine debug sidecar e2e tests after changing extensions/debug/src; cargo test -p core_engine alone can reuse the previous target/debug/debug_extension binary.', medium, 'F004 T016 implementation 2026-06-24')"}
{"ts":1782262495,"op":"assert","clause":"trigger(debug_sidecar_rebuild_before_e2e, 'extensions/debug/src/*', file)"}
{"ts":1782262965,"op":"assert","clause":"rule(debug_init_present_payload_requires_languages, pitfall, 'DebugInitializeConfig::from_init_payload must accept only absent extension_config as Ok(None); a present payload without languages must return InvalidConfig, while {languages:{}} remains the explicit empty config.', high, 'F004 review remediation 2026-06-24')"}
{"ts":1782265212,"op":"assert","clause":"rule(debug_session_cleanup_registered_until_success, pitfall, 'Debug SessionManager terminate and disconnect must keep a session registered if adapter cleanup fails so callers can retry cleanup or shutdown_all can still reach the process tree.', high, 'F004 review remediation 2026-06-24')"}
{"ts":1782292946,"op":"assert","clause":"rule(debug_dap_set_breakpoints_group_by_source, pitfall, 'DAP setBreakpoints replaces the complete breakpoint set for a source; send one request per source containing all requested breakpoints, never one request per breakpoint.', high, 'F004 remediation 2026-06-24')"}
{"ts":1782292946,"op":"assert","clause":"rule(debug_dap_output_events_buffered, pitfall, 'Debug sidecars must drain buffered DAP output events after resume/step/pause waits and include them in DebugStop.output_since with stable per-session sequence numbers.', high, 'F004 remediation 2026-06-24')"}
{"ts":1782296413,"op":"assert","clause":"rule(debug_extension_install_target, pitfall, 'The install-extensions target must include debug in the default EXTENSIONS list so the lazy debug sidecar is installed into the extension scope; otherwise tower_debug_* calls fail spawning debug_extension.', high, 'MCP debug tool install verification 2026-06-24')"}
64 changes: 64 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ write is rejected with `PreconditionFailed` if the file changed since it was rea
| `tower_global_replace` | Replace every `target` with `replacement` across all indexed files; per-file CAS via `expected_versions` map (path → SHA-256) — conflicts land in `TxReport.errors`, non-conflicting files still commit. |
| `tower_create_directory` | Recursive `mkdir`. |
| `tower_delete_file` | Delete a file. |
| `tower_list_dir` | List indexed files and synthesized directories under a workspace-relative directory path. |
| `tower_find_file` | Match a substring/fuzzy `query` against file paths. |
| `tower_search_text` | Grep `pattern` across all indexed file contents. |
| `tower_reindex` | Full workspace re-scan; rebuild file + text-search indexes (reconciles external create/delete). |
Expand Down Expand Up @@ -110,6 +111,37 @@ Positions are **0-based** `line` + **UTF-16** `character` offset.
| `tower_lsp_hover` | Hover info for the symbol at a position. |
| `tower_lsp_diagnostics` | Errors/warnings for a file. |

### Debug — interactive sessions (`debug` extension, spec 33)

Opt-in; tools appear only when `[debug.<language>]` is configured and the `debug` extension is
enabled. A discovered `debug` extension takes priority; otherwise the bundled sidecar is used when
`debug_extension` is available next to `tower`.

| Tool | Purpose |
|------|---------|
| `tower_debug_launch` | Launch a configured Debug Adapter Protocol session; returns `session_id` and initial stop state. |
| `tower_debug_set_breakpoints` | Replace the breakpoint set for a source path within a session. |
| `tower_debug_continue` | Resume execution until stop, termination, or timeout. |
| `tower_debug_step` | Step execution for a session/thread until the adapter reports a stop. |
| `tower_debug_pause` | Pause a running session/thread. |
| `tower_debug_threads` | List threads for a debug session. |
| `tower_debug_stack` | Read stack frames for a thread. |
| `tower_debug_variables` | Read variables for a DAP variables reference. |
| `tower_debug_evaluate` | Evaluate an expression in a stack frame. |
| `tower_debug_terminate` | Terminate a debug session and clean up the adapter process. |
| `tower_debug_disconnect` | Disconnect from a debug session. |
| `tower_debug_sessions` | List active debug sessions and their last known state. |

### Linting (`lint` extension)

Runs configured linters from `.tower/config.toml`; unsupported paths return a successful unsupported
result rather than a transport error.

| Tool | Purpose |
|------|---------|
| `tower_lint_check` | Run configured linters for one workspace-relative path, or all supported indexed files when `path` is omitted. |
| `tower_lint_fix` | Apply structured lint fixes for one path or all supported indexed files; supports `dry_run` and `unsafe`. |

### Formatting

| Tool | Purpose |
Expand Down Expand Up @@ -252,6 +284,7 @@ Mutating tools accept an optional `expected_version` (hex SHA-256 from a prior `
| `tower_global_replace` | Replace every `target` with `replacement` across all indexed files; per-file CAS via `expected_versions` map (path → SHA-256) — conflicts land in `TxReport.errors`, non-conflicting files still commit. |
| `tower_create_directory` | Recursive `mkdir`. |
| `tower_delete_file` | Delete a file. |
| `tower_list_dir` | List indexed files and synthesized directories under a workspace-relative directory path. |
| `tower_find_file` | Match a substring/fuzzy `query` against file paths. |
| `tower_search_text` | Grep `pattern` across all indexed file contents. |
| `tower_reindex` | Full workspace re-scan; rebuild file + text-search indexes (reconciles external create/delete). |
Expand Down Expand Up @@ -281,6 +314,37 @@ Positions are **0-based** `line` + **UTF-16** `character` offset.
| `tower_lsp_hover` | Hover info for the symbol at a position. |
| `tower_lsp_diagnostics` | Errors/warnings for a file. |

### Debug — interactive sessions (`debug` extension)

Opt-in; tools appear only when `[debug.<language>]` is configured and the `debug` extension is
enabled. A discovered `debug` extension takes priority; otherwise the bundled sidecar is used when
`debug_extension` is available next to `tower`.

| Tool | Purpose |
|------|---------|
| `tower_debug_launch` | Launch a configured Debug Adapter Protocol session; returns `session_id` and initial stop state. |
| `tower_debug_set_breakpoints` | Replace the breakpoint set for a source path within a session. |
| `tower_debug_continue` | Resume execution until stop, termination, or timeout. |
| `tower_debug_step` | Step execution for a session/thread until the adapter reports a stop. |
| `tower_debug_pause` | Pause a running session/thread. |
| `tower_debug_threads` | List threads for a debug session. |
| `tower_debug_stack` | Read stack frames for a thread. |
| `tower_debug_variables` | Read variables for a DAP variables reference. |
| `tower_debug_evaluate` | Evaluate an expression in a stack frame. |
| `tower_debug_terminate` | Terminate a debug session and clean up the adapter process. |
| `tower_debug_disconnect` | Disconnect from a debug session. |
| `tower_debug_sessions` | List active debug sessions and their last known state. |

### Linting (`lint` extension)

Runs configured linters from `.tower/config.toml`; unsupported paths return a successful unsupported
result rather than a transport error.

| Tool | Purpose |
|------|---------|
| `tower_lint_check` | Run configured linters for one workspace-relative path, or all supported indexed files when `path` is omitted. |
| `tower_lint_fix` | Apply structured lint fixes for one path or all supported indexed files; supports `dry_run` and `unsafe`. |

### Formatting

| Tool | Purpose |
Expand Down
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
resolver = "2"
members = [
"crates/core_engine",
"crates/extension_sidecar_harness",
"crates/extension_protocol",
# Test-only sidecar extension binary for spec 23 integration tests.
"extensions/test_helper",
Expand All @@ -12,6 +13,8 @@ members = [
"extensions/fixtures/garbage_frames",
# Regression fixture: completes init then ignores `shutdown` (forces host kill escalation).
"extensions/fixtures/ignore_shutdown",
# F004 deterministic Debug Adapter Protocol fixture for debug e2e tests.
"extensions/fixtures/debug_adapter",
# Spec 26 native extensions (native binaries, no WASM).
"extensions/ast",
"extensions/hello",
Expand All @@ -21,10 +24,13 @@ members = [
"extensions/fmt",
# F002 lint sidecar extension.
"extensions/lint",
# F004 debug sidecar extension.
"extensions/debug",
]

default-members = [
"crates/core_engine",
"crates/extension_sidecar_harness",
"crates/extension_protocol",
# test_helper extension binary — compiled natively by the pre-test
# `cargo build --workspace --bins` step so spec 23 tests can spawn it.
Expand All @@ -37,6 +43,8 @@ default-members = [
"extensions/fixtures/garbage_frames",
# Regression fixture: completes init then ignores `shutdown` (bug #1, shutdown deadlock).
"extensions/fixtures/ignore_shutdown",
# F004 deterministic Debug Adapter Protocol fixture for debug e2e tests.
"extensions/fixtures/debug_adapter",
# Spec 26 native extensions — compiled natively (no WASM, no WASI SDK).
"extensions/ast",
"extensions/hello",
Expand All @@ -46,6 +54,8 @@ default-members = [
"extensions/fmt",
# F002 lint sidecar extension.
"extensions/lint",
# F004 debug sidecar extension.
"extensions/debug",
]

[workspace.package]
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ INSTALL_DIR ?= $(HOME)/.local/bin
# For the global XDG scope, pass
# EXT_DEST=$(HOME)/.local/share/tower/extensions
# EXT_PROFILE — release (default, deployable) or debug (fast, reuses dev build).
EXTENSIONS ?= ast lsp fmt lint
EXTENSIONS ?= ast lsp fmt lint debug
EXT_DEST ?= .tower/extensions
EXT_PROFILE ?= release

Expand Down
Loading
Loading