delimit-cli 4.5.13 → 4.6.1
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/CHANGELOG.md +48 -0
- package/README.md +9 -8
- package/bin/delimit-cli.js +179 -4
- package/bin/delimit-setup.js +46 -6
- package/gateway/ai/_compile_status.py +154 -0
- package/gateway/ai/agent_dispatch.py +41 -0
- package/gateway/ai/backends/git_health.py +175 -0
- package/gateway/ai/backends/tools_infra.py +163 -10
- package/gateway/ai/cli_contract.py +185 -0
- package/gateway/ai/daemon.py +10 -0
- package/gateway/ai/daily_digest.py +1 -2
- package/gateway/ai/delimit_daemon.py +67 -0
- package/gateway/ai/dispatch_gate.py +399 -0
- package/gateway/ai/governance.py +181 -0
- package/gateway/ai/heartbeat.py +290 -0
- package/gateway/ai/hot_reload.py +1 -2
- package/gateway/ai/led193_daemon/executor.py +9 -0
- package/gateway/ai/ledger_manager.py +90 -4
- package/gateway/ai/ledger_proof.py +127 -0
- package/gateway/ai/license.py +132 -47
- package/gateway/ai/license_core.cpython-310-x86_64-linux-gnu.so +0 -0
- package/gateway/ai/license_core.pyi +1 -1
- package/gateway/ai/notify.py +39 -0
- package/gateway/ai/outreach_loop_daemon.py +349 -0
- package/gateway/ai/outreach_substantive.py +1437 -0
- package/gateway/ai/pro_tools.yaml +167 -0
- package/gateway/ai/reaper.py +70 -0
- package/gateway/ai/reddit_scanner.py +17 -6
- package/gateway/ai/sensing/schema.py +1 -1
- package/gateway/ai/sensing/signal_store.py +0 -1
- package/gateway/ai/server.py +5490 -1602
- package/gateway/ai/social_capability/fit_floor.py +114 -12
- package/gateway/ai/social_queue.py +166 -10
- package/gateway/ai/tdqs_lint.py +611 -0
- package/gateway/ai/tenant_auth.py +329 -0
- package/gateway/ai/tenant_data.py +339 -0
- package/gateway/ai/tenant_paths.py +150 -0
- package/gateway/ai/usage_allowlist.py +198 -0
- package/gateway/ai/workers/base.py +2 -2
- package/gateway/ai/workers/executor.py +32 -3
- package/gateway/ai/workers/outreach_drafter.py +0 -1
- package/gateway/ai/workers/pr_drafter.py +0 -1
- package/gateway/ai/x_ranker.py +12 -2
- package/gateway/core/json_schema_diff.py +25 -1
- package/lib/auth-signin.js +136 -0
- package/lib/auth-signout.js +169 -0
- package/lib/delimit-template.js +11 -0
- package/lib/migration-2092-banner.js +213 -0
- package/package.json +5 -2
- package/server.json +4 -4
- package/scripts/build-license-core.sh +0 -85
- package/scripts/security-check.sh +0 -66
- package/scripts/test-license-core-so.sh +0 -107
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# PRO_TOOLS single source of truth — LED-1410.
|
|
2
|
+
#
|
|
3
|
+
# This file is the canonical list of every Delimit MCP tool that
|
|
4
|
+
# requires a Pro license. Codegen propagates it into:
|
|
5
|
+
#
|
|
6
|
+
# - ai/license_core.py : PRO_TOOLS + FREE_TRIAL_LIMITS (gets
|
|
7
|
+
# compiled to .so for paying customers)
|
|
8
|
+
# - ai/license.py : Python fallback PRO_TOOLS for customers
|
|
9
|
+
# whose platform has no .so, AND the
|
|
10
|
+
# extension frozenset that fills in tools
|
|
11
|
+
# added after the last compiled build
|
|
12
|
+
# - ai/rate_limiter.py : PRO_TOOLS (filtered to non-deliberation
|
|
13
|
+
# tools, since DELIBERATION_TOOLS has its
|
|
14
|
+
# own tier in rate_limiter)
|
|
15
|
+
#
|
|
16
|
+
# To add or remove a Pro tool:
|
|
17
|
+
# 1. Edit this file
|
|
18
|
+
# 2. Run: python3 scripts/gen_pro_tools.py
|
|
19
|
+
# 3. Commit the regenerated .py files alongside the YAML change
|
|
20
|
+
#
|
|
21
|
+
# CI runs scripts/check_pro_tools_drift.py on every push and fails if
|
|
22
|
+
# any of the three generated files diverge from this manifest.
|
|
23
|
+
#
|
|
24
|
+
# DO NOT add an "extension set" in license.py by hand — that was the
|
|
25
|
+
# class of bug that LED-1260 caught (compiled set diverged from
|
|
26
|
+
# fallback set; customers with the binary got tools free while
|
|
27
|
+
# customers without paid). One YAML, three regenerated callers.
|
|
28
|
+
|
|
29
|
+
version: 1
|
|
30
|
+
|
|
31
|
+
# Tools tagged `kind: deliberation` go into the DELIBERATION_TOOLS
|
|
32
|
+
# frozenset in rate_limiter.py (separate rate-limit tier). They are
|
|
33
|
+
# ALSO Pro, but they're not in rate_limiter's PRO_TOOLS frozenset
|
|
34
|
+
# (that one is "pro non-deliberation").
|
|
35
|
+
#
|
|
36
|
+
# `in_compiled` controls whether the tool appears in license_core.py's
|
|
37
|
+
# baked-in PRO_TOOLS set (which gets compiled into the .so customers
|
|
38
|
+
# receive). License.py's fallback + extension sets always include
|
|
39
|
+
# every tool here regardless of in_compiled, so the gate is consistent
|
|
40
|
+
# for non-binary customers. The split exists because:
|
|
41
|
+
# - true → tool is gated by gate_tool() (the function that ships
|
|
42
|
+
# in the .so). Binary customers see this tool as Pro.
|
|
43
|
+
# - false → tool is in the fallback set but NOT in the compiled set.
|
|
44
|
+
# Binary customers' gate_tool() returns None (not gated).
|
|
45
|
+
# Non-binary customers see the tool as Pro via the fallback.
|
|
46
|
+
# The `false` entries are a historical leak — LED-1260 surfaced this
|
|
47
|
+
# class of bug and added the affected tools to the extension/fallback
|
|
48
|
+
# but did NOT close the gate-side gap. The codegen here preserves the
|
|
49
|
+
# current behavior verbatim; closing the gap requires founder
|
|
50
|
+
# ratification per CLAUDE.md "What Constitutes a Breaking Change for
|
|
51
|
+
# Users" (changes default behavior for paying customers). Track at
|
|
52
|
+
# LED-1454 (PR-B follow-up).
|
|
53
|
+
#
|
|
54
|
+
# `free_trial_limit` lets a tool be called N times before requiring a
|
|
55
|
+
# license (used by license_core's FREE_TRIAL_LIMITS dict). Only set
|
|
56
|
+
# this on tools where a free trial makes operational sense; most Pro
|
|
57
|
+
# tools should NOT be partially-free.
|
|
58
|
+
|
|
59
|
+
tools:
|
|
60
|
+
# ── Deliberation (separate rate tier) ────────────────────────────
|
|
61
|
+
- {name: delimit_deliberate, kind: deliberation, free_trial_limit: 3}
|
|
62
|
+
# LED-1260 leaky-gap (in_compiled: false) — landed AFTER the
|
|
63
|
+
# compiled set was last built. LED-1454 ratifies the closure.
|
|
64
|
+
- {name: delimit_security_deliberate, kind: deliberation, in_compiled: false}
|
|
65
|
+
|
|
66
|
+
# ── Governance (deep) ────────────────────────────────────────────
|
|
67
|
+
- {name: delimit_gov_evaluate, kind: pro, category: governance}
|
|
68
|
+
- {name: delimit_gov_policy, kind: pro, category: governance}
|
|
69
|
+
- {name: delimit_gov_run, kind: pro, category: governance}
|
|
70
|
+
- {name: delimit_gov_verify, kind: pro, category: governance}
|
|
71
|
+
# LED-1260 caught this missing from compiled; in_compiled stays false
|
|
72
|
+
# until LED-1454 closes the leaky-gate gap with founder ratification.
|
|
73
|
+
- {name: delimit_gov_new_task, kind: pro, category: governance, in_compiled: false}
|
|
74
|
+
|
|
75
|
+
# ── OS layer ─────────────────────────────────────────────────────
|
|
76
|
+
- {name: delimit_os_plan, kind: pro, category: os}
|
|
77
|
+
- {name: delimit_os_status, kind: pro, category: os}
|
|
78
|
+
- {name: delimit_os_gates, kind: pro, category: os}
|
|
79
|
+
|
|
80
|
+
# ── Deploy pipeline ──────────────────────────────────────────────
|
|
81
|
+
- {name: delimit_deploy_plan, kind: pro, category: deploy}
|
|
82
|
+
- {name: delimit_deploy_build, kind: pro, category: deploy}
|
|
83
|
+
- {name: delimit_deploy_publish, kind: pro, category: deploy}
|
|
84
|
+
- {name: delimit_deploy_verify, kind: pro, category: deploy}
|
|
85
|
+
- {name: delimit_deploy_rollback, kind: pro, category: deploy}
|
|
86
|
+
- {name: delimit_deploy_status, kind: pro, category: deploy}
|
|
87
|
+
- {name: delimit_deploy_site, kind: pro, category: deploy}
|
|
88
|
+
- {name: delimit_deploy_npm, kind: pro, category: deploy}
|
|
89
|
+
|
|
90
|
+
# ── Memory (note: store + recent are FREE; only search is Pro) ───
|
|
91
|
+
- {name: delimit_memory_search, kind: pro, category: memory}
|
|
92
|
+
|
|
93
|
+
# ── Vault ────────────────────────────────────────────────────────
|
|
94
|
+
- {name: delimit_vault_search, kind: pro, category: vault}
|
|
95
|
+
- {name: delimit_vault_snapshot, kind: pro, category: vault}
|
|
96
|
+
- {name: delimit_vault_health, kind: pro, category: vault}
|
|
97
|
+
|
|
98
|
+
# ── Evidence ─────────────────────────────────────────────────────
|
|
99
|
+
- {name: delimit_evidence_collect, kind: pro, category: evidence}
|
|
100
|
+
- {name: delimit_evidence_verify, kind: pro, category: evidence}
|
|
101
|
+
|
|
102
|
+
# ── Models (provider configuration surface) ──────────────────────
|
|
103
|
+
- {name: delimit_models, kind: pro, category: models}
|
|
104
|
+
|
|
105
|
+
# ── Observability ────────────────────────────────────────────────
|
|
106
|
+
- {name: delimit_obs_metrics, kind: pro, category: observability}
|
|
107
|
+
- {name: delimit_obs_logs, kind: pro, category: observability}
|
|
108
|
+
- {name: delimit_obs_status, kind: pro, category: observability}
|
|
109
|
+
|
|
110
|
+
# ── Release ──────────────────────────────────────────────────────
|
|
111
|
+
- {name: delimit_release_plan, kind: pro, category: release}
|
|
112
|
+
- {name: delimit_release_status, kind: pro, category: release}
|
|
113
|
+
- {name: delimit_release_sync, kind: pro, category: release}
|
|
114
|
+
|
|
115
|
+
# ── Cost ─────────────────────────────────────────────────────────
|
|
116
|
+
- {name: delimit_cost_analyze, kind: pro, category: cost}
|
|
117
|
+
- {name: delimit_cost_optimize, kind: pro, category: cost}
|
|
118
|
+
- {name: delimit_cost_alert, kind: pro, category: cost}
|
|
119
|
+
|
|
120
|
+
# ── Social ───────────────────────────────────────────────────────
|
|
121
|
+
- {name: delimit_social_post, kind: pro, category: social}
|
|
122
|
+
- {name: delimit_social_generate, kind: pro, category: social}
|
|
123
|
+
- {name: delimit_social_history, kind: pro, category: social}
|
|
124
|
+
# LED-1260 caught this missing from compiled; in_compiled stays
|
|
125
|
+
# false until LED-1454 closes the leaky-gate gap.
|
|
126
|
+
- {name: delimit_social_approve, kind: pro, category: social, in_compiled: false}
|
|
127
|
+
|
|
128
|
+
# ── Security orchestrator ────────────────────────────────────────
|
|
129
|
+
# LED-1260 leaky-gap (in_compiled: false) — see LED-1454.
|
|
130
|
+
- {name: delimit_security_ingest, kind: pro, category: security, in_compiled: false}
|
|
131
|
+
|
|
132
|
+
# ── Repo deep ────────────────────────────────────────────────────
|
|
133
|
+
# LED-1260 leaky-gap on all four repo_* tools (in_compiled: false) —
|
|
134
|
+
# binary customers got these tools free while non-binary customers
|
|
135
|
+
# paid via the fallback set. LED-1454 ratifies the closure.
|
|
136
|
+
- {name: delimit_repo_analyze, kind: pro, category: repo, in_compiled: false}
|
|
137
|
+
- {name: delimit_repo_config_audit, kind: pro, category: repo, in_compiled: false}
|
|
138
|
+
- {name: delimit_repo_config_validate, kind: pro, category: repo, in_compiled: false}
|
|
139
|
+
- {name: delimit_repo_diagnose, kind: pro, category: repo, in_compiled: false}
|
|
140
|
+
|
|
141
|
+
# ── Test ─────────────────────────────────────────────────────────
|
|
142
|
+
# LED-1260 leaky-gap (in_compiled: false) — see LED-1454.
|
|
143
|
+
- {name: delimit_test_coverage, kind: pro, category: test, in_compiled: false}
|
|
144
|
+
|
|
145
|
+
# ── Screen capture (browser automation) ──────────────────────────
|
|
146
|
+
- {name: delimit_screen_record, kind: pro, category: capture}
|
|
147
|
+
- {name: delimit_screenshot, kind: pro, category: capture}
|
|
148
|
+
|
|
149
|
+
# ── Notifications ────────────────────────────────────────────────
|
|
150
|
+
- {name: delimit_notify, kind: pro, category: notify}
|
|
151
|
+
|
|
152
|
+
# ── Agent orchestration ──────────────────────────────────────────
|
|
153
|
+
- {name: delimit_agent_dispatch, kind: pro, category: agent}
|
|
154
|
+
- {name: delimit_agent_status, kind: pro, category: agent}
|
|
155
|
+
- {name: delimit_agent_complete, kind: pro, category: agent}
|
|
156
|
+
- {name: delimit_agent_handoff, kind: pro, category: agent}
|
|
157
|
+
|
|
158
|
+
# ── Autonomous build loop ────────────────────────────────────────
|
|
159
|
+
# LED-1260 leaky-gap on all four (in_compiled: false) — these landed
|
|
160
|
+
# AFTER the compiled set was last built. LED-1454 ratifies closure.
|
|
161
|
+
- {name: delimit_next_task, kind: pro, category: build_loop, in_compiled: false}
|
|
162
|
+
- {name: delimit_task_complete, kind: pro, category: build_loop, in_compiled: false}
|
|
163
|
+
- {name: delimit_loop_status, kind: pro, category: build_loop, in_compiled: false}
|
|
164
|
+
- {name: delimit_loop_config, kind: pro, category: build_loop, in_compiled: false}
|
|
165
|
+
|
|
166
|
+
# ── Worker Pool v2 executor (LED-981) ────────────────────────────
|
|
167
|
+
- {name: delimit_executor, kind: pro, category: agent}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import logging
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, Any, List
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger("delimit.reaper")
|
|
11
|
+
|
|
12
|
+
def reap_agent_tasks(project_path: str = "/home/delimit/delimit-gateway") -> List[str]:
|
|
13
|
+
"""Reap completed agent arms by checking for commits and merging."""
|
|
14
|
+
from ai.agent_dispatch import get_agent_status, complete_task
|
|
15
|
+
from ai.ledger_manager import update_item
|
|
16
|
+
|
|
17
|
+
# 1. Get all dispatched tasks
|
|
18
|
+
res = get_agent_status()
|
|
19
|
+
tasks = res.get("tasks", [])
|
|
20
|
+
if not isinstance(tasks, list):
|
|
21
|
+
tasks = list(tasks.values())
|
|
22
|
+
|
|
23
|
+
reaped = []
|
|
24
|
+
for task in tasks:
|
|
25
|
+
if task.get("status") != "dispatched":
|
|
26
|
+
continue
|
|
27
|
+
|
|
28
|
+
task_id = task.get("id")
|
|
29
|
+
desc = task.get("description", "")
|
|
30
|
+
|
|
31
|
+
# 2. Extract branch from description
|
|
32
|
+
match = re.search(r'branch ([\w/-]+)', desc)
|
|
33
|
+
if not match:
|
|
34
|
+
continue
|
|
35
|
+
branch = match.group(1)
|
|
36
|
+
|
|
37
|
+
# 3. Check for new commits on the branch
|
|
38
|
+
try:
|
|
39
|
+
cmd = ["git", "-C", project_path, "log", f"main..${branch}", "--oneline"]
|
|
40
|
+
p = subprocess.run(cmd, capture_output=True, text=True)
|
|
41
|
+
if p.returncode == 0 and p.stdout.strip():
|
|
42
|
+
logger.info(f"Reaper: Found activity on ${branch} for task ${task_id}")
|
|
43
|
+
|
|
44
|
+
# 4. RUN TESTS
|
|
45
|
+
test_cmd = ["python3", "-m", "pytest", "tests/", "-v", "--maxfail=3"]
|
|
46
|
+
env = {"DELIMIT_TEST_MODE": "1", "PATH": f"/root/.delimit/shims:${os.environ['PATH']}"}
|
|
47
|
+
test_p = subprocess.run(test_cmd, cwd=project_path, capture_output=True, text=True, env={**os.environ, **env})
|
|
48
|
+
|
|
49
|
+
if test_p.returncode == 0:
|
|
50
|
+
# 5. MERGE
|
|
51
|
+
subprocess.run(["git", "-C", project_path, "checkout", "main"], check=True)
|
|
52
|
+
subprocess.run(["git", "-C", project_path, "merge", branch], check=True)
|
|
53
|
+
|
|
54
|
+
# 6. COMPLETE
|
|
55
|
+
complete_task(task_id, result="Reaper: Actually built and merged to main.")
|
|
56
|
+
|
|
57
|
+
# 7. Update Ledger
|
|
58
|
+
ctx = task.get("context", "")
|
|
59
|
+
led_match = re.search(r'LED-(\d+)', ctx)
|
|
60
|
+
if led_match:
|
|
61
|
+
led_id = led_match.group(0)
|
|
62
|
+
update_item(item_id=led_id, status="done", note=f"Arm ${task_id} merged.")
|
|
63
|
+
|
|
64
|
+
reaped.append(task_id)
|
|
65
|
+
else:
|
|
66
|
+
logger.warning(f"Reaper: Tests failed for ${branch}, skipping merge.")
|
|
67
|
+
except Exception as e:
|
|
68
|
+
logger.warning(f"Reaper: Failed to reap task ${task_id}: ${e}")
|
|
69
|
+
|
|
70
|
+
return reaped
|
|
@@ -470,14 +470,19 @@ def score_and_classify(
|
|
|
470
470
|
final_score = engagement * fresh_mult * comment_opp * relevance_mult
|
|
471
471
|
is_karma = group == "karma_building"
|
|
472
472
|
|
|
473
|
-
# Classification
|
|
474
|
-
|
|
473
|
+
# Classification (LED-1335 freshness tightening 2026-05-12: founder
|
|
474
|
+
# explicit "we want fresh posts for highest visibility." Comment
|
|
475
|
+
# visibility decays sharply after 6h, marginal after 12h, ~zero
|
|
476
|
+
# after 24h. Old behavior let 12-48h posts through as medium and
|
|
477
|
+
# the daemon drafted on them. New thresholds: hard-skip > 24h,
|
|
478
|
+
# high_priority < 6h, medium_priority < 12h, low_priority < 24h.)
|
|
479
|
+
if post.get("stickied") or age_h > 24 or comments > 100:
|
|
475
480
|
priority = "skip"
|
|
476
|
-
elif final_score >= 30 and age_h <
|
|
481
|
+
elif final_score >= 30 and age_h < 6 and comments < 50:
|
|
477
482
|
priority = "high_priority"
|
|
478
|
-
elif final_score >= 10 or (len(tags) >= 2 and age_h <
|
|
483
|
+
elif (final_score >= 10 and age_h < 12) or (len(tags) >= 2 and age_h < 12):
|
|
479
484
|
priority = "medium_priority"
|
|
480
|
-
elif final_score >= 3:
|
|
485
|
+
elif final_score >= 3 and age_h < 24:
|
|
481
486
|
priority = "low_priority"
|
|
482
487
|
else:
|
|
483
488
|
priority = "skip"
|
|
@@ -724,6 +729,7 @@ def monitor_user_engagement(username: str = "delimitdev", proxy_url: str = PROXY
|
|
|
724
729
|
cd = cc.get("data", {})
|
|
725
730
|
if cd.get("id") != comment_id:
|
|
726
731
|
continue
|
|
732
|
+
our_comment_body = cd.get("body") or ""
|
|
727
733
|
replies_listing = cd.get("replies")
|
|
728
734
|
if not isinstance(replies_listing, dict):
|
|
729
735
|
continue
|
|
@@ -732,7 +738,10 @@ def monitor_user_engagement(username: str = "delimitdev", proxy_url: str = PROXY
|
|
|
732
738
|
rd = rc.get("data", {})
|
|
733
739
|
reply_id = rd.get("id", "")
|
|
734
740
|
reply_author = rd.get("author", "")
|
|
735
|
-
|
|
741
|
+
# Capture full reply body for the follow-up drafter (the alert
|
|
742
|
+
# email's short preview still uses the truncated form below).
|
|
743
|
+
reply_body_full = rd.get("body") or ""
|
|
744
|
+
reply_body = reply_body_full[:200]
|
|
736
745
|
if not reply_id or reply_author == username:
|
|
737
746
|
continue
|
|
738
747
|
seen_key = f"reply_{reply_id}"
|
|
@@ -744,6 +753,8 @@ def monitor_user_engagement(username: str = "delimitdev", proxy_url: str = PROXY
|
|
|
744
753
|
"reply_id": reply_id,
|
|
745
754
|
"reply_author": reply_author,
|
|
746
755
|
"reply_body": reply_body,
|
|
756
|
+
"reply_body_full": reply_body_full,
|
|
757
|
+
"our_comment_body": our_comment_body,
|
|
747
758
|
"subreddit": d.get("subreddit", ""),
|
|
748
759
|
"title": d.get("link_title", ""),
|
|
749
760
|
"message": f"u/{reply_author} replied to your comment in r/{d.get('subreddit','')}: {reply_body[:100]}",
|
|
@@ -10,7 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
import hashlib
|
|
11
11
|
import re
|
|
12
12
|
from dataclasses import dataclass, field, asdict
|
|
13
|
-
from typing import Any, Dict, List
|
|
13
|
+
from typing import Any, Dict, List
|
|
14
14
|
from urllib.parse import urlparse, urlunparse, parse_qsl, urlencode
|
|
15
15
|
|
|
16
16
|
|