@0xmaxma/claude-gateway 1.1.9 → 1.1.10

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.
@@ -35,6 +35,7 @@ import { hasMarkdown, toTelegramHtml } from './pure'
35
35
  const STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join(homedir(), '.claude', 'channels', 'telegram')
36
36
  const ACCESS_FILE = join(STATE_DIR, 'access.json')
37
37
  const APPROVED_DIR = join(STATE_DIR, 'approved')
38
+ const AWAITING_OWNER_FILE = join(STATE_DIR, 'awaiting-owner')
38
39
  const ENV_FILE = join(STATE_DIR, '.env')
39
40
 
40
41
  // Load .env fallback when token not injected via env block (standalone mode).
@@ -114,7 +115,7 @@ type GroupPolicy = {
114
115
  }
115
116
 
116
117
  type Access = {
117
- dmPolicy: 'pairing' | 'allowlist' | 'disabled'
118
+ dmPolicy: 'open' | 'pairing' | 'allowlist' | 'disabled'
118
119
  allowFrom: string[]
119
120
  groups: Record<string, GroupPolicy>
120
121
  pending: Record<string, PendingEntry>
@@ -232,7 +233,40 @@ function gate(ctx: Context): GateResult {
232
233
  const senderId = String(from.id)
233
234
  const chatType = ctx.chat?.type
234
235
 
236
+ // Owner init-pairing sentinel: first private message auto-approves sender as owner.
235
237
  if (chatType === 'private') {
238
+ try {
239
+ const stat = statSync(AWAITING_OWNER_FILE)
240
+ const age = Date.now() - stat.mtimeMs
241
+ if (age < 10 * 60 * 1000) {
242
+ // Sentinel is valid — approve this sender as owner
243
+ if (!access.allowFrom.includes(senderId)) access.allowFrom.push(senderId)
244
+ saveAccess(access)
245
+ rmSync(AWAITING_OWNER_FILE, { force: true })
246
+ // Write approved file so receiver sends confirmation message
247
+ mkdirSync(APPROVED_DIR, { recursive: true })
248
+ writeFileSync(join(APPROVED_DIR, senderId), String(ctx.chat!.id))
249
+ return { action: 'deliver', access }
250
+ } else {
251
+ rmSync(AWAITING_OWNER_FILE, { force: true })
252
+ }
253
+ } catch (err) {
254
+ if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
255
+ // Unexpected I/O error — deny to be safe rather than silently allowing
256
+ return { action: 'drop' }
257
+ }
258
+ // ENOENT — no sentinel, continue normal gate logic
259
+ }
260
+ }
261
+
262
+ if (chatType === 'private') {
263
+ if (access.dmPolicy === 'open') {
264
+ if (!access.allowFrom.includes(senderId)) {
265
+ access.allowFrom.push(senderId)
266
+ saveAccess(access)
267
+ }
268
+ return { action: 'deliver', access }
269
+ }
236
270
  if (access.allowFrom.includes(senderId)) return { action: 'deliver', access }
237
271
  if (access.dmPolicy === 'allowlist') return { action: 'drop' }
238
272
 
@@ -1592,7 +1626,7 @@ if (RECEIVER_MODE) {
1592
1626
  }
1593
1627
  if (err instanceof Error && err.message === 'Aborted delay') return
1594
1628
  process.stderr.write(`telegram channel (receiver): polling failed: ${err}\n`)
1595
- return
1629
+ process.exit(1)
1596
1630
  }
1597
1631
  }
1598
1632
  })()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xmaxma/claude-gateway",
3
- "version": "1.1.9",
3
+ "version": "1.1.10",
4
4
  "description": "Multi-agent gateway for Claude",
5
5
  "repository": {
6
6
  "type": "git",