@codemem/server 0.46.0-beta.2 → 0.46.0-rc.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.
@@ -34,6 +34,13 @@ export interface SyncStatusInput {
34
34
  getSyncRuntimeStatus?: () => SyncRuntimeStatus | null;
35
35
  operations: SyncStatusOperations;
36
36
  }
37
+ interface PeerStatusReadModel {
38
+ items: Record<string, unknown>[];
39
+ byId: Record<string, unknown>;
40
+ }
41
+ export declare function safeDaemonIssueCode(state: string, lastError: string | null | undefined): "coordinator_timeout" | "coordinator_error" | null;
42
+ export declare function latestFailedPeerIds(store: MemoryStore, activePeerIds: Set<string>, isRecentIso: (value: unknown) => boolean): Set<string>;
43
+ export declare function degradedDaemonState(peers: PeerStatusReadModel, failedPeerIds: Set<string>): string;
37
44
  export declare function buildSyncStatusResponse(input: SyncStatusInput): Promise<Record<string, unknown>>;
38
45
  export {};
39
46
  //# sourceMappingURL=sync-status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync-status.d.ts","sourceRoot":"","sources":["../../src/application/sync-status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-status.d.ts","sourceRoot":"","sources":["../../src/application/sync-status.ts"],"names":[],"mappings":"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"}
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, 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";
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, classifyRecordedSyncFailure, 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";
@@ -671,14 +671,9 @@ function syncSelect(options) {
671
671
  ${SYNC_OCCURRED_AT_SQL} AS occurred_at,
672
672
  CASE WHEN ok <> 0 THEN 'succeeded' ELSE 'failed' END AS status,
673
673
  ops_in AS metric_a, ops_out AS metric_b,
674
- CASE
675
- WHEN lower(error) LIKE '%auth%' OR lower(error) LIKE '%unauthorized%' THEN 'authentication'
676
- WHEN lower(error) LIKE '%timeout%' OR lower(error) LIKE '%timed out%' THEN 'timeout'
677
- WHEN lower(error) LIKE '%version%' OR lower(error) LIKE '%capability%' THEN 'compatibility'
678
- WHEN lower(error) LIKE '%connect%' OR lower(error) LIKE '%network%'
679
- OR lower(error) LIKE '%dns%' THEN 'connectivity'
680
- ELSE 'unspecified'
681
- END AS category
674
+ -- Raw error text; syncEvent classifies it server-side and never returns it.
675
+ error AS category,
676
+ failure_category AS stored_category
682
677
  FROM sync_attempts ${predicates.length ? `WHERE ${predicates.join(" AND ")}` : ""}
683
678
  ORDER BY ${SYNC_OCCURRED_AT_SQL} DESC, id DESC
684
679
  LIMIT @sourceLimit`;
@@ -712,7 +707,8 @@ function observerSelect(options) {
712
707
  WHEN lower(COALESCE(observer_error_code, error_type)) LIKE '%schema%'
713
708
  OR lower(COALESCE(observer_error_code, error_type)) LIKE '%parse%' THEN 'response format'
714
709
  ELSE 'unspecified'
715
- END AS category
710
+ END AS category,
711
+ NULL AS stored_category
716
712
  FROM raw_event_flush_batches
717
713
  WHERE status = '${status}' ${providerFilter} ${cursorFilter}
718
714
  ORDER BY updated_at DESC, id DESC
@@ -729,7 +725,7 @@ function maintenanceSelect(options) {
729
725
  return `SELECT 'maintenance' AS source_type, kind AS source_id,
730
726
  'm:' || hex(kind) AS order_key, updated_at AS occurred_at,
731
727
  status, progress_current AS metric_a, progress_total AS metric_b,
732
- NULL AS category
728
+ NULL AS category, NULL AS stored_category
733
729
  FROM maintenance_jobs WHERE status IN (${statuses.join(", ")})`;
734
730
  }
735
731
  function backlogSelect(options) {
@@ -763,7 +759,8 @@ function backlogSelect(options) {
763
759
  'b:' || printf('%020d', 0) AS order_key, occurred_at,
764
760
  CASE WHEN pending >= 1000 THEN 'error' ELSE 'warning' END AS status,
765
761
  pending AS metric_a, sessions AS metric_b,
766
- CASE WHEN candidate_count > 1000 THEN 'capped' ELSE NULL END AS category
762
+ CASE WHEN candidate_count > 1000 THEN 'capped' ELSE NULL END AS category,
763
+ NULL AS stored_category
767
764
  FROM (
768
765
  SELECT MAX(updated_at) AS occurred_at,
769
766
  SUM(pending) AS pending,
@@ -805,11 +802,28 @@ function loadSourceRows(store, options) {
805
802
  ORDER BY occurred_at DESC, order_key DESC
806
803
  LIMIT @resultLimit`).all(params);
807
804
  }
805
+ var SYNC_FAILURE_MESSAGES = {
806
+ connectivity: "Sync could not reach a paired device, or the device did not respond in time.",
807
+ trust: "Sync stopped because the pairing or identity check between two devices failed.",
808
+ scope: "Sync stopped because two devices disagree about access to a shared Space.",
809
+ compatibility: "Sync stopped because two devices run incompatible Codemem versions."
810
+ };
811
+ var SPECIFIC_STORED_SYNC_CATEGORIES = /* @__PURE__ */ new Set([
812
+ "trust",
813
+ "scope",
814
+ "connectivity",
815
+ "compatibility"
816
+ ]);
817
+ function syncFailureCategory(row) {
818
+ const stored = row.stored_category;
819
+ if (stored && SPECIFIC_STORED_SYNC_CATEGORIES.has(stored)) return stored;
820
+ return classifyRecordedSyncFailure(row.category);
821
+ }
808
822
  function syncEvent(row, includeTechnical) {
809
823
  const succeeded = row.status === "succeeded";
810
824
  const opsIn = Number(row.metric_a ?? 0);
811
825
  const opsOut = Number(row.metric_b ?? 0);
812
- const category = row.category ?? "unspecified";
826
+ const category = succeeded ? "other" : syncFailureCategory(row);
813
827
  return {
814
828
  id: opaqueId("sync-attempt", row.source_id),
815
829
  orderKey: row.order_key,
@@ -817,7 +831,7 @@ function syncEvent(row, includeTechnical) {
817
831
  severity: succeeded ? "info" : "error",
818
832
  subsystem: "sync",
819
833
  code: succeeded ? "sync_attempt_succeeded" : "sync_attempt_failed",
820
- message: succeeded ? "A sync attempt completed." : "A sync attempt failed before all work completed.",
834
+ message: succeeded ? "A sync attempt completed." : SYNC_FAILURE_MESSAGES[category] ?? "A sync attempt failed before all work completed.",
821
835
  recovery: succeeded ? void 0 : {
822
836
  label: "Open advanced sync diagnostics",
823
837
  href: "#advanced/sync/diagnostics"
@@ -4151,6 +4165,14 @@ async function reconcileRecipientPolicyProjectsOperation(store, options) {
4151
4165
  }
4152
4166
  //#endregion
4153
4167
  //#region src/application/sync-status.ts
4168
+ var SAFE_RUNTIME_DETAILS = {
4169
+ starting: "Running initial sync in background",
4170
+ stopping: "Stopping sync daemon",
4171
+ error: "Background sync failed. Open diagnostics for details.",
4172
+ rebootstrapping: "Restoring sync baseline",
4173
+ needs_attention: "Sync needs attention",
4174
+ disabled: "Sync is off"
4175
+ };
4154
4176
  function traceSync(label, operation) {
4155
4177
  if (process.env.CODEMEM_TRACE_SYNC_STATUS !== "1") return operation();
4156
4178
  const startedAt = Date.now();
@@ -4215,6 +4237,10 @@ function initialDaemonState(config, rows, daemonRunning) {
4215
4237
  if (!daemonRunning) return "stopped";
4216
4238
  return "ok";
4217
4239
  }
4240
+ function safeDaemonIssueCode(state, lastError) {
4241
+ if (state !== "error" || !lastError?.includes("coordinator enrollment maintenance failed")) return null;
4242
+ return lastError.includes(":request_timeout") || lastError.endsWith(" (coordinator_timeout)") ? "coordinator_timeout" : "coordinator_error";
4243
+ }
4218
4244
  function retentionPayload(config, rows, retainedFloor) {
4219
4245
  const state = rows.retention;
4220
4246
  return {
@@ -4282,8 +4308,9 @@ function readBaseStatus(input) {
4282
4308
  state = runtime.phase;
4283
4309
  statusPayload.daemon_state = state;
4284
4310
  statusPayload.daemon_running = runtime.phase === "starting" || running;
4285
- statusPayload.daemon_detail = runtime.detail ?? detail;
4311
+ statusPayload.daemon_detail = input.showDiagnostics ? runtime.detail ?? detail : SAFE_RUNTIME_DETAILS[runtime.phase] ?? null;
4286
4312
  }
4313
+ statusPayload.daemon_issue_code = safeDaemonIssueCode(state, runtime?.phase === "error" ? null : rows.daemon?.last_error);
4287
4314
  return {
4288
4315
  config,
4289
4316
  localDeviceId: rows.device?.device_id ?? null,
@@ -4340,16 +4367,35 @@ function readAttemptStatus(input) {
4340
4367
  latestError: String(rows[0]?.error || "").trim()
4341
4368
  };
4342
4369
  }
4370
+ function latestFailedPeerIds(store, activePeerIds, isRecentIso) {
4371
+ const cutoff = (/* @__PURE__ */ new Date(Date.now() - 6e5)).toISOString();
4372
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4373
+ return traceSync("recentPeerFailures", () => {
4374
+ const rows = store.db.prepare(`SELECT peer_device_id, ok, error, finished_at
4375
+ FROM sync_attempts
4376
+ WHERE (CASE WHEN finished_at IS NULL THEN started_at ELSE finished_at END) BETWEEN ? AND ?
4377
+ ORDER BY (CASE WHEN finished_at IS NULL THEN started_at ELSE finished_at END) DESC, id DESC`).iterate(cutoff, now);
4378
+ const seen = /* @__PURE__ */ new Set();
4379
+ const failed = /* @__PURE__ */ new Set();
4380
+ for (const row of rows) {
4381
+ if (!activePeerIds.has(row.peer_device_id) || seen.has(row.peer_device_id)) continue;
4382
+ if (!isRecentIso(row.finished_at)) continue;
4383
+ seen.add(row.peer_device_id);
4384
+ if (!row.ok && row.error) failed.add(row.peer_device_id);
4385
+ }
4386
+ return failed;
4387
+ });
4388
+ }
4343
4389
  function peerStates(peers) {
4344
4390
  return new Set(peers.items.map((peer) => String(peer.status?.peer_state ?? "")));
4345
4391
  }
4346
4392
  function allPeersOffline(peers) {
4347
4393
  return peers.items.length > 0 && peers.items.every((peer) => String(peer.status?.peer_state ?? "") === "offline");
4348
4394
  }
4349
- function degradedDaemonState(input, peers, attempts) {
4395
+ function degradedDaemonState(peers, failedPeerIds) {
4350
4396
  const states = peerStates(peers);
4351
4397
  const allOffline = allPeersOffline(peers);
4352
- if (Boolean(attempts.items[0] && attempts.items[0].status === "error" && input.operations.isRecentIso(attempts.items[0].finished_at))) {
4398
+ if (failedPeerIds.size > 0) {
4353
4399
  if (states.has("online") || states.has("degraded")) return "degraded";
4354
4400
  if (allOffline) return "offline-peers";
4355
4401
  if (peers.items.length > 0) return "stale";
@@ -4359,14 +4405,14 @@ function degradedDaemonState(input, peers, attempts) {
4359
4405
  if (peers.items.length > 0 && !states.has("online")) return "stale";
4360
4406
  return "ok";
4361
4407
  }
4362
- function applyDerivedDaemonState(input, base, peers, attempts, statusBlock) {
4408
+ function applyDerivedDaemonState(base, peers, attempts, failedPeerIds, statusBlock) {
4363
4409
  let state = base.daemonState;
4364
4410
  if (state === "ok" && attempts.latestError.startsWith("needs_attention:")) {
4365
4411
  state = "needs_attention";
4366
4412
  const detail = attempts.latestError.replace(/^needs_attention:/, "");
4367
4413
  base.statusPayload.daemon_detail = detail;
4368
4414
  statusBlock.daemon_detail = detail;
4369
- } else if (state === "ok") state = degradedDaemonState(input, peers, attempts);
4415
+ } else if (state === "ok") state = degradedDaemonState(peers, failedPeerIds);
4370
4416
  base.statusPayload.daemon_state = state;
4371
4417
  statusBlock.daemon_state = state;
4372
4418
  }
@@ -4384,6 +4430,12 @@ async function buildSyncStatusResponse(input) {
4384
4430
  const coordinator = traceSync("coordinator", () => input.operations.redactCoordinatorStatus(coordinatorSnapshot, input.showDiagnostics));
4385
4431
  const peers = readPeerStatus(input, base.localDeviceId);
4386
4432
  const attempts = readAttemptStatus(input);
4433
+ const activePeerIds = new Set(peers.items.map((peer) => String(peer.peer_device_id ?? "")));
4434
+ const failedPeerIds = latestFailedPeerIds(input.store, activePeerIds, input.operations.isRecentIso);
4435
+ for (const peer of peers.items) {
4436
+ const status = peer.status;
4437
+ status.recent_failed_attempt = failedPeerIds.has(String(peer.peer_device_id ?? ""));
4438
+ }
4387
4439
  const statusBlock = {
4388
4440
  ...base.statusPayload,
4389
4441
  background_maintenance: input.operations.summarizeMaintenanceJobs(listMaintenanceJobs(input.store.db), input.showDiagnostics),
@@ -4397,7 +4449,7 @@ async function buildSyncStatusResponse(input) {
4397
4449
  const sharingReview = traceSync("sharingReview", () => input.store.sharingReviewSummary(input.project));
4398
4450
  const recipientPolicyReconciliation = traceSync("recipientPolicyReconciliation", () => input.operations.listRecipientPolicyReconciliationStatus(input.store));
4399
4451
  const joinRequests = await readJoinRequests(input, base.config);
4400
- applyDerivedDaemonState(input, base, peers, attempts, statusBlock);
4452
+ applyDerivedDaemonState(base, peers, attempts, failedPeerIds, statusBlock);
4401
4453
  const response = {
4402
4454
  ...base.statusPayload,
4403
4455
  status: statusBlock,
@@ -4458,6 +4510,126 @@ function snapshotPageRequest(query, localDeviceId) {
4458
4510
  };
4459
4511
  }
4460
4512
  //#endregion
4513
+ //#region src/routes/device-rename.ts
4514
+ async function enrolledGroups(config, deviceId) {
4515
+ const remoteUrl = config.syncCoordinatorUrl || null;
4516
+ const adminSecret = config.syncCoordinatorAdminSecret || null;
4517
+ if (!remoteUrl || !adminSecret) throw new Error("coordinator_unavailable");
4518
+ const groups = await coordinatorListGroupsAction({
4519
+ remoteUrl,
4520
+ adminSecret
4521
+ });
4522
+ if (groups.length > 25) throw new Error("coordinator_evidence_too_large");
4523
+ const devices = (await Promise.all(groups.map((group) => coordinatorListDevicesAction({
4524
+ groupId: group.group_id,
4525
+ includeDisabled: true,
4526
+ remoteUrl,
4527
+ adminSecret
4528
+ })))).flat();
4529
+ if (devices.length > 500) throw new Error("coordinator_evidence_too_large");
4530
+ const matches = devices.filter((device) => device.device_id === deviceId);
4531
+ if (new Set(matches.map((device) => `${device.public_key}:${device.fingerprint}`)).size > 1) throw new Error("device_enrollment_conflict");
4532
+ return [...new Set(matches.map((device) => device.group_id))].sort();
4533
+ }
4534
+ async function renameEnrolledGroups(config, groups, deviceId, name) {
4535
+ let renamed = 0;
4536
+ for (const groupId of groups) try {
4537
+ if (!await coordinatorRenameDeviceAction({
4538
+ groupId,
4539
+ deviceId,
4540
+ displayName: name,
4541
+ remoteUrl: config.syncCoordinatorUrl || null,
4542
+ adminSecret: config.syncCoordinatorAdminSecret || null
4543
+ })) break;
4544
+ renamed += 1;
4545
+ } catch {
4546
+ break;
4547
+ }
4548
+ return renamed;
4549
+ }
4550
+ async function renameDevice(store, deviceId, name, provenance) {
4551
+ const config = readCoordinatorSyncConfig();
4552
+ if (provenance === "coordinator_enrollment" && !config.syncCoordinatorUrl) return {
4553
+ ok: false,
4554
+ error: "coordinator_device_names_unavailable",
4555
+ status: 503
4556
+ };
4557
+ let groups = [];
4558
+ if (config.syncCoordinatorUrl) {
4559
+ try {
4560
+ groups = await enrolledGroups(config, deviceId);
4561
+ } catch (error) {
4562
+ if (error instanceof Error && error.message === "device_enrollment_conflict") return {
4563
+ ok: false,
4564
+ error: "device_enrollment_conflict",
4565
+ status: 409
4566
+ };
4567
+ return {
4568
+ ok: false,
4569
+ error: "coordinator_device_names_unavailable",
4570
+ status: 503
4571
+ };
4572
+ }
4573
+ if (provenance === "coordinator_enrollment" && groups.length === 0) return {
4574
+ ok: false,
4575
+ error: "device_enrollment_unavailable",
4576
+ status: 409
4577
+ };
4578
+ }
4579
+ const renamedGroupCount = await renameEnrolledGroups(config, groups, deviceId, name);
4580
+ if (renamedGroupCount !== groups.length) return {
4581
+ ok: false,
4582
+ error: "coordinator_device_rename_incomplete",
4583
+ status: 503,
4584
+ renamedGroupCount
4585
+ };
4586
+ if (!store.db.transaction(() => {
4587
+ const result = store.db.prepare("UPDATE identity_devices SET display_name = ?, updated_at = ? WHERE device_id = ? AND status = 'active'").run(name, (/* @__PURE__ */ new Date()).toISOString(), deviceId);
4588
+ if (result.changes) store.db.prepare("UPDATE sync_peers SET name = ? WHERE peer_device_id = ?").run(name, deviceId);
4589
+ return result.changes;
4590
+ })()) return {
4591
+ ok: false,
4592
+ error: "device_not_found",
4593
+ status: 409
4594
+ };
4595
+ return {
4596
+ ok: true,
4597
+ display_name: name
4598
+ };
4599
+ }
4600
+ function deviceRenameRoutes(getStore) {
4601
+ const pendingDevices = /* @__PURE__ */ new Set();
4602
+ return new Hono().post("/api/sync/recipient-policy/v1/devices/:device_id/rename", async (c) => {
4603
+ const store = getStore();
4604
+ const deviceId = String(c.req.param("device_id") ?? "").trim();
4605
+ const binding = store.db.prepare("SELECT provenance FROM identity_devices WHERE device_id = ? AND status = 'active'").get(deviceId);
4606
+ if (!binding) return c.json({ error: "device_not_found" }, 404);
4607
+ let body;
4608
+ try {
4609
+ body = await c.req.json();
4610
+ } catch {
4611
+ return c.json({ error: "invalid_json" }, 400);
4612
+ }
4613
+ let name;
4614
+ try {
4615
+ name = normalizeHumanPresentationName(String(body.display_name ?? ""), "display_name");
4616
+ } catch {
4617
+ return c.json({ error: "display_name_invalid" }, 400);
4618
+ }
4619
+ if (pendingDevices.has(deviceId)) return c.json({ error: "device_rename_busy" }, 409);
4620
+ pendingDevices.add(deviceId);
4621
+ try {
4622
+ const result = await renameDevice(store, deviceId, name, binding.provenance);
4623
+ if (!result.ok) return c.json(result, result.status);
4624
+ return c.json(result);
4625
+ } catch {
4626
+ return c.json({ error: "device_rename_failed" }, 503);
4627
+ } finally {
4628
+ pendingDevices.delete(deviceId);
4629
+ }
4630
+ });
4631
+ }
4632
+ //#endregion
4461
4633
  //#region src/routes/team-setup-view.ts
4462
4634
  var enabled = {
4463
4635
  enabled: true,
@@ -7429,6 +7601,21 @@ function recipientPolicyPresenceCapabilityExpiresAt(enrollment, observedAt) {
7429
7601
  function recipientPolicyEnrollmentValueIsValid(value) {
7430
7602
  return typeof value === "string" && value.length > 0 && value === value.trim();
7431
7603
  }
7604
+ function recipientPolicyPresenceCapabilityExpiries(enrollments, observedAt) {
7605
+ return new Map(enrollments.map((enrollment) => [enrollment.device_id, recipientPolicyPresenceCapabilityExpiresAt(enrollment, observedAt)]));
7606
+ }
7607
+ function recipientPolicySnapshotUnavailable(stage, error) {
7608
+ console.warn(`[sync] recipient policy coordinator snapshot failed: stage=${stage} code=${coordinatorEnrollmentFailureCode(error)}`);
7609
+ throw new Error("recipient_policy_snapshot_not_fresh");
7610
+ }
7611
+ async function readRecipientPolicyCoordinatorSnapshot(read) {
7612
+ for (let attempt = 0;; attempt++) try {
7613
+ return await read();
7614
+ } catch (error) {
7615
+ if (!(error instanceof RemoteCoordinatorRequestError) || error.status !== 429 || attempt >= 2) throw error;
7616
+ await new Promise((resolve) => setTimeout(resolve, (attempt + 1) * 1e3));
7617
+ }
7618
+ }
7432
7619
  function createRecipientPolicyReconcilerEffects(store, options = {}) {
7433
7620
  const config = options.config ?? readCoordinatorSyncConfig();
7434
7621
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -7470,15 +7657,13 @@ function createRecipientPolicyReconcilerEffects(store, options = {}) {
7470
7657
  now,
7471
7658
  snapshot: async ({ scopeId }) => {
7472
7659
  const targetOptions = coordinatorOptions(scopeId);
7473
- const snapshotMemberships = (await coordinatorListScopeMembershipsAction({
7660
+ const snapshotMemberships = (await readRecipientPolicyCoordinatorSnapshot(() => coordinatorListScopeMembershipsAction({
7474
7661
  groupId: targetOptions.groupId,
7475
7662
  scopeId,
7476
7663
  includeRevoked: true,
7477
7664
  remoteUrl: targetOptions.remoteUrl,
7478
7665
  adminSecret: targetOptions.adminSecret
7479
- }).catch(() => {
7480
- throw new Error("recipient_policy_snapshot_not_fresh");
7481
- })).map((membership) => {
7666
+ })).catch((error) => recipientPolicySnapshotUnavailable("scope_memberships", error))).map((membership) => {
7482
7667
  if (typeof membership.device_id !== "string" || membership.status !== "active" && membership.status !== "revoked") throw new Error("recipient_policy_snapshot_invalid");
7483
7668
  const status = membership.status;
7484
7669
  return {
@@ -7499,15 +7684,13 @@ function createRecipientPolicyReconcilerEffects(store, options = {}) {
7499
7684
  listBoundaryEnrollments: async ({ scopeId }) => {
7500
7685
  const targetOptions = coordinatorOptions(scopeId);
7501
7686
  const observedAt = now();
7502
- const enrollments = await listDevices({
7687
+ const enrollments = await readRecipientPolicyCoordinatorSnapshot(() => listDevices({
7503
7688
  groupId: targetOptions.groupId,
7504
7689
  includeDisabled: true,
7505
7690
  remoteUrl: targetOptions.remoteUrl,
7506
7691
  adminSecret: targetOptions.adminSecret
7507
- }).catch(() => {
7508
- throw new Error("recipient_policy_snapshot_not_fresh");
7509
- });
7510
- const presenceCapabilityExpiries = new Map(enrollments.map((enrollment) => [enrollment.device_id, recipientPolicyPresenceCapabilityExpiresAt(enrollment, observedAt)]));
7692
+ })).catch((error) => recipientPolicySnapshotUnavailable("device_enrollments", error));
7693
+ const presenceCapabilityExpiries = recipientPolicyPresenceCapabilityExpiries(enrollments, observedAt);
7511
7694
  const mapped = enrollments.map((enrollment) => {
7512
7695
  if (enrollment.group_id !== targetOptions.groupId || !recipientPolicyEnrollmentValueIsValid(enrollment.device_id) || !recipientPolicyEnrollmentValueIsValid(enrollment.public_key) || !recipientPolicyEnrollmentValueIsValid(enrollment.fingerprint) || fingerprintPublicKey(enrollment.public_key) !== enrollment.fingerprint || enrollment.enabled !== 0 && enrollment.enabled !== 1 || enrollment.identity_id !== null && !recipientPolicyEnrollmentValueIsValid(enrollment.identity_id)) throw new Error("recipient_policy_snapshot_invalid");
7513
7696
  return {
@@ -9959,7 +10142,7 @@ function syncRoutes(getStore, getSyncRuntimeStatus, options = {}) {
9959
10142
  localDeviceId: store.deviceId
9960
10143
  }));
9961
10144
  });
9962
- app.get("/api/sync/recipient-policy/v1/intent", (c) => {
10145
+ app.route("/", deviceRenameRoutes(getStore)).get("/api/sync/recipient-policy/v1/intent", (c) => {
9963
10146
  const store = getStore();
9964
10147
  return c.json(listRecipientPolicyIntent(store.db));
9965
10148
  });