@songsid/agend 2.2.0-beta.5 → 2.2.0-beta.7
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/agent-cli-instructions.md +6 -2
- package/dist/agent-cli.js +9 -5
- package/dist/agent-cli.js.map +1 -1
- package/dist/backend/claude-carry.d.ts +22 -0
- package/dist/backend/claude-carry.js +170 -0
- package/dist/backend/claude-carry.js.map +1 -0
- package/dist/backend/claude-code.d.ts +16 -0
- package/dist/backend/claude-code.js +92 -2
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +7 -0
- package/dist/backend/credential-profile.js +7 -1
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/kiro.js +5 -2
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.d.ts +67 -0
- package/dist/backend/muse.js +370 -44
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/background-work-ended.d.ts +18 -0
- package/dist/background-work-ended.js +30 -0
- package/dist/background-work-ended.js.map +1 -0
- package/dist/channel/adapters/discord.js +12 -1
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +4 -5
- package/dist/channel/adapters/telegram.js +39 -17
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +3 -3
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-edit-errors.d.ts +5 -0
- package/dist/channel/message-edit-errors.js +24 -0
- package/dist/channel/message-edit-errors.js.map +1 -0
- package/dist/channel/types.d.ts +3 -0
- package/dist/cli.js +25 -10
- package/dist/cli.js.map +1 -1
- package/dist/cross-instance-envelope.js +2 -0
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +6 -0
- package/dist/daemon.js +165 -54
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +27 -0
- package/dist/delivery-outbox.js +175 -6
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-context.d.ts +4 -1
- package/dist/fleet-manager.d.ts +110 -6
- package/dist/fleet-manager.js +558 -100
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +44 -9
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +14 -1
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +4 -0
- package/dist/human-delivery-receipts.d.ts +83 -0
- package/dist/human-delivery-receipts.js +194 -0
- package/dist/human-delivery-receipts.js.map +1 -0
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +1 -1
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +22 -2
- package/dist/locale.js.map +1 -1
- package/dist/needs-you-hub.js +2 -0
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +6 -0
- package/dist/needs-you-live.js +23 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/outbound-handlers.d.ts +10 -0
- package/dist/outbound-handlers.js +39 -14
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +15 -13
- package/dist/outbound-schemas.js +5 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-link-progress.d.ts +1 -1
- package/dist/public-link-progress.js +8 -2
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.d.ts +2 -1
- package/dist/public-preview.js +8 -5
- package/dist/public-preview.js.map +1 -1
- package/dist/public-web-link.d.ts +4 -1
- package/dist/public-web-link.js +27 -10
- package/dist/public-web-link.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +3 -0
- package/dist/reply-buttons-controller.js +3 -2
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/restart-progress.d.ts +4 -0
- package/dist/restart-progress.js +7 -0
- package/dist/restart-progress.js.map +1 -1
- package/dist/service-installer.d.ts +31 -0
- package/dist/service-installer.js +41 -2
- package/dist/service-installer.js.map +1 -1
- package/dist/topic-commands.d.ts +3 -2
- package/dist/topic-commands.js +17 -5
- package/dist/topic-commands.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -15
- package/dist/tunnel/cloudflared.js +36 -1
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/types.d.ts +5 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/ui/chat-strings.js +8 -2
- package/dist/ui/chat-thread.js +24 -4
- package/dist/ui/chat-time.js +80 -0
- package/dist/ui/preview-panel.js +7 -1
- package/dist/ui/preview.js +5 -1
- package/dist/ui/shared/app-stream.js +21 -4
- package/dist/ui/shared/app.css +9 -3
- package/dist/ui/shared/usage-dialog.js +10 -1
- package/dist/update-install.d.ts +6 -2
- package/dist/update-install.js +8 -2
- package/dist/update-install.js.map +1 -1
- package/dist/update-marker.d.ts +11 -0
- package/dist/update-marker.js +12 -0
- package/dist/update-marker.js.map +1 -1
- package/dist/web-api.d.ts +5 -1
- package/dist/web-api.js +8 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-commands.d.ts +2 -2
- package/dist/web-commands.js +3 -2
- package/dist/web-commands.js.map +1 -1
- package/dist/web-reply-files.d.ts +45 -0
- package/dist/web-reply-files.js +223 -0
- package/dist/web-reply-files.js.map +1 -0
- package/dist/web-server-drain.d.ts +10 -0
- package/dist/web-server-drain.js +50 -0
- package/dist/web-server-drain.js.map +1 -0
- package/dist/web-upload.d.ts +17 -4
- package/dist/web-upload.js +64 -13
- package/dist/web-upload.js.map +1 -1
- package/package.json +1 -1
- package/templates/launchd.plist.ejs +3 -1
- package/templates/systemd.service.ejs +2 -1
|
@@ -8,6 +8,8 @@ export function renderCrossInstanceHandoffMetadata(meta) {
|
|
|
8
8
|
rows.push(`${label}: ${value.trim()}`);
|
|
9
9
|
};
|
|
10
10
|
add("message_id", meta.message_id);
|
|
11
|
+
add("verification_id", meta.verification_id);
|
|
12
|
+
add("forwards", meta.forwards);
|
|
11
13
|
add("correlation_id", meta.correlation_id);
|
|
12
14
|
add("request_kind", meta.request_kind);
|
|
13
15
|
add("task_summary", meta.task_summary);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-instance-envelope.js","sourceRoot":"","sources":["../src/cross-instance-envelope.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cross-instance-envelope.js","sourceRoot":"","sources":["../src/cross-instance-envelope.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
CHANGED
|
@@ -1484,6 +1484,12 @@ export declare class Daemon extends EventEmitter {
|
|
|
1484
1484
|
/** #1650: how this instance talks to the fleet — MCP tools, or agend-agent commands (agent_mode: cli). */
|
|
1485
1485
|
private agentMode;
|
|
1486
1486
|
private formatInboundMessage;
|
|
1487
|
+
/** Pure cached owner: no pane/process query on ingress. */
|
|
1488
|
+
captureHumanReceiptOwner(): string | null;
|
|
1489
|
+
/** The same formatter/sanitizer used by the actual write; snapshot only. */
|
|
1490
|
+
humanReceiptWire(content: string, meta: Record<string, string>, kind: string): string;
|
|
1491
|
+
private humanReceiptAttempt;
|
|
1492
|
+
private finishHumanReceipt;
|
|
1487
1493
|
/**
|
|
1488
1494
|
* Whether ONE delivery reached a verdict, carried by that delivery.
|
|
1489
1495
|
*
|
package/dist/daemon.js
CHANGED
|
@@ -9,6 +9,7 @@ import { rotateLogIfNeededAsync } from "./logger.js";
|
|
|
9
9
|
import { coredumpFilterLaunchPrefix } from "./coredump-filter.js";
|
|
10
10
|
import { mcpServerState } from "./mcp-liveness.js";
|
|
11
11
|
import { clearPausedMarker, writePausedMarker } from "./pause-marker.js";
|
|
12
|
+
import { writeBackgroundWorkEndedMarker } from "./background-work-ended.js";
|
|
12
13
|
import { TmuxManager, resolveTmuxLogicalSize } from "./tmux-manager.js";
|
|
13
14
|
import { TranscriptMonitor } from "./transcript-monitor.js";
|
|
14
15
|
import { createTranscriptSource } from "./transcript-sources.js";
|
|
@@ -32,6 +33,7 @@ import { HangDetector } from "./hang-detector.js";
|
|
|
32
33
|
import { writeSecretFile } from "./secret-file.js";
|
|
33
34
|
import { PaneWriteLock } from "./pane-write-lock.js";
|
|
34
35
|
import { buildFleetInstructions } from "./instructions.js";
|
|
36
|
+
import { formatHumanInboundMessage, prepareDeliveryWire, steerInboundEnvelope, BTW_INBOUND_PREFIX, humanBodyHash, humanOwnerObjectId } from "./human-delivery-receipts.js";
|
|
35
37
|
import { formatCrossInstanceInboundMessage, renderCrossInstanceHandoffMetadata, } from "./cross-instance-envelope.js";
|
|
36
38
|
import { agendMessageInInput, bottomRowIsReady, inputAreaText, inputShowsPastedText, pastedTextSignature, pasteLeftInInput, strandedAgendMessageInInput } from "./pane-input-residue.js";
|
|
37
39
|
import { TurnReplyGuard } from "./turn-reply-guard.js";
|
|
@@ -2002,6 +2004,7 @@ export class Daemon extends EventEmitter {
|
|
|
2002
2004
|
}
|
|
2003
2005
|
}
|
|
2004
2006
|
deferDurableDelivery(meta, reason) {
|
|
2007
|
+
this.finishHumanReceipt(meta, { reached: false });
|
|
2005
2008
|
const delivery = this.durableDeliveryAttempt(meta);
|
|
2006
2009
|
if (delivery === null || delivery === false)
|
|
2007
2010
|
return;
|
|
@@ -4232,6 +4235,13 @@ export class Daemon extends EventEmitter {
|
|
|
4232
4235
|
if (!backend.quitBlockedByDialog(pane))
|
|
4233
4236
|
return false;
|
|
4234
4237
|
this.logger.warn({ reason }, "The CLI asked to confirm its exit (background work is running) — cancelling that prompt and stopping the process, not answering it");
|
|
4238
|
+
// #1716: the background work is about to be ended — record it where the
|
|
4239
|
+
// stop/restart reply and the instance topic notice can report it, so the
|
|
4240
|
+
// kill is never silent.
|
|
4241
|
+
try {
|
|
4242
|
+
writeBackgroundWorkEndedMarker(this.instanceDir, reason);
|
|
4243
|
+
}
|
|
4244
|
+
catch { /* reporting only */ }
|
|
4235
4245
|
await this.tmux.sendSpecialKey("Escape").catch(() => false);
|
|
4236
4246
|
return true;
|
|
4237
4247
|
}
|
|
@@ -4564,6 +4574,39 @@ export class Daemon extends EventEmitter {
|
|
|
4564
4574
|
this.pauseRequested = false;
|
|
4565
4575
|
return;
|
|
4566
4576
|
}
|
|
4577
|
+
// #1717: an idle pause is AgEnD-initiated and silent — it must not kill
|
|
4578
|
+
// the user's running background work the way an explicit stop may. Defer
|
|
4579
|
+
// this cycle while the backend reports background work; the next idle
|
|
4580
|
+
// tick retries once the task ends. A pane-capture failure proceeds (the
|
|
4581
|
+
// quit-menu handler below stays the backstop), never wedges unpaused.
|
|
4582
|
+
if (this.backend?.backgroundWorkRunning && this.tmux) {
|
|
4583
|
+
const tmux = this.tmux;
|
|
4584
|
+
const windowId = tmux.getWindowId?.();
|
|
4585
|
+
const generation = this.spawnGeneration;
|
|
4586
|
+
let pane = null;
|
|
4587
|
+
try {
|
|
4588
|
+
pane = await tmux.capturePane();
|
|
4589
|
+
}
|
|
4590
|
+
catch { /* capture failed — pause as before, after revalidation */ }
|
|
4591
|
+
// #1730 P2-2: the await yields — the pane read is only valid for the
|
|
4592
|
+
// world it was taken from. Revalidate owner, phase, state and queue
|
|
4593
|
+
// before acting on it; anything that moved defers this cycle.
|
|
4594
|
+
if (this.tmux !== tmux
|
|
4595
|
+
|| this.tmux?.getWindowId?.() !== windowId
|
|
4596
|
+
|| this.spawnGeneration !== generation
|
|
4597
|
+
|| this.getPauseWakeState() !== "active"
|
|
4598
|
+
|| !(this.instanceState === "idle" || (allowStuck && this.instanceState === "stuck"))
|
|
4599
|
+
|| this.pasteQueueDepth > 0) {
|
|
4600
|
+
this.logger.info("Deferring auto-pause: pause preconditions changed during the pane read");
|
|
4601
|
+
this.pauseRequested = false;
|
|
4602
|
+
return;
|
|
4603
|
+
}
|
|
4604
|
+
if (pane !== null && this.backend?.backgroundWorkRunning?.(pane)) {
|
|
4605
|
+
this.logger.info("Deferring auto-pause: background work is still running");
|
|
4606
|
+
this.pauseRequested = false;
|
|
4607
|
+
return;
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4567
4610
|
this.pauseWakeState = "pausing";
|
|
4568
4611
|
this.healthCheckPaused = true;
|
|
4569
4612
|
this.freezeRuntimeMonitors();
|
|
@@ -6281,11 +6324,7 @@ export class Daemon extends EventEmitter {
|
|
|
6281
6324
|
* is a durable delivery) must LEAD the persisted user message — restart reconciliation recognises a delivery only by a
|
|
6282
6325
|
* marker at the start of the body (#1197) — so the banner goes right after it, not in front of it.
|
|
6283
6326
|
*/
|
|
6284
|
-
static steerEnvelope(inbound) {
|
|
6285
|
-
const banner = "[STEERING — mid-task course correction. Fold this into the CURRENT work if one is active.]\n";
|
|
6286
|
-
const marker = inbound.match(/^\[agend-delivery-id:[^\]\r\n]+\]\r?\n/);
|
|
6287
|
-
return marker ? marker[0] + banner + inbound.slice(marker[0].length) : banner + inbound;
|
|
6288
|
-
}
|
|
6327
|
+
static steerEnvelope(inbound) { return steerInboundEnvelope(inbound); }
|
|
6289
6328
|
/**
|
|
6290
6329
|
* The one place an inbound message grows its metadata wrapper ([user:]/
|
|
6291
6330
|
* [from:] prefix, pending reactions, handoff metadata, reply instructions).
|
|
@@ -6296,35 +6335,65 @@ export class Daemon extends EventEmitter {
|
|
|
6296
6335
|
/** #1650: how this instance talks to the fleet — MCP tools, or agend-agent commands (agent_mode: cli). */
|
|
6297
6336
|
agentMode() { return this.config.agent_mode === "cli" ? "cli" : "mcp"; }
|
|
6298
6337
|
formatInboundMessage(content, meta) {
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
let formatted;
|
|
6302
|
-
if (
|
|
6303
|
-
formatted
|
|
6338
|
+
if (!meta.from_instance)
|
|
6339
|
+
return formatHumanInboundMessage(content, meta, this.agentMode());
|
|
6340
|
+
let formatted = formatCrossInstanceInboundMessage(content, meta, this.agentMode());
|
|
6341
|
+
if (meta.reply_to_text)
|
|
6342
|
+
formatted += '\n(reply_to: "' + meta.reply_to_text + '")';
|
|
6343
|
+
if (meta.delivery_id)
|
|
6344
|
+
formatted = "[agend-delivery-id:" + meta.delivery_id + "]\n" + formatted;
|
|
6345
|
+
return formatted;
|
|
6346
|
+
}
|
|
6347
|
+
/** Pure cached owner: no pane/process query on ingress. */
|
|
6348
|
+
captureHumanReceiptOwner() {
|
|
6349
|
+
try {
|
|
6350
|
+
if (this.deliveryWritesStopping || this.spawning || !this.tmux)
|
|
6351
|
+
return null;
|
|
6352
|
+
const o = this.interactionOwner();
|
|
6353
|
+
const window = this.tmux.getWindowId();
|
|
6354
|
+
if (!window || !o.bootId || ![o.spawnGeneration, o.launchAttempt, o.launchFenceEpoch, this.deliveryEpoch]
|
|
6355
|
+
.every(n => Number.isSafeInteger(n) && n >= 0))
|
|
6356
|
+
return null;
|
|
6357
|
+
return JSON.stringify([o.bootId, o.spawnGeneration, o.launchAttempt, o.launchFenceEpoch,
|
|
6358
|
+
this.deliveryEpoch, humanOwnerObjectId(this.tmux), window]);
|
|
6304
6359
|
}
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
}
|
|
6324
|
-
|
|
6325
|
-
|
|
6360
|
+
catch {
|
|
6361
|
+
return null;
|
|
6362
|
+
}
|
|
6363
|
+
}
|
|
6364
|
+
/** The same formatter/sanitizer used by the actual write; snapshot only. */
|
|
6365
|
+
humanReceiptWire(content, meta, kind) {
|
|
6366
|
+
let wire = kind === "raw_paste" ? content
|
|
6367
|
+
: !meta.from_instance && content.startsWith("/raw ") && kind === "fleet_inbound"
|
|
6368
|
+
? content.slice(5) : this.formatInboundMessage(content, meta);
|
|
6369
|
+
if (kind === "steer")
|
|
6370
|
+
wire = Daemon.steerEnvelope(wire);
|
|
6371
|
+
else if (kind === "btw")
|
|
6372
|
+
wire = BTW_INBOUND_PREFIX + wire;
|
|
6373
|
+
return prepareDeliveryWire(wire, kind === "raw_paste");
|
|
6374
|
+
}
|
|
6375
|
+
humanReceiptAttempt(meta, wire) {
|
|
6376
|
+
const id = meta.human_receipt_id;
|
|
6377
|
+
const daemonOwner = meta.human_daemon_owner;
|
|
6378
|
+
if (!id || !/^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/.test(id) || meta.verification_id !== "hmsg-" + id
|
|
6379
|
+
|| !daemonOwner || !meta.human_owner_key || !/^[a-f0-9]{64}$/.test(meta.human_wire_sha256 ?? "")
|
|
6380
|
+
|| humanBodyHash(prepareDeliveryWire(wire)) !== meta.human_wire_sha256)
|
|
6381
|
+
return undefined;
|
|
6382
|
+
return { receiptId: id, verificationId: meta.verification_id, expectedWireHash: meta.human_wire_sha256,
|
|
6383
|
+
ownerKey: meta.human_owner_key, current: () => this.captureHumanReceiptOwner() === daemonOwner };
|
|
6384
|
+
}
|
|
6385
|
+
finishHumanReceipt(meta, verdict) {
|
|
6386
|
+
if (!meta.human_receipt_id || !meta.human_owner_key)
|
|
6387
|
+
return;
|
|
6388
|
+
const attempt = verdict.humanReceipt;
|
|
6389
|
+
const proof = attempt?.current() && !["unverified", "output-edge", "unverifiable"].includes(verdict.proof ?? "")
|
|
6390
|
+
? attempt.proof ?? null : null;
|
|
6391
|
+
try {
|
|
6392
|
+
this.emit("human_receipt_result", { receipt_id: meta.human_receipt_id, owner_key: meta.human_owner_key, proof });
|
|
6393
|
+
}
|
|
6394
|
+
catch (err) {
|
|
6395
|
+
this.logger.error({ err }, "Could not publish human delivery evidence");
|
|
6326
6396
|
}
|
|
6327
|
-
return formatted;
|
|
6328
6397
|
}
|
|
6329
6398
|
/**
|
|
6330
6399
|
* Whether ONE delivery reached a verdict, carried by that delivery.
|
|
@@ -6417,12 +6486,13 @@ export class Daemon extends EventEmitter {
|
|
|
6417
6486
|
this.deferDurableDelivery(meta, "delivery epoch changed while waking for steer");
|
|
6418
6487
|
return;
|
|
6419
6488
|
}
|
|
6420
|
-
const verdict = { reached: false };
|
|
6489
|
+
const verdict = { reached: false, humanReceipt: this.humanReceiptAttempt(meta, formatted) };
|
|
6421
6490
|
try {
|
|
6422
6491
|
if (await this.deliverMessage(formatted, status, {
|
|
6423
6492
|
steer: true,
|
|
6424
6493
|
deliveryEpoch,
|
|
6425
6494
|
submissionId: meta.message_id,
|
|
6495
|
+
...(meta.verification_id ? { humanVerificationId: meta.verification_id } : {}),
|
|
6426
6496
|
verdict,
|
|
6427
6497
|
durableAttempt: durableAttempt || undefined,
|
|
6428
6498
|
})) {
|
|
@@ -6453,6 +6523,9 @@ export class Daemon extends EventEmitter {
|
|
|
6453
6523
|
this.retryDurableDeliveryBeforeBegin(durableAttempt, err.message);
|
|
6454
6524
|
throw err;
|
|
6455
6525
|
}
|
|
6526
|
+
finally {
|
|
6527
|
+
this.finishHumanReceipt(meta, verdict);
|
|
6528
|
+
}
|
|
6456
6529
|
}).catch(err => {
|
|
6457
6530
|
this.deferDurableDelivery(meta, `target wake/steer failed before pane submission: ${err.message}`);
|
|
6458
6531
|
this.logger.warn({ err: err.message }, "steer delivery error");
|
|
@@ -6468,24 +6541,37 @@ export class Daemon extends EventEmitter {
|
|
|
6468
6541
|
* so channel delivery intentionally uses a normal wrapped inbound instead.
|
|
6469
6542
|
*/
|
|
6470
6543
|
btwMessage(content, meta, deliveryEpoch = this.deliveryEpoch) {
|
|
6471
|
-
if (!this.isDeliveryEpochCurrent(deliveryEpoch))
|
|
6544
|
+
if (!this.isDeliveryEpochCurrent(deliveryEpoch)) {
|
|
6545
|
+
this.finishHumanReceipt(meta, { reached: false });
|
|
6472
6546
|
return;
|
|
6547
|
+
}
|
|
6473
6548
|
this.updateLastChat(meta.chat_id, meta.thread_id, meta.adapter_id);
|
|
6474
6549
|
this.pendingWork.recordInbound();
|
|
6475
6550
|
this.recordRecentUserMessage(content, meta);
|
|
6476
|
-
const formatted =
|
|
6477
|
-
+ this.formatInboundMessage(content, meta);
|
|
6551
|
+
const formatted = BTW_INBOUND_PREFIX + this.formatInboundMessage(content, meta);
|
|
6478
6552
|
const status = channelStatus(meta);
|
|
6479
6553
|
this.steerLock = this.steerLock.then(async () => {
|
|
6480
|
-
if (!this.isDeliveryEpochCurrent(deliveryEpoch))
|
|
6554
|
+
if (!this.isDeliveryEpochCurrent(deliveryEpoch)) {
|
|
6555
|
+
this.finishHumanReceipt(meta, { reached: false });
|
|
6481
6556
|
return;
|
|
6557
|
+
}
|
|
6482
6558
|
await this.wake();
|
|
6483
|
-
if (!this.isDeliveryEpochCurrent(deliveryEpoch))
|
|
6559
|
+
if (!this.isDeliveryEpochCurrent(deliveryEpoch)) {
|
|
6560
|
+
this.finishHumanReceipt(meta, { reached: false });
|
|
6484
6561
|
return;
|
|
6485
|
-
|
|
6486
|
-
|
|
6562
|
+
}
|
|
6563
|
+
const verdict = { reached: false, humanReceipt: this.humanReceiptAttempt(meta, formatted) };
|
|
6564
|
+
try {
|
|
6565
|
+
if (await this.deliverMessage(formatted, status, { steer: true, deliveryEpoch, submissionId: meta.message_id,
|
|
6566
|
+
...(meta.verification_id ? { humanVerificationId: meta.verification_id } : {}), verdict })) {
|
|
6567
|
+
this.markTurnStarted(meta, formatted, deliveryEpoch);
|
|
6568
|
+
}
|
|
6569
|
+
}
|
|
6570
|
+
finally {
|
|
6571
|
+
this.finishHumanReceipt(meta, verdict);
|
|
6487
6572
|
}
|
|
6488
6573
|
}).catch(err => {
|
|
6574
|
+
this.finishHumanReceipt(meta, { reached: false });
|
|
6489
6575
|
this.logger.warn({ err: err.message }, "btw delivery error");
|
|
6490
6576
|
});
|
|
6491
6577
|
}
|
|
@@ -6599,7 +6685,7 @@ export class Daemon extends EventEmitter {
|
|
|
6599
6685
|
// A fresh delivery begins a fresh turn — its bubble must not inherit
|
|
6600
6686
|
// the previous turn's tool list.
|
|
6601
6687
|
this.resetToolProgress();
|
|
6602
|
-
verdict = { reached: false };
|
|
6688
|
+
verdict = { reached: false, humanReceipt: this.humanReceiptAttempt(meta, formatted) };
|
|
6603
6689
|
const durableAttempt = this.durableDeliveryAttempt(meta, content);
|
|
6604
6690
|
if (durableAttempt === false) {
|
|
6605
6691
|
this.deferDurableDelivery(meta, "invalid durable delivery attempt metadata");
|
|
@@ -6609,6 +6695,7 @@ export class Daemon extends EventEmitter {
|
|
|
6609
6695
|
if (await this.deliverMessage(formatted, status, {
|
|
6610
6696
|
deliveryEpoch,
|
|
6611
6697
|
submissionId: meta.message_id,
|
|
6698
|
+
...(meta.verification_id ? { humanVerificationId: meta.verification_id } : {}),
|
|
6612
6699
|
verdict,
|
|
6613
6700
|
durableAttempt: durableAttempt || undefined,
|
|
6614
6701
|
})) {
|
|
@@ -6656,6 +6743,7 @@ export class Daemon extends EventEmitter {
|
|
|
6656
6743
|
this.logger.warn({ err: err.message }, "Durable pane delivery deferred after exception");
|
|
6657
6744
|
}
|
|
6658
6745
|
finally {
|
|
6746
|
+
this.finishHumanReceipt(meta, verdict);
|
|
6659
6747
|
this.pasteQueueDepth--;
|
|
6660
6748
|
}
|
|
6661
6749
|
}).catch(err => {
|
|
@@ -6692,12 +6780,7 @@ export class Daemon extends EventEmitter {
|
|
|
6692
6780
|
&& !this.isDeliveryEpochCurrent(opts.deliveryEpoch);
|
|
6693
6781
|
if (cancelled() || this.stormWindow?.isStopped())
|
|
6694
6782
|
return false;
|
|
6695
|
-
|
|
6696
|
-
const fenceCount = (formatted.match(/```/g) || []).length;
|
|
6697
|
-
if (!opts?.preserveExactBytes && fenceCount % 2 !== 0) {
|
|
6698
|
-
// Odd number of fences = unclosed. Remove all code fences from the message.
|
|
6699
|
-
formatted = formatted.replace(/```/g, "");
|
|
6700
|
-
}
|
|
6783
|
+
formatted = prepareDeliveryWire(formatted, opts?.preserveExactBytes);
|
|
6701
6784
|
// Direct paths such as /steer, /btw, /raw and schedules do not pass the
|
|
6702
6785
|
// FleetManager idle gate. Hold them at the final common pane-write path so
|
|
6703
6786
|
// a tmux storm cannot force any text into a half-booted CLI.
|
|
@@ -6870,7 +6953,7 @@ export class Daemon extends EventEmitter {
|
|
|
6870
6953
|
return stale();
|
|
6871
6954
|
if (residue !== "clear")
|
|
6872
6955
|
return this.failDelivery(verdict, status, "input-residue", residue);
|
|
6873
|
-
const written = await this.writeMessageToPane(formatted, windowId, handingOffToNativeQueue, status, opts?.submissionId, verdict, opts?.durableAttempt, opts?.steer === true, writeCurrent);
|
|
6956
|
+
const written = await this.writeMessageToPane(formatted, windowId, handingOffToNativeQueue, status, opts?.submissionId, verdict, opts?.durableAttempt, opts?.steer === true, writeCurrent, opts?.humanVerificationId);
|
|
6874
6957
|
// #1690: still under the lock — whatever waits on it next must already see what this write started.
|
|
6875
6958
|
if (verdict.paneWriteStarted)
|
|
6876
6959
|
opts?.onPaneWritten?.();
|
|
@@ -7665,7 +7748,7 @@ export class Daemon extends EventEmitter {
|
|
|
7665
7748
|
return false;
|
|
7666
7749
|
const row = norm(shown);
|
|
7667
7750
|
// The marker line holds nothing but the marker: the row is exactly it.
|
|
7668
|
-
if (/^\[agend-delivery-id:[^\]\s]+\]$/.test(first))
|
|
7751
|
+
if (/^\[agend-(?:delivery|human)-id:[^\]\s]+\]$/.test(first))
|
|
7669
7752
|
return row === first;
|
|
7670
7753
|
return row === first || row.startsWith(`${first} `);
|
|
7671
7754
|
}
|
|
@@ -8207,6 +8290,8 @@ export class Daemon extends EventEmitter {
|
|
|
8207
8290
|
if (!current())
|
|
8208
8291
|
return false;
|
|
8209
8292
|
if (evidence === "submitted") {
|
|
8293
|
+
if (pending.signature.unique)
|
|
8294
|
+
pending.signature.humanPositive?.("unique-id-pane");
|
|
8210
8295
|
if (status)
|
|
8211
8296
|
this.emit("message_confirmed", status);
|
|
8212
8297
|
return true;
|
|
@@ -8242,6 +8327,8 @@ export class Daemon extends EventEmitter {
|
|
|
8242
8327
|
if (retry === "cancelled")
|
|
8243
8328
|
return false;
|
|
8244
8329
|
if (retry === "submitted") {
|
|
8330
|
+
if (pending.signature.unique)
|
|
8331
|
+
pending.signature.humanPositive?.("unique-id-pane");
|
|
8245
8332
|
if (status)
|
|
8246
8333
|
this.emit("message_confirmed", status);
|
|
8247
8334
|
return true;
|
|
@@ -8382,9 +8469,24 @@ export class Daemon extends EventEmitter {
|
|
|
8382
8469
|
verdict = { reached: false }, durableAttempt, steer = false,
|
|
8383
8470
|
// #829: the caller's fence, asked once more after the last await before the
|
|
8384
8471
|
// first side effect. Stale means unwritten: false, with no failure verdict.
|
|
8385
|
-
stillCurrent) {
|
|
8386
|
-
const signature = this.submissionSignature(formatted, submissionId);
|
|
8472
|
+
stillCurrent, humanVerificationId) {
|
|
8473
|
+
const signature = this.submissionSignature(formatted, humanVerificationId ?? submissionId, humanVerificationId !== undefined);
|
|
8387
8474
|
const rawPaste = durableAttempt?.submissionMode === "raw_paste";
|
|
8475
|
+
const humanAttempt = verdict.humanReceipt;
|
|
8476
|
+
const humanMode = rawPaste ? "raw_paste" : steer ? "steer"
|
|
8477
|
+
: handingOffToNativeQueue ? "native_queue_handoff" : "idle_submit";
|
|
8478
|
+
if (humanAttempt && signature.unique && signature.value === "agend-human-id:" + humanAttempt.verificationId
|
|
8479
|
+
&& humanBodyHash(formatted) === humanAttempt.expectedWireHash) {
|
|
8480
|
+
signature.humanPositive = tag => {
|
|
8481
|
+
if (!humanAttempt.current() || (stillCurrent && !stillCurrent()))
|
|
8482
|
+
return;
|
|
8483
|
+
humanAttempt.proof = {
|
|
8484
|
+
receipt_id: humanAttempt.receiptId, verification_id: humanAttempt.verificationId,
|
|
8485
|
+
wire_sha256: humanBodyHash(formatted), owner_key: humanAttempt.ownerKey,
|
|
8486
|
+
mode: humanMode, tag,
|
|
8487
|
+
};
|
|
8488
|
+
};
|
|
8489
|
+
}
|
|
8388
8490
|
let windowId = initialWindowId;
|
|
8389
8491
|
// The spawn this write belongs to: acceptance evidence is only read while it is still the current one (#1197).
|
|
8390
8492
|
const spawnAtWrite = this.spawnGeneration;
|
|
@@ -8530,6 +8632,7 @@ export class Daemon extends EventEmitter {
|
|
|
8530
8632
|
// positively hold typed text, and after it be the empty placeholder again. The empty placeholder here means the
|
|
8531
8633
|
// paste never reached the box; an unreadable box (a failed or late capture, a dialog) proves nothing: no Enter.
|
|
8532
8634
|
const steerComposerProof = handingOffToNativeQueue && steer && !!this.backend?.readSteerComposer && tmuxAtWrite !== null;
|
|
8635
|
+
let humanComposerOwned = false;
|
|
8533
8636
|
let steerEnterDeadline = Infinity;
|
|
8534
8637
|
if (steerComposerProof) {
|
|
8535
8638
|
const deadline = performance.now() + STEER_PASTE_VISIBLE_MS;
|
|
@@ -8553,6 +8656,8 @@ export class Daemon extends EventEmitter {
|
|
|
8553
8656
|
return this.failDelivery(verdict, status, "steer-paste", before === null ? "box-unread" : `box-still-${before.mode}`);
|
|
8554
8657
|
if (!this.steerPasteIsOurs(before.pane, formatted))
|
|
8555
8658
|
return this.failDelivery(verdict, status, "steer-paste", "box-not-this-paste");
|
|
8659
|
+
const shown = this.backend?.readSteerComposerText?.(before.pane)?.replace(/\s+/g, " ").trim();
|
|
8660
|
+
humanComposerOwned = !!humanAttempt && shown === "[agend-human-id:" + humanAttempt.verificationId + "]";
|
|
8556
8661
|
// …and so is the Enter: the key is sent only while the reading is still within it.
|
|
8557
8662
|
steerEnterDeadline = deadline;
|
|
8558
8663
|
}
|
|
@@ -8624,6 +8729,9 @@ export class Daemon extends EventEmitter {
|
|
|
8624
8729
|
if (after === "steer" || after === "queue" || after === "idle") {
|
|
8625
8730
|
const probe = await withinMs(this.probeBlockingDialog(), deadline - performance.now());
|
|
8626
8731
|
if (probe?.state === "clear" && performance.now() <= deadline && steerCurrent() && this.getWindowId() === windowId) {
|
|
8732
|
+
if (humanComposerOwned)
|
|
8733
|
+
signature.humanPositive?.(after === "steer" ? "composer-empty-steer"
|
|
8734
|
+
: after === "queue" ? "composer-empty-queue" : "composer-empty-idle");
|
|
8627
8735
|
verdict.phase = "steer-accepted";
|
|
8628
8736
|
verdict.proof = `steer-composer-${after}`;
|
|
8629
8737
|
if (status)
|
|
@@ -9210,8 +9318,11 @@ export class Daemon extends EventEmitter {
|
|
|
9210
9318
|
// the input row is proof in itself — which also means a momentary
|
|
9211
9319
|
// failure to read the pane BEFORE pasting cannot turn a delivered
|
|
9212
9320
|
// message into a re-paste.
|
|
9213
|
-
if (signature.unique && after.payload > 0)
|
|
9321
|
+
if (signature.unique && after.payload > 0) {
|
|
9322
|
+
if (after.inputReadable)
|
|
9323
|
+
signature.humanPositive?.("unique-id-pane");
|
|
9214
9324
|
return this.submittedProof();
|
|
9325
|
+
}
|
|
9215
9326
|
if (unattributedResidue)
|
|
9216
9327
|
return "unverifiable";
|
|
9217
9328
|
// 3. Otherwise the evidence must be NEW relative to the pane as it was
|
|
@@ -9348,7 +9459,7 @@ export class Daemon extends EventEmitter {
|
|
|
9348
9459
|
* paste that never landed. System pastes carry no envelope and fall back to
|
|
9349
9460
|
* the body signature, which the baseline comparison still ties to this paste.
|
|
9350
9461
|
*/
|
|
9351
|
-
submissionSignature(formatted, trustedId) {
|
|
9462
|
+
submissionSignature(formatted, trustedId, verification = false) {
|
|
9352
9463
|
// The id must come from the message's own metadata, never from scanning the
|
|
9353
9464
|
// rendered text: agents and users discuss message ids in the body all the
|
|
9354
9465
|
// time ("check message_id: abc"), and a body-scanned value would match an
|
|
@@ -9357,7 +9468,7 @@ export class Daemon extends EventEmitter {
|
|
|
9357
9468
|
// the handoff metadata identifies THIS delivery.
|
|
9358
9469
|
const id = trustedId?.trim();
|
|
9359
9470
|
if (id)
|
|
9360
|
-
return { value:
|
|
9471
|
+
return { value: (verification ? "agend-human-id:" : "message_id:") + id, unique: true };
|
|
9361
9472
|
return { value: pastedTextSignature(formatted), unique: false };
|
|
9362
9473
|
}
|
|
9363
9474
|
/**
|