@kolisachint/hoocode-agent 0.4.53 → 0.4.55

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.
@@ -21,6 +21,7 @@ import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../cor
21
21
  import { SessionManager } from "../../core/session-manager.js";
22
22
  import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
23
23
  import { taskStore } from "../../core/task-store.js";
24
+ import { TeamApprovalCoordinator } from "../../core/team-approvals.js";
24
25
  import { buildCompactWordmark } from "../../core/wordmark.js";
25
26
  import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
26
27
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
@@ -2124,11 +2125,64 @@ export class InteractiveMode {
2124
2125
  // =========================================================================
2125
2126
  /**
2126
2127
  * Wire a hooteams connection into the TUI. Called by main.ts when `--team`
2127
- * is set, before run(). Enables team focus (app.team.focus), nudging (n)
2128
- * and the attach side panel (a) on the task panel's teams view.
2128
+ * is set, before run(). Enables team focus (app.team.focus), nudging (n),
2129
+ * the attach side panel (a) on the task panel's teams view, and approval
2130
+ * gates: task_paused events (and gates already pending on the server)
2131
+ * surface inline in the attach panel when it shows the paused role,
2132
+ * otherwise in the options pane; the answer goes back over
2133
+ * POST /tasks/:id/resume.
2129
2134
  */
2130
2135
  attachTeamClient(client) {
2131
2136
  this.teamClient = client;
2137
+ const approvals = new TeamApprovalCoordinator({
2138
+ present: (approval, signal) => this.presentTeamApproval(approval, signal),
2139
+ resume: (taskId, option) => client.resume(taskId, option),
2140
+ info: (message) => this.showStatus(message),
2141
+ warn: (message) => this.showWarning(message),
2142
+ });
2143
+ client.subscribe((event) => approvals.handleEvent(event));
2144
+ // Gates that opened before we attached don't replay as task_paused.
2145
+ void client.pendingApprovals().then((pending) => {
2146
+ for (const gate of pending)
2147
+ approvals.enqueuePending(gate);
2148
+ }, () => {
2149
+ // Best-effort like the rest of the bridge; live gates still arrive via SSE.
2150
+ });
2151
+ }
2152
+ /**
2153
+ * Show one team approval gate and resolve with the chosen (or free-form)
2154
+ * answer, undefined when skipped. When the attach side panel is open on the
2155
+ * role that paused, the gate renders inline in the panel — right where its
2156
+ * stream stopped; otherwise it goes to the options pane, waiting politely
2157
+ * while another ask is on screen. Either way the signal (gate answered
2158
+ * elsewhere) dismisses the prompt.
2159
+ */
2160
+ async presentTeamApproval(approval, signal) {
2161
+ const panel = this.teamAttachPanel;
2162
+ if (panel && approval.role === panel.role) {
2163
+ this.teamAttachHandle?.focus();
2164
+ const answer = await panel.presentApproval(approval, signal);
2165
+ // Detaching mid-gate settles as skipped — fall through to the options
2166
+ // pane so the question isn't silently lost. A skip with the panel
2167
+ // still open is a real skip.
2168
+ if (answer !== undefined || signal.aborted || this.teamAttachPanel === panel)
2169
+ return answer;
2170
+ }
2171
+ while (this.askOptions && !signal.aborted) {
2172
+ await new Promise((resolve) => setTimeout(resolve, 200));
2173
+ }
2174
+ if (signal.aborted)
2175
+ return undefined;
2176
+ const answers = await this.showAskOptions([
2177
+ {
2178
+ question: approval.question,
2179
+ short: approval.taskId,
2180
+ detail: `team task "${approval.taskId}"${approval.role ? ` (${approval.role})` : ""} is paused until answered`,
2181
+ options: approval.options.map((label) => ({ label })),
2182
+ allowCustom: true,
2183
+ },
2184
+ ], { signal });
2185
+ return answers?.[0];
2132
2186
  }
2133
2187
  /** Move keyboard focus to the task panel's team roster. */
2134
2188
  enterTeamFocus() {