easc-cli 1.1.29 → 1.1.31

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.
@@ -0,0 +1,444 @@
1
+ // Supabase configuration
2
+ const SUPABASE_URL = "https://affhpjwojmovvrwxlnmn.supabase.co"
3
+ const SUPABASE_ANON_KEY =
4
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFmZmhwandvam1vdnZyd3hsbm1uIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjkwMTgyMjMsImV4cCI6MjA4NDU5NDIyM30.fN44OO4Plw-45fL7l-G1sSfliPvveN3t-gP1Pwm0LME"
5
+
6
+ // Initialize Supabase
7
+ const supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
8
+
9
+ // Global state
10
+ let charities = []
11
+ let categories = []
12
+ let currentCharityId = null
13
+ let offset = 0
14
+ const limit = 6
15
+
16
+ // DOM elements
17
+ const navToggle = document.getElementById("navToggle")
18
+ const navMenu = document.querySelector(".nav-menu")
19
+ const charitiesGrid = document.getElementById("charitiesGrid")
20
+ const categoryFilter = document.getElementById("categoryFilter")
21
+ const sortFilter = document.getElementById("sortFilter")
22
+ const searchInput = document.getElementById("searchInput")
23
+ const loadMoreBtn = document.getElementById("loadMoreBtn")
24
+ const donationModal = document.getElementById("donationModal")
25
+ const donationForm = document.getElementById("donationForm")
26
+ const contactForm = document.getElementById("contactForm")
27
+
28
+ // Initialize app
29
+ document.addEventListener("DOMContentLoaded", async () => {
30
+ await initializeApp()
31
+ })
32
+
33
+ async function initializeApp() {
34
+ try {
35
+ await loadCategories()
36
+ await loadCharities()
37
+ await loadStats()
38
+ setupEventListeners()
39
+ } catch (error) {
40
+ console.error("Error initializing app:", error)
41
+ showToast("Error loading application", "error")
42
+ }
43
+ }
44
+
45
+ // Event Listeners
46
+ function setupEventListeners() {
47
+ // Navigation toggle
48
+ navToggle.addEventListener("click", () => {
49
+ navMenu.classList.toggle("active")
50
+ })
51
+
52
+ // Smooth scrolling for navigation links
53
+ document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
54
+ anchor.addEventListener("click", function (e) {
55
+ e.preventDefault()
56
+ const target = document.querySelector(this.getAttribute("href"))
57
+ if (target) {
58
+ target.scrollIntoView({ behavior: "smooth", block: "start" })
59
+ navMenu.classList.remove("active")
60
+ }
61
+ })
62
+ })
63
+
64
+ // Filters
65
+ categoryFilter.addEventListener("change", filterCharities)
66
+ sortFilter.addEventListener("change", filterCharities)
67
+ searchInput.addEventListener("input", debounce(filterCharities, 300))
68
+
69
+ // Donation form
70
+ donationForm.addEventListener("submit", handleDonation)
71
+
72
+ // Contact form
73
+ contactForm.addEventListener("submit", handleContact)
74
+
75
+ // Amount buttons
76
+ document.querySelectorAll(".amount-btn").forEach((btn) => {
77
+ btn.addEventListener("click", function () {
78
+ document.querySelectorAll(".amount-btn").forEach((b) => b.classList.remove("active"))
79
+ this.classList.add("active")
80
+ document.getElementById("donationAmount").value = this.dataset.amount
81
+ })
82
+ })
83
+
84
+ // Modal close on outside click
85
+ donationModal.addEventListener("click", (e) => {
86
+ if (e.target === donationModal) {
87
+ closeDonationModal()
88
+ }
89
+ })
90
+ }
91
+
92
+ // Load categories
93
+ async function loadCategories() {
94
+ try {
95
+ const { data, error } = await supabase.from("categories").select("*").order("name")
96
+
97
+ if (error) throw error
98
+ categories = data
99
+
100
+ // Populate category filter
101
+ categories.forEach((category) => {
102
+ const option = document.createElement("option")
103
+ option.value = category.name
104
+ option.textContent = category.name
105
+ categoryFilter.appendChild(option)
106
+ })
107
+
108
+ // Populate footer categories
109
+ const footerCategories = document.getElementById("footerCategories")
110
+ categories.forEach((category) => {
111
+ const li = document.createElement("li")
112
+ const a = document.createElement("a")
113
+ a.href = "#charities"
114
+ a.textContent = category.name
115
+ a.addEventListener("click", (e) => {
116
+ e.preventDefault()
117
+ categoryFilter.value = category.name
118
+ filterCharities()
119
+ scrollToCharities()
120
+ })
121
+ li.appendChild(a)
122
+ footerCategories.appendChild(li)
123
+ })
124
+ } catch (error) {
125
+ console.error("Error loading categories:", error)
126
+ }
127
+ }
128
+
129
+ // Load charities
130
+ async function loadCharities(reset = false) {
131
+ try {
132
+ if (reset) {
133
+ offset = 0
134
+ charities = []
135
+ }
136
+
137
+ let query = supabase
138
+ .from("charities")
139
+ .select("*")
140
+ .eq("is_active", true)
141
+ .range(offset, offset + limit - 1)
142
+ .order("created_at", { ascending: false })
143
+
144
+ // Apply filters
145
+ const category = categoryFilter.value
146
+ if (category) {
147
+ query = query.eq("category", category)
148
+ }
149
+
150
+ const searchTerm = searchInput.value.trim()
151
+ if (searchTerm) {
152
+ query = query.or(`name.ilike.%${searchTerm}%,description.ilike.%${searchTerm}%`)
153
+ }
154
+
155
+ // Apply sorting
156
+ const sortBy = sortFilter.value
157
+ if (sortBy === "name") {
158
+ query = query.order("name", { ascending: true })
159
+ } else if (sortBy === "goal") {
160
+ query = query.order("goal_amount", { ascending: false })
161
+ } else if (sortBy === "progress") {
162
+ query = query.order("current_amount", { ascending: false })
163
+ }
164
+
165
+ const { data, error } = await query
166
+
167
+ if (error) throw error
168
+
169
+ if (reset) {
170
+ charities = data
171
+ } else {
172
+ charities = [...charities, ...data]
173
+ }
174
+
175
+ renderCharities()
176
+ updateLoadMoreButton(data.length)
177
+ } catch (error) {
178
+ console.error("Error loading charities:", error)
179
+ showToast("Error loading charities", "error")
180
+ }
181
+ }
182
+
183
+ // Render charities
184
+ function renderCharities() {
185
+ charitiesGrid.innerHTML = ""
186
+
187
+ charities.forEach((charity) => {
188
+ const card = createCharityCard(charity)
189
+ charitiesGrid.appendChild(card)
190
+ })
191
+ }
192
+
193
+ // Create charity card
194
+ function createCharityCard(charity) {
195
+ const progress = (charity.current_amount / charity.goal_amount) * 100
196
+
197
+ const card = document.createElement("div")
198
+ card.className = "charity-card"
199
+ card.onclick = () => openDonationModal(charity)
200
+
201
+ card.innerHTML = `
202
+ <img src="${charity.image_url || "https://images.unsplash.com/photo-1488521787991-ed7bba14b592?w=400"}"
203
+ alt="${charity.name}" class="charity-image">
204
+ <div class="charity-content">
205
+ <span class="charity-category">${charity.category}</span>
206
+ <h3 class="charity-title">${charity.name}</h3>
207
+ <p class="charity-description">${charity.description}</p>
208
+ <div class="charity-progress">
209
+ <div class="progress-bar">
210
+ <div class="progress-fill" style="width: ${Math.min(progress, 100)}%"></div>
211
+ </div>
212
+ <div class="charity-stats">
213
+ <span class="charity-amount">$${charity.current_amount.toLocaleString()}</span>
214
+ <span class="charity-goal">Goal: $${charity.goal_amount.toLocaleString()}</span>
215
+ </div>
216
+ </div>
217
+ <div class="charity-actions">
218
+ <button class="btn btn-primary" onclick="event.stopPropagation(); openDonationModal(${JSON.stringify(charity).replace(/"/g, "&quot;")})">
219
+ Donate Now
220
+ </button>
221
+ <button class="btn btn-secondary" onclick="event.stopPropagation(); window.open('${charity.website_url}', '_blank')">
222
+ Learn More
223
+ </button>
224
+ </div>
225
+ </div>
226
+ `
227
+
228
+ return card
229
+ }
230
+
231
+ // Filter charities
232
+ async function filterCharities() {
233
+ await loadCharities(true)
234
+ }
235
+
236
+ // Search charities
237
+ async function searchCharities() {
238
+ await filterCharities()
239
+ }
240
+
241
+ // Load more charities
242
+ async function loadMoreCharities() {
243
+ offset += limit
244
+ await loadCharities()
245
+ }
246
+
247
+ // Update load more button
248
+ function updateLoadMoreButton(loadedCount) {
249
+ if (loadedCount < limit) {
250
+ loadMoreBtn.style.display = "none"
251
+ } else {
252
+ loadMoreBtn.style.display = "inline-block"
253
+ }
254
+ }
255
+
256
+ // Load statistics
257
+ async function loadStats() {
258
+ try {
259
+ // Get total charities
260
+ const { count: totalCharities, error: charitiesError } = await supabase
261
+ .from("charities")
262
+ .select("*", { count: "exact", head: true })
263
+ .eq("is_active", true)
264
+
265
+ // Get total raised
266
+ const { data: raisedData, error: raisedError } = await supabase
267
+ .from("charities")
268
+ .select("current_amount")
269
+ .eq("is_active", true)
270
+
271
+ // Get total donors
272
+ const { count: totalDonors, error: donorsError } = await supabase
273
+ .from("donations")
274
+ .select("*", { count: "exact", head: true })
275
+ .eq("payment_status", "completed")
276
+
277
+ if (charitiesError || raisedError || donorsError) throw new Error("Error loading stats")
278
+
279
+ // Update DOM
280
+ document.getElementById("totalCharities").textContent = totalCharities || 0
281
+
282
+ const totalRaised = raisedData?.reduce((sum, charity) => sum + parseFloat(charity.current_amount), 0) || 0
283
+ document.getElementById("totalRaised").textContent = `$${totalRaised.toLocaleString()}`
284
+
285
+ document.getElementById("totalDonors").textContent = totalDonors || 0
286
+ } catch (error) {
287
+ console.error("Error loading stats:", error)
288
+ }
289
+ }
290
+
291
+ // Open donation modal
292
+ function openDonationModal(charity) {
293
+ currentCharityId = charity.id
294
+
295
+ const modalCharityInfo = document.getElementById("modalCharityInfo")
296
+ modalCharityInfo.innerHTML = `
297
+ <h4>${charity.name}</h4>
298
+ <p>${charity.description}</p>
299
+ <div class="charity-progress">
300
+ <div class="progress-bar">
301
+ <div class="progress-fill" style="width: ${(charity.current_amount / charity.goal_amount) * 100}%"></div>
302
+ </div>
303
+ <div class="charity-stats">
304
+ <span>$${charity.current_amount.toLocaleString()} raised</span>
305
+ <span>Goal: $${charity.goal_amount.toLocaleString()}</span>
306
+ </div>
307
+ </div>
308
+ `
309
+
310
+ donationModal.classList.add("active")
311
+ }
312
+
313
+ // Close donation modal
314
+ function closeDonationModal() {
315
+ donationModal.classList.remove("active")
316
+ donationForm.reset()
317
+ document.querySelectorAll(".amount-btn").forEach((btn) => btn.classList.remove("active"))
318
+ currentCharityId = null
319
+ }
320
+
321
+ // Handle donation
322
+ async function handleDonation(e) {
323
+ e.preventDefault()
324
+
325
+ if (!currentCharityId) {
326
+ showToast("Please select a charity", "error")
327
+ return
328
+ }
329
+
330
+ const formData = new FormData(donationForm)
331
+ const donation = {
332
+ charity_id: currentCharityId,
333
+ donor_name: formData.get("donorName") || document.getElementById("donorName").value,
334
+ donor_email: formData.get("donorEmail") || document.getElementById("donorEmail").value,
335
+ amount: parseFloat(document.getElementById("donationAmount").value),
336
+ message: document.getElementById("donationMessage").value,
337
+ is_anonymous: document.getElementById("anonymousDonation").checked,
338
+ payment_status: "pending",
339
+ }
340
+
341
+ try {
342
+ // Insert donation
343
+ const { data, error } = await supabase.from("donations").insert([donation]).select()
344
+
345
+ if (error) throw error
346
+
347
+ // Simulate payment processing (in real app, integrate with payment gateway)
348
+ showToast("Processing payment...", "success")
349
+
350
+ setTimeout(async () => {
351
+ // Update payment status
352
+ const { error: updateError } = await supabase
353
+ .from("donations")
354
+ .update({ payment_status: "completed" })
355
+ .eq("id", data[0].id)
356
+
357
+ if (updateError) throw updateError
358
+
359
+ // Update charity amount
360
+ const { error: charityError } = await supabase
361
+ .from("charities")
362
+ .update({
363
+ current_amount: supabase.raw(`current_amount + ${donation.amount}`),
364
+ updated_at: new Date().toISOString(),
365
+ })
366
+ .eq("id", currentCharityId)
367
+
368
+ if (charityError) throw charityError
369
+
370
+ showToast("Thank you for your donation!", "success")
371
+ closeDonationModal()
372
+ await loadCharities(true)
373
+ await loadStats()
374
+ }, 2000)
375
+ } catch (error) {
376
+ console.error("Error processing donation:", error)
377
+ showToast("Error processing donation", "error")
378
+ }
379
+ }
380
+
381
+ // Handle contact form
382
+ async function handleContact(e) {
383
+ e.preventDefault()
384
+
385
+ const contact = {
386
+ name: document.getElementById("contactName").value,
387
+ email: document.getElementById("contactEmail").value,
388
+ message: document.getElementById("contactMessage").value,
389
+ created_at: new Date().toISOString(),
390
+ }
391
+
392
+ try {
393
+ // In a real app, send this to your backend or email service
394
+ console.log("Contact form submission:", contact)
395
+ showToast("Message sent successfully!", "success")
396
+ contactForm.reset()
397
+ } catch (error) {
398
+ console.error("Error sending message:", error)
399
+ showToast("Error sending message", "error")
400
+ }
401
+ }
402
+
403
+ // Utility functions
404
+ function scrollToCharities() {
405
+ document.getElementById("charities").scrollIntoView({ behavior: "smooth" })
406
+ }
407
+
408
+ function showToast(message, type = "success") {
409
+ const toast = document.createElement("div")
410
+ toast.className = `toast ${type}`
411
+ toast.textContent = message
412
+
413
+ document.body.appendChild(toast)
414
+
415
+ setTimeout(() => {
416
+ toast.classList.add("show")
417
+ }, 100)
418
+
419
+ setTimeout(() => {
420
+ toast.classList.remove("show")
421
+ setTimeout(() => {
422
+ document.body.removeChild(toast)
423
+ }, 300)
424
+ }, 3000)
425
+ }
426
+
427
+ function debounce(func, wait) {
428
+ let timeout
429
+ return function executedFunction(...args) {
430
+ const later = () => {
431
+ clearTimeout(timeout)
432
+ func(...args)
433
+ }
434
+ clearTimeout(timeout)
435
+ timeout = setTimeout(later, wait)
436
+ }
437
+ }
438
+
439
+ // Export functions for global access
440
+ window.openDonationModal = openDonationModal
441
+ window.closeDonationModal = closeDonationModal
442
+ window.scrollToCharities = scrollToCharities
443
+ window.searchCharities = searchCharities
444
+ window.loadMoreCharities = loadMoreCharities
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "1.1.29",
3
+ "version": "1.1.31",
4
4
  "name": "easc-cli",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -46,9 +46,7 @@
46
46
  "typescript": "catalog:",
47
47
  "vscode-languageserver-types": "3.17.5",
48
48
  "why-is-node-running": "3.2.2",
49
- "zod-to-json-schema": "3.24.5"
50
- },
51
- "dependencies": {
49
+ "zod-to-json-schema": "3.24.5",
52
50
  "@actions/core": "1.11.1",
53
51
  "@actions/github": "6.0.1",
54
52
  "@agentclientprotocol/sdk": "0.5.1",
@@ -73,7 +71,6 @@
73
71
  "@ai-sdk/xai": "2.0.51",
74
72
  "@clack/prompts": "1.0.0-alpha.1",
75
73
  "@eliseart.ai/plugin": "workspace:*",
76
- "@eliseart.ai/script": "workspace:*",
77
74
  "@eliseart.ai/sdk": "workspace:*",
78
75
  "@eliseart.ai/util": "workspace:*",
79
76
  "@gitlab/gitlab-ai-provider": "3.1.2",
@@ -90,7 +87,6 @@
90
87
  "@pierre/diffs": "catalog:",
91
88
  "@solid-primitives/event-bus": "1.1.2",
92
89
  "@solid-primitives/scheduled": "1.5.2",
93
- "@standard-schema/spec": "1.0.0",
94
90
  "@zip.js/zip.js": "2.7.62",
95
91
  "ai": "catalog:",
96
92
  "bonjour-service": "1.3.0",
@@ -122,6 +118,7 @@
122
118
  "zod": "catalog:",
123
119
  "zod-to-json-schema": "3.24.5"
124
120
  },
121
+ "dependencies": {},
125
122
  "optionalDependencies": {
126
123
  "easc-linux-x64": "0.0.0-main-202601221753",
127
124
  "easc-linux-arm64": "0.0.0-main-202601221753",
@@ -1570,19 +1570,19 @@ function InlineTool(props: {
1570
1570
  }}
1571
1571
  backgroundColor={hover() ? theme.backgroundElement : undefined}
1572
1572
  >
1573
- <text paddingLeft={3} fg={fg()} attributes={denied() ? TextAttributes.STRIKETHROUGH : undefined}>
1574
- <Show
1575
- fallback={
1576
- <box flexDirection="row" gap={1}>
1577
- <Spinner />
1578
- <text fg={fg()}> {props.pending}</text>
1579
- </box>
1580
- }
1581
- when={props.complete}
1582
- >
1573
+ <Show
1574
+ fallback={
1575
+ <box flexDirection="row" gap={1} paddingLeft={3}>
1576
+ <Spinner fg={fg()} />
1577
+ <text fg={fg()} attributes={denied() ? TextAttributes.STRIKETHROUGH : undefined}> {props.pending}</text>
1578
+ </box>
1579
+ }
1580
+ when={props.complete}
1581
+ >
1582
+ <text paddingLeft={3} fg={fg()} attributes={denied() ? TextAttributes.STRIKETHROUGH : undefined}>
1583
1583
  <span style={{ fg: props.iconColor }}>{props.icon}</span> {props.children}
1584
- </Show>
1585
- </text>
1584
+ </text>
1585
+ </Show>
1586
1586
  <Show when={error() && !denied()}>
1587
1587
  <text fg={theme.error}>{error()}</text>
1588
1588
  </Show>