@delete101020/aidlc 4.0.38 → 4.0.41
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 +1 -1
- package/dist/bundle.js +1718 -243
- package/dist/templates/ainative/artifacts/build-plan.md +4 -0
- package/dist/templates/ainative/artifacts/implement.md +18 -5
- package/dist/templates/ainative/artifacts/review.md +3 -2
- package/dist/templates/ainative/artifacts/verify.md +3 -2
- package/dist/templates/ainative/skills/native-build-plan.md +9 -0
- package/dist/templates/ainative/skills/native-implement.md +26 -2
- package/dist/templates/ainative/skills/native-review.md +7 -3
- package/dist/templates/ainative/skills/native-verify.md +7 -2
- package/dist/templates/ainative/validators/verdict.mjs +109 -0
- package/dist/templates/sdlc/validators/ci.mjs +3 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -19700,6 +19700,7 @@ var require_FollowUpHookSchema = __commonJS({
|
|
|
19700
19700
|
return typeof p === "string" && path17.posix.basename(p.replace(/\\/g, "/")) === exports2.FOLLOW_UPS_FILE;
|
|
19701
19701
|
});
|
|
19702
19702
|
}
|
|
19703
|
+
var STEP_KEYS_NOT_HOOKS = ["on_reject"];
|
|
19703
19704
|
function collectFollowUpHookIssues(raw) {
|
|
19704
19705
|
const issues = [];
|
|
19705
19706
|
const pipelines = raw?.pipelines;
|
|
@@ -19720,7 +19721,7 @@ var require_FollowUpHookSchema = __commonJS({
|
|
|
19720
19721
|
const label = typeof step.name === "string" ? step.name : typeof step.agent === "string" ? step.agent : String(si);
|
|
19721
19722
|
const at = `pipelines.${pid}.steps.${label}`;
|
|
19722
19723
|
for (const key of Object.keys(step)) {
|
|
19723
|
-
if (!key.startsWith("on_")) {
|
|
19724
|
+
if (!key.startsWith("on_") || STEP_KEYS_NOT_HOOKS.includes(key)) {
|
|
19724
19725
|
continue;
|
|
19725
19726
|
}
|
|
19726
19727
|
if (!isHookKey(key)) {
|
|
@@ -19763,14 +19764,18 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
19763
19764
|
"../core/dist/schema/WorkspaceSchema.js"(exports2) {
|
|
19764
19765
|
"use strict";
|
|
19765
19766
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
19766
|
-
exports2.WorkspaceValidationError = exports2.WorkspaceSchema = void 0;
|
|
19767
|
-
exports2.normalizeStep =
|
|
19767
|
+
exports2.WorkspaceValidationError = exports2.WorkspaceSchema = exports2.AMBIGUOUS_STEP_INDEX = exports2.DEFAULT_MAX_BATCHES = exports2.DEFAULT_MAX_SEND_BACKS = void 0;
|
|
19768
|
+
exports2.normalizeStep = normalizeStep5;
|
|
19768
19769
|
exports2.stepSkillAlternatives = stepSkillAlternatives;
|
|
19769
19770
|
exports2.resolveStepSkills = resolveStepSkills;
|
|
19770
19771
|
exports2.producesEntries = producesEntries;
|
|
19772
|
+
exports2.requiresEntries = requiresEntries;
|
|
19771
19773
|
exports2.stepAgentId = stepAgentId3;
|
|
19772
19774
|
exports2.stepDagId = stepDagId;
|
|
19775
|
+
exports2.findStepIndex = findStepIndex2;
|
|
19776
|
+
exports2.sendBackIssues = sendBackIssues;
|
|
19773
19777
|
exports2.collectWorkspaceRefIssues = collectWorkspaceRefIssues3;
|
|
19778
|
+
exports2.unsafeRunnerArg = unsafeRunnerArg;
|
|
19774
19779
|
exports2.validateWorkspace = validateWorkspace6;
|
|
19775
19780
|
var zod_1 = require_zod();
|
|
19776
19781
|
var FollowUpHookSchema_1 = require_FollowUpHookSchema();
|
|
@@ -19916,8 +19921,14 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
19916
19921
|
* agent's `models` as one more choice on the card; a pick there wins.
|
|
19917
19922
|
*/
|
|
19918
19923
|
model: zod_1.z.string().min(1).optional(),
|
|
19919
|
-
/**
|
|
19920
|
-
|
|
19924
|
+
/**
|
|
19925
|
+
* Artifact paths required from upstream. Gate-checked before work AND on
|
|
19926
|
+
* Mark step done — except entries marked `{ path, optional: true }`, for
|
|
19927
|
+
* an upstream file that is legitimately absent on some runs (an upstream
|
|
19928
|
+
* `produces` entry that is itself optional). Those are listed with the
|
|
19929
|
+
* step but never block it.
|
|
19930
|
+
*/
|
|
19931
|
+
requires: zod_1.z.array(ProducesEntrySchema).default([]),
|
|
19921
19932
|
/**
|
|
19922
19933
|
* Agent ids of upstream steps this step depends on. When non-empty the
|
|
19923
19934
|
* step stays `pending` until every listed step transitions to `approved`,
|
|
@@ -19940,6 +19951,46 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
19940
19951
|
* (infinite loop, network stall). Defaults to 120_000 when omitted.
|
|
19941
19952
|
*/
|
|
19942
19953
|
auto_review_timeout_ms: zod_1.z.number().int().positive().optional(),
|
|
19954
|
+
/**
|
|
19955
|
+
* Where an `auto_review` reject sends the work. Without it the step is
|
|
19956
|
+
* rejected in place and the run stops — right for a check on the step's
|
|
19957
|
+
* own output, wrong for verify/review, where running the check again on
|
|
19958
|
+
* the same code gives the same answer and it is `implement` that has to
|
|
19959
|
+
* change. The target reopens with the reason as its feedback, the steps
|
|
19960
|
+
* after it reset, and the autopilot loop carries on from there.
|
|
19961
|
+
*
|
|
19962
|
+
* The target is a step name (or agent id) before this one, without
|
|
19963
|
+
* `human_review` — work a human gate approved goes back through a human.
|
|
19964
|
+
* A validator can name the same target in its verdict (`sendBackTo`), or
|
|
19965
|
+
* name this step / `null` to stop here instead. Bounded by the
|
|
19966
|
+
* pipeline's `max_send_backs`.
|
|
19967
|
+
*/
|
|
19968
|
+
on_reject: zod_1.z.object({ send_back_to: zod_1.z.string().min(1) }).optional(),
|
|
19969
|
+
/**
|
|
19970
|
+
* Minutes the step's agent may run under `aidlc run exec` / Run to
|
|
19971
|
+
* completion before it is stopped (the whole process tree: SIGTERM, then
|
|
19972
|
+
* SIGKILL). A timed-out step fails the run — it is not sent back and does
|
|
19973
|
+
* not count toward `max_send_backs` — and stays `awaiting_work`. Unset
|
|
19974
|
+
* means no limit.
|
|
19975
|
+
*/
|
|
19976
|
+
timeout_minutes: zod_1.z.number().positive().optional(),
|
|
19977
|
+
/**
|
|
19978
|
+
* Run the step as a series of agent sessions ("batches") instead of one.
|
|
19979
|
+
* Each session does a slice of the work and ends its first `produces`
|
|
19980
|
+
* file with `Status: continue` or `Status: done`; on `continue` the exec
|
|
19981
|
+
* loop starts a fresh session on the same revision. A missing or
|
|
19982
|
+
* unreadable `Status:` line fails the step. `timeout_minutes` applies to
|
|
19983
|
+
* each batch.
|
|
19984
|
+
*/
|
|
19985
|
+
batches: zod_1.z.boolean().optional(),
|
|
19986
|
+
/**
|
|
19987
|
+
* Batches one `aidlc run exec` may run on this step before it stops for a
|
|
19988
|
+
* person ({@link DEFAULT_MAX_BATCHES} when unset). Running exec again
|
|
19989
|
+
* allows as many more.
|
|
19990
|
+
*/
|
|
19991
|
+
max_batches: zod_1.z.number().int().positive().optional(),
|
|
19992
|
+
/** Stop the loop after every `continue` batch, for a person to look before the next. */
|
|
19993
|
+
pause_between_batches: zod_1.z.boolean().optional(),
|
|
19943
19994
|
/** When true, the runner pauses for human approval before advancing. */
|
|
19944
19995
|
human_review: zod_1.z.boolean().default(false),
|
|
19945
19996
|
/**
|
|
@@ -20001,12 +20052,42 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20001
20052
|
recipe: zod_1.z.string().min(1).optional(),
|
|
20002
20053
|
steps: zod_1.z.array(PipelineStepSchema).min(1),
|
|
20003
20054
|
on_failure: zod_1.z.enum(["stop", "continue"]).default("stop"),
|
|
20004
|
-
budget: PipelineBudgetSchema.optional()
|
|
20055
|
+
budget: PipelineBudgetSchema.optional(),
|
|
20056
|
+
/**
|
|
20057
|
+
* How many times the autopilot loop may send work back (`on_reject`)
|
|
20058
|
+
* before it stops for a human. Counted from the last time a human acted on
|
|
20059
|
+
* the run — approve, reject, rerun, request update — so a run that was
|
|
20060
|
+
* steered by hand does not start out at the ceiling. Defaults to
|
|
20061
|
+
* {@link DEFAULT_MAX_SEND_BACKS}; 0 stops at the first reject.
|
|
20062
|
+
*/
|
|
20063
|
+
max_send_backs: zod_1.z.number().int().min(0).optional(),
|
|
20064
|
+
/**
|
|
20065
|
+
* The run is meant to go unattended. `aidlc run exec` / Run to completion
|
|
20066
|
+
* then refuses to start unless it is safe to leave alone — on a branch
|
|
20067
|
+
* other than main, a clean working tree, the approval-gate hook registered
|
|
20068
|
+
* for Claude steps — and the hook blocks on its own errors instead of
|
|
20069
|
+
* allowing. See `runs/autopilotPreflight.ts`.
|
|
20070
|
+
*/
|
|
20071
|
+
autopilot: zod_1.z.boolean().optional()
|
|
20072
|
+
}).superRefine((p, ctx) => {
|
|
20073
|
+
for (const issue of sendBackIssues(p.steps)) {
|
|
20074
|
+
ctx.addIssue({ code: "custom", path: ["steps", issue.stepIdx, "on_reject", "send_back_to"], message: issue.message });
|
|
20075
|
+
}
|
|
20005
20076
|
});
|
|
20077
|
+
exports2.DEFAULT_MAX_SEND_BACKS = 3;
|
|
20078
|
+
exports2.DEFAULT_MAX_BATCHES = 10;
|
|
20006
20079
|
var RecipeGateSchema = zod_1.z.object({
|
|
20007
20080
|
human_review: zod_1.z.boolean().optional(),
|
|
20008
20081
|
auto_review: zod_1.z.boolean().optional(),
|
|
20009
|
-
auto_review_runner: zod_1.z.string().min(1).optional()
|
|
20082
|
+
auto_review_runner: zod_1.z.string().min(1).optional(),
|
|
20083
|
+
/** Where this step's auto-review reject sends the work — see the step's `on_reject`. */
|
|
20084
|
+
on_reject: zod_1.z.object({ send_back_to: zod_1.z.string().min(1) }).optional(),
|
|
20085
|
+
/** Run-time limit for this step — see the step's `timeout_minutes`. */
|
|
20086
|
+
timeout_minutes: zod_1.z.number().positive().optional(),
|
|
20087
|
+
/** Batched sessions for this step — see the step's `batches`. */
|
|
20088
|
+
batches: zod_1.z.boolean().optional(),
|
|
20089
|
+
max_batches: zod_1.z.number().int().positive().optional(),
|
|
20090
|
+
pause_between_batches: zod_1.z.boolean().optional()
|
|
20010
20091
|
});
|
|
20011
20092
|
var RecipeSchema = zod_1.z.object({
|
|
20012
20093
|
id: zod_1.z.string().min(1),
|
|
@@ -20031,9 +20112,13 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20031
20112
|
* plan) and none after, a risky one wants them everywhere. Only the fields
|
|
20032
20113
|
* present override; the rest inherit.
|
|
20033
20114
|
*/
|
|
20034
|
-
gates: zod_1.z.record(zod_1.z.string(), RecipeGateSchema).optional()
|
|
20115
|
+
gates: zod_1.z.record(zod_1.z.string(), RecipeGateSchema).optional(),
|
|
20116
|
+
/** Sets the assembled pipeline's `autopilot` — see the pipeline's. */
|
|
20117
|
+
autopilot: zod_1.z.boolean().optional(),
|
|
20118
|
+
/** Sets the assembled pipeline's `max_send_backs`, over the source pipeline's. */
|
|
20119
|
+
max_send_backs: zod_1.z.number().int().min(0).optional()
|
|
20035
20120
|
});
|
|
20036
|
-
function
|
|
20121
|
+
function normalizeStep5(step) {
|
|
20037
20122
|
if (typeof step === "string") {
|
|
20038
20123
|
return {
|
|
20039
20124
|
agent: step,
|
|
@@ -20043,26 +20128,15 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20043
20128
|
produces_optional: [],
|
|
20044
20129
|
produces_contains: [],
|
|
20045
20130
|
requires: [],
|
|
20131
|
+
requires_optional: [],
|
|
20046
20132
|
depends_on: [],
|
|
20047
20133
|
auto_review: false,
|
|
20048
20134
|
human_review: false
|
|
20049
20135
|
};
|
|
20050
20136
|
}
|
|
20051
20137
|
const obj = step;
|
|
20052
|
-
const requires =
|
|
20053
|
-
const produces =
|
|
20054
|
-
const produces_optional = [];
|
|
20055
|
-
for (const entry of Array.isArray(obj.produces) ? obj.produces : []) {
|
|
20056
|
-
if (typeof entry === "string") {
|
|
20057
|
-
produces.push(entry);
|
|
20058
|
-
} else if (entry && typeof entry === "object" && typeof entry.path === "string") {
|
|
20059
|
-
const e = entry;
|
|
20060
|
-
produces.push(e.path);
|
|
20061
|
-
if (e.optional === true) {
|
|
20062
|
-
produces_optional.push(e.path);
|
|
20063
|
-
}
|
|
20064
|
-
}
|
|
20065
|
-
}
|
|
20138
|
+
const [requires, requires_optional] = splitArtifactEntries(obj.requires);
|
|
20139
|
+
const [produces, produces_optional] = splitArtifactEntries(obj.produces);
|
|
20066
20140
|
const produces_contains = Array.isArray(obj.produces_contains) ? obj.produces_contains : [];
|
|
20067
20141
|
const depends_on = Array.isArray(obj.depends_on) ? obj.depends_on : [];
|
|
20068
20142
|
const skills = Array.isArray(obj.skills) ? obj.skills.map(String).filter((s) => s.length > 0) : typeof obj.skill === "string" && obj.skill.length > 0 ? [obj.skill] : void 0;
|
|
@@ -20085,10 +20159,19 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20085
20159
|
produces_optional,
|
|
20086
20160
|
produces_contains,
|
|
20087
20161
|
requires,
|
|
20162
|
+
requires_optional,
|
|
20088
20163
|
depends_on,
|
|
20089
20164
|
auto_review: obj.auto_review === true,
|
|
20090
20165
|
auto_review_runner: typeof obj.auto_review_runner === "string" ? obj.auto_review_runner : void 0,
|
|
20091
20166
|
auto_review_timeout_ms: typeof obj.auto_review_timeout_ms === "number" && obj.auto_review_timeout_ms > 0 ? obj.auto_review_timeout_ms : void 0,
|
|
20167
|
+
...isOnReject(obj.on_reject) ? { on_reject: { send_back_to: obj.on_reject.send_back_to } } : {},
|
|
20168
|
+
...typeof obj.timeout_minutes === "number" && obj.timeout_minutes > 0 ? { timeout_minutes: obj.timeout_minutes } : {},
|
|
20169
|
+
...obj.batches === true ? {
|
|
20170
|
+
batches: {
|
|
20171
|
+
max: typeof obj.max_batches === "number" && obj.max_batches >= 1 ? Math.floor(obj.max_batches) : exports2.DEFAULT_MAX_BATCHES,
|
|
20172
|
+
pause: obj.pause_between_batches === true
|
|
20173
|
+
}
|
|
20174
|
+
} : {},
|
|
20092
20175
|
human_review: obj.human_review === true,
|
|
20093
20176
|
...git && { git }
|
|
20094
20177
|
};
|
|
@@ -20110,6 +20193,25 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20110
20193
|
const optional = new Set(norm.produces_optional);
|
|
20111
20194
|
return norm.produces.map((p) => optional.has(p) ? { path: p, optional: true } : p);
|
|
20112
20195
|
}
|
|
20196
|
+
function requiresEntries(norm) {
|
|
20197
|
+
return producesEntries({ produces: norm.requires, produces_optional: norm.requires_optional });
|
|
20198
|
+
}
|
|
20199
|
+
function splitArtifactEntries(raw) {
|
|
20200
|
+
const all = [];
|
|
20201
|
+
const optional = [];
|
|
20202
|
+
for (const entry of Array.isArray(raw) ? raw : []) {
|
|
20203
|
+
if (typeof entry === "string") {
|
|
20204
|
+
all.push(entry);
|
|
20205
|
+
} else if (entry && typeof entry === "object" && typeof entry.path === "string") {
|
|
20206
|
+
const e = entry;
|
|
20207
|
+
all.push(e.path);
|
|
20208
|
+
if (e.optional === true) {
|
|
20209
|
+
optional.push(e.path);
|
|
20210
|
+
}
|
|
20211
|
+
}
|
|
20212
|
+
}
|
|
20213
|
+
return [all, optional];
|
|
20214
|
+
}
|
|
20113
20215
|
function stepAgentId3(step) {
|
|
20114
20216
|
if (typeof step === "string") {
|
|
20115
20217
|
return step;
|
|
@@ -20120,9 +20222,57 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20120
20222
|
return "";
|
|
20121
20223
|
}
|
|
20122
20224
|
function stepDagId(step) {
|
|
20123
|
-
const norm =
|
|
20225
|
+
const norm = normalizeStep5(step);
|
|
20124
20226
|
return norm.name ?? norm.agent;
|
|
20125
20227
|
}
|
|
20228
|
+
exports2.AMBIGUOUS_STEP_INDEX = -2;
|
|
20229
|
+
function findStepIndex2(steps, ref) {
|
|
20230
|
+
const asInt = parseInt(ref, 10);
|
|
20231
|
+
if (!isNaN(asInt) && String(asInt) === ref) {
|
|
20232
|
+
return asInt >= 0 && asInt < steps.length ? asInt : -1;
|
|
20233
|
+
}
|
|
20234
|
+
const byName = steps.findIndex((s) => s.name === ref);
|
|
20235
|
+
if (byName >= 0) {
|
|
20236
|
+
return byName;
|
|
20237
|
+
}
|
|
20238
|
+
const byAgent = steps.map((s, i) => s.agent === ref ? i : -1).filter((i) => i >= 0);
|
|
20239
|
+
if (byAgent.length > 1) {
|
|
20240
|
+
return exports2.AMBIGUOUS_STEP_INDEX;
|
|
20241
|
+
}
|
|
20242
|
+
return byAgent.length === 1 ? byAgent[0] : -1;
|
|
20243
|
+
}
|
|
20244
|
+
function isOnReject(v) {
|
|
20245
|
+
return !!v && typeof v === "object" && typeof v.send_back_to === "string" && v.send_back_to.length > 0;
|
|
20246
|
+
}
|
|
20247
|
+
function sendBackIssues(steps) {
|
|
20248
|
+
const norms = steps.map((s) => normalizeStep5(s));
|
|
20249
|
+
const issues = [];
|
|
20250
|
+
norms.forEach((n, i) => {
|
|
20251
|
+
const target = n.on_reject?.send_back_to;
|
|
20252
|
+
if (!target) {
|
|
20253
|
+
return;
|
|
20254
|
+
}
|
|
20255
|
+
const id = n.name ?? n.agent;
|
|
20256
|
+
const add = (message) => {
|
|
20257
|
+
issues.push({ stepIdx: i, message: `Step "${id}": ${message}` });
|
|
20258
|
+
};
|
|
20259
|
+
if (!n.auto_review) {
|
|
20260
|
+
add("`on_reject` routes an auto-review reject, and this step has `auto_review` off.");
|
|
20261
|
+
return;
|
|
20262
|
+
}
|
|
20263
|
+
const t = findStepIndex2(norms, target);
|
|
20264
|
+
if (t === exports2.AMBIGUOUS_STEP_INDEX) {
|
|
20265
|
+
add(`\`on_reject.send_back_to\` "${target}" is an agent with more than one step; name the step.`);
|
|
20266
|
+
} else if (t < 0) {
|
|
20267
|
+
add(`\`on_reject.send_back_to\` "${target}" is not a step of this pipeline.`);
|
|
20268
|
+
} else if (t >= i) {
|
|
20269
|
+
add(`\`on_reject.send_back_to\` "${target}" must be a step before this one.`);
|
|
20270
|
+
} else if (norms[t].human_review) {
|
|
20271
|
+
add(`\`on_reject.send_back_to\` "${target}" has \`human_review: true\`. Work a human approved goes back through a human \u2014 turn that gate off or drop \`on_reject\`.`);
|
|
20272
|
+
}
|
|
20273
|
+
});
|
|
20274
|
+
return issues;
|
|
20275
|
+
}
|
|
20126
20276
|
function collectWorkspaceRefIssues3(config) {
|
|
20127
20277
|
const issues = [];
|
|
20128
20278
|
const agentIds = new Set(config.agents.map((a) => a.id));
|
|
@@ -20140,7 +20290,7 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20140
20290
|
}
|
|
20141
20291
|
for (const pipeline of config.pipelines) {
|
|
20142
20292
|
for (const step of pipeline.steps) {
|
|
20143
|
-
const norm =
|
|
20293
|
+
const norm = normalizeStep5(step);
|
|
20144
20294
|
const id = norm.name ?? norm.agent;
|
|
20145
20295
|
if (!agentIds.has(norm.agent)) {
|
|
20146
20296
|
issues.push({
|
|
@@ -20266,8 +20416,60 @@ var require_WorkspaceSchema = __commonJS({
|
|
|
20266
20416
|
/** Claude tier alias (or any `model:` value) → concrete model id, lowercased keys. */
|
|
20267
20417
|
model_aliases: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).default({}),
|
|
20268
20418
|
/** Model id → rate. The key `*` applies to every model of this provider. */
|
|
20269
|
-
rates: zod_1.z.record(zod_1.z.string(), ProviderRateSchema).default({})
|
|
20419
|
+
rates: zod_1.z.record(zod_1.z.string(), ProviderRateSchema).default({}),
|
|
20420
|
+
/**
|
|
20421
|
+
* Extra command-line arguments for this runner's CLI, added to every step it
|
|
20422
|
+
* runs — chiefly what a headless agent may do without asking:
|
|
20423
|
+
*
|
|
20424
|
+
* ```yaml
|
|
20425
|
+
* providers:
|
|
20426
|
+
* default:
|
|
20427
|
+
* args: [--permission-mode, acceptEdits, --allowedTools, "Bash(npm test:*)"]
|
|
20428
|
+
* ```
|
|
20429
|
+
*
|
|
20430
|
+
* Committed with the workspace, so the whole team runs with the same
|
|
20431
|
+
* permissions instead of each clone's own `.claude/settings.json`. Flags
|
|
20432
|
+
* that switch permission checks off altogether are refused — see
|
|
20433
|
+
* {@link unsafeRunnerArg}.
|
|
20434
|
+
*/
|
|
20435
|
+
args: zod_1.z.array(zod_1.z.string()).default([])
|
|
20436
|
+
}).superRefine((p, ctx) => {
|
|
20437
|
+
const bad = unsafeRunnerArg(p.args);
|
|
20438
|
+
if (bad) {
|
|
20439
|
+
ctx.addIssue({
|
|
20440
|
+
code: "custom",
|
|
20441
|
+
path: ["args"],
|
|
20442
|
+
message: `\`${bad}\` switches the agent's permission checks off, and \`args\` is committed for everyone who runs this workspace \u2014 unattended runs included. Allow the tools it needs instead (\`--allowedTools\` for Claude), or run it in a sandbox of your own with \`runner: custom\`.`
|
|
20443
|
+
});
|
|
20444
|
+
}
|
|
20270
20445
|
});
|
|
20446
|
+
function unsafeRunnerArg(args) {
|
|
20447
|
+
const flags = /* @__PURE__ */ new Set([
|
|
20448
|
+
"--dangerously-skip-permissions",
|
|
20449
|
+
"--allow-dangerously-skip-permissions",
|
|
20450
|
+
"--dangerously-bypass-approvals-and-sandbox",
|
|
20451
|
+
"--yolo",
|
|
20452
|
+
"--allow-all",
|
|
20453
|
+
"--allow-all-paths"
|
|
20454
|
+
]);
|
|
20455
|
+
const values = {
|
|
20456
|
+
"--permission-mode": "bypassPermissions",
|
|
20457
|
+
"--sandbox": "danger-full-access",
|
|
20458
|
+
"-s": "danger-full-access"
|
|
20459
|
+
};
|
|
20460
|
+
for (let i = 0; i < args.length; i++) {
|
|
20461
|
+
const [flag, inline] = args[i].split(/=(.*)/s, 2);
|
|
20462
|
+
if (flags.has(flag)) {
|
|
20463
|
+
return args[i];
|
|
20464
|
+
}
|
|
20465
|
+
const unsafe = values[flag];
|
|
20466
|
+
const value = inline ?? args[i + 1];
|
|
20467
|
+
if (unsafe && value === unsafe) {
|
|
20468
|
+
return `${flag} ${unsafe}`;
|
|
20469
|
+
}
|
|
20470
|
+
}
|
|
20471
|
+
return null;
|
|
20472
|
+
}
|
|
20271
20473
|
exports2.WorkspaceSchema = zod_1.z.object({
|
|
20272
20474
|
/** Schema version — bump on breaking changes. Currently always "1.0". */
|
|
20273
20475
|
version: zod_1.z.string().min(1),
|
|
@@ -20378,7 +20580,7 @@ var require_PipelineAssembler = __commonJS({
|
|
|
20378
20580
|
"use strict";
|
|
20379
20581
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
20380
20582
|
exports2.PipelineAssembleError = void 0;
|
|
20381
|
-
exports2.assemblePipeline =
|
|
20583
|
+
exports2.assemblePipeline = assemblePipeline5;
|
|
20382
20584
|
exports2.recipePipelineId = recipePipelineId4;
|
|
20383
20585
|
exports2.pipelineRecipeLabel = pipelineRecipeLabel;
|
|
20384
20586
|
var WorkspaceSchema_1 = require_WorkspaceSchema();
|
|
@@ -20389,7 +20591,7 @@ var require_PipelineAssembler = __commonJS({
|
|
|
20389
20591
|
}
|
|
20390
20592
|
};
|
|
20391
20593
|
exports2.PipelineAssembleError = PipelineAssembleError4;
|
|
20392
|
-
function
|
|
20594
|
+
function assemblePipeline5(config, opts) {
|
|
20393
20595
|
const recipe = config.recipes.find((r) => r.id === opts.recipeId);
|
|
20394
20596
|
if (!recipe) {
|
|
20395
20597
|
const available = config.recipes.map((r) => r.id).join(", ") || "(none defined)";
|
|
@@ -20446,7 +20648,7 @@ var require_PipelineAssembler = __commonJS({
|
|
|
20446
20648
|
name: norm.name ?? id,
|
|
20447
20649
|
enabled: norm.enabled,
|
|
20448
20650
|
produces: (0, WorkspaceSchema_1.producesEntries)(norm),
|
|
20449
|
-
requires: norm
|
|
20651
|
+
requires: (0, WorkspaceSchema_1.requiresEntries)(norm),
|
|
20450
20652
|
depends_on,
|
|
20451
20653
|
auto_review,
|
|
20452
20654
|
human_review: gate.human_review ?? norm.human_review
|
|
@@ -20466,14 +20668,40 @@ var require_PipelineAssembler = __commonJS({
|
|
|
20466
20668
|
if (auto_review_runner) {
|
|
20467
20669
|
step.auto_review_runner = auto_review_runner;
|
|
20468
20670
|
}
|
|
20671
|
+
const on_reject = gate.on_reject ?? norm.on_reject;
|
|
20672
|
+
if (on_reject) {
|
|
20673
|
+
step.on_reject = { send_back_to: on_reject.send_back_to };
|
|
20674
|
+
}
|
|
20675
|
+
const timeout_minutes = gate.timeout_minutes ?? norm.timeout_minutes;
|
|
20676
|
+
if (timeout_minutes !== void 0) {
|
|
20677
|
+
step.timeout_minutes = timeout_minutes;
|
|
20678
|
+
}
|
|
20679
|
+
const batched = gate.batches ?? norm.batches !== void 0;
|
|
20680
|
+
if (batched) {
|
|
20681
|
+
step.batches = true;
|
|
20682
|
+
const max = gate.max_batches ?? norm.batches?.max;
|
|
20683
|
+
if (max !== void 0) {
|
|
20684
|
+
step.max_batches = max;
|
|
20685
|
+
}
|
|
20686
|
+
if (gate.pause_between_batches ?? norm.batches?.pause) {
|
|
20687
|
+
step.pause_between_batches = true;
|
|
20688
|
+
}
|
|
20689
|
+
}
|
|
20469
20690
|
return step;
|
|
20470
20691
|
});
|
|
20692
|
+
const sendBackProblems = (0, WorkspaceSchema_1.sendBackIssues)(steps);
|
|
20693
|
+
if (sendBackProblems.length > 0) {
|
|
20694
|
+
throw new PipelineAssembleError4(`Recipe "${recipe.id}" assembled a pipeline whose \`on_reject\` cannot work:
|
|
20695
|
+
` + sendBackProblems.map((i) => ` - ${i.message}`).join("\n"));
|
|
20696
|
+
}
|
|
20471
20697
|
const assembled = {
|
|
20472
20698
|
id: opts.pipelineId ?? recipe.id,
|
|
20473
20699
|
derived_from: source.id,
|
|
20474
20700
|
recipe: recipe.id,
|
|
20475
20701
|
steps,
|
|
20476
|
-
on_failure: source.on_failure
|
|
20702
|
+
on_failure: source.on_failure,
|
|
20703
|
+
...(recipe.max_send_backs ?? source.max_send_backs) !== void 0 ? { max_send_backs: recipe.max_send_backs ?? source.max_send_backs } : {},
|
|
20704
|
+
...(recipe.autopilot ?? source.autopilot) !== void 0 ? { autopilot: recipe.autopilot ?? source.autopilot } : {}
|
|
20477
20705
|
};
|
|
20478
20706
|
const refIssues = (0, WorkspaceSchema_1.collectWorkspaceRefIssues)({
|
|
20479
20707
|
...config,
|
|
@@ -20795,7 +21023,7 @@ ${raw.slice(0, 200)}`);
|
|
|
20795
21023
|
name: norm.name ?? a.phase,
|
|
20796
21024
|
enabled: norm.enabled,
|
|
20797
21025
|
produces: (0, WorkspaceSchema_1.producesEntries)(norm),
|
|
20798
|
-
requires: norm
|
|
21026
|
+
requires: (0, WorkspaceSchema_1.requiresEntries)(norm),
|
|
20799
21027
|
depends_on: anchor ? [anchor] : usesDag && steps.length > 0 ? [(0, WorkspaceSchema_1.stepDagId)(steps[steps.length - 1])] : [],
|
|
20800
21028
|
auto_review: norm.auto_review,
|
|
20801
21029
|
human_review: norm.human_review
|
|
@@ -21318,6 +21546,9 @@ var require_PipelineRunner = __commonJS({
|
|
|
21318
21546
|
steps
|
|
21319
21547
|
};
|
|
21320
21548
|
}
|
|
21549
|
+
function requiredPaths(norm) {
|
|
21550
|
+
return norm.requires.filter((p) => !norm.requires_optional.includes(p));
|
|
21551
|
+
}
|
|
21321
21552
|
function canStartStep(args) {
|
|
21322
21553
|
const { state, pipeline, workspaceRoot } = args;
|
|
21323
21554
|
const idx = args.stepIdx ?? state.currentStepIdx;
|
|
@@ -21327,7 +21558,7 @@ var require_PipelineRunner = __commonJS({
|
|
|
21327
21558
|
}
|
|
21328
21559
|
const norm = (0, WorkspaceSchema_1.normalizeStep)(stepConfig);
|
|
21329
21560
|
const missing = [];
|
|
21330
|
-
for (const rel of norm.
|
|
21561
|
+
for (const rel of requiredPaths(norm).map((p) => (0, RunState_1.resolvePath)(p, state.context))) {
|
|
21331
21562
|
const abs = path17.isAbsolute(rel) ? rel : path17.join(workspaceRoot, rel);
|
|
21332
21563
|
if (!fs14.existsSync(abs)) {
|
|
21333
21564
|
missing.push(rel);
|
|
@@ -21354,7 +21585,7 @@ var require_PipelineRunner = __commonJS({
|
|
|
21354
21585
|
throw new PipelineRunError3(`Pipeline mismatch \u2014 step "${(0, RunState_1.stepIdentity)(step)}" is at index ${idx}, which pipeline "${pipeline.id}" does not have.`);
|
|
21355
21586
|
}
|
|
21356
21587
|
const norm = (0, WorkspaceSchema_1.normalizeStep)(stepConfig);
|
|
21357
|
-
const resolvedRequires = norm.
|
|
21588
|
+
const resolvedRequires = requiredPaths(norm).map((p) => (0, RunState_1.resolvePath)(p, state.context));
|
|
21358
21589
|
const missingRequires = [];
|
|
21359
21590
|
for (const rel of resolvedRequires) {
|
|
21360
21591
|
const abs = path17.isAbsolute(rel) ? rel : path17.join(workspaceRoot, rel);
|
|
@@ -21476,6 +21707,7 @@ var require_PipelineRunner = __commonJS({
|
|
|
21476
21707
|
const step = state.steps[idx];
|
|
21477
21708
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21478
21709
|
const next = clone(state);
|
|
21710
|
+
delete next.sendBacks;
|
|
21479
21711
|
if (step.status === "approved") {
|
|
21480
21712
|
for (const i of followersOf(pipeline, idx)) {
|
|
21481
21713
|
const follower = next.steps[i];
|
|
@@ -21533,13 +21765,34 @@ var require_PipelineRunner = __commonJS({
|
|
|
21533
21765
|
runner: verdict.runner
|
|
21534
21766
|
});
|
|
21535
21767
|
if (verdict.decision === "reject") {
|
|
21768
|
+
const route = autoRejectRoute(next, pipeline, idx, norm, verdict);
|
|
21769
|
+
if ("targetIdx" in route) {
|
|
21770
|
+
const count = next.sendBacks ?? 0;
|
|
21771
|
+
const max = pipeline.max_send_backs ?? WorkspaceSchema_1.DEFAULT_MAX_SEND_BACKS;
|
|
21772
|
+
if (count < max) {
|
|
21773
|
+
sendBack(next, {
|
|
21774
|
+
idx,
|
|
21775
|
+
targetIdx: route.targetIdx,
|
|
21776
|
+
reason: verdict.reason,
|
|
21777
|
+
at: verdict.at,
|
|
21778
|
+
pipeline,
|
|
21779
|
+
source: route.source
|
|
21780
|
+
});
|
|
21781
|
+
next.sendBacks = count + 1;
|
|
21782
|
+
return next;
|
|
21783
|
+
}
|
|
21784
|
+
route.note = `Sent back ${count} time${count === 1 ? "" : "s"} already (max_send_backs: ${max}) \u2014 stopping for a human instead of going round again.`;
|
|
21785
|
+
}
|
|
21786
|
+
const reason = "note" in route && route.note ? `${verdict.reason}
|
|
21787
|
+
|
|
21788
|
+
${route.note}` : verdict.reason;
|
|
21536
21789
|
nextStep.status = "rejected";
|
|
21537
|
-
nextStep.rejectReason =
|
|
21790
|
+
nextStep.rejectReason = reason;
|
|
21538
21791
|
nextStep.history = pushHistory(nextStep.history, {
|
|
21539
21792
|
kind: "reject",
|
|
21540
21793
|
at: verdict.at,
|
|
21541
21794
|
revision: nextStep.revision,
|
|
21542
|
-
reason
|
|
21795
|
+
reason,
|
|
21543
21796
|
sentBackToIdx: idx,
|
|
21544
21797
|
...nextStep.skill ? { skill: nextStep.skill } : {},
|
|
21545
21798
|
...nextStep.chosenModel ? { model: nextStep.chosenModel } : {}
|
|
@@ -21555,6 +21808,35 @@ var require_PipelineRunner = __commonJS({
|
|
|
21555
21808
|
}
|
|
21556
21809
|
return advance(next, idx, pipeline);
|
|
21557
21810
|
}
|
|
21811
|
+
function autoRejectRoute(state, pipeline, idx, norm, verdict) {
|
|
21812
|
+
const label = (i) => `"${(0, RunState_1.stepIdentity)(state.steps[i])}" (step ${i + 1})`;
|
|
21813
|
+
const configured = norm.on_reject?.send_back_to;
|
|
21814
|
+
const cfgIdx = configured ? (0, WorkspaceSchema_1.findStepIndex)(pipeline.steps.map(WorkspaceSchema_1.normalizeStep), configured) : -1;
|
|
21815
|
+
if (configured && !(cfgIdx >= 0 && cfgIdx < idx)) {
|
|
21816
|
+
return { note: `\`on_reject.send_back_to\` "${configured}" is not a step before this one \u2014 fix the pipeline.` };
|
|
21817
|
+
}
|
|
21818
|
+
if (verdict.sendBackTo === void 0) {
|
|
21819
|
+
return cfgIdx >= 0 ? { targetIdx: cfgIdx, source: "config" } : {};
|
|
21820
|
+
}
|
|
21821
|
+
if (verdict.sendBackTo === null) {
|
|
21822
|
+
return {};
|
|
21823
|
+
}
|
|
21824
|
+
const asked = String(verdict.sendBackTo);
|
|
21825
|
+
const v = (0, WorkspaceSchema_1.findStepIndex)(state.steps, asked);
|
|
21826
|
+
if (v === idx) {
|
|
21827
|
+
return {};
|
|
21828
|
+
}
|
|
21829
|
+
if (v < 0 || v > idx) {
|
|
21830
|
+
return { note: `The validator asked to send this back to "${asked}", which is not a step before this one.` };
|
|
21831
|
+
}
|
|
21832
|
+
if (v !== cfgIdx) {
|
|
21833
|
+
const allowed = cfgIdx >= 0 ? `only ${label(cfgIdx)} is` : "no step is (see `on_reject.send_back_to`)";
|
|
21834
|
+
return {
|
|
21835
|
+
note: `The validator suggests sending this back to ${label(v)}; ${allowed} sent back automatically. Send it back by hand if you agree.`
|
|
21836
|
+
};
|
|
21837
|
+
}
|
|
21838
|
+
return { targetIdx: v, source: "verdict" };
|
|
21839
|
+
}
|
|
21558
21840
|
function retryAutoReview(args) {
|
|
21559
21841
|
const { pipeline } = args;
|
|
21560
21842
|
const state = alignedOrThrow(args.state, pipeline);
|
|
@@ -21577,6 +21859,7 @@ var require_PipelineRunner = __commonJS({
|
|
|
21577
21859
|
throw new PipelineRunError3(`Step "${step.agent}" no longer has auto_review enabled in pipeline "${pipeline.id}".`);
|
|
21578
21860
|
}
|
|
21579
21861
|
const next = clone(state);
|
|
21862
|
+
delete next.sendBacks;
|
|
21580
21863
|
next.steps[idx] = {
|
|
21581
21864
|
...step,
|
|
21582
21865
|
status: "awaiting_auto_review",
|
|
@@ -21597,7 +21880,9 @@ var require_PipelineRunner = __commonJS({
|
|
|
21597
21880
|
if (step.status !== "awaiting_review") {
|
|
21598
21881
|
throw new PipelineRunError3(`Cannot approve step "${step.agent}": status is "${step.status}", expected "awaiting_review"`);
|
|
21599
21882
|
}
|
|
21600
|
-
|
|
21883
|
+
const next = clone(state);
|
|
21884
|
+
delete next.sendBacks;
|
|
21885
|
+
return advance(next, idx, pipeline);
|
|
21601
21886
|
}
|
|
21602
21887
|
function rejectStep3(args) {
|
|
21603
21888
|
const { state, reason, targetIdx, pipeline } = args;
|
|
@@ -21606,75 +21891,19 @@ var require_PipelineRunner = __commonJS({
|
|
|
21606
21891
|
if (!step) {
|
|
21607
21892
|
throw new PipelineRunError3(`No step at index ${idx}`);
|
|
21608
21893
|
}
|
|
21609
|
-
if (step.status !== "awaiting_review") {
|
|
21610
|
-
throw new PipelineRunError3(`Cannot reject step "${step.agent}": status is "${step.status}", expected "awaiting_review"`);
|
|
21611
|
-
}
|
|
21612
21894
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21613
21895
|
const isCascade = typeof targetIdx === "number" && targetIdx >= 0 && targetIdx < idx;
|
|
21896
|
+
if (step.status !== "awaiting_review" && !(isCascade && step.status === "rejected")) {
|
|
21897
|
+
throw new PipelineRunError3(`Cannot reject step "${step.agent}": status is "${step.status}", expected "awaiting_review"`);
|
|
21898
|
+
}
|
|
21614
21899
|
if (isCascade) {
|
|
21615
21900
|
const next2 = clone(state);
|
|
21616
|
-
|
|
21617
|
-
|
|
21618
|
-
kind: "reject",
|
|
21619
|
-
at: now,
|
|
21620
|
-
revision: next2.steps[idx].revision,
|
|
21621
|
-
reason,
|
|
21622
|
-
sentBackToIdx: targetIdx,
|
|
21623
|
-
...next2.steps[idx].skill ? { skill: next2.steps[idx].skill } : {},
|
|
21624
|
-
...next2.steps[idx].chosenModel ? { model: next2.steps[idx].chosenModel } : {}
|
|
21625
|
-
});
|
|
21626
|
-
const usesDag = pipeline ? pipeline.steps.map(WorkspaceSchema_1.normalizeStep).some((s) => s.depends_on.length > 0) : false;
|
|
21627
|
-
const targetIdxN = targetIdx;
|
|
21628
|
-
const resetIndices = usesDag && pipeline ? collectDagResetSet(pipeline, state, targetIdxN, idx) : sequentialRange(targetIdxN, idx);
|
|
21629
|
-
for (const i of resetIndices) {
|
|
21630
|
-
const s = next2.steps[i];
|
|
21631
|
-
if (i === targetIdxN) {
|
|
21632
|
-
const newRev = s.revision + 1;
|
|
21633
|
-
next2.steps[i] = {
|
|
21634
|
-
...s,
|
|
21635
|
-
status: "awaiting_work",
|
|
21636
|
-
revision: newRev,
|
|
21637
|
-
feedback: blame,
|
|
21638
|
-
rejectReason: void 0,
|
|
21639
|
-
autoReviewVerdict: void 0,
|
|
21640
|
-
artifactsProduced: [],
|
|
21641
|
-
finishedAt: void 0,
|
|
21642
|
-
startedAt: now,
|
|
21643
|
-
history: pushHistory(s.history, {
|
|
21644
|
-
kind: "rerun",
|
|
21645
|
-
at: now,
|
|
21646
|
-
revision: newRev,
|
|
21647
|
-
feedback: blame
|
|
21648
|
-
})
|
|
21649
|
-
};
|
|
21650
|
-
} else if (i === idx) {
|
|
21651
|
-
next2.steps[i] = {
|
|
21652
|
-
...s,
|
|
21653
|
-
status: "pending",
|
|
21654
|
-
rejectReason: void 0,
|
|
21655
|
-
autoReviewVerdict: void 0,
|
|
21656
|
-
artifactsProduced: [],
|
|
21657
|
-
startedAt: void 0,
|
|
21658
|
-
finishedAt: void 0,
|
|
21659
|
-
history: rejectedHistory
|
|
21660
|
-
};
|
|
21661
|
-
} else {
|
|
21662
|
-
next2.steps[i] = {
|
|
21663
|
-
...s,
|
|
21664
|
-
status: "pending",
|
|
21665
|
-
rejectReason: void 0,
|
|
21666
|
-
autoReviewVerdict: void 0,
|
|
21667
|
-
artifactsProduced: [],
|
|
21668
|
-
startedAt: void 0,
|
|
21669
|
-
finishedAt: void 0
|
|
21670
|
-
};
|
|
21671
|
-
}
|
|
21672
|
-
}
|
|
21673
|
-
next2.currentStepIdx = targetIdx;
|
|
21674
|
-
next2.status = "running";
|
|
21901
|
+
sendBack(next2, { idx, targetIdx, reason, at: now, pipeline });
|
|
21902
|
+
delete next2.sendBacks;
|
|
21675
21903
|
return next2;
|
|
21676
21904
|
}
|
|
21677
21905
|
const next = clone(state);
|
|
21906
|
+
delete next.sendBacks;
|
|
21678
21907
|
next.steps[idx] = {
|
|
21679
21908
|
...step,
|
|
21680
21909
|
status: "rejected",
|
|
@@ -21707,6 +21936,7 @@ var require_PipelineRunner = __commonJS({
|
|
|
21707
21936
|
}
|
|
21708
21937
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21709
21938
|
const next = clone(state);
|
|
21939
|
+
delete next.sendBacks;
|
|
21710
21940
|
const newRev = step.revision + 1;
|
|
21711
21941
|
const carriedFeedback = feedback ?? step.feedback;
|
|
21712
21942
|
next.steps[idx] = {
|
|
@@ -21769,6 +21999,7 @@ var require_PipelineRunner = __commonJS({
|
|
|
21769
21999
|
}
|
|
21770
22000
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21771
22001
|
const next = clone(state);
|
|
22002
|
+
delete next.sendBacks;
|
|
21772
22003
|
const normalized = pipeline.steps.map(WorkspaceSchema_1.normalizeStep);
|
|
21773
22004
|
const usesDag = normalized.some((s) => s.depends_on.length > 0);
|
|
21774
22005
|
const upper = state.status === "completed" ? pipeline.steps.length - 1 : state.currentStepIdx;
|
|
@@ -21912,6 +22143,7 @@ var require_PipelineRunner = __commonJS({
|
|
|
21912
22143
|
const step = state.steps[idx];
|
|
21913
22144
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21914
22145
|
const next = clone(state);
|
|
22146
|
+
delete next.sendBacks;
|
|
21915
22147
|
const newRev = step.revision + 1;
|
|
21916
22148
|
const carriedFeedback = feedback ?? step.feedback;
|
|
21917
22149
|
next.steps[idx] = {
|
|
@@ -22058,6 +22290,70 @@ var require_PipelineRunner = __commonJS({
|
|
|
22058
22290
|
next.status = "completed";
|
|
22059
22291
|
}
|
|
22060
22292
|
}
|
|
22293
|
+
function sendBack(next, args) {
|
|
22294
|
+
const { idx, targetIdx, reason, at: now, pipeline, source } = args;
|
|
22295
|
+
const before = clone(next);
|
|
22296
|
+
const step = next.steps[idx];
|
|
22297
|
+
const blame = `Rejected at step ${idx + 1} (${step.agent})${reason ? `: ${reason}` : ""}`;
|
|
22298
|
+
const rejectedHistory = pushHistory(step.history, {
|
|
22299
|
+
kind: "reject",
|
|
22300
|
+
at: now,
|
|
22301
|
+
revision: step.revision,
|
|
22302
|
+
reason,
|
|
22303
|
+
sentBackToIdx: targetIdx,
|
|
22304
|
+
...source ? { source } : {},
|
|
22305
|
+
...step.skill ? { skill: step.skill } : {},
|
|
22306
|
+
...step.chosenModel ? { model: step.chosenModel } : {}
|
|
22307
|
+
});
|
|
22308
|
+
const usesDag = pipeline ? pipeline.steps.map(WorkspaceSchema_1.normalizeStep).some((s) => s.depends_on.length > 0) : false;
|
|
22309
|
+
const resetIndices = usesDag && pipeline ? collectDagResetSet(pipeline, before, targetIdx, idx) : sequentialRange(targetIdx, idx);
|
|
22310
|
+
for (const i of resetIndices) {
|
|
22311
|
+
const s = next.steps[i];
|
|
22312
|
+
if (i === targetIdx) {
|
|
22313
|
+
const newRev = s.revision + 1;
|
|
22314
|
+
next.steps[i] = {
|
|
22315
|
+
...s,
|
|
22316
|
+
status: "awaiting_work",
|
|
22317
|
+
revision: newRev,
|
|
22318
|
+
feedback: blame,
|
|
22319
|
+
rejectReason: void 0,
|
|
22320
|
+
autoReviewVerdict: void 0,
|
|
22321
|
+
artifactsProduced: [],
|
|
22322
|
+
finishedAt: void 0,
|
|
22323
|
+
startedAt: now,
|
|
22324
|
+
history: pushHistory(s.history, {
|
|
22325
|
+
kind: "rerun",
|
|
22326
|
+
at: now,
|
|
22327
|
+
revision: newRev,
|
|
22328
|
+
feedback: blame
|
|
22329
|
+
})
|
|
22330
|
+
};
|
|
22331
|
+
} else if (i === idx) {
|
|
22332
|
+
next.steps[i] = {
|
|
22333
|
+
...s,
|
|
22334
|
+
status: "pending",
|
|
22335
|
+
rejectReason: void 0,
|
|
22336
|
+
autoReviewVerdict: void 0,
|
|
22337
|
+
artifactsProduced: [],
|
|
22338
|
+
startedAt: void 0,
|
|
22339
|
+
finishedAt: void 0,
|
|
22340
|
+
history: rejectedHistory
|
|
22341
|
+
};
|
|
22342
|
+
} else {
|
|
22343
|
+
next.steps[i] = {
|
|
22344
|
+
...s,
|
|
22345
|
+
status: "pending",
|
|
22346
|
+
rejectReason: void 0,
|
|
22347
|
+
autoReviewVerdict: void 0,
|
|
22348
|
+
artifactsProduced: [],
|
|
22349
|
+
startedAt: void 0,
|
|
22350
|
+
finishedAt: void 0
|
|
22351
|
+
};
|
|
22352
|
+
}
|
|
22353
|
+
}
|
|
22354
|
+
next.currentStepIdx = targetIdx;
|
|
22355
|
+
next.status = "running";
|
|
22356
|
+
}
|
|
22061
22357
|
function clone(value) {
|
|
22062
22358
|
return JSON.parse(JSON.stringify(value));
|
|
22063
22359
|
}
|
|
@@ -25470,7 +25766,7 @@ var require_PlanGenerator = __commonJS({
|
|
|
25470
25766
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
25471
25767
|
exports2.generatePlan = generatePlan;
|
|
25472
25768
|
exports2.renderPlanMarkdown = renderPlanMarkdown;
|
|
25473
|
-
function
|
|
25769
|
+
function normalizeStep5(step) {
|
|
25474
25770
|
if (typeof step === "string") {
|
|
25475
25771
|
return { name: step };
|
|
25476
25772
|
}
|
|
@@ -25586,7 +25882,7 @@ var require_PlanGenerator = __commonJS({
|
|
|
25586
25882
|
}
|
|
25587
25883
|
function generatePlan(epicId, context, pipeline, workspace) {
|
|
25588
25884
|
const complexity = inferScopeComplexity(context.scope);
|
|
25589
|
-
const steps = (pipeline.steps || []).map(
|
|
25885
|
+
const steps = (pipeline.steps || []).map(normalizeStep5);
|
|
25590
25886
|
const agentCountPerPhase = allocateAgentCount(complexity, steps.length);
|
|
25591
25887
|
const phaseAllocations = steps.map((step) => {
|
|
25592
25888
|
const agentId = step.agent || "unknown";
|
|
@@ -26708,6 +27004,11 @@ var require_EpicStepEdit = __commonJS({
|
|
|
26708
27004
|
}
|
|
26709
27005
|
function commitEpicStepEdit2(args) {
|
|
26710
27006
|
const { workspaceRoot, doc, plan } = args;
|
|
27007
|
+
const sendBack = (0, WorkspaceSchema_1.sendBackIssues)(plan.pipeline.steps);
|
|
27008
|
+
if (sendBack.length > 0) {
|
|
27009
|
+
throw new EpicStepEditError2(`This edit would leave \`on_reject\` pointing at a step it cannot send work to:
|
|
27010
|
+
` + sendBack.map((i) => ` - ${i.message}`).join("\n"));
|
|
27011
|
+
}
|
|
26711
27012
|
args.writeWorkspace(plan.pipeline);
|
|
26712
27013
|
try {
|
|
26713
27014
|
RunStateStore_1.RunStateStore.save(workspaceRoot, plan.runState);
|
|
@@ -26754,6 +27055,7 @@ var require_EpicStepEdit = __commonJS({
|
|
|
26754
27055
|
delete next.auto_review;
|
|
26755
27056
|
delete next.auto_review_runner;
|
|
26756
27057
|
delete next.auto_review_timeout_ms;
|
|
27058
|
+
delete next.on_reject;
|
|
26757
27059
|
}
|
|
26758
27060
|
const nextRaw = [...raw];
|
|
26759
27061
|
nextRaw[idx] = next;
|
|
@@ -28662,6 +28964,69 @@ var require_resolveCommand = __commonJS({
|
|
|
28662
28964
|
}
|
|
28663
28965
|
});
|
|
28664
28966
|
|
|
28967
|
+
// ../core/dist/runner/processTree.js
|
|
28968
|
+
var require_processTree = __commonJS({
|
|
28969
|
+
"../core/dist/runner/processTree.js"(exports2) {
|
|
28970
|
+
"use strict";
|
|
28971
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
28972
|
+
exports2.STOP_GRACE_MS = void 0;
|
|
28973
|
+
exports2.processGroupSpawnOptions = processGroupSpawnOptions;
|
|
28974
|
+
exports2.stopOnAbort = stopOnAbort;
|
|
28975
|
+
exports2.stopProcessTree = stopProcessTree;
|
|
28976
|
+
var child_process_1 = require("child_process");
|
|
28977
|
+
exports2.STOP_GRACE_MS = 1e4;
|
|
28978
|
+
function processGroupSpawnOptions() {
|
|
28979
|
+
return process.platform === "win32" ? {} : { detached: true };
|
|
28980
|
+
}
|
|
28981
|
+
function stopOnAbort(proc, signal, graceMs = exports2.STOP_GRACE_MS) {
|
|
28982
|
+
if (!signal) {
|
|
28983
|
+
return () => {
|
|
28984
|
+
};
|
|
28985
|
+
}
|
|
28986
|
+
let timer;
|
|
28987
|
+
const onAbort = () => {
|
|
28988
|
+
stopProcessTree(proc, "SIGTERM");
|
|
28989
|
+
timer = setTimeout(() => stopProcessTree(proc, "SIGKILL"), graceMs);
|
|
28990
|
+
timer.unref?.();
|
|
28991
|
+
};
|
|
28992
|
+
if (signal.aborted) {
|
|
28993
|
+
onAbort();
|
|
28994
|
+
} else {
|
|
28995
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
28996
|
+
}
|
|
28997
|
+
return () => {
|
|
28998
|
+
signal.removeEventListener("abort", onAbort);
|
|
28999
|
+
if (timer) {
|
|
29000
|
+
clearTimeout(timer);
|
|
29001
|
+
stopProcessTree(proc, "SIGKILL");
|
|
29002
|
+
}
|
|
29003
|
+
};
|
|
29004
|
+
}
|
|
29005
|
+
function stopProcessTree(proc, sig) {
|
|
29006
|
+
const pid = proc.pid;
|
|
29007
|
+
if (!pid) {
|
|
29008
|
+
return;
|
|
29009
|
+
}
|
|
29010
|
+
if (process.platform === "win32") {
|
|
29011
|
+
try {
|
|
29012
|
+
(0, child_process_1.spawn)("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true }).on("error", () => {
|
|
29013
|
+
});
|
|
29014
|
+
} catch {
|
|
29015
|
+
}
|
|
29016
|
+
return;
|
|
29017
|
+
}
|
|
29018
|
+
try {
|
|
29019
|
+
process.kill(-pid, sig);
|
|
29020
|
+
} catch {
|
|
29021
|
+
try {
|
|
29022
|
+
proc.kill(sig);
|
|
29023
|
+
} catch {
|
|
29024
|
+
}
|
|
29025
|
+
}
|
|
29026
|
+
}
|
|
29027
|
+
}
|
|
29028
|
+
});
|
|
29029
|
+
|
|
28665
29030
|
// ../core/dist/runner/DefaultRunner.js
|
|
28666
29031
|
var require_DefaultRunner = __commonJS({
|
|
28667
29032
|
"../core/dist/runner/DefaultRunner.js"(exports2) {
|
|
@@ -28674,6 +29039,7 @@ var require_DefaultRunner = __commonJS({
|
|
|
28674
29039
|
var mcp_1 = require_mcp();
|
|
28675
29040
|
var ndjson_1 = require_ndjson();
|
|
28676
29041
|
var resolveCommand_1 = require_resolveCommand();
|
|
29042
|
+
var processTree_1 = require_processTree();
|
|
28677
29043
|
var DefaultRunner3 = class {
|
|
28678
29044
|
opts;
|
|
28679
29045
|
/**
|
|
@@ -28712,6 +29078,10 @@ var require_DefaultRunner = __commonJS({
|
|
|
28712
29078
|
ctx.skill,
|
|
28713
29079
|
...model ? ["--model", model] : [],
|
|
28714
29080
|
...this.opts.extraArgs ?? [],
|
|
29081
|
+
...ctx.extraArgs ?? [],
|
|
29082
|
+
// `--allowedTools` and friends take any number of values, and would take
|
|
29083
|
+
// the prompt as one more; `--` ends the options.
|
|
29084
|
+
"--",
|
|
28715
29085
|
userMessage
|
|
28716
29086
|
];
|
|
28717
29087
|
const cmd = (0, resolveCommand_1.resolveCommand)(bin);
|
|
@@ -28721,8 +29091,10 @@ var require_DefaultRunner = __commonJS({
|
|
|
28721
29091
|
// inside a Claude Code session — a fresh `claude` rejects it as invalid.
|
|
28722
29092
|
// ctx.env (workspace-configured) is layered last so explicit keys win.
|
|
28723
29093
|
env: (0, claudeEnv_1.buildClaudeSpawnEnv)(ctx.env),
|
|
28724
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
29094
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
29095
|
+
...(0, processTree_1.processGroupSpawnOptions)()
|
|
28725
29096
|
});
|
|
29097
|
+
const detach = (0, processTree_1.stopOnAbort)(proc, ctx.signal);
|
|
28726
29098
|
let finalText = "";
|
|
28727
29099
|
let costUsd;
|
|
28728
29100
|
const handleEvent = (evt) => {
|
|
@@ -28748,11 +29120,13 @@ var require_DefaultRunner = __commonJS({
|
|
|
28748
29120
|
});
|
|
28749
29121
|
return new Promise((resolve5) => {
|
|
28750
29122
|
proc.on("error", (err) => {
|
|
29123
|
+
detach();
|
|
28751
29124
|
ctx.onError(`Failed to spawn ${bin}: ${err.message}
|
|
28752
29125
|
`);
|
|
28753
29126
|
resolve5({ success: false, output: finalText, costUsd });
|
|
28754
29127
|
});
|
|
28755
29128
|
proc.on("close", (code) => {
|
|
29129
|
+
detach();
|
|
28756
29130
|
sink.flush();
|
|
28757
29131
|
resolve5({ success: code === 0, output: finalText, costUsd });
|
|
28758
29132
|
});
|
|
@@ -28823,6 +29197,7 @@ var require_CodexRunner = __commonJS({
|
|
|
28823
29197
|
var ndjson_1 = require_ndjson();
|
|
28824
29198
|
var models_1 = require_models();
|
|
28825
29199
|
var resolveCommand_1 = require_resolveCommand();
|
|
29200
|
+
var processTree_1 = require_processTree();
|
|
28826
29201
|
var CodexRunner2 = class {
|
|
28827
29202
|
opts;
|
|
28828
29203
|
/**
|
|
@@ -28859,14 +29234,17 @@ var require_CodexRunner = __commonJS({
|
|
|
28859
29234
|
this.opts.sandbox ?? "workspace-write",
|
|
28860
29235
|
...model ? ["--model", model] : [],
|
|
28861
29236
|
...this.opts.extraArgs ?? [],
|
|
29237
|
+
...ctx.extraArgs ?? [],
|
|
28862
29238
|
buildPrompt(ctx)
|
|
28863
29239
|
];
|
|
28864
29240
|
const cmd = (0, resolveCommand_1.resolveCommand)(bin);
|
|
28865
29241
|
const proc = (0, child_process_1.spawn)(cmd.command, [...cmd.args, ...args], {
|
|
28866
29242
|
cwd: ctx.workspaceRoot,
|
|
28867
29243
|
env: { ...process.env, ...ctx.env },
|
|
28868
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
29244
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
29245
|
+
...(0, processTree_1.processGroupSpawnOptions)()
|
|
28869
29246
|
});
|
|
29247
|
+
const detach = (0, processTree_1.stopOnAbort)(proc, ctx.signal);
|
|
28870
29248
|
let streamed = "";
|
|
28871
29249
|
let lastMessage = "";
|
|
28872
29250
|
let sawDelta = false;
|
|
@@ -28918,11 +29296,13 @@ var require_CodexRunner = __commonJS({
|
|
|
28918
29296
|
proc.stderr.on("data", (d) => ctx.onError(d.toString("utf8")));
|
|
28919
29297
|
return new Promise((resolve5) => {
|
|
28920
29298
|
proc.on("error", (err) => {
|
|
29299
|
+
detach();
|
|
28921
29300
|
ctx.onError(`Failed to spawn ${bin}: ${err.message}
|
|
28922
29301
|
`);
|
|
28923
29302
|
resolve5({ success: false, output: "", usage });
|
|
28924
29303
|
});
|
|
28925
29304
|
proc.on("close", (code) => {
|
|
29305
|
+
detach();
|
|
28926
29306
|
sink.flush();
|
|
28927
29307
|
resolve5({
|
|
28928
29308
|
success: code === 0,
|
|
@@ -28995,6 +29375,7 @@ var require_CopilotRunner = __commonJS({
|
|
|
28995
29375
|
var ndjson_1 = require_ndjson();
|
|
28996
29376
|
var models_1 = require_models();
|
|
28997
29377
|
var resolveCommand_1 = require_resolveCommand();
|
|
29378
|
+
var processTree_1 = require_processTree();
|
|
28998
29379
|
var GRAPH_SERVERS2 = ["ast-graph", "codegraph"];
|
|
28999
29380
|
var CopilotRunner2 = class {
|
|
29000
29381
|
opts;
|
|
@@ -29032,14 +29413,17 @@ var require_CopilotRunner = __commonJS({
|
|
|
29032
29413
|
...this.opts.keepBuiltinMcps ? [] : ["--disable-builtin-mcps"],
|
|
29033
29414
|
...graph ? ["--additional-mcp-config", copilotMcpConfig(graph)] : [],
|
|
29034
29415
|
...model ? ["--model", model] : [],
|
|
29035
|
-
...this.opts.extraArgs ?? []
|
|
29416
|
+
...this.opts.extraArgs ?? [],
|
|
29417
|
+
...ctx.extraArgs ?? []
|
|
29036
29418
|
];
|
|
29037
29419
|
const cmd = (0, resolveCommand_1.resolveCommand)(bin);
|
|
29038
29420
|
const proc = (0, child_process_1.spawn)(cmd.command, [...cmd.args, ...args], {
|
|
29039
29421
|
cwd: ctx.workspaceRoot,
|
|
29040
29422
|
env: { ...process.env, ...ctx.env },
|
|
29041
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
29423
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
29424
|
+
...(0, processTree_1.processGroupSpawnOptions)()
|
|
29042
29425
|
});
|
|
29426
|
+
const detach = (0, processTree_1.stopOnAbort)(proc, ctx.signal);
|
|
29043
29427
|
let streamed = "";
|
|
29044
29428
|
let lastMessage = "";
|
|
29045
29429
|
const deltaSeen = /* @__PURE__ */ new Set();
|
|
@@ -29101,11 +29485,13 @@ var require_CopilotRunner = __commonJS({
|
|
|
29101
29485
|
proc.stdin.end((0, CodexRunner_1.buildPrompt)(ctx));
|
|
29102
29486
|
return new Promise((resolve5) => {
|
|
29103
29487
|
proc.on("error", (err) => {
|
|
29488
|
+
detach();
|
|
29104
29489
|
ctx.onError(`Failed to spawn ${bin}: ${err.message}
|
|
29105
29490
|
`);
|
|
29106
29491
|
resolve5({ success: false, output: "" });
|
|
29107
29492
|
});
|
|
29108
29493
|
proc.on("close", (code) => {
|
|
29494
|
+
detach();
|
|
29109
29495
|
sink.flush();
|
|
29110
29496
|
resolve5({
|
|
29111
29497
|
success: code === 0,
|
|
@@ -30355,7 +30741,10 @@ var require_promptComposer = __commonJS({
|
|
|
30355
30741
|
const inlineInstructions = !!instructions && !harness.projectInstructions;
|
|
30356
30742
|
const language = artifactLanguage?.trim() || null;
|
|
30357
30743
|
const depth = (0, strictMode_1.strictModeSection)(input.strictMode === false ? false : true);
|
|
30358
|
-
|
|
30744
|
+
const history = input.runHistory ? `## Prior revisions
|
|
30745
|
+
|
|
30746
|
+
Earlier rejections and feedback for this step: \`${input.runHistory.file}\` \u2192 \`steps[${input.runHistory.stepIdx}].history\`. Do not bring back what they rejected.` : null;
|
|
30747
|
+
if (!inlinePersona && !inlineInstructions && !language && !depth && !history) {
|
|
30359
30748
|
return {
|
|
30360
30749
|
text: skills,
|
|
30361
30750
|
included: { persona: false, instructions: false, language: false, depth: false }
|
|
@@ -30380,6 +30769,9 @@ var require_promptComposer = __commonJS({
|
|
|
30380
30769
|
if (depth) {
|
|
30381
30770
|
parts.push(depth);
|
|
30382
30771
|
}
|
|
30772
|
+
if (history) {
|
|
30773
|
+
parts.push(history);
|
|
30774
|
+
}
|
|
30383
30775
|
const skillText = inlinePersona ? stripPersonaDirectives(skills) : skills;
|
|
30384
30776
|
parts.push(["## Phase Behavior", "", skillText.trim()].join("\n"));
|
|
30385
30777
|
return {
|
|
@@ -30731,6 +31123,235 @@ var require_commandBodyFreshness = __commonJS({
|
|
|
30731
31123
|
}
|
|
30732
31124
|
});
|
|
30733
31125
|
|
|
31126
|
+
// ../core/dist/runs/autopilotPreflight.js
|
|
31127
|
+
var require_autopilotPreflight = __commonJS({
|
|
31128
|
+
"../core/dist/runs/autopilotPreflight.js"(exports2) {
|
|
31129
|
+
"use strict";
|
|
31130
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
31131
|
+
if (k2 === void 0) k2 = k;
|
|
31132
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
31133
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
31134
|
+
desc = { enumerable: true, get: function() {
|
|
31135
|
+
return m[k];
|
|
31136
|
+
} };
|
|
31137
|
+
}
|
|
31138
|
+
Object.defineProperty(o, k2, desc);
|
|
31139
|
+
} : function(o, m, k, k2) {
|
|
31140
|
+
if (k2 === void 0) k2 = k;
|
|
31141
|
+
o[k2] = m[k];
|
|
31142
|
+
});
|
|
31143
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
|
|
31144
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31145
|
+
} : function(o, v) {
|
|
31146
|
+
o["default"] = v;
|
|
31147
|
+
});
|
|
31148
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
|
|
31149
|
+
var ownKeys = function(o) {
|
|
31150
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
31151
|
+
var ar = [];
|
|
31152
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
31153
|
+
return ar;
|
|
31154
|
+
};
|
|
31155
|
+
return ownKeys(o);
|
|
31156
|
+
};
|
|
31157
|
+
return function(mod) {
|
|
31158
|
+
if (mod && mod.__esModule) return mod;
|
|
31159
|
+
var result = {};
|
|
31160
|
+
if (mod != null) {
|
|
31161
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31162
|
+
}
|
|
31163
|
+
__setModuleDefault(result, mod);
|
|
31164
|
+
return result;
|
|
31165
|
+
};
|
|
31166
|
+
}();
|
|
31167
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
31168
|
+
exports2.AUTOPILOT_ENV = exports2.APPROVAL_GATE_SCRIPT = void 0;
|
|
31169
|
+
exports2.findApprovalGate = findApprovalGate2;
|
|
31170
|
+
exports2.autopilotPreflight = autopilotPreflight;
|
|
31171
|
+
exports2.hasEmptyCiChecks = hasEmptyCiChecks2;
|
|
31172
|
+
exports2.emptyCiChecksMessage = emptyCiChecksMessage2;
|
|
31173
|
+
var child_process_1 = require("child_process");
|
|
31174
|
+
var fs14 = __importStar(require("fs"));
|
|
31175
|
+
var os3 = __importStar(require("os"));
|
|
31176
|
+
var path17 = __importStar(require("path"));
|
|
31177
|
+
var claudeHome_1 = require_claudeHome();
|
|
31178
|
+
var EpicScaffold_1 = require_EpicScaffold();
|
|
31179
|
+
var WorkspaceSchema_1 = require_WorkspaceSchema();
|
|
31180
|
+
exports2.APPROVAL_GATE_SCRIPT = "aidlc-approval-gate";
|
|
31181
|
+
exports2.AUTOPILOT_ENV = "AIDLC_AUTOPILOT";
|
|
31182
|
+
var PROTECTED_BRANCHES = ["main", "master"];
|
|
31183
|
+
function findApprovalGate2(root, opts = {}) {
|
|
31184
|
+
const files = [
|
|
31185
|
+
path17.join(root, ".claude", "settings.json"),
|
|
31186
|
+
path17.join(root, ".claude", "settings.local.json"),
|
|
31187
|
+
path17.join(opts.userConfigDir ?? (0, claudeHome_1.claudeConfigDir)(), "settings.json")
|
|
31188
|
+
];
|
|
31189
|
+
let brokenReason = null;
|
|
31190
|
+
for (const file of files) {
|
|
31191
|
+
let settings = null;
|
|
31192
|
+
try {
|
|
31193
|
+
settings = JSON.parse(fs14.readFileSync(file, "utf8"));
|
|
31194
|
+
} catch {
|
|
31195
|
+
continue;
|
|
31196
|
+
}
|
|
31197
|
+
const groups = settings?.hooks?.PreToolUse;
|
|
31198
|
+
if (!Array.isArray(groups)) {
|
|
31199
|
+
continue;
|
|
31200
|
+
}
|
|
31201
|
+
for (const g of groups) {
|
|
31202
|
+
if (!Array.isArray(g?.hooks) || !matcherCoversBash(g.matcher)) {
|
|
31203
|
+
continue;
|
|
31204
|
+
}
|
|
31205
|
+
for (const h of g.hooks) {
|
|
31206
|
+
if (typeof h?.command !== "string" || !h.command.includes(exports2.APPROVAL_GATE_SCRIPT)) {
|
|
31207
|
+
continue;
|
|
31208
|
+
}
|
|
31209
|
+
const script = hookScriptPath(h.command, root);
|
|
31210
|
+
if (!script) {
|
|
31211
|
+
continue;
|
|
31212
|
+
}
|
|
31213
|
+
if (!fs14.existsSync(script)) {
|
|
31214
|
+
brokenReason = `${rel(root, file)} runs ${script}, which does not exist.`;
|
|
31215
|
+
continue;
|
|
31216
|
+
}
|
|
31217
|
+
if (runsScriptDirectly(h.command) && process.platform !== "win32" && !isExecutable(script)) {
|
|
31218
|
+
brokenReason = `${rel(root, script)} is registered in ${rel(root, file)} but is not executable (chmod +x it).`;
|
|
31219
|
+
continue;
|
|
31220
|
+
}
|
|
31221
|
+
return { found: true, settingsFile: file, script };
|
|
31222
|
+
}
|
|
31223
|
+
}
|
|
31224
|
+
}
|
|
31225
|
+
return {
|
|
31226
|
+
found: false,
|
|
31227
|
+
reason: brokenReason ?? 'no PreToolUse hook running .claude/hooks/aidlc-approval-gate.py on Bash in .claude/settings.json, .claude/settings.local.json or your user settings \u2014 see ONBOARDING.md, "Turn on the approval gate".'
|
|
31228
|
+
};
|
|
31229
|
+
}
|
|
31230
|
+
function autopilotPreflight(args) {
|
|
31231
|
+
const { root, state, config } = args;
|
|
31232
|
+
const problems = [];
|
|
31233
|
+
const git = (gitArgs) => {
|
|
31234
|
+
try {
|
|
31235
|
+
return (0, child_process_1.execFileSync)("git", gitArgs, {
|
|
31236
|
+
cwd: root,
|
|
31237
|
+
encoding: "utf8",
|
|
31238
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
31239
|
+
maxBuffer: 64 * 1024 * 1024
|
|
31240
|
+
});
|
|
31241
|
+
} catch {
|
|
31242
|
+
return null;
|
|
31243
|
+
}
|
|
31244
|
+
};
|
|
31245
|
+
if (git(["rev-parse", "--is-inside-work-tree"])?.trim() !== "true") {
|
|
31246
|
+
problems.push("This is not a git checkout. Autopilot works on a branch of its own, so it needs git.");
|
|
31247
|
+
} else {
|
|
31248
|
+
const branch = git(["symbolic-ref", "--short", "-q", "HEAD"])?.trim();
|
|
31249
|
+
const remoteDefault = git(["symbolic-ref", "--short", "-q", "refs/remotes/origin/HEAD"])?.trim().replace(/^origin\//, "");
|
|
31250
|
+
const protectedBranches = /* @__PURE__ */ new Set([...PROTECTED_BRANCHES, ...remoteDefault ? [remoteDefault] : []]);
|
|
31251
|
+
if (!branch) {
|
|
31252
|
+
problems.push("HEAD is detached. Check out a branch for this epic (git switch -c <branch>) so the agent's commits land on it.");
|
|
31253
|
+
} else if (protectedBranches.has(branch)) {
|
|
31254
|
+
problems.push(`You are on "${branch}". Autopilot does not commit to it \u2014 switch to a branch for this epic (git switch -c <branch>).`);
|
|
31255
|
+
}
|
|
31256
|
+
const skip = [
|
|
31257
|
+
toPosix(path17.relative(root, path17.join((0, EpicScaffold_1.epicsRoot)(root, config), state.runId))),
|
|
31258
|
+
".aidlc"
|
|
31259
|
+
];
|
|
31260
|
+
const dirty = dirtyPaths(git(["status", "--porcelain=v1", "-z", "--untracked-files=all"]) ?? "").filter((p) => !skip.some((s) => p === s || p.startsWith(`${s}/`)));
|
|
31261
|
+
if (dirty.length > 0) {
|
|
31262
|
+
const shown = dirty.slice(0, 5).join(", ") + (dirty.length > 5 ? `, and ${dirty.length - 5} more` : "");
|
|
31263
|
+
problems.push(`The working tree has uncommitted changes (${shown}). Commit or stash them first: the agent would build on them, and its own changes would be mixed in with them.`);
|
|
31264
|
+
}
|
|
31265
|
+
}
|
|
31266
|
+
const claudeSteps = new Set(state.steps.filter((s) => s.status !== "approved").map((s) => config.agents.find((a) => a.id === s.agent)).filter((a) => a?.runner === "default").map((a) => a.id));
|
|
31267
|
+
if (claudeSteps.size > 0) {
|
|
31268
|
+
const gate = findApprovalGate2(root, { userConfigDir: args.userConfigDir });
|
|
31269
|
+
if (!gate.found) {
|
|
31270
|
+
problems.push(`The approval gate is not on: ${gate.reason}`);
|
|
31271
|
+
}
|
|
31272
|
+
}
|
|
31273
|
+
args.pipeline.steps.forEach((s, i) => {
|
|
31274
|
+
if (state.steps[i]?.status === "approved") {
|
|
31275
|
+
return;
|
|
31276
|
+
}
|
|
31277
|
+
const norm = (0, WorkspaceSchema_1.normalizeStep)(s);
|
|
31278
|
+
const runner = norm.auto_review ? norm.auto_review_runner : void 0;
|
|
31279
|
+
if (runner && hasEmptyCiChecks2(root, runner)) {
|
|
31280
|
+
problems.push(emptyCiChecksMessage2(runner, norm.name ?? norm.agent));
|
|
31281
|
+
}
|
|
31282
|
+
});
|
|
31283
|
+
return problems;
|
|
31284
|
+
}
|
|
31285
|
+
var EMPTY_CHECKS = /\bCHECKS\s*=\s*\[\s*\]/;
|
|
31286
|
+
function hasEmptyCiChecks2(root, runner) {
|
|
31287
|
+
let text;
|
|
31288
|
+
try {
|
|
31289
|
+
text = fs14.readFileSync(path17.isAbsolute(runner) ? runner : path17.join(root, runner), "utf8");
|
|
31290
|
+
} catch {
|
|
31291
|
+
return false;
|
|
31292
|
+
}
|
|
31293
|
+
const code = text.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
31294
|
+
return EMPTY_CHECKS.test(code);
|
|
31295
|
+
}
|
|
31296
|
+
function emptyCiChecksMessage2(runner, step) {
|
|
31297
|
+
return `${runner} has no commands in CHECKS, so it passes whatever "${step}" builds. Add your lint, typecheck and test commands to it before leaving a run alone.`;
|
|
31298
|
+
}
|
|
31299
|
+
function dirtyPaths(out2) {
|
|
31300
|
+
const parts = out2.split("\0");
|
|
31301
|
+
const paths = [];
|
|
31302
|
+
for (let i = 0; i < parts.length; i++) {
|
|
31303
|
+
const entry = parts[i];
|
|
31304
|
+
if (entry.length < 4) {
|
|
31305
|
+
continue;
|
|
31306
|
+
}
|
|
31307
|
+
paths.push(entry.slice(3));
|
|
31308
|
+
if (entry[0] === "R" || entry[0] === "C") {
|
|
31309
|
+
i++;
|
|
31310
|
+
}
|
|
31311
|
+
}
|
|
31312
|
+
return paths;
|
|
31313
|
+
}
|
|
31314
|
+
function matcherCoversBash(matcher) {
|
|
31315
|
+
if (!matcher || matcher === "*") {
|
|
31316
|
+
return true;
|
|
31317
|
+
}
|
|
31318
|
+
try {
|
|
31319
|
+
return new RegExp(`^(?:${matcher})$`).test("Bash");
|
|
31320
|
+
} catch {
|
|
31321
|
+
return matcher.split("|").map((m) => m.trim()).includes("Bash");
|
|
31322
|
+
}
|
|
31323
|
+
}
|
|
31324
|
+
function hookScriptPath(command, root) {
|
|
31325
|
+
const expanded = command.replace(/\$\{?CLAUDE_PROJECT_DIR\}?/g, root).replace(/["']/g, "");
|
|
31326
|
+
const token = expanded.split(/\s+/).find((t) => t.includes(exports2.APPROVAL_GATE_SCRIPT));
|
|
31327
|
+
if (!token) {
|
|
31328
|
+
return null;
|
|
31329
|
+
}
|
|
31330
|
+
const p = token.startsWith("~/") ? path17.join(os3.homedir(), token.slice(2)) : token;
|
|
31331
|
+
return path17.resolve(root, p);
|
|
31332
|
+
}
|
|
31333
|
+
function runsScriptDirectly(command) {
|
|
31334
|
+
const first = command.replace(/["']/g, "").trim().split(/\s+/)[0] ?? "";
|
|
31335
|
+
return first.includes(exports2.APPROVAL_GATE_SCRIPT);
|
|
31336
|
+
}
|
|
31337
|
+
function isExecutable(file) {
|
|
31338
|
+
try {
|
|
31339
|
+
fs14.accessSync(file, fs14.constants.X_OK);
|
|
31340
|
+
return true;
|
|
31341
|
+
} catch {
|
|
31342
|
+
return false;
|
|
31343
|
+
}
|
|
31344
|
+
}
|
|
31345
|
+
function rel(root, p) {
|
|
31346
|
+
const r = path17.relative(root, p);
|
|
31347
|
+
return r.startsWith("..") ? p : toPosix(r);
|
|
31348
|
+
}
|
|
31349
|
+
function toPosix(p) {
|
|
31350
|
+
return p.split(path17.sep).join("/");
|
|
31351
|
+
}
|
|
31352
|
+
}
|
|
31353
|
+
});
|
|
31354
|
+
|
|
30734
31355
|
// ../core/dist/runs/GitRunStateStore.js
|
|
30735
31356
|
var require_GitRunStateStore = __commonJS({
|
|
30736
31357
|
"../core/dist/runs/GitRunStateStore.js"(exports2) {
|
|
@@ -31355,20 +31976,323 @@ Expected a JS/TS module at "${scriptPath}" with a default-exported function retu
|
|
|
31355
31976
|
at,
|
|
31356
31977
|
runner
|
|
31357
31978
|
};
|
|
31358
|
-
} finally {
|
|
31359
|
-
if (timer) {
|
|
31360
|
-
clearTimeout(timer);
|
|
31979
|
+
} finally {
|
|
31980
|
+
if (timer) {
|
|
31981
|
+
clearTimeout(timer);
|
|
31982
|
+
}
|
|
31983
|
+
}
|
|
31984
|
+
if (!raw || raw.decision !== "pass" && raw.decision !== "reject" || typeof raw.reason !== "string") {
|
|
31985
|
+
return {
|
|
31986
|
+
decision: "reject",
|
|
31987
|
+
reason: `Auto-reviewer returned malformed verdict: ${JSON.stringify(raw)}`,
|
|
31988
|
+
at,
|
|
31989
|
+
runner
|
|
31990
|
+
};
|
|
31991
|
+
}
|
|
31992
|
+
const verdict = { decision: raw.decision, reason: raw.reason, at, runner };
|
|
31993
|
+
const sendBackTo = raw.sendBackTo;
|
|
31994
|
+
if (sendBackTo !== void 0) {
|
|
31995
|
+
verdict.sendBackTo = sendBackTo === null || typeof sendBackTo === "string" || typeof sendBackTo === "number" ? sendBackTo : JSON.stringify(sendBackTo);
|
|
31996
|
+
}
|
|
31997
|
+
return verdict;
|
|
31998
|
+
}
|
|
31999
|
+
}
|
|
32000
|
+
});
|
|
32001
|
+
|
|
32002
|
+
// ../core/dist/runs/revisionFeedback.js
|
|
32003
|
+
var require_revisionFeedback = __commonJS({
|
|
32004
|
+
"../core/dist/runs/revisionFeedback.js"(exports2) {
|
|
32005
|
+
"use strict";
|
|
32006
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
32007
|
+
exports2.revisionFeedback = revisionFeedback;
|
|
32008
|
+
function revisionFeedback(state, stepIdx) {
|
|
32009
|
+
const step = state.steps[stepIdx];
|
|
32010
|
+
if (!step || step.revision <= 1) {
|
|
32011
|
+
return null;
|
|
32012
|
+
}
|
|
32013
|
+
const history = step.history ?? [];
|
|
32014
|
+
const prev = step.revision - 1;
|
|
32015
|
+
const reject = findLast(history, (h) => h.kind === "reject" && h.revision === prev && h.sentBackToIdx === stepIdx);
|
|
32016
|
+
const reason = reject?.kind === "reject" ? reject.reason?.trim() : void 0;
|
|
32017
|
+
const carried = findLast(history, (h) => h.kind === "rerun" && h.revision === prev);
|
|
32018
|
+
const fbRaw = step.feedback?.trim();
|
|
32019
|
+
const fb = fbRaw && !(carried?.kind === "rerun" && carried.feedback?.trim() === fbRaw) ? fbRaw : void 0;
|
|
32020
|
+
const lines = [];
|
|
32021
|
+
if (reason && !fb?.includes(reason)) {
|
|
32022
|
+
lines.push(`Rejected at step ${stepIdx + 1} (${step.agent}): ${reason}`);
|
|
32023
|
+
}
|
|
32024
|
+
if (fb && !reason?.includes(fb)) {
|
|
32025
|
+
lines.push(fb);
|
|
32026
|
+
}
|
|
32027
|
+
if (lines.length === 0) {
|
|
32028
|
+
return null;
|
|
32029
|
+
}
|
|
32030
|
+
return [`Revision ${step.revision}. Address before anything else:`, ...lines.map((l) => `- ${l}`)].join("\n");
|
|
32031
|
+
}
|
|
32032
|
+
function findLast(entries, pred) {
|
|
32033
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
32034
|
+
if (pred(entries[i])) {
|
|
32035
|
+
return entries[i];
|
|
32036
|
+
}
|
|
32037
|
+
}
|
|
32038
|
+
return void 0;
|
|
32039
|
+
}
|
|
32040
|
+
}
|
|
32041
|
+
});
|
|
32042
|
+
|
|
32043
|
+
// ../core/dist/runs/runLock.js
|
|
32044
|
+
var require_runLock = __commonJS({
|
|
32045
|
+
"../core/dist/runs/runLock.js"(exports2) {
|
|
32046
|
+
"use strict";
|
|
32047
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
32048
|
+
if (k2 === void 0) k2 = k;
|
|
32049
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32050
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
32051
|
+
desc = { enumerable: true, get: function() {
|
|
32052
|
+
return m[k];
|
|
32053
|
+
} };
|
|
32054
|
+
}
|
|
32055
|
+
Object.defineProperty(o, k2, desc);
|
|
32056
|
+
} : function(o, m, k, k2) {
|
|
32057
|
+
if (k2 === void 0) k2 = k;
|
|
32058
|
+
o[k2] = m[k];
|
|
32059
|
+
});
|
|
32060
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
|
|
32061
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32062
|
+
} : function(o, v) {
|
|
32063
|
+
o["default"] = v;
|
|
32064
|
+
});
|
|
32065
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
|
|
32066
|
+
var ownKeys = function(o) {
|
|
32067
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
32068
|
+
var ar = [];
|
|
32069
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
32070
|
+
return ar;
|
|
32071
|
+
};
|
|
32072
|
+
return ownKeys(o);
|
|
32073
|
+
};
|
|
32074
|
+
return function(mod) {
|
|
32075
|
+
if (mod && mod.__esModule) return mod;
|
|
32076
|
+
var result = {};
|
|
32077
|
+
if (mod != null) {
|
|
32078
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32079
|
+
}
|
|
32080
|
+
__setModuleDefault(result, mod);
|
|
32081
|
+
return result;
|
|
32082
|
+
};
|
|
32083
|
+
}();
|
|
32084
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
32085
|
+
exports2.runLockFile = runLockFile;
|
|
32086
|
+
exports2.acquireRunLock = acquireRunLock;
|
|
32087
|
+
var fs14 = __importStar(require("fs"));
|
|
32088
|
+
var path17 = __importStar(require("path"));
|
|
32089
|
+
var RunStateStore_1 = require_RunStateStore();
|
|
32090
|
+
function runLockFile(root, runId) {
|
|
32091
|
+
return RunStateStore_1.RunStateStore.file(root, runId).replace(/\.json$/, ".lock");
|
|
32092
|
+
}
|
|
32093
|
+
function acquireRunLock(root, runId) {
|
|
32094
|
+
const file = runLockFile(root, runId);
|
|
32095
|
+
fs14.mkdirSync(path17.dirname(file), { recursive: true });
|
|
32096
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
32097
|
+
try {
|
|
32098
|
+
fs14.writeFileSync(file, JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }), { flag: "wx" });
|
|
32099
|
+
return {
|
|
32100
|
+
release: () => {
|
|
32101
|
+
if (lockPid(file) === process.pid) {
|
|
32102
|
+
fs14.rmSync(file, { force: true });
|
|
32103
|
+
}
|
|
32104
|
+
}
|
|
32105
|
+
};
|
|
32106
|
+
} catch (err) {
|
|
32107
|
+
if (err.code !== "EEXIST") {
|
|
32108
|
+
throw err;
|
|
32109
|
+
}
|
|
32110
|
+
}
|
|
32111
|
+
const pid = lockPid(file);
|
|
32112
|
+
if (pid !== null && isAlive(pid)) {
|
|
32113
|
+
return { heldBy: pid };
|
|
32114
|
+
}
|
|
32115
|
+
fs14.rmSync(file, { force: true });
|
|
32116
|
+
}
|
|
32117
|
+
return { heldBy: lockPid(file) ?? -1 };
|
|
32118
|
+
}
|
|
32119
|
+
function lockPid(file) {
|
|
32120
|
+
try {
|
|
32121
|
+
const pid = JSON.parse(fs14.readFileSync(file, "utf8")).pid;
|
|
32122
|
+
return typeof pid === "number" && Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
32123
|
+
} catch {
|
|
32124
|
+
return null;
|
|
32125
|
+
}
|
|
32126
|
+
}
|
|
32127
|
+
function isAlive(pid) {
|
|
32128
|
+
try {
|
|
32129
|
+
process.kill(pid, 0);
|
|
32130
|
+
return true;
|
|
32131
|
+
} catch (err) {
|
|
32132
|
+
return err.code === "EPERM";
|
|
32133
|
+
}
|
|
32134
|
+
}
|
|
32135
|
+
}
|
|
32136
|
+
});
|
|
32137
|
+
|
|
32138
|
+
// ../core/dist/runs/codeFingerprint.js
|
|
32139
|
+
var require_codeFingerprint = __commonJS({
|
|
32140
|
+
"../core/dist/runs/codeFingerprint.js"(exports2) {
|
|
32141
|
+
"use strict";
|
|
32142
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
32143
|
+
if (k2 === void 0) k2 = k;
|
|
32144
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32145
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
32146
|
+
desc = { enumerable: true, get: function() {
|
|
32147
|
+
return m[k];
|
|
32148
|
+
} };
|
|
32149
|
+
}
|
|
32150
|
+
Object.defineProperty(o, k2, desc);
|
|
32151
|
+
} : function(o, m, k, k2) {
|
|
32152
|
+
if (k2 === void 0) k2 = k;
|
|
32153
|
+
o[k2] = m[k];
|
|
32154
|
+
});
|
|
32155
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
|
|
32156
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32157
|
+
} : function(o, v) {
|
|
32158
|
+
o["default"] = v;
|
|
32159
|
+
});
|
|
32160
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
|
|
32161
|
+
var ownKeys = function(o) {
|
|
32162
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
32163
|
+
var ar = [];
|
|
32164
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
32165
|
+
return ar;
|
|
32166
|
+
};
|
|
32167
|
+
return ownKeys(o);
|
|
32168
|
+
};
|
|
32169
|
+
return function(mod) {
|
|
32170
|
+
if (mod && mod.__esModule) return mod;
|
|
32171
|
+
var result = {};
|
|
32172
|
+
if (mod != null) {
|
|
32173
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32174
|
+
}
|
|
32175
|
+
__setModuleDefault(result, mod);
|
|
32176
|
+
return result;
|
|
32177
|
+
};
|
|
32178
|
+
}();
|
|
32179
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
32180
|
+
exports2.codeFingerprint = codeFingerprint;
|
|
32181
|
+
var child_process_1 = require("child_process");
|
|
32182
|
+
var fs14 = __importStar(require("fs"));
|
|
32183
|
+
var os3 = __importStar(require("os"));
|
|
32184
|
+
var path17 = __importStar(require("path"));
|
|
32185
|
+
function codeFingerprint(root, exclude) {
|
|
32186
|
+
const git = (args, env) => (0, child_process_1.execFileSync)("git", args, {
|
|
32187
|
+
cwd: root,
|
|
32188
|
+
encoding: "utf8",
|
|
32189
|
+
env: env ? { ...process.env, ...env } : process.env,
|
|
32190
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
32191
|
+
maxBuffer: 64 * 1024 * 1024
|
|
32192
|
+
}).trim();
|
|
32193
|
+
let realIndex;
|
|
32194
|
+
try {
|
|
32195
|
+
realIndex = path17.resolve(root, git(["rev-parse", "--git-path", "index"]));
|
|
32196
|
+
} catch {
|
|
32197
|
+
return null;
|
|
32198
|
+
}
|
|
32199
|
+
const dir = fs14.mkdtempSync(path17.join(os3.tmpdir(), "aidlc-fp-"));
|
|
32200
|
+
const index = path17.join(dir, "index");
|
|
32201
|
+
try {
|
|
32202
|
+
if (fs14.existsSync(realIndex)) {
|
|
32203
|
+
fs14.copyFileSync(realIndex, index);
|
|
32204
|
+
}
|
|
32205
|
+
const env = { GIT_INDEX_FILE: index };
|
|
32206
|
+
git(["add", "-A", "--", "."], env);
|
|
32207
|
+
const skip = exclude.filter((p) => p && !p.startsWith(".."));
|
|
32208
|
+
if (skip.length > 0) {
|
|
32209
|
+
git(["rm", "-r", "-q", "--cached", "--ignore-unmatch", "--", ...skip], env);
|
|
32210
|
+
}
|
|
32211
|
+
return git(["write-tree"], env);
|
|
32212
|
+
} catch {
|
|
32213
|
+
return null;
|
|
32214
|
+
} finally {
|
|
32215
|
+
fs14.rmSync(dir, { recursive: true, force: true });
|
|
32216
|
+
}
|
|
32217
|
+
}
|
|
32218
|
+
}
|
|
32219
|
+
});
|
|
32220
|
+
|
|
32221
|
+
// ../core/dist/runs/batchStatus.js
|
|
32222
|
+
var require_batchStatus = __commonJS({
|
|
32223
|
+
"../core/dist/runs/batchStatus.js"(exports2) {
|
|
32224
|
+
"use strict";
|
|
32225
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
32226
|
+
if (k2 === void 0) k2 = k;
|
|
32227
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32228
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
32229
|
+
desc = { enumerable: true, get: function() {
|
|
32230
|
+
return m[k];
|
|
32231
|
+
} };
|
|
32232
|
+
}
|
|
32233
|
+
Object.defineProperty(o, k2, desc);
|
|
32234
|
+
} : function(o, m, k, k2) {
|
|
32235
|
+
if (k2 === void 0) k2 = k;
|
|
32236
|
+
o[k2] = m[k];
|
|
32237
|
+
});
|
|
32238
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
|
|
32239
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32240
|
+
} : function(o, v) {
|
|
32241
|
+
o["default"] = v;
|
|
32242
|
+
});
|
|
32243
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
|
|
32244
|
+
var ownKeys = function(o) {
|
|
32245
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
32246
|
+
var ar = [];
|
|
32247
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
32248
|
+
return ar;
|
|
32249
|
+
};
|
|
32250
|
+
return ownKeys(o);
|
|
32251
|
+
};
|
|
32252
|
+
return function(mod) {
|
|
32253
|
+
if (mod && mod.__esModule) return mod;
|
|
32254
|
+
var result = {};
|
|
32255
|
+
if (mod != null) {
|
|
32256
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32257
|
+
}
|
|
32258
|
+
__setModuleDefault(result, mod);
|
|
32259
|
+
return result;
|
|
32260
|
+
};
|
|
32261
|
+
}();
|
|
32262
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
32263
|
+
exports2.readBatchStatus = readBatchStatus;
|
|
32264
|
+
exports2.readBatchStatusFile = readBatchStatusFile;
|
|
32265
|
+
var fs14 = __importStar(require("fs"));
|
|
32266
|
+
var path17 = __importStar(require("path"));
|
|
32267
|
+
var LINE = /^[\s>#*_-]*status[\s*_]*:[\s*_`]*([a-z]+)[*_`]*(.*)$/i;
|
|
32268
|
+
var TAIL = /^\s*(?:$|[—–-]\s|[(.,;])/;
|
|
32269
|
+
function readBatchStatus(text, file = "the report") {
|
|
32270
|
+
let last = null;
|
|
32271
|
+
for (const line of text.split(/\r?\n/)) {
|
|
32272
|
+
const m = LINE.exec(line);
|
|
32273
|
+
if (m) {
|
|
32274
|
+
last = { word: m[1].toLowerCase(), tail: m[2] };
|
|
31361
32275
|
}
|
|
31362
32276
|
}
|
|
31363
|
-
if (!
|
|
31364
|
-
return {
|
|
31365
|
-
|
|
31366
|
-
|
|
31367
|
-
|
|
31368
|
-
|
|
31369
|
-
|
|
32277
|
+
if (!last) {
|
|
32278
|
+
return { error: `${file} has no \`Status: continue\` or \`Status: done\` line.` };
|
|
32279
|
+
}
|
|
32280
|
+
if ((last.word === "continue" || last.word === "done") && TAIL.test(last.tail)) {
|
|
32281
|
+
return { status: last.word };
|
|
32282
|
+
}
|
|
32283
|
+
return {
|
|
32284
|
+
error: `The last Status line in ${file} reads "${last.word}${last.tail}", not \`Status: continue\` or \`Status: done\`.`
|
|
32285
|
+
};
|
|
32286
|
+
}
|
|
32287
|
+
function readBatchStatusFile(root, rel) {
|
|
32288
|
+
const abs = path17.isAbsolute(rel) ? rel : path17.join(root, rel);
|
|
32289
|
+
let text;
|
|
32290
|
+
try {
|
|
32291
|
+
text = fs14.readFileSync(abs, "utf8");
|
|
32292
|
+
} catch {
|
|
32293
|
+
return { error: `${rel} does not exist, so the batch did not say whether it is done.` };
|
|
31370
32294
|
}
|
|
31371
|
-
return
|
|
32295
|
+
return readBatchStatus(text, rel);
|
|
31372
32296
|
}
|
|
31373
32297
|
}
|
|
31374
32298
|
});
|
|
@@ -31426,9 +32350,16 @@ var require_execEngine = __commonJS({
|
|
|
31426
32350
|
var runProgress_1 = require_runProgress();
|
|
31427
32351
|
var budget_1 = require_budget();
|
|
31428
32352
|
var producesSnapshot_1 = require_producesSnapshot();
|
|
32353
|
+
var revisionFeedback_1 = require_revisionFeedback();
|
|
32354
|
+
var runLock_1 = require_runLock();
|
|
32355
|
+
var codeFingerprint_1 = require_codeFingerprint();
|
|
32356
|
+
var batchStatus_1 = require_batchStatus();
|
|
32357
|
+
var autopilotPreflight_1 = require_autopilotPreflight();
|
|
32358
|
+
var processTree_1 = require_processTree();
|
|
31429
32359
|
var pricing_1 = require_pricing();
|
|
31430
32360
|
var models_1 = require_models();
|
|
31431
32361
|
var WorkspaceSchema_1 = require_WorkspaceSchema();
|
|
32362
|
+
var RunState_1 = require_RunState();
|
|
31432
32363
|
var artifactLanguage_1 = require_artifactLanguage();
|
|
31433
32364
|
var strictMode_1 = require_strictMode();
|
|
31434
32365
|
var inheritedContext_1 = require_inheritedContext();
|
|
@@ -31444,6 +32375,21 @@ var require_execEngine = __commonJS({
|
|
|
31444
32375
|
}
|
|
31445
32376
|
}
|
|
31446
32377
|
async function runExecLoop2(root, runId, opts, hooks = {}) {
|
|
32378
|
+
if (opts.dryRun) {
|
|
32379
|
+
return execLoop2(root, runId, opts, hooks);
|
|
32380
|
+
}
|
|
32381
|
+
const lock = (0, runLock_1.acquireRunLock)(root, runId);
|
|
32382
|
+
if ("heldBy" in lock) {
|
|
32383
|
+
hooks.onRunFailed?.(`Run "${runId}" is already being executed (pid ${lock.heldBy}). Stop that one first, or wait for it to finish.`);
|
|
32384
|
+
return { kind: "error" };
|
|
32385
|
+
}
|
|
32386
|
+
try {
|
|
32387
|
+
return await execLoop2(root, runId, opts, hooks);
|
|
32388
|
+
} finally {
|
|
32389
|
+
lock.release();
|
|
32390
|
+
}
|
|
32391
|
+
}
|
|
32392
|
+
async function execLoop2(root, runId, opts, hooks) {
|
|
31447
32393
|
const untilIdx = opts.untilIdx ?? -1;
|
|
31448
32394
|
const initialState = RunStateStore_1.RunStateStore.load(root, runId);
|
|
31449
32395
|
if (!initialState) {
|
|
@@ -31456,8 +32402,23 @@ var require_execEngine = __commonJS({
|
|
|
31456
32402
|
return { kind: "error" };
|
|
31457
32403
|
}
|
|
31458
32404
|
const budget = initialPipeline.budget;
|
|
32405
|
+
const batchesRun = /* @__PURE__ */ new Map();
|
|
32406
|
+
if (initialPipeline.autopilot && !opts.dryRun) {
|
|
32407
|
+
let problems;
|
|
32408
|
+
try {
|
|
32409
|
+
const ws = WorkspaceLoader_1.WorkspaceLoader.load(root);
|
|
32410
|
+
problems = (0, autopilotPreflight_1.autopilotPreflight)({ root, state: initialState, pipeline: initialPipeline, config: ws.config });
|
|
32411
|
+
} catch (err) {
|
|
32412
|
+
problems = [`Could not check the workspace: ${errMsg(err)}`];
|
|
32413
|
+
}
|
|
32414
|
+
if (problems.length > 0) {
|
|
32415
|
+
hooks.onRunFailed?.(`Pipeline "${initialPipeline.id}" is an autopilot pipeline, and it is not safe to leave this run alone yet:
|
|
32416
|
+
` + problems.map((p) => ` - ${p}`).join("\n"));
|
|
32417
|
+
return { kind: "error" };
|
|
32418
|
+
}
|
|
32419
|
+
}
|
|
31459
32420
|
while (true) {
|
|
31460
|
-
if (opts.shouldCancel?.()) {
|
|
32421
|
+
if (opts.shouldCancel?.() || opts.signal?.aborted) {
|
|
31461
32422
|
hooks.onCancelled?.();
|
|
31462
32423
|
return { kind: "cancelled" };
|
|
31463
32424
|
}
|
|
@@ -31523,47 +32484,56 @@ var require_execEngine = __commonJS({
|
|
|
31523
32484
|
hooks.onRunFailed?.(`Unexpected step status "${step.status}" \u2014 cannot exec.`);
|
|
31524
32485
|
return { kind: "error" };
|
|
31525
32486
|
}
|
|
31526
|
-
const
|
|
31527
|
-
if (
|
|
32487
|
+
const ran = await execStep(root, state, runId, opts, hooks);
|
|
32488
|
+
if (ran === "failed") {
|
|
31528
32489
|
return { kind: "error" };
|
|
31529
32490
|
}
|
|
31530
|
-
if (
|
|
31531
|
-
return { kind: "
|
|
32491
|
+
if (ran === "stalled") {
|
|
32492
|
+
return { kind: "stalled" };
|
|
32493
|
+
}
|
|
32494
|
+
if (ran === "stopped") {
|
|
32495
|
+
return { kind: "cancelled" };
|
|
31532
32496
|
}
|
|
31533
|
-
if (
|
|
32497
|
+
if (ran === "batch") {
|
|
32498
|
+
const overBudget2 = checkRunBudget(root, runId, state.currentStepIdx, budget, hooks);
|
|
32499
|
+
if (overBudget2) {
|
|
32500
|
+
return overBudget2;
|
|
32501
|
+
}
|
|
32502
|
+
const idx = state.currentStepIdx;
|
|
32503
|
+
const cfg = initialPipeline.steps[idx] ? (0, WorkspaceSchema_1.normalizeStep)(initialPipeline.steps[idx]).batches : void 0;
|
|
32504
|
+
const key = `${idx}:${step.revision}`;
|
|
32505
|
+
const n = (batchesRun.get(key) ?? 0) + 1;
|
|
32506
|
+
batchesRun.set(key, n);
|
|
31534
32507
|
const after = RunStateStore_1.RunStateStore.load(root, runId);
|
|
31535
|
-
const
|
|
31536
|
-
|
|
31537
|
-
|
|
31538
|
-
|
|
31539
|
-
|
|
31540
|
-
|
|
31541
|
-
}) : [];
|
|
31542
|
-
const lastStepCost = after?.steps[state.currentStepIdx]?.costUsd;
|
|
31543
|
-
const verdict = (0, budget_1.checkBudget)({ stepCosts, stepAccounting, budget, lastStepCost });
|
|
31544
|
-
if (!verdict.ok) {
|
|
31545
|
-
hooks.onBudget?.({
|
|
31546
|
-
spent: verdict.spent,
|
|
31547
|
-
limit: verdict.limit,
|
|
31548
|
-
ok: false,
|
|
31549
|
-
exceeded: verdict.exceeded,
|
|
31550
|
-
onExceed: budget.on_exceed,
|
|
32508
|
+
const batchNo = after ? batchesOf(after.steps[idx]).length : n;
|
|
32509
|
+
if (cfg && n >= cfg.max) {
|
|
32510
|
+
hooks.onStalled?.({
|
|
32511
|
+
stepIdx: idx,
|
|
32512
|
+
agent: step.agent,
|
|
32513
|
+
revision: step.revision,
|
|
31551
32514
|
runId,
|
|
31552
|
-
|
|
31553
|
-
estimated: verdict.estimated,
|
|
31554
|
-
blindSteps: verdict.blindSteps
|
|
32515
|
+
reason: `"${step.agent}" ran ${n} batch${n === 1 ? "" : "es"} (\`max_batches: ${cfg.max}\`) and still says \`Status: continue\`. Read its progress before letting it carry on: running exec again allows ${cfg.max} more.`
|
|
31555
32516
|
});
|
|
31556
|
-
return
|
|
31557
|
-
}
|
|
31558
|
-
|
|
31559
|
-
|
|
31560
|
-
|
|
31561
|
-
|
|
31562
|
-
|
|
31563
|
-
|
|
31564
|
-
|
|
31565
|
-
|
|
31566
|
-
|
|
32517
|
+
return { kind: "stalled" };
|
|
32518
|
+
}
|
|
32519
|
+
if (cfg?.pause) {
|
|
32520
|
+
hooks.onBatchPause?.({
|
|
32521
|
+
stepIdx: idx,
|
|
32522
|
+
agent: step.agent,
|
|
32523
|
+
batch: batchNo,
|
|
32524
|
+
runId,
|
|
32525
|
+
report: batchReport(initialPipeline, after ?? state, idx) ?? ""
|
|
32526
|
+
});
|
|
32527
|
+
return { kind: "batch_pause" };
|
|
32528
|
+
}
|
|
32529
|
+
continue;
|
|
32530
|
+
}
|
|
32531
|
+
if (opts.dryRun) {
|
|
32532
|
+
return { kind: "dry_run" };
|
|
32533
|
+
}
|
|
32534
|
+
const overBudget = checkRunBudget(root, runId, state.currentStepIdx, budget, hooks);
|
|
32535
|
+
if (overBudget) {
|
|
32536
|
+
return overBudget;
|
|
31567
32537
|
}
|
|
31568
32538
|
if (untilIdx >= 0 && state.currentStepIdx >= untilIdx) {
|
|
31569
32539
|
hooks.onUntilStop?.({ untilIdx });
|
|
@@ -31571,10 +32541,49 @@ var require_execEngine = __commonJS({
|
|
|
31571
32541
|
}
|
|
31572
32542
|
}
|
|
31573
32543
|
}
|
|
32544
|
+
function checkRunBudget(root, runId, stepIdx, budget, hooks) {
|
|
32545
|
+
if (!budget) {
|
|
32546
|
+
return null;
|
|
32547
|
+
}
|
|
32548
|
+
const after = RunStateStore_1.RunStateStore.load(root, runId);
|
|
32549
|
+
const stepCosts = after ? after.steps.map((s) => s.costUsd) : [];
|
|
32550
|
+
const stepAccounting = after ? after.steps.map((s) => {
|
|
32551
|
+
if (typeof s.costUsd === "number") {
|
|
32552
|
+
return s.costEstimated ? "estimated" : "measured";
|
|
32553
|
+
}
|
|
32554
|
+
return s.startedAt ? "blind" : void 0;
|
|
32555
|
+
}) : [];
|
|
32556
|
+
const lastStepCost = after?.steps[stepIdx]?.costUsd;
|
|
32557
|
+
const verdict = (0, budget_1.checkBudget)({ stepCosts, stepAccounting, budget, lastStepCost });
|
|
32558
|
+
if (!verdict.ok) {
|
|
32559
|
+
hooks.onBudget?.({
|
|
32560
|
+
spent: verdict.spent,
|
|
32561
|
+
limit: verdict.limit,
|
|
32562
|
+
ok: false,
|
|
32563
|
+
exceeded: verdict.exceeded,
|
|
32564
|
+
onExceed: budget.on_exceed,
|
|
32565
|
+
runId,
|
|
32566
|
+
measured: verdict.measured,
|
|
32567
|
+
estimated: verdict.estimated,
|
|
32568
|
+
blindSteps: verdict.blindSteps
|
|
32569
|
+
});
|
|
32570
|
+
return budget.on_exceed === "fail" ? { kind: "error" } : { kind: "budget_pause" };
|
|
32571
|
+
}
|
|
32572
|
+
hooks.onBudget?.({
|
|
32573
|
+
spent: verdict.spent,
|
|
32574
|
+
limit: budget.max_usd,
|
|
32575
|
+
ok: true,
|
|
32576
|
+
runId,
|
|
32577
|
+
measured: verdict.measured,
|
|
32578
|
+
estimated: verdict.estimated,
|
|
32579
|
+
blindSteps: verdict.blindSteps
|
|
32580
|
+
});
|
|
32581
|
+
return null;
|
|
32582
|
+
}
|
|
31574
32583
|
function loadSkills(ws, skillIds) {
|
|
31575
32584
|
return skillIds.map((id) => ws.skills.load(id)).join("\n\n---\n\n");
|
|
31576
32585
|
}
|
|
31577
|
-
function buildStepPrompt(ws, agent, skillIds, runner, root, epicId) {
|
|
32586
|
+
function buildStepPrompt(ws, agent, skillIds, runner, root, epicId, stepRec, stepIdx) {
|
|
31578
32587
|
const harness = (0, types_1.harnessCapabilities)(runner);
|
|
31579
32588
|
return (0, promptComposer_1.composeAgentPrompt)({
|
|
31580
32589
|
skills: loadSkills(ws, skillIds),
|
|
@@ -31584,7 +32593,8 @@ var require_execEngine = __commonJS({
|
|
|
31584
32593
|
artifactLanguage: (0, artifactLanguage_1.resolveArtifactLanguage)(ws.config),
|
|
31585
32594
|
// Per epic, not per workspace: how deep a phase goes is a property of the
|
|
31586
32595
|
// work item. An epic that never set it reads as strict.
|
|
31587
|
-
strictMode: (0, strictMode_1.resolveEpicStrictMode)((0, EpicScaffold_1.epicsRoot)(root, ws.config), epicId)
|
|
32596
|
+
strictMode: (0, strictMode_1.resolveEpicStrictMode)((0, EpicScaffold_1.epicsRoot)(root, ws.config), epicId),
|
|
32597
|
+
runHistory: stepRec.revision > 1 ? { file: path17.relative(root, RunStateStore_1.RunStateStore.file(root, epicId)).split(path17.sep).join("/"), stepIdx } : null
|
|
31588
32598
|
});
|
|
31589
32599
|
}
|
|
31590
32600
|
async function execStep(root, state, runId, opts, hooks) {
|
|
@@ -31596,17 +32606,17 @@ var require_execEngine = __commonJS({
|
|
|
31596
32606
|
ws = WorkspaceLoader_1.WorkspaceLoader.load(root);
|
|
31597
32607
|
} catch (err) {
|
|
31598
32608
|
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: `Failed to load workspace: ${errMsg(err)}` });
|
|
31599
|
-
return
|
|
32609
|
+
return "failed";
|
|
31600
32610
|
}
|
|
31601
32611
|
const pipeline = ws.config.pipelines.find((p) => p.id === state.pipelineId);
|
|
31602
32612
|
if (!pipeline) {
|
|
31603
32613
|
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: `Pipeline "${state.pipelineId}" not found in workspace.yaml.` });
|
|
31604
|
-
return
|
|
32614
|
+
return "failed";
|
|
31605
32615
|
}
|
|
31606
32616
|
const agent = ws.config.agents.find((a) => a.id === agentId);
|
|
31607
32617
|
if (!agent) {
|
|
31608
32618
|
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: `Agent "${agentId}" not found in workspace.yaml.` });
|
|
31609
|
-
return
|
|
32619
|
+
return "failed";
|
|
31610
32620
|
}
|
|
31611
32621
|
const stepCfg = pipeline.steps[stepIdx];
|
|
31612
32622
|
const norm = stepCfg ? (0, WorkspaceSchema_1.normalizeStep)(stepCfg) : void 0;
|
|
@@ -31621,22 +32631,38 @@ var require_execEngine = __commonJS({
|
|
|
31621
32631
|
runner = ws.runners.resolve(agent);
|
|
31622
32632
|
} catch (err) {
|
|
31623
32633
|
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: `Failed to resolve runner for agent "${agentId}": ${errMsg(err)}` });
|
|
31624
|
-
return
|
|
32634
|
+
return "failed";
|
|
31625
32635
|
}
|
|
31626
32636
|
try {
|
|
31627
|
-
prompt2 = buildStepPrompt(ws, agent, skillIds, runner, root, state.runId);
|
|
32637
|
+
prompt2 = buildStepPrompt(ws, agent, skillIds, runner, root, state.runId, stepRec, stepIdx);
|
|
31628
32638
|
} catch (err) {
|
|
31629
32639
|
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: `Failed to load skills for agent "${agentId}": ${errMsg(err)}` });
|
|
31630
|
-
return
|
|
32640
|
+
return "failed";
|
|
31631
32641
|
}
|
|
31632
32642
|
const skillText = prompt2.text;
|
|
31633
32643
|
const env = ws.envResolver.resolveLayered(ws.config.environment ?? {}, agent.env ?? {});
|
|
32644
|
+
if (pipeline.autopilot) {
|
|
32645
|
+
env[autopilotPreflight_1.AUTOPILOT_ENV] = "1";
|
|
32646
|
+
}
|
|
31634
32647
|
const contextStr = Object.entries(state.context).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
31635
32648
|
const epicRoot = path17.relative(root, (0, EpicScaffold_1.epicsRoot)(root, ws.config)).split(path17.sep).join("/");
|
|
31636
32649
|
const inherited = state.context.from_epic ? `
|
|
31637
32650
|
|
|
31638
32651
|
About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` : "";
|
|
31639
|
-
const
|
|
32652
|
+
const baseMessage = opts.message ?? (contextStr ? contextStr + inherited : `Execute step: ${agentId}`);
|
|
32653
|
+
const feedback = (0, revisionFeedback_1.revisionFeedback)(state, stepIdx);
|
|
32654
|
+
const report = norm?.batches ? batchReport(pipeline, state, stepIdx) : null;
|
|
32655
|
+
if (norm?.batches && !report) {
|
|
32656
|
+
hooks.onStepFailed?.({
|
|
32657
|
+
stepIdx,
|
|
32658
|
+
agent: agentId,
|
|
32659
|
+
message: `Step "${agentId}" has \`batches: true\` but no \`produces\` file to write its \`Status:\` line in.`
|
|
32660
|
+
});
|
|
32661
|
+
return "failed";
|
|
32662
|
+
}
|
|
32663
|
+
const batchNo = report ? batchesOf(stepRec).length + 1 : 0;
|
|
32664
|
+
const batchNote = report ? batchInstructions(report, batchNo, stepRec.revision) : null;
|
|
32665
|
+
const userMessage = [baseMessage, feedback, batchNote].filter(Boolean).join("\n\n");
|
|
31640
32666
|
if (opts.dryRun) {
|
|
31641
32667
|
hooks.onDryRunPreview?.({
|
|
31642
32668
|
skills: skillIds.join(", "),
|
|
@@ -31645,7 +32671,7 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
|
|
|
31645
32671
|
env,
|
|
31646
32672
|
inlined: prompt2.included
|
|
31647
32673
|
});
|
|
31648
|
-
return
|
|
32674
|
+
return "done";
|
|
31649
32675
|
}
|
|
31650
32676
|
hooks.onStepStart?.({
|
|
31651
32677
|
stepIdx,
|
|
@@ -31659,20 +32685,69 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
|
|
|
31659
32685
|
const aliases = (0, pricing_1.providerAliases)(ws.config.providers, agent.runner);
|
|
31660
32686
|
const resolvedModel = (0, models_1.resolveProviderModel)(agent.runner, agentModel, aliases);
|
|
31661
32687
|
const producedBefore = (0, producesSnapshot_1.snapshotProduces)({ state, pipeline, workspaceRoot: root, stepIdx });
|
|
31662
|
-
const
|
|
31663
|
-
|
|
31664
|
-
|
|
31665
|
-
|
|
31666
|
-
|
|
31667
|
-
|
|
31668
|
-
|
|
31669
|
-
|
|
31670
|
-
|
|
31671
|
-
|
|
31672
|
-
|
|
31673
|
-
|
|
32688
|
+
const codeExclude = [
|
|
32689
|
+
path17.relative(root, path17.join((0, EpicScaffold_1.epicsRoot)(root, ws.config), state.runId)),
|
|
32690
|
+
".aidlc"
|
|
32691
|
+
];
|
|
32692
|
+
const sentBackHere = isAutoSendBackTarget(state, stepIdx);
|
|
32693
|
+
const codeBefore = sentBackHere || report ? (0, codeFingerprint_1.codeFingerprint)(root, codeExclude) : null;
|
|
32694
|
+
const stop = new AbortController();
|
|
32695
|
+
const minutes = norm?.timeout_minutes;
|
|
32696
|
+
let timedOut = false;
|
|
32697
|
+
const timer = minutes ? setTimeout(() => {
|
|
32698
|
+
timedOut = true;
|
|
32699
|
+
stop.abort();
|
|
32700
|
+
}, minutes * 6e4) : void 0;
|
|
32701
|
+
const onStopNow = () => stop.abort();
|
|
32702
|
+
opts.signal?.addEventListener("abort", onStopNow, { once: true });
|
|
32703
|
+
let result;
|
|
32704
|
+
try {
|
|
32705
|
+
result = await settledOrAbandoned(runner.run({
|
|
32706
|
+
skill: skillText,
|
|
32707
|
+
env,
|
|
32708
|
+
args: userMessage ? [userMessage] : [],
|
|
32709
|
+
workspaceRoot: root,
|
|
32710
|
+
model: agentModel,
|
|
32711
|
+
modelAliases: aliases,
|
|
32712
|
+
extraArgs: ws.config.providers[agent.runner]?.args,
|
|
32713
|
+
signal: stop.signal,
|
|
32714
|
+
onOutput: (chunk) => hooks.onOutput?.(chunk),
|
|
32715
|
+
onError: (chunk) => hooks.onErrorOutput?.(chunk),
|
|
32716
|
+
claude: null
|
|
32717
|
+
}), stop.signal);
|
|
32718
|
+
} finally {
|
|
32719
|
+
if (timer) {
|
|
32720
|
+
clearTimeout(timer);
|
|
32721
|
+
}
|
|
32722
|
+
opts.signal?.removeEventListener("abort", onStopNow);
|
|
32723
|
+
}
|
|
32724
|
+
if (stop.signal.aborted) {
|
|
32725
|
+
recordInterrupted(root, runId, stepIdx, timedOut ? { why: "timeout", minutes } : { why: "stopped" });
|
|
32726
|
+
if (timedOut) {
|
|
32727
|
+
hooks.onStepFailed?.({
|
|
32728
|
+
stepIdx,
|
|
32729
|
+
agent: agentId,
|
|
32730
|
+
message: `Step "${agentId}" ran past its ${minutes}-minute limit (\`timeout_minutes\`) and was stopped. It is still awaiting work on revision ${stepRec.revision}; nothing was sent back. Whatever it half-wrote is still in the working tree.`
|
|
32731
|
+
});
|
|
32732
|
+
return "failed";
|
|
32733
|
+
}
|
|
32734
|
+
hooks.onStepStopped?.({ stepIdx, agent: agentId, revision: stepRec.revision, runId });
|
|
32735
|
+
return "stopped";
|
|
32736
|
+
}
|
|
32737
|
+
if (!result || !result.success) {
|
|
31674
32738
|
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: `Step "${agentId}" failed (non-zero exit).` });
|
|
31675
|
-
return
|
|
32739
|
+
return "failed";
|
|
32740
|
+
}
|
|
32741
|
+
const codeUnchanged = codeBefore !== null && (0, codeFingerprint_1.codeFingerprint)(root, codeExclude) === codeBefore;
|
|
32742
|
+
if (sentBackHere && codeUnchanged && batchNo <= 1) {
|
|
32743
|
+
hooks.onStalled?.({
|
|
32744
|
+
stepIdx,
|
|
32745
|
+
agent: agentId,
|
|
32746
|
+
revision: stepRec.revision,
|
|
32747
|
+
runId,
|
|
32748
|
+
reason: `Revision ${stepRec.revision} of "${agentId}" changed no code \u2014 the working tree is what it was before it ran (its report aside). Sent back ${state.sendBacks} time${state.sendBacks === 1 ? "" : "s"}; stopping rather than have the same code reviewed again.`
|
|
32749
|
+
});
|
|
32750
|
+
return "stalled";
|
|
31676
32751
|
}
|
|
31677
32752
|
const stale = (0, producesSnapshot_1.unchangedProduces)(producedBefore, root);
|
|
31678
32753
|
if (stale.length > 0) {
|
|
@@ -31681,37 +32756,64 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
|
|
|
31681
32756
|
agent: agentId,
|
|
31682
32757
|
message: `Step "${agentId}" reported success but left its artifacts unchanged: ${stale.join(", ")}. The agent may have failed to write them. Check its output, then rerun the step.`
|
|
31683
32758
|
});
|
|
31684
|
-
return
|
|
32759
|
+
return "failed";
|
|
32760
|
+
}
|
|
32761
|
+
if (report) {
|
|
32762
|
+
const read = (0, batchStatus_1.readBatchStatusFile)(root, report);
|
|
32763
|
+
if ("error" in read) {
|
|
32764
|
+
hooks.onStepFailed?.({
|
|
32765
|
+
stepIdx,
|
|
32766
|
+
agent: agentId,
|
|
32767
|
+
message: `Step "${agentId}" runs in batches and its report cannot say whether it is done: ${read.error} Add the line, then run exec again.`
|
|
32768
|
+
});
|
|
32769
|
+
return "failed";
|
|
32770
|
+
}
|
|
32771
|
+
if (read.status === "continue") {
|
|
32772
|
+
if (codeUnchanged) {
|
|
32773
|
+
hooks.onStalled?.({
|
|
32774
|
+
stepIdx,
|
|
32775
|
+
agent: agentId,
|
|
32776
|
+
revision: stepRec.revision,
|
|
32777
|
+
runId,
|
|
32778
|
+
reason: `Batch ${batchNo} of "${agentId}" asked for another session but changed no code \u2014 the working tree is what it was before it ran (its report aside). Stopping rather than start the same batch again.`
|
|
32779
|
+
});
|
|
32780
|
+
return "stalled";
|
|
32781
|
+
}
|
|
32782
|
+
const fresh = RunStateStore_1.RunStateStore.load(root, runId);
|
|
32783
|
+
const rec = fresh?.steps[stepIdx];
|
|
32784
|
+
if (!fresh || !rec) {
|
|
32785
|
+
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: `Run "${runId}" disappeared.` });
|
|
32786
|
+
return "failed";
|
|
32787
|
+
}
|
|
32788
|
+
recordProvenance(rec, { agent, resolvedModel, agentModel, skillIds, alternatives, modelOpts });
|
|
32789
|
+
const cost = addBatchCost(rec, batchNo, result, batchCost(result, ws, agent.runner, resolvedModel ?? agentModel));
|
|
32790
|
+
rec.history = [...rec.history ?? [], {
|
|
32791
|
+
kind: "batch",
|
|
32792
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32793
|
+
revision: rec.revision,
|
|
32794
|
+
batch: batchNo,
|
|
32795
|
+
...cost !== void 0 ? { costUsd: cost } : {}
|
|
32796
|
+
}];
|
|
32797
|
+
persist(root, fresh);
|
|
32798
|
+
hooks.onBatchDone?.({
|
|
32799
|
+
stepIdx,
|
|
32800
|
+
agent: agentId,
|
|
32801
|
+
revision: rec.revision,
|
|
32802
|
+
batch: batchNo,
|
|
32803
|
+
costUsd: cost,
|
|
32804
|
+
costEstimated: rec.costEstimated,
|
|
32805
|
+
runId
|
|
32806
|
+
});
|
|
32807
|
+
return "batch";
|
|
32808
|
+
}
|
|
31685
32809
|
}
|
|
31686
32810
|
let next;
|
|
31687
32811
|
let freshState;
|
|
31688
32812
|
try {
|
|
31689
32813
|
freshState = RunStateStore_1.RunStateStore.load(root, runId);
|
|
31690
32814
|
const rec = freshState.steps[stepIdx];
|
|
31691
|
-
rec
|
|
31692
|
-
rec.
|
|
31693
|
-
if (alternatives) {
|
|
31694
|
-
rec.skill = skillIds[0];
|
|
31695
|
-
}
|
|
31696
|
-
if (modelOpts.models) {
|
|
31697
|
-
rec.chosenModel = agentModel;
|
|
31698
|
-
}
|
|
31699
|
-
rec.usage = result.usage;
|
|
31700
|
-
if (typeof result.costUsd === "number") {
|
|
31701
|
-
rec.costUsd = result.costUsd;
|
|
31702
|
-
rec.costEstimated = void 0;
|
|
31703
|
-
} else {
|
|
31704
|
-
const est = (0, pricing_1.estimateCostUsd)({
|
|
31705
|
-
table: (0, pricing_1.ratesFromConfig)(ws.config.providers),
|
|
31706
|
-
provider: agent.runner,
|
|
31707
|
-
model: resolvedModel ?? agentModel,
|
|
31708
|
-
usage: result.usage
|
|
31709
|
-
});
|
|
31710
|
-
if (est) {
|
|
31711
|
-
rec.costUsd = est.usd;
|
|
31712
|
-
rec.costEstimated = true;
|
|
31713
|
-
}
|
|
31714
|
-
}
|
|
32815
|
+
recordProvenance(rec, { agent, resolvedModel, agentModel, skillIds, alternatives, modelOpts });
|
|
32816
|
+
addBatchCost(rec, batchNo, result, batchCost(result, ws, agent.runner, resolvedModel ?? agentModel));
|
|
31715
32817
|
next = (0, PipelineRunner_1.markStepDone)({ state: freshState, pipeline, workspaceRoot: root });
|
|
31716
32818
|
} catch (err) {
|
|
31717
32819
|
if (err instanceof PipelineRunner_1.PipelineRunError && err.missing?.length) {
|
|
@@ -31719,7 +32821,7 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
|
|
|
31719
32821
|
} else {
|
|
31720
32822
|
hooks.onStepFailed?.({ stepIdx, agent: agentId, message: errMsg(err) });
|
|
31721
32823
|
}
|
|
31722
|
-
return
|
|
32824
|
+
return "failed";
|
|
31723
32825
|
}
|
|
31724
32826
|
persist(root, next, freshState);
|
|
31725
32827
|
const doneStep = next.steps[stepIdx];
|
|
@@ -31732,7 +32834,111 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
|
|
|
31732
32834
|
runner: agent.runner,
|
|
31733
32835
|
model: resolvedModel
|
|
31734
32836
|
});
|
|
31735
|
-
return
|
|
32837
|
+
return "done";
|
|
32838
|
+
}
|
|
32839
|
+
function batchesOf(rec) {
|
|
32840
|
+
if (!rec) {
|
|
32841
|
+
return [];
|
|
32842
|
+
}
|
|
32843
|
+
return (rec.history ?? []).flatMap((h) => h.kind === "batch" && h.revision === rec.revision ? [h] : []);
|
|
32844
|
+
}
|
|
32845
|
+
function batchReport(pipeline, state, stepIdx) {
|
|
32846
|
+
const cfg = pipeline.steps[stepIdx];
|
|
32847
|
+
if (!cfg) {
|
|
32848
|
+
return null;
|
|
32849
|
+
}
|
|
32850
|
+
const norm = (0, WorkspaceSchema_1.normalizeStep)(cfg);
|
|
32851
|
+
const first = norm.produces.find((p) => !norm.produces_optional.includes(p));
|
|
32852
|
+
return first ? (0, RunState_1.resolvePath)(first, state.context) : null;
|
|
32853
|
+
}
|
|
32854
|
+
function batchInstructions(report, batchNo, revision) {
|
|
32855
|
+
const lines = [
|
|
32856
|
+
`This step runs in batches: this is batch ${batchNo} of revision ${revision}, in a fresh session.`,
|
|
32857
|
+
batchNo === 1 && revision > 1 ? `Make this batch the fixes the feedback above asks for. Keep the progress table ${report} already has from the earlier revision, so you know what is done, and add the fixes to it.` : batchNo === 1 ? "Start with the first batch in the plan." : `${report} records what earlier batches did. Read it first, then do the next batch in the plan.`,
|
|
32858
|
+
`Do that one batch only, then update ${report}: its progress table, and as its last line \`Status: continue\` if any of the step's work is left, or \`Status: done\` when all of it is finished. A batch may be split smaller if it does not fit; never do two in one session.`
|
|
32859
|
+
];
|
|
32860
|
+
return lines.join(" ");
|
|
32861
|
+
}
|
|
32862
|
+
function recordProvenance(rec, p) {
|
|
32863
|
+
rec.runner = p.agent.runner;
|
|
32864
|
+
rec.model = p.resolvedModel;
|
|
32865
|
+
if (p.alternatives) {
|
|
32866
|
+
rec.skill = p.skillIds[0];
|
|
32867
|
+
}
|
|
32868
|
+
if (p.modelOpts.models) {
|
|
32869
|
+
rec.chosenModel = p.agentModel;
|
|
32870
|
+
}
|
|
32871
|
+
}
|
|
32872
|
+
function batchCost(result, ws, provider, model) {
|
|
32873
|
+
if (typeof result.costUsd === "number") {
|
|
32874
|
+
return { usd: result.costUsd, estimated: false };
|
|
32875
|
+
}
|
|
32876
|
+
const est = (0, pricing_1.estimateCostUsd)({
|
|
32877
|
+
table: (0, pricing_1.ratesFromConfig)(ws.config.providers),
|
|
32878
|
+
provider,
|
|
32879
|
+
model,
|
|
32880
|
+
usage: result.usage
|
|
32881
|
+
});
|
|
32882
|
+
return est ? { usd: est.usd, estimated: true } : void 0;
|
|
32883
|
+
}
|
|
32884
|
+
function addBatchCost(rec, batchNo, result, cost) {
|
|
32885
|
+
const carry = batchNo > 1;
|
|
32886
|
+
rec.usage = carry ? addUsage(rec.usage, result.usage) : result.usage;
|
|
32887
|
+
if (!cost) {
|
|
32888
|
+
return void 0;
|
|
32889
|
+
}
|
|
32890
|
+
if (carry && typeof rec.costUsd === "number") {
|
|
32891
|
+
rec.costUsd += cost.usd;
|
|
32892
|
+
rec.costEstimated = rec.costEstimated || cost.estimated || void 0;
|
|
32893
|
+
} else {
|
|
32894
|
+
rec.costUsd = cost.usd;
|
|
32895
|
+
rec.costEstimated = cost.estimated || void 0;
|
|
32896
|
+
}
|
|
32897
|
+
return cost.usd;
|
|
32898
|
+
}
|
|
32899
|
+
function addUsage(a, b) {
|
|
32900
|
+
if (!a) {
|
|
32901
|
+
return b;
|
|
32902
|
+
}
|
|
32903
|
+
if (!b) {
|
|
32904
|
+
return a;
|
|
32905
|
+
}
|
|
32906
|
+
const sum = (x, y) => x === void 0 && y === void 0 ? void 0 : (x ?? 0) + (y ?? 0);
|
|
32907
|
+
return { inputTokens: sum(a.inputTokens, b.inputTokens), outputTokens: sum(a.outputTokens, b.outputTokens) };
|
|
32908
|
+
}
|
|
32909
|
+
async function settledOrAbandoned(run, signal) {
|
|
32910
|
+
let timer;
|
|
32911
|
+
const abandoned = new Promise((resolve5) => {
|
|
32912
|
+
const giveUp = () => {
|
|
32913
|
+
timer = setTimeout(() => resolve5(null), processTree_1.STOP_GRACE_MS + 5e3);
|
|
32914
|
+
};
|
|
32915
|
+
if (signal.aborted) {
|
|
32916
|
+
giveUp();
|
|
32917
|
+
} else {
|
|
32918
|
+
signal.addEventListener("abort", giveUp, { once: true });
|
|
32919
|
+
}
|
|
32920
|
+
});
|
|
32921
|
+
try {
|
|
32922
|
+
return await Promise.race([run, abandoned]);
|
|
32923
|
+
} finally {
|
|
32924
|
+
if (timer) {
|
|
32925
|
+
clearTimeout(timer);
|
|
32926
|
+
}
|
|
32927
|
+
}
|
|
32928
|
+
}
|
|
32929
|
+
function recordInterrupted(root, runId, stepIdx, what) {
|
|
32930
|
+
const fresh = RunStateStore_1.RunStateStore.load(root, runId);
|
|
32931
|
+
const rec = fresh?.steps[stepIdx];
|
|
32932
|
+
if (!fresh || !rec) {
|
|
32933
|
+
return;
|
|
32934
|
+
}
|
|
32935
|
+
rec.history = [...rec.history ?? [], {
|
|
32936
|
+
kind: "interrupted",
|
|
32937
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32938
|
+
revision: rec.revision,
|
|
32939
|
+
...what
|
|
32940
|
+
}];
|
|
32941
|
+
RunStateStore_1.RunStateStore.save(root, fresh);
|
|
31736
32942
|
}
|
|
31737
32943
|
async function runAutoReviewStep(root, runId, hooks) {
|
|
31738
32944
|
const state = RunStateStore_1.RunStateStore.load(root, runId);
|
|
@@ -31762,18 +32968,43 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
|
|
|
31762
32968
|
return false;
|
|
31763
32969
|
}
|
|
31764
32970
|
persist(root, next, state);
|
|
32971
|
+
const idx = state.currentStepIdx;
|
|
32972
|
+
const sentBack = verdict.decision === "reject" && next.currentStepIdx !== idx && next.steps[idx].status === "pending";
|
|
31765
32973
|
hooks.onAutoReviewResult?.({
|
|
31766
32974
|
agent: step.agent,
|
|
31767
32975
|
decision: verdict.decision,
|
|
31768
|
-
reason: verdict.reason,
|
|
31769
|
-
runId
|
|
32976
|
+
reason: next.steps[idx].rejectReason ?? verdict.reason,
|
|
32977
|
+
runId,
|
|
32978
|
+
...sentBack ? {
|
|
32979
|
+
sentBackTo: {
|
|
32980
|
+
stepIdx: next.currentStepIdx,
|
|
32981
|
+
agent: next.steps[next.currentStepIdx].agent,
|
|
32982
|
+
revision: next.steps[next.currentStepIdx].revision,
|
|
32983
|
+
count: next.sendBacks ?? 0,
|
|
32984
|
+
max: pipeline.max_send_backs ?? WorkspaceSchema_1.DEFAULT_MAX_SEND_BACKS
|
|
32985
|
+
}
|
|
32986
|
+
} : {}
|
|
31770
32987
|
});
|
|
31771
32988
|
return true;
|
|
31772
32989
|
}
|
|
32990
|
+
function isAutoSendBackTarget(state, stepIdx) {
|
|
32991
|
+
if (!state.sendBacks) {
|
|
32992
|
+
return false;
|
|
32993
|
+
}
|
|
32994
|
+
let latest = null;
|
|
32995
|
+
for (const s of state.steps) {
|
|
32996
|
+
for (const h of s.history ?? []) {
|
|
32997
|
+
if (h.kind === "reject" && h.source && (!latest || h.at >= latest.at)) {
|
|
32998
|
+
latest = { at: h.at, to: h.sentBackToIdx };
|
|
32999
|
+
}
|
|
33000
|
+
}
|
|
33001
|
+
}
|
|
33002
|
+
return latest?.to === stepIdx;
|
|
33003
|
+
}
|
|
31773
33004
|
async function autoApproveStep(root, state, hooks) {
|
|
31774
33005
|
const ws = WorkspaceLoader_1.WorkspaceLoader.load(root);
|
|
31775
33006
|
const pipeline = ws.config.pipelines.find((p) => p.id === state.pipelineId);
|
|
31776
|
-
const next = (0, PipelineRunner_1.approveStep)({ state, pipeline });
|
|
33007
|
+
const next = { ...(0, PipelineRunner_1.approveStep)({ state, pipeline }), sendBacks: state.sendBacks };
|
|
31777
33008
|
persist(root, next, state);
|
|
31778
33009
|
hooks.onAutoApproved?.({ agent: state.steps[state.currentStepIdx].agent });
|
|
31779
33010
|
}
|
|
@@ -31948,6 +33179,10 @@ var require_runReport = __commonJS({
|
|
|
31948
33179
|
return ` - \u2714 approved (rev ${h.revision}${h.skill ? `, ${h.skill}` : ""}${h.model ? `, ${h.model}` : ""})`;
|
|
31949
33180
|
case "undo":
|
|
31950
33181
|
return ` - \u21B6 mark-done undone (rev ${h.revision}, was ${h.from})`;
|
|
33182
|
+
case "interrupted":
|
|
33183
|
+
return h.why === "timeout" ? ` - \u23F1 stopped after ${h.minutes ?? "?"} min (timeout_minutes, rev ${h.revision})` : ` - \u23F9 stopped mid-step (rev ${h.revision})`;
|
|
33184
|
+
case "batch":
|
|
33185
|
+
return ` - \u21BB batch ${h.batch} done, more to come (rev ${h.revision}${typeof h.costUsd === "number" ? `, $${h.costUsd.toFixed(4)}` : ""})`;
|
|
31951
33186
|
default:
|
|
31952
33187
|
return " - (unknown event)";
|
|
31953
33188
|
}
|
|
@@ -32593,6 +33828,8 @@ into working code on a feature branch.
|
|
|
32593
33828
|
dependsOn: ["review"]
|
|
32594
33829
|
}
|
|
32595
33830
|
];
|
|
33831
|
+
var VERDICT_VALIDATOR = ".aidlc/validators/verdict.mjs";
|
|
33832
|
+
var CI_VALIDATOR = ".aidlc/validators/ci.mjs";
|
|
32596
33833
|
var AINATIVE_RECIPES = [
|
|
32597
33834
|
{
|
|
32598
33835
|
id: "native-quick",
|
|
@@ -32601,7 +33838,7 @@ into working code on a feature branch.
|
|
|
32601
33838
|
},
|
|
32602
33839
|
{
|
|
32603
33840
|
id: "native-lite",
|
|
32604
|
-
description: "Small change with a precedent already in the codebase \u2014 no spec, no separate verify. The human gates sit up front, on intent and build-plan, where a wrong direction is cheapest to correct; implement and review then run to the end unattended. Trade-off: review is the only quality gate left, and nobody reads it before the branch is finished \u2014 prefer native-fix when the change has no precedent to follow.",
|
|
33841
|
+
description: "Small change with a precedent already in the codebase \u2014 no spec, no separate verify. The human gates sit up front, on intent and build-plan, where a wrong direction is cheapest to correct; implement and review then run to the end unattended. Trade-off: review is the only quality gate left, and nobody reads it before the branch is finished \u2014 a hold verdict stops the run, but prefer native-fix when the change has no precedent to follow.",
|
|
32605
33842
|
steps: ["intent", "build-plan", "implement", "review"],
|
|
32606
33843
|
// Spelled out for all four steps, including the two that would inherit
|
|
32607
33844
|
// `true` anyway: where the humans stand is the point of this recipe, so
|
|
@@ -32610,7 +33847,48 @@ into working code on a feature branch.
|
|
|
32610
33847
|
intent: { human_review: true },
|
|
32611
33848
|
"build-plan": { human_review: true },
|
|
32612
33849
|
implement: { human_review: false },
|
|
32613
|
-
review
|
|
33850
|
+
// Nobody reads review.md before the run ends, so something has to: a
|
|
33851
|
+
// `hold` (or no readable verdict) rejects the step instead of letting
|
|
33852
|
+
// the run report `completed`.
|
|
33853
|
+
review: { human_review: false, auto_review: true, auto_review_runner: VERDICT_VALIDATOR }
|
|
33854
|
+
}
|
|
33855
|
+
},
|
|
33856
|
+
{
|
|
33857
|
+
id: "native-autopilot",
|
|
33858
|
+
description: "Left to run on its own once the plan is approved \u2014 no spec. A person approves intent and build-plan, then implement, verify and review run unattended: CI checks implement, and a failed verify or a review hold sends the work back to implement on its own, up to three times. The run stops at review for a person to approve the finished branch. Needs a branch of its own, the approval-gate hook and real CHECKS in .aidlc/validators/ci.mjs.",
|
|
33859
|
+
steps: ["intent", "build-plan", "implement", "verify", "review"],
|
|
33860
|
+
autopilot: true,
|
|
33861
|
+
max_send_backs: 3,
|
|
33862
|
+
gates: {
|
|
33863
|
+
intent: { human_review: true, timeout_minutes: 20 },
|
|
33864
|
+
"build-plan": { human_review: true, timeout_minutes: 20 },
|
|
33865
|
+
// A CI reject reruns implement on its own feedback; it is never sent
|
|
33866
|
+
// anywhere else. Each batch is a fresh session with its own 30 minutes.
|
|
33867
|
+
implement: {
|
|
33868
|
+
human_review: false,
|
|
33869
|
+
auto_review: true,
|
|
33870
|
+
auto_review_runner: CI_VALIDATOR,
|
|
33871
|
+
batches: true,
|
|
33872
|
+
timeout_minutes: 30
|
|
33873
|
+
},
|
|
33874
|
+
verify: {
|
|
33875
|
+
human_review: false,
|
|
33876
|
+
auto_review: true,
|
|
33877
|
+
auto_review_runner: VERDICT_VALIDATOR,
|
|
33878
|
+
on_reject: { send_back_to: "implement" },
|
|
33879
|
+
timeout_minutes: 20
|
|
33880
|
+
},
|
|
33881
|
+
// A person still approves the end of the run (a `ship` stops here), but
|
|
33882
|
+
// only once: a `hold` goes back to implement without waiting for them.
|
|
33883
|
+
// Once the validators have earned trust, `human_review: false` makes a
|
|
33884
|
+
// `ship` complete the run.
|
|
33885
|
+
review: {
|
|
33886
|
+
human_review: true,
|
|
33887
|
+
auto_review: true,
|
|
33888
|
+
auto_review_runner: VERDICT_VALIDATOR,
|
|
33889
|
+
on_reject: { send_back_to: "implement" },
|
|
33890
|
+
timeout_minutes: 20
|
|
33891
|
+
}
|
|
32614
33892
|
}
|
|
32615
33893
|
},
|
|
32616
33894
|
{
|
|
@@ -32823,7 +34101,9 @@ into working code on a feature branch.
|
|
|
32823
34101
|
description: r.description,
|
|
32824
34102
|
from: workflow.pipelineId,
|
|
32825
34103
|
steps: r.steps,
|
|
32826
|
-
...r.gates ? { gates: r.gates } : {}
|
|
34104
|
+
...r.gates ? { gates: r.gates } : {},
|
|
34105
|
+
...r.autopilot !== void 0 ? { autopilot: r.autopilot } : {},
|
|
34106
|
+
...r.max_send_backs !== void 0 ? { max_send_backs: r.max_send_backs } : {}
|
|
32827
34107
|
})),
|
|
32828
34108
|
sidebar: {
|
|
32829
34109
|
views: [
|
|
@@ -33054,12 +34334,15 @@ export default async function ci(_ctx) {
|
|
|
33054
34334
|
}
|
|
33055
34335
|
`;
|
|
33056
34336
|
function writeBuiltinAutoReviewValidators(extensionPath, root, workflow) {
|
|
34337
|
+
const runners = [
|
|
34338
|
+
...workflow.phases.filter((p) => p.autoReview).map((p) => p.autoReviewRunner),
|
|
34339
|
+
...(workflow.recipes ?? []).flatMap((r) => Object.values(r.gates ?? {}).map((g) => g.auto_review_runner))
|
|
34340
|
+
];
|
|
33057
34341
|
const seen = /* @__PURE__ */ new Set();
|
|
33058
|
-
for (const
|
|
33059
|
-
if (!
|
|
34342
|
+
for (const rel of runners) {
|
|
34343
|
+
if (!rel) {
|
|
33060
34344
|
continue;
|
|
33061
34345
|
}
|
|
33062
|
-
const rel = phase.autoReviewRunner;
|
|
33063
34346
|
if (path17.isAbsolute(rel) || rel.startsWith("..")) {
|
|
33064
34347
|
continue;
|
|
33065
34348
|
}
|
|
@@ -34116,13 +35399,14 @@ var require_dist = __commonJS({
|
|
|
34116
35399
|
"../core/dist/index.js"(exports2) {
|
|
34117
35400
|
"use strict";
|
|
34118
35401
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
34119
|
-
exports2.
|
|
34120
|
-
exports2.
|
|
34121
|
-
exports2.
|
|
34122
|
-
exports2.
|
|
34123
|
-
exports2.
|
|
34124
|
-
exports2.
|
|
34125
|
-
exports2.
|
|
35402
|
+
exports2.commitEpicStepEdit = exports2.planSetEpicStepGates = exports2.planRemoveEpicStep = exports2.planAddEpicStep = exports2.EpicWorkflowSwitchError = exports2.canSwitchEpicWorkflow = exports2.epicWorkflowLock = exports2.applyEpicWorkflowSwitch = exports2.stageEpicWorkflowSwitch = exports2.planEpicWorkflowSwitch = exports2.EpicDescriptionError = exports2.setEpicDescription = exports2.lockedEpicDirError = exports2.EpicScaffoldError = exports2.epicsRoot = exports2.mapStepStatusToEpic = exports2.mirrorRunStateToEpic = exports2.scaffoldEpic = exports2.resolveArtifactCommitConfig = exports2.commitApprovedArtifacts = exports2.PipelineAdaptError = exports2.applyAdaptation = exports2.parseAdaptationVerdict = exports2.buildAdaptationPrompt = exports2.buildPhaseCatalog = exports2.slugEpicId = exports2.parseClassificationVerdict = exports2.buildClassificationPrompt = exports2.heuristicClassify = exports2.PipelineAssembleError = exports2.pipelineRecipeLabel = exports2.recipePipelineId = exports2.assemblePipeline = exports2.unsafeRunnerArg = exports2.DEFAULT_MAX_BATCHES = exports2.DEFAULT_MAX_SEND_BACKS = exports2.AMBIGUOUS_STEP_INDEX = exports2.sendBackIssues = exports2.findStepIndex = exports2.collectWorkspaceRefIssues = exports2.resolveStepSkills = exports2.stepSkillAlternatives = exports2.stepDagId = exports2.stepAgentId = exports2.requiresEntries = exports2.producesEntries = exports2.normalizeStep = exports2.WorkspaceValidationError = exports2.validateWorkspace = exports2.WorkspaceSchema = void 0;
|
|
35403
|
+
exports2.generatePlan = exports2.collectContext = exports2.followUpHookFailures = exports2.pendingFollowUpDone = exports2.applyFollowUpHookRun = exports2.trackFollowUpChildren = exports2.writeFollowUpHookLedger = exports2.readFollowUpHookLedger = exports2.followUpHookLedgerPath = exports2.runFollowUpHook = exports2.fillFollowUpHookCommand = exports2.resolveFollowUpHooks = exports2.epicPipelineId = exports2.FOLLOW_UP_HOOK_TIMEOUT_MS = exports2.FOLLOW_UP_HOOKS_LEDGER = exports2.stepProducesFollowUps = exports2.collectFollowUpHookIssues = exports2.FOLLOW_UP_HOOK_PLACEHOLDERS = exports2.FOLLOW_UP_HOOK_KEYS = exports2.FOLLOW_UP_INTENT = exports2.FOLLOW_UPS_FILE = exports2.MANUAL_FOLLOW_UP_KEY_PREFIX = exports2.followUpDefaults = exports2.nextManualFollowUpKey = exports2.withFollowUpProvenance = exports2.openManifestFollowUp = exports2.combinedParentId = exports2.followUpChildId = exports2.followUpsOf = exports2.readEpicFollowUps = exports2.parseFollowUps = exports2.FollowUpsParseError = exports2.FollowUpManifestSchema = exports2.FollowUpItemSchema = exports2.SIGNAL_FILE = exports2.FOLLOW_UP_ARTIFACT = exports2.readEpicSignal = exports2.existingEpicIds = exports2.followUpIdFor = exports2.followUpEpicId = exports2.renderIntentMarkdown = exports2.openFollowUpEpic = exports2.openIncidentEpic = exports2.SignalParseError = exports2.isSignal = exports2.parseSignal = exports2.SignalSchema = exports2.EpicStepEditError = exports2.resolveStepRef = exports2.describeGateEffect = void 0;
|
|
35404
|
+
exports2.readUserConfig = exports2.readGitUserName = exports2.ensureUserConfigIgnored = exports2.USER_CONFIG_RELPATH = exports2.USER_CONFIG_IGNORE_LINE = exports2.suggestEpicId = exports2.resolveEpicIdPrefixChain = exports2.resolveEpicIdPrefix = exports2.epicIdDateStamp = exports2.deriveEpicIdPrefix = exports2.EPIC_ID_PREFIX_PATTERN = exports2.EPIC_ID_PREFIX_KEY = exports2.resolveArtifactLanguage = exports2.commandBodyPredatesArtifactLanguage = exports2.artifactLanguageSection = exports2.ARTIFACT_LANGUAGE_HEADING = exports2.stripPersonaDirectives = exports2.composeAgentPrompt = exports2.PROJECT_INSTRUCTION_FILES = exports2.findProjectInstructions = exports2.stripPersonaMetadata = exports2.PersonaLoader = exports2.SkillNotFoundError = exports2.SkillLoader = exports2.EnvVarMissingError = exports2.EnvResolver = exports2.epicPipelineReport = exports2.planEpicPipelineExtraction = exports2.epicOwningPipeline = exports2.unstageEpicPipeline = exports2.stageEpicPipeline = exports2.writeEpicPipelines = exports2.splitEpicPipelines = exports2.mergeEpicPipelines = exports2.epicPipelinePath = exports2.EPIC_PIPELINE_FILENAME = exports2.unusedAfterStepRemoval = exports2.skillReferences = exports2.agentReferences = exports2.renameSkillRefs = exports2.renameAgentRefs = exports2.dropRecipesForPipeline = exports2.dropRecipeStep = exports2.recipesDrawingFrom = exports2.WORKSPACE_DIR = exports2.WORKSPACE_FILENAME = exports2.WorkspaceParseError = exports2.WorkspaceNotFoundError = exports2.WorkspaceLoader = exports2.renderPlanMarkdown = void 0;
|
|
35405
|
+
exports2.hasEmptyCiChecks = exports2.findApprovalGate = exports2.autopilotPreflight = exports2.STOP_GRACE_MS = exports2.stopProcessTree = exports2.stopOnAbort = exports2.processGroupSpawnOptions = exports2.claudeModelArg = exports2.DefaultRunner = exports2.RunnerRegistry = exports2.targetPath = exports2.scopePaths = exports2.discoverAssets = exports2.commandBodyIsStale = exports2.readEpicTags = exports2.normalizeTags = exports2.normalizeTag = exports2.epicMatchesTags = exports2.applyTagEdit = exports2.MAX_TAG_LENGTH = exports2.EPIC_TAGS_KEY = exports2.inheritedContextNote = exports2.INHERITED_CONTEXT_MARKER = exports2.strictModeSection = exports2.resolveEpicStrictMode = exports2.epicStrictMode = exports2.commandBodyPredatesStrictMode = exports2.STRICT_MODE_KEY = exports2.STRICT_MODE_HEADING = exports2.setEpicWatched = exports2.setEpicListFlat = exports2.setEpicSort = exports2.setActiveEpic = exports2.recordEpicOpened = exports2.readEpicListFlat = exports2.readEpicSort = exports2.readEpicFocus = exports2.pushRecent = exports2.epicSortFrom = exports2.epicIdFromBranch = exports2.epicFocusFrom = exports2.WATCHED_EPICS_KEY = exports2.RECENT_EPICS_LIMIT = exports2.RECENT_EPICS_KEY = exports2.EPIC_LIST_FLAT_KEY = exports2.EPIC_SORT_KEY = exports2.ACTIVE_EPIC_KEY = exports2.writeUserEpicIdPrefix = exports2.userConfigPath = exports2.updateUserConfig = void 0;
|
|
35406
|
+
exports2.isStepOptional = exports2.isRunComplete = exports2.deriveRunProgress = exports2.PipelineRunError = exports2.retryAutoReview = exports2.submitAutoReviewVerdict = exports2.dirtyUpstreamOf = exports2.rerunApprovedStep = exports2.canRerunApprovedStep = exports2.chooseStepModel = exports2.chooseStepSkill = exports2.requestStepUpdate = exports2.rerunStep = exports2.rejectStep = exports2.approveStep = exports2.undoStepDone = exports2.canUndoStepDone = exports2.markStepDone = exports2.canStartStep = exports2.startRun = exports2.activateBackendFromWorkspace = exports2.activateRunStateBackend = exports2.resolveRunStateBackend = exports2.GitRunStateStore = exports2.RUN_ID_PATTERN = exports2.FileRunStateStore = exports2.RunStateStore = exports2.harnessCapabilities = exports2.NO_HARNESS_CAPABILITIES = exports2.RunnerValidationError = exports2.validateRunnerExport = exports2.CustomRunnerLoader = exports2.buildClaudeSpawnEnv = exports2.hasClaudeLogin = exports2.isInsideClaudeCodeSession = exports2.createJsonSink = exports2.createLineSink = exports2.isCodexMcpConfigured = exports2.codexConfigPath = exports2.readProjectMcpServer = exports2.mcpRegistrarFor = exports2.codexMcpRegistrar = exports2.claudeMcpRegistrar = exports2.copilotMcpConfig = exports2.copilotGraphServer = exports2.CopilotRunner = exports2.CodexRunner = exports2.AUTOPILOT_ENV = exports2.APPROVAL_GATE_SCRIPT = exports2.emptyCiChecksMessage = void 0;
|
|
35407
|
+
exports2.isClaudeTierAlias = exports2.CLAUDE_TIER_ALIASES = exports2.FAST_MODEL = exports2.CODING_MODEL = exports2.PLANNING_MODEL = exports2.isBuiltinPreset = exports2.BUILTIN_PRESET_IDS = exports2.writeBuiltinAutoReviewValidators = exports2.resolvePrimaryStack = exports2.getSdlcArtifactTemplates = exports2.getBuiltinArtifactTemplates = exports2.phaseArtifactFileName = exports2.sdlcClaudeCommand = exports2.builtinClaudeCommand = exports2.loadAllBuiltinPresets = exports2.loadBuiltinPreset = exports2.planRecipeMigration = exports2.getBuiltinRecipeSummaries = exports2.getAllBuiltinPipelineSummaries = exports2.getSdlcBuiltinPipelineSummary = exports2.getBuiltinPipelineSummary = exports2.getBuiltinWorkflowByPipelineId = exports2.getBuiltinWorkflow = exports2.workflowSlug = exports2.builtinTemplatesRoot = exports2.pipelineCommandId = exports2.PHASES = exports2.BUILTIN_WORKFLOWS = exports2.withBackfilledStepNames = exports2.describeDrift = exports2.reconcileRunSteps = exports2.RUN_STATE_SCHEMA_VERSION = exports2.migrateRunState = exports2.stepIdentity = exports2.resolvePath = exports2.AutoReviewerError = exports2.runAutoReview = exports2.renderRunReport = exports2.verifyRun = exports2.runExecLoop = exports2.estimateCostUsd = exports2.providerAliases = exports2.ratesFromConfig = exports2.mergeRates = exports2.BUILTIN_RATES = exports2.unchangedProduces = exports2.snapshotProduces = exports2.checkBudget = exports2.weighStepProgress = exports2.isActiveStatus = void 0;
|
|
35408
|
+
exports2.defaultClaudeConfigDir = exports2.getClaudeConfigDirOverride = exports2.setClaudeConfigDir = exports2.resolveDeclaredPath = exports2.expandHome = exports2.ProfileLoadError = exports2.UnknownStandardError = exports2.builtinProfiles = exports2.loadActiveProfile = exports2.loadProfile = exports2.listProfileManifests = exports2.resolveStandard = exports2.workspaceStandard = exports2.isBuiltinProfileId = exports2.ProfileSchema = exports2.TRACE_RULES = exports2.PROFILES_DIR = exports2.DEFAULT_PROFILE_ID = exports2.BUILTIN_PROFILE_IDS = exports2.setEpicMemoryHook = exports2.isEpicMemoryHookEnabled = exports2.installAnnotationTools = exports2.relativeEpicRoot = exports2.provisionDeclaredWorkflows = exports2.provisionWorkflowFiles = exports2.writeWorkflowArtifactTemplates = exports2.writeWorkflowCommands = exports2.provisionShortcutDocs = exports2.writeTwoLayerCommands = exports2.shortcutCommandDoc = exports2.backboneCommandDoc = exports2.unprovisionedPhases = exports2.nextEligiblePhase = exports2.resolveComposition = exports2.shortcutCommandId = exports2.getCanonicalPhase = exports2.isCanonicalPhase = exports2.BACKBONE_COMMAND_ID = exports2.CANONICAL_PHASE_IDS = exports2.CANONICAL_PHASES = exports2.renderTemplate = exports2.DEFAULT_GLOBAL_WORKFLOW_IDS = exports2.detectGlobalBuiltinSource = exports2.uninstallWorkflowGlobalsByIds = exports2.isWorkflowGloballyInstalled = exports2.installWorkflowGlobalsByIds = exports2.installGlobalDefaults = exports2.stepModelOptions = exports2.pickAgentModel = exports2.resolveProviderModel = void 0;
|
|
35409
|
+
exports2.AIDLC_CORE_VERSION = exports2.AIDLC_CLI_GUIDE_TEXT = exports2.AIDLC_KNOWLEDGE = exports2.clearResolveCommandCache = exports2.resolveCommand = exports2.remapClaudePath = exports2.claudeConfigEnv = exports2.claudeJsonPath = exports2.isDefaultClaudeConfigDir = exports2.claudeConfigDir = exports2.resolveClaudeConfigDir = void 0;
|
|
34126
35410
|
var WorkspaceSchema_1 = require_WorkspaceSchema();
|
|
34127
35411
|
Object.defineProperty(exports2, "WorkspaceSchema", { enumerable: true, get: function() {
|
|
34128
35412
|
return WorkspaceSchema_1.WorkspaceSchema;
|
|
@@ -34139,6 +35423,9 @@ var require_dist = __commonJS({
|
|
|
34139
35423
|
Object.defineProperty(exports2, "producesEntries", { enumerable: true, get: function() {
|
|
34140
35424
|
return WorkspaceSchema_1.producesEntries;
|
|
34141
35425
|
} });
|
|
35426
|
+
Object.defineProperty(exports2, "requiresEntries", { enumerable: true, get: function() {
|
|
35427
|
+
return WorkspaceSchema_1.requiresEntries;
|
|
35428
|
+
} });
|
|
34142
35429
|
Object.defineProperty(exports2, "stepAgentId", { enumerable: true, get: function() {
|
|
34143
35430
|
return WorkspaceSchema_1.stepAgentId;
|
|
34144
35431
|
} });
|
|
@@ -34154,6 +35441,24 @@ var require_dist = __commonJS({
|
|
|
34154
35441
|
Object.defineProperty(exports2, "collectWorkspaceRefIssues", { enumerable: true, get: function() {
|
|
34155
35442
|
return WorkspaceSchema_1.collectWorkspaceRefIssues;
|
|
34156
35443
|
} });
|
|
35444
|
+
Object.defineProperty(exports2, "findStepIndex", { enumerable: true, get: function() {
|
|
35445
|
+
return WorkspaceSchema_1.findStepIndex;
|
|
35446
|
+
} });
|
|
35447
|
+
Object.defineProperty(exports2, "sendBackIssues", { enumerable: true, get: function() {
|
|
35448
|
+
return WorkspaceSchema_1.sendBackIssues;
|
|
35449
|
+
} });
|
|
35450
|
+
Object.defineProperty(exports2, "AMBIGUOUS_STEP_INDEX", { enumerable: true, get: function() {
|
|
35451
|
+
return WorkspaceSchema_1.AMBIGUOUS_STEP_INDEX;
|
|
35452
|
+
} });
|
|
35453
|
+
Object.defineProperty(exports2, "DEFAULT_MAX_SEND_BACKS", { enumerable: true, get: function() {
|
|
35454
|
+
return WorkspaceSchema_1.DEFAULT_MAX_SEND_BACKS;
|
|
35455
|
+
} });
|
|
35456
|
+
Object.defineProperty(exports2, "DEFAULT_MAX_BATCHES", { enumerable: true, get: function() {
|
|
35457
|
+
return WorkspaceSchema_1.DEFAULT_MAX_BATCHES;
|
|
35458
|
+
} });
|
|
35459
|
+
Object.defineProperty(exports2, "unsafeRunnerArg", { enumerable: true, get: function() {
|
|
35460
|
+
return WorkspaceSchema_1.unsafeRunnerArg;
|
|
35461
|
+
} });
|
|
34157
35462
|
var PipelineAssembler_1 = require_PipelineAssembler();
|
|
34158
35463
|
Object.defineProperty(exports2, "assemblePipeline", { enumerable: true, get: function() {
|
|
34159
35464
|
return PipelineAssembler_1.assemblePipeline;
|
|
@@ -34717,6 +36022,38 @@ var require_dist = __commonJS({
|
|
|
34717
36022
|
Object.defineProperty(exports2, "claudeModelArg", { enumerable: true, get: function() {
|
|
34718
36023
|
return DefaultRunner_1.claudeModelArg;
|
|
34719
36024
|
} });
|
|
36025
|
+
var processTree_1 = require_processTree();
|
|
36026
|
+
Object.defineProperty(exports2, "processGroupSpawnOptions", { enumerable: true, get: function() {
|
|
36027
|
+
return processTree_1.processGroupSpawnOptions;
|
|
36028
|
+
} });
|
|
36029
|
+
Object.defineProperty(exports2, "stopOnAbort", { enumerable: true, get: function() {
|
|
36030
|
+
return processTree_1.stopOnAbort;
|
|
36031
|
+
} });
|
|
36032
|
+
Object.defineProperty(exports2, "stopProcessTree", { enumerable: true, get: function() {
|
|
36033
|
+
return processTree_1.stopProcessTree;
|
|
36034
|
+
} });
|
|
36035
|
+
Object.defineProperty(exports2, "STOP_GRACE_MS", { enumerable: true, get: function() {
|
|
36036
|
+
return processTree_1.STOP_GRACE_MS;
|
|
36037
|
+
} });
|
|
36038
|
+
var autopilotPreflight_1 = require_autopilotPreflight();
|
|
36039
|
+
Object.defineProperty(exports2, "autopilotPreflight", { enumerable: true, get: function() {
|
|
36040
|
+
return autopilotPreflight_1.autopilotPreflight;
|
|
36041
|
+
} });
|
|
36042
|
+
Object.defineProperty(exports2, "findApprovalGate", { enumerable: true, get: function() {
|
|
36043
|
+
return autopilotPreflight_1.findApprovalGate;
|
|
36044
|
+
} });
|
|
36045
|
+
Object.defineProperty(exports2, "hasEmptyCiChecks", { enumerable: true, get: function() {
|
|
36046
|
+
return autopilotPreflight_1.hasEmptyCiChecks;
|
|
36047
|
+
} });
|
|
36048
|
+
Object.defineProperty(exports2, "emptyCiChecksMessage", { enumerable: true, get: function() {
|
|
36049
|
+
return autopilotPreflight_1.emptyCiChecksMessage;
|
|
36050
|
+
} });
|
|
36051
|
+
Object.defineProperty(exports2, "APPROVAL_GATE_SCRIPT", { enumerable: true, get: function() {
|
|
36052
|
+
return autopilotPreflight_1.APPROVAL_GATE_SCRIPT;
|
|
36053
|
+
} });
|
|
36054
|
+
Object.defineProperty(exports2, "AUTOPILOT_ENV", { enumerable: true, get: function() {
|
|
36055
|
+
return autopilotPreflight_1.AUTOPILOT_ENV;
|
|
36056
|
+
} });
|
|
34720
36057
|
var CodexRunner_1 = require_CodexRunner();
|
|
34721
36058
|
Object.defineProperty(exports2, "CodexRunner", { enumerable: true, get: function() {
|
|
34722
36059
|
return CodexRunner_1.CodexRunner;
|
|
@@ -43891,7 +45228,7 @@ var require_package = __commonJS({
|
|
|
43891
45228
|
"package.json"(exports2, module2) {
|
|
43892
45229
|
module2.exports = {
|
|
43893
45230
|
name: "@delete101020/aidlc",
|
|
43894
|
-
version: "4.0.
|
|
45231
|
+
version: "4.0.41",
|
|
43895
45232
|
description: "AIDLC Native CLI, a fork of AIDLC \u2014 drive Claude through the six-stage AI-Native SDLC Playbook: Plan \u2192 Design \u2192 Build \u2192 Test \u2192 Deploy \u2192 Maintain, with artifact gates, requirements traceability, an incident loop back to Plan, and Spec Kit support.",
|
|
43896
45233
|
license: "MIT",
|
|
43897
45234
|
repository: {
|
|
@@ -47158,6 +48495,76 @@ function providerChecks(ws) {
|
|
|
47158
48495
|
}
|
|
47159
48496
|
return checks;
|
|
47160
48497
|
}
|
|
48498
|
+
function autopilotChecks(root, ws) {
|
|
48499
|
+
const checks = [];
|
|
48500
|
+
const autopilot = ws.config.pipelines.filter((p) => p.autopilot).map((p) => p.id);
|
|
48501
|
+
const needed = autopilot.length > 0;
|
|
48502
|
+
const missing = (label, info2) => needed ? fail(label, info2) : warn(label, info2);
|
|
48503
|
+
if (needed) {
|
|
48504
|
+
checks.push(ok(`autopilot pipeline${autopilot.length !== 1 ? "s" : ""}`, autopilot.join(", ")));
|
|
48505
|
+
}
|
|
48506
|
+
const usesClaude = ws.config.agents.some((a) => a.runner === "default");
|
|
48507
|
+
if (usesClaude) {
|
|
48508
|
+
const gate = (0, import_core5.findApprovalGate)(root);
|
|
48509
|
+
checks.push(gate.found ? ok("approval gate hook", path4.relative(root, gate.settingsFile).split(path4.sep).join("/") || gate.settingsFile) : missing("approval gate hook", gate.reason));
|
|
48510
|
+
const args = ws.config.providers.default?.args ?? [];
|
|
48511
|
+
const viaArgs = args.some((a) => /^--(allowedTools|allowed-tools|permission-mode)(=|$)/.test(a));
|
|
48512
|
+
const viaSettings = claudeAllowListFiles(root);
|
|
48513
|
+
checks.push(viaArgs ? ok("headless permissions", "providers.default.args") : viaSettings.length > 0 ? ok("headless permissions", `permissions.allow in ${viaSettings.join(", ")}`) : missing(
|
|
48514
|
+
"headless permissions",
|
|
48515
|
+
'nothing allows Claude to edit files or run commands without asking, and under --print nobody can be asked \u2014 set providers.default.args (e.g. [--permission-mode, acceptEdits, --allowedTools, "Bash(npm test:*)"])'
|
|
48516
|
+
));
|
|
48517
|
+
}
|
|
48518
|
+
for (const id of autopilot) {
|
|
48519
|
+
const pipeline = ws.config.pipelines.find((p) => p.id === id);
|
|
48520
|
+
const runners = new Set(pipeline.steps.map((s) => ws.config.agents.find((a) => a.id === (typeof s === "string" ? s : s.agent))?.runner).filter((r) => !!r && r !== "default"));
|
|
48521
|
+
for (const runner of runners) {
|
|
48522
|
+
checks.push(warn(
|
|
48523
|
+
`"${id}" on ${runner}`,
|
|
48524
|
+
`the approval gate is a Claude Code hook, and ${runner} steps run without it \u2014 they rely on ${runner}'s own sandbox`
|
|
48525
|
+
));
|
|
48526
|
+
}
|
|
48527
|
+
}
|
|
48528
|
+
const unattended = [
|
|
48529
|
+
...ws.config.pipelines.filter((p) => p.autopilot).map((p) => ({ label: `"${p.id}"`, pipeline: p, fatal: true }))
|
|
48530
|
+
];
|
|
48531
|
+
for (const r of ws.config.recipes.filter((r2) => r2.autopilot)) {
|
|
48532
|
+
try {
|
|
48533
|
+
unattended.push({ label: `recipe "${r.id}"`, pipeline: (0, import_core5.assemblePipeline)(ws.config, { recipeId: r.id }), fatal: false });
|
|
48534
|
+
} catch {
|
|
48535
|
+
}
|
|
48536
|
+
}
|
|
48537
|
+
for (const { label, pipeline, fatal } of unattended) {
|
|
48538
|
+
for (const s of pipeline.steps) {
|
|
48539
|
+
const norm = (0, import_core5.normalizeStep)(s);
|
|
48540
|
+
const runner = norm.auto_review ? norm.auto_review_runner : void 0;
|
|
48541
|
+
if (!runner) {
|
|
48542
|
+
continue;
|
|
48543
|
+
}
|
|
48544
|
+
const step = norm.name ?? norm.agent;
|
|
48545
|
+
checks.push((0, import_core5.hasEmptyCiChecks)(root, runner) ? (fatal ? fail : warn)(`${label} CI checks`, (0, import_core5.emptyCiChecksMessage)(runner, step)) : ok(`${label} auto-review on "${step}"`, runner));
|
|
48546
|
+
}
|
|
48547
|
+
}
|
|
48548
|
+
return checks;
|
|
48549
|
+
}
|
|
48550
|
+
function claudeAllowListFiles(root) {
|
|
48551
|
+
const files = [
|
|
48552
|
+
path4.join(root, ".claude", "settings.json"),
|
|
48553
|
+
path4.join(root, ".claude", "settings.local.json"),
|
|
48554
|
+
path4.join((0, import_core5.claudeConfigDir)(), "settings.json")
|
|
48555
|
+
];
|
|
48556
|
+
return files.filter((f) => {
|
|
48557
|
+
try {
|
|
48558
|
+
const allow = JSON.parse(fs3.readFileSync(f, "utf8"))?.permissions?.allow;
|
|
48559
|
+
return Array.isArray(allow) && allow.length > 0;
|
|
48560
|
+
} catch {
|
|
48561
|
+
return false;
|
|
48562
|
+
}
|
|
48563
|
+
}).map((f) => {
|
|
48564
|
+
const r = path4.relative(root, f);
|
|
48565
|
+
return r.startsWith("..") ? f.replace(os.homedir(), "~") : r.split(path4.sep).join("/");
|
|
48566
|
+
});
|
|
48567
|
+
}
|
|
47161
48568
|
function registerDoctor(program3) {
|
|
47162
48569
|
program3.command("doctor").description("Validate workspace, claude binary, env, skills, and run state files").option("--json", "Output all checks as JSON (exit 1 still signals failures)").action((opts, cmd) => {
|
|
47163
48570
|
const root = resolveWorkspaceRoot(cmd);
|
|
@@ -47266,6 +48673,7 @@ function registerDoctor(program3) {
|
|
|
47266
48673
|
if (ws) {
|
|
47267
48674
|
emitSection("Harness parity", parityChecks(root, ws));
|
|
47268
48675
|
emitSection("Providers", providerChecks(ws));
|
|
48676
|
+
emitSection("Unattended runs", autopilotChecks(root, ws));
|
|
47269
48677
|
}
|
|
47270
48678
|
const runChecks = [];
|
|
47271
48679
|
const runsDir = path4.join(root, ".aidlc", "runs");
|
|
@@ -47576,21 +48984,9 @@ function findPipelineForRun(root, state) {
|
|
|
47576
48984
|
return null;
|
|
47577
48985
|
}
|
|
47578
48986
|
}
|
|
47579
|
-
var AMBIGUOUS_STEP =
|
|
48987
|
+
var AMBIGUOUS_STEP = import_core7.AMBIGUOUS_STEP_INDEX;
|
|
47580
48988
|
function resolveStepIdx(state, step) {
|
|
47581
|
-
|
|
47582
|
-
if (!isNaN(asInt) && String(asInt) === step) {
|
|
47583
|
-
return asInt >= 0 && asInt < state.steps.length ? asInt : -1;
|
|
47584
|
-
}
|
|
47585
|
-
const byName = state.steps.findIndex((s) => s.name === step);
|
|
47586
|
-
if (byName >= 0) {
|
|
47587
|
-
return byName;
|
|
47588
|
-
}
|
|
47589
|
-
const byAgent = state.steps.map((s, i) => s.agent === step ? i : -1).filter((i) => i >= 0);
|
|
47590
|
-
if (byAgent.length > 1) {
|
|
47591
|
-
return AMBIGUOUS_STEP;
|
|
47592
|
-
}
|
|
47593
|
-
return byAgent.length === 1 ? byAgent[0] : -1;
|
|
48989
|
+
return (0, import_core7.findStepIndex)(state.steps, step);
|
|
47594
48990
|
}
|
|
47595
48991
|
function stepLabel(s) {
|
|
47596
48992
|
return s.name ?? s.agent;
|
|
@@ -48730,19 +50126,40 @@ function registerRun(program3) {
|
|
|
48730
50126
|
console.log(import_chalk10.default.green("\u{1F389} Run completed \u2014 all steps approved."));
|
|
48731
50127
|
}
|
|
48732
50128
|
});
|
|
48733
|
-
cmd.command("reject <runId>").description(
|
|
50129
|
+
cmd.command("reject <runId>").description(
|
|
50130
|
+
'Reject the current awaiting_review step.\n Without --to the work stays on this step (then `run rerun`). With --to it goes\n back to an earlier step: that step reopens with the reason as its feedback and\n the steps after it reset to pending. Mirrors the extension\'s "Send back to step N".'
|
|
50131
|
+
).requiredOption("--reason <text>", "Why the step was rejected").option("--to <step>", "Earlier step to send the work back to (0-based index, step name or agent id)").action((runId, opts, actionCmd) => {
|
|
48734
50132
|
const root = resolveWorkspaceRoot(actionCmd);
|
|
48735
50133
|
const state = requireRun(root, runId);
|
|
48736
50134
|
const pipeline = requirePipelineForRun(root, state);
|
|
50135
|
+
const idx = state.currentStepIdx;
|
|
50136
|
+
let targetIdx;
|
|
50137
|
+
if (opts.to !== void 0) {
|
|
50138
|
+
targetIdx = requireStepIdx(state, opts.to);
|
|
50139
|
+
if (targetIdx >= idx) {
|
|
50140
|
+
console.error(import_chalk10.default.red(
|
|
50141
|
+
`--to must name a step before the rejected one (${idx}:${state.steps[idx].agent}), got ${targetIdx}:${state.steps[targetIdx].agent}.`
|
|
50142
|
+
));
|
|
50143
|
+
process.exit(1);
|
|
50144
|
+
}
|
|
50145
|
+
}
|
|
48737
50146
|
let next;
|
|
48738
50147
|
try {
|
|
48739
|
-
next = (0, import_core13.rejectStep)({ state, reason: opts.reason, pipeline });
|
|
50148
|
+
next = (0, import_core13.rejectStep)({ state, reason: opts.reason, targetIdx, pipeline });
|
|
48740
50149
|
} catch (err) {
|
|
48741
50150
|
console.error(import_chalk10.default.red(err instanceof Error ? err.message : String(err)));
|
|
48742
50151
|
process.exit(1);
|
|
48743
50152
|
}
|
|
48744
50153
|
saveRunState(root, next, state);
|
|
48745
|
-
const step = state.steps[
|
|
50154
|
+
const step = state.steps[idx];
|
|
50155
|
+
if (targetIdx !== void 0) {
|
|
50156
|
+
const target = next.steps[targetIdx];
|
|
50157
|
+
console.log(import_chalk10.default.red("\u2718") + ` Rejected "${step.agent}" \u2014 sent back to "${target.agent}" (rev ${target.revision})`);
|
|
50158
|
+
console.log(import_chalk10.default.dim(` Reason: ${opts.reason}`));
|
|
50159
|
+
console.log(import_chalk10.default.dim(` When done: aidlc run mark-done ${runId}`));
|
|
50160
|
+
printRunSummary(next);
|
|
50161
|
+
return;
|
|
50162
|
+
}
|
|
48746
50163
|
console.log(import_chalk10.default.red("\u2718") + ` Rejected "${step.agent}"`);
|
|
48747
50164
|
console.log(import_chalk10.default.dim(` Reason: ${opts.reason}`));
|
|
48748
50165
|
console.log(import_chalk10.default.dim(` Rerun: aidlc run rerun ${runId} [--feedback "..."]`));
|
|
@@ -48845,7 +50262,7 @@ function registerRun(program3) {
|
|
|
48845
50262
|
console.log(JSON.stringify(state, null, 2));
|
|
48846
50263
|
});
|
|
48847
50264
|
cmd.command("exec <runId>").description(
|
|
48848
|
-
"Execute the current step by spawning the claude CLI, then auto-advance.\n Streams output live. Stops at human_review steps unless --auto-approve.\n Exit codes: 0 completed (or stopped at --until), 2 paused on a gate\n (awaiting review / rejected / budget), 1 error. --require-complete maps\n
|
|
50265
|
+
"Execute the current step by spawning the claude CLI, then auto-advance.\n Streams output live. Stops at human_review steps unless --auto-approve.\n Exit codes: 0 completed (or stopped at --until), 2 paused on a gate\n (awaiting review / rejected / sent back max_send_backs times / no code\n change after a send-back or a batch / max_batches / pause_between_batches /\n budget / stopped), 1 error (a step that ran\n past its timeout_minutes included). --require-complete maps any\n non-completed outcome to 1 for CI gating.\n Ctrl+C once: stop after the running step. Twice: stop it now."
|
|
48849
50266
|
).option("--until <step>", "Stop after this step completes (index or agent id)").option("--auto-approve", "Also auto-approve human_review steps without pausing").option("--require-complete", "Exit 1 unless the run reaches completed (for CI gating)").option("--json", "Suppress decorative output; print a final JSON summary to stdout (claude stream goes to stderr)").option("--message <text>", "Override the user message sent to claude (default: context pairs)").option("--dry-run", "Print the assembled prompt without spawning claude").option("--skill <id>", "On steps that offer alternative skills (default_skill), run this one").action(async (runId, opts, actionCmd) => {
|
|
48850
50267
|
const root = resolveWorkspaceRoot(actionCmd);
|
|
48851
50268
|
if (opts.json) {
|
|
@@ -48952,12 +50369,38 @@ async function execLoop(root, runId, opts) {
|
|
|
48952
50369
|
const initialState = requireRun(root, runId);
|
|
48953
50370
|
const untilIdx = opts.until !== void 0 ? requireStepIdx(initialState, opts.until) : -1;
|
|
48954
50371
|
const claudeOut = opts.json ? process.stderr : process.stdout;
|
|
48955
|
-
|
|
48956
|
-
|
|
48957
|
-
|
|
48958
|
-
|
|
48959
|
-
|
|
48960
|
-
);
|
|
50372
|
+
let cancelRequested = false;
|
|
50373
|
+
const stopNow = new AbortController();
|
|
50374
|
+
const onSigint = () => {
|
|
50375
|
+
if (!cancelRequested) {
|
|
50376
|
+
cancelRequested = true;
|
|
50377
|
+
console.error(import_chalk10.default.yellow("\n\u23F9 Stopping after the running step finishes. Press Ctrl+C again to stop it now."));
|
|
50378
|
+
} else if (!stopNow.signal.aborted) {
|
|
50379
|
+
console.error(import_chalk10.default.yellow("\n\u23F9 Stopping the running step now\u2026"));
|
|
50380
|
+
stopNow.abort();
|
|
50381
|
+
} else {
|
|
50382
|
+
process.exit(130);
|
|
50383
|
+
}
|
|
50384
|
+
};
|
|
50385
|
+
process.on("SIGINT", onSigint);
|
|
50386
|
+
try {
|
|
50387
|
+
return await (0, import_core13.runExecLoop)(
|
|
50388
|
+
root,
|
|
50389
|
+
runId,
|
|
50390
|
+
{
|
|
50391
|
+
untilIdx,
|
|
50392
|
+
autoApprove: opts.autoApprove,
|
|
50393
|
+
message: opts.message,
|
|
50394
|
+
dryRun: opts.dryRun,
|
|
50395
|
+
skill: opts.skill,
|
|
50396
|
+
shouldCancel: () => cancelRequested,
|
|
50397
|
+
signal: stopNow.signal
|
|
50398
|
+
},
|
|
50399
|
+
cliExecHooks(runId, claudeOut)
|
|
50400
|
+
);
|
|
50401
|
+
} finally {
|
|
50402
|
+
process.off("SIGINT", onSigint);
|
|
50403
|
+
}
|
|
48961
50404
|
}
|
|
48962
50405
|
async function driveAutoReview(root, runId, state) {
|
|
48963
50406
|
const pipeline = requirePipelineForRun(root, state);
|
|
@@ -49057,6 +50500,35 @@ ${reason}`)),
|
|
|
49057
50500
|
\u2718 Step "${e.agent}" was rejected.`));
|
|
49058
50501
|
info(import_chalk10.default.dim(` Rerun: aidlc run rerun ${e.runId} [--feedback "..."]`));
|
|
49059
50502
|
},
|
|
50503
|
+
onStepStopped: (e) => {
|
|
50504
|
+
info(import_chalk10.default.yellow(`
|
|
50505
|
+
\u23F9 Stopped "${e.agent}" mid-step (rev ${e.revision}). It is still awaiting work.`));
|
|
50506
|
+
info(import_chalk10.default.dim(" Anything it half-wrote is still in the working tree \u2014 check git status."));
|
|
50507
|
+
info(import_chalk10.default.dim(` Resume: aidlc run exec ${e.runId}`));
|
|
50508
|
+
},
|
|
50509
|
+
onCancelled: () => info(import_chalk10.default.yellow("\n\u23F9 Stopped after the step that was running.")),
|
|
50510
|
+
onStalled: (e) => {
|
|
50511
|
+
info(import_chalk10.default.yellow(`
|
|
50512
|
+
\u23F8 ${e.reason}`));
|
|
50513
|
+
info(import_chalk10.default.dim(` What it was asked, and what it did: aidlc run report ${e.runId}`));
|
|
50514
|
+
info(import_chalk10.default.dim(` Then make the change and: aidlc run mark-done ${e.runId} \u2014 or try again: aidlc run exec ${e.runId}`));
|
|
50515
|
+
},
|
|
50516
|
+
onBatchDone: (e) => {
|
|
50517
|
+
sep4();
|
|
50518
|
+
info(import_chalk10.default.cyan(`
|
|
50519
|
+
\u21BB Batch ${e.batch} of "${e.agent}" done \u2014 starting the next in a fresh session.`));
|
|
50520
|
+
if (typeof e.costUsd === "number") {
|
|
50521
|
+
info(import_chalk10.default.dim(` cost: $${e.costUsd.toFixed(4)}`));
|
|
50522
|
+
}
|
|
50523
|
+
},
|
|
50524
|
+
onBatchPause: (e) => {
|
|
50525
|
+
info(import_chalk10.default.cyan(`
|
|
50526
|
+
\u23F8 Batch ${e.batch} of "${e.agent}" done; pausing (pause_between_batches).`));
|
|
50527
|
+
if (e.report) {
|
|
50528
|
+
info(import_chalk10.default.dim(` Progress: ${e.report}`));
|
|
50529
|
+
}
|
|
50530
|
+
info(import_chalk10.default.dim(` Next batch: aidlc run exec ${e.runId}`));
|
|
50531
|
+
},
|
|
49060
50532
|
onStepSkipped: (e) => {
|
|
49061
50533
|
info(import_chalk10.default.yellow(`
|
|
49062
50534
|
\u2933 Step "${e.agent}" was rejected \u2014 carrying on.`) + import_chalk10.default.dim(` ${e.reason}`));
|
|
@@ -49067,6 +50539,9 @@ ${reason}`)),
|
|
|
49067
50539
|
onAutoReviewResult: (e) => {
|
|
49068
50540
|
if (e.decision === "pass") {
|
|
49069
50541
|
info(import_chalk10.default.green("\u2714 Auto-review passed") + import_chalk10.default.dim(` \u2014 ${e.reason}`));
|
|
50542
|
+
} else if (e.sentBackTo) {
|
|
50543
|
+
const to = e.sentBackTo;
|
|
50544
|
+
info(import_chalk10.default.yellow(`\u21A9 Auto-review rejected \u2014 sent back to "${to.agent}" (rev ${to.revision}, send-back ${to.count} of ${to.max})`) + import_chalk10.default.dim(` \u2014 ${e.reason}`));
|
|
49070
50545
|
} else {
|
|
49071
50546
|
info(import_chalk10.default.red("\u2718 Auto-review rejected") + import_chalk10.default.dim(` \u2014 ${e.reason}`));
|
|
49072
50547
|
info(import_chalk10.default.dim(` Fix the issue, then: aidlc run rerun ${e.runId} [--feedback "..."]`));
|