@cocorograph/hub-agent 0.7.33 → 0.7.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocorograph/hub-agent",
3
- "version": "0.7.33",
3
+ "version": "0.7.34",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -125,6 +125,47 @@ export class CodexStreamBridge extends EventEmitter {
125
125
  }
126
126
  }
127
127
 
128
+ /**
129
+ * cwd 配下の Codex thread 一覧を返す (Cockpit Codex 両対応 セッションピッカー/最新
130
+ * セッション自動選択用。claude 側 listSessions と対称)。
131
+ *
132
+ * `thread/list` は特定のスレッドに紐付かない app-server のグローバル RPC (公式スキーマ
133
+ * `ThreadListParams`/`ThreadListResponse` で確認済み: cwd フィルタ・sortKey='recency_at'・
134
+ * sortDirection='desc' が使える) なので、attach() のような常駐セッションは作らず、
135
+ * 呼び出しごとに使い捨てクライアントで initialize → thread/list → stop する
136
+ * (list のためだけに長寿命プロセスを維持しない = リーク防止)。
137
+ *
138
+ * @returns {Promise<Array<{thread_id: string, cwd: string, preview: string, updated_at_ms: number}>>}
139
+ */
140
+ async listThreads({ cwd, limit } = {}) {
141
+ const client = this._clientFactory({ cwd, codexCmd: this.codexCmd, logger: this.logger })
142
+ client.start()
143
+ try {
144
+ await client.request("initialize", { clientInfo: CLIENT_INFO })
145
+ const result = await client.request("thread/list", {
146
+ cwd: cwd || undefined,
147
+ limit: limit || undefined,
148
+ // recency_at は「読み込みも含めた実際の使用感」の並び順 (公式スキーマの説明:
149
+ // "Unix timestamp used for thread recency ordering")。updated_at だと最終書き込み
150
+ // のみで並ぶため、Claude 側の mtime (listSessions) と体感を揃えるならこちらが近い。
151
+ sortKey: "recency_at",
152
+ sortDirection: "desc",
153
+ })
154
+ const threads = Array.isArray(result?.data) ? result.data : []
155
+ return threads.map((t) => ({
156
+ thread_id: t.id,
157
+ cwd: t.cwd || "",
158
+ preview: typeof t.preview === "string" ? t.preview.slice(0, 80) : "",
159
+ // recencyAt 優先 (無ければ updatedAt) を ms へ変換。claude 側 ClaudeSessionSummary.mtime
160
+ // (ms epoch) と同じ単位に揃え、frontend が同じ並び替えロジックを使い回せるようにする。
161
+ updated_at_ms:
162
+ (typeof t.recencyAt === "number" ? t.recencyAt : t.updatedAt || 0) * 1000,
163
+ }))
164
+ } finally {
165
+ client.stop()
166
+ }
167
+ }
168
+
128
169
  _wireClient(session) {
129
170
  const { client, stream_id } = session
130
171
  client.on("notification", (msg) => this._onNotification(session, msg))
package/src/main.mjs CHANGED
@@ -3230,6 +3230,41 @@ async function dispatch(msg, ctx) {
3230
3230
  if (!ctx.codexBridge) return
3231
3231
  ctx.codexBridge.detach({ stream_id: msg.stream_id })
3232
3232
  return
3233
+ case "codex.sessions.request": {
3234
+ // cwd 配下の Codex thread 一覧を返す (claude.sessions.request と対称。
3235
+ // Cockpit のセッションピッカー/最新セッション自動選択用)。
3236
+ const stream_id = msg.stream_id
3237
+ const cwd = msg.cwd || ""
3238
+ const limit = typeof msg.limit === "number" ? msg.limit : undefined
3239
+ if (!ctx.codexBridge) {
3240
+ ctx.client.send({
3241
+ type: "codex.sessions.response",
3242
+ stream_id,
3243
+ cwd,
3244
+ sessions: [],
3245
+ error: "codex_unavailable: codex CLI が agent の PATH に見つかりません",
3246
+ })
3247
+ return
3248
+ }
3249
+ try {
3250
+ const sessions = await ctx.codexBridge.listThreads({ cwd, limit })
3251
+ ctx.client.send({
3252
+ type: "codex.sessions.response",
3253
+ stream_id,
3254
+ cwd,
3255
+ sessions,
3256
+ })
3257
+ } catch (err) {
3258
+ ctx.client.send({
3259
+ type: "codex.sessions.response",
3260
+ stream_id,
3261
+ cwd,
3262
+ sessions: [],
3263
+ error: err.message,
3264
+ })
3265
+ }
3266
+ return
3267
+ }
3233
3268
  case "claude.history.request": {
3234
3269
  // Sprint G 0.6.1: ~/.claude/projects/<cwd-encoded>/<session_id>.jsonl を読んで
3235
3270
  // 過去メッセージを返す。ChatView の re-mount 時の UI 復元用。