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