@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
package/dist/config.js ADDED
@@ -0,0 +1,178 @@
1
+ import { bounded, readJson, record, string, strings, slug, integer, safePath } from "./core.js";
2
+ export const PLANNING_LABEL = "crewbie:ready-for-planning";
3
+ export const RESTART_LABEL = "crewbie:restart";
4
+ export const DEFAULT_LIMITS = { spec: 600, hot: 600, constitution: 600, topic: 1500 };
5
+ export const DEFAULT_EXECUTION_LIMITS = { maxLaunchesPerBatch: 20, maxAttemptsPerTask: 3 };
6
+ export const DEFAULT_MERGE = { method: "merge" };
7
+ export function modelProfile(value) {
8
+ if (value !== "economy" && value !== "balanced" && value !== "quality")
9
+ throw new Error("Model profile must be economy, balanced or quality.");
10
+ return value;
11
+ }
12
+ export function mergeFor(config) { return config.merge ?? DEFAULT_MERGE; }
13
+ /** The enabled reviewer of feature PRs and the model it runs with, or null when PR review is off. */
14
+ export function reviewerFor(config) {
15
+ if (!config.review?.enabled)
16
+ return null;
17
+ const role = config.roles.find((role) => role.id === config.review?.role);
18
+ if (!role)
19
+ throw new Error(`review.role ${config.review.role} is not a configured role.`);
20
+ return { role: role.id, model: config.review.model ?? role.model };
21
+ }
22
+ export function limitsFor(config) { return config?.limits ?? DEFAULT_LIMITS; }
23
+ export function isRoleContextPath(path) {
24
+ return /^(?:[A-Za-z0-9._ -]+\/)*[A-Za-z0-9._ -]+\.md$/i.test(path)
25
+ && !path.includes("..") && !path.toLowerCase().startsWith(".git/");
26
+ }
27
+ export function isExistingAgentPath(path) {
28
+ return /^(?:\.github\/agents\/[A-Za-z0-9._-]+\.agent\.md|\.claude\/agents\/[A-Za-z0-9._-]+\.md)$/.test(path)
29
+ && !path.includes("..") && !/\/crewbie-/i.test(path);
30
+ }
31
+ export function agentArchivePath(path) { return `.crewbie/agent-archive/${path.replace(/^\./, "")}`; }
32
+ export function parseConfig(value) {
33
+ const data = record(value, "Configuration");
34
+ if (data.schemaVersion !== 1)
35
+ throw new Error("Unsupported configuration version.");
36
+ const repository = string(data.repository, "repository", true);
37
+ if (repository && !/^[A-Za-z0-9-]+\/[A-Za-z0-9_.-]+$/.test(repository))
38
+ throw new Error("repository must be owner/name.");
39
+ if (data.approvers !== undefined) {
40
+ const approvers = strings(data.approvers, "approvers");
41
+ if (approvers.some((login) => !/^[A-Za-z0-9-]+$/.test(login)))
42
+ throw new Error("Approvers must be GitHub user logins.");
43
+ }
44
+ if (!Array.isArray(data.roles) || !data.roles.length)
45
+ throw new Error("Define at least one role.");
46
+ const roles = data.roles.map((value) => {
47
+ const role = record(value, "role");
48
+ const result = { id: slug(role.id, "role id"), purpose: string(role.purpose, "role purpose"), model: string(role.model, "role model", true) };
49
+ if (result.model.trim().toLowerCase() === "auto")
50
+ throw new Error("Choose an explicit approved model, not auto.");
51
+ if (["coordinator", "improver"].includes(result.id))
52
+ throw new Error(`${result.id} is reserved for a framework role.`);
53
+ const guidance = {};
54
+ for (const key of ["checks", "nonNegotiables", "contextPaths"]) {
55
+ if (role[key] === undefined)
56
+ continue;
57
+ const entries = strings(role[key], `role ${key}`);
58
+ if (entries.length > 10 || entries.some((entry) => !entry.trim()))
59
+ throw new Error(`Role ${key} needs at most ten nonempty entries.`);
60
+ guidance[key] = entries;
61
+ }
62
+ const invalidPath = guidance.contextPaths?.find((path) => !isRoleContextPath(path));
63
+ if (invalidPath !== undefined) {
64
+ throw new Error(`Role ${result.id} contextPaths contains ${JSON.stringify(invalidPath)}; use repository-relative Markdown paths.`);
65
+ }
66
+ const sourceAgent = role.sourceAgent === undefined ? undefined : string(role.sourceAgent, "source agent");
67
+ if (sourceAgent !== undefined && !isExistingAgentPath(sourceAgent))
68
+ throw new Error(`Unsupported source agent: ${sourceAgent}`);
69
+ const complexity = role.complexity;
70
+ if (complexity !== undefined && complexity !== "routine" && complexity !== "standard" && complexity !== "complex")
71
+ throw new Error("Role complexity must be routine, standard or complex.");
72
+ return { ...result, ...guidance, ...(sourceAgent === undefined ? {} : { sourceAgent }),
73
+ ...(complexity === undefined ? {} : { complexity }),
74
+ ...(role.modelReason === undefined ? {} : { modelReason: string(role.modelReason, "model selection reason") }) };
75
+ });
76
+ if (new Set(roles.map((role) => role.id)).size !== roles.length)
77
+ throw new Error("Role IDs must be unique.");
78
+ const adopted = roles.flatMap((role) => role.sourceAgent ? [role.sourceAgent] : []);
79
+ if (new Set(adopted).size !== adopted.length)
80
+ throw new Error("Each existing agent can be adopted by only one Crewbie specialist.");
81
+ const nightly = record(data.nightly, "nightly");
82
+ if (typeof nightly.enabled !== "boolean")
83
+ throw new Error("nightly.enabled must be true or false.");
84
+ const allowedPaths = strings(nightly.allowedPaths, "nightly.allowedPaths");
85
+ for (const path of allowedPaths) {
86
+ const instruction = path === "AGENTS.md" || path === ".github/copilot-instructions.md" || /^\.github\/instructions\/[a-z0-9._-]+\.instructions\.md$/.test(path);
87
+ const constitutionPath = typeof data.constitution === "string" && path === data.constitution && path.endsWith(".md");
88
+ if ((!/^(?:\.crewbie\/(?:team|decisions)\/|\.crewbie\/(?:decisions|constitution|instructions)\.md$|\.github\/agents\/crewbie-[a-z0-9-]+\.agent\.md$)/.test(path) && !instruction && !constitutionPath) || path.includes("..") || path.includes("\\") || path.startsWith("/") || path.includes(":")) {
89
+ throw new Error(`Nightly path is not a supported managed memory/profile path: ${path}`);
90
+ }
91
+ }
92
+ const constitution = data.constitution === null ? null : string(data.constitution, "constitution");
93
+ if (constitution && !constitution.endsWith(".md"))
94
+ throw new Error("The constitution must reference a Markdown document.");
95
+ const adoData = data.ado === null ? null : record(data.ado, "ado");
96
+ const ado = adoData === null ? null : {
97
+ organization: string(adoData.organization, "ADO organization"),
98
+ project: string(adoData.project, "ADO project"),
99
+ workItemType: string(adoData.workItemType, "ADO work item type"),
100
+ };
101
+ if (ado && !/^[A-Za-z0-9-]+$/.test(ado.organization))
102
+ throw new Error("Use an ADO organization name, not a URL.");
103
+ const rawLimits = data.limits === undefined ? {} : record(data.limits, "word limits");
104
+ const limits = Object.fromEntries(Object.entries(DEFAULT_LIMITS).map(([key, fallback]) => [key, integer(rawLimits[key] ?? fallback, `${key} word limit`, 1, 10000)]));
105
+ if (rawLimits.pr !== undefined)
106
+ limits.pr = integer(rawLimits.pr, "pr word limit", 1, 10000);
107
+ let planning;
108
+ if (data.planning !== undefined) {
109
+ const value = record(data.planning, "planning");
110
+ if (typeof value.enabled !== "boolean")
111
+ throw new Error("planning.enabled must be true or false.");
112
+ const model = string(value.model, "planning.model", !value.enabled);
113
+ if (model && (!/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(model) || model.toLowerCase() === "auto"))
114
+ throw new Error("Choose an explicit planning model identifier, not auto.");
115
+ if (value.executeOnMerge !== undefined && typeof value.executeOnMerge !== "boolean")
116
+ throw new Error("planning.executeOnMerge must be true or false.");
117
+ if (value.executeOnMerge === true && !value.enabled)
118
+ throw new Error("Enable planning before opting into execution on merge.");
119
+ planning = { enabled: value.enabled, model, ...(value.executeOnMerge === undefined ? {} : { executeOnMerge: value.executeOnMerge }) };
120
+ }
121
+ const execution = data.execution === undefined ? undefined : record(data.execution, "execution limits");
122
+ let merge;
123
+ if (data.merge !== undefined) {
124
+ const value = record(data.merge, "merge");
125
+ const method = value.method ?? DEFAULT_MERGE.method;
126
+ if (method !== "merge" && method !== "squash" && method !== "rebase")
127
+ throw new Error("merge.method must be merge, squash or rebase.");
128
+ // Legacy merge.mode and merge.minConfidence are ignored: task PRs always merge into the feature branch.
129
+ merge = { method };
130
+ }
131
+ let review;
132
+ if (data.review !== undefined) {
133
+ const value = record(data.review, "review");
134
+ if (typeof value.enabled !== "boolean")
135
+ throw new Error("review.enabled must be true or false.");
136
+ const role = slug(value.role, "review.role");
137
+ if (value.enabled && !roles.some((item) => item.id === role))
138
+ throw new Error(`review.role ${role} is not a configured role.`);
139
+ const model = value.model === undefined ? undefined : string(value.model, "review.model");
140
+ if (model !== undefined && (!/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(model) || model.toLowerCase() === "auto"))
141
+ throw new Error("Choose an explicit review model identifier, not auto.");
142
+ review = { enabled: value.enabled, role, ...(model === undefined ? {} : { model }) };
143
+ }
144
+ let local;
145
+ if (data.local !== undefined) {
146
+ const value = record(data.local, "local");
147
+ const start = string(value.start, "local.start");
148
+ bounded(start, 120, "local.start");
149
+ local = { start };
150
+ }
151
+ return {
152
+ schemaVersion: 1, repository, roles, constitution,
153
+ maxActive: integer(data.maxActive, "maxActive", 1, 20),
154
+ nightly: { enabled: nightly.enabled, maxRecords: integer(nightly.maxRecords, "maxRecords", 1, 100), allowedPaths },
155
+ ado, limits, ...(planning ? { planning } : {}),
156
+ ...(data.modelProfile === undefined ? {} : { modelProfile: modelProfile(data.modelProfile) }),
157
+ ...(execution === undefined ? {} : { execution: {
158
+ maxLaunchesPerBatch: integer(execution.maxLaunchesPerBatch, "maximum launches per batch", 1, 1000),
159
+ maxAttemptsPerTask: integer(execution.maxAttemptsPerTask, "maximum attempts per task", 1, 100),
160
+ } }),
161
+ ...(merge ? { merge } : {}),
162
+ ...(review ? { review } : {}),
163
+ ...(local ? { local } : {}),
164
+ };
165
+ }
166
+ export async function loadConfig(root) {
167
+ const config = parseConfig(await readJson(await safePath(root, ".crewbie/config.json")));
168
+ if (config.constitution)
169
+ await safePath(root, config.constitution);
170
+ return config;
171
+ }
172
+ export function requireExecution(config) {
173
+ if (!config.repository)
174
+ throw new Error("Configure a repository before remote writes.");
175
+ if (config.roles.some((role) => !role.model.trim()))
176
+ throw new Error("Approve an explicit model for every specialist before execution.");
177
+ }
178
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/core.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ export declare class GitHubError extends Error {
2
+ readonly status: number;
3
+ readonly requestId: string | null;
4
+ constructor(status: number, requestId: string | null);
5
+ }
6
+ export declare function record(value: unknown, name: string): Record<string, unknown>;
7
+ export declare function string(value: unknown, name: string, allowEmpty?: boolean): string;
8
+ export declare function strings(value: unknown, name: string): string[];
9
+ export declare function integer(value: unknown, name: string, min?: number, max?: number): number;
10
+ export declare function slug(value: unknown, name: string): string;
11
+ export declare function hash(value: string): string;
12
+ export declare function textHash(value: string): string;
13
+ export declare function matchesTextHash(value: string, digest: unknown): boolean;
14
+ export declare function json(value: unknown): string;
15
+ export declare function words(value: string): number;
16
+ export declare function bounded(value: string, limit: number, name: string): void;
17
+ export declare const AGENT_PROMPT_CHARACTERS = 30000;
18
+ export declare function agentPromptLength(profile: string): number;
19
+ export declare function agentPrompt(profile: string, name: string, remedy?: string): void;
20
+ export declare function errorCode(error: unknown, code: string): boolean;
21
+ export declare function optionalText(path: string): Promise<string | null>;
22
+ export declare function readJson(path: string): Promise<unknown>;
23
+ /**
24
+ * Parses a model's JSON answer without another paid request, tolerating the prose preambles and Markdown fences
25
+ * models add despite "return only JSON": bare JSON, else the last fenced block holding an object, else the last
26
+ * balanced top-level object in the text. The caller still validates the value's shape.
27
+ */
28
+ export declare function modelJson(output: string, name: string): unknown;
29
+ /** Reject traversal and symlink parents before reading or changing repository files. */
30
+ export declare function safePath(root: string, file: string): Promise<string>;
31
+ export declare function writeAtomic(root: string, file: string, content: string): Promise<void>;
package/dist/core.js ADDED
@@ -0,0 +1,186 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstat, mkdir, readFile, realpath, rename, writeFile } from "node:fs/promises";
3
+ import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
4
+ export class GitHubError extends Error {
5
+ status;
6
+ requestId;
7
+ constructor(status, requestId) {
8
+ const advice = status === 401 ? "Authenticate with a user-authorized GitHub credential."
9
+ : status === 403 ? "Check repository permissions, policy, and rate limits."
10
+ : status === 404 ? "Check the repository, branch, profile, and token access."
11
+ : status === 429 ? "Wait for the rate limit to reset before retrying."
12
+ : "Check GitHub availability and the documented preview interface.";
13
+ super(`GitHub HTTP ${status}. ${advice}${requestId ? ` Request: ${requestId}.` : ""}`);
14
+ this.status = status;
15
+ this.requestId = requestId;
16
+ this.name = "GitHubError";
17
+ }
18
+ }
19
+ export function record(value, name) {
20
+ if (!value || typeof value !== "object" || Array.isArray(value))
21
+ throw new Error(`${name} must be an object.`);
22
+ return value;
23
+ }
24
+ export function string(value, name, allowEmpty = false) {
25
+ if (typeof value !== "string" || (!allowEmpty && !value.trim()))
26
+ throw new Error(`${name} must be text${allowEmpty ? "" : " and cannot be empty"}.`);
27
+ return value;
28
+ }
29
+ export function strings(value, name) {
30
+ if (!Array.isArray(value))
31
+ throw new Error(`${name} must be a list.`);
32
+ return value.map((item) => string(item, name));
33
+ }
34
+ export function integer(value, name, min = 1, max = Number.MAX_SAFE_INTEGER) {
35
+ if (!Number.isSafeInteger(value) || Number(value) < min || Number(value) > max)
36
+ throw new Error(`${name} must be an integer from ${min} to ${max}.`);
37
+ return Number(value);
38
+ }
39
+ export function slug(value, name) {
40
+ const result = string(value, name);
41
+ if (!/^[a-z][a-z0-9-]{0,63}$/.test(result))
42
+ throw new Error(`${name} must start with a letter and contain only lowercase letters, digits, and hyphens.`);
43
+ return result;
44
+ }
45
+ export function hash(value) {
46
+ return createHash("sha256").update(value).digest("hex");
47
+ }
48
+ export function textHash(value) {
49
+ return hash(value.replaceAll("\r\n", "\n"));
50
+ }
51
+ export function matchesTextHash(value, digest) {
52
+ const lf = value.replaceAll("\r\n", "\n");
53
+ // Accept pre-normalization manifests and proposals from either checkout style.
54
+ return digest === hash(lf) || digest === hash(value) || digest === hash(lf.replaceAll("\n", "\r\n"));
55
+ }
56
+ export function json(value) {
57
+ return JSON.stringify(value, null, 2) + "\n";
58
+ }
59
+ export function words(value) {
60
+ return value.trim() ? value.trim().split(/\s+/u).length : 0;
61
+ }
62
+ export function bounded(value, limit, name) {
63
+ if (words(value) > limit)
64
+ throw new Error(`${name} exceeds ${limit} words. Curate or split it; nothing was truncated.`);
65
+ }
66
+ // GitHub's documented maximum for a custom agent's Markdown prompt below the frontmatter:
67
+ // https://docs.github.com/en/copilot/reference/custom-agents-configuration
68
+ export const AGENT_PROMPT_CHARACTERS = 30_000;
69
+ export function agentPromptLength(profile) {
70
+ const text = profile.replace(/^\uFEFF/, "");
71
+ const header = /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/.exec(text);
72
+ return (header ? text.slice(header[0].length) : text).length;
73
+ }
74
+ export function agentPrompt(profile, name, remedy = "Shorten it; nothing was truncated.") {
75
+ const length = agentPromptLength(profile);
76
+ if (length > AGENT_PROMPT_CHARACTERS)
77
+ throw new Error(`${name} prompt has ${length} characters; GitHub custom agents allow at most ${AGENT_PROMPT_CHARACTERS}. ${remedy}`);
78
+ }
79
+ export function errorCode(error, code) {
80
+ return error instanceof Error && "code" in error && error.code === code;
81
+ }
82
+ export async function optionalText(path) {
83
+ try {
84
+ return await readFile(path, "utf8");
85
+ }
86
+ catch (error) {
87
+ if (errorCode(error, "ENOENT"))
88
+ return null;
89
+ throw error;
90
+ }
91
+ }
92
+ export async function readJson(path) {
93
+ return JSON.parse(await readFile(path, "utf8"));
94
+ }
95
+ /**
96
+ * Parses a model's JSON answer without another paid request, tolerating the prose preambles and Markdown fences
97
+ * models add despite "return only JSON": bare JSON, else the last fenced block holding an object, else the last
98
+ * balanced top-level object in the text. The caller still validates the value's shape.
99
+ */
100
+ export function modelJson(output, name) {
101
+ const text = output.replace(/^\uFEFF/, "").trim();
102
+ if (!text)
103
+ throw new SyntaxError(`${name} is empty.`);
104
+ const parse = (candidate) => {
105
+ try {
106
+ const value = JSON.parse(candidate);
107
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
108
+ }
109
+ catch {
110
+ return undefined;
111
+ }
112
+ };
113
+ const whole = parse(text);
114
+ if (whole)
115
+ return whole;
116
+ const fenced = [...text.matchAll(/```[a-zA-Z0-9_-]*[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]*```/g)].map((match) => parse(match[1].trim())).filter((value) => value !== undefined);
117
+ if (fenced.length)
118
+ return fenced.at(-1);
119
+ const objects = [];
120
+ let unclosed = false;
121
+ for (let start = text.indexOf("{"); start !== -1; start = text.indexOf("{", start + 1)) {
122
+ let depth = 0, quoted = false, escaped = false, end = -1;
123
+ for (let index = start; index < text.length && end === -1; index++) {
124
+ const char = text[index];
125
+ if (quoted) {
126
+ if (escaped)
127
+ escaped = false;
128
+ else if (char === "\\")
129
+ escaped = true;
130
+ else if (char === "\"")
131
+ quoted = false;
132
+ }
133
+ else if (char === "\"")
134
+ quoted = true;
135
+ else if (char === "{")
136
+ depth++;
137
+ else if (char === "}" && --depth === 0)
138
+ end = index;
139
+ }
140
+ if (end === -1) {
141
+ unclosed = true;
142
+ break;
143
+ }
144
+ const value = parse(text.slice(start, end + 1));
145
+ if (value) {
146
+ objects.push(value);
147
+ start = end;
148
+ }
149
+ }
150
+ if (objects.length)
151
+ return objects.at(-1);
152
+ throw new SyntaxError(`${name} contains no complete JSON object${unclosed ? "; an object opens but never closes, so the output looks truncated" : ""}.`);
153
+ }
154
+ /** Reject traversal and symlink parents before reading or changing repository files. */
155
+ export async function safePath(root, file) {
156
+ if (!file || isAbsolute(file) || /^[A-Za-z]:/.test(file) || file.includes("\0"))
157
+ throw new Error(`Unsafe repository path: ${file}`);
158
+ const base = await realpath(root);
159
+ const target = resolve(base, file.replaceAll("\\", sep).replaceAll("/", sep));
160
+ const rel = relative(base, target);
161
+ if (!rel || rel.startsWith(`..${sep}`) || rel === ".." || isAbsolute(rel))
162
+ throw new Error(`Path leaves repository: ${file}`);
163
+ if (rel.split(sep).some((part) => part.toLowerCase() === ".git"))
164
+ throw new Error("Crewbie does not read or write Git internals through repository paths.");
165
+ let current = base;
166
+ for (const part of rel.split(sep)) {
167
+ current = resolve(current, part);
168
+ try {
169
+ if ((await lstat(current)).isSymbolicLink())
170
+ throw new Error(`Symlinks are not allowed in managed paths: ${file}`);
171
+ }
172
+ catch (error) {
173
+ if (!errorCode(error, "ENOENT"))
174
+ throw error;
175
+ }
176
+ }
177
+ return target;
178
+ }
179
+ export async function writeAtomic(root, file, content) {
180
+ const target = await safePath(root, file);
181
+ await mkdir(dirname(target), { recursive: true });
182
+ const temporary = `${target}.${process.pid}.${crypto.randomUUID()}.tmp`;
183
+ await writeFile(temporary, content, { flag: "wx" });
184
+ await rename(temporary, target);
185
+ }
186
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Config } from "../config.js";
2
+ import type { GitHubApi } from "../tracking/github.js";
3
+ export declare function attributedBody(body: string, specialist: string, model: string, taskUrl: string, issue?: number, usage?: string): string;
4
+ export declare function attributePull(client: GitHubApi, config: Config, pr: Record<string, unknown>, task: Record<string, unknown>, owner: string, model: string, issue?: number): Promise<void>;
5
+ export declare function specialistNote(edits: readonly {
6
+ editor: string | null;
7
+ body: string;
8
+ }[], profile: string): string | null;
9
+ /** The specialist's description replaces Copilot's summary; Copilot's suffix block is kept. */
10
+ export declare function restoredBody(note: string, body: string): string;
@@ -0,0 +1,102 @@
1
+ import { integer, record, string } from "../core.js";
2
+ import { collectPrUsage, renderPrUsage } from "../reporting/pr-usage.js";
3
+ export function attributedBody(body, specialist, model, taskUrl, issue, usage) {
4
+ const start = "<!-- crewbie-attribution -->", end = "<!-- /crewbie-attribution -->";
5
+ const blocks = [...body.matchAll(/<!-- crewbie-attribution -->[\s\S]*?<!-- \/crewbie-attribution -->/g)];
6
+ if (blocks.length > 1 || (body.includes(start) !== body.includes(end)) || (body.includes(start) && !blocks.length)) {
7
+ throw new Error("PR attribution markers are ambiguous; reconcile the description.");
8
+ }
9
+ const attribution = `${start}\n**Specialist:** \`${specialist}\` | **Requested model:** \`${model}\`\n[GitHub-confirmed specialist task](${taskUrl})${issue === undefined ? "" : `\nCloses #${integer(issue, "execution issue")}`}${usage ? `\n\n${usage}` : ""}\n${end}`;
10
+ return blocks[0] ? body.replace(blocks[0][0], attribution) : `${attribution}\n\n${body}`;
11
+ }
12
+ export async function attributePull(client, config, pr, task, owner, model, issue) {
13
+ const profile = `crewbie-${owner}`;
14
+ if (!task.custom_agent || record(task.custom_agent, "native profile").id !== profile) {
15
+ throw new Error(`PR #${pr.number}: GitHub did not confirm ${profile}; attribution was not invented.`);
16
+ }
17
+ const id = string(task.id, "native task ID");
18
+ if (!/^[a-zA-Z0-9-]+$/.test(id))
19
+ throw new Error("Invalid native task ID.");
20
+ const number = integer(pr.number, "PR number");
21
+ const body = typeof pr.body === "string" ? pr.body : "";
22
+ const usage = typeof task.session_count === "number" ? renderPrUsage(await collectPrUsage(client, config.repository, pr))
23
+ : "**Observed tokens:** unavailable. **AI credits:** unavailable. Native session metadata was not exposed.";
24
+ let note = null;
25
+ try {
26
+ note = specialistNote(await prEdits(client, config, number), profile);
27
+ }
28
+ catch (error) {
29
+ console.warn(`Crewbie: specialist description for PR #${number} could not be recovered: ${error instanceof Error ? error.message : String(error)}`);
30
+ }
31
+ const restore = note !== null && note.length <= 60_000 && !body.includes(note);
32
+ const attributed = (text) => attributedBody(text, profile, model, `https://github.com/${config.repository}/tasks/${id}`, issue, usage);
33
+ let after = attributed(restore ? restoredBody(note, body) : body);
34
+ if (after === body)
35
+ return;
36
+ const path = `/repos/${config.repository}/pulls/${number}`;
37
+ const fresh = record(await client.request("GET", path), "fresh PR");
38
+ if (fresh.body !== pr.body || record(fresh.head, "fresh head").sha !== record(pr.head, "expected head").sha || fresh.state !== "open") {
39
+ throw new Error("PR changed before attribution; reconcile again rather than overwriting it.");
40
+ }
41
+ if (restore) {
42
+ try {
43
+ await keepCopilotSummary(client, config, number, id, body);
44
+ }
45
+ catch (error) {
46
+ console.warn(`Crewbie: kept Copilot's summary on PR #${number} because it could not be saved as a comment: ${error instanceof Error ? error.message : String(error)}`);
47
+ after = attributed(body);
48
+ if (after === body)
49
+ return;
50
+ }
51
+ }
52
+ const updated = record(await client.request("PATCH", path, { body: after }), "updated PR");
53
+ if (updated.body !== after)
54
+ throw new Error("GitHub did not confirm specialist attribution.");
55
+ }
56
+ const COPILOT_EDITOR = "copilot-swe-agent";
57
+ const SUFFIX = "<!-- START COPILOT CODING AGENT SUFFIX -->";
58
+ const ATTRIBUTION = /<!-- crewbie-attribution -->[\s\S]*?<!-- \/crewbie-attribution -->\s*/g;
59
+ // The cloud agent's final summary replaces the specialist's own PR description; recover the specialist's last version.
60
+ export function specialistNote(edits, profile) {
61
+ const marker = new RegExp(`^\\s*(?:\\*\\*)?Specialist:(?:\\*\\*)?\\s*\`?${profile.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\`?`, "m");
62
+ for (const edit of edits) {
63
+ if (edit.editor !== COPILOT_EDITOR || edit.body.includes("<!-- crewbie-attribution -->") || !marker.test(edit.body))
64
+ continue;
65
+ const note = edit.body.split(SUFFIX)[0].trim();
66
+ return note.length ? note : null;
67
+ }
68
+ return null;
69
+ }
70
+ /** The specialist's description replaces Copilot's summary; Copilot's suffix block is kept. */
71
+ export function restoredBody(note, body) {
72
+ const suffix = body.indexOf(SUFFIX);
73
+ return suffix < 0 ? note : `${note}\n\n${body.slice(suffix)}`;
74
+ }
75
+ async function prEdits(client, config, number) {
76
+ const [owner, name] = config.repository.split("/");
77
+ const result = record(await client.request("POST", "/graphql", {
78
+ query: "query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){pullRequest(number:$number){userContentEdits(first:50){nodes{editor{login} diff}}}}}",
79
+ variables: { owner, name, number },
80
+ }), "PR edit history");
81
+ const nodes = record(record(record(record(result.data, "GraphQL data").repository, "repository").pullRequest, "pull request").userContentEdits, "PR edits").nodes;
82
+ if (!Array.isArray(nodes))
83
+ throw new Error("GitHub returned no PR edit history.");
84
+ return nodes.map((raw) => {
85
+ const node = record(raw, "PR edit");
86
+ const editor = node.editor === null ? null : record(node.editor, "PR editor").login;
87
+ return { editor: typeof editor === "string" ? editor : null, body: typeof node.diff === "string" ? node.diff : "" };
88
+ });
89
+ }
90
+ async function keepCopilotSummary(client, config, number, taskId, body) {
91
+ const tag = `<!-- crewbie-copilot-summary:${taskId} -->`;
92
+ const comments = await client.list(`/repos/${config.repository}/issues/${number}/comments`);
93
+ if (comments.some((comment) => typeof comment.body === "string" && comment.body.includes(tag)))
94
+ return;
95
+ const summary = body.split(SUFFIX)[0].replace(ATTRIBUTION, "").trim();
96
+ if (!summary)
97
+ return;
98
+ await client.request("POST", `/repos/${config.repository}/issues/${number}/comments`, {
99
+ body: `${tag}\n**Copilot's final session summary.** Crewbie restored the specialist's own description as the PR body:\n\n${summary.split("\n").map((line) => `> ${line}`).join("\n")}`,
100
+ });
101
+ }
102
+ //# sourceMappingURL=attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/execution/attribution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Config } from "../config.js";
2
+ import { type GitHubApi } from "../tracking/github.js";
3
+ export declare function cancelRun(client: GitHubApi, config: Config, issueNumber: number, runId: number, apply: boolean): Promise<string>;
@@ -0,0 +1,59 @@
1
+ import { GitHubError, integer, record, string } from "../core.js";
2
+ import { taskMetadata } from "../specification/batch.js";
3
+ import { requireWriter } from "../tracking/github.js";
4
+ import { linkedPull } from "./dispatch.js";
5
+ import { withDispatchLock } from "./controls.js";
6
+ export async function cancelRun(client, config, issueNumber, runId, apply) {
7
+ integer(issueNumber, "issue");
8
+ integer(runId, "run ID");
9
+ const prefix = `/repos/${config.repository}`;
10
+ const inspect = async () => {
11
+ const issue = record(await client.request("GET", `${prefix}/issues/${issueNumber}`), "execution issue");
12
+ const metadata = taskMetadata(string(issue.body, "issue body"));
13
+ if (!metadata)
14
+ throw new Error("Cancellation requires a Crewbie execution issue.");
15
+ const pr = await linkedPull(client, config.repository, issueNumber, metadata.branch);
16
+ if (!pr)
17
+ throw new Error("No unambiguous linked Copilot PR. Use GitHub's session viewer to stop the session manually.");
18
+ const run = record(await client.request("GET", `${prefix}/actions/runs/${runId}`), "agent run");
19
+ const head = record(pr.head, "PR head");
20
+ if (run.event !== "dynamic" || record(run.repository, "run repository").full_name !== config.repository
21
+ || record(head.repo, "PR repository").full_name !== config.repository || run.head_branch !== head.ref
22
+ || !Array.isArray(run.pull_requests) || !run.pull_requests.some((raw) => record(raw, "run PR").id === pr.id)) {
23
+ throw new Error("Run is not an attributable cloud-agent run for this issue. No cancellation requested.");
24
+ }
25
+ return run;
26
+ };
27
+ const run = await inspect();
28
+ const url = `https://github.com/${config.repository}/actions/runs/${runId}`;
29
+ if (run.status === "completed")
30
+ return `Run already completed (${String(run.conclusion)}). Nothing cancelled; inspect preserved work. ${url}`;
31
+ if (!apply)
32
+ return `Preview: request cancellation of cloud-agent run ${runId} for issue #${issueNumber}. Commits, approvals and consumed launch allowances remain. This does not pause future launches. ${url}\nRepeat with --apply.`;
33
+ await requireWriter(client, config.repository);
34
+ return withDispatchLock(client, config, async () => {
35
+ const fresh = await inspect();
36
+ if (fresh.status === "completed")
37
+ return "Run completed before cancellation; nothing cancelled.";
38
+ if (fresh.run_attempt !== run.run_attempt)
39
+ throw new Error("Run attempt changed; preview cancellation again.");
40
+ try {
41
+ await client.request("POST", `${prefix}/actions/runs/${runId}/cancel`);
42
+ }
43
+ catch (error) {
44
+ const reason = error instanceof GitHubError ? `HTTP ${error.status}` : error instanceof Error ? error.message : "unknown request outcome";
45
+ throw new Error(`Cancellation was not confirmed (${reason}); inspect the run before retrying. This backend or credential may not support it. Use Stop session in GitHub's session viewer. No force-cancel, replacement or refund was attempted. ${url}`);
46
+ }
47
+ let result;
48
+ try {
49
+ result = record(await client.request("GET", `${prefix}/actions/runs/${runId}`), "cancellation status");
50
+ }
51
+ catch (error) {
52
+ throw new Error(`Cancellation requested, but verification failed. Inspect ${url} before retrying. ${error instanceof Error ? error.message : "Status unavailable."}`);
53
+ }
54
+ return result.status === "completed" && result.conclusion === "cancelled"
55
+ ? `Actions run cancellation confirmed. Commits and launch claims are preserved; verify native session termination before replacement. ${url}`
56
+ : `Cancellation requested, not confirmed. Do not assume the agent has stopped or spending has ended. Inspect ${url}; no replacement was started.`;
57
+ });
58
+ }
59
+ //# sourceMappingURL=cancel.js.map