@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 +1 -1
- package/src/codex-stream-bridge.mjs +62 -3
- package/src/main.mjs +44 -1
package/package.json
CHANGED
|
@@ -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
|
-
/**
|
|
198
|
-
|
|
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
|
-
|
|
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({
|
|
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 復元用。
|