* Execute the push and track its lifecycle. * Push is read-only on disk (delta+probe, no merge writes), so no event * suppression is needed — edits arriving mid-push hit schedulePush() and * the debounce re-arms after this push completes.
()
| 82 | * the debounce re-arms after this push completes. |
| 83 | */ |
| 84 | async function executePush(): Promise<void> { |
| 85 | if (!syncState) { |
| 86 | return |
| 87 | } |
| 88 | pushInProgress = true |
| 89 | try { |
| 90 | const result = await pushTeamMemory(syncState) |
| 91 | if (result.success) { |
| 92 | hasPendingChanges = false |
| 93 | } |
| 94 | if (result.success && result.filesUploaded > 0) { |
| 95 | logForDebugging( |
| 96 | `team-memory-watcher: pushed ${result.filesUploaded} files`, |
| 97 | { level: 'info' }, |
| 98 | ) |
| 99 | } else if (!result.success) { |
| 100 | logForDebugging(`team-memory-watcher: push failed: ${result.error}`, { |
| 101 | level: 'warn', |
| 102 | }) |
| 103 | if (isPermanentFailure(result) && pushSuppressedReason === null) { |
| 104 | pushSuppressedReason = |
| 105 | result.httpStatus !== undefined |
| 106 | ? `http_${result.httpStatus}` |
| 107 | : (result.errorType ?? 'unknown') |
| 108 | logForDebugging( |
| 109 | `team-memory-watcher: suppressing retry until next unlink or session restart (${pushSuppressedReason})`, |
| 110 | { level: 'warn' }, |
| 111 | ) |
| 112 | logEvent('tengu_team_mem_push_suppressed', { |
| 113 | reason: |
| 114 | pushSuppressedReason as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| 115 | ...(result.httpStatus && { status: result.httpStatus }), |
| 116 | }) |
| 117 | } |
| 118 | } |
| 119 | } catch (e) { |
| 120 | logForDebugging(`team-memory-watcher: push error: ${errorMessage(e)}`, { |
| 121 | level: 'warn', |
| 122 | }) |
| 123 | } finally { |
| 124 | pushInProgress = false |
| 125 | currentPushPromise = null |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /** |
| 130 | * Debounced push: waits for writes to settle, then pushes once. |
no test coverage detected