> ## 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"`。
  即使是唯讀權限,也可能讀取 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!
```

## 自訂處理器

若要依請求類型個別控制核准或拒絕,請傳入 closure。
`$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 請求形式,而是以 Session Event(`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`  | 於此 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](/zh-TW/packages/laravel-copilot-sdk/cloud-sessions.md)
- [開始使用 - GitHub Copilot SDK for Laravel](/zh-TW/packages/laravel-copilot-sdk/getting-started.md)
- [GitHub Copilot SDK for Laravel](/zh-TW/packages/laravel-copilot-sdk/index.md)
- [部署](/zh-TW/deployment.md)
- [授權（Gate 與 Policy）](/zh-TW/authorization.md)
