@amistio/cli 0.1.54 → 0.1.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +966 -684
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { createHash as createHash9, randomUUID as randomUUID3 } from "node:crypto";
5
- import { writeFile as writeFile12 } from "node:fs/promises";
6
- import os9 from "node:os";
7
- import path19 from "node:path";
4
+ import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
5
+ import { writeFile as writeFile13 } from "node:fs/promises";
6
+ import os10 from "node:os";
7
+ import path20 from "node:path";
8
8
  import { Command } from "commander";
9
9
 
10
10
  // ../shared/src/schemas.ts
@@ -3302,8 +3302,8 @@ var toolSessionMutationSchema = z3.object({
3302
3302
  });
3303
3303
  function resolveApiUrl(apiUrl, urlPath) {
3304
3304
  const base = apiUrl.endsWith("/") ? apiUrl.slice(0, -1) : apiUrl;
3305
- const path20 = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
3306
- return new URL(`${base}${path20}`);
3305
+ const path21 = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
3306
+ return new URL(`${base}${path21}`);
3307
3307
  }
3308
3308
 
3309
3309
  // src/orchestrator.ts
@@ -3622,6 +3622,7 @@ function createDurableResultFinalizationEntry(input, now = (/* @__PURE__ */ new
3622
3622
  });
3623
3623
  }
3624
3624
  function createImplementationFinalizationEntry(input, now = (/* @__PURE__ */ new Date()).toISOString()) {
3625
+ const telemetry = normalizeImplementationFinalizationTelemetry(input.telemetry);
3625
3626
  return implementationFinalizationEntrySchema.parse({
3626
3627
  schemaVersion: 1,
3627
3628
  kind: "implementationFinalization",
@@ -3635,7 +3636,7 @@ function createImplementationFinalizationEntry(input, now = (/* @__PURE__ */ new
3635
3636
  attempt: input.attempt,
3636
3637
  idempotencyKey: input.idempotencyKey,
3637
3638
  finalStatus: input.finalStatus,
3638
- telemetry: input.telemetry,
3639
+ telemetry,
3639
3640
  retryCount: 0,
3640
3641
  createdAt: now,
3641
3642
  updatedAt: now
@@ -3830,6 +3831,18 @@ function implementationFinalizationEntryKey(entry) {
3830
3831
  const hash = createHash2("sha256").update([entry.accountId, entry.projectId, entry.repositoryLinkId, entry.runnerId, entry.workItemId, String(entry.attempt), entry.idempotencyKey].join("\0")).digest("hex").slice(0, 32);
3831
3832
  return `implementation-finalization-${hash}`;
3832
3833
  }
3834
+ function normalizeImplementationFinalizationTelemetry(telemetry) {
3835
+ const { repositoryLockId, ...rest } = telemetry;
3836
+ const boundedRepositoryLockId = boundTelemetryIdentifier(repositoryLockId, 200);
3837
+ return { ...rest, ...boundedRepositoryLockId ? { repositoryLockId: boundedRepositoryLockId } : {} };
3838
+ }
3839
+ function boundTelemetryIdentifier(value, maxLength) {
3840
+ const trimmed = value?.trim();
3841
+ if (!trimmed) return void 0;
3842
+ if (trimmed.length <= maxLength) return trimmed;
3843
+ const hash = createHash2("sha256").update(trimmed).digest("hex").slice(0, 32);
3844
+ return `sha256:${hash}:length:${trimmed.length}`;
3845
+ }
3833
3846
  function truncateLocalError(error) {
3834
3847
  const trimmed = error.trim();
3835
3848
  return trimmed.length > 600 ? `${trimmed.slice(0, 600)}...` : trimmed;
@@ -6245,6 +6258,191 @@ async function checkRunnerWatchGitPreflight(options) {
6245
6258
  return { status: "blocked", exitCode: 1, message, readiness: readiness2 };
6246
6259
  }
6247
6260
 
6261
+ // src/runner-active-claims.ts
6262
+ import { randomUUID as randomUUID3 } from "node:crypto";
6263
+ import { chmod as chmod3, mkdir as mkdir9, readFile as readFile9, rm as rm3, stat as stat4, writeFile as writeFile9 } from "node:fs/promises";
6264
+ import os6 from "node:os";
6265
+ import path11 from "node:path";
6266
+ var activeClaimLockStaleMs = 3e4;
6267
+ var activeClaimLockRetryMs = 20;
6268
+ var activeClaimLockAttempts = 50;
6269
+ var maxStoredActiveClaims = 100;
6270
+ var LocalRunnerActiveClaimStore = class {
6271
+ constructor(filePath = defaultActiveClaimStorePath()) {
6272
+ this.filePath = filePath;
6273
+ }
6274
+ filePath;
6275
+ operation = Promise.resolve();
6276
+ async reserve(input) {
6277
+ return this.withLockedStore(async () => {
6278
+ const now = /* @__PURE__ */ new Date();
6279
+ const data = normalizeActiveClaimFile(await this.read());
6280
+ data.activeClaims = pruneExpiredClaims(data.activeClaims, now.getTime());
6281
+ const conflict = data.activeClaims.find((record2) => activeClaimConflicts(record2, input));
6282
+ if (conflict) {
6283
+ return { status: "blocked", reason: activeClaimConflictReason(conflict, input), existing: conflict };
6284
+ }
6285
+ const record = {
6286
+ ...input,
6287
+ reservationId: `runner_claim_${randomUUID3()}`,
6288
+ processId: process.pid,
6289
+ reservedAt: now.toISOString(),
6290
+ updatedAt: now.toISOString()
6291
+ };
6292
+ data.activeClaims = [...data.activeClaims, record].slice(-maxStoredActiveClaims);
6293
+ await this.write(data);
6294
+ return { status: "reserved", record };
6295
+ });
6296
+ }
6297
+ async release(reservationId) {
6298
+ await this.withLockedStore(async () => {
6299
+ const data = normalizeActiveClaimFile(await this.read());
6300
+ const activeClaims = data.activeClaims.filter((record) => record.reservationId !== reservationId);
6301
+ if (activeClaims.length === data.activeClaims.length) {
6302
+ return;
6303
+ }
6304
+ await this.write({ activeClaims });
6305
+ });
6306
+ }
6307
+ async listActive(now = Date.now()) {
6308
+ return this.withLockedStore(async () => {
6309
+ const data = normalizeActiveClaimFile(await this.read());
6310
+ const activeClaims = pruneExpiredClaims(data.activeClaims, now);
6311
+ if (activeClaims.length !== data.activeClaims.length) {
6312
+ await this.write({ activeClaims });
6313
+ }
6314
+ return activeClaims;
6315
+ });
6316
+ }
6317
+ async withLockedStore(operation) {
6318
+ return this.withProcessLock(async () => {
6319
+ const release = await this.acquireFileLock();
6320
+ try {
6321
+ return await operation();
6322
+ } finally {
6323
+ await release();
6324
+ }
6325
+ });
6326
+ }
6327
+ async withProcessLock(operation) {
6328
+ const previous = this.operation;
6329
+ let releaseProcessLock = () => void 0;
6330
+ this.operation = new Promise((resolve) => {
6331
+ releaseProcessLock = resolve;
6332
+ });
6333
+ await previous.catch(() => void 0);
6334
+ try {
6335
+ return await operation();
6336
+ } finally {
6337
+ releaseProcessLock();
6338
+ }
6339
+ }
6340
+ async acquireFileLock() {
6341
+ const lockPath = `${this.filePath}.lock`;
6342
+ await mkdir9(path11.dirname(this.filePath), { recursive: true });
6343
+ for (let attempt = 0; attempt < activeClaimLockAttempts; attempt += 1) {
6344
+ try {
6345
+ await mkdir9(lockPath);
6346
+ return async () => {
6347
+ await rm3(lockPath, { recursive: true, force: true });
6348
+ };
6349
+ } catch (error) {
6350
+ if (!isNodeErrorCode(error, "EEXIST")) {
6351
+ throw error;
6352
+ }
6353
+ await removeStaleLock(lockPath, Date.now());
6354
+ await delay(activeClaimLockRetryMs);
6355
+ }
6356
+ }
6357
+ throw new Error("Could not acquire local runner active-claim lock.");
6358
+ }
6359
+ async read() {
6360
+ try {
6361
+ return JSON.parse(await readFile9(this.filePath, "utf8"));
6362
+ } catch {
6363
+ return { activeClaims: [] };
6364
+ }
6365
+ }
6366
+ async write(data) {
6367
+ await mkdir9(path11.dirname(this.filePath), { recursive: true });
6368
+ await writeFile9(this.filePath, JSON.stringify(data, null, 2), { encoding: "utf8", mode: 384 });
6369
+ await chmod3(this.filePath, 384);
6370
+ }
6371
+ };
6372
+ var defaultRunnerActiveClaimStore = new LocalRunnerActiveClaimStore();
6373
+ function activeClaimConflictMessage(result) {
6374
+ if (result.reason === "sameLane") {
6375
+ return `Runner lane ${result.existing.claimLaneId} is already working on ${result.existing.workItemId}.`;
6376
+ }
6377
+ if (result.reason === "sameWorktree") {
6378
+ return `Runner worktree ${result.existing.worktreeKey} is already reserved by lane ${result.existing.claimLaneId}.`;
6379
+ }
6380
+ return `Runner work item ${result.existing.workItemId} is already reserved by lane ${result.existing.claimLaneId}.`;
6381
+ }
6382
+ function defaultActiveClaimStorePath() {
6383
+ return path11.join(os6.homedir(), ".config", "amistio", "active-runner-claims.json");
6384
+ }
6385
+ function normalizeActiveClaimFile(value) {
6386
+ if (!value || typeof value !== "object" || !("activeClaims" in value)) {
6387
+ return { activeClaims: [] };
6388
+ }
6389
+ const activeClaims = value.activeClaims;
6390
+ if (!Array.isArray(activeClaims)) {
6391
+ return { activeClaims: [] };
6392
+ }
6393
+ return {
6394
+ activeClaims: activeClaims.filter(isRunnerActiveClaimRecord)
6395
+ };
6396
+ }
6397
+ function isRunnerActiveClaimRecord(value) {
6398
+ if (!value || typeof value !== "object") return false;
6399
+ const record = value;
6400
+ return typeof record.reservationId === "string" && typeof record.accountId === "string" && typeof record.projectId === "string" && typeof record.repositoryLinkId === "string" && typeof record.runnerId === "string" && typeof record.claimLaneId === "string" && typeof record.workItemId === "string" && typeof record.attempt === "number" && typeof record.expiresAt === "string" && typeof record.reservedAt === "string" && typeof record.updatedAt === "string" && typeof record.processId === "number";
6401
+ }
6402
+ function pruneExpiredClaims(records, now) {
6403
+ return records.filter((record) => {
6404
+ const expiresAt = Date.parse(record.expiresAt);
6405
+ return Number.isFinite(expiresAt) && expiresAt > now;
6406
+ });
6407
+ }
6408
+ function activeClaimConflicts(record, input) {
6409
+ if (record.accountId !== input.accountId || record.projectId !== input.projectId || record.repositoryLinkId !== input.repositoryLinkId) {
6410
+ return false;
6411
+ }
6412
+ if (record.runnerId === input.runnerId && record.claimLaneId === input.claimLaneId) {
6413
+ return true;
6414
+ }
6415
+ if (record.workItemId === input.workItemId) {
6416
+ return true;
6417
+ }
6418
+ return Boolean(record.worktreeKey && input.worktreeKey && record.worktreeKey === input.worktreeKey);
6419
+ }
6420
+ function activeClaimConflictReason(record, input) {
6421
+ if (record.runnerId === input.runnerId && record.claimLaneId === input.claimLaneId) {
6422
+ return "sameLane";
6423
+ }
6424
+ if (record.workItemId === input.workItemId) {
6425
+ return "sameWorkItem";
6426
+ }
6427
+ return "sameWorktree";
6428
+ }
6429
+ async function removeStaleLock(lockPath, now) {
6430
+ try {
6431
+ const lockStat = await stat4(lockPath);
6432
+ if (now - lockStat.mtimeMs > activeClaimLockStaleMs) {
6433
+ await rm3(lockPath, { recursive: true, force: true });
6434
+ }
6435
+ } catch {
6436
+ return;
6437
+ }
6438
+ }
6439
+ function isNodeErrorCode(error, code) {
6440
+ return typeof error === "object" && error !== null && error.code === code;
6441
+ }
6442
+ function delay(ms) {
6443
+ return new Promise((resolve) => setTimeout(resolve, ms));
6444
+ }
6445
+
6248
6446
  // src/runner-patch-drift.ts
6249
6447
  var patchDriftPatterns = [
6250
6448
  { signature: "applyPatchVerificationFailed", pattern: /apply_patch\s+verification\s+failed/i },
@@ -6307,9 +6505,9 @@ ${options.detail}`);
6307
6505
  // src/runner-service.ts
6308
6506
  import { spawn as spawn3 } from "node:child_process";
6309
6507
  import { createHash as createHash5 } from "node:crypto";
6310
- import { mkdir as mkdir9, readFile as readFile9, rm as rm3, writeFile as writeFile9 } from "node:fs/promises";
6311
- import os6 from "node:os";
6312
- import path11 from "node:path";
6508
+ import { mkdir as mkdir10, readFile as readFile10, rm as rm4, writeFile as writeFile10 } from "node:fs/promises";
6509
+ import os7 from "node:os";
6510
+ import path12 from "node:path";
6313
6511
  function detectRunnerServicePlatform(platform = process.platform) {
6314
6512
  if (platform === "darwin") return "launchd";
6315
6513
  if (platform === "linux") return "systemd";
@@ -6320,19 +6518,19 @@ function createRunnerServiceDescriptor(input) {
6320
6518
  if (platform === "unsupported") {
6321
6519
  throw new Error("Startup services are supported for user-level launchd on macOS and systemd user services on Linux.");
6322
6520
  }
6323
- const homeDir = input.homeDir ?? os6.homedir();
6521
+ const homeDir = input.homeDir ?? os7.homedir();
6324
6522
  const serviceName = runnerServiceName(input);
6325
6523
  const serviceFilePath = runnerServiceFilePath(platform, serviceName, homeDir);
6326
6524
  const now = (/* @__PURE__ */ new Date()).toISOString();
6327
6525
  const command = [input.executablePath ?? process.execPath, input.scriptPath ?? process.argv[1], ...input.args];
6328
- const logPath = path11.join(input.metadataDir ?? defaultRunnerMetadataDir(), `${runnerServiceKey(input)}.service.log`);
6526
+ const logPath = path12.join(input.metadataDir ?? defaultRunnerMetadataDir(), `${runnerServiceKey(input)}.service.log`);
6329
6527
  const metadata = {
6330
6528
  schemaVersion: 1,
6331
6529
  accountId: input.accountId,
6332
6530
  projectId: input.projectId,
6333
6531
  repositoryLinkId: input.repositoryLinkId,
6334
6532
  runnerId: input.runnerId,
6335
- rootDir: path11.resolve(input.rootDir),
6533
+ rootDir: path12.resolve(input.rootDir),
6336
6534
  apiUrl: input.apiUrl,
6337
6535
  serviceName,
6338
6536
  serviceFilePath,
@@ -6349,9 +6547,9 @@ function createRunnerServiceDescriptor(input) {
6349
6547
  }
6350
6548
  async function installRunnerService(input, options = {}) {
6351
6549
  const descriptor = createRunnerServiceDescriptor(input);
6352
- await mkdir9(path11.dirname(descriptor.metadata.serviceFilePath), { recursive: true });
6353
- await mkdir9(input.metadataDir ?? defaultRunnerMetadataDir(), { recursive: true });
6354
- await writeFile9(descriptor.metadata.serviceFilePath, descriptor.content, { encoding: "utf8", mode: 384 });
6550
+ await mkdir10(path12.dirname(descriptor.metadata.serviceFilePath), { recursive: true });
6551
+ await mkdir10(input.metadataDir ?? defaultRunnerMetadataDir(), { recursive: true });
6552
+ await writeFile10(descriptor.metadata.serviceFilePath, descriptor.content, { encoding: "utf8", mode: 384 });
6355
6553
  await writeRunnerServiceMetadata(descriptor.metadata, input.metadataDir);
6356
6554
  if (options.activate !== false) {
6357
6555
  const activation = await activateRunnerService(descriptor.metadata);
@@ -6367,13 +6565,13 @@ async function removeRunnerService(input) {
6367
6565
  return void 0;
6368
6566
  }
6369
6567
  await deactivateRunnerService(metadata).catch(() => void 0);
6370
- await rm3(metadata.serviceFilePath, { force: true });
6371
- await rm3(runnerServiceMetadataPath(input, input.metadataDir ?? defaultRunnerMetadataDir()), { force: true });
6568
+ await rm4(metadata.serviceFilePath, { force: true });
6569
+ await rm4(runnerServiceMetadataPath(input, input.metadataDir ?? defaultRunnerMetadataDir()), { force: true });
6372
6570
  return { ...metadata, status: "removed", updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
6373
6571
  }
6374
6572
  async function readRunnerServiceMetadata(input, metadataDir = defaultRunnerMetadataDir()) {
6375
6573
  try {
6376
- const parsed = JSON.parse(await readFile9(runnerServiceMetadataPath(input, metadataDir), "utf8"));
6574
+ const parsed = JSON.parse(await readFile10(runnerServiceMetadataPath(input, metadataDir), "utf8"));
6377
6575
  if (parsed.schemaVersion !== 1 || !parsed.serviceName || !parsed.serviceFilePath) {
6378
6576
  return void 0;
6379
6577
  }
@@ -6383,8 +6581,8 @@ async function readRunnerServiceMetadata(input, metadataDir = defaultRunnerMetad
6383
6581
  }
6384
6582
  }
6385
6583
  async function writeRunnerServiceMetadata(metadata, metadataDir = defaultRunnerMetadataDir()) {
6386
- await mkdir9(metadataDir, { recursive: true });
6387
- await writeFile9(runnerServiceMetadataPath(metadata, metadataDir), JSON.stringify(metadata, null, 2), { encoding: "utf8", mode: 384 });
6584
+ await mkdir10(metadataDir, { recursive: true });
6585
+ await writeFile10(runnerServiceMetadataPath(metadata, metadataDir), JSON.stringify(metadata, null, 2), { encoding: "utf8", mode: 384 });
6388
6586
  }
6389
6587
  async function runnerServiceRuntimeStatus(metadata) {
6390
6588
  if (metadata.platform === "launchd") {
@@ -6467,12 +6665,12 @@ WantedBy=default.target
6467
6665
  }
6468
6666
  function runnerServiceFilePath(platform, serviceName, homeDir) {
6469
6667
  if (platform === "launchd") {
6470
- return path11.join(homeDir, "Library", "LaunchAgents", `${serviceName}.plist`);
6668
+ return path12.join(homeDir, "Library", "LaunchAgents", `${serviceName}.plist`);
6471
6669
  }
6472
- return path11.join(homeDir, ".config", "systemd", "user", `${serviceName}.service`);
6670
+ return path12.join(homeDir, ".config", "systemd", "user", `${serviceName}.service`);
6473
6671
  }
6474
6672
  function runnerServiceMetadataPath(input, metadataDir) {
6475
- return path11.join(metadataDir, `${runnerServiceKey(input)}.service.json`);
6673
+ return path12.join(metadataDir, `${runnerServiceKey(input)}.service.json`);
6476
6674
  }
6477
6675
  function runnerServiceName(input) {
6478
6676
  return `com.amistio.runner.${runnerServiceKey(input).slice(0, 20)}`;
@@ -6807,8 +7005,8 @@ function createSmokeSession({ now, status, lastActivityAt }) {
6807
7005
  // src/sync.ts
6808
7006
  import { execFile as execFile3 } from "node:child_process";
6809
7007
  import { createHash as createHash6 } from "node:crypto";
6810
- import { mkdir as mkdir10, readdir as readdir5, readFile as readFile10, stat as stat4, writeFile as writeFile10 } from "node:fs/promises";
6811
- import path12 from "node:path";
7008
+ import { mkdir as mkdir11, readdir as readdir5, readFile as readFile11, stat as stat5, writeFile as writeFile11 } from "node:fs/promises";
7009
+ import path13 from "node:path";
6812
7010
  import { promisify as promisify3 } from "node:util";
6813
7011
  var execFileAsync3 = promisify3(execFile3);
6814
7012
  var legacySyncRoots = ["architecture", "context", "decisions", "features", "memory", "plans", "prompts", "workflows"];
@@ -6904,7 +7102,7 @@ async function readLocalSyncedDocuments(rootDir) {
6904
7102
  const documentFiles = await findBrainDocumentFiles(rootDir);
6905
7103
  const documents = [];
6906
7104
  for (const fullPath of documentFiles) {
6907
- const raw = await readFile10(fullPath, "utf8");
7105
+ const raw = await readFile11(fullPath, "utf8");
6908
7106
  const repoPath = toRepoPath(rootDir, fullPath);
6909
7107
  const parsed = parseSyncedDocument(raw, repoPath);
6910
7108
  if (!parsed) {
@@ -6954,8 +7152,8 @@ async function materializeBrainDocuments(rootDir, documents, options = {}) {
6954
7152
  result.skipped.push(document.repoPath);
6955
7153
  continue;
6956
7154
  }
6957
- await mkdir10(path12.dirname(fullPath), { recursive: true });
6958
- await writeFile10(fullPath, createSyncedDocumentContent(document), "utf8");
7155
+ await mkdir11(path13.dirname(fullPath), { recursive: true });
7156
+ await writeFile11(fullPath, createSyncedDocumentContent(document), "utf8");
6959
7157
  result.written.push(document.repoPath);
6960
7158
  }
6961
7159
  return result;
@@ -7084,7 +7282,7 @@ function parseSyncedHtml(content) {
7084
7282
  }
7085
7283
  async function readExistingSyncedDocument(fullPath) {
7086
7284
  try {
7087
- const raw = await readFile10(fullPath, "utf8");
7285
+ const raw = await readFile11(fullPath, "utf8");
7088
7286
  const parsed = parseSyncedDocument(raw, fullPath);
7089
7287
  if (!parsed) {
7090
7288
  return { exists: true };
@@ -7109,7 +7307,7 @@ async function readExistingSyncedDocument(fullPath) {
7109
7307
  async function findBrainDocumentFiles(rootDir) {
7110
7308
  const files = [];
7111
7309
  for (const syncRoot of [...syncRoots, htmlSyncRoot]) {
7112
- const fullRoot = path12.join(rootDir, syncRoot);
7310
+ const fullRoot = path13.join(rootDir, syncRoot);
7113
7311
  if (!await exists2(fullRoot)) {
7114
7312
  continue;
7115
7313
  }
@@ -7119,7 +7317,7 @@ async function findBrainDocumentFiles(rootDir) {
7119
7317
  }
7120
7318
  async function walkBrainDocumentFiles(directory, files) {
7121
7319
  for (const entry of await readdir5(directory, { withFileTypes: true })) {
7122
- const fullPath = path12.join(directory, entry.name);
7320
+ const fullPath = path13.join(directory, entry.name);
7123
7321
  if (entry.isDirectory()) {
7124
7322
  await walkBrainDocumentFiles(fullPath, files);
7125
7323
  } else if (entry.isFile() && /\.(md|mdx|html?)$/i.test(entry.name)) {
@@ -7128,23 +7326,23 @@ async function walkBrainDocumentFiles(directory, files) {
7128
7326
  }
7129
7327
  }
7130
7328
  function safeRepoPath(rootDir, repoPath) {
7131
- if (path12.isAbsolute(repoPath)) {
7329
+ if (path13.isAbsolute(repoPath)) {
7132
7330
  throw new Error(`Refusing to use absolute repo path: ${repoPath}`);
7133
7331
  }
7134
- const normalized = path12.normalize(repoPath);
7135
- if (normalized === ".." || normalized.startsWith(`..${path12.sep}`)) {
7332
+ const normalized = path13.normalize(repoPath);
7333
+ if (normalized === ".." || normalized.startsWith(`..${path13.sep}`)) {
7136
7334
  throw new Error(`Refusing to use path outside the repository: ${repoPath}`);
7137
7335
  }
7138
- const root = path12.resolve(rootDir);
7139
- const fullPath = path12.resolve(root, normalized);
7140
- if (!fullPath.startsWith(`${root}${path12.sep}`)) {
7336
+ const root = path13.resolve(rootDir);
7337
+ const fullPath = path13.resolve(root, normalized);
7338
+ if (!fullPath.startsWith(`${root}${path13.sep}`)) {
7141
7339
  throw new Error(`Refusing to use path outside the repository: ${repoPath}`);
7142
7340
  }
7143
7341
  return fullPath;
7144
7342
  }
7145
7343
  function isControlPlanePath(repoPath) {
7146
- const normalized = path12.normalize(repoPath);
7147
- return syncRoots.some((syncRoot) => normalized === syncRoot || normalized.startsWith(`${syncRoot}${path12.sep}`)) || normalized === htmlSyncRoot || normalized.startsWith(`${htmlSyncRoot}${path12.sep}`);
7344
+ const normalized = path13.normalize(repoPath);
7345
+ return syncRoots.some((syncRoot) => normalized === syncRoot || normalized.startsWith(`${syncRoot}${path13.sep}`)) || normalized === htmlSyncRoot || normalized.startsWith(`${htmlSyncRoot}${path13.sep}`);
7148
7346
  }
7149
7347
  function canonicalControlPlaneRepoPath(repoPath) {
7150
7348
  const normalized = repoPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -7155,16 +7353,16 @@ function canonicalControlPlaneRepoPath(repoPath) {
7155
7353
  return normalized;
7156
7354
  }
7157
7355
  function toRepoPath(rootDir, fullPath) {
7158
- return path12.relative(rootDir, fullPath).split(path12.sep).join("/");
7356
+ return path13.relative(rootDir, fullPath).split(path13.sep).join("/");
7159
7357
  }
7160
7358
  function inferTitle(content, repoPath) {
7161
7359
  const heading = content.split("\n").find((line) => line.startsWith("# "))?.replace(/^#\s+/, "").trim();
7162
7360
  if (heading) return heading;
7163
7361
  const htmlHeading = content.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1]?.replace(/<[^>]+>/g, "").trim();
7164
- return htmlHeading || path12.basename(repoPath, path12.extname(repoPath));
7362
+ return htmlHeading || path13.basename(repoPath, path13.extname(repoPath));
7165
7363
  }
7166
7364
  async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingDocuments, options) {
7167
- const root = path12.resolve(rootDir);
7365
+ const root = path13.resolve(rootDir);
7168
7366
  const maxBytes = (options.maxFileKb ?? defaultAutoSyncMaxFileKb) * 1024;
7169
7367
  const syncedAt = options.syncedAt ?? (/* @__PURE__ */ new Date()).toISOString();
7170
7368
  const existingById = new Map(existingDocuments.map((document) => [document.documentId, document]));
@@ -7180,7 +7378,7 @@ async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingD
7180
7378
  continue;
7181
7379
  }
7182
7380
  const fullPath = safeRepoPath(root, normalizedRepoPath);
7183
- const fileStat = await stat4(fullPath).catch(() => void 0);
7381
+ const fileStat = await stat5(fullPath).catch(() => void 0);
7184
7382
  if (!fileStat?.isFile()) {
7185
7383
  skipped.push({ repoPath: normalizedRepoPath, reason: "unreadable" });
7186
7384
  continue;
@@ -7189,7 +7387,7 @@ async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingD
7189
7387
  skipped.push({ repoPath: normalizedRepoPath, reason: "tooLarge" });
7190
7388
  continue;
7191
7389
  }
7192
- const content = await readFile10(fullPath, "utf8").catch(() => void 0);
7390
+ const content = await readFile11(fullPath, "utf8").catch(() => void 0);
7193
7391
  if (content === void 0) {
7194
7392
  skipped.push({ repoPath: normalizedRepoPath, reason: "unreadable" });
7195
7393
  continue;
@@ -7254,7 +7452,7 @@ async function listAutoSyncCandidatePaths(rootDir) {
7254
7452
  }
7255
7453
  const files = [];
7256
7454
  for (const syncRoot of [...syncRoots, htmlSyncRoot, ...legacySyncRoots]) {
7257
- const fullRoot = path12.join(rootDir, syncRoot);
7455
+ const fullRoot = path13.join(rootDir, syncRoot);
7258
7456
  if (await exists2(fullRoot)) {
7259
7457
  await walkAutoSyncFiles(rootDir, fullRoot, files);
7260
7458
  }
@@ -7263,8 +7461,8 @@ async function listAutoSyncCandidatePaths(rootDir) {
7263
7461
  }
7264
7462
  async function walkAutoSyncFiles(rootDir, directory, files) {
7265
7463
  for (const entry of await readdir5(directory, { withFileTypes: true }).catch(() => [])) {
7266
- const fullPath = path12.join(directory, entry.name);
7267
- const repoPath = normalizeRepoPath3(path12.relative(rootDir, fullPath));
7464
+ const fullPath = path13.join(directory, entry.name);
7465
+ const repoPath = normalizeRepoPath3(path13.relative(rootDir, fullPath));
7268
7466
  if (entry.isDirectory()) {
7269
7467
  if (!autoSyncExcludedDirectoryNames.has(entry.name)) {
7270
7468
  await walkAutoSyncFiles(rootDir, fullPath, files);
@@ -7318,7 +7516,7 @@ function parseFrontmatterFromSyncedDocument(frontmatter) {
7318
7516
  }
7319
7517
  async function exists2(filePath) {
7320
7518
  try {
7321
- await stat4(filePath);
7519
+ await stat5(filePath);
7322
7520
  return true;
7323
7521
  } catch {
7324
7522
  return false;
@@ -7326,9 +7524,9 @@ async function exists2(filePath) {
7326
7524
  }
7327
7525
 
7328
7526
  // src/tool-session-store.ts
7329
- import { mkdir as mkdir11, readFile as readFile11, writeFile as writeFile11 } from "node:fs/promises";
7330
- import os7 from "node:os";
7331
- import path13 from "node:path";
7527
+ import { mkdir as mkdir12, readFile as readFile12, writeFile as writeFile12 } from "node:fs/promises";
7528
+ import os8 from "node:os";
7529
+ import path14 from "node:path";
7332
7530
  var LocalToolSessionStore = class {
7333
7531
  constructor(filePath = defaultSessionStorePath()) {
7334
7532
  this.filePath = filePath;
@@ -7342,12 +7540,12 @@ var LocalToolSessionStore = class {
7342
7540
  async setProviderSessionId(toolSessionId, toolName, providerSessionId) {
7343
7541
  const data = await this.read();
7344
7542
  data[toolSessionId] = { toolName, providerSessionId, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
7345
- await mkdir11(path13.dirname(this.filePath), { recursive: true });
7346
- await writeFile11(this.filePath, JSON.stringify(data, null, 2), "utf8");
7543
+ await mkdir12(path14.dirname(this.filePath), { recursive: true });
7544
+ await writeFile12(this.filePath, JSON.stringify(data, null, 2), "utf8");
7347
7545
  }
7348
7546
  async read() {
7349
7547
  try {
7350
- return JSON.parse(await readFile11(this.filePath, "utf8"));
7548
+ return JSON.parse(await readFile12(this.filePath, "utf8"));
7351
7549
  } catch {
7352
7550
  return {};
7353
7551
  }
@@ -7355,16 +7553,16 @@ var LocalToolSessionStore = class {
7355
7553
  };
7356
7554
  function defaultSessionStorePath() {
7357
7555
  if (process.platform === "darwin") {
7358
- return path13.join(os7.homedir(), "Library", "Application Support", "Amistio", "tool-sessions.json");
7556
+ return path14.join(os8.homedir(), "Library", "Application Support", "Amistio", "tool-sessions.json");
7359
7557
  }
7360
7558
  if (process.platform === "win32") {
7361
- return path13.join(process.env.APPDATA ?? os7.homedir(), "Amistio", "tool-sessions.json");
7559
+ return path14.join(process.env.APPDATA ?? os8.homedir(), "Amistio", "tool-sessions.json");
7362
7560
  }
7363
- return path13.join(process.env.XDG_STATE_HOME ?? path13.join(os7.homedir(), ".local", "state"), "amistio", "tool-sessions.json");
7561
+ return path14.join(process.env.XDG_STATE_HOME ?? path14.join(os8.homedir(), ".local", "state"), "amistio", "tool-sessions.json");
7364
7562
  }
7365
7563
 
7366
7564
  // src/work-runner.ts
7367
- import path14 from "node:path";
7565
+ import path15 from "node:path";
7368
7566
  var generationResultStart = "AMISTIO_BRAIN_GENERATION_RESULT_START";
7369
7567
  var generationResultEnd = "AMISTIO_BRAIN_GENERATION_RESULT_END";
7370
7568
  var assistantAnswerStart = "AMISTIO_ASSISTANT_ANSWER_START";
@@ -8958,15 +9156,15 @@ function normalizeProjectContextRepoPath(value, options) {
8958
9156
  if (!trimmed || /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(trimmed) || /^file:/i.test(trimmed) || /^[A-Za-z]:($|[^\\/])/.test(trimmed)) {
8959
9157
  throwUnsafeProjectContextPath();
8960
9158
  }
8961
- const absolute = trimmed.startsWith("/") || trimmed.startsWith("\\\\") || path14.isAbsolute(trimmed) || path14.win32.isAbsolute(trimmed);
9159
+ const absolute = trimmed.startsWith("/") || trimmed.startsWith("\\\\") || path15.isAbsolute(trimmed) || path15.win32.isAbsolute(trimmed);
8962
9160
  if (!absolute) {
8963
9161
  return normalizeRelativeProjectContextPath(trimmed);
8964
9162
  }
8965
9163
  if (!options.repositoryRoot) {
8966
9164
  throwUnsafeProjectContextPath();
8967
9165
  }
8968
- const useWindowsPathRules = path14.win32.isAbsolute(trimmed) && !trimmed.startsWith("/");
8969
- const relativePath = useWindowsPathRules ? path14.win32.relative(path14.win32.resolve(options.repositoryRoot), path14.win32.resolve(trimmed)) : path14.relative(path14.resolve(options.repositoryRoot), path14.resolve(trimmed));
9166
+ const useWindowsPathRules = path15.win32.isAbsolute(trimmed) && !trimmed.startsWith("/");
9167
+ const relativePath = useWindowsPathRules ? path15.win32.relative(path15.win32.resolve(options.repositoryRoot), path15.win32.resolve(trimmed)) : path15.relative(path15.resolve(options.repositoryRoot), path15.resolve(trimmed));
8970
9168
  return normalizeRelativeProjectContextPath(relativePath);
8971
9169
  }
8972
9170
  function normalizeRelativeProjectContextPath(value) {
@@ -9050,15 +9248,15 @@ function stripJsonFence(value) {
9050
9248
  }
9051
9249
 
9052
9250
  // src/runner-resources.ts
9053
- import os8 from "node:os";
9251
+ import os9 from "node:os";
9054
9252
  var defaultRuntime = {
9055
9253
  nowMs: () => Date.now(),
9056
9254
  memoryUsage: () => process.memoryUsage(),
9057
9255
  uptime: () => process.uptime(),
9058
9256
  cpuUsage: () => process.cpuUsage(),
9059
- totalmem: () => os8.totalmem(),
9060
- freemem: () => os8.freemem(),
9061
- loadavg: () => os8.loadavg()
9257
+ totalmem: () => os9.totalmem(),
9258
+ freemem: () => os9.freemem(),
9259
+ loadavg: () => os9.loadavg()
9062
9260
  };
9063
9261
  var previousRunnerResourceSample;
9064
9262
  function sampleCurrentRunnerResourceUsage() {
@@ -9171,8 +9369,8 @@ function roundNumber(value, digits) {
9171
9369
  // src/importer.ts
9172
9370
  import { execFile as execFile4 } from "node:child_process";
9173
9371
  import { createHash as createHash7 } from "node:crypto";
9174
- import { readdir as readdir6, readFile as readFile12, stat as stat5 } from "node:fs/promises";
9175
- import path15 from "node:path";
9372
+ import { readdir as readdir6, readFile as readFile13, stat as stat6 } from "node:fs/promises";
9373
+ import path16 from "node:path";
9176
9374
  import { promisify as promisify4 } from "node:util";
9177
9375
  var execFileAsync4 = promisify4(execFile4);
9178
9376
  var defaultMaxFileKb = 256;
@@ -9193,12 +9391,12 @@ var documentFolderByType = {
9193
9391
  workflow: "docs/workflows"
9194
9392
  };
9195
9393
  async function inspectLocalRepository(rootDir, defaultBranch) {
9196
- const requestedRoot = path15.resolve(rootDir);
9394
+ const requestedRoot = path16.resolve(rootDir);
9197
9395
  const root = await runGit2(["-C", requestedRoot, "rev-parse", "--show-toplevel"]).catch(() => requestedRoot);
9198
9396
  const detectedBranch = await runGit2(["-C", root, "symbolic-ref", "--quiet", "--short", "HEAD"]).catch(() => defaultBranch);
9199
9397
  const originUrl = await runGit2(["-C", root, "remote", "get-url", "origin"]).catch(() => void 0);
9200
9398
  const parsedCloneUrl = originUrl ? parseOptionalOriginCloneUrl(originUrl) : void 0;
9201
- const repoName = (parsedCloneUrl?.repoName ?? path15.basename(root)) || "repository";
9399
+ const repoName = (parsedCloneUrl?.repoName ?? path16.basename(root)) || "repository";
9202
9400
  const fingerprintSeed = parsedCloneUrl ? `origin:${parsedCloneUrl.normalizedKey}` : `repo:${repoName}:${detectedBranch || defaultBranch}`;
9203
9401
  return {
9204
9402
  rootDir: root,
@@ -9210,7 +9408,7 @@ async function inspectLocalRepository(rootDir, defaultBranch) {
9210
9408
  };
9211
9409
  }
9212
9410
  async function scanLegacyDocuments(options) {
9213
- const rootDir = path15.resolve(options.rootDir);
9411
+ const rootDir = path16.resolve(options.rootDir);
9214
9412
  const maxBytes = (options.maxFileKb ?? defaultMaxFileKb) * 1024;
9215
9413
  const skipped = [];
9216
9414
  const candidates = [];
@@ -9230,8 +9428,8 @@ async function scanLegacyDocuments(options) {
9230
9428
  skipped.push({ repoPath, reason: "excluded" });
9231
9429
  continue;
9232
9430
  }
9233
- const fullPath = path15.join(rootDir, ...repoPath.split("/"));
9234
- const fileStat = await stat5(fullPath).catch(() => void 0);
9431
+ const fullPath = path16.join(rootDir, ...repoPath.split("/"));
9432
+ const fileStat = await stat6(fullPath).catch(() => void 0);
9235
9433
  if (!fileStat?.isFile()) {
9236
9434
  skipped.push({ repoPath, reason: "unreadable" });
9237
9435
  continue;
@@ -9240,7 +9438,7 @@ async function scanLegacyDocuments(options) {
9240
9438
  skipped.push({ repoPath, reason: "tooLarge" });
9241
9439
  continue;
9242
9440
  }
9243
- const content = await readFile12(fullPath, "utf8").catch(() => void 0);
9441
+ const content = await readFile13(fullPath, "utf8").catch(() => void 0);
9244
9442
  if (content === void 0) {
9245
9443
  skipped.push({ repoPath, reason: "unreadable" });
9246
9444
  continue;
@@ -9332,8 +9530,8 @@ async function listRepositoryPaths(rootDir) {
9332
9530
  async function walkRepository(rootDir, directory, files) {
9333
9531
  const entries = await readdir6(directory, { withFileTypes: true }).catch(() => []);
9334
9532
  for (const entry of entries) {
9335
- const fullPath = path15.join(directory, entry.name);
9336
- const repoPath = normalizeRepoPath4(path15.relative(rootDir, fullPath));
9533
+ const fullPath = path16.join(directory, entry.name);
9534
+ const repoPath = normalizeRepoPath4(path16.relative(rootDir, fullPath));
9337
9535
  if (entry.isDirectory()) {
9338
9536
  if (!excludedDirectoryNames.has(entry.name)) {
9339
9537
  await walkRepository(rootDir, fullPath, files);
@@ -9401,9 +9599,9 @@ function uniqueDestinationPath(basePath, sourcePath, usedPaths) {
9401
9599
  usedPaths.add(basePath);
9402
9600
  return basePath;
9403
9601
  }
9404
- const extension = path15.posix.extname(basePath) || ".md";
9405
- const directory = path15.posix.dirname(basePath);
9406
- const basename = path15.posix.basename(basePath, extension);
9602
+ const extension = path16.posix.extname(basePath) || ".md";
9603
+ const directory = path16.posix.dirname(basePath);
9604
+ const basename = path16.posix.basename(basePath, extension);
9407
9605
  const uniquePath = `${directory}/${basename}-${hashText(sourcePath, 8)}${extension}`;
9408
9606
  usedPaths.add(uniquePath);
9409
9607
  return uniquePath;
@@ -9476,7 +9674,7 @@ function inferTitle2(content, repoPath) {
9476
9674
  if (heading) return heading;
9477
9675
  const htmlHeading = body.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1]?.replace(/<[^>]+>/g, "").trim();
9478
9676
  if (htmlHeading) return htmlHeading;
9479
- const basename = path15.posix.basename(repoPath, path15.posix.extname(repoPath)).replace(/[-_]+/g, " ").trim();
9677
+ const basename = path16.posix.basename(repoPath, path16.posix.extname(repoPath)).replace(/[-_]+/g, " ").trim();
9480
9678
  return titleCase(basename || "Imported Document");
9481
9679
  }
9482
9680
  function stripFrontmatter(content) {
@@ -9517,7 +9715,7 @@ async function runGit2(args) {
9517
9715
 
9518
9716
  // src/runner-actions.ts
9519
9717
  import { spawn as spawn4 } from "node:child_process";
9520
- import path16 from "node:path";
9718
+ import path17 from "node:path";
9521
9719
  function buildBackgroundRunnerArgs(options) {
9522
9720
  const args = [
9523
9721
  "run",
@@ -9527,7 +9725,7 @@ function buildBackgroundRunnerArgs(options) {
9527
9725
  "--runner-id",
9528
9726
  options.runnerId,
9529
9727
  "--root",
9530
- path16.resolve(options.root),
9728
+ path17.resolve(options.root),
9531
9729
  "--session",
9532
9730
  options.session,
9533
9731
  "--interval-seconds",
@@ -9651,8 +9849,8 @@ function truncateProcessOutput(value) {
9651
9849
 
9652
9850
  // src/git-worktree.ts
9653
9851
  import { execFile as execFile5 } from "node:child_process";
9654
- import { copyFile, lstat, mkdir as mkdir12, readdir as readdir7, stat as stat6 } from "node:fs/promises";
9655
- import path17 from "node:path";
9852
+ import { copyFile, lstat, mkdir as mkdir13, readdir as readdir7, stat as stat7 } from "node:fs/promises";
9853
+ import path18 from "node:path";
9656
9854
  import { promisify as promisify5 } from "node:util";
9657
9855
  var execFileAsync5 = promisify5(execFile5);
9658
9856
  var exactLocalEnvironmentFiles = /* @__PURE__ */ new Set([".env", ".env.local", ".env.development", ".env.development.local", ".env.test", ".env.test.local", ".env.production", ".env.production.local"]);
@@ -9687,7 +9885,7 @@ async function prepareGitWorktreeIsolation(rootDir, workItem) {
9687
9885
  return { ...identity, baseRevision, worktreePath, ...preparedLocalEnvironmentFileCount2 ? { preparedLocalEnvironmentFileCount: preparedLocalEnvironmentFileCount2 } : {} };
9688
9886
  }
9689
9887
  await repairMissingRegisteredWorktree(repoRoot, worktreePath, identity.branch, identity.worktreeKey);
9690
- await mkdir12(path17.dirname(worktreePath), { recursive: true });
9888
+ await mkdir13(path18.dirname(worktreePath), { recursive: true });
9691
9889
  const branchExists = await gitCommandSucceeds(repoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${identity.branch}`]);
9692
9890
  const worktreeArgs = branchExists ? ["worktree", "add", worktreePath, identity.branch] : ["worktree", "add", "-b", identity.branch, worktreePath, baseRevision];
9693
9891
  await gitOutput(repoRoot, worktreeArgs).catch((error) => {
@@ -9705,9 +9903,9 @@ async function resolveExistingGitWorktreeIsolation(rootDir, workItem) {
9705
9903
  return { ...identity, baseRevision, worktreePath };
9706
9904
  }
9707
9905
  function localWorktreePath(repoRoot, worktreeKey) {
9708
- const repoName = path17.basename(repoRoot);
9906
+ const repoName = path18.basename(repoRoot);
9709
9907
  const worktreeSlug = worktreeKey.split("/").filter(Boolean).pop() ?? "work";
9710
- return path17.join(path17.dirname(repoRoot), `${repoName}.worktrees`, worktreeSlug);
9908
+ return path18.join(path18.dirname(repoRoot), `${repoName}.worktrees`, worktreeSlug);
9711
9909
  }
9712
9910
  async function assertExistingWorktree(worktreePath, branch) {
9713
9911
  await gitOutput(worktreePath, ["rev-parse", "--is-inside-work-tree"]);
@@ -9770,7 +9968,7 @@ function parseRegisteredGitWorktrees(output) {
9770
9968
  return worktrees;
9771
9969
  }
9772
9970
  function normalizeGitWorktreePath(value) {
9773
- const resolved = path17.resolve(value);
9971
+ const resolved = path18.resolve(value);
9774
9972
  return resolved.startsWith("/private/var/") ? resolved.replace("/private/var/", "/var/") : resolved;
9775
9973
  }
9776
9974
  async function assertBaseRevision(repoRoot, baseRevision, currentHead) {
@@ -9790,8 +9988,8 @@ async function prepareLocalWorktreeEnvironment(repoRoot, worktreePath) {
9790
9988
  const candidates = await localEnvironmentFileCandidates(repoRoot);
9791
9989
  let preparedCount = 0;
9792
9990
  for (const candidate of candidates) {
9793
- const sourcePath = path17.join(repoRoot, candidate);
9794
- const targetPath = path17.join(worktreePath, candidate);
9991
+ const sourcePath = path18.join(repoRoot, candidate);
9992
+ const targetPath = path18.join(worktreePath, candidate);
9795
9993
  if (await pathExists(targetPath)) {
9796
9994
  continue;
9797
9995
  }
@@ -9822,7 +10020,7 @@ async function localEnvironmentFileCandidates(repoRoot) {
9822
10020
  if (!isRootFileName(name)) {
9823
10021
  continue;
9824
10022
  }
9825
- const source = await lstat(path17.join(repoRoot, name)).catch(() => void 0);
10023
+ const source = await lstat(path18.join(repoRoot, name)).catch(() => void 0);
9826
10024
  if (source?.isFile()) {
9827
10025
  candidates.push(name);
9828
10026
  }
@@ -9833,7 +10031,7 @@ function isAllowedLocalEnvironmentFile(name) {
9833
10031
  return exactLocalEnvironmentFiles.has(name) || localEnvironmentFilePattern.test(name);
9834
10032
  }
9835
10033
  function isRootFileName(name) {
9836
- return name === path17.basename(name) && !name.includes("/") && !name.includes("\\");
10034
+ return name === path18.basename(name) && !name.includes("/") && !name.includes("\\");
9837
10035
  }
9838
10036
  async function gitOutput(cwd, args) {
9839
10037
  const { stdout } = await execFileAsync5("git", args, { cwd, maxBuffer: 1024 * 1024 });
@@ -9843,7 +10041,7 @@ async function gitCommandSucceeds(cwd, args) {
9843
10041
  return execFileAsync5("git", args, { cwd }).then(() => true, () => false);
9844
10042
  }
9845
10043
  async function pathExists(value) {
9846
- return stat6(value).then(() => true, () => false);
10044
+ return stat7(value).then(() => true, () => false);
9847
10045
  }
9848
10046
  function workIsolationSlug(scopeId, title) {
9849
10047
  const scopeSlug = slugify(scopeId);
@@ -9866,7 +10064,7 @@ function safeFileError(error) {
9866
10064
 
9867
10065
  // src/implementation-handoff.ts
9868
10066
  import { execFile as execFile6 } from "node:child_process";
9869
- import path18 from "node:path";
10067
+ import path19 from "node:path";
9870
10068
  import { promisify as promisify6 } from "node:util";
9871
10069
  var execFileAsync6 = promisify6(execFile6);
9872
10070
  var DEFAULT_IMPLEMENTATION_EXPECTED_OUTCOME = "sourceImplementation";
@@ -10320,7 +10518,7 @@ async function cleanupWorktree(run, input) {
10320
10518
  return { status: "failed", message: "Cleanup skipped because the worktree is not clean after PR handoff." };
10321
10519
  }
10322
10520
  try {
10323
- await gitOutput2(run, input.primaryRepoRoot || path18.dirname(input.worktreePath), ["worktree", "remove", input.worktreePath]);
10521
+ await gitOutput2(run, input.primaryRepoRoot || path19.dirname(input.worktreePath), ["worktree", "remove", input.worktreePath]);
10324
10522
  return { status: "completed" };
10325
10523
  } catch (error) {
10326
10524
  return { status: "failed", message: `Cleanup failed: ${safeErrorMessage(error)}` };
@@ -11138,7 +11336,7 @@ program.command("import").description("Pair an existing checkout and import lega
11138
11336
  });
11139
11337
  program.command("pair").description("Pair this repository with an Amistio web project").requiredOption("--account <accountId>", "Amistio account ID").requiredOption("--project <projectId>", "Amistio project ID").option("--repository-link <repositoryLinkId>", "Existing repository link ID").option("--default-branch <branch>", "Default branch", "main").option("--api-url <url>", apiUrlOptionDescription, defaultApiUrl()).option("--pairing-code <code>", "Short-lived pairing code from the Amistio app").option("--token <token>", "Runner/device credential to store outside the repository").option("--root <path>", "Repository root", defaultRoot).action(async (options, command) => {
11140
11338
  const pairingRoot = await resolvePairingRoot(options.root, { explicitRoot: command.getOptionValueSource("root") === "cli" });
11141
- let repositoryLinkId = options.repositoryLink ?? `repo_${randomUUID3()}`;
11339
+ let repositoryLinkId = options.repositoryLink ?? `repo_${randomUUID4()}`;
11142
11340
  let credential = options.token;
11143
11341
  if (options.pairingCode) {
11144
11342
  const pairing = await new ApiClient({
@@ -11279,7 +11477,7 @@ sync.command("watch").description("Watch repository brain folders and auto-sync
11279
11477
  console.log(`Auto-sync watcher stopped after ${iterations} polling attempt${iterations === 1 ? "" : "s"}.`);
11280
11478
  return;
11281
11479
  }
11282
- await delay(options.intervalSeconds * 1e3);
11480
+ await delay2(options.intervalSeconds * 1e3);
11283
11481
  }
11284
11482
  });
11285
11483
  var work = program.command("work").description("Inspect approved work items");
@@ -11324,7 +11522,7 @@ work.command("prompt").description("Print or write an approved work prompt witho
11324
11522
  }
11325
11523
  const prompt = await createRunnerWorkPrompt(context.client, context.metadata.amistioProjectId, workItem);
11326
11524
  if (options.out) {
11327
- await writeFile12(options.out, prompt, "utf8");
11525
+ await writeFile13(options.out, prompt, "utf8");
11328
11526
  console.log(`Wrote work prompt to ${options.out}.`);
11329
11527
  } else {
11330
11528
  console.log(prompt);
@@ -11434,7 +11632,7 @@ program.command("orchestrate").description("Update the Amistio control plane thr
11434
11632
  ...options.toolCommand ? { toolCommand: options.toolCommand } : {},
11435
11633
  ...localModelConfig,
11436
11634
  streamOutput: options.stream,
11437
- ...sessionPolicy === "none" ? {} : { session: { toolSessionId: `local_orchestration_${randomUUID3()}`, policy: sessionPolicy, decision: localSessionDecision(sessionPolicy) } }
11635
+ ...sessionPolicy === "none" ? {} : { session: { toolSessionId: `local_orchestration_${randomUUID4()}`, policy: sessionPolicy, decision: localSessionDecision(sessionPolicy) } }
11438
11636
  });
11439
11637
  if (!options.stream && result.stdout.trim()) {
11440
11638
  console.log(result.stdout.trim());
@@ -11475,7 +11673,7 @@ program.command("run").description("Claim and run approved Amistio work locally"
11475
11673
  projectId: context.metadata.amistioProjectId,
11476
11674
  repositoryLinkId: context.metadata.repositoryLinkId,
11477
11675
  runnerId,
11478
- rootDir: path19.resolve(options.root),
11676
+ rootDir: path20.resolve(options.root),
11479
11677
  apiUrl: options.apiUrl,
11480
11678
  args: buildBackgroundRunnerArgs(resolvedOptions)
11481
11679
  });
@@ -11545,7 +11743,7 @@ program.command("run").description("Claim and run approved Amistio work locally"
11545
11743
  console.log(`Runner stopped after ${iterations} polling attempt${iterations === 1 ? "" : "s"}.`);
11546
11744
  return;
11547
11745
  }
11548
- await delay(options.intervalSeconds * 1e3);
11746
+ await delay2(options.intervalSeconds * 1e3);
11549
11747
  }
11550
11748
  } finally {
11551
11749
  process.off("SIGINT", handleShutdownSignal);
@@ -11704,7 +11902,7 @@ runnerService.command("install").description("Install a user-level startup servi
11704
11902
  projectId: context.metadata.amistioProjectId,
11705
11903
  repositoryLinkId: context.metadata.repositoryLinkId,
11706
11904
  runnerId,
11707
- rootDir: path19.resolve(options.root),
11905
+ rootDir: path20.resolve(options.root),
11708
11906
  apiUrl: options.apiUrl,
11709
11907
  args,
11710
11908
  platform
@@ -11993,612 +12191,696 @@ async function runNextWorkItem({
11993
12191
  }
11994
12192
  return { status: "idle", exitCode: 0, nextAction, message };
11995
12193
  }
11996
- const prompt = await createRunnerWorkPrompt(apiClient, projectId, result.workItem);
11997
- await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
11998
- status: "running",
11999
- summary: "Prepared local runner execution prompt.",
12000
- idempotencyKey: `runner_milestone_prompt_${result.workItem.workItemId}_${result.workItem.attempt}`,
12001
- metadata: { workKind: result.workItem.workKind ?? "implementation", attempt: result.workItem.attempt }
12002
- });
12003
- if (dryRun || toolConfig.tool === "none") {
12004
- console.log(prompt);
12005
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12006
- return { status: "preview", exitCode: 0 };
12007
- }
12008
- const worktreeIsolation = await prepareWorktreeForClaimedItem({ apiClient, heartbeatConcurrency, maxPreflightAttempts, projectId, repositoryLinkId, root, runnerId, toolConfig, workItem: result.workItem });
12009
- if (worktreeIsolation.status !== "ready") {
12010
- return { status: worktreeIsolation.status === "failed" ? "failed" : "blocked", exitCode: 1, message: worktreeIsolation.message };
12011
- }
12012
- const executionRoot = worktreeIsolation.isolation?.worktreePath ?? root;
12013
- const isolationTelemetry = workItemIsolationTelemetry(result.workItem, worktreeIsolation.isolation);
12014
- const environmentReadiness = await checkRunnerExecutionEnvironment({
12015
- executionRoot,
12016
- primaryCheckoutRoot: root,
12017
- profile: executionProfile,
12018
- setupCommands: runnerEnvironmentSetupCommands(setupPackageManagerInstall),
12019
- ...result.workItem.workKind ? { workKind: result.workItem.workKind } : {},
12020
- env: process.env
12021
- });
12022
- if (environmentReadiness.profile === "dockerWorkspace" && environmentReadiness.status === "ready") {
12023
- environmentReadiness.status = "blocked";
12024
- environmentReadiness.summary = "Runner execution environment dockerWorkspace is blocked: containerized harness execution is not enabled in this runner build.";
12025
- environmentReadiness.blockers.push({ reason: "unsupportedProfile", summary: "Containerized harness execution is not enabled in this runner build.", remediation: "Select hostWorktree or hostWorktreeWithSetup until Docker workspace execution is enabled.", safePaths: [] });
12026
- environmentReadiness.checks.push({ checkId: "docker-harness", title: "Docker harness", status: "blocked", reason: "unsupportedProfile", summary: "Docker workspace envelope is valid, but this runner cannot execute the harness inside the container yet.", safePaths: [] });
12027
- }
12028
- if (environmentReadiness.status === "blocked") {
12029
- const statusResult2 = await apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "blocked", `environment_blocked_${result.workItem.workItemId}_${result.workItem.attempt}_${randomUUID3()}`, runnerId, {
12030
- ...isolationTelemetry,
12031
- executionEnvironmentProfile: environmentReadiness.profile,
12032
- executionEnvironmentReadiness: environmentReadiness,
12033
- blockerReason: environmentReadiness.summary,
12034
- message: environmentReadiness.summary
12194
+ const localActiveClaim = await defaultRunnerActiveClaimStore.reserve(runnerActiveClaimInput({
12195
+ accountId: commandContext.accountId,
12196
+ claimLaneId,
12197
+ repositoryLinkId,
12198
+ runnerId,
12199
+ toolTimeoutMs,
12200
+ workItem: result.workItem
12201
+ }));
12202
+ if (localActiveClaim.status === "blocked") {
12203
+ return await releaseSkippedLocalClaim({
12204
+ apiClient,
12205
+ claimLaneId,
12206
+ conflict: localActiveClaim,
12207
+ projectId,
12208
+ repositoryLinkId,
12209
+ runnerId,
12210
+ workItem: result.workItem
12035
12211
  });
12036
- await recordRunnerMilestone(apiClient, projectId, statusResult2.workItem, runnerId, repositoryLinkId, {
12037
- status: "warning",
12038
- summary: environmentReadiness.summary,
12039
- idempotencyKey: `runner_milestone_environment_blocked_${result.workItem.workItemId}_${statusResult2.workItem.idempotencyKey}`,
12040
- metadata: { executionEnvironmentProfile: environmentReadiness.profile, blockerReasons: environmentReadiness.blockers.map((blocker) => blocker.reason) }
12212
+ }
12213
+ const releaseLocalActiveClaim = async () => {
12214
+ await defaultRunnerActiveClaimStore.release(localActiveClaim.record.reservationId).catch((error) => {
12215
+ console.error(`Could not release local Amistio active-claim reservation for ${result.workItem?.workItemId}: ${truncateLogExcerpt(errorDetail(error))}`);
12041
12216
  });
12042
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "blocked", {
12043
- ...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
12044
- currentWorkItemId: result.workItem.workItemId,
12045
- currentExecutionEnvironmentProfile: environmentReadiness.profile,
12046
- environmentReadiness,
12047
- preferenceMessage: environmentReadiness.summary,
12048
- ...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
12049
- ...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
12050
- ...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
12217
+ };
12218
+ try {
12219
+ const prompt = await createRunnerWorkPrompt(apiClient, projectId, result.workItem);
12220
+ await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12221
+ status: "running",
12222
+ summary: "Prepared local runner execution prompt.",
12223
+ idempotencyKey: `runner_milestone_prompt_${result.workItem.workItemId}_${result.workItem.attempt}`,
12224
+ metadata: { workKind: result.workItem.workKind ?? "implementation", attempt: result.workItem.attempt }
12051
12225
  });
12052
- console.error(environmentReadiness.summary);
12053
- return { status: "blocked", exitCode: 1, message: environmentReadiness.summary };
12054
- }
12055
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "running", {
12056
- ...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
12057
- currentWorkItemId: result.workItem.workItemId,
12058
- currentExecutionEnvironmentProfile: environmentReadiness.profile,
12059
- environmentReadiness,
12060
- ...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
12061
- ...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
12062
- ...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
12063
- });
12064
- if (isImplementationHandoffWork(result.workItem)) {
12065
- const repositoryLink = await loadWorkItemRepositoryLink(apiClient, projectId, result.workItem.repositoryLinkId ?? repositoryLinkId).catch(() => void 0);
12066
- const readinessHandoff = await checkImplementationHandoffReadiness({
12067
- primaryRepoRoot: root,
12068
- ...repositoryLink ? { repositoryLink } : {},
12069
- workItem: result.workItem,
12070
- ...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
12071
- worktreePath: executionRoot
12226
+ if (dryRun || toolConfig.tool === "none") {
12227
+ console.log(prompt);
12228
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12229
+ return { status: "preview", exitCode: 0 };
12230
+ }
12231
+ const worktreeIsolation = await prepareWorktreeForClaimedItem({ apiClient, heartbeatConcurrency, maxPreflightAttempts, projectId, repositoryLinkId, root, runnerId, toolConfig, workItem: result.workItem });
12232
+ if (worktreeIsolation.status !== "ready") {
12233
+ return { status: worktreeIsolation.status === "failed" ? "failed" : "blocked", exitCode: 1, message: worktreeIsolation.message };
12234
+ }
12235
+ const executionRoot = worktreeIsolation.isolation?.worktreePath ?? root;
12236
+ const isolationTelemetry = workItemIsolationTelemetry(result.workItem, worktreeIsolation.isolation);
12237
+ const environmentReadiness = await checkRunnerExecutionEnvironment({
12238
+ executionRoot,
12239
+ primaryCheckoutRoot: root,
12240
+ profile: executionProfile,
12241
+ setupCommands: runnerEnvironmentSetupCommands(setupPackageManagerInstall),
12242
+ ...result.workItem.workKind ? { workKind: result.workItem.workKind } : {},
12243
+ env: process.env
12072
12244
  });
12073
- if (readinessHandoff) {
12074
- const message = readinessHandoff.message ?? "Implementation handoff readiness is blocked before local tool execution.";
12075
- const statusResult2 = await apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "blocked", `handoff_readiness_blocked_${result.workItem.workItemId}_${result.workItem.attempt}_${randomUUID3()}`, runnerId, {
12245
+ if (environmentReadiness.profile === "dockerWorkspace" && environmentReadiness.status === "ready") {
12246
+ environmentReadiness.status = "blocked";
12247
+ environmentReadiness.summary = "Runner execution environment dockerWorkspace is blocked: containerized harness execution is not enabled in this runner build.";
12248
+ environmentReadiness.blockers.push({ reason: "unsupportedProfile", summary: "Containerized harness execution is not enabled in this runner build.", remediation: "Select hostWorktree or hostWorktreeWithSetup until Docker workspace execution is enabled.", safePaths: [] });
12249
+ environmentReadiness.checks.push({ checkId: "docker-harness", title: "Docker harness", status: "blocked", reason: "unsupportedProfile", summary: "Docker workspace envelope is valid, but this runner cannot execute the harness inside the container yet.", safePaths: [] });
12250
+ }
12251
+ if (environmentReadiness.status === "blocked") {
12252
+ const statusResult2 = await apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "blocked", `environment_blocked_${result.workItem.workItemId}_${result.workItem.attempt}_${randomUUID4()}`, runnerId, {
12076
12253
  ...isolationTelemetry,
12077
- implementationHandoff: readinessHandoff,
12078
- blockerReason: message,
12079
- message,
12080
- ...readinessHandoff.error ? { error: readinessHandoff.error } : {}
12254
+ executionEnvironmentProfile: environmentReadiness.profile,
12255
+ executionEnvironmentReadiness: environmentReadiness,
12256
+ blockerReason: environmentReadiness.summary,
12257
+ message: environmentReadiness.summary
12081
12258
  });
12082
12259
  await recordRunnerMilestone(apiClient, projectId, statusResult2.workItem, runnerId, repositoryLinkId, {
12083
- status: "blocked",
12084
- summary: message,
12085
- idempotencyKey: `runner_milestone_handoff_readiness_blocked_${result.workItem.workItemId}_${statusResult2.workItem.idempotencyKey}`,
12086
- metadata: {
12087
- recoveryCategory: readinessHandoff.recovery?.category ?? "providerBlocked",
12088
- executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
12089
- executionBranch: isolationTelemetry.executionBranch ?? ""
12090
- }
12260
+ status: "warning",
12261
+ summary: environmentReadiness.summary,
12262
+ idempotencyKey: `runner_milestone_environment_blocked_${result.workItem.workItemId}_${statusResult2.workItem.idempotencyKey}`,
12263
+ metadata: { executionEnvironmentProfile: environmentReadiness.profile, blockerReasons: environmentReadiness.blockers.map((blocker) => blocker.reason) }
12091
12264
  });
12092
12265
  await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "blocked", {
12093
12266
  ...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
12094
12267
  currentWorkItemId: result.workItem.workItemId,
12095
- preferenceMessage: message,
12268
+ currentExecutionEnvironmentProfile: environmentReadiness.profile,
12269
+ environmentReadiness,
12270
+ preferenceMessage: environmentReadiness.summary,
12096
12271
  ...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
12097
12272
  ...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
12098
12273
  ...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
12099
12274
  });
12100
- console.error(message);
12101
- return { status: "blocked", exitCode: 1, message };
12102
- }
12103
- }
12104
- const resolvedModelConfig = toolConfigModelOptions(toolConfig);
12105
- const preparedHarnessRun = await builtinAmistioHarnessAdapter.createRunPreview({
12106
- rootDir: executionRoot,
12107
- prompt,
12108
- tool: toolConfig.tool,
12109
- invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
12110
- ...toolCommand ? { toolCommand } : {},
12111
- ...resolvedModelConfig,
12112
- executionPolicy: {
12113
- executionRoot,
12114
- mutationPolicy: harnessMutationPolicyForWorkItem(result.workItem),
12115
- claimLaneId
12275
+ console.error(environmentReadiness.summary);
12276
+ return { status: "blocked", exitCode: 1, message: environmentReadiness.summary };
12116
12277
  }
12117
- });
12118
- const preview = preparedHarnessRun.preview;
12119
- const sessionContext = await prepareToolSession({
12120
- apiClient,
12121
- projectId,
12122
- repositoryLinkId,
12123
- runnerId,
12124
- machineId: runnerMachineId(),
12125
- sessionPolicy: result.workItem.sessionPolicy ?? sessionPolicy,
12126
- toolName: preview.toolName,
12127
- ...toolConfig.model ? { model: toolConfig.model } : {},
12128
- supportsSessionReuse: preview.supportsSessionReuse,
12129
- resumabilityScope: preview.resumabilityScope,
12130
- workItem: result.workItem,
12131
- isolationTelemetry
12132
- });
12133
- console.log(`Claimed ${result.workItem.workItemId}. Running ${preview.toolName}: ${preview.displayCommand}`);
12134
- const autopilotClaimLine = formatAutopilotClaimLine(result.workItem);
12135
- if (autopilotClaimLine) {
12136
- console.log(autopilotClaimLine);
12137
- }
12138
- const promptBatchClaimLine = formatPromptBatchClaimLine(result.workItem);
12139
- if (promptBatchClaimLine) {
12140
- console.log(promptBatchClaimLine);
12141
- }
12142
- await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12143
- status: "running",
12144
- summary: `Local runner started ${preview.toolName} execution.`,
12145
- idempotencyKey: `runner_milestone_started_${result.workItem.workItemId}_${result.workItem.attempt}`,
12146
- metadata: {
12147
- tool: preview.toolName,
12148
- invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
12149
- claimLaneId: preparedHarnessRun.concurrency.claimLaneId,
12150
- harnessSupportsConcurrentRuns: preparedHarnessRun.concurrency.supportsConcurrentRuns,
12151
- harnessRequiresExclusiveRepository: preparedHarnessRun.concurrency.requiresExclusiveRepository,
12152
- harnessRequiresExclusiveProviderAuth: preparedHarnessRun.concurrency.requiresExclusiveProviderAuth,
12153
- harnessSerializedResourceKeys: preparedHarnessRun.concurrency.serializedResourceKeys
12278
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "running", {
12279
+ ...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
12280
+ currentWorkItemId: result.workItem.workItemId,
12281
+ currentExecutionEnvironmentProfile: environmentReadiness.profile,
12282
+ environmentReadiness,
12283
+ ...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
12284
+ ...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
12285
+ ...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
12286
+ });
12287
+ if (isImplementationHandoffWork(result.workItem)) {
12288
+ const repositoryLink = await loadWorkItemRepositoryLink(apiClient, projectId, result.workItem.repositoryLinkId ?? repositoryLinkId).catch(() => void 0);
12289
+ const readinessHandoff = await checkImplementationHandoffReadiness({
12290
+ primaryRepoRoot: root,
12291
+ ...repositoryLink ? { repositoryLink } : {},
12292
+ workItem: result.workItem,
12293
+ ...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
12294
+ worktreePath: executionRoot
12295
+ });
12296
+ if (readinessHandoff) {
12297
+ const message = readinessHandoff.message ?? "Implementation handoff readiness is blocked before local tool execution.";
12298
+ const statusResult2 = await apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "blocked", `handoff_readiness_blocked_${result.workItem.workItemId}_${result.workItem.attempt}_${randomUUID4()}`, runnerId, {
12299
+ ...isolationTelemetry,
12300
+ implementationHandoff: readinessHandoff,
12301
+ blockerReason: message,
12302
+ message,
12303
+ ...readinessHandoff.error ? { error: readinessHandoff.error } : {}
12304
+ });
12305
+ await recordRunnerMilestone(apiClient, projectId, statusResult2.workItem, runnerId, repositoryLinkId, {
12306
+ status: "blocked",
12307
+ summary: message,
12308
+ idempotencyKey: `runner_milestone_handoff_readiness_blocked_${result.workItem.workItemId}_${statusResult2.workItem.idempotencyKey}`,
12309
+ metadata: {
12310
+ recoveryCategory: readinessHandoff.recovery?.category ?? "providerBlocked",
12311
+ executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
12312
+ executionBranch: isolationTelemetry.executionBranch ?? ""
12313
+ }
12314
+ });
12315
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "blocked", {
12316
+ ...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
12317
+ currentWorkItemId: result.workItem.workItemId,
12318
+ preferenceMessage: message,
12319
+ ...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
12320
+ ...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
12321
+ ...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
12322
+ });
12323
+ console.error(message);
12324
+ return { status: "blocked", exitCode: 1, message };
12325
+ }
12154
12326
  }
12155
- });
12156
- const startedAt = Date.now();
12157
- const providerSessionStore = new LocalToolSessionStore();
12158
- const providerSessionId = sessionContext.toolSession ? await providerSessionStore.getProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName) : void 0;
12159
- let toolResult;
12160
- const stopLeaseRenewal = startWorkLeaseRenewal({ apiClient, projectId, repositoryLinkId, runnerId, toolConfig, workItem: result.workItem, telemetry: isolationTelemetry, heartbeatConcurrency });
12161
- try {
12162
- toolResult = await builtinAmistioHarnessAdapter.executeRun({
12163
- preparedRun: preparedHarnessRun,
12327
+ const resolvedModelConfig = toolConfigModelOptions(toolConfig);
12328
+ const preparedHarnessRun = await builtinAmistioHarnessAdapter.createRunPreview({
12164
12329
  rootDir: executionRoot,
12165
12330
  prompt,
12166
12331
  tool: toolConfig.tool,
12167
12332
  invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
12168
12333
  ...toolCommand ? { toolCommand } : {},
12169
12334
  ...resolvedModelConfig,
12170
- streamOutput: stream,
12171
- timeoutMs: toolTimeoutMs,
12172
- ...sessionContext.toolSession ? {
12173
- session: {
12174
- toolSessionId: sessionContext.toolSession.toolSessionId,
12175
- policy: sessionContext.policy,
12176
- decision: sessionContext.decision,
12177
- ...providerSessionId ? { providerSessionId } : {}
12178
- }
12179
- } : {}
12335
+ executionPolicy: {
12336
+ executionRoot,
12337
+ mutationPolicy: harnessMutationPolicyForWorkItem(result.workItem),
12338
+ claimLaneId
12339
+ }
12180
12340
  });
12181
- } catch (error) {
12182
- stopLeaseRenewal();
12183
- const detail = truncateLogExcerpt(errorDetail(error));
12184
- const durationMs2 = Date.now() - startedAt;
12185
- const message = `${preview.toolName} failed before returning a result.`;
12186
- const settlements = await Promise.allSettled([
12187
- apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency)),
12188
- markToolSessionBlocked(apiClient, projectId, sessionContext.toolSession, errorMessage7(error)),
12189
- apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "failed", `run_failed_${result.workItem.workItemId}_${result.workItem.attempt}_${runnerId}`, runnerId, {
12190
- ...isolationTelemetry,
12191
- tool: preview.toolName,
12192
- ...toolConfig.model ? { model: toolConfig.model } : {},
12193
- durationMs: durationMs2,
12194
- message,
12195
- error: detail,
12196
- ...result.workItem.workKind === "promptBatch" ? { promptBatch: finalizePromptBatchMetadata(result.workItem, "failed", detail) } : {},
12197
- ...sessionContext.toolSession ? { toolSessionId: sessionContext.toolSession.toolSessionId } : {},
12198
- sessionPolicy: sessionContext.policy,
12199
- sessionDecision: sessionContext.decision,
12200
- sessionDecisionReason: sessionContext.reason
12201
- }),
12202
- recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12203
- status: "failed",
12204
- summary: message,
12205
- idempotencyKey: `runner_milestone_tool_throw_${result.workItem.workItemId}_${result.workItem.attempt}`,
12206
- metadata: { tool: preview.toolName, error: detail }
12207
- })
12208
- ]);
12209
- logRejectedSettlements("record local tool failure", settlements);
12210
- if (verbose || !stream) {
12211
- console.error(detail);
12341
+ const preview = preparedHarnessRun.preview;
12342
+ const sessionContext = await prepareToolSession({
12343
+ apiClient,
12344
+ projectId,
12345
+ repositoryLinkId,
12346
+ runnerId,
12347
+ machineId: runnerMachineId(),
12348
+ sessionPolicy: result.workItem.sessionPolicy ?? sessionPolicy,
12349
+ toolName: preview.toolName,
12350
+ ...toolConfig.model ? { model: toolConfig.model } : {},
12351
+ supportsSessionReuse: preview.supportsSessionReuse,
12352
+ resumabilityScope: preview.resumabilityScope,
12353
+ workItem: result.workItem,
12354
+ isolationTelemetry
12355
+ });
12356
+ console.log(`Claimed ${result.workItem.workItemId}. Running ${preview.toolName}: ${preview.displayCommand}`);
12357
+ const autopilotClaimLine = formatAutopilotClaimLine(result.workItem);
12358
+ if (autopilotClaimLine) {
12359
+ console.log(autopilotClaimLine);
12212
12360
  }
12213
- return { status: "failed", exitCode: 1, message };
12214
- }
12215
- stopLeaseRenewal();
12216
- if (sessionContext.toolSession && toolResult.providerSessionId) {
12217
- await providerSessionStore.setProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName, toolResult.providerSessionId);
12218
- }
12219
- if (!stream && toolResult.stdout.trim()) {
12220
- console.log(toolResult.stdout.trim());
12221
- }
12222
- if (!stream && toolResult.stderr.trim()) {
12223
- console.error(toolResult.stderr.trim());
12224
- }
12225
- if (result.workItem.workKind === "brainGeneration" || result.workItem.workKind === "planRevision") {
12226
- try {
12227
- return await finalizeBrainGenerationWork({
12228
- apiClient,
12229
- durationMs: Date.now() - startedAt,
12230
- projectId,
12231
- repositoryLinkId,
12232
- runnerId,
12233
- sessionContext,
12234
- toolConfig,
12235
- toolName: preview.toolName,
12236
- toolResult,
12237
- workItem: result.workItem
12238
- });
12239
- } catch (error) {
12240
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12361
+ const promptBatchClaimLine = formatPromptBatchClaimLine(result.workItem);
12362
+ if (promptBatchClaimLine) {
12363
+ console.log(promptBatchClaimLine);
12241
12364
  }
12242
- }
12243
- if (result.workItem.workKind === "assistantQuestion") {
12365
+ await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12366
+ status: "running",
12367
+ summary: `Local runner started ${preview.toolName} execution.`,
12368
+ idempotencyKey: `runner_milestone_started_${result.workItem.workItemId}_${result.workItem.attempt}`,
12369
+ metadata: {
12370
+ tool: preview.toolName,
12371
+ invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
12372
+ claimLaneId: preparedHarnessRun.concurrency.claimLaneId,
12373
+ harnessSupportsConcurrentRuns: preparedHarnessRun.concurrency.supportsConcurrentRuns,
12374
+ harnessRequiresExclusiveRepository: preparedHarnessRun.concurrency.requiresExclusiveRepository,
12375
+ harnessRequiresExclusiveProviderAuth: preparedHarnessRun.concurrency.requiresExclusiveProviderAuth,
12376
+ harnessSerializedResourceKeys: preparedHarnessRun.concurrency.serializedResourceKeys
12377
+ }
12378
+ });
12379
+ const startedAt = Date.now();
12380
+ const providerSessionStore = new LocalToolSessionStore();
12381
+ const providerSessionId = sessionContext.toolSession ? await providerSessionStore.getProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName) : void 0;
12382
+ let toolResult;
12383
+ const stopLeaseRenewal = startWorkLeaseRenewal({ apiClient, projectId, repositoryLinkId, runnerId, toolConfig, workItem: result.workItem, telemetry: isolationTelemetry, heartbeatConcurrency });
12244
12384
  try {
12245
- return await finalizeAssistantQuestionWork({
12246
- apiClient,
12247
- durationMs: Date.now() - startedAt,
12248
- projectId,
12249
- repositoryLinkId,
12250
- runnerId,
12251
- sessionContext,
12252
- toolConfig,
12253
- toolName: preview.toolName,
12254
- toolResult,
12255
- workItem: result.workItem
12385
+ toolResult = await builtinAmistioHarnessAdapter.executeRun({
12386
+ preparedRun: preparedHarnessRun,
12387
+ rootDir: executionRoot,
12388
+ prompt,
12389
+ tool: toolConfig.tool,
12390
+ invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
12391
+ ...toolCommand ? { toolCommand } : {},
12392
+ ...resolvedModelConfig,
12393
+ streamOutput: stream,
12394
+ timeoutMs: toolTimeoutMs,
12395
+ ...sessionContext.toolSession ? {
12396
+ session: {
12397
+ toolSessionId: sessionContext.toolSession.toolSessionId,
12398
+ policy: sessionContext.policy,
12399
+ decision: sessionContext.decision,
12400
+ ...providerSessionId ? { providerSessionId } : {}
12401
+ }
12402
+ } : {}
12256
12403
  });
12257
12404
  } catch (error) {
12258
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12405
+ stopLeaseRenewal();
12406
+ const detail = truncateLogExcerpt(errorDetail(error));
12407
+ const durationMs2 = Date.now() - startedAt;
12408
+ const message = `${preview.toolName} failed before returning a result.`;
12409
+ const settlements = await Promise.allSettled([
12410
+ apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency)),
12411
+ markToolSessionBlocked(apiClient, projectId, sessionContext.toolSession, errorMessage7(error)),
12412
+ apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "failed", `run_failed_${result.workItem.workItemId}_${result.workItem.attempt}_${runnerId}`, runnerId, {
12413
+ ...isolationTelemetry,
12414
+ tool: preview.toolName,
12415
+ ...toolConfig.model ? { model: toolConfig.model } : {},
12416
+ durationMs: durationMs2,
12417
+ message,
12418
+ error: detail,
12419
+ ...result.workItem.workKind === "promptBatch" ? { promptBatch: finalizePromptBatchMetadata(result.workItem, "failed", detail) } : {},
12420
+ ...sessionContext.toolSession ? { toolSessionId: sessionContext.toolSession.toolSessionId } : {},
12421
+ sessionPolicy: sessionContext.policy,
12422
+ sessionDecision: sessionContext.decision,
12423
+ sessionDecisionReason: sessionContext.reason
12424
+ }),
12425
+ recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12426
+ status: "failed",
12427
+ summary: message,
12428
+ idempotencyKey: `runner_milestone_tool_throw_${result.workItem.workItemId}_${result.workItem.attempt}`,
12429
+ metadata: { tool: preview.toolName, error: detail }
12430
+ })
12431
+ ]);
12432
+ logRejectedSettlements("record local tool failure", settlements);
12433
+ if (verbose || !stream) {
12434
+ console.error(detail);
12435
+ }
12436
+ return { status: "failed", exitCode: 1, message };
12259
12437
  }
12260
- }
12261
- if (result.workItem.workKind === "impactPreview") {
12262
- try {
12263
- return await finalizeImpactPreviewWork({
12264
- apiClient,
12265
- durationMs: Date.now() - startedAt,
12266
- projectId,
12267
- repositoryLinkId,
12268
- root,
12269
- runnerId,
12270
- sessionContext,
12271
- toolConfig,
12272
- toolName: preview.toolName,
12273
- toolResult,
12274
- workItem: result.workItem
12275
- });
12276
- } catch (error) {
12277
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12438
+ stopLeaseRenewal();
12439
+ if (sessionContext.toolSession && toolResult.providerSessionId) {
12440
+ await providerSessionStore.setProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName, toolResult.providerSessionId);
12278
12441
  }
12279
- }
12280
- if (result.workItem.workKind === "issueDiagnosis") {
12281
- try {
12282
- return await finalizeIssueDiagnosisWork({
12283
- apiClient,
12284
- durationMs: Date.now() - startedAt,
12285
- projectId,
12286
- repositoryLinkId,
12287
- runnerId,
12288
- sessionContext,
12289
- toolConfig,
12290
- toolName: preview.toolName,
12291
- toolResult,
12292
- workItem: result.workItem
12293
- });
12294
- } catch (error) {
12295
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12442
+ if (!stream && toolResult.stdout.trim()) {
12443
+ console.log(toolResult.stdout.trim());
12296
12444
  }
12297
- }
12298
- if (result.workItem.workKind === "securityPostureScan") {
12299
- try {
12300
- return await finalizeSecurityPostureScanWork({
12301
- apiClient,
12302
- durationMs: Date.now() - startedAt,
12303
- projectId,
12304
- repositoryLinkId,
12305
- runnerId,
12306
- sessionContext,
12307
- toolConfig,
12308
- toolName: preview.toolName,
12309
- toolResult,
12310
- workItem: result.workItem
12311
- });
12312
- } catch (error) {
12313
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12445
+ if (!stream && toolResult.stderr.trim()) {
12446
+ console.error(toolResult.stderr.trim());
12314
12447
  }
12315
- }
12316
- if (result.workItem.workKind === "appEvaluationScan") {
12317
- try {
12318
- return await finalizeAppEvaluationScanWork({
12319
- apiClient,
12320
- durationMs: Date.now() - startedAt,
12321
- projectId,
12322
- repositoryLinkId,
12323
- runnerId,
12324
- sessionContext,
12325
- toolConfig,
12326
- toolName: preview.toolName,
12327
- toolResult,
12328
- workItem: result.workItem
12329
- });
12330
- } catch (error) {
12331
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12448
+ if (result.workItem.workKind === "brainGeneration" || result.workItem.workKind === "planRevision") {
12449
+ try {
12450
+ return await finalizeBrainGenerationWork({
12451
+ apiClient,
12452
+ durationMs: Date.now() - startedAt,
12453
+ projectId,
12454
+ repositoryLinkId,
12455
+ runnerId,
12456
+ sessionContext,
12457
+ toolConfig,
12458
+ toolName: preview.toolName,
12459
+ toolResult,
12460
+ workItem: result.workItem
12461
+ });
12462
+ } catch (error) {
12463
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12464
+ }
12332
12465
  }
12333
- }
12334
- if (result.workItem.workKind === "brainConsolidationScan") {
12335
- try {
12336
- return await finalizeBrainConsolidationScanWork({
12337
- apiClient,
12338
- durationMs: Date.now() - startedAt,
12339
- projectId,
12340
- repositoryLinkId,
12341
- runnerId,
12342
- sessionContext,
12343
- toolConfig,
12344
- toolName: preview.toolName,
12345
- toolResult,
12346
- workItem: result.workItem
12347
- });
12348
- } catch (error) {
12349
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12466
+ if (result.workItem.workKind === "assistantQuestion") {
12467
+ try {
12468
+ return await finalizeAssistantQuestionWork({
12469
+ apiClient,
12470
+ durationMs: Date.now() - startedAt,
12471
+ projectId,
12472
+ repositoryLinkId,
12473
+ runnerId,
12474
+ sessionContext,
12475
+ toolConfig,
12476
+ toolName: preview.toolName,
12477
+ toolResult,
12478
+ workItem: result.workItem
12479
+ });
12480
+ } catch (error) {
12481
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12482
+ }
12350
12483
  }
12351
- }
12352
- if (result.workItem.workKind === "projectContextRefresh") {
12353
- try {
12354
- return await finalizeProjectContextRefreshWork({
12355
- apiClient,
12356
- durationMs: Date.now() - startedAt,
12357
- executionRoot,
12358
- projectId,
12359
- repositoryLinkId,
12360
- runnerId,
12361
- sessionContext,
12362
- toolConfig,
12363
- toolName: preview.toolName,
12364
- toolResult,
12365
- workItem: result.workItem
12366
- });
12367
- } catch (error) {
12368
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12484
+ if (result.workItem.workKind === "impactPreview") {
12485
+ try {
12486
+ return await finalizeImpactPreviewWork({
12487
+ apiClient,
12488
+ durationMs: Date.now() - startedAt,
12489
+ projectId,
12490
+ repositoryLinkId,
12491
+ root,
12492
+ runnerId,
12493
+ sessionContext,
12494
+ toolConfig,
12495
+ toolName: preview.toolName,
12496
+ toolResult,
12497
+ workItem: result.workItem
12498
+ });
12499
+ } catch (error) {
12500
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12501
+ }
12369
12502
  }
12370
- }
12371
- if (result.workItem.workKind === "implementationVerification") {
12372
- try {
12373
- return await finalizeImplementationVerificationWork({
12374
- apiClient,
12375
- durationMs: Date.now() - startedAt,
12376
- projectId,
12377
- repositoryLinkId,
12378
- runnerId,
12379
- sessionContext,
12380
- toolConfig,
12381
- toolName: preview.toolName,
12382
- toolResult,
12383
- workItem: result.workItem
12503
+ if (result.workItem.workKind === "issueDiagnosis") {
12504
+ try {
12505
+ return await finalizeIssueDiagnosisWork({
12506
+ apiClient,
12507
+ durationMs: Date.now() - startedAt,
12508
+ projectId,
12509
+ repositoryLinkId,
12510
+ runnerId,
12511
+ sessionContext,
12512
+ toolConfig,
12513
+ toolName: preview.toolName,
12514
+ toolResult,
12515
+ workItem: result.workItem
12516
+ });
12517
+ } catch (error) {
12518
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12519
+ }
12520
+ }
12521
+ if (result.workItem.workKind === "securityPostureScan") {
12522
+ try {
12523
+ return await finalizeSecurityPostureScanWork({
12524
+ apiClient,
12525
+ durationMs: Date.now() - startedAt,
12526
+ projectId,
12527
+ repositoryLinkId,
12528
+ runnerId,
12529
+ sessionContext,
12530
+ toolConfig,
12531
+ toolName: preview.toolName,
12532
+ toolResult,
12533
+ workItem: result.workItem
12534
+ });
12535
+ } catch (error) {
12536
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12537
+ }
12538
+ }
12539
+ if (result.workItem.workKind === "appEvaluationScan") {
12540
+ try {
12541
+ return await finalizeAppEvaluationScanWork({
12542
+ apiClient,
12543
+ durationMs: Date.now() - startedAt,
12544
+ projectId,
12545
+ repositoryLinkId,
12546
+ runnerId,
12547
+ sessionContext,
12548
+ toolConfig,
12549
+ toolName: preview.toolName,
12550
+ toolResult,
12551
+ workItem: result.workItem
12552
+ });
12553
+ } catch (error) {
12554
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12555
+ }
12556
+ }
12557
+ if (result.workItem.workKind === "brainConsolidationScan") {
12558
+ try {
12559
+ return await finalizeBrainConsolidationScanWork({
12560
+ apiClient,
12561
+ durationMs: Date.now() - startedAt,
12562
+ projectId,
12563
+ repositoryLinkId,
12564
+ runnerId,
12565
+ sessionContext,
12566
+ toolConfig,
12567
+ toolName: preview.toolName,
12568
+ toolResult,
12569
+ workItem: result.workItem
12570
+ });
12571
+ } catch (error) {
12572
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12573
+ }
12574
+ }
12575
+ if (result.workItem.workKind === "projectContextRefresh") {
12576
+ try {
12577
+ return await finalizeProjectContextRefreshWork({
12578
+ apiClient,
12579
+ durationMs: Date.now() - startedAt,
12580
+ executionRoot,
12581
+ projectId,
12582
+ repositoryLinkId,
12583
+ runnerId,
12584
+ sessionContext,
12585
+ toolConfig,
12586
+ toolName: preview.toolName,
12587
+ toolResult,
12588
+ workItem: result.workItem
12589
+ });
12590
+ } catch (error) {
12591
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12592
+ }
12593
+ }
12594
+ if (result.workItem.workKind === "implementationVerification") {
12595
+ try {
12596
+ return await finalizeImplementationVerificationWork({
12597
+ apiClient,
12598
+ durationMs: Date.now() - startedAt,
12599
+ projectId,
12600
+ repositoryLinkId,
12601
+ runnerId,
12602
+ sessionContext,
12603
+ toolConfig,
12604
+ toolName: preview.toolName,
12605
+ toolResult,
12606
+ workItem: result.workItem
12607
+ });
12608
+ } catch (error) {
12609
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12610
+ }
12611
+ }
12612
+ if (result.workItem.workKind === "testQualityScan") {
12613
+ try {
12614
+ return await finalizeTestQualityScanWork({
12615
+ apiClient,
12616
+ durationMs: Date.now() - startedAt,
12617
+ projectId,
12618
+ repositoryLinkId,
12619
+ runnerId,
12620
+ sessionContext,
12621
+ toolConfig,
12622
+ toolName: preview.toolName,
12623
+ toolResult,
12624
+ workItem: result.workItem
12625
+ });
12626
+ } catch (error) {
12627
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12628
+ }
12629
+ }
12630
+ if (result.workItem.workKind === "implementationTestGate") {
12631
+ try {
12632
+ return await finalizeImplementationTestGateWork({
12633
+ apiClient,
12634
+ durationMs: Date.now() - startedAt,
12635
+ projectId,
12636
+ repositoryLinkId,
12637
+ runnerId,
12638
+ sessionContext,
12639
+ toolConfig,
12640
+ toolName: preview.toolName,
12641
+ toolResult,
12642
+ workItem: result.workItem
12643
+ });
12644
+ } catch (error) {
12645
+ return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12646
+ }
12647
+ }
12648
+ let finalStatus = toolResult.exitCode === 0 ? "completed" : "failed";
12649
+ const durationMs = Date.now() - startedAt;
12650
+ const promptBatchResult = result.workItem.workKind === "promptBatch" ? parsePromptBatchResultBestEffort(toolResult) : void 0;
12651
+ const promptBatchFinalStatus = promptBatchResult ? workStatusFromPromptBatchResult(promptBatchResult) : void 0;
12652
+ if (promptBatchFinalStatus && (toolResult.exitCode === 0 || promptBatchFinalStatus !== "completed")) {
12653
+ finalStatus = promptBatchFinalStatus;
12654
+ }
12655
+ const failureExcerpt = finalStatus === "completed" ? void 0 : truncateLogExcerpt(toolResult.stderr || toolResult.stdout);
12656
+ let implementationHandoff;
12657
+ let finalMessage = `${preview.toolName} exited with code ${toolResult.exitCode}.`;
12658
+ let finalError = failureExcerpt ?? promptBatchFailureReason(promptBatchResult);
12659
+ const patchDrift = finalStatus !== "completed" ? classifyPatchDriftToolResult(toolResult) : void 0;
12660
+ if (patchDrift) {
12661
+ finalStatus = "blocked";
12662
+ finalMessage = patchDrift.message;
12663
+ finalError = patchDrift.summary;
12664
+ implementationHandoff = {
12665
+ status: "blocked",
12666
+ cleanupStatus: "pending",
12667
+ message: patchDrift.message,
12668
+ error: patchDrift.summary,
12669
+ recovery: {
12670
+ category: "patchDrift",
12671
+ availableActions: ["requeueFreshAttempt", "exportHandoffDetails"],
12672
+ conflictFiles: [],
12673
+ summary: "The local patch did not match the current worktree context. Refresh context or queue a fresh linked attempt before retrying.",
12674
+ ...isolationTelemetry.executionWorktreeKey ? { worktreeKey: isolationTelemetry.executionWorktreeKey } : {}
12675
+ }
12676
+ };
12677
+ }
12678
+ if (promptBatchResult && finalStatus !== "completed" && toolResult.exitCode === 0) {
12679
+ finalMessage = "Prompt batch reported a failed or blocked child prompt.";
12680
+ }
12681
+ if (finalStatus === "completed" && isImplementationHandoffWork(result.workItem)) {
12682
+ await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12683
+ status: "running",
12684
+ summary: "Preparing GitHub PR handoff for implementation work.",
12685
+ idempotencyKey: `runner_milestone_handoff_started_${result.workItem.workItemId}_${result.workItem.attempt}`,
12686
+ metadata: { executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
12384
12687
  });
12385
- } catch (error) {
12386
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12688
+ const repositoryLink = await loadWorkItemRepositoryLink(apiClient, projectId, result.workItem.repositoryLinkId ?? repositoryLinkId);
12689
+ const approvedArtifacts = await apiClient.listBrainDocuments(projectId).then((response) => response.documents).catch((error) => {
12690
+ implementationHandoff = {
12691
+ status: "blocked",
12692
+ cleanupStatus: "pending",
12693
+ artifacts: { included: [], skipped: [], blocked: [] },
12694
+ message: "Implementation handoff is blocked because approved artifact metadata could not be loaded.",
12695
+ error: truncateLogExcerpt(errorDetail(error))
12696
+ };
12697
+ return void 0;
12698
+ });
12699
+ if (!implementationHandoff) {
12700
+ implementationHandoff = await completeImplementationHandoff({
12701
+ ...approvedArtifacts ? { approvedArtifacts } : {},
12702
+ primaryRepoRoot: root,
12703
+ ...repositoryLink ? { repositoryLink } : {},
12704
+ verificationSummary: "Local execution reported completion.",
12705
+ workItem: result.workItem,
12706
+ ...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
12707
+ worktreePath: executionRoot
12708
+ });
12709
+ }
12710
+ finalStatus = workStatusFromImplementationHandoff(implementationHandoff);
12711
+ finalMessage = implementationHandoff.message ?? "Implementation handoff finished.";
12712
+ finalError = implementationHandoff.error;
12387
12713
  }
12388
- }
12389
- if (result.workItem.workKind === "testQualityScan") {
12714
+ const updatedToolSession = await finalizeToolSession({
12715
+ apiClient,
12716
+ projectId,
12717
+ status: toolResult.exitCode === 0 ? "completed" : "failed",
12718
+ runnerId,
12719
+ workItemId: result.workItem.workItemId,
12720
+ stdout: toolResult.stdout,
12721
+ ...sessionContext.toolSession ? { session: sessionContext.toolSession } : {},
12722
+ ...toolResult.messageCount !== void 0 ? { messageCount: toolResult.messageCount } : {},
12723
+ ...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
12724
+ ...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
12725
+ ...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {}
12726
+ });
12727
+ let statusResult;
12728
+ const finalizationIdempotencyKey = `run_${result.workItem.workItemId}_${randomUUID4()}`;
12729
+ const finalizationTelemetry = {
12730
+ tool: preview.toolName,
12731
+ ...toolResult.model ? { model: toolResult.model } : {},
12732
+ durationMs,
12733
+ message: finalMessage,
12734
+ ...isolationTelemetry,
12735
+ ...finalStatus === "blocked" ? { blockerReason: finalMessage } : {},
12736
+ sessionPolicy: sessionContext.policy,
12737
+ sessionDecision: sessionContext.decision,
12738
+ sessionDecisionReason: sessionContext.reason,
12739
+ ...updatedToolSession ? { toolSessionId: updatedToolSession.toolSessionId } : {},
12740
+ ...updatedToolSession?.sessionGroupKey ? { sessionGroupKey: updatedToolSession.sessionGroupKey } : {},
12741
+ ...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
12742
+ ...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
12743
+ ...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {},
12744
+ ...implementationHandoff ? { implementationHandoff } : {},
12745
+ ...result.workItem.workKind === "promptBatch" ? { promptBatch: finalizePromptBatchMetadata(result.workItem, finalStatus, finalError, promptBatchResult) } : {},
12746
+ ...finalError ? { error: finalError } : {}
12747
+ };
12390
12748
  try {
12391
- return await finalizeTestQualityScanWork({
12392
- apiClient,
12393
- durationMs: Date.now() - startedAt,
12749
+ const implementationFinalization = isNonMutatingImplementationOutcome(result.workItem) ? await submitNonMutatingImplementationCompletion(apiClient, {
12750
+ attempt: result.workItem.attempt,
12751
+ finalStatus,
12752
+ idempotencyKey: finalizationIdempotencyKey,
12394
12753
  projectId,
12395
- repositoryLinkId,
12396
12754
  runnerId,
12397
- sessionContext,
12398
- toolConfig,
12399
- toolName: preview.toolName,
12400
- toolResult,
12401
- workItem: result.workItem
12402
- });
12403
- } catch (error) {
12404
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12405
- }
12406
- }
12407
- if (result.workItem.workKind === "implementationTestGate") {
12408
- try {
12409
- return await finalizeImplementationTestGateWork({
12410
- apiClient,
12411
- durationMs: Date.now() - startedAt,
12755
+ telemetry: finalizationTelemetry,
12756
+ workItemId: result.workItem.workItemId
12757
+ }) : await submitStagedImplementationFinalization(apiClient, {
12758
+ accountId: commandContext.accountId,
12759
+ attempt: result.workItem.attempt,
12760
+ finalStatus,
12761
+ idempotencyKey: finalizationIdempotencyKey,
12412
12762
  projectId,
12413
12763
  repositoryLinkId,
12414
12764
  runnerId,
12415
- sessionContext,
12416
- toolConfig,
12417
- toolName: preview.toolName,
12418
- toolResult,
12419
- workItem: result.workItem
12765
+ telemetry: implementationFinalizationTelemetry(finalizationTelemetry),
12766
+ workItemId: result.workItem.workItemId,
12767
+ workKind: result.workItem.workKind === "promptBatch" ? "promptBatch" : "implementation"
12420
12768
  });
12769
+ if (implementationFinalization.status === "failed") {
12770
+ if (implementationFinalization.retryable) {
12771
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency)).catch(() => void 0);
12772
+ return { status: "blocked", exitCode: 0, message: implementationFinalization.message };
12773
+ }
12774
+ throw new Error(implementationFinalization.message);
12775
+ }
12776
+ if (implementationFinalization.status === "deferred") {
12777
+ const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
12778
+ await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12779
+ status: "queued",
12780
+ summary: gateMessage,
12781
+ idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
12782
+ metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
12783
+ });
12784
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12785
+ console.log(gateMessage);
12786
+ return { status: "blocked", exitCode: 0, message: gateMessage };
12787
+ }
12788
+ statusResult = { workItem: implementationFinalization.workItem };
12421
12789
  } catch (error) {
12422
- return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
12423
- }
12424
- }
12425
- let finalStatus = toolResult.exitCode === 0 ? "completed" : "failed";
12426
- const durationMs = Date.now() - startedAt;
12427
- const promptBatchResult = result.workItem.workKind === "promptBatch" ? parsePromptBatchResultBestEffort(toolResult) : void 0;
12428
- const promptBatchFinalStatus = promptBatchResult ? workStatusFromPromptBatchResult(promptBatchResult) : void 0;
12429
- if (promptBatchFinalStatus && (toolResult.exitCode === 0 || promptBatchFinalStatus !== "completed")) {
12430
- finalStatus = promptBatchFinalStatus;
12431
- }
12432
- const failureExcerpt = finalStatus === "completed" ? void 0 : truncateLogExcerpt(toolResult.stderr || toolResult.stdout);
12433
- let implementationHandoff;
12434
- let finalMessage = `${preview.toolName} exited with code ${toolResult.exitCode}.`;
12435
- let finalError = failureExcerpt ?? promptBatchFailureReason(promptBatchResult);
12436
- const patchDrift = finalStatus !== "completed" ? classifyPatchDriftToolResult(toolResult) : void 0;
12437
- if (patchDrift) {
12438
- finalStatus = "blocked";
12439
- finalMessage = patchDrift.message;
12440
- finalError = patchDrift.summary;
12441
- implementationHandoff = {
12442
- status: "blocked",
12443
- cleanupStatus: "pending",
12444
- message: patchDrift.message,
12445
- error: patchDrift.summary,
12446
- recovery: {
12447
- category: "patchDrift",
12448
- availableActions: ["requeueFreshAttempt", "exportHandoffDetails"],
12449
- conflictFiles: [],
12450
- summary: "The local patch did not match the current worktree context. Refresh context or queue a fresh linked attempt before retrying.",
12451
- ...isolationTelemetry.executionWorktreeKey ? { worktreeKey: isolationTelemetry.executionWorktreeKey } : {}
12790
+ if (error instanceof AmistioApiError && error.status === 409 && error.detail.includes("implementation_test_gate_required")) {
12791
+ const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
12792
+ await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12793
+ status: "queued",
12794
+ summary: gateMessage,
12795
+ idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
12796
+ metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
12797
+ });
12798
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12799
+ console.log(gateMessage);
12800
+ return { status: "blocked", exitCode: 0 };
12452
12801
  }
12453
- };
12454
- }
12455
- if (promptBatchResult && finalStatus !== "completed" && toolResult.exitCode === 0) {
12456
- finalMessage = "Prompt batch reported a failed or blocked child prompt.";
12457
- }
12458
- if (finalStatus === "completed" && isImplementationHandoffWork(result.workItem)) {
12802
+ throw error;
12803
+ }
12459
12804
  await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12460
- status: "running",
12461
- summary: "Preparing GitHub PR handoff for implementation work.",
12462
- idempotencyKey: `runner_milestone_handoff_started_${result.workItem.workItemId}_${result.workItem.attempt}`,
12463
- metadata: { executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
12464
- });
12465
- const repositoryLink = await loadWorkItemRepositoryLink(apiClient, projectId, result.workItem.repositoryLinkId ?? repositoryLinkId);
12466
- const approvedArtifacts = await apiClient.listBrainDocuments(projectId).then((response) => response.documents).catch((error) => {
12467
- implementationHandoff = {
12468
- status: "blocked",
12469
- cleanupStatus: "pending",
12470
- artifacts: { included: [], skipped: [], blocked: [] },
12471
- message: "Implementation handoff is blocked because approved artifact metadata could not be loaded.",
12472
- error: truncateLogExcerpt(errorDetail(error))
12473
- };
12474
- return void 0;
12805
+ status: finalStatus,
12806
+ summary: finalMessage,
12807
+ idempotencyKey: `runner_milestone_finished_${result.workItem.workItemId}_${statusResult.workItem.idempotencyKey}`,
12808
+ metadata: {
12809
+ tool: preview.toolName,
12810
+ durationMs,
12811
+ exitCode: toolResult.exitCode,
12812
+ verificationSummary: finalStatus === "completed" ? "Local execution reported completion." : "Local execution reported failure.",
12813
+ executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
12814
+ executionBranch: isolationTelemetry.executionBranch ?? "",
12815
+ ...implementationHandoff?.status ? { handoffStatus: implementationHandoff.status } : {},
12816
+ ...implementationHandoff?.prUrl ? { prUrl: implementationHandoff.prUrl } : {},
12817
+ ...implementationHandoff?.cleanupStatus ? { cleanupStatus: implementationHandoff.cleanupStatus } : {},
12818
+ ...implementationHandoff?.artifacts ? artifactHandoffMetadata(implementationHandoff.artifacts) : {}
12819
+ }
12475
12820
  });
12476
- if (!implementationHandoff) {
12477
- implementationHandoff = await completeImplementationHandoff({
12478
- ...approvedArtifacts ? { approvedArtifacts } : {},
12479
- primaryRepoRoot: root,
12480
- ...repositoryLink ? { repositoryLink } : {},
12481
- verificationSummary: "Local execution reported completion.",
12482
- workItem: result.workItem,
12483
- ...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
12484
- worktreePath: executionRoot
12485
- });
12486
- }
12487
- finalStatus = workStatusFromImplementationHandoff(implementationHandoff);
12488
- finalMessage = implementationHandoff.message ?? "Implementation handoff finished.";
12489
- finalError = implementationHandoff.error;
12821
+ await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12822
+ const durationSeconds = Math.round(durationMs / 1e3);
12823
+ console.log(`Marked ${statusResult.workItem.workItemId} ${statusResult.workItem.status} after ${durationSeconds}s.`);
12824
+ return { status: finalStatus, exitCode: finalStatus === "completed" ? toolResult.exitCode : 1 };
12825
+ } finally {
12826
+ await releaseLocalActiveClaim();
12490
12827
  }
12491
- const updatedToolSession = await finalizeToolSession({
12492
- apiClient,
12493
- projectId,
12494
- status: toolResult.exitCode === 0 ? "completed" : "failed",
12828
+ }
12829
+ function runnerActiveClaimInput({ accountId, claimLaneId, repositoryLinkId, runnerId, toolTimeoutMs, workItem }) {
12830
+ const identity = needsGitWorktreeIsolation(workItem) ? resolveWorktreeIdentity(workItem) : void 0;
12831
+ const implementationScopeId = identity?.implementationScopeId ?? workItem.implementationScopeId;
12832
+ const worktreeKey = identity?.worktreeKey ?? workItem.executionWorktreeKey;
12833
+ const executionBranch = identity?.branch ?? workItem.executionBranch;
12834
+ const expiresAtMs = Date.now() + Math.max(toolTimeoutMs, RUNNER_WORK_LEASE_SECONDS * 1e3) + RUNNER_WORK_LEASE_SECONDS * 1e3;
12835
+ return {
12836
+ accountId,
12837
+ projectId: workItem.projectId,
12838
+ repositoryLinkId: workItem.repositoryLinkId ?? repositoryLinkId,
12495
12839
  runnerId,
12496
- workItemId: result.workItem.workItemId,
12497
- stdout: toolResult.stdout,
12498
- ...sessionContext.toolSession ? { session: sessionContext.toolSession } : {},
12499
- ...toolResult.messageCount !== void 0 ? { messageCount: toolResult.messageCount } : {},
12500
- ...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
12501
- ...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
12502
- ...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {}
12503
- });
12504
- let statusResult;
12505
- const finalizationIdempotencyKey = `run_${result.workItem.workItemId}_${randomUUID3()}`;
12506
- const finalizationTelemetry = {
12507
- tool: preview.toolName,
12508
- ...toolResult.model ? { model: toolResult.model } : {},
12509
- durationMs,
12510
- message: finalMessage,
12511
- ...isolationTelemetry,
12512
- ...finalStatus === "blocked" ? { blockerReason: finalMessage } : {},
12513
- sessionPolicy: sessionContext.policy,
12514
- sessionDecision: sessionContext.decision,
12515
- sessionDecisionReason: sessionContext.reason,
12516
- ...updatedToolSession ? { toolSessionId: updatedToolSession.toolSessionId } : {},
12517
- ...updatedToolSession?.sessionGroupKey ? { sessionGroupKey: updatedToolSession.sessionGroupKey } : {},
12518
- ...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
12519
- ...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
12520
- ...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {},
12521
- ...implementationHandoff ? { implementationHandoff } : {},
12522
- ...result.workItem.workKind === "promptBatch" ? { promptBatch: finalizePromptBatchMetadata(result.workItem, finalStatus, finalError, promptBatchResult) } : {},
12523
- ...finalError ? { error: finalError } : {}
12840
+ claimLaneId,
12841
+ workItemId: workItem.workItemId,
12842
+ ...workItem.claimLeaseId ? { claimLeaseId: workItem.claimLeaseId } : {},
12843
+ attempt: workItem.attempt,
12844
+ ...implementationScopeId ? { implementationScopeId } : {},
12845
+ ...worktreeKey ? { worktreeKey } : {},
12846
+ ...executionBranch ? { executionBranch } : {},
12847
+ expiresAt: new Date(expiresAtMs).toISOString()
12524
12848
  };
12525
- try {
12526
- const implementationFinalization = isNonMutatingImplementationOutcome(result.workItem) ? await submitNonMutatingImplementationCompletion(apiClient, {
12527
- attempt: result.workItem.attempt,
12528
- finalStatus,
12529
- idempotencyKey: finalizationIdempotencyKey,
12530
- projectId,
12849
+ }
12850
+ async function releaseSkippedLocalClaim({ apiClient, claimLaneId, conflict, projectId, repositoryLinkId, runnerId, workItem }) {
12851
+ const message = activeClaimConflictMessage(conflict);
12852
+ await apiClient.updateWorkStatus(projectId, workItem.workItemId, "approved", `local_claim_conflict_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`, runnerId, {
12853
+ ...workItemIsolationTelemetry(workItem, void 0),
12854
+ claimLaneId,
12855
+ message,
12856
+ releaseClaim: true
12857
+ }).catch(async (error) => {
12858
+ await apiClient.recordRunnerLog(projectId, {
12531
12859
  runnerId,
12532
- telemetry: finalizationTelemetry,
12533
- workItemId: result.workItem.workItemId
12534
- }) : await submitStagedImplementationFinalization(apiClient, {
12535
- accountId: commandContext.accountId,
12536
- attempt: result.workItem.attempt,
12537
- finalStatus,
12538
- idempotencyKey: finalizationIdempotencyKey,
12539
- projectId,
12540
12860
  repositoryLinkId,
12541
- runnerId,
12542
- telemetry: implementationFinalizationTelemetry(finalizationTelemetry),
12543
- workItemId: result.workItem.workItemId,
12544
- workKind: result.workItem.workKind === "promptBatch" ? "promptBatch" : "implementation"
12545
- });
12546
- if (implementationFinalization.status === "failed") {
12547
- if (implementationFinalization.retryable) {
12548
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency)).catch(() => void 0);
12549
- return { status: "blocked", exitCode: 0, message: implementationFinalization.message };
12550
- }
12551
- throw new Error(implementationFinalization.message);
12552
- }
12553
- if (implementationFinalization.status === "deferred") {
12554
- const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
12555
- await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12556
- status: "queued",
12557
- summary: gateMessage,
12558
- idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
12559
- metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
12560
- });
12561
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12562
- console.log(gateMessage);
12563
- return { status: "blocked", exitCode: 0, message: gateMessage };
12564
- }
12565
- statusResult = { workItem: implementationFinalization.workItem };
12566
- } catch (error) {
12567
- if (error instanceof AmistioApiError && error.status === 409 && error.detail.includes("implementation_test_gate_required")) {
12568
- const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
12569
- await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12570
- status: "queued",
12571
- summary: gateMessage,
12572
- idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
12573
- metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
12574
- });
12575
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12576
- console.log(gateMessage);
12577
- return { status: "blocked", exitCode: 0 };
12578
- }
12579
- throw error;
12580
- }
12581
- await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
12582
- status: finalStatus,
12583
- summary: finalMessage,
12584
- idempotencyKey: `runner_milestone_finished_${result.workItem.workItemId}_${statusResult.workItem.idempotencyKey}`,
12585
- metadata: {
12586
- tool: preview.toolName,
12587
- durationMs,
12588
- exitCode: toolResult.exitCode,
12589
- verificationSummary: finalStatus === "completed" ? "Local execution reported completion." : "Local execution reported failure.",
12590
- executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
12591
- executionBranch: isolationTelemetry.executionBranch ?? "",
12592
- ...implementationHandoff?.status ? { handoffStatus: implementationHandoff.status } : {},
12593
- ...implementationHandoff?.prUrl ? { prUrl: implementationHandoff.prUrl } : {},
12594
- ...implementationHandoff?.cleanupStatus ? { cleanupStatus: implementationHandoff.cleanupStatus } : {},
12595
- ...implementationHandoff?.artifacts ? artifactHandoffMetadata(implementationHandoff.artifacts) : {}
12596
- }
12861
+ status: "blocked",
12862
+ workItemId: workItem.workItemId,
12863
+ workTitle: workItem.title,
12864
+ ...workItem.workKind ? { workKind: workItem.workKind } : {},
12865
+ ...claimLaneId ? { claimLaneId } : {},
12866
+ message: "Runner skipped a locally conflicting active claim but could not release the server claim.",
12867
+ error: truncateLogExcerpt(errorDetail(error)),
12868
+ machineId: runnerMachineId()
12869
+ }).catch(() => void 0);
12597
12870
  });
12598
- await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
12599
- const durationSeconds = Math.round(durationMs / 1e3);
12600
- console.log(`Marked ${statusResult.workItem.workItemId} ${statusResult.workItem.status} after ${durationSeconds}s.`);
12601
- return { status: finalStatus, exitCode: finalStatus === "completed" ? toolResult.exitCode : 1 };
12871
+ await apiClient.recordRunnerLog(projectId, {
12872
+ runnerId,
12873
+ repositoryLinkId,
12874
+ status: "blocked",
12875
+ workItemId: workItem.workItemId,
12876
+ workTitle: workItem.title,
12877
+ ...workItem.workKind ? { workKind: workItem.workKind } : {},
12878
+ ...claimLaneId ? { claimLaneId } : {},
12879
+ message,
12880
+ machineId: runnerMachineId()
12881
+ }).catch(() => void 0);
12882
+ console.error(message);
12883
+ return { status: "idle", exitCode: 0, message };
12602
12884
  }
12603
12885
  function artifactHandoffMetadata(artifacts) {
12604
12886
  return {
@@ -12644,7 +12926,7 @@ async function prepareWorktreeForClaimedItem({ apiClient, heartbeatConcurrency,
12644
12926
  const telemetry = workItemIsolationTelemetry(workItem, { ...identity, baseRevision: workItem.baseRevision ?? "unknown", worktreePath: "" });
12645
12927
  const finalAttempt = workItem.attempt >= maxPreflightAttempts;
12646
12928
  const statusMessage = finalAttempt ? `Git worktree preflight failed after ${workItem.attempt}/${maxPreflightAttempts} attempts. ${message}` : `Git worktree preflight attempt ${workItem.attempt}/${maxPreflightAttempts} failed. Requeueing for retry. ${message}`;
12647
- const statusResult = await apiClient.updateWorkStatus(projectId, workItem.workItemId, finalAttempt ? "failed" : "approved", `worktree_${finalAttempt ? "failed" : "retry"}_${workItem.workItemId}_${workItem.attempt}_${randomUUID3()}`, runnerId, {
12929
+ const statusResult = await apiClient.updateWorkStatus(projectId, workItem.workItemId, finalAttempt ? "failed" : "approved", `worktree_${finalAttempt ? "failed" : "retry"}_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`, runnerId, {
12648
12930
  ...telemetry,
12649
12931
  message: statusMessage,
12650
12932
  ...finalAttempt ? { blockerReason: message } : { releaseClaim: true },
@@ -12713,7 +12995,7 @@ async function recordFinalizationFailure({ apiClient, durationMs, error, isolati
12713
12995
  const settlements = await Promise.allSettled([
12714
12996
  apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig)),
12715
12997
  markToolSessionBlocked(apiClient, projectId, sessionContext.toolSession, errorMessage7(error)),
12716
- apiClient.updateWorkStatus(projectId, workItem.workItemId, "failed", `finalize_failed_${workItem.workItemId}_${workItem.attempt}_${randomUUID3()}`, runnerId, {
12998
+ apiClient.updateWorkStatus(projectId, workItem.workItemId, "failed", `finalize_failed_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`, runnerId, {
12717
12999
  ...isolationTelemetry,
12718
13000
  tool: toolName,
12719
13001
  durationMs,
@@ -12950,7 +13232,7 @@ async function updateRunnerCommandStatus(apiClient, context, command, status, me
12950
13232
  runnerId: context.runnerId,
12951
13233
  repositoryLinkId: context.repositoryLinkId,
12952
13234
  status,
12953
- idempotencyKey: `runner_command_${command.commandId}_${status}_${randomUUID3()}`,
13235
+ idempotencyKey: `runner_command_${command.commandId}_${status}_${randomUUID4()}`,
12954
13236
  message,
12955
13237
  ...error ? { error } : {},
12956
13238
  ...providerAuthStatus ? { providerAuthStatus } : {}
@@ -13042,7 +13324,7 @@ async function findRecoveryWorkItem(apiClient, projectId, workItemId) {
13042
13324
  return workItems.find((item) => item.workItemId === workItemId);
13043
13325
  }
13044
13326
  async function submitRecoveredHandoff(apiClient, context, workItem, handoff, action) {
13045
- await apiClient.updateWorkStatus(context.projectId, workItem.workItemId, recoveredHandoffWorkStatus(handoff), `handoff_recovery_${workItem.workItemId}_${action}_${randomUUID3()}`, context.runnerId, {
13327
+ await apiClient.updateWorkStatus(context.projectId, workItem.workItemId, recoveredHandoffWorkStatus(handoff), `handoff_recovery_${workItem.workItemId}_${action}_${randomUUID4()}`, context.runnerId, {
13046
13328
  implementationHandoff: handoff,
13047
13329
  ...handoff.message ? { message: handoff.message } : {},
13048
13330
  ...workItem.controllingAdrId ? { controllingAdrId: workItem.controllingAdrId } : {},
@@ -13440,7 +13722,7 @@ ${toolResult.stderr}`);
13440
13722
  const resultMutation = {
13441
13723
  status: "completed",
13442
13724
  runnerId,
13443
- idempotencyKey: `generation_${workItem.workItemId}_${workItem.attempt}_${randomUUID3()}`,
13725
+ idempotencyKey: `generation_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`,
13444
13726
  artifacts,
13445
13727
  tool: toolName,
13446
13728
  durationMs,
@@ -13515,7 +13797,7 @@ ${toolResult.stderr}`);
13515
13797
  const failedResult2 = await apiClient.submitBrainGenerationResult(projectId, workItem.workItemId, {
13516
13798
  status: "failed",
13517
13799
  runnerId,
13518
- idempotencyKey: `generation_${workItem.workItemId}_${randomUUID3()}`,
13800
+ idempotencyKey: `generation_${workItem.workItemId}_${randomUUID4()}`,
13519
13801
  tool: toolName,
13520
13802
  durationMs,
13521
13803
  ...failedSessionTelemetry,
@@ -13565,7 +13847,7 @@ ${toolResult.stderr}`);
13565
13847
  const resultMutation = {
13566
13848
  status: "completed",
13567
13849
  runnerId,
13568
- idempotencyKey: `assistant_${workItem.workItemId}_${randomUUID3()}`,
13850
+ idempotencyKey: `assistant_${workItem.workItemId}_${randomUUID4()}`,
13569
13851
  answer: answerResult.answer,
13570
13852
  sourceBoundary: answerResult.sourceBoundary,
13571
13853
  citations: answerResult.citations,
@@ -13601,7 +13883,7 @@ ${toolResult.stderr}`);
13601
13883
  const failedMutation = {
13602
13884
  status: "failed",
13603
13885
  runnerId,
13604
- idempotencyKey: `assistant_${workItem.workItemId}_${randomUUID3()}`,
13886
+ idempotencyKey: `assistant_${workItem.workItemId}_${randomUUID4()}`,
13605
13887
  tool: toolName,
13606
13888
  durationMs,
13607
13889
  ...sessionTelemetry,
@@ -13664,7 +13946,7 @@ ${toolResult.stderr}`);
13664
13946
  const resultMutation = {
13665
13947
  status: "completed",
13666
13948
  runnerId,
13667
- idempotencyKey: `impact_${workItem.workItemId}_${randomUUID3()}`,
13949
+ idempotencyKey: `impact_${workItem.workItemId}_${randomUUID4()}`,
13668
13950
  report: {
13669
13951
  ...report,
13670
13952
  analyzedRepoRevision: report.analyzedRepoRevision ?? metadata?.lastSyncedRevision
@@ -13701,7 +13983,7 @@ ${toolResult.stderr}`);
13701
13983
  const failedMutation = {
13702
13984
  status: "failed",
13703
13985
  runnerId,
13704
- idempotencyKey: `impact_${workItem.workItemId}_${randomUUID3()}`,
13986
+ idempotencyKey: `impact_${workItem.workItemId}_${randomUUID4()}`,
13705
13987
  tool: toolName,
13706
13988
  durationMs,
13707
13989
  ...sessionTelemetry,
@@ -13762,7 +14044,7 @@ ${toolResult.stderr}`);
13762
14044
  const resultMutation = {
13763
14045
  status: "completed",
13764
14046
  runnerId,
13765
- idempotencyKey: `issue_${workItem.workItemId}_${randomUUID3()}`,
14047
+ idempotencyKey: `issue_${workItem.workItemId}_${randomUUID4()}`,
13766
14048
  diagnosis,
13767
14049
  tool: toolName,
13768
14050
  durationMs,
@@ -13796,7 +14078,7 @@ ${toolResult.stderr}`);
13796
14078
  const failedMutation = {
13797
14079
  status: "failed",
13798
14080
  runnerId,
13799
- idempotencyKey: `issue_${workItem.workItemId}_${randomUUID3()}`,
14081
+ idempotencyKey: `issue_${workItem.workItemId}_${randomUUID4()}`,
13800
14082
  tool: toolName,
13801
14083
  durationMs,
13802
14084
  ...sessionTelemetry,
@@ -13857,7 +14139,7 @@ ${toolResult.stderr}`);
13857
14139
  const resultMutation = {
13858
14140
  status: "completed",
13859
14141
  runnerId,
13860
- idempotencyKey: `security_${workItem.workItemId}_${randomUUID3()}`,
14142
+ idempotencyKey: `security_${workItem.workItemId}_${randomUUID4()}`,
13861
14143
  result: scanResult,
13862
14144
  tool: toolName,
13863
14145
  durationMs,
@@ -13891,7 +14173,7 @@ ${toolResult.stderr}`);
13891
14173
  const failedMutation = {
13892
14174
  status: "failed",
13893
14175
  runnerId,
13894
- idempotencyKey: `security_${workItem.workItemId}_${randomUUID3()}`,
14176
+ idempotencyKey: `security_${workItem.workItemId}_${randomUUID4()}`,
13895
14177
  tool: toolName,
13896
14178
  durationMs,
13897
14179
  ...sessionTelemetry,
@@ -13952,7 +14234,7 @@ ${toolResult.stderr}`);
13952
14234
  const resultMutation = {
13953
14235
  status: "completed",
13954
14236
  runnerId,
13955
- idempotencyKey: `app_evaluation_${workItem.workItemId}_${randomUUID3()}`,
14237
+ idempotencyKey: `app_evaluation_${workItem.workItemId}_${randomUUID4()}`,
13956
14238
  result: scanResult,
13957
14239
  tool: toolName,
13958
14240
  durationMs,
@@ -13986,7 +14268,7 @@ ${toolResult.stderr}`);
13986
14268
  const failedMutation = {
13987
14269
  status: "failed",
13988
14270
  runnerId,
13989
- idempotencyKey: `app_evaluation_${workItem.workItemId}_${randomUUID3()}`,
14271
+ idempotencyKey: `app_evaluation_${workItem.workItemId}_${randomUUID4()}`,
13990
14272
  tool: toolName,
13991
14273
  durationMs,
13992
14274
  ...sessionTelemetry,
@@ -14047,7 +14329,7 @@ ${toolResult.stderr}`);
14047
14329
  const resultMutation = {
14048
14330
  status: "completed",
14049
14331
  runnerId,
14050
- idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID3()}`,
14332
+ idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID4()}`,
14051
14333
  result: scanResult,
14052
14334
  tool: toolName,
14053
14335
  durationMs,
@@ -14081,7 +14363,7 @@ ${toolResult.stderr}`);
14081
14363
  const failedMutation = {
14082
14364
  status: "failed",
14083
14365
  runnerId,
14084
- idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID3()}`,
14366
+ idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID4()}`,
14085
14367
  tool: toolName,
14086
14368
  durationMs,
14087
14369
  ...sessionTelemetry,
@@ -14143,7 +14425,7 @@ ${toolResult.stderr}`, { repositoryRoot: executionRoot });
14143
14425
  const resultMutation = {
14144
14426
  status: "completed",
14145
14427
  runnerId,
14146
- idempotencyKey: `project_context_${workItem.workItemId}_${randomUUID3()}`,
14428
+ idempotencyKey: `project_context_${workItem.workItemId}_${randomUUID4()}`,
14147
14429
  result: refreshResult,
14148
14430
  tool: toolName,
14149
14431
  durationMs,
@@ -14189,7 +14471,7 @@ ${toolResult.stderr}`, { repositoryRoot: executionRoot });
14189
14471
  const failedMutation = {
14190
14472
  status: "failed",
14191
14473
  runnerId,
14192
- idempotencyKey: `project_context_${workItem.workItemId}_${randomUUID3()}`,
14474
+ idempotencyKey: `project_context_${workItem.workItemId}_${randomUUID4()}`,
14193
14475
  tool: toolName,
14194
14476
  durationMs,
14195
14477
  ...sessionTelemetry,
@@ -14250,7 +14532,7 @@ ${toolResult.stderr}`);
14250
14532
  const resultMutation = {
14251
14533
  status: "completed",
14252
14534
  runnerId,
14253
- idempotencyKey: `implementation_verification_${workItem.workItemId}_${randomUUID3()}`,
14535
+ idempotencyKey: `implementation_verification_${workItem.workItemId}_${randomUUID4()}`,
14254
14536
  result: verificationResult,
14255
14537
  tool: toolName,
14256
14538
  durationMs,
@@ -14284,7 +14566,7 @@ ${toolResult.stderr}`);
14284
14566
  const failedMutation = {
14285
14567
  status: "failed",
14286
14568
  runnerId,
14287
- idempotencyKey: `implementation_verification_${workItem.workItemId}_${randomUUID3()}`,
14569
+ idempotencyKey: `implementation_verification_${workItem.workItemId}_${randomUUID4()}`,
14288
14570
  tool: toolName,
14289
14571
  durationMs,
14290
14572
  ...sessionTelemetry,
@@ -14345,7 +14627,7 @@ ${toolResult.stderr}`);
14345
14627
  const resultMutation = {
14346
14628
  status: "completed",
14347
14629
  runnerId,
14348
- idempotencyKey: `test_quality_${workItem.workItemId}_${randomUUID3()}`,
14630
+ idempotencyKey: `test_quality_${workItem.workItemId}_${randomUUID4()}`,
14349
14631
  result: scanResult,
14350
14632
  tool: toolName,
14351
14633
  durationMs,
@@ -14379,7 +14661,7 @@ ${toolResult.stderr}`);
14379
14661
  const failedMutation = {
14380
14662
  status: "failed",
14381
14663
  runnerId,
14382
- idempotencyKey: `test_quality_${workItem.workItemId}_${randomUUID3()}`,
14664
+ idempotencyKey: `test_quality_${workItem.workItemId}_${randomUUID4()}`,
14383
14665
  tool: toolName,
14384
14666
  durationMs,
14385
14667
  ...sessionTelemetry,
@@ -14440,7 +14722,7 @@ ${toolResult.stderr}`);
14440
14722
  const resultMutation = {
14441
14723
  status: "completed",
14442
14724
  runnerId,
14443
- idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${randomUUID3()}`,
14725
+ idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${randomUUID4()}`,
14444
14726
  result: gateResult,
14445
14727
  tool: toolName,
14446
14728
  durationMs,
@@ -14474,7 +14756,7 @@ ${toolResult.stderr}`);
14474
14756
  const failedMutation = {
14475
14757
  status: "failed",
14476
14758
  runnerId,
14477
- idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${randomUUID3()}`,
14759
+ idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${randomUUID4()}`,
14478
14760
  tool: toolName,
14479
14761
  durationMs,
14480
14762
  ...sessionTelemetry,
@@ -14711,7 +14993,7 @@ async function prepareToolSession({
14711
14993
  });
14712
14994
  return { ...selection, toolSession: toolSession2 };
14713
14995
  }
14714
- const toolSessionId = `tool_session_${randomUUID3()}`;
14996
+ const toolSessionId = `tool_session_${randomUUID4()}`;
14715
14997
  const { toolSession } = await apiClient.createToolSession(projectId, {
14716
14998
  toolSessionId,
14717
14999
  repositoryLinkId,
@@ -14870,7 +15152,7 @@ function runnerEnvironmentSetupCommands(setupPackageManagerInstall) {
14870
15152
  return setupPackageManagerInstall ? [{ id: "packageManager.install" }] : [];
14871
15153
  }
14872
15154
  function inferRepoName(root) {
14873
- return path19.basename(path19.resolve(root)) || "repository";
15155
+ return path20.basename(path20.resolve(root)) || "repository";
14874
15156
  }
14875
15157
  function createRepoFingerprint(accountId, projectId, repositoryLinkId) {
14876
15158
  return createHash9("sha256").update(`${accountId}:${projectId}:${repositoryLinkId}`).digest("hex");
@@ -15148,7 +15430,7 @@ function runnerHeartbeatMetadata(toolConfig, mode = currentRunnerMode(), concurr
15148
15430
  return {
15149
15431
  version: CLI_VERSION,
15150
15432
  mode,
15151
- hostname: os9.hostname(),
15433
+ hostname: os10.hostname(),
15152
15434
  ...runnerIsolationCapabilityMetadata(),
15153
15435
  maxConcurrentWork: concurrencyMetadata.maxConcurrentWork,
15154
15436
  activeClaimLaneIds: concurrencyMetadata.activeClaimLaneIds,
@@ -15173,9 +15455,9 @@ function runnerHeartbeatMetadata(toolConfig, mode = currentRunnerMode(), concurr
15173
15455
  };
15174
15456
  }
15175
15457
  function runnerMachineId() {
15176
- return createHash9("sha256").update(`${os9.hostname()}:${os9.platform()}:${os9.arch()}`).digest("hex").slice(0, 20);
15458
+ return createHash9("sha256").update(`${os10.hostname()}:${os10.platform()}:${os10.arch()}`).digest("hex").slice(0, 20);
15177
15459
  }
15178
- async function delay(milliseconds) {
15460
+ async function delay2(milliseconds) {
15179
15461
  await new Promise((resolve) => setTimeout(resolve, milliseconds));
15180
15462
  }
15181
15463
  program.parseAsync().catch((error) => {