@amistio/cli 0.1.55 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +958 -687
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { createHash as createHash9, randomUUID as
|
|
5
|
-
import { writeFile as
|
|
6
|
-
import
|
|
7
|
-
import
|
|
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
|
|
11
11
|
import { z } from "zod";
|
|
12
|
+
var runnerMaxConcurrentWorkLimit = 8;
|
|
12
13
|
var isoDateTimeSchema = z.string().datetime({ offset: true });
|
|
13
14
|
var itemTypeSchema = z.enum([
|
|
14
15
|
"account",
|
|
@@ -948,8 +949,8 @@ var runnerHeartbeatItemSchema = baseItemSchema.extend({
|
|
|
948
949
|
supportedExecutionEnvironmentProfiles: z.array(runnerExecutionEnvironmentProfileSchema).optional(),
|
|
949
950
|
currentExecutionEnvironmentProfile: runnerExecutionEnvironmentProfileSchema.optional(),
|
|
950
951
|
environmentReadiness: runnerEnvironmentReadinessSchema.optional(),
|
|
951
|
-
maxConcurrentWork: z.number().int().min(1).max(
|
|
952
|
-
activeClaimLaneIds: z.array(runnerClaimLaneIdSchema).max(
|
|
952
|
+
maxConcurrentWork: z.number().int().min(1).max(runnerMaxConcurrentWorkLimit).optional(),
|
|
953
|
+
activeClaimLaneIds: z.array(runnerClaimLaneIdSchema).max(runnerMaxConcurrentWorkLimit).optional(),
|
|
953
954
|
currentWorkItemId: z.string().min(1).optional(),
|
|
954
955
|
currentImplementationScopeId: z.string().min(1).optional(),
|
|
955
956
|
currentWorktreeKey: z.string().min(1).optional(),
|
|
@@ -3302,8 +3303,8 @@ var toolSessionMutationSchema = z3.object({
|
|
|
3302
3303
|
});
|
|
3303
3304
|
function resolveApiUrl(apiUrl, urlPath) {
|
|
3304
3305
|
const base = apiUrl.endsWith("/") ? apiUrl.slice(0, -1) : apiUrl;
|
|
3305
|
-
const
|
|
3306
|
-
return new URL(`${base}${
|
|
3306
|
+
const path21 = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
|
|
3307
|
+
return new URL(`${base}${path21}`);
|
|
3307
3308
|
}
|
|
3308
3309
|
|
|
3309
3310
|
// src/orchestrator.ts
|
|
@@ -6258,6 +6259,191 @@ async function checkRunnerWatchGitPreflight(options) {
|
|
|
6258
6259
|
return { status: "blocked", exitCode: 1, message, readiness: readiness2 };
|
|
6259
6260
|
}
|
|
6260
6261
|
|
|
6262
|
+
// src/runner-active-claims.ts
|
|
6263
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
6264
|
+
import { chmod as chmod3, mkdir as mkdir9, readFile as readFile9, rm as rm3, stat as stat4, writeFile as writeFile9 } from "node:fs/promises";
|
|
6265
|
+
import os6 from "node:os";
|
|
6266
|
+
import path11 from "node:path";
|
|
6267
|
+
var activeClaimLockStaleMs = 3e4;
|
|
6268
|
+
var activeClaimLockRetryMs = 20;
|
|
6269
|
+
var activeClaimLockAttempts = 50;
|
|
6270
|
+
var maxStoredActiveClaims = 100;
|
|
6271
|
+
var LocalRunnerActiveClaimStore = class {
|
|
6272
|
+
constructor(filePath = defaultActiveClaimStorePath()) {
|
|
6273
|
+
this.filePath = filePath;
|
|
6274
|
+
}
|
|
6275
|
+
filePath;
|
|
6276
|
+
operation = Promise.resolve();
|
|
6277
|
+
async reserve(input) {
|
|
6278
|
+
return this.withLockedStore(async () => {
|
|
6279
|
+
const now = /* @__PURE__ */ new Date();
|
|
6280
|
+
const data = normalizeActiveClaimFile(await this.read());
|
|
6281
|
+
data.activeClaims = pruneExpiredClaims(data.activeClaims, now.getTime());
|
|
6282
|
+
const conflict = data.activeClaims.find((record2) => activeClaimConflicts(record2, input));
|
|
6283
|
+
if (conflict) {
|
|
6284
|
+
return { status: "blocked", reason: activeClaimConflictReason(conflict, input), existing: conflict };
|
|
6285
|
+
}
|
|
6286
|
+
const record = {
|
|
6287
|
+
...input,
|
|
6288
|
+
reservationId: `runner_claim_${randomUUID3()}`,
|
|
6289
|
+
processId: process.pid,
|
|
6290
|
+
reservedAt: now.toISOString(),
|
|
6291
|
+
updatedAt: now.toISOString()
|
|
6292
|
+
};
|
|
6293
|
+
data.activeClaims = [...data.activeClaims, record].slice(-maxStoredActiveClaims);
|
|
6294
|
+
await this.write(data);
|
|
6295
|
+
return { status: "reserved", record };
|
|
6296
|
+
});
|
|
6297
|
+
}
|
|
6298
|
+
async release(reservationId) {
|
|
6299
|
+
await this.withLockedStore(async () => {
|
|
6300
|
+
const data = normalizeActiveClaimFile(await this.read());
|
|
6301
|
+
const activeClaims = data.activeClaims.filter((record) => record.reservationId !== reservationId);
|
|
6302
|
+
if (activeClaims.length === data.activeClaims.length) {
|
|
6303
|
+
return;
|
|
6304
|
+
}
|
|
6305
|
+
await this.write({ activeClaims });
|
|
6306
|
+
});
|
|
6307
|
+
}
|
|
6308
|
+
async listActive(now = Date.now()) {
|
|
6309
|
+
return this.withLockedStore(async () => {
|
|
6310
|
+
const data = normalizeActiveClaimFile(await this.read());
|
|
6311
|
+
const activeClaims = pruneExpiredClaims(data.activeClaims, now);
|
|
6312
|
+
if (activeClaims.length !== data.activeClaims.length) {
|
|
6313
|
+
await this.write({ activeClaims });
|
|
6314
|
+
}
|
|
6315
|
+
return activeClaims;
|
|
6316
|
+
});
|
|
6317
|
+
}
|
|
6318
|
+
async withLockedStore(operation) {
|
|
6319
|
+
return this.withProcessLock(async () => {
|
|
6320
|
+
const release = await this.acquireFileLock();
|
|
6321
|
+
try {
|
|
6322
|
+
return await operation();
|
|
6323
|
+
} finally {
|
|
6324
|
+
await release();
|
|
6325
|
+
}
|
|
6326
|
+
});
|
|
6327
|
+
}
|
|
6328
|
+
async withProcessLock(operation) {
|
|
6329
|
+
const previous = this.operation;
|
|
6330
|
+
let releaseProcessLock = () => void 0;
|
|
6331
|
+
this.operation = new Promise((resolve) => {
|
|
6332
|
+
releaseProcessLock = resolve;
|
|
6333
|
+
});
|
|
6334
|
+
await previous.catch(() => void 0);
|
|
6335
|
+
try {
|
|
6336
|
+
return await operation();
|
|
6337
|
+
} finally {
|
|
6338
|
+
releaseProcessLock();
|
|
6339
|
+
}
|
|
6340
|
+
}
|
|
6341
|
+
async acquireFileLock() {
|
|
6342
|
+
const lockPath = `${this.filePath}.lock`;
|
|
6343
|
+
await mkdir9(path11.dirname(this.filePath), { recursive: true });
|
|
6344
|
+
for (let attempt = 0; attempt < activeClaimLockAttempts; attempt += 1) {
|
|
6345
|
+
try {
|
|
6346
|
+
await mkdir9(lockPath);
|
|
6347
|
+
return async () => {
|
|
6348
|
+
await rm3(lockPath, { recursive: true, force: true });
|
|
6349
|
+
};
|
|
6350
|
+
} catch (error) {
|
|
6351
|
+
if (!isNodeErrorCode(error, "EEXIST")) {
|
|
6352
|
+
throw error;
|
|
6353
|
+
}
|
|
6354
|
+
await removeStaleLock(lockPath, Date.now());
|
|
6355
|
+
await delay(activeClaimLockRetryMs);
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6358
|
+
throw new Error("Could not acquire local runner active-claim lock.");
|
|
6359
|
+
}
|
|
6360
|
+
async read() {
|
|
6361
|
+
try {
|
|
6362
|
+
return JSON.parse(await readFile9(this.filePath, "utf8"));
|
|
6363
|
+
} catch {
|
|
6364
|
+
return { activeClaims: [] };
|
|
6365
|
+
}
|
|
6366
|
+
}
|
|
6367
|
+
async write(data) {
|
|
6368
|
+
await mkdir9(path11.dirname(this.filePath), { recursive: true });
|
|
6369
|
+
await writeFile9(this.filePath, JSON.stringify(data, null, 2), { encoding: "utf8", mode: 384 });
|
|
6370
|
+
await chmod3(this.filePath, 384);
|
|
6371
|
+
}
|
|
6372
|
+
};
|
|
6373
|
+
var defaultRunnerActiveClaimStore = new LocalRunnerActiveClaimStore();
|
|
6374
|
+
function activeClaimConflictMessage(result) {
|
|
6375
|
+
if (result.reason === "sameLane") {
|
|
6376
|
+
return `Runner lane ${result.existing.claimLaneId} is already working on ${result.existing.workItemId}.`;
|
|
6377
|
+
}
|
|
6378
|
+
if (result.reason === "sameWorktree") {
|
|
6379
|
+
return `Runner worktree ${result.existing.worktreeKey} is already reserved by lane ${result.existing.claimLaneId}.`;
|
|
6380
|
+
}
|
|
6381
|
+
return `Runner work item ${result.existing.workItemId} is already reserved by lane ${result.existing.claimLaneId}.`;
|
|
6382
|
+
}
|
|
6383
|
+
function defaultActiveClaimStorePath() {
|
|
6384
|
+
return path11.join(os6.homedir(), ".config", "amistio", "active-runner-claims.json");
|
|
6385
|
+
}
|
|
6386
|
+
function normalizeActiveClaimFile(value) {
|
|
6387
|
+
if (!value || typeof value !== "object" || !("activeClaims" in value)) {
|
|
6388
|
+
return { activeClaims: [] };
|
|
6389
|
+
}
|
|
6390
|
+
const activeClaims = value.activeClaims;
|
|
6391
|
+
if (!Array.isArray(activeClaims)) {
|
|
6392
|
+
return { activeClaims: [] };
|
|
6393
|
+
}
|
|
6394
|
+
return {
|
|
6395
|
+
activeClaims: activeClaims.filter(isRunnerActiveClaimRecord)
|
|
6396
|
+
};
|
|
6397
|
+
}
|
|
6398
|
+
function isRunnerActiveClaimRecord(value) {
|
|
6399
|
+
if (!value || typeof value !== "object") return false;
|
|
6400
|
+
const record = value;
|
|
6401
|
+
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";
|
|
6402
|
+
}
|
|
6403
|
+
function pruneExpiredClaims(records, now) {
|
|
6404
|
+
return records.filter((record) => {
|
|
6405
|
+
const expiresAt = Date.parse(record.expiresAt);
|
|
6406
|
+
return Number.isFinite(expiresAt) && expiresAt > now;
|
|
6407
|
+
});
|
|
6408
|
+
}
|
|
6409
|
+
function activeClaimConflicts(record, input) {
|
|
6410
|
+
if (record.accountId !== input.accountId || record.projectId !== input.projectId || record.repositoryLinkId !== input.repositoryLinkId) {
|
|
6411
|
+
return false;
|
|
6412
|
+
}
|
|
6413
|
+
if (record.runnerId === input.runnerId && record.claimLaneId === input.claimLaneId) {
|
|
6414
|
+
return true;
|
|
6415
|
+
}
|
|
6416
|
+
if (record.workItemId === input.workItemId) {
|
|
6417
|
+
return true;
|
|
6418
|
+
}
|
|
6419
|
+
return Boolean(record.worktreeKey && input.worktreeKey && record.worktreeKey === input.worktreeKey);
|
|
6420
|
+
}
|
|
6421
|
+
function activeClaimConflictReason(record, input) {
|
|
6422
|
+
if (record.runnerId === input.runnerId && record.claimLaneId === input.claimLaneId) {
|
|
6423
|
+
return "sameLane";
|
|
6424
|
+
}
|
|
6425
|
+
if (record.workItemId === input.workItemId) {
|
|
6426
|
+
return "sameWorkItem";
|
|
6427
|
+
}
|
|
6428
|
+
return "sameWorktree";
|
|
6429
|
+
}
|
|
6430
|
+
async function removeStaleLock(lockPath, now) {
|
|
6431
|
+
try {
|
|
6432
|
+
const lockStat = await stat4(lockPath);
|
|
6433
|
+
if (now - lockStat.mtimeMs > activeClaimLockStaleMs) {
|
|
6434
|
+
await rm3(lockPath, { recursive: true, force: true });
|
|
6435
|
+
}
|
|
6436
|
+
} catch {
|
|
6437
|
+
return;
|
|
6438
|
+
}
|
|
6439
|
+
}
|
|
6440
|
+
function isNodeErrorCode(error, code) {
|
|
6441
|
+
return typeof error === "object" && error !== null && error.code === code;
|
|
6442
|
+
}
|
|
6443
|
+
function delay(ms) {
|
|
6444
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6445
|
+
}
|
|
6446
|
+
|
|
6261
6447
|
// src/runner-patch-drift.ts
|
|
6262
6448
|
var patchDriftPatterns = [
|
|
6263
6449
|
{ signature: "applyPatchVerificationFailed", pattern: /apply_patch\s+verification\s+failed/i },
|
|
@@ -6320,9 +6506,9 @@ ${options.detail}`);
|
|
|
6320
6506
|
// src/runner-service.ts
|
|
6321
6507
|
import { spawn as spawn3 } from "node:child_process";
|
|
6322
6508
|
import { createHash as createHash5 } from "node:crypto";
|
|
6323
|
-
import { mkdir as
|
|
6324
|
-
import
|
|
6325
|
-
import
|
|
6509
|
+
import { mkdir as mkdir10, readFile as readFile10, rm as rm4, writeFile as writeFile10 } from "node:fs/promises";
|
|
6510
|
+
import os7 from "node:os";
|
|
6511
|
+
import path12 from "node:path";
|
|
6326
6512
|
function detectRunnerServicePlatform(platform = process.platform) {
|
|
6327
6513
|
if (platform === "darwin") return "launchd";
|
|
6328
6514
|
if (platform === "linux") return "systemd";
|
|
@@ -6333,19 +6519,19 @@ function createRunnerServiceDescriptor(input) {
|
|
|
6333
6519
|
if (platform === "unsupported") {
|
|
6334
6520
|
throw new Error("Startup services are supported for user-level launchd on macOS and systemd user services on Linux.");
|
|
6335
6521
|
}
|
|
6336
|
-
const homeDir = input.homeDir ??
|
|
6522
|
+
const homeDir = input.homeDir ?? os7.homedir();
|
|
6337
6523
|
const serviceName = runnerServiceName(input);
|
|
6338
6524
|
const serviceFilePath = runnerServiceFilePath(platform, serviceName, homeDir);
|
|
6339
6525
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6340
6526
|
const command = [input.executablePath ?? process.execPath, input.scriptPath ?? process.argv[1], ...input.args];
|
|
6341
|
-
const logPath =
|
|
6527
|
+
const logPath = path12.join(input.metadataDir ?? defaultRunnerMetadataDir(), `${runnerServiceKey(input)}.service.log`);
|
|
6342
6528
|
const metadata = {
|
|
6343
6529
|
schemaVersion: 1,
|
|
6344
6530
|
accountId: input.accountId,
|
|
6345
6531
|
projectId: input.projectId,
|
|
6346
6532
|
repositoryLinkId: input.repositoryLinkId,
|
|
6347
6533
|
runnerId: input.runnerId,
|
|
6348
|
-
rootDir:
|
|
6534
|
+
rootDir: path12.resolve(input.rootDir),
|
|
6349
6535
|
apiUrl: input.apiUrl,
|
|
6350
6536
|
serviceName,
|
|
6351
6537
|
serviceFilePath,
|
|
@@ -6362,9 +6548,9 @@ function createRunnerServiceDescriptor(input) {
|
|
|
6362
6548
|
}
|
|
6363
6549
|
async function installRunnerService(input, options = {}) {
|
|
6364
6550
|
const descriptor = createRunnerServiceDescriptor(input);
|
|
6365
|
-
await
|
|
6366
|
-
await
|
|
6367
|
-
await
|
|
6551
|
+
await mkdir10(path12.dirname(descriptor.metadata.serviceFilePath), { recursive: true });
|
|
6552
|
+
await mkdir10(input.metadataDir ?? defaultRunnerMetadataDir(), { recursive: true });
|
|
6553
|
+
await writeFile10(descriptor.metadata.serviceFilePath, descriptor.content, { encoding: "utf8", mode: 384 });
|
|
6368
6554
|
await writeRunnerServiceMetadata(descriptor.metadata, input.metadataDir);
|
|
6369
6555
|
if (options.activate !== false) {
|
|
6370
6556
|
const activation = await activateRunnerService(descriptor.metadata);
|
|
@@ -6380,13 +6566,13 @@ async function removeRunnerService(input) {
|
|
|
6380
6566
|
return void 0;
|
|
6381
6567
|
}
|
|
6382
6568
|
await deactivateRunnerService(metadata).catch(() => void 0);
|
|
6383
|
-
await
|
|
6384
|
-
await
|
|
6569
|
+
await rm4(metadata.serviceFilePath, { force: true });
|
|
6570
|
+
await rm4(runnerServiceMetadataPath(input, input.metadataDir ?? defaultRunnerMetadataDir()), { force: true });
|
|
6385
6571
|
return { ...metadata, status: "removed", updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
6386
6572
|
}
|
|
6387
6573
|
async function readRunnerServiceMetadata(input, metadataDir = defaultRunnerMetadataDir()) {
|
|
6388
6574
|
try {
|
|
6389
|
-
const parsed = JSON.parse(await
|
|
6575
|
+
const parsed = JSON.parse(await readFile10(runnerServiceMetadataPath(input, metadataDir), "utf8"));
|
|
6390
6576
|
if (parsed.schemaVersion !== 1 || !parsed.serviceName || !parsed.serviceFilePath) {
|
|
6391
6577
|
return void 0;
|
|
6392
6578
|
}
|
|
@@ -6396,8 +6582,8 @@ async function readRunnerServiceMetadata(input, metadataDir = defaultRunnerMetad
|
|
|
6396
6582
|
}
|
|
6397
6583
|
}
|
|
6398
6584
|
async function writeRunnerServiceMetadata(metadata, metadataDir = defaultRunnerMetadataDir()) {
|
|
6399
|
-
await
|
|
6400
|
-
await
|
|
6585
|
+
await mkdir10(metadataDir, { recursive: true });
|
|
6586
|
+
await writeFile10(runnerServiceMetadataPath(metadata, metadataDir), JSON.stringify(metadata, null, 2), { encoding: "utf8", mode: 384 });
|
|
6401
6587
|
}
|
|
6402
6588
|
async function runnerServiceRuntimeStatus(metadata) {
|
|
6403
6589
|
if (metadata.platform === "launchd") {
|
|
@@ -6480,12 +6666,12 @@ WantedBy=default.target
|
|
|
6480
6666
|
}
|
|
6481
6667
|
function runnerServiceFilePath(platform, serviceName, homeDir) {
|
|
6482
6668
|
if (platform === "launchd") {
|
|
6483
|
-
return
|
|
6669
|
+
return path12.join(homeDir, "Library", "LaunchAgents", `${serviceName}.plist`);
|
|
6484
6670
|
}
|
|
6485
|
-
return
|
|
6671
|
+
return path12.join(homeDir, ".config", "systemd", "user", `${serviceName}.service`);
|
|
6486
6672
|
}
|
|
6487
6673
|
function runnerServiceMetadataPath(input, metadataDir) {
|
|
6488
|
-
return
|
|
6674
|
+
return path12.join(metadataDir, `${runnerServiceKey(input)}.service.json`);
|
|
6489
6675
|
}
|
|
6490
6676
|
function runnerServiceName(input) {
|
|
6491
6677
|
return `com.amistio.runner.${runnerServiceKey(input).slice(0, 20)}`;
|
|
@@ -6820,8 +7006,8 @@ function createSmokeSession({ now, status, lastActivityAt }) {
|
|
|
6820
7006
|
// src/sync.ts
|
|
6821
7007
|
import { execFile as execFile3 } from "node:child_process";
|
|
6822
7008
|
import { createHash as createHash6 } from "node:crypto";
|
|
6823
|
-
import { mkdir as
|
|
6824
|
-
import
|
|
7009
|
+
import { mkdir as mkdir11, readdir as readdir5, readFile as readFile11, stat as stat5, writeFile as writeFile11 } from "node:fs/promises";
|
|
7010
|
+
import path13 from "node:path";
|
|
6825
7011
|
import { promisify as promisify3 } from "node:util";
|
|
6826
7012
|
var execFileAsync3 = promisify3(execFile3);
|
|
6827
7013
|
var legacySyncRoots = ["architecture", "context", "decisions", "features", "memory", "plans", "prompts", "workflows"];
|
|
@@ -6917,7 +7103,7 @@ async function readLocalSyncedDocuments(rootDir) {
|
|
|
6917
7103
|
const documentFiles = await findBrainDocumentFiles(rootDir);
|
|
6918
7104
|
const documents = [];
|
|
6919
7105
|
for (const fullPath of documentFiles) {
|
|
6920
|
-
const raw = await
|
|
7106
|
+
const raw = await readFile11(fullPath, "utf8");
|
|
6921
7107
|
const repoPath = toRepoPath(rootDir, fullPath);
|
|
6922
7108
|
const parsed = parseSyncedDocument(raw, repoPath);
|
|
6923
7109
|
if (!parsed) {
|
|
@@ -6967,8 +7153,8 @@ async function materializeBrainDocuments(rootDir, documents, options = {}) {
|
|
|
6967
7153
|
result.skipped.push(document.repoPath);
|
|
6968
7154
|
continue;
|
|
6969
7155
|
}
|
|
6970
|
-
await
|
|
6971
|
-
await
|
|
7156
|
+
await mkdir11(path13.dirname(fullPath), { recursive: true });
|
|
7157
|
+
await writeFile11(fullPath, createSyncedDocumentContent(document), "utf8");
|
|
6972
7158
|
result.written.push(document.repoPath);
|
|
6973
7159
|
}
|
|
6974
7160
|
return result;
|
|
@@ -7097,7 +7283,7 @@ function parseSyncedHtml(content) {
|
|
|
7097
7283
|
}
|
|
7098
7284
|
async function readExistingSyncedDocument(fullPath) {
|
|
7099
7285
|
try {
|
|
7100
|
-
const raw = await
|
|
7286
|
+
const raw = await readFile11(fullPath, "utf8");
|
|
7101
7287
|
const parsed = parseSyncedDocument(raw, fullPath);
|
|
7102
7288
|
if (!parsed) {
|
|
7103
7289
|
return { exists: true };
|
|
@@ -7122,7 +7308,7 @@ async function readExistingSyncedDocument(fullPath) {
|
|
|
7122
7308
|
async function findBrainDocumentFiles(rootDir) {
|
|
7123
7309
|
const files = [];
|
|
7124
7310
|
for (const syncRoot of [...syncRoots, htmlSyncRoot]) {
|
|
7125
|
-
const fullRoot =
|
|
7311
|
+
const fullRoot = path13.join(rootDir, syncRoot);
|
|
7126
7312
|
if (!await exists2(fullRoot)) {
|
|
7127
7313
|
continue;
|
|
7128
7314
|
}
|
|
@@ -7132,7 +7318,7 @@ async function findBrainDocumentFiles(rootDir) {
|
|
|
7132
7318
|
}
|
|
7133
7319
|
async function walkBrainDocumentFiles(directory, files) {
|
|
7134
7320
|
for (const entry of await readdir5(directory, { withFileTypes: true })) {
|
|
7135
|
-
const fullPath =
|
|
7321
|
+
const fullPath = path13.join(directory, entry.name);
|
|
7136
7322
|
if (entry.isDirectory()) {
|
|
7137
7323
|
await walkBrainDocumentFiles(fullPath, files);
|
|
7138
7324
|
} else if (entry.isFile() && /\.(md|mdx|html?)$/i.test(entry.name)) {
|
|
@@ -7141,23 +7327,23 @@ async function walkBrainDocumentFiles(directory, files) {
|
|
|
7141
7327
|
}
|
|
7142
7328
|
}
|
|
7143
7329
|
function safeRepoPath(rootDir, repoPath) {
|
|
7144
|
-
if (
|
|
7330
|
+
if (path13.isAbsolute(repoPath)) {
|
|
7145
7331
|
throw new Error(`Refusing to use absolute repo path: ${repoPath}`);
|
|
7146
7332
|
}
|
|
7147
|
-
const normalized =
|
|
7148
|
-
if (normalized === ".." || normalized.startsWith(`..${
|
|
7333
|
+
const normalized = path13.normalize(repoPath);
|
|
7334
|
+
if (normalized === ".." || normalized.startsWith(`..${path13.sep}`)) {
|
|
7149
7335
|
throw new Error(`Refusing to use path outside the repository: ${repoPath}`);
|
|
7150
7336
|
}
|
|
7151
|
-
const root =
|
|
7152
|
-
const fullPath =
|
|
7153
|
-
if (!fullPath.startsWith(`${root}${
|
|
7337
|
+
const root = path13.resolve(rootDir);
|
|
7338
|
+
const fullPath = path13.resolve(root, normalized);
|
|
7339
|
+
if (!fullPath.startsWith(`${root}${path13.sep}`)) {
|
|
7154
7340
|
throw new Error(`Refusing to use path outside the repository: ${repoPath}`);
|
|
7155
7341
|
}
|
|
7156
7342
|
return fullPath;
|
|
7157
7343
|
}
|
|
7158
7344
|
function isControlPlanePath(repoPath) {
|
|
7159
|
-
const normalized =
|
|
7160
|
-
return syncRoots.some((syncRoot) => normalized === syncRoot || normalized.startsWith(`${syncRoot}${
|
|
7345
|
+
const normalized = path13.normalize(repoPath);
|
|
7346
|
+
return syncRoots.some((syncRoot) => normalized === syncRoot || normalized.startsWith(`${syncRoot}${path13.sep}`)) || normalized === htmlSyncRoot || normalized.startsWith(`${htmlSyncRoot}${path13.sep}`);
|
|
7161
7347
|
}
|
|
7162
7348
|
function canonicalControlPlaneRepoPath(repoPath) {
|
|
7163
7349
|
const normalized = repoPath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
|
|
@@ -7168,16 +7354,16 @@ function canonicalControlPlaneRepoPath(repoPath) {
|
|
|
7168
7354
|
return normalized;
|
|
7169
7355
|
}
|
|
7170
7356
|
function toRepoPath(rootDir, fullPath) {
|
|
7171
|
-
return
|
|
7357
|
+
return path13.relative(rootDir, fullPath).split(path13.sep).join("/");
|
|
7172
7358
|
}
|
|
7173
7359
|
function inferTitle(content, repoPath) {
|
|
7174
7360
|
const heading = content.split("\n").find((line) => line.startsWith("# "))?.replace(/^#\s+/, "").trim();
|
|
7175
7361
|
if (heading) return heading;
|
|
7176
7362
|
const htmlHeading = content.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1]?.replace(/<[^>]+>/g, "").trim();
|
|
7177
|
-
return htmlHeading ||
|
|
7363
|
+
return htmlHeading || path13.basename(repoPath, path13.extname(repoPath));
|
|
7178
7364
|
}
|
|
7179
7365
|
async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingDocuments, options) {
|
|
7180
|
-
const root =
|
|
7366
|
+
const root = path13.resolve(rootDir);
|
|
7181
7367
|
const maxBytes = (options.maxFileKb ?? defaultAutoSyncMaxFileKb) * 1024;
|
|
7182
7368
|
const syncedAt = options.syncedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
7183
7369
|
const existingById = new Map(existingDocuments.map((document) => [document.documentId, document]));
|
|
@@ -7193,7 +7379,7 @@ async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingD
|
|
|
7193
7379
|
continue;
|
|
7194
7380
|
}
|
|
7195
7381
|
const fullPath = safeRepoPath(root, normalizedRepoPath);
|
|
7196
|
-
const fileStat = await
|
|
7382
|
+
const fileStat = await stat5(fullPath).catch(() => void 0);
|
|
7197
7383
|
if (!fileStat?.isFile()) {
|
|
7198
7384
|
skipped.push({ repoPath: normalizedRepoPath, reason: "unreadable" });
|
|
7199
7385
|
continue;
|
|
@@ -7202,7 +7388,7 @@ async function collectExternalBrainDocumentsForPush(rootDir, metadata, existingD
|
|
|
7202
7388
|
skipped.push({ repoPath: normalizedRepoPath, reason: "tooLarge" });
|
|
7203
7389
|
continue;
|
|
7204
7390
|
}
|
|
7205
|
-
const content = await
|
|
7391
|
+
const content = await readFile11(fullPath, "utf8").catch(() => void 0);
|
|
7206
7392
|
if (content === void 0) {
|
|
7207
7393
|
skipped.push({ repoPath: normalizedRepoPath, reason: "unreadable" });
|
|
7208
7394
|
continue;
|
|
@@ -7267,7 +7453,7 @@ async function listAutoSyncCandidatePaths(rootDir) {
|
|
|
7267
7453
|
}
|
|
7268
7454
|
const files = [];
|
|
7269
7455
|
for (const syncRoot of [...syncRoots, htmlSyncRoot, ...legacySyncRoots]) {
|
|
7270
|
-
const fullRoot =
|
|
7456
|
+
const fullRoot = path13.join(rootDir, syncRoot);
|
|
7271
7457
|
if (await exists2(fullRoot)) {
|
|
7272
7458
|
await walkAutoSyncFiles(rootDir, fullRoot, files);
|
|
7273
7459
|
}
|
|
@@ -7276,8 +7462,8 @@ async function listAutoSyncCandidatePaths(rootDir) {
|
|
|
7276
7462
|
}
|
|
7277
7463
|
async function walkAutoSyncFiles(rootDir, directory, files) {
|
|
7278
7464
|
for (const entry of await readdir5(directory, { withFileTypes: true }).catch(() => [])) {
|
|
7279
|
-
const fullPath =
|
|
7280
|
-
const repoPath = normalizeRepoPath3(
|
|
7465
|
+
const fullPath = path13.join(directory, entry.name);
|
|
7466
|
+
const repoPath = normalizeRepoPath3(path13.relative(rootDir, fullPath));
|
|
7281
7467
|
if (entry.isDirectory()) {
|
|
7282
7468
|
if (!autoSyncExcludedDirectoryNames.has(entry.name)) {
|
|
7283
7469
|
await walkAutoSyncFiles(rootDir, fullPath, files);
|
|
@@ -7331,7 +7517,7 @@ function parseFrontmatterFromSyncedDocument(frontmatter) {
|
|
|
7331
7517
|
}
|
|
7332
7518
|
async function exists2(filePath) {
|
|
7333
7519
|
try {
|
|
7334
|
-
await
|
|
7520
|
+
await stat5(filePath);
|
|
7335
7521
|
return true;
|
|
7336
7522
|
} catch {
|
|
7337
7523
|
return false;
|
|
@@ -7339,9 +7525,9 @@ async function exists2(filePath) {
|
|
|
7339
7525
|
}
|
|
7340
7526
|
|
|
7341
7527
|
// src/tool-session-store.ts
|
|
7342
|
-
import { mkdir as
|
|
7343
|
-
import
|
|
7344
|
-
import
|
|
7528
|
+
import { mkdir as mkdir12, readFile as readFile12, writeFile as writeFile12 } from "node:fs/promises";
|
|
7529
|
+
import os8 from "node:os";
|
|
7530
|
+
import path14 from "node:path";
|
|
7345
7531
|
var LocalToolSessionStore = class {
|
|
7346
7532
|
constructor(filePath = defaultSessionStorePath()) {
|
|
7347
7533
|
this.filePath = filePath;
|
|
@@ -7355,12 +7541,12 @@ var LocalToolSessionStore = class {
|
|
|
7355
7541
|
async setProviderSessionId(toolSessionId, toolName, providerSessionId) {
|
|
7356
7542
|
const data = await this.read();
|
|
7357
7543
|
data[toolSessionId] = { toolName, providerSessionId, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
7358
|
-
await
|
|
7359
|
-
await
|
|
7544
|
+
await mkdir12(path14.dirname(this.filePath), { recursive: true });
|
|
7545
|
+
await writeFile12(this.filePath, JSON.stringify(data, null, 2), "utf8");
|
|
7360
7546
|
}
|
|
7361
7547
|
async read() {
|
|
7362
7548
|
try {
|
|
7363
|
-
return JSON.parse(await
|
|
7549
|
+
return JSON.parse(await readFile12(this.filePath, "utf8"));
|
|
7364
7550
|
} catch {
|
|
7365
7551
|
return {};
|
|
7366
7552
|
}
|
|
@@ -7368,16 +7554,16 @@ var LocalToolSessionStore = class {
|
|
|
7368
7554
|
};
|
|
7369
7555
|
function defaultSessionStorePath() {
|
|
7370
7556
|
if (process.platform === "darwin") {
|
|
7371
|
-
return
|
|
7557
|
+
return path14.join(os8.homedir(), "Library", "Application Support", "Amistio", "tool-sessions.json");
|
|
7372
7558
|
}
|
|
7373
7559
|
if (process.platform === "win32") {
|
|
7374
|
-
return
|
|
7560
|
+
return path14.join(process.env.APPDATA ?? os8.homedir(), "Amistio", "tool-sessions.json");
|
|
7375
7561
|
}
|
|
7376
|
-
return
|
|
7562
|
+
return path14.join(process.env.XDG_STATE_HOME ?? path14.join(os8.homedir(), ".local", "state"), "amistio", "tool-sessions.json");
|
|
7377
7563
|
}
|
|
7378
7564
|
|
|
7379
7565
|
// src/work-runner.ts
|
|
7380
|
-
import
|
|
7566
|
+
import path15 from "node:path";
|
|
7381
7567
|
var generationResultStart = "AMISTIO_BRAIN_GENERATION_RESULT_START";
|
|
7382
7568
|
var generationResultEnd = "AMISTIO_BRAIN_GENERATION_RESULT_END";
|
|
7383
7569
|
var assistantAnswerStart = "AMISTIO_ASSISTANT_ANSWER_START";
|
|
@@ -8971,15 +9157,15 @@ function normalizeProjectContextRepoPath(value, options) {
|
|
|
8971
9157
|
if (!trimmed || /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(trimmed) || /^file:/i.test(trimmed) || /^[A-Za-z]:($|[^\\/])/.test(trimmed)) {
|
|
8972
9158
|
throwUnsafeProjectContextPath();
|
|
8973
9159
|
}
|
|
8974
|
-
const absolute = trimmed.startsWith("/") || trimmed.startsWith("\\\\") ||
|
|
9160
|
+
const absolute = trimmed.startsWith("/") || trimmed.startsWith("\\\\") || path15.isAbsolute(trimmed) || path15.win32.isAbsolute(trimmed);
|
|
8975
9161
|
if (!absolute) {
|
|
8976
9162
|
return normalizeRelativeProjectContextPath(trimmed);
|
|
8977
9163
|
}
|
|
8978
9164
|
if (!options.repositoryRoot) {
|
|
8979
9165
|
throwUnsafeProjectContextPath();
|
|
8980
9166
|
}
|
|
8981
|
-
const useWindowsPathRules =
|
|
8982
|
-
const relativePath = useWindowsPathRules ?
|
|
9167
|
+
const useWindowsPathRules = path15.win32.isAbsolute(trimmed) && !trimmed.startsWith("/");
|
|
9168
|
+
const relativePath = useWindowsPathRules ? path15.win32.relative(path15.win32.resolve(options.repositoryRoot), path15.win32.resolve(trimmed)) : path15.relative(path15.resolve(options.repositoryRoot), path15.resolve(trimmed));
|
|
8983
9169
|
return normalizeRelativeProjectContextPath(relativePath);
|
|
8984
9170
|
}
|
|
8985
9171
|
function normalizeRelativeProjectContextPath(value) {
|
|
@@ -9063,15 +9249,15 @@ function stripJsonFence(value) {
|
|
|
9063
9249
|
}
|
|
9064
9250
|
|
|
9065
9251
|
// src/runner-resources.ts
|
|
9066
|
-
import
|
|
9252
|
+
import os9 from "node:os";
|
|
9067
9253
|
var defaultRuntime = {
|
|
9068
9254
|
nowMs: () => Date.now(),
|
|
9069
9255
|
memoryUsage: () => process.memoryUsage(),
|
|
9070
9256
|
uptime: () => process.uptime(),
|
|
9071
9257
|
cpuUsage: () => process.cpuUsage(),
|
|
9072
|
-
totalmem: () =>
|
|
9073
|
-
freemem: () =>
|
|
9074
|
-
loadavg: () =>
|
|
9258
|
+
totalmem: () => os9.totalmem(),
|
|
9259
|
+
freemem: () => os9.freemem(),
|
|
9260
|
+
loadavg: () => os9.loadavg()
|
|
9075
9261
|
};
|
|
9076
9262
|
var previousRunnerResourceSample;
|
|
9077
9263
|
function sampleCurrentRunnerResourceUsage() {
|
|
@@ -9184,8 +9370,8 @@ function roundNumber(value, digits) {
|
|
|
9184
9370
|
// src/importer.ts
|
|
9185
9371
|
import { execFile as execFile4 } from "node:child_process";
|
|
9186
9372
|
import { createHash as createHash7 } from "node:crypto";
|
|
9187
|
-
import { readdir as readdir6, readFile as
|
|
9188
|
-
import
|
|
9373
|
+
import { readdir as readdir6, readFile as readFile13, stat as stat6 } from "node:fs/promises";
|
|
9374
|
+
import path16 from "node:path";
|
|
9189
9375
|
import { promisify as promisify4 } from "node:util";
|
|
9190
9376
|
var execFileAsync4 = promisify4(execFile4);
|
|
9191
9377
|
var defaultMaxFileKb = 256;
|
|
@@ -9206,12 +9392,12 @@ var documentFolderByType = {
|
|
|
9206
9392
|
workflow: "docs/workflows"
|
|
9207
9393
|
};
|
|
9208
9394
|
async function inspectLocalRepository(rootDir, defaultBranch) {
|
|
9209
|
-
const requestedRoot =
|
|
9395
|
+
const requestedRoot = path16.resolve(rootDir);
|
|
9210
9396
|
const root = await runGit2(["-C", requestedRoot, "rev-parse", "--show-toplevel"]).catch(() => requestedRoot);
|
|
9211
9397
|
const detectedBranch = await runGit2(["-C", root, "symbolic-ref", "--quiet", "--short", "HEAD"]).catch(() => defaultBranch);
|
|
9212
9398
|
const originUrl = await runGit2(["-C", root, "remote", "get-url", "origin"]).catch(() => void 0);
|
|
9213
9399
|
const parsedCloneUrl = originUrl ? parseOptionalOriginCloneUrl(originUrl) : void 0;
|
|
9214
|
-
const repoName = (parsedCloneUrl?.repoName ??
|
|
9400
|
+
const repoName = (parsedCloneUrl?.repoName ?? path16.basename(root)) || "repository";
|
|
9215
9401
|
const fingerprintSeed = parsedCloneUrl ? `origin:${parsedCloneUrl.normalizedKey}` : `repo:${repoName}:${detectedBranch || defaultBranch}`;
|
|
9216
9402
|
return {
|
|
9217
9403
|
rootDir: root,
|
|
@@ -9223,7 +9409,7 @@ async function inspectLocalRepository(rootDir, defaultBranch) {
|
|
|
9223
9409
|
};
|
|
9224
9410
|
}
|
|
9225
9411
|
async function scanLegacyDocuments(options) {
|
|
9226
|
-
const rootDir =
|
|
9412
|
+
const rootDir = path16.resolve(options.rootDir);
|
|
9227
9413
|
const maxBytes = (options.maxFileKb ?? defaultMaxFileKb) * 1024;
|
|
9228
9414
|
const skipped = [];
|
|
9229
9415
|
const candidates = [];
|
|
@@ -9243,8 +9429,8 @@ async function scanLegacyDocuments(options) {
|
|
|
9243
9429
|
skipped.push({ repoPath, reason: "excluded" });
|
|
9244
9430
|
continue;
|
|
9245
9431
|
}
|
|
9246
|
-
const fullPath =
|
|
9247
|
-
const fileStat = await
|
|
9432
|
+
const fullPath = path16.join(rootDir, ...repoPath.split("/"));
|
|
9433
|
+
const fileStat = await stat6(fullPath).catch(() => void 0);
|
|
9248
9434
|
if (!fileStat?.isFile()) {
|
|
9249
9435
|
skipped.push({ repoPath, reason: "unreadable" });
|
|
9250
9436
|
continue;
|
|
@@ -9253,7 +9439,7 @@ async function scanLegacyDocuments(options) {
|
|
|
9253
9439
|
skipped.push({ repoPath, reason: "tooLarge" });
|
|
9254
9440
|
continue;
|
|
9255
9441
|
}
|
|
9256
|
-
const content = await
|
|
9442
|
+
const content = await readFile13(fullPath, "utf8").catch(() => void 0);
|
|
9257
9443
|
if (content === void 0) {
|
|
9258
9444
|
skipped.push({ repoPath, reason: "unreadable" });
|
|
9259
9445
|
continue;
|
|
@@ -9345,8 +9531,8 @@ async function listRepositoryPaths(rootDir) {
|
|
|
9345
9531
|
async function walkRepository(rootDir, directory, files) {
|
|
9346
9532
|
const entries = await readdir6(directory, { withFileTypes: true }).catch(() => []);
|
|
9347
9533
|
for (const entry of entries) {
|
|
9348
|
-
const fullPath =
|
|
9349
|
-
const repoPath = normalizeRepoPath4(
|
|
9534
|
+
const fullPath = path16.join(directory, entry.name);
|
|
9535
|
+
const repoPath = normalizeRepoPath4(path16.relative(rootDir, fullPath));
|
|
9350
9536
|
if (entry.isDirectory()) {
|
|
9351
9537
|
if (!excludedDirectoryNames.has(entry.name)) {
|
|
9352
9538
|
await walkRepository(rootDir, fullPath, files);
|
|
@@ -9414,9 +9600,9 @@ function uniqueDestinationPath(basePath, sourcePath, usedPaths) {
|
|
|
9414
9600
|
usedPaths.add(basePath);
|
|
9415
9601
|
return basePath;
|
|
9416
9602
|
}
|
|
9417
|
-
const extension =
|
|
9418
|
-
const directory =
|
|
9419
|
-
const basename =
|
|
9603
|
+
const extension = path16.posix.extname(basePath) || ".md";
|
|
9604
|
+
const directory = path16.posix.dirname(basePath);
|
|
9605
|
+
const basename = path16.posix.basename(basePath, extension);
|
|
9420
9606
|
const uniquePath = `${directory}/${basename}-${hashText(sourcePath, 8)}${extension}`;
|
|
9421
9607
|
usedPaths.add(uniquePath);
|
|
9422
9608
|
return uniquePath;
|
|
@@ -9489,7 +9675,7 @@ function inferTitle2(content, repoPath) {
|
|
|
9489
9675
|
if (heading) return heading;
|
|
9490
9676
|
const htmlHeading = body.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1]?.replace(/<[^>]+>/g, "").trim();
|
|
9491
9677
|
if (htmlHeading) return htmlHeading;
|
|
9492
|
-
const basename =
|
|
9678
|
+
const basename = path16.posix.basename(repoPath, path16.posix.extname(repoPath)).replace(/[-_]+/g, " ").trim();
|
|
9493
9679
|
return titleCase(basename || "Imported Document");
|
|
9494
9680
|
}
|
|
9495
9681
|
function stripFrontmatter(content) {
|
|
@@ -9530,7 +9716,7 @@ async function runGit2(args) {
|
|
|
9530
9716
|
|
|
9531
9717
|
// src/runner-actions.ts
|
|
9532
9718
|
import { spawn as spawn4 } from "node:child_process";
|
|
9533
|
-
import
|
|
9719
|
+
import path17 from "node:path";
|
|
9534
9720
|
function buildBackgroundRunnerArgs(options) {
|
|
9535
9721
|
const args = [
|
|
9536
9722
|
"run",
|
|
@@ -9540,7 +9726,7 @@ function buildBackgroundRunnerArgs(options) {
|
|
|
9540
9726
|
"--runner-id",
|
|
9541
9727
|
options.runnerId,
|
|
9542
9728
|
"--root",
|
|
9543
|
-
|
|
9729
|
+
path17.resolve(options.root),
|
|
9544
9730
|
"--session",
|
|
9545
9731
|
options.session,
|
|
9546
9732
|
"--interval-seconds",
|
|
@@ -9664,8 +9850,8 @@ function truncateProcessOutput(value) {
|
|
|
9664
9850
|
|
|
9665
9851
|
// src/git-worktree.ts
|
|
9666
9852
|
import { execFile as execFile5 } from "node:child_process";
|
|
9667
|
-
import { copyFile, lstat, mkdir as
|
|
9668
|
-
import
|
|
9853
|
+
import { copyFile, lstat, mkdir as mkdir13, readdir as readdir7, stat as stat7 } from "node:fs/promises";
|
|
9854
|
+
import path18 from "node:path";
|
|
9669
9855
|
import { promisify as promisify5 } from "node:util";
|
|
9670
9856
|
var execFileAsync5 = promisify5(execFile5);
|
|
9671
9857
|
var exactLocalEnvironmentFiles = /* @__PURE__ */ new Set([".env", ".env.local", ".env.development", ".env.development.local", ".env.test", ".env.test.local", ".env.production", ".env.production.local"]);
|
|
@@ -9700,7 +9886,7 @@ async function prepareGitWorktreeIsolation(rootDir, workItem) {
|
|
|
9700
9886
|
return { ...identity, baseRevision, worktreePath, ...preparedLocalEnvironmentFileCount2 ? { preparedLocalEnvironmentFileCount: preparedLocalEnvironmentFileCount2 } : {} };
|
|
9701
9887
|
}
|
|
9702
9888
|
await repairMissingRegisteredWorktree(repoRoot, worktreePath, identity.branch, identity.worktreeKey);
|
|
9703
|
-
await
|
|
9889
|
+
await mkdir13(path18.dirname(worktreePath), { recursive: true });
|
|
9704
9890
|
const branchExists = await gitCommandSucceeds(repoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${identity.branch}`]);
|
|
9705
9891
|
const worktreeArgs = branchExists ? ["worktree", "add", worktreePath, identity.branch] : ["worktree", "add", "-b", identity.branch, worktreePath, baseRevision];
|
|
9706
9892
|
await gitOutput(repoRoot, worktreeArgs).catch((error) => {
|
|
@@ -9718,9 +9904,9 @@ async function resolveExistingGitWorktreeIsolation(rootDir, workItem) {
|
|
|
9718
9904
|
return { ...identity, baseRevision, worktreePath };
|
|
9719
9905
|
}
|
|
9720
9906
|
function localWorktreePath(repoRoot, worktreeKey) {
|
|
9721
|
-
const repoName =
|
|
9907
|
+
const repoName = path18.basename(repoRoot);
|
|
9722
9908
|
const worktreeSlug = worktreeKey.split("/").filter(Boolean).pop() ?? "work";
|
|
9723
|
-
return
|
|
9909
|
+
return path18.join(path18.dirname(repoRoot), `${repoName}.worktrees`, worktreeSlug);
|
|
9724
9910
|
}
|
|
9725
9911
|
async function assertExistingWorktree(worktreePath, branch) {
|
|
9726
9912
|
await gitOutput(worktreePath, ["rev-parse", "--is-inside-work-tree"]);
|
|
@@ -9783,7 +9969,7 @@ function parseRegisteredGitWorktrees(output) {
|
|
|
9783
9969
|
return worktrees;
|
|
9784
9970
|
}
|
|
9785
9971
|
function normalizeGitWorktreePath(value) {
|
|
9786
|
-
const resolved =
|
|
9972
|
+
const resolved = path18.resolve(value);
|
|
9787
9973
|
return resolved.startsWith("/private/var/") ? resolved.replace("/private/var/", "/var/") : resolved;
|
|
9788
9974
|
}
|
|
9789
9975
|
async function assertBaseRevision(repoRoot, baseRevision, currentHead) {
|
|
@@ -9803,8 +9989,8 @@ async function prepareLocalWorktreeEnvironment(repoRoot, worktreePath) {
|
|
|
9803
9989
|
const candidates = await localEnvironmentFileCandidates(repoRoot);
|
|
9804
9990
|
let preparedCount = 0;
|
|
9805
9991
|
for (const candidate of candidates) {
|
|
9806
|
-
const sourcePath =
|
|
9807
|
-
const targetPath =
|
|
9992
|
+
const sourcePath = path18.join(repoRoot, candidate);
|
|
9993
|
+
const targetPath = path18.join(worktreePath, candidate);
|
|
9808
9994
|
if (await pathExists(targetPath)) {
|
|
9809
9995
|
continue;
|
|
9810
9996
|
}
|
|
@@ -9835,7 +10021,7 @@ async function localEnvironmentFileCandidates(repoRoot) {
|
|
|
9835
10021
|
if (!isRootFileName(name)) {
|
|
9836
10022
|
continue;
|
|
9837
10023
|
}
|
|
9838
|
-
const source = await lstat(
|
|
10024
|
+
const source = await lstat(path18.join(repoRoot, name)).catch(() => void 0);
|
|
9839
10025
|
if (source?.isFile()) {
|
|
9840
10026
|
candidates.push(name);
|
|
9841
10027
|
}
|
|
@@ -9846,7 +10032,7 @@ function isAllowedLocalEnvironmentFile(name) {
|
|
|
9846
10032
|
return exactLocalEnvironmentFiles.has(name) || localEnvironmentFilePattern.test(name);
|
|
9847
10033
|
}
|
|
9848
10034
|
function isRootFileName(name) {
|
|
9849
|
-
return name ===
|
|
10035
|
+
return name === path18.basename(name) && !name.includes("/") && !name.includes("\\");
|
|
9850
10036
|
}
|
|
9851
10037
|
async function gitOutput(cwd, args) {
|
|
9852
10038
|
const { stdout } = await execFileAsync5("git", args, { cwd, maxBuffer: 1024 * 1024 });
|
|
@@ -9856,7 +10042,7 @@ async function gitCommandSucceeds(cwd, args) {
|
|
|
9856
10042
|
return execFileAsync5("git", args, { cwd }).then(() => true, () => false);
|
|
9857
10043
|
}
|
|
9858
10044
|
async function pathExists(value) {
|
|
9859
|
-
return
|
|
10045
|
+
return stat7(value).then(() => true, () => false);
|
|
9860
10046
|
}
|
|
9861
10047
|
function workIsolationSlug(scopeId, title) {
|
|
9862
10048
|
const scopeSlug = slugify(scopeId);
|
|
@@ -9879,7 +10065,7 @@ function safeFileError(error) {
|
|
|
9879
10065
|
|
|
9880
10066
|
// src/implementation-handoff.ts
|
|
9881
10067
|
import { execFile as execFile6 } from "node:child_process";
|
|
9882
|
-
import
|
|
10068
|
+
import path19 from "node:path";
|
|
9883
10069
|
import { promisify as promisify6 } from "node:util";
|
|
9884
10070
|
var execFileAsync6 = promisify6(execFile6);
|
|
9885
10071
|
var DEFAULT_IMPLEMENTATION_EXPECTED_OUTCOME = "sourceImplementation";
|
|
@@ -10333,7 +10519,7 @@ async function cleanupWorktree(run, input) {
|
|
|
10333
10519
|
return { status: "failed", message: "Cleanup skipped because the worktree is not clean after PR handoff." };
|
|
10334
10520
|
}
|
|
10335
10521
|
try {
|
|
10336
|
-
await gitOutput2(run, input.primaryRepoRoot ||
|
|
10522
|
+
await gitOutput2(run, input.primaryRepoRoot || path19.dirname(input.worktreePath), ["worktree", "remove", input.worktreePath]);
|
|
10337
10523
|
return { status: "completed" };
|
|
10338
10524
|
} catch (error) {
|
|
10339
10525
|
return { status: "failed", message: `Cleanup failed: ${safeErrorMessage(error)}` };
|
|
@@ -11036,7 +11222,7 @@ var DEFAULT_MAX_PREFLIGHT_ATTEMPTS = 3;
|
|
|
11036
11222
|
var DEFAULT_TOOL_TIMEOUT_SECONDS = 30 * 60;
|
|
11037
11223
|
var RUNNER_WORK_LEASE_SECONDS = 300;
|
|
11038
11224
|
var RUNNER_WORK_LEASE_RENEWAL_MS = 12e4;
|
|
11039
|
-
var MAX_CONCURRENT_RUNNER_WORK =
|
|
11225
|
+
var MAX_CONCURRENT_RUNNER_WORK = runnerMaxConcurrentWorkLimit;
|
|
11040
11226
|
var runnerSupportedWorkKinds = ["brainGeneration", "implementation", "promptBatch", "planRevision", "assistantQuestion", "impactPreview", "issueDiagnosis", "securityPostureScan", "appEvaluationScan", "brainConsolidationScan", "projectContextRefresh", "implementationVerification", "testQualityScan", "implementationTestGate"];
|
|
11041
11227
|
program.name("amistio").description("Amistio project brain CLI").version(CLI_VERSION);
|
|
11042
11228
|
program.command("init").description("Create Amistio control-plane folders for a new project").option("--root <path>", "Repository root", defaultRoot).action(async (options) => {
|
|
@@ -11151,7 +11337,7 @@ program.command("import").description("Pair an existing checkout and import lega
|
|
|
11151
11337
|
});
|
|
11152
11338
|
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) => {
|
|
11153
11339
|
const pairingRoot = await resolvePairingRoot(options.root, { explicitRoot: command.getOptionValueSource("root") === "cli" });
|
|
11154
|
-
let repositoryLinkId = options.repositoryLink ?? `repo_${
|
|
11340
|
+
let repositoryLinkId = options.repositoryLink ?? `repo_${randomUUID4()}`;
|
|
11155
11341
|
let credential = options.token;
|
|
11156
11342
|
if (options.pairingCode) {
|
|
11157
11343
|
const pairing = await new ApiClient({
|
|
@@ -11292,7 +11478,7 @@ sync.command("watch").description("Watch repository brain folders and auto-sync
|
|
|
11292
11478
|
console.log(`Auto-sync watcher stopped after ${iterations} polling attempt${iterations === 1 ? "" : "s"}.`);
|
|
11293
11479
|
return;
|
|
11294
11480
|
}
|
|
11295
|
-
await
|
|
11481
|
+
await delay2(options.intervalSeconds * 1e3);
|
|
11296
11482
|
}
|
|
11297
11483
|
});
|
|
11298
11484
|
var work = program.command("work").description("Inspect approved work items");
|
|
@@ -11337,7 +11523,7 @@ work.command("prompt").description("Print or write an approved work prompt witho
|
|
|
11337
11523
|
}
|
|
11338
11524
|
const prompt = await createRunnerWorkPrompt(context.client, context.metadata.amistioProjectId, workItem);
|
|
11339
11525
|
if (options.out) {
|
|
11340
|
-
await
|
|
11526
|
+
await writeFile13(options.out, prompt, "utf8");
|
|
11341
11527
|
console.log(`Wrote work prompt to ${options.out}.`);
|
|
11342
11528
|
} else {
|
|
11343
11529
|
console.log(prompt);
|
|
@@ -11447,7 +11633,7 @@ program.command("orchestrate").description("Update the Amistio control plane thr
|
|
|
11447
11633
|
...options.toolCommand ? { toolCommand: options.toolCommand } : {},
|
|
11448
11634
|
...localModelConfig,
|
|
11449
11635
|
streamOutput: options.stream,
|
|
11450
|
-
...sessionPolicy === "none" ? {} : { session: { toolSessionId: `local_orchestration_${
|
|
11636
|
+
...sessionPolicy === "none" ? {} : { session: { toolSessionId: `local_orchestration_${randomUUID4()}`, policy: sessionPolicy, decision: localSessionDecision(sessionPolicy) } }
|
|
11451
11637
|
});
|
|
11452
11638
|
if (!options.stream && result.stdout.trim()) {
|
|
11453
11639
|
console.log(result.stdout.trim());
|
|
@@ -11488,7 +11674,7 @@ program.command("run").description("Claim and run approved Amistio work locally"
|
|
|
11488
11674
|
projectId: context.metadata.amistioProjectId,
|
|
11489
11675
|
repositoryLinkId: context.metadata.repositoryLinkId,
|
|
11490
11676
|
runnerId,
|
|
11491
|
-
rootDir:
|
|
11677
|
+
rootDir: path20.resolve(options.root),
|
|
11492
11678
|
apiUrl: options.apiUrl,
|
|
11493
11679
|
args: buildBackgroundRunnerArgs(resolvedOptions)
|
|
11494
11680
|
});
|
|
@@ -11558,7 +11744,7 @@ program.command("run").description("Claim and run approved Amistio work locally"
|
|
|
11558
11744
|
console.log(`Runner stopped after ${iterations} polling attempt${iterations === 1 ? "" : "s"}.`);
|
|
11559
11745
|
return;
|
|
11560
11746
|
}
|
|
11561
|
-
await
|
|
11747
|
+
await delay2(options.intervalSeconds * 1e3);
|
|
11562
11748
|
}
|
|
11563
11749
|
} finally {
|
|
11564
11750
|
process.off("SIGINT", handleShutdownSignal);
|
|
@@ -11717,7 +11903,7 @@ runnerService.command("install").description("Install a user-level startup servi
|
|
|
11717
11903
|
projectId: context.metadata.amistioProjectId,
|
|
11718
11904
|
repositoryLinkId: context.metadata.repositoryLinkId,
|
|
11719
11905
|
runnerId,
|
|
11720
|
-
rootDir:
|
|
11906
|
+
rootDir: path20.resolve(options.root),
|
|
11721
11907
|
apiUrl: options.apiUrl,
|
|
11722
11908
|
args,
|
|
11723
11909
|
platform
|
|
@@ -12006,612 +12192,696 @@ async function runNextWorkItem({
|
|
|
12006
12192
|
}
|
|
12007
12193
|
return { status: "idle", exitCode: 0, nextAction, message };
|
|
12008
12194
|
}
|
|
12009
|
-
const
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
12018
|
-
await
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
const isolationTelemetry = workItemIsolationTelemetry(result.workItem, worktreeIsolation.isolation);
|
|
12027
|
-
const environmentReadiness = await checkRunnerExecutionEnvironment({
|
|
12028
|
-
executionRoot,
|
|
12029
|
-
primaryCheckoutRoot: root,
|
|
12030
|
-
profile: executionProfile,
|
|
12031
|
-
setupCommands: runnerEnvironmentSetupCommands(setupPackageManagerInstall),
|
|
12032
|
-
...result.workItem.workKind ? { workKind: result.workItem.workKind } : {},
|
|
12033
|
-
env: process.env
|
|
12034
|
-
});
|
|
12035
|
-
if (environmentReadiness.profile === "dockerWorkspace" && environmentReadiness.status === "ready") {
|
|
12036
|
-
environmentReadiness.status = "blocked";
|
|
12037
|
-
environmentReadiness.summary = "Runner execution environment dockerWorkspace is blocked: containerized harness execution is not enabled in this runner build.";
|
|
12038
|
-
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: [] });
|
|
12039
|
-
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: [] });
|
|
12040
|
-
}
|
|
12041
|
-
if (environmentReadiness.status === "blocked") {
|
|
12042
|
-
const statusResult2 = await apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "blocked", `environment_blocked_${result.workItem.workItemId}_${result.workItem.attempt}_${randomUUID3()}`, runnerId, {
|
|
12043
|
-
...isolationTelemetry,
|
|
12044
|
-
executionEnvironmentProfile: environmentReadiness.profile,
|
|
12045
|
-
executionEnvironmentReadiness: environmentReadiness,
|
|
12046
|
-
blockerReason: environmentReadiness.summary,
|
|
12047
|
-
message: environmentReadiness.summary
|
|
12195
|
+
const localActiveClaim = await defaultRunnerActiveClaimStore.reserve(runnerActiveClaimInput({
|
|
12196
|
+
accountId: commandContext.accountId,
|
|
12197
|
+
claimLaneId,
|
|
12198
|
+
repositoryLinkId,
|
|
12199
|
+
runnerId,
|
|
12200
|
+
toolTimeoutMs,
|
|
12201
|
+
workItem: result.workItem
|
|
12202
|
+
}));
|
|
12203
|
+
if (localActiveClaim.status === "blocked") {
|
|
12204
|
+
return await releaseSkippedLocalClaim({
|
|
12205
|
+
apiClient,
|
|
12206
|
+
claimLaneId,
|
|
12207
|
+
conflict: localActiveClaim,
|
|
12208
|
+
projectId,
|
|
12209
|
+
repositoryLinkId,
|
|
12210
|
+
runnerId,
|
|
12211
|
+
workItem: result.workItem
|
|
12048
12212
|
});
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
metadata: { executionEnvironmentProfile: environmentReadiness.profile, blockerReasons: environmentReadiness.blockers.map((blocker) => blocker.reason) }
|
|
12213
|
+
}
|
|
12214
|
+
const releaseLocalActiveClaim = async () => {
|
|
12215
|
+
await defaultRunnerActiveClaimStore.release(localActiveClaim.record.reservationId).catch((error) => {
|
|
12216
|
+
console.error(`Could not release local Amistio active-claim reservation for ${result.workItem?.workItemId}: ${truncateLogExcerpt(errorDetail(error))}`);
|
|
12054
12217
|
});
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
|
|
12218
|
+
};
|
|
12219
|
+
try {
|
|
12220
|
+
const prompt = await createRunnerWorkPrompt(apiClient, projectId, result.workItem);
|
|
12221
|
+
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12222
|
+
status: "running",
|
|
12223
|
+
summary: "Prepared local runner execution prompt.",
|
|
12224
|
+
idempotencyKey: `runner_milestone_prompt_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12225
|
+
metadata: { workKind: result.workItem.workKind ?? "implementation", attempt: result.workItem.attempt }
|
|
12064
12226
|
});
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
...
|
|
12082
|
-
|
|
12083
|
-
...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
|
|
12084
|
-
worktreePath: executionRoot
|
|
12227
|
+
if (dryRun || toolConfig.tool === "none") {
|
|
12228
|
+
console.log(prompt);
|
|
12229
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
|
|
12230
|
+
return { status: "preview", exitCode: 0 };
|
|
12231
|
+
}
|
|
12232
|
+
const worktreeIsolation = await prepareWorktreeForClaimedItem({ apiClient, heartbeatConcurrency, maxPreflightAttempts, projectId, repositoryLinkId, root, runnerId, toolConfig, workItem: result.workItem });
|
|
12233
|
+
if (worktreeIsolation.status !== "ready") {
|
|
12234
|
+
return { status: worktreeIsolation.status === "failed" ? "failed" : "blocked", exitCode: 1, message: worktreeIsolation.message };
|
|
12235
|
+
}
|
|
12236
|
+
const executionRoot = worktreeIsolation.isolation?.worktreePath ?? root;
|
|
12237
|
+
const isolationTelemetry = workItemIsolationTelemetry(result.workItem, worktreeIsolation.isolation);
|
|
12238
|
+
const environmentReadiness = await checkRunnerExecutionEnvironment({
|
|
12239
|
+
executionRoot,
|
|
12240
|
+
primaryCheckoutRoot: root,
|
|
12241
|
+
profile: executionProfile,
|
|
12242
|
+
setupCommands: runnerEnvironmentSetupCommands(setupPackageManagerInstall),
|
|
12243
|
+
...result.workItem.workKind ? { workKind: result.workItem.workKind } : {},
|
|
12244
|
+
env: process.env
|
|
12085
12245
|
});
|
|
12086
|
-
if (
|
|
12087
|
-
|
|
12088
|
-
|
|
12246
|
+
if (environmentReadiness.profile === "dockerWorkspace" && environmentReadiness.status === "ready") {
|
|
12247
|
+
environmentReadiness.status = "blocked";
|
|
12248
|
+
environmentReadiness.summary = "Runner execution environment dockerWorkspace is blocked: containerized harness execution is not enabled in this runner build.";
|
|
12249
|
+
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: [] });
|
|
12250
|
+
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: [] });
|
|
12251
|
+
}
|
|
12252
|
+
if (environmentReadiness.status === "blocked") {
|
|
12253
|
+
const statusResult2 = await apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "blocked", `environment_blocked_${result.workItem.workItemId}_${result.workItem.attempt}_${randomUUID4()}`, runnerId, {
|
|
12089
12254
|
...isolationTelemetry,
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12255
|
+
executionEnvironmentProfile: environmentReadiness.profile,
|
|
12256
|
+
executionEnvironmentReadiness: environmentReadiness,
|
|
12257
|
+
blockerReason: environmentReadiness.summary,
|
|
12258
|
+
message: environmentReadiness.summary
|
|
12094
12259
|
});
|
|
12095
12260
|
await recordRunnerMilestone(apiClient, projectId, statusResult2.workItem, runnerId, repositoryLinkId, {
|
|
12096
|
-
status: "
|
|
12097
|
-
summary:
|
|
12098
|
-
idempotencyKey: `
|
|
12099
|
-
metadata: {
|
|
12100
|
-
recoveryCategory: readinessHandoff.recovery?.category ?? "providerBlocked",
|
|
12101
|
-
executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
|
|
12102
|
-
executionBranch: isolationTelemetry.executionBranch ?? ""
|
|
12103
|
-
}
|
|
12261
|
+
status: "warning",
|
|
12262
|
+
summary: environmentReadiness.summary,
|
|
12263
|
+
idempotencyKey: `runner_milestone_environment_blocked_${result.workItem.workItemId}_${statusResult2.workItem.idempotencyKey}`,
|
|
12264
|
+
metadata: { executionEnvironmentProfile: environmentReadiness.profile, blockerReasons: environmentReadiness.blockers.map((blocker) => blocker.reason) }
|
|
12104
12265
|
});
|
|
12105
12266
|
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "blocked", {
|
|
12106
12267
|
...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
|
|
12107
12268
|
currentWorkItemId: result.workItem.workItemId,
|
|
12108
|
-
|
|
12269
|
+
currentExecutionEnvironmentProfile: environmentReadiness.profile,
|
|
12270
|
+
environmentReadiness,
|
|
12271
|
+
preferenceMessage: environmentReadiness.summary,
|
|
12109
12272
|
...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
|
|
12110
12273
|
...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
|
|
12111
12274
|
...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
|
|
12112
12275
|
});
|
|
12113
|
-
console.error(
|
|
12114
|
-
return { status: "blocked", exitCode: 1, message };
|
|
12276
|
+
console.error(environmentReadiness.summary);
|
|
12277
|
+
return { status: "blocked", exitCode: 1, message: environmentReadiness.summary };
|
|
12115
12278
|
}
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
harnessRequiresExclusiveRepository: preparedHarnessRun.concurrency.requiresExclusiveRepository,
|
|
12165
|
-
harnessRequiresExclusiveProviderAuth: preparedHarnessRun.concurrency.requiresExclusiveProviderAuth,
|
|
12166
|
-
harnessSerializedResourceKeys: preparedHarnessRun.concurrency.serializedResourceKeys
|
|
12279
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "running", {
|
|
12280
|
+
...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
|
|
12281
|
+
currentWorkItemId: result.workItem.workItemId,
|
|
12282
|
+
currentExecutionEnvironmentProfile: environmentReadiness.profile,
|
|
12283
|
+
environmentReadiness,
|
|
12284
|
+
...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
|
|
12285
|
+
...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
|
|
12286
|
+
...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
|
|
12287
|
+
});
|
|
12288
|
+
if (isImplementationHandoffWork(result.workItem)) {
|
|
12289
|
+
const repositoryLink = await loadWorkItemRepositoryLink(apiClient, projectId, result.workItem.repositoryLinkId ?? repositoryLinkId).catch(() => void 0);
|
|
12290
|
+
const readinessHandoff = await checkImplementationHandoffReadiness({
|
|
12291
|
+
primaryRepoRoot: root,
|
|
12292
|
+
...repositoryLink ? { repositoryLink } : {},
|
|
12293
|
+
workItem: result.workItem,
|
|
12294
|
+
...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
|
|
12295
|
+
worktreePath: executionRoot
|
|
12296
|
+
});
|
|
12297
|
+
if (readinessHandoff) {
|
|
12298
|
+
const message = readinessHandoff.message ?? "Implementation handoff readiness is blocked before local tool execution.";
|
|
12299
|
+
const statusResult2 = await apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "blocked", `handoff_readiness_blocked_${result.workItem.workItemId}_${result.workItem.attempt}_${randomUUID4()}`, runnerId, {
|
|
12300
|
+
...isolationTelemetry,
|
|
12301
|
+
implementationHandoff: readinessHandoff,
|
|
12302
|
+
blockerReason: message,
|
|
12303
|
+
message,
|
|
12304
|
+
...readinessHandoff.error ? { error: readinessHandoff.error } : {}
|
|
12305
|
+
});
|
|
12306
|
+
await recordRunnerMilestone(apiClient, projectId, statusResult2.workItem, runnerId, repositoryLinkId, {
|
|
12307
|
+
status: "blocked",
|
|
12308
|
+
summary: message,
|
|
12309
|
+
idempotencyKey: `runner_milestone_handoff_readiness_blocked_${result.workItem.workItemId}_${statusResult2.workItem.idempotencyKey}`,
|
|
12310
|
+
metadata: {
|
|
12311
|
+
recoveryCategory: readinessHandoff.recovery?.category ?? "providerBlocked",
|
|
12312
|
+
executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
|
|
12313
|
+
executionBranch: isolationTelemetry.executionBranch ?? ""
|
|
12314
|
+
}
|
|
12315
|
+
});
|
|
12316
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "blocked", {
|
|
12317
|
+
...runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency),
|
|
12318
|
+
currentWorkItemId: result.workItem.workItemId,
|
|
12319
|
+
preferenceMessage: message,
|
|
12320
|
+
...isolationTelemetry.implementationScopeId ? { currentImplementationScopeId: isolationTelemetry.implementationScopeId } : {},
|
|
12321
|
+
...isolationTelemetry.executionWorktreeKey ? { currentWorktreeKey: isolationTelemetry.executionWorktreeKey } : {},
|
|
12322
|
+
...isolationTelemetry.executionBranch ? { currentBranch: isolationTelemetry.executionBranch } : {}
|
|
12323
|
+
});
|
|
12324
|
+
console.error(message);
|
|
12325
|
+
return { status: "blocked", exitCode: 1, message };
|
|
12326
|
+
}
|
|
12167
12327
|
}
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
const providerSessionStore = new LocalToolSessionStore();
|
|
12171
|
-
const providerSessionId = sessionContext.toolSession ? await providerSessionStore.getProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName) : void 0;
|
|
12172
|
-
let toolResult;
|
|
12173
|
-
const stopLeaseRenewal = startWorkLeaseRenewal({ apiClient, projectId, repositoryLinkId, runnerId, toolConfig, workItem: result.workItem, telemetry: isolationTelemetry, heartbeatConcurrency });
|
|
12174
|
-
try {
|
|
12175
|
-
toolResult = await builtinAmistioHarnessAdapter.executeRun({
|
|
12176
|
-
preparedRun: preparedHarnessRun,
|
|
12328
|
+
const resolvedModelConfig = toolConfigModelOptions(toolConfig);
|
|
12329
|
+
const preparedHarnessRun = await builtinAmistioHarnessAdapter.createRunPreview({
|
|
12177
12330
|
rootDir: executionRoot,
|
|
12178
12331
|
prompt,
|
|
12179
12332
|
tool: toolConfig.tool,
|
|
12180
12333
|
invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
|
|
12181
12334
|
...toolCommand ? { toolCommand } : {},
|
|
12182
12335
|
...resolvedModelConfig,
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
policy: sessionContext.policy,
|
|
12189
|
-
decision: sessionContext.decision,
|
|
12190
|
-
...providerSessionId ? { providerSessionId } : {}
|
|
12191
|
-
}
|
|
12192
|
-
} : {}
|
|
12336
|
+
executionPolicy: {
|
|
12337
|
+
executionRoot,
|
|
12338
|
+
mutationPolicy: harnessMutationPolicyForWorkItem(result.workItem),
|
|
12339
|
+
claimLaneId
|
|
12340
|
+
}
|
|
12193
12341
|
});
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
sessionDecisionReason: sessionContext.reason
|
|
12214
|
-
}),
|
|
12215
|
-
recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12216
|
-
status: "failed",
|
|
12217
|
-
summary: message,
|
|
12218
|
-
idempotencyKey: `runner_milestone_tool_throw_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12219
|
-
metadata: { tool: preview.toolName, error: detail }
|
|
12220
|
-
})
|
|
12221
|
-
]);
|
|
12222
|
-
logRejectedSettlements("record local tool failure", settlements);
|
|
12223
|
-
if (verbose || !stream) {
|
|
12224
|
-
console.error(detail);
|
|
12342
|
+
const preview = preparedHarnessRun.preview;
|
|
12343
|
+
const sessionContext = await prepareToolSession({
|
|
12344
|
+
apiClient,
|
|
12345
|
+
projectId,
|
|
12346
|
+
repositoryLinkId,
|
|
12347
|
+
runnerId,
|
|
12348
|
+
machineId: runnerMachineId(),
|
|
12349
|
+
sessionPolicy: result.workItem.sessionPolicy ?? sessionPolicy,
|
|
12350
|
+
toolName: preview.toolName,
|
|
12351
|
+
...toolConfig.model ? { model: toolConfig.model } : {},
|
|
12352
|
+
supportsSessionReuse: preview.supportsSessionReuse,
|
|
12353
|
+
resumabilityScope: preview.resumabilityScope,
|
|
12354
|
+
workItem: result.workItem,
|
|
12355
|
+
isolationTelemetry
|
|
12356
|
+
});
|
|
12357
|
+
console.log(`Claimed ${result.workItem.workItemId}. Running ${preview.toolName}: ${preview.displayCommand}`);
|
|
12358
|
+
const autopilotClaimLine = formatAutopilotClaimLine(result.workItem);
|
|
12359
|
+
if (autopilotClaimLine) {
|
|
12360
|
+
console.log(autopilotClaimLine);
|
|
12225
12361
|
}
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
if (sessionContext.toolSession && toolResult.providerSessionId) {
|
|
12230
|
-
await providerSessionStore.setProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName, toolResult.providerSessionId);
|
|
12231
|
-
}
|
|
12232
|
-
if (!stream && toolResult.stdout.trim()) {
|
|
12233
|
-
console.log(toolResult.stdout.trim());
|
|
12234
|
-
}
|
|
12235
|
-
if (!stream && toolResult.stderr.trim()) {
|
|
12236
|
-
console.error(toolResult.stderr.trim());
|
|
12237
|
-
}
|
|
12238
|
-
if (result.workItem.workKind === "brainGeneration" || result.workItem.workKind === "planRevision") {
|
|
12239
|
-
try {
|
|
12240
|
-
return await finalizeBrainGenerationWork({
|
|
12241
|
-
apiClient,
|
|
12242
|
-
durationMs: Date.now() - startedAt,
|
|
12243
|
-
projectId,
|
|
12244
|
-
repositoryLinkId,
|
|
12245
|
-
runnerId,
|
|
12246
|
-
sessionContext,
|
|
12247
|
-
toolConfig,
|
|
12248
|
-
toolName: preview.toolName,
|
|
12249
|
-
toolResult,
|
|
12250
|
-
workItem: result.workItem
|
|
12251
|
-
});
|
|
12252
|
-
} catch (error) {
|
|
12253
|
-
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12362
|
+
const promptBatchClaimLine = formatPromptBatchClaimLine(result.workItem);
|
|
12363
|
+
if (promptBatchClaimLine) {
|
|
12364
|
+
console.log(promptBatchClaimLine);
|
|
12254
12365
|
}
|
|
12255
|
-
|
|
12256
|
-
|
|
12366
|
+
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12367
|
+
status: "running",
|
|
12368
|
+
summary: `Local runner started ${preview.toolName} execution.`,
|
|
12369
|
+
idempotencyKey: `runner_milestone_started_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12370
|
+
metadata: {
|
|
12371
|
+
tool: preview.toolName,
|
|
12372
|
+
invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
|
|
12373
|
+
claimLaneId: preparedHarnessRun.concurrency.claimLaneId,
|
|
12374
|
+
harnessSupportsConcurrentRuns: preparedHarnessRun.concurrency.supportsConcurrentRuns,
|
|
12375
|
+
harnessRequiresExclusiveRepository: preparedHarnessRun.concurrency.requiresExclusiveRepository,
|
|
12376
|
+
harnessRequiresExclusiveProviderAuth: preparedHarnessRun.concurrency.requiresExclusiveProviderAuth,
|
|
12377
|
+
harnessSerializedResourceKeys: preparedHarnessRun.concurrency.serializedResourceKeys
|
|
12378
|
+
}
|
|
12379
|
+
});
|
|
12380
|
+
const startedAt = Date.now();
|
|
12381
|
+
const providerSessionStore = new LocalToolSessionStore();
|
|
12382
|
+
const providerSessionId = sessionContext.toolSession ? await providerSessionStore.getProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName) : void 0;
|
|
12383
|
+
let toolResult;
|
|
12384
|
+
const stopLeaseRenewal = startWorkLeaseRenewal({ apiClient, projectId, repositoryLinkId, runnerId, toolConfig, workItem: result.workItem, telemetry: isolationTelemetry, heartbeatConcurrency });
|
|
12257
12385
|
try {
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
|
|
12386
|
+
toolResult = await builtinAmistioHarnessAdapter.executeRun({
|
|
12387
|
+
preparedRun: preparedHarnessRun,
|
|
12388
|
+
rootDir: executionRoot,
|
|
12389
|
+
prompt,
|
|
12390
|
+
tool: toolConfig.tool,
|
|
12391
|
+
invocationChannel: toolConfig.requestedInvocationChannel ?? "auto",
|
|
12392
|
+
...toolCommand ? { toolCommand } : {},
|
|
12393
|
+
...resolvedModelConfig,
|
|
12394
|
+
streamOutput: stream,
|
|
12395
|
+
timeoutMs: toolTimeoutMs,
|
|
12396
|
+
...sessionContext.toolSession ? {
|
|
12397
|
+
session: {
|
|
12398
|
+
toolSessionId: sessionContext.toolSession.toolSessionId,
|
|
12399
|
+
policy: sessionContext.policy,
|
|
12400
|
+
decision: sessionContext.decision,
|
|
12401
|
+
...providerSessionId ? { providerSessionId } : {}
|
|
12402
|
+
}
|
|
12403
|
+
} : {}
|
|
12269
12404
|
});
|
|
12270
12405
|
} catch (error) {
|
|
12271
|
-
|
|
12406
|
+
stopLeaseRenewal();
|
|
12407
|
+
const detail = truncateLogExcerpt(errorDetail(error));
|
|
12408
|
+
const durationMs2 = Date.now() - startedAt;
|
|
12409
|
+
const message = `${preview.toolName} failed before returning a result.`;
|
|
12410
|
+
const settlements = await Promise.allSettled([
|
|
12411
|
+
apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency)),
|
|
12412
|
+
markToolSessionBlocked(apiClient, projectId, sessionContext.toolSession, errorMessage7(error)),
|
|
12413
|
+
apiClient.updateWorkStatus(projectId, result.workItem.workItemId, "failed", `run_failed_${result.workItem.workItemId}_${result.workItem.attempt}_${runnerId}`, runnerId, {
|
|
12414
|
+
...isolationTelemetry,
|
|
12415
|
+
tool: preview.toolName,
|
|
12416
|
+
...toolConfig.model ? { model: toolConfig.model } : {},
|
|
12417
|
+
durationMs: durationMs2,
|
|
12418
|
+
message,
|
|
12419
|
+
error: detail,
|
|
12420
|
+
...result.workItem.workKind === "promptBatch" ? { promptBatch: finalizePromptBatchMetadata(result.workItem, "failed", detail) } : {},
|
|
12421
|
+
...sessionContext.toolSession ? { toolSessionId: sessionContext.toolSession.toolSessionId } : {},
|
|
12422
|
+
sessionPolicy: sessionContext.policy,
|
|
12423
|
+
sessionDecision: sessionContext.decision,
|
|
12424
|
+
sessionDecisionReason: sessionContext.reason
|
|
12425
|
+
}),
|
|
12426
|
+
recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12427
|
+
status: "failed",
|
|
12428
|
+
summary: message,
|
|
12429
|
+
idempotencyKey: `runner_milestone_tool_throw_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12430
|
+
metadata: { tool: preview.toolName, error: detail }
|
|
12431
|
+
})
|
|
12432
|
+
]);
|
|
12433
|
+
logRejectedSettlements("record local tool failure", settlements);
|
|
12434
|
+
if (verbose || !stream) {
|
|
12435
|
+
console.error(detail);
|
|
12436
|
+
}
|
|
12437
|
+
return { status: "failed", exitCode: 1, message };
|
|
12272
12438
|
}
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
return await finalizeImpactPreviewWork({
|
|
12277
|
-
apiClient,
|
|
12278
|
-
durationMs: Date.now() - startedAt,
|
|
12279
|
-
projectId,
|
|
12280
|
-
repositoryLinkId,
|
|
12281
|
-
root,
|
|
12282
|
-
runnerId,
|
|
12283
|
-
sessionContext,
|
|
12284
|
-
toolConfig,
|
|
12285
|
-
toolName: preview.toolName,
|
|
12286
|
-
toolResult,
|
|
12287
|
-
workItem: result.workItem
|
|
12288
|
-
});
|
|
12289
|
-
} catch (error) {
|
|
12290
|
-
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12439
|
+
stopLeaseRenewal();
|
|
12440
|
+
if (sessionContext.toolSession && toolResult.providerSessionId) {
|
|
12441
|
+
await providerSessionStore.setProviderSessionId(sessionContext.toolSession.toolSessionId, preview.toolName, toolResult.providerSessionId);
|
|
12291
12442
|
}
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
try {
|
|
12295
|
-
return await finalizeIssueDiagnosisWork({
|
|
12296
|
-
apiClient,
|
|
12297
|
-
durationMs: Date.now() - startedAt,
|
|
12298
|
-
projectId,
|
|
12299
|
-
repositoryLinkId,
|
|
12300
|
-
runnerId,
|
|
12301
|
-
sessionContext,
|
|
12302
|
-
toolConfig,
|
|
12303
|
-
toolName: preview.toolName,
|
|
12304
|
-
toolResult,
|
|
12305
|
-
workItem: result.workItem
|
|
12306
|
-
});
|
|
12307
|
-
} catch (error) {
|
|
12308
|
-
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12443
|
+
if (!stream && toolResult.stdout.trim()) {
|
|
12444
|
+
console.log(toolResult.stdout.trim());
|
|
12309
12445
|
}
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
try {
|
|
12313
|
-
return await finalizeSecurityPostureScanWork({
|
|
12314
|
-
apiClient,
|
|
12315
|
-
durationMs: Date.now() - startedAt,
|
|
12316
|
-
projectId,
|
|
12317
|
-
repositoryLinkId,
|
|
12318
|
-
runnerId,
|
|
12319
|
-
sessionContext,
|
|
12320
|
-
toolConfig,
|
|
12321
|
-
toolName: preview.toolName,
|
|
12322
|
-
toolResult,
|
|
12323
|
-
workItem: result.workItem
|
|
12324
|
-
});
|
|
12325
|
-
} catch (error) {
|
|
12326
|
-
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12446
|
+
if (!stream && toolResult.stderr.trim()) {
|
|
12447
|
+
console.error(toolResult.stderr.trim());
|
|
12327
12448
|
}
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
})
|
|
12343
|
-
|
|
12344
|
-
|
|
12449
|
+
if (result.workItem.workKind === "brainGeneration" || result.workItem.workKind === "planRevision") {
|
|
12450
|
+
try {
|
|
12451
|
+
return await finalizeBrainGenerationWork({
|
|
12452
|
+
apiClient,
|
|
12453
|
+
durationMs: Date.now() - startedAt,
|
|
12454
|
+
projectId,
|
|
12455
|
+
repositoryLinkId,
|
|
12456
|
+
runnerId,
|
|
12457
|
+
sessionContext,
|
|
12458
|
+
toolConfig,
|
|
12459
|
+
toolName: preview.toolName,
|
|
12460
|
+
toolResult,
|
|
12461
|
+
workItem: result.workItem
|
|
12462
|
+
});
|
|
12463
|
+
} catch (error) {
|
|
12464
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12465
|
+
}
|
|
12345
12466
|
}
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
})
|
|
12361
|
-
|
|
12362
|
-
|
|
12467
|
+
if (result.workItem.workKind === "assistantQuestion") {
|
|
12468
|
+
try {
|
|
12469
|
+
return await finalizeAssistantQuestionWork({
|
|
12470
|
+
apiClient,
|
|
12471
|
+
durationMs: Date.now() - startedAt,
|
|
12472
|
+
projectId,
|
|
12473
|
+
repositoryLinkId,
|
|
12474
|
+
runnerId,
|
|
12475
|
+
sessionContext,
|
|
12476
|
+
toolConfig,
|
|
12477
|
+
toolName: preview.toolName,
|
|
12478
|
+
toolResult,
|
|
12479
|
+
workItem: result.workItem
|
|
12480
|
+
});
|
|
12481
|
+
} catch (error) {
|
|
12482
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12483
|
+
}
|
|
12363
12484
|
}
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
})
|
|
12380
|
-
|
|
12381
|
-
|
|
12485
|
+
if (result.workItem.workKind === "impactPreview") {
|
|
12486
|
+
try {
|
|
12487
|
+
return await finalizeImpactPreviewWork({
|
|
12488
|
+
apiClient,
|
|
12489
|
+
durationMs: Date.now() - startedAt,
|
|
12490
|
+
projectId,
|
|
12491
|
+
repositoryLinkId,
|
|
12492
|
+
root,
|
|
12493
|
+
runnerId,
|
|
12494
|
+
sessionContext,
|
|
12495
|
+
toolConfig,
|
|
12496
|
+
toolName: preview.toolName,
|
|
12497
|
+
toolResult,
|
|
12498
|
+
workItem: result.workItem
|
|
12499
|
+
});
|
|
12500
|
+
} catch (error) {
|
|
12501
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12502
|
+
}
|
|
12382
12503
|
}
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|
|
12504
|
+
if (result.workItem.workKind === "issueDiagnosis") {
|
|
12505
|
+
try {
|
|
12506
|
+
return await finalizeIssueDiagnosisWork({
|
|
12507
|
+
apiClient,
|
|
12508
|
+
durationMs: Date.now() - startedAt,
|
|
12509
|
+
projectId,
|
|
12510
|
+
repositoryLinkId,
|
|
12511
|
+
runnerId,
|
|
12512
|
+
sessionContext,
|
|
12513
|
+
toolConfig,
|
|
12514
|
+
toolName: preview.toolName,
|
|
12515
|
+
toolResult,
|
|
12516
|
+
workItem: result.workItem
|
|
12517
|
+
});
|
|
12518
|
+
} catch (error) {
|
|
12519
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12520
|
+
}
|
|
12521
|
+
}
|
|
12522
|
+
if (result.workItem.workKind === "securityPostureScan") {
|
|
12523
|
+
try {
|
|
12524
|
+
return await finalizeSecurityPostureScanWork({
|
|
12525
|
+
apiClient,
|
|
12526
|
+
durationMs: Date.now() - startedAt,
|
|
12527
|
+
projectId,
|
|
12528
|
+
repositoryLinkId,
|
|
12529
|
+
runnerId,
|
|
12530
|
+
sessionContext,
|
|
12531
|
+
toolConfig,
|
|
12532
|
+
toolName: preview.toolName,
|
|
12533
|
+
toolResult,
|
|
12534
|
+
workItem: result.workItem
|
|
12535
|
+
});
|
|
12536
|
+
} catch (error) {
|
|
12537
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12538
|
+
}
|
|
12539
|
+
}
|
|
12540
|
+
if (result.workItem.workKind === "appEvaluationScan") {
|
|
12541
|
+
try {
|
|
12542
|
+
return await finalizeAppEvaluationScanWork({
|
|
12543
|
+
apiClient,
|
|
12544
|
+
durationMs: Date.now() - startedAt,
|
|
12545
|
+
projectId,
|
|
12546
|
+
repositoryLinkId,
|
|
12547
|
+
runnerId,
|
|
12548
|
+
sessionContext,
|
|
12549
|
+
toolConfig,
|
|
12550
|
+
toolName: preview.toolName,
|
|
12551
|
+
toolResult,
|
|
12552
|
+
workItem: result.workItem
|
|
12553
|
+
});
|
|
12554
|
+
} catch (error) {
|
|
12555
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12556
|
+
}
|
|
12557
|
+
}
|
|
12558
|
+
if (result.workItem.workKind === "brainConsolidationScan") {
|
|
12559
|
+
try {
|
|
12560
|
+
return await finalizeBrainConsolidationScanWork({
|
|
12561
|
+
apiClient,
|
|
12562
|
+
durationMs: Date.now() - startedAt,
|
|
12563
|
+
projectId,
|
|
12564
|
+
repositoryLinkId,
|
|
12565
|
+
runnerId,
|
|
12566
|
+
sessionContext,
|
|
12567
|
+
toolConfig,
|
|
12568
|
+
toolName: preview.toolName,
|
|
12569
|
+
toolResult,
|
|
12570
|
+
workItem: result.workItem
|
|
12571
|
+
});
|
|
12572
|
+
} catch (error) {
|
|
12573
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12574
|
+
}
|
|
12575
|
+
}
|
|
12576
|
+
if (result.workItem.workKind === "projectContextRefresh") {
|
|
12577
|
+
try {
|
|
12578
|
+
return await finalizeProjectContextRefreshWork({
|
|
12579
|
+
apiClient,
|
|
12580
|
+
durationMs: Date.now() - startedAt,
|
|
12581
|
+
executionRoot,
|
|
12582
|
+
projectId,
|
|
12583
|
+
repositoryLinkId,
|
|
12584
|
+
runnerId,
|
|
12585
|
+
sessionContext,
|
|
12586
|
+
toolConfig,
|
|
12587
|
+
toolName: preview.toolName,
|
|
12588
|
+
toolResult,
|
|
12589
|
+
workItem: result.workItem
|
|
12590
|
+
});
|
|
12591
|
+
} catch (error) {
|
|
12592
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12593
|
+
}
|
|
12594
|
+
}
|
|
12595
|
+
if (result.workItem.workKind === "implementationVerification") {
|
|
12596
|
+
try {
|
|
12597
|
+
return await finalizeImplementationVerificationWork({
|
|
12598
|
+
apiClient,
|
|
12599
|
+
durationMs: Date.now() - startedAt,
|
|
12600
|
+
projectId,
|
|
12601
|
+
repositoryLinkId,
|
|
12602
|
+
runnerId,
|
|
12603
|
+
sessionContext,
|
|
12604
|
+
toolConfig,
|
|
12605
|
+
toolName: preview.toolName,
|
|
12606
|
+
toolResult,
|
|
12607
|
+
workItem: result.workItem
|
|
12608
|
+
});
|
|
12609
|
+
} catch (error) {
|
|
12610
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12611
|
+
}
|
|
12612
|
+
}
|
|
12613
|
+
if (result.workItem.workKind === "testQualityScan") {
|
|
12614
|
+
try {
|
|
12615
|
+
return await finalizeTestQualityScanWork({
|
|
12616
|
+
apiClient,
|
|
12617
|
+
durationMs: Date.now() - startedAt,
|
|
12618
|
+
projectId,
|
|
12619
|
+
repositoryLinkId,
|
|
12620
|
+
runnerId,
|
|
12621
|
+
sessionContext,
|
|
12622
|
+
toolConfig,
|
|
12623
|
+
toolName: preview.toolName,
|
|
12624
|
+
toolResult,
|
|
12625
|
+
workItem: result.workItem
|
|
12626
|
+
});
|
|
12627
|
+
} catch (error) {
|
|
12628
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12629
|
+
}
|
|
12630
|
+
}
|
|
12631
|
+
if (result.workItem.workKind === "implementationTestGate") {
|
|
12632
|
+
try {
|
|
12633
|
+
return await finalizeImplementationTestGateWork({
|
|
12634
|
+
apiClient,
|
|
12635
|
+
durationMs: Date.now() - startedAt,
|
|
12636
|
+
projectId,
|
|
12637
|
+
repositoryLinkId,
|
|
12638
|
+
runnerId,
|
|
12639
|
+
sessionContext,
|
|
12640
|
+
toolConfig,
|
|
12641
|
+
toolName: preview.toolName,
|
|
12642
|
+
toolResult,
|
|
12643
|
+
workItem: result.workItem
|
|
12644
|
+
});
|
|
12645
|
+
} catch (error) {
|
|
12646
|
+
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12647
|
+
}
|
|
12648
|
+
}
|
|
12649
|
+
let finalStatus = toolResult.exitCode === 0 ? "completed" : "failed";
|
|
12650
|
+
const durationMs = Date.now() - startedAt;
|
|
12651
|
+
const promptBatchResult = result.workItem.workKind === "promptBatch" ? parsePromptBatchResultBestEffort(toolResult) : void 0;
|
|
12652
|
+
const promptBatchFinalStatus = promptBatchResult ? workStatusFromPromptBatchResult(promptBatchResult) : void 0;
|
|
12653
|
+
if (promptBatchFinalStatus && (toolResult.exitCode === 0 || promptBatchFinalStatus !== "completed")) {
|
|
12654
|
+
finalStatus = promptBatchFinalStatus;
|
|
12655
|
+
}
|
|
12656
|
+
const failureExcerpt = finalStatus === "completed" ? void 0 : truncateLogExcerpt(toolResult.stderr || toolResult.stdout);
|
|
12657
|
+
let implementationHandoff;
|
|
12658
|
+
let finalMessage = `${preview.toolName} exited with code ${toolResult.exitCode}.`;
|
|
12659
|
+
let finalError = failureExcerpt ?? promptBatchFailureReason(promptBatchResult);
|
|
12660
|
+
const patchDrift = finalStatus !== "completed" ? classifyPatchDriftToolResult(toolResult) : void 0;
|
|
12661
|
+
if (patchDrift) {
|
|
12662
|
+
finalStatus = "blocked";
|
|
12663
|
+
finalMessage = patchDrift.message;
|
|
12664
|
+
finalError = patchDrift.summary;
|
|
12665
|
+
implementationHandoff = {
|
|
12666
|
+
status: "blocked",
|
|
12667
|
+
cleanupStatus: "pending",
|
|
12668
|
+
message: patchDrift.message,
|
|
12669
|
+
error: patchDrift.summary,
|
|
12670
|
+
recovery: {
|
|
12671
|
+
category: "patchDrift",
|
|
12672
|
+
availableActions: ["requeueFreshAttempt", "exportHandoffDetails"],
|
|
12673
|
+
conflictFiles: [],
|
|
12674
|
+
summary: "The local patch did not match the current worktree context. Refresh context or queue a fresh linked attempt before retrying.",
|
|
12675
|
+
...isolationTelemetry.executionWorktreeKey ? { worktreeKey: isolationTelemetry.executionWorktreeKey } : {}
|
|
12676
|
+
}
|
|
12677
|
+
};
|
|
12678
|
+
}
|
|
12679
|
+
if (promptBatchResult && finalStatus !== "completed" && toolResult.exitCode === 0) {
|
|
12680
|
+
finalMessage = "Prompt batch reported a failed or blocked child prompt.";
|
|
12681
|
+
}
|
|
12682
|
+
if (finalStatus === "completed" && isImplementationHandoffWork(result.workItem)) {
|
|
12683
|
+
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12684
|
+
status: "running",
|
|
12685
|
+
summary: "Preparing GitHub PR handoff for implementation work.",
|
|
12686
|
+
idempotencyKey: `runner_milestone_handoff_started_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12687
|
+
metadata: { executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
|
|
12397
12688
|
});
|
|
12398
|
-
|
|
12399
|
-
|
|
12689
|
+
const repositoryLink = await loadWorkItemRepositoryLink(apiClient, projectId, result.workItem.repositoryLinkId ?? repositoryLinkId);
|
|
12690
|
+
const approvedArtifacts = await apiClient.listBrainDocuments(projectId).then((response) => response.documents).catch((error) => {
|
|
12691
|
+
implementationHandoff = {
|
|
12692
|
+
status: "blocked",
|
|
12693
|
+
cleanupStatus: "pending",
|
|
12694
|
+
artifacts: { included: [], skipped: [], blocked: [] },
|
|
12695
|
+
message: "Implementation handoff is blocked because approved artifact metadata could not be loaded.",
|
|
12696
|
+
error: truncateLogExcerpt(errorDetail(error))
|
|
12697
|
+
};
|
|
12698
|
+
return void 0;
|
|
12699
|
+
});
|
|
12700
|
+
if (!implementationHandoff) {
|
|
12701
|
+
implementationHandoff = await completeImplementationHandoff({
|
|
12702
|
+
...approvedArtifacts ? { approvedArtifacts } : {},
|
|
12703
|
+
primaryRepoRoot: root,
|
|
12704
|
+
...repositoryLink ? { repositoryLink } : {},
|
|
12705
|
+
verificationSummary: "Local execution reported completion.",
|
|
12706
|
+
workItem: result.workItem,
|
|
12707
|
+
...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
|
|
12708
|
+
worktreePath: executionRoot
|
|
12709
|
+
});
|
|
12710
|
+
}
|
|
12711
|
+
finalStatus = workStatusFromImplementationHandoff(implementationHandoff);
|
|
12712
|
+
finalMessage = implementationHandoff.message ?? "Implementation handoff finished.";
|
|
12713
|
+
finalError = implementationHandoff.error;
|
|
12400
12714
|
}
|
|
12401
|
-
|
|
12402
|
-
|
|
12715
|
+
const updatedToolSession = await finalizeToolSession({
|
|
12716
|
+
apiClient,
|
|
12717
|
+
projectId,
|
|
12718
|
+
status: toolResult.exitCode === 0 ? "completed" : "failed",
|
|
12719
|
+
runnerId,
|
|
12720
|
+
workItemId: result.workItem.workItemId,
|
|
12721
|
+
stdout: toolResult.stdout,
|
|
12722
|
+
...sessionContext.toolSession ? { session: sessionContext.toolSession } : {},
|
|
12723
|
+
...toolResult.messageCount !== void 0 ? { messageCount: toolResult.messageCount } : {},
|
|
12724
|
+
...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
|
|
12725
|
+
...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
|
|
12726
|
+
...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {}
|
|
12727
|
+
});
|
|
12728
|
+
let statusResult;
|
|
12729
|
+
const finalizationIdempotencyKey = `run_${result.workItem.workItemId}_${randomUUID4()}`;
|
|
12730
|
+
const finalizationTelemetry = {
|
|
12731
|
+
tool: preview.toolName,
|
|
12732
|
+
...toolResult.model ? { model: toolResult.model } : {},
|
|
12733
|
+
durationMs,
|
|
12734
|
+
message: finalMessage,
|
|
12735
|
+
...isolationTelemetry,
|
|
12736
|
+
...finalStatus === "blocked" ? { blockerReason: finalMessage } : {},
|
|
12737
|
+
sessionPolicy: sessionContext.policy,
|
|
12738
|
+
sessionDecision: sessionContext.decision,
|
|
12739
|
+
sessionDecisionReason: sessionContext.reason,
|
|
12740
|
+
...updatedToolSession ? { toolSessionId: updatedToolSession.toolSessionId } : {},
|
|
12741
|
+
...updatedToolSession?.sessionGroupKey ? { sessionGroupKey: updatedToolSession.sessionGroupKey } : {},
|
|
12742
|
+
...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
|
|
12743
|
+
...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
|
|
12744
|
+
...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {},
|
|
12745
|
+
...implementationHandoff ? { implementationHandoff } : {},
|
|
12746
|
+
...result.workItem.workKind === "promptBatch" ? { promptBatch: finalizePromptBatchMetadata(result.workItem, finalStatus, finalError, promptBatchResult) } : {},
|
|
12747
|
+
...finalError ? { error: finalError } : {}
|
|
12748
|
+
};
|
|
12403
12749
|
try {
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12750
|
+
const implementationFinalization = isNonMutatingImplementationOutcome(result.workItem) ? await submitNonMutatingImplementationCompletion(apiClient, {
|
|
12751
|
+
attempt: result.workItem.attempt,
|
|
12752
|
+
finalStatus,
|
|
12753
|
+
idempotencyKey: finalizationIdempotencyKey,
|
|
12407
12754
|
projectId,
|
|
12408
|
-
repositoryLinkId,
|
|
12409
12755
|
runnerId,
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
return recordFinalizationFailure({ apiClient, error, isolationTelemetry, projectId, repositoryLinkId, runnerId, sessionContext, toolConfig, toolName: preview.toolName, workItem: result.workItem, durationMs: Date.now() - startedAt });
|
|
12418
|
-
}
|
|
12419
|
-
}
|
|
12420
|
-
if (result.workItem.workKind === "implementationTestGate") {
|
|
12421
|
-
try {
|
|
12422
|
-
return await finalizeImplementationTestGateWork({
|
|
12423
|
-
apiClient,
|
|
12424
|
-
durationMs: Date.now() - startedAt,
|
|
12756
|
+
telemetry: finalizationTelemetry,
|
|
12757
|
+
workItemId: result.workItem.workItemId
|
|
12758
|
+
}) : await submitStagedImplementationFinalization(apiClient, {
|
|
12759
|
+
accountId: commandContext.accountId,
|
|
12760
|
+
attempt: result.workItem.attempt,
|
|
12761
|
+
finalStatus,
|
|
12762
|
+
idempotencyKey: finalizationIdempotencyKey,
|
|
12425
12763
|
projectId,
|
|
12426
12764
|
repositoryLinkId,
|
|
12427
12765
|
runnerId,
|
|
12428
|
-
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
toolResult,
|
|
12432
|
-
workItem: result.workItem
|
|
12766
|
+
telemetry: implementationFinalizationTelemetry(finalizationTelemetry),
|
|
12767
|
+
workItemId: result.workItem.workItemId,
|
|
12768
|
+
workKind: result.workItem.workKind === "promptBatch" ? "promptBatch" : "implementation"
|
|
12433
12769
|
});
|
|
12770
|
+
if (implementationFinalization.status === "failed") {
|
|
12771
|
+
if (implementationFinalization.retryable) {
|
|
12772
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency)).catch(() => void 0);
|
|
12773
|
+
return { status: "blocked", exitCode: 0, message: implementationFinalization.message };
|
|
12774
|
+
}
|
|
12775
|
+
throw new Error(implementationFinalization.message);
|
|
12776
|
+
}
|
|
12777
|
+
if (implementationFinalization.status === "deferred") {
|
|
12778
|
+
const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
|
|
12779
|
+
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12780
|
+
status: "queued",
|
|
12781
|
+
summary: gateMessage,
|
|
12782
|
+
idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12783
|
+
metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
|
|
12784
|
+
});
|
|
12785
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
|
|
12786
|
+
console.log(gateMessage);
|
|
12787
|
+
return { status: "blocked", exitCode: 0, message: gateMessage };
|
|
12788
|
+
}
|
|
12789
|
+
statusResult = { workItem: implementationFinalization.workItem };
|
|
12434
12790
|
} catch (error) {
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
let implementationHandoff;
|
|
12447
|
-
let finalMessage = `${preview.toolName} exited with code ${toolResult.exitCode}.`;
|
|
12448
|
-
let finalError = failureExcerpt ?? promptBatchFailureReason(promptBatchResult);
|
|
12449
|
-
const patchDrift = finalStatus !== "completed" ? classifyPatchDriftToolResult(toolResult) : void 0;
|
|
12450
|
-
if (patchDrift) {
|
|
12451
|
-
finalStatus = "blocked";
|
|
12452
|
-
finalMessage = patchDrift.message;
|
|
12453
|
-
finalError = patchDrift.summary;
|
|
12454
|
-
implementationHandoff = {
|
|
12455
|
-
status: "blocked",
|
|
12456
|
-
cleanupStatus: "pending",
|
|
12457
|
-
message: patchDrift.message,
|
|
12458
|
-
error: patchDrift.summary,
|
|
12459
|
-
recovery: {
|
|
12460
|
-
category: "patchDrift",
|
|
12461
|
-
availableActions: ["requeueFreshAttempt", "exportHandoffDetails"],
|
|
12462
|
-
conflictFiles: [],
|
|
12463
|
-
summary: "The local patch did not match the current worktree context. Refresh context or queue a fresh linked attempt before retrying.",
|
|
12464
|
-
...isolationTelemetry.executionWorktreeKey ? { worktreeKey: isolationTelemetry.executionWorktreeKey } : {}
|
|
12791
|
+
if (error instanceof AmistioApiError && error.status === 409 && error.detail.includes("implementation_test_gate_required")) {
|
|
12792
|
+
const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
|
|
12793
|
+
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12794
|
+
status: "queued",
|
|
12795
|
+
summary: gateMessage,
|
|
12796
|
+
idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12797
|
+
metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
|
|
12798
|
+
});
|
|
12799
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
|
|
12800
|
+
console.log(gateMessage);
|
|
12801
|
+
return { status: "blocked", exitCode: 0 };
|
|
12465
12802
|
}
|
|
12466
|
-
|
|
12467
|
-
|
|
12468
|
-
if (promptBatchResult && finalStatus !== "completed" && toolResult.exitCode === 0) {
|
|
12469
|
-
finalMessage = "Prompt batch reported a failed or blocked child prompt.";
|
|
12470
|
-
}
|
|
12471
|
-
if (finalStatus === "completed" && isImplementationHandoffWork(result.workItem)) {
|
|
12803
|
+
throw error;
|
|
12804
|
+
}
|
|
12472
12805
|
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12473
|
-
status:
|
|
12474
|
-
summary:
|
|
12475
|
-
idempotencyKey: `
|
|
12476
|
-
metadata: {
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12806
|
+
status: finalStatus,
|
|
12807
|
+
summary: finalMessage,
|
|
12808
|
+
idempotencyKey: `runner_milestone_finished_${result.workItem.workItemId}_${statusResult.workItem.idempotencyKey}`,
|
|
12809
|
+
metadata: {
|
|
12810
|
+
tool: preview.toolName,
|
|
12811
|
+
durationMs,
|
|
12812
|
+
exitCode: toolResult.exitCode,
|
|
12813
|
+
verificationSummary: finalStatus === "completed" ? "Local execution reported completion." : "Local execution reported failure.",
|
|
12814
|
+
executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
|
|
12815
|
+
executionBranch: isolationTelemetry.executionBranch ?? "",
|
|
12816
|
+
...implementationHandoff?.status ? { handoffStatus: implementationHandoff.status } : {},
|
|
12817
|
+
...implementationHandoff?.prUrl ? { prUrl: implementationHandoff.prUrl } : {},
|
|
12818
|
+
...implementationHandoff?.cleanupStatus ? { cleanupStatus: implementationHandoff.cleanupStatus } : {},
|
|
12819
|
+
...implementationHandoff?.artifacts ? artifactHandoffMetadata(implementationHandoff.artifacts) : {}
|
|
12820
|
+
}
|
|
12488
12821
|
});
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12492
|
-
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
workItem: result.workItem,
|
|
12496
|
-
...worktreeIsolation.isolation ? { worktreeIsolation: worktreeIsolation.isolation } : {},
|
|
12497
|
-
worktreePath: executionRoot
|
|
12498
|
-
});
|
|
12499
|
-
}
|
|
12500
|
-
finalStatus = workStatusFromImplementationHandoff(implementationHandoff);
|
|
12501
|
-
finalMessage = implementationHandoff.message ?? "Implementation handoff finished.";
|
|
12502
|
-
finalError = implementationHandoff.error;
|
|
12822
|
+
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
|
|
12823
|
+
const durationSeconds = Math.round(durationMs / 1e3);
|
|
12824
|
+
console.log(`Marked ${statusResult.workItem.workItemId} ${statusResult.workItem.status} after ${durationSeconds}s.`);
|
|
12825
|
+
return { status: finalStatus, exitCode: finalStatus === "completed" ? toolResult.exitCode : 1 };
|
|
12826
|
+
} finally {
|
|
12827
|
+
await releaseLocalActiveClaim();
|
|
12503
12828
|
}
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
|
|
12507
|
-
|
|
12829
|
+
}
|
|
12830
|
+
function runnerActiveClaimInput({ accountId, claimLaneId, repositoryLinkId, runnerId, toolTimeoutMs, workItem }) {
|
|
12831
|
+
const identity = needsGitWorktreeIsolation(workItem) ? resolveWorktreeIdentity(workItem) : void 0;
|
|
12832
|
+
const implementationScopeId = identity?.implementationScopeId ?? workItem.implementationScopeId;
|
|
12833
|
+
const worktreeKey = identity?.worktreeKey ?? workItem.executionWorktreeKey;
|
|
12834
|
+
const executionBranch = identity?.branch ?? workItem.executionBranch;
|
|
12835
|
+
const expiresAtMs = Date.now() + Math.max(toolTimeoutMs, RUNNER_WORK_LEASE_SECONDS * 1e3) + RUNNER_WORK_LEASE_SECONDS * 1e3;
|
|
12836
|
+
return {
|
|
12837
|
+
accountId,
|
|
12838
|
+
projectId: workItem.projectId,
|
|
12839
|
+
repositoryLinkId: workItem.repositoryLinkId ?? repositoryLinkId,
|
|
12508
12840
|
runnerId,
|
|
12509
|
-
|
|
12510
|
-
|
|
12511
|
-
...
|
|
12512
|
-
|
|
12513
|
-
...
|
|
12514
|
-
...
|
|
12515
|
-
...
|
|
12516
|
-
|
|
12517
|
-
let statusResult;
|
|
12518
|
-
const finalizationIdempotencyKey = `run_${result.workItem.workItemId}_${randomUUID3()}`;
|
|
12519
|
-
const finalizationTelemetry = {
|
|
12520
|
-
tool: preview.toolName,
|
|
12521
|
-
...toolResult.model ? { model: toolResult.model } : {},
|
|
12522
|
-
durationMs,
|
|
12523
|
-
message: finalMessage,
|
|
12524
|
-
...isolationTelemetry,
|
|
12525
|
-
...finalStatus === "blocked" ? { blockerReason: finalMessage } : {},
|
|
12526
|
-
sessionPolicy: sessionContext.policy,
|
|
12527
|
-
sessionDecision: sessionContext.decision,
|
|
12528
|
-
sessionDecisionReason: sessionContext.reason,
|
|
12529
|
-
...updatedToolSession ? { toolSessionId: updatedToolSession.toolSessionId } : {},
|
|
12530
|
-
...updatedToolSession?.sessionGroupKey ? { sessionGroupKey: updatedToolSession.sessionGroupKey } : {},
|
|
12531
|
-
...toolResult.tokensIn !== void 0 ? { tokensIn: toolResult.tokensIn } : {},
|
|
12532
|
-
...toolResult.tokensOut !== void 0 ? { tokensOut: toolResult.tokensOut } : {},
|
|
12533
|
-
...toolResult.costUsd !== void 0 ? { costUsd: toolResult.costUsd } : {},
|
|
12534
|
-
...implementationHandoff ? { implementationHandoff } : {},
|
|
12535
|
-
...result.workItem.workKind === "promptBatch" ? { promptBatch: finalizePromptBatchMetadata(result.workItem, finalStatus, finalError, promptBatchResult) } : {},
|
|
12536
|
-
...finalError ? { error: finalError } : {}
|
|
12841
|
+
claimLaneId,
|
|
12842
|
+
workItemId: workItem.workItemId,
|
|
12843
|
+
...workItem.claimLeaseId ? { claimLeaseId: workItem.claimLeaseId } : {},
|
|
12844
|
+
attempt: workItem.attempt,
|
|
12845
|
+
...implementationScopeId ? { implementationScopeId } : {},
|
|
12846
|
+
...worktreeKey ? { worktreeKey } : {},
|
|
12847
|
+
...executionBranch ? { executionBranch } : {},
|
|
12848
|
+
expiresAt: new Date(expiresAtMs).toISOString()
|
|
12537
12849
|
};
|
|
12538
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12850
|
+
}
|
|
12851
|
+
async function releaseSkippedLocalClaim({ apiClient, claimLaneId, conflict, projectId, repositoryLinkId, runnerId, workItem }) {
|
|
12852
|
+
const message = activeClaimConflictMessage(conflict);
|
|
12853
|
+
await apiClient.updateWorkStatus(projectId, workItem.workItemId, "approved", `local_claim_conflict_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`, runnerId, {
|
|
12854
|
+
...workItemIsolationTelemetry(workItem, void 0),
|
|
12855
|
+
claimLaneId,
|
|
12856
|
+
message,
|
|
12857
|
+
releaseClaim: true
|
|
12858
|
+
}).catch(async (error) => {
|
|
12859
|
+
await apiClient.recordRunnerLog(projectId, {
|
|
12544
12860
|
runnerId,
|
|
12545
|
-
telemetry: finalizationTelemetry,
|
|
12546
|
-
workItemId: result.workItem.workItemId
|
|
12547
|
-
}) : await submitStagedImplementationFinalization(apiClient, {
|
|
12548
|
-
accountId: commandContext.accountId,
|
|
12549
|
-
attempt: result.workItem.attempt,
|
|
12550
|
-
finalStatus,
|
|
12551
|
-
idempotencyKey: finalizationIdempotencyKey,
|
|
12552
|
-
projectId,
|
|
12553
12861
|
repositoryLinkId,
|
|
12554
|
-
|
|
12555
|
-
|
|
12556
|
-
|
|
12557
|
-
workKind:
|
|
12558
|
-
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
}
|
|
12564
|
-
throw new Error(implementationFinalization.message);
|
|
12565
|
-
}
|
|
12566
|
-
if (implementationFinalization.status === "deferred") {
|
|
12567
|
-
const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
|
|
12568
|
-
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12569
|
-
status: "queued",
|
|
12570
|
-
summary: gateMessage,
|
|
12571
|
-
idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12572
|
-
metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
|
|
12573
|
-
});
|
|
12574
|
-
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
|
|
12575
|
-
console.log(gateMessage);
|
|
12576
|
-
return { status: "blocked", exitCode: 0, message: gateMessage };
|
|
12577
|
-
}
|
|
12578
|
-
statusResult = { workItem: implementationFinalization.workItem };
|
|
12579
|
-
} catch (error) {
|
|
12580
|
-
if (error instanceof AmistioApiError && error.status === 409 && error.detail.includes("implementation_test_gate_required")) {
|
|
12581
|
-
const gateMessage = "Implementation test gate was queued and must pass before completion or PR handoff is finalized.";
|
|
12582
|
-
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12583
|
-
status: "queued",
|
|
12584
|
-
summary: gateMessage,
|
|
12585
|
-
idempotencyKey: `runner_milestone_test_gate_required_${result.workItem.workItemId}_${result.workItem.attempt}`,
|
|
12586
|
-
metadata: { tool: preview.toolName, durationMs, executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "", executionBranch: isolationTelemetry.executionBranch ?? "" }
|
|
12587
|
-
});
|
|
12588
|
-
await apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig, currentRunnerMode(), heartbeatConcurrency));
|
|
12589
|
-
console.log(gateMessage);
|
|
12590
|
-
return { status: "blocked", exitCode: 0 };
|
|
12591
|
-
}
|
|
12592
|
-
throw error;
|
|
12593
|
-
}
|
|
12594
|
-
await recordRunnerMilestone(apiClient, projectId, result.workItem, runnerId, repositoryLinkId, {
|
|
12595
|
-
status: finalStatus,
|
|
12596
|
-
summary: finalMessage,
|
|
12597
|
-
idempotencyKey: `runner_milestone_finished_${result.workItem.workItemId}_${statusResult.workItem.idempotencyKey}`,
|
|
12598
|
-
metadata: {
|
|
12599
|
-
tool: preview.toolName,
|
|
12600
|
-
durationMs,
|
|
12601
|
-
exitCode: toolResult.exitCode,
|
|
12602
|
-
verificationSummary: finalStatus === "completed" ? "Local execution reported completion." : "Local execution reported failure.",
|
|
12603
|
-
executionWorktreeKey: isolationTelemetry.executionWorktreeKey ?? "",
|
|
12604
|
-
executionBranch: isolationTelemetry.executionBranch ?? "",
|
|
12605
|
-
...implementationHandoff?.status ? { handoffStatus: implementationHandoff.status } : {},
|
|
12606
|
-
...implementationHandoff?.prUrl ? { prUrl: implementationHandoff.prUrl } : {},
|
|
12607
|
-
...implementationHandoff?.cleanupStatus ? { cleanupStatus: implementationHandoff.cleanupStatus } : {},
|
|
12608
|
-
...implementationHandoff?.artifacts ? artifactHandoffMetadata(implementationHandoff.artifacts) : {}
|
|
12609
|
-
}
|
|
12862
|
+
status: "blocked",
|
|
12863
|
+
workItemId: workItem.workItemId,
|
|
12864
|
+
workTitle: workItem.title,
|
|
12865
|
+
...workItem.workKind ? { workKind: workItem.workKind } : {},
|
|
12866
|
+
...claimLaneId ? { claimLaneId } : {},
|
|
12867
|
+
message: "Runner skipped a locally conflicting active claim but could not release the server claim.",
|
|
12868
|
+
error: truncateLogExcerpt(errorDetail(error)),
|
|
12869
|
+
machineId: runnerMachineId()
|
|
12870
|
+
}).catch(() => void 0);
|
|
12610
12871
|
});
|
|
12611
|
-
await apiClient.
|
|
12612
|
-
|
|
12613
|
-
|
|
12614
|
-
|
|
12872
|
+
await apiClient.recordRunnerLog(projectId, {
|
|
12873
|
+
runnerId,
|
|
12874
|
+
repositoryLinkId,
|
|
12875
|
+
status: "blocked",
|
|
12876
|
+
workItemId: workItem.workItemId,
|
|
12877
|
+
workTitle: workItem.title,
|
|
12878
|
+
...workItem.workKind ? { workKind: workItem.workKind } : {},
|
|
12879
|
+
...claimLaneId ? { claimLaneId } : {},
|
|
12880
|
+
message,
|
|
12881
|
+
machineId: runnerMachineId()
|
|
12882
|
+
}).catch(() => void 0);
|
|
12883
|
+
console.error(message);
|
|
12884
|
+
return { status: "idle", exitCode: 0, message };
|
|
12615
12885
|
}
|
|
12616
12886
|
function artifactHandoffMetadata(artifacts) {
|
|
12617
12887
|
return {
|
|
@@ -12657,7 +12927,7 @@ async function prepareWorktreeForClaimedItem({ apiClient, heartbeatConcurrency,
|
|
|
12657
12927
|
const telemetry = workItemIsolationTelemetry(workItem, { ...identity, baseRevision: workItem.baseRevision ?? "unknown", worktreePath: "" });
|
|
12658
12928
|
const finalAttempt = workItem.attempt >= maxPreflightAttempts;
|
|
12659
12929
|
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}`;
|
|
12660
|
-
const statusResult = await apiClient.updateWorkStatus(projectId, workItem.workItemId, finalAttempt ? "failed" : "approved", `worktree_${finalAttempt ? "failed" : "retry"}_${workItem.workItemId}_${workItem.attempt}_${
|
|
12930
|
+
const statusResult = await apiClient.updateWorkStatus(projectId, workItem.workItemId, finalAttempt ? "failed" : "approved", `worktree_${finalAttempt ? "failed" : "retry"}_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`, runnerId, {
|
|
12661
12931
|
...telemetry,
|
|
12662
12932
|
message: statusMessage,
|
|
12663
12933
|
...finalAttempt ? { blockerReason: message } : { releaseClaim: true },
|
|
@@ -12726,7 +12996,7 @@ async function recordFinalizationFailure({ apiClient, durationMs, error, isolati
|
|
|
12726
12996
|
const settlements = await Promise.allSettled([
|
|
12727
12997
|
apiClient.sendRunnerHeartbeat(projectId, runnerId, repositoryLinkId, "online", runnerHeartbeatMetadata(toolConfig)),
|
|
12728
12998
|
markToolSessionBlocked(apiClient, projectId, sessionContext.toolSession, errorMessage7(error)),
|
|
12729
|
-
apiClient.updateWorkStatus(projectId, workItem.workItemId, "failed", `finalize_failed_${workItem.workItemId}_${workItem.attempt}_${
|
|
12999
|
+
apiClient.updateWorkStatus(projectId, workItem.workItemId, "failed", `finalize_failed_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`, runnerId, {
|
|
12730
13000
|
...isolationTelemetry,
|
|
12731
13001
|
tool: toolName,
|
|
12732
13002
|
durationMs,
|
|
@@ -12963,7 +13233,7 @@ async function updateRunnerCommandStatus(apiClient, context, command, status, me
|
|
|
12963
13233
|
runnerId: context.runnerId,
|
|
12964
13234
|
repositoryLinkId: context.repositoryLinkId,
|
|
12965
13235
|
status,
|
|
12966
|
-
idempotencyKey: `runner_command_${command.commandId}_${status}_${
|
|
13236
|
+
idempotencyKey: `runner_command_${command.commandId}_${status}_${randomUUID4()}`,
|
|
12967
13237
|
message,
|
|
12968
13238
|
...error ? { error } : {},
|
|
12969
13239
|
...providerAuthStatus ? { providerAuthStatus } : {}
|
|
@@ -13055,7 +13325,7 @@ async function findRecoveryWorkItem(apiClient, projectId, workItemId) {
|
|
|
13055
13325
|
return workItems.find((item) => item.workItemId === workItemId);
|
|
13056
13326
|
}
|
|
13057
13327
|
async function submitRecoveredHandoff(apiClient, context, workItem, handoff, action) {
|
|
13058
|
-
await apiClient.updateWorkStatus(context.projectId, workItem.workItemId, recoveredHandoffWorkStatus(handoff), `handoff_recovery_${workItem.workItemId}_${action}_${
|
|
13328
|
+
await apiClient.updateWorkStatus(context.projectId, workItem.workItemId, recoveredHandoffWorkStatus(handoff), `handoff_recovery_${workItem.workItemId}_${action}_${randomUUID4()}`, context.runnerId, {
|
|
13059
13329
|
implementationHandoff: handoff,
|
|
13060
13330
|
...handoff.message ? { message: handoff.message } : {},
|
|
13061
13331
|
...workItem.controllingAdrId ? { controllingAdrId: workItem.controllingAdrId } : {},
|
|
@@ -13243,7 +13513,8 @@ async function submitImplementationFinalizationEntry(apiClient, entry, options =
|
|
|
13243
13513
|
...entry.telemetry,
|
|
13244
13514
|
message: message2,
|
|
13245
13515
|
blockerReason: message2,
|
|
13246
|
-
releaseClaim: true
|
|
13516
|
+
releaseClaim: true,
|
|
13517
|
+
releaseReason: "implementationTestGatePending"
|
|
13247
13518
|
}).catch((releaseError) => {
|
|
13248
13519
|
console.error(`Could not release implementation work ${entry.workItemId} while waiting for its test gate: ${truncateLogExcerpt(errorMessage7(releaseError))}`);
|
|
13249
13520
|
});
|
|
@@ -13453,7 +13724,7 @@ ${toolResult.stderr}`);
|
|
|
13453
13724
|
const resultMutation = {
|
|
13454
13725
|
status: "completed",
|
|
13455
13726
|
runnerId,
|
|
13456
|
-
idempotencyKey: `generation_${workItem.workItemId}_${workItem.attempt}_${
|
|
13727
|
+
idempotencyKey: `generation_${workItem.workItemId}_${workItem.attempt}_${randomUUID4()}`,
|
|
13457
13728
|
artifacts,
|
|
13458
13729
|
tool: toolName,
|
|
13459
13730
|
durationMs,
|
|
@@ -13528,7 +13799,7 @@ ${toolResult.stderr}`);
|
|
|
13528
13799
|
const failedResult2 = await apiClient.submitBrainGenerationResult(projectId, workItem.workItemId, {
|
|
13529
13800
|
status: "failed",
|
|
13530
13801
|
runnerId,
|
|
13531
|
-
idempotencyKey: `generation_${workItem.workItemId}_${
|
|
13802
|
+
idempotencyKey: `generation_${workItem.workItemId}_${randomUUID4()}`,
|
|
13532
13803
|
tool: toolName,
|
|
13533
13804
|
durationMs,
|
|
13534
13805
|
...failedSessionTelemetry,
|
|
@@ -13578,7 +13849,7 @@ ${toolResult.stderr}`);
|
|
|
13578
13849
|
const resultMutation = {
|
|
13579
13850
|
status: "completed",
|
|
13580
13851
|
runnerId,
|
|
13581
|
-
idempotencyKey: `assistant_${workItem.workItemId}_${
|
|
13852
|
+
idempotencyKey: `assistant_${workItem.workItemId}_${randomUUID4()}`,
|
|
13582
13853
|
answer: answerResult.answer,
|
|
13583
13854
|
sourceBoundary: answerResult.sourceBoundary,
|
|
13584
13855
|
citations: answerResult.citations,
|
|
@@ -13614,7 +13885,7 @@ ${toolResult.stderr}`);
|
|
|
13614
13885
|
const failedMutation = {
|
|
13615
13886
|
status: "failed",
|
|
13616
13887
|
runnerId,
|
|
13617
|
-
idempotencyKey: `assistant_${workItem.workItemId}_${
|
|
13888
|
+
idempotencyKey: `assistant_${workItem.workItemId}_${randomUUID4()}`,
|
|
13618
13889
|
tool: toolName,
|
|
13619
13890
|
durationMs,
|
|
13620
13891
|
...sessionTelemetry,
|
|
@@ -13677,7 +13948,7 @@ ${toolResult.stderr}`);
|
|
|
13677
13948
|
const resultMutation = {
|
|
13678
13949
|
status: "completed",
|
|
13679
13950
|
runnerId,
|
|
13680
|
-
idempotencyKey: `impact_${workItem.workItemId}_${
|
|
13951
|
+
idempotencyKey: `impact_${workItem.workItemId}_${randomUUID4()}`,
|
|
13681
13952
|
report: {
|
|
13682
13953
|
...report,
|
|
13683
13954
|
analyzedRepoRevision: report.analyzedRepoRevision ?? metadata?.lastSyncedRevision
|
|
@@ -13714,7 +13985,7 @@ ${toolResult.stderr}`);
|
|
|
13714
13985
|
const failedMutation = {
|
|
13715
13986
|
status: "failed",
|
|
13716
13987
|
runnerId,
|
|
13717
|
-
idempotencyKey: `impact_${workItem.workItemId}_${
|
|
13988
|
+
idempotencyKey: `impact_${workItem.workItemId}_${randomUUID4()}`,
|
|
13718
13989
|
tool: toolName,
|
|
13719
13990
|
durationMs,
|
|
13720
13991
|
...sessionTelemetry,
|
|
@@ -13775,7 +14046,7 @@ ${toolResult.stderr}`);
|
|
|
13775
14046
|
const resultMutation = {
|
|
13776
14047
|
status: "completed",
|
|
13777
14048
|
runnerId,
|
|
13778
|
-
idempotencyKey: `issue_${workItem.workItemId}_${
|
|
14049
|
+
idempotencyKey: `issue_${workItem.workItemId}_${randomUUID4()}`,
|
|
13779
14050
|
diagnosis,
|
|
13780
14051
|
tool: toolName,
|
|
13781
14052
|
durationMs,
|
|
@@ -13809,7 +14080,7 @@ ${toolResult.stderr}`);
|
|
|
13809
14080
|
const failedMutation = {
|
|
13810
14081
|
status: "failed",
|
|
13811
14082
|
runnerId,
|
|
13812
|
-
idempotencyKey: `issue_${workItem.workItemId}_${
|
|
14083
|
+
idempotencyKey: `issue_${workItem.workItemId}_${randomUUID4()}`,
|
|
13813
14084
|
tool: toolName,
|
|
13814
14085
|
durationMs,
|
|
13815
14086
|
...sessionTelemetry,
|
|
@@ -13870,7 +14141,7 @@ ${toolResult.stderr}`);
|
|
|
13870
14141
|
const resultMutation = {
|
|
13871
14142
|
status: "completed",
|
|
13872
14143
|
runnerId,
|
|
13873
|
-
idempotencyKey: `security_${workItem.workItemId}_${
|
|
14144
|
+
idempotencyKey: `security_${workItem.workItemId}_${randomUUID4()}`,
|
|
13874
14145
|
result: scanResult,
|
|
13875
14146
|
tool: toolName,
|
|
13876
14147
|
durationMs,
|
|
@@ -13904,7 +14175,7 @@ ${toolResult.stderr}`);
|
|
|
13904
14175
|
const failedMutation = {
|
|
13905
14176
|
status: "failed",
|
|
13906
14177
|
runnerId,
|
|
13907
|
-
idempotencyKey: `security_${workItem.workItemId}_${
|
|
14178
|
+
idempotencyKey: `security_${workItem.workItemId}_${randomUUID4()}`,
|
|
13908
14179
|
tool: toolName,
|
|
13909
14180
|
durationMs,
|
|
13910
14181
|
...sessionTelemetry,
|
|
@@ -13965,7 +14236,7 @@ ${toolResult.stderr}`);
|
|
|
13965
14236
|
const resultMutation = {
|
|
13966
14237
|
status: "completed",
|
|
13967
14238
|
runnerId,
|
|
13968
|
-
idempotencyKey: `app_evaluation_${workItem.workItemId}_${
|
|
14239
|
+
idempotencyKey: `app_evaluation_${workItem.workItemId}_${randomUUID4()}`,
|
|
13969
14240
|
result: scanResult,
|
|
13970
14241
|
tool: toolName,
|
|
13971
14242
|
durationMs,
|
|
@@ -13999,7 +14270,7 @@ ${toolResult.stderr}`);
|
|
|
13999
14270
|
const failedMutation = {
|
|
14000
14271
|
status: "failed",
|
|
14001
14272
|
runnerId,
|
|
14002
|
-
idempotencyKey: `app_evaluation_${workItem.workItemId}_${
|
|
14273
|
+
idempotencyKey: `app_evaluation_${workItem.workItemId}_${randomUUID4()}`,
|
|
14003
14274
|
tool: toolName,
|
|
14004
14275
|
durationMs,
|
|
14005
14276
|
...sessionTelemetry,
|
|
@@ -14060,7 +14331,7 @@ ${toolResult.stderr}`);
|
|
|
14060
14331
|
const resultMutation = {
|
|
14061
14332
|
status: "completed",
|
|
14062
14333
|
runnerId,
|
|
14063
|
-
idempotencyKey: `brain_consolidation_${workItem.workItemId}_${
|
|
14334
|
+
idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID4()}`,
|
|
14064
14335
|
result: scanResult,
|
|
14065
14336
|
tool: toolName,
|
|
14066
14337
|
durationMs,
|
|
@@ -14094,7 +14365,7 @@ ${toolResult.stderr}`);
|
|
|
14094
14365
|
const failedMutation = {
|
|
14095
14366
|
status: "failed",
|
|
14096
14367
|
runnerId,
|
|
14097
|
-
idempotencyKey: `brain_consolidation_${workItem.workItemId}_${
|
|
14368
|
+
idempotencyKey: `brain_consolidation_${workItem.workItemId}_${randomUUID4()}`,
|
|
14098
14369
|
tool: toolName,
|
|
14099
14370
|
durationMs,
|
|
14100
14371
|
...sessionTelemetry,
|
|
@@ -14156,7 +14427,7 @@ ${toolResult.stderr}`, { repositoryRoot: executionRoot });
|
|
|
14156
14427
|
const resultMutation = {
|
|
14157
14428
|
status: "completed",
|
|
14158
14429
|
runnerId,
|
|
14159
|
-
idempotencyKey: `project_context_${workItem.workItemId}_${
|
|
14430
|
+
idempotencyKey: `project_context_${workItem.workItemId}_${randomUUID4()}`,
|
|
14160
14431
|
result: refreshResult,
|
|
14161
14432
|
tool: toolName,
|
|
14162
14433
|
durationMs,
|
|
@@ -14202,7 +14473,7 @@ ${toolResult.stderr}`, { repositoryRoot: executionRoot });
|
|
|
14202
14473
|
const failedMutation = {
|
|
14203
14474
|
status: "failed",
|
|
14204
14475
|
runnerId,
|
|
14205
|
-
idempotencyKey: `project_context_${workItem.workItemId}_${
|
|
14476
|
+
idempotencyKey: `project_context_${workItem.workItemId}_${randomUUID4()}`,
|
|
14206
14477
|
tool: toolName,
|
|
14207
14478
|
durationMs,
|
|
14208
14479
|
...sessionTelemetry,
|
|
@@ -14263,7 +14534,7 @@ ${toolResult.stderr}`);
|
|
|
14263
14534
|
const resultMutation = {
|
|
14264
14535
|
status: "completed",
|
|
14265
14536
|
runnerId,
|
|
14266
|
-
idempotencyKey: `implementation_verification_${workItem.workItemId}_${
|
|
14537
|
+
idempotencyKey: `implementation_verification_${workItem.workItemId}_${randomUUID4()}`,
|
|
14267
14538
|
result: verificationResult,
|
|
14268
14539
|
tool: toolName,
|
|
14269
14540
|
durationMs,
|
|
@@ -14297,7 +14568,7 @@ ${toolResult.stderr}`);
|
|
|
14297
14568
|
const failedMutation = {
|
|
14298
14569
|
status: "failed",
|
|
14299
14570
|
runnerId,
|
|
14300
|
-
idempotencyKey: `implementation_verification_${workItem.workItemId}_${
|
|
14571
|
+
idempotencyKey: `implementation_verification_${workItem.workItemId}_${randomUUID4()}`,
|
|
14301
14572
|
tool: toolName,
|
|
14302
14573
|
durationMs,
|
|
14303
14574
|
...sessionTelemetry,
|
|
@@ -14358,7 +14629,7 @@ ${toolResult.stderr}`);
|
|
|
14358
14629
|
const resultMutation = {
|
|
14359
14630
|
status: "completed",
|
|
14360
14631
|
runnerId,
|
|
14361
|
-
idempotencyKey: `test_quality_${workItem.workItemId}_${
|
|
14632
|
+
idempotencyKey: `test_quality_${workItem.workItemId}_${randomUUID4()}`,
|
|
14362
14633
|
result: scanResult,
|
|
14363
14634
|
tool: toolName,
|
|
14364
14635
|
durationMs,
|
|
@@ -14392,7 +14663,7 @@ ${toolResult.stderr}`);
|
|
|
14392
14663
|
const failedMutation = {
|
|
14393
14664
|
status: "failed",
|
|
14394
14665
|
runnerId,
|
|
14395
|
-
idempotencyKey: `test_quality_${workItem.workItemId}_${
|
|
14666
|
+
idempotencyKey: `test_quality_${workItem.workItemId}_${randomUUID4()}`,
|
|
14396
14667
|
tool: toolName,
|
|
14397
14668
|
durationMs,
|
|
14398
14669
|
...sessionTelemetry,
|
|
@@ -14453,7 +14724,7 @@ ${toolResult.stderr}`);
|
|
|
14453
14724
|
const resultMutation = {
|
|
14454
14725
|
status: "completed",
|
|
14455
14726
|
runnerId,
|
|
14456
|
-
idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${
|
|
14727
|
+
idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${randomUUID4()}`,
|
|
14457
14728
|
result: gateResult,
|
|
14458
14729
|
tool: toolName,
|
|
14459
14730
|
durationMs,
|
|
@@ -14487,7 +14758,7 @@ ${toolResult.stderr}`);
|
|
|
14487
14758
|
const failedMutation = {
|
|
14488
14759
|
status: "failed",
|
|
14489
14760
|
runnerId,
|
|
14490
|
-
idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${
|
|
14761
|
+
idempotencyKey: `implementation_test_gate_${workItem.workItemId}_${randomUUID4()}`,
|
|
14491
14762
|
tool: toolName,
|
|
14492
14763
|
durationMs,
|
|
14493
14764
|
...sessionTelemetry,
|
|
@@ -14724,7 +14995,7 @@ async function prepareToolSession({
|
|
|
14724
14995
|
});
|
|
14725
14996
|
return { ...selection, toolSession: toolSession2 };
|
|
14726
14997
|
}
|
|
14727
|
-
const toolSessionId = `tool_session_${
|
|
14998
|
+
const toolSessionId = `tool_session_${randomUUID4()}`;
|
|
14728
14999
|
const { toolSession } = await apiClient.createToolSession(projectId, {
|
|
14729
15000
|
toolSessionId,
|
|
14730
15001
|
repositoryLinkId,
|
|
@@ -14883,7 +15154,7 @@ function runnerEnvironmentSetupCommands(setupPackageManagerInstall) {
|
|
|
14883
15154
|
return setupPackageManagerInstall ? [{ id: "packageManager.install" }] : [];
|
|
14884
15155
|
}
|
|
14885
15156
|
function inferRepoName(root) {
|
|
14886
|
-
return
|
|
15157
|
+
return path20.basename(path20.resolve(root)) || "repository";
|
|
14887
15158
|
}
|
|
14888
15159
|
function createRepoFingerprint(accountId, projectId, repositoryLinkId) {
|
|
14889
15160
|
return createHash9("sha256").update(`${accountId}:${projectId}:${repositoryLinkId}`).digest("hex");
|
|
@@ -15161,7 +15432,7 @@ function runnerHeartbeatMetadata(toolConfig, mode = currentRunnerMode(), concurr
|
|
|
15161
15432
|
return {
|
|
15162
15433
|
version: CLI_VERSION,
|
|
15163
15434
|
mode,
|
|
15164
|
-
hostname:
|
|
15435
|
+
hostname: os10.hostname(),
|
|
15165
15436
|
...runnerIsolationCapabilityMetadata(),
|
|
15166
15437
|
maxConcurrentWork: concurrencyMetadata.maxConcurrentWork,
|
|
15167
15438
|
activeClaimLaneIds: concurrencyMetadata.activeClaimLaneIds,
|
|
@@ -15186,9 +15457,9 @@ function runnerHeartbeatMetadata(toolConfig, mode = currentRunnerMode(), concurr
|
|
|
15186
15457
|
};
|
|
15187
15458
|
}
|
|
15188
15459
|
function runnerMachineId() {
|
|
15189
|
-
return createHash9("sha256").update(`${
|
|
15460
|
+
return createHash9("sha256").update(`${os10.hostname()}:${os10.platform()}:${os10.arch()}`).digest("hex").slice(0, 20);
|
|
15190
15461
|
}
|
|
15191
|
-
async function
|
|
15462
|
+
async function delay2(milliseconds) {
|
|
15192
15463
|
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
15193
15464
|
}
|
|
15194
15465
|
program.parseAsync().catch((error) => {
|