@peakflo/agent-harness 0.2.9-rc.3 → 0.2.9-rc.4

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 CHANGED
@@ -57,10 +57,12 @@ cloud sandbox runs Pi only.
57
57
  through the Peakflo model gateway and are not metered by Peakflo.
58
58
  - When you sign out of a harness, or remove it, the runner stops taking work
59
59
  for it after its next check.
60
- - Claude Code also needs the Claude Agent SDK, which is not installed with the
61
- runner: `npm install -g @anthropic-ai/claude-agent-sdk`. Without it Peakflo
62
- shows Claude Code as "Detected, not runnable by this runner" with this
63
- instruction.
60
+ - What the runner brings and what it expects, the same split as the 20x app:
61
+ it brings the Claude Agent SDK (a dependency of this package, installed with
62
+ it); it expects the tools themselves — `codex`, `claude`, `cursor-agent` —
63
+ to be installed and signed in on the machine. The SDK includes a copy of the
64
+ Claude binary for your platform, which is most of this package's install
65
+ size (about 260 MB installed).
64
66
  - Each turn starts the harness's own program and stops it when the turn ends.
65
67
  The conversation continues from the session the harness saved on this
66
68
  machine.
@@ -46,7 +46,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
46
46
  exports.ClaudeCodeAdapter = exports.ClaudeSystemSubtype = void 0;
47
47
  const coding_agent_adapter_1 = require("./coding-agent-adapter");
48
48
  const permission_mode_1 = require("../runtime/permission-mode");
49
- const vendor_backends_1 = require("../vendor-backends");
50
49
  let ClaudeAgentSDK = null;
51
50
  /** Module-level cache for the resolved Claude executable path (persists across adapter instances) */
52
51
  let resolvedClaudeExecutablePath = null;
@@ -271,10 +270,7 @@ class ClaudeCodeAdapter {
271
270
  }
272
271
  async loadSDK() {
273
272
  try {
274
- // CHANGED from 20x: the SDK is not bundled with the runner (it would add
275
- // ~190 MB to every install), so it is also looked for in the global
276
- // node_modules. See `vendor-backends.ts`.
277
- ClaudeAgentSDK = (await (0, vendor_backends_1.importClaudeSdk)());
273
+ ClaudeAgentSDK = await Promise.resolve().then(() => __importStar(require('@anthropic-ai/claude-agent-sdk')));
278
274
  console.log('[ClaudeCodeAdapter] SDK loaded successfully');
279
275
  }
280
276
  catch (error) {
package/dist/harness.js CHANGED
@@ -1035,12 +1035,16 @@ class Harness {
1035
1035
  blocked.set(harness.name, reason);
1036
1036
  continue;
1037
1037
  }
1038
+ /*
1039
+ * NAME AND VERSION ONLY. The harness's models are already in
1040
+ * `harnesses[]`, which is sent once and then by digest. Repeating them
1041
+ * here put them back into every heartbeat: about 15 KB each time on a
1042
+ * machine with Cursor's 200 models, seen on the first release candidate
1043
+ * that had this.
1044
+ */
1038
1045
  capabilities.backends.push({
1039
1046
  name: harness.name,
1040
- version: harness.version ?? null,
1041
- ...(harness.models && harness.models.length > 0
1042
- ? { models: harness.models.map(({ id, name }) => ({ id, name })) }
1043
- : {})
1047
+ version: harness.version ?? null
1044
1048
  });
1045
1049
  }
1046
1050
  return blocked;
@@ -47,31 +47,23 @@ export declare const CLAUDE_SDK_PACKAGE = "@anthropic-ai/claude-agent-sdk";
47
47
  * runner. Fixed sentences, like every other reason in the report.
48
48
  */
49
49
  export declare const NOT_RUNNABLE_REASONS: {
50
- readonly claudeSdkMissing: "The Claude Agent SDK is not installed. Run `npm install -g @anthropic-ai/claude-agent-sdk` on this machine.";
50
+ readonly claudeSdkMissing: "The Claude Agent SDK that ships with this runner could not be loaded. Reinstall the runner.";
51
51
  readonly sandbox: "A cloud sandbox runs Pi only.";
52
52
  };
53
53
  /**
54
- * Directories to look for the SDK in, besides this package's own
55
- * `node_modules`.
54
+ * Where the SDK is, or null.
56
55
  *
57
- * WHY IT IS NOT SIMPLY A DEPENDENCY. In 20x the SDK ships inside the app. Here
58
- * that would add its platform package — about 190 MB, a copy of the Claude
59
- * binary — to EVERY install of the runner, the cloud sandbox included, for a
60
- * harness most installs never use. The adapter already points the SDK at the
61
- * `claude` the user installed, so only the SDK's own JavaScript is needed, and
62
- * a machine that wants Claude Code installs it once, globally.
63
- */
64
- export declare function claudeSdkSearchRoots(env?: NodeJS.ProcessEnv, execPath?: string): string[];
65
- /**
66
- * Where the SDK can be loaded from, or null. Synchronous and cheap (a few
67
- * file reads), so it can be asked on every capability report.
56
+ * THE SDK IS A DEPENDENCY OF THIS PACKAGE, as it is of the 20x app: installing
57
+ * the runner installs it, and nothing else has to be done on the machine. So
58
+ * it is looked for in one place, this package's own dependency tree.
59
+ *
60
+ * Null is still possible and still handled, because "declared" is not
61
+ * "present": an install that was interrupted, pruned, or made with
62
+ * dependencies left out has no SDK. Claude Code is then reported as not
63
+ * runnable, with a reason, instead of being routed a turn it must fail.
68
64
  *
69
- * `ownTree` is this package's own resolution, replaced in tests — this
70
- * repository has the SDK as a dev dependency, so "not installed" could not be
71
- * tested otherwise.
65
+ * `ownTree` is replaced in tests, which could not otherwise see "missing".
72
66
  */
73
- export declare function resolveClaudeSdk(roots?: readonly string[], ownTree?: () => string): string | null;
74
- /** Import the SDK from wherever `resolveClaudeSdk` finds it. Throws when absent. */
75
- export declare function importClaudeSdk(): Promise<unknown>;
67
+ export declare function resolveClaudeSdk(ownTree?: () => string): string | null;
76
68
  /** Whether this runner can build an adapter for a vendor backend right now. */
77
69
  export declare function vendorBackendBlocker(backend: string, runtime: string): string | null;
@@ -25,14 +25,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.NOT_RUNNABLE_REASONS = exports.CLAUDE_SDK_PACKAGE = exports.VENDOR_BACKENDS = void 0;
26
26
  exports.isVendorBackend = isVendorBackend;
27
27
  exports.vendorModelId = vendorModelId;
28
- exports.claudeSdkSearchRoots = claudeSdkSearchRoots;
29
28
  exports.resolveClaudeSdk = resolveClaudeSdk;
30
- exports.importClaudeSdk = importClaudeSdk;
31
29
  exports.vendorBackendBlocker = vendorBackendBlocker;
32
- const node_fs_1 = require("node:fs");
33
30
  const node_module_1 = require("node:module");
34
- const node_path_1 = require("node:path");
35
- const node_url_1 = require("node:url");
36
31
  exports.VENDOR_BACKENDS = ['codex', 'claude-code', 'cursor'];
37
32
  function isVendorBackend(name) {
38
33
  return exports.VENDOR_BACKENDS.includes(name);
@@ -65,94 +60,30 @@ exports.CLAUDE_SDK_PACKAGE = '@anthropic-ai/claude-agent-sdk';
65
60
  * runner. Fixed sentences, like every other reason in the report.
66
61
  */
67
62
  exports.NOT_RUNNABLE_REASONS = {
68
- claudeSdkMissing: 'The Claude Agent SDK is not installed. Run `npm install -g @anthropic-ai/claude-agent-sdk` on this machine.',
63
+ claudeSdkMissing: 'The Claude Agent SDK that ships with this runner could not be loaded. Reinstall the runner.',
69
64
  sandbox: 'A cloud sandbox runs Pi only.'
70
65
  };
71
66
  /**
72
- * Directories to look for the SDK in, besides this package's own
73
- * `node_modules`.
67
+ * Where the SDK is, or null.
74
68
  *
75
- * WHY IT IS NOT SIMPLY A DEPENDENCY. In 20x the SDK ships inside the app. Here
76
- * that would add its platform package — about 190 MB, a copy of the Claude
77
- * binary — to EVERY install of the runner, the cloud sandbox included, for a
78
- * harness most installs never use. The adapter already points the SDK at the
79
- * `claude` the user installed, so only the SDK's own JavaScript is needed, and
80
- * a machine that wants Claude Code installs it once, globally.
81
- */
82
- function claudeSdkSearchRoots(env = process.env, execPath = process.execPath) {
83
- const roots = [
84
- env.PF_CLAUDE_AGENT_SDK_DIR,
85
- // `npm install -g` beside the running node: <prefix>/lib/node_modules
86
- (0, node_path_1.join)((0, node_path_1.dirname)((0, node_path_1.dirname)(execPath)), 'lib', 'node_modules'),
87
- // Windows: <prefix>\node_modules
88
- (0, node_path_1.join)((0, node_path_1.dirname)(execPath), 'node_modules'),
89
- '/opt/homebrew/lib/node_modules',
90
- '/usr/local/lib/node_modules'
91
- ];
92
- return [...new Set(roots.filter((root) => Boolean(root)))];
93
- }
94
- /** The file a package directory loads as, read from its own package.json. */
95
- function packageEntry(directory) {
96
- try {
97
- const manifest = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(directory, 'package.json'), 'utf8'));
98
- const root = manifest.exports && typeof manifest.exports === 'object'
99
- ? (manifest.exports['.'] ??
100
- manifest.exports)
101
- : manifest.exports;
102
- const fromExports = typeof root === 'string'
103
- ? root
104
- : root && typeof root === 'object'
105
- ? (root.import ??
106
- root.default)
107
- : undefined;
108
- const entry = [
109
- fromExports,
110
- manifest.module,
111
- manifest.main,
112
- 'index.js'
113
- ].find((candidate) => typeof candidate === 'string');
114
- const file = entry ? (0, node_path_1.join)(directory, entry) : null;
115
- return file && (0, node_fs_1.existsSync)(file) ? file : null;
116
- }
117
- catch {
118
- return null;
119
- }
120
- }
121
- /**
122
- * Where the SDK can be loaded from, or null. Synchronous and cheap (a few
123
- * file reads), so it can be asked on every capability report.
69
+ * THE SDK IS A DEPENDENCY OF THIS PACKAGE, as it is of the 20x app: installing
70
+ * the runner installs it, and nothing else has to be done on the machine. So
71
+ * it is looked for in one place, this package's own dependency tree.
72
+ *
73
+ * Null is still possible and still handled, because "declared" is not
74
+ * "present": an install that was interrupted, pruned, or made with
75
+ * dependencies left out has no SDK. Claude Code is then reported as not
76
+ * runnable, with a reason, instead of being routed a turn it must fail.
124
77
  *
125
- * `ownTree` is this package's own resolution, replaced in tests — this
126
- * repository has the SDK as a dev dependency, so "not installed" could not be
127
- * tested otherwise.
78
+ * `ownTree` is replaced in tests, which could not otherwise see "missing".
128
79
  */
129
- function resolveClaudeSdk(roots = claudeSdkSearchRoots(), ownTree = () => (0, node_module_1.createRequire)(__filename).resolve(exports.CLAUDE_SDK_PACKAGE)) {
80
+ function resolveClaudeSdk(ownTree = () => (0, node_module_1.createRequire)(__filename).resolve(exports.CLAUDE_SDK_PACKAGE)) {
130
81
  try {
131
82
  return ownTree();
132
83
  }
133
84
  catch {
134
- // Not in this package's own tree.
135
- }
136
- for (const root of roots) {
137
- const entry = packageEntry((0, node_path_1.join)(root, exports.CLAUDE_SDK_PACKAGE));
138
- if (entry)
139
- return entry;
140
- }
141
- return null;
142
- }
143
- /** Import the SDK from wherever `resolveClaudeSdk` finds it. Throws when absent. */
144
- async function importClaudeSdk() {
145
- const resolved = resolveClaudeSdk();
146
- if (!resolved) {
147
- throw new Error(exports.NOT_RUNNABLE_REASONS.claudeSdkMissing);
85
+ return null;
148
86
  }
149
- /*
150
- * `new Function` keeps this a REAL dynamic import in the compiled CommonJS
151
- * output. Written as `import(x)`, TypeScript turns it into `require(x)`,
152
- * and the SDK is an ES module that `require` cannot load on every Node.
153
- */
154
- const dynamicImport = new Function('specifier', 'return import(specifier)');
155
- return dynamicImport((0, node_url_1.pathToFileURL)(resolved).href);
156
87
  }
157
88
  /** Whether this runner can build an adapter for a vendor backend right now. */
158
89
  function vendorBackendBlocker(backend, runtime) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peakflo/agent-harness",
3
- "version": "0.2.9-rc.3",
3
+ "version": "0.2.9-rc.4",
4
4
  "description": "Headless Peakflo coding-agent harness. One codebase, three hosting modes: a Daytona cloud sandbox, a customer VM, and the 20x desktop.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -29,7 +29,6 @@
29
29
  "test": "jest"
30
30
  },
31
31
  "devDependencies": {
32
- "@anthropic-ai/claude-agent-sdk": "^0.3.195",
33
32
  "@opencode-ai/sdk": "^1.15.13",
34
33
  "@types/node": "^22.10.0",
35
34
  "tsx": "^4.19.3",
@@ -37,6 +36,7 @@
37
36
  "undici": "^7.21.0"
38
37
  },
39
38
  "dependencies": {
39
+ "@anthropic-ai/claude-agent-sdk": "0.3.258",
40
40
  "@modelcontextprotocol/client": "2.0.0",
41
41
  "@peculiar/x509": "^2.1.0",
42
42
  "reflect-metadata": "^0.2.2"