codemem 0.32.2 → 0.33.0-alpha.1

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { DEDUP_KEY_BACKFILL_JOB, DEFAULT_COORDINATOR_DB_PATH, DedupKeyBackfillRunner, MUTATING_TOOL_NAMES, MemoryStore, ObserverClient, REF_BACKFILL_JOB, RawEventSweeper, RefBackfillRunner, SCOPE_BACKFILL_JOB, SESSION_CONTEXT_BACKFILL_JOB, SUMMARY_DEDUP_BACKFILL_JOB, ScopeBackfillRunner, SessionContextBackfillRunner, SummaryDedupBackfillRunner, SyncRetentionRunner, VERSION, VectorModelMigrationRunner, aiBackfillStructuredContent, applyBootstrapSnapshot, backfillMemoryDedupKeys, backfillNarrativeFromBody, backfillTagsText, backfillVectors, buildAuthHeaders, buildBaseUrl, buildRawEventEnvelopeFromHook, compareMemoryRoleReports, connect, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnrollDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorUpdateScopeAction, createBetterSqliteCoordinatorApp, deactivateLowSignalMemories, deactivateLowSignalObservations, dedupNearDuplicateMemories, ensureDeviceIdentity, ensureSchemaBootstrapped, exportMemories, extractApplyPatchPaths, fetchAllSnapshotPages, fingerprintPublicKey, flushRawEvents, getExtractionBenchmarkProfile, getInjectionEvalScenarioPack, getInjectionEvalScenarioPrompts, getMaintenanceJob, getMemoryRoleReport, getRawEventRelinkPlan, getRawEventRelinkReport, getRawEventStatus, getSemanticIndexDiagnostics, getSessionExtractionEval, getSessionExtractionEvalScenario, getWorkspaceCodememConfigPath, hasPendingDedupKeyBackfill, hasPendingRefBackfill, hasPendingScopeBackfill, hasPendingSessionContextBackfill, hasPendingSummaryDedupBackfill, hasUnsyncedSharedMemoryChanges, importMemories, initDatabase, isEmbeddingDisabled, listMaintenanceJobs, loadObserverConfig, loadPublicKey, loadSqliteVec, mdnsEnabled, planReplicationOpsAgePrune, pruneReplicationOpsUntilCaughtUp, rawEventsGate, readCodememConfigFile, readCodememConfigFileAtPath, readCoordinatorSyncConfig, readImportPayload, replayBatchExtraction, replayBatchExtractionWithTierRouting, requestJson, resolveCodememConfigPath, resolveDbPath, resolveHookProject, resolveProject, retryRawEventFailures, runSyncDaemon, runSyncPass, scanSecretsRetroactive, schema, setPeerProjectFilter, stripJsonComments, stripPrivateObj, stripTrailingCommas, syncPassPreflight, updatePeerAddresses, vacuumDatabase, writeCodememConfigFile } from "@codemem/core";
2
+ import { DEDUP_KEY_BACKFILL_JOB, DEFAULT_COORDINATOR_DB_PATH, DedupKeyBackfillRunner, MUTATING_TOOL_NAMES, MemoryStore, ObserverClient, REF_BACKFILL_JOB, RawEventSweeper, RefBackfillRunner, SCOPE_BACKFILL_JOB, SESSION_CONTEXT_BACKFILL_JOB, SUMMARY_DEDUP_BACKFILL_JOB, ScopeBackfillRunner, SessionContextBackfillRunner, SummaryDedupBackfillRunner, SyncRetentionRunner, VERSION, VectorModelMigrationRunner, aiBackfillStructuredContent, applyBootstrapSnapshot, backfillMemoryDedupKeys, backfillNarrativeFromBody, backfillTagsText, backfillVectors, buildAuthHeaders, buildBaseUrl, buildRawEventEnvelopeFromHook, compareMemoryRoleReports, connect, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnrollDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorUpdateScopeAction, createBetterSqliteCoordinatorApp, deactivateLowSignalMemories, deactivateLowSignalObservations, dedupNearDuplicateMemories, ensureDeviceIdentity, ensureSchemaBootstrapped, exportMemories, extractApplyPatchPaths, fetchAllSnapshotPages, fingerprintPublicKey, flushRawEvents, formatHostPort, getExtractionBenchmarkProfile, getInjectionEvalScenarioPack, getInjectionEvalScenarioPrompts, getMaintenanceJob, getMemoryRoleReport, getRawEventRelinkPlan, getRawEventRelinkReport, getRawEventStatus, getSemanticIndexDiagnostics, getSessionExtractionEval, getSessionExtractionEvalScenario, getWorkspaceCodememConfigPath, hasPendingDedupKeyBackfill, hasPendingRefBackfill, hasPendingScopeBackfill, hasPendingSessionContextBackfill, hasPendingSummaryDedupBackfill, hasUnsyncedSharedMemoryChanges, importMemories, initDatabase, isEmbeddingDisabled, listMaintenanceJobs, listPerPeerScopeSyncState, loadObserverConfig, loadPublicKey, loadSqliteVec, mdnsEnabled, planReplicationOpsAgePrune, pruneReplicationOpsUntilCaughtUp, rawEventsGate, readCodememConfigFile, readCodememConfigFileAtPath, readCoordinatorSyncConfig, readImportPayload, replayBatchExtraction, replayBatchExtractionWithTierRouting, requestJson, resolveCodememConfigPath, resolveDbPath, resolveHookProject, resolveProject, retryRawEventFailures, runSyncDaemon, runSyncPass, scanSecretsRetroactive, schema, setPeerProjectFilter, stripJsonComments, stripPrivateObj, stripTrailingCommas, syncPassPreflight, updatePeerAddresses, vacuumDatabase, writeCodememConfigFile } from "@codemem/core";
3
3
  import { Command, Option } from "commander";
4
4
  import omelette from "omelette";
5
5
  import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
@@ -5411,8 +5411,8 @@ function parseProjectList(value) {
5411
5411
  }
5412
5412
  function collectAdvertiseAddresses(explicitAddress, configuredHost, port, interfaces) {
5413
5413
  if (explicitAddress && !["auto", "default"].includes(explicitAddress.toLowerCase())) return [explicitAddress];
5414
- if (configuredHost && configuredHost !== "0.0.0.0") return [`${configuredHost}:${port}`];
5415
- const addresses = Object.values(interfaces).flatMap((entries) => entries ?? []).filter((entry) => !entry.internal).map((entry) => entry.address).filter((address) => address && address !== "127.0.0.1" && address !== "::1").map((address) => `${address}:${port}`);
5414
+ if (configuredHost && configuredHost !== "0.0.0.0") return [formatHostPort(configuredHost, port)];
5415
+ const addresses = Object.values(interfaces).flatMap((entries) => entries ?? []).filter((entry) => !entry.internal).map((entry) => entry.address).filter((address) => address && address !== "127.0.0.1" && address !== "::1").map((address) => formatHostPort(address, port));
5416
5416
  return [...new Set(addresses)];
5417
5417
  }
5418
5418
  //#endregion
@@ -5742,10 +5742,23 @@ pairCmd.action(async (opts) => {
5742
5742
  process.exitCode = 1;
5743
5743
  return;
5744
5744
  }
5745
+ const existingPeer = drizzle(store.db, { schema }).select({ pinned_fingerprint: schema.syncPeers.pinned_fingerprint }).from(schema.syncPeers).where(eq(schema.syncPeers.peer_device_id, deviceId)).get();
5746
+ const existingFingerprint = String(existingPeer?.pinned_fingerprint ?? "").trim();
5747
+ if (existingFingerprint && existingFingerprint !== fingerprint) {
5748
+ const msg = "Pairing payload conflicts with the existing trusted fingerprint for this device. Remove or repair the old peer before accepting this pairing payload.";
5749
+ if (opts.json) {
5750
+ emitJsonError("peer_conflict", msg);
5751
+ return;
5752
+ }
5753
+ p.log.error(msg);
5754
+ process.exitCode = 1;
5755
+ return;
5756
+ }
5745
5757
  updatePeerAddresses(store.db, deviceId, resolvedAddresses, {
5746
5758
  name: opts.name,
5747
5759
  pinnedFingerprint: fingerprint,
5748
- publicKey
5760
+ publicKey,
5761
+ replaceTrust: true
5749
5762
  });
5750
5763
  if (opts.default) setPeerProjectFilter(store.db, deviceId, {
5751
5764
  include: null,
@@ -5912,6 +5925,17 @@ statusCmd.action((opts) => {
5912
5925
  last_error: schema.syncPeers.last_error
5913
5926
  }).from(schema.syncPeers).all();
5914
5927
  const semanticIndex = getSemanticIndexDiagnostics(store.db);
5928
+ const localDeviceId = deviceRow?.device_id ?? null;
5929
+ const peersWithScopes = peers.map((peer) => {
5930
+ const peerDeviceId = String(peer.peer_device_id ?? "").trim();
5931
+ return {
5932
+ peer,
5933
+ scopes: listPerPeerScopeSyncState(store.db, {
5934
+ localDeviceId,
5935
+ peerDeviceId
5936
+ })
5937
+ };
5938
+ });
5915
5939
  if (opts.json) {
5916
5940
  console.log(JSON.stringify({
5917
5941
  enabled: config.sync_enabled === true,
@@ -5922,11 +5946,12 @@ statusCmd.action((opts) => {
5922
5946
  device_id: deviceRow?.device_id ?? null,
5923
5947
  fingerprint: deviceRow?.fingerprint ?? null,
5924
5948
  coordinator_url: config.sync_coordinator_url ?? null,
5925
- peers: peers.map((peer) => ({
5949
+ peers: peersWithScopes.map(({ peer, scopes }) => ({
5926
5950
  device_id: peer.peer_device_id,
5927
5951
  name: peer.name,
5928
5952
  last_sync: peer.last_sync_at,
5929
- status: peer.last_error ?? "ok"
5953
+ status: peer.last_error ?? "ok",
5954
+ scopes
5930
5955
  }))
5931
5956
  }, null, 2));
5932
5957
  return;
@@ -5942,9 +5967,20 @@ statusCmd.action((opts) => {
5942
5967
  if (deviceRow) p.log.info(`Device ID: ${deviceRow.device_id}\nFingerprint: ${deviceRow.fingerprint}`);
5943
5968
  else p.log.warn("Device identity not initialized (run `codemem sync enable`)");
5944
5969
  if (peers.length === 0) p.log.info("Peers: none");
5945
- else for (const peer of peers) {
5946
- const label = peer.name || peer.peer_device_id;
5947
- p.log.message(` ${label}: last_sync=${peer.last_sync_at ?? "never"}, status=${peer.last_error ?? "ok"}`);
5970
+ else for (const { peer, scopes } of peersWithScopes) {
5971
+ const peerHeader = ` ${peer.name || peer.peer_device_id}: last_sync=${peer.last_sync_at ?? "never"}, status=${peer.last_error ?? "ok"}`;
5972
+ if (scopes.length === 0) p.log.message(peerHeader);
5973
+ else {
5974
+ const scopeLines = scopes.map((scope) => {
5975
+ const state = scope.bootstrapped ? "synced" : "pending";
5976
+ return ` - ${scope.label} (${scope.scope_id}): ${state}`;
5977
+ });
5978
+ p.log.message([
5979
+ peerHeader,
5980
+ " Spaces:",
5981
+ ...scopeLines
5982
+ ].join("\n"));
5983
+ }
5948
5984
  }
5949
5985
  p.log.info([
5950
5986
  "Semantic index:",