harnery 0.42.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/commander.d.ts +16 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +18 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +95 -52
- 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/tunnel.d.ts +65 -0
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +290 -101
- package/dist/commands/web-fetch.d.ts +3 -2
- package/dist/commands/web-fetch.d.ts.map +1 -1
- package/dist/commands/web-fetch.js +25 -19
- package/dist/commands/web.d.ts +7 -1
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +9 -3
- 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 +19 -17
- 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 +64 -43
- 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/names.d.ts +43 -3
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +87 -3
- 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/events/v3/support-storage/pack-reader.d.ts.map +1 -1
- package/dist/core/events/v3/support-storage/pack-reader.js +42 -16
- 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 +120 -23
- package/dist/core/hooks/fork-lineage.d.ts +40 -0
- package/dist/core/hooks/fork-lineage.d.ts.map +1 -0
- package/dist/core/hooks/fork-lineage.js +62 -0
- package/dist/core/hooks/resolve/transcript.d.ts +16 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +84 -0
- package/dist/core/hooks/shell-rm.d.ts +2 -0
- package/dist/core/hooks/shell-rm.d.ts.map +1 -0
- package/dist/core/hooks/shell-rm.js +105 -0
- package/dist/core/hooks/shell-tokens.d.ts +12 -0
- package/dist/core/hooks/shell-tokens.d.ts.map +1 -0
- package/dist/core/hooks/shell-tokens.js +97 -0
- package/dist/core/hooks/shell-waiter.d.ts.map +1 -1
- package/dist/core/hooks/shell-waiter.js +3 -93
- 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/semantic/contract.d.ts +5 -5
- 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/storage/process-log.d.ts +12 -0
- package/dist/core/storage/process-log.d.ts.map +1 -1
- package/dist/core/storage/process-log.js +10 -2
- 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/tunnel/allowlist.d.ts +44 -0
- package/dist/lib/tunnel/allowlist.d.ts.map +1 -0
- package/dist/lib/tunnel/allowlist.js +204 -0
- package/dist/lib/tunnel/current-address.d.ts +41 -0
- package/dist/lib/tunnel/current-address.d.ts.map +1 -0
- package/dist/lib/tunnel/current-address.js +123 -0
- package/dist/lib/tunnel/gate.js +13 -6
- package/dist/lib/tunnel/processes.d.ts +39 -0
- package/dist/lib/tunnel/processes.d.ts.map +1 -0
- package/dist/lib/tunnel/processes.js +121 -0
- package/dist/lib/tunnel/state.d.ts +28 -3
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +98 -27
- 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 +8 -1
- package/src/commander.ts +32 -0
- package/src/commands/agents.ts +151 -74
- 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/tunnel.ts +394 -116
- package/src/commands/web-fetch.ts +30 -19
- package/src/commands/web.ts +9 -3
- 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 +35 -20
- package/src/core/agents/render/session-context.ts +92 -48
- 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/names.ts +117 -6
- 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/events/v3/support-storage/pack-reader.ts +45 -19
- 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 +139 -22
- package/src/core/hooks/fork-lineage.ts +82 -0
- package/src/core/hooks/resolve/transcript.ts +88 -0
- package/src/core/hooks/shell-rm.ts +103 -0
- package/src/core/hooks/shell-tokens.ts +96 -0
- package/src/core/hooks/shell-waiter.ts +4 -91
- 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/storage/process-log.ts +17 -2
- 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/tunnel/allowlist.ts +208 -0
- package/src/lib/tunnel/current-address.ts +158 -0
- package/src/lib/tunnel/gate.ts +16 -8
- package/src/lib/tunnel/processes.ts +149 -0
- package/src/lib/tunnel/state.ts +123 -27
- package/src/lib/zip/index.ts +483 -0
|
@@ -14,9 +14,11 @@ import { fileURLToPath } from "node:url";
|
|
|
14
14
|
* harnery repo at the *matching version tag* into a cache dir and install the
|
|
15
15
|
* web app's deps. Subsequent runs reuse the cache.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* `web/` imports readers from `src/`, and `web/next.config.ts` resolves the
|
|
18
|
+
* root `playwright` package, so the install covers the repository root and
|
|
19
|
+
* then `web/`. Installing the `playwright` package downloads no browsers.
|
|
20
|
+
* Installing `web/` alone left `harn web up` failing with
|
|
21
|
+
* `Cannot find module 'playwright/package.json'`.
|
|
20
22
|
*/
|
|
21
23
|
const DEFAULT_REPO_URL = "https://github.com/ryanjkelly/harnery.git";
|
|
22
24
|
/** harnery's own package root: src/commands/ -> ../.. ; valid in both src/ and dist/. */
|
|
@@ -46,8 +48,8 @@ function webCacheRoot(ref) {
|
|
|
46
48
|
return path.join(base, "harnery", "web", safeRef);
|
|
47
49
|
}
|
|
48
50
|
/** bun if available (preferred), else npm. Both support `<runner> install` and `<runner> run <script>`. */
|
|
49
|
-
export function webRunner() {
|
|
50
|
-
const r =
|
|
51
|
+
export function webRunner(spawn = spawnSync) {
|
|
52
|
+
const r = spawn("bun", ["--version"], { stdio: "ignore" });
|
|
51
53
|
return r.status === 0 ? "bun" : "npm";
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
@@ -55,13 +57,14 @@ export function webRunner() {
|
|
|
55
57
|
* its path, fetching (clone + install) on first use. Returns null on failure
|
|
56
58
|
* (after emitting an actionable error).
|
|
57
59
|
*/
|
|
58
|
-
export function lazyFetchWebRoot(emit) {
|
|
60
|
+
export function lazyFetchWebRoot(emit, spawn = spawnSync) {
|
|
59
61
|
const { version, repoUrl } = readPkg();
|
|
60
62
|
const ref = resolveRef(version);
|
|
61
63
|
const cacheRoot = webCacheRoot(ref);
|
|
62
64
|
const webDir = path.join(cacheRoot, "web");
|
|
63
|
-
// node_modules in the cached web/ is the "fetched + installed" marker.
|
|
64
|
-
if (existsSync(path.join(
|
|
65
|
+
// node_modules in both the cached root and web/ is the "fetched + installed" marker.
|
|
66
|
+
if (existsSync(path.join(cacheRoot, "node_modules")) &&
|
|
67
|
+
existsSync(path.join(webDir, "node_modules"))) {
|
|
65
68
|
emit.log(`harn web · using cached dashboard (${ref})`, "info");
|
|
66
69
|
return webDir;
|
|
67
70
|
}
|
|
@@ -71,7 +74,7 @@ export function lazyFetchWebRoot(emit) {
|
|
|
71
74
|
if (existsSync(cacheRoot))
|
|
72
75
|
rmSync(cacheRoot, { recursive: true, force: true });
|
|
73
76
|
mkdirSync(path.dirname(cacheRoot), { recursive: true });
|
|
74
|
-
const clone =
|
|
77
|
+
const clone = spawn("git", ["clone", "--depth", "1", "--branch", ref, repoUrl, cacheRoot], {
|
|
75
78
|
stdio: "inherit",
|
|
76
79
|
});
|
|
77
80
|
if (clone.status !== 0) {
|
|
@@ -84,16 +87,19 @@ export function lazyFetchWebRoot(emit) {
|
|
|
84
87
|
});
|
|
85
88
|
return null;
|
|
86
89
|
}
|
|
87
|
-
const runner = webRunner();
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
const runner = webRunner(spawn);
|
|
91
|
+
for (const dir of [cacheRoot, webDir]) {
|
|
92
|
+
const where = dir === webDir ? "web/" : "the harnery root";
|
|
93
|
+
emit.log(`harn web · installing dashboard deps (${runner} install in ${where})`, "info");
|
|
94
|
+
const install = spawn(runner, ["install"], { cwd: dir, stdio: "inherit" });
|
|
95
|
+
if (install.status !== 0) {
|
|
96
|
+
emit.error({
|
|
97
|
+
code: "web_fetch_failed",
|
|
98
|
+
message: `${runner} install in ${dir} failed (status ${install.status})`,
|
|
99
|
+
hint: `Try manually: cd ${dir} && ${runner} install`,
|
|
100
|
+
});
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
97
103
|
}
|
|
98
104
|
emit.log(`harn web · dashboard ready (cached at ${webDir})`, "info");
|
|
99
105
|
return webDir;
|
package/dist/commands/web.d.ts
CHANGED
|
@@ -19,7 +19,13 @@ export declare function resolveMaxOldSpaceMb(flag?: string): number;
|
|
|
19
19
|
* wins without clobbering flags the caller set (source maps, inspector, …).
|
|
20
20
|
*/
|
|
21
21
|
export declare function nodeOptionsWithHeapCap(mb: number): string | undefined;
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Preload the dashboard's server hooks (keep-alive and request diagnostics)
|
|
24
|
+
* without replacing Next's HTTP server. NODE_OPTIONS reaches the child that
|
|
25
|
+
* `next dev` forks, but Next re-parses every `--import` into one value, so
|
|
26
|
+
* this names the single combined preload; a second, different `--import`
|
|
27
|
+
* would collapse into an unloadable path (web/server-preload.mjs).
|
|
28
|
+
*/
|
|
23
29
|
export declare function nodeOptionsWithWebDiagnostics(webDir: string, mb: number): string;
|
|
24
30
|
export declare function webPerformanceLogDestination(coordRoot: string, env?: Readonly<Record<string, string | undefined>>): string;
|
|
25
31
|
/**
|
|
@@ -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;AA8CnD;;;;;;;;;;;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;AAED
|
|
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;AA8CnD;;;;;;;;;;;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;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC9D,MAAM,CAQR;AAmDD;;;;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,CA2N5E"}
|
package/dist/commands/web.js
CHANGED
|
@@ -71,12 +71,18 @@ export function nodeOptionsWithHeapCap(mb) {
|
|
|
71
71
|
return inherited;
|
|
72
72
|
return `${inherited} --max-old-space-size=${mb}`.trim();
|
|
73
73
|
}
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Preload the dashboard's server hooks (keep-alive and request diagnostics)
|
|
76
|
+
* without replacing Next's HTTP server. NODE_OPTIONS reaches the child that
|
|
77
|
+
* `next dev` forks, but Next re-parses every `--import` into one value, so
|
|
78
|
+
* this names the single combined preload; a second, different `--import`
|
|
79
|
+
* would collapse into an unloadable path (web/server-preload.mjs).
|
|
80
|
+
*/
|
|
75
81
|
export function nodeOptionsWithWebDiagnostics(webDir, mb) {
|
|
76
82
|
const inherited = nodeOptionsWithHeapCap(mb) ?? "";
|
|
77
|
-
if (inherited.includes("server-
|
|
83
|
+
if (inherited.includes("server-preload.mjs"))
|
|
78
84
|
return inherited;
|
|
79
|
-
const preload = pathToFileURL(path.join(webDir, "server-
|
|
85
|
+
const preload = pathToFileURL(path.join(webDir, "server-preload.mjs")).href;
|
|
80
86
|
return `${inherited} --import=${preload}`.trim();
|
|
81
87
|
}
|
|
82
88
|
export function webPerformanceLogDestination(coordRoot, env = process.env) {
|
|
@@ -472,10 +472,10 @@ export function registerWorkflowCommand(program, emit) {
|
|
|
472
472
|
});
|
|
473
473
|
workflow
|
|
474
474
|
.command("reclaim <run-id>")
|
|
475
|
-
.description("
|
|
475
|
+
.description("Preview reclaim of an inactive owned workspace, or confirm salvage or discard and release.")
|
|
476
476
|
.option("--yes", "Confirm that this commits or discards uncommitted work, then releases")
|
|
477
477
|
.option("--discard", "Throw the uncommitted work away instead of salvaging it")
|
|
478
|
-
.option("--json", "Emit the reclaim
|
|
478
|
+
.option("--json", "Emit the reclaim preview or confirmed result as JSON")
|
|
479
479
|
.action(async (runId, opts) => {
|
|
480
480
|
const coordRoot = resolveCoordRoot();
|
|
481
481
|
if (!coordRoot) {
|
|
@@ -485,50 +485,44 @@ export function registerWorkflowCommand(program, emit) {
|
|
|
485
485
|
});
|
|
486
486
|
process.exit(1);
|
|
487
487
|
}
|
|
488
|
-
if (!opts.yes) {
|
|
489
|
-
emit.error({
|
|
490
|
-
code: "reclaim_confirmation_required",
|
|
491
|
-
message: opts.discard
|
|
492
|
-
? "reclaim --discard permanently destroys uncommitted work; pass --yes to confirm"
|
|
493
|
-
: "workspace reclaim commits uncommitted work to its branch and then releases the worktree; pass --yes to confirm",
|
|
494
|
-
});
|
|
495
|
-
process.exit(1);
|
|
496
|
-
}
|
|
497
488
|
try {
|
|
498
|
-
const {
|
|
499
|
-
const
|
|
500
|
-
if (
|
|
501
|
-
emit.error({ code: "workflow_reclaim_failed", message: inspection.error });
|
|
502
|
-
process.exit(1);
|
|
503
|
-
}
|
|
504
|
-
const allocation = inspection.value.allocation;
|
|
505
|
-
if (!allocation) {
|
|
489
|
+
const { createLocalGitWorktreeProvider, readWorkflowRunManifest } = await import("../core/workflow/index.js");
|
|
490
|
+
const binding = readWorkflowRunManifest(coordRoot, runId).execution.workspace_binding;
|
|
491
|
+
if (binding?.provider.id !== "local-git-worktree") {
|
|
506
492
|
emit.error({
|
|
507
493
|
code: "workflow_reclaim_unavailable",
|
|
508
494
|
message: `run ${runId} has no provider-owned Git workspace to reclaim`,
|
|
509
495
|
});
|
|
510
496
|
process.exit(1);
|
|
511
497
|
}
|
|
512
|
-
const
|
|
513
|
-
|
|
498
|
+
const provider = createLocalGitWorktreeProvider({ coordRoot });
|
|
499
|
+
const result = await provider.reclaim(binding, {
|
|
514
500
|
mode: opts.discard ? "discard" : "salvage",
|
|
515
|
-
|
|
501
|
+
yes: opts.yes,
|
|
516
502
|
});
|
|
517
|
-
// Cleanup still owns removal. Reclaim only changes whether the tree it
|
|
518
|
-
// finds is dirty, so there is one audited release path, not two.
|
|
519
|
-
const provider = await builtInProviderForRun(coordRoot, runId);
|
|
520
|
-
const cleanup = await cleanupWorkspace({ coordRoot, runId, provider });
|
|
521
503
|
if (opts.json) {
|
|
522
504
|
emit.config({ format: "json" });
|
|
523
|
-
emit.data(
|
|
505
|
+
emit.data(result);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (result.action === "preview") {
|
|
509
|
+
const holders = result.lease_holder.map((holder) => `${holder.scope}: ${holder.owner_id ?? "unknown"}${holder.pid ? ` (pid ${holder.pid})` : ""}${holder.detail ? `; ${holder.detail}` : ""}`);
|
|
510
|
+
emit.text(`reclaim preview: ${result.run_id}\n` +
|
|
511
|
+
`mode: ${result.mode}\nliveness: ${result.liveness}\nownership: ${result.ownership}\n` +
|
|
512
|
+
`lease holder: ${holders.length > 0 ? holders.join(", ") : "none observed"}\n` +
|
|
513
|
+
`dirty paths: ${result.dirty_paths === null ? "unknown" : result.dirty_paths.length > 0 ? result.dirty_paths.join(", ") : "none"}\n` +
|
|
514
|
+
(result.ownership_detail ? `ownership detail: ${result.ownership_detail}\n` : "") +
|
|
515
|
+
`Pass --yes to confirm ${result.mode} and release after all checks pass.\n`);
|
|
524
516
|
return;
|
|
525
517
|
}
|
|
526
|
-
emit.text(`reclaim ${preparation.action}: ${preparation.detail}\n` +
|
|
527
|
-
`workspace cleanup ${cleanup.status}: ${cleanup.binding_id}\n`);
|
|
518
|
+
emit.text(`reclaim ${result.preparation.action}: ${result.preparation.detail}\n` +
|
|
519
|
+
`workspace cleanup ${result.cleanup.status}: ${result.cleanup.binding_id}\n`);
|
|
528
520
|
}
|
|
529
521
|
catch (error) {
|
|
530
522
|
emit.error({
|
|
531
|
-
code: "
|
|
523
|
+
code: error instanceof Error && "code" in error && typeof error.code === "string"
|
|
524
|
+
? error.code
|
|
525
|
+
: "workflow_reclaim_failed",
|
|
532
526
|
message: error instanceof Error ? error.message : String(error),
|
|
533
527
|
});
|
|
534
528
|
process.exit(1);
|
|
@@ -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;AAI7C,OAAO,EAAE,KAAK,gBAAgB,EAA2B,MAAM,yBAAyB,CAAC;AAgBzF,OAAO,EACL,KAAK,mCAAmC,EAEzC,MAAM,iDAAiD,CAAC;AASzD,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,6BAA6B,CAAC;AAQrC,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,MAAM,WAAW,uCAAuC;IACtD,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,+BAA+B;IAC9C,KAAK,EAAE,WAAW,GAAG,UAAU,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB;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;
|
|
1
|
+
{"version":3,"file":"live-authority-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-authority-v3.ts"],"names":[],"mappings":"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"}
|
|
@@ -419,6 +419,10 @@ function recordLiveAuthority(input, signal, observation, expected, desired, appl
|
|
|
419
419
|
platform: livePlatformV3(),
|
|
420
420
|
expected_prior_state_digest: coordinationAuthorityStateDigestV3(expected),
|
|
421
421
|
desired_state_digest: coordinationAuthorityStateDigestV3(desired),
|
|
422
|
+
expected_generation_id: input.expectedGenerationId ??
|
|
423
|
+
(subject === input.owner
|
|
424
|
+
? expected.v3_generation_id
|
|
425
|
+
: readLiveCoordinationRow(input.coordRoot, input.owner)?.v3_generation_id),
|
|
422
426
|
reconciler: {
|
|
423
427
|
readStateDigest: () => {
|
|
424
428
|
const heartbeat = readHeartbeat(input.coordRoot, subject);
|
|
@@ -448,9 +452,16 @@ export function liveCoordinationWriteModeV3(coordRoot) {
|
|
|
448
452
|
return route.mode;
|
|
449
453
|
}
|
|
450
454
|
function requireHeartbeat(input, owner) {
|
|
455
|
+
if (input.expectedGenerationId &&
|
|
456
|
+
readLiveCoordinationRow(input.coordRoot, owner)?.v3_generation_id !== input.expectedGenerationId) {
|
|
457
|
+
throw new LiveCoordinationAuthorityV3Error("expected_generation_changed");
|
|
458
|
+
}
|
|
451
459
|
const heartbeat = ensureLiveCoordinationHeartbeat(input.coordRoot, owner, owner === input.owner ? input.nativeSessionId : owner, input.adapter);
|
|
452
460
|
if (!heartbeat)
|
|
453
461
|
throw new LiveCoordinationAuthorityV3Error(`heartbeat_missing:${owner}`);
|
|
462
|
+
if (input.expectedGenerationId && heartbeat.v3_generation_id !== input.expectedGenerationId) {
|
|
463
|
+
throw new LiveCoordinationAuthorityV3Error("expected_generation_changed");
|
|
464
|
+
}
|
|
454
465
|
return heartbeat;
|
|
455
466
|
}
|
|
456
467
|
export function coordinationAuthorityStateDigestV3(heartbeat) {
|
|
@@ -11,10 +11,12 @@ interface LiveLifecycleObservationBaseV3 {
|
|
|
11
11
|
adapter: EventAdapterIdV3;
|
|
12
12
|
observedAt?: string;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
interface LiveSweepObservationV3Input extends LiveLifecycleObservationBaseV3 {
|
|
15
|
+
expectedGenerationId: `gen_${string}` | null;
|
|
15
16
|
observation: "stale_heartbeat" | "killed" | "unparseable_heartbeat" | "missing_timestamp";
|
|
16
17
|
ageMs: number;
|
|
17
|
-
}
|
|
18
|
+
}
|
|
19
|
+
export declare function recordLiveSweepObservationV3(input: LiveSweepObservationV3Input): LiveLifecycleObservationV3Result;
|
|
18
20
|
export declare function recordLiveResumeObservationV3(input: LiveLifecycleObservationBaseV3): LiveLifecycleObservationV3Result;
|
|
19
21
|
export {};
|
|
20
22
|
//# sourceMappingURL=live-lifecycle-v3.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-lifecycle-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-lifecycle-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"live-lifecycle-v3.d.ts","sourceRoot":"","sources":["../../../src/core/agents/live-lifecycle-v3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAcxD,MAAM,MAAM,gCAAgC,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAErF,UAAU,8BAA8B;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,2BAA4B,SAAQ,8BAA8B;IAC1E,oBAAoB,EAAE,OAAO,MAAM,EAAE,GAAG,IAAI,CAAC;IAC7C,WAAW,EAAE,iBAAiB,GAAG,QAAQ,GAAG,uBAAuB,GAAG,mBAAmB,CAAC;IAC1F,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,2BAA2B,GACjC,gCAAgC,CAqBlC;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,8BAA8B,GACpC,gCAAgC,CAalC"}
|
|
@@ -3,17 +3,27 @@ import { buildEventV3 } from "../events/v3/builder.js";
|
|
|
3
3
|
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
|
+
import { withGenerationCustodyV3 } from "../events/v3/generation-custody.js";
|
|
6
7
|
import { liveInstanceIdV3, livePlatformV3, resolveLiveEventLedgerRouteV3, } from "../events/v3/live-routing.js";
|
|
7
8
|
import { readJoinableHookProducerStateV3 } from "../events/v3/producers/recorder.js";
|
|
8
9
|
import { writeEventV3 } from "../events/v3/writer.js";
|
|
9
10
|
import { LiveCoordinationAuthorityV3Error } from "./live-authority-v3.js";
|
|
10
11
|
import { liveCoordinationAdapterV3 } from "./state/live-coordination-view.js";
|
|
11
12
|
export function recordLiveSweepObservationV3(input) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
input = { ...input };
|
|
14
|
+
// Reject stale observations before preparing durable custody state. The
|
|
15
|
+
// in-custody checks cover replacement while acquiring custody and reentry.
|
|
16
|
+
requireSweepHookState(input);
|
|
17
|
+
return withGenerationCustodyV3(input.coordRoot, [liveInstanceIdV3(input.owner)], () => {
|
|
18
|
+
requireSweepHookState(input);
|
|
19
|
+
return recordObservation(input, "lifecycle.sweep_observed", {
|
|
20
|
+
subject_instance_id: liveInstanceIdV3(input.owner),
|
|
21
|
+
observation: input.observation,
|
|
22
|
+
provisional: true,
|
|
23
|
+
age_ms: Math.max(0, Math.floor(input.ageMs)),
|
|
24
|
+
}, () => {
|
|
25
|
+
requireSweepHookState(input);
|
|
26
|
+
});
|
|
17
27
|
});
|
|
18
28
|
}
|
|
19
29
|
export function recordLiveResumeObservationV3(input) {
|
|
@@ -23,9 +33,9 @@ export function recordLiveResumeObservationV3(input) {
|
|
|
23
33
|
prior_generation_id: hook.generation_id,
|
|
24
34
|
continuity: "native",
|
|
25
35
|
evidence_reference: "heartbeat_recreated",
|
|
26
|
-
});
|
|
36
|
+
}, () => { });
|
|
27
37
|
}
|
|
28
|
-
function recordObservation(input, eventType, payload) {
|
|
38
|
+
function recordObservation(input, eventType, payload, beforeWrite) {
|
|
29
39
|
const route = resolveLiveEventLedgerRouteV3(input.coordRoot);
|
|
30
40
|
if (route.state === "blocked")
|
|
31
41
|
throw new LiveCoordinationAuthorityV3Error(route.reason);
|
|
@@ -73,6 +83,7 @@ function recordObservation(input, eventType, payload) {
|
|
|
73
83
|
monotonic_ns: process.hrtime.bigint().toString(),
|
|
74
84
|
};
|
|
75
85
|
const event = buildEventV3(eventType, { ...common, payload });
|
|
86
|
+
beforeWrite();
|
|
76
87
|
const durability = writeEventV3(input.coordRoot, event, {
|
|
77
88
|
expectedGenesisId: control.genesis.event.payload.genesis_id,
|
|
78
89
|
});
|
|
@@ -81,6 +92,16 @@ function recordObservation(input, eventType, payload) {
|
|
|
81
92
|
}
|
|
82
93
|
return { state: "recorded", event };
|
|
83
94
|
}
|
|
95
|
+
function requireSweepHookState(input) {
|
|
96
|
+
if (typeof input.expectedGenerationId !== "string" ||
|
|
97
|
+
!/^gen_[a-zA-Z0-9._-]+$/.test(input.expectedGenerationId)) {
|
|
98
|
+
throw new LiveCoordinationAuthorityV3Error("hook_generation_not_joinable");
|
|
99
|
+
}
|
|
100
|
+
const hook = requireHookState(withAttestedAdapter(input));
|
|
101
|
+
if (hook.generation_id !== input.expectedGenerationId) {
|
|
102
|
+
throw new LiveCoordinationAuthorityV3Error("expected_generation_changed");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
84
105
|
function withAttestedAdapter(input) {
|
|
85
106
|
const adapter = liveCoordinationAdapterV3(input.coordRoot, input.owner);
|
|
86
107
|
if (!adapter)
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
* shown to them, because nothing surfaces another session's journal.
|
|
10
10
|
*
|
|
11
11
|
* This module addresses the durable persona name instead of the instance, so a
|
|
12
|
-
* message can be queued before its recipient exists.
|
|
13
|
-
*
|
|
14
|
-
* the
|
|
12
|
+
* message can be queued before its recipient exists. The recipient's next
|
|
13
|
+
* SessionStart or prompt can drain the queue for injection. A drain does not
|
|
14
|
+
* confirm that the adapter emitted the context or that anyone read it.
|
|
15
15
|
*
|
|
16
16
|
* Storage: `.harnery/mailbox/<slug>.jsonl`, one JSON record per line, appended
|
|
17
|
-
* by senders and removed by an atomic claim on the recipient's side.
|
|
18
|
-
* records are appended to `.harnery/mailbox/delivered/<slug>.jsonl` for audit
|
|
17
|
+
* by senders and removed by an atomic claim on the recipient's side. Drained
|
|
18
|
+
* records are appended to `.harnery/mailbox/delivered/<slug>.jsonl` for audit,
|
|
19
|
+
* with injection explicitly unconfirmed.
|
|
19
20
|
*
|
|
20
21
|
* Related but distinct: `core/inbox` is an instance-keyed transport with a
|
|
21
22
|
* storage-framework service behind it. This mailbox is name-keyed, file-only,
|
|
@@ -81,10 +82,10 @@ export declare function peekMailbox(coordRoot: string, name: string): MailboxMes
|
|
|
81
82
|
/**
|
|
82
83
|
* Claim and return every pending message for a name.
|
|
83
84
|
*
|
|
84
|
-
* The claim is an atomic rename, so two sessions sharing a name cannot
|
|
85
|
+
* The claim is an atomic rename, so two sessions sharing a name cannot claim
|
|
85
86
|
* the same message twice: whichever rename wins owns the batch. Claimed records
|
|
86
|
-
* are
|
|
87
|
-
*
|
|
87
|
+
* are archived before the claim file is removed. The archive records only the
|
|
88
|
+
* drain; output, recipient read, and turn completion remain unconfirmed.
|
|
88
89
|
*/
|
|
89
90
|
export declare function drainMailbox(coordRoot: string, name: string): MailboxMessageV1[];
|
|
90
91
|
/** Render a drained batch as the context block a recipient reads. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mailbox.d.ts","sourceRoot":"","sources":["../../../src/core/agents/mailbox.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mailbox.d.ts","sourceRoot":"","sources":["../../../src/core/agents/mailbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAqBH,eAAO,MAAM,sBAAsB,EAAG,4BAAqC,CAAC;AAE5E;mCACmC;AACnC,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,qEAAqE;AACrE,eAAO,MAAM,WAAW,KAAK,CAAC;AAI9B,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,sBAAsB,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb;qEACiE;IACjE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,eAAe,CAAC;AAEnE,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,WAAW,EAAE,qBAAqB;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM;gBAFb,WAAW,EAAE,qBAAqB,EAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM;CAOzB;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGjD;AAYD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnE;AAqBD;;+DAE+D;AAC/D,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAU1E;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE,CAiBjF;AAiBD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CA6BlE;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAa/E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA2DhF;AA8CD,qEAAqE;AACrE,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,MAAM,CAcR"}
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
* shown to them, because nothing surfaces another session's journal.
|
|
10
10
|
*
|
|
11
11
|
* This module addresses the durable persona name instead of the instance, so a
|
|
12
|
-
* message can be queued before its recipient exists.
|
|
13
|
-
*
|
|
14
|
-
* the
|
|
12
|
+
* message can be queued before its recipient exists. The recipient's next
|
|
13
|
+
* SessionStart or prompt can drain the queue for injection. A drain does not
|
|
14
|
+
* confirm that the adapter emitted the context or that anyone read it.
|
|
15
15
|
*
|
|
16
16
|
* Storage: `.harnery/mailbox/<slug>.jsonl`, one JSON record per line, appended
|
|
17
|
-
* by senders and removed by an atomic claim on the recipient's side.
|
|
18
|
-
* records are appended to `.harnery/mailbox/delivered/<slug>.jsonl` for audit
|
|
17
|
+
* by senders and removed by an atomic claim on the recipient's side. Drained
|
|
18
|
+
* records are appended to `.harnery/mailbox/delivered/<slug>.jsonl` for audit,
|
|
19
|
+
* with injection explicitly unconfirmed.
|
|
19
20
|
*
|
|
20
21
|
* Related but distinct: `core/inbox` is an instance-keyed transport with a
|
|
21
22
|
* storage-framework service behind it. This mailbox is name-keyed, file-only,
|
|
@@ -34,8 +35,8 @@ export const MAILBOX_MESSAGE_SCHEMA = "harnery.mailbox-message/v1";
|
|
|
34
35
|
export const MAX_BODY_BYTES = 4000;
|
|
35
36
|
/** Pending messages held for one name before senders are refused. */
|
|
36
37
|
export const MAX_PENDING = 25;
|
|
37
|
-
/**
|
|
38
|
-
const
|
|
38
|
+
/** Drain-archive ceiling; the file is truncated from the head past this. */
|
|
39
|
+
const MAX_ARCHIVE_BYTES = 256 * 1024;
|
|
39
40
|
export class MailboxCapacityError extends Error {
|
|
40
41
|
reason_code;
|
|
41
42
|
current;
|
|
@@ -68,7 +69,7 @@ export function mailboxDir(coordRoot) {
|
|
|
68
69
|
export function mailboxPath(coordRoot, name) {
|
|
69
70
|
return join(mailboxDir(coordRoot), `${slugFor(name)}.jsonl`);
|
|
70
71
|
}
|
|
71
|
-
function
|
|
72
|
+
function archivePath(coordRoot, name) {
|
|
72
73
|
return join(mailboxDir(coordRoot), "delivered", `${slugFor(name)}.jsonl`);
|
|
73
74
|
}
|
|
74
75
|
function parseLines(content) {
|
|
@@ -196,10 +197,10 @@ export function peekMailbox(coordRoot, name) {
|
|
|
196
197
|
/**
|
|
197
198
|
* Claim and return every pending message for a name.
|
|
198
199
|
*
|
|
199
|
-
* The claim is an atomic rename, so two sessions sharing a name cannot
|
|
200
|
+
* The claim is an atomic rename, so two sessions sharing a name cannot claim
|
|
200
201
|
* the same message twice: whichever rename wins owns the batch. Claimed records
|
|
201
|
-
* are
|
|
202
|
-
*
|
|
202
|
+
* are archived before the claim file is removed. The archive records only the
|
|
203
|
+
* drain; output, recipient read, and turn completion remain unconfirmed.
|
|
203
204
|
*/
|
|
204
205
|
export function drainMailbox(coordRoot, name) {
|
|
205
206
|
let path;
|
|
@@ -233,10 +234,16 @@ export function drainMailbox(coordRoot, name) {
|
|
|
233
234
|
}
|
|
234
235
|
if (messages.length > 0) {
|
|
235
236
|
try {
|
|
236
|
-
const archive =
|
|
237
|
+
const archive = archivePath(coordRoot, name);
|
|
237
238
|
mkdirSync(join(mailboxDir(coordRoot), "delivered"), { recursive: true });
|
|
238
|
-
const
|
|
239
|
-
appendFileSync(archive, `${messages
|
|
239
|
+
const drainedAt = new Date().toISOString();
|
|
240
|
+
appendFileSync(archive, `${messages
|
|
241
|
+
.map((m) => JSON.stringify({
|
|
242
|
+
...m,
|
|
243
|
+
drained_at: drainedAt,
|
|
244
|
+
delivery_status: "injection-unconfirmed",
|
|
245
|
+
}))
|
|
246
|
+
.join("\n")}\n`, "utf8");
|
|
240
247
|
trimArchive(archive);
|
|
241
248
|
}
|
|
242
249
|
catch {
|
|
@@ -291,7 +298,7 @@ function sweepStaleClaims(coordRoot) {
|
|
|
291
298
|
}
|
|
292
299
|
function trimArchive(path) {
|
|
293
300
|
try {
|
|
294
|
-
if (statSync(path).size <=
|
|
301
|
+
if (statSync(path).size <= MAX_ARCHIVE_BYTES)
|
|
295
302
|
return;
|
|
296
303
|
const lines = readFileSync(path, "utf8").split("\n").filter(Boolean);
|
|
297
304
|
const keep = lines.slice(Math.floor(lines.length / 2));
|
|
@@ -307,8 +314,8 @@ export function formatMailboxDelivery(coordRoot, messages) {
|
|
|
307
314
|
return "";
|
|
308
315
|
const bin = resolveBinName(coordRoot);
|
|
309
316
|
const header = messages.length === 1
|
|
310
|
-
? `Message from a peer agent (
|
|
311
|
-
: `${messages.length} messages from peer agents (
|
|
317
|
+
? `Message from a peer agent (prepared for injection, recorded in your journal):`
|
|
318
|
+
: `${messages.length} messages from peer agents (prepared for injection, recorded in your journal):`;
|
|
312
319
|
const body = messages
|
|
313
320
|
.map((m) => {
|
|
314
321
|
const when = m.created_at.replace("T", " ").replace(/\.\d+Z$/, "Z");
|
|
@@ -55,6 +55,8 @@ export interface PromptContextOpts {
|
|
|
55
55
|
* being bounced into a retry. Not hash-deduped, same rationale as the
|
|
56
56
|
* status footer. */
|
|
57
57
|
turnRitualNudge?: string;
|
|
58
|
+
/** The emitter acknowledges exactly these IDs only after output succeeds. */
|
|
59
|
+
onInboxPrepared?: (messageIds: readonly string[]) => void;
|
|
58
60
|
}
|
|
59
61
|
/**
|
|
60
62
|
* Build the combined UserPromptSubmit additionalContext string. Returns "" when
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/prompt-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;
|
|
1
|
+
{"version":3,"file":"prompt-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/prompt-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAiDH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;8EAC0E;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;kFAC8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;kFAC8E;IAC9E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;uEACmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;wBAIoB;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CAC3D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CA8EnE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CA6CtF"}
|
|
@@ -37,13 +37,14 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, w
|
|
|
37
37
|
import { join } from "node:path";
|
|
38
38
|
import { coordEnv } from "../../../lib/env.js";
|
|
39
39
|
import { endOfTurnStatusCommand, hostPromptReminder, resolveBinName } from "../../config.js";
|
|
40
|
+
import { formatPeerInbox, peerInbox } from "../../inbox/peer-messages.js";
|
|
40
41
|
import { readRemoteMachines } from "../../presence/index.js";
|
|
41
42
|
import { readResourceStatus } from "../../resources/status.js";
|
|
42
|
-
import { drainMailbox, formatMailboxDelivery } from "../mailbox.js";
|
|
43
43
|
import { sessionNameDisplayBlock, sessionNameDisplayPending } from "../session-name-display.js";
|
|
44
44
|
import { heartbeatPath } from "../state/heartbeat-reader.js";
|
|
45
45
|
import { readLiveCoordinationRow, readLiveCoordinationRows, } from "../state/live-coordination-view.js";
|
|
46
|
-
import {
|
|
46
|
+
import { forkRelationLabels } from "../state/names.js";
|
|
47
|
+
import { formatPendingCouncils } from "./session-context.js";
|
|
47
48
|
/**
|
|
48
49
|
* Build the combined UserPromptSubmit additionalContext string. Returns "" when
|
|
49
50
|
* nothing has changed since the last call (so the caller can skip the JSON emit).
|
|
@@ -59,16 +60,12 @@ export function renderPromptContext(opts) {
|
|
|
59
60
|
// Every name-addressed section below (messages, councils) is silently
|
|
60
61
|
// skipped without it.
|
|
61
62
|
const resolvedName = agentName ?? readLiveCoordinationRow(coordRoot, instanceId)?.name;
|
|
62
|
-
// 1.
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (delivered.length > 0) {
|
|
69
|
-
recordDeliveredMessages(instanceId, delivered);
|
|
70
|
-
sections.push(formatMailboxDelivery(coordRoot, delivered));
|
|
71
|
-
}
|
|
63
|
+
// 1. Instance-bound messages. Rendering is read-only; failed output leaves
|
|
64
|
+
// this same batch pending rather than losing it before a prompt sees it.
|
|
65
|
+
const delivered = peerInbox(coordRoot).prepareSurface(instanceId);
|
|
66
|
+
if (delivered.length > 0) {
|
|
67
|
+
opts.onInboxPrepared?.(delivered.map(({ message_id }) => message_id));
|
|
68
|
+
sections.push(formatPeerInbox(coordRoot, delivered));
|
|
72
69
|
}
|
|
73
70
|
// 2. Peer table with hash dedup.
|
|
74
71
|
const peerTable = computePeerTableIfChanged(coordRoot, instanceId, sessionId);
|
|
@@ -337,7 +334,7 @@ function computePeerTableIfChanged(coordRoot, selfInstanceId, selfSessionIdFallb
|
|
|
337
334
|
if (oldHash && oldHash === newHash)
|
|
338
335
|
return "";
|
|
339
336
|
// Render peer table via the same formatter used at SessionStart.
|
|
340
|
-
const local = formatPeerTable(peers, mySessionId);
|
|
337
|
+
const local = formatPeerTable(peers, mySessionId, forkRelationLabels(coordRoot, selfInstanceId, new Set(peers.map((p) => p.instance_id ?? ""))));
|
|
341
338
|
const remoteTable = formatRemoteTable(remote);
|
|
342
339
|
const table = [local, remoteTable].filter(Boolean).join("\n\n");
|
|
343
340
|
if (!table)
|
|
@@ -458,7 +455,7 @@ function writeHashFile(path, value) {
|
|
|
458
455
|
* intentionally co-located here so the prompt-context renderer is self-contained
|
|
459
456
|
* (no cross-file imports of formatting internals). If both renderers diverge,
|
|
460
457
|
* pull the shared bits into a small util module. */
|
|
461
|
-
function formatPeerTable(peers, mySessionId) {
|
|
458
|
+
function formatPeerTable(peers, mySessionId, relations = new Map()) {
|
|
462
459
|
if (peers.length === 0)
|
|
463
460
|
return "";
|
|
464
461
|
const nowSec = Math.floor(Date.now() / 1000);
|
|
@@ -474,9 +471,13 @@ function formatPeerTable(peers, mySessionId) {
|
|
|
474
471
|
.map((p) => {
|
|
475
472
|
const folded = fold[p.instance_id ?? ""] ?? [];
|
|
476
473
|
const display = Array.from(new Set([...(p.files_touched ?? []), ...folded])).sort();
|
|
477
|
-
|
|
474
|
+
const relation = relations.get(p.instance_id ?? "");
|
|
475
|
+
return { ...p, display_files: display, ...(relation ? { relation } : {}) };
|
|
478
476
|
});
|
|
479
|
-
|
|
477
|
+
// Related sessions sort first so a fork parent never hides in "+N more".
|
|
478
|
+
const blocking = rows
|
|
479
|
+
.filter((p) => p.session_id !== mySessionId)
|
|
480
|
+
.sort((a, b) => Number(!!b.relation) - Number(!!a.relation) || byStartedAt(a, b));
|
|
480
481
|
const group = rows.filter((p) => p.session_id === mySessionId).sort(byStartedAt);
|
|
481
482
|
const out = [];
|
|
482
483
|
const blk = renderSubtable(blocking, "Other agent groups active (their files block you):", nowSec);
|
|
@@ -508,7 +509,8 @@ function formatRow(r, nowSec) {
|
|
|
508
509
|
// Prefer a short instance_id over a bare "unknown" so an incomplete row is
|
|
509
510
|
// still identifiable.
|
|
510
511
|
const label = r.name ?? (r.instance_id ? r.instance_id.slice(0, 8) : "unknown");
|
|
511
|
-
|
|
512
|
+
const relation = r.relation ? ` [${r.relation}]` : "";
|
|
513
|
+
return ` - agent-${label}${relation}${taskPart} (${statePart}, ${ageFrom}, ${filesPart})`;
|
|
512
514
|
}
|
|
513
515
|
function formatState(r) {
|
|
514
516
|
const activity = r.activity ?? "unknown";
|