@suzuke/agend 0.0.1 → 1.0.0

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.
Files changed (202) hide show
  1. package/README.md +557 -1
  2. package/README.zh-TW.md +504 -0
  3. package/dist/access-path.d.ts +7 -0
  4. package/dist/access-path.js +12 -0
  5. package/dist/access-path.js.map +1 -0
  6. package/dist/approval/approval-server.d.ts +30 -0
  7. package/dist/approval/approval-server.js +156 -0
  8. package/dist/approval/approval-server.js.map +1 -0
  9. package/dist/approval/tmux-prompt-detector.d.ts +34 -0
  10. package/dist/approval/tmux-prompt-detector.js +264 -0
  11. package/dist/approval/tmux-prompt-detector.js.map +1 -0
  12. package/dist/backend/approval-strategy.d.ts +14 -0
  13. package/dist/backend/approval-strategy.js +2 -0
  14. package/dist/backend/approval-strategy.js.map +1 -0
  15. package/dist/backend/claude-code.d.ts +13 -0
  16. package/dist/backend/claude-code.js +114 -0
  17. package/dist/backend/claude-code.js.map +1 -0
  18. package/dist/backend/codex.d.ts +10 -0
  19. package/dist/backend/codex.js +58 -0
  20. package/dist/backend/codex.js.map +1 -0
  21. package/dist/backend/factory.d.ts +2 -0
  22. package/dist/backend/factory.js +19 -0
  23. package/dist/backend/factory.js.map +1 -0
  24. package/dist/backend/gemini-cli.d.ts +10 -0
  25. package/dist/backend/gemini-cli.js +68 -0
  26. package/dist/backend/gemini-cli.js.map +1 -0
  27. package/dist/backend/hook-based-approval.d.ts +20 -0
  28. package/dist/backend/hook-based-approval.js +41 -0
  29. package/dist/backend/hook-based-approval.js.map +1 -0
  30. package/dist/backend/index.d.ts +6 -0
  31. package/dist/backend/index.js +6 -0
  32. package/dist/backend/index.js.map +1 -0
  33. package/dist/backend/opencode.d.ts +10 -0
  34. package/dist/backend/opencode.js +63 -0
  35. package/dist/backend/opencode.js.map +1 -0
  36. package/dist/backend/types.d.ts +26 -0
  37. package/dist/backend/types.js +2 -0
  38. package/dist/backend/types.js.map +1 -0
  39. package/dist/channel/access-manager.d.ts +18 -0
  40. package/dist/channel/access-manager.js +149 -0
  41. package/dist/channel/access-manager.js.map +1 -0
  42. package/dist/channel/adapters/discord.d.ts +45 -0
  43. package/dist/channel/adapters/discord.js +366 -0
  44. package/dist/channel/adapters/discord.js.map +1 -0
  45. package/dist/channel/adapters/telegram.d.ts +58 -0
  46. package/dist/channel/adapters/telegram.js +569 -0
  47. package/dist/channel/adapters/telegram.js.map +1 -0
  48. package/dist/channel/attachment-handler.d.ts +15 -0
  49. package/dist/channel/attachment-handler.js +55 -0
  50. package/dist/channel/attachment-handler.js.map +1 -0
  51. package/dist/channel/factory.d.ts +12 -0
  52. package/dist/channel/factory.js +38 -0
  53. package/dist/channel/factory.js.map +1 -0
  54. package/dist/channel/ipc-bridge.d.ts +26 -0
  55. package/dist/channel/ipc-bridge.js +170 -0
  56. package/dist/channel/ipc-bridge.js.map +1 -0
  57. package/dist/channel/mcp-server.d.ts +10 -0
  58. package/dist/channel/mcp-server.js +196 -0
  59. package/dist/channel/mcp-server.js.map +1 -0
  60. package/dist/channel/mcp-tools.d.ts +909 -0
  61. package/dist/channel/mcp-tools.js +346 -0
  62. package/dist/channel/mcp-tools.js.map +1 -0
  63. package/dist/channel/message-bus.d.ts +17 -0
  64. package/dist/channel/message-bus.js +86 -0
  65. package/dist/channel/message-bus.js.map +1 -0
  66. package/dist/channel/message-queue.d.ts +39 -0
  67. package/dist/channel/message-queue.js +248 -0
  68. package/dist/channel/message-queue.js.map +1 -0
  69. package/dist/channel/tool-router.d.ts +6 -0
  70. package/dist/channel/tool-router.js +69 -0
  71. package/dist/channel/tool-router.js.map +1 -0
  72. package/dist/channel/tool-tracker.d.ts +13 -0
  73. package/dist/channel/tool-tracker.js +58 -0
  74. package/dist/channel/tool-tracker.js.map +1 -0
  75. package/dist/channel/types.d.ts +116 -0
  76. package/dist/channel/types.js +2 -0
  77. package/dist/channel/types.js.map +1 -0
  78. package/dist/cli.d.ts +2 -0
  79. package/dist/cli.js +782 -0
  80. package/dist/cli.js.map +1 -0
  81. package/dist/config.d.ts +8 -0
  82. package/dist/config.js +85 -0
  83. package/dist/config.js.map +1 -0
  84. package/dist/container-manager.d.ts +24 -0
  85. package/dist/container-manager.js +148 -0
  86. package/dist/container-manager.js.map +1 -0
  87. package/dist/context-guardian.d.ts +29 -0
  88. package/dist/context-guardian.js +123 -0
  89. package/dist/context-guardian.js.map +1 -0
  90. package/dist/cost-guard.d.ts +21 -0
  91. package/dist/cost-guard.js +113 -0
  92. package/dist/cost-guard.js.map +1 -0
  93. package/dist/daemon-entry.d.ts +1 -0
  94. package/dist/daemon-entry.js +29 -0
  95. package/dist/daemon-entry.js.map +1 -0
  96. package/dist/daemon.d.ts +88 -0
  97. package/dist/daemon.js +820 -0
  98. package/dist/daemon.js.map +1 -0
  99. package/dist/daily-summary.d.ts +13 -0
  100. package/dist/daily-summary.js +55 -0
  101. package/dist/daily-summary.js.map +1 -0
  102. package/dist/db.d.ts +10 -0
  103. package/dist/db.js +43 -0
  104. package/dist/db.js.map +1 -0
  105. package/dist/event-log.d.ts +22 -0
  106. package/dist/event-log.js +66 -0
  107. package/dist/event-log.js.map +1 -0
  108. package/dist/export-import.d.ts +2 -0
  109. package/dist/export-import.js +110 -0
  110. package/dist/export-import.js.map +1 -0
  111. package/dist/fleet-context.d.ts +36 -0
  112. package/dist/fleet-context.js +4 -0
  113. package/dist/fleet-context.js.map +1 -0
  114. package/dist/fleet-manager.d.ts +115 -0
  115. package/dist/fleet-manager.js +1742 -0
  116. package/dist/fleet-manager.js.map +1 -0
  117. package/dist/fleet-system-prompt.d.ts +11 -0
  118. package/dist/fleet-system-prompt.js +60 -0
  119. package/dist/fleet-system-prompt.js.map +1 -0
  120. package/dist/hang-detector.d.ts +16 -0
  121. package/dist/hang-detector.js +53 -0
  122. package/dist/hang-detector.js.map +1 -0
  123. package/dist/index.d.ts +8 -0
  124. package/dist/index.js +6 -0
  125. package/dist/index.js.map +1 -0
  126. package/dist/install-recorder.d.ts +30 -0
  127. package/dist/install-recorder.js +159 -0
  128. package/dist/install-recorder.js.map +1 -0
  129. package/dist/logger.d.ts +3 -0
  130. package/dist/logger.js +63 -0
  131. package/dist/logger.js.map +1 -0
  132. package/dist/meeting/orchestrator.d.ts +30 -0
  133. package/dist/meeting/orchestrator.js +355 -0
  134. package/dist/meeting/orchestrator.js.map +1 -0
  135. package/dist/meeting/prompt-builder.d.ts +12 -0
  136. package/dist/meeting/prompt-builder.js +96 -0
  137. package/dist/meeting/prompt-builder.js.map +1 -0
  138. package/dist/meeting/role-assigner.d.ts +2 -0
  139. package/dist/meeting/role-assigner.js +25 -0
  140. package/dist/meeting/role-assigner.js.map +1 -0
  141. package/dist/meeting/types.d.ts +21 -0
  142. package/dist/meeting/types.js +2 -0
  143. package/dist/meeting/types.js.map +1 -0
  144. package/dist/meeting-manager.d.ts +10 -0
  145. package/dist/meeting-manager.js +38 -0
  146. package/dist/meeting-manager.js.map +1 -0
  147. package/dist/memory-layer.d.ts +13 -0
  148. package/dist/memory-layer.js +44 -0
  149. package/dist/memory-layer.js.map +1 -0
  150. package/dist/plugin/agend/.claude-plugin/plugin.json +5 -0
  151. package/dist/plugin/agend/.mcp.json +9 -0
  152. package/dist/plugin/ccd-channel/.claude-plugin/plugin.json +5 -0
  153. package/dist/plugin/ccd-channel/.mcp.json +9 -0
  154. package/dist/process-manager.d.ts +31 -0
  155. package/dist/process-manager.js +264 -0
  156. package/dist/process-manager.js.map +1 -0
  157. package/dist/scheduler/db.d.ts +16 -0
  158. package/dist/scheduler/db.js +132 -0
  159. package/dist/scheduler/db.js.map +1 -0
  160. package/dist/scheduler/db.test.d.ts +1 -0
  161. package/dist/scheduler/db.test.js +92 -0
  162. package/dist/scheduler/db.test.js.map +1 -0
  163. package/dist/scheduler/index.d.ts +4 -0
  164. package/dist/scheduler/index.js +4 -0
  165. package/dist/scheduler/index.js.map +1 -0
  166. package/dist/scheduler/scheduler.d.ts +25 -0
  167. package/dist/scheduler/scheduler.js +119 -0
  168. package/dist/scheduler/scheduler.js.map +1 -0
  169. package/dist/scheduler/scheduler.test.d.ts +1 -0
  170. package/dist/scheduler/scheduler.test.js +119 -0
  171. package/dist/scheduler/scheduler.test.js.map +1 -0
  172. package/dist/scheduler/types.d.ts +47 -0
  173. package/dist/scheduler/types.js +7 -0
  174. package/dist/scheduler/types.js.map +1 -0
  175. package/dist/service-installer.d.ts +14 -0
  176. package/dist/service-installer.js +91 -0
  177. package/dist/service-installer.js.map +1 -0
  178. package/dist/setup-wizard.d.ts +14 -0
  179. package/dist/setup-wizard.js +517 -0
  180. package/dist/setup-wizard.js.map +1 -0
  181. package/dist/stt.d.ts +10 -0
  182. package/dist/stt.js +33 -0
  183. package/dist/stt.js.map +1 -0
  184. package/dist/tmux-manager.d.ts +22 -0
  185. package/dist/tmux-manager.js +131 -0
  186. package/dist/tmux-manager.js.map +1 -0
  187. package/dist/topic-commands.d.ts +22 -0
  188. package/dist/topic-commands.js +176 -0
  189. package/dist/topic-commands.js.map +1 -0
  190. package/dist/transcript-monitor.d.ts +21 -0
  191. package/dist/transcript-monitor.js +149 -0
  192. package/dist/transcript-monitor.js.map +1 -0
  193. package/dist/types.d.ts +153 -0
  194. package/dist/types.js +2 -0
  195. package/dist/types.js.map +1 -0
  196. package/dist/webhook-emitter.d.ts +15 -0
  197. package/dist/webhook-emitter.js +41 -0
  198. package/dist/webhook-emitter.js.map +1 -0
  199. package/package.json +60 -4
  200. package/templates/launchd.plist.ejs +29 -0
  201. package/templates/systemd.service.ejs +15 -0
  202. package/index.js +0 -1
@@ -0,0 +1,156 @@
1
+ import { createServer } from "node:http";
2
+ import { randomBytes } from "node:crypto";
3
+ const DANGER_PATTERNS = [
4
+ /\brm\b/, // any file deletion
5
+ /\bgit\s+push\b/, // any push (not just --force)
6
+ /\bgit\s+reset\b/, // any reset
7
+ /\bgit\s+clean\b/, // any clean
8
+ /\bgit\s+checkout\s+\./, // discard changes
9
+ /\bgit\s+restore\b/, // discard changes
10
+ /\bmv\b/, // move/rename files
11
+ /\bdd\b/,
12
+ /\bmkfs\b/,
13
+ /\bsudo\b/,
14
+ /\bchmod\b/,
15
+ /\bchown\b/,
16
+ /\bkill\b/,
17
+ /\bpkill\b/,
18
+ /(?<!\d)>\s*\/(?:etc|usr|var|bin|sbin|lib|opt|root|System|Library)\b/, // redirect to system paths (not /tmp, not 2>/dev/null)
19
+ /(?:\/usr)?\/s?bin\/(rm|chmod|chown|mkfs|dd)\b/, // full path variants
20
+ /\b(?:command|env|builtin)\s+(rm|chmod|chown|sudo)\b/, // command wrappers
21
+ /\$\(.*\b(rm|dd|mkfs)\b/, // command substitution with dangerous commands
22
+ ];
23
+ function isSafeTool(toolName) {
24
+ if (toolName === "Bash" || toolName.startsWith("Bash("))
25
+ return false;
26
+ return true;
27
+ }
28
+ function isDangerousCommand(command) {
29
+ return DANGER_PATTERNS.some(pattern => pattern.test(command));
30
+ }
31
+ const APPROVAL_TIMEOUT_MS = 120_000;
32
+ export class ApprovalServer {
33
+ server = null;
34
+ messageBus;
35
+ port;
36
+ ipcServer;
37
+ topicMode;
38
+ instanceName;
39
+ token;
40
+ constructor(opts) {
41
+ this.messageBus = opts.messageBus;
42
+ this.port = opts.port;
43
+ this.ipcServer = opts.ipcServer ?? null;
44
+ this.topicMode = opts.topicMode ?? false;
45
+ this.instanceName = opts.instanceName ?? "";
46
+ this.token = randomBytes(32).toString("hex");
47
+ }
48
+ getToken() {
49
+ return this.token;
50
+ }
51
+ async start() {
52
+ return new Promise((resolve, reject) => {
53
+ this.server = createServer(async (req, res) => {
54
+ if (req.headers.authorization !== `Bearer ${this.token}`) {
55
+ res.writeHead(401);
56
+ res.end(JSON.stringify({ error: "Unauthorized" }));
57
+ return;
58
+ }
59
+ if (req.method !== "POST" || req.url !== "/approve") {
60
+ res.writeHead(404);
61
+ res.end(JSON.stringify({ error: "Not found" }));
62
+ return;
63
+ }
64
+ let body = "";
65
+ req.on("data", (chunk) => { body += chunk; });
66
+ req.on("end", async () => {
67
+ try {
68
+ const { tool_name, tool_input } = JSON.parse(body);
69
+ let permissionDecision;
70
+ let permissionDecisionReason;
71
+ if (tool_name === "Bash" && typeof tool_input?.command === "string" && isDangerousCommand(tool_input.command)) {
72
+ // Dangerous Bash commands → require human approval
73
+ const prompt = `⚠️ ${tool_name}\n\`\`\`\n${tool_input.command}\n\`\`\``;
74
+ const decision = await this.requestApproval(prompt);
75
+ permissionDecision = decision;
76
+ permissionDecisionReason = decision === "allow"
77
+ ? "approved by user"
78
+ : "denied by user";
79
+ }
80
+ else {
81
+ // Everything else (all tools + normal Bash) → auto-allow
82
+ permissionDecision = "allow";
83
+ }
84
+ res.writeHead(200, { "Content-Type": "application/json" });
85
+ res.end(JSON.stringify({
86
+ hookSpecificOutput: {
87
+ hookEventName: "PreToolUse",
88
+ permissionDecision,
89
+ ...(permissionDecisionReason ? { permissionDecisionReason } : {}),
90
+ },
91
+ }));
92
+ }
93
+ catch (err) {
94
+ res.writeHead(400, { "Content-Type": "application/json" });
95
+ res.end(JSON.stringify({ error: "Bad request" }));
96
+ }
97
+ });
98
+ });
99
+ this.server.on("error", reject);
100
+ this.server.listen(this.port, "127.0.0.1", () => {
101
+ const address = this.server.address();
102
+ const actualPort = typeof address === "object" && address !== null ? address.port : this.port;
103
+ resolve(actualPort);
104
+ });
105
+ });
106
+ }
107
+ requestApproval(prompt) {
108
+ if (this.topicMode && this.ipcServer) {
109
+ return this.requestApprovalViaIpc(prompt);
110
+ }
111
+ return this.requestApprovalViaBus(prompt);
112
+ }
113
+ /** DM mode: use messageBus directly (adapter is registered on this daemon) */
114
+ async requestApprovalViaBus(prompt) {
115
+ const result = await this.messageBus.requestApproval(prompt);
116
+ return result.decision === "deny" ? "deny" : "allow";
117
+ }
118
+ /** Topic mode: forward approval request to fleet manager via IPC */
119
+ requestApprovalViaIpc(prompt) {
120
+ return new Promise((resolve) => {
121
+ const approvalId = `approval-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
122
+ const timeout = setTimeout(() => {
123
+ cleanup();
124
+ resolve("deny");
125
+ }, APPROVAL_TIMEOUT_MS);
126
+ const onMessage = (msg) => {
127
+ if (msg.type === "fleet_approval_response" && msg.approvalId === approvalId) {
128
+ cleanup();
129
+ resolve(msg.decision === "deny" ? "deny" : "allow");
130
+ }
131
+ };
132
+ const cleanup = () => {
133
+ clearTimeout(timeout);
134
+ this.ipcServer?.removeListener("message", onMessage);
135
+ };
136
+ this.ipcServer?.on("message", onMessage);
137
+ this.ipcServer?.broadcast({
138
+ type: "fleet_approval_request",
139
+ approvalId,
140
+ instanceName: this.instanceName,
141
+ prompt,
142
+ });
143
+ });
144
+ }
145
+ async stop() {
146
+ return new Promise((resolve) => {
147
+ if (!this.server) {
148
+ resolve();
149
+ return;
150
+ }
151
+ this.server.close(() => resolve());
152
+ this.server = null;
153
+ });
154
+ }
155
+ }
156
+ //# sourceMappingURL=approval-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-server.js","sourceRoot":"","sources":["../../src/approval/approval-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { TmuxManager } from "../tmux-manager.js";
2
+ import type { ApprovalResponse } from "../channel/types.js";
3
+ export type PromptType = "permission" | "settings_error" | "dev_channels" | "mcp_trust" | "file_creation" | "unknown";
4
+ /** Detect whether text contains a Claude Code interactive prompt */
5
+ export declare function detectInteractivePrompt(text: string): boolean;
6
+ /** Classify a detected prompt to determine handling strategy */
7
+ export declare function classifyPrompt(text: string): PromptType;
8
+ export declare function detectPermissionPrompt(text: string): boolean;
9
+ /**
10
+ * Extract tool name from Claude Code permission prompt text.
11
+ * Returns the permission-format tool name (e.g. "mcp__puppeteer__puppeteer_navigate").
12
+ */
13
+ export declare function extractToolPattern(text: string): string | null;
14
+ /** Build a clean prompt message for Telegram display */
15
+ export declare function formatPromptForDisplay(text: string): string;
16
+ export declare function loadToolAllowlist(instanceDir: string): string[];
17
+ export declare function saveToolToAllowlist(instanceDir: string, pattern: string): void;
18
+ export declare class TmuxPromptDetector {
19
+ private outputLogPath;
20
+ private tmux;
21
+ private approvalFn;
22
+ private logger;
23
+ private instanceDir?;
24
+ private pollTimer;
25
+ private byteOffset;
26
+ private pendingApproval;
27
+ constructor(outputLogPath: string, tmux: TmuxManager, approvalFn: (prompt: string) => Promise<ApprovalResponse>, logger: {
28
+ info(...args: any[]): void;
29
+ warn(...args: any[]): void;
30
+ error(...args: any[]): void;
31
+ }, instanceDir?: string | undefined);
32
+ startPolling(intervalMs?: number): void;
33
+ stop(): void;
34
+ }
@@ -0,0 +1,264 @@
1
+ import { readFileSync, statSync, writeFileSync, existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ /** Strip ANSI escape codes from terminal output */
4
+ function stripAnsi(text) {
5
+ // eslint-disable-next-line no-control-regex
6
+ return text.replace(/\x1b\[\d*C/g, " ") // cursor forward → space
7
+ .replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "") // other CSI sequences
8
+ .replace(/\x1b\][^\x07]*\x07/g, "") // OSC sequences
9
+ .replace(/\x1b[()][0-9A-B]/g, "") // charset switches
10
+ .replace(/[\x00-\x08\x0e-\x1f]/g, ""); // misc control chars
11
+ }
12
+ /** Detect whether text contains a Claude Code interactive prompt */
13
+ export function detectInteractivePrompt(text) {
14
+ const clean = stripAnsi(text);
15
+ // All Claude Code interactive prompts have numbered options like "1." or "❯ 1."
16
+ // combined with "Esc to cancel" or "Enter to confirm"
17
+ const hasNumberedOption = /[❯>]?\s*1\.\s/.test(clean);
18
+ const hasPromptChrome = /Esc to cancel|Enter to confirm/.test(clean);
19
+ return hasNumberedOption && hasPromptChrome;
20
+ }
21
+ /** Classify a detected prompt to determine handling strategy */
22
+ export function classifyPrompt(text) {
23
+ const clean = stripAnsi(text);
24
+ // Permission / tool use: "Do you want to proceed?" with Yes/No
25
+ if (/Do you want to proceed/i.test(clean) && /\bYes\b/.test(clean) && /\bNo\b/.test(clean)) {
26
+ return "permission";
27
+ }
28
+ // Settings error: has "Settings Error" or "Continue without these settings"
29
+ if (/Settings Error/i.test(clean) || /Continue without these settings/i.test(clean)) {
30
+ return "settings_error";
31
+ }
32
+ // Dev channels: "I am using this for local development"
33
+ if (/I am using this for local development/i.test(clean)) {
34
+ return "dev_channels";
35
+ }
36
+ // MCP trust: "New MCP server found" or "Use this and all future"
37
+ if (/New MCP server found/i.test(clean) || /Use this and all future/i.test(clean)) {
38
+ return "mcp_trust";
39
+ }
40
+ // File creation: "Do you want to create"
41
+ if (/Do you want to create/i.test(clean)) {
42
+ return "file_creation";
43
+ }
44
+ return "unknown";
45
+ }
46
+ // ── Kept for backwards compat with tests ─────────────────────────────────────
47
+ export function detectPermissionPrompt(text) {
48
+ const clean = stripAnsi(text);
49
+ return /1\.\s*Yes\b/.test(clean) && /3\.\s*No\b/.test(clean);
50
+ }
51
+ /**
52
+ * Extract tool name from Claude Code permission prompt text.
53
+ * Returns the permission-format tool name (e.g. "mcp__puppeteer__puppeteer_navigate").
54
+ */
55
+ export function extractToolPattern(text) {
56
+ const clean = stripAnsi(text);
57
+ // "don't" may appear as don't, don.t, or dont (apostrophe stripped by terminal)
58
+ const m = clean.match(/don.?t ask again for\s+(.+?)\s+commands?\s+in\b/i);
59
+ if (!m)
60
+ return null;
61
+ const display = m[1].trim();
62
+ // MCP tool: "server - tool_name" → "mcp__server__tool_name"
63
+ const mcpMatch = display.match(/^(\S+)\s*-\s*(\S+)$/);
64
+ if (mcpMatch) {
65
+ return `mcp__${mcpMatch[1]}__${mcpMatch[2]}`;
66
+ }
67
+ // Built-in tool: "Bash" → "Bash(*)"
68
+ return `${display}(*)`;
69
+ }
70
+ /** Build a clean prompt message for Telegram display */
71
+ export function formatPromptForDisplay(text) {
72
+ const clean = stripAnsi(text)
73
+ .replace(/\r/g, "")
74
+ .replace(/\n{3,}/g, "\n\n")
75
+ .trim();
76
+ // Tool use prompt: extract tool name and args
77
+ const toolMatch = clean.match(/(\S+\s*-\s*\S+)\s*\(([^)]*)\)\s*\(MCP\)/i)
78
+ ?? clean.match(/(\S+)\s*\(([^)]*)\)/);
79
+ if (toolMatch) {
80
+ const tool = toolMatch[1].trim();
81
+ const args = toolMatch[2].trim();
82
+ const truncatedArgs = args.length > 200 ? args.slice(0, 200) + "…" : args;
83
+ return `⚠️ ${tool}\n\`\`\`\n${truncatedArgs}\n\`\`\``;
84
+ }
85
+ // Fallback: cleaned text, truncated
86
+ const truncated = clean.length > 500 ? clean.slice(0, 500) + "…" : clean;
87
+ return `⚠️ Prompt\n${truncated}`;
88
+ }
89
+ // ── Persistent tool allowlist ────────────────────────────────────────────────
90
+ const ALLOWLIST_FILE = "tool-allowlist.json";
91
+ export function loadToolAllowlist(instanceDir) {
92
+ const p = join(instanceDir, ALLOWLIST_FILE);
93
+ if (!existsSync(p))
94
+ return [];
95
+ try {
96
+ const data = JSON.parse(readFileSync(p, "utf8"));
97
+ return Array.isArray(data) ? data : [];
98
+ }
99
+ catch {
100
+ return [];
101
+ }
102
+ }
103
+ export function saveToolToAllowlist(instanceDir, pattern) {
104
+ const list = loadToolAllowlist(instanceDir);
105
+ if (!list.includes(pattern)) {
106
+ list.push(pattern);
107
+ writeFileSync(join(instanceDir, ALLOWLIST_FILE), JSON.stringify(list, null, 2));
108
+ }
109
+ }
110
+ // ── Prompt handler helpers ───────────────────────────────────────────────────
111
+ /**
112
+ * Select option N in a Claude Code interactive menu.
113
+ * Option 1 is pre-selected (❯), so:
114
+ * option 1 → Enter
115
+ * option 2 → Down + Enter
116
+ * option 3 → Down + Down + Enter
117
+ */
118
+ async function selectOption(tmux, option) {
119
+ for (let i = 1; i < option; i++) {
120
+ await tmux.sendSpecialKey("Down");
121
+ }
122
+ await tmux.sendSpecialKey("Enter");
123
+ }
124
+ async function pressEscape(tmux) {
125
+ await tmux.sendSpecialKey("Escape");
126
+ }
127
+ // ── Main detector ────────────────────────────────────────────────────────────
128
+ export class TmuxPromptDetector {
129
+ outputLogPath;
130
+ tmux;
131
+ approvalFn;
132
+ logger;
133
+ instanceDir;
134
+ pollTimer = null;
135
+ byteOffset = 0;
136
+ pendingApproval = false;
137
+ constructor(outputLogPath, tmux, approvalFn, logger, instanceDir) {
138
+ this.outputLogPath = outputLogPath;
139
+ this.tmux = tmux;
140
+ this.approvalFn = approvalFn;
141
+ this.logger = logger;
142
+ this.instanceDir = instanceDir;
143
+ }
144
+ startPolling(intervalMs = 2000) {
145
+ if (this.pollTimer !== null)
146
+ return;
147
+ // Skip existing content — only detect prompts written after we start
148
+ try {
149
+ this.byteOffset = statSync(this.outputLogPath).size;
150
+ }
151
+ catch { /* file may not exist yet */ }
152
+ this.pollTimer = setInterval(async () => {
153
+ // Read new content from log file
154
+ let newContent;
155
+ try {
156
+ const stat = statSync(this.outputLogPath);
157
+ const fileSize = stat.size;
158
+ if (fileSize <= this.byteOffset)
159
+ return;
160
+ const buf = Buffer.alloc(fileSize - this.byteOffset);
161
+ const fd = await import("node:fs").then(fs => fs.openSync(this.outputLogPath, "r"));
162
+ const { readSync, closeSync } = await import("node:fs");
163
+ const bytesRead = readSync(fd, buf, 0, buf.length, this.byteOffset);
164
+ closeSync(fd);
165
+ if (bytesRead <= 0)
166
+ return;
167
+ newContent = buf.subarray(0, bytesRead).toString("utf8");
168
+ this.byteOffset += bytesRead;
169
+ }
170
+ catch {
171
+ // File may not exist yet (ENOENT); silently ignore
172
+ return;
173
+ }
174
+ // Detect and handle prompts
175
+ try {
176
+ if (!detectInteractivePrompt(newContent) || this.pendingApproval)
177
+ return;
178
+ const promptType = classifyPrompt(newContent);
179
+ this.logger.info({ promptType }, "TmuxPromptDetector: interactive prompt detected");
180
+ switch (promptType) {
181
+ case "dev_channels":
182
+ case "mcp_trust":
183
+ // Auto-confirm: option 1 is already selected
184
+ await selectOption(this.tmux, 1);
185
+ this.logger.info({ promptType }, "TmuxPromptDetector: auto-confirmed");
186
+ break;
187
+ case "settings_error":
188
+ // "Continue without these settings" is option 2
189
+ await selectOption(this.tmux, 2);
190
+ this.logger.info("TmuxPromptDetector: auto-continued past settings error");
191
+ break;
192
+ case "file_creation":
193
+ // Auto-deny file creation prompts (SKILL.md etc.)
194
+ await pressEscape(this.tmux);
195
+ this.logger.info("TmuxPromptDetector: auto-denied file creation");
196
+ break;
197
+ case "permission":
198
+ // Forward to user via Telegram
199
+ this.pendingApproval = true;
200
+ try {
201
+ const toolPattern = extractToolPattern(newContent);
202
+ const cleanPrompt = formatPromptForDisplay(newContent);
203
+ const result = await this.approvalFn(cleanPrompt);
204
+ this.logger.info({ decision: result.decision }, "TmuxPromptDetector: user responded");
205
+ if (result.decision === "always_allow") {
206
+ await selectOption(this.tmux, 2); // "Yes, and don't ask again"
207
+ if (toolPattern && this.instanceDir) {
208
+ saveToolToAllowlist(this.instanceDir, toolPattern);
209
+ this.logger.info({ toolPattern }, "TmuxPromptDetector: added to allowlist");
210
+ }
211
+ }
212
+ else if (result.decision === "approve") {
213
+ await selectOption(this.tmux, 1); // "Yes"
214
+ }
215
+ else {
216
+ await selectOption(this.tmux, 3); // "No"
217
+ }
218
+ }
219
+ catch (err) {
220
+ this.logger.warn("TmuxPromptDetector: approval error, denying", err);
221
+ await pressEscape(this.tmux);
222
+ }
223
+ finally {
224
+ this.pendingApproval = false;
225
+ }
226
+ break;
227
+ case "unknown":
228
+ default:
229
+ // Forward unknown prompts to user too
230
+ this.pendingApproval = true;
231
+ try {
232
+ const cleanPrompt = formatPromptForDisplay(newContent);
233
+ const result = await this.approvalFn(cleanPrompt);
234
+ this.logger.info({ decision: result.decision }, "TmuxPromptDetector: user responded to unknown prompt");
235
+ if (result.decision === "deny") {
236
+ await pressEscape(this.tmux);
237
+ }
238
+ else {
239
+ await selectOption(this.tmux, 1);
240
+ }
241
+ }
242
+ catch (err) {
243
+ this.logger.error({ err }, "Unknown prompt approval error");
244
+ await pressEscape(this.tmux);
245
+ }
246
+ finally {
247
+ this.pendingApproval = false;
248
+ }
249
+ break;
250
+ }
251
+ }
252
+ catch (err) {
253
+ this.logger.error({ err }, "Prompt detection error");
254
+ }
255
+ }, intervalMs);
256
+ }
257
+ stop() {
258
+ if (this.pollTimer !== null) {
259
+ clearInterval(this.pollTimer);
260
+ this.pollTimer = null;
261
+ }
262
+ }
263
+ }
264
+ //# sourceMappingURL=tmux-prompt-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux-prompt-detector.js","sourceRoot":"","sources":["../../src/approval/tmux-prompt-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface ApprovalStrategy {
2
+ /**
3
+ * Return hook definitions to merge into CLI settings.
4
+ * Hook-based: returns { hooks: { PreToolUse: [...] } }
5
+ * Shell-wrapper: returns {} (no hooks needed)
6
+ */
7
+ setup(port: number): {
8
+ hooks?: Record<string, unknown>;
9
+ };
10
+ /** Start the approval service. Returns the actual port. */
11
+ start(): Promise<number>;
12
+ /** Stop the approval service */
13
+ stop(): Promise<void>;
14
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=approval-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-strategy.js","sourceRoot":"","sources":["../../src/backend/approval-strategy.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import type { CliBackend, CliBackendConfig } from "./types.js";
2
+ export declare class ClaudeCodeBackend implements CliBackend {
3
+ private instanceDir;
4
+ constructor(instanceDir: string);
5
+ buildCommand(config: CliBackendConfig): string;
6
+ writeConfig(config: CliBackendConfig): void;
7
+ getContextUsage(): number | null;
8
+ getSessionId(): string | null;
9
+ cleanup(_config: CliBackendConfig): void;
10
+ /** Pre-approve ANTHROPIC_API_KEY in ~/.claude.json to skip the interactive prompt */
11
+ private preApproveApiKey;
12
+ private writeStatusLineScript;
13
+ }
@@ -0,0 +1,114 @@
1
+ import { join } from "node:path";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ export class ClaudeCodeBackend {
5
+ instanceDir;
6
+ constructor(instanceDir) {
7
+ this.instanceDir = instanceDir;
8
+ }
9
+ buildCommand(config) {
10
+ const settingsPath = join(this.instanceDir, "claude-settings.json");
11
+ const mcpConfigPath = join(this.instanceDir, "mcp-config.json");
12
+ // Forward Anthropic env vars to the CLI process (tmux shell doesn't inherit daemon's env)
13
+ const envPrefix = ["CMUX_CLAUDE_HOOKS_DISABLED=1", "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"];
14
+ for (const key of ["ANTHROPIC_BASE_URL", "ANTHROPIC_API_KEY"]) {
15
+ if (process.env[key])
16
+ envPrefix.push(`${key}=${process.env[key]}`);
17
+ }
18
+ let cmd = `${envPrefix.join(" ")} claude --settings ${settingsPath} --mcp-config ${mcpConfigPath} --dangerously-skip-permissions`;
19
+ const sessionIdFile = join(this.instanceDir, "session-id");
20
+ if (existsSync(sessionIdFile)) {
21
+ const sid = readFileSync(sessionIdFile, "utf-8").trim();
22
+ if (sid && /^[a-zA-Z0-9_-]+$/.test(sid))
23
+ cmd += ` --resume ${sid}`;
24
+ }
25
+ if (config.model) {
26
+ cmd += ` --model ${config.model}`;
27
+ }
28
+ if (config.systemPrompt) {
29
+ const promptPath = join(this.instanceDir, "system-prompt.md");
30
+ writeFileSync(promptPath, config.systemPrompt);
31
+ cmd += ` --system-prompt "${promptPath}"`;
32
+ }
33
+ return cmd;
34
+ }
35
+ writeConfig(config) {
36
+ // 1. Write mcp-config.json to instance dir (loaded via --mcp-config)
37
+ const mcpConfigPath = join(this.instanceDir, "mcp-config.json");
38
+ const mcpConfig = { mcpServers: config.mcpServers };
39
+ writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
40
+ // 2. Write statusline script
41
+ const statusLineCommand = this.writeStatusLineScript();
42
+ // 3. Write claude-settings.json (permissions handled by --dangerously-skip-permissions)
43
+ const settings = {
44
+ statusLine: {
45
+ type: "command",
46
+ command: statusLineCommand,
47
+ },
48
+ };
49
+ writeFileSync(join(this.instanceDir, "claude-settings.json"), JSON.stringify(settings));
50
+ // 4. Pre-approve API key to skip interactive prompt on startup
51
+ this.preApproveApiKey(config);
52
+ }
53
+ getContextUsage() {
54
+ try {
55
+ const sf = join(this.instanceDir, "statusline.json");
56
+ const data = JSON.parse(readFileSync(sf, "utf-8"));
57
+ return data.context_window?.used_percentage ?? null;
58
+ }
59
+ catch (err) {
60
+ // File may not exist yet during startup — return null to signal unavailable
61
+ return null;
62
+ }
63
+ }
64
+ getSessionId() {
65
+ try {
66
+ const sf = join(this.instanceDir, "statusline.json");
67
+ const data = JSON.parse(readFileSync(sf, "utf-8"));
68
+ return data.session_id ?? null;
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ cleanup(_config) {
75
+ // mcp-config.json is in instance dir, cleaned up when instance is deleted
76
+ }
77
+ /** Pre-approve ANTHROPIC_API_KEY in ~/.claude.json to skip the interactive prompt */
78
+ preApproveApiKey(_config) {
79
+ const apiKey = process.env.ANTHROPIC_API_KEY;
80
+ if (!apiKey)
81
+ return;
82
+ const fingerprint = apiKey.length > 20 ? apiKey.slice(-20) : apiKey;
83
+ const claudeJsonPath = join(homedir(), ".claude.json");
84
+ let claudeCfg = {};
85
+ try {
86
+ claudeCfg = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
87
+ }
88
+ catch { /* new file or parse error */ }
89
+ const existing = claudeCfg.customApiKeyResponses;
90
+ const approved = existing?.approved ?? [];
91
+ if (!approved.includes(fingerprint)) {
92
+ claudeCfg.customApiKeyResponses = {
93
+ approved: [...approved, fingerprint],
94
+ rejected: existing?.rejected ?? [],
95
+ };
96
+ writeFileSync(claudeJsonPath, JSON.stringify(claudeCfg, null, 2));
97
+ }
98
+ }
99
+ writeStatusLineScript() {
100
+ const statusFile = join(this.instanceDir, "statusline.json");
101
+ // Use a Node.js script instead of bash to avoid shell injection via statusFile path
102
+ const script = [
103
+ "#!/usr/bin/env node",
104
+ "const fs = require('fs');",
105
+ "let input = '';",
106
+ "process.stdin.on('data', d => input += d);",
107
+ `process.stdin.on('end', () => { fs.writeFileSync(${JSON.stringify(statusFile)}, input); console.log('ok'); });`,
108
+ ].join("\n");
109
+ const scriptPath = join(this.instanceDir, "statusline.js");
110
+ writeFileSync(scriptPath, script, { mode: 0o755 });
111
+ return scriptPath;
112
+ }
113
+ }
114
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/backend/claude-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { CliBackend, CliBackendConfig } from "./types.js";
2
+ export declare class CodexBackend implements CliBackend {
3
+ private instanceDir;
4
+ constructor(instanceDir: string);
5
+ buildCommand(config: CliBackendConfig): string;
6
+ writeConfig(config: CliBackendConfig): void;
7
+ getContextUsage(): number | null;
8
+ getSessionId(): string | null;
9
+ cleanup(config: CliBackendConfig): void;
10
+ }