tracebook 0.1.1 → 1.0.0

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -24
  3. data/README.md +197 -713
  4. data/app/assets/javascripts/tracebook/application.js +92 -35
  5. data/app/assets/stylesheets/tracebook/application.css +1882 -55
  6. data/app/controllers/tracebook/application_controller.rb +25 -0
  7. data/app/controllers/tracebook/chats_controller.rb +229 -0
  8. data/app/controllers/tracebook/comments_controller.rb +25 -0
  9. data/app/helpers/tracebook/chats_helper.rb +29 -0
  10. data/app/models/tracebook/chat_review.rb +19 -0
  11. data/app/models/tracebook/comment.rb +14 -0
  12. data/app/models/tracebook/message_cost.rb +12 -0
  13. data/app/models/tracebook/pricing_rule.rb +6 -8
  14. data/app/views/tracebook/chats/index.html.erb +77 -0
  15. data/app/views/tracebook/chats/show.html.erb +94 -0
  16. data/config/routes.rb +6 -6
  17. data/db/migrate/20260325000100_create_tracebook_message_costs.rb +19 -0
  18. data/db/migrate/20260325000200_create_tracebook_chat_reviews.rb +19 -0
  19. data/db/migrate/{20241112000300_create_tracebook_pricing_rules.rb → 20260325000300_create_tracebook_pricing_rules.rb} +3 -3
  20. data/db/migrate/20260325000500_create_tracebook_comments.rb +15 -0
  21. data/lib/generators/tracebook/install/install_generator.rb +6 -9
  22. data/lib/generators/tracebook/install/templates/initializer.rb.tt +11 -5
  23. data/lib/tasks/tracebook_tasks.rake +14 -4
  24. data/lib/tracebook/adapters/ruby_llm.rb +19 -81
  25. data/lib/tracebook/adapters.rb +5 -4
  26. data/lib/tracebook/config.rb +83 -104
  27. data/lib/tracebook/engine.rb +6 -0
  28. data/lib/tracebook/errors.rb +0 -2
  29. data/lib/tracebook/pricing/calculator.rb +11 -6
  30. data/lib/tracebook/pricing.rb +0 -2
  31. data/lib/tracebook/redaction/pattern.rb +124 -0
  32. data/lib/tracebook/redaction/pipeline.rb +32 -0
  33. data/lib/tracebook/seeds/pricing_rules.rb +62 -0
  34. data/lib/tracebook/version.rb +1 -1
  35. data/lib/tracebook.rb +46 -152
  36. metadata +23 -51
  37. data/app/controllers/tracebook/exports_controller.rb +0 -25
  38. data/app/controllers/tracebook/interactions_controller.rb +0 -71
  39. data/app/helpers/tracebook/interactions_helper.rb +0 -35
  40. data/app/jobs/tracebook/daily_rollups_job.rb +0 -100
  41. data/app/jobs/tracebook/export_job.rb +0 -162
  42. data/app/jobs/tracebook/persist_interaction_job.rb +0 -160
  43. data/app/mailers/tracebook/application_mailer.rb +0 -6
  44. data/app/models/tracebook/interaction.rb +0 -103
  45. data/app/models/tracebook/redaction_rule.rb +0 -81
  46. data/app/models/tracebook/rollup_daily.rb +0 -73
  47. data/app/views/tracebook/interactions/index.html.erb +0 -108
  48. data/app/views/tracebook/interactions/show.html.erb +0 -44
  49. data/db/migrate/20241112000100_create_tracebook_interactions.rb +0 -55
  50. data/db/migrate/20241112000200_create_tracebook_rollups_dailies.rb +0 -24
  51. data/db/migrate/20241112000400_create_tracebook_redaction_rules.rb +0 -19
  52. data/lib/tracebook/adapters/active_agent.rb +0 -82
  53. data/lib/tracebook/mappers/anthropic.rb +0 -59
  54. data/lib/tracebook/mappers/base.rb +0 -38
  55. data/lib/tracebook/mappers/ollama.rb +0 -49
  56. data/lib/tracebook/mappers/openai.rb +0 -75
  57. data/lib/tracebook/mappers.rb +0 -283
  58. data/lib/tracebook/normalized_interaction.rb +0 -86
  59. data/lib/tracebook/redaction_pipeline.rb +0 -88
  60. data/lib/tracebook/redactors/base.rb +0 -29
  61. data/lib/tracebook/redactors/card_pan.rb +0 -15
  62. data/lib/tracebook/redactors/email.rb +0 -15
  63. data/lib/tracebook/redactors/phone.rb +0 -15
  64. data/lib/tracebook/redactors.rb +0 -8
  65. data/lib/tracebook/result.rb +0 -53
@@ -4,14 +4,7 @@
4
4
 
5
5
  function warnStimulusMissing() {
6
6
  if (booted) return;
7
-
8
- console.warn("TraceBook: Stimulus failed to load; keyboard shortcuts disabled.");
9
- if (document.body) {
10
- const banner = document.createElement("div");
11
- banner.className = "tb-alert";
12
- banner.textContent = "Keyboard navigation is unavailable because Stimulus failed to load.";
13
- document.body.prepend(banner);
14
- }
7
+ console.warn("TraceBook: Stimulus failed to load.");
15
8
  }
16
9
 
17
10
  function startApplication() {
@@ -23,56 +16,120 @@
23
16
  booted = true;
24
17
  const application = window.Stimulus.Application.start();
25
18
 
26
- class KeyboardController extends window.Stimulus.Controller {
19
+ class BulkSelectController extends window.Stimulus.Controller {
20
+ static get targets() {
21
+ return ["toggleAll", "checkbox", "submitButton"];
22
+ }
23
+
24
+ connect() {
25
+ this.updateButtonState();
26
+ }
27
+
28
+ toggleAll() {
29
+ const checked = this.toggleAllTarget.checked;
30
+ this.checkboxTargets.forEach((checkbox) => {
31
+ checkbox.checked = checked;
32
+ });
33
+ this.updateButtonState();
34
+ }
35
+
36
+ checkboxChanged() {
37
+ this.updateButtonState();
38
+ }
39
+
40
+ updateButtonState() {
41
+ const hasSelectedCheckboxes = this.checkboxTargets.some((checkbox) => checkbox.checked);
42
+ this.submitButtonTarget.disabled = !hasSelectedCheckboxes;
43
+ }
44
+ }
45
+
46
+ class JsonViewerController extends window.Stimulus.Controller {
27
47
  static get targets() {
28
- return ["table", "row", "checkbox", "toggleAll", "reviewState"];
48
+ return ["content", "icon", "copyBtn", "copyText"];
49
+ }
50
+
51
+ static get values() {
52
+ return { collapsed: Boolean };
29
53
  }
30
54
 
31
55
  connect() {
32
- this.index = 0;
33
- this.updateSelection();
34
- this.element.addEventListener("keydown", this.handleKeydown.bind(this));
56
+ if (this.collapsedValue) {
57
+ this.collapse();
58
+ } else {
59
+ this.expand();
60
+ }
35
61
  }
36
62
 
37
- handleKeydown(event) {
38
- if (["j", "J"].includes(event.key)) {
39
- event.preventDefault();
40
- this.index = Math.min(this.rowTargets.length - 1, this.index + 1);
41
- this.updateSelection();
63
+ toggle(event) {
64
+ // Don't toggle if clicking the copy button
65
+ if (event.target.closest('.tb-copy-btn')) return;
66
+
67
+ if (this.element.classList.contains("tb-collapsed")) {
68
+ this.expand();
69
+ } else {
70
+ this.collapse();
42
71
  }
43
- if (["k", "K"].includes(event.key)) {
44
- event.preventDefault();
45
- this.index = Math.max(0, this.index - 1);
46
- this.updateSelection();
72
+ }
73
+
74
+ collapse() {
75
+ this.element.classList.add("tb-collapsed");
76
+ this.element.classList.remove("tb-expanded");
77
+ if (this.hasContentTarget) {
78
+ this.contentTarget.style.display = "none";
47
79
  }
48
- if ([" ", "Enter"].includes(event.key)) {
49
- event.preventDefault();
50
- const checkbox = this.checkboxTargets[this.index];
51
- if (checkbox) {
52
- checkbox.checked = !checkbox.checked;
53
- }
80
+ if (this.hasIconTarget) {
81
+ this.iconTarget.textContent = "▶";
54
82
  }
55
83
  }
56
84
 
57
- updateSelection() {
58
- this.rowTargets.forEach((row, idx) => {
59
- row.classList.toggle("tb-selected", idx === this.index);
85
+ expand() {
86
+ this.element.classList.remove("tb-collapsed");
87
+ this.element.classList.add("tb-expanded");
88
+ if (this.hasContentTarget) {
89
+ this.contentTarget.style.display = "block";
90
+ }
91
+ if (this.hasIconTarget) {
92
+ this.iconTarget.textContent = "▼";
93
+ }
94
+ }
95
+
96
+ copy(event) {
97
+ event.stopPropagation();
98
+ const btn = event.currentTarget;
99
+ const payload = btn.dataset.payload;
100
+
101
+ navigator.clipboard.writeText(payload).then(() => {
102
+ if (this.hasCopyTextTarget) {
103
+ const originalText = this.copyTextTarget.textContent;
104
+ this.copyTextTarget.textContent = "Copied!";
105
+ setTimeout(() => { this.copyTextTarget.textContent = originalText; }, 2000);
106
+ }
107
+ }).catch(() => {
108
+ console.error("Failed to copy to clipboard");
60
109
  });
61
110
  }
62
111
  }
63
112
 
64
- class JsonViewerController extends window.Stimulus.Controller {
113
+ class MessageToggleController extends window.Stimulus.Controller {
65
114
  static get targets() {
66
- return ["content"];
115
+ return ["content", "icon"];
67
116
  }
68
117
 
69
118
  toggle() {
70
- this.element.classList.toggle("tb-collapsed");
119
+ const isHidden = this.contentTarget.classList.contains("hidden");
120
+ if (isHidden) {
121
+ this.contentTarget.classList.remove("hidden");
122
+ this.iconTarget.textContent = "▼";
123
+ } else {
124
+ this.contentTarget.classList.add("hidden");
125
+ this.iconTarget.textContent = "▶";
126
+ }
71
127
  }
72
128
  }
73
129
 
74
- application.register("keyboard", KeyboardController);
130
+ application.register("bulk-select", BulkSelectController);
75
131
  application.register("json-viewer", JsonViewerController);
132
+ application.register("message-toggle", MessageToggleController);
76
133
  }
77
134
 
78
135
  if (window.Stimulus) {