> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 권한 요청

> Laravel Copilot SDK의 권한 요청을 기본값, 내장 핸들러, 커스텀 승인 콜백으로 제어합니다.

## 권한 요청

## 기본 동작(`deny-all`)

`config/copilot.php`의 `permission_approve`가 `"deny-all"`(기본값)인 경우, `Copilot::run()`이나 `Copilot::start()`에서는 권한 요청이 자동으로 **거부**됩니다.

텍스트 생성 중심의 용도에서는 권한이 필요 없는 경우가 많으므로 안전한 기본값입니다.

```php theme={null}
// config/copilot.php
'permission_approve' => env('COPILOT_PERMISSION_APPROVE', 'deny-all'),
```

## 설정 가능한 값

| 값                  | 동작                                            |
| ------------------ | --------------------------------------------- |
| `"deny-all"`       | 모두 자동 거부(**기본값**)                             |
| `"approve-safety"` | `shell`과 `write`만 거부하고 나머지는 자동 허용             |
| `"approve-all"`    | 모두 자동 허용                                      |
| `false`            | 핸들러 없음. `onPermissionRequest`가 필수(공식 SDK와 동일) |

```php theme={null}
// .env
COPILOT_PERMISSION_APPROVE="approve-safety"
```

<Warning>
  사용자 입력 프롬프트를 받는 경우, `"approve-safety"`와 `"approve-all"`은 위험합니다.
  반드시 `false` 또는 `"deny-all"`을 사용해 주세요.
  read-only 권한이라도 Laravel 프로젝트의 코드가 읽힐 가능성이 있습니다.
</Warning>

## `PermissionHandler::approveAll()`

`PermissionHandler::approveAll()`은 모든 요청을 자동 허용합니다.

```php theme={null}
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Support\PermissionHandler;
use Revolution\Copilot\Types\SessionConfig;

$config = new SessionConfig(
    onPermissionRequest: PermissionHandler::approveAll(),
);

$response = Copilot::run(prompt: 'Hello', config: $config);
```

## `PermissionHandler::approveSafety()`

`PermissionHandler::approveSafety()`는 고위험 권한(`shell`, `write`)만 거부하고 나머지는 자동 허용합니다.

```php theme={null}
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Support\PermissionHandler;
use Revolution\Copilot\Types\SessionConfig;

$config = new SessionConfig(
    onPermissionRequest: PermissionHandler::approveSafety(),
);

$response = Copilot::run(prompt: 'Hello', config: $config);
```

이것이라고 해서 완전히 안전한 것은 아닙니다.
엄밀히 제어하려면 커스텀 핸들러를 구현해 `$request['kind']`를 보고 판정하세요.

## `PermissionHandler::denyAll()`

`PermissionHandler::denyAll()`은 모두 거부합니다.

```php theme={null}
use Revolution\Copilot\Support\PermissionHandler;
use Revolution\Copilot\Types\SessionConfig;

$config = new SessionConfig(
    onPermissionRequest: PermissionHandler::denyAll(),
);
```

## Client를 직접 사용하는 경우

`CopilotClient`를 직접 사용할 경우, 공식 SDK와 마찬가지로 `onPermissionRequest`의 지정이 **필수**입니다.

```php theme={null}
use Revolution\Copilot\Client;
use Revolution\Copilot\Support\PermissionHandler;

$client = new Client([
    'cli_path' => 'copilot',
    'cli_args' => [],
    'cwd' => base_path(),
    'log_level' => 'info',
    'env' => null,
]);
$client->start();

// onPermissionRequest는 필수
$session = $client->createSession([
    'onPermissionRequest' => PermissionHandler::approveSafety(),
]);

// 생략하면 InvalidArgumentException
// $session = $client->createSession([]); // Error!
```

## 커스텀 핸들러

요청 종류별로 허용/거부를 제어하려면 클로저를 전달합니다.
`$request`와 `$invocation`은 다음과 같은 배열입니다.

```php theme={null}
use Illuminate\Support\Facades\Artisan;
use Revolution\Copilot\Contracts\CopilotSession;
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Support\PermissionRequestResultKind;
use Revolution\Copilot\Types\SessionConfig;

use function Laravel\Prompts\{confirm, note, spin, text};

Artisan::command('copilot:chat', function () {
    $config = new SessionConfig(
        onPermissionRequest: function (array $request, array $invocation) {
            $confirm = confirm(
                label: 'Do you accept the requested permissions?',
            );
            if ($confirm) {
                return PermissionRequestResultKind::approveOnce();
            } else {
                return PermissionRequestResultKind::reject();
            }
        },
    );

    Copilot::start(function (CopilotSession $session) use ($config) {
        while (true) {
            $prompt = text(
                label: 'Enter your prompt',
                placeholder: 'Ask me anything...',
                required: true,
                hint: 'Ctrl+C to exit',
            );

            $response = spin(
                callback: fn () => $session->sendAndWait($prompt),
                message: 'Waiting for Copilot response...',
            );

            note($response->content());
        }
    }, config: $config);
});
```

### `$request`

`kind`와 `toolCallId` 외의 필드는 `kind`에 따라 달라집니다.

```text theme={null}
kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "memory" | "hook"
```

```php theme={null}
[
  "kind" => "shell",
  "toolCallId" => "toolu_...",
  "fullCommandText" => "...",
  "intention" => "Run copilot:ping to test permission request",
  "commands" => [
    [
      "identifier" => "bash",
      "readOnly" => false,
    ]
  ]
  "possiblePaths" => [],
  "possibleUrls" => [],
  "hasWriteFileRedirection" => false,
  "canOfferSessionApproval" => false,
]
```

### `$invocation`

```php theme={null}
[
  "sessionId" => "...",
]
```

## Response

권한 판정 결과는 배열로 반환합니다.
`PermissionRequestResultKind` 클래스를 사용하면 가독성이 좋아집니다.

```php theme={null}
return PermissionRequestResultKind::approveOnce();
return PermissionRequestResultKind::reject();
```

## 프로토콜 세부

Protocol v3(현재의 기본값)에서는 권한 요청이 JSON-RPC 요청이 아니라 세션 이벤트(`permission.requested`)로 전달됩니다.
SDK는 내부에서 이를 처리하고 `session.permissions.handlePendingPermissionRequest` RPC로 응답합니다.

**`SessionConfig`의 사용법은 변하지 않습니다.**
`onPermissionRequest`에 핸들러를 전달하면 프로토콜 차이는 SDK가 흡수합니다.

## PermissionRequestResultKind

`['kind' => 'approve-once']` 형식으로 직접 반환할 수도 있지만, `PermissionRequestResultKind`를 사용하면 이해하기 쉬워집니다.

```php theme={null}
use Revolution\Copilot\Support\PermissionRequestResultKind;

$confirm = confirm(
    label: 'Do you accept the requested permissions?',
);

if ($confirm) {
    return PermissionRequestResultKind::approveOnce();
} else {
    return PermissionRequestResultKind::reject();
}
```

### 사용 가능한 메서드

| 메서드                    | 값                      | 설명                              |
| ---------------------- | ---------------------- | ------------------------------- |
| `approveOnce()`        | `approve-once`         | 이번 요청만 허용                       |
| `approveForSession()`  | `approve-for-session`  | 이 세션 중의 동종 요청을 모두 허용            |
| `approveForLocation()` | `approve-for-location` | 이 위치(파일 경로 등)에서의 동종 요청을 모두 허용   |
| `reject()`             | `reject`               | 요청 거부                           |
| `userNotAvailable()`   | `user-not-available`   | 사용자가 응답할 수 없는 상태(비대화형 환경 등)     |
| `noResult()`           | `no-result`            | 핸들러가 결과를 반환할 수 없는 경우(RPC 호출 스킵) |

`Laravel\Prompts\select`를 사용하려면 `PermissionRequestResultKind::select()`로 선택지를 가져올 수 있습니다.

```php theme={null}
use Revolution\Copilot\Support\PermissionRequestResultKind;
use function Laravel\Prompts\select;

$select = select(
    label: 'Do you accept the requested permissions?',
    options: PermissionRequestResultKind::select(),
);

return ['kind' => $select];
```

### no-result

핸들러가 결과를 반환할 수 없는 경우(예: 비대화 환경)는 `no-result`를 반환할 수 있습니다.
`no-result`를 반환하면 RPC 호출을 스킵하고 Copilot CLI 측의 기본 거부가 적용됩니다.

```php theme={null}
return PermissionRequestResultKind::noResult();
// 또는 ['kind' => 'no-result']
```

<Info>
  최신 정보는 [GitHub 저장소](https://github.com/invokable/laravel-copilot-sdk)를 참고하세요.
</Info>


## Related topics

- [Cloud Sessions](/ko/packages/laravel-copilot-sdk/cloud-sessions.md)
- [시작하기 - GitHub Copilot SDK for Laravel](/ko/packages/laravel-copilot-sdk/getting-started.md)
- [GitHub Copilot SDK for Laravel](/ko/packages/laravel-copilot-sdk/index.md)
- [OAuth 2.0 인증 - Google Sheets API for Laravel](/ko/packages/laravel-google-sheets/oauth.md)
- [검증](/ko/validation.md)
