codebee 0.1.103 → 0.1.105

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 (128) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -21
  3. package/README.md +5 -3
  4. package/app/core/acceptance.py +100 -100
  5. package/app/core/acp_client.py +457 -457
  6. package/app/core/aiflavor.py +197 -197
  7. package/app/core/analytics.py +38 -38
  8. package/app/core/artifacts.py +148 -148
  9. package/app/core/assets.py +110 -110
  10. package/app/core/attachments.py +623 -623
  11. package/app/core/audit.py +30 -30
  12. package/app/core/backend_profiles.py +188 -188
  13. package/app/core/backup.py +470 -470
  14. package/app/core/beekeeper.py +183 -183
  15. package/app/core/benchstore.py +102 -102
  16. package/app/core/bookmeta.py +1036 -1036
  17. package/app/core/bookmeta_catalog.py +180 -180
  18. package/app/core/branching.py +137 -137
  19. package/app/core/capability.py +144 -144
  20. package/app/core/chaptersafe.py +32 -32
  21. package/app/core/checkpoints.py +48 -5
  22. package/app/core/cleanup.py +303 -303
  23. package/app/core/command_auth.py +302 -302
  24. package/app/core/compaction.py +201 -201
  25. package/app/core/contracts.py +255 -255
  26. package/app/core/covergen.py +356 -356
  27. package/app/core/defectretro.py +43 -43
  28. package/app/core/diagnostics.py +114 -114
  29. package/app/core/dispatch_log.py +128 -128
  30. package/app/core/env_scrub.py +85 -85
  31. package/app/core/errorlog.py +137 -137
  32. package/app/core/eval_matrix.py +91 -91
  33. package/app/core/evaluation.py +174 -174
  34. package/app/core/failure_notify.py +290 -290
  35. package/app/core/flow_graph.py +33 -33
  36. package/app/core/goal_service.py +167 -167
  37. package/app/core/health.py +389 -389
  38. package/app/core/history.py +38 -38
  39. package/app/core/hooks.py +162 -162
  40. package/app/core/knowledge_pipeline.py +86 -86
  41. package/app/core/manager.py +2386 -2385
  42. package/app/core/mocks.py +64 -64
  43. package/app/core/notify.py +201 -201
  44. package/app/core/novel_quality.py +285 -181
  45. package/app/core/openapi.py +246 -217
  46. package/app/core/operations.py +228 -228
  47. package/app/core/paihang.py +145 -145
  48. package/app/core/pipeline.py +81 -11
  49. package/app/core/planner.py +7 -0
  50. package/app/core/portguard.py +111 -111
  51. package/app/core/presence.py +77 -77
  52. package/app/core/preview.py +293 -293
  53. package/app/core/project_memory.py +252 -206
  54. package/app/core/prompt_guard.py +78 -78
  55. package/app/core/publish/__init__.py +7 -7
  56. package/app/core/publish/auto.py +659 -659
  57. package/app/core/publish/chaprows.py +138 -138
  58. package/app/core/publish/flows-fanqie-calibrated.json +442 -442
  59. package/app/core/publish/manager.py +1185 -1185
  60. package/app/core/publish/qimao.py +193 -193
  61. package/app/core/publish/volumes.py +108 -108
  62. package/app/core/publish/ws.py +139 -139
  63. package/app/core/quality_gate.py +201 -201
  64. package/app/core/redact.py +38 -38
  65. package/app/core/registry.py +35 -0
  66. package/app/core/repeat_guard.py +129 -129
  67. package/app/core/retrieval.py +137 -137
  68. package/app/core/review_requests.py +119 -0
  69. package/app/core/runner.py +5 -1
  70. package/app/core/sandbox_runtime.py +95 -95
  71. package/app/core/selfupdate.py +384 -384
  72. package/app/core/session_log.py +161 -161
  73. package/app/core/sessions.py +312 -312
  74. package/app/core/settings.py +215 -215
  75. package/app/core/settings_schema.py +282 -282
  76. package/app/core/share_page.py +114 -114
  77. package/app/core/skill_scan.py +139 -139
  78. package/app/core/skillpacks/market/character-bible.md +66 -66
  79. package/app/core/skillpacks/market/code-risk-checklist.md +58 -58
  80. package/app/core/skillpacks/market/git-workflow.md +57 -57
  81. package/app/core/skillpacks/market/release-notes.md +72 -72
  82. package/app/core/skillpacks/market/weekly-report.md +71 -71
  83. package/app/core/skillpacks/market/worldview-consistency.md +70 -70
  84. package/app/core/step_runner.py +132 -132
  85. package/app/core/story_tracking.py +275 -275
  86. package/app/core/task_compile.py +199 -199
  87. package/app/core/telemetry.py +292 -292
  88. package/app/core/tlsctx.py +64 -64
  89. package/app/core/token_meter.py +147 -147
  90. package/app/core/tool_outputs.py +107 -107
  91. package/app/core/tracing.py +207 -207
  92. package/app/core/upstream.py +41 -41
  93. package/app/core/usage.py +1038 -1038
  94. package/app/core/volumes.py +389 -389
  95. package/app/core/webhooks.py +89 -89
  96. package/app/core/wxdigest.py +865 -865
  97. package/app/core/zentao.py +2692 -2692
  98. package/app/main.py +43 -0
  99. package/app/mcp_server.py +244 -244
  100. package/app/pick_dialog.py +110 -110
  101. package/app/ui/app.js +21 -2
  102. package/app/ui/artdiff.js +74 -74
  103. package/app/ui/hive3d.js +54 -31
  104. package/app/ui/i18n.js +32 -1
  105. package/app/ui/icons/bee.svg +79 -79
  106. package/app/ui/index.html +1 -0
  107. package/app/ui/manifest.json +16 -16
  108. package/app/ui/qrcode.js +2297 -2297
  109. package/bin/tutti.js +147 -147
  110. package/package.json +1 -1
  111. package/tools/wx_reader.py +261 -261
  112. package/app/.playwright-cli/console-2026-09-23T08-26-03-635Z.log +0 -88
  113. package/app/.playwright-cli/page-2026-09-23T08-26-03-845Z.yml +0 -126
  114. package/app/.playwright-cli/page-2026-09-23T08-29-44-203Z.png +0 -0
  115. package/app/.playwright-cli/page-2026-09-23T08-35-42-046Z.yml +0 -210
  116. package/app/.playwright-cli/page-2026-09-23T08-36-52-858Z.png +0 -0
  117. package/app/.playwright-cli/page-2026-09-23T08-37-33-938Z.png +0 -0
  118. package/app/.playwright-cli/run-detail-after.png +0 -0
  119. package/app/output/_createbook_body.json +0 -1
  120. package/app/output/_probe_fq_click.py +0 -50
  121. package/app/output/_probe_fq_form.py +0 -42
  122. package/app/output/_probe_fq_modal.py +0 -55
  123. package/app/output/_probe_fq_points.py +0 -71
  124. package/app/output/_probe_fq_submit.py +0 -34
  125. package/app/output/_probe_fq_watch.py +0 -62
  126. package/app/output/workbench-clean-preview.jpg +0 -0
  127. package/app/output/workbench-reference-render.png +0 -0
  128. package/app/output/workbench-shell.png +0 -0
@@ -1,89 +1,89 @@
1
- # -*- coding: utf-8 -*-
2
- """Webhook signing and delivery-id replay protection."""
3
- from __future__ import annotations
4
-
5
- import hashlib
6
- import hmac
7
- import json
8
- import sqlite3
9
- import threading
10
- import time
11
- from pathlib import Path
12
-
13
- from . import paths
14
-
15
- _FILE = paths.DATA_DIR / "webhook_deliveries.json"
16
- MAX_SKEW_SECONDS = 300
17
- MAX_DELIVERIES = 2000
18
- _LOCK = threading.RLock()
19
-
20
-
21
- def sign(secret, body, timestamp):
22
- payload = (str(timestamp) + ".").encode("utf-8") + (body or b"")
23
- return "sha256=" + hmac.new(str(secret or "").encode("utf-8"), payload,
24
- hashlib.sha256).hexdigest()
25
-
26
-
27
- def verify(secret, body, signature, timestamp, *, now=None, max_skew=MAX_SKEW_SECONDS):
28
- if not secret or not signature:
29
- return False
30
- try:
31
- ts = int(timestamp)
32
- if abs((time.time() if now is None else float(now)) - ts) > max(1, int(max_skew)):
33
- return False
34
- except (TypeError, ValueError):
35
- return False
36
- expected = sign(secret, body, ts)
37
- return hmac.compare_digest(expected, str(signature).strip())
38
-
39
-
40
- def verify_raw(secret, body, signature):
41
- """Verify providers such as GitHub that sign the raw body only."""
42
- if not secret or not signature:
43
- return False
44
- expected = "sha256=" + hmac.new(str(secret).encode("utf-8"), body or b"",
45
- hashlib.sha256).hexdigest()
46
- return hmac.compare_digest(expected, str(signature).strip())
47
-
48
-
49
- def _load():
50
- try:
51
- value = json.loads(_FILE.read_text(encoding="utf-8"))
52
- return value if isinstance(value, dict) else {}
53
- except (OSError, TypeError, ValueError):
54
- return {}
55
-
56
-
57
- def claim_delivery(delivery_id, *, now=None, ttl_seconds=86400):
58
- delivery_id = str(delivery_id or "").strip()[:160]
59
- if not delivery_id:
60
- return True, {"deduplicated": False, "delivery_id": ""}
61
- stamp = float(time.time() if now is None else now)
62
- db_path = _FILE.with_suffix(_FILE.suffix + ".sqlite3")
63
- with _LOCK:
64
- db_path.parent.mkdir(parents=True, exist_ok=True)
65
- with sqlite3.connect(str(db_path), timeout=5) as db:
66
- db.execute("CREATE TABLE IF NOT EXISTS deliveries (delivery_id TEXT PRIMARY KEY, claimed_at REAL NOT NULL)")
67
- cutoff = stamp - max(60, int(ttl_seconds))
68
- db.execute("DELETE FROM deliveries WHERE claimed_at < ?", (cutoff,))
69
- try:
70
- db.execute("INSERT INTO deliveries(delivery_id, claimed_at) VALUES (?, ?)",
71
- (delivery_id, stamp))
72
- except sqlite3.IntegrityError:
73
- return False, {"deduplicated": True, "delivery_id": delivery_id}
74
- db.execute("DELETE FROM deliveries WHERE delivery_id NOT IN (SELECT delivery_id FROM deliveries ORDER BY claimed_at DESC LIMIT ?)",
75
- (MAX_DELIVERIES,))
76
- return True, {"deduplicated": False, "delivery_id": delivery_id}
77
-
78
-
79
- def release_delivery(delivery_id):
80
- delivery_id = str(delivery_id or "").strip()[:160]
81
- if not delivery_id:
82
- return
83
- db_path = _FILE.with_suffix(_FILE.suffix + ".sqlite3")
84
- with _LOCK:
85
- try:
86
- with sqlite3.connect(str(db_path), timeout=5) as db:
87
- db.execute("DELETE FROM deliveries WHERE delivery_id = ?", (delivery_id,))
88
- except (OSError, sqlite3.Error):
89
- pass
1
+ # -*- coding: utf-8 -*-
2
+ """Webhook signing and delivery-id replay protection."""
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import hmac
7
+ import json
8
+ import sqlite3
9
+ import threading
10
+ import time
11
+ from pathlib import Path
12
+
13
+ from . import paths
14
+
15
+ _FILE = paths.DATA_DIR / "webhook_deliveries.json"
16
+ MAX_SKEW_SECONDS = 300
17
+ MAX_DELIVERIES = 2000
18
+ _LOCK = threading.RLock()
19
+
20
+
21
+ def sign(secret, body, timestamp):
22
+ payload = (str(timestamp) + ".").encode("utf-8") + (body or b"")
23
+ return "sha256=" + hmac.new(str(secret or "").encode("utf-8"), payload,
24
+ hashlib.sha256).hexdigest()
25
+
26
+
27
+ def verify(secret, body, signature, timestamp, *, now=None, max_skew=MAX_SKEW_SECONDS):
28
+ if not secret or not signature:
29
+ return False
30
+ try:
31
+ ts = int(timestamp)
32
+ if abs((time.time() if now is None else float(now)) - ts) > max(1, int(max_skew)):
33
+ return False
34
+ except (TypeError, ValueError):
35
+ return False
36
+ expected = sign(secret, body, ts)
37
+ return hmac.compare_digest(expected, str(signature).strip())
38
+
39
+
40
+ def verify_raw(secret, body, signature):
41
+ """Verify providers such as GitHub that sign the raw body only."""
42
+ if not secret or not signature:
43
+ return False
44
+ expected = "sha256=" + hmac.new(str(secret).encode("utf-8"), body or b"",
45
+ hashlib.sha256).hexdigest()
46
+ return hmac.compare_digest(expected, str(signature).strip())
47
+
48
+
49
+ def _load():
50
+ try:
51
+ value = json.loads(_FILE.read_text(encoding="utf-8"))
52
+ return value if isinstance(value, dict) else {}
53
+ except (OSError, TypeError, ValueError):
54
+ return {}
55
+
56
+
57
+ def claim_delivery(delivery_id, *, now=None, ttl_seconds=86400):
58
+ delivery_id = str(delivery_id or "").strip()[:160]
59
+ if not delivery_id:
60
+ return True, {"deduplicated": False, "delivery_id": ""}
61
+ stamp = float(time.time() if now is None else now)
62
+ db_path = _FILE.with_suffix(_FILE.suffix + ".sqlite3")
63
+ with _LOCK:
64
+ db_path.parent.mkdir(parents=True, exist_ok=True)
65
+ with sqlite3.connect(str(db_path), timeout=5) as db:
66
+ db.execute("CREATE TABLE IF NOT EXISTS deliveries (delivery_id TEXT PRIMARY KEY, claimed_at REAL NOT NULL)")
67
+ cutoff = stamp - max(60, int(ttl_seconds))
68
+ db.execute("DELETE FROM deliveries WHERE claimed_at < ?", (cutoff,))
69
+ try:
70
+ db.execute("INSERT INTO deliveries(delivery_id, claimed_at) VALUES (?, ?)",
71
+ (delivery_id, stamp))
72
+ except sqlite3.IntegrityError:
73
+ return False, {"deduplicated": True, "delivery_id": delivery_id}
74
+ db.execute("DELETE FROM deliveries WHERE delivery_id NOT IN (SELECT delivery_id FROM deliveries ORDER BY claimed_at DESC LIMIT ?)",
75
+ (MAX_DELIVERIES,))
76
+ return True, {"deduplicated": False, "delivery_id": delivery_id}
77
+
78
+
79
+ def release_delivery(delivery_id):
80
+ delivery_id = str(delivery_id or "").strip()[:160]
81
+ if not delivery_id:
82
+ return
83
+ db_path = _FILE.with_suffix(_FILE.suffix + ".sqlite3")
84
+ with _LOCK:
85
+ try:
86
+ with sqlite3.connect(str(db_path), timeout=5) as db:
87
+ db.execute("DELETE FROM deliveries WHERE delivery_id = ?", (delivery_id,))
88
+ except (OSError, sqlite3.Error):
89
+ pass