@trycadence/cli 0.1.18-dev.0 → 0.1.21-dev.0
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/dist/cadence +194 -20
- package/package.json +1 -1
package/dist/cadence
CHANGED
|
@@ -1488,6 +1488,7 @@ function createCadenceClient(options = {}) {
|
|
|
1488
1488
|
current: (input) => rpc.sessions.current.query(input),
|
|
1489
1489
|
leases: {
|
|
1490
1490
|
create: (input) => rpc.sessions.leases.create.mutate(input),
|
|
1491
|
+
renew: (input) => rpc.sessions.leases.renew.mutate(input),
|
|
1491
1492
|
release: (input) => rpc.sessions.leases.release.mutate(input)
|
|
1492
1493
|
}
|
|
1493
1494
|
},
|
|
@@ -1520,7 +1521,7 @@ import { createInterface } from "readline/promises";
|
|
|
1520
1521
|
// package.json
|
|
1521
1522
|
var package_default = {
|
|
1522
1523
|
name: "@trycadence/cli",
|
|
1523
|
-
version: "0.1.
|
|
1524
|
+
version: "0.1.21-dev.0",
|
|
1524
1525
|
private: false,
|
|
1525
1526
|
type: "module",
|
|
1526
1527
|
bin: {
|
|
@@ -3308,6 +3309,8 @@ function readAgentSessionCadenceContext(record) {
|
|
|
3308
3309
|
...typeof contextRecord.ticketId === "string" ? { ticketId: contextRecord.ticketId } : {},
|
|
3309
3310
|
...typeof contextRecord.sessionId === "string" ? { sessionId: contextRecord.sessionId } : {},
|
|
3310
3311
|
...typeof contextRecord.changesetId === "string" ? { changesetId: contextRecord.changesetId } : {},
|
|
3312
|
+
...typeof contextRecord.leaseId === "string" ? { leaseId: contextRecord.leaseId } : {},
|
|
3313
|
+
...typeof contextRecord.leaseExpiresAt === "string" ? { leaseExpiresAt: contextRecord.leaseExpiresAt } : {},
|
|
3311
3314
|
...typeof contextRecord.capturedAt === "string" ? { capturedAt: contextRecord.capturedAt } : {}
|
|
3312
3315
|
};
|
|
3313
3316
|
return cadenceContext.ticketId || cadenceContext.sessionId || cadenceContext.changesetId ? { cadenceContext } : {};
|
|
@@ -3355,9 +3358,38 @@ async function writeAgentCheckpointAuditFile(parsed, options, audit) {
|
|
|
3355
3358
|
`);
|
|
3356
3359
|
return filePath;
|
|
3357
3360
|
}
|
|
3361
|
+
async function readAgentLoopLockHolder(lockPath) {
|
|
3362
|
+
try {
|
|
3363
|
+
const text = await readFile(join(lockPath, "holder.json"), "utf8");
|
|
3364
|
+
const parsed = JSON.parse(text);
|
|
3365
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
3366
|
+
} catch {
|
|
3367
|
+
return null;
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
function lockHolderPid(holder) {
|
|
3371
|
+
const pid = holder?.pid;
|
|
3372
|
+
return typeof pid === "number" && Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
3373
|
+
}
|
|
3374
|
+
function processIsRunning(pid) {
|
|
3375
|
+
try {
|
|
3376
|
+
process.kill(pid, 0);
|
|
3377
|
+
return true;
|
|
3378
|
+
} catch (error) {
|
|
3379
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ESRCH") {
|
|
3380
|
+
return false;
|
|
3381
|
+
}
|
|
3382
|
+
return true;
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3358
3385
|
async function removeStaleAgentLoopLock(lockPath) {
|
|
3359
3386
|
try {
|
|
3360
3387
|
const lockStats = await stat(lockPath);
|
|
3388
|
+
const holderPid = lockHolderPid(await readAgentLoopLockHolder(lockPath));
|
|
3389
|
+
if (holderPid !== null && !processIsRunning(holderPid)) {
|
|
3390
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
3391
|
+
return true;
|
|
3392
|
+
}
|
|
3361
3393
|
if (Date.now() - lockStats.mtimeMs < defaultCheckpointWorkerTimeoutMs) {
|
|
3362
3394
|
return false;
|
|
3363
3395
|
}
|
|
@@ -3501,6 +3533,8 @@ function activeSessionFromCurrent(current) {
|
|
|
3501
3533
|
...sessionId ? { id: sessionId } : {},
|
|
3502
3534
|
ticketId: leaseRecord.ticketId,
|
|
3503
3535
|
...typeof leaseRecord.changesetId === "string" ? { changesetId: leaseRecord.changesetId } : typeof sessionRecord.changesetId === "string" ? { changesetId: sessionRecord.changesetId } : {},
|
|
3536
|
+
...typeof leaseRecord.id === "string" ? { leaseId: leaseRecord.id } : {},
|
|
3537
|
+
...typeof leaseRecord.expiresAt === "string" ? { leaseExpiresAt: leaseRecord.expiresAt } : {},
|
|
3504
3538
|
status: "active"
|
|
3505
3539
|
};
|
|
3506
3540
|
}
|
|
@@ -3525,6 +3559,8 @@ function cadenceContextFromCurrent(current) {
|
|
|
3525
3559
|
const ticketId = typeof activeSession.ticketId === "string" ? activeSession.ticketId : undefined;
|
|
3526
3560
|
const sessionId = typeof activeSession.id === "string" ? activeSession.id : undefined;
|
|
3527
3561
|
const changesetId = typeof activeSession.changesetId === "string" ? activeSession.changesetId : undefined;
|
|
3562
|
+
const leaseId = typeof activeSession.leaseId === "string" ? activeSession.leaseId : undefined;
|
|
3563
|
+
const leaseExpiresAt2 = typeof activeSession.leaseExpiresAt === "string" ? activeSession.leaseExpiresAt : undefined;
|
|
3528
3564
|
if (!ticketId && !sessionId && !changesetId) {
|
|
3529
3565
|
return;
|
|
3530
3566
|
}
|
|
@@ -3532,9 +3568,41 @@ function cadenceContextFromCurrent(current) {
|
|
|
3532
3568
|
...ticketId ? { ticketId } : {},
|
|
3533
3569
|
...sessionId ? { sessionId } : {},
|
|
3534
3570
|
...changesetId ? { changesetId } : {},
|
|
3571
|
+
...leaseId ? { leaseId } : {},
|
|
3572
|
+
...leaseExpiresAt2 ? { leaseExpiresAt: leaseExpiresAt2 } : {},
|
|
3535
3573
|
capturedAt: new Date().toISOString()
|
|
3536
3574
|
};
|
|
3537
3575
|
}
|
|
3576
|
+
function leaseExpiresAtFromResponse(value) {
|
|
3577
|
+
return value && typeof value === "object" && "expiresAt" in value && typeof value.expiresAt === "string" ? value.expiresAt : undefined;
|
|
3578
|
+
}
|
|
3579
|
+
async function renewAgentSessionLease(client, projectId, context) {
|
|
3580
|
+
if (!context?.leaseId) {
|
|
3581
|
+
return context;
|
|
3582
|
+
}
|
|
3583
|
+
const expiresAt = leaseExpiresAt(defaultLeaseTtlSeconds);
|
|
3584
|
+
const renewed = await client.sessions.leases.renew({
|
|
3585
|
+
projectId,
|
|
3586
|
+
leaseId: context.leaseId,
|
|
3587
|
+
lease: {
|
|
3588
|
+
expiresAt,
|
|
3589
|
+
...commandMetadata()
|
|
3590
|
+
}
|
|
3591
|
+
});
|
|
3592
|
+
return {
|
|
3593
|
+
...context,
|
|
3594
|
+
leaseId: objectStringId(renewed) ?? context.leaseId,
|
|
3595
|
+
leaseExpiresAt: leaseExpiresAtFromResponse(renewed) ?? expiresAt,
|
|
3596
|
+
capturedAt: new Date().toISOString()
|
|
3597
|
+
};
|
|
3598
|
+
}
|
|
3599
|
+
async function renewAgentSessionLeaseBestEffort(client, projectId, context) {
|
|
3600
|
+
try {
|
|
3601
|
+
return await renewAgentSessionLease(client, projectId, context);
|
|
3602
|
+
} catch {
|
|
3603
|
+
return context;
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3538
3606
|
async function readCurrentCadenceContext(client, projectId) {
|
|
3539
3607
|
const current = await client.sessions.current({
|
|
3540
3608
|
projectId,
|
|
@@ -3566,18 +3634,6 @@ function shouldSkipForCooldown(state, cooldownSeconds) {
|
|
|
3566
3634
|
const lastCheckpointMs = new Date(state.lastCheckpointAt).getTime();
|
|
3567
3635
|
return !Number.isNaN(lastCheckpointMs) && Date.now() - lastCheckpointMs < cooldownSeconds * 1000;
|
|
3568
3636
|
}
|
|
3569
|
-
function synthesizeAgentEventFromSession(agentSessionKeyValue, session, options) {
|
|
3570
|
-
return {
|
|
3571
|
-
source: session.source,
|
|
3572
|
-
event: "checkpoint",
|
|
3573
|
-
workspacePath: options.cwd ?? process.cwd(),
|
|
3574
|
-
occurredAt: new Date().toISOString(),
|
|
3575
|
-
agentSessionKey: agentSessionKeyValue,
|
|
3576
|
-
...session.lastAssistantMessage ? { lastAssistantMessage: session.lastAssistantMessage } : {},
|
|
3577
|
-
...session.recentTurns?.length ? { recentTurns: session.recentTurns } : {},
|
|
3578
|
-
payloadKeys: []
|
|
3579
|
-
};
|
|
3580
|
-
}
|
|
3581
3637
|
var checkpointRouteActions = ["current", "noop", "intake_create", "intake_attach", "switch_existing", "needs_human"];
|
|
3582
3638
|
var checkpointConfidenceLevels = ["low", "medium", "high"];
|
|
3583
3639
|
var checkpointSessionActions = ["keep", "handoff", "end", "complete_ticket"];
|
|
@@ -4216,6 +4272,9 @@ function buildRoutePrompt(input) {
|
|
|
4216
4272
|
"You are generating a compact Cadence dogfood routing plan for an agent-run worker.",
|
|
4217
4273
|
"The model judges; the Cadence CLI validates and executes. Return JSON only. Do not call tools to mutate Cadence yourself.",
|
|
4218
4274
|
"Decide where this agent session belongs before checkpoint memory is written.",
|
|
4275
|
+
"First decide whether the latest request is directed at this source agent to perform work, or whether this is a meta/utility task about quoted conversation content.",
|
|
4276
|
+
"If the transcript asks this agent to generate a title, branch name, label, summary, classification, or other metadata for quoted user text, treat the quoted work as reference material, not active work for this agent.",
|
|
4277
|
+
"For those meta/utility cases, return route.action noop with entries [] even when the quoted text describes durable repo work.",
|
|
4219
4278
|
"Do not include raw diffs, raw transcripts, terminal logs, tool streams, secrets, file contents, or model reasoning in server-bound fields.",
|
|
4220
4279
|
'Return this sparse JSON shape: {"summary":"short routing summary","sessionTitle":{"text":"short GUI session title","confidence":"low|medium|high","reason":"why this title names the routed focus"},"route":{"action":"current|noop|intake_create|intake_attach|switch_existing","confidence":"low|medium|high","reason":"short reason","request":"natural language intake request when intake is needed","targetTicketId":"optional existing ticket id"},"entries":[{"kind":"intent|decision|rationale|action|verification|blocker|correction|note","summary":"short entry summary","body":"safe Cadence work-log body"}],"files":[{"path":"relative/path.ts","kind":"added|modified|deleted|renamed|unknown"}]}',
|
|
4221
4280
|
"Generate sessionTitle only when the routed focus is durable enough to name a GUI row. Omit it for noop/filler. Keep it under 80 characters and do not reuse the latest checkpoint summary as the title.",
|
|
@@ -4252,6 +4311,8 @@ function buildRouteCandidatePrompt(input) {
|
|
|
4252
4311
|
"You are resolving Cadence agent-run routing after intake returned possible existing work.",
|
|
4253
4312
|
"Intake is retrieval, not the final decision. The model judges; the Cadence CLI validates and executes. Return JSON only.",
|
|
4254
4313
|
"Choose whether this agent session should create a new ticket, attach/switch to one concrete candidate ticket, keep the current context, or no-op.",
|
|
4314
|
+
"Before choosing a candidate, decide whether the latest request is directed at this source agent to perform work, or whether this is a meta/utility task about quoted conversation content.",
|
|
4315
|
+
"If the transcript asks this agent to generate a title, branch name, label, summary, classification, or other metadata for quoted user text, return noop and do not attach/create/switch based on the quoted work.",
|
|
4255
4316
|
"Use intake_create when the recent request is durable and the candidates are weak, adjacent, completed, or not concrete matches.",
|
|
4256
4317
|
"Use intake_attach or switch_existing only when one candidate ticket is clearly the same work. You must include targetTicketId from the candidate list.",
|
|
4257
4318
|
"Use current only when the saved/current Cadence context clearly fits the recent work.",
|
|
@@ -4864,6 +4925,9 @@ async function runAgentRunIngestStop(parsed, options, config, meta) {
|
|
|
4864
4925
|
try {
|
|
4865
4926
|
const client = await createClient(config, options);
|
|
4866
4927
|
cadenceContext = await readCurrentCadenceContext(client, projectId) ?? cadenceContext;
|
|
4928
|
+
if (!duplicateTurn) {
|
|
4929
|
+
cadenceContext = await renewAgentSessionLeaseBestEffort(client, projectId, cadenceContext);
|
|
4930
|
+
}
|
|
4867
4931
|
} catch {}
|
|
4868
4932
|
}
|
|
4869
4933
|
const observedSession = {
|
|
@@ -4883,6 +4947,11 @@ async function runAgentRunIngestStop(parsed, options, config, meta) {
|
|
|
4883
4947
|
...normalized.lastAssistantMessage ? { lastAssistantMessage: normalized.lastAssistantMessage } : {},
|
|
4884
4948
|
...recentTurns ? { recentTurns } : {}
|
|
4885
4949
|
};
|
|
4950
|
+
let observedEventFile;
|
|
4951
|
+
const ensureObservedEventFile = async () => {
|
|
4952
|
+
observedEventFile ??= await writeAgentEventFile(parsed, options, normalized);
|
|
4953
|
+
return observedEventFile;
|
|
4954
|
+
};
|
|
4886
4955
|
const countedState = {
|
|
4887
4956
|
...state,
|
|
4888
4957
|
sessions: {
|
|
@@ -4907,7 +4976,7 @@ async function runAgentRunIngestStop(parsed, options, config, meta) {
|
|
|
4907
4976
|
};
|
|
4908
4977
|
}
|
|
4909
4978
|
if (!savedCadenceContext?.ticketId) {
|
|
4910
|
-
const eventFile2 = await
|
|
4979
|
+
const eventFile2 = await ensureObservedEventFile();
|
|
4911
4980
|
const lockPath2 = agentLoopLockPath(parsed, options, normalized.agentSessionKey);
|
|
4912
4981
|
const workerArgs2 = [
|
|
4913
4982
|
"agent-run",
|
|
@@ -5009,13 +5078,24 @@ async function runAgentRunIngestStop(parsed, options, config, meta) {
|
|
|
5009
5078
|
};
|
|
5010
5079
|
}
|
|
5011
5080
|
if (nextCount < threshold) {
|
|
5012
|
-
await
|
|
5081
|
+
const eventFile2 = await ensureObservedEventFile();
|
|
5082
|
+
await writeAgentLoopState(parsed, options, {
|
|
5083
|
+
...state,
|
|
5084
|
+
sessions: {
|
|
5085
|
+
...state.sessions,
|
|
5086
|
+
[normalized.agentSessionKey]: {
|
|
5087
|
+
...observedSession,
|
|
5088
|
+
lastEventFile: eventFile2
|
|
5089
|
+
}
|
|
5090
|
+
}
|
|
5091
|
+
});
|
|
5013
5092
|
const data2 = {
|
|
5014
5093
|
action: duplicateTurn ? "updated" : "counted",
|
|
5015
5094
|
...duplicateTurn ? { reason: "duplicate_turn" } : {},
|
|
5016
5095
|
agentSessionKey: normalized.agentSessionKey,
|
|
5017
5096
|
stopCount: nextCount,
|
|
5018
|
-
threshold
|
|
5097
|
+
threshold,
|
|
5098
|
+
eventFile: eventFile2
|
|
5019
5099
|
};
|
|
5020
5100
|
return {
|
|
5021
5101
|
stdout: parsed.flags.json ? formatJson(successEnvelope(data2, meta)) : `${JSON.stringify(data2, null, 2)}
|
|
@@ -5077,7 +5157,7 @@ async function runAgentRunIngestStop(parsed, options, config, meta) {
|
|
|
5077
5157
|
exitCode: 0
|
|
5078
5158
|
};
|
|
5079
5159
|
}
|
|
5080
|
-
const eventFile = await
|
|
5160
|
+
const eventFile = await ensureObservedEventFile();
|
|
5081
5161
|
const lockPath = agentLoopLockPath(parsed, options, normalized.agentSessionKey);
|
|
5082
5162
|
const workerArgs = [
|
|
5083
5163
|
"agent-run",
|
|
@@ -5217,9 +5297,35 @@ async function runAgentRunRoute(parsed, options, config, meta) {
|
|
|
5217
5297
|
});
|
|
5218
5298
|
}
|
|
5219
5299
|
const savedContext = sessionState.cadenceContext;
|
|
5220
|
-
const currentContext = savedContext?.ticketId ? undefined : await readCurrentCadenceContext(client, projectId);
|
|
5221
5300
|
const eventFile = parsed.options["event-file"] ?? sessionState.lastEventFile;
|
|
5222
|
-
|
|
5301
|
+
if (!eventFile || !existsSync(eventFile)) {
|
|
5302
|
+
await writeAgentLoopState(parsed, options, {
|
|
5303
|
+
...state,
|
|
5304
|
+
sessions: {
|
|
5305
|
+
...state.sessions,
|
|
5306
|
+
[agentSessionKeyValue]: {
|
|
5307
|
+
...sessionState,
|
|
5308
|
+
stopCount: 0,
|
|
5309
|
+
threshold: defaultCheckpointThresholdValue(),
|
|
5310
|
+
lastAction: "skipped",
|
|
5311
|
+
lastReason: "no_event_file"
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
});
|
|
5315
|
+
const data = {
|
|
5316
|
+
action: "skipped",
|
|
5317
|
+
reason: "no_event_file",
|
|
5318
|
+
agentSessionKey: agentSessionKeyValue
|
|
5319
|
+
};
|
|
5320
|
+
return {
|
|
5321
|
+
stdout: parsed.flags.json ? formatJson(successEnvelope(data, meta)) : `${JSON.stringify(data, null, 2)}
|
|
5322
|
+
`,
|
|
5323
|
+
stderr: "",
|
|
5324
|
+
exitCode: 0
|
|
5325
|
+
};
|
|
5326
|
+
}
|
|
5327
|
+
const event = tryParseJsonObject(await readFile(eventFile, "utf8"), eventFile);
|
|
5328
|
+
const currentContext = savedContext?.ticketId ? undefined : await readCurrentCadenceContext(client, projectId);
|
|
5223
5329
|
const checkpointSettings = await resolveCheckpointSettings(parsed, options);
|
|
5224
5330
|
const gitStatus = gitOutput(["status", "--short"], options);
|
|
5225
5331
|
const gitDiffStat = gitOutput(["diff", "--stat", "origin/dev..."], options);
|
|
@@ -5325,6 +5431,8 @@ async function runAgentRunRoute(parsed, options, config, meta) {
|
|
|
5325
5431
|
let targetTicketId = currentTicketId;
|
|
5326
5432
|
let targetSessionId = currentSessionId;
|
|
5327
5433
|
let targetChangesetId = currentChangesetId;
|
|
5434
|
+
let targetLeaseId = savedContext?.leaseId ?? currentContext?.leaseId;
|
|
5435
|
+
let targetLeaseExpiresAt = savedContext?.leaseExpiresAt ?? currentContext?.leaseExpiresAt;
|
|
5328
5436
|
let intakeResult;
|
|
5329
5437
|
let selectedTicket;
|
|
5330
5438
|
let summary = routePlan.summary ?? routePlan.entries[0]?.summary ?? routePlan.route.reason ?? "Agent run route";
|
|
@@ -5354,6 +5462,8 @@ async function runAgentRunRoute(parsed, options, config, meta) {
|
|
|
5354
5462
|
...targetTicketId ? { ticketId: targetTicketId } : {},
|
|
5355
5463
|
...targetSessionId ? { sessionId: targetSessionId } : {},
|
|
5356
5464
|
...targetChangesetId ? { changesetId: targetChangesetId } : {},
|
|
5465
|
+
...targetLeaseId ? { leaseId: targetLeaseId } : {},
|
|
5466
|
+
...targetLeaseExpiresAt ? { leaseExpiresAt: targetLeaseExpiresAt } : {},
|
|
5357
5467
|
...eventFile ? { eventFile } : {},
|
|
5358
5468
|
event,
|
|
5359
5469
|
prompt,
|
|
@@ -5382,6 +5492,8 @@ async function runAgentRunRoute(parsed, options, config, meta) {
|
|
|
5382
5492
|
ticketId: targetTicketId,
|
|
5383
5493
|
...targetSessionId ? { sessionId: targetSessionId } : {},
|
|
5384
5494
|
...targetChangesetId ? { changesetId: targetChangesetId } : {},
|
|
5495
|
+
...targetLeaseId ? { leaseId: targetLeaseId } : {},
|
|
5496
|
+
...targetLeaseExpiresAt ? { leaseExpiresAt: targetLeaseExpiresAt } : {},
|
|
5385
5497
|
capturedAt: checkedAt
|
|
5386
5498
|
}
|
|
5387
5499
|
} : {},
|
|
@@ -5549,6 +5661,8 @@ async function runAgentRunRoute(parsed, options, config, meta) {
|
|
|
5549
5661
|
...commandMetadata()
|
|
5550
5662
|
}
|
|
5551
5663
|
});
|
|
5664
|
+
targetLeaseId = objectStringId(lease);
|
|
5665
|
+
targetLeaseExpiresAt = leaseExpiresAtFromResponse(lease);
|
|
5552
5666
|
lifecycleOperations.push(checkpointLifecycleOperation("lease.claimed", true, { ticketId: targetTicketId, sessionId: targetSessionId, lease }));
|
|
5553
5667
|
}
|
|
5554
5668
|
if (targetSessionId) {
|
|
@@ -5638,6 +5752,8 @@ async function runAgentRunCheckpoint(parsed, options, config, meta) {
|
|
|
5638
5752
|
const ticketId = parsed.options.ticket ?? savedContext?.ticketId ?? currentContext?.ticketId;
|
|
5639
5753
|
const sessionId = parsed.options.session ?? savedContext?.sessionId ?? currentContext?.sessionId;
|
|
5640
5754
|
const changesetId = parsed.options.changeset ?? savedContext?.changesetId ?? currentContext?.changesetId;
|
|
5755
|
+
const leaseId = savedContext?.leaseId ?? currentContext?.leaseId;
|
|
5756
|
+
const leaseExpiresAtValue = savedContext?.leaseExpiresAt ?? currentContext?.leaseExpiresAt;
|
|
5641
5757
|
if (!ticketId) {
|
|
5642
5758
|
await writeAgentLoopState(parsed, options, {
|
|
5643
5759
|
...state,
|
|
@@ -5663,7 +5779,36 @@ async function runAgentRunCheckpoint(parsed, options, config, meta) {
|
|
|
5663
5779
|
};
|
|
5664
5780
|
}
|
|
5665
5781
|
const eventFile = parsed.options["event-file"] ?? sessionState.lastEventFile;
|
|
5666
|
-
|
|
5782
|
+
if (!eventFile || !existsSync(eventFile)) {
|
|
5783
|
+
await writeAgentLoopState(parsed, options, {
|
|
5784
|
+
...state,
|
|
5785
|
+
sessions: {
|
|
5786
|
+
...state.sessions,
|
|
5787
|
+
[agentSessionKeyValue]: {
|
|
5788
|
+
...sessionState,
|
|
5789
|
+
stopCount: 0,
|
|
5790
|
+
threshold: defaultCheckpointThresholdValue(),
|
|
5791
|
+
lastAction: "skipped",
|
|
5792
|
+
lastReason: "no_event_file"
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
});
|
|
5796
|
+
const data = {
|
|
5797
|
+
action: "skipped",
|
|
5798
|
+
reason: "no_event_file",
|
|
5799
|
+
agentSessionKey: agentSessionKeyValue,
|
|
5800
|
+
...ticketId ? { ticketId } : {},
|
|
5801
|
+
...sessionId ? { sessionId } : {},
|
|
5802
|
+
...changesetId ? { changesetId } : {}
|
|
5803
|
+
};
|
|
5804
|
+
return {
|
|
5805
|
+
stdout: parsed.flags.json ? formatJson(successEnvelope(data, meta)) : `${JSON.stringify(data, null, 2)}
|
|
5806
|
+
`,
|
|
5807
|
+
stderr: "",
|
|
5808
|
+
exitCode: 0
|
|
5809
|
+
};
|
|
5810
|
+
}
|
|
5811
|
+
const event = tryParseJsonObject(await readFile(eventFile, "utf8"), eventFile);
|
|
5667
5812
|
const mode = checkpointModeForCommand(parsed);
|
|
5668
5813
|
const logKind = parseWorkLogEntryKind(parsed.options["log-kind"] ?? "note");
|
|
5669
5814
|
const updateSummary = parseBooleanOption(parsed.options["update-summary"], false);
|
|
@@ -5934,6 +6079,8 @@ async function runAgentRunCheckpoint(parsed, options, config, meta) {
|
|
|
5934
6079
|
ticketId,
|
|
5935
6080
|
...sessionId ? { sessionId } : {},
|
|
5936
6081
|
...changesetId ? { changesetId } : {},
|
|
6082
|
+
...leaseId ? { leaseId } : {},
|
|
6083
|
+
...leaseExpiresAtValue ? { leaseExpiresAt: leaseExpiresAtValue } : {},
|
|
5937
6084
|
capturedAt: checkedAt
|
|
5938
6085
|
},
|
|
5939
6086
|
lastCheckpointAt: checkedAt,
|
|
@@ -5972,6 +6119,8 @@ async function runAgentRunCheckpoint(parsed, options, config, meta) {
|
|
|
5972
6119
|
let targetTicketId = ticketId;
|
|
5973
6120
|
let targetSessionId = sessionId;
|
|
5974
6121
|
let targetChangesetId = changesetId;
|
|
6122
|
+
let targetLeaseId = leaseId;
|
|
6123
|
+
let targetLeaseExpiresAt = leaseExpiresAtValue;
|
|
5975
6124
|
const cadenceWrites = [];
|
|
5976
6125
|
const lifecycleOperations = [];
|
|
5977
6126
|
let intakeResult;
|
|
@@ -6000,6 +6149,8 @@ async function runAgentRunCheckpoint(parsed, options, config, meta) {
|
|
|
6000
6149
|
ticketId: targetTicketId,
|
|
6001
6150
|
...targetSessionId ? { sessionId: targetSessionId } : {},
|
|
6002
6151
|
...targetChangesetId ? { changesetId: targetChangesetId } : {},
|
|
6152
|
+
...targetLeaseId ? { leaseId: targetLeaseId } : {},
|
|
6153
|
+
...targetLeaseExpiresAt ? { leaseExpiresAt: targetLeaseExpiresAt } : {},
|
|
6003
6154
|
...eventFile ? { eventFile } : {},
|
|
6004
6155
|
event,
|
|
6005
6156
|
prompt,
|
|
@@ -6035,6 +6186,8 @@ async function runAgentRunCheckpoint(parsed, options, config, meta) {
|
|
|
6035
6186
|
ticketId: targetTicketId,
|
|
6036
6187
|
...targetSessionId ? { sessionId: targetSessionId } : {},
|
|
6037
6188
|
...targetChangesetId ? { changesetId: targetChangesetId } : {},
|
|
6189
|
+
...targetLeaseId ? { leaseId: targetLeaseId } : {},
|
|
6190
|
+
...targetLeaseExpiresAt ? { leaseExpiresAt: targetLeaseExpiresAt } : {},
|
|
6038
6191
|
capturedAt: checkedAt
|
|
6039
6192
|
},
|
|
6040
6193
|
lastCheckpointAt: checkedAt,
|
|
@@ -6272,7 +6425,25 @@ async function runAgentRunSweep(parsed, options, config, meta) {
|
|
|
6272
6425
|
for (const staleSession of staleSessions) {
|
|
6273
6426
|
const existingSession = nextState.sessions[staleSession.agentSessionKey];
|
|
6274
6427
|
const hasContext = Boolean(existingSession?.cadenceContext?.ticketId);
|
|
6428
|
+
const eventFile = existingSession?.lastEventFile;
|
|
6275
6429
|
if (existingSession) {
|
|
6430
|
+
if (!eventFile || !existsSync(eventFile)) {
|
|
6431
|
+
nextState = {
|
|
6432
|
+
...nextState,
|
|
6433
|
+
sessions: {
|
|
6434
|
+
...nextState.sessions,
|
|
6435
|
+
[staleSession.agentSessionKey]: {
|
|
6436
|
+
...existingSession,
|
|
6437
|
+
stopCount: 0,
|
|
6438
|
+
threshold: defaultCheckpointThresholdValue(),
|
|
6439
|
+
lastAction: "skipped",
|
|
6440
|
+
lastReason: "no_event_file"
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
};
|
|
6444
|
+
await writeAgentLoopState(parsed, options, nextState);
|
|
6445
|
+
continue;
|
|
6446
|
+
}
|
|
6276
6447
|
nextState = {
|
|
6277
6448
|
...nextState,
|
|
6278
6449
|
sessions: {
|
|
@@ -6285,6 +6456,7 @@ async function runAgentRunSweep(parsed, options, config, meta) {
|
|
|
6285
6456
|
};
|
|
6286
6457
|
await writeAgentLoopState(parsed, options, nextState);
|
|
6287
6458
|
}
|
|
6459
|
+
const realEventFile = eventFile;
|
|
6288
6460
|
await spawnAgentRunCheckpoint([
|
|
6289
6461
|
"agent-run",
|
|
6290
6462
|
hasContext ? "checkpoint" : "route",
|
|
@@ -6292,6 +6464,8 @@ async function runAgentRunSweep(parsed, options, config, meta) {
|
|
|
6292
6464
|
staleSession.agentSessionKey,
|
|
6293
6465
|
"--reason",
|
|
6294
6466
|
hasContext ? "idle" : "missing_context",
|
|
6467
|
+
"--event-file",
|
|
6468
|
+
realEventFile,
|
|
6295
6469
|
"--lock",
|
|
6296
6470
|
agentLoopLockPath(parsed, options, staleSession.agentSessionKey),
|
|
6297
6471
|
...parsed.flags.project ? ["--project", parsed.flags.project] : [],
|