incremnt 0.7.1 → 0.7.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.
@@ -690,6 +690,42 @@ function parseLimit(value, { defaultValue, max }) {
690
690
  return Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, max) : defaultValue;
691
691
  }
692
692
 
693
+ function coachObservationSourceTriggerForScoreSnapshots(snapshots) {
694
+ if (!Array.isArray(snapshots)) return undefined;
695
+ const reasons = snapshots.map((snapshot) => snapshot?.triggerReason);
696
+ if (reasons.length === 0 || reasons.some((reason) => !reason)) return undefined;
697
+ if (reasons.includes('sessionSave')) return 'session_completed';
698
+ if (reasons.every((reason) => reason === 'historicalBackfill')) {
699
+ return 'manual_backfill';
700
+ }
701
+ if (reasons.every((reason) => reason === 'dailyRefresh')) {
702
+ return 'daily_refresh';
703
+ }
704
+ return undefined;
705
+ }
706
+
707
+ function coachObservationGenerationMetadata(result, sourceTrigger) {
708
+ return {
709
+ attempted: true,
710
+ generated: Number(result?.generated ?? 0),
711
+ persisted: Number(result?.persisted ?? 0),
712
+ skippedReason: result?.skippedReason ?? null,
713
+ sourceTrigger: sourceTrigger ?? null
714
+ };
715
+ }
716
+
717
+ function normalizeAskCoachObservationFollowUp(value) {
718
+ if (!value || typeof value !== 'object') return null;
719
+ const id = String(value.id ?? '').trim();
720
+ return id ? { id: id.slice(0, 128) } : null;
721
+ }
722
+
723
+ function selectAskCoachObservationFollowUp(requested, observations) {
724
+ if (!requested) return null;
725
+ return (Array.isArray(observations) ? observations : [])
726
+ .find((observation) => String(observation?.id ?? '') === requested.id);
727
+ }
728
+
693
729
  function routeRequest(url, method) {
694
730
  const pathname = url.pathname;
695
731
 
@@ -1064,7 +1100,13 @@ function routeRequest(url, method) {
1064
1100
  }
1065
1101
 
1066
1102
  if (pathname === '/cli/coach-observations/current') {
1067
- return { command: 'coach-observations-current', options: { limit: url.searchParams.get('limit') ?? undefined } };
1103
+ return {
1104
+ command: 'coach-observations-current',
1105
+ options: {
1106
+ limit: url.searchParams.get('limit') ?? undefined,
1107
+ refresh: url.searchParams.get('refresh') ?? undefined
1108
+ }
1109
+ };
1068
1110
  }
1069
1111
 
1070
1112
  {
@@ -2037,6 +2079,7 @@ export function createSyncServiceRequestHandler({
2037
2079
  insertScoreSnapshotsForAccount = null,
2038
2080
  listScoreSnapshotsForAccount = null,
2039
2081
  getCurrentWeeklyScoreDigestForAccount = null,
2082
+ generateCoachObservationsForAccount = null,
2040
2083
  listCurrentCoachObservationsForAccount = null,
2041
2084
  markCoachObservationSeenForAccount = null,
2042
2085
  dismissCoachObservationForAccount = null,
@@ -2906,6 +2949,22 @@ export function createSyncServiceRequestHandler({
2906
2949
  return;
2907
2950
  }
2908
2951
  const result = await insertScoreSnapshotsForAccount(account, body.snapshots);
2952
+ if (generateCoachObservationsForAccount) {
2953
+ const sourceTrigger = coachObservationSourceTriggerForScoreSnapshots(body.snapshots);
2954
+ try {
2955
+ const generationResult = await generateCoachObservationsForAccount(account, { sourceTrigger });
2956
+ result.coachObservations = coachObservationGenerationMetadata(generationResult, sourceTrigger);
2957
+ } catch (error) {
2958
+ console.error('Coach observation generation after score upload failed:', error.message);
2959
+ result.coachObservations = {
2960
+ attempted: true,
2961
+ generated: 0,
2962
+ persisted: 0,
2963
+ skippedReason: 'generation_failed',
2964
+ sourceTrigger
2965
+ };
2966
+ }
2967
+ }
2909
2968
  json(response, 200, result);
2910
2969
  return;
2911
2970
  } catch (error) {
@@ -3549,16 +3608,62 @@ export function createSyncServiceRequestHandler({
3549
3608
  methodNotAllowed(response, 'Use GET for /cli/coach-observations/current.');
3550
3609
  return;
3551
3610
  }
3611
+ if (route.options.refresh && route.options.refresh !== 'morning_open') {
3612
+ badRequest(response, 'Unsupported coach observations refresh value.');
3613
+ return;
3614
+ }
3552
3615
  if (!listCurrentCoachObservationsForAccount) {
3553
3616
  json(response, 503, { error: 'Coach observations not available' });
3554
3617
  return;
3555
3618
  }
3556
3619
  try {
3557
3620
  const limit = parseLimit(route.options.limit, { defaultValue: 5, max: 20 });
3621
+ let refresh = null;
3622
+ if (route.options.refresh === 'morning_open') {
3623
+ const writeAccount = writeAuthenticator
3624
+ ? await writeAuthenticator(requestToken)
3625
+ : requestToken === token
3626
+ ? account
3627
+ : null;
3628
+ if (!writeAccount) {
3629
+ unauthorized(response, request);
3630
+ return;
3631
+ }
3632
+ const sourceTrigger = 'daily_refresh';
3633
+ if (generateCoachObservationsForAccount) {
3634
+ try {
3635
+ const generationResult = await generateCoachObservationsForAccount(writeAccount, {
3636
+ sourceTrigger,
3637
+ refresh: route.options.refresh
3638
+ });
3639
+ refresh = coachObservationGenerationMetadata(generationResult, sourceTrigger);
3640
+ } catch (error) {
3641
+ console.error('Coach observation generation on morning open failed:', error.message);
3642
+ refresh = {
3643
+ attempted: true,
3644
+ generated: 0,
3645
+ persisted: 0,
3646
+ skippedReason: 'generation_failed',
3647
+ sourceTrigger
3648
+ };
3649
+ }
3650
+ } else {
3651
+ refresh = {
3652
+ attempted: false,
3653
+ generated: 0,
3654
+ persisted: 0,
3655
+ skippedReason: 'generation_unavailable',
3656
+ sourceTrigger
3657
+ };
3658
+ }
3659
+ }
3558
3660
  const observations = await listCurrentCoachObservationsForAccount(account, {
3559
3661
  limit
3560
3662
  });
3561
- json(response, 200, { observations: observations ?? [] });
3663
+ json(response, 200, {
3664
+ observations: observations ?? [],
3665
+ ...(refresh ? { refresh } : {})
3666
+ });
3562
3667
  } catch (err) {
3563
3668
  console.error('Coach observations read error:', err.message);
3564
3669
  json(response, 500, { error: 'Failed to read coach observations' });
@@ -4274,6 +4379,7 @@ export function createSyncServiceRequestHandler({
4274
4379
 
4275
4380
  const queries = await import('./queries.js');
4276
4381
  const exclude = parseExclude(body?.exclude);
4382
+ const requestedCoachObservation = normalizeAskCoachObservationFollowUp(body?.coachObservation);
4277
4383
  let coachFacts = [];
4278
4384
  if (listCoachFactsForAccount) {
4279
4385
  try {
@@ -4303,15 +4409,18 @@ export function createSyncServiceRequestHandler({
4303
4409
  let coachObservations = [];
4304
4410
  if (listCurrentCoachObservationsForAccount) {
4305
4411
  try {
4306
- coachObservations = await listCurrentCoachObservationsForAccount(account, { limit: 3 }) ?? [];
4412
+ coachObservations = await listCurrentCoachObservationsForAccount(account, { limit: requestedCoachObservation ? 10 : 3 }) ?? [];
4307
4413
  } catch (observationErr) {
4308
4414
  console.error('Coach observations read error (ask):', observationErr.message);
4309
4415
  }
4310
4416
  }
4417
+ const coachObservationFollowUp = selectAskCoachObservationFollowUp(requestedCoachObservation, coachObservations);
4311
4418
 
4312
- const routedContext = queries.askRoutedContext
4313
- ? queries.askRoutedContext(snapshot, question, { exclude, coachFacts, coachObservations })
4314
- : { context: queries.askContext(snapshot, { exclude }), metadata: { route: 'legacy' } };
4419
+ const routedContext = coachObservationFollowUp && queries.askObservationFollowUpContext
4420
+ ? queries.askObservationFollowUpContext(snapshot, question, coachObservationFollowUp, { exclude, coachFacts })
4421
+ : queries.askRoutedContext
4422
+ ? queries.askRoutedContext(snapshot, question, { exclude, coachFacts, coachObservations })
4423
+ : { context: queries.askContext(snapshot, { exclude }), metadata: { route: 'legacy' } };
4315
4424
  const persistedKind = persistedConversation?.kind ?? (conversationId?.startsWith('weekly-checkin:') ? 'weekly-checkin' : 'ask');
4316
4425
  const incrementScorePrelude = formatIncrementScorePrelude(scoreSnapshots);
4317
4426