harnery 0.8.0 → 0.10.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 +2 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +8 -0
- package/dist/commands/agents.d.ts +24 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +244 -13
- package/dist/commands/backup.d.ts +5 -4
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +15 -14
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +27 -1
- package/dist/commands/claude-desktop.d.ts +19 -0
- package/dist/commands/claude-desktop.d.ts.map +1 -0
- package/dist/commands/claude-desktop.js +168 -0
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +149 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +37 -0
- package/dist/commands/eml.d.ts +32 -0
- package/dist/commands/eml.d.ts.map +1 -1
- package/dist/commands/eml.js +16 -3
- package/dist/commands/grep.d.ts +35 -2
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +427 -139
- package/dist/commands/harness.d.ts +11 -0
- package/dist/commands/harness.d.ts.map +1 -0
- package/dist/commands/harness.js +118 -0
- package/dist/commands/init.d.ts +15 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +125 -14
- package/dist/commands/presence.d.ts +9 -4
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +88 -5
- package/dist/commands/relay.d.ts +9 -0
- package/dist/commands/relay.d.ts.map +1 -0
- package/dist/commands/relay.js +143 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +5 -0
- package/dist/commands/workflow.d.ts +4 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +82 -0
- package/dist/core/agents/canonical-emit.d.ts +15 -0
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +41 -3
- package/dist/core/agents/cli.js +14 -5
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +44 -3
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +26 -1
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +26 -1
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +4 -37
- package/dist/core/agents/rules/stop-hook.d.ts +8 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +8 -0
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +16 -43
- package/dist/core/agents/state/heartbeat-projector.d.ts +2 -0
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-projector.js +24 -4
- package/dist/core/agents/state/heartbeat-writer.d.ts +16 -2
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +24 -7
- package/dist/core/agents/state/names.d.ts +38 -3
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +46 -7
- package/dist/core/agents/state/pidmap.d.ts +5 -1
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +58 -2
- package/dist/core/agents/state/stale-sweep.d.ts +3 -2
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +6 -6
- package/dist/core/config.d.ts +77 -11
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +210 -25
- package/dist/core/context/index.d.ts +144 -0
- package/dist/core/context/index.d.ts.map +1 -0
- package/dist/core/context/index.js +380 -0
- package/dist/core/harnesses/bench.d.ts +29 -0
- package/dist/core/harnesses/bench.d.ts.map +1 -0
- package/dist/core/harnesses/bench.js +151 -0
- package/dist/core/harnesses/index.d.ts +9 -0
- package/dist/core/harnesses/index.d.ts.map +1 -0
- package/dist/core/harnesses/index.js +4 -0
- package/dist/core/harnesses/profiles.d.ts +62 -0
- package/dist/core/harnesses/profiles.d.ts.map +1 -0
- package/dist/core/harnesses/profiles.js +115 -0
- package/dist/core/harnesses/registry.d.ts +15 -0
- package/dist/core/harnesses/registry.d.ts.map +1 -0
- package/dist/core/harnesses/registry.js +113 -0
- package/dist/core/harnesses/types.d.ts +64 -0
- package/dist/core/harnesses/types.d.ts.map +1 -0
- package/dist/core/harnesses/types.js +20 -0
- package/dist/core/hooks/cli.js +309 -66
- package/dist/core/hooks/events/schema.d.ts +42 -1
- package/dist/core/hooks/events/schema.d.ts.map +1 -1
- package/dist/core/hooks/harness/events.d.ts +7 -0
- package/dist/core/hooks/harness/events.d.ts.map +1 -1
- package/dist/core/hooks/harness/events.js +4 -0
- package/dist/core/hooks/harness/parse.d.ts +1 -1
- package/dist/core/hooks/harness/parse.d.ts.map +1 -1
- package/dist/core/hooks/harness/parse.js +4 -0
- package/dist/core/hooks/resolve/coord-root.d.ts +11 -0
- package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
- package/dist/core/hooks/resolve/coord-root.js +28 -6
- package/dist/core/presence/blob.d.ts +40 -0
- package/dist/core/presence/blob.d.ts.map +1 -0
- package/dist/core/presence/blob.js +91 -0
- package/dist/core/presence/git.d.ts +68 -0
- package/dist/core/presence/git.d.ts.map +1 -0
- package/dist/core/presence/git.js +173 -0
- package/dist/core/presence/index.d.ts +74 -0
- package/dist/core/presence/index.d.ts.map +1 -0
- package/dist/core/presence/index.js +224 -0
- package/dist/core/presence/relay-client.d.ts +39 -0
- package/dist/core/presence/relay-client.d.ts.map +1 -0
- package/dist/core/presence/relay-client.js +295 -0
- package/dist/core/presence/relay-protocol.d.ts +94 -0
- package/dist/core/presence/relay-protocol.d.ts.map +1 -0
- package/dist/core/presence/relay-protocol.js +169 -0
- package/dist/core/workflow/billing.d.ts +48 -0
- package/dist/core/workflow/billing.d.ts.map +1 -0
- package/dist/core/workflow/billing.js +108 -0
- package/dist/core/workflow/child-env.d.ts +30 -0
- package/dist/core/workflow/child-env.d.ts.map +1 -0
- package/dist/core/workflow/child-env.js +43 -0
- package/dist/core/workflow/engine.d.ts +21 -0
- package/dist/core/workflow/engine.d.ts.map +1 -0
- package/dist/core/workflow/engine.js +349 -0
- package/dist/core/workflow/harnesses.d.ts +17 -0
- package/dist/core/workflow/harnesses.d.ts.map +1 -0
- package/dist/core/workflow/harnesses.js +21 -0
- package/dist/core/workflow/spawn-claude.d.ts +25 -0
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -0
- package/dist/core/workflow/spawn-claude.js +103 -0
- package/dist/core/workflow/spawn-codex.d.ts +22 -0
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -0
- package/dist/core/workflow/spawn-codex.js +88 -0
- package/dist/core/workflow/spawn-cursor.d.ts +29 -0
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -0
- package/dist/core/workflow/spawn-cursor.js +91 -0
- package/dist/core/workflow/types.d.ts +152 -0
- package/dist/core/workflow/types.d.ts.map +1 -0
- package/dist/core/workflow/types.js +9 -0
- package/dist/core/workflow/validate.d.ts +15 -0
- package/dist/core/workflow/validate.d.ts.map +1 -0
- package/dist/core/workflow/validate.js +70 -0
- package/dist/lib/browser/client.d.ts +16 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +22 -0
- package/dist/lib/browser/index.d.ts +1 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +1 -0
- package/dist/lib/browser/launch-args.d.ts +21 -0
- package/dist/lib/browser/launch-args.d.ts.map +1 -0
- package/dist/lib/browser/launch-args.js +32 -0
- package/dist/lib/claude-desktop.d.ts +105 -0
- package/dist/lib/claude-desktop.d.ts.map +1 -0
- package/dist/lib/claude-desktop.js +217 -0
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +5 -2
- package/dist/lib/identities/assume.d.ts +51 -0
- package/dist/lib/identities/assume.d.ts.map +1 -0
- package/dist/lib/identities/assume.js +274 -0
- package/dist/lib/identities/index.d.ts +7 -7
- package/dist/lib/identities/index.d.ts.map +1 -1
- package/dist/lib/identities/index.js +24 -24
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +15 -2
- package/package.json +12 -1
- package/schemas/config.schema.json +88 -19
- package/src/commander.ts +8 -0
- package/src/commands/agents.ts +280 -14
- package/src/commands/backup.ts +17 -16
- package/src/commands/browse.ts +32 -0
- package/src/commands/claude-desktop.ts +215 -0
- package/src/commands/context.ts +174 -1
- package/src/commands/doctor.ts +44 -0
- package/src/commands/eml.ts +22 -4
- package/src/commands/grep.ts +535 -142
- package/src/commands/harness.ts +147 -0
- package/src/commands/init.ts +138 -17
- package/src/commands/presence.ts +111 -5
- package/src/commands/relay.ts +160 -0
- package/src/commands/sync.ts +4 -0
- package/src/commands/workflow.ts +123 -0
- package/src/core/agents/canonical-emit.ts +41 -3
- package/src/core/agents/cli.ts +15 -6
- package/src/core/agents/render/prompt-context.ts +48 -3
- package/src/core/agents/render/session-context.ts +27 -1
- package/src/core/agents/rules/claim-conflict.ts +26 -1
- package/src/core/agents/rules/commit-conflict.ts +4 -33
- package/src/core/agents/rules/stop-hook.ts +17 -0
- package/src/core/agents/session-events.ts +15 -39
- package/src/core/agents/state/heartbeat-projector.ts +23 -2
- package/src/core/agents/state/heartbeat-writer.ts +33 -7
- package/src/core/agents/state/names.ts +68 -9
- package/src/core/agents/state/pidmap.ts +59 -2
- package/src/core/agents/state/stale-sweep.ts +6 -11
- package/src/core/config.ts +271 -24
- package/src/core/context/index.ts +575 -0
- package/src/core/harnesses/bench.ts +214 -0
- package/src/core/harnesses/index.ts +31 -0
- package/src/core/harnesses/profiles.ts +141 -0
- package/src/core/harnesses/registry.ts +140 -0
- package/src/core/harnesses/types.ts +90 -0
- package/src/core/hooks/cli.ts +361 -65
- package/src/core/hooks/events/schema.ts +72 -0
- package/src/core/hooks/harness/events.ts +11 -0
- package/src/core/hooks/harness/parse.ts +7 -1
- package/src/core/hooks/resolve/coord-root.ts +28 -6
- package/src/core/presence/blob.ts +125 -0
- package/src/core/presence/git.ts +191 -0
- package/src/core/presence/index.ts +274 -0
- package/src/core/presence/relay-client.ts +322 -0
- package/src/core/presence/relay-protocol.ts +246 -0
- package/src/core/workflow/billing.ts +152 -0
- package/src/core/workflow/child-env.ts +47 -0
- package/src/core/workflow/engine.ts +403 -0
- package/src/core/workflow/harnesses.ts +33 -0
- package/src/core/workflow/spawn-claude.ts +118 -0
- package/src/core/workflow/spawn-codex.ts +93 -0
- package/src/core/workflow/spawn-cursor.ts +108 -0
- package/src/core/workflow/types.ts +160 -0
- package/src/core/workflow/validate.ts +75 -0
- package/src/lib/browser/client.ts +37 -0
- package/src/lib/browser/index.ts +1 -0
- package/src/lib/browser/launch-args.ts +33 -0
- package/src/lib/claude-desktop.ts +293 -0
- package/src/lib/docs-lint.ts +5 -2
- package/src/lib/identities/assume.ts +363 -0
- package/src/lib/identities/index.ts +28 -24
- package/src/lib/instructions/templates.ts +16 -2
package/src/core/hooks/cli.ts
CHANGED
|
@@ -27,6 +27,17 @@ import { consumeSince, writeCursor } from "../agents/events/consume.ts";
|
|
|
27
27
|
import { evaluateStopHook } from "../agents/rules/stop-hook.ts";
|
|
28
28
|
import { projectHeartbeats } from "../agents/state/heartbeat-projector.ts";
|
|
29
29
|
import { shellMutationPaths } from "../agents/state/shell-mutation.ts";
|
|
30
|
+
import {
|
|
31
|
+
checkpointContext,
|
|
32
|
+
completeContextRecovery,
|
|
33
|
+
extractContextSample,
|
|
34
|
+
markContextCompactionCompleted,
|
|
35
|
+
type PreparedContextRecovery,
|
|
36
|
+
prepareContextRecovery,
|
|
37
|
+
readContextState,
|
|
38
|
+
recordContextSample,
|
|
39
|
+
} from "../context/index.ts";
|
|
40
|
+
import { ensureRelayDaemon, fetchPresence, publishPresence } from "../presence/index.ts";
|
|
30
41
|
import {
|
|
31
42
|
captureImages,
|
|
32
43
|
detectPresence,
|
|
@@ -94,6 +105,17 @@ async function readStdin(): Promise<string> {
|
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Env for child agent-coord spawns, with the coord root pinned. The hook
|
|
110
|
+
* process may be running with the session shell's cwd (inside a submodule or
|
|
111
|
+
* scratch dir), and agent-coord resolves its root from cwd unless overridden —
|
|
112
|
+
* without the pin a child could write state to a different .harnery than the
|
|
113
|
+
* one this hook resolved.
|
|
114
|
+
*/
|
|
115
|
+
function childEnv(coordRoot: string): NodeJS.ProcessEnv {
|
|
116
|
+
return { ...process.env, HARNERY_COORD_ROOT_OVERRIDE: coordRoot };
|
|
117
|
+
}
|
|
118
|
+
|
|
97
119
|
function appendDebug(coordRoot: string, entry: Record<string, unknown>): void {
|
|
98
120
|
const path = join(coordRoot, ".harnery", "debug", "agent-hook.ndjson");
|
|
99
121
|
try {
|
|
@@ -143,6 +165,7 @@ function assignNameViaAgentCoord(
|
|
|
143
165
|
const result = spawnSync(binary, ["assign-name", instanceId, kind], {
|
|
144
166
|
encoding: "utf8",
|
|
145
167
|
timeout: 2000,
|
|
168
|
+
env: childEnv(coordRoot),
|
|
146
169
|
});
|
|
147
170
|
if (result.status !== 0 || !result.stdout) return null;
|
|
148
171
|
const parsed = JSON.parse(result.stdout.trim()) as {
|
|
@@ -254,6 +277,12 @@ function buildEventData(
|
|
|
254
277
|
name: assigned?.name,
|
|
255
278
|
kind: "session",
|
|
256
279
|
agent_id: ctx.instanceId,
|
|
280
|
+
// Workflow-child linkage: `workflow run` children carry the run id in
|
|
281
|
+
// env (spawn adapters set it via buildChildEnv), so their sessions and
|
|
282
|
+
// heartbeats join back to the run journal + /workflows web view.
|
|
283
|
+
...(coordEnv("WORKFLOW_CHILD") === "1" && coordEnv("WORKFLOW_RUN_ID")
|
|
284
|
+
? { workflow_run_id: coordEnv("WORKFLOW_RUN_ID") }
|
|
285
|
+
: {}),
|
|
257
286
|
};
|
|
258
287
|
}
|
|
259
288
|
|
|
@@ -368,9 +397,49 @@ function buildEventData(
|
|
|
368
397
|
...(summary.truncated ? { truncated: true } : {}),
|
|
369
398
|
};
|
|
370
399
|
}
|
|
400
|
+
|
|
401
|
+
case "context.compaction.started": {
|
|
402
|
+
const metadata = objectRecord(p?.raw.compact_metadata);
|
|
403
|
+
return {
|
|
404
|
+
trigger: stringField(p?.raw.trigger) ?? stringField(metadata?.trigger),
|
|
405
|
+
pre_tokens:
|
|
406
|
+
numberField(p?.raw.pre_tokens) ??
|
|
407
|
+
numberField(metadata?.pre_tokens) ??
|
|
408
|
+
numberField(metadata?.pre_compact_tokens),
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
case "context.compaction.completed": {
|
|
413
|
+
const metadata = objectRecord(p?.raw.compact_metadata);
|
|
414
|
+
return {
|
|
415
|
+
trigger: stringField(p?.raw.trigger) ?? stringField(metadata?.trigger),
|
|
416
|
+
pre_tokens:
|
|
417
|
+
numberField(p?.raw.pre_tokens) ??
|
|
418
|
+
numberField(metadata?.pre_tokens) ??
|
|
419
|
+
numberField(metadata?.pre_compact_tokens),
|
|
420
|
+
post_tokens:
|
|
421
|
+
numberField(p?.raw.post_tokens) ??
|
|
422
|
+
numberField(metadata?.post_tokens) ??
|
|
423
|
+
numberField(metadata?.post_compact_tokens),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
371
426
|
}
|
|
372
427
|
}
|
|
373
428
|
|
|
429
|
+
function objectRecord(value: unknown): Record<string, unknown> | undefined {
|
|
430
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
431
|
+
? (value as Record<string, unknown>)
|
|
432
|
+
: undefined;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function stringField(value: unknown): string | undefined {
|
|
436
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function numberField(value: unknown): number | undefined {
|
|
440
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
441
|
+
}
|
|
442
|
+
|
|
374
443
|
async function main(): Promise<number> {
|
|
375
444
|
const { eventName, extra } = parseArgv(process.argv.slice(2));
|
|
376
445
|
const harness = detectHarness(process.argv.slice(2));
|
|
@@ -471,6 +540,84 @@ async function main(): Promise<number> {
|
|
|
471
540
|
event_id: envelope.event_id,
|
|
472
541
|
});
|
|
473
542
|
|
|
543
|
+
// Context telemetry is opportunistic and truthful: only persist a sample
|
|
544
|
+
// when the harness payload actually exposes usage/window data. Identical
|
|
545
|
+
// measurements are de-duplicated before they reach the canonical stream.
|
|
546
|
+
if (payload?.raw) {
|
|
547
|
+
try {
|
|
548
|
+
const sample = extractContextSample(payload.raw, {
|
|
549
|
+
sessionId,
|
|
550
|
+
harness,
|
|
551
|
+
model: payload.model,
|
|
552
|
+
source: "hook",
|
|
553
|
+
confidence: "reported",
|
|
554
|
+
});
|
|
555
|
+
if (sample) {
|
|
556
|
+
const recorded = recordContextSample(coordRoot, owner.instance_id, sample);
|
|
557
|
+
if (recorded.changed) {
|
|
558
|
+
emit(coordRoot, {
|
|
559
|
+
event_type: "context.sampled",
|
|
560
|
+
instance_id: owner.instance_id,
|
|
561
|
+
session_id: sessionId,
|
|
562
|
+
harness,
|
|
563
|
+
data: {
|
|
564
|
+
model: sample.model,
|
|
565
|
+
used_tokens: sample.used_tokens,
|
|
566
|
+
window_tokens: sample.window_tokens,
|
|
567
|
+
used_percent: sample.used_percent,
|
|
568
|
+
telemetry_source: sample.source,
|
|
569
|
+
confidence: sample.confidence,
|
|
570
|
+
},
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
} catch (err) {
|
|
575
|
+
logError(coordRoot, err, { phase: "context-sample" });
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// A native pre-compaction signal is the safest available point to capture
|
|
580
|
+
// external work state. The operation is idempotent until recovery, so a
|
|
581
|
+
// harness retry cannot create a storm of near-identical capsules.
|
|
582
|
+
if (norm.event_type === "context.compaction.started") {
|
|
583
|
+
try {
|
|
584
|
+
const checkpoint = checkpointContext(coordRoot, {
|
|
585
|
+
sessionId,
|
|
586
|
+
instanceId: owner.instance_id,
|
|
587
|
+
harness,
|
|
588
|
+
cwd: payload?.cwd ?? process.cwd(),
|
|
589
|
+
reason: "pre_compact",
|
|
590
|
+
model: payload?.model,
|
|
591
|
+
});
|
|
592
|
+
emit(coordRoot, {
|
|
593
|
+
event_type: "context.checkpoint.created",
|
|
594
|
+
instance_id: owner.instance_id,
|
|
595
|
+
session_id: sessionId,
|
|
596
|
+
harness,
|
|
597
|
+
data: {
|
|
598
|
+
capsule_id: checkpoint.capsule.capsule_id,
|
|
599
|
+
generation: checkpoint.capsule.generation,
|
|
600
|
+
path: checkpoint.state.latest_capsule ?? "",
|
|
601
|
+
reason: checkpoint.capsule.reason,
|
|
602
|
+
reused: checkpoint.reused,
|
|
603
|
+
},
|
|
604
|
+
});
|
|
605
|
+
} catch (err) {
|
|
606
|
+
logError(coordRoot, err, { phase: "context-checkpoint" });
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (norm.event_type === "context.compaction.completed") {
|
|
611
|
+
try {
|
|
612
|
+
markContextCompactionCompleted(coordRoot, {
|
|
613
|
+
sessionId,
|
|
614
|
+
instanceId: owner.instance_id,
|
|
615
|
+
});
|
|
616
|
+
} catch (err) {
|
|
617
|
+
logError(coordRoot, err, { phase: "context-compaction-completed" });
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
474
621
|
// Phase 8: SessionStart post-emit: project the event so the heartbeat
|
|
475
622
|
// lands synchronously, run stale-sweep, and emit the harness-shaped
|
|
476
623
|
// systemMessage JSON (peer table + wiring check + council invites).
|
|
@@ -489,11 +636,61 @@ async function main(): Promise<number> {
|
|
|
489
636
|
} catch (err) {
|
|
490
637
|
logError(coordRoot, err, { phase: "session-start-image-janitor" });
|
|
491
638
|
}
|
|
639
|
+
let recovery: PreparedContextRecovery | null = null;
|
|
640
|
+
if (payload?.source === "compact") {
|
|
641
|
+
try {
|
|
642
|
+
emit(coordRoot, {
|
|
643
|
+
event_type: "context.compaction.completed",
|
|
644
|
+
instance_id: owner.instance_id,
|
|
645
|
+
session_id: sessionId,
|
|
646
|
+
harness,
|
|
647
|
+
data: { trigger: "auto" },
|
|
648
|
+
});
|
|
649
|
+
markContextCompactionCompleted(coordRoot, {
|
|
650
|
+
sessionId,
|
|
651
|
+
instanceId: owner.instance_id,
|
|
652
|
+
});
|
|
653
|
+
recovery = prepareContextRecovery(coordRoot, {
|
|
654
|
+
instanceId: owner.instance_id,
|
|
655
|
+
sessionId,
|
|
656
|
+
cwd: payload?.cwd ?? process.cwd(),
|
|
657
|
+
});
|
|
658
|
+
} catch (err) {
|
|
659
|
+
logError(coordRoot, err, { phase: "context-recovery-session-start" });
|
|
660
|
+
}
|
|
661
|
+
}
|
|
492
662
|
try {
|
|
493
|
-
await emitSessionStartSystemMessage(
|
|
663
|
+
const injected = await emitSessionStartSystemMessage(
|
|
664
|
+
coordRoot,
|
|
665
|
+
owner.instance_id,
|
|
666
|
+
sessionId,
|
|
667
|
+
data,
|
|
668
|
+
harness,
|
|
669
|
+
recovery?.briefing ?? "",
|
|
670
|
+
);
|
|
671
|
+
if (injected && recovery) {
|
|
672
|
+
completeRecoveryInjection(
|
|
673
|
+
coordRoot,
|
|
674
|
+
owner.instance_id,
|
|
675
|
+
sessionId,
|
|
676
|
+
harness,
|
|
677
|
+
recovery,
|
|
678
|
+
"SessionStart",
|
|
679
|
+
);
|
|
680
|
+
}
|
|
494
681
|
} catch (err) {
|
|
495
682
|
logError(coordRoot, err, { phase: "session-start-systemMessage" });
|
|
496
683
|
}
|
|
684
|
+
// Cross-machine presence (ADR 0016): announce this machine's sessions and
|
|
685
|
+
// pull peers'. Both are throttled + fail-silent; network runs detached.
|
|
686
|
+
// When a relay is configured, also make sure the live-socket daemon runs.
|
|
687
|
+
try {
|
|
688
|
+
publishPresence(coordRoot);
|
|
689
|
+
fetchPresence(coordRoot);
|
|
690
|
+
ensureRelayDaemon(coordRoot);
|
|
691
|
+
} catch (err) {
|
|
692
|
+
logError(coordRoot, err, { phase: "session-start-presence" });
|
|
693
|
+
}
|
|
497
694
|
}
|
|
498
695
|
|
|
499
696
|
// Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Harness-
|
|
@@ -510,6 +707,13 @@ async function main(): Promise<number> {
|
|
|
510
707
|
scratchArchive(coordRoot, owner.instance_id);
|
|
511
708
|
runSessionSyncExtension(coordRoot, true);
|
|
512
709
|
}
|
|
710
|
+
// Presence: publish the post-cleanup state so peers see this session gone
|
|
711
|
+
// promptly rather than waiting out the remote-stale window.
|
|
712
|
+
try {
|
|
713
|
+
publishPresence(coordRoot);
|
|
714
|
+
} catch (err) {
|
|
715
|
+
logError(coordRoot, err, { phase: "session-end-presence" });
|
|
716
|
+
}
|
|
513
717
|
}
|
|
514
718
|
|
|
515
719
|
// Phase 8: SubagentStart: sync-project to create the subagent heartbeat,
|
|
@@ -519,7 +723,11 @@ async function main(): Promise<number> {
|
|
|
519
723
|
try {
|
|
520
724
|
const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
|
|
521
725
|
if (existsSync(agentCoordBin)) {
|
|
522
|
-
spawnSync(agentCoordBin, ["project"], {
|
|
726
|
+
spawnSync(agentCoordBin, ["project"], {
|
|
727
|
+
encoding: "utf8",
|
|
728
|
+
timeout: 3000,
|
|
729
|
+
env: childEnv(coordRoot),
|
|
730
|
+
});
|
|
523
731
|
spawnSync(
|
|
524
732
|
agentCoordBin,
|
|
525
733
|
[
|
|
@@ -528,7 +736,7 @@ async function main(): Promise<number> {
|
|
|
528
736
|
"--instance",
|
|
529
737
|
owner.instance_id,
|
|
530
738
|
],
|
|
531
|
-
{ encoding: "utf8", timeout: 2000 },
|
|
739
|
+
{ encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
|
|
532
740
|
);
|
|
533
741
|
}
|
|
534
742
|
emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data, harness);
|
|
@@ -551,7 +759,7 @@ async function main(): Promise<number> {
|
|
|
551
759
|
"--instance",
|
|
552
760
|
owner.instance_id,
|
|
553
761
|
],
|
|
554
|
-
{ encoding: "utf8", timeout: 2000 },
|
|
762
|
+
{ encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
|
|
555
763
|
);
|
|
556
764
|
}
|
|
557
765
|
} catch (err) {
|
|
@@ -569,8 +777,47 @@ async function main(): Promise<number> {
|
|
|
569
777
|
const prompt = (payload?.raw?.prompt as string | undefined) ?? "";
|
|
570
778
|
if (prompt) detectPresence(prompt);
|
|
571
779
|
}
|
|
780
|
+
// Presence: throttled pull of peer machines' presence refs (default 60s
|
|
781
|
+
// interval; the systemMessage below reads whatever is locally known).
|
|
572
782
|
try {
|
|
573
|
-
|
|
783
|
+
fetchPresence(coordRoot);
|
|
784
|
+
} catch (err) {
|
|
785
|
+
logError(coordRoot, err, { phase: "user-prompt-submit-presence" });
|
|
786
|
+
}
|
|
787
|
+
let recovery: PreparedContextRecovery | null = null;
|
|
788
|
+
const continuityState = readContextState(coordRoot, sessionId);
|
|
789
|
+
if (
|
|
790
|
+
continuityState?.phase === "checkpointed" &&
|
|
791
|
+
continuityState.compaction_completed_at !== undefined
|
|
792
|
+
) {
|
|
793
|
+
try {
|
|
794
|
+
recovery = prepareContextRecovery(coordRoot, {
|
|
795
|
+
instanceId: owner.instance_id,
|
|
796
|
+
sessionId,
|
|
797
|
+
cwd: payload?.cwd ?? process.cwd(),
|
|
798
|
+
});
|
|
799
|
+
} catch (err) {
|
|
800
|
+
logError(coordRoot, err, { phase: "context-recovery-user-prompt" });
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
try {
|
|
804
|
+
const injected = await emitUserPromptSubmitSystemMessage(
|
|
805
|
+
coordRoot,
|
|
806
|
+
owner.instance_id,
|
|
807
|
+
sessionId,
|
|
808
|
+
harness,
|
|
809
|
+
recovery?.briefing ?? "",
|
|
810
|
+
);
|
|
811
|
+
if (injected && recovery) {
|
|
812
|
+
completeRecoveryInjection(
|
|
813
|
+
coordRoot,
|
|
814
|
+
owner.instance_id,
|
|
815
|
+
sessionId,
|
|
816
|
+
harness,
|
|
817
|
+
recovery,
|
|
818
|
+
"UserPromptSubmit",
|
|
819
|
+
);
|
|
820
|
+
}
|
|
574
821
|
} catch (err) {
|
|
575
822
|
logError(coordRoot, err, { phase: "user-prompt-submit-systemMessage" });
|
|
576
823
|
}
|
|
@@ -623,6 +870,17 @@ async function main(): Promise<number> {
|
|
|
623
870
|
logError(coordRoot, err, { phase: "stop-projection" });
|
|
624
871
|
}
|
|
625
872
|
|
|
873
|
+
// Presence: publish AFTER the projection above so the blob carries this
|
|
874
|
+
// turn's fresh task/turn_summary/files. Change-batched + keepalive'd;
|
|
875
|
+
// the push itself runs detached. The relay daemon (when configured) is
|
|
876
|
+
// re-ensured here too — it self-exits on idle, and the next turn revives it.
|
|
877
|
+
try {
|
|
878
|
+
publishPresence(coordRoot);
|
|
879
|
+
ensureRelayDaemon(coordRoot);
|
|
880
|
+
} catch (err) {
|
|
881
|
+
logError(coordRoot, err, { phase: "stop-presence" });
|
|
882
|
+
}
|
|
883
|
+
|
|
626
884
|
// Stop verdict (status-box + set-task gate). Direct in-process call: the
|
|
627
885
|
// rule lives in harnery. agent-hook already emitted this turn.stop (with
|
|
628
886
|
// status_box_present) above, so the evidence is in the stream.
|
|
@@ -632,6 +890,7 @@ async function main(): Promise<number> {
|
|
|
632
890
|
session_id: sessionId,
|
|
633
891
|
harness,
|
|
634
892
|
bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
|
|
893
|
+
workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
|
|
635
894
|
});
|
|
636
895
|
if (!verdict.allow) {
|
|
637
896
|
// Harness-aware enforcement channel: Claude Code / Codex honor exit-2 +
|
|
@@ -796,6 +1055,7 @@ async function runPreToolUseGuard(
|
|
|
796
1055
|
input: verdictReq,
|
|
797
1056
|
encoding: "utf8",
|
|
798
1057
|
timeout: 3000,
|
|
1058
|
+
env: childEnv(coordRoot),
|
|
799
1059
|
});
|
|
800
1060
|
if (result.status !== 0 || !result.stdout) continue;
|
|
801
1061
|
let parsed: { allow?: boolean; reason?: string } = {};
|
|
@@ -893,6 +1153,7 @@ function healHeartbeatViaCli(
|
|
|
893
1153
|
spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--harness=${harness}`], {
|
|
894
1154
|
encoding: "utf8",
|
|
895
1155
|
timeout: 2000,
|
|
1156
|
+
env: childEnv(coordRoot),
|
|
896
1157
|
});
|
|
897
1158
|
}
|
|
898
1159
|
|
|
@@ -1000,6 +1261,7 @@ function stampToolActivity(
|
|
|
1000
1261
|
spawnSync(agentCoordBin, ["stamp-tool-activity", instanceId, toolName, target], {
|
|
1001
1262
|
encoding: "utf8",
|
|
1002
1263
|
timeout: 2000,
|
|
1264
|
+
env: childEnv(coordRoot),
|
|
1003
1265
|
});
|
|
1004
1266
|
}
|
|
1005
1267
|
|
|
@@ -1051,6 +1313,7 @@ function releaseClaimOnFailure(
|
|
|
1051
1313
|
spawnSync(agentCoordBin, ["release-claim", instanceId, canonical], {
|
|
1052
1314
|
encoding: "utf8",
|
|
1053
1315
|
timeout: 2000,
|
|
1316
|
+
env: childEnv(coordRoot),
|
|
1054
1317
|
});
|
|
1055
1318
|
}
|
|
1056
1319
|
|
|
@@ -1101,36 +1364,42 @@ async function emitUserPromptSubmitSystemMessage(
|
|
|
1101
1364
|
instanceId: string,
|
|
1102
1365
|
sessionId: string,
|
|
1103
1366
|
harness: Harness,
|
|
1104
|
-
|
|
1367
|
+
recoveryBriefing = "",
|
|
1368
|
+
): Promise<boolean> {
|
|
1105
1369
|
const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
|
|
1106
|
-
|
|
1370
|
+
let additionalContext = "";
|
|
1107
1371
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1372
|
+
if (existsSync(agentCoordBin)) {
|
|
1373
|
+
// Look up the agent's name from its heartbeat (for council pending rendering).
|
|
1374
|
+
let agentName = "";
|
|
1375
|
+
try {
|
|
1376
|
+
const fs = require("node:fs") as typeof import("node:fs");
|
|
1377
|
+
const hbPath = join(coordRoot, ".harnery", "active", `${instanceId}.json`);
|
|
1378
|
+
if (fs.existsSync(hbPath)) {
|
|
1379
|
+
const hb = JSON.parse(fs.readFileSync(hbPath, "utf8")) as { name?: string };
|
|
1380
|
+
agentName = hb.name ?? "";
|
|
1381
|
+
}
|
|
1382
|
+
} catch {
|
|
1383
|
+
/* fall through with empty name; peer table still renders */
|
|
1116
1384
|
}
|
|
1117
|
-
} catch {
|
|
1118
|
-
/* fall through with empty name; peer table still renders */
|
|
1119
|
-
}
|
|
1120
1385
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
if (
|
|
1386
|
+
const args = ["prompt-context", "--instance", instanceId, "--session", sessionId];
|
|
1387
|
+
if (agentName) args.push("--name", agentName);
|
|
1388
|
+
// Cursor + Codex sessions get the set-task staleness nudge. CC enforces it
|
|
1389
|
+
// via the Stop-hook transcript scan; the nudge replaces that for harnesses
|
|
1390
|
+
// that don't reliably expose a transcript_path during stop.
|
|
1391
|
+
if (harness === "cursor" || harness === "codex") args.push("--task-nudge");
|
|
1392
|
+
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1393
|
+
if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
|
|
1394
|
+
}
|
|
1395
|
+
if (recoveryBriefing) {
|
|
1396
|
+
additionalContext = [additionalContext, recoveryBriefing].filter(Boolean).join("\n\n");
|
|
1397
|
+
}
|
|
1398
|
+
if (!additionalContext) return false;
|
|
1131
1399
|
|
|
1132
1400
|
const { emitContext } = await import("./harness/output.ts");
|
|
1133
1401
|
emitContext(harness, "UserPromptSubmit", additionalContext);
|
|
1402
|
+
return true;
|
|
1134
1403
|
}
|
|
1135
1404
|
|
|
1136
1405
|
function emitSubagentStartContext(
|
|
@@ -1183,45 +1452,45 @@ async function emitSessionStartSystemMessage(
|
|
|
1183
1452
|
sessionId: string,
|
|
1184
1453
|
emittedData: Record<string, unknown>,
|
|
1185
1454
|
harness: Harness,
|
|
1186
|
-
|
|
1455
|
+
recoveryBriefing = "",
|
|
1456
|
+
): Promise<boolean> {
|
|
1187
1457
|
const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
|
|
1188
|
-
|
|
1458
|
+
let additionalContext = "";
|
|
1459
|
+
if (existsSync(agentCoordBin)) {
|
|
1460
|
+
// Sync-project so the heartbeat exists for downstream readers (peer table,
|
|
1461
|
+
// wiring check, council invites).
|
|
1462
|
+
spawnSync(agentCoordBin, ["project"], { encoding: "utf8", timeout: 3000 });
|
|
1463
|
+
// Stale-sweep dead peers before rendering peer table.
|
|
1464
|
+
spawnSync(agentCoordBin, ["stale-sweep"], { encoding: "utf8", timeout: 3000 });
|
|
1465
|
+
|
|
1466
|
+
// SESSION_START activity log line, fired across all harnesses.
|
|
1467
|
+
const model = (emittedData.model as string | undefined) ?? "unknown";
|
|
1468
|
+
const source = (emittedData.source as string | undefined) ?? "startup";
|
|
1469
|
+
const platform = harnessPlatform(harness);
|
|
1470
|
+
spawnSync(
|
|
1471
|
+
agentCoordBin,
|
|
1472
|
+
[
|
|
1473
|
+
"log",
|
|
1474
|
+
`SESSION_START model=${model} source=${source} platform=${platform}`,
|
|
1475
|
+
"--instance",
|
|
1476
|
+
instanceId,
|
|
1477
|
+
],
|
|
1478
|
+
{ encoding: "utf8", timeout: 2000 },
|
|
1479
|
+
);
|
|
1189
1480
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
[
|
|
1203
|
-
"log",
|
|
1204
|
-
`SESSION_START model=${model} source=${source} platform=${platform}`,
|
|
1205
|
-
"--instance",
|
|
1206
|
-
instanceId,
|
|
1207
|
-
],
|
|
1208
|
-
{ encoding: "utf8", timeout: 2000 },
|
|
1209
|
-
);
|
|
1210
|
-
|
|
1211
|
-
// Render the systemMessage via agent-coord.
|
|
1212
|
-
const agentName = (emittedData.name as string | undefined) ?? "";
|
|
1213
|
-
const args = ["session-context", "--instance", instanceId, "--session", sessionId];
|
|
1214
|
-
if (agentName) args.push("--name", agentName);
|
|
1215
|
-
// The "You are agent-X." prefix in session-context renders unqualified by
|
|
1216
|
-
// default (claude-code-style). For cursor/codex the bash dispatchers add
|
|
1217
|
-
// a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
|
|
1218
|
-
if (harness !== "claude-code") {
|
|
1219
|
-
args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
|
|
1481
|
+
// Render the systemMessage via agent-coord.
|
|
1482
|
+
const agentName = (emittedData.name as string | undefined) ?? "";
|
|
1483
|
+
const args = ["session-context", "--instance", instanceId, "--session", sessionId];
|
|
1484
|
+
if (agentName) args.push("--name", agentName);
|
|
1485
|
+
// The "You are agent-X." prefix in session-context renders unqualified by
|
|
1486
|
+
// default (claude-code-style). For cursor/codex the bash dispatchers add
|
|
1487
|
+
// a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
|
|
1488
|
+
if (harness !== "claude-code") {
|
|
1489
|
+
args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
|
|
1490
|
+
}
|
|
1491
|
+
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1492
|
+
if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
|
|
1220
1493
|
}
|
|
1221
|
-
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1222
|
-
if (result.status !== 0 || !result.stdout) return;
|
|
1223
|
-
let additionalContext = result.stdout.trim();
|
|
1224
|
-
if (!additionalContext) return;
|
|
1225
1494
|
|
|
1226
1495
|
// Effect (claude-code): merge the scratch recovery cue into the session-start
|
|
1227
1496
|
// context. Was a standalone additionalContext emission from the previous
|
|
@@ -1229,11 +1498,38 @@ async function emitSessionStartSystemMessage(
|
|
|
1229
1498
|
// entry, it folds in here.
|
|
1230
1499
|
if (harness === "claude-code") {
|
|
1231
1500
|
const cue = scratchRecoveryCue(coordRoot);
|
|
1232
|
-
if (cue) additionalContext =
|
|
1501
|
+
if (cue) additionalContext = [additionalContext, cue].filter(Boolean).join("\n\n");
|
|
1502
|
+
}
|
|
1503
|
+
if (recoveryBriefing) {
|
|
1504
|
+
additionalContext = [additionalContext, recoveryBriefing].filter(Boolean).join("\n\n");
|
|
1233
1505
|
}
|
|
1506
|
+
if (!additionalContext) return false;
|
|
1234
1507
|
|
|
1235
1508
|
const { emitContext } = await import("./harness/output.ts");
|
|
1236
1509
|
emitContext(harness, "SessionStart", additionalContext);
|
|
1510
|
+
return true;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
function completeRecoveryInjection(
|
|
1514
|
+
coordRoot: string,
|
|
1515
|
+
instanceId: string,
|
|
1516
|
+
sessionId: string,
|
|
1517
|
+
harness: Harness,
|
|
1518
|
+
recovery: PreparedContextRecovery,
|
|
1519
|
+
injectionEvent: "SessionStart" | "UserPromptSubmit",
|
|
1520
|
+
): void {
|
|
1521
|
+
completeContextRecovery(coordRoot, { sessionId, instanceId });
|
|
1522
|
+
emit(coordRoot, {
|
|
1523
|
+
event_type: "context.recovery.injected",
|
|
1524
|
+
instance_id: instanceId,
|
|
1525
|
+
session_id: sessionId,
|
|
1526
|
+
harness,
|
|
1527
|
+
data: {
|
|
1528
|
+
capsule_id: recovery.capsule.capsule_id,
|
|
1529
|
+
generation: recovery.capsule.generation,
|
|
1530
|
+
injection_event: injectionEvent,
|
|
1531
|
+
},
|
|
1532
|
+
});
|
|
1237
1533
|
}
|
|
1238
1534
|
|
|
1239
1535
|
main()
|
|
@@ -47,6 +47,10 @@ export type SessionStart = EventEnvelope<
|
|
|
47
47
|
cwd: string;
|
|
48
48
|
model?: string;
|
|
49
49
|
pid: number;
|
|
50
|
+
/** Present iff this session is a `workflow run` child: the run id whose
|
|
51
|
+
* journal owns it (child env HARNERY_WORKFLOW_RUN_ID). Optional-field
|
|
52
|
+
* addition per the schema evolution rules (minor bump). */
|
|
53
|
+
workflow_run_id?: string;
|
|
50
54
|
}
|
|
51
55
|
>;
|
|
52
56
|
|
|
@@ -190,6 +194,56 @@ export type ImageCaptured = EventEnvelope<
|
|
|
190
194
|
}
|
|
191
195
|
>;
|
|
192
196
|
|
|
197
|
+
// Context continuity
|
|
198
|
+
export type ContextSampled = EventEnvelope<
|
|
199
|
+
"context.sampled",
|
|
200
|
+
{
|
|
201
|
+
model?: string;
|
|
202
|
+
used_tokens?: number;
|
|
203
|
+
window_tokens?: number;
|
|
204
|
+
used_percent?: number;
|
|
205
|
+
telemetry_source: "hook" | "native_event" | "result" | "transcript" | "estimate";
|
|
206
|
+
confidence: "exact" | "reported" | "estimated";
|
|
207
|
+
}
|
|
208
|
+
>;
|
|
209
|
+
|
|
210
|
+
export type ContextCheckpointCreated = EventEnvelope<
|
|
211
|
+
"context.checkpoint.created",
|
|
212
|
+
{
|
|
213
|
+
capsule_id: string;
|
|
214
|
+
generation: number;
|
|
215
|
+
path: string;
|
|
216
|
+
reason: "manual" | "pressure" | "pre_compact" | "session_end";
|
|
217
|
+
reused: boolean;
|
|
218
|
+
}
|
|
219
|
+
>;
|
|
220
|
+
|
|
221
|
+
export type ContextCompactionStarted = EventEnvelope<
|
|
222
|
+
"context.compaction.started",
|
|
223
|
+
{
|
|
224
|
+
trigger?: string;
|
|
225
|
+
pre_tokens?: number;
|
|
226
|
+
}
|
|
227
|
+
>;
|
|
228
|
+
|
|
229
|
+
export type ContextCompactionCompleted = EventEnvelope<
|
|
230
|
+
"context.compaction.completed",
|
|
231
|
+
{
|
|
232
|
+
trigger?: string;
|
|
233
|
+
pre_tokens?: number;
|
|
234
|
+
post_tokens?: number;
|
|
235
|
+
}
|
|
236
|
+
>;
|
|
237
|
+
|
|
238
|
+
export type ContextRecoveryInjected = EventEnvelope<
|
|
239
|
+
"context.recovery.injected",
|
|
240
|
+
{
|
|
241
|
+
capsule_id: string;
|
|
242
|
+
generation: number;
|
|
243
|
+
injection_event: "SessionStart" | "UserPromptSubmit";
|
|
244
|
+
}
|
|
245
|
+
>;
|
|
246
|
+
|
|
193
247
|
// File claims
|
|
194
248
|
export type ClaimAcquire = EventEnvelope<
|
|
195
249
|
"claim.acquire",
|
|
@@ -253,6 +307,18 @@ export type StatePresenceChange = EventEnvelope<
|
|
|
253
307
|
|
|
254
308
|
export type StateHeartbeat = EventEnvelope<"state.heartbeat", Record<string, never>>;
|
|
255
309
|
|
|
310
|
+
/** A live session adopted a durable persona/role. The event is authoritative
|
|
311
|
+
* for replay; `.name-history` carries the same binding for heartbeat healing. */
|
|
312
|
+
export type IdentityAssumed = EventEnvelope<
|
|
313
|
+
"identity.assumed",
|
|
314
|
+
{
|
|
315
|
+
name: string;
|
|
316
|
+
agent_id: string;
|
|
317
|
+
previous_name?: string;
|
|
318
|
+
previous_agent_id?: string;
|
|
319
|
+
}
|
|
320
|
+
>;
|
|
321
|
+
|
|
256
322
|
// Council
|
|
257
323
|
export type CouncilOpen = EventEnvelope<
|
|
258
324
|
"council.open",
|
|
@@ -394,6 +460,11 @@ export type Event =
|
|
|
394
460
|
| ToolPostUseFailure
|
|
395
461
|
| ToolOutputChunk
|
|
396
462
|
| ImageCaptured
|
|
463
|
+
| ContextSampled
|
|
464
|
+
| ContextCheckpointCreated
|
|
465
|
+
| ContextCompactionStarted
|
|
466
|
+
| ContextCompactionCompleted
|
|
467
|
+
| ContextRecoveryInjected
|
|
397
468
|
| ClaimAcquire
|
|
398
469
|
| ClaimRelease
|
|
399
470
|
| ClaimConflict
|
|
@@ -402,6 +473,7 @@ export type Event =
|
|
|
402
473
|
| StateScratchAppend
|
|
403
474
|
| StatePresenceChange
|
|
404
475
|
| StateHeartbeat
|
|
476
|
+
| IdentityAssumed
|
|
405
477
|
| CouncilOpen
|
|
406
478
|
| CouncilRoundOpen
|
|
407
479
|
| CouncilContribution
|