@google/jules-merge 0.0.1

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 (67) hide show
  1. package/README.md +201 -0
  2. package/dist/cli/check-conflicts.command.mjs +387 -0
  3. package/dist/cli/index.mjs +28 -0
  4. package/dist/cli/init.command.mjs +159 -0
  5. package/dist/core/src/activities/client.d.ts +131 -0
  6. package/dist/core/src/activities/summary.d.ts +22 -0
  7. package/dist/core/src/activities/types.d.ts +79 -0
  8. package/dist/core/src/api.d.ts +49 -0
  9. package/dist/core/src/artifacts.d.ts +105 -0
  10. package/dist/core/src/caching.d.ts +31 -0
  11. package/dist/core/src/client.d.ts +180 -0
  12. package/dist/core/src/errors.d.ts +97 -0
  13. package/dist/core/src/index.d.ts +49 -0
  14. package/dist/core/src/mappers.d.ts +53 -0
  15. package/dist/core/src/network/adapter.d.ts +47 -0
  16. package/dist/core/src/platform/node.d.ts +45 -0
  17. package/dist/core/src/platform/types.d.ts +88 -0
  18. package/dist/core/src/polling.d.ts +43 -0
  19. package/dist/core/src/query/computed.d.ts +86 -0
  20. package/dist/core/src/query/projection.d.ts +80 -0
  21. package/dist/core/src/query/schema.d.ts +124 -0
  22. package/dist/core/src/query/select.d.ts +21 -0
  23. package/dist/core/src/query/validate.d.ts +68 -0
  24. package/dist/core/src/session.d.ts +195 -0
  25. package/dist/core/src/sessions.d.ts +87 -0
  26. package/dist/core/src/snapshot.d.ts +46 -0
  27. package/dist/core/src/sources.d.ts +23 -0
  28. package/dist/core/src/storage/cache-info.d.ts +43 -0
  29. package/dist/core/src/storage/memory.d.ts +69 -0
  30. package/dist/core/src/storage/node-fs.d.ts +95 -0
  31. package/dist/core/src/storage/root.d.ts +17 -0
  32. package/dist/core/src/storage/types.d.ts +115 -0
  33. package/dist/core/src/streaming.d.ts +47 -0
  34. package/dist/core/src/types.d.ts +1418 -0
  35. package/dist/core/src/utils/page-token.d.ts +55 -0
  36. package/dist/core/src/utils.d.ts +27 -0
  37. package/dist/index.mjs +395 -0
  38. package/dist/merge/src/__tests__/conflicts/git-handler.test.d.ts +1 -0
  39. package/dist/merge/src/__tests__/conflicts/git-spec.test.d.ts +1 -0
  40. package/dist/merge/src/__tests__/conflicts/session-handler.test.d.ts +1 -0
  41. package/dist/merge/src/__tests__/conflicts/session-spec.test.d.ts +1 -0
  42. package/dist/merge/src/__tests__/init/init-handler.test.d.ts +1 -0
  43. package/dist/merge/src/__tests__/init/init-spec.test.d.ts +1 -0
  44. package/dist/merge/src/__tests__/init/templates.test.d.ts +1 -0
  45. package/dist/merge/src/__tests__/shared/git.test.d.ts +1 -0
  46. package/dist/merge/src/__tests__/shared/github.test.d.ts +1 -0
  47. package/dist/merge/src/__tests__/shared/session.test.d.ts +1 -0
  48. package/dist/merge/src/cli/check-conflicts.command.d.ts +24 -0
  49. package/dist/merge/src/cli/index.d.ts +2 -0
  50. package/dist/merge/src/cli/init.command.d.ts +23 -0
  51. package/dist/merge/src/conflicts/git-handler.d.ts +4 -0
  52. package/dist/merge/src/conflicts/git-spec.d.ts +43 -0
  53. package/dist/merge/src/conflicts/index.d.ts +4 -0
  54. package/dist/merge/src/conflicts/session-handler.d.ts +9 -0
  55. package/dist/merge/src/conflicts/session-spec.d.ts +43 -0
  56. package/dist/merge/src/index.d.ts +5 -0
  57. package/dist/merge/src/init/index.d.ts +4 -0
  58. package/dist/merge/src/init/init-handler.d.ts +4 -0
  59. package/dist/merge/src/init/init-spec.d.ts +41 -0
  60. package/dist/merge/src/init/templates.d.ts +10 -0
  61. package/dist/merge/src/mcp/index.d.ts +1 -0
  62. package/dist/merge/src/mcp/server.d.ts +2 -0
  63. package/dist/merge/src/shared/git.d.ts +17 -0
  64. package/dist/merge/src/shared/github.d.ts +18 -0
  65. package/dist/merge/src/shared/result.d.ts +19 -0
  66. package/dist/merge/src/shared/session.d.ts +16 -0
  67. package/package.json +60 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Utilities for constructing and parsing Jules API pageTokens.
18
+ *
19
+ * The Jules API uses nanosecond timestamps as pageTokens for activity pagination.
20
+ * This allows us to construct tokens from cached activity createTimes,
21
+ * enabling efficient incremental syncing without re-downloading existing activities.
22
+ *
23
+ * @module
24
+ */
25
+ /**
26
+ * Converts a Jules API pageToken back to a Date.
27
+ * Useful for debugging and logging.
28
+ *
29
+ * @param token - The pageToken string (nanosecond timestamp)
30
+ * @returns The corresponding Date object
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const date = pageTokenToDate("1704448500999999000");
35
+ * // Returns Date for 2024-01-05T10:05:00.999Z
36
+ * ```
37
+ */
38
+ export declare function pageTokenToDate(token: string): Date;
39
+ /**
40
+ * Checks if a session's activities are "frozen" (no new activities possible).
41
+ * A session is considered frozen if its last activity is older than the threshold.
42
+ *
43
+ * @param lastActivityCreateTime - The createTime of the most recent activity
44
+ * @param thresholdDays - Number of days after which a session is frozen (default: 30)
45
+ * @returns true if the session is frozen and no API call is needed
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * const isFrozen = isSessionFrozen("2024-01-05T10:05:00Z");
50
+ * if (isFrozen) {
51
+ * // Skip API call - no new activities will ever appear
52
+ * }
53
+ * ```
54
+ */
55
+ export declare function isSessionFrozen(lastActivityCreateTime: string, thresholdDays?: number): boolean;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * The internal engine for jules.all()
18
+ *
19
+ * @param items - Data to process
20
+ * @param mapper - Async function (item) => result
21
+ * @param options - Configuration options
22
+ */
23
+ export declare function pMap<T, R>(items: T[], mapper: (item: T, index: number) => Promise<R>, options?: {
24
+ concurrency?: number;
25
+ stopOnError?: boolean;
26
+ delayMs?: number;
27
+ }): Promise<R[]>;
package/dist/index.mjs ADDED
@@ -0,0 +1,395 @@
1
+ // src/conflicts/session-spec.ts
2
+ import { z } from "zod";
3
+ var SessionCheckInputSchema = z.object({
4
+ sessionId: z.string().min(1, "Session ID is required"),
5
+ repo: z.string().min(1).refine((s) => s.includes("/"), "Must be in owner/repo format"),
6
+ base: z.string().default("main")
7
+ });
8
+ var SessionCheckErrorCode = z.enum([
9
+ "SESSION_QUERY_FAILED",
10
+ "GITHUB_API_ERROR",
11
+ "RATE_LIMIT_EXCEEDED",
12
+ "UNKNOWN_ERROR"
13
+ ]);
14
+ // src/shared/result.ts
15
+ function ok(data) {
16
+ return { success: true, data };
17
+ }
18
+ function fail(code, message, recoverable = false, suggestion) {
19
+ return { success: false, error: { code, message, recoverable, suggestion } };
20
+ }
21
+
22
+ // src/shared/session.ts
23
+ import { jules } from "@google/jules-sdk";
24
+ async function getSessionChangedFiles(client, sessionId) {
25
+ const session = client.session(sessionId);
26
+ await session.activities.hydrate();
27
+ const snapshot = await session.snapshot();
28
+ const isBusy = isBusyState(snapshot.state);
29
+ if (isBusy) {
30
+ return aggregateFromActivities(snapshot.activities ?? []);
31
+ }
32
+ const changeSet = typeof snapshot.changeSet === "function" ? snapshot.changeSet() : undefined;
33
+ if (!changeSet)
34
+ return [];
35
+ const parsed = changeSet.parsed();
36
+ return parsed.files.map((f) => ({
37
+ path: f.path,
38
+ changeType: f.changeType
39
+ }));
40
+ }
41
+ function isBusyState(state) {
42
+ const busy = new Set([
43
+ "queued",
44
+ "planning",
45
+ "inProgress",
46
+ "in_progress"
47
+ ]);
48
+ return busy.has(state);
49
+ }
50
+ function aggregateFromActivities(activities) {
51
+ const fileMap = new Map;
52
+ for (const activity of activities) {
53
+ for (const artifact of activity.artifacts) {
54
+ if (artifact.type === "changeSet") {
55
+ const parsed = artifact.parsed();
56
+ for (const file of parsed.files) {
57
+ const existing = fileMap.get(file.path);
58
+ if (existing) {
59
+ existing.latestChangeType = file.changeType;
60
+ } else {
61
+ fileMap.set(file.path, {
62
+ firstChangeType: file.changeType,
63
+ latestChangeType: file.changeType
64
+ });
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ const result = [];
71
+ for (const [path, info] of fileMap) {
72
+ if (info.firstChangeType === "created" && info.latestChangeType === "deleted") {
73
+ continue;
74
+ }
75
+ const netType = info.firstChangeType === "created" ? "created" : info.latestChangeType;
76
+ result.push({ path, changeType: netType });
77
+ }
78
+ return result;
79
+ }
80
+
81
+ // src/shared/github.ts
82
+ import { Octokit } from "@octokit/rest";
83
+ import { createAppAuth } from "@octokit/auth-app";
84
+ async function compareCommits(octokit, owner, repo, base, head) {
85
+ const { data } = await octokit.repos.compareCommits({
86
+ owner,
87
+ repo,
88
+ base,
89
+ head
90
+ });
91
+ return (data.files ?? []).map((f) => f.filename);
92
+ }
93
+ async function getFileContent(octokit, owner, repo, path, ref) {
94
+ try {
95
+ const { data } = await octokit.repos.getContent({
96
+ owner,
97
+ repo,
98
+ path,
99
+ ref
100
+ });
101
+ if ("content" in data && typeof data.content === "string") {
102
+ return Buffer.from(data.content, "base64").toString("utf-8");
103
+ }
104
+ return "";
105
+ } catch (error) {
106
+ if (error?.status === 404) {
107
+ return "";
108
+ }
109
+ throw error;
110
+ }
111
+ }
112
+
113
+ // src/conflicts/session-handler.ts
114
+ class SessionCheckHandler {
115
+ octokit;
116
+ julesClient;
117
+ constructor(octokit, julesClient) {
118
+ this.octokit = octokit;
119
+ this.julesClient = julesClient;
120
+ }
121
+ async execute(input) {
122
+ try {
123
+ const [owner, repo] = input.repo.split("/");
124
+ let sessionPaths;
125
+ try {
126
+ const sessionFiles = await getSessionChangedFiles(this.julesClient, input.sessionId);
127
+ sessionPaths = sessionFiles.map((f) => f.path);
128
+ } catch (error) {
129
+ return fail("SESSION_QUERY_FAILED", `Failed to query session ${input.sessionId}: ${error.message}`, true, "Verify the session ID is correct and JULES_API_KEY is set.");
130
+ }
131
+ let remoteFiles;
132
+ try {
133
+ remoteFiles = await compareCommits(this.octokit, owner, repo, input.base, "HEAD");
134
+ } catch (error) {
135
+ return fail("GITHUB_API_ERROR", `Failed to compare commits: ${error.message}`, true, "Check GITHUB_TOKEN and repository access.");
136
+ }
137
+ const remoteSet = new Set(remoteFiles);
138
+ const overlapping = sessionPaths.filter((f) => remoteSet.has(f));
139
+ if (overlapping.length === 0) {
140
+ return ok({
141
+ status: "clean",
142
+ message: "No conflicts detected.",
143
+ conflicts: []
144
+ });
145
+ }
146
+ const conflicts = await Promise.all(overlapping.map(async (filePath) => {
147
+ const remoteShadowContent = await getFileContent(this.octokit, owner, repo, filePath, input.base);
148
+ return {
149
+ filePath,
150
+ conflictReason: "Remote commit modified this file since branch creation.",
151
+ remoteShadowContent
152
+ };
153
+ }));
154
+ return ok({
155
+ status: "conflict",
156
+ message: `The remote ${input.base} branch has advanced. Rebase required for ${overlapping.join(", ")}.`,
157
+ conflicts
158
+ });
159
+ } catch (error) {
160
+ return fail("UNKNOWN_ERROR", error instanceof Error ? error.message : String(error), false);
161
+ }
162
+ }
163
+ }
164
+ // src/conflicts/git-spec.ts
165
+ import { z as z2 } from "zod";
166
+ var GitCheckInputSchema = z2.object({
167
+ repo: z2.string().min(1).refine((s) => s.includes("/"), "Must be in owner/repo format"),
168
+ pullRequestNumber: z2.number().int().positive(),
169
+ failingCommitSha: z2.string().min(1)
170
+ });
171
+ var GitCheckErrorCode = z2.enum([
172
+ "NO_UNMERGED_FILES",
173
+ "GIT_STATUS_FAILED",
174
+ "FILE_READ_FAILED",
175
+ "UNKNOWN_ERROR"
176
+ ]);
177
+ // src/conflicts/git-handler.ts
178
+ import { readFile } from "node:fs/promises";
179
+
180
+ // src/shared/git.ts
181
+ import { execFile } from "node:child_process";
182
+ import { promisify } from "node:util";
183
+ var execFileAsync = promisify(execFile);
184
+ async function gitStatusUnmerged(cwd) {
185
+ try {
186
+ const { stdout } = await execFileAsync("git", ["status", "--porcelain"], { cwd });
187
+ const files = stdout.split(`
188
+ `).filter((line) => line.startsWith("UU ")).map((line) => line.slice(3).trim());
189
+ return { ok: true, data: files };
190
+ } catch (error) {
191
+ return {
192
+ ok: false,
193
+ error: error instanceof Error ? error.message : String(error)
194
+ };
195
+ }
196
+ }
197
+ async function gitMergeBase(head, base, cwd) {
198
+ try {
199
+ const { stdout } = await execFileAsync("git", ["merge-base", head, base], { cwd });
200
+ return { ok: true, data: stdout.trim() };
201
+ } catch (error) {
202
+ return {
203
+ ok: false,
204
+ error: error instanceof Error ? error.message : String(error)
205
+ };
206
+ }
207
+ }
208
+
209
+ // src/conflicts/git-handler.ts
210
+ class GitCheckHandler {
211
+ async execute(input) {
212
+ try {
213
+ const statusResult = await gitStatusUnmerged();
214
+ if (!statusResult.ok) {
215
+ return fail("GIT_STATUS_FAILED", `Failed to get git status: ${statusResult.error}`, true, "Ensure git is available and the working directory is a repository.");
216
+ }
217
+ const unmergedFiles = statusResult.data;
218
+ if (unmergedFiles.length === 0) {
219
+ return fail("NO_UNMERGED_FILES", "No unmerged files found. The merge conflict may have already been resolved.", false);
220
+ }
221
+ const affectedFiles = await Promise.all(unmergedFiles.map(async (filePath) => {
222
+ let content;
223
+ try {
224
+ content = await readFile(filePath, "utf-8");
225
+ } catch (error) {
226
+ return {
227
+ filePath,
228
+ baseCommitSha: "",
229
+ gitConflictMarkers: `[Error reading file: ${error.message}]`
230
+ };
231
+ }
232
+ const markers = extractConflictMarkers(content);
233
+ return {
234
+ filePath,
235
+ baseCommitSha: "",
236
+ gitConflictMarkers: markers
237
+ };
238
+ }));
239
+ const mergeBaseResult = await gitMergeBase(input.failingCommitSha, "HEAD");
240
+ const baseSha = mergeBaseResult.ok ? mergeBaseResult.data : "unknown";
241
+ for (const file of affectedFiles) {
242
+ file.baseCommitSha = baseSha;
243
+ }
244
+ const taskDirective = [
245
+ `MERGE CONFLICT RESOLUTION REQUIRED for PR #${input.pullRequestNumber}.`,
246
+ `Failing commit: ${input.failingCommitSha}.`,
247
+ `${affectedFiles.length} file(s) have unresolved conflicts.`,
248
+ `Review the gitConflictMarkers for each file and rewrite the code to resolve all conflicts.`
249
+ ].join(`
250
+ `);
251
+ return ok({
252
+ taskDirective,
253
+ priority: "critical",
254
+ affectedFiles
255
+ });
256
+ } catch (error) {
257
+ return fail("UNKNOWN_ERROR", error instanceof Error ? error.message : String(error), false);
258
+ }
259
+ }
260
+ }
261
+ function extractConflictMarkers(content) {
262
+ const lines = content.split(`
263
+ `);
264
+ const blocks = [];
265
+ let inConflict = false;
266
+ let currentBlock = [];
267
+ for (const line of lines) {
268
+ if (line.startsWith("<<<<<<<")) {
269
+ inConflict = true;
270
+ currentBlock = [line];
271
+ } else if (line.startsWith(">>>>>>>") && inConflict) {
272
+ currentBlock.push(line);
273
+ blocks.push(currentBlock.join(`
274
+ `));
275
+ inConflict = false;
276
+ currentBlock = [];
277
+ } else if (inConflict) {
278
+ currentBlock.push(line);
279
+ }
280
+ }
281
+ return blocks.join(`
282
+ ---
283
+ `);
284
+ }
285
+ // src/init/init-spec.ts
286
+ import { z as z3 } from "zod";
287
+ var InitInputSchema = z3.object({
288
+ outputDir: z3.string().min(1).default("."),
289
+ workflowName: z3.string().min(1).default("jules-merge-check"),
290
+ baseBranch: z3.string().min(1).default("main"),
291
+ force: z3.boolean().default(false)
292
+ });
293
+ var InitErrorCode = z3.enum([
294
+ "DIRECTORY_NOT_FOUND",
295
+ "FILE_ALREADY_EXISTS",
296
+ "WRITE_FAILED",
297
+ "UNKNOWN_ERROR"
298
+ ]);
299
+ // src/init/init-handler.ts
300
+ import { mkdir, writeFile, access, stat } from "node:fs/promises";
301
+ import { join, resolve } from "node:path";
302
+
303
+ // src/init/templates.ts
304
+ function buildWorkflowYaml(options) {
305
+ return `# Generated by jules-merge init
306
+ # This workflow checks for merge conflicts on pull requests.
307
+ name: ${options.workflowName}
308
+
309
+ on:
310
+ pull_request:
311
+ branches: [${options.baseBranch}]
312
+
313
+ permissions:
314
+ contents: read
315
+ pull-requests: read
316
+
317
+ jobs:
318
+ check-conflicts:
319
+ runs-on: ubuntu-latest
320
+ steps:
321
+ - uses: actions/checkout@v4
322
+ with:
323
+ fetch-depth: 0
324
+
325
+ - name: Attempt merge
326
+ id: merge
327
+ continue-on-error: true
328
+ run: |
329
+ git config user.name "github-actions"
330
+ git config user.email "github-actions@github.com"
331
+ git fetch origin \${{ github.event.pull_request.base.ref }}
332
+ git merge origin/\${{ github.event.pull_request.base.ref }} --no-commit --no-ff || true
333
+
334
+ - name: Check for conflicts
335
+ run: |
336
+ npx @google/jules-merge check-conflicts \\
337
+ --repo \${{ github.repository }} \\
338
+ --pr \${{ github.event.pull_request.number }} \\
339
+ --sha \${{ github.event.pull_request.head.sha }}
340
+ `;
341
+ }
342
+
343
+ // src/init/init-handler.ts
344
+ class InitHandler {
345
+ async execute(input) {
346
+ try {
347
+ const outputDir = resolve(input.outputDir);
348
+ try {
349
+ const stats = await stat(outputDir);
350
+ if (!stats.isDirectory()) {
351
+ return fail("DIRECTORY_NOT_FOUND", `${outputDir} is not a directory.`, true, "Provide a valid directory path with --output-dir.");
352
+ }
353
+ } catch {
354
+ return fail("DIRECTORY_NOT_FOUND", `Directory does not exist: ${outputDir}`, true, "Create the directory first or provide a valid path.");
355
+ }
356
+ const workflowDir = join(outputDir, ".github", "workflows");
357
+ const filePath = join(workflowDir, `${input.workflowName}.yml`);
358
+ if (!input.force) {
359
+ try {
360
+ await access(filePath);
361
+ return fail("FILE_ALREADY_EXISTS", `Workflow file already exists: ${filePath}`, true, "Use --force to overwrite.");
362
+ } catch {}
363
+ }
364
+ const content = buildWorkflowYaml({
365
+ workflowName: input.workflowName,
366
+ baseBranch: input.baseBranch
367
+ });
368
+ try {
369
+ await mkdir(workflowDir, { recursive: true });
370
+ await writeFile(filePath, content, "utf-8");
371
+ } catch (error) {
372
+ return fail("WRITE_FAILED", `Failed to write workflow file: ${error.message}`, true);
373
+ }
374
+ return ok({ filePath, content });
375
+ } catch (error) {
376
+ return fail("UNKNOWN_ERROR", error instanceof Error ? error.message : String(error), false);
377
+ }
378
+ }
379
+ }
380
+ export {
381
+ ok,
382
+ getSessionChangedFiles,
383
+ fail,
384
+ jules as createJulesClient,
385
+ buildWorkflowYaml,
386
+ SessionCheckInputSchema,
387
+ SessionCheckHandler,
388
+ SessionCheckErrorCode,
389
+ InitInputSchema,
390
+ InitHandler,
391
+ InitErrorCode,
392
+ GitCheckInputSchema,
393
+ GitCheckHandler,
394
+ GitCheckErrorCode
395
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ declare const _default: import("citty").CommandDef<{
2
+ session: {
3
+ type: "string";
4
+ description: string;
5
+ };
6
+ repo: {
7
+ type: "string";
8
+ description: string;
9
+ };
10
+ base: {
11
+ type: "string";
12
+ description: string;
13
+ default: string;
14
+ };
15
+ pr: {
16
+ type: "string";
17
+ description: string;
18
+ };
19
+ sha: {
20
+ type: "string";
21
+ description: string;
22
+ };
23
+ }>;
24
+ export default _default;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,23 @@
1
+ declare const _default: import("citty").CommandDef<{
2
+ 'output-dir': {
3
+ type: "string";
4
+ description: string;
5
+ default: string;
6
+ };
7
+ 'workflow-name': {
8
+ type: "string";
9
+ description: string;
10
+ default: string;
11
+ };
12
+ 'base-branch': {
13
+ type: "string";
14
+ description: string;
15
+ default: string;
16
+ };
17
+ force: {
18
+ type: "boolean";
19
+ description: string;
20
+ default: false;
21
+ };
22
+ }>;
23
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import type { GitCheckSpec, GitCheckInput, GitCheckResult } from './git-spec.js';
2
+ export declare class GitCheckHandler implements GitCheckSpec {
3
+ execute(input: GitCheckInput): Promise<GitCheckResult>;
4
+ }
@@ -0,0 +1,43 @@
1
+ import { z } from 'zod';
2
+ export declare const GitCheckInputSchema: z.ZodObject<{
3
+ repo: z.ZodEffects<z.ZodString, string, string>;
4
+ pullRequestNumber: z.ZodNumber;
5
+ failingCommitSha: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ repo: string;
8
+ pullRequestNumber: number;
9
+ failingCommitSha: string;
10
+ }, {
11
+ repo: string;
12
+ pullRequestNumber: number;
13
+ failingCommitSha: string;
14
+ }>;
15
+ export type GitCheckInput = z.infer<typeof GitCheckInputSchema>;
16
+ export declare const GitCheckErrorCode: z.ZodEnum<["NO_UNMERGED_FILES", "GIT_STATUS_FAILED", "FILE_READ_FAILED", "UNKNOWN_ERROR"]>;
17
+ export type GitCheckErrorCode = z.infer<typeof GitCheckErrorCode>;
18
+ export interface GitCheckData {
19
+ taskDirective: string;
20
+ priority: 'standard' | 'critical';
21
+ affectedFiles: Array<{
22
+ filePath: string;
23
+ baseCommitSha: string;
24
+ gitConflictMarkers: string;
25
+ }>;
26
+ }
27
+ export interface GitCheckSuccess {
28
+ success: true;
29
+ data: GitCheckData;
30
+ }
31
+ export interface GitCheckFailure {
32
+ success: false;
33
+ error: {
34
+ code: GitCheckErrorCode;
35
+ message: string;
36
+ recoverable: boolean;
37
+ suggestion?: string;
38
+ };
39
+ }
40
+ export type GitCheckResult = GitCheckSuccess | GitCheckFailure;
41
+ export interface GitCheckSpec {
42
+ execute(input: GitCheckInput): Promise<GitCheckResult>;
43
+ }
@@ -0,0 +1,4 @@
1
+ export * from './session-spec.js';
2
+ export { SessionCheckHandler } from './session-handler.js';
3
+ export * from './git-spec.js';
4
+ export { GitCheckHandler } from './git-handler.js';
@@ -0,0 +1,9 @@
1
+ import type { Octokit } from '@octokit/rest';
2
+ import type { JulesClient } from '@google/jules-sdk';
3
+ import type { SessionCheckSpec, SessionCheckInput, SessionCheckResult } from './session-spec.js';
4
+ export declare class SessionCheckHandler implements SessionCheckSpec {
5
+ private octokit;
6
+ private julesClient;
7
+ constructor(octokit: Octokit, julesClient: JulesClient);
8
+ execute(input: SessionCheckInput): Promise<SessionCheckResult>;
9
+ }
@@ -0,0 +1,43 @@
1
+ import { z } from 'zod';
2
+ export declare const SessionCheckInputSchema: z.ZodObject<{
3
+ sessionId: z.ZodString;
4
+ repo: z.ZodEffects<z.ZodString, string, string>;
5
+ base: z.ZodDefault<z.ZodString>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ sessionId: string;
8
+ repo: string;
9
+ base: string;
10
+ }, {
11
+ sessionId: string;
12
+ repo: string;
13
+ base?: string | undefined;
14
+ }>;
15
+ export type SessionCheckInput = z.infer<typeof SessionCheckInputSchema>;
16
+ export declare const SessionCheckErrorCode: z.ZodEnum<["SESSION_QUERY_FAILED", "GITHUB_API_ERROR", "RATE_LIMIT_EXCEEDED", "UNKNOWN_ERROR"]>;
17
+ export type SessionCheckErrorCode = z.infer<typeof SessionCheckErrorCode>;
18
+ export interface SessionCheckData {
19
+ status: 'clean' | 'conflict';
20
+ message: string;
21
+ conflicts: Array<{
22
+ filePath: string;
23
+ conflictReason: string;
24
+ remoteShadowContent: string;
25
+ }>;
26
+ }
27
+ export interface SessionCheckSuccess {
28
+ success: true;
29
+ data: SessionCheckData;
30
+ }
31
+ export interface SessionCheckFailure {
32
+ success: false;
33
+ error: {
34
+ code: SessionCheckErrorCode;
35
+ message: string;
36
+ recoverable: boolean;
37
+ suggestion?: string;
38
+ };
39
+ }
40
+ export type SessionCheckResult = SessionCheckSuccess | SessionCheckFailure;
41
+ export interface SessionCheckSpec {
42
+ execute(input: SessionCheckInput): Promise<SessionCheckResult>;
43
+ }
@@ -0,0 +1,5 @@
1
+ export * from './conflicts/index.js';
2
+ export * from './init/index.js';
3
+ export { ok, fail } from './shared/result.js';
4
+ export { getSessionChangedFiles, createJulesClient } from './shared/session.js';
5
+ export type { SessionFileInfo } from './shared/session.js';
@@ -0,0 +1,4 @@
1
+ export * from './init-spec.js';
2
+ export { InitHandler } from './init-handler.js';
3
+ export { buildWorkflowYaml } from './templates.js';
4
+ export type { WorkflowTemplateOptions } from './templates.js';