@afokapu/atdd-flow 0.3.31 → 0.3.33
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/package.json +1 -1
- package/src/seats.ts +30 -3
package/package.json
CHANGED
package/src/seats.ts
CHANGED
|
@@ -218,10 +218,37 @@ export function resolveModelCommand(config: Desk, candidate: ModelCandidate) {
|
|
|
218
218
|
return { agent: resolveExecutable(config, candidate.executable), args: candidate.args ?? [] };
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
async function
|
|
221
|
+
async function isExactNamedCoordinator(root: string, record: Seat, address: string) {
|
|
222
|
+
if (record.address !== address || record.role !== "coordinator") return false;
|
|
223
|
+
const config = await project(root, record.project);
|
|
224
|
+
const role = config.roles.coordinator;
|
|
225
|
+
const suffix = `@${config.project}`;
|
|
226
|
+
const local = record.address.endsWith(suffix) ? record.address.slice(0, -suffix.length) : "";
|
|
227
|
+
const match = local.match(/^coordinator\.([a-z0-9_-]+)$/);
|
|
228
|
+
if (!config.repository || role?.address !== "coordinator.{name}@{project}" || role.branch !== "integration/{name}" || !role.worktree || !match) return false;
|
|
229
|
+
const stream = match[1]!;
|
|
230
|
+
const expectedWorktree = resolve(fill(role.worktree, {
|
|
231
|
+
project: config.project, name: stream, worktree_root: config.worktree_root ?? "", repository: config.repository,
|
|
232
|
+
}));
|
|
233
|
+
if (record.branch !== `integration/${stream}` || resolve(record.worktree) !== expectedWorktree || expectedWorktree === resolve(config.repository)) return false;
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
const peers = await Promise.all((await readdir(paths(root).seats(config.project))).map(async (name) => {
|
|
237
|
+
try { return await readYaml<Seat>(join(paths(root).seats(config.project), name, "seat.yaml")); }
|
|
238
|
+
catch { return undefined; }
|
|
239
|
+
}));
|
|
240
|
+
return !peers.some((peer) => peer && peer.address !== record.address && peer.role === "coordinator"
|
|
241
|
+
&& (peer.branch === record.branch || resolve(peer.worktree) === expectedWorktree));
|
|
242
|
+
} catch { return false; }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function launchEligibleTasks(root: string, record: Seat, address: string) {
|
|
246
|
+
const coordinator = await isExactNamedCoordinator(root, record, address);
|
|
222
247
|
const tasks = await seatTasks(root, record.project, record.address);
|
|
223
248
|
const eligible = await Promise.all(tasks.map(async (entry) => {
|
|
224
|
-
|
|
249
|
+
const accountable = record.role === "driver" ? entry.task.assignee === record.address
|
|
250
|
+
: coordinator && entry.task.coordinator === record.address;
|
|
251
|
+
if (!accountable || entry.task.blocker) return undefined;
|
|
225
252
|
if (entry.task.status === "in_progress") return entry;
|
|
226
253
|
if (entry.task.status !== "todo") return undefined;
|
|
227
254
|
const dependencies = await Promise.all((entry.task.depends_on ?? []).map(async (id) => {
|
|
@@ -357,7 +384,7 @@ export async function launchPiRuntime(root: string, address: string, args: strin
|
|
|
357
384
|
if (resume && ((requestedPane && requestedPane !== existingPane) || herdrSession !== existingSession)) {
|
|
358
385
|
throw new Error("Resume cannot relocate a Pi session across a Herdr session or pane; use explicit exact-session adoption.");
|
|
359
386
|
}
|
|
360
|
-
const active = await launchEligibleTasks(root, record);
|
|
387
|
+
const active = await launchEligibleTasks(root, record, resolved);
|
|
361
388
|
if (!active.length) throw new Error(`${resolved} has no launch-eligible task; refusing runtime launch.`);
|
|
362
389
|
const selection = await chooseLaunchModel(root, config, record, required(await modelPortfolio(root), "models.yaml for Pi runtime launch"), dependencies.select);
|
|
363
390
|
const model = resolveModelCommand(config, selection.candidate);
|