delimit-cli 3.14.42 → 3.14.44
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/gateway/ai/notify.py +5 -6
- package/gateway/ai/server.py +3 -3
- package/package.json +5 -1
- package/gateway/ai/founding_users.py +0 -162
- package/gateway/ai/inbox_daemon.py +0 -684
- package/gateway/ai/social.py +0 -666
- package/gateway/ai/social_target.py +0 -1635
package/gateway/ai/notify.py
CHANGED
|
@@ -37,7 +37,7 @@ INBOX_ROUTING_FILE = Path.home() / ".delimit" / "inbox_routing.jsonl"
|
|
|
37
37
|
IMAP_HOST = "mail.spacemail.com"
|
|
38
38
|
IMAP_PORT = 993
|
|
39
39
|
IMAP_USER = "pro@delimit.ai"
|
|
40
|
-
FORWARD_TO =
|
|
40
|
+
FORWARD_TO = os.environ.get("DELIMIT_FORWARD_TO", "")
|
|
41
41
|
|
|
42
42
|
# Domains/senders whose emails require owner action
|
|
43
43
|
OWNER_ACTION_DOMAINS = {
|
|
@@ -61,7 +61,7 @@ OWNER_ACTION_DOMAINS = {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
OWNER_ACTION_SENDERS = {
|
|
64
|
-
|
|
64
|
+
os.environ.get("DELIMIT_FORWARD_TO", ""),
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
# Subject patterns that indicate owner-action (compiled once)
|
|
@@ -222,13 +222,12 @@ def send_email(
|
|
|
222
222
|
"""Send an email notification via SMTP.
|
|
223
223
|
|
|
224
224
|
Args:
|
|
225
|
-
to: Recipient email address. Falls back to DELIMIT_SMTP_TO
|
|
226
|
-
jamsonsholdings@gmail.com.
|
|
225
|
+
to: Recipient email address. Falls back to DELIMIT_SMTP_TO env var.
|
|
227
226
|
subject: Email subject line.
|
|
228
227
|
body: Email body text (preferred). Falls back to 'message' for
|
|
229
228
|
backward compatibility.
|
|
230
229
|
from_account: Sender account key in ~/.delimit/secrets/smtp-all.json
|
|
231
|
-
(e.g. 'pro@delimit.ai', '
|
|
230
|
+
(e.g. 'pro@delimit.ai', '<configured-email>'). If provided, SMTP
|
|
232
231
|
credentials are loaded from that file instead of env vars.
|
|
233
232
|
message: Email body text (legacy parameter, use 'body' instead).
|
|
234
233
|
event_type: Event category for filtering/logging.
|
|
@@ -258,7 +257,7 @@ def send_email(
|
|
|
258
257
|
smtp_pass = os.environ.get("DELIMIT_SMTP_PASS", "")
|
|
259
258
|
smtp_from = os.environ.get("DELIMIT_SMTP_FROM", "")
|
|
260
259
|
|
|
261
|
-
smtp_to = to or os.environ.get("DELIMIT_SMTP_TO", "
|
|
260
|
+
smtp_to = to or os.environ.get("DELIMIT_SMTP_TO", "")
|
|
262
261
|
|
|
263
262
|
if not all([smtp_host, smtp_from, smtp_to]):
|
|
264
263
|
record = {
|
package/gateway/ai/server.py
CHANGED
|
@@ -5886,9 +5886,9 @@ def delimit_notify(channel: str = "webhook", message: str = "",
|
|
|
5886
5886
|
subject: Subject line (email only). Use [ACTION], [INFO], [ALERT] prefix.
|
|
5887
5887
|
event_type: Event category for filtering.
|
|
5888
5888
|
to: Recipient email address (email only). Overrides default DELIMIT_SMTP_TO.
|
|
5889
|
-
Send to any address — leave empty for default (
|
|
5889
|
+
Send to any address — leave empty for default (uses DELIMIT_SMTP_TO env var).
|
|
5890
5890
|
from_account: Sender account key from ~/.delimit/secrets/smtp-all.json
|
|
5891
|
-
(e.g. 'pro@delimit.ai', '
|
|
5891
|
+
(e.g. 'pro@delimit.ai', '<configured-email>'). Email only.
|
|
5892
5892
|
"""
|
|
5893
5893
|
from ai.notify import send_notification
|
|
5894
5894
|
return _with_next_steps("notify", _safe_call(
|
|
@@ -5994,7 +5994,7 @@ def delimit_notify_inbox(action: str = "status", limit: int = 10,
|
|
|
5994
5994
|
"""Check inbound email inbox, classify, and route (Pro).
|
|
5995
5995
|
|
|
5996
5996
|
Polls pro@delimit.ai via IMAP. Classifies emails as owner-action
|
|
5997
|
-
(forwards to
|
|
5997
|
+
(forwards to configured email) or non-owner (stays in inbox).
|
|
5998
5998
|
|
|
5999
5999
|
Args:
|
|
6000
6000
|
action: 'status' (show inbox state), 'poll' (classify and optionally forward),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "delimit-cli",
|
|
3
3
|
"mcpName": "io.github.delimit-ai/delimit-mcp-server",
|
|
4
|
-
"version": "3.14.
|
|
4
|
+
"version": "3.14.44",
|
|
5
5
|
"description": "Unify Claude Code, Codex, Cursor, and Gemini CLI with persistent context, governance, and multi-model debate.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
"lib/",
|
|
10
10
|
"adapters/",
|
|
11
11
|
"gateway/",
|
|
12
|
+
"!gateway/ai/social_target.py",
|
|
13
|
+
"!gateway/ai/social.py",
|
|
14
|
+
"!gateway/ai/founding_users.py",
|
|
15
|
+
"!gateway/ai/inbox_daemon.py",
|
|
12
16
|
"scripts/",
|
|
13
17
|
"server.json",
|
|
14
18
|
"README.md",
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
"""Founding User tracker — manages the 25 founding user slots.
|
|
2
|
-
|
|
3
|
-
Monitors Supabase for new signups, sends welcome emails,
|
|
4
|
-
tracks slots remaining, and manages the 12-month term.
|
|
5
|
-
"""
|
|
6
|
-
import json
|
|
7
|
-
import smtplib
|
|
8
|
-
import imaplib
|
|
9
|
-
from email.mime.text import MIMEText
|
|
10
|
-
from email.mime.multipart import MIMEMultipart
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from datetime import datetime, timezone
|
|
13
|
-
|
|
14
|
-
SECRETS_DIR = Path.home() / ".delimit" / "secrets"
|
|
15
|
-
FOUNDING_USERS_FILE = Path.home() / ".delimit" / "founding_users.json"
|
|
16
|
-
MAX_FOUNDING_USERS = 25
|
|
17
|
-
SMTP_HOST = "mail.spacemail.com"
|
|
18
|
-
SMTP_PORT = 465
|
|
19
|
-
IMAP_HOST = "mail.spacemail.com"
|
|
20
|
-
EMAIL = "pro@delimit.ai"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def _load_creds():
|
|
24
|
-
"""Load email credentials."""
|
|
25
|
-
return {"email": EMAIL, "password": "Bladabah3!"}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def _load_founding_users() -> dict:
|
|
29
|
-
"""Load founding users registry."""
|
|
30
|
-
if FOUNDING_USERS_FILE.exists():
|
|
31
|
-
return json.loads(FOUNDING_USERS_FILE.read_text())
|
|
32
|
-
return {"users": [], "created_at": datetime.now(timezone.utc).isoformat()}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _save_founding_users(data: dict):
|
|
36
|
-
"""Save founding users registry."""
|
|
37
|
-
FOUNDING_USERS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
38
|
-
FOUNDING_USERS_FILE.write_text(json.dumps(data, indent=2))
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def get_status() -> dict:
|
|
42
|
-
"""Get founding user program status."""
|
|
43
|
-
data = _load_founding_users()
|
|
44
|
-
users = data.get("users", [])
|
|
45
|
-
return {
|
|
46
|
-
"total_slots": MAX_FOUNDING_USERS,
|
|
47
|
-
"claimed": len(users),
|
|
48
|
-
"remaining": MAX_FOUNDING_USERS - len(users),
|
|
49
|
-
"users": [{"email": u["email"], "name": u.get("name", ""), "joined": u["joined_at"]} for u in users],
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def register_founding_user(email: str, name: str = "", github_username: str = "") -> dict:
|
|
54
|
-
"""Register a new founding user."""
|
|
55
|
-
data = _load_founding_users()
|
|
56
|
-
users = data.get("users", [])
|
|
57
|
-
|
|
58
|
-
if len(users) >= MAX_FOUNDING_USERS:
|
|
59
|
-
return {"error": "All 25 founding user spots are claimed.", "remaining": 0}
|
|
60
|
-
|
|
61
|
-
if any(u["email"] == email for u in users):
|
|
62
|
-
return {"error": "Already registered as a founding user.", "email": email}
|
|
63
|
-
|
|
64
|
-
user = {
|
|
65
|
-
"email": email,
|
|
66
|
-
"name": name,
|
|
67
|
-
"github_username": github_username,
|
|
68
|
-
"joined_at": datetime.now(timezone.utc).isoformat(),
|
|
69
|
-
"term_months": 12,
|
|
70
|
-
"status": "active",
|
|
71
|
-
}
|
|
72
|
-
users.append(user)
|
|
73
|
-
data["users"] = users
|
|
74
|
-
_save_founding_users(data)
|
|
75
|
-
|
|
76
|
-
# Send welcome email
|
|
77
|
-
try:
|
|
78
|
-
_send_welcome_email(email, name)
|
|
79
|
-
except Exception:
|
|
80
|
-
pass # Don't fail registration if email fails
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
"registered": True,
|
|
84
|
-
"email": email,
|
|
85
|
-
"slot": len(users),
|
|
86
|
-
"remaining": MAX_FOUNDING_USERS - len(users),
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def _send_welcome_email(to_email: str, name: str = ""):
|
|
91
|
-
"""Send welcome email to new founding user."""
|
|
92
|
-
creds = _load_creds()
|
|
93
|
-
greeting = f"Hi {name}," if name else "Hi,"
|
|
94
|
-
|
|
95
|
-
html = f"""
|
|
96
|
-
<div style="font-family: -apple-system, sans-serif; max-width: 600px; margin: 0 auto; background: #0a0a1a; color: #e5e7eb; padding: 40px; border-radius: 12px;">
|
|
97
|
-
<div style="text-align: center; margin-bottom: 32px;">
|
|
98
|
-
<span style="font-size: 32px; font-weight: 800; background: linear-gradient(135deg, #3b82f6, #8b5cf6); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
|
|
99
|
-
</> Delimit
|
|
100
|
-
</span>
|
|
101
|
-
</div>
|
|
102
|
-
|
|
103
|
-
<h1 style="color: #fff; font-size: 24px; margin-bottom: 16px;">Welcome, Founding User</h1>
|
|
104
|
-
|
|
105
|
-
<p>{greeting}</p>
|
|
106
|
-
|
|
107
|
-
<p>You're one of 25 founding users getting full access to Delimit for 12 months. That includes:</p>
|
|
108
|
-
|
|
109
|
-
<ul style="line-height: 2;">
|
|
110
|
-
<li>Full enterprise dashboard (app.delimit.ai)</li>
|
|
111
|
-
<li>106 MCP tools across Claude Code, Codex, Cursor, Gemini CLI</li>
|
|
112
|
-
<li>Multi-model deliberation</li>
|
|
113
|
-
<li>Team management, audit trail, policy editor</li>
|
|
114
|
-
<li>Priority feedback channel</li>
|
|
115
|
-
<li>Permanent Founding User badge</li>
|
|
116
|
-
</ul>
|
|
117
|
-
|
|
118
|
-
<div style="background: #1a1a2e; border: 1px solid #374151; border-radius: 8px; padding: 16px; margin: 24px 0;">
|
|
119
|
-
<p style="margin: 0; font-family: monospace; color: #22c55e;">$ npx delimit-cli setup</p>
|
|
120
|
-
</div>
|
|
121
|
-
|
|
122
|
-
<p>Questions? Reply to this email — it goes straight to the founder.</p>
|
|
123
|
-
|
|
124
|
-
<p style="color: #9ca3af; font-size: 14px; margin-top: 32px;">
|
|
125
|
-
— The Delimit Team<br>
|
|
126
|
-
delimit.ai
|
|
127
|
-
</p>
|
|
128
|
-
</div>
|
|
129
|
-
"""
|
|
130
|
-
|
|
131
|
-
msg = MIMEMultipart("alternative")
|
|
132
|
-
msg["From"] = f"Delimit <{EMAIL}>"
|
|
133
|
-
msg["To"] = to_email
|
|
134
|
-
msg["Subject"] = "Welcome to Delimit — You're a Founding User"
|
|
135
|
-
msg.attach(MIMEText(html, "html"))
|
|
136
|
-
|
|
137
|
-
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as server:
|
|
138
|
-
server.login(creds["email"], creds["password"])
|
|
139
|
-
server.send_message(msg)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def check_inbox() -> list:
|
|
143
|
-
"""Check pro@delimit.ai inbox for new messages."""
|
|
144
|
-
creds = _load_creds()
|
|
145
|
-
try:
|
|
146
|
-
mail = imaplib.IMAP4_SSL(IMAP_HOST, 993)
|
|
147
|
-
mail.login(creds["email"], creds["password"])
|
|
148
|
-
mail.select("inbox")
|
|
149
|
-
status, messages = mail.search(None, "UNSEEN")
|
|
150
|
-
if not messages[0]:
|
|
151
|
-
mail.logout()
|
|
152
|
-
return []
|
|
153
|
-
|
|
154
|
-
results = []
|
|
155
|
-
for mid in messages[0].split():
|
|
156
|
-
status, data = mail.fetch(mid, "(BODY[HEADER.FIELDS (FROM SUBJECT DATE)])")
|
|
157
|
-
header = data[0][1].decode()
|
|
158
|
-
results.append(header.strip())
|
|
159
|
-
mail.logout()
|
|
160
|
-
return results
|
|
161
|
-
except Exception as e:
|
|
162
|
-
return [{"error": str(e)}]
|