@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.
- package/README.md +205 -0
- package/dist/analyze/formatting.d.ts +19 -0
- package/dist/analyze/goals.d.ts +18 -0
- package/dist/analyze/handler.d.ts +23 -0
- package/dist/analyze/index.d.ts +8 -0
- package/dist/analyze/milestone.d.ts +43 -0
- package/dist/analyze/prompt.d.ts +10 -0
- package/dist/analyze/spec.d.ts +54 -0
- package/dist/analyze/triage-prompt.d.ts +16 -0
- package/dist/cli/analyze.command.d.ts +24 -0
- package/dist/cli/analyze.command.mjs +1015 -0
- package/dist/cli/commands.json +1 -0
- package/dist/cli/configure.command.d.ts +21 -0
- package/dist/cli/configure.command.mjs +623 -0
- package/dist/cli/dispatch.command.d.ts +16 -0
- package/dist/cli/dispatch.command.mjs +777 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.mjs +40 -0
- package/dist/cli/init.command.d.ts +38 -0
- package/dist/cli/init.command.mjs +1287 -0
- package/dist/cli/merge.command.d.ts +36 -0
- package/dist/cli/merge.command.mjs +859 -0
- package/dist/cli/signal.command.d.ts +2 -0
- package/dist/cli/signal.command.mjs +288 -0
- package/dist/configure/handler.d.ts +19 -0
- package/dist/configure/index.d.ts +4 -0
- package/dist/configure/labels.d.ts +6 -0
- package/dist/configure/spec.d.ts +49 -0
- package/dist/dispatch/events.d.ts +12 -0
- package/dist/dispatch/handler.d.ts +21 -0
- package/dist/dispatch/index.d.ts +5 -0
- package/dist/dispatch/spec.d.ts +47 -0
- package/dist/dispatch/status.d.ts +24 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +2105 -0
- package/dist/init/handler.d.ts +22 -0
- package/dist/init/index.d.ts +4 -0
- package/dist/init/ops/commit-files.d.ts +10 -0
- package/dist/init/ops/create-branch.d.ts +16 -0
- package/dist/init/ops/create-pr.d.ts +15 -0
- package/dist/init/ops/pr-body.d.ts +5 -0
- package/dist/init/ops/upload-secrets.d.ts +11 -0
- package/dist/init/spec.d.ts +50 -0
- package/dist/init/templates/analyze.d.ts +2 -0
- package/dist/init/templates/dispatch.d.ts +2 -0
- package/dist/init/templates/example-goal.d.ts +5 -0
- package/dist/init/templates/merge.d.ts +2 -0
- package/dist/init/templates/types.d.ts +6 -0
- package/dist/init/templates.d.ts +10 -0
- package/dist/init/types.d.ts +19 -0
- package/dist/init/wizard/headless.d.ts +8 -0
- package/dist/init/wizard/index.d.ts +3 -0
- package/dist/init/wizard/interactive.d.ts +9 -0
- package/dist/init/wizard/types.d.ts +22 -0
- package/dist/merge/handler.d.ts +21 -0
- package/dist/merge/index.d.ts +5 -0
- package/dist/merge/ops/index.d.ts +4 -0
- package/dist/merge/ops/redispatch.d.ts +8 -0
- package/dist/merge/ops/squash-merge.d.ts +8 -0
- package/dist/merge/ops/update-branch.d.ts +11 -0
- package/dist/merge/ops/wait-for-ci.d.ts +7 -0
- package/dist/merge/select/by-fleet-run.d.ts +8 -0
- package/dist/merge/select/by-label.d.ts +7 -0
- package/dist/merge/select/index.d.ts +2 -0
- package/dist/merge/spec.d.ts +99 -0
- package/dist/shared/auth/cache-plugin.d.ts +9 -0
- package/dist/shared/auth/git.d.ts +22 -0
- package/dist/shared/auth/index.d.ts +4 -0
- package/dist/shared/auth/octokit.d.ts +11 -0
- package/dist/shared/auth/resolve-key.d.ts +11 -0
- package/dist/shared/events/analyze.d.ts +37 -0
- package/dist/shared/events/configure.d.ts +21 -0
- package/dist/shared/events/dispatch.d.ts +26 -0
- package/dist/shared/events/error.d.ts +7 -0
- package/dist/shared/events/index.d.ts +16 -0
- package/dist/shared/events/init.d.ts +49 -0
- package/dist/shared/events/merge.d.ts +72 -0
- package/dist/shared/events.d.ts +1 -0
- package/dist/shared/index.d.ts +6 -0
- package/dist/shared/result/create-result-schemas.d.ts +72 -0
- package/dist/shared/result/fail.d.ts +10 -0
- package/dist/shared/result/index.d.ts +3 -0
- package/dist/shared/result/ok.d.ts +5 -0
- package/dist/shared/schemas/check-run.d.ts +16 -0
- package/dist/shared/schemas/index.d.ts +4 -0
- package/dist/shared/schemas/label.d.ts +16 -0
- package/dist/shared/schemas/pr.d.ts +19 -0
- package/dist/shared/schemas/repo-info.d.ts +16 -0
- package/dist/shared/session-dispatcher.d.ts +18 -0
- package/dist/shared/ui/assert-never.d.ts +13 -0
- package/dist/shared/ui/index.d.ts +18 -0
- package/dist/shared/ui/interactive.d.ts +19 -0
- package/dist/shared/ui/plain.d.ts +16 -0
- package/dist/shared/ui/render/analyze.d.ts +4 -0
- package/dist/shared/ui/render/configure.d.ts +4 -0
- package/dist/shared/ui/render/dispatch.d.ts +4 -0
- package/dist/shared/ui/render/error.d.ts +4 -0
- package/dist/shared/ui/render/init.d.ts +4 -0
- package/dist/shared/ui/render/merge.d.ts +4 -0
- package/dist/shared/ui/session-url.d.ts +13 -0
- package/dist/shared/ui/spec.d.ts +30 -0
- package/dist/signal/handler.d.ts +17 -0
- package/dist/signal/index.d.ts +3 -0
- package/dist/signal/spec.d.ts +60 -0
- package/package.json +76 -0
|
@@ -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,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[]>;
|
package/dist/index.d.ts
ADDED