flanders 0.7.0 → 0.9.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 +91 -79
- package/lib/ai/AiRunner.d.ts +3 -1
- package/lib/ai/AiRunner.js +2 -2
- package/lib/ai/AiSession.d.ts +3 -1
- package/lib/ai/AiSession.js +2 -0
- package/lib/ai/ClaudeAdapter.d.ts +2 -1
- package/lib/ai/ClaudeAdapter.js +7 -3
- package/lib/ai/CodexAdapter.js +9 -80
- package/lib/ai/ToolAdapter.d.ts +7 -3
- package/lib/ai/toolErrorClassification.d.ts +7 -0
- package/lib/ai/toolErrorClassification.js +78 -0
- package/lib/cli.js +10 -4
- package/lib/commands/Implement.d.ts +3 -0
- package/lib/commands/Implement.js +60 -16
- package/lib/commands/Install.d.ts +9 -4
- package/lib/commands/Install.js +250 -105
- package/lib/commands/skillArtifacts.js +40 -36
- package/lib/contexts.d.ts +1 -0
- package/lib/fastMode.d.ts +2 -0
- package/lib/fastMode.js +15 -0
- package/lib/plan/PlanFile.d.ts +3 -1
- package/lib/plan/PlanFile.js +8 -1
- package/lib/prompts/prompts.js +6 -6
- package/lib/prompts/skills.js +13 -7
- package/lib/toolNames.d.ts +1 -0
- package/lib/toolNames.js +4 -0
- package/lib/ui/BottomBlock.d.ts +11 -8
- package/lib/ui/BottomBlock.js +24 -3
- package/lib/ui/PromptHelper.d.ts +7 -0
- package/lib/ui/PromptHelper.js +22 -0
- package/lib/ui/formatters.d.ts +3 -2
- package/lib/ui/formatters.js +7 -2
- package/lib/workspace/FlandersConfig.d.ts +3 -1
- package/lib/workspace/FlandersConfig.js +5 -1
- package/package.json +3 -2
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isRateLimitMessage = isRateLimitMessage;
|
|
4
|
+
exports.isRetryableHttpStatus = isRetryableHttpStatus;
|
|
5
|
+
exports.isRetryableTransport = isRetryableTransport;
|
|
6
|
+
exports.synthesizeRateLimitEvent = synthesizeRateLimitEvent;
|
|
7
|
+
exports.classifyToolFailure = classifyToolFailure;
|
|
8
|
+
const RATE_LIMIT_SUBSTRINGS = [
|
|
9
|
+
"out of credits",
|
|
10
|
+
"refill",
|
|
11
|
+
"usage limit",
|
|
12
|
+
"rate limit",
|
|
13
|
+
"rate-limit",
|
|
14
|
+
"rate_limit",
|
|
15
|
+
"quota",
|
|
16
|
+
"too many requests"
|
|
17
|
+
];
|
|
18
|
+
const RATE_LIMIT_429_RE = /\b429\b/;
|
|
19
|
+
const EIGHT_MINUTES_MS = 8 * 60000;
|
|
20
|
+
const TWELVE_MINUTES_MS = 12 * 60000;
|
|
21
|
+
const FIVE_XX_RE = /\b5\d{2}\b/;
|
|
22
|
+
const STATUS_408_RE = /\b408\b/;
|
|
23
|
+
const STATUS_425_RE = /\b425\b/;
|
|
24
|
+
const TRANSPORT_SUBSTRINGS = [
|
|
25
|
+
"timeout",
|
|
26
|
+
"timed out",
|
|
27
|
+
"connection reset",
|
|
28
|
+
"connection refused",
|
|
29
|
+
"socket hang up",
|
|
30
|
+
"temporarily unavailable",
|
|
31
|
+
"service unavailable",
|
|
32
|
+
"gateway",
|
|
33
|
+
"network",
|
|
34
|
+
"econnreset",
|
|
35
|
+
"econnrefused",
|
|
36
|
+
"enotfound",
|
|
37
|
+
"etimedout",
|
|
38
|
+
"eai_again"
|
|
39
|
+
];
|
|
40
|
+
function isRateLimitMessage(message) {
|
|
41
|
+
const lower = message.trim().toLowerCase();
|
|
42
|
+
for (const sub of RATE_LIMIT_SUBSTRINGS) {
|
|
43
|
+
if (lower.includes(sub))
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return RATE_LIMIT_429_RE.test(message.trim());
|
|
47
|
+
}
|
|
48
|
+
function isRetryableHttpStatus(message) {
|
|
49
|
+
const trimmed = message.trim();
|
|
50
|
+
if (FIVE_XX_RE.test(trimmed))
|
|
51
|
+
return true;
|
|
52
|
+
if (STATUS_408_RE.test(trimmed))
|
|
53
|
+
return true;
|
|
54
|
+
if (STATUS_425_RE.test(trimmed))
|
|
55
|
+
return true;
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function isRetryableTransport(message) {
|
|
59
|
+
const lower = message.trim().toLowerCase();
|
|
60
|
+
for (const sub of TRANSPORT_SUBSTRINGS) {
|
|
61
|
+
if (lower.includes(sub))
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
function synthesizeRateLimitEvent(time, random) {
|
|
67
|
+
const r = EIGHT_MINUTES_MS + Math.round(random.random() * (TWELVE_MINUTES_MS - EIGHT_MINUTES_MS));
|
|
68
|
+
return { type: "rate_limit", waitUntilMs: time.now() + r };
|
|
69
|
+
}
|
|
70
|
+
function classifyToolFailure(message, time, random) {
|
|
71
|
+
if (isRateLimitMessage(message)) {
|
|
72
|
+
return synthesizeRateLimitEvent(time, random);
|
|
73
|
+
}
|
|
74
|
+
if (isRetryableHttpStatus(message) || isRetryableTransport(message)) {
|
|
75
|
+
return { type: "error", retryable: true, message };
|
|
76
|
+
}
|
|
77
|
+
return { type: "error", retryable: false, message };
|
|
78
|
+
}
|
package/lib/cli.js
CHANGED
|
@@ -235,7 +235,7 @@ const ask = (() => {
|
|
|
235
235
|
const o = q.options[i];
|
|
236
236
|
const marker = pickedLabels.has(o.label) ? "*" : " ";
|
|
237
237
|
const isDefault = q.defaultIndex === i;
|
|
238
|
-
out.write(` ${marker} ${i + 1}) ${o.label}${o.description ? ` — ${o.description}` : ""}${isDefault ? " (
|
|
238
|
+
out.write(` ${marker} ${i + 1}) ${o.label}${o.description ? ` — ${o.description}` : ""}${isDefault ? " (configured — press Enter)" : ""}\n`);
|
|
239
239
|
}
|
|
240
240
|
if (existing) {
|
|
241
241
|
const labels = existing.picked.map(p => p.label).join(", ");
|
|
@@ -249,7 +249,9 @@ const ask = (() => {
|
|
|
249
249
|
async askChoices(questions, output) {
|
|
250
250
|
const out = output !== null && output !== void 0 ? output : outputContext;
|
|
251
251
|
const total = questions.length;
|
|
252
|
-
const answers =
|
|
252
|
+
const answers = questions.map(q => q.multiSelect && q.defaultIndexes !== undefined && q.defaultIndexes.length > 0
|
|
253
|
+
? { picked: q.defaultIndexes.map(i => q.options[i]) }
|
|
254
|
+
: undefined);
|
|
253
255
|
let idx = 0;
|
|
254
256
|
while (idx < total) {
|
|
255
257
|
const q = questions[idx];
|
|
@@ -259,8 +261,8 @@ const ask = (() => {
|
|
|
259
261
|
hints.push(q.multiSelect
|
|
260
262
|
? `[1-${q.options.length}, comma-separated; free-text OK]`
|
|
261
263
|
: `[1-${q.options.length}; free-text OK]`);
|
|
262
|
-
if (q.defaultIndex !== undefined) {
|
|
263
|
-
hints.push("Enter for
|
|
264
|
+
if (q.defaultIndex !== undefined || (q.multiSelect && existing !== undefined && existing.picked.length > 0)) {
|
|
265
|
+
hints.push("Enter for configured");
|
|
264
266
|
}
|
|
265
267
|
if (idx > 0) {
|
|
266
268
|
hints.push("'-' back");
|
|
@@ -297,6 +299,10 @@ const ask = (() => {
|
|
|
297
299
|
idx++;
|
|
298
300
|
continue;
|
|
299
301
|
}
|
|
302
|
+
if (raw === "" && q.multiSelect && existing !== undefined && existing.picked.length > 0) {
|
|
303
|
+
idx++;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
300
306
|
const parsed = parseAnswer(raw, q.options.length, q.multiSelect);
|
|
301
307
|
if (!parsed) {
|
|
302
308
|
out.writeError("Invalid input. Pick a valid option number, type free-form text, or use '-' / '+' to navigate.\n");
|
|
@@ -3,6 +3,7 @@ import type { FlandersConfig } from "../workspace/FlandersConfig";
|
|
|
3
3
|
import type { Activity } from "../ui/BottomBlock";
|
|
4
4
|
import { PlatformContext } from "../workspace/Workspace";
|
|
5
5
|
export type { Activity };
|
|
6
|
+
export declare function completedPlanPath(planPath: string): string;
|
|
6
7
|
export type ImplementContexts = Readonly<{
|
|
7
8
|
claude: ScriptContext;
|
|
8
9
|
script: ScriptContext;
|
|
@@ -27,6 +28,7 @@ export declare class Implement {
|
|
|
27
28
|
private _block;
|
|
28
29
|
private _buffered;
|
|
29
30
|
private _currentWorkerSessionId;
|
|
31
|
+
private _workerSessionTokens;
|
|
30
32
|
private _activeSession;
|
|
31
33
|
private _activeScript;
|
|
32
34
|
private _activeReviewerSessions;
|
|
@@ -41,6 +43,7 @@ export declare class Implement {
|
|
|
41
43
|
private _taskRateLimitMs;
|
|
42
44
|
private _taskRateLimitStartedAt;
|
|
43
45
|
private _taskTokens;
|
|
46
|
+
private _otherTasksSeconds;
|
|
44
47
|
private _runPromise;
|
|
45
48
|
get config(): FlandersConfig | null;
|
|
46
49
|
constructor(rawArgs: readonly string[], _options: ImplementOptions, _contexts: ImplementContexts);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Implement = void 0;
|
|
4
|
+
exports.completedPlanPath = completedPlanPath;
|
|
4
5
|
const AiSession_1 = require("../ai/AiSession");
|
|
5
6
|
const ClaudeAdapter_1 = require("../ai/ClaudeAdapter");
|
|
6
7
|
const CodexAdapter_1 = require("../ai/CodexAdapter");
|
|
@@ -16,6 +17,16 @@ const formatters_1 = require("../ui/formatters");
|
|
|
16
17
|
const voiceVariants_1 = require("../voiceVariants");
|
|
17
18
|
const Workspace_1 = require("../workspace/Workspace");
|
|
18
19
|
const MAX_ITER = 5;
|
|
20
|
+
const COMPLETED_PLAN_MARKER = "V-";
|
|
21
|
+
function completedPlanPath(planPath) {
|
|
22
|
+
const slash = Math.max(planPath.lastIndexOf("/"), planPath.lastIndexOf("\\"));
|
|
23
|
+
const dir = planPath.slice(0, slash + 1);
|
|
24
|
+
const base = planPath.slice(slash + 1);
|
|
25
|
+
if (base.startsWith(COMPLETED_PLAN_MARKER)) {
|
|
26
|
+
return planPath;
|
|
27
|
+
}
|
|
28
|
+
return `${dir}${COMPLETED_PLAN_MARKER}${base}`;
|
|
29
|
+
}
|
|
19
30
|
class LineBufferedBlock {
|
|
20
31
|
constructor(_block) {
|
|
21
32
|
this._block = _block;
|
|
@@ -62,6 +73,7 @@ class Implement {
|
|
|
62
73
|
this._workspace = null;
|
|
63
74
|
this._block = null;
|
|
64
75
|
this._currentWorkerSessionId = null;
|
|
76
|
+
this._workerSessionTokens = { inputTokens: 0, outputTokens: 0 };
|
|
65
77
|
this._activeSession = null;
|
|
66
78
|
this._activeScript = null;
|
|
67
79
|
this._activeReviewerSessions = new Set();
|
|
@@ -76,6 +88,7 @@ class Implement {
|
|
|
76
88
|
this._taskRateLimitMs = 0;
|
|
77
89
|
this._taskRateLimitStartedAt = null;
|
|
78
90
|
this._taskTokens = { it: 0, ot: 0 };
|
|
91
|
+
this._otherTasksSeconds = 0;
|
|
79
92
|
this._runPromise = this._run(rawArgs);
|
|
80
93
|
this._runPromise.catch(() => { });
|
|
81
94
|
}
|
|
@@ -141,13 +154,15 @@ class Implement {
|
|
|
141
154
|
const planTotals = plan.planTotals();
|
|
142
155
|
if (initialParse.tasks.every(t => t.done)) {
|
|
143
156
|
this._block.setHeader({ indexLabel: `${totalTasks}/${totalTasks}` });
|
|
144
|
-
this._block.setMetrics({ plan: { tokens: planTotals.it + planTotals.ot,
|
|
157
|
+
this._block.setMetrics({ plan: { tokens: planTotals.it + planTotals.ot, baseSeconds: planTotals.t } });
|
|
145
158
|
this._buffered.write(`${(0, voiceVariants_1.pickVariant)(voiceVariants_1.tasksCompletedPool, this._contexts.random)}\n`);
|
|
146
159
|
this._finalizeBlock("Done");
|
|
147
160
|
return 0;
|
|
148
161
|
}
|
|
149
|
-
|
|
150
|
-
|
|
162
|
+
const completedAtStartup = initialParse.tasks.filter(t => t.done).length;
|
|
163
|
+
const startupIndexLabel = `${completedAtStartup}/${totalTasks}`;
|
|
164
|
+
this._block.setHeader({ indexLabel: startupIndexLabel });
|
|
165
|
+
this._block.setMetrics({ plan: { tokens: planTotals.it + planTotals.ot, baseSeconds: planTotals.t } });
|
|
151
166
|
const gitAvailable = await (0, Git_1.isGitAvailable)(this._contexts.script, this._contexts.time);
|
|
152
167
|
const insideWorkTree = gitAvailable && await (0, Git_1.isInsideWorkTree)(this._contexts.script, this._contexts.time, this._options.projectRoot);
|
|
153
168
|
if (!insideWorkTree) {
|
|
@@ -167,6 +182,7 @@ class Implement {
|
|
|
167
182
|
this._behaviorRuleList = specs.flanders;
|
|
168
183
|
this._workspace = new Workspace_1.Workspace(this._contexts.fs, this._contexts.platform);
|
|
169
184
|
const wsPaths = await this._workspace.setup(this._config.reviewers.length);
|
|
185
|
+
this._block.setHeader({ indexLabel: startupIndexLabel, phaseMessage: "preparing build and test scripts" });
|
|
170
186
|
await this._detectBuildAndTest(wsPaths);
|
|
171
187
|
if (this._disposed) {
|
|
172
188
|
this._finalizeBlock("Interrupted");
|
|
@@ -241,7 +257,7 @@ class Implement {
|
|
|
241
257
|
.split("<BUILD_SCRIPT_PATH>").join(ws.buildScript)
|
|
242
258
|
.split("<TEST_SCRIPT_PATH>").join(ws.testScript)
|
|
243
259
|
.split("<RULE_LIST>").join(this._formatPathList(this._ruleList));
|
|
244
|
-
await this._runAi(this._config.worker.tool, this._config.worker.model, this._config.worker.effort, prompt);
|
|
260
|
+
await this._runAi(this._config.worker.tool, this._config.worker.model, this._config.worker.effort, this._config.worker.fast, prompt);
|
|
245
261
|
}
|
|
246
262
|
_setActivity(activity) {
|
|
247
263
|
if (!this._currentTask)
|
|
@@ -269,9 +285,10 @@ class Implement {
|
|
|
269
285
|
if (!this._currentTask || this._taskRateLimitStartedAt !== null)
|
|
270
286
|
return;
|
|
271
287
|
const planTotals = plan.planTotals();
|
|
288
|
+
const anchorMs = this._taskStartedAt + this._taskRateLimitMs;
|
|
272
289
|
this._block.setMetrics({
|
|
273
|
-
task: { tokens: this._taskTokens.it + this._taskTokens.ot,
|
|
274
|
-
plan: { tokens: planTotals.it + planTotals.ot,
|
|
290
|
+
task: { tokens: this._taskTokens.it + this._taskTokens.ot, anchorMs, baseSeconds: 0 },
|
|
291
|
+
plan: { tokens: planTotals.it + planTotals.ot, anchorMs, baseSeconds: this._otherTasksSeconds }
|
|
275
292
|
});
|
|
276
293
|
}
|
|
277
294
|
_gitOutputContext() {
|
|
@@ -287,10 +304,12 @@ class Implement {
|
|
|
287
304
|
this._currentTask = task;
|
|
288
305
|
this._currentIndexLabel = indexLabel;
|
|
289
306
|
this._currentWorkerSessionId = null;
|
|
307
|
+
this._workerSessionTokens = { inputTokens: 0, outputTokens: 0 };
|
|
290
308
|
this._taskStartedAt = this._contexts.time.now();
|
|
291
309
|
this._taskRateLimitMs = 0;
|
|
292
310
|
this._taskRateLimitStartedAt = null;
|
|
293
311
|
this._taskTokens = { it: 0, ot: 0 };
|
|
312
|
+
this._otherTasksSeconds = plan.planTotals().t - task.metrics.t;
|
|
294
313
|
this._updateMetrics(plan);
|
|
295
314
|
let iteration = 0;
|
|
296
315
|
for (;;) {
|
|
@@ -343,17 +362,32 @@ class Implement {
|
|
|
343
362
|
continue;
|
|
344
363
|
}
|
|
345
364
|
await plan.markDone(task.line, { it: this._taskTokens.it, ot: this._taskTokens.ot, t: this._activeSeconds() });
|
|
365
|
+
const originalPlanPath = plan.path;
|
|
366
|
+
let completionRenamed = false;
|
|
367
|
+
if (plan.nextOpenTask() === null) {
|
|
368
|
+
const completedPath = completedPlanPath(originalPlanPath);
|
|
369
|
+
if (completedPath !== originalPlanPath) {
|
|
370
|
+
await plan.rename(completedPath);
|
|
371
|
+
completionRenamed = true;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
const revertCompletion = async () => {
|
|
375
|
+
if (completionRenamed) {
|
|
376
|
+
await plan.rename(originalPlanPath);
|
|
377
|
+
}
|
|
378
|
+
await plan.markOpen(task.line, { it: this._taskTokens.it, ot: this._taskTokens.ot, t: this._activeSeconds() });
|
|
379
|
+
};
|
|
346
380
|
const commitMessage = task.taskNumber ? `${task.taskNumber} ${task.title}` : task.title;
|
|
347
381
|
const addResult = await (0, Git_1.addAll)(this._contexts.script, this._contexts.time, this._gitOutputContext(), this._options.projectRoot);
|
|
348
382
|
if (addResult.code !== 0) {
|
|
349
383
|
await this._writeErrorLog(ws, `git add -A failed (exit ${addResult.code})\n--- stdout ---\n${addResult.stdout}\n--- stderr ---\n${addResult.stderr}`);
|
|
350
|
-
await
|
|
384
|
+
await revertCompletion();
|
|
351
385
|
continue;
|
|
352
386
|
}
|
|
353
387
|
const commitResult = await (0, Git_1.commit)(this._contexts.script, this._contexts.time, this._gitOutputContext(), this._options.projectRoot, commitMessage);
|
|
354
388
|
if (commitResult.code !== 0) {
|
|
355
389
|
await this._writeErrorLog(ws, `git commit failed (exit ${commitResult.code})\n--- stdout ---\n${commitResult.stdout}\n--- stderr ---\n${commitResult.stderr}`);
|
|
356
|
-
await
|
|
390
|
+
await revertCompletion();
|
|
357
391
|
continue;
|
|
358
392
|
}
|
|
359
393
|
const planTotals = plan.planTotals();
|
|
@@ -394,10 +428,17 @@ class Implement {
|
|
|
394
428
|
prompt = `${prompt}\n\n${(0, prompts_1.linkedReferenceDirective)(ws.specFile)}`;
|
|
395
429
|
}
|
|
396
430
|
const { result, capturedOutput } = iteration === 1
|
|
397
|
-
? await this._runAi(this._config.worker.tool, this._config.worker.model, this._config.worker.effort, prompt)
|
|
398
|
-
: await this._runAi(this._config.worker.tool, this._config.worker.model, this._config.worker.effort, prompt, this._currentWorkerSessionId);
|
|
399
|
-
if (result.sessionId !== null) {
|
|
431
|
+
? await this._runAi(this._config.worker.tool, this._config.worker.model, this._config.worker.effort, this._config.worker.fast, prompt, null, this._workerSessionTokens)
|
|
432
|
+
: await this._runAi(this._config.worker.tool, this._config.worker.model, this._config.worker.effort, this._config.worker.fast, prompt, this._currentWorkerSessionId, this._workerSessionTokens);
|
|
433
|
+
if (result.sessionId !== null && result.sessionId !== this._currentWorkerSessionId) {
|
|
400
434
|
this._currentWorkerSessionId = result.sessionId;
|
|
435
|
+
this._workerSessionTokens = { inputTokens: result.inputTokens, outputTokens: result.outputTokens };
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
this._workerSessionTokens = {
|
|
439
|
+
inputTokens: this._workerSessionTokens.inputTokens + result.inputTokens,
|
|
440
|
+
outputTokens: this._workerSessionTokens.outputTokens + result.outputTokens
|
|
441
|
+
};
|
|
401
442
|
}
|
|
402
443
|
this._taskTokens.it += result.inputTokens;
|
|
403
444
|
this._taskTokens.ot += result.outputTokens;
|
|
@@ -604,7 +645,7 @@ class Implement {
|
|
|
604
645
|
};
|
|
605
646
|
let runResult;
|
|
606
647
|
try {
|
|
607
|
-
runResult = await this._runAiWith(reviewer.tool, reviewer.model, reviewer.effort, prompt, null, callbacks);
|
|
648
|
+
runResult = await this._runAiWith(reviewer.tool, reviewer.model, reviewer.effort, reviewer.fast, prompt, null, callbacks);
|
|
608
649
|
}
|
|
609
650
|
catch (e) {
|
|
610
651
|
if (this._cancelledReviewers.has(idx)) {
|
|
@@ -652,7 +693,8 @@ class Implement {
|
|
|
652
693
|
}
|
|
653
694
|
return new ClaudeAdapter_1.ClaudeAdapter({
|
|
654
695
|
claude: this._contexts.claude,
|
|
655
|
-
time: this._contexts.time
|
|
696
|
+
time: this._contexts.time,
|
|
697
|
+
random: this._contexts.random
|
|
656
698
|
});
|
|
657
699
|
}
|
|
658
700
|
_defaultRunAiCallbacks() {
|
|
@@ -685,10 +727,10 @@ class Implement {
|
|
|
685
727
|
}
|
|
686
728
|
};
|
|
687
729
|
}
|
|
688
|
-
_runAi(tool, model, effort, prompt, initialSessionId) {
|
|
689
|
-
return this._runAiWith(tool, model, effort, prompt, initialSessionId !== null && initialSessionId !== void 0 ? initialSessionId : null, this._defaultRunAiCallbacks());
|
|
730
|
+
_runAi(tool, model, effort, fast, prompt, initialSessionId, priorSessionUsage) {
|
|
731
|
+
return this._runAiWith(tool, model, effort, fast, prompt, initialSessionId !== null && initialSessionId !== void 0 ? initialSessionId : null, this._defaultRunAiCallbacks(), priorSessionUsage);
|
|
690
732
|
}
|
|
691
|
-
async _runAiWith(tool, model, effort, prompt, initialSessionId, callbacks) {
|
|
733
|
+
async _runAiWith(tool, model, effort, fast, prompt, initialSessionId, callbacks, priorSessionUsage) {
|
|
692
734
|
if (this._disposed) {
|
|
693
735
|
throw new Error("Implement disposed");
|
|
694
736
|
}
|
|
@@ -712,7 +754,9 @@ class Implement {
|
|
|
712
754
|
prompt,
|
|
713
755
|
model,
|
|
714
756
|
effort,
|
|
757
|
+
fast,
|
|
715
758
|
...(initialSessionId != null ? { resumeSessionId: initialSessionId } : null),
|
|
759
|
+
...(priorSessionUsage != null ? { priorSessionUsage } : null),
|
|
716
760
|
onLongWaitStart: callbacks.onLongWaitStart,
|
|
717
761
|
onLongWaitEnd: callbacks.onLongWaitEnd
|
|
718
762
|
}, {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AskContext, FsContext, OutputContext, ScriptContext } from "../contexts";
|
|
2
2
|
import type { PlatformContext } from "../workspace/Workspace";
|
|
3
|
+
import type { ToolName } from "../ai/ToolAdapter";
|
|
3
4
|
export type InstallContexts = Readonly<{
|
|
4
5
|
fs: FsContext;
|
|
5
6
|
ask: AskContext;
|
|
@@ -11,18 +12,20 @@ export type InstallOptions = Readonly<{
|
|
|
11
12
|
projectRoot: string;
|
|
12
13
|
}>;
|
|
13
14
|
type ReviewerFlagAnswers = Readonly<{
|
|
14
|
-
tool?:
|
|
15
|
+
tool?: ToolName;
|
|
15
16
|
model?: string;
|
|
16
17
|
effort?: string;
|
|
17
18
|
}>;
|
|
18
19
|
export type ResolvedAnswers = Readonly<{
|
|
19
20
|
scope?: "project" | "global";
|
|
20
|
-
|
|
21
|
-
workerTool?:
|
|
21
|
+
skillsTools?: readonly ToolName[];
|
|
22
|
+
workerTool?: ToolName;
|
|
22
23
|
workerModel?: string;
|
|
23
24
|
workerEffort?: string;
|
|
25
|
+
workerFast?: boolean;
|
|
24
26
|
reviewers?: readonly ReviewerFlagAnswers[];
|
|
25
27
|
optionalReviewerIndices?: readonly number[];
|
|
28
|
+
fastReviewerIndices?: readonly number[];
|
|
26
29
|
reviewerMinimum?: number;
|
|
27
30
|
}>;
|
|
28
31
|
export declare function parseInstallFlags(rawArgs: readonly string[]): Readonly<{
|
|
@@ -39,9 +42,11 @@ export declare class Install {
|
|
|
39
42
|
constructor(rawArgs: readonly string[], _options: InstallOptions, _contexts: InstallContexts);
|
|
40
43
|
result(): Promise<number>;
|
|
41
44
|
private _resolveCuratedChoice;
|
|
42
|
-
private
|
|
45
|
+
private _resolveGroupedModel;
|
|
46
|
+
private _resolveFreeTextModel;
|
|
43
47
|
private _resolveRoleModel;
|
|
44
48
|
private _resolveRoleEffort;
|
|
49
|
+
private _resolveRoleFast;
|
|
45
50
|
private _resolveReviewer;
|
|
46
51
|
private _run;
|
|
47
52
|
dispose(): Promise<void>;
|