@cocorograph/hub-agent 0.7.33 → 0.7.35

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.35",
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))
@@ -194,8 +235,23 @@ export class CodexStreamBridge extends EventEmitter {
194
235
  })
195
236
  }
196
237
 
197
- /** @returns {Promise<void>} */
198
- async input({ stream_id, message }) {
238
+ /**
239
+ * @param {object} args
240
+ * @param {string} args.stream_id
241
+ * @param {object} args.message
242
+ * @param {string} [args.model] - 公式スキーマ `TurnStartParams.model`
243
+ * ("Override the model for this turn and subsequent turns")。turn/start でのみ有効。
244
+ * @param {string} [args.effort] - 公式スキーマ `TurnStartParams.effort`
245
+ * ("Override the reasoning effort for this turn and subsequent turns")。turn/start でのみ有効。
246
+ * @returns {Promise<void>}
247
+ *
248
+ * ⚠️ `turn/steer` (`TurnSteerParams`) には model/effort フィールドが存在しない
249
+ * (公式スキーマで未対応と確認済み、2026-07-03)。そのためターン実行中 (busy) に
250
+ * model/effort を渡しても turn/steer 経由では反映されず、次の非 busy な input()
251
+ * (= turn/start) から有効になる。呼び出し側 (main.mjs) はこれを承知の上で常に
252
+ * model/effort を渡してよい (steer 分岐では単に無視される)。
253
+ */
254
+ async input({ stream_id, message, model, effort }) {
199
255
  const session = this._require(stream_id)
200
256
  const input = userInputFromMessage(message)
201
257
  if (session.activeTurnId) {
@@ -206,7 +262,10 @@ export class CodexStreamBridge extends EventEmitter {
206
262
  })
207
263
  return
208
264
  }
209
- await session.client.request("turn/start", { threadId: session.threadId, input })
265
+ const params = { threadId: session.threadId, input }
266
+ if (model) params.model = model
267
+ if (effort) params.effort = effort
268
+ await session.client.request("turn/start", params)
210
269
  }
211
270
 
212
271
  /** @returns {Promise<void>} */
package/src/main.mjs CHANGED
@@ -3201,9 +3201,17 @@ async function dispatch(msg, ctx) {
3201
3201
  return
3202
3202
  }
3203
3203
  case "codex.input":
3204
+ // model/effort: turn/start (非 busy 時) にのみ反映される override。turn/steer
3205
+ // (busy 時) は公式スキーマ上 model/effort 非対応のため、その場合は
3206
+ // codex-stream-bridge.mjs 側で無視され次の非 busy な input() から効く。
3204
3207
  if (!ctx.codexBridge) return
3205
3208
  ctx.codexBridge
3206
- .input({ stream_id: msg.stream_id, message: msg.message })
3209
+ .input({
3210
+ stream_id: msg.stream_id,
3211
+ message: msg.message,
3212
+ model: msg.model || undefined,
3213
+ effort: msg.effort || undefined,
3214
+ })
3207
3215
  .catch((err) => {
3208
3216
  ctx.client.send({
3209
3217
  type: "codex.error",
@@ -3230,6 +3238,41 @@ async function dispatch(msg, ctx) {
3230
3238
  if (!ctx.codexBridge) return
3231
3239
  ctx.codexBridge.detach({ stream_id: msg.stream_id })
3232
3240
  return
3241
+ case "codex.sessions.request": {
3242
+ // cwd 配下の Codex thread 一覧を返す (claude.sessions.request と対称。
3243
+ // Cockpit のセッションピッカー/最新セッション自動選択用)。
3244
+ const stream_id = msg.stream_id
3245
+ const cwd = msg.cwd || ""
3246
+ const limit = typeof msg.limit === "number" ? msg.limit : undefined
3247
+ if (!ctx.codexBridge) {
3248
+ ctx.client.send({
3249
+ type: "codex.sessions.response",
3250
+ stream_id,
3251
+ cwd,
3252
+ sessions: [],
3253
+ error: "codex_unavailable: codex CLI が agent の PATH に見つかりません",
3254
+ })
3255
+ return
3256
+ }
3257
+ try {
3258
+ const sessions = await ctx.codexBridge.listThreads({ cwd, limit })
3259
+ ctx.client.send({
3260
+ type: "codex.sessions.response",
3261
+ stream_id,
3262
+ cwd,
3263
+ sessions,
3264
+ })
3265
+ } catch (err) {
3266
+ ctx.client.send({
3267
+ type: "codex.sessions.response",
3268
+ stream_id,
3269
+ cwd,
3270
+ sessions: [],
3271
+ error: err.message,
3272
+ })
3273
+ }
3274
+ return
3275
+ }
3233
3276
  case "claude.history.request": {
3234
3277
  // Sprint G 0.6.1: ~/.claude/projects/<cwd-encoded>/<session_id>.jsonl を読んで
3235
3278
  // 過去メッセージを返す。ChatView の re-mount 時の UI 復元用。