@crewbie/cli 0.1.0-alpha.49

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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +253 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +506 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/config.d.ts +84 -0
  7. package/dist/config.js +178 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/core.d.ts +31 -0
  10. package/dist/core.js +186 -0
  11. package/dist/core.js.map +1 -0
  12. package/dist/execution/attribution.d.ts +10 -0
  13. package/dist/execution/attribution.js +102 -0
  14. package/dist/execution/attribution.js.map +1 -0
  15. package/dist/execution/cancel.d.ts +3 -0
  16. package/dist/execution/cancel.js +59 -0
  17. package/dist/execution/cancel.js.map +1 -0
  18. package/dist/execution/capabilities.d.ts +22 -0
  19. package/dist/execution/capabilities.js +101 -0
  20. package/dist/execution/capabilities.js.map +1 -0
  21. package/dist/execution/controls.d.ts +51 -0
  22. package/dist/execution/controls.js +257 -0
  23. package/dist/execution/controls.js.map +1 -0
  24. package/dist/execution/dispatch.d.ts +69 -0
  25. package/dist/execution/dispatch.js +831 -0
  26. package/dist/execution/dispatch.js.map +1 -0
  27. package/dist/execution/fix.d.ts +3 -0
  28. package/dist/execution/fix.js +267 -0
  29. package/dist/execution/fix.js.map +1 -0
  30. package/dist/execution/github.d.ts +15 -0
  31. package/dist/execution/github.js +43 -0
  32. package/dist/execution/github.js.map +1 -0
  33. package/dist/execution/merge.d.ts +15 -0
  34. package/dist/execution/merge.js +133 -0
  35. package/dist/execution/merge.js.map +1 -0
  36. package/dist/execution/planning-approval.d.ts +33 -0
  37. package/dist/execution/planning-approval.js +227 -0
  38. package/dist/execution/planning-approval.js.map +1 -0
  39. package/dist/execution/pr-review.d.ts +86 -0
  40. package/dist/execution/pr-review.js +339 -0
  41. package/dist/execution/pr-review.js.map +1 -0
  42. package/dist/execution/review-loop.d.ts +63 -0
  43. package/dist/execution/review-loop.js +463 -0
  44. package/dist/execution/review-loop.js.map +1 -0
  45. package/dist/execution/test-feature.d.ts +29 -0
  46. package/dist/execution/test-feature.js +240 -0
  47. package/dist/execution/test-feature.js.map +1 -0
  48. package/dist/execution/watch.d.ts +12 -0
  49. package/dist/execution/watch.js +34 -0
  50. package/dist/execution/watch.js.map +1 -0
  51. package/dist/memory/context.d.ts +14 -0
  52. package/dist/memory/context.js +82 -0
  53. package/dist/memory/context.js.map +1 -0
  54. package/dist/memory/improvement.d.ts +25 -0
  55. package/dist/memory/improvement.js +168 -0
  56. package/dist/memory/improvement.js.map +1 -0
  57. package/dist/memory/launch.d.ts +9 -0
  58. package/dist/memory/launch.js +65 -0
  59. package/dist/memory/launch.js.map +1 -0
  60. package/dist/memory/runner.d.ts +4 -0
  61. package/dist/memory/runner.js +74 -0
  62. package/dist/memory/runner.js.map +1 -0
  63. package/dist/memory/state.d.ts +10 -0
  64. package/dist/memory/state.js +42 -0
  65. package/dist/memory/state.js.map +1 -0
  66. package/dist/presentation.d.ts +19 -0
  67. package/dist/presentation.js +128 -0
  68. package/dist/presentation.js.map +1 -0
  69. package/dist/reporting/dashboard.d.ts +2 -0
  70. package/dist/reporting/dashboard.js +106 -0
  71. package/dist/reporting/dashboard.js.map +1 -0
  72. package/dist/reporting/pr-usage.d.ts +24 -0
  73. package/dist/reporting/pr-usage.js +179 -0
  74. package/dist/reporting/pr-usage.js.map +1 -0
  75. package/dist/reporting/records.d.ts +28 -0
  76. package/dist/reporting/records.js +152 -0
  77. package/dist/reporting/records.js.map +1 -0
  78. package/dist/setup/agents.d.ts +8 -0
  79. package/dist/setup/agents.js +83 -0
  80. package/dist/setup/agents.js.map +1 -0
  81. package/dist/setup/assessment.d.ts +31 -0
  82. package/dist/setup/assessment.js +75 -0
  83. package/dist/setup/assessment.js.map +1 -0
  84. package/dist/setup/auto-loaded.d.ts +17 -0
  85. package/dist/setup/auto-loaded.js +49 -0
  86. package/dist/setup/auto-loaded.js.map +1 -0
  87. package/dist/setup/copilot-version.d.ts +7 -0
  88. package/dist/setup/copilot-version.js +39 -0
  89. package/dist/setup/copilot-version.js.map +1 -0
  90. package/dist/setup/copilot.d.ts +22 -0
  91. package/dist/setup/copilot.js +164 -0
  92. package/dist/setup/copilot.js.map +1 -0
  93. package/dist/setup/init.d.ts +41 -0
  94. package/dist/setup/init.js +315 -0
  95. package/dist/setup/init.js.map +1 -0
  96. package/dist/setup/install.d.ts +12 -0
  97. package/dist/setup/install.js +211 -0
  98. package/dist/setup/install.js.map +1 -0
  99. package/dist/setup/instruction-quality.d.ts +25 -0
  100. package/dist/setup/instruction-quality.js +258 -0
  101. package/dist/setup/instruction-quality.js.map +1 -0
  102. package/dist/setup/inventory.d.ts +26 -0
  103. package/dist/setup/inventory.js +78 -0
  104. package/dist/setup/inventory.js.map +1 -0
  105. package/dist/setup/onboarding.d.ts +40 -0
  106. package/dist/setup/onboarding.js +472 -0
  107. package/dist/setup/onboarding.js.map +1 -0
  108. package/dist/setup/package.d.ts +2 -0
  109. package/dist/setup/package.js +8 -0
  110. package/dist/setup/package.js.map +1 -0
  111. package/dist/setup/planning-workflow.d.ts +3 -0
  112. package/dist/setup/planning-workflow.js +250 -0
  113. package/dist/setup/planning-workflow.js.map +1 -0
  114. package/dist/setup/repository-map.d.ts +34 -0
  115. package/dist/setup/repository-map.js +89 -0
  116. package/dist/setup/repository-map.js.map +1 -0
  117. package/dist/setup/review.d.ts +8 -0
  118. package/dist/setup/review.js +137 -0
  119. package/dist/setup/review.js.map +1 -0
  120. package/dist/setup/team.d.ts +18 -0
  121. package/dist/setup/team.js +172 -0
  122. package/dist/setup/team.js.map +1 -0
  123. package/dist/setup/templates.d.ts +11 -0
  124. package/dist/setup/templates.js +494 -0
  125. package/dist/setup/templates.js.map +1 -0
  126. package/dist/setup/terminal.d.ts +12 -0
  127. package/dist/setup/terminal.js +11 -0
  128. package/dist/setup/terminal.js.map +1 -0
  129. package/dist/setup/update.d.ts +6 -0
  130. package/dist/setup/update.js +71 -0
  131. package/dist/setup/update.js.map +1 -0
  132. package/dist/specification/batch.d.ts +50 -0
  133. package/dist/specification/batch.js +127 -0
  134. package/dist/specification/batch.js.map +1 -0
  135. package/dist/specification/plan-checks.d.ts +6 -0
  136. package/dist/specification/plan-checks.js +73 -0
  137. package/dist/specification/plan-checks.js.map +1 -0
  138. package/dist/specification/planning.d.ts +26 -0
  139. package/dist/specification/planning.js +507 -0
  140. package/dist/specification/planning.js.map +1 -0
  141. package/dist/specification/prose.d.ts +1 -0
  142. package/dist/specification/prose.js +15 -0
  143. package/dist/specification/prose.js.map +1 -0
  144. package/dist/tracking/ado.d.ts +19 -0
  145. package/dist/tracking/ado.js +128 -0
  146. package/dist/tracking/ado.js.map +1 -0
  147. package/dist/tracking/github.d.ts +8 -0
  148. package/dist/tracking/github.js +112 -0
  149. package/dist/tracking/github.js.map +1 -0
  150. package/dist/tracking/issues.d.ts +28 -0
  151. package/dist/tracking/issues.js +180 -0
  152. package/dist/tracking/issues.js.map +1 -0
  153. package/dist/tracking/native.d.ts +5 -0
  154. package/dist/tracking/native.js +30 -0
  155. package/dist/tracking/native.js.map +1 -0
  156. package/dist/tracking/refs.d.ts +14 -0
  157. package/dist/tracking/refs.js +56 -0
  158. package/dist/tracking/refs.js.map +1 -0
  159. package/dist/tracking/sources.d.ts +5 -0
  160. package/dist/tracking/sources.js +29 -0
  161. package/dist/tracking/sources.js.map +1 -0
  162. package/docs/operations.md +1114 -0
  163. package/examples/batch.json +27 -0
  164. package/examples/runs.json +22 -0
  165. package/package.json +50 -0
@@ -0,0 +1,19 @@
1
+ import type { Config } from "../config.js";
2
+ import type { Batch, Task } from "../specification/batch.js";
3
+ import { type GitHubApi } from "./github.js";
4
+ import type { Work } from "../execution/dispatch.js";
5
+ export interface Source {
6
+ uri: string;
7
+ revision: string;
8
+ text: string;
9
+ fingerprint: string;
10
+ }
11
+ export interface AdoApi {
12
+ request(method: string, resource: string, body?: unknown, patch?: boolean): Promise<unknown>;
13
+ }
14
+ export declare function adoApi(config: NonNullable<Config["ado"]>, token: string, fetcher?: typeof fetch): AdoApi;
15
+ export declare function importWorkItem(client: AdoApi, config: NonNullable<Config["ado"]>, id: number): Promise<Source>;
16
+ export declare function createWorkItem(client: AdoApi, config: NonNullable<Config["ado"]>, batch: Batch, task: Task): Promise<number>;
17
+ export declare function writeBack(client: AdoApi, id: number, links: string[], message: string): Promise<boolean>;
18
+ export declare function linkAdo(github: GitHubApi, config: Config, issue: number, workItem: number): Promise<void>;
19
+ export declare function syncAdo(github: GitHubApi, ado: AdoApi, config: Config, work: Work[]): Promise<void>;
@@ -0,0 +1,128 @@
1
+ import { hash, integer, record, string } from "../core.js";
2
+ import { isWriter } from "./github.js";
3
+ import { linkedPull } from "../execution/dispatch.js";
4
+ export function adoApi(config, token, fetcher = fetch) {
5
+ if (!token.trim())
6
+ throw new Error("Set CREWBIE_ADO_TOKEN in a credential store before using ADO.");
7
+ const base = `https://dev.azure.com/${encodeURIComponent(config.organization)}/${encodeURIComponent(config.project)}/_apis/wit`;
8
+ return {
9
+ async request(method, resource, body, patch = false) {
10
+ if (!resource.startsWith("/") || resource.startsWith("//") || resource.includes("://"))
11
+ throw new Error("Invalid ADO resource.");
12
+ const version = resource.includes("/comments") ? "7.1-preview.4" : "7.1";
13
+ const response = await fetcher(`${base}${resource}${resource.includes("?") ? "&" : "?"}api-version=${version}`, {
14
+ method, headers: {
15
+ Authorization: `Basic ${Buffer.from(`:${token}`).toString("base64")}`,
16
+ "Content-Type": patch ? "application/json-patch+json" : "application/json",
17
+ }, ...(body === undefined ? {} : { body: JSON.stringify(body) }),
18
+ redirect: "error", signal: AbortSignal.timeout(30_000),
19
+ });
20
+ if (!response.ok)
21
+ throw new Error(`ADO HTTP ${response.status}. Check access and project/type configuration; reconcile unknown write outcomes before retrying.`);
22
+ return response.status === 204 ? null : response.json();
23
+ },
24
+ };
25
+ }
26
+ export async function importWorkItem(client, config, id) {
27
+ integer(id, "work item ID");
28
+ const item = record(await client.request("GET", `/workitems/${id}`), "ADO work item");
29
+ const fields = record(item.fields, "ADO fields");
30
+ const title = string(fields["System.Title"], "ADO title");
31
+ const description = fields["System.Description"];
32
+ const criteria = fields["Microsoft.VSTS.Common.AcceptanceCriteria"];
33
+ const content = [title, typeof description === "string" ? description : "", typeof criteria === "string" ? criteria : ""].filter(Boolean).join("\n\n");
34
+ return {
35
+ uri: `https://dev.azure.com/${encodeURIComponent(config.organization)}/${encodeURIComponent(config.project)}/_workitems/edit/${id}`,
36
+ revision: String(integer(item.rev, "ADO revision")),
37
+ text: content, fingerprint: hash(content),
38
+ };
39
+ }
40
+ function html(text) {
41
+ return `<pre>${text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")}</pre>`;
42
+ }
43
+ export async function createWorkItem(client, config, batch, task) {
44
+ const marker = `Crewbie-${hash(`${batch.id}/${task.id}`).slice(0, 24)}`;
45
+ const query = record(await client.request("POST", "/wiql", { query: `SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = @project AND [System.Tags] CONTAINS '${marker}'` }), "ADO query");
46
+ if (!Array.isArray(query.workItems))
47
+ throw new Error("ADO returned no work item list.");
48
+ if (query.workItems.length > 1)
49
+ throw new Error(`Multiple ADO work items match ${task.id}. Resolve the mapping before retrying.`);
50
+ if (query.workItems.length === 1) {
51
+ const existing = record(query.workItems[0], "work item reference");
52
+ const id = integer(existing.id, "ADO work item ID");
53
+ const item = record(await client.request("GET", `/workitems/${id}`), "existing ADO item");
54
+ const fields = record(item.fields, "existing ADO fields");
55
+ if (fields["System.Title"] !== task.title || fields["System.Description"] !== html(task.body)) {
56
+ throw new Error(`ADO work item ${id} drifted from the approved task. Reconcile rather than overwrite.`);
57
+ }
58
+ return id;
59
+ }
60
+ const created = record(await client.request("POST", `/workitems/$${encodeURIComponent(config.workItemType)}`, [
61
+ { op: "add", path: "/fields/System.Title", value: task.title },
62
+ { op: "add", path: "/fields/System.Description", value: html(task.body) },
63
+ { op: "add", path: "/fields/System.Tags", value: marker },
64
+ ], true), "created ADO item");
65
+ return integer(created.id, "created work item ID");
66
+ }
67
+ export async function writeBack(client, id, links, message) {
68
+ integer(id, "work item ID");
69
+ if (links.some((link) => !/^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/(?:issues|pull)\/\d+$/.test(link))) {
70
+ throw new Error("Write-back links must be GitHub issue or PR URLs.");
71
+ }
72
+ if (message.length > 2000)
73
+ throw new Error("Write-back must be concise.");
74
+ const marker = `[Crewbie:${hash(JSON.stringify({ links: [...links].sort(), message })).slice(0, 24)}]`;
75
+ let continuation = "";
76
+ for (let page = 0; page < 100; page++) {
77
+ const response = record(await client.request("GET", `/workitems/${id}/comments?$top=100${continuation ? `&continuationToken=${encodeURIComponent(continuation)}` : ""}`), "ADO comments");
78
+ if (!Array.isArray(response.comments))
79
+ throw new Error("ADO returned an invalid comments page.");
80
+ if (response.comments.some((item) => String(record(item, "ADO comment").text ?? "").includes(marker)))
81
+ return false;
82
+ if (response.continuationToken === undefined || response.continuationToken === null || response.continuationToken === "") {
83
+ await client.request("POST", `/workitems/${id}/comments`, { text: `${message}\n\n${links.join("\n")}\n\n${marker}` });
84
+ return true;
85
+ }
86
+ continuation = string(response.continuationToken, "ADO continuation token");
87
+ }
88
+ throw new Error("ADO comment pagination exceeded the safety limit; no comment was posted.");
89
+ }
90
+ export async function linkAdo(github, config, issue, workItem) {
91
+ if (!config.ado)
92
+ throw new Error("ADO is not configured.");
93
+ const body = `Crewbie ADO: ${config.ado.organization}/${config.ado.project}#${workItem}`;
94
+ const path = `/repos/${config.repository}/issues/${issue}/comments`;
95
+ const comments = await github.list(path);
96
+ let exists = false;
97
+ for (const comment of comments)
98
+ if (comment.body === body && await isWriter(github, config.repository, comment.user))
99
+ exists = true;
100
+ if (!exists) {
101
+ await github.request("POST", path, { body });
102
+ }
103
+ }
104
+ export async function syncAdo(github, ado, config, work) {
105
+ if (!config.ado)
106
+ throw new Error("ADO is not configured.");
107
+ for (const item of work) {
108
+ const issue = integer(item.issue.number, "issue number");
109
+ const comments = await github.list(`/repos/${config.repository}/issues/${issue}/comments`);
110
+ const prefix = `Crewbie ADO: ${config.ado.organization}/${config.ado.project}#`;
111
+ const links = [];
112
+ for (const comment of comments) {
113
+ if (typeof comment.body === "string" && comment.body.startsWith(prefix) && await isWriter(github, config.repository, comment.user))
114
+ links.push(comment);
115
+ }
116
+ const ids = [...new Set(links.map((comment) => integer(Number(String(comment.body).slice(prefix.length)), "linked ADO ID")))];
117
+ if (ids.length > 1)
118
+ throw new Error(`Issue #${issue} has conflicting ADO links. Reconcile them before write-back.`);
119
+ if (!ids[0])
120
+ continue;
121
+ const urls = [`https://github.com/${config.repository}/issues/${issue}`];
122
+ const pr = await linkedPull(github, config.repository, issue, item.metadata.branch);
123
+ if (pr)
124
+ urls.push(`https://github.com/${config.repository}/pull/${integer(pr.number, "PR number")}`);
125
+ await writeBack(ado, ids[0], urls, `Crewbie status: ${item.state}. ${item.reason}`);
126
+ }
127
+ }
128
+ //# sourceMappingURL=ado.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ado.js","sourceRoot":"","sources":["../../src/tracking/ado.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface GitHubApi {
2
+ request(method: string, path: string, body?: unknown): Promise<unknown>;
3
+ list(path: string): Promise<Record<string, unknown>[]>;
4
+ }
5
+ export declare function isUser(value: unknown): boolean;
6
+ export declare function isWriter(client: GitHubApi, repository: string, value: unknown): Promise<boolean>;
7
+ export declare function api(token: string, fetcher?: typeof fetch): GitHubApi;
8
+ export declare function requireWriter(client: GitHubApi, repository: string): Promise<string>;
@@ -0,0 +1,112 @@
1
+ import { GitHubError, record } from "../core.js";
2
+ import { redact } from "../setup/inventory.js";
3
+ import { setTimeout } from "node:timers/promises";
4
+ const WRITER_PERMISSIONS = new Set(["admin", "maintain", "write"]);
5
+ const writerCache = new WeakMap();
6
+ export function isUser(value) {
7
+ if (value === null || value === undefined)
8
+ return false;
9
+ const user = record(value, "GitHub author");
10
+ return user.type === "User" && typeof user.login === "string";
11
+ }
12
+ export async function isWriter(client, repository, value) {
13
+ if (!isUser(value))
14
+ return false;
15
+ const login = String(record(value, "GitHub author").login);
16
+ const key = `${repository.toLowerCase()}:${login.toLowerCase()}`;
17
+ let cache = writerCache.get(client);
18
+ if (!cache) {
19
+ cache = new Map();
20
+ writerCache.set(client, cache);
21
+ }
22
+ const cached = cache.get(key);
23
+ if (cached !== undefined)
24
+ return cached;
25
+ let authorized = false;
26
+ try {
27
+ const result = record(await client.request("GET", `/repos/${repository}/collaborators/${encodeURIComponent(login)}/permission`), "repository permission");
28
+ const permission = typeof result.permission === "string" ? result.permission.toLowerCase() : "";
29
+ const role = typeof result.role_name === "string" ? result.role_name.toLowerCase() : "";
30
+ authorized = WRITER_PERMISSIONS.has(permission) || WRITER_PERMISSIONS.has(role);
31
+ }
32
+ catch (error) {
33
+ if (!(error instanceof GitHubError && error.status === 404))
34
+ throw error;
35
+ }
36
+ cache.set(key, authorized);
37
+ return authorized;
38
+ }
39
+ export function api(token, fetcher = fetch) {
40
+ if (!token.trim())
41
+ throw new Error("A GitHub user-authorized credential is required.");
42
+ async function request(method, path, body) {
43
+ if (!path.startsWith("/") || path.startsWith("//") || path.includes("://"))
44
+ throw new Error("GitHub requests must use an API-relative path.");
45
+ const readOnly = method === "GET" || (method === "POST" && path === "/graphql"
46
+ && typeof body === "object" && body !== null && "query" in body && typeof body.query === "string"
47
+ && /^\s*query(?:\s|\()/.test(body.query) && !/\bmutation\b/.test(body.query));
48
+ for (let attempt = 0;; attempt++) {
49
+ const response = await fetcher(`https://api.github.com${path}`, {
50
+ method, headers: {
51
+ Accept: "application/vnd.github+json", Authorization: `Bearer ${token}`,
52
+ "X-GitHub-Api-Version": "2022-11-28", "Content-Type": "application/json",
53
+ }, ...(body === undefined ? {} : { body: JSON.stringify(body) }),
54
+ redirect: "error", signal: AbortSignal.timeout(30_000),
55
+ });
56
+ if (!response.ok) {
57
+ if (readOnly && attempt < 2 && [502, 503, 504].includes(response.status)) {
58
+ const retryAfter = response.headers.get("retry-after");
59
+ const wait = retryAfter === null ? 1000 * 2 ** attempt
60
+ : /^\d+$/.test(retryAfter) ? Number(retryAfter) * 1000 : Math.max(0, Date.parse(retryAfter) - Date.now());
61
+ if (Number.isFinite(wait) && wait <= 30_000) {
62
+ console.warn(`Crewbie: transient HTTP ${response.status} reading ${path}; retry ${attempt + 1}/2 in ${wait}ms.`);
63
+ await setTimeout(wait);
64
+ continue;
65
+ }
66
+ }
67
+ const error = new GitHubError(response.status, response.headers.get("x-github-request-id"));
68
+ error.message += ` Operation: ${method} ${path}.`;
69
+ // GitHub's own message (for example which permission or policy refused) is the actionable part of a 4xx.
70
+ const said = await response.text().then((text) => { try {
71
+ return JSON.parse(text).message;
72
+ }
73
+ catch {
74
+ return undefined;
75
+ } }, () => undefined);
76
+ if (typeof said === "string" && said.trim())
77
+ error.message += ` GitHub said: ${redact(said.trim().replace(/\s+/g, " ").slice(0, 300))}`;
78
+ throw error;
79
+ }
80
+ if (response.status === 204)
81
+ return null;
82
+ if (response.status === 202) {
83
+ const text = await response.text();
84
+ return text.trim() ? JSON.parse(text) : null;
85
+ }
86
+ return response.json();
87
+ }
88
+ }
89
+ return {
90
+ request,
91
+ async list(path) {
92
+ const all = [];
93
+ for (let page = 1; page <= 100; page++) {
94
+ const value = await request("GET", `${path}${path.includes("?") ? "&" : "?"}per_page=100&page=${page}`);
95
+ if (!Array.isArray(value))
96
+ throw new Error("GitHub returned an invalid paginated response.");
97
+ all.push(...value.map((item) => record(item, "GitHub list item")));
98
+ if (value.length < 100)
99
+ return all;
100
+ }
101
+ throw new Error("GitHub pagination exceeded the safety limit. Narrow the requested data.");
102
+ },
103
+ };
104
+ }
105
+ export async function requireWriter(client, repository) {
106
+ const user = record(await client.request("GET", "/user"), "authenticated user");
107
+ if (!await isWriter(client, repository, user) || typeof user.login !== "string") {
108
+ throw new Error(`The authenticated GitHub user needs write access to ${repository}.`);
109
+ }
110
+ return user.login;
111
+ }
112
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/tracking/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Config } from "../config.js";
2
+ import { type Batch } from "../specification/batch.js";
3
+ import { type GitHubApi } from "./github.js";
4
+ import type { AdoApi } from "./ado.js";
5
+ export declare const STATUSES: readonly ["blocked", "ready", "running", "review", "failed", "done"];
6
+ export declare function setupLabels(config: Config): string[];
7
+ export declare function labelDescription(name: string): string;
8
+ export declare function ensureLabels(client: GitHubApi, config: Config): Promise<void>;
9
+ export declare function managedIssues(client: GitHubApi, repository: string, state?: "all" | "open" | "closed", since?: Date): Promise<Record<string, unknown>[]>;
10
+ export declare function approvalComment(digest: string, execute: boolean): string;
11
+ export declare function hasApproval(client: GitHubApi, config: Config, issue: Record<string, unknown>, execute?: boolean): Promise<boolean>;
12
+ /**
13
+ * Moves approved task issues to their owner's current configured model and re-approves the exact new title and body.
14
+ * Only the model in the task metadata changes; scope, owner and dependencies stay bound to the original approval.
15
+ */
16
+ export declare function reapproveIssues(client: GitHubApi, config: Config, issues: number[], apply: boolean): Promise<string>;
17
+ /** hasApproval over comments the caller already fetched. */
18
+ export declare function approvedIn(client: GitHubApi, comments: Record<string, unknown>[], config: Config, issue: Record<string, unknown>, execute?: boolean): Promise<boolean>;
19
+ export declare function publish(client: GitHubApi, config: Config, batch: Batch, ado?: AdoApi, dispatchWorkflow?: boolean): Promise<{
20
+ task: string;
21
+ issue: number;
22
+ }[]>;
23
+ export declare function setStatus(client: GitHubApi, repo: string, issue: Record<string, unknown>, status: typeof STATUSES[number]): Promise<void>;
24
+ export declare function publishDescription(client: GitHubApi, config: Config, number: number, proposal: unknown, apply?: boolean): Promise<{
25
+ before: string;
26
+ after: string;
27
+ headSha: string;
28
+ }>;
@@ -0,0 +1,180 @@
1
+ import { limitsFor, PLANNING_LABEL, RESTART_LABEL, requireExecution } from "../config.js";
2
+ import { GitHubError, hash, integer, record, string } from "../core.js";
3
+ import { checkPrDescription } from "../specification/prose.js";
4
+ import { batchDigest, issueBody, issueDigest, requireApproval, taskMetadata } from "../specification/batch.js";
5
+ import { isWriter, requireWriter } from "./github.js";
6
+ import { ledgerHas } from "./refs.js";
7
+ import { verifySources } from "./sources.js";
8
+ export const STATUSES = ["blocked", "ready", "running", "review", "failed", "done"];
9
+ export function setupLabels(config) {
10
+ return ["crewbie:managed", PLANNING_LABEL, RESTART_LABEL, ...STATUSES.map((status) => `crewbie:${status}`), ...config.roles.map((role) => `crewbie:owner:${role.id}`)];
11
+ }
12
+ const LABEL_PURPOSES = {
13
+ [RESTART_LABEL]: "Write-access request: relaunch a task whose previous session ended; counts as an attempt.",
14
+ };
15
+ export function labelDescription(name) {
16
+ return LABEL_PURPOSES[name] ?? "Crewbie workflow metadata; approval and prerequisites are checked separately.";
17
+ }
18
+ export async function ensureLabels(client, config) {
19
+ const prefix = `/repos/${config.repository}`;
20
+ const existing = new Set((await client.list(`${prefix}/labels`)).map((label) => label.name));
21
+ const labels = setupLabels(config);
22
+ for (const name of labels) {
23
+ if (!existing.has(name))
24
+ await client.request("POST", `${prefix}/labels`, { name, color: "b11f4b",
25
+ description: labelDescription(name) });
26
+ }
27
+ }
28
+ export async function managedIssues(client, repository, state = "all", since) {
29
+ return (await client.list(`/repos/${repository}/issues?state=${state}&labels=crewbie%3Amanaged${since ? `&since=${since.toISOString()}` : ""}`)).filter((issue) => !issue.pull_request);
30
+ }
31
+ export function approvalComment(digest, execute) {
32
+ return `Crewbie approval: ${digest}\nExecution: ${execute ? "approved" : "not-approved"}\n\nScope, specialist, model, and dependencies are bound to the issue's exact title and body.`;
33
+ }
34
+ export async function hasApproval(client, config, issue, execute = true) {
35
+ string(issue.body, "issue body");
36
+ const comments = await client.list(`/repos/${config.repository}/issues/${integer(issue.number, "issue number")}/comments`);
37
+ return approvedIn(client, comments, config, issue, execute);
38
+ }
39
+ /**
40
+ * Moves approved task issues to their owner's current configured model and re-approves the exact new title and body.
41
+ * Only the model in the task metadata changes; scope, owner and dependencies stay bound to the original approval.
42
+ */
43
+ export async function reapproveIssues(client, config, issues, apply) {
44
+ const lines = [];
45
+ const changes = [];
46
+ for (const number of issues) {
47
+ const issue = record(await client.request("GET", `/repos/${config.repository}/issues/${number}`), "task issue");
48
+ if (issue.state !== "open")
49
+ throw new Error(`Issue #${number} is closed; only open tasks can be re-approved.`);
50
+ const body = string(issue.body, "issue body");
51
+ const title = string(issue.title, "issue title");
52
+ const metadata = taskMetadata(body);
53
+ if (!metadata)
54
+ throw new Error(`Issue #${number} is not a Crewbie task.`);
55
+ const role = config.roles.find((role) => role.id === metadata.task.owner);
56
+ if (!role)
57
+ throw new Error(`Issue #${number}'s owner ${metadata.task.owner} is not a configured role. Replan it instead.`);
58
+ const payload = { ...metadata, task: { ...metadata.task, model: role.model } };
59
+ const next = body.replace(/<!-- crewbie-task:[A-Za-z0-9+/=]+ -->/, `<!-- crewbie-task:${Buffer.from(JSON.stringify(payload)).toString("base64")} -->`);
60
+ const comments = await client.list(`/repos/${config.repository}/issues/${number}/comments`);
61
+ if (next === body && await approvedIn(client, comments, config, issue)) {
62
+ lines.push(`#${number}: already approved for crewbie-${role.id} on ${role.model}; nothing to change.`);
63
+ continue;
64
+ }
65
+ const claimed = await ledgerHas(client, config.repository, `claims/${number}`);
66
+ changes.push({ number, body: next, title, claimed });
67
+ lines.push(`#${number}: ${next === body ? "re-approve" : `model ${metadata.task.model} -> ${role.model}`} for crewbie-${role.id}${claimed ? `; add ${RESTART_LABEL} afterwards to relaunch it` : ""}.`);
68
+ }
69
+ if (!apply)
70
+ return `Preview:\n${lines.join("\n")}\nRepeat with --apply to update the issues and post your execution approval. No agents are started.`;
71
+ if (changes.length)
72
+ await requireWriter(client, config.repository);
73
+ for (const change of changes) {
74
+ await client.request("PATCH", `/repos/${config.repository}/issues/${change.number}`, { body: change.body });
75
+ await client.request("POST", `/repos/${config.repository}/issues/${change.number}/comments`, { body: approvalComment(issueDigest(change.title, change.body), true) });
76
+ }
77
+ return `${lines.join("\n")}\n${changes.length ? "Updated and re-approved. No agents were started; dispatch launches unclaimed tasks on its next run." : "Nothing to change."}`;
78
+ }
79
+ /** hasApproval over comments the caller already fetched. */
80
+ export async function approvedIn(client, comments, config, issue, execute = true) {
81
+ const expected = approvalComment(issueDigest(string(issue.title, "issue title"), string(issue.body, "issue body")), execute);
82
+ for (const comment of comments) {
83
+ if (comment.body === expected && comment.created_at === comment.updated_at && await isWriter(client, config.repository, comment.user))
84
+ return true;
85
+ }
86
+ return false;
87
+ }
88
+ export async function publish(client, config, batch, ado, dispatchWorkflow = true) {
89
+ requireExecution(config);
90
+ requireApproval(batch);
91
+ await requireWriter(client, config.repository);
92
+ await verifySources(batch.sources, client, config, ado);
93
+ await ensureLabels(client, config);
94
+ const existing = await managedIssues(client, config.repository);
95
+ const results = [];
96
+ try {
97
+ for (const task of batch.tasks) {
98
+ const candidates = existing.filter((issue) => {
99
+ const data = taskMetadata(String(issue.body ?? ""));
100
+ // A closed issue from an earlier approved revision of this batch is superseded, not a conflict.
101
+ return data?.batch === batch.id && data.task.id === task.id && !(issue.state === "closed" && data.batchDigest !== batchDigest(batch));
102
+ });
103
+ if (candidates.length > 1)
104
+ throw new Error(`Multiple issues represent ${batch.id}/${task.id}. Reconcile before publishing.`);
105
+ const body = issueBody(batch, task);
106
+ let issue = candidates[0];
107
+ if (issue) {
108
+ const metadata = taskMetadata(String(issue.body ?? ""));
109
+ if (metadata?.batchDigest !== batchDigest(batch) || issue.body !== body || issue.title !== task.title) {
110
+ throw new Error(`Published ${task.id} differs from the approved batch. Reconcile the issue explicitly; no overwrite was attempted.`);
111
+ }
112
+ }
113
+ else {
114
+ issue = record(await client.request("POST", `/repos/${config.repository}/issues`, {
115
+ title: task.title, body, labels: ["crewbie:managed", `crewbie:owner:${task.owner}`, "crewbie:blocked"],
116
+ }), "created issue");
117
+ existing.push(issue);
118
+ }
119
+ const number = integer(issue.number, "issue number");
120
+ if (!await hasApproval(client, config, issue, batch.approval?.execute === true)) {
121
+ await client.request("POST", `/repos/${config.repository}/issues/${number}/comments`, { body: approvalComment(issueDigest(task.title, body), batch.approval?.execute === true) });
122
+ }
123
+ results.push({ task: task.id, issue: number });
124
+ }
125
+ // GITHUB_TOKEN-originated labels do not reliably trigger another workflow.
126
+ if (batch.approval?.execute && dispatchWorkflow) {
127
+ const metadata = record(await client.request("GET", `/repos/${config.repository}`), "repository");
128
+ await client.request("POST", `/repos/${config.repository}/actions/workflows/crewbie-dispatch.yml/dispatches`, { ref: string(metadata.default_branch, "default branch") });
129
+ }
130
+ return results;
131
+ }
132
+ catch (error) {
133
+ throw new Error(`Publication stopped. Confirmed task/issue mappings: ${JSON.stringify(results)}. Reconcile unknown outcomes before retrying; existing matching issues are reused. ${error instanceof Error ? error.message : "Remote request failed."}`);
134
+ }
135
+ }
136
+ export async function setStatus(client, repo, issue, status) {
137
+ if (!Array.isArray(issue.labels))
138
+ throw new Error("Issue labels are missing.");
139
+ const old = issue.labels.map((label) => typeof label === "string" ? label : string(record(label, "label").name, "label name"));
140
+ const obsolete = old.filter((label) => STATUSES.some((state) => label === `crewbie:${state}`) && label !== `crewbie:${status}`);
141
+ const path = `/repos/${repo}/issues/${integer(issue.number, "issue number")}/labels`;
142
+ if (!old.includes(`crewbie:${status}`))
143
+ await client.request("POST", path, { labels: [`crewbie:${status}`] });
144
+ for (const label of obsolete) {
145
+ // An earlier step of the same run, or a person, may already have removed it.
146
+ try {
147
+ await client.request("DELETE", `${path}/${encodeURIComponent(label)}`);
148
+ }
149
+ catch (error) {
150
+ if (!(error instanceof GitHubError && error.status === 404))
151
+ throw error;
152
+ }
153
+ }
154
+ // Later status changes in this run start from the labels just written.
155
+ issue.labels = [...old.filter((label) => !obsolete.includes(label) && label !== `crewbie:${status}`), `crewbie:${status}`];
156
+ }
157
+ export async function publishDescription(client, config, number, proposal, apply = false) {
158
+ if (!config.repository)
159
+ throw new Error("Configure a repository before finalizing a PR.");
160
+ const data = record(proposal, "PR description proposal");
161
+ const after = string(data.body, "proposed PR description");
162
+ checkPrDescription(after, limitsFor(config).pr);
163
+ const path = `/repos/${config.repository}/pulls/${integer(number, "PR number")}`;
164
+ const pr = record(await client.request("GET", path), "PR");
165
+ const before = typeof pr.body === "string" ? pr.body : "";
166
+ const headSha = string(record(pr.head, "PR head").sha, "PR revision");
167
+ if (pr.state !== "open")
168
+ throw new Error("Only an open PR can be finalized.");
169
+ if (headSha !== string(data.headSha, "expected head revision") || hash(before) !== string(data.beforeHash, "expected description hash")) {
170
+ throw new Error("PR head or description changed. Review a fresh proposal; nothing was overwritten.");
171
+ }
172
+ if (apply) {
173
+ await requireWriter(client, config.repository);
174
+ const updated = record(await client.request("PATCH", path, { body: after }), "updated PR");
175
+ if (updated.body !== after)
176
+ throw new Error("GitHub did not confirm the proposed description. Inspect the PR before retrying.");
177
+ }
178
+ return { before, after, headSha };
179
+ }
180
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/tracking/issues.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { GitHubApi } from "./github.js";
2
+ export declare function cloudTasks(client: GitHubApi, repo: string): Promise<{
3
+ tasks: Record<string, unknown>[];
4
+ warning: string | null;
5
+ }>;
@@ -0,0 +1,30 @@
1
+ import { GitHubError, record, string } from "../core.js";
2
+ export async function cloudTasks(client, repo) {
3
+ const tasks = [];
4
+ const ids = new Set();
5
+ try {
6
+ for (let page = 1; page <= 100; page++) {
7
+ const response = record(await client.request("GET", `/agents/repos/${repo}/tasks?per_page=100&page=${page}`), "cloud tasks");
8
+ if (!Array.isArray(response.tasks))
9
+ throw new Error("GitHub returned invalid cloud task telemetry.");
10
+ for (const raw of response.tasks) {
11
+ const task = record(raw, "cloud task");
12
+ const id = string(task.id, "cloud task ID");
13
+ if (ids.has(id))
14
+ throw new Error("Cloud task pagination did not advance; session capacity remains unverified.");
15
+ ids.add(id);
16
+ tasks.push(task);
17
+ }
18
+ if (response.tasks.length < 100)
19
+ return { tasks, warning: null };
20
+ }
21
+ throw new Error("Cloud task pagination exceeded the safety limit; inspect session capacity before dispatch.");
22
+ }
23
+ catch (error) {
24
+ if (error instanceof GitHubError && [403, 404].includes(error.status)) {
25
+ return { tasks: [], warning: `Cloud session status is unavailable (HTTP ${error.status}); capacity remains reserved.` };
26
+ }
27
+ throw error;
28
+ }
29
+ }
30
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../../src/tracking/native.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGzD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAiB,EAAE,IAAY;IAC9D,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,IAAI,CAAC;QACH,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,iBAAiB,IAAI,4BAA4B,IAAI,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC;YAC7H,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;YACrG,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;gBACvC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;gBAC5C,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;gBAChH,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;YACD,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG;gBAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACnE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,4FAA4F,CAAC,CAAC;IAChH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACtE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,6CAA6C,KAAK,CAAC,MAAM,+BAA+B,EAAE,CAAC;QAC1H,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { GitHubApi } from "./github.js";
2
+ export interface LedgerRef {
3
+ name: string;
4
+ ref: string;
5
+ object?: Record<string, unknown>;
6
+ }
7
+ /** Full ref for a ledger entry, e.g. ledgerRef("claims/3") === "refs/crewbie/claims/3". */
8
+ export declare function ledgerRef(name: string): string;
9
+ export declare function listLedger(client: GitHubApi, repository: string, prefix: string): Promise<LedgerRef[]>;
10
+ export declare function ledgerHas(client: GitHubApi, repository: string, name: string): Promise<boolean>;
11
+ /** Atomically creates a ledger ref; GitHub answers 422 when it already exists. */
12
+ export declare function createLedger(client: GitHubApi, repository: string, name: string, sha: string): Promise<void>;
13
+ /** Deletes the ledger ref; with legacy, deletes whichever of the current and legacy refs exist. */
14
+ export declare function deleteLedger(client: GitHubApi, repository: string, name: string, legacy?: boolean): Promise<void>;