@rogatio/cli 5.0.0 → 5.1.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.
@@ -214,6 +214,353 @@ var HTTP_METHODS = Object.freeze([
214
214
  "TRACE"
215
215
  ]);
216
216
 
217
+ // packages/editor/src/ai-assist-panel.ts
218
+ function createAIAssistPanel(_container, _editor, onApply, onClose) {
219
+ let visible = false;
220
+ let streamingContent = "";
221
+ let streamingMessageIndex = -1;
222
+ const messages = [];
223
+ const panel = document.createElement("div");
224
+ panel.className = "ai-assist-panel";
225
+ panel.style.cssText = `
226
+ position: fixed;
227
+ top: 0;
228
+ right: 0;
229
+ bottom: 0;
230
+ width: 400px;
231
+ max-width: 100vw;
232
+ background: #1e1e24;
233
+ border-left: 1px solid #333;
234
+ display: flex;
235
+ flex-direction: column;
236
+ z-index: 1000;
237
+ transform: translateX(100%);
238
+ transition: transform 0.2s ease;
239
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
240
+ font-size: 13px;
241
+ color: #e0e0e0;
242
+ `;
243
+ const header = document.createElement("div");
244
+ header.style.cssText = `
245
+ padding: 12px 16px;
246
+ border-bottom: 1px solid #333;
247
+ display: flex;
248
+ align-items: center;
249
+ justify-content: space-between;
250
+ background: #15151a;
251
+ `;
252
+ header.innerHTML = `
253
+ <div style="display: flex; align-items: center; gap: 8px;">
254
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
255
+ <path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8z"/>
256
+ <path d="M12 6v6l4 2"/>
257
+ </svg>
258
+ <span style="font-weight: 600;">AI Assist</span>
259
+ </div>
260
+ <button class="ai-close-btn" style="
261
+ background: none;
262
+ border: none;
263
+ color: #888;
264
+ cursor: pointer;
265
+ padding: 4px;
266
+ border-radius: 4px;
267
+ ">
268
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
269
+ <line x1="18" y1="6" x2="6" y2="18"/>
270
+ <line x1="6" y1="6" x2="18" y2="18"/>
271
+ </svg>
272
+ </button>
273
+ `;
274
+ const messagesContainer = document.createElement("div");
275
+ messagesContainer.style.cssText = `
276
+ flex: 1;
277
+ overflow-y: auto;
278
+ padding: 16px;
279
+ display: flex;
280
+ flex-direction: column;
281
+ gap: 12px;
282
+ `;
283
+ const inputContainer = document.createElement("div");
284
+ inputContainer.style.cssText = `
285
+ padding: 12px 16px;
286
+ border-top: 1px solid #333;
287
+ background: #15151a;
288
+ `;
289
+ const inputWrapper = document.createElement("div");
290
+ inputWrapper.style.cssText = `
291
+ display: flex;
292
+ gap: 8px;
293
+ margin-bottom: 8px;
294
+ `;
295
+ const textarea = document.createElement("textarea");
296
+ textarea.placeholder = "Ask AI to generate rules, fix issues, or explain...";
297
+ textarea.style.cssText = `
298
+ flex: 1;
299
+ background: #2a2a34;
300
+ border: 1px solid #3a3a48;
301
+ border-radius: 8px;
302
+ padding: 10px 12px;
303
+ color: #e0e0e0;
304
+ font-family: inherit;
305
+ font-size: 13px;
306
+ resize: none;
307
+ min-height: 60px;
308
+ max-height: 150px;
309
+ outline: none;
310
+ `;
311
+ const sendButton = document.createElement("button");
312
+ sendButton.textContent = "Send";
313
+ sendButton.style.cssText = `
314
+ background: #3b82f6;
315
+ color: white;
316
+ border: none;
317
+ border-radius: 8px;
318
+ padding: 10px 20px;
319
+ font-weight: 600;
320
+ cursor: pointer;
321
+ align-self: flex-end;
322
+ transition: background 0.2s;
323
+ `;
324
+ const statusText = document.createElement("div");
325
+ statusText.style.cssText = `
326
+ font-size: 11px;
327
+ color: #666;
328
+ text-align: center;
329
+ `;
330
+ inputWrapper.appendChild(textarea);
331
+ inputWrapper.appendChild(sendButton);
332
+ inputContainer.appendChild(inputWrapper);
333
+ inputContainer.appendChild(statusText);
334
+ panel.appendChild(header);
335
+ panel.appendChild(messagesContainer);
336
+ panel.appendChild(inputContainer);
337
+ const closeBtn = header.querySelector(".ai-close-btn");
338
+ function show() {
339
+ if (!visible) {
340
+ visible = true;
341
+ document.body.appendChild(panel);
342
+ requestAnimationFrame(() => {
343
+ panel.style.transform = "translateX(0)";
344
+ });
345
+ textarea.focus();
346
+ }
347
+ }
348
+ function hide() {
349
+ if (visible) {
350
+ visible = false;
351
+ panel.style.transform = "translateX(100%)";
352
+ setTimeout(() => {
353
+ if (!visible && panel.parentNode) {
354
+ panel.parentNode.removeChild(panel);
355
+ }
356
+ }, 200);
357
+ onClose();
358
+ }
359
+ }
360
+ function isVisible() {
361
+ return visible;
362
+ }
363
+ function addMessage(message) {
364
+ const messageEl = document.createElement("div");
365
+ messageEl.style.cssText = `
366
+ display: flex;
367
+ flex-direction: column;
368
+ gap: 8px;
369
+ max-width: 85%;
370
+ ${message.role === "user" ? "align-self: flex-end;" : "align-self: flex-start;"}
371
+ `;
372
+ const bubble = document.createElement("div");
373
+ bubble.style.cssText = `
374
+ padding: 10px 14px;
375
+ border-radius: 16px;
376
+ ${message.role === "user" ? "background: #3b82f6; color: white; border-bottom-right-radius: 4px;" : "background: #2a2a34; color: #e0e0e0; border-bottom-left-radius: 4px;"}
377
+ white-space: pre-wrap;
378
+ word-wrap: break-word;
379
+ `;
380
+ bubble.textContent = message.content;
381
+ messageEl.appendChild(bubble);
382
+ if (message.proposal) {
383
+ const proposalEl = createProposalElement(message.proposal);
384
+ messageEl.appendChild(proposalEl);
385
+ }
386
+ messagesContainer.appendChild(messageEl);
387
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
388
+ }
389
+ function createProposalElement(proposal) {
390
+ const container = document.createElement("div");
391
+ container.style.cssText = `
392
+ margin-top: 8px;
393
+ padding: 12px;
394
+ background: #1a1a24;
395
+ border: 1px solid #333;
396
+ border-radius: 8px;
397
+ `;
398
+ const explanation = document.createElement("div");
399
+ explanation.style.cssText = `
400
+ font-size: 12px;
401
+ color: #aaa;
402
+ margin-bottom: 12px;
403
+ line-height: 1.5;
404
+ `;
405
+ explanation.textContent = proposal.explanation;
406
+ container.appendChild(explanation);
407
+ const rulesList = document.createElement("div");
408
+ rulesList.style.cssText = `
409
+ display: flex;
410
+ flex-direction: column;
411
+ gap: 8px;
412
+ `;
413
+ for (const rule of proposal.rules) {
414
+ const ruleEl = document.createElement("div");
415
+ ruleEl.style.cssText = `
416
+ padding: 10px;
417
+ background: #2a2a34;
418
+ border-radius: 6px;
419
+ border: 1px solid #3a3a48;
420
+ `;
421
+ const ruleHeader = document.createElement("div");
422
+ ruleHeader.style.cssText = `
423
+ display: flex;
424
+ align-items: center;
425
+ gap: 8px;
426
+ margin-bottom: 8px;
427
+ `;
428
+ const kindBadge = document.createElement("span");
429
+ kindBadge.textContent = rule.kind;
430
+ kindBadge.style.cssText = `
431
+ font-size: 10px;
432
+ font-weight: 600;
433
+ text-transform: uppercase;
434
+ padding: 2px 8px;
435
+ border-radius: 4px;
436
+ background: #3b82f6;
437
+ color: white;
438
+ `;
439
+ const ruleName = document.createElement("span");
440
+ ruleName.textContent = rule.name;
441
+ ruleName.style.cssText = `
442
+ font-weight: 500;
443
+ flex: 1;
444
+ `;
445
+ ruleHeader.appendChild(kindBadge);
446
+ ruleHeader.appendChild(ruleName);
447
+ const ruleDetails = document.createElement("div");
448
+ ruleDetails.style.cssText = `
449
+ font-size: 11px;
450
+ color: #888;
451
+ display: grid;
452
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
453
+ gap: 4px 12px;
454
+ `;
455
+ const addDetail = (label, value) => {
456
+ const detail = document.createElement("div");
457
+ detail.innerHTML = `<span style="color:#666;">${label}:</span> ${value}`;
458
+ ruleDetails.appendChild(detail);
459
+ };
460
+ addDetail("Regex", rule.urlRegex);
461
+ if (rule.origins?.length) addDetail("Origins", rule.origins.join(", "));
462
+ if (rule.resourceTypes?.length)
463
+ addDetail("Types", rule.resourceTypes.join(", "));
464
+ if (rule.priority !== void 0)
465
+ addDetail("Priority", rule.priority.toString());
466
+ if (rule.method) addDetail("Method", rule.method);
467
+ const actionBtn = document.createElement("button");
468
+ actionBtn.textContent = "Apply Rule";
469
+ actionBtn.style.cssText = `
470
+ margin-top: 10px;
471
+ width: 100%;
472
+ background: #22c55e;
473
+ color: white;
474
+ border: none;
475
+ border-radius: 6px;
476
+ padding: 8px;
477
+ font-weight: 600;
478
+ cursor: pointer;
479
+ transition: background 0.2s;
480
+ `;
481
+ actionBtn.addEventListener("click", () => {
482
+ onApply(proposal);
483
+ });
484
+ ruleEl.appendChild(ruleHeader);
485
+ ruleEl.appendChild(ruleDetails);
486
+ ruleEl.appendChild(actionBtn);
487
+ rulesList.appendChild(ruleEl);
488
+ }
489
+ container.appendChild(rulesList);
490
+ return container;
491
+ }
492
+ function clearMessages() {
493
+ messages.length = 0;
494
+ streamingContent = "";
495
+ streamingMessageIndex = -1;
496
+ messagesContainer.innerHTML = "";
497
+ }
498
+ function updateStreamingContent(content) {
499
+ if (streamingMessageIndex >= 0 && streamingMessageIndex < messages.length) {
500
+ const message = messages[streamingMessageIndex];
501
+ message.content = streamingContent + content;
502
+ const bubbles = messagesContainer.querySelectorAll(
503
+ "div > div:first-child"
504
+ );
505
+ if (bubbles[streamingMessageIndex]) {
506
+ bubbles[streamingMessageIndex].textContent = message.content;
507
+ }
508
+ }
509
+ }
510
+ function startStreaming(role) {
511
+ streamingContent = "";
512
+ const message = { role, content: "", isStreaming: true };
513
+ messages.push(message);
514
+ streamingMessageIndex = messages.length - 1;
515
+ addMessage(message);
516
+ }
517
+ function finishStreaming(proposal) {
518
+ if (streamingMessageIndex >= 0 && streamingMessageIndex < messages.length) {
519
+ const message = messages[streamingMessageIndex];
520
+ message.isStreaming = false;
521
+ if (proposal) message.proposal = proposal;
522
+ const messageEls = messagesContainer.children;
523
+ if (messageEls[streamingMessageIndex]) {
524
+ const existingProposal = messageEls[streamingMessageIndex].querySelector("div > div:last-child");
525
+ if (proposal) {
526
+ if (existingProposal) existingProposal.remove();
527
+ const proposalEl = createProposalElement(proposal);
528
+ messageEls[streamingMessageIndex].appendChild(
529
+ proposalEl
530
+ );
531
+ }
532
+ }
533
+ }
534
+ streamingContent = "";
535
+ streamingMessageIndex = -1;
536
+ }
537
+ function handleSend() {
538
+ const prompt = textarea.value.trim();
539
+ if (!prompt) return;
540
+ textarea.value = "";
541
+ textarea.style.height = "auto";
542
+ }
543
+ closeBtn.addEventListener("click", hide);
544
+ sendButton.addEventListener("click", handleSend);
545
+ textarea.addEventListener("keydown", (e) => {
546
+ if (e.key === "Enter" && !e.shiftKey) {
547
+ e.preventDefault();
548
+ handleSend();
549
+ }
550
+ });
551
+ return {
552
+ show,
553
+ hide,
554
+ isVisible,
555
+ addMessage,
556
+ clearMessages,
557
+ // Expose streaming methods for the aiAssist handler to use
558
+ startStreaming,
559
+ updateStreamingContent,
560
+ finishStreaming
561
+ };
562
+ }
563
+
217
564
  // packages/editor/src/rule-types/mock.ts
218
565
  function isRecord(value) {
219
566
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -340,7 +687,7 @@ function createMockRuleType() {
340
687
  return stable(diagnostics);
341
688
  },
342
689
  mount(context) {
343
- const { document, container } = context;
690
+ const { document: document2, container } = context;
344
691
  const getCurrent = () => asMockAction(context.getField("mock"));
345
692
  const setAction = (next) => {
346
693
  context.setField("mock", next);
@@ -349,9 +696,9 @@ function createMockRuleType() {
349
696
  const current = getCurrent();
350
697
  container.replaceChildren();
351
698
  if (current === void 0) return;
352
- const statusLabel = document.createElement("label");
699
+ const statusLabel = document2.createElement("label");
353
700
  statusLabel.textContent = "Status";
354
- const statusInput = document.createElement("input");
701
+ const statusInput = document2.createElement("input");
355
702
  statusInput.type = "number";
356
703
  statusInput.min = String(LIMITS.minMockStatus);
357
704
  statusInput.max = String(LIMITS.maxMockStatus);
@@ -365,9 +712,9 @@ function createMockRuleType() {
365
712
  });
366
713
  context.registerControl("/mock/status", statusInput);
367
714
  statusLabel.append(statusInput);
368
- const delayLabel = document.createElement("label");
715
+ const delayLabel = document2.createElement("label");
369
716
  delayLabel.textContent = "Delay (ms)";
370
- const delayInput = document.createElement("input");
717
+ const delayInput = document2.createElement("input");
371
718
  delayInput.type = "number";
372
719
  delayInput.min = "0";
373
720
  delayInput.max = String(LIMITS.maxMockDelayMs);
@@ -383,20 +730,20 @@ function createMockRuleType() {
383
730
  });
384
731
  context.registerControl("/mock/delayMs", delayInput);
385
732
  delayLabel.append(delayInput);
386
- const sourceLabel = document.createElement("label");
733
+ const sourceLabel = document2.createElement("label");
387
734
  sourceLabel.textContent = "Body source";
388
- const sourceSelect = document.createElement("select");
735
+ const sourceSelect = document2.createElement("select");
389
736
  sourceSelect.dataset.editorField = "true";
390
- const bodyOption = document.createElement("option");
737
+ const bodyOption = document2.createElement("option");
391
738
  bodyOption.value = "body";
392
739
  bodyOption.textContent = "Inline body";
393
- const fileOption = document.createElement("option");
740
+ const fileOption = document2.createElement("option");
394
741
  fileOption.value = "file";
395
742
  fileOption.textContent = "File snapshot";
396
743
  sourceSelect.append(bodyOption, fileOption);
397
744
  sourceSelect.value = typeof current.file === "string" ? "file" : "body";
398
745
  context.registerControl("/mock/body-source", sourceSelect);
399
- const bodyArea = document.createElement("textarea");
746
+ const bodyArea = document2.createElement("textarea");
400
747
  bodyArea.value = typeof current.body === "string" ? current.body : "";
401
748
  bodyArea.dataset.editorField = "true";
402
749
  bodyArea.addEventListener("input", () => {
@@ -405,9 +752,9 @@ function createMockRuleType() {
405
752
  setAction({ ...c, body: bodyArea.value, file: void 0 });
406
753
  });
407
754
  context.registerControl("/mock/body", bodyArea);
408
- const fileLabel = document.createElement("label");
755
+ const fileLabel = document2.createElement("label");
409
756
  fileLabel.textContent = "File path";
410
- const fileInput = document.createElement("input");
757
+ const fileInput = document2.createElement("input");
411
758
  fileInput.type = "text";
412
759
  fileInput.value = typeof current.file === "string" ? current.file : "";
413
760
  fileInput.dataset.editorField = "true";
@@ -425,8 +772,8 @@ function createMockRuleType() {
425
772
  };
426
773
  sourceSelect.addEventListener("change", syncSource);
427
774
  syncSource();
428
- const headersFieldset = document.createElement("fieldset");
429
- const headersLegend = document.createElement("legend");
775
+ const headersFieldset = document2.createElement("fieldset");
776
+ const headersLegend = document2.createElement("legend");
430
777
  headersLegend.textContent = "Response headers";
431
778
  headersFieldset.append(headersLegend);
432
779
  const renderHeaders = () => {
@@ -437,11 +784,11 @@ function createMockRuleType() {
437
784
  });
438
785
  const headers = c.headers ?? [];
439
786
  headers.forEach((header, index) => {
440
- const row = document.createElement("div");
787
+ const row = document2.createElement("div");
441
788
  row.dataset.mockHeaderRow = String(index);
442
- const nameLabel = document.createElement("label");
789
+ const nameLabel = document2.createElement("label");
443
790
  nameLabel.textContent = "Name";
444
- const nameInput = document.createElement("input");
791
+ const nameInput = document2.createElement("input");
445
792
  nameInput.type = "text";
446
793
  nameInput.value = header.name;
447
794
  nameInput.dataset.editorField = "true";
@@ -455,9 +802,9 @@ function createMockRuleType() {
455
802
  });
456
803
  context.registerControl(`/mock/headers/${index}/name`, nameInput);
457
804
  nameLabel.append(nameInput);
458
- const valueLabel = document.createElement("label");
805
+ const valueLabel = document2.createElement("label");
459
806
  valueLabel.textContent = "Value";
460
- const valueInput = document.createElement("input");
807
+ const valueInput = document2.createElement("input");
461
808
  valueInput.type = "text";
462
809
  valueInput.value = header.value;
463
810
  valueInput.dataset.editorField = "true";
@@ -471,7 +818,7 @@ function createMockRuleType() {
471
818
  });
472
819
  context.registerControl(`/mock/headers/${index}/value`, valueInput);
473
820
  valueLabel.append(valueInput);
474
- const remove = document.createElement("button");
821
+ const remove = document2.createElement("button");
475
822
  remove.type = "button";
476
823
  remove.textContent = "Remove";
477
824
  remove.dataset.editorField = "true";
@@ -484,7 +831,7 @@ function createMockRuleType() {
484
831
  row.append(nameLabel, valueLabel, remove);
485
832
  headersFieldset.append(row);
486
833
  });
487
- const add = document.createElement("button");
834
+ const add = document2.createElement("button");
488
835
  add.type = "button";
489
836
  add.textContent = "Add header";
490
837
  add.dataset.editorField = "true";
@@ -612,7 +959,7 @@ var queryRuleType = {
612
959
  return stable2(diagnostics);
613
960
  },
614
961
  mount(context) {
615
- const { document, container } = context;
962
+ const { document: document2, container } = context;
616
963
  const getCurrent = () => asQueryAction(context.getField("action"));
617
964
  const setAction = (next) => {
618
965
  context.setField("action", next);
@@ -622,11 +969,11 @@ var queryRuleType = {
622
969
  container.replaceChildren();
623
970
  if (current === void 0) return;
624
971
  current.params.forEach((param, index) => {
625
- const row = document.createElement("div");
972
+ const row = document2.createElement("div");
626
973
  row.dataset.queryParamRow = String(index);
627
- const nameLabel = document.createElement("label");
974
+ const nameLabel = document2.createElement("label");
628
975
  nameLabel.textContent = "Name";
629
- const nameInput = document.createElement("input");
976
+ const nameInput = document2.createElement("input");
630
977
  nameInput.type = "text";
631
978
  nameInput.value = param.name;
632
979
  nameInput.dataset.editorField = "true";
@@ -640,9 +987,9 @@ var queryRuleType = {
640
987
  });
641
988
  context.registerControl(`/action/params/${index}/name`, nameInput);
642
989
  nameLabel.append(nameInput);
643
- const valueLabel = document.createElement("label");
990
+ const valueLabel = document2.createElement("label");
644
991
  valueLabel.textContent = "Value";
645
- const valueInput = document.createElement("input");
992
+ const valueInput = document2.createElement("input");
646
993
  valueInput.type = "text";
647
994
  valueInput.value = param.value;
648
995
  valueInput.dataset.editorField = "true";
@@ -656,7 +1003,7 @@ var queryRuleType = {
656
1003
  });
657
1004
  context.registerControl(`/action/params/${index}/value`, valueInput);
658
1005
  valueLabel.append(valueInput);
659
- const remove = document.createElement("button");
1006
+ const remove = document2.createElement("button");
660
1007
  remove.type = "button";
661
1008
  remove.textContent = "Remove";
662
1009
  remove.dataset.editorField = "true";
@@ -669,7 +1016,7 @@ var queryRuleType = {
669
1016
  row.append(nameLabel, valueLabel, remove);
670
1017
  container.append(row);
671
1018
  });
672
- const add = document.createElement("button");
1019
+ const add = document2.createElement("button");
673
1020
  add.type = "button";
674
1021
  add.textContent = "Add parameter";
675
1022
  add.dataset.editorField = "true";
@@ -834,17 +1181,17 @@ function createRequestBodyRuleType() {
834
1181
  return stable3(diagnostics);
835
1182
  },
836
1183
  mount(context) {
837
- const { document, container } = context;
1184
+ const { document: document2, container } = context;
838
1185
  const render = () => {
839
1186
  const current = requestBodyOf(context.getField("requestBody"));
840
1187
  container.replaceChildren();
841
1188
  if (current === void 0) return;
842
- const modeSelect = document.createElement("select");
1189
+ const modeSelect = document2.createElement("select");
843
1190
  modeSelect.value = current.mode;
844
- const replaceOption = document.createElement("option");
1191
+ const replaceOption = document2.createElement("option");
845
1192
  replaceOption.value = "replace";
846
1193
  replaceOption.textContent = "Replace body";
847
- const regexOption = document.createElement("option");
1194
+ const regexOption = document2.createElement("option");
848
1195
  regexOption.value = "regex";
849
1196
  regexOption.textContent = "Regex replace";
850
1197
  modeSelect.append(replaceOption, regexOption);
@@ -862,7 +1209,7 @@ function createRequestBodyRuleType() {
862
1209
  context.registerControl("/requestBody/mode", modeSelect);
863
1210
  container.append(modeSelect);
864
1211
  if (current.mode === "replace") {
865
- const bodyInput = document.createElement("textarea");
1212
+ const bodyInput = document2.createElement("textarea");
866
1213
  bodyInput.value = current.body ?? "";
867
1214
  bodyInput.placeholder = "Replacement body";
868
1215
  bodyInput.addEventListener("input", () => {
@@ -872,7 +1219,7 @@ function createRequestBodyRuleType() {
872
1219
  context.registerControl("/requestBody/body", bodyInput);
873
1220
  container.append(bodyInput);
874
1221
  } else {
875
- const patternInput = document.createElement("input");
1222
+ const patternInput = document2.createElement("input");
876
1223
  patternInput.type = "text";
877
1224
  patternInput.value = current.pattern ?? "";
878
1225
  patternInput.placeholder = "Regex pattern";
@@ -882,7 +1229,7 @@ function createRequestBodyRuleType() {
882
1229
  });
883
1230
  context.registerControl("/requestBody/pattern", patternInput);
884
1231
  container.append(patternInput);
885
- const replacementInput = document.createElement("input");
1232
+ const replacementInput = document2.createElement("input");
886
1233
  replacementInput.type = "text";
887
1234
  replacementInput.value = current.replacement ?? "";
888
1235
  replacementInput.placeholder = "Replacement";
@@ -964,15 +1311,15 @@ function createResponseBodyRuleType() {
964
1311
  return stable4(diagnostics);
965
1312
  },
966
1313
  mount(context) {
967
- const { document, container } = context;
1314
+ const { document: document2, container } = context;
968
1315
  const render = () => {
969
1316
  const current = replacementsOf(context.getField("responseBody"));
970
1317
  container.replaceChildren();
971
1318
  if (current === void 0) return;
972
1319
  current.forEach((entry, index) => {
973
- const row = document.createElement("div");
1320
+ const row = document2.createElement("div");
974
1321
  row.dataset.responseBodyReplacement = String(index);
975
- const pattern = document.createElement("input");
1322
+ const pattern = document2.createElement("input");
976
1323
  pattern.type = "text";
977
1324
  pattern.value = entry.pattern;
978
1325
  pattern.placeholder = "Pattern";
@@ -987,7 +1334,7 @@ function createResponseBodyRuleType() {
987
1334
  `/responseBody/replacements/${index}/pattern`,
988
1335
  pattern
989
1336
  );
990
- const replacement = document.createElement("input");
1337
+ const replacement = document2.createElement("input");
991
1338
  replacement.type = "text";
992
1339
  replacement.value = entry.replacement;
993
1340
  replacement.placeholder = "Replacement";
@@ -1002,7 +1349,7 @@ function createResponseBodyRuleType() {
1002
1349
  `/responseBody/replacements/${index}/replacement`,
1003
1350
  replacement
1004
1351
  );
1005
- const remove = document.createElement("button");
1352
+ const remove = document2.createElement("button");
1006
1353
  remove.type = "button";
1007
1354
  remove.textContent = "Remove replacement";
1008
1355
  remove.addEventListener("click", () => {
@@ -1013,7 +1360,7 @@ function createResponseBodyRuleType() {
1013
1360
  row.append(pattern, replacement, remove);
1014
1361
  container.append(row);
1015
1362
  });
1016
- const add = document.createElement("button");
1363
+ const add = document2.createElement("button");
1017
1364
  add.type = "button";
1018
1365
  add.textContent = "Add replacement";
1019
1366
  add.addEventListener("click", () => {
@@ -1463,6 +1810,7 @@ var EditorControllerImpl = class {
1463
1810
  testResult = void 0;
1464
1811
  testRunning = false;
1465
1812
  testRequestId = 0;
1813
+ aiAssistPanel = null;
1466
1814
  constructor(options, initial, extensions) {
1467
1815
  this.root = options.root;
1468
1816
  this.document = options.root.ownerDocument;
@@ -1475,6 +1823,19 @@ var EditorControllerImpl = class {
1475
1823
  if (initialDiagnostics.length > 0) {
1476
1824
  throw new EditorInitializationError(initialDiagnostics);
1477
1825
  }
1826
+ if (options.aiAssist) {
1827
+ this.aiAssistPanel = createAIAssistPanel(
1828
+ this.root,
1829
+ {
1830
+ getDraft: () => this.getDraft(),
1831
+ navigateToGroup: (groupId) => this.navigateToGroup(groupId)
1832
+ },
1833
+ (proposal) => this.applyAIProposal(proposal),
1834
+ () => {
1835
+ }
1836
+ // onClose
1837
+ );
1838
+ }
1478
1839
  this.host = this.document.createElement("div");
1479
1840
  this.host.className = "rogatio-editor";
1480
1841
  this.host.dataset.rogatioEditor = "true";
@@ -1548,6 +1909,10 @@ var EditorControllerImpl = class {
1548
1909
  destroy() {
1549
1910
  if (this.destroyed) return;
1550
1911
  this.destroyed = true;
1912
+ if (this.aiAssistPanel) {
1913
+ this.aiAssistPanel.hide();
1914
+ this.aiAssistPanel = null;
1915
+ }
1551
1916
  this.cleanupExtensions();
1552
1917
  this.host.removeEventListener("click", this.handleClick);
1553
1918
  this.host.removeEventListener("input", this.handleInput);
@@ -1677,6 +2042,12 @@ var EditorControllerImpl = class {
1677
2042
  }
1678
2043
  };
1679
2044
  dispatchCommand(command, element) {
2045
+ if (command === "ai-assist") {
2046
+ if (this.aiAssistPanel) {
2047
+ this.aiAssistPanel.show();
2048
+ }
2049
+ return;
2050
+ }
1680
2051
  if (command === "validate") {
1681
2052
  this.validate();
1682
2053
  return;
@@ -2189,6 +2560,48 @@ var EditorControllerImpl = class {
2189
2560
  this.focusRequest = failure.path;
2190
2561
  this.render();
2191
2562
  }
2563
+ applyAIProposal(proposal) {
2564
+ for (const ruleProposal of proposal.rules) {
2565
+ let group = this.groupById(ruleProposal.groupId);
2566
+ if (!group) {
2567
+ const groupId = ruleProposal.groupId;
2568
+ this.draft.groups.push({
2569
+ id: groupId,
2570
+ name: "AI Group",
2571
+ origins: [],
2572
+ rules: []
2573
+ });
2574
+ group = this.groupById(groupId);
2575
+ }
2576
+ if (!group) return;
2577
+ const ruleId = this.nextId("rule-ai");
2578
+ const rule = {
2579
+ id: ruleId,
2580
+ name: ruleProposal.name,
2581
+ urlRegex: ruleProposal.urlRegex,
2582
+ origins: ruleProposal.origins ? [...ruleProposal.origins] : [],
2583
+ resourceTypes: ruleProposal.resourceTypes ? [...ruleProposal.resourceTypes] : ["main_frame"],
2584
+ priority: ruleProposal.priority ?? 100
2585
+ };
2586
+ if (ruleProposal.method) {
2587
+ rule.method = ruleProposal.method;
2588
+ }
2589
+ const actionField = ruleProposal.kind === "redirect" || ruleProposal.kind === "mock" ? ruleProposal.kind : "action";
2590
+ rule[actionField] = ruleProposal.action;
2591
+ group.rules.push(rule);
2592
+ this.markChanged();
2593
+ const groupIdStr = String(group.id);
2594
+ this.focusRequest = pointer(
2595
+ "groups",
2596
+ this.groupIndex(groupIdStr),
2597
+ "rules",
2598
+ group.rules.length - 1,
2599
+ "name"
2600
+ );
2601
+ }
2602
+ this.statusMessage = `Applied ${proposal.rules.length} rule${proposal.rules.length === 1 ? "" : "s"} from AI.`;
2603
+ this.render();
2604
+ }
2192
2605
  addGroupOrigin(groupId) {
2193
2606
  const group = this.groupById(groupId);
2194
2607
  if (!group || this.saving) return;
@@ -2617,6 +3030,11 @@ var EditorControllerImpl = class {
2617
3030
  renderCommandBar() {
2618
3031
  this.commandBar.replaceChildren();
2619
3032
  this.commandBar.setAttribute("aria-busy", this.saving ? "true" : "false");
3033
+ if (this.aiAssistPanel) {
3034
+ this.commandBar.append(
3035
+ this.createCommandButton("AI Assist", "ai-assist", this.saving)
3036
+ );
3037
+ }
2620
3038
  this.commandBar.append(
2621
3039
  this.createCommandButton("Validate", "validate", this.saving),
2622
3040
  this.createCommandButton("Save", "save", this.saving || !this.isDirty()),
@@ -3596,10 +4014,10 @@ var HEADER_OPERATIONS = [
3596
4014
  "append",
3597
4015
  "remove"
3598
4016
  ];
3599
- function createSelect(document, options, value, onChange) {
3600
- const select = document.createElement("select");
4017
+ function createSelect(document2, options, value, onChange) {
4018
+ const select = document2.createElement("select");
3601
4019
  for (const option of options) {
3602
- const opt = document.createElement("option");
4020
+ const opt = document2.createElement("option");
3603
4021
  opt.value = option;
3604
4022
  opt.textContent = option;
3605
4023
  if (option === value) opt.selected = true;
@@ -3608,8 +4026,8 @@ function createSelect(document, options, value, onChange) {
3608
4026
  select.addEventListener("change", () => onChange(select.value));
3609
4027
  return select;
3610
4028
  }
3611
- function createInput(document, value, onChange, maxLength) {
3612
- const input = document.createElement("input");
4029
+ function createInput(document2, value, onChange, maxLength) {
4030
+ const input = document2.createElement("input");
3613
4031
  input.type = "text";
3614
4032
  input.value = value;
3615
4033
  if (maxLength !== void 0) input.maxLength = maxLength;
@@ -3624,16 +4042,16 @@ function createHeaderRuleType() {
3624
4042
  return rule.type === "header";
3625
4043
  },
3626
4044
  mount(context) {
3627
- const document = context.document;
3628
- const fieldset = document.createElement("fieldset");
3629
- const legend = document.createElement("legend");
4045
+ const document2 = context.document;
4046
+ const fieldset = document2.createElement("fieldset");
4047
+ const legend = document2.createElement("legend");
3630
4048
  legend.textContent = "Header rule";
3631
4049
  fieldset.append(legend);
3632
- const directionLabel = document.createElement("label");
4050
+ const directionLabel = document2.createElement("label");
3633
4051
  directionLabel.textContent = "Direction";
3634
4052
  const directionValue = context.getField("headerDirection") ?? "request";
3635
4053
  const directionSelect = createSelect(
3636
- document,
4054
+ document2,
3637
4055
  HEADER_DIRECTIONS,
3638
4056
  directionValue,
3639
4057
  (value) => {
@@ -3643,11 +4061,11 @@ function createHeaderRuleType() {
3643
4061
  context.registerControl("/headerDirection", directionSelect);
3644
4062
  directionLabel.append(directionSelect);
3645
4063
  fieldset.append(directionLabel);
3646
- const operationLabel = document.createElement("label");
4064
+ const operationLabel = document2.createElement("label");
3647
4065
  operationLabel.textContent = "Operation";
3648
4066
  const operationValue = context.getField("headerOperation") ?? "set";
3649
4067
  const operationSelect = createSelect(
3650
- document,
4068
+ document2,
3651
4069
  HEADER_OPERATIONS,
3652
4070
  operationValue,
3653
4071
  (value) => {
@@ -3657,11 +4075,11 @@ function createHeaderRuleType() {
3657
4075
  context.registerControl("/headerOperation", operationSelect);
3658
4076
  operationLabel.append(operationSelect);
3659
4077
  fieldset.append(operationLabel);
3660
- const nameLabel = document.createElement("label");
4078
+ const nameLabel = document2.createElement("label");
3661
4079
  nameLabel.textContent = "Header name";
3662
4080
  const nameValue = context.getField("headerName") ?? "";
3663
4081
  const nameInput = createInput(
3664
- document,
4082
+ document2,
3665
4083
  nameValue,
3666
4084
  (value) => {
3667
4085
  context.setField("headerName", value);
@@ -3671,11 +4089,11 @@ function createHeaderRuleType() {
3671
4089
  context.registerControl("/headerName", nameInput);
3672
4090
  nameLabel.append(nameInput);
3673
4091
  fieldset.append(nameLabel);
3674
- const valueLabel = document.createElement("label");
4092
+ const valueLabel = document2.createElement("label");
3675
4093
  valueLabel.textContent = "Header value";
3676
4094
  const valueValue = context.getField("headerValue") ?? "";
3677
4095
  const valueInput = createInput(
3678
- document,
4096
+ document2,
3679
4097
  valueValue,
3680
4098
  (value) => {
3681
4099
  context.setField("headerValue", value);
@@ -3773,10 +4191,10 @@ function createRedirectRuleType() {
3773
4191
  return rule.type === "redirect";
3774
4192
  },
3775
4193
  mount(context) {
3776
- const document = context.document;
3777
- const label = document.createElement("label");
4194
+ const document2 = context.document;
4195
+ const label = document2.createElement("label");
3778
4196
  label.textContent = "Redirect destination URL";
3779
- const input = document.createElement("input");
4197
+ const input = document2.createElement("input");
3780
4198
  input.type = "text";
3781
4199
  input.maxLength = 2048;
3782
4200
  const existing = context.getField("redirect.destination");