@suzuke/agend 1.0.0 → 1.0.2
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/README.md +50 -528
- package/README.zh-TW.md +49 -474
- package/dist/channel/adapters/discord.js +1 -1
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/factory.js +2 -2
- package/dist/channel/factory.js.map +1 -1
- package/dist/channel/mcp-tools.js +3 -3
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +37 -36
- package/dist/daemon.js.map +1 -1
- package/dist/export-import.js +2 -2
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-manager.js +5 -8
- package/dist/fleet-manager.js.map +1 -1
- package/dist/setup-wizard.js +2 -2
- package/dist/setup-wizard.js.map +1 -1
- package/dist/tmux-manager.js +3 -2
- package/dist/tmux-manager.js.map +1 -1
- package/package.json +3 -5
- package/dist/approval/approval-server.d.ts +0 -30
- package/dist/approval/approval-server.js +0 -156
- package/dist/approval/approval-server.js.map +0 -1
- package/dist/approval/tmux-prompt-detector.d.ts +0 -34
- package/dist/approval/tmux-prompt-detector.js +0 -264
- package/dist/approval/tmux-prompt-detector.js.map +0 -1
- package/dist/backend/approval-strategy.d.ts +0 -14
- package/dist/backend/approval-strategy.js +0 -2
- package/dist/backend/approval-strategy.js.map +0 -1
- package/dist/backend/hook-based-approval.d.ts +0 -20
- package/dist/backend/hook-based-approval.js +0 -41
- package/dist/backend/hook-based-approval.js.map +0 -1
- package/dist/container-manager.d.ts +0 -24
- package/dist/container-manager.js +0 -148
- package/dist/container-manager.js.map +0 -1
- package/dist/db.d.ts +0 -10
- package/dist/db.js +0 -43
- package/dist/db.js.map +0 -1
- package/dist/install-recorder.d.ts +0 -30
- package/dist/install-recorder.js +0 -159
- package/dist/install-recorder.js.map +0 -1
- package/dist/meeting/orchestrator.d.ts +0 -30
- package/dist/meeting/orchestrator.js +0 -355
- package/dist/meeting/orchestrator.js.map +0 -1
- package/dist/meeting/prompt-builder.d.ts +0 -12
- package/dist/meeting/prompt-builder.js +0 -96
- package/dist/meeting/prompt-builder.js.map +0 -1
- package/dist/meeting/role-assigner.d.ts +0 -2
- package/dist/meeting/role-assigner.js +0 -25
- package/dist/meeting/role-assigner.js.map +0 -1
- package/dist/meeting/types.d.ts +0 -21
- package/dist/meeting/types.js +0 -2
- package/dist/meeting/types.js.map +0 -1
- package/dist/meeting-manager.d.ts +0 -10
- package/dist/meeting-manager.js +0 -38
- package/dist/meeting-manager.js.map +0 -1
- package/dist/memory-layer.d.ts +0 -13
- package/dist/memory-layer.js +0 -44
- package/dist/memory-layer.js.map +0 -1
- package/dist/plugin/agend/.mcp.json +0 -9
- package/dist/plugin/ccd-channel/.claude-plugin/plugin.json +0 -5
- package/dist/plugin/ccd-channel/.mcp.json +0 -9
- package/dist/process-manager.d.ts +0 -31
- package/dist/process-manager.js +0 -264
- package/dist/process-manager.js.map +0 -1
|
@@ -1,156 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"approval-server.js","sourceRoot":"","sources":["../../src/approval/approval-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,34 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,264 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tmux-prompt-detector.js","sourceRoot":"","sources":["../../src/approval/tmux-prompt-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,mDAAmD;AACnD,SAAS,SAAS,CAAC,IAAY;IAC7B,4CAA4C;IAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAY,yBAAyB;SAChE,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAE,sBAAsB;SAC7D,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAM,gBAAgB;SACxD,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAQ,mBAAmB;SAC3D,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC,CAAG,qBAAqB;AAC3E,CAAC;AAYD,oEAAoE;AACpE,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,gFAAgF;IAChF,sDAAsD;IACtD,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,eAAe,GAAG,gCAAgC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrE,OAAO,iBAAiB,IAAI,eAAe,CAAC;AAC9C,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE9B,+DAA+D;IAC/D,IAAI,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3F,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,4EAA4E;IAC5E,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpF,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,wDAAwD;IACxD,IAAI,wCAAwC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,iEAAiE;IACjE,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAClF,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,yCAAyC;IACzC,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,gFAAgF;IAChF,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAC1E,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5B,4DAA4D;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACtD,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,CAAC;IACD,oCAAoC;IACpC,OAAO,GAAG,OAAO,KAAK,CAAC;AACzB,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC;SAC1B,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;SAClB,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,IAAI,EAAE,CAAC;IAEV,8CAA8C;IAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,0CAA0C,CAAC;WACvD,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACrD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1E,OAAO,MAAM,IAAI,aAAa,aAAa,UAAU,CAAC;IACxD,CAAC;IAED,oCAAoC;IACpC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;IACzE,OAAO,cAAc,SAAS,EAAE,CAAC;AACnC,CAAC;AAED,gFAAgF;AAEhF,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAE7C,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC5C,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,OAAe;IACtE,MAAM,IAAI,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnB,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF;;;;;;GAMG;AACH,KAAK,UAAU,YAAY,CAAC,IAAiB,EAAE,MAAc;IAC3D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAiB;IAC1C,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED,gFAAgF;AAEhF,MAAM,OAAO,kBAAkB;IAMnB;IACA;IACA;IACA;IACA;IATF,SAAS,GAA0C,IAAI,CAAC;IACxD,UAAU,GAAG,CAAC,CAAC;IACf,eAAe,GAAG,KAAK,CAAC;IAEhC,YACU,aAAqB,EACrB,IAAiB,EACjB,UAAyD,EACzD,MAA+F,EAC/F,WAAoB;QAJpB,kBAAa,GAAb,aAAa,CAAQ;QACrB,SAAI,GAAJ,IAAI,CAAa;QACjB,eAAU,GAAV,UAAU,CAA+C;QACzD,WAAM,GAAN,MAAM,CAAyF;QAC/F,gBAAW,GAAX,WAAW,CAAS;IAC3B,CAAC;IAEJ,YAAY,CAAC,UAAU,GAAG,IAAI;QAC5B,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;YAAE,OAAO;QAEpC,qEAAqE;QACrE,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC,CAAC,4BAA4B,CAAC,CAAC;QAExC,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YACtC,iCAAiC;YACjC,IAAI,UAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3B,IAAI,QAAQ,IAAI,IAAI,CAAC,UAAU;oBAAE,OAAO;gBAExC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;gBACrD,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC;gBACpF,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;gBACxD,MAAM,SAAS,GAAG,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;gBACpE,SAAS,CAAC,EAAE,CAAC,CAAC;gBACd,IAAI,SAAS,IAAI,CAAC;oBAAE,OAAO;gBAE3B,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACzD,IAAI,CAAC,UAAU,IAAI,SAAS,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,mDAAmD;gBACnD,OAAO;YACT,CAAC;YAED,4BAA4B;YAC5B,IAAI,CAAC;gBACH,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,eAAe;oBAAE,OAAO;gBAEzE,MAAM,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;gBAC9C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,iDAAiD,CAAC,CAAC;gBAEpF,QAAQ,UAAU,EAAE,CAAC;oBACnB,KAAK,cAAc,CAAC;oBACpB,KAAK,WAAW;wBACd,6CAA6C;wBAC7C,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;wBACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,oCAAoC,CAAC,CAAC;wBACvE,MAAM;oBAER,KAAK,gBAAgB;wBACnB,gDAAgD;wBAChD,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;wBACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;wBAC3E,MAAM;oBAER,KAAK,eAAe;wBAClB,kDAAkD;wBAClD,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;wBAClE,MAAM;oBAER,KAAK,YAAY;wBACf,+BAA+B;wBAC/B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;wBAC5B,IAAI,CAAC;4BACH,MAAM,WAAW,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;4BACnD,MAAM,WAAW,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;4BACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;4BAClD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,oCAAoC,CAAC,CAAC;4BAEtF,IAAI,MAAM,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;gCACvC,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,6BAA6B;gCAC/D,IAAI,WAAW,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oCACpC,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;oCACnD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,wCAAwC,CAAC,CAAC;gCAC9E,CAAC;4BACH,CAAC;iCAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gCACzC,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ;4BAC5C,CAAC;iCAAM,CAAC;gCACN,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO;4BAC3C,CAAC;wBACH,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE,GAAG,CAAC,CAAC;4BACrE,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC/B,CAAC;gCAAS,CAAC;4BACT,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;wBAC/B,CAAC;wBACD,MAAM;oBAER,KAAK,SAAS,CAAC;oBACf;wBACE,sCAAsC;wBACtC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;wBAC5B,IAAI,CAAC;4BACH,MAAM,WAAW,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;4BACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;4BAClD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,sDAAsD,CAAC,CAAC;4BACxG,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;gCAC/B,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BAC/B,CAAC;iCAAM,CAAC;gCACN,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;4BACnC,CAAC;wBACH,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,+BAA+B,CAAC,CAAC;4BAC5D,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC/B,CAAC;gCAAS,CAAC;4BACT,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;wBAC/B,CAAC;wBACD,MAAM;gBACV,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;YACvD,CAAC;QACH,CAAC,EAAE,UAAU,CAAC,CAAC;IACjB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC5B,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,14 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"approval-strategy.js","sourceRoot":"","sources":["../../src/backend/approval-strategy.ts"],"names":[],"mappings":""}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { ApprovalStrategy } from "./approval-strategy.js";
|
|
2
|
-
import type { MessageBus } from "../channel/message-bus.js";
|
|
3
|
-
import type { IpcServer } from "../channel/ipc-bridge.js";
|
|
4
|
-
export interface HookBasedApprovalOptions {
|
|
5
|
-
messageBus: MessageBus;
|
|
6
|
-
port: number;
|
|
7
|
-
ipcServer?: IpcServer | null;
|
|
8
|
-
topicMode?: boolean;
|
|
9
|
-
instanceName?: string;
|
|
10
|
-
}
|
|
11
|
-
export declare class HookBasedApproval implements ApprovalStrategy {
|
|
12
|
-
private opts;
|
|
13
|
-
private server;
|
|
14
|
-
constructor(opts: HookBasedApprovalOptions);
|
|
15
|
-
setup(port: number): {
|
|
16
|
-
hooks: Record<string, unknown>;
|
|
17
|
-
};
|
|
18
|
-
start(): Promise<number>;
|
|
19
|
-
stop(): Promise<void>;
|
|
20
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ApprovalServer } from "../approval/approval-server.js";
|
|
2
|
-
export class HookBasedApproval {
|
|
3
|
-
opts;
|
|
4
|
-
server;
|
|
5
|
-
constructor(opts) {
|
|
6
|
-
this.opts = opts;
|
|
7
|
-
this.server = new ApprovalServer({
|
|
8
|
-
messageBus: opts.messageBus,
|
|
9
|
-
port: opts.port,
|
|
10
|
-
ipcServer: opts.ipcServer,
|
|
11
|
-
topicMode: opts.topicMode,
|
|
12
|
-
instanceName: opts.instanceName,
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
setup(port) {
|
|
16
|
-
const token = this.server.getToken();
|
|
17
|
-
return {
|
|
18
|
-
hooks: {
|
|
19
|
-
PreToolUse: [
|
|
20
|
-
{
|
|
21
|
-
matcher: "Bash",
|
|
22
|
-
hooks: [
|
|
23
|
-
{
|
|
24
|
-
type: "command",
|
|
25
|
-
command: `curl -s -X POST http://127.0.0.1:${port}/approve -H 'Content-Type: application/json' -H 'Authorization: Bearer ${token}' -d @- --max-time 130 --connect-timeout 1 || echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"approval server unreachable"}}'`,
|
|
26
|
-
timeout: 135000,
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
async start() {
|
|
35
|
-
return this.server.start();
|
|
36
|
-
}
|
|
37
|
-
async stop() {
|
|
38
|
-
return this.server.stop();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=hook-based-approval.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hook-based-approval.js","sourceRoot":"","sources":["../../src/backend/hook-based-approval.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAYhE,MAAM,OAAO,iBAAiB;IAGR;IAFZ,MAAM,CAAiB;IAE/B,YAAoB,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,cAAc,CAAC;YAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,YAAY,EAAE,IAAI,CAAC,YAAY;SAChC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAY;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,OAAO;YACL,KAAK,EAAE;gBACL,UAAU,EAAE;oBACV;wBACE,OAAO,EAAE,MAAM;wBACf,KAAK,EAAE;4BACL;gCACE,IAAI,EAAE,SAAS;gCACf,OAAO,EAAE,oCAAoC,IAAI,0EAA0E,KAAK,iMAAiM;gCACjU,OAAO,EAAE,MAAM;6BAChB;yBACF;qBACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;CACF"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type PendingPackages } from "./install-recorder.js";
|
|
2
|
-
/**
|
|
3
|
-
* Generate Dockerfile RUN lines from pending packages.
|
|
4
|
-
*/
|
|
5
|
-
export declare function generateDockerfilePatch(pending: PendingPackages): string;
|
|
6
|
-
export interface ContainerOptions {
|
|
7
|
-
projectRoots: string[];
|
|
8
|
-
dataDir: string;
|
|
9
|
-
ccdInstallDir: string;
|
|
10
|
-
extraMounts: string[];
|
|
11
|
-
memory?: string;
|
|
12
|
-
cpus?: string;
|
|
13
|
-
network?: string;
|
|
14
|
-
}
|
|
15
|
-
export declare class ContainerManager {
|
|
16
|
-
isRunning(): Promise<boolean>;
|
|
17
|
-
ensureRunning(opts: ContainerOptions): Promise<void>;
|
|
18
|
-
destroy(): Promise<void>;
|
|
19
|
-
shouldAutoBake(recordPath: string): boolean;
|
|
20
|
-
autoBake(recordPath: string, dockerfilePath: string): Promise<{
|
|
21
|
-
success: boolean;
|
|
22
|
-
packages: PendingPackages;
|
|
23
|
-
}>;
|
|
24
|
-
}
|