nomoreide 0.1.30 → 0.1.32

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.
@@ -0,0 +1,89 @@
1
+ import type { ApprovalBroker } from "./approval-broker.js";
2
+ export type AgentChatProviderId = "claude" | "codex";
3
+ export type DetectedAgentName = "claude-code" | "codex" | "gemini" | "unknown";
4
+ export interface AgentChatProvider {
5
+ id: AgentChatProviderId;
6
+ label: string;
7
+ commandName: string;
8
+ bin: string;
9
+ installHint: string;
10
+ intro: string;
11
+ }
12
+ export interface AgentInvocation {
13
+ bin: string;
14
+ args: string[];
15
+ }
16
+ /** Streamed back to the route, which forwards each as an SSE event. */
17
+ export type AgentStreamEvent = {
18
+ type: "session";
19
+ sessionId: string;
20
+ } | {
21
+ type: "text";
22
+ text: string;
23
+ } | {
24
+ type: "tool_use";
25
+ id: string;
26
+ name: string;
27
+ input: unknown;
28
+ } | {
29
+ type: "tool_result";
30
+ id: string;
31
+ name: string;
32
+ preview: string;
33
+ isError: boolean;
34
+ } | {
35
+ type: "approval_request";
36
+ requestId: string;
37
+ name: string;
38
+ input: unknown;
39
+ } | {
40
+ type: "done";
41
+ stopReason: string | null;
42
+ } | {
43
+ type: "error";
44
+ message: string;
45
+ };
46
+ export interface AgentRuntimeDeps {
47
+ /** Working directory the agent session runs in (the workspace root). */
48
+ cwd: string;
49
+ /** CLI provider selected from the agent that started NoMoreIDE. */
50
+ provider?: AgentChatProvider;
51
+ }
52
+ export interface AgentRunOptions {
53
+ signal?: AbortSignal;
54
+ /** When present, gated tools prompt the dock for approval via this broker. */
55
+ approval?: {
56
+ broker: ApprovalBroker;
57
+ url: string;
58
+ };
59
+ }
60
+ /** Pick the in-dock chat provider from the same detected-agent signal as /agent. */
61
+ export declare function resolveChatProvider(detectedName: DetectedAgentName): AgentChatProvider;
62
+ export declare function publicProviderInfo(provider: AgentChatProvider): {
63
+ id: AgentChatProviderId;
64
+ label: string;
65
+ commandName: string;
66
+ installHint: string;
67
+ intro: string;
68
+ };
69
+ /** True when the selected agent CLI is installed and runnable. Memoized. */
70
+ export declare function isAgentAvailable(provider?: AgentChatProvider): Promise<boolean>;
71
+ /** Whether tool calls are gated behind dock approval (vs. fully autonomous). */
72
+ export declare function approvalsEnabled(provider?: AgentChatProvider): boolean;
73
+ export declare function buildAgentInvocation(provider: AgentChatProvider, message: string, resumeSessionId: string | undefined, gating: boolean): AgentInvocation;
74
+ export declare class AgentRuntime {
75
+ private readonly deps;
76
+ constructor(deps: AgentRuntimeDeps);
77
+ /**
78
+ * Run one user turn. Streams events until the CLI exits. `resumeSessionId`
79
+ * continues a prior Claude Code session; omit it to start a fresh one.
80
+ */
81
+ run(message: string, resumeSessionId: string | undefined, onEvent: (event: AgentStreamEvent) => void, options?: AgentRunOptions): Promise<void>;
82
+ }
83
+ /**
84
+ * Parse one NDJSON line from Claude Code's stream-json output, emitting the
85
+ * relevant dock events. Returns the session id when this line is the init event.
86
+ */
87
+ export declare function handleClaudeLine(line: string, toolNames: Map<string, string>, onEvent: (event: AgentStreamEvent) => void): string | undefined;
88
+ /** Parse one JSONL event from `codex exec --json`. */
89
+ export declare function handleCodexLine(line: string, toolNames: Map<string, string>, onEvent: (event: AgentStreamEvent) => void): string | undefined;
@@ -0,0 +1,424 @@
1
+ import { spawn } from "node:child_process";
2
+ import { mkdtempSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ /**
6
+ * In-dashboard AI agent backed by the real local agent CLI. NoMoreIDE selects
7
+ * Claude Code or Codex from the same startup-agent detection used by /agent,
8
+ * then drives that CLI in a machine-readable headless mode rather than calling
9
+ * a vendor API directly.
10
+ *
11
+ * Conversation continuity uses the selected CLI's own session store: the first
12
+ * turn returns a session id, which the client sends back as `resumeSessionId` on
13
+ * the next turn. The server holds no transcript state.
14
+ *
15
+ * Tool permissions: unless NOMOREIDE_AGENT_PERMISSION_MODE=bypassPermissions,
16
+ * the agent runs in `default` mode with a PreToolUse hook on mutating tools.
17
+ * The hook blocks and asks the dock (via ApprovalBroker) for an Allow/Deny.
18
+ */
19
+ const CLAUDE_BIN = process.env.NOMOREIDE_CLAUDE_BIN || "claude";
20
+ const CODEX_BIN = process.env.NOMOREIDE_CODEX_BIN || "codex";
21
+ /** "bypassPermissions" runs fully autonomous (no approval prompts). */
22
+ const PERMISSION_MODE = process.env.NOMOREIDE_AGENT_PERMISSION_MODE || "default";
23
+ const CODEX_APPROVAL_POLICY = process.env.NOMOREIDE_CODEX_APPROVAL_POLICY || "never";
24
+ /** Tools that trigger an approval prompt (mutating / side-effecting ones). */
25
+ const GATED_TOOLS = "Bash|Edit|Write|MultiEdit|NotebookEdit";
26
+ /** Truncate tool-result previews shown in the dock. */
27
+ const PREVIEW_LIMIT = 400;
28
+ const CLAUDE_PROVIDER = {
29
+ id: "claude",
30
+ label: "Claude Code",
31
+ commandName: "claude",
32
+ bin: CLAUDE_BIN,
33
+ installHint: "Install Claude Code (and run `claude login`) so it is on NoMoreIDE's PATH, then reload.",
34
+ intro: "This is real Claude Code, running in your workspace with full tools - e.g. \"restart the api and tail its logs\", \"what changed in git and why?\", \"fix the failing test\".",
35
+ };
36
+ const CODEX_PROVIDER = {
37
+ id: "codex",
38
+ label: "Codex",
39
+ commandName: "codex",
40
+ bin: CODEX_BIN,
41
+ installHint: "Install Codex CLI (and run `codex login`) so it is on NoMoreIDE's PATH, then reload.",
42
+ intro: "This is real Codex CLI, running in your workspace with full tools - e.g. \"restart the api and tail its logs\", \"what changed in git and why?\", \"fix the failing test\".",
43
+ };
44
+ const availabilityProbes = new Map();
45
+ /** Pick the in-dock chat provider from the same detected-agent signal as /agent. */
46
+ export function resolveChatProvider(detectedName) {
47
+ return detectedName === "codex" ? CODEX_PROVIDER : CLAUDE_PROVIDER;
48
+ }
49
+ export function publicProviderInfo(provider) {
50
+ return {
51
+ id: provider.id,
52
+ label: provider.label,
53
+ commandName: provider.commandName,
54
+ installHint: provider.installHint,
55
+ intro: provider.intro,
56
+ };
57
+ }
58
+ /** True when the selected agent CLI is installed and runnable. Memoized. */
59
+ export function isAgentAvailable(provider = CLAUDE_PROVIDER) {
60
+ const existing = availabilityProbes.get(provider.id);
61
+ if (existing)
62
+ return existing;
63
+ const probe = new Promise((resolve) => {
64
+ const child = spawn(provider.bin, ["--version"], { stdio: "ignore" });
65
+ child.on("error", () => resolve(false));
66
+ child.on("close", (code) => resolve(code === 0));
67
+ }).catch(() => false);
68
+ availabilityProbes.set(provider.id, probe);
69
+ return probe;
70
+ }
71
+ /** Whether tool calls are gated behind dock approval (vs. fully autonomous). */
72
+ export function approvalsEnabled(provider = CLAUDE_PROVIDER) {
73
+ return provider.id === "claude" && PERMISSION_MODE !== "bypassPermissions";
74
+ }
75
+ export function buildAgentInvocation(provider, message, resumeSessionId, gating) {
76
+ if (provider.id === "codex") {
77
+ const args = ["-a", CODEX_APPROVAL_POLICY, "exec"];
78
+ if (resumeSessionId) {
79
+ args.push("resume", "--json", "--skip-git-repo-check", resumeSessionId, message);
80
+ }
81
+ else {
82
+ args.push("--json", "--skip-git-repo-check", message);
83
+ }
84
+ return { bin: provider.bin, args };
85
+ }
86
+ const args = [
87
+ "--print",
88
+ "--output-format",
89
+ "stream-json",
90
+ "--verbose",
91
+ "--include-partial-messages",
92
+ "--permission-mode",
93
+ gating ? "default" : PERMISSION_MODE,
94
+ ];
95
+ if (gating) {
96
+ args.push("--settings", approvalSettings());
97
+ }
98
+ if (resumeSessionId)
99
+ args.push("--resume", resumeSessionId);
100
+ args.push(message);
101
+ return { bin: provider.bin, args };
102
+ }
103
+ export class AgentRuntime {
104
+ deps;
105
+ constructor(deps) {
106
+ this.deps = deps;
107
+ }
108
+ /**
109
+ * Run one user turn. Streams events until the CLI exits. `resumeSessionId`
110
+ * continues a prior Claude Code session; omit it to start a fresh one.
111
+ */
112
+ async run(message, resumeSessionId, onEvent, options = {}) {
113
+ const { signal, approval } = options;
114
+ const provider = this.deps.provider ?? CLAUDE_PROVIDER;
115
+ const gating = Boolean(approval) && approvalsEnabled(provider);
116
+ const invocation = buildAgentInvocation(provider, message, resumeSessionId, gating);
117
+ const env = gating && approval
118
+ ? { ...process.env, NOMOREIDE_APPROVAL_URL: approval.url }
119
+ : process.env;
120
+ await new Promise((resolve) => {
121
+ const child = spawn(invocation.bin, invocation.args, {
122
+ cwd: this.deps.cwd,
123
+ env,
124
+ stdio: ["ignore", "pipe", "pipe"],
125
+ });
126
+ const toolNames = new Map();
127
+ let stdout = "";
128
+ let stderr = "";
129
+ let finished = false;
130
+ let openedSession;
131
+ const finish = () => {
132
+ if (finished)
133
+ return;
134
+ finished = true;
135
+ if (openedSession)
136
+ approval?.broker.closeRun(openedSession);
137
+ resolve();
138
+ };
139
+ // Bridge the broker's approval requests onto the SSE stream the moment
140
+ // we learn this run's session id.
141
+ const onLine = (line) => {
142
+ const sessionId = provider.id === "codex"
143
+ ? handleCodexLine(line, toolNames, onEvent)
144
+ : handleClaudeLine(line, toolNames, onEvent);
145
+ if (sessionId && gating && approval && !openedSession) {
146
+ openedSession = sessionId;
147
+ approval.broker.openRun(sessionId, (request) => onEvent({
148
+ type: "approval_request",
149
+ requestId: request.requestId,
150
+ name: request.name,
151
+ input: request.input,
152
+ }));
153
+ }
154
+ };
155
+ if (signal) {
156
+ if (signal.aborted)
157
+ child.kill();
158
+ else
159
+ signal.addEventListener("abort", () => child.kill(), { once: true });
160
+ }
161
+ child.on("error", (error) => {
162
+ onEvent({
163
+ type: "error",
164
+ message: error.code === "ENOENT"
165
+ ? `Could not run "${provider.bin}". ${provider.installHint}`
166
+ : error.message,
167
+ });
168
+ finish();
169
+ });
170
+ child.stdout.setEncoding("utf8");
171
+ child.stdout.on("data", (chunk) => {
172
+ stdout += chunk;
173
+ let newline = stdout.indexOf("\n");
174
+ while (newline !== -1) {
175
+ const line = stdout.slice(0, newline).trim();
176
+ stdout = stdout.slice(newline + 1);
177
+ if (line)
178
+ onLine(line);
179
+ newline = stdout.indexOf("\n");
180
+ }
181
+ });
182
+ child.stderr.setEncoding("utf8");
183
+ child.stderr.on("data", (chunk) => {
184
+ stderr += chunk;
185
+ });
186
+ child.on("close", (code) => {
187
+ if (signal?.aborted)
188
+ return finish();
189
+ const leftover = stdout.trim();
190
+ if (leftover)
191
+ onLine(leftover);
192
+ if (code !== 0) {
193
+ onEvent({
194
+ type: "error",
195
+ message: stderr.trim() || `${provider.label} exited with code ${code}.`,
196
+ });
197
+ }
198
+ finish();
199
+ });
200
+ });
201
+ }
202
+ }
203
+ /**
204
+ * Parse one NDJSON line from Claude Code's stream-json output, emitting the
205
+ * relevant dock events. Returns the session id when this line is the init event.
206
+ */
207
+ export function handleClaudeLine(line, toolNames, onEvent) {
208
+ let obj;
209
+ try {
210
+ obj = JSON.parse(line);
211
+ }
212
+ catch {
213
+ return undefined;
214
+ }
215
+ switch (obj.type) {
216
+ case "system": {
217
+ if (obj.subtype === "init" && typeof obj.session_id === "string") {
218
+ onEvent({ type: "session", sessionId: obj.session_id });
219
+ return obj.session_id;
220
+ }
221
+ return undefined;
222
+ }
223
+ case "stream_event": {
224
+ // Token-level text deltas (from --include-partial-messages).
225
+ const event = obj.event;
226
+ if (event?.type === "content_block_delta" && event.delta?.type === "text_delta") {
227
+ onEvent({ type: "text", text: event.delta.text ?? "" });
228
+ }
229
+ return undefined;
230
+ }
231
+ case "assistant": {
232
+ for (const block of messageContent(obj.message)) {
233
+ if (block.type === "tool_use" && typeof block.id === "string") {
234
+ toolNames.set(block.id, String(block.name));
235
+ onEvent({ type: "tool_use", id: block.id, name: String(block.name), input: block.input });
236
+ }
237
+ }
238
+ return undefined;
239
+ }
240
+ case "user": {
241
+ for (const block of messageContent(obj.message)) {
242
+ if (block.type === "tool_result" && typeof block.tool_use_id === "string") {
243
+ onEvent({
244
+ type: "tool_result",
245
+ id: block.tool_use_id,
246
+ name: toolNames.get(block.tool_use_id) ?? "tool",
247
+ preview: previewOf(block.content),
248
+ isError: Boolean(block.is_error),
249
+ });
250
+ }
251
+ }
252
+ return undefined;
253
+ }
254
+ case "result": {
255
+ onEvent({ type: "done", stopReason: typeof obj.subtype === "string" ? obj.subtype : null });
256
+ return undefined;
257
+ }
258
+ default:
259
+ return undefined;
260
+ }
261
+ }
262
+ /** Parse one JSONL event from `codex exec --json`. */
263
+ export function handleCodexLine(line, toolNames, onEvent) {
264
+ let obj;
265
+ try {
266
+ obj = JSON.parse(line);
267
+ }
268
+ catch {
269
+ return undefined;
270
+ }
271
+ if (obj.type === "thread.started" && typeof obj.thread_id === "string") {
272
+ onEvent({ type: "session", sessionId: obj.thread_id });
273
+ return obj.thread_id;
274
+ }
275
+ if (obj.type === "item.started" || obj.type === "item.completed") {
276
+ const item = obj.item;
277
+ if (!item || typeof item.id !== "string" || typeof item.type !== "string") {
278
+ return undefined;
279
+ }
280
+ if (item.type === "command_execution") {
281
+ const name = "command";
282
+ toolNames.set(item.id, name);
283
+ const command = typeof item.command === "string" ? item.command : "";
284
+ if (obj.type === "item.started") {
285
+ onEvent({ type: "tool_use", id: item.id, name, input: { command } });
286
+ return undefined;
287
+ }
288
+ onEvent({
289
+ type: "tool_result",
290
+ id: item.id,
291
+ name,
292
+ preview: previewOf(item.aggregated_output),
293
+ isError: typeof item.exit_code === "number"
294
+ ? item.exit_code !== 0
295
+ : item.status === "failed",
296
+ });
297
+ return undefined;
298
+ }
299
+ if (item.type === "agent_message" && obj.type === "item.completed") {
300
+ const text = typeof item.text === "string" ? item.text : "";
301
+ if (text)
302
+ onEvent({ type: "text", text });
303
+ return undefined;
304
+ }
305
+ }
306
+ if (obj.type === "turn.completed") {
307
+ onEvent({ type: "done", stopReason: null });
308
+ }
309
+ return undefined;
310
+ }
311
+ function messageContent(message) {
312
+ const content = message?.content;
313
+ return Array.isArray(content) ? content : [];
314
+ }
315
+ function previewOf(content) {
316
+ let text;
317
+ if (typeof content === "string") {
318
+ text = content;
319
+ }
320
+ else if (Array.isArray(content)) {
321
+ text = content
322
+ .map((block) => typeof block === "string"
323
+ ? block
324
+ : typeof block.text === "string"
325
+ ? block.text
326
+ : "")
327
+ .join(" ");
328
+ }
329
+ else {
330
+ text = "";
331
+ }
332
+ text = text.trim();
333
+ return text.length > PREVIEW_LIMIT ? `${text.slice(0, PREVIEW_LIMIT)}…` : text;
334
+ }
335
+ let hookPath;
336
+ let settingsJson;
337
+ /** Inline `--settings` JSON installing the PreToolUse approval hook. Cached. */
338
+ function approvalSettings() {
339
+ if (!settingsJson) {
340
+ const command = `node ${JSON.stringify(ensureHookScript())}`;
341
+ settingsJson = JSON.stringify({
342
+ hooks: {
343
+ PreToolUse: [{ matcher: GATED_TOOLS, hooks: [{ type: "command", command }] }],
344
+ },
345
+ });
346
+ }
347
+ return settingsJson;
348
+ }
349
+ /**
350
+ * Write the approval-hook script to a temp file once, runnable by plain `node`
351
+ * in both dev (tsx) and built modes. It POSTs the pending tool call to the web
352
+ * server and blocks until the user's decision returns, then prints the
353
+ * PreToolUse permission decision Claude Code expects.
354
+ */
355
+ function ensureHookScript() {
356
+ if (hookPath)
357
+ return hookPath;
358
+ const dir = mkdtempSync(join(tmpdir(), "nomoreide-agent-"));
359
+ hookPath = join(dir, "approval-hook.cjs");
360
+ writeFileSync(hookPath, HOOK_SOURCE, "utf8");
361
+ return hookPath;
362
+ }
363
+ const HOOK_SOURCE = `"use strict";
364
+ const http = require("http");
365
+ const { randomUUID } = require("crypto");
366
+ let body = "";
367
+ process.stdin.on("data", (d) => (body += d));
368
+ process.stdin.on("end", () => {
369
+ let input = {};
370
+ try { input = JSON.parse(body); } catch {}
371
+ const url = process.env.NOMOREIDE_APPROVAL_URL;
372
+ if (!url) return decide("deny", "Approval channel not configured.");
373
+ let target;
374
+ try { target = new URL(url); } catch { return decide("deny", "Bad approval URL."); }
375
+ const payload = JSON.stringify({
376
+ sessionId: input.session_id,
377
+ requestId: randomUUID(),
378
+ toolName: input.tool_name,
379
+ toolInput: input.tool_input,
380
+ });
381
+ const req = http.request(
382
+ {
383
+ hostname: target.hostname,
384
+ port: target.port,
385
+ path: target.pathname,
386
+ method: "POST",
387
+ headers: { "content-type": "application/json", "content-length": Buffer.byteLength(payload) },
388
+ },
389
+ (res) => {
390
+ let data = "";
391
+ res.setEncoding("utf8");
392
+ res.on("data", (c) => (data += c));
393
+ res.on("end", () => {
394
+ try {
395
+ const r = JSON.parse(data);
396
+ decide(r.decision === "allow" ? "allow" : "deny", r.reason);
397
+ } catch {
398
+ decide("deny", "No decision returned.");
399
+ }
400
+ });
401
+ },
402
+ );
403
+ req.on("error", () => decide("deny", "Approval request failed to reach NoMoreIDE."));
404
+ req.setTimeout(10 * 60 * 1000, () => {
405
+ req.destroy();
406
+ decide("deny", "Approval timed out.");
407
+ });
408
+ req.write(payload);
409
+ req.end();
410
+ });
411
+ function decide(permissionDecision, reason) {
412
+ process.stdout.write(
413
+ JSON.stringify({
414
+ hookSpecificOutput: {
415
+ hookEventName: "PreToolUse",
416
+ permissionDecision,
417
+ permissionDecisionReason: reason || "",
418
+ },
419
+ }),
420
+ );
421
+ process.exit(0);
422
+ }
423
+ `;
424
+ //# sourceMappingURL=agent-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-runtime.js","sourceRoot":"","sources":["../../src/core/agent-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Bridges Claude Code's PreToolUse permission hook to the web UI. The hook
3
+ * (a child process of the spawned `claude`) POSTs an approval request and
4
+ * blocks; the broker emits it onto the active chat SSE stream and parks a
5
+ * resolver until the browser POSTs the user's decision back.
6
+ *
7
+ * Keyed by Claude Code session id, which both the SSE stream (from the init
8
+ * event) and the hook (from its stdin payload) know.
9
+ */
10
+ export interface ApprovalRequest {
11
+ requestId: string;
12
+ name: string;
13
+ input: unknown;
14
+ }
15
+ export interface ApprovalDecision {
16
+ decision: "allow" | "deny";
17
+ reason?: string;
18
+ }
19
+ export declare class ApprovalBroker {
20
+ private readonly channels;
21
+ /** Register the SSE emitter for a session so approvals can reach the browser. */
22
+ openRun(sessionId: string, emit: (request: ApprovalRequest) => void): void;
23
+ /** Tear down a session, auto-denying anything still awaiting a decision. */
24
+ closeRun(sessionId: string): void;
25
+ /** Called by the hook endpoint. Resolves once the user decides (or no channel). */
26
+ requestApproval(sessionId: string | undefined, requestId: string, name: string, input: unknown): Promise<ApprovalDecision>;
27
+ /** Called by the browser. Returns false if the request is unknown/expired. */
28
+ resolve(sessionId: string, requestId: string, decision: ApprovalDecision): boolean;
29
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Bridges Claude Code's PreToolUse permission hook to the web UI. The hook
3
+ * (a child process of the spawned `claude`) POSTs an approval request and
4
+ * blocks; the broker emits it onto the active chat SSE stream and parks a
5
+ * resolver until the browser POSTs the user's decision back.
6
+ *
7
+ * Keyed by Claude Code session id, which both the SSE stream (from the init
8
+ * event) and the hook (from its stdin payload) know.
9
+ */
10
+ export class ApprovalBroker {
11
+ channels = new Map();
12
+ /** Register the SSE emitter for a session so approvals can reach the browser. */
13
+ openRun(sessionId, emit) {
14
+ this.channels.set(sessionId, { emit, pending: new Map() });
15
+ }
16
+ /** Tear down a session, auto-denying anything still awaiting a decision. */
17
+ closeRun(sessionId) {
18
+ const channel = this.channels.get(sessionId);
19
+ if (!channel)
20
+ return;
21
+ for (const resolve of channel.pending.values()) {
22
+ resolve({ decision: "deny", reason: "The agent session ended before you responded." });
23
+ }
24
+ this.channels.delete(sessionId);
25
+ }
26
+ /** Called by the hook endpoint. Resolves once the user decides (or no channel). */
27
+ requestApproval(sessionId, requestId, name, input) {
28
+ const channel = sessionId ? this.channels.get(sessionId) : undefined;
29
+ if (!channel) {
30
+ return Promise.resolve({ decision: "deny", reason: "No active agent session to approve." });
31
+ }
32
+ return new Promise((resolve) => {
33
+ channel.pending.set(requestId, resolve);
34
+ channel.emit({ requestId, name, input });
35
+ });
36
+ }
37
+ /** Called by the browser. Returns false if the request is unknown/expired. */
38
+ resolve(sessionId, requestId, decision) {
39
+ const channel = this.channels.get(sessionId);
40
+ const resolver = channel?.pending.get(requestId);
41
+ if (!channel || !resolver)
42
+ return false;
43
+ channel.pending.delete(requestId);
44
+ resolver(decision);
45
+ return true;
46
+ }
47
+ }
48
+ //# sourceMappingURL=approval-broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-broker.js","sourceRoot":"","sources":["../../src/core/approval-broker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkBH,MAAM,OAAO,cAAc;IACR,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEvD,iFAAiF;IACjF,OAAO,CAAC,SAAiB,EAAE,IAAwC;QACjE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,4EAA4E;IAC5E,QAAQ,CAAC,SAAiB;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC/C,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,+CAA+C,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,mFAAmF;IACnF,eAAe,CACb,SAA6B,EAC7B,SAAiB,EACjB,IAAY,EACZ,KAAc;QAEd,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,qCAAqC,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,8EAA8E;IAC9E,OAAO,CAAC,SAAiB,EAAE,SAAiB,EAAE,QAA0B;QACtE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QACxC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -43,3 +43,4 @@ export interface AgentInfo {
43
43
  projects: AgentProjectEntry[];
44
44
  }
45
45
  export declare function buildAgentInfo(cwd: string): Promise<AgentInfo>;
46
+ export declare function detectAgent(): Promise<AgentInfo["detected"]>;
@@ -17,7 +17,7 @@ export async function buildAgentInfo(cwd) {
17
17
  const projects = collectProjects(claudeJson, cwd);
18
18
  return { detected, project, skills, mcpServers, projects };
19
19
  }
20
- async function detectAgent() {
20
+ export async function detectAgent() {
21
21
  const env = process.env;
22
22
  const signals = [];
23
23
  let name = "unknown";