@elizaos/app-core 2.0.0-alpha.335 → 2.0.0-alpha.336

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.
Files changed (46) hide show
  1. package/apps/app-lifeops/src/routes/lifeops-routes.d.ts.map +1 -1
  2. package/apps/app-lifeops/src/routes/lifeops-routes.js +10 -1
  3. package/i18n/locales/en.json +5 -5
  4. package/package.json +5 -5
  5. package/packages/app-core/src/components/character/CharacterEditorPanels.d.ts.map +1 -1
  6. package/packages/app-core/src/components/character/CharacterEditorPanels.js +192 -85
  7. package/packages/app-core/src/components/character/CharacterExperienceWorkspace.d.ts.map +1 -1
  8. package/packages/app-core/src/components/character/CharacterExperienceWorkspace.js +182 -31
  9. package/packages/app-core/src/components/character/CharacterHubView.d.ts.map +1 -1
  10. package/packages/app-core/src/components/character/CharacterHubView.js +253 -23
  11. package/packages/app-core/src/components/character/CharacterOverviewSection.d.ts +14 -1
  12. package/packages/app-core/src/components/character/CharacterOverviewSection.d.ts.map +1 -1
  13. package/packages/app-core/src/components/character/CharacterOverviewSection.js +35 -8
  14. package/packages/app-core/src/components/character/character-hub-helpers.d.ts.map +1 -1
  15. package/packages/app-core/src/components/character/character-hub-helpers.js +3 -7
  16. package/packages/app-core/src/components/pages/AutomationsView.d.ts.map +1 -1
  17. package/packages/app-core/src/components/pages/AutomationsView.js +341 -193
  18. package/packages/app-core/src/components/pages/HeartbeatForm.d.ts.map +1 -1
  19. package/packages/app-core/src/components/pages/HeartbeatForm.js +12 -14
  20. package/packages/app-core/src/components/pages/KnowledgeView.d.ts.map +1 -1
  21. package/packages/app-core/src/components/pages/KnowledgeView.js +20 -6
  22. package/packages/app-core/src/components/pages/RelationshipsGraphPanel.d.ts +2 -1
  23. package/packages/app-core/src/components/pages/RelationshipsGraphPanel.d.ts.map +1 -1
  24. package/packages/app-core/src/components/pages/RelationshipsGraphPanel.js +3 -3
  25. package/packages/app-core/src/components/pages/WorkflowGraphViewer.d.ts +0 -9
  26. package/packages/app-core/src/components/pages/WorkflowGraphViewer.d.ts.map +1 -1
  27. package/packages/app-core/src/components/pages/WorkflowGraphViewer.js +50 -18
  28. package/packages/app-core/src/components/pages/knowledge-detail.d.ts.map +1 -1
  29. package/packages/app-core/src/components/pages/knowledge-detail.js +28 -2
  30. package/packages/app-core/src/components/pages/page-scoped-conversations.d.ts +1 -1
  31. package/packages/app-core/src/components/pages/page-scoped-conversations.js +4 -4
  32. package/packages/app-core/src/components/pages/relationships/RelationshipsPersonPanels.d.ts +2 -1
  33. package/packages/app-core/src/components/pages/relationships/RelationshipsPersonPanels.d.ts.map +1 -1
  34. package/packages/app-core/src/components/pages/relationships/RelationshipsPersonPanels.js +69 -32
  35. package/packages/app-core/src/components/pages/relationships/RelationshipsSidebar.d.ts +1 -6
  36. package/packages/app-core/src/components/pages/relationships/RelationshipsSidebar.d.ts.map +1 -1
  37. package/packages/app-core/src/components/pages/relationships/RelationshipsSidebar.js +4 -4
  38. package/packages/app-core/src/components/pages/relationships/RelationshipsWorkspaceView.d.ts +2 -1
  39. package/packages/app-core/src/components/pages/relationships/RelationshipsWorkspaceView.d.ts.map +1 -1
  40. package/packages/app-core/src/components/pages/relationships/RelationshipsWorkspaceView.js +25 -15
  41. package/packages/app-core/src/i18n/locales/en.json +5 -5
  42. package/packages/app-core/src/registry/generate-apps.js +2 -2
  43. package/packages/shared/src/contracts/lifeops.d.ts +4 -0
  44. package/packages/shared/src/contracts/lifeops.d.ts.map +1 -1
  45. package/packages/typescript/src/features/advanced-capabilities/clipboard/services/clipboardService.d.ts.map +1 -1
  46. package/packages/typescript/src/features/advanced-capabilities/clipboard/services/clipboardService.js +6 -1
@@ -1 +1 @@
1
- {"version":3,"file":"lifeops-routes.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/routes/lifeops-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AA6D3E,OAAO,EAAE,KAAK,YAAY,EAAU,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AAYrE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC;IAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE;QACL,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;QAC7B,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5E,YAAY,EAAE,CAAC,CAAC,SAAS,MAAM,EAC7B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,OAAO,CAAC,EAAE,mBAAmB,KAC1B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,mBAAmB,EAAE,CACnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,KAAK,EAAE,MAAM,KACV,MAAM,GAAG,IAAI,CAAC;CACpB;AAwjBD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,mBAAmB,GACvB,OAAO,CAAC,OAAO,CAAC,CAitDlB"}
1
+ {"version":3,"file":"lifeops-routes.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/routes/lifeops-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AA6D3E,OAAO,EAAE,KAAK,YAAY,EAAU,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AAYrE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC;IAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE;QACL,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;QAC7B,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5E,YAAY,EAAE,CAAC,CAAC,SAAS,MAAM,EAC7B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,OAAO,CAAC,EAAE,mBAAmB,KAC1B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,mBAAmB,EAAE,CACnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,KAAK,EAAE,MAAM,KACV,MAAM,GAAG,IAAI,CAAC;CACpB;AAwjBD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,mBAAmB,GACvB,OAAO,CAAC,OAAO,CAAC,CA4tDlB"}
@@ -699,10 +699,14 @@ export async function handleLifeOpsRoutes(ctx) {
699
699
  return runRoute(ctx, async (service) => {
700
700
  const event = await service.updateCalendarEvent(url, {
701
701
  eventId,
702
+ side: body.side ?? parseConnectorSideQuery(url.searchParams.get("side")),
703
+ grantId: body.grantId ?? url.searchParams.get("grantId") ?? undefined,
704
+ calendarId: body.calendarId ?? url.searchParams.get("calendarId") ?? undefined,
702
705
  title: body.title,
703
706
  description: body.notes,
704
707
  startAt: body.startAt,
705
708
  endAt: body.endAt,
709
+ timeZone: body.timeZone,
706
710
  });
707
711
  json(res, { event });
708
712
  });
@@ -711,7 +715,12 @@ export async function handleLifeOpsRoutes(ctx) {
711
715
  if (rateLimitRequest(ctx, "calendar_delete"))
712
716
  return true;
713
717
  return runRoute(ctx, async (service) => {
714
- await service.deleteCalendarEvent(url, { eventId });
718
+ await service.deleteCalendarEvent(url, {
719
+ eventId,
720
+ side: parseConnectorSideQuery(url.searchParams.get("side")),
721
+ grantId: url.searchParams.get("grantId") ?? undefined,
722
+ calendarId: url.searchParams.get("calendarId") ?? undefined,
723
+ });
715
724
  json(res, { deleted: true });
716
725
  });
717
726
  }
@@ -3024,7 +3024,7 @@
3024
3024
  "lifeopspage.agentGithubConnectedRestarting": "Agent GitHub{{githubHandle}} connected and the cloud runtime is restarting.",
3025
3025
  "lifeopspage.agentGithubConnected": "Agent GitHub{{githubHandle}} connected.",
3026
3026
  "lifeopspage.notLinked": "Not linked",
3027
- "lifeopspage.githubDetailsPartial": "Some GitHub cloud details are still unavailable. You can still connect accounts.",
3027
+ "lifeopspage.githubDetailsPartial": "GitHub details unavailable.",
3028
3028
  "lifeopspage.githubDetailsLoadFailed": "GitHub connection details failed to load.",
3029
3029
  "lifeopspage.githubLinkFailed": "Failed to link GitHub to this agent.",
3030
3030
  "lifeopspage.enabled": "LifeOps enabled.",
@@ -3039,7 +3039,7 @@
3039
3039
  "lifeopspage.agentGithubDisconnected": "Agent GitHub disconnected.",
3040
3040
  "lifeopspage.disconnectAgentGithubFailed": "Failed to disconnect agent GitHub.",
3041
3041
  "lifeopspage.cloudRequired": "Cloud required",
3042
- "lifeopspage.noCloudAgent": "No cloud agent",
3042
+ "lifeopspage.noCloudAgent": "No agent",
3043
3043
  "lifeopspage.loadingState": "Loading LifeOps app state",
3044
3044
  "lifeopspage.waitingRuntime": "Waiting for LifeOps runtime",
3045
3045
  "lifeopspage.enableTitle": "Your personal assistant for calendar, email, and routines",
@@ -3055,7 +3055,7 @@
3055
3055
  "lifeopspage.enabling": "Enabling…",
3056
3056
  "lifeopspage.enable": "Enable LifeOps",
3057
3057
  "lifeopspage.disableHint": "You can disable LifeOps at any time.",
3058
- "lifeopspage.setupTitle": "Setup",
3058
+ "lifeopspage.setupTitle": "Access",
3059
3059
  "lifeopspage.setupDescription": "Connect Google, GitHub, and messaging accounts.",
3060
3060
  "lifeopspage.disable": "Disable LifeOps",
3061
3061
  "lifeopsworkspace.user": "User",
@@ -3114,8 +3114,8 @@
3114
3114
  "lifeopssettings.googleConnected": "Google connected",
3115
3115
  "lifeopssettings.local": "Local",
3116
3116
  "lifeopssettings.cloud": "Cloud",
3117
- "lifeopssettings.localModeDescription": "Tokens stay on this device. LifeOps can only access Google while the app is running.",
3118
- "lifeopssettings.cloudModeDescription": "Tokens live in Eliza Cloud. The agent can check Google on your behalf even when the app is closed.",
3117
+ "lifeopssettings.localModeDescription": "This device only.",
3118
+ "lifeopssettings.cloudModeDescription": "Background access.",
3119
3119
  "lifeopssettings.user": "User",
3120
3120
  "lifeopssettings.capabilityCalendar": "Cal",
3121
3121
  "lifeopssettings.capabilityMail": "Mail",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/app-core",
3
- "version": "2.0.0-alpha.335",
3
+ "version": "2.0.0-alpha.336",
4
4
  "description": "Shared application core for elizaOS white-label agent apps.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -469,7 +469,7 @@
469
469
  "@capacitor/preferences": "^8.0.1",
470
470
  "@capacitor/push-notifications": "^8.0.0",
471
471
  "@clack/prompts": "^1.0.0",
472
- "@elizaos/agent": "^2.0.0-alpha.335",
472
+ "@elizaos/agent": "^2.0.0-alpha.336",
473
473
  "@elizaos/app-companion": "^0.0.0",
474
474
  "@elizaos/app-elizamaker": "^0.0.0",
475
475
  "@elizaos/app-lifeops": "^0.0.0",
@@ -478,11 +478,11 @@
478
478
  "@elizaos/app-task-coordinator": "^0.0.0",
479
479
  "@elizaos/app-training": "^0.0.1",
480
480
  "@elizaos/app-vincent": "^0.0.0",
481
- "@elizaos/core": "^2.0.0-alpha.335",
481
+ "@elizaos/core": "^2.0.0-alpha.336",
482
482
  "@elizaos/plugin-browser-bridge": "^0.1.0",
483
483
  "@elizaos/plugin-wechat": "^0.1.0",
484
- "@elizaos/shared": "^2.0.0-alpha.335",
485
- "@elizaos/ui": "^2.0.0-alpha.335",
484
+ "@elizaos/shared": "^2.0.0-alpha.336",
485
+ "@elizaos/ui": "^2.0.0-alpha.336",
486
486
  "@radix-ui/react-checkbox": "^1.3.3",
487
487
  "@radix-ui/react-dialog": "^1.1.15",
488
488
  "@radix-ui/react-dropdown-menu": "^2.1.16",
@@ -1 +1 @@
1
- {"version":3,"file":"CharacterEditorPanels.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterEditorPanels.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAQzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAsFnE,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC9D;AAED,MAAM,WAAW,wBAAwB;IACvC,CAAC,EAAE,aAAa,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,6BAA6B,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,mBAAmB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,sBAAsB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,2BAA2B,EAAE,CAC3B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,KACV,IAAI,CAAC;IACV,sBAAsB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,yBAAyB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAClE,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC9D;AAED,MAAM,WAAW,2BAA2B;IAC1C,CAAC,EAAE,aAAa,CAAC;IACjB,yBAAyB,EAAE,mBAAmB,EAAE,CAAC;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC9D;AAID,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,eAAe,EACf,CAAC,GACF,EAAE,2BAA2B,2CAqB7B;AAID,wBAAgB,mBAAmB,CAAC,EAClC,CAAC,EACD,mBAAmB,EACnB,gBAAgB,EAChB,6BAA6B,EAC7B,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,sBAAsB,EACtB,yBAAyB,EACzB,CAAC,GACF,EAAE,wBAAwB,2CA4K1B;AAID,wBAAgB,sBAAsB,CAAC,EACrC,CAAC,EACD,yBAAyB,EACzB,eAAe,EACf,CAAC,GACF,EAAE,2BAA2B,2CAmP7B"}
1
+ {"version":3,"file":"CharacterEditorPanels.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterEditorPanels.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAQzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AA2KnE,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC9D;AAED,MAAM,WAAW,wBAAwB;IACvC,CAAC,EAAE,aAAa,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,6BAA6B,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,mBAAmB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,sBAAsB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,2BAA2B,EAAE,CAC3B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,KACV,IAAI,CAAC;IACV,sBAAsB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,yBAAyB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAClE,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC9D;AAED,MAAM,WAAW,2BAA2B;IAC1C,CAAC,EAAE,aAAa,CAAC;IACjB,yBAAyB,EAAE,mBAAmB,EAAE,CAAC;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC9D;AAID,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,eAAe,EACf,CAAC,GACF,EAAE,2BAA2B,2CAqB7B;AAID,wBAAgB,mBAAmB,CAAC,EAClC,CAAC,EACD,mBAAmB,EACnB,gBAAgB,EAChB,6BAA6B,EAC7B,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,sBAAsB,EACtB,yBAAyB,EACzB,CAAC,GACF,EAAE,wBAAwB,2CAoP1B;AAID,wBAAgB,sBAAsB,CAAC,EACrC,CAAC,EACD,yBAAyB,EACzB,eAAe,EACf,CAAC,GACF,EAAE,2BAA2B,2CAsX7B"}
@@ -7,9 +7,9 @@ const PlusIconSvg = ({ className }) => (_jsx("svg", { width: "10", height: "10",
7
7
  const TrashIconSvg = ({ className }) => (_jsx("svg", { width: "11", height: "11", viewBox: "0 0 11 11", fill: "none", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: className, children: _jsx("path", { d: "M1.75 2.75h7.5M4 2.75V1.75h3v1M2.75 2.75l.4 6.75h4.7l.4-6.75" }) }));
8
8
  /* ── Small grip icon shown as drag affordance ───────────────────── */
9
9
  const GripIconSvg = ({ className }) => (_jsxs("svg", { width: "10", height: "14", viewBox: "0 0 10 14", fill: "currentColor", "aria-hidden": "true", className: className, children: [_jsx("circle", { cx: "3", cy: "3", r: "1" }), _jsx("circle", { cx: "3", cy: "7", r: "1" }), _jsx("circle", { cx: "3", cy: "11", r: "1" }), _jsx("circle", { cx: "7", cy: "3", r: "1" }), _jsx("circle", { cx: "7", cy: "7", r: "1" }), _jsx("circle", { cx: "7", cy: "11", r: "1" })] }));
10
- /* ── Shared styles for inline plus/trash buttons ─────────────────── */
11
- const inlineAddBtn = "inline-flex h-7 w-7 items-center justify-center rounded-sm text-accent/80 transition-colors hover:bg-accent/10 hover:text-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent/60 disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent";
12
- const inlineIconBtn = "inline-flex h-7 w-7 items-center justify-center rounded-sm text-muted transition-colors hover:bg-bg-muted/70 hover:text-txt focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent/60";
10
+ const ArrowUpIconSvg = ({ className }) => (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: className, children: _jsx("path", { d: "M6 10V2M2.75 5.25 6 2l3.25 3.25" }) }));
11
+ const ArrowDownIconSvg = ({ className }) => (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: className, children: _jsx("path", { d: "M6 2v8M2.75 6.75 6 10l3.25-3.25" }) }));
12
+ const compactIconBtn = "inline-flex h-7 w-7 items-center justify-center rounded-sm border border-border/35 text-muted transition-colors hover:border-border/70 hover:bg-bg-muted/70 hover:text-txt focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent/60 disabled:cursor-not-allowed disabled:opacity-35 disabled:hover:bg-transparent";
13
13
  /* ── Style section constants ─────────────────────────────────────── */
14
14
  const STYLE_SECTION_KEYS = ["all"];
15
15
  const STYLE_SECTION_PLACEHOLDERS = {
@@ -24,6 +24,49 @@ const STYLE_SECTION_EMPTY_STATES = {
24
24
  defaultValue: "No style rules yet.",
25
25
  },
26
26
  };
27
+ const STYLE_INTENT_GROUPS = [
28
+ {
29
+ id: "voice",
30
+ label: "Voice",
31
+ hint: "Tone, phrasing, vocabulary, and point of view.",
32
+ match: /\b(tone|voice|speak|writes?|sounds?|word|phrase|slang|grammar|sentence|style|humor|funny|serious|casual|formal|emoji)\b/i,
33
+ },
34
+ {
35
+ id: "behavior",
36
+ label: "Behavior",
37
+ hint: "How the character acts, answers, and makes choices.",
38
+ match: /\b(should|always|never|avoid|prefer|respond|answer|ask|explain|focus|do not|don't|must|will|acts?|behavior)\b/i,
39
+ },
40
+ {
41
+ id: "boundaries",
42
+ label: "Boundaries",
43
+ hint: "Safety, limits, privacy, and things to refuse or avoid.",
44
+ match: /\b(refuse|limit|boundary|private|privacy|secret|safe|unsafe|harm|illegal|policy|disclose|medical|legal|financial)\b/i,
45
+ },
46
+ {
47
+ id: "general",
48
+ label: "General",
49
+ hint: "Rules that do not fit a specific intent yet.",
50
+ match: null,
51
+ },
52
+ ];
53
+ function normalizeComparable(value) {
54
+ return value.trim().toLowerCase().replace(/\s+/g, " ");
55
+ }
56
+ function getDuplicateIndices(items) {
57
+ const buckets = new Map();
58
+ items.forEach((item, index) => {
59
+ const normalized = normalizeComparable(item);
60
+ if (!normalized)
61
+ return;
62
+ buckets.set(normalized, [...(buckets.get(normalized) ?? []), index]);
63
+ });
64
+ return new Set([...buckets.values()].filter((indices) => indices.length > 1).flat());
65
+ }
66
+ function getStyleIntentGroupId(item) {
67
+ return (STYLE_INTENT_GROUPS.find((group) => group.match?.test(item)) ??
68
+ STYLE_INTENT_GROUPS[STYLE_INTENT_GROUPS.length - 1]).id;
69
+ }
27
70
  /* ── CharacterIdentityPanel ──────────────────────────────────────── */
28
71
  export function CharacterIdentityPanel({ bioText, handleFieldEdit, t, }) {
29
72
  return (_jsx("div", { className: "flex flex-col gap-5", children: _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.08em] text-muted", children: t("charactereditor.AboutMe", { defaultValue: "About Me" }) }), _jsx(Textarea, { value: bioText, rows: 8, placeholder: t("charactereditor.AboutMePlaceholder", {
@@ -40,39 +83,57 @@ export function CharacterStylePanel({ d, pendingStyleEntries, styleEntryDrafts,
40
83
  next.splice(to, 0, moved);
41
84
  return next;
42
85
  };
43
- return (_jsxs("section", { className: "flex flex-col gap-3", children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.08em] text-muted", children: t("charactereditor.StyleRulesHeader", {
44
- defaultValue: "Style Rules",
45
- }) }), _jsx("div", { className: "flex flex-col gap-3 min-h-0", children: STYLE_SECTION_KEYS.map((key) => {
86
+ return (_jsxs("section", { className: "flex flex-col gap-4", children: [_jsx("div", { className: "flex flex-wrap items-end justify-between gap-2", children: _jsxs("div", { children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.08em] text-muted", children: t("charactereditor.StyleRulesHeader", {
87
+ defaultValue: "Style Rules",
88
+ }) }), _jsx("p", { className: "mt-1 text-xs text-muted", children: t("charactereditor.StyleRulesHelp", {
89
+ defaultValue: "Effective rules from style.all, grouped by intent for easier review.",
90
+ }) })] }) }), _jsx("div", { className: "flex flex-col gap-5 min-h-0", children: STYLE_SECTION_KEYS.map((key) => {
46
91
  const items = style?.[key] ?? [];
47
- return (_jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": `style-section-${key}`, children: [_jsx("div", { className: "flex flex-col gap-1", children: items.length > 0 ? (items.map((item, index) => {
48
- const isDragging = dragStyleIndex?.key === key &&
49
- dragStyleIndex.index === index;
50
- return (_jsxs("fieldset", { draggable: true, onDragStart: (e) => {
51
- setDragStyleIndex({ key, index });
52
- e.dataTransfer.effectAllowed = "move";
53
- }, onDragOver: (e) => {
54
- if (dragStyleIndex === null ||
55
- dragStyleIndex.key !== key ||
56
- dragStyleIndex.index === index)
57
- return;
58
- e.preventDefault();
59
- e.dataTransfer.dropEffect = "move";
60
- }, onDrop: (e) => {
61
- e.preventDefault();
62
- if (dragStyleIndex === null ||
63
- dragStyleIndex.key !== key ||
64
- dragStyleIndex.index === index)
65
- return;
66
- handleReorderStyleEntries(key, reorderStyle(items, dragStyleIndex.index, index));
67
- setDragStyleIndex(null);
68
- }, onDragEnd: () => setDragStyleIndex(null), className: `group flex min-w-0 items-start gap-2 border-0 p-0 transition-opacity ${isDragging ? "opacity-40" : ""}`, children: [_jsx("span", { className: "mt-1 shrink-0 text-muted opacity-30 transition-opacity group-hover:opacity-80 cursor-grab active:cursor-grabbing select-none", "aria-hidden": "true", title: t("charactereditor.DragToReorder", {
69
- defaultValue: "Drag to reorder",
70
- }), children: _jsx(GripIconSvg, {}) }), _jsx("span", { className: "mt-0.5 shrink-0 text-2xs font-bold text-accent", children: index + 1 }), _jsx(Textarea, { value: styleEntryDrafts[key]?.[index] ?? item, rows: 1, onChange: (e) => handleStyleEntryDraftChange(key, index, e.target.value), onBlur: () => handleCommitStyleEntry(key, index), "aria-label": `${t(`charactereditor.StyleRules.${key}`, {
71
- defaultValue: "Style rule",
72
- })} ${index + 1}`, className: "min-w-0 flex-1 resize-none border-none bg-transparent p-0 font-mono text-xs leading-normal text-txt [field-sizing:content] min-h-[1.5em] focus-visible:outline-none focus-visible:shadow-none" }), _jsx(Button, { variant: "ghost", size: "icon", className: "mt-0.5 h-auto w-auto shrink-0 p-0 text-muted opacity-0 transition-[opacity,color] duration-150 hover:text-danger group-hover:opacity-100 focus-visible:opacity-100", onClick: () => handleRemoveStyleEntry(key, index), title: t("common.remove"), "aria-label": `${t("common.remove")} ${t(`charactereditor.StyleRules.${key}`, {
73
- defaultValue: "style rule",
74
- })} ${index + 1}`, children: _jsx(TrashIconSvg, {}) })] }, `${key}:${item}`));
75
- })) : (_jsx("div", { className: "py-3 text-xs-tight text-muted", children: t(STYLE_SECTION_EMPTY_STATES[key].key, {
92
+ const duplicateIndices = getDuplicateIndices(items);
93
+ const groupedItems = STYLE_INTENT_GROUPS.map((group) => ({
94
+ ...group,
95
+ entries: items
96
+ .map((item, index) => ({ item, index }))
97
+ .filter(({ item }) => getStyleIntentGroupId(item) === group.id),
98
+ })).filter((group) => group.entries.length > 0);
99
+ return (_jsxs("div", { className: "flex flex-col gap-3", "data-testid": `style-section-${key}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-muted", children: [_jsxs("span", { className: "rounded-sm border border-border/40 px-2 py-1", children: [items.length, " ", t("charactereditor.StyleRuleCount", {
100
+ defaultValue: "rules",
101
+ })] }), duplicateIndices.size > 0 ? (_jsxs("span", { className: "rounded-sm border border-warning/50 bg-warning/10 px-2 py-1 text-warning", children: [duplicateIndices.size, " ", t("charactereditor.PossibleDuplicates", {
102
+ defaultValue: "possible duplicates",
103
+ })] })) : null] }), _jsx("div", { className: "flex flex-col gap-3", children: items.length > 0 ? (groupedItems.map((group) => (_jsxs("section", { className: "flex min-w-0 flex-col gap-2", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-1", children: [_jsx("h4", { className: "text-xs font-semibold text-txt", children: group.label }), _jsx("span", { className: "text-[0.68rem] text-muted", children: group.hint })] }), _jsx("div", { className: "flex flex-col gap-2", children: group.entries.map(({ item, index }) => {
104
+ const isDragging = dragStyleIndex?.key === key &&
105
+ dragStyleIndex.index === index;
106
+ const isDuplicate = duplicateIndices.has(index);
107
+ return (_jsxs("fieldset", { draggable: true, onDragStart: (e) => {
108
+ setDragStyleIndex({ key, index });
109
+ e.dataTransfer.effectAllowed = "move";
110
+ }, onDragOver: (e) => {
111
+ if (dragStyleIndex === null ||
112
+ dragStyleIndex.key !== key ||
113
+ dragStyleIndex.index === index)
114
+ return;
115
+ e.preventDefault();
116
+ e.dataTransfer.dropEffect = "move";
117
+ }, onDrop: (e) => {
118
+ e.preventDefault();
119
+ if (dragStyleIndex === null ||
120
+ dragStyleIndex.key !== key ||
121
+ dragStyleIndex.index === index)
122
+ return;
123
+ handleReorderStyleEntries(key, reorderStyle(items, dragStyleIndex.index, index));
124
+ setDragStyleIndex(null);
125
+ }, onDragEnd: () => setDragStyleIndex(null), className: `group flex min-w-0 items-center gap-2 rounded-md border p-2.5 transition-opacity ${isDuplicate
126
+ ? "border-warning/50 bg-warning/5"
127
+ : "border-border/35 bg-bg-muted/20"} ${isDragging ? "opacity-40" : ""}`, children: [_jsx("span", { className: "shrink-0 text-muted opacity-60 cursor-grab active:cursor-grabbing select-none", "aria-hidden": "true", title: t("charactereditor.DragToReorder", {
128
+ defaultValue: "Drag to reorder",
129
+ }), children: _jsx(GripIconSvg, {}) }), _jsx(Input, { value: styleEntryDrafts[key]?.[index] ?? item, onChange: (e) => handleStyleEntryDraftChange(key, index, e.target.value), onBlur: () => handleCommitStyleEntry(key, index), "aria-label": `${t(`charactereditor.StyleRules.${key}`, {
130
+ defaultValue: "Style rule",
131
+ })} ${index + 1}`, className: "h-9 min-w-0 flex-1 rounded-sm border border-border/25 bg-bg/60 px-2 text-sm text-txt focus-visible:border-accent/60 focus-visible:ring-0" }), isDuplicate ? (_jsx("span", { className: "shrink-0 rounded-sm bg-warning/15 px-1.5 py-0.5 text-[0.68rem] font-medium text-warning", children: t("charactereditor.DuplicateRule", {
132
+ defaultValue: "duplicate",
133
+ }) })) : null, _jsx("div", { className: "flex shrink-0 items-center", children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "h-7 w-7 shrink-0 rounded-sm border border-border/35 p-0 text-muted transition-colors hover:border-danger/45 hover:bg-danger/10 hover:text-danger", onClick: () => handleRemoveStyleEntry(key, index), title: t("common.remove"), "aria-label": `${t("common.remove")} ${t(`charactereditor.StyleRules.${key}`, {
134
+ defaultValue: "style rule",
135
+ })} ${index + 1}`, children: _jsx(TrashIconSvg, {}) }) })] }, `${key}:${index}`));
136
+ }) })] }, group.id)))) : (_jsx("div", { className: "rounded-md border border-dashed border-border/40 bg-bg-muted/20 px-3 py-4 text-sm text-muted", children: t(STYLE_SECTION_EMPTY_STATES[key].key, {
76
137
  defaultValue: STYLE_SECTION_EMPTY_STATES[key].defaultValue,
77
138
  }) })) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { type: "text", value: pendingStyleEntries[key], placeholder: t(STYLE_SECTION_PLACEHOLDERS[key].key, {
78
139
  defaultValue: STYLE_SECTION_PLACEHOLDERS[key].defaultValue,
@@ -81,25 +142,50 @@ export function CharacterStylePanel({ d, pendingStyleEntries, styleEntryDrafts,
81
142
  e.preventDefault();
82
143
  handleAddStyleEntry(key);
83
144
  }
84
- }, className: "h-7 min-w-0 flex-1 rounded-none border-0 border-b border-border/40 bg-transparent px-0 font-mono text-xs-tight text-txt outline-none focus:border-accent" }), _jsx("button", { type: "button", className: inlineAddBtn, onClick: () => handleAddStyleEntry(key), disabled: !pendingStyleEntries[key].trim(), title: t("charactereditor.AddStyleRule", {
145
+ }, className: "h-9 min-w-0 flex-1 rounded-md border border-border/40 bg-bg/70 px-3 text-sm text-txt outline-none focus:border-accent" }), _jsxs("button", { type: "button", className: "inline-flex h-9 shrink-0 items-center gap-2 rounded-md border border-accent/35 px-3 text-sm font-medium text-accent transition-colors hover:bg-accent/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent/60 disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent", onClick: () => handleAddStyleEntry(key), disabled: !pendingStyleEntries[key].trim(), title: t("charactereditor.AddStyleRule", {
85
146
  defaultValue: "Add style rule",
86
147
  }), "aria-label": t("charactereditor.AddStyleRule", {
87
148
  defaultValue: "Add style rule",
88
- }), children: _jsx(PlusIconSvg, {}) })] })] }, key));
149
+ }), children: [_jsx(PlusIconSvg, {}), t("charactereditor.AddStyleRuleShort", {
150
+ defaultValue: "Add rule",
151
+ })] })] })] }, key));
89
152
  }) })] }));
90
153
  }
91
154
  /* ── CharacterExamplesPanel ──────────────────────────────────────── */
92
155
  export function CharacterExamplesPanel({ d, normalizedMessageExamples, handleFieldEdit, t, }) {
93
156
  const [dragPostIndex, setDragPostIndex] = useState(null);
157
+ const postExamples = d.postExamples ?? [];
158
+ const duplicatePostIndices = getDuplicateIndices(postExamples);
94
159
  const reorder = (list, from, to) => {
95
160
  const next = [...list];
96
161
  const [moved] = next.splice(from, 1);
97
162
  next.splice(to, 0, moved);
98
163
  return next;
99
164
  };
100
- return (_jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs("section", { className: "flex flex-col gap-3", children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.08em] text-muted", children: t("charactereditor.ChatExamples", {
101
- defaultValue: "Chat Examples",
102
- }) }), _jsxs("div", { className: "flex flex-col divide-y divide-border/30", children: [normalizedMessageExamples.map((convo, ci) => (_jsxs("div", { className: "flex flex-col gap-1.5 py-2.5 first:pt-0 last:pb-0", children: [convo.examples.map((msg, mi) => (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(GripIconSvg, {}), _jsx("span", { className: `w-12 shrink-0 pr-1 text-right text-[0.5rem] font-semibold uppercase tracking-[0.06em] ${msg.name === "{{user1}}" ? "text-muted" : "text-accent"}`, children: msg.name === "{{user1}}" ? "user" : "agent" }), _jsx(Input, { value: msg.content?.text ?? "", "aria-label": `${msg.name === "{{user1}}" ? "User" : "Agent"} message, conversation ${ci + 1}, turn ${mi + 1}`, onChange: (e) => {
165
+ const movePostExample = (from, to) => {
166
+ if (to < 0 || to >= postExamples.length)
167
+ return;
168
+ handleFieldEdit("postExamples", reorder(postExamples, from, to));
169
+ };
170
+ return (_jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs("section", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-2", children: [_jsxs("div", { children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.08em] text-muted", children: t("charactereditor.ChatExamples", {
171
+ defaultValue: "Chat Examples",
172
+ }) }), _jsx("p", { className: "mt-1 text-xs text-muted", children: t("charactereditor.ChatExamplesHelp", {
173
+ defaultValue: "Example conversations grouped by channel and speaker.",
174
+ }) })] }), _jsxs("span", { className: "rounded-sm border border-border/40 px-2 py-1 text-xs text-muted", children: [normalizedMessageExamples.length, " ", t("charactereditor.ConversationCount", {
175
+ defaultValue: "conversations",
176
+ })] })] }), _jsxs("div", { className: "flex flex-col gap-3", children: [normalizedMessageExamples.map((convo, ci) => (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border border-border/35 bg-bg-muted/15 p-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("h4", { className: "text-xs font-semibold text-txt", children: [t("charactereditor.ChatConversation", {
177
+ defaultValue: "Conversation",
178
+ }), " ", ci + 1] }), _jsxs("span", { className: "text-[0.68rem] text-muted", children: [convo.examples.length, " ", t("charactereditor.TurnCount", {
179
+ defaultValue: "turns",
180
+ })] })] }), _jsx("button", { type: "button", className: compactIconBtn, onClick: () => {
181
+ const updated = [...normalizedMessageExamples];
182
+ updated.splice(ci, 1);
183
+ handleFieldEdit("messageExamples", updated);
184
+ }, title: t("charactereditor.RemoveExample", {
185
+ defaultValue: "Remove conversation",
186
+ }), "aria-label": `${t("common.remove")} conversation ${ci + 1}`, children: _jsx(TrashIconSvg, {}) })] }), convo.examples.map((msg, mi) => (_jsxs("div", { className: "grid min-w-0 grid-cols-[4.5rem_1fr] items-start gap-2", children: [_jsx("span", { className: `mt-2 rounded-sm border px-2 py-1 text-center text-[0.68rem] font-semibold uppercase tracking-[0.06em] ${msg.name === "{{user1}}"
187
+ ? "border-border/40 text-muted"
188
+ : "border-accent/35 bg-accent/10 text-accent"}`, children: msg.name === "{{user1}}" ? "user" : "agent" }), _jsx(Textarea, { value: msg.content?.text ?? "", rows: 2, "aria-label": `${msg.name === "{{user1}}" ? "User" : "Agent"} message, conversation ${ci + 1}, turn ${mi + 1}`, onChange: (e) => {
103
189
  const updated = [...normalizedMessageExamples];
104
190
  const convoClone = {
105
191
  examples: [...updated[ci].examples],
@@ -110,33 +196,29 @@ export function CharacterExamplesPanel({ d, normalizedMessageExamples, handleFie
110
196
  };
111
197
  updated[ci] = convoClone;
112
198
  handleFieldEdit("messageExamples", updated);
113
- }, className: "h-7 flex-1 rounded-none border-0 border-b border-border/40 bg-transparent px-0 text-xs-tight leading-tight text-txt outline-none focus:border-accent" })] }, `msg-${ci}-${mi}`))), _jsxs("div", { className: "mt-0.5 ml-[4.25rem] flex items-center justify-between", children: [_jsx("button", { type: "button", className: inlineAddBtn, onClick: () => {
114
- const agentName = typeof d.name === "string" && d.name.trim()
115
- ? d.name.trim()
116
- : "Agent";
117
- const updated = [...normalizedMessageExamples];
118
- const convoClone = {
119
- examples: [
120
- ...updated[ci].examples,
121
- { name: "{{user1}}", content: { text: "" } },
122
- { name: agentName, content: { text: "" } },
123
- ],
124
- };
125
- updated[ci] = convoClone;
126
- handleFieldEdit("messageExamples", updated);
127
- }, title: t("charactereditor.AddTurn", {
199
+ }, className: "min-h-[3rem] w-full resize-y rounded-sm border border-border/30 bg-bg/70 px-2 py-1.5 text-sm leading-relaxed text-txt focus-visible:border-accent/60 focus-visible:ring-0" })] }, `msg-${ci}-${mi}`))), _jsx("div", { className: "mt-1 flex items-center justify-between gap-2", children: _jsxs("button", { type: "button", className: "inline-flex h-8 items-center gap-2 rounded-md border border-border/40 px-2.5 text-xs font-medium text-txt transition-colors hover:bg-bg-muted/70 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent/60", onClick: () => {
200
+ const agentName = typeof d.name === "string" && d.name.trim()
201
+ ? d.name.trim()
202
+ : "Agent";
203
+ const updated = [...normalizedMessageExamples];
204
+ const convoClone = {
205
+ examples: [
206
+ ...updated[ci].examples,
207
+ { name: "{{user1}}", content: { text: "" } },
208
+ { name: agentName, content: { text: "" } },
209
+ ],
210
+ };
211
+ updated[ci] = convoClone;
212
+ handleFieldEdit("messageExamples", updated);
213
+ }, title: t("charactereditor.AddTurn", {
214
+ defaultValue: "Add turn",
215
+ }), "aria-label": t("charactereditor.AddTurn", {
216
+ defaultValue: "Add turn",
217
+ }), children: [_jsx(PlusIconSvg, {}), t("charactereditor.AddTurn", {
128
218
  defaultValue: "Add turn",
129
- }), "aria-label": t("charactereditor.AddTurn", {
130
- defaultValue: "Add turn",
131
- }), children: _jsx(PlusIconSvg, {}) }), _jsx("button", { type: "button", className: inlineIconBtn, onClick: () => {
132
- const updated = [...normalizedMessageExamples];
133
- updated.splice(ci, 1);
134
- handleFieldEdit("messageExamples", updated);
135
- }, title: t("charactereditor.RemoveExample", {
136
- defaultValue: "Remove conversation",
137
- }), "aria-label": `${t("common.remove")} conversation ${ci + 1}`, children: _jsx(TrashIconSvg, {}) })] })] }, `convo-${ci}`))), normalizedMessageExamples.length === 0 && (_jsx("div", { className: "py-3 text-xs-tight text-muted", children: t("charactereditor.NoChatExamples", {
219
+ })] }) })] }, `convo-${ci}`))), normalizedMessageExamples.length === 0 && (_jsx("div", { className: "rounded-md border border-dashed border-border/40 bg-bg-muted/20 px-3 py-4 text-sm text-muted", children: t("charactereditor.NoChatExamples", {
138
220
  defaultValue: "No chat examples yet.",
139
- }) }))] }), _jsx("button", { type: "button", className: `${inlineAddBtn} self-start mt-1`, onClick: () => {
221
+ }) }))] }), _jsxs("button", { type: "button", className: "inline-flex h-9 self-start items-center gap-2 rounded-md border border-accent/35 px-3 text-sm font-medium text-accent transition-colors hover:bg-accent/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent/60", onClick: () => {
140
222
  const agentName = typeof d.name === "string" && d.name.trim()
141
223
  ? d.name.trim()
142
224
  : "Agent";
@@ -154,10 +236,19 @@ export function CharacterExamplesPanel({ d, normalizedMessageExamples, handleFie
154
236
  defaultValue: "Add conversation",
155
237
  }), "aria-label": t("charactereditor.AddConversation", {
156
238
  defaultValue: "Add conversation",
157
- }), children: _jsx(PlusIconSvg, {}) })] }), _jsxs("section", { className: "flex flex-col gap-3", children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.08em] text-muted", children: t("charactereditor.PostExamples", {
158
- defaultValue: "Post Examples",
159
- }) }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [(d.postExamples ?? []).map((post, pi) => {
239
+ }), children: [_jsx(PlusIconSvg, {}), t("charactereditor.AddConversation", {
240
+ defaultValue: "Add conversation",
241
+ })] })] }), _jsxs("section", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-2", children: [_jsxs("div", { children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.08em] text-muted", children: t("charactereditor.PostExamples", {
242
+ defaultValue: "Post Examples",
243
+ }) }), _jsx("p", { className: "mt-1 text-xs text-muted", children: t("charactereditor.PostExamplesHelp", {
244
+ defaultValue: "Standalone post examples for social channels.",
245
+ }) })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-muted", children: [_jsxs("span", { className: "rounded-sm border border-border/40 px-2 py-1", children: [postExamples.length, " ", t("charactereditor.PostCount", {
246
+ defaultValue: "posts",
247
+ })] }), duplicatePostIndices.size > 0 ? (_jsxs("span", { className: "rounded-sm border border-warning/50 bg-warning/10 px-2 py-1 text-warning", children: [duplicatePostIndices.size, " ", t("charactereditor.PossibleDuplicates", {
248
+ defaultValue: "possible duplicates",
249
+ })] })) : null] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [postExamples.map((post, pi) => {
160
250
  const isDragging = dragPostIndex === pi;
251
+ const isDuplicate = duplicatePostIndices.has(pi);
161
252
  return (_jsxs("fieldset", { draggable: true, onDragStart: (e) => {
162
253
  setDragPostIndex(pi);
163
254
  e.dataTransfer.effectAllowed = "move";
@@ -170,29 +261,45 @@ export function CharacterExamplesPanel({ d, normalizedMessageExamples, handleFie
170
261
  e.preventDefault();
171
262
  if (dragPostIndex === null || dragPostIndex === pi)
172
263
  return;
173
- handleFieldEdit("postExamples", reorder(d.postExamples ?? [], dragPostIndex, pi));
264
+ handleFieldEdit("postExamples", reorder(postExamples, dragPostIndex, pi));
174
265
  setDragPostIndex(null);
175
- }, onDragEnd: () => setDragPostIndex(null), className: `group flex min-w-0 items-center gap-1.5 border-0 p-0 transition-opacity ${isDragging ? "opacity-40" : ""}`, children: [_jsx("span", { className: "text-muted opacity-30 transition-opacity group-hover:opacity-80 cursor-grab active:cursor-grabbing select-none", "aria-hidden": "true", title: t("charactereditor.DragToReorder", {
266
+ }, onDragEnd: () => setDragPostIndex(null), className: `group flex min-w-0 items-start gap-2 rounded-md border p-2.5 transition-opacity ${isDuplicate
267
+ ? "border-warning/50 bg-warning/5"
268
+ : "border-border/35 bg-bg-muted/15"} ${isDragging ? "opacity-40" : ""}`, children: [_jsx("span", { className: "mt-2 text-muted opacity-60 cursor-grab active:cursor-grabbing select-none", "aria-hidden": "true", title: t("charactereditor.DragToReorder", {
176
269
  defaultValue: "Drag to reorder",
177
- }), children: _jsx(GripIconSvg, {}) }), _jsx(Input, { value: post, "aria-label": `Post example ${pi + 1}`, onChange: (e) => {
178
- const updated = [...(d.postExamples ?? [])];
179
- updated[pi] = e.target.value;
180
- handleFieldEdit("postExamples", updated);
181
- }, className: "h-7 flex-1 rounded-none border-0 border-b border-border/40 bg-transparent px-0 text-xs-tight leading-tight text-txt outline-none focus:border-accent" }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-auto w-auto shrink-0 p-0 text-muted opacity-0 transition-[opacity,color] duration-150 hover:text-danger group-hover:opacity-100 focus-visible:opacity-100", onClick: () => {
182
- const updated = [...(d.postExamples ?? [])];
183
- updated.splice(pi, 1);
184
- handleFieldEdit("postExamples", updated);
185
- }, "aria-label": `${t("common.remove")} post ${pi + 1}`, title: t("charactereditor.RemovePost", {
186
- defaultValue: "Remove post",
187
- }), children: _jsx(TrashIconSvg, {}) })] }, `post-${pi}`));
188
- }), (d.postExamples ?? []).length === 0 && (_jsx("div", { className: "py-3 text-xs-tight text-muted", children: t("charactereditor.NoPostExamples", {
270
+ }), children: _jsx(GripIconSvg, {}) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [_jsxs("span", { className: "text-[0.68rem] font-semibold uppercase tracking-[0.06em] text-accent", children: [t("charactereditor.PostExample", {
271
+ defaultValue: "Post",
272
+ }), " ", "#", pi + 1] }), isDuplicate ? (_jsx("span", { className: "rounded-sm bg-warning/15 px-1.5 py-0.5 text-[0.68rem] font-medium text-warning", children: t("charactereditor.DuplicatePost", {
273
+ defaultValue: "duplicate",
274
+ }) })) : null] }), _jsx(Textarea, { value: post, rows: 3, "aria-label": `Post example ${pi + 1}`, onChange: (e) => {
275
+ const updated = [...postExamples];
276
+ updated[pi] = e.target.value;
277
+ handleFieldEdit("postExamples", updated);
278
+ }, className: "min-h-[4.25rem] w-full resize-y rounded-sm border border-border/30 bg-bg/70 px-2 py-1.5 text-sm leading-relaxed text-txt focus-visible:border-accent/60 focus-visible:ring-0" })] }), _jsxs("div", { className: "flex shrink-0 flex-col gap-1", children: [_jsx("button", { type: "button", className: compactIconBtn, onClick: () => movePostExample(pi, pi - 1), disabled: pi === 0, title: t("charactereditor.MovePostUp", {
279
+ defaultValue: "Move post up",
280
+ }), "aria-label": `${t("charactereditor.MovePostUp", {
281
+ defaultValue: "Move post up",
282
+ })} ${pi + 1}`, children: _jsx(ArrowUpIconSvg, {}) }), _jsx("button", { type: "button", className: compactIconBtn, onClick: () => movePostExample(pi, pi + 1), disabled: pi === postExamples.length - 1, title: t("charactereditor.MovePostDown", {
283
+ defaultValue: "Move post down",
284
+ }), "aria-label": `${t("charactereditor.MovePostDown", {
285
+ defaultValue: "Move post down",
286
+ })} ${pi + 1}`, children: _jsx(ArrowDownIconSvg, {}) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "h-7 w-7 shrink-0 rounded-sm border border-border/35 p-0 text-muted transition-colors hover:border-danger/45 hover:bg-danger/10 hover:text-danger", onClick: () => {
287
+ const updated = [...postExamples];
288
+ updated.splice(pi, 1);
289
+ handleFieldEdit("postExamples", updated);
290
+ }, "aria-label": `${t("common.remove")} post ${pi + 1}`, title: t("charactereditor.RemovePost", {
291
+ defaultValue: "Remove post",
292
+ }), children: _jsx(TrashIconSvg, {}) })] })] }, `post-${pi}`));
293
+ }), postExamples.length === 0 && (_jsx("div", { className: "rounded-md border border-dashed border-border/40 bg-bg-muted/20 px-3 py-4 text-sm text-muted", children: t("charactereditor.NoPostExamples", {
189
294
  defaultValue: "No post examples yet.",
190
- }) })), _jsx("button", { type: "button", className: `${inlineAddBtn} self-start mt-1`, onClick: () => {
191
- const updated = [...(d.postExamples ?? []), ""];
295
+ }) })), _jsxs("button", { type: "button", className: "mt-1 inline-flex h-9 self-start items-center gap-2 rounded-md border border-accent/35 px-3 text-sm font-medium text-accent transition-colors hover:bg-accent/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent/60", onClick: () => {
296
+ const updated = [...postExamples, ""];
192
297
  handleFieldEdit("postExamples", updated);
193
298
  }, title: t("charactereditor.AddPost", {
194
299
  defaultValue: "Add Post",
195
300
  }), "aria-label": t("charactereditor.AddPost", {
196
301
  defaultValue: "Add Post",
197
- }), children: _jsx(PlusIconSvg, {}) })] })] })] }));
302
+ }), children: [_jsx(PlusIconSvg, {}), t("charactereditor.AddPost", {
303
+ defaultValue: "Add Post",
304
+ })] })] })] })] }));
198
305
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CharacterExperienceWorkspace.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterExperienceWorkspace.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,uBAAuB,CAAC;AAoC/B,wBAAgB,4BAA4B,CAAC,EAC3C,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,EAAE;IACD,WAAW,EAAE,yBAAyB,EAAE,CAAC;IACzC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kBAAkB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,CAAC,EAAE,CACjB,UAAU,EAAE,yBAAyB,EACrC,KAAK,EAAE,wBAAwB,KAC5B,IAAI,CAAC;IACV,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,2CA+QA"}
1
+ {"version":3,"file":"CharacterExperienceWorkspace.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterExperienceWorkspace.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,uBAAuB,CAAC;AAqK/B,wBAAgB,4BAA4B,CAAC,EAC3C,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,EAAE;IACD,WAAW,EAAE,yBAAyB,EAAE,CAAC;IACzC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kBAAkB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,CAAC,EAAE,CACjB,UAAU,EAAE,yBAAyB,EACrC,KAAK,EAAE,wBAAwB,KAC5B,IAAI,CAAC;IACV,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,2CAiqBA"}