@oss-autopilot/core 1.9.0 → 1.11.0

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.
@@ -32,13 +32,11 @@ export declare const IssueScopeSchema: z.ZodEnum<{
32
32
  beginner: "beginner";
33
33
  intermediate: "intermediate";
34
34
  }>;
35
- export declare const StateEventTypeSchema: z.ZodEnum<{
36
- pr_tracked: "pr_tracked";
37
- pr_merged: "pr_merged";
38
- pr_closed: "pr_closed";
39
- pr_dormant: "pr_dormant";
40
- daily_check: "daily_check";
41
- comment_posted: "comment_posted";
35
+ export declare const DiffToolSchema: z.ZodEnum<{
36
+ inline: "inline";
37
+ custom: "custom";
38
+ sourcetree: "sourcetree";
39
+ vscode: "vscode";
42
40
  }>;
43
41
  export declare const RepoSignalsSchema: z.ZodObject<{
44
42
  hasActiveMaintainers: z.ZodBoolean;
@@ -61,28 +59,22 @@ export declare const RepoScoreSchema: z.ZodObject<{
61
59
  stargazersCount: z.ZodOptional<z.ZodNumber>;
62
60
  language: z.ZodOptional<z.ZodNullable<z.ZodString>>;
63
61
  }, z.core.$strip>;
64
- export declare const StateEventSchema: z.ZodObject<{
65
- id: z.ZodString;
66
- type: z.ZodEnum<{
67
- pr_tracked: "pr_tracked";
68
- pr_merged: "pr_merged";
69
- pr_closed: "pr_closed";
70
- pr_dormant: "pr_dormant";
71
- daily_check: "daily_check";
72
- comment_posted: "comment_posted";
73
- }>;
74
- at: z.ZodString;
75
- data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
76
- }, z.core.$strip>;
77
62
  export declare const StoredMergedPRSchema: z.ZodObject<{
78
63
  url: z.ZodString;
79
64
  title: z.ZodString;
80
65
  mergedAt: z.ZodString;
66
+ learningsExtractedAt: z.ZodOptional<z.ZodString>;
81
67
  }, z.core.$strip>;
82
68
  export declare const StoredClosedPRSchema: z.ZodObject<{
83
69
  url: z.ZodString;
84
70
  title: z.ZodString;
85
71
  closedAt: z.ZodString;
72
+ learningsExtractedAt: z.ZodOptional<z.ZodString>;
73
+ }, z.core.$strip>;
74
+ export declare const AnalyzedIssueConversationSchema: z.ZodObject<{
75
+ url: z.ZodString;
76
+ repo: z.ZodString;
77
+ analyzedAt: z.ZodString;
86
78
  }, z.core.$strip>;
87
79
  export declare const ContributionGuidelinesSchema: z.ZodObject<{
88
80
  branchNamingConvention: z.ZodOptional<z.ZodString>;
@@ -193,6 +185,10 @@ export declare const StatusOverrideSchema: z.ZodObject<{
193
185
  export declare const AgentConfigSchema: z.ZodObject<{
194
186
  setupComplete: z.ZodDefault<z.ZodBoolean>;
195
187
  setupCompletedAt: z.ZodOptional<z.ZodString>;
188
+ persistence: z.ZodDefault<z.ZodEnum<{
189
+ local: "local";
190
+ gist: "gist";
191
+ }>>;
196
192
  maxActivePRs: z.ZodDefault<z.ZodNumber>;
197
193
  dormantThresholdDays: z.ZodDefault<z.ZodNumber>;
198
194
  approachingDormantDays: z.ZodDefault<z.ZodNumber>;
@@ -209,10 +205,8 @@ export declare const AgentConfigSchema: z.ZodObject<{
209
205
  trustedProjects: z.ZodDefault<z.ZodArray<z.ZodString>>;
210
206
  githubUsername: z.ZodDefault<z.ZodString>;
211
207
  minRepoScoreThreshold: z.ZodDefault<z.ZodNumber>;
212
- scoreThreshold: z.ZodDefault<z.ZodNumber>;
213
208
  starredRepos: z.ZodDefault<z.ZodArray<z.ZodString>>;
214
209
  starredReposLastFetched: z.ZodOptional<z.ZodString>;
215
- showHealthCheck: z.ZodOptional<z.ZodBoolean>;
216
210
  squashByDefault: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"ask">]>>;
217
211
  localRepoScanPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
218
212
  minStars: z.ZodDefault<z.ZodNumber>;
@@ -239,6 +233,13 @@ export declare const AgentConfigSchema: z.ZodObject<{
239
233
  education: "education";
240
234
  }>>>;
241
235
  preferredOrgs: z.ZodDefault<z.ZodArray<z.ZodString>>;
236
+ diffTool: z.ZodDefault<z.ZodEnum<{
237
+ inline: "inline";
238
+ custom: "custom";
239
+ sourcetree: "sourcetree";
240
+ vscode: "vscode";
241
+ }>>;
242
+ diffToolCustomCommand: z.ZodOptional<z.ZodString>;
242
243
  }, z.core.$strip>;
243
244
  export declare const LocalRepoCacheSchema: z.ZodObject<{
244
245
  repos: z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -320,7 +321,8 @@ export declare const DailyDigestSchema: z.ZodObject<{
320
321
  }, z.core.$strip>;
321
322
  }, z.core.$strip>;
322
323
  export declare const AgentStateSchema: z.ZodObject<{
323
- version: z.ZodLiteral<2>;
324
+ version: z.ZodLiteral<3>;
325
+ gistId: z.ZodOptional<z.ZodString>;
324
326
  repoScores: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
325
327
  repo: z.ZodString;
326
328
  score: z.ZodNumber;
@@ -340,6 +342,10 @@ export declare const AgentStateSchema: z.ZodObject<{
340
342
  config: z.ZodDefault<z.ZodObject<{
341
343
  setupComplete: z.ZodDefault<z.ZodBoolean>;
342
344
  setupCompletedAt: z.ZodOptional<z.ZodString>;
345
+ persistence: z.ZodDefault<z.ZodEnum<{
346
+ local: "local";
347
+ gist: "gist";
348
+ }>>;
343
349
  maxActivePRs: z.ZodDefault<z.ZodNumber>;
344
350
  dormantThresholdDays: z.ZodDefault<z.ZodNumber>;
345
351
  approachingDormantDays: z.ZodDefault<z.ZodNumber>;
@@ -356,10 +362,8 @@ export declare const AgentStateSchema: z.ZodObject<{
356
362
  trustedProjects: z.ZodDefault<z.ZodArray<z.ZodString>>;
357
363
  githubUsername: z.ZodDefault<z.ZodString>;
358
364
  minRepoScoreThreshold: z.ZodDefault<z.ZodNumber>;
359
- scoreThreshold: z.ZodDefault<z.ZodNumber>;
360
365
  starredRepos: z.ZodDefault<z.ZodArray<z.ZodString>>;
361
366
  starredReposLastFetched: z.ZodOptional<z.ZodString>;
362
- showHealthCheck: z.ZodOptional<z.ZodBoolean>;
363
367
  squashByDefault: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"ask">]>>;
364
368
  localRepoScanPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
365
369
  minStars: z.ZodDefault<z.ZodNumber>;
@@ -386,20 +390,14 @@ export declare const AgentStateSchema: z.ZodObject<{
386
390
  education: "education";
387
391
  }>>>;
388
392
  preferredOrgs: z.ZodDefault<z.ZodArray<z.ZodString>>;
393
+ diffTool: z.ZodDefault<z.ZodEnum<{
394
+ inline: "inline";
395
+ custom: "custom";
396
+ sourcetree: "sourcetree";
397
+ vscode: "vscode";
398
+ }>>;
399
+ diffToolCustomCommand: z.ZodOptional<z.ZodString>;
389
400
  }, z.core.$strip>>;
390
- events: z.ZodDefault<z.ZodArray<z.ZodObject<{
391
- id: z.ZodString;
392
- type: z.ZodEnum<{
393
- pr_tracked: "pr_tracked";
394
- pr_merged: "pr_merged";
395
- pr_closed: "pr_closed";
396
- pr_dormant: "pr_dormant";
397
- daily_check: "daily_check";
398
- comment_posted: "comment_posted";
399
- }>;
400
- at: z.ZodString;
401
- data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
402
- }, z.core.$strip>>>;
403
401
  lastRunAt: z.ZodDefault<z.ZodString>;
404
402
  lastDigestAt: z.ZodOptional<z.ZodString>;
405
403
  lastDigest: z.ZodOptional<z.ZodObject<{
@@ -454,7 +452,6 @@ export declare const AgentStateSchema: z.ZodObject<{
454
452
  monthlyMergedCounts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
455
453
  monthlyClosedCounts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
456
454
  monthlyOpenedCounts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
457
- dailyActivityCounts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
458
455
  localRepoCache: z.ZodOptional<z.ZodObject<{
459
456
  repos: z.ZodRecord<z.ZodString, z.ZodObject<{
460
457
  path: z.ZodString;
@@ -468,11 +465,18 @@ export declare const AgentStateSchema: z.ZodObject<{
468
465
  url: z.ZodString;
469
466
  title: z.ZodString;
470
467
  mergedAt: z.ZodString;
468
+ learningsExtractedAt: z.ZodOptional<z.ZodString>;
471
469
  }, z.core.$strip>>>;
472
470
  closedPRs: z.ZodOptional<z.ZodArray<z.ZodObject<{
473
471
  url: z.ZodString;
474
472
  title: z.ZodString;
475
473
  closedAt: z.ZodString;
474
+ learningsExtractedAt: z.ZodOptional<z.ZodString>;
475
+ }, z.core.$strip>>>;
476
+ analyzedIssueConversations: z.ZodOptional<z.ZodArray<z.ZodObject<{
477
+ url: z.ZodString;
478
+ repo: z.ZodString;
479
+ analyzedAt: z.ZodString;
476
480
  }, z.core.$strip>>>;
477
481
  activeIssues: z.ZodDefault<z.ZodArray<z.ZodObject<{
478
482
  id: z.ZodNumber;
@@ -523,12 +527,12 @@ export type IssueStatus = z.infer<typeof IssueStatusSchema>;
523
527
  export type FetchedPRStatus = z.infer<typeof FetchedPRStatusSchema>;
524
528
  export type ProjectCategory = z.infer<typeof ProjectCategorySchema>;
525
529
  export type IssueScope = z.infer<typeof IssueScopeSchema>;
526
- export type StateEventType = z.infer<typeof StateEventTypeSchema>;
530
+ export type DiffTool = z.infer<typeof DiffToolSchema>;
527
531
  export type RepoSignals = z.infer<typeof RepoSignalsSchema>;
528
532
  export type RepoScore = z.infer<typeof RepoScoreSchema>;
529
- export type StateEvent = z.infer<typeof StateEventSchema>;
530
533
  export type StoredMergedPR = z.infer<typeof StoredMergedPRSchema>;
531
534
  export type StoredClosedPR = z.infer<typeof StoredClosedPRSchema>;
535
+ export type AnalyzedIssueConversation = z.infer<typeof AnalyzedIssueConversationSchema>;
532
536
  export type ContributionGuidelines = z.infer<typeof ContributionGuidelinesSchema>;
533
537
  export type IssueVettingResult = z.infer<typeof IssueVettingResultSchema>;
534
538
  export type TrackedIssue = z.infer<typeof TrackedIssueSchema>;
@@ -21,14 +21,7 @@ export const ProjectCategorySchema = z.enum([
21
21
  'education',
22
22
  ]);
23
23
  export const IssueScopeSchema = z.enum(['beginner', 'intermediate', 'advanced']);
24
- export const StateEventTypeSchema = z.enum([
25
- 'pr_tracked',
26
- 'pr_merged',
27
- 'pr_closed',
28
- 'pr_dormant',
29
- 'daily_check',
30
- 'comment_posted',
31
- ]);
24
+ export const DiffToolSchema = z.enum(['inline', 'sourcetree', 'vscode', 'custom']);
32
25
  // ── 2. Leaf schemas ──────────────────────────────────────────────────
33
26
  export const RepoSignalsSchema = z.object({
34
27
  hasActiveMaintainers: z.boolean(),
@@ -47,21 +40,22 @@ export const RepoScoreSchema = z.object({
47
40
  stargazersCount: z.number().optional(),
48
41
  language: z.string().nullable().optional(),
49
42
  });
50
- export const StateEventSchema = z.object({
51
- id: z.string(),
52
- type: StateEventTypeSchema,
53
- at: z.string(),
54
- data: z.record(z.string(), z.unknown()),
55
- });
56
43
  export const StoredMergedPRSchema = z.object({
57
44
  url: z.string(),
58
45
  title: z.string(),
59
46
  mergedAt: z.string(),
47
+ learningsExtractedAt: z.string().optional(),
60
48
  });
61
49
  export const StoredClosedPRSchema = z.object({
62
50
  url: z.string(),
63
51
  title: z.string(),
64
52
  closedAt: z.string(),
53
+ learningsExtractedAt: z.string().optional(),
54
+ });
55
+ export const AnalyzedIssueConversationSchema = z.object({
56
+ url: z.string(),
57
+ repo: z.string(),
58
+ analyzedAt: z.string(),
65
59
  });
66
60
  // ── 3. Contribution schemas ──────────────────────────────────────────
67
61
  export const ContributionGuidelinesSchema = z.object({
@@ -123,6 +117,7 @@ export const StatusOverrideSchema = z.object({
123
117
  export const AgentConfigSchema = z.object({
124
118
  setupComplete: z.boolean().default(false),
125
119
  setupCompletedAt: z.string().optional(),
120
+ persistence: z.enum(['local', 'gist']).default('local'),
126
121
  maxActivePRs: z.number().default(10),
127
122
  dormantThresholdDays: z.number().default(30),
128
123
  approachingDormantDays: z.number().default(25),
@@ -135,10 +130,8 @@ export const AgentConfigSchema = z.object({
135
130
  trustedProjects: z.array(z.string()).default([]),
136
131
  githubUsername: z.string().default(''),
137
132
  minRepoScoreThreshold: z.number().default(4),
138
- scoreThreshold: z.number().int().min(1).max(10).default(6),
139
133
  starredRepos: z.array(z.string()).default([]),
140
134
  starredReposLastFetched: z.string().optional(),
141
- showHealthCheck: z.boolean().optional(),
142
135
  squashByDefault: z.union([z.boolean(), z.literal('ask')]).default(true),
143
136
  localRepoScanPaths: z.array(z.string()).optional(),
144
137
  minStars: z.number().default(50),
@@ -151,6 +144,8 @@ export const AgentConfigSchema = z.object({
151
144
  skippedIssuesPath: z.string().optional(),
152
145
  projectCategories: z.array(ProjectCategorySchema).default([]),
153
146
  preferredOrgs: z.array(z.string()).default([]),
147
+ diffTool: DiffToolSchema.default('inline'),
148
+ diffToolCustomCommand: z.string().optional(),
154
149
  });
155
150
  // ── 6. Cache schemas ─────────────────────────────────────────────────
156
151
  export const LocalRepoCacheSchema = z.object({
@@ -198,19 +193,19 @@ export const DailyDigestSchema = z.object({
198
193
  });
199
194
  // ── 8. Root schema ───────────────────────────────────────────────────
200
195
  export const AgentStateSchema = z.object({
201
- version: z.literal(2),
196
+ version: z.literal(3),
197
+ gistId: z.string().optional(),
202
198
  repoScores: z.record(z.string(), RepoScoreSchema).default({}),
203
199
  config: AgentConfigSchema.default(() => AgentConfigSchema.parse({})),
204
- events: z.array(StateEventSchema).default([]),
205
200
  lastRunAt: z.string().default(() => new Date().toISOString()),
206
201
  lastDigestAt: z.string().optional(),
207
202
  lastDigest: DailyDigestSchema.optional(),
208
203
  monthlyMergedCounts: z.record(z.string(), z.number()).optional(),
209
204
  monthlyClosedCounts: z.record(z.string(), z.number()).optional(),
210
205
  monthlyOpenedCounts: z.record(z.string(), z.number()).optional(),
211
- dailyActivityCounts: z.record(z.string(), z.number()).optional(),
212
206
  localRepoCache: LocalRepoCacheSchema.optional(),
213
207
  mergedPRs: z.array(StoredMergedPRSchema).optional(),
214
208
  closedPRs: z.array(StoredClosedPRSchema).optional(),
209
+ analyzedIssueConversations: z.array(AnalyzedIssueConversationSchema).optional(),
215
210
  activeIssues: z.array(TrackedIssueSchema).default([]),
216
211
  });
@@ -3,23 +3,26 @@
3
3
  * Thin coordinator that delegates persistence to state-persistence.ts
4
4
  * and scoring logic to repo-score-manager.ts.
5
5
  */
6
- import { AgentState, TrackedIssue, RepoScore, RepoScoreUpdate, StateEvent, StateEventType, DailyDigest, LocalRepoCache, StatusOverride, FetchedPRStatus, StoredMergedPR, StoredClosedPR } from './types.js';
6
+ import { AgentState, TrackedIssue, RepoScore, RepoScoreUpdate, DailyDigest, LocalRepoCache, StatusOverride, FetchedPRStatus, StoredMergedPR, StoredClosedPR } from './types.js';
7
7
  import type { Stats } from './repo-score-manager.js';
8
+ import { GistStateStore } from './gist-state-store.js';
8
9
  export { acquireLock, releaseLock, atomicWriteFileSync } from './state-persistence.js';
9
10
  export type { Stats } from './repo-score-manager.js';
10
11
  /**
11
12
  * Singleton manager for persistent agent state stored in ~/.oss-autopilot/state.json.
12
13
  *
13
14
  * Delegates file I/O to state-persistence.ts and scoring logic to repo-score-manager.ts.
14
- * Retains lightweight CRUD operations for config, events, issues, shelving, dismissal,
15
+ * Retains lightweight CRUD operations for config, issues, shelving, dismissal,
15
16
  * and status overrides.
16
17
  */
17
18
  export declare class StateManager {
18
- private state;
19
- private readonly inMemoryOnly;
19
+ protected state: AgentState;
20
+ protected inMemoryOnly: boolean;
20
21
  private lastLoadedMtimeMs;
21
22
  private _batching;
22
23
  private _batchDirty;
24
+ protected gistStore: GistStateStore | null;
25
+ protected gistDegraded: boolean;
23
26
  /**
24
27
  * Create a new StateManager instance.
25
28
  * @param inMemoryOnly - When true, state is held only in memory and never read from or
@@ -27,6 +30,15 @@ export declare class StateManager {
27
30
  * Defaults to false (normal persistent mode).
28
31
  */
29
32
  constructor(inMemoryOnly?: boolean);
33
+ /**
34
+ * Async factory that creates a StateManager backed by a GitHub Gist.
35
+ *
36
+ * The regular constructor is synchronous (for backwards-compat), but Gist
37
+ * bootstrapping requires network calls, so this factory is async.
38
+ *
39
+ * @param token - GitHub personal access token with `gist` scope
40
+ */
41
+ static createWithGist(token: string): Promise<StateManager>;
30
42
  /**
31
43
  * Attempt PR count reconciliation, logging a warning on failure.
32
44
  * Called after every state load from disk.
@@ -58,8 +70,17 @@ export declare class StateManager {
58
70
  /**
59
71
  * Persist the current state to disk, creating a timestamped backup of the previous
60
72
  * state file first. In in-memory mode, only updates `lastRunAt` without any file I/O.
73
+ *
74
+ * In Gist mode, writes to a local cache file (not the main state file) so the Gist
75
+ * remains the source of truth. Use `checkpoint()` to push state to the Gist.
61
76
  */
62
77
  save(): void;
78
+ /** Push current state to Gist (async). Call at well-defined moments (end of daily, after claim). */
79
+ checkpoint(): Promise<boolean>;
80
+ /** Whether this StateManager is backed by a Gist. */
81
+ isGistMode(): boolean;
82
+ /** Whether the Gist is in degraded mode (using local cache fallback). */
83
+ isGistDegraded(): boolean;
63
84
  /**
64
85
  * Get the current state as a read-only snapshot.
65
86
  */
@@ -69,6 +90,11 @@ export declare class StateManager {
69
90
  * Returns true if state was reloaded, false if unchanged or in-memory mode.
70
91
  */
71
92
  reloadIfChanged(): boolean;
93
+ /**
94
+ * Re-fetch state from the backing Gist (if in Gist mode).
95
+ * Throttled to once per 30 seconds by GistStateStore. Returns true if state was refreshed.
96
+ */
97
+ refreshFromGist(): Promise<boolean>;
72
98
  /**
73
99
  * Store the latest daily digest and update the digest timestamp.
74
100
  * @param digest - The daily digest to store
@@ -89,11 +115,6 @@ export declare class StateManager {
89
115
  * @param counts - Monthly opened PR counts keyed by YYYY-MM
90
116
  */
91
117
  setMonthlyOpenedCounts(counts: Record<string, number>): void;
92
- /**
93
- * Update daily activity counts for dashboard display.
94
- * @param counts - Daily activity counts keyed by YYYY-MM-DD
95
- */
96
- setDailyActivityCounts(counts: Record<string, number>): void;
97
118
  /**
98
119
  * Update the local repository cache.
99
120
  * @param cache - Local repository cache mapping repo names to paths
@@ -122,26 +143,6 @@ export declare class StateManager {
122
143
  * @param config - Partial config object to merge
123
144
  */
124
145
  updateConfig(config: Partial<AgentState['config']>): void;
125
- /**
126
- * Append a new event to the event log and auto-persist.
127
- * Events are capped at 1000 to prevent unbounded growth.
128
- * @param type - The event type identifier
129
- * @param data - Arbitrary event payload
130
- */
131
- appendEvent(type: StateEventType, data: Record<string, unknown>): void;
132
- /**
133
- * Filter events by type.
134
- * @param type - The event type to filter by
135
- * @returns Events matching the given type
136
- */
137
- getEventsByType(type: StateEventType): StateEvent[];
138
- /**
139
- * Filter events within a date range.
140
- * @param since - Start of range (inclusive)
141
- * @param until - End of range (inclusive), defaults to now
142
- * @returns Events within the date range
143
- */
144
- getEventsInRange(since: Date, until?: Date): StateEvent[];
145
146
  /**
146
147
  * Track a new issue. No-op if the issue URL is already tracked.
147
148
  * @param issue - The issue to track
@@ -287,6 +288,19 @@ export declare class StateManager {
287
288
  * ```
288
289
  */
289
290
  export declare function getStateManager(): StateManager;
291
+ /**
292
+ * Get or create a StateManager with Gist-backed persistence.
293
+ * If a StateManager already exists (from sync init), returns it.
294
+ * If a token is provided and no manager exists, creates one with Gist backing.
295
+ * Falls back to sync initialization if no token is provided.
296
+ *
297
+ * **Important:** This must be called (and awaited) before any command runs for
298
+ * Gist mode to be active. It pre-sets the singleton so that subsequent
299
+ * `getStateManager()` calls return the Gist-backed instance. If this is not
300
+ * called first, `getStateManager()` will lazily create a local-only
301
+ * StateManager and Gist checkpoints will be no-ops.
302
+ */
303
+ export declare function getStateManagerAsync(token?: string): Promise<StateManager>;
290
304
  /**
291
305
  * Reset the singleton StateManager instance to null. Intended for test isolation.
292
306
  */