qwen-code/package.json
Shaojin Wen 0d6f3d42e6
feat(verify-pr): ship a one-command capture helper (#8114)
* feat(verify-pr): ship a one-command capture helper

Fourth attempt at the same failure, and the first one aimed at the real
cause. The score so far:

  #8016  captures were "Optionally … when text cannot carry the
         oracle"                                        -> 0 images / 14 runs
  #8104  captures became budget item 4 in Scope
         selection                                      -> 0 images / 1 run

That last run is the one that settles it. Same PR (#7975), browser
installed and working ("Install evidence browser: success"), and the
verification got DEEPER — 64 assertions against 40, 53 tables against
31 — while still producing zero images. An agent reading the instruction,
doing more work than before, and still not capturing is not an agent that
missed the instruction.

The cause is one I should have checked when I wrote #8016: the skill sent
the agent to build node-pty -> xterm.js -> Playwright itself, and
`node-pty` is not a dependency of this repo. It needs a native build. The
`playwright` package is not a declared dependency either. So the
documented route did not exist, and the incentive was entirely against
trying it: authoring that pipeline risks failing and eats budget, while
skipping costs nothing and is invisible.

`scripts/verify-capture.mjs` makes a capture one command using deps that
are already installed:

    node scripts/verify-capture.mjs --out evidence/01-ab.png \
      --title 'A/B: the gate flips' -- node my-harness.mjs

Command (or stdin) -> @xterm/headless parses the ANSI into a cell grid
with colour and bold -> SVG -> sharp rasterises. No browser, no
pseudo-terminal. A non-zero exit from the captured command still produces
an image, because capturing a failing base arm is the normal case.

The skill's dead route is removed and replaced with that command, and the
budget line drops from ~5 minutes to ~2 because there is no pipeline to
author. QWEN_VERIFY_CHROMIUM and its install stay for a future web-UI
capture, but the terminal route no longer depends on them — gating on a
browser the route does not use is how an absent browser turns into a
skipped capture.

Mutation-verified 7/7 against the real helper and the real PNGs: bare LF
(staircase render), no event-loop turn (blank capture), dropped bold,
dropped colour, no blank-row trimming, tolerating an empty capture, and
dropped geometry validation.

Two of those initially SURVIVED. The colour test compared "coloured and
bold" against plain and asserted the bytes differ — which passes while
EITHER attribute survives. That is the wrong-reason trap this skill warns
about, met in the skill's own test file. Each attribute is now isolated
against the same plain baseline (green-no-bold, bold-no-colour), and both
mutations kill.

119/119 across both suites; prettier and eslint clean.

* fix(verify-pr): harden capture helper per review (#8114)

- Strip U+FE0F before rasterising: the emoji variation selector made Pango
  abort() in native code (SIGTRAP, no PNG, no diagnostic) when no colour-emoji
  font exists; the base codepoint renders. Add a non-ASCII regression test.
- Await xterm's write callback instead of a fixed 120ms sleep, so a large
  capture is not read mid-parse and silently come out blank.
- Name a signal-killed child ("killed by SIGKILL") rather than "exited null".
- Warn on stderr when input is taller than --rows and the top is dropped.
- Correct the falsified "route did not exist" rationale: the browser pipeline's
  deps do resolve from this repo; the real fragility is that
  integration-tests/terminal-capture is not a root workspace. Keep a skill
  pointer to terminal-capture for TUI/web-UI captures this helper cannot do.
- Qualify the colour claim (16 base ANSI colours; 256/truecolor fall back).
- Tests: feed both --cols and --rows to the geometry guard, exercise escapeXml,
  flatten the SKILL.md assertion against reflow, and replace the platform-fragile
  PNG byte-length check (flaked at 846B on Linux vs >1000B on macOS) with the
  deterministic canvas geometry.

* fix(verify-pr): exercise colour fallback and fix wrap-aware truncation warning (#8114)

* fix(verify-pr): separate stdout/stderr join and pin next() guard (#8114)

* fix(scripts): correct verify-capture truncation guard and SGR 30 colour (#8114)

The truncation guard compared wrapped rows against --rows, but
newline-terminated output needs one row beyond its last line (the final
CRLF scrolls it off the scrollback-less viewport), so input of exactly
--rows lines — including the default 40 — lost its top line with no
warning, and taller input under-reported the drop by one. Compare against
a capacity of rows - 1 for newline-terminated input.

Also lift SGR 30 foreground to the default grey: it mapped to #1e1e1e,
identical to the canvas background, so black-foreground labels (e.g.
vitest's project badge) vanished as black-on-black.

* fix(scripts): address review feedback on verify-capture helper (#8114)

- Declare sharp as a root devDependency so the script does not rely on
  workspace hoisting from packages/core
- Guard against TTY stdin hanging silently: check process.stdin.isTTY
  before readFileSync(0) and print usage immediately
- Fix phantom blank row when stdout already ends with a newline: only
  insert a separator between stdout and stderr when stdout lacks a
  trailing newline
- Strengthen 256-colour/truecolor test to decode pixels and assert the
  #d4d4d4 fallback grey is present
- Add test for non-newline-terminated input that fits exactly --rows
- Add test for the phantom blank row fix (console.log + stderr)

---------

Co-authored-by: wenshao <wenshao@example.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-07-31 07:48:09 +00:00

182 lines
8.9 KiB
JSON

{
"name": "@qwen-code/qwen-code",
"version": "0.21.2",
"engines": {
"node": ">=22.0.0"
},
"type": "module",
"workspaces": [
"packages/*",
"packages/channels/base",
"packages/channels/telegram",
"packages/channels/weixin",
"packages/channels/dingtalk",
"packages/channels/wecom",
"packages/channels/feishu",
"packages/channels/qqbot",
"packages/channels/github",
"packages/channels/gitlab",
"packages/channels/plugin-example",
"integrations/external-context",
"!packages/desktop"
],
"repository": {
"type": "git",
"url": "git+https://github.com/QwenLM/qwen-code.git"
},
"config": {
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.21.2"
},
"scripts": {
"start": "node scripts/start.js",
"dev": "node scripts/dev.js",
"dev:daemon": "node scripts/daemon-dev.js",
"debug": "cross-env DEBUG=1 node --inspect-brk scripts/start.js",
"generate": "node scripts/generate-git-commit-info.js",
"generate:settings-schema": "node --import tsx/esm scripts/generate-settings-schema.ts",
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=3072\" node scripts/build.js",
"build-and-start": "npm run build && npm run start",
"build:vscode": "node scripts/build_vscode_companion.js",
"build:all": "npm run build && npm run build:sandbox && npm run build:vscode",
"build:packages": "npm run build --workspaces",
"build:sandbox": "node scripts/build_sandbox.js",
"bundle": "npm run generate && node esbuild.config.js && node scripts/copy_bundle_assets.js",
"test": "cross-env NODE_OPTIONS=\"--max-old-space-size=3072\" npm run test --workspaces --if-present --parallel",
"test:ci": "cross-env NODE_OPTIONS=\"--max-old-space-size=3072\" npm run test:ci --workspaces --if-present --parallel && npm run test:scripts",
"test:release": "cross-env NODE_OPTIONS=\"--max-old-space-size=3072\" npm run test:ci --workspaces --if-present --parallel -- --coverage.enabled=false && npm run test:scripts",
"test:scripts": "vitest run --config ./scripts/tests/vitest.config.ts",
"test:e2e": "cross-env VERBOSE=true KEEP_OUTPUT=true npm run test:integration:sandbox:none",
"test:integration:all": "npm run test:integration:sandbox:none && npm run test:integration:sandbox:docker && npm run test:integration:sandbox:podman",
"test:integration:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests",
"test:integration:sandbox:docker": "cross-env QWEN_SANDBOX=docker npm run build:sandbox && QWEN_SANDBOX=docker vitest run --root ./integration-tests",
"test:integration:sandbox:podman": "cross-env QWEN_SANDBOX=podman vitest run --root ./integration-tests",
"test:integration:no-ak:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests ./fake-openai-server.test.ts ./cli/qwen-serve-routes.test.ts ./cli/qwen-serve-streaming.test.ts ./cli/daemon-invocation-context.test.ts",
"test:integration:sdk:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests --poolOptions.threads.maxThreads 2 sdk-typescript",
"test:integration:sdk:sandbox:docker": "cross-env QWEN_SANDBOX=docker npm run build:sandbox && QWEN_SANDBOX=docker vitest run --root ./integration-tests --poolOptions.threads.maxThreads 2 sdk-typescript",
"test:sdk:python": "python3 -m pytest -c packages/sdk-python/pyproject.toml packages/sdk-python/tests -q",
"test:integration:cli:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests cli",
"test:integration:cli:sandbox:docker": "cross-env QWEN_SANDBOX=docker npm run build:sandbox && QWEN_SANDBOX=docker vitest run --root ./integration-tests cli",
"test:integration:interactive:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests interactive",
"test:integration:interactive:sandbox:docker": "cross-env QWEN_SANDBOX=docker npm run build:sandbox && QWEN_SANDBOX=docker vitest run --root ./integration-tests interactive",
"test:terminal-bench": "cross-env VERBOSE=true KEEP_OUTPUT=true vitest run --config ./vitest.terminal-bench.config.ts --root ./integration-tests",
"test:terminal-bench:oracle": "cross-env VERBOSE=true KEEP_OUTPUT=true vitest run --config ./vitest.terminal-bench.config.ts --root ./integration-tests -t 'oracle'",
"test:terminal-bench:qwen": "cross-env VERBOSE=true KEEP_OUTPUT=true vitest run --config ./vitest.terminal-bench.config.ts --root ./integration-tests -t 'qwen'",
"lint": "eslint . --ext .ts,.tsx && eslint integration-tests",
"lint:fix": "eslint . --fix && eslint integration-tests --fix",
"lint:ci": "eslint . --ext .ts,.tsx --max-warnings 0 && eslint integration-tests --max-warnings 0",
"lint:sdk:python": "python3 -m ruff check --config packages/sdk-python/pyproject.toml packages/sdk-python",
"lint:all": "node scripts/lint.js",
"audit:runtime:critical": "node scripts/audit-runtime-critical.js",
"format": "prettier --experimental-cli --write .",
"typecheck": "npm run typecheck --workspaces --if-present",
"typecheck:sdk:python": "python3 -m mypy --config-file packages/sdk-python/pyproject.toml packages/sdk-python/src",
"smoke:sdk:python": "python3 packages/sdk-python/scripts/smoke_real.py",
"build:sdk:python": "python3 -m build packages/sdk-python",
"check-i18n": "npm run check-i18n --workspace=packages/cli",
"preflight": "npm run clean && npm ci && npm run format && npm run lint:ci && npm run build && npm run typecheck && npm run test:ci && npm run check:serve-fast-path-bundle",
"postinstall": "patch-package",
"prepare": "node scripts/prepare.js",
"prepare:package": "node scripts/prepare-package.js",
"package:hosted-installation": "node scripts/build-hosted-installation-assets.js",
"package:standalone": "node scripts/create-standalone-package.js",
"package:standalone:release": "node scripts/build-standalone-release.js",
"verify:installation-release": "node scripts/verify-installation-release.js",
"release:version": "node scripts/version.js",
"changelog": "node scripts/generate-changelog.js",
"telemetry": "node scripts/telemetry.js",
"check:lockfile": "node scripts/check-lockfile.js",
"check:desktop-isolation": "node scripts/check-desktop-isolation.js",
"check:serve-fast-path-bundle": "node scripts/clean-package-build-artifacts.js && npm run build -- --cli-only && cross-env DEV=true npm run bundle && node scripts/check-serve-fast-path-bundle.js",
"desktop-openwork-sync": "bun run scripts/desktop-openwork-sync.ts",
"clean": "node scripts/clean.js",
"pre-commit": "node scripts/pre-commit.js"
},
"overrides": {
"ansi-regex": "6.2.2",
"cliui": {
"wrap-ansi": "7.0.0"
},
"baseline-browser-mapping": "^2.9.19",
"normalize-package-data": "^7.0.1",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0"
},
"bin": {
"qwen": "scripts/cli-entry.js"
},
"files": [
"dist/",
"scripts/cli-entry.js",
"README.md",
"LICENSE"
],
"devDependencies": {
"@types/chrome": "^0.1.32",
"@types/marked": "^5.0.2",
"@types/mime-types": "^3.0.1",
"@types/minimatch": "^5.1.2",
"@types/mock-fs": "^4.13.4",
"@types/proper-lockfile": "^4.1.4",
"@types/shell-quote": "^1.7.5",
"@types/uuid": "^10.0.0",
"@vitest/coverage-v8": "^3.1.1",
"@vitest/eslint-plugin": "^1.3.4",
"@xterm/headless": "^5.5.0",
"@xterm/xterm": "^6.0.0",
"cross-env": "^7.0.3",
"esbuild": "^0.25.0",
"esbuild-plugin-wasm": "^1.1.0",
"eslint": "^9.24.0",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-check-file": "^3.3.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-license-header": "^0.8.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"glob": "^10.5.0",
"globals": "^16.0.0",
"husky": "^9.1.7",
"json": "^11.0.0",
"lint-staged": "^16.1.6",
"memfs": "^4.42.0",
"mnemonist": "^0.40.3",
"mock-fs": "^5.5.0",
"msw": "^2.10.4",
"npm-run-all": "^4.1.5",
"patch-package": "^8.0.1",
"prettier": "^3.5.3",
"react-devtools-core": "^6.1.5",
"semver": "^7.7.2",
"sharp": "^0.34.5",
"strip-ansi": "^7.1.2",
"tsx": "^4.20.3",
"typescript-eslint": "^8.30.1",
"vitest": "^3.2.4",
"yaml": "^2.8.1",
"yargs": "^17.7.2"
},
"dependencies": {
"@testing-library/dom": "^10.4.1",
"ink": "^7.0.3",
"simple-git": "^3.36.0"
},
"optionalDependencies": {
"@lydell/node-pty": "1.2.0-beta.10",
"@lydell/node-pty-darwin-arm64": "1.2.0-beta.10",
"@lydell/node-pty-darwin-x64": "1.2.0-beta.10",
"@lydell/node-pty-linux-x64": "1.2.0-beta.10",
"@lydell/node-pty-win32-arm64": "1.2.0-beta.10",
"@lydell/node-pty-win32-x64": "1.2.0-beta.10"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint --fix --max-warnings 0 --no-warn-ignored"
],
"*.{json,md}": [
"prettier --write"
]
}
}