sigit-code 1.6.3__tar.gz → 1.6.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/AGENTS.md +36 -2
  2. sigit_code-1.6.5/.sigit/code-cloud-agent/config.toml +6 -0
  3. sigit_code-1.6.5/.sigit/code-review/config.toml +3 -0
  4. {sigit_code-1.6.3 → sigit_code-1.6.5}/AGENTS.md +36 -2
  5. {sigit_code-1.6.3 → sigit_code-1.6.5}/CHANGELOG.md +96 -0
  6. {sigit_code-1.6.3 → sigit_code-1.6.5}/CLAUDE.md +36 -2
  7. {sigit_code-1.6.3 → sigit_code-1.6.5}/Cargo.lock +176 -134
  8. {sigit_code-1.6.3 → sigit_code-1.6.5}/Cargo.toml +4 -4
  9. {sigit_code-1.6.3 → sigit_code-1.6.5}/PKG-INFO +1 -1
  10. {sigit_code-1.6.3 → sigit_code-1.6.5}/README.md +30 -0
  11. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/backend.rs +306 -67
  12. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/chat.rs +28 -7
  13. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/client_fs.rs +3 -2
  14. sigit_code-1.6.5/src/client_terminal.rs +468 -0
  15. sigit_code-1.6.5/src/harness_markup.rs +381 -0
  16. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/headless.rs +49 -22
  17. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/inline_tool_calls.rs +262 -1
  18. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/main.rs +782 -141
  19. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/provider.rs +18 -0
  20. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/tools.rs +539 -110
  21. sigit_code-1.6.5/tests/acp_audio.rs +310 -0
  22. sigit_code-1.6.5/tests/acp_client_terminal.rs +504 -0
  23. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_concurrent_sessions.rs +150 -3
  24. sigit_code-1.6.5/tests/acp_embedded_context.rs +274 -0
  25. sigit_code-1.6.5/tests/acp_harness_markup.rs +270 -0
  26. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_permissions.rs +154 -1
  27. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/agent-client-protocol/SKILL.md +0 -0
  28. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/ai-assisted-coding/SKILL.md +0 -0
  29. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/branding/SKILL.md +0 -0
  30. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/run-sigit/SKILL.md +0 -0
  31. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/run-sigit/driver.mjs +0 -0
  32. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/run-sigit/tui-smoke.sh +0 -0
  33. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/sigit-code-release/SKILL.md +0 -0
  34. {sigit_code-1.6.3 → sigit_code-1.6.5}/.agents/skills/tool-calling/SKILL.md +0 -0
  35. {sigit_code-1.6.3 → sigit_code-1.6.5}/.cargo/config.toml +0 -0
  36. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/agent-client-protocol/SKILL.md +0 -0
  37. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/ai-assisted-coding/SKILL.md +0 -0
  38. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/branding/SKILL.md +0 -0
  39. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/run-sigit/SKILL.md +0 -0
  40. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/run-sigit/driver.mjs +0 -0
  41. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/run-sigit/tui-smoke.sh +0 -0
  42. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/sigit-code-release/SKILL.md +0 -0
  43. {sigit_code-1.6.3 → sigit_code-1.6.5}/.claude/skills/tool-calling/SKILL.md +0 -0
  44. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/ci.yml +0 -0
  45. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-aur.yml +0 -0
  46. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-crates.yml +0 -0
  47. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-github.yml +0 -0
  48. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-homebrew.yml +0 -0
  49. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-npm.yml +0 -0
  50. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-nuget.yml +0 -0
  51. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-pypi.yml +0 -0
  52. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-scoop.yml +0 -0
  53. {sigit_code-1.6.3 → sigit_code-1.6.5}/.github/workflows/release-winget.yml +0 -0
  54. {sigit_code-1.6.3 → sigit_code-1.6.5}/.gitignore +0 -0
  55. {sigit_code-1.6.3 → sigit_code-1.6.5}/.nvmrc +0 -0
  56. {sigit_code-1.6.3 → sigit_code-1.6.5}/.sigit/factory/config.toml +0 -0
  57. {sigit_code-1.6.3 → sigit_code-1.6.5}/LICENSE +0 -0
  58. {sigit_code-1.6.3 → sigit_code-1.6.5}/docs/headless.md +0 -0
  59. {sigit_code-1.6.3 → sigit_code-1.6.5}/docs/hooks.md +0 -0
  60. {sigit_code-1.6.3 → sigit_code-1.6.5}/docs/mcp.md +0 -0
  61. {sigit_code-1.6.3 → sigit_code-1.6.5}/examples/settings-with-hooks.toml +0 -0
  62. {sigit_code-1.6.3 → sigit_code-1.6.5}/examples/skills/README.md +0 -0
  63. {sigit_code-1.6.3 → sigit_code-1.6.5}/examples/skills/commit-message/SKILL.md +0 -0
  64. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/README.md.tmpl +0 -0
  65. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/package-compat.json.tmpl +0 -0
  66. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/package-main.json.tmpl +0 -0
  67. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/package.json.tmpl +0 -0
  68. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/scripts/render-main-package.cjs +0 -0
  69. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/scripts/render-platform-package.cjs +0 -0
  70. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/sigit/.gitignore +0 -0
  71. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/sigit/README.md +0 -0
  72. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/sigit/package.json +0 -0
  73. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/sigit/src/index.ts +0 -0
  74. {sigit_code-1.6.3 → sigit_code-1.6.5}/npm/sigit/tsconfig.json +0 -0
  75. {sigit_code-1.6.3 → sigit_code-1.6.5}/nuget/.gitignore +0 -0
  76. {sigit_code-1.6.3 → sigit_code-1.6.5}/nuget/sigit/Program.cs +0 -0
  77. {sigit_code-1.6.3 → sigit_code-1.6.5}/nuget/sigit/README.md +0 -0
  78. {sigit_code-1.6.3 → sigit_code-1.6.5}/nuget/sigit/SiGit.Code.csproj +0 -0
  79. {sigit_code-1.6.3 → sigit_code-1.6.5}/packaging/aur/PKGBUILD.in +0 -0
  80. {sigit_code-1.6.3 → sigit_code-1.6.5}/packaging/nfpm.yaml +0 -0
  81. {sigit_code-1.6.3 → sigit_code-1.6.5}/packaging/windows/check-static-crt.ps1 +0 -0
  82. {sigit_code-1.6.3 → sigit_code-1.6.5}/packaging/winget/getSigit.siGitCode.installer.yaml.in +0 -0
  83. {sigit_code-1.6.3 → sigit_code-1.6.5}/packaging/winget/getSigit.siGitCode.locale.en-US.yaml.in +0 -0
  84. {sigit_code-1.6.3 → sigit_code-1.6.5}/packaging/winget/getSigit.siGitCode.yaml.in +0 -0
  85. {sigit_code-1.6.3 → sigit_code-1.6.5}/pypi/README.md +0 -0
  86. {sigit_code-1.6.3 → sigit_code-1.6.5}/pypi/pyproject.toml +0 -0
  87. {sigit_code-1.6.3 → sigit_code-1.6.5}/pyproject.toml +0 -0
  88. {sigit_code-1.6.3 → sigit_code-1.6.5}/rust-toolchain.toml +0 -0
  89. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/account.rs +0 -0
  90. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/browser_auth.rs +0 -0
  91. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/commands.rs +0 -0
  92. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/credentials.rs +0 -0
  93. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/frontmatter.rs +0 -0
  94. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/hooks.rs +0 -0
  95. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/instructions.rs +0 -0
  96. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/mcp.rs +0 -0
  97. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/models.rs +0 -0
  98. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/permissions.rs +0 -0
  99. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/session_store.rs +0 -0
  100. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/settings.rs +0 -0
  101. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/setup.rs +0 -0
  102. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/skills.rs +0 -0
  103. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/subagents.rs +0 -0
  104. {sigit_code-1.6.3 → sigit_code-1.6.5}/src/workspace.rs +0 -0
  105. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_client_fs.rs +0 -0
  106. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_endpoint_errors.rs +0 -0
  107. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_images.rs +0 -0
  108. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_logout.rs +0 -0
  109. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_multi_root.rs +0 -0
  110. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_session_list.rs +0 -0
  111. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_session_load.rs +0 -0
  112. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_stop_reasons.rs +0 -0
  113. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/acp_tool_stdin.rs +0 -0
  114. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/headless_mode.rs +0 -0
  115. {sigit_code-1.6.3 → sigit_code-1.6.5}/tests/version_flag.rs +0 -0
@@ -152,6 +152,13 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
152
152
  well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
153
153
  and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
154
154
  didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
155
+ What that scanner lets through then goes through `src/harness_markup.rs`, which removes
156
+ markup the model makes up in the harness's shape (issue #122): a `<system_warning>`-style
157
+ block (any `system_*`/`system-*` tag) is dropped whole, from the reply and the history, and
158
+ other underscore-named tags like `<Option_Picker>` lose the tags but keep their text. Code is
159
+ never touched, and an opening tag only counts at the start of a line, since prose writes
160
+ placeholders like `<repo_url>` the same way. It has to run after the inline-call scanner,
161
+ because `<tool_call>` matches its underscore rule.
155
162
  Image attachments: ACP fixes `promptCapabilities.image` for the whole connection, while the
156
163
  model can change on any turn, so the capability is always advertised and the decision is made
157
164
  per prompt. `InferenceBackend::accepts_images` answers for the active model (on-device: no;
@@ -163,6 +170,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
163
170
  when its model cannot read them, which is what makes a mid-thread switch to a text-only tier
164
171
  safe. Read history text through `backend::message_text`, never `content.as_str()`.
165
172
  `IMAGE_TIERS` mirrors onde-cloud's `IMAGE_CANDIDATES`; update both together.
173
+ Audio attachments take the same path (`promptCapabilities.audio`, `accepts_audio`,
174
+ `audio_for_turn`, `without_audio`), sent as OpenAI `input_audio` parts. No cloud tier
175
+ takes audio, because onde-cloud drops `input_audio` parts when it parses a request, so
176
+ `provider::model_accepts_audio` says no for every `onde-*` id and yes for a user's own
177
+ endpoint. If onde-cloud ever routes audio, give it a tier table like `IMAGE_TIERS`.
166
178
  - **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
167
179
  wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
168
180
  `~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
@@ -330,7 +342,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
330
342
  `execute_tool_impl` asks `route_for` before it dispatches `read_file`, `create_file`,
331
343
  `edit_file` or `multi_edit`. Each of those tools is split into a parse step and a pure
332
344
  render/apply step (`ReadFileCall`, `CreateFileCall`, `EditCall`) that the disk path and the
333
- client path share, so the model gets the same result text either way. The two capabilities are
345
+ client path share, so the model gets the same result text either way. The writing tools also
346
+ hand back the file before and after (`tools::FileChange`, via `execute_tool_with_change`), which
347
+ `handle_prompt` sends as ACP `diff` content ahead of the result text. A permission request for
348
+ one of them carries the same diff, worked out by `preview_file_change` without writing anything
349
+ and before the workspace is released, since a relative path resolves against the session's cwd. The two capabilities are
334
350
  independent: a client that only reads still gets its edits written to disk. The disk is the
335
351
  fallback throughout: nothing is registered in the TUI or headless modes, a path outside the
336
352
  session's roots is not routed, and a request the client fails or leaves unanswered for 30
@@ -338,6 +354,23 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
338
354
  inside a spawned prompt turn, never from `handle_initialize` itself (deadlock, same as
339
355
  permission requests). Existence checks and `create_file`'s parent directories still use the
340
356
  disk. `SIGIT_CLIENT_FS=off` turns the routing off. Covered by `tests/acp_client_fs.rs`.
357
+ - **`src/client_terminal.rs`** — `run_command` in the ACP client's terminal. A client that
358
+ advertises `terminal` in `initialize` runs a foreground command itself (`terminal/create`, with
359
+ the platform shell as `command` and the whole command line as one argument), and
360
+ `exec_run_command_via_client` embeds the terminal in the tool call as `terminal` content, so the
361
+ user watches the output live and can stop the command from the editor. The seam is
362
+ `client_fs`'s: `handle_initialize` registers `AcpClientTerminal`, and `execute_tool_impl` asks
363
+ `client_terminal_route` before the blocking path. Embedding needs the tool call's id, which is
364
+ why `execute_tool_with_change` takes one. What `run_command` promises stays put: the 120 s
365
+ timeout ends in `terminal/kill`, the output is capped, and `CommitWatch` still amends the
366
+ co-author trailer, checking HEAD on disk before and after. Background commands stay local
367
+ (`command_output` and `kill_command` read their pipes), and so does a command whose directory
368
+ is outside the session's roots, since nothing says the editor's machine can see it. A
369
+ `terminal/create` the client fails means nothing ran, so the command runs locally; a failure
370
+ after that is reported as the tool's error instead, because running it again could repeat its
371
+ effects. The finished card keeps the terminal and drops the result text, which still goes out
372
+ as `raw_output`. `SIGIT_CLIENT_TERMINAL=off` turns the routing off. Covered by
373
+ `tests/acp_client_terminal.rs`.
341
374
  - **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
342
375
  `tokio::select!` to multiplex terminal events with streaming tokens.
343
376
  - **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
@@ -407,7 +440,8 @@ verbosity with `RUST_LOG`.
407
440
  default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
408
441
  `SIGIT_MODEL`, `SIGIT_MAX_TOOL_ROUNDS` (1 to 500, default 24; the tool-round cap of a
409
442
  headless run or an ACP prompt turn), `SIGIT_MCP` (`off` disables MCP), `SIGIT_CLIENT_FS` (`off` keeps the file tools on disk even when the
410
- ACP client offers `fs/read_text_file` / `fs/write_text_file`), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
443
+ ACP client offers `fs/read_text_file` / `fs/write_text_file`), `SIGIT_CLIENT_TERMINAL` (`off` runs
444
+ `run_command` locally even when the ACP client offers a terminal), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
411
445
  smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
412
446
  server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
413
447
  mutating tools; the escape hatch for clients without permission-request support),
@@ -0,0 +1,6 @@
1
+ [pull_request]
2
+ base = "development"
3
+ branch_prefix = "feature"
4
+
5
+ [agent]
6
+ max_tool_rounds = 60
@@ -0,0 +1,3 @@
1
+ [review.reviewer_skill]
2
+ name = "sigit-code-review-inner-loop"
3
+ version = "1.0.0"
@@ -152,6 +152,13 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
152
152
  well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
153
153
  and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
154
154
  didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
155
+ What that scanner lets through then goes through `src/harness_markup.rs`, which removes
156
+ markup the model makes up in the harness's shape (issue #122): a `<system_warning>`-style
157
+ block (any `system_*`/`system-*` tag) is dropped whole, from the reply and the history, and
158
+ other underscore-named tags like `<Option_Picker>` lose the tags but keep their text. Code is
159
+ never touched, and an opening tag only counts at the start of a line, since prose writes
160
+ placeholders like `<repo_url>` the same way. It has to run after the inline-call scanner,
161
+ because `<tool_call>` matches its underscore rule.
155
162
  Image attachments: ACP fixes `promptCapabilities.image` for the whole connection, while the
156
163
  model can change on any turn, so the capability is always advertised and the decision is made
157
164
  per prompt. `InferenceBackend::accepts_images` answers for the active model (on-device: no;
@@ -163,6 +170,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
163
170
  when its model cannot read them, which is what makes a mid-thread switch to a text-only tier
164
171
  safe. Read history text through `backend::message_text`, never `content.as_str()`.
165
172
  `IMAGE_TIERS` mirrors onde-cloud's `IMAGE_CANDIDATES`; update both together.
173
+ Audio attachments take the same path (`promptCapabilities.audio`, `accepts_audio`,
174
+ `audio_for_turn`, `without_audio`), sent as OpenAI `input_audio` parts. No cloud tier
175
+ takes audio, because onde-cloud drops `input_audio` parts when it parses a request, so
176
+ `provider::model_accepts_audio` says no for every `onde-*` id and yes for a user's own
177
+ endpoint. If onde-cloud ever routes audio, give it a tier table like `IMAGE_TIERS`.
166
178
  - **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
167
179
  wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
168
180
  `~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
@@ -330,7 +342,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
330
342
  `execute_tool_impl` asks `route_for` before it dispatches `read_file`, `create_file`,
331
343
  `edit_file` or `multi_edit`. Each of those tools is split into a parse step and a pure
332
344
  render/apply step (`ReadFileCall`, `CreateFileCall`, `EditCall`) that the disk path and the
333
- client path share, so the model gets the same result text either way. The two capabilities are
345
+ client path share, so the model gets the same result text either way. The writing tools also
346
+ hand back the file before and after (`tools::FileChange`, via `execute_tool_with_change`), which
347
+ `handle_prompt` sends as ACP `diff` content ahead of the result text. A permission request for
348
+ one of them carries the same diff, worked out by `preview_file_change` without writing anything
349
+ and before the workspace is released, since a relative path resolves against the session's cwd. The two capabilities are
334
350
  independent: a client that only reads still gets its edits written to disk. The disk is the
335
351
  fallback throughout: nothing is registered in the TUI or headless modes, a path outside the
336
352
  session's roots is not routed, and a request the client fails or leaves unanswered for 30
@@ -338,6 +354,23 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
338
354
  inside a spawned prompt turn, never from `handle_initialize` itself (deadlock, same as
339
355
  permission requests). Existence checks and `create_file`'s parent directories still use the
340
356
  disk. `SIGIT_CLIENT_FS=off` turns the routing off. Covered by `tests/acp_client_fs.rs`.
357
+ - **`src/client_terminal.rs`** — `run_command` in the ACP client's terminal. A client that
358
+ advertises `terminal` in `initialize` runs a foreground command itself (`terminal/create`, with
359
+ the platform shell as `command` and the whole command line as one argument), and
360
+ `exec_run_command_via_client` embeds the terminal in the tool call as `terminal` content, so the
361
+ user watches the output live and can stop the command from the editor. The seam is
362
+ `client_fs`'s: `handle_initialize` registers `AcpClientTerminal`, and `execute_tool_impl` asks
363
+ `client_terminal_route` before the blocking path. Embedding needs the tool call's id, which is
364
+ why `execute_tool_with_change` takes one. What `run_command` promises stays put: the 120 s
365
+ timeout ends in `terminal/kill`, the output is capped, and `CommitWatch` still amends the
366
+ co-author trailer, checking HEAD on disk before and after. Background commands stay local
367
+ (`command_output` and `kill_command` read their pipes), and so does a command whose directory
368
+ is outside the session's roots, since nothing says the editor's machine can see it. A
369
+ `terminal/create` the client fails means nothing ran, so the command runs locally; a failure
370
+ after that is reported as the tool's error instead, because running it again could repeat its
371
+ effects. The finished card keeps the terminal and drops the result text, which still goes out
372
+ as `raw_output`. `SIGIT_CLIENT_TERMINAL=off` turns the routing off. Covered by
373
+ `tests/acp_client_terminal.rs`.
341
374
  - **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
342
375
  `tokio::select!` to multiplex terminal events with streaming tokens.
343
376
  - **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
@@ -407,7 +440,8 @@ verbosity with `RUST_LOG`.
407
440
  default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
408
441
  `SIGIT_MODEL`, `SIGIT_MAX_TOOL_ROUNDS` (1 to 500, default 24; the tool-round cap of a
409
442
  headless run or an ACP prompt turn), `SIGIT_MCP` (`off` disables MCP), `SIGIT_CLIENT_FS` (`off` keeps the file tools on disk even when the
410
- ACP client offers `fs/read_text_file` / `fs/write_text_file`), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
443
+ ACP client offers `fs/read_text_file` / `fs/write_text_file`), `SIGIT_CLIENT_TERMINAL` (`off` runs
444
+ `run_command` locally even when the ACP client offers a terminal), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
411
445
  smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
412
446
  server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
413
447
  mutating tools; the escape hatch for clients without permission-request support),
@@ -1,5 +1,101 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.5
4
+
5
+ ### Added
6
+
7
+ - **An `@file` mention can carry unsaved edits.** siGit Code now advertises
8
+ `promptCapabilities.embeddedContext`, so a client can put a resource's
9
+ contents in the prompt instead of sending a link to it. Before, a client
10
+ that follows the spec only sent `resource_link`, and siGit Code read the
11
+ file from disk, missing whatever the user had not saved yet (#141).
12
+ - **A prompt can carry audio.** siGit Code now advertises
13
+ `promptCapabilities.audio` and sends an attached clip to the model as an
14
+ OpenAI `input_audio` part. It works the way image attachments do: a model on
15
+ an endpoint you configure yourself gets the clip and decides for itself,
16
+ while siGit Code Cloud tiers and on-device models, none of which take audio
17
+ today, get a note in its place and the editor says the clip was left out
18
+ (#143).
19
+ - **The README says what telemetry is sent.** A new Telemetry section covers
20
+ the model-timing events Onde Inference can report for on-device models,
21
+ what they leave out, and how to turn them off with `ONDE_DISABLE_PULSE=1`.
22
+
23
+ ### Changed
24
+
25
+ - **A turn that cannot get its session back stops.** A turn on an HTTP backend
26
+ gives up the process-wide working directory while it waits and reinstalls
27
+ its session before a tool runs. If the reinstall failed, the turn logged a
28
+ warning and carried on in whichever directory was current. Nothing makes it
29
+ fail today, since a close waits for the turn, but the turn now ends as
30
+ cancelled instead of depending on that.
31
+ - **Dependencies match the rest of the Onde stack.** Onde 1.2.2 to 1.3.1,
32
+ reqwest 0.12 to 0.13 and ratatui 0.29 to 0.30, the versions Ed, OndeCode and
33
+ SplitFire Agent use. ratatui is built with only its crossterm backend, which
34
+ drops the second copy of crossterm (0.28) from the build.
35
+
36
+ ### Fixed
37
+
38
+ - **Tags a model makes up no longer show in the reply.** After a long run of
39
+ tool rounds, a model could start writing markup that looked like it came
40
+ from siGit Code: a `<system_warning>` block telling the user the previous
41
+ turn was injected and should be ignored, or a question wrapped in
42
+ `<Option_Picker>`. Neither tag means anything to siGit Code or the editor,
43
+ so both rendered as raw text. A `system_*` block is now dropped from the
44
+ reply and from the history, and other made-up tags are removed while the
45
+ text inside them stays. Code blocks are left alone. The system prompt also
46
+ tells the model to write plain Markdown and to list choices as plain text
47
+ (#122).
48
+
49
+ - **Closing a thread that is waiting at a permission prompt no longer hangs.**
50
+ `session/close` cancels the session's running turn and waits for it to end,
51
+ but a turn stopped at a permission prompt only went on when the client
52
+ answered the request. A client that closed the thread without answering
53
+ left the close, and every later request for that thread, waiting for good.
54
+ The same held for `session/cancel` with a client that did not send the
55
+ cancelled outcome the protocol asks for. The permission wait now ends on
56
+ the cancellation as well, and an approval that arrives after the turn was
57
+ cancelled runs nothing.
58
+
59
+ - **A closed thread no longer leaves its request lock behind.** The process
60
+ kept one lock per session id for as long as it ran, for closed threads and
61
+ for ids no session ever had. The entry now goes with the last request that
62
+ used it.
63
+
64
+ - **A tool call that did not run no longer shows as completed.** When policy
65
+ or plan mode denied a call, when the user picked Deny at the permission
66
+ prompt, or when the repeat guard skipped a call the model made three times,
67
+ the editor's card still ended `completed`. Those cards now end `failed`, the
68
+ same way a call cancelled at the prompt already did. A call denied at the
69
+ prompt also gets its own title back instead of keeping the permission
70
+ request's (#139).
71
+
72
+ - **On-device inference no longer panics on some non-English text.** siGit Code
73
+ now builds on Onde 1.3.1, which fixes a panic when a message longer than 100
74
+ bytes had a multi-byte character (an accented letter, CJK, or an emoji) at
75
+ byte 100. Onde 1.3 also reports Pulse events for streaming inference, which
76
+ is the path on-device turns take, so those turns are now reported alongside
77
+ model loads. `ONDE_DISABLE_PULSE=1` turns Pulse off.
78
+
79
+ ## 1.6.4
80
+
81
+ ### Added
82
+
83
+ - **DeepSeek DSML tool calls written into the reply text are recovered.** A
84
+ DeepSeek-family endpoint can render a tool call as literal
85
+ `<|DSML|tool_calls>` text instead of the structured `tool_calls` field,
86
+ which streamed the tag into the editor and ended the turn with nothing run.
87
+ The inline tool-call scanner that already recovered the GLM XML and Kimi K3
88
+ shapes now recovers the DSML shape too, including a marker split across
89
+ stream chunks. A block that fails to parse is still kept out of the reply
90
+ and the history, and the model is told the call did not run (#181).
91
+
92
+ ### Fixed
93
+
94
+ - **The round-cap stop message no longer carries a stray run of spaces.**
95
+ When the tool-round cap ended a turn, the closing message could collapse a
96
+ space run into the wrong spot, which the editor then rendered verbatim
97
+ (#177).
98
+
3
99
  ## 1.6.3
4
100
 
5
101
  ### Added
@@ -152,6 +152,13 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
152
152
  well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
153
153
  and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
154
154
  didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
155
+ What that scanner lets through then goes through `src/harness_markup.rs`, which removes
156
+ markup the model makes up in the harness's shape (issue #122): a `<system_warning>`-style
157
+ block (any `system_*`/`system-*` tag) is dropped whole, from the reply and the history, and
158
+ other underscore-named tags like `<Option_Picker>` lose the tags but keep their text. Code is
159
+ never touched, and an opening tag only counts at the start of a line, since prose writes
160
+ placeholders like `<repo_url>` the same way. It has to run after the inline-call scanner,
161
+ because `<tool_call>` matches its underscore rule.
155
162
  Image attachments: ACP fixes `promptCapabilities.image` for the whole connection, while the
156
163
  model can change on any turn, so the capability is always advertised and the decision is made
157
164
  per prompt. `InferenceBackend::accepts_images` answers for the active model (on-device: no;
@@ -163,6 +170,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
163
170
  when its model cannot read them, which is what makes a mid-thread switch to a text-only tier
164
171
  safe. Read history text through `backend::message_text`, never `content.as_str()`.
165
172
  `IMAGE_TIERS` mirrors onde-cloud's `IMAGE_CANDIDATES`; update both together.
173
+ Audio attachments take the same path (`promptCapabilities.audio`, `accepts_audio`,
174
+ `audio_for_turn`, `without_audio`), sent as OpenAI `input_audio` parts. No cloud tier
175
+ takes audio, because onde-cloud drops `input_audio` parts when it parses a request, so
176
+ `provider::model_accepts_audio` says no for every `onde-*` id and yes for a user's own
177
+ endpoint. If onde-cloud ever routes audio, give it a tier table like `IMAGE_TIERS`.
166
178
  - **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
167
179
  wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
168
180
  `~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
@@ -330,7 +342,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
330
342
  `execute_tool_impl` asks `route_for` before it dispatches `read_file`, `create_file`,
331
343
  `edit_file` or `multi_edit`. Each of those tools is split into a parse step and a pure
332
344
  render/apply step (`ReadFileCall`, `CreateFileCall`, `EditCall`) that the disk path and the
333
- client path share, so the model gets the same result text either way. The two capabilities are
345
+ client path share, so the model gets the same result text either way. The writing tools also
346
+ hand back the file before and after (`tools::FileChange`, via `execute_tool_with_change`), which
347
+ `handle_prompt` sends as ACP `diff` content ahead of the result text. A permission request for
348
+ one of them carries the same diff, worked out by `preview_file_change` without writing anything
349
+ and before the workspace is released, since a relative path resolves against the session's cwd. The two capabilities are
334
350
  independent: a client that only reads still gets its edits written to disk. The disk is the
335
351
  fallback throughout: nothing is registered in the TUI or headless modes, a path outside the
336
352
  session's roots is not routed, and a request the client fails or leaves unanswered for 30
@@ -338,6 +354,23 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
338
354
  inside a spawned prompt turn, never from `handle_initialize` itself (deadlock, same as
339
355
  permission requests). Existence checks and `create_file`'s parent directories still use the
340
356
  disk. `SIGIT_CLIENT_FS=off` turns the routing off. Covered by `tests/acp_client_fs.rs`.
357
+ - **`src/client_terminal.rs`** — `run_command` in the ACP client's terminal. A client that
358
+ advertises `terminal` in `initialize` runs a foreground command itself (`terminal/create`, with
359
+ the platform shell as `command` and the whole command line as one argument), and
360
+ `exec_run_command_via_client` embeds the terminal in the tool call as `terminal` content, so the
361
+ user watches the output live and can stop the command from the editor. The seam is
362
+ `client_fs`'s: `handle_initialize` registers `AcpClientTerminal`, and `execute_tool_impl` asks
363
+ `client_terminal_route` before the blocking path. Embedding needs the tool call's id, which is
364
+ why `execute_tool_with_change` takes one. What `run_command` promises stays put: the 120 s
365
+ timeout ends in `terminal/kill`, the output is capped, and `CommitWatch` still amends the
366
+ co-author trailer, checking HEAD on disk before and after. Background commands stay local
367
+ (`command_output` and `kill_command` read their pipes), and so does a command whose directory
368
+ is outside the session's roots, since nothing says the editor's machine can see it. A
369
+ `terminal/create` the client fails means nothing ran, so the command runs locally; a failure
370
+ after that is reported as the tool's error instead, because running it again could repeat its
371
+ effects. The finished card keeps the terminal and drops the result text, which still goes out
372
+ as `raw_output`. `SIGIT_CLIENT_TERMINAL=off` turns the routing off. Covered by
373
+ `tests/acp_client_terminal.rs`.
341
374
  - **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
342
375
  `tokio::select!` to multiplex terminal events with streaming tokens.
343
376
  - **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
@@ -407,7 +440,8 @@ verbosity with `RUST_LOG`.
407
440
  default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
408
441
  `SIGIT_MODEL`, `SIGIT_MAX_TOOL_ROUNDS` (1 to 500, default 24; the tool-round cap of a
409
442
  headless run or an ACP prompt turn), `SIGIT_MCP` (`off` disables MCP), `SIGIT_CLIENT_FS` (`off` keeps the file tools on disk even when the
410
- ACP client offers `fs/read_text_file` / `fs/write_text_file`), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
443
+ ACP client offers `fs/read_text_file` / `fs/write_text_file`), `SIGIT_CLIENT_TERMINAL` (`off` runs
444
+ `run_command` locally even when the ACP client offers a terminal), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
411
445
  smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
412
446
  server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
413
447
  mutating tools; the escape hatch for clients without permission-request support),