@codemem/server 0.46.0-alpha.1 → 0.46.0-alpha.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.
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, CODEMEM_CONFIG_ENV_OVERRIDES, 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, 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, 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, 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, CODEMEM_CONFIG_ENV_OVERRIDES, 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, 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, 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";
4
4
  import { serveStatic } from "@hono/node-server/serve-static";
5
5
  import { Hono } from "hono";
6
6
  import { createMiddleware } from "hono/factory";
@@ -2675,21 +2675,26 @@ function resolveRawEventInboxDirectory(dbPath, homeDir = homedir()) {
2675
2675
  const target = createHash("sha256").update(resolve(dbPath)).digest("hex").slice(0, 24);
2676
2676
  return join(homeDir, ".codemem", INBOX_DIRECTORY_NAME, target);
2677
2677
  }
2678
- function entryContent(request, flushBoundary) {
2678
+ function entryContent(request, flushBoundary, boundary) {
2679
2679
  return {
2680
2680
  version: 1,
2681
2681
  request,
2682
- flush_boundary: flushBoundary
2682
+ flush_boundary: flushBoundary,
2683
+ ...boundary ? { boundary: {
2684
+ source: boundary.source,
2685
+ stream_id: boundary.streamId,
2686
+ ...boundary.id ? { id: boundary.id } : {}
2687
+ } } : {}
2683
2688
  };
2684
2689
  }
2685
- function storedEntry(request, flushBoundary, enqueueOrder) {
2690
+ function storedEntry(request, flushBoundary, boundary, enqueueOrder) {
2686
2691
  return {
2687
- ...entryContent(request, flushBoundary),
2692
+ ...entryContent(request, flushBoundary, boundary),
2688
2693
  enqueue_order: enqueueOrder.toString()
2689
2694
  };
2690
2695
  }
2691
2696
  function entryContentId(entry) {
2692
- return contentId(JSON.stringify(entryContent(entry.request, entry.flushBoundary)));
2697
+ return contentId(JSON.stringify(entryContent(entry.request, entry.flushBoundary, entry.boundary)));
2693
2698
  }
2694
2699
  function inboxFileName(enqueueOrder, id) {
2695
2700
  return `${enqueueOrder.toString().padStart(24, "0")}-${id}.json`;
@@ -2749,10 +2754,17 @@ async function ensurePrivateDirectory(path) {
2749
2754
  function parseStoredEntry(serialized) {
2750
2755
  const parsed = JSON.parse(serialized);
2751
2756
  if (parsed.version !== 1 || typeof parsed.enqueue_order !== "string" || !/^[1-9]\d*$/u.test(parsed.enqueue_order) || parsed.request == null || typeof parsed.request !== "object" || Array.isArray(parsed.request) || typeof parsed.flush_boundary !== "boolean") throw new Error("invalid raw-event inbox entry");
2757
+ const storedBoundary = parsed.boundary;
2758
+ if (storedBoundary !== void 0 && (typeof storedBoundary.source !== "string" || storedBoundary.source.trim() === "" || typeof storedBoundary.stream_id !== "string" || storedBoundary.stream_id.trim() === "" || storedBoundary.id !== void 0 && (typeof storedBoundary.id !== "string" || storedBoundary.id.trim() === ""))) throw new Error("invalid raw-event inbox boundary");
2752
2759
  return {
2753
2760
  entry: {
2754
2761
  request: parsed.request,
2755
- flushBoundary: parsed.flush_boundary
2762
+ flushBoundary: parsed.flush_boundary,
2763
+ ...storedBoundary ? { boundary: {
2764
+ source: storedBoundary.source,
2765
+ streamId: storedBoundary.stream_id,
2766
+ ...storedBoundary.id ? { id: storedBoundary.id } : {}
2767
+ } } : {}
2756
2768
  },
2757
2769
  enqueueOrder: BigInt(parsed.enqueue_order)
2758
2770
  };
@@ -2803,7 +2815,8 @@ var FileRawEventInbox = class {
2803
2815
  const flushBoundary = options.flushBoundary === true;
2804
2816
  const id = entryContentId({
2805
2817
  request,
2806
- flushBoundary
2818
+ flushBoundary,
2819
+ boundary: options.boundary
2807
2820
  });
2808
2821
  await ensurePrivateDirectory(this.directory);
2809
2822
  const entries = await readdir(this.directory, { withFileTypes: true });
@@ -2823,7 +2836,7 @@ var FileRawEventInbox = class {
2823
2836
  throw error;
2824
2837
  }
2825
2838
  const enqueueOrder = await this.allocateEnqueueOrder(entries);
2826
- const serialized = JSON.stringify(storedEntry(request, flushBoundary, enqueueOrder));
2839
+ const serialized = JSON.stringify(storedEntry(request, flushBoundary, options.boundary, enqueueOrder));
2827
2840
  const destination = join(this.directory, inboxFileName(enqueueOrder, id));
2828
2841
  const temporary = join(this.directory, `.${id}.${process.pid}.${randomUUID()}.tmp`);
2829
2842
  try {
@@ -3024,10 +3037,11 @@ function createViewerRawEventInbox(options) {
3024
3037
  onCorruptEntries: options.onCorruptEntries,
3025
3038
  onBacklog: options.onBacklog,
3026
3039
  onBacklogRecovered: options.onBacklogRecovered,
3027
- processEntry: async ({ request, flushBoundary }) => {
3040
+ processEntry: async ({ request, flushBoundary, boundary }) => {
3028
3041
  const result = ingestRawEvents(store, request);
3029
3042
  nudgeRawEventSessions(options.sweeper, result.sessions);
3030
- if (flushBoundary && isClaudeBoundaryEnvelope(request)) await flushRawEventBoundarySessions(options.sweeper, result.sessions);
3043
+ if (boundary) await options.sweeper?.flushBoundary(boundary.streamId, boundary.source);
3044
+ else if (flushBoundary && isClaudeBoundaryEnvelope(request)) await flushRawEventBoundarySessions(options.sweeper, result.sessions);
3031
3045
  }
3032
3046
  });
3033
3047
  return {
@@ -3155,15 +3169,94 @@ async function enqueueRawEventRequest(options) {
3155
3169
  if (!target.ok) return options.c.json(target.body, target.status);
3156
3170
  const validation = validateRawEvents(options.request);
3157
3171
  try {
3158
- await options.inbox.enqueue(validation.request, { flushBoundary: options.flushBoundary });
3172
+ await options.inbox.enqueue(validation.request, options.boundary ? {
3173
+ flushBoundary: options.flushBoundary,
3174
+ boundary: options.boundary
3175
+ } : { flushBoundary: options.flushBoundary });
3159
3176
  } catch (error) {
3160
3177
  return boundedInboxErrorResponse(options.c, error);
3161
3178
  }
3179
+ const accepted = options.acceptedCount ?? validation.received;
3162
3180
  return options.c.json({
3163
- accepted: validation.received,
3164
- queued: validation.received
3181
+ accepted,
3182
+ queued: accepted
3165
3183
  }, 202);
3166
3184
  }
3185
+ function piEventName(payload) {
3186
+ for (const key of [
3187
+ "piEvent",
3188
+ "pi_event",
3189
+ "event",
3190
+ "type"
3191
+ ]) {
3192
+ const value = payload[key];
3193
+ if (typeof value === "string" && value.trim()) return value.trim();
3194
+ }
3195
+ return "";
3196
+ }
3197
+ function piInboxBoundary(payload, envelope, signal) {
3198
+ if (!["session_before_compact", "session_shutdown"].includes(piEventName(payload))) return;
3199
+ const streamId = envelope?.session_stream_id ?? signal?.session_id;
3200
+ if (!streamId) return;
3201
+ const envelopeTimestamp = envelope?.payload.timestamp;
3202
+ const id = typeof envelopeTimestamp === "string" ? envelopeTimestamp : signal?.ts;
3203
+ return {
3204
+ source: "pi",
3205
+ streamId,
3206
+ ...id ? { id } : {}
3207
+ };
3208
+ }
3209
+ async function postPiHookRequest(c, getStore, sweeper, inbox, inboxTarget) {
3210
+ const result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);
3211
+ if (result instanceof Response) return result;
3212
+ const payload = result;
3213
+ try {
3214
+ const target = validateViewerTarget(inbox && inboxTarget ? inboxTarget : getStore(), payload, { requirePairedTargets: true });
3215
+ if (!target.ok) return c.json(target.body, target.status);
3216
+ const untargeted = untargetedPayload(payload);
3217
+ const envelope = buildRawEventEnvelopeFromPiEvent(untargeted);
3218
+ const signal = buildPiFlushSignalFromEvent(untargeted);
3219
+ const boundary = piInboxBoundary(untargeted, envelope, signal);
3220
+ if (envelope === null && signal === null) return c.json({
3221
+ inserted: 0,
3222
+ skipped: 1
3223
+ });
3224
+ if (inbox) return await enqueueRawEventRequest({
3225
+ c,
3226
+ getStore,
3227
+ inbox,
3228
+ inboxTarget,
3229
+ payload,
3230
+ request: envelope ? {
3231
+ ...envelope,
3232
+ source: "pi"
3233
+ } : {
3234
+ source: "pi",
3235
+ session_stream_id: signal?.session_id,
3236
+ events: []
3237
+ },
3238
+ flushBoundary: false,
3239
+ ...boundary ? {
3240
+ boundary,
3241
+ acceptedCount: 1
3242
+ } : {}
3243
+ });
3244
+ if (envelope === null) return c.json({
3245
+ inserted: 0,
3246
+ skipped: 1
3247
+ });
3248
+ const ingestResult = await ingestNormalizedEnvelope(getStore(), sweeper, {
3249
+ ...envelope,
3250
+ source: "pi"
3251
+ });
3252
+ return c.json({
3253
+ inserted: ingestResult.inserted,
3254
+ skipped: ingestResult.skipped
3255
+ });
3256
+ } catch (error) {
3257
+ return boundedIngestErrorResponse(c, error);
3258
+ }
3259
+ }
3167
3260
  async function postRawEventRequest(c, getStore, sweeper, inbox, inboxTarget) {
3168
3261
  const result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);
3169
3262
  if (result instanceof Response) return result;
@@ -3197,6 +3290,81 @@ async function ingestNormalizedEnvelope(store, sweeper, envelope, flushBoundary
3197
3290
  if (flushBoundary && isClaudeBoundaryEnvelope(envelope)) await flushRawEventBoundarySessions(sweeper, result.sessions);
3198
3291
  return result;
3199
3292
  }
3293
+ async function postClaudeHookRequest(c, getStore, sweeper, inbox, inboxTarget, transcriptDiagnostics) {
3294
+ const result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);
3295
+ if (result instanceof Response) return result;
3296
+ const payload = result;
3297
+ try {
3298
+ const target = validateViewerTarget(inbox && inboxTarget ? inboxTarget : getStore(), payload, { requirePairedTargets: true });
3299
+ if (!target.ok) return c.json(target.body, target.status);
3300
+ let transcriptOutcome = null;
3301
+ const envelope = buildRawEventEnvelopeFromHook(untargetedPayload(payload), {
3302
+ transcriptPolicy: {
3303
+ trust: "restricted",
3304
+ approvedRoots: [claudeTranscriptRoot()]
3305
+ },
3306
+ onTranscriptOutcome: (outcome) => {
3307
+ transcriptOutcome = outcome;
3308
+ transcriptDiagnostics.record("claude", outcome);
3309
+ }
3310
+ });
3311
+ if (envelope === null) return c.json(transcriptSkipResponse(transcriptOutcome));
3312
+ const flushBoundary = c.req.header("x-codemem-boundary-flush") === "1";
3313
+ if (inbox) return await enqueueRawEventRequest({
3314
+ c,
3315
+ getStore,
3316
+ inbox,
3317
+ inboxTarget,
3318
+ payload,
3319
+ request: { ...envelope },
3320
+ flushBoundary
3321
+ });
3322
+ const ingestResult = await ingestNormalizedEnvelope(getStore(), sweeper, envelope, flushBoundary);
3323
+ return c.json({
3324
+ inserted: ingestResult.inserted,
3325
+ skipped: ingestResult.skipped
3326
+ });
3327
+ } catch (error) {
3328
+ return boundedIngestErrorResponse(c, error);
3329
+ }
3330
+ }
3331
+ async function postCodexHookRequest(c, getStore, sweeper, inbox, inboxTarget, transcriptDiagnostics) {
3332
+ const result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);
3333
+ if (result instanceof Response) return result;
3334
+ const payload = result;
3335
+ try {
3336
+ const target = validateViewerTarget(inbox && inboxTarget ? inboxTarget : getStore(), payload, { requirePairedTargets: true });
3337
+ if (!target.ok) return c.json(target.body, target.status);
3338
+ let transcriptOutcome = null;
3339
+ const envelope = buildRawEventEnvelopeFromCodexHook(untargetedPayload(payload), {
3340
+ transcriptPolicy: {
3341
+ trust: "restricted",
3342
+ approvedRoots: [codexTranscriptRoot()]
3343
+ },
3344
+ onTranscriptOutcome: (outcome) => {
3345
+ transcriptOutcome = outcome;
3346
+ transcriptDiagnostics.record("codex", outcome);
3347
+ }
3348
+ });
3349
+ if (envelope === null) return c.json(transcriptSkipResponse(transcriptOutcome));
3350
+ if (inbox) return await enqueueRawEventRequest({
3351
+ c,
3352
+ getStore,
3353
+ inbox,
3354
+ inboxTarget,
3355
+ payload,
3356
+ request: { ...envelope },
3357
+ flushBoundary: false
3358
+ });
3359
+ const ingestResult = await ingestNormalizedEnvelope(getStore(), sweeper, envelope);
3360
+ return c.json({
3361
+ inserted: ingestResult.inserted,
3362
+ skipped: ingestResult.skipped
3363
+ });
3364
+ } catch (error) {
3365
+ return boundedIngestErrorResponse(c, error);
3366
+ }
3367
+ }
3200
3368
  function rawEventsRoutes(getStore, sweeper, inbox, inboxTarget) {
3201
3369
  const app = new Hono();
3202
3370
  const transcriptDiagnostics = createTranscriptDiagnostics();
@@ -3248,89 +3416,9 @@ function rawEventsRoutes(getStore, sweeper, inbox, inboxTarget) {
3248
3416
  });
3249
3417
  });
3250
3418
  app.post("/api/raw-events", (c) => postRawEventRequest(c, getStore, sweeper, inbox, inboxTarget));
3251
- app.post("/api/claude-hooks", async (c) => {
3252
- const result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);
3253
- if (result instanceof Response) return result;
3254
- const payload = result;
3255
- try {
3256
- const store = getStore();
3257
- const target = validateViewerTarget(store, payload, { requirePairedTargets: true });
3258
- if (!target.ok) return c.json(target.body, target.status);
3259
- let transcriptOutcome = null;
3260
- const envelope = buildRawEventEnvelopeFromHook(untargetedPayload(payload), {
3261
- transcriptPolicy: {
3262
- trust: "restricted",
3263
- approvedRoots: [claudeTranscriptRoot()]
3264
- },
3265
- onTranscriptOutcome: (outcome) => {
3266
- transcriptOutcome = outcome;
3267
- transcriptDiagnostics.record("claude", outcome);
3268
- }
3269
- });
3270
- if (envelope === null) return c.json(transcriptSkipResponse(transcriptOutcome));
3271
- const ingestResult = await ingestNormalizedEnvelope(store, sweeper, envelope, c.req.header("x-codemem-boundary-flush") === "1");
3272
- return c.json({
3273
- inserted: ingestResult.inserted,
3274
- skipped: ingestResult.skipped
3275
- });
3276
- } catch (err) {
3277
- return boundedIngestErrorResponse(c, err);
3278
- }
3279
- });
3280
- app.post("/api/codex-hooks", async (c) => {
3281
- const result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);
3282
- if (result instanceof Response) return result;
3283
- const payload = result;
3284
- try {
3285
- const store = getStore();
3286
- const target = validateViewerTarget(store, payload, { requirePairedTargets: true });
3287
- if (!target.ok) return c.json(target.body, target.status);
3288
- let transcriptOutcome = null;
3289
- const envelope = buildRawEventEnvelopeFromCodexHook(untargetedPayload(payload), {
3290
- transcriptPolicy: {
3291
- trust: "restricted",
3292
- approvedRoots: [codexTranscriptRoot()]
3293
- },
3294
- onTranscriptOutcome: (outcome) => {
3295
- transcriptOutcome = outcome;
3296
- transcriptDiagnostics.record("codex", outcome);
3297
- }
3298
- });
3299
- if (envelope === null) return c.json(transcriptSkipResponse(transcriptOutcome));
3300
- const ingestResult = await ingestNormalizedEnvelope(store, sweeper, envelope);
3301
- return c.json({
3302
- inserted: ingestResult.inserted,
3303
- skipped: ingestResult.skipped
3304
- });
3305
- } catch (err) {
3306
- return boundedIngestErrorResponse(c, err);
3307
- }
3308
- });
3309
- app.post("/api/pi-hooks", async (c) => {
3310
- const result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);
3311
- if (result instanceof Response) return result;
3312
- const payload = result;
3313
- try {
3314
- const store = getStore();
3315
- const target = validateViewerTarget(store, payload, { requirePairedTargets: true });
3316
- if (!target.ok) return c.json(target.body, target.status);
3317
- const envelope = buildRawEventEnvelopeFromPiEvent(untargetedPayload(payload));
3318
- if (envelope === null) return c.json({
3319
- inserted: 0,
3320
- skipped: 1
3321
- });
3322
- const ingestResult = await ingestNormalizedEnvelope(store, sweeper, {
3323
- ...envelope,
3324
- source: "pi"
3325
- });
3326
- return c.json({
3327
- inserted: ingestResult.inserted,
3328
- skipped: ingestResult.skipped
3329
- });
3330
- } catch (err) {
3331
- return boundedIngestErrorResponse(c, err);
3332
- }
3333
- });
3419
+ app.post("/api/claude-hooks", (c) => postClaudeHookRequest(c, getStore, sweeper, inbox, inboxTarget, transcriptDiagnostics));
3420
+ app.post("/api/codex-hooks", (c) => postCodexHookRequest(c, getStore, sweeper, inbox, inboxTarget, transcriptDiagnostics));
3421
+ app.post("/api/pi-hooks", (c) => postPiHookRequest(c, getStore, sweeper, inbox, inboxTarget));
3334
3422
  return app;
3335
3423
  }
3336
3424
  //#endregion