@telepath-computer/television 0.1.18 → 0.1.20

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.
@@ -0,0 +1 @@
1
+ artifact-view{background:var(--color-bg-muted);border:1px solid var(--color-border);border-radius:10px;box-sizing:border-box;width:100%;height:100%;display:flex;flex-direction:column;overflow:hidden}.artifact-title-bar{display:flex;align-items:center;height:34px;padding:0 12px;flex-shrink:0;border-bottom:1px solid var(--color-border);-webkit-user-select:none;user-select:none}.artifact-title{flex:1;font-size:13px;font-weight:500;color:var(--color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.artifact-close-btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:6px;background:transparent;color:var(--color-text-muted);cursor:pointer;flex-shrink:0}.artifact-close-btn:hover{background:var(--color-interactive);color:var(--color-text)}.artifact-content{flex:1;min-height:0;overflow:hidden;padding:0}layout-view{width:100%;flex:1;min-width:0;min-height:0;display:flex;align-items:flex-start;overflow:hidden;outline:none;position:relative;--layout-unit-x: 120px;--layout-unit-y: 120px;--layout-gap: 16px;--layout-drag-transition-ms: 0ms;--color-drag-target: color-mix( in srgb, var(--color-border, var(--neutral-300, #cbd5e1)) 55%, transparent );--shadow-drag-card: 0 24px 48px color-mix(in srgb, var(--neutral-900, #0f172a) 28%, transparent)}layout-view .track{display:flex;align-items:start;gap:var(--layout-gap);flex-shrink:0;width:max-content;will-change:transform;transition:transform .2s ease}layout-view .node{display:grid;grid-template-columns:repeat(4,var(--layout-unit-x));grid-template-rows:repeat(6,var(--layout-unit-y));gap:var(--layout-gap);align-self:start;width:calc(var(--layout-unit-x) * 4 + var(--layout-gap) * 3);will-change:transform}layout-view .card-slot{border-radius:12px;box-sizing:border-box;cursor:default;min-width:0;min-height:0;position:relative;z-index:1}layout-view .card-slot artifact-view{width:100%;height:100%}layout-view .card-slot[data-layout-draggable=true]{cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none}layout-view .card-placeholder{border-radius:12px;background:var(--color-drag-target);position:relative;z-index:0}layout-view .card-placeholder[data-layout-placeholder-ghost=true]{background:transparent;border:0;opacity:0;pointer-events:none}layout-view .drag-preview{position:fixed;z-index:10;pointer-events:none;filter:drop-shadow(var(--shadow-drag-card))}layout-view .drag-preview>*{width:100%;height:100%}workspace-view{width:100%;flex:1;min-width:0;min-height:0;display:flex;flex-direction:column}workspace-view [data-testid=empty-workspace]{margin:0;padding:1rem}chat-history{display:block;position:relative;flex:1;min-height:0;background:var(--color-bg)}chat-history .chat-history-scroll{position:absolute;top:0;right:0;bottom:0;left:0;overflow-y:auto;padding:var(--space-16);display:flex;flex-direction:column;gap:var(--space-12);font-family:var(--font-sans);font-size:var(--text-base);line-height:var(--leading-base);color:var(--color-text)}chat-history .chat-message{width:100%}chat-history .chat-message-user{background:var(--color-interactive-hover);border-radius:var(--radius-sm);padding:var(--space-8) var(--space-12)}chat-history .chat-message-assistant{background:transparent;padding:var(--space-8) var(--space-12)}chat-history .chat-message-body>*:first-child{margin-top:0}chat-history .chat-message-body>*:last-child{margin-bottom:0}chat-history .chat-message-body p{margin:var(--space-8) 0 0 0}chat-history .chat-message-body p:first-child{margin-top:0}chat-history .chat-message-body h1,chat-history .chat-message-body h2,chat-history .chat-message-body h3,chat-history .chat-message-body h4,chat-history .chat-message-body h5,chat-history .chat-message-body h6{font-size:inherit;line-height:inherit;font-weight:700;margin:var(--space-8) 0 0 0}chat-history .chat-message-body h1:first-child,chat-history .chat-message-body h2:first-child,chat-history .chat-message-body h3:first-child,chat-history .chat-message-body h4:first-child,chat-history .chat-message-body h5:first-child,chat-history .chat-message-body h6:first-child{margin-top:0}chat-history .chat-message-body code{font-family:var(--font-mono);font-size:.9em;background:var(--color-interactive);border-radius:var(--radius-sm);padding:0 var(--space-4)}chat-history .chat-message-body pre{margin:var(--space-8) 0 0 0;padding:var(--space-8) var(--space-12);background:var(--color-surface);border-radius:var(--radius-sm);overflow-x:auto;font-family:var(--font-mono);font-size:var(--text-sm)}chat-history .chat-message-body pre code{background:transparent;padding:0;font-size:inherit}chat-history .chat-message-body ul,chat-history .chat-message-body ol{margin:var(--space-8) 0 0 0;padding-left:var(--space-16)}chat-history .chat-message-body ul:first-child,chat-history .chat-message-body ol:first-child{margin-top:0}chat-history .chat-message-body li{margin:var(--space-4) 0}chat-history .chat-message-body blockquote{margin:var(--space-8) 0 0 0;padding-left:var(--space-12);border-left:2px solid var(--color-border);color:var(--color-text-muted)}chat-history .chat-message-body a{color:var(--color-text);text-decoration:underline}chat-history .chat-message-body strong{font-weight:700}chat-history .chat-message-body em{font-style:italic}chat-history .chat-message-badge{display:inline;margin-left:var(--space-4);font-size:var(--text-xs);color:var(--color-text-muted)}chat-history .chat-history-jump{position:absolute;left:50%;bottom:var(--space-12);transform:translate(-50%);z-index:1;display:inline-flex;align-items:center;gap:var(--space-8);padding:var(--space-8) var(--space-16);background:var(--color-surface);color:var(--color-text);border:none;border-radius:999px;box-shadow:var(--shadow-popover);font-family:var(--font-sans);font-size:var(--text-sm);cursor:pointer}chat-history .chat-history-jump[hidden]{display:none}chat-history .chat-history-jump:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}chat-input{display:flex;align-items:center;gap:var(--space-8);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:0;padding-right:var(--space-4)}chat-input textarea{flex:1;min-width:0;background:transparent;border:none;resize:none;font-family:var(--font-sans);font-size:var(--text-base);line-height:var(--leading-base);color:var(--color-text);padding:var(--space-8) var(--space-12);outline:none}chat-input button{flex-shrink:0;width:32px;height:32px;padding:0;display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:var(--radius-sm);color:var(--color-text);cursor:pointer}chat-input button:hover:not(:disabled){background:var(--color-interactive)}chat-input button:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}chat-input button:disabled{cursor:default;color:var(--color-text-muted)}chat-panel{display:flex;flex-direction:column;width:350px;flex:none;background:var(--color-bg);border-left:1px solid var(--color-border);min-height:0}chat-panel[hidden]{display:none}chat-panel chat-history{flex:1;min-height:0}chat-panel chat-history .chat-history-scroll{padding-bottom:0}chat-panel .chat-panel-input{padding:var(--space-12);flex:none}television-app{width:100%;height:100%;display:grid;grid-template-rows:auto 1fr;grid-template-areas:"header" "main"}television-app>header{grid-area:header;position:relative;z-index:10}television-app>main{grid-area:main;grid-row:1 / -1}body.electron television-app>header{-webkit-app-region:drag;padding-left:80px;border-bottom:1px solid var(--color-border)}header{display:flex;align-items:center;justify-content:space-between;height:34px;padding:0 12px;flex-shrink:0;-webkit-user-select:none;user-select:none}television-app>header>nav{display:flex;align-items:center;gap:8px;min-width:0}workspace-picker,workspace-picker [trigger],button[variant=toolbar],.settings-server-remove-button,.settings-submit-button,.settings-cancel-button,.settings-connect-button,.settings-field input{-webkit-app-region:no-drag}workspace-picker dropdown-menu::part(panel){min-width:18rem}workspace-picker [trigger],workspace-picker [trigger][data-dropdown-trigger]{min-width:0;padding:0;border:none;background:transparent;font-size:13px;font-weight:600}workspace-picker [trigger] .trigger-label{white-space:nowrap}dropdown-group{display:block;padding:4px 0}dropdown-label{display:block;padding:0 10px 4px;font-size:12px;color:color-mix(in srgb,currentColor 60%,transparent)}dropdown-item{display:block;padding:6px 10px;border-radius:4px;cursor:pointer}dropdown-item[selected]{background:color-mix(in srgb,var(--color-border) 70%,white)}dropdown-item[action]{color:color-mix(in srgb,currentColor 50%,transparent)}dropdown-item[danger]{color:#c74343}television-app>main{min-width:0;min-height:0;overflow:hidden;display:flex;flex-direction:row}television-app>main.auth-gate{display:flex;align-items:center;justify-content:center}.settings-panel{width:min(32rem,100%);display:flex;flex-direction:column;padding:20px;border:1px solid var(--color-border);border-radius:12px;background:var(--color-bg)}.workspace-modal,.auth-modal{width:min(24rem,100%);display:flex;flex-direction:column;padding:20px;border:1px solid var(--color-border);border-radius:12px;background:var(--color-bg)}.auth-form{display:flex;flex-direction:column;gap:12px}.auth-modal-title,.auth-modal-copy{margin:0}.auth-token-input-invalid{border-color:#c74343}.workspace-form{display:flex;flex-direction:column;gap:12px}.workspace-form-actions{display:flex;gap:8px}.workspace-modal-title,.workspace-delete-copy,.workspace-delete-warning,.workspace-delete-error{margin:0}.workspace-delete-warning,.workspace-delete-error{font-size:13px}.workspace-delete-error{color:#c74343}.settings-section-title{margin:0}.settings-section,.settings-server-list,.settings-add-server-form{display:flex;flex-direction:column;gap:12px}.settings-form-actions{display:flex;gap:8px}.settings-card{padding:12px;border:1px solid var(--color-border);border-radius:8px}.settings-server{display:flex;align-items:center;justify-content:space-between;gap:12px}.settings-server-details{min-width:0}.settings-server-name{font-weight:600}.settings-server-url{font-size:13px;word-break:break-word;color:color-mix(in srgb,currentColor 70%,transparent)}.settings-server-remove-button,.settings-submit-button,.settings-cancel-button,.settings-connect-button{padding:8px 12px;border-radius:8px}.settings-field{display:flex;flex-direction:column;gap:6px}.settings-field input{width:100%;padding:8px 10px;border:1px solid var(--color-border);border-radius:8px;background:var(--color-bg);color:inherit;font:inherit;box-sizing:border-box}.settings-submit-button,.settings-cancel-button,.settings-connect-button{align-self:flex-start}dropdown-menu{position:relative;display:inline-block;color:inherit}dropdown-group{display:grid;gap:var(--space-4)}dropdown-label{display:block;padding:var(--space-4) var(--space-8);color:var(--color-text-muted);font:inherit;font-size:var(--text-sm);font-weight:600;letter-spacing:.04em;text-transform:uppercase}dropdown-divider{display:block;height:1px;margin:var(--space-4) 0;background:var(--color-border)}[data-dropdown-trigger],dropdown-item{color:inherit;font:inherit;line-height:1.2}[data-dropdown-trigger],dropdown-menu::part(trigger){display:inline-flex;align-items:center;gap:var(--space-8);margin:0;padding:.375rem .5rem;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-surface);color:var(--color-text);box-shadow:none;cursor:pointer}[data-dropdown-trigger]:hover,dropdown-menu::part(trigger):hover{background:var(--color-interactive-hover)}dropdown-menu[open] [data-dropdown-trigger],dropdown-menu[open]::part(trigger){background:var(--color-interactive)}[data-dropdown-trigger-label],dropdown-menu::part(trigger-label){min-width:0}[data-dropdown-trigger-icon],dropdown-menu::part(trigger-icon){display:inline-flex;align-items:center;justify-content:center;flex:none}[data-dropdown-trigger]:focus-visible,dropdown-menu::part(trigger):focus-visible,dropdown-item:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}dropdown-menu::part(panel){position:absolute;top:calc(100% + var(--space-4));left:0;z-index:var(--layer-popover);min-width:12rem;padding:var(--space-4);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);box-shadow:var(--shadow-popover)}dropdown-item{display:block;margin:0;padding:.375rem .5rem;border-radius:var(--radius-sm);cursor:pointer;-webkit-user-select:none;user-select:none}dropdown-item:hover{background:var(--color-interactive-hover)}dropdown-item[selected]{background:var(--color-interactive)}panel-view{display:block}panel-view::part(panel){display:flex;flex-direction:column;gap:var(--space-16);color:var(--color-text)}panel-view::part(header){display:flex;align-items:center;justify-content:space-between;gap:var(--space-12)}panel-view::part(title-group){display:flex;align-items:center;gap:var(--space-8);min-width:0}panel-view::part(title){margin:0;font:inherit;font-size:var(--text-lg);font-weight:600;color:var(--color-text)}panel-view::part(button){display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;margin:0;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-surface);color:var(--color-text);box-shadow:none;cursor:pointer}panel-view::part(button):hover{background:var(--color-interactive-hover)}panel-view::part(button):focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}panel-view::part(icon){display:inline-flex;align-items:center;justify-content:center;flex:none}panel-view::part(back-icon){transform:rotate(90deg)}modal-overlay{color:inherit}modal-overlay::part(backdrop){position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--layer-modal);display:flex;align-items:center;justify-content:center;padding:var(--space-16);background:var(--color-overlay-backdrop)}*,*:before,*:after{box-sizing:border-box}:root{--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;--font-brand: var(--font-sans);--font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;--text-base: 14px;--text-scale: 1.125;--text-sm: round(calc(var(--text-base) / var(--text-scale)), 1px);--text-lg: round(calc(var(--text-base) * var(--text-scale)), 1px);--text-xl: round(calc(var(--text-lg) * var(--text-scale)), 1px);--leading-base: 1.5;--space-2: 2px;--space-4: 4px;--space-6: 6px;--space-8: 8px;--space-12: 12px;--space-16: 16px;--space-24: 24px;--space-32: 32px;--space-48: 48px;--space-64: 64px;--radius-sm: .375rem;--radius-md: .5rem;--layer-popover: 10;--layer-modal: 1000;--shadow-popover: 0 12px 32px rgb(0 0 0 / .14);--shadow-modal: 0 24px 64px rgb(0 0 0 / .2)}html,body{margin:0;padding:0;width:100%;height:100%}body{font-family:var(--font-sans);font-size:var(--text-base);line-height:var(--leading-base);color:var(--color-text);background:var(--color-bg)}a{text-underline-offset:.15em;text-decoration-thickness:.08em}button,input,textarea,select{font:inherit;color:inherit}a{color:var(--color-link)}h1,h2,h3,h4,h5,h6,p,ul,ol,blockquote,pre,hr{margin:0}h1,h2,h3,h4,h5,h6{font-weight:600;color:var(--color-text)}code{font-family:var(--font-mono);font-size:.9em;background:var(--color-bg-muted);padding:var(--space-2) var(--space-4);border-radius:var(--radius-sm)}pre{font-family:var(--font-mono);background:var(--color-bg-muted);padding:var(--space-12);border-radius:var(--radius-md);overflow-x:auto}pre code{background:none;padding:0}blockquote{padding-left:var(--space-16);border-left:3px solid var(--color-border);color:var(--color-text-muted)}hr{border:none;border-top:1px solid var(--color-border)}table{border-collapse:collapse}th,td{padding:var(--space-8) var(--space-12);border:1px solid var(--color-border);text-align:left}th{background:var(--color-bg-muted);font-weight:600}.prose{line-height:var(--leading-base)}.prose h1{font-size:var(--text-xl);margin-bottom:var(--space-8)}.prose h2{font-size:var(--text-lg);margin-top:var(--space-24);margin-bottom:var(--space-8)}.prose h3,.prose h4,.prose h5,.prose h6{font-size:var(--text-base);margin-top:var(--space-24);margin-bottom:var(--space-8)}.prose p{margin:var(--space-12) 0}.prose ul,.prose ol{padding-left:var(--space-24);margin:var(--space-12) 0}.prose blockquote,.prose pre{margin:var(--space-12) 0}.prose hr{margin:var(--space-24) 0}.prose table{width:100%;margin:var(--space-12) 0}.prose img{max-width:100%;height:auto}.prose>:first-child{margin-top:0}.prose>:last-child{margin-bottom:0}[data-ui-icon]{display:inline-block;vertical-align:middle}button{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-6);border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-bg);color:inherit;cursor:pointer}button:hover{background:var(--color-interactive)}button[variant=toolbar]{border:none;background:transparent;color:var(--color-text-muted)}button[size=sm]{min-height:26px;padding:var(--space-2) var(--space-6)}button[size=md]{min-height:32px;padding:var(--space-6) var(--space-12)}:root{--black: #000000;--white: #ffffff;--neutral-50: oklch(.985 .001 106.423);--neutral-100: oklch(.97 .001 106.424);--neutral-200: oklch(.923 .003 48.717);--neutral-300: oklch(.869 .005 56.366);--neutral-400: oklch(.709 .01 56.259);--neutral-500: oklch(.553 .013 58.071);--neutral-600: oklch(.444 .011 73.639);--neutral-700: oklch(.374 .01 67.558);--neutral-800: oklch(.268 .007 34.298);--neutral-900: oklch(.216 .006 56.043);--neutral-950: oklch(.147 .004 49.25)}:root{--color-bg: var(--neutral-50);--color-bg-muted: var(--neutral-100);--color-surface: var(--white);--color-surface-muted: var(--neutral-100);--color-interactive: var(--neutral-200);--color-interactive-hover: var(--neutral-300);--color-border: var(--neutral-300);--color-border-muted: var(--neutral-200);--color-text: var(--neutral-900);--color-text-muted: var(--neutral-500);--color-link: inherit;--color-focus-ring: var(--neutral-500);--color-overlay-backdrop: rgb(0 0 0 / .5);color-scheme:light}:root{--color-bg: var(--neutral-200);--color-border: var(--neutral-300)}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Television</title>
7
- <script type="module" crossorigin src="./assets/index-Bjw5Y84l.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-CmOTsDN-.css">
7
+ <script type="module" crossorigin src="./assets/index-CNuBQ_8R.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-D0BGTUk2.css">
9
9
  </head>
10
10
  <body></body>
11
11
  </html>
package/dist/cli.cjs CHANGED
@@ -75577,21 +75577,19 @@ var ACPBridge = class {
75577
75577
  error = null;
75578
75578
  stdoutBuffer = "";
75579
75579
  stderrBuffer = "";
75580
- subscribers = /* @__PURE__ */ new Set();
75581
75580
  send;
75582
75581
  constructor(send) {
75583
75582
  this.send = send;
75584
75583
  }
75585
- handleClientMessage(socket, message) {
75584
+ handleClientMessage(message) {
75586
75585
  switch (message.type) {
75587
75586
  case "acp-bridge-connect":
75588
- this.subscribers.add(socket);
75589
- this.ensureStarted();
75590
- this.sendStatus(socket);
75587
+ void this.ensureStarted();
75588
+ this.sendStatus();
75591
75589
  return;
75592
75590
  case "acp-bridge-message":
75593
75591
  if (!this.child || this.status !== "ready") {
75594
- this.sendStatus(socket);
75592
+ this.sendStatus();
75595
75593
  return;
75596
75594
  }
75597
75595
  this.child.stdin.write(`${JSON.stringify(message.message)}
@@ -75599,11 +75597,10 @@ var ACPBridge = class {
75599
75597
  return;
75600
75598
  }
75601
75599
  }
75602
- detachSocket(socket) {
75603
- this.subscribers.delete(socket);
75600
+ detachSocket() {
75601
+ void this.stop();
75604
75602
  }
75605
75603
  async stop() {
75606
- this.subscribers.clear();
75607
75604
  if (!this.child) {
75608
75605
  return;
75609
75606
  }
@@ -75627,7 +75624,7 @@ var ACPBridge = class {
75627
75624
  }
75628
75625
  this.status = "launching";
75629
75626
  this.error = null;
75630
- this.broadcastStatus();
75627
+ this.sendStatus();
75631
75628
  await (0, import_promises2.mkdir)(ACP_STUB_CWD, { recursive: true });
75632
75629
  const child = (0, import_node_child_process2.spawn)(ACP_COMMAND, ACP_ARGS, {
75633
75630
  cwd: ACP_STUB_CWD,
@@ -75635,21 +75632,30 @@ var ACPBridge = class {
75635
75632
  });
75636
75633
  this.child = child;
75637
75634
  child.once("spawn", () => {
75635
+ if (this.child !== child) {
75636
+ return;
75637
+ }
75638
75638
  this.status = "ready";
75639
75639
  this.error = null;
75640
- this.broadcastStatus();
75640
+ this.sendStatus();
75641
75641
  });
75642
75642
  child.once("error", (error2) => {
75643
+ if (this.child !== child) {
75644
+ return;
75645
+ }
75643
75646
  this.child = null;
75644
75647
  this.status = "error";
75645
75648
  this.error = error2.message;
75646
- this.broadcastStatus();
75649
+ this.sendStatus();
75647
75650
  });
75648
75651
  child.once("exit", () => {
75652
+ if (this.child !== child) {
75653
+ return;
75654
+ }
75649
75655
  this.child = null;
75650
75656
  this.status = "exited";
75651
75657
  this.error = this.stderrBuffer.trim() || this.error;
75652
- this.broadcastStatus();
75658
+ this.sendStatus();
75653
75659
  });
75654
75660
  child.stdout.on("data", (chunk) => {
75655
75661
  this.stdoutBuffer += chunk.toString();
@@ -75673,33 +75679,24 @@ var ACPBridge = class {
75673
75679
  }
75674
75680
  try {
75675
75681
  const message = JSON.parse(line);
75676
- this.broadcast({ type: "acp-bridge-message", message });
75682
+ this.send({ type: "acp-bridge-message", message });
75677
75683
  } catch (error2) {
75678
75684
  this.status = "error";
75679
75685
  this.error = error2 instanceof Error ? error2.message : String(error2);
75680
- this.broadcastStatus();
75686
+ this.sendStatus();
75681
75687
  }
75682
75688
  }
75683
75689
  }
75684
- sendStatus(socket) {
75690
+ sendStatus() {
75685
75691
  const message = {
75686
75692
  type: "acp-bridge-status",
75687
75693
  status: this.status,
75688
75694
  ...this.error ? { error: this.error } : {}
75689
75695
  };
75690
- this.send(socket, message);
75696
+ this.send(message);
75691
75697
  }
75692
- broadcastStatus() {
75693
- this.broadcast({
75694
- type: "acp-bridge-status",
75695
- status: this.status,
75696
- ...this.error ? { error: this.error } : {}
75697
- });
75698
- }
75699
- broadcast(message) {
75700
- for (const socket of this.subscribers) {
75701
- this.send(socket, message);
75702
- }
75698
+ getChildPID() {
75699
+ return this.child?.pid ?? null;
75703
75700
  }
75704
75701
  };
75705
75702
 
@@ -77292,7 +77289,7 @@ var Server2 = class {
77292
77289
  httpServer;
77293
77290
  wsServer;
77294
77291
  store;
77295
- acpBridge;
77292
+ acpBridges = /* @__PURE__ */ new Map();
77296
77293
  host;
77297
77294
  port;
77298
77295
  publicServer;
@@ -77304,7 +77301,6 @@ var Server2 = class {
77304
77301
  this.port = options.port ?? DEFAULT_SERVER_PORT;
77305
77302
  this.publicServer = options.public ?? false;
77306
77303
  this.baseURL = buildServerURL(this.host ?? DEFAULT_SERVER_HOST, this.port);
77307
- this.acpBridge = new ACPBridge((socket, message) => this.send(socket, message));
77308
77304
  this.app = (0, import_express2.default)();
77309
77305
  this.httpServer = import_node_http.default.createServer(this.app);
77310
77306
  this.wsServer = new import_websocket_server.default({ server: this.httpServer, path: "/ws" });
@@ -77346,11 +77342,14 @@ var Server2 = class {
77346
77342
  type: "workspace-list",
77347
77343
  workspaces: this.store.listWorkspaces()
77348
77344
  });
77345
+ const acpBridge = new ACPBridge((message) => this.send(socket, message));
77346
+ this.acpBridges.set(socket, acpBridge);
77349
77347
  socket.on("message", (data) => {
77350
77348
  this.handleClientMessage(socket, data.toString());
77351
77349
  });
77352
77350
  socket.on("close", () => {
77353
- this.acpBridge.detachSocket(socket);
77351
+ this.acpBridges.get(socket)?.detachSocket();
77352
+ this.acpBridges.delete(socket);
77354
77353
  });
77355
77354
  });
77356
77355
  this.store.addEventListener("store-change", (event) => {
@@ -77381,12 +77380,25 @@ var Server2 = class {
77381
77380
  getAuthToken() {
77382
77381
  return this.store.authToken;
77383
77382
  }
77383
+ getACPBridgePID() {
77384
+ for (const bridge of this.acpBridges.values()) {
77385
+ const pid = bridge.getChildPID();
77386
+ if (pid) {
77387
+ return pid;
77388
+ }
77389
+ }
77390
+ return null;
77391
+ }
77392
+ getACPBridgePIDs() {
77393
+ return [...this.acpBridges.values()].map((bridge) => bridge.getChildPID()).filter((pid) => pid !== null);
77394
+ }
77384
77395
  stop() {
77385
77396
  return new Promise((resolve, reject) => {
77386
77397
  for (const socket of this.wsServer.clients) {
77387
77398
  socket.terminate();
77388
77399
  }
77389
- void this.acpBridge.stop().then(() => {
77400
+ void Promise.all([...this.acpBridges.values()].map((bridge) => bridge.stop())).then(() => {
77401
+ this.acpBridges.clear();
77390
77402
  this.wsServer.close((wsError) => {
77391
77403
  if (wsError) {
77392
77404
  reject(wsError);
@@ -77414,7 +77426,7 @@ var Server2 = class {
77414
77426
  return;
77415
77427
  }
77416
77428
  if (isACPBridgeClientMessage(message)) {
77417
- this.acpBridge.handleClientMessage(socket, message);
77429
+ this.acpBridges.get(socket)?.handleClientMessage(message);
77418
77430
  return;
77419
77431
  }
77420
77432
  if (!isClientMessage(message)) {
package/dist/electron.cjs CHANGED
@@ -71865,21 +71865,19 @@ var ACPBridge = class {
71865
71865
  error = null;
71866
71866
  stdoutBuffer = "";
71867
71867
  stderrBuffer = "";
71868
- subscribers = /* @__PURE__ */ new Set();
71869
71868
  send;
71870
71869
  constructor(send) {
71871
71870
  this.send = send;
71872
71871
  }
71873
- handleClientMessage(socket, message) {
71872
+ handleClientMessage(message) {
71874
71873
  switch (message.type) {
71875
71874
  case "acp-bridge-connect":
71876
- this.subscribers.add(socket);
71877
- this.ensureStarted();
71878
- this.sendStatus(socket);
71875
+ void this.ensureStarted();
71876
+ this.sendStatus();
71879
71877
  return;
71880
71878
  case "acp-bridge-message":
71881
71879
  if (!this.child || this.status !== "ready") {
71882
- this.sendStatus(socket);
71880
+ this.sendStatus();
71883
71881
  return;
71884
71882
  }
71885
71883
  this.child.stdin.write(`${JSON.stringify(message.message)}
@@ -71887,11 +71885,10 @@ var ACPBridge = class {
71887
71885
  return;
71888
71886
  }
71889
71887
  }
71890
- detachSocket(socket) {
71891
- this.subscribers.delete(socket);
71888
+ detachSocket() {
71889
+ void this.stop();
71892
71890
  }
71893
71891
  async stop() {
71894
- this.subscribers.clear();
71895
71892
  if (!this.child) {
71896
71893
  return;
71897
71894
  }
@@ -71915,7 +71912,7 @@ var ACPBridge = class {
71915
71912
  }
71916
71913
  this.status = "launching";
71917
71914
  this.error = null;
71918
- this.broadcastStatus();
71915
+ this.sendStatus();
71919
71916
  await (0, import_promises.mkdir)(ACP_STUB_CWD, { recursive: true });
71920
71917
  const child = (0, import_node_child_process.spawn)(ACP_COMMAND, ACP_ARGS, {
71921
71918
  cwd: ACP_STUB_CWD,
@@ -71923,21 +71920,30 @@ var ACPBridge = class {
71923
71920
  });
71924
71921
  this.child = child;
71925
71922
  child.once("spawn", () => {
71923
+ if (this.child !== child) {
71924
+ return;
71925
+ }
71926
71926
  this.status = "ready";
71927
71927
  this.error = null;
71928
- this.broadcastStatus();
71928
+ this.sendStatus();
71929
71929
  });
71930
71930
  child.once("error", (error2) => {
71931
+ if (this.child !== child) {
71932
+ return;
71933
+ }
71931
71934
  this.child = null;
71932
71935
  this.status = "error";
71933
71936
  this.error = error2.message;
71934
- this.broadcastStatus();
71937
+ this.sendStatus();
71935
71938
  });
71936
71939
  child.once("exit", () => {
71940
+ if (this.child !== child) {
71941
+ return;
71942
+ }
71937
71943
  this.child = null;
71938
71944
  this.status = "exited";
71939
71945
  this.error = this.stderrBuffer.trim() || this.error;
71940
- this.broadcastStatus();
71946
+ this.sendStatus();
71941
71947
  });
71942
71948
  child.stdout.on("data", (chunk) => {
71943
71949
  this.stdoutBuffer += chunk.toString();
@@ -71961,33 +71967,24 @@ var ACPBridge = class {
71961
71967
  }
71962
71968
  try {
71963
71969
  const message = JSON.parse(line);
71964
- this.broadcast({ type: "acp-bridge-message", message });
71970
+ this.send({ type: "acp-bridge-message", message });
71965
71971
  } catch (error2) {
71966
71972
  this.status = "error";
71967
71973
  this.error = error2 instanceof Error ? error2.message : String(error2);
71968
- this.broadcastStatus();
71974
+ this.sendStatus();
71969
71975
  }
71970
71976
  }
71971
71977
  }
71972
- sendStatus(socket) {
71978
+ sendStatus() {
71973
71979
  const message = {
71974
71980
  type: "acp-bridge-status",
71975
71981
  status: this.status,
71976
71982
  ...this.error ? { error: this.error } : {}
71977
71983
  };
71978
- this.send(socket, message);
71984
+ this.send(message);
71979
71985
  }
71980
- broadcastStatus() {
71981
- this.broadcast({
71982
- type: "acp-bridge-status",
71983
- status: this.status,
71984
- ...this.error ? { error: this.error } : {}
71985
- });
71986
- }
71987
- broadcast(message) {
71988
- for (const socket of this.subscribers) {
71989
- this.send(socket, message);
71990
- }
71986
+ getChildPID() {
71987
+ return this.child?.pid ?? null;
71991
71988
  }
71992
71989
  };
71993
71990
 
@@ -73580,7 +73577,7 @@ var Server2 = class {
73580
73577
  httpServer;
73581
73578
  wsServer;
73582
73579
  store;
73583
- acpBridge;
73580
+ acpBridges = /* @__PURE__ */ new Map();
73584
73581
  host;
73585
73582
  port;
73586
73583
  publicServer;
@@ -73592,7 +73589,6 @@ var Server2 = class {
73592
73589
  this.port = options.port ?? DEFAULT_SERVER_PORT;
73593
73590
  this.publicServer = options.public ?? false;
73594
73591
  this.baseURL = buildServerURL(this.host ?? DEFAULT_SERVER_HOST, this.port);
73595
- this.acpBridge = new ACPBridge((socket, message) => this.send(socket, message));
73596
73592
  this.app = (0, import_express2.default)();
73597
73593
  this.httpServer = import_node_http.default.createServer(this.app);
73598
73594
  this.wsServer = new import_websocket_server.default({ server: this.httpServer, path: "/ws" });
@@ -73634,11 +73630,14 @@ var Server2 = class {
73634
73630
  type: "workspace-list",
73635
73631
  workspaces: this.store.listWorkspaces()
73636
73632
  });
73633
+ const acpBridge = new ACPBridge((message) => this.send(socket, message));
73634
+ this.acpBridges.set(socket, acpBridge);
73637
73635
  socket.on("message", (data) => {
73638
73636
  this.handleClientMessage(socket, data.toString());
73639
73637
  });
73640
73638
  socket.on("close", () => {
73641
- this.acpBridge.detachSocket(socket);
73639
+ this.acpBridges.get(socket)?.detachSocket();
73640
+ this.acpBridges.delete(socket);
73642
73641
  });
73643
73642
  });
73644
73643
  this.store.addEventListener("store-change", (event) => {
@@ -73669,12 +73668,25 @@ var Server2 = class {
73669
73668
  getAuthToken() {
73670
73669
  return this.store.authToken;
73671
73670
  }
73671
+ getACPBridgePID() {
73672
+ for (const bridge of this.acpBridges.values()) {
73673
+ const pid = bridge.getChildPID();
73674
+ if (pid) {
73675
+ return pid;
73676
+ }
73677
+ }
73678
+ return null;
73679
+ }
73680
+ getACPBridgePIDs() {
73681
+ return [...this.acpBridges.values()].map((bridge) => bridge.getChildPID()).filter((pid) => pid !== null);
73682
+ }
73672
73683
  stop() {
73673
73684
  return new Promise((resolve, reject) => {
73674
73685
  for (const socket of this.wsServer.clients) {
73675
73686
  socket.terminate();
73676
73687
  }
73677
- void this.acpBridge.stop().then(() => {
73688
+ void Promise.all([...this.acpBridges.values()].map((bridge) => bridge.stop())).then(() => {
73689
+ this.acpBridges.clear();
73678
73690
  this.wsServer.close((wsError) => {
73679
73691
  if (wsError) {
73680
73692
  reject(wsError);
@@ -73702,7 +73714,7 @@ var Server2 = class {
73702
73714
  return;
73703
73715
  }
73704
73716
  if (isACPBridgeClientMessage(message)) {
73705
- this.acpBridge.handleClientMessage(socket, message);
73717
+ this.acpBridges.get(socket)?.handleClientMessage(message);
73706
73718
  return;
73707
73719
  }
73708
73720
  if (!isClientMessage(message)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telepath-computer/television",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "type": "module",
5
5
  "main": "dist/electron.cjs",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "type-check": "tsc --noEmit",
24
24
  "test:setup": "playwright install chromium",
25
25
  "test:core": "vitest run test/main.test.ts test/layout.test.ts test/television-client.test.ts test/workspace-service.test.ts test/browser-server.test.ts test/server-manager.test.ts test/server-store.test.ts test/artifacts.test.ts test/artifact-runtime.test.ts test/html-artifact-srcdoc.test.ts test/demo-layout-state.test.ts test/server.test.ts test/cli.test.ts test/acp-client.fake-server.test.ts",
26
- "test:ui": "vitest run test/client-store.test.ts test/runtime.test.ts test/renderer.test.ts test/artifact-view.test.ts test/layout-stream.test.ts test/drag-controller.test.ts test/layout-mutations.test.ts test/workspace-view.test.ts test/app-root.test.ts test/chat-input.test.ts",
26
+ "test:ui": "vitest run test/client-store.test.ts test/runtime.test.ts test/renderer.test.ts test/artifact-view.test.ts test/layout-stream.test.ts test/drag-controller.test.ts test/layout-mutations.test.ts test/workspace-view.test.ts test/app-root.test.ts test/chat-input.test.ts test/chat-history.test.ts test/chat-panel.test.ts test/wheel-gesture.test.ts",
27
27
  "test": "npm run test:core && npm run test:ui",
28
28
  "test:e2e": "playwright test --config=playwright.config.ts",
29
29
  "test:electron": "npm run build && scripts/test-electron.sh",
@@ -44,8 +44,9 @@
44
44
  "@rupertsworld/event-target": "^0.1.0",
45
45
  "@rupertsworld/observable": "^0.1.2",
46
46
  "@telepath-computer/tool-router": "latest",
47
- "@telepath-computer/ui": "latest",
47
+ "@telepath-computer/ui": "^0.1.5",
48
48
  "commander": "^14.0.3",
49
+ "dompurify": "^3.3.3",
49
50
  "express": "^4.21.0",
50
51
  "lit-html": "^3.3.2",
51
52
  "marked": "^17.0.4",
@@ -56,6 +57,7 @@
56
57
  "devDependencies": {
57
58
  "@eslint/js": "^9.39.4",
58
59
  "@playwright/test": "^1.58.2",
60
+ "@types/dompurify": "^3.0.5",
59
61
  "@types/express": "^5.0.0",
60
62
  "@types/node": "^22.0.0",
61
63
  "@types/supertest": "^6.0.0",