@rogatio/cli 5.0.0 → 5.1.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.
@@ -214,6 +214,360 @@ 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
+ const _request = {
541
+ kind: "generate",
542
+ prompt,
543
+ context: {
544
+ project: editor.getDraft()
545
+ }
546
+ };
547
+ textarea.value = "";
548
+ textarea.style.height = "auto";
549
+ }
550
+ closeBtn.addEventListener("click", hide);
551
+ sendButton.addEventListener("click", handleSend);
552
+ textarea.addEventListener("keydown", (e) => {
553
+ if (e.key === "Enter" && !e.shiftKey) {
554
+ e.preventDefault();
555
+ handleSend();
556
+ }
557
+ });
558
+ return {
559
+ show,
560
+ hide,
561
+ isVisible,
562
+ addMessage,
563
+ clearMessages,
564
+ // Expose streaming methods for the aiAssist handler to use
565
+ startStreaming,
566
+ updateStreamingContent,
567
+ finishStreaming
568
+ };
569
+ }
570
+
217
571
  // packages/editor/src/rule-types/mock.ts
218
572
  function isRecord(value) {
219
573
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -340,7 +694,7 @@ function createMockRuleType() {
340
694
  return stable(diagnostics);
341
695
  },
342
696
  mount(context) {
343
- const { document, container } = context;
697
+ const { document: document2, container } = context;
344
698
  const getCurrent = () => asMockAction(context.getField("mock"));
345
699
  const setAction = (next) => {
346
700
  context.setField("mock", next);
@@ -349,9 +703,9 @@ function createMockRuleType() {
349
703
  const current = getCurrent();
350
704
  container.replaceChildren();
351
705
  if (current === void 0) return;
352
- const statusLabel = document.createElement("label");
706
+ const statusLabel = document2.createElement("label");
353
707
  statusLabel.textContent = "Status";
354
- const statusInput = document.createElement("input");
708
+ const statusInput = document2.createElement("input");
355
709
  statusInput.type = "number";
356
710
  statusInput.min = String(LIMITS.minMockStatus);
357
711
  statusInput.max = String(LIMITS.maxMockStatus);
@@ -365,9 +719,9 @@ function createMockRuleType() {
365
719
  });
366
720
  context.registerControl("/mock/status", statusInput);
367
721
  statusLabel.append(statusInput);
368
- const delayLabel = document.createElement("label");
722
+ const delayLabel = document2.createElement("label");
369
723
  delayLabel.textContent = "Delay (ms)";
370
- const delayInput = document.createElement("input");
724
+ const delayInput = document2.createElement("input");
371
725
  delayInput.type = "number";
372
726
  delayInput.min = "0";
373
727
  delayInput.max = String(LIMITS.maxMockDelayMs);
@@ -383,20 +737,20 @@ function createMockRuleType() {
383
737
  });
384
738
  context.registerControl("/mock/delayMs", delayInput);
385
739
  delayLabel.append(delayInput);
386
- const sourceLabel = document.createElement("label");
740
+ const sourceLabel = document2.createElement("label");
387
741
  sourceLabel.textContent = "Body source";
388
- const sourceSelect = document.createElement("select");
742
+ const sourceSelect = document2.createElement("select");
389
743
  sourceSelect.dataset.editorField = "true";
390
- const bodyOption = document.createElement("option");
744
+ const bodyOption = document2.createElement("option");
391
745
  bodyOption.value = "body";
392
746
  bodyOption.textContent = "Inline body";
393
- const fileOption = document.createElement("option");
747
+ const fileOption = document2.createElement("option");
394
748
  fileOption.value = "file";
395
749
  fileOption.textContent = "File snapshot";
396
750
  sourceSelect.append(bodyOption, fileOption);
397
751
  sourceSelect.value = typeof current.file === "string" ? "file" : "body";
398
752
  context.registerControl("/mock/body-source", sourceSelect);
399
- const bodyArea = document.createElement("textarea");
753
+ const bodyArea = document2.createElement("textarea");
400
754
  bodyArea.value = typeof current.body === "string" ? current.body : "";
401
755
  bodyArea.dataset.editorField = "true";
402
756
  bodyArea.addEventListener("input", () => {
@@ -405,9 +759,9 @@ function createMockRuleType() {
405
759
  setAction({ ...c, body: bodyArea.value, file: void 0 });
406
760
  });
407
761
  context.registerControl("/mock/body", bodyArea);
408
- const fileLabel = document.createElement("label");
762
+ const fileLabel = document2.createElement("label");
409
763
  fileLabel.textContent = "File path";
410
- const fileInput = document.createElement("input");
764
+ const fileInput = document2.createElement("input");
411
765
  fileInput.type = "text";
412
766
  fileInput.value = typeof current.file === "string" ? current.file : "";
413
767
  fileInput.dataset.editorField = "true";
@@ -425,8 +779,8 @@ function createMockRuleType() {
425
779
  };
426
780
  sourceSelect.addEventListener("change", syncSource);
427
781
  syncSource();
428
- const headersFieldset = document.createElement("fieldset");
429
- const headersLegend = document.createElement("legend");
782
+ const headersFieldset = document2.createElement("fieldset");
783
+ const headersLegend = document2.createElement("legend");
430
784
  headersLegend.textContent = "Response headers";
431
785
  headersFieldset.append(headersLegend);
432
786
  const renderHeaders = () => {
@@ -437,11 +791,11 @@ function createMockRuleType() {
437
791
  });
438
792
  const headers = c.headers ?? [];
439
793
  headers.forEach((header, index) => {
440
- const row = document.createElement("div");
794
+ const row = document2.createElement("div");
441
795
  row.dataset.mockHeaderRow = String(index);
442
- const nameLabel = document.createElement("label");
796
+ const nameLabel = document2.createElement("label");
443
797
  nameLabel.textContent = "Name";
444
- const nameInput = document.createElement("input");
798
+ const nameInput = document2.createElement("input");
445
799
  nameInput.type = "text";
446
800
  nameInput.value = header.name;
447
801
  nameInput.dataset.editorField = "true";
@@ -455,9 +809,9 @@ function createMockRuleType() {
455
809
  });
456
810
  context.registerControl(`/mock/headers/${index}/name`, nameInput);
457
811
  nameLabel.append(nameInput);
458
- const valueLabel = document.createElement("label");
812
+ const valueLabel = document2.createElement("label");
459
813
  valueLabel.textContent = "Value";
460
- const valueInput = document.createElement("input");
814
+ const valueInput = document2.createElement("input");
461
815
  valueInput.type = "text";
462
816
  valueInput.value = header.value;
463
817
  valueInput.dataset.editorField = "true";
@@ -471,7 +825,7 @@ function createMockRuleType() {
471
825
  });
472
826
  context.registerControl(`/mock/headers/${index}/value`, valueInput);
473
827
  valueLabel.append(valueInput);
474
- const remove = document.createElement("button");
828
+ const remove = document2.createElement("button");
475
829
  remove.type = "button";
476
830
  remove.textContent = "Remove";
477
831
  remove.dataset.editorField = "true";
@@ -484,7 +838,7 @@ function createMockRuleType() {
484
838
  row.append(nameLabel, valueLabel, remove);
485
839
  headersFieldset.append(row);
486
840
  });
487
- const add = document.createElement("button");
841
+ const add = document2.createElement("button");
488
842
  add.type = "button";
489
843
  add.textContent = "Add header";
490
844
  add.dataset.editorField = "true";
@@ -612,7 +966,7 @@ var queryRuleType = {
612
966
  return stable2(diagnostics);
613
967
  },
614
968
  mount(context) {
615
- const { document, container } = context;
969
+ const { document: document2, container } = context;
616
970
  const getCurrent = () => asQueryAction(context.getField("action"));
617
971
  const setAction = (next) => {
618
972
  context.setField("action", next);
@@ -622,11 +976,11 @@ var queryRuleType = {
622
976
  container.replaceChildren();
623
977
  if (current === void 0) return;
624
978
  current.params.forEach((param, index) => {
625
- const row = document.createElement("div");
979
+ const row = document2.createElement("div");
626
980
  row.dataset.queryParamRow = String(index);
627
- const nameLabel = document.createElement("label");
981
+ const nameLabel = document2.createElement("label");
628
982
  nameLabel.textContent = "Name";
629
- const nameInput = document.createElement("input");
983
+ const nameInput = document2.createElement("input");
630
984
  nameInput.type = "text";
631
985
  nameInput.value = param.name;
632
986
  nameInput.dataset.editorField = "true";
@@ -640,9 +994,9 @@ var queryRuleType = {
640
994
  });
641
995
  context.registerControl(`/action/params/${index}/name`, nameInput);
642
996
  nameLabel.append(nameInput);
643
- const valueLabel = document.createElement("label");
997
+ const valueLabel = document2.createElement("label");
644
998
  valueLabel.textContent = "Value";
645
- const valueInput = document.createElement("input");
999
+ const valueInput = document2.createElement("input");
646
1000
  valueInput.type = "text";
647
1001
  valueInput.value = param.value;
648
1002
  valueInput.dataset.editorField = "true";
@@ -656,7 +1010,7 @@ var queryRuleType = {
656
1010
  });
657
1011
  context.registerControl(`/action/params/${index}/value`, valueInput);
658
1012
  valueLabel.append(valueInput);
659
- const remove = document.createElement("button");
1013
+ const remove = document2.createElement("button");
660
1014
  remove.type = "button";
661
1015
  remove.textContent = "Remove";
662
1016
  remove.dataset.editorField = "true";
@@ -669,7 +1023,7 @@ var queryRuleType = {
669
1023
  row.append(nameLabel, valueLabel, remove);
670
1024
  container.append(row);
671
1025
  });
672
- const add = document.createElement("button");
1026
+ const add = document2.createElement("button");
673
1027
  add.type = "button";
674
1028
  add.textContent = "Add parameter";
675
1029
  add.dataset.editorField = "true";
@@ -834,17 +1188,17 @@ function createRequestBodyRuleType() {
834
1188
  return stable3(diagnostics);
835
1189
  },
836
1190
  mount(context) {
837
- const { document, container } = context;
1191
+ const { document: document2, container } = context;
838
1192
  const render = () => {
839
1193
  const current = requestBodyOf(context.getField("requestBody"));
840
1194
  container.replaceChildren();
841
1195
  if (current === void 0) return;
842
- const modeSelect = document.createElement("select");
1196
+ const modeSelect = document2.createElement("select");
843
1197
  modeSelect.value = current.mode;
844
- const replaceOption = document.createElement("option");
1198
+ const replaceOption = document2.createElement("option");
845
1199
  replaceOption.value = "replace";
846
1200
  replaceOption.textContent = "Replace body";
847
- const regexOption = document.createElement("option");
1201
+ const regexOption = document2.createElement("option");
848
1202
  regexOption.value = "regex";
849
1203
  regexOption.textContent = "Regex replace";
850
1204
  modeSelect.append(replaceOption, regexOption);
@@ -862,7 +1216,7 @@ function createRequestBodyRuleType() {
862
1216
  context.registerControl("/requestBody/mode", modeSelect);
863
1217
  container.append(modeSelect);
864
1218
  if (current.mode === "replace") {
865
- const bodyInput = document.createElement("textarea");
1219
+ const bodyInput = document2.createElement("textarea");
866
1220
  bodyInput.value = current.body ?? "";
867
1221
  bodyInput.placeholder = "Replacement body";
868
1222
  bodyInput.addEventListener("input", () => {
@@ -872,7 +1226,7 @@ function createRequestBodyRuleType() {
872
1226
  context.registerControl("/requestBody/body", bodyInput);
873
1227
  container.append(bodyInput);
874
1228
  } else {
875
- const patternInput = document.createElement("input");
1229
+ const patternInput = document2.createElement("input");
876
1230
  patternInput.type = "text";
877
1231
  patternInput.value = current.pattern ?? "";
878
1232
  patternInput.placeholder = "Regex pattern";
@@ -882,7 +1236,7 @@ function createRequestBodyRuleType() {
882
1236
  });
883
1237
  context.registerControl("/requestBody/pattern", patternInput);
884
1238
  container.append(patternInput);
885
- const replacementInput = document.createElement("input");
1239
+ const replacementInput = document2.createElement("input");
886
1240
  replacementInput.type = "text";
887
1241
  replacementInput.value = current.replacement ?? "";
888
1242
  replacementInput.placeholder = "Replacement";
@@ -964,15 +1318,15 @@ function createResponseBodyRuleType() {
964
1318
  return stable4(diagnostics);
965
1319
  },
966
1320
  mount(context) {
967
- const { document, container } = context;
1321
+ const { document: document2, container } = context;
968
1322
  const render = () => {
969
1323
  const current = replacementsOf(context.getField("responseBody"));
970
1324
  container.replaceChildren();
971
1325
  if (current === void 0) return;
972
1326
  current.forEach((entry, index) => {
973
- const row = document.createElement("div");
1327
+ const row = document2.createElement("div");
974
1328
  row.dataset.responseBodyReplacement = String(index);
975
- const pattern = document.createElement("input");
1329
+ const pattern = document2.createElement("input");
976
1330
  pattern.type = "text";
977
1331
  pattern.value = entry.pattern;
978
1332
  pattern.placeholder = "Pattern";
@@ -987,7 +1341,7 @@ function createResponseBodyRuleType() {
987
1341
  `/responseBody/replacements/${index}/pattern`,
988
1342
  pattern
989
1343
  );
990
- const replacement = document.createElement("input");
1344
+ const replacement = document2.createElement("input");
991
1345
  replacement.type = "text";
992
1346
  replacement.value = entry.replacement;
993
1347
  replacement.placeholder = "Replacement";
@@ -1002,7 +1356,7 @@ function createResponseBodyRuleType() {
1002
1356
  `/responseBody/replacements/${index}/replacement`,
1003
1357
  replacement
1004
1358
  );
1005
- const remove = document.createElement("button");
1359
+ const remove = document2.createElement("button");
1006
1360
  remove.type = "button";
1007
1361
  remove.textContent = "Remove replacement";
1008
1362
  remove.addEventListener("click", () => {
@@ -1013,7 +1367,7 @@ function createResponseBodyRuleType() {
1013
1367
  row.append(pattern, replacement, remove);
1014
1368
  container.append(row);
1015
1369
  });
1016
- const add = document.createElement("button");
1370
+ const add = document2.createElement("button");
1017
1371
  add.type = "button";
1018
1372
  add.textContent = "Add replacement";
1019
1373
  add.addEventListener("click", () => {
@@ -1463,6 +1817,7 @@ var EditorControllerImpl = class {
1463
1817
  testResult = void 0;
1464
1818
  testRunning = false;
1465
1819
  testRequestId = 0;
1820
+ aiAssistPanel = null;
1466
1821
  constructor(options, initial, extensions) {
1467
1822
  this.root = options.root;
1468
1823
  this.document = options.root.ownerDocument;
@@ -1475,6 +1830,19 @@ var EditorControllerImpl = class {
1475
1830
  if (initialDiagnostics.length > 0) {
1476
1831
  throw new EditorInitializationError(initialDiagnostics);
1477
1832
  }
1833
+ if (options.aiAssist) {
1834
+ this.aiAssistPanel = createAIAssistPanel(
1835
+ this.root,
1836
+ {
1837
+ getDraft: () => this.getDraft(),
1838
+ navigateToGroup: (groupId) => this.navigateToGroup(groupId)
1839
+ },
1840
+ (proposal) => this.applyAIProposal(proposal),
1841
+ () => {
1842
+ }
1843
+ // onClose
1844
+ );
1845
+ }
1478
1846
  this.host = this.document.createElement("div");
1479
1847
  this.host.className = "rogatio-editor";
1480
1848
  this.host.dataset.rogatioEditor = "true";
@@ -1548,6 +1916,10 @@ var EditorControllerImpl = class {
1548
1916
  destroy() {
1549
1917
  if (this.destroyed) return;
1550
1918
  this.destroyed = true;
1919
+ if (this.aiAssistPanel) {
1920
+ this.aiAssistPanel.hide();
1921
+ this.aiAssistPanel = null;
1922
+ }
1551
1923
  this.cleanupExtensions();
1552
1924
  this.host.removeEventListener("click", this.handleClick);
1553
1925
  this.host.removeEventListener("input", this.handleInput);
@@ -1677,6 +2049,12 @@ var EditorControllerImpl = class {
1677
2049
  }
1678
2050
  };
1679
2051
  dispatchCommand(command, element) {
2052
+ if (command === "ai-assist") {
2053
+ if (this.aiAssistPanel) {
2054
+ this.aiAssistPanel.show();
2055
+ }
2056
+ return;
2057
+ }
1680
2058
  if (command === "validate") {
1681
2059
  this.validate();
1682
2060
  return;
@@ -2189,6 +2567,47 @@ var EditorControllerImpl = class {
2189
2567
  this.focusRequest = failure.path;
2190
2568
  this.render();
2191
2569
  }
2570
+ applyAIProposal(proposal) {
2571
+ for (const ruleProposal of proposal.rules) {
2572
+ let group = this.groupById(ruleProposal.groupId);
2573
+ if (!group) {
2574
+ const groupId = ruleProposal.groupId;
2575
+ this.draft.groups.push({
2576
+ id: groupId,
2577
+ name: "AI Group",
2578
+ origins: [],
2579
+ rules: []
2580
+ });
2581
+ group = this.groupById(groupId);
2582
+ }
2583
+ if (!group) return;
2584
+ const ruleId = this.nextId("rule-ai");
2585
+ const rule = {
2586
+ id: ruleId,
2587
+ name: ruleProposal.name,
2588
+ urlRegex: ruleProposal.urlRegex,
2589
+ origins: ruleProposal.origins ?? [],
2590
+ resourceTypes: ruleProposal.resourceTypes ?? ["main_frame"],
2591
+ priority: ruleProposal.priority ?? 100
2592
+ };
2593
+ if (ruleProposal.method) {
2594
+ rule.method = ruleProposal.method;
2595
+ }
2596
+ const actionField = ruleProposal.kind === "redirect" || ruleProposal.kind === "mock" ? ruleProposal.kind : "action";
2597
+ rule[actionField] = ruleProposal.action;
2598
+ group.rules.push(rule);
2599
+ this.markChanged();
2600
+ this.focusRequest = pointer(
2601
+ "groups",
2602
+ this.groupIndex(group.id),
2603
+ "rules",
2604
+ group.rules.length - 1,
2605
+ "name"
2606
+ );
2607
+ }
2608
+ this.statusMessage = `Applied ${proposal.rules.length} rule${proposal.rules.length === 1 ? "" : "s"} from AI.`;
2609
+ this.render();
2610
+ }
2192
2611
  addGroupOrigin(groupId) {
2193
2612
  const group = this.groupById(groupId);
2194
2613
  if (!group || this.saving) return;
@@ -2617,6 +3036,11 @@ var EditorControllerImpl = class {
2617
3036
  renderCommandBar() {
2618
3037
  this.commandBar.replaceChildren();
2619
3038
  this.commandBar.setAttribute("aria-busy", this.saving ? "true" : "false");
3039
+ if (this.aiAssistPanel) {
3040
+ this.commandBar.append(
3041
+ this.createCommandButton("AI Assist", "ai-assist", this.saving)
3042
+ );
3043
+ }
2620
3044
  this.commandBar.append(
2621
3045
  this.createCommandButton("Validate", "validate", this.saving),
2622
3046
  this.createCommandButton("Save", "save", this.saving || !this.isDirty()),
@@ -3596,10 +4020,10 @@ var HEADER_OPERATIONS = [
3596
4020
  "append",
3597
4021
  "remove"
3598
4022
  ];
3599
- function createSelect(document, options, value, onChange) {
3600
- const select = document.createElement("select");
4023
+ function createSelect(document2, options, value, onChange) {
4024
+ const select = document2.createElement("select");
3601
4025
  for (const option of options) {
3602
- const opt = document.createElement("option");
4026
+ const opt = document2.createElement("option");
3603
4027
  opt.value = option;
3604
4028
  opt.textContent = option;
3605
4029
  if (option === value) opt.selected = true;
@@ -3608,8 +4032,8 @@ function createSelect(document, options, value, onChange) {
3608
4032
  select.addEventListener("change", () => onChange(select.value));
3609
4033
  return select;
3610
4034
  }
3611
- function createInput(document, value, onChange, maxLength) {
3612
- const input = document.createElement("input");
4035
+ function createInput(document2, value, onChange, maxLength) {
4036
+ const input = document2.createElement("input");
3613
4037
  input.type = "text";
3614
4038
  input.value = value;
3615
4039
  if (maxLength !== void 0) input.maxLength = maxLength;
@@ -3624,16 +4048,16 @@ function createHeaderRuleType() {
3624
4048
  return rule.type === "header";
3625
4049
  },
3626
4050
  mount(context) {
3627
- const document = context.document;
3628
- const fieldset = document.createElement("fieldset");
3629
- const legend = document.createElement("legend");
4051
+ const document2 = context.document;
4052
+ const fieldset = document2.createElement("fieldset");
4053
+ const legend = document2.createElement("legend");
3630
4054
  legend.textContent = "Header rule";
3631
4055
  fieldset.append(legend);
3632
- const directionLabel = document.createElement("label");
4056
+ const directionLabel = document2.createElement("label");
3633
4057
  directionLabel.textContent = "Direction";
3634
4058
  const directionValue = context.getField("headerDirection") ?? "request";
3635
4059
  const directionSelect = createSelect(
3636
- document,
4060
+ document2,
3637
4061
  HEADER_DIRECTIONS,
3638
4062
  directionValue,
3639
4063
  (value) => {
@@ -3643,11 +4067,11 @@ function createHeaderRuleType() {
3643
4067
  context.registerControl("/headerDirection", directionSelect);
3644
4068
  directionLabel.append(directionSelect);
3645
4069
  fieldset.append(directionLabel);
3646
- const operationLabel = document.createElement("label");
4070
+ const operationLabel = document2.createElement("label");
3647
4071
  operationLabel.textContent = "Operation";
3648
4072
  const operationValue = context.getField("headerOperation") ?? "set";
3649
4073
  const operationSelect = createSelect(
3650
- document,
4074
+ document2,
3651
4075
  HEADER_OPERATIONS,
3652
4076
  operationValue,
3653
4077
  (value) => {
@@ -3657,11 +4081,11 @@ function createHeaderRuleType() {
3657
4081
  context.registerControl("/headerOperation", operationSelect);
3658
4082
  operationLabel.append(operationSelect);
3659
4083
  fieldset.append(operationLabel);
3660
- const nameLabel = document.createElement("label");
4084
+ const nameLabel = document2.createElement("label");
3661
4085
  nameLabel.textContent = "Header name";
3662
4086
  const nameValue = context.getField("headerName") ?? "";
3663
4087
  const nameInput = createInput(
3664
- document,
4088
+ document2,
3665
4089
  nameValue,
3666
4090
  (value) => {
3667
4091
  context.setField("headerName", value);
@@ -3671,11 +4095,11 @@ function createHeaderRuleType() {
3671
4095
  context.registerControl("/headerName", nameInput);
3672
4096
  nameLabel.append(nameInput);
3673
4097
  fieldset.append(nameLabel);
3674
- const valueLabel = document.createElement("label");
4098
+ const valueLabel = document2.createElement("label");
3675
4099
  valueLabel.textContent = "Header value";
3676
4100
  const valueValue = context.getField("headerValue") ?? "";
3677
4101
  const valueInput = createInput(
3678
- document,
4102
+ document2,
3679
4103
  valueValue,
3680
4104
  (value) => {
3681
4105
  context.setField("headerValue", value);
@@ -3773,10 +4197,10 @@ function createRedirectRuleType() {
3773
4197
  return rule.type === "redirect";
3774
4198
  },
3775
4199
  mount(context) {
3776
- const document = context.document;
3777
- const label = document.createElement("label");
4200
+ const document2 = context.document;
4201
+ const label = document2.createElement("label");
3778
4202
  label.textContent = "Redirect destination URL";
3779
- const input = document.createElement("input");
4203
+ const input = document2.createElement("input");
3780
4204
  input.type = "text";
3781
4205
  input.maxLength = 2048;
3782
4206
  const existing = context.getField("redirect.destination");