mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
refactor(cli): rename serve files to kebab-case (#5592)
Rename the PR1 serve and daemon adapter files from issue #5576 to kebab-case and update current imports, tests, comments, and developer docs to match. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
This commit is contained in:
parent
ec99a7f2db
commit
b4705b2534
81 changed files with 186 additions and 186 deletions
|
|
@ -1142,7 +1142,7 @@ packages/core/src/config/config.ts # setMcpTransportPool / getMcpT
|
|||
packages/cli/src/acp-integration/acpAgent.ts # QwenAgent.mcpPool construction; broadcastBudgetEvent;
|
||||
# newSessionConfig wires pool into Config;
|
||||
# killSession calls pool.releaseSession
|
||||
packages/cli/src/serve/runQwenServe.ts # pass --mcp-pool-transports + budget env to ACP child
|
||||
packages/cli/src/serve/run-qwen-serve.ts # pass --mcp-pool-transports + budget env to ACP child
|
||||
packages/cli/src/serve/httpAcpBridge.ts # buildWorkspaceMcpStatus reads pool;
|
||||
# restartMcpServer extMethod returns RestartResult[]
|
||||
packages/cli/src/serve/capabilities.ts # advertise mcp_workspace_pool
|
||||
|
|
@ -1160,7 +1160,7 @@ Per maintainer's feature-cohesive batch guidance (#4175 branching strategy 2026-
|
|||
| 1 | `refactor(core): split McpClient.discover into pure tool/prompt list and unify connect paths` | Add `discoverAndReturn()`; extract shared `establishConnection()` used by both `McpClient.connect()` and `connectToMcpServer()` factory; legacy `discover()` becomes thin wrapper that registers (preserves standalone qwen behavior). Zero observable behavior change. | `mcp-client.ts`, `mcp-client.test.ts` |
|
||||
| 2 | `feat(core): McpTransportPool + SessionMcpView` | Pool core: `fingerprint`, refcount, `spawnInFlight` dedupe, `sessionToEntries` reverse index, drain state machine, snapshot replay on attach, generation guard, tool+prompt dual fan-out, per-session trust copy. Mock McpClient for unit tests. No production wiring. | new `mcp-transport-pool.ts`, `mcp-pool-key.ts`, `mcp-pool-entry.ts`, `session-mcp-view.ts`, `mcp-pool-events.ts` + tests |
|
||||
| 3 | `feat(core): cross-platform descendant pid sweep + pool health monitor` | `listDescendantPids` (Unix `pgrep -P` recursive, Windows PowerShell CIM); unified health monitor inside `PoolEntry` (interval check + failure count + reconnect backoff per §6.6); subprocess-spawn integration tests gated on `QWEN_INTEGRATION === '1'`. | new `pid-descendants.ts` + tests; `mcp-pool-entry.ts` |
|
||||
| 4 | `feat(serve): wire McpTransportPool into QwenAgent daemon mode` | `Config.setMcpTransportPool` + `getMcpTransportPool`; `ToolRegistry` threads pool into `McpClientManager`; `McpClientManager` optional `pool?` ctor param; `acpAgent.QwenAgent` constructs pool at init; `newSessionConfig` injection; `killSession` calls `pool.releaseSession`; SDK MCP + HTTP/SSE bypass via `createUnpooledConnection`; CLI flags `--mcp-pool-transports`, `--mcp-pool-drain-ms`, `--no-mcp-pool`. | `config.ts`, `tool-registry.ts`, `mcp-client-manager.ts`, `acpAgent.ts`, `runQwenServe.ts` |
|
||||
| 4 | `feat(serve): wire McpTransportPool into QwenAgent daemon mode` | `Config.setMcpTransportPool` + `getMcpTransportPool`; `ToolRegistry` threads pool into `McpClientManager`; `McpClientManager` optional `pool?` ctor param; `acpAgent.QwenAgent` constructs pool at init; `newSessionConfig` injection; `killSession` calls `pool.releaseSession`; SDK MCP + HTTP/SSE bypass via `createUnpooledConnection`; CLI flags `--mcp-pool-transports`, `--mcp-pool-drain-ms`, `--no-mcp-pool`. | `config.ts`, `tool-registry.ts`, `mcp-client-manager.ts`, `acpAgent.ts`, `run-qwen-serve.ts` |
|
||||
| 5 | `feat(serve): pool-aware status + restart routes` | `QwenAgent.getMcpPoolAccounting` extMethod; `httpAcpBridge.buildWorkspaceMcpStatus` pool-first + bootstrap-session fallback; `restartMcpServer` accepts `?entryIndex=` and returns `RestartResult[]`; `entryCount` + `entrySummary[].entryIndex` on cell; capability tags `mcp_workspace_pool` + `mcp_pool_restart`. | `httpAcpBridge.ts`, `capabilities.ts`, SDK types |
|
||||
| 6 | `feat(serve): graduate MCP budget guardrails to workspace scope` | Move `tryReserveSlot`/`releaseSlotName`/hysteresis state machine from `McpClientManager` to pool; remove per-session `setMcpBudgetEventCallback` wiring in `acpAgent.newSessionConfig`; `QwenAgent.broadcastBudgetEvent` fan-out; snapshot cell `scope: 'workspace'`; SDK `scope?` additive field; `isWorkspaceScopedBudgetEvent` helper; inline doc updates. | `mcp-transport-pool.ts`, `mcp-client-manager.ts`, `acpAgent.ts`, `httpAcpBridge.ts`, SDK |
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ Use these anchors when moving from the docs into the latest `main` code:
|
|||
|
||||
| Surface | Implementation anchors | Primary docs |
|
||||
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| Bootstrap and HTTP assembly | `packages/cli/src/serve/runQwenServe.ts`, `server.ts`, `/demo` | [`02`](./02-serve-runtime.md), [`20`](./20-quickstart-operations.md) |
|
||||
| Bootstrap and HTTP assembly | `packages/cli/src/serve/run-qwen-serve.ts`, `server.ts`, `/demo` | [`02`](./02-serve-runtime.md), [`20`](./20-quickstart-operations.md) |
|
||||
| ACP bridge and session multiplexing | `packages/acp-bridge/src/bridge.ts`, `packages/acp-bridge/src/bridgeTypes.ts`, `@qwen-code/acp-bridge` | [`03`](./03-acp-bridge.md), [`08`](./08-session-lifecycle.md) |
|
||||
| Permission mediation | `packages/acp-bridge/src/permissionMediator.ts`, `fromLoopback: boolean`, `policy.*` | [`04`](./04-permission-mediation.md), [`12`](./12-auth-security.md) |
|
||||
| MCP transport pool | `packages/core/src/tools/mcp-transport-pool.ts`, `mcp-pool-key.ts`, `pid-descendants.ts`, `session-mcp-view.ts`, `/mcp refresh`, `MCPCallInterruptedError` | [`05`](./05-mcp-transport-pool.md), [`06`](./06-mcp-budget-guardrails.md) |
|
||||
|
|
@ -94,7 +94,7 @@ Use these anchors when moving from the docs into the latest `main` code:
|
|||
| Event schema and SSE writer | `packages/sdk-typescript/src/daemon/events.ts`, `packages/cli/src/serve/server.ts`, `formatSseFrame`, `packages/cli/src/acp-integration/session/emitters/ToolCallEmitter.ts`, `ToolCallEmitter.resolveToolProvenance`, `tool_call.provenance`, `serverId` | [`09`](./09-event-schema.md), [`10`](./10-event-bus.md) |
|
||||
| Event resync | `state_resync_required`, `awaitingResync`, `RESYNC_PASSTHROUGH_TYPES`, `asKnownDaemonEvent`, `unrecognizedKnownEventCount` | [`09`](./09-event-schema.md), [`10`](./10-event-bus.md) |
|
||||
| Capabilities | `packages/cli/src/serve/capabilities.ts`, `mcp_server_restart_refused.reason`, `MCP_RESTART_REFUSED_REASONS.has` | [`11`](./11-capabilities-versioning.md) |
|
||||
| Auth and device flow | `packages/cli/src/serve/auth.ts`, `packages/cli/src/serve/auth/deviceFlow.ts` | [`12`](./12-auth-security.md) |
|
||||
| Auth and device flow | `packages/cli/src/serve/auth.ts`, `packages/cli/src/serve/auth/device-flow.ts` | [`12`](./12-auth-security.md) |
|
||||
| TypeScript SDK daemon client | `packages/sdk-typescript/src/daemon/{DaemonClient,DaemonSessionClient,DaemonAuthFlow,sse,events,types}.ts`, `MCP_RESTART_DEFAULT_TIMEOUT_MS` | [`13`](./13-sdk-daemon-client.md) |
|
||||
| Shared UI transcript layer | `DaemonUiEventType`, `DaemonSessionProvider`, `packages/webui/src/daemon/` | [`13`](./13-sdk-daemon-client.md), [`14`](./14-cli-tui-adapter.md), [`../daemon-ui/README.md`](../daemon-ui/README.md) |
|
||||
| Channels and IDE adapters | `packages/channels/`, `packages/vscode-ide-companion/src/services/daemonIdeConnection.ts` | [`15`](./15-channel-adapters.md), [`16`](./16-vscode-ide-adapter.md) |
|
||||
|
|
@ -152,7 +152,7 @@ Use these anchors when moving from the docs into the latest `main` code:
|
|||
| Surface | Status |
|
||||
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
|
||||
| `docs/developers/daemon-client-adapters/tui.md` | Historical draft for the old `DaemonTuiAdapter` spike; current shared UI transcript architecture is in doc 14. |
|
||||
| `packages/cli/src/ui/daemon/DaemonTuiAdapter.ts` | Legacy experimental adapter still in-tree. New shared UI work should prefer SDK `daemon/ui/*`. |
|
||||
| `packages/cli/src/ui/daemon/daemon-tui-adapter.ts` | Legacy experimental adapter still in-tree. New shared UI work should prefer SDK `daemon/ui/*`. |
|
||||
| `--no-http-bridge` | Accepted for compatibility but falls back to http-bridge and prints stderr. |
|
||||
|
||||
### Forward compatibility
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ The daemon process and the ACP child are connected by an `AcpChannel` (default:
|
|||
```mermaid
|
||||
flowchart TB
|
||||
subgraph serve["packages/cli/src/serve"]
|
||||
RQS["runQwenServe.ts<br/>(bootstrap)"]
|
||||
RQS["run-qwen-serve.ts<br/>(bootstrap)"]
|
||||
SRV["server.ts (Express)"]
|
||||
CAP["capabilities.ts"]
|
||||
AUTH["auth.ts"]
|
||||
FSM["fs/ (sandbox)"]
|
||||
DSP["daemonStatusProvider.ts"]
|
||||
DSP["daemon-status-provider.ts"]
|
||||
end
|
||||
|
||||
subgraph br["packages/acp-bridge"]
|
||||
|
|
@ -99,7 +99,7 @@ flowchart TB
|
|||
|
||||
subgraph adapters["Adapters"]
|
||||
WUIP["webui/src/daemon/<br/>DaemonSessionProvider.tsx"]
|
||||
TUIA["cli/src/ui/daemon/<br/>DaemonTuiAdapter.ts"]
|
||||
TUIA["cli/src/ui/daemon/<br/>daemon-tui-adapter.ts"]
|
||||
CHB["channels/base/<br/>DaemonChannelBridge.ts"]
|
||||
DT["channels/dingtalk"]
|
||||
WX["channels/weixin"]
|
||||
|
|
@ -327,7 +327,7 @@ The two-phase shutdown matters because in-flight HTTP requests, in-flight SSE su
|
|||
|
||||
| Concern | File |
|
||||
| -------------------- | ----------------------------------------------------------- |
|
||||
| Bootstrap | `packages/cli/src/serve/runQwenServe.ts` |
|
||||
| Bootstrap | `packages/cli/src/serve/run-qwen-serve.ts` |
|
||||
| Express app | `packages/cli/src/serve/server.ts` |
|
||||
| Capability registry | `packages/cli/src/serve/capabilities.ts` |
|
||||
| Auth middleware | `packages/cli/src/serve/auth.ts` |
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
## Architecture
|
||||
|
||||
**Entry**: `runQwenServe(opts, deps)` in `packages/cli/src/serve/runQwenServe.ts`. Returns a `RunHandle` (`{ url, port, close, ... }`).
|
||||
**Entry**: `runQwenServe(opts, deps)` in `packages/cli/src/serve/run-qwen-serve.ts`. Returns a `RunHandle` (`{ url, port, close, ... }`).
|
||||
|
||||
**App factory**: `createServeApp(opts, getPort, deps)` in `packages/cli/src/serve/server.ts`. Builds the Express `Application`. Direct embedders and tests call it without the bootstrap wrapper.
|
||||
|
||||
|
|
@ -40,20 +40,20 @@
|
|||
| Path | Role |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `serve/fs/` | `WorkspaceFileSystem` factory plus `policy.ts` (size/trust/binary checks), `paths.ts` (canonicalize, resolveWithin, symlink rejection), `audit.ts`, and typed `FsError` values. |
|
||||
| `serve/routes/workspaceFileRead.ts`, `workspaceFileWrite.ts` | HTTP handlers for `GET /file`, `GET /file/bytes`, `POST /file/write`, and `POST /file/edit`. |
|
||||
| `serve/workspaceMemory.ts` | `GET/POST /workspace/memory` (QWEN.md CRUD). |
|
||||
| `serve/workspaceAgents.ts` | `GET/POST/DELETE /workspace/agents` (subagent CRUD). |
|
||||
| `serve/daemonStatusProvider.ts` | Env snapshot plus daemon-host preflight cells: Node version, CLI entry, workspace stat, ripgrep, git, npm. |
|
||||
| `serve/permissionAudit.ts` | `PermissionAuditRing` (512-entry FIFO) and `createPermissionAuditPublisher`. |
|
||||
| `serve/auth/deviceFlow.ts`, `qwenDeviceFlowProvider.ts` | Device-flow OAuth routes. See [`12-auth-security.md`](./12-auth-security.md). |
|
||||
| `serve/routes/workspace-file-read.ts`, `workspace-file-write.ts` | HTTP handlers for `GET /file`, `GET /file/bytes`, `POST /file/write`, and `POST /file/edit`. |
|
||||
| `serve/workspace-memory.ts` | `GET/POST /workspace/memory` (QWEN.md CRUD). |
|
||||
| `serve/workspace-agents.ts` | `GET/POST/DELETE /workspace/agents` (subagent CRUD). |
|
||||
| `serve/daemon-status-provider.ts` | Env snapshot plus daemon-host preflight cells: Node version, CLI entry, workspace stat, ripgrep, git, npm. |
|
||||
| `serve/permission-audit.ts` | `PermissionAuditRing` (512-entry FIFO) and `createPermissionAuditPublisher`. |
|
||||
| `serve/auth/device-flow.ts`, `qwen-device-flow-provider.ts` | Device-flow OAuth routes. See [`12-auth-security.md`](./12-auth-security.md). |
|
||||
| `serve/daemonLogger.ts` | `DaemonLogger` structured file logs. See [`19-observability.md`](./19-observability.md). |
|
||||
| `serve/debugMode.ts` | Shared `isServeDebugMode()` predicate controlling verbose error context in HTTP responses. |
|
||||
| `serve/debug-mode.ts` | Shared `isServeDebugMode()` predicate controlling verbose error context in HTTP responses. |
|
||||
| `serve/acpHttp/` | ACP Streamable HTTP transport (RFD #721), mounted at `/acp`. Seven files implement JSON-RPC POST, SSE GET, DELETE teardown, and shared bridge usage in parallel with the REST surface. |
|
||||
| `serve/demo.ts` | Self-contained inline HTML for `GET /demo`: browser debug console with chat UI, event log, and workspace inspector. On loopback without `--require-auth`, it is registered **before** `bearerAuth`; on non-loopback or with `--require-auth`, it is registered **after** `bearerAuth`. Served with CSP `default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'` plus `X-Frame-Options: DENY`. |
|
||||
|
||||
**Re-export shims** for compatibility with pre-F1 import paths:
|
||||
|
||||
- `serve/eventBus.ts` -> `@qwen-code/acp-bridge/eventBus`
|
||||
- `serve/event-bus.ts` -> `@qwen-code/acp-bridge/eventBus`
|
||||
- `serve/status.ts` -> `@qwen-code/acp-bridge/status`
|
||||
- `serve/httpAcpBridge.ts` -> `@qwen-code/acp-bridge`
|
||||
|
||||
|
|
@ -144,12 +144,12 @@ See [`17-configuration.md`](./17-configuration.md) for the merged reference.
|
|||
|
||||
## References
|
||||
|
||||
- `packages/cli/src/serve/runQwenServe.ts` (bootstrap, boot validation, graceful shutdown)
|
||||
- `packages/cli/src/serve/run-qwen-serve.ts` (bootstrap, boot validation, graceful shutdown)
|
||||
- `packages/cli/src/serve/server.ts` (`createServeApp()`, middleware and route assembly)
|
||||
- `packages/cli/src/serve/auth.ts` (CORS, Host allowlist, bearer auth, mutation gate)
|
||||
- `packages/cli/src/serve/rateLimit.ts` (per-tier HTTP rate limit)
|
||||
- `packages/cli/src/serve/rate-limit.ts` (per-tier HTTP rate limit)
|
||||
- `packages/cli/src/serve/capabilities.ts` (capability registry and conditional advertisement)
|
||||
- `packages/cli/src/serve/types.ts` (`ServeOptions`, `CapabilitiesEnvelope`)
|
||||
- `packages/cli/src/serve/daemonStatusProvider.ts`
|
||||
- `packages/cli/src/serve/permissionAudit.ts`
|
||||
- `packages/cli/src/serve/daemon-status-provider.ts`
|
||||
- `packages/cli/src/serve/permission-audit.ts`
|
||||
- Issues: [#3803](https://github.com/QwenLM/qwen-code/issues/3803), [#4175](https://github.com/QwenLM/qwen-code/issues/4175)
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ context threaded through bridge calls; it carries `clientId`,
|
|||
- `MCP_RESTART_TIMEOUT_MS = 300_000` (5 min) — the bridge timeout for `/workspace/mcp/:server/restart` is intentionally large because `McpClientManager.MAX_DISCOVERY_TIMEOUT_MS` can be up to 5 min for stdio servers. A shorter deadline would produce false timeouts while the ACP child kept reconnecting in the background.
|
||||
- `BridgeOptions.eventRingSize > 1_000_000` throws at construction.
|
||||
- `connection.unstable_resumeSession` is exposed through the stable `session_resume` daemon capability; `unstable_session_resume` remains advertised as a deprecated compatibility alias for older SDKs. Clients should feature-detect `session_resume`.
|
||||
- The bridge package is `@qwen-code/acp-bridge` and is consumed through re-export shims in `serve/eventBus.ts`, `serve/status.ts`, `serve/httpAcpBridge.ts` for backward compatibility with pre-F1 import paths. New code should import directly.
|
||||
- The bridge package is `@qwen-code/acp-bridge` and is consumed through re-export shims in `serve/event-bus.ts`, `serve/status.ts`, `serve/httpAcpBridge.ts` for backward compatibility with pre-F1 import paths. New code should import directly.
|
||||
|
||||
## References
|
||||
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ unanimity for M = 4, use the same field.
|
|||
## Boot-time policy validation
|
||||
|
||||
`runQwenServe.validatePolicyConfig(policyConfig)`
|
||||
(`packages/cli/src/serve/runQwenServe.ts`) validates merged `settings.json`
|
||||
(`packages/cli/src/serve/run-qwen-serve.ts`) validates merged `settings.json`
|
||||
`policy.*` at boot and throws `InvalidPolicyConfigError` for operator mistakes:
|
||||
|
||||
- `policy.permissionStrategy` is set but not in the four supported modes. The
|
||||
|
|
@ -270,5 +270,5 @@ mechanism does not exist in v1.
|
|||
- `packages/acp-bridge/src/permissionMediator.ts` (F3 mediator implementation)
|
||||
- `packages/acp-bridge/src/bridgeClient.ts` (uses structural sub-typing on `PermissionMediator`)
|
||||
- `packages/acp-bridge/src/bridgeErrors.ts` (`CancelSentinelCollisionError`, `InvalidPermissionOptionError`, `PermissionForbiddenError`)
|
||||
- `packages/cli/src/serve/permissionAudit.ts` (audit ring + publisher)
|
||||
- `packages/cli/src/serve/permission-audit.ts` (audit ring + publisher)
|
||||
- Issue: [#4175](https://github.com/QwenLM/qwen-code/issues/4175) F3 series.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ The HTTP file routes (`GET /file`, `GET /file/bytes`, `POST /file/write`, `POST
|
|||
| `policy.ts` | `MAX_READ_BYTES`, `MAX_WRITE_BYTES`, `BINARY_PROBE_BYTES`, `assertTrustedForIntent`, `detectBinary`, `enforceReadBytesSize`, `enforceReadSize`, `enforceWriteSize`, `shouldIgnore`. |
|
||||
| `audit.ts` | `FS_ACCESS_EVENT_TYPE`, `FS_DENIED_EVENT_TYPE`, `createAuditPublisher`, audit payload types. |
|
||||
| `errors.ts` | `FsError` class, `isFsError`, `FsErrorKind` union (14 kinds), `FsErrorStatus` union (`400 / 403 / 404 / 409 / 413 / 422 / 500 / 503`). |
|
||||
| `workspaceFileSystem.ts` | `createWorkspaceFileSystemFactory`, `WorkspaceFileSystem` (the orchestrator that reads/writes/lists), `WriteMode`, `ContentHash`, `FsEntry`, `FsStat`, `ListOptions`, `GlobOptions`, `ReadTextOptions`, `ReadBytesOptions`, `WriteTextAtomicOptions`. |
|
||||
| `workspace-file-system.ts` | `createWorkspaceFileSystemFactory`, `WorkspaceFileSystem` (the orchestrator that reads/writes/lists), `WriteMode`, `ContentHash`, `FsEntry`, `FsStat`, `ListOptions`, `GlobOptions`, `ReadTextOptions`, `ReadBytesOptions`, `WriteTextAtomicOptions`. |
|
||||
|
||||
### `FsErrorKind` taxonomy
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ interface BridgeFileSystem {
|
|||
}
|
||||
```
|
||||
|
||||
This is the injection point for ACP `readTextFile` / `writeTextFile`. Bridge tests and Mode A embedded callers can omit it on `BridgeOptions`; `BridgeClient` falls back to its inline `fs.readFile` / `fs.writeFile` proxy (preserves pre-F1 behavior). Production `qwen serve` wires `BridgeFileSystem` through `createBridgeFileSystemAdapter(fsFactory)` (`packages/cli/src/serve/bridgeFileSystemAdapter.ts`) so agent-side ACP writes pick up the same TOCTOU, symlink, trust-gate, and audit gates the HTTP routes use.
|
||||
This is the injection point for ACP `readTextFile` / `writeTextFile`. Bridge tests and Mode A embedded callers can omit it on `BridgeOptions`; `BridgeClient` falls back to its inline `fs.readFile` / `fs.writeFile` proxy (preserves pre-F1 behavior). Production `qwen serve` wires `BridgeFileSystem` through `createBridgeFileSystemAdapter(fsFactory)` (`packages/cli/src/serve/bridge-file-system-adapter.ts`) so agent-side ACP writes pick up the same TOCTOU, symlink, trust-gate, and audit gates the HTTP routes use.
|
||||
|
||||
Two defensive gates the adapter MUST replicate (because the inline proxy is fully bypassed when the adapter is injected):
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ flowchart LR
|
|||
- `@qwen-code/qwen-code-core` — `Ignore`, `isBinaryFile`, `Config.isTrustedFolder()`.
|
||||
- `node:fs`, `node:path`, `node:crypto`.
|
||||
- `@qwen-code/acp-bridge` — `BridgeFileSystem` contract on the ACP side.
|
||||
- HTTP routes: `packages/cli/src/serve/routes/workspaceFileRead.ts`, `workspaceFileWrite.ts`.
|
||||
- HTTP routes: `packages/cli/src/serve/routes/workspace-file-read.ts`, `workspace-file-write.ts`.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
|
@ -239,7 +239,7 @@ flowchart LR
|
|||
- `packages/cli/src/serve/fs/policy.ts`
|
||||
- `packages/cli/src/serve/fs/errors.ts`
|
||||
- `packages/cli/src/serve/fs/audit.ts`
|
||||
- `packages/cli/src/serve/fs/workspaceFileSystem.ts`
|
||||
- `packages/cli/src/serve/bridgeFileSystemAdapter.ts`
|
||||
- `packages/cli/src/serve/fs/workspace-file-system.ts`
|
||||
- `packages/cli/src/serve/bridge-file-system-adapter.ts`
|
||||
- `packages/acp-bridge/src/bridgeFileSystem.ts`
|
||||
- HTTP route reference: [`../qwen-serve-protocol.md`](../qwen-serve-protocol.md).
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ Already-aborted signals at subscribe time call `onAbort()` synchronously before
|
|||
|
||||
- Consumed by `packages/acp-bridge/src/bridge.ts` (`BridgeClient.sessionUpdate` / `BridgeClient.extNotification` → `events.publish(...)`).
|
||||
- Consumed by `packages/cli/src/serve/server.ts` (SSE route handler → `events.subscribe(...)` then formats `BridgeEvent` to SSE wire frames).
|
||||
- Re-export shim: `packages/cli/src/serve/eventBus.ts` → `@qwen-code/acp-bridge/eventBus`.
|
||||
- Re-export shim: `packages/cli/src/serve/event-bus.ts` → `@qwen-code/acp-bridge/eventBus`.
|
||||
- SDK consumer: `packages/sdk-typescript/src/daemon/sse.ts` (`parseSseStream`), then `asKnownDaemonEvent` (see [`09-event-schema.md`](./09-event-schema.md), [`13-sdk-daemon-client.md`](./13-sdk-daemon-client.md)).
|
||||
|
||||
## Configuration
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ This doc walks through each layer and the explicit invariants the boot path enfo
|
|||
|
||||
### Boot-time refuse rules
|
||||
|
||||
In `runQwenServe.ts`:
|
||||
In `run-qwen-serve.ts`:
|
||||
|
||||
```ts
|
||||
if (!isLoopbackBind(opts.hostname) && !token) {
|
||||
|
|
@ -180,10 +180,10 @@ Separate OAuth surface for provider authentication (Qwen OAuth, etc.):
|
|||
|
||||
SSE events `auth_device_flow_{started, throttled, authorized, failed, cancelled}` fan-out flow state to all subscribers so multi-client UIs stay in sync. See [`09-event-schema.md`](./09-event-schema.md).
|
||||
|
||||
Implementation: `packages/cli/src/serve/auth/deviceFlow.ts` + `qwenDeviceFlowProvider.ts`.
|
||||
Implementation: `packages/cli/src/serve/auth/device-flow.ts` + `qwen-device-flow-provider.ts`.
|
||||
|
||||
**Log injection / Trojan Source defense**: `sanitizeForStderr(value)`
|
||||
(`deviceFlow.ts`) replaces ASCII control characters and Unicode control
|
||||
(`device-flow.ts`) replaces ASCII control characters and Unicode control
|
||||
characters with `?`. A malicious IdP could otherwise forge log lines or hide
|
||||
payloads:
|
||||
|
||||
|
|
@ -269,8 +269,8 @@ sequenceDiagram
|
|||
## Dependencies
|
||||
|
||||
- `node:crypto` — `createHash`, `timingSafeEqual`.
|
||||
- `packages/cli/src/serve/loopbackBinds.ts` — `isLoopbackBind`.
|
||||
- `packages/cli/src/serve/auth/deviceFlow.ts` — device-flow state machine.
|
||||
- `packages/cli/src/serve/loopback-binds.ts` — `isLoopbackBind`.
|
||||
- `packages/cli/src/serve/auth/device-flow.ts` — device-flow state machine.
|
||||
- `@qwen-code/acp-bridge` — surfaces device-flow events on the per-session SSE bus.
|
||||
|
||||
## Configuration
|
||||
|
|
@ -295,9 +295,9 @@ sequenceDiagram
|
|||
## References
|
||||
|
||||
- `packages/cli/src/serve/auth.ts` (entire file)
|
||||
- `packages/cli/src/serve/runQwenServe.ts` (refuse rules)
|
||||
- `packages/cli/src/serve/loopbackBinds.ts`
|
||||
- `packages/cli/src/serve/auth/deviceFlow.ts`
|
||||
- `packages/cli/src/serve/auth/qwenDeviceFlowProvider.ts`
|
||||
- `packages/cli/src/serve/run-qwen-serve.ts` (refuse rules)
|
||||
- `packages/cli/src/serve/loopback-binds.ts`
|
||||
- `packages/cli/src/serve/auth/device-flow.ts`
|
||||
- `packages/cli/src/serve/auth/qwen-device-flow-provider.ts`
|
||||
- User-facing threat model: [`../../users/qwen-serve.md`](../../users/qwen-serve.md).
|
||||
- Wire reference: [`../qwen-serve-protocol.md`](../qwen-serve-protocol.md).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Shared UI Transcript Layer
|
||||
|
||||
> **Current status**: `packages/cli/src/ui/daemon/DaemonTuiAdapter.ts` is still present on `main` as a legacy experimental CLI-side adapter. This document describes the newer SDK-side shared UI transcript layer: reusable daemon event normalization and transcript primitives that any UI host can consume, including Web, TUI, IDE, and IM channels. CLI TUI, channel, and VS Code IDE migrations are follow-up work.
|
||||
> **Current status**: `packages/cli/src/ui/daemon/daemon-tui-adapter.ts` is still present on `main` as a legacy experimental CLI-side adapter. This document describes the newer SDK-side shared UI transcript layer: reusable daemon event normalization and transcript primitives that any UI host can consume, including Web, TUI, IDE, and IM channels. CLI TUI, channel, and VS Code IDE migrations are follow-up work.
|
||||
|
||||
## Overview
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ The web UI can now connect directly to daemon HTTP+SSE and render a transcript.
|
|||
|
||||
[`../daemon-ui/MIGRATION.md`](../daemon-ui/MIGRATION.md) provides a v2 incremental guide for web chat and web terminal adapters. It explicitly calls out that **CLI TUI, channel base, and VS Code IDE are not migrated by that PR**; each will move in follow-up PRs and use the conformance suite to preserve rendering parity.
|
||||
|
||||
## Relationship to legacy `DaemonTuiAdapter.ts`
|
||||
## Relationship to legacy `daemon-tui-adapter.ts`
|
||||
|
||||
| Dimension | Legacy CLI `DaemonTuiAdapter` | New shared transcript layer |
|
||||
| ----------------- | --------------------------------------------------------------- | -------------------------------------------------------------- |
|
||||
|
|
@ -175,7 +175,7 @@ The web UI can now connect directly to daemon HTTP+SSE and render a transcript.
|
|||
|
||||
## Caveats and known limits
|
||||
|
||||
- **`DaemonTuiAdapter.ts` still exists**. It is the CLI package's legacy experimental adapter. New code should prefer SDK `ui/*`: `normalizeDaemonEvent`, `reduceDaemonTranscriptEvents`, and `DaemonTranscriptBlock`.
|
||||
- **`daemon-tui-adapter.ts` still exists**. It is the CLI package's legacy experimental adapter. New code should prefer SDK `ui/*`: `normalizeDaemonEvent`, `reduceDaemonTranscriptEvents`, and `DaemonTranscriptBlock`.
|
||||
- **CLI TUI, channel base, and VS Code IDE are not migrated yet**. They still maintain their own rendering logic. The `docs/developers/daemon-client-adapters/` directory still has `ide.md`, `channel-web.md`, and the historical `tui.md` draft; the newer `web-ui.md` covers the web UI adapter design.
|
||||
- **`eventId` is the primary ordering key**. `createdAt` remains as a deprecated alias (`clientReceivedAt`). New code should use `selectTranscriptBlocksOrderedByEventId(state)`. `MIGRATION.md` shows the code diff for switching from `createdAt` ordering to `eventId` ordering.
|
||||
- **Unknown wire types normalize to `debug`**. They are no longer dropped as in the old adapter. Renderers do not show `debug` by default; hosts must opt in to display it.
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ The daemon reads settings once at boot through `loadSettings(boundWorkspace)` in
|
|||
| `DEFAULT_MAX_PENDING_PER_SESSION` | `bridge.ts` | `64` | Aligned with `DEFAULT_MAX_SUBSCRIBERS`. |
|
||||
| `MAX_RESOLVED_PERMISSION_RECORDS` | `permissionMediator.ts` | `512` | FIFO for recently resolved permissions. |
|
||||
| `KILL_HARD_DEADLINE_MS` | `spawnChannel.ts` | `10_000` | Per-channel graceful shutdown window. |
|
||||
| `SHUTDOWN_FORCE_CLOSE_MS` | `runQwenServe.ts` | `5_000` | HTTP server force-close timer. |
|
||||
| `SHUTDOWN_FORCE_CLOSE_MS` | `run-qwen-serve.ts` | `5_000` | HTTP server force-close timer. |
|
||||
| `MAX_READ_BYTES` | `fs/policy.ts` | `256 * 1024` | Read cap. |
|
||||
| `MAX_WRITE_BYTES` | `fs/policy.ts` | `5 * 1024 * 1024` | Write cap. |
|
||||
| `MAX_DISPLAY_NAME_LENGTH` | `bridge.ts` | `256` | Session `displayName` cap. |
|
||||
|
|
|
|||
|
|
@ -60,13 +60,13 @@ Typed classes thrown by the bridge / mediator. Most carry an HTTP status via the
|
|||
| `BridgeTimeoutError` | 504 | Bridge-level wallclock exceeded. | Retry; investigate underlying slowness. |
|
||||
| `MissingCliEntryError` | 500 | The `qwen` CLI entry file is missing (defined in `status.ts`, not `bridgeErrors.ts`). | Confirm the CLI install is complete; check that `packages/cli/index.ts` exists. |
|
||||
|
||||
## Boot-time configuration errors (`packages/cli/src/serve/runQwenServe.ts`)
|
||||
## Boot-time configuration errors (`packages/cli/src/serve/run-qwen-serve.ts`)
|
||||
|
||||
| Class | When | Remediation |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `InvalidPolicyConfigError` | `validatePolicyConfig()` rejects merged settings: unknown `policy.permissionStrategy` (validated against `SERVE_CAPABILITY_REGISTRY.permission_mediation.modes`) or non-positive-integer `policy.consensusQuorum`. Boot fails explicitly. | Fix the offending field in `settings.json`. The class supports `instanceof`; `runQwenServe` uses it to distinguish policy mismatch from settings read I/O failures, which fall back to defaults. |
|
||||
|
||||
## Device Flow auth (`packages/cli/src/serve/auth/deviceFlow.ts`)
|
||||
## Device Flow auth (`packages/cli/src/serve/auth/device-flow.ts`)
|
||||
|
||||
| Class | When | Notes |
|
||||
| ---------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
| `/workspace/skills`, `/workspace/providers` | Routes | ACP-side live snapshots; return empty idle data when no session exists. |
|
||||
| Per-session SSE | `GET /session/:id/events` | Real-time event stream. |
|
||||
| `/demo` debug console | `GET /demo` (`packages/cli/src/serve/demo.ts`) | Browser-accessible single-page console: chat, event log, workspace inspector, and permission UX. On loopback, `http://127.0.0.1:4170/demo` is the quickest end-to-end validation path without writing SDK code. Registration rules are in [`02-serve-runtime.md`](./02-serve-runtime.md). |
|
||||
| `PermissionAuditRing` | `permissionAudit.ts` | In-memory FIFO of 512 permission decisions. |
|
||||
| `PermissionAuditRing` | `permission-audit.ts` | In-memory FIFO of 512 permission decisions. |
|
||||
| Mediator `decisionReason` audit | `permissionMediator.ts` | Internal structured record explaining why a permission request resolved the way it did. |
|
||||
|
||||
## What does not exist today
|
||||
|
|
@ -110,7 +110,7 @@ flowchart TD
|
|||
|
||||
## State and lifecycle
|
||||
|
||||
- `QWEN_SERVE_DEBUG` is read on every check through `isServeDebugMode()` from `debugMode.ts`; toggling it does not require restart. Boot logs are not available unless the env was set at boot.
|
||||
- `QWEN_SERVE_DEBUG` is read on every check through `isServeDebugMode()` from `debug-mode.ts`; toggling it does not require restart. Boot logs are not available unless the env was set at boot.
|
||||
- `PermissionAuditRing` is bounded at 512 FIFO entries; older records are silently dropped.
|
||||
- `DaemonStatusProvider` rebuilds cells per request and does not cache; avoid unnecessary high-frequency polling.
|
||||
|
||||
|
|
@ -142,9 +142,9 @@ flowchart TD
|
|||
|
||||
## References
|
||||
|
||||
- `packages/cli/src/serve/daemonStatusProvider.ts`
|
||||
- `packages/cli/src/serve/daemon-status-provider.ts`
|
||||
- `packages/cli/src/serve/daemonLogger.ts` (`DaemonLogger`, `buildDaemonLogLine`)
|
||||
- `packages/cli/src/serve/debugMode.ts` (`isServeDebugMode`)
|
||||
- `packages/cli/src/serve/debug-mode.ts` (`isServeDebugMode`)
|
||||
- `packages/acp-bridge/src/permissionMediator.ts` (`PermissionDecisionReason`)
|
||||
- `packages/cli/src/serve/server.ts` (`daemonTelemetryMiddleware`, access-log middleware)
|
||||
- Configuration: [`17-configuration.md`](./17-configuration.md)
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ Settings I/O failure, such as malformed JSON, falls back to defaults. `InvalidPo
|
|||
|
||||
## 6. Boot refusal scenarios (explicit failures)
|
||||
|
||||
`runQwenServe.ts` intentionally throws instead of falling back in these cases:
|
||||
`run-qwen-serve.ts` intentionally throws instead of falling back in these cases:
|
||||
|
||||
| Scenario | Error prefix |
|
||||
| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
|
|
@ -232,7 +232,7 @@ commands/serve.ts const { runQwenServe } = await import('../ser
|
|||
commands/serve.ts await runQwenServe({...})
|
||||
|
|
||||
v
|
||||
serve/runQwenServe.ts runQwenServe(opts, deps)
|
||||
serve/run-qwen-serve.ts runQwenServe(opts, deps)
|
||||
| |- trim token
|
||||
| |- hostname mismatch fallback
|
||||
| |- auth preflight
|
||||
|
|
@ -244,7 +244,7 @@ serve/runQwenServe.ts runQwenServe(opts, deps)
|
|||
| `- createHttpAcpBridge({...})
|
||||
|
|
||||
v
|
||||
serve/runQwenServe.ts const app = createServeApp(opts, () => actualPort, {...})
|
||||
serve/run-qwen-serve.ts const app = createServeApp(opts, () => actualPort, {...})
|
||||
|
|
||||
v
|
||||
serve/server.ts createServeApp() - builds Express app (**does not listen**)
|
||||
|
|
@ -253,7 +253,7 @@ serve/server.ts createServeApp() - builds Express app (**does
|
|||
| `- return app
|
||||
|
|
||||
v
|
||||
serve/runQwenServe.ts server = app.listen(port, hostname, cb)
|
||||
serve/run-qwen-serve.ts server = app.listen(port, hostname, cb)
|
||||
| |- server.maxConnections = cap
|
||||
| |- actualPort = server.address().port
|
||||
| |- write "qwen serve listening on ..."
|
||||
|
|
@ -277,10 +277,10 @@ The main assembly happens in `createServeApp()` in `server.ts`, which mounts fou
|
|||
| Routes | File | Mounting entry |
|
||||
| ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------- |
|
||||
| `/health`, `/demo`, `/capabilities`, all session routes, device flow, permission vote, SSE, and single-server MCP restart | `packages/cli/src/serve/server.ts` | Registered directly inside `createServeApp()` |
|
||||
| `/workspace/memory` (GET/POST) | `packages/cli/src/serve/workspaceMemory.ts` | `mountWorkspaceMemoryRoutes()` |
|
||||
| All `/workspace/agents` CRUD routes | `packages/cli/src/serve/workspaceAgents.ts` | `mountWorkspaceAgentsRoutes()` |
|
||||
| `GET /file`, `/file/bytes`, `/list`, `/glob`, `/stat` | `packages/cli/src/serve/routes/workspaceFileRead.ts` | `registerWorkspaceFileReadRoutes()` |
|
||||
| `POST /file/write`, `/file/edit` | `packages/cli/src/serve/routes/workspaceFileWrite.ts` | `registerWorkspaceFileWriteRoutes()` |
|
||||
| `/workspace/memory` (GET/POST) | `packages/cli/src/serve/workspace-memory.ts` | `mountWorkspaceMemoryRoutes()` |
|
||||
| All `/workspace/agents` CRUD routes | `packages/cli/src/serve/workspace-agents.ts` | `mountWorkspaceAgentsRoutes()` |
|
||||
| `GET /file`, `/file/bytes`, `/list`, `/glob`, `/stat` | `packages/cli/src/serve/routes/workspace-file-read.ts` | `registerWorkspaceFileReadRoutes()` |
|
||||
| `POST /file/write`, `/file/edit` | `packages/cli/src/serve/routes/workspace-file-write.ts` | `registerWorkspaceFileWriteRoutes()` |
|
||||
|
||||
For the complete route and wire protocol reference, see [`../qwen-serve-protocol.md`](../qwen-serve-protocol.md). For architecture, see [`01-architecture.md`](./01-architecture.md).
|
||||
|
||||
|
|
@ -361,7 +361,7 @@ QWEN_SERVE_DEBUG=1 qwen serve
|
|||
## References
|
||||
|
||||
- CLI entry: `packages/cli/src/commands/serve.ts`
|
||||
- Bootstrap: `packages/cli/src/serve/runQwenServe.ts`
|
||||
- Bootstrap: `packages/cli/src/serve/run-qwen-serve.ts`
|
||||
- Express factory: `packages/cli/src/serve/server.ts`
|
||||
- Middleware: `packages/cli/src/serve/auth.ts`
|
||||
- Bridge factory: `packages/acp-bridge/src/bridge.ts`
|
||||
|
|
|
|||
|
|
@ -1673,13 +1673,13 @@ The connection then closes.
|
|||
| Path | Purpose |
|
||||
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `packages/cli/src/commands/serve.ts` | yargs command + flag schema |
|
||||
| `packages/cli/src/serve/runQwenServe.ts` | listener lifecycle + signal handling |
|
||||
| `packages/cli/src/serve/run-qwen-serve.ts` | listener lifecycle + signal handling |
|
||||
| `packages/cli/src/serve/server.ts` | Express routes + middleware |
|
||||
| `packages/cli/src/serve/auth.ts` | bearer + Host allowlist + CORS deny |
|
||||
| `packages/cli/src/serve/httpAcpBridge.ts` | spawn-or-attach + per-session FIFO + permission registry |
|
||||
| `packages/cli/src/serve/status.ts` | read-only daemon status wire types + `ServeErrorKind` + `BridgeTimeoutError` + `mapDomainErrorToErrorKind` |
|
||||
| `packages/cli/src/serve/envSnapshot.ts` | pure helper that builds `/workspace/env` payloads from `process.*` state, including credential redaction |
|
||||
| `packages/cli/src/serve/eventBus.ts` | bounded async queue + replay ring |
|
||||
| `packages/cli/src/serve/env-snapshot.ts` | pure helper that builds `/workspace/env` payloads from `process.*` state, including credential redaction |
|
||||
| `packages/acp-bridge/src/eventBus.ts` | bounded async queue + replay ring |
|
||||
| `packages/sdk-typescript/src/daemon/DaemonClient.ts` | TS client |
|
||||
| `packages/sdk-typescript/src/daemon/sse.ts` | EventSource frame parser |
|
||||
| `integration-tests/cli/qwen-serve-routes.test.ts` | 18 cases, no LLM |
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ import { fileURLToPath } from 'node:url';
|
|||
import { afterAll, describe, expect, it } from 'vitest';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
import { EventBus } from '../../packages/cli/src/serve/eventBus.js';
|
||||
import { EventBus } from '../../packages/cli/src/serve/event-bus.js';
|
||||
import {
|
||||
spawnDaemon,
|
||||
startRssPolling,
|
||||
|
|
@ -528,7 +528,7 @@ async function measureRssAtSessionCount(sessionCount: number): Promise<{
|
|||
// doesn't take a sessionId in publish/subscribe — the bus instance
|
||||
// itself is per-session, owned upstream. We use it directly here for
|
||||
// deterministic backpressure invariants without needing a live HTTP
|
||||
// round-trip; pattern matches `packages/cli/src/serve/eventBus.test.ts`.
|
||||
// round-trip; pattern matches `packages/acp-bridge/src/eventBus.test.ts`.
|
||||
it('overflow at maxQueued boundary fires client_evicted', async () => {
|
||||
const bus = new EventBus();
|
||||
const ac = new AbortController();
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ Lift history (#4175 Mode B daemon roadmap):
|
|||
`maxSessions`, `eventRingSize`, `permissionResponseTimeoutMs`,
|
||||
persistence callbacks, etc.) plus the `DaemonStatusProvider`
|
||||
injection seam for daemon-host env / preflight cells (production
|
||||
impl in `cli/src/serve/daemonStatusProvider.ts`) and the F1
|
||||
impl in `cli/src/serve/daemon-status-provider.ts`) and the F1
|
||||
`BridgeFileSystem` injection seam for the ACP fs proxy.
|
||||
- `spawnChannel` (F1) — `defaultSpawnChannelFactory` + `killChild` +
|
||||
`SCRUBBED_CHILD_ENV_KEYS` denylist + `scrubChildEnv` pure env-policy
|
||||
|
|
@ -113,8 +113,8 @@ Both variants are stable across the F1 lift.
|
|||
|
||||
## Backward compatibility
|
||||
|
||||
`packages/cli/src/serve/eventBus.ts` and
|
||||
`packages/cli/src/serve/inMemoryChannel.ts` remain as one-line
|
||||
`packages/cli/src/serve/event-bus.ts` and
|
||||
`packages/cli/src/serve/in-memory-channel.ts` remain as one-line
|
||||
re-export wrappers, so every existing relative import inside
|
||||
`serve/` and the one external import in `cli/src/commands/serve.ts`
|
||||
keeps resolving without churn.
|
||||
|
|
@ -124,8 +124,8 @@ After F1, `packages/cli/src/serve/httpAcpBridge.ts` shrinks to a
|
|||
symbol (`createHttpAcpBridge`, `defaultSpawnChannelFactory`,
|
||||
`BridgeClient`, all the typed errors, all the type aliases) from
|
||||
the lifted subpaths. Every relative `./httpAcpBridge.js` import in
|
||||
`server.ts` / `runQwenServe.ts` / `workspaceAgents.ts` /
|
||||
`workspaceMemory.ts` / `index.ts` / the bridge test suite keeps
|
||||
`server.ts` / `run-qwen-serve.ts` / `workspace-agents.ts` /
|
||||
`workspace-memory.ts` / `index.ts` / the bridge test suite keeps
|
||||
resolving without any call-site changes.
|
||||
|
||||
## See also
|
||||
|
|
|
|||
|
|
@ -1033,7 +1033,7 @@ export function createAcpSessionBridge(opts: BridgeOptions): AcpSessionBridge {
|
|||
// Build the mediator before the BridgeClient so the agent's
|
||||
// `requestPermission` callback can hand the record straight in.
|
||||
// Audit publisher fallback: when the host doesn't supply one
|
||||
// (cli/serve/runQwenServe.ts wraps a real `PermissionAuditRing`
|
||||
// (cli/serve/run-qwen-serve.ts wraps a real `PermissionAuditRing`
|
||||
// backed publisher in production), we use the canonical no-op
|
||||
// fallback so the mediator can still run for embedded callers /
|
||||
// tests without an audit consumer.
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
*
|
||||
*
|
||||
* The bridge package owns the error contract directly. The
|
||||
* 7 error classes server.ts imports + 1 each from workspaceAgents.ts
|
||||
* and workspaceMemory.ts continue to resolve through the
|
||||
* 7 error classes server.ts imports + 1 each from workspace-agents.ts
|
||||
* and workspace-memory.ts continue to resolve through the
|
||||
* httpAcpBridge.ts re-export shim.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export type DiagnosticLineSink = (
|
|||
*
|
||||
* The bridge is intentionally agnostic about how its host computes
|
||||
* these cells; production `qwen serve` provides
|
||||
* `cli/src/serve/daemonStatusProvider.ts` which wraps
|
||||
* `cli/src/serve/daemon-status-provider.ts` which wraps
|
||||
* `buildEnvStatusFromProcess` + `buildDaemonPreflightCells`. Future
|
||||
* Mode A / in-process consumers may omit the provider entirely; the
|
||||
* bridge falls back to idle placeholders so `getWorkspaceEnvStatus`
|
||||
|
|
@ -254,7 +254,7 @@ export interface BridgeOptions {
|
|||
* status cells (env snapshot, daemon preflight). Production
|
||||
* `qwen serve` provides
|
||||
* `createDaemonStatusProvider()` from
|
||||
* `cli/src/serve/daemonStatusProvider.ts`.
|
||||
* `cli/src/serve/daemon-status-provider.ts`.
|
||||
*
|
||||
* **When omitted**: the bridge returns idle placeholders for
|
||||
* `getWorkspaceEnvStatus` (full envelope with empty `cells: []`
|
||||
|
|
@ -326,7 +326,7 @@ export interface BridgeOptions {
|
|||
* the bridge unit-test suite) can run the mediator without an
|
||||
* audit consumer.
|
||||
*
|
||||
* **In production** (`qwen serve`), `runQwenServe.ts` allocates a
|
||||
* **In production** (`qwen serve`), `run-qwen-serve.ts` allocates a
|
||||
* `PermissionAuditRing` (default capacity 512), wraps it with
|
||||
* `createPermissionAuditPublisher`, and passes the result here.
|
||||
* The ring stays alive for the lifetime of the daemon so a future
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ const WARN_RESET_RATIO = 0.375;
|
|||
* session from being opened thousands of times by an attacker to amplify
|
||||
* each `publish()` (which is O(N) over subscribers) into a CPU/memory
|
||||
* DoS. Daemon's HTTP listener also wants `server.maxConnections`
|
||||
* configured at the listener level — see `runQwenServe.ts`.
|
||||
* configured at the listener level — see `run-qwen-serve.ts`.
|
||||
*/
|
||||
const DEFAULT_MAX_SUBSCRIBERS = 64;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
* @internal
|
||||
*
|
||||
* Shared bridge test fixtures used by `bridge.test.ts` (acp-bridge
|
||||
* package) and `daemonStatusProvider.test.ts` (cli package). Extracted
|
||||
* package) and `daemon-status-provider.test.ts` (cli package). Extracted
|
||||
* so both suites can exercise the same
|
||||
* `FakeAgent` / `makeChannel` / `makeBridge` helpers without
|
||||
* cross-package duplication.
|
||||
|
|
@ -86,7 +86,7 @@ export const SESS_A = `sess:${WS_A}`;
|
|||
* Unlike the pre-split cli-side helper, this version does NOT default
|
||||
* `statusProvider` — that's a daemon-host-specific seam and
|
||||
* the acp-bridge tests exercise the no-provider fallback paths. The
|
||||
* cli-side `daemonStatusProvider.test.ts` defines its own wrapper that
|
||||
* cli-side `daemon-status-provider.test.ts` defines its own wrapper that
|
||||
* wires `createDaemonStatusProvider()` for the 4 daemon-host
|
||||
* integration tests.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ export type PermissionDecisionReason =
|
|||
|
||||
/**
|
||||
* Audit sink the mediator writes to. Implementation lives in
|
||||
* `packages/cli/src/serve/permissionAudit.ts` and writes into an
|
||||
* `packages/cli/src/serve/permission-audit.ts` and writes into an
|
||||
* in-memory bounded ring on the bridge — NOT onto the SSE bus
|
||||
* (audit records and SSE wire events are intentionally separate
|
||||
* channels by design).
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
* but the denylist still wins).
|
||||
* - An `overrides` map with `undefined` value silently failing to
|
||||
* delete a stale inherited var (PR 14 fix #4247 wenshao R5 —
|
||||
* the `runQwenServe.ts:216` use case).
|
||||
* the `run-qwen-serve.ts:216` use case).
|
||||
*
|
||||
* Each branch listed below is now regression-guarded by an assertion.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1018,7 +1018,7 @@ export function createIdleWorkspaceProvidersStatus(
|
|||
* tests, embedded callers that don't need daemon-host cells). Single
|
||||
* construction site so future optional-field additions to
|
||||
* `ServeWorkspaceEnvStatus` only need updating in one place — the
|
||||
* production builder in `cli/src/serve/envSnapshot.ts buildEnvStatusFromProcess`
|
||||
* production builder in `cli/src/serve/env-snapshot.ts buildEnvStatusFromProcess`
|
||||
* and this helper would otherwise diverge silently (TS won't flag a
|
||||
* missing optional field).
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2599,7 +2599,7 @@ class QwenAgent implements Agent {
|
|||
private connection: AgentSideConnection,
|
||||
) {
|
||||
// Pool kill switch via env var so operators can A/B compare or
|
||||
// roll back without rebuilding. `runQwenServe.ts` sets this when
|
||||
// roll back without rebuilding. `run-qwen-serve.ts` sets this when
|
||||
// `--no-mcp-pool` is passed at daemon startup.
|
||||
if (process.env['QWEN_SERVE_NO_MCP_POOL'] === '1') {
|
||||
this.mcpPool = undefined;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type { Argv, CommandModule } from 'yargs';
|
|||
// with ~50ms of cold ESM resolution. The runtime import is deferred to the
|
||||
// handler below so it only loads when the user actually runs `qwen serve`.
|
||||
import { writeStderrLine } from '../utils/stdioHelpers.js';
|
||||
import { DEFAULT_RING_SIZE } from '../serve/eventBus.js';
|
||||
import { DEFAULT_RING_SIZE } from '../serve/event-bus.js';
|
||||
import {
|
||||
ApprovalMode,
|
||||
MCP_BUDGET_WARN_FRACTION,
|
||||
|
|
|
|||
|
|
@ -2155,7 +2155,7 @@ const SETTINGS_SCHEMA = {
|
|||
'unreachable quorum. Unset = floor(M/2)+1. ' +
|
||||
'Requires daemon restart — read once at boot.',
|
||||
showInDialog: false,
|
||||
// runQwenServe.ts validates `Number.isInteger(n) && n >= 1` and
|
||||
// run-qwen-serve.ts validates `Number.isInteger(n) && n >= 1` and
|
||||
// refuses to boot otherwise. Override the generated schema so IDE
|
||||
// (VSCode, JetBrains via JSON Schema) flags `0`, `-1`, `1.5`
|
||||
// BEFORE the user restarts the daemon. The bare `type:'number'`
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import {
|
|||
TooManyActiveDeviceFlowsError,
|
||||
UnsupportedDeviceFlowProviderError,
|
||||
UpstreamDeviceFlowError,
|
||||
} from '../auth/deviceFlow.js';
|
||||
} from '../auth/device-flow.js';
|
||||
import type { HttpAcpBridge } from '@qwen-code/acp-bridge/bridgeTypes';
|
||||
import type { BridgeEvent } from '@qwen-code/acp-bridge/eventBus';
|
||||
import {
|
||||
|
|
@ -35,13 +35,13 @@ import {
|
|||
MAX_READ_BYTES,
|
||||
type WorkspaceFileSystemFactory,
|
||||
} from '../fs/index.js';
|
||||
import type { DeviceFlowRegistry } from '../auth/deviceFlow.js';
|
||||
import { collectWorkspaceMemoryStatus } from '../workspaceMemory.js';
|
||||
import type { DeviceFlowRegistry } from '../auth/device-flow.js';
|
||||
import { collectWorkspaceMemoryStatus } from '../workspace-memory.js';
|
||||
import {
|
||||
createDaemonSubagentManager,
|
||||
toSummary as agentToSummary,
|
||||
toDetail as agentToDetail,
|
||||
} from '../workspaceAgents.js';
|
||||
} from '../workspace-agents.js';
|
||||
import {
|
||||
InvalidCursorError,
|
||||
listWorkspaceSessionsForResponse,
|
||||
|
|
@ -1853,7 +1853,7 @@ export class AcpDispatcher {
|
|||
}
|
||||
const startResult = await this.deviceFlowRegistry.start({
|
||||
providerId:
|
||||
providerId as import('../auth/deviceFlow.js').DeviceFlowProviderId,
|
||||
providerId as import('../auth/device-flow.js').DeviceFlowProviderId,
|
||||
initiatorClientId: conn.clientId,
|
||||
});
|
||||
const { view, attached } = startResult;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type { HttpAcpBridge } from '@qwen-code/acp-bridge/bridgeTypes';
|
|||
import { writeStderrLine } from '../../utils/stdioHelpers.js';
|
||||
import type { DaemonWorkspaceService } from '../workspace-service/types.js';
|
||||
import type { WorkspaceFileSystemFactory } from '../fs/index.js';
|
||||
import type { DeviceFlowRegistry } from '../auth/deviceFlow.js';
|
||||
import type { DeviceFlowRegistry } from '../auth/device-flow.js';
|
||||
import { AcpDispatcher } from './dispatch.js';
|
||||
import {
|
||||
ConnectionRegistry,
|
||||
|
|
@ -21,7 +21,7 @@ import {
|
|||
} from './connectionRegistry.js';
|
||||
import { SseStream } from './sseStream.js';
|
||||
import { WsStream } from './wsStream.js';
|
||||
import type { RateLimitTier } from '../rateLimit.js';
|
||||
import type { RateLimitTier } from '../rate-limit.js';
|
||||
import { RPC, error as rpcError, isRequest, parseInbound } from './jsonRpc.js';
|
||||
|
||||
export const ACP_CONNECTION_HEADER = 'acp-connection-id';
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
* `defaultSpawnChannelFactory`, `createAcpSessionBridge` factory closure,
|
||||
* plus the supporting types/errors/options/status) to
|
||||
* `@qwen-code/acp-bridge`. This shim preserves every existing relative
|
||||
* import path (`./acpSessionBridge.js`) so `server.ts`, `runQwenServe.ts`,
|
||||
* `workspaceAgents.ts`, `workspaceMemory.ts`, `index.ts`, plus the
|
||||
* import path (`./acpSessionBridge.js`) so `server.ts`, `run-qwen-serve.ts`,
|
||||
* `workspace-agents.ts`, `workspace-memory.ts`, `index.ts`, plus the
|
||||
* bridge test suite, keep resolving without any call-site changes.
|
||||
*
|
||||
* The implementation now lives at:
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ describe('createMutationGate (#4175 PR 15)', () => {
|
|||
expect(body.error).toMatch(/--token/);
|
||||
// `--require-auth` is intentionally NOT named here as a remediation:
|
||||
// setting it without a token is itself a boot-error path (see
|
||||
// `runQwenServe.ts`). The error must point operators at fixes that
|
||||
// `run-qwen-serve.ts`). The error must point operators at fixes that
|
||||
// work standalone.
|
||||
expect(body.error).not.toMatch(/--require-auth/);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { createHash, timingSafeEqual } from 'node:crypto';
|
||||
import type { Request, Response, NextFunction, RequestHandler } from 'express';
|
||||
import { isLoopbackBind } from './loopbackBinds.js';
|
||||
import { isLoopbackBind } from './loopback-binds.js';
|
||||
|
||||
/**
|
||||
* Reject any request that carries an `Origin` header. CLI/SDK clients never
|
||||
|
|
@ -428,7 +428,7 @@ export function createMutationGate(
|
|||
// cache is visible.
|
||||
const strictDenier: RequestHandler = (_req: Request, res: Response) => {
|
||||
// Only list remediations that work standalone. `--require-auth` is
|
||||
// paired-required-with-a-token at boot (`runQwenServe.ts` refuses
|
||||
// paired-required-with-a-token at boot (`run-qwen-serve.ts` refuses
|
||||
// to start with the flag set but no token), so naming it as a
|
||||
// third standalone option here would loop the operator into a
|
||||
// different boot error. Configuring a token via `QWEN_SERVER_TOKEN`
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import {
|
|||
type DeviceFlowPollResult,
|
||||
type DeviceFlowProvider,
|
||||
type DeviceFlowProviderId,
|
||||
} from './deviceFlow.js';
|
||||
} from './device-flow.js';
|
||||
|
||||
interface FakeClock {
|
||||
now: number;
|
||||
|
|
@ -630,8 +630,8 @@ describe('DeviceFlowRegistry — polling state machine', () => {
|
|||
// here loudly.
|
||||
const dir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const sources = [
|
||||
fs.readFileSync(path.join(dir, 'deviceFlow.ts'), 'utf8'),
|
||||
fs.readFileSync(path.join(dir, 'qwenDeviceFlowProvider.ts'), 'utf8'),
|
||||
fs.readFileSync(path.join(dir, 'device-flow.ts'), 'utf8'),
|
||||
fs.readFileSync(path.join(dir, 'qwen-device-flow-provider.ts'), 'utf8'),
|
||||
];
|
||||
const forbiddenPatterns = [
|
||||
// Static imports
|
||||
|
|
@ -30,8 +30,8 @@ import {
|
|||
QwenOAuthPollError,
|
||||
type IQwenOAuth2Client,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { QwenOAuthDeviceFlowProvider } from './qwenDeviceFlowProvider.js';
|
||||
import { brandSecret } from './deviceFlow.js';
|
||||
import { QwenOAuthDeviceFlowProvider } from './qwen-device-flow-provider.js';
|
||||
import { brandSecret } from './device-flow.js';
|
||||
|
||||
function fakeClient(
|
||||
overrides: Partial<IQwenOAuth2Client> = {},
|
||||
|
|
@ -28,7 +28,7 @@ import {
|
|||
type DeviceFlowProvider,
|
||||
type DeviceFlowProviderId,
|
||||
type DeviceFlowStartResult,
|
||||
} from './deviceFlow.js';
|
||||
} from './device-flow.js';
|
||||
|
||||
const QWEN_OAUTH_SCOPE = 'openid profile email model.completion';
|
||||
|
||||
|
|
@ -33,11 +33,11 @@ import type {
|
|||
ReadTextFileRequest,
|
||||
WriteTextFileRequest,
|
||||
} from '@agentclientprotocol/sdk';
|
||||
import { createBridgeFileSystemAdapter } from './bridgeFileSystemAdapter.js';
|
||||
import { createBridgeFileSystemAdapter } from './bridge-file-system-adapter.js';
|
||||
import {
|
||||
createWorkspaceFileSystemFactory,
|
||||
type WorkspaceFileSystemFactory,
|
||||
} from './fs/workspaceFileSystem.js';
|
||||
} from './fs/workspace-file-system.js';
|
||||
|
||||
describe('createBridgeFileSystemAdapter', () => {
|
||||
let tmpDir: string;
|
||||
|
|
@ -136,7 +136,7 @@ describe('createBridgeFileSystemAdapter', () => {
|
|||
// Symlink-rejection posture (BridgeFileSystem contract divergence
|
||||
// from the pre-F1 inline proxy) is enforced by `writeTextOverwrite`
|
||||
// and verified at the lower layer in
|
||||
// `workspaceFileSystem.test.ts > writeTextOverwrite rejects symlink
|
||||
// `workspace-file-system.test.ts > writeTextOverwrite rejects symlink
|
||||
// targets planted post-resolve (symlink_escape)`. Re-testing at the
|
||||
// adapter layer would only re-exercise the same code path; the
|
||||
// adapter contract is "delegate to writeTextOverwrite", and the
|
||||
|
|
@ -59,7 +59,7 @@ import type { BridgeFileSystem } from '@qwen-code/acp-bridge';
|
|||
import type {
|
||||
WorkspaceFileSystemFactory,
|
||||
RequestContext,
|
||||
} from './fs/workspaceFileSystem.js';
|
||||
} from './fs/workspace-file-system.js';
|
||||
|
||||
/** Route label used in audit events for ACP-triggered fs operations. */
|
||||
const ACP_WRITE_ROUTE = 'ACP writeTextFile';
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createDaemonStatusProvider } from './daemonStatusProvider.js';
|
||||
import { createDaemonStatusProvider } from './daemon-status-provider.js';
|
||||
import { createDaemonWorkspaceService } from './workspace-service/index.js';
|
||||
import type {
|
||||
DaemonWorkspaceServiceDeps,
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
*
|
||||
* Lift origin (#4175 PR 22b/2): the inline `buildDaemonPreflightCells`
|
||||
* function moved here from `httpAcpBridge.ts`; `buildEnvStatusFromProcess`
|
||||
* stays in `envSnapshot.ts` and is wrapped here. Mode A consumers can
|
||||
* stays in `env-snapshot.ts` and is wrapped here. Mode A consumers can
|
||||
* omit this provider entirely — the bridge falls back to idle placeholders.
|
||||
*/
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ import {
|
|||
type ServeWorkspaceEnvStatus,
|
||||
} from '@qwen-code/acp-bridge';
|
||||
import { getGitVersion, getNpmVersion } from '../utils/systemInfo.js';
|
||||
import { buildEnvStatusFromProcess } from './envSnapshot.js';
|
||||
import { buildEnvStatusFromProcess } from './env-snapshot.js';
|
||||
|
||||
const REQUIRED_NODE_MAJOR = 22;
|
||||
|
||||
|
|
@ -11,12 +11,12 @@ import type {
|
|||
AcpSessionBridge,
|
||||
BridgeDaemonStatusSnapshot,
|
||||
} from './acpSessionBridge.js';
|
||||
import { DeviceFlowRegistry } from './auth/deviceFlow.js';
|
||||
import { DeviceFlowRegistry } from './auth/device-flow.js';
|
||||
import {
|
||||
buildDaemonStatusResponse,
|
||||
type BuildDaemonStatusOptions,
|
||||
} from './daemonStatus.js';
|
||||
import type { RateLimiterInstance, RateLimitTier } from './rateLimit.js';
|
||||
import type { RateLimiterInstance, RateLimitTier } from './rate-limit.js';
|
||||
import type { DaemonWorkspaceService } from './workspace-service/index.js';
|
||||
|
||||
const BASE_WORKSPACE = '/work/status';
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
import type { ServeProtocolVersions } from './capabilities.js';
|
||||
import type { AcpHttpHandle } from './acpHttp/index.js';
|
||||
import type { DeviceFlowRegistry } from './auth/deviceFlow.js';
|
||||
import type { DeviceFlowRegistry } from './auth/device-flow.js';
|
||||
import type { DaemonLogger } from './daemonLogger.js';
|
||||
import type {
|
||||
AcpSessionBridge,
|
||||
BridgeDaemonStatusSnapshot,
|
||||
} from './acpSessionBridge.js';
|
||||
import { isLoopbackBind } from './loopbackBinds.js';
|
||||
import type { RateLimiterInstance, RateLimitTier } from './rateLimit.js';
|
||||
import { isLoopbackBind } from './loopback-binds.js';
|
||||
import type { RateLimiterInstance, RateLimitTier } from './rate-limit.js';
|
||||
import type { ServeOptions } from './types.js';
|
||||
import type {
|
||||
DaemonWorkspaceService,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
* `httpAcpBridge.ts` (which gates stderr-side debug log output).
|
||||
*
|
||||
* Extracted into its own module in fold-in 2i so route files
|
||||
* (`workspaceMemory.ts`, `workspaceAgents.ts`, future Wave 4 mutation
|
||||
* (`workspace-memory.ts`, `workspace-agents.ts`, future Wave 4 mutation
|
||||
* routes) can share one canonical predicate when deciding whether to
|
||||
* include `errorMessage` / `filePath` in their response bodies.
|
||||
* Without the toggle, error responses carry only structured fields
|
||||
|
|
@ -12,7 +12,7 @@ import {
|
|||
ENV_SECRET_VARS,
|
||||
buildEnvStatusFromProcess,
|
||||
readProxyVar,
|
||||
} from './envSnapshot.js';
|
||||
} from './env-snapshot.js';
|
||||
|
||||
const TRACKED_ENV = [
|
||||
...ENV_SECRET_VARS,
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
// Re-export wrapper. The implementation lives in `@qwen-code/acp-bridge`
|
||||
// (lifted in #4175 PR 22a). Existing `import { ... } from './eventBus.js'`
|
||||
// (lifted in #4175 PR 22a). Existing `import { ... } from './event-bus.js'`
|
||||
// callers inside `serve/` and the one external import in
|
||||
// `cli/src/commands/serve.ts:14` keep resolving without churn.
|
||||
//
|
||||
|
|
@ -14,7 +14,7 @@ import {
|
|||
createAuditPublisher,
|
||||
} from './audit.js';
|
||||
import type { ResolvedPath } from './paths.js';
|
||||
import type { BridgeEvent } from '../eventBus.js';
|
||||
import type { BridgeEvent } from '../event-bus.js';
|
||||
|
||||
function expectedHash(p: string): string {
|
||||
return createHash('sha256').update(p).digest('hex').slice(0, 16);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { createHash } from 'node:crypto';
|
||||
import * as path from 'node:path';
|
||||
import { EVENT_SCHEMA_VERSION, type BridgeEvent } from '../eventBus.js';
|
||||
import { EVENT_SCHEMA_VERSION, type BridgeEvent } from '../event-bus.js';
|
||||
import type { FsErrorKind } from './errors.js';
|
||||
import type { Intent, ResolvedPath } from './paths.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { WorkspaceContext } from '@qwen-code/qwen-code-core';
|
|||
import { canonicalizeWorkspace, resolveWithinWorkspace } from './paths.js';
|
||||
// `isFsError` is a runtime guard called below — must stay a value
|
||||
// import. `FsError` is type-only here (typed `catch` variable); same
|
||||
// for `FsErrorKind`. The eslint-disable mirrors the workspaceFileSystem.ts
|
||||
// for `FsErrorKind`. The eslint-disable mirrors the workspace-file-system.ts
|
||||
// fix and exists because the auto-fix at commit 7b0db4c3a promoted the
|
||||
// whole line to `import type`, erasing `isFsError` at runtime and
|
||||
// failing 11 tests in this file alone.
|
||||
|
|
|
|||
|
|
@ -60,4 +60,4 @@ export {
|
|||
type WriteOutcome,
|
||||
type WriteTextAtomicOptions,
|
||||
type WriteTextAtomicOutcome,
|
||||
} from './workspaceFileSystem.js';
|
||||
} from './workspace-file-system.js';
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ export interface ReadSizeOutcome {
|
|||
* when `opts.maxBytes < fileSize <= MAX_READ_BYTES`. It runs only
|
||||
* AFTER `readText`'s pre-stat hard-cap check has rejected files
|
||||
* above `MAX_READ_BYTES` with `file_too_large` (see
|
||||
* `workspaceFileSystem.ts:readText`). Within the hard cap the
|
||||
* `workspace-file-system.ts:readText`). Within the hard cap the
|
||||
* caller can opt into a tighter byte ceiling via `opts.maxBytes`,
|
||||
* and we surface that truncation via `truncated: true` rather
|
||||
* than throwing — operators want to see a partial config file
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
type WorkspaceFileSystem,
|
||||
type WorkspaceFileSystemFactory,
|
||||
} from './index.js';
|
||||
import type { BridgeEvent } from '../eventBus.js';
|
||||
import type { BridgeEvent } from '../event-bus.js';
|
||||
import { canonicalizeWorkspace } from './paths.js';
|
||||
import { isFsError } from './errors.js';
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ import {
|
|||
type Ignore,
|
||||
type WriteTextFileOptions,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import type { BridgeEvent } from '../eventBus.js';
|
||||
import type { BridgeEvent } from '../event-bus.js';
|
||||
import {
|
||||
type AuditContext,
|
||||
type AuditPublisher,
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
// Re-export wrapper. The implementation lives in `@qwen-code/acp-bridge`
|
||||
// (lifted in #4175 PR 22a). Existing `import { createInMemoryChannel }
|
||||
// from './inMemoryChannel.js'` callers inside `serve/` and the SDK
|
||||
// from './in-memory-channel.js'` callers inside `serve/` and the SDK
|
||||
// in-process bridge tests keep resolving without churn.
|
||||
//
|
||||
// @see ../../../acp-bridge/src/inMemoryChannel.ts for the implementation
|
||||
|
|
@ -9,7 +9,7 @@ export {
|
|||
runQwenServe,
|
||||
type RunHandle,
|
||||
type RunQwenServeDeps,
|
||||
} from './runQwenServe.js';
|
||||
} from './run-qwen-serve.js';
|
||||
export {
|
||||
CAPABILITIES_SCHEMA_VERSION,
|
||||
STAGE1_FEATURES,
|
||||
|
|
@ -98,7 +98,7 @@ export {
|
|||
ENV_PROXY_VARS,
|
||||
ENV_SECRET_VARS,
|
||||
buildEnvStatusFromProcess,
|
||||
} from './envSnapshot.js';
|
||||
} from './env-snapshot.js';
|
||||
export {
|
||||
bearerAuth,
|
||||
createMutationGate,
|
||||
|
|
@ -139,5 +139,5 @@ export {
|
|||
EVENT_SCHEMA_VERSION,
|
||||
type BridgeEvent,
|
||||
type SubscribeOptions,
|
||||
} from './eventBus.js';
|
||||
export { createInMemoryChannel } from './inMemoryChannel.js';
|
||||
} from './event-bus.js';
|
||||
export { createInMemoryChannel } from './in-memory-channel.js';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
createPermissionAuditPublisher,
|
||||
DEFAULT_PERMISSION_AUDIT_RING_SIZE,
|
||||
PermissionAuditRing,
|
||||
} from './permissionAudit.js';
|
||||
} from './permission-audit.js';
|
||||
import type {
|
||||
PermissionRequestRecord,
|
||||
PermissionVote,
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { createRateLimiter, createKeyExtractor } from './rateLimit.js';
|
||||
import { createRateLimiter, createKeyExtractor } from './rate-limit.js';
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
function mockReq(overrides: Record<string, unknown> = {}): Request {
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import type { Request, Response, NextFunction, RequestHandler } from 'express';
|
||||
import { isLoopbackBind } from './loopbackBinds.js';
|
||||
import { isLoopbackBind } from './loopback-binds.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
|
|
@ -16,7 +16,7 @@ import {
|
|||
canonicalizeWorkspace,
|
||||
createWorkspaceFileSystemFactory,
|
||||
} from '../fs/index.js';
|
||||
import type { BridgeEvent } from '../eventBus.js';
|
||||
import type { BridgeEvent } from '../event-bus.js';
|
||||
import type { ServeOptions } from '../types.js';
|
||||
|
||||
const baseOpts: ServeOptions = {
|
||||
|
|
@ -15,7 +15,7 @@ import {
|
|||
canonicalizeWorkspace,
|
||||
createWorkspaceFileSystemFactory,
|
||||
} from '../fs/index.js';
|
||||
import type { BridgeEvent } from '../eventBus.js';
|
||||
import type { BridgeEvent } from '../event-bus.js';
|
||||
import type { ServeOptions } from '../types.js';
|
||||
|
||||
const baseOpts: ServeOptions = {
|
||||
|
|
@ -16,7 +16,7 @@ import {
|
|||
applyReadHeaders,
|
||||
sendFsError,
|
||||
workspaceRelative,
|
||||
} from './workspaceFileRead.js';
|
||||
} from './workspace-file-read.js';
|
||||
|
||||
interface RegisterDeps {
|
||||
bridge: AcpSessionBridge;
|
||||
|
|
@ -13,7 +13,7 @@ import {
|
|||
InvalidPolicyConfigError,
|
||||
runQwenServe,
|
||||
validatePolicyConfig,
|
||||
} from './runQwenServe.js';
|
||||
} from './run-qwen-serve.js';
|
||||
import type { HttpAcpBridge } from './acpSessionBridge.js';
|
||||
|
||||
/**
|
||||
|
|
@ -8,8 +8,8 @@ import * as fs from 'node:fs';
|
|||
import { type Server } from 'node:http';
|
||||
import * as path from 'node:path';
|
||||
import { writeStderrLine, writeStdoutLine } from '../utils/stdioHelpers.js';
|
||||
import type { BridgeEvent } from './eventBus.js';
|
||||
import { getDeviceFlowRegistry } from './auth/deviceFlow.js';
|
||||
import type { BridgeEvent } from './event-bus.js';
|
||||
import { getDeviceFlowRegistry } from './auth/device-flow.js';
|
||||
import {
|
||||
loadSettings,
|
||||
reloadEnvironment,
|
||||
|
|
@ -48,15 +48,15 @@ import {
|
|||
type TelemetryRuntimeConfig,
|
||||
type TelemetrySettings,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { createBridgeFileSystemAdapter } from './bridgeFileSystemAdapter.js';
|
||||
import { createDaemonStatusProvider } from './daemonStatusProvider.js';
|
||||
import { isLoopbackBind } from './loopbackBinds.js';
|
||||
import { createBridgeFileSystemAdapter } from './bridge-file-system-adapter.js';
|
||||
import { createDaemonStatusProvider } from './daemon-status-provider.js';
|
||||
import { isLoopbackBind } from './loopback-binds.js';
|
||||
import { resolveWebShellDir } from './webShellStatic.js';
|
||||
import { parseAllowOriginPatterns } from './auth.js';
|
||||
import {
|
||||
createPermissionAuditPublisher,
|
||||
PermissionAuditRing,
|
||||
} from './permissionAudit.js';
|
||||
} from './permission-audit.js';
|
||||
import {
|
||||
createServeApp,
|
||||
getActiveSseCount,
|
||||
|
|
@ -74,7 +74,7 @@ import type {
|
|||
import type { WorkspaceFileSystemFactory } from './fs/index.js';
|
||||
import type { PermissionPolicy } from '@qwen-code/acp-bridge';
|
||||
import { getCliVersion } from '../utils/version.js';
|
||||
import { getRateLimiter } from './rateLimit.js';
|
||||
import { getRateLimiter } from './rate-limit.js';
|
||||
import type { AcpHttpHandle } from './acpHttp/index.js';
|
||||
|
||||
const QWEN_SERVER_TOKEN_ENV = 'QWEN_SERVER_TOKEN';
|
||||
|
|
@ -862,7 +862,7 @@ export async function runQwenServe(
|
|||
|
||||
// Construct `fsFactory` BEFORE the bridge so the bridge can wire it
|
||||
// through `BridgeFileSystem` for ACP-side writeTextFile / readTextFile
|
||||
// calls. See `bridgeFileSystemAdapter.ts` for the translation layer.
|
||||
// calls. See `bridge-file-system-adapter.ts` for the translation layer.
|
||||
const trustedWorkspace = deps.trustedWorkspace ?? true;
|
||||
const fsFactory = resolveBridgeFsFactory({
|
||||
boundWorkspace,
|
||||
|
|
@ -19,7 +19,7 @@ import {
|
|||
PromptDeadlineExceededError,
|
||||
resolvePromptDeadlineMs,
|
||||
} from './server.js';
|
||||
import { runQwenServe, type RunHandle } from './runQwenServe.js';
|
||||
import { runQwenServe, type RunHandle } from './run-qwen-serve.js';
|
||||
import { resolveWebShellDir, isDocumentNavigation } from './webShellStatic.js';
|
||||
import {
|
||||
CONDITIONAL_SERVE_FEATURES,
|
||||
|
|
@ -77,7 +77,7 @@ import {
|
|||
type AcpSessionBridge,
|
||||
type SessionMetadataUpdate,
|
||||
} from './acpSessionBridge.js';
|
||||
import type { BridgeEvent, SubscribeOptions } from './eventBus.js';
|
||||
import type { BridgeEvent, SubscribeOptions } from './event-bus.js';
|
||||
import type {
|
||||
ServeSessionContextStatus,
|
||||
ServeSessionContextUsageStatus,
|
||||
|
|
@ -1273,8 +1273,8 @@ function fakeBridge(opts: FakeBridgeOpts = {}): FakeBridge {
|
|||
publishWorkspaceEvent(_event) {
|
||||
// Issue #4175 PR 16 — fakeBridge default is a no-op. Tests that
|
||||
// assert on workspace fan-out override this through the dedicated
|
||||
// route-level test files (workspaceMemory.test.ts /
|
||||
// workspaceAgents.test.ts) where the real fan-out behavior is
|
||||
// route-level test files (workspace-memory.test.ts /
|
||||
// workspace-agents.test.ts) where the real fan-out behavior is
|
||||
// exercised against a live bridge.
|
||||
},
|
||||
knownClientIds() {
|
||||
|
|
@ -1935,7 +1935,7 @@ describe('createServeApp', () => {
|
|||
});
|
||||
|
||||
it('omits mcp_workspace_pool / mcp_pool_restart when mcpPoolActive=false (F2 #4175 commit 5)', async () => {
|
||||
// Mirrors the env-var kill switch path: `runQwenServe.ts` infers
|
||||
// Mirrors the env-var kill switch path: `run-qwen-serve.ts` infers
|
||||
// `mcpPoolActive: false` when the parent process has
|
||||
// `QWEN_SERVE_NO_MCP_POOL=1`. Verify the capability envelope
|
||||
// tracks the toggle so SDK clients pre-flighting on the tags
|
||||
|
|
@ -10436,7 +10436,7 @@ describe('auth device-flow routes', () => {
|
|||
// whose `poll` is scripted per-test. Lives at the top of the suite so
|
||||
// every `it()` can compose it with the registry.
|
||||
function makeFakeProvider(): {
|
||||
provider: import('./auth/deviceFlow.js').DeviceFlowProvider;
|
||||
provider: import('./auth/device-flow.js').DeviceFlowProvider;
|
||||
startCount: () => number;
|
||||
} {
|
||||
let starts = 0;
|
||||
|
|
@ -10449,10 +10449,10 @@ describe('auth device-flow routes', () => {
|
|||
deviceCode:
|
||||
// Use the brandSecret helper so the secret follows the same
|
||||
// redaction shape the production provider produces.
|
||||
(await import('./auth/deviceFlow.js')).brandSecret(
|
||||
(await import('./auth/device-flow.js')).brandSecret(
|
||||
`device-${starts}`,
|
||||
),
|
||||
pkceVerifier: (await import('./auth/deviceFlow.js')).brandSecret(
|
||||
pkceVerifier: (await import('./auth/device-flow.js')).brandSecret(
|
||||
`pkce-${starts}`,
|
||||
),
|
||||
userCode: `USER-${starts}`,
|
||||
|
|
@ -10935,8 +10935,8 @@ describe('auth device-flow routes', () => {
|
|||
// must surface as 502 with code:'upstream_error' instead of falling
|
||||
// through `sendBridgeError`'s generic 500 path. Build a fake
|
||||
// provider whose start always throws.
|
||||
const { UpstreamDeviceFlowError } = await import('./auth/deviceFlow.js');
|
||||
const failingProvider: import('./auth/deviceFlow.js').DeviceFlowProvider = {
|
||||
const { UpstreamDeviceFlowError } = await import('./auth/device-flow.js');
|
||||
const failingProvider: import('./auth/device-flow.js').DeviceFlowProvider = {
|
||||
providerId: 'qwen-oauth',
|
||||
async start() {
|
||||
throw new UpstreamDeviceFlowError('mocked upstream outage');
|
||||
|
|
@ -10964,9 +10964,9 @@ describe('auth device-flow routes', () => {
|
|||
// PR 21 fold-in 0 P1-13: cover the time-based expiry path via an
|
||||
// injected registry with a controlled clock + manual sweeper trigger.
|
||||
const { DeviceFlowRegistry, brandSecret } = await import(
|
||||
'./auth/deviceFlow.js'
|
||||
'./auth/device-flow.js'
|
||||
);
|
||||
const fakeProvider: import('./auth/deviceFlow.js').DeviceFlowProvider = {
|
||||
const fakeProvider: import('./auth/device-flow.js').DeviceFlowProvider = {
|
||||
providerId: 'qwen-oauth',
|
||||
async start() {
|
||||
return {
|
||||
|
|
@ -11067,7 +11067,7 @@ describe('auth device-flow routes', () => {
|
|||
it('POST returns 409 too_many_active_flows when registry cap is reached', async () => {
|
||||
// Inject a fake registry whose `start` always throws the cap error.
|
||||
const { TooManyActiveDeviceFlowsError } = await import(
|
||||
'./auth/deviceFlow.js'
|
||||
'./auth/device-flow.js'
|
||||
);
|
||||
const fakeRegistry = {
|
||||
start: async () => {
|
||||
|
|
@ -11077,7 +11077,7 @@ describe('auth device-flow routes', () => {
|
|||
cancel: () => undefined,
|
||||
listPending: () => [],
|
||||
dispose: () => {},
|
||||
} as unknown as import('./auth/deviceFlow.js').DeviceFlowRegistry;
|
||||
} as unknown as import('./auth/device-flow.js').DeviceFlowRegistry;
|
||||
|
||||
const bridge = fakeBridge();
|
||||
const app = createServeApp({ ...baseOpts, token: 'tkn' }, undefined, {
|
||||
|
|
|
|||
|
|
@ -55,16 +55,16 @@ import {
|
|||
type DeviceFlowProvider,
|
||||
type DeviceFlowProviderId,
|
||||
type DeviceFlowPublicView,
|
||||
} from './auth/deviceFlow.js';
|
||||
} from './auth/device-flow.js';
|
||||
import { mapDomainErrorToErrorKind } from '@qwen-code/acp-bridge';
|
||||
import { QwenOAuthDeviceFlowProvider } from './auth/qwenDeviceFlowProvider.js';
|
||||
import { createBridgeFileSystemAdapter } from './bridgeFileSystemAdapter.js';
|
||||
import { createDaemonStatusProvider } from './daemonStatusProvider.js';
|
||||
import { isServeDebugMode } from './debugMode.js';
|
||||
import { QwenOAuthDeviceFlowProvider } from './auth/qwen-device-flow-provider.js';
|
||||
import { createBridgeFileSystemAdapter } from './bridge-file-system-adapter.js';
|
||||
import { createDaemonStatusProvider } from './daemon-status-provider.js';
|
||||
import { isServeDebugMode } from './debug-mode.js';
|
||||
import { SUPPORTED_LANGUAGES } from '../i18n/index.js';
|
||||
import { loadSettings } from '../config/settings.js';
|
||||
import { isWorkspaceTrusted } from '../config/trustedFolders.js';
|
||||
import { isLoopbackBind } from './loopbackBinds.js';
|
||||
import { isLoopbackBind } from './loopback-binds.js';
|
||||
import { mountAcpHttp, type AcpHttpHandle } from './acpHttp/index.js';
|
||||
import {
|
||||
buildDaemonStatusResponse,
|
||||
|
|
@ -104,7 +104,7 @@ import {
|
|||
getAdvertisedServeFeatures,
|
||||
getServeProtocolVersions,
|
||||
} from './capabilities.js';
|
||||
import { SubscriberLimitExceededError, type BridgeEvent } from './eventBus.js';
|
||||
import { SubscriberLimitExceededError, type BridgeEvent } from './event-bus.js';
|
||||
import {
|
||||
CAPABILITIES_SCHEMA_VERSION,
|
||||
type CapabilitiesEnvelope,
|
||||
|
|
@ -119,26 +119,26 @@ import {
|
|||
mountWebShellAssets,
|
||||
mountWebShellSpaFallback,
|
||||
} from './webShellStatic.js';
|
||||
import { mountWorkspaceMemoryRoutes } from './workspaceMemory.js';
|
||||
import { mountWorkspaceAgentsRoutes } from './workspaceAgents.js';
|
||||
import { mountWorkspaceMemoryRoutes } from './workspace-memory.js';
|
||||
import { mountWorkspaceAgentsRoutes } from './workspace-agents.js';
|
||||
import {
|
||||
createWorkspaceFileSystemFactory,
|
||||
type WorkspaceFileSystemFactory,
|
||||
} from './fs/index.js';
|
||||
import { registerWorkspaceFileReadRoutes } from './routes/workspaceFileRead.js';
|
||||
import { registerWorkspaceFileWriteRoutes } from './routes/workspaceFileWrite.js';
|
||||
import { registerWorkspaceFileReadRoutes } from './routes/workspace-file-read.js';
|
||||
import { registerWorkspaceFileWriteRoutes } from './routes/workspace-file-write.js';
|
||||
import {
|
||||
createDaemonWorkspaceService,
|
||||
type DaemonWorkspaceService,
|
||||
type WorkspaceRequestContext,
|
||||
} from './workspace-service/index.js';
|
||||
import { registerWorkspaceSettingsRoutes } from './routes/workspaceSettings.js';
|
||||
import { registerWorkspaceSettingsRoutes } from './routes/workspace-settings.js';
|
||||
import { registerA2uiActionRoutes } from './routes/a2uiAction.js';
|
||||
import {
|
||||
createRateLimiter,
|
||||
setRateLimiter,
|
||||
type RateLimiterInstance,
|
||||
} from './rateLimit.js';
|
||||
} from './rate-limit.js';
|
||||
import {
|
||||
STATUS_SCHEMA_VERSION,
|
||||
type ServeExtensionCapabilities,
|
||||
|
|
@ -1596,7 +1596,7 @@ export function createServeApp(
|
|||
// both halves of the policy (matched → CORS headers + pass-through or
|
||||
// 204 preflight; unmatched → 403 with the same error envelope as the
|
||||
// wall). When `--allow-origin` is empty/undefined, the deny-wall stays
|
||||
// installed. Pattern parsing happens in `runQwenServe.ts` for validation;
|
||||
// installed. Pattern parsing happens in `run-qwen-serve.ts` for validation;
|
||||
// here we still keep the wildcard/no-token invariant for embedded
|
||||
// callers that construct the app directly.
|
||||
if (opts.allowOrigins && opts.allowOrigins.length > 0) {
|
||||
|
|
@ -4521,7 +4521,7 @@ export function createServeApp(
|
|||
const idleForMs = Date.now() - lastWriteAt;
|
||||
if (idleForMs < writerIdleTimeoutMs) return;
|
||||
// Reuse the existing `client_evicted` taxonomy from
|
||||
// `eventBus.ts` so SDK reducers branch on the same frame type
|
||||
// `event-bus.ts` so SDK reducers branch on the same frame type
|
||||
// they already handle for queue-overflow eviction; the new
|
||||
// `reason` slot is the differentiator. Write DIRECTLY here
|
||||
// (bypassing `writeWithBackpressure`) because the chain may
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import express from 'express';
|
|||
import type { Application, NextFunction, Request, Response } from 'express';
|
||||
import { resolveBundleDir } from '@qwen-code/qwen-code-core';
|
||||
import { writeStderrLine } from '../utils/stdioHelpers.js';
|
||||
import { isServeDebugMode } from './debugMode.js';
|
||||
import { isServeDebugMode } from './debug-mode.js';
|
||||
|
||||
/**
|
||||
* Content-Security-Policy for the Web Shell HTML shell.
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import {
|
|||
import { Storage, QWEN_DIR } from '@qwen-code/qwen-code-core';
|
||||
import { createMutationGate } from './auth.js';
|
||||
import type { AcpSessionBridge } from './acpSessionBridge.js';
|
||||
import type { BridgeEvent } from './eventBus.js';
|
||||
import { mountWorkspaceAgentsRoutes } from './workspaceAgents.js';
|
||||
import type { BridgeEvent } from './event-bus.js';
|
||||
import { mountWorkspaceAgentsRoutes } from './workspace-agents.js';
|
||||
|
||||
type RecordedEvent = Omit<BridgeEvent, 'id' | 'v'>;
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ import {
|
|||
type SubagentLevel,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { writeStderrLine } from '../utils/stdioHelpers.js';
|
||||
import { isServeDebugMode } from './debugMode.js';
|
||||
import { isServeDebugMode } from './debug-mode.js';
|
||||
import {
|
||||
InvalidClientIdError,
|
||||
type AcpSessionBridge,
|
||||
|
|
@ -24,8 +24,8 @@ import {
|
|||
InvalidClientIdError,
|
||||
type AcpSessionBridge,
|
||||
} from './acpSessionBridge.js';
|
||||
import type { BridgeEvent } from './eventBus.js';
|
||||
import { mountWorkspaceMemoryRoutes } from './workspaceMemory.js';
|
||||
import type { BridgeEvent } from './event-bus.js';
|
||||
import { mountWorkspaceMemoryRoutes } from './workspace-memory.js';
|
||||
|
||||
type RecordedEvent = Omit<BridgeEvent, 'id' | 'v'>;
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ import {
|
|||
writeWorkspaceContextFile,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { writeStderrLine } from '../utils/stdioHelpers.js';
|
||||
import { isServeDebugMode } from './debugMode.js';
|
||||
import { isServeDebugMode } from './debug-mode.js';
|
||||
import type { AcpSessionBridge } from './acpSessionBridge.js';
|
||||
import {
|
||||
createIdleWorkspaceMemoryStatus,
|
||||
|
|
@ -159,7 +159,7 @@ export function mountWorkspaceMemoryRoutes(
|
|||
if (clientId === null) return;
|
||||
let originatorClientId: string | undefined;
|
||||
if (clientId !== undefined) {
|
||||
// Mirror the workspaceAgents.ts `resolveOriginatorClientId`
|
||||
// Mirror the workspace-agents.ts `resolveOriginatorClientId`
|
||||
// posture: validate against `bridge.knownClientIds()`, send
|
||||
// 400 directly, return `null` so the caller short-circuits.
|
||||
// Previously this branch threw `InvalidClientIdError` and
|
||||
|
|
@ -15,7 +15,7 @@ import {
|
|||
reduceDaemonEventToTuiUpdates,
|
||||
type DaemonTuiEvent,
|
||||
type DaemonTuiSessionClient,
|
||||
} from './DaemonTuiAdapter.js';
|
||||
} from './daemon-tui-adapter.js';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
|
||||
class EventQueue implements AsyncGenerator<DaemonTuiEvent> {
|
||||
|
|
@ -12,7 +12,7 @@ export default defineConfig({
|
|||
resolve: {
|
||||
alias: {
|
||||
'@qwen-code/qwen-code-core': path.resolve(__dirname, '../core/index.ts'),
|
||||
// cli's daemonStatusProvider.test.ts imports `FakeAgent` /
|
||||
// cli's daemon-status-provider.test.ts imports `FakeAgent` /
|
||||
// `makeChannel` from acp-bridge's package-private
|
||||
// `internal/testUtils` module. This alias overrides the runtime
|
||||
// resolution so vitest reads the .ts source directly instead of
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ function resolveContextFilePath(
|
|||
// appending to a stale `QWEN.md` — clients then observed "I just
|
||||
// wrote content but it's missing from /workspace/memory". Mirrors the
|
||||
// discovery path's `getAllGeminiMdFilenames()` usage in
|
||||
// `workspaceMemory.ts:collectWorkspaceMemoryStatus`.
|
||||
// `workspace-memory.ts:collectWorkspaceMemoryStatus`.
|
||||
const filename = getCurrentGeminiMdFilename();
|
||||
if (scope === 'workspace') {
|
||||
return path.join(projectRoot, filename);
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ function readBudgetFromEnv(): McpBudgetConfig {
|
|||
// operator typos
|
||||
// like `QWEN_SERVE_MCP_CLIENT_BUDGET=abc` previously fell
|
||||
// through silently to "no budget" with zero indication. The
|
||||
// CLI parent (`commands/serve.ts` + `runQwenServe.ts`)
|
||||
// CLI parent (`commands/serve.ts` + `run-qwen-serve.ts`)
|
||||
// validates and throws, but the ACP child process — where
|
||||
// this function runs — has no such validation. Surface a
|
||||
// boot breadcrumb so operators see the misconfiguration in
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|||
|
||||
function isLoopbackHostname(hostname: string): boolean {
|
||||
// Keep this client-side policy aligned with
|
||||
// packages/cli/src/serve/loopbackBinds.ts when daemon bind rules change.
|
||||
// packages/cli/src/serve/loopback-binds.ts when daemon bind rules change.
|
||||
const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
||||
if (normalized === 'localhost' || normalized === '::1') {
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue