@ai-ecoverse/slicc-spectrum 2.5.0 → 2.7.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.
@@ -794,6 +794,135 @@ var DummyBrowser = class extends Emitter {
794
794
  }
795
795
  };
796
796
 
797
+ // src/dummy/capture.ts
798
+ var PNG = Uint8Array.from(
799
+ atob(
800
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
801
+ ),
802
+ (char) => char.charCodeAt(0)
803
+ );
804
+ function denied(what) {
805
+ throw new DOMException(`${what} was denied`, "NotAllowedError");
806
+ }
807
+ function switchKey(kind) {
808
+ return kind === "audio" ? "microphone" : kind === "video" ? "camera" : "screen";
809
+ }
810
+ function allowed(switches, kind) {
811
+ const key = switchKey(kind);
812
+ const found = switches?.list().find((item) => item.key === key);
813
+ return !found || found.on;
814
+ }
815
+ var DummyCapture = class {
816
+ kinds;
817
+ still;
818
+ #live;
819
+ #switches;
820
+ #clock;
821
+ #deny;
822
+ #active = /* @__PURE__ */ new Map();
823
+ #prior = null;
824
+ constructor(scenario, clock2, live, switches) {
825
+ this.#clock = clock2;
826
+ this.#live = live;
827
+ this.#switches = switches;
828
+ this.#deny = scenario === "deny";
829
+ this.kinds = scenario === "audio" ? ["audio"] : ["audio", "video"];
830
+ this.still = () => this.#still();
831
+ if (live) {
832
+ this.#prior = live.act.bind(live);
833
+ live.act = (id) => {
834
+ const session2 = this.#active.get(id);
835
+ if (session2) session2.stop();
836
+ else this.#prior?.(id);
837
+ };
838
+ }
839
+ }
840
+ async record(kind) {
841
+ if (this.#deny || !allowed(this.#switches, kind))
842
+ denied(kind === "audio" ? "Microphone access" : "Camera access");
843
+ if (this.kinds && !this.kinds.includes(kind))
844
+ throw new DOMException(`Recording ${kind} isn\u2019t supported here`, "NotSupportedError");
845
+ const id = `capture-${kind}`;
846
+ if (this.#active.has(id)) throw new DOMException("Already recording", "InvalidStateError");
847
+ let settle;
848
+ let fail;
849
+ let done = false;
850
+ const finished = new Promise((resolve2, reject) => {
851
+ settle = resolve2;
852
+ fail = reject;
853
+ });
854
+ const mimeType = kind === "audio" ? "audio/webm" : "video/webm";
855
+ const name2 = "recording.webm";
856
+ const started = Date.now();
857
+ const item = {
858
+ id,
859
+ kind: kind === "audio" ? "microphone" : "camera",
860
+ label: kind === "audio" ? "Recording microphone" : "Recording camera",
861
+ what: kind === "audio" ? "Desk microphone" : "Face camera",
862
+ asker: "you",
863
+ since: started,
864
+ action: { label: "Stop" }
865
+ };
866
+ const end = (take, error) => {
867
+ if (done) return;
868
+ done = true;
869
+ this.#active.delete(id);
870
+ if (this.#live?.items().some((row) => row.id === id)) this.#prior?.(id);
871
+ if (error) fail(error);
872
+ else if (take) settle(take);
873
+ };
874
+ const session2 = {
875
+ stop: () => end({
876
+ blob: new Blob([PNG], { type: mimeType }),
877
+ mimeType,
878
+ name: name2,
879
+ durationMs: Math.max(0, Date.now() - started)
880
+ }),
881
+ cancel: () => end(null, new DOMException("Recording cancelled", "AbortError"))
882
+ };
883
+ this.#active.set(id, session2);
884
+ this.#live?.add(item);
885
+ return { ...session2, finished };
886
+ }
887
+ async #still() {
888
+ if (this.#deny || !allowed(this.#switches, "screen")) denied("Screen capture");
889
+ await this.#clock.sleep();
890
+ const id = "capture-still";
891
+ if (this.#active.has(id)) throw new DOMException("Already capturing", "InvalidStateError");
892
+ const item = {
893
+ id,
894
+ kind: "screen",
895
+ label: "Taking a photo",
896
+ what: "This screen",
897
+ asker: "you",
898
+ since: Date.now(),
899
+ action: { label: "Cancel" }
900
+ };
901
+ return await new Promise((resolve2, reject) => {
902
+ let done = false;
903
+ const finish = (still, error) => {
904
+ if (done) return;
905
+ done = true;
906
+ this.#active.delete(id);
907
+ if (this.#live?.items().some((row) => row.id === id)) this.#prior?.(id);
908
+ if (error) reject(error);
909
+ else if (still) resolve2(still);
910
+ };
911
+ const abort = () => finish(null, new DOMException("Screenshot cancelled", "AbortError"));
912
+ this.#active.set(id, { stop: abort, cancel: abort });
913
+ this.#live?.add(item);
914
+ void this.#clock.sleep().then(() => {
915
+ if (done) return;
916
+ finish({
917
+ blob: new Blob([PNG], { type: "image/png" }),
918
+ mimeType: "image/png",
919
+ name: "screenshot.png"
920
+ });
921
+ });
922
+ });
923
+ }
924
+ };
925
+
797
926
  // src/dummy/changes.ts
798
927
  var repos = ["/workspace/harbor", "/workspace/skills"];
799
928
  var linkCommand = "curl -fsSL https://get.sliccy.ai/slicc | sh";
@@ -4175,6 +4304,7 @@ var DummyFiles = class extends Emitter {
4175
4304
 
4176
4305
  // src/dummy/live.ts
4177
4306
  function liveFixtures(scenario, now2 = Date.now()) {
4307
+ if (scenario === "empty") return [];
4178
4308
  const screen = {
4179
4309
  id: "live-screen",
4180
4310
  kind: "screen",
@@ -4708,7 +4838,7 @@ var followers = [
4708
4838
  exit: true,
4709
4839
  state: "connected",
4710
4840
  kind: "cli",
4711
- access: { control: true, fixed: true }
4841
+ access: { control: true, browser: true, fixed: true }
4712
4842
  },
4713
4843
  {
4714
4844
  id: "link-pier",
@@ -4720,9 +4850,21 @@ var followers = [
4720
4850
  exit: true,
4721
4851
  state: "connected",
4722
4852
  kind: "cli",
4723
- access: { control: true },
4853
+ access: { control: true, browser: true },
4724
4854
  controlling: "prompt"
4725
4855
  },
4856
+ {
4857
+ id: "link-dock",
4858
+ name: "slicc on dock-builder",
4859
+ host: "dock-builder.slicc.internal",
4860
+ address: "198.18.57.13",
4861
+ mode: "remote",
4862
+ offers: ["http"],
4863
+ exit: false,
4864
+ state: "connected",
4865
+ kind: "cli",
4866
+ access: { control: false, browser: false }
4867
+ },
4726
4868
  {
4727
4869
  id: "link-bay",
4728
4870
  name: "SLICC on bay-laptop",
@@ -4789,9 +4931,9 @@ var outdatedDevice = {
4789
4931
  note: "Update slicc to 1.47.0 or later to share this computer\u2019s browsers."
4790
4932
  };
4791
4933
  var others = linkedDevices.filter((device) => device.id !== pairedDevice.id);
4792
- function grant(device, key, allowed) {
4793
- const access = { ...device.access, [key]: allowed };
4794
- if (key === "view" && !allowed && "control" in access) access.control = false;
4934
+ function grant(device, key, allowed2) {
4935
+ const access = { ...device.access, [key]: allowed2 };
4936
+ if (key === "view" && !allowed2 && "control" in access) access.control = false;
4795
4937
  const next = { ...device, access, asking: device.asking && !access.view };
4796
4938
  if (!access.view && !access.control) next.controlling = void 0;
4797
4939
  else if (!access.control && next.controlling === "prompt") next.controlling = "watch";
@@ -4898,8 +5040,8 @@ var DummyNetwork = class extends Emitter {
4898
5040
  ({ links: this.#links, exit: this.#exit } = linksFixtures(links));
4899
5041
  this.setExit = (exit) => this.#setExit(exit);
4900
5042
  this.unlink = (id) => this.#unlink(id);
4901
- this.setRemoteControl = (id, allowed) => this.#control(id, allowed);
4902
- this.setAccess = (id, key, allowed) => this.#access(id, key, allowed);
5043
+ this.setRemoteControl = (id, allowed2) => this.#control(id, allowed2);
5044
+ this.setAccess = (id, key, allowed2) => this.#access(id, key, allowed2);
4903
5045
  this.rotateJoinUrl = () => this.#rotate();
4904
5046
  this.retryLinks = () => this.#retry();
4905
5047
  this.mountFolder = (source) => this.#mountFolder(source);
@@ -5010,22 +5152,22 @@ var DummyNetwork = class extends Emitter {
5010
5152
  this.#exit = exit;
5011
5153
  this.#emit();
5012
5154
  }
5013
- async #control(id, allowed) {
5155
+ async #control(id, allowed2) {
5014
5156
  await this.#clock.sleep(4);
5015
5157
  const links = this.#links;
5016
5158
  const devices = links.devices.map((device) => {
5017
5159
  if (device.id !== id) return device;
5018
- const next = { ...device, control: { ...device.control, allowed } };
5019
- return allowed ? next : { ...next, controlling: void 0 };
5160
+ const next = { ...device, control: { ...device.control, allowed: allowed2 } };
5161
+ return allowed2 ? next : { ...next, controlling: void 0 };
5020
5162
  });
5021
5163
  this.#links = { ...links, devices };
5022
5164
  this.#emit();
5023
5165
  }
5024
- async #access(id, key, allowed) {
5166
+ async #access(id, key, allowed2) {
5025
5167
  await this.#clock.sleep(4);
5026
5168
  const links = this.#links;
5027
5169
  const devices = links.devices.map(
5028
- (device) => device.id === id ? grant(device, key, allowed) : device
5170
+ (device) => device.id === id ? grant(device, key, allowed2) : device
5029
5171
  );
5030
5172
  this.#links = { ...links, devices };
5031
5173
  this.#emit();
@@ -7537,6 +7679,16 @@ var movedDocs = "https://docs.eu.example/mcp";
7537
7679
  function hinted(login) {
7538
7680
  return login === "code" || login === "url" || login === "lookalike";
7539
7681
  }
7682
+ function capturePorts(capture, live, switches, time) {
7683
+ const livePort = live !== "off" ? new DummyLive(live) : capture === "off" ? void 0 : new DummyLive("empty");
7684
+ const switchPort = switches === "off" ? void 0 : new DummySwitches();
7685
+ const capturePort = capture === "off" ? void 0 : new DummyCapture(capture, time, livePort, switchPort);
7686
+ return {
7687
+ ...livePort ? { live: livePort } : {},
7688
+ ...capturePort ? { capture: capturePort } : {},
7689
+ ...switchPort ? { switches: switchPort } : {}
7690
+ };
7691
+ }
7540
7692
  function signInChat(conversations2, login) {
7541
7693
  if (!hinted(login)) return conversations2;
7542
7694
  return {
@@ -7613,6 +7765,7 @@ function createDummyModel({
7613
7765
  approvals = "off",
7614
7766
  asks = "off",
7615
7767
  live = "off",
7768
+ capture = "off",
7616
7769
  switches = "off",
7617
7770
  follow = "off",
7618
7771
  vault = "off",
@@ -7635,6 +7788,7 @@ function createDummyModel({
7635
7788
  older = "off"
7636
7789
  } = {}) {
7637
7790
  const time = clock(delay);
7791
+ const capturePortsOn = capturePorts(capture, live, switches, time);
7638
7792
  const mount = mounts === "off" ? null : { scenario: mounts, point: mountPoint, files: mounted };
7639
7793
  const pending2 = changes === "git" ? [...pending, skillEdit] : pending;
7640
7794
  const files3 = new DummyFiles(files, directories, pending2, time, mount);
@@ -7704,8 +7858,7 @@ function createDummyModel({
7704
7858
  ...noticePort ? { notices: noticePort } : {},
7705
7859
  ...tabs2 === "off" ? {} : { tabs: new DummyTabs(tabs2, time) },
7706
7860
  ...approvals === "off" ? {} : { approvals: new DummyApprovals(approvals, time, vaultPort) },
7707
- ...live === "off" ? {} : { live: new DummyLive(live) },
7708
- ...switches === "off" ? {} : { switches: new DummySwitches() },
7861
+ ...capturePortsOn,
7709
7862
  ...follow === "off" ? {} : { follow: new DummyFollow(follow, time) },
7710
7863
  ...vaultPort ? { vault: vaultPort } : {},
7711
7864
  ...guestsPort(guests, time)
@@ -7721,6 +7874,7 @@ function createDummyModel({
7721
7874
  export {
7722
7875
  DummyApprovals,
7723
7876
  DummyBrowser,
7877
+ DummyCapture,
7724
7878
  DummyChanges,
7725
7879
  DummyFollow,
7726
7880
  DummyGuestAgent,