harnery 0.46.0 → 0.47.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 +24 -0
- package/bin/README.md +10 -0
- package/bin/agent-coord.mjs +3 -0
- package/bin/agent-hook.mjs +3 -0
- package/bin/harn.mjs +3 -0
- package/bin/run.mjs +43 -0
- package/dist/commander.d.ts +18 -6
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +74 -2
- package/dist/commands/agents.d.ts +25 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +70 -27
- package/dist/commands/autoupdate.d.ts +12 -0
- package/dist/commands/autoupdate.d.ts.map +1 -0
- package/dist/commands/autoupdate.js +190 -0
- package/dist/commands/computer.d.ts +45 -0
- package/dist/commands/computer.d.ts.map +1 -0
- package/dist/commands/computer.js +509 -0
- package/dist/commands/docs.js +3 -1
- package/dist/commands/fetch.js +11 -1
- package/dist/commands/grep.d.ts +72 -0
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +200 -47
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +15 -9
- package/dist/commands/rm.js +2 -2
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +2 -0
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +2 -3
- package/dist/core/agents/coord-bin.d.ts +3 -0
- package/dist/core/agents/coord-bin.d.ts.map +1 -1
- package/dist/core/agents/coord-bin.js +6 -0
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +6 -2
- package/dist/core/agents/render/prompt-context.d.ts +55 -7
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +122 -48
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +36 -16
- package/dist/core/agents/rules/stop-hook.d.ts +6 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +20 -1
- package/dist/core/agents/state/proc-start.d.ts +3 -1
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +26 -4
- package/dist/core/autoupdate/engine.d.ts +97 -0
- package/dist/core/autoupdate/engine.d.ts.map +1 -0
- package/dist/core/autoupdate/engine.js +548 -0
- package/dist/core/autoupdate/fingerprint.d.ts +16 -0
- package/dist/core/autoupdate/fingerprint.d.ts.map +1 -0
- package/dist/core/autoupdate/fingerprint.js +73 -0
- package/dist/core/autoupdate/git.d.ts +30 -0
- package/dist/core/autoupdate/git.d.ts.map +1 -0
- package/dist/core/autoupdate/git.js +82 -0
- package/dist/core/autoupdate/index.d.ts +6 -0
- package/dist/core/autoupdate/index.d.ts.map +1 -0
- package/dist/core/autoupdate/index.js +4 -0
- package/dist/core/autoupdate/state.d.ts +59 -0
- package/dist/core/autoupdate/state.d.ts.map +1 -0
- package/dist/core/autoupdate/state.js +214 -0
- package/dist/core/autoupdate/types.d.ts +113 -0
- package/dist/core/autoupdate/types.d.ts.map +1 -0
- package/dist/core/autoupdate/types.js +35 -0
- package/dist/core/config.d.ts +53 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +114 -1
- package/dist/core/events/v3/bootstrap.js +1 -0
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-build.js +1 -0
- package/dist/core/hooks/adapter/wiring.d.ts +12 -2
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +38 -8
- package/dist/core/hooks/autoupdate-cue.d.ts +29 -0
- package/dist/core/hooks/autoupdate-cue.d.ts.map +1 -0
- package/dist/core/hooks/autoupdate-cue.js +53 -0
- package/dist/core/hooks/cli.js +52 -4
- package/dist/core/hooks/effects/index.js +4 -4
- package/dist/core/hooks/resolve/coord-root.js +1 -0
- package/dist/core/hooks/resolve/transcript.d.ts +12 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +54 -0
- package/dist/core/semantic/contract.d.ts +3 -3
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +4 -2
- package/dist/core/storage/modes.d.ts +1 -1
- package/dist/core/storage/modes.d.ts.map +1 -1
- package/dist/core/storage/modes.js +5 -1
- package/dist/core/workflow/durable-record.d.ts +2 -0
- package/dist/core/workflow/durable-record.d.ts.map +1 -1
- package/dist/core/workflow/durable-record.js +13 -1
- package/dist/core/workflow/engine.js +4 -0
- package/dist/core/workflow/spawn-claude.d.ts +7 -0
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +16 -4
- package/dist/core/workflow/specialists.d.ts.map +1 -1
- package/dist/core/workflow/specialists.js +1 -0
- package/dist/core/workflow/types.d.ts +10 -0
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +1 -9
- package/dist/lib/computer/cua.d.ts +50 -0
- package/dist/lib/computer/cua.d.ts.map +1 -0
- package/dist/lib/computer/cua.js +474 -0
- package/dist/lib/computer/host.d.ts +19 -0
- package/dist/lib/computer/host.d.ts.map +1 -0
- package/dist/lib/computer/host.js +72 -0
- package/dist/lib/computer/lease.d.ts +13 -0
- package/dist/lib/computer/lease.d.ts.map +1 -0
- package/dist/lib/computer/lease.js +269 -0
- package/dist/lib/computer/types.d.ts +163 -0
- package/dist/lib/computer/types.d.ts.map +1 -0
- package/dist/lib/computer/types.js +10 -0
- package/dist/lib/docs-metadata-v2.d.ts.map +1 -1
- package/dist/lib/docs-metadata-v2.js +6 -5
- package/dist/lib/exec.d.ts.map +1 -1
- package/dist/lib/exec.js +1 -0
- package/dist/lib/guarded-remove.d.ts.map +1 -1
- package/dist/lib/guarded-remove.js +5 -4
- package/dist/lib/headless/index.d.ts +33 -0
- package/dist/lib/headless/index.d.ts.map +1 -1
- package/dist/lib/headless/index.js +38 -2
- package/dist/lib/http/client.d.ts +2 -9
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +30 -9
- package/dist/lib/instructions/apply.d.ts +9 -0
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +92 -14
- package/dist/lib/instructions/git-hooks.d.ts.map +1 -1
- package/dist/lib/instructions/git-hooks.js +8 -4
- package/dist/lib/instructions/templates.d.ts +11 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +81 -1
- package/package.json +5 -5
- package/schemas/config.schema.json +89 -1
- package/src/commander.ts +98 -8
- package/src/commands/agents.ts +100 -32
- package/src/commands/autoupdate.ts +250 -0
- package/src/commands/computer.ts +682 -0
- package/src/commands/docs.ts +3 -1
- package/src/commands/fetch.ts +11 -1
- package/src/commands/grep.ts +274 -59
- package/src/commands/init.ts +17 -7
- package/src/commands/rm.ts +2 -2
- package/src/commands/web.ts +2 -0
- package/src/core/agents/canonical-emit.ts +2 -3
- package/src/core/agents/coord-bin.ts +30 -0
- package/src/core/agents/coord-client.ts +6 -2
- package/src/core/agents/render/prompt-context.ts +152 -53
- package/src/core/agents/rules/claim-conflict.ts +50 -18
- package/src/core/agents/rules/stop-hook.ts +28 -1
- package/src/core/agents/state/proc-start.ts +29 -5
- package/src/core/autoupdate/engine.ts +691 -0
- package/src/core/autoupdate/fingerprint.ts +89 -0
- package/src/core/autoupdate/git.ts +120 -0
- package/src/core/autoupdate/index.ts +29 -0
- package/src/core/autoupdate/state.ts +269 -0
- package/src/core/autoupdate/types.ts +135 -0
- package/src/core/config.ts +142 -1
- package/src/core/events/v3/bootstrap.ts +1 -0
- package/src/core/events/v3/runtime-build.ts +1 -0
- package/src/core/hooks/adapter/wiring.ts +51 -6
- package/src/core/hooks/autoupdate-cue.ts +72 -0
- package/src/core/hooks/cli.ts +54 -1
- package/src/core/hooks/effects/index.ts +4 -4
- package/src/core/hooks/resolve/coord-root.ts +1 -0
- package/src/core/hooks/resolve/transcript.ts +61 -0
- package/src/core/semantic/service.ts +6 -2
- package/src/core/storage/modes.ts +7 -1
- package/src/core/workflow/durable-record.ts +15 -1
- package/src/core/workflow/engine.ts +3 -0
- package/src/core/workflow/spawn-claude.ts +16 -4
- package/src/core/workflow/specialists.ts +1 -0
- package/src/core/workflow/types.ts +10 -0
- package/src/core/workflow/workspaces/leases.ts +1 -9
- package/src/lib/computer/cua.ts +572 -0
- package/src/lib/computer/host.ts +87 -0
- package/src/lib/computer/lease.ts +299 -0
- package/src/lib/computer/types.ts +177 -0
- package/src/lib/docs-metadata-v2.ts +24 -5
- package/src/lib/exec.ts +1 -0
- package/src/lib/guarded-remove.ts +5 -3
- package/src/lib/headless/index.ts +66 -2
- package/src/lib/http/client.ts +33 -19
- package/src/lib/instructions/apply.ts +100 -12
- package/src/lib/instructions/git-hooks.ts +8 -4
- package/src/lib/instructions/templates.ts +95 -1
|
@@ -54,6 +54,12 @@ export function stateFileMode(): number {
|
|
|
54
54
|
* True when a state file or directory is readable or writable by someone it should not be: anyone
|
|
55
55
|
* but the owner in private mode, anyone outside the owner and group in group mode.
|
|
56
56
|
*/
|
|
57
|
-
export function stateModeTooOpen(
|
|
57
|
+
export function stateModeTooOpen(
|
|
58
|
+
mode: number,
|
|
59
|
+
platform: NodeJS.Platform = process.platform,
|
|
60
|
+
): boolean {
|
|
61
|
+
// Windows synthesizes POSIX mode bits; access is controlled by inherited
|
|
62
|
+
// NTFS ACLs, which chmod and stat.mode cannot inspect or tighten.
|
|
63
|
+
if (platform === "win32") return false;
|
|
58
64
|
return (mode & (stateSharing() === "group" ? 0o007 : 0o077)) !== 0;
|
|
59
65
|
}
|
|
@@ -61,10 +61,24 @@ export function writeImmutableJson(path: string, value: unknown): boolean {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export function fsyncParentDirectory(path: string): void {
|
|
64
|
-
|
|
64
|
+
fsyncDirectory(dirname(path));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Flush directory entries where the runtime supports it; file fsync remains mandatory. */
|
|
68
|
+
export function fsyncDirectory(directory: string): void {
|
|
65
69
|
const fd = openSync(directory, "r");
|
|
66
70
|
try {
|
|
67
71
|
fsyncSync(fd);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
// Windows does not expose directory FlushFileBuffers through node:fs.
|
|
74
|
+
// Keep atomic links/renames and file flushes, but do not claim POSIX
|
|
75
|
+
// directory-entry durability on that platform. Other errors still fail.
|
|
76
|
+
if (
|
|
77
|
+
process.platform !== "win32" ||
|
|
78
|
+
!["EPERM", "EINVAL", "ENOTSUP"].includes((error as NodeJS.ErrnoException).code ?? "")
|
|
79
|
+
) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
68
82
|
} finally {
|
|
69
83
|
closeSync(fd);
|
|
70
84
|
}
|
|
@@ -1101,6 +1101,7 @@ async function executeWorkflow(
|
|
|
1101
1101
|
runId,
|
|
1102
1102
|
agentId: id,
|
|
1103
1103
|
subscriptionOnly,
|
|
1104
|
+
...(agentOpts.mcp ? { mcp: agentOpts.mcp } : {}),
|
|
1104
1105
|
// A full-access launch has no sandbox to project a policy into.
|
|
1105
1106
|
...(access.mode === "full-access"
|
|
1106
1107
|
? { access: "full-access" as const }
|
|
@@ -1505,6 +1506,8 @@ function agentCallKey(
|
|
|
1505
1506
|
agentOpts.schema ?? null,
|
|
1506
1507
|
];
|
|
1507
1508
|
if (agentOpts.specialist) parts.push(agentOpts.specialist);
|
|
1509
|
+
// Appended only when set so existing resume keys stay stable.
|
|
1510
|
+
if (agentOpts.mcp) parts.push({ mcp: agentOpts.mcp });
|
|
1508
1511
|
parts.push(prompt);
|
|
1509
1512
|
const basis = JSON.stringify(parts);
|
|
1510
1513
|
return createHash("sha256").update(basis).digest("hex").slice(0, 16);
|
|
@@ -16,9 +16,17 @@
|
|
|
16
16
|
* visible to peers — the point of running them under harnery. So the child
|
|
17
17
|
* gets HARNERY_WORKFLOW_CHILD=1 and the stop-hook rule exempts it
|
|
18
18
|
* (stop-hook.ts), keeping heartbeats + events on.
|
|
19
|
+
* 3. **No MCP servers or claude.ai connectors unless the spawn asks.** A
|
|
20
|
+
* headless child otherwise loads every connector on the account (about 130
|
|
21
|
+
* tool schemas) into every turn. `req.mcp` defaults to `"none"` (strict
|
|
22
|
+
* empty MCP config plus ENABLE_CLAUDEAI_MCP_SERVERS=false); `"inherit"` or
|
|
23
|
+
* a server map is the per-spawn opt-in. Project settings, hooks, and
|
|
24
|
+
* CLAUDE.md still load: workflow children need them, so this adapter never
|
|
25
|
+
* passes `--setting-sources ""`.
|
|
19
26
|
*/
|
|
20
27
|
|
|
21
28
|
import { exec } from "../../lib/exec.ts";
|
|
29
|
+
import { claudeMcpLaunch } from "../../lib/headless/index.ts";
|
|
22
30
|
import { builtinAdapterProfile, validateAdapterEffort } from "../adapters/profiles.ts";
|
|
23
31
|
import type { AdapterInvocation, AdapterRawResult } from "../adapters/types.ts";
|
|
24
32
|
import { notFoundError } from "./adapters.ts";
|
|
@@ -62,6 +70,7 @@ export function buildClaudeInvocation(req: SpawnRequest): AdapterInvocation {
|
|
|
62
70
|
if (fullAccess) argv.push(...fullAccess);
|
|
63
71
|
if (req.model) argv.push("--model", req.model);
|
|
64
72
|
if (req.effort) argv.push("--effort", req.effort);
|
|
73
|
+
argv.push(...claudeMcpLaunch(req.mcp).args);
|
|
65
74
|
return { argv };
|
|
66
75
|
}
|
|
67
76
|
|
|
@@ -152,10 +161,13 @@ export const claudeCodeSpawner: Spawner = async (req: SpawnRequest): Promise<Spa
|
|
|
152
161
|
}
|
|
153
162
|
const r = await exec(invocation.argv, {
|
|
154
163
|
cwd: req.cwd,
|
|
155
|
-
env:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
env: {
|
|
165
|
+
...buildChildEnv(req.runId, {
|
|
166
|
+
subscriptionOnly: req.subscriptionOnly,
|
|
167
|
+
agentId: req.agentId,
|
|
168
|
+
}),
|
|
169
|
+
...claudeMcpLaunch(req.mcp).env,
|
|
170
|
+
},
|
|
159
171
|
timeout: req.timeoutMs,
|
|
160
172
|
});
|
|
161
173
|
return normalizeClaudeResult({ ...r, durationMs: Date.now() - t0 });
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Design record: decision 0015 (portable coordination-aware workflows).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type { ClaudeMcpMode } from "../../lib/headless/index.ts";
|
|
10
11
|
import type { DiagnosticAdvice } from "../diagnostics/contract.ts";
|
|
11
12
|
import type {
|
|
12
13
|
DispatchCostEstimator,
|
|
@@ -342,6 +343,11 @@ export interface AgentOpts {
|
|
|
342
343
|
* Mixed-adapter workflows are legal: triage on one CLI, deep work on
|
|
343
344
|
* another. */
|
|
344
345
|
adapter?: AdapterName;
|
|
346
|
+
/** MCP servers a Claude Code child may load (default `"none"`: no MCP
|
|
347
|
+
* servers, no claude.ai connectors). Set `"inherit"` for a stage that really
|
|
348
|
+
* calls a connector, or `{ mcpServers: {...} }` for exactly those servers.
|
|
349
|
+
* Other adapters ignore it. */
|
|
350
|
+
mcp?: ClaudeMcpMode;
|
|
345
351
|
}
|
|
346
352
|
|
|
347
353
|
/** Open registry key. The built-in catalog currently contains Claude Code,
|
|
@@ -436,6 +442,10 @@ export interface SpawnRequest {
|
|
|
436
442
|
* spawner refuses it when its adapter declares no full-access rendering, and
|
|
437
443
|
* refuses it alongside a filesystem policy, which it would contradict. */
|
|
438
444
|
access?: WorkerAccessMode;
|
|
445
|
+
/** MCP servers a Claude Code child may load. Absent means `"none"`: no MCP
|
|
446
|
+
* servers and no claude.ai connectors. `"inherit"` or an explicit server map
|
|
447
|
+
* is the per-spawn opt-in (see `ClaudeMcpMode`). Other adapters ignore it. */
|
|
448
|
+
mcp?: ClaudeMcpMode;
|
|
439
449
|
}
|
|
440
450
|
|
|
441
451
|
/**
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { hostname } from "node:os";
|
|
18
18
|
import { basename, dirname, join, resolve } from "node:path";
|
|
19
19
|
import { stateDirMode, stateFileMode } from "../../storage/modes.ts";
|
|
20
|
+
import { fsyncDirectory } from "../durable-record.ts";
|
|
20
21
|
|
|
21
22
|
const MAX_LEASE_BYTES = 8 * 1024;
|
|
22
23
|
const MAX_CONTENTION_OBSERVATION_ATTEMPTS = 8;
|
|
@@ -568,15 +569,6 @@ function digestBytes(bytes: string): string {
|
|
|
568
569
|
return createHash("sha256").update(bytes).digest("hex");
|
|
569
570
|
}
|
|
570
571
|
|
|
571
|
-
function fsyncDirectory(path: string): void {
|
|
572
|
-
const fd = openSync(path, "r");
|
|
573
|
-
try {
|
|
574
|
-
fsyncSync(fd);
|
|
575
|
-
} finally {
|
|
576
|
-
closeSync(fd);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
572
|
function safeUnlink(path: string): void {
|
|
581
573
|
try {
|
|
582
574
|
unlinkSync(path);
|