Skip to content

Commit 294ea76

Browse files
committed
删除冗余字段
1 parent 1969dae commit 294ea76

111 files changed

Lines changed: 1402 additions & 1419 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/tools.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Coding Code 的工具系统是 Agent 与外部世界交互的核心机制。本
5050
- **Core 工具**:始终可用,在启动时注册。包括上述所有内置工具。
5151
- **MCP 工具**:从 MCP 服务自动导入和注册。名称空间化为 `serverName:toolName` 格式,避免不同服务间的工具名冲突。
5252

53-
Agent 在一次运行开始时注册内置工具、项目 MCP 工具和 `dispatch_agent`。plan 模式通过独立的 `PLAN_MODE_ALLOWED_TOOLS` 策略过滤工具。
53+
Agent 在一次运行开始时注册内置工具、项目 MCP 工具和 `dispatch_agent`。plan 模式通过独立的 `PLAN_PROFILE_ALLOWED_TOOLS` 策略过滤工具。
5454

5555
---
5656

@@ -103,7 +103,7 @@ interface ToolVisibilityPolicy {
103103
|------|------|------|
104104
| 1 | **RuleEngine** | 规则引擎匹配,支持 glob 模式匹配工具名和参数,按优先级排序 |
105105
| 2 | **ReadonlyWhitelist** | 只读工具自动放行(read_file, search_code, search_files, fetch_url, web_search, dispatch_agent, todo_write) |
106-
| 3 | **PermissionMode** | 权限模式判断:`bypass`(全部放行)、`acceptEdits`(非破坏性工具放行)、`default`(继续下一层)。`plan` 模式由独立的 `agent/mode.ts` 中的 `planModeGateHook` 在 Layer 4 强制,不在此层处理 |
106+
| 3 | **PermissionMode** | 权限模式判断:`bypass`(全部放行)、`acceptEdits`(非破坏性工具放行)、`default`(继续下一层)。`plan` Profile 由独立的 `agent/profile.ts` 中的 `planProfileGateHook` 在 Layer 4 强制,不在此层处理 |
107107
| 4 | **HookPreToolUse** | 钩子决策,可返回 allow/deny/ask/continue,支持 `modifiedInput` 修改参数 |
108108
| 5 | **UserConfirmation** | 异步用户确认,支持 allow/deny/always/never 四种响应,always/never 会持久化为规则 |
109109
| 6 | **AuditLog** | 每一层决策后记录审计日志,通过 `tool.approval.post` 钩子发出 |
@@ -134,7 +134,7 @@ type PermissionMode = 'default' | 'acceptEdits' | 'bypass';
134134
- `acceptEdits`:非破坏性工具自动放行,减少确认弹窗
135135
- `bypass`:全部放行,跳过所有审批(慎用)
136136

137-
> `plan` 不再是 `PermissionMode` 的成员。plan 模式通过 `AgentProfile.name === 'plan'` 结构化识别,由 `agent/mode.ts` 的 `planModeGateHook` 和 `PLAN_MODE_ALLOWED_TOOLS` 共同限制工具。
137+
> `plan` 不再是 `PermissionMode` 的成员。plan Profile 通过 `AgentProfile.name === 'plan'` 结构化识别,由 `agent/profile.ts` 的 `planProfileGateHook` 和 `PLAN_PROFILE_ALLOWED_TOOLS` 共同限制工具。
138138
139139
### OS 级沙箱(预留)
140140

‎packages/codingcode/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
"./checkpoint/bootstrap": "./src/checkpoint/bootstrap.ts",
4545
"./llm/factory": "./src/llm/factory.ts",
4646
"./llm/client": "./src/llm/client.ts",
47-
"./layer": "./src/layer.ts"
47+
"./layer": "./src/layer.ts",
48+
"./subagent/types": "./src/subagent/types.ts"
4849
},
4950
"dependencies": {
5051
"@ai-sdk/deepseek": "^2.0.35",

‎packages/codingcode/src/agent/agent.ts‎

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import { ToolRegistry } from '../tools/registry.js';
2424
import { submitPlanTool } from '../tools/domains/subagent/submit-plan.js';
2525
import { createDispatchAgentTool } from '../tools/domains/subagent/dispatch.js';
2626
import { normalizePath } from '../core/path.js';
27-
import { isPlanProfile } from './mode.js';
28-
import type { SessionMode } from '../session/types.js';
27+
import { isPlanProfile } from './profile.js';
28+
import type { AgentProfileName } from '../subagent/types.js';
2929
import type { PermissionMode } from '../approval/types.js';
3030

3131
const REACTIVE_COMPACT_MAX_RETRIES = 3;
@@ -119,7 +119,7 @@ export const sendMessage = (
119119
options: {
120120
signal?: AbortSignal;
121121
approvalOverride?: import('../approval/index.js').ApprovalService;
122-
mode?: SessionMode;
122+
activeProfile?: AgentProfileName;
123123
permissionMode?: PermissionMode;
124124
model?: string;
125125
}
@@ -143,27 +143,28 @@ export const sendMessage = (
143143
yield* skills.evictProject(normalizedCwd);
144144

145145
if (!sessionId) {
146-
if (!options.mode || !options.permissionMode || !options.model) {
146+
if (!options.activeProfile || !options.permissionMode || !options.model) {
147147
return yield* Effect.fail(
148-
new AgentError('CONFIG_MISSING', 'new session requires mode, permissionMode, and model')
148+
new AgentError(
149+
'CONFIG_MISSING',
150+
'new session requires activeProfile, permissionMode, and model'
151+
)
149152
);
150153
}
151-
const created = yield* session.createSessionWithProfile(normalizedCwd, {
154+
const created = yield* session.create(normalizedCwd, {
152155
model: options.model,
153-
mode: options.mode,
156+
activeProfile: options.activeProfile,
154157
permissionMode: options.permissionMode,
155158
});
156159
sessionId = created.sessionId;
157160
}
158161
const state = yield* session.load(normalizedCwd, sessionId);
159-
if (state.activeProfile) {
160-
yield* runtime.restoreSessionProfile(
161-
normalizedCwd,
162-
state.sessionId,
163-
state.activeProfile,
164-
state.permissionMode
165-
);
166-
}
162+
yield* runtime.restoreSessionProfile(
163+
normalizedCwd,
164+
state.sessionId,
165+
state.activeProfile,
166+
state.permissionMode
167+
);
167168
state.memorySnapshot = memory.loadMemoryForPrompt(state.cwd);
168169
const sid = state.sessionId;
169170

@@ -183,8 +184,7 @@ export const sendMessage = (
183184

184185
yield* session.recordUser(state, actualInput);
185186

186-
const turnTitle = actualInput.trim().slice(0, 5) || '(empty)';
187-
yield* checkpoint.snapshotBaseline(state.cwd, sid, turnId, turnTitle);
187+
yield* checkpoint.snapshotBaseline(state.cwd, sid, turnId);
188188

189189
const rulesText = rules.getAllRules(state.cwd);
190190

@@ -269,7 +269,7 @@ export function agentLoop(
269269

270270
for (let attempt = 0; attempt <= maxOverflowRetries; attempt++) {
271271
const payload = yield* Effect.sync(() =>
272-
context.assemblePayload(state.transcriptPath, llm.modelInfo.maxTokens)
272+
context.assemblePayload(session.getTranscriptPath(state), llm.modelInfo.maxTokens)
273273
);
274274
messages = payload.messages;
275275

@@ -293,7 +293,12 @@ export function agentLoop(
293293

294294
const compressResult = yield* Effect.tryPromise({
295295
try: () =>
296-
context.compactIfNeeded(state.transcriptPath, messages, llm.modelInfo.maxTokens, llm),
296+
context.compactIfNeeded(
297+
session.getTranscriptPath(state),
298+
messages,
299+
llm.modelInfo.maxTokens,
300+
llm
301+
),
297302
catch: (e) => new AgentError('LLM_FAILED', String(e)),
298303
});
299304
if (compressResult.didCompress && compressResult.messages) {
@@ -339,7 +344,7 @@ export function agentLoop(
339344
const compressResult = yield* Effect.tryPromise({
340345
try: () =>
341346
context.compactWithLLM(
342-
state.transcriptPath,
347+
session.getTranscriptPath(state),
343348
llm.modelInfo.maxTokens,
344349
llm,
345350
undefined
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,38 @@ export function isPlanProfile(p: { name: string } | null | undefined): boolean {
2222
return p?.name === PLAN_PROFILE_NAME;
2323
}
2424

25-
export const PLAN_MODE_ALLOWED_TOOLS: ReadonlySet<string> = new Set([
25+
export const PLAN_PROFILE_ALLOWED_TOOLS: ReadonlySet<string> = new Set([
2626
'read_file',
2727
'search_files',
2828
'search_code',
2929
'fetch_url',
3030
'submit_plan',
3131
]);
3232

33-
export function isSessionInPlanMode(sessionId: string, cwd: string): boolean {
33+
export function isSessionUsingPlanProfile(sessionId: string, cwd: string): boolean {
3434
try {
3535
const paths = computePaths(cwd, sessionId);
3636
const idx = JSON.parse(readFileSync(paths.indexPath, 'utf8')) as {
37-
mode?: string;
37+
activeProfile?: string;
3838
};
39-
return idx?.mode === 'plan';
39+
return idx?.activeProfile === PLAN_PROFILE_NAME;
4040
} catch {
4141
return false;
4242
}
4343
}
4444

45-
export const planModeGateHook: DecisionHandler = (payload) => {
45+
export const planProfileGateHook: DecisionHandler = (payload) => {
4646
const sessionId = payload.sessionId as string | undefined;
4747
const projectPath = payload.projectPath as string | undefined;
4848
if (!sessionId || !projectPath) return null;
49-
if (!isSessionInPlanMode(sessionId, projectPath)) return null;
49+
if (!isSessionUsingPlanProfile(sessionId, projectPath)) return null;
5050

5151
const toolName = payload.toolName as string | undefined;
5252
if (!toolName) return null;
53-
if (PLAN_MODE_ALLOWED_TOOLS.has(toolName)) return null;
53+
if (PLAN_PROFILE_ALLOWED_TOOLS.has(toolName)) return null;
5454

5555
return {
5656
decision: 'deny',
57-
reason: 'Write operations denied in plan mode. Use submit_plan to submit a plan.',
57+
reason: 'Write operations denied in plan profile. Use submit_plan to submit a plan.',
5858
};
5959
};

‎packages/codingcode/src/agent/prompt.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const PLAN_PROMPT = `You are a planning agent. Your role is to analyze th
6767
6868
You can read files and search code. You can submit a plan via the \`submit_plan\` tool — each call overwrites the previous plan file; use it to revise your plan based on user feedback.
6969
70-
In plan mode, write_file / edit_file / execute_command are denied. The only write operation allowed is \`submit_plan\`.
70+
In plan profile, write_file / edit_file / execute_command are denied. The only write operation allowed is \`submit_plan\`.
7171
7272
## Research process
7373
1. Understand the project structure and conventions

‎packages/codingcode/src/checkpoint/checkpoint-service.ts‎

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,13 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
5151
}
5252

5353
return {
54-
snapshotBaseline: (projectPath: string, sessionId: string, turnId: number, title?: string) =>
54+
snapshotBaseline: (projectPath: string, sessionId: string, turnId: number) =>
5555
Effect.sync(() => {
5656
const sg = ensure(projectPath);
5757
repairIncompleteTurn(sg, sessionId);
5858
if (sg.isTooLargeForSnapshot()) return;
5959
const lock = lockFor(projectPath);
60-
const msg = title
61-
? `${commitMsg(sessionId, turnId, 'baseline')} ${title}`
62-
: commitMsg(sessionId, turnId, 'baseline');
60+
const msg = commitMsg(sessionId, turnId, 'baseline');
6361
lock.lock();
6462
try {
6563
sg.commit(msg);
@@ -90,7 +88,6 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
9088
const completedTurns = getCompletedTurnsFor(sg, sessionId);
9189
const result: Array<{
9290
turnId: number;
93-
title: string;
9491
files: string[];
9592
}> = [];
9693

@@ -100,23 +97,12 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
10097
const fCommit = sg.findCommitByMessage(`${prefix}${i}-final`);
10198
if (!fCommit) continue;
10299

103-
const msgResult = sg.git(
104-
'log',
105-
'--all',
106-
'--grep',
107-
`${prefix}${i}-baseline`,
108-
'--format=%s',
109-
'-1'
110-
);
111-
const fullMsg = msgResult.stdout.trim();
112-
const title = fullMsg.includes(' ') ? fullMsg.split(' ').slice(1).join(' ') : '';
113-
114100
const allChanges = sg.diffFiles(bCommit, fCommit);
115101
const files = [
116102
...new Set(allChanges.map((c) => normalizePath(resolve(projectPath, c.file)))),
117103
];
118104

119-
result.push({ turnId: i, title, files });
105+
result.push({ turnId: i, files });
120106
}
121107
return result;
122108
}),

‎packages/codingcode/src/cli.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ async function main() {
3838

3939
if (tuiOnly) {
4040
const tuiPath = '../../tui/src/index.js';
41-
const { runTui, createTuiClientFromFacades } = yield* Effect.tryPromise(() =>
42-
import(tuiPath)
41+
const { runTui, createTuiClientFromFacades } = yield* Effect.tryPromise(
42+
() => import(tuiPath)
4343
);
4444
const llm = yield* llmFactory.getLLMClient();
4545
const client = createTuiClientFromFacades(llm, rt);
@@ -53,8 +53,8 @@ async function main() {
5353

5454
if (!serveOnly) {
5555
const tuiPath = '../../tui/src/index.js';
56-
const { runTui, createTuiClientFromFacades } = yield* Effect.tryPromise(() =>
57-
import(tuiPath)
56+
const { runTui, createTuiClientFromFacades } = yield* Effect.tryPromise(
57+
() => import(tuiPath)
5858
);
5959
const llm = yield* llmFactory.getLLMClient();
6060
const client = createTuiClientFromFacades(llm, rt);

‎packages/codingcode/src/client/http/agent-runtime.ts‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface AgentRuntimeClient {
1515
}): Promise<void>;
1616
compact(input: { sessionId: string; cwd: string }): Promise<void>;
1717

18-
getCheckpoints(): Promise<Array<{ turnId: number; title: string; files: string[] }>>;
18+
getCheckpoints(): Promise<Array<{ turnId: number; files: string[] }>>;
1919
getCheckpointDiff(turnId?: number): Promise<import('../../checkpoint/types.js').CheckpointDiff>;
2020
revertCheckpointFiles(
2121
turnId: number,
@@ -27,9 +27,7 @@ export interface AgentRuntimeClient {
2727
rollbackCodeToTurn(
2828
throughTurnId: number
2929
): Promise<import('../../checkpoint/types.js').CodeRollbackResult>;
30-
rollbackContext(
31-
throughTurnId: number
32-
): Promise<{
30+
rollbackContext(throughTurnId: number): Promise<{
3331
turns: Array<{ id: string; items: object[]; status: string }>;
3432
rollbackState: import('../../checkpoint/types.js').RollbackState;
3533
}>;
@@ -43,9 +41,7 @@ export interface AgentRuntimeClient {
4341
files?: string[]
4442
): Promise<import('../../checkpoint/types.js').CodeRollbackUndoResult>;
4543
getRollbackState(): Promise<import('../../checkpoint/types.js').RollbackState>;
46-
forkSession(
47-
atTurnId?: number
48-
): Promise<{
44+
forkSession(atTurnId?: number): Promise<{
4945
sessionId: string;
5046
turns: Array<{ id: string; items: object[]; status: string }>;
5147
}>;

‎packages/codingcode/src/client/http/sessions.ts‎

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,32 @@ import type {
66
RollbackPreviewDiff,
77
RollbackState,
88
} from '../../checkpoint/types.js';
9-
import type { SessionEvent, SessionIndex, SessionMode } from '../../session/types.js';
9+
import type { SessionEvent, SessionIndex } from '../../session/types.js';
10+
import type { AgentProfileName } from '../../subagent/types.js';
1011
import type { createRequestHelpers } from './request.js';
1112

1213
export interface SessionClient {
1314
createSession(input: {
1415
cwd: string;
15-
mode: SessionMode;
16+
activeProfile: AgentProfileName;
1617
permissionMode: PermissionMode;
1718
model: string;
1819
}): Promise<{ sessionId: string }>;
1920
resumeSession(input: { sessionId: string; cwd: string }): Promise<SessionEvent[]>;
2021
listSessions(input: { cwd: string }): Promise<SessionIndex[]>;
2122
getSessionHistory(input: { sessionId: string; cwd: string }): Promise<SessionEvent[]>;
2223
deleteSession(input: { sessionId: string; cwd: string }): Promise<void>;
23-
getSessionMode(input: { sessionId: string; cwd: string }): Promise<{
24-
mode: SessionMode;
24+
getSessionProfile(input: { sessionId: string; cwd: string }): Promise<{
25+
activeProfile: AgentProfileName;
2526
permissionMode: PermissionMode;
2627
cwd: string;
2728
available: Array<{ name: string; description: string }>;
2829
}>;
29-
setSessionMode(input: {
30+
setSessionProfile(input: {
3031
sessionId: string;
3132
cwd: string;
32-
mode: SessionMode;
33-
}): Promise<{ mode: SessionMode; permissionMode: PermissionMode }>;
33+
activeProfile: AgentProfileName;
34+
}): Promise<{ activeProfile: AgentProfileName; permissionMode: PermissionMode }>;
3435
getSessionPermissionMode(input: { sessionId: string; cwd: string }): Promise<PermissionMode>;
3536
setSessionPermissionMode(input: {
3637
sessionId: string;
@@ -92,8 +93,8 @@ export function createHttpSessionClient(
9293
const { apiGet, apiPost, apiPut, apiDelete } = request;
9394

9495
return {
95-
async createSession({ cwd, mode, permissionMode, model }) {
96-
return apiPost('/api/sessions', { cwd, mode, permissionMode, model });
96+
async createSession({ cwd, activeProfile, permissionMode, model }) {
97+
return apiPost('/api/sessions', { cwd, activeProfile, permissionMode, model });
9798
},
9899

99100
async resumeSession({ sessionId, cwd }) {
@@ -115,12 +116,12 @@ export function createHttpSessionClient(
115116
await apiDelete(`/api/sessions/${sessionId}?cwd=${encodeURIComponent(cwd)}`);
116117
},
117118

118-
async getSessionMode({ sessionId, cwd }) {
119-
return apiGet(`/api/sessions/${sessionId}/mode?cwd=${encodeURIComponent(cwd)}`);
119+
async getSessionProfile({ sessionId, cwd }) {
120+
return apiGet(`/api/sessions/${sessionId}/profile?cwd=${encodeURIComponent(cwd)}`);
120121
},
121122

122-
async setSessionMode({ sessionId, cwd, mode }) {
123-
return apiPost(`/api/sessions/${sessionId}/mode`, { cwd, mode });
123+
async setSessionProfile({ sessionId, cwd, activeProfile }) {
124+
return apiPost(`/api/sessions/${sessionId}/profile`, { cwd, activeProfile });
124125
},
125126

126127
async getSessionPermissionMode({ sessionId, cwd }) {
@@ -135,9 +136,7 @@ export function createHttpSessionClient(
135136
},
136137

137138
async getSessionPlan({ sessionId, cwd }) {
138-
return apiGet(
139-
`/api/sessions/${sessionId}/plan?cwd=${encodeURIComponent(cwd)}`
140-
);
139+
return apiGet(`/api/sessions/${sessionId}/plan?cwd=${encodeURIComponent(cwd)}`);
141140
},
142141

143142
async getCheckpointDiff({ sessionId, cwd, turnId }) {

‎packages/codingcode/src/client/types.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export interface AgentClient {
4040
listModels(): Promise<{ models: SelectableModel[]; activeId: string | null }>;
4141
switchModel(id: string): Promise<void>;
4242
getSessionId(): string;
43-
getCheckpoints(): Promise<Array<{ turnId: number; title: string; files: string[] }>>;
43+
getCheckpoints(): Promise<Array<{ turnId: number; files: string[] }>>;
4444
getCheckpointDiff(turnId?: number): Promise<CheckpointDiff>;
4545
revertCheckpointFiles(turnId: number, files: string[]): Promise<CodeRollbackResult>;
4646
previewRollbackDiff(throughTurnId: number): Promise<RollbackPreviewDiff>;

0 commit comments

Comments
 (0)