harnery 0.43.0 → 0.44.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/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/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 +16 -1
- 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/workflow.js +24 -30
- 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 -0
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +41 -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/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 +9 -1
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +47 -27
- 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/servers/index.d.ts +24 -13
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +132 -92
- package/dist/core/servers/tunnels.d.ts +3 -5
- package/dist/core/servers/tunnels.d.ts.map +1 -1
- package/dist/core/servers/tunnels.js +3 -9
- 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 +9 -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/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 +1 -1
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +1 -1
- 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/run-state.d.ts +3 -1
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +31 -27
- 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 +270 -6
- 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 +35 -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.map +1 -1
- package/dist/core/workflow/workspaces/recovery.js +21 -13
- 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/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 +7 -1
- 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/governor.ts +23 -10
- package/src/commands/inbox.ts +52 -2
- package/src/commands/rm.ts +43 -4
- package/src/commands/servers.ts +16 -4
- package/src/commands/supervisor.ts +7 -2
- package/src/commands/toc.ts +14 -6
- package/src/commands/workflow.ts +30 -30
- 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 +57 -0
- package/src/core/agents/state/stale-sweep.ts +247 -82
- package/src/core/agents/state/unchanged-file.ts +456 -0
- 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 +71 -24
- package/src/core/resources/status.ts +57 -8
- package/src/core/servers/index.ts +177 -91
- package/src/core/servers/tunnels.ts +3 -11
- 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 +88 -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/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 +0 -1
- package/src/core/workflow/live-session-v3.ts +146 -5
- package/src/core/workflow/proof.ts +134 -26
- package/src/core/workflow/run-state.ts +31 -29
- 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 +315 -5
- package/src/core/workflow/workspaces/ownership.ts +232 -0
- package/src/core/workflow/workspaces/reclaim.ts +58 -0
- package/src/core/workflow/workspaces/recovery.ts +25 -13
- 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/zip/index.ts +483 -0
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* string.
|
|
8
8
|
*/
|
|
9
9
|
import { statSync } from "node:fs";
|
|
10
|
-
import { type MailboxMessageV1 } from "../mailbox.js";
|
|
11
10
|
export interface RenderOpts {
|
|
12
11
|
coordRoot: string;
|
|
13
12
|
instanceId: string;
|
|
@@ -16,19 +15,14 @@ export interface RenderOpts {
|
|
|
16
15
|
/** Adapter label rendered in parens after the self-name (e.g. "Cursor", "Codex").
|
|
17
16
|
* Claude Code omits it. */
|
|
18
17
|
platformLabel?: string;
|
|
18
|
+
/** The emitter acknowledges exactly these IDs only after output succeeds. */
|
|
19
|
+
onInboxPrepared?: (messageIds: readonly string[]) => void;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* Build the combined SessionStart systemMessage. Returns the additionalContext
|
|
22
23
|
* string (or "" if there's nothing to say).
|
|
23
24
|
*/
|
|
24
25
|
export declare function renderSessionContext(opts: RenderOpts): string;
|
|
25
|
-
/**
|
|
26
|
-
* Write delivered peer messages into the recipient's own journal, so they
|
|
27
|
-
* survive context compaction the way any other coordination breadcrumb does.
|
|
28
|
-
* A message the sender already journaled (the recipient was live when it was
|
|
29
|
-
* sent) is skipped to avoid a duplicate entry.
|
|
30
|
-
*/
|
|
31
|
-
export declare function recordDeliveredMessages(instanceId: string, messages: readonly MailboxMessageV1[]): void;
|
|
32
26
|
/**
|
|
33
27
|
* Returns a list of commit-guard wiring issues (empty when wired). Portable
|
|
34
28
|
* across host projects: it asserts the FUNCTIONAL property ("does this repo's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/session-context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAyC,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"session-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/session-context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAyC,QAAQ,EAAE,MAAM,SAAS,CAAC;AAyB1E,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;+BAC2B;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CAC3D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CA8F7D;AA6LD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBvD;AA0DD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAiDlF;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,iBAAW,CAAC"}
|
|
@@ -11,9 +11,8 @@ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { resolveBinName, resolveHooksSetupHint } from "../../config.js";
|
|
13
13
|
import { harneryVersion, loadAdapterWiring } from "../../hooks/adapter/wiring.js";
|
|
14
|
-
import {
|
|
14
|
+
import { formatPeerInbox, peerInbox } from "../../inbox/peer-messages.js";
|
|
15
15
|
import { readRemoteMachines } from "../../presence/index.js";
|
|
16
|
-
import { drainMailbox, formatMailboxDelivery } from "../mailbox.js";
|
|
17
16
|
import { readLiveCoordinationRows } from "../state/live-coordination-view.js";
|
|
18
17
|
import { forkRelationLabels, readForkState } from "../state/names.js";
|
|
19
18
|
/**
|
|
@@ -56,15 +55,12 @@ export function renderSessionContext(opts) {
|
|
|
56
55
|
if (isLinkedWorktree(coordRoot)) {
|
|
57
56
|
messages.push(`Running inside worktree ${process.cwd()}. The coord layer is scoped to this worktree only; use \`${resolveBinName(coordRoot)} worktree diff\` to check for conflicts against sibling worktrees.`);
|
|
58
57
|
}
|
|
59
|
-
// 3.
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
recordDeliveredMessages(instanceId, delivered);
|
|
66
|
-
messages.push(formatMailboxDelivery(coordRoot, delivered));
|
|
67
|
-
}
|
|
58
|
+
// 3. Rendering never consumes a message. The native emitter acknowledges the
|
|
59
|
+
// prepared instance-bound batch only after it has flushed the output.
|
|
60
|
+
const delivered = peerInbox(coordRoot).prepareSurface(instanceId);
|
|
61
|
+
if (delivered.length > 0) {
|
|
62
|
+
opts.onInboxPrepared?.(delivered.map(({ message_id }) => message_id));
|
|
63
|
+
messages.push(formatPeerInbox(coordRoot, delivered));
|
|
68
64
|
}
|
|
69
65
|
// 4. Council invites
|
|
70
66
|
if (agentName) {
|
|
@@ -107,25 +103,6 @@ export function renderSessionContext(opts) {
|
|
|
107
103
|
}
|
|
108
104
|
return messages.join("\n\n");
|
|
109
105
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Write delivered peer messages into the recipient's own journal, so they
|
|
112
|
-
* survive context compaction the way any other coordination breadcrumb does.
|
|
113
|
-
* A message the sender already journaled (the recipient was live when it was
|
|
114
|
-
* sent) is skipped to avoid a duplicate entry.
|
|
115
|
-
*/
|
|
116
|
-
export function recordDeliveredMessages(instanceId, messages) {
|
|
117
|
-
for (const m of messages) {
|
|
118
|
-
if (m.journaled)
|
|
119
|
-
continue;
|
|
120
|
-
try {
|
|
121
|
-
appendEntry(instanceId, "handoff", `from agent-${m.from_name}: ${m.body}`);
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
// A journal write failure must never cost the delivery itself; the
|
|
125
|
-
// message is already in the rendered context the model reads.
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
106
|
/** One-line-per-agent view of sessions on other machines (presence refs). */
|
|
130
107
|
function formatRemoteMachines(coordRoot) {
|
|
131
108
|
try {
|
|
@@ -331,9 +331,9 @@ function sessionNameBlock(coordRoot, instanceId) {
|
|
|
331
331
|
catch {
|
|
332
332
|
// The ledger evidence still authorizes the block; the cache is UX only.
|
|
333
333
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
334
|
+
// The first post-mint reply was already rejected. Repeating its title later
|
|
335
|
+
// cannot change that evidence; the JSON retry result opens a new window.
|
|
336
|
+
const instruction = `Run \`${resolveBinName(coordRoot)} agents suggest-name --json\` as your only tool call to create a fresh verification boundary, then display its suggested_session_name verbatim by itself in a fenced code block${name ? `: ${name}` : "."}`;
|
|
337
337
|
return {
|
|
338
338
|
allow: false,
|
|
339
339
|
exit_code: 2,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/heartbeat-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"heartbeat-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/heartbeat-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
17
17
|
import { dirname, join } from "node:path";
|
|
18
|
+
import { assertCurrentGenerationV3, withGenerationCustodyV3, } from "../../events/v3/generation-custody.js";
|
|
19
|
+
import { liveInstanceIdV3 } from "../../events/v3/live-routing.js";
|
|
18
20
|
import { canonicalClaimPath } from "../claim-path.js";
|
|
19
21
|
import { heartbeatPath, readHeartbeat } from "./heartbeat-reader.js";
|
|
20
22
|
export { readHeartbeat } from "./heartbeat-reader.js";
|
|
@@ -38,13 +40,16 @@ export function setLifecycleCache(coordRoot, instanceId, state, reason, suggeste
|
|
|
38
40
|
}));
|
|
39
41
|
}
|
|
40
42
|
function mutate(coordRoot, instanceId, fn) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
return withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(instanceId)], () => {
|
|
44
|
+
const hb = readHeartbeat(coordRoot, instanceId);
|
|
45
|
+
if (!hb)
|
|
46
|
+
return null;
|
|
47
|
+
const next = fn(hb);
|
|
48
|
+
next.last_heartbeat = nowIsoSeconds();
|
|
49
|
+
assertCurrentGenerationV3(coordRoot, liveInstanceIdV3(instanceId), hb.v3_generation_id);
|
|
50
|
+
atomicWrite(heartbeatPath(coordRoot, instanceId), JSON.stringify(next, null, 2));
|
|
51
|
+
return next;
|
|
52
|
+
});
|
|
48
53
|
}
|
|
49
54
|
export function setTask(coordRoot, instanceId, task) {
|
|
50
55
|
return mutate(coordRoot, instanceId, (hb) => {
|
|
@@ -68,13 +73,16 @@ export function setTask(coordRoot, instanceId, task) {
|
|
|
68
73
|
}
|
|
69
74
|
/** Update the disposable identity cache after a canonical V3 attestation. */
|
|
70
75
|
export function setIdentityCache(coordRoot, instanceId, name, agentId) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
return withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(instanceId)], () => {
|
|
77
|
+
const heartbeat = readHeartbeat(coordRoot, instanceId);
|
|
78
|
+
if (!heartbeat)
|
|
79
|
+
return null;
|
|
80
|
+
heartbeat.name = name;
|
|
81
|
+
heartbeat.agent_id = agentId;
|
|
82
|
+
assertCurrentGenerationV3(coordRoot, liveInstanceIdV3(instanceId), heartbeat.v3_generation_id);
|
|
83
|
+
atomicWrite(heartbeatPath(coordRoot, instanceId), JSON.stringify(heartbeat, null, 2));
|
|
84
|
+
return heartbeat;
|
|
85
|
+
});
|
|
78
86
|
}
|
|
79
87
|
/** Restore the pool-assigned display name on a generation that was
|
|
80
88
|
* materialized before the adapter's normal SessionStart naming path ran.
|
|
@@ -248,6 +256,9 @@ export function clearCoordinationCache(coordRoot, instanceId) {
|
|
|
248
256
|
}
|
|
249
257
|
}
|
|
250
258
|
export function healPidmap(coordRoot, instanceId, pid) {
|
|
259
|
+
withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(instanceId)], () => healPidmapUnderCustody(coordRoot, instanceId, pid));
|
|
260
|
+
}
|
|
261
|
+
function healPidmapUnderCustody(coordRoot, instanceId, pid) {
|
|
251
262
|
const dir = join(coordRoot, ".harnery", "pid-map");
|
|
252
263
|
mkdirSync(dir, { recursive: true });
|
|
253
264
|
const hb = readHeartbeat(coordRoot, instanceId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-coordination-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/live-coordination-writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"live-coordination-writer.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/live-coordination-writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAUhD,OAAO,EAAE,KAAK,SAAS,EAAiB,MAAM,uBAAuB,CAAC;AAUtE;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,OAAO,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,SAAS,GAAG,IAAI,CASlB;AAED,wFAAwF;AACxF,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,OAAO,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,SAAS,GAAG,IAAI,CASlB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { readCoordinationViewV3, requireAuthoritySafeCoordinationViewV3, } from "../../events/v3/coordination-view.js";
|
|
4
|
+
import { assertCurrentGenerationV3, withGenerationCustodyV3, } from "../../events/v3/generation-custody.js";
|
|
4
5
|
import { liveInstanceIdV3, resolveLiveEventLedgerRouteV3 } from "../../events/v3/live-routing.js";
|
|
5
6
|
import { readHeartbeat } from "./heartbeat-reader.js";
|
|
6
7
|
import { isAdapterV3, isCurrentV3HeartbeatCache, observedAdapterV3, projectHeartbeatV3, } from "./live-coordination-view.js";
|
|
@@ -19,6 +20,9 @@ export function repairLiveCoordinationHeartbeat(coordRoot, nativeInstanceId, nat
|
|
|
19
20
|
return materializeLiveCoordinationHeartbeat(coordRoot, nativeInstanceId, nativeSessionId, adapter, model, true);
|
|
20
21
|
}
|
|
21
22
|
function materializeLiveCoordinationHeartbeat(coordRoot, nativeInstanceId, nativeSessionId, _adapter, model, force) {
|
|
23
|
+
return withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(nativeInstanceId)], () => materializeHeartbeatUnderCustody(coordRoot, nativeInstanceId, nativeSessionId, _adapter, model, force));
|
|
24
|
+
}
|
|
25
|
+
function materializeHeartbeatUnderCustody(coordRoot, nativeInstanceId, nativeSessionId, _adapter, model, force) {
|
|
22
26
|
const route = resolveLiveEventLedgerRouteV3(coordRoot);
|
|
23
27
|
if (route.state === "blocked")
|
|
24
28
|
throw new Error(`event_v3_coordination_view:${route.reason}`);
|
|
@@ -85,6 +89,7 @@ function materializeLiveCoordinationHeartbeat(coordRoot, nativeInstanceId, nativ
|
|
|
85
89
|
v3_projection_event_id: generation.last_event_id,
|
|
86
90
|
v3_task_state: generation.task_state === "set" ? "set" : "cleared",
|
|
87
91
|
};
|
|
92
|
+
assertCurrentGenerationV3(coordRoot, liveInstanceIdV3(nativeInstanceId), generation.generation_id);
|
|
88
93
|
writeHeartbeatCache(coordRoot, nativeInstanceId, materialized);
|
|
89
94
|
return materialized;
|
|
90
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pidmap.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/pidmap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"pidmap.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/pidmap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA2BH,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAGA;AAwCD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA8B7D;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,IAAI,CAIN;AAsCD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAmBjF;AAED,yFAAyF;AACzF,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAoBzF"}
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
17
17
|
import { dirname, join } from "node:path";
|
|
18
|
+
import { withGenerationCustodyV3 } from "../../events/v3/generation-custody.js";
|
|
19
|
+
import { liveInstanceIdV3 } from "../../events/v3/live-routing.js";
|
|
18
20
|
import { checkPidToken, processStartToken } from "./proc-start.js";
|
|
19
21
|
/**
|
|
20
22
|
* Row count that triggers a dead-row sweep on the next write.
|
|
@@ -110,6 +112,9 @@ export function prunePidmapDeadRows(coordRoot) {
|
|
|
110
112
|
return removed;
|
|
111
113
|
}
|
|
112
114
|
export function writePidmapRow(coordRoot, pid, instanceId, platform) {
|
|
115
|
+
withGenerationCustodyV3(coordRoot, [liveInstanceIdV3(instanceId)], () => writePidmapRowUnderCustody(coordRoot, pid, instanceId, platform));
|
|
116
|
+
}
|
|
117
|
+
function writePidmapRowUnderCustody(coordRoot, pid, instanceId, platform) {
|
|
113
118
|
const dir = join(coordRoot, ".harnery", "pid-map");
|
|
114
119
|
const path = join(dir, String(pid));
|
|
115
120
|
// Stamped at write time, when the pid provably belongs to the process we
|
|
@@ -68,6 +68,24 @@ export declare function psStartToken(pid: number, run?: (pid: number) => {
|
|
|
68
68
|
* will not say.
|
|
69
69
|
*/
|
|
70
70
|
export declare function processStartToken(pid: number): string | null;
|
|
71
|
+
export type ProcessGenerationVerdict = "same" | "different" | "unknown";
|
|
72
|
+
type ReadProcessStartToken = (pid: number) => string | null;
|
|
73
|
+
/** A missing or unreadable token never establishes process identity. */
|
|
74
|
+
export declare function verifyProcessGeneration(pid: number, recordedToken: string | null | undefined, readToken?: ReadProcessStartToken): ProcessGenerationVerdict;
|
|
75
|
+
export interface ProcessGenerationSignalDependencies {
|
|
76
|
+
readToken?: ReadProcessStartToken;
|
|
77
|
+
kill?: (pid: number, signal: NodeJS.Signals | number) => unknown;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Recheck the process generation immediately before sending the signal.
|
|
81
|
+
*
|
|
82
|
+
* The process can still exit and its PID can be reused between the token read
|
|
83
|
+
* and the signal. Eliminating that race requires a generation-bound OS handle.
|
|
84
|
+
*/
|
|
85
|
+
export declare function signalIfSameGeneration(pid: number, recordedToken: string | null | undefined, signal: NodeJS.Signals | number, dependencies?: ProcessGenerationSignalDependencies): {
|
|
86
|
+
sent: boolean;
|
|
87
|
+
verdict: ProcessGenerationVerdict;
|
|
88
|
+
};
|
|
71
89
|
/**
|
|
72
90
|
* Do two tokens describe the same run?
|
|
73
91
|
*
|
|
@@ -92,4 +110,5 @@ export declare function tokensAgree(recorded: string, current: string): boolean;
|
|
|
92
110
|
* treated every row previously: trust it if the pid is alive.
|
|
93
111
|
*/
|
|
94
112
|
export declare function checkPidToken(pid: number, recorded: string | undefined): "match" | "mismatch" | "unverified";
|
|
113
|
+
export {};
|
|
95
114
|
//# sourceMappingURL=proc-start.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proc-start.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/proc-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAMH,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,IAAI,CAAC;AAc9C;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,eAAe,CAOjD;AAyBD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc3D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAiB,GAC7E,MAAM,GAAG,IAAI,CAUf;AAWD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQtE;AAOD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,GAAG,UAAU,GAAG,YAAY,CAKrC"}
|
|
1
|
+
{"version":3,"file":"proc-start.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/proc-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAMH,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,IAAI,CAAC;AAc9C;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,eAAe,CAOjD;AAyBD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc3D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAiB,GAC7E,MAAM,GAAG,IAAI,CAUf;AAWD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5D;AAED,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;AAExE,KAAK,qBAAqB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAE5D,wEAAwE;AACxE,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,SAAS,GAAE,qBAAyC,GACnD,wBAAwB,CAkB1B;AAED,MAAM,WAAW,mCAAmC;IAClD,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,OAAO,CAAC;CAClE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,EAC/B,YAAY,GAAE,mCAAwC,GACrD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,wBAAwB,CAAA;CAAE,CAUtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQtE;AAOD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,GAAG,UAAU,GAAG,YAAY,CAKrC"}
|
|
@@ -151,6 +151,47 @@ export function processStartToken(pid) {
|
|
|
151
151
|
return null;
|
|
152
152
|
return startTokenProbe() === "procfs" ? procfsStartToken(pid) : psStartToken(pid);
|
|
153
153
|
}
|
|
154
|
+
/** A missing or unreadable token never establishes process identity. */
|
|
155
|
+
export function verifyProcessGeneration(pid, recordedToken, readToken = processStartToken) {
|
|
156
|
+
if (!Number.isInteger(pid) ||
|
|
157
|
+
pid <= 0 ||
|
|
158
|
+
typeof recordedToken !== "string" ||
|
|
159
|
+
!recordedToken.trim())
|
|
160
|
+
return "unknown";
|
|
161
|
+
// A bootless Linux token cannot identify a process across machine boots.
|
|
162
|
+
if (/^l\d+$/.test(recordedToken))
|
|
163
|
+
return "unknown";
|
|
164
|
+
try {
|
|
165
|
+
const currentToken = readToken(pid);
|
|
166
|
+
if (typeof currentToken !== "string" || !currentToken.trim())
|
|
167
|
+
return "unknown";
|
|
168
|
+
if (/^l\d+$/.test(currentToken))
|
|
169
|
+
return "unknown";
|
|
170
|
+
return currentToken === recordedToken ? "same" : "different";
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return "unknown";
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Recheck the process generation immediately before sending the signal.
|
|
178
|
+
*
|
|
179
|
+
* The process can still exit and its PID can be reused between the token read
|
|
180
|
+
* and the signal. Eliminating that race requires a generation-bound OS handle.
|
|
181
|
+
*/
|
|
182
|
+
export function signalIfSameGeneration(pid, recordedToken, signal, dependencies = {}) {
|
|
183
|
+
const kill = dependencies.kill ?? process.kill;
|
|
184
|
+
const verdict = verifyProcessGeneration(pid, recordedToken, dependencies.readToken);
|
|
185
|
+
if (verdict !== "same")
|
|
186
|
+
return { sent: false, verdict };
|
|
187
|
+
try {
|
|
188
|
+
kill(pid, signal);
|
|
189
|
+
return { sent: true, verdict };
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return { sent: false, verdict };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
154
195
|
/**
|
|
155
196
|
* Do two tokens describe the same run?
|
|
156
197
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stale-sweep.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/stale-sweep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"stale-sweep.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/state/stale-sweep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAyIH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG;IAC7C,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAuPA"}
|