ai-foreman 1.7.3 → 1.7.5
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 +5 -0
- package/dist/activity.d.ts +63 -0
- package/dist/activity.js +244 -0
- package/dist/adapters/claude.d.ts +10 -1
- package/dist/adapters/claude.js +70 -6
- package/dist/adapters/codex.d.ts +1 -0
- package/dist/adapters/codex.js +65 -5
- package/dist/adapters/recovering.js +7 -1
- package/dist/adapters/types.d.ts +32 -0
- package/dist/agentRun.d.ts +5 -0
- package/dist/agentRun.js +7 -2
- package/dist/branch/github.js +2 -1
- package/dist/branch/gitlab.js +2 -1
- package/dist/branch/presentation.d.ts +17 -0
- package/dist/branch/presentation.js +38 -0
- package/dist/branch/resume.d.ts +2 -0
- package/dist/branch/resume.js +2 -0
- package/dist/branch/runner.js +44 -25
- package/dist/cli/events.js +24 -5
- package/dist/cli/runtimeAuthPrompt.js +5 -1
- package/dist/cli/start.js +36 -23
- package/dist/foreman.d.ts +7 -2
- package/dist/foreman.js +17 -1
- package/dist/index.js +3 -1
- package/dist/providerQuestions.d.ts +37 -0
- package/dist/providerQuestions.js +216 -0
- package/dist/qaReview.js +12 -9
- package/dist/qaSnapshot.d.ts +14 -0
- package/dist/qaSnapshot.js +117 -1
- package/dist/runtimeReadiness.js +5 -0
- package/dist/sources/sourceRegistry.js +13 -6
- package/dist/tickets/importer.js +13 -8
- package/dist/tickets/sourceFetch.js +19 -0
- package/package.json +11 -3
package/dist/tickets/importer.js
CHANGED
|
@@ -5,6 +5,7 @@ import { StateDb } from "./stateDb.js";
|
|
|
5
5
|
import { nowTimestamp } from "./events.js";
|
|
6
6
|
import { loadTicketsConfig, resolveTicketPaths } from "./config.js";
|
|
7
7
|
import { insertXlSplitRecommendations } from "./recommendations.js";
|
|
8
|
+
import { currentActivity, withActivityPhase } from "../activity.js";
|
|
8
9
|
export function importFromMarkdown(_progressDocPath) {
|
|
9
10
|
throw new Error("foreman tickets import is not yet implemented.\n\n" +
|
|
10
11
|
"To start fresh:\n" +
|
|
@@ -19,9 +20,9 @@ export function importFromMarkdown(_progressDocPath) {
|
|
|
19
20
|
export async function importExternalSources(projectDir, sources, opts) {
|
|
20
21
|
const results = [];
|
|
21
22
|
for (const source of sources) {
|
|
22
|
-
const items = source.type === "linear"
|
|
23
|
-
?
|
|
24
|
-
:
|
|
23
|
+
const items = await withActivityPhase(`importing ${source.type} tickets`, () => source.type === "linear"
|
|
24
|
+
? fetchLinearIssues(source, opts)
|
|
25
|
+
: fetchJiraIssues(source, opts));
|
|
25
26
|
const snapshotPath = writeImportSnapshot(projectDir, source.type, {
|
|
26
27
|
source: redactSource(source),
|
|
27
28
|
fetched_at: new Date().toISOString(),
|
|
@@ -42,11 +43,13 @@ export async function importExternalSources(projectDir, sources, opts) {
|
|
|
42
43
|
return results;
|
|
43
44
|
}
|
|
44
45
|
export async function validateExternalSourceAccess(source) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
await withActivityPhase(`checking ${source.type} access`, async () => {
|
|
47
|
+
if (source.type === "linear") {
|
|
48
|
+
await fetchLinearIssues(source, { importCap: 1, commentLimit: 0 });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
await fetchJiraIssues(source, { importCap: 1, commentLimit: 0 });
|
|
52
|
+
});
|
|
50
53
|
}
|
|
51
54
|
export async function fetchLinearIssues(source, opts) {
|
|
52
55
|
const apiKey = process.env[source.api_key_env];
|
|
@@ -84,6 +87,7 @@ export async function fetchLinearIssues(source, opts) {
|
|
|
84
87
|
if (items.length >= opts.importCap)
|
|
85
88
|
break;
|
|
86
89
|
}
|
|
90
|
+
currentActivity()?.update("importing Linear tickets", `fetched ${items.length}`);
|
|
87
91
|
if (!issues?.pageInfo?.hasNextPage || !issues.pageInfo.endCursor || nodes.length === 0)
|
|
88
92
|
break;
|
|
89
93
|
after = issues.pageInfo.endCursor;
|
|
@@ -137,6 +141,7 @@ export async function fetchJiraIssues(source, opts) {
|
|
|
137
141
|
if (items.length >= opts.importCap)
|
|
138
142
|
break;
|
|
139
143
|
}
|
|
144
|
+
currentActivity()?.update("importing Jira tickets", `fetched ${items.length}`);
|
|
140
145
|
nextPageToken = typeof json.nextPageToken === "string" ? json.nextPageToken : undefined;
|
|
141
146
|
if (!nextPageToken || issues.length === 0 || json.isLast === true)
|
|
142
147
|
break;
|
|
@@ -5,12 +5,22 @@ import { isIP } from "node:net";
|
|
|
5
5
|
import { basename, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
6
6
|
import { readdirSync } from "node:fs";
|
|
7
7
|
import { parse as parseHtml } from "parse5";
|
|
8
|
+
import { currentActivity, withActivityPhase } from "../activity.js";
|
|
8
9
|
export const DEFAULT_SOURCE_FETCH_LIMITS = {
|
|
9
10
|
timeoutMs: 15_000,
|
|
10
11
|
maxBytes: 10 * 1024 * 1024,
|
|
11
12
|
maxRedirects: 5,
|
|
12
13
|
};
|
|
13
14
|
export async function fetchAndSnapshotUrl(projectDir, input, limits = {}) {
|
|
15
|
+
const label = (() => { try {
|
|
16
|
+
return `fetching source ${new URL(input).hostname}`;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return "fetching URL source";
|
|
20
|
+
} })();
|
|
21
|
+
return withActivityPhase(label, () => fetchAndSnapshotUrlInternal(projectDir, input, limits));
|
|
22
|
+
}
|
|
23
|
+
async function fetchAndSnapshotUrlInternal(projectDir, input, limits) {
|
|
14
24
|
const effective = { ...DEFAULT_SOURCE_FETCH_LIMITS, ...limits };
|
|
15
25
|
const requested = normalizePublicHttpUrl(input);
|
|
16
26
|
let current = requested;
|
|
@@ -126,6 +136,7 @@ async function readLimitedBody(response, maxBytes) {
|
|
|
126
136
|
if (done)
|
|
127
137
|
break;
|
|
128
138
|
total += value.length;
|
|
139
|
+
currentActivity()?.pulse(`downloaded ${formatBytes(total)}`);
|
|
129
140
|
if (total > maxBytes) {
|
|
130
141
|
await reader.cancel();
|
|
131
142
|
throw new Error(`URL content exceeds ${maxBytes} byte limit`);
|
|
@@ -174,6 +185,7 @@ async function extractSourceText(kind, bytes) {
|
|
|
174
185
|
const document = await pdfjs.getDocument({ data: bytes, useWorkerFetch: false, isEvalSupported: false }).promise;
|
|
175
186
|
const pages = [];
|
|
176
187
|
for (let pageNumber = 1; pageNumber <= document.numPages; pageNumber++) {
|
|
188
|
+
currentActivity()?.update("extracting PDF source", `page ${pageNumber}/${document.numPages}`);
|
|
177
189
|
const page = await document.getPage(pageNumber);
|
|
178
190
|
const content = await page.getTextContent();
|
|
179
191
|
pages.push(content.items.map((item) => "str" in item ? item.str : "").join(" "));
|
|
@@ -185,6 +197,13 @@ async function extractSourceText(kind, bytes) {
|
|
|
185
197
|
const decoded = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
186
198
|
return kind === "html" ? htmlToText(decoded) : decoded;
|
|
187
199
|
}
|
|
200
|
+
function formatBytes(bytes) {
|
|
201
|
+
if (bytes < 1024)
|
|
202
|
+
return `${bytes} B`;
|
|
203
|
+
if (bytes < 1024 * 1024)
|
|
204
|
+
return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
205
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
206
|
+
}
|
|
188
207
|
export function htmlToText(html) {
|
|
189
208
|
const doc = parseHtml(html);
|
|
190
209
|
const blocks = new Set(["address", "article", "aside", "blockquote", "br", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "header", "li", "main", "p", "section", "table", "tr"]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-foreman",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.5",
|
|
4
4
|
"description": "An orchestrator that keeps Codex CLI / Claude Code builders moving through their step list unattended. Part of Rafi.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"ai-foreman": "dist/index.js"
|
|
18
18
|
},
|
|
19
19
|
"exports": {
|
|
20
|
+
"./activity.js": {
|
|
21
|
+
"types": "./dist/activity.d.ts",
|
|
22
|
+
"default": "./dist/activity.js"
|
|
23
|
+
},
|
|
20
24
|
"./agent-run.js": {
|
|
21
25
|
"types": "./dist/agentRun.d.ts",
|
|
22
26
|
"default": "./dist/agentRun.js"
|
|
@@ -25,6 +29,10 @@
|
|
|
25
29
|
"types": "./dist/interviews.d.ts",
|
|
26
30
|
"default": "./dist/interviews.js"
|
|
27
31
|
},
|
|
32
|
+
"./provider-questions.js": {
|
|
33
|
+
"types": "./dist/providerQuestions.d.ts",
|
|
34
|
+
"default": "./dist/providerQuestions.js"
|
|
35
|
+
},
|
|
28
36
|
"./runtime-readiness.js": {
|
|
29
37
|
"types": "./dist/runtimeReadiness.d.ts",
|
|
30
38
|
"default": "./dist/runtimeReadiness.js"
|
|
@@ -118,8 +126,8 @@
|
|
|
118
126
|
"@anthropic-ai/claude-agent-sdk": "^0.3.148"
|
|
119
127
|
},
|
|
120
128
|
"dependencies": {
|
|
121
|
-
"special-agents": "0.8.
|
|
122
|
-
"rafi-spec": "0.8.
|
|
129
|
+
"special-agents": "0.8.3",
|
|
130
|
+
"rafi-spec": "0.8.3",
|
|
123
131
|
"@clack/prompts": "^1.4.0",
|
|
124
132
|
"ajv": "^8.20.0",
|
|
125
133
|
"ajv-formats": "^3.0.1",
|