@rune-kit/rune 2.2.4 → 2.3.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 (78) hide show
  1. package/README.md +1 -1
  2. package/compiler/adapters/openclaw.js +63 -0
  3. package/compiler/emitter.js +10 -0
  4. package/docs/EXTENSION-TEMPLATE.md +18 -0
  5. package/docs/SKILL-TEMPLATE.md +46 -0
  6. package/docs/guides/index.html +84 -21
  7. package/docs/index.html +303 -37
  8. package/docs/script.js +236 -18
  9. package/docs/style.css +417 -59
  10. package/extensions/saas/PACK.md +13 -8
  11. package/extensions/saas/skills/billing-integration.md +82 -3
  12. package/package.json +7 -5
  13. package/skills/adversary/SKILL.md +12 -0
  14. package/skills/audit/SKILL.md +64 -1
  15. package/skills/autopsy/SKILL.md +12 -0
  16. package/skills/ba/SKILL.md +63 -1
  17. package/skills/brainstorm/SKILL.md +11 -0
  18. package/skills/completion-gate/SKILL.md +51 -2
  19. package/skills/context-engine/SKILL.md +83 -1
  20. package/skills/context-pack/SKILL.md +160 -0
  21. package/skills/cook/SKILL.md +657 -808
  22. package/skills/cook/references/deviation-rules.md +19 -0
  23. package/skills/cook/references/error-recovery.md +37 -0
  24. package/skills/cook/references/exit-conditions.md +31 -0
  25. package/skills/cook/references/loop-detection.md +39 -0
  26. package/skills/cook/references/mid-run-signals.md +31 -0
  27. package/skills/cook/references/output-format.md +40 -0
  28. package/skills/cook/references/pack-detection.md +82 -0
  29. package/skills/cook/references/pause-resume-template.md +38 -0
  30. package/skills/cook/references/rfc-template.md +52 -0
  31. package/skills/cook/references/sharp-edges.md +24 -0
  32. package/skills/cook/references/subagent-status.md +38 -0
  33. package/skills/db/SKILL.md +12 -0
  34. package/skills/debug/SKILL.md +81 -2
  35. package/skills/deploy/SKILL.md +56 -1
  36. package/skills/design/SKILL.md +9 -0
  37. package/skills/docs/SKILL.md +12 -0
  38. package/skills/docs-seeker/SKILL.md +11 -0
  39. package/skills/fix/SKILL.md +63 -3
  40. package/skills/git/SKILL.md +55 -1
  41. package/skills/incident/SKILL.md +10 -0
  42. package/skills/journal/SKILL.md +51 -3
  43. package/skills/launch/SKILL.md +12 -0
  44. package/skills/logic-guardian/SKILL.md +11 -0
  45. package/skills/marketing/SKILL.md +13 -0
  46. package/skills/mcp-builder/SKILL.md +13 -0
  47. package/skills/onboard/SKILL.md +54 -2
  48. package/skills/perf/SKILL.md +11 -0
  49. package/skills/plan/SKILL.md +342 -629
  50. package/skills/plan/references/completeness-scoring.md +37 -0
  51. package/skills/plan/references/outcome-block.md +41 -0
  52. package/skills/plan/references/plan-templates.md +193 -0
  53. package/skills/plan/references/wave-planning.md +44 -0
  54. package/skills/plan/references/workflow-registry.md +53 -0
  55. package/skills/preflight/SKILL.md +135 -1
  56. package/skills/rescue/SKILL.md +10 -0
  57. package/skills/research/SKILL.md +36 -8
  58. package/skills/retro/SKILL.md +325 -0
  59. package/skills/review/SKILL.md +100 -1
  60. package/skills/review-intake/SKILL.md +11 -0
  61. package/skills/safeguard/SKILL.md +12 -0
  62. package/skills/scaffold/SKILL.md +10 -0
  63. package/skills/scope-guard/SKILL.md +11 -0
  64. package/skills/scout/SKILL.md +9 -0
  65. package/skills/sentinel/SKILL.md +307 -320
  66. package/skills/sentinel/references/config-protection.md +52 -0
  67. package/skills/sentinel/references/destructive-commands.md +40 -0
  68. package/skills/sentinel/references/domain-hooks.md +73 -0
  69. package/skills/sentinel/references/framework-patterns.md +46 -0
  70. package/skills/sentinel/references/owasp-patterns.md +69 -0
  71. package/skills/sentinel/references/secret-patterns.md +40 -0
  72. package/skills/sentinel/references/skill-content-guard.md +55 -0
  73. package/skills/session-bridge/SKILL.md +60 -2
  74. package/skills/skill-forge/SKILL.md +131 -4
  75. package/skills/skill-router/SKILL.md +33 -1
  76. package/skills/surgeon/SKILL.md +12 -0
  77. package/skills/team/SKILL.md +35 -1
  78. package/skills/test/SKILL.md +211 -7
package/docs/script.js CHANGED
@@ -43,9 +43,9 @@
43
43
  const dy = nodes[i].y - nodes[j].y;
44
44
  const dist = Math.sqrt(dx * dx + dy * dy);
45
45
  if (dist < maxDist) {
46
- const alpha = (1 - dist / maxDist) * 0.35;
47
- ctx.strokeStyle = `rgba(16, 185, 129, ${alpha})`;
48
- ctx.lineWidth = 0.6;
46
+ const alpha = (1 - dist / maxDist) * 0.5;
47
+ ctx.strokeStyle = `rgba(60, 85, 50, ${alpha})`;
48
+ ctx.lineWidth = 0.8;
49
49
  ctx.beginPath();
50
50
  ctx.moveTo(nodes[i].x, nodes[i].y);
51
51
  ctx.lineTo(nodes[j].x, nodes[j].y);
@@ -56,7 +56,7 @@
56
56
 
57
57
  // draw nodes
58
58
  for (const n of nodes) {
59
- ctx.fillStyle = 'rgba(16, 185, 129, 0.6)';
59
+ ctx.fillStyle = 'rgba(60, 85, 50, 0.7)';
60
60
  ctx.beginPath();
61
61
  ctx.arc(n.x, n.y, n.r, 0, Math.PI * 2);
62
62
  ctx.fill();
@@ -98,7 +98,7 @@
98
98
  });
99
99
  }, { threshold: 0.1 });
100
100
 
101
- document.querySelectorAll('.layer, .feature-card, .workflow-card, .compare-card, .ext-card, .install-card, .pricing-card, .stat').forEach(el => {
101
+ document.querySelectorAll('.layer, .feature-card, .workflow-card, .compare-card, .ext-card, .install-card, .pricing-card, .stat, .mesh-tier, .mesh-point').forEach(el => {
102
102
  el.style.animationPlayState = 'paused';
103
103
  observer.observe(el);
104
104
  });
@@ -134,29 +134,57 @@
134
134
 
135
135
  // ─── Payment Flow ───
136
136
  const PAY_API = 'https://pay.theio.vn';
137
- const BANK_ID = 'vpbank';
137
+ const BANK_ID = 'tpbank';
138
138
  const BANK_ACCOUNT = '04162263666';
139
- const ACCOUNT_NAME = 'NGUYEN CONG';
139
+ const ACCOUNT_NAME = 'NGUYEN VIET NAM';
140
+
141
+ // Launch promo: 50% off for 7 days
142
+ const PROMO = {
143
+ discount: 0.5,
144
+ endsAt: new Date('2026-03-25T23:59:59+07:00').getTime(),
145
+ };
146
+
147
+ function isPromoActive() {
148
+ return Date.now() < PROMO.endsAt;
149
+ }
150
+
151
+ function fmtVND(n) {
152
+ return n.toLocaleString('vi-VN') + ' VND';
153
+ }
140
154
 
141
155
  const PRODUCT_INFO = {
142
156
  'rune-pro': {
143
157
  title: 'Get Rune Pro', titleShort: 'Rune Pro',
144
- priceVN: '1,190,000 VND', priceIntl: '$49 USD',
145
- amountLabel: '1,190,000 VND (~$49 USD)',
158
+ basePrice: 1190000, baseIntl: 49,
146
159
  btnClass: 'btn-pro',
147
160
  },
148
161
  'rune-biz': {
149
162
  title: 'Get Rune Business', titleShort: 'Rune Business',
150
- priceVN: '3,590,000 VND', priceIntl: '$149 USD',
151
- amountLabel: '3,590,000 VND (~$149 USD)',
163
+ basePrice: 3590000, baseIntl: 149,
152
164
  btnClass: 'btn-biz',
153
165
  },
154
166
  };
155
167
 
168
+ function getProductPricing(key) {
169
+ const info = PRODUCT_INFO[key];
170
+ const promo = isPromoActive();
171
+ const price = promo ? Math.round(info.basePrice * (1 - PROMO.discount)) : info.basePrice;
172
+ const intl = promo ? Math.round(info.baseIntl * (1 - PROMO.discount)) : info.baseIntl;
173
+ return {
174
+ ...info,
175
+ priceVN: fmtVND(price),
176
+ priceIntl: '$' + intl + ' USD',
177
+ amountLabel: fmtVND(price) + ' (~$' + intl + ' USD)',
178
+ promo,
179
+ originalVN: fmtVND(info.basePrice),
180
+ originalIntl: '$' + info.baseIntl + ' USD',
181
+ };
182
+ }
183
+
156
184
  let payState = { product: null, orderCode: null, pollTimer: null };
157
185
 
158
186
  function openPayment(product) {
159
- const info = PRODUCT_INFO[product];
187
+ const info = getProductPricing(product);
160
188
  if (!info) return;
161
189
 
162
190
  payState = { product, orderCode: null, pollTimer: null };
@@ -164,8 +192,17 @@ function openPayment(product) {
164
192
  document.getElementById('pay-title').textContent = info.title;
165
193
  document.getElementById('pay-title-2').textContent = info.title;
166
194
  document.getElementById('pay-amount-2').textContent = info.amountLabel;
167
- document.getElementById('pay-price-vn').textContent = info.priceVN;
168
- document.getElementById('pay-price-intl').textContent = info.priceIntl;
195
+
196
+ const vnPriceEl = document.getElementById('pay-price-vn');
197
+ const intlPriceEl = document.getElementById('pay-price-intl');
198
+ if (info.promo) {
199
+ vnPriceEl.innerHTML = '<s style="opacity:.5">' + info.originalVN + '</s> ' + info.priceVN;
200
+ intlPriceEl.innerHTML = '<s style="opacity:.5">' + info.originalIntl + '</s> ' + info.priceIntl;
201
+ } else {
202
+ vnPriceEl.textContent = info.priceVN;
203
+ intlPriceEl.textContent = info.priceIntl;
204
+ }
205
+
169
206
  document.getElementById('pay-github').value = '';
170
207
  document.getElementById('pay-email').value = '';
171
208
  document.getElementById('pay-error').hidden = true;
@@ -190,8 +227,9 @@ function closePayment() {
190
227
  }
191
228
 
192
229
  function showPayStep(n) {
193
- for (let i = 1; i <= 4; i++) {
194
- document.getElementById('pay-step-' + i).hidden = (i !== n);
230
+ for (let i = 1; i <= 6; i++) {
231
+ const el = document.getElementById('pay-step-' + i);
232
+ if (el) el.hidden = (i !== n);
195
233
  }
196
234
  }
197
235
 
@@ -200,6 +238,70 @@ function showVNPayment() {
200
238
  document.getElementById('pay-github').focus();
201
239
  }
202
240
 
241
+ function showIntlPayment() {
242
+ const info = getProductPricing(payState.product);
243
+ document.getElementById('pay-title-5').textContent = info.title;
244
+ document.getElementById('pay-amount-5').textContent = info.priceIntl;
245
+ document.getElementById('pay-intl-github').value = '';
246
+ document.getElementById('pay-intl-email').value = '';
247
+ document.getElementById('pay-intl-error').hidden = true;
248
+
249
+ const btn = document.getElementById('pay-intl-submit');
250
+ btn.className = 'btn ' + info.btnClass;
251
+ btn.style.width = '100%';
252
+ btn.style.marginTop = '16px';
253
+
254
+ showPayStep(5);
255
+ document.getElementById('pay-intl-github').focus();
256
+ }
257
+
258
+ async function startPolarCheckout() {
259
+ const github = document.getElementById('pay-intl-github').value.trim();
260
+ const email = document.getElementById('pay-intl-email').value.trim();
261
+ const errorEl = document.getElementById('pay-intl-error');
262
+
263
+ if (!github) {
264
+ errorEl.textContent = 'Please enter your GitHub username';
265
+ errorEl.hidden = false;
266
+ return;
267
+ }
268
+
269
+ if (!/^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}$/.test(github)) {
270
+ errorEl.textContent = 'Invalid GitHub username format';
271
+ errorEl.hidden = false;
272
+ return;
273
+ }
274
+
275
+ errorEl.hidden = true;
276
+ const btn = document.getElementById('pay-intl-submit');
277
+ btn.disabled = true;
278
+ btn.textContent = 'Redirecting to checkout...';
279
+
280
+ try {
281
+ const res = await fetch(PAY_API + '/checkout/polar', {
282
+ method: 'POST',
283
+ headers: { 'Content-Type': 'application/json' },
284
+ body: JSON.stringify({
285
+ product: payState.product,
286
+ githubUsername: github,
287
+ email: email || undefined,
288
+ }),
289
+ });
290
+
291
+ const data = await res.json();
292
+ if (!data.success || !data.url) throw new Error(data.error || 'Failed to create checkout');
293
+
294
+ // Redirect to Polar checkout page (context embedded in success_url by worker)
295
+ window.location.href = data.url;
296
+ } catch (err) {
297
+ errorEl.textContent = err.message;
298
+ errorEl.hidden = false;
299
+ } finally {
300
+ btn.disabled = false;
301
+ btn.textContent = 'Pay with Card / PayPal';
302
+ }
303
+ }
304
+
203
305
  async function createOrder() {
204
306
  const github = document.getElementById('pay-github').value.trim();
205
307
  const email = document.getElementById('pay-email').value.trim();
@@ -264,8 +366,14 @@ function startPolling(github) {
264
366
  if (data.status === 'delivered') {
265
367
  clearInterval(payState.pollTimer);
266
368
  payState.pollTimer = null;
267
- document.getElementById('pay-success-user').textContent = github;
268
- showPayStep(4);
369
+ // VN users → Vietnamese success (step 6)
370
+ const vnUser = document.getElementById('pay-success-user-vn');
371
+ if (vnUser) vnUser.textContent = github;
372
+ const vnInstall = document.getElementById('pay-success-install-vn');
373
+ if (vnInstall && (payState.product === 'rune-biz' || payState.product === 'RUNE-BIZ')) {
374
+ vnInstall.textContent = 'Bạn nhận cả Pro + Business packs — xem README trong repo';
375
+ }
376
+ showPayStep(6);
269
377
  } else if (data.status === 'underpaid') {
270
378
  document.getElementById('pay-status').innerHTML =
271
379
  '<span style="color:var(--loss)">&#9888; Amount too low. Please transfer the exact amount.</span>';
@@ -275,3 +383,113 @@ function startPolling(github) {
275
383
  }
276
384
  }, 5000);
277
385
  }
386
+
387
+ // ─── Promo Countdown ───
388
+ (function initPromoCountdown() {
389
+ if (!isPromoActive()) return;
390
+
391
+ // Add "50% OFF" ribbon to Pro and Business cards
392
+ ['.pricing-pro', '.pricing-biz'].forEach(sel => {
393
+ const card = document.querySelector(sel);
394
+ if (!card) return;
395
+ const ribbon = document.createElement('div');
396
+ ribbon.className = 'promo-ribbon';
397
+ ribbon.textContent = '50% OFF';
398
+ card.appendChild(ribbon);
399
+ });
400
+
401
+ // Update pricing cards with promo prices + save badge
402
+ const proCard = document.querySelector('.pricing-pro .pricing-price');
403
+ const bizCard = document.querySelector('.pricing-biz .pricing-price');
404
+ if (proCard) proCard.innerHTML = '<s style="opacity:.35;font-size:.55em">$49</s> $25<span class="pricing-period"> lifetime</span><br><span class="promo-save">Save $24</span>';
405
+ if (bizCard) bizCard.innerHTML = '<s style="opacity:.35;font-size:.55em">$149</s> $75<span class="pricing-period"> lifetime</span><br><span class="promo-save">Save $74</span>';
406
+
407
+ // Update "What's Included" values in Business card
408
+ document.querySelectorAll('.includes-value').forEach(el => {
409
+ if (el.textContent.includes('$49')) el.innerHTML = '<s>$49</s> $25 value';
410
+ if (el.textContent.includes('$100')) el.innerHTML = '<s>$100</s> $50 value';
411
+ });
412
+
413
+ // Update buttons
414
+ const proBtn = document.querySelector('.pricing-pro .btn-pro');
415
+ const bizBtn = document.querySelector('.pricing-biz .btn-biz');
416
+ if (proBtn) proBtn.innerHTML = 'Get Rune Pro &mdash; <s style="opacity:.6">$49</s>&nbsp;$25';
417
+ if (bizBtn) bizBtn.innerHTML = 'Get Rune Business &mdash; <s style="opacity:.6">$149</s>&nbsp;$75';
418
+
419
+ // Update comparison table
420
+ document.querySelectorAll('.table-price').forEach(el => {
421
+ if (el.textContent.includes('$49')) el.innerHTML = '<s style="opacity:.5">$49</s>&nbsp;$25';
422
+ if (el.textContent.includes('$149')) el.innerHTML = '<s style="opacity:.5">$149</s>&nbsp;$75';
423
+ });
424
+
425
+ // Create countdown banner (sticky bottom)
426
+ const banner = document.createElement('div');
427
+ banner.id = 'promo-banner';
428
+ banner.style.cssText = `
429
+ position:fixed;bottom:0;left:0;right:0;z-index:9999;
430
+ background:linear-gradient(135deg,#4a6843 0%,#5b7852 50%,#7a9e6e 100%);
431
+ color:#fff;text-align:center;padding:10px 16px;
432
+ font:600 14px/1.4 "Space Grotesk",sans-serif;
433
+ display:flex;align-items:center;justify-content:center;gap:16px;
434
+ box-shadow:0 -4px 20px rgba(91,120,82,.2);
435
+ `.replace(/\n\s+/g, '');
436
+ banner.innerHTML = ''
437
+ + '<span style="font-size:18px">&#9889;</span>'
438
+ + '<span><strong>Launch Week</strong> &mdash; 50% OFF all paid packs</span>'
439
+ + '<span id="promo-timer" style="font-family:JetBrains Mono,monospace;font-weight:700;background:rgba(0,0,0,.2);padding:5px 12px;border-radius:6px;letter-spacing:.5px;min-width:150px"></span>'
440
+ + '<a href="#pricing" style="background:#f5f0e8;color:#4a6843;text-decoration:none;font-weight:700;padding:6px 16px;border-radius:6px;font-size:13px;white-space:nowrap">Grab the deal &rarr;</a>';
441
+ document.body.appendChild(banner);
442
+ document.body.style.paddingBottom = '52px';
443
+
444
+ function tick() {
445
+ const diff = PROMO.endsAt - Date.now();
446
+ if (diff <= 0) { banner.remove(); document.body.style.paddingBottom = ''; return; }
447
+ const d = Math.floor(diff / 86400000);
448
+ const h = Math.floor((diff % 86400000) / 3600000);
449
+ const m = Math.floor((diff % 3600000) / 60000);
450
+ const s = Math.floor((diff % 60000) / 1000);
451
+ const timer = document.getElementById('promo-timer');
452
+ if (timer) timer.textContent = d + 'd ' + h + 'h ' + m + 'm ' + s + 's';
453
+ }
454
+ tick();
455
+ setInterval(tick, 1000);
456
+ })();
457
+
458
+ // ─── Polar Success Return ───
459
+ (function checkPolarReturn() {
460
+ const params = new URLSearchParams(window.location.search);
461
+ if (params.get('polar') === 'success') {
462
+ // Read context from URL (embedded by worker in success_url)
463
+ const github = params.get('gh') || 'your GitHub account';
464
+ const product = params.get('pkg') || '';
465
+
466
+ // Clean URL
467
+ window.history.replaceState({}, '', window.location.pathname);
468
+
469
+ // Show success message
470
+ const modal = document.getElementById('pay-modal');
471
+ if (modal) {
472
+ modal.hidden = false;
473
+ document.body.style.overflow = 'hidden';
474
+ showSuccessForProduct(product, github);
475
+ for (let i = 1; i <= 5; i++) {
476
+ document.getElementById('pay-step-' + i).hidden = (i !== 4);
477
+ }
478
+ }
479
+ }
480
+ })();
481
+
482
+ // Update success page based on product context
483
+ function showSuccessForProduct(product, github) {
484
+ const el = document.getElementById('pay-success-user');
485
+ if (el) el.textContent = github || 'your GitHub account';
486
+
487
+ const installEl = document.getElementById('pay-success-install');
488
+ if (!installEl) return;
489
+
490
+ if (product === 'rune-biz' || product === 'RUNE-BIZ') {
491
+ installEl.textContent = 'You get Pro + Business packs — check the repo README for setup';
492
+ } else {
493
+ installEl.textContent = 'Follow the setup guide in the repo README';
494
+ }
495
+ }