sigit-code 1.5.13__tar.gz → 1.6.1__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.
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/AGENTS.md +55 -10
- {sigit_code-1.5.13/.claude → sigit_code-1.6.1/.agents}/skills/agent-client-protocol/SKILL.md +17 -12
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/skills/sigit-code-release/SKILL.md +2 -0
- {sigit_code-1.5.13/.agents → sigit_code-1.6.1/.claude}/skills/agent-client-protocol/SKILL.md +17 -12
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.claude/skills/sigit-code-release/SKILL.md +2 -0
- sigit_code-1.6.1/.sigit/factory/config.toml +62 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/AGENTS.md +55 -10
- {sigit_code-1.5.13 → sigit_code-1.6.1}/CHANGELOG.md +111 -1
- {sigit_code-1.5.13 → sigit_code-1.6.1}/CLAUDE.md +55 -10
- {sigit_code-1.5.13 → sigit_code-1.6.1}/Cargo.lock +8 -8
- {sigit_code-1.5.13 → sigit_code-1.6.1}/Cargo.toml +2 -2
- {sigit_code-1.5.13 → sigit_code-1.6.1}/PKG-INFO +1 -1
- {sigit_code-1.5.13 → sigit_code-1.6.1}/docs/headless.md +5 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/backend.rs +1088 -91
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/headless.rs +155 -5
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/main.rs +621 -112
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/mcp.rs +239 -69
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/provider.rs +56 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/tools.rs +176 -7
- {sigit_code-1.5.13 → sigit_code-1.6.1}/tests/acp_endpoint_errors.rs +14 -11
- sigit_code-1.6.1/tests/acp_images.rs +318 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/tests/acp_permissions.rs +93 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/tests/acp_session_load.rs +83 -0
- sigit_code-1.6.1/tests/acp_stop_reasons.rs +439 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/tests/headless_mode.rs +109 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.agents/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.cargo/config.toml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.claude/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.claude/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.claude/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.claude/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.claude/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.claude/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/ci.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-aur.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-crates.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-github.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-homebrew.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-npm.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-nuget.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-pypi.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-scoop.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.github/workflows/release-winget.yml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.gitignore +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/.nvmrc +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/LICENSE +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/README.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/docs/hooks.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/docs/mcp.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/examples/settings-with-hooks.toml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/examples/skills/README.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/examples/skills/commit-message/SKILL.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/README.md.tmpl +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/package-compat.json.tmpl +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/package-main.json.tmpl +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/package.json.tmpl +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/scripts/render-main-package.cjs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/scripts/render-platform-package.cjs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/sigit/.gitignore +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/sigit/README.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/sigit/package.json +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/sigit/src/index.ts +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/npm/sigit/tsconfig.json +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/nuget/.gitignore +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/nuget/sigit/Program.cs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/nuget/sigit/README.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/nuget/sigit/SiGit.Code.csproj +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/packaging/aur/PKGBUILD.in +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/packaging/nfpm.yaml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/packaging/windows/check-static-crt.ps1 +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/packaging/winget/getSigit.siGitCode.installer.yaml.in +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/packaging/winget/getSigit.siGitCode.locale.en-US.yaml.in +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/packaging/winget/getSigit.siGitCode.yaml.in +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/pypi/README.md +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/pypi/pyproject.toml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/pyproject.toml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/rust-toolchain.toml +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/account.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/browser_auth.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/chat.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/commands.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/credentials.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/frontmatter.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/hooks.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/inline_tool_calls.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/instructions.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/models.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/permissions.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/session_store.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/settings.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/setup.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/skills.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/subagents.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/src/workspace.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/tests/acp_multi_root.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/tests/acp_session_list.rs +0 -0
- {sigit_code-1.5.13 → sigit_code-1.6.1}/tests/acp_tool_stdin.rs +0 -0
|
@@ -127,10 +127,31 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
127
127
|
endpoint can also fail *after* the response is open, reporting it as a `data:` frame holding
|
|
128
128
|
the same envelope; that frame has no `choices`, so `consume_stream` has to check for it
|
|
129
129
|
explicitly or it parses as an empty chunk and the turn ends looking like an empty answer.
|
|
130
|
+
`TurnResult::finish` carries the endpoint's `finish_reason` up to the loop, and
|
|
131
|
+
`stop_reason_for` in `main.rs` turns it into the ACP stop reason: the tool-round cap is
|
|
132
|
+
`max_turn_requests`, `length` is `max_tokens`, `content_filter` is `refusal`. ACP defines a
|
|
133
|
+
refusal as a turn the next prompt will not include, so `handle_prompt` restores the history
|
|
134
|
+
it snapshotted before the turn instead of only relabelling the response.
|
|
135
|
+
The round that reaches the cap (24, or `SIGIT_MAX_TOOL_ROUNDS`) is followed by one forced
|
|
136
|
+
text reply with no tools. The model cannot see that the tools are gone, so
|
|
137
|
+
`round_cap_note` is appended to that round's last tool result, and the turn always closes
|
|
138
|
+
with `round_cap_stop_message`. Without both, the thread stops on the model announcing a
|
|
139
|
+
step that never runs (issue #120).
|
|
130
140
|
Some models write tool calls into content as text; `src/inline_tool_calls.rs` recovers the
|
|
131
141
|
well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
|
|
132
142
|
and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
|
|
133
143
|
didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
|
|
144
|
+
Image attachments: ACP fixes `promptCapabilities.image` for the whole connection, while the
|
|
145
|
+
model can change on any turn, so the capability is always advertised and the decision is made
|
|
146
|
+
per prompt. `InferenceBackend::accepts_images` answers for the active model (on-device: no;
|
|
147
|
+
remote: `provider::model_accepts_images`, which reads the hard-coded `IMAGE_TIERS` for
|
|
148
|
+
`onde-*` ids and says yes for a user's own endpoint). `images_for_turn` in `main.rs` either
|
|
149
|
+
passes the images to `send_message_with_images` or drops them with a note to the user and a
|
|
150
|
+
bracketed note to the model. A message with images is stored in history as OpenAI content
|
|
151
|
+
parts and stays that way; `OpenAiBackend` strips the images per request (`without_images`)
|
|
152
|
+
when its model cannot read them, which is what makes a mid-thread switch to a text-only tier
|
|
153
|
+
safe. Read history text through `backend::message_text`, never `content.as_str()`.
|
|
154
|
+
`IMAGE_TIERS` mirrors onde-cloud's `IMAGE_CANDIDATES`; update both together.
|
|
134
155
|
- **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
|
|
135
156
|
wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
|
|
136
157
|
`~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
|
|
@@ -225,6 +246,17 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
225
246
|
it's a remote server, the registry's URL-match rule forces a domain namespace (`si.sigit` ↔
|
|
226
247
|
`sigit.si`) verified by a DNS TXT record, not the GitHub-OIDC scheme `smbcloud-cli` uses for its
|
|
227
248
|
package listing.
|
|
249
|
+
Separate from all of the above are the servers an ACP client passes in `mcpServers` on
|
|
250
|
+
`session/new`, `session/load` and `session/fork`. ACP requires agents to connect to the stdio
|
|
251
|
+
ones, and they belong to the session that named them, so they cannot live in the startup
|
|
252
|
+
global: `connect_session_servers` returns a `SessionServers` that `main.rs` keeps on
|
|
253
|
+
`SessionState` and installs with `set_session_servers` whenever a session becomes live, the
|
|
254
|
+
same way it swaps the roots. `tool_specs`, `call_tool` and `/mcp` read the startup servers and
|
|
255
|
+
then the live session's. A client-supplied server whose name is already taken by a startup
|
|
256
|
+
server is not connected, since both would claim the same `mcp__<server>__` prefix. Streamable
|
|
257
|
+
HTTP entries are connected too, with the URL and headers the client sent, because
|
|
258
|
+
`handle_initialize` advertises `mcpCapabilities.http`. SSE is not advertised (the MCP spec
|
|
259
|
+
deprecated it), so a conforming client never sends one and a stray entry is skipped.
|
|
228
260
|
- **`src/permissions.rs`** — tool permission policy. Every tool call passes through
|
|
229
261
|
`decision_for` before executing: read-only tools always run; mutating tools (and all
|
|
230
262
|
`mcp__*`/unknown tools) are governed by, in order: per-session plan mode (`/plan` — deny all
|
|
@@ -232,7 +264,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
232
264
|
overrides and the default mode from `[permissions]` in `settings.toml` (`allow`/`ask`/`deny`,
|
|
233
265
|
default `ask`; `SIGIT_PERMISSIONS` env overrides the default). On `ask`, the ACP path sends
|
|
234
266
|
`session/request_permission` (allow once / allow for session / deny) and the TUI pauses the
|
|
235
|
-
inference task on a y/a/n prompt.
|
|
267
|
+
inference task on a y/a/n prompt. On the ACP path the decision is taken *before* the call is
|
|
268
|
+
announced, because it sets the announced status: a call that will ask starts `pending`, the
|
|
269
|
+
permission request carries that call's own id, and an `in_progress` update follows approval.
|
|
270
|
+
That update also puts the card's title back, since the permission request overwrites it
|
|
271
|
+
with the full arguments. Note: ACP turn-affecting handlers run in `cx.spawn`ed tasks
|
|
236
272
|
serialized by `SiGitAgent::turn_lock` so the dispatch loop can route the client's permission
|
|
237
273
|
answer mid-turn — don't move them back inline, and don't await client requests from inline
|
|
238
274
|
handlers (deadlock).
|
|
@@ -261,7 +297,8 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
261
297
|
read another session's roots from the global. Project-local
|
|
262
298
|
discovery reads it: skills, slash commands, subagent types, and instruction files all scan
|
|
263
299
|
every root. MCP is deliberately not on that list — `mcp::init` runs once at startup, before
|
|
264
|
-
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell.
|
|
300
|
+
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell. (The servers a
|
|
301
|
+
client names in `mcpServers` are a different thing and are per session; see `src/mcp.rs`.)
|
|
265
302
|
- **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
|
|
266
303
|
`tokio::select!` to multiplex terminal events with streaming tokens.
|
|
267
304
|
- **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
|
|
@@ -325,7 +362,8 @@ verbosity with `RUST_LOG`.
|
|
|
325
362
|
|
|
326
363
|
`OPENAI_BASE_URL` / `OPENAI_API_KEY` (provider override), `SIGIT_API_URL` (account API base,
|
|
327
364
|
default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
|
|
328
|
-
`SIGIT_MODEL`, `
|
|
365
|
+
`SIGIT_MODEL`, `SIGIT_MAX_TOOL_ROUNDS` (1 to 500, default 24; the tool-round cap of a
|
|
366
|
+
headless run or an ACP prompt turn), `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
|
|
329
367
|
smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
|
|
330
368
|
server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
|
|
331
369
|
mutating tools; the escape hatch for clients without permission-request support),
|
|
@@ -376,13 +414,20 @@ Three of these need credentials or a one-time manual step before they work:
|
|
|
376
414
|
|
|
377
415
|
- Scoop needs a `getsigit/scoop-bucket` repo and a `SCOOP_BUCKET_TOKEN` secret, mirroring the
|
|
378
416
|
Homebrew tap setup.
|
|
379
|
-
- winget needs a `WINGET_TOKEN` (PAT with `public_repo`) so `wingetcreate` can fork
|
|
380
|
-
`microsoft/winget-pkgs
|
|
381
|
-
which wingetcreate warns can leak the
|
|
382
|
-
|
|
383
|
-
`manifests/g/getSigit/siGitCode` path
|
|
384
|
-
`packaging/winget/*.yaml.in` and running
|
|
385
|
-
fallback runs once, then every later
|
|
417
|
+
- winget needs a `WINGET_TOKEN` (PAT with `public_repo` scope) so `wingetcreate` can fork
|
|
418
|
+
`microsoft/winget-pkgs` and open the manifest PR. It is passed as
|
|
419
|
+
`WINGET_CREATE_GITHUB_TOKEN` rather than `--token`, which wingetcreate warns can leak the
|
|
420
|
+
token into logs. `wingetcreate update` only works on a package that already exists in
|
|
421
|
+
`microsoft/winget-pkgs`, so the workflow checks the `manifests/g/getSigit/siGitCode` path
|
|
422
|
+
first and falls back to rendering `packaging/winget/*.yaml.in` and running
|
|
423
|
+
`wingetcreate submit` for a first submission. That fallback runs once, then every later
|
|
424
|
+
release takes the `update` path. Two non-obvious things in the update path: the `--urls`
|
|
425
|
+
arguments carry a trailing `|x64` / `|arm64` suffix that tells wingetcreate which installer
|
|
426
|
+
entry each URL replaces — without it, wingetcreate guesses from the file name, and
|
|
427
|
+
"sigit-win-amd64.exe" is not a spelling it recognises; and the first-submission render
|
|
428
|
+
uppercases the SHA256 (`tr '[:lower:]' '[:upper:]'`) to match the community validation
|
|
429
|
+
pipeline, which writes 64-hex checksums uppercase. The update path also passes
|
|
430
|
+
`--release-date`, `--release-notes-url`, `--submit`, and `--no-open` explicitly.
|
|
386
431
|
- The AUR needs `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_PRIVATE_KEY`. It publishes `sigit-bin`
|
|
387
432
|
(a prebuilt binary) so Arch users are not compiling the on-device inference stack to install a
|
|
388
433
|
CLI.
|
{sigit_code-1.5.13/.claude → sigit_code-1.6.1/.agents}/skills/agent-client-protocol/SKILL.md
RENAMED
|
@@ -11,7 +11,7 @@ ACP is a JSON-RPC 2.0 protocol over **stdio** for integrating AI coding agents
|
|
|
11
11
|
with editors (Zed, JetBrains, Neovim, etc.). The agent runs as a subprocess;
|
|
12
12
|
the editor is the client. Communication is newline-delimited JSON on stdin/stdout.
|
|
13
13
|
|
|
14
|
-
Crate: `agent-client-protocol = "
|
|
14
|
+
Crate: `agent-client-protocol = "2.2"` (siGit pins 2.2.0 in `Cargo.lock`)
|
|
15
15
|
Docs: https://docs.rs/agent-client-protocol
|
|
16
16
|
Spec: https://agentclientprotocol.com
|
|
17
17
|
|
|
@@ -21,6 +21,11 @@ Spec: https://agentclientprotocol.com
|
|
|
21
21
|
> handler receives a `ConnectionTo<Client>` (`cx`) you use to send notifications
|
|
22
22
|
> and spawn tasks — so the old mpsc "circular dependency" pattern is gone.
|
|
23
23
|
|
|
24
|
+
> **SDK 2.x is not protocol v2.** The 2.x crate still speaks ACP protocol v1 by
|
|
25
|
+
> default, which is what siGit and Zed use (`ProtocolVersion::V1`). The draft v2
|
|
26
|
+
> protocol (`Agent.v2()`, `V2ConnectionTo`) sits behind the `unstable_protocol_v2`
|
|
27
|
+
> feature and siGit does not enable it.
|
|
28
|
+
|
|
24
29
|
siGit's entire ACP server lives in `src/main.rs` (`run_acp_server`, the
|
|
25
30
|
`SiGitAgent` struct, and its `handle_*` methods). Read it alongside this skill.
|
|
26
31
|
|
|
@@ -30,10 +35,8 @@ siGit's entire ACP server lives in `src/main.rs` (`run_acp_server`, the
|
|
|
30
35
|
|
|
31
36
|
```toml
|
|
32
37
|
[dependencies]
|
|
33
|
-
agent-client-protocol = { version = "
|
|
34
|
-
"unstable_session_fork",
|
|
35
|
-
"unstable_session_additional_directories", # additional_directories on session requests
|
|
36
|
-
"unstable_auth_methods", # AuthMethod::Agent etc.
|
|
38
|
+
agent-client-protocol = { version = "2.2", features = [
|
|
39
|
+
"unstable_session_fork", # session/fork support
|
|
37
40
|
] }
|
|
38
41
|
async-trait = "0.1"
|
|
39
42
|
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "io-std", "io-util", "sync", "time"] }
|
|
@@ -42,9 +45,12 @@ futures = "0.3"
|
|
|
42
45
|
uuid = { version = "1", features = ["v4"] }
|
|
43
46
|
```
|
|
44
47
|
|
|
45
|
-
The `unstable_*` features gate real types/methods (`ForkSessionRequest
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
The `unstable_*` features gate real types/methods (`ForkSessionRequest`).
|
|
49
|
+
Without them the corresponding APIs don't exist and you'll get "no
|
|
50
|
+
variant/method" errors. `additional_directories` and `AuthMethod::Agent` used
|
|
51
|
+
to need `unstable_session_additional_directories` and `unstable_auth_methods`;
|
|
52
|
+
both are stable in 2.x and those feature names no longer exist, so listing them
|
|
53
|
+
is a Cargo resolution error.
|
|
48
54
|
|
|
49
55
|
---
|
|
50
56
|
|
|
@@ -556,10 +562,9 @@ Editor Agent
|
|
|
556
562
|
8. **Never write to stdout except JSON-RPC** — log to stderr; in TTY mode siGit
|
|
557
563
|
redirects fds to `$TMPDIR/sigit.log`. Any stray `println!` or native library
|
|
558
564
|
stdout write corrupts the wire.
|
|
559
|
-
9. **Unstable features gate real types** — `unstable_session_fork
|
|
560
|
-
`
|
|
561
|
-
|
|
562
|
-
`AuthMethod::Agent` won't exist.
|
|
565
|
+
9. **Unstable features gate real types** — `unstable_session_fork` must be on
|
|
566
|
+
in `Cargo.toml` or `ForkSessionRequest` won't exist. `additional_directories`
|
|
567
|
+
and `AuthMethod::Agent` are stable in 2.x and need no feature.
|
|
563
568
|
10. **Zed re-fires the last config selection on connect** — make
|
|
564
569
|
`setConfigOption` a no-op when the requested model is already active, and
|
|
565
570
|
never start a model switch while a startup load is still in flight (GPU OOM).
|
|
@@ -38,6 +38,7 @@ Use this skill when preparing a release for this repository.
|
|
|
38
38
|
- The GitHub release body is generated, not hand-written: `release-github.yml`'s release job checks out the tag, awk-extracts the `## <version>` section from `CHANGELOG.md` (a missing section is a hard failure), appends a full-changelog link and a `sigit.si/code` footnote, and publishes it via `body_path: release_notes.md`. The only file a release-prep change needs to touch is `CHANGELOG.md` — never edit release notes in the GitHub UI, because the next tag push would overwrite them.
|
|
39
39
|
- npm and NuGet publish via OIDC trusted publishing — neither has a stored token in the repo. On npm this is configured per package (each `@getsigit/*` name has a trusted publisher pointing at `release-npm.yml`), so a new package needs the same setup before its first publish will work. OIDC requires npm >= 11.5.1 and Node >= 22.14.0.
|
|
40
40
|
- The NuGet package (`SiGit.Code`, `dotnet tool install --global SiGit.Code`) bundles all six platform binaries under `native/<os>-<arch>/` behind a managed shim, rather than shipping one package per platform like npm/PyPI. Watch the nuget.org 250 MB package-size limit if it ever grows.
|
|
41
|
+
- The winget channel (`release-winget.yml`) needs a `WINGET_TOKEN` secret that is a **classic PAT** with `public_repo` scope — not a fine-grained PAT. wingetcreate forks `microsoft/winget-pkgs` on first use and submits a PR from that fork; a fine-grained PAT scoped to `getsigit/sigit` cannot fork a repo outside its scope and every release fails with a 403/404 on the fork step. The token is passed as `WINGET_CREATE_GITHUB_TOKEN` (not `--token`) so it doesn't leak into logs. `wingetcreate update` only works on a package that already exists in `microsoft/winget-pkgs`, so the workflow checks `manifests/g/getSigit/siGitCode` first and falls back to `wingetcreate submit` with `packaging/winget/*.yaml.in` for the first release; every later release takes the `update` path. If a winget release fails with a fork/permission error, check the `WINGET_TOKEN` secret type before re-dispatching.
|
|
41
42
|
- The baked-in official MCP server is separately listed in the public MCP Registry as `si.sigit/sigit` (`release-mcp-registry.yml`, driven by `server.json` at the repo root). It's a remote Streamable-HTTP listing, so it's verified by a DNS TXT record on the `sigit.si` domain rather than the GitHub-OIDC scheme used for package listings.
|
|
42
43
|
|
|
43
44
|
## Git release flow
|
|
@@ -84,3 +85,4 @@ Pushing the `v*.*.*` tag is what fires every release workflow, so create and pus
|
|
|
84
85
|
- Package names, install commands, and branding stay consistent across npm, PyPI, crates.io, Homebrew, NuGet, Scoop, winget, AUR, and the `.deb`/`.rpm` packages.
|
|
85
86
|
- Every release asset (including the new `.deb`/`.rpm`/raw binaries consumed by Scoop, winget, and AUR) has a matching `.sha256` sidecar.
|
|
86
87
|
- Any known release limitations are called out explicitly, including a dispatch failure in `release-scoop`/`release-winget`/`release-aur` (non-fatal — logged as a warning by `release-github.yml`) versus a hard failure in a directly tag-triggered workflow like `release-nuget` or `release-mcp-registry`.
|
|
88
|
+
- The `WINGET_TOKEN` secret is a classic PAT with `public_repo` scope (not fine-grained), so wingetcreate can fork `microsoft/winget-pkgs`. If a winget release fails on the fork step, verify the token type before re-dispatching.
|
{sigit_code-1.5.13/.agents → sigit_code-1.6.1/.claude}/skills/agent-client-protocol/SKILL.md
RENAMED
|
@@ -11,7 +11,7 @@ ACP is a JSON-RPC 2.0 protocol over **stdio** for integrating AI coding agents
|
|
|
11
11
|
with editors (Zed, JetBrains, Neovim, etc.). The agent runs as a subprocess;
|
|
12
12
|
the editor is the client. Communication is newline-delimited JSON on stdin/stdout.
|
|
13
13
|
|
|
14
|
-
Crate: `agent-client-protocol = "
|
|
14
|
+
Crate: `agent-client-protocol = "2.2"` (siGit pins 2.2.0 in `Cargo.lock`)
|
|
15
15
|
Docs: https://docs.rs/agent-client-protocol
|
|
16
16
|
Spec: https://agentclientprotocol.com
|
|
17
17
|
|
|
@@ -21,6 +21,11 @@ Spec: https://agentclientprotocol.com
|
|
|
21
21
|
> handler receives a `ConnectionTo<Client>` (`cx`) you use to send notifications
|
|
22
22
|
> and spawn tasks — so the old mpsc "circular dependency" pattern is gone.
|
|
23
23
|
|
|
24
|
+
> **SDK 2.x is not protocol v2.** The 2.x crate still speaks ACP protocol v1 by
|
|
25
|
+
> default, which is what siGit and Zed use (`ProtocolVersion::V1`). The draft v2
|
|
26
|
+
> protocol (`Agent.v2()`, `V2ConnectionTo`) sits behind the `unstable_protocol_v2`
|
|
27
|
+
> feature and siGit does not enable it.
|
|
28
|
+
|
|
24
29
|
siGit's entire ACP server lives in `src/main.rs` (`run_acp_server`, the
|
|
25
30
|
`SiGitAgent` struct, and its `handle_*` methods). Read it alongside this skill.
|
|
26
31
|
|
|
@@ -30,10 +35,8 @@ siGit's entire ACP server lives in `src/main.rs` (`run_acp_server`, the
|
|
|
30
35
|
|
|
31
36
|
```toml
|
|
32
37
|
[dependencies]
|
|
33
|
-
agent-client-protocol = { version = "
|
|
34
|
-
"unstable_session_fork",
|
|
35
|
-
"unstable_session_additional_directories", # additional_directories on session requests
|
|
36
|
-
"unstable_auth_methods", # AuthMethod::Agent etc.
|
|
38
|
+
agent-client-protocol = { version = "2.2", features = [
|
|
39
|
+
"unstable_session_fork", # session/fork support
|
|
37
40
|
] }
|
|
38
41
|
async-trait = "0.1"
|
|
39
42
|
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "io-std", "io-util", "sync", "time"] }
|
|
@@ -42,9 +45,12 @@ futures = "0.3"
|
|
|
42
45
|
uuid = { version = "1", features = ["v4"] }
|
|
43
46
|
```
|
|
44
47
|
|
|
45
|
-
The `unstable_*` features gate real types/methods (`ForkSessionRequest
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
The `unstable_*` features gate real types/methods (`ForkSessionRequest`).
|
|
49
|
+
Without them the corresponding APIs don't exist and you'll get "no
|
|
50
|
+
variant/method" errors. `additional_directories` and `AuthMethod::Agent` used
|
|
51
|
+
to need `unstable_session_additional_directories` and `unstable_auth_methods`;
|
|
52
|
+
both are stable in 2.x and those feature names no longer exist, so listing them
|
|
53
|
+
is a Cargo resolution error.
|
|
48
54
|
|
|
49
55
|
---
|
|
50
56
|
|
|
@@ -556,10 +562,9 @@ Editor Agent
|
|
|
556
562
|
8. **Never write to stdout except JSON-RPC** — log to stderr; in TTY mode siGit
|
|
557
563
|
redirects fds to `$TMPDIR/sigit.log`. Any stray `println!` or native library
|
|
558
564
|
stdout write corrupts the wire.
|
|
559
|
-
9. **Unstable features gate real types** — `unstable_session_fork
|
|
560
|
-
`
|
|
561
|
-
|
|
562
|
-
`AuthMethod::Agent` won't exist.
|
|
565
|
+
9. **Unstable features gate real types** — `unstable_session_fork` must be on
|
|
566
|
+
in `Cargo.toml` or `ForkSessionRequest` won't exist. `additional_directories`
|
|
567
|
+
and `AuthMethod::Agent` are stable in 2.x and need no feature.
|
|
563
568
|
10. **Zed re-fires the last config selection on connect** — make
|
|
564
569
|
`setConfigOption` a no-op when the requested model is already active, and
|
|
565
570
|
never start a model switch while a startup load is still in flight (GPU OOM).
|
|
@@ -38,6 +38,7 @@ Use this skill when preparing a release for this repository.
|
|
|
38
38
|
- The GitHub release body is generated, not hand-written: `release-github.yml`'s release job checks out the tag, awk-extracts the `## <version>` section from `CHANGELOG.md` (a missing section is a hard failure), appends a full-changelog link and a `sigit.si/code` footnote, and publishes it via `body_path: release_notes.md`. The only file a release-prep change needs to touch is `CHANGELOG.md` — never edit release notes in the GitHub UI, because the next tag push would overwrite them.
|
|
39
39
|
- npm and NuGet publish via OIDC trusted publishing — neither has a stored token in the repo. On npm this is configured per package (each `@getsigit/*` name has a trusted publisher pointing at `release-npm.yml`), so a new package needs the same setup before its first publish will work. OIDC requires npm >= 11.5.1 and Node >= 22.14.0.
|
|
40
40
|
- The NuGet package (`SiGit.Code`, `dotnet tool install --global SiGit.Code`) bundles all six platform binaries under `native/<os>-<arch>/` behind a managed shim, rather than shipping one package per platform like npm/PyPI. Watch the nuget.org 250 MB package-size limit if it ever grows.
|
|
41
|
+
- The winget channel (`release-winget.yml`) needs a `WINGET_TOKEN` secret that is a **classic PAT** with `public_repo` scope — not a fine-grained PAT. wingetcreate forks `microsoft/winget-pkgs` on first use and submits a PR from that fork; a fine-grained PAT scoped to `getsigit/sigit` cannot fork a repo outside its scope and every release fails with a 403/404 on the fork step. The token is passed as `WINGET_CREATE_GITHUB_TOKEN` (not `--token`) so it doesn't leak into logs. `wingetcreate update` only works on a package that already exists in `microsoft/winget-pkgs`, so the workflow checks `manifests/g/getSigit/siGitCode` first and falls back to `wingetcreate submit` with `packaging/winget/*.yaml.in` for the first release; every later release takes the `update` path. If a winget release fails with a fork/permission error, check the `WINGET_TOKEN` secret type before re-dispatching.
|
|
41
42
|
- The baked-in official MCP server is separately listed in the public MCP Registry as `si.sigit/sigit` (`release-mcp-registry.yml`, driven by `server.json` at the repo root). It's a remote Streamable-HTTP listing, so it's verified by a DNS TXT record on the `sigit.si` domain rather than the GitHub-OIDC scheme used for package listings.
|
|
42
43
|
|
|
43
44
|
## Git release flow
|
|
@@ -84,3 +85,4 @@ Pushing the `v*.*.*` tag is what fires every release workflow, so create and pus
|
|
|
84
85
|
- Package names, install commands, and branding stay consistent across npm, PyPI, crates.io, Homebrew, NuGet, Scoop, winget, AUR, and the `.deb`/`.rpm` packages.
|
|
85
86
|
- Every release asset (including the new `.deb`/`.rpm`/raw binaries consumed by Scoop, winget, and AUR) has a matching `.sha256` sidecar.
|
|
86
87
|
- Any known release limitations are called out explicitly, including a dispatch failure in `release-scoop`/`release-winget`/`release-aur` (non-fatal — logged as a warning by `release-github.yml`) versus a hard failure in a directly tag-triggered workflow like `release-nuget` or `release-mcp-registry`.
|
|
88
|
+
- The `WINGET_TOKEN` secret is a classic PAT with `public_repo` scope (not fine-grained), so wingetcreate can fork `microsoft/winget-pkgs`. If a winget release fails on the fork step, verify the token type before re-dispatching.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[repo]
|
|
2
|
+
owner = "getsigit"
|
|
3
|
+
name = "sigit"
|
|
4
|
+
slug = "getsigit-sigit"
|
|
5
|
+
|
|
6
|
+
[agent]
|
|
7
|
+
login = "sigit-code-review"
|
|
8
|
+
display_name = "siGit Code Review"
|
|
9
|
+
|
|
10
|
+
[harvest]
|
|
11
|
+
state = "closed"
|
|
12
|
+
limit = 50
|
|
13
|
+
since = "2026-09-01"
|
|
14
|
+
cadence = "weekly"
|
|
15
|
+
day_of_week = "Mon"
|
|
16
|
+
runs_dir = "~/.agents/skills/sigit-code-review-outer-loop/runs"
|
|
17
|
+
report_format = "markdown"
|
|
18
|
+
compare_previous = true
|
|
19
|
+
|
|
20
|
+
[review.reviewer_skill]
|
|
21
|
+
name = "sigit-code-review-outer-loop"
|
|
22
|
+
version = "1.0.0"
|
|
23
|
+
|
|
24
|
+
[review.author_skill]
|
|
25
|
+
name = "sigit-code-review-feedbacks-response"
|
|
26
|
+
version = "1.0.0"
|
|
27
|
+
|
|
28
|
+
[review.repo_guidance]
|
|
29
|
+
branch_rules = "{fix,feature,release}/*"
|
|
30
|
+
ci_gate = "CI"
|
|
31
|
+
watch_paths = ["src/**"]
|
|
32
|
+
ignore_paths = ["**/*.md", "**/*.txt", "docs/**", "vendor/**", ".github/**", "*.lock"]
|
|
33
|
+
|
|
34
|
+
[[guardrails.known_issues]]
|
|
35
|
+
pattern = "all_zero_summary"
|
|
36
|
+
source = "getsigit-sigit"
|
|
37
|
+
description = "Zero findings on a large control-flow diff may be recall loss from an over-corrected prompt bar, not a clean review. Seen on stack #163 (900 additions, 0 findings)."
|
|
38
|
+
action = "flag_in_report"
|
|
39
|
+
|
|
40
|
+
[[guardrails.known_issues]]
|
|
41
|
+
pattern = "confident_false_positives"
|
|
42
|
+
source = "getsigit-sigit"
|
|
43
|
+
description = "Confident declarative findings whose premise is contradicted by the cited code. Seen on stack #160 (5 of 5 findings rejected, rejected_rate 1.0). The hedge ban replaced speculative questions with confident wrong claims."
|
|
44
|
+
action = "flag_in_report"
|
|
45
|
+
|
|
46
|
+
[[guardrails.known_issues]]
|
|
47
|
+
pattern = "approval_on_disagree"
|
|
48
|
+
source = "getsigit-sigit"
|
|
49
|
+
description = "Agent approves within 30-45s of an author disagreement without processing the correction. Compounds with confident false positives: wrong claim, author corrects, agent approves without re-reading."
|
|
50
|
+
action = "flag_in_report"
|
|
51
|
+
|
|
52
|
+
[[guardrails.known_issues]]
|
|
53
|
+
pattern = "repeat_findings_high"
|
|
54
|
+
source = "getsigit-sigit-si"
|
|
55
|
+
description = "Repeat findings above 30% indicate the agent is re-raising issues the author already addressed."
|
|
56
|
+
action = "flag_in_report"
|
|
57
|
+
|
|
58
|
+
[[guardrails.known_issues]]
|
|
59
|
+
pattern = "force_pushes_inflate_rounds"
|
|
60
|
+
source = "smbcloudXYZ-smbcloud"
|
|
61
|
+
description = "Force pushes cause one-for-one review round inflation; the agent re-reads unchanged diffs."
|
|
62
|
+
action = "note_in_report"
|
|
@@ -127,10 +127,31 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
127
127
|
endpoint can also fail *after* the response is open, reporting it as a `data:` frame holding
|
|
128
128
|
the same envelope; that frame has no `choices`, so `consume_stream` has to check for it
|
|
129
129
|
explicitly or it parses as an empty chunk and the turn ends looking like an empty answer.
|
|
130
|
+
`TurnResult::finish` carries the endpoint's `finish_reason` up to the loop, and
|
|
131
|
+
`stop_reason_for` in `main.rs` turns it into the ACP stop reason: the tool-round cap is
|
|
132
|
+
`max_turn_requests`, `length` is `max_tokens`, `content_filter` is `refusal`. ACP defines a
|
|
133
|
+
refusal as a turn the next prompt will not include, so `handle_prompt` restores the history
|
|
134
|
+
it snapshotted before the turn instead of only relabelling the response.
|
|
135
|
+
The round that reaches the cap (24, or `SIGIT_MAX_TOOL_ROUNDS`) is followed by one forced
|
|
136
|
+
text reply with no tools. The model cannot see that the tools are gone, so
|
|
137
|
+
`round_cap_note` is appended to that round's last tool result, and the turn always closes
|
|
138
|
+
with `round_cap_stop_message`. Without both, the thread stops on the model announcing a
|
|
139
|
+
step that never runs (issue #120).
|
|
130
140
|
Some models write tool calls into content as text; `src/inline_tool_calls.rs` recovers the
|
|
131
141
|
well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
|
|
132
142
|
and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
|
|
133
143
|
didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
|
|
144
|
+
Image attachments: ACP fixes `promptCapabilities.image` for the whole connection, while the
|
|
145
|
+
model can change on any turn, so the capability is always advertised and the decision is made
|
|
146
|
+
per prompt. `InferenceBackend::accepts_images` answers for the active model (on-device: no;
|
|
147
|
+
remote: `provider::model_accepts_images`, which reads the hard-coded `IMAGE_TIERS` for
|
|
148
|
+
`onde-*` ids and says yes for a user's own endpoint). `images_for_turn` in `main.rs` either
|
|
149
|
+
passes the images to `send_message_with_images` or drops them with a note to the user and a
|
|
150
|
+
bracketed note to the model. A message with images is stored in history as OpenAI content
|
|
151
|
+
parts and stays that way; `OpenAiBackend` strips the images per request (`without_images`)
|
|
152
|
+
when its model cannot read them, which is what makes a mid-thread switch to a text-only tier
|
|
153
|
+
safe. Read history text through `backend::message_text`, never `content.as_str()`.
|
|
154
|
+
`IMAGE_TIERS` mirrors onde-cloud's `IMAGE_CANDIDATES`; update both together.
|
|
134
155
|
- **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
|
|
135
156
|
wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
|
|
136
157
|
`~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
|
|
@@ -225,6 +246,17 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
225
246
|
it's a remote server, the registry's URL-match rule forces a domain namespace (`si.sigit` ↔
|
|
226
247
|
`sigit.si`) verified by a DNS TXT record, not the GitHub-OIDC scheme `smbcloud-cli` uses for its
|
|
227
248
|
package listing.
|
|
249
|
+
Separate from all of the above are the servers an ACP client passes in `mcpServers` on
|
|
250
|
+
`session/new`, `session/load` and `session/fork`. ACP requires agents to connect to the stdio
|
|
251
|
+
ones, and they belong to the session that named them, so they cannot live in the startup
|
|
252
|
+
global: `connect_session_servers` returns a `SessionServers` that `main.rs` keeps on
|
|
253
|
+
`SessionState` and installs with `set_session_servers` whenever a session becomes live, the
|
|
254
|
+
same way it swaps the roots. `tool_specs`, `call_tool` and `/mcp` read the startup servers and
|
|
255
|
+
then the live session's. A client-supplied server whose name is already taken by a startup
|
|
256
|
+
server is not connected, since both would claim the same `mcp__<server>__` prefix. Streamable
|
|
257
|
+
HTTP entries are connected too, with the URL and headers the client sent, because
|
|
258
|
+
`handle_initialize` advertises `mcpCapabilities.http`. SSE is not advertised (the MCP spec
|
|
259
|
+
deprecated it), so a conforming client never sends one and a stray entry is skipped.
|
|
228
260
|
- **`src/permissions.rs`** — tool permission policy. Every tool call passes through
|
|
229
261
|
`decision_for` before executing: read-only tools always run; mutating tools (and all
|
|
230
262
|
`mcp__*`/unknown tools) are governed by, in order: per-session plan mode (`/plan` — deny all
|
|
@@ -232,7 +264,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
232
264
|
overrides and the default mode from `[permissions]` in `settings.toml` (`allow`/`ask`/`deny`,
|
|
233
265
|
default `ask`; `SIGIT_PERMISSIONS` env overrides the default). On `ask`, the ACP path sends
|
|
234
266
|
`session/request_permission` (allow once / allow for session / deny) and the TUI pauses the
|
|
235
|
-
inference task on a y/a/n prompt.
|
|
267
|
+
inference task on a y/a/n prompt. On the ACP path the decision is taken *before* the call is
|
|
268
|
+
announced, because it sets the announced status: a call that will ask starts `pending`, the
|
|
269
|
+
permission request carries that call's own id, and an `in_progress` update follows approval.
|
|
270
|
+
That update also puts the card's title back, since the permission request overwrites it
|
|
271
|
+
with the full arguments. Note: ACP turn-affecting handlers run in `cx.spawn`ed tasks
|
|
236
272
|
serialized by `SiGitAgent::turn_lock` so the dispatch loop can route the client's permission
|
|
237
273
|
answer mid-turn — don't move them back inline, and don't await client requests from inline
|
|
238
274
|
handlers (deadlock).
|
|
@@ -261,7 +297,8 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
261
297
|
read another session's roots from the global. Project-local
|
|
262
298
|
discovery reads it: skills, slash commands, subagent types, and instruction files all scan
|
|
263
299
|
every root. MCP is deliberately not on that list — `mcp::init` runs once at startup, before
|
|
264
|
-
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell.
|
|
300
|
+
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell. (The servers a
|
|
301
|
+
client names in `mcpServers` are a different thing and are per session; see `src/mcp.rs`.)
|
|
265
302
|
- **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
|
|
266
303
|
`tokio::select!` to multiplex terminal events with streaming tokens.
|
|
267
304
|
- **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
|
|
@@ -325,7 +362,8 @@ verbosity with `RUST_LOG`.
|
|
|
325
362
|
|
|
326
363
|
`OPENAI_BASE_URL` / `OPENAI_API_KEY` (provider override), `SIGIT_API_URL` (account API base,
|
|
327
364
|
default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
|
|
328
|
-
`SIGIT_MODEL`, `
|
|
365
|
+
`SIGIT_MODEL`, `SIGIT_MAX_TOOL_ROUNDS` (1 to 500, default 24; the tool-round cap of a
|
|
366
|
+
headless run or an ACP prompt turn), `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
|
|
329
367
|
smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
|
|
330
368
|
server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
|
|
331
369
|
mutating tools; the escape hatch for clients without permission-request support),
|
|
@@ -376,13 +414,20 @@ Three of these need credentials or a one-time manual step before they work:
|
|
|
376
414
|
|
|
377
415
|
- Scoop needs a `getsigit/scoop-bucket` repo and a `SCOOP_BUCKET_TOKEN` secret, mirroring the
|
|
378
416
|
Homebrew tap setup.
|
|
379
|
-
- winget needs a `WINGET_TOKEN` (PAT with `public_repo`) so `wingetcreate` can fork
|
|
380
|
-
`microsoft/winget-pkgs
|
|
381
|
-
which wingetcreate warns can leak the
|
|
382
|
-
|
|
383
|
-
`manifests/g/getSigit/siGitCode` path
|
|
384
|
-
`packaging/winget/*.yaml.in` and running
|
|
385
|
-
fallback runs once, then every later
|
|
417
|
+
- winget needs a `WINGET_TOKEN` (PAT with `public_repo` scope) so `wingetcreate` can fork
|
|
418
|
+
`microsoft/winget-pkgs` and open the manifest PR. It is passed as
|
|
419
|
+
`WINGET_CREATE_GITHUB_TOKEN` rather than `--token`, which wingetcreate warns can leak the
|
|
420
|
+
token into logs. `wingetcreate update` only works on a package that already exists in
|
|
421
|
+
`microsoft/winget-pkgs`, so the workflow checks the `manifests/g/getSigit/siGitCode` path
|
|
422
|
+
first and falls back to rendering `packaging/winget/*.yaml.in` and running
|
|
423
|
+
`wingetcreate submit` for a first submission. That fallback runs once, then every later
|
|
424
|
+
release takes the `update` path. Two non-obvious things in the update path: the `--urls`
|
|
425
|
+
arguments carry a trailing `|x64` / `|arm64` suffix that tells wingetcreate which installer
|
|
426
|
+
entry each URL replaces — without it, wingetcreate guesses from the file name, and
|
|
427
|
+
"sigit-win-amd64.exe" is not a spelling it recognises; and the first-submission render
|
|
428
|
+
uppercases the SHA256 (`tr '[:lower:]' '[:upper:]'`) to match the community validation
|
|
429
|
+
pipeline, which writes 64-hex checksums uppercase. The update path also passes
|
|
430
|
+
`--release-date`, `--release-notes-url`, `--submit`, and `--no-open` explicitly.
|
|
386
431
|
- The AUR needs `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_PRIVATE_KEY`. It publishes `sigit-bin`
|
|
387
432
|
(a prebuilt binary) so Arch users are not compiling the on-device inference stack to install a
|
|
388
433
|
CLI.
|
|
@@ -1,6 +1,116 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 1.6.1
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Images can be attached to a prompt in the editor.** siGit Code now
|
|
8
|
+
advertises `promptCapabilities.image`, so an ACP client offers image
|
|
9
|
+
attachments. The image goes to the model when the active model reads images.
|
|
10
|
+
The model picker marks those models with "reads images". The on-device
|
|
11
|
+
models and four cloud tiers (`nova`, `orbit`, `apex`, `flux`) are text-only:
|
|
12
|
+
with one of them active the image is left out, a note in the thread says so,
|
|
13
|
+
and the model is told an image was withheld. Switching a thread that already
|
|
14
|
+
holds images to a text-only model flags that once as well. Cloud tiers need
|
|
15
|
+
siGit Code Cloud to accept image parts, which is rolling out separately
|
|
16
|
+
(#134).
|
|
17
|
+
|
|
18
|
+
- **The tool-round cap of a headless run can be set.** `--max-tool-rounds <n>`
|
|
19
|
+
or `SIGIT_MAX_TOOL_ROUNDS` (1 to 500) replaces the built-in 24 for
|
|
20
|
+
`sigit run` and `sigit -p`. The flag wins over the variable.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **A prompt turn now reports why it stopped.** ACP defines five stop reasons
|
|
25
|
+
and siGit Code only ever sent `end_turn` and `cancelled`. A turn that runs
|
|
26
|
+
into the tool-round cap now ends with `max_turn_requests`, a reply cut off
|
|
27
|
+
at the token limit with `max_tokens`, and a reply the endpoint withheld
|
|
28
|
+
(`content_filter`) with `refusal`. A refused turn is also taken out of the
|
|
29
|
+
conversation, which is what the protocol tells the client to expect (#140).
|
|
30
|
+
|
|
31
|
+
- **A tool call that needs approval is one card, not two.** The permission
|
|
32
|
+
request carried an id of its own, so an ACP client showed an approval card
|
|
33
|
+
beside a call that already claimed to be running. The call is now announced
|
|
34
|
+
as `pending`, the permission request names that same call, and it moves to
|
|
35
|
+
`in_progress` once approved. Calls allowed by policy still start out
|
|
36
|
+
`in_progress` (#138).
|
|
37
|
+
|
|
38
|
+
- **A turn that runs out of tool rounds says so.** In an editor, a long task
|
|
39
|
+
could stop on a line like "Now commit:" with nothing after it. The turn had
|
|
40
|
+
used all 24 tool rounds, the model spent its last reply announcing the next
|
|
41
|
+
step, and the call behind it was dropped. siGit Code now tells the model
|
|
42
|
+
that its rounds are used up before that last reply, and ends the turn with a
|
|
43
|
+
message saying why it stopped and that "continue" picks it back up.
|
|
44
|
+
`SIGIT_MAX_TOOL_ROUNDS` now sets the cap for editor sessions too (#120).
|
|
45
|
+
|
|
46
|
+
- **A headless run no longer ends silently with no final message.** When the
|
|
47
|
+
last round came back empty, which is what happens when a run is cut off at
|
|
48
|
+
the tool-round cap mid-task, stdout was empty and the exit status was 0, so
|
|
49
|
+
a caller could not tell it from a run with nothing to report. siGit Code now
|
|
50
|
+
asks the model once for its final message before finishing.
|
|
51
|
+
|
|
52
|
+
## 1.6.0
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- **Editors can pass HTTP MCP servers to a session.** siGit Code now
|
|
57
|
+
advertises `mcpCapabilities.http`, so an ACP client may list Streamable HTTP
|
|
58
|
+
servers in `mcpServers` next to stdio ones. They are connected with the URL
|
|
59
|
+
and headers the client sent and are scoped to that session, like the stdio
|
|
60
|
+
ones. SSE is still not advertised, since the MCP spec deprecated it (#151).
|
|
61
|
+
|
|
62
|
+
- **The plan panel survives a failed turn.** The last `write_todos` list is
|
|
63
|
+
now kept by siGit Code itself. When a turn ends in an endpoint error before
|
|
64
|
+
the model gets to call `write_todos` again, the saved list is sent to the
|
|
65
|
+
editor again, so the plan stays on screen where it used to go blank (#132).
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- **The ACP Rust SDK is now 2.2** (`agent-client-protocol`, up from 1.3).
|
|
70
|
+
siGit Code still speaks ACP protocol v1 to the editor, so nothing changes on
|
|
71
|
+
the wire. The `unstable_auth_methods` feature is gone because agent auth
|
|
72
|
+
methods are stable in 2.x.
|
|
73
|
+
|
|
74
|
+
### Fixed
|
|
75
|
+
|
|
76
|
+
- **MCP servers the editor passes to a session are connected.** ACP clients
|
|
77
|
+
can name MCP servers in `mcpServers` when they open a session, and agents
|
|
78
|
+
are required to connect to the stdio ones. siGit Code accepted the field and
|
|
79
|
+
ignored it. The servers are now spawned when the session opens, their tools
|
|
80
|
+
are offered to that session only, and `/mcp` lists them as coming from the
|
|
81
|
+
editor. `SIGIT_MCP=off` still turns all of it off (#135).
|
|
82
|
+
|
|
83
|
+
- **A relative `cwd` is rejected when a session starts.** ACP requires the
|
|
84
|
+
working directory and every `additionalDirectories` entry to be absolute.
|
|
85
|
+
`session/new`, `session/load` and `session/fork` used to accept a relative
|
|
86
|
+
one and resolve it against wherever the editor spawned the process. They now
|
|
87
|
+
answer with an invalid-params error (#136).
|
|
88
|
+
|
|
89
|
+
- **Loading a session that does not exist is an error.** `session/load` with
|
|
90
|
+
an id that was never saved used to succeed and open an empty session under
|
|
91
|
+
that id, so the editor showed a blank thread that looked restored. It now
|
|
92
|
+
answers "not found" (`-32002`). A thread opened in the running process but
|
|
93
|
+
not spoken in yet still loads (#137).
|
|
94
|
+
|
|
95
|
+
- **Compaction no longer dead-ends a long session.** The summarization request
|
|
96
|
+
used to carry the whole conversation, which by then was already over the
|
|
97
|
+
model's window, so siGit Code Cloud timed out with a 504 and the session
|
|
98
|
+
stopped with "start a new thread". The transcript sent for summarizing is
|
|
99
|
+
now capped, cut from the middle so the opening request and the latest state
|
|
100
|
+
are kept. If summarizing still fails, the oldest messages are dropped until
|
|
101
|
+
the history fits, with whole tool rounds removed together. A failed attempt
|
|
102
|
+
leaves the conversation as it was (#125).
|
|
103
|
+
|
|
104
|
+
- **Gateway error pages stay out of the chat.** When an endpoint answers with
|
|
105
|
+
an HTML error page, the error shown is the status line, not the page's
|
|
106
|
+
markup (#125).
|
|
107
|
+
|
|
108
|
+
- **Issue and pull request work no longer assumes GitHub.** The system prompt
|
|
109
|
+
treated forge features as if every repository lived on GitHub, while the
|
|
110
|
+
built-in `mcp__sigit__*` tools only work for repositories hosted on
|
|
111
|
+
sigit.si. The agent now checks the remote first, uses those tools only for
|
|
112
|
+
sigit.si repositories, and reaches for the forge's own CLI (`gh`, `glab`,
|
|
113
|
+
`tea`) elsewhere (#127).
|
|
4
114
|
|
|
5
115
|
## 1.5.13
|
|
6
116
|
|