fix(ext): !stop CancelCascadeInvocation RPC — AG 빨간■ 동일 메커니즘 적용 #task-411
This commit is contained in:
@@ -43,12 +43,10 @@
|
||||
### [2026-03-11] rejectAgentStep — AG 미등록 VS Code 커맨드
|
||||
- **증상**: `/stop` 및 거부 시 `antigravity.agent.rejectAgentStep` → `command not found`
|
||||
- **원인**: AG IDE가 이 커맨드를 런타임에 등록하지 않음 (상수 정의만 존재)
|
||||
- **해결** (2026-03-18): `command-handler.ts`의 `!stop` 핸들러를 `sdk.cascade.cancelCurrentTask()`로 교체.
|
||||
WS 경로는 이미 SDK 사용 중이었으므로 file-based 경로만 수정.
|
||||
- `CancelCascadeInvocation` gRPC 메서드도 사용 가능 (cascade_id 필요)
|
||||
- **E2E 검증 필요** — AG 가동 중 `!stop` 명령 테스트
|
||||
- **주의**: `sdk.cascade.rejectStep()`은 여전히 내부적으로 `rejectAgentStep` 커맨드를 호출할 수 있음.
|
||||
단일 step 거부보다 `cancelCurrentTask()`(전체 중단)가 더 안정적.
|
||||
- **해결** (2026-03-18): `_cancelCurrentCascade()` 헬퍼 추가 — `sdk.titles.getActiveCascadeId()` → `ls.cancelCascade(cascadeId)` (CancelCascadeInvocation RPC).
|
||||
AG의 빨간색 ■ 버튼과 동일한 메커니즘. rawRPC fallback 포함.
|
||||
- ~~`sdk.cascade.cancelCurrentTask()` — SDK에 존재하지 않는 메서드, 무시됨~~
|
||||
- **주의**: `getActiveCascadeId()`가 null이면 취소 불가 — 로그로 확인 필요
|
||||
- **Vikunja**: #411
|
||||
|
||||
---
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
|---|------|------|------|------|
|
||||
| 001 | 06:09~06:26 | known-issues 정리/아카이빙 + Collector 폐기 마킹 + 문서 보강 (architecture, tech-stack, conventions) | `881a424` | ✅ |
|
||||
| 002 | 06:33~06:50 | Hub/WS 단위 테스트 45개 작성 (연결 관리, pending_owners, 라우팅, 인증) | `ac803d4` | ✅ |
|
||||
| 003 | 06:50~07:00 | rejectAgentStep 대안 조사 — CancelCascadeInvocation RPC 발견 | `bcca706` | 🔧 |
|
||||
| 003 | 06:50~07:05 | !stop 핸들러 SDK cancelCurrentTask() 교체 + VSIX 재빌드/설치 | `759dab5` | ✅ |
|
||||
| 004 | 07:03~07:15 | !stop 재수정 — cancelCurrentTask→CancelCascadeInvocation RPC (AG 빨간■ 동일) + VSIX 설치 | `8d5940b` | ✅ |
|
||||
|
||||
@@ -435,7 +435,7 @@ async function activate(context) {
|
||||
onCommand: (data) => {
|
||||
logToFile(`[WS-CMD] ${data.text?.substring(0, 50)}`);
|
||||
(0, command_handler_1.handleWSCommand)({
|
||||
bridgePath, projectName, sdk, autoApproveEnabled, logToFile,
|
||||
bridgePath, projectName, sdk, ls: sdk?.ls, autoApproveEnabled, logToFile,
|
||||
onAutoApproveChanged: (enabled) => { autoApproveEnabled = enabled; },
|
||||
recentDiscordSentTexts,
|
||||
}, data);
|
||||
@@ -558,7 +558,7 @@ async function activate(context) {
|
||||
}
|
||||
// Watch commands directory
|
||||
(0, command_handler_1.watchCommandsDir)({
|
||||
bridgePath, projectName, sdk, autoApproveEnabled, logToFile,
|
||||
bridgePath, projectName, sdk, ls: sdk?.ls, autoApproveEnabled, logToFile,
|
||||
onAutoApproveChanged: (enabled) => { autoApproveEnabled = enabled; },
|
||||
recentDiscordSentTexts,
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -17,6 +17,8 @@ export interface CommandHandlerContext {
|
||||
bridgePath: string;
|
||||
projectName: string;
|
||||
sdk: any;
|
||||
/** LSBridge instance for direct LS RPC calls (cancelCascade, etc.) */
|
||||
ls: any;
|
||||
autoApproveEnabled: boolean;
|
||||
logToFile: (msg: string) => void;
|
||||
/** Called when auto-approve is toggled; extension.ts updates its own state */
|
||||
@@ -93,9 +95,7 @@ export function handleWSCommand(ctx: CommandHandlerContext, data: { text?: strin
|
||||
|
||||
if (text === '!stop') {
|
||||
ctx.logToFile('[WS-CMD] !stop — cancelling AG task');
|
||||
if (ctx.sdk) {
|
||||
try { ctx.sdk.cascade.cancelCurrentTask(); } catch { }
|
||||
}
|
||||
_cancelCurrentCascade(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,6 +122,42 @@ export function handleWSCommand(ctx: CommandHandlerContext, data: { text?: strin
|
||||
|
||||
// ─── Private ───
|
||||
|
||||
/**
|
||||
* Cancel the currently active cascade via CancelCascadeInvocation RPC.
|
||||
* This is the same mechanism AG's native red ■ stop button uses.
|
||||
*/
|
||||
async function _cancelCurrentCascade(ctx: CommandHandlerContext) {
|
||||
// 1. Get the active cascade ID from SDK titles manager
|
||||
const cascadeId = ctx.sdk?.titles?.getActiveCascadeId?.();
|
||||
if (!cascadeId) {
|
||||
ctx.logToFile('[STOP] No active cascade to cancel (getActiveCascadeId returned null)');
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.logToFile(`[STOP] Cancelling cascade: ${cascadeId.substring(0, 12)}...`);
|
||||
|
||||
// 2. Use LSBridge.cancelCascade() → CancelCascadeInvocation RPC
|
||||
if (ctx.ls) {
|
||||
try {
|
||||
await ctx.ls.cancelCascade(cascadeId);
|
||||
ctx.logToFile(`[STOP] ✅ CancelCascadeInvocation sent for ${cascadeId.substring(0, 12)}`);
|
||||
return;
|
||||
} catch (e: any) {
|
||||
ctx.logToFile(`[STOP] LSBridge cancelCascade failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback: try rawRPC directly via sdk.ls
|
||||
if (ctx.sdk?.ls?.rawRPC) {
|
||||
try {
|
||||
await ctx.sdk.ls.rawRPC('CancelCascadeInvocation', { cascadeId });
|
||||
ctx.logToFile(`[STOP] ✅ rawRPC CancelCascadeInvocation sent for ${cascadeId.substring(0, 12)}`);
|
||||
} catch (e: any) {
|
||||
ctx.logToFile(`[STOP] rawRPC fallback also failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _processCommandFile(filePath: string, ctx: CommandHandlerContext) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
@@ -158,15 +194,8 @@ function _processCommandFile(filePath: string, ctx: CommandHandlerContext) {
|
||||
console.log(`Gravity Bridge: approve_terminal error: ${e.message}`)
|
||||
);
|
||||
} else if (text === '!stop') {
|
||||
// Cancel current operation — use SDK (rejectAgentStep is NOT a registered VS Code command)
|
||||
if (ctx.sdk) {
|
||||
try {
|
||||
ctx.sdk.cascade.cancelCurrentTask();
|
||||
console.log('Gravity Bridge: ✅ stop sent via SDK');
|
||||
} catch (e: any) {
|
||||
console.log(`Gravity Bridge: stop error: ${e.message}`);
|
||||
}
|
||||
}
|
||||
// Cancel current operation — use CancelCascadeInvocation RPC (same as AG's red ■ button)
|
||||
_cancelCurrentCascade(ctx);
|
||||
} else if (text.startsWith('!auto')) {
|
||||
// Auto-approve mode toggle
|
||||
let enabled: boolean;
|
||||
|
||||
@@ -366,6 +366,7 @@ let sawRunningAfterPending = true;
|
||||
// ─── Step Probe, Response Watcher, Approval Strategies → extracted to ./step-probe.ts ───
|
||||
|
||||
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
console.log('Gravity Bridge: activating...');
|
||||
|
||||
@@ -426,7 +427,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
onCommand: (data: WSCommandData) => {
|
||||
logToFile(`[WS-CMD] ${data.text?.substring(0, 50)}`);
|
||||
handleWSCommand({
|
||||
handleWSCommand({
|
||||
bridgePath, projectName, sdk, ls: sdk?.ls, autoApproveEnabled, logToFile,
|
||||
onAutoApproveChanged: (enabled: boolean) => { autoApproveEnabled = enabled; },
|
||||
recentDiscordSentTexts,
|
||||
}, data);
|
||||
@@ -555,7 +556,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Watch commands directory
|
||||
watchCommandsDir({
|
||||
watchCommandsDir({
|
||||
bridgePath, projectName, sdk, ls: sdk?.ls, autoApproveEnabled, logToFile,
|
||||
onAutoApproveChanged: (enabled: boolean) => { autoApproveEnabled = enabled; },
|
||||
recentDiscordSentTexts,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user