@ai-ecoverse/slicc-spectrum 2.6.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",
@@ -4801,9 +4931,9 @@ var outdatedDevice = {
4801
4931
  note: "Update slicc to 1.47.0 or later to share this computer\u2019s browsers."
4802
4932
  };
4803
4933
  var others = linkedDevices.filter((device) => device.id !== pairedDevice.id);
4804
- function grant(device, key, allowed) {
4805
- const access = { ...device.access, [key]: allowed };
4806
- 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;
4807
4937
  const next = { ...device, access, asking: device.asking && !access.view };
4808
4938
  if (!access.view && !access.control) next.controlling = void 0;
4809
4939
  else if (!access.control && next.controlling === "prompt") next.controlling = "watch";
@@ -4910,8 +5040,8 @@ var DummyNetwork = class extends Emitter {
4910
5040
  ({ links: this.#links, exit: this.#exit } = linksFixtures(links));
4911
5041
  this.setExit = (exit) => this.#setExit(exit);
4912
5042
  this.unlink = (id) => this.#unlink(id);
4913
- this.setRemoteControl = (id, allowed) => this.#control(id, allowed);
4914
- 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);
4915
5045
  this.rotateJoinUrl = () => this.#rotate();
4916
5046
  this.retryLinks = () => this.#retry();
4917
5047
  this.mountFolder = (source) => this.#mountFolder(source);
@@ -5022,22 +5152,22 @@ var DummyNetwork = class extends Emitter {
5022
5152
  this.#exit = exit;
5023
5153
  this.#emit();
5024
5154
  }
5025
- async #control(id, allowed) {
5155
+ async #control(id, allowed2) {
5026
5156
  await this.#clock.sleep(4);
5027
5157
  const links = this.#links;
5028
5158
  const devices = links.devices.map((device) => {
5029
5159
  if (device.id !== id) return device;
5030
- const next = { ...device, control: { ...device.control, allowed } };
5031
- return allowed ? next : { ...next, controlling: void 0 };
5160
+ const next = { ...device, control: { ...device.control, allowed: allowed2 } };
5161
+ return allowed2 ? next : { ...next, controlling: void 0 };
5032
5162
  });
5033
5163
  this.#links = { ...links, devices };
5034
5164
  this.#emit();
5035
5165
  }
5036
- async #access(id, key, allowed) {
5166
+ async #access(id, key, allowed2) {
5037
5167
  await this.#clock.sleep(4);
5038
5168
  const links = this.#links;
5039
5169
  const devices = links.devices.map(
5040
- (device) => device.id === id ? grant(device, key, allowed) : device
5170
+ (device) => device.id === id ? grant(device, key, allowed2) : device
5041
5171
  );
5042
5172
  this.#links = { ...links, devices };
5043
5173
  this.#emit();
@@ -7549,6 +7679,16 @@ var movedDocs = "https://docs.eu.example/mcp";
7549
7679
  function hinted(login) {
7550
7680
  return login === "code" || login === "url" || login === "lookalike";
7551
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
+ }
7552
7692
  function signInChat(conversations2, login) {
7553
7693
  if (!hinted(login)) return conversations2;
7554
7694
  return {
@@ -7625,6 +7765,7 @@ function createDummyModel({
7625
7765
  approvals = "off",
7626
7766
  asks = "off",
7627
7767
  live = "off",
7768
+ capture = "off",
7628
7769
  switches = "off",
7629
7770
  follow = "off",
7630
7771
  vault = "off",
@@ -7647,6 +7788,7 @@ function createDummyModel({
7647
7788
  older = "off"
7648
7789
  } = {}) {
7649
7790
  const time = clock(delay);
7791
+ const capturePortsOn = capturePorts(capture, live, switches, time);
7650
7792
  const mount = mounts === "off" ? null : { scenario: mounts, point: mountPoint, files: mounted };
7651
7793
  const pending2 = changes === "git" ? [...pending, skillEdit] : pending;
7652
7794
  const files3 = new DummyFiles(files, directories, pending2, time, mount);
@@ -7716,8 +7858,7 @@ function createDummyModel({
7716
7858
  ...noticePort ? { notices: noticePort } : {},
7717
7859
  ...tabs2 === "off" ? {} : { tabs: new DummyTabs(tabs2, time) },
7718
7860
  ...approvals === "off" ? {} : { approvals: new DummyApprovals(approvals, time, vaultPort) },
7719
- ...live === "off" ? {} : { live: new DummyLive(live) },
7720
- ...switches === "off" ? {} : { switches: new DummySwitches() },
7861
+ ...capturePortsOn,
7721
7862
  ...follow === "off" ? {} : { follow: new DummyFollow(follow, time) },
7722
7863
  ...vaultPort ? { vault: vaultPort } : {},
7723
7864
  ...guestsPort(guests, time)
@@ -7733,6 +7874,7 @@ function createDummyModel({
7733
7874
  export {
7734
7875
  DummyApprovals,
7735
7876
  DummyBrowser,
7877
+ DummyCapture,
7736
7878
  DummyChanges,
7737
7879
  DummyFollow,
7738
7880
  DummyGuestAgent,