@comty.io/core 0.1.1 → 0.1.3

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.
package/comty-sdk.js CHANGED
@@ -12,9 +12,7 @@ function getComtyStyle() {
12
12
  --comty-foreground: #fafafa;
13
13
  --comty-muted: var(--comty-toolbar-muted);
14
14
  --comty-accent: #55aaf5;
15
- --comty-agent-warning: #e9b86d;
16
- --comty-agent-success: #80c9a4;
17
- --comty-agent-error: #ef7676;
15
+ --comty-error: #ef7676;
18
16
  --comty-outline: oklch(0.62 0.18 255);
19
17
  --comty-paper: #fff;
20
18
  --comty-ink: #171717;
@@ -58,8 +56,6 @@ function getComtyStyle() {
58
56
  --comty-dialog-width: 32rem;
59
57
  --comty-dialog-shadow: 0 1.5rem 4rem rgb(0 0 0 / .16);
60
58
  --comty-motion-duration: 220ms;
61
- --comty-working-dot-size: .25em;
62
- --comty-working-dot-gap: .125em;
63
59
  --comty-ease-out: cubic-bezier(0.23, 1, 0.32, 1);
64
60
  --comty-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
65
61
  position: fixed;
@@ -71,68 +67,7 @@ function getComtyStyle() {
71
67
  font-family: var(--comty-font);
72
68
  color-scheme: dark;
73
69
  }
74
- html.comty-agent-enabled body { transition: margin-left 220ms cubic-bezier(0.23, 1, 0.32, 1), margin-right 220ms cubic-bezier(0.23, 1, 0.32, 1); }
75
- html.comty-agent-docked[data-comty-agent-side="left"] body { margin-left: 22rem; }
76
- html.comty-agent-docked[data-comty-agent-side="right"] body { margin-right: 22rem; }
77
- @media (max-width: 50rem) { html.comty-agent-docked body { margin-left: 0; margin-right: 0; } }
78
- #comty-root > .comty-agent-panel { position: fixed; left: 0; top: 0; bottom: 0; z-index: 2147483647; width: min(22rem, calc(100vw - 3rem)); box-sizing: border-box; display: flex; flex-direction: column; overflow: hidden; pointer-events: auto; border-right: .0625rem solid var(--comty-hover-surface); background: var(--comty-surface); color: var(--comty-foreground); font: .875rem/1.4 ui-sans-serif, system-ui, sans-serif; transform: translateX(0); transition: transform var(--comty-motion-duration) var(--comty-ease-out); color-scheme: dark; }
79
- #comty-root > .comty-agent-panel[data-side="right"] { left: auto; right: 0; border-right: 0; border-left: .0625rem solid var(--comty-hover-surface); }
80
- #comty-root > .comty-agent-panel[data-closed] { transform: translateX(-100%); pointer-events: none; }
81
- #comty-root > .comty-agent-panel[data-side="right"][data-closed] { transform: translateX(100%); }
82
- #comty-root > .comty-agent-panel[hidden] { display: none; }
83
- .comty-agent-panel *, .comty-agent-panel *::before { box-sizing: border-box; }
84
- .comty-agent-panel-header { display: flex; flex: 0 0 auto; align-items: center; gap: .75rem; padding: .5rem .75rem; border-bottom: .0625rem solid var(--comty-hover-surface); }
85
- .comty-agent-brand { display: grid; place-items: center; width: 2.375rem; height: 2.375rem; flex-shrink: 0; border-radius: .6875rem; color: var(--comty-accent); background: var(--comty-hover-surface); }
86
- .comty-agent-panel svg { display: block; width: 1rem; height: 1rem; flex-shrink: 0; }
87
- .comty-agent-brand svg { width: 1.25rem; height: 1.25rem; }
88
- .comty-agent-heading { flex: 1; min-width: 0; }
89
- .comty-agent-heading strong { display: block; font-weight: 600; font-size: .875rem; }
90
- .comty-agent-panel-content { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: var(--comty-hover-surface) transparent; padding: .375rem .5rem 2rem; }
91
- .comty-agent-item { padding: .375rem .25rem; overflow-wrap: anywhere; }
92
- .comty-agent-item + .comty-agent-item { border-top: .0625rem solid var(--comty-hover-surface); }
93
- .comty-agent-item h3 { margin: 0 0 .25rem; color: var(--comty-foreground); font: 500 .875rem/1.4 ui-sans-serif, system-ui, sans-serif; }
94
- .comty-agent-list { display: grid; gap: .125rem; }
95
- .comty-agent-row { position: relative; display: flex; align-items: center; gap: .625rem; min-height: 2rem; padding: .25rem .5rem; border-radius: .5rem; color: var(--comty-foreground); }
96
- .comty-agent-row:hover { background: var(--comty-hover-surface); }
97
- .comty-agent-dot { width: .4375rem; height: .4375rem; flex: 0 0 auto; border-radius: 50%; background: var(--comty-muted); }
98
- .comty-working-indicator { display: inline-grid; grid-template-columns: repeat(3, var(--comty-working-dot-size)); gap: var(--comty-working-dot-gap); flex: 0 0 auto; color: var(--comty-foreground); }
99
- .comty-working-indicator > i { display: block; width: var(--comty-working-dot-size); height: var(--comty-working-dot-size); border-radius: 50%; background: currentColor; opacity: .25; transition: opacity 150ms linear; }
100
- .comty-working-indicator > i[data-active] { opacity: 1; }
101
- .comty-agent-dot[data-status="success"] { background: var(--comty-agent-success); }
102
- .comty-agent-dot[data-status="error"] { background: var(--comty-agent-error); }
103
- .comty-agent-row-name { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
104
- .comty-agent-row-state { flex: 0 0 auto; color: var(--comty-muted); font-size: .875rem; }
105
- .comty-agent-row-actions { position: absolute; top: 50%; right: .25rem; display: flex; gap: .25rem; border-radius: .25rem; background: var(--comty-hover-surface); opacity: 0; pointer-events: none; transform: translateY(-50%); }
106
- .comty-agent-row:hover .comty-agent-row-actions, .comty-agent-row-actions:has(.comty-agent-action:focus-visible) { opacity: 1; pointer-events: auto; }
107
- @media (hover: none) { .comty-agent-row-actions { position: static; opacity: 1; pointer-events: auto; transform: none; background: transparent; } }
108
- .comty-agent-panel .comty-agent-row-actions .comty-agent-action { min-height: 1.5rem; padding: .125rem .375rem; border-radius: .25rem; background: transparent; color: var(--comty-muted); font-size: .875rem; }
109
- .comty-agent-panel .comty-agent-row-actions .comty-agent-action:hover { color: var(--comty-foreground); background: var(--comty-surface); }
110
- .comty-agent-error-popover { position: fixed; z-index: 2147483647; width: min(20rem, calc(100vw - 1rem)); max-height: calc(100vh - 1rem); overflow: auto; padding: .75rem .875rem; border: 0; border-radius: .625rem; background: var(--comty-surface); box-shadow: var(--comty-floating-shadow); color: var(--comty-foreground); font: .875rem/1.4 ui-sans-serif, system-ui, sans-serif; pointer-events: none; color-scheme: dark; }
111
- .comty-agent-error-popover strong { display: block; font-weight: 600; }
112
- .comty-agent-error-popover p { margin: .375rem 0 0; color: var(--comty-muted); white-space: pre-wrap; overflow-wrap: anywhere; }
113
- .comty-agent-panel p { margin: .5rem 0 0; font: inherit; color: var(--comty-muted); }
114
- .comty-agent-error { margin-top: .75rem; }
115
- .comty-agent-error strong { display: block; font-weight: 500; color: var(--comty-foreground); }
116
- .comty-agent-error p { margin-top: .25rem; }
117
- .comty-agent-banner { margin-bottom: 1rem; }
118
- .comty-agent-banner .comty-agent-error { margin-top: 0; }
119
- .comty-agent-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .875rem; }
120
- .comty-agent-panel .comty-agent-action { display: inline-flex; align-items: center; justify-content: center; gap: .375rem; min-height: 2rem; margin: 0; padding: .375rem .625rem; border: 0; border-radius: .5rem; font: 500 .875rem/1.4 ui-sans-serif, system-ui, sans-serif; cursor: pointer; color: var(--comty-foreground); background: var(--comty-hover-surface); transition: background-color 150ms ease; }
121
- .comty-agent-panel .comty-agent-action:hover { background: color-mix(in srgb, var(--comty-foreground) 12%, var(--comty-hover-surface)); }
122
- .comty-agent-panel .comty-agent-action[data-primary] { color: var(--comty-paper); background: var(--comty-accent); }
123
- .comty-agent-panel .comty-agent-action:disabled { opacity: .5; cursor: wait; }
124
- .comty-agent-panel .comty-agent-close { width: 1.5rem; min-height: 1.5rem; padding: 0; background: transparent; color: var(--comty-muted); }
125
- .comty-agent-panel :is(button, summary):focus-visible { outline: .125rem solid var(--comty-accent); outline-offset: .1875rem; }
126
- .comty-agent-details { margin-top: .625rem; }
127
- .comty-agent-panel summary { cursor: pointer; color: var(--comty-muted); font-size: .875rem; }
128
- .comty-agent-panel pre { margin: .5rem 0 0; padding: .625rem; white-space: pre-wrap; overflow-wrap: anywhere; max-height: 10rem; overflow: auto; border-radius: .5rem; background: var(--comty-surface); color: var(--comty-muted); font: .875rem/1.4 ui-monospace, monospace; }
129
- .comty-agent-empty { padding: 1rem .5rem; text-align: center; }
130
- .comty-agent-empty .comty-agent-brand { margin: 0 auto .875rem; }
131
- .comty-agent-empty strong { font-size: .875rem; font-weight: 500; }
132
- .comty-agent-empty p { max-width: 15rem; margin: .5rem auto 0; font-size: .875rem; }
133
- .comty-agent-working { position: fixed; z-index: 1; box-sizing: border-box; border: 2px solid var(--comty-accent); border-radius: .25rem; pointer-events: none; }
134
- .comty-agent-working-badge { position: absolute; left: -.125rem; bottom: 100%; display: inline-flex; align-items: center; gap: .4rem; padding: .25rem .5rem; border-radius: .375rem .375rem 0 0; background: var(--comty-surface); color: var(--comty-foreground); font: 600 .6875rem/1.4 ui-sans-serif, system-ui, sans-serif; white-space: nowrap; }
135
- .comty-agent-working[data-badge-below] .comty-agent-working-badge { bottom: auto; top: 100%; border-radius: 0 0 .375rem .375rem; }
70
+
136
71
  #comty-root { cursor: default; }
137
72
  #comty-root::backdrop { background: transparent; pointer-events: none; }
138
73
  html.comty-comment-placement,
@@ -205,8 +140,7 @@ function getComtyStyle() {
205
140
  #comty-root [hidden] { display: none !important; }
206
141
  [data-comty-anchor-hidden] { visibility: hidden !important; pointer-events: none !important; }
207
142
  @media (prefers-reduced-motion: reduce) {
208
- html.comty-agent-enabled body { transition: none; }
209
- .comty-toolbar, .comty-control-button, .comty-sidepanel, .comty-pin, .comty-bubble, .comty-agent-panel, .comty-agent-action, .comty-agent-dot, .comty-working-indicator > i { transition: none !important; animation: none !important; }
143
+ .comty-toolbar, .comty-control-button, .comty-sidepanel, .comty-pin, .comty-bubble { transition: none !important; animation: none !important; }
210
144
  }
211
145
 
212
146
  .comty-sidepanel {
@@ -767,12 +701,12 @@ function getComtyStyle() {
767
701
  }
768
702
 
769
703
  .comty-popover-item.comty-popover-item-destructive {
770
- color: var(--comty-agent-error);
704
+ color: var(--comty-error);
771
705
  }
772
706
 
773
707
  .comty-popover-item.comty-popover-item-destructive:hover,
774
708
  .comty-popover-item.comty-popover-item-destructive:focus-visible {
775
- background: color-mix(in srgb, var(--comty-agent-error) 12%, var(--comty-surface));
709
+ background: color-mix(in srgb, var(--comty-error) 12%, var(--comty-surface));
776
710
  outline: none;
777
711
  }
778
712
 
@@ -2328,7 +2262,7 @@ function createCommentThread(context) {
2328
2262
  const {
2329
2263
  root, apiUrl, projectKey, commentStatuses, selectedStatusFilters, placedPins,
2330
2264
  closeBubbles, getCommentStatus, updateCommentStatus, applyStatusDot,
2331
- renderSidepanelComments, applyStatusFilters, loadComments, createThreadItem,
2265
+ renderSidepanelComments, applyStatusFilters, createThreadItem,
2332
2266
  isOwnCommentEntry, updateCommentContent, deleteSdkComment, getCommentId,
2333
2267
  updateReplyContent, deleteSdkReply, createCommentAvatar, getSdkHeaders,
2334
2268
  showAuthPrompt,
@@ -2358,7 +2292,7 @@ function createCommentThread(context) {
2358
2292
 
2359
2293
  const title = document.createElement("h2");
2360
2294
  title.className = "comty-bubble-title";
2361
- title.innerText = comment.kind === "agent" ? "Agent task" : "Comment";
2295
+ title.innerText = "Comment";
2362
2296
  header.appendChild(title);
2363
2297
 
2364
2298
  const headerActions = document.createElement("div");
@@ -2402,7 +2336,7 @@ function createCommentThread(context) {
2402
2336
  };
2403
2337
 
2404
2338
  const saveStatus = async (nextStatus, control) => {
2405
- if (!context.canWrite && !comment.local_agent) return false;
2339
+ if (!context.canWrite) return false;
2406
2340
  control.disabled = true;
2407
2341
  const savedStatus = await updateCommentStatus(comment, nextStatus);
2408
2342
  control.disabled = false;
@@ -2418,10 +2352,6 @@ function createCommentThread(context) {
2418
2352
  syncStatusTrigger();
2419
2353
  renderSidepanelComments();
2420
2354
  applyStatusFilters();
2421
- if (comment.local_agent && savedStatus === "done") {
2422
- closeBubbles();
2423
- void loadComments({ force: true });
2424
- }
2425
2355
  if (
2426
2356
  selectedStatusFilters.size > 0 &&
2427
2357
  !selectedStatusFilters.has(savedStatusOption.value)
@@ -2431,7 +2361,7 @@ function createCommentThread(context) {
2431
2361
  return true;
2432
2362
  };
2433
2363
 
2434
- statusMenuButton.disabled = comment.local_agent || !context.canWrite;
2364
+ statusMenuButton.disabled = !context.canWrite;
2435
2365
  statusMenuButton.onclick = (event) => {
2436
2366
  event.stopPropagation();
2437
2367
  const existingPopover = document.querySelector(
@@ -2574,7 +2504,7 @@ function createCommentThread(context) {
2574
2504
  );
2575
2505
  };
2576
2506
 
2577
- const mainItem = createThreadItem(comment, { showMore: !comment.local_agent && isOwnCommentEntry(comment) });
2507
+ const mainItem = createThreadItem(comment, { showMore: isOwnCommentEntry(comment) });
2578
2508
 
2579
2509
  const startEditingEntry = (entry, item, persist) => {
2580
2510
  if (!isOwnCommentEntry(entry)) return;
@@ -2721,7 +2651,7 @@ function createCommentThread(context) {
2721
2651
  const replyForm = document.createElement("div");
2722
2652
  replyForm.className = "comty-reply-form";
2723
2653
 
2724
- if (context.canWrite && !comment.local_agent) {
2654
+ if (context.canWrite) {
2725
2655
  replyForm.appendChild(createCommentAvatar(context.currentUser || { name: "You" }));
2726
2656
  const replyField = document.createElement("div");
2727
2657
  replyField.className = "comty-reply-field";
@@ -2792,7 +2722,7 @@ function createCommentThread(context) {
2792
2722
  replyField.appendChild(replyInput);
2793
2723
  replyField.appendChild(replyButton);
2794
2724
  replyForm.appendChild(replyField);
2795
- } else if (!comment.local_agent) {
2725
+ } else {
2796
2726
  replyForm.classList.add("comty-reply-form-guest");
2797
2727
  const signInButton = document.createElement("button");
2798
2728
  signInButton.className = "comty-sign-in-reply";
@@ -2805,7 +2735,7 @@ function createCommentThread(context) {
2805
2735
  replyForm.appendChild(signInButton);
2806
2736
  }
2807
2737
 
2808
- if (!comment.local_agent) thread.appendChild(replyForm);
2738
+ thread.appendChild(replyForm);
2809
2739
  bubble.appendChild(thread);
2810
2740
  root.appendChild(bubble);
2811
2741
 
@@ -3042,17 +2972,7 @@ const instanceKey = Symbol.for("comty.sdk.instance");
3042
2972
  /** Initialize once per document; safe to import and call during server rendering. */
3043
2973
  function initComty(options = {}) {
3044
2974
  if (typeof window === "undefined" || typeof document === "undefined") return Promise.resolve();
3045
- const isLocalSite = ["localhost", "127.0.0.1", "[::1]"].includes(window.location.hostname);
3046
- const agent = options.agent;
3047
- if (agent && (!isLocalSite || typeof agent.token !== "string" || !/^[a-f0-9]{64}$/.test(agent.token))) {
3048
- return Promise.reject(new TypeError("Comty: invalid local companion configuration"));
3049
- }
3050
- if (agent) {
3051
- try {
3052
- if (new URL(agent.url).origin !== window.location.origin) throw new Error();
3053
- } catch { return Promise.reject(new TypeError("Comty: companion must share the page origin")); }
3054
- }
3055
- const projectKey = options.projectKey || (agent ? "local" : undefined);
2975
+ const projectKey = options.projectKey;
3056
2976
  const apiUrl = options.apiUrl || "http://localhost:4000";
3057
2977
  if (typeof projectKey !== "string" || !projectKey.trim()) {
3058
2978
  return Promise.reject(new TypeError("Comty: projectKey is required"));
@@ -3064,14 +2984,12 @@ function initComty(options = {}) {
3064
2984
  if (!["http:", "https:"].includes(parsedApi.protocol)) {
3065
2985
  return Promise.reject(new TypeError("Comty: apiUrl must be an absolute HTTP(S) URL"));
3066
2986
  }
3067
- const configuration = JSON.stringify([projectKey, apiUrl, agent || null]);
2987
+ const configuration = JSON.stringify([projectKey, apiUrl]);
3068
2988
  const existing = window[instanceKey];
3069
2989
  if (existing) {
3070
2990
  return existing.configuration === configuration ? existing.ready
3071
2991
  : Promise.reject(new Error("Comty: already initialized with different options"));
3072
2992
  }
3073
- const agentBridgeUrl = agent?.url;
3074
- const localOnly = Boolean(agent && !options.projectKey);
3075
2993
  const ready = new Promise((resolve, reject) => {
3076
2994
  const mount = () => {
3077
2995
  try { resolve(mountComty()); } catch (error) { reject(error); }
@@ -3085,19 +3003,10 @@ function initComty(options = {}) {
3085
3003
 
3086
3004
  function mountComty() {
3087
3005
  let projectId = null;
3088
- let localTasks = [];
3089
- let localApprovals = [];
3090
- let agentPanelOpen = false;
3091
- let agentPanelSignature = "";
3092
- let agentPanelTransition = 0;
3093
- let agentConnectionError = "";
3094
- let agentActionError = "";
3095
- const agentPendingActions = new Set();
3096
3006
  const session = {
3097
3007
  mode: "off",
3098
- get comments() { return this.mode === "browse" || this.mode === "edit" || this.mode === "agent"; },
3099
- get edit() { return this.mode === "edit" || this.mode === "agent"; },
3100
- get agent() { return this.mode === "agent"; },
3008
+ get comments() { return this.mode === "browse" || this.mode === "edit"; },
3009
+ get edit() { return this.mode === "edit"; },
3101
3010
  get inspect() { return this.mode === "inspect"; },
3102
3011
  };
3103
3012
  const selectedStatusFilters = new Set();
@@ -3118,10 +3027,9 @@ function initComty(options = {}) {
3118
3027
  const tokenStorageKey = `comty:${projectKey}:token`;
3119
3028
  let sdkToken = "";
3120
3029
  const activeHoverCommentIds = new Set();
3121
- /** @type {null | 'edit' | 'browse' | 'agent'} */
3030
+ /** @type {null | 'edit' | 'browse'} */
3122
3031
  let sessionEntry = null;
3123
3032
  const placedPins = new Map();
3124
- const workingOutlines = new Map();
3125
3033
  const placementDiagnostics = new Map();
3126
3034
  let inspectedElement = null;
3127
3035
  let selectedElement = null;
@@ -3168,7 +3076,6 @@ function initComty(options = {}) {
3168
3076
  const root = document.createElement("div");
3169
3077
  root.id = "comty-root";
3170
3078
  document.body.appendChild(root);
3171
- if (agent) document.documentElement.classList.add("comty-agent-enabled");
3172
3079
 
3173
3080
  const style = document.createElement("style");
3174
3081
  style.innerHTML = getComtyStyle();
@@ -3216,40 +3123,20 @@ function initComty(options = {}) {
3216
3123
  const inspectorBtn = toolButton("Inspect · Shift I", '<path d="M8 3H5a2 2 0 0 0-2 2v3m13-5h3a2 2 0 0 1 2 2v3M3 16v3a2 2 0 0 0 2 2h3m13-5v3a2 2 0 0 1-2 2h-3"/><path d="m9 9 8 4-4 1-1 4Z"/>', () => setSession("inspect"));
3217
3124
  const btn = toolButton("Comment · Shift C", '<path d="M21 11.5a8.4 8.4 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.4 8.4 0 0 1-3.8-.9L3 21l1.9-5.7a8.4 8.4 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6A8.4 8.4 0 0 1 12.5 3h.5a8.5 8.5 0 0 1 8 8v.5Z"/>', () => {
3218
3125
  if (!canWrite) showAuthPrompt();
3219
- else if (session.agent || session.inspect || !isSessionActive()) startEditSession();
3126
+ else if (session.inspect || !isSessionActive()) startEditSession();
3220
3127
  else if (!session.edit) setSession("edit", { entry: sessionEntry });
3221
3128
  });
3222
3129
  btn.id = "comty-toggle";
3223
- const agentBtn = isLocalSite
3224
- ? toolButton("Agent task · localhost only", '<path d="M8 7 3 12l5 5m8-10 5 5-5 5M14 4l-4 16"/>', () => {
3225
- startAgentSession();
3226
- })
3227
- : null;
3228
3130
  const divider = document.createElement("span");
3229
3131
  divider.className = "comty-tool-divider";
3230
3132
  toolbar.appendChild(divider);
3231
3133
  const commentTools = document.createElement("div");
3232
3134
  commentTools.className = "comty-tool-context";
3233
3135
  toolbar.appendChild(commentTools);
3234
- const agentTools = agentBtn ? document.createElement("div") : null;
3235
- if (agentTools) {
3236
- agentTools.className = "comty-tool-context";
3237
- agentTools.hidden = true;
3238
- toolbar.appendChild(agentTools);
3239
- }
3240
- const agentHistoryBtn = agentTools ? toolButton("Local agent history", '<path d="M3 12a9 9 0 1 0 3-6.7M3 4v4h4"/><path d="M12 7v5l3 2"/>', () => {
3241
- if (!agent) { showAgentBridgeError(); return; }
3242
- agentPanelOpen = !agentPanelOpen;
3243
- renderAgentPanel();
3244
- }) : null;
3245
- if (agentHistoryBtn) {
3246
- agentHistoryBtn.setAttribute("aria-expanded", "false");
3247
- agentTools.appendChild(agentHistoryBtn);
3248
- }
3249
3136
  const primaryTools = document.createElement("div");
3250
3137
  primaryTools.className = "comty-tool-primary";
3251
3138
  toolbar.insertBefore(primaryTools, browseBtn);
3252
- for (const button of [browseBtn, inspectorBtn, btn, agentBtn].filter(Boolean)) primaryTools.appendChild(button);
3139
+ for (const button of [browseBtn, inspectorBtn, btn]) primaryTools.appendChild(button);
3253
3140
  const inspectorTools = document.createElement("div");
3254
3141
  inspectorTools.className = "comty-tool-context";
3255
3142
  inspectorTools.hidden = true;
@@ -4098,50 +3985,6 @@ function initComty(options = {}) {
4098
3985
  let toolbarMotionFrame = 0;
4099
3986
  let toolbarAnimations = [];
4100
3987
  const reducedMotion = matchMedia("(prefers-reduced-motion: reduce)");
4101
- let workingIndicatorTimer = 0;
4102
- function scheduleWorkingIndicators() {
4103
- if (workingIndicatorTimer || reducedMotion.matches || document.hidden) return;
4104
- workingIndicatorTimer = setTimeout(() => {
4105
- workingIndicatorTimer = 0;
4106
- if (!root.isConnected) return;
4107
- const indicators = root.querySelectorAll('.comty-working-indicator');
4108
- if (!indicators.length) return;
4109
- for (const indicator of indicators) {
4110
- const previous = Number(indicator.dataset.activeDots.split(',')[0]);
4111
- const first = (previous + 1 + Math.floor(Math.random() * 8)) % 9;
4112
- const second = (first + 1 + Math.floor(Math.random() * 8)) % 9;
4113
- indicator.dataset.activeDots = `${first},${second}`;
4114
- [...indicator.children].forEach((dot, index) => dot.toggleAttribute('data-active', index === first || index === second));
4115
- }
4116
- scheduleWorkingIndicators();
4117
- }, 600);
4118
- }
4119
- function createWorkingIndicator() {
4120
- const indicator = document.createElement('span');
4121
- indicator.className = 'comty-working-indicator';
4122
- indicator.setAttribute('aria-hidden', 'true');
4123
- indicator.dataset.activeDots = '3,5';
4124
- for (let index = 0; index < 9; index++) {
4125
- const dot = document.createElement('i');
4126
- dot.toggleAttribute('data-active', index === 3 || index === 5);
4127
- indicator.appendChild(dot);
4128
- }
4129
- scheduleWorkingIndicators();
4130
- return indicator;
4131
- }
4132
- function resetWorkingIndicators() {
4133
- clearTimeout(workingIndicatorTimer);
4134
- workingIndicatorTimer = 0;
4135
- if (reducedMotion.matches) {
4136
- for (const indicator of root.querySelectorAll('.comty-working-indicator')) {
4137
- indicator.dataset.activeDots = '3,5';
4138
- [...indicator.children].forEach((dot, index) => dot.toggleAttribute('data-active', index === 3 || index === 5));
4139
- }
4140
- }
4141
- if (root.querySelector('.comty-working-indicator')) scheduleWorkingIndicators();
4142
- }
4143
- reducedMotion.addEventListener('change', resetWorkingIndicators);
4144
- document.addEventListener('visibilitychange', resetWorkingIndicators);
4145
3988
  const clampToolbar = (value, size, viewport) => Math.max(8, Math.min(value, viewport - size - 8));
4146
3989
  function rememberToolbarPosition(left, top) {
4147
3990
  const width = toolbar.offsetWidth, height = toolbar.offsetHeight;
@@ -4254,7 +4097,7 @@ function initComty(options = {}) {
4254
4097
 
4255
4098
  function prepareToolbarMotion() {
4256
4099
  if (toolbarMotionFrame) return;
4257
- const nodes = [toolbarSurface, dragHandle, primaryTools, commentTools, agentTools, inspectorTools].filter(Boolean);
4100
+ const nodes = [toolbarSurface, dragHandle, primaryTools, commentTools, inspectorTools].filter(Boolean);
4258
4101
  // Move each group's background with its icons, including when interrupted.
4259
4102
  const before = new Map(nodes.filter(node => !node.hidden).map(node => [node, {
4260
4103
  rect: node.getBoundingClientRect(), opacity: getComputedStyle(node).opacity,
@@ -4497,7 +4340,7 @@ function initComty(options = {}) {
4497
4340
  return;
4498
4341
  }
4499
4342
 
4500
- if ((session.edit && mode === "browse") || (session.agent && mode === "edit")) {
4343
+ if (session.edit && mode === "browse") {
4501
4344
  closeBubbles();
4502
4345
  }
4503
4346
  const hadComments = session.comments;
@@ -4511,7 +4354,6 @@ function initComty(options = {}) {
4511
4354
  } else {
4512
4355
  hideInspector();
4513
4356
  }
4514
- if (session.agent && sidepanelOpen) setSidepanelOpen(false);
4515
4357
  syncToolbar();
4516
4358
  ensureLiveTracking();
4517
4359
  if (renderComments || !hadComments) renderCachedComments();
@@ -4524,10 +4366,6 @@ function initComty(options = {}) {
4524
4366
  }
4525
4367
 
4526
4368
  function showAuthPrompt(forbidden = false) {
4527
- if (localOnly) {
4528
- showAgentBridgeError("Shared comments need a Comty project key. Use the Agent tool for local tasks without signing in.");
4529
- return;
4530
- }
4531
4369
  document.querySelector(".comty-auth-backdrop")?.remove();
4532
4370
  const opener = document.activeElement;
4533
4371
  const backdrop = document.createElement("div");
@@ -4589,17 +4427,14 @@ function initComty(options = {}) {
4589
4427
  }
4590
4428
 
4591
4429
  function syncToolbar() {
4592
- if (commentTools.hidden !== (session.inspect || session.agent) || inspectorTools.hidden !== !session.inspect || (agentTools && agentTools.hidden !== !session.agent)) prepareToolbarMotion();
4430
+ if (commentTools.hidden !== session.inspect || inspectorTools.hidden !== !session.inspect) prepareToolbarMotion();
4593
4431
  root.classList.toggle("comty-active", session.comments || session.edit || sidepanelOpen || session.inspect);
4594
4432
  browseBtn.setAttribute("aria-pressed", String(!session.edit && !session.inspect));
4595
4433
  inspectorBtn.setAttribute("aria-pressed", String(session.inspect));
4596
- btn.setAttribute("aria-pressed", String(session.edit && !session.agent));
4597
- agentBtn?.setAttribute("aria-pressed", String(session.edit && session.agent));
4598
- commentTools.hidden = session.inspect || session.agent;
4599
- if (agentTools) agentTools.hidden = !session.agent;
4434
+ btn.setAttribute("aria-pressed", String(session.edit));
4435
+ commentTools.hidden = session.inspect;
4600
4436
  inspectorTools.hidden = !session.inspect;
4601
4437
  syncInspectorTools();
4602
- renderAgentPanel();
4603
4438
  }
4604
4439
 
4605
4440
  const inspectionLayer = document.createElement("div");
@@ -5047,13 +4882,6 @@ function initComty(options = {}) {
5047
4882
  setSession("edit", { renderComments: true });
5048
4883
  }
5049
4884
 
5050
- function startAgentSession() {
5051
- if (!isLocalSite) return;
5052
- if (session.agent) return;
5053
- closeBubbles();
5054
- setSession("agent", { renderComments: true });
5055
- }
5056
-
5057
4885
  function toggleSidepanel() {
5058
4886
  if (sidepanelOpen) {
5059
4887
  setSidepanelOpen(false);
@@ -5077,7 +4905,7 @@ function initComty(options = {}) {
5077
4905
  showAuthPrompt();
5078
4906
  return;
5079
4907
  }
5080
- if (session.agent || session.inspect || !isSessionActive()) {
4908
+ if (session.inspect || !isSessionActive()) {
5081
4909
  startEditSession();
5082
4910
  return;
5083
4911
  }
@@ -5852,7 +5680,7 @@ function initComty(options = {}) {
5852
5680
 
5853
5681
  const textarea = document.createElement("textarea");
5854
5682
  textarea.className = "comty-create-textarea";
5855
- textarea.placeholder = payload.kind === "agent" ? "Describe the change for your agent" : "Add a comment";
5683
+ textarea.placeholder = "Add a comment";
5856
5684
  textarea.setAttribute("aria-label", textarea.placeholder);
5857
5685
  textarea.rows = 1;
5858
5686
 
@@ -5861,7 +5689,7 @@ function initComty(options = {}) {
5861
5689
 
5862
5690
  const submitBtn = document.createElement("button");
5863
5691
  submitBtn.className = "comty-btn-submit";
5864
- submitBtn.setAttribute("aria-label", payload.kind === "agent" ? "Send agent task" : "Post comment");
5692
+ submitBtn.setAttribute("aria-label", "Post comment");
5865
5693
  submitBtn.innerHTML = `
5866
5694
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
5867
5695
  <path d="M12 19V5M5 12l7-7 7 7"/>
@@ -5875,22 +5703,18 @@ function initComty(options = {}) {
5875
5703
  submitBtn.disabled = true;
5876
5704
  textarea.disabled = true;
5877
5705
 
5878
- if (payload.kind === "agent" && !agent) {
5879
- showAgentBridgeError(); submitBtn.disabled = false; textarea.disabled = false; return;
5880
- }
5881
5706
  payload.content = content;
5882
5707
  textarea.textContent = content;
5883
5708
 
5884
5709
  let post;
5885
5710
  try {
5886
- post = await fetch(payload.kind === "agent" ? `${agentBridgeUrl}/tasks` : `${apiUrl}/api/comments`, {
5711
+ post = await fetch(`${apiUrl}/api/comments`, {
5887
5712
  method: "POST",
5888
- headers: payload.kind === "agent" ? agentHeaders() : getSdkHeaders({ "Content-Type": "application/json" }),
5889
- body: JSON.stringify(payload.kind === "agent" ? { ...payload, projectKey } : payload),
5713
+ headers: getSdkHeaders({ "Content-Type": "application/json" }),
5714
+ body: JSON.stringify(payload),
5890
5715
  });
5891
5716
  } catch (error) {
5892
5717
  console.error("Comty: save failed", error);
5893
- if (payload.kind === "agent") showAgentBridgeError();
5894
5718
  submitBtn.disabled = false;
5895
5719
  textarea.disabled = false;
5896
5720
  return;
@@ -5898,15 +5722,14 @@ function initComty(options = {}) {
5898
5722
 
5899
5723
  if (!post.ok) {
5900
5724
  console.error("Comty: save failed", await post.text());
5901
- if (payload.kind === "agent") showAgentBridgeError();
5902
5725
  submitBtn.disabled = false;
5903
5726
  textarea.disabled = false;
5904
5727
  return;
5905
5728
  }
5906
5729
 
5907
5730
  const data = await post.json();
5908
- const commentId = payload.kind === "agent" ? data?.task?.id : data?.id;
5909
- const captureNodes = commentId && payload.kind !== "agent"
5731
+ const commentId = data?.id;
5732
+ const captureNodes = commentId
5910
5733
  ? createCaptureAnnotation(pin, bubble, content)
5911
5734
  : [];
5912
5735
  bubble.remove();
@@ -5914,10 +5737,9 @@ function initComty(options = {}) {
5914
5737
  draftAnchor = null;
5915
5738
  hideInspector();
5916
5739
  if (commentId) {
5917
- if (payload.kind === "agent") showAgentTaskToast(String(commentId));
5918
- else addLocalComment(String(commentId), payload);
5740
+ addLocalComment(String(commentId), payload);
5919
5741
  void loadComments({ force: true });
5920
- if (payload.kind !== "agent") void uploadCommentScreenshot(String(commentId), payload, captureNodes);
5742
+ void uploadCommentScreenshot(String(commentId), payload, captureNodes);
5921
5743
  } else {
5922
5744
  void loadComments({ force: true });
5923
5745
  }
@@ -5974,223 +5796,6 @@ function initComty(options = {}) {
5974
5796
  setTimeout(() => textarea.focus(), 10);
5975
5797
  }
5976
5798
 
5977
- function agentHeaders() { return { "Content-Type": "application/json", "X-Comty-Token": agent?.token || "" }; }
5978
-
5979
- function showAgentBridgeError(message = "Start your app with comty dev to use the local agent. Check the terminal if it is already running.") {
5980
- root.querySelectorAll(".comty-agent-task-toast").forEach((node) => node.remove());
5981
- const toast = document.createElement("div");
5982
- toast.className = "comty-auth-toast comty-agent-task-toast";
5983
- toast.setAttribute("role", "alert");
5984
- const issue = describeAgentError(message);
5985
- toast.textContent = issue.title + ". " + issue.description;
5986
- root.appendChild(toast);
5987
- setTimeout(() => toast.remove(), 5000);
5988
- }
5989
-
5990
- function showAgentTaskToast() {
5991
- agentPanelOpen = true;
5992
- agentPanelSignature = "";
5993
- renderAgentPanel();
5994
- }
5995
-
5996
- function describeAgentError(error) {
5997
- const raw = typeof error === 'string' ? error : JSON.stringify(error, null, 2) || 'Unknown error';
5998
- let value = error;
5999
- for (let depth = 0; depth < 8; depth++) {
6000
- if (typeof value === 'string') {
6001
- try { value = JSON.parse(value); continue; } catch {}
6002
- const start = value.indexOf('{'), end = value.lastIndexOf('}');
6003
- if (start >= 0 && end > start) { try { value = JSON.parse(value.slice(start, end + 1)); continue; } catch {} }
6004
- break;
6005
- }
6006
- if (!value || typeof value !== 'object') break;
6007
- value = value.error || value.message || value.cause || value.stderr || value;
6008
- }
6009
- const message = typeof value === 'string' ? value : '';
6010
- const source = raw + ' ' + message;
6011
- const agentName = /codex/i.test(source) ? 'Codex' : /claude/i.test(source) ? 'Claude Code' : /cursor/i.test(source) ? 'Cursor' : 'your coding agent';
6012
- let title, description;
6013
- if (/requires a newer version|upgrade.*latest|outdated|unsupported.*version/i.test(source)) {
6014
- title = 'Agent update required'; description = `Update ${agentName}, restart your local development session, then retry this task.`;
6015
- } else if (/insufficient_quota|quota exceeded|credit balance|billing|usage limit/i.test(source)) {
6016
- title = 'Usage limit reached'; description = 'Check your agent account’s usage allowance or billing, then retry when capacity is available.';
6017
- } else if (/rate.?limit|too many requests|\b429\b/i.test(source)) {
6018
- title = 'Too many requests'; description = 'The agent is temporarily rate limited. Wait a moment before retrying.';
6019
- } else if (/unauthorized|unauthenticated|authentication|not logged|sign.?in|log.?in|invalid.api.key|\b401\b/i.test(source)) {
6020
- title = 'Sign in to your agent'; description = `Open ${agentName} and sign in again, then retry this task.`;
6021
- } else if (/model.*(?:not found|does not exist|unavailable|not supported)|unsupported model|model_not_found/i.test(source)) {
6022
- title = 'Model unavailable'; description = 'Choose a model available to your agent account in the local Comty configuration, then restart and retry.';
6023
- } else if (/disconnected|ECONNREFUSED|ENOTFOUND|network|failed to fetch|development server stopped/i.test(source)) {
6024
- title = 'Connection lost'; description = 'Check that your local development server and coding agent are running. Reconnect before retrying; your task history is kept.';
6025
- } else if (/timed? ?out|timeout|exceeded.*minutes/i.test(source)) {
6026
- title = 'Task timed out'; description = 'Review any changes already made, then retry with a smaller, more specific request.';
6027
- } else if (/permission|denied|forbidden|\b403\b/i.test(source)) {
6028
- title = 'Permission needed'; description = 'Check the agent’s access to this project and any pending approval before retrying.';
6029
- } else if (/ENOENT|command not found|not installed|executable.*not found/i.test(source)) {
6030
- title = 'Agent not found'; description = `Install or configure ${agentName} in your local development environment, then restart and retry.`;
6031
- } else if (/completion was not verified/i.test(source)) {
6032
- title = 'Result needs checking'; description = 'The agent could not confirm completion. Review the changes before retrying.';
6033
- } else {
6034
- title = 'Task could not finish';
6035
- description = message && !/[{}]|\[object Object\]/.test(message) ? message.slice(0, 300) : 'The agent reported an unexpected error. Review the technical details and any changes before retrying.';
6036
- }
6037
- return { title, description, raw, message };
6038
- }
6039
-
6040
- function renderAgentPanel() {
6041
- if (!agent) return;
6042
- let panel = root.querySelector(".comty-agent-panel");
6043
- if (!panel) {
6044
- panel = document.createElement("section");
6045
- panel.className = "comty-agent-panel";
6046
- panel.setAttribute("aria-label", "Local agent tasks");
6047
- panel.hidden = true;
6048
- // Keep the dock above inspection overlays and below the toolbar.
6049
- root.insertBefore(panel, toolbar);
6050
- }
6051
- const open = session.agent && agentPanelOpen;
6052
- if (open) {
6053
- if (panel.hidden) {
6054
- const rect = toolbar.getBoundingClientRect();
6055
- panel.dataset.side = rect.left + rect.width / 2 < innerWidth / 2 ? "left" : "right";
6056
- document.documentElement.dataset.comtyAgentSide = panel.dataset.side;
6057
- panel.dataset.closed = "";
6058
- panel.hidden = false;
6059
- panel.getBoundingClientRect();
6060
- }
6061
- if (panel.hasAttribute("data-closed")) { agentPanelTransition++; delete panel.dataset.closed; }
6062
- } else if (!panel.hidden && !panel.hasAttribute("data-closed")) {
6063
- const transition = ++agentPanelTransition;
6064
- panel.dataset.closed = "";
6065
- const finish = () => { if (transition === agentPanelTransition && panel.hasAttribute("data-closed")) panel.hidden = true; };
6066
- if (reducedMotion.matches) finish();
6067
- else setTimeout(finish, parseFloat(getComputedStyle(root).getPropertyValue("--comty-motion-duration")));
6068
- }
6069
- panel.inert = !open;
6070
- panel.setAttribute("aria-hidden", String(!open));
6071
- document.documentElement.classList.toggle("comty-agent-docked", open);
6072
- agentHistoryBtn?.setAttribute("aria-expanded", String(open));
6073
- agentHistoryBtn?.setAttribute("aria-pressed", String(open));
6074
- const signature = JSON.stringify([localTasks, localApprovals, agentConnectionError, agentActionError, agentPanelOpen]);
6075
- if (signature === agentPanelSignature) return;
6076
- agentPanelSignature = signature;
6077
- root.querySelector('.comty-agent-error-popover')?.remove();
6078
- const expanded = new Set([...panel.querySelectorAll('details[data-detail-key][open]')].map(node => node.dataset.detailKey));
6079
- const focusKey = panel.contains(document.activeElement) ? document.activeElement.dataset.focusKey : null;
6080
- const scrollTop = panel.querySelector('.comty-agent-panel-content')?.scrollTop || 0;
6081
- const node = (tag, className, text) => {
6082
- const element = document.createElement(tag);
6083
- if (className) element.className = className;
6084
- if (text != null) element.textContent = text;
6085
- return element;
6086
- };
6087
- const codeIcon = '<path d="m8 6-6 6 6 6m8-12 6 6-6 6m-3-15-2 18"/>';
6088
- const brand = () => { const element = node('span', 'comty-agent-brand'); element.innerHTML = icon(codeIcon); element.setAttribute('aria-hidden', 'true'); return element; };
6089
- panel.replaceChildren();
6090
- const header = node('header', 'comty-agent-panel-header');
6091
- const heading = node('div', 'comty-agent-heading');
6092
- heading.append(node('strong', '', 'Modifications'));
6093
- const toggle = node('button', 'comty-agent-action comty-agent-close'); toggle.type = 'button';
6094
- toggle.innerHTML = icon('<path d="m6 6 12 12M6 18 18 6"/>');
6095
- toggle.setAttribute('aria-label', 'Close local agent sidebar'); toggle.title = 'Close sidebar'; toggle.dataset.focusKey = 'close';
6096
- toggle.onclick = () => { agentPanelOpen = false; renderAgentPanel(); agentHistoryBtn?.focus({ preventScroll: true }); };
6097
- header.append(heading, toggle); panel.appendChild(header);
6098
- const content = node('div', 'comty-agent-panel-content'); panel.appendChild(content);
6099
- const technicalDetails = (parent, raw, key) => {
6100
- const details = node('details', 'comty-agent-details'); details.dataset.detailKey = key; details.open = expanded.has(key);
6101
- const summary = node('summary', '', 'Technical details'); summary.dataset.focusKey = 'details-' + key;
6102
- details.append(summary, node('pre', '', raw)); parent.appendChild(details);
6103
- };
6104
- const errorMessage = (parent, error, key) => {
6105
- const issue = describeAgentError(error);
6106
- const message = node('div', 'comty-agent-error');
6107
- message.append(node('strong', '', issue.title), node('p', '', issue.description));
6108
- parent.appendChild(message); technicalDetails(parent, issue.raw, key);
6109
- };
6110
- if (agentConnectionError || agentActionError) {
6111
- const banner = node('div', 'comty-agent-item comty-agent-banner'); banner.setAttribute('role', 'alert');
6112
- errorMessage(banner, agentConnectionError || agentActionError, 'connection'); content.appendChild(banner);
6113
- }
6114
- const action = (parent, label, path, input = {}, primary = false) => {
6115
- const button = node('button', 'comty-agent-action', label); button.type = 'button';
6116
- const key = path + JSON.stringify(input); button.dataset.focusKey = key;
6117
- button.disabled = agentPendingActions.has(key);
6118
- if (primary) button.dataset.primary = '';
6119
- button.onclick = async () => {
6120
- if (agentPendingActions.has(key)) return;
6121
- agentActionError = '';
6122
- agentPendingActions.add(key); button.disabled = true; button.textContent = 'Please wait…';
6123
- try {
6124
- const response = await fetch(`${agentBridgeUrl}/${path}`, { method: 'POST', headers: agentHeaders(), body: JSON.stringify(input) });
6125
- if (!response.ok) {
6126
- const body = await response.json().catch(() => null);
6127
- throw new Error(typeof body?.error === 'string' ? body.error : JSON.stringify(body?.error || { status: response.status, message: 'Request failed' }));
6128
- }
6129
- await loadComments({ force: true });
6130
- } catch (error) { agentActionError = error.message; }
6131
- finally { agentPendingActions.delete(key); agentPanelSignature = ''; renderAgentPanel(); }
6132
- };
6133
- parent.appendChild(button);
6134
- };
6135
- for (const approval of localApprovals) {
6136
- const section = node('div', 'comty-agent-item');
6137
- section.append(node('h3', '', 'Approval required'));
6138
- const task = localTasks.find(task => task.id === approval.taskId);
6139
- if (task) section.appendChild(node('p', '', task.content));
6140
- section.appendChild(node('p', '', 'Review this operation before allowing the agent to continue.'));
6141
- const operation = approval.details?.command || approval.details?.file_path || approval.details?.path;
6142
- if (typeof operation === 'string' || Array.isArray(operation)) section.appendChild(node('pre', '', Array.isArray(operation) ? operation.join(' ') : operation));
6143
- technicalDetails(section, JSON.stringify(approval.details ?? {}, null, 2), 'approval-' + approval.id);
6144
- const actions = node('div', 'comty-agent-actions');
6145
- action(actions, 'Allow once', `approvals/${approval.id}`, { allow: true }, true);
6146
- action(actions, 'Deny', `approvals/${approval.id}`, { allow: false });
6147
- section.appendChild(actions); content.appendChild(section);
6148
- }
6149
- const list = node('div', 'comty-agent-list'); content.appendChild(list);
6150
- const hideErrorPopover = () => root.querySelector('.comty-agent-error-popover')?.remove();
6151
- content.addEventListener('scroll', hideErrorPopover, { passive: true });
6152
- for (const [index, task] of [...localTasks].reverse().entries()) {
6153
- const failed = Boolean(task.error) || task.status === 'in_review';
6154
- const state = failed ? 'error' : task.status === 'done' ? 'success' : task.status === 'cancel' ? 'cancel' : 'working';
6155
- const row = node('div', 'comty-agent-row'); row.dataset.taskId = task.id;
6156
- const dot = state === 'working' ? createWorkingIndicator() : node('span', 'comty-agent-dot');
6157
- dot.dataset.status = state; dot.setAttribute('aria-hidden', 'true');
6158
- const name = node('span', 'comty-agent-row-name', task.content);
6159
- row.append(dot, name);
6160
- if (state === 'working') row.appendChild(node('span', 'comty-agent-row-state', task.status === 'todo' ? 'Starting' : 'Working'));
6161
- const actions = node('div', 'comty-agent-row-actions');
6162
- if (['in_review', 'cancel'].includes(task.status)) action(actions, 'Retry', `tasks/${task.id}/retry`);
6163
- if (['todo', 'in_progress'].includes(task.status)) action(actions, 'Cancel', `tasks/${task.id}/cancel`);
6164
- if (actions.childElementCount) row.appendChild(actions);
6165
- row.setAttribute('aria-label', `${task.content}, ${state === 'error' ? 'failed' : state === 'success' ? 'completed' : state === 'cancel' ? 'cancelled' : task.status === 'todo' ? 'starting' : 'working'}`);
6166
- if (failed) {
6167
- const tooltipId = `comty-agent-error-${index}`;
6168
- const showErrorPopover = () => {
6169
- hideErrorPopover();
6170
- const issue = describeAgentError(task.error || task.result?.summary || task.progress || 'Completion was not verified');
6171
- const popover = node('div', 'comty-agent-error-popover'); popover.id = tooltipId; popover.setAttribute('role', 'tooltip');
6172
- popover.append(node('strong', '', task.content), node('p', '', issue.message || issue.description));
6173
- root.appendChild(popover);
6174
- const rowRect = row.getBoundingClientRect();
6175
- const popoverRect = popover.getBoundingClientRect();
6176
- const left = panel.dataset.side === 'right' ? rowRect.left - popoverRect.width - 8 : rowRect.right + 8;
6177
- popover.style.left = `${Math.max(8, Math.min(left, innerWidth - popoverRect.width - 8))}px`;
6178
- popover.style.top = `${Math.max(8, Math.min(rowRect.top - 4, innerHeight - popoverRect.height - 8))}px`;
6179
- };
6180
- row.addEventListener('mouseenter', showErrorPopover);
6181
- row.addEventListener('mouseleave', hideErrorPopover);
6182
- }
6183
- list.appendChild(row);
6184
- }
6185
- if (!localTasks.length && !localApprovals.length) {
6186
- const empty = node('div', 'comty-agent-empty');
6187
- empty.append(brand(), node('strong', '', localTasks.length ? 'All caught up' : 'What shall we change?'), node('p', '', 'Point at an element on the page and describe the change you want.'));
6188
- content.appendChild(empty);
6189
- }
6190
- content.scrollTop = scrollTop;
6191
- if (focusKey && open) [...panel.querySelectorAll('[data-focus-key]')].find(element => element.dataset.focusKey === focusKey)?.focus({ preventScroll: true });
6192
- }
6193
-
6194
5799
  function setSidepanelOpen(open) {
6195
5800
  sidepanelOpen = open;
6196
5801
  sidepanel.classList.toggle("comty-sidepanel-open", sidepanelOpen);
@@ -6244,7 +5849,6 @@ function initComty(options = {}) {
6244
5849
  ? sidepanelSearch.value.trim().toLowerCase()
6245
5850
  : "";
6246
5851
  let list = cachedComments.filter((comment) => {
6247
- if (comment.local_agent || comment.kind === "agent") return false;
6248
5852
  if (
6249
5853
  search &&
6250
5854
  !`${comment.content ?? ""} ${getCommentLabel(comment)}`
@@ -6430,15 +6034,14 @@ function initComty(options = {}) {
6430
6034
  createStatusFilters();
6431
6035
 
6432
6036
  async function updateCommentStatus(comment, status) {
6433
- if (comment?.local_agent || !projectId || !comment?.id) return false;
6037
+ if (!projectId || !comment?.id) return false;
6434
6038
 
6435
6039
  let res;
6436
6040
  try {
6437
- const local = comment.local_agent === true;
6438
- res = await fetch(local ? `${agentBridgeUrl}/tasks/${encodeURIComponent(comment.id)}/status` : `${apiUrl}/api/comments/${comment.id}/status`, {
6041
+ res = await fetch(`${apiUrl}/api/comments/${comment.id}/status`, {
6439
6042
  method: "POST",
6440
- headers: local ? { "Content-Type": "application/json" } : getSdkHeaders({ "Content-Type": "application/json" }),
6441
- body: JSON.stringify(local ? { status } : {
6043
+ headers: getSdkHeaders({ "Content-Type": "application/json" }),
6044
+ body: JSON.stringify({
6442
6045
  projectKey,
6443
6046
  host: window.location.host,
6444
6047
  status,
@@ -6455,7 +6058,7 @@ function initComty(options = {}) {
6455
6058
  }
6456
6059
 
6457
6060
  const data = await res.json();
6458
- comment.status = getCommentStatus(data.task?.status ?? data.status).value;
6061
+ comment.status = getCommentStatus(data.status).value;
6459
6062
  return comment.status;
6460
6063
  }
6461
6064
 
@@ -6643,7 +6246,7 @@ function initComty(options = {}) {
6643
6246
  const openCommentThread = createCommentThread({
6644
6247
  root, apiUrl, projectKey, commentStatuses, selectedStatusFilters, placedPins,
6645
6248
  closeBubbles, getCommentStatus, updateCommentStatus, applyStatusDot,
6646
- renderSidepanelComments, applyStatusFilters, loadComments, createThreadItem,
6249
+ renderSidepanelComments, applyStatusFilters, createThreadItem,
6647
6250
  isOwnCommentEntry, updateCommentContent, deleteSdkComment, getCommentId,
6648
6251
  updateReplyContent, deleteSdkReply, createCommentAvatar, getSdkHeaders,
6649
6252
  showAuthPrompt,
@@ -6872,12 +6475,12 @@ function initComty(options = {}) {
6872
6475
  function reconcileComments(comments) {
6873
6476
  const previous = new Map(cachedComments.map(comment => [String(comment.id), comment]));
6874
6477
  cachedComments = comments
6875
- .filter(comment => comment.kind !== "agent" || comment.status !== "done")
6478
+ .filter(comment => comment.kind !== "agent" && !comment.local_agent)
6876
6479
  .map(comment => Object.assign(previous.get(String(comment.id)) || {}, comment));
6877
6480
  }
6878
6481
 
6879
6482
  async function loadComments({ force = false } = {}) {
6880
- if (!projectId && !agent) return;
6483
+ if (!projectId) return;
6881
6484
  const pagePath = window.location.pathname;
6882
6485
  if (!force && cachedPagePath === pagePath) { await renderComments(cachedComments); return; }
6883
6486
  if (pendingCommentsLoad) {
@@ -6885,7 +6488,7 @@ function initComty(options = {}) {
6885
6488
  if (!force) return;
6886
6489
  }
6887
6490
  pendingCommentsLoad = (async () => {
6888
- let comments = cachedPagePath === pagePath ? cachedComments.filter(comment => !comment.local_agent) : [];
6491
+ let comments = cachedPagePath === pagePath ? cachedComments : [];
6889
6492
  if (projectId) {
6890
6493
  try {
6891
6494
  const url = new URL(`${apiUrl}/api/comments`);
@@ -6896,37 +6499,15 @@ function initComty(options = {}) {
6896
6499
  if (Array.isArray(data.comments)) comments = data.comments;
6897
6500
  } catch (error) { console.error("Comty: list comments failed", error); }
6898
6501
  }
6899
- if (agent) {
6900
- try {
6901
- const res = await fetch(`${agentBridgeUrl}/tasks`, { headers: agentHeaders(), cache: "no-store" });
6902
- if (!res.ok) throw new Error("Local companion unavailable");
6903
- const data = await res.json();
6904
- if (Array.isArray(data.tasks)) localTasks = data.tasks;
6905
- if (Array.isArray(data.approvals)) localApprovals = data.approvals;
6906
- agentConnectionError = "";
6907
- } catch (error) {
6908
- agentConnectionError = "Local agent disconnected. Check the development server, then reload this page. Your task history is kept.";
6909
- console.error("Comty: local tasks failed", error);
6910
- }
6911
- comments.push(...localTasks.filter(task => task.page_path === pagePath && !["done", "cancel"].includes(task.status)));
6912
- renderAgentPanel();
6913
- }
6914
6502
  reconcileComments(comments);
6915
6503
  cachedPagePath = pagePath;
6916
6504
  renderSidepanelComments();
6917
6505
  await renderComments(cachedComments);
6918
- syncAgentWorkingOutlines();
6919
6506
  ensureLiveTracking();
6920
6507
  })();
6921
6508
  try { await pendingCommentsLoad; } finally { pendingCommentsLoad = null; }
6922
6509
  }
6923
6510
 
6924
- if (agent) {
6925
- setInterval(() => {
6926
- if (!pendingCommentsLoad && document.visibilityState === "visible") void loadComments({ force: true });
6927
- }, 2000);
6928
- }
6929
-
6930
6511
  function getPinPoint(pin) {
6931
6512
  return { x: parseFloat(pin.style.left), y: parseFloat(pin.style.top) };
6932
6513
  }
@@ -6993,50 +6574,16 @@ function initComty(options = {}) {
6993
6574
  }
6994
6575
  }
6995
6576
 
6996
- function syncAgentWorkingOutlines() {
6997
- const working = localTasks.filter(task => task.status === "in_progress" && task.page_path === window.location.pathname);
6998
- const ids = new Set(working.map(task => String(task.id)));
6999
- for (const [id, outline] of workingOutlines) {
7000
- if (ids.has(id)) continue;
7001
- outline.remove(); workingOutlines.delete(id);
7002
- }
7003
- const modal = getTopActiveModal();
7004
- for (const task of working) {
7005
- const id = String(task.id);
7006
- let outline = workingOutlines.get(id);
7007
- if (!outline) {
7008
- outline = document.createElement("div");
7009
- outline.className = "comty-agent-working";
7010
- outline.setAttribute("aria-label", "Agent working on this element");
7011
- const badge = document.createElement("span");
7012
- badge.className = "comty-agent-working-badge";
7013
- badge.append(createWorkingIndicator(), "Working");
7014
- outline.appendChild(badge); root.appendChild(outline);
7015
- workingOutlines.set(id, outline);
7016
- }
7017
- const target = resolveCommentElement(task);
7018
- const point = target && getVisibleAnchorPoint(target, Number(task.rel_x), Number(task.rel_y), modal);
7019
- outline.hidden = !point;
7020
- if (!point) continue;
7021
- const rect = target.getBoundingClientRect();
7022
- setMeasuredRect(outline, rect);
7023
- outline.toggleAttribute("data-badge-below", rect.top < 32);
7024
- }
7025
- }
7026
-
7027
6577
  function onFrame() {
7028
6578
  if (motion.enabled) updateMotion();
7029
6579
  if (session.comments) syncCommentAnchors();
7030
- if (session.agent || workingOutlines.size || localTasks.some(task => task.status === "in_progress" && task.page_path === window.location.pathname)) {
7031
- syncAgentWorkingOutlines();
7032
- }
7033
6580
  if (session.inspect || session.edit || inspectionLayer.childNodes.length) renderInspector();
7034
6581
  if (session.inspect && rulersEnabled) renderRulers();
7035
6582
  if (session.inspect && rulersEnabled) measurements.render();
7036
6583
  }
7037
6584
 
7038
6585
  function ensureLiveTracking() {
7039
- const active = motion.enabled || session.inspect || session.edit || (session.comments && cachedComments.length > 0) || workingOutlines.size > 0;
6586
+ const active = motion.enabled || session.inspect || session.edit || (session.comments && cachedComments.length > 0);
7040
6587
  if (!active || document.hidden) {
7041
6588
  if (liveFrame) cancelAnimationFrame(liveFrame);
7042
6589
  liveFrame = null;
@@ -7056,14 +6603,13 @@ function initComty(options = {}) {
7056
6603
  syncOverlayHost();
7057
6604
 
7058
6605
  function renderCachedComments() {
7059
- if (!session.comments && !session.inspect && !session.edit && !workingOutlines.size) return;
6606
+ if (!session.comments && !session.inspect && !session.edit) return;
7060
6607
  if (resizeRenderFrame) {
7061
6608
  window.cancelAnimationFrame(resizeRenderFrame);
7062
6609
  }
7063
6610
  resizeRenderFrame = window.requestAnimationFrame(() => {
7064
6611
  resizeRenderFrame = null;
7065
6612
  syncCommentAnchors();
7066
- syncAgentWorkingOutlines();
7067
6613
  renderInspector();
7068
6614
  ensureLiveTracking();
7069
6615
  });
@@ -7244,12 +6790,11 @@ function initComty(options = {}) {
7244
6790
  const y = e.clientY;
7245
6791
 
7246
6792
  const anchorContext = getAnchorContext(el);
7247
- if (session.agent && anchorContext) anchorContext.inspectedStyles = getInspectRows(el);
7248
6793
 
7249
6794
  const payload = {
7250
6795
  ...getDeviceContext(),
7251
6796
  projectId,
7252
- kind: session.agent ? "agent" : "comment",
6797
+ kind: "comment",
7253
6798
  host: window.location.host,
7254
6799
  pagePath: window.location.pathname,
7255
6800
  selector: getSelector(el),
@@ -7349,7 +6894,6 @@ function initComty(options = {}) {
7349
6894
  window.addEventListener("blur", () => { measureAlt = false; renderInspector(); });
7350
6895
 
7351
6896
  async function boot() {
7352
- if (localOnly) { await loadComments(); return; }
7353
6897
  const res = await fetch(`${apiUrl}/api/sdk/bootstrap`, {
7354
6898
  method: "POST",
7355
6899
  headers: getSdkHeaders({ "Content-Type": "application/json" }),
@@ -7362,7 +6906,6 @@ function initComty(options = {}) {
7362
6906
 
7363
6907
  if (!res.ok) {
7364
6908
  console.error("Comty: bootstrap failed", await res.text());
7365
- if (agent) await loadComments();
7366
6909
  return;
7367
6910
  }
7368
6911
 
@@ -7398,26 +6941,12 @@ function initComty(options = {}) {
7398
6941
  getDistanceSegments, getInspectRows, syncCommentAnchors,
7399
6942
  setInspectorMode(enabled) { setSession(enabled ? "inspect" : "off"); },
7400
6943
  startEditSession, startBrowseSession, endSession, showInspector,
7401
- motion, setMotionEnabled, updateMotion, describeAgentError,
7402
- previewAgent(tasks, approvals = [], error = "") {
7403
- localTasks = tasks;
7404
- localApprovals = approvals;
7405
- agentConnectionError = error;
7406
- startAgentSession();
7407
- agentPanelOpen = true;
7408
- agentPanelSignature = "";
7409
- renderAgentPanel();
7410
- },
6944
+ motion, setMotionEnabled, updateMotion,
7411
6945
  seed(comments) {
7412
6946
  reconcileComments(comments);
7413
6947
  setSession(session.comments ? session.mode : "browse", { entry: sessionEntry, renderComments: true });
7414
6948
  return renderComments(cachedComments, { retry: false });
7415
6949
  },
7416
- seedAgentTasks(tasks) {
7417
- localTasks = tasks;
7418
- syncAgentWorkingOutlines();
7419
- ensureLiveTracking();
7420
- },
7421
6950
  setCanWrite(value) { canWrite = value; },
7422
6951
  invalidate() { anchorRevision += 1; },
7423
6952
  });
@@ -7425,7 +6954,6 @@ function initComty(options = {}) {
7425
6954
 
7426
6955
  return boot().catch(error => {
7427
6956
  console.error("Comty: bootstrap failed", error);
7428
- if (agent) return loadComments();
7429
6957
  });
7430
6958
  }
7431
6959
  }