modjules 0.1.1 → 0.2.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.
Files changed (48) hide show
  1. package/README.md +10 -6
  2. package/dist/activities/client.d.ts +44 -1
  3. package/dist/activities/types.d.ts +7 -0
  4. package/dist/activity/summary.d.ts +7 -0
  5. package/dist/api.d.ts +31 -1
  6. package/dist/artifacts.d.ts +22 -1
  7. package/dist/browser.d.ts +9 -1
  8. package/dist/browser.mjs +304 -0
  9. package/dist/browser.mjs.map +1 -0
  10. package/dist/caching.d.ts +16 -0
  11. package/dist/client.d.ts +53 -1
  12. package/dist/errors.d.ts +7 -0
  13. package/dist/github/adapter.d.ts +2 -0
  14. package/dist/github/api.d.ts +6 -0
  15. package/dist/github/caching.d.ts +2 -0
  16. package/dist/github/errors.d.ts +17 -0
  17. package/dist/github/index.d.ts +3 -0
  18. package/dist/github/pr-client.d.ts +12 -0
  19. package/dist/github/types.d.ts +72 -0
  20. package/dist/index.d.ts +24 -2
  21. package/dist/index.mjs +1438 -0
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/memory-DE2Wujcu.js +2573 -0
  24. package/dist/memory-DE2Wujcu.js.map +1 -0
  25. package/dist/platform/browser.d.ts +13 -1
  26. package/dist/platform/node.d.ts +15 -1
  27. package/dist/platform/types.d.ts +56 -1
  28. package/dist/platform/web.d.ts +29 -0
  29. package/dist/query/computed.d.ts +65 -0
  30. package/dist/query/projection.d.ts +65 -0
  31. package/dist/query/schema.d.ts +109 -0
  32. package/dist/query/select.d.ts +6 -0
  33. package/dist/query/validate.d.ts +59 -0
  34. package/dist/session.d.ts +30 -6
  35. package/dist/sessions.d.ts +65 -0
  36. package/dist/snapshot.d.ts +23 -0
  37. package/dist/storage/cache-info.d.ts +28 -0
  38. package/dist/storage/memory.d.ts +15 -2
  39. package/dist/storage/node-fs.d.ts +19 -3
  40. package/dist/storage/root.d.ts +2 -0
  41. package/dist/storage/types.d.ts +63 -1
  42. package/dist/types.d.ts +422 -11
  43. package/dist/utils/page-token.d.ts +60 -0
  44. package/dist/utils.d.ts +1 -1
  45. package/package.json +14 -44
  46. package/dist/browser.es.js +0 -158
  47. package/dist/client-D2GRjxRE.mjs +0 -927
  48. package/dist/index.es.js +0 -140
@@ -0,0 +1,65 @@
1
+ import { Activity } from '../types.js';
2
+ /**
3
+ * List of computed field names for activities
4
+ */
5
+ export declare const ACTIVITY_COMPUTED_FIELDS: readonly ["artifactCount", "summary"];
6
+ /**
7
+ * List of computed field names for sessions
8
+ */
9
+ export declare const SESSION_COMPUTED_FIELDS: readonly ["durationMs"];
10
+ /**
11
+ * Check if a field name is a computed field for activities
12
+ */
13
+ export declare function isActivityComputedField(field: string): boolean;
14
+ /**
15
+ * Check if a field name is a computed field for sessions
16
+ */
17
+ export declare function isSessionComputedField(field: string): boolean;
18
+ /**
19
+ * Compute the artifactCount for an activity
20
+ */
21
+ export declare function computeArtifactCount(activity: Activity): number;
22
+ /**
23
+ * Compute the summary for an activity
24
+ * Delegates to existing toSummary implementation
25
+ */
26
+ export declare function computeSummary(activity: Activity): string;
27
+ /**
28
+ * Compute the duration in milliseconds for a session
29
+ */
30
+ export declare function computeDurationMs(session: {
31
+ createTime?: string;
32
+ updateTime?: string;
33
+ }): number;
34
+ /**
35
+ * Inject computed fields into an activity based on selected fields
36
+ *
37
+ * @param activity The activity to augment
38
+ * @param selectFields The fields being selected (or undefined for default)
39
+ * @returns Activity with computed fields added
40
+ */
41
+ export declare function injectActivityComputedFields(activity: Activity, selectFields?: string[]): Activity & {
42
+ artifactCount?: number;
43
+ summary?: string;
44
+ };
45
+ /**
46
+ * Inject computed fields into a session based on selected fields
47
+ *
48
+ * @param session The session to augment
49
+ * @param selectFields The fields being selected (or undefined for default)
50
+ * @returns Session with computed fields added
51
+ */
52
+ export declare function injectSessionComputedFields<T extends {
53
+ createTime?: string;
54
+ updateTime?: string;
55
+ }>(session: T, selectFields?: string[]): T & {
56
+ durationMs?: number;
57
+ };
58
+ /**
59
+ * Default projection fields for activities (includes computed fields)
60
+ */
61
+ export declare const DEFAULT_ACTIVITY_PROJECTION: string[];
62
+ /**
63
+ * Default projection fields for sessions
64
+ */
65
+ export declare const DEFAULT_SESSION_PROJECTION: string[];
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Projection Engine for Jules Query Language
3
+ *
4
+ * Supports:
5
+ * - Dot notation field paths: "plan.steps.title"
6
+ * - Wildcard inclusion: "*"
7
+ * - Exclusion prefix: "-artifacts.data"
8
+ * - Implicit array traversal: "artifacts.type" works on arrays
9
+ */
10
+ /**
11
+ * Parsed select expression
12
+ */
13
+ export interface SelectExpression {
14
+ path: string[];
15
+ exclude: boolean;
16
+ wildcard: boolean;
17
+ }
18
+ /**
19
+ * Parse a select expression string into structured form
20
+ *
21
+ * Examples:
22
+ * - "id" → { path: ["id"], exclude: false, wildcard: false }
23
+ * - "plan.steps.title" → { path: ["plan", "steps", "title"], exclude: false, wildcard: false }
24
+ * - "-artifacts.data" → { path: ["artifacts", "data"], exclude: true, wildcard: false }
25
+ * - "*" → { path: [], exclude: false, wildcard: true }
26
+ */
27
+ export declare function parseSelectExpression(expr: string): SelectExpression;
28
+ /**
29
+ * Get a value at a nested path, handling arrays transparently
30
+ *
31
+ * For paths that traverse arrays, returns an array of values from each element.
32
+ *
33
+ * Examples:
34
+ * - getPath({a: {b: 1}}, ["a", "b"]) → 1
35
+ * - getPath({items: [{x: 1}, {x: 2}]}, ["items", "x"]) → [1, 2]
36
+ */
37
+ export declare function getPath(obj: unknown, path: string[]): unknown;
38
+ /**
39
+ * Set a value at a nested path, creating intermediate objects as needed
40
+ *
41
+ * For array paths, preserves array structure.
42
+ */
43
+ export declare function setPath(obj: Record<string, unknown>, path: string[], value: unknown): void;
44
+ /**
45
+ * Delete a value at a nested path
46
+ *
47
+ * For paths ending in array elements, removes the field from each element.
48
+ */
49
+ export declare function deletePath(obj: unknown, path: string[]): void;
50
+ /**
51
+ * Deep clone an object
52
+ */
53
+ export declare function deepClone<T>(obj: T): T;
54
+ /**
55
+ * Project a document according to select expressions
56
+ *
57
+ * @param doc The source document
58
+ * @param selects Array of select expression strings
59
+ * @returns Projected document with only selected fields
60
+ */
61
+ export declare function projectDocument(doc: Record<string, unknown>, selects: string[]): Record<string, unknown>;
62
+ /**
63
+ * Check if a path is a prefix of another path
64
+ */
65
+ export declare function isPathPrefix(prefix: string[], path: string[]): boolean;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Schema Introspection for Jules Query Language
3
+ *
4
+ * Provides TypeScript type definitions and field metadata for LLM discoverability.
5
+ * These schemas help LLMs understand the shape of Session, Activity, and related types
6
+ * to translate natural language queries into proper JQL.
7
+ */
8
+ /**
9
+ * Field metadata for schema introspection
10
+ */
11
+ export interface FieldMeta {
12
+ /** Field name */
13
+ name: string;
14
+ /** TypeScript type representation */
15
+ type: string;
16
+ /** Human-readable description */
17
+ description: string;
18
+ /** Whether field is optional */
19
+ optional?: boolean;
20
+ /** Whether field is computed (not stored, derived at query time) */
21
+ computed?: boolean;
22
+ /** Whether field can be filtered in where clause */
23
+ filterable?: boolean;
24
+ /** Whether field can be used in select projection */
25
+ selectable?: boolean;
26
+ /** Nested fields if this is an object or array type */
27
+ fields?: FieldMeta[];
28
+ }
29
+ /**
30
+ * Schema definition for a domain
31
+ */
32
+ export interface DomainSchema {
33
+ /** Domain name */
34
+ domain: 'sessions' | 'activities';
35
+ /** Human-readable description */
36
+ description: string;
37
+ /** All fields in this domain */
38
+ fields: FieldMeta[];
39
+ /** Example queries for this domain */
40
+ examples: QueryExample[];
41
+ }
42
+ /**
43
+ * Example query for documentation
44
+ */
45
+ export interface QueryExample {
46
+ /** Natural language description */
47
+ description: string;
48
+ /** JQL query */
49
+ query: Record<string, unknown>;
50
+ }
51
+ /**
52
+ * Schema for SessionResource
53
+ */
54
+ export declare const SESSION_SCHEMA: DomainSchema;
55
+ /**
56
+ * Schema for Activity types
57
+ */
58
+ export declare const ACTIVITY_SCHEMA: DomainSchema;
59
+ /**
60
+ * FilterOp schema for where clause operators
61
+ */
62
+ export declare const FILTER_OP_SCHEMA: {
63
+ description: string;
64
+ operators: {
65
+ name: string;
66
+ description: string;
67
+ example: string;
68
+ }[];
69
+ dotNotation: {
70
+ description: string;
71
+ examples: string[];
72
+ };
73
+ };
74
+ /**
75
+ * Projection schema for select clause
76
+ */
77
+ export declare const PROJECTION_SCHEMA: {
78
+ description: string;
79
+ syntax: {
80
+ name: string;
81
+ description: string;
82
+ example: string;
83
+ }[];
84
+ defaults: {
85
+ sessions: string[];
86
+ activities: string[];
87
+ };
88
+ };
89
+ /**
90
+ * Get the full schema for a domain
91
+ */
92
+ export declare function getSchema(domain: 'sessions' | 'activities'): DomainSchema;
93
+ /**
94
+ * Get all schemas with filter and projection documentation
95
+ */
96
+ export declare function getAllSchemas(): {
97
+ sessions: DomainSchema;
98
+ activities: DomainSchema;
99
+ filterOps: typeof FILTER_OP_SCHEMA;
100
+ projection: typeof PROJECTION_SCHEMA;
101
+ };
102
+ /**
103
+ * Generate TypeScript type definition string for a domain
104
+ */
105
+ export declare function generateTypeDefinition(domain: 'sessions' | 'activities'): string;
106
+ /**
107
+ * Generate markdown documentation for LLM consumption
108
+ */
109
+ export declare function generateMarkdownDocs(): string;
@@ -0,0 +1,6 @@
1
+ import { JulesClient, JulesQuery, JulesDomain, QueryResult } from '../types.js';
2
+ /**
3
+ * Standalone query engine function.
4
+ * Handles planning, index scanning, and hydration.
5
+ */
6
+ export declare function select<T extends JulesDomain>(client: JulesClient, query: JulesQuery<T>): Promise<QueryResult<T>[]>;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Query Validator for Jules Query Language
3
+ *
4
+ * Validates queries before execution, providing actionable error messages
5
+ * for LLMs to self-correct their queries.
6
+ */
7
+ export interface ValidationError {
8
+ /** Error code for programmatic handling */
9
+ code: ValidationErrorCode;
10
+ /** JSON path to the error location (e.g., "where.artifacts.type") */
11
+ path: string;
12
+ /** Human-readable error message */
13
+ message: string;
14
+ /** Suggested fix or valid alternatives */
15
+ suggestion?: string;
16
+ }
17
+ export interface ValidationWarning {
18
+ /** Warning code */
19
+ code: string;
20
+ /** JSON path to the warning location */
21
+ path: string;
22
+ /** Human-readable warning message */
23
+ message: string;
24
+ }
25
+ export interface ValidationResult {
26
+ /** Whether the query is valid */
27
+ valid: boolean;
28
+ /** Validation errors (if any) */
29
+ errors: ValidationError[];
30
+ /** Validation warnings (non-blocking issues) */
31
+ warnings: ValidationWarning[];
32
+ /** Auto-corrected query (if corrections were possible) */
33
+ correctedQuery?: Record<string, unknown>;
34
+ }
35
+ export type ValidationErrorCode = 'INVALID_STRUCTURE' | 'MISSING_REQUIRED_FIELD' | 'INVALID_DOMAIN' | 'INVALID_FIELD_PATH' | 'INVALID_OPERATOR' | 'INVALID_OPERATOR_VALUE' | 'COMPUTED_FIELD_FILTER' | 'INVALID_ORDER' | 'INVALID_LIMIT' | 'INVALID_SELECT_EXPRESSION';
36
+ /**
37
+ * Validate a Jules Query Language query
38
+ *
39
+ * @param query - The query object to validate
40
+ * @returns Validation result with errors, warnings, and optional corrections
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const result = validateQuery({
45
+ * from: 'activities',
46
+ * where: { type: 'agentMessaged' },
47
+ * select: ['id', 'message']
48
+ * });
49
+ *
50
+ * if (!result.valid) {
51
+ * console.log('Errors:', result.errors);
52
+ * }
53
+ * ```
54
+ */
55
+ export declare function validateQuery(query: unknown): ValidationResult;
56
+ /**
57
+ * Format validation result as a human-readable string
58
+ */
59
+ export declare function formatValidationResult(result: ValidationResult): string;
package/dist/session.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { SelectOptions } from './activities/types.js';
1
+ import { ActivityClient, SelectOptions } from './activities/types.js';
2
2
  import { ApiClient } from './api.js';
3
3
  import { InternalConfig } from './client.js';
4
- import { ActivityStorage } from './storage/types.js';
4
+ import { ActivityStorage, SessionStorage } from './storage/types.js';
5
5
  import { StreamActivitiesOptions } from './streaming.js';
6
- import { Activity, ActivityAgentMessaged, Outcome, SessionClient, SessionResource, SessionState } from './types.js';
6
+ import { Activity, ActivityAgentMessaged, Outcome, SessionClient, SessionResource, SessionState, SessionSnapshot } from './types.js';
7
7
  /**
8
8
  * Implementation of the SessionClient interface.
9
9
  * Manages an interactive session with the Jules agent.
@@ -12,6 +12,7 @@ export declare class SessionClientImpl implements SessionClient {
12
12
  readonly id: string;
13
13
  private apiClient;
14
14
  private config;
15
+ private sessionStorage;
15
16
  private _activities;
16
17
  /**
17
18
  * Creates a new instance of SessionClientImpl.
@@ -19,22 +20,37 @@ export declare class SessionClientImpl implements SessionClient {
19
20
  * @param sessionId The ID of the session.
20
21
  * @param apiClient The API client to use for network requests.
21
22
  * @param config The configuration options.
22
- * @param storage The storage engine for activities.
23
+ * @param activityStorage The storage engine for activities.
24
+ * @param sessionStorage The storage engine for sessions.
23
25
  * @param platform The platform adapter.
24
26
  */
25
- constructor(sessionId: string, apiClient: ApiClient, config: InternalConfig, storage: ActivityStorage, platform: any);
27
+ constructor(sessionId: string, apiClient: ApiClient, config: InternalConfig, activityStorage: ActivityStorage, sessionStorage: SessionStorage, // Injected dependency
28
+ platform: any);
29
+ private request;
26
30
  /**
27
31
  * COLD STREAM: Yields all known past activities from local storage.
32
+ * If local cache is empty, fetches from network first.
28
33
  */
29
34
  history(): AsyncIterable<Activity>;
35
+ /**
36
+ * Forces a full sync of activities from the network to local cache.
37
+ * @returns The number of new activities synced.
38
+ */
39
+ hydrate(): Promise<number>;
30
40
  /**
31
41
  * HOT STREAM: Yields ONLY future activities as they arrive from the network.
32
42
  */
33
43
  updates(): AsyncIterable<Activity>;
34
44
  /**
35
45
  * LOCAL QUERY: Performs rich filtering against local storage only.
46
+ *
47
+ * @deprecated Use `session.activities.select()` instead.
36
48
  */
37
49
  select(options?: SelectOptions): Promise<Activity[]>;
50
+ /**
51
+ * Scoped access to activity-specific operations.
52
+ */
53
+ get activities(): ActivityClient;
38
54
  /**
39
55
  * Provides a real-time stream of activities for the session.
40
56
  *
@@ -115,7 +131,15 @@ export declare class SessionClientImpl implements SessionClient {
115
131
  */
116
132
  waitFor(targetState: SessionState): Promise<void>;
117
133
  /**
118
- * Retrieves the latest state of the underlying session resource from the API.
134
+ * Retrieves the latest state of the underlying session resource.
135
+ * Implements "Iceberg" Read-Through caching.
119
136
  */
120
137
  info(): Promise<SessionResource>;
138
+ /**
139
+ * Creates a point-in-time snapshot of the session.
140
+ * This is a network operation that fetches the latest session info and all activities.
141
+ *
142
+ * @returns A `SessionSnapshot` instance.
143
+ */
144
+ snapshot(): Promise<SessionSnapshot>;
121
145
  }
@@ -0,0 +1,65 @@
1
+ import { ApiClient } from './api.js';
2
+ import { SessionResource } from './types.js';
3
+ import { SessionStorage } from './storage/types.js';
4
+ export type ListSessionsOptions = {
5
+ pageSize?: number;
6
+ pageToken?: string;
7
+ /**
8
+ * Hard limit on the number of items to yield when iterating.
9
+ * Useful if you want "The last 50" without manual counting.
10
+ */
11
+ limit?: number;
12
+ /**
13
+ * Whether to persist fetched sessions to local storage.
14
+ * Defaults to `true` (Write-Through Caching).
15
+ * Set to `false` to disable side effects.
16
+ */
17
+ persist?: boolean;
18
+ };
19
+ export type ListSessionsResponse = {
20
+ sessions: SessionResource[];
21
+ nextPageToken?: string;
22
+ };
23
+ /**
24
+ * The SessionCursor handles the complexity of pagination state.
25
+ * It is "Thenable" (acts like a Promise) and "AsyncIterable".
26
+ *
27
+ * This allows two usage patterns:
28
+ * 1. `await jules.sessions()` - Get the first page (Promise behavior).
29
+ * 2. `for await (const session of jules.sessions())` - Stream all sessions (AsyncIterable behavior).
30
+ *
31
+ * **Design Notes:**
32
+ * - **Pagination:** Handles `nextPageToken` automatically during iteration. For manual control,
33
+ * access the `nextPageToken` property on the promised response.
34
+ * - **Limiting:** The `limit` option hard-stops the iteration after N items, preventing over-fetching.
35
+ * - **Write-Through Caching:** Fetched sessions are automatically persisted to local storage
36
+ * using `storage.upsertMany()`. This ensures the local graph is populated during listing.
37
+ * - **Platform:** Fully platform-agnostic (Node.js/Browser/GAS) via the injected `ApiClient`.
38
+ */
39
+ export declare class SessionCursor implements PromiseLike<ListSessionsResponse>, AsyncIterable<SessionResource> {
40
+ private apiClient;
41
+ private storage;
42
+ private options;
43
+ constructor(apiClient: ApiClient, storage: SessionStorage, options?: ListSessionsOptions);
44
+ /**
45
+ * DX Feature: Promise Compatibility.
46
+ * Allows `const page = await jules.sessions()` to just get the first page.
47
+ * This is great for UIs that render a list and a "Load More" button.
48
+ */
49
+ then<TResult1 = ListSessionsResponse, TResult2 = never>(onfulfilled?: ((value: ListSessionsResponse) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
50
+ /**
51
+ * DX Feature: Async Iterator.
52
+ * Allows `for await (const s of jules.sessions())` to stream ALL items.
53
+ * Automatically handles page tokens and fetching behind the scenes.
54
+ */
55
+ [Symbol.asyncIterator](): AsyncIterator<SessionResource>;
56
+ /**
57
+ * Helper to fetch all pages into a single array.
58
+ * WARNING: Use with caution on large datasets.
59
+ */
60
+ all(): Promise<SessionResource[]>;
61
+ /**
62
+ * Internal fetcher that maps the options to the REST parameters.
63
+ */
64
+ private fetchPage;
65
+ }
@@ -0,0 +1,23 @@
1
+ import { Activity, PullRequest, SessionInsights, SessionResource, SessionSnapshot, SessionState, SerializedSnapshot, TimelineEntry } from './types.js';
2
+ export declare class SessionSnapshotImpl implements SessionSnapshot {
3
+ readonly id: string;
4
+ readonly state: SessionState;
5
+ readonly url: string;
6
+ readonly createdAt: Date;
7
+ readonly updatedAt: Date;
8
+ readonly durationMs: number;
9
+ readonly prompt: string;
10
+ readonly title: string;
11
+ readonly pr?: PullRequest;
12
+ readonly activities: readonly Activity[];
13
+ readonly activityCounts: Readonly<Record<string, number>>;
14
+ readonly timeline: readonly TimelineEntry[];
15
+ readonly insights: SessionInsights;
16
+ constructor(session: SessionResource, activities: Activity[]);
17
+ private computeActivityCounts;
18
+ private computeTimeline;
19
+ private generateSummary;
20
+ private computeInsights;
21
+ toJSON(): SerializedSnapshot;
22
+ toMarkdown(): string;
23
+ }
@@ -0,0 +1,28 @@
1
+ import { Activity } from '../types.js';
2
+ /**
3
+ * Represents the cache information for a single session.
4
+ */
5
+ export type SessionCacheInfo = {
6
+ sessionId: string;
7
+ activityCount: number;
8
+ lastSyncedAt: Date;
9
+ };
10
+ /**
11
+ * Represents global cache information.
12
+ */
13
+ export type GlobalCacheInfo = {
14
+ lastSyncedAt: Date;
15
+ sessionCount: number;
16
+ };
17
+ /**
18
+ * Retrieves cache information for a specific session.
19
+ *
20
+ * @param sessionId - The ID of the session.
21
+ * @returns A promise that resolves with the session's cache information, or null if not found.
22
+ */
23
+ export declare function getSessionCacheInfo(sessionId: string, rootDirOverride?: string): Promise<SessionCacheInfo | null>;
24
+ export declare function updateGlobalCacheMetadata(rootDirOverride?: string): Promise<void>;
25
+ export declare function getCacheInfo(rootDirOverride?: string): Promise<GlobalCacheInfo>;
26
+ export declare function getSessionCount(rootDirOverride?: string): Promise<number>;
27
+ export declare function getActivityCount(sessionId: string, rootDirOverride?: string): Promise<number>;
28
+ export declare function getLatestActivities(sessionId: string, n: number, rootDirOverride?: string): Promise<Activity[]>;
@@ -1,5 +1,5 @@
1
- import { Activity } from '../types.js';
2
- import { ActivityStorage } from './types.js';
1
+ import { Activity, SessionResource } from '../types.js';
2
+ import { ActivityStorage, SessionStorage, CachedSession, SessionIndexEntry } from './types.js';
3
3
  /**
4
4
  * In-memory implementation of ActivityStorage.
5
5
  * Useful for testing or environments where persistence is not required.
@@ -38,3 +38,16 @@ export declare class MemoryStorage implements ActivityStorage {
38
38
  */
39
39
  scan(): AsyncIterable<Activity>;
40
40
  }
41
+ /**
42
+ * In-memory implementation of SessionStorage.
43
+ */
44
+ export declare class MemorySessionStorage implements SessionStorage {
45
+ private sessions;
46
+ private index;
47
+ init(): Promise<void>;
48
+ upsert(session: SessionResource): Promise<void>;
49
+ upsertMany(sessions: SessionResource[]): Promise<void>;
50
+ get(sessionId: string): Promise<CachedSession | undefined>;
51
+ delete(sessionId: string): Promise<void>;
52
+ scanIndex(): AsyncIterable<SessionIndexEntry>;
53
+ }
@@ -1,13 +1,14 @@
1
- import { Activity } from '../types.js';
2
- import { ActivityStorage } from './types.js';
1
+ import { Activity, SessionResource } from '../types.js';
2
+ import { ActivityStorage, SessionStorage, CachedSession, SessionIndexEntry } from './types.js';
3
3
  /**
4
4
  * Node.js filesystem implementation of ActivityStorage.
5
5
  * Stores activities in a JSONL file located at `.jules/cache/<sessionId>/activities.jsonl`.
6
6
  */
7
7
  export declare class NodeFileStorage implements ActivityStorage {
8
8
  private filePath;
9
+ private metadataPath;
9
10
  private initialized;
10
- constructor(sessionId: string, rootDir?: string);
11
+ constructor(sessionId: string, rootDir: string);
11
12
  /**
12
13
  * Initializes the storage by ensuring the cache directory exists.
13
14
  *
@@ -20,6 +21,8 @@ export declare class NodeFileStorage implements ActivityStorage {
20
21
  * Closes the storage.
21
22
  */
22
23
  close(): Promise<void>;
24
+ private _readMetadata;
25
+ private _writeMetadata;
23
26
  /**
24
27
  * Appends an activity to the file.
25
28
  *
@@ -52,3 +55,16 @@ export declare class NodeFileStorage implements ActivityStorage {
52
55
  */
53
56
  scan(): AsyncIterable<Activity>;
54
57
  }
58
+ export declare class NodeSessionStorage implements SessionStorage {
59
+ private cacheDir;
60
+ private indexFilePath;
61
+ private initialized;
62
+ constructor(rootDir: string);
63
+ init(): Promise<void>;
64
+ private getSessionPath;
65
+ upsert(session: SessionResource): Promise<void>;
66
+ upsertMany(sessions: SessionResource[]): Promise<void>;
67
+ get(sessionId: string): Promise<CachedSession | undefined>;
68
+ delete(sessionId: string): Promise<void>;
69
+ scanIndex(): AsyncIterable<SessionIndexEntry>;
70
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isWritable(dir: string): boolean;
2
+ export declare function getRootDir(): string;
@@ -1,4 +1,62 @@
1
- import { Activity } from '../types.js';
1
+ import { Activity, SessionResource } from '../types.js';
2
+ /**
3
+ * Represents the wrapper around the raw resource, adding local metadata.
4
+ */
5
+ export type CachedSession = {
6
+ resource: SessionResource;
7
+ _lastSyncedAt: number;
8
+ };
9
+ /**
10
+ * Subset of session fields required for the high-speed index.
11
+ * These are the fields we can filter on without opening the heavy session file.
12
+ */
13
+ export type SessionIndexEntry = {
14
+ id: string;
15
+ title: string;
16
+ state: string;
17
+ createTime: string;
18
+ source: string;
19
+ _updatedAt: number;
20
+ };
21
+ /**
22
+ * Ephemeral (but persisted) metadata about a session's cache state.
23
+ * Stored separately from the main session.json to allow for frequent updates
24
+ * without rewriting the larger session object.
25
+ */
26
+ export type SessionMetadata = {
27
+ activityCount: number;
28
+ };
29
+ export interface SessionStorage {
30
+ /**
31
+ * Initializes the storage (ensure directories exist).
32
+ */
33
+ init(): Promise<void>;
34
+ /**
35
+ * Persists a session state.
36
+ * 1. Writes the full resource to atomic storage (.jules/cache/<id>/session.json).
37
+ * 2. Appends metadata to the high-speed index (.jules/cache/sessions.jsonl).
38
+ */
39
+ upsert(session: SessionResource): Promise<void>;
40
+ /**
41
+ * Bulk optimization for upserting pages from the API.
42
+ */
43
+ upsertMany(sessions: SessionResource[]): Promise<void>;
44
+ /**
45
+ * Retrieves a specific session by ID.
46
+ * Returns undefined if not found or if the file is corrupt.
47
+ */
48
+ get(sessionId: string): Promise<CachedSession | undefined>;
49
+ /**
50
+ * Deletes a session and its associated artifacts from local cache.
51
+ */
52
+ delete(sessionId: string): Promise<void>;
53
+ /**
54
+ * Scans the high-speed index.
55
+ * Implementation MUST handle deduplication (Last-Write-Wins) because the
56
+ * index is an append-only log.
57
+ */
58
+ scanIndex(): AsyncIterable<SessionIndexEntry>;
59
+ }
2
60
  /**
3
61
  * Abstract interface for the isomorphic storage layer.
4
62
  * Implementations handle the specifics of persisting immutable activities
@@ -36,3 +94,7 @@ export interface ActivityStorage {
36
94
  */
37
95
  scan(): AsyncIterable<Activity>;
38
96
  }
97
+ export interface GlobalCacheMetadata {
98
+ lastSyncedAt: number;
99
+ sessionCount: number;
100
+ }