delimit-cli 3.14.28 → 3.14.30

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 (48) hide show
  1. package/bin/delimit-setup.js +3 -6
  2. package/gateway/ai/backends/deploy_bridge.py +56 -2
  3. package/gateway/ai/backends/gateway_core.py +212 -1
  4. package/gateway/ai/backends/generate_bridge.py +84 -13
  5. package/gateway/ai/backends/governance_bridge.py +63 -16
  6. package/gateway/ai/backends/memory_bridge.py +77 -76
  7. package/gateway/ai/backends/ops_bridge.py +76 -6
  8. package/gateway/ai/backends/os_bridge.py +23 -3
  9. package/gateway/ai/backends/repo_bridge.py +156 -17
  10. package/gateway/ai/backends/tools_design.py +116 -9
  11. package/gateway/ai/backends/tools_infra.py +200 -72
  12. package/gateway/ai/backends/tools_real.py +8 -0
  13. package/gateway/ai/backends/ui_bridge.py +115 -5
  14. package/gateway/ai/backends/vault_bridge.py +69 -114
  15. package/gateway/ai/content_engine.py +1276 -0
  16. package/gateway/ai/context_fs.py +193 -0
  17. package/gateway/ai/daemon.py +500 -0
  18. package/gateway/ai/data_plane.py +291 -0
  19. package/gateway/ai/deliberation.py +1033 -6
  20. package/gateway/ai/events.py +39 -0
  21. package/gateway/ai/founding_users.py +162 -0
  22. package/gateway/ai/governance.py +698 -4
  23. package/gateway/ai/inbox_daemon.py +78 -17
  24. package/gateway/ai/integrations/__init__.py +1 -0
  25. package/gateway/ai/integrations/opensage_wrapper.py +288 -0
  26. package/gateway/ai/key_resolver.py +95 -0
  27. package/gateway/ai/ledger_manager.py +289 -1
  28. package/gateway/ai/license.py +62 -4
  29. package/gateway/ai/license_core.py +208 -7
  30. package/gateway/ai/local_server.py +215 -0
  31. package/gateway/ai/loop_engine.py +408 -0
  32. package/gateway/ai/mcp_bridge.py +178 -0
  33. package/gateway/ai/release_sync.py +2 -2
  34. package/gateway/ai/screen_record.py +374 -0
  35. package/gateway/ai/secrets_broker.py +235 -0
  36. package/gateway/ai/social.py +189 -27
  37. package/gateway/ai/social_target.py +1635 -0
  38. package/gateway/ai/supabase_sync.py +190 -0
  39. package/gateway/ai/tracing.py +195 -0
  40. package/gateway/core/contract_ledger.py +1 -1
  41. package/gateway/core/dependency_graph.py +1 -1
  42. package/gateway/core/dependency_manifest.py +1 -1
  43. package/gateway/core/diff_engine_v2.py +272 -78
  44. package/gateway/core/event_backbone.py +2 -2
  45. package/gateway/core/event_schema.py +1 -1
  46. package/gateway/core/impact_analyzer.py +1 -1
  47. package/gateway/core/policy_engine.py +4 -0
  48. package/package.json +1 -1
@@ -0,0 +1,39 @@
1
+ """Event ingestion for dashboard real-time feed."""
2
+ import json
3
+ import time
4
+ from pathlib import Path
5
+ from datetime import datetime
6
+
7
+ EVENTS_DIR = Path.home() / ".delimit" / "events"
8
+
9
+
10
+ def emit(event_type: str, tool: str, model: str = "", detail: str = "", venture: str = ""):
11
+ """Write an event to the daily events log."""
12
+ EVENTS_DIR.mkdir(parents=True, exist_ok=True)
13
+ today = datetime.utcnow().strftime("%Y-%m-%d")
14
+ event = {
15
+ "ts": datetime.utcnow().isoformat() + "Z",
16
+ "type": event_type, # tool_call, governance_check, deliberation, deploy, error
17
+ "tool": tool,
18
+ "model": model,
19
+ "detail": detail,
20
+ "venture": venture,
21
+ }
22
+ with open(EVENTS_DIR / f"events-{today}.jsonl", "a") as f:
23
+ f.write(json.dumps(event) + "\n")
24
+
25
+
26
+ def recent(limit: int = 50) -> list:
27
+ """Get the most recent events across all days."""
28
+ events = []
29
+ if not EVENTS_DIR.exists():
30
+ return events
31
+ for f in sorted(EVENTS_DIR.glob("events-*.jsonl"), reverse=True):
32
+ for line in reversed(f.read_text().splitlines()):
33
+ try:
34
+ events.append(json.loads(line))
35
+ except Exception:
36
+ pass
37
+ if len(events) >= limit:
38
+ return events
39
+ return events
@@ -0,0 +1,162 @@
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
+ &lt;/&gt; 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)}]