sigit-code 1.5.9__tar.gz → 1.5.11__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.9 → sigit_code-1.5.11}/.agents/AGENTS.md +34 -5
- {sigit_code-1.5.9/.claude → sigit_code-1.5.11/.agents}/skills/agent-client-protocol/SKILL.md +11 -1
- {sigit_code-1.5.9/.agents → sigit_code-1.5.11/.claude}/skills/agent-client-protocol/SKILL.md +11 -1
- {sigit_code-1.5.9 → sigit_code-1.5.11}/AGENTS.md +34 -5
- {sigit_code-1.5.9 → sigit_code-1.5.11}/CHANGELOG.md +140 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/CLAUDE.md +34 -5
- {sigit_code-1.5.9 → sigit_code-1.5.11}/Cargo.lock +1 -1
- {sigit_code-1.5.9 → sigit_code-1.5.11}/Cargo.toml +1 -1
- {sigit_code-1.5.9 → sigit_code-1.5.11}/PKG-INFO +5 -3
- {sigit_code-1.5.9 → sigit_code-1.5.11}/README.md +41 -7
- sigit_code-1.5.11/docs/headless.md +64 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/sigit/README.md +5 -3
- {sigit_code-1.5.9 → sigit_code-1.5.11}/nuget/sigit/README.md +10 -4
- {sigit_code-1.5.9 → sigit_code-1.5.11}/pypi/README.md +4 -2
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/backend.rs +479 -71
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/chat.rs +11 -22
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/headless.rs +278 -41
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/inline_tool_calls.rs +431 -79
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/instructions.rs +3 -1
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/main.rs +996 -171
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/permissions.rs +0 -12
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/provider.rs +8 -0
- sigit_code-1.5.11/src/session_store.rs +526 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/tools.rs +428 -72
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/workspace.rs +14 -3
- {sigit_code-1.5.9 → sigit_code-1.5.11}/tests/acp_permissions.rs +261 -0
- sigit_code-1.5.11/tests/acp_session_list.rs +246 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/tests/headless_mode.rs +166 -4
- sigit_code-1.5.9/src/session_store.rs +0 -261
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.agents/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.agents/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.agents/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.agents/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.agents/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.agents/skills/sigit-code-release/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.agents/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.claude/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.claude/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.claude/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.claude/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.claude/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.claude/skills/sigit-code-release/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.claude/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/ci.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-aur.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-crates.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-github.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-homebrew.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-npm.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-nuget.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-pypi.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-scoop.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.github/workflows/release-winget.yml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.gitignore +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/.nvmrc +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/LICENSE +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/docs/hooks.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/docs/mcp.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/examples/settings-with-hooks.toml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/examples/skills/README.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/examples/skills/commit-message/SKILL.md +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/README.md.tmpl +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/package-compat.json.tmpl +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/package-main.json.tmpl +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/package.json.tmpl +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/scripts/render-main-package.cjs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/scripts/render-platform-package.cjs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/sigit/.gitignore +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/sigit/package.json +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/sigit/src/index.ts +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/npm/sigit/tsconfig.json +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/nuget/.gitignore +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/nuget/sigit/Program.cs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/nuget/sigit/SiGit.Code.csproj +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/packaging/aur/PKGBUILD.in +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/packaging/nfpm.yaml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/packaging/winget/getSigit.siGitCode.installer.yaml.in +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/packaging/winget/getSigit.siGitCode.locale.en-US.yaml.in +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/packaging/winget/getSigit.siGitCode.yaml.in +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/pypi/pyproject.toml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/pyproject.toml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/rust-toolchain.toml +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/account.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/browser_auth.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/commands.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/credentials.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/frontmatter.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/hooks.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/mcp.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/models.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/settings.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/setup.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/skills.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/src/subagents.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/tests/acp_endpoint_errors.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/tests/acp_multi_root.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/tests/acp_session_load.rs +0 -0
- {sigit_code-1.5.9 → sigit_code-1.5.11}/tests/acp_tool_stdin.rs +0 -0
|
@@ -111,9 +111,13 @@ The agent loop is backend-agnostic. The flow: a turn (messages + tool specs) goe
|
|
|
111
111
|
feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete backend.
|
|
112
112
|
|
|
113
113
|
- **`src/main.rs`** — entry point, mode dispatch, the full ACP `Agent` impl (session lifecycle:
|
|
114
|
-
new/load/fork/prompt/cancel, config options, slash-command advertisement), and the `SYSTEM_PROMPT
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
new/load/fork/prompt/cancel, config options, slash-command advertisement), and the `SYSTEM_PROMPT`.
|
|
115
|
+
ACP session state owns its roots, conversation, and selected model even though the process has
|
|
116
|
+
one live backend; activating a thread parks and restores all three. Unknown session ids are
|
|
117
|
+
rejected instead of silently borrowing the active thread's cwd. Prompt cancellation is routed
|
|
118
|
+
outside `turn_lock`, which lets a client cancel the turn currently holding that lock. The
|
|
119
|
+
`SYSTEM_PROMPT` bakes in smbCloud-specific context the agent should use when the repo is clearly
|
|
120
|
+
smbCloud, and stay general otherwise.
|
|
117
121
|
- **`src/backend.rs`** — the `InferenceBackend` trait and neutral types (`ToolSpec`, `ToolCall`,
|
|
118
122
|
`ToolResult`, `TurnResult`). Two impls: `LocalBackend` (on-device via `onde::ChatEngine`) and
|
|
119
123
|
`OpenAiBackend` (any OpenAI-compatible HTTP endpoint). A `BackendError` is user-facing: the
|
|
@@ -123,6 +127,10 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
123
127
|
endpoint can also fail *after* the response is open, reporting it as a `data:` frame holding
|
|
124
128
|
the same envelope; that frame has no `choices`, so `consume_stream` has to check for it
|
|
125
129
|
explicitly or it parses as an empty chunk and the turn ends looking like an empty answer.
|
|
130
|
+
Some models write tool calls into content as text; `src/inline_tool_calls.rs` recovers the
|
|
131
|
+
well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
|
|
132
|
+
and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
|
|
133
|
+
didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
|
|
126
134
|
- **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
|
|
127
135
|
wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
|
|
128
136
|
`~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
|
|
@@ -131,7 +139,8 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
131
139
|
`multi_edit`, `delete_file`, `run_command`, `write_todos`, `remember`. Add a tool in both the
|
|
132
140
|
spec list (`all_tools`) and the execute `match` (`execute_tool`). `run_command` also enforces
|
|
133
141
|
commit attribution: when a command creates a new commit that lacks the
|
|
134
|
-
`Co-Authored-By: siGit Code` trailer (`
|
|
142
|
+
`Co-Authored-By: siGit Code` trailer (`commit_co_author_trailer()`, which reads
|
|
143
|
+
`siGit Code v<version>-<acp|tui|headless>` from the surface `main` sets via `set_surface`), it amends the trailer in —
|
|
135
144
|
unless the commit already exists on a remote, which is never rewritten. Every child process it
|
|
136
145
|
spawns (`spawn_shell`, the `git` helpers, and `hooks.rs`) sets `stdin` to null and never
|
|
137
146
|
inherits it: in ACP mode sigit's stdin is the JSON-RPC pipe from the editor, so a command that
|
|
@@ -243,12 +252,32 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
243
252
|
`handle_initialize` is what makes the rest of this reachable — without it Zed keeps the first
|
|
244
253
|
root, drops the others, and shows "This agent doesn't currently support multi-root workspaces".
|
|
245
254
|
The process still has one working directory, so the extra roots live in a
|
|
246
|
-
process-global here and `project_dirs()` returns cwd-first, extras after.
|
|
255
|
+
process-global here and `project_dirs()` returns cwd-first, extras after.
|
|
256
|
+
One process also serves every thread the editor has open, so that global
|
|
257
|
+
(with the cwd, the backend conversation, and the background-task owner in
|
|
258
|
+
`tools.rs`) always belongs to the *live* session: `main.rs` keeps a
|
|
259
|
+
`SessionState` per session id and `activate_session` parks the live one and
|
|
260
|
+
installs the requested one before any prompt or config change runs. Don't
|
|
261
|
+
read another session's roots from the global. Project-local
|
|
247
262
|
discovery reads it: skills, slash commands, subagent types, and instruction files all scan
|
|
248
263
|
every root. MCP is deliberately not on that list — `mcp::init` runs once at startup, before
|
|
249
264
|
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell.
|
|
250
265
|
- **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
|
|
251
266
|
`tokio::select!` to multiplex terminal events with streaming tokens.
|
|
267
|
+
- **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
|
|
268
|
+
clients. The legacy `-p` form reaches the same parser. Every new run gets a UUID session id;
|
|
269
|
+
`--resume <id>` restores that session through `session_store`, and `--output jsonl` emits a
|
|
270
|
+
structured session/delta/tool/result stream while logs stay on stderr. Headless permission
|
|
271
|
+
prompts collapse to denial unless the tool was pre-approved with `--allow-tool`.
|
|
272
|
+
- **`src/session_store.rs`** — durable conversations: one JSON-lines history file per session at
|
|
273
|
+
`$SIGIT_CONFIG_DIR/sessions/<id>.jsonl`, written atomically, restorable into either backend.
|
|
274
|
+
Each save also writes a `<id>.meta.json` sidecar naming the session's `cwd` and the extra roots
|
|
275
|
+
of a multi-root project. That sidecar is what makes a thread *listable*: ACP's `session/list`
|
|
276
|
+
(advertised as `sessionCapabilities.list`, handled by `handle_list_sessions` in `main.rs` — the
|
|
277
|
+
editor's "Import Threads" picker) must report an absolute `cwd` per session and may filter on
|
|
278
|
+
it, so a session without one is skipped there while still reopening by id through
|
|
279
|
+
`session/load`. Sidecars are written at save time, not at session start, so a thread nobody
|
|
280
|
+
spoke in leaves nothing behind.
|
|
252
281
|
- **`src/setup.rs`** — model cache location, local model discovery, selected-model persistence.
|
|
253
282
|
Must run (`setup_shared_model_cache`) *before* anything touches `ChatEngine`/`hf-hub`, since
|
|
254
283
|
those read env vars once at init.
|
{sigit_code-1.5.9/.claude → sigit_code-1.5.11/.agents}/skills/agent-client-protocol/SKILL.md
RENAMED
|
@@ -196,6 +196,7 @@ the connection and the agent anymore. Don't reintroduce the mpsc forwarder patte
|
|
|
196
196
|
| `NewSessionRequest` | `handle_new_session` | sets cwd, resets history, advertises commands + config options |
|
|
197
197
|
| `LoadSessionRequest` | `handle_load_session` | like new_session; gated by `load_session(true)` capability |
|
|
198
198
|
| `ForkSessionRequest` | `handle_fork_session` | gated by `unstable_session_fork` + `SessionForkCapabilities` |
|
|
199
|
+
| `ListSessionsRequest` | `handle_list_sessions` | the editor's "Import Threads" picker; gated by `SessionListCapabilities` |
|
|
199
200
|
| `PromptRequest` | `handle_prompt` | the turn: parse blocks → slash commands or tool-calling loop |
|
|
200
201
|
| `SetSessionConfigOptionRequest` | `handle_set_session_config_option` | the Zed model picker — switches/downloads models |
|
|
201
202
|
| `CancelNotification` | `handle_cancel` | notification, no response |
|
|
@@ -226,7 +227,8 @@ Ok(InitializeResponse::new(ProtocolVersion::V1) // use V1, not args.proto
|
|
|
226
227
|
.load_session(true) // enables LoadSessionRequest
|
|
227
228
|
.session_capabilities(
|
|
228
229
|
SessionCapabilities::new()
|
|
229
|
-
.fork(SessionForkCapabilities::new())
|
|
230
|
+
.fork(SessionForkCapabilities::new()) // enables ForkSessionRequest
|
|
231
|
+
.list(SessionListCapabilities::new()), // enables ListSessionsRequest
|
|
230
232
|
),
|
|
231
233
|
)
|
|
232
234
|
.meta(initialize_meta())) // free-form Meta (see below)
|
|
@@ -573,6 +575,14 @@ Editor Agent
|
|
|
573
575
|
12. **Store `SessionId` as `SessionId`**, not `String`, so `==` is clean.
|
|
574
576
|
13. **`SetSessionConfigOptionResponse::new(config_options)`** — the response
|
|
575
577
|
carries the *rebuilt* options so the picker reflects the new current value.
|
|
578
|
+
14. **`session/list` needs a `cwd` per session, which history alone can't
|
|
579
|
+
supply.** `SessionInfo` requires an absolute `cwd` and the request may
|
|
580
|
+
filter on it, so `session_store` writes a `<id>.meta.json` sidecar next to
|
|
581
|
+
each saved thread; sessions without one are skipped by
|
|
582
|
+
`handle_list_sessions` rather than guessed at. Advertising
|
|
583
|
+
`SessionCapabilities::new().list(SessionListCapabilities::new())` is what
|
|
584
|
+
turns the editor's "Import Threads" picker from an error banner into a
|
|
585
|
+
list.
|
|
576
586
|
|
|
577
587
|
---
|
|
578
588
|
|
{sigit_code-1.5.9/.agents → sigit_code-1.5.11/.claude}/skills/agent-client-protocol/SKILL.md
RENAMED
|
@@ -196,6 +196,7 @@ the connection and the agent anymore. Don't reintroduce the mpsc forwarder patte
|
|
|
196
196
|
| `NewSessionRequest` | `handle_new_session` | sets cwd, resets history, advertises commands + config options |
|
|
197
197
|
| `LoadSessionRequest` | `handle_load_session` | like new_session; gated by `load_session(true)` capability |
|
|
198
198
|
| `ForkSessionRequest` | `handle_fork_session` | gated by `unstable_session_fork` + `SessionForkCapabilities` |
|
|
199
|
+
| `ListSessionsRequest` | `handle_list_sessions` | the editor's "Import Threads" picker; gated by `SessionListCapabilities` |
|
|
199
200
|
| `PromptRequest` | `handle_prompt` | the turn: parse blocks → slash commands or tool-calling loop |
|
|
200
201
|
| `SetSessionConfigOptionRequest` | `handle_set_session_config_option` | the Zed model picker — switches/downloads models |
|
|
201
202
|
| `CancelNotification` | `handle_cancel` | notification, no response |
|
|
@@ -226,7 +227,8 @@ Ok(InitializeResponse::new(ProtocolVersion::V1) // use V1, not args.proto
|
|
|
226
227
|
.load_session(true) // enables LoadSessionRequest
|
|
227
228
|
.session_capabilities(
|
|
228
229
|
SessionCapabilities::new()
|
|
229
|
-
.fork(SessionForkCapabilities::new())
|
|
230
|
+
.fork(SessionForkCapabilities::new()) // enables ForkSessionRequest
|
|
231
|
+
.list(SessionListCapabilities::new()), // enables ListSessionsRequest
|
|
230
232
|
),
|
|
231
233
|
)
|
|
232
234
|
.meta(initialize_meta())) // free-form Meta (see below)
|
|
@@ -573,6 +575,14 @@ Editor Agent
|
|
|
573
575
|
12. **Store `SessionId` as `SessionId`**, not `String`, so `==` is clean.
|
|
574
576
|
13. **`SetSessionConfigOptionResponse::new(config_options)`** — the response
|
|
575
577
|
carries the *rebuilt* options so the picker reflects the new current value.
|
|
578
|
+
14. **`session/list` needs a `cwd` per session, which history alone can't
|
|
579
|
+
supply.** `SessionInfo` requires an absolute `cwd` and the request may
|
|
580
|
+
filter on it, so `session_store` writes a `<id>.meta.json` sidecar next to
|
|
581
|
+
each saved thread; sessions without one are skipped by
|
|
582
|
+
`handle_list_sessions` rather than guessed at. Advertising
|
|
583
|
+
`SessionCapabilities::new().list(SessionListCapabilities::new())` is what
|
|
584
|
+
turns the editor's "Import Threads" picker from an error banner into a
|
|
585
|
+
list.
|
|
576
586
|
|
|
577
587
|
---
|
|
578
588
|
|
|
@@ -111,9 +111,13 @@ The agent loop is backend-agnostic. The flow: a turn (messages + tool specs) goe
|
|
|
111
111
|
feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete backend.
|
|
112
112
|
|
|
113
113
|
- **`src/main.rs`** — entry point, mode dispatch, the full ACP `Agent` impl (session lifecycle:
|
|
114
|
-
new/load/fork/prompt/cancel, config options, slash-command advertisement), and the `SYSTEM_PROMPT
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
new/load/fork/prompt/cancel, config options, slash-command advertisement), and the `SYSTEM_PROMPT`.
|
|
115
|
+
ACP session state owns its roots, conversation, and selected model even though the process has
|
|
116
|
+
one live backend; activating a thread parks and restores all three. Unknown session ids are
|
|
117
|
+
rejected instead of silently borrowing the active thread's cwd. Prompt cancellation is routed
|
|
118
|
+
outside `turn_lock`, which lets a client cancel the turn currently holding that lock. The
|
|
119
|
+
`SYSTEM_PROMPT` bakes in smbCloud-specific context the agent should use when the repo is clearly
|
|
120
|
+
smbCloud, and stay general otherwise.
|
|
117
121
|
- **`src/backend.rs`** — the `InferenceBackend` trait and neutral types (`ToolSpec`, `ToolCall`,
|
|
118
122
|
`ToolResult`, `TurnResult`). Two impls: `LocalBackend` (on-device via `onde::ChatEngine`) and
|
|
119
123
|
`OpenAiBackend` (any OpenAI-compatible HTTP endpoint). A `BackendError` is user-facing: the
|
|
@@ -123,6 +127,10 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
123
127
|
endpoint can also fail *after* the response is open, reporting it as a `data:` frame holding
|
|
124
128
|
the same envelope; that frame has no `choices`, so `consume_stream` has to check for it
|
|
125
129
|
explicitly or it parses as an empty chunk and the turn ends looking like an empty answer.
|
|
130
|
+
Some models write tool calls into content as text; `src/inline_tool_calls.rs` recovers the
|
|
131
|
+
well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
|
|
132
|
+
and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
|
|
133
|
+
didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
|
|
126
134
|
- **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
|
|
127
135
|
wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
|
|
128
136
|
`~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
|
|
@@ -131,7 +139,8 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
131
139
|
`multi_edit`, `delete_file`, `run_command`, `write_todos`, `remember`. Add a tool in both the
|
|
132
140
|
spec list (`all_tools`) and the execute `match` (`execute_tool`). `run_command` also enforces
|
|
133
141
|
commit attribution: when a command creates a new commit that lacks the
|
|
134
|
-
`Co-Authored-By: siGit Code` trailer (`
|
|
142
|
+
`Co-Authored-By: siGit Code` trailer (`commit_co_author_trailer()`, which reads
|
|
143
|
+
`siGit Code v<version>-<acp|tui|headless>` from the surface `main` sets via `set_surface`), it amends the trailer in —
|
|
135
144
|
unless the commit already exists on a remote, which is never rewritten. Every child process it
|
|
136
145
|
spawns (`spawn_shell`, the `git` helpers, and `hooks.rs`) sets `stdin` to null and never
|
|
137
146
|
inherits it: in ACP mode sigit's stdin is the JSON-RPC pipe from the editor, so a command that
|
|
@@ -243,12 +252,32 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
243
252
|
`handle_initialize` is what makes the rest of this reachable — without it Zed keeps the first
|
|
244
253
|
root, drops the others, and shows "This agent doesn't currently support multi-root workspaces".
|
|
245
254
|
The process still has one working directory, so the extra roots live in a
|
|
246
|
-
process-global here and `project_dirs()` returns cwd-first, extras after.
|
|
255
|
+
process-global here and `project_dirs()` returns cwd-first, extras after.
|
|
256
|
+
One process also serves every thread the editor has open, so that global
|
|
257
|
+
(with the cwd, the backend conversation, and the background-task owner in
|
|
258
|
+
`tools.rs`) always belongs to the *live* session: `main.rs` keeps a
|
|
259
|
+
`SessionState` per session id and `activate_session` parks the live one and
|
|
260
|
+
installs the requested one before any prompt or config change runs. Don't
|
|
261
|
+
read another session's roots from the global. Project-local
|
|
247
262
|
discovery reads it: skills, slash commands, subagent types, and instruction files all scan
|
|
248
263
|
every root. MCP is deliberately not on that list — `mcp::init` runs once at startup, before
|
|
249
264
|
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell.
|
|
250
265
|
- **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
|
|
251
266
|
`tokio::select!` to multiplex terminal events with streaming tokens.
|
|
267
|
+
- **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
|
|
268
|
+
clients. The legacy `-p` form reaches the same parser. Every new run gets a UUID session id;
|
|
269
|
+
`--resume <id>` restores that session through `session_store`, and `--output jsonl` emits a
|
|
270
|
+
structured session/delta/tool/result stream while logs stay on stderr. Headless permission
|
|
271
|
+
prompts collapse to denial unless the tool was pre-approved with `--allow-tool`.
|
|
272
|
+
- **`src/session_store.rs`** — durable conversations: one JSON-lines history file per session at
|
|
273
|
+
`$SIGIT_CONFIG_DIR/sessions/<id>.jsonl`, written atomically, restorable into either backend.
|
|
274
|
+
Each save also writes a `<id>.meta.json` sidecar naming the session's `cwd` and the extra roots
|
|
275
|
+
of a multi-root project. That sidecar is what makes a thread *listable*: ACP's `session/list`
|
|
276
|
+
(advertised as `sessionCapabilities.list`, handled by `handle_list_sessions` in `main.rs` — the
|
|
277
|
+
editor's "Import Threads" picker) must report an absolute `cwd` per session and may filter on
|
|
278
|
+
it, so a session without one is skipped there while still reopening by id through
|
|
279
|
+
`session/load`. Sidecars are written at save time, not at session start, so a thread nobody
|
|
280
|
+
spoke in leaves nothing behind.
|
|
252
281
|
- **`src/setup.rs`** — model cache location, local model discovery, selected-model persistence.
|
|
253
282
|
Must run (`setup_shared_model_cache`) *before* anything touches `ChatEngine`/`hf-hub`, since
|
|
254
283
|
those read env vars once at init.
|
|
@@ -1,5 +1,145 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 1.5.11
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`sigit run` drives the agent headlessly with resumable sessions.** A new
|
|
10
|
+
non-interactive subcommand runs a prompt through the same agent loop as the
|
|
11
|
+
editor and terminal surfaces, for scripts, CI, and Factory clients. Every run
|
|
12
|
+
gets a UUID session id, writes a JSON-lines history file under
|
|
13
|
+
`~/.config/sigit/sessions/`, and can be restored with `--resume <id>`.
|
|
14
|
+
`--output jsonl` emits a structured session/delta/tool/result stream on
|
|
15
|
+
stdout while logs stay on stderr, and `--allow-tool` pre-approves a tool so
|
|
16
|
+
permission prompts collapse to denial in a non-interactive context. The
|
|
17
|
+
legacy `-p` form still works. Each run also rewrites the session metadata
|
|
18
|
+
with its own cwd and extra roots, so resuming keeps multi-root projects
|
|
19
|
+
|
|
20
|
+
- **Saved threads can be imported into the editor.** siGit Code now advertises
|
|
21
|
+
ACP's `sessionCapabilities.list` and answers `session/list`, so Zed's "Import
|
|
22
|
+
Threads" picker offers the conversations stored under
|
|
23
|
+
`~/.config/sigit/sessions/` instead of reporting that the agent doesn't
|
|
24
|
+
support the capability. A saved session gets a sidecar recording the project
|
|
25
|
+
directory it ran in — listing reports that `cwd`, the extra roots of a
|
|
26
|
+
multi-root project, an ISO 8601 last-activity timestamp, and a title taken
|
|
27
|
+
from the first user message — and a request may filter on `cwd` so one
|
|
28
|
+
project is never offered another's threads. Threads saved before this have no
|
|
29
|
+
sidecar and are not listed; they still reopen by id through `session/load`
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **The commit trailer names the siGit Code version and surface.** Commits
|
|
34
|
+
siGit Code makes now end with
|
|
35
|
+
`Co-Authored-By: siGit Code v<version>-<surface> <noreply@sigit.si>` instead
|
|
36
|
+
of the bare name, where the surface is `acp` (an editor), `tui` (the
|
|
37
|
+
terminal UI), or `headless` (`sigit run`). The model changes from session to
|
|
38
|
+
session; the version and surface tell you which build of the agent wrote the
|
|
39
|
+
commit and how it was driven. GitHub still credits the co-author, since it
|
|
40
|
+
matches on the address. A commit that already carries a siGit Code trailer
|
|
41
|
+
from an older version is left alone
|
|
42
|
+
|
|
43
|
+
- **The terminal UI's model knows which directory the project is in.** The
|
|
44
|
+
editor (ACP) and headless paths put the working directory in the system
|
|
45
|
+
prompt, but the terminal UI only added the project's instruction files, so
|
|
46
|
+
on `/init` a small on-device model invented a `AGENTS.md` path and failed.
|
|
47
|
+
All three places the terminal UI builds a prompt now go through the same
|
|
48
|
+
session context path the ACP sessions get. The cloud tier switch had also
|
|
49
|
+
been dropping the instruction files; that's fixed too
|
|
50
|
+
|
|
51
|
+
- **An empty `write_todos` list clears the plan.** `write_todos` rejected an
|
|
52
|
+
empty list, so the model had no way to clear a finished checklist and the
|
|
53
|
+
last plan stayed in the editor until the session ended. An empty list now
|
|
54
|
+
returns "Task list cleared." and goes to the client as an ACP plan with no
|
|
55
|
+
entries. The tool description tells the model it can do this
|
|
56
|
+
|
|
57
|
+
- **`sigit run` gives clearer usage errors.** A second positional prompt says
|
|
58
|
+
"unexpected extra argument", a bare `sigit run` says "missing prompt", and a
|
|
59
|
+
mistyped flag like `--quite` is rejected instead of becoming the prompt
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **Each ACP session keeps its own roots, conversation, and tasks.** Zed runs
|
|
64
|
+
one siGit process for every open thread, but the process had a single cwd,
|
|
65
|
+
workspace root list, backend conversation, and background task table. The
|
|
66
|
+
most recent session owned all of them, so a prompt from an older thread ran
|
|
67
|
+
against another repo with another thread's history. A `SessionState` is now
|
|
68
|
+
kept per session id; before a prompt or config change runs, the live
|
|
69
|
+
conversation is parked and the requested session's cwd, extra roots, and
|
|
70
|
+
conversation are installed, rebuilding the system prompt from its roots.
|
|
71
|
+
`new`/`load`/`fork` share a single session-opening path, and fork carries the
|
|
72
|
+
source thread's conversation. Background tasks are scoped to the session that
|
|
73
|
+
started them, opening a session no longer wipes every other session's
|
|
74
|
+
permission grants, and model selection is routed per session
|
|
75
|
+
|
|
76
|
+
- **New sessions no longer carry the previous thread's history.** Opening a
|
|
77
|
+
new thread in Zed showed a `[Conversation summary]` from an earlier session.
|
|
78
|
+
The session handlers cleared the on-device engine but not the history a cloud
|
|
79
|
+
backend keeps for itself, and the startup routing to the cloud tier then
|
|
80
|
+
carried that history into the installed backend. A provider override had the
|
|
81
|
+
same leak. All session entry points now share a path that strips stale
|
|
82
|
+
history too, and unknown session ids are rejected instead of borrowing the
|
|
83
|
+
live thread's state
|
|
84
|
+
|
|
85
|
+
- **Unparseable tool-call markup is hidden and retried, not shown as text.**
|
|
86
|
+
Some models write tool calls into the reply as text. Well-formed blocks were
|
|
87
|
+
already recovered and run, but a block that failed to parse or never closed
|
|
88
|
+
was printed to the editor as-is and stayed in history, so the model later
|
|
89
|
+
read back a call it had "made" with no result and began writing invented
|
|
90
|
+
`<function_results>`. The scanner now reports those blocks as malformed; the
|
|
91
|
+
backend drops them from the reply and history, and when the only tool call
|
|
92
|
+
was malformed the model gets one retry telling it the call didn't run. A
|
|
93
|
+
block that merely *mentions* a tool-call marker (a backticked `<tool_call>` or an
|
|
94
|
+
unclosed XTML `<|open|>tools`) is now kept as prose, so a reply explaining
|
|
95
|
+
the scanner no longer loses everything after the first marker. The
|
|
96
|
+
non-streamed path now strips broken blocks beside structured calls and runs
|
|
97
|
+
any inline calls that did parse, matching the streaming path
|
|
98
|
+
|
|
99
|
+
- **The co-author trailer ends a conflicted merge commit.** Finishing a
|
|
100
|
+
conflicted merge with `git commit --no-edit` keeps git's `# Conflicts:` list
|
|
101
|
+
in the message, since no editor runs to strip it. When siGit Code then added
|
|
102
|
+
its trailer, the trailer went in above that list, so it was no longer the last
|
|
103
|
+
paragraph and GitHub didn't credit the co-author. The amend now drops the
|
|
104
|
+
leftover comment block and puts the trailer last. It also fixes a commit
|
|
105
|
+
that already has the trailer but still ends in that block
|
|
106
|
+
|
|
107
|
+
## 1.5.10
|
|
108
|
+
|
|
109
|
+
### What changed
|
|
110
|
+
|
|
111
|
+
- **Xcode's context no longer buries slash commands.** Xcode sends the user's
|
|
112
|
+
prompt as the last of several text blocks, with project context in the
|
|
113
|
+
blocks before it, so `/models` and friends sat in the middle of joined text
|
|
114
|
+
and were handed to the model instead of dispatching locally. Slash-command
|
|
115
|
+
parsing now searches the prompt's text blocks from the end, so a standalone
|
|
116
|
+
command in the final user block dispatches no matter what context the client
|
|
117
|
+
prepends
|
|
118
|
+
- **The nova tier is the default cloud engine.** When local inference is off
|
|
119
|
+
and no explicit provider override is set, the cloud tier now defaults to
|
|
120
|
+
`nova` (the `onde-nova` model) instead of the balanced tier, in both the
|
|
121
|
+
interactive and headless paths
|
|
122
|
+
|
|
123
|
+
### Fixed
|
|
124
|
+
|
|
125
|
+
- **Malformed Chinese-model tool calls are handled end-to-end in ACP.** The
|
|
126
|
+
inline-call recovery that 1.5.9 added for Kimi K3's XTML protocol and GLM's
|
|
127
|
+
mis-tagged blocks only applied to the interactive and headless surfaces;
|
|
128
|
+
the ACP path never ran it, so an editor session still surfaced raw protocol
|
|
129
|
+
text and dropped the calls. Recovery now runs in the ACP prompt loop too,
|
|
130
|
+
covered by integration tests, and the tool names are checked against the
|
|
131
|
+
turn's offered tools before anything executes
|
|
132
|
+
- **Suppressed tool-call log spam is gone.** The guard that logs when a
|
|
133
|
+
structured call is dropped for arriving as forced text fired once per
|
|
134
|
+
streamed argument fragment — one malformed call could log a warning per
|
|
135
|
+
chunk. The check now fires once per turn with the count and names of what
|
|
136
|
+
was dropped, and the non-streaming path reports the same
|
|
137
|
+
- **A history-replay test no longer races on the process cwd.** One ACP test
|
|
138
|
+
built its expected path from `std::env::current_dir()` while other tests
|
|
139
|
+
briefly swap that process-global cwd, so on CI it could read a temp
|
|
140
|
+
directory mid-swap and compare a truncated title against an untruncated
|
|
141
|
+
expectation. It now uses a fixed path it never needed to derive
|
|
142
|
+
|
|
3
143
|
## 1.5.9
|
|
4
144
|
|
|
5
145
|
### Fixed
|
|
@@ -111,9 +111,13 @@ The agent loop is backend-agnostic. The flow: a turn (messages + tool specs) goe
|
|
|
111
111
|
feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete backend.
|
|
112
112
|
|
|
113
113
|
- **`src/main.rs`** — entry point, mode dispatch, the full ACP `Agent` impl (session lifecycle:
|
|
114
|
-
new/load/fork/prompt/cancel, config options, slash-command advertisement), and the `SYSTEM_PROMPT
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
new/load/fork/prompt/cancel, config options, slash-command advertisement), and the `SYSTEM_PROMPT`.
|
|
115
|
+
ACP session state owns its roots, conversation, and selected model even though the process has
|
|
116
|
+
one live backend; activating a thread parks and restores all three. Unknown session ids are
|
|
117
|
+
rejected instead of silently borrowing the active thread's cwd. Prompt cancellation is routed
|
|
118
|
+
outside `turn_lock`, which lets a client cancel the turn currently holding that lock. The
|
|
119
|
+
`SYSTEM_PROMPT` bakes in smbCloud-specific context the agent should use when the repo is clearly
|
|
120
|
+
smbCloud, and stay general otherwise.
|
|
117
121
|
- **`src/backend.rs`** — the `InferenceBackend` trait and neutral types (`ToolSpec`, `ToolCall`,
|
|
118
122
|
`ToolResult`, `TurnResult`). Two impls: `LocalBackend` (on-device via `onde::ChatEngine`) and
|
|
119
123
|
`OpenAiBackend` (any OpenAI-compatible HTTP endpoint). A `BackendError` is user-facing: the
|
|
@@ -123,6 +127,10 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
123
127
|
endpoint can also fail *after* the response is open, reporting it as a `data:` frame holding
|
|
124
128
|
the same envelope; that frame has no `choices`, so `consume_stream` has to check for it
|
|
125
129
|
explicitly or it parses as an empty chunk and the turn ends looking like an empty answer.
|
|
130
|
+
Some models write tool calls into content as text; `src/inline_tool_calls.rs` recovers the
|
|
131
|
+
well-formed ones. A block that doesn't parse (or never closes) is dropped from both the reply
|
|
132
|
+
and history, and `OpenAiBackend::complete` retries once with a note telling the model the call
|
|
133
|
+
didn't run. Leaving the raw block in history makes the model invent `<function_results>` later.
|
|
126
134
|
- **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
|
|
127
135
|
wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
|
|
128
136
|
`~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
|
|
@@ -131,7 +139,8 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
131
139
|
`multi_edit`, `delete_file`, `run_command`, `write_todos`, `remember`. Add a tool in both the
|
|
132
140
|
spec list (`all_tools`) and the execute `match` (`execute_tool`). `run_command` also enforces
|
|
133
141
|
commit attribution: when a command creates a new commit that lacks the
|
|
134
|
-
`Co-Authored-By: siGit Code` trailer (`
|
|
142
|
+
`Co-Authored-By: siGit Code` trailer (`commit_co_author_trailer()`, which reads
|
|
143
|
+
`siGit Code v<version>-<acp|tui|headless>` from the surface `main` sets via `set_surface`), it amends the trailer in —
|
|
135
144
|
unless the commit already exists on a remote, which is never rewritten. Every child process it
|
|
136
145
|
spawns (`spawn_shell`, the `git` helpers, and `hooks.rs`) sets `stdin` to null and never
|
|
137
146
|
inherits it: in ACP mode sigit's stdin is the JSON-RPC pipe from the editor, so a command that
|
|
@@ -243,12 +252,32 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
243
252
|
`handle_initialize` is what makes the rest of this reachable — without it Zed keeps the first
|
|
244
253
|
root, drops the others, and shows "This agent doesn't currently support multi-root workspaces".
|
|
245
254
|
The process still has one working directory, so the extra roots live in a
|
|
246
|
-
process-global here and `project_dirs()` returns cwd-first, extras after.
|
|
255
|
+
process-global here and `project_dirs()` returns cwd-first, extras after.
|
|
256
|
+
One process also serves every thread the editor has open, so that global
|
|
257
|
+
(with the cwd, the backend conversation, and the background-task owner in
|
|
258
|
+
`tools.rs`) always belongs to the *live* session: `main.rs` keeps a
|
|
259
|
+
`SessionState` per session id and `activate_session` parks the live one and
|
|
260
|
+
installs the requested one before any prompt or config change runs. Don't
|
|
261
|
+
read another session's roots from the global. Project-local
|
|
247
262
|
discovery reads it: skills, slash commands, subagent types, and instruction files all scan
|
|
248
263
|
every root. MCP is deliberately not on that list — `mcp::init` runs once at startup, before
|
|
249
264
|
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell.
|
|
250
265
|
- **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
|
|
251
266
|
`tokio::select!` to multiplex terminal events with streaming tokens.
|
|
267
|
+
- **`src/headless.rs`** — non-interactive `sigit run` execution for scripts, CI, and Factory
|
|
268
|
+
clients. The legacy `-p` form reaches the same parser. Every new run gets a UUID session id;
|
|
269
|
+
`--resume <id>` restores that session through `session_store`, and `--output jsonl` emits a
|
|
270
|
+
structured session/delta/tool/result stream while logs stay on stderr. Headless permission
|
|
271
|
+
prompts collapse to denial unless the tool was pre-approved with `--allow-tool`.
|
|
272
|
+
- **`src/session_store.rs`** — durable conversations: one JSON-lines history file per session at
|
|
273
|
+
`$SIGIT_CONFIG_DIR/sessions/<id>.jsonl`, written atomically, restorable into either backend.
|
|
274
|
+
Each save also writes a `<id>.meta.json` sidecar naming the session's `cwd` and the extra roots
|
|
275
|
+
of a multi-root project. That sidecar is what makes a thread *listable*: ACP's `session/list`
|
|
276
|
+
(advertised as `sessionCapabilities.list`, handled by `handle_list_sessions` in `main.rs` — the
|
|
277
|
+
editor's "Import Threads" picker) must report an absolute `cwd` per session and may filter on
|
|
278
|
+
it, so a session without one is skipped there while still reopening by id through
|
|
279
|
+
`session/load`. Sidecars are written at save time, not at session start, so a thread nobody
|
|
280
|
+
spoke in leaves nothing behind.
|
|
252
281
|
- **`src/setup.rs`** — model cache location, local model discovery, selected-model persistence.
|
|
253
282
|
Must run (`setup_shared_model_cache`) *before* anything touches `ChatEngine`/`hf-hub`, since
|
|
254
283
|
those read env vars once at init.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sigit-code
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.11
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Environment :: Console
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -57,7 +57,8 @@ This installs a native `sigit` binary for your platform. You do not need a compi
|
|
|
57
57
|
sigit
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
That opens the local chat UI.
|
|
60
|
+
That opens the local chat UI. Editors drive the same binary in ACP mode, which
|
|
61
|
+
needs the `--acp` argument.
|
|
61
62
|
|
|
62
63
|
### Zed
|
|
63
64
|
|
|
@@ -68,7 +69,8 @@ siGit Code works as an [ACP-compatible](https://github.com/nicobailon/agent-clie
|
|
|
68
69
|
"agent_servers": {
|
|
69
70
|
"siGit Code": {
|
|
70
71
|
"type": "custom",
|
|
71
|
-
"command": "/absolute/path/to/sigit"
|
|
72
|
+
"command": "/absolute/path/to/sigit",
|
|
73
|
+
"args": ["--acp"]
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
<a href="https://github.com/getsigit/sigit/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-235843?style=flat-square&labelColor=17211D" alt="License"></a>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
siGit Code is
|
|
11
|
+
siGit Code is the local agent runtime for **siGit Factory**. It runs on your machine by default,
|
|
12
|
+
with optional cloud inference and remote automation when you choose them.
|
|
12
13
|
|
|
13
14
|
Its home is [code.sigit.si](https://code.sigit.si). You can run it yourself, as below, or use the hosted version (siGit Code Cloud) there if you would rather not run a model locally. [sigit.si](https://sigit.si) is Git hosting built for AI workflows.
|
|
14
15
|
|
|
@@ -16,9 +17,13 @@ It works in any codebase. In smbCloud repos it is more useful out of the box bec
|
|
|
16
17
|
|
|
17
18
|
You can use it in two ways:
|
|
18
19
|
|
|
19
|
-
- **ACP mode:** Zed or another ACP-compatible editor starts it over stdio
|
|
20
|
+
- **ACP mode:** Zed or another ACP-compatible editor starts it over stdio with the `--acp` argument
|
|
20
21
|
- **Terminal mode:** run `sigit` for the interactive chat UI
|
|
21
22
|
|
|
23
|
+
Every ACP client must pass `--acp`. It takes no other arguments, and it is what
|
|
24
|
+
tells the binary to speak the Agent Client Protocol instead of opening the
|
|
25
|
+
terminal UI.
|
|
26
|
+
|
|
22
27
|
| Platform | ACP mode | Terminal mode |
|
|
23
28
|
|----------|----------|---------------|
|
|
24
29
|
| macOS | ✓ | ✓ |
|
|
@@ -59,7 +64,8 @@ Add this to `~/.config/zed/settings.json`:
|
|
|
59
64
|
"agent_servers": {
|
|
60
65
|
"siGit Code": {
|
|
61
66
|
"type": "custom",
|
|
62
|
-
"command": "/absolute/path/to/sigit"
|
|
67
|
+
"command": "/absolute/path/to/sigit",
|
|
68
|
+
"args": ["--acp"]
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
}
|
|
@@ -74,8 +80,8 @@ In Xcode, open **Settings > Intelligence > Agents**, add a custom agent, and set
|
|
|
74
80
|
- **Executable:** the absolute path to `sigit`
|
|
75
81
|
- **Arguments:** `--acp`
|
|
76
82
|
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
In Xcode the `--acp` mode also loads the selected on-device model on the first
|
|
84
|
+
prompt, so you do not need to send `/load` from the Xcode chat.
|
|
79
85
|
|
|
80
86
|
To let siGit use Xcode's build, test, and project tools, enable **Allow external
|
|
81
87
|
agents to use Xcode tools** in Xcode's Intelligence settings, keep the project
|
|
@@ -100,7 +106,7 @@ Install from the [Visual Studio Code Marketplace](https://marketplace.visualstud
|
|
|
100
106
|
"sigit": {
|
|
101
107
|
"name": "siGit (on-device)",
|
|
102
108
|
"command": "sigit",
|
|
103
|
-
"args": [],
|
|
109
|
+
"args": ["--acp"],
|
|
104
110
|
"env": {}
|
|
105
111
|
},
|
|
106
112
|
},
|
|
@@ -117,7 +123,7 @@ Install [ACP Client](https://marketplace.visualstudio.com/items?itemName=formula
|
|
|
117
123
|
"acp.agents": {
|
|
118
124
|
"siGit Code": {
|
|
119
125
|
"command": "sigit",
|
|
120
|
-
"args": [],
|
|
126
|
+
"args": ["--acp"],
|
|
121
127
|
"env": {}
|
|
122
128
|
}
|
|
123
129
|
}
|
|
@@ -130,6 +136,34 @@ Run `sigit` in a terminal and you get the same model and system prompt as the ed
|
|
|
130
136
|
|
|
131
137
|
Terminal mode currently needs Unix terminal behavior, so it works on macOS and Linux only.
|
|
132
138
|
|
|
139
|
+
## Headless and CI mode
|
|
140
|
+
|
|
141
|
+
Use `sigit run` to execute the same agent from scripts, CI, or another siGit Factory client:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
sigit run "Review this repository and run the focused tests" --cwd .
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Every run receives a durable session ID. The ID is printed to stderr in text mode and included
|
|
148
|
+
in every event in JSONL mode. Resume the same conversation from a later command—or import it in
|
|
149
|
+
an ACP client—by passing that ID:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
sigit run "Continue with the next issue" --resume <session-id>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
For automation, JSONL output provides session, assistant-delta, tool-call, tool-result, result,
|
|
156
|
+
and error events on stdout. Logs remain on stderr.
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
sigit run "Run the checks" --output jsonl --allow-tool run_command
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Mutating tools still follow siGit's permission policy. Because a headless run cannot answer an
|
|
163
|
+
interactive permission prompt, approve only the tools the run needs with repeatable
|
|
164
|
+
`--allow-tool` flags. The legacy `sigit -p "<prompt>"` form remains supported. See the
|
|
165
|
+
[headless execution reference](docs/headless.md) for the event contract and exit codes.
|
|
166
|
+
|
|
133
167
|
## Platform support
|
|
134
168
|
|
|
135
169
|
| Platform | Architecture |
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Headless execution
|
|
2
|
+
|
|
3
|
+
`sigit run` exposes the siGit Code agent runtime to scripts, CI, and siGit Factory clients.
|
|
4
|
+
It uses the same provider selection, project instructions, skills, tools, MCP servers, and
|
|
5
|
+
permission policy as the interactive and ACP surfaces.
|
|
6
|
+
|
|
7
|
+
## Run and resume
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
sigit run "Review this repository" --cwd /path/to/repository
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
A new run receives a UUID session ID and saves its conversation under the siGit configuration
|
|
14
|
+
directory. Text mode prints the ID to stderr as `Session: <id>`. Resume it later with:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
sigit run "Continue with the fixes" --resume <id>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The saved metadata includes the primary working directory, additional project roots, and model.
|
|
21
|
+
This makes the same session discoverable through ACP `session/list` and loadable by an editor.
|
|
22
|
+
Each run rewrites that metadata with its own `--cwd` and `--add-dir` values, so a resume records
|
|
23
|
+
where the session last ran. Pass the same `--add-dir` flags again to keep extra roots attached.
|
|
24
|
+
|
|
25
|
+
Use repeatable `--add-dir <path>` flags for multi-root workspaces. Mutating tools that would ask
|
|
26
|
+
for interactive permission are denied in headless mode unless granted with
|
|
27
|
+
`--allow-tool <name>`. A repeatable `--deny-tool <name>` takes precedence over grants and
|
|
28
|
+
settings.
|
|
29
|
+
|
|
30
|
+
## JSONL output
|
|
31
|
+
|
|
32
|
+
Pass `--output jsonl` for a machine-readable stdout stream:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
sigit run "Run the focused tests" --output jsonl --allow-tool run_command
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Each line is one JSON object. Every event includes `type` and `session_id`. A run that gets as far
|
|
39
|
+
as inference starts with a `session` event. A run that fails before that, because no remote
|
|
40
|
+
provider is configured or the `--resume` session doesn't exist, emits a single `error` event and
|
|
41
|
+
nothing else.
|
|
42
|
+
|
|
43
|
+
| Type | Additional fields | Meaning |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `session` | `resumed` | Identifies the run before inference starts. |
|
|
46
|
+
| `assistant_delta` | `text` | One visible streamed response fragment. |
|
|
47
|
+
| `tool_call` | `tool_call_id`, `name`, `arguments` | A tool requested by the model. `arguments` is the tool's JSON string. |
|
|
48
|
+
| `tool_result` | `tool_call_id`, `name`, `content` | The executed result or permission denial returned to the model. |
|
|
49
|
+
| `result` | `text`, `tool_rounds` | The completed turn and its final visible text. |
|
|
50
|
+
| `error` | `message` | A provider, session, or inference failure. |
|
|
51
|
+
|
|
52
|
+
Logs and diagnostics stay on stderr. `--quiet` applies only to text output and cannot be combined
|
|
53
|
+
with JSONL output.
|
|
54
|
+
|
|
55
|
+
## Exit codes
|
|
56
|
+
|
|
57
|
+
| Code | Meaning |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `0` | The turn completed, including turns where a tool was denied by policy. |
|
|
60
|
+
| `1` | Provider resolution, session restoration, inference, or tool-loop failure. |
|
|
61
|
+
| `2` | Invalid command-line arguments or working directories. |
|
|
62
|
+
|
|
63
|
+
The earlier `sigit -p "<prompt>"` syntax remains an alias for headless execution and accepts the
|
|
64
|
+
same flags.
|