@taskforcehq/taskforce 0.3.320 → 0.3.321

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.
@@ -54,6 +54,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
54
54
  const isPricingRoute = location.pathname === '/pricing';
55
55
  const isPlansRoute = location.pathname === '/plans';
56
56
  const isPlansScreen = location.pathname === '/' && String(routeQuery.get('screen') || '').trim().toLowerCase() === 'plans';
57
+ const plansPath = buildPlansPath();
57
58
  const planSelectionPath = buildPlansPath({ gate: 'plan_selection_required' });
58
59
  const navigate = useNavigate();
59
60
  const [loginEmail, setLoginEmail] = useState('');
@@ -1284,7 +1285,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1284
1285
  || pendingVerificationCommercialState === 'checkout_pending';
1285
1286
  setCommercialOnboardingRedirectActive(commercialOnboardingGate);
1286
1287
  setPendingPostAuthRedirect({
1287
- path: pendingVerificationRedirectPath || nextPath,
1288
+ path: pendingVerificationRedirectPath || nextTarget,
1288
1289
  workspaceSetupRequired: pendingVerificationWorkspaceSetupRequired,
1289
1290
  commercialOnboardingGate
1290
1291
  });
@@ -1608,6 +1609,11 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1608
1609
  });
1609
1610
  const result = createResult || saveResult;
1610
1611
  if (!result?.success) {
1612
+ if (result?.code === 'WORKSPACE_LIMIT_REACHED') {
1613
+ setSetupBusy(false);
1614
+ navigate(plansPath, { replace: true });
1615
+ return;
1616
+ }
1611
1617
  setSetupError(result?.error || t('setup.saveWorkspaceFailed'));
1612
1618
  }
1613
1619
  else {
@@ -1620,8 +1626,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1620
1626
  setSetupBusy(false);
1621
1627
  return;
1622
1628
  }
1623
- const shouldApplyStarterPack = workspaceSetupSource === 'local'
1624
- && Boolean(selectedSetupPack)
1629
+ const shouldApplyStarterPack = Boolean(selectedSetupPack)
1625
1630
  && (setupTaxonomySections.categories || setupTaxonomySections.types || setupTaxonomySections.priorities);
1626
1631
  if (shouldApplyStarterPack && selectedSetupPack) {
1627
1632
  const applyResult = await settingsModel.onApplySystemTaxonomyPack({
@@ -622,10 +622,34 @@ export function useTaskforceWorkspaceBootstrap(args) {
622
622
  setWorkspaceBootstrapPending(true);
623
623
  try {
624
624
  await fetchBootstrapConfig({ ignoreAuthGuard });
625
- await Promise.all([
626
- fetchTasks(tasksSilent, { ignoreAuthGuard }),
627
- fetchReferenceData({ ignoreAuthGuard })
628
- ]);
625
+ const workspaceId = String(currentWorkspaceIdRef.current || 'default').trim() || 'default';
626
+ const deferredStartedAt = getBootstrapTimestamp();
627
+ void fetchTasks(tasksSilent, { ignoreAuthGuard }).then(() => {
628
+ logBootstrapDebug('cloud_bootstrap_tasks_loaded_deferred', {
629
+ reason,
630
+ workspaceId,
631
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - deferredStartedAt))
632
+ });
633
+ }).catch((error) => {
634
+ logBootstrapDebug('cloud_bootstrap_tasks_deferred_failed', {
635
+ reason,
636
+ workspaceId,
637
+ error: error instanceof Error ? error.message : String(error)
638
+ });
639
+ });
640
+ void fetchReferenceData({ ignoreAuthGuard }).then(() => {
641
+ logBootstrapDebug('cloud_bootstrap_reference_data_loaded_deferred', {
642
+ reason,
643
+ workspaceId,
644
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - deferredStartedAt))
645
+ });
646
+ }).catch((error) => {
647
+ logBootstrapDebug('cloud_bootstrap_reference_data_deferred_failed', {
648
+ reason,
649
+ workspaceId,
650
+ error: error instanceof Error ? error.message : String(error)
651
+ });
652
+ });
629
653
  void fetchPlanningEntities({ ignoreAuthGuard });
630
654
  if (includeDeferredArchive) {
631
655
  scheduleDeferredArchiveBootstrap();
@@ -636,7 +660,7 @@ export function useTaskforceWorkspaceBootstrap(args) {
636
660
  authenticated: true,
637
661
  workspaceSetupRequired: false,
638
662
  success: true,
639
- workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default'
663
+ workspaceId
640
664
  });
641
665
  return { success: true, authenticated: true, workspaceSetupRequired: false };
642
666
  }
@@ -740,6 +740,21 @@ export function createTaskforceMcpServer(options = {}) {
740
740
  }))
741
741
  .filter((actor) => Boolean(actor.id));
742
742
  }
743
+ function buildTaskWriteSummary(task) {
744
+ return {
745
+ id: task?.id || null,
746
+ referenceLabel: getTaskReferenceLabel(task) || null,
747
+ title: task?.title || null,
748
+ status: task?.status || null,
749
+ assignee: task?.assignee || null,
750
+ workstreamId: task?.workstreamId || null,
751
+ scheduledDate: task?.scheduledDate || null,
752
+ dueDate: task?.dueDate || null,
753
+ scheduledWeekKey: task?.scheduledWeekKey || null,
754
+ orderInDay: task?.orderInDay ?? null,
755
+ updatedAt: task?.updatedAt || null,
756
+ };
757
+ }
743
758
  function buildAiProfileDescriptor(profile) {
744
759
  return {
745
760
  id: profile.id,
@@ -2178,7 +2193,7 @@ export function createTaskforceMcpServer(options = {}) {
2178
2193
  const assigneeHint = describeEligibleAssignees();
2179
2194
  const mutatingProfileTokenProperty = {
2180
2195
  type: "string",
2181
- description: "Optional AI profile token returned by resolve_profile. Pass this when your MCP client does not preserve session identity between calls."
2196
+ description: "Optional AI profile token returned by resolve_profile. Pass this when your MCP client does not preserve session identity between calls. In stateless/cloud MCP clients without ambient AI binding, this is usually required on mutating calls after bootstrap."
2182
2197
  };
2183
2198
  const prefix = `[Project: ${PROJECT_NAME}] `;
2184
2199
  const agentNote = runtimeMode === 'local'
@@ -2190,11 +2205,32 @@ export function createTaskforceMcpServer(options = {}) {
2190
2205
  .filter(Boolean)
2191
2206
  .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
2192
2207
  .join(' ');
2208
+ const nonDestructiveWriteTools = new Set([
2209
+ 'add_annotated_attachment_marker',
2210
+ 'add_comment',
2211
+ 'add_document_review_comment',
2212
+ 'bulk_add_annotated_attachment_markers',
2213
+ 'create_annotated_attachment_session',
2214
+ 'create_document_review_session',
2215
+ 'create_initiative',
2216
+ 'create_task',
2217
+ 'create_workstream',
2218
+ 'link_task_context',
2219
+ 'resolve_profile',
2220
+ 'review_document',
2221
+ 'review_image',
2222
+ ]);
2193
2223
  const annotationsForTool = (name) => {
2194
2224
  const title = titleForTool(name);
2195
- return isMcpWriteToolName(name)
2196
- ? { title, destructiveHint: true }
2197
- : { title, readOnlyHint: true };
2225
+ if (!isMcpWriteToolName(name)) {
2226
+ return { title, readOnlyHint: true, destructiveHint: false, openWorldHint: false };
2227
+ }
2228
+ return {
2229
+ title,
2230
+ readOnlyHint: false,
2231
+ destructiveHint: !nonDestructiveWriteTools.has(name),
2232
+ openWorldHint: false,
2233
+ };
2198
2234
  };
2199
2235
  const tools = registeredTools
2200
2236
  .map((tool) => tool.buildDescriptor({
@@ -2915,7 +2951,13 @@ export function createTaskforceMcpServer(options = {}) {
2915
2951
  workstreamIds: [resolvedWorkstreamId],
2916
2952
  });
2917
2953
  return {
2918
- content: [{ type: "text", text: JSON.stringify(updated, null, 2) }],
2954
+ content: [{
2955
+ type: "text",
2956
+ text: JSON.stringify({
2957
+ task: buildTaskWriteSummary(updated),
2958
+ workstreamId: resolvedWorkstreamId,
2959
+ }, null, 2)
2960
+ }],
2919
2961
  };
2920
2962
  }
2921
2963
  case "clear_task_workstream": {
@@ -2935,7 +2977,14 @@ export function createTaskforceMcpServer(options = {}) {
2935
2977
  ...(priorWorkstreamId ? { includeWorkstreams: true, workstreamIds: [priorWorkstreamId] } : {}),
2936
2978
  });
2937
2979
  return {
2938
- content: [{ type: "text", text: JSON.stringify(updated, null, 2) }],
2980
+ content: [{
2981
+ type: "text",
2982
+ text: JSON.stringify({
2983
+ task: buildTaskWriteSummary(updated),
2984
+ workstreamId: null,
2985
+ previousWorkstreamId: priorWorkstreamId,
2986
+ }, null, 2)
2987
+ }],
2939
2988
  };
2940
2989
  }
2941
2990
  case "set_workstream_initiative": {
@@ -4001,7 +4050,7 @@ export function createTaskforceMcpServer(options = {}) {
4001
4050
  persistedOrderInDay: result.task.orderInDay ?? null
4002
4051
  },
4003
4052
  warnings: result.warnings,
4004
- task: result.task
4053
+ task: buildTaskWriteSummary(result.task)
4005
4054
  }, null, 2)
4006
4055
  }],
4007
4056
  };
@@ -4154,6 +4203,7 @@ export function createTaskforceMcpServer(options = {}) {
4154
4203
  priority: resolveNumberOption('priority', createArgs.priority, getActivePriorities().map(p => ({ value: p.value, label: p.label }))),
4155
4204
  approach: resolveStringOption('approach', createArgs.approach, getActiveApproaches().map(a => ({ value: a.value, label: a.label }))),
4156
4205
  assignee: resolveRuntimeTaskAssigneeInput(createAssigneeInput),
4206
+ workstreamId: createArgs.workstreamId ? resolveWorkstreamByIdentifierOrThrow(createArgs.workstreamId).id : undefined,
4157
4207
  status: resolveStringOption('status', createArgs.status, STATUS_OPTIONS),
4158
4208
  complexity: resolveNumberOption('complexity', createArgs.complexity, COMPLEXITY_OPTIONS)
4159
4209
  };
@@ -4219,7 +4269,7 @@ export function createTaskforceMcpServer(options = {}) {
4219
4269
  content: [{
4220
4270
  type: "text",
4221
4271
  text: JSON.stringify({
4222
- task: updated,
4272
+ task: buildTaskWriteSummary(updated),
4223
4273
  started: true,
4224
4274
  claimed: resolved.claimed && updated.assignee === activeAiProfileId,
4225
4275
  statusChanged: resolved.previousStatus !== String(updated.status || '').trim(),
@@ -4294,7 +4344,13 @@ export function createTaskforceMcpServer(options = {}) {
4294
4344
  includeStats: true,
4295
4345
  });
4296
4346
  return {
4297
- content: [{ type: "text", text: JSON.stringify(updated, null, 2) }],
4347
+ content: [{
4348
+ type: "text",
4349
+ text: JSON.stringify({
4350
+ task: buildTaskWriteSummary(updated),
4351
+ changedFields: Object.keys(finalUpdates),
4352
+ }, null, 2)
4353
+ }],
4298
4354
  };
4299
4355
  }
4300
4356
  catch (error) {
@@ -4385,7 +4441,13 @@ export function createTaskforceMcpServer(options = {}) {
4385
4441
  includeStats: true,
4386
4442
  });
4387
4443
  return {
4388
- content: [{ type: "text", text: JSON.stringify(updated, null, 2) }],
4444
+ content: [{
4445
+ type: "text",
4446
+ text: JSON.stringify({
4447
+ task: buildTaskWriteSummary(updated),
4448
+ assignee: resolvedAssignee,
4449
+ }, null, 2)
4450
+ }],
4389
4451
  };
4390
4452
  }
4391
4453
  case "bulk_assign_tasks": {
@@ -353,6 +353,7 @@ export function registerTaskPlanningTools(registerTool, executeTool) {
353
353
  title: stringProperty('Task title.'),
354
354
  description: stringProperty('Optional task description.'),
355
355
  assignee: stringProperty(`${context.assigneeHint} Call list_assignees to inspect the current eligible IDs.`),
356
+ workstreamId: stringProperty('Optional workstream ID or workstream reference such as WS-123. Use this to create the task directly inside a workstream without a separate set_task_workstream call.'),
356
357
  category: stringProperty('Task category value.'),
357
358
  type: stringProperty('Task type value.', context.typeEnum),
358
359
  priority: numberProperty(context.priorityDesc),
@@ -1 +1 @@
1
- import{r as c,j as e}from"./vendor-react-CKJs5o3c.js";import{s as Ue,p as _,u as ie,v as De,w as se,x as le,y as we,t as r,E as Te,z as Me,B as ke,C as fe,F as b,G as oe}from"./index-rB9GGUCz.js";import{a0 as Re,x as $e,h as Ee,B as ne,m as C,b as Le,$ as Be,a5 as Ge}from"./vendor-icons-CLnehDTw.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function Fe(l){return typeof l.avatarUrl=="string"&&l.avatarUrl.trim().length>0}function K(l){return l?fe(l.avatarUrl,l.avatarRevision,l.avatarUpdatedAt):""}function ze(l){return l?fe(l.avatarSourceUrl,l.avatarRevision,l.avatarUpdatedAt):""}function He(l){return l.find(Fe)||l[0]}function ce(l){return`${l.seatScope||"unknown"}:${l.name.trim().toLowerCase()}`}function Oe(l){const m=Math.max(0,l-1);return`${m} duplicate${m===1?"":"s"}`}function de(l){return!l||typeof l!="object"?null:{used:Math.max(0,Number(l.used||0)),limit:l.limit===null||l.limit===void 0?null:Math.max(0,Number(l.limit||0)),remaining:l.remaining===null||l.remaining===void 0?null:Math.max(0,Number(l.remaining||0))}}function pe(l,m){const U=m?.variant==="inline"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconInline}`:m?.variant==="detail"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconDetail}`:r.aiProfileSeatScopeIcon;return l==="cloud_metered"?e.jsx("span",{className:`${U} ${r.aiProfileSeatScopeIconCloud}`,title:"Cloud MCP","aria-label":"Cloud MCP",children:e.jsx(Be,{size:20})}):l==="local_unmetered"?e.jsx("span",{className:`${U} ${r.aiProfileSeatScopeIconLocal}`,title:"Local MCP","aria-label":"Local MCP",children:e.jsx(Ge,{size:20})}):null}function qe({workspaceId:l,cloudAuthConfigured:m=!1,authSessionResolved:U=!1,isAuthenticated:ue=!1,cloudAiProfileSeatUsage:me=null,agentTrayOpen:E=!1,onCloseAgentTray:he,mcpSettingsNode:V=null}){const[S,L]=c.useState([]),[ve,ge]=c.useState(null),[B,J]=c.useState(!1),[h,D]=c.useState(null),[w,v]=c.useState(null),[T,x]=c.useState(null),[W,G]=c.useState(null),[ye,Y]=c.useState(!1),[P,j]=c.useState(null),[q,Q]=c.useState(null),[X,M]=c.useState(!1),[Pe,g]=c.useState(null),k=c.useCallback(async()=>{if(l){J(!0);try{const a=`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(l)}&kind=agent`,t=await fetch(a,{credentials:"include"}),i=t.ok?await t.json().catch(()=>({})):{},o=de(i?.aiProfileSeatUsage),d=Array.isArray(i?.assignees)?i.assignees.filter(s=>s.kind==="agent").map(s=>({id:String(s.value||""),name:String(s.label||s.value||"Unknown Agent"),username:String(s.username||s.value||""),icon:String(s.icon||"Bot"),color:String(s.color||"#6B7280"),avatarUrl:typeof s.avatarUrl=="string"?s.avatarUrl:null,avatarSourceUrl:typeof s.avatarSourceUrl=="string"?s.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(s.avatarRevision))?Math.max(0,Math.floor(Number(s.avatarRevision))):0,avatarUpdatedAt:typeof s.avatarUpdatedAt=="string"?s.avatarUpdatedAt:null,kind:String(s.kind||"agent"),description:typeof s.description=="string"?s.description:null,role:typeof s.role=="string"?s.role:null,provider:typeof s.provider=="string"?s.provider:null,model:typeof s.model=="string"?s.model:null,surfaceType:_(s.surfaceType),seatScope:Ue(s.seatScope),archivedAt:typeof s.archivedAt=="string"?s.archivedAt:null,createdAt:String(s.createdAt||""),updatedAt:String(s.updatedAt||s.createdAt||""),lastActiveAt:typeof s.lastActiveAt=="string"?s.lastActiveAt:null})):[];L(d),ge(o),x(s=>s&&!d.some(p=>p.id===s.profileId)?null:s),G(s=>s&&!d.some(p=>p.id===s.profileId)?null:s)}finally{J(!1)}}},[l]);c.useEffect(()=>{k()},[k]);const R=c.useMemo(()=>{const a=new Map;for(const t of S){const i=ie(t.surfaceType);a.has(i)||a.set(i,new Map);const o=a.get(i),d=ce(t);o.has(d)||o.set(d,[]),o.get(d).push(t)}return De.map(t=>({section:t,label:se(t),groups:Array.from(a.get(t)?.entries()||[]).map(([i,o])=>({groupId:`${t}:${i}`,section:t,sectionLabel:se(t),profiles:o,primaryProfile:He(o)}))})).filter(t=>t.groups.length>0)},[S]),y=c.useMemo(()=>R.flatMap(a=>a.groups),[R]),n=c.useMemo(()=>y.find(a=>a.groupId===P)||y[0]||null,[y,P]),u=c.useMemo(()=>S.find(a=>a.id===q)||null,[S,q]);c.useEffect(()=>{if(!y.length){P!==null&&j(null);return}(!P||!y.some(a=>a.groupId===P))&&j(y[0].groupId)},[y,P]);const Ae=async(a,t)=>{v(null),x(null);try{const i=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:a,mergeId:t})}),o=await i.json().catch(()=>({}));if(!i.ok){v({type:"error",message:String(o?.error||"Failed to merge AI profiles.")});return}D(null),v({type:"success",message:"AI profiles merged."}),await k(),b({workspaceId:l,profileId:a,reason:"merge"})}catch{v({type:"error",message:"Failed to merge AI profiles."})}},Z=async a=>{if(window.confirm(`Remove ${a.name} from the active roster? This frees an AI profile seat and preserves task and comment history.`)){x(null),v(null);try{const i=await fetch("/api/taskforce/workspace/ai-profiles/archive",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a.id,reason:"manual_archive"})}),o=await i.json().catch(()=>({}));if(!i.ok){x({profileId:a.id,message:String(o?.error||"Failed to remove AI profile from roster.")});return}(h?.keepId===a.id||h?.mergeId===a.id)&&D(null),v({type:"success",message:"AI profile removed from active roster."}),await k(),b({workspaceId:l,profileId:a.id,reason:"archive"})}catch{x({profileId:a.id,message:"Failed to remove AI profile from roster."})}}},Se=async(a,t)=>{const i=_(t),o=new Set(a.profiles.map(p=>p.surfaceType??"")),d=i??"";if(o.size===1&&o.has(d))return;Y(!0),G(null),v(null);const s=[];try{for(const f of a.profiles){const I=await fetch("/api/taskforce/workspace/ai-profiles/surface-type",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:f.id,surfaceType:i})}),H=await I.json().catch(()=>({}));if(!I.ok||!H?.profile)throw new Error(String(H?.error||"Failed to update AI profile category."));const O=H.profile;s.push({...f,surfaceType:_(O.surfaceType),updatedAt:typeof O.updatedAt=="string"?O.updatedAt:f.updatedAt})}const p=new Map(s.map(f=>[f.id,f]));L(f=>f.map(I=>p.get(I.id)||I));const A=p.get(a.primaryProfile.id)||{...a.primaryProfile,surfaceType:i},Ce=ie(A.surfaceType);j(`${Ce}:${ce(A)}`),v({type:"success",message:"AI profile category updated."});for(const f of s)b({workspaceId:l,profileId:f.id,reason:"update"})}catch(p){G({profileId:a.primaryProfile.id,message:String(p?.message||"Failed to update AI profile category.")})}finally{Y(!1)}},ee=a=>new Promise((t,i)=>{const o=new FileReader;o.onload=()=>t(String(o.result||"")),o.onerror=()=>i(new Error("Failed to read image file.")),o.readAsDataURL(a)}),ae=a=>{const t=String(a?.id||"").trim();t&&L(i=>i.map(o=>o.id===t?{...o,avatarUrl:typeof a.avatarUrl=="string"?a.avatarUrl:null,avatarSourceUrl:typeof a.avatarSourceUrl=="string"?a.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(a.avatarRevision))?Math.max(0,Math.floor(Number(a.avatarRevision))):o.avatarRevision,avatarUpdatedAt:typeof a.avatarUpdatedAt=="string"?a.avatarUpdatedAt:o.avatarUpdatedAt,updatedAt:typeof a.updatedAt=="string"?a.updatedAt:o.updatedAt}:o))},xe=async(a,t,i)=>{const o=await ee(t),d=i?await ee(i):null,s={profileId:a,displayImage:{dataUrl:o,mimeType:t.type||"application/octet-stream",originalName:t.name||"display-avatar"}};i&&d&&(s.sourceImage={dataUrl:d,mimeType:i.type||"application/octet-stream",originalName:i.name||"source-avatar"});const p=await fetch("/api/taskforce/workspace/ai-profiles/avatar/upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),A=await p.json().catch(()=>({}));if(!p.ok||!A?.profile)throw new Error(String(A?.error||"Failed to update AI profile avatar."));ae(A.profile),b({workspaceId:l,profileId:a,reason:"avatar"})},je=async a=>{const t=await fetch("/api/taskforce/workspace/ai-profiles/avatar",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a,avatarUrl:null,avatarSourceUrl:null})}),i=await t.json().catch(()=>({}));if(!t.ok||!i?.profile)throw new Error(String(i?.error||"Failed to update AI profile avatar."));ae(i.profile),b({workspaceId:l,profileId:a,reason:"avatar"})},Ne=async(a,t)=>{if(!u)return!1;if(!a.type.startsWith("image/"))return g("AI profile photo must be an image file."),!1;M(!0),g(null);try{const i=await oe(a,{maxBytes:5242880});if(i.exceededLimit)throw new Error(a.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile photo must be 5 MB or smaller.");const o=i.file;let d=null;if(t){const s=await oe(t,{maxBytes:5242880});if(s.exceededLimit)throw new Error(t.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile source photo must be 5 MB or smaller.");d=s.file}return await xe(u.id,o,d),!0}catch(i){return g(String(i?.message||"Failed to update AI profile photo.")),!1}finally{M(!1)}},Ie=async()=>{if(u){M(!0),g(null);try{await je(u.id)}catch(a){g(String(a?.message||"Failed to remove AI profile photo."))}finally{M(!1)}}},N=a=>{const t=String(a||"").trim();if(!t)return"Unknown";const i=Date.parse(t);return Number.isFinite(i)?new Date(i).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):t},re=c.useMemo(()=>{if(!n)return{attributes:[],dates:[]};const a=n.primaryProfile,t=i=>i||"Not set";return{attributes:[{label:"Category",value:a.surfaceType?le(a.surfaceType):""},{label:"Connection",value:a.seatScope?we(a.seatScope):""},{label:"Provider",value:a.provider||""},{label:"Model",value:a.model||""}].map(i=>({...i,value:t(i.value)})),dates:[{label:"Status",value:a.archivedAt?"Retired":"Active"},{label:"Recruited",value:N(a.createdAt)},{label:"Last updated",value:N(a.updatedAt)},{label:"Last active",value:N(a.lastActiveAt)}].map(i=>({...i,value:t(i.value)}))}},[n]),be=!!n&&n.profiles.length>1,te=m&&U&&!ue,$=m?de(me):ve,F=te?"Log into account for Cloud agents":$?`${$.used}/${$.limit===null?"Unlimited":$.limit}`:null,z=!!V;return e.jsxs("section",{className:`${r.agentsModuleRoot} ${z?r.agentsModuleWithTray:""} ${z&&E?r.agentsModuleTrayOpen:""}`.trim(),children:[z&&e.jsxs("aside",{className:`${r.agentTrayPanel} ${E?r.agentTrayPanelOpen:""}`.trim(),"aria-label":"Agent MCP settings tray","aria-hidden":!E,children:[e.jsxs("div",{className:r.agentTrayHeader,children:[e.jsxs("span",{className:r.agentTrayTitle,children:[e.jsx(Re,{size:14}),"MCP Settings"]}),e.jsx("button",{type:"button",className:"tf-control-icon",onClick:he,title:"Collapse agent tray","aria-label":"Collapse agent tray",children:e.jsx($e,{size:16})})]}),e.jsx("div",{className:`${r.agentTrayContent} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.agentTrayContentInner,children:V})})]}),e.jsx("div",{className:r.agentsModuleContent,children:e.jsx("div",{className:`${r.settingGroup} ${r.agentsModuleGroup}`,children:e.jsxs("div",{children:[e.jsx("h4",{className:r.settingSubTitle,children:"Registered AI Profiles"}),e.jsx("p",{className:`${r.settingsHint} ${r.marginBottom12}`,children:"AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost, or remove inactive profiles from the active roster to free seats while preserving history."}),F&&e.jsx("div",{className:r.aiProfileSeatSummary,children:te?F:`Registered Cloud Agents: ${F}`}),B&&e.jsxs("div",{className:r.settingsHint,children:[e.jsx(Ee,{size:13,className:r.spinner})," Loading profiles…"]}),!B&&S.length===0&&e.jsx("div",{className:r.settingsHint,children:"No AI profiles registered yet."}),!B&&R.length>0&&e.jsxs("div",{className:r.aiProfilesExplorer,children:[e.jsx("div",{className:`${r.aiProfilesListPane} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.aiProfilesList,children:R.map(a=>e.jsxs("div",{className:r.aiProfilesSection,children:[e.jsx("div",{className:r.aiProfilesSectionHeader,children:a.label}),a.groups.map(t=>{const i=n?.groupId===t.groupId,o=t.primaryProfile;return e.jsxs("div",{role:"button",tabIndex:0,className:`${r.aiProfileGroup} ${t.profiles.length>1?r.aiProfileGroupDuplicate:""} ${i?r.aiProfileGroupSelected:""}`,onClick:()=>j(t.groupId),onKeyDown:d=>{d.key!=="Enter"&&d.key!==" "||(d.preventDefault(),j(t.groupId))},"aria-pressed":i,children:[pe(o.seatScope),e.jsxs("div",{className:r.aiProfileGroupHeader,children:[e.jsx("span",{className:r.aiProfileGroupAvatar,style:{color:o.color},children:o.avatarUrl?e.jsx("img",{src:K(o),alt:""}):e.jsx(ne,{size:22})}),e.jsxs("span",{className:r.aiProfileGroupIdentity,children:[e.jsx("span",{className:r.aiProfileName,children:o.name}),e.jsxs("span",{className:r.aiProfileHandle,children:["@",o.username]}),e.jsx("span",{className:r.aiProfileRole,children:o.role||"Role not set"}),t.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDuplicateBadge,children:[e.jsx(C,{size:11})," ",Oe(t.profiles.length)]})]})]})]},t.groupId)})]},a.section))})}),n&&e.jsx("div",{className:r.aiProfileDetailPane,children:e.jsxs("div",{className:r.aiProfileDetailCard,children:[pe(n.primaryProfile.seatScope,{variant:"detail"}),e.jsxs("div",{className:r.aiProfileDetailHero,children:[e.jsx(Te,{label:"Edit AI profile photo",imageUrl:K(n.primaryProfile),fallback:e.jsx(ne,{size:38}),accentColor:n.primaryProfile.color,size:176,width:153,height:207,radius:6,editBadgeSize:28,editIconSize:14,className:r.aiProfileDetailAvatar,onClick:()=>{g(null),Q(n.primaryProfile.id)}}),e.jsxs("div",{className:r.aiProfileDetailHeading,children:[e.jsx("div",{className:r.aiProfileDetailTitleRow,children:e.jsx("h5",{className:r.aiProfileDetailTitle,children:n.primaryProfile.name})}),e.jsxs("div",{className:r.aiProfileDetailMetaRow,children:[e.jsxs("span",{className:r.aiProfileDetailHandle,children:["@",n.primaryProfile.username]}),n.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDetailLinkedCount,children:[n.profiles.length," linked"]})]}),e.jsxs("div",{className:r.aiProfileDetailRole,children:["Role: ",n.primaryProfile.role||"Not set"]}),n.primaryProfile.description&&e.jsx("div",{className:r.aiProfileDetailDescription,children:n.primaryProfile.description}),e.jsxs("div",{className:r.aiProfileSignatureColor,children:[e.jsx("span",{children:"Signature color"}),e.jsx("span",{className:r.aiProfileSignatureSwatch,style:{backgroundColor:n.primaryProfile.color},"aria-hidden":"true"}),e.jsx("span",{children:n.primaryProfile.color})]})]})]}),e.jsxs("div",{className:r.aiProfileDetailDataList,children:[e.jsx("div",{className:r.aiProfileDetailDataGroup,children:re.attributes.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Category"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent category",value:n.primaryProfile.surfaceType??"",disabled:ye,onChange:t=>{Se(n,t.target.value)},children:[e.jsx("option",{value:"",children:"Unclassified"}),Me.map(t=>e.jsx("option",{value:t,children:le(t)},t))]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))}),e.jsx("div",{className:`${r.aiProfileDetailDataGroup} ${r.aiProfileDetailDateGroup}`,children:re.dates.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Status"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent roster status",value:n.primaryProfile.archivedAt?"retired":"active",onChange:t=>{t.target.value==="retire"&&Z(n.primaryProfile)},children:[e.jsx("option",{value:"active",children:"Active"}),n.primaryProfile.archivedAt?e.jsx("option",{value:"retired",children:"Retired"}):e.jsx("option",{value:"retire",children:"Retire from roster"})]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))})]}),W?.profileId===n.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:W.message})]}),be?e.jsxs("div",{className:r.aiProfileInstanceSection,children:[e.jsxs("div",{className:r.aiProfileInstanceSectionHeader,children:[e.jsx("span",{children:"Profile instances"}),e.jsx("span",{className:r.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),e.jsx("div",{className:r.aiProfileInstanceList,children:n.profiles.map(a=>e.jsxs("div",{className:r.aiProfileInstanceCard,children:[e.jsxs("div",{className:r.aiProfileInstanceTopRow,children:[e.jsxs("div",{children:[e.jsxs("div",{className:r.aiProfileInstanceName,children:["@",a.username]}),e.jsx("div",{className:r.aiProfileIdChip,children:a.id})]}),h?.keepId===a.id&&e.jsx("span",{className:r.aiProfileKeepBadge,children:"Keeping"})]}),e.jsxs("div",{className:r.aiProfileInstanceMeta,children:[e.jsxs("span",{children:["Created ",N(a.createdAt)]}),e.jsxs("span",{children:["Updated ",N(a.updatedAt)]})]}),h?.keepId!==a.id&&e.jsx("button",{className:r.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const t=n.profiles.find(i=>i.id!==a.id)?.id;t&&D({keepId:a.id,mergeId:t})},children:"Keep this"}),T?.profileId===a.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:T.message})]}),e.jsx("button",{className:r.aiProfileDangerTextButton,title:"Remove this profile from the active roster",onClick:()=>{Z(a)},children:"Remove from roster"})]},a.id))}),h&&n.profiles.some(a=>a.id===h.keepId)&&e.jsxs("div",{className:r.aiProfileMergeActions,children:[e.jsx("button",{className:r.dangerBtn,onClick:()=>{Ae(h.keepId,h.mergeId)},children:"Merge duplicates"}),e.jsx("button",{className:r.secondaryHeaderBtn,onClick:()=>D(null),children:"Cancel"})]})]}):e.jsxs("div",{className:r.aiProfileIdFooter,children:[e.jsx("div",{className:r.aiProfileIdFooterValue,children:n.primaryProfile.id}),T?.profileId===n.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:T.message})]})]})]})})]}),w&&e.jsxs("div",{className:`${w.type==="success"?r.successMessage:r.errorMessage} ${r.marginTop12}`,children:[w.type==="success"?e.jsx(Le,{size:14}):e.jsx(C,{size:14}),w.message]})]})})}),e.jsx(ke,{isOpen:!!u,theme:"dark",title:"Edit AI Profile Photo",currentImageUrl:K(u),editorImageUrl:ze(u),fallbackInitial:(u?.name||"AI").charAt(0).toUpperCase(),accept:"image/png,image/jpeg,image/webp,image/gif",busy:X,hasPendingImage:!1,canRemove:!!u?.avatarUrl,error:Pe,notice:null,onClose:()=>{X||(Q(null),g(null))},onApplyImage:Ne,onRemoveImage:Ie})]})}export{qe as AgentsModule};
1
+ import{r as c,j as e}from"./vendor-react-CKJs5o3c.js";import{s as Ue,p as _,u as ie,v as De,w as se,x as le,y as we,t as r,E as Te,z as Me,B as ke,C as fe,F as b,G as oe}from"./index-CGDQY0nN.js";import{a0 as Re,x as $e,h as Ee,B as ne,m as C,b as Le,$ as Be,a5 as Ge}from"./vendor-icons-CLnehDTw.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function Fe(l){return typeof l.avatarUrl=="string"&&l.avatarUrl.trim().length>0}function K(l){return l?fe(l.avatarUrl,l.avatarRevision,l.avatarUpdatedAt):""}function ze(l){return l?fe(l.avatarSourceUrl,l.avatarRevision,l.avatarUpdatedAt):""}function He(l){return l.find(Fe)||l[0]}function ce(l){return`${l.seatScope||"unknown"}:${l.name.trim().toLowerCase()}`}function Oe(l){const m=Math.max(0,l-1);return`${m} duplicate${m===1?"":"s"}`}function de(l){return!l||typeof l!="object"?null:{used:Math.max(0,Number(l.used||0)),limit:l.limit===null||l.limit===void 0?null:Math.max(0,Number(l.limit||0)),remaining:l.remaining===null||l.remaining===void 0?null:Math.max(0,Number(l.remaining||0))}}function pe(l,m){const U=m?.variant==="inline"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconInline}`:m?.variant==="detail"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconDetail}`:r.aiProfileSeatScopeIcon;return l==="cloud_metered"?e.jsx("span",{className:`${U} ${r.aiProfileSeatScopeIconCloud}`,title:"Cloud MCP","aria-label":"Cloud MCP",children:e.jsx(Be,{size:20})}):l==="local_unmetered"?e.jsx("span",{className:`${U} ${r.aiProfileSeatScopeIconLocal}`,title:"Local MCP","aria-label":"Local MCP",children:e.jsx(Ge,{size:20})}):null}function qe({workspaceId:l,cloudAuthConfigured:m=!1,authSessionResolved:U=!1,isAuthenticated:ue=!1,cloudAiProfileSeatUsage:me=null,agentTrayOpen:E=!1,onCloseAgentTray:he,mcpSettingsNode:V=null}){const[S,L]=c.useState([]),[ve,ge]=c.useState(null),[B,J]=c.useState(!1),[h,D]=c.useState(null),[w,v]=c.useState(null),[T,x]=c.useState(null),[W,G]=c.useState(null),[ye,Y]=c.useState(!1),[P,j]=c.useState(null),[q,Q]=c.useState(null),[X,M]=c.useState(!1),[Pe,g]=c.useState(null),k=c.useCallback(async()=>{if(l){J(!0);try{const a=`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(l)}&kind=agent`,t=await fetch(a,{credentials:"include"}),i=t.ok?await t.json().catch(()=>({})):{},o=de(i?.aiProfileSeatUsage),d=Array.isArray(i?.assignees)?i.assignees.filter(s=>s.kind==="agent").map(s=>({id:String(s.value||""),name:String(s.label||s.value||"Unknown Agent"),username:String(s.username||s.value||""),icon:String(s.icon||"Bot"),color:String(s.color||"#6B7280"),avatarUrl:typeof s.avatarUrl=="string"?s.avatarUrl:null,avatarSourceUrl:typeof s.avatarSourceUrl=="string"?s.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(s.avatarRevision))?Math.max(0,Math.floor(Number(s.avatarRevision))):0,avatarUpdatedAt:typeof s.avatarUpdatedAt=="string"?s.avatarUpdatedAt:null,kind:String(s.kind||"agent"),description:typeof s.description=="string"?s.description:null,role:typeof s.role=="string"?s.role:null,provider:typeof s.provider=="string"?s.provider:null,model:typeof s.model=="string"?s.model:null,surfaceType:_(s.surfaceType),seatScope:Ue(s.seatScope),archivedAt:typeof s.archivedAt=="string"?s.archivedAt:null,createdAt:String(s.createdAt||""),updatedAt:String(s.updatedAt||s.createdAt||""),lastActiveAt:typeof s.lastActiveAt=="string"?s.lastActiveAt:null})):[];L(d),ge(o),x(s=>s&&!d.some(p=>p.id===s.profileId)?null:s),G(s=>s&&!d.some(p=>p.id===s.profileId)?null:s)}finally{J(!1)}}},[l]);c.useEffect(()=>{k()},[k]);const R=c.useMemo(()=>{const a=new Map;for(const t of S){const i=ie(t.surfaceType);a.has(i)||a.set(i,new Map);const o=a.get(i),d=ce(t);o.has(d)||o.set(d,[]),o.get(d).push(t)}return De.map(t=>({section:t,label:se(t),groups:Array.from(a.get(t)?.entries()||[]).map(([i,o])=>({groupId:`${t}:${i}`,section:t,sectionLabel:se(t),profiles:o,primaryProfile:He(o)}))})).filter(t=>t.groups.length>0)},[S]),y=c.useMemo(()=>R.flatMap(a=>a.groups),[R]),n=c.useMemo(()=>y.find(a=>a.groupId===P)||y[0]||null,[y,P]),u=c.useMemo(()=>S.find(a=>a.id===q)||null,[S,q]);c.useEffect(()=>{if(!y.length){P!==null&&j(null);return}(!P||!y.some(a=>a.groupId===P))&&j(y[0].groupId)},[y,P]);const Ae=async(a,t)=>{v(null),x(null);try{const i=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:a,mergeId:t})}),o=await i.json().catch(()=>({}));if(!i.ok){v({type:"error",message:String(o?.error||"Failed to merge AI profiles.")});return}D(null),v({type:"success",message:"AI profiles merged."}),await k(),b({workspaceId:l,profileId:a,reason:"merge"})}catch{v({type:"error",message:"Failed to merge AI profiles."})}},Z=async a=>{if(window.confirm(`Remove ${a.name} from the active roster? This frees an AI profile seat and preserves task and comment history.`)){x(null),v(null);try{const i=await fetch("/api/taskforce/workspace/ai-profiles/archive",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a.id,reason:"manual_archive"})}),o=await i.json().catch(()=>({}));if(!i.ok){x({profileId:a.id,message:String(o?.error||"Failed to remove AI profile from roster.")});return}(h?.keepId===a.id||h?.mergeId===a.id)&&D(null),v({type:"success",message:"AI profile removed from active roster."}),await k(),b({workspaceId:l,profileId:a.id,reason:"archive"})}catch{x({profileId:a.id,message:"Failed to remove AI profile from roster."})}}},Se=async(a,t)=>{const i=_(t),o=new Set(a.profiles.map(p=>p.surfaceType??"")),d=i??"";if(o.size===1&&o.has(d))return;Y(!0),G(null),v(null);const s=[];try{for(const f of a.profiles){const I=await fetch("/api/taskforce/workspace/ai-profiles/surface-type",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:f.id,surfaceType:i})}),H=await I.json().catch(()=>({}));if(!I.ok||!H?.profile)throw new Error(String(H?.error||"Failed to update AI profile category."));const O=H.profile;s.push({...f,surfaceType:_(O.surfaceType),updatedAt:typeof O.updatedAt=="string"?O.updatedAt:f.updatedAt})}const p=new Map(s.map(f=>[f.id,f]));L(f=>f.map(I=>p.get(I.id)||I));const A=p.get(a.primaryProfile.id)||{...a.primaryProfile,surfaceType:i},Ce=ie(A.surfaceType);j(`${Ce}:${ce(A)}`),v({type:"success",message:"AI profile category updated."});for(const f of s)b({workspaceId:l,profileId:f.id,reason:"update"})}catch(p){G({profileId:a.primaryProfile.id,message:String(p?.message||"Failed to update AI profile category.")})}finally{Y(!1)}},ee=a=>new Promise((t,i)=>{const o=new FileReader;o.onload=()=>t(String(o.result||"")),o.onerror=()=>i(new Error("Failed to read image file.")),o.readAsDataURL(a)}),ae=a=>{const t=String(a?.id||"").trim();t&&L(i=>i.map(o=>o.id===t?{...o,avatarUrl:typeof a.avatarUrl=="string"?a.avatarUrl:null,avatarSourceUrl:typeof a.avatarSourceUrl=="string"?a.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(a.avatarRevision))?Math.max(0,Math.floor(Number(a.avatarRevision))):o.avatarRevision,avatarUpdatedAt:typeof a.avatarUpdatedAt=="string"?a.avatarUpdatedAt:o.avatarUpdatedAt,updatedAt:typeof a.updatedAt=="string"?a.updatedAt:o.updatedAt}:o))},xe=async(a,t,i)=>{const o=await ee(t),d=i?await ee(i):null,s={profileId:a,displayImage:{dataUrl:o,mimeType:t.type||"application/octet-stream",originalName:t.name||"display-avatar"}};i&&d&&(s.sourceImage={dataUrl:d,mimeType:i.type||"application/octet-stream",originalName:i.name||"source-avatar"});const p=await fetch("/api/taskforce/workspace/ai-profiles/avatar/upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),A=await p.json().catch(()=>({}));if(!p.ok||!A?.profile)throw new Error(String(A?.error||"Failed to update AI profile avatar."));ae(A.profile),b({workspaceId:l,profileId:a,reason:"avatar"})},je=async a=>{const t=await fetch("/api/taskforce/workspace/ai-profiles/avatar",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a,avatarUrl:null,avatarSourceUrl:null})}),i=await t.json().catch(()=>({}));if(!t.ok||!i?.profile)throw new Error(String(i?.error||"Failed to update AI profile avatar."));ae(i.profile),b({workspaceId:l,profileId:a,reason:"avatar"})},Ne=async(a,t)=>{if(!u)return!1;if(!a.type.startsWith("image/"))return g("AI profile photo must be an image file."),!1;M(!0),g(null);try{const i=await oe(a,{maxBytes:5242880});if(i.exceededLimit)throw new Error(a.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile photo must be 5 MB or smaller.");const o=i.file;let d=null;if(t){const s=await oe(t,{maxBytes:5242880});if(s.exceededLimit)throw new Error(t.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile source photo must be 5 MB or smaller.");d=s.file}return await xe(u.id,o,d),!0}catch(i){return g(String(i?.message||"Failed to update AI profile photo.")),!1}finally{M(!1)}},Ie=async()=>{if(u){M(!0),g(null);try{await je(u.id)}catch(a){g(String(a?.message||"Failed to remove AI profile photo."))}finally{M(!1)}}},N=a=>{const t=String(a||"").trim();if(!t)return"Unknown";const i=Date.parse(t);return Number.isFinite(i)?new Date(i).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):t},re=c.useMemo(()=>{if(!n)return{attributes:[],dates:[]};const a=n.primaryProfile,t=i=>i||"Not set";return{attributes:[{label:"Category",value:a.surfaceType?le(a.surfaceType):""},{label:"Connection",value:a.seatScope?we(a.seatScope):""},{label:"Provider",value:a.provider||""},{label:"Model",value:a.model||""}].map(i=>({...i,value:t(i.value)})),dates:[{label:"Status",value:a.archivedAt?"Retired":"Active"},{label:"Recruited",value:N(a.createdAt)},{label:"Last updated",value:N(a.updatedAt)},{label:"Last active",value:N(a.lastActiveAt)}].map(i=>({...i,value:t(i.value)}))}},[n]),be=!!n&&n.profiles.length>1,te=m&&U&&!ue,$=m?de(me):ve,F=te?"Log into account for Cloud agents":$?`${$.used}/${$.limit===null?"Unlimited":$.limit}`:null,z=!!V;return e.jsxs("section",{className:`${r.agentsModuleRoot} ${z?r.agentsModuleWithTray:""} ${z&&E?r.agentsModuleTrayOpen:""}`.trim(),children:[z&&e.jsxs("aside",{className:`${r.agentTrayPanel} ${E?r.agentTrayPanelOpen:""}`.trim(),"aria-label":"Agent MCP settings tray","aria-hidden":!E,children:[e.jsxs("div",{className:r.agentTrayHeader,children:[e.jsxs("span",{className:r.agentTrayTitle,children:[e.jsx(Re,{size:14}),"MCP Settings"]}),e.jsx("button",{type:"button",className:"tf-control-icon",onClick:he,title:"Collapse agent tray","aria-label":"Collapse agent tray",children:e.jsx($e,{size:16})})]}),e.jsx("div",{className:`${r.agentTrayContent} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.agentTrayContentInner,children:V})})]}),e.jsx("div",{className:r.agentsModuleContent,children:e.jsx("div",{className:`${r.settingGroup} ${r.agentsModuleGroup}`,children:e.jsxs("div",{children:[e.jsx("h4",{className:r.settingSubTitle,children:"Registered AI Profiles"}),e.jsx("p",{className:`${r.settingsHint} ${r.marginBottom12}`,children:"AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost, or remove inactive profiles from the active roster to free seats while preserving history."}),F&&e.jsx("div",{className:r.aiProfileSeatSummary,children:te?F:`Registered Cloud Agents: ${F}`}),B&&e.jsxs("div",{className:r.settingsHint,children:[e.jsx(Ee,{size:13,className:r.spinner})," Loading profiles…"]}),!B&&S.length===0&&e.jsx("div",{className:r.settingsHint,children:"No AI profiles registered yet."}),!B&&R.length>0&&e.jsxs("div",{className:r.aiProfilesExplorer,children:[e.jsx("div",{className:`${r.aiProfilesListPane} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.aiProfilesList,children:R.map(a=>e.jsxs("div",{className:r.aiProfilesSection,children:[e.jsx("div",{className:r.aiProfilesSectionHeader,children:a.label}),a.groups.map(t=>{const i=n?.groupId===t.groupId,o=t.primaryProfile;return e.jsxs("div",{role:"button",tabIndex:0,className:`${r.aiProfileGroup} ${t.profiles.length>1?r.aiProfileGroupDuplicate:""} ${i?r.aiProfileGroupSelected:""}`,onClick:()=>j(t.groupId),onKeyDown:d=>{d.key!=="Enter"&&d.key!==" "||(d.preventDefault(),j(t.groupId))},"aria-pressed":i,children:[pe(o.seatScope),e.jsxs("div",{className:r.aiProfileGroupHeader,children:[e.jsx("span",{className:r.aiProfileGroupAvatar,style:{color:o.color},children:o.avatarUrl?e.jsx("img",{src:K(o),alt:""}):e.jsx(ne,{size:22})}),e.jsxs("span",{className:r.aiProfileGroupIdentity,children:[e.jsx("span",{className:r.aiProfileName,children:o.name}),e.jsxs("span",{className:r.aiProfileHandle,children:["@",o.username]}),e.jsx("span",{className:r.aiProfileRole,children:o.role||"Role not set"}),t.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDuplicateBadge,children:[e.jsx(C,{size:11})," ",Oe(t.profiles.length)]})]})]})]},t.groupId)})]},a.section))})}),n&&e.jsx("div",{className:r.aiProfileDetailPane,children:e.jsxs("div",{className:r.aiProfileDetailCard,children:[pe(n.primaryProfile.seatScope,{variant:"detail"}),e.jsxs("div",{className:r.aiProfileDetailHero,children:[e.jsx(Te,{label:"Edit AI profile photo",imageUrl:K(n.primaryProfile),fallback:e.jsx(ne,{size:38}),accentColor:n.primaryProfile.color,size:176,width:153,height:207,radius:6,editBadgeSize:28,editIconSize:14,className:r.aiProfileDetailAvatar,onClick:()=>{g(null),Q(n.primaryProfile.id)}}),e.jsxs("div",{className:r.aiProfileDetailHeading,children:[e.jsx("div",{className:r.aiProfileDetailTitleRow,children:e.jsx("h5",{className:r.aiProfileDetailTitle,children:n.primaryProfile.name})}),e.jsxs("div",{className:r.aiProfileDetailMetaRow,children:[e.jsxs("span",{className:r.aiProfileDetailHandle,children:["@",n.primaryProfile.username]}),n.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDetailLinkedCount,children:[n.profiles.length," linked"]})]}),e.jsxs("div",{className:r.aiProfileDetailRole,children:["Role: ",n.primaryProfile.role||"Not set"]}),n.primaryProfile.description&&e.jsx("div",{className:r.aiProfileDetailDescription,children:n.primaryProfile.description}),e.jsxs("div",{className:r.aiProfileSignatureColor,children:[e.jsx("span",{children:"Signature color"}),e.jsx("span",{className:r.aiProfileSignatureSwatch,style:{backgroundColor:n.primaryProfile.color},"aria-hidden":"true"}),e.jsx("span",{children:n.primaryProfile.color})]})]})]}),e.jsxs("div",{className:r.aiProfileDetailDataList,children:[e.jsx("div",{className:r.aiProfileDetailDataGroup,children:re.attributes.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Category"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent category",value:n.primaryProfile.surfaceType??"",disabled:ye,onChange:t=>{Se(n,t.target.value)},children:[e.jsx("option",{value:"",children:"Unclassified"}),Me.map(t=>e.jsx("option",{value:t,children:le(t)},t))]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))}),e.jsx("div",{className:`${r.aiProfileDetailDataGroup} ${r.aiProfileDetailDateGroup}`,children:re.dates.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Status"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent roster status",value:n.primaryProfile.archivedAt?"retired":"active",onChange:t=>{t.target.value==="retire"&&Z(n.primaryProfile)},children:[e.jsx("option",{value:"active",children:"Active"}),n.primaryProfile.archivedAt?e.jsx("option",{value:"retired",children:"Retired"}):e.jsx("option",{value:"retire",children:"Retire from roster"})]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))})]}),W?.profileId===n.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:W.message})]}),be?e.jsxs("div",{className:r.aiProfileInstanceSection,children:[e.jsxs("div",{className:r.aiProfileInstanceSectionHeader,children:[e.jsx("span",{children:"Profile instances"}),e.jsx("span",{className:r.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),e.jsx("div",{className:r.aiProfileInstanceList,children:n.profiles.map(a=>e.jsxs("div",{className:r.aiProfileInstanceCard,children:[e.jsxs("div",{className:r.aiProfileInstanceTopRow,children:[e.jsxs("div",{children:[e.jsxs("div",{className:r.aiProfileInstanceName,children:["@",a.username]}),e.jsx("div",{className:r.aiProfileIdChip,children:a.id})]}),h?.keepId===a.id&&e.jsx("span",{className:r.aiProfileKeepBadge,children:"Keeping"})]}),e.jsxs("div",{className:r.aiProfileInstanceMeta,children:[e.jsxs("span",{children:["Created ",N(a.createdAt)]}),e.jsxs("span",{children:["Updated ",N(a.updatedAt)]})]}),h?.keepId!==a.id&&e.jsx("button",{className:r.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const t=n.profiles.find(i=>i.id!==a.id)?.id;t&&D({keepId:a.id,mergeId:t})},children:"Keep this"}),T?.profileId===a.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:T.message})]}),e.jsx("button",{className:r.aiProfileDangerTextButton,title:"Remove this profile from the active roster",onClick:()=>{Z(a)},children:"Remove from roster"})]},a.id))}),h&&n.profiles.some(a=>a.id===h.keepId)&&e.jsxs("div",{className:r.aiProfileMergeActions,children:[e.jsx("button",{className:r.dangerBtn,onClick:()=>{Ae(h.keepId,h.mergeId)},children:"Merge duplicates"}),e.jsx("button",{className:r.secondaryHeaderBtn,onClick:()=>D(null),children:"Cancel"})]})]}):e.jsxs("div",{className:r.aiProfileIdFooter,children:[e.jsx("div",{className:r.aiProfileIdFooterValue,children:n.primaryProfile.id}),T?.profileId===n.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:T.message})]})]})]})})]}),w&&e.jsxs("div",{className:`${w.type==="success"?r.successMessage:r.errorMessage} ${r.marginTop12}`,children:[w.type==="success"?e.jsx(Le,{size:14}):e.jsx(C,{size:14}),w.message]})]})})}),e.jsx(ke,{isOpen:!!u,theme:"dark",title:"Edit AI Profile Photo",currentImageUrl:K(u),editorImageUrl:ze(u),fallbackInitial:(u?.name||"AI").charAt(0).toUpperCase(),accept:"image/png,image/jpeg,image/webp,image/gif",busy:X,hasPendingImage:!1,canRemove:!!u?.avatarUrl,error:Pe,notice:null,onClose:()=>{X||(Q(null),g(null))},onApplyImage:Ne,onRemoveImage:Ie})]})}export{qe as AgentsModule};
@@ -1,3 +1,3 @@
1
- import{j as t,r as s,R as aa}from"./vendor-react-CKJs5o3c.js";import{R as Fn,f as ge,e as Rt,g as Hn,t as za,M as na}from"./index-rB9GGUCz.js";import{a7 as Ua,x as Dn,w as On,p as zn,P as Un,c as sa,T as Ga,r as Gn,h as Ka,an as Kn,R as Wn,ao as Yn,ap as Xn,aq as Vn,ar as ia,C as la,as as qn,at as Za,au as Qa,av as en,aw as tn,g as Jn,f as Zn,b as ca}from"./vendor-icons-CLnehDTw.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function Qn({copied:r,disabled:l=!1,label:f,onClick:p,title:b="Copy image reference",ariaLabel:x,className:L=""}){return t.jsx(Fn,{copied:r,disabled:l,label:"",onClick:p,title:b,ariaLabel:x,className:L,children:f})}const es="_shell_17mlo_1",ts="_shellWithImageTray_17mlo_18",as="_shellImageTrayOpen_17mlo_22",ns="_imageTrayPanel_17mlo_26",ss="_imageTrayPanelOpen_17mlo_50",rs="_imageTrayHeader_17mlo_58",os="_imageTrayTitle_17mlo_73",is="_imageTraySearch_17mlo_85",ls="_imageTraySearchIcon_17mlo_91",cs="_imageTraySearchInput_17mlo_100",ds="_imageTrayList_17mlo_117",us="_imageTrayState_17mlo_129",ms="_imageTrayStateError_17mlo_130",fs="_imageTrayItem_17mlo_142",hs="_imageTrayItemActive_17mlo_164",ps="_imageTrayThumb_17mlo_174",gs="_imageTrayItemBody_17mlo_191",ys="_imageTrayItemTitle_17mlo_199",bs="_imageTrayItemTask_17mlo_200",xs="_imageTrayItemMetaDetails_17mlo_201",vs="_imageTrayItemMeta_17mlo_201",_s="_imageTrayItemReference_17mlo_239",Is="_panel_17mlo_246",ws="_sessionPanel_17mlo_252",ks="_detailPanel_17mlo_253",Ss="_sessionContextBar_17mlo_259",Ns="_sessionContextLeft_17mlo_270",Cs="_sessionContextRight_17mlo_271",js="_sessionContextLabel_17mlo_286",Ts="_sessionContextSpacer_17mlo_292",$s="_canvasPanel_17mlo_297",Rs="_canvasWorkspace_17mlo_304",Ps="_canvasMain_17mlo_311",Bs="_panelHeader_17mlo_318",Es="_panelHeaderText_17mlo_327",As="_panelTitle_17mlo_331",Ms="_canvasHeading_17mlo_335",Ls="_sessionActions_17mlo_339",Fs="_sessionList_17mlo_347",Hs="_annotationList_17mlo_348",Ds="_markerHelpModalBody_17mlo_363",Os="_openImageModalBody_17mlo_369",zs="_openImageField_17mlo_375",Us="_openImageActions_17mlo_379",Gs="_markerHelpItem_17mlo_385",Ks="_markerHelpHeader_17mlo_393",Ws="_markerHelpExample_17mlo_405",Ys="_sessionCard_17mlo_409",Xs="_annotationCard_17mlo_410",Vs="_sessionEmptyState_17mlo_427",qs="_sessionCardButton_17mlo_434",Js="_annotationCardButton_17mlo_444",Zs="_sessionCardBody_17mlo_454",Qs="_sessionCardActive_17mlo_460",er="_annotationCardActive_17mlo_461",tr="_annotationMeta_17mlo_471",ar="_annotationInstructionPreview_17mlo_478",nr="_annotationPreviewFooter_17mlo_486",sr="_annotationInstructionEditor_17mlo_493",rr="_annotationTypeField_17mlo_499",or="_annotationInstructionButton_17mlo_505",ir="_annotationInstructionField_17mlo_514",lr="_sessionMeta_17mlo_518",cr="_sessionTitle_17mlo_525",dr="_annotationTitle_17mlo_526",ur="_sessionTimestamp_17mlo_532",mr="_annotationKind_17mlo_533",fr="_annotationInstructionTypeIcon_17mlo_537",hr="_sessionInstructionPreview_17mlo_543",pr="_sessionInstructionEditor_17mlo_551",gr="_sessionCardFooter_17mlo_557",yr="_toolRail_17mlo_564",br="_canvasToolRail_17mlo_573",xr="_toolbarCluster_17mlo_594",vr="_toolbarViewportCluster_17mlo_601",_r="_toolbarSeparator_17mlo_605",Ir="_toolBtn_17mlo_611",wr="_toolRailButton_17mlo_615",kr="_toolbarButton_17mlo_625",Sr="_toolBtnActive_17mlo_630",Nr="_toolbarActions_17mlo_637",Cr="_toolbarSelectionActions_17mlo_646",jr="_toolbarColorPicker_17mlo_654",Tr="_colorPickerButton_17mlo_658",$r="_colorPickerSwatch_17mlo_663",Rr="_colorPickerPopover_17mlo_671",Pr="_colorOption_17mlo_686",Br="_colorOptionActive_17mlo_696",Er="_toolbarUtilities_17mlo_703",Ar="_toolbarGeometryFields_17mlo_711",Mr="_toolbarGeometryField_17mlo_711",Lr="_toolbarGeometryLabel_17mlo_724",Fr="_toolbarGeometryInput_17mlo_730",Hr="_iconButton_17mlo_735",Dr="_ghostBtn_17mlo_740",Or="_payloadBtn_17mlo_741",zr="_backToTaskBtn_17mlo_742",Ur="_canvasScroller_17mlo_762",Gr="_canvasFrame_17mlo_778",Kr="_canvasMedia_17mlo_785",Wr="_canvasStatusOverlay_17mlo_793",Yr="_canvasStatusCard_17mlo_805",Xr="_canvasImage_17mlo_818",Vr="_overlay_17mlo_825",qr="_overlaySelect_17mlo_831",Jr="_overlayPan_17mlo_835",Zr="_overlaySvg_17mlo_839",Qr="_overlayHitLayer_17mlo_848",eo="_arrowHitArea_17mlo_857",to="_canvasHandleHit_17mlo_864",ao="_canvasResizeHandleHit_17mlo_871",no="_canvasHandleVisible_17mlo_875",so="_pin_17mlo_892",ro="_note_17mlo_893",oo="_annotationNumberBadge_17mlo_910",io="_box_17mlo_935",lo="_boxNumberBadge_17mlo_944",co="_arrowNumberBadge_17mlo_950",uo="_boxSurface_17mlo_954",mo="_selected_17mlo_967",fo="_textInput_17mlo_984",ho="_textArea_17mlo_985",po="_select_17mlo_967",go="_sessionTitleInput_17mlo_992",yo="_sessionInstructionField_17mlo_997",bo="_detailEmpty_17mlo_1006",xo="_emptyState_17mlo_1007",vo="_payloadModalBody_17mlo_1019",_o="_payloadModalToolbar_17mlo_1026",Io="_payloadViewToggle_17mlo_1033",wo="_payloadModalActions_17mlo_1034",ko="_payloadModalPreview_17mlo_1041",So="_statusBar_17mlo_1056",No="_annotationSummary_17mlo_1068",a={shell:es,shellWithImageTray:ts,shellImageTrayOpen:as,imageTrayPanel:ns,imageTrayPanelOpen:ss,imageTrayHeader:rs,imageTrayTitle:os,imageTraySearch:is,imageTraySearchIcon:ls,imageTraySearchInput:cs,imageTrayList:ds,imageTrayState:us,imageTrayStateError:ms,imageTrayItem:fs,imageTrayItemActive:hs,imageTrayThumb:ps,imageTrayItemBody:gs,imageTrayItemTitle:ys,imageTrayItemTask:bs,imageTrayItemMetaDetails:xs,imageTrayItemMeta:vs,imageTrayItemReference:_s,panel:Is,sessionPanel:ws,detailPanel:ks,sessionContextBar:Ss,sessionContextLeft:Ns,sessionContextRight:Cs,sessionContextLabel:js,sessionContextSpacer:Ts,canvasPanel:$s,canvasWorkspace:Rs,canvasMain:Ps,panelHeader:Bs,panelHeaderText:Es,panelTitle:As,canvasHeading:Ms,sessionActions:Ls,sessionList:Fs,annotationList:Hs,markerHelpModalBody:Ds,openImageModalBody:Os,openImageField:zs,openImageActions:Us,markerHelpItem:Gs,markerHelpHeader:Ks,markerHelpExample:Ws,sessionCard:Ys,annotationCard:Xs,sessionEmptyState:Vs,sessionCardButton:qs,annotationCardButton:Js,sessionCardBody:Zs,sessionCardActive:Qs,annotationCardActive:er,annotationMeta:tr,annotationInstructionPreview:ar,annotationPreviewFooter:nr,annotationInstructionEditor:sr,annotationTypeField:rr,annotationInstructionButton:or,annotationInstructionField:ir,sessionMeta:lr,sessionTitle:cr,annotationTitle:dr,sessionTimestamp:ur,annotationKind:mr,annotationInstructionTypeIcon:fr,sessionInstructionPreview:hr,sessionInstructionEditor:pr,sessionCardFooter:gr,toolRail:yr,canvasToolRail:br,toolbarCluster:xr,toolbarViewportCluster:vr,toolbarSeparator:_r,toolBtn:Ir,toolRailButton:wr,toolbarButton:kr,toolBtnActive:Sr,toolbarActions:Nr,toolbarSelectionActions:Cr,toolbarColorPicker:jr,colorPickerButton:Tr,colorPickerSwatch:$r,colorPickerPopover:Rr,colorOption:Pr,colorOptionActive:Br,toolbarUtilities:Er,toolbarGeometryFields:Ar,toolbarGeometryField:Mr,toolbarGeometryLabel:Lr,toolbarGeometryInput:Fr,iconButton:Hr,ghostBtn:Dr,payloadBtn:Or,backToTaskBtn:zr,canvasScroller:Ur,canvasFrame:Gr,canvasMedia:Kr,canvasStatusOverlay:Wr,canvasStatusCard:Yr,canvasImage:Xr,overlay:Vr,overlaySelect:qr,overlayPan:Jr,overlaySvg:Zr,overlayHitLayer:Qr,arrowHitArea:eo,canvasHandleHit:to,canvasResizeHandleHit:ao,canvasHandleVisible:no,pin:so,note:ro,annotationNumberBadge:oo,box:io,boxNumberBadge:lo,arrowNumberBadge:co,boxSurface:uo,selected:mo,textInput:fo,textArea:ho,select:po,sessionTitleInput:go,sessionInstructionField:yo,detailEmpty:bo,emptyState:xo,payloadModalBody:vo,payloadModalToolbar:_o,payloadViewToggle:Io,payloadModalActions:wo,payloadModalPreview:ko,statusBar:So,annotationSummary:No},Wa=[{value:"review",label:"Review"},{value:"change",label:"Change"},{value:"question",label:"Question"}],Ya=[{value:"select",label:"Select",icon:qn},{value:"pin",label:"Pin",icon:Za},{value:"box",label:"Box",icon:Qa},{value:"arrow",label:"Arrow",icon:en},{value:"text-note",label:"Note",icon:tn}],Co={pin:Za,box:Qa,arrow:en,"text-note":tn},jo={pin:"Pin",box:"Box",arrow:"Arrow","text-note":"Note"},To={review:ia,change:ca,question:la,issue:la,idea:ia},Pt={select:{short:"Select and edit existing markers.",detail:"Use Select to click, drag, reorder, resize, and update markers that are already on the image.",example:"Example: move an existing marker after the screenshot changes."},pin:{short:"Mark a precise spot.",detail:"Use Pin when feedback points to one exact location instead of a broader area.",example:'Example: "This icon is misaligned by 2px."'},box:{short:"Mark an area or component.",detail:"Use Box when the feedback applies to a whole region, card, panel, or bounded UI block.",example:'Example: "This whole card needs tighter padding and a stronger border."'},arrow:{short:"Show direction or relationship.",detail:"Use Arrow when you need to show movement, attachment, flow, or source-to-target intent.",example:'Example: "This tooltip should anchor to this button, not the panel."'},"text-note":{short:"Add a comment-style point marker.",detail:"Use Note when you want a point marker that reads more like a comment or open question.",example:'Example: "Ask design whether this badge should stay."'}},ct={question:"#0f766e",change:"#2563eb",issue:"#dc2626",idea:"#d97706",review:"#7c3aed"},$o=["#7c3aed","#2563eb","#0f766e","#dc2626","#d97706","#111827"],ce="review";function Ke(r){const l=String(r.displayName||"").trim();return l?`${l} review`:"Annotated session"}function an(){return`annotation-${Math.random().toString(36).slice(2,10)}`}function I(r){return!Number.isFinite(r)||r<=0?0:r>=1?1:r}function Se(r){return I(Math.max(.02,r))}function Ge(r){return r?[String(r.taskId||"").trim(),String(r.assetId||"").trim(),String(r.path||"").trim()].join("::"):""}function nn(r){if(!(r instanceof HTMLElement))return!1;const l=r.tagName.toLowerCase();return r.isContentEditable?!0:l==="input"||l==="textarea"||l==="select"}function Ro(r){if(!(r instanceof HTMLElement))return!1;if(nn(r))return!0;const l=r.tagName.toLowerCase();return l==="button"||l==="a"||r.getAttribute("role")==="button"}function ke(r){return r.map((l,f)=>({...l,order:f}))}function ra(r){if(!r)return"Unsaved";const l=new Date(r);return Number.isNaN(l.getTime())?"Unsaved":l.toLocaleString()}function Po(r){const l=typeof r=="number"&&Number.isFinite(r)?Math.max(0,r):0;return l<1024?`${l}B`:l<1024*1024?`${(l/1024).toFixed(1)}KB`:`${(l/(1024*1024)).toFixed(1)}MB`}function Bo(r){if(!r)return"";const l=new Date(r);if(Number.isNaN(l.getTime()))return"";const p=new Date().getTime()-l.getTime(),b=Math.floor(p/(1e3*60*60*24));return b<=0?"Today":b===1?"Yesterday":b<7?`${b}d ago`:b<30?`${Math.floor(b/7)}w ago`:l.toLocaleDateString()}function Bt(r){const l=String(r.createdByActor?.label||"").trim();return l||null}function Eo(r){const l=String(r||"").trim().replace(/\s+/g," ");return l?l.length>110?`${l.slice(0,107)}...`:l:""}function Xa(r,l,f,p=ct[ce]){const b={id:an(),order:0,instruction:"",markerType:ce,color:p};if(r==="pin")return{...b,kind:r,x:l.x,y:l.y};if(r==="text-note")return{...b,kind:r,x:l.x,y:l.y};if(r==="box"){const L=f||l;return{...b,kind:r,x:I(Math.min(l.x,L.x)),y:I(Math.min(l.y,L.y)),width:Se(Math.abs(L.x-l.x)),height:Se(Math.abs(L.y-l.y))}}const x=f||l;return{...b,kind:"arrow",x:l.x,y:l.y,x2:x.x,y2:x.y}}function oa(r){return r.color?r.color:ct[r.markerType||ce]}function Ao(r,l){const f=Math.max(l.width,1),p=Math.max(l.height,1),b=r.x*f,x=r.y*p,L=r.x2*f,ne=r.y2*p,se=L-b,dt=ne-x,Ne=Math.hypot(se,dt)||1,We=se/Ne,Ce=dt/Ne,G=Math.max(10,Math.min(16,Ne-2)),ye=G*.62,je=L-We*G,$=ne-Ce*G,ut=-Ce,be=We;return{shaftX1:b,shaftY1:x,shaftX2:je,shaftY2:$,headPoints:[`${L},${ne}`,`${je+ut*ye},${$+be*ye}`,`${je-ut*ye},${$-be*ye}`].join(" ")}}function Mo(r,l){return{...r,markerType:l,color:r.color||ct[l]}}function Lo(r,l){return{...r,id:an(),order:l}}function Fo(r,l){const f=String(r||"").trim()||(l?Ke(l):"Annotated session");return/\bcopy$/i.test(f)?`${f} 2`:`${f} copy`}function Ho(r,l,f){if(l===f||l<0||f<0||l>=r.length||f>=r.length)return r;const p=[...r],[b]=p.splice(l,1);return b?(p.splice(f,0,b),ke(p)):r}function ae(r){return String(Math.round(I(r)*1e3)/10)}function Do(r){const l=Number.parseFloat(r);return Number.isFinite(l)?I(l/100):null}function Oo(r,l,f){return r.kind==="pin"||r.kind==="text-note"?l==="x"||l==="y"?{...r,[l]:I(f)}:r:r.kind==="box"?l==="x"||l==="y"?{...r,[l]:I(f)}:l==="width"||l==="height"?{...r,[l]:Se(f)}:r:l==="x"||l==="y"||l==="x2"||l==="y2"?{...r,[l]:I(f)}:r}function zo(r){return r.kind==="pin"||r.kind==="text-note"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)}]:r.kind==="box"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)},{key:"width",label:"Width",value:ae(r.width)},{key:"height",label:"Height",value:ae(r.height)}]:[{key:"x",label:"Start X",value:ae(r.x)},{key:"y",label:"Start Y",value:ae(r.y)},{key:"x2",label:"End X",value:ae(r.x2)},{key:"y2",label:"End Y",value:ae(r.y2)}]}function Uo(r){if(!r)return null;const l=Math.round(r.x*100),f=Math.round(r.y*100),p=Math.round(r.width*100),b=Math.round(r.height*100);return`crop ${l}%, ${f}% size ${p}% x ${b}%`}function Go(r){return Number.isFinite(r)?Math.min(4,Math.max(.25,Number(r.toFixed(2)))):1}function Va(r){const l=[`Annotated attachment: ${r.title||r.image.displayName}`,`Image: ${r.image.displayName}`,`Image Reference: ${r.image.referenceLabel||r.image.assetId}`,`Task ID: ${r.taskId}`,r.globalInstruction?`Global instruction: ${r.globalInstruction}`:"Global instruction: None provided.","Markers:"];return r.annotations.length===0?(l.push("0. No markers."),l.join(`
1
+ import{j as t,r as s,R as aa}from"./vendor-react-CKJs5o3c.js";import{R as Fn,f as ge,e as Rt,g as Hn,t as za,M as na}from"./index-CGDQY0nN.js";import{a7 as Ua,x as Dn,w as On,p as zn,P as Un,c as sa,T as Ga,r as Gn,h as Ka,an as Kn,R as Wn,ao as Yn,ap as Xn,aq as Vn,ar as ia,C as la,as as qn,at as Za,au as Qa,av as en,aw as tn,g as Jn,f as Zn,b as ca}from"./vendor-icons-CLnehDTw.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function Qn({copied:r,disabled:l=!1,label:f,onClick:p,title:b="Copy image reference",ariaLabel:x,className:L=""}){return t.jsx(Fn,{copied:r,disabled:l,label:"",onClick:p,title:b,ariaLabel:x,className:L,children:f})}const es="_shell_17mlo_1",ts="_shellWithImageTray_17mlo_18",as="_shellImageTrayOpen_17mlo_22",ns="_imageTrayPanel_17mlo_26",ss="_imageTrayPanelOpen_17mlo_50",rs="_imageTrayHeader_17mlo_58",os="_imageTrayTitle_17mlo_73",is="_imageTraySearch_17mlo_85",ls="_imageTraySearchIcon_17mlo_91",cs="_imageTraySearchInput_17mlo_100",ds="_imageTrayList_17mlo_117",us="_imageTrayState_17mlo_129",ms="_imageTrayStateError_17mlo_130",fs="_imageTrayItem_17mlo_142",hs="_imageTrayItemActive_17mlo_164",ps="_imageTrayThumb_17mlo_174",gs="_imageTrayItemBody_17mlo_191",ys="_imageTrayItemTitle_17mlo_199",bs="_imageTrayItemTask_17mlo_200",xs="_imageTrayItemMetaDetails_17mlo_201",vs="_imageTrayItemMeta_17mlo_201",_s="_imageTrayItemReference_17mlo_239",Is="_panel_17mlo_246",ws="_sessionPanel_17mlo_252",ks="_detailPanel_17mlo_253",Ss="_sessionContextBar_17mlo_259",Ns="_sessionContextLeft_17mlo_270",Cs="_sessionContextRight_17mlo_271",js="_sessionContextLabel_17mlo_286",Ts="_sessionContextSpacer_17mlo_292",$s="_canvasPanel_17mlo_297",Rs="_canvasWorkspace_17mlo_304",Ps="_canvasMain_17mlo_311",Bs="_panelHeader_17mlo_318",Es="_panelHeaderText_17mlo_327",As="_panelTitle_17mlo_331",Ms="_canvasHeading_17mlo_335",Ls="_sessionActions_17mlo_339",Fs="_sessionList_17mlo_347",Hs="_annotationList_17mlo_348",Ds="_markerHelpModalBody_17mlo_363",Os="_openImageModalBody_17mlo_369",zs="_openImageField_17mlo_375",Us="_openImageActions_17mlo_379",Gs="_markerHelpItem_17mlo_385",Ks="_markerHelpHeader_17mlo_393",Ws="_markerHelpExample_17mlo_405",Ys="_sessionCard_17mlo_409",Xs="_annotationCard_17mlo_410",Vs="_sessionEmptyState_17mlo_427",qs="_sessionCardButton_17mlo_434",Js="_annotationCardButton_17mlo_444",Zs="_sessionCardBody_17mlo_454",Qs="_sessionCardActive_17mlo_460",er="_annotationCardActive_17mlo_461",tr="_annotationMeta_17mlo_471",ar="_annotationInstructionPreview_17mlo_478",nr="_annotationPreviewFooter_17mlo_486",sr="_annotationInstructionEditor_17mlo_493",rr="_annotationTypeField_17mlo_499",or="_annotationInstructionButton_17mlo_505",ir="_annotationInstructionField_17mlo_514",lr="_sessionMeta_17mlo_518",cr="_sessionTitle_17mlo_525",dr="_annotationTitle_17mlo_526",ur="_sessionTimestamp_17mlo_532",mr="_annotationKind_17mlo_533",fr="_annotationInstructionTypeIcon_17mlo_537",hr="_sessionInstructionPreview_17mlo_543",pr="_sessionInstructionEditor_17mlo_551",gr="_sessionCardFooter_17mlo_557",yr="_toolRail_17mlo_564",br="_canvasToolRail_17mlo_573",xr="_toolbarCluster_17mlo_594",vr="_toolbarViewportCluster_17mlo_601",_r="_toolbarSeparator_17mlo_605",Ir="_toolBtn_17mlo_611",wr="_toolRailButton_17mlo_615",kr="_toolbarButton_17mlo_625",Sr="_toolBtnActive_17mlo_630",Nr="_toolbarActions_17mlo_637",Cr="_toolbarSelectionActions_17mlo_646",jr="_toolbarColorPicker_17mlo_654",Tr="_colorPickerButton_17mlo_658",$r="_colorPickerSwatch_17mlo_663",Rr="_colorPickerPopover_17mlo_671",Pr="_colorOption_17mlo_686",Br="_colorOptionActive_17mlo_696",Er="_toolbarUtilities_17mlo_703",Ar="_toolbarGeometryFields_17mlo_711",Mr="_toolbarGeometryField_17mlo_711",Lr="_toolbarGeometryLabel_17mlo_724",Fr="_toolbarGeometryInput_17mlo_730",Hr="_iconButton_17mlo_735",Dr="_ghostBtn_17mlo_740",Or="_payloadBtn_17mlo_741",zr="_backToTaskBtn_17mlo_742",Ur="_canvasScroller_17mlo_762",Gr="_canvasFrame_17mlo_778",Kr="_canvasMedia_17mlo_785",Wr="_canvasStatusOverlay_17mlo_793",Yr="_canvasStatusCard_17mlo_805",Xr="_canvasImage_17mlo_818",Vr="_overlay_17mlo_825",qr="_overlaySelect_17mlo_831",Jr="_overlayPan_17mlo_835",Zr="_overlaySvg_17mlo_839",Qr="_overlayHitLayer_17mlo_848",eo="_arrowHitArea_17mlo_857",to="_canvasHandleHit_17mlo_864",ao="_canvasResizeHandleHit_17mlo_871",no="_canvasHandleVisible_17mlo_875",so="_pin_17mlo_892",ro="_note_17mlo_893",oo="_annotationNumberBadge_17mlo_910",io="_box_17mlo_935",lo="_boxNumberBadge_17mlo_944",co="_arrowNumberBadge_17mlo_950",uo="_boxSurface_17mlo_954",mo="_selected_17mlo_967",fo="_textInput_17mlo_984",ho="_textArea_17mlo_985",po="_select_17mlo_967",go="_sessionTitleInput_17mlo_992",yo="_sessionInstructionField_17mlo_997",bo="_detailEmpty_17mlo_1006",xo="_emptyState_17mlo_1007",vo="_payloadModalBody_17mlo_1019",_o="_payloadModalToolbar_17mlo_1026",Io="_payloadViewToggle_17mlo_1033",wo="_payloadModalActions_17mlo_1034",ko="_payloadModalPreview_17mlo_1041",So="_statusBar_17mlo_1056",No="_annotationSummary_17mlo_1068",a={shell:es,shellWithImageTray:ts,shellImageTrayOpen:as,imageTrayPanel:ns,imageTrayPanelOpen:ss,imageTrayHeader:rs,imageTrayTitle:os,imageTraySearch:is,imageTraySearchIcon:ls,imageTraySearchInput:cs,imageTrayList:ds,imageTrayState:us,imageTrayStateError:ms,imageTrayItem:fs,imageTrayItemActive:hs,imageTrayThumb:ps,imageTrayItemBody:gs,imageTrayItemTitle:ys,imageTrayItemTask:bs,imageTrayItemMetaDetails:xs,imageTrayItemMeta:vs,imageTrayItemReference:_s,panel:Is,sessionPanel:ws,detailPanel:ks,sessionContextBar:Ss,sessionContextLeft:Ns,sessionContextRight:Cs,sessionContextLabel:js,sessionContextSpacer:Ts,canvasPanel:$s,canvasWorkspace:Rs,canvasMain:Ps,panelHeader:Bs,panelHeaderText:Es,panelTitle:As,canvasHeading:Ms,sessionActions:Ls,sessionList:Fs,annotationList:Hs,markerHelpModalBody:Ds,openImageModalBody:Os,openImageField:zs,openImageActions:Us,markerHelpItem:Gs,markerHelpHeader:Ks,markerHelpExample:Ws,sessionCard:Ys,annotationCard:Xs,sessionEmptyState:Vs,sessionCardButton:qs,annotationCardButton:Js,sessionCardBody:Zs,sessionCardActive:Qs,annotationCardActive:er,annotationMeta:tr,annotationInstructionPreview:ar,annotationPreviewFooter:nr,annotationInstructionEditor:sr,annotationTypeField:rr,annotationInstructionButton:or,annotationInstructionField:ir,sessionMeta:lr,sessionTitle:cr,annotationTitle:dr,sessionTimestamp:ur,annotationKind:mr,annotationInstructionTypeIcon:fr,sessionInstructionPreview:hr,sessionInstructionEditor:pr,sessionCardFooter:gr,toolRail:yr,canvasToolRail:br,toolbarCluster:xr,toolbarViewportCluster:vr,toolbarSeparator:_r,toolBtn:Ir,toolRailButton:wr,toolbarButton:kr,toolBtnActive:Sr,toolbarActions:Nr,toolbarSelectionActions:Cr,toolbarColorPicker:jr,colorPickerButton:Tr,colorPickerSwatch:$r,colorPickerPopover:Rr,colorOption:Pr,colorOptionActive:Br,toolbarUtilities:Er,toolbarGeometryFields:Ar,toolbarGeometryField:Mr,toolbarGeometryLabel:Lr,toolbarGeometryInput:Fr,iconButton:Hr,ghostBtn:Dr,payloadBtn:Or,backToTaskBtn:zr,canvasScroller:Ur,canvasFrame:Gr,canvasMedia:Kr,canvasStatusOverlay:Wr,canvasStatusCard:Yr,canvasImage:Xr,overlay:Vr,overlaySelect:qr,overlayPan:Jr,overlaySvg:Zr,overlayHitLayer:Qr,arrowHitArea:eo,canvasHandleHit:to,canvasResizeHandleHit:ao,canvasHandleVisible:no,pin:so,note:ro,annotationNumberBadge:oo,box:io,boxNumberBadge:lo,arrowNumberBadge:co,boxSurface:uo,selected:mo,textInput:fo,textArea:ho,select:po,sessionTitleInput:go,sessionInstructionField:yo,detailEmpty:bo,emptyState:xo,payloadModalBody:vo,payloadModalToolbar:_o,payloadViewToggle:Io,payloadModalActions:wo,payloadModalPreview:ko,statusBar:So,annotationSummary:No},Wa=[{value:"review",label:"Review"},{value:"change",label:"Change"},{value:"question",label:"Question"}],Ya=[{value:"select",label:"Select",icon:qn},{value:"pin",label:"Pin",icon:Za},{value:"box",label:"Box",icon:Qa},{value:"arrow",label:"Arrow",icon:en},{value:"text-note",label:"Note",icon:tn}],Co={pin:Za,box:Qa,arrow:en,"text-note":tn},jo={pin:"Pin",box:"Box",arrow:"Arrow","text-note":"Note"},To={review:ia,change:ca,question:la,issue:la,idea:ia},Pt={select:{short:"Select and edit existing markers.",detail:"Use Select to click, drag, reorder, resize, and update markers that are already on the image.",example:"Example: move an existing marker after the screenshot changes."},pin:{short:"Mark a precise spot.",detail:"Use Pin when feedback points to one exact location instead of a broader area.",example:'Example: "This icon is misaligned by 2px."'},box:{short:"Mark an area or component.",detail:"Use Box when the feedback applies to a whole region, card, panel, or bounded UI block.",example:'Example: "This whole card needs tighter padding and a stronger border."'},arrow:{short:"Show direction or relationship.",detail:"Use Arrow when you need to show movement, attachment, flow, or source-to-target intent.",example:'Example: "This tooltip should anchor to this button, not the panel."'},"text-note":{short:"Add a comment-style point marker.",detail:"Use Note when you want a point marker that reads more like a comment or open question.",example:'Example: "Ask design whether this badge should stay."'}},ct={question:"#0f766e",change:"#2563eb",issue:"#dc2626",idea:"#d97706",review:"#7c3aed"},$o=["#7c3aed","#2563eb","#0f766e","#dc2626","#d97706","#111827"],ce="review";function Ke(r){const l=String(r.displayName||"").trim();return l?`${l} review`:"Annotated session"}function an(){return`annotation-${Math.random().toString(36).slice(2,10)}`}function I(r){return!Number.isFinite(r)||r<=0?0:r>=1?1:r}function Se(r){return I(Math.max(.02,r))}function Ge(r){return r?[String(r.taskId||"").trim(),String(r.assetId||"").trim(),String(r.path||"").trim()].join("::"):""}function nn(r){if(!(r instanceof HTMLElement))return!1;const l=r.tagName.toLowerCase();return r.isContentEditable?!0:l==="input"||l==="textarea"||l==="select"}function Ro(r){if(!(r instanceof HTMLElement))return!1;if(nn(r))return!0;const l=r.tagName.toLowerCase();return l==="button"||l==="a"||r.getAttribute("role")==="button"}function ke(r){return r.map((l,f)=>({...l,order:f}))}function ra(r){if(!r)return"Unsaved";const l=new Date(r);return Number.isNaN(l.getTime())?"Unsaved":l.toLocaleString()}function Po(r){const l=typeof r=="number"&&Number.isFinite(r)?Math.max(0,r):0;return l<1024?`${l}B`:l<1024*1024?`${(l/1024).toFixed(1)}KB`:`${(l/(1024*1024)).toFixed(1)}MB`}function Bo(r){if(!r)return"";const l=new Date(r);if(Number.isNaN(l.getTime()))return"";const p=new Date().getTime()-l.getTime(),b=Math.floor(p/(1e3*60*60*24));return b<=0?"Today":b===1?"Yesterday":b<7?`${b}d ago`:b<30?`${Math.floor(b/7)}w ago`:l.toLocaleDateString()}function Bt(r){const l=String(r.createdByActor?.label||"").trim();return l||null}function Eo(r){const l=String(r||"").trim().replace(/\s+/g," ");return l?l.length>110?`${l.slice(0,107)}...`:l:""}function Xa(r,l,f,p=ct[ce]){const b={id:an(),order:0,instruction:"",markerType:ce,color:p};if(r==="pin")return{...b,kind:r,x:l.x,y:l.y};if(r==="text-note")return{...b,kind:r,x:l.x,y:l.y};if(r==="box"){const L=f||l;return{...b,kind:r,x:I(Math.min(l.x,L.x)),y:I(Math.min(l.y,L.y)),width:Se(Math.abs(L.x-l.x)),height:Se(Math.abs(L.y-l.y))}}const x=f||l;return{...b,kind:"arrow",x:l.x,y:l.y,x2:x.x,y2:x.y}}function oa(r){return r.color?r.color:ct[r.markerType||ce]}function Ao(r,l){const f=Math.max(l.width,1),p=Math.max(l.height,1),b=r.x*f,x=r.y*p,L=r.x2*f,ne=r.y2*p,se=L-b,dt=ne-x,Ne=Math.hypot(se,dt)||1,We=se/Ne,Ce=dt/Ne,G=Math.max(10,Math.min(16,Ne-2)),ye=G*.62,je=L-We*G,$=ne-Ce*G,ut=-Ce,be=We;return{shaftX1:b,shaftY1:x,shaftX2:je,shaftY2:$,headPoints:[`${L},${ne}`,`${je+ut*ye},${$+be*ye}`,`${je-ut*ye},${$-be*ye}`].join(" ")}}function Mo(r,l){return{...r,markerType:l,color:r.color||ct[l]}}function Lo(r,l){return{...r,id:an(),order:l}}function Fo(r,l){const f=String(r||"").trim()||(l?Ke(l):"Annotated session");return/\bcopy$/i.test(f)?`${f} 2`:`${f} copy`}function Ho(r,l,f){if(l===f||l<0||f<0||l>=r.length||f>=r.length)return r;const p=[...r],[b]=p.splice(l,1);return b?(p.splice(f,0,b),ke(p)):r}function ae(r){return String(Math.round(I(r)*1e3)/10)}function Do(r){const l=Number.parseFloat(r);return Number.isFinite(l)?I(l/100):null}function Oo(r,l,f){return r.kind==="pin"||r.kind==="text-note"?l==="x"||l==="y"?{...r,[l]:I(f)}:r:r.kind==="box"?l==="x"||l==="y"?{...r,[l]:I(f)}:l==="width"||l==="height"?{...r,[l]:Se(f)}:r:l==="x"||l==="y"||l==="x2"||l==="y2"?{...r,[l]:I(f)}:r}function zo(r){return r.kind==="pin"||r.kind==="text-note"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)}]:r.kind==="box"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)},{key:"width",label:"Width",value:ae(r.width)},{key:"height",label:"Height",value:ae(r.height)}]:[{key:"x",label:"Start X",value:ae(r.x)},{key:"y",label:"Start Y",value:ae(r.y)},{key:"x2",label:"End X",value:ae(r.x2)},{key:"y2",label:"End Y",value:ae(r.y2)}]}function Uo(r){if(!r)return null;const l=Math.round(r.x*100),f=Math.round(r.y*100),p=Math.round(r.width*100),b=Math.round(r.height*100);return`crop ${l}%, ${f}% size ${p}% x ${b}%`}function Go(r){return Number.isFinite(r)?Math.min(4,Math.max(.25,Number(r.toFixed(2)))):1}function Va(r){const l=[`Annotated attachment: ${r.title||r.image.displayName}`,`Image: ${r.image.displayName}`,`Image Reference: ${r.image.referenceLabel||r.image.assetId}`,`Task ID: ${r.taskId}`,r.globalInstruction?`Global instruction: ${r.globalInstruction}`:"Global instruction: None provided.","Markers:"];return r.annotations.length===0?(l.push("0. No markers."),l.join(`
2
2
  `)):(r.annotations.forEach((f,p)=>{const b=f.markerType||ce,x=Uo(f.cropHint);l.push(`${p+1}. ${f.kind} (${b})`),l.push(`Instruction: ${f.instruction||"No marker instruction."}`),x&&l.push(`Region: ${x}`)}),l.join(`
3
3
  `))}function Et(r){return{title:r.title,globalInstruction:r.globalInstruction,annotations:ke(r.annotations)}}function qa(r){return JSON.stringify(Et(r))}function Ja(r){const l=JSON.parse(r);return Et({title:String(l?.title||""),globalInstruction:String(l?.globalInstruction||""),annotations:Array.isArray(l?.annotations)?l.annotations:[]})}function Ko(r,l){return Et({title:r?.title||l,globalInstruction:r?.globalInstruction||"",annotations:r?.annotations||[]})}function Qo({runtimeMode:r="local",apiBaseUrl:l="",cloudAuthBaseUrl:f="",workspaceId:p="default",sessionLoadReady:b=!0,requestedTarget:x=null,requestedSessionId:L=null,requestedOpenVersion:ne=0,imageTrayOpen:se,onCloseImageTray:dt,resolveTaskReferenceLabel:Ne,resolveImageReferenceLabel:We,onRequestedTargetHandled:Ce,onOpenTarget:G,onContextChange:ye,onBackToTask:je}){const $=r==="cloud"&&(f||l)||"",[ut,be]=s.useState(x),[mt,Te]=s.useState([]),[v,$e]=s.useState(null),[At,Ye]=s.useState(!1),[Re,Xe]=s.useState(""),[Pe,Ve]=s.useState(""),[j,re]=s.useState([]),[S,F]=s.useState(null),[ft,da]=s.useState(ct[ce]),[ht,pt]=s.useState(!1),[T,Be]=s.useState("select"),[sn,xe]=s.useState(!1),[gt,ua]=s.useState(!1),[V,q]=s.useState(!1),[ma,g]=s.useState(null),[K,R]=s.useState("saved"),[Wo,O]=s.useState(null),[yt,fa]=s.useState(!1),[oe,Mt]=s.useState(null),[de,Lt]=s.useState(!1),[rn,Ft]=s.useState(!1),[Ht,ha]=s.useState("json"),[bt,Dt]=s.useState(!1),[xt,Ot]=s.useState(!1),[on,pa]=s.useState(!1),[ln,vt]=s.useState(!1),[zt,_t]=s.useState(""),[qe,ga]=s.useState(!1),[Ut,cn]=s.useState([]),[It,dn]=s.useState(""),[un,ya]=s.useState(!1),[ba,xa]=s.useState(null),[ue,Je]=s.useState(!1),[Gt,Ze]=s.useState(!1),[P,Kt]=s.useState(1),[mn,Qe]=s.useState(!1),[fn,et]=s.useState(!1),[wt,va]=s.useState(!1),[kt,tt]=s.useState({width:0,height:0}),_a=s.useRef(null),Ee=s.useRef(null),Wt=s.useRef(null),Ia=s.useRef(null),me=s.useRef(L),ie=s.useRef(""),St=s.useRef(0),Yt=s.useRef(""),ve=s.useRef(0),Nt=s.useRef(null),wa=s.useRef(0),fe=s.useRef(!1),at=s.useRef(null),Xt=s.useRef(null),_e=s.useRef(null),H=s.useRef(""),A=s.useRef(""),Ct=s.useRef(null),J=s.useRef(null),Ae=s.useRef(!1),jt=s.useRef(null),nt=s.useRef(null),st=s.useRef(null),Ie=s.useRef(null),Me=s.useRef(null),Le=s.useRef(null),Fe=s.useRef(null),he=s.useRef(null),Z=s.useRef(null),ka=s.useRef(null),Sa=s.useRef(null),B=s.useMemo(()=>mt.find(e=>e.id===v)||null,[v,mt]),Q=s.useMemo(()=>`workspaceId=${encodeURIComponent(String(p||"default").trim()||"default")}`,[p]),E=s.useMemo(()=>({"x-taskforce-workspace-id":String(p||"default").trim()||"default"}),[p]),z=s.useMemo(()=>j.find(e=>e.id===S)||null,[j,S]),ee=s.useMemo(()=>Ge(x),[x]),le=typeof G=="function",d=le?x:ut,Tt=s.useMemo(()=>{const e=String(d?.taskId||"").trim();if(!e)return"";const n=Ne?.(e).trim()||"";if(n)return n;const o=String(d?.taskReferenceLabel||"").trim();return o&&o!==e?o:n||e},[d?.taskId,d?.taskReferenceLabel,Ne]),rt=s.useMemo(()=>{const e=String(d?.assetId||"").trim();if(!e)return"";const n=We?.(e).trim()||"";return n||String(d?.imageReferenceLabel||"").trim()},[d?.assetId,d?.imageReferenceLabel,We]),Vt=s.useMemo(()=>j.findIndex(e=>e.id===S),[j,S]),qt=z?.color||ft,Na=s.useMemo(()=>Et({title:Re,globalInstruction:Pe,annotations:j}),[j,Pe,Re]),He=s.useMemo(()=>qa(Na),[Na]),Ca=He!==A.current,y=s.useMemo(()=>({width:Math.max(kt.width*P,0),height:Math.max(kt.height*P,0)}),[kt.height,kt.width,P]),De=s.useMemo(()=>({visibleRadius:7,hitRadius:11}),[]),Jt=s.useMemo(()=>`0 0 ${Math.max(y.width,1)} ${Math.max(y.height,1)}`,[y.height,y.width]),ot=typeof se=="boolean",ja=s.useMemo(()=>{const e=It.trim().toLowerCase();return e?Ut.filter(n=>[n.displayName,n.originalFilename,n.imageReferenceLabel,n.taskReferenceLabel,n.assetId].filter(Boolean).join(" ").toLowerCase().includes(e)):Ut},[Ut,It]),Oe=s.useMemo(()=>{const e=Ee.current;return e?P>1||y.width>e.clientWidth+1||y.height>e.clientHeight+1:P>1},[y.height,y.width,P]),Zt=`${Math.round(P*100)}%`,W=Oe&&(mn||fn),Qt=s.useMemo(()=>{const e=new Map;return j.forEach((n,o)=>{e.set(n.id,o+1)}),e},[j]);s.useEffect(()=>{me.current=L},[L]),s.useEffect(()=>{const e=Ia.current;if(!e||!S)return;e.focus();const n=e.value.length;e.setSelectionRange(n,n)},[S]),s.useEffect(()=>{_e.current=v},[v]),s.useEffect(()=>{Ye(!1)},[v]),s.useEffect(()=>{if(!z){pt(!1);return}da(z.color||ct[z.markerType||ce])},[z]);const $t=s.useCallback(async e=>{const n=typeof performance<"u"?performance.now():Date.now(),o=await ge(`/api/taskforce/annotated-attachments/sessions?${Q}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...E},body:JSON.stringify({taskId:e.taskId,baseImageAssetId:e.assetId,title:Ke(e),globalInstruction:"",annotations:[]})},$),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(String(i?.error||"Failed to create session."));const c=i?.session;if(!c?.id)throw new Error("Failed to create session.");return Rt("annotated_session_create_completed",{assetId:e.assetId,taskId:e.taskId||null,sessionId:c.id,durationMs:Math.round((typeof performance<"u"?performance.now():Date.now())-n),debugTimings:i?.debugTimings||null,serverTiming:typeof o.headers?.get=="function"&&o.headers.get("server-timing")||null}),c},[E,$,Q]),Ta=s.useCallback(e=>new Promise((n,o)=>{const i=new FileReader;i.onload=()=>n(typeof i.result=="string"?i.result:""),i.onerror=()=>o(i.error||new Error("Failed to read clipboard image.")),i.readAsDataURL(e)}),[]),N=s.useCallback(()=>{at.current!==null&&(window.clearTimeout(at.current),at.current=null),st.current!==null&&(window.clearTimeout(st.current),st.current=null)},[]),ze=s.useCallback(e=>{Xe(e.title),Ve(e.globalInstruction),re(e.annotations),F(n=>n&&e.annotations.some(o=>o.id===n)?n:e.annotations[0]?.id||null)},[]),pe=s.useCallback((e,n)=>{const o=Ke(n||d||{assetId:e.baseImageAssetId,displayName:"Annotated session"}),i=Ko(e,o),c=qa(i);fe.current=!0,N(),ze(i),A.current=c,H.current=c,Ct.current=null,Ae.current=!1,jt.current=null,nt.current=null,O(null),R("saved"),q(!1)},[d,ze,N]),it=s.useCallback(e=>{fe.current=!0,N(),Te([]),$e(null),xe(!1),Ye(!1),Xe(Ke(e)),Ve(""),re([]),F(null),A.current="",H.current="",Ct.current=null,Ae.current=!1,jt.current=null,nt.current=null,Mt(null),Ft(!1),O(null),R("saved"),q(!1)},[N]),we=s.useCallback(async(e,n,o)=>{const i=_e.current;if(!i)return!0;if(e===A.current)return J.current||(O(null),R("saved")),!0;if(J.current){if(Ae.current=!0,!o?.waitForInFlight||!await J.current)return!1;const m=H.current;return m===A.current?!0:we(m,n,o)}N();const c=Ja(e);jt.current=i,Ct.current=e,q(!0),g(null),O(null),R("saving");const h=(async()=>{try{const u=await ge(`/api/taskforce/annotated-attachments/sessions/${encodeURIComponent(i)}?${Q}`,{method:"PATCH",credentials:"include",headers:{"Content-Type":"application/json",...E},body:JSON.stringify(c)},$),m=await u.json().catch(()=>({}));if(!u.ok)throw new Error(String(m?.error||"Failed to save session."));const _=m?.session;if(!_?.id)throw new Error("Failed to save session.");Te(ta=>{const Da=ta.findIndex(Ln=>Ln.id===_.id);if(Da===-1)return[_,...ta];const Oa=[...ta];return Oa[Da]=_,Oa}),A.current=e,nt.current=null,O(null);const k=_e.current===_.id,C=H.current,X=C!==e,lt=Ae.current||X;return Ae.current=!1,k&&!lt?(fe.current=!0,ze(c),R("saved")):!lt&&C===A.current?R("saved"):R("pending"),!0}catch(u){const m=u instanceof Error?u.message:"Failed to save session.";return g(m),O(m),R("error"),nt.current!==e&&_e.current===i&&H.current===e&&(nt.current=e,st.current=window.setTimeout(()=>{st.current=null,!(_e.current!==i||H.current!==e)&&we(e,n,{waitForInFlight:!0})},1500)),!1}finally{Ct.current=null,J.current=null,jt.current=null,q(!1)}})();J.current=h;const w=await h;if(w){const u=H.current;if(u!==A.current)return we(u,n,o)}return w},[ze,N,E,$,Q]),$a=s.useCallback(e=>{if(_e.current){if(H.current===A.current){O(null),J.current||R("saved");return}K!=="saving"&&R("pending"),N(),at.current=window.setTimeout(()=>{at.current=null,we(H.current,"structure")},e)}},[N,we,K]),Y=s.useCallback(e=>{Xt.current=e},[]),M=s.useCallback(async e=>{N();const n=H.current;return!_e.current||n===A.current?(O(null),J.current||R("saved"),!0):we(n,e,{waitForInFlight:!0})},[N,we]),hn=s.useCallback(()=>{const e=A.current;e&&(N(),fe.current=!0,ze(Ja(e)),O(null),R("saved"),g(null))},[ze,N]),U=s.useCallback(async(e,n)=>{const o=typeof performance<"u"?performance.now():Date.now(),i=JSON.stringify({targetKey:Ge(e),requestedSessionId:n?.requestedSessionId??null,autoCreateIfEmpty:n?.autoCreateIfEmpty===!0});if(Nt.current===i)return;const c=ve.current+1;ve.current=c,Nt.current=i,ua(!0),g(null);try{const h=new URLSearchParams;p&&h.set("workspaceId",p),e.taskId&&h.set("taskId",e.taskId),h.set("imageAssetId",e.assetId);const w=await ge(`/api/taskforce/annotated-attachments/sessions?${h.toString()}`,{credentials:"include",headers:E,cache:"no-store"},$),u=await w.json().catch(()=>({}));if(!w.ok)throw new Error(String(u?.error||"Failed to load annotated attachment sessions."));const m=Array.isArray(u?.sessions)?u.sessions:[];if(Rt("annotated_sessions_loaded",{assetId:e.assetId,taskId:e.taskId||null,requestedSessionId:n?.requestedSessionId??null,autoCreateIfEmpty:n?.autoCreateIfEmpty===!0,sessionCount:m.length,durationMs:Math.round((typeof performance<"u"?performance.now():Date.now())-o),serverTiming:typeof w.headers?.get=="function"&&w.headers.get("server-timing")||null}),m.length===0&&n?.autoCreateIfEmpty&&String(e.assetId||"").trim()){const C=n?.requestedSessionId??me.current;if(me.current=null,C&&g("The previously selected annotation session could not be restored."),ve.current!==c)return;const X=await $t(e);if(Rt("annotated_sessions_auto_created_after_empty_load",{assetId:e.assetId,taskId:e.taskId||null,sessionId:X.id,totalDurationMs:Math.round((typeof performance<"u"?performance.now():Date.now())-o)}),ve.current!==c)return;Te([X]),$e(X.id),xe(!1),pe(X,e);return}if(ve.current!==c)return;Te(m),xe(m.length===0);const _=n?.requestedSessionId??me.current;me.current=null;const k=m.find(C=>C.id===_)||m[0]||null;_&&!k&&g("The previously selected annotation session could not be restored."),$e(k?.id||null),k?pe(k,e):(fe.current=!0,N(),Xe(Ke(e)),Ve(""),re([]),F(null),A.current="",H.current="",O(null),R("saved"))}catch(h){if(ve.current!==c)return;g(h instanceof Error?h.message:"Failed to load sessions.")}finally{Nt.current===i&&(Nt.current=null),ve.current===c&&ua(!1)}},[N,$t,E,$,pe,p]),Ra=s.useCallback(async()=>{ya(!0),xa(null);try{const e=new URLSearchParams;e.set("workspaceId",String(p||"default").trim()||"default");const n=await ge(`/api/taskforce/annotated-attachments/images?${e.toString()}`,{credentials:"include",headers:E,cache:"no-store"},$),o=await n.json().catch(()=>({}));if(!n.ok)throw new Error(String(o?.error||"Failed to load images."));cn(Array.isArray(o?.images)?o.images:[])}catch(e){xa(e instanceof Error?e.message:"Failed to load images.")}finally{ya(!1)}},[E,$,p]),pn=s.useCallback(async()=>{if(typeof navigator>"u"||!navigator.clipboard||typeof navigator.clipboard.read!="function"){g("Clipboard image paste is not supported in this environment.");return}va(!0),g(null),wa.current=Date.now()+2e3;try{const n=(await navigator.clipboard.read()).find(_=>_.types.some(k=>k.startsWith("image/"))),o=n?.types.find(_=>_.startsWith("image/"))||"";if(!n||!o)throw new Error("No image found on the clipboard.");const i=await n.getType(o),c=await Ta(i);if(!c)throw new Error("Failed to read clipboard image.");const h=o==="image/jpeg"?"jpg":o==="image/webp"?"webp":o==="image/gif"?"gif":"png",w=await fetch("/api/taskforce/context-upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...E},body:JSON.stringify({file:c,originalName:`pasted-image.${h}`,workspaceId:String(p||"default").trim()||"default"})}),u=await w.json().catch(()=>({}));if(!w.ok||!u?.success||typeof u?.assetId!="string"||typeof u?.path!="string")throw new Error(String(u?.error||"Failed to paste image into Image Notes."));const m={assetId:u.assetId,imageReferenceLabel:typeof u?.referenceLabel=="string"?u.referenceLabel:void 0,path:u.path,displayName:typeof u?.displayName=="string"&&u.displayName.trim().length>0?u.displayName.trim():"Pasted image"};me.current=null,le?(ie.current="",G?.(m,{sessionId:null})):(be(m),ie.current=Ge(m),U(m,{autoCreateIfEmpty:!0}))}catch(e){g(e instanceof Error?e.message:"Failed to paste image.")}finally{va(!1)}},[le,U,G,Ta,E,p]),gn=s.useCallback(async()=>{const e=zt.trim();if(!e){g("Enter an image reference to open.");return}ga(!0),g(null);try{const n=new URLSearchParams({workspaceId:String(p||"default").trim()||"default"}),o=await ge(`/api/taskforce/annotated-attachments/images/${encodeURIComponent(e)}?${n.toString()}`,{method:"GET",credentials:"include",headers:E}),i=await o.json().catch(()=>({}));if(!o.ok||!i?.target||typeof i.target.assetId!="string"||typeof i.target.path!="string")throw new Error(String(i?.error||"Failed to open image reference."));const c={assetId:i.target.assetId,path:i.target.path,displayName:typeof i.target.displayName=="string"&&i.target.displayName.trim().length>0?i.target.displayName.trim():"Image attachment",taskId:typeof i.target.taskId=="string"&&i.target.taskId.trim().length>0?i.target.taskId.trim():void 0,taskReferenceLabel:typeof i.target.taskReferenceLabel=="string"&&i.target.taskReferenceLabel.trim().length>0?i.target.taskReferenceLabel.trim():void 0,imageReferenceLabel:typeof i.target.imageReferenceLabel=="string"&&i.target.imageReferenceLabel.trim().length>0?i.target.imageReferenceLabel.trim():void 0};me.current=null,vt(!1),_t(""),le?(ie.current="",G?.(c,{sessionId:null})):(be(c),ie.current=Ge(c),U(c,{autoCreateIfEmpty:!0}))}catch(n){g(n instanceof Error?n.message:"Failed to open image reference.")}finally{ga(!1)}},[le,U,G,zt,E,p]),yn=s.useCallback(async e=>{if(!e.assetId||!e.path||!await M("session-switch"))return;const o={assetId:e.assetId,path:e.path,displayName:String(e.displayName||e.originalFilename||"Image attachment").trim()||"Image attachment",...e.taskId?{taskId:e.taskId}:{},...e.taskReferenceLabel?{taskReferenceLabel:e.taskReferenceLabel}:{},...e.imageReferenceLabel?{imageReferenceLabel:e.imageReferenceLabel}:{}};me.current=null,g(null),le?(ie.current="",G?.(o,{sessionId:null})):(be(o),ie.current=Ge(o),it(o),U(o,{autoCreateIfEmpty:!0}))},[M,le,U,G,it]),Pa=s.useCallback(e=>{Te(n=>{const o=n.findIndex(c=>c.id===e.id);if(o===-1)return[e,...n];const i=[...n];return i[o]=e,i}),$e(e.id),pe(e,d)},[d,pe]),Ba=s.useCallback(e=>{Te(n=>{const o=n.filter(c=>c.id!==e),i=o[0]||null;return $e(i?.id||null),i?pe(i,d):(fe.current=!0,N(),Xe(Ke(d||{displayName:"Annotated session"})),Ve(""),re([]),F(null),A.current="",H.current="",O(null),R("saved")),o})},[d,N,pe]);s.useEffect(()=>{if(!x)return;if(le||be(n=>n&&Ge(n)===ee&&n.taskReferenceLabel===x.taskReferenceLabel&&n.imageReferenceLabel===x.imageReferenceLabel&&n.displayName===x.displayName?n:x),!b){ee&&(ee!==ie.current||ne!==St.current)&&ee!==Yt.current&&(it(x),Yt.current=ee,St.current=ne,Rt("annotated_sessions_load_deferred",{assetId:x.assetId,taskId:x.taskId||null,requestedTargetKey:ee})),Ce?.();return}ee&&(ee!==ie.current||ne!==St.current)&&(it(x),ie.current=ee,St.current=ne,Yt.current="",U(x,{autoCreateIfEmpty:!0})),Ce?.()},[le,U,Ce,ne,x,ee,it,L,b]),s.useEffect(()=>{d&&ye?.({target:d,sessionId:v})},[d,ye,v]),s.useEffect(()=>{if(!d||typeof document>"u"||!b)return;const e=()=>{Date.now()<wa.current||H.current!==A.current||V||gt||U(d,{requestedSessionId:v})},n=()=>{document.visibilityState==="visible"&&e()};return document.addEventListener("visibilitychange",n),()=>{document.removeEventListener("visibilitychange",n)}},[d,U,gt,V,v,b]),s.useEffect(()=>{if(!d?.path){Je(!1),Ze(!1),tt({width:0,height:0});return}Je(!0),Ze(!1),tt({width:0,height:0}),Kt(1),Qe(!1),et(!1)},[d?.path]),s.useEffect(()=>{if(!ue)return;const e=Wt.current;!e||!e.complete||e.naturalWidth<=0||e.naturalHeight<=0||(tt({width:e.naturalWidth,height:e.naturalHeight}),Je(!1),Ze(!1))},[d?.path,ue]),s.useEffect(()=>{Oe||(Qe(!1),et(!1))},[Oe]),s.useEffect(()=>{Mt(null)},[v]),s.useEffect(()=>{if(H.current=He,fe.current){fe.current=!1;return}if(!v){N(),O(null),R("saved");return}if(He===A.current){N(),J.current||(O(null),R("saved"));return}const e=Xt.current;if(Xt.current=null,K==="error"&&e===null)return;const n=e??600;if(J.current){Ae.current=!0,R("pending");return}$a(n)},[N,He,K,$a,v]),s.useEffect(()=>{v&&(J.current||He===A.current&&K!=="error"&&K!=="saved"&&(O(null),R("saved")))},[He,K,v]),s.useEffect(()=>{!ot||!se||Ra()},[Ra,se,ot]),s.useEffect(()=>{if(typeof window>"u")return;const e=n=>{H.current!==A.current&&(n.preventDefault(),n.returnValue="")};return window.addEventListener("beforeunload",e),()=>window.removeEventListener("beforeunload",e)},[]),s.useEffect(()=>{if(typeof document>"u")return;const e=()=>{document.visibilityState==="hidden"&&M("visibility-hidden")};return document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[M]),s.useEffect(()=>{if(!ht||typeof document>"u")return;const e=n=>{const o=n.target;o instanceof Node&&(ka.current?.contains(o)||pt(!1))};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[ht]),s.useEffect(()=>{if(!At||typeof document>"u")return;const e=n=>{const o=n.target;o instanceof Node&&(Sa.current?.contains(o)||Ye(!1))};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[At]),s.useEffect(()=>()=>{N()},[N]),s.useEffect(()=>{if(!de)return;const e=window.setTimeout(()=>Lt(!1),2e3);return()=>window.clearTimeout(e)},[de]),s.useEffect(()=>{if(!bt)return;const e=window.setTimeout(()=>Dt(!1),2e3);return()=>window.clearTimeout(e)},[bt]),s.useEffect(()=>{if(!xt)return;const e=window.setTimeout(()=>Ot(!1),2e3);return()=>window.clearTimeout(e)},[xt]);const te=s.useCallback((e,n,o=300)=>{re(i=>ke(i.map(c=>c.id===e?n(c):c))),Y(o)},[Y]),bn=s.useCallback(e=>{z&&(te(z.id,n=>({...n,color:e})),da(e),pt(!1))},[z,te]),Ea=s.useCallback(async()=>{if(!(!d||!await M("session-switch"))){q(!0),g(null);try{const n=await $t(d);xe(!1),await U(d,{requestedSessionId:n.id,autoCreateIfEmpty:!1}),Be("select")}catch(n){g(n instanceof Error?n.message:"Failed to create session."),xe(!0)}finally{q(!1)}}},[d,$t,M,U]),xn=s.useCallback(e=>{if(e!=="select"&&!B){Qe(!1),g("No session exists for this image yet."),xe(!0);return}g(null),xe(!1),Qe(!1),Be(e)},[B]),vn=s.useCallback(async()=>{if(!(!d||!B||!await M("duplicate"))){q(!0),g(null);try{const n=ke(j.map((h,w)=>Lo(h,w))),o=await ge(`/api/taskforce/annotated-attachments/sessions?${Q}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...E},body:JSON.stringify({taskId:d.taskId,baseImageAssetId:d.assetId,title:Fo(Re||B.title,d),globalInstruction:Pe,annotations:n})},$),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(String(i?.error||"Failed to duplicate session."));const c=i?.session;if(!c?.id)throw new Error("Failed to duplicate session.");Pa(c),Be("select")}catch(n){g(n instanceof Error?n.message:"Failed to duplicate session.")}finally{q(!1)}}},[d,j,Pe,Re,Pa,M,E,$,B,Q]),_n=s.useCallback(async()=>M("manual"),[M]),Aa=s.useCallback(async()=>{if(v){fa(!0),g(null);try{const e=await ge(`/api/taskforce/annotated-attachments/sessions/${encodeURIComponent(v)}/payload?${Q}`,{credentials:"include",headers:E},$),n=await e.json().catch(()=>({}));if(!e.ok)throw new Error(String(n?.error||"Failed to load payload preview."));Mt(n?.payload||null)}catch(e){g(e instanceof Error?e.message:"Failed to load payload preview.")}finally{fa(!1)}}},[E,$,v,Q]),In=s.useCallback(()=>{v&&M("payload-preview").then(e=>{e&&(Ft(!0),Aa())})},[M,Aa,v]),Ma=s.useCallback(async e=>{if(!oe||!navigator.clipboard||typeof navigator.clipboard.writeText!="function"){g("Clipboard copy is not available in this browser.");return}try{const n=e==="json"?JSON.stringify(oe,null,2):Va(oe);await navigator.clipboard.writeText(n),Lt(e)}catch(n){g(n instanceof Error?n.message:"Failed to copy payload content."),Lt(!1)}},[oe]),wn=s.useCallback(async()=>{if(!Tt||!navigator.clipboard||typeof navigator.clipboard.writeText!="function"){g("Clipboard copy is not available in this browser.");return}try{await navigator.clipboard.writeText(Tt),Dt(!0)}catch(e){g(e instanceof Error?e.message:"Failed to copy task id."),Dt(!1)}},[Tt]),kn=s.useCallback(async()=>{if(!rt||!navigator.clipboard||typeof navigator.clipboard.writeText!="function"){g("Clipboard copy is not available in this browser.");return}try{await navigator.clipboard.writeText(rt),Ot(!0)}catch(e){g(e instanceof Error?e.message:"Failed to copy image reference."),Ot(!1)}},[rt]),Sn=s.useCallback(async()=>{if(!v||!await M("delete-session"))return;const n=(B?.title||"Untitled session").trim()||"Untitled session";if(window.confirm(`Delete the annotated attachment session "${n}"?`)){q(!0),g(null);try{const o=await ge(`/api/taskforce/annotated-attachments/sessions/${encodeURIComponent(v)}?${Q}`,{method:"DELETE",credentials:"include",headers:E},$),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(String(i?.error||"Failed to delete session."));Ba(v),Be("select")}catch(o){g(o instanceof Error?o.message:"Failed to delete session.")}finally{q(!1)}}},[M,Ba,E,$,B,v,Q]),ea=s.useCallback(()=>{S&&(re(e=>ke(e.filter(n=>n.id!==S))),F(null),Y(300))},[Y,S]),Ue=s.useCallback(e=>{const n=Go(e),o=Ee.current;if(!o||n===P){Kt(n);return}const i=(o.scrollLeft+o.clientWidth/2)*(n/P)-o.clientWidth/2,c=(o.scrollTop+o.clientHeight/2)*(n/P)-o.clientHeight/2;Kt(n),window.requestAnimationFrame(()=>{o.scrollLeft=Math.max(0,i),o.scrollTop=Math.max(0,c)})},[P]),Nn=s.useCallback(()=>{Ue(P+.25)},[Ue,P]),Cn=s.useCallback(()=>{Ue(P-.25)},[Ue,P]),jn=s.useCallback(()=>{Ue(1);const e=Ee.current;e&&window.requestAnimationFrame(()=>{e.scrollLeft=0,e.scrollTop=0})},[Ue]),La=s.useCallback(e=>{S&&re(n=>{const o=n.findIndex(c=>c.id===S);if(o===-1)return n;const i=e==="up"?o-1:o+1;return i<0||i>=n.length?n:(Y(300),Ho(n,o,i))})},[Y,S]);s.useEffect(()=>{if(!S)return;const e=n=>{n.key==="Delete"&&(nn(n.target)||(n.preventDefault(),ea()))};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[ea,S]),s.useEffect(()=>{const e=i=>{i.code==="Space"&&Oe&&(Ro(i.target)||(i.preventDefault(),et(!0)))},n=i=>{i.code==="Space"&&et(!1)},o=()=>{et(!1)};return window.addEventListener("keydown",e),window.addEventListener("keyup",n),window.addEventListener("blur",o),()=>{window.removeEventListener("keydown",e),window.removeEventListener("keyup",n),window.removeEventListener("blur",o)}},[Oe]);const D=s.useCallback(e=>{const n=_a.current?.getBoundingClientRect();return!n||n.width<=0||n.height<=0?null:{x:I((e.clientX-n.left)/n.width),y:I((e.clientY-n.top)/n.height)}},[]),Tn=s.useCallback(e=>{if(W){const i=Ee.current;if(!i)return;Z.current={pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,scrollLeft:i.scrollLeft,scrollTop:i.scrollTop},e.currentTarget.setPointerCapture(e.pointerId),e.preventDefault();return}if(!v)return;if(T==="select"){F(null);return}const n=D(e);if(!n)return;if(T==="pin"||T==="text-note"){const i=Xa(T,n,n,ft);re(c=>ke([...c,i])),F(i.id),Y(300),Be("select");return}Ie.current=n;const o=Xa(T,n,n,ft);he.current={annotationId:o.id,kind:T},e.currentTarget.setPointerCapture?.(e.pointerId),re(i=>ke([...i,o])),F(o.id),Y(300)},[ft,W,Y,D,v,T]),$n=s.useCallback(e=>{if(Z.current?.pointerId===e.pointerId){e.currentTarget.releasePointerCapture?.(e.pointerId);return}if(!Ie.current||!he.current||T!=="box"&&T!=="arrow")return;const n=D(e);Ie.current=null,he.current=null,e.currentTarget.releasePointerCapture?.(e.pointerId),n&&Be("select")},[D,T]),Fa=s.useCallback((e,n)=>{if(T!=="select"||W)return;const o=D(e);o&&(Me.current={annotationId:n.id,originPointer:o,originAnnotation:n},F(n.id),e.stopPropagation())},[W,D,T]),Rn=s.useCallback(e=>{if(Z.current?.pointerId===e.pointerId){const u=Ee.current;if(!u)return;const m=e.clientX-Z.current.startX,_=e.clientY-Z.current.startY;u.scrollLeft=Z.current.scrollLeft-m,u.scrollTop=Z.current.scrollTop-_;return}if(he.current&&Ie.current){const u=D(e);if(!u)return;const{annotationId:m,kind:_}=he.current,k=Ie.current;te(m,C=>_==="box"&&C.kind==="box"?{...C,x:I(Math.min(k.x,u.x)),y:I(Math.min(k.y,u.y)),width:Se(Math.abs(u.x-k.x)),height:Se(Math.abs(u.y-k.y))}:_==="arrow"&&C.kind==="arrow"?{...C,x:k.x,y:k.y,x2:u.x,y2:u.y}:C);return}if(Le.current){const u=D(e);if(!u)return;const{annotationId:m,originPointer:_,originAnnotation:k}=Le.current,C=u.x-_.x,X=u.y-_.y;te(m,()=>({...k,width:Se(k.width+C),height:Se(k.height+X)}));return}if(Fe.current){const u=D(e);if(!u)return;const{annotationId:m,endpoint:_,originPointer:k,originAnnotation:C}=Fe.current,X=u.x-k.x,lt=u.y-k.y;te(m,()=>_==="tail"?{...C,x:I(C.x+X),y:I(C.y+lt)}:{...C,x2:I(C.x2+X),y2:I(C.y2+lt)});return}if(!Me.current)return;const n=D(e);if(!n)return;const{annotationId:o,originPointer:i,originAnnotation:c}=Me.current,h=n.x-i.x,w=n.y-i.y;te(o,()=>c.kind==="pin"||c.kind==="text-note"?{...c,x:I(c.x+h),y:I(c.y+w)}:c.kind==="box"?{...c,x:I(c.x+h),y:I(c.y+w)}:{...c,x:I(c.x+h),y:I(c.y+w),x2:I(c.x2+h),y2:I(c.y2+w)})},[D,te]),Pn=s.useCallback(()=>{Ie.current=null,Me.current=null,Le.current=null,Fe.current=null,he.current=null,Z.current=null},[]),Bn=s.useCallback(()=>{Ie.current=null,Me.current=null,Le.current=null,Fe.current=null,he.current=null,Z.current=null},[]),En=s.useCallback(()=>{Me.current=null,Le.current=null,Fe.current=null,he.current=null,Z.current=null},[]),An=s.useCallback((e,n)=>{if(T!=="select"||W)return;const o=D(e);o&&(Le.current={annotationId:n.id,originPointer:o,originAnnotation:n},F(n.id),e.stopPropagation())},[W,D,T]),Ha=s.useCallback((e,n,o)=>{if(T!=="select"||W)return;const i=D(e);i&&(Fe.current={annotationId:n.id,originPointer:i,originAnnotation:n,endpoint:o},F(n.id),e.stopPropagation())},[W,D,T]),Mn=B?.updatedAt?ra(B.updatedAt):"Not saved yet";return t.jsxs("div",{className:`${a.shell} ${ot?a.shellWithImageTray:""} ${ot&&se?a.shellImageTrayOpen:""}`.trim(),children:[ot?t.jsxs("aside",{className:`${a.imageTrayPanel} ${se?a.imageTrayPanelOpen:""}`.trim(),"aria-label":"Image tray","aria-hidden":!se,children:[t.jsxs("div",{className:a.imageTrayHeader,children:[t.jsxs("span",{className:a.imageTrayTitle,children:[t.jsx(Ua,{size:14}),"Images"]}),t.jsx("button",{type:"button",className:"tf-control-icon",onClick:dt,title:"Collapse image tray","aria-label":"Collapse image tray",children:t.jsx(Dn,{size:16})})]}),t.jsxs("div",{className:a.imageTraySearch,children:[t.jsx(On,{size:12,className:a.imageTraySearchIcon}),t.jsx("input",{type:"text",placeholder:"Search images...",value:It,onChange:e=>dn(e.target.value),className:a.imageTraySearchInput})]}),t.jsx("div",{className:`tf-scrollbar ${a.imageTrayList}`,children:un?t.jsx("div",{className:a.imageTrayState,children:"Loading images..."}):ba?t.jsx("div",{className:a.imageTrayStateError,children:ba}):ja.length===0?t.jsx("div",{className:a.imageTrayState,children:It.trim()?"No images match your search.":"No images found."}):ja.map(e=>{const n=d?.assetId===e.assetId,o=typeof e.attachmentCount=="number"&&Number.isFinite(e.attachmentCount)?Math.max(0,e.attachmentCount):0,i=typeof e.sessionCount=="number"&&Number.isFinite(e.sessionCount)?Math.max(0,e.sessionCount):0,c=o>1?`${o} tasks linked`:o===1?e.taskReferenceLabel||"1 task linked":"Unattached",h=String(e.displayName||e.originalFilename||"Image attachment").trim()||"Image attachment";return t.jsxs("button",{type:"button",className:`${a.imageTrayItem} ${n?a.imageTrayItemActive:""}`.trim(),onClick:()=>{yn(e)},title:h,children:[t.jsx("span",{className:a.imageTrayThumb,children:t.jsx("img",{src:e.path,alt:"",loading:"lazy"})}),t.jsxs("span",{className:a.imageTrayItemBody,children:[t.jsx("span",{className:a.imageTrayItemTitle,children:h}),t.jsx("span",{className:a.imageTrayItemTask,children:c}),t.jsxs("span",{className:a.imageTrayItemMeta,children:[t.jsxs("span",{className:a.imageTrayItemMetaDetails,children:[Po(e.sizeBytes),e.updatedAt?t.jsxs(t.Fragment,{children:[" · ",Bo(e.updatedAt)]}):null,i>0?t.jsxs(t.Fragment,{children:[" · ",i," session",i===1?"":"s"]}):null]}),e.imageReferenceLabel?t.jsx("span",{className:a.imageTrayItemReference,children:e.imageReferenceLabel}):null]})]})]},e.assetId)})})]}):null,t.jsxs("section",{className:`tf-surface-panel ${a.panel} ${a.sessionPanel}`,children:[t.jsx("div",{className:a.sessionContextBar,children:d?.taskId?t.jsxs(t.Fragment,{children:[t.jsx("div",{className:a.sessionContextLeft,children:je?t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.backToTaskBtn}`,onClick:()=>{M("back-to-task").then(e=>{e&&d.taskId&&je(d.taskId)})},"aria-label":"Back to task",title:"Back to task",children:t.jsx(zn,{size:16})}):t.jsx("div",{className:a.sessionContextSpacer,"aria-hidden":"true"})}),t.jsx("div",{className:a.sessionContextRight,children:t.jsx(Hn,{copied:bt,onClick:()=>{wn()},title:"Copy task id",ariaLabel:bt?"Copied task id":"Copy task id",label:Tt})})]}):t.jsxs(t.Fragment,{children:[t.jsx("div",{className:a.sessionContextLeft,children:t.jsx("span",{className:`tf-label-micro ${a.sessionContextLabel}`,children:"Unattached Image"})}),t.jsx("div",{className:a.sessionContextRight,children:t.jsx("div",{className:a.sessionContextSpacer,"aria-hidden":"true"})})]})}),t.jsxs("div",{className:a.panelHeader,children:[t.jsxs("div",{className:a.panelHeaderText,children:[t.jsx("div",{className:`tf-heading-card ${a.panelTitle}`,children:"Sessions"}),d?null:t.jsx("div",{className:"tf-text-secondary",children:"Open an image attachment to begin"})]}),t.jsx("div",{className:a.sessionActions,children:t.jsx("button",{type:"button",className:`tf-control-icon ${a.iconButton}`,onClick:()=>{Ea()},disabled:!d||V,"aria-label":"Create session",title:"Create session",children:t.jsx(Un,{size:16})})})]}),d?gt?t.jsx("div",{className:a.emptyState,children:t.jsx("p",{className:"tf-empty-copy",children:"Loading sessions…"})}):t.jsx("div",{className:`tf-scrollbar ${a.sessionList}`,children:mt.length===0?t.jsxs("div",{className:a.sessionEmptyState,children:[t.jsx("div",{className:`tf-heading-card ${a.sessionTitle}`,children:"No sessions yet"}),t.jsx("div",{className:`tf-text-secondary ${a.annotationSummary}`,children:"Create the first annotation session for this image."})]}):mt.map(e=>{const n=v===e.id,o=n&&At,i=Eo(n?Pe:e.globalInstruction),c=(n?Re:e.title)||"Untitled session";return t.jsxs("div",{className:`tf-surface-elevated ${a.sessionCard} ${n?a.sessionCardActive:""}`,ref:n?Sa:void 0,onBlur:o?h=>{const w=h.relatedTarget;w instanceof Node&&h.currentTarget.contains(w)||Ye(!1)}:void 0,children:[o?t.jsxs("div",{className:a.sessionCardBody,children:[t.jsxs("div",{className:a.sessionMeta,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-session-title",children:"Session title"}),t.jsx("input",{id:"annotated-session-title",className:`tf-field-shell ${a.textInput} ${a.sessionTitleInput}`,value:Re,onChange:h=>{Xe(h.target.value),Y(600)},placeholder:"Session title"}),t.jsx("span",{className:`tf-text-meta ${a.sessionTimestamp}`,children:ra(e.updatedAt)})]}),Bt(e)?t.jsxs("div",{className:`tf-text-secondary ${a.sessionCreator}`,children:["Created by ",Bt(e)]}):null,t.jsxs("div",{className:a.sessionInstructionEditor,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-session-instruction",children:"Session instruction"}),t.jsx("textarea",{id:"annotated-session-instruction",className:`tf-field-shell ${a.textArea} ${a.sessionInstructionField}`,value:Pe,onChange:h=>{Ve(h.target.value),Y(600)},placeholder:"Add overall instructions, context, or framing for this session."})]}),t.jsxs("div",{className:`tf-text-secondary ${a.annotationSummary}`,children:[e.annotations.length," annotation",e.annotations.length===1?"":"s"]})]}):t.jsxs("button",{type:"button",className:a.sessionCardButton,onClick:()=>{if(n){Ye(!0);return}M("session-switch").then(h=>{h&&($e(e.id),pe(e,d))})},"aria-pressed":n,children:[t.jsxs("div",{className:a.sessionMeta,children:[t.jsx("span",{className:`tf-heading-card ${a.sessionTitle}`,children:c}),t.jsx("span",{className:`tf-text-meta ${a.sessionTimestamp}`,children:ra(e.updatedAt)})]}),Bt(e)?t.jsxs("div",{className:`tf-text-secondary ${a.sessionCreator}`,children:["Created by ",Bt(e)]}):null,i?t.jsx("div",{className:`tf-text-secondary ${a.sessionInstructionPreview}`,children:i}):null,t.jsxs("div",{className:`tf-text-secondary ${a.annotationSummary}`,children:[e.annotations.length," annotation",e.annotations.length===1?"":"s"]})]}),n?t.jsx("div",{className:a.sessionCardFooter,children:t.jsxs(t.Fragment,{children:[t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:()=>{vn()},disabled:V,"aria-label":"Duplicate session",title:`Duplicate session "${c}"`,children:t.jsx(sa,{size:16})}),t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:()=>{Sn()},disabled:V,"aria-label":"Delete session",title:`Delete session "${c}"`,children:t.jsx(Ga,{size:16})})]})}):null]},e.id)})}):t.jsxs("div",{className:a.emptyState,children:[t.jsx("strong",{className:"tf-empty-title",children:"No image selected"}),t.jsx("p",{className:"tf-empty-copy",children:"Open an image attachment from a task to start an annotated session."})]})]}),t.jsxs("section",{className:`tf-surface-panel ${a.panel} ${a.canvasPanel}`,children:[t.jsxs("div",{className:a.panelHeader,children:[t.jsxs("div",{className:a.canvasHeading,children:[t.jsx("div",{className:"tf-heading-card",children:d?.displayName||"Annotated attachment"}),t.jsx("div",{className:"tf-text-secondary",children:B?`${j.length} markers · ${Mn}`:"Pick or create a session"})]}),rt?t.jsx(Qn,{copied:xt,onClick:()=>{kn()},title:"Copy image reference",ariaLabel:xt?"Copied image reference":"Copy image reference",label:rt}):null]}),t.jsxs("div",{className:a.toolRail,children:[t.jsxs("div",{className:`${a.toolbarCluster} ${a.toolbarViewportCluster}`,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{_n()},disabled:!B||V||!Ca&&K!=="error","aria-label":V?"Saving session":"Save session",title:V?"Saving session":"Save session",children:t.jsx(Gn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>vt(!0),disabled:qe,"aria-label":"Open image",title:"Open image",children:t.jsx(Ua,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{pn()},disabled:wt,"aria-label":wt?"Pasting image":"Paste image",title:wt?"Pasting image":"Paste image",children:wt?t.jsx(Ka,{size:18,className:za.spin}):t.jsx(Kn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{B&&hn()},disabled:!B||!Ca,"aria-label":"Reset unsaved changes",title:"Reset unsaved changes",children:t.jsx(Wn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:Cn,disabled:!d||ue||P<=.25,"aria-label":"Zoom out",children:t.jsx(Yn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:jn,disabled:!d||ue||P===1,"aria-label":`Reset zoom to 100 percent (currently ${Zt})`,title:`Reset zoom to 100% (currently ${Zt})`,children:t.jsx("span",{children:Zt})}),t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:Nn,disabled:!d||ue||P>=4,"aria-label":"Zoom in",children:t.jsx(Xn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.toolBtn} ${a.toolbarButton} ${W?a.toolBtnActive:""}`,onClick:()=>Qe(e=>!e),disabled:!d||ue||!Oe,"aria-label":"Pan canvas",title:"Pan canvas",children:t.jsx(Vn,{size:18})})]}),t.jsx("span",{className:a.toolbarSeparator,"aria-hidden":"true"}),t.jsxs("div",{className:a.toolbarActions,children:[t.jsx("div",{className:a.toolbarSelectionActions,children:z?t.jsxs(t.Fragment,{children:[t.jsxs("div",{ref:ka,className:a.toolbarColorPicker,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton} ${a.colorPickerButton}`,onClick:()=>pt(e=>!e),"aria-label":"Marker color","aria-expanded":ht,title:"Marker color",children:t.jsx("span",{className:a.colorPickerSwatch,style:{backgroundColor:qt},"aria-hidden":"true"})}),ht?t.jsx("div",{className:a.colorPickerPopover,role:"menu","aria-label":"Marker color options",children:$o.map(e=>t.jsx("button",{type:"button",className:`${a.colorOption} ${qt===e?a.colorOptionActive:""}`,style:{backgroundColor:e},onClick:()=>bn(e),"aria-label":`Use marker color ${e}`,"aria-pressed":qt===e},e))}):null]}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:ea,"aria-label":"Delete marker",title:"Delete selected marker",children:t.jsx(Ga,{size:18})}),t.jsx("div",{className:a.toolbarGeometryFields,"aria-label":"Marker geometry percent controls",children:zo(z).map(e=>t.jsxs("label",{className:a.toolbarGeometryField,children:[t.jsx("span",{className:`tf-text-meta ${a.toolbarGeometryLabel}`,children:e.label}),t.jsx("input",{className:`tf-field-shell ${a.toolbarGeometryInput}`,type:"number",min:0,max:100,step:.1,value:e.value,onChange:n=>{const o=Do(n.target.value);o!==null&&te(z.id,i=>Oo(i,e.key,o))},"aria-label":`${e.label} percent`})]},e.key))})]}):null}),t.jsxs("div",{className:a.toolbarUtilities,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.payloadBtn} ${a.toolbarButton}`,onClick:In,disabled:!B||yt,"aria-label":yt?"Loading payload preview":"Preview payload",title:yt?"Loading payload preview":"Preview payload",children:t.jsx(ia,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>pa(!0),"aria-label":"How to use marker tools",title:"How to use marker tools",children:t.jsx(la,{size:18})})]})]})]}),t.jsxs("div",{className:a.canvasWorkspace,children:[t.jsx("div",{className:a.canvasToolRail,"aria-label":"Annotation tools",children:Ya.map(e=>{const n=e.icon;return t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${T===e.value?a.toolBtnActive:""}`,onClick:()=>xn(e.value),disabled:!d,title:e.label,"aria-label":`${e.label} tool. ${Pt[e.value].short}`,children:t.jsx(n,{size:18})},e.value)})}),t.jsx("div",{className:a.canvasMain,children:t.jsx("div",{ref:Ee,className:`tf-scrollbar ${a.canvasScroller}`,children:d?t.jsxs(t.Fragment,{children:[ue&&!Gt?t.jsx("div",{className:a.canvasStatusOverlay,"aria-live":"polite",children:t.jsxs("div",{className:a.canvasStatusCard,children:[t.jsx(Ka,{size:20,className:za.spinner}),t.jsx("span",{children:"Loading image…"})]})}):null,Gt?t.jsx("div",{className:a.canvasStatusOverlay,"aria-live":"polite",children:t.jsx("div",{className:a.canvasStatusCard,children:t.jsx("span",{children:"Image failed to load."})})}):null,t.jsx("div",{className:a.canvasFrame,children:t.jsxs("div",{className:a.canvasMedia,style:{width:y.width?`${y.width}px`:void 0,height:y.height?`${y.height}px`:void 0},children:[t.jsx("img",{ref:Wt,src:d.path,alt:d.displayName,className:a.canvasImage,onLoad:()=>{const e=Wt.current;tt({width:e?.naturalWidth||0,height:e?.naturalHeight||0}),Je(!1),Ze(!1)},onError:()=>{tt({width:0,height:0}),Je(!1),Ze(!0)}}),!ue&&!Gt&&B?t.jsxs("div",{ref:_a,className:`${a.overlay} ${T==="select"?a.overlaySelect:""} ${W?a.overlayPan:""}`,onPointerDown:Tn,onPointerMove:Rn,onPointerUp:e=>{$n(e),En()},"data-testid":"annotated-attachment-overlay",onPointerLeave:Pn,onPointerCancel:Bn,children:[t.jsx("svg",{className:a.overlaySvg,viewBox:Jt,preserveAspectRatio:"none","aria-hidden":"true",children:j.filter(e=>e.kind==="arrow").map(e=>{const n=Ao(e,y),o=oa(e),i=S===e.id;return t.jsxs(aa.Fragment,{children:[i?t.jsxs(t.Fragment,{children:[t.jsx("line",{x1:n.shaftX1,y1:n.shaftY1,x2:n.shaftX2,y2:n.shaftY2,stroke:"color-mix(in srgb, var(--surface-elevated) 92%, transparent)",strokeWidth:14,strokeLinecap:"round"}),t.jsx("polygon",{points:n.headPoints,fill:o,stroke:"color-mix(in srgb, var(--surface-elevated) 92%, transparent)",strokeWidth:4,strokeLinejoin:"round"})]}):null,t.jsx("line",{x1:n.shaftX1,y1:n.shaftY1,x2:n.shaftX2,y2:n.shaftY2,stroke:o,strokeWidth:i?10:6,strokeLinecap:"round"}),t.jsx("polygon",{points:n.headPoints,fill:o})]},e.id)})}),t.jsx("svg",{className:a.overlayHitLayer,viewBox:Jt,preserveAspectRatio:"none",children:j.filter(e=>e.kind==="arrow").map(e=>t.jsxs(aa.Fragment,{children:[t.jsx("line",{x1:e.x*y.width,y1:e.y*y.height,x2:e.x2*y.width,y2:e.y2*y.height,className:a.arrowHitArea,"data-testid":`annotated-arrow-hit-${e.id}`,"aria-label":`Arrow marker ${Qt.get(e.id)||0}`,onPointerDown:n=>Fa(n,e),onClick:n=>{n.stopPropagation(),F(e.id)}}),S===e.id?t.jsxs(t.Fragment,{children:[t.jsx("circle",{cx:e.x*y.width,cy:e.y*y.height,r:De.hitRadius,className:a.canvasHandleHit,role:"button",tabIndex:0,"aria-label":"Move arrow tail",onPointerDown:n=>Ha(n,e,"tail")}),t.jsx("circle",{cx:e.x*y.width,cy:e.y*y.height,r:De.visibleRadius,className:a.canvasHandleVisible,"aria-hidden":"true"}),t.jsx("circle",{cx:e.x2*y.width,cy:e.y2*y.height,r:De.hitRadius,className:a.canvasHandleHit,role:"button",tabIndex:0,"aria-label":"Move arrow tip",onPointerDown:n=>Ha(n,e,"tip")}),t.jsx("circle",{cx:e.x2*y.width,cy:e.y2*y.height,r:De.visibleRadius,className:a.canvasHandleVisible,"aria-hidden":"true"})]}):null]},`hit-${e.id}`))}),j.filter(e=>e.kind==="arrow").map(e=>t.jsx("div",{className:`${a.annotationNumberBadge} ${a.arrowNumberBadge}`,style:{left:`${(e.x+e.x2)/2*100}%`,top:`${(e.y+e.y2)/2*100}%`,backgroundColor:oa(e)},"aria-hidden":"true",children:Qt.get(e.id)||0},`arrow-number-${e.id}`)),j.filter(e=>e.kind!=="arrow").map(e=>{const n=oa(e),o=Qt.get(e.id)||0,i={onPointerDown:c=>Fa(c,e),onClick:c=>{c.stopPropagation(),F(e.id)}};return e.kind==="pin"?t.jsx("button",{type:"button",...i,className:`${a.pin} ${S===e.id?a.selected:""}`,style:{left:`${e.x*100}%`,top:`${e.y*100}%`,backgroundColor:n},children:o},e.id):e.kind==="text-note"?t.jsx("button",{type:"button",...i,className:`${a.note} ${S===e.id?a.selected:""}`,style:{left:`${e.x*100}%`,top:`${e.y*100}%`,backgroundColor:n},children:o},e.id):t.jsxs("div",{className:`${a.box} ${S===e.id?a.selected:""}`,style:{left:`${e.x*100}%`,top:`${e.y*100}%`,width:`${e.width*100}%`,height:`${e.height*100}%`,borderColor:n},children:[t.jsx("span",{className:`${a.annotationNumberBadge} ${a.boxNumberBadge}`,style:{backgroundColor:n},"aria-hidden":"true",children:o}),t.jsx("button",{type:"button",...i,className:a.boxSurface,"aria-label":`Box marker ${o}`})]},e.id)}),t.jsx("svg",{className:a.overlaySvg,viewBox:Jt,preserveAspectRatio:"none",children:j.filter(e=>e.kind==="box"&&S===e.id).map(e=>t.jsxs(aa.Fragment,{children:[t.jsx("circle",{cx:(e.x+e.width)*y.width,cy:(e.y+e.height)*y.height,r:De.hitRadius,className:`${a.canvasHandleHit} ${a.canvasResizeHandleHit}`,role:"button",tabIndex:0,"aria-label":"Resize box marker",onPointerDown:n=>An(n,e)}),t.jsx("circle",{cx:(e.x+e.width)*y.width,cy:(e.y+e.height)*y.height,r:De.visibleRadius,className:a.canvasHandleVisible,"aria-hidden":"true"})]},`box-handle-${e.id}`))})]}):null]})})]}):t.jsx("div",{className:a.emptyState,children:t.jsx("p",{className:"tf-empty-copy",children:"Select an image attachment to annotate."})})})})]}),t.jsxs("div",{className:a.statusBar,children:[t.jsx("span",{children:K==="error"?"Save failed. Retry now.":K==="saving"||K==="pending"?"Saving…":"Saved"}),ma?t.jsx("span",{children:ma}):t.jsx("span",{children:B?W?"Drag on the image to pan.":T==="select"?"Select a marker to edit it.":`Click on the image to place a ${T}.`:"Create a session to begin placing markers on this image."}),d&&!B&&sn?t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{Ea()},disabled:V||gt,children:V?"Creating…":"Create one now"}):null]})]}),t.jsx("section",{className:`tf-surface-panel ${a.panel} ${a.detailPanel}`,children:B?t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:a.panelHeader,children:[t.jsxs("div",{className:a.panelHeaderText,children:[t.jsx("div",{className:`tf-heading-card ${a.panelTitle}`,children:"Markers"}),t.jsxs("div",{className:"tf-text-secondary",children:[j.length," in this session"]})]}),t.jsxs("div",{className:a.sessionActions,children:[t.jsx("button",{type:"button",className:`tf-control-icon ${a.iconButton}`,onClick:()=>La("up"),disabled:!z||Vt<=0,"aria-label":"Move marker up",children:t.jsx(Jn,{size:16})}),t.jsx("button",{type:"button",className:`tf-control-icon ${a.iconButton}`,onClick:()=>La("down"),disabled:!z||Vt===-1||Vt>=j.length-1,"aria-label":"Move marker down",children:t.jsx(Zn,{size:16})})]})]}),t.jsx("div",{className:`tf-scrollbar ${a.annotationList}`,children:j.length===0?t.jsx("div",{className:a.detailEmpty,children:t.jsx("p",{className:"tf-empty-copy",children:"Add a marker on the image to begin."})}):j.map((e,n)=>{const o=Co[e.kind],i=jo[e.kind],c=`${i} ${n+1}`,h=To[e.markerType||ce],w=Wa.find(m=>m.value===(e.markerType||ce))?.label||"Review",u=S===e.id;return t.jsxs("div",{className:`tf-surface-elevated ${a.annotationCard} ${u?a.annotationCardActive:""}`,children:[t.jsx("button",{type:"button",className:a.annotationCardButton,onClick:()=>F(e.id),"aria-label":i,children:t.jsxs("div",{className:a.annotationMeta,children:[t.jsx("span",{className:`tf-heading-card ${a.annotationTitle}`,children:c}),t.jsx("span",{className:`tf-text-meta ${a.annotationKind}`,"aria-hidden":"true",children:t.jsx(o,{size:16})})]})}),u?t.jsxs("div",{className:a.annotationInstructionEditor,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-marker-instruction",children:"Marker instruction"}),t.jsx("textarea",{id:"annotated-marker-instruction",ref:u?Ia:null,className:`tf-field-shell ${a.textArea} ${a.annotationInstructionField}`,value:e.instruction,onChange:m=>{te(e.id,_=>({..._,instruction:m.target.value}),600)},onBlur:()=>{M("text")},placeholder:"What should the AI focus on for this marker?"}),t.jsxs("div",{className:a.annotationTypeField,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-marker-type",children:"Instruction type"}),t.jsx("select",{id:"annotated-marker-type",className:`tf-field-shell ${a.select}`,value:e.markerType||ce,onChange:m=>{te(e.id,_=>Mo(_,m.target.value))},children:Wa.map(m=>t.jsx("option",{value:m.value,children:m.label},m.value))})]})]}):t.jsx("button",{type:"button",className:a.annotationInstructionButton,onClick:()=>F(e.id),"aria-label":`Edit ${i} instruction`,children:t.jsxs("div",{className:a.annotationInstructionEditor,children:[t.jsx("div",{className:`tf-text-secondary ${a.annotationInstructionPreview}`,children:e.instruction.trim()||"No marker instruction yet."}),t.jsx("div",{className:a.annotationPreviewFooter,children:t.jsx("span",{className:`tf-text-meta ${a.annotationInstructionTypeIcon}`,"aria-label":`Instruction type: ${w}`,title:w,children:t.jsx(h,{size:16})})})]})})]},e.id)})})]}):t.jsxs("div",{className:a.emptyState,children:[t.jsx("strong",{className:"tf-empty-title",children:"No active session"}),t.jsx("p",{className:"tf-empty-copy",children:"Create or select a session to edit annotations."})]})}),t.jsx(na,{isOpen:ln,onClose:()=>{qe||(vt(!1),_t(""))},title:"Open Image",size:"sm",children:t.jsxs("form",{className:a.openImageModalBody,onSubmit:e=>{e.preventDefault(),gn()},children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-open-image-reference",children:"Image reference number"}),t.jsx("input",{id:"annotated-open-image-reference",className:`tf-field-shell ${a.textInput} ${a.openImageField}`,value:zt,onChange:e=>_t(e.target.value),placeholder:"I-24",autoFocus:!0}),t.jsxs("div",{className:a.openImageActions,children:[t.jsx("button",{type:"button",className:"tf-button-ghost tf-button-compact",onClick:()=>{vt(!1),_t("")},disabled:qe,children:"Cancel"}),t.jsx("button",{type:"submit",className:"tf-button-primary tf-button-compact",disabled:qe,children:qe?"Opening…":"Open"})]})]})}),t.jsx(na,{isOpen:on,onClose:()=>pa(!1),title:"How To Use Markers",size:"md",children:t.jsx("div",{className:a.markerHelpModalBody,children:Ya.filter(e=>e.value!=="select").map(e=>t.jsxs("div",{className:`tf-surface-inset ${a.markerHelpItem}`,children:[t.jsxs("div",{className:a.markerHelpHeader,children:[t.jsx("strong",{className:"tf-heading-card",children:e.label}),t.jsx("span",{className:"tf-text-meta",children:Pt[e.value].short})]}),t.jsx("p",{className:"tf-text-secondary",children:Pt[e.value].detail}),t.jsx("p",{className:`tf-text-body ${a.markerHelpExample}`,children:Pt[e.value].example})]},e.value))})}),t.jsx(na,{isOpen:rn,onClose:()=>Ft(!1),title:"AI Payload",size:"lg",children:t.jsxs("div",{className:a.payloadModalBody,children:[t.jsxs("div",{className:a.payloadModalToolbar,children:[t.jsxs("div",{className:a.payloadViewToggle,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.toolBtn} ${Ht==="json"?a.toolBtnActive:""}`,onClick:()=>ha("json"),children:"JSON"}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.toolBtn} ${Ht==="brief"?a.toolBtnActive:""}`,onClick:()=>ha("brief"),children:"AI Brief"})]}),t.jsxs("div",{className:a.payloadModalActions,children:[t.jsxs("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn}`,onClick:()=>{Ma("json")},disabled:!oe,"aria-label":de==="json"?"Copied JSON":"Copy JSON",title:de==="json"?"Copied JSON":"Copy JSON",children:[de==="json"?t.jsx(ca,{size:16}):t.jsx(sa,{size:16}),t.jsx("span",{children:"JSON"})]}),t.jsxs("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn}`,onClick:()=>{Ma("brief")},disabled:!oe,"aria-label":de==="brief"?"Copied AI Brief":"Copy AI Brief",title:de==="brief"?"Copied AI Brief":"Copy AI Brief",children:[de==="brief"?t.jsx(ca,{size:16}):t.jsx(sa,{size:16}),t.jsx("span",{children:"AI Brief"})]})]})]}),yt?t.jsx("div",{className:a.detailEmpty,children:t.jsx("p",{className:"tf-empty-copy",children:"Loading payload…"})}):oe?t.jsx("pre",{className:`tf-surface-inset tf-scrollbar ${a.payloadModalPreview}`,children:Ht==="json"?JSON.stringify(oe,null,2):Va(oe)}):t.jsx("div",{className:a.detailEmpty,children:t.jsx("p",{className:"tf-empty-copy",children:"Load a payload preview to inspect the current session contract."})})]})})]})}export{Qo as AnnotatedAttachmentWorkspaceShell};