cliclaw 1.0.22 → 1.0.24
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/bin/cli.js +8 -9
- package/package.json +1 -1
- package/src/agents/codex.ts +8 -14
- package/src/config.ts +6 -0
- package/src/handlers/messages.ts +21 -22
package/bin/cli.js
CHANGED
|
@@ -189,19 +189,18 @@ async function runConfigWizard() {
|
|
|
189
189
|
console.log(`${c.gray} Leave empty to configure later.\n${c.reset}`)
|
|
190
190
|
const forumId = await prompt('FORUM_GROUP_ID (Enter to skip)', existing.FORUM_GROUP_ID || '')
|
|
191
191
|
|
|
192
|
-
console.log(`\n${c.bold}
|
|
193
|
-
console.log(` ${c.bold}1)
|
|
194
|
-
console.log(` ${c.bold}2)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
ok(`Permission mode: ${permMode}`)
|
|
192
|
+
console.log(`\n${c.bold}Codex — aprovação de comandos${c.reset}`)
|
|
193
|
+
console.log(` ${c.bold}1) ask${c.reset} — pergunta antes de cada comando ${c.cyan}(recomendado)${c.reset}`)
|
|
194
|
+
console.log(` ${c.bold}2) allow${c.reset} — executa tudo automaticamente\n`)
|
|
195
|
+
const approvalChoice = await prompt('Escolha [1/2]',
|
|
196
|
+
existing.CODEX_APPROVAL === 'allow' ? '2' : '1')
|
|
197
|
+
const codexApproval = approvalChoice === '2' ? 'allow' : 'ask'
|
|
198
|
+
ok(`Codex approval: ${codexApproval}`)
|
|
200
199
|
|
|
201
200
|
const dataDir = existing.DATA_DIR || path.join(USER_DIR, 'data')
|
|
202
201
|
let envContent = `TELEGRAM_BOT_TOKEN=${token}\n`
|
|
203
202
|
if (forumId) envContent += `FORUM_GROUP_ID=${forumId}\n`
|
|
204
|
-
envContent += `
|
|
203
|
+
envContent += `CODEX_APPROVAL=${codexApproval}\n`
|
|
205
204
|
envContent += `DATA_DIR=${dataDir}\n`
|
|
206
205
|
fs.writeFileSync(envFile, envContent, 'utf8')
|
|
207
206
|
ok(`.env saved → ${envFile}`)
|
package/package.json
CHANGED
package/src/agents/codex.ts
CHANGED
|
@@ -14,8 +14,8 @@ const BASE_ENV = {
|
|
|
14
14
|
LANG: 'en_US.UTF-8',
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const SESSION_TTL_MS = 30 * 60 * 1000
|
|
18
|
-
const RESPONSE_TIMEOUT_MS =
|
|
17
|
+
const SESSION_TTL_MS = 30 * 60 * 1000 // kill idle processes after 30 min
|
|
18
|
+
const RESPONSE_TIMEOUT_MS = 10 * 60_000 // 10 min — allows time for user approval clicks
|
|
19
19
|
|
|
20
20
|
interface PendingReq {
|
|
21
21
|
resolve: (r: { text: string; usage?: TokenUsage }) => void
|
|
@@ -199,11 +199,14 @@ function getOrStart(appSessionId: string): ProtoSession {
|
|
|
199
199
|
|
|
200
200
|
// ─── public API ──────────────────────────────────────────────────────────────
|
|
201
201
|
export async function askCodex(
|
|
202
|
-
session:
|
|
203
|
-
userMessage:
|
|
204
|
-
_onNewThreadId?: (id: string) => void
|
|
202
|
+
session: { id: string; codexThreadId?: string },
|
|
203
|
+
userMessage: string,
|
|
204
|
+
_onNewThreadId?: (id: string) => void,
|
|
205
|
+
approvalHandler?: (callId: string, commandStr: string) => Promise<boolean>
|
|
205
206
|
): Promise<{ text: string; usage?: TokenUsage }> {
|
|
206
207
|
const ps = getOrStart(session.id)
|
|
208
|
+
// Update handler every call (chat context may have changed)
|
|
209
|
+
if (approvalHandler !== undefined) ps.approvalHandler = approvalHandler
|
|
207
210
|
const msgId = randomUUID()
|
|
208
211
|
|
|
209
212
|
return new Promise((resolve, reject) => {
|
|
@@ -237,15 +240,6 @@ export async function askCodex(
|
|
|
237
240
|
)
|
|
238
241
|
}
|
|
239
242
|
|
|
240
|
-
/** Attach a per-session handler that is called whenever codex wants to run a command. */
|
|
241
|
-
export function setCodexApprovalHandler(
|
|
242
|
-
appSessionId: string,
|
|
243
|
-
handler: (callId: string, commandStr: string) => Promise<boolean>
|
|
244
|
-
): void {
|
|
245
|
-
const ps = protoSessions.get(appSessionId)
|
|
246
|
-
if (ps) ps.approvalHandler = handler
|
|
247
|
-
}
|
|
248
|
-
|
|
249
243
|
export function killCodexSession(appSessionId: string) {
|
|
250
244
|
const ps = protoSessions.get(appSessionId)
|
|
251
245
|
if (ps) {
|
package/src/config.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { homedir } from 'os'
|
|
|
5
5
|
|
|
6
6
|
export type AgentName = 'claude' | 'codex'
|
|
7
7
|
export type PermissionMode = 'auto' | 'session' | 'ask'
|
|
8
|
+
export type CodexApproval = 'ask' | 'allow'
|
|
8
9
|
|
|
9
10
|
export interface Config {
|
|
10
11
|
TELEGRAM_BOT_TOKEN: string
|
|
@@ -12,6 +13,7 @@ export interface Config {
|
|
|
12
13
|
FORUM_GROUP_ID: string
|
|
13
14
|
TELEGRAM_ADMIN_IDS: string[]
|
|
14
15
|
PERMISSION_MODE: PermissionMode
|
|
16
|
+
CODEX_APPROVAL: CodexApproval
|
|
15
17
|
availableAgents: AgentName[]
|
|
16
18
|
}
|
|
17
19
|
|
|
@@ -59,6 +61,9 @@ export function loadConfig(): Config {
|
|
|
59
61
|
rawMode === 'session' ? 'session' :
|
|
60
62
|
rawMode === 'ask' ? 'ask' : 'auto'
|
|
61
63
|
|
|
64
|
+
const rawApproval = (process.env.CODEX_APPROVAL || 'ask').toLowerCase()
|
|
65
|
+
const codexApproval: CodexApproval = rawApproval === 'allow' ? 'allow' : 'ask'
|
|
66
|
+
|
|
62
67
|
const config: Config = {
|
|
63
68
|
TELEGRAM_BOT_TOKEN: process.env.TELEGRAM_BOT_TOKEN || '',
|
|
64
69
|
DATA_DIR: process.env.DATA_DIR || join(USER_DIR, 'data'),
|
|
@@ -66,6 +71,7 @@ export function loadConfig(): Config {
|
|
|
66
71
|
TELEGRAM_ADMIN_IDS: (process.env.TELEGRAM_ADMIN_IDS || '')
|
|
67
72
|
.split(',').map(id => id.trim()).filter(Boolean),
|
|
68
73
|
PERMISSION_MODE: permMode,
|
|
74
|
+
CODEX_APPROVAL: codexApproval,
|
|
69
75
|
availableAgents: checkAgents(),
|
|
70
76
|
}
|
|
71
77
|
|
package/src/handlers/messages.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Bot, Context, Api } from 'grammy'
|
|
|
3
3
|
import type { Storage, Session } from '../storage'
|
|
4
4
|
import type { Config } from '../config'
|
|
5
5
|
import { askClaude, type TokenUsage } from '../agents/claude'
|
|
6
|
-
import { askCodex
|
|
6
|
+
import { askCodex } from '../agents/codex'
|
|
7
7
|
import { mdToTg, splitHtml } from '../utils/markdown'
|
|
8
8
|
import { getLang, t } from '../i18n'
|
|
9
9
|
import { registerApproval, respondApproval } from './approvals'
|
|
@@ -102,26 +102,24 @@ export function registerMessageHandler(bot: Bot<Context>, storage: Storage, conf
|
|
|
102
102
|
|
|
103
103
|
storage.addMessage(chatId, session.id, 'user', text)
|
|
104
104
|
|
|
105
|
-
// ──
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
})
|
|
124
|
-
}
|
|
105
|
+
// ── build codex approval handler (only if CODEX_APPROVAL=ask) ──────────
|
|
106
|
+
const codexApprovalHandler = (session.model === 'codex' && config.CODEX_APPROVAL === 'ask')
|
|
107
|
+
? (callId: string, cmdStr: string) => {
|
|
108
|
+
const approvalId = randomUUID()
|
|
109
|
+
ctx.api.sendMessage(chatId,
|
|
110
|
+
`🔧 <b>Codex quer executar:</b>\n<code>${escapeHtml(cmdStr)}</code>`,
|
|
111
|
+
{
|
|
112
|
+
...replyOpts,
|
|
113
|
+
parse_mode: 'HTML',
|
|
114
|
+
reply_markup: { inline_keyboard: [[
|
|
115
|
+
{ text: '✅ Aprovar', callback_data: `capprove:${approvalId}` },
|
|
116
|
+
{ text: '❌ Negar', callback_data: `cdeny:${approvalId}` },
|
|
117
|
+
]] },
|
|
118
|
+
}
|
|
119
|
+
).catch(() => {})
|
|
120
|
+
return new Promise<boolean>((resolve) => registerApproval(approvalId, resolve))
|
|
121
|
+
}
|
|
122
|
+
: undefined
|
|
125
123
|
|
|
126
124
|
let response: string
|
|
127
125
|
try {
|
|
@@ -131,7 +129,8 @@ export function registerMessageHandler(bot: Bot<Context>, storage: Storage, conf
|
|
|
131
129
|
(id) => storage.setClaudeSessionId(chatId, session!.id, id))
|
|
132
130
|
} else {
|
|
133
131
|
result = await askCodex(session, text,
|
|
134
|
-
(id) => storage.setCodexThreadId(chatId, session!.id, id)
|
|
132
|
+
(id) => storage.setCodexThreadId(chatId, session!.id, id),
|
|
133
|
+
codexApprovalHandler)
|
|
135
134
|
}
|
|
136
135
|
response = (isFirstMessage && result.usage) ? result.text + formatUsage(result.usage) : result.text
|
|
137
136
|
} catch (err: any) {
|