sigit-code 1.5.6__tar.gz → 1.5.8__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.6 → sigit_code-1.5.8}/.agents/AGENTS.md +42 -8
- {sigit_code-1.5.6/.claude → sigit_code-1.5.8/.agents}/skills/agent-client-protocol/SKILL.md +19 -4
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.agents/skills/sigit-code-release/SKILL.md +3 -0
- {sigit_code-1.5.6/.agents → sigit_code-1.5.8/.claude}/skills/agent-client-protocol/SKILL.md +19 -4
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.claude/skills/sigit-code-release/SKILL.md +3 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-aur.yml +8 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-crates.yml +34 -6
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-github.yml +8 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-homebrew.yml +8 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-npm.yml +75 -32
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-nuget.yml +37 -6
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-pypi.yml +29 -6
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-scoop.yml +8 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/release-winget.yml +8 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.gitignore +1 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/AGENTS.md +42 -8
- {sigit_code-1.5.6 → sigit_code-1.5.8}/CHANGELOG.md +134 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/CLAUDE.md +42 -8
- {sigit_code-1.5.6 → sigit_code-1.5.8}/Cargo.lock +1 -1
- {sigit_code-1.5.6 → sigit_code-1.5.8}/Cargo.toml +1 -1
- {sigit_code-1.5.6 → sigit_code-1.5.8}/PKG-INFO +1 -1
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/README.md.tmpl +1 -1
- sigit_code-1.5.8/npm/package-compat.json.tmpl +41 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/package.json.tmpl +1 -1
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/scripts/render-main-package.cjs +8 -7
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/scripts/render-platform-package.cjs +11 -3
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/sigit/README.md +8 -0
- sigit_code-1.5.8/npm/sigit/src/index.ts +74 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/backend.rs +354 -24
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/chat.rs +127 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/commands.rs +5 -4
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/headless.rs +42 -5
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/hooks.rs +3 -0
- sigit_code-1.5.8/src/inline_tool_calls.rs +420 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/instructions.rs +51 -5
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/main.rs +911 -132
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/models.rs +50 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/permissions.rs +132 -7
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/settings.rs +12 -25
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/skills.rs +5 -4
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/subagents.rs +5 -4
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/tools.rs +142 -15
- sigit_code-1.5.8/src/workspace.rs +160 -0
- sigit_code-1.5.8/tests/acp_endpoint_errors.rs +356 -0
- sigit_code-1.5.8/tests/acp_multi_root.rs +254 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/tests/acp_permissions.rs +546 -0
- sigit_code-1.5.8/tests/acp_session_load.rs +320 -0
- sigit_code-1.5.8/tests/acp_tool_stdin.rs +235 -0
- sigit_code-1.5.6/npm/sigit/src/index.ts +0 -43
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.agents/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.agents/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.agents/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.agents/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.agents/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.agents/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.claude/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.claude/skills/branding/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.claude/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.claude/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.claude/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.claude/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.github/workflows/ci.yml +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/.nvmrc +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/LICENSE +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/README.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/docs/hooks.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/docs/mcp.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/examples/settings-with-hooks.toml +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/examples/skills/README.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/examples/skills/commit-message/SKILL.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/package-main.json.tmpl +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/sigit/.gitignore +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/sigit/package.json +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/npm/sigit/tsconfig.json +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/nuget/.gitignore +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/nuget/sigit/Program.cs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/nuget/sigit/README.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/nuget/sigit/SiGit.Code.csproj +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/packaging/aur/PKGBUILD.in +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/packaging/nfpm.yaml +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/packaging/winget/getSigit.siGitCode.installer.yaml.in +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/packaging/winget/getSigit.siGitCode.locale.en-US.yaml.in +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/packaging/winget/getSigit.siGitCode.yaml.in +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/pypi/README.md +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/pypi/pyproject.toml +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/pyproject.toml +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/rust-toolchain.toml +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/account.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/browser_auth.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/credentials.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/frontmatter.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/mcp.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/provider.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/session_store.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/src/setup.rs +0 -0
- {sigit_code-1.5.6 → sigit_code-1.5.8}/tests/headless_mode.rs +0 -0
|
@@ -116,7 +116,13 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
116
116
|
smbCloud, and stay general otherwise).
|
|
117
117
|
- **`src/backend.rs`** — the `InferenceBackend` trait and neutral types (`ToolSpec`, `ToolCall`,
|
|
118
118
|
`ToolResult`, `TurnResult`). Two impls: `LocalBackend` (on-device via `onde::ChatEngine`) and
|
|
119
|
-
`OpenAiBackend` (any OpenAI-compatible HTTP endpoint).
|
|
119
|
+
`OpenAiBackend` (any OpenAI-compatible HTTP endpoint). A `BackendError` is user-facing: the
|
|
120
|
+
ACP prompt handler passes it to the client verbatim and the editor puts it in an error banner,
|
|
121
|
+
so `describe_api_error` unwraps the OpenAI `{"error":{"message":…}}` envelope and shows that
|
|
122
|
+
message on its own, falling back to the status only when there is nothing to unwrap. An
|
|
123
|
+
endpoint can also fail *after* the response is open, reporting it as a `data:` frame holding
|
|
124
|
+
the same envelope; that frame has no `choices`, so `consume_stream` has to check for it
|
|
125
|
+
explicitly or it parses as an empty chunk and the turn ends looking like an empty answer.
|
|
120
126
|
- **`src/provider.rs`** — decides *which* backend serves inference. Resolution order, first match
|
|
121
127
|
wins: (1) override via `OPENAI_BASE_URL`+`OPENAI_API_KEY` or active profile in
|
|
122
128
|
`~/.config/sigit/providers.toml`; (2) siGit Code Cloud when logged in; (3) on-device.
|
|
@@ -126,7 +132,13 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
126
132
|
spec list (`all_tools`) and the execute `match` (`execute_tool`). `run_command` also enforces
|
|
127
133
|
commit attribution: when a command creates a new commit that lacks the
|
|
128
134
|
`Co-Authored-By: siGit Code` trailer (`COMMIT_CO_AUTHOR_TRAILER`), it amends the trailer in —
|
|
129
|
-
unless the commit already exists on a remote, which is never rewritten.
|
|
135
|
+
unless the commit already exists on a remote, which is never rewritten. Every child process it
|
|
136
|
+
spawns (`spawn_shell`, the `git` helpers, and `hooks.rs`) sets `stdin` to null and never
|
|
137
|
+
inherits it: in ACP mode sigit's stdin is the JSON-RPC pipe from the editor, so a command that
|
|
138
|
+
reads stdin both blocks forever and eats the client's next request, wedging the session past
|
|
139
|
+
any timeout. On Unix the shell also leads its own process group so the timeout kills the whole
|
|
140
|
+
tree, and stdout/stderr are drained on threads while the command runs — waiting first and
|
|
141
|
+
reading after deadlocks as soon as the output outgrows the pipe buffer. Also owns the `task`
|
|
130
142
|
tool: a nested agent loop in a fresh conversation, offered only when `subagent_available()`
|
|
131
143
|
(a subagent factory is registered — see `register_subagent_factory_for` in `main.rs`; on-device
|
|
132
144
|
registers a `None`-returning factory since onde has a single shared history). A subagent's
|
|
@@ -145,7 +157,8 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
145
157
|
HTTP/JSON-RPC implementation.
|
|
146
158
|
- **`src/skills.rs`** — [Agent Skills](https://agentskills.io) support. Discovers skill
|
|
147
159
|
folders (each with a `SKILL.md`: YAML frontmatter `name` + `description`, then Markdown
|
|
148
|
-
instructions) from `.sigit/skills/` and `.claude/skills/` in
|
|
160
|
+
instructions) from `.sigit/skills/` and `.claude/skills/` in every project root (see `src/workspace.rs`),
|
|
161
|
+
`$SIGIT_CONFIG_DIR/skills/`,
|
|
149
162
|
and `~/.claude/skills/`. Progressive disclosure: the discovery list (name + description) is
|
|
150
163
|
baked into the dynamically-built `skill` tool's description, and activating a skill (the model
|
|
151
164
|
calls `skill` with a name) loads the full `SKILL.md` body. The `skill` tool is appended in the
|
|
@@ -153,7 +166,7 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
153
166
|
and only when at least one skill exists.
|
|
154
167
|
- **`src/commands.rs`** — user-defined slash commands. Discovers Markdown files (each an
|
|
155
168
|
optional YAML frontmatter block — `description`, `argument-hint` — followed by a prompt-template
|
|
156
|
-
body) from `.sigit/commands/` and `.claude/commands/` in
|
|
169
|
+
body) from `.sigit/commands/` and `.claude/commands/` in every project root, `$SIGIT_CONFIG_DIR/commands/`,
|
|
157
170
|
and `~/.claude/commands/`. A subdirectory namespaces the command with `:`
|
|
158
171
|
(`.sigit/commands/git/commit.md` → `/git:commit`). Unlike skills there's no tool-call
|
|
159
172
|
indirection: invoking one works exactly like the built-in `/init` — `commands::render`
|
|
@@ -167,7 +180,7 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
167
180
|
- **`src/subagents.rs`** — configurable subagent types for the `task` tool. Discovers Markdown
|
|
168
181
|
files (YAML frontmatter `name` + `description`, optional comma-separated `tools:` allow-list,
|
|
169
182
|
then a Markdown body that becomes the subagent's system prompt) from `.sigit/agents/` and
|
|
170
|
-
`.claude/agents/` in
|
|
183
|
+
`.claude/agents/` in every project root, `$SIGIT_CONFIG_DIR/agents/`, and `~/.claude/agents/`. Passing a
|
|
171
184
|
type's `name` as `task`'s `subagent_type` argument swaps in that system prompt and, if `tools:`
|
|
172
185
|
is set, narrows the offered toolset to its *intersection* with `SUBAGENT_TOOL_NAMES` — the
|
|
173
186
|
security-relevant narrowing logic lives in `tools.rs` next to that constant, not here; this
|
|
@@ -218,9 +231,22 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
218
231
|
Reads `AGENTS.md` (the cross-tool [agents.md](https://agents.md) standard) and `CLAUDE.md`,
|
|
219
232
|
walking from the session cwd up to the repo root (nearest ancestor with `.git`, never above it),
|
|
220
233
|
plus a global file under `$SIGIT_CONFIG_DIR`. Files are ordered outermost-first so the deepest
|
|
221
|
-
(most specific) wins.
|
|
222
|
-
|
|
223
|
-
|
|
234
|
+
(most specific) wins. In a multi-root project that walk is repeated for every root
|
|
235
|
+
(`load_workspace_instructions`). The combined block is injected via `session_context_message`
|
|
236
|
+
in `main.rs` — pushed as a system message at every ACP session entry point (new/load/fork +
|
|
237
|
+
model switch) and appended to the system prompt on the cloud and TUI-startup paths.
|
|
238
|
+
- **`src/workspace.rs`** — the directories the session treats as project roots. An editor can
|
|
239
|
+
open several at once (Zed calls it a multi-root project) and ACP carries the extras as
|
|
240
|
+
`additional_directories` on every session request; the headless CLI takes them as repeatable
|
|
241
|
+
`--add-dir` flags. A client only sends those extras to an agent that advertises
|
|
242
|
+
`sessionCapabilities.additionalDirectories` in its `initialize` reply, so that capability in
|
|
243
|
+
`handle_initialize` is what makes the rest of this reachable — without it Zed keeps the first
|
|
244
|
+
root, drops the others, and shows "This agent doesn't currently support multi-root workspaces".
|
|
245
|
+
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. Project-local
|
|
247
|
+
discovery reads it: skills, slash commands, subagent types, and instruction files all scan
|
|
248
|
+
every root. MCP is deliberately not on that list — `mcp::init` runs once at startup, before
|
|
249
|
+
any session exists, so a second root's `.sigit/mcp.toml` has nobody to tell.
|
|
224
250
|
- **`src/chat.rs`** — the Unix-only ratatui TUI. Loading-spinner phase then chat; uses
|
|
225
251
|
`tokio::select!` to multiplex terminal events with streaming tokens.
|
|
226
252
|
- **`src/setup.rs`** — model cache location, local model discovery, selected-model persistence.
|
|
@@ -301,6 +327,14 @@ winget, and the AUR PKGBUILD each need one, and they consume the raw binaries ra
|
|
|
301
327
|
tarball. `release-github` also builds a `.deb` and `.rpm` per Linux target with nfpm
|
|
302
328
|
(`packaging/nfpm.yaml`), packaging the already-built binary rather than re-invoking cargo.
|
|
303
329
|
|
|
330
|
+
Re-pushing a tag fires every release workflow a second time, so each one is grouped by tag in a
|
|
331
|
+
`concurrency` block with `cancel-in-progress: false` — the duplicate queues behind the original
|
|
332
|
+
rather than interrupting a publish that is halfway through uploading. What keeps the queued run
|
|
333
|
+
from going red is the "is this version already published?" check each publishing workflow does
|
|
334
|
+
before it uploads. Those checks are load-bearing, not belt-and-braces: v1.5.6 published twice
|
|
335
|
+
because the crates.io one asked the API with curl's default User-Agent, which crates.io answers
|
|
336
|
+
with a 403, which read as "not published yet".
|
|
337
|
+
|
|
304
338
|
Three of these need credentials or a one-time manual step before they work:
|
|
305
339
|
|
|
306
340
|
- Scoop needs a `getsigit/scoop-bucket` repo and a `SCOOP_BUCKET_TOKEN` secret, mirroring the
|
|
@@ -271,8 +271,14 @@ Ok(ForkSessionResponse::new(new_id).config_options(config_options))
|
|
|
271
271
|
per-session picker (see Config options below).
|
|
272
272
|
|
|
273
273
|
The session requests carry `cwd: PathBuf` and (with the feature)
|
|
274
|
-
`additional_directories: Vec<PathBuf
|
|
275
|
-
|
|
274
|
+
`additional_directories: Vec<PathBuf>` — the other directories of a multi-root
|
|
275
|
+
project, sent only to an agent whose `initialize` reply carries
|
|
276
|
+
`SessionCapabilities::new().additional_directories(SessionAdditionalDirectoriesCapabilities::new())`. `SiGitAgent::enter_session_roots` stashes `cwd`, `set_current_dir`s to
|
|
277
|
+
it, hands the extras to `workspace::set_additional_roots`, and returns the ones
|
|
278
|
+
that survived (a root that isn't a directory, repeats, or just names `cwd` again
|
|
279
|
+
is dropped). `session_context_message` then names every root in the system
|
|
280
|
+
message, and project-local discovery — skills, slash commands, subagent types,
|
|
281
|
+
instruction files — scans all of them, primary root first.
|
|
276
282
|
|
|
277
283
|
### `PromptRequest` / blocks
|
|
278
284
|
|
|
@@ -555,8 +561,17 @@ Editor Agent
|
|
|
555
561
|
10. **Zed re-fires the last config selection on connect** — make
|
|
556
562
|
`setConfigOption` a no-op when the requested model is already active, and
|
|
557
563
|
never start a model switch while a startup load is still in flight (GPU OOM).
|
|
558
|
-
11.
|
|
559
|
-
|
|
564
|
+
11. **`additional_directories` is not decoration** — dropping it means a
|
|
565
|
+
multi-root project silently behaves as if only the first root existed, with
|
|
566
|
+
the other repositories' `AGENTS.md` and skills missing. Route it through
|
|
567
|
+
`workspace.rs`, not just the log line. Handling it is also only half the
|
|
568
|
+
job: Zed gates the field on
|
|
569
|
+
`agentCapabilities.sessionCapabilities.additionalDirectories` being present
|
|
570
|
+
in the `initialize` reply, so an agent that reads the field but never
|
|
571
|
+
advertises the capability is never sent one, and the user gets a banner
|
|
572
|
+
saying the agent has no multi-root support.
|
|
573
|
+
12. **Store `SessionId` as `SessionId`**, not `String`, so `==` is clean.
|
|
574
|
+
13. **`SetSessionConfigOptionResponse::new(config_options)`** — the response
|
|
560
575
|
carries the *rebuilt* options so the picker reflects the new current value.
|
|
561
576
|
|
|
562
577
|
---
|
|
@@ -28,6 +28,8 @@ Use this skill when preparing a release for this repository.
|
|
|
28
28
|
- Update the root `sigit` package entry in `Cargo.lock` when the crate version changes.
|
|
29
29
|
- Add or update the top changelog entry in `CHANGELOG.md` for the release being cut.
|
|
30
30
|
- Do not treat `npm/sigit/package.json` `0.0.0-dev` as a bug by default. The npm release workflow rewrites it at publish time using `npm/scripts/render-main-package.cjs` and the release tag.
|
|
31
|
+
- Every npm package publishes twice, under `@getsigit` and under `@smbcloud`. `@smbcloud` is the pre-1.5.5 name, mirrored so an install predating the rename keeps updating; `@getsigit` is canonical and is what the README, the Homebrew tap, and the ACP registry entry point at. All fourteen names (two base packages, twelve platform packages) publish over OIDC and each needs its own Trusted Publisher on npm pointing at `release-npm.yml`.
|
|
32
|
+
- The scope is a render-time argument, not a second copy of the packaging: `render-platform-package.cjs` takes it as a fifth argument, and the base package picks it up from `package-main.json.tmpl` versus `package-compat.json.tmpl`. `npm/sigit/src/index.ts` is built once and shipped under both names — it reads its own `package.json` at runtime to decide which scope to resolve the platform binary from, and prints the migration notice only when it finds itself running as `@smbcloud/sigit`.
|
|
31
33
|
- Do not add a hardcoded version to `pypi/pyproject.toml` for normal releases. PyPI uses `maturin` with `dynamic = ["version"]` and derives the published package version from `Cargo.toml`.
|
|
32
34
|
- Release workflows are tag-driven. `release-github.yml`, `release-npm.yml`, `release-pypi.yml`, `release-crates.yml`, `release-homebrew.yml`, `release-nuget.yml`, and `release-mcp-registry.yml` all derive `RELEASE_VERSION` from a `v*.*.*` tag or a manually supplied tag input.
|
|
33
35
|
- The crate is published to crates.io (`release-crates.yml`) and the Homebrew tap is updated (`release-homebrew.yml`) as part of the tag-driven flow. Per the siGit release flow, Homebrew is auto-triggered — do not dispatch it manually.
|
|
@@ -58,6 +60,7 @@ Pushing the `v*.*.*` tag is what fires every release workflow, so create and pus
|
|
|
58
60
|
- `CHANGELOG.md`
|
|
59
61
|
- `README.md`
|
|
60
62
|
- `npm/sigit/package.json`
|
|
63
|
+
- `npm/package-main.json.tmpl`, `npm/package-compat.json.tmpl`, `npm/package.json.tmpl` (publish-time package metadata for both scopes)
|
|
61
64
|
- `npm/scripts/render-main-package.cjs`
|
|
62
65
|
- `npm/`
|
|
63
66
|
- `pypi/`
|
|
@@ -271,8 +271,14 @@ Ok(ForkSessionResponse::new(new_id).config_options(config_options))
|
|
|
271
271
|
per-session picker (see Config options below).
|
|
272
272
|
|
|
273
273
|
The session requests carry `cwd: PathBuf` and (with the feature)
|
|
274
|
-
`additional_directories: Vec<PathBuf
|
|
275
|
-
|
|
274
|
+
`additional_directories: Vec<PathBuf>` — the other directories of a multi-root
|
|
275
|
+
project, sent only to an agent whose `initialize` reply carries
|
|
276
|
+
`SessionCapabilities::new().additional_directories(SessionAdditionalDirectoriesCapabilities::new())`. `SiGitAgent::enter_session_roots` stashes `cwd`, `set_current_dir`s to
|
|
277
|
+
it, hands the extras to `workspace::set_additional_roots`, and returns the ones
|
|
278
|
+
that survived (a root that isn't a directory, repeats, or just names `cwd` again
|
|
279
|
+
is dropped). `session_context_message` then names every root in the system
|
|
280
|
+
message, and project-local discovery — skills, slash commands, subagent types,
|
|
281
|
+
instruction files — scans all of them, primary root first.
|
|
276
282
|
|
|
277
283
|
### `PromptRequest` / blocks
|
|
278
284
|
|
|
@@ -555,8 +561,17 @@ Editor Agent
|
|
|
555
561
|
10. **Zed re-fires the last config selection on connect** — make
|
|
556
562
|
`setConfigOption` a no-op when the requested model is already active, and
|
|
557
563
|
never start a model switch while a startup load is still in flight (GPU OOM).
|
|
558
|
-
11.
|
|
559
|
-
|
|
564
|
+
11. **`additional_directories` is not decoration** — dropping it means a
|
|
565
|
+
multi-root project silently behaves as if only the first root existed, with
|
|
566
|
+
the other repositories' `AGENTS.md` and skills missing. Route it through
|
|
567
|
+
`workspace.rs`, not just the log line. Handling it is also only half the
|
|
568
|
+
job: Zed gates the field on
|
|
569
|
+
`agentCapabilities.sessionCapabilities.additionalDirectories` being present
|
|
570
|
+
in the `initialize` reply, so an agent that reads the field but never
|
|
571
|
+
advertises the capability is never sent one, and the user gets a banner
|
|
572
|
+
saying the agent has no multi-root support.
|
|
573
|
+
12. **Store `SessionId` as `SessionId`**, not `String`, so `==` is clean.
|
|
574
|
+
13. **`SetSessionConfigOptionResponse::new(config_options)`** — the response
|
|
560
575
|
carries the *rebuilt* options so the picker reflects the new current value.
|
|
561
576
|
|
|
562
577
|
---
|
|
@@ -28,6 +28,8 @@ Use this skill when preparing a release for this repository.
|
|
|
28
28
|
- Update the root `sigit` package entry in `Cargo.lock` when the crate version changes.
|
|
29
29
|
- Add or update the top changelog entry in `CHANGELOG.md` for the release being cut.
|
|
30
30
|
- Do not treat `npm/sigit/package.json` `0.0.0-dev` as a bug by default. The npm release workflow rewrites it at publish time using `npm/scripts/render-main-package.cjs` and the release tag.
|
|
31
|
+
- Every npm package publishes twice, under `@getsigit` and under `@smbcloud`. `@smbcloud` is the pre-1.5.5 name, mirrored so an install predating the rename keeps updating; `@getsigit` is canonical and is what the README, the Homebrew tap, and the ACP registry entry point at. All fourteen names (two base packages, twelve platform packages) publish over OIDC and each needs its own Trusted Publisher on npm pointing at `release-npm.yml`.
|
|
32
|
+
- The scope is a render-time argument, not a second copy of the packaging: `render-platform-package.cjs` takes it as a fifth argument, and the base package picks it up from `package-main.json.tmpl` versus `package-compat.json.tmpl`. `npm/sigit/src/index.ts` is built once and shipped under both names — it reads its own `package.json` at runtime to decide which scope to resolve the platform binary from, and prints the migration notice only when it finds itself running as `@smbcloud/sigit`.
|
|
31
33
|
- Do not add a hardcoded version to `pypi/pyproject.toml` for normal releases. PyPI uses `maturin` with `dynamic = ["version"]` and derives the published package version from `Cargo.toml`.
|
|
32
34
|
- Release workflows are tag-driven. `release-github.yml`, `release-npm.yml`, `release-pypi.yml`, `release-crates.yml`, `release-homebrew.yml`, `release-nuget.yml`, and `release-mcp-registry.yml` all derive `RELEASE_VERSION` from a `v*.*.*` tag or a manually supplied tag input.
|
|
33
35
|
- The crate is published to crates.io (`release-crates.yml`) and the Homebrew tap is updated (`release-homebrew.yml`) as part of the tag-driven flow. Per the siGit release flow, Homebrew is auto-triggered — do not dispatch it manually.
|
|
@@ -58,6 +60,7 @@ Pushing the `v*.*.*` tag is what fires every release workflow, so create and pus
|
|
|
58
60
|
- `CHANGELOG.md`
|
|
59
61
|
- `README.md`
|
|
60
62
|
- `npm/sigit/package.json`
|
|
63
|
+
- `npm/package-main.json.tmpl`, `npm/package-compat.json.tmpl`, `npm/package.json.tmpl` (publish-time package metadata for both scopes)
|
|
61
64
|
- `npm/scripts/render-main-package.cjs`
|
|
62
65
|
- `npm/`
|
|
63
66
|
- `pypi/`
|
|
@@ -12,6 +12,14 @@ on:
|
|
|
12
12
|
description: "Release tag (e.g. v1.5.2)"
|
|
13
13
|
required: true
|
|
14
14
|
|
|
15
|
+
concurrency:
|
|
16
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
17
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
18
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
19
|
+
# just hits the "already published" check and exits clean.
|
|
20
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
21
|
+
cancel-in-progress: false
|
|
22
|
+
|
|
15
23
|
permissions:
|
|
16
24
|
contents: read
|
|
17
25
|
|
|
@@ -10,6 +10,14 @@ on:
|
|
|
10
10
|
description: "Release tag (e.g. v1.0.2)"
|
|
11
11
|
required: true
|
|
12
12
|
|
|
13
|
+
concurrency:
|
|
14
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
15
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
16
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
17
|
+
# just hits the "already published" check and exits clean.
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
13
21
|
permissions:
|
|
14
22
|
contents: read
|
|
15
23
|
|
|
@@ -56,12 +64,32 @@ jobs:
|
|
|
56
64
|
print(next(p['version'] for p in pkgs if p['name']=='sigit'))")
|
|
57
65
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
58
66
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
# crates.io answers 403 to requests without a descriptive
|
|
68
|
+
# User-Agent, so curl's default one makes this look like a 404 and
|
|
69
|
+
# the publish below runs into "crate already exists on the index".
|
|
70
|
+
# Branch on the status code rather than on curl's exit status, so an
|
|
71
|
+
# answer we do not understand stops the job instead of quietly
|
|
72
|
+
# degrading into that same failure.
|
|
73
|
+
# Retry first, so a timeout or a 5xx costs a few seconds instead of
|
|
74
|
+
# the whole release.
|
|
75
|
+
STATUS=$(curl -sS -o /dev/null -w '%{http_code}' \
|
|
76
|
+
--retry 3 --retry-delay 2 --retry-all-errors \
|
|
77
|
+
-H "User-Agent: ${GITHUB_REPOSITORY} release workflow (https://github.com/${GITHUB_REPOSITORY})" \
|
|
78
|
+
"https://crates.io/api/v1/crates/sigit/${VERSION}")
|
|
79
|
+
|
|
80
|
+
case "$STATUS" in
|
|
81
|
+
200)
|
|
82
|
+
echo "sigit ${VERSION} already exists on crates.io, skipping publish"
|
|
83
|
+
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
84
|
+
;;
|
|
85
|
+
404)
|
|
86
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
87
|
+
;;
|
|
88
|
+
*)
|
|
89
|
+
echo "Unexpected ${STATUS} from crates.io while checking whether sigit ${VERSION} is published" >&2
|
|
90
|
+
exit 1
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
65
93
|
|
|
66
94
|
- name: Publish to crates.io
|
|
67
95
|
if: steps.crates-check.outputs.exists != 'true'
|
|
@@ -10,6 +10,14 @@ on:
|
|
|
10
10
|
description: "Release tag (e.g. v0.1.1)"
|
|
11
11
|
required: true
|
|
12
12
|
|
|
13
|
+
concurrency:
|
|
14
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
15
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
16
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
17
|
+
# just hits the "already published" check and exits clean.
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
13
21
|
permissions:
|
|
14
22
|
contents: write
|
|
15
23
|
actions: write
|
|
@@ -7,6 +7,14 @@ on:
|
|
|
7
7
|
description: "Release tag (e.g. v0.1.1)"
|
|
8
8
|
required: true
|
|
9
9
|
|
|
10
|
+
concurrency:
|
|
11
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
12
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
13
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
14
|
+
# just hits the "already published" check and exits clean.
|
|
15
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
10
18
|
permissions:
|
|
11
19
|
contents: read
|
|
12
20
|
|
|
@@ -10,6 +10,14 @@ on:
|
|
|
10
10
|
description: "Release tag (e.g. v0.1.1)"
|
|
11
11
|
required: true
|
|
12
12
|
|
|
13
|
+
concurrency:
|
|
14
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
15
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
16
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
17
|
+
# just hits the "already published" check and exits clean.
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
13
21
|
permissions:
|
|
14
22
|
id-token: write
|
|
15
23
|
contents: read
|
|
@@ -108,8 +116,10 @@ jobs:
|
|
|
108
116
|
shell: bash
|
|
109
117
|
run: npm install -g npm@latest
|
|
110
118
|
|
|
111
|
-
# Authentication is OIDC: each @getsigit/* package has a
|
|
112
|
-
# Publisher pointing at this workflow, so there is no token to
|
|
119
|
+
# Authentication is OIDC: each @getsigit/* and @smbcloud/* package has a
|
|
120
|
+
# Trusted Publisher pointing at this workflow, so there is no token to
|
|
121
|
+
# leak. @smbcloud is the pre-1.5.5 scope, published alongside @getsigit
|
|
122
|
+
# so that an install made before the rename keeps updating.
|
|
113
123
|
- name: Publish platform package to NPM
|
|
114
124
|
shell: bash
|
|
115
125
|
run: |
|
|
@@ -141,13 +151,6 @@ jobs:
|
|
|
141
151
|
# Create the package directory
|
|
142
152
|
mkdir -p "${node_pkg}/bin"
|
|
143
153
|
|
|
144
|
-
# Generate package.json + README for this platform slice
|
|
145
|
-
node ./scripts/render-platform-package.cjs \
|
|
146
|
-
"${node_pkg}" \
|
|
147
|
-
"${node_version}" \
|
|
148
|
-
"${node_os}" \
|
|
149
|
-
"${node_arch}"
|
|
150
|
-
|
|
151
154
|
# Windows binaries carry a .exe extension
|
|
152
155
|
if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
|
|
153
156
|
cargo_bin="${cargo_bin}.exe"
|
|
@@ -155,18 +158,36 @@ jobs:
|
|
|
155
158
|
|
|
156
159
|
cp "../target/${{ matrix.build.TARGET }}/release/${cargo_bin}" "${node_pkg}/bin"
|
|
157
160
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
# One binary, published under both scopes: re-render package.json and
|
|
162
|
+
# README for each, from the same directory.
|
|
163
|
+
for scope in "@getsigit" "@smbcloud"; do
|
|
164
|
+
node ./scripts/render-platform-package.cjs \
|
|
165
|
+
"${node_pkg}" \
|
|
166
|
+
"${node_version}" \
|
|
167
|
+
"${node_os}" \
|
|
168
|
+
"${node_arch}" \
|
|
169
|
+
"${scope}"
|
|
170
|
+
|
|
171
|
+
npm_package_name="${scope}/${node_pkg}"
|
|
172
|
+
|
|
173
|
+
# `npm view` exits non-zero both when the version is genuinely
|
|
174
|
+
# unpublished and when the registry could not be reached, so treat
|
|
175
|
+
# only an E404 as "not published yet". Anything else stops the job
|
|
176
|
+
# instead of publishing over a version that is already there.
|
|
177
|
+
if view_output=$(npm view "${npm_package_name}@${node_version}" version 2>&1); then
|
|
178
|
+
echo "${npm_package_name}@${node_version} already exists on npm, skipping publish"
|
|
179
|
+
continue
|
|
180
|
+
elif ! grep -q "E404" <<<"${view_output}"; then
|
|
181
|
+
echo "npm view failed while checking ${npm_package_name}@${node_version}:" >&2
|
|
182
|
+
echo "${view_output}" >&2
|
|
183
|
+
exit 1
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
(cd "${node_pkg}" && npm publish --access public)
|
|
187
|
+
done
|
|
167
188
|
|
|
168
189
|
publish-npm-base:
|
|
169
|
-
name: Publish base NPM
|
|
190
|
+
name: Publish base NPM packages (@getsigit/sigit, @smbcloud/sigit)
|
|
170
191
|
needs: publish-npm-binaries
|
|
171
192
|
runs-on: ubuntu-latest
|
|
172
193
|
|
|
@@ -200,25 +221,47 @@ jobs:
|
|
|
200
221
|
shell: bash
|
|
201
222
|
run: npm install -g npm@latest
|
|
202
223
|
|
|
203
|
-
- name: Publish base
|
|
224
|
+
- name: Publish base packages to NPM
|
|
204
225
|
shell: bash
|
|
205
226
|
run: |
|
|
206
227
|
cd npm/sigit
|
|
207
228
|
|
|
208
|
-
# Rewrite package.json with the correct release version and
|
|
209
|
-
# matching optionalDependency versions
|
|
210
|
-
node ../scripts/render-main-package.cjs \
|
|
211
|
-
"./package.json" \
|
|
212
|
-
"${{ env.RELEASE_VERSION }}"
|
|
213
|
-
|
|
214
|
-
npm_package_name="@getsigit/sigit"
|
|
215
229
|
npm_package_version="${{ env.RELEASE_VERSION }}"
|
|
216
230
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
231
|
+
# Rewrite package.json with the correct release version and matching
|
|
232
|
+
# optionalDependency versions, then build. The compiled launcher is
|
|
233
|
+
# scope-agnostic — it reads its own package.json at runtime to decide
|
|
234
|
+
# which scope to resolve the platform binary from — so both packages
|
|
235
|
+
# ship the same lib/ and it only needs building once.
|
|
236
|
+
node ../scripts/render-main-package.cjs \
|
|
237
|
+
"./package.json" \
|
|
238
|
+
"${npm_package_version}"
|
|
221
239
|
|
|
222
240
|
npm install
|
|
223
241
|
npm run build
|
|
224
|
-
|
|
242
|
+
|
|
243
|
+
# @getsigit/sigit is the canonical package; @smbcloud/sigit is the
|
|
244
|
+
# pre-1.5.5 name, kept publishing so installs predating the rename
|
|
245
|
+
# keep updating. Its template points optionalDependencies at the
|
|
246
|
+
# @smbcloud platform packages.
|
|
247
|
+
for template in "package-main.json.tmpl" "package-compat.json.tmpl"; do
|
|
248
|
+
node ../scripts/render-main-package.cjs \
|
|
249
|
+
"./package.json" \
|
|
250
|
+
"${npm_package_version}" \
|
|
251
|
+
"${template}"
|
|
252
|
+
|
|
253
|
+
npm_package_name=$(node -p "require('./package.json').name")
|
|
254
|
+
|
|
255
|
+
# Same E404-only reading as the platform packages above: a registry
|
|
256
|
+
# failure must not look like an unpublished version.
|
|
257
|
+
if view_output=$(npm view "${npm_package_name}@${npm_package_version}" version 2>&1); then
|
|
258
|
+
echo "${npm_package_name}@${npm_package_version} already exists on npm, skipping publish"
|
|
259
|
+
continue
|
|
260
|
+
elif ! grep -q "E404" <<<"${view_output}"; then
|
|
261
|
+
echo "npm view failed while checking ${npm_package_name}@${npm_package_version}:" >&2
|
|
262
|
+
echo "${view_output}" >&2
|
|
263
|
+
exit 1
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
npm publish --access public
|
|
267
|
+
done
|
|
@@ -10,6 +10,14 @@ on:
|
|
|
10
10
|
description: "Release tag (e.g. v1.5.2)"
|
|
11
11
|
required: true
|
|
12
12
|
|
|
13
|
+
concurrency:
|
|
14
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
15
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
16
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
17
|
+
# just hits the "already published" check and exits clean.
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
13
21
|
permissions:
|
|
14
22
|
contents: read
|
|
15
23
|
|
|
@@ -288,12 +296,35 @@ jobs:
|
|
|
288
296
|
shell: bash
|
|
289
297
|
run: |
|
|
290
298
|
package_index_url="https://api.nuget.org/v3-flatcontainer/sigit.code/index.json"
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
299
|
+
|
|
300
|
+
# Keep the fetch and the version match separate. Piping curl into
|
|
301
|
+
# grep hides a failed fetch behind an empty match, so an outage or a
|
|
302
|
+
# blocked request would read as "not published yet" and send the
|
|
303
|
+
# publish below into a version that is already there. A 404 here
|
|
304
|
+
# means the package itself is not on NuGet, which is the first
|
|
305
|
+
# release and a real "not published".
|
|
306
|
+
index=$(mktemp)
|
|
307
|
+
STATUS=$(curl -sS -o "${index}" -w '%{http_code}' \
|
|
308
|
+
--retry 3 --retry-delay 2 --retry-all-errors "${package_index_url}")
|
|
309
|
+
|
|
310
|
+
case "$STATUS" in
|
|
311
|
+
200)
|
|
312
|
+
if grep -F "\"${RELEASE_VERSION}\"" "${index}" >/dev/null; then
|
|
313
|
+
echo "${NUGET_PACKAGE_ID} ${RELEASE_VERSION} already exists on NuGet, skipping publish"
|
|
314
|
+
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
315
|
+
else
|
|
316
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
317
|
+
fi
|
|
318
|
+
;;
|
|
319
|
+
404)
|
|
320
|
+
echo "${NUGET_PACKAGE_ID} is not on NuGet yet, publishing its first version"
|
|
321
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
322
|
+
;;
|
|
323
|
+
*)
|
|
324
|
+
echo "Unexpected ${STATUS} from NuGet while checking whether ${NUGET_PACKAGE_ID} ${RELEASE_VERSION} is published" >&2
|
|
325
|
+
exit 1
|
|
326
|
+
;;
|
|
327
|
+
esac
|
|
297
328
|
|
|
298
329
|
# Exchange the workflow's OIDC token for a short-lived NuGet API key. The
|
|
299
330
|
# key is written to the environment for the subsequent `dotnet nuget push`
|
|
@@ -10,6 +10,14 @@ on:
|
|
|
10
10
|
description: "Release tag (e.g. v0.1.1)"
|
|
11
11
|
required: true
|
|
12
12
|
|
|
13
|
+
concurrency:
|
|
14
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
15
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
16
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
17
|
+
# just hits the "already published" check and exits clean.
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
13
21
|
permissions:
|
|
14
22
|
id-token: write
|
|
15
23
|
contents: read
|
|
@@ -173,12 +181,27 @@ jobs:
|
|
|
173
181
|
id: pypi-check
|
|
174
182
|
shell: bash
|
|
175
183
|
run: |
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
184
|
+
# Branch on the status code rather than on curl's exit status: with
|
|
185
|
+
# -f every non-2xx answer looks alike, so a registry outage or a
|
|
186
|
+
# blocked request would read as "not published yet" and send the
|
|
187
|
+
# publish below into a version that is already there.
|
|
188
|
+
STATUS=$(curl -sS -o /dev/null -w '%{http_code}' \
|
|
189
|
+
--retry 3 --retry-delay 2 --retry-all-errors \
|
|
190
|
+
"https://pypi.org/pypi/sigit-code/${RELEASE_VERSION}/json")
|
|
191
|
+
|
|
192
|
+
case "$STATUS" in
|
|
193
|
+
200)
|
|
194
|
+
echo "sigit-code ${RELEASE_VERSION} already exists on PyPI, skipping publish"
|
|
195
|
+
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
196
|
+
;;
|
|
197
|
+
404)
|
|
198
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
199
|
+
;;
|
|
200
|
+
*)
|
|
201
|
+
echo "Unexpected ${STATUS} from PyPI while checking whether sigit-code ${RELEASE_VERSION} is published" >&2
|
|
202
|
+
exit 1
|
|
203
|
+
;;
|
|
204
|
+
esac
|
|
182
205
|
|
|
183
206
|
- name: Publish distribution
|
|
184
207
|
if: steps.pypi-check.outputs.exists != 'true'
|
|
@@ -8,6 +8,14 @@ on:
|
|
|
8
8
|
description: "Release tag (e.g. v1.5.2)"
|
|
9
9
|
required: true
|
|
10
10
|
|
|
11
|
+
concurrency:
|
|
12
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
13
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
14
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
15
|
+
# just hits the "already published" check and exits clean.
|
|
16
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
11
19
|
permissions:
|
|
12
20
|
contents: read
|
|
13
21
|
|
|
@@ -20,6 +20,14 @@ on:
|
|
|
20
20
|
description: "Release tag (e.g. v1.5.2)"
|
|
21
21
|
required: true
|
|
22
22
|
|
|
23
|
+
concurrency:
|
|
24
|
+
# A re-pushed or re-dispatched tag fires this a second time. Queue the
|
|
25
|
+
# duplicate behind the original instead of cancelling it: cancelling a run
|
|
26
|
+
# mid-publish can leave a channel half-uploaded, whereas a queued duplicate
|
|
27
|
+
# just hits the "already published" check and exits clean.
|
|
28
|
+
group: ${{ github.workflow }}-${{ github.event.inputs.tag || github.ref_name }}
|
|
29
|
+
cancel-in-progress: false
|
|
30
|
+
|
|
23
31
|
permissions:
|
|
24
32
|
contents: read
|
|
25
33
|
|