@iblai/iblai-js 2.7.4 → 2.7.6

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.
@@ -55,15 +55,17 @@ export declare function addSkillToAgent(page: Page, skillName: string): Promise<
55
55
  */
56
56
  export declare function verifySkillAdded(page: Page, skillName: string): Promise<void>;
57
57
  /**
58
- * Open the three-dots actions menu for a skill row on the active sub-tab.
59
- * Agent-tab rows offer "Remove from Agent" only; catalog rows offer
60
- * Edit/Delete (for editable skills). The menu content portals to
61
- * document.body, so the returned locator is page-level by design.
58
+ * Open the three-dots actions menu for a CATALOG skill row (Edit/Delete on
59
+ * editable skills). Agent-tab rows have no menu detaching is a direct
60
+ * "Remove" button there (see `removeSkillFromAgent`). The menu content
61
+ * portals to document.body, so the returned locator is page-level by design.
62
62
  */
63
63
  export declare function openSkillActionsMenu(page: Page, skillName: string): Promise<Locator>;
64
64
  /**
65
- * Detach a skill from the agent via its row menu ("Remove from Agent") on the
66
- * "Agent Skills" sub-tab. Waits for the toast and for the row to disappear.
65
+ * Detach a skill from the agent via its row's direct "Remove" button on the
66
+ * "Agent Skills" sub-tab (the visible text is just "Remove"; the button's
67
+ * accessible name carries the skill, mirroring the catalog's Add button).
68
+ * Waits for the toast confirming the detach.
67
69
  */
68
70
  export declare function removeSkillFromAgent(page: Page, skillName: string): Promise<void>;
69
71
  /**
@@ -55,15 +55,17 @@ export declare function addSkillToAgent(page: Page, skillName: string): Promise<
55
55
  */
56
56
  export declare function verifySkillAdded(page: Page, skillName: string): Promise<void>;
57
57
  /**
58
- * Open the three-dots actions menu for a skill row on the active sub-tab.
59
- * Agent-tab rows offer "Remove from Agent" only; catalog rows offer
60
- * Edit/Delete (for editable skills). The menu content portals to
61
- * document.body, so the returned locator is page-level by design.
58
+ * Open the three-dots actions menu for a CATALOG skill row (Edit/Delete on
59
+ * editable skills). Agent-tab rows have no menu detaching is a direct
60
+ * "Remove" button there (see `removeSkillFromAgent`). The menu content
61
+ * portals to document.body, so the returned locator is page-level by design.
62
62
  */
63
63
  export declare function openSkillActionsMenu(page: Page, skillName: string): Promise<Locator>;
64
64
  /**
65
- * Detach a skill from the agent via its row menu ("Remove from Agent") on the
66
- * "Agent Skills" sub-tab. Waits for the toast and for the row to disappear.
65
+ * Detach a skill from the agent via its row's direct "Remove" button on the
66
+ * "Agent Skills" sub-tab (the visible text is just "Remove"; the button's
67
+ * accessible name carries the skill, mirroring the catalog's Add button).
68
+ * Waits for the toast confirming the detach.
67
69
  */
68
70
  export declare function removeSkillFromAgent(page: Page, skillName: string): Promise<void>;
69
71
  /**
@@ -55,15 +55,17 @@ export declare function addSkillToAgent(page: Page, skillName: string): Promise<
55
55
  */
56
56
  export declare function verifySkillAdded(page: Page, skillName: string): Promise<void>;
57
57
  /**
58
- * Open the three-dots actions menu for a skill row on the active sub-tab.
59
- * Agent-tab rows offer "Remove from Agent" only; catalog rows offer
60
- * Edit/Delete (for editable skills). The menu content portals to
61
- * document.body, so the returned locator is page-level by design.
58
+ * Open the three-dots actions menu for a CATALOG skill row (Edit/Delete on
59
+ * editable skills). Agent-tab rows have no menu detaching is a direct
60
+ * "Remove" button there (see `removeSkillFromAgent`). The menu content
61
+ * portals to document.body, so the returned locator is page-level by design.
62
62
  */
63
63
  export declare function openSkillActionsMenu(page: Page, skillName: string): Promise<Locator>;
64
64
  /**
65
- * Detach a skill from the agent via its row menu ("Remove from Agent") on the
66
- * "Agent Skills" sub-tab. Waits for the toast and for the row to disappear.
65
+ * Detach a skill from the agent via its row's direct "Remove" button on the
66
+ * "Agent Skills" sub-tab (the visible text is just "Remove"; the button's
67
+ * accessible name carries the skill, mirroring the catalog's Add button).
68
+ * Waits for the toast confirming the detach.
67
69
  */
68
70
  export declare function removeSkillFromAgent(page: Page, skillName: string): Promise<void>;
69
71
  /**
@@ -3041,7 +3041,8 @@ var clawSandboxAgentSkills$3 = {
3041
3041
  noEffectiveSkills: "No skills enabled for this agent yet. Add one from the Available Skills tab.",
3042
3042
  addToAgent: "Add",
3043
3043
  addToAgentLabel: "Add {name} to this agent",
3044
- removeFromAgent: "Remove from Agent",
3044
+ removeFromAgent: "Remove",
3045
+ removeFromAgentLabel: "Remove {name} from this agent",
3045
3046
  skillAdded: "{name} added",
3046
3047
  skillRemoved: "{name} removed",
3047
3048
  featuredBadge: "Featured",
@@ -10204,7 +10205,8 @@ var clawSandboxAgentSkills$2 = {
10204
10205
  noEffectiveSkills: "Cet agent n'a pas encore de compétences activées. Ajoutez-en une depuis l'onglet Compétences disponibles.",
10205
10206
  addToAgent: "Ajouter",
10206
10207
  addToAgentLabel: "Ajouter {name} à cet agent",
10207
- removeFromAgent: "Retirer de l'agent",
10208
+ removeFromAgent: "Retirer",
10209
+ removeFromAgentLabel: "Retirer {name} de cet agent",
10208
10210
  skillAdded: "{name} ajoutée",
10209
10211
  skillRemoved: "{name} retirée",
10210
10212
  featuredBadge: "En vedette",
@@ -17201,7 +17203,8 @@ var clawSandboxAgentSkills$1 = {
17201
17203
  noEffectiveSkills: "Este agente aún no tiene habilidades habilitadas. Añade una desde la pestaña Habilidades disponibles.",
17202
17204
  addToAgent: "Añadir",
17203
17205
  addToAgentLabel: "Añadir {name} a este agente",
17204
- removeFromAgent: "Quitar del agente",
17206
+ removeFromAgent: "Quitar",
17207
+ removeFromAgentLabel: "Quitar {name} de este agente",
17205
17208
  skillAdded: "{name} añadida",
17206
17209
  skillRemoved: "{name} eliminada",
17207
17210
  featuredBadge: "Destacada",
@@ -24198,7 +24201,8 @@ var clawSandboxAgentSkills = {
24198
24201
  noEffectiveSkills: "此智能体尚未启用任何技能。请从“可用技能”标签页添加。",
24199
24202
  addToAgent: "添加",
24200
24203
  addToAgentLabel: "将 {name} 添加到此智能体",
24201
- removeFromAgent: "从智能体中移除",
24204
+ removeFromAgent: "移除",
24205
+ removeFromAgentLabel: "将 {name} 从此智能体中移除",
24202
24206
  skillAdded: "已添加 {name}",
24203
24207
  skillRemoved: "已移除 {name}",
24204
24208
  featuredBadge: "精选",
@@ -236140,12 +236144,31 @@ const EMPTY_SKILL_FORM = {
236140
236144
  };
236141
236145
  /** Page size for both skill lists. */
236142
236146
  const SKILLS_PAGE_SIZE = 10;
236143
- function AgentSkills({ platformKey, mentorUniqueId }) {
236147
+ function AgentSkills({ platformKey, mentorUniqueId, mentorDbId }) {
236144
236148
  var _a, _b, _c, _d, _e, _f;
236145
236149
  const t = useT();
236146
236150
  // Skills are managed independently of the sandbox connection — org-level
236147
236151
  // skills and the mentor's assignments both resolve without a wired Claw
236148
236152
  // instance, so we always fetch and let admins add/assign skills freely.
236153
+ // Assignment reads/writes are RBAC-gated when the host passes `mentorDbId`:
236154
+ // each action needs its grant from the mentor's permission check (the
236155
+ // endpoints 403 without it). Without a `mentorDbId` there is nothing to
236156
+ // check against, so the gates fail open — previous behavior.
236157
+ const rbacPermissions = useSelector(selectRbacPermissions);
236158
+ const mentorRbacKey = mentorDbId != null ? `/mentors/${mentorDbId}/` : null;
236159
+ const hasMentorRbacData = mentorRbacKey ? mentorRbacKey in rbacPermissions : false;
236160
+ const hasAssignmentGrant = (permission) => mentorRbacKey
236161
+ ? hasMentorRbacData && checkRbacPermission(rbacPermissions, `${mentorRbacKey}#${permission}`)
236162
+ : true;
236163
+ const canViewAssignments = hasAssignmentGrant('view_skill_assignments');
236164
+ const canCreateAssignment = hasAssignmentGrant('create_skill_assignment');
236165
+ const canWriteAssignment = hasAssignmentGrant('write_skill_assignment');
236166
+ const canDeleteAssignment = hasAssignmentGrant('delete_skill_assignment');
236167
+ // The Available Skills catalog is a platform-level resource without its own
236168
+ // mentor-scoped grant; its only purpose here is attaching skills, so the
236169
+ // whole tab (fetch included — it can 403 too) plus skill authoring rides on
236170
+ // `create_skill_assignment` until the backend exposes catalog grants.
236171
+ const canBrowseCatalog = canCreateAssignment;
236149
236172
  // The "Agent Skills" tab pages the assignment list server-side.
236150
236173
  const [agentPage, setAgentPage] = useState(1);
236151
236174
  const { data: assignmentsPage, isLoading: isLoadingAssignments } = useGetMentorSkillAssignmentsQuery({
@@ -236153,7 +236176,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
236153
236176
  mentorUniqueId,
236154
236177
  limit: SKILLS_PAGE_SIZE,
236155
236178
  offset: (agentPage - 1) * SKILLS_PAGE_SIZE,
236156
- });
236179
+ }, { skip: !canViewAssignments });
236157
236180
  const agentAssignments = (_a = assignmentsPage === null || assignmentsPage === void 0 ? void 0 : assignmentsPage.results) !== null && _a !== void 0 ? _a : [];
236158
236181
  const agentTotalCount = (_b = assignmentsPage === null || assignmentsPage === void 0 ? void 0 : assignmentsPage.count) !== null && _b !== void 0 ? _b : 0;
236159
236182
  const agentTotalPages = Math.max(1, Math.ceil(agentTotalCount / SKILLS_PAGE_SIZE));
@@ -236167,7 +236190,9 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
236167
236190
  const { data: assignmentCoverage } = useGetMentorSkillAssignmentsQuery({
236168
236191
  org: platformKey,
236169
236192
  mentorUniqueId,
236170
- });
236193
+ },
236194
+ // Only powers the catalog tab's "Added" chips — pointless without it.
236195
+ { skip: !canViewAssignments || !canBrowseCatalog });
236171
236196
  const assignedSkillIds = new Set(((_c = assignmentCoverage === null || assignmentCoverage === void 0 ? void 0 : assignmentCoverage.results) !== null && _c !== void 0 ? _c : []).map((a) => a.skill));
236172
236197
  // The "Available skills" tab pages the catalog server-side. Deliberately
236173
236198
  // unfiltered: disabled skills stay listed (switch off) so admins can
@@ -236177,7 +236202,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
236177
236202
  org: platformKey,
236178
236203
  limit: SKILLS_PAGE_SIZE,
236179
236204
  offset: (catalogPage - 1) * SKILLS_PAGE_SIZE,
236180
- });
236205
+ }, { skip: !canBrowseCatalog });
236181
236206
  const catalogSkills = (_d = catalogSkillsPage === null || catalogSkillsPage === void 0 ? void 0 : catalogSkillsPage.results) !== null && _d !== void 0 ? _d : [];
236182
236207
  const catalogTotalCount = (_e = catalogSkillsPage === null || catalogSkillsPage === void 0 ? void 0 : catalogSkillsPage.count) !== null && _e !== void 0 ? _e : 0;
236183
236208
  const catalogTotalPages = Math.max(1, Math.ceil(catalogTotalCount / SKILLS_PAGE_SIZE));
@@ -236308,7 +236333,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
236308
236333
  }).unwrap();
236309
236334
  // A private skill only takes effect once assigned, and the Agent Skills
236310
236335
  // tab lists assignments — so attach it to this agent right away.
236311
- if (form.privateToAgent && (created === null || created === void 0 ? void 0 : created.unique_id)) {
236336
+ if (form.privateToAgent && (created === null || created === void 0 ? void 0 : created.unique_id) && canCreateAssignment) {
236312
236337
  await createAssignment({
236313
236338
  org: platformKey,
236314
236339
  mentorUniqueId,
@@ -236348,7 +236373,10 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
236348
236373
  }).unwrap();
236349
236374
  // Making a skill private to this agent implies it should be usable by
236350
236375
  // it — attach it if it isn't assigned yet.
236351
- if (!privateLocked && form.privateToAgent && !assignedSkillIds.has(editingSkill.unique_id)) {
236376
+ if (!privateLocked &&
236377
+ form.privateToAgent &&
236378
+ canCreateAssignment &&
236379
+ !assignedSkillIds.has(editingSkill.unique_id)) {
236352
236380
  await createAssignment({
236353
236381
  org: platformKey,
236354
236382
  mentorUniqueId,
@@ -236376,17 +236404,21 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
236376
236404
  }
236377
236405
  };
236378
236406
  const renderBadges = (skill) => (jsxs("span", { className: "flex flex-wrap items-center gap-1", children: [skill.category && (jsx("span", { className: "rounded-full bg-gray-100 px-2 py-0.5 text-[0.625rem] text-gray-500", children: skill.category })), skill.skill_type === 'native' && (jsx("span", { className: "rounded-full bg-purple-50 px-2 py-0.5 text-[0.625rem] text-purple-600", children: t('clawSandboxAgentSkills.nativeBadge') })), skill.is_featured && (jsx("span", { className: "rounded-full bg-amber-50 px-2 py-0.5 text-[0.625rem] text-amber-600", children: t('clawSandboxAgentSkills.featuredBadge') })), skill.mentor === mentorUniqueId && (jsx("span", { className: "rounded-full bg-blue-50 px-2 py-0.5 text-[0.625rem] text-blue-600", children: t('clawSandboxAgentSkills.privateBadge') }))] }));
236379
- // Agent-tab rows are assignments: their only row action is detaching.
236380
- const renderAssignmentMenu = (assignment) => (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', { name: assignment.skill_name }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsx(DropdownMenuContent, { align: "end", children: jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => handleDetach(assignment), children: [jsx(CircleMinus$1, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.removeFromAgent')] }) })] }));
236407
+ // Agent-tab rows are assignments: detaching is their only action, so it's
236408
+ // a direct button (mirroring the catalog's "Add to Agent") rather than a
236409
+ // one-item three-dots menu — hidden entirely without the delete grant.
236410
+ const renderAssignmentRemoveButton = (assignment) => !canDeleteAssignment ? null : (jsxs(Button$1, { variant: "outline", size: "sm", className: "cursor-pointer", disabled: isMutatingAgentSkill, onClick: () => handleDetach(assignment), "aria-label": t('clawSandboxAgentSkills.removeFromAgentLabel', {
236411
+ name: assignment.skill_name,
236412
+ }), children: [jsx(CircleMinus$1, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.removeFromAgent')] }));
236381
236413
  // Catalog rows carry the full skill object: edit/delete where allowed.
236382
236414
  const renderSkillMenu = (skill) => {
236383
236415
  if (!isSkillEditable(skill))
236384
236416
  return null;
236385
236417
  return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', { name: skill.name }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => openEditSkillDialog(skill), children: [jsx(Pen, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.edit')] }), jsxs(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", onClick: () => setDeletingSkill(skill), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.delete')] })] })] }));
236386
236418
  };
236387
- return (jsxs("div", { className: "space-y-4", "data-testid": "agent-skills-content", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsxs("p", { className: "flex items-start gap-2 text-xs text-gray-500", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 shrink-0 text-gray-400" }), jsx("span", { children: t('clawSandboxAgentSkills.sessionNote') })] }), jsxs(Button$1, { onClick: openNewSkillDialog, size: "sm", className: "shrink-0 cursor-pointer bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.newSkill')] })] }), jsxs(Tabs, { defaultValue: "agent", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.tabsAriaLabel'), "data-testid": "agent-skills-tabs", children: [jsx(TabsTrigger, { value: "agent", "data-testid": "agent-skills-tab-agent", children: t('clawSandboxAgentSkills.tabAgentSkills') }), jsx(TabsTrigger, { value: "available", "data-testid": "agent-skills-tab-available", children: t('clawSandboxAgentSkills.tabAvailableSkills') })] }), jsx(TabsContent, { value: "agent", className: "space-y-3", children: isLoadingAssignments ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : agentTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noEffectiveSkills') }) })) : (jsxs(Fragment$1, { children: [agentAssignments.map((assignment) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "agent-skill-row", children: [jsx("div", { className: "min-w-0 space-y-1", children: jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: assignment.skill_name }), assignment.skill_slug && (jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["/", assignment.skill_slug] }))] }) }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [jsx(Switch, { checked: assignment.enabled, onCheckedChange: (checked) => handleToggleAssignment(assignment, checked), disabled: isMutatingAgentSkill, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(assignment.enabled
236419
+ return (jsxs("div", { className: "space-y-4", "data-testid": "agent-skills-content", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsxs("p", { className: "flex items-start gap-2 text-xs text-gray-500", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 shrink-0 text-gray-400" }), jsx("span", { children: t('clawSandboxAgentSkills.sessionNote') })] }), canBrowseCatalog && (jsxs(Button$1, { onClick: openNewSkillDialog, size: "sm", className: "shrink-0 cursor-pointer bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.newSkill')] }))] }), jsxs(Tabs, { defaultValue: "agent", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.tabsAriaLabel'), "data-testid": "agent-skills-tabs", children: [jsx(TabsTrigger, { value: "agent", "data-testid": "agent-skills-tab-agent", children: t('clawSandboxAgentSkills.tabAgentSkills') }), canBrowseCatalog && (jsx(TabsTrigger, { value: "available", "data-testid": "agent-skills-tab-available", children: t('clawSandboxAgentSkills.tabAvailableSkills') }))] }), jsx(TabsContent, { value: "agent", className: "space-y-3", children: isLoadingAssignments ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : agentTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noEffectiveSkills') }) })) : (jsxs(Fragment$1, { children: [agentAssignments.map((assignment) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "agent-skill-row", children: [jsx("div", { className: "min-w-0 space-y-1", children: jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: assignment.skill_name }), assignment.skill_slug && (jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["/", assignment.skill_slug] }))] }) }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [jsx(Switch, { checked: assignment.enabled, onCheckedChange: (checked) => handleToggleAssignment(assignment, checked), disabled: isMutatingAgentSkill || !canWriteAssignment, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(assignment.enabled
236388
236420
  ? 'clawSandboxAgentSkills.skillEnabledLabel'
236389
- : 'clawSandboxAgentSkills.skillDisabledLabel', { name: assignment.skill_name }) }), renderAssignmentMenu(assignment)] })] }, assignment.id))), jsx(IblPagination, { currentPage: agentPage, totalPages: agentTotalPages, onPageChange: setAgentPage, disabled: isMutatingAgentSkill })] })) }), jsx(TabsContent, { value: "available", className: "space-y-3", children: isLoadingCatalog ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : catalogTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noSkillsAvailable') }) })) : (jsxs(Fragment$1, { children: [catalogSkills.map((skill) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "available-skill-row", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: skill.name }), jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", skill.version] }), renderBadges(skill)] }), skill.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [isCoveredByAgent(skill) ? (jsx("span", { className: "rounded-full bg-green-50 px-2 py-0.5 text-xs text-green-700", children: t('clawSandboxAgentSkills.addedBadge') })) : isOtherAgentsPrivate(skill) ? (
236421
+ : 'clawSandboxAgentSkills.skillDisabledLabel', { name: assignment.skill_name }) }), renderAssignmentRemoveButton(assignment)] })] }, assignment.id))), jsx(IblPagination, { currentPage: agentPage, totalPages: agentTotalPages, onPageChange: setAgentPage, disabled: isMutatingAgentSkill })] })) }), canBrowseCatalog && (jsx(TabsContent, { value: "available", className: "space-y-3", children: isLoadingCatalog ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : catalogTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noSkillsAvailable') }) })) : (jsxs(Fragment$1, { children: [catalogSkills.map((skill) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "available-skill-row", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: skill.name }), jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", skill.version] }), renderBadges(skill)] }), skill.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [isCoveredByAgent(skill) ? (jsx("span", { className: "rounded-full bg-green-50 px-2 py-0.5 text-xs text-green-700", children: t('clawSandboxAgentSkills.addedBadge') })) : isOtherAgentsPrivate(skill) ? (
236390
236422
  // Another agent's private skill: Add stays visible but
236391
236423
  // disabled, with the reason on hover/focus.
236392
236424
  jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsxs(Button$1, { variant: "outline", size: "sm", disabled: true, "aria-label": t('clawSandboxAgentSkills.addToAgentLabel', {
@@ -236395,7 +236427,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
236395
236427
  name: skill.name,
236396
236428
  }), children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.addToAgent')] })), isSkillEditable(skill) && (jsx(Switch, { checked: skill.enabled, onCheckedChange: (checked) => handleToggleSkill(skill, checked), disabled: isUpdatingSkill, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(skill.enabled
236397
236429
  ? 'clawSandboxAgentSkills.skillEnabledLabel'
236398
- : 'clawSandboxAgentSkills.skillDisabledLabel', { name: skill.name }) })), renderSkillMenu(skill)] })] }, skill.id))), jsx(IblPagination, { currentPage: catalogPage, totalPages: catalogTotalPages, onPageChange: setCatalogPage, disabled: isMutatingAgentSkill })] })) })] }), jsx(OverlayModal, { open: showNewDialog, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.newSkillDialogTitle'), className: "max-w-2xl", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: [jsx(SkillForm, { form: form, onChange: setForm }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.filesAfterCreateHint') })] }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleCreateSkill, disabled: isCreatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isCreatingSkill
236430
+ : 'clawSandboxAgentSkills.skillDisabledLabel', { name: skill.name }) })), renderSkillMenu(skill)] })] }, skill.id))), jsx(IblPagination, { currentPage: catalogPage, totalPages: catalogTotalPages, onPageChange: setCatalogPage, disabled: isMutatingAgentSkill })] })) }))] }), jsx(OverlayModal, { open: showNewDialog, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.newSkillDialogTitle'), className: "max-w-2xl", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: [jsx(SkillForm, { form: form, onChange: setForm }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.filesAfterCreateHint') })] }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleCreateSkill, disabled: isCreatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isCreatingSkill
236399
236431
  ? t('clawSandboxAgentSkills.creating')
236400
236432
  : t('clawSandboxAgentSkills.create') })] })] }) }), jsx(OverlayModal, { open: !!editingSkill, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.editSkillDialogTitle'), className: "max-w-2xl", children: jsxs(Tabs, { defaultValue: "details", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.editSkillDialogTitle'), "data-testid": "skill-dialog-tabs", children: [jsx(TabsTrigger, { value: "details", "data-testid": "skill-dialog-tab-details", children: t('clawSandboxAgentSkills.detailsTab') }), jsx(TabsTrigger, { value: "files", "data-testid": "skill-dialog-tab-files", children: t('clawSandboxAgentSkills.filesTab') })] }), jsx(TabsContent, { value: "details", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: jsx(SkillForm, { form: form, onChange: setForm, privateLocked: !!editingSkill && isOtherAgentsPrivate(editingSkill) }) }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleUpdateSkill, disabled: isUpdatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isUpdatingSkill
236401
236433
  ? t('clawSandboxAgentSkills.saving')
@@ -238996,6 +239028,14 @@ function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpe
238996
239028
  ? checkRbacPermission(rbacPermissions, `/mentors/${mentorDbId}/#chat`)
238997
239029
  : true; // Default to true if mentor ID not available or RBAC data not loaded
238998
239030
  const isChatDisabledByRbac = !hasChatPermission;
239031
+ // Listing an agent's skills is a separate, stricter grant than chatting:
239032
+ // the per-agent skills endpoint 403s for users without
239033
+ // `view_skill_assignments`, so the `/` picker's fetch stays off until the
239034
+ // mentor's permission check has explicitly granted it (no permission data
239035
+ // loaded means no fetch — chatting never requires this endpoint).
239036
+ const hasSkillAssignmentsPermission = mentorDbId && hasMentorRbacData
239037
+ ? checkRbacPermission(rbacPermissions, `/mentors/${mentorDbId}/#view_skill_assignments`)
239038
+ : false;
238999
239039
  const { FreeTrialDialog, closeModal: closeFreeTrialModal, isModalOpen: isFreeTrialModalOpen, executeWithTrialCheck, } = useShowFreeTrialDialog();
239000
239040
  const embedMode = useEmbedMode();
239001
239041
  const inputValue = useSelector(chatInputSliceSelectors.selectTextareaInput);
@@ -239038,7 +239078,7 @@ function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpe
239038
239078
  const fetchedSlashSkills = useSlashSkills({
239039
239079
  org: tenantKey,
239040
239080
  mentorUniqueId,
239041
- enabled: slashSkillsEnabled && !slashSkills,
239081
+ enabled: slashSkillsEnabled && !slashSkills && hasSkillAssignmentsPermission,
239042
239082
  active: slashTokenActive,
239043
239083
  });
239044
239084
  const effectiveSlashSkills = slashSkills !== null && slashSkills !== void 0 ? slashSkills : (slashSkillsEnabled ? fetchedSlashSkills.skills : []);
@@ -98586,7 +98586,8 @@ var clawSandboxAgentSkills$3 = {
98586
98586
  noEffectiveSkills: "No skills enabled for this agent yet. Add one from the Available Skills tab.",
98587
98587
  addToAgent: "Add",
98588
98588
  addToAgentLabel: "Add {name} to this agent",
98589
- removeFromAgent: "Remove from Agent",
98589
+ removeFromAgent: "Remove",
98590
+ removeFromAgentLabel: "Remove {name} from this agent",
98590
98591
  skillAdded: "{name} added",
98591
98592
  skillRemoved: "{name} removed",
98592
98593
  featuredBadge: "Featured",
@@ -105749,7 +105750,8 @@ var clawSandboxAgentSkills$2 = {
105749
105750
  noEffectiveSkills: "Cet agent n'a pas encore de compétences activées. Ajoutez-en une depuis l'onglet Compétences disponibles.",
105750
105751
  addToAgent: "Ajouter",
105751
105752
  addToAgentLabel: "Ajouter {name} à cet agent",
105752
- removeFromAgent: "Retirer de l'agent",
105753
+ removeFromAgent: "Retirer",
105754
+ removeFromAgentLabel: "Retirer {name} de cet agent",
105753
105755
  skillAdded: "{name} ajoutée",
105754
105756
  skillRemoved: "{name} retirée",
105755
105757
  featuredBadge: "En vedette",
@@ -112746,7 +112748,8 @@ var clawSandboxAgentSkills$1 = {
112746
112748
  noEffectiveSkills: "Este agente aún no tiene habilidades habilitadas. Añade una desde la pestaña Habilidades disponibles.",
112747
112749
  addToAgent: "Añadir",
112748
112750
  addToAgentLabel: "Añadir {name} a este agente",
112749
- removeFromAgent: "Quitar del agente",
112751
+ removeFromAgent: "Quitar",
112752
+ removeFromAgentLabel: "Quitar {name} de este agente",
112750
112753
  skillAdded: "{name} añadida",
112751
112754
  skillRemoved: "{name} eliminada",
112752
112755
  featuredBadge: "Destacada",
@@ -119743,7 +119746,8 @@ var clawSandboxAgentSkills = {
119743
119746
  noEffectiveSkills: "此智能体尚未启用任何技能。请从“可用技能”标签页添加。",
119744
119747
  addToAgent: "添加",
119745
119748
  addToAgentLabel: "将 {name} 添加到此智能体",
119746
- removeFromAgent: "从智能体中移除",
119749
+ removeFromAgent: "移除",
119750
+ removeFromAgentLabel: "将 {name} 从此智能体中移除",
119747
119751
  skillAdded: "已添加 {name}",
119748
119752
  skillRemoved: "已移除 {name}",
119749
119753
  featuredBadge: "精选",
@@ -259087,12 +259091,31 @@ const EMPTY_SKILL_FORM = {
259087
259091
  };
259088
259092
  /** Page size for both skill lists. */
259089
259093
  const SKILLS_PAGE_SIZE = 10;
259090
- function AgentSkills({ platformKey, mentorUniqueId }) {
259094
+ function AgentSkills({ platformKey, mentorUniqueId, mentorDbId }) {
259091
259095
  var _a, _b, _c, _d, _e, _f;
259092
259096
  const t = useT();
259093
259097
  // Skills are managed independently of the sandbox connection — org-level
259094
259098
  // skills and the mentor's assignments both resolve without a wired Claw
259095
259099
  // instance, so we always fetch and let admins add/assign skills freely.
259100
+ // Assignment reads/writes are RBAC-gated when the host passes `mentorDbId`:
259101
+ // each action needs its grant from the mentor's permission check (the
259102
+ // endpoints 403 without it). Without a `mentorDbId` there is nothing to
259103
+ // check against, so the gates fail open — previous behavior.
259104
+ const rbacPermissions = useSelector(selectRbacPermissions);
259105
+ const mentorRbacKey = mentorDbId != null ? `/mentors/${mentorDbId}/` : null;
259106
+ const hasMentorRbacData = mentorRbacKey ? mentorRbacKey in rbacPermissions : false;
259107
+ const hasAssignmentGrant = (permission) => mentorRbacKey
259108
+ ? hasMentorRbacData && checkRbacPermission(rbacPermissions, `${mentorRbacKey}#${permission}`)
259109
+ : true;
259110
+ const canViewAssignments = hasAssignmentGrant('view_skill_assignments');
259111
+ const canCreateAssignment = hasAssignmentGrant('create_skill_assignment');
259112
+ const canWriteAssignment = hasAssignmentGrant('write_skill_assignment');
259113
+ const canDeleteAssignment = hasAssignmentGrant('delete_skill_assignment');
259114
+ // The Available Skills catalog is a platform-level resource without its own
259115
+ // mentor-scoped grant; its only purpose here is attaching skills, so the
259116
+ // whole tab (fetch included — it can 403 too) plus skill authoring rides on
259117
+ // `create_skill_assignment` until the backend exposes catalog grants.
259118
+ const canBrowseCatalog = canCreateAssignment;
259096
259119
  // The "Agent Skills" tab pages the assignment list server-side.
259097
259120
  const [agentPage, setAgentPage] = useState(1);
259098
259121
  const { data: assignmentsPage, isLoading: isLoadingAssignments } = useGetMentorSkillAssignmentsQuery({
@@ -259100,7 +259123,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
259100
259123
  mentorUniqueId,
259101
259124
  limit: SKILLS_PAGE_SIZE,
259102
259125
  offset: (agentPage - 1) * SKILLS_PAGE_SIZE,
259103
- });
259126
+ }, { skip: !canViewAssignments });
259104
259127
  const agentAssignments = (_a = assignmentsPage === null || assignmentsPage === void 0 ? void 0 : assignmentsPage.results) !== null && _a !== void 0 ? _a : [];
259105
259128
  const agentTotalCount = (_b = assignmentsPage === null || assignmentsPage === void 0 ? void 0 : assignmentsPage.count) !== null && _b !== void 0 ? _b : 0;
259106
259129
  const agentTotalPages = Math.max(1, Math.ceil(agentTotalCount / SKILLS_PAGE_SIZE));
@@ -259114,7 +259137,9 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
259114
259137
  const { data: assignmentCoverage } = useGetMentorSkillAssignmentsQuery({
259115
259138
  org: platformKey,
259116
259139
  mentorUniqueId,
259117
- });
259140
+ },
259141
+ // Only powers the catalog tab's "Added" chips — pointless without it.
259142
+ { skip: !canViewAssignments || !canBrowseCatalog });
259118
259143
  const assignedSkillIds = new Set(((_c = assignmentCoverage === null || assignmentCoverage === void 0 ? void 0 : assignmentCoverage.results) !== null && _c !== void 0 ? _c : []).map((a) => a.skill));
259119
259144
  // The "Available skills" tab pages the catalog server-side. Deliberately
259120
259145
  // unfiltered: disabled skills stay listed (switch off) so admins can
@@ -259124,7 +259149,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
259124
259149
  org: platformKey,
259125
259150
  limit: SKILLS_PAGE_SIZE,
259126
259151
  offset: (catalogPage - 1) * SKILLS_PAGE_SIZE,
259127
- });
259152
+ }, { skip: !canBrowseCatalog });
259128
259153
  const catalogSkills = (_d = catalogSkillsPage === null || catalogSkillsPage === void 0 ? void 0 : catalogSkillsPage.results) !== null && _d !== void 0 ? _d : [];
259129
259154
  const catalogTotalCount = (_e = catalogSkillsPage === null || catalogSkillsPage === void 0 ? void 0 : catalogSkillsPage.count) !== null && _e !== void 0 ? _e : 0;
259130
259155
  const catalogTotalPages = Math.max(1, Math.ceil(catalogTotalCount / SKILLS_PAGE_SIZE));
@@ -259255,7 +259280,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
259255
259280
  }).unwrap();
259256
259281
  // A private skill only takes effect once assigned, and the Agent Skills
259257
259282
  // tab lists assignments — so attach it to this agent right away.
259258
- if (form.privateToAgent && (created === null || created === void 0 ? void 0 : created.unique_id)) {
259283
+ if (form.privateToAgent && (created === null || created === void 0 ? void 0 : created.unique_id) && canCreateAssignment) {
259259
259284
  await createAssignment({
259260
259285
  org: platformKey,
259261
259286
  mentorUniqueId,
@@ -259295,7 +259320,10 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
259295
259320
  }).unwrap();
259296
259321
  // Making a skill private to this agent implies it should be usable by
259297
259322
  // it — attach it if it isn't assigned yet.
259298
- if (!privateLocked && form.privateToAgent && !assignedSkillIds.has(editingSkill.unique_id)) {
259323
+ if (!privateLocked &&
259324
+ form.privateToAgent &&
259325
+ canCreateAssignment &&
259326
+ !assignedSkillIds.has(editingSkill.unique_id)) {
259299
259327
  await createAssignment({
259300
259328
  org: platformKey,
259301
259329
  mentorUniqueId,
@@ -259323,17 +259351,21 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
259323
259351
  }
259324
259352
  };
259325
259353
  const renderBadges = (skill) => (jsxs("span", { className: "flex flex-wrap items-center gap-1", children: [skill.category && (jsx("span", { className: "rounded-full bg-gray-100 px-2 py-0.5 text-[0.625rem] text-gray-500", children: skill.category })), skill.skill_type === 'native' && (jsx("span", { className: "rounded-full bg-purple-50 px-2 py-0.5 text-[0.625rem] text-purple-600", children: t('clawSandboxAgentSkills.nativeBadge') })), skill.is_featured && (jsx("span", { className: "rounded-full bg-amber-50 px-2 py-0.5 text-[0.625rem] text-amber-600", children: t('clawSandboxAgentSkills.featuredBadge') })), skill.mentor === mentorUniqueId && (jsx("span", { className: "rounded-full bg-blue-50 px-2 py-0.5 text-[0.625rem] text-blue-600", children: t('clawSandboxAgentSkills.privateBadge') }))] }));
259326
- // Agent-tab rows are assignments: their only row action is detaching.
259327
- const renderAssignmentMenu = (assignment) => (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', { name: assignment.skill_name }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsx(DropdownMenuContent, { align: "end", children: jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => handleDetach(assignment), children: [jsx(CircleMinus$1, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.removeFromAgent')] }) })] }));
259354
+ // Agent-tab rows are assignments: detaching is their only action, so it's
259355
+ // a direct button (mirroring the catalog's "Add to Agent") rather than a
259356
+ // one-item three-dots menu — hidden entirely without the delete grant.
259357
+ const renderAssignmentRemoveButton = (assignment) => !canDeleteAssignment ? null : (jsxs(Button$1, { variant: "outline", size: "sm", className: "cursor-pointer", disabled: isMutatingAgentSkill, onClick: () => handleDetach(assignment), "aria-label": t('clawSandboxAgentSkills.removeFromAgentLabel', {
259358
+ name: assignment.skill_name,
259359
+ }), children: [jsx(CircleMinus$1, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.removeFromAgent')] }));
259328
259360
  // Catalog rows carry the full skill object: edit/delete where allowed.
259329
259361
  const renderSkillMenu = (skill) => {
259330
259362
  if (!isSkillEditable(skill))
259331
259363
  return null;
259332
259364
  return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', { name: skill.name }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => openEditSkillDialog(skill), children: [jsx(Pen, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.edit')] }), jsxs(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", onClick: () => setDeletingSkill(skill), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.delete')] })] })] }));
259333
259365
  };
259334
- return (jsxs("div", { className: "space-y-4", "data-testid": "agent-skills-content", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsxs("p", { className: "flex items-start gap-2 text-xs text-gray-500", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 shrink-0 text-gray-400" }), jsx("span", { children: t('clawSandboxAgentSkills.sessionNote') })] }), jsxs(Button$1, { onClick: openNewSkillDialog, size: "sm", className: "shrink-0 cursor-pointer bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.newSkill')] })] }), jsxs(Tabs, { defaultValue: "agent", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.tabsAriaLabel'), "data-testid": "agent-skills-tabs", children: [jsx(TabsTrigger, { value: "agent", "data-testid": "agent-skills-tab-agent", children: t('clawSandboxAgentSkills.tabAgentSkills') }), jsx(TabsTrigger, { value: "available", "data-testid": "agent-skills-tab-available", children: t('clawSandboxAgentSkills.tabAvailableSkills') })] }), jsx(TabsContent, { value: "agent", className: "space-y-3", children: isLoadingAssignments ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : agentTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noEffectiveSkills') }) })) : (jsxs(Fragment$1, { children: [agentAssignments.map((assignment) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "agent-skill-row", children: [jsx("div", { className: "min-w-0 space-y-1", children: jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: assignment.skill_name }), assignment.skill_slug && (jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["/", assignment.skill_slug] }))] }) }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [jsx(Switch, { checked: assignment.enabled, onCheckedChange: (checked) => handleToggleAssignment(assignment, checked), disabled: isMutatingAgentSkill, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(assignment.enabled
259366
+ return (jsxs("div", { className: "space-y-4", "data-testid": "agent-skills-content", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsxs("p", { className: "flex items-start gap-2 text-xs text-gray-500", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 shrink-0 text-gray-400" }), jsx("span", { children: t('clawSandboxAgentSkills.sessionNote') })] }), canBrowseCatalog && (jsxs(Button$1, { onClick: openNewSkillDialog, size: "sm", className: "shrink-0 cursor-pointer bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.newSkill')] }))] }), jsxs(Tabs, { defaultValue: "agent", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.tabsAriaLabel'), "data-testid": "agent-skills-tabs", children: [jsx(TabsTrigger, { value: "agent", "data-testid": "agent-skills-tab-agent", children: t('clawSandboxAgentSkills.tabAgentSkills') }), canBrowseCatalog && (jsx(TabsTrigger, { value: "available", "data-testid": "agent-skills-tab-available", children: t('clawSandboxAgentSkills.tabAvailableSkills') }))] }), jsx(TabsContent, { value: "agent", className: "space-y-3", children: isLoadingAssignments ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : agentTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noEffectiveSkills') }) })) : (jsxs(Fragment$1, { children: [agentAssignments.map((assignment) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "agent-skill-row", children: [jsx("div", { className: "min-w-0 space-y-1", children: jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: assignment.skill_name }), assignment.skill_slug && (jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["/", assignment.skill_slug] }))] }) }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [jsx(Switch, { checked: assignment.enabled, onCheckedChange: (checked) => handleToggleAssignment(assignment, checked), disabled: isMutatingAgentSkill || !canWriteAssignment, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(assignment.enabled
259335
259367
  ? 'clawSandboxAgentSkills.skillEnabledLabel'
259336
- : 'clawSandboxAgentSkills.skillDisabledLabel', { name: assignment.skill_name }) }), renderAssignmentMenu(assignment)] })] }, assignment.id))), jsx(IblPagination, { currentPage: agentPage, totalPages: agentTotalPages, onPageChange: setAgentPage, disabled: isMutatingAgentSkill })] })) }), jsx(TabsContent, { value: "available", className: "space-y-3", children: isLoadingCatalog ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : catalogTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noSkillsAvailable') }) })) : (jsxs(Fragment$1, { children: [catalogSkills.map((skill) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "available-skill-row", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: skill.name }), jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", skill.version] }), renderBadges(skill)] }), skill.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [isCoveredByAgent(skill) ? (jsx("span", { className: "rounded-full bg-green-50 px-2 py-0.5 text-xs text-green-700", children: t('clawSandboxAgentSkills.addedBadge') })) : isOtherAgentsPrivate(skill) ? (
259368
+ : 'clawSandboxAgentSkills.skillDisabledLabel', { name: assignment.skill_name }) }), renderAssignmentRemoveButton(assignment)] })] }, assignment.id))), jsx(IblPagination, { currentPage: agentPage, totalPages: agentTotalPages, onPageChange: setAgentPage, disabled: isMutatingAgentSkill })] })) }), canBrowseCatalog && (jsx(TabsContent, { value: "available", className: "space-y-3", children: isLoadingCatalog ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : catalogTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noSkillsAvailable') }) })) : (jsxs(Fragment$1, { children: [catalogSkills.map((skill) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "available-skill-row", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: skill.name }), jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", skill.version] }), renderBadges(skill)] }), skill.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [isCoveredByAgent(skill) ? (jsx("span", { className: "rounded-full bg-green-50 px-2 py-0.5 text-xs text-green-700", children: t('clawSandboxAgentSkills.addedBadge') })) : isOtherAgentsPrivate(skill) ? (
259337
259369
  // Another agent's private skill: Add stays visible but
259338
259370
  // disabled, with the reason on hover/focus.
259339
259371
  jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsxs(Button$1, { variant: "outline", size: "sm", disabled: true, "aria-label": t('clawSandboxAgentSkills.addToAgentLabel', {
@@ -259342,7 +259374,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
259342
259374
  name: skill.name,
259343
259375
  }), children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.addToAgent')] })), isSkillEditable(skill) && (jsx(Switch, { checked: skill.enabled, onCheckedChange: (checked) => handleToggleSkill(skill, checked), disabled: isUpdatingSkill, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(skill.enabled
259344
259376
  ? 'clawSandboxAgentSkills.skillEnabledLabel'
259345
- : 'clawSandboxAgentSkills.skillDisabledLabel', { name: skill.name }) })), renderSkillMenu(skill)] })] }, skill.id))), jsx(IblPagination, { currentPage: catalogPage, totalPages: catalogTotalPages, onPageChange: setCatalogPage, disabled: isMutatingAgentSkill })] })) })] }), jsx(OverlayModal, { open: showNewDialog, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.newSkillDialogTitle'), className: "max-w-2xl", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: [jsx(SkillForm, { form: form, onChange: setForm }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.filesAfterCreateHint') })] }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleCreateSkill, disabled: isCreatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isCreatingSkill
259377
+ : 'clawSandboxAgentSkills.skillDisabledLabel', { name: skill.name }) })), renderSkillMenu(skill)] })] }, skill.id))), jsx(IblPagination, { currentPage: catalogPage, totalPages: catalogTotalPages, onPageChange: setCatalogPage, disabled: isMutatingAgentSkill })] })) }))] }), jsx(OverlayModal, { open: showNewDialog, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.newSkillDialogTitle'), className: "max-w-2xl", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: [jsx(SkillForm, { form: form, onChange: setForm }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.filesAfterCreateHint') })] }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleCreateSkill, disabled: isCreatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isCreatingSkill
259346
259378
  ? t('clawSandboxAgentSkills.creating')
259347
259379
  : t('clawSandboxAgentSkills.create') })] })] }) }), jsx(OverlayModal, { open: !!editingSkill, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.editSkillDialogTitle'), className: "max-w-2xl", children: jsxs(Tabs, { defaultValue: "details", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.editSkillDialogTitle'), "data-testid": "skill-dialog-tabs", children: [jsx(TabsTrigger, { value: "details", "data-testid": "skill-dialog-tab-details", children: t('clawSandboxAgentSkills.detailsTab') }), jsx(TabsTrigger, { value: "files", "data-testid": "skill-dialog-tab-files", children: t('clawSandboxAgentSkills.filesTab') })] }), jsx(TabsContent, { value: "details", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: jsx(SkillForm, { form: form, onChange: setForm, privateLocked: !!editingSkill && isOtherAgentsPrivate(editingSkill) }) }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleUpdateSkill, disabled: isUpdatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isUpdatingSkill
259348
259380
  ? t('clawSandboxAgentSkills.saving')
@@ -261773,6 +261805,14 @@ function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpe
261773
261805
  ? checkRbacPermission(rbacPermissions, `/mentors/${mentorDbId}/#chat`)
261774
261806
  : true; // Default to true if mentor ID not available or RBAC data not loaded
261775
261807
  const isChatDisabledByRbac = !hasChatPermission;
261808
+ // Listing an agent's skills is a separate, stricter grant than chatting:
261809
+ // the per-agent skills endpoint 403s for users without
261810
+ // `view_skill_assignments`, so the `/` picker's fetch stays off until the
261811
+ // mentor's permission check has explicitly granted it (no permission data
261812
+ // loaded means no fetch — chatting never requires this endpoint).
261813
+ const hasSkillAssignmentsPermission = mentorDbId && hasMentorRbacData
261814
+ ? checkRbacPermission(rbacPermissions, `/mentors/${mentorDbId}/#view_skill_assignments`)
261815
+ : false;
261776
261816
  const { FreeTrialDialog, closeModal: closeFreeTrialModal, isModalOpen: isFreeTrialModalOpen, executeWithTrialCheck, } = useShowFreeTrialDialog();
261777
261817
  const embedMode = useEmbedMode();
261778
261818
  const inputValue = useSelector(chatInputSliceSelectors.selectTextareaInput);
@@ -261815,7 +261855,7 @@ function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpe
261815
261855
  const fetchedSlashSkills = useSlashSkills({
261816
261856
  org: tenantKey,
261817
261857
  mentorUniqueId,
261818
- enabled: slashSkillsEnabled && !slashSkills,
261858
+ enabled: slashSkillsEnabled && !slashSkills && hasSkillAssignmentsPermission,
261819
261859
  active: slashTokenActive,
261820
261860
  });
261821
261861
  const effectiveSlashSkills = slashSkills !== null && slashSkills !== void 0 ? slashSkills : (slashSkillsEnabled ? fetchedSlashSkills.skills : []);
@@ -268657,7 +268697,7 @@ function PlatformSidebarFooter({ collapsed, config, }) {
268657
268697
  * defined for completeness so adding "Organization" later is a one-line
268658
268698
  * change.
268659
268699
  */
268660
- function PlatformAccountSheet({ tab, onClose, tenantKey, username, email, onInviteClick, mainPlatformKey, authUrl, currentSpa, platformBaseDomain, showGradebookTab = false, }) {
268700
+ function PlatformAccountSheet({ tab, onClose, tenantKey, username, email, onInviteClick, mainPlatformKey, authUrl, currentSpa, platformBaseDomain, showGradebookTab = false, onboardingBasePath = '', rbacPermissions = {}, }) {
268661
268701
  const t = useT();
268662
268702
  const open = tab !== null;
268663
268703
  const accountTabTitles = {
@@ -268676,11 +268716,11 @@ function PlatformAccountSheet({ tab, onClose, tenantKey, username, email, onInvi
268676
268716
  advanced: t('platformSidebar.accountDescAdvanced'),
268677
268717
  billing: t('platformSidebar.accountDescBilling'),
268678
268718
  };
268679
- return (jsx(Dialog, { open: open, onOpenChange: (o) => !o && onClose(), children: jsxs(DialogContent, { className: "mx-auto my-auto flex h-[90vh] w-[95vw] max-w-none flex-col justify-between gap-0 rounded-lg p-0 sm:max-w-7xl", children: [jsxs(DialogHeader, { className: "flex-shrink-0 border-b border-gray-200 p-4 pt-[30px]", children: [jsx(DialogTitle, { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: tab ? accountTabTitles[tab] : '' }), jsx(DialogDescription, { className: "text-sm leading-relaxed text-gray-600", children: tab ? accountTabDescriptions[tab] : '' })] }), jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto p-6", children: [tab === 'management' && (jsx(Admin, { tenant: tenantKey, onInviteClick: onInviteClick,
268719
+ return (jsx(Dialog, { open: open, onOpenChange: (o) => !o && onClose(), children: jsxs(DialogContent, { className: "mx-auto my-auto flex h-[90vh] w-[95vw] max-w-none flex-col justify-between gap-0 rounded-lg p-0 sm:max-w-7xl", children: [jsxs(DialogHeader, { className: "flex-shrink-0 border-b border-gray-200 p-4 pt-[30px]", children: [jsx(DialogTitle, { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: tab ? accountTabTitles[tab] : '' }), jsx(DialogDescription, { className: "text-sm leading-relaxed text-gray-600", children: tab ? accountTabDescriptions[tab] : '' })] }), jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto p-6", children: [tab === 'management' && (jsx(Admin, { onboardingBasePath: onboardingBasePath, tenant: tenantKey, onInviteClick: onInviteClick,
268680
268720
  // RBAC is off for this entry point — admin users see every
268681
268721
  // sub-tab. Tenant-level access is already gated by the
268682
268722
  // sidebar footer visibility rules.
268683
- hasUserTabPermission: true, hasGroupsTabPermission: true, hasRolesTabPermission: true, hasPoliciesTabPermission: true, hasTeamsTabPermission: true, hasAlertsTabPermission: true, hasInviteUserPermission: true, hasCreateTeamPermission: true, enableRbac: false, rbacPermissions: {}, showGradebookTab: showGradebookTab })), tab === 'integrations' && jsx(IntegrationsTab, { tenantKey: tenantKey, username: username }), tab === 'billing' && (jsx(BillingTab, { tenant: tenantKey, username: username, mainPlatformKey: mainPlatformKey, currentUserEmail: email })), tab === 'monetization' && jsx(MonetizationTab, { platformKey: tenantKey, authURL: authUrl }), tab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenantKey, username: username, currentSPA: currentSpa, authURL: authUrl, currentPlatformBaseDomain: platformBaseDomain }))] })] }) }));
268723
+ hasUserTabPermission: true, hasGroupsTabPermission: true, hasRolesTabPermission: true, hasPoliciesTabPermission: true, hasTeamsTabPermission: true, hasAlertsTabPermission: true, hasInviteUserPermission: true, hasCreateTeamPermission: true, enableRbac: false, rbacPermissions: rbacPermissions, currentSpa: currentSpa, showGradebookTab: showGradebookTab, authSpaUrl: authUrl })), tab === 'integrations' && jsx(IntegrationsTab, { tenantKey: tenantKey, username: username }), tab === 'billing' && (jsx(BillingTab, { tenant: tenantKey, username: username, mainPlatformKey: mainPlatformKey, currentUserEmail: email })), tab === 'monetization' && jsx(MonetizationTab, { platformKey: tenantKey, authURL: authUrl }), tab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenantKey, username: username, currentSPA: currentSpa, authURL: authUrl, currentPlatformBaseDomain: platformBaseDomain }))] })] }) }));
268684
268724
  }
268685
268725
 
268686
268726
  /**
@@ -275151,7 +275191,7 @@ function AgentSkillsTab({ labels: labelsOverride, tenantKey: tenantKeyProp, ment
275151
275191
  return (jsxs(Fragment$1, { children: [jsx("div", { className: "hidden h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block", children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-700", children: labels.header.description })] }) }), jsx("div", { className: "flex-1 space-y-4 p-3", style: {
275152
275192
  overflowY: 'auto',
275153
275193
  overflowX: 'hidden',
275154
- }, children: isSettingsLoading || !mentorUniqueId ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: labels.loading })] })) : knownNotBaseAgent ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: labels.notBaseAgent }) })) : (jsx(AgentSkills, { platformKey: tenantKey, mentorUniqueId: mentorUniqueId })) })] }));
275194
+ }, children: isSettingsLoading || !mentorUniqueId ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: labels.loading })] })) : knownNotBaseAgent ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: labels.notBaseAgent }) })) : (jsx(AgentSkills, { platformKey: tenantKey, mentorUniqueId: mentorUniqueId, mentorDbId: settings === null || settings === void 0 ? void 0 : settings.mentor_id })) })] }));
275155
275195
  }
275156
275196
 
275157
275197
  const AGENT_GRADER_TAB_LABELS = {
@@ -55,15 +55,17 @@ export declare function addSkillToAgent(page: Page, skillName: string): Promise<
55
55
  */
56
56
  export declare function verifySkillAdded(page: Page, skillName: string): Promise<void>;
57
57
  /**
58
- * Open the three-dots actions menu for a skill row on the active sub-tab.
59
- * Agent-tab rows offer "Remove from Agent" only; catalog rows offer
60
- * Edit/Delete (for editable skills). The menu content portals to
61
- * document.body, so the returned locator is page-level by design.
58
+ * Open the three-dots actions menu for a CATALOG skill row (Edit/Delete on
59
+ * editable skills). Agent-tab rows have no menu detaching is a direct
60
+ * "Remove" button there (see `removeSkillFromAgent`). The menu content
61
+ * portals to document.body, so the returned locator is page-level by design.
62
62
  */
63
63
  export declare function openSkillActionsMenu(page: Page, skillName: string): Promise<Locator>;
64
64
  /**
65
- * Detach a skill from the agent via its row menu ("Remove from Agent") on the
66
- * "Agent Skills" sub-tab. Waits for the toast and for the row to disappear.
65
+ * Detach a skill from the agent via its row's direct "Remove" button on the
66
+ * "Agent Skills" sub-tab (the visible text is just "Remove"; the button's
67
+ * accessible name carries the skill, mirroring the catalog's Add button).
68
+ * Waits for the toast confirming the detach.
67
69
  */
68
70
  export declare function removeSkillFromAgent(page: Page, skillName: string): Promise<void>;
69
71
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iblai/iblai-js",
3
- "version": "2.7.4",
3
+ "version": "2.7.6",
4
4
  "description": "Unified JavaScript SDK for IBL.ai — re-exports data-layer, web-containers, and web-utils under a single package",
5
5
  "type": "module",
6
6
  "engines": {
@@ -77,8 +77,8 @@
77
77
  "dotenv": "16.6.1",
78
78
  "winston": "3.19.0",
79
79
  "@iblai/data-layer": "1.13.0",
80
- "@iblai/mcp": "1.12.1",
81
- "@iblai/web-containers": "1.19.2",
80
+ "@iblai/mcp": "1.12.2",
81
+ "@iblai/web-containers": "1.19.4",
82
82
  "@iblai/web-utils": "2.2.2"
83
83
  },
84
84
  "peerDependencies": {