@ai-ecoverse/slicc-spectrum 1.92.0 → 1.93.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.
@@ -5,8 +5,26 @@ import {
5
5
  } from "./chunk-XQHRTHDQ.js";
6
6
  import {
7
7
  DummySettings,
8
- clock
9
- } from "./chunk-3CM23WFV.js";
8
+ accounts,
9
+ agents,
10
+ clock,
11
+ conversations,
12
+ defaults,
13
+ directories,
14
+ files,
15
+ laterModels,
16
+ models,
17
+ mountPoint,
18
+ mounted,
19
+ pending,
20
+ providerAccount,
21
+ providerAccounts,
22
+ providerFixtures,
23
+ queues,
24
+ skillEdit,
25
+ tabs,
26
+ terminals
27
+ } from "./chunk-RYA3OPGE.js";
10
28
  import {
11
29
  Emitter
12
30
  } from "./chunk-T5NHW4KC.js";
@@ -196,23 +214,23 @@ function session(now2) {
196
214
  const harbor2 = { tabId: "tab-preview", agentId: "cone-harbor" };
197
215
  return Array.from({ length: 170 }, (_, i) => {
198
216
  const city = cities[i % cities.length];
199
- const at3 = now2 - 286 * second + i * 960;
217
+ const at = now2 - 286 * second + i * 960;
200
218
  switch (i % 5) {
201
219
  case 0:
202
220
  return {
203
221
  ...harbor2,
204
222
  kind: "goto",
205
223
  value: `http://localhost:8787/forecast?city=${city}&days=${i % 7 + 1}&units=metric&compare=tides,wind,swell&session=run-${i}`,
206
- at: at3
224
+ at
207
225
  };
208
226
  case 1:
209
- return { ...harbor2, kind: "snapshot", at: at3 };
227
+ return { ...harbor2, kind: "snapshot", at };
210
228
  case 2:
211
- return { ...harbor2, kind: "click", target: `button "Day ${i % 7 + 1}"`, at: at3 };
229
+ return { ...harbor2, kind: "click", target: `button "Day ${i % 7 + 1}"`, at };
212
230
  case 3:
213
- return { ...harbor2, kind: "scroll", at: at3 };
231
+ return { ...harbor2, kind: "scroll", at };
214
232
  default:
215
- return { ...harbor2, kind: "screenshot", at: at3 };
233
+ return { ...harbor2, kind: "screenshot", at };
216
234
  }
217
235
  });
218
236
  }
@@ -327,9 +345,9 @@ var DummyBrowser = class extends Emitter {
327
345
  this.emit("action", { ...action });
328
346
  }
329
347
  async run(script2) {
330
- for (const [index2, draft] of script2.entries()) {
348
+ for (const [index, draft] of script2.entries()) {
331
349
  const id = this.record(draft);
332
- if (index2 === script2.length - 1) return;
350
+ if (index === script2.length - 1) return;
333
351
  await this.#clock.sleep(20);
334
352
  this.finish(id);
335
353
  await this.#clock.sleep(10);
@@ -405,11 +423,11 @@ var DummyBrowser = class extends Emitter {
405
423
  this.#load(id);
406
424
  }
407
425
  close(id) {
408
- const index2 = this.#tabs.findIndex((tab) => tab.id === id);
409
- if (index2 < 0) return;
410
- this.#tabs.splice(index2, 1);
426
+ const index = this.#tabs.findIndex((tab) => tab.id === id);
427
+ if (index < 0) return;
428
+ this.#tabs.splice(index, 1);
411
429
  if (this.#active === id)
412
- this.#active = this.#tabs[Math.min(index2, this.#tabs.length - 1)]?.id ?? null;
430
+ this.#active = this.#tabs[Math.min(index, this.#tabs.length - 1)]?.id ?? null;
413
431
  this.#changed();
414
432
  }
415
433
  async screenshot(id) {
@@ -513,1558 +531,6 @@ var DummyFollow = class extends Emitter {
513
531
  }
514
532
  };
515
533
 
516
- // src/dummy/showcase.ts
517
- var start = Date.UTC(2026, 9, 4, 16, 0);
518
- var at = (minutes2) => start + minutes2 * 6e4;
519
- function picture(label2, from, to, width = 640, height = 400) {
520
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${from}"/><stop offset="1" stop-color="${to}"/></linearGradient></defs><rect width="${width}" height="${height}" fill="url(#g)"/><text x="50%" y="50%" font-family="sans-serif" font-size="${Math.round(height / 9)}" fill="#ffffff" text-anchor="middle" dominant-baseline="middle">${label2}</text></svg>`;
521
- return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
522
- }
523
- function tone(seconds = 0.6, frequency = 440, rate = 8e3) {
524
- const samples = Math.round(seconds * rate);
525
- const bytes = new Uint8Array(44 + samples);
526
- const view = new DataView(bytes.buffer);
527
- const text = (offset, value) => {
528
- for (let i = 0; i < value.length; i++) bytes[offset + i] = value.charCodeAt(i);
529
- };
530
- text(0, "RIFF");
531
- view.setUint32(4, 36 + samples, true);
532
- text(8, "WAVEfmt ");
533
- view.setUint32(16, 16, true);
534
- view.setUint16(20, 1, true);
535
- view.setUint16(22, 1, true);
536
- view.setUint32(24, rate, true);
537
- view.setUint32(28, rate, true);
538
- view.setUint16(32, 1, true);
539
- view.setUint16(34, 8, true);
540
- text(36, "data");
541
- view.setUint32(40, samples, true);
542
- for (let i = 0; i < samples; i++) {
543
- const fade = Math.min(1, (samples - i) / (rate / 10));
544
- bytes[44 + i] = 128 + Math.round(60 * fade * Math.sin(2 * Math.PI * frequency * i / rate));
545
- }
546
- let binary = "";
547
- for (const byte of bytes) binary += String.fromCharCode(byte);
548
- return `data:audio/wav;base64,${btoa(binary)}`;
549
- }
550
- function tool(id, name2, title, input, output, extra = {}) {
551
- return { id, name: name2, title, input, output, status: "done", paths: [], ...extra };
552
- }
553
- var markdown = [
554
- "## The forecast API in one page",
555
- "",
556
- "harbor answers `GET /forecast?city=\u2026` with the day\u2019s **high**, **low** and a *short summary*, and caches per city for an hour. ~~XML output~~ is gone.",
557
- "",
558
- "### How a request flows",
559
- "",
560
- "1. The worker parses the city.",
561
- "2. The cache answers if it has a fresh entry:",
562
- " - same UTC day",
563
- " - younger than one hour",
564
- "3. Otherwise the upstream call runs, with three retries.",
565
- "",
566
- "> Upstream is slow at the top of the hour. Retries back off at 250, 500 and 1000 ms.",
567
- "",
568
- "```ts",
569
- "export async function forecast(city: string): Promise<Forecast> {",
570
- " const cached = cache.get(city);",
571
- " if (cached) return cached;",
572
- " return cache.set(city, await retry(() => upstream(city)));",
573
- "}",
574
- "```",
575
- "",
576
- "| Route | Cache | Typical latency |",
577
- "| --- | --- | ---: |",
578
- "| `/forecast` | 1 hour, per city | 38 ms |",
579
- "| `/health` | none | 2 ms |",
580
- "| `/forecast` (miss) | \u2014 | 410 ms |",
581
- "",
582
- "- [x] TTL fix merged",
583
- "- [ ] Move the cache to KV",
584
- "",
585
- "Details are in the [API reference](https://api.example.com/docs/v2/forecast). A long path that must wrap: `/workspace/harbor/node_modules/.cache/wrangler/state/v3/cache/miniflare-CacheObject/7c1f0e3b9a5d4e2f8b6a1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f.sqlite`."
586
- ].join("\n");
587
- var toolShapes = [
588
- tool("k-t1", "bash", "Count the routes", "rg -c 'pathname ===' src", "src/index.ts:2"),
589
- tool(
590
- "k-t2",
591
- "read_file",
592
- "Read the router",
593
- "/workspace/harbor/src/index.ts",
594
- "import { forecast } from './routes/forecast.ts';\n\u2026",
595
- {
596
- paths: ["/workspace/harbor/src/index.ts"]
597
- }
598
- ),
599
- tool(
600
- "k-t3",
601
- "write_file",
602
- "Create the KV binding notes",
603
- "/workspace/harbor/docs/kv.md",
604
- "Wrote 18 lines",
605
- {
606
- paths: ["/workspace/harbor/docs/kv.md"]
607
- }
608
- ),
609
- tool(
610
- "k-t4",
611
- "edit_file",
612
- "Rename the cache key",
613
- "/workspace/harbor/src/lib/cache.ts",
614
- 'No match for "cityKey(" in src/lib/cache.ts',
615
- {
616
- status: "error",
617
- paths: ["/workspace/harbor/src/lib/cache.ts"]
618
- }
619
- ),
620
- tool(
621
- "k-t5",
622
- "grep",
623
- "Find TODOs",
624
- 'TODO --glob "src/**"',
625
- "src/routes/forecast.ts:14: TODO: cache negative results\nsrc/lib/units.ts:3: TODO: round half to even"
626
- ),
627
- tool(
628
- "k-t6",
629
- "web_fetch",
630
- "Fetch the API changelog",
631
- "https://api.example.com/changelog.json",
632
- '{ "latest": "2.4.1", "breaking": false }'
633
- ),
634
- tool(
635
- "k-t7",
636
- "browser",
637
- "Screenshot the preview",
638
- "screenshot http://localhost:8787/",
639
- "Captured 1280\xD7800",
640
- {
641
- image: picture("localhost:8787", "#3b63fb", "#0a7a43", 640, 400)
642
- }
643
- ),
644
- tool(
645
- "k-t8",
646
- "scoop_scoop",
647
- "Start a scoop for the docs",
648
- "name: docs-pass\ntask: Update the forecast page to Celsius",
649
- "Scoop docs-pass is running"
650
- ),
651
- tool(
652
- "k-t9",
653
- "feed_scoop",
654
- "Hand the screenshots to docs-pass",
655
- "scoop_name: docs-pass\nmessage: Use the new screenshots in /tmp/shots",
656
- "Delivered"
657
- ),
658
- tool(
659
- "k-t10",
660
- "send_message",
661
- "Tell quiet-otter the tests pass",
662
- "to: quiet-otter\nmessage: CI is green, merge when ready",
663
- "Delivered"
664
- ),
665
- tool(
666
- "k-t11",
667
- "drop_scoop",
668
- "Wrap up amber-heron",
669
- "scoop_name: amber-heron",
670
- "Dropped amber-heron; its notes are in /shared/notes"
671
- ),
672
- tool(
673
- "k-t12",
674
- "update_global_memory",
675
- "Remember the cache rule",
676
- "Cache keys are per city and per UTC day.",
677
- "Memory updated (3 sections, 412 characters)"
678
- ),
679
- tool(
680
- "k-mcp",
681
- "mcp__docs__search",
682
- "docs \xB7 search",
683
- '{\n "query": "forecast units"\n}',
684
- "2 pages: /forecast, /units"
685
- ),
686
- tool("k-t13", "bash", "Deploy to staging", "wrangler deploy --env staging", "Stopped", {
687
- status: "cancelled"
688
- }),
689
- tool("k-t14", "bash", "Watch the logs", "wrangler tail --env staging", "", { status: "running" }),
690
- tool(
691
- "k-t16",
692
- "bash",
693
- "Check the staging routes",
694
- "wrangler routes list --env staging",
695
- "ROUTE ZONE WORKER ENV\nforecast.harbor.example/v2/forecast/* harbor.example harbor-forecast-v2 staging\nerror: the route forecast.harbor.example/v2/units/* belongs to another account; ask its owner to release it first",
696
- {
697
- status: "error",
698
- notes: [
699
- { severity: "error", text: "Exited with code 5" },
700
- {
701
- severity: "warn",
702
- text: "Output truncated: 12 lines and 1,840 bytes dropped from the start"
703
- },
704
- { severity: "info", text: "Full output in /tmp/pi-bash-7f3a.log" }
705
- ]
706
- }
707
- )
708
- ];
709
- var licks = [
710
- [
711
- "webhook",
712
- "GitHub \xB7 pull_request.opened",
713
- "example/harbor#58 Add retries for upstream timeouts",
714
- '{\n "action": "opened",\n "number": 58,\n "repository": { "full_name": "example/harbor" }\n}',
715
- {}
716
- ],
717
- [
718
- "cron",
719
- "Every weekday 09:00",
720
- "Morning summary for the harbor cone",
721
- void 0,
722
- { count: 3 }
723
- ],
724
- [
725
- "sprinkle",
726
- "Release board",
727
- "Button \u201CShip 1.9.0\u201D clicked",
728
- '{ "button": "ship", "version": "1.9.0" }',
729
- {}
730
- ],
731
- [
732
- "fswatch",
733
- "/workspace/harbor/src",
734
- "2 files changed",
735
- "modified /workspace/harbor/src/lib/cache.ts\ncreated /workspace/harbor/src/lib/retry.ts",
736
- {}
737
- ],
738
- [
739
- "session-reload",
740
- "Session restored",
741
- "The page reloaded; 4 cones resumed from storage",
742
- void 0,
743
- {}
744
- ],
745
- [
746
- "navigate",
747
- "api.example.com",
748
- "A page offered a SLICC handoff: open the forecast docs",
749
- '{ "verb": "open", "target": "https://api.example.com/docs/v2/forecast" }',
750
- {}
751
- ],
752
- [
753
- "discovery",
754
- "api.example.com",
755
- "Found an ai-catalog.json with 3 tools",
756
- "https://api.example.com/.well-known/ai-catalog.json",
757
- {}
758
- ],
759
- ["upgrade", "SLICC updated", "6.4.0 \u2192 6.5.0", void 0, {}],
760
- [
761
- "workflow",
762
- "release-notes",
763
- "Step 2 of 4 finished: collect merged pull requests",
764
- void 0,
765
- {}
766
- ],
767
- ["bash", "Job 3", "npm run build exited with status 0 after 41 s", void 0, {}],
768
- ["jshd", "collect.jsh", "Script finished: 12 pull requests since v1.8.0", void 0, {}],
769
- ["preview", "Preview bridge", "Connected from localhost:8787", void 0, {}],
770
- [
771
- "cherry",
772
- "Host page",
773
- "Event \u201Ccart-updated\u201D from shop.example.com",
774
- '{ "items": 3, "total": 42.5 }',
775
- {}
776
- ],
777
- ["scoop-notify", "docs-pass", "Finished: the forecast page now shows Celsius", void 0, {}],
778
- ["scoop-idle", "amber-heron", "Idle for 30 minutes", void 0, {}],
779
- ["scoop-wait", "quiet-otter", "The wait for CI resolved: all checks passed", void 0, {}],
780
- [
781
- "sudo-request",
782
- "docs-pass",
783
- "Wants to push to example/harbor (branch docs/celsius)",
784
- "git push origin docs/celsius",
785
- { state: "pending", expiresAt: Date.now() + 10 * 6e4 }
786
- ],
787
- [
788
- "sudo-request",
789
- "quiet-otter",
790
- "Wants to read secrets: UPSTREAM_TOKEN",
791
- void 0,
792
- { state: "confirmed" }
793
- ],
794
- [
795
- "sudo-request",
796
- "amber-heron",
797
- "Wants to run: rm -rf /workspace/harbor/node_modules",
798
- void 0,
799
- { state: "dismissed" }
800
- ]
801
- ];
802
- var attachmentsMessage = {
803
- id: "k-u2",
804
- role: "user",
805
- text: "Here is the mockup, my notes and the old spec.",
806
- createdAt: at(4),
807
- attachments: [
808
- {
809
- id: "k-a1",
810
- name: "forecast-card.png",
811
- kind: "image",
812
- mimeType: "image/png",
813
- size: 48211,
814
- url: picture("Mockup", "#f5a623", "#d0021b", 480, 320)
815
- },
816
- {
817
- id: "k-a2",
818
- name: "notes.txt",
819
- kind: "text",
820
- mimeType: "text/plain",
821
- size: 214,
822
- text: "Show \xB0C first.\nRound to whole degrees.\nKeep the summary under 60 characters."
823
- },
824
- {
825
- id: "k-a3",
826
- name: "spec-v1.pdf",
827
- kind: "file",
828
- mimeType: "application/pdf",
829
- size: 1204331,
830
- path: "/home/user/downloads/spec-v1.pdf"
831
- },
832
- {
833
- id: "k-a4",
834
- name: "UPSTREAM_TOKEN",
835
- kind: "secret",
836
- mimeType: "application/octet-stream",
837
- size: 0
838
- },
839
- {
840
- id: "k-a5",
841
- name: "recording.mov",
842
- kind: "file",
843
- mimeType: "video/quicktime",
844
- size: 98304e3,
845
- error: "Too large: attachments are limited to 25 MB"
846
- }
847
- ]
848
- };
849
- var showcaseAgent = {
850
- id: "cone-kitchen",
851
- name: "kitchen-sink",
852
- kind: "cone",
853
- parentId: null,
854
- status: "idle",
855
- model: "claude-opus-5-5",
856
- contextFill: 0.47,
857
- unread: 0
858
- };
859
- function opening() {
860
- return [
861
- {
862
- id: "k-u1",
863
- role: "user",
864
- text: "Give me the full tour of harbor, everything you can show.",
865
- createdAt: at(0)
866
- },
867
- {
868
- id: "k-m1",
869
- role: "assistant",
870
- status: "done",
871
- createdAt: at(1),
872
- model: "claude-sonnet-5-5",
873
- usage: { input: 18204, output: 912, cost: 0.31 },
874
- parts: [
875
- {
876
- type: "thinking",
877
- text: "Start with the shape of the API, then show the pieces one kind at a time."
878
- },
879
- { type: "text", text: markdown }
880
- ]
881
- },
882
- attachmentsMessage,
883
- {
884
- id: "k-m2",
885
- role: "assistant",
886
- status: "done",
887
- createdAt: at(5),
888
- model: "claude-sonnet-5-5",
889
- parts: [
890
- {
891
- type: "text",
892
- text: "Mockup, notes and spec received. The recording was too large to attach. Here are the current screens and the alert sound:"
893
- },
894
- {
895
- type: "media",
896
- items: [
897
- {
898
- kind: "image",
899
- src: picture("Forecast card", "#3b63fb", "#7a5af8"),
900
- alt: "The forecast card in light mode"
901
- },
902
- {
903
- kind: "image",
904
- src: picture("Dark card", "#1d1d1d", "#3b63fb"),
905
- alt: "The forecast card in dark mode"
906
- },
907
- {
908
- kind: "image",
909
- src: picture("Phone", "#0a7a43", "#12b886", 360, 640),
910
- alt: "The forecast card on a phone"
911
- },
912
- {
913
- kind: "video",
914
- src: "",
915
- poster: picture("\u25B6 Walkthrough", "#292929", "#717171"),
916
- alt: "A walkthrough of the forecast page"
917
- },
918
- { kind: "audio", src: tone(), alt: "The storm alert sound" }
919
- ]
920
- }
921
- ]
922
- },
923
- { id: "k-u3", role: "user", text: "Show me every tool you used.", createdAt: at(8) },
924
- {
925
- id: "k-m3",
926
- role: "assistant",
927
- status: "done",
928
- createdAt: at(9),
929
- model: "claude-sonnet-5-5",
930
- parts: [
931
- { type: "text", text: "Every tool from today\u2019s run, in order:" },
932
- ...toolShapes.map((call) => ({ type: "tool", tool: call }))
933
- ]
934
- },
935
- {
936
- id: "k-tool1",
937
- role: "tool",
938
- createdAt: at(12),
939
- tool: tool(
940
- "k-t15",
941
- "bash",
942
- "You ran a command",
943
- "git log --oneline -3",
944
- "a1b2c3d fix: expire entries from the previous day\ne4f5a6b feat: retry upstream timeouts\n0c9d8e7 chore: update wrangler"
945
- )
946
- }
947
- ];
948
- }
949
- function runs() {
950
- return [
951
- {
952
- id: "k-u6",
953
- role: "user",
954
- text: "Get the forecast docs ready for the Celsius release.",
955
- createdAt: at(13)
956
- },
957
- {
958
- id: "k-m8",
959
- role: "assistant",
960
- status: "done",
961
- createdAt: at(13.1),
962
- model: "claude-sonnet-5-5",
963
- parts: [
964
- { type: "text", text: "Checking what the docs and the API say today." },
965
- ...[
966
- tool(
967
- "k-r1",
968
- "bash",
969
- "Ask the API for Lisbon",
970
- "curl -s https://api.example.com/v2/forecast?city=Lisbon",
971
- '{ "city": "Lisbon", "high": 71, "low": 58, "unit": "F" }'
972
- ),
973
- tool(
974
- "k-r2",
975
- "bash",
976
- "Read the forecast page",
977
- "cat /workspace/harbor/docs/forecast.md",
978
- "# Forecast\n\nTemperatures are in Fahrenheit."
979
- ),
980
- tool("k-r3", "bash", "See what changed", "git status --short", " M src/lib/units.ts"),
981
- tool(
982
- "k-r4",
983
- "read_file",
984
- "Read the units helper",
985
- "/workspace/harbor/src/lib/units.ts",
986
- "export function toCelsius(f: number): number {\u2026}",
987
- { paths: ["/workspace/harbor/src/lib/units.ts"] }
988
- )
989
- ].map((call) => ({ type: "tool", tool: call })),
990
- {
991
- type: "text",
992
- text: "The page still says Fahrenheit. Updating it, then building and testing."
993
- },
994
- ...[
995
- tool(
996
- "k-r5",
997
- "edit_file",
998
- "Switch the page to Celsius",
999
- "/workspace/harbor/docs/forecast.md",
1000
- "Edited 1 line",
1001
- {
1002
- paths: ["/workspace/harbor/docs/forecast.md"],
1003
- diff: {
1004
- before: "# Forecast\n\nTemperatures are in Fahrenheit.\n",
1005
- after: "# Forecast\n\nTemperatures are in Celsius.\n"
1006
- }
1007
- }
1008
- ),
1009
- tool("k-r6", "bash", "Build the site", "npm run build", "Built 14 pages in 2.1s", {
1010
- meta: "timeout 120s"
1011
- }),
1012
- tool(
1013
- "k-r7",
1014
- "bash",
1015
- "Run the unit tests",
1016
- "npx vitest run src/lib/units.test.ts",
1017
- "FAIL src/lib/units.test.ts > rounds half to even\nExpected 22, received 21",
1018
- {
1019
- status: "error",
1020
- notes: [{ severity: "error", text: "Exited with code 1" }]
1021
- }
1022
- ),
1023
- tool(
1024
- "k-r8",
1025
- "bash",
1026
- "Open the release pull request",
1027
- 'gh pr create --repo https://git.example.com/example/harbor --title "Celsius docs"',
1028
- "Stopped before the tests pass",
1029
- { status: "cancelled" }
1030
- ),
1031
- tool("k-r9", "bash", "Watch the preview logs", "wrangler tail --env preview", "", {
1032
- status: "running"
1033
- })
1034
- ].map((call) => ({ type: "tool", tool: call })),
1035
- {
1036
- type: "text",
1037
- text: "One test fails on rounding, so the pull request waits for the fix."
1038
- }
1039
- ]
1040
- },
1041
- {
1042
- id: "k-tool2",
1043
- role: "tool",
1044
- createdAt: at(13.5),
1045
- tool: tool(
1046
- "k-r10",
1047
- "bash",
1048
- "Check the preview port",
1049
- "lsof -i :8787",
1050
- "workerd 4120 harbor 12u IPv4 TCP localhost:8787 (LISTEN)"
1051
- )
1052
- }
1053
- ];
1054
- }
1055
- function work() {
1056
- return [
1057
- {
1058
- id: "k-m4",
1059
- role: "assistant",
1060
- status: "done",
1061
- createdAt: at(14),
1062
- model: "claude-sonnet-5-5",
1063
- parts: [
1064
- { type: "text", text: "Here is where things stand." },
1065
- { type: "sprinkle", sprinkle: "status" },
1066
- {
1067
- type: "delegation",
1068
- kind: "scoop",
1069
- scoop: "docs-pass",
1070
- text: "Started a scoop to update the docs"
1071
- },
1072
- {
1073
- type: "delegation",
1074
- kind: "feed",
1075
- scoop: "docs-pass",
1076
- text: "Handed over the new screenshots"
1077
- },
1078
- {
1079
- type: "delegation",
1080
- kind: "sprinkle",
1081
- scoop: "suggestions",
1082
- text: "Opened the suggestions sprinkle"
1083
- },
1084
- { type: "delegation", kind: "drop", scoop: "amber-heron", text: "Wrapped up amber-heron" }
1085
- ]
1086
- },
1087
- {
1088
- id: "k-m5",
1089
- role: "assistant",
1090
- status: "done",
1091
- createdAt: at(18),
1092
- model: "claude-sonnet-5-5",
1093
- parts: [
1094
- { type: "text", text: "Three decisions from earlier:" },
1095
- {
1096
- type: "question",
1097
- question: {
1098
- id: "k-q1",
1099
- kind: "yes-no",
1100
- question: "Tag 1.9.0 after the merge?",
1101
- options: [],
1102
- state: "answered",
1103
- answer: "Yes"
1104
- }
1105
- },
1106
- {
1107
- type: "question",
1108
- question: {
1109
- id: "k-q2",
1110
- kind: "text",
1111
- question: "What should the release be called?",
1112
- options: [],
1113
- state: "inert"
1114
- }
1115
- },
1116
- {
1117
- type: "question",
1118
- question: {
1119
- id: "k-q3",
1120
- kind: "choice",
1121
- question: "Where should the cache live?",
1122
- options: ["Keep it in memory", "Move it to KV", "Decide after the load test"],
1123
- state: "open"
1124
- }
1125
- }
1126
- ]
1127
- }
1128
- ];
1129
- }
1130
- function events() {
1131
- return [
1132
- {
1133
- id: "k-s1",
1134
- role: "system",
1135
- kind: "compaction",
1136
- title: "Context compacted",
1137
- text: "58 earlier messages were summarized.",
1138
- trigger: "threshold",
1139
- state: "summarized",
1140
- createdAt: at(1440)
1141
- },
1142
- {
1143
- id: "k-s2",
1144
- role: "system",
1145
- kind: "compaction",
1146
- title: "Compaction failed, transcript truncated",
1147
- text: "The summary failed, so the oldest 20 messages were dropped instead.",
1148
- trigger: "overflow",
1149
- state: "fallback",
1150
- createdAt: at(1441)
1151
- },
1152
- ...licks.map(
1153
- ([channel, title, text, body, extra], index2) => ({
1154
- id: `k-l${index2 + 1}`,
1155
- role: "lick",
1156
- channel,
1157
- title,
1158
- text,
1159
- createdAt: at(1445 + index2),
1160
- ...body ? { body } : {},
1161
- ...extra
1162
- })
1163
- ),
1164
- {
1165
- id: "k-u4",
1166
- role: "user",
1167
- text: "Actually, stop the deploy, staging is frozen today.",
1168
- mode: "steer",
1169
- createdAt: at(1470)
1170
- },
1171
- {
1172
- id: "k-m6",
1173
- role: "assistant",
1174
- status: "stopped",
1175
- createdAt: at(1470),
1176
- model: "claude-haiku-4-5",
1177
- parts: [{ type: "text", text: "Stopping the staging deploy and leaving" }]
1178
- },
1179
- {
1180
- id: "k-u5",
1181
- role: "user",
1182
- text: "Update the forecast page to Celsius and use the new screenshots.",
1183
- from: "harbor",
1184
- createdAt: at(1472)
1185
- },
1186
- {
1187
- id: "k-m7",
1188
- role: "assistant",
1189
- status: "error",
1190
- createdAt: at(1475),
1191
- model: "claude-haiku-4-5",
1192
- parts: [
1193
- {
1194
- type: "thinking",
1195
- text: "The model rejected the request because the context is too large."
1196
- },
1197
- {
1198
- type: "error",
1199
- message: "The request is too large for this model.",
1200
- detail: "The model returned 413: the request is larger than its context window.",
1201
- action: "change-model"
1202
- }
1203
- ]
1204
- },
1205
- {
1206
- id: "k-s3",
1207
- role: "system",
1208
- kind: "error",
1209
- title: "docs-pass failed",
1210
- text: "The Adobe session expired. Log in again to continue.",
1211
- action: "login",
1212
- account: "ai-adobe",
1213
- createdAt: at(1476)
1214
- },
1215
- {
1216
- id: "k-s4",
1217
- role: "system",
1218
- kind: "error",
1219
- title: "Rate limited",
1220
- text: "Anthropic answered 429. Retrying in 30 seconds.",
1221
- action: "retry",
1222
- createdAt: at(1477)
1223
- },
1224
- {
1225
- id: "k-s5",
1226
- role: "system",
1227
- kind: "notice",
1228
- title: "Model changed",
1229
- text: "to Claude Opus 5.5 (Anthropic)",
1230
- createdAt: at(1478)
1231
- }
1232
- ];
1233
- }
1234
- function showcase() {
1235
- return [...opening(), ...runs(), ...work(), ...events()];
1236
- }
1237
- function showcaseQueue() {
1238
- return [
1239
- {
1240
- id: "k-q-1",
1241
- role: "user",
1242
- text: "Then open a pull request for the docs.",
1243
- createdAt: at(1480),
1244
- queued: true,
1245
- mode: "queue"
1246
- },
1247
- {
1248
- id: "k-q-2",
1249
- role: "user",
1250
- text: "And post the link in the release channel.",
1251
- createdAt: at(1481),
1252
- queued: true,
1253
- mode: "queue"
1254
- }
1255
- ];
1256
- }
1257
-
1258
- // src/dummy/fixtures.ts
1259
- var cacheBefore = `export interface Entry<T> {
1260
- value: T;
1261
- storedAt: number;
1262
- }
1263
-
1264
- const TTL = 60 * 60 * 1000;
1265
-
1266
- export class ForecastCache<T> {
1267
- #entries = new Map<string, Entry<T>>();
1268
-
1269
- get(key: string, now = Date.now()): T | undefined {
1270
- const entry = this.#entries.get(key);
1271
- if (!entry) return undefined;
1272
- const day = new Date(entry.storedAt).getDate();
1273
- if (day !== new Date(now).getDate()) return entry.value;
1274
- if (now - entry.storedAt > TTL) return undefined;
1275
- return entry.value;
1276
- }
1277
-
1278
- set(key: string, value: T, now = Date.now()): void {
1279
- this.#entries.set(key, { value, storedAt: now });
1280
- }
1281
- }
1282
- `;
1283
- var cacheAfter = `export interface Entry<T> {
1284
- value: T;
1285
- storedAt: number;
1286
- }
1287
-
1288
- const TTL = 60 * 60 * 1000;
1289
-
1290
- export class ForecastCache<T> {
1291
- #entries = new Map<string, Entry<T>>();
1292
-
1293
- get(key: string, now = Date.now()): T | undefined {
1294
- const entry = this.#entries.get(key);
1295
- if (!entry) return undefined;
1296
- if (dayOf(entry.storedAt) !== dayOf(now)) {
1297
- this.#entries.delete(key);
1298
- return undefined;
1299
- }
1300
- if (now - entry.storedAt > TTL) return undefined;
1301
- return entry.value;
1302
- }
1303
-
1304
- set(key: string, value: T, now = Date.now()): void {
1305
- this.#entries.set(key, { value, storedAt: now });
1306
- }
1307
- }
1308
-
1309
- function dayOf(time: number): string {
1310
- return new Date(time).toISOString().slice(0, 10);
1311
- }
1312
- `;
1313
- var retry = `export async function retry<T>(task: () => Promise<T>, attempts = 3, wait = 250): Promise<T> {
1314
- let last: unknown;
1315
- for (let attempt = 0; attempt < attempts; attempt++) {
1316
- try {
1317
- return await task();
1318
- } catch (error) {
1319
- last = error;
1320
- await new Promise((resolve) => setTimeout(resolve, wait * 2 ** attempt));
1321
- }
1322
- }
1323
- throw last;
1324
- }
1325
- `;
1326
- var legacyXml = `export function toXml(forecast: { city: string; high: number; low: number }): string {
1327
- return \`<forecast city="\${forecast.city}"><high>\${forecast.high}</high><low>\${forecast.low}</low></forecast>\`;
1328
- }
1329
- `;
1330
- var forecastBefore = `import { ForecastCache } from '../lib/cache.ts';
1331
- import { toCelsius } from '../lib/units.ts';
1332
-
1333
- const cache = new ForecastCache<Forecast>();
1334
-
1335
- export interface Forecast {
1336
- city: string;
1337
- high: number;
1338
- low: number;
1339
- summary: string;
1340
- }
1341
-
1342
- export async function forecast(city: string, upstream: typeof fetch = fetch): Promise<Forecast> {
1343
- const cached = cache.get(city);
1344
- if (cached) return cached;
1345
- const response = await upstream(\`https://api.example.com/v2/forecast?city=\${encodeURIComponent(city)}\`);
1346
- const body = await response.json();
1347
- const result = {
1348
- city,
1349
- high: toCelsius(body.daily.max),
1350
- low: toCelsius(body.daily.min),
1351
- summary: body.daily.summary,
1352
- };
1353
- cache.set(city, result);
1354
- return result;
1355
- }
1356
- `;
1357
- var forecastAfter = forecastBefore.replace(
1358
- "import { toCelsius } from '../lib/units.ts';",
1359
- "import { retry } from '../lib/retry.ts';\nimport { toCelsius } from '../lib/units.ts';"
1360
- ).replace("const response = await upstream(", "const response = await retry(() =>\n upstream(").replace("(city)}`);", "(city)}`)\n );");
1361
- var units = `export function toCelsius(fahrenheit: number): number {
1362
- return Math.round(((fahrenheit - 32) * 5) / 9);
1363
- }
1364
-
1365
- export function toFahrenheit(celsius: number): number {
1366
- return Math.round((celsius * 9) / 5 + 32);
1367
- }
1368
- `;
1369
- var unitsTest = `import assert from 'node:assert/strict';
1370
- import { test } from 'node:test';
1371
- import { toCelsius, toFahrenheit } from '../src/lib/units.ts';
1372
-
1373
- test('converts both ways', () => {
1374
- assert.equal(toCelsius(212), 100);
1375
- assert.equal(toFahrenheit(0), 32);
1376
- });
1377
- `;
1378
- var index = `import { forecast } from './routes/forecast.ts';
1379
-
1380
- export default {
1381
- async fetch(request: Request): Promise<Response> {
1382
- const url = new URL(request.url);
1383
- if (url.pathname === '/health') return new Response('ok');
1384
- const city = url.searchParams.get('city');
1385
- if (!city) return Response.json({ error: 'city is required' }, { status: 400 });
1386
- return Response.json(await forecast(city));
1387
- },
1388
- };
1389
- `;
1390
- var readme = `# harbor
1391
-
1392
- A small forecast API that sits in front of the upstream weather service and caches per city.
1393
-
1394
- ## Development
1395
-
1396
- \`\`\`sh
1397
- npm install
1398
- npm test
1399
- npm run dev
1400
- \`\`\`
1401
-
1402
- The worker listens on \`http://localhost:8787\`. Try \`/forecast?city=Lisbon\`.
1403
- `;
1404
- var pkg = `{
1405
- "name": "harbor",
1406
- "private": true,
1407
- "type": "module",
1408
- "scripts": {
1409
- "dev": "wrangler dev",
1410
- "test": "node --test test/"
1411
- },
1412
- "devDependencies": {
1413
- "wrangler": "4.40.0"
1414
- }
1415
- }
1416
- `;
1417
- var skill = `---
1418
- name: release-notes
1419
- description: Draft release notes from merged pull requests since the last tag.
1420
- ---
1421
-
1422
- 1. Run \`collect.jsh\` with the repository and the previous tag.
1423
- 2. Group the pull requests by label: features, fixes, chores.
1424
- 3. Write one sentence per change, in the past tense, without ticket numbers.
1425
- `;
1426
- var collect = `const [repo, since] = process.argv.slice(2);
1427
- const pulls = await gh(\`repos/\${repo}/pulls?state=closed&per_page=100\`);
1428
- for (const pull of pulls.filter((p) => p.merged_at > since)) {
1429
- console.log(\`\${pull.number}\\t\${pull.labels.map((l) => l.name).join(',')}\\t\${pull.title}\`);
1430
- }
1431
- `;
1432
- var memory = `# Shared memory
1433
-
1434
- ## Preferences
1435
- - Keep replies short. Lead with the result, then the evidence.
1436
- - Run the tests before saying something is fixed.
1437
-
1438
- ## Projects
1439
- - harbor: forecast API, deployed as a worker. Cache bugs show up around midnight UTC.
1440
- - release-notes: drafted every Friday from merged pull requests.
1441
- `;
1442
- var standup = `# Standup, 4 October
1443
-
1444
- - harbor: retries for upstream timeouts are in review.
1445
- - Docs: the forecast endpoint page still shows Fahrenheit examples.
1446
- - Next: move the cache to KV once the TTL fix lands.
1447
- `;
1448
- var sample = `{
1449
- "city": "Lisbon",
1450
- "daily": { "max": 77, "min": 61, "summary": "Clear, light wind from the north" }
1451
- }
1452
- `;
1453
- var bashrc = `export PS1='\\u@slicc:\\w\\$ '
1454
- alias ll='ls -la'
1455
- `;
1456
- var suggestions = `${JSON.stringify(
1457
- [
1458
- {
1459
- id: "sug-units",
1460
- kind: "skill",
1461
- title: "Unit conversions",
1462
- body: "You converted Fahrenheit to Celsius by hand in three chats this week. A skill can do it for you.",
1463
- skill: "unit-converter",
1464
- install: "unit-converter from raw.githubusercontent.com/example/skills/main/unit-converter/SKILL.md"
1465
- },
1466
- {
1467
- id: "sug-notes",
1468
- kind: "use-case",
1469
- title: "Release notes from the week",
1470
- body: "You write release notes for harbor every Friday. Let the cone draft them from the commits.",
1471
- prompt: "Draft release notes for harbor from the commits since last Friday."
1472
- },
1473
- {
1474
- id: "sug-cache",
1475
- kind: "tip",
1476
- title: "Name your cache keys",
1477
- body: "Forecast cache keys mix the city and the units. Splitting them makes stale entries easier to find."
1478
- }
1479
- ],
1480
- null,
1481
- 2
1482
- )}
1483
- `;
1484
- var files = {
1485
- "/workspace/harbor/README.md": readme,
1486
- "/workspace/harbor/package.json": pkg,
1487
- "/workspace/harbor/wrangler.toml": 'name = "harbor"\nmain = "src/index.ts"\ncompatibility_date = "2026-09-01"\n',
1488
- "/workspace/harbor/.gitignore": "node_modules/\n.wrangler/\n",
1489
- "/workspace/harbor/src/index.ts": index,
1490
- "/workspace/harbor/src/routes/forecast.ts": forecastBefore,
1491
- "/workspace/harbor/src/lib/cache.ts": cacheBefore,
1492
- "/workspace/harbor/src/lib/units.ts": units,
1493
- "/workspace/harbor/src/legacy/xml.ts": legacyXml,
1494
- "/workspace/harbor/static/radar.png": "\x89PNG\r\n\n",
1495
- "/workspace/harbor/test/units.test.ts": unitsTest,
1496
- "/workspace/skills/release-notes/SKILL.md": skill,
1497
- "/workspace/skills/release-notes/scripts/collect.jsh": collect,
1498
- "/shared/MEMORY.md": memory,
1499
- "/shared/notes/2026-10-04-standup.md": standup,
1500
- "/home/user/.bashrc": bashrc,
1501
- "/home/.gelatiere/suggestions.json": suggestions,
1502
- "/tmp/forecast-sample.json": sample
1503
- };
1504
- var directories = ["/sessions", "/home/user/downloads"];
1505
- var mountPoint = "/mnt/photos";
1506
- var mounted = {
1507
- "README.md": "# Photos\n\nHarbor shots for the forecast pages, one album per season.\n",
1508
- "albums/autumn.json": '{ "title": "Autumn", "shots": ["breakwater-fog", "pier-at-dusk"] }\n',
1509
- "albums/winter.json": '{ "title": "Winter", "shots": ["ice-on-the-buoys"] }\n',
1510
- "captions.txt": "breakwater-fog: low cloud over the outer wall\npier-at-dusk: lamps on, tide out\n"
1511
- };
1512
- var pending = [
1513
- {
1514
- path: "/workspace/harbor/src/lib/cache.ts",
1515
- status: "modified",
1516
- before: cacheBefore,
1517
- after: cacheAfter,
1518
- agentId: "cone-harbor"
1519
- },
1520
- {
1521
- path: "/workspace/harbor/src/lib/retry.ts",
1522
- status: "added",
1523
- before: null,
1524
- after: retry,
1525
- agentId: "scoop-otter"
1526
- },
1527
- {
1528
- path: "/workspace/harbor/src/routes/forecast.ts",
1529
- status: "modified",
1530
- before: forecastBefore,
1531
- after: forecastAfter,
1532
- agentId: "scoop-otter"
1533
- },
1534
- {
1535
- path: "/workspace/harbor/src/legacy/xml.ts",
1536
- status: "deleted",
1537
- before: legacyXml,
1538
- after: null,
1539
- agentId: "cone-harbor"
1540
- },
1541
- {
1542
- path: "/workspace/harbor/static/radar.png",
1543
- status: "modified",
1544
- before: null,
1545
- after: null,
1546
- agentId: "scoop-otter"
1547
- }
1548
- ];
1549
- var skillEdit = {
1550
- path: "/workspace/skills/release-notes/SKILL.md",
1551
- status: "modified",
1552
- before: skill,
1553
- after: `${skill}4. Link each change to its pull request.
1554
- `,
1555
- agentId: null
1556
- };
1557
- var models = [
1558
- { id: "claude-opus-5-5", label: "Claude Opus 5.5", provider: "Anthropic", images: true },
1559
- { id: "claude-sonnet-5-5", label: "Claude Sonnet 5.5", provider: "Anthropic", images: true },
1560
- { id: "claude-haiku-4-5", label: "Claude Haiku 4.5", provider: "Anthropic", images: true },
1561
- { id: "local-small", label: "Local (ort-llama)", provider: "This browser", images: false },
1562
- { id: "local-guard", label: "Local guard", provider: "This browser", kind: "classifier" },
1563
- { id: "local-tiny", label: "Local tiny (no tools)", provider: "This browser", tools: false }
1564
- ];
1565
- var laterModels = [
1566
- { id: "gpt-6", label: "GPT-6", provider: "OpenAI", images: true },
1567
- { id: "gpt-6-mini", label: "GPT-6 mini", provider: "OpenAI", images: true, default: true }
1568
- ];
1569
- var defaults = {
1570
- color: "system",
1571
- model: "claude-sonnet-5-5",
1572
- thinking: "medium",
1573
- sendOnEnter: true,
1574
- pushToTalk: false,
1575
- showThinking: true,
1576
- diffStyle: "unified"
1577
- };
1578
- var accounts = [
1579
- { id: "anthropic", provider: "Anthropic", identity: "API key ending 3f2a", status: "connected" },
1580
- { id: "github", provider: "GitHub", identity: "@example-dev", status: "connected" },
1581
- { id: "adobe", provider: "Adobe", identity: "dev@example.com", status: "expired" },
1582
- {
1583
- id: "ai-adobe",
1584
- provider: "Adobe AI",
1585
- identity: "harbor-ops@example.com",
1586
- status: "expired",
1587
- auth: "oauth"
1588
- },
1589
- { id: "openai", provider: "OpenAI", identity: "", status: "disconnected", auth: "api-key" },
1590
- {
1591
- id: "amazon-bedrock",
1592
- provider: "Amazon Bedrock",
1593
- identity: "",
1594
- status: "disconnected",
1595
- auth: "api-key",
1596
- fields: [
1597
- {
1598
- name: "region",
1599
- label: "Region",
1600
- required: true,
1601
- options: [
1602
- { value: "us-east-1", label: "US East (N. Virginia)" },
1603
- { value: "us-west-2", label: "US West (Oregon)" },
1604
- { value: "eu-central-1", label: "Europe (Frankfurt)" },
1605
- { value: "ap-northeast-1", label: "Asia Pacific (Tokyo)" }
1606
- ],
1607
- value: "us-west-2"
1608
- }
1609
- ]
1610
- },
1611
- {
1612
- id: "mcp:docs",
1613
- provider: "docs",
1614
- identity: "docs.example",
1615
- status: "connected",
1616
- auth: "api-key",
1617
- group: "mcp",
1618
- secret: "token"
1619
- },
1620
- {
1621
- id: "mcp:tickets",
1622
- provider: "tickets",
1623
- identity: "tickets.example",
1624
- status: "expired",
1625
- auth: "api-key",
1626
- group: "mcp",
1627
- secret: "token"
1628
- },
1629
- {
1630
- id: "mcp:design",
1631
- provider: "design",
1632
- identity: "design.example",
1633
- status: "disconnected",
1634
- auth: "oauth",
1635
- group: "mcp"
1636
- }
1637
- ];
1638
- var agents = [
1639
- {
1640
- id: "cone-sliccy",
1641
- name: "sliccy",
1642
- kind: "cone",
1643
- parentId: null,
1644
- status: "idle",
1645
- model: "claude-sonnet-5-5",
1646
- contextFill: 0.21,
1647
- unread: 0
1648
- },
1649
- showcaseAgent,
1650
- {
1651
- id: "cone-harbor",
1652
- name: "harbor",
1653
- kind: "cone",
1654
- parentId: null,
1655
- status: "idle",
1656
- model: "claude-opus-5-5",
1657
- contextFill: 0.38,
1658
- unread: 0
1659
- },
1660
- {
1661
- id: "scoop-otter",
1662
- name: "quiet-otter",
1663
- kind: "scoop",
1664
- parentId: "cone-harbor",
1665
- status: "working",
1666
- model: "claude-haiku-4-5",
1667
- contextFill: 0.12,
1668
- unread: 0
1669
- },
1670
- {
1671
- id: "scoop-heron",
1672
- name: "amber-heron",
1673
- kind: "scoop",
1674
- parentId: "cone-harbor",
1675
- status: "idle",
1676
- model: "claude-haiku-4-5",
1677
- contextFill: 0.04,
1678
- unread: 0
1679
- },
1680
- {
1681
- id: "cone-release",
1682
- name: "release-notes",
1683
- kind: "cone",
1684
- parentId: null,
1685
- status: "idle",
1686
- model: "claude-sonnet-5-5",
1687
- contextFill: 0.7,
1688
- unread: 1
1689
- },
1690
- {
1691
- id: "cone-triage",
1692
- name: "inbox-triage",
1693
- kind: "cone",
1694
- parentId: null,
1695
- status: "waiting",
1696
- model: "claude-sonnet-5-5",
1697
- contextFill: 0.95,
1698
- unread: 2
1699
- },
1700
- {
1701
- id: "scoop-wren",
1702
- name: "tidal-wren",
1703
- kind: "scoop",
1704
- parentId: "cone-sliccy",
1705
- status: "idle",
1706
- model: "claude-haiku-4-5",
1707
- contextFill: 0.02,
1708
- unread: 0
1709
- },
1710
- {
1711
- id: "cone-tides",
1712
- name: "tide-tables",
1713
- kind: "cone",
1714
- parentId: null,
1715
- status: "idle",
1716
- model: "claude-sonnet-5-5",
1717
- contextFill: 0.31,
1718
- unread: 0,
1719
- frozen: true
1720
- }
1721
- ];
1722
- var start2 = Date.UTC(2026, 9, 5, 8, 30);
1723
- var at2 = (minutes2) => start2 + minutes2 * 6e4;
1724
- var queues = { "cone-kitchen": showcaseQueue() };
1725
- var conversations = {
1726
- "cone-kitchen": showcase(),
1727
- "cone-sliccy": [
1728
- {
1729
- id: "m-s0",
1730
- role: "assistant",
1731
- status: "done",
1732
- createdAt: at2(-24 * 60),
1733
- parts: [
1734
- {
1735
- type: "text",
1736
- text: "Hi, I am sliccy. Tell me a little about yourself, and I will set things up for you."
1737
- },
1738
- { type: "sprinkle", sprinkle: "welcome" }
1739
- ]
1740
- },
1741
- {
1742
- id: "m-s1",
1743
- role: "user",
1744
- text: "What is on my plate today?",
1745
- createdAt: at2(0)
1746
- },
1747
- {
1748
- id: "m-s2",
1749
- role: "assistant",
1750
- status: "done",
1751
- createdAt: at2(1),
1752
- parts: [
1753
- {
1754
- type: "tool",
1755
- tool: {
1756
- id: "t-s1",
1757
- name: "read_file",
1758
- title: "Read the standup notes",
1759
- input: "/shared/notes/2026-10-04-standup.md",
1760
- output: standup,
1761
- status: "done",
1762
- paths: ["/shared/notes/2026-10-04-standup.md"]
1763
- }
1764
- },
1765
- {
1766
- type: "text",
1767
- text: "Three things carry over from yesterday:\n\n1. **harbor**: the retry change is in review, and the midnight cache bug is still open.\n2. **Docs**: the forecast page still shows Fahrenheit examples.\n3. **release-notes** has a draft waiting for you.\n\nThe `harbor` cone is the one to start with."
1768
- }
1769
- ]
1770
- }
1771
- ],
1772
- "cone-harbor": [
1773
- {
1774
- id: "m-h1",
1775
- role: "lick",
1776
- channel: "webhook",
1777
- title: "GitHub \xB7 issue opened",
1778
- text: "example/harbor#57: Forecast stays on yesterday after midnight UTC",
1779
- createdAt: at2(2)
1780
- },
1781
- {
1782
- id: "m-h2",
1783
- role: "user",
1784
- text: "The forecast endpoint serves stale data after midnight UTC. Find out why and fix it.",
1785
- createdAt: at2(3)
1786
- },
1787
- {
1788
- id: "m-h3",
1789
- role: "assistant",
1790
- status: "done",
1791
- createdAt: at2(4),
1792
- parts: [
1793
- {
1794
- type: "thinking",
1795
- text: "Stale after midnight points at the cache expiry. Check how the cache compares days."
1796
- },
1797
- {
1798
- type: "tool",
1799
- tool: {
1800
- id: "t-h1",
1801
- name: "bash",
1802
- title: "Search for the cache expiry",
1803
- input: 'rg -n "getDate|TTL" src',
1804
- output: "src/lib/cache.ts:6:const TTL = 60 * 60 * 1000;\nsrc/lib/cache.ts:14: const day = new Date(entry.storedAt).getDate();\nsrc/lib/cache.ts:16: if (now - entry.storedAt > TTL) return undefined;",
1805
- status: "done",
1806
- paths: ["/workspace/harbor/src/lib/cache.ts"]
1807
- }
1808
- },
1809
- {
1810
- type: "tool",
1811
- tool: {
1812
- id: "t-h2",
1813
- name: "read_file",
1814
- title: "Read the cache",
1815
- input: "/workspace/harbor/src/lib/cache.ts",
1816
- output: cacheBefore,
1817
- status: "done",
1818
- paths: ["/workspace/harbor/src/lib/cache.ts"]
1819
- }
1820
- },
1821
- {
1822
- type: "tool",
1823
- tool: {
1824
- id: "t-h3",
1825
- name: "edit_file",
1826
- title: "Expire entries from the previous day",
1827
- input: "/workspace/harbor/src/lib/cache.ts",
1828
- output: "Replaced 1 block (4 lines \u2192 7 lines), added dayOf()",
1829
- status: "done",
1830
- paths: ["/workspace/harbor/src/lib/cache.ts"],
1831
- diff: { before: cacheBefore, after: cacheAfter }
1832
- }
1833
- },
1834
- {
1835
- type: "tool",
1836
- tool: {
1837
- id: "t-h4",
1838
- name: "bash",
1839
- title: "Run the tests",
1840
- input: "npm test",
1841
- meta: "timeout 120s",
1842
- output: "> harbor@0.0.0 test\n> node --test test/\n\n\u2714 converts both ways (0.6ms)\n\u2714 expires entries from the previous day (0.4ms)\n\u2139 tests 2\n\u2139 pass 2\n\u2139 fail 0",
1843
- status: "done",
1844
- paths: []
1845
- }
1846
- },
1847
- {
1848
- type: "text",
1849
- text: "Found it. `ForecastCache.get` compared **local** calendar days, and when the day changed it returned the old entry instead of dropping it:\n\n```ts\nif (day !== new Date(now).getDate()) return entry.value;\n```\n\nI changed it to compare UTC dates and delete the entry, so the first request after midnight goes upstream. The tests pass.\n\n| | Before | After |\n| --- | --- | --- |\n| Day compared | local `getDate()` | UTC `toISOString()` |\n| On a new day | returns stale entry | deletes and refetches |\n\nquiet-otter is adding retries for upstream timeouts in a scoop."
1850
- },
1851
- {
1852
- type: "delegation",
1853
- kind: "scoop",
1854
- scoop: "quiet-otter",
1855
- text: "Started a scoop to add retries around the upstream fetch"
1856
- }
1857
- ]
1858
- },
1859
- {
1860
- id: "m-h4",
1861
- role: "lick",
1862
- channel: "scoop-notify",
1863
- title: "quiet-otter",
1864
- text: "Started: add retries with backoff around the upstream fetch",
1865
- createdAt: at2(9)
1866
- }
1867
- ],
1868
- "scoop-otter": [
1869
- {
1870
- id: "m-o1",
1871
- role: "user",
1872
- origin: "agent",
1873
- from: "harbor",
1874
- text: "Wrap the upstream fetch in src/routes/forecast.ts with three retries and exponential backoff.",
1875
- createdAt: at2(9)
1876
- },
1877
- {
1878
- id: "m-o2",
1879
- role: "assistant",
1880
- status: "done",
1881
- createdAt: at2(10),
1882
- parts: [
1883
- {
1884
- type: "tool",
1885
- tool: {
1886
- id: "t-o1",
1887
- name: "write_file",
1888
- title: "Add retry()",
1889
- input: "/workspace/harbor/src/lib/retry.ts",
1890
- output: "Wrote 12 lines",
1891
- status: "done",
1892
- paths: ["/workspace/harbor/src/lib/retry.ts"]
1893
- }
1894
- },
1895
- {
1896
- type: "tool",
1897
- tool: {
1898
- id: "t-o2",
1899
- name: "edit_file",
1900
- title: "Use retry() for the upstream call",
1901
- input: "/workspace/harbor/src/routes/forecast.ts",
1902
- output: "Replaced 1 block",
1903
- status: "done",
1904
- paths: ["/workspace/harbor/src/routes/forecast.ts"]
1905
- }
1906
- },
1907
- { type: "text", text: "Both edits are in. Running the tests next." }
1908
- ]
1909
- }
1910
- ],
1911
- "scoop-heron": [],
1912
- "scoop-wren": [],
1913
- "cone-tides": [
1914
- {
1915
- id: "m-f1",
1916
- role: "user",
1917
- text: "Add a tide table endpoint next to the forecast, with high and low water per day.",
1918
- createdAt: at2(-2900)
1919
- },
1920
- {
1921
- id: "m-f2",
1922
- role: "assistant",
1923
- status: "done",
1924
- createdAt: at2(-2898),
1925
- parts: [
1926
- {
1927
- type: "text",
1928
- text: "Added `/v1/tides?city=` with the next seven days of high and low water. It reads from the same upstream as the forecast and shares its cache."
1929
- }
1930
- ]
1931
- }
1932
- ],
1933
- "cone-release": [
1934
- {
1935
- id: "m-r1",
1936
- role: "lick",
1937
- channel: "cron",
1938
- title: "Every Friday 09:00",
1939
- text: "Draft the release notes for example/harbor",
1940
- createdAt: at2(-1440)
1941
- },
1942
- {
1943
- id: "m-r2",
1944
- role: "assistant",
1945
- status: "done",
1946
- createdAt: at2(-1438),
1947
- parts: [
1948
- {
1949
- type: "tool",
1950
- tool: {
1951
- id: "t-r1",
1952
- name: "bash",
1953
- title: "Collect merged pull requests",
1954
- input: "collect.jsh example/harbor v1.8.0",
1955
- output: "41 fix Return 400 when the city is missing\n43 feature Add /health\n44 chore Update wrangler to 4.40.0",
1956
- status: "done",
1957
- paths: ["/workspace/skills/release-notes/scripts/collect.jsh"]
1958
- }
1959
- },
1960
- {
1961
- type: "text",
1962
- text: "## harbor 1.9.0\n\n**Features**\n- Added a `/health` endpoint.\n\n**Fixes**\n- Requests without a city now get a 400 instead of a 500.\n\n**Chores**\n- Updated wrangler to 4.40.0."
1963
- }
1964
- ]
1965
- },
1966
- {
1967
- id: "m-r3",
1968
- role: "lick",
1969
- channel: "cron",
1970
- severity: "error",
1971
- title: "Crontab",
1972
- text: "Crontab line 3 is invalid",
1973
- body: "30 25 * * * sweep-drafts\nThe hour is 25. It must be 0 to 23.",
1974
- createdAt: at2(-1430)
1975
- },
1976
- {
1977
- id: "m-r4",
1978
- role: "lick",
1979
- channel: "fswatch",
1980
- severity: "warn",
1981
- title: "/workspace/notes",
1982
- text: "File watch on /workspace/notes stopped; retrying",
1983
- createdAt: at2(-1429)
1984
- },
1985
- {
1986
- id: "m-r5",
1987
- role: "lick",
1988
- channel: "workflow",
1989
- title: "Release report",
1990
- text: "The weekly release report is ready",
1991
- body: "Summary: harbor 1.9.0 shipped three changes this week, the /health endpoint, a 400 for requests without a city and a wrangler update, with no failed deploys, no rollbacks and two flaky test runs in the forecast suite that passed on retry, so the next release can go out on Friday as planned once the docs pass lands.",
1992
- createdAt: at2(-1428)
1993
- }
1994
- ],
1995
- "cone-triage": [
1996
- {
1997
- id: "m-t1",
1998
- role: "system",
1999
- kind: "compaction",
2000
- trigger: "threshold",
2001
- state: "summarized",
2002
- title: "Context compacted",
2003
- text: "41 earlier messages were summarized to stay under the context limit.",
2004
- createdAt: at2(-30)
2005
- },
2006
- {
2007
- id: "m-t2",
2008
- role: "assistant",
2009
- status: "done",
2010
- createdAt: at2(-20),
2011
- parts: [
2012
- {
2013
- type: "text",
2014
- text: "Two messages need a decision from you:\n\n- A vendor asks to move Thursday\u2019s call to Friday.\n- The staging certificate expires in 6 days. Should I open a ticket?"
2015
- }
2016
- ]
2017
- },
2018
- {
2019
- id: "m-t3",
2020
- role: "system",
2021
- kind: "error",
2022
- action: "login",
2023
- title: "Mail connector",
2024
- text: "The connector returned 401. Reconnect the account in Settings.",
2025
- createdAt: at2(-19)
2026
- },
2027
- {
2028
- id: "m-t4",
2029
- role: "system",
2030
- kind: "error",
2031
- action: "login",
2032
- account: "mcp:tickets",
2033
- title: "Tickets connector",
2034
- text: "The tickets server rejected its token.",
2035
- createdAt: at2(-18)
2036
- }
2037
- ]
2038
- };
2039
- var tabs = [
2040
- {
2041
- id: "tab-preview",
2042
- title: "harbor \xB7 localhost",
2043
- url: "http://localhost:8787/forecast?city=Lisbon",
2044
- status: "complete",
2045
- agentId: "cone-harbor"
2046
- },
2047
- {
2048
- id: "tab-docs",
2049
- title: "Forecast API reference",
2050
- url: "https://api.example.com/docs/v2/forecast",
2051
- status: "complete",
2052
- agentId: null,
2053
- favicon: `data:image/svg+xml;charset=utf-8,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect width="16" height="16" rx="3" fill="#7a5af8"/><text x="8" y="12" font-family="sans-serif" font-size="11" font-weight="700" fill="#ffffff" text-anchor="middle">A</text></svg>')}`
2054
- },
2055
- {
2056
- id: "tab-pull",
2057
- title: "Add retries for upstream timeouts \xB7 Pull request #58",
2058
- url: "https://git.example.com/example/harbor/pull/58",
2059
- status: "complete",
2060
- agentId: "scoop-otter",
2061
- favicon: `data:image/svg+xml;charset=utf-8,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect width="16" height="16" rx="3" fill="#0a7a43"/><text x="8" y="12" font-family="sans-serif" font-size="11" font-weight="700" fill="#ffffff" text-anchor="middle">G</text></svg>')}`
2062
- }
2063
- ];
2064
- var terminals = [
2065
- { id: "term-1", title: "bash", cwd: "/workspace/harbor", agentId: null }
2066
- ];
2067
-
2068
534
  // src/dummy/guest.ts
2069
535
  var guestOnly = "a guest can only watch and send messages";
2070
536
  var guestReview = "Messages from guests need a review, and this agent can't review them yet.";
@@ -2096,13 +562,13 @@ var forecastSprinkle = {
2096
562
  html: "<style>body { font-family: var(--s2-font-family); color: var(--s2-content-default); padding: var(--s2-spacing-200) var(--s2-spacing-300); } table { border-collapse: collapse; } td { padding: 4px 12px 4px 0; }</style><table><tr><td>Fri</td><td>21\xB0</td><td>Sunny</td></tr><tr><td>Sat</td><td>19\xB0</td><td>Cloudy</td></tr><tr><td>Sun</td><td>18\xB0</td><td>Showers</td></tr></table><script>window.slicc.lick({ action: 'viewed', data: { rows: 3 } });<\/script>"
2097
563
  };
2098
564
  function guestTranscript(now2 = Date.now(), twin = false) {
2099
- const at3 = (minutes2) => now2 - minutes2 * minute;
565
+ const at = (minutes2) => now2 - minutes2 * minute;
2100
566
  const namesake = twin ? [
2101
567
  {
2102
568
  id: "g-9",
2103
569
  role: "user",
2104
570
  text: "Same name, another seat.",
2105
- createdAt: at3(8),
571
+ createdAt: at(8),
2106
572
  origin: "guest",
2107
573
  from: guestLabel,
2108
574
  seat: "seat-mara-2",
@@ -2114,13 +580,13 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2114
580
  id: "g-1",
2115
581
  role: "user",
2116
582
  text: "Check the Porto forecast endpoint before Mara joins.",
2117
- createdAt: at3(42)
583
+ createdAt: at(42)
2118
584
  },
2119
585
  {
2120
586
  id: "g-2",
2121
587
  role: "assistant",
2122
588
  status: "done",
2123
- createdAt: at3(41),
589
+ createdAt: at(41),
2124
590
  model: "claude-sonnet-5-5",
2125
591
  parts: [
2126
592
  { type: "text", text: "I read the handler and ran its tests." },
@@ -2155,7 +621,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2155
621
  id: "g-3",
2156
622
  role: "user",
2157
623
  text: "Hi! Could you add the weekend to the forecast table?",
2158
- createdAt: at3(30),
624
+ createdAt: at(30),
2159
625
  origin: "guest",
2160
626
  from: guestLabel,
2161
627
  seat: "seat-mara",
@@ -2165,7 +631,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2165
631
  id: "g-4",
2166
632
  role: "assistant",
2167
633
  status: "done",
2168
- createdAt: at3(29),
634
+ createdAt: at(29),
2169
635
  model: "claude-sonnet-5-5",
2170
636
  parts: [
2171
637
  {
@@ -2187,7 +653,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2187
653
  id: "g-5",
2188
654
  role: "user",
2189
655
  text: "Does it cover Lisbon too?",
2190
- createdAt: at3(12),
656
+ createdAt: at(12),
2191
657
  origin: "guest",
2192
658
  from: otherGuest,
2193
659
  seat: "seat-jonas",
@@ -2197,7 +663,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2197
663
  id: "g-6",
2198
664
  role: "assistant",
2199
665
  status: "done",
2200
- createdAt: at3(11),
666
+ createdAt: at(11),
2201
667
  model: "claude-sonnet-5-5",
2202
668
  parts: [
2203
669
  { type: "text", text: "Not yet. I can add it." },
@@ -2221,7 +687,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2221
687
  text: "wants to fetch the Lisbon forecast",
2222
688
  body: "curl -s https://api.example.com/forecast?city=lisbon",
2223
689
  state: "pending",
2224
- createdAt: at3(10),
690
+ createdAt: at(10),
2225
691
  expiresAt: now2 + 20 * minute
2226
692
  },
2227
693
  {
@@ -2231,7 +697,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2231
697
  title: "The model is busy",
2232
698
  text: "The provider asked to slow down.",
2233
699
  action: "retry",
2234
- createdAt: at3(9)
700
+ createdAt: at(9)
2235
701
  },
2236
702
  ...namesake
2237
703
  ];
@@ -2630,14 +1096,14 @@ var importCones = [
2630
1096
  }
2631
1097
  ];
2632
1098
  var idle = { phase: "idle", done: 0, total: 0, text: "" };
2633
- function conversation(id, title, at3) {
1099
+ function conversation(id, title, at) {
2634
1100
  return [
2635
- { id: `${id}-1`, role: "user", text: title, createdAt: at3 },
1101
+ { id: `${id}-1`, role: "user", text: title, createdAt: at },
2636
1102
  {
2637
1103
  id: `${id}-2`,
2638
1104
  role: "assistant",
2639
1105
  status: "done",
2640
- createdAt: at3 + 6e4,
1106
+ createdAt: at + 6e4,
2641
1107
  parts: [
2642
1108
  { type: "text", text: "Imported from SLICC 6. The earlier turns are in the report." }
2643
1109
  ]
@@ -2723,7 +1189,7 @@ var DummyImport = class {
2723
1189
  };
2724
1190
 
2725
1191
  // src/dummy/script.ts
2726
- var units2 = "/workspace/harbor/src/lib/units.ts";
1192
+ var units = "/workspace/harbor/src/lib/units.ts";
2727
1193
  var kelvin = `
2728
1194
  export function toKelvin(celsius: number): number {
2729
1195
  return Math.round((celsius + 273.15) * 100) / 100;
@@ -2770,29 +1236,29 @@ function edit() {
2770
1236
  type: "tool",
2771
1237
  name: "read_file",
2772
1238
  title: "Read the unit helpers",
2773
- input: units2,
1239
+ input: units,
2774
1240
  output: "export function toCelsius(fahrenheit: number): number { \u2026 }\nexport function toFahrenheit(celsius: number): number { \u2026 }",
2775
- paths: [units2],
1241
+ paths: [units],
2776
1242
  ticks: 10
2777
1243
  },
2778
1244
  {
2779
1245
  type: "tool",
2780
1246
  name: "edit_file",
2781
1247
  title: "Add toKelvin()",
2782
- input: units2,
1248
+ input: units,
2783
1249
  output: "Appended 4 lines",
2784
- paths: [units2],
1250
+ paths: [units],
2785
1251
  ticks: 20,
2786
1252
  effect: async ({ files: files3, agentId }) => {
2787
- const before = await files3.read(units2);
2788
- await files3.write(units2, before + kelvin, agentId);
1253
+ const before = await files3.read(units);
1254
+ await files3.write(units, before + kelvin, agentId);
2789
1255
  }
2790
1256
  },
2791
1257
  {
2792
1258
  type: "part",
2793
1259
  part: {
2794
1260
  type: "diff",
2795
- path: units2,
1261
+ path: units,
2796
1262
  before: "export function toFahrenheit(celsius: number): number {\n return Math.round((celsius * 9) / 5 + 32);\n}\n",
2797
1263
  after: `export function toFahrenheit(celsius: number): number {
2798
1264
  return Math.round((celsius * 9) / 5 + 32);
@@ -2973,7 +1439,7 @@ function look(attachments) {
2973
1439
  }
2974
1440
  ];
2975
1441
  }
2976
- var suggestions2 = [
1442
+ var suggestions = [
2977
1443
  [/\b(debug|investigate)\b/, "Add the unit to the cache key"],
2978
1444
  [/\btests?\b/, "Open a pull request with the fix"],
2979
1445
  [/\b(fix|edit|add|change)\b/, "Run the tests"],
@@ -2982,7 +1448,7 @@ var suggestions2 = [
2982
1448
  ];
2983
1449
  function script(prompt, attachments = []) {
2984
1450
  const text = prompt.toLowerCase();
2985
- const suggestion = suggestions2.find(([pattern]) => pattern.test(text))?.[1] ?? "Run the tests";
1451
+ const suggestion = suggestions.find(([pattern]) => pattern.test(text))?.[1] ?? "Run the tests";
2986
1452
  if (attachments.length > 0) return { steps: look(attachments), suggestion };
2987
1453
  if (/\bforbidden\b/.test(text)) return { steps: filtered(), suggestion };
2988
1454
  if (/\b(ask|choose|decide)\b/.test(text)) return { steps: ask(), suggestion };
@@ -3139,7 +1605,7 @@ var DummyAgent = class extends Emitter {
3139
1605
  }
3140
1606
  async #tool(agentId, reply, step, run) {
3141
1607
  this.#status(agentId, "working");
3142
- const tool2 = {
1608
+ const tool = {
3143
1609
  id: this.#id("t"),
3144
1610
  name: step.name,
3145
1611
  title: step.title,
@@ -3148,12 +1614,12 @@ var DummyAgent = class extends Emitter {
3148
1614
  status: "running",
3149
1615
  paths: step.paths
3150
1616
  };
3151
- reply.parts.push({ type: "tool", tool: tool2 });
1617
+ reply.parts.push({ type: "tool", tool });
3152
1618
  this.emit("message", { agentId, message: reply });
3153
1619
  await this.#clock.sleep(step.ticks * run.pace);
3154
1620
  const done = run.stopped ? { status: "cancelled", output: "Stopped" } : { status: "done", output: step.output };
3155
1621
  if (!run.stopped) await step.effect?.({ ...this.#effects, agentId });
3156
- Object.assign(tool2, done);
1622
+ Object.assign(tool, done);
3157
1623
  this.emit("message", { agentId, message: reply });
3158
1624
  }
3159
1625
  async #step(agentId, reply, step, run) {
@@ -3337,9 +1803,9 @@ var DummyAgent = class extends Emitter {
3337
1803
  }
3338
1804
  async rewind(agentId, messageId) {
3339
1805
  const messages = this.#messages.get(agentId);
3340
- const at3 = messages?.findIndex((message) => message.id === messageId) ?? -1;
3341
- if (!messages || at3 < 0) return null;
3342
- const turn = messages.slice(0, at3).findLastIndex((message) => message.role === "user");
1806
+ const at = messages?.findIndex((message) => message.id === messageId) ?? -1;
1807
+ if (!messages || at < 0) return null;
1808
+ const turn = messages.slice(0, at).findLastIndex((message) => message.role === "user");
3343
1809
  if (turn < 0) return null;
3344
1810
  const user = messages[turn];
3345
1811
  const turns = messages.splice(turn).filter((message) => message.role === "user").length;
@@ -5006,17 +3472,17 @@ var DummyFiles = class extends Emitter {
5006
3472
  if (mount.scenario === "fail") throw new Error("The folder couldn\u2019t be mounted.");
5007
3473
  if (point !== void 0 && !this.#needs.has(point))
5008
3474
  throw new Error(`Nothing is waiting for a folder at ${point}.`);
5009
- const at3 = point ?? mount.point;
3475
+ const at = point ?? mount.point;
5010
3476
  const files3 = [];
5011
3477
  for (const [path, text] of Object.entries(mount.files)) {
5012
- const file = `${at3}/${path}`;
3478
+ const file = `${at}/${path}`;
5013
3479
  this.#put(file, text, Date.now());
5014
3480
  files3.push(file);
5015
3481
  }
5016
- this.#mounted.add(at3);
5017
- this.#needs.delete(at3);
3482
+ this.#mounted.add(at);
3483
+ this.#needs.delete(at);
5018
3484
  this.#remount(files3);
5019
- return at3;
3485
+ return at;
5020
3486
  }
5021
3487
  async #eject(path) {
5022
3488
  await this.#clock.sleep();
@@ -5046,29 +3512,29 @@ var DummyMemory = class extends Emitter {
5046
3512
  #next = 1;
5047
3513
  constructor(memories2, scopes = () => [{ id: "global", label: "Everyone" }]) {
5048
3514
  super();
5049
- this.#memories = memories2.map((memory2) => ({ ...memory2 }));
3515
+ this.#memories = memories2.map((memory) => ({ ...memory }));
5050
3516
  this.#scopes = scopes;
5051
3517
  }
5052
3518
  scopes() {
5053
3519
  return this.#scopes();
5054
3520
  }
5055
3521
  list() {
5056
- return this.#memories.map((memory2) => ({ ...memory2 }));
3522
+ return this.#memories.map((memory) => ({ ...memory }));
5057
3523
  }
5058
3524
  save(draft) {
5059
- const memory2 = {
3525
+ const memory = {
5060
3526
  ...draft,
5061
3527
  id: draft.id ?? `mem-new-${this.#next++}`,
5062
3528
  updatedAt: Date.now()
5063
3529
  };
5064
- const index2 = this.#memories.findIndex((candidate) => candidate.id === memory2.id);
5065
- if (index2 < 0) this.#memories.push(memory2);
5066
- else this.#memories[index2] = memory2;
3530
+ const index = this.#memories.findIndex((candidate) => candidate.id === memory.id);
3531
+ if (index < 0) this.#memories.push(memory);
3532
+ else this.#memories[index] = memory;
5067
3533
  this.emit("memories", this.list());
5068
- return { ...memory2 };
3534
+ return { ...memory };
5069
3535
  }
5070
3536
  remove(id) {
5071
- this.#memories = this.#memories.filter((memory2) => memory2.id !== id);
3537
+ this.#memories = this.#memories.filter((memory) => memory.id !== id);
5072
3538
  this.emit("memories", this.list());
5073
3539
  }
5074
3540
  };
@@ -5846,8 +4312,8 @@ var DummyNetwork = class extends Emitter {
5846
4312
  ...device,
5847
4313
  folders: device.folders.map((folder) => {
5848
4314
  const { mounted: _, ...rest } = folder;
5849
- const at3 = mounted2(folder);
5850
- return at3 ? { ...rest, mounted: at3 } : rest;
4315
+ const at = mounted2(folder);
4316
+ return at ? { ...rest, mounted: at } : rest;
5851
4317
  })
5852
4318
  } : device
5853
4319
  );
@@ -6568,9 +5034,9 @@ function packageFixtures(scenario) {
6568
5034
  79e5
6569
5035
  )
6570
5036
  ];
6571
- const at3 = (id) => items.findIndex((item) => item.id === id);
5037
+ const at = (id) => items.findIndex((item) => item.id === id);
6572
5038
  const patch = (id, change) => {
6573
- items[at3(id)] = { ...items[at3(id)], ...change };
5039
+ items[at(id)] = { ...items[at(id)], ...change };
6574
5040
  };
6575
5041
  patch("python", {
6576
5042
  state: "installed",
@@ -7236,6 +5702,8 @@ var DummyVault = class extends Emitter {
7236
5702
  #serial = 0;
7237
5703
  buttons = [];
7238
5704
  puts = [];
5705
+ endpointChanges = [];
5706
+ #refuses;
7239
5707
  cancelled = [];
7240
5708
  imports = [];
7241
5709
  exported = 0;
@@ -7247,6 +5715,16 @@ var DummyVault = class extends Emitter {
7247
5715
  this.#list = { ...list, secrets: [...list.secrets, ...records] };
7248
5716
  this.#time = time;
7249
5717
  this.#available = scenario === "waiting" ? "waiting" : "ready";
5718
+ this.#refuses = scenario === "endpoints-fail";
5719
+ }
5720
+ async endpoints(change) {
5721
+ await this.#time.sleep(5);
5722
+ if (this.#refuses)
5723
+ throw vaultFailure(
5724
+ "EINVAL",
5725
+ "The vault refused that endpoint. Check the address and try again."
5726
+ );
5727
+ this.endpointChanges.push(change);
7250
5728
  }
7251
5729
  status() {
7252
5730
  return this.#available === "waiting" ? null : this.#status;
@@ -7475,6 +5953,13 @@ function vaultAccounts(accounts2) {
7475
5953
  (account) => account.auth === "api-key" || account.id === "github" ? { ...account, store: "vault" } : account
7476
5954
  );
7477
5955
  }
5956
+ function settingsAccounts(accounts2, providers) {
5957
+ const all = accounts2 === "vault" ? vaultAccounts(accounts) : accounts;
5958
+ if (providers === "all") return providerAccounts(all);
5959
+ return all.map(
5960
+ (account) => providers === "none" && account.group !== "mcp" ? { ...account, status: "disconnected", identity: "" } : account
5961
+ );
5962
+ }
7478
5963
  function guestsPort(guests, time) {
7479
5964
  return guests === "off" ? {} : { guests: new DummyGuests(guests, time) };
7480
5965
  }
@@ -7551,14 +6036,13 @@ function createDummyModel({
7551
6036
  settings: new DummySettings(
7552
6037
  defaults,
7553
6038
  providers === "none" ? [...models, ...laterModels] : models,
7554
- (accounts2 === "vault" ? vaultAccounts(accounts) : accounts).map(
7555
- (account) => providers === "none" && account.group !== "mcp" ? { ...account, status: "disconnected", identity: "" } : account
7556
- ),
6039
+ settingsAccounts(accounts2, providers),
7557
6040
  storage,
7558
6041
  time,
7559
6042
  void 0,
7560
6043
  providers === "none",
7561
- login
6044
+ login,
6045
+ providers === "all" ? providerFixtures : void 0
7562
6046
  ),
7563
6047
  memory: new DummyMemory(memories, () => [
7564
6048
  { id: "global", label: "Everyone" },
@@ -7646,6 +6130,9 @@ export {
7646
6130
  pairingCode,
7647
6131
  pairingRefused,
7648
6132
  pairingStopped,
6133
+ providerAccount,
6134
+ providerAccounts,
6135
+ providerFixtures,
7649
6136
  tabsFixtures,
7650
6137
  tailnetFixtures,
7651
6138
  updateFixtures,