From fe2578508d54066f8d41754745e57d49c121ae0c Mon Sep 17 00:00:00 2001 From: sim Date: Fri, 13 Nov 2026 10:45:50 +0800 Subject: [PATCH 1/2] refactor(vscode): move the extension from packages/pi-vscode to vscode/ packages/ holds the Python packages: each has a pyproject.toml, and the uv workspace and the pytest paths name them one by one. The extension is not Python and is in neither list. web/ and tui/ are at the root for the same reason, and each has its own CI, as the extension has. No file changes inside the extension (80 pure renames, 8 renames with a small edit). What the new place needed: - scripts/lib.mjs: REPO_ROOT is one folder up now (package.mjs reads LICENSE from it, make-icon.mjs reads web/public/favicon.svg). - test/packaging.test.ts reads the workflow; real-agent, real-first-run and real-thinking find the repository with ../.. (was ../../..). - package.json: repository.directory is vscode. - vscode-extension.yml: the trigger path, 8 working-directory values, the artifact path, and three ../../vsix/ paths (now ../vsix/). The three have no "pi-vscode" in the text, so a search by name misses them. Two of them are in the publish job, which does not run in a pull request. - README.md, AGENTS.md, the design document (decision D38) and the record of the agent context usage name the new folder. A new test (points every path of the workflow at the real layout) checks the folder, the trigger path, the artifact path and every ../vsix hop against the real layout. Four wrong values of the workflow (the old folder in a working-directory, in the trigger and in the artifact path, and ../../vsix in the last publish step) each make it fail. The workflow file name (vscode-extension.yml) and the environment (vscode-publish) do not change: the two registries name them, not a directory. This commit does not change which CI runs: ci.yml has no paths filter. --- .github/workflows/vscode-extension.yml | 30 +++++++++--------- AGENTS.md | 2 +- README.md | 6 ++-- .../2026-11-04-vscode-extension-design.md | 15 +++++---- docs/specs/2026-11-13-agent-context-usage.md | 2 +- {packages/pi-vscode => vscode}/.gitignore | 0 {packages/pi-vscode => vscode}/.vscodeignore | 0 {packages/pi-vscode => vscode}/CHANGELOG.md | 0 {packages/pi-vscode => vscode}/PACKAGING.md | 2 +- {packages/pi-vscode => vscode}/README.md | 2 +- {packages/pi-vscode => vscode}/RELEASING.md | 0 .../pi-vscode => vscode}/agent-assets.json | 0 {packages/pi-vscode => vscode}/esbuild.mjs | 0 .../pi-vscode => vscode}/eslint.config.mjs | 0 {packages/pi-vscode => vscode}/media/chat.css | 0 {packages/pi-vscode => vscode}/media/icon.png | Bin .../media/walkthrough/chat.md | 0 .../media/walkthrough/history.md | 0 .../media/walkthrough/modes.md | 0 .../media/walkthrough/open-folder.md | 0 .../media/walkthrough/setup.md | 0 .../media/walkthrough/trouble.md | 0 .../pi-vscode => vscode}/media/zycode.svg | 0 .../pi-vscode => vscode}/package-lock.json | 0 {packages/pi-vscode => vscode}/package.json | 2 +- .../scripts/check-vsix.mjs | 0 .../scripts/fetch-agent.mjs | 0 .../pi-vscode => vscode}/scripts/lib.d.mts | 0 .../pi-vscode => vscode}/scripts/lib.mjs | 2 +- .../scripts/make-icon.mjs | 0 .../scripts/notices.d.mts | 0 .../pi-vscode => vscode}/scripts/notices.mjs | 0 .../pi-vscode => vscode}/scripts/package.mjs | 0 .../scripts/python_licenses.py | 0 .../scripts/smoke-vsix.mjs | 0 .../scripts/webview-harness.d.mts | 0 .../scripts/webview-harness.mjs | 0 .../src/core/acp-connection.ts | 0 .../src/core/agent-process.ts | 0 .../src/core/chat-controller.ts | 0 .../src/core/diff-store.ts | 0 .../src/core/diff-tracker.ts | 0 .../pi-vscode => vscode}/src/core/diff.ts | 0 .../src/core/first-run.ts | 0 .../pi-vscode => vscode}/src/core/host.ts | 0 .../pi-vscode => vscode}/src/core/locate.ts | 0 .../pi-vscode => vscode}/src/core/markdown.ts | 0 .../pi-vscode => vscode}/src/core/protocol.ts | 0 .../src/core/session-list.ts | 0 .../src/core/status-row.ts | 0 .../pi-vscode => vscode}/src/core/thinking.ts | 0 .../pi-vscode => vscode}/src/core/throttle.ts | 0 .../src/core/tool-calls.ts | 0 .../pi-vscode => vscode}/src/core/version.ts | 0 .../pi-vscode => vscode}/src/extension.ts | 0 .../pi-vscode => vscode}/src/ui/chat-view.ts | 0 .../src/ui/diff-documents.ts | 0 .../src/ui/sessions-view.ts | 0 .../pi-vscode => vscode}/src/ui/status-bar.ts | 0 .../src/ui/vscode-host.ts | 0 .../pi-vscode => vscode}/src/webview/dom.ts | 0 .../pi-vscode => vscode}/src/webview/main.ts | 0 .../src/webview/tsconfig.json | 0 .../test/always-approve.test.ts | 0 .../test/controller.test.ts | 0 .../test/diff-view.test.ts | 0 .../pi-vscode => vscode}/test/diff.test.ts | 0 .../pi-vscode => vscode}/test/fake-agent.mjs | 0 .../test/first-run-flow.test.ts | 0 .../test/first-run.test.ts | 0 .../test/fixtures/patches.json | 0 .../pi-vscode => vscode}/test/global-setup.ts | 0 .../pi-vscode => vscode}/test/helpers.ts | 0 .../pi-vscode => vscode}/test/locate.test.ts | 0 .../test/markdown.test.ts | 0 .../test/packaging.test.ts | 19 ++++++++++- .../test/protocol.test.ts | 0 .../test/real-agent.test.ts | 2 +- .../test/real-first-run.test.ts | 2 +- .../test/real-thinking.test.ts | 2 +- .../test/session-list.test.ts | 0 .../test/sessions.test.ts | 0 .../test/status-row.test.ts | 0 .../test/support/fake_model.py | 0 .../test/support/pty_answers.py | 0 .../test/thinking.test.ts | 0 .../test/throttle.test.ts | 0 .../test/tool-calls.test.ts | 0 .../pi-vscode => vscode}/test/usage.test.ts | 0 .../pi-vscode => vscode}/test/version.test.ts | 0 .../pi-vscode => vscode}/test/webview.test.ts | 0 {packages/pi-vscode => vscode}/tsconfig.json | 0 .../pi-vscode => vscode}/vitest.config.ts | 0 93 files changed, 53 insertions(+), 35 deletions(-) rename {packages/pi-vscode => vscode}/.gitignore (100%) rename {packages/pi-vscode => vscode}/.vscodeignore (100%) rename {packages/pi-vscode => vscode}/CHANGELOG.md (100%) rename {packages/pi-vscode => vscode}/PACKAGING.md (94%) rename {packages/pi-vscode => vscode}/README.md (99%) rename {packages/pi-vscode => vscode}/RELEASING.md (100%) rename {packages/pi-vscode => vscode}/agent-assets.json (100%) rename {packages/pi-vscode => vscode}/esbuild.mjs (100%) rename {packages/pi-vscode => vscode}/eslint.config.mjs (100%) rename {packages/pi-vscode => vscode}/media/chat.css (100%) rename {packages/pi-vscode => vscode}/media/icon.png (100%) rename {packages/pi-vscode => vscode}/media/walkthrough/chat.md (100%) rename {packages/pi-vscode => vscode}/media/walkthrough/history.md (100%) rename {packages/pi-vscode => vscode}/media/walkthrough/modes.md (100%) rename {packages/pi-vscode => vscode}/media/walkthrough/open-folder.md (100%) rename {packages/pi-vscode => vscode}/media/walkthrough/setup.md (100%) rename {packages/pi-vscode => vscode}/media/walkthrough/trouble.md (100%) rename {packages/pi-vscode => vscode}/media/zycode.svg (100%) rename {packages/pi-vscode => vscode}/package-lock.json (100%) rename {packages/pi-vscode => vscode}/package.json (99%) rename {packages/pi-vscode => vscode}/scripts/check-vsix.mjs (100%) rename {packages/pi-vscode => vscode}/scripts/fetch-agent.mjs (100%) rename {packages/pi-vscode => vscode}/scripts/lib.d.mts (100%) rename {packages/pi-vscode => vscode}/scripts/lib.mjs (98%) rename {packages/pi-vscode => vscode}/scripts/make-icon.mjs (100%) rename {packages/pi-vscode => vscode}/scripts/notices.d.mts (100%) rename {packages/pi-vscode => vscode}/scripts/notices.mjs (100%) rename {packages/pi-vscode => vscode}/scripts/package.mjs (100%) rename {packages/pi-vscode => vscode}/scripts/python_licenses.py (100%) rename {packages/pi-vscode => vscode}/scripts/smoke-vsix.mjs (100%) rename {packages/pi-vscode => vscode}/scripts/webview-harness.d.mts (100%) rename {packages/pi-vscode => vscode}/scripts/webview-harness.mjs (100%) rename {packages/pi-vscode => vscode}/src/core/acp-connection.ts (100%) rename {packages/pi-vscode => vscode}/src/core/agent-process.ts (100%) rename {packages/pi-vscode => vscode}/src/core/chat-controller.ts (100%) rename {packages/pi-vscode => vscode}/src/core/diff-store.ts (100%) rename {packages/pi-vscode => vscode}/src/core/diff-tracker.ts (100%) rename {packages/pi-vscode => vscode}/src/core/diff.ts (100%) rename {packages/pi-vscode => vscode}/src/core/first-run.ts (100%) rename {packages/pi-vscode => vscode}/src/core/host.ts (100%) rename {packages/pi-vscode => vscode}/src/core/locate.ts (100%) rename {packages/pi-vscode => vscode}/src/core/markdown.ts (100%) rename {packages/pi-vscode => vscode}/src/core/protocol.ts (100%) rename {packages/pi-vscode => vscode}/src/core/session-list.ts (100%) rename {packages/pi-vscode => vscode}/src/core/status-row.ts (100%) rename {packages/pi-vscode => vscode}/src/core/thinking.ts (100%) rename {packages/pi-vscode => vscode}/src/core/throttle.ts (100%) rename {packages/pi-vscode => vscode}/src/core/tool-calls.ts (100%) rename {packages/pi-vscode => vscode}/src/core/version.ts (100%) rename {packages/pi-vscode => vscode}/src/extension.ts (100%) rename {packages/pi-vscode => vscode}/src/ui/chat-view.ts (100%) rename {packages/pi-vscode => vscode}/src/ui/diff-documents.ts (100%) rename {packages/pi-vscode => vscode}/src/ui/sessions-view.ts (100%) rename {packages/pi-vscode => vscode}/src/ui/status-bar.ts (100%) rename {packages/pi-vscode => vscode}/src/ui/vscode-host.ts (100%) rename {packages/pi-vscode => vscode}/src/webview/dom.ts (100%) rename {packages/pi-vscode => vscode}/src/webview/main.ts (100%) rename {packages/pi-vscode => vscode}/src/webview/tsconfig.json (100%) rename {packages/pi-vscode => vscode}/test/always-approve.test.ts (100%) rename {packages/pi-vscode => vscode}/test/controller.test.ts (100%) rename {packages/pi-vscode => vscode}/test/diff-view.test.ts (100%) rename {packages/pi-vscode => vscode}/test/diff.test.ts (100%) rename {packages/pi-vscode => vscode}/test/fake-agent.mjs (100%) rename {packages/pi-vscode => vscode}/test/first-run-flow.test.ts (100%) rename {packages/pi-vscode => vscode}/test/first-run.test.ts (100%) rename {packages/pi-vscode => vscode}/test/fixtures/patches.json (100%) rename {packages/pi-vscode => vscode}/test/global-setup.ts (100%) rename {packages/pi-vscode => vscode}/test/helpers.ts (100%) rename {packages/pi-vscode => vscode}/test/locate.test.ts (100%) rename {packages/pi-vscode => vscode}/test/markdown.test.ts (100%) rename {packages/pi-vscode => vscode}/test/packaging.test.ts (89%) rename {packages/pi-vscode => vscode}/test/protocol.test.ts (100%) rename {packages/pi-vscode => vscode}/test/real-agent.test.ts (99%) rename {packages/pi-vscode => vscode}/test/real-first-run.test.ts (99%) rename {packages/pi-vscode => vscode}/test/real-thinking.test.ts (99%) rename {packages/pi-vscode => vscode}/test/session-list.test.ts (100%) rename {packages/pi-vscode => vscode}/test/sessions.test.ts (100%) rename {packages/pi-vscode => vscode}/test/status-row.test.ts (100%) rename {packages/pi-vscode => vscode}/test/support/fake_model.py (100%) rename {packages/pi-vscode => vscode}/test/support/pty_answers.py (100%) rename {packages/pi-vscode => vscode}/test/thinking.test.ts (100%) rename {packages/pi-vscode => vscode}/test/throttle.test.ts (100%) rename {packages/pi-vscode => vscode}/test/tool-calls.test.ts (100%) rename {packages/pi-vscode => vscode}/test/usage.test.ts (100%) rename {packages/pi-vscode => vscode}/test/version.test.ts (100%) rename {packages/pi-vscode => vscode}/test/webview.test.ts (100%) rename {packages/pi-vscode => vscode}/tsconfig.json (100%) rename {packages/pi-vscode => vscode}/vitest.config.ts (100%) diff --git a/.github/workflows/vscode-extension.yml b/.github/workflows/vscode-extension.yml index bafb0fbd..0b2f75f9 100644 --- a/.github/workflows/vscode-extension.yml +++ b/.github/workflows/vscode-extension.yml @@ -1,4 +1,4 @@ -# The zycode VS Code extension (packages/pi-vscode). +# The zycode VS Code extension (vscode/). # # On a pull request that touches the extension: tests, and a linux-x64 VSIX with its smoke test. # By hand (Actions > "VS Code extension" > Run workflow): the same for the chosen targets, and, @@ -9,7 +9,7 @@ # and the environment allows deployments from `main` only. # - Both registries name THIS FILE by its file name (`vscode-extension.yml`) in their trusted # publisher entries. Do not rename it without changing both entries. -# - The first upload to each registry is a hand upload (packages/pi-vscode/RELEASING.md). +# - The first upload to each registry is a hand upload (vscode/RELEASING.md). name: VS Code extension @@ -17,7 +17,7 @@ on: pull_request: paths: - ".github/workflows/vscode-extension.yml" - - "packages/pi-vscode/**" + - "vscode/**" workflow_dispatch: inputs: publish: @@ -64,9 +64,9 @@ jobs: with: node-version: 22 - run: npm ci - working-directory: packages/pi-vscode + working-directory: vscode - run: npm run check - working-directory: packages/pi-vscode + working-directory: vscode plan: name: Targets @@ -108,16 +108,16 @@ jobs: with: python-version: "3.12" # for THIRD-PARTY-NOTICES - run: npm ci - working-directory: packages/pi-vscode + working-directory: vscode - name: Download the agent, check its sha256, build, write the notices, package, check the VSIX run: node scripts/package.mjs "$TARGET" - working-directory: packages/pi-vscode + working-directory: vscode env: TARGET: ${{ matrix.target }} - uses: actions/upload-artifact@v6 with: name: vsix-${{ matrix.target }} - path: packages/pi-vscode/out/*.vsix + path: vscode/out/*.vsix if-no-files-found: error retention-days: 14 @@ -148,8 +148,8 @@ jobs: if: steps.has.outputs.linux_x64 == 'true' run: | npm ci - node scripts/smoke-vsix.mjs ../../vsix/*.vsix - working-directory: packages/pi-vscode + node scripts/smoke-vsix.mjs ../vsix/*.vsix + working-directory: vscode publish: name: Publish @@ -179,7 +179,7 @@ jobs: merge-multiple: true - name: Install the pinned vsce and ovsx run: npm ci - working-directory: packages/pi-vscode + working-directory: vscode - name: Files to publish run: | ls -l vsix @@ -187,17 +187,17 @@ jobs: # A repeat of a half-done publish skips what is already there (--skip-duplicate). - name: Open VSX if: inputs.registries != 'marketplace' - working-directory: packages/pi-vscode + working-directory: vscode run: | set -eu - for f in ../../vsix/*.vsix; do + for f in ../vsix/*.vsix; do npx --no-install ovsx publish --trusted-publishing --skip-duplicate "$f" done - name: Visual Studio Marketplace if: inputs.registries != 'open-vsx' - working-directory: packages/pi-vscode + working-directory: vscode run: | set -eu - for f in ../../vsix/*.vsix; do + for f in ../vsix/*.vsix; do npx --no-install vsce publish --oidc --skip-duplicate --packagePath "$f" done diff --git a/AGENTS.md b/AGENTS.md index 42623759..7b520782 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,7 +37,7 @@ AgentMessage[] → transform_context() → convert_to_llm() → LangChain BaseMe | `packages/pi-mcp/` | Optional extension `pi-mcp-py` (entry point `pi-mcp`): connects the MCP servers (stdio, http, sse) that an ACP client passes in `session/new`, one runner task per server, tools named `mcp____`, `/mcp` command. Core, harness and CLI have no MCP client; they hand the servers over as data (`ClientMcpServer`, `ExtensionAPI.client_mcp_servers`). Design: `docs/specs/2026-10-23-mcp-extension-design.md`. Its tests are left out of a run that did not install the package (the header says so) | — | | `packaging/agent/` | Builds the agent as a one-file executable (PyInstaller; `build.py`, `zycode-agent.spec`, `entry.py`) and the smoke test over ACP with a fake model server (`smoke.py`). `.github/workflows/agent-binaries.yml` runs both on five platforms and attaches the archives to the GitHub Release after the `Release` workflow. A frozen build has no interpreter: `host.py` starts a frozen `child.py`, and only the OpenAI-format provider is in it. Design and the registry entry draft: `docs/specs/2026-10-31-agent-binaries.md` | — | | `packages/pi-agent-cli/` | Standard-ACP CLI (`python -m pi_agent_cli`); config `agent.example.toml`, home `~/.pi-python`; TUI binary `zypi` under `tui/`. See [`packages/pi-agent-cli/AGENTS.md`](packages/pi-agent-cli/AGENTS.md) for spawn, config, first run (`--setup` and the terminal login that `initialize` offers to a client that can run one; `zypi` still gets `authMethods: []`), prompt pipeline, and the three permission modes `ask`, `auto` and `always-approve` (Auto: rules, and a model step for a `bash` call that no rule decides: `auto_rules.py`, `auto_classifier.py`, `auto_mode.py`, `permission_modes.py`; design `docs/specs/2026-11-02-auto-mode-design.md`; the pager offers all three, and a clean start is `ask`). The items on the ACP wire beyond standard ACP (`pi/session/delete`, `_meta.sessionId`, and others) are in the register `docs/specs/2026-11-05-acp-extension-registry.md` | — | -| `packages/pi-vscode/` | The VS Code extension `zycode.zycode` (TypeScript, `src/core/` has no `vscode` import). It is an ACP client and a chat view for zycode in VS Code: it starts the agent as a child process, shows permission questions and a diff for `write`/`edit`, runs the first-run setup in a terminal (a walkthrough, a banner and hints guide the first start; the agent's own `--setup` and `auth_required` carry it, no wire item and no agent change), lists past chats of the folder in a view (`session/list`, `session/load`, `pi/session/delete`), and offers the three permission modes `ask`, `auto` and `always-approve` in the chat menu (`always-approve` only after a modal warning, never restored for a new chat, a past chat or a restart, and not in an untrusted workspace; the `zycode.permissionMode` setting stays `ask`/`auto`; it moves the agent with the agent's own `pi/yolo_mode_changed`). The extension never writes `always-approve` through `set_config_option`. A Thinking menu shows `thinking_level` of `agent.toml`; agent 0.9.1 cannot change it live, so a change edits that one line (checked by parsing, after a modal), restarts the agent and reopens the chat (design section 7c). One VSIX per platform, each with the bundled `zycode-agent` binary of one Release (pin and sha256 in `agent-assets.json`). Not a Python package: ruff and pytest do not read it; `.github/workflows/vscode-extension.yml` runs `npm run check` and a `linux-x64` VSIX smoke test for a PR that changes it, and publishes (Trusted Publishing, by hand on `main`, environment `vscode-publish`). Version 1.0.0 is the first stable release (the pre-release 0.1.0 was uploaded by hand; the 1.0.0 run, run `43181052994` on 2026-11-12, was the first real OIDC publish and worked on the first try on Open VSX and the Marketplace, five targets, no token; the record is in `packages/pi-vscode/RELEASING.md`; stable = even minor, pre-release = odd minor). Do not rename that file or the environment: the registries name them. Local check: `cd packages/pi-vscode; npm run check`. Design: `docs/specs/2026-11-04-vscode-extension-design.md`; make and test a VSIX: `packages/pi-vscode/PACKAGING.md`; releases: `packages/pi-vscode/RELEASING.md` | — | +| `vscode/` | The VS Code extension `zycode.zycode` (TypeScript, `src/core/` has no `vscode` import). It is an ACP client and a chat view for zycode in VS Code: it starts the agent as a child process, shows permission questions and a diff for `write`/`edit`, runs the first-run setup in a terminal (a walkthrough, a banner and hints guide the first start; the agent's own `--setup` and `auth_required` carry it, no wire item and no agent change), lists past chats of the folder in a view (`session/list`, `session/load`, `pi/session/delete`), and offers the three permission modes `ask`, `auto` and `always-approve` in the chat menu (`always-approve` only after a modal warning, never restored for a new chat, a past chat or a restart, and not in an untrusted workspace; the `zycode.permissionMode` setting stays `ask`/`auto`; it moves the agent with the agent's own `pi/yolo_mode_changed`). The extension never writes `always-approve` through `set_config_option`. A Thinking menu shows `thinking_level` of `agent.toml`; agent 0.9.1 cannot change it live, so a change edits that one line (checked by parsing, after a modal), restarts the agent and reopens the chat (design section 7c). One VSIX per platform, each with the bundled `zycode-agent` binary of one Release (pin and sha256 in `agent-assets.json`). Not a Python package: ruff and pytest do not read it; `.github/workflows/vscode-extension.yml` runs `npm run check` and a `linux-x64` VSIX smoke test for a PR that changes it, and publishes (Trusted Publishing, by hand on `main`, environment `vscode-publish`). Version 1.0.0 is the first stable release (the pre-release 0.1.0 was uploaded by hand; the 1.0.0 run, run `43181052994` on 2026-11-12, was the first real OIDC publish and worked on the first try on Open VSX and the Marketplace, five targets, no token; the record is in `vscode/RELEASING.md`; stable = even minor, pre-release = odd minor). Do not rename that file or the environment: the registries name them. Local check: `cd vscode; npm run check`. Design: `docs/specs/2026-11-04-vscode-extension-design.md`; make and test a VSIX: `vscode/PACKAGING.md`; releases: `vscode/RELEASING.md` | — | | `web/` | Product site for zycode, live at `https://zycode.dev` (static Astro, Node ≥ 22.23.4; English at `/`, Chinese at `/zh/`; Cloudflare Workers static assets, no server of ours). Not a Python package: ruff and pytest do not read it; `.github/workflows/web-ci.yml` runs `npm run check` and `npm run build` for a PR that changes `web/`. A merge to `main` that changes `web/` deploys to `zycode.dev` by itself (Cloudflare Workers Builds, not GitHub Actions). Its claims must stay equal to the README table "Status" and to the benchmark report, and `en.ts` / `zh.ts` keep the same keys. See [`web/README.md`](web/README.md) for commands, deploy, the domain, and the Cloudflare settings that are not in the repository | — | ### Invariants diff --git a/README.md b/README.md index 10dd3748..f9b0d946 100644 --- a/README.md +++ b/README.md @@ -153,14 +153,14 @@ After installing, set up config and start the TUI — see [TUI & Code-Agent Guid ### VS Code extension -The extension `zycode.zycode` ([`packages/pi-vscode`](packages/pi-vscode/README.md)) puts the zycode agent in a chat view in VS Code. It has the agent program inside, so you do not install the Python agent first. It is unofficial and not affiliated with pi or Microsoft. +The extension `zycode.zycode` ([`vscode`](vscode/README.md)) puts the zycode agent in a chat view in VS Code. It has the agent program inside, so you do not install the Python agent first. It is unofficial and not affiliated with pi or Microsoft. - **VS Code:** install it from the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=zycode.zycode), or run `code --install-extension zycode.zycode`. - **VSCodium and other editors that use Open VSX:** install it from [Open VSX](https://open-vsx.org/extension/zycode/zycode). - **Platforms:** version 1.0.0 is published on both registries for five platforms: `linux-x64`, `linux-arm64`, `darwin-arm64`, `darwin-x64` and `win32-x64`. Each one has the agent program inside. - **What it has:** a chat view with a question card for each tool call that is not read-only; a **Show diff** button for `write` and `edit`; a getting-started guide and help for the first start (the setup runs in a VS Code terminal); a **Past chats** view; a mode menu (**Ask**, **Auto** and **Always approve**); and a **Thinking** menu. -- **Auto is not a sandbox.** It guards what a call writes or runs. It does not guard what a call reads or sends. Use a container or a virtual machine if you need a boundary. See the [extension README](packages/pi-vscode/README.md) for the three modes. -- **Limits:** the bundled agent is not code-signed, and it has only the OpenAI-format provider. The repository lists Windows and macOS as not verified. An install of 1.0.0 in a real VS Code is not measured yet. The release record is in [`RELEASING.md`](packages/pi-vscode/RELEASING.md). +- **Auto is not a sandbox.** It guards what a call writes or runs. It does not guard what a call reads or sends. Use a container or a virtual machine if you need a boundary. See the [extension README](vscode/README.md) for the three modes. +- **Limits:** the bundled agent is not code-signed, and it has only the OpenAI-format provider. The repository lists Windows and macOS as not verified. An install of 1.0.0 in a real VS Code is not measured yet. The release record is in [`RELEASING.md`](vscode/RELEASING.md). ### In Zed (custom agent) diff --git a/docs/specs/2026-11-04-vscode-extension-design.md b/docs/specs/2026-11-04-vscode-extension-design.md index fbb2fdc3..1bd1bd44 100644 --- a/docs/specs/2026-11-04-vscode-extension-design.md +++ b/docs/specs/2026-11-04-vscode-extension-design.md @@ -2,8 +2,8 @@ > Scope: a VS Code extension (`zycode.zycode`) that runs the zycode agent and shows a chat for it. This record gives the design of Phase 1 (the pre-release 0.1.0) and of the changes of 1.0.0 (sections 7a, 7b, 9 and 11). > Decided: 2026-11-04. The user adopted the plan of the research report (ZY-59, sections 1 to 6 and 9) and chose: route (a), an ACP-client extension with its own webview chat; publisher `zycode`; extension name `zycode`; display name "zycode"; five targets; no telemetry; no code signing; Trusted Publishing for the publish pipeline. -> Status: Phase 1 is built (`packages/pi-vscode/`, `.github/workflows/vscode-extension.yml`). 0.1.0 (pre-release) is published on both registries (uploaded by hand). 1.0.0 is the first stable release; it adds the first-run guide (section 7a), `always-approve` in the mode menu (section 9) and the Past chats view (section 7b). `packages/pi-vscode/RELEASING.md` has the steps and the 1.0.0 release record. Result (2026-11-12): 1.0.0 was published by the workflow to both registries with OIDC (section 13). Where this record and the code differ, the code wins. -> Code: `packages/pi-vscode/`. Agent side (unchanged): `packages/pi-agent-cli/pi_agent_cli/{agent,events,auth_methods,permissions,trust_prompt,permission_modes}.py`. +> Status: Phase 1 is built (`vscode/`, `.github/workflows/vscode-extension.yml`). 0.1.0 (pre-release) is published on both registries (uploaded by hand). 1.0.0 is the first stable release; it adds the first-run guide (section 7a), `always-approve` in the mode menu (section 9) and the Past chats view (section 7b). `vscode/RELEASING.md` has the steps and the 1.0.0 release record. Result (2026-11-12): 1.0.0 was published by the workflow to both registries with OIDC (section 13). Where this record and the code differ, the code wins. +> Code: `vscode/`. Agent side (unchanged): `packages/pi-agent-cli/pi_agent_cli/{agent,events,auth_methods,permissions,trust_prompt,permission_modes}.py`. > Facts about the agent in this record come from the source tree at `9c763c8` and from a run of the real agent over ACP (section 1). Facts about VS Code come from the research report; they were true on 2026-11-04. --- @@ -64,7 +64,7 @@ Rules: ### 2.1 Files ``` -packages/pi-vscode/ +vscode/ ├── package.json manifest, zycodeAgentVersion, scripts ├── src/ │ ├── extension.ts @@ -486,10 +486,10 @@ No `alpine-*` (the binary needs glibc), no `linux-armhf` (no binary), no `win32- What this means for the package: -- The packaging script makes VSIX files that a person can upload by hand: `zycode--.vsix` in `packages/pi-vscode/out/`, each built as a stable release (since 1.0.0), plus `SHA256SUMS`. A file is the same whether the workflow or a person uploads it. The workflow also keeps the five VSIX files as run artifacts for 14 days, so a person can take them from a run with `publish` off. -- `packages/pi-vscode/RELEASING.md` is the exact checklist of the first release: (1) the five VSIX files by hand to Open VSX; (2) register the Open VSX trusted publisher (done, by the owner's word of 2026-11-12), and test it with a workflow run that only skips duplicates (no such run was made); (3) `linux-x64` by hand to the Marketplace, then the workflow for the other four targets; (4) later releases from the workflow. +- The packaging script makes VSIX files that a person can upload by hand: `zycode--.vsix` in `vscode/out/`, each built as a stable release (since 1.0.0), plus `SHA256SUMS`. A file is the same whether the workflow or a person uploads it. The workflow also keeps the five VSIX files as run artifacts for 14 days, so a person can take them from a run with `publish` off. +- `vscode/RELEASING.md` is the exact checklist of the first release: (1) the five VSIX files by hand to Open VSX; (2) register the Open VSX trusted publisher (done, by the owner's word of 2026-11-12), and test it with a workflow run that only skips duplicates (no such run was made); (3) `linux-x64` by hand to the Marketplace, then the workflow for the other four targets; (4) later releases from the workflow. - Not verified: the live Open VSX page with five files at once; that the Marketplace page keeps the pre-release flag of a VSIX and takes a platform VSIX; the first `vsce publish --oidc` of any kind from this repository. The checklist says what to look at after each step. -- **Result (2026-11-12): the first `vsce publish --oidc` and the first Open VSX Trusted Publishing publish from this repository worked.** Run `43181052994` on `main` (commit `8b0e50c`) published 1.0.0 for five targets to Open VSX (08:18:55Z to 08:19:17Z, `Trusted publishing token issued`) and then to the Marketplace (`vsce publish --oidc`, 08:19:24Z to 08:19:57Z), with no token. The run finished green at 08:20Z. Both versions were visible with the public APIs: Open VSX 08:23Z to 08:25Z, Marketplace 08:26Z to 08:28Z. `preRelease` is false on Open VSX, the Marketplace shows no PreRelease property, and the sha256 of the five Open VSX files equals the `sha256sum` in the Publish log. Record: `packages/pi-vscode/RELEASING.md`. +- **Result (2026-11-12): the first `vsce publish --oidc` and the first Open VSX Trusted Publishing publish from this repository worked.** Run `43181052994` on `main` (commit `8b0e50c`) published 1.0.0 for five targets to Open VSX (08:18:55Z to 08:19:17Z, `Trusted publishing token issued`) and then to the Marketplace (`vsce publish --oidc`, 08:19:24Z to 08:19:57Z), with no token. The run finished green at 08:20Z. Both versions were visible with the public APIs: Open VSX 08:23Z to 08:25Z, Marketplace 08:26Z to 08:28Z. `preRelease` is false on Open VSX, the Marketplace shows no PreRelease property, and the sha256 of the five Open VSX files equals the `sha256sum` in the Publish log. Record: `vscode/RELEASING.md`. **Which trigger runs on `main`.** `workflow_dispatch` runs on the branch or tag that the user chooses. The "Run workflow" button offers any branch, and the environment rule refuses all but `main`. A `workflow_run` run always uses the default branch: GitHub sets `GITHUB_REF` to the default branch and `GITHUB_SHA` to its last commit (GitHub Docs, "Events that trigger workflows", `workflow_run`), so it passes the environment rule, but it builds the last commit of `main`, not the commit of the run that triggered it. A tag or `release` trigger would run on a tag ref, which the environment refuses. The extension version is not the agent version, and a new agent Release must not publish an extension by itself. So the workflow uses `workflow_dispatch` only for publishing. The job `guard` fails at once, before any build and before the reviewer is asked, when `publish` is ticked on a ref other than `main`. @@ -528,7 +528,7 @@ From the report, section 3.3 (Phase 2 and later), and from the limits above: | Extension host | activation, the view loads, `Show diff` opens a diff editor, restricted mode does not start the agent | `@vscode/test-electron` with a real VS Code, under `xvfb` on Linux | manual in Phase 1; not in CI | | Package | `check-vsix` on each VSIX: binary, exec bit, notices, license, icon, walkthrough pages, no pre-release flag, no `node_modules`; sha256 mismatch is refused; `package` refuses on Windows. `scripts/smoke-vsix.mjs` starts the frozen binary three times (section PACKAGING.md): no model, the mode option, and a turn with a fake model server for the list, load, delete and the always-approve signal | a script; in CI for `linux-x64` | Linux | -**Commands** (run from `packages/pi-vscode`, and pasted into each pull request): `npm ci`, `npm run typecheck`, `npm run lint`, `npm test`, and for the real agent `npm run test:agent`. The workflow in section 11 runs the same checks on a pull request that changes the extension. +**Commands** (run from `vscode`, and pasted into each pull request): `npm ci`, `npm run typecheck`, `npm run lint`, `npm test`, and for the real agent `npm run test:agent`. The workflow in section 11 runs the same checks on a pull request that changes the extension. **Result (2026-11-12): the Open VSX and Marketplace publish path is now measured (1.0.0, five targets, OIDC, no token); an install of 1.0.0 in a real VS Code is not.** **Not verified on any machine of ours:** Windows and macOS (the extension host, the terminal for `--setup`, the exec bit after a VS Code install, the first start of an unsigned binary under Gatekeeper and SmartScreen, a Windows antivirus on a PyInstaller file), Remote-SSH, WSL and dev containers, the Marketplace scan of the VSIX, Open VSX. The README lists the limits that remain. @@ -579,3 +579,4 @@ From the report, section 3.3 (Phase 2 and later), and from the limits above: | D35 (built) | The webview draws the text of a streamed answer at most once each 80 ms. The first piece is drawn at once. The pieces that come in a pause are joined into one draw at the end of the pause, counted from the end of the last draw. The last piece is always drawn. A reset of the chat cancels a draw that is planned. | A draw makes the DOM of the whole answer again, so its cost grows with the length of the answer. We measured it in headless Chrome, with the text already N characters long (the median of 25 pieces of 4 characters, two runs): 7 ms at 3,000 characters, 16 ms at 8,000 and 37 ms at 20,000. The reader of 1.0.0 took 5, 12 and 26 ms, so the new reader is about 1.4 times slower for each draw. The host sends each piece at once. If a model sends 50 pieces each second (an assumption: we did not measure a real model), the time between two pieces is 20 ms, and a draw of 37 ms does not fit in it. With the pause there are at most 12 draws each second, so a draw of 37 ms uses less than half of the time of the page. A change that draws only the last block again is a later option, if 80 ms is not enough. | | D36 (built) | **Recommended: as built.** The context and the cost in the status row come only from the standard `usage_update` of the agent. The extension counts no tokens, has no setting for the size of the window, and shows nothing when the agent sends nothing. Options not taken: **B**, an estimate that the extension makes (for example characters ÷ 4); **C**, a setting `zycode.contextWindow`; **D**, change the agent now (the user said: write down the investigation only). | Agent 0.9.1 does not know the real window (`Model.context_window` is 128,000 for every model, and no key sets it) and has no price (`cost.total` is 0 in all 21 messages that we read), so a number from the extension would be a guess that looks like a fact. The pager made the same decision on 2026-10-13: it shows no context and no cost, and no number is invented. The row shows by itself when an agent sends `usage_update`, with no change in the extension. The findings and the agent change that is needed are in `docs/specs/2026-11-13-agent-context-usage.md`. | | D37 (built) | **Recommended: as built.** The time of the turn is measured by the clock of the host, and the folder comes from the session. Both show in the header (and in the tooltip of the status bar item). The page counts the running time with its own timer, and changes one element each 500 ms. Options not taken: a clock in the status bar item (it needs a timer in the extension host each second); the tokens of the last turn (the agent does not send them). | The agent sends no times, and the pager draws clocks of its own for the same reason (2026-10-13). A tick that changes one element leaves a menu that is open alone; a new `state` message for each second would close it. The host sends a fresh `elapsedMs` in each `state` message, so a clock that has drifted is set right at the next one. | +| D38 (built) | **Recommended: as built.** The extension lives in `vscode/`, at the root of the repository, and not in `packages/pi-vscode/`. The workflow file `vscode-extension.yml` and the environment `vscode-publish` keep their names. Options not taken: **B**, keep `packages/pi-vscode/`; **C**, a longer name (`zycode-vscode/`, `extensions/vscode/`). | `packages/` holds the six Python packages. Each has a `pyproject.toml`, and the uv workspace and the pytest paths in the root `pyproject.toml` name them one by one. The extension is not Python and is in neither list. `web/` and `tui/` are at the root for the same reason, and each has its own CI, as the extension has (`vscode-extension.yml`). **The move does not change which CI runs for a change.** `ci.yml` (Ruff and pytest) has no `paths` filter, so it runs for every pull request, also for one that only touches `web/`. What the move changed: `REPO_ROOT` in `scripts/lib.mjs` and the three `../../..` in the opt-in tests; the test that reads the workflow; `repository.directory`; and the workflow (8 `working-directory`, the artifact path, the trigger path, and three `../../vsix/` that have no `pi-vscode` in the text, so a search by name misses them; two of them are in the publish job, which does not run in a pull request). A test now checks all of these against the real layout (`points every path of the workflow at the real layout`). The two registries name the repository, the workflow file and the environment, and not a directory, so the trusted publishers stay valid. Old links to `packages/pi-vscode/...` on GitHub do not work any more. The README of 1.0.0 names the old folder as text only, with no link (the next release says `vscode`), and its CHANGELOG and walkthrough have no link into it. | diff --git a/docs/specs/2026-11-13-agent-context-usage.md b/docs/specs/2026-11-13-agent-context-usage.md index 9c5c3c3e..7ccb03e8 100644 --- a/docs/specs/2026-11-13-agent-context-usage.md +++ b/docs/specs/2026-11-13-agent-context-usage.md @@ -54,7 +54,7 @@ The extension reads `usage_update` when an agent sends it (design section 7d). U ## 6. Release path -An agent change is not enough. The extension bundles one fixed agent binary. After the change: release the agent, then change `zycodeAgentVersion` and the size and the sha256 in `packages/pi-vscode/agent-assets.json`, then release the extension. A user who sets `zycode.agentPath` gets the change as soon as that program is new. +An agent change is not enough. The extension bundles one fixed agent binary. After the change: release the agent, then change `zycodeAgentVersion` and the size and the sha256 in `vscode/agent-assets.json`, then release the extension. A user who sets `zycode.agentPath` gets the change as soon as that program is new. ## 7. Open decisions (for the owner) diff --git a/packages/pi-vscode/.gitignore b/vscode/.gitignore similarity index 100% rename from packages/pi-vscode/.gitignore rename to vscode/.gitignore diff --git a/packages/pi-vscode/.vscodeignore b/vscode/.vscodeignore similarity index 100% rename from packages/pi-vscode/.vscodeignore rename to vscode/.vscodeignore diff --git a/packages/pi-vscode/CHANGELOG.md b/vscode/CHANGELOG.md similarity index 100% rename from packages/pi-vscode/CHANGELOG.md rename to vscode/CHANGELOG.md diff --git a/packages/pi-vscode/PACKAGING.md b/vscode/PACKAGING.md similarity index 94% rename from packages/pi-vscode/PACKAGING.md rename to vscode/PACKAGING.md index 1792b0d8..c7a7c0c6 100644 --- a/packages/pi-vscode/PACKAGING.md +++ b/vscode/PACKAGING.md @@ -1,6 +1,6 @@ # Packaging the zycode extension -One VSIX per platform. Each VSIX holds the `zycode-agent` program of one release (`agent-assets.json`). Work from the `packages/pi-vscode` folder. Use Linux. The Linux and macOS programs must keep their execute bit in the VSIX, and only Linux is tested for that. +One VSIX per platform. Each VSIX holds the `zycode-agent` program of one release (`agent-assets.json`). Work from the `vscode` folder. Use Linux. The Linux and macOS programs must keep their execute bit in the VSIX, and only Linux is tested for that. ## Make the files diff --git a/packages/pi-vscode/README.md b/vscode/README.md similarity index 99% rename from packages/pi-vscode/README.md rename to vscode/README.md index 81fdcd2b..50363108 100644 --- a/packages/pi-vscode/README.md +++ b/vscode/README.md @@ -2,7 +2,7 @@ **Unofficial; not affiliated with pi or Microsoft.** -zycode is a coding agent. This extension puts it in a chat view in VS Code. The agent can read your files, edit them, and run commands, and it asks you before it does anything that is not read-only. The extension starts the agent program on your machine and talks to it over the [Agent Client Protocol](https://agentclientprotocol.com). Source: (`packages/pi-vscode`). Site: . +zycode is a coding agent. This extension puts it in a chat view in VS Code. The agent can read your files, edit them, and run commands, and it asks you before it does anything that is not read-only. The extension starts the agent program on your machine and talks to it over the [Agent Client Protocol](https://agentclientprotocol.com). Source: (`vscode`). Site: . ## What you get diff --git a/packages/pi-vscode/RELEASING.md b/vscode/RELEASING.md similarity index 100% rename from packages/pi-vscode/RELEASING.md rename to vscode/RELEASING.md diff --git a/packages/pi-vscode/agent-assets.json b/vscode/agent-assets.json similarity index 100% rename from packages/pi-vscode/agent-assets.json rename to vscode/agent-assets.json diff --git a/packages/pi-vscode/esbuild.mjs b/vscode/esbuild.mjs similarity index 100% rename from packages/pi-vscode/esbuild.mjs rename to vscode/esbuild.mjs diff --git a/packages/pi-vscode/eslint.config.mjs b/vscode/eslint.config.mjs similarity index 100% rename from packages/pi-vscode/eslint.config.mjs rename to vscode/eslint.config.mjs diff --git a/packages/pi-vscode/media/chat.css b/vscode/media/chat.css similarity index 100% rename from packages/pi-vscode/media/chat.css rename to vscode/media/chat.css diff --git a/packages/pi-vscode/media/icon.png b/vscode/media/icon.png similarity index 100% rename from packages/pi-vscode/media/icon.png rename to vscode/media/icon.png diff --git a/packages/pi-vscode/media/walkthrough/chat.md b/vscode/media/walkthrough/chat.md similarity index 100% rename from packages/pi-vscode/media/walkthrough/chat.md rename to vscode/media/walkthrough/chat.md diff --git a/packages/pi-vscode/media/walkthrough/history.md b/vscode/media/walkthrough/history.md similarity index 100% rename from packages/pi-vscode/media/walkthrough/history.md rename to vscode/media/walkthrough/history.md diff --git a/packages/pi-vscode/media/walkthrough/modes.md b/vscode/media/walkthrough/modes.md similarity index 100% rename from packages/pi-vscode/media/walkthrough/modes.md rename to vscode/media/walkthrough/modes.md diff --git a/packages/pi-vscode/media/walkthrough/open-folder.md b/vscode/media/walkthrough/open-folder.md similarity index 100% rename from packages/pi-vscode/media/walkthrough/open-folder.md rename to vscode/media/walkthrough/open-folder.md diff --git a/packages/pi-vscode/media/walkthrough/setup.md b/vscode/media/walkthrough/setup.md similarity index 100% rename from packages/pi-vscode/media/walkthrough/setup.md rename to vscode/media/walkthrough/setup.md diff --git a/packages/pi-vscode/media/walkthrough/trouble.md b/vscode/media/walkthrough/trouble.md similarity index 100% rename from packages/pi-vscode/media/walkthrough/trouble.md rename to vscode/media/walkthrough/trouble.md diff --git a/packages/pi-vscode/media/zycode.svg b/vscode/media/zycode.svg similarity index 100% rename from packages/pi-vscode/media/zycode.svg rename to vscode/media/zycode.svg diff --git a/packages/pi-vscode/package-lock.json b/vscode/package-lock.json similarity index 100% rename from packages/pi-vscode/package-lock.json rename to vscode/package-lock.json diff --git a/packages/pi-vscode/package.json b/vscode/package.json similarity index 99% rename from packages/pi-vscode/package.json rename to vscode/package.json index f2a9504a..2b750492 100644 --- a/packages/pi-vscode/package.json +++ b/vscode/package.json @@ -14,7 +14,7 @@ "repository": { "type": "git", "url": "https://github.com/zy1233/pi-python.git", - "directory": "packages/pi-vscode" + "directory": "vscode" }, "bugs": { "url": "https://github.com/zy1233/pi-python/issues" diff --git a/packages/pi-vscode/scripts/check-vsix.mjs b/vscode/scripts/check-vsix.mjs similarity index 100% rename from packages/pi-vscode/scripts/check-vsix.mjs rename to vscode/scripts/check-vsix.mjs diff --git a/packages/pi-vscode/scripts/fetch-agent.mjs b/vscode/scripts/fetch-agent.mjs similarity index 100% rename from packages/pi-vscode/scripts/fetch-agent.mjs rename to vscode/scripts/fetch-agent.mjs diff --git a/packages/pi-vscode/scripts/lib.d.mts b/vscode/scripts/lib.d.mts similarity index 100% rename from packages/pi-vscode/scripts/lib.d.mts rename to vscode/scripts/lib.d.mts diff --git a/packages/pi-vscode/scripts/lib.mjs b/vscode/scripts/lib.mjs similarity index 98% rename from packages/pi-vscode/scripts/lib.mjs rename to vscode/scripts/lib.mjs index 3853379c..394a610b 100644 --- a/packages/pi-vscode/scripts/lib.mjs +++ b/vscode/scripts/lib.mjs @@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url"; import { gunzipSync, inflateRawSync } from "node:zlib"; export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); -export const REPO_ROOT = path.resolve(ROOT, "..", ".."); +export const REPO_ROOT = path.resolve(ROOT, ".."); export const CACHE_DIR = path.join(ROOT, ".vsix-cache"); export const OUT_DIR = path.join(ROOT, "out"); diff --git a/packages/pi-vscode/scripts/make-icon.mjs b/vscode/scripts/make-icon.mjs similarity index 100% rename from packages/pi-vscode/scripts/make-icon.mjs rename to vscode/scripts/make-icon.mjs diff --git a/packages/pi-vscode/scripts/notices.d.mts b/vscode/scripts/notices.d.mts similarity index 100% rename from packages/pi-vscode/scripts/notices.d.mts rename to vscode/scripts/notices.d.mts diff --git a/packages/pi-vscode/scripts/notices.mjs b/vscode/scripts/notices.mjs similarity index 100% rename from packages/pi-vscode/scripts/notices.mjs rename to vscode/scripts/notices.mjs diff --git a/packages/pi-vscode/scripts/package.mjs b/vscode/scripts/package.mjs similarity index 100% rename from packages/pi-vscode/scripts/package.mjs rename to vscode/scripts/package.mjs diff --git a/packages/pi-vscode/scripts/python_licenses.py b/vscode/scripts/python_licenses.py similarity index 100% rename from packages/pi-vscode/scripts/python_licenses.py rename to vscode/scripts/python_licenses.py diff --git a/packages/pi-vscode/scripts/smoke-vsix.mjs b/vscode/scripts/smoke-vsix.mjs similarity index 100% rename from packages/pi-vscode/scripts/smoke-vsix.mjs rename to vscode/scripts/smoke-vsix.mjs diff --git a/packages/pi-vscode/scripts/webview-harness.d.mts b/vscode/scripts/webview-harness.d.mts similarity index 100% rename from packages/pi-vscode/scripts/webview-harness.d.mts rename to vscode/scripts/webview-harness.d.mts diff --git a/packages/pi-vscode/scripts/webview-harness.mjs b/vscode/scripts/webview-harness.mjs similarity index 100% rename from packages/pi-vscode/scripts/webview-harness.mjs rename to vscode/scripts/webview-harness.mjs diff --git a/packages/pi-vscode/src/core/acp-connection.ts b/vscode/src/core/acp-connection.ts similarity index 100% rename from packages/pi-vscode/src/core/acp-connection.ts rename to vscode/src/core/acp-connection.ts diff --git a/packages/pi-vscode/src/core/agent-process.ts b/vscode/src/core/agent-process.ts similarity index 100% rename from packages/pi-vscode/src/core/agent-process.ts rename to vscode/src/core/agent-process.ts diff --git a/packages/pi-vscode/src/core/chat-controller.ts b/vscode/src/core/chat-controller.ts similarity index 100% rename from packages/pi-vscode/src/core/chat-controller.ts rename to vscode/src/core/chat-controller.ts diff --git a/packages/pi-vscode/src/core/diff-store.ts b/vscode/src/core/diff-store.ts similarity index 100% rename from packages/pi-vscode/src/core/diff-store.ts rename to vscode/src/core/diff-store.ts diff --git a/packages/pi-vscode/src/core/diff-tracker.ts b/vscode/src/core/diff-tracker.ts similarity index 100% rename from packages/pi-vscode/src/core/diff-tracker.ts rename to vscode/src/core/diff-tracker.ts diff --git a/packages/pi-vscode/src/core/diff.ts b/vscode/src/core/diff.ts similarity index 100% rename from packages/pi-vscode/src/core/diff.ts rename to vscode/src/core/diff.ts diff --git a/packages/pi-vscode/src/core/first-run.ts b/vscode/src/core/first-run.ts similarity index 100% rename from packages/pi-vscode/src/core/first-run.ts rename to vscode/src/core/first-run.ts diff --git a/packages/pi-vscode/src/core/host.ts b/vscode/src/core/host.ts similarity index 100% rename from packages/pi-vscode/src/core/host.ts rename to vscode/src/core/host.ts diff --git a/packages/pi-vscode/src/core/locate.ts b/vscode/src/core/locate.ts similarity index 100% rename from packages/pi-vscode/src/core/locate.ts rename to vscode/src/core/locate.ts diff --git a/packages/pi-vscode/src/core/markdown.ts b/vscode/src/core/markdown.ts similarity index 100% rename from packages/pi-vscode/src/core/markdown.ts rename to vscode/src/core/markdown.ts diff --git a/packages/pi-vscode/src/core/protocol.ts b/vscode/src/core/protocol.ts similarity index 100% rename from packages/pi-vscode/src/core/protocol.ts rename to vscode/src/core/protocol.ts diff --git a/packages/pi-vscode/src/core/session-list.ts b/vscode/src/core/session-list.ts similarity index 100% rename from packages/pi-vscode/src/core/session-list.ts rename to vscode/src/core/session-list.ts diff --git a/packages/pi-vscode/src/core/status-row.ts b/vscode/src/core/status-row.ts similarity index 100% rename from packages/pi-vscode/src/core/status-row.ts rename to vscode/src/core/status-row.ts diff --git a/packages/pi-vscode/src/core/thinking.ts b/vscode/src/core/thinking.ts similarity index 100% rename from packages/pi-vscode/src/core/thinking.ts rename to vscode/src/core/thinking.ts diff --git a/packages/pi-vscode/src/core/throttle.ts b/vscode/src/core/throttle.ts similarity index 100% rename from packages/pi-vscode/src/core/throttle.ts rename to vscode/src/core/throttle.ts diff --git a/packages/pi-vscode/src/core/tool-calls.ts b/vscode/src/core/tool-calls.ts similarity index 100% rename from packages/pi-vscode/src/core/tool-calls.ts rename to vscode/src/core/tool-calls.ts diff --git a/packages/pi-vscode/src/core/version.ts b/vscode/src/core/version.ts similarity index 100% rename from packages/pi-vscode/src/core/version.ts rename to vscode/src/core/version.ts diff --git a/packages/pi-vscode/src/extension.ts b/vscode/src/extension.ts similarity index 100% rename from packages/pi-vscode/src/extension.ts rename to vscode/src/extension.ts diff --git a/packages/pi-vscode/src/ui/chat-view.ts b/vscode/src/ui/chat-view.ts similarity index 100% rename from packages/pi-vscode/src/ui/chat-view.ts rename to vscode/src/ui/chat-view.ts diff --git a/packages/pi-vscode/src/ui/diff-documents.ts b/vscode/src/ui/diff-documents.ts similarity index 100% rename from packages/pi-vscode/src/ui/diff-documents.ts rename to vscode/src/ui/diff-documents.ts diff --git a/packages/pi-vscode/src/ui/sessions-view.ts b/vscode/src/ui/sessions-view.ts similarity index 100% rename from packages/pi-vscode/src/ui/sessions-view.ts rename to vscode/src/ui/sessions-view.ts diff --git a/packages/pi-vscode/src/ui/status-bar.ts b/vscode/src/ui/status-bar.ts similarity index 100% rename from packages/pi-vscode/src/ui/status-bar.ts rename to vscode/src/ui/status-bar.ts diff --git a/packages/pi-vscode/src/ui/vscode-host.ts b/vscode/src/ui/vscode-host.ts similarity index 100% rename from packages/pi-vscode/src/ui/vscode-host.ts rename to vscode/src/ui/vscode-host.ts diff --git a/packages/pi-vscode/src/webview/dom.ts b/vscode/src/webview/dom.ts similarity index 100% rename from packages/pi-vscode/src/webview/dom.ts rename to vscode/src/webview/dom.ts diff --git a/packages/pi-vscode/src/webview/main.ts b/vscode/src/webview/main.ts similarity index 100% rename from packages/pi-vscode/src/webview/main.ts rename to vscode/src/webview/main.ts diff --git a/packages/pi-vscode/src/webview/tsconfig.json b/vscode/src/webview/tsconfig.json similarity index 100% rename from packages/pi-vscode/src/webview/tsconfig.json rename to vscode/src/webview/tsconfig.json diff --git a/packages/pi-vscode/test/always-approve.test.ts b/vscode/test/always-approve.test.ts similarity index 100% rename from packages/pi-vscode/test/always-approve.test.ts rename to vscode/test/always-approve.test.ts diff --git a/packages/pi-vscode/test/controller.test.ts b/vscode/test/controller.test.ts similarity index 100% rename from packages/pi-vscode/test/controller.test.ts rename to vscode/test/controller.test.ts diff --git a/packages/pi-vscode/test/diff-view.test.ts b/vscode/test/diff-view.test.ts similarity index 100% rename from packages/pi-vscode/test/diff-view.test.ts rename to vscode/test/diff-view.test.ts diff --git a/packages/pi-vscode/test/diff.test.ts b/vscode/test/diff.test.ts similarity index 100% rename from packages/pi-vscode/test/diff.test.ts rename to vscode/test/diff.test.ts diff --git a/packages/pi-vscode/test/fake-agent.mjs b/vscode/test/fake-agent.mjs similarity index 100% rename from packages/pi-vscode/test/fake-agent.mjs rename to vscode/test/fake-agent.mjs diff --git a/packages/pi-vscode/test/first-run-flow.test.ts b/vscode/test/first-run-flow.test.ts similarity index 100% rename from packages/pi-vscode/test/first-run-flow.test.ts rename to vscode/test/first-run-flow.test.ts diff --git a/packages/pi-vscode/test/first-run.test.ts b/vscode/test/first-run.test.ts similarity index 100% rename from packages/pi-vscode/test/first-run.test.ts rename to vscode/test/first-run.test.ts diff --git a/packages/pi-vscode/test/fixtures/patches.json b/vscode/test/fixtures/patches.json similarity index 100% rename from packages/pi-vscode/test/fixtures/patches.json rename to vscode/test/fixtures/patches.json diff --git a/packages/pi-vscode/test/global-setup.ts b/vscode/test/global-setup.ts similarity index 100% rename from packages/pi-vscode/test/global-setup.ts rename to vscode/test/global-setup.ts diff --git a/packages/pi-vscode/test/helpers.ts b/vscode/test/helpers.ts similarity index 100% rename from packages/pi-vscode/test/helpers.ts rename to vscode/test/helpers.ts diff --git a/packages/pi-vscode/test/locate.test.ts b/vscode/test/locate.test.ts similarity index 100% rename from packages/pi-vscode/test/locate.test.ts rename to vscode/test/locate.test.ts diff --git a/packages/pi-vscode/test/markdown.test.ts b/vscode/test/markdown.test.ts similarity index 100% rename from packages/pi-vscode/test/markdown.test.ts rename to vscode/test/markdown.test.ts diff --git a/packages/pi-vscode/test/packaging.test.ts b/vscode/test/packaging.test.ts similarity index 89% rename from packages/pi-vscode/test/packaging.test.ts rename to vscode/test/packaging.test.ts index bd8edc61..d343cb10 100644 --- a/packages/pi-vscode/test/packaging.test.ts +++ b/vscode/test/packaging.test.ts @@ -145,7 +145,7 @@ describe("bundledPackages (the npm part of THIRD-PARTY-NOTICES)", () => { describe("release files", () => { const root = path.join(__dirname, ".."); const manifest = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8")); - const workflow = readFileSync(path.join(root, "..", "..", ".github", "workflows", "vscode-extension.yml"), "utf8"); + const workflow = readFileSync(path.join(root, "..", ".github", "workflows", "vscode-extension.yml"), "utf8"); it("is the extension zycode.zycode that the registry entries name", () => { expect(manifest.publisher).toBe("zycode"); @@ -194,6 +194,23 @@ describe("release files", () => { expect(workflow).not.toMatch(/tags:/); expect(workflow).toContain("github.ref != 'refs/heads/main'"); }); + + it("points every path of the workflow at the real layout: the folder, the artifact, and the ../vsix of the steps that start in it", () => { + const repo = path.resolve(root, ".."); + const folder = path.relative(repo, root).split(path.sep).join("/"); + // A move of the extension must change all of these. A stale value fails here, and not in a release. + const dirs = [...workflow.matchAll(/^[ \t]*working-directory:[ \t]*(\S+)/gm)].map((m) => m[1] ?? ""); + expect(dirs.length).toBeGreaterThan(0); + expect(new Set(dirs)).toEqual(new Set([folder])); + expect(workflow).toContain(` - "${folder}/**"`); + expect(workflow).toContain(`path: ${folder}/out/*.vsix`); + // `vsix/` is a folder at the top of the checkout (download-artifact puts it there). A step that starts in the + // extension folder reaches it with `../vsix`. The publish job does not run in a pull request, so only this + // test can see a wrong hop in it. + const hops = [...workflow.matchAll(/((?:\.\.\/)+)vsix\//g)].map((m) => m[1] ?? ""); + expect(hops.length).toBeGreaterThan(0); + for (const hop of hops) expect(path.resolve(root, hop, "vsix")).toBe(path.join(repo, "vsix")); + }); }); describe("manifest contributions", () => { diff --git a/packages/pi-vscode/test/protocol.test.ts b/vscode/test/protocol.test.ts similarity index 100% rename from packages/pi-vscode/test/protocol.test.ts rename to vscode/test/protocol.test.ts diff --git a/packages/pi-vscode/test/real-agent.test.ts b/vscode/test/real-agent.test.ts similarity index 99% rename from packages/pi-vscode/test/real-agent.test.ts rename to vscode/test/real-agent.test.ts index 9bda54a4..b9b5aaa9 100644 --- a/packages/pi-vscode/test/real-agent.test.ts +++ b/vscode/test/real-agent.test.ts @@ -8,7 +8,7 @@ import { afterEach, describe, expect, it } from "vitest"; import { TestHost, newController, ofType, tempDir, waitFor } from "./helpers.js"; const here = path.dirname(fileURLToPath(import.meta.url)); -const repo = path.resolve(here, "../../.."); +const repo = path.resolve(here, "../.."); const python = process.env.ZYCODE_REAL_AGENT_PYTHON ?? path.join(repo, ".venv", "bin", "python"); const script = path.join(repo, "packages", "pi-agent-cli", "tests", "_tool_agent.py"); const enabled = process.env.ZYCODE_REAL_AGENT === "1" && existsSync(python) && existsSync(script); diff --git a/packages/pi-vscode/test/real-first-run.test.ts b/vscode/test/real-first-run.test.ts similarity index 99% rename from packages/pi-vscode/test/real-first-run.test.ts rename to vscode/test/real-first-run.test.ts index 06e04c20..96c79fe2 100644 --- a/packages/pi-vscode/test/real-first-run.test.ts +++ b/vscode/test/real-first-run.test.ts @@ -12,7 +12,7 @@ import type { SessionRow } from "../src/core/session-list.js"; import { TestHost, newController, ofType, tempDir, waitFor, type TestHostOptions } from "./helpers.js"; const here = path.dirname(fileURLToPath(import.meta.url)); -const repo = path.resolve(here, "../../.."); +const repo = path.resolve(here, "../.."); const python = process.env.ZYCODE_REAL_AGENT_PYTHON ?? path.join(repo, ".venv", "bin", "python"); const enabled = process.env.ZYCODE_REAL_AGENT === "1" && existsSync(python) && process.platform !== "win32"; diff --git a/packages/pi-vscode/test/real-thinking.test.ts b/vscode/test/real-thinking.test.ts similarity index 99% rename from packages/pi-vscode/test/real-thinking.test.ts rename to vscode/test/real-thinking.test.ts index 0b535984..6bd1bd30 100644 --- a/packages/pi-vscode/test/real-thinking.test.ts +++ b/vscode/test/real-thinking.test.ts @@ -11,7 +11,7 @@ import type { ChatController } from "../src/core/chat-controller.js"; import { TestHost, newController, tempDir, waitFor } from "./helpers.js"; const here = path.dirname(fileURLToPath(import.meta.url)); -const repo = path.resolve(here, "../../.."); +const repo = path.resolve(here, "../.."); const python = process.env.ZYCODE_REAL_AGENT_PYTHON ?? path.join(repo, ".venv", "bin", "python"); const enabled = process.env.ZYCODE_REAL_AGENT === "1" && existsSync(python) && process.platform !== "win32"; diff --git a/packages/pi-vscode/test/session-list.test.ts b/vscode/test/session-list.test.ts similarity index 100% rename from packages/pi-vscode/test/session-list.test.ts rename to vscode/test/session-list.test.ts diff --git a/packages/pi-vscode/test/sessions.test.ts b/vscode/test/sessions.test.ts similarity index 100% rename from packages/pi-vscode/test/sessions.test.ts rename to vscode/test/sessions.test.ts diff --git a/packages/pi-vscode/test/status-row.test.ts b/vscode/test/status-row.test.ts similarity index 100% rename from packages/pi-vscode/test/status-row.test.ts rename to vscode/test/status-row.test.ts diff --git a/packages/pi-vscode/test/support/fake_model.py b/vscode/test/support/fake_model.py similarity index 100% rename from packages/pi-vscode/test/support/fake_model.py rename to vscode/test/support/fake_model.py diff --git a/packages/pi-vscode/test/support/pty_answers.py b/vscode/test/support/pty_answers.py similarity index 100% rename from packages/pi-vscode/test/support/pty_answers.py rename to vscode/test/support/pty_answers.py diff --git a/packages/pi-vscode/test/thinking.test.ts b/vscode/test/thinking.test.ts similarity index 100% rename from packages/pi-vscode/test/thinking.test.ts rename to vscode/test/thinking.test.ts diff --git a/packages/pi-vscode/test/throttle.test.ts b/vscode/test/throttle.test.ts similarity index 100% rename from packages/pi-vscode/test/throttle.test.ts rename to vscode/test/throttle.test.ts diff --git a/packages/pi-vscode/test/tool-calls.test.ts b/vscode/test/tool-calls.test.ts similarity index 100% rename from packages/pi-vscode/test/tool-calls.test.ts rename to vscode/test/tool-calls.test.ts diff --git a/packages/pi-vscode/test/usage.test.ts b/vscode/test/usage.test.ts similarity index 100% rename from packages/pi-vscode/test/usage.test.ts rename to vscode/test/usage.test.ts diff --git a/packages/pi-vscode/test/version.test.ts b/vscode/test/version.test.ts similarity index 100% rename from packages/pi-vscode/test/version.test.ts rename to vscode/test/version.test.ts diff --git a/packages/pi-vscode/test/webview.test.ts b/vscode/test/webview.test.ts similarity index 100% rename from packages/pi-vscode/test/webview.test.ts rename to vscode/test/webview.test.ts diff --git a/packages/pi-vscode/tsconfig.json b/vscode/tsconfig.json similarity index 100% rename from packages/pi-vscode/tsconfig.json rename to vscode/tsconfig.json diff --git a/packages/pi-vscode/vitest.config.ts b/vscode/vitest.config.ts similarity index 100% rename from packages/pi-vscode/vitest.config.ts rename to vscode/vitest.config.ts From a67d0add54a5e626cb15577ce5ab8c8fd7021d6a Mon Sep 17 00:00:00 2001 From: sim Date: Fri, 13 Nov 2026 10:49:36 +0800 Subject: [PATCH 2/2] ci: do not run Ruff and pytest for a change that only touches the extension or the docs ci.yml had no paths filter, so every pull request ran the whole Python CI (Ruff, and pytest on three Python versions: about 15 minutes of runner time), also a pull request that only changes vscode/ or web/. Moving the extension to the root does not change that. This does. The filter is a `paths` list with `!` patterns, on push and on pull_request: - "**" - "!vscode/**" - "!docs/**" - "!.github/workflows/vscode-extension.yml" - "**/*.py" GitHub reads the patterns in order: a `!` pattern takes a file out, and a later positive pattern puts it back. The workflow runs when at least one changed file is left in. So: - Only vscode/, docs/ and the extension workflow, with no .py file: skipped. (The extension has its own workflow.) - Any .py file runs it. This matters: Ruff reads three Python files inside vscode/ (scripts/python_licenses.py, test/support/fake_model.py, test/support/pty_answers.py). A paths-ignore on vscode/** would skip them. - Any other file runs it, also AGENTS.md, README.md and ci.yml itself. Why it is safe: - No check is required on main (the ruleset only forbids a deletion and a force push), so a skipped run blocks no merge. - docs/ has Markdown only, and it is in `extend-exclude` of Ruff and outside `testpaths` of pytest. No Python test reads vscode/ or docs/. Checked: every workflow parses as YAML, and a model of the documented rule (patterns in order) gave the expected result for 18 single paths and 7 sets of paths, among them the files of the pull request 124 (skipped), the three Python files (run) and "extension + AGENTS.md" (run). Not verified: the effect on GitHub. This commit changes ci.yml, so its own pull request runs the workflow. The first pull request that touches only the extension shows the effect. AGENTS.md: the row of vscode/ said that ruff does not read the extension. It reads the three Python files. The row says so now, and says what the filter does. Design document: decision D39. --- .github/workflows/ci.yml | 19 +++++++++++++++++++ AGENTS.md | 2 +- .../2026-11-04-vscode-extension-design.md | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1074f444..0108370e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,28 @@ name: CI +# Ruff and pytest read Python. A change that touches only the paths below cannot change their result: +# the extension has its own workflow (vscode-extension.yml), `docs/` is outside Ruff (`extend-exclude`) +# and outside `testpaths`, and no Python test reads either folder. GitHub runs this workflow when ANY +# changed file is left in the list, so a change that also touches another file still runs it. +# The order matters: a `!` pattern takes a file out, and the last pattern puts every Python file back +# (Ruff reads the three Python helpers inside `vscode/`). No check is required on `main`, so a run that +# is skipped blocks no merge. on: push: branches: [main] + paths: + - "**" + - "!vscode/**" + - "!docs/**" + - "!.github/workflows/vscode-extension.yml" + - "**/*.py" pull_request: + paths: + - "**" + - "!vscode/**" + - "!docs/**" + - "!.github/workflows/vscode-extension.yml" + - "**/*.py" concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/AGENTS.md b/AGENTS.md index 7b520782..bfe94417 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,7 +37,7 @@ AgentMessage[] → transform_context() → convert_to_llm() → LangChain BaseMe | `packages/pi-mcp/` | Optional extension `pi-mcp-py` (entry point `pi-mcp`): connects the MCP servers (stdio, http, sse) that an ACP client passes in `session/new`, one runner task per server, tools named `mcp____`, `/mcp` command. Core, harness and CLI have no MCP client; they hand the servers over as data (`ClientMcpServer`, `ExtensionAPI.client_mcp_servers`). Design: `docs/specs/2026-10-23-mcp-extension-design.md`. Its tests are left out of a run that did not install the package (the header says so) | — | | `packaging/agent/` | Builds the agent as a one-file executable (PyInstaller; `build.py`, `zycode-agent.spec`, `entry.py`) and the smoke test over ACP with a fake model server (`smoke.py`). `.github/workflows/agent-binaries.yml` runs both on five platforms and attaches the archives to the GitHub Release after the `Release` workflow. A frozen build has no interpreter: `host.py` starts a frozen `child.py`, and only the OpenAI-format provider is in it. Design and the registry entry draft: `docs/specs/2026-10-31-agent-binaries.md` | — | | `packages/pi-agent-cli/` | Standard-ACP CLI (`python -m pi_agent_cli`); config `agent.example.toml`, home `~/.pi-python`; TUI binary `zypi` under `tui/`. See [`packages/pi-agent-cli/AGENTS.md`](packages/pi-agent-cli/AGENTS.md) for spawn, config, first run (`--setup` and the terminal login that `initialize` offers to a client that can run one; `zypi` still gets `authMethods: []`), prompt pipeline, and the three permission modes `ask`, `auto` and `always-approve` (Auto: rules, and a model step for a `bash` call that no rule decides: `auto_rules.py`, `auto_classifier.py`, `auto_mode.py`, `permission_modes.py`; design `docs/specs/2026-11-02-auto-mode-design.md`; the pager offers all three, and a clean start is `ask`). The items on the ACP wire beyond standard ACP (`pi/session/delete`, `_meta.sessionId`, and others) are in the register `docs/specs/2026-11-05-acp-extension-registry.md` | — | -| `vscode/` | The VS Code extension `zycode.zycode` (TypeScript, `src/core/` has no `vscode` import). It is an ACP client and a chat view for zycode in VS Code: it starts the agent as a child process, shows permission questions and a diff for `write`/`edit`, runs the first-run setup in a terminal (a walkthrough, a banner and hints guide the first start; the agent's own `--setup` and `auth_required` carry it, no wire item and no agent change), lists past chats of the folder in a view (`session/list`, `session/load`, `pi/session/delete`), and offers the three permission modes `ask`, `auto` and `always-approve` in the chat menu (`always-approve` only after a modal warning, never restored for a new chat, a past chat or a restart, and not in an untrusted workspace; the `zycode.permissionMode` setting stays `ask`/`auto`; it moves the agent with the agent's own `pi/yolo_mode_changed`). The extension never writes `always-approve` through `set_config_option`. A Thinking menu shows `thinking_level` of `agent.toml`; agent 0.9.1 cannot change it live, so a change edits that one line (checked by parsing, after a modal), restarts the agent and reopens the chat (design section 7c). One VSIX per platform, each with the bundled `zycode-agent` binary of one Release (pin and sha256 in `agent-assets.json`). Not a Python package: ruff and pytest do not read it; `.github/workflows/vscode-extension.yml` runs `npm run check` and a `linux-x64` VSIX smoke test for a PR that changes it, and publishes (Trusted Publishing, by hand on `main`, environment `vscode-publish`). Version 1.0.0 is the first stable release (the pre-release 0.1.0 was uploaded by hand; the 1.0.0 run, run `43181052994` on 2026-11-12, was the first real OIDC publish and worked on the first try on Open VSX and the Marketplace, five targets, no token; the record is in `vscode/RELEASING.md`; stable = even minor, pre-release = odd minor). Do not rename that file or the environment: the registries name them. Local check: `cd vscode; npm run check`. Design: `docs/specs/2026-11-04-vscode-extension-design.md`; make and test a VSIX: `vscode/PACKAGING.md`; releases: `vscode/RELEASING.md` | — | +| `vscode/` | The VS Code extension `zycode.zycode` (TypeScript, `src/core/` has no `vscode` import). It is an ACP client and a chat view for zycode in VS Code: it starts the agent as a child process, shows permission questions and a diff for `write`/`edit`, runs the first-run setup in a terminal (a walkthrough, a banner and hints guide the first start; the agent's own `--setup` and `auth_required` carry it, no wire item and no agent change), lists past chats of the folder in a view (`session/list`, `session/load`, `pi/session/delete`), and offers the three permission modes `ask`, `auto` and `always-approve` in the chat menu (`always-approve` only after a modal warning, never restored for a new chat, a past chat or a restart, and not in an untrusted workspace; the `zycode.permissionMode` setting stays `ask`/`auto`; it moves the agent with the agent's own `pi/yolo_mode_changed`). The extension never writes `always-approve` through `set_config_option`. A Thinking menu shows `thinking_level` of `agent.toml`; agent 0.9.1 cannot change it live, so a change edits that one line (checked by parsing, after a modal), restarts the agent and reopens the chat (design section 7c). One VSIX per platform, each with the bundled `zycode-agent` binary of one Release (pin and sha256 in `agent-assets.json`). Not a Python package: pytest does not read it, and ruff reads only its three Python helpers (`scripts/python_licenses.py`, `test/support/fake_model.py`, `test/support/pty_answers.py`). `.github/workflows/vscode-extension.yml` runs `npm run check` and a `linux-x64` VSIX smoke test for a PR that changes it. `ci.yml` (Ruff, pytest) skips a PR that touches only `vscode/`, `docs/` and that workflow, with no `.py` file (a `paths` filter with `!` patterns; no check is required on `main`, so a skipped run blocks no merge). The same workflow publishes (Trusted Publishing, by hand on `main`, environment `vscode-publish`). Version 1.0.0 is the first stable release (the pre-release 0.1.0 was uploaded by hand; the 1.0.0 run, run `43181052994` on 2026-11-12, was the first real OIDC publish and worked on the first try on Open VSX and the Marketplace, five targets, no token; the record is in `vscode/RELEASING.md`; stable = even minor, pre-release = odd minor). Do not rename that file or the environment: the registries name them. Local check: `cd vscode; npm run check`. Design: `docs/specs/2026-11-04-vscode-extension-design.md`; make and test a VSIX: `vscode/PACKAGING.md`; releases: `vscode/RELEASING.md` | — | | `web/` | Product site for zycode, live at `https://zycode.dev` (static Astro, Node ≥ 22.23.4; English at `/`, Chinese at `/zh/`; Cloudflare Workers static assets, no server of ours). Not a Python package: ruff and pytest do not read it; `.github/workflows/web-ci.yml` runs `npm run check` and `npm run build` for a PR that changes `web/`. A merge to `main` that changes `web/` deploys to `zycode.dev` by itself (Cloudflare Workers Builds, not GitHub Actions). Its claims must stay equal to the README table "Status" and to the benchmark report, and `en.ts` / `zh.ts` keep the same keys. See [`web/README.md`](web/README.md) for commands, deploy, the domain, and the Cloudflare settings that are not in the repository | — | ### Invariants diff --git a/docs/specs/2026-11-04-vscode-extension-design.md b/docs/specs/2026-11-04-vscode-extension-design.md index 1bd1bd44..4e180328 100644 --- a/docs/specs/2026-11-04-vscode-extension-design.md +++ b/docs/specs/2026-11-04-vscode-extension-design.md @@ -580,3 +580,4 @@ From the report, section 3.3 (Phase 2 and later), and from the limits above: | D36 (built) | **Recommended: as built.** The context and the cost in the status row come only from the standard `usage_update` of the agent. The extension counts no tokens, has no setting for the size of the window, and shows nothing when the agent sends nothing. Options not taken: **B**, an estimate that the extension makes (for example characters ÷ 4); **C**, a setting `zycode.contextWindow`; **D**, change the agent now (the user said: write down the investigation only). | Agent 0.9.1 does not know the real window (`Model.context_window` is 128,000 for every model, and no key sets it) and has no price (`cost.total` is 0 in all 21 messages that we read), so a number from the extension would be a guess that looks like a fact. The pager made the same decision on 2026-10-13: it shows no context and no cost, and no number is invented. The row shows by itself when an agent sends `usage_update`, with no change in the extension. The findings and the agent change that is needed are in `docs/specs/2026-11-13-agent-context-usage.md`. | | D37 (built) | **Recommended: as built.** The time of the turn is measured by the clock of the host, and the folder comes from the session. Both show in the header (and in the tooltip of the status bar item). The page counts the running time with its own timer, and changes one element each 500 ms. Options not taken: a clock in the status bar item (it needs a timer in the extension host each second); the tokens of the last turn (the agent does not send them). | The agent sends no times, and the pager draws clocks of its own for the same reason (2026-10-13). A tick that changes one element leaves a menu that is open alone; a new `state` message for each second would close it. The host sends a fresh `elapsedMs` in each `state` message, so a clock that has drifted is set right at the next one. | | D38 (built) | **Recommended: as built.** The extension lives in `vscode/`, at the root of the repository, and not in `packages/pi-vscode/`. The workflow file `vscode-extension.yml` and the environment `vscode-publish` keep their names. Options not taken: **B**, keep `packages/pi-vscode/`; **C**, a longer name (`zycode-vscode/`, `extensions/vscode/`). | `packages/` holds the six Python packages. Each has a `pyproject.toml`, and the uv workspace and the pytest paths in the root `pyproject.toml` name them one by one. The extension is not Python and is in neither list. `web/` and `tui/` are at the root for the same reason, and each has its own CI, as the extension has (`vscode-extension.yml`). **The move does not change which CI runs for a change.** `ci.yml` (Ruff and pytest) has no `paths` filter, so it runs for every pull request, also for one that only touches `web/`. What the move changed: `REPO_ROOT` in `scripts/lib.mjs` and the three `../../..` in the opt-in tests; the test that reads the workflow; `repository.directory`; and the workflow (8 `working-directory`, the artifact path, the trigger path, and three `../../vsix/` that have no `pi-vscode` in the text, so a search by name misses them; two of them are in the publish job, which does not run in a pull request). A test now checks all of these against the real layout (`points every path of the workflow at the real layout`). The two registries name the repository, the workflow file and the environment, and not a directory, so the trusted publishers stay valid. Old links to `packages/pi-vscode/...` on GitHub do not work any more. The README of 1.0.0 names the old folder as text only, with no link (the next release says `vscode`), and its CHANGELOG and walkthrough have no link into it. | +| D39 (built) | **Recommended: as built.** `ci.yml` (Ruff and pytest) does not run for a change that touches only `vscode/`, `docs/` and `vscode-extension.yml`, with no `.py` file. It is a `paths` filter with `!` patterns, on `push` and on `pull_request`. Options not taken: a `paths-ignore` filter with `vscode/**` (it would also skip the three Python helpers in `vscode/`, which Ruff reads); also leaving out `web/**` and `tui/**` (the same idea, but not asked for, and not checked against their tests). | A change of the extension started the whole Python CI (Ruff, and pytest on three Python versions, about 15 minutes of runner time), because `ci.yml` had no filter. For a pull request that only changes the extension and its documents, no Python result can change. No test reads `vscode/` or `docs/`, `docs` is in `extend-exclude` of Ruff, and `docs/` has Markdown only. Ruff does read the three Python files in `vscode/` (`scripts/python_licenses.py`, `test/support/fake_model.py`, `test/support/pty_answers.py`), so the last pattern, `**/*.py`, puts every Python file back (GitHub reads the patterns in order, and a positive pattern after a `!` pattern puts a file back). The workflow still runs when any other file is in the change (for example `AGENTS.md`, `README.md`, or `ci.yml` itself). No check is required on `main` (the ruleset only forbids a deletion and a force push), so a skipped run blocks no merge. Not verified: the effect on GitHub. The pull request that adds the filter changes `ci.yml`, so it runs the workflow itself. The first pull request that touches only the extension shows the effect. |