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

# Session Context 與篩選

> 說明如何使用 Laravel Copilot SDK 的 SessionContext 與 SessionListFilter,依 working directory 或 Git 資訊查詢與篩選 Session。

## Session Context 與篩選

自 GitHub Copilot SDK v0.1.24 起,Session 加入了包含 working directory 與 Git 資訊的 context,並可在 Session 清單中進行篩選。

## SessionContext

`SessionContext` 保存 Session 建立時的 working directory 與 Git 儲存庫資訊。

### 屬性

* `cwd` (`string`): working directory 的絕對路徑
* `gitRoot` (`?string`): Git 儲存庫的根目錄(在 Git 儲存庫外為 `null`)
* `repository` (`?string`): GitHub 儲存庫(`owner/repo` 格式,例如 `invokable/laravel-copilot-sdk`)
* `branch` (`?string`): 目前的 Git 分支名稱

### 使用範例

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

// 取得 Session 清單
$sessions = Copilot::client()->listSessions();

foreach ($sessions as $metadata) {
    echo "Session: {$metadata->sessionId}\n";

    if ($metadata->context !== null) {
        echo "  Working directory: {$metadata->context->cwd}\n";

        if ($metadata->context->repository !== null) {
            echo "  Repository: {$metadata->context->repository}\n";
            echo "  Branch: {$metadata->context->branch}\n";
        }
    }
}
```

## SessionListFilter

使用 `SessionListFilter` 可以只取得特定 working directory 或儲存庫的 Session。

### 屬性

* `cwd` (`?string`): 以 working directory 完全相符篩選
* `gitRoot` (`?string`): 以 Git root 目錄篩選
* `repository` (`?string`): 以儲存庫(`owner/repo` 格式)篩選
* `branch` (`?string`): 以分支名稱篩選

### 使用範例

#### 以陣列指定篩選

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

// 只取得特定儲存庫的 Session
$sessions = Copilot::client()->listSessions([
    'repository' => 'invokable/laravel-copilot-sdk',
]);

// 取得在特定分支上進行的 Session
$sessions = Copilot::client()->listSessions([
    'repository' => 'owner/repo',
    'branch' => 'feature/new-feature',
]);

// 取得特定 working directory 的 Session
$sessions = Copilot::client()->listSessions([
    'cwd' => '/home/user/projects/my-app',
]);
```

#### 使用 SessionListFilter 類別

```php theme={null}
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Types\SessionListFilter;

$filter = new SessionListFilter(
    repository: 'owner/repo',
    branch: 'main',
);

$sessions = Copilot::client()->listSessions($filter);
```

## `session.context_changed` 事件

當 Session 執行過程中 working directory 變更時,會觸發 `session.context_changed` 事件。

### 事件類型

```php theme={null}
use Revolution\Copilot\Enums\SessionEventType;

SessionEventType::SESSION_CONTEXT_CHANGED; // 'session.context_changed'
```

### 事件資料

事件資料包含更新後的 context 資訊。

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

Copilot::start(function ($session) {
    $session->on(function ($event) {
        if ($event->type === 'session.context_changed') {
            $data = $event->data;

            echo "Working directory 已變更\n";
            echo "  cwd: {$data['cwd']}\n";
            echo "  repository: {$data['repository']}\n";
            echo "  branch: {$data['branch']}\n";
        }
    });

    $response = $session->sendAndWait(
        prompt: 'Change to a different directory and list files',
    );
});
```

## SessionMetadata

`SessionMetadata` 新增了 `context` 屬性。

### 新屬性

* `context` (`?SessionContext`): Session 的 working directory 與 Git 資訊

### 使用範例

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

$sessions = Copilot::client()->listSessions();

foreach ($sessions as $metadata) {
    echo "Session ID: {$metadata->sessionId}\n";
    echo "開始時間: {$metadata->startTime}\n";

    // context 為選填,因此需要 null 檢查
    if ($metadata->context !== null) {
        echo "Context:\n";
        echo "  Working directory: {$metadata->context->cwd}\n";

        if ($metadata->context->repository !== null) {
            echo "  Repository: {$metadata->context->repository}\n";
        }

        if ($metadata->context->branch !== null) {
            echo "  Branch: {$metadata->context->branch}\n";
        }
    }

    echo "\n";
}
```

## 實用範例

### 取得特定專案的 Session

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

// 僅取得 Laravel Copilot SDK 專案的 Session
$sessions = Copilot::client()->listSessions([
    'repository' => 'invokable/laravel-copilot-sdk',
]);

// 顯示進行中的 Session
foreach ($sessions as $metadata) {
    echo "{$metadata->sessionId}: {$metadata->summary}\n";
    echo "  Branch: {$metadata->context->branch}\n";
}
```

### 管理 Feature branch 的 Session

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

$sessions = Copilot::client()->listSessions();

$featureSessions = array_filter($sessions, function ($metadata) {
    return $metadata->context !== null
        && str_starts_with($metadata->context->branch ?? '', 'feature/');
});

// 依 feature branch 將 Session 分組
$byBranch = [];
foreach ($featureSessions as $metadata) {
    $branch = $metadata->context->branch;
    $byBranch[$branch][] = $metadata;
}

foreach ($byBranch as $branch => $sessions) {
    echo "{$branch}: " . count($sessions) . " Session\n";
}
```

### 依 working directory 整理 Session

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

$sessions = Copilot::client()->listSessions();

// 依 working directory 分組
$byCwd = [];
foreach ($sessions as $metadata) {
    if ($metadata->context !== null) {
        $cwd = $metadata->context->cwd;
        $byCwd[$cwd][] = $metadata;
    }
}

// 顯示每個目錄的 Session 數
foreach ($byCwd as $cwd => $sessions) {
    echo "{$cwd}: " . count($sessions) . " Session\n";
}
```

## 注意事項

* `context` 只有在 Git 儲存庫中建立的 Session 才會包含 Git 相關資訊(`gitRoot`、`repository`、`branch`)。
* `context` 欄位可在 Copilot CLI v0.0.409 以後版本使用。舊版本會回傳 `null`。
* 篩選以完全相符方式運作。不支援部分符合或萬用字元。
* `SessionListFilter` 的所有欄位皆為選填。未指定篩選條件時會回傳所有 Session。

<Info>
  最新資訊請參閱 [GitHub 儲存庫](https://github.com/invokable/laravel-copilot-sdk)。
</Info>


## Related topics

- [laravel/agent-skills — Laravel 官方 AI Agent 技能集](/zh-TW/blog/agent-skills-introduction.md)
- [Context（脈絡）](/zh-TW/context.md)
- [Session Hook](/zh-TW/packages/laravel-copilot-sdk/hooks.md)
- [Session 恢復](/zh-TW/packages/laravel-copilot-sdk/resume.md)
- [Laravel Maestro — 啟動套件開發的協調器](/zh-TW/blog/maestro-introduction.md)
