@sagentlab/navarch-runtime 0.1.66 → 0.1.68
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/api.cjs +2 -2
- package/dist/delivery.cjs +8 -4
- package/dist/git-worktree.cjs +13 -1
- package/dist/session.cjs +16 -5
- package/package.json +1 -1
package/dist/api.cjs
CHANGED
|
@@ -142,8 +142,8 @@ class NavarchApiClient {
|
|
|
142
142
|
return result;
|
|
143
143
|
}
|
|
144
144
|
/** Best-effort, lease-scoped activity signal for connected machines. */
|
|
145
|
-
async reportActivity(leaseId, phase) {
|
|
146
|
-
await this.request("POST", `/api/dispatch/${encodeURIComponent(leaseId)}/activity`, { phase }, { allowEmpty: true });
|
|
145
|
+
async reportActivity(leaseId, phase, detail) {
|
|
146
|
+
await this.request("POST", `/api/dispatch/${encodeURIComponent(leaseId)}/activity`, { phase, ...(detail ? { detail } : {}) }, { allowEmpty: true });
|
|
147
147
|
}
|
|
148
148
|
/** schema-design.md §7 — `POST /api/dispatch/:leaseId/complete {status, report, evidence_urls, cost}`. */
|
|
149
149
|
async completeLease(leaseId, req) {
|
package/dist/delivery.cjs
CHANGED
|
@@ -110,6 +110,13 @@ function evaluateDelivery(probe) {
|
|
|
110
110
|
}
|
|
111
111
|
return { status: "no_changes" };
|
|
112
112
|
}
|
|
113
|
+
// A failed GitHub lookup also means we cannot distinguish a genuinely
|
|
114
|
+
// unpushed commit from a successful push whose remote-tracking ref was not
|
|
115
|
+
// fetched after the agent turn. Do not fail and delete a delivered worktree
|
|
116
|
+
// based only on the cache in that state.
|
|
117
|
+
if (probe.pullRequestLookupFailed) {
|
|
118
|
+
return { status: "unknown", reason: "the pull request lookup could not run, so delivery cannot be confirmed" };
|
|
119
|
+
}
|
|
113
120
|
if (probe.unpushedCommits > 0) {
|
|
114
121
|
const plural = probe.unpushedCommits === 1 ? "commit" : "commits";
|
|
115
122
|
return {
|
|
@@ -118,10 +125,7 @@ function evaluateDelivery(probe) {
|
|
|
118
125
|
"were never pushed, so the work exists only in this session's worktree",
|
|
119
126
|
};
|
|
120
127
|
}
|
|
121
|
-
// Pushed, but nothing carries it.
|
|
122
|
-
if (probe.pullRequestLookupFailed) {
|
|
123
|
-
return { status: "unknown", reason: "the pull request lookup could not run, so delivery cannot be confirmed" };
|
|
124
|
-
}
|
|
128
|
+
// Pushed, but nothing carries it. GitHub answered the lookup above.
|
|
125
129
|
const plural = probe.commitsAhead === 1 ? "commit" : "commits";
|
|
126
130
|
return {
|
|
127
131
|
status: "incomplete",
|
package/dist/git-worktree.cjs
CHANGED
|
@@ -31,6 +31,7 @@ class GitWorktree {
|
|
|
31
31
|
cloneUrl;
|
|
32
32
|
githubToken;
|
|
33
33
|
repoLocalGithubToken;
|
|
34
|
+
prContinuation;
|
|
34
35
|
taskBranchSuffix;
|
|
35
36
|
legacyTaskBranchSuffix;
|
|
36
37
|
taskOwnershipTrailer;
|
|
@@ -57,11 +58,16 @@ class GitWorktree {
|
|
|
57
58
|
this.legacyTaskBranchSuffix = `-${normalizedTaskId}`;
|
|
58
59
|
this.taskOwnershipTrailer = `Navarch-Task-ID: ${normalizedTaskId}`;
|
|
59
60
|
this.sessionTokenMarker = `navarch-session-github-token:${sessionKey}`;
|
|
60
|
-
|
|
61
|
+
// A continuation delivers on the reviewed PR's existing branch. Its
|
|
62
|
+
// initial worktree branch is disposable and must not collide with a
|
|
63
|
+
// previous attempt's temporary branch in the bare cache.
|
|
64
|
+
this.branch = `navarch/${branchSlug(options)}${this.taskBranchSuffix}` +
|
|
65
|
+
(options.prContinuation ? `-${sessionKey}` : "");
|
|
61
66
|
this.runner = options.runner ?? sandbox_cjs_1.nodeCommandRunner;
|
|
62
67
|
this.cloneUrl = options.cloneUrl;
|
|
63
68
|
this.githubToken = options.githubToken;
|
|
64
69
|
this.repoLocalGithubToken = options.repoLocalGithubToken;
|
|
70
|
+
this.prContinuation = options.prContinuation ?? false;
|
|
65
71
|
this.hostedCheckpointRef = options.restoreHostedCheckpoint ? hostedCheckpointRef(options.taskId) : null;
|
|
66
72
|
this.hostedCheckpointLocalRef = `refs/navarch/restored-checkpoints/${taskKey}`;
|
|
67
73
|
}
|
|
@@ -349,6 +355,12 @@ class GitWorktree {
|
|
|
349
355
|
}
|
|
350
356
|
/** Returns the fetched task-owned remote branch when an earlier attempt pushed it. */
|
|
351
357
|
async resolveTaskBranchRef() {
|
|
358
|
+
// A follow-up must check out the reviewed PR's head, not adopt a branch
|
|
359
|
+
// bearing this task's short suffix. An earlier attempt may have pushed its
|
|
360
|
+
// temporary branch after dropping the claim commit; that branch must not
|
|
361
|
+
// prevent later attempts from reaching the actual PR.
|
|
362
|
+
if (this.prContinuation)
|
|
363
|
+
return null;
|
|
352
364
|
const refs = await this.runGit(["--git-dir", this.repositoryPath, "for-each-ref", "--format=%(refname)", "refs/remotes/origin/navarch"], false);
|
|
353
365
|
const suffixMatches = refs.stdout
|
|
354
366
|
.split("\n")
|
package/dist/session.cjs
CHANGED
|
@@ -199,6 +199,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
199
199
|
taskId: task.id,
|
|
200
200
|
taskSummary: task.summary,
|
|
201
201
|
taskType: task.task_type,
|
|
202
|
+
prContinuation: allowBranchRename,
|
|
202
203
|
sessionId,
|
|
203
204
|
cloneUrl,
|
|
204
205
|
githubToken,
|
|
@@ -400,16 +401,22 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
400
401
|
let activityPending = Promise.resolve();
|
|
401
402
|
let outputObservedAt = 0;
|
|
402
403
|
let outputReportedAt = 0;
|
|
404
|
+
let outputUpdates = 0;
|
|
405
|
+
let agentTurnStartedAt = 0;
|
|
403
406
|
let adapterRunning = false;
|
|
404
|
-
const reportActivity = (phase) => {
|
|
405
|
-
activityPending = activityPending.then(() => api.reportActivity(leaseId, phase)).catch((error) => {
|
|
407
|
+
const reportActivity = (phase, detail) => {
|
|
408
|
+
activityPending = activityPending.then(() => api.reportActivity(leaseId, phase, detail)).catch((error) => {
|
|
406
409
|
log.warn(`activity update failed for ${leaseId}: ${(0, redact_cjs_1.redactText)(String(error), registry.list())}`);
|
|
407
410
|
});
|
|
408
411
|
};
|
|
409
412
|
const activityTimer = setInterval(() => {
|
|
410
413
|
if (adapterRunning && outputObservedAt > outputReportedAt && Date.now() - outputReportedAt >= 60_000) {
|
|
411
414
|
outputReportedAt = Date.now();
|
|
412
|
-
reportActivity("output"
|
|
415
|
+
reportActivity("output", {
|
|
416
|
+
outputUpdates,
|
|
417
|
+
elapsedSeconds: Math.floor((outputReportedAt - agentTurnStartedAt) / 1000),
|
|
418
|
+
});
|
|
419
|
+
outputUpdates = 0;
|
|
413
420
|
}
|
|
414
421
|
}, 15_000);
|
|
415
422
|
const heartbeatGuard = new lease_heartbeat_cjs_1.LeaseHeartbeatGuard(claimed.expires_at, () => {
|
|
@@ -484,6 +491,9 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
484
491
|
await node_fs_1.promises.writeFile(node_path_1.default.join(workDir, "prompt.md"), runPrompt, "utf8");
|
|
485
492
|
adapterStarted = true;
|
|
486
493
|
adapterRunning = true;
|
|
494
|
+
agentTurnStartedAt = Date.now();
|
|
495
|
+
outputReportedAt = agentTurnStartedAt;
|
|
496
|
+
outputUpdates = 0;
|
|
487
497
|
reportActivity("running");
|
|
488
498
|
const remainingRuntimeMs = maxRuntimeMs > 0
|
|
489
499
|
? maxRuntimeMs - (node_perf_hooks_1.performance.now() - agentBudgetStartedAt)
|
|
@@ -508,7 +518,7 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
508
518
|
cwd: gitWorktree.worktreePath,
|
|
509
519
|
dockerExec: sandbox ? { containerName: sandbox.name, runner: sandbox_cjs_1.nodeCommandRunner } : undefined,
|
|
510
520
|
signal: activeAbortController.signal,
|
|
511
|
-
onActivity: () => { outputObservedAt = Date.now(); },
|
|
521
|
+
onActivity: () => { outputObservedAt = Date.now(); outputUpdates += 1; },
|
|
512
522
|
}, task.idle_timeout_ms ?? config.sessionIdleTimeoutMs ?? 45 * 60_000, runtime === "opencode" ? config.opencodeStartupTimeoutMs : 0);
|
|
513
523
|
activeAbortController = null;
|
|
514
524
|
adapterRunning = false;
|
|
@@ -622,7 +632,8 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
622
632
|
deliveryFailureSummary =
|
|
623
633
|
`Session ended without delivering the task: ${delivery.reason}. ` +
|
|
624
634
|
`${deliveryCorrectionRetries} correction turn(s) did not recover it. ` +
|
|
625
|
-
"The session worktree is deleted at teardown
|
|
635
|
+
"The session worktree is deleted at teardown. Pushed commits remain on origin; " +
|
|
636
|
+
"uncommitted or unpushed work may be lost. The task needs another attempt.";
|
|
626
637
|
log.warn(`failing ${leaseId}: ${deliveryFailureSummary}`);
|
|
627
638
|
mapping.leaseOutcome = "failed";
|
|
628
639
|
mapping.exitStatus = "failed";
|
package/package.json
CHANGED