harnery 0.43.0 → 0.45.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/README.md +3 -3
- package/dist/commander.js +1 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +41 -48
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +38 -11
- package/dist/commands/diagnostics.d.ts.map +1 -1
- package/dist/commands/diagnostics.js +10 -0
- package/dist/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +22 -7
- package/dist/commands/files.d.ts +2 -2
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +7 -4
- package/dist/commands/governor.js +22 -10
- package/dist/commands/inbox.d.ts +1 -1
- package/dist/commands/inbox.d.ts.map +1 -1
- package/dist/commands/inbox.js +55 -2
- package/dist/commands/rm.d.ts.map +1 -1
- package/dist/commands/rm.js +28 -4
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/commands/servers.js +26 -17
- package/dist/commands/supervisor.d.ts.map +1 -1
- package/dist/commands/supervisor.js +7 -2
- package/dist/commands/toc.d.ts +14 -0
- package/dist/commands/toc.d.ts.map +1 -1
- package/dist/commands/toc.js +7 -4
- package/dist/commands/tunnel.d.ts +15 -0
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +453 -153
- package/dist/commands/turn-rollback.d.ts +5 -0
- package/dist/commands/turn-rollback.d.ts.map +1 -0
- package/dist/commands/turn-rollback.js +76 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +68 -30
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +18 -0
- package/dist/core/agents/live-authority-v3.d.ts +1 -0
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +11 -0
- package/dist/core/agents/live-lifecycle-v3.d.ts +4 -2
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/live-lifecycle-v3.js +28 -7
- package/dist/core/agents/mailbox.d.ts +9 -8
- package/dist/core/agents/mailbox.d.ts.map +1 -1
- package/dist/core/agents/mailbox.js +24 -17
- package/dist/core/agents/render/prompt-context.d.ts +2 -0
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +8 -12
- package/dist/core/agents/render/session-context.d.ts +2 -8
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +7 -30
- package/dist/core/agents/rules/stop-hook.js +3 -3
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +25 -14
- package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-writer.js +5 -0
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +5 -0
- package/dist/core/agents/state/proc-start.d.ts +19 -1
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +46 -1
- package/dist/core/agents/state/process-handle.d.ts +26 -0
- package/dist/core/agents/state/process-handle.d.ts.map +1 -0
- package/dist/core/agents/state/process-handle.js +121 -0
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +180 -70
- package/dist/core/agents/state/unchanged-file.d.ts +44 -0
- package/dist/core/agents/state/unchanged-file.d.ts.map +1 -0
- package/dist/core/agents/state/unchanged-file.js +390 -0
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
- package/dist/core/artifacts/delivery-card.js +2 -1
- package/dist/core/context/index.d.ts +22 -10
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +381 -119
- package/dist/core/context/observation.d.ts +26 -0
- package/dist/core/context/observation.d.ts.map +1 -0
- package/dist/core/context/observation.js +11 -0
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +25 -14
- package/dist/core/diagnostics/path-identity.d.ts +3 -0
- package/dist/core/diagnostics/path-identity.d.ts.map +1 -0
- package/dist/core/diagnostics/path-identity.js +12 -0
- package/dist/core/diagnostics/sanitize.d.ts.map +1 -1
- package/dist/core/diagnostics/sanitize.js +4 -3
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +29 -0
- package/dist/core/events/v3/generation-custody.d.ts +5 -0
- package/dist/core/events/v3/generation-custody.d.ts.map +1 -0
- package/dist/core/events/v3/generation-custody.js +50 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +1 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +7 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +77 -64
- package/dist/core/governor/planning.d.ts.map +1 -1
- package/dist/core/governor/planning.js +14 -1
- package/dist/core/governor/service-read.d.ts +10 -2
- package/dist/core/governor/service-read.d.ts.map +1 -1
- package/dist/core/governor/service-read.js +105 -22
- package/dist/core/governor/service.d.ts +20 -2
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +72 -47
- package/dist/core/hooks/cli.js +33 -5
- package/dist/core/inbox/contract.d.ts +2 -1
- package/dist/core/inbox/contract.d.ts.map +1 -1
- package/dist/core/inbox/index.d.ts +2 -0
- package/dist/core/inbox/index.d.ts.map +1 -1
- package/dist/core/inbox/index.js +2 -0
- package/dist/core/inbox/peer-messages.d.ts +37 -0
- package/dist/core/inbox/peer-messages.d.ts.map +1 -0
- package/dist/core/inbox/peer-messages.js +72 -0
- package/dist/core/inbox/service.d.ts +8 -1
- package/dist/core/inbox/service.d.ts.map +1 -1
- package/dist/core/inbox/service.js +67 -21
- package/dist/core/inbox/targets.d.ts +22 -0
- package/dist/core/inbox/targets.d.ts.map +1 -0
- package/dist/core/inbox/targets.js +108 -0
- package/dist/core/inbox/watcher.js +7 -3
- package/dist/core/journal/index.d.ts.map +1 -1
- package/dist/core/journal/index.js +17 -2
- package/dist/core/resources/contract.d.ts +3 -0
- package/dist/core/resources/contract.d.ts.map +1 -1
- package/dist/core/resources/service-status.d.ts +14 -1
- package/dist/core/resources/service-status.d.ts.map +1 -1
- package/dist/core/resources/service-status.js +23 -13
- package/dist/core/resources/service.d.ts +7 -13
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +34 -91
- package/dist/core/resources/status.d.ts +2 -5
- package/dist/core/resources/status.d.ts.map +1 -1
- package/dist/core/resources/status.js +36 -7
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +2 -9
- package/dist/core/servers/index.d.ts +34 -22
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +297 -144
- package/dist/core/servers/tunnels.d.ts +7 -7
- package/dist/core/servers/tunnels.d.ts.map +1 -1
- package/dist/core/servers/tunnels.js +47 -10
- package/dist/core/supervisor/contract.d.ts +12 -0
- package/dist/core/supervisor/contract.d.ts.map +1 -1
- package/dist/core/supervisor/explanations.d.ts.map +1 -1
- package/dist/core/supervisor/explanations.js +2 -1
- package/dist/core/supervisor/findings.d.ts.map +1 -1
- package/dist/core/supervisor/findings.js +54 -9
- package/dist/core/supervisor/service.d.ts +7 -1
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +59 -29
- package/dist/core/supervisor/services.d.ts.map +1 -1
- package/dist/core/supervisor/services.js +22 -1
- package/dist/core/supervisor/status.d.ts +17 -2
- package/dist/core/supervisor/status.d.ts.map +1 -1
- package/dist/core/supervisor/status.js +70 -12
- package/dist/core/supervisor/timeline.d.ts.map +1 -1
- package/dist/core/supervisor/timeline.js +2 -1
- package/dist/core/turn-rollback/content.d.ts +53 -0
- package/dist/core/turn-rollback/content.d.ts.map +1 -0
- package/dist/core/turn-rollback/content.js +396 -0
- package/dist/core/turn-rollback/index.d.ts +72 -0
- package/dist/core/turn-rollback/index.d.ts.map +1 -0
- package/dist/core/turn-rollback/index.js +443 -0
- package/dist/core/work/state.js +7 -7
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +105 -32
- package/dist/core/workflow/failure-evidence.d.ts +16 -0
- package/dist/core/workflow/failure-evidence.d.ts.map +1 -0
- package/dist/core/workflow/failure-evidence.js +114 -0
- package/dist/core/workflow/index.d.ts +5 -3
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +3 -2
- package/dist/core/workflow/live-session-v3.d.ts +6 -0
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +126 -5
- package/dist/core/workflow/proof.d.ts +5 -5
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +115 -20
- package/dist/core/workflow/recovery-audit.d.ts +30 -0
- package/dist/core/workflow/recovery-audit.d.ts.map +1 -0
- package/dist/core/workflow/recovery-audit.js +116 -0
- package/dist/core/workflow/run-state.d.ts +20 -1
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +141 -32
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +19 -0
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +13 -0
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +19 -0
- package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
- package/dist/core/workflow/spawn-opencode.js +14 -0
- package/dist/core/workflow/types.d.ts +64 -17
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/index.d.ts +0 -1
- package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/index.js +0 -1
- package/dist/core/workflow/workspaces/leases.d.ts +3 -1
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +30 -16
- package/dist/core/workflow/workspaces/local-git.d.ts +6 -2
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +328 -8
- package/dist/core/workflow/workspaces/ownership.d.ts +11 -0
- package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/ownership.js +194 -0
- package/dist/core/workflow/workspaces/reclaim.d.ts +40 -0
- package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/reclaim.js +14 -0
- package/dist/core/workflow/workspaces/recovery.d.ts +2 -0
- package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/recovery.js +42 -10
- package/dist/core/workflow/workspaces/state.d.ts +1 -0
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +21 -1
- package/dist/lib/browser/windows-chrome.d.ts +100 -12
- package/dist/lib/browser/windows-chrome.d.ts.map +1 -1
- package/dist/lib/browser/windows-chrome.js +262 -73
- package/dist/lib/docs-links.d.ts.map +1 -1
- package/dist/lib/docs-links.js +45 -2
- package/dist/lib/guarded-remove.d.ts +7 -0
- package/dist/lib/guarded-remove.d.ts.map +1 -1
- package/dist/lib/guarded-remove.js +106 -12
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +4 -0
- package/dist/lib/tunnel/state.d.ts +13 -6
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +58 -12
- package/dist/lib/zip/index.d.ts +41 -0
- package/dist/lib/zip/index.d.ts.map +1 -0
- package/dist/lib/zip/index.js +398 -0
- package/package.json +12 -1
- package/src/commander.ts +10 -0
- package/src/commands/agents.ts +54 -63
- package/src/commands/browse.ts +50 -14
- package/src/commands/diagnostics.ts +10 -0
- package/src/commands/doctor.ts +26 -7
- package/src/commands/files.ts +13 -5
- package/src/commands/governor.ts +23 -10
- package/src/commands/inbox.ts +52 -2
- package/src/commands/rm.ts +43 -4
- package/src/commands/servers.ts +27 -26
- package/src/commands/supervisor.ts +7 -2
- package/src/commands/toc.ts +14 -6
- package/src/commands/tunnel.ts +533 -166
- package/src/commands/turn-rollback.ts +111 -0
- package/src/commands/workflow.ts +89 -30
- package/src/core/agents/coord-client.ts +20 -0
- package/src/core/agents/live-authority-v3.ts +17 -0
- package/src/core/agents/live-lifecycle-v3.ts +52 -14
- package/src/core/agents/mailbox.ts +26 -17
- package/src/core/agents/render/prompt-context.ts +10 -12
- package/src/core/agents/render/session-context.ts +9 -32
- package/src/core/agents/rules/stop-hook.ts +3 -3
- package/src/core/agents/state/heartbeat-writer.ts +29 -12
- package/src/core/agents/state/live-coordination-writer.ts +29 -0
- package/src/core/agents/state/pidmap.ts +13 -0
- package/src/core/agents/state/proc-start.ts +62 -2
- package/src/core/agents/state/process-handle.ts +165 -0
- package/src/core/agents/state/stale-sweep.ts +247 -82
- package/src/core/agents/state/unchanged-file.ts +456 -0
- package/src/core/artifacts/delivery-card.ts +7 -1
- package/src/core/context/index.ts +446 -136
- package/src/core/context/observation.ts +29 -0
- package/src/core/diagnostics/bundle.ts +23 -18
- package/src/core/diagnostics/path-identity.ts +15 -0
- package/src/core/diagnostics/sanitize.ts +4 -3
- package/src/core/events/v3/authority-outbox.ts +56 -0
- package/src/core/events/v3/generation-custody.ts +59 -0
- package/src/core/events/v3/producers/coordination-recorder.ts +15 -0
- package/src/core/events/v3/producers/recorder.ts +94 -68
- package/src/core/governor/planning.ts +20 -8
- package/src/core/governor/service-read.ts +128 -20
- package/src/core/governor/service.ts +119 -42
- package/src/core/hooks/cli.ts +33 -5
- package/src/core/inbox/contract.ts +2 -1
- package/src/core/inbox/index.ts +2 -0
- package/src/core/inbox/peer-messages.ts +94 -0
- package/src/core/inbox/service.ts +88 -22
- package/src/core/inbox/targets.ts +148 -0
- package/src/core/inbox/watcher.ts +8 -9
- package/src/core/journal/index.ts +19 -2
- package/src/core/resources/contract.ts +4 -0
- package/src/core/resources/service-status.ts +35 -12
- package/src/core/resources/service.ts +57 -95
- package/src/core/resources/status.ts +57 -8
- package/src/core/semantic/service.ts +2 -8
- package/src/core/servers/index.ts +376 -141
- package/src/core/servers/tunnels.ts +57 -13
- package/src/core/supervisor/contract.ts +13 -0
- package/src/core/supervisor/explanations.ts +4 -1
- package/src/core/supervisor/findings.ts +68 -10
- package/src/core/supervisor/service.ts +87 -26
- package/src/core/supervisor/services.ts +26 -8
- package/src/core/supervisor/status.ts +89 -12
- package/src/core/supervisor/timeline.ts +2 -1
- package/src/core/turn-rollback/content.ts +499 -0
- package/src/core/turn-rollback/index.ts +580 -0
- package/src/core/work/state.ts +7 -7
- package/src/core/workflow/engine.ts +131 -49
- package/src/core/workflow/failure-evidence.ts +141 -0
- package/src/core/workflow/index.ts +12 -2
- package/src/core/workflow/live-session-v3.ts +146 -5
- package/src/core/workflow/proof.ts +134 -26
- package/src/core/workflow/recovery-audit.ts +181 -0
- package/src/core/workflow/run-state.ts +165 -34
- package/src/core/workflow/spawn-claude.ts +18 -0
- package/src/core/workflow/spawn-codex.ts +13 -0
- package/src/core/workflow/spawn-cursor.ts +18 -0
- package/src/core/workflow/spawn-opencode.ts +14 -0
- package/src/core/workflow/types.ts +51 -17
- package/src/core/workflow/workspaces/index.ts +0 -1
- package/src/core/workflow/workspaces/leases.ts +48 -17
- package/src/core/workflow/workspaces/local-git.ts +388 -7
- package/src/core/workflow/workspaces/ownership.ts +232 -0
- package/src/core/workflow/workspaces/reclaim.ts +62 -0
- package/src/core/workflow/workspaces/recovery.ts +45 -10
- package/src/core/workflow/workspaces/state.ts +20 -0
- package/src/lib/browser/windows-chrome.ts +346 -86
- package/src/lib/docs-links.ts +49 -2
- package/src/lib/guarded-remove.ts +132 -14
- package/src/lib/identities/assume.ts +4 -0
- package/src/lib/tunnel/state.ts +70 -15
- package/src/lib/zip/index.ts +483 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HarneryInboxLimits, HarneryInboxMessageRecordV1 } from "./contract.js";
|
|
2
|
+
import { HarneryInboxService } from "./service.js";
|
|
3
|
+
import { type MessageTargetInput } from "./targets.js";
|
|
4
|
+
/** Preserve the existing ping body/count bounds. Pending messages have no TTL;
|
|
5
|
+
* the lifecycle planner protects them through the idle finalization window. */
|
|
6
|
+
export declare const PEER_INBOX_LIMITS: HarneryInboxLimits;
|
|
7
|
+
export declare function peerInbox(coordRoot: string): HarneryInboxService;
|
|
8
|
+
/** CLI and web use this one path. A receipt proves a synced append, never that
|
|
9
|
+
* a process is awake or that the recipient has noticed the message. */
|
|
10
|
+
export declare function sendPeerMessage(input: {
|
|
11
|
+
coordRoot: string;
|
|
12
|
+
target: MessageTargetInput;
|
|
13
|
+
senderInstanceId: string | null;
|
|
14
|
+
senderName: string;
|
|
15
|
+
body: string;
|
|
16
|
+
}): {
|
|
17
|
+
ok: false;
|
|
18
|
+
code: "no_peer" | "ambiguous_peer" | "not_live" | "authority_unsafe";
|
|
19
|
+
message: string;
|
|
20
|
+
candidates?: string[];
|
|
21
|
+
} | {
|
|
22
|
+
state: "queued" | "written-live";
|
|
23
|
+
message_id: string;
|
|
24
|
+
body_bytes: number;
|
|
25
|
+
synced: true;
|
|
26
|
+
ok: true;
|
|
27
|
+
target: {
|
|
28
|
+
instance_id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
delivery: "written-live" | "queued";
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export declare function formatPeerInbox(coordRoot: string, messages: readonly HarneryInboxMessageRecordV1[]): string;
|
|
34
|
+
/** Wait for every earlier stdout write to finish before acknowledging context.
|
|
35
|
+
* If output fails, the caller throws and leaves the batch pending. */
|
|
36
|
+
export declare function acknowledgeEmittedPeerInbox(coordRoot: string, instanceId: string, messageIds: readonly string[]): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=peer-messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-messages.d.ts","sourceRoot":"","sources":["../../../src/core/inbox/peer-messages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,KAAK,kBAAkB,EAAwB,MAAM,cAAc,CAAC;AAI7E;+EAC+E;AAC/E,eAAO,MAAM,iBAAiB,EAAE,kBAY/B,CAAC;AAEF,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,CAEhE;AAED;uEACuE;AACvE,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;;;;;;;;;;;;;;;;EAWA;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,2BAA2B,EAAE,GAC/C,MAAM,CA4BR;AAED;sEACsE;AACtE,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,OAAO,CAAC,IAAI,CAAC,CAMf"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { resolveBinName } from "../config.js";
|
|
2
|
+
import { HarneryInboxService } from "./service.js";
|
|
3
|
+
import { resolveMessageTarget } from "./targets.js";
|
|
4
|
+
const DAY = 24 * 60 * 60_000;
|
|
5
|
+
/** Preserve the existing ping body/count bounds. Pending messages have no TTL;
|
|
6
|
+
* the lifecycle planner protects them through the idle finalization window. */
|
|
7
|
+
export const PEER_INBOX_LIMITS = {
|
|
8
|
+
max_message_body_bytes: 4_000,
|
|
9
|
+
max_pending_count: 25,
|
|
10
|
+
max_pending_bytes: 100_000,
|
|
11
|
+
max_history_bytes: 1024 * 1024,
|
|
12
|
+
max_history_records: 10_000,
|
|
13
|
+
warning_pressure_ratio: 0.8,
|
|
14
|
+
max_surface_count: 10,
|
|
15
|
+
max_surface_bytes: 16_000,
|
|
16
|
+
max_surface_tokens: 4_000,
|
|
17
|
+
surfaced_grace_ms: 7 * DAY,
|
|
18
|
+
terminal_grace_ms: 7 * DAY,
|
|
19
|
+
};
|
|
20
|
+
export function peerInbox(coordRoot) {
|
|
21
|
+
return new HarneryInboxService({ coord_root: coordRoot, limits: PEER_INBOX_LIMITS });
|
|
22
|
+
}
|
|
23
|
+
/** CLI and web use this one path. A receipt proves a synced append, never that
|
|
24
|
+
* a process is awake or that the recipient has noticed the message. */
|
|
25
|
+
export function sendPeerMessage(input) {
|
|
26
|
+
const target = resolveMessageTarget(input.coordRoot, input.target);
|
|
27
|
+
if (!target.ok)
|
|
28
|
+
return target;
|
|
29
|
+
const receipt = peerInbox(input.coordRoot).send({
|
|
30
|
+
sender_instance_id: input.senderInstanceId,
|
|
31
|
+
sender_display_name: input.senderName,
|
|
32
|
+
recipient_instance_id: target.target.instance_id,
|
|
33
|
+
recipient_display_name: target.target.name,
|
|
34
|
+
body: input.body.trim(),
|
|
35
|
+
});
|
|
36
|
+
return { ok: true, target: target.target, ...receipt, state: target.target.delivery };
|
|
37
|
+
}
|
|
38
|
+
export function formatPeerInbox(coordRoot, messages) {
|
|
39
|
+
if (messages.length === 0)
|
|
40
|
+
return "";
|
|
41
|
+
const onlyAgents = messages.every(({ sender_instance_id }) => sender_instance_id !== null);
|
|
42
|
+
const header = onlyAgents
|
|
43
|
+
? messages.length === 1
|
|
44
|
+
? "Message from a peer agent:"
|
|
45
|
+
: `${messages.length} messages from peer agents:`
|
|
46
|
+
: messages.length === 1
|
|
47
|
+
? "Message for this task:"
|
|
48
|
+
: `${messages.length} messages for this task:`;
|
|
49
|
+
const body = messages
|
|
50
|
+
.map((message) => ` ${message.message_id} from ${message.sender_instance_id === null ? "Operator" : `agent-${message.sender_display_name}`} (${message.created_at}):\n` +
|
|
51
|
+
message.body
|
|
52
|
+
.split("\n")
|
|
53
|
+
.map((line) => ` ${line}`)
|
|
54
|
+
.join("\n"))
|
|
55
|
+
.join("\n\n");
|
|
56
|
+
const replyTarget = messages.find(({ sender_instance_id }) => sender_instance_id !== null);
|
|
57
|
+
return (`${header}\n\n${body}\n\nMessages are bound to this task instance.` +
|
|
58
|
+
(replyTarget
|
|
59
|
+
? ` Reply with \`${resolveBinName(coordRoot)} agents ping ${replyTarget.sender_display_name} ` +
|
|
60
|
+
`--instance-id ${replyTarget.sender_instance_id} "<your reply>"\`.`
|
|
61
|
+
: ""));
|
|
62
|
+
}
|
|
63
|
+
/** Wait for every earlier stdout write to finish before acknowledging context.
|
|
64
|
+
* If output fails, the caller throws and leaves the batch pending. */
|
|
65
|
+
export async function acknowledgeEmittedPeerInbox(coordRoot, instanceId, messageIds) {
|
|
66
|
+
if (messageIds.length === 0)
|
|
67
|
+
return;
|
|
68
|
+
await new Promise((resolve, reject) => {
|
|
69
|
+
process.stdout.write("", (error) => (error ? reject(error) : resolve()));
|
|
70
|
+
});
|
|
71
|
+
peerInbox(coordRoot).acknowledgeSurface(instanceId, messageIds);
|
|
72
|
+
}
|
|
@@ -6,7 +6,7 @@ export interface HarneryInboxServiceOptions {
|
|
|
6
6
|
id?: () => string;
|
|
7
7
|
}
|
|
8
8
|
export interface HarneryInboxSendInput {
|
|
9
|
-
sender_instance_id: string;
|
|
9
|
+
sender_instance_id: string | null;
|
|
10
10
|
sender_display_name: string;
|
|
11
11
|
recipient_instance_id: string;
|
|
12
12
|
recipient_display_name: string;
|
|
@@ -26,6 +26,13 @@ export declare class HarneryInboxService {
|
|
|
26
26
|
pending(recipientInstanceId: string): HarneryInboxMessageRecordV1[];
|
|
27
27
|
status(recipientInstanceId: string): HarneryInboxStatusV1;
|
|
28
28
|
surface(recipientInstanceId: string, emit: (messages: readonly HarneryInboxMessageRecordV1[]) => Promise<void> | void, budget?: HarneryInboxSurfaceBudget): Promise<HarneryInboxSurfaceResult>;
|
|
29
|
+
/** Preparing prompt text is read-only. A failed or abandoned emission must
|
|
30
|
+
* leave the same messages pending for the recipient's next prompt. */
|
|
31
|
+
prepareSurface(recipientInstanceId: string, budget?: HarneryInboxSurfaceBudget): HarneryInboxMessageRecordV1[];
|
|
32
|
+
/** Call only after the selected IDs have actually been emitted. A message
|
|
33
|
+
* appended while output is in flight remains pending rather than being
|
|
34
|
+
* included in an acknowledgement of an older batch. */
|
|
35
|
+
acknowledgeSurface(recipientInstanceId: string, messageIds: readonly string[]): void;
|
|
29
36
|
}
|
|
30
37
|
export declare function inboxPath(coordRoot: string, recipientInstanceId: string): string;
|
|
31
38
|
export declare function project(records: readonly HarneryInboxRecordV1[]): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/inbox/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/inbox/service.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,IAAI,CAAC;CACd;AAED,qBAAa,mBAAmB;;gBAGlB,OAAO,EAAE,0BAA0B;IAK/C,IAAI,CAAC,KAAK,EAAE,qBAAqB,GAAG,uBAAuB;IA2C3D,OAAO,CAAC,mBAAmB,EAAE,MAAM,GAAG,oBAAoB,EAAE;IAS5D,OAAO,CAAC,mBAAmB,EAAE,MAAM,GAAG,2BAA2B,EAAE;IAInE,MAAM,CAAC,mBAAmB,EAAE,MAAM,GAAG,oBAAoB;IA0BnD,OAAO,CACX,mBAAmB,EAAE,MAAM,EAC3B,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,2BAA2B,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,EAChF,MAAM,GAAE,yBAIP,GACA,OAAO,CAAC,yBAAyB,CAAC;IAiBrC;0EACsE;IACtE,cAAc,CACZ,mBAAmB,EAAE,MAAM,EAC3B,MAAM,GAAE,yBAIP,GACA,2BAA2B,EAAE;IAKhC;;2DAEuD;IACvD,kBAAkB,CAAC,mBAAmB,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;CA2BrF;AA4BD,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAGhF;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,GAAG;IACjE,OAAO,EAAE,2BAA2B,EAAE,CAAC;IACvC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAsBA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { existsSync, statSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
|
-
import { readCrashSafeJsonlFile, updateCrashSafeJsonlFile } from "../storage/durable-history.js";
|
|
4
|
+
import { readCrashSafeJsonlFile, updateCrashSafeJsonlFile, } from "../storage/durable-history.js";
|
|
5
5
|
import { HARNERY_INBOX_RECORD_SCHEMA, HARNERY_INBOX_STATUS_SCHEMA, HarneryInboxCapacityError, } from "./contract.js";
|
|
6
6
|
export class HarneryInboxService {
|
|
7
7
|
#options;
|
|
@@ -20,7 +20,7 @@ export class HarneryInboxService {
|
|
|
20
20
|
schema: HARNERY_INBOX_RECORD_SCHEMA,
|
|
21
21
|
kind: "message",
|
|
22
22
|
message_id: `msg_${this.#options.id?.() ?? randomUUID()}`,
|
|
23
|
-
sender_instance_id:
|
|
23
|
+
sender_instance_id: senderId(input.sender_instance_id),
|
|
24
24
|
sender_display_name: boundedDisplay(input.sender_display_name),
|
|
25
25
|
recipient_instance_id: recipient,
|
|
26
26
|
recipient_display_name: boundedDisplay(input.recipient_display_name),
|
|
@@ -29,7 +29,7 @@ export class HarneryInboxService {
|
|
|
29
29
|
body_bytes: bodyBytes,
|
|
30
30
|
};
|
|
31
31
|
const path = inboxPath(this.#options.coord_root, recipient);
|
|
32
|
-
return
|
|
32
|
+
return updateInboxHistory(path, readOptions(limits), (records) => {
|
|
33
33
|
const projection = project(records);
|
|
34
34
|
capacityCheck(projection, record, path, limits);
|
|
35
35
|
return {
|
|
@@ -44,7 +44,10 @@ export class HarneryInboxService {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
records(recipientInstanceId) {
|
|
47
|
-
|
|
47
|
+
const records = readCrashSafeJsonlFile(inboxPath(this.#options.coord_root, opaqueId(recipientInstanceId, "recipient instance")), readOptions(this.#options.limits));
|
|
48
|
+
for (const record of records)
|
|
49
|
+
validateRecord(record);
|
|
50
|
+
return records;
|
|
48
51
|
}
|
|
49
52
|
pending(recipientInstanceId) {
|
|
50
53
|
return project(this.records(recipientInstanceId)).pending;
|
|
@@ -75,18 +78,42 @@ export class HarneryInboxService {
|
|
|
75
78
|
max_bytes: this.#options.limits.max_surface_bytes,
|
|
76
79
|
max_tokens: this.#options.limits.max_surface_tokens,
|
|
77
80
|
}) {
|
|
78
|
-
validateSurfaceBudget(budget);
|
|
79
81
|
const recipient = opaqueId(recipientInstanceId, "recipient instance");
|
|
80
|
-
const selected =
|
|
82
|
+
const selected = this.prepareSurface(recipient, budget);
|
|
81
83
|
await emit(selected);
|
|
82
|
-
|
|
84
|
+
this.acknowledgeSurface(recipient, selected.map(({ message_id }) => message_id));
|
|
85
|
+
const remaining = this.pending(recipient);
|
|
86
|
+
return {
|
|
87
|
+
emitted: selected,
|
|
88
|
+
remaining_pending_count: remaining.length,
|
|
89
|
+
remaining_pending_bytes: remaining.reduce((sum, record) => sum + record.body_bytes, 0),
|
|
90
|
+
repeated_after_crash_possible: true,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Preparing prompt text is read-only. A failed or abandoned emission must
|
|
94
|
+
* leave the same messages pending for the recipient's next prompt. */
|
|
95
|
+
prepareSurface(recipientInstanceId, budget = {
|
|
96
|
+
max_count: this.#options.limits.max_surface_count,
|
|
97
|
+
max_bytes: this.#options.limits.max_surface_bytes,
|
|
98
|
+
max_tokens: this.#options.limits.max_surface_tokens,
|
|
99
|
+
}) {
|
|
100
|
+
validateSurfaceBudget(budget);
|
|
101
|
+
return selectOldestFitting(this.pending(recipientInstanceId), budget);
|
|
102
|
+
}
|
|
103
|
+
/** Call only after the selected IDs have actually been emitted. A message
|
|
104
|
+
* appended while output is in flight remains pending rather than being
|
|
105
|
+
* included in an acknowledgement of an older batch. */
|
|
106
|
+
acknowledgeSurface(recipientInstanceId, messageIds) {
|
|
107
|
+
const recipient = opaqueId(recipientInstanceId, "recipient instance");
|
|
108
|
+
const selected = new Set(messageIds);
|
|
109
|
+
if (selected.size > 0) {
|
|
83
110
|
const surfacedAt = now(this.#options).toISOString();
|
|
84
|
-
|
|
111
|
+
updateInboxHistory(inboxPath(this.#options.coord_root, recipient), readOptions(this.#options.limits), (records) => {
|
|
85
112
|
const stillPending = new Set(project(records).pending.map(({ message_id }) => message_id));
|
|
86
113
|
return {
|
|
87
|
-
append: selected
|
|
88
|
-
.filter((
|
|
89
|
-
.map((
|
|
114
|
+
append: [...selected]
|
|
115
|
+
.filter((message_id) => stillPending.has(message_id))
|
|
116
|
+
.map((message_id) => ({
|
|
90
117
|
schema: HARNERY_INBOX_RECORD_SCHEMA,
|
|
91
118
|
kind: "surfaced",
|
|
92
119
|
message_id,
|
|
@@ -96,13 +123,26 @@ export class HarneryInboxService {
|
|
|
96
123
|
};
|
|
97
124
|
});
|
|
98
125
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** The shared writer refuses an occupied lease before invoking the update.
|
|
129
|
+
* Briefly retry only that exact refusal so concurrent peer senders both get
|
|
130
|
+
* a chance to append. All validation, authority and I/O failures still fail
|
|
131
|
+
* immediately, and an occupied live lease is never removed or overridden. */
|
|
132
|
+
function updateInboxHistory(path, options, update) {
|
|
133
|
+
const deadline = performance.now() + 2_000;
|
|
134
|
+
const pause = new Int32Array(new SharedArrayBuffer(4));
|
|
135
|
+
while (true) {
|
|
136
|
+
try {
|
|
137
|
+
return updateCrashSafeJsonlFile(path, options, update);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
if (!(error instanceof Error) ||
|
|
141
|
+
error.message !== `durable history lease busy: ${path}.lease` ||
|
|
142
|
+
performance.now() >= deadline)
|
|
143
|
+
throw error;
|
|
144
|
+
Atomics.wait(pause, 0, 0, Math.min(10, deadline - performance.now()));
|
|
145
|
+
}
|
|
106
146
|
}
|
|
107
147
|
}
|
|
108
148
|
export function inboxPath(coordRoot, recipientInstanceId) {
|
|
@@ -174,10 +214,13 @@ function now(options) {
|
|
|
174
214
|
return options.now?.() ?? new Date();
|
|
175
215
|
}
|
|
176
216
|
function opaqueId(value, field) {
|
|
177
|
-
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value))
|
|
217
|
+
if (typeof value !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value))
|
|
178
218
|
throw new Error(`invalid ${field} id`);
|
|
179
219
|
return value;
|
|
180
220
|
}
|
|
221
|
+
function senderId(value) {
|
|
222
|
+
return value === null ? null : opaqueId(value, "sender instance");
|
|
223
|
+
}
|
|
181
224
|
function boundedDisplay(value) {
|
|
182
225
|
const result = value.trim();
|
|
183
226
|
if (result.length === 0 || Buffer.byteLength(result) > 256)
|
|
@@ -187,8 +230,11 @@ function boundedDisplay(value) {
|
|
|
187
230
|
function validateRecord(record) {
|
|
188
231
|
if (record.schema !== HARNERY_INBOX_RECORD_SCHEMA)
|
|
189
232
|
throw new Error("unknown inbox record schema");
|
|
190
|
-
if (record.kind === "message"
|
|
191
|
-
|
|
233
|
+
if (record.kind === "message") {
|
|
234
|
+
senderId(record.sender_instance_id);
|
|
235
|
+
if (Buffer.byteLength(record.body) !== record.body_bytes) {
|
|
236
|
+
throw new Error(`inbox message ${record.message_id} has invalid body_bytes`);
|
|
237
|
+
}
|
|
192
238
|
}
|
|
193
239
|
}
|
|
194
240
|
function validateLimits(limits) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface MessageTargetInput {
|
|
2
|
+
name?: string;
|
|
3
|
+
instanceId?: string;
|
|
4
|
+
requireLive?: boolean;
|
|
5
|
+
now?: Date;
|
|
6
|
+
}
|
|
7
|
+
export type MessageTargetResult = {
|
|
8
|
+
ok: true;
|
|
9
|
+
target: {
|
|
10
|
+
instance_id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
delivery: "written-live" | "queued";
|
|
13
|
+
};
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
code: "no_peer" | "ambiguous_peer" | "not_live" | "authority_unsafe";
|
|
17
|
+
message: string;
|
|
18
|
+
candidates?: string[];
|
|
19
|
+
};
|
|
20
|
+
/** Resolve one immutable recipient without extending presence or claiming attention. */
|
|
21
|
+
export declare function resolveMessageTarget(coordRoot: string, input: MessageTargetInput): MessageTargetResult;
|
|
22
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../../src/core/inbox/targets.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,MAAM,mBAAmB,GAC3B;IACE,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,CAAA;KAAE,CAAC;CACpF,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,SAAS,GAAG,gBAAgB,GAAG,UAAU,GAAG,kBAAkB,CAAC;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEN,wFAAwF;AACxF,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,kBAAkB,GACxB,mBAAmB,CAwFrB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { resolveName } from "../agents/state/names.js";
|
|
2
|
+
import { coordFreshnessSeconds } from "../config.js";
|
|
3
|
+
import { readCoordinationViewV3, requireAuthoritySafeCoordinationViewV3, } from "../events/v3/coordination-view.js";
|
|
4
|
+
import { liveInstanceIdV3, nativeInstanceIdV3, observeLiveEventLedgerRouteV3, } from "../events/v3/live-route-observer.js";
|
|
5
|
+
/** Resolve one immutable recipient without extending presence or claiming attention. */
|
|
6
|
+
export function resolveMessageTarget(coordRoot, input) {
|
|
7
|
+
const requestedName = normalizeName(input.name);
|
|
8
|
+
const requestedInstance = input.instanceId?.trim();
|
|
9
|
+
if (!requestedName && !requestedInstance) {
|
|
10
|
+
return { ok: false, code: "no_peer", message: "Supply an exact agent name or instance id." };
|
|
11
|
+
}
|
|
12
|
+
const now = input.now?.getTime() ?? Date.now();
|
|
13
|
+
if (!Number.isFinite(now))
|
|
14
|
+
return unsafe("The message addressing clock is invalid.");
|
|
15
|
+
let view;
|
|
16
|
+
try {
|
|
17
|
+
if (observeLiveEventLedgerRouteV3(coordRoot).state === "blocked") {
|
|
18
|
+
return unsafe("The event ledger cannot establish message recipient authority.");
|
|
19
|
+
}
|
|
20
|
+
view = requireAuthoritySafeCoordinationViewV3(readCoordinationViewV3(coordRoot));
|
|
21
|
+
if (!view.source_complete)
|
|
22
|
+
return unsafe("The event ledger read is incomplete.");
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return unsafe("The event ledger cannot establish message recipient authority.");
|
|
26
|
+
}
|
|
27
|
+
// Address historical instances without reopening them. A current generation
|
|
28
|
+
// wins over its own terminal history; otherwise use its last ledger position.
|
|
29
|
+
const byInstance = new Map();
|
|
30
|
+
for (const generation of Object.values(view.terminal_generations)) {
|
|
31
|
+
const prior = byInstance.get(generation.instance_id);
|
|
32
|
+
if (!prior || laterPosition(generation, prior))
|
|
33
|
+
byInstance.set(generation.instance_id, generation);
|
|
34
|
+
}
|
|
35
|
+
for (const generation of Object.values(view.instances))
|
|
36
|
+
byInstance.set(generation.instance_id, generation);
|
|
37
|
+
const freshnessMs = coordFreshnessSeconds(coordRoot) * 1_000;
|
|
38
|
+
const candidates = [...byInstance.values()].flatMap((generation) => {
|
|
39
|
+
const instanceId = nativeInstanceIdV3(generation.instance_id);
|
|
40
|
+
const name = resolveName(coordRoot, instanceId)?.name;
|
|
41
|
+
if (!name)
|
|
42
|
+
return [];
|
|
43
|
+
if (requestedInstance && liveInstanceIdV3(requestedInstance) !== generation.instance_id)
|
|
44
|
+
return [];
|
|
45
|
+
if (requestedName && normalizeName(name) !== requestedName)
|
|
46
|
+
return [];
|
|
47
|
+
const age = now - Date.parse(generation.last_observed_at);
|
|
48
|
+
const diagnostics = view.diagnostics_by_generation[generation.generation_id] ?? [];
|
|
49
|
+
return [
|
|
50
|
+
{
|
|
51
|
+
instanceId,
|
|
52
|
+
name,
|
|
53
|
+
safe: !diagnostics.some((diagnostic) => diagnostic.authority_blocking),
|
|
54
|
+
fresh: generation.phase === "live" && Number.isFinite(age) && age >= 0 && age <= freshnessMs,
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
});
|
|
58
|
+
if (candidates.length === 0) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
code: "no_peer",
|
|
62
|
+
message: "No known agent matches that exact name and instance.",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (candidates.some((candidate) => !candidate.safe)) {
|
|
66
|
+
return unsafe("A matching agent generation does not have safe coordination authority.");
|
|
67
|
+
}
|
|
68
|
+
const fresh = candidates.filter((candidate) => candidate.fresh);
|
|
69
|
+
const selected = requestedInstance ? candidates : fresh.length > 0 ? fresh : candidates;
|
|
70
|
+
if (selected.length !== 1) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
code: "ambiguous_peer",
|
|
74
|
+
message: "Several agent instances hold that exact name; specify --instance-id.",
|
|
75
|
+
candidates: selected.map(({ instanceId }) => instanceId).sort(),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const target = selected[0];
|
|
79
|
+
if (input.requireLive && !target.fresh) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
code: "not_live",
|
|
83
|
+
message: "That agent is known but outside live presence; omit --require-live to queue its message.",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
target: {
|
|
89
|
+
instance_id: target.instanceId,
|
|
90
|
+
name: target.name,
|
|
91
|
+
delivery: target.fresh ? "written-live" : "queued",
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function laterPosition(left, right) {
|
|
96
|
+
return (left.source_position.segment_ordinal > right.source_position.segment_ordinal ||
|
|
97
|
+
(left.source_position.segment_ordinal === right.source_position.segment_ordinal &&
|
|
98
|
+
left.source_position.byte_offset > right.source_position.byte_offset));
|
|
99
|
+
}
|
|
100
|
+
function normalizeName(name) {
|
|
101
|
+
return (name ?? "")
|
|
102
|
+
.trim()
|
|
103
|
+
.replace(/^agent-/i, "")
|
|
104
|
+
.toLowerCase();
|
|
105
|
+
}
|
|
106
|
+
function unsafe(message) {
|
|
107
|
+
return { ok: false, code: "authority_unsafe", message };
|
|
108
|
+
}
|
|
@@ -17,10 +17,14 @@ export async function* watchInbox(service, recipientInstanceId, options) {
|
|
|
17
17
|
}
|
|
18
18
|
function delay(ms, signal) {
|
|
19
19
|
return new Promise((resolve) => {
|
|
20
|
-
const
|
|
21
|
-
signal.addEventListener("abort", () => {
|
|
20
|
+
const finish = () => {
|
|
22
21
|
clearTimeout(timer);
|
|
22
|
+
signal.removeEventListener("abort", finish);
|
|
23
23
|
resolve();
|
|
24
|
-
}
|
|
24
|
+
};
|
|
25
|
+
const timer = setTimeout(finish, ms);
|
|
26
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
27
|
+
if (signal.aborted)
|
|
28
|
+
finish();
|
|
25
29
|
});
|
|
26
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/journal/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/journal/index.ts"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,kBAAkB,iFAQrB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAC3C,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,6DAA6D;AAC7D,eAAO,MAAM,eAAe,QACyF,CAAC;AAEtH,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,UAAU,IAAI,MAAM,CAMnC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAInC;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGtD;AAeD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,CAAC,GAAE,IAAiB,GAAG,MAAM,CAW1D;AAID,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAwEtE;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAkBxD;AAmBD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,SAAoB,GAAG,SAAS,EAAE,CA2DrF;AAID,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,MAAM,GACX,UAAU,CAiEZ;AAID,wGAAwG;AACxG,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhE;AAED,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,IAAI,SAAyB,GAAG,MAAM,CAkBnE;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAuB9C;AAED,qDAAqD;AACrD,wBAAgB,YAAY,IAAI;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,EAAE,CAWF;AAID,wBAAgB,mBAAmB,IAAI,MAAM,CAM5C;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAIjE;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ9D"}
|
|
@@ -3,6 +3,8 @@ import { dirname, resolve } from "node:path";
|
|
|
3
3
|
import { resolveMachineLabel } from "../../lib/machine.js";
|
|
4
4
|
import { assertSafeInstanceId, monorepoRoot, resolveContainedFile, resolveOwner, } from "../agents/index.js";
|
|
5
5
|
import { readLiveCoordinationRow, readLiveCoordinationRows, } from "../agents/state/live-coordination-view.js";
|
|
6
|
+
import { readCoordinationViewV3, requireAuthoritySafeCoordinationViewV3, } from "../events/v3/coordination-view.js";
|
|
7
|
+
import { liveInstanceIdV3, observeLiveEventLedgerRouteV3, } from "../events/v3/live-route-observer.js";
|
|
6
8
|
/**
|
|
7
9
|
* Agent journal: per-agent markdown journal at `.harnery/journal/<instance_id>.md`.
|
|
8
10
|
*
|
|
@@ -340,12 +342,25 @@ export function sweepOrphanJournals() {
|
|
|
340
342
|
const dir = journalDir();
|
|
341
343
|
const root = monorepoRoot();
|
|
342
344
|
const archived = [];
|
|
345
|
+
if (!root)
|
|
346
|
+
return archived;
|
|
347
|
+
let view;
|
|
348
|
+
try {
|
|
349
|
+
if (observeLiveEventLedgerRouteV3(root).state === "blocked")
|
|
350
|
+
return archived;
|
|
351
|
+
view = requireAuthoritySafeCoordinationViewV3(readCoordinationViewV3(root));
|
|
352
|
+
if (!view.source_complete)
|
|
353
|
+
return archived;
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
// A missing or unsafe read does not prove that an owner has ended.
|
|
357
|
+
return archived;
|
|
358
|
+
}
|
|
343
359
|
for (const f of readdirSync(dir)) {
|
|
344
360
|
if (!f.endsWith(".md"))
|
|
345
361
|
continue;
|
|
346
362
|
const instanceId = f.replace(/\.md$/, "");
|
|
347
|
-
|
|
348
|
-
if (!hb) {
|
|
363
|
+
if (!view.instances[liveInstanceIdV3(instanceId)]) {
|
|
349
364
|
const dest = archiveJournal(instanceId);
|
|
350
365
|
if (dest)
|
|
351
366
|
archived.push(dest);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProcessGenerationVerdict } from "../agents/state/proc-start.js";
|
|
1
2
|
export declare const RESOURCE_SNAPSHOT_SCHEMA_VERSION = 2;
|
|
2
3
|
export declare const RESOURCE_SERVICE_STATUS_SCHEMA_VERSION = 1;
|
|
3
4
|
export type ResourceSupportState = "supported" | "partial" | "unsupported" | "error";
|
|
@@ -140,6 +141,8 @@ export interface ResourceServiceStatusRecord {
|
|
|
140
141
|
export interface ResourceServiceStatus {
|
|
141
142
|
running: boolean;
|
|
142
143
|
stale: boolean;
|
|
144
|
+
generation: ProcessGenerationVerdict;
|
|
145
|
+
liveness: "running" | "stopped" | "unknown";
|
|
143
146
|
record?: ResourceServiceStatusRecord;
|
|
144
147
|
status_path: string;
|
|
145
148
|
snapshot_path: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/core/resources/contract.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/core/resources/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
import { type ProcessGenerationVerdict } from "../agents/state/proc-start.js";
|
|
1
2
|
import { type ResourceServiceStatus } from "./contract.js";
|
|
2
|
-
export
|
|
3
|
+
export interface ResourceProcessDependencies {
|
|
4
|
+
readToken?: (pid: number) => string | null;
|
|
5
|
+
probePid?: (pid: number) => unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare function readResourceServiceStatus(coordRoot: string, nowMs?: number, dependencies?: ResourceProcessDependencies): ResourceServiceStatus;
|
|
8
|
+
export declare function resourceProcessLiveness(owner: {
|
|
9
|
+
pid: number;
|
|
10
|
+
host: string;
|
|
11
|
+
start_token?: string;
|
|
12
|
+
}, dependencies?: ResourceProcessDependencies): {
|
|
13
|
+
generation: ProcessGenerationVerdict;
|
|
14
|
+
liveness: ResourceServiceStatus["liveness"];
|
|
15
|
+
};
|
|
3
16
|
//# sourceMappingURL=service-status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-status.d.ts","sourceRoot":"","sources":["../../../src/core/resources/service-status.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,eAAe,CAAC;AAKvB,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,SAAa,
|
|
1
|
+
{"version":3,"file":"service-status.d.ts","sourceRoot":"","sources":["../../../src/core/resources/service-status.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,eAAe,CAAC;AAKvB,MAAM,WAAW,2BAA2B;IAC1C,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACrC;AAED,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,SAAa,EAClB,YAAY,GAAE,2BAAgC,GAC7C,qBAAqB,CA2BvB;AAcD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAC1D,YAAY,GAAE,2BAAgC,GAC7C;IAAE,UAAU,EAAE,wBAAwB,CAAC;IAAC,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAA;CAAE,CAgBvF"}
|
|
@@ -1,29 +1,31 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import { hostname } from "node:os";
|
|
2
|
-
import {
|
|
3
|
+
import { verifyProcessGeneration, } from "../agents/state/proc-start.js";
|
|
3
4
|
import { RESOURCE_SERVICE_STATUS_SCHEMA_VERSION, } from "./contract.js";
|
|
4
5
|
import { readResourceServiceRecord, resourcePaths } from "./storage.js";
|
|
5
6
|
const STALE_HEARTBEAT_MS = 15_000;
|
|
6
|
-
export function readResourceServiceStatus(coordRoot, nowMs = Date.now()) {
|
|
7
|
+
export function readResourceServiceStatus(coordRoot, nowMs = Date.now(), dependencies = {}) {
|
|
7
8
|
const paths = resourcePaths(coordRoot);
|
|
8
9
|
const record = readResourceServiceRecord(coordRoot);
|
|
9
10
|
if (!validRecord(record)) {
|
|
10
11
|
return {
|
|
11
12
|
running: false,
|
|
12
13
|
stale: false,
|
|
14
|
+
generation: "unknown",
|
|
15
|
+
liveness: existsSync(paths.service) ? "unknown" : "stopped",
|
|
13
16
|
status_path: paths.service,
|
|
14
17
|
snapshot_path: paths.snapshot,
|
|
15
18
|
};
|
|
16
19
|
}
|
|
17
20
|
const heartbeatAt = Date.parse(record.heartbeat_at);
|
|
18
21
|
const stale = !Number.isFinite(heartbeatAt) || nowMs - heartbeatAt > STALE_HEARTBEAT_MS;
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
!stale &&
|
|
22
|
-
(record.state === "starting" || record.state === "running" || record.state === "stopping") &&
|
|
23
|
-
pidStillMatches(record.pid, record.start_token);
|
|
22
|
+
const owner = resourceProcessLiveness(record, dependencies);
|
|
23
|
+
const liveness = owner.generation === "same" && record.state === "stopped" ? "stopped" : owner.liveness;
|
|
24
24
|
return {
|
|
25
|
-
running,
|
|
25
|
+
running: liveness === "running" && !stale,
|
|
26
26
|
stale,
|
|
27
|
+
generation: owner.generation,
|
|
28
|
+
liveness,
|
|
27
29
|
record,
|
|
28
30
|
status_path: paths.service,
|
|
29
31
|
snapshot_path: paths.snapshot,
|
|
@@ -36,13 +38,21 @@ function validRecord(value) {
|
|
|
36
38
|
typeof value.host === "string" &&
|
|
37
39
|
typeof value.heartbeat_at === "string");
|
|
38
40
|
}
|
|
39
|
-
function
|
|
41
|
+
export function resourceProcessLiveness(owner, dependencies = {}) {
|
|
42
|
+
if (owner.host !== hostname())
|
|
43
|
+
return { generation: "unknown", liveness: "unknown" };
|
|
40
44
|
try {
|
|
41
|
-
process.kill(pid, 0);
|
|
45
|
+
(dependencies.probePid ?? ((pid) => process.kill(pid, 0)))(owner.pid);
|
|
42
46
|
}
|
|
43
47
|
catch (error) {
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
return {
|
|
49
|
+
generation: "unknown",
|
|
50
|
+
liveness: error.code === "ESRCH" ? "stopped" : "unknown",
|
|
51
|
+
};
|
|
46
52
|
}
|
|
47
|
-
|
|
53
|
+
const generation = verifyProcessGeneration(owner.pid, owner.start_token, dependencies.readToken);
|
|
54
|
+
return {
|
|
55
|
+
generation,
|
|
56
|
+
liveness: generation === "same" ? "running" : generation === "different" ? "stopped" : "unknown",
|
|
57
|
+
};
|
|
48
58
|
}
|