mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-08 01:09:46 -10:00
Compare commits
22
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4578dacc0 | ||
|
|
164150633a | ||
|
|
5d080ef46b | ||
|
|
1d233c0a9b | ||
|
|
de1443b2ed | ||
|
|
84c1b15540 | ||
|
|
6393a90ed6 | ||
|
|
cd3e0b0a9f | ||
|
|
aa9ba8412e | ||
|
|
a97db8832f | ||
|
|
ef4da1323f | ||
|
|
1e848492e5 | ||
|
|
2ffe1831b0 | ||
|
|
13e2596b2e | ||
|
|
8c4e759798 | ||
|
|
d597f0e095 | ||
|
|
ce2fcffaf1 | ||
|
|
61b09364f0 | ||
|
|
d1a0d048ee | ||
|
|
c88c77bf70 | ||
|
|
640d936bfb | ||
|
|
8e363fcaa5 |
No files matched your search
@@ -206,55 +206,10 @@ jobs:
|
||||
# Platform payloads first under the `platform` dist-tag, then the wrapper,
|
||||
# with the `latest` dist-tag checked before and after (platform versions
|
||||
# are semver PRERELEASES of the wrapper version and must never become
|
||||
# `latest`). Versions already on the registry are skipped, so "Re-run
|
||||
# failed jobs" is safe after a partial publish.
|
||||
# `latest`). npm applies publishes asynchronously, so the script waits
|
||||
# until npm shows every platform version before the wrapper goes out,
|
||||
# and until `latest` moves after it. Versions already on the registry
|
||||
# are skipped, so "Re-run failed jobs" is safe after a partial publish.
|
||||
- name: Publish npm packages
|
||||
shell: bash
|
||||
run: scripts/npm/publish-packages.sh dist/npm
|
||||
|
||||
# One final release under the pre-rename name @gitlawb/zero. Zero 0.9.0's
|
||||
# `zero upgrade` runs `npm install -g @gitlawb/zero@latest`, and people
|
||||
# reinstall the old name from shell history and old tutorials, so this
|
||||
# release is published once more under it: the same verified artifacts,
|
||||
# assembled as @gitlawb/zero, which the binary and wrapper recognise and
|
||||
# answer with the switch steps (docs/NPM_PACKAGING.md). Runs after the
|
||||
# @twigpine/zero publish, so the package it points at already exists.
|
||||
#
|
||||
# The gate keeps this to a single release: it is owed only while the old
|
||||
# name's latest is still the last pre-rename version, or is this version
|
||||
# (a re-run after it went out). After this release, `npm deprecate` the
|
||||
# old package and delete these two steps.
|
||||
- name: Check whether the final @gitlawb/zero release is owed
|
||||
id: legacy-name
|
||||
shell: bash
|
||||
env:
|
||||
LAST_PRE_RENAME_VERSION: 0.9.0
|
||||
run: |
|
||||
version="$(node -p "require('./package.json').version")"
|
||||
latest=""
|
||||
for _ in 1 2 3; do
|
||||
latest="$(npm view @gitlawb/zero dist-tags.latest 2>/dev/null || true)"
|
||||
if [ -n "$latest" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
if [ -z "$latest" ]; then
|
||||
echo "::error::could not read the latest dist-tag of @gitlawb/zero from the registry" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$latest" = "$LAST_PRE_RENAME_VERSION" ] || [ "$latest" = "$version" ]; then
|
||||
owed=true
|
||||
else
|
||||
owed=false
|
||||
fi
|
||||
echo "@gitlawb/zero latest is ${latest}; final release under the old name owed: ${owed}"
|
||||
echo "owed=${owed}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Publish the final @gitlawb/zero release
|
||||
if: ${{ steps.legacy-name.outputs.owed == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
node scripts/npm/build-platform-packages.mjs \
|
||||
--artifacts-dir dist/artifacts --out-dir dist/npm-legacy --package-name @gitlawb/zero
|
||||
scripts/npm/publish-packages.sh dist/npm-legacy
|
||||
@@ -1 +1 @@
|
||||
{".":"0.10.0"}
|
||||
{".":"0.11.0"}
|
||||
@@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) once the first release is
|
||||
tagged. Until then, source builds report the version `dev`.
|
||||
|
||||
## [0.11.0](https://github.com/Twigpine/zero/compare/v0.10.0...v0.11.0) (2026-10-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **providers:** add Concentrate provider preset ([#1147](https://github.com/Twigpine/zero/issues/1147)) ([61b0936](https://github.com/Twigpine/zero/commit/61b09364f0f45b0fa8aebaf0a6c3d1c55dbe01c3))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** let providers subcommands run with no active provider ([#1143](https://github.com/Twigpine/zero/issues/1143)) ([d1a0d04](https://github.com/Twigpine/zero/commit/d1a0d048ee2c1e7cbfb75160ec4c9f099f3c4472))
|
||||
* **npm:** wait for npm to apply each publish, and drop the one-time @gitlawb/zero steps ([#1145](https://github.com/Twigpine/zero/issues/1145)) ([8e363fc](https://github.com/Twigpine/zero/commit/8e363fcaa5d51bf5b5b244692dc61bf8d4ae8799))
|
||||
* **tui,cli:** stop a repository's git config from running programs in Zero's own git calls ([#1133](https://github.com/Twigpine/zero/issues/1133)) ([640d936](https://github.com/Twigpine/zero/commit/640d936bfbe00c4cd3017ca35fb7b5c15d91a1c5))
|
||||
* **workspaceindex:** skip git-ignored and build-cache dirs in Scan only ([#1117](https://github.com/Twigpine/zero/issues/1117)) ([c88c77b](https://github.com/Twigpine/zero/commit/c88c77bf701039dca01d9786bf5648d779c949b3))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **redaction:** add fast-path byte checks to eliminate regex allocations on clean strings ([#945](https://github.com/Twigpine/zero/issues/945)) ([ce2fcff](https://github.com/Twigpine/zero/commit/ce2fcffaf10d8e8c8c5a13e06fd7809f09fc9867))
|
||||
|
||||
## [0.10.0](https://github.com/Twigpine/zero/compare/v0.9.0...v0.10.0) (2026-10-15)
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-blue"></a>
|
||||
<img alt="Go 1.26.9+" src="https://img.shields.io/badge/Go-1.26.9+-00ADD8?logo=go&logoColor=white">
|
||||
<img alt="Go 1.26.10+" src="https://img.shields.io/badge/Go-1.26.10+-00ADD8?logo=go&logoColor=white">
|
||||
<img alt="25+ providers" src="https://img.shields.io/badge/providers-25+-34E2EA">
|
||||
<a href="https://discord.gg/CaQDS6wdFn"><img alt="Discord" src="https://img.shields.io/badge/Discord-join-5865F2?logo=discord&logoColor=white"></a>
|
||||
<br>
|
||||
@@ -158,7 +158,7 @@ irm https://raw.githubusercontent.com/Twigpine/zero/main/scripts/install.ps1 | i
|
||||
|
||||
### From source
|
||||
|
||||
Source builds require Go 1.26.9+.
|
||||
Source builds require Go 1.26.10+.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Twigpine/zero.git
|
||||
@@ -173,17 +173,18 @@ If you are testing before the first public release, build from source:
|
||||
go build -o zero ./cmd/zero
|
||||
```
|
||||
|
||||
On Linux, build the sandbox helper too if you want native sandboxing:
|
||||
On Linux, native sandboxing needs Bubblewrap. The main `zero` binary re-executes
|
||||
itself as the helper when `zero-linux-sandbox` is absent. A separate helper next
|
||||
to `zero` or on `PATH` still takes precedence:
|
||||
|
||||
```bash
|
||||
go build -o zero-linux-sandbox ./cmd/zero-linux-sandbox
|
||||
go build -o zero-seccomp ./cmd/zero-seccomp # optional compatibility wrapper
|
||||
go build -o zero-linux-sandbox ./cmd/zero-linux-sandbox # optional
|
||||
go build -o zero-seccomp ./cmd/zero-seccomp # optional compatibility wrapper
|
||||
```
|
||||
|
||||
Put `zero` and `zero-linux-sandbox` in the same directory on `PATH`
|
||||
(`~/.local/bin` is a good default). macOS does not need an extra helper binary.
|
||||
Windows source builds can use the main `zero.exe` as their sandbox helper; release
|
||||
archives still ship standalone Windows helper executables.
|
||||
Put `zero` on `PATH` (`~/.local/bin` is a good default). macOS does not need an
|
||||
extra helper binary. Windows source builds can use the main `zero.exe` as their
|
||||
sandbox helper; release archives still ship standalone Windows helper executables.
|
||||
|
||||
More install details: [docs/INSTALL.md](docs/INSTALL.md).
|
||||
|
||||
@@ -216,6 +217,7 @@ export AIMLAPI_API_KEY=...
|
||||
export LONGCAT_API_KEY=...
|
||||
export FIREWORKS_API_KEY=...
|
||||
export GMI_API_KEY=...
|
||||
export CONCENTRATE_API_KEY=...
|
||||
export MINIMAX_API_KEY=...
|
||||
export MINIMAXI_API_KEY=...
|
||||
```
|
||||
@@ -244,6 +246,12 @@ To configure GMI Cloud directly, run:
|
||||
zero providers setup gmicloud --set-active
|
||||
```
|
||||
|
||||
To configure Concentrate directly, run:
|
||||
|
||||
```bash
|
||||
zero providers setup concentrate --set-active
|
||||
```
|
||||
|
||||
MiniMax presets use the Anthropic-compatible endpoints for the global and China
|
||||
regions:
|
||||
|
||||
|
||||
+13
-6
@@ -12,7 +12,7 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-blue"></a>
|
||||
<img alt="Go 1.26.9+" src="https://img.shields.io/badge/Go-1.26.9+-00ADD8?logo=go&logoColor=white">
|
||||
<img alt="Go 1.26.10+" src="https://img.shields.io/badge/Go-1.26.10+-00ADD8?logo=go&logoColor=white">
|
||||
<img alt="25+ providers" src="https://img.shields.io/badge/providers-25+-34E2EA">
|
||||
<a href="https://discord.gg/CaQDS6wdFn"><img alt="Discord" src="https://img.shields.io/badge/Discord-join-5865F2?logo=discord&logoColor=white"></a>
|
||||
<br>
|
||||
@@ -136,7 +136,7 @@ irm https://raw.githubusercontent.com/Twigpine/zero/main/scripts/install.ps1 | i
|
||||
|
||||
### 从源码构建
|
||||
|
||||
源码构建需要 Go 1.26.9+。
|
||||
源码构建需要 Go 1.26.10+。
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Twigpine/zero.git
|
||||
@@ -150,14 +150,14 @@ go run ./cmd/zero
|
||||
go build -o zero ./cmd/zero
|
||||
```
|
||||
|
||||
在 Linux 上,如果你需要原生沙箱,还需要构建沙箱辅助程序:
|
||||
在 Linux 上,原生沙箱需要 Bubblewrap。主程序 `zero` 在找不到 `zero-linux-sandbox` 时会以自身作为辅助进程重新执行。同目录或 PATH 上的独立 helper 仍优先:
|
||||
|
||||
```bash
|
||||
go build -o zero-linux-sandbox ./cmd/zero-linux-sandbox
|
||||
go build -o zero-seccomp ./cmd/zero-seccomp # 可选的兼容性包装器
|
||||
go build -o zero-linux-sandbox ./cmd/zero-linux-sandbox # 可选
|
||||
go build -o zero-seccomp ./cmd/zero-seccomp # 可选的兼容性包装器
|
||||
```
|
||||
|
||||
将 `zero` 和 `zero-linux-sandbox` 放在 `PATH` 上的同一目录中(`~/.local/bin` 是一个好的默认选择)。macOS 不需要额外的辅助二进制文件。Windows 源码构建可以使用主 `zero.exe` 作为沙箱辅助程序;发布包仍然附带独立的 Windows 辅助可执行文件。
|
||||
将 `zero` 放在 `PATH` 上(`~/.local/bin` 是一个好的默认选择)。macOS 不需要额外的辅助二进制文件。Windows 源码构建可以使用主 `zero.exe` 作为沙箱辅助程序;发布包仍然附带独立的 Windows 辅助可执行文件。
|
||||
|
||||
更多安装细节:[docs/INSTALL.md](docs/INSTALL.md)。
|
||||
|
||||
@@ -186,6 +186,7 @@ export ANTHROPIC_API_KEY=...
|
||||
export GEMINI_API_KEY=...
|
||||
export LONGCAT_API_KEY=...
|
||||
export GMI_API_KEY=...
|
||||
export CONCENTRATE_API_KEY=...
|
||||
```
|
||||
|
||||
要直接配置美团 LongCat(LongCat-2.0),运行:
|
||||
@@ -200,6 +201,12 @@ zero providers setup longcat --set-active
|
||||
zero providers setup gmicloud --set-active
|
||||
```
|
||||
|
||||
要直接配置 Concentrate,运行:
|
||||
|
||||
```bash
|
||||
zero providers setup concentrate --set-active
|
||||
```
|
||||
|
||||
对于本地模型,运行 Ollama、LM Studio 或 [Atomic Chat](https://atomic.chat) 桌面应用,
|
||||
然后使用 `zero setup` 或 `zero providers detect`。使用 Atomic Chat 时,请先加载模型并启用
|
||||
本地 OpenAI 兼容 API(默认地址为 `http://127.0.0.1:1337/v1`),再选择 `atomic-chat-local`。
|
||||
|
||||
+5
-5
@@ -2,8 +2,8 @@
|
||||
|
||||
## Questions, setup help, configuration
|
||||
|
||||
Ask in [GitHub Discussions](https://github.com/Gitlawb/zero/discussions). Use
|
||||
[Q&A](https://github.com/Gitlawb/zero/discussions/categories/q-a) so answers can
|
||||
Ask in [GitHub Discussions](https://github.com/Twigpine/zero/discussions). Use
|
||||
[Q&A](https://github.com/Twigpine/zero/discussions/categories/q-a) so answers can
|
||||
be marked and found by the next person.
|
||||
|
||||
The fastest way to a useful answer is to include:
|
||||
@@ -18,19 +18,19 @@ The fastest way to a useful answer is to include:
|
||||
## Bugs
|
||||
|
||||
If Zero does something wrong (crashes, wrong output, broken behavior), file a
|
||||
[bug report](https://github.com/Gitlawb/zero/issues/new/choose). If you are not
|
||||
[bug report](https://github.com/Twigpine/zero/issues/new/choose). If you are not
|
||||
sure whether it is a bug or a setup problem, start in Discussions and we will
|
||||
promote it to an issue if it is one.
|
||||
|
||||
## Feature ideas
|
||||
|
||||
Start a thread in
|
||||
[Ideas](https://github.com/Gitlawb/zero/discussions/categories/ideas). Zero is
|
||||
[Ideas](https://github.com/Twigpine/zero/discussions/categories/ideas). Zero is
|
||||
in controlled development (see CONTRIBUTING.md), so discussing an idea first is
|
||||
also the path to getting a PR accepted.
|
||||
|
||||
## Security issues
|
||||
|
||||
Never file a public issue or discussion. Report privately via
|
||||
[GitHub Security Advisories](https://github.com/Gitlawb/zero/security/advisories/new)
|
||||
[GitHub Security Advisories](https://github.com/Twigpine/zero/security/advisories/new)
|
||||
(see SECURITY.md).
|
||||
@@ -5,7 +5,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/perfbench"
|
||||
"github.com/Twigpine/zero/internal/perfbench"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/perfbench"
|
||||
"github.com/Twigpine/zero/internal/perfbench"
|
||||
)
|
||||
|
||||
func TestParseArgsUsesCliAndEnvOverrides(t *testing.T) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/perfbench"
|
||||
"github.com/Twigpine/zero/internal/perfbench"
|
||||
)
|
||||
|
||||
// taskOptions configures the `zero-perf-bench tasks` subcommand: the reproducible
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/execprofile"
|
||||
"github.com/Gitlawb/zero/internal/perfbench"
|
||||
"github.com/Twigpine/zero/internal/execprofile"
|
||||
"github.com/Twigpine/zero/internal/perfbench"
|
||||
)
|
||||
|
||||
// turnOptions configures the `zero-perf-bench turn` subcommand: the per-turn
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/review"
|
||||
"github.com/Twigpine/zero/internal/review"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/release"
|
||||
"github.com/Twigpine/zero/internal/release"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
+5
-1
@@ -3,9 +3,13 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/cli"
|
||||
"github.com/Twigpine/zero/internal/cli"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 && os.Args[1] == sandbox.LinuxSandboxHelperSubcommand {
|
||||
os.Exit(sandbox.RunLinuxSandboxHelper(os.Args[1:], os.Stderr))
|
||||
}
|
||||
os.Exit(cli.Run(os.Args[1:], os.Stdout, os.Stderr))
|
||||
}
|
||||
@@ -110,6 +110,8 @@ Discovery roots (earlier wins on name collisions):
|
||||
|
||||
A missing directory is fine — Zero just omits it. Management commands (`zero skill add` / `zero skill remove`) always write to the primary Zero dir only; `list` / `info` search primary + `~/.agents/skills`. `skill info` reports lock source/hash when present and whether the on-disk `SKILL.md` has drifted from the recorded hash.
|
||||
|
||||
For a skill installed since Zero started installing bundled files, `skill info` also reports drift in any file installed with it.
|
||||
|
||||
```text
|
||||
~/.local/share/zero/skills/ # primary (install/remove target)
|
||||
run-benchmarks/
|
||||
@@ -140,6 +142,15 @@ Only `name` and `description` are recognized in the frontmatter today. The `name
|
||||
|
||||
The `skill` tool lets the agent load any discovered skill by name (primary, agents, or plugin).
|
||||
|
||||
A skill can ship files beside its `SKILL.md`, in the [agentskills.io](https://agentskills.io/specification) layout: `scripts/`, `references/`, `assets/` or anything else the instructions refer to. `zero skill add` installs the whole skill directory, leaving out hidden entries such as `.git` and not following or copying symlinks (it lists any it skipped). A skill larger than 1,000 files or 32 MiB is refused. When the `skill` tool loads a skill that has such files, its output ends with the skill's directory and a list of the files, so instructions like "run `scripts/fill.py`" can be followed. Running a bundled script goes through the normal tool permissions; installing or loading a skill never runs anything.
|
||||
|
||||
```text
|
||||
pdf/
|
||||
SKILL.md
|
||||
scripts/fill.py
|
||||
references/form-fields.md
|
||||
```
|
||||
|
||||
## 4. Hooks
|
||||
|
||||
Hooks fire shell commands on lifecycle events. Configure them in JSON:
|
||||
|
||||
+27
-14
@@ -185,13 +185,19 @@ describe a version that is no longer on disk. Prefer `mise upgrade`.
|
||||
go install github.com/Gitlawb/zero/cmd/zero@latest
|
||||
```
|
||||
|
||||
This builds from source, so it needs Go 1.26.9+ and it does not go through the
|
||||
Every release so far declares the module path `github.com/Gitlawb/zero`, so
|
||||
`go install` has to use that path; `github.com/Twigpine/zero/cmd/zero@latest`
|
||||
fails with "module declares its path as" until a release is tagged with the new
|
||||
module path.
|
||||
|
||||
This builds from source, so it needs Go 1.26.10+ and it does not go through the
|
||||
release archives. Two consequences worth knowing before you pick it:
|
||||
|
||||
- On Linux you also need the sandbox helper, which is a separate binary and is
|
||||
not installed by this command. See
|
||||
- On Linux, Bubblewrap is still required for native sandboxing. Zero resolves
|
||||
the helper in this order: an executable `zero-linux-sandbox` next to `zero`,
|
||||
then `PATH`, then self-exec of the main binary. Standalone helpers remain
|
||||
optional and preferred. See
|
||||
[Sandbox Helpers For Source Builds](#sandbox-helpers-for-source-builds).
|
||||
Without it, native sandboxing is unavailable.
|
||||
- `zero upgrade` treats the result as a standalone install and will replace the
|
||||
binary with a release build rather than rebuilding from source. If you chose
|
||||
`go install` deliberately, rerun it instead.
|
||||
@@ -212,25 +218,32 @@ Build a local binary:
|
||||
go build -o zero ./cmd/zero
|
||||
```
|
||||
|
||||
Source builds require Go 1.26.9+.
|
||||
Source builds require Go 1.26.10+.
|
||||
|
||||
### Sandbox Helpers For Source Builds
|
||||
|
||||
Release archives include the platform sandbox helpers. If you build directly
|
||||
from source, build the helpers you need:
|
||||
Release archives include the platform sandbox helpers. A source build of the
|
||||
main `zero` binary is enough for Linux native sandboxing. Zero resolves the
|
||||
helper in this order:
|
||||
|
||||
Linux:
|
||||
1. an executable `zero-linux-sandbox` next to `zero`
|
||||
2. then `PATH`
|
||||
3. then self-exec of the main binary
|
||||
|
||||
Bubblewrap must still be installed. Standalone helpers remain optional and
|
||||
preferred.
|
||||
|
||||
A separate helper remains supported if it sits next to `zero` or on `PATH`:
|
||||
|
||||
```bash
|
||||
go build -o zero ./cmd/zero
|
||||
go build -o zero-linux-sandbox ./cmd/zero-linux-sandbox
|
||||
go build -o zero-seccomp ./cmd/zero-seccomp
|
||||
go build -o zero-linux-sandbox ./cmd/zero-linux-sandbox # optional
|
||||
go build -o zero-seccomp ./cmd/zero-seccomp # optional compatibility wrapper
|
||||
```
|
||||
|
||||
Put `zero` and `zero-linux-sandbox` in the same directory on `PATH`, for example
|
||||
`~/.local/bin`. `zero-seccomp` is kept as a compatibility wrapper; the sandbox
|
||||
helper applies the Unix-socket filter itself when that sandbox option is enabled.
|
||||
Linux native sandboxing also requires Bubblewrap to be installed.
|
||||
Put `zero` on `PATH`, for example `~/.local/bin`. `zero-seccomp` is kept as a
|
||||
compatibility wrapper; the sandbox helper applies the Unix-socket filter itself
|
||||
when that sandbox option is enabled.
|
||||
|
||||
macOS uses the system sandbox and does not need an extra helper binary.
|
||||
|
||||
|
||||
+26
-44
@@ -130,9 +130,14 @@ registry.
|
||||
bootstrap publish) — a missing value must not abort the job between the
|
||||
platform and wrapper publishes, which would strand a half-published
|
||||
release.
|
||||
2. **Platform versions publish before the wrapper.** The wrapper's
|
||||
`optionalDependencies` pin exact suffixed versions; publishing the wrapper
|
||||
first would create a window where installs resolve aliases that 404.
|
||||
2. **Platform versions are on the registry before the wrapper.** The
|
||||
wrapper's `optionalDependencies` pin exact suffixed versions; publishing
|
||||
the wrapper first would create a window where installs resolve aliases
|
||||
that 404. Ordering the uploads is not enough: npm applies a publish
|
||||
asynchronously, and in 0.10.0 a platform version appeared ten minutes
|
||||
after its upload returned, after the wrapper. The publish script waits
|
||||
until npm shows every platform version before it publishes the wrapper,
|
||||
and waits the same way for `latest` afterwards (up to 30 minutes in all).
|
||||
3. **Exact-version pinning.** The wrapper at `X.Y.Z` references platform
|
||||
versions `X.Y.Z-<platform>-<arch>` exactly — never ranges — so a wrapper
|
||||
and its binaries can never skew. The publish script refuses to start when
|
||||
@@ -161,54 +166,31 @@ bin, so npm refuses to install one over the other (`EEXIST`), and forcing it
|
||||
lets a later uninstall of the old package delete the shared bin. The user
|
||||
has to uninstall the old package and install the new one, in that order.
|
||||
|
||||
Deprecating the old package alone does not reach existing users. 0.9.0's
|
||||
`zero upgrade` runs `npm install -g @gitlawb/zero@latest`; with nothing newer
|
||||
under that name, npm reinstalls nothing, prints no deprecation warning (it
|
||||
only warns when it installs something), and Zero reports the update as done.
|
||||
So 0.10.0 is published once more under the old name, as a bridge:
|
||||
Deprecating the old package alone would not have reached existing users.
|
||||
0.9.0's `zero upgrade` runs `npm install -g @gitlawb/zero@latest`; with
|
||||
nothing newer under that name, npm reinstalls nothing, prints no deprecation
|
||||
warning (it only warns when it installs something), and Zero reports the
|
||||
update as done. So 0.10.0 was published once more under the old name, as a
|
||||
bridge:
|
||||
|
||||
- The publish job assembles the same verified artifacts a second time with
|
||||
`build-platform-packages.mjs --package-name @gitlawb/zero` and publishes
|
||||
them with the same script, after the `@twigpine/zero` publish. A gate runs
|
||||
it only while the old name's `latest` is still 0.9.0 (or is this version,
|
||||
on a re-run), so it cannot happen twice.
|
||||
- The release job assembled the same verified artifacts a second time with
|
||||
`build-platform-packages.mjs --package-name @gitlawb/zero` and published
|
||||
them with the same script, after the `@twigpine/zero` publish. The steps
|
||||
that did this ran once and have been removed from `release-artifacts.yml`.
|
||||
- The bridge build knows its name from the `package.json` beside it. The Go
|
||||
binary reports it as `InstallMethodNpmLegacy`: `zero upgrade` refuses
|
||||
with the switch steps instead of reinstalling it, and `zero update --check`
|
||||
adds them. `bin/zero.js` prints the same steps after `zero` exits, on a
|
||||
terminal only.
|
||||
- Updating from 0.9.0 now installs a real version, so npm also shows the
|
||||
terminal only. This handling stays in the code, since only a build
|
||||
installed under the old name ever triggers it.
|
||||
- Updating from 0.9.0 installs that bridge build, so npm also shows the
|
||||
deprecation message.
|
||||
|
||||
### Runbook
|
||||
|
||||
Before the first release under the new name:
|
||||
|
||||
1. Create the package, since npm only attaches a trusted publisher to a
|
||||
package that exists: publish an empty `@twigpine/[email protected]` by hand with
|
||||
`npm publish --access public --tag bootstrap`, then
|
||||
`npm deprecate @twigpine/[email protected] "Placeholder; install @twigpine/zero@latest"`.
|
||||
2. Trust this workflow for it:
|
||||
`npm trust github @twigpine/zero --repo Twigpine/zero --file release-artifacts.yml --env npm-publish --allow-publish`.
|
||||
3. Point the old package's trusted publisher at this repository too, for the
|
||||
bridge publish: `npm trust list @gitlawb/zero`, revoke the existing entry
|
||||
with `npm trust revoke @gitlawb/zero --id <id>`, then run the same
|
||||
`npm trust github` command for `@gitlawb/zero`.
|
||||
4. Confirm Settings → Environments → `npm-publish` has a required reviewer.
|
||||
The environment exists either way; without a reviewer the job does not
|
||||
wait for approval.
|
||||
|
||||
After the release, once both packages show 0.10.0 as `latest`:
|
||||
|
||||
1. `npm deprecate @gitlawb/zero "Zero moved to @twigpine/zero. Switch with: npm uninstall -g @gitlawb/zero && npm install -g @twigpine/zero"`
|
||||
(no version range, so every version, including the platform payloads,
|
||||
carries it). Never unpublish: existing installs resolve their platform
|
||||
payload through these versions.
|
||||
2. Revoke the old package's trusted publisher (`npm trust revoke`), so
|
||||
nothing can publish under that name again.
|
||||
3. Delete the two `@gitlawb/zero` steps from `release-artifacts.yml`. The Go
|
||||
and wrapper handling of the old name can stay; it only activates in a
|
||||
build installed under that name.
|
||||
`@gitlawb/zero` is deprecated on every version and no longer has a trusted
|
||||
publisher, so this release workflow cannot publish it again; another version
|
||||
would take a maintainer publishing by hand. Its versions stay on the
|
||||
registry: existing installs resolve their platform payload through them, so
|
||||
they must never be unpublished.
|
||||
|
||||
## Runbook: bumping the vendored helpers
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/Gitlawb/zero
|
||||
module github.com/Twigpine/zero
|
||||
|
||||
go 1.26.9
|
||||
go 1.26.10
|
||||
|
||||
require (
|
||||
charm.land/bubbles/v2 v2.1.1
|
||||
|
||||
+27
-20
@@ -13,18 +13,18 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Gitlawb/zero/internal/config"
|
||||
"github.com/Gitlawb/zero/internal/modelregistry"
|
||||
"github.com/Gitlawb/zero/internal/providercatalog"
|
||||
"github.com/Gitlawb/zero/internal/providermodelcatalog"
|
||||
"github.com/Gitlawb/zero/internal/providermodeldiscovery"
|
||||
"github.com/Gitlawb/zero/internal/redaction"
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/sessions"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/usage"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/config"
|
||||
"github.com/Twigpine/zero/internal/modelregistry"
|
||||
"github.com/Twigpine/zero/internal/providercatalog"
|
||||
"github.com/Twigpine/zero/internal/providermodelcatalog"
|
||||
"github.com/Twigpine/zero/internal/providermodeldiscovery"
|
||||
"github.com/Twigpine/zero/internal/redaction"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sessions"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/usage"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// Deps are the ZERO capabilities the ACP Agent drives. The CLI fills these with
|
||||
@@ -528,8 +528,6 @@ func (a *Agent) runTurn(ctx context.Context, sess *acpSession, userText string,
|
||||
queue := func(input sessions.AppendEventInput) {
|
||||
pendingEvents = append(pendingEvents, input)
|
||||
}
|
||||
queue(messageEvent("user", userText))
|
||||
|
||||
visionCache := make(map[string]bool)
|
||||
var visionCacheMu sync.Mutex
|
||||
supportsVision := func(modelID string) bool {
|
||||
@@ -553,6 +551,9 @@ func (a *Agent) runTurn(ctx context.Context, sess *acpSession, userText string,
|
||||
effectivePrompt = fmt.Sprintf("[Note: %s]\n\n%s", msg, userText)
|
||||
images = nil
|
||||
}
|
||||
// Match the TUI: only images actually sent to the model enter history.
|
||||
attachments := sessions.MessageAttachments{Images: len(images)}
|
||||
queue(messageEvent("user", userText, attachments))
|
||||
|
||||
opts := agent.Options{
|
||||
Cwd: sess.cwd,
|
||||
@@ -593,7 +594,7 @@ func (a *Agent) runTurn(ctx context.Context, sess *acpSession, userText string,
|
||||
agentPrompt := buildPrompt(sess.snapshotHistory(), effectivePrompt)
|
||||
result, runErr := a.deps.RunAgent(ctx, agentPrompt, provider, opts)
|
||||
if result.FinalAnswer != "" {
|
||||
queue(messageEvent("assistant", result.FinalAnswer))
|
||||
queue(messageEvent("assistant", result.FinalAnswer, sessions.MessageAttachments{}))
|
||||
}
|
||||
reason, stopErr := stopReasonFor(result, runErr)
|
||||
if stopErr != nil {
|
||||
@@ -614,7 +615,7 @@ func (a *Agent) runTurn(ctx context.Context, sess *acpSession, userText string,
|
||||
// one file write, which is the contiguity restored here — not a disk
|
||||
// transaction, and not a promise about crashes mid-fsync. Reported by @jatmn.
|
||||
persistenceErr := a.persistTurn(sess.id, pendingEvents)
|
||||
sess.appendHistory(turnRecord{user: userText, assistant: result.FinalAnswer})
|
||||
sess.appendHistory(turnRecord{user: attachments.WithContent(userText), assistant: result.FinalAnswer})
|
||||
a.warnPersistence(
|
||||
note,
|
||||
"save session history",
|
||||
@@ -930,10 +931,14 @@ func (a *Agent) persistTurn(sessionID string, inputs []sessions.AppendEventInput
|
||||
return err
|
||||
}
|
||||
|
||||
func messageEvent(role, content string) sessions.AppendEventInput {
|
||||
func messageEvent(role, content string, attachments sessions.MessageAttachments) sessions.AppendEventInput {
|
||||
payload := map[string]any{"role": role, "content": content}
|
||||
if role == "user" && (attachments.Images > 0 || attachments.Documents > 0) {
|
||||
payload["attachments"] = attachments
|
||||
}
|
||||
return sessions.AppendEventInput{
|
||||
Type: sessions.EventMessage,
|
||||
Payload: map[string]any{"role": role, "content": content},
|
||||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1094,14 +1099,16 @@ func (a *Agent) loadHistory(sessionID string, requireHistoryLog bool) ([]turnRec
|
||||
continue
|
||||
}
|
||||
var msg struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
Attachments sessions.MessageAttachments `json:"attachments"`
|
||||
}
|
||||
if json.Unmarshal(raw, &msg) != nil {
|
||||
continue
|
||||
}
|
||||
switch msg.Role {
|
||||
case "user":
|
||||
msg.Content = msg.Attachments.WithContent(msg.Content)
|
||||
messages = append(messages, persistedMessage{eventID: persistedMessageIdentity(sessionID, e), role: msg.Role, content: msg.Content})
|
||||
if havePending {
|
||||
records = append(records, turnRecord{user: pendingUser})
|
||||
|
||||
@@ -19,13 +19,13 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Gitlawb/zero/internal/config"
|
||||
"github.com/Gitlawb/zero/internal/providermodeldiscovery"
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/sessions"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/config"
|
||||
"github.com/Twigpine/zero/internal/providermodeldiscovery"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sessions"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// fakeProvider streams a canned assistant message and ends the turn — enough to
|
||||
@@ -960,7 +960,11 @@ func TestACPHardTurnFailureDoesNotCommitHistory(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := h.client.Call(ctx, MethodSessionPrompt, PromptParams{
|
||||
SessionID: created.SessionID, Prompt: []ContentBlock{TextBlock("failed question")},
|
||||
SessionID: created.SessionID,
|
||||
Prompt: []ContentBlock{
|
||||
TextBlock("failed question"),
|
||||
ImageBlock(base64.StdEncoding.EncodeToString([]byte("failed image")), "image/png"),
|
||||
},
|
||||
}, &PromptResult{}); err == nil {
|
||||
t.Fatal("hard RunAgent failure was reported as a successful turn")
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
)
|
||||
|
||||
// ---- an offered option is an acceptable answer ----
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package acp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/config"
|
||||
"github.com/Twigpine/zero/internal/providermodeldiscovery"
|
||||
"github.com/Twigpine/zero/internal/sessions"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestACPImageAttachmentHistory(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
text string
|
||||
images int
|
||||
withoutVision bool
|
||||
want string
|
||||
}{
|
||||
{name: "image only", images: 1, want: "[1 image]"},
|
||||
{name: "text and images", text: "compare these", images: 2, want: "compare these [2 images]"},
|
||||
{name: "ignored by model", images: 1, withoutVision: true, want: ""},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
deps := testDeps(t)
|
||||
deps.DiscoverModels = func(context.Context, config.ProviderProfile) ([]providermodeldiscovery.Model, error) {
|
||||
modalities := []string{"text", "image"}
|
||||
if tc.withoutVision {
|
||||
modalities = []string{"text"}
|
||||
}
|
||||
return []providermodeldiscovery.Model{{ID: "fake-model", InputModalities: modalities}}, nil
|
||||
}
|
||||
type observedTurn struct {
|
||||
prompt string
|
||||
images int
|
||||
}
|
||||
turns := make(chan observedTurn, 8)
|
||||
deps.RunAgent = func(_ context.Context, prompt string, _ zeroruntime.Provider, opts agent.Options) (agent.Result, error) {
|
||||
turns <- observedTurn{prompt: prompt, images: len(opts.Images)}
|
||||
return agent.Result{FinalAnswer: "received"}, nil
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
workspace := t.TempDir()
|
||||
h := newHarness(t, deps)
|
||||
defer h.stop()
|
||||
var created NewSessionResult
|
||||
if err := h.client.Call(ctx, MethodSessionNew, NewSessionParams{Cwd: workspace}, &created); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
const imageData = "image-history-bytes-not-for-storage"
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(imageData))
|
||||
var blocks []ContentBlock
|
||||
if tc.text != "" {
|
||||
blocks = append(blocks, TextBlock(tc.text))
|
||||
}
|
||||
for range tc.images {
|
||||
blocks = append(blocks, ImageBlock(encoded, "image/png"))
|
||||
}
|
||||
if err := h.client.Call(ctx, MethodSessionPrompt, PromptParams{SessionID: created.SessionID, Prompt: blocks}, &PromptResult{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
live := <-turns
|
||||
wantLiveImages := tc.images
|
||||
if tc.withoutVision {
|
||||
wantLiveImages = 0
|
||||
}
|
||||
if live.images != wantLiveImages {
|
||||
t.Fatalf("live images = %d, want %d", live.images, wantLiveImages)
|
||||
}
|
||||
events, err := deps.Store.ReadEvents(created.SessionID)
|
||||
if err != nil || len(events) < 2 {
|
||||
t.Fatalf("read completed turn: events=%+v err=%v", events, err)
|
||||
}
|
||||
var user struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
Attachments struct {
|
||||
Images int `json:"images"`
|
||||
} `json:"attachments"`
|
||||
}
|
||||
if err := json.Unmarshal(events[0].Payload, &user); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if user.Role != "user" || user.Content != tc.text || user.Attachments.Images != wantLiveImages {
|
||||
t.Errorf("stored user event = %s, want original text and attachments.images=%d", events[0].Payload, wantLiveImages)
|
||||
}
|
||||
for _, event := range events {
|
||||
if bytes.Contains(event.Payload, []byte(encoded)) || bytes.Contains(event.Payload, []byte(imageData)) {
|
||||
t.Errorf("image data leaked into session event: %s", event.Payload)
|
||||
}
|
||||
}
|
||||
followUp := func(t *testing.T, client *clientHarness) {
|
||||
t.Helper()
|
||||
if err := client.client.Call(ctx, MethodSessionPrompt, PromptParams{
|
||||
SessionID: created.SessionID, Prompt: []ContentBlock{TextBlock("what did I send?")},
|
||||
}, &PromptResult{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := <-turns
|
||||
if want := "User: " + tc.want + "\n"; !strings.Contains(got.prompt, want) {
|
||||
t.Errorf("seeded prompt missing user history %q: %q", want, got.prompt)
|
||||
}
|
||||
if got.images != 0 {
|
||||
t.Errorf("historical images reattached: %d", got.images)
|
||||
}
|
||||
}
|
||||
followUp(t, h)
|
||||
h.stop()
|
||||
// Fresh agents and stores reproduce a process restart, with no shared
|
||||
// in-memory history to hide a missing attachment in the event log.
|
||||
for _, method := range []string{MethodSessionLoad, MethodSessionResume} {
|
||||
t.Run(method, func(t *testing.T) {
|
||||
restoredDeps := deps
|
||||
restoredDeps.Store = sessions.NewStore(sessions.StoreOptions{RootDir: deps.Store.RootDir})
|
||||
loader := newHarness(t, restoredDeps)
|
||||
defer loader.stop()
|
||||
if err := loader.client.Call(ctx, method, LoadSessionParams{SessionID: created.SessionID, Cwd: workspace}, &LoadSessionResult{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if method == MethodSessionLoad {
|
||||
select {
|
||||
case update := <-loader.notifications:
|
||||
if update.SessionUpdate != UpdateUserMessageChunk || update.Content.Text != tc.want {
|
||||
t.Errorf("replayed user = %+v, want %q", update, tc.want)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatal("user turn was not replayed")
|
||||
}
|
||||
} else {
|
||||
select {
|
||||
case update := <-loader.notifications:
|
||||
t.Errorf("resume replayed transcript: %+v", update)
|
||||
default:
|
||||
}
|
||||
}
|
||||
followUp(t, loader)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestACPAttachmentHistoryReadsExistingSessionMessages(t *testing.T) {
|
||||
deps := testDeps(t)
|
||||
meta, err := deps.Store.Create(sessions.CreateInput{SessionID: "attachment-compatibility", Cwd: t.TempDir()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i, payload := range []string{
|
||||
`{"role":"user","content":"old text"}`,
|
||||
`{"role":"user","content":"","attachments":{"images":1,"documents":2}}`,
|
||||
`{"role":"user","content":"still text","attachments":{"images":-1,"documents":1.5}}`,
|
||||
`{"role":"assistant","content":"answer","attachments":{"images":1}}`,
|
||||
} {
|
||||
if _, err := deps.Store.AppendEvent(meta.SessionID, sessions.AppendEventInput{Type: sessions.EventMessage, Payload: json.RawMessage(payload)}); err != nil {
|
||||
t.Fatalf("append message %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
a := &Agent{deps: deps}
|
||||
_, messages, _, err := a.loadHistory(meta.SessionID, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := []string{"old text", "[1 image] [2 documents]", "still text", "answer"}
|
||||
if len(messages) != len(want) {
|
||||
t.Fatalf("messages = %+v", messages)
|
||||
}
|
||||
for i, text := range want {
|
||||
if messages[i].content != text {
|
||||
t.Errorf("message %d = %q, want %q", i, messages[i].content, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Gitlawb/zero/internal/sessions"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/sessions"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// captureAgentOptions makes every turn record the agent.Options it was built
|
||||
|
||||
@@ -3,7 +3,7 @@ package acp
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
)
|
||||
|
||||
// permission.go maps ZERO's permission prompt model onto ACP's
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
)
|
||||
|
||||
func escalationRequest(escalates bool) agent.PermissionRequest {
|
||||
|
||||
@@ -3,7 +3,7 @@ package acp
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
)
|
||||
|
||||
func TestBuildPermissionOptions(t *testing.T) {
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
// translate.go maps ZERO's agent events onto ACP session/update payloads. The
|
||||
@@ -83,7 +83,7 @@ func browserToolDetails(name string) (*BrowserToolDetails, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
const zeroBrowserMetaKey = "github.com/Gitlawb/zero/browser"
|
||||
const zeroBrowserMetaKey = "github.com/Twigpine/zero/browser"
|
||||
|
||||
// attachBrowserToolDetails stores ZERO's browser descriptor in ACP's reserved
|
||||
// extension channel. Keeping this in one helper prevents start, result, and
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
func browserDescriptor(t *testing.T, update ToolCallUpdate) BrowserToolDetails {
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/agent"
|
||||
"github.com/Gitlawb/zero/internal/sessions"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/agent"
|
||||
"github.com/Twigpine/zero/internal/sessions"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// `zero exec` persists every provider usage report as a session usage event, so
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func enabledSelfCorrector(t *testing.T) *SelfCorrector {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
type normalizationRecordingShellTool struct {
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// providerCallingAskUserThenAnswer returns a mock provider whose first turn calls
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/testutil"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/testutil"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestAsyncDiagnosticsNilCollectorNoOps(t *testing.T) {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"mvdan.cc/sh/v3/syntax"
|
||||
)
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
func TestProposedCommandPrefixUsesSafeSimpleCommands(t *testing.T) {
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// Session compaction.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// compactableHistory returns a history whose middle is large enough to trip
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestCompactMessagesReturnsMetadataForManualCompaction(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// Compaction preservation.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// stateConversation is a long enough conversation that Compact elides a middle
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestClipBytesHandlesTinyLimitsOnRuneBoundaries(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// recentEdits extracts each mutated file's path and a one-line note from the
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
var markerPattern = regexp.MustCompile(`msg-\d+`)
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// --- Pure Compact() tests -------------------------------------------------
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// someRequestContains reports whether any message sent to the provider across all
|
||||
|
||||
@@ -3,7 +3,7 @@ package agent
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// Context budget.
|
||||
|
||||
@@ -3,7 +3,7 @@ package agent
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestMeasureContextSplitsByCategory(t *testing.T) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package agent
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
type contextPlannerConfig struct {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestContextPlannerPreservesProviderRequest(t *testing.T) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
// richMCPTool mimics a real MCP tool's schema (Exa/Firecrawl-style search): an
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestOptionsDeferThresholdFieldExists(t *testing.T) {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
func TestExecuteToolCallCategorizesFilteredDenial(t *testing.T) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
// argsPermTool implements tools.ArgsPermissioner; plainTool does not.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// TestOptionsModelSwitcherFieldExists asserts the escalation hook is an
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func equalStringSlices(left []string, right []string) bool {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/lsp"
|
||||
"github.com/Twigpine/zero/internal/lsp"
|
||||
)
|
||||
|
||||
// fileDiagnosticsTimeout bounds one inline post-edit diagnostics check so a
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
type customApplyPatchTool struct {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// Guardrail thresholds for the agent loop. These keep a runaway model from
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// emptyTurn is a stream that produces no visible text and no tool calls.
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/hooks"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/hooks"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
func TestAppendHookFeedbackFormatsOutput(t *testing.T) {
|
||||
|
||||
@@ -11,15 +11,15 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/execution"
|
||||
"github.com/Gitlawb/zero/internal/hooks"
|
||||
"github.com/Gitlawb/zero/internal/modelregistry"
|
||||
"github.com/Gitlawb/zero/internal/redaction"
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/streamjson"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/execution"
|
||||
"github.com/Twigpine/zero/internal/hooks"
|
||||
"github.com/Twigpine/zero/internal/modelregistry"
|
||||
"github.com/Twigpine/zero/internal/redaction"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/streamjson"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
const maxTurnsAnswer = "Agent reached maximum number of turns without a final answer."
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// imageEchoProvider records the messages of the first request it receives, then
|
||||
|
||||
@@ -13,13 +13,13 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/execution"
|
||||
"github.com/Gitlawb/zero/internal/hooks"
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/specmode"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/execution"
|
||||
"github.com/Twigpine/zero/internal/hooks"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/specmode"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
type mockProvider struct {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
type safetyTool struct {
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// midStreamAbortProvider connects successfully but emits a transport-abort
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/hooks"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/hooks"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
type propagationOutputTool struct {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
// Parallel read-ahead for tool batches. When a turn requests several
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// probeTool records execution overlap and ordering so tests can assert what
|
||||
|
||||
@@ -3,7 +3,7 @@ package agent
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
func TestPartitionToolsActiveAppendsLoadedToolAfterEagerBlock(t *testing.T) {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// countingSchemaTool records how many times its Parameters() schema is read, so a
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
// promptShellTool is a minimal shell-style tool whose Safety requires a prompt,
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
func TestPermissionScope(t *testing.T) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func planUpdateTurn(status string) zeroruntime.CollectedStream {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
)
|
||||
|
||||
// escalatingEngine allows unsandboxed escalation: no denied reads, so
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
// profileController observes per-turn run signals and decides at most one
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestProfileControllerNilPolicyIsNoOp(t *testing.T) {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// These ceilings are a deliberate ratchet on Zero's fixed per-turn overhead — the
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// promptSubstrings are the cacheable components of the prompt a run sends to a
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// TestComputePrefixFingerprintStableAcrossCalls asserts the headline property
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// Stale tool-output pruning reclaims context at ZERO token/latency cost before
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// bigToolResult builds a tool-result message with approximately tokens worth of
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/errhint"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/errhint"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// Mid-stream reconnect: a long autonomous task (a big refactor, a swarm member,
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// flakyProvider fails the first failBefore connect attempts with failErr, then
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestRequestPermissionsTurnGrantAllowsLaterToolAndCleansUp(t *testing.T) {
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/lsp"
|
||||
"github.com/Gitlawb/zero/internal/redaction"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/verify"
|
||||
"github.com/Twigpine/zero/internal/lsp"
|
||||
"github.com/Twigpine/zero/internal/redaction"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/verify"
|
||||
)
|
||||
|
||||
// defaultSelfCorrectMaxAttempts bounds how many corrective rounds a single run
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/lsp"
|
||||
"github.com/Gitlawb/zero/internal/verify"
|
||||
"github.com/Twigpine/zero/internal/lsp"
|
||||
"github.com/Twigpine/zero/internal/verify"
|
||||
)
|
||||
|
||||
type fakeVerifier struct {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// stallProvider connects successfully (HTTP 200) but the stream emits a stall/idle
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/config"
|
||||
"github.com/Gitlawb/zero/internal/repomap"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/workspaceseed"
|
||||
"github.com/Twigpine/zero/internal/config"
|
||||
"github.com/Twigpine/zero/internal/repomap"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/workspaceseed"
|
||||
)
|
||||
|
||||
// coreSystemPrompt is the de-branded coding-craft instruction set: identity,
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
)
|
||||
|
||||
// TestMain points userConfigDirForPrompt at an empty, package-wide temp
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
type taskStatus string
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestTaskStateReplayIsDeterministic(t *testing.T) {
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
func TestNonVisionImageNoticeQualifiesBudgetRecovery(t *testing.T) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package agent
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// sessionProvider adapts a TurnSession back to the Provider interface so the
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
// fakeTurnSession wraps an inner provider for streaming while counting the
|
||||
|
||||
@@ -3,13 +3,13 @@ package agent
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Gitlawb/zero/internal/execution"
|
||||
"github.com/Gitlawb/zero/internal/hooks"
|
||||
"github.com/Gitlawb/zero/internal/sandbox"
|
||||
"github.com/Gitlawb/zero/internal/streamjson"
|
||||
"github.com/Gitlawb/zero/internal/tools"
|
||||
"github.com/Gitlawb/zero/internal/trace"
|
||||
"github.com/Gitlawb/zero/internal/zeroruntime"
|
||||
"github.com/Twigpine/zero/internal/execution"
|
||||
"github.com/Twigpine/zero/internal/hooks"
|
||||
"github.com/Twigpine/zero/internal/sandbox"
|
||||
"github.com/Twigpine/zero/internal/streamjson"
|
||||
"github.com/Twigpine/zero/internal/tools"
|
||||
"github.com/Twigpine/zero/internal/trace"
|
||||
"github.com/Twigpine/zero/internal/zeroruntime"
|
||||
)
|
||||
|
||||
type Message = zeroruntime.Message
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/Gitlawb/zero-fixture/internal/release"
|
||||
"github.com/Twigpine/zero-fixture/internal/release"
|
||||
)
|
||||
|
||||
func smokeTarget(alreadyBuilt bool) string {
|
||||
|
||||
Loaded 100 of 708 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user