Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,29 @@ $content = Copilot::start(function (CopilotSession $session) {
dump($content);
```

### List sessions with filtering

```php
use Revolution\Copilot\Facades\Copilot;

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

// Filter sessions by repository
$sessions = Copilot::client()->listSessions(['repository' => 'owner/repo']);

// Filter by branch
$sessions = Copilot::client()->listSessions(['branch' => 'main']);

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

### `copilot()` helper

Alternatively, you can use the `copilot()` helper function.
Expand Down
2 changes: 1 addition & 1 deletion copilot-sdk
Submodule copilot-sdk updated 65 files
+56 −0 .github/workflows/codegen-check.yml
+5 −1 docs/guides/session-persistence.md
+3 −1 docs/guides/setup/backend-services.md
+2 −1 docs/guides/setup/bundled-cli.md
+1 −0 docs/guides/setup/byok.md
+2 −0 docs/guides/setup/github-oauth.md
+1 −0 docs/guides/setup/local-cli.md
+27 −3 dotnet/src/Client.cs
+365 −0 dotnet/src/Generated/Rpc.cs
+280 −8 dotnet/src/Generated/SessionEvents.cs
+7 −0 dotnet/src/Session.cs
+34 −0 dotnet/src/Types.cs
+82 −0 dotnet/test/RpcTests.cs
+19 −0 dotnet/test/SessionTests.cs
+13 −1 go/README.md
+38 −8 go/client.go
+670 −0 go/cmd/bundler/main.go
+17 −0 go/embeddedcli/installer.go
+101 −12 go/generated_session_events.go
+4 −1 go/go.mod
+2 −0 go/go.sum
+188 −0 go/internal/e2e/rpc_test.go
+12 −3 go/internal/e2e/session_test.go
+202 −0 go/internal/embeddedcli/embeddedcli.go
+136 −0 go/internal/embeddedcli/embeddedcli_test.go
+29 −0 go/internal/flock/flock.go
+16 −0 go/internal/flock/flock_other.go
+88 −0 go/internal/flock/flock_test.go
+28 −0 go/internal/flock/flock_unix.go
+66 −0 go/internal/flock/flock_windows.go
+250 −0 go/rpc/generated_rpc.go
+5 −0 go/session.go
+39 −6 go/types.go
+18 −2 nodejs/README.md
+28 −28 nodejs/package-lock.json
+2 −2 nodejs/package.json
+0 −795 nodejs/scripts/generate-csharp-session-types.ts
+0 −373 nodejs/scripts/generate-session-types.ts
+31 −12 nodejs/src/client.ts
+208 −0 nodejs/src/generated/rpc.ts
+98 −8 nodejs/src/generated/session-events.ts
+2 −0 nodejs/src/index.ts
+12 −0 nodejs/src/session.ts
+30 −0 nodejs/src/types.ts
+97 −0 nodejs/test/e2e/rpc.test.ts
+21 −0 nodejs/test/e2e/session.test.ts
+4 −0 python/copilot/__init__.py
+29 −2 python/copilot/client.py
+604 −0 python/copilot/generated/rpc.py
+212 −21 python/copilot/generated/session_events.py
+9 −0 python/copilot/session.py
+61 −0 python/copilot/types.py
+104 −0 python/e2e/test_rpc.py
+7 −0 python/e2e/test_session.py
+5 −0 python/scripts/build-wheels.mjs
+1 −0 scripts/codegen/.gitignore
+772 −0 scripts/codegen/csharp.ts
+302 −0 scripts/codegen/go.ts
+1,030 −0 scripts/codegen/package-lock.json
+18 −0 scripts/codegen/package.json
+303 −0 scripts/codegen/python.ts
+194 −0 scripts/codegen/typescript.ts
+138 −0 scripts/codegen/utils.ts
+28 −28 test/harness/package-lock.json
+1 −1 test/harness/package.json
5 changes: 5 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,12 @@ $config = new SessionConfig(

Now that you've got the basics, explore more features:

- **Session Management**
- `listSessions()` - List and filter sessions by repository, branch, or working directory
- `resumeSession()` - Resume previous sessions
- Session context tracking (cwd, git info)
- **[Official SDK Documentation](https://github.com/github/copilot-sdk)** - Full reference
- **[Japanese Documentation](../docs/jp/)** - Detailed docs in Japanese

---

Expand Down
242 changes: 242 additions & 0 deletions docs/jp/session-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
# セッションコンテキストとフィルタリング

GitHub Copilot SDK v0.1.24以降では、セッションに作業ディレクトリとGit情報を含むコンテキストが追加され、セッション一覧でフィルタリングできるようになりました。

## SessionContext

`SessionContext`は、セッションが作成された時の作業ディレクトリとGitリポジトリの情報を保持します。

### プロパティ

- `cwd` (string): 作業ディレクトリの絶対パス
- `gitRoot` (?string): Gitリポジトリのルートディレクトリ(Gitリポジトリ内でない場合はnull)
- `repository` (?string): GitHubリポジトリ(`owner/repo`形式、例: `invokable/laravel-copilot-sdk`)
- `branch` (?string): 現在のGitブランチ名

### 使用例

```php
use Revolution\Copilot\Facades\Copilot;

// セッション一覧を取得
$sessions = Copilot::client()->listSessions();

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

if ($metadata->context !== null) {
echo " 作業ディレクトリ: {$metadata->context->cwd}\n";

if ($metadata->context->repository !== null) {
echo " リポジトリ: {$metadata->context->repository}\n";
echo " ブランチ: {$metadata->context->branch}\n";
}
}
}
```

## SessionListFilter

`SessionListFilter`を使用して、特定の作業ディレクトリやリポジトリのセッションのみを取得できます。

### プロパティ

- `cwd` (?string): 作業ディレクトリで完全一致フィルタ
- `gitRoot` (?string): Gitルートディレクトリでフィルタ
- `repository` (?string): リポジトリ(`owner/repo`形式)でフィルタ
- `branch` (?string): ブランチ名でフィルタ

### 使用例

#### 配列でフィルタ指定

```php
use Revolution\Copilot\Facades\Copilot;

// 特定のリポジトリのセッションのみを取得
$sessions = Copilot::client()->listSessions([
'repository' => 'invokable/laravel-copilot-sdk',
]);

// 特定のブランチで作業中のセッションを取得
$sessions = Copilot::client()->listSessions([
'repository' => 'owner/repo',
'branch' => 'feature/new-feature',
]);

// 特定の作業ディレクトリのセッションを取得
$sessions = Copilot::client()->listSessions([
'cwd' => '/home/user/projects/my-app',
]);
```

#### SessionListFilterクラスを使用

```php
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.context_changed`イベントが発火します。

### イベントタイプ

```php
use Revolution\Copilot\Enums\SessionEventType;

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

### イベントデータ

イベントデータには更新されたコンテキスト情報が含まれます:

```php
use Revolution\Copilot\Facades\Copilot;

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

echo "作業ディレクトリが変更されました\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): セッションの作業ディレクトリとGit情報

### 使用例

```php
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 "コンテキスト:\n";
echo " 作業ディレクトリ: {$metadata->context->cwd}\n";

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

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

echo "\n";
}
```

## 実用例

### 特定のプロジェクトのセッションを取得

```php
use Revolution\Copilot\Facades\Copilot;

// Laravel Copilot SDKプロジェクトのセッションのみを取得
$sessions = Copilot::client()->listSessions([
'repository' => 'invokable/laravel-copilot-sdk',
]);

// 作業中のセッションを表示
foreach ($sessions as $metadata) {
echo "{$metadata->sessionId}: {$metadata->summary}\n";
echo " ブランチ: {$metadata->context->branch}\n";
}
```

### 機能ブランチのセッションを管理

```php
use Revolution\Copilot\Facades\Copilot;

// feature/* ブランチで作業中のセッションを取得(簡易的な例)
$sessions = Copilot::client()->listSessions();

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

// 機能ブランチごとにセッションをグループ化
$byBranch = [];
foreach ($featureSessions as $metadata) {
$branch = $metadata->context->branch;
$byBranch[$branch][] = $metadata;
}

foreach ($byBranch as $branch => $sessions) {
echo "{$branch}: " . count($sessions) . " セッション\n";
}
```

### 作業ディレクトリごとにセッションを整理

```php
use Revolution\Copilot\Facades\Copilot;

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

// 作業ディレクトリでグループ化
$byCwd = [];
foreach ($sessions as $metadata) {
if ($metadata->context !== null) {
$cwd = $metadata->context->cwd;
$byCwd[$cwd][] = $metadata;
}
}

// ディレクトリごとのセッション数を表示
foreach ($byCwd as $cwd => $sessions) {
echo "{$cwd}: " . count($sessions) . " セッション\n";
}
```

## 注意事項

- `context`は、セッションがGitリポジトリ内で作成された場合にのみGit関連情報(`gitRoot`, `repository`, `branch`)を含みます。
- `context`フィールドは、Copilot CLI v0.0.409以降で利用可能です。古いバージョンでは`null`が返されます。
- フィルタリングは完全一致で動作します。部分一致やワイルドカードはサポートされていません。
- `SessionListFilter`のすべてのフィールドはオプショナルです。フィルタを指定しない場合は、すべてのセッションが返されます。

## 公式SDKとの互換性

この機能は、公式GitHub Copilot SDK PR #427で追加されたものと同等です:
- Node.js SDK
- Python SDK
- Go SDK
- .NET SDK

すべてのSDKで同じAPIと動作を提供しています。
26 changes: 24 additions & 2 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use Revolution\Copilot\Types\SessionConfig;
use Revolution\Copilot\Types\SessionEvent;
use Revolution\Copilot\Types\SessionLifecycleEvent;
use Revolution\Copilot\Types\SessionListFilter;
use Revolution\Copilot\Types\SessionMetadata;
use Revolution\Copilot\Types\ToolResultObject;
use Revolution\Copilot\Types\UserInputRequest;
Expand Down Expand Up @@ -492,15 +493,36 @@ public function deleteSession(string $sessionId): void
/**
* List all available sessions.
*
* Returns metadata about each session including ID, timestamps, summary, and context.
*
* @param SessionListFilter|array{cwd?: string, gitRoot?: string, repository?: string, branch?: string}|null $filter Optional filter to limit returned sessions by context fields
* @return array<SessionMetadata>
*
* @throws JsonRpcException
*
* @example
* // List all sessions
* $sessions = $client->listSessions();
*
* // List sessions for a specific repository
* $sessions = $client->listSessions(['repository' => 'owner/repo']);
*
* // List sessions in a specific working directory
* $sessions = $client->listSessions(new SessionListFilter(cwd: '/path/to/project'));
*/
public function listSessions(): array
public function listSessions(SessionListFilter|array|null $filter = null): array
{
$this->ensureConnected();

$response = $this->rpcClient->request('session.list', []);
$filterArray = match (true) {
$filter instanceof SessionListFilter => $filter->toArray(),
is_array($filter) => array_filter($filter, fn ($v) => $v !== null),
default => [],
};

$response = $this->rpcClient->request('session.list', array_filter([
'filter' => $filterArray ?: null,
]));

return array_map(
fn (array $session) => SessionMetadata::fromArray($session),
Expand Down
12 changes: 12 additions & 0 deletions src/Contracts/CopilotClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use Revolution\Copilot\Types\ResumeSessionConfig;
use Revolution\Copilot\Types\SessionConfig;
use Revolution\Copilot\Types\SessionLifecycleEvent;
use Revolution\Copilot\Types\SessionListFilter;
use Revolution\Copilot\Types\SessionMetadata;
use Throwable;

/**
Expand Down Expand Up @@ -69,6 +71,16 @@ public function getAuthStatus(): GetAuthStatusResponse;
*/
public function listModels(): array;

/**
* List all available sessions.
*
* @param SessionListFilter|array{cwd?: string, gitRoot?: string, repository?: string, branch?: string}|null $filter
* @return array<SessionMetadata>
*
* @throws JsonRpcException
*/
public function listSessions(SessionListFilter|array|null $filter = null): array;

/**
* Gets the foreground session ID in TUI+server mode.
*
Expand Down
1 change: 1 addition & 0 deletions src/Enums/SessionEventType.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum SessionEventType: string
case SESSION_USAGE_INFO = 'session.usage_info';
case SESSION_COMPACTION_START = 'session.compaction_start';
case SESSION_COMPACTION_COMPLETE = 'session.compaction_complete';
case SESSION_CONTEXT_CHANGED = 'session.context_changed';

// User messages
case USER_MESSAGE = 'user.message';
Expand Down
Loading