@taskforcehq/taskforce 0.3.332 → 0.3.333
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/routes/localService.js +1 -0
- package/dist/server/routes/syncPushRoutes.d.ts +3 -0
- package/dist/server/routes/syncPushRoutes.js +8 -2
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +1 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +7 -6
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +2 -2
- package/dist/sync/engine/workspaceSyncEngineLocalApply.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +6 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +34 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +2 -2
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +4 -1
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +53 -10
- package/dist/sync/syncService.d.ts +1 -0
- package/dist/sync/syncService.js +5 -2
- package/dist/ui/assets/{AiIdentityRosterCard-CDMPtnbC.js → AiIdentityRosterCard-Cfvb9Nuv.js} +1 -1
- package/dist/ui/assets/{AiProfilesModule-Cww85C4E.js → AiProfilesModule-0oR70eFG.js} +1 -1
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-Dt9TKYSH.js → AnnotatedAttachmentWorkspace-C33iH_r_.js} +1 -1
- package/dist/ui/assets/{AssetTraySortControl-CKgapnxu.js → AssetTraySortControl-BAqxUtke.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-T-cEVcOZ.js → ContextAttachmentManager-BudIbOR9.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-HD4MUjAZ.js → DocumentWorkspace-A8dFQyId.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-_V0zfMuh.js → EntityActivityTimeline-g7vtdsx1.js} +1 -1
- package/dist/ui/assets/{PlanningModule-mTkBygsB.js → PlanningModule-D-DeQs4F.js} +1 -1
- package/dist/ui/assets/{PlansPage-Btiq06VO.js → PlansPage-BWmfGi0Z.js} +1 -1
- package/dist/ui/assets/{TaskContextUpload-C00NVUpn.js → TaskContextUpload-BA_lQmS9.js} +1 -1
- package/dist/ui/assets/{TaskSettings-Cp-L-4xh.js → TaskSettings-DAlH4YIP.js} +1 -1
- package/dist/ui/assets/{TaskforceAgentsModule-Coq9-PUp.js → TaskforceAgentsModule-DmeCf6pJ.js} +1 -1
- package/dist/ui/assets/{WorkflowManagerModule-CuqRzMmM.js → WorkflowManagerModule-p08eDOaa.js} +1 -1
- package/dist/ui/assets/index-GHJgcW3j.js +7 -0
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
- package/dist/ui/assets/index-DSQINwt9.js +0 -7
|
@@ -437,6 +437,7 @@ export function registerLocalServiceRoutes(deps) {
|
|
|
437
437
|
workspaceId: session.workspaceId,
|
|
438
438
|
core: deps.core,
|
|
439
439
|
serverName: 'taskforce-local-service',
|
|
440
|
+
version: context.appVersion,
|
|
440
441
|
logStartup: false,
|
|
441
442
|
runtimeMode: 'local',
|
|
442
443
|
operationIdentityScope: {
|
|
@@ -23,6 +23,8 @@ interface RegisterWorkspacePushSyncRoutesArgs {
|
|
|
23
23
|
coexistenceDirection?: 'cloud-push';
|
|
24
24
|
actorUserId?: string;
|
|
25
25
|
assertedActiveV3TaskMetadataIds?: ReadonlySet<string>;
|
|
26
|
+
assertedActiveV3TaskDeleteIds?: ReadonlySet<string>;
|
|
27
|
+
candidateTerminalV3TaskDeleteIds?: ReadonlySet<string>;
|
|
26
28
|
assertedActiveV3TaskLifecycleIds?: ReadonlySet<string>;
|
|
27
29
|
assertedActiveV3TaskReopenAssigneeIds?: ReadonlySet<string>;
|
|
28
30
|
assertedActiveV3InitiativeIds?: ReadonlySet<string>;
|
|
@@ -31,6 +33,7 @@ interface RegisterWorkspacePushSyncRoutesArgs {
|
|
|
31
33
|
result: any;
|
|
32
34
|
deleteCount: number;
|
|
33
35
|
emittedEventIds: string[];
|
|
36
|
+
settledTaskDeleteIds?: string[];
|
|
34
37
|
}>;
|
|
35
38
|
}
|
|
36
39
|
export interface WorkspaceSyncPushAppliedTaskUpsert {
|
|
@@ -211,6 +211,9 @@ export function registerWorkspacePushSyncRoutes({ addRoute, core, context, audit
|
|
|
211
211
|
code: 'SYNC_V2_PROJECTION_BOUNDARY_MISMATCH', statusCode: 409,
|
|
212
212
|
});
|
|
213
213
|
}
|
|
214
|
+
const candidateTerminalV3TaskDeleteIds = v2ExcludedProjections.includes('task/root-v1')
|
|
215
|
+
? incomingTaskUpsertIdSet
|
|
216
|
+
: new Set();
|
|
214
217
|
if (typeof process !== 'undefined' && process.env?.TASKFORCE_SYNC_KEY) {
|
|
215
218
|
const syncKey = process.env.TASKFORCE_SYNC_KEY;
|
|
216
219
|
const decryptedChanges = [];
|
|
@@ -267,11 +270,12 @@ export function registerWorkspacePushSyncRoutes({ addRoute, core, context, audit
|
|
|
267
270
|
code: 'WORKSPACE_SYNC_V3_INITIATIVE_LEGACY_PUSH_DISABLED', statusCode: 409,
|
|
268
271
|
});
|
|
269
272
|
}
|
|
270
|
-
const { result, deleteCount, emittedEventIds } = await dispatchWorkspaceSyncChanges(targetWorkspaceId, incomingChanges, {
|
|
273
|
+
const { result, deleteCount, emittedEventIds, settledTaskDeleteIds = [], } = await dispatchWorkspaceSyncChanges(targetWorkspaceId, incomingChanges, {
|
|
271
274
|
allowReferenceNumberReassignment,
|
|
272
275
|
coexistenceDirection: 'cloud-push',
|
|
273
276
|
actorUserId: String(access.userId || '').trim(),
|
|
274
277
|
assertedActiveV3TaskMetadataIds,
|
|
278
|
+
candidateTerminalV3TaskDeleteIds,
|
|
275
279
|
assertedActiveV3TaskLifecycleIds,
|
|
276
280
|
assertedActiveV3TaskReopenAssigneeIds,
|
|
277
281
|
assertedActiveV3InitiativeIds,
|
|
@@ -281,8 +285,9 @@ export function registerWorkspacePushSyncRoutes({ addRoute, core, context, audit
|
|
|
281
285
|
let appliedTaskUpserts;
|
|
282
286
|
try {
|
|
283
287
|
const durabilityStore = new WorkspaceSyncDurabilityStore(core.getDatabaseAdapter());
|
|
288
|
+
const settledTaskDeleteIdSet = new Set(settledTaskDeleteIds);
|
|
284
289
|
appliedTaskUpserts = readWorkspaceSyncPushAppliedTaskUpserts({
|
|
285
|
-
taskIds: incomingTaskUpsertIds,
|
|
290
|
+
taskIds: incomingTaskUpsertIds.filter((taskId) => !settledTaskDeleteIdSet.has(taskId)),
|
|
286
291
|
getTask: (taskId) => core.getTask(taskId, targetWorkspaceId),
|
|
287
292
|
listTaskRevisionProjections: (taskIds) => (durabilityStore.listTaskRevisionProjections({
|
|
288
293
|
tenantId: core.getTenantId(),
|
|
@@ -306,6 +311,7 @@ export function registerWorkspacePushSyncRoutes({ addRoute, core, context, audit
|
|
|
306
311
|
idempotencyKey: idempotencyKey || null,
|
|
307
312
|
emittedEventIds,
|
|
308
313
|
appliedTaskUpserts,
|
|
314
|
+
...(settledTaskDeleteIds.length > 0 ? { settledTaskDeleteIds } : {}),
|
|
309
315
|
result,
|
|
310
316
|
suppressedV2ProjectionCounts,
|
|
311
317
|
durationMs
|
|
@@ -82,6 +82,7 @@ export interface LocalWorkspaceSyncSettledV2PushBatch {
|
|
|
82
82
|
task: WorkspaceSyncTaskSnapshot;
|
|
83
83
|
durableRevision?: WorkspaceSyncDurableTaskRevision;
|
|
84
84
|
}>;
|
|
85
|
+
settledTaskDeleteIds?: string[];
|
|
85
86
|
}
|
|
86
87
|
export interface LocalWorkspaceSyncPendingV2PushBatchProgress {
|
|
87
88
|
totalBatches: number;
|
|
@@ -528,11 +528,7 @@ function isPendingV2Push(value) {
|
|
|
528
528
|
&& settledBatchOperationIdentities.every((identity) => /^[a-f0-9]{64}$/.test(identity))
|
|
529
529
|
&& settledBatchContributions !== null
|
|
530
530
|
&& settledBatchContributions.every((entry) => (isRecord(entry)
|
|
531
|
-
&&
|
|
532
|
-
'operationIdentity',
|
|
533
|
-
'settlementIdentityFingerprint',
|
|
534
|
-
'appliedTaskUpserts',
|
|
535
|
-
])
|
|
531
|
+
&& hasRequiredAndAllowedKeys(entry, ['operationIdentity', 'settlementIdentityFingerprint', 'appliedTaskUpserts'], ['settledTaskDeleteIds'])
|
|
536
532
|
&& typeof entry.operationIdentity === 'string'
|
|
537
533
|
&& /^[a-f0-9]{64}$/.test(entry.operationIdentity)
|
|
538
534
|
&& typeof entry.settlementIdentityFingerprint === 'string'
|
|
@@ -545,7 +541,11 @@ function isPendingV2Push(value) {
|
|
|
545
541
|
&& isNonEmptyText(upsert.task.id)
|
|
546
542
|
&& isJson(upsert.task)
|
|
547
543
|
&& (upsert.durableRevision === undefined
|
|
548
|
-
|| (isRecord(upsert.durableRevision) && isJson(upsert.durableRevision)))))
|
|
544
|
+
|| (isRecord(upsert.durableRevision) && isJson(upsert.durableRevision)))))
|
|
545
|
+
&& (entry.settledTaskDeleteIds === undefined
|
|
546
|
+
|| (isStringArray(entry.settledTaskDeleteIds)
|
|
547
|
+
&& new Set(entry.settledTaskDeleteIds).size
|
|
548
|
+
=== entry.settledTaskDeleteIds.length))))
|
|
549
549
|
&& new Set(settledBatchContributions.map((entry) => entry.operationIdentity)).size === settledBatchContributions.length
|
|
550
550
|
&& settledBatchContributions.every((entry) => (settledBatchOperationIdentities.includes(entry.operationIdentity))));
|
|
551
551
|
const settlementContributionsMatchPlan = hasLegacyShape || (preparedPlan !== null
|
|
@@ -563,6 +563,7 @@ function isPendingV2Push(value) {
|
|
|
563
563
|
operationIdentity: entry.operationIdentity,
|
|
564
564
|
changes,
|
|
565
565
|
appliedTaskUpserts: entry.appliedTaskUpserts,
|
|
566
|
+
settledTaskDeleteIds: entry.settledTaskDeleteIds,
|
|
566
567
|
excludedProjections: preparedPlan.ownership.combinedExcludedProjections,
|
|
567
568
|
})) === entry.settlementIdentityFingerprint;
|
|
568
569
|
}
|
|
@@ -2,7 +2,7 @@ import { workspaceSyncGatewayOperationClassFor, workspaceSyncGatewayTimeoutMs, }
|
|
|
2
2
|
import { canonicalWorkspaceSyncJson } from '../v3/canonicalWorkspaceSyncJson.js';
|
|
3
3
|
import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR, resolveWorkspaceSyncV3CombinedCoverageForExclusions, } from '../v3/workspaceSyncV3CombinedWireContract.js';
|
|
4
4
|
import { WORKSPACE_SYNC_ENGINE_TRANSFER_COMPLETION_VERSION, } from './workspaceSyncEngineTransferCompletion.js';
|
|
5
|
-
import {
|
|
5
|
+
import { parseWorkspaceSyncEnginePushTaskSettlement, parseWorkspaceSyncEngineV2PushBoundary, workspaceSyncEngineExpectedTaskEchoIds, } from './workspaceSyncEnginePushCompletion.js';
|
|
6
6
|
const PERMIT_DEADLINE_SLACK_MS = 5_000;
|
|
7
7
|
function isPlainObject(value) {
|
|
8
8
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -388,7 +388,7 @@ export function createBrowserGatewayWorkspaceSyncEngineRemoteServices(options) {
|
|
|
388
388
|
requireAcceptedJsonObject: true,
|
|
389
389
|
validateAcceptedData: (value) => {
|
|
390
390
|
try {
|
|
391
|
-
|
|
391
|
+
parseWorkspaceSyncEnginePushTaskSettlement(value, expectedTaskEchoIds);
|
|
392
392
|
return true;
|
|
393
393
|
}
|
|
394
394
|
catch {
|
|
@@ -11,6 +11,7 @@ export interface WorkspaceSyncEngineLocalApplyResult {
|
|
|
11
11
|
result: unknown;
|
|
12
12
|
deleteCount: number;
|
|
13
13
|
emittedEventIds: string[];
|
|
14
|
+
settledTaskDeleteIds?: string[];
|
|
14
15
|
}
|
|
15
16
|
export interface WorkspaceSyncEngineLocalContentReader {
|
|
16
17
|
loadDocument(workspaceId: string, path: string): Promise<{
|
|
@@ -19,10 +19,15 @@ export interface WorkspaceSyncEngineAppliedTaskUpsert {
|
|
|
19
19
|
}
|
|
20
20
|
export declare function workspaceSyncEngineExpectedTaskEchoIds(changes: readonly WorkspaceSyncChange[]): string[];
|
|
21
21
|
export declare function parseWorkspaceSyncEngineAppliedTaskUpserts(value: unknown, expectedTaskIds: readonly string[]): WorkspaceSyncEngineAppliedTaskUpsert[];
|
|
22
|
+
export declare function parseWorkspaceSyncEnginePushTaskSettlement(value: unknown, expectedTaskIds: readonly string[]): {
|
|
23
|
+
appliedTaskUpserts: WorkspaceSyncEngineAppliedTaskUpsert[];
|
|
24
|
+
settledTaskDeleteIds: string[];
|
|
25
|
+
};
|
|
22
26
|
export declare function createWorkspaceSyncEngineV2SettlementIdentityProjection(input: {
|
|
23
27
|
operationIdentity: string;
|
|
24
28
|
changes: readonly WorkspaceSyncChange[];
|
|
25
29
|
appliedTaskUpserts: readonly WorkspaceSyncEngineAppliedTaskUpsert[];
|
|
30
|
+
settledTaskDeleteIds?: readonly string[];
|
|
26
31
|
excludedProjections?: readonly WorkspaceSyncV2ProjectionExclusion[];
|
|
27
32
|
}): {
|
|
28
33
|
version: 1;
|
|
@@ -31,4 +36,5 @@ export declare function createWorkspaceSyncEngineV2SettlementIdentityProjection(
|
|
|
31
36
|
archived: boolean;
|
|
32
37
|
task: Record<string, unknown>;
|
|
33
38
|
}>;
|
|
39
|
+
settledTaskDeleteIds?: string[];
|
|
34
40
|
};
|
|
@@ -86,6 +86,28 @@ export function parseWorkspaceSyncEngineAppliedTaskUpserts(value, expectedTaskId
|
|
|
86
86
|
}
|
|
87
87
|
return normalized;
|
|
88
88
|
}
|
|
89
|
+
export function parseWorkspaceSyncEnginePushTaskSettlement(value, expectedTaskIds) {
|
|
90
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
91
|
+
throw new TypeError('The V2 push authoritative echo response is invalid.');
|
|
92
|
+
}
|
|
93
|
+
const source = value;
|
|
94
|
+
const settledTaskDeleteIds = source.settledTaskDeleteIds === undefined
|
|
95
|
+
? []
|
|
96
|
+
: source.settledTaskDeleteIds;
|
|
97
|
+
if (!Array.isArray(settledTaskDeleteIds)
|
|
98
|
+
|| settledTaskDeleteIds.some((taskId) => (typeof taskId !== 'string'
|
|
99
|
+
|| taskId.trim().length === 0
|
|
100
|
+
|| taskId !== taskId.trim()))
|
|
101
|
+
|| new Set(settledTaskDeleteIds).size !== settledTaskDeleteIds.length
|
|
102
|
+
|| settledTaskDeleteIds.some((taskId) => !expectedTaskIds.includes(taskId))) {
|
|
103
|
+
throw new TypeError('The V2 push terminal task settlement identities are invalid.');
|
|
104
|
+
}
|
|
105
|
+
const settledIds = new Set(settledTaskDeleteIds);
|
|
106
|
+
return {
|
|
107
|
+
appliedTaskUpserts: parseWorkspaceSyncEngineAppliedTaskUpserts(value, expectedTaskIds.filter((taskId) => !settledIds.has(taskId))),
|
|
108
|
+
settledTaskDeleteIds: [...settledTaskDeleteIds],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
89
111
|
function taskSettlementProjection(task, preserveReferenceNumber) {
|
|
90
112
|
const { updatedAt: _updatedAt, ...stableTask } = structuredClone(task);
|
|
91
113
|
if (!preserveReferenceNumber)
|
|
@@ -136,7 +158,17 @@ export function createWorkspaceSyncEngineV2SettlementIdentityProjection(input) {
|
|
|
136
158
|
if (!operationIdentity || operationIdentity !== input.operationIdentity) {
|
|
137
159
|
throw new TypeError('The V2 push settlement operation identity is invalid.');
|
|
138
160
|
}
|
|
139
|
-
const
|
|
161
|
+
const allExpectedTaskUpserts = input.changes.filter((change) => change.op === 'upsert');
|
|
162
|
+
const expectedTaskIds = allExpectedTaskUpserts.map((change) => String(change.task.id || '').trim());
|
|
163
|
+
const settledTaskDeleteIds = [...(input.settledTaskDeleteIds || [])];
|
|
164
|
+
if ((settledTaskDeleteIds.length > 0
|
|
165
|
+
&& !input.excludedProjections?.includes('task/root-v1'))
|
|
166
|
+
|| settledTaskDeleteIds.some((taskId) => !expectedTaskIds.includes(taskId))
|
|
167
|
+
|| new Set(settledTaskDeleteIds).size !== settledTaskDeleteIds.length) {
|
|
168
|
+
throw new TypeError('The V2 push terminal task settlement identities are invalid.');
|
|
169
|
+
}
|
|
170
|
+
const settledIds = new Set(settledTaskDeleteIds);
|
|
171
|
+
const expectedTaskUpserts = allExpectedTaskUpserts.filter((change) => !settledIds.has(String(change.task.id || '').trim()));
|
|
140
172
|
if (expectedTaskUpserts.length !== input.appliedTaskUpserts.length) {
|
|
141
173
|
throw new TypeError('The V2 push authoritative settlement projection is incomplete.');
|
|
142
174
|
}
|
|
@@ -167,5 +199,6 @@ export function createWorkspaceSyncEngineV2SettlementIdentityProjection(input) {
|
|
|
167
199
|
version: 1,
|
|
168
200
|
operationIdentity,
|
|
169
201
|
taskUpserts: expectedProjection,
|
|
202
|
+
...(settledTaskDeleteIds.length > 0 ? { settledTaskDeleteIds } : {}),
|
|
170
203
|
};
|
|
171
204
|
}
|
|
@@ -2,7 +2,7 @@ import { workspaceSyncGatewayOperationClassFor, workspaceSyncGatewayTimeoutMs, }
|
|
|
2
2
|
import { canonicalWorkspaceSyncJson } from '../v3/canonicalWorkspaceSyncJson.js';
|
|
3
3
|
import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR, resolveWorkspaceSyncV3CombinedCoverageForExclusions, } from '../v3/workspaceSyncV3CombinedWireContract.js';
|
|
4
4
|
import { WORKSPACE_SYNC_ENGINE_TRANSFER_COMPLETION_VERSION, } from './workspaceSyncEngineTransferCompletion.js';
|
|
5
|
-
import {
|
|
5
|
+
import { parseWorkspaceSyncEnginePushTaskSettlement, parseWorkspaceSyncEngineV2PushBoundary, workspaceSyncEngineExpectedTaskEchoIds, } from './workspaceSyncEnginePushCompletion.js';
|
|
6
6
|
const PERMIT_DEADLINE_SLACK_MS = 5_000;
|
|
7
7
|
function isPlainObject(value) {
|
|
8
8
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -311,7 +311,7 @@ export function createServerWorkspaceSyncEngineRemoteServices(options) {
|
|
|
311
311
|
requireAcceptedJsonObject: true,
|
|
312
312
|
validateAcceptedData: (value) => {
|
|
313
313
|
try {
|
|
314
|
-
|
|
314
|
+
parseWorkspaceSyncEnginePushTaskSettlement(value, expectedTaskEchoIds);
|
|
315
315
|
return true;
|
|
316
316
|
}
|
|
317
317
|
catch {
|
|
@@ -623,7 +623,7 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
|
|
|
623
623
|
acknowledgedOperationIdentities.length;
|
|
624
624
|
}
|
|
625
625
|
},
|
|
626
|
-
onAcceptedBatchSettled: async ({ operationIdentity, settlementIdentityFingerprint, appliedTaskUpserts, transferReceipt, pushBoundary, excludedProjections, }) => {
|
|
626
|
+
onAcceptedBatchSettled: async ({ operationIdentity, settlementIdentityFingerprint, appliedTaskUpserts, settledTaskDeleteIds, transferReceipt, pushBoundary, excludedProjections, }) => {
|
|
627
627
|
const pendingV2Push = checkpoint.pendingV2Push;
|
|
628
628
|
if (!pendingV2Push
|
|
629
629
|
|| pendingV2Push.settlementVersion !== 1
|
|
@@ -661,6 +661,9 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
|
|
|
661
661
|
operationIdentity,
|
|
662
662
|
settlementIdentityFingerprint,
|
|
663
663
|
appliedTaskUpserts: structuredClone(appliedTaskUpserts),
|
|
664
|
+
...(settledTaskDeleteIds.length > 0 ? {
|
|
665
|
+
settledTaskDeleteIds: [...settledTaskDeleteIds],
|
|
666
|
+
} : {}),
|
|
664
667
|
},
|
|
665
668
|
],
|
|
666
669
|
},
|
|
@@ -17,6 +17,7 @@ export interface WorkspaceSyncV2DispatchOptions {
|
|
|
17
17
|
coexistenceDirection?: TaskMetadataCoexistenceDirection;
|
|
18
18
|
assertedActiveV3TaskMetadataIds?: ReadonlySet<string>;
|
|
19
19
|
assertedActiveV3TaskDeleteIds?: ReadonlySet<string>;
|
|
20
|
+
candidateTerminalV3TaskDeleteIds?: ReadonlySet<string>;
|
|
20
21
|
assertedActiveV3TaskLifecycleIds?: ReadonlySet<string>;
|
|
21
22
|
assertedActiveV3TaskReopenAssigneeIds?: ReadonlySet<string>;
|
|
22
23
|
assertedActiveV3Taxonomy?: boolean;
|
|
@@ -156,11 +156,40 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
156
156
|
throw createSyncRouteError('Cloud pull contained content from an excluded v2 projection.', { excludedProjections: Array.from(v2ExcludedProjections) }, { code: 'SYNC_V2_EXCLUDED_PROJECTION_PRESENT', statusCode: 409 });
|
|
157
157
|
}
|
|
158
158
|
const taskMutationsForApply = prepareWorkspaceSyncV2TaskCarriers(applyModel.taskMutations, v2ExcludedProjections, (taskId) => core.getTask(taskId, workspaceId));
|
|
159
|
-
if (v2ExcludedProjections.has('task/root-v1')
|
|
159
|
+
if (v2ExcludedProjections.has('task/root-v1')
|
|
160
|
+
&& !(options.coexistenceDirection === 'cloud-push'
|
|
161
|
+
&& options.candidateTerminalV3TaskDeleteIds?.size)) {
|
|
160
162
|
assertWorkspaceSyncV2TaskCarrierRootsExist(taskMutationsForApply, (taskId) => Boolean(core.getTask(taskId, workspaceId)));
|
|
161
163
|
}
|
|
162
164
|
return { applyModel, taskMutationsForApply, v2ExcludedProjections };
|
|
163
165
|
};
|
|
166
|
+
const resolveTaskCarrierSettlement = (workspaceId, taskMutations, ownership, options) => {
|
|
167
|
+
const candidates = options.coexistenceDirection === 'cloud-push'
|
|
168
|
+
? options.candidateTerminalV3TaskDeleteIds
|
|
169
|
+
: undefined;
|
|
170
|
+
if (!candidates?.size) {
|
|
171
|
+
return { taskMutationsForSettlement: taskMutations, settledTaskDeleteIds: [] };
|
|
172
|
+
}
|
|
173
|
+
const terminalOwnership = new Set(ownership
|
|
174
|
+
.filter((entry) => entry.activeDeleteOperation === true || entry.deleteOwned === true)
|
|
175
|
+
.map((entry) => entry.taskId));
|
|
176
|
+
const settledTaskDeleteIds = candidates
|
|
177
|
+
? taskMutations.upserts
|
|
178
|
+
.map((mutation) => mutation.task.id)
|
|
179
|
+
.filter((taskId) => (candidates.has(taskId)
|
|
180
|
+
&& terminalOwnership.has(taskId)
|
|
181
|
+
&& !core.getTask(taskId, workspaceId)))
|
|
182
|
+
: [];
|
|
183
|
+
const settledIds = new Set(settledTaskDeleteIds);
|
|
184
|
+
const taskMutationsForSettlement = settledIds.size > 0
|
|
185
|
+
? {
|
|
186
|
+
...taskMutations,
|
|
187
|
+
upserts: taskMutations.upserts.filter((mutation) => !settledIds.has(mutation.task.id)),
|
|
188
|
+
}
|
|
189
|
+
: taskMutations;
|
|
190
|
+
assertWorkspaceSyncV2TaskCarrierRootsExist(taskMutationsForSettlement, (taskId) => Boolean(core.getTask(taskId, workspaceId)));
|
|
191
|
+
return { taskMutationsForSettlement, settledTaskDeleteIds };
|
|
192
|
+
};
|
|
164
193
|
const prepareTaskSnapshotForDispatch = (workspaceId, taskMutationsForApply, v2ExcludedProjections, options) => {
|
|
165
194
|
const prepared = prepareTaskSyncSnapshotApply({
|
|
166
195
|
core,
|
|
@@ -335,14 +364,15 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
335
364
|
if (options.coexistenceDirection === 'cloud-push'
|
|
336
365
|
&& taskMutationsForApply.upserts.some((mutation) => mutation.durableRevision))
|
|
337
366
|
throw new Error('Task durable revisions are only accepted from the cloud pull feed.');
|
|
367
|
+
const { taskMutationsForSettlement, settledTaskDeleteIds, } = resolveTaskCarrierSettlement(workspaceId, taskMutationsForApply, ownership, options);
|
|
338
368
|
const durablePull = options.coexistenceDirection === 'local-pull'
|
|
339
369
|
? prepareDurableTaskPullMutations({
|
|
340
370
|
store: durabilityStore,
|
|
341
371
|
tenantId: core.getTenantId(),
|
|
342
372
|
workspaceId,
|
|
343
|
-
taskMutations:
|
|
373
|
+
taskMutations: taskMutationsForSettlement,
|
|
344
374
|
})
|
|
345
|
-
: { taskMutations:
|
|
375
|
+
: { taskMutations: taskMutationsForSettlement, pendingRevisions: [] };
|
|
346
376
|
const prepared = prepareTaskSyncSnapshotApply({
|
|
347
377
|
core,
|
|
348
378
|
workspaceId,
|
|
@@ -361,7 +391,7 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
361
391
|
ownership: durabilityStore.listTaskTaxonomyProjectionOwnership({
|
|
362
392
|
tenantId: core.getTenantId(),
|
|
363
393
|
workspaceId,
|
|
364
|
-
taskIds:
|
|
394
|
+
taskIds: taskMutationsForSettlement.upserts.map((mutation) => mutation.task.id),
|
|
365
395
|
}),
|
|
366
396
|
}),
|
|
367
397
|
v3OwnedTaskDeleteIds: resolveV3OwnedTaskDeleteIds({
|
|
@@ -396,7 +426,7 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
396
426
|
revisions: durablePull.pendingRevisions,
|
|
397
427
|
now: revisionNow,
|
|
398
428
|
});
|
|
399
|
-
return { prepared, result };
|
|
429
|
+
return { prepared, result, settledTaskDeleteIds };
|
|
400
430
|
},
|
|
401
431
|
});
|
|
402
432
|
})()
|
|
@@ -407,6 +437,7 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
407
437
|
workspaceId,
|
|
408
438
|
prepared: preparedTaskSnapshot,
|
|
409
439
|
}),
|
|
440
|
+
settledTaskDeleteIds: [],
|
|
410
441
|
};
|
|
411
442
|
const result = finalPreparedTaskSnapshot.result;
|
|
412
443
|
const committedTaskIds = finalPreparedTaskSnapshot.result.changedTaskIds || [];
|
|
@@ -480,7 +511,14 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
480
511
|
recordSyncDiagnostic,
|
|
481
512
|
createSyncRouteError,
|
|
482
513
|
});
|
|
483
|
-
return {
|
|
514
|
+
return {
|
|
515
|
+
result,
|
|
516
|
+
deleteCount,
|
|
517
|
+
emittedEventIds: Array.from(emittedEventIds),
|
|
518
|
+
...(finalPreparedTaskSnapshot.settledTaskDeleteIds.length > 0 ? {
|
|
519
|
+
settledTaskDeleteIds: finalPreparedTaskSnapshot.settledTaskDeleteIds,
|
|
520
|
+
} : {}),
|
|
521
|
+
};
|
|
484
522
|
}
|
|
485
523
|
finally {
|
|
486
524
|
unsubscribeRealtime();
|
|
@@ -796,14 +834,15 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
796
834
|
if (options.coexistenceDirection === 'cloud-push'
|
|
797
835
|
&& taskMutationsForApply.upserts.some((mutation) => mutation.durableRevision))
|
|
798
836
|
throw new Error('Task durable revisions are only accepted from the cloud pull feed.');
|
|
837
|
+
const { taskMutationsForSettlement, settledTaskDeleteIds, } = resolveTaskCarrierSettlement(workspaceId, taskMutationsForApply, ownership, options);
|
|
799
838
|
const durablePull = options.coexistenceDirection === 'local-pull'
|
|
800
839
|
? prepareDurableTaskPullMutations({
|
|
801
840
|
store: durabilityStore,
|
|
802
841
|
tenantId: core.getTenantId(),
|
|
803
842
|
workspaceId,
|
|
804
|
-
taskMutations:
|
|
843
|
+
taskMutations: taskMutationsForSettlement,
|
|
805
844
|
})
|
|
806
|
-
: { taskMutations:
|
|
845
|
+
: { taskMutations: taskMutationsForSettlement, pendingRevisions: [] };
|
|
807
846
|
const prepared = prepareTaskSyncSnapshotApply({
|
|
808
847
|
core,
|
|
809
848
|
workspaceId,
|
|
@@ -822,7 +861,7 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
822
861
|
ownership: durabilityStore.listTaskTaxonomyProjectionOwnership({
|
|
823
862
|
tenantId: core.getTenantId(),
|
|
824
863
|
workspaceId,
|
|
825
|
-
taskIds:
|
|
864
|
+
taskIds: taskMutationsForSettlement.upserts.map((mutation) => mutation.task.id),
|
|
826
865
|
}),
|
|
827
866
|
}),
|
|
828
867
|
v3OwnedTaskDeleteIds: resolveV3OwnedTaskDeleteIds({
|
|
@@ -857,7 +896,7 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
857
896
|
revisions: durablePull.pendingRevisions,
|
|
858
897
|
now: revisionNow,
|
|
859
898
|
});
|
|
860
|
-
return { prepared, result };
|
|
899
|
+
return { prepared, result, settledTaskDeleteIds };
|
|
861
900
|
},
|
|
862
901
|
});
|
|
863
902
|
})()
|
|
@@ -869,6 +908,7 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
869
908
|
prepared: preparedTaskSnapshot,
|
|
870
909
|
deferSideEffects: true,
|
|
871
910
|
}),
|
|
911
|
+
settledTaskDeleteIds: [],
|
|
872
912
|
};
|
|
873
913
|
const protectedTaskCount = finalPreparedTaskSnapshot.prepared.metadataPreservedTaskIds.length;
|
|
874
914
|
const protectedLifecycleTaskCount = finalPreparedTaskSnapshot.prepared.lifecyclePreservedTaskIds.length;
|
|
@@ -934,6 +974,9 @@ export function createWorkspaceSyncV2ChangeDispatcher(dependencies) {
|
|
|
934
974
|
result: finalPreparedTaskSnapshot.result,
|
|
935
975
|
deleteCount,
|
|
936
976
|
emittedEventIds: [],
|
|
977
|
+
...(finalPreparedTaskSnapshot.settledTaskDeleteIds.length > 0 ? {
|
|
978
|
+
settledTaskDeleteIds: finalPreparedTaskSnapshot.settledTaskDeleteIds,
|
|
979
|
+
} : {}),
|
|
937
980
|
};
|
|
938
981
|
const beforeCommitResult = options.transactionHooks?.beforeCommit?.(result);
|
|
939
982
|
assertSynchronousTransactionResult(beforeCommitResult);
|
|
@@ -72,6 +72,7 @@ export interface WorkspacePushSyncInput {
|
|
|
72
72
|
operationIdentity: string;
|
|
73
73
|
settlementIdentityFingerprint: string;
|
|
74
74
|
appliedTaskUpserts: WorkspacePushSyncResult['appliedTaskUpserts'];
|
|
75
|
+
settledTaskDeleteIds: string[];
|
|
75
76
|
transferReceipt: WorkspaceSyncEngineRemoteTransferReceipt;
|
|
76
77
|
pushBoundary: WorkspaceSyncEngineV2PushBoundary;
|
|
77
78
|
excludedProjections?: readonly WorkspaceSyncV2ProjectionExclusion[];
|
package/dist/sync/syncService.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { applyLocalWorkspaceChanges, getLocalWorkspaceContentPullObligations, recordLocalWorkspaceContentPullObligationFailures, getLocalWorkspaceContentManifest, pullUserSettings, pushUserSettings, prepareWorkspacePushChanges, } from './cloudSyncApi.js';
|
|
2
2
|
import { workspaceSyncContentPullObligationId, } from './engine/workspaceSyncContentPullObligationStore.js';
|
|
3
3
|
import { createBrowserWorkspaceSyncEngineRemoteServices, } from './engine/workspaceSyncEngineRemoteServices.js';
|
|
4
|
-
import { createWorkspaceSyncEngineV2SettlementIdentityProjection, createWorkspaceSyncEngineV2PushBoundary,
|
|
4
|
+
import { createWorkspaceSyncEngineV2SettlementIdentityProjection, createWorkspaceSyncEngineV2PushBoundary, parseWorkspaceSyncEnginePushTaskSettlement, workspaceSyncEngineExpectedTaskEchoIds, } from './engine/workspaceSyncEnginePushCompletion.js';
|
|
5
5
|
import { encryptDocument } from './encryptionService.js';
|
|
6
6
|
import { decryptWorkspaceSyncContentChangeInPlace } from './workspaceSyncContentDecryption.js';
|
|
7
7
|
import { decideWorkspaceContentFetch, fingerprintWorkspaceContentBody, } from './workspaceContentManifest.js';
|
|
@@ -835,7 +835,8 @@ export async function runWorkspacePushSyncService(input) {
|
|
|
835
835
|
emittedEventIds.add(eventId);
|
|
836
836
|
}
|
|
837
837
|
}
|
|
838
|
-
const
|
|
838
|
+
const taskSettlement = parseWorkspaceSyncEnginePushTaskSettlement(pushData, expectedTaskEchoIds);
|
|
839
|
+
const normalizedTaskUpserts = taskSettlement.appliedTaskUpserts;
|
|
839
840
|
appliedTaskUpserts.push(...normalizedTaskUpserts);
|
|
840
841
|
if (input.onAcceptedBatchSettled) {
|
|
841
842
|
if (!pushResult.transferReceipt) {
|
|
@@ -847,9 +848,11 @@ export async function runWorkspacePushSyncService(input) {
|
|
|
847
848
|
operationIdentity: idempotencyKey,
|
|
848
849
|
changes: plainBatchChanges,
|
|
849
850
|
appliedTaskUpserts: normalizedTaskUpserts,
|
|
851
|
+
settledTaskDeleteIds: taskSettlement.settledTaskDeleteIds,
|
|
850
852
|
excludedProjections: effectiveV2ExcludedProjections,
|
|
851
853
|
})),
|
|
852
854
|
appliedTaskUpserts: normalizedTaskUpserts,
|
|
855
|
+
settledTaskDeleteIds: taskSettlement.settledTaskDeleteIds,
|
|
853
856
|
transferReceipt: pushResult.transferReceipt,
|
|
854
857
|
pushBoundary,
|
|
855
858
|
excludedProjections: effectiveV2ExcludedProjections,
|
package/dist/ui/assets/{AiIdentityRosterCard-CDMPtnbC.js → AiIdentityRosterCard-Cfvb9Nuv.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as i}from"./vendor-react-CKJs5o3c.js";import{t as r}from"./index-
|
|
1
|
+
import{j as i}from"./vendor-react-CKJs5o3c.js";import{t as r}from"./index-GHJgcW3j.js";const t=[{name:"Blue",value:"#4269d0"},{name:"Orange",value:"#efb118"},{name:"Red",value:"#ff725c"},{name:"Cyan",value:"#6cc5b0"},{name:"Green",value:"#3ca951"},{name:"Pink",value:"#ff8ab7"},{name:"Purple",value:"#a463f2"},{name:"Light blue",value:"#97bbf5"},{name:"Brown",value:"#9c6b4e"},{name:"Gray",value:"#9498a0"}];function N(e){const s=String(e||"ai").trim().toLowerCase();let a=2166136261;for(let l=0;l<s.length;l+=1)a^=s.charCodeAt(l),a=Math.imul(a,16777619);return t[(a>>>0)%t.length].value}function b(e){const[s,a=""]=e.split("#"),n=s.includes("?")?"&":"?";return`${s}${n}taskforceCloud=1${a?`#${a}`:""}`}function $(e){return/^https?:\/\//i.test(e)?e:b(e)}function j({name:e,username:s,subtitle:a,avatar:n,selected:l,disabled:o=!1,onSelect:u,ariaLabel:c,avatarVariant:f="portrait",avatarClassName:m="",avatarStyle:d,className:p="",topUtility:h,bottomUtility:v,footer:P}){return i.jsxs("button",{type:"button",className:`${r.aiProfileGroup} ${l?r.aiProfileGroupSelected:""} ${p}`.trim(),onClick:u,disabled:o,"aria-label":c,"aria-pressed":l,children:[h,v,i.jsxs("span",{className:r.aiProfileGroupHeader,children:[i.jsx("span",{className:`${r.aiProfileGroupAvatar} ${f==="logo"?r.aiProfileGroupAvatarLogo:""} ${m}`.trim(),style:d,"aria-hidden":"true",children:n}),i.jsxs("span",{className:r.aiProfileGroupIdentity,children:[i.jsx("span",{className:r.aiProfileName,children:e}),s?i.jsxs("span",{className:r.aiProfileHandle,children:["@",s]}):null,i.jsx("span",{className:r.aiProfileRole,children:a}),P]})]})]})}export{j as A,N as a,t as b,$ as r,b as w};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as f,j as a}from"./vendor-react-CKJs5o3c.js";import{ad as Qe,ae as re,U as Ue,af as ea,ag as W,t as r,W as aa,ah as ra,ai as Re,X as ta,aj as ia,ak as te,al as Me,am as la,Z as oa,Y as Ee,a0 as b,a1 as ke}from"./index-DSQINwt9.js";import{A as sa,b as na,r as Ce}from"./AiIdentityRosterCard-CDMPtnbC.js";import{ay as ca,ak as da,U as fa,w as ua,Z as V,J as Le,ax as pa,aC as ma}from"./vendor-icons-Bsq-mcEn.js";import"./vendor-markdown-_lhNCyq-.js";import"./vendor-dnd-CJ-AjP-Y.js";import"./vendor-router-AqJMU8Lz.js";const va=["chat_app","ide","cli","coding_tool","taskforce_agent","agent","unclassified"];function L(l){return typeof l.avatarUrl=="string"&&l.avatarUrl.trim().length>0}function ie(l){return l?Ee(l.avatarUrl,l.avatarRevision,l.avatarUpdatedAt):""}function ga(l){return l?Ee(l.avatarSourceUrl,l.avatarRevision,l.avatarUpdatedAt):""}function ha(l){return l.find(L)||l[0]}function ya({profile:l,className:g=""}){const A=ie(l),$=W(l),{activeImageUrl:T,handleImageError:Y}=oa(A,$);return T?a.jsx("img",{src:T,alt:"",className:g,onError:Y}):a.jsx(Le,{size:22})}function K(l){const g=te(l);return g?`taskforce-agent:${g}`:`${l.seatScope||"unknown"}:${l.name.trim().toLowerCase()}`}function le(l){const g=l.providerMetadata?.taskforce;return!!(g&&typeof g=="object"&&!Array.isArray(g)&&String(g.taskforceAgentId||"").trim())}function Pa(l){return le(l)?"taskforce_agent":Me(l.surfaceType)}function Te(l){return l==="taskforce_agent"?"Taskforce Agents":la(l)}function Aa(l){return le(l)?"Taskforce Agent":l.surfaceType?Re(l.surfaceType):""}function Sa(l){const g=Math.max(0,l-1);return`${g} duplicate${g===1?"":"s"}`}function we(l){return!l||typeof l!="object"?null:{used:Math.max(0,Number(l.used||0)),limit:l.limit===null||l.limit===void 0?null:Math.max(0,Number(l.limit||0)),remaining:l.remaining===null||l.remaining===void 0?null:Math.max(0,Number(l.remaining||0))}}function De(l,g){const A=g?.variant==="inline"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconInline}`:g?.variant==="detail"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconDetail}`:r.aiProfileSeatScopeIcon;return l==="cloud_metered"?a.jsx("span",{className:`${A} ${r.aiProfileSeatScopeIconCloud}`,title:"Cloud MCP","aria-label":"Cloud MCP",children:a.jsx(pa,{size:20})}):l==="local_unmetered"?a.jsx("span",{className:`${A} ${r.aiProfileSeatScopeIconLocal}`,title:"Local MCP","aria-label":"Local MCP",children:a.jsx(ma,{size:20})}):null}function Ca({workspaceId:l,runtimeMode:g="local",cloudAuthConfigured:A=!1,authSessionResolved:$=!1,isAuthenticated:T=!1,cloudAiProfileSeatUsage:Y=null,agentTrayOpen:Z=!1,onCloseAgentTray:$e,mcpSettingsNode:oe=null,resolveCloudAuthUrl:B,theme:Be="dark",onNotice:w}){const[N,O]=f.useState([]),[Oe,Fe]=f.useState(null),[Ge,se]=f.useState(!1),[S,F]=f.useState(null),[G,D]=f.useState(null),[ne,X]=f.useState(null),[_e,ce]=f.useState(!1),[U,_]=f.useState(null),[de,fe]=f.useState(null),[ue,z]=f.useState(!1),[ze,P]=f.useState(null),[He,x]=f.useState(null),[R,pe]=f.useState(null),[me,k]=f.useState({}),[ve,ge]=f.useState(!1),[q,he]=f.useState(!1),[ye,Pe]=f.useState(null),C=f.useCallback(async()=>{if(l){se(!0);try{const e=`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(l)}&kind=agent`,t=await fetch(e,{credentials:"include"}),o=t.ok?await t.json().catch(()=>({})):{},s=we(o?.aiProfileSeatUsage),d=Array.isArray(o?.assignees)?o.assignees.filter(i=>i.kind==="agent").map(i=>({id:String(i.value||""),name:String(i.label||i.value||"Unknown Agent"),username:String(i.username||i.value||""),icon:String(i.icon||"Bot"),color:String(i.color||"#6B7280"),colorSource:typeof i.colorSource=="string"?i.colorSource:null,colorUpdatedAt:typeof i.colorUpdatedAt=="string"?i.colorUpdatedAt:null,avatarUrl:typeof i.avatarUrl=="string"?i.avatarUrl:null,avatarSourceUrl:typeof i.avatarSourceUrl=="string"?i.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(i.avatarRevision))?Math.max(0,Math.floor(Number(i.avatarRevision))):0,avatarUpdatedAt:typeof i.avatarUpdatedAt=="string"?i.avatarUpdatedAt:null,kind:String(i.kind||"agent"),description:typeof i.description=="string"?i.description:null,role:typeof i.role=="string"?i.role:null,provider:typeof i.provider=="string"?i.provider:null,model:typeof i.model=="string"?i.model:null,surfaceType:re(i.surfaceType),seatScope:Qe(i.seatScope),providerMetadata:i.providerMetadata&&typeof i.providerMetadata=="object"&&!Array.isArray(i.providerMetadata)?i.providerMetadata:null,archivedAt:typeof i.archivedAt=="string"?i.archivedAt:null,createdAt:String(i.createdAt||""),updatedAt:String(i.updatedAt||i.createdAt||""),lastActiveAt:typeof i.lastActiveAt=="string"?i.lastActiveAt:null})):[];O(d),Fe(s),D(i=>i&&!d.some(u=>u.id===i.profileId)?null:i),X(i=>i&&!d.some(u=>u.id===i.profileId)?null:i)}finally{se(!1)}}},[l]);f.useEffect(()=>{C()},[C]),f.useEffect(()=>{const e=t=>{const o=t.detail;(String(o?.workspaceId||"").trim()||"default")===l&&o?.origin!=="ai-profiles-module"&&C()};return window.addEventListener(Ue,e),()=>window.removeEventListener(Ue,e)},[C,l]);const H=f.useMemo(()=>{const e=new Map;for(const t of N){const o=Pa(t);e.has(o)||e.set(o,new Map);const s=e.get(o),d=K(t);s.has(d)||s.set(d,[]),s.get(d).push(t)}return va.map(t=>({section:t,label:Te(t),groups:Array.from(e.get(t)?.entries()||[]).map(([o,s])=>({groupId:`${t}:${o}`,section:t,sectionLabel:Te(t),profiles:s,primaryProfile:ha(s)}))})).filter(t=>t.groups.length>0)},[N]),I=f.useMemo(()=>H.flatMap(e=>e.groups),[H]),n=f.useMemo(()=>I.find(e=>e.groupId===U)||I[0]||null,[I,U]),p=f.useMemo(()=>N.find(e=>e.id===de)||null,[N,de]),Ae=p&&me[p.id]||null,Se=n&&me[n.primaryProfile.id]||null;f.useEffect(()=>{if(!I.length){U!==null&&_(null);return}(!U||!I.some(e=>e.groupId===U))&&_(I[0].groupId)},[I,U]);const Je=async(e,t)=>{D(null);try{const o=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:e,mergeId:t})}),s=await o.json().catch(()=>({}));if(!o.ok){w?.(String(s?.error||"Failed to merge AI profiles."),"error");return}F(null),w?.("AI profiles merged.","success"),await C(),b({workspaceId:l,profileId:e,reason:"merge",origin:"ai-profiles-module"})}catch{w?.("Failed to merge AI profiles.","error")}},xe=async e=>{if(window.confirm(`Remove ${e.name} from the active roster? This frees an AI profile seat and preserves task and comment history.`)){D(null);try{const o=await fetch("/api/taskforce/workspace/ai-profiles/archive",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:e.id,reason:"manual_archive"})}),s=await o.json().catch(()=>({}));if(!o.ok){D({profileId:e.id,message:String(s?.error||"Failed to remove AI profile from roster.")});return}(S?.keepId===e.id||S?.mergeId===e.id)&&F(null),w?.("AI profile removed from active roster.","success"),await C(),b({workspaceId:l,profileId:e.id,reason:"archive",origin:"ai-profiles-module"})}catch{D({profileId:e.id,message:"Failed to remove AI profile from roster."})}}},Ve=async(e,t)=>{const o=re(t),s=new Set(e.profiles.map(u=>u.surfaceType??"")),d=o??"";if(s.size===1&&s.has(d))return;ce(!0),X(null);const i=[];try{for(const c of e.profiles){const m=await fetch("/api/taskforce/workspace/ai-profiles/surface-type",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:c.id,surfaceType:o})}),v=await m.json().catch(()=>({}));if(!m.ok||!v?.profile)throw new Error(String(v?.error||"Failed to update AI profile category."));const j=v.profile;i.push({...c,surfaceType:re(j.surfaceType),updatedAt:typeof j.updatedAt=="string"?j.updatedAt:c.updatedAt})}const u=new Map(i.map(c=>[c.id,c]));O(c=>c.map(m=>u.get(m.id)||m));const h=u.get(e.primaryProfile.id)||{...e.primaryProfile,surfaceType:o},y=Me(h.surfaceType);_(`${y}:${K(h)}`),w?.("AI profile category updated.","success");for(const c of i)b({workspaceId:l,profileId:c.id,reason:"update",origin:"ai-profiles-module"})}catch(u){X({profileId:e.primaryProfile.id,message:String(u?.message||"Failed to update AI profile category.")})}finally{ce(!1)}},Ie=async(e,t,o=!1)=>{he(!0),Pe(null);try{const s=K(e.primaryProfile),d=N.filter(c=>K(c)===s),i=await fetch("/api/taskforce/workspace/ai-profiles/color",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileIds:d.map(c=>c.id),color:t,reset:o})}),u=await i.text();let h={};try{h=u?JSON.parse(u):{}}catch{h={}}if(!i.ok){const c=i.status===404?"Color updates are unavailable in the running Taskforce server. Restart Taskforce and try again.":`Failed to update AI profile color (HTTP ${i.status}).`;throw new Error(String(h.error||c))}if(!Array.isArray(h.profiles))throw new Error("Taskforce returned an invalid response while updating the AI profile color.");const y=new Map(h.profiles.map(c=>[String(c.id),c]));O(c=>c.map(m=>{const v=y.get(m.id);return v?{...m,color:String(v.color||m.color),colorSource:v.colorSource??m.colorSource,colorUpdatedAt:v.colorUpdatedAt??m.colorUpdatedAt,updatedAt:v.updatedAt??m.updatedAt}:m})),ge(!1);for(const c of d)b({workspaceId:l,profileId:c.id,reason:"update",origin:"ai-profiles-module"})}catch(s){Pe(String(s?.message||"Failed to update AI profile color."))}finally{he(!1)}},je=e=>new Promise((t,o)=>{const s=new FileReader;s.onload=()=>t(String(s.result||"")),s.onerror=()=>o(new Error("Failed to read image file.")),s.readAsDataURL(e)}),Q=e=>{const t=String(e?.id||"").trim();t&&O(o=>o.map(s=>s.id===t?{...s,avatarUrl:typeof e.avatarUrl=="string"?e.avatarUrl:null,avatarSourceUrl:typeof e.avatarSourceUrl=="string"?e.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(e.avatarRevision))?Math.max(0,Math.floor(Number(e.avatarRevision))):s.avatarRevision,avatarUpdatedAt:typeof e.avatarUpdatedAt=="string"?e.avatarUpdatedAt:s.avatarUpdatedAt,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:s.updatedAt}:s))},Ke=async(e,t,o,s=!1)=>{const d=await je(t),i=o?await je(o):null,u={profileId:e,preserveExistingSource:s,displayImage:{dataUrl:d,mimeType:t.type||"application/octet-stream",originalName:t.name||"display-avatar"}};o&&i&&(u.sourceImage={dataUrl:i,mimeType:o.type||"application/octet-stream",originalName:o.name||"source-avatar"});const h=await fetch("/api/taskforce/workspace/ai-profiles/avatar/upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),y=await h.json().catch(()=>({}));if(!h.ok||!y?.profile)throw new Error(String(y?.error||"Failed to update AI profile avatar."));Q(y.profile),b({workspaceId:l,profileId:e,reason:"avatar",origin:"ai-profiles-module"})},We=async e=>{const t=await fetch("/api/taskforce/workspace/ai-profiles/avatar",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:e,avatarUrl:null,avatarSourceUrl:null})}),o=await t.json().catch(()=>({}));if(!t.ok||!o?.profile)throw new Error(String(o?.error||"Failed to update AI profile avatar."));Q(o.profile),b({workspaceId:l,profileId:e,reason:"avatar",origin:"ai-profiles-module"})},Ye=async e=>{if(R)return!1;const t=te(e),o=L(e);if(o&&!window.confirm(`Replace the existing avatar for ${e.name}?`))return!1;const s=t?"":window.prompt("Optional visual direction (300 characters maximum). Leave blank to use the profile details.","");if(s===null)return!1;const d=g==="local";if(d&&(!A||!$||!T||!B))return P("Sign in to Taskforce Cloud to generate profile avatars."),x(null),!1;pe(e.id),P(null),x(null),k(i=>({...i,[e.id]:{error:null,notice:null}}));try{const i=t?`/api/taskforce/agents/${encodeURIComponent(t)}/avatar/generate`:"/api/taskforce/workspace/ai-profiles/avatar/generate",u=d&&B?B(i):i,h=await fetch(u,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(t?{workspaceId:l}:{workspaceId:l,profileId:e.id,visualDirection:s.slice(0,300),replaceExisting:o})}),y=await h.text().catch(()=>"");let c={};if(y&&!/^\s*(?:<!doctype\s+html|<html\b)/i.test(y))try{c=JSON.parse(y)}catch{c={}}if(!h.ok||!c?.profile&&!c?.agent)throw new Error(String(c?.error||(h.status?`Unable to generate avatar. HTTP ${h.status}.`:"Unable to generate avatar.")));const m=c.profile||{id:e.id,avatarUrl:c.agent?.avatarUrl??null,avatarSourceUrl:c.agent?.avatarSourceUrl??null,avatarRevision:c.agent?.avatarRevision??0,avatarUpdatedAt:c.agent?.avatarUpdatedAt??null},v=d&&B?{...m,avatarUrl:m.avatarUrl?Ce(m.avatarUrl):m.avatarUrl,avatarSourceUrl:m.avatarSourceUrl?Ce(m.avatarSourceUrl):m.avatarSourceUrl}:m;return Q(v),k(d?j=>({...j,[e.id]:{error:null,notice:`Generated photo for ${e.name} was saved in Taskforce Cloud. The local copy will be retained when sync runs.`}}):j=>({...j,[e.id]:{error:null,notice:`Generated photo for ${e.name} was saved.`}})),b({workspaceId:l,profileId:e.id,reason:"avatar",origin:"ai-profiles-module",...t?{taskforceAgentAvatar:{agentId:t,avatarUrl:typeof v.avatarUrl=="string"?v.avatarUrl:null,avatarSourceUrl:typeof v.avatarSourceUrl=="string"?v.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(v.avatarRevision))?Math.max(0,Math.floor(Number(v.avatarRevision))):0,avatarUpdatedAt:typeof v.avatarUpdatedAt=="string"?v.avatarUpdatedAt:null}}:{}}),!0}catch(i){return k(u=>({...u,[e.id]:{error:String(i?.message||"Unable to generate profile avatar."),notice:null}})),!1}finally{pe(null)}},Ze=async(e,t,o)=>{if(!p)return!1;if(!e.type.startsWith("image/"))return P("AI profile photo must be an image file."),!1;z(!0),P(null),x(null),k(s=>{const d={...s};return delete d[p.id],d});try{const s=await ke(e,{maxBytes:5242880});if(s.exceededLimit)throw new Error(e.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile photo must be 5 MB or smaller.");const d=s.file;let i=null;if(t){const u=await ke(t,{maxBytes:5242880});if(u.exceededLimit)throw new Error(t.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile source photo must be 5 MB or smaller.");i=u.file}return await Ke(p.id,d,i,o?.preserveExistingSource===!0),!0}catch(s){return P(String(s?.message||"Failed to update AI profile photo.")),!1}finally{z(!1)}},Xe=async()=>{if(p){z(!0),P(null),x(null),k(e=>{const t={...e};return delete t[p.id],t});try{await We(p.id),x("Profile photo removed.")}catch(e){P(String(e?.message||"Failed to remove AI profile photo."))}finally{z(!1)}}},M=e=>{const t=String(e||"").trim();if(!t)return"Unknown";const o=Date.parse(t);return Number.isFinite(o)?new Date(o).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):t},be=f.useMemo(()=>{if(!n)return{attributes:[],dates:[]};const e=n.primaryProfile,t=o=>o||"Not set";return{attributes:[{label:"Category",value:Aa(e)},{label:"Connection",value:e.seatScope?ea(e.seatScope):""},{label:"Provider",value:e.provider||""},{label:"Model",value:e.model||""}].map(o=>({...o,value:t(o.value)})),dates:[{label:"Status",value:e.archivedAt?"Retired":"Active"},{label:"Recruited",value:M(e.createdAt)},{label:"Last updated",value:M(e.updatedAt)},{label:"Last active",value:M(e.lastActiveAt)}].map(o=>({...o,value:t(o.value)}))}},[n]),qe=!!n&&n.profiles.length>1,E=!!n&&!L(n.primaryProfile)&&!!W(n.primaryProfile),Ne=A&&$&&!T,J=A?we(Y):Oe,ee=Ne?"Log into account for Cloud AI Profiles":J?`${J.used}/${J.limit===null?"Unlimited":J.limit}`:null,ae=!!oe;return a.jsxs("section",{className:`${r.agentsModuleRoot} ${ae?r.agentsModuleWithTray:""} ${ae&&Z?r.agentsModuleTrayOpen:""}`.trim(),children:[ae&&a.jsxs("aside",{className:`${r.agentTrayPanel} ${Z?r.agentTrayPanelOpen:""}`.trim(),"aria-label":"AI Profile MCP settings tray","aria-hidden":!Z,children:[a.jsxs("div",{className:r.agentTrayHeader,children:[a.jsxs("span",{className:r.agentTrayTitle,children:[a.jsx(ca,{size:14}),"MCP Settings"]}),a.jsx("button",{type:"button",className:"tf-control-icon",onClick:$e,title:"Collapse AI Profile tray","aria-label":"Collapse AI Profile tray",children:a.jsx(da,{size:16})})]}),a.jsx("div",{className:`${r.agentTrayContent} tf-scrollbar tf-scrollbar--track-transparent`,children:a.jsx("div",{className:r.agentTrayContentInner,children:oe})})]}),a.jsx("div",{className:r.agentsModuleContent,children:a.jsxs("div",{className:r.aiProfilesExplorer,children:[a.jsxs("aside",{className:r.aiProfilesRosterPanel,"aria-label":"AI profile roster",children:[a.jsx("div",{className:r.taskforceAgentRosterHeader,children:a.jsxs("span",{className:r.taskforceAgentRosterTitle,children:[a.jsx(fa,{size:14}),"AI Profiles"]})}),ee&&a.jsx("div",{className:r.aiProfilesRosterSummary,children:a.jsx("div",{className:r.aiProfileSeatSummary,children:Ne?ee:`Registered Cloud AI Profiles: ${ee}`})}),Ge?a.jsxs("div",{className:r.aiProfilesRosterState,role:"status","aria-live":"polite",children:[a.jsx(ua,{size:13,className:r.spinner})," Loading profiles…"]}):N.length===0?a.jsx("div",{className:r.aiProfilesRosterState,children:"No AI profiles registered yet."}):H.length>0?a.jsx("div",{className:`${r.aiProfilesListPane} tf-scrollbar tf-scrollbar--track-transparent tf-tray-scroll-viewport`,children:a.jsx("div",{className:r.aiProfilesList,children:H.map(e=>a.jsxs("div",{className:r.aiProfilesSection,children:[a.jsx("div",{className:r.aiProfilesSectionHeader,children:e.label}),e.groups.map(t=>{const o=n?.groupId===t.groupId,s=t.primaryProfile,d=!L(s)&&!!W(s);return a.jsx(sa,{name:s.name,username:s.username,subtitle:s.role||"Role not set",selected:o,onSelect:()=>_(t.groupId),avatarVariant:d?"logo":"portrait",avatar:a.jsx(ya,{profile:s}),avatarStyle:{color:s.color},className:t.profiles.length>1?r.aiProfileGroupDuplicate:"",topUtility:De(s.seatScope),bottomUtility:a.jsx("span",{className:r.aiProfileGroupSignatureSwatch,style:{backgroundColor:s.color},title:`Signature color ${s.color}`,"aria-hidden":"true"}),footer:t.profiles.length>1?a.jsxs("span",{className:r.aiProfileDuplicateBadge,children:[a.jsx(V,{size:11})," ",Sa(t.profiles.length)]}):null},t.groupId)})]},e.section))})}):null]}),a.jsx("main",{className:`${r.aiProfilesDetailViewport} tf-scrollbar`,"aria-label":"AI profile details",children:n&&a.jsx("div",{className:r.aiProfileDetailPane,children:a.jsxs("div",{className:r.aiProfileDetailCard,children:[De(n.primaryProfile.seatScope,{variant:"detail"}),a.jsxs("div",{className:r.aiProfileDetailHero,children:[a.jsx(aa,{label:"Edit AI profile photo",imageUrl:ie(n.primaryProfile),fallbackImageUrl:W(n.primaryProfile),fallback:a.jsx(Le,{size:38}),accentColor:E?null:n.primaryProfile.color,size:176,width:E?176:153,height:E?176:207,radius:E?0:6,editBadgeSize:28,editIconSize:14,loading:R===n.primaryProfile.id,loadingLabel:`Generating ${n.primaryProfile.name} photo`,error:!!Se?.error,errorLabel:Se?.error||"Profile photo generation failed",className:`${r.aiProfileDetailAvatar} ${E?r.aiProfileDetailAvatarLogo:""}`.trim(),onClick:()=>{P(null),x(null),fe(n.primaryProfile.id)}}),a.jsxs("div",{className:r.aiProfileDetailHeading,children:[a.jsx("div",{className:r.aiProfileDetailTitleRow,children:a.jsx("h5",{className:r.aiProfileDetailTitle,children:n.primaryProfile.name})}),a.jsxs("div",{className:r.aiProfileDetailMetaRow,children:[a.jsxs("span",{className:r.aiProfileDetailHandle,children:["@",n.primaryProfile.username]}),n.profiles.length>1&&a.jsxs("span",{className:r.aiProfileDetailLinkedCount,children:[n.profiles.length," linked"]})]}),a.jsxs("div",{className:r.aiProfileDetailRole,children:["Role: ",n.primaryProfile.role||"Not set"]}),n.primaryProfile.description&&a.jsx("div",{className:r.aiProfileDetailDescription,children:n.primaryProfile.description}),a.jsxs("div",{className:r.aiProfileSignatureColor,children:[a.jsx("span",{children:"Signature color"}),a.jsxs("button",{type:"button",className:r.aiProfileSignatureColorButton,onClick:()=>ge(e=>!e),disabled:q,"aria-expanded":ve,"aria-label":"Change signature color",children:[a.jsx("span",{className:r.aiProfileSignatureSwatch,style:{backgroundColor:n.primaryProfile.color},"aria-hidden":"true"}),a.jsx("span",{children:n.primaryProfile.color})]})]}),ve&&a.jsxs("div",{className:r.aiProfileColorPicker,"aria-label":"Signature color options",children:[na.map(({name:e,value:t})=>a.jsx("button",{type:"button",className:r.aiProfileColorOption,style:{backgroundColor:t},"aria-label":`Use ${e}`,"aria-pressed":n.primaryProfile.color.toLowerCase()===t.toLowerCase(),disabled:q,onClick:()=>{Ie(n,t)}},t)),a.jsx("button",{type:"button",className:r.secondaryHeaderBtn,disabled:q,onClick:()=>{Ie(n,void 0,!0)},children:"Reset"})]}),ye&&a.jsx("div",{className:r.aiProfileInlineError,children:ye})]})]}),a.jsxs("div",{className:r.aiProfileDetailDataList,children:[a.jsx("div",{className:r.aiProfileDetailDataGroup,children:be.attributes.map(e=>a.jsxs("div",{className:r.aiProfileDetailDataRow,children:[a.jsx("span",{className:r.aiProfileDetailDataLabel,children:e.label}),e.label==="Category"&&!le(n.primaryProfile)?a.jsx("span",{className:r.aiProfileDetailDataValue,children:a.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent category",value:n.primaryProfile.surfaceType??"",disabled:_e,onChange:t=>{Ve(n,t.target.value)},children:[a.jsx("option",{value:"",children:"Unclassified"}),ra.map(t=>a.jsx("option",{value:t,children:Re(t)},t))]})}):a.jsx("span",{className:r.aiProfileDetailDataValue,children:e.value})]},e.label))}),a.jsx("div",{className:`${r.aiProfileDetailDataGroup} ${r.aiProfileDetailDateGroup}`,children:be.dates.map(e=>a.jsxs("div",{className:r.aiProfileDetailDataRow,children:[a.jsx("span",{className:r.aiProfileDetailDataLabel,children:e.label}),e.label==="Status"?a.jsx("span",{className:r.aiProfileDetailDataValue,children:a.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent roster status",value:n.primaryProfile.archivedAt?"retired":"active",onChange:t=>{t.target.value==="retire"&&xe(n.primaryProfile)},children:[a.jsx("option",{value:"active",children:"Active"}),n.primaryProfile.archivedAt?a.jsx("option",{value:"retired",children:"Retired"}):a.jsx("option",{value:"retire",children:"Retire from roster"})]})}):a.jsx("span",{className:r.aiProfileDetailDataValue,children:e.value})]},e.label))})]}),ne?.profileId===n.primaryProfile.id&&a.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[a.jsx(V,{size:12}),a.jsx("span",{children:ne.message})]}),qe?a.jsxs("div",{className:r.aiProfileInstanceSection,children:[a.jsxs("div",{className:r.aiProfileInstanceSectionHeader,children:[a.jsx("span",{children:"Profile instances"}),a.jsx("span",{className:r.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),a.jsx("div",{className:r.aiProfileInstanceList,children:n.profiles.map(e=>a.jsxs("div",{className:r.aiProfileInstanceCard,children:[a.jsxs("div",{className:r.aiProfileInstanceTopRow,children:[a.jsxs("div",{children:[a.jsxs("div",{className:r.aiProfileInstanceName,children:["@",e.username]}),a.jsx("div",{className:r.aiProfileIdChip,children:e.id})]}),S?.keepId===e.id&&a.jsx("span",{className:r.aiProfileKeepBadge,children:"Keeping"})]}),a.jsxs("div",{className:r.aiProfileInstanceMeta,children:[a.jsxs("span",{children:["Created ",M(e.createdAt)]}),a.jsxs("span",{children:["Updated ",M(e.updatedAt)]})]}),S?.keepId!==e.id&&a.jsx("button",{className:r.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const t=n.profiles.find(o=>o.id!==e.id)?.id;t&&F({keepId:e.id,mergeId:t})},children:"Keep this"}),G?.profileId===e.id&&a.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[a.jsx(V,{size:12}),a.jsx("span",{children:G.message})]}),a.jsx("button",{className:r.aiProfileDangerTextButton,title:"Remove this profile from the active roster",onClick:()=>{xe(e)},children:"Remove from roster"})]},e.id))}),S&&n.profiles.some(e=>e.id===S.keepId)&&a.jsxs("div",{className:r.aiProfileMergeActions,children:[a.jsx("button",{className:r.dangerBtn,onClick:()=>{Je(S.keepId,S.mergeId)},children:"Merge duplicates"}),a.jsx("button",{className:r.secondaryHeaderBtn,onClick:()=>F(null),children:"Cancel"})]})]}):a.jsxs("div",{className:r.aiProfileIdFooter,children:[a.jsx("div",{className:r.aiProfileIdFooterValue,children:n.primaryProfile.id}),G?.profileId===n.primaryProfile.id&&a.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[a.jsx(V,{size:12}),a.jsx("span",{children:G.message})]})]})]})})})]})}),a.jsx(ta,{isOpen:!!p,theme:Be,title:"Edit AI Profile Photo",currentImageUrl:ie(p),editorImageUrl:ga(p),fallbackInitial:(p?.name||"AI").charAt(0).toUpperCase(),accept:"image/png,image/jpeg,image/webp,image/gif",busy:ue,generating:R===p?.id,generateLabel:p&&L(p)?"Regenerate":"Generate",hasPendingImage:!1,canRemove:!!p?.avatarUrl,error:ze||Ae?.error||null,notice:He||Ae?.notice||null,onClose:()=>{ue||(fe(null),P(null),x(null))},onApplyImage:Ze,onGenerateImage:p&&(!R||R===p.id)&&(ia(p)||te(p))?()=>Ye(p):void 0,onRemoveImage:Xe},p?.id||"ai-profile-avatar-closed")]})}export{Ca as AiProfilesModule};
|
|
1
|
+
import{r as f,j as a}from"./vendor-react-CKJs5o3c.js";import{ad as Qe,ae as re,U as Ue,af as ea,ag as W,t as r,W as aa,ah as ra,ai as Re,X as ta,aj as ia,ak as te,al as Me,am as la,Z as oa,Y as Ee,a0 as b,a1 as ke}from"./index-GHJgcW3j.js";import{A as sa,b as na,r as Ce}from"./AiIdentityRosterCard-Cfvb9Nuv.js";import{ay as ca,ak as da,U as fa,w as ua,Z as V,J as Le,ax as pa,aC as ma}from"./vendor-icons-Bsq-mcEn.js";import"./vendor-markdown-_lhNCyq-.js";import"./vendor-dnd-CJ-AjP-Y.js";import"./vendor-router-AqJMU8Lz.js";const va=["chat_app","ide","cli","coding_tool","taskforce_agent","agent","unclassified"];function L(l){return typeof l.avatarUrl=="string"&&l.avatarUrl.trim().length>0}function ie(l){return l?Ee(l.avatarUrl,l.avatarRevision,l.avatarUpdatedAt):""}function ga(l){return l?Ee(l.avatarSourceUrl,l.avatarRevision,l.avatarUpdatedAt):""}function ha(l){return l.find(L)||l[0]}function ya({profile:l,className:g=""}){const A=ie(l),$=W(l),{activeImageUrl:T,handleImageError:Y}=oa(A,$);return T?a.jsx("img",{src:T,alt:"",className:g,onError:Y}):a.jsx(Le,{size:22})}function K(l){const g=te(l);return g?`taskforce-agent:${g}`:`${l.seatScope||"unknown"}:${l.name.trim().toLowerCase()}`}function le(l){const g=l.providerMetadata?.taskforce;return!!(g&&typeof g=="object"&&!Array.isArray(g)&&String(g.taskforceAgentId||"").trim())}function Pa(l){return le(l)?"taskforce_agent":Me(l.surfaceType)}function Te(l){return l==="taskforce_agent"?"Taskforce Agents":la(l)}function Aa(l){return le(l)?"Taskforce Agent":l.surfaceType?Re(l.surfaceType):""}function Sa(l){const g=Math.max(0,l-1);return`${g} duplicate${g===1?"":"s"}`}function we(l){return!l||typeof l!="object"?null:{used:Math.max(0,Number(l.used||0)),limit:l.limit===null||l.limit===void 0?null:Math.max(0,Number(l.limit||0)),remaining:l.remaining===null||l.remaining===void 0?null:Math.max(0,Number(l.remaining||0))}}function De(l,g){const A=g?.variant==="inline"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconInline}`:g?.variant==="detail"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconDetail}`:r.aiProfileSeatScopeIcon;return l==="cloud_metered"?a.jsx("span",{className:`${A} ${r.aiProfileSeatScopeIconCloud}`,title:"Cloud MCP","aria-label":"Cloud MCP",children:a.jsx(pa,{size:20})}):l==="local_unmetered"?a.jsx("span",{className:`${A} ${r.aiProfileSeatScopeIconLocal}`,title:"Local MCP","aria-label":"Local MCP",children:a.jsx(ma,{size:20})}):null}function Ca({workspaceId:l,runtimeMode:g="local",cloudAuthConfigured:A=!1,authSessionResolved:$=!1,isAuthenticated:T=!1,cloudAiProfileSeatUsage:Y=null,agentTrayOpen:Z=!1,onCloseAgentTray:$e,mcpSettingsNode:oe=null,resolveCloudAuthUrl:B,theme:Be="dark",onNotice:w}){const[N,O]=f.useState([]),[Oe,Fe]=f.useState(null),[Ge,se]=f.useState(!1),[S,F]=f.useState(null),[G,D]=f.useState(null),[ne,X]=f.useState(null),[_e,ce]=f.useState(!1),[U,_]=f.useState(null),[de,fe]=f.useState(null),[ue,z]=f.useState(!1),[ze,P]=f.useState(null),[He,x]=f.useState(null),[R,pe]=f.useState(null),[me,k]=f.useState({}),[ve,ge]=f.useState(!1),[q,he]=f.useState(!1),[ye,Pe]=f.useState(null),C=f.useCallback(async()=>{if(l){se(!0);try{const e=`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(l)}&kind=agent`,t=await fetch(e,{credentials:"include"}),o=t.ok?await t.json().catch(()=>({})):{},s=we(o?.aiProfileSeatUsage),d=Array.isArray(o?.assignees)?o.assignees.filter(i=>i.kind==="agent").map(i=>({id:String(i.value||""),name:String(i.label||i.value||"Unknown Agent"),username:String(i.username||i.value||""),icon:String(i.icon||"Bot"),color:String(i.color||"#6B7280"),colorSource:typeof i.colorSource=="string"?i.colorSource:null,colorUpdatedAt:typeof i.colorUpdatedAt=="string"?i.colorUpdatedAt:null,avatarUrl:typeof i.avatarUrl=="string"?i.avatarUrl:null,avatarSourceUrl:typeof i.avatarSourceUrl=="string"?i.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(i.avatarRevision))?Math.max(0,Math.floor(Number(i.avatarRevision))):0,avatarUpdatedAt:typeof i.avatarUpdatedAt=="string"?i.avatarUpdatedAt:null,kind:String(i.kind||"agent"),description:typeof i.description=="string"?i.description:null,role:typeof i.role=="string"?i.role:null,provider:typeof i.provider=="string"?i.provider:null,model:typeof i.model=="string"?i.model:null,surfaceType:re(i.surfaceType),seatScope:Qe(i.seatScope),providerMetadata:i.providerMetadata&&typeof i.providerMetadata=="object"&&!Array.isArray(i.providerMetadata)?i.providerMetadata:null,archivedAt:typeof i.archivedAt=="string"?i.archivedAt:null,createdAt:String(i.createdAt||""),updatedAt:String(i.updatedAt||i.createdAt||""),lastActiveAt:typeof i.lastActiveAt=="string"?i.lastActiveAt:null})):[];O(d),Fe(s),D(i=>i&&!d.some(u=>u.id===i.profileId)?null:i),X(i=>i&&!d.some(u=>u.id===i.profileId)?null:i)}finally{se(!1)}}},[l]);f.useEffect(()=>{C()},[C]),f.useEffect(()=>{const e=t=>{const o=t.detail;(String(o?.workspaceId||"").trim()||"default")===l&&o?.origin!=="ai-profiles-module"&&C()};return window.addEventListener(Ue,e),()=>window.removeEventListener(Ue,e)},[C,l]);const H=f.useMemo(()=>{const e=new Map;for(const t of N){const o=Pa(t);e.has(o)||e.set(o,new Map);const s=e.get(o),d=K(t);s.has(d)||s.set(d,[]),s.get(d).push(t)}return va.map(t=>({section:t,label:Te(t),groups:Array.from(e.get(t)?.entries()||[]).map(([o,s])=>({groupId:`${t}:${o}`,section:t,sectionLabel:Te(t),profiles:s,primaryProfile:ha(s)}))})).filter(t=>t.groups.length>0)},[N]),I=f.useMemo(()=>H.flatMap(e=>e.groups),[H]),n=f.useMemo(()=>I.find(e=>e.groupId===U)||I[0]||null,[I,U]),p=f.useMemo(()=>N.find(e=>e.id===de)||null,[N,de]),Ae=p&&me[p.id]||null,Se=n&&me[n.primaryProfile.id]||null;f.useEffect(()=>{if(!I.length){U!==null&&_(null);return}(!U||!I.some(e=>e.groupId===U))&&_(I[0].groupId)},[I,U]);const Je=async(e,t)=>{D(null);try{const o=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:e,mergeId:t})}),s=await o.json().catch(()=>({}));if(!o.ok){w?.(String(s?.error||"Failed to merge AI profiles."),"error");return}F(null),w?.("AI profiles merged.","success"),await C(),b({workspaceId:l,profileId:e,reason:"merge",origin:"ai-profiles-module"})}catch{w?.("Failed to merge AI profiles.","error")}},xe=async e=>{if(window.confirm(`Remove ${e.name} from the active roster? This frees an AI profile seat and preserves task and comment history.`)){D(null);try{const o=await fetch("/api/taskforce/workspace/ai-profiles/archive",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:e.id,reason:"manual_archive"})}),s=await o.json().catch(()=>({}));if(!o.ok){D({profileId:e.id,message:String(s?.error||"Failed to remove AI profile from roster.")});return}(S?.keepId===e.id||S?.mergeId===e.id)&&F(null),w?.("AI profile removed from active roster.","success"),await C(),b({workspaceId:l,profileId:e.id,reason:"archive",origin:"ai-profiles-module"})}catch{D({profileId:e.id,message:"Failed to remove AI profile from roster."})}}},Ve=async(e,t)=>{const o=re(t),s=new Set(e.profiles.map(u=>u.surfaceType??"")),d=o??"";if(s.size===1&&s.has(d))return;ce(!0),X(null);const i=[];try{for(const c of e.profiles){const m=await fetch("/api/taskforce/workspace/ai-profiles/surface-type",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:c.id,surfaceType:o})}),v=await m.json().catch(()=>({}));if(!m.ok||!v?.profile)throw new Error(String(v?.error||"Failed to update AI profile category."));const j=v.profile;i.push({...c,surfaceType:re(j.surfaceType),updatedAt:typeof j.updatedAt=="string"?j.updatedAt:c.updatedAt})}const u=new Map(i.map(c=>[c.id,c]));O(c=>c.map(m=>u.get(m.id)||m));const h=u.get(e.primaryProfile.id)||{...e.primaryProfile,surfaceType:o},y=Me(h.surfaceType);_(`${y}:${K(h)}`),w?.("AI profile category updated.","success");for(const c of i)b({workspaceId:l,profileId:c.id,reason:"update",origin:"ai-profiles-module"})}catch(u){X({profileId:e.primaryProfile.id,message:String(u?.message||"Failed to update AI profile category.")})}finally{ce(!1)}},Ie=async(e,t,o=!1)=>{he(!0),Pe(null);try{const s=K(e.primaryProfile),d=N.filter(c=>K(c)===s),i=await fetch("/api/taskforce/workspace/ai-profiles/color",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileIds:d.map(c=>c.id),color:t,reset:o})}),u=await i.text();let h={};try{h=u?JSON.parse(u):{}}catch{h={}}if(!i.ok){const c=i.status===404?"Color updates are unavailable in the running Taskforce server. Restart Taskforce and try again.":`Failed to update AI profile color (HTTP ${i.status}).`;throw new Error(String(h.error||c))}if(!Array.isArray(h.profiles))throw new Error("Taskforce returned an invalid response while updating the AI profile color.");const y=new Map(h.profiles.map(c=>[String(c.id),c]));O(c=>c.map(m=>{const v=y.get(m.id);return v?{...m,color:String(v.color||m.color),colorSource:v.colorSource??m.colorSource,colorUpdatedAt:v.colorUpdatedAt??m.colorUpdatedAt,updatedAt:v.updatedAt??m.updatedAt}:m})),ge(!1);for(const c of d)b({workspaceId:l,profileId:c.id,reason:"update",origin:"ai-profiles-module"})}catch(s){Pe(String(s?.message||"Failed to update AI profile color."))}finally{he(!1)}},je=e=>new Promise((t,o)=>{const s=new FileReader;s.onload=()=>t(String(s.result||"")),s.onerror=()=>o(new Error("Failed to read image file.")),s.readAsDataURL(e)}),Q=e=>{const t=String(e?.id||"").trim();t&&O(o=>o.map(s=>s.id===t?{...s,avatarUrl:typeof e.avatarUrl=="string"?e.avatarUrl:null,avatarSourceUrl:typeof e.avatarSourceUrl=="string"?e.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(e.avatarRevision))?Math.max(0,Math.floor(Number(e.avatarRevision))):s.avatarRevision,avatarUpdatedAt:typeof e.avatarUpdatedAt=="string"?e.avatarUpdatedAt:s.avatarUpdatedAt,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:s.updatedAt}:s))},Ke=async(e,t,o,s=!1)=>{const d=await je(t),i=o?await je(o):null,u={profileId:e,preserveExistingSource:s,displayImage:{dataUrl:d,mimeType:t.type||"application/octet-stream",originalName:t.name||"display-avatar"}};o&&i&&(u.sourceImage={dataUrl:i,mimeType:o.type||"application/octet-stream",originalName:o.name||"source-avatar"});const h=await fetch("/api/taskforce/workspace/ai-profiles/avatar/upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),y=await h.json().catch(()=>({}));if(!h.ok||!y?.profile)throw new Error(String(y?.error||"Failed to update AI profile avatar."));Q(y.profile),b({workspaceId:l,profileId:e,reason:"avatar",origin:"ai-profiles-module"})},We=async e=>{const t=await fetch("/api/taskforce/workspace/ai-profiles/avatar",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:e,avatarUrl:null,avatarSourceUrl:null})}),o=await t.json().catch(()=>({}));if(!t.ok||!o?.profile)throw new Error(String(o?.error||"Failed to update AI profile avatar."));Q(o.profile),b({workspaceId:l,profileId:e,reason:"avatar",origin:"ai-profiles-module"})},Ye=async e=>{if(R)return!1;const t=te(e),o=L(e);if(o&&!window.confirm(`Replace the existing avatar for ${e.name}?`))return!1;const s=t?"":window.prompt("Optional visual direction (300 characters maximum). Leave blank to use the profile details.","");if(s===null)return!1;const d=g==="local";if(d&&(!A||!$||!T||!B))return P("Sign in to Taskforce Cloud to generate profile avatars."),x(null),!1;pe(e.id),P(null),x(null),k(i=>({...i,[e.id]:{error:null,notice:null}}));try{const i=t?`/api/taskforce/agents/${encodeURIComponent(t)}/avatar/generate`:"/api/taskforce/workspace/ai-profiles/avatar/generate",u=d&&B?B(i):i,h=await fetch(u,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(t?{workspaceId:l}:{workspaceId:l,profileId:e.id,visualDirection:s.slice(0,300),replaceExisting:o})}),y=await h.text().catch(()=>"");let c={};if(y&&!/^\s*(?:<!doctype\s+html|<html\b)/i.test(y))try{c=JSON.parse(y)}catch{c={}}if(!h.ok||!c?.profile&&!c?.agent)throw new Error(String(c?.error||(h.status?`Unable to generate avatar. HTTP ${h.status}.`:"Unable to generate avatar.")));const m=c.profile||{id:e.id,avatarUrl:c.agent?.avatarUrl??null,avatarSourceUrl:c.agent?.avatarSourceUrl??null,avatarRevision:c.agent?.avatarRevision??0,avatarUpdatedAt:c.agent?.avatarUpdatedAt??null},v=d&&B?{...m,avatarUrl:m.avatarUrl?Ce(m.avatarUrl):m.avatarUrl,avatarSourceUrl:m.avatarSourceUrl?Ce(m.avatarSourceUrl):m.avatarSourceUrl}:m;return Q(v),k(d?j=>({...j,[e.id]:{error:null,notice:`Generated photo for ${e.name} was saved in Taskforce Cloud. The local copy will be retained when sync runs.`}}):j=>({...j,[e.id]:{error:null,notice:`Generated photo for ${e.name} was saved.`}})),b({workspaceId:l,profileId:e.id,reason:"avatar",origin:"ai-profiles-module",...t?{taskforceAgentAvatar:{agentId:t,avatarUrl:typeof v.avatarUrl=="string"?v.avatarUrl:null,avatarSourceUrl:typeof v.avatarSourceUrl=="string"?v.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(v.avatarRevision))?Math.max(0,Math.floor(Number(v.avatarRevision))):0,avatarUpdatedAt:typeof v.avatarUpdatedAt=="string"?v.avatarUpdatedAt:null}}:{}}),!0}catch(i){return k(u=>({...u,[e.id]:{error:String(i?.message||"Unable to generate profile avatar."),notice:null}})),!1}finally{pe(null)}},Ze=async(e,t,o)=>{if(!p)return!1;if(!e.type.startsWith("image/"))return P("AI profile photo must be an image file."),!1;z(!0),P(null),x(null),k(s=>{const d={...s};return delete d[p.id],d});try{const s=await ke(e,{maxBytes:5242880});if(s.exceededLimit)throw new Error(e.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile photo must be 5 MB or smaller.");const d=s.file;let i=null;if(t){const u=await ke(t,{maxBytes:5242880});if(u.exceededLimit)throw new Error(t.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile source photo must be 5 MB or smaller.");i=u.file}return await Ke(p.id,d,i,o?.preserveExistingSource===!0),!0}catch(s){return P(String(s?.message||"Failed to update AI profile photo.")),!1}finally{z(!1)}},Xe=async()=>{if(p){z(!0),P(null),x(null),k(e=>{const t={...e};return delete t[p.id],t});try{await We(p.id),x("Profile photo removed.")}catch(e){P(String(e?.message||"Failed to remove AI profile photo."))}finally{z(!1)}}},M=e=>{const t=String(e||"").trim();if(!t)return"Unknown";const o=Date.parse(t);return Number.isFinite(o)?new Date(o).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):t},be=f.useMemo(()=>{if(!n)return{attributes:[],dates:[]};const e=n.primaryProfile,t=o=>o||"Not set";return{attributes:[{label:"Category",value:Aa(e)},{label:"Connection",value:e.seatScope?ea(e.seatScope):""},{label:"Provider",value:e.provider||""},{label:"Model",value:e.model||""}].map(o=>({...o,value:t(o.value)})),dates:[{label:"Status",value:e.archivedAt?"Retired":"Active"},{label:"Recruited",value:M(e.createdAt)},{label:"Last updated",value:M(e.updatedAt)},{label:"Last active",value:M(e.lastActiveAt)}].map(o=>({...o,value:t(o.value)}))}},[n]),qe=!!n&&n.profiles.length>1,E=!!n&&!L(n.primaryProfile)&&!!W(n.primaryProfile),Ne=A&&$&&!T,J=A?we(Y):Oe,ee=Ne?"Log into account for Cloud AI Profiles":J?`${J.used}/${J.limit===null?"Unlimited":J.limit}`:null,ae=!!oe;return a.jsxs("section",{className:`${r.agentsModuleRoot} ${ae?r.agentsModuleWithTray:""} ${ae&&Z?r.agentsModuleTrayOpen:""}`.trim(),children:[ae&&a.jsxs("aside",{className:`${r.agentTrayPanel} ${Z?r.agentTrayPanelOpen:""}`.trim(),"aria-label":"AI Profile MCP settings tray","aria-hidden":!Z,children:[a.jsxs("div",{className:r.agentTrayHeader,children:[a.jsxs("span",{className:r.agentTrayTitle,children:[a.jsx(ca,{size:14}),"MCP Settings"]}),a.jsx("button",{type:"button",className:"tf-control-icon",onClick:$e,title:"Collapse AI Profile tray","aria-label":"Collapse AI Profile tray",children:a.jsx(da,{size:16})})]}),a.jsx("div",{className:`${r.agentTrayContent} tf-scrollbar tf-scrollbar--track-transparent`,children:a.jsx("div",{className:r.agentTrayContentInner,children:oe})})]}),a.jsx("div",{className:r.agentsModuleContent,children:a.jsxs("div",{className:r.aiProfilesExplorer,children:[a.jsxs("aside",{className:r.aiProfilesRosterPanel,"aria-label":"AI profile roster",children:[a.jsx("div",{className:r.taskforceAgentRosterHeader,children:a.jsxs("span",{className:r.taskforceAgentRosterTitle,children:[a.jsx(fa,{size:14}),"AI Profiles"]})}),ee&&a.jsx("div",{className:r.aiProfilesRosterSummary,children:a.jsx("div",{className:r.aiProfileSeatSummary,children:Ne?ee:`Registered Cloud AI Profiles: ${ee}`})}),Ge?a.jsxs("div",{className:r.aiProfilesRosterState,role:"status","aria-live":"polite",children:[a.jsx(ua,{size:13,className:r.spinner})," Loading profiles…"]}):N.length===0?a.jsx("div",{className:r.aiProfilesRosterState,children:"No AI profiles registered yet."}):H.length>0?a.jsx("div",{className:`${r.aiProfilesListPane} tf-scrollbar tf-scrollbar--track-transparent tf-tray-scroll-viewport`,children:a.jsx("div",{className:r.aiProfilesList,children:H.map(e=>a.jsxs("div",{className:r.aiProfilesSection,children:[a.jsx("div",{className:r.aiProfilesSectionHeader,children:e.label}),e.groups.map(t=>{const o=n?.groupId===t.groupId,s=t.primaryProfile,d=!L(s)&&!!W(s);return a.jsx(sa,{name:s.name,username:s.username,subtitle:s.role||"Role not set",selected:o,onSelect:()=>_(t.groupId),avatarVariant:d?"logo":"portrait",avatar:a.jsx(ya,{profile:s}),avatarStyle:{color:s.color},className:t.profiles.length>1?r.aiProfileGroupDuplicate:"",topUtility:De(s.seatScope),bottomUtility:a.jsx("span",{className:r.aiProfileGroupSignatureSwatch,style:{backgroundColor:s.color},title:`Signature color ${s.color}`,"aria-hidden":"true"}),footer:t.profiles.length>1?a.jsxs("span",{className:r.aiProfileDuplicateBadge,children:[a.jsx(V,{size:11})," ",Sa(t.profiles.length)]}):null},t.groupId)})]},e.section))})}):null]}),a.jsx("main",{className:`${r.aiProfilesDetailViewport} tf-scrollbar`,"aria-label":"AI profile details",children:n&&a.jsx("div",{className:r.aiProfileDetailPane,children:a.jsxs("div",{className:r.aiProfileDetailCard,children:[De(n.primaryProfile.seatScope,{variant:"detail"}),a.jsxs("div",{className:r.aiProfileDetailHero,children:[a.jsx(aa,{label:"Edit AI profile photo",imageUrl:ie(n.primaryProfile),fallbackImageUrl:W(n.primaryProfile),fallback:a.jsx(Le,{size:38}),accentColor:E?null:n.primaryProfile.color,size:176,width:E?176:153,height:E?176:207,radius:E?0:6,editBadgeSize:28,editIconSize:14,loading:R===n.primaryProfile.id,loadingLabel:`Generating ${n.primaryProfile.name} photo`,error:!!Se?.error,errorLabel:Se?.error||"Profile photo generation failed",className:`${r.aiProfileDetailAvatar} ${E?r.aiProfileDetailAvatarLogo:""}`.trim(),onClick:()=>{P(null),x(null),fe(n.primaryProfile.id)}}),a.jsxs("div",{className:r.aiProfileDetailHeading,children:[a.jsx("div",{className:r.aiProfileDetailTitleRow,children:a.jsx("h5",{className:r.aiProfileDetailTitle,children:n.primaryProfile.name})}),a.jsxs("div",{className:r.aiProfileDetailMetaRow,children:[a.jsxs("span",{className:r.aiProfileDetailHandle,children:["@",n.primaryProfile.username]}),n.profiles.length>1&&a.jsxs("span",{className:r.aiProfileDetailLinkedCount,children:[n.profiles.length," linked"]})]}),a.jsxs("div",{className:r.aiProfileDetailRole,children:["Role: ",n.primaryProfile.role||"Not set"]}),n.primaryProfile.description&&a.jsx("div",{className:r.aiProfileDetailDescription,children:n.primaryProfile.description}),a.jsxs("div",{className:r.aiProfileSignatureColor,children:[a.jsx("span",{children:"Signature color"}),a.jsxs("button",{type:"button",className:r.aiProfileSignatureColorButton,onClick:()=>ge(e=>!e),disabled:q,"aria-expanded":ve,"aria-label":"Change signature color",children:[a.jsx("span",{className:r.aiProfileSignatureSwatch,style:{backgroundColor:n.primaryProfile.color},"aria-hidden":"true"}),a.jsx("span",{children:n.primaryProfile.color})]})]}),ve&&a.jsxs("div",{className:r.aiProfileColorPicker,"aria-label":"Signature color options",children:[na.map(({name:e,value:t})=>a.jsx("button",{type:"button",className:r.aiProfileColorOption,style:{backgroundColor:t},"aria-label":`Use ${e}`,"aria-pressed":n.primaryProfile.color.toLowerCase()===t.toLowerCase(),disabled:q,onClick:()=>{Ie(n,t)}},t)),a.jsx("button",{type:"button",className:r.secondaryHeaderBtn,disabled:q,onClick:()=>{Ie(n,void 0,!0)},children:"Reset"})]}),ye&&a.jsx("div",{className:r.aiProfileInlineError,children:ye})]})]}),a.jsxs("div",{className:r.aiProfileDetailDataList,children:[a.jsx("div",{className:r.aiProfileDetailDataGroup,children:be.attributes.map(e=>a.jsxs("div",{className:r.aiProfileDetailDataRow,children:[a.jsx("span",{className:r.aiProfileDetailDataLabel,children:e.label}),e.label==="Category"&&!le(n.primaryProfile)?a.jsx("span",{className:r.aiProfileDetailDataValue,children:a.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent category",value:n.primaryProfile.surfaceType??"",disabled:_e,onChange:t=>{Ve(n,t.target.value)},children:[a.jsx("option",{value:"",children:"Unclassified"}),ra.map(t=>a.jsx("option",{value:t,children:Re(t)},t))]})}):a.jsx("span",{className:r.aiProfileDetailDataValue,children:e.value})]},e.label))}),a.jsx("div",{className:`${r.aiProfileDetailDataGroup} ${r.aiProfileDetailDateGroup}`,children:be.dates.map(e=>a.jsxs("div",{className:r.aiProfileDetailDataRow,children:[a.jsx("span",{className:r.aiProfileDetailDataLabel,children:e.label}),e.label==="Status"?a.jsx("span",{className:r.aiProfileDetailDataValue,children:a.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent roster status",value:n.primaryProfile.archivedAt?"retired":"active",onChange:t=>{t.target.value==="retire"&&xe(n.primaryProfile)},children:[a.jsx("option",{value:"active",children:"Active"}),n.primaryProfile.archivedAt?a.jsx("option",{value:"retired",children:"Retired"}):a.jsx("option",{value:"retire",children:"Retire from roster"})]})}):a.jsx("span",{className:r.aiProfileDetailDataValue,children:e.value})]},e.label))})]}),ne?.profileId===n.primaryProfile.id&&a.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[a.jsx(V,{size:12}),a.jsx("span",{children:ne.message})]}),qe?a.jsxs("div",{className:r.aiProfileInstanceSection,children:[a.jsxs("div",{className:r.aiProfileInstanceSectionHeader,children:[a.jsx("span",{children:"Profile instances"}),a.jsx("span",{className:r.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),a.jsx("div",{className:r.aiProfileInstanceList,children:n.profiles.map(e=>a.jsxs("div",{className:r.aiProfileInstanceCard,children:[a.jsxs("div",{className:r.aiProfileInstanceTopRow,children:[a.jsxs("div",{children:[a.jsxs("div",{className:r.aiProfileInstanceName,children:["@",e.username]}),a.jsx("div",{className:r.aiProfileIdChip,children:e.id})]}),S?.keepId===e.id&&a.jsx("span",{className:r.aiProfileKeepBadge,children:"Keeping"})]}),a.jsxs("div",{className:r.aiProfileInstanceMeta,children:[a.jsxs("span",{children:["Created ",M(e.createdAt)]}),a.jsxs("span",{children:["Updated ",M(e.updatedAt)]})]}),S?.keepId!==e.id&&a.jsx("button",{className:r.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const t=n.profiles.find(o=>o.id!==e.id)?.id;t&&F({keepId:e.id,mergeId:t})},children:"Keep this"}),G?.profileId===e.id&&a.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[a.jsx(V,{size:12}),a.jsx("span",{children:G.message})]}),a.jsx("button",{className:r.aiProfileDangerTextButton,title:"Remove this profile from the active roster",onClick:()=>{xe(e)},children:"Remove from roster"})]},e.id))}),S&&n.profiles.some(e=>e.id===S.keepId)&&a.jsxs("div",{className:r.aiProfileMergeActions,children:[a.jsx("button",{className:r.dangerBtn,onClick:()=>{Je(S.keepId,S.mergeId)},children:"Merge duplicates"}),a.jsx("button",{className:r.secondaryHeaderBtn,onClick:()=>F(null),children:"Cancel"})]})]}):a.jsxs("div",{className:r.aiProfileIdFooter,children:[a.jsx("div",{className:r.aiProfileIdFooterValue,children:n.primaryProfile.id}),G?.profileId===n.primaryProfile.id&&a.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[a.jsx(V,{size:12}),a.jsx("span",{children:G.message})]})]})]})})})]})}),a.jsx(ta,{isOpen:!!p,theme:Be,title:"Edit AI Profile Photo",currentImageUrl:ie(p),editorImageUrl:ga(p),fallbackInitial:(p?.name||"AI").charAt(0).toUpperCase(),accept:"image/png,image/jpeg,image/webp,image/gif",busy:ue,generating:R===p?.id,generateLabel:p&&L(p)?"Regenerate":"Generate",hasPendingImage:!1,canRemove:!!p?.avatarUrl,error:ze||Ae?.error||null,notice:He||Ae?.notice||null,onClose:()=>{ue||(fe(null),P(null),x(null))},onApplyImage:Ze,onGenerateImage:p&&(!R||R===p.id)&&(ia(p)||te(p))?()=>Ye(p):void 0,onRemoveImage:Xe},p?.id||"ai-profile-avatar-closed")]})}export{Ca as AiProfilesModule};
|