codemem 0.29.2 → 0.30.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, SESSION_CONTEXT_BACKFILL_JOB, SUMMARY_DEDUP_BACKFILL_JOB, SessionContextBackfillRunner, SummaryDedupBackfillRunner, SyncRetentionRunner, VERSION, VectorModelMigrationRunner, aiBackfillStructuredContent, applyBootstrapSnapshot, backfillMemoryDedupKeys, backfillNarrativeFromBody, backfillTagsText, backfillVectors, buildAuthHeaders, buildBaseUrl, buildRawEventEnvelopeFromHook, compareMemoryRoleReports, connect, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorDisableDeviceAction, coordinatorEnrollDeviceAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, 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, 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, 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";
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";
@@ -1669,6 +1669,12 @@ function readCoordinatorPublicKey(opts) {
1669
1669
  if (!inline) throw new Error("Public key required via --public-key or --public-key-file");
1670
1670
  return inline;
1671
1671
  }
1672
+ function parseOptionalInteger(value, name) {
1673
+ if (value == null || !String(value).trim()) return null;
1674
+ const parsed = Number.parseInt(String(value), 10);
1675
+ if (!Number.isFinite(parsed)) throw new Error(`${name} must be an integer`);
1676
+ return parsed;
1677
+ }
1672
1678
  /**
1673
1679
  * Build a fresh coordinator command tree. Each call returns independent
1674
1680
  * Commander instances so the tree can be mounted under multiple parents.
@@ -1814,6 +1820,231 @@ function buildCoordinatorCommand() {
1814
1820
  }
1815
1821
  });
1816
1822
  cmd.addCommand(listDevicesCmd);
1823
+ const listScopesCmd = new Command("list-scopes").configureHelp(helpStyle).description("List coordinator Sharing domains for a group").argument("<group>", "group id").option("--include-inactive", "include inactive Sharing domains").option("--remote-url <url>", "remote coordinator URL override").option("--admin-secret <secret>", "remote coordinator admin secret override");
1824
+ addDbOption(listScopesCmd);
1825
+ addJsonOption(listScopesCmd);
1826
+ listScopesCmd.action(async (groupId, opts) => {
1827
+ try {
1828
+ const rows = await coordinatorListScopesAction({
1829
+ groupId,
1830
+ includeInactive: opts.includeInactive === true,
1831
+ dbPath: resolveDbOpt(opts) ?? null,
1832
+ remoteUrl: opts.remoteUrl?.trim() || null,
1833
+ adminSecret: opts.adminSecret?.trim() || null
1834
+ });
1835
+ if (opts.json) {
1836
+ console.log(JSON.stringify(rows, null, 2));
1837
+ return;
1838
+ }
1839
+ p.intro("codemem coordinator list-scopes");
1840
+ if (rows.length === 0) {
1841
+ p.outro(`No Sharing domains for ${groupId.trim()}`);
1842
+ return;
1843
+ }
1844
+ for (const row of rows) p.log.message(`- ${row.label} (${row.scope_id}) status=${row.status} epoch=${row.membership_epoch}`);
1845
+ p.outro(`${rows.length} Sharing domain(s)`);
1846
+ } catch (err) {
1847
+ if (opts.json) {
1848
+ emitJsonError("list_scopes_failed", err instanceof Error ? err.message : String(err));
1849
+ return;
1850
+ }
1851
+ p.log.error(err instanceof Error ? err.message : String(err));
1852
+ process.exitCode = 1;
1853
+ }
1854
+ });
1855
+ cmd.addCommand(listScopesCmd);
1856
+ const createScopeCmd = new Command("create-scope").configureHelp(helpStyle).description("Create a coordinator Sharing domain").argument("<group>", "group id").argument("<scope-id>", "Sharing domain scope_id").requiredOption("--label <label>", "Sharing domain label").option("--kind <kind>", "Sharing domain kind").option("--authority-type <type>", "authority type").option("--coordinator-id <id>", "coordinator id assertion").option("--membership-epoch <epoch>", "membership epoch").option("--manifest-hash <hash>", "membership manifest hash").option("--status <status>", "Sharing domain status").option("--remote-url <url>", "remote coordinator URL override").option("--admin-secret <secret>", "remote coordinator admin secret override");
1857
+ addDbOption(createScopeCmd);
1858
+ addJsonOption(createScopeCmd);
1859
+ createScopeCmd.action(async (groupId, scopeId, opts) => {
1860
+ try {
1861
+ const scope = await coordinatorCreateScopeAction({
1862
+ groupId,
1863
+ scopeId,
1864
+ label: opts.label.trim(),
1865
+ kind: opts.kind?.trim() || null,
1866
+ authorityType: opts.authorityType?.trim() || null,
1867
+ coordinatorId: opts.coordinatorId?.trim() || null,
1868
+ membershipEpoch: parseOptionalInteger(opts.membershipEpoch, "membership epoch"),
1869
+ manifestHash: opts.manifestHash?.trim() || null,
1870
+ status: opts.status?.trim() || null,
1871
+ dbPath: resolveDbOpt(opts) ?? null,
1872
+ remoteUrl: opts.remoteUrl?.trim() || null,
1873
+ adminSecret: opts.adminSecret?.trim() || null
1874
+ });
1875
+ if (opts.json) {
1876
+ console.log(JSON.stringify(scope, null, 2));
1877
+ return;
1878
+ }
1879
+ p.intro("codemem coordinator create-scope");
1880
+ p.log.success(`Sharing domain ready: ${scope.scope_id}`);
1881
+ p.outro(scope.label);
1882
+ } catch (err) {
1883
+ if (opts.json) {
1884
+ emitJsonError("create_scope_failed", err instanceof Error ? err.message : String(err));
1885
+ return;
1886
+ }
1887
+ p.log.error(err instanceof Error ? err.message : String(err));
1888
+ process.exitCode = 1;
1889
+ }
1890
+ });
1891
+ cmd.addCommand(createScopeCmd);
1892
+ const updateScopeCmd = new Command("update-scope").configureHelp(helpStyle).description("Update coordinator Sharing domain metadata").argument("<group>", "group id").argument("<scope-id>", "Sharing domain scope_id").option("--label <label>", "Sharing domain label").option("--kind <kind>", "Sharing domain kind").option("--authority-type <type>", "authority type").option("--coordinator-id <id>", "coordinator id assertion").option("--membership-epoch <epoch>", "membership epoch").option("--manifest-hash <hash>", "membership manifest hash").option("--status <status>", "Sharing domain status").option("--remote-url <url>", "remote coordinator URL override").option("--admin-secret <secret>", "remote coordinator admin secret override");
1893
+ addDbOption(updateScopeCmd);
1894
+ addJsonOption(updateScopeCmd);
1895
+ updateScopeCmd.action(async (groupId, scopeId, opts) => {
1896
+ try {
1897
+ const scope = await coordinatorUpdateScopeAction({
1898
+ groupId,
1899
+ scopeId,
1900
+ label: opts.label?.trim(),
1901
+ kind: opts.kind?.trim(),
1902
+ authorityType: opts.authorityType?.trim(),
1903
+ coordinatorId: opts.coordinatorId?.trim(),
1904
+ membershipEpoch: parseOptionalInteger(opts.membershipEpoch, "membership epoch"),
1905
+ manifestHash: opts.manifestHash?.trim(),
1906
+ status: opts.status?.trim(),
1907
+ dbPath: resolveDbOpt(opts) ?? null,
1908
+ remoteUrl: opts.remoteUrl?.trim() || null,
1909
+ adminSecret: opts.adminSecret?.trim() || null
1910
+ });
1911
+ if (!scope) {
1912
+ if (opts.json) {
1913
+ emitJsonError("scope_not_found", `Sharing domain not found: ${scopeId.trim()}`);
1914
+ return;
1915
+ }
1916
+ p.log.error(`Sharing domain not found: ${scopeId.trim()}`);
1917
+ process.exitCode = 1;
1918
+ return;
1919
+ }
1920
+ if (opts.json) {
1921
+ console.log(JSON.stringify(scope, null, 2));
1922
+ return;
1923
+ }
1924
+ p.intro("codemem coordinator update-scope");
1925
+ p.log.success(`Updated Sharing domain: ${scope.scope_id}`);
1926
+ p.outro(scope.label);
1927
+ } catch (err) {
1928
+ if (opts.json) {
1929
+ emitJsonError("update_scope_failed", err instanceof Error ? err.message : String(err));
1930
+ return;
1931
+ }
1932
+ p.log.error(err instanceof Error ? err.message : String(err));
1933
+ process.exitCode = 1;
1934
+ }
1935
+ });
1936
+ cmd.addCommand(updateScopeCmd);
1937
+ const listScopeMembersCmd = new Command("list-scope-members").configureHelp(helpStyle).description("List explicit members of a Sharing domain").argument("<group>", "group id").argument("<scope-id>", "Sharing domain scope_id").option("--include-revoked", "include revoked memberships").option("--remote-url <url>", "remote coordinator URL override").option("--admin-secret <secret>", "remote coordinator admin secret override");
1938
+ addDbOption(listScopeMembersCmd);
1939
+ addJsonOption(listScopeMembersCmd);
1940
+ listScopeMembersCmd.action(async (groupId, scopeId, opts) => {
1941
+ try {
1942
+ const rows = await coordinatorListScopeMembershipsAction({
1943
+ groupId,
1944
+ scopeId,
1945
+ includeRevoked: opts.includeRevoked === true,
1946
+ dbPath: resolveDbOpt(opts) ?? null,
1947
+ remoteUrl: opts.remoteUrl?.trim() || null,
1948
+ adminSecret: opts.adminSecret?.trim() || null
1949
+ });
1950
+ if (opts.json) {
1951
+ console.log(JSON.stringify(rows, null, 2));
1952
+ return;
1953
+ }
1954
+ p.intro("codemem coordinator list-scope-members");
1955
+ if (rows.length === 0) {
1956
+ p.outro(`No members for Sharing domain ${scopeId.trim()}`);
1957
+ return;
1958
+ }
1959
+ for (const row of rows) p.log.message(`- ${row.device_id} role=${row.role} status=${row.status} epoch=${row.membership_epoch}`);
1960
+ p.outro(`${rows.length} member(s)`);
1961
+ } catch (err) {
1962
+ if (opts.json) {
1963
+ emitJsonError("list_scope_members_failed", err instanceof Error ? err.message : String(err));
1964
+ return;
1965
+ }
1966
+ p.log.error(err instanceof Error ? err.message : String(err));
1967
+ process.exitCode = 1;
1968
+ }
1969
+ });
1970
+ cmd.addCommand(listScopeMembersCmd);
1971
+ const grantScopeMemberCmd = new Command("grant-scope-member").configureHelp(helpStyle).description("Grant a device explicit access to a Sharing domain").argument("<group>", "group id").argument("<scope-id>", "Sharing domain scope_id").argument("<device-id>", "device id").option("--role <role>", "membership role").option("--membership-epoch <epoch>", "membership epoch").option("--manifest-hash <hash>", "membership manifest hash").option("--remote-url <url>", "remote coordinator URL override").option("--admin-secret <secret>", "remote coordinator admin secret override");
1972
+ addDbOption(grantScopeMemberCmd);
1973
+ addJsonOption(grantScopeMemberCmd);
1974
+ grantScopeMemberCmd.action(async (groupId, scopeId, deviceId, opts) => {
1975
+ try {
1976
+ const membership = await coordinatorGrantScopeMembershipAction({
1977
+ groupId,
1978
+ scopeId,
1979
+ deviceId,
1980
+ role: opts.role?.trim() || null,
1981
+ membershipEpoch: parseOptionalInteger(opts.membershipEpoch, "membership epoch"),
1982
+ manifestHash: opts.manifestHash?.trim() || null,
1983
+ dbPath: resolveDbOpt(opts) ?? null,
1984
+ remoteUrl: opts.remoteUrl?.trim() || null,
1985
+ adminSecret: opts.adminSecret?.trim() || null
1986
+ });
1987
+ if (opts.json) {
1988
+ console.log(JSON.stringify(membership, null, 2));
1989
+ return;
1990
+ }
1991
+ p.intro("codemem coordinator grant-scope-member");
1992
+ p.log.success(`Granted ${deviceId.trim()} to Sharing domain ${scopeId.trim()}`);
1993
+ p.outro(membership.role);
1994
+ } catch (err) {
1995
+ if (opts.json) {
1996
+ emitJsonError("grant_scope_member_failed", err instanceof Error ? err.message : String(err));
1997
+ return;
1998
+ }
1999
+ p.log.error(err instanceof Error ? err.message : String(err));
2000
+ process.exitCode = 1;
2001
+ }
2002
+ });
2003
+ cmd.addCommand(grantScopeMemberCmd);
2004
+ const revokeScopeMemberCmd = new Command("revoke-scope-member").configureHelp(helpStyle).description("Revoke a device from a Sharing domain").argument("<group>", "group id").argument("<scope-id>", "Sharing domain scope_id").argument("<device-id>", "device id").option("--membership-epoch <epoch>", "membership epoch").option("--manifest-hash <hash>", "membership manifest hash").option("--remote-url <url>", "remote coordinator URL override").option("--admin-secret <secret>", "remote coordinator admin secret override");
2005
+ addDbOption(revokeScopeMemberCmd);
2006
+ addJsonOption(revokeScopeMemberCmd);
2007
+ revokeScopeMemberCmd.action(async (groupId, scopeId, deviceId, opts) => {
2008
+ try {
2009
+ if (!await coordinatorRevokeScopeMembershipAction({
2010
+ groupId,
2011
+ scopeId,
2012
+ deviceId,
2013
+ membershipEpoch: parseOptionalInteger(opts.membershipEpoch, "membership epoch"),
2014
+ manifestHash: opts.manifestHash?.trim() || null,
2015
+ dbPath: resolveDbOpt(opts) ?? null,
2016
+ remoteUrl: opts.remoteUrl?.trim() || null,
2017
+ adminSecret: opts.adminSecret?.trim() || null
2018
+ })) {
2019
+ if (opts.json) {
2020
+ emitJsonError("scope_membership_not_found", "Sharing domain membership not found");
2021
+ return;
2022
+ }
2023
+ p.log.error("Sharing domain membership not found");
2024
+ process.exitCode = 1;
2025
+ return;
2026
+ }
2027
+ if (opts.json) {
2028
+ console.log(JSON.stringify({
2029
+ ok: true,
2030
+ scope_id: scopeId.trim(),
2031
+ device_id: deviceId.trim()
2032
+ }, null, 2));
2033
+ return;
2034
+ }
2035
+ p.intro("codemem coordinator revoke-scope-member");
2036
+ p.log.success(`Revoked ${deviceId.trim()} from Sharing domain ${scopeId.trim()}`);
2037
+ p.outro("revoked");
2038
+ } catch (err) {
2039
+ if (opts.json) {
2040
+ emitJsonError("revoke_scope_member_failed", err instanceof Error ? err.message : String(err));
2041
+ return;
2042
+ }
2043
+ p.log.error(err instanceof Error ? err.message : String(err));
2044
+ process.exitCode = 1;
2045
+ }
2046
+ });
2047
+ cmd.addCommand(revokeScopeMemberCmd);
1817
2048
  const renameDeviceCmd = new Command("rename-device").configureHelp(helpStyle).description("Rename an enrolled device in the local coordinator store").argument("<group>", "group id").argument("<device-id>", "device id").requiredOption("--name <name>", "display name");
1818
2049
  addDbOption(renameDeviceCmd);
1819
2050
  addJsonOption(renameDeviceCmd);
@@ -4297,6 +4528,15 @@ async function startForegroundViewer(invocation) {
4297
4528
  signal: backfillAbort.signal
4298
4529
  });
4299
4530
  const backfillCoordinator = createSequentialBackfillCoordinator(store, [
4531
+ {
4532
+ name: "Sharing-domain",
4533
+ kind: SCOPE_BACKFILL_JOB,
4534
+ isPending: hasPendingScopeBackfill,
4535
+ createRunner: () => new ScopeBackfillRunner({
4536
+ dbPath,
4537
+ signal: backfillAbort.signal
4538
+ })
4539
+ },
4300
4540
  {
4301
4541
  name: "Dedup-key",
4302
4542
  kind: DEDUP_KEY_BACKFILL_JOB,