@cocorograph/hub-agent 0.8.105 → 0.8.106

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.8.105",
3
+ "version": "0.8.106",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの Claude / Codex チャットと tmux セッションを中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -966,8 +966,15 @@ export class ClaudeStreamSession {
966
966
  this.logger?.debug({ stream_id: this.stream_id, cwd: this.cwd, stderr: text }, "claude cli stderr")
967
967
  }
968
968
 
969
- /** SDK options.canUseTool: tool 起動を許可するかを browser に問い合わせる。 */
970
- async _canUseTool(toolName, input) {
969
+ /**
970
+ * SDK options.canUseTool: tool 起動を許可するかを browser に問い合わせる。
971
+ *
972
+ * SDK は第 3 引数 options.agentID に「サブエージェント内からの要求ならその ID」を渡す。
973
+ * これを載せないと、サブエージェントの承認要求がチーフ本人の要求と見分けられない
974
+ * (承認カードに依頼元が出ない)。チーフ本人の要求では agentID が無いので agent_id は省く。
975
+ * 「常に許可」の判定は browser 側でツール名単位のまま (依頼元で自動許可を止めない)。
976
+ */
977
+ async _canUseTool(toolName, input, options) {
971
978
  if (!this.onPermission) return { behavior: "allow", updatedInput: input }
972
979
  let displayState
973
980
  try {
@@ -976,15 +983,17 @@ export class ClaudeStreamSession {
976
983
  return { behavior: "deny", message: PERMISSION_MASK_DENIAL }
977
984
  }
978
985
  const request_id = randomUUID()
986
+ const agent_id = typeof options?.agentID === "string" && options.agentID ? options.agentID : undefined
979
987
  return await new Promise((resolve) => {
980
988
  this._permissionResolvers.set(request_id, {
981
989
  resolve,
982
990
  tool_name: toolName,
983
991
  input,
984
992
  displayState,
993
+ agent_id,
985
994
  })
986
995
  try {
987
- this.onPermission({ tool_name: toolName, input: displayState ? copyPermissionInput(displayState.displayInput) : input, request_id })
996
+ this.onPermission({ tool_name: toolName, input: displayState ? copyPermissionInput(displayState.displayInput) : input, request_id, ...(agent_id ? { agent_id } : {}) })
988
997
  } catch (err) {
989
998
  this.logger?.warn(
990
999
  { stream_id: this.stream_id },
@@ -1108,7 +1117,7 @@ export class ClaudeStreamSession {
1108
1117
  if (!this.onPermission || this._permissionResolvers.size === 0) return
1109
1118
  for (const [request_id, r] of this._permissionResolvers) {
1110
1119
  try {
1111
- this.onPermission({ tool_name: r.tool_name, input: r.displayState ? copyPermissionInput(r.displayState.displayInput) : r.input, request_id })
1120
+ this.onPermission({ tool_name: r.tool_name, input: r.displayState ? copyPermissionInput(r.displayState.displayInput) : r.input, request_id, ...(r.agent_id ? { agent_id: r.agent_id } : {}) })
1112
1121
  } catch (err) {
1113
1122
  this.logger?.warn(
1114
1123
  { stream_id: this.stream_id, request_id },
@@ -1504,7 +1513,7 @@ export class ClaudeStreamSession {
1504
1513
  const options = {
1505
1514
  cwd: this.cwd,
1506
1515
  env: siblingEnvFor(this.cwd),
1507
- canUseTool: (toolName, input) => this._canUseTool(toolName, input),
1516
+ canUseTool: (toolName, input, options) => this._canUseTool(toolName, input, options),
1508
1517
  includePartialMessages: true,
1509
1518
  includeHookEvents: true,
1510
1519
  abortController: this._abortController,
@@ -2236,7 +2245,7 @@ export class ClaudeStreamSession {
2236
2245
  const options = {
2237
2246
  cwd: this.cwd,
2238
2247
  env: siblingEnvFor(this.cwd),
2239
- canUseTool: (toolName, input) => this._canUseTool(toolName, input),
2248
+ canUseTool: (toolName, input, options) => this._canUseTool(toolName, input, options),
2240
2249
  includePartialMessages: true,
2241
2250
  includeHookEvents: true,
2242
2251
  abortController: this._residentAbortController,
@@ -3043,7 +3052,7 @@ export class ClaudeStreamBridge extends EventEmitter {
3043
3052
  this._liveBySession.set(key, session)
3044
3053
  }
3045
3054
  },
3046
- onPermission: ({ tool_name, input, request_id }) => {
3055
+ onPermission: ({ tool_name, input, request_id, agent_id }) => {
3047
3056
  // 多端末共有: session_id を載せて backend が session group へ broadcast できるように
3048
3057
  // する (全端末に許可ダイアログを出し、先着 1 件の reply を採用する)。
3049
3058
  this.emit("permission", {
@@ -3053,6 +3062,7 @@ export class ClaudeStreamBridge extends EventEmitter {
3053
3062
  request_id,
3054
3063
  tool_name,
3055
3064
  input,
3065
+ ...(agent_id ? { agent_id } : {}),
3056
3066
  })
3057
3067
  },
3058
3068
  onPermissionCancel: ({ request_ids, reason }) => {
package/src/main.mjs CHANGED
@@ -822,9 +822,10 @@ export function wireBridgeEvents(client, { claudeBridge, codexBridge }) {
822
822
  resolveChatContextPct(session, event)
823
823
  sendBridgeMessage(client, { type: "claude.event", stream_id, session_id, event })
824
824
  })
825
- claudeBridge.on("permission", ({ stream_id, session_id, cwd, request_id, tool_name, input }) => {
825
+ claudeBridge.on("permission", ({ stream_id, session_id, cwd, request_id, tool_name, input, agent_id }) => {
826
826
  // 多端末共有: session_id を載せて backend が session group へ broadcast できるように
827
827
  // する (全端末に許可ダイアログ → 先着 1 件採用)。
828
+ // agent_id はサブエージェントからの要求のときだけ載る (承認カードで依頼元を示す)。
828
829
  sendBridgeMessage(client, {
829
830
  type: "claude.permission.request",
830
831
  stream_id,
@@ -832,6 +833,7 @@ export function wireBridgeEvents(client, { claudeBridge, codexBridge }) {
832
833
  request_id,
833
834
  tool_name,
834
835
  input,
836
+ ...(agent_id ? { agent_id } : {}),
835
837
  })
836
838
  })
837
839
  claudeBridge.on(