@oss-autopilot/core 3.13.2 → 3.13.3

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/cli.js CHANGED
@@ -81,6 +81,20 @@ program.hook('preAction', async (thisCommand, actionCommand) => {
81
81
  const { ensureGistPersistence } = await import('./core/index.js');
82
82
  await ensureGistPersistence(token);
83
83
  }
84
+ else {
85
+ // #1431: localOnly skips the AUTH GATE, not gist persistence. Mutating
86
+ // localOnly commands (shelve/move/dismiss/override/...) already call
87
+ // maybeCheckpoint, which silently no-ops when the singleton never
88
+ // bootstrapped — so a gist-configured user's CLI mutations were written
89
+ // local-only with no warning and never reached the Gist. Best-effort
90
+ // bootstrap; the warning semantics live (and are unit-tested) in
91
+ // bootstrapGistBestEffort.
92
+ const { bootstrapGistBestEffort } = await import('./core/index.js');
93
+ const localOnlyWarning = await bootstrapGistBestEffort(getGitHubTokenAsync);
94
+ if (localOnlyWarning) {
95
+ console.error(`Warning: ${localOnlyWarning}`);
96
+ }
97
+ }
84
98
  });
85
99
  // First-run detection: if no subcommand was provided and no state file exists,
86
100
  // show a quick-start guide and exit before Commander displays generic help.
@@ -546,6 +546,15 @@ async function executeDailyCheckInternal(token) {
546
546
  // One collector shared by every phase — threaded through explicitly so the
547
547
  // callgraph documents which phases can produce non-fatal warnings. See #1042.
548
548
  const warnings = [];
549
+ // Surface gist-mode degradation in the machine-readable envelope (#1431):
550
+ // a process whose config says `persistence: gist` but whose manager is
551
+ // local-only (transient init fallback, or a localOnly entry point that
552
+ // never bootstrapped) writes mutations that will not sync. Previously the
553
+ // only signal was a stderr warn, invisible to --json consumers.
554
+ const smForGistCheck = getStateManager();
555
+ if (smForGistCheck.getState().config.persistence === 'gist' && !smForGistCheck.isGistMode()) {
556
+ recordWarning(warnings, 'gist-init', 'Gist persistence degraded', new Error('configured for Gist but running local-only in this process; mutations will not sync until Gist init succeeds'));
557
+ }
549
558
  // Surface Gist staleness up-front so consumers see it even if Phase 1 fails (#1193).
550
559
  const staleness = getStateManager().getStateStaleness();
551
560
  if (staleness) {
@@ -2,7 +2,7 @@
2
2
  * Core module exports
3
3
  * Re-exports all core functionality for convenient imports
4
4
  */
5
- export { StateManager, getStateManager, getStateManagerAsync, ensureGistPersistence, type GistPersistenceStatus, maybeCheckpoint, resetStateManager, type Stats, } from './state.js';
5
+ export { StateManager, getStateManager, getStateManagerAsync, ensureGistPersistence, bootstrapGistBestEffort, type GistPersistenceStatus, maybeCheckpoint, resetStateManager, type Stats, } from './state.js';
6
6
  export { GistStateStore } from './gist-state-store.js';
7
7
  export { guidelinesFilename, repoFromGuidelinesFilename, GUIDELINES_FILE_PREFIX, GUIDELINES_MAX_BYTES, GuidelinesNotAvailableError, GuidelinesTooLargeError, } from './guidelines-store.js';
8
8
  export { PRMonitor, type PRCheckFailure, type FetchPRsResult, computeDisplayLabel, classifyCICheck, classifyFailingChecks, } from './pr-monitor.js';
@@ -2,7 +2,7 @@
2
2
  * Core module exports
3
3
  * Re-exports all core functionality for convenient imports
4
4
  */
5
- export { StateManager, getStateManager, getStateManagerAsync, ensureGistPersistence, maybeCheckpoint, resetStateManager, } from './state.js';
5
+ export { StateManager, getStateManager, getStateManagerAsync, ensureGistPersistence, bootstrapGistBestEffort, maybeCheckpoint, resetStateManager, } from './state.js';
6
6
  export { GistStateStore } from './gist-state-store.js';
7
7
  export { guidelinesFilename, repoFromGuidelinesFilename, GUIDELINES_FILE_PREFIX, GUIDELINES_MAX_BYTES, GuidelinesNotAvailableError, GuidelinesTooLargeError, } from './guidelines-store.js';
8
8
  export { PRMonitor, computeDisplayLabel, classifyCICheck, classifyFailingChecks, } from './pr-monitor.js';
@@ -456,6 +456,25 @@ export type GistPersistenceStatus =
456
456
  * to local-only (transient network failure). A later call may recover. */
457
457
  | 'degraded';
458
458
  export declare function ensureGistPersistence(token: string | null): Promise<GistPersistenceStatus>;
459
+ /**
460
+ * Best-effort gist bootstrap for entry points WITHOUT the auth gate (#1431):
461
+ * the CLI's localOnly commands (shelve/move/dismiss/override/config/setup/...)
462
+ * skip token enforcement, but a gist-configured user's mutations must still
463
+ * reach the Gist — their maybeCheckpoint calls silently no-op when the
464
+ * singleton never bootstrapped.
465
+ *
466
+ * Returns a human-readable LOCAL-ONLY warning when the process will write
467
+ * local-only despite a gist config, or null when no warning is needed
468
+ * (local mode, or gist mode successfully activated).
469
+ *
470
+ * Ordering: peek first with no token (zero spawn cost for genuinely-local
471
+ * users), fetch a token only when the config asks for gist. Hard
472
+ * ConfigurationErrors are converted to a warning instead of thrown — the
473
+ * localOnly set includes config/setup, the very commands needed to REPAIR a
474
+ * broken gist setup, so they must not be bricked by it. (The auth-gated
475
+ * path keeps throwing per #1202.)
476
+ */
477
+ export declare function bootstrapGistBestEffort(fetchToken: () => Promise<string | null>): Promise<string | null>;
459
478
  /**
460
479
  * Reset the singleton StateManager instance to null. Intended for test isolation.
461
480
  */
@@ -1000,6 +1000,49 @@ export async function ensureGistPersistence(token) {
1000
1000
  const mgr = await getStateManagerAsync(token);
1001
1001
  return mgr.isGistMode() ? 'gist' : 'degraded';
1002
1002
  }
1003
+ /**
1004
+ * Best-effort gist bootstrap for entry points WITHOUT the auth gate (#1431):
1005
+ * the CLI's localOnly commands (shelve/move/dismiss/override/config/setup/...)
1006
+ * skip token enforcement, but a gist-configured user's mutations must still
1007
+ * reach the Gist — their maybeCheckpoint calls silently no-op when the
1008
+ * singleton never bootstrapped.
1009
+ *
1010
+ * Returns a human-readable LOCAL-ONLY warning when the process will write
1011
+ * local-only despite a gist config, or null when no warning is needed
1012
+ * (local mode, or gist mode successfully activated).
1013
+ *
1014
+ * Ordering: peek first with no token (zero spawn cost for genuinely-local
1015
+ * users), fetch a token only when the config asks for gist. Hard
1016
+ * ConfigurationErrors are converted to a warning instead of thrown — the
1017
+ * localOnly set includes config/setup, the very commands needed to REPAIR a
1018
+ * broken gist setup, so they must not be bricked by it. (The auth-gated
1019
+ * path keeps throwing per #1202.)
1020
+ */
1021
+ export async function bootstrapGistBestEffort(fetchToken) {
1022
+ let reason = null;
1023
+ try {
1024
+ let status = await ensureGistPersistence(null);
1025
+ if (status === 'no-token') {
1026
+ status = await ensureGistPersistence(await fetchToken());
1027
+ }
1028
+ if (status === 'no-token')
1029
+ reason = 'no GitHub token is available';
1030
+ else if (status === 'state-unreadable')
1031
+ reason = 'the state file could not be read';
1032
+ else if (status === 'degraded')
1033
+ reason = 'Gist initialization hit a transient network failure';
1034
+ }
1035
+ catch (err) {
1036
+ reason =
1037
+ err instanceof ConfigurationError
1038
+ ? `Gist initialization failed (${errorMessage(err)}) — fix the Gist setup (check the token's gist scope, or run state-show / setup) before relying on sync`
1039
+ : `Gist initialization failed: ${errorMessage(err)}`;
1040
+ }
1041
+ if (reason === null)
1042
+ return null;
1043
+ return (`Gist persistence is configured but ${reason} — changes made by this command are ` +
1044
+ 'LOCAL-ONLY and may be overwritten by the next successful Gist sync.');
1045
+ }
1003
1046
  /**
1004
1047
  * Reset the singleton StateManager instance to null. Intended for test isolation.
1005
1048
  */
@@ -51,7 +51,7 @@ export interface CompactRepoGroup {
51
51
  * See `DailyWarning` and issue #1042 for the rationale — keeping this a
52
52
  * fixed union so downstream consumers can switch on it without drift.
53
53
  */
54
- export type DailyWarningPhase = 'fetch' | 'repo-scores' | 'analytics' | 'scout-sync' | 'partition' | 'dismiss-filter' | 'gist-checkpoint' | 'gist-staleness' | 'state-load';
54
+ export type DailyWarningPhase = 'fetch' | 'repo-scores' | 'analytics' | 'scout-sync' | 'partition' | 'dismiss-filter' | 'gist-init' | 'gist-checkpoint' | 'gist-staleness' | 'state-load';
55
55
  /**
56
56
  * A single non-fatal failure surfaced from the `daily` pipeline. Unlike
57
57
  * `PRCheckFailure` (which is scoped to per-PR fetch errors), this covers
@@ -179,6 +179,7 @@ export declare const StatusOutputSchema: z.ZodObject<{
179
179
  "scout-sync": "scout-sync";
180
180
  partition: "partition";
181
181
  "dismiss-filter": "dismiss-filter";
182
+ "gist-init": "gist-init";
182
183
  "gist-checkpoint": "gist-checkpoint";
183
184
  "gist-staleness": "gist-staleness";
184
185
  "state-load": "state-load";
@@ -394,6 +395,7 @@ export declare const DailyOutputSchema: z.ZodObject<{
394
395
  "scout-sync": "scout-sync";
395
396
  partition: "partition";
396
397
  "dismiss-filter": "dismiss-filter";
398
+ "gist-init": "gist-init";
397
399
  "gist-checkpoint": "gist-checkpoint";
398
400
  "gist-staleness": "gist-staleness";
399
401
  "state-load": "state-load";
@@ -541,6 +543,7 @@ export declare const CompactDailyOutputSchema: z.ZodObject<{
541
543
  "scout-sync": "scout-sync";
542
544
  partition: "partition";
543
545
  "dismiss-filter": "dismiss-filter";
546
+ "gist-init": "gist-init";
544
547
  "gist-checkpoint": "gist-checkpoint";
545
548
  "gist-staleness": "gist-staleness";
546
549
  "state-load": "state-load";
@@ -90,6 +90,7 @@ const DailyWarningPhaseSchema = z.enum([
90
90
  'scout-sync',
91
91
  'partition',
92
92
  'dismiss-filter',
93
+ 'gist-init',
93
94
  'gist-checkpoint',
94
95
  'gist-staleness',
95
96
  'state-load',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "3.13.2",
3
+ "version": "3.13.3",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {