@google/jules-fleet 0.0.1-experimental.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 (105) hide show
  1. package/README.md +205 -0
  2. package/dist/analyze/formatting.d.ts +19 -0
  3. package/dist/analyze/goals.d.ts +18 -0
  4. package/dist/analyze/handler.d.ts +23 -0
  5. package/dist/analyze/index.d.ts +8 -0
  6. package/dist/analyze/milestone.d.ts +43 -0
  7. package/dist/analyze/prompt.d.ts +10 -0
  8. package/dist/analyze/spec.d.ts +54 -0
  9. package/dist/analyze/triage-prompt.d.ts +16 -0
  10. package/dist/cli/analyze.command.d.ts +24 -0
  11. package/dist/cli/analyze.command.mjs +1015 -0
  12. package/dist/cli/commands.json +1 -0
  13. package/dist/cli/configure.command.d.ts +21 -0
  14. package/dist/cli/configure.command.mjs +623 -0
  15. package/dist/cli/dispatch.command.d.ts +16 -0
  16. package/dist/cli/dispatch.command.mjs +777 -0
  17. package/dist/cli/index.d.ts +2 -0
  18. package/dist/cli/index.mjs +40 -0
  19. package/dist/cli/init.command.d.ts +38 -0
  20. package/dist/cli/init.command.mjs +1287 -0
  21. package/dist/cli/merge.command.d.ts +36 -0
  22. package/dist/cli/merge.command.mjs +859 -0
  23. package/dist/cli/signal.command.d.ts +2 -0
  24. package/dist/cli/signal.command.mjs +288 -0
  25. package/dist/configure/handler.d.ts +19 -0
  26. package/dist/configure/index.d.ts +4 -0
  27. package/dist/configure/labels.d.ts +6 -0
  28. package/dist/configure/spec.d.ts +49 -0
  29. package/dist/dispatch/events.d.ts +12 -0
  30. package/dist/dispatch/handler.d.ts +21 -0
  31. package/dist/dispatch/index.d.ts +5 -0
  32. package/dist/dispatch/spec.d.ts +47 -0
  33. package/dist/dispatch/status.d.ts +24 -0
  34. package/dist/index.d.ts +7 -0
  35. package/dist/index.mjs +2105 -0
  36. package/dist/init/handler.d.ts +22 -0
  37. package/dist/init/index.d.ts +4 -0
  38. package/dist/init/ops/commit-files.d.ts +10 -0
  39. package/dist/init/ops/create-branch.d.ts +16 -0
  40. package/dist/init/ops/create-pr.d.ts +15 -0
  41. package/dist/init/ops/pr-body.d.ts +5 -0
  42. package/dist/init/ops/upload-secrets.d.ts +11 -0
  43. package/dist/init/spec.d.ts +50 -0
  44. package/dist/init/templates/analyze.d.ts +2 -0
  45. package/dist/init/templates/dispatch.d.ts +2 -0
  46. package/dist/init/templates/example-goal.d.ts +5 -0
  47. package/dist/init/templates/merge.d.ts +2 -0
  48. package/dist/init/templates/types.d.ts +6 -0
  49. package/dist/init/templates.d.ts +10 -0
  50. package/dist/init/types.d.ts +19 -0
  51. package/dist/init/wizard/headless.d.ts +8 -0
  52. package/dist/init/wizard/index.d.ts +3 -0
  53. package/dist/init/wizard/interactive.d.ts +9 -0
  54. package/dist/init/wizard/types.d.ts +22 -0
  55. package/dist/merge/handler.d.ts +21 -0
  56. package/dist/merge/index.d.ts +5 -0
  57. package/dist/merge/ops/index.d.ts +4 -0
  58. package/dist/merge/ops/redispatch.d.ts +8 -0
  59. package/dist/merge/ops/squash-merge.d.ts +8 -0
  60. package/dist/merge/ops/update-branch.d.ts +11 -0
  61. package/dist/merge/ops/wait-for-ci.d.ts +7 -0
  62. package/dist/merge/select/by-fleet-run.d.ts +8 -0
  63. package/dist/merge/select/by-label.d.ts +7 -0
  64. package/dist/merge/select/index.d.ts +2 -0
  65. package/dist/merge/spec.d.ts +99 -0
  66. package/dist/shared/auth/cache-plugin.d.ts +9 -0
  67. package/dist/shared/auth/git.d.ts +22 -0
  68. package/dist/shared/auth/index.d.ts +4 -0
  69. package/dist/shared/auth/octokit.d.ts +11 -0
  70. package/dist/shared/auth/resolve-key.d.ts +11 -0
  71. package/dist/shared/events/analyze.d.ts +37 -0
  72. package/dist/shared/events/configure.d.ts +21 -0
  73. package/dist/shared/events/dispatch.d.ts +26 -0
  74. package/dist/shared/events/error.d.ts +7 -0
  75. package/dist/shared/events/index.d.ts +16 -0
  76. package/dist/shared/events/init.d.ts +49 -0
  77. package/dist/shared/events/merge.d.ts +72 -0
  78. package/dist/shared/events.d.ts +1 -0
  79. package/dist/shared/index.d.ts +6 -0
  80. package/dist/shared/result/create-result-schemas.d.ts +72 -0
  81. package/dist/shared/result/fail.d.ts +10 -0
  82. package/dist/shared/result/index.d.ts +3 -0
  83. package/dist/shared/result/ok.d.ts +5 -0
  84. package/dist/shared/schemas/check-run.d.ts +16 -0
  85. package/dist/shared/schemas/index.d.ts +4 -0
  86. package/dist/shared/schemas/label.d.ts +16 -0
  87. package/dist/shared/schemas/pr.d.ts +19 -0
  88. package/dist/shared/schemas/repo-info.d.ts +16 -0
  89. package/dist/shared/session-dispatcher.d.ts +18 -0
  90. package/dist/shared/ui/assert-never.d.ts +13 -0
  91. package/dist/shared/ui/index.d.ts +18 -0
  92. package/dist/shared/ui/interactive.d.ts +19 -0
  93. package/dist/shared/ui/plain.d.ts +16 -0
  94. package/dist/shared/ui/render/analyze.d.ts +4 -0
  95. package/dist/shared/ui/render/configure.d.ts +4 -0
  96. package/dist/shared/ui/render/dispatch.d.ts +4 -0
  97. package/dist/shared/ui/render/error.d.ts +4 -0
  98. package/dist/shared/ui/render/init.d.ts +4 -0
  99. package/dist/shared/ui/render/merge.d.ts +4 -0
  100. package/dist/shared/ui/session-url.d.ts +13 -0
  101. package/dist/shared/ui/spec.d.ts +30 -0
  102. package/dist/signal/handler.d.ts +17 -0
  103. package/dist/signal/index.d.ts +3 -0
  104. package/dist/signal/spec.d.ts +60 -0
  105. package/package.json +76 -0
@@ -0,0 +1,2 @@
1
+ declare const _default: import("citty").CommandDef<import("citty").ArgsDef>;
2
+ export default _default;
@@ -0,0 +1,288 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/cli/signal.command.ts
5
+ import { defineCommand } from "citty";
6
+ import { readFileSync } from "fs";
7
+
8
+ // src/shared/auth/octokit.ts
9
+ import { Octokit } from "octokit";
10
+ import { createAppAuth } from "@octokit/auth-app";
11
+
12
+ // src/shared/auth/cache-plugin.ts
13
+ function cachePlugin(octokit) {
14
+ const cache = new Map;
15
+ octokit.hook.wrap("request", async (request, options) => {
16
+ const key = `${options.method} ${options.url}`;
17
+ const cached = cache.get(key);
18
+ if (cached) {
19
+ options.headers = {
20
+ ...options.headers,
21
+ "if-none-match": cached.etag
22
+ };
23
+ }
24
+ try {
25
+ const response = await request(options);
26
+ const etag = response.headers.etag;
27
+ if (etag) {
28
+ cache.set(key, { etag, data: response.data });
29
+ }
30
+ return response;
31
+ } catch (error) {
32
+ if (error.status === 304 && cached) {
33
+ return { ...error.response, data: cached.data, status: 200 };
34
+ }
35
+ throw error;
36
+ }
37
+ });
38
+ }
39
+
40
+ // src/shared/auth/resolve-key.ts
41
+ function resolvePrivateKey(base64Value, rawValue) {
42
+ if (base64Value) {
43
+ return Buffer.from(base64Value, "base64").toString("utf-8");
44
+ }
45
+ if (rawValue) {
46
+ return rawValue.replace(/\\n/g, `
47
+ `);
48
+ }
49
+ throw new Error("No private key provided. Set GITHUB_APP_PRIVATE_KEY_BASE64 (recommended) or GITHUB_APP_PRIVATE_KEY.");
50
+ }
51
+
52
+ // src/shared/auth/octokit.ts
53
+ var CachedOctokit = Octokit.plugin(cachePlugin);
54
+ function getAuthOptions() {
55
+ const appId = process.env.GITHUB_APP_ID;
56
+ const privateKeyBase64 = process.env.GITHUB_APP_PRIVATE_KEY_BASE64;
57
+ const privateKeyRaw = process.env.GITHUB_APP_PRIVATE_KEY;
58
+ const installationId = process.env.GITHUB_APP_INSTALLATION_ID;
59
+ if (appId && (privateKeyBase64 || privateKeyRaw) && installationId) {
60
+ return {
61
+ authStrategy: createAppAuth,
62
+ auth: {
63
+ appId,
64
+ privateKey: resolvePrivateKey(privateKeyBase64, privateKeyRaw),
65
+ installationId: Number(installationId)
66
+ }
67
+ };
68
+ }
69
+ const token = process.env.GITHUB_TOKEN;
70
+ if (token) {
71
+ return { auth: token };
72
+ }
73
+ throw new Error("GitHub auth not configured. Set GITHUB_APP_ID + GITHUB_APP_PRIVATE_KEY + GITHUB_APP_INSTALLATION_ID for App auth, or GITHUB_TOKEN for PAT auth.");
74
+ }
75
+ function createFleetOctokit() {
76
+ return new CachedOctokit(getAuthOptions());
77
+ }
78
+
79
+ // src/shared/auth/git.ts
80
+ import { exec } from "child_process";
81
+ import { promisify } from "util";
82
+ var execAsync = promisify(exec);
83
+ async function getGitRepoInfo(remoteName = "origin") {
84
+ const ghRepo = process.env.GITHUB_REPOSITORY;
85
+ if (ghRepo) {
86
+ const [owner, repo] = ghRepo.split("/");
87
+ return { owner, repo, fullName: ghRepo };
88
+ }
89
+ const { stdout } = await execAsync(`git remote get-url ${remoteName}`);
90
+ return parseGitRemoteUrl(stdout.trim());
91
+ }
92
+ function parseGitRemoteUrl(remoteUrl) {
93
+ const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/(.+?)(\.git)?$/);
94
+ if (sshMatch) {
95
+ const [, owner, repo] = sshMatch;
96
+ return {
97
+ owner,
98
+ repo: repo.replace(/\.git$/, ""),
99
+ fullName: `${owner}/${repo.replace(/\.git$/, "")}`
100
+ };
101
+ }
102
+ const httpsMatch = remoteUrl.match(/https?:\/\/github\.com\/([^/]+)\/(.+?)(\.git)?$/);
103
+ if (httpsMatch) {
104
+ const [, owner, repo] = httpsMatch;
105
+ return {
106
+ owner,
107
+ repo: repo.replace(/\.git$/, ""),
108
+ fullName: `${owner}/${repo.replace(/\.git$/, "")}`
109
+ };
110
+ }
111
+ throw new Error(`Unable to parse git remote URL: ${remoteUrl}`);
112
+ }
113
+
114
+ // src/signal/spec.ts
115
+ import { z } from "zod";
116
+ var SignalKind = z.enum(["insight", "assessment"]);
117
+ var SignalCreateInputSchema = z.object({
118
+ owner: z.string().min(1),
119
+ repo: z.string().min(1),
120
+ kind: SignalKind.default("assessment"),
121
+ title: z.string().min(1),
122
+ body: z.string().min(1),
123
+ tags: z.array(z.string()).default([]),
124
+ scope: z.string().optional()
125
+ });
126
+ var SignalCreateErrorCode = z.enum([
127
+ "GITHUB_API_ERROR",
128
+ "SCOPE_NOT_FOUND",
129
+ "UNKNOWN_ERROR"
130
+ ]);
131
+
132
+ // src/signal/handler.ts
133
+ class SignalCreateHandler {
134
+ deps;
135
+ constructor(deps) {
136
+ this.deps = deps;
137
+ }
138
+ async execute(input) {
139
+ try {
140
+ const { octokit } = this.deps;
141
+ const labels = [...input.tags];
142
+ labels.push(input.kind === "insight" ? "fleet-insight" : "fleet-assessment");
143
+ let milestoneNumber;
144
+ if (input.scope) {
145
+ const { data: milestones } = await octokit.rest.issues.listMilestones({
146
+ owner: input.owner,
147
+ repo: input.repo,
148
+ state: "open"
149
+ });
150
+ const match = milestones.find((m) => m.title.toLowerCase() === input.scope.toLowerCase());
151
+ if (!match) {
152
+ return {
153
+ success: false,
154
+ error: {
155
+ code: "SCOPE_NOT_FOUND",
156
+ message: `No open milestone found matching scope "${input.scope}"`,
157
+ recoverable: true,
158
+ suggestion: `Create a milestone named "${input.scope}" or omit --scope`
159
+ }
160
+ };
161
+ }
162
+ milestoneNumber = match.number;
163
+ }
164
+ const { data } = await octokit.rest.issues.create({
165
+ owner: input.owner,
166
+ repo: input.repo,
167
+ title: input.title,
168
+ body: input.body,
169
+ labels,
170
+ ...milestoneNumber && { milestone: milestoneNumber }
171
+ });
172
+ return {
173
+ success: true,
174
+ data: { id: data.number, url: data.html_url }
175
+ };
176
+ } catch (error) {
177
+ if (error instanceof Error && "status" in error) {
178
+ return {
179
+ success: false,
180
+ error: {
181
+ code: "GITHUB_API_ERROR",
182
+ message: error.message,
183
+ recoverable: error.status === 403 || error.status === 429,
184
+ suggestion: error.status === 401 ? "Check your GITHUB_TOKEN or GitHub App credentials" : undefined
185
+ }
186
+ };
187
+ }
188
+ return {
189
+ success: false,
190
+ error: {
191
+ code: "UNKNOWN_ERROR",
192
+ message: error instanceof Error ? error.message : String(error),
193
+ recoverable: false
194
+ }
195
+ };
196
+ }
197
+ }
198
+ }
199
+
200
+ // src/cli/signal.command.ts
201
+ var create = defineCommand({
202
+ meta: {
203
+ name: "create",
204
+ description: "Create a signal (insight or assessment)"
205
+ },
206
+ args: {
207
+ title: {
208
+ type: "string",
209
+ description: "Signal title",
210
+ required: true
211
+ },
212
+ kind: {
213
+ type: "string",
214
+ description: "Signal kind: insight (informational) or assessment (actionable)",
215
+ default: "assessment"
216
+ },
217
+ body: {
218
+ type: "string",
219
+ description: "Signal body content (markdown)"
220
+ },
221
+ "body-file": {
222
+ type: "string",
223
+ description: "Path to a markdown file containing the signal body"
224
+ },
225
+ tag: {
226
+ type: "string",
227
+ description: "Tag/label to apply (comma-separated for multiple)"
228
+ },
229
+ scope: {
230
+ type: "string",
231
+ description: "Scope name (maps to milestone in GitHub)"
232
+ },
233
+ owner: {
234
+ type: "string",
235
+ description: "Repository owner (auto-detected from git remote if omitted)"
236
+ },
237
+ repo: {
238
+ type: "string",
239
+ description: "Repository name (auto-detected from git remote if omitted)"
240
+ }
241
+ },
242
+ async run({ args }) {
243
+ let body = args.body ?? "";
244
+ if (args["body-file"]) {
245
+ body = readFileSync(args["body-file"], "utf-8");
246
+ }
247
+ let owner = args.owner;
248
+ let repo = args.repo;
249
+ if (!owner || !repo) {
250
+ const repoInfo = await getGitRepoInfo();
251
+ owner = owner || repoInfo.owner;
252
+ repo = repo || repoInfo.repo;
253
+ }
254
+ const tags = args.tag ? args.tag.split(",").map((t) => t.trim()) : [];
255
+ const input = SignalCreateInputSchema.parse({
256
+ owner,
257
+ repo,
258
+ kind: args.kind,
259
+ title: args.title,
260
+ body,
261
+ tags,
262
+ scope: args.scope || undefined
263
+ });
264
+ const octokit = createFleetOctokit();
265
+ const handler = new SignalCreateHandler({ octokit });
266
+ const result = await handler.execute(input);
267
+ if (!result.success) {
268
+ console.error(`Error [${result.error.code}]: ${result.error.message}`);
269
+ if (result.error.suggestion) {
270
+ console.error(` Suggestion: ${result.error.suggestion}`);
271
+ }
272
+ process.exit(1);
273
+ }
274
+ console.log(`Created signal #${result.data.id}: ${result.data.url}`);
275
+ }
276
+ });
277
+ var signal_command_default = defineCommand({
278
+ meta: {
279
+ name: "signal",
280
+ description: "Manage fleet signals (insights and assessments)"
281
+ },
282
+ subCommands: {
283
+ create
284
+ }
285
+ });
286
+ export {
287
+ signal_command_default as default
288
+ };
@@ -0,0 +1,19 @@
1
+ import type { Octokit } from 'octokit';
2
+ import type { ConfigureInput, ConfigureResult, ConfigureSpec } from './spec.js';
3
+ import type { FleetEmitter } from '../shared/events.js';
4
+ export interface ConfigureHandlerDeps {
5
+ octokit: Octokit;
6
+ emit?: FleetEmitter;
7
+ }
8
+ /**
9
+ * ConfigureHandler manages repo resources (labels, etc.).
10
+ * Never throws — all errors returned as Result.
11
+ */
12
+ export declare class ConfigureHandler implements ConfigureSpec {
13
+ private octokit;
14
+ private emit;
15
+ constructor(deps: ConfigureHandlerDeps);
16
+ execute(input: ConfigureInput): Promise<ConfigureResult>;
17
+ private createLabels;
18
+ private deleteLabels;
19
+ }
@@ -0,0 +1,4 @@
1
+ export type { ConfigureInput, ConfigureResult, ConfigureSuccess, ConfigureFailure, ConfigureSpec, } from './spec.js';
2
+ export { ConfigureInputSchema, ConfigureAction, ConfigureResource, ConfigureErrorCode, } from './spec.js';
3
+ export { ConfigureHandler } from './handler.js';
4
+ export { FLEET_LABELS } from './labels.js';
@@ -0,0 +1,6 @@
1
+ import type { Label } from '../shared/schemas/label.js';
2
+ /**
3
+ * Fleet label definitions.
4
+ * These are the labels that fleet commands expect to exist in the repo.
5
+ */
6
+ export declare const FLEET_LABELS: readonly Label[];
@@ -0,0 +1,49 @@
1
+ import { z } from 'zod';
2
+ export declare const ConfigureAction: z.ZodEnum<["create", "delete"]>;
3
+ export type ConfigureAction = z.infer<typeof ConfigureAction>;
4
+ export declare const ConfigureResource: z.ZodEnum<["labels"]>;
5
+ export type ConfigureResource = z.infer<typeof ConfigureResource>;
6
+ export declare const ConfigureInputSchema: z.ZodObject<{
7
+ /** Resource to configure */
8
+ resource: z.ZodEnum<["labels"]>;
9
+ /** Create or delete the resource */
10
+ action: z.ZodDefault<z.ZodEnum<["create", "delete"]>>;
11
+ /** Repository owner */
12
+ owner: z.ZodString;
13
+ /** Repository name */
14
+ repo: z.ZodString;
15
+ }, "strip", z.ZodTypeAny, {
16
+ owner: string;
17
+ repo: string;
18
+ resource: "labels";
19
+ action: "create" | "delete";
20
+ }, {
21
+ owner: string;
22
+ repo: string;
23
+ resource: "labels";
24
+ action?: "create" | "delete" | undefined;
25
+ }>;
26
+ export type ConfigureInput = z.infer<typeof ConfigureInputSchema>;
27
+ export declare const ConfigureErrorCode: z.ZodEnum<["GITHUB_API_ERROR", "UNKNOWN_ERROR"]>;
28
+ export type ConfigureErrorCode = z.infer<typeof ConfigureErrorCode>;
29
+ export interface ConfigureSuccess {
30
+ success: true;
31
+ data: {
32
+ created: string[];
33
+ deleted: string[];
34
+ skipped: string[];
35
+ };
36
+ }
37
+ export interface ConfigureFailure {
38
+ success: false;
39
+ error: {
40
+ code: ConfigureErrorCode;
41
+ message: string;
42
+ recoverable: boolean;
43
+ suggestion?: string;
44
+ };
45
+ }
46
+ export type ConfigureResult = ConfigureSuccess | ConfigureFailure;
47
+ export interface ConfigureSpec {
48
+ execute(input: ConfigureInput): Promise<ConfigureResult>;
49
+ }
@@ -0,0 +1,12 @@
1
+ import type { Octokit } from 'octokit';
2
+ /** Recorded dispatch event */
3
+ export interface DispatchRecord {
4
+ commentId: number;
5
+ timestamp: string;
6
+ }
7
+ /**
8
+ * Appends a dispatch event comment to an issue.
9
+ * This is the write side of the event-sourced pattern —
10
+ * `getDispatchStatus` is the read side.
11
+ */
12
+ export declare function recordDispatch(octokit: Octokit, owner: string, repo: string, issueNumber: number, sessionId: string): Promise<DispatchRecord>;
@@ -0,0 +1,21 @@
1
+ import type { Octokit } from 'octokit';
2
+ import type { DispatchInput, DispatchResult, DispatchSpec } from './spec.js';
3
+ import type { SessionDispatcher } from '../shared/session-dispatcher.js';
4
+ import type { FleetEmitter } from '../shared/events.js';
5
+ export interface DispatchHandlerDeps {
6
+ octokit: Octokit;
7
+ dispatcher: SessionDispatcher;
8
+ emit?: FleetEmitter;
9
+ }
10
+ /**
11
+ * DispatchHandler finds undispatched fleet issues in a milestone
12
+ * and fires Jules worker sessions for each.
13
+ * Never throws — all errors returned as Result.
14
+ */
15
+ export declare class DispatchHandler implements DispatchSpec {
16
+ private octokit;
17
+ private dispatcher;
18
+ private emit;
19
+ constructor(deps: DispatchHandlerDeps);
20
+ execute(input: DispatchInput): Promise<DispatchResult>;
21
+ }
@@ -0,0 +1,5 @@
1
+ export type { DispatchInput, DispatchResult, DispatchSuccess, DispatchFailure, DispatchSpec, } from './spec.js';
2
+ export { DispatchInputSchema, DispatchErrorCode } from './spec.js';
3
+ export { DispatchHandler } from './handler.js';
4
+ export { recordDispatch, type DispatchRecord, } from './events.js';
5
+ export { getDispatchStatus, type DispatchEvent, type IssueDispatchStatus, } from './status.js';
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod';
2
+ export declare const DispatchInputSchema: z.ZodObject<{
3
+ /** Milestone ID to scope dispatch */
4
+ milestone: z.ZodString;
5
+ /** Repository owner */
6
+ owner: z.ZodString;
7
+ /** Repository name */
8
+ repo: z.ZodString;
9
+ /** Base branch for Jules sessions */
10
+ baseBranch: z.ZodDefault<z.ZodString>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ owner: string;
13
+ repo: string;
14
+ milestone: string;
15
+ baseBranch: string;
16
+ }, {
17
+ owner: string;
18
+ repo: string;
19
+ milestone: string;
20
+ baseBranch?: string | undefined;
21
+ }>;
22
+ export type DispatchInput = z.infer<typeof DispatchInputSchema>;
23
+ export declare const DispatchErrorCode: z.ZodEnum<["NO_FLEET_ISSUES", "MILESTONE_FETCH_FAILED", "SESSION_DISPATCH_FAILED", "UNKNOWN_ERROR"]>;
24
+ export type DispatchErrorCode = z.infer<typeof DispatchErrorCode>;
25
+ export interface DispatchSuccess {
26
+ success: true;
27
+ data: {
28
+ dispatched: Array<{
29
+ issueNumber: number;
30
+ sessionId: string;
31
+ }>;
32
+ skipped: number;
33
+ };
34
+ }
35
+ export interface DispatchFailure {
36
+ success: false;
37
+ error: {
38
+ code: DispatchErrorCode;
39
+ message: string;
40
+ recoverable: boolean;
41
+ suggestion?: string;
42
+ };
43
+ }
44
+ export type DispatchResult = DispatchSuccess | DispatchFailure;
45
+ export interface DispatchSpec {
46
+ execute(input: DispatchInput): Promise<DispatchResult>;
47
+ }
@@ -0,0 +1,24 @@
1
+ import type { Octokit } from 'octokit';
2
+ /** Parsed dispatch event from a comment */
3
+ export interface DispatchEvent {
4
+ sessionId: string;
5
+ timestamp: string;
6
+ commentId: number;
7
+ }
8
+ /** Lifecycle status of a dispatched issue */
9
+ export interface IssueDispatchStatus {
10
+ number: number;
11
+ open: boolean;
12
+ labels: string[];
13
+ dispatchEvent: DispatchEvent | null;
14
+ linkedPRs: number[];
15
+ }
16
+ /**
17
+ * Reads each issue's comment log and returns factual lifecycle signals:
18
+ * - Whether the issue is open/closed
19
+ * - Whether it has a dispatch event comment (and the session ID)
20
+ * - Which open PRs reference it
21
+ *
22
+ * Takes Octokit as a parameter for testability.
23
+ */
24
+ export declare function getDispatchStatus(octokit: Octokit, owner: string, repo: string, issueNumbers: number[]): Promise<IssueDispatchStatus[]>;
@@ -0,0 +1,7 @@
1
+ export * from './shared/index.js';
2
+ export * from './merge/index.js';
3
+ export * from './init/index.js';
4
+ export * from './configure/index.js';
5
+ export * from './analyze/index.js';
6
+ export * from './dispatch/index.js';
7
+ export * from './signal/index.js';