sigit-code 1.6.6__tar.gz → 1.6.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.6.6 → sigit_code-1.6.8}/.agents/AGENTS.md +5 -1
- sigit_code-1.6.8/.github/workflows/release-winget.yml +320 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/AGENTS.md +5 -1
- {sigit_code-1.6.6 → sigit_code-1.6.8}/CHANGELOG.md +36 -1
- {sigit_code-1.6.6 → sigit_code-1.6.8}/CLAUDE.md +5 -1
- {sigit_code-1.6.6 → sigit_code-1.6.8}/Cargo.lock +1 -1
- {sigit_code-1.6.6 → sigit_code-1.6.8}/Cargo.toml +1 -1
- {sigit_code-1.6.6 → sigit_code-1.6.8}/PKG-INFO +1 -1
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/main.rs +158 -16
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_audio.rs +45 -0
- sigit_code-1.6.6/.github/workflows/release-winget.yml +0 -178
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/agent-client-protocol/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/branding/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/sigit-code-release/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.agents/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.cargo/config.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/agent-client-protocol/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/ai-assisted-coding/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/branding/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/run-sigit/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/run-sigit/driver.mjs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/run-sigit/tui-smoke.sh +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/sigit-code-release/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.claude/skills/tool-calling/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/ci.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-aur.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-crates.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-github.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-homebrew.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-npm.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-nuget.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-pypi.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.github/workflows/release-scoop.yml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.gitignore +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.nvmrc +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.sigit/code-cloud-agent/config.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.sigit/code-review/config.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/.sigit/factory/config.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/LICENSE +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/README.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/docs/headless.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/docs/hooks.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/docs/mcp.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/examples/settings-with-hooks.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/examples/skills/README.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/examples/skills/commit-message/SKILL.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/README.md.tmpl +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/package-compat.json.tmpl +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/package-main.json.tmpl +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/package.json.tmpl +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/scripts/render-main-package.cjs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/scripts/render-platform-package.cjs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/sigit/.gitignore +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/sigit/README.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/sigit/package.json +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/sigit/src/index.ts +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/npm/sigit/tsconfig.json +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/nuget/.gitignore +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/nuget/sigit/Program.cs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/nuget/sigit/README.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/nuget/sigit/SiGit.Code.csproj +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/packaging/aur/PKGBUILD.in +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/packaging/nfpm.yaml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/packaging/windows/check-static-crt.ps1 +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/packaging/winget/getSigit.siGitCode.installer.yaml.in +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/packaging/winget/getSigit.siGitCode.locale.en-US.yaml.in +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/packaging/winget/getSigit.siGitCode.yaml.in +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/pypi/README.md +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/pypi/pyproject.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/pyproject.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/rust-toolchain.toml +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/account.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/backend.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/browser_auth.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/chat.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/client_fs.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/client_terminal.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/commands.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/credentials.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/frontmatter.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/harness_markup.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/headless.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/hooks.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/inline_tool_calls.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/instructions.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/mcp.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/models.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/permissions.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/provider.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/repetition.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/session_store.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/settings.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/setup.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/skills.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/subagents.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/tools.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/src/workspace.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_client_fs.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_client_terminal.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_concurrent_sessions.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_embedded_context.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_endpoint_errors.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_harness_markup.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_images.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_logout.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_multi_root.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_permissions.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_session_list.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_session_load.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_stop_reasons.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_tool_call_name.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/acp_tool_stdin.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/headless_mode.rs +0 -0
- {sigit_code-1.6.6 → sigit_code-1.6.8}/tests/version_flag.rs +0 -0
|
@@ -310,7 +310,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
310
310
|
conversation); lifecycle and config handlers hold it throughout, and `handle_prompt` holds it
|
|
311
311
|
through a `WorkspaceHold` that it releases while waiting on an HTTP endpoint or a permission
|
|
312
312
|
answer and retakes (reinstalling its session via `resume_workspace`) before any tool runs. An
|
|
313
|
-
on-device turn never releases it. Take the session lock first, never the other way round.
|
|
313
|
+
on-device turn never releases it. Take the session lock first, never the other way round. A turn registers its `PromptCancellation` at
|
|
314
|
+
the top of `handle_prompt`, before it waits on either lock, and a `PromptRegistration`
|
|
315
|
+
guard clears it on every return, so a `session/cancel` that arrives while the turn
|
|
316
|
+
is still queued, switching threads, loading a model or running a slash command ends
|
|
317
|
+
it as `cancelled`. The checks sit after each of those waits. Tool
|
|
314
318
|
execution, subagents included, still runs one session at a time.
|
|
315
319
|
- **`src/instructions.rs`** — project instruction files, the always-on counterpart to skills.
|
|
316
320
|
Reads `AGENTS.md` (the cross-tool [agents.md](https://agents.md) standard) and `CLAUDE.md`,
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
name: winget Release
|
|
2
|
+
|
|
3
|
+
# Dispatched by release-github.yml once the release and its checksums exist.
|
|
4
|
+
#
|
|
5
|
+
# winget manifests live in microsoft/winget-pkgs, and `wingetcreate update`
|
|
6
|
+
# only works on a package that is already there. So this workflow branches:
|
|
7
|
+
#
|
|
8
|
+
# - package already in winget-pkgs -> `wingetcreate update`, which rewrites
|
|
9
|
+
# the URLs and re-hashes the installers for us.
|
|
10
|
+
# - package not there yet -> render the manifests in packaging/winget/ and
|
|
11
|
+
# `wingetcreate submit` them as a new package.
|
|
12
|
+
#
|
|
13
|
+
# The second path only runs once, but keeping it here means a first release
|
|
14
|
+
# does not need someone to sit at a Windows box running `wingetcreate new`
|
|
15
|
+
# interactively.
|
|
16
|
+
on:
|
|
17
|
+
workflow_dispatch:
|
|
18
|
+
inputs:
|
|
19
|
+
tag:
|
|
20
|
+
description: "Release tag (e.g. v1.5.2)"
|
|
21
|
+
required: true
|
|
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
|
+
|
|
31
|
+
permissions:
|
|
32
|
+
contents: read
|
|
33
|
+
|
|
34
|
+
env:
|
|
35
|
+
REPO: getsigit/sigit
|
|
36
|
+
PACKAGE_IDENTIFIER: getSigit.siGitCode
|
|
37
|
+
|
|
38
|
+
jobs:
|
|
39
|
+
submit-winget-manifest:
|
|
40
|
+
name: Submit winget manifest
|
|
41
|
+
# wingetcreate is a Windows-only tool.
|
|
42
|
+
runs-on: windows-latest
|
|
43
|
+
|
|
44
|
+
steps:
|
|
45
|
+
- name: Check out repository
|
|
46
|
+
uses: actions/checkout@v6
|
|
47
|
+
|
|
48
|
+
- name: Resolve tag, version and release date
|
|
49
|
+
id: release
|
|
50
|
+
shell: bash
|
|
51
|
+
env:
|
|
52
|
+
GH_TOKEN: ${{ github.token }}
|
|
53
|
+
run: |
|
|
54
|
+
TAG="${{ github.event.inputs.tag }}"
|
|
55
|
+
VERSION="${TAG#v}"
|
|
56
|
+
# wingetcreate wants ReleaseDate as YYYY-MM-DD.
|
|
57
|
+
DATE=$(gh release view "$TAG" --repo "$REPO" --json publishedAt --jq '.publishedAt[0:10]')
|
|
58
|
+
|
|
59
|
+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
60
|
+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
61
|
+
echo "date=${DATE}" >> "$GITHUB_OUTPUT"
|
|
62
|
+
|
|
63
|
+
- name: Check whether the package is already in winget-pkgs
|
|
64
|
+
id: exists
|
|
65
|
+
shell: bash
|
|
66
|
+
env:
|
|
67
|
+
GH_TOKEN: ${{ github.token }}
|
|
68
|
+
run: |
|
|
69
|
+
# manifests are filed under the lowercased first letter of the
|
|
70
|
+
# publisher, e.g. manifests/g/getSigit/siGitCode.
|
|
71
|
+
PUBLISHER="${PACKAGE_IDENTIFIER%%.*}"
|
|
72
|
+
NAME="${PACKAGE_IDENTIFIER#*.}"
|
|
73
|
+
FIRST=$(echo "${PUBLISHER:0:1}" | tr '[:upper:]' '[:lower:]')
|
|
74
|
+
PATH_IN_REPO="manifests/${FIRST}/${PUBLISHER}/${NAME}"
|
|
75
|
+
|
|
76
|
+
if gh api "repos/microsoft/winget-pkgs/contents/${PATH_IN_REPO}" >/dev/null 2>&1; then
|
|
77
|
+
echo "Found ${PACKAGE_IDENTIFIER} at ${PATH_IN_REPO}; submitting an update."
|
|
78
|
+
echo "found=true" >> "$GITHUB_OUTPUT"
|
|
79
|
+
else
|
|
80
|
+
echo "No ${PACKAGE_IDENTIFIER} at ${PATH_IN_REPO}; submitting it as a new package."
|
|
81
|
+
echo "found=false" >> "$GITHUB_OUTPUT"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
- name: Render manifests for a first submission
|
|
85
|
+
if: steps.exists.outputs.found == 'false'
|
|
86
|
+
shell: bash
|
|
87
|
+
env:
|
|
88
|
+
GH_TOKEN: ${{ github.token }}
|
|
89
|
+
run: |
|
|
90
|
+
TAG="${{ steps.release.outputs.tag }}"
|
|
91
|
+
VERSION="${{ steps.release.outputs.version }}"
|
|
92
|
+
|
|
93
|
+
mkdir -p artifacts manifests
|
|
94
|
+
|
|
95
|
+
gh release download "$TAG" \
|
|
96
|
+
--repo "$REPO" \
|
|
97
|
+
--pattern "sigit-win-*.exe.sha256" \
|
|
98
|
+
--dir artifacts/
|
|
99
|
+
|
|
100
|
+
# The schema wants 64 hex characters; the community validation
|
|
101
|
+
# pipeline writes them uppercase, so match that.
|
|
102
|
+
SHA_AMD64=$(tr -d '[:space:]' < artifacts/sigit-win-amd64.exe.sha256 | tr '[:lower:]' '[:upper:]')
|
|
103
|
+
SHA_ARM64=$(tr -d '[:space:]' < artifacts/sigit-win-arm64.exe.sha256 | tr '[:lower:]' '[:upper:]')
|
|
104
|
+
|
|
105
|
+
RELEASE_DATE="${{ steps.release.outputs.date }}"
|
|
106
|
+
|
|
107
|
+
for template in packaging/winget/*.yaml.in; do
|
|
108
|
+
out="manifests/$(basename "$template" .in)"
|
|
109
|
+
sed \
|
|
110
|
+
-e "s|@VERSION@|${VERSION}|g" \
|
|
111
|
+
-e "s|@TAG@|${TAG}|g" \
|
|
112
|
+
-e "s|@REPO@|${REPO}|g" \
|
|
113
|
+
-e "s|@SHA_AMD64@|${SHA_AMD64}|g" \
|
|
114
|
+
-e "s|@SHA_ARM64@|${SHA_ARM64}|g" \
|
|
115
|
+
-e "s|@RELEASE_DATE@|${RELEASE_DATE}|g" \
|
|
116
|
+
"$template" > "$out"
|
|
117
|
+
|
|
118
|
+
echo "--- ${out} ---"
|
|
119
|
+
cat "$out"
|
|
120
|
+
done
|
|
121
|
+
|
|
122
|
+
- name: Download wingetcreate
|
|
123
|
+
shell: pwsh
|
|
124
|
+
run: Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe
|
|
125
|
+
|
|
126
|
+
# winget-pkgs convention: file the "please add/update this package"
|
|
127
|
+
# Package Request issue *first*, then open the manifest PR that fulfils
|
|
128
|
+
# it with "Resolves #N". Doing it the other way round (PR first, issue
|
|
129
|
+
# after) reads as "here's a request, and here's the PR that already did
|
|
130
|
+
# it", posted seconds apart.
|
|
131
|
+
#
|
|
132
|
+
# The issue and the PR are authored by two separate PATs, configured as
|
|
133
|
+
# the repo secrets WINGET_ISSUE_TOKEN (the Package Request issue) and
|
|
134
|
+
# WINGET_PR_TOKEN (the manifest PR). Both need public_repo scope on
|
|
135
|
+
# microsoft/winget-pkgs (fork + open issues/PRs). WINGET_PR_TOKEN
|
|
136
|
+
# replaces the old single WINGET_TOKEN.
|
|
137
|
+
- name: File the winget Package Request issue
|
|
138
|
+
id: issue
|
|
139
|
+
shell: bash
|
|
140
|
+
env:
|
|
141
|
+
# Authored by the issue account for this repo.
|
|
142
|
+
GH_TOKEN: ${{ secrets.WINGET_ISSUE_TOKEN }}
|
|
143
|
+
run: |
|
|
144
|
+
set -euo pipefail
|
|
145
|
+
|
|
146
|
+
if [ -z "${GH_TOKEN:-}" ]; then
|
|
147
|
+
echo "WINGET_ISSUE_TOKEN is not set. It needs a PAT (public_repo) for the account that should author the Package Request issue." >&2
|
|
148
|
+
exit 1
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
VERSION="${{ steps.release.outputs.version }}"
|
|
152
|
+
TAG="${{ steps.release.outputs.tag }}"
|
|
153
|
+
|
|
154
|
+
# The release assets, same URLs the update step feeds wingetcreate.
|
|
155
|
+
BASE="https://github.com/${REPO}/releases/download/${TAG}"
|
|
156
|
+
INSTALLER_AMD64="${BASE}/sigit-win-amd64.exe"
|
|
157
|
+
INSTALLER_ARM64="${BASE}/sigit-win-arm64.exe"
|
|
158
|
+
|
|
159
|
+
# winget-pkgs' Package Request is an issue *form*
|
|
160
|
+
# (.github/ISSUE_TEMPLATE/package_request.yml): the title must be
|
|
161
|
+
# "[Package Request]: ..." and the body has to carry the labelled
|
|
162
|
+
# fields below (Installer Url especially — without it a maintainer
|
|
163
|
+
# just replies "please provide the installer link"). A free-text
|
|
164
|
+
# body lands as Needs-Triage and can't be acted on.
|
|
165
|
+
ISSUE_BODY=$(cat <<EOF
|
|
166
|
+
Download Page Url: https://github.com/${REPO}/releases/tag/${TAG}
|
|
167
|
+
Publisher: getSigit
|
|
168
|
+
Package Name: siGit Code
|
|
169
|
+
Description: siGit Code, an AI coding agent that runs on your machine.
|
|
170
|
+
Package Version: ${VERSION}
|
|
171
|
+
Installer Url: ${INSTALLER_AMD64}
|
|
172
|
+
Installer Url: ${INSTALLER_ARM64}
|
|
173
|
+
EOF
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
ISSUE_URL=$(gh issue create \
|
|
177
|
+
--repo microsoft/winget-pkgs \
|
|
178
|
+
--title "[Package Request]: ${PACKAGE_IDENTIFIER} ${VERSION}" \
|
|
179
|
+
--body "$ISSUE_BODY")
|
|
180
|
+
|
|
181
|
+
echo "Opened issue ${ISSUE_URL}"
|
|
182
|
+
echo "issue_url=${ISSUE_URL}" >> "$GITHUB_OUTPUT"
|
|
183
|
+
echo "issue_number=${ISSUE_URL##*/}" >> "$GITHUB_OUTPUT"
|
|
184
|
+
|
|
185
|
+
- name: Submit new package
|
|
186
|
+
id: submit_new
|
|
187
|
+
if: steps.exists.outputs.found == 'false'
|
|
188
|
+
shell: pwsh
|
|
189
|
+
env:
|
|
190
|
+
# wingetcreate reads the token from this variable. Passing it as
|
|
191
|
+
# --token instead makes the tool warn that the token can end up in
|
|
192
|
+
# logs, which on a shared runner is not a warning worth ignoring.
|
|
193
|
+
# This is the PR-author account for this repo (see mapping above).
|
|
194
|
+
WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_PR_TOKEN }}
|
|
195
|
+
run: |
|
|
196
|
+
if (-not $env:WINGET_CREATE_GITHUB_TOKEN) {
|
|
197
|
+
Write-Error "WINGET_PR_TOKEN is not set. It needs a PAT with public_repo scope so wingetcreate can fork microsoft/winget-pkgs and open the manifest PR."
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
$version = "${{ steps.release.outputs.version }}"
|
|
201
|
+
|
|
202
|
+
# Tee stdout so we can scrape the PR URL afterwards. wingetcreate
|
|
203
|
+
# prints "Pull request can be found here: <url>" on success, and
|
|
204
|
+
# that line is the only handle we get on the PR it just opened.
|
|
205
|
+
# --no-open because the runner has no browser to open the PR in.
|
|
206
|
+
.\wingetcreate.exe submit manifests `
|
|
207
|
+
--prtitle "New package: $env:PACKAGE_IDENTIFIER version $version" `
|
|
208
|
+
--no-open 2>&1 | Tee-Object -Variable output
|
|
209
|
+
|
|
210
|
+
if ($LASTEXITCODE -ne 0) {
|
|
211
|
+
Write-Error "wingetcreate submit failed with exit code $LASTEXITCODE"
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
$match = [regex]::Match(($output -join "`n"), 'https://github\.com/microsoft/winget-pkgs/pull/(\d+)')
|
|
215
|
+
if ($match.Success) {
|
|
216
|
+
"pr_url=$($match.Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
|
217
|
+
"pr_number=$($match.Groups[1].Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
|
218
|
+
} else {
|
|
219
|
+
Write-Warning "Could not find the PR URL in wingetcreate output; skipping issue linking."
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
- name: Submit manifest update
|
|
223
|
+
id: submit_update
|
|
224
|
+
if: steps.exists.outputs.found == 'true'
|
|
225
|
+
shell: pwsh
|
|
226
|
+
env:
|
|
227
|
+
# PR-author account for this repo (see mapping above).
|
|
228
|
+
WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_PR_TOKEN }}
|
|
229
|
+
run: |
|
|
230
|
+
if (-not $env:WINGET_CREATE_GITHUB_TOKEN) {
|
|
231
|
+
Write-Error "WINGET_PR_TOKEN is not set. It needs a PAT with public_repo scope so wingetcreate can fork microsoft/winget-pkgs and open the manifest PR."
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
$tag = "${{ steps.release.outputs.tag }}"
|
|
235
|
+
$version = "${{ steps.release.outputs.version }}"
|
|
236
|
+
$base = "https://github.com/${env:REPO}/releases/download/$tag"
|
|
237
|
+
|
|
238
|
+
# The trailing |x64 and |arm64 tell wingetcreate which installer
|
|
239
|
+
# entry each URL replaces. Without them it guesses from the file
|
|
240
|
+
# name, and "sigit-win-amd64.exe" is not a spelling it recognises.
|
|
241
|
+
.\wingetcreate.exe update $env:PACKAGE_IDENTIFIER `
|
|
242
|
+
--version $version `
|
|
243
|
+
--urls "$base/sigit-win-amd64.exe|x64" "$base/sigit-win-arm64.exe|arm64" `
|
|
244
|
+
--release-notes-url "https://github.com/${env:REPO}/releases/tag/$tag" `
|
|
245
|
+
--release-date "${{ steps.release.outputs.date }}" `
|
|
246
|
+
--prtitle "Update $env:PACKAGE_IDENTIFIER to version $version" `
|
|
247
|
+
--submit `
|
|
248
|
+
--no-open 2>&1 | Tee-Object -Variable output
|
|
249
|
+
|
|
250
|
+
if ($LASTEXITCODE -ne 0) {
|
|
251
|
+
Write-Error "wingetcreate failed with exit code $LASTEXITCODE"
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
$match = [regex]::Match(($output -join "`n"), 'https://github\.com/microsoft/winget-pkgs/pull/(\d+)')
|
|
255
|
+
if ($match.Success) {
|
|
256
|
+
"pr_url=$($match.Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
|
257
|
+
"pr_number=$($match.Groups[1].Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
|
258
|
+
} else {
|
|
259
|
+
Write-Warning "Could not find the PR URL in wingetcreate output; skipping issue linking."
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# wingetcreate has no --prbody flag (only --prtitle), so it always opens
|
|
263
|
+
# the PR with the winget-pkgs template: an empty Description and an
|
|
264
|
+
# unticked "Linked to an issue" box next to a "Resolves #[Issue Number]"
|
|
265
|
+
# placeholder. The issue already exists (filed first, above), so this
|
|
266
|
+
# step just rewrites the body to point the PR at it with "Resolves #N".
|
|
267
|
+
#
|
|
268
|
+
# This must run as the PR author (WINGET_PR_TOKEN) — the account that
|
|
269
|
+
# opened the PR via wingetcreate — since only the author (or a repo
|
|
270
|
+
# maintainer) can edit it.
|
|
271
|
+
- name: Set the winget PR body and link the issue
|
|
272
|
+
id: link
|
|
273
|
+
if: >-
|
|
274
|
+
(steps.submit_new.outputs.pr_number != '') ||
|
|
275
|
+
(steps.submit_update.outputs.pr_number != '')
|
|
276
|
+
shell: bash
|
|
277
|
+
env:
|
|
278
|
+
GH_TOKEN: ${{ secrets.WINGET_PR_TOKEN }}
|
|
279
|
+
run: |
|
|
280
|
+
set -euo pipefail
|
|
281
|
+
|
|
282
|
+
PR_URL="${{ steps.submit_new.outputs.pr_url || steps.submit_update.outputs.pr_url }}"
|
|
283
|
+
ISSUE_NUMBER="${{ steps.issue.outputs.issue_number }}"
|
|
284
|
+
VERSION="${{ steps.release.outputs.version }}"
|
|
285
|
+
TAG="${{ steps.release.outputs.tag }}"
|
|
286
|
+
|
|
287
|
+
if [ -n "$ISSUE_NUMBER" ]; then
|
|
288
|
+
CHECKBOX="- [x] Linked to an issue (if applicable)"
|
|
289
|
+
RESOLVES="- Resolves #${ISSUE_NUMBER}"
|
|
290
|
+
else
|
|
291
|
+
CHECKBOX="- [ ] Linked to an issue (if applicable)"
|
|
292
|
+
RESOLVES=""
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
if [ "${{ steps.exists.outputs.found }}" = "false" ]; then
|
|
296
|
+
DESC="Adds ${PACKAGE_IDENTIFIER} version ${VERSION} from ${TAG}."
|
|
297
|
+
else
|
|
298
|
+
DESC="Updates ${PACKAGE_IDENTIFIER} to version ${VERSION} from ${TAG}."
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
# Mirrors the current .github/PULL_REQUEST_TEMPLATE.md; keep the
|
|
302
|
+
# checklist items in sync with it (e.g. the 1.12 schema line).
|
|
303
|
+
BODY=$(cat <<EOF
|
|
304
|
+
## 📖 Description
|
|
305
|
+
${DESC}
|
|
306
|
+
## ✅ Checklist
|
|
307
|
+
- [x] Signed the [Contributor License Agreement](https://cla.opensource.microsoft.com)
|
|
308
|
+
${CHECKBOX}
|
|
309
|
+
${RESOLVES}
|
|
310
|
+
## 📦 Manifest Checklist
|
|
311
|
+
- [x] Checked that there aren't other open [pull requests](https://github.com/microsoft/winget-pkgs/pulls) for the same manifest update/change
|
|
312
|
+
- [x] This PR only modifies one (1) manifest
|
|
313
|
+
- [x] Validated manifest locally with \`winget validate --manifest <directory>\`
|
|
314
|
+
- [x] Tested manifest locally with \`winget install --manifest <directory>\`
|
|
315
|
+
- [x] Manifest conforms to the [1.12 schema](https://github.com/microsoft/winget-pkgs/tree/master/doc/manifest/schema/1.12.0)
|
|
316
|
+
EOF
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
gh pr edit "$PR_URL" --body "$BODY"
|
|
320
|
+
echo "Linked ${PR_URL} to issue #${ISSUE_NUMBER:-<none>}"
|
|
@@ -310,7 +310,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
310
310
|
conversation); lifecycle and config handlers hold it throughout, and `handle_prompt` holds it
|
|
311
311
|
through a `WorkspaceHold` that it releases while waiting on an HTTP endpoint or a permission
|
|
312
312
|
answer and retakes (reinstalling its session via `resume_workspace`) before any tool runs. An
|
|
313
|
-
on-device turn never releases it. Take the session lock first, never the other way round.
|
|
313
|
+
on-device turn never releases it. Take the session lock first, never the other way round. A turn registers its `PromptCancellation` at
|
|
314
|
+
the top of `handle_prompt`, before it waits on either lock, and a `PromptRegistration`
|
|
315
|
+
guard clears it on every return, so a `session/cancel` that arrives while the turn
|
|
316
|
+
is still queued, switching threads, loading a model or running a slash command ends
|
|
317
|
+
it as `cancelled`. The checks sit after each of those waits. Tool
|
|
314
318
|
execution, subagents included, still runs one session at a time.
|
|
315
319
|
- **`src/instructions.rs`** — project instruction files, the always-on counterpart to skills.
|
|
316
320
|
Reads `AGENTS.md` (the cross-tool [agents.md](https://agents.md) standard) and `CLAUDE.md`,
|
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 1.6.8
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **A bare launch of `sigit.exe` on Windows exits 0 instead of bailing.** A
|
|
8
|
+
no-argument launch with a TTY stdin falls through to the non-Unix branch,
|
|
9
|
+
which has no TUI to start (the interactive client needs Unix-only fd
|
|
10
|
+
redirection). It now prints a short usage message pointing at ACP and
|
|
11
|
+
headless modes and exits 0, so winget's installer validator no longer reports
|
|
12
|
+
a `Validation-Executable-Error`.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **winget submissions link back to their Package Request issue.** The release
|
|
17
|
+
workflow scrapes the winget-pkgs PR URL from wingetcreate, opens a Package
|
|
18
|
+
Request issue on first submission, and rewrites the PR body to fill the
|
|
19
|
+
Description, tick the issue checkbox, and add `Resolves #NNN` — replacing the
|
|
20
|
+
manual per-PR edit that used to follow each release.
|
|
21
|
+
- **The winget release workflow files its Package Request issue first and uses
|
|
22
|
+
two scoped tokens.** The Package Request issue is opened before the
|
|
23
|
+
winget-pkgs PR so the PR can reference it immediately, and issue creation and
|
|
24
|
+
PR submission now use separate tokens (`WINGET_ISSUE_TOKEN` and
|
|
25
|
+
`WINGET_PR_TOKEN`) rather than one shared token.
|
|
26
|
+
|
|
27
|
+
## 1.6.7
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **A cancel that arrives before the turn starts is no longer lost.** A prompt
|
|
32
|
+
now registers for `session/cancel` as soon as it begins, not once it reaches
|
|
33
|
+
inference. A cancel that lands while the turn is queued on the workspace,
|
|
34
|
+
switching threads, loading a model, or running a slash command ends it with
|
|
35
|
+
`cancelled` instead of `end_turn`.
|
|
36
|
+
- **A prompt that is only audio is answered.** A clip with no text or image used
|
|
37
|
+
to end the turn at once with nothing sent to the model, even though the agent
|
|
38
|
+
advertises audio.
|
|
4
39
|
|
|
5
40
|
## 1.6.6
|
|
6
41
|
|
|
@@ -310,7 +310,11 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
|
|
|
310
310
|
conversation); lifecycle and config handlers hold it throughout, and `handle_prompt` holds it
|
|
311
311
|
through a `WorkspaceHold` that it releases while waiting on an HTTP endpoint or a permission
|
|
312
312
|
answer and retakes (reinstalling its session via `resume_workspace`) before any tool runs. An
|
|
313
|
-
on-device turn never releases it. Take the session lock first, never the other way round.
|
|
313
|
+
on-device turn never releases it. Take the session lock first, never the other way round. A turn registers its `PromptCancellation` at
|
|
314
|
+
the top of `handle_prompt`, before it waits on either lock, and a `PromptRegistration`
|
|
315
|
+
guard clears it on every return, so a `session/cancel` that arrives while the turn
|
|
316
|
+
is still queued, switching threads, loading a model or running a slash command ends
|
|
317
|
+
it as `cancelled`. The checks sit after each of those waits. Tool
|
|
314
318
|
execution, subagents included, still runs one session at a time.
|
|
315
319
|
- **`src/instructions.rs`** — project instruction files, the always-on counterpart to skills.
|
|
316
320
|
Reads `AGENTS.md` (the cross-tool [agents.md](https://agents.md) standard) and `CLAUDE.md`,
|
|
@@ -465,6 +465,21 @@ impl PromptCancellation {
|
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
+
/// Removes a turn's cancellation from the agent's registry when the turn ends,
|
|
469
|
+
/// whichever way it returns.
|
|
470
|
+
struct PromptRegistration<'a> {
|
|
471
|
+
agent: &'a SiGitAgent,
|
|
472
|
+
session_id: SessionId,
|
|
473
|
+
cancellation: Arc<PromptCancellation>,
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
impl Drop for PromptRegistration<'_> {
|
|
477
|
+
fn drop(&mut self) {
|
|
478
|
+
self.agent
|
|
479
|
+
.finish_prompt(&self.session_id, &self.cancellation);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
468
483
|
enum DrainTurnError {
|
|
469
484
|
Backend(backend::BackendError),
|
|
470
485
|
Cancelled,
|
|
@@ -3063,10 +3078,31 @@ impl SiGitAgent {
|
|
|
3063
3078
|
return Ok(PromptResponse::new(StopReason::Cancelled));
|
|
3064
3079
|
}
|
|
3065
3080
|
|
|
3081
|
+
// Registered before anything that can wait, so a `session/cancel` that
|
|
3082
|
+
// lands while this turn is still queued on the workspace, switching
|
|
3083
|
+
// sessions or loading a model is seen. The session lock is held, so the
|
|
3084
|
+
// slot can only be this turn's. The guard clears it on every return.
|
|
3085
|
+
let cancellation = Arc::new(PromptCancellation::default());
|
|
3086
|
+
self.prompt_cancellations
|
|
3087
|
+
.lock()
|
|
3088
|
+
.unwrap()
|
|
3089
|
+
.insert(session_id.to_string(), Arc::clone(&cancellation));
|
|
3090
|
+
let _registration = PromptRegistration {
|
|
3091
|
+
agent: self,
|
|
3092
|
+
session_id: session_id.clone(),
|
|
3093
|
+
cancellation: Arc::clone(&cancellation),
|
|
3094
|
+
};
|
|
3095
|
+
|
|
3066
3096
|
// Everything below (slash commands included) acts on the live session,
|
|
3067
3097
|
// so it has to be this one. Resource links are read relative to its cwd.
|
|
3068
3098
|
let mut workspace = WorkspaceHold::acquire(&self.workspace_lock).await;
|
|
3099
|
+
if cancellation.cancelled.load(Ordering::Acquire) {
|
|
3100
|
+
return Ok(PromptResponse::new(StopReason::Cancelled));
|
|
3101
|
+
}
|
|
3069
3102
|
self.activate_session(&session_id).await?;
|
|
3103
|
+
if cancellation.cancelled.load(Ordering::Acquire) {
|
|
3104
|
+
return Ok(PromptResponse::new(StopReason::Cancelled));
|
|
3105
|
+
}
|
|
3070
3106
|
|
|
3071
3107
|
// log every block so we can debug @ references and file context
|
|
3072
3108
|
for (i, block) in args.prompt.iter().enumerate() {
|
|
@@ -3204,7 +3240,7 @@ impl SiGitAgent {
|
|
|
3204
3240
|
|
|
3205
3241
|
let user_text = parts.join("\n");
|
|
3206
3242
|
|
|
3207
|
-
if user_text.trim().is_empty() && images.is_empty() {
|
|
3243
|
+
if user_text.trim().is_empty() && images.is_empty() && audio.is_empty() {
|
|
3208
3244
|
return Ok(PromptResponse::new(StopReason::EndTurn));
|
|
3209
3245
|
}
|
|
3210
3246
|
|
|
@@ -3230,17 +3266,18 @@ impl SiGitAgent {
|
|
|
3230
3266
|
match commands::resolve_command(&command) {
|
|
3231
3267
|
Some(custom) => commands::render(&custom.body, argument.as_deref()),
|
|
3232
3268
|
None => {
|
|
3233
|
-
return
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3269
|
+
return self
|
|
3270
|
+
.run_slash(
|
|
3271
|
+
cx,
|
|
3272
|
+
session_id,
|
|
3273
|
+
SlashCommand::Unknown(command, argument),
|
|
3274
|
+
&cancellation,
|
|
3275
|
+
)
|
|
3276
|
+
.await;
|
|
3240
3277
|
}
|
|
3241
3278
|
}
|
|
3242
3279
|
}
|
|
3243
|
-
Some(command) => return
|
|
3280
|
+
Some(command) => return self.run_slash(cx, session_id, command, &cancellation).await,
|
|
3244
3281
|
None => user_text,
|
|
3245
3282
|
};
|
|
3246
3283
|
|
|
@@ -3267,7 +3304,12 @@ impl SiGitAgent {
|
|
|
3267
3304
|
{
|
|
3268
3305
|
if self.auto_load_local_model {
|
|
3269
3306
|
self.start_startup_model_load_if_needed();
|
|
3270
|
-
|
|
3307
|
+
tokio::select! {
|
|
3308
|
+
ready = self.await_model_ready(cx, &session_id) => ready?,
|
|
3309
|
+
() = cancellation.cancelled() => {
|
|
3310
|
+
return Ok(PromptResponse::new(StopReason::Cancelled));
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3271
3313
|
} else {
|
|
3272
3314
|
self.send_assistant_message(
|
|
3273
3315
|
cx,
|
|
@@ -3280,11 +3322,9 @@ impl SiGitAgent {
|
|
|
3280
3322
|
}
|
|
3281
3323
|
}
|
|
3282
3324
|
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
.unwrap()
|
|
3287
|
-
.insert(session_id.to_string(), Arc::clone(&cancellation));
|
|
3325
|
+
if cancellation.cancelled.load(Ordering::Acquire) {
|
|
3326
|
+
return Ok(PromptResponse::new(StopReason::Cancelled));
|
|
3327
|
+
}
|
|
3288
3328
|
|
|
3289
3329
|
// ── tool-calling loop ────────────────────────────────────────────
|
|
3290
3330
|
// send message → execute any tool calls → feed results back
|
|
@@ -3987,6 +4027,24 @@ impl SiGitAgent {
|
|
|
3987
4027
|
}
|
|
3988
4028
|
}
|
|
3989
4029
|
|
|
4030
|
+
/// Run a built-in slash command as a turn. A `session/cancel` ends it with
|
|
4031
|
+
/// `Cancelled`; only `/compact` and `/load` take long enough to notice.
|
|
4032
|
+
async fn run_slash(
|
|
4033
|
+
&self,
|
|
4034
|
+
cx: &ConnectionTo<Client>,
|
|
4035
|
+
session_id: SessionId,
|
|
4036
|
+
command: SlashCommand,
|
|
4037
|
+
cancellation: &PromptCancellation,
|
|
4038
|
+
) -> agent_client_protocol::Result<PromptResponse> {
|
|
4039
|
+
if cancellation.cancelled.load(Ordering::Acquire) {
|
|
4040
|
+
return Ok(PromptResponse::new(StopReason::Cancelled));
|
|
4041
|
+
}
|
|
4042
|
+
tokio::select! {
|
|
4043
|
+
response = exec_slash_acp(self, cx, session_id, command) => response,
|
|
4044
|
+
() = cancellation.cancelled() => Ok(PromptResponse::new(StopReason::Cancelled)),
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
|
|
3990
4048
|
fn finish_prompt(&self, session_id: &SessionId, cancellation: &Arc<PromptCancellation>) {
|
|
3991
4049
|
let key = session_id.to_string();
|
|
3992
4050
|
let mut active = self.prompt_cancellations.lock().unwrap();
|
|
@@ -6187,7 +6245,26 @@ async fn main() -> anyhow::Result<()> {
|
|
|
6187
6245
|
}
|
|
6188
6246
|
#[cfg(not(unix))]
|
|
6189
6247
|
{
|
|
6190
|
-
|
|
6248
|
+
// No TUI on non-Unix: the interactive full-screen client relies on
|
|
6249
|
+
// fd redirection that only exists on Unix. A bare launch in a
|
|
6250
|
+
// terminal (the common case, and exactly what the winget installer
|
|
6251
|
+
// validator does — run `sigit.exe` with no arguments) therefore has
|
|
6252
|
+
// nothing to do, so print how to use the binary and exit cleanly.
|
|
6253
|
+
// Bailing here instead would return a non-zero exit code, which the
|
|
6254
|
+
// validator reads as a failure (Validation-Executable-Error).
|
|
6255
|
+
println!(
|
|
6256
|
+
"siGit Code v{}\n\n\
|
|
6257
|
+
Interactive terminal mode is Unix-only (macOS / Linux). On this \
|
|
6258
|
+
platform sigit runs as an ACP agent for editor integration, or \
|
|
6259
|
+
non-interactively from a script:\n\n\
|
|
6260
|
+
\x20 sigit run \"<prompt>\" run one prompt and exit\n\
|
|
6261
|
+
\x20 sigit --version print the version\n\
|
|
6262
|
+
\x20 sigit login sign in to siGit Code Cloud\n\n\
|
|
6263
|
+
Point your editor's ACP client at this binary to use it \
|
|
6264
|
+
interactively.",
|
|
6265
|
+
env!("CARGO_PKG_VERSION")
|
|
6266
|
+
);
|
|
6267
|
+
Ok(())
|
|
6191
6268
|
}
|
|
6192
6269
|
} else {
|
|
6193
6270
|
// ACP mode: keep stdout untouched for protocol JSON only.
|
|
@@ -6406,6 +6483,71 @@ mod tests {
|
|
|
6406
6483
|
assert!(agent.active_session.lock().unwrap().is_none());
|
|
6407
6484
|
}
|
|
6408
6485
|
|
|
6486
|
+
#[tokio::test]
|
|
6487
|
+
async fn a_turn_leaves_no_cancellation_behind_however_it_returns() {
|
|
6488
|
+
let agent = SiGitAgent::new(
|
|
6489
|
+
Arc::new(ChatEngine::new()),
|
|
6490
|
+
default_local_model_config(),
|
|
6491
|
+
Arc::new(AtomicBool::new(true)),
|
|
6492
|
+
Arc::new(AtomicBool::new(false)),
|
|
6493
|
+
Arc::new(std::sync::Mutex::new(None)),
|
|
6494
|
+
false,
|
|
6495
|
+
false,
|
|
6496
|
+
);
|
|
6497
|
+
let session_id = SessionId::new("early");
|
|
6498
|
+
let turn = Arc::new(PromptCancellation::default());
|
|
6499
|
+
agent
|
|
6500
|
+
.prompt_cancellations
|
|
6501
|
+
.lock()
|
|
6502
|
+
.unwrap()
|
|
6503
|
+
.insert("early".into(), Arc::clone(&turn));
|
|
6504
|
+
let registration = PromptRegistration {
|
|
6505
|
+
agent: &agent,
|
|
6506
|
+
session_id: session_id.clone(),
|
|
6507
|
+
cancellation: Arc::clone(&turn),
|
|
6508
|
+
};
|
|
6509
|
+
|
|
6510
|
+
// A cancel that arrives before the turn reaches inference is recorded
|
|
6511
|
+
// and stays visible to every check the turn makes afterwards.
|
|
6512
|
+
agent
|
|
6513
|
+
.handle_cancel(CancelNotification::new(session_id.clone()))
|
|
6514
|
+
.await
|
|
6515
|
+
.unwrap();
|
|
6516
|
+
assert!(turn.cancelled.load(Ordering::Acquire));
|
|
6517
|
+
tokio::time::timeout(std::time::Duration::from_millis(50), turn.cancelled())
|
|
6518
|
+
.await
|
|
6519
|
+
.expect("a pre-cancelled turn must resolve at once");
|
|
6520
|
+
|
|
6521
|
+
drop(registration);
|
|
6522
|
+
assert!(agent.prompt_cancellations.lock().unwrap().is_empty());
|
|
6523
|
+
}
|
|
6524
|
+
|
|
6525
|
+
#[tokio::test]
|
|
6526
|
+
async fn a_finished_turn_does_not_remove_its_successors_cancellation() {
|
|
6527
|
+
let agent = SiGitAgent::new(
|
|
6528
|
+
Arc::new(ChatEngine::new()),
|
|
6529
|
+
default_local_model_config(),
|
|
6530
|
+
Arc::new(AtomicBool::new(true)),
|
|
6531
|
+
Arc::new(AtomicBool::new(false)),
|
|
6532
|
+
Arc::new(std::sync::Mutex::new(None)),
|
|
6533
|
+
false,
|
|
6534
|
+
false,
|
|
6535
|
+
);
|
|
6536
|
+
let old = Arc::new(PromptCancellation::default());
|
|
6537
|
+
let new = Arc::new(PromptCancellation::default());
|
|
6538
|
+
agent
|
|
6539
|
+
.prompt_cancellations
|
|
6540
|
+
.lock()
|
|
6541
|
+
.unwrap()
|
|
6542
|
+
.insert("s".into(), Arc::clone(&new));
|
|
6543
|
+
drop(PromptRegistration {
|
|
6544
|
+
agent: &agent,
|
|
6545
|
+
session_id: SessionId::new("s"),
|
|
6546
|
+
cancellation: old,
|
|
6547
|
+
});
|
|
6548
|
+
assert!(agent.prompt_cancellations.lock().unwrap().contains_key("s"));
|
|
6549
|
+
}
|
|
6550
|
+
|
|
6409
6551
|
#[tokio::test]
|
|
6410
6552
|
async fn cancel_signals_only_the_matching_active_prompt() {
|
|
6411
6553
|
let agent = SiGitAgent::new(
|