Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
18772ed
refactor(cli): keep acp-integration off serve internals (#8084)
yiliang114 Aug 14, 2026
99a1172
Merge remote-tracking branch 'origin/main' into HEAD
yiliang114 Aug 14, 2026
0691cb9
fix(cli): harden the acp/serve boundary guard (round 2)
yiliang114 Aug 14, 2026
ac83137
test(cli): pin serve boundary lint rules
yiliang114 Aug 15, 2026
ec63477
test(cli): close serve boundary lint gaps
yiliang114 Aug 15, 2026
78ead13
fix(lint): close serve-boundary entrances and harden the guard
yiliang114 Aug 15, 2026
17d16d5
fix(lint): correct TSImportType selector path and computed-template h…
yiliang114 Aug 15, 2026
4abaca1
fix(lint): close the remaining round-6 serve-boundary entrances
yiliang114 Aug 15, 2026
6f7a13d
fix(lint): cover vitest serve-boundary calls
yiliang114 Aug 15, 2026
0c8c334
fix(lint): close the round-7 serve-boundary entrance classes
yiliang114 Aug 15, 2026
1815694
refactor(lint): resolve the serve boundary by resolution, not text (#…
yiliang114 Aug 16, 2026
23cf025
Merge branch 'main' into fix/acp-serve-boundary-guard
yiliang114 Aug 16, 2026
02e502a
fix(lint): drop the dead serveGuardSyntaxRules helper
yiliang114 Aug 16, 2026
3d8be1f
fix(lint): close serve boundary resolver gaps
yiliang114 Aug 16, 2026
3cc4298
fix(lint): address serve boundary review suggestions
yiliang114 Aug 16, 2026
cf05dd5
fix(lint): close round-11 serve boundary gaps
yiliang114 Aug 16, 2026
34fc045
chore: merge main into serve boundary guard
yiliang114 Aug 16, 2026
2d59792
fix(cli): restore live session source import
yiliang114 Aug 16, 2026
3da80b9
fix(lint): clear the two lint errors breaking CI on the boundary rule
yiliang114 Aug 16, 2026
c4758e3
fix(lint): close bounded serve boundary gaps
yiliang114 Aug 16, 2026
7112ab4
fix(lint): complete the round-12 boundary escape closures
yiliang114 Aug 16, 2026
552bc7c
fix(lint): close the round-12 reviewer escape classes (#8084)
yiliang114 Aug 17, 2026
c11b30c
fix(lint): repair corrupted files from the git-API blob upload
yiliang114 Aug 17, 2026
8e583a8
Merge remote-tracking branch 'origin/main' into HEAD
yiliang114 Aug 17, 2026
ebe1cb5
fix(lint): close the round-13 serve-boundary escape classes (#8084)
yiliang114 Aug 17, 2026
9fbd906
fix(lint): close the round-13 binding-hop and callee-opacity escapes …
yiliang114 Aug 18, 2026
58d4398
refactor(cli): simplify ACP serve boundary guard
yiliang114 Aug 19, 2026
ff4e3b0
Merge remote-tracking branch 'origin/main' into codex/pr-9144-scope-back
yiliang114 Aug 20, 2026
210b2e1
fix(lint): close the round-21 contract pins and bare-barrel escape (#…
yiliang114 Aug 20, 2026
01475ab
fix(lint): close dynamic-import and js-file holes in the acp/serve gu…
yiliang114 Aug 22, 2026
5e7511a
fix(lint): make acp/serve dynamic-import guard case-insensitive
yiliang114 Aug 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ export default tseslint.config(
'import/namespace': 'off', // Disabled due to https://github.com/import-js/eslint-plugin-import/issues/2866
},
},
{
// ACP integration and the daemon are separate runtime surfaces that happen
// to share a package directory. ACP may consume neutral contracts under
// `runtime/`, but never `serve/` implementation modules — see #8084.
files: ['packages/cli/src/acp-integration/**/*.{ts,tsx}'],
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
rules: {
'no-restricted-imports': [
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
'error',
{
patterns: [
{
group: ['**/serve', '**/serve/*', '**/serve/**'],
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
message:
'acp-integration must not import serve/ internals. Put shared, lifecycle-free logic in packages/cli/src/runtime/ instead (#8084).',
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
},
],
},
],
},
},
{
// `utils/` is the layer every other directory imports, so it must not
// import back into one. The daemon direction is clean and enforced here;
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/acp-integration/acpAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ import {
type PermissionRuleSet,
} from '../config/permission-settings.js';
import { createLoadedSettingsAdapter } from '../config/loadedSettingsAdapter.js';
import { isCompatibleLiveSessionSource } from '../serve/conversations/session-source.js';
import { isCompatibleLiveSessionSource } from '../runtime/live-session-source.js';
import type { ApprovalModeValue } from './session/types.js';
import { z } from 'zod';
import type { CliArgs } from '../config/config.js';
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/acp-integration/session/Session.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ import * as nonInteractiveCliCommands from '../../nonInteractiveCliCommands.js';
import { CommandKind } from '../../ui/commands/types.js';
import { buildAcpModelOptions } from '../../utils/acpModelUtils.js';
import { CHANNEL_PROMPT_META_KEY } from '@qwen-code/channel-base';
import { CAPTURE_SCREEN_CONTEXT_TOOL_NAME } from '../../serve/live/capture-screen-context.js';
import { SPEAK_TO_USER_TOOL_NAME } from '../../serve/live/live-speak-to-user.js';
import { CAPTURE_SCREEN_CONTEXT_TOOL_NAME } from '../live/capture-screen-context.js';
import { SPEAK_TO_USER_TOOL_NAME } from '../live/live-speak-to-user.js';
import {
collectHistoryReplayUpdates,
createReplayCumulativeUsage,
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/acp-integration/session/Session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,19 +223,19 @@ import { normalizeChannelDeliveryText } from '../../runtime/channel-delivery.js'
import {
CAPTURE_SCREEN_CONTEXT_TOOL_NAME,
CaptureScreenContextTool,
} from '../../serve/live/capture-screen-context.js';
} from '../live/capture-screen-context.js';
import {
createLiveTaskTools,
type LiveTaskTool,
} from '../../serve/live/live-task-tools.js';
} from '../live/live-task-tools.js';
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
import {
SPEAK_TO_USER_TOOL_NAME,
SpeakToUserTool,
} from '../../serve/live/live-speak-to-user.js';
} from '../live/live-speak-to-user.js';
import {
LIVE_BACKEND_END_INSTRUCTIONS,
LIVE_BACKEND_START_INSTRUCTIONS,
} from '../../serve/live/live-backend-instructions.js';
} from '../live/live-backend-instructions.js';
import { readVoiceModel } from '../../services/voice-settings.js';
import {
MAX_AUDIO_BYTES,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
readLoadableLiveConversationMetadata,
type ConversationSessionMetadataStore,
type LiveSessionCreationMetadata,
} from './session-source.js';
} from './live-session-source.js';

const LIVE_ID = '550e8400-e29b-41d4-a716-446655440000';
const LIVE_CHILD_ID = '550e8400-e29b-41d4-a716-446655440001';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import {
isValidSessionId,
normalizeSessionIdForLookup,
} from '../../config/session-id.js';
} from '../config/session-id.js';

export const LIVE_SESSION_SOURCE_PREFIX = 'realtime_voice:';
export const STANDALONE_SESSION_SOURCE_TYPE = 'standalone';
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/serve/acp-http/dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import {
isReservedLiveSessionSource,
isReservedStandaloneSessionSource,
readLoadableLiveConversationMetadata,
} from '../conversations/session-source.js';
} from '../../runtime/live-session-source.js';
import {
translateAndCheckAbsoluteWorkspacePath,
canonicalizeWorkspace,
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/serve/live/live-session-coordinator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ import type { LiveProviderCredential } from './provider-credentials.js';
import {
isCompatibleLiveSessionSource,
LIVE_SESSION_SOURCE_PREFIX,
} from '../conversations/session-source.js';
} from '../../runtime/live-session-source.js';
import type { LiveProviderReadiness, LiveSessionLocator } from './types.js';

export { LIVE_SESSION_SOURCE_PREFIX } from '../conversations/session-source.js';
export { LIVE_SESSION_SOURCE_PREFIX } from '../../runtime/live-session-source.js';

const MAX_COORDINATOR_REQUEST_CHARS = 32_000;
const MAX_COORDINATOR_RESULT_CHARS = 48_000;
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/serve/live/live-task-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
WorkspaceRuntime,
} from '../workspace-registry.js';
import { isLiveTaskToolName, LiveTaskService } from './live-task-service.js';
import { LIVE_SESSION_SOURCE_PREFIX } from '../conversations/session-source.js';
import { LIVE_SESSION_SOURCE_PREFIX } from '../../runtime/live-session-source.js';

const persistedSessions = vi.hoisted(() => new Map<string, unknown>());
const persistedSessionOwners = vi.hoisted(() => new Map<string, string>());
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/serve/live/live-task-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { laterActivityTimestamp } from '../server/activity-timestamp.js';
import {
isCompatibleLiveSessionSource,
readLoadableLiveConversationMetadata,
} from '../conversations/session-source.js';
} from '../../runtime/live-session-source.js';
import { conversationRuntimeUnavailableError } from '../conversations/conversation-runtime-errors.js';

const DEFAULT_LIST_LIMIT = 20;
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/serve/multi-workspace-sessions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
} from './workspace-registry.js';
import type { WorkspaceRuntimeProvenance } from './managed-scratch-workspace.js';
import type { ConversationWorkspace } from './conversations/conversation-workspace.js';
import { LIVE_SESSION_SOURCE_PREFIX } from './conversations/session-source.js';
import { LIVE_SESSION_SOURCE_PREFIX } from '../runtime/live-session-source.js';
import { createSessionOrganizationService } from './session-organization-helpers.js';
import {
serializeWorkspaceTranscriptResponseForTesting,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/serve/routes/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
isReservedLiveSessionSource,
isReservedStandaloneSessionSource,
readLoadableLiveConversationMetadata,
} from '../conversations/session-source.js';
} from '../../runtime/live-session-source.js';
import type { ConversationRuntimeActivityGate } from '../conversations/conversation-runtime-activity.js';
import { ConversationRuntimeOwnershipError } from '../conversations/conversation-runtime-errors.js';
import express, {
Expand Down
58 changes: 58 additions & 0 deletions scripts/tests/acp-serve-boundary-guard.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/

import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { ESLint } from 'eslint';
import { expect, it } from 'vitest';

const root = join(dirname(fileURLToPath(import.meta.url)), '../..');

const eslint = new ESLint({ cwd: root });

async function restrictedReports(statement) {
const filePath = join(
root,
'packages/cli/src/acp-integration/boundary-probe.ts',
);
const [result] = await eslint.lintText(`${statement}\n`, { filePath });
return result.messages.filter((m) => m.ruleId === 'no-restricted-imports');
}

// Bare-directory specifiers resolve to packages/cli/src/serve/index.ts, a
// barrel re-exporting the full daemon surface — they must be caught by the
// same guard that blocks deep serve/ internals (#8084).
it.each(['../serve', '../../serve'])(
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
'blocks the bare barrel specifier %s from acp-integration',
async (specifier) => {
const reports = await restrictedReports(
`import { createServeApp } from '${specifier}';`,
);
expect(reports).toHaveLength(1);
expect(reports[0].message).toContain('acp-integration');
},
);

it('blocks a bare barrel re-export from acp-integration', async () => {
const reports = await restrictedReports(
`export { createServeApp } from '../serve';`,
);
expect(reports).toHaveLength(1);
});

it('still blocks deep serve/ internals from acp-integration', async () => {
const reports = await restrictedReports(
`import { createServeApp } from '../serve/index.js';`,
);
expect(reports).toHaveLength(1);
});

it('allows neutral runtime/ contracts from acp-integration', async () => {
const reports = await restrictedReports(
`import { something } from '../runtime/contracts.js';`,
);
expect(reports).toHaveLength(0);
});
4 changes: 2 additions & 2 deletions scripts/tests/cross-package-contracts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const imports = [
],
[
'LIVE_TASK_TOOL_NAMES',
'packages/cli/src/serve/live/live-task-tools.ts',
'packages/cli/src/acp-integration/live/live-task-tools.ts',
'@qwen-code/acp-bridge/bridgeOptions',
],
[
Expand All @@ -65,7 +65,7 @@ const imports = [
],
[
'LiveTaskToolName',
'packages/cli/src/serve/live/live-task-tools.ts',
'packages/cli/src/acp-integration/live/live-task-tools.ts',
'@qwen-code/acp-bridge/bridgeOptions',
],
[
Expand Down
Loading