lark-coding-assistant 0.2.7 → 0.2.8
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/cli.js +32 -6
- package/dist/cli.js.map +1 -1
- package/dist/daemon-entry.js +73 -32
- package/dist/daemon-entry.js.map +1 -1
- package/dist/hook-entry.js.map +1 -1
- package/package.json +1 -1
package/dist/daemon-entry.js
CHANGED
|
@@ -450,6 +450,7 @@ var SessionReconciler = class {
|
|
|
450
450
|
misses = /* @__PURE__ */ new Map();
|
|
451
451
|
async reconcile(input, discover = false, signal) {
|
|
452
452
|
const sessions = { ...input.sessions };
|
|
453
|
+
const removedSessions = [];
|
|
453
454
|
let changed = false;
|
|
454
455
|
for (const [id, session] of Object.entries(sessions)) {
|
|
455
456
|
if (signal?.aborted) throw signal.reason;
|
|
@@ -467,9 +468,14 @@ var SessionReconciler = class {
|
|
|
467
468
|
continue;
|
|
468
469
|
}
|
|
469
470
|
if (result2.status === "dead") {
|
|
471
|
+
const terminalOutput = await this.tmux.capture(result2.pane.paneId, 80, signal).catch((error) => {
|
|
472
|
+
void this.log(`failed to capture dead tmux pane ${result2.pane.paneId}: ${errorMessage2(error)}`);
|
|
473
|
+
return "";
|
|
474
|
+
});
|
|
470
475
|
await this.tmux.killSession(result2.pane.sessionName, signal).catch((error) => this.log(
|
|
471
476
|
`failed to clean dead tmux session ${result2.pane.sessionName}: ${errorMessage2(error)}`
|
|
472
477
|
));
|
|
478
|
+
removedSessions.push({ session, pane: result2.pane, terminalOutput });
|
|
473
479
|
delete sessions[id];
|
|
474
480
|
this.misses.delete(id);
|
|
475
481
|
changed = true;
|
|
@@ -478,6 +484,7 @@ var SessionReconciler = class {
|
|
|
478
484
|
const misses = (this.misses.get(id) ?? 0) + 1;
|
|
479
485
|
this.misses.set(id, misses);
|
|
480
486
|
if (misses < this.missingThreshold) continue;
|
|
487
|
+
removedSessions.push({ session });
|
|
481
488
|
delete sessions[id];
|
|
482
489
|
this.misses.delete(id);
|
|
483
490
|
changed = true;
|
|
@@ -489,7 +496,7 @@ var SessionReconciler = class {
|
|
|
489
496
|
if (activeSessionId !== input.activeSessionId) changed = true;
|
|
490
497
|
const removedActive = input.activeSessionId && !sessions[input.activeSessionId] ? input.sessions?.[input.activeSessionId] : void 0;
|
|
491
498
|
const state = changed ? { ...input, sessions, activeSessionId, updatedAt: Date.now() } : input;
|
|
492
|
-
return { state, liveSessions: Object.values(sessions), removedActive, changed };
|
|
499
|
+
return { state, liveSessions: Object.values(sessions), removedActive, removedSessions, changed };
|
|
493
500
|
}
|
|
494
501
|
async confirm(session, signal) {
|
|
495
502
|
const direct = await this.tmux.inspectStatus(session.paneId, signal);
|
|
@@ -3222,6 +3229,10 @@ var AssistantDaemon = class {
|
|
|
3222
3229
|
}
|
|
3223
3230
|
case "start":
|
|
3224
3231
|
return this.startSession(request.sessionId, request.cwd, request.agent, request.resume);
|
|
3232
|
+
case "reconcile": {
|
|
3233
|
+
await this.reconcileSessions(true);
|
|
3234
|
+
return { ok: true };
|
|
3235
|
+
}
|
|
3225
3236
|
case "status":
|
|
3226
3237
|
return { ok: true, value: await this.runtimeStatus(request.sessionId) };
|
|
3227
3238
|
case "tail":
|
|
@@ -3333,11 +3344,6 @@ var AssistantDaemon = class {
|
|
|
3333
3344
|
agentVersion,
|
|
3334
3345
|
updatedAt: Date.now()
|
|
3335
3346
|
};
|
|
3336
|
-
const pendingClaim = this.pendingAgentSessionClaims.get(sessionId);
|
|
3337
|
-
if (pendingClaim) {
|
|
3338
|
-
const claimed = this.claimStartingAgentSession(session, pendingClaim);
|
|
3339
|
-
if (!claimed.ok) return claimed;
|
|
3340
|
-
}
|
|
3341
3347
|
if (resume && resume.mode !== "picker") {
|
|
3342
3348
|
const initialClaim = await context.stage(
|
|
3343
3349
|
"agent-identity",
|
|
@@ -3376,11 +3382,6 @@ var AssistantDaemon = class {
|
|
|
3376
3382
|
));
|
|
3377
3383
|
await this.rememberSessionWorkspace(session.cwd);
|
|
3378
3384
|
}
|
|
3379
|
-
const lateClaim = this.pendingAgentSessionClaims.get(sessionId);
|
|
3380
|
-
if (lateClaim) {
|
|
3381
|
-
const claimed = this.claimStartingAgentSession(session, lateClaim);
|
|
3382
|
-
if (!claimed.ok) return claimed;
|
|
3383
|
-
}
|
|
3384
3385
|
try {
|
|
3385
3386
|
await context.stage("metadata", () => this.tmux.writeMetadata(pane.sessionName, {
|
|
3386
3387
|
managed: true,
|
|
@@ -4654,20 +4655,56 @@ ${escapeFence2(output).slice(-6500)}
|
|
|
4654
4655
|
if (session && session.agent !== candidate.agent) {
|
|
4655
4656
|
return { ok: false, error: "agent-session candidate does not match managed session" };
|
|
4656
4657
|
}
|
|
4657
|
-
|
|
4658
|
-
if (owner) {
|
|
4658
|
+
if (!session) {
|
|
4659
4659
|
this.pendingAgentSessionClaims.set(candidate.sessionId, candidate);
|
|
4660
4660
|
await this.log(
|
|
4661
|
-
`agent session
|
|
4661
|
+
`agent session hook candidate awaiting managed session: session=${candidate.sessionId} agent=${candidate.agent} agentSession=${candidate.agentSessionId}`
|
|
4662
4662
|
);
|
|
4663
|
-
|
|
4664
|
-
return fail(agentSessionInUse(candidate.sessionId, owner.id, candidate.agentSessionId));
|
|
4663
|
+
return { ok: true };
|
|
4665
4664
|
}
|
|
4666
|
-
if (
|
|
4667
|
-
this.pendingAgentSessionClaims.
|
|
4665
|
+
if (session.agentSessionId) {
|
|
4666
|
+
this.pendingAgentSessionClaims.delete(session.id);
|
|
4667
|
+
if (session.agentSessionId !== candidate.agentSessionId) {
|
|
4668
|
+
await this.log(
|
|
4669
|
+
`ignored agent session hook candidate: session=${session.id} agent=${session.agent} hookSession=${candidate.agentSessionId} confirmedSession=${session.agentSessionId}`
|
|
4670
|
+
);
|
|
4671
|
+
}
|
|
4668
4672
|
return { ok: true };
|
|
4669
4673
|
}
|
|
4670
|
-
|
|
4674
|
+
this.pendingAgentSessionClaims.set(candidate.sessionId, candidate);
|
|
4675
|
+
const agentSessionId = await this.resolvePaneNativeAgentSessionId(session);
|
|
4676
|
+
if (!agentSessionId) return { ok: true };
|
|
4677
|
+
if (agentSessionId !== candidate.agentSessionId) {
|
|
4678
|
+
await this.log(
|
|
4679
|
+
`ignored stale agent session hook candidate: session=${session.id} agent=${session.agent} hookSession=${candidate.agentSessionId} pidSession=${agentSessionId}`
|
|
4680
|
+
);
|
|
4681
|
+
}
|
|
4682
|
+
const confirmed = { ...candidate, agentSessionId, source: "pid-confirmed" };
|
|
4683
|
+
const owner = this.findAgentSessionOwner(session.agent, agentSessionId, session.id);
|
|
4684
|
+
if (owner) {
|
|
4685
|
+
await this.log(
|
|
4686
|
+
`confirmed agent session conflict: session=${session.id} agent=${session.agent} agentSession=${agentSessionId} owner=${owner.id}`
|
|
4687
|
+
);
|
|
4688
|
+
await this.rejectDuplicateAgentSession(confirmed, owner);
|
|
4689
|
+
return fail(agentSessionInUse(session.id, owner.id, agentSessionId));
|
|
4690
|
+
}
|
|
4691
|
+
return this.persistConfirmedAgentSessionClaim(session, confirmed);
|
|
4692
|
+
}
|
|
4693
|
+
async resolvePaneNativeAgentSessionId(session) {
|
|
4694
|
+
let pane;
|
|
4695
|
+
try {
|
|
4696
|
+
pane = await this.tmux.inspect(session.paneId);
|
|
4697
|
+
} catch (error) {
|
|
4698
|
+
void this.log(`failed to inspect pane for native session: session=${session.id} error=${errorMessage3(error)}`);
|
|
4699
|
+
return void 0;
|
|
4700
|
+
}
|
|
4701
|
+
if (!pane || pane.dead) return void 0;
|
|
4702
|
+
return resolveNativeAgentSessionId(session.agent, pane.pid).catch((error) => {
|
|
4703
|
+
void this.log(`failed to resolve native agent session for ${session.id}: ${errorMessage3(error)}`);
|
|
4704
|
+
return void 0;
|
|
4705
|
+
});
|
|
4706
|
+
}
|
|
4707
|
+
async persistConfirmedAgentSessionClaim(session, candidate) {
|
|
4671
4708
|
const updated = { ...session, agentSessionId: candidate.agentSessionId, updatedAt: Date.now() };
|
|
4672
4709
|
this.state = {
|
|
4673
4710
|
...this.state,
|
|
@@ -4692,12 +4729,7 @@ ${escapeFence2(output).slice(-6500)}
|
|
|
4692
4729
|
async refreshNativeAgentSessionClaims() {
|
|
4693
4730
|
for (const session of Object.values(this.state.sessions ?? {})) {
|
|
4694
4731
|
if (session.agentSessionId) continue;
|
|
4695
|
-
const
|
|
4696
|
-
if (!pane || pane.dead) continue;
|
|
4697
|
-
const agentSessionId = await resolveNativeAgentSessionId(session.agent, pane.pid).catch((error) => {
|
|
4698
|
-
void this.log(`failed to resolve native agent session for ${session.id}: ${errorMessage3(error)}`);
|
|
4699
|
-
return void 0;
|
|
4700
|
-
});
|
|
4732
|
+
const agentSessionId = await this.resolvePaneNativeAgentSessionId(session);
|
|
4701
4733
|
if (!agentSessionId) continue;
|
|
4702
4734
|
await this.handleAgentSessionStarted({
|
|
4703
4735
|
sessionId: session.id,
|
|
@@ -4717,11 +4749,6 @@ ${escapeFence2(output).slice(-6500)}
|
|
|
4717
4749
|
session.agentSessionId = committedClaim2;
|
|
4718
4750
|
return { ok: true };
|
|
4719
4751
|
}
|
|
4720
|
-
const pending2 = this.pendingAgentSessionClaims.get(session.id);
|
|
4721
|
-
if (pending2) {
|
|
4722
|
-
const claimed = this.claimStartingAgentSession(session, pending2);
|
|
4723
|
-
if (!claimed.ok || session.agentSessionId) return claimed;
|
|
4724
|
-
}
|
|
4725
4752
|
if (signal?.aborted) throw signal.reason;
|
|
4726
4753
|
const pane2 = await this.tmux.inspect(session.paneId, signal);
|
|
4727
4754
|
if (signal?.aborted) throw signal.reason;
|
|
@@ -4746,8 +4773,6 @@ ${escapeFence2(output).slice(-6500)}
|
|
|
4746
4773
|
const pane = await this.tmux.inspect(session.paneId, signal);
|
|
4747
4774
|
if (signal?.aborted) throw signal.reason;
|
|
4748
4775
|
if (!pane || pane.dead) return fail(await this.startupExitedError(session, pane));
|
|
4749
|
-
const pending = this.pendingAgentSessionClaims.get(session.id);
|
|
4750
|
-
if (pending) return this.claimStartingAgentSession(session, pending);
|
|
4751
4776
|
const committedClaim = this.state.sessions?.[session.id]?.agentSessionId;
|
|
4752
4777
|
if (committedClaim) {
|
|
4753
4778
|
session.agentSessionId = committedClaim;
|
|
@@ -4900,6 +4925,22 @@ ${output}`
|
|
|
4900
4925
|
).catch((error) => this.log(`exit notification failed: ${errorMessage3(error)}`));
|
|
4901
4926
|
}
|
|
4902
4927
|
this.state = result2.state;
|
|
4928
|
+
for (const removed of result2.removedSessions) {
|
|
4929
|
+
const exitStatus = removed.pane?.exitStatus;
|
|
4930
|
+
if (exitStatus === void 0 || exitStatus === 0) continue;
|
|
4931
|
+
const terminalExcerpt = startupTerminalExcerpt(tailScreen(removed.terminalOutput ?? "", 80).slice(-3e3));
|
|
4932
|
+
await this.rememberSessionExitEvent({
|
|
4933
|
+
sessionId: removed.session.id,
|
|
4934
|
+
agent: removed.session.agent,
|
|
4935
|
+
reason: "agent-exited",
|
|
4936
|
+
exitStatus,
|
|
4937
|
+
terminalExcerpt: terminalExcerpt || void 0,
|
|
4938
|
+
occurredAt: Date.now()
|
|
4939
|
+
});
|
|
4940
|
+
await this.log(
|
|
4941
|
+
`agent exited: session=${removed.session.id} agent=${removed.session.agent} exit=${exitStatus}`
|
|
4942
|
+
);
|
|
4943
|
+
}
|
|
4903
4944
|
for (const sessionId of this.pendingResumePickers.keys()) {
|
|
4904
4945
|
if (!this.state.sessions?.[sessionId]) this.pendingResumePickers.delete(sessionId);
|
|
4905
4946
|
}
|