harnery 0.34.1 → 0.35.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/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +2 -0
- package/dist/commands/agents.d.ts +15 -4
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +89 -175
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +26 -2
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +2 -2
- package/dist/commands/events.d.ts.map +1 -1
- package/dist/commands/events.js +18 -1
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +2 -2
- package/dist/commands/semantic.d.ts +4 -0
- package/dist/commands/semantic.d.ts.map +1 -0
- package/dist/commands/semantic.js +147 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +17 -0
- package/dist/core/agents/canonical-emit.d.ts +3 -0
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +12 -0
- package/dist/core/agents/claim-path.d.ts +11 -0
- package/dist/core/agents/claim-path.d.ts.map +1 -0
- package/dist/core/agents/claim-path.js +22 -0
- package/dist/core/agents/coord-client.d.ts +29 -3
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +88 -9
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +1 -3
- package/dist/core/agents/live-lifecycle-v3.js +3 -3
- package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
- package/dist/core/agents/live-observation-v3.js +2 -2
- package/dist/core/agents/render/prompt-context.js +12 -10
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +23 -11
- package/dist/core/agents/session-name-display.d.ts +1 -0
- package/dist/core/agents/session-name-display.d.ts.map +1 -1
- package/dist/core/agents/session-name-display.js +8 -1
- package/dist/core/agents/state/heartbeat-reader.d.ts +46 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
- package/dist/core/agents/state/heartbeat-reader.js +25 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts +3 -48
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +16 -34
- package/dist/core/agents/state/live-coordination-view.d.ts +1 -1
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +25 -1
- package/dist/core/agents/state/names.d.ts +9 -1
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +190 -182
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +23 -5
- package/dist/core/artifacts/constants.d.ts +5 -0
- package/dist/core/artifacts/constants.d.ts.map +1 -0
- package/dist/core/artifacts/constants.js +4 -0
- package/dist/core/artifacts/index.d.ts +3 -3
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +50 -7
- package/dist/core/events/v3/base-contract.d.ts +795 -0
- package/dist/core/events/v3/base-contract.d.ts.map +1 -1
- package/dist/core/events/v3/base-contract.js +33 -0
- package/dist/core/events/v3/capabilities.d.ts +11 -0
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +23 -0
- package/dist/core/events/v3/generated.d.ts +1 -1
- package/dist/core/events/v3/generated.js +1 -1
- package/dist/core/events/v3/index.d.ts +4 -3
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +4 -3
- package/dist/core/events/v3/latency.d.ts +31 -1
- package/dist/core/events/v3/latency.d.ts.map +1 -1
- package/dist/core/events/v3/latency.js +127 -3
- package/dist/core/events/v3/live-routing.d.ts +30 -0
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +109 -1
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/command-recorder.js +10 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +14 -3
- package/dist/core/events/v3/producers/hook-base.d.ts +17 -1
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +82 -1
- package/dist/core/events/v3/producers/intake.d.ts +6 -0
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +11 -0
- package/dist/core/events/v3/producers/recorder.d.ts +62 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +654 -18
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +51 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
- package/dist/core/events/v3/turn-telemetry.d.ts +9 -0
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.d.ts +3 -0
- package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.js +14 -0
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts +119 -0
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
- package/dist/core/hooks/adapter/runtime-telemetry.js +568 -0
- package/dist/core/hooks/cli.js +111 -36
- package/dist/core/hooks/remediation-cap.d.ts +34 -0
- package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
- package/dist/core/hooks/remediation-cap.js +71 -0
- package/dist/core/hooks/resolve/transcript.d.ts +25 -9
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +22 -10
- package/dist/core/semantic/adapters.d.ts +34 -0
- package/dist/core/semantic/adapters.d.ts.map +1 -0
- package/dist/core/semantic/adapters.js +222 -0
- package/dist/core/semantic/contract.d.ts +588 -0
- package/dist/core/semantic/contract.d.ts.map +1 -0
- package/dist/core/semantic/contract.js +230 -0
- package/dist/core/semantic/evidence.d.ts +11 -0
- package/dist/core/semantic/evidence.d.ts.map +1 -0
- package/dist/core/semantic/evidence.js +262 -0
- package/dist/core/semantic/index.d.ts +10 -0
- package/dist/core/semantic/index.d.ts.map +1 -0
- package/dist/core/semantic/index.js +9 -0
- package/dist/core/semantic/once.d.ts +33 -0
- package/dist/core/semantic/once.d.ts.map +1 -0
- package/dist/core/semantic/once.js +293 -0
- package/dist/core/semantic/prompt.d.ts +12 -0
- package/dist/core/semantic/prompt.d.ts.map +1 -0
- package/dist/core/semantic/prompt.js +70 -0
- package/dist/core/semantic/scheduler.d.ts +16 -0
- package/dist/core/semantic/scheduler.d.ts.map +1 -0
- package/dist/core/semantic/scheduler.js +67 -0
- package/dist/core/semantic/service-status.d.ts +31 -0
- package/dist/core/semantic/service-status.d.ts.map +1 -0
- package/dist/core/semantic/service-status.js +84 -0
- package/dist/core/semantic/service.d.ts +51 -0
- package/dist/core/semantic/service.d.ts.map +1 -0
- package/dist/core/semantic/service.js +470 -0
- package/dist/core/semantic/storage.d.ts +71 -0
- package/dist/core/semantic/storage.d.ts.map +1 -0
- package/dist/core/semantic/storage.js +179 -0
- package/dist/core/semantic/validate.d.ts +16 -0
- package/dist/core/semantic/validate.d.ts.map +1 -0
- package/dist/core/semantic/validate.js +174 -0
- package/dist/lib/browser/client.d.ts +11 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +13 -0
- package/dist/lib/browser/index.d.ts +1 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/standalone-html.d.ts +25 -0
- package/dist/lib/browser/standalone-html.d.ts.map +1 -0
- package/dist/lib/browser/standalone-html.js +284 -0
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +1 -0
- package/dist/lib/instructions/templates.d.ts +2 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +144 -4
- package/package.json +6 -1
- package/schemas/event-v3.schema.json +2758 -478
- package/src/commander.ts +2 -0
- package/src/commands/agents.ts +102 -167
- package/src/commands/browse.ts +25 -2
- package/src/commands/decision.ts +8 -2
- package/src/commands/events.ts +21 -1
- package/src/commands/presence.ts +7 -2
- package/src/commands/semantic.ts +179 -0
- package/src/commands/web.ts +15 -0
- package/src/core/agents/canonical-emit.ts +15 -0
- package/src/core/agents/claim-path.ts +23 -0
- package/src/core/agents/coord-client.ts +92 -8
- package/src/core/agents/live-authority-v3.ts +1 -4
- package/src/core/agents/live-lifecycle-v3.ts +8 -3
- package/src/core/agents/live-observation-v3.ts +7 -2
- package/src/core/agents/render/prompt-context.ts +13 -10
- package/src/core/agents/rules/stop-hook.ts +24 -11
- package/src/core/agents/session-name-display.ts +9 -1
- package/src/core/agents/state/heartbeat-reader.ts +69 -0
- package/src/core/agents/state/heartbeat-writer.ts +20 -84
- package/src/core/agents/state/live-coordination-view.ts +26 -1
- package/src/core/agents/state/names.ts +190 -182
- package/src/core/agents/state/stale-sweep.ts +25 -5
- package/src/core/artifacts/constants.ts +4 -0
- package/src/core/artifacts/index.ts +49 -7
- package/src/core/events/v3/base-contract.ts +39 -0
- package/src/core/events/v3/capabilities.ts +34 -0
- package/src/core/events/v3/generated.ts +1 -1
- package/src/core/events/v3/index.ts +21 -0
- package/src/core/events/v3/latency.ts +213 -2
- package/src/core/events/v3/live-routing.ts +120 -1
- package/src/core/events/v3/producers/command-recorder.ts +10 -1
- package/src/core/events/v3/producers/coordination-recorder.ts +17 -5
- package/src/core/events/v3/producers/hook-base.ts +115 -1
- package/src/core/events/v3/producers/intake.ts +18 -0
- package/src/core/events/v3/producers/recorder.ts +856 -21
- package/src/core/events/v3/runtime-telemetry-capabilities.ts +137 -0
- package/src/core/events/v3/turn-telemetry.ts +10 -0
- package/src/core/hooks/adapter/parse.ts +16 -0
- package/src/core/hooks/adapter/runtime-telemetry.ts +805 -0
- package/src/core/hooks/cli.ts +123 -39
- package/src/core/hooks/remediation-cap.ts +77 -0
- package/src/core/hooks/resolve/transcript.ts +37 -11
- package/src/core/semantic/adapters.ts +293 -0
- package/src/core/semantic/contract.ts +298 -0
- package/src/core/semantic/evidence.ts +336 -0
- package/src/core/semantic/index.ts +127 -0
- package/src/core/semantic/once.ts +410 -0
- package/src/core/semantic/prompt.ts +84 -0
- package/src/core/semantic/scheduler.ts +107 -0
- package/src/core/semantic/service-status.ts +118 -0
- package/src/core/semantic/service.ts +580 -0
- package/src/core/semantic/storage.ts +286 -0
- package/src/core/semantic/validate.ts +212 -0
- package/src/lib/browser/client.ts +21 -0
- package/src/lib/browser/index.ts +4 -0
- package/src/lib/browser/standalone-html.ts +312 -0
- package/src/lib/instructions/apply.ts +1 -0
- package/src/lib/instructions/templates.ts +149 -4
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { createSemanticAdapters, discoverSemanticReaders, inspectSemanticDocument, readSemanticManifest, readSemanticServiceStatus, requestSemanticServiceStop, runSemanticOnce, runSemanticServiceDaemon, semanticPaths, spawnSemanticService, } from "../core/semantic/index.js";
|
|
3
|
+
export function registerSemanticCommand(program, emit, context) {
|
|
4
|
+
const semantic = program
|
|
5
|
+
.command("semantic")
|
|
6
|
+
.description("Build and inspect evidence-cited semantic readings of active V3 generations");
|
|
7
|
+
semantic
|
|
8
|
+
.command("once")
|
|
9
|
+
.description("Run one bounded semantic pass using each generation's source harness")
|
|
10
|
+
.option("--root <path>", "Explicit coordination root")
|
|
11
|
+
.option("--calls-per-hour <count>", "Configured call ceiling below the hard limit", integer)
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
try {
|
|
14
|
+
emit.data(await runSemanticOnce({
|
|
15
|
+
coordRoot: resolve(options.root ?? coordRoot(context)),
|
|
16
|
+
callsPerHour: options.callsPerHour,
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
emitFailure(emit, "semantic_once_failed", error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const service = semantic
|
|
24
|
+
.command("service")
|
|
25
|
+
.description("Run semantic reading as a singleton service");
|
|
26
|
+
service
|
|
27
|
+
.command("start")
|
|
28
|
+
.description("Start or resume the detached per-root semantic reader service")
|
|
29
|
+
.option("--root <path>", "Explicit coordination root")
|
|
30
|
+
.option("--calls-per-hour <count>", "Configured call ceiling below the hard limit", integer)
|
|
31
|
+
.action(async (options) => {
|
|
32
|
+
try {
|
|
33
|
+
emit.data(await spawnSemanticService(resolve(options.root ?? coordRoot(context)), {
|
|
34
|
+
callsPerHour: options.callsPerHour,
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
emitFailure(emit, "semantic_service_start_failed", error);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
service
|
|
42
|
+
.command("status")
|
|
43
|
+
.description("Show singleton liveness, pass metrics, and pending work")
|
|
44
|
+
.option("--root <path>", "Explicit coordination root")
|
|
45
|
+
.action((options) => {
|
|
46
|
+
try {
|
|
47
|
+
emit.data(readSemanticServiceStatus(resolve(options.root ?? coordRoot(context))));
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
emitFailure(emit, "semantic_service_status_failed", error);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
service
|
|
54
|
+
.command("stop")
|
|
55
|
+
.description("Request a graceful stop after the current model call")
|
|
56
|
+
.option("--root <path>", "Explicit coordination root")
|
|
57
|
+
.action(async (options) => {
|
|
58
|
+
try {
|
|
59
|
+
const root = resolve(options.root ?? coordRoot(context));
|
|
60
|
+
let status = requestSemanticServiceStop(root);
|
|
61
|
+
const deadline = Date.now() + 5_000;
|
|
62
|
+
while (status.running && Date.now() < deadline) {
|
|
63
|
+
await new Promise((done) => setTimeout(done, 50));
|
|
64
|
+
status = readSemanticServiceStatus(root);
|
|
65
|
+
}
|
|
66
|
+
emit.data(status);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
emitFailure(emit, "semantic_service_stop_failed", error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
service
|
|
73
|
+
.command("daemon", { hidden: true })
|
|
74
|
+
.description("Internal detached semantic service entrypoint")
|
|
75
|
+
.option("--root <path>", "Explicit coordination root")
|
|
76
|
+
.option("--calls-per-hour <count>", "Configured call ceiling below the hard limit", integer)
|
|
77
|
+
.action(async (options) => {
|
|
78
|
+
try {
|
|
79
|
+
emit.data(await runSemanticServiceDaemon({
|
|
80
|
+
coordRoot: resolve(options.root ?? coordRoot(context)),
|
|
81
|
+
callsPerHour: options.callsPerHour,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
emitFailure(emit, "semantic_service_daemon_failed", error);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
semantic
|
|
89
|
+
.command("inspect")
|
|
90
|
+
.description("Inspect one generation or instance semantic document")
|
|
91
|
+
.argument("<instance-or-generation>")
|
|
92
|
+
.option("--root <path>", "Explicit coordination root")
|
|
93
|
+
.action((instanceOrGeneration, options) => {
|
|
94
|
+
try {
|
|
95
|
+
const document = inspectSemanticDocument(resolve(options.root ?? coordRoot(context)), instanceOrGeneration);
|
|
96
|
+
if (!document)
|
|
97
|
+
throw new Error(`no semantic document for ${instanceOrGeneration}`);
|
|
98
|
+
emit.data(document);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
emitFailure(emit, "semantic_inspect_failed", error);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
semantic
|
|
105
|
+
.command("doctor")
|
|
106
|
+
.description("Inspect semantic reader availability without making a model request")
|
|
107
|
+
.option("--root <path>", "Explicit coordination root")
|
|
108
|
+
.action((options) => {
|
|
109
|
+
try {
|
|
110
|
+
const root = resolve(options.root ?? coordRoot(context));
|
|
111
|
+
emit.data({
|
|
112
|
+
schema_version: 1,
|
|
113
|
+
root,
|
|
114
|
+
storage: semanticPaths(root).root,
|
|
115
|
+
readers: discoverSemanticReaders(createSemanticAdapters()),
|
|
116
|
+
manifest: readManifestSafe(root),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
emitFailure(emit, "semantic_doctor_failed", error);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function coordRoot(context) {
|
|
125
|
+
return resolve(context?.resolveCoordRoot?.() ??
|
|
126
|
+
context?.repoRoot ??
|
|
127
|
+
process.env.HARNERY_COORD_ROOT ??
|
|
128
|
+
process.cwd());
|
|
129
|
+
}
|
|
130
|
+
function integer(value) {
|
|
131
|
+
const parsed = Number(value);
|
|
132
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1)
|
|
133
|
+
throw new Error("count must be a positive integer");
|
|
134
|
+
return parsed;
|
|
135
|
+
}
|
|
136
|
+
function readManifestSafe(root) {
|
|
137
|
+
try {
|
|
138
|
+
return readSemanticManifest(root);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function emitFailure(emit, code, error) {
|
|
145
|
+
emit.error({ code, message: error instanceof Error ? error.message : String(error) });
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/commands/web.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/commands/web.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAkCnD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKrE;AAyCD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAevE;AAsBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA6K5E"}
|
package/dist/commands/web.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createServer } from "node:net";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { DEFAULT_WEB_PORT, resolveWebPort } from "../core/config.js";
|
|
7
|
+
import { ensureSemanticServiceRunning } from "../core/semantic/service.js";
|
|
7
8
|
import { lazyFetchWebRoot, webRunner } from "./web-fetch.js";
|
|
8
9
|
/**
|
|
9
10
|
* `harn web`: Next.js dashboard for harnery's coord state.
|
|
@@ -65,6 +66,20 @@ export function nodeOptionsWithHeapCap(mb) {
|
|
|
65
66
|
return inherited;
|
|
66
67
|
return `${inherited} --max-old-space-size=${mb}`.trim();
|
|
67
68
|
}
|
|
69
|
+
async function startSemanticServiceWithWeb(coordRoot, emit) {
|
|
70
|
+
const result = await ensureSemanticServiceRunning(coordRoot);
|
|
71
|
+
if (result.state === "started")
|
|
72
|
+
emit.log("semantic reader · started automatically", "info");
|
|
73
|
+
if (result.state === "running")
|
|
74
|
+
emit.log("semantic reader · already running", "info");
|
|
75
|
+
if (result.state === "paused")
|
|
76
|
+
emit.log("semantic reader · paused by operator", "info");
|
|
77
|
+
if (result.state === "inactive")
|
|
78
|
+
emit.log("semantic reader · waiting for active V3", "info");
|
|
79
|
+
if (result.state === "unavailable") {
|
|
80
|
+
emit.log(`semantic reader · unavailable (${result.error ?? "startup failed"})`, "warn");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
68
83
|
/**
|
|
69
84
|
* Resolve the web app root. A local `web/` (source checkout / submodule) wins.
|
|
70
85
|
* Otherwise, on an npm install, lazy-fetch it (clone + install) unless the
|
|
@@ -168,6 +183,7 @@ export function registerWebCommand(program, emit) {
|
|
|
168
183
|
}
|
|
169
184
|
if (!(await requireAvailablePort(emit, port)))
|
|
170
185
|
return;
|
|
186
|
+
await startSemanticServiceWithWeb(coordRoot, emit);
|
|
171
187
|
const heapMb = resolveMaxOldSpaceMb(opts.maxOldSpace);
|
|
172
188
|
emit.log(`harn web · http://localhost:${port} (${mode})`, "info");
|
|
173
189
|
emit.log(`files origin · http://harnery-files.localhost:${port}`, "info");
|
|
@@ -253,6 +269,7 @@ export function registerWebCommand(program, emit) {
|
|
|
253
269
|
}
|
|
254
270
|
if (!(await requireAvailablePort(emit, port)))
|
|
255
271
|
return;
|
|
272
|
+
await startSemanticServiceWithWeb(coordRoot, emit);
|
|
256
273
|
const heapMb = resolveMaxOldSpaceMb(opts.maxOldSpace);
|
|
257
274
|
emit.log(`harn web · http://localhost:${port} (start)`, "info");
|
|
258
275
|
emit.log(`reading .harnery/ from: ${coordRoot}`, "info");
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* seconds and record the observation before the parent command exits.
|
|
11
11
|
*/
|
|
12
12
|
import type { LiveCoordinationObservationV3 } from "../events/v3/live-observation.js";
|
|
13
|
+
import type { Heartbeat } from "./state/heartbeat-reader.js";
|
|
13
14
|
export type EventV3EmitObservation = LiveCoordinationObservationV3 | {
|
|
14
15
|
event_type: "coord.lifecycle_changed";
|
|
15
16
|
new_state: "active" | "blocked" | "done";
|
|
@@ -35,4 +36,6 @@ export declare function emitEventV3(input: EventV3EmitInput): boolean;
|
|
|
35
36
|
* Normalize the heartbeat's `platform` field to the canonical Adapter type.
|
|
36
37
|
*/
|
|
37
38
|
export declare function normalizeAdapter(platform: string | undefined): "claude-code" | "cursor" | "codex";
|
|
39
|
+
/** Producer joins use the private native session ID, never its V3 fingerprint. */
|
|
40
|
+
export declare function nativeSessionIdentity(row: Pick<Heartbeat, "native_session_id" | "session_id"> | null | undefined, fallback: string): string;
|
|
38
41
|
//# sourceMappingURL=canonical-emit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-emit.d.ts","sourceRoot":"","sources":["../../../src/core/agents/canonical-emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"canonical-emit.d.ts","sourceRoot":"","sources":["../../../src/core/agents/canonical-emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAGtF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,MAAM,sBAAsB,GAC9B,6BAA6B,GAC7B;IACE,UAAU,EAAE,yBAAyB,CAAC;IACtC,SAAS,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAEN,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC5C,WAAW,EAAE,sBAAsB,CAAC;CACrC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAE5E;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CA4C5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,GAAG,OAAO,CAIjG;AAED,kFAAkF;AAClF,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,mBAAmB,GAAG,YAAY,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3E,QAAQ,EAAE,MAAM,GACf,MAAM,CAQR"}
|
|
@@ -80,3 +80,15 @@ export function normalizeAdapter(platform) {
|
|
|
80
80
|
return "codex";
|
|
81
81
|
return "claude-code";
|
|
82
82
|
}
|
|
83
|
+
/** Producer joins use the private native session ID, never its V3 fingerprint. */
|
|
84
|
+
export function nativeSessionIdentity(row, fallback) {
|
|
85
|
+
if (row?.native_session_id)
|
|
86
|
+
return row.native_session_id;
|
|
87
|
+
// A projection-only row carries the privacy-safe canonical session
|
|
88
|
+
// fingerprint, not the adapter's native session ID needed to join the hook
|
|
89
|
+
// producer. Until a disposable cache exists, the resolved owner is the only
|
|
90
|
+
// native identity available to command surfaces.
|
|
91
|
+
if (row?.session_id && !/^sid_[a-f0-9]{64}$/.test(row.session_id))
|
|
92
|
+
return row.session_id;
|
|
93
|
+
return fallback;
|
|
94
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical identity for an authority-bearing write claim.
|
|
3
|
+
*
|
|
4
|
+
* Workspace paths stay portable and repository-relative. Approved paths
|
|
5
|
+
* outside the coordination root become resolved absolute paths so a later
|
|
6
|
+
* release matches whether the caller supplies the stored dot-dot form or the
|
|
7
|
+
* absolute target. This is lexical identity only; finalization policy owns the
|
|
8
|
+
* physical containment and symlink checks before a claim is acquired.
|
|
9
|
+
*/
|
|
10
|
+
export declare function canonicalClaimPath(coordRoot: string, value: string): string;
|
|
11
|
+
//# sourceMappingURL=claim-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claim-path.d.ts","sourceRoot":"","sources":["../../../src/core/agents/claim-path.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO3E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical identity for an authority-bearing write claim.
|
|
4
|
+
*
|
|
5
|
+
* Workspace paths stay portable and repository-relative. Approved paths
|
|
6
|
+
* outside the coordination root become resolved absolute paths so a later
|
|
7
|
+
* release matches whether the caller supplies the stored dot-dot form or the
|
|
8
|
+
* absolute target. This is lexical identity only; finalization policy owns the
|
|
9
|
+
* physical containment and symlink checks before a claim is acquired.
|
|
10
|
+
*/
|
|
11
|
+
export function canonicalClaimPath(coordRoot, value) {
|
|
12
|
+
const root = resolve(coordRoot);
|
|
13
|
+
const absolute = resolve(root, value);
|
|
14
|
+
const fromRoot = relative(root, absolute);
|
|
15
|
+
const contained = fromRoot !== ".." && !fromRoot.startsWith(`..${sep}`) && !isAbsolute(fromRoot);
|
|
16
|
+
if (contained)
|
|
17
|
+
return portable(fromRoot || ".");
|
|
18
|
+
return portable(absolute);
|
|
19
|
+
}
|
|
20
|
+
function portable(value) {
|
|
21
|
+
return value.split(sep).join("/");
|
|
22
|
+
}
|
|
@@ -104,9 +104,10 @@ export declare function pidStartToken(pid: number): string | null;
|
|
|
104
104
|
* Prefer a row whose platform matches `HARNERY_AGENT_COORD_PLATFORM` (default
|
|
105
105
|
* `claude-code`); otherwise return the first owner seen on the walk.
|
|
106
106
|
*
|
|
107
|
-
* Subagents intentionally do not write pid-map entries; a Bash-tool
|
|
108
|
-
* from inside
|
|
109
|
-
*
|
|
107
|
+
* Subagents intentionally do not write pid-map entries; a bare Bash-tool
|
|
108
|
+
* ppid-walk from inside an unbridged child therefore resolves to the parent's
|
|
109
|
+
* pid-map entry. Native hook bridges supersede this fallback through the
|
|
110
|
+
* child session environment.
|
|
110
111
|
*/
|
|
111
112
|
export declare function resolveOwner(): string | null;
|
|
112
113
|
/**
|
|
@@ -120,6 +121,20 @@ export declare function resolveOwnerWithSource(): {
|
|
|
120
121
|
owner: string | null;
|
|
121
122
|
source: "env" | "pidmap" | "pidmap_fallback" | "session_env" | "active_singleton" | "none";
|
|
122
123
|
};
|
|
124
|
+
/**
|
|
125
|
+
* The nearest pid-map anchor on our own ppid chain whose start token PROVES the
|
|
126
|
+
* row still describes the process holding that pid, or null when the nearest
|
|
127
|
+
* row is unverified, recycled, or absent.
|
|
128
|
+
*
|
|
129
|
+
* Nearest matters: in a nested-agent tree (session A spawns a headless session
|
|
130
|
+
* B whose shell runs this code), both A's and B's adapter processes are
|
|
131
|
+
* ancestors, and only the innermost one owns this process's tool environment.
|
|
132
|
+
* Exported for unit testing with an injectable root.
|
|
133
|
+
*/
|
|
134
|
+
export declare function nearestVerifiedSessionAnchor(root: string): {
|
|
135
|
+
owner: string;
|
|
136
|
+
platform: string;
|
|
137
|
+
} | null;
|
|
123
138
|
/**
|
|
124
139
|
* Walk our own ppid chain for a pid-map row in ONE given root.
|
|
125
140
|
*
|
|
@@ -149,6 +164,17 @@ export declare function sessionIdentityFromEnv(): string | null;
|
|
|
149
164
|
* Exported for unit testing with an injectable root.
|
|
150
165
|
*/
|
|
151
166
|
export declare function resolveOwnerBySessionEnv(root: string): string | null;
|
|
167
|
+
/**
|
|
168
|
+
* `resolveOwnerBySessionEnv` plus WHICH adapter's producer state the session id
|
|
169
|
+
* joined. The caller uses the adapter to tell a same-adapter conflict (the env
|
|
170
|
+
* var is stamped fresh per tool call and outranks a possibly-lagging pid-map
|
|
171
|
+
* row) from a cross-adapter one (the var is inherited context from an outer
|
|
172
|
+
* session and the verified row wins).
|
|
173
|
+
*/
|
|
174
|
+
export declare function resolveOwnerBySessionEnvDetailed(root: string): {
|
|
175
|
+
owner: string;
|
|
176
|
+
adapters: string[];
|
|
177
|
+
} | null;
|
|
152
178
|
/**
|
|
153
179
|
* Return the native instance label of the sole live V3 generation in this
|
|
154
180
|
* coord root, or null if there are zero or more than one.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coord-client.d.ts","sourceRoot":"","sources":["../../../src/core/agents/coord-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAWhE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAI5E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOhF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CA+B7E;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7D;AAeD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGtD;AAiED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,mFAAmF;AACnF,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAExE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2CxD;AAgCD
|
|
1
|
+
{"version":3,"file":"coord-client.d.ts","sourceRoot":"","sources":["../../../src/core/agents/coord-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAWhE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAI5E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOhF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CA+B7E;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7D;AAeD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGtD;AAiED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,mFAAmF;AACnF,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAExE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2CxD;AAgCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI;IACxC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,iBAAiB,GAAG,aAAa,GAAG,kBAAkB,GAAG,MAAM,CAAC;CAC5F,CAsEA;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAsB5C;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG;IAClD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,QAAQ,GAAG,iBAAiB,GAAG,MAAM,CAAC;CAC/C,CAyBA;AAqBD,sFAAsF;AACtF;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAEtD;AAuCD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAmB9C;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOpE"}
|
|
@@ -339,9 +339,10 @@ function readPidmapRow(pidmapDir, pid) {
|
|
|
339
339
|
* Prefer a row whose platform matches `HARNERY_AGENT_COORD_PLATFORM` (default
|
|
340
340
|
* `claude-code`); otherwise return the first owner seen on the walk.
|
|
341
341
|
*
|
|
342
|
-
* Subagents intentionally do not write pid-map entries; a Bash-tool
|
|
343
|
-
* from inside
|
|
344
|
-
*
|
|
342
|
+
* Subagents intentionally do not write pid-map entries; a bare Bash-tool
|
|
343
|
+
* ppid-walk from inside an unbridged child therefore resolves to the parent's
|
|
344
|
+
* pid-map entry. Native hook bridges supersede this fallback through the
|
|
345
|
+
* child session environment.
|
|
345
346
|
*/
|
|
346
347
|
export function resolveOwner() {
|
|
347
348
|
return resolveOwnerWithSource().owner;
|
|
@@ -368,9 +369,34 @@ export function resolveOwnerWithSource() {
|
|
|
368
369
|
// Every supported adapter exports its native session id into subprocesses.
|
|
369
370
|
// Match it against the live V3 producer state, never a disposable cache.
|
|
370
371
|
if (shouldPreferSessionEnv()) {
|
|
371
|
-
const bySession =
|
|
372
|
+
const bySession = resolveOwnerBySessionEnvDetailed(root);
|
|
372
373
|
if (bySession) {
|
|
373
|
-
|
|
374
|
+
// Env vars cross process boundaries that session identity does not: a
|
|
375
|
+
// nested different-adapter child inherits its spawner's exported id (a
|
|
376
|
+
// Codex session's CODEX_THREAD_ID survives into a `claude -p` child's
|
|
377
|
+
// shells untouched), and that stale statement joins the spawner's live
|
|
378
|
+
// producer. The nearest token-verified pid-map anchor names the session
|
|
379
|
+
// whose tool environment this process actually runs in, so on a
|
|
380
|
+
// CROSS-adapter conflict the anchor wins — the anchoring adapter never
|
|
381
|
+
// stamps another adapter's variable, so a foreign-adapter id here is
|
|
382
|
+
// inherited context, while the anchor row is re-healed on every tool
|
|
383
|
+
// call. A SAME-adapter conflict keeps the env: the adapter stamps its
|
|
384
|
+
// own variable fresh per tool call, and the row may lag one heal (e.g.
|
|
385
|
+
// a session id change inside one process). Only per-session-process
|
|
386
|
+
// adapters may anchor (claude-code, codex) — Cursor sessions share one
|
|
387
|
+
// terminal process, so a verified Cursor row can belong to a sibling
|
|
388
|
+
// session. Unverified rows keep losing to the env too: without a start
|
|
389
|
+
// token the row is the guess the env ordering was introduced to beat.
|
|
390
|
+
// Never for bridge-marked children: a connector crosses a process-tree
|
|
391
|
+
// boundary, so an anchor in THIS tree is someone else's by definition.
|
|
392
|
+
const anchor = bridge ? null : nearestVerifiedSessionAnchor(root);
|
|
393
|
+
if (anchor &&
|
|
394
|
+
anchor.owner !== bySession.owner &&
|
|
395
|
+
!bySession.adapters.includes(anchor.platform) &&
|
|
396
|
+
(anchor.platform === "claude-code" || anchor.platform === "codex")) {
|
|
397
|
+
return { owner: anchor.owner, source: "pidmap" };
|
|
398
|
+
}
|
|
399
|
+
return { owner: bySession.owner, source: "session_env" };
|
|
374
400
|
}
|
|
375
401
|
}
|
|
376
402
|
// Connector children cross process-tree boundaries where pid ancestry is
|
|
@@ -394,6 +420,42 @@ export function resolveOwnerWithSource() {
|
|
|
394
420
|
}
|
|
395
421
|
return { owner: null, source: "none" };
|
|
396
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* The nearest pid-map anchor on our own ppid chain whose start token PROVES the
|
|
425
|
+
* row still describes the process holding that pid, or null when the nearest
|
|
426
|
+
* row is unverified, recycled, or absent.
|
|
427
|
+
*
|
|
428
|
+
* Nearest matters: in a nested-agent tree (session A spawns a headless session
|
|
429
|
+
* B whose shell runs this code), both A's and B's adapter processes are
|
|
430
|
+
* ancestors, and only the innermost one owns this process's tool environment.
|
|
431
|
+
* Exported for unit testing with an injectable root.
|
|
432
|
+
*/
|
|
433
|
+
export function nearestVerifiedSessionAnchor(root) {
|
|
434
|
+
const pidmapDir = resolve(root, ".harnery", "pid-map");
|
|
435
|
+
if (!existsSync(pidmapDir))
|
|
436
|
+
return null;
|
|
437
|
+
let pid = process.pid;
|
|
438
|
+
for (let hop = 0; hop < 20; hop++) {
|
|
439
|
+
if (pid === null)
|
|
440
|
+
break;
|
|
441
|
+
const row = readPidmapRow(pidmapDir, pid);
|
|
442
|
+
if (row) {
|
|
443
|
+
const owner = parsePidmapRowOwner(row);
|
|
444
|
+
if (owner && !pidWasRecycled(pid, row)) {
|
|
445
|
+
// A recycled row is about a dead process's tenure of this pid — walk
|
|
446
|
+
// past it like the owner walk does. A live row without a provable
|
|
447
|
+
// token match is the nearest anchor but not a VERIFIED one: stop and
|
|
448
|
+
// report none, so the session env keeps outranking guesses.
|
|
449
|
+
const token = parsePidmapRowStartToken(row);
|
|
450
|
+
if (!token || !pidStartToken(pid))
|
|
451
|
+
return null;
|
|
452
|
+
return { owner, platform: parsePidmapRowPlatform(row) };
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
pid = readPpid(pid);
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
397
459
|
/**
|
|
398
460
|
* Walk our own ppid chain for a pid-map row in ONE given root.
|
|
399
461
|
*
|
|
@@ -501,19 +563,36 @@ function shouldPreferSessionEnv() {
|
|
|
501
563
|
* Exported for unit testing with an injectable root.
|
|
502
564
|
*/
|
|
503
565
|
export function resolveOwnerBySessionEnv(root) {
|
|
566
|
+
return resolveOwnerBySessionEnvDetailed(root)?.owner ?? null;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* `resolveOwnerBySessionEnv` plus WHICH adapter's producer state the session id
|
|
570
|
+
* joined. The caller uses the adapter to tell a same-adapter conflict (the env
|
|
571
|
+
* var is stamped fresh per tool call and outranks a possibly-lagging pid-map
|
|
572
|
+
* row) from a cross-adapter one (the var is inherited context from an outer
|
|
573
|
+
* session and the verified row wins).
|
|
574
|
+
*/
|
|
575
|
+
export function resolveOwnerBySessionEnvDetailed(root) {
|
|
504
576
|
const sessionIds = sessionIdsFromEnv();
|
|
505
577
|
if (sessionIds.length === 0)
|
|
506
578
|
return null;
|
|
507
579
|
const adapters = adapterCandidatesFromEnv();
|
|
508
|
-
const matches = new
|
|
580
|
+
const matches = new Map();
|
|
509
581
|
for (const sessionId of sessionIds) {
|
|
510
582
|
for (const adapter of adapters) {
|
|
511
583
|
const state = readHookProducerStateV3(root, adapter, sessionId);
|
|
512
|
-
if (state && !state.terminal)
|
|
513
|
-
|
|
584
|
+
if (state && !state.terminal) {
|
|
585
|
+
const owner = nativeOwnerForV3Instance(root, state.instance_id);
|
|
586
|
+
const set = matches.get(owner) ?? new Set();
|
|
587
|
+
set.add(adapter);
|
|
588
|
+
matches.set(owner, set);
|
|
589
|
+
}
|
|
514
590
|
}
|
|
515
591
|
}
|
|
516
|
-
|
|
592
|
+
if (matches.size !== 1)
|
|
593
|
+
return null;
|
|
594
|
+
const [owner, adapterSet] = [...matches.entries()][0];
|
|
595
|
+
return { owner, adapters: [...adapterSet] };
|
|
517
596
|
}
|
|
518
597
|
/**
|
|
519
598
|
* Return the native instance label of the sole live V3 generation in this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-authority-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-authority-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAehE,OAAO,EACL,KAAK,mCAAmC,EAEzC,MAAM,iDAAiD,CAAC;
|
|
1
|
+
{"version":3,"file":"live-authority-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-authority-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAehE,OAAO,EACL,KAAK,mCAAmC,EAEzC,MAAM,iDAAiD,CAAC;AAqBzD,eAAO,MAAM,gCAAgC,EAAG,iBAA0B,CAAC;AAE3E,qBAAa,gCAAiC,SAAQ,KAAK;aAC7B,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAI3C;AAED,MAAM,MAAM,iCAAiC,GACzC;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GACtB;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,mCAAmC,CAAA;CAAE,CAAC;AAEvE,MAAM,WAAW,oCAAoC;IACnD,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,OAAO,MAAM,EAAE,CAAC;IACrC,aAAa,EAAE,OAAO,MAAM,EAAE,CAAC;CAChC;AAED,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,KAAK,EAAE;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,oCAAoC,CAkDvC;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,mBAAmB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5C,iCAAiC,CAiCnC;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,mBAAmB,GAAG;IAC3B,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACA,iCAAiC,CAmCnC;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,mBAAmB,GAAG;IAC3B,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B,GACA,iCAAiC,CAuCnC;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,mBAAmB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChE,iCAAiC,CAuBnC;AAuDD,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAI/E"}
|
|
@@ -4,6 +4,7 @@ import { readCoordinationViewV3, requireAuthoritySafeCoordinationViewV3, } from
|
|
|
4
4
|
import { LIVE_HOOK_V3_PRODUCER_ID, liveInstanceIdV3, livePlatformV3, resolveLiveEventLedgerRouteV3, } from "../events/v3/live-routing.js";
|
|
5
5
|
import { recordCoordinationAuthorityV3, } from "../events/v3/producers/coordination-recorder.js";
|
|
6
6
|
import { readTerminalHookProducerStateV3, recordHookSignalV3, } from "../events/v3/producers/recorder.js";
|
|
7
|
+
import { canonicalClaimPath } from "./claim-path.js";
|
|
7
8
|
import { acquireClaim, readHeartbeat, releaseClaim, setIdentityCache, setLifecycleCache, setTask, } from "./state/heartbeat-writer.js";
|
|
8
9
|
import { ensureLiveCoordinationHeartbeat, liveCoordinationAdapterV3, } from "./state/live-coordination-view.js";
|
|
9
10
|
import { recordNameAssumption } from "./state/names.js";
|
|
@@ -228,6 +229,3 @@ function authorityStateDigest(heartbeat) {
|
|
|
228
229
|
display_name: heartbeat.name ?? null,
|
|
229
230
|
}));
|
|
230
231
|
}
|
|
231
|
-
function canonicalClaimPath(coordRoot, path) {
|
|
232
|
-
return path.startsWith(`${coordRoot}/`) ? path.slice(coordRoot.length + 1) : path;
|
|
233
|
-
}
|
|
@@ -4,7 +4,7 @@ import { normalizeNativeIdV3 } from "../events/v3/canonical.js";
|
|
|
4
4
|
import { readEventV3ControlState } from "../events/v3/control.js";
|
|
5
5
|
import { fingerprintContextV3 } from "../events/v3/fingerprint-keys.js";
|
|
6
6
|
import { liveInstanceIdV3, livePlatformV3, resolveLiveEventLedgerRouteV3, } from "../events/v3/live-routing.js";
|
|
7
|
-
import {
|
|
7
|
+
import { readJoinableHookProducerStateV3 } from "../events/v3/producers/recorder.js";
|
|
8
8
|
import { writeEventV3 } from "../events/v3/writer.js";
|
|
9
9
|
import { LiveCoordinationAuthorityV3Error } from "./live-authority-v3.js";
|
|
10
10
|
import { liveCoordinationAdapterV3 } from "./state/live-coordination-view.js";
|
|
@@ -83,8 +83,8 @@ function withAttestedAdapter(input) {
|
|
|
83
83
|
return { ...input, adapter };
|
|
84
84
|
}
|
|
85
85
|
function requireHookState(input) {
|
|
86
|
-
const hook =
|
|
87
|
-
if (!hook
|
|
86
|
+
const hook = readJoinableHookProducerStateV3(input.coordRoot, input.adapter, input.nativeSessionId, liveInstanceIdV3(input.owner));
|
|
87
|
+
if (!hook) {
|
|
88
88
|
throw new LiveCoordinationAuthorityV3Error("hook_generation_not_joinable");
|
|
89
89
|
}
|
|
90
90
|
return hook;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-observation-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-observation-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAQ7C,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAIrE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAWtF,YAAY,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAEtF,MAAM,WAAW,wCAAwC;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,6BAA6B,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yCAAyC;IACxD,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,wCAAwC,GAC9C,yCAAyC,
|
|
1
|
+
{"version":3,"file":"live-observation-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-observation-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAQ7C,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAIrE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAWtF,YAAY,EAAE,6BAA6B,EAAE,MAAM,kCAAkC,CAAC;AAEtF,MAAM,WAAW,wCAAwC;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,6BAA6B,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yCAAyC;IACxD,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,wCAAwC,GAC9C,yCAAyC,CAuJ3C;AAkBD,MAAM,MAAM,sCAAsC,GAAG,OAAO,CAC1D,WAAW,EACX,6BAA6B,CAAC,YAAY,CAAC,CAC5C,CAAC"}
|
|
@@ -5,7 +5,7 @@ import { readEventV3ControlState } from "../events/v3/control.js";
|
|
|
5
5
|
import { readCoordinationViewV3 } from "../events/v3/coordination-view.js";
|
|
6
6
|
import { fingerprintContextV3 } from "../events/v3/fingerprint-keys.js";
|
|
7
7
|
import { liveInstanceIdV3, livePlatformV3, resolveLiveEventLedgerRouteV3, } from "../events/v3/live-routing.js";
|
|
8
|
-
import {
|
|
8
|
+
import { readJoinableHookProducerStateV3 } from "../events/v3/producers/recorder.js";
|
|
9
9
|
import { writeEventV3 } from "../events/v3/writer.js";
|
|
10
10
|
import { LiveCoordinationAuthorityV3Error } from "./live-authority-v3.js";
|
|
11
11
|
import { liveCoordinationAdapterV3 } from "./state/live-coordination-view.js";
|
|
@@ -23,7 +23,7 @@ export function recordLiveCoordinationObservationV3(input) {
|
|
|
23
23
|
throw new LiveCoordinationAuthorityV3Error("control_state_changed");
|
|
24
24
|
}
|
|
25
25
|
const adapter = liveCoordinationAdapterV3(input.coordRoot, input.owner) ?? input.adapter;
|
|
26
|
-
const hook =
|
|
26
|
+
const hook = readJoinableHookProducerStateV3(input.coordRoot, adapter, input.nativeSessionId, liveInstanceIdV3(input.owner));
|
|
27
27
|
if (!hook ||
|
|
28
28
|
hook.terminal ||
|
|
29
29
|
!hook.last_event_id ||
|
|
@@ -140,7 +140,7 @@ function computeFocusNudgeIfChanged(coordRoot, selfInstanceId, opts) {
|
|
|
140
140
|
// Keyed on "a name was ever produced", not task_updated_at: a bare clear
|
|
141
141
|
// as the first declaration must not end the naming window.
|
|
142
142
|
needsNudge = true;
|
|
143
|
-
nudgeKind = "session-name";
|
|
143
|
+
nudgeKind = pendingSessionName ? "session-name-pending" : "session-name-unminted";
|
|
144
144
|
message = pendingSessionName
|
|
145
145
|
? `This session name is still pending display. Before any prose or another tool call, send this exact block as your next assistant text:\n\n${sessionNameDisplayBlock(pendingSessionName)}`
|
|
146
146
|
: `This session has no name yet: run \`${bin} agents set-task "<2-5 word session topic>"\` as your first tool call. ` +
|
|
@@ -170,18 +170,20 @@ function computeFocusNudgeIfChanged(coordRoot, selfInstanceId, opts) {
|
|
|
170
170
|
clearHashFile(hashFile);
|
|
171
171
|
return "";
|
|
172
172
|
}
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
// is
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
if (nudgeKind === "session-name") {
|
|
173
|
+
// An unminted session still gets a fresh reminder on every prompt until its
|
|
174
|
+
// first focus declaration. Once a name exists, the exact pending-name prompt
|
|
175
|
+
// is delivered once per minted value. Repeating it on every prompt creates
|
|
176
|
+
// an unbounded loop on adapters that cannot verify assistant reply text.
|
|
177
|
+
if (nudgeKind === "session-name-unminted") {
|
|
179
178
|
clearHashFile(hashFile);
|
|
180
179
|
return message;
|
|
181
180
|
}
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
|
|
181
|
+
// A pending reminder is keyed only to the minted name: changing the task
|
|
182
|
+
// must not reconstruct or re-request that older title. Task reminders retain
|
|
183
|
+
// their own task-state key.
|
|
184
|
+
const state = nudgeKind === "session-name-pending"
|
|
185
|
+
? `${nudgeKind}|name=${pendingSessionName ?? ""}`
|
|
186
|
+
: `${nudgeKind}|task=${taskValue}|updated=${hb.task_updated_at ?? ""}|threshold=${threshold}`;
|
|
185
187
|
const newHash = sha256Hex16(state);
|
|
186
188
|
const oldHash = safeRead(hashFile);
|
|
187
189
|
if (oldHash && oldHash === newHash)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop-hook.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/rules/stop-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAM3D,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAInE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,aAAa,CA6BvF;AAED,oFAAoF;AACpF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,OAAO,EAAE,GACzB,aAAa,
|
|
1
|
+
{"version":3,"file":"stop-hook.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/rules/stop-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAM3D,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAInE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,aAAa,CA6BvF;AAED,oFAAoF;AACpF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,OAAO,EAAE,GACzB,aAAa,CA6Gf"}
|