@codemem/server 0.46.0-beta.1 → 0.46.0-beta.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"coordinator-maintenance.d.ts","sourceRoot":"","sources":["../../src/application/coordinator-maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,8BAA8B,EACnC,KAAK,gCAAgC,EACrC,+BAA+B,EAC/B,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,kCAAkC;IAClD,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,wBAAwB,GAAG,WAAW,CAAC;CACzD;AAED,MAAM,WAAW,iCAAiC;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QACZ,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EACJ,UAAU,GACV,wBAAwB,GACxB,oBAAoB,GACpB,iBAAiB,GACjB,iBAAiB,GACjB,YAAY,GACZ,QAAQ,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACH;AAED,MAAM,MAAM,4BAA4B,GAAG,CAC1C,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,MAAM,KACf,OAAO,CAAC,kCAAkC,CAAC,CAAC;AA2BjD,eAAO,MAAM,oCAAoC,aAc/C,CAAC;AAwLH,wBAAsB,oCAAoC,CACzD,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,gBAAgB,EAAE,4BAA4B,CAAA;CAAE,GACrF,OAAO,CAAC,iCAAiC,CAAC,CAuB5C;AAED,MAAM,WAAW,sCAAsC;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QACZ,wBAAwB,EAAE,MAAM,CAAC;QACjC,MAAM,EAAE,8BAA8B,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;QAC5D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC,CAAC;CACH;AAMD,wBAAsB,yCAAyC,CAC9D,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IACR,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,gCAAgC,CAAC;IAC1C,gBAAgB,CAAC,EAAE,OAAO,+BAA+B,CAAC;CAC1D,GACC,OAAO,CAAC,sCAAsC,CAAC,CAuEjD"}
1
+ {"version":3,"file":"coordinator-maintenance.d.ts","sourceRoot":"","sources":["../../src/application/coordinator-maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,WAAW,EAChB,KAAK,8BAA8B,EACnC,KAAK,gCAAgC,EACrC,+BAA+B,EAE/B,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,kCAAkC;IAClD,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,wBAAwB,GAAG,WAAW,CAAC;CACzD;AAED,MAAM,WAAW,iCAAiC;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QACZ,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EACJ,UAAU,GACV,wBAAwB,GACxB,oBAAoB,GACpB,iBAAiB,GACjB,iBAAiB,GACjB,YAAY,GACZ,QAAQ,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACH;AAED,MAAM,MAAM,4BAA4B,GAAG,CAC1C,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,MAAM,KACf,OAAO,CAAC,kCAAkC,CAAC,CAAC;AA6BjD,eAAO,MAAM,oCAAoC,aAc/C,CAAC;AAwLH,wBAAsB,oCAAoC,CACzD,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,gBAAgB,EAAE,4BAA4B,CAAA;CAAE,GACrF,OAAO,CAAC,iCAAiC,CAAC,CAuB5C;AAED,MAAM,WAAW,sCAAsC;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QACZ,wBAAwB,EAAE,MAAM,CAAC;QACjC,MAAM,EAAE,8BAA8B,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;QAC5D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC,CAAC;CACH;AAkHD,wBAAsB,yCAAyC,CAC9D,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IACR,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,gCAAgC,CAAC;IAC1C,gBAAgB,CAAC,EAAE,OAAO,+BAA+B,CAAC;CAC1D,GACC,OAAO,CAAC,sCAAsC,CAAC,CAwDjD"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { dirname, isAbsolute, join, posix, resolve, win32 } from "node:path";
3
- import { ACCESS_CLEANUP_OP_TYPE, CodememConfigMutationError, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, LegacyTeamSetupRosterCapacityError, MEMORY_FILTER_FIELD_TYPES, MEMORY_FILTER_NAMES, MEMORY_KIND_DESCRIPTIONS, MemoryStore, ObserverClient, PROMPT_TRANSPORT_PROTOCOL_RANGE, REMEMBER_MEMORY_KINDS, RawEventIngestValidationError, RecipientPolicyEdgeRequestError, RecipientPolicyTeamRenameError, RemoteCoordinatorRequestError, SCOPE_MEMBERSHIP_REVOCATION_LIMITATION, SYNC_AUTHORIZATION_REFRESH_HEADER, SYNC_CAPABILITY_HEADER, SYNC_FEATURES_HEADER, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, VIEWER_IDENTITY_TARGET_KEYS, VIEWER_SERVICE_DISCRIMINATOR, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, automaticRecallHealth, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildFilterClausesWithContext, buildPiFlushSignalFromEvent, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildRawEventEnvelopeFromPiEvent, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, canonicalWorkspaceIdentity, claimRecipientPolicyActorMutations, claimRecipientPolicyPublicationMutation, cleanupNonces, clearLegacyTeamSetupDeviceDecision, clonePromptPackAttempt, coerceObserverCommand, commitDeviceIdentityBindings, commitRecipientPolicyEdges, containLegacyTeamSetupCompletionConflict, coordinatorArchiveGroupAction, coordinatorCreateAddDeviceInviteAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateLegacyTeamCompletionAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGetLegacyTeamCompletionAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListConsumedTeamInvitesAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListLegacyTeamCompletionsAction, coordinatorListReviewedRecipientInviteEvidenceAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, countShareableProjectMemories, createCoordinatorReciprocalApproval, decodeInvitePayload, dedupeOrderedIds, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, getCodememConfigPath, getCodememEnvOverrideValues, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isAutomaticRecallMeasurement, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, judgeDistillReport, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, memoryFilterValueMatchesType, mergeAddresses, migrateRecipientPolicyIntent, mutateCodememConfigFile, negotiateSyncCapability, normalizeAddress, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectMatchesFilter, projectShareLifecycle, promptPackArtifactFingerprint, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordAutomaticRecall, recordHighestObservedDirectSignatureVersion, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveDbPath, resolveObserverRuntime, resolveProject, resolveProjectRoot, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, runSyncPass, schema, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, storeVectors, summarizeInboundScopeRejections, summaryLikeSqlPredicate, supportsSyncFeature, syncScopeResetRequiredPayload, toJson, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMapping, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, validateRawEvents, verifyDirectPeerSignature, verifyRecipientReviewedIntent, verifySignature } from "@codemem/core";
3
+ import { ACCESS_CLEANUP_OP_TYPE, CodememConfigMutationError, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, LegacyTeamSetupRosterCapacityError, MEMORY_FILTER_FIELD_TYPES, MEMORY_FILTER_NAMES, MEMORY_KIND_DESCRIPTIONS, MemoryStore, ObserverClient, PROMPT_TRANSPORT_PROTOCOL_RANGE, REMEMBER_MEMORY_KINDS, RawEventIngestValidationError, RecipientPolicyEdgeRequestError, RecipientPolicyTeamRenameError, RemoteCoordinatorRequestError, SCOPE_MEMBERSHIP_REVOCATION_LIMITATION, SYNC_AUTHORIZATION_REFRESH_HEADER, SYNC_CAPABILITY_HEADER, SYNC_FEATURES_HEADER, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, VIEWER_IDENTITY_TARGET_KEYS, VIEWER_SERVICE_DISCRIMINATOR, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, analyzeProjectScopeMappingChangesGuardrails, analyzeProjectScopeMappingDeletionGuardrails, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, automaticRecallHealth, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildFilterClausesWithContext, buildPiFlushSignalFromEvent, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildRawEventEnvelopeFromPiEvent, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, canonicalRepositoryProjectIdentity, canonicalWorkspaceIdentity, claimRecipientPolicyActorMutations, claimRecipientPolicyPublicationMutation, cleanupNonces, clearLegacyTeamSetupDeviceDecision, clonePromptPackAttempt, coerceObserverCommand, commitDeviceIdentityBindings, commitRecipientPolicyEdges, containLegacyTeamSetupCompletionConflict, coordinatorArchiveGroupAction, coordinatorCreateAddDeviceInviteAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateLegacyTeamCompletionAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGetLegacyTeamCompletionAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListConsumedTeamInvitesAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListLegacyTeamCompletionsAction, coordinatorListReviewedRecipientInviteEvidenceAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, countShareableProjectMemories, createCoordinatorReciprocalApproval, decodeInvitePayload, dedupeOrderedIds, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, getCodememConfigPath, getCodememEnvOverrideValues, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isAutomaticRecallMeasurement, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, judgeDistillReport, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadReplicationOpsForPeer, lookupCoordinatorPeers, memoryFilterValueMatchesType, mergeAddresses, migrateRecipientPolicyIntent, mutateCodememConfigFile, negotiateSyncCapability, normalizeAddress, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectMatchesFilter, projectShareLifecycle, promptPackArtifactFingerprint, readCodememConfigFile, readCoordinatorSyncConfig, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordAutomaticRecall, recordHighestObservedDirectSignatureVersion, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, repositoryIdentitiesByWorkspace, repositoryIdentityForWorkspace, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveDbPath, resolveObserverRuntime, resolveProject, resolveProjectRoot, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, runSyncPass, schema, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, storeVectors, summarizeInboundScopeRejections, summaryLikeSqlPredicate, supportsSyncFeature, syncScopeResetRequiredPayload, toJson, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMappings, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, validateRawEvents, verifyDirectPeerSignature, verifyRecipientReviewedIntent, verifySignature, wakeRecipientPoliciesForIdentities, wakeRecipientPoliciesForProjectIdentities } from "@codemem/core";
4
4
  import { serveStatic } from "@hono/node-server/serve-static";
5
5
  import { Hono } from "hono";
6
6
  import { createMiddleware } from "hono/factory";
@@ -3847,6 +3847,8 @@ var AUTOMATIC_WAITING_ACCEPTANCE_RETRY_COOLDOWN_MS = 3e4;
3847
3847
  var AUTOMATIC_WAITING_DEVICE_RETRY_COOLDOWN_MS = 3e5;
3848
3848
  var TERMINAL_SHARE_MAINTENANCE_ERRORS = /* @__PURE__ */ new Set([
3849
3849
  "coordinator_not_configured",
3850
+ "conflicting_repository_mappings",
3851
+ "project_mapping_conflict",
3850
3852
  "team_sharing_not_configured",
3851
3853
  "team_selection_ambiguous",
3852
3854
  "initiating_device_not_reviewed",
@@ -4048,25 +4050,69 @@ async function advancePendingProjectSharesOperation(store, options) {
4048
4050
  var RECIPIENT_POLICY_MAINTENANCE_MAX_LIMIT = 10;
4049
4051
  var RECIPIENT_POLICY_MAINTENANCE_DEFAULT_LIMIT = 3;
4050
4052
  var RECIPIENT_POLICY_MAINTENANCE_BACKOFF_MS = 6e4;
4053
+ function recipientPolicyMaintenanceCandidates(store, retryBefore, limit) {
4054
+ const repositoryIdentities = repositoryIdentitiesByWorkspace(store.db);
4055
+ const canonicalize = (projectId) => canonicalRepositoryProjectIdentity(repositoryIdentities, projectId);
4056
+ const projectIds = store.db.prepare(`SELECT canonical_project_identity FROM project_recipients
4057
+ UNION SELECT canonical_project_identity FROM recipient_policy_authority_states`).all();
4058
+ const authorityRows = store.db.prepare(`SELECT authority_state, canonical_project_identity, last_attempt_at, safe_error_code
4059
+ FROM recipient_policy_authority_states`).all();
4060
+ const authorityByProject = /* @__PURE__ */ new Map();
4061
+ for (const row of authorityRows) {
4062
+ const projectId = canonicalize(row.canonical_project_identity);
4063
+ const current = authorityByProject.get(projectId);
4064
+ if (!current) {
4065
+ authorityByProject.set(projectId, row);
4066
+ continue;
4067
+ }
4068
+ if (current.canonical_project_identity === projectId) continue;
4069
+ if (row.canonical_project_identity === projectId) {
4070
+ authorityByProject.set(projectId, row);
4071
+ continue;
4072
+ }
4073
+ if (String(row.last_attempt_at ?? "") > String(current.last_attempt_at ?? "")) authorityByProject.set(projectId, row);
4074
+ }
4075
+ return [...new Set(projectIds.map((row) => canonicalize(row.canonical_project_identity)))].filter((projectId) => {
4076
+ const authority = authorityByProject.get(projectId);
4077
+ return authority == null || authority.last_attempt_at == null || authority.safe_error_code == null && authority.authority_state !== "active" || authority.last_attempt_at <= retryBefore;
4078
+ }).toSorted((left, right) => {
4079
+ const leftAttempt = authorityByProject.get(left)?.last_attempt_at;
4080
+ const rightAttempt = authorityByProject.get(right)?.last_attempt_at;
4081
+ if (leftAttempt == null && rightAttempt != null) return -1;
4082
+ if (leftAttempt != null && rightAttempt == null) return 1;
4083
+ return String(leftAttempt ?? "").localeCompare(String(rightAttempt ?? "")) || left.localeCompare(right);
4084
+ }).slice(0, limit);
4085
+ }
4086
+ function recordRecipientPolicyMaintenanceFailure(store, projectId, attemptedAt) {
4087
+ store.db.prepare(`INSERT INTO recipient_policy_authority_states(
4088
+ canonical_project_identity, state_changed_at, created_at, updated_at,
4089
+ attempt_count, last_attempt_at, safe_error_code, last_error_at
4090
+ ) VALUES (?, ?, ?, ?, 1, ?, 'recipient_policy_reconciliation_failed', ?)
4091
+ ON CONFLICT(canonical_project_identity) DO UPDATE SET
4092
+ attempt_count = attempt_count + 1, last_attempt_at = excluded.last_attempt_at,
4093
+ safe_error_code = excluded.safe_error_code, last_error_at = excluded.last_error_at,
4094
+ updated_at = excluded.updated_at`).run(projectId, attemptedAt, attemptedAt, attemptedAt, attemptedAt, attemptedAt);
4095
+ }
4096
+ function isSqliteBusy$1(error) {
4097
+ if (!error || typeof error !== "object" || !("code" in error)) return false;
4098
+ const code = error.code;
4099
+ return typeof code === "string" && (code.startsWith("SQLITE_BUSY") || code.startsWith("SQLITE_LOCKED"));
4100
+ }
4101
+ function recordMaintenanceFailureIfAvailable(store, projectId, attemptedAt, error) {
4102
+ if (isSqliteBusy$1(error)) return;
4103
+ try {
4104
+ recordRecipientPolicyMaintenanceFailure(store, projectId, attemptedAt);
4105
+ } catch (bookkeepingError) {
4106
+ if (!isSqliteBusy$1(bookkeepingError)) throw bookkeepingError;
4107
+ }
4108
+ }
4051
4109
  async function reconcileRecipientPolicyProjectsOperation(store, options) {
4052
4110
  const limit = Math.max(1, Math.min(Math.trunc(options.limit ?? RECIPIENT_POLICY_MAINTENANCE_DEFAULT_LIMIT), RECIPIENT_POLICY_MAINTENANCE_MAX_LIMIT));
4053
4111
  const maintenanceNow = options.now ?? /* @__PURE__ */ new Date();
4054
4112
  const backoffMs = Math.max(0, Math.trunc(options.backoffMs ?? RECIPIENT_POLICY_MAINTENANCE_BACKOFF_MS));
4055
4113
  const retryBefore = new Date(maintenanceNow.getTime() - backoffMs).toISOString();
4056
- const rows = store.db.prepare(`WITH projects AS (
4057
- SELECT DISTINCT canonical_project_identity FROM project_recipients
4058
- UNION
4059
- SELECT canonical_project_identity FROM recipient_policy_authority_states
4060
- )
4061
- SELECT projects.canonical_project_identity
4062
- FROM projects
4063
- LEFT JOIN recipient_policy_authority_states authority
4064
- ON authority.canonical_project_identity = projects.canonical_project_identity
4065
- WHERE authority.safe_error_code IS NULL OR authority.last_attempt_at IS NULL
4066
- OR authority.last_attempt_at <= ?
4067
- ORDER BY CASE WHEN authority.last_attempt_at IS NULL THEN 0 ELSE 1 END,
4068
- authority.last_attempt_at, projects.canonical_project_identity
4069
- LIMIT ?`).all(retryBefore, limit);
4114
+ const attemptedAt = maintenanceNow.toISOString();
4115
+ const projectIds = recipientPolicyMaintenanceCandidates(store, retryBefore, limit);
4070
4116
  const reconcileProject = options.reconcileProject ?? reconcileRecipientPolicyProject;
4071
4117
  const result = {
4072
4118
  processed: 0,
@@ -4076,25 +4122,26 @@ async function reconcileRecipientPolicyProjectsOperation(store, options) {
4076
4122
  failed: 0,
4077
4123
  items: []
4078
4124
  };
4079
- for (const row of rows) {
4125
+ for (const projectId of projectIds) {
4080
4126
  result.processed += 1;
4081
4127
  try {
4082
4128
  const outcome = await reconcileProject(store.db, {
4083
- canonicalProjectIdentity: row.canonical_project_identity,
4129
+ canonicalProjectIdentity: projectId,
4084
4130
  leaseOwner: options.leaseOwner ?? `recipient-policy-maintenance:${store.deviceId || process.pid}`
4085
4131
  }, options.effects);
4086
4132
  if (outcome.status === "active") result.active += 1;
4087
4133
  else if (outcome.status === "needs_attention") result.attention += 1;
4088
4134
  else result.waiting += 1;
4089
4135
  result.items.push({
4090
- canonicalProjectIdentity: row.canonical_project_identity,
4136
+ canonicalProjectIdentity: projectId,
4091
4137
  status: outcome.status,
4092
4138
  safeErrorCode: outcome.safeErrorCode
4093
4139
  });
4094
- } catch {
4140
+ } catch (error) {
4141
+ recordMaintenanceFailureIfAvailable(store, projectId, attemptedAt, error);
4095
4142
  result.failed += 1;
4096
4143
  result.items.push({
4097
- canonicalProjectIdentity: row.canonical_project_identity,
4144
+ canonicalProjectIdentity: projectId,
4098
4145
  status: "failed",
4099
4146
  safeErrorCode: "recipient_policy_reconciliation_failed"
4100
4147
  });
@@ -6594,6 +6641,14 @@ function missingGuardrailConfirmations(warnings, confirmedTokens) {
6594
6641
  const confirmed = new Set(confirmedTokens);
6595
6642
  return warnings.filter((warning) => warning.requires_confirmation && (!warning.confirmation_token || !confirmed.has(warning.confirmation_token)));
6596
6643
  }
6644
+ function mappingGuardrailChallenge(warnings, missing) {
6645
+ return {
6646
+ error: "guardrail_confirmation_required",
6647
+ required_guardrails: [...new Set(missing.map((warning) => warning.code))],
6648
+ required_guardrail_tokens: [...new Set(missing.map((warning) => warning.confirmation_token))].filter((token) => typeof token === "string" && token.length > 0),
6649
+ guardrail_warnings: warnings
6650
+ };
6651
+ }
6597
6652
  function parseViewerProjectMappingInput(body) {
6598
6653
  const id = optionalViewerInteger(body, "id");
6599
6654
  const priority = optionalViewerInteger(body, "priority");
@@ -6608,6 +6663,14 @@ function parseViewerProjectMappingInput(body) {
6608
6663
  source: optionalViewerStrictString(body, "source") ?? "user"
6609
6664
  };
6610
6665
  }
6666
+ function parseViewerProjectMappingInputs(body) {
6667
+ const rawMappings = body.mappings;
6668
+ if (!Array.isArray(rawMappings) || rawMappings.length === 0) throw new Error("mappings must be a non-empty array");
6669
+ return rawMappings.map((raw) => {
6670
+ if (raw == null || typeof raw !== "object" || Array.isArray(raw)) throw new Error("each mapping must be an object");
6671
+ return parseViewerProjectMappingInput(raw);
6672
+ });
6673
+ }
6611
6674
  function coordinatorAdminMutationStatus(message) {
6612
6675
  if (message.includes("scope_not_found") || message.includes("membership_not_found") || message.includes("group_not_found") || message.includes("Group not found") || message.includes("Scope not found") || message.includes("device_not_enrolled_for_scope_group") || message.includes("device must be enrolled")) return 404;
6613
6676
  if (message.includes("not active") || message.includes("scope_not_active") || message.includes("scope_membership_effect_conflict") || message.includes("group_archived") || message.includes("Group is archived")) return 409;
@@ -7565,13 +7628,25 @@ function recipientPolicyReadCopy(state) {
7565
7628
  explanation: "Legacy scope enforcement remains in control while reconciliation is pending."
7566
7629
  };
7567
7630
  }
7631
+ function recipientPolicyAuthorityForAliases(store, canonicalProjectIdentity, aliases) {
7632
+ const canonical = getRecipientPolicyAuthorityState(store.db, canonicalProjectIdentity);
7633
+ if (canonical) return canonical;
7634
+ return aliases.filter((identity) => identity !== canonicalProjectIdentity).map((identity) => getRecipientPolicyAuthorityState(store.db, identity)).filter((state) => state != null).toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))[0] ?? null;
7635
+ }
7568
7636
  function listRecipientPolicyReconciliationStatus(store) {
7637
+ const projectIds = store.db.prepare(`SELECT DISTINCT canonical_project_identity FROM project_recipients WHERE status = 'active'
7638
+ UNION SELECT canonical_project_identity FROM recipient_policy_authority_states
7639
+ ORDER BY canonical_project_identity`).all().map((row) => row.canonical_project_identity);
7640
+ const repositoryIdentities = repositoryIdentitiesByWorkspace(store.db);
7641
+ const aliasesByProject = /* @__PURE__ */ new Map();
7642
+ for (const projectId of projectIds) {
7643
+ const canonical = canonicalRepositoryProjectIdentity(repositoryIdentities, projectId);
7644
+ aliasesByProject.set(canonical, [...aliasesByProject.get(canonical) ?? [], projectId]);
7645
+ }
7569
7646
  return {
7570
7647
  version: 1,
7571
- items: store.db.prepare(`SELECT DISTINCT canonical_project_identity FROM project_recipients WHERE status = 'active'
7572
- UNION SELECT canonical_project_identity FROM recipient_policy_authority_states
7573
- ORDER BY canonical_project_identity`).all().map((row) => row.canonical_project_identity).map((canonicalProjectIdentity) => {
7574
- const state = recipientPolicyReadState(getRecipientPolicyAuthorityState(store.db, canonicalProjectIdentity));
7648
+ items: [...aliasesByProject.keys()].toSorted().map((canonicalProjectIdentity) => {
7649
+ const state = recipientPolicyReadState(recipientPolicyAuthorityForAliases(store, canonicalProjectIdentity, aliasesByProject.get(canonicalProjectIdentity) ?? []));
7575
7650
  return {
7576
7651
  canonicalProjectIdentity,
7577
7652
  state,
@@ -8565,6 +8640,7 @@ function addLegacySharedReviewRow(groups, row, identity, candidate, isOwnedBySel
8565
8640
  }
8566
8641
  function collectLegacySharedReviewGroups(store) {
8567
8642
  const ownedBySelf = store.buildOwnershipPredicate();
8643
+ const repositoryIdentities = repositoryIdentitiesByWorkspace(store.db);
8568
8644
  const candidatesByIdentity = new Map(listProjectScopeCandidates(store.db, { limit: null }).map((candidate) => [candidate.workspace_identity, candidate]));
8569
8645
  const groups = /* @__PURE__ */ new Map();
8570
8646
  let memoryCount = 0;
@@ -8576,6 +8652,11 @@ function collectLegacySharedReviewGroups(store) {
8576
8652
  cwd: row.cwd,
8577
8653
  gitBranch: row.git_branch,
8578
8654
  gitRemote: row.git_remote,
8655
+ repositoryIdentity: repositoryIdentityForWorkspace(repositoryIdentities, {
8656
+ cwd: row.cwd,
8657
+ gitRemote: row.git_remote,
8658
+ metadataJson: row.session_metadata_json
8659
+ }),
8579
8660
  project: row.project,
8580
8661
  workspaceId: row.workspace_id
8581
8662
  });
@@ -8650,7 +8731,8 @@ function legacySharedReviewSummaryRows(store) {
8650
8731
  m.workspace_id,
8651
8732
  m.actor_id,
8652
8733
  m.origin_device_id,
8653
- m.metadata_json
8734
+ m.metadata_json,
8735
+ s.metadata_json AS session_metadata_json
8654
8736
  FROM memory_items m
8655
8737
  LEFT JOIN sessions s ON s.id = m.session_id
8656
8738
  WHERE m.scope_id = ?
@@ -8690,7 +8772,8 @@ function legacySharedReviewRows(store) {
8690
8772
  m.workspace_id,
8691
8773
  m.actor_id,
8692
8774
  m.origin_device_id,
8693
- m.metadata_json
8775
+ m.metadata_json,
8776
+ s.metadata_json AS session_metadata_json
8694
8777
  FROM memory_items m
8695
8778
  LEFT JOIN sessions s ON s.id = m.session_id
8696
8779
  WHERE m.scope_id = ?
@@ -8707,7 +8790,7 @@ function legacySharedReviewConfirmationToken(input) {
8707
8790
  return Buffer.from(`${input.workspaceIdentity}|${input.scopeId}|${payload}`, "utf8").toString("base64url");
8708
8791
  }
8709
8792
  function projectInventoryRowsForWorkspace(store, workspaceIdentity) {
8710
- return store.db.prepare(`SELECT m.id,
8793
+ const rows = store.db.prepare(`SELECT m.id,
8711
8794
  m.rev,
8712
8795
  s.project,
8713
8796
  s.cwd,
@@ -8716,15 +8799,23 @@ function projectInventoryRowsForWorkspace(store, workspaceIdentity) {
8716
8799
  m.workspace_id,
8717
8800
  m.actor_id,
8718
8801
  m.origin_device_id,
8719
- m.metadata_json
8802
+ m.metadata_json,
8803
+ s.metadata_json AS session_metadata_json
8720
8804
  FROM memory_items m
8721
8805
  LEFT JOIN sessions s ON s.id = m.session_id
8722
8806
  WHERE m.active = 1
8723
- AND m.deleted_at IS NULL`).all().filter((row) => {
8807
+ AND m.deleted_at IS NULL`).all();
8808
+ const repositoryIdentities = repositoryIdentitiesByWorkspace(store.db);
8809
+ return rows.filter((row) => {
8724
8810
  return canonicalWorkspaceIdentity({
8725
8811
  cwd: row.cwd,
8726
8812
  gitBranch: row.git_branch,
8727
8813
  gitRemote: row.git_remote,
8814
+ repositoryIdentity: repositoryIdentityForWorkspace(repositoryIdentities, {
8815
+ cwd: row.cwd,
8816
+ gitRemote: row.git_remote,
8817
+ metadataJson: row.session_metadata_json
8818
+ }),
8728
8819
  project: row.project,
8729
8820
  workspaceId: row.workspace_id
8730
8821
  }).value === workspaceIdentity;
@@ -8778,11 +8869,17 @@ function assertLocalDeviceScopeMembership(store, scopeId) {
8778
8869
  LIMIT 1`).get(scopeId, store.deviceId)) throw new Error(`local device is not a member of Sharing domain ${scopeId}`);
8779
8870
  }
8780
8871
  function legacySharedReviewRowsForWorkspace(store, workspaceIdentity) {
8872
+ const repositoryIdentities = repositoryIdentitiesByWorkspace(store.db);
8781
8873
  return legacySharedReviewRows(store).filter((row) => {
8782
8874
  return canonicalWorkspaceIdentity({
8783
8875
  cwd: row.cwd,
8784
8876
  gitBranch: row.git_branch,
8785
8877
  gitRemote: row.git_remote,
8878
+ repositoryIdentity: repositoryIdentityForWorkspace(repositoryIdentities, {
8879
+ cwd: row.cwd,
8880
+ gitRemote: row.git_remote,
8881
+ metadataJson: row.session_metadata_json
8882
+ }),
8786
8883
  project: row.project,
8787
8884
  workspaceId: row.workspace_id
8788
8885
  }).value === workspaceIdentity;
@@ -9329,6 +9426,119 @@ function serializeProjectScopeInventory(store, inventory, sharingByProject) {
9329
9426
  }))
9330
9427
  };
9331
9428
  }
9429
+ async function deleteProjectScopeMappingRoute(c, store) {
9430
+ const id = Number(c.req.param("id"));
9431
+ let releasePublicationMutation;
9432
+ try {
9433
+ const body = c.req.header("content-type")?.includes("application/json") ? await parseViewerJsonBody(c) : {};
9434
+ if (!body) return c.json({ error: "invalid json" }, 400);
9435
+ const confirmedGuardrailTokens = optionalViewerStringList(body, "confirmed_guardrail_tokens");
9436
+ releasePublicationMutation = await claimRecipientPolicyPublicationMutation(store.db);
9437
+ const [deviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });
9438
+ const warnings = analyzeProjectScopeMappingDeletionGuardrails(store.db, id, deviceId);
9439
+ const missing = missingGuardrailConfirmations(warnings, confirmedGuardrailTokens);
9440
+ if (missing.length > 0) return c.json({
9441
+ error: "guardrail_confirmation_required",
9442
+ required_guardrails: [...new Set(missing.map((warning) => warning.code))],
9443
+ required_guardrail_tokens: missing.map((warning) => warning.confirmation_token),
9444
+ guardrail_warnings: warnings
9445
+ }, 409);
9446
+ const deleted = deleteProjectMappingAndWakePolicies(store, id, deviceId, confirmedGuardrailTokens);
9447
+ return c.json({
9448
+ ok: true,
9449
+ deleted
9450
+ });
9451
+ } catch (error) {
9452
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
9453
+ } finally {
9454
+ releasePublicationMutation?.();
9455
+ }
9456
+ }
9457
+ function projectSharingByRepository(store, operations) {
9458
+ const operationById = new Map(operations.map((operation) => [operation.operation_id, operation]));
9459
+ const sharingByProject = /* @__PURE__ */ new Map();
9460
+ const mappings = store.db.prepare("SELECT workspace_identity, project_pattern FROM project_scope_mappings").all();
9461
+ const repositoryIdentities = repositoryIdentitiesByWorkspace(store.db, { knownRepositoryIdentities: mappings.flatMap((mapping) => [mapping.workspace_identity, mapping.project_pattern]) });
9462
+ const seenOperationProjects = /* @__PURE__ */ new Set();
9463
+ const reviewed = store.db.prepare(`SELECT p.operation_id, p.canonical_project_identity
9464
+ FROM share_operation_projects p
9465
+ JOIN share_operations o ON o.operation_id = p.operation_id
9466
+ WHERE o.inviter_actor_id = ? ORDER BY o.created_at, p.ordinal`).all(store.actorId);
9467
+ for (const item of reviewed) {
9468
+ const operation = operationById.get(item.operation_id);
9469
+ if (!operation) continue;
9470
+ const projectId = canonicalRepositoryProjectIdentity(repositoryIdentities, item.canonical_project_identity);
9471
+ const operationProjectKey = `${item.operation_id}\u0000${projectId}`;
9472
+ if (seenOperationProjects.has(operationProjectKey)) continue;
9473
+ seenOperationProjects.add(operationProjectKey);
9474
+ const current = sharingByProject.get(projectId) ?? [];
9475
+ current.push({
9476
+ person: operation.person,
9477
+ lifecycle: {
9478
+ state: operation.lifecycle.state,
9479
+ label: operation.lifecycle.label,
9480
+ explanation: operation.lifecycle.explanation
9481
+ }
9482
+ });
9483
+ sharingByProject.set(projectId, current);
9484
+ }
9485
+ return sharingByProject;
9486
+ }
9487
+ function deactivateActorAndWakePolicies(store, actorId, now) {
9488
+ store.db.transaction(() => {
9489
+ store.db.prepare("UPDATE actors SET status = 'deactivated', updated_at = ? WHERE actor_id = ?").run(now, actorId);
9490
+ store.db.prepare("UPDATE sync_peers SET actor_id = NULL WHERE actor_id = ?").run(actorId);
9491
+ wakeRecipientPoliciesForIdentities(store.db, [actorId], now);
9492
+ }).immediate();
9493
+ }
9494
+ function finishActorMerge(store, primaryActorId, secondaryActorId, now) {
9495
+ store.db.prepare("UPDATE actors SET status = 'merged', merged_into_actor_id = ?, updated_at = ? WHERE actor_id = ?").run(primaryActorId, now, secondaryActorId);
9496
+ wakeRecipientPoliciesForIdentities(store.db, [primaryActorId, secondaryActorId], now);
9497
+ }
9498
+ function policyWakeMappings(store) {
9499
+ return store.db.prepare("SELECT id, scope_id, workspace_identity FROM project_scope_mappings ORDER BY id").all();
9500
+ }
9501
+ function existingRequestedMappings(mappings, inputs) {
9502
+ const requestedIds = new Set(inputs.map((input) => input.id).filter((id) => id != null));
9503
+ const requestedIdentities = new Set(inputs.map((input) => input.workspace_identity).filter((identity) => identity != null).map((identity) => canonicalWorkspaceIdentity({ cwd: identity }).value));
9504
+ return mappings.filter((mapping) => {
9505
+ if (requestedIds.has(mapping.id)) return true;
9506
+ if (!mapping.workspace_identity) return false;
9507
+ return requestedIdentities.has(canonicalWorkspaceIdentity({ cwd: mapping.workspace_identity }).value);
9508
+ });
9509
+ }
9510
+ function mappedProjectsInScopes(mappings, scopeIds) {
9511
+ return mappings.filter((mapping) => scopeIds.has(mapping.scope_id)).map((mapping) => mapping.workspace_identity).filter((identity) => identity != null);
9512
+ }
9513
+ function wakeRecipientPolicyProjects(store, projectIdentities, now) {
9514
+ wakeRecipientPoliciesForProjectIdentities(store.db, [...new Set(projectIdentities)], now);
9515
+ }
9516
+ function saveProjectMappingsAndWakePolicies(store, deviceId, mappingInputs) {
9517
+ return store.db.transaction(() => {
9518
+ const before = policyWakeMappings(store);
9519
+ const previousMappings = existingRequestedMappings(before, mappingInputs);
9520
+ const mappings = upsertProjectScopeSettingsMappings(store.db, mappingInputs, { deviceId });
9521
+ const after = policyWakeMappings(store);
9522
+ const changedScopeIds = /* @__PURE__ */ new Set([...previousMappings.map((mapping) => mapping.scope_id), ...mappings.map((mapping) => mapping.scope_id)]);
9523
+ wakeRecipientPolicyProjects(store, [...mappedProjectsInScopes(before, changedScopeIds), ...mappedProjectsInScopes(after, changedScopeIds)], (/* @__PURE__ */ new Date()).toISOString());
9524
+ return mappings;
9525
+ }).immediate();
9526
+ }
9527
+ function deleteProjectMappingAndWakePolicies(store, mappingId, deviceId, confirmedGuardrailTokens) {
9528
+ return store.db.transaction(() => {
9529
+ const before = policyWakeMappings(store);
9530
+ const removed = before.find((mapping) => mapping.id === mappingId);
9531
+ const deleted = deleteProjectScopeSettingsMapping(store.db, mappingId, {
9532
+ deviceId,
9533
+ confirmedGuardrailTokens
9534
+ });
9535
+ if (deleted && removed) {
9536
+ const changedScopeIds = /* @__PURE__ */ new Set([removed.scope_id]);
9537
+ wakeRecipientPolicyProjects(store, [...mappedProjectsInScopes(before, changedScopeIds), ...mappedProjectsInScopes(policyWakeMappings(store), changedScopeIds)], (/* @__PURE__ */ new Date()).toISOString());
9538
+ }
9539
+ return deleted;
9540
+ }).immediate();
9541
+ }
9332
9542
  /**
9333
9543
  * Viewer-facing sync management routes (/api/sync/*).
9334
9544
  *
@@ -9961,27 +10171,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
9961
10171
  scopeId: c.req.query("scope_id"),
9962
10172
  status: c.req.query("status")
9963
10173
  });
9964
- const operations = await shareOperationReadModels(store, void 0, false);
9965
- const operationById = new Map(operations.map((operation) => [operation.operation_id, operation]));
9966
- const sharingByProject = /* @__PURE__ */ new Map();
9967
- const reviewed = store.db.prepare(`SELECT p.operation_id, p.canonical_project_identity
9968
- FROM share_operation_projects p
9969
- JOIN share_operations o ON o.operation_id = p.operation_id
9970
- WHERE o.inviter_actor_id = ? ORDER BY o.created_at, p.ordinal`).all(store.actorId);
9971
- for (const item of reviewed) {
9972
- const operation = operationById.get(item.operation_id);
9973
- if (!operation) continue;
9974
- const current = sharingByProject.get(item.canonical_project_identity) ?? [];
9975
- current.push({
9976
- person: operation.person,
9977
- lifecycle: {
9978
- state: operation.lifecycle.state,
9979
- label: operation.lifecycle.label,
9980
- explanation: operation.lifecycle.explanation
9981
- }
9982
- });
9983
- sharingByProject.set(item.canonical_project_identity, current);
9984
- }
10174
+ const sharingByProject = projectSharingByRepository(store, await shareOperationReadModels(store, void 0, false));
9985
10175
  return c.json(serializeProjectScopeInventory(store, inventory, sharingByProject));
9986
10176
  });
9987
10177
  app.post("/api/sync/projects/reassign-project", async (c) => {
@@ -10238,28 +10428,19 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
10238
10428
  const confirmedGuardrailTokens = optionalViewerStringList(body, "confirmed_guardrail_tokens");
10239
10429
  const mappingInput = parseViewerProjectMappingInput(body);
10240
10430
  releasePublicationMutation = await claimRecipientPolicyPublicationMutation(store.db);
10241
- const analysis = analyzeProjectScopeMappingChangeGuardrails(store.db, mappingInput);
10431
+ const [deviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });
10432
+ const analysis = analyzeProjectScopeMappingChangeGuardrails(store.db, {
10433
+ ...mappingInput,
10434
+ deviceId
10435
+ });
10242
10436
  if (analysis.requested_workspace_identity?.startsWith("unmapped:")) return c.json({
10243
10437
  error: "unmapped_project_local_only",
10244
10438
  message: "Unmapped projects need a stable path, git remote, or workspace id before assigning a Sharing domain.",
10245
10439
  guardrail_warnings: analysis.warnings
10246
10440
  }, 400);
10247
10441
  const missingConfirmations = missingGuardrailConfirmations(analysis.warnings, confirmedGuardrailTokens);
10248
- if (missingConfirmations.length > 0) {
10249
- const missingCodes = [...new Set(missingConfirmations.map((warning) => warning.code))];
10250
- const missingTokens = [...new Set(missingConfirmations.map((warning) => warning.confirmation_token))].filter((token) => typeof token === "string" && token.length > 0);
10251
- return c.json({
10252
- error: "guardrail_confirmation_required",
10253
- required_guardrails: missingCodes,
10254
- required_guardrail_tokens: missingTokens,
10255
- guardrail_warnings: analysis.warnings
10256
- }, 409);
10257
- }
10258
- const [deviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });
10259
- const mapping = upsertProjectScopeSettingsMapping(store.db, {
10260
- deviceId,
10261
- ...mappingInput
10262
- });
10442
+ if (missingConfirmations.length > 0) return c.json(mappingGuardrailChallenge(analysis.warnings, missingConfirmations), 409);
10443
+ const [mapping] = saveProjectMappingsAndWakePolicies(store, deviceId, [mappingInput]);
10263
10444
  return c.json({
10264
10445
  ok: true,
10265
10446
  mapping,
@@ -10277,14 +10458,13 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
10277
10458
  if (!body) return c.json({ error: "invalid json" }, 400);
10278
10459
  let releasePublicationMutation;
10279
10460
  try {
10280
- const rawMappings = body.mappings;
10281
- if (!Array.isArray(rawMappings) || rawMappings.length === 0) return c.json({ error: "mappings must be a non-empty array" }, 400);
10282
- const mappingInputs = rawMappings.map((raw) => {
10283
- if (raw == null || typeof raw !== "object" || Array.isArray(raw)) throw new Error("each mapping must be an object");
10284
- return parseViewerProjectMappingInput(raw);
10285
- });
10461
+ const mappingInputs = parseViewerProjectMappingInputs(body);
10286
10462
  releasePublicationMutation = await claimRecipientPolicyPublicationMutation(store.db);
10287
- const analyses = mappingInputs.map((mappingInput) => analyzeProjectScopeMappingChangeGuardrails(store.db, mappingInput));
10463
+ const [deviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });
10464
+ const analyses = analyzeProjectScopeMappingChangesGuardrails(store.db, mappingInputs.map((input) => ({
10465
+ ...input,
10466
+ deviceId
10467
+ })));
10288
10468
  const unmapped = analyses.find((analysis) => analysis.requested_workspace_identity?.startsWith("unmapped:"));
10289
10469
  if (unmapped) return c.json({
10290
10470
  error: "unmapped_project_local_only",
@@ -10292,24 +10472,10 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
10292
10472
  guardrail_warnings: unmapped.warnings
10293
10473
  }, 400);
10294
10474
  const missingConfirmations = analyses.flatMap((analysis) => missingGuardrailConfirmations(analysis.warnings, []));
10295
- if (missingConfirmations.length > 0) {
10296
- const missingCodes = [...new Set(missingConfirmations.map((warning) => warning.code))];
10297
- const missingTokens = [...new Set(missingConfirmations.map((warning) => warning.confirmation_token))].filter((token) => typeof token === "string" && token.length > 0);
10298
- return c.json({
10299
- error: "guardrail_confirmation_required",
10300
- required_guardrails: missingCodes,
10301
- required_guardrail_tokens: missingTokens,
10302
- guardrail_warnings: analyses.flatMap((analysis) => analysis.warnings)
10303
- }, 409);
10304
- }
10305
- const [deviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });
10306
- const saveMappings = store.db.transaction(() => mappingInputs.map((mappingInput) => upsertProjectScopeSettingsMapping(store.db, {
10307
- deviceId,
10308
- ...mappingInput
10309
- })));
10475
+ if (missingConfirmations.length > 0) return c.json(mappingGuardrailChallenge(analyses.flatMap((analysis) => analysis.warnings), missingConfirmations), 409);
10310
10476
  return c.json({
10311
10477
  ok: true,
10312
- mappings: saveMappings(),
10478
+ mappings: saveProjectMappingsAndWakePolicies(store, deviceId, mappingInputs),
10313
10479
  guardrail_warnings: analyses.flatMap((analysis) => analysis.warnings)
10314
10480
  });
10315
10481
  } catch (error) {
@@ -10318,23 +10484,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
10318
10484
  releasePublicationMutation?.();
10319
10485
  }
10320
10486
  });
10321
- app.delete("/api/sync/sharing-domains/project-mappings/:id", async (c) => {
10322
- const store = getStore();
10323
- const id = Number(c.req.param("id"));
10324
- let releasePublicationMutation;
10325
- try {
10326
- releasePublicationMutation = await claimRecipientPolicyPublicationMutation(store.db);
10327
- const deleted = deleteProjectScopeSettingsMapping(store.db, id);
10328
- return c.json({
10329
- ok: true,
10330
- deleted
10331
- });
10332
- } catch (error) {
10333
- return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
10334
- } finally {
10335
- releasePublicationMutation?.();
10336
- }
10337
- });
10487
+ app.delete("/api/sync/sharing-domains/project-mappings/:id", (c) => deleteProjectScopeMappingRoute(c, getStore()));
10338
10488
  app.post("/api/sync/peers/identity", async (c) => {
10339
10489
  const store = getStore();
10340
10490
  ensureLocalActorRecord(store);
@@ -10592,11 +10742,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
10592
10742
  WHERE inviter_actor_id = ? OR recipient_actor_id = ? OR person_id = ?`).run(secondaryActorId, primaryActorId, secondaryActorId, primaryActorId, secondaryActorId, primaryActorId, now, secondaryActorId, secondaryActorId, secondaryActorId);
10593
10743
  const peerUpdate = d.update(schema.syncPeers).set({ actor_id: primaryActorId }).where(eq(schema.syncPeers.actor_id, secondaryActorId)).run();
10594
10744
  if (primary.is_local) d.update(schema.syncPeers).set({ claimed_local_actor: 1 }).where(eq(schema.syncPeers.actor_id, primaryActorId)).run();
10595
- d.update(schema.actors).set({
10596
- status: "merged",
10597
- merged_into_actor_id: primaryActorId,
10598
- updated_at: now
10599
- }).where(eq(schema.actors.actor_id, secondaryActorId)).run();
10745
+ finishActorMerge(store, primaryActorId, secondaryActorId, now);
10600
10746
  return { mergedCount: Number(peerUpdate.changes ?? 0) };
10601
10747
  }).immediate();
10602
10748
  if ("error" in result) return c.json({ error: result.error }, result.status);
@@ -10615,16 +10761,10 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
10615
10761
  if (actorId === store.actorId) return c.json({ error: "cannot deactivate this device's own local actor" }, 409);
10616
10762
  const releaseActorMutations = await claimRecipientPolicyActorMutations(store.db, [actorId]);
10617
10763
  queueMicrotask(releaseActorMutations);
10618
- const d = drizzle(store.db, { schema });
10619
- const actor = d.select().from(schema.actors).where(eq(schema.actors.actor_id, actorId)).get();
10764
+ const actor = drizzle(store.db, { schema }).select().from(schema.actors).where(eq(schema.actors.actor_id, actorId)).get();
10620
10765
  if (!actor) return c.json({ error: "actor not found" }, 404);
10621
10766
  if (actor.status !== "active") return c.json({ error: "actor not active" }, 409);
10622
- const now = (/* @__PURE__ */ new Date()).toISOString();
10623
- d.update(schema.actors).set({
10624
- status: "deactivated",
10625
- updated_at: now
10626
- }).where(eq(schema.actors.actor_id, actorId)).run();
10627
- d.update(schema.syncPeers).set({ actor_id: null }).where(eq(schema.syncPeers.actor_id, actorId)).run();
10767
+ deactivateActorAndWakePolicies(store, actorId, (/* @__PURE__ */ new Date()).toISOString());
10628
10768
  return c.json({ ok: true });
10629
10769
  });
10630
10770
  app.post("/api/sync/legacy-devices/claim", async (c) => {