@topline-build/harness-mcp 0.5.0 → 0.5.2
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/CHANGELOG.md +11 -5
- package/README.md +6 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -1
- package/docs/generated/build-mcp-manifest.json +7 -2
- package/docs/generated/build-mcp-reference.md +2 -1
- package/package.json +1 -1
- package/scripts/certify-live.mjs +105 -22
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,17 @@ All notable customer-visible Build MCP changes are recorded here. A source chang
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
## 0.5.2 - 2026-09-26
|
|
8
|
+
|
|
9
|
+
- Report rejected bearer credentials as `authorization_required`, with scoped cache-clearing and browser reconnect guidance instead of input-correction advice.
|
|
10
|
+
- Guide connection-specific cache cleanup and recovery of existing deployment progress before a write is retried.
|
|
11
|
+
- Report native client certification timeouts as failures even when partial output mentions authentication; a timed-out process is not proof of a missing provider session.
|
|
12
|
+
|
|
13
|
+
## 0.5.1 - 2026-09-18
|
|
14
|
+
|
|
15
|
+
- Harden the bundled Claude certification script with strict tool isolation, effective-runtime proof, and noninteractive JSONL validation.
|
|
16
|
+
- Update certification setup documentation and regression coverage.
|
|
17
|
+
- Harden live certification CI and add an exact-version website documentation dispatch probe.
|
|
12
18
|
|
|
13
19
|
## 0.5.0
|
|
14
20
|
|
package/README.md
CHANGED
|
@@ -22,6 +22,8 @@ npx -y @topline-build/harness-mcp
|
|
|
22
22
|
|
|
23
23
|
Run `npx -y @topline-build/harness-mcp --help` for every supported flag and environment variable. `TOPLINE_MCP_TOKEN` is an advanced manual-token fallback; browser-approved OAuth is preferred.
|
|
24
24
|
|
|
25
|
+
If a tool returns `authorization_required`, clear only that connection's OAuth cache and reconnect through browser sign-in. Replace an expired or revoked manual token if using the fallback. Inspect existing artifact/deployment progress before retrying a write; the helper does not silently replay the rejected request.
|
|
26
|
+
|
|
25
27
|
## Typical workflow
|
|
26
28
|
|
|
27
29
|
1. Use `platform_init_artifact_app` to create a starter, or point at an existing artifact app.
|
|
@@ -75,9 +77,11 @@ can consume provider model quota and runs only for clients whose CLI can reject
|
|
|
75
77
|
user/global MCP configuration and disable every built-in tool. Claude Code is
|
|
76
78
|
currently the supported mediated client; Codex and Cursor report
|
|
77
79
|
`strict_client_tool_isolation_unavailable` instead of starting an agent with
|
|
78
|
-
broader access. The Claude process uses strict MCP configuration,
|
|
80
|
+
broader access. The Claude process uses strict MCP configuration, bare mode,
|
|
79
81
|
no built-in tools, an allowlisted environment, an isolated OAuth cache, and a
|
|
80
|
-
server exposing only `platform_inspect_artifact_app`.
|
|
82
|
+
server exposing only `platform_inspect_artifact_app`. Its bare noninteractive
|
|
83
|
+
permission bypass is accepted only when Claude's structured init event proves
|
|
84
|
+
that this is the sole effective tool and MCP server. The write credential is
|
|
81
85
|
available only to the direct exact-SHA apply path. Missing client CLIs, provider
|
|
82
86
|
login, URL/app inputs, or credentials produce explicit `skipped` results and
|
|
83
87
|
exit successfully by default; `--require-all` exits 2 for any skip. A failed
|
package/dist/index.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export interface PackedArtifactAppBundle {
|
|
|
32
32
|
type ToolProgressReporter = (progress: number, message: string) => void | Promise<void>;
|
|
33
33
|
export declare const DEFAULT_MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
34
34
|
export declare const BUILD_MCP_SERVER_NAME = "topline-build-stdio";
|
|
35
|
-
export declare const HARNESS_MCP_VERSION = "0.5.
|
|
35
|
+
export declare const HARNESS_MCP_VERSION = "0.5.2";
|
|
36
36
|
export declare const DEFAULT_OAUTH_SCOPES: readonly string[];
|
|
37
37
|
export interface BuildMcpSetupOption {
|
|
38
38
|
readonly flag: string;
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } fr
|
|
|
13
13
|
export const DEFAULT_MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
14
14
|
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
15
15
|
export const BUILD_MCP_SERVER_NAME = "topline-build-stdio";
|
|
16
|
-
export const HARNESS_MCP_VERSION = "0.5.
|
|
16
|
+
export const HARNESS_MCP_VERSION = "0.5.2";
|
|
17
17
|
export const DEFAULT_OAUTH_SCOPES = Object.freeze(["harness:artifact:read", "harness:artifact:write", "harness:artifact:deploy", "harness:artifact:delete"]);
|
|
18
18
|
export const BUILD_MCP_SETUP_OPTIONS = Object.freeze([
|
|
19
19
|
{ flag: "--url", env: "TOPLINE_API_URL", aliases: ["PLATFORM_API_URL", "OVERSITE_API_URL"], required: true, description: "Topline tenant base URL. HTTPS is required except for loopback development." },
|
|
@@ -1063,6 +1063,7 @@ function toolError(message) {
|
|
|
1063
1063
|
return structuredToolError(message);
|
|
1064
1064
|
}
|
|
1065
1065
|
const BUILD_MCP_RECOVERY_ERROR_VALUES = {
|
|
1066
|
+
authorization_required: { retryable: false, recoveryAction: "Clear only this connection's cached OAuth credentials, then reconnect the Build MCP through browser sign-in. If using a manual bearer token, replace the expired or revoked token. Recover existing artifact/deployment progress before retrying a write." },
|
|
1066
1067
|
platform_harness_timeout: { retryable: true, recoveryAction: "Retry the call. For a deployment, use platform_list_artifact_drafts to recover the artifact and platform_wait_artifact_deploy to resume progress." },
|
|
1067
1068
|
platform_mcp_tool_error: { retryable: false, recoveryAction: "Read the returned error code, correct the request or OAuth scopes, then retry." },
|
|
1068
1069
|
artifact_deploy_wait_timeout: { retryable: true, recoveryAction: "Call platform_wait_artifact_deploy again with the same artifactId and operationId." },
|
|
@@ -1087,6 +1088,8 @@ function structuredToolError(message) {
|
|
|
1087
1088
|
};
|
|
1088
1089
|
}
|
|
1089
1090
|
function recoveryErrorCode(message) {
|
|
1091
|
+
if (/^platform_harness_http_error:401(?::|$)/.test(message))
|
|
1092
|
+
return "authorization_required";
|
|
1090
1093
|
const known = [
|
|
1091
1094
|
"artifact_delete_plan_stale",
|
|
1092
1095
|
"artifact_deploy_wait_timeout",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": {
|
|
4
4
|
"name": "@topline-build/harness-mcp",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.2",
|
|
6
6
|
"bin": {
|
|
7
7
|
"topline-mcp": "dist/cli.js"
|
|
8
8
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"defaultVersion": "2025-11-25",
|
|
13
13
|
"server": {
|
|
14
14
|
"name": "topline-build-stdio",
|
|
15
|
-
"version": "0.5.
|
|
15
|
+
"version": "0.5.2"
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"generatedFrom": {
|
|
@@ -171,6 +171,11 @@
|
|
|
171
171
|
"recoveryAction": "Inspect the code and message, correct the input if needed, then retry the same tool."
|
|
172
172
|
},
|
|
173
173
|
"catalog": [
|
|
174
|
+
{
|
|
175
|
+
"code": "authorization_required",
|
|
176
|
+
"retryable": false,
|
|
177
|
+
"recoveryAction": "Clear only this connection's cached OAuth credentials, then reconnect the Build MCP through browser sign-in. If using a manual bearer token, replace the expired or revoked token. Recover existing artifact/deployment progress before retrying a write."
|
|
178
|
+
},
|
|
174
179
|
{
|
|
175
180
|
"code": "platform_harness_timeout",
|
|
176
181
|
"retryable": true,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Generated from `src/index.ts#BUILD_MCP_TOOLS`. Do not edit this file by hand.
|
|
4
4
|
|
|
5
|
-
Package: `@topline-build/harness-mcp@0.5.
|
|
5
|
+
Package: `@topline-build/harness-mcp@0.5.2`
|
|
6
6
|
Transport: `stdio`
|
|
7
7
|
Default protocol: `2025-11-25`
|
|
8
8
|
Canonical guide: https://topline.build/docs/build-mcp-guide
|
|
@@ -32,6 +32,7 @@ The first authenticated tool call normally opens browser approval. Set `TOPLINE_
|
|
|
32
32
|
|
|
33
33
|
Tool failures set `isError: true` and return `structuredContent.error` with `code`, `message`, `retryable`, and `recoveryAction`.
|
|
34
34
|
|
|
35
|
+
- `authorization_required` (not automatically retryable): Clear only this connection's cached OAuth credentials, then reconnect the Build MCP through browser sign-in. If using a manual bearer token, replace the expired or revoked token. Recover existing artifact/deployment progress before retrying a write.
|
|
35
36
|
- `platform_harness_timeout` (retryable): Retry the call. For a deployment, use platform_list_artifact_drafts to recover the artifact and platform_wait_artifact_deploy to resume progress.
|
|
36
37
|
- `platform_mcp_tool_error` (not automatically retryable): Read the returned error code, correct the request or OAuth scopes, then retry.
|
|
37
38
|
- `artifact_deploy_wait_timeout` (retryable): Call platform_wait_artifact_deploy again with the same artifactId and operationId.
|
package/package.json
CHANGED
package/scripts/certify-live.mjs
CHANGED
|
@@ -20,6 +20,23 @@ const EXPECTED_TOOLS = [
|
|
|
20
20
|
"platform_validate_artifact",
|
|
21
21
|
"platform_plan_artifact_draft_delete"
|
|
22
22
|
];
|
|
23
|
+
const PROVIDER_ENV_KEYS = [
|
|
24
|
+
"ANTHROPIC_API_KEY",
|
|
25
|
+
"TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY",
|
|
26
|
+
"TOPLINE_CERTIFICATION_ALLOW_BEDROCK",
|
|
27
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
28
|
+
"ANTHROPIC_MODEL",
|
|
29
|
+
"ANTHROPIC_SMALL_FAST_MODEL",
|
|
30
|
+
"DISABLE_PROMPT_CACHING",
|
|
31
|
+
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC",
|
|
32
|
+
"AWS_ACCESS_KEY_ID",
|
|
33
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
34
|
+
"AWS_SESSION_TOKEN",
|
|
35
|
+
"AWS_REGION",
|
|
36
|
+
"AWS_DEFAULT_REGION",
|
|
37
|
+
"AWS_EC2_METADATA_DISABLED",
|
|
38
|
+
"AWS_STS_REGIONAL_ENDPOINTS"
|
|
39
|
+
];
|
|
23
40
|
const packageJson = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
|
|
24
41
|
const manifest = JSON.parse(await readFile(new URL("../docs/generated/build-mcp-manifest.json", import.meta.url), "utf8"));
|
|
25
42
|
let args;
|
|
@@ -38,8 +55,7 @@ if (process.argv[2] === "--certification-read-only-server") {
|
|
|
38
55
|
}
|
|
39
56
|
|
|
40
57
|
async function runCertificationReadOnlyServer(values) {
|
|
41
|
-
delete process.env
|
|
42
|
-
delete process.env.TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY;
|
|
58
|
+
for (const key of PROVIDER_ENV_KEYS) delete process.env[key];
|
|
43
59
|
const opts = parseHarnessOptions(values, withoutManualToken(process.env));
|
|
44
60
|
const server = createHarnessMcpStdioServer(opts, ["platform_inspect_artifact_app"]);
|
|
45
61
|
await server.connect(new StdioServerTransport());
|
|
@@ -179,10 +195,7 @@ async function agentMediatedRead(name, command, scratch, apiUrl, appDir, workspa
|
|
|
179
195
|
if (!appDir) return skipped("certification_app_missing");
|
|
180
196
|
const server = {
|
|
181
197
|
command: process.execPath,
|
|
182
|
-
env:
|
|
183
|
-
ANTHROPIC_API_KEY: "",
|
|
184
|
-
TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY: ""
|
|
185
|
-
},
|
|
198
|
+
env: Object.fromEntries(PROVIDER_ENV_KEYS.map((key) => [key, ""])),
|
|
186
199
|
args: [
|
|
187
200
|
fileURLToPath(import.meta.url),
|
|
188
201
|
"--certification-read-only-server",
|
|
@@ -198,21 +211,20 @@ async function agentMediatedRead(name, command, scratch, apiUrl, appDir, workspa
|
|
|
198
211
|
const configPath = path.join(configDir, "mcp.json");
|
|
199
212
|
await writeFile(configPath, JSON.stringify({ mcpServers: { "topline-build": server } }, null, 2), "utf8");
|
|
200
213
|
const result = run(command, [
|
|
201
|
-
"--mcp-config", configPath, "--strict-mcp-config", "--
|
|
214
|
+
"--mcp-config", configPath, "--strict-mcp-config", "--bare",
|
|
202
215
|
"--tools", "", "--allowedTools", "mcp__topline-build__platform_inspect_artifact_app",
|
|
203
|
-
"--
|
|
216
|
+
"--dangerously-skip-permissions", "--no-chrome", "--disable-slash-commands",
|
|
204
217
|
"--no-session-persistence", "--max-budget-usd", "0.25",
|
|
205
|
-
"-p", "--output-format", "stream-json", prompt
|
|
218
|
+
"-p", "--verbose", "--output-format", "stream-json", prompt
|
|
206
219
|
], scratch, 180000, strictAgentEnvironment(process.env));
|
|
207
220
|
if (!result.ok) {
|
|
208
|
-
return
|
|
209
|
-
? skipped("provider_credentials_or_client_session_unavailable")
|
|
210
|
-
: failed("client_mediated_read_failed", result.exitCode);
|
|
221
|
+
return clientMediatedFailure(result);
|
|
211
222
|
}
|
|
212
223
|
const usedTool = hasToolCallEvidence(result.output, "platform_inspect_artifact_app");
|
|
213
224
|
const certified = hasAssistantCertificationEvidence(result.output);
|
|
214
|
-
|
|
215
|
-
|
|
225
|
+
const isolated = hasStrictClaudeInitEvidence(result.output);
|
|
226
|
+
return usedTool && certified && isolated
|
|
227
|
+
? passed({ tool: "platform_inspect_artifact_app", providerModelUsed: true, strictToolIsolation: true, provider: process.env.CLAUDE_CODE_USE_BEDROCK === "1" ? "bedrock" : "anthropic" })
|
|
216
228
|
: failed("client_mediated_tool_evidence_missing", result.exitCode);
|
|
217
229
|
}
|
|
218
230
|
|
|
@@ -330,6 +342,12 @@ async function certifyProtocol({ apiUrl, token, appDir, workspaceRoot }) {
|
|
|
330
342
|
}
|
|
331
343
|
|
|
332
344
|
function selfTestReport() {
|
|
345
|
+
const timedOutProbe = run({ executable: process.execPath, prefix: [] }, ["-e", "console.log('api key authentication required'); setInterval(() => {}, 1000)"], process.cwd(), 1000);
|
|
346
|
+
const timedOutFailure = clientMediatedFailure(timedOutProbe);
|
|
347
|
+
if (!timedOutProbe.timedOut || !authUnavailable(timedOutProbe.output) || timedOutFailure.status !== "failed" || timedOutFailure.reason !== "client_mediated_read_timed_out"
|
|
348
|
+
|| clientMediatedFailure({ timedOut: false, output: "not logged in", exitCode: 1 }).status !== "skipped") {
|
|
349
|
+
throw new Error("client_timeout_classification_self_test_failed");
|
|
350
|
+
}
|
|
333
351
|
const toolName = "platform_inspect_artifact_app";
|
|
334
352
|
const promptOnly = JSON.stringify({ type: "user", content: `Call ${toolName} and print TOPLINE_CLIENT_READ_CERTIFIED.` });
|
|
335
353
|
const toolEvent = JSON.stringify({ type: "item.completed", item: { type: "mcp_tool_call", tool: toolName } });
|
|
@@ -355,6 +373,18 @@ function selfTestReport() {
|
|
|
355
373
|
ANTHROPIC_API_KEY: "anthropic-secret",
|
|
356
374
|
TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY: "1"
|
|
357
375
|
});
|
|
376
|
+
const bedrockStrictEnvironment = strictAgentEnvironment({
|
|
377
|
+
PATH: "kept-path",
|
|
378
|
+
AWS_ACCESS_KEY_ID: "temporary-access-key",
|
|
379
|
+
AWS_SECRET_ACCESS_KEY: "temporary-secret-key",
|
|
380
|
+
AWS_SESSION_TOKEN: "temporary-session-token",
|
|
381
|
+
AWS_REGION: "us-west-2",
|
|
382
|
+
AWS_DEFAULT_REGION: "us-west-2",
|
|
383
|
+
CLAUDE_CODE_USE_BEDROCK: "1",
|
|
384
|
+
ANTHROPIC_MODEL: "global.anthropic.claude-sonnet-4-6",
|
|
385
|
+
ANTHROPIC_SMALL_FAST_MODEL: "global.anthropic.claude-sonnet-4-6",
|
|
386
|
+
TOPLINE_CERTIFICATION_ALLOW_BEDROCK: "1"
|
|
387
|
+
});
|
|
358
388
|
if (hasToolCallEvidence(promptOnly, toolName)
|
|
359
389
|
|| !hasToolCallEvidence(toolEvent, toolName)
|
|
360
390
|
|| hasAssistantCertificationEvidence(promptOnly)
|
|
@@ -367,7 +397,12 @@ function selfTestReport() {
|
|
|
367
397
|
|| strictEnvironment.USERPROFILE !== "kept-profile"
|
|
368
398
|
|| ["AWS_ACCESS_KEY_ID", "DATABASE_URL", "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "CURSOR_API_KEY", "TOPLINE_MCP_TOKEN"].some((key) => key in strictEnvironment)
|
|
369
399
|
|| optedInStrictEnvironment.ANTHROPIC_API_KEY !== "anthropic-secret"
|
|
370
|
-
|| "TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY" in optedInStrictEnvironment
|
|
400
|
+
|| "TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY" in optedInStrictEnvironment
|
|
401
|
+
|| bedrockStrictEnvironment.CLAUDE_CODE_USE_BEDROCK !== "1"
|
|
402
|
+
|| bedrockStrictEnvironment.AWS_ACCESS_KEY_ID !== "temporary-access-key"
|
|
403
|
+
|| bedrockStrictEnvironment.AWS_SECRET_ACCESS_KEY !== "temporary-secret-key"
|
|
404
|
+
|| bedrockStrictEnvironment.AWS_SESSION_TOKEN !== "temporary-session-token"
|
|
405
|
+
|| "TOPLINE_CERTIFICATION_ALLOW_BEDROCK" in bedrockStrictEnvironment) {
|
|
371
406
|
throw new Error("client_tool_evidence_self_test_failed");
|
|
372
407
|
}
|
|
373
408
|
return {
|
|
@@ -435,7 +470,7 @@ function clientCommand(name) {
|
|
|
435
470
|
return { executable, prefix: [] };
|
|
436
471
|
}
|
|
437
472
|
|
|
438
|
-
function run(command, commandArgs, cwd, timeout = 30000, env =
|
|
473
|
+
function run(command, commandArgs, cwd, timeout = 30000, env = clientProbeEnvironment(process.env)) {
|
|
439
474
|
const result = spawnSync(command.executable, [...command.prefix, ...commandArgs], {
|
|
440
475
|
cwd,
|
|
441
476
|
encoding: "utf8",
|
|
@@ -446,14 +481,22 @@ function run(command, commandArgs, cwd, timeout = 30000, env = withoutManualToke
|
|
|
446
481
|
return {
|
|
447
482
|
ok: result.status === 0,
|
|
448
483
|
missing: result.error?.code === "ENOENT",
|
|
484
|
+
timedOut: result.error?.code === "ETIMEDOUT",
|
|
449
485
|
exitCode: result.status,
|
|
450
486
|
stdout: result.stdout || "",
|
|
451
487
|
output: `${result.stdout || ""}\n${result.stderr || ""}`
|
|
452
488
|
};
|
|
453
489
|
}
|
|
454
490
|
|
|
491
|
+
function clientMediatedFailure(result) {
|
|
492
|
+
if (result.timedOut) return failed("client_mediated_read_timed_out", result.exitCode);
|
|
493
|
+
return authUnavailable(result.output)
|
|
494
|
+
? skipped("provider_credentials_or_client_session_unavailable")
|
|
495
|
+
: failed("client_mediated_read_failed", result.exitCode);
|
|
496
|
+
}
|
|
497
|
+
|
|
455
498
|
function authUnavailable(output) {
|
|
456
|
-
return /not logged in|not authenticated|authentication required|api key|login required|please login|sign in/i.test(output);
|
|
499
|
+
return /not logged in|not authenticated|authentication required|api key|login required|please login|sign in|unable to locate credentials|security token|AccessDeniedException|UnrecognizedClientException/i.test(output);
|
|
457
500
|
}
|
|
458
501
|
|
|
459
502
|
function hasToolCallEvidence(output, toolName) {
|
|
@@ -468,6 +511,29 @@ function hasToolCallEvidence(output, toolName) {
|
|
|
468
511
|
return false;
|
|
469
512
|
}
|
|
470
513
|
|
|
514
|
+
function hasStrictClaudeInitEvidence(output) {
|
|
515
|
+
for (const line of output.split(/\r?\n/)) {
|
|
516
|
+
if (!line.trim().startsWith("{")) continue;
|
|
517
|
+
try {
|
|
518
|
+
const value = JSON.parse(line);
|
|
519
|
+
if (value?.type !== "system" || value?.subtype !== "init") continue;
|
|
520
|
+
return Array.isArray(value.tools)
|
|
521
|
+
&& value.tools.length === 1
|
|
522
|
+
&& value.tools[0] === "mcp__topline-build__platform_inspect_artifact_app"
|
|
523
|
+
&& Array.isArray(value.mcp_servers)
|
|
524
|
+
&& value.mcp_servers.length === 1
|
|
525
|
+
&& value.mcp_servers[0]?.name === "topline-build"
|
|
526
|
+
&& value.mcp_servers[0]?.status === "connected"
|
|
527
|
+
&& value.permissionMode === "bypassPermissions"
|
|
528
|
+
&& Array.isArray(value.slash_commands)
|
|
529
|
+
&& value.slash_commands.length === 0;
|
|
530
|
+
} catch {
|
|
531
|
+
// Only the structured Claude init event can prove the effective tool set.
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
|
|
471
537
|
function containsToolCall(value, toolName) {
|
|
472
538
|
if (!value || typeof value !== "object") return false;
|
|
473
539
|
const type = typeof value.type === "string" ? value.type : "";
|
|
@@ -510,17 +576,34 @@ function withoutManualToken(source) {
|
|
|
510
576
|
}
|
|
511
577
|
|
|
512
578
|
function strictAgentEnvironment(source) {
|
|
579
|
+
const env = clientProbeEnvironment(source);
|
|
580
|
+
if (source.TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY === "1" && source.ANTHROPIC_API_KEY) {
|
|
581
|
+
env.ANTHROPIC_API_KEY = source.ANTHROPIC_API_KEY;
|
|
582
|
+
}
|
|
583
|
+
const bedrockCredentialKeys = ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"];
|
|
584
|
+
if (source.TOPLINE_CERTIFICATION_ALLOW_BEDROCK === "1"
|
|
585
|
+
&& source.CLAUDE_CODE_USE_BEDROCK === "1"
|
|
586
|
+
&& bedrockCredentialKeys.every((key) => typeof source[key] === "string" && source[key].length > 0)) {
|
|
587
|
+
for (const key of [
|
|
588
|
+
...bedrockCredentialKeys,
|
|
589
|
+
"AWS_REGION", "AWS_DEFAULT_REGION", "AWS_EC2_METADATA_DISABLED", "AWS_STS_REGIONAL_ENDPOINTS",
|
|
590
|
+
"CLAUDE_CODE_USE_BEDROCK", "ANTHROPIC_MODEL", "ANTHROPIC_SMALL_FAST_MODEL",
|
|
591
|
+
"DISABLE_PROMPT_CACHING", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC"
|
|
592
|
+
]) {
|
|
593
|
+
if (typeof source[key] === "string" && source[key].length > 0) env[key] = source[key];
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return env;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function clientProbeEnvironment(source) {
|
|
513
600
|
const allowed = new Set([
|
|
514
601
|
"ALL_PROXY", "APPDATA", "CI", "COMSPEC", "FORCE_COLOR", "HTTP_PROXY", "HTTPS_PROXY",
|
|
515
602
|
"LANG", "LC_ALL", "LOCALAPPDATA", "NODE_EXTRA_CA_CERTS", "NO_COLOR", "NO_PROXY", "PATH",
|
|
516
603
|
"PATHEXT", "PROGRAMDATA", "SSL_CERT_DIR", "SSL_CERT_FILE", "SYSTEMROOT", "TEMP", "TMP",
|
|
517
604
|
"USERPROFILE", "WINDIR"
|
|
518
605
|
]);
|
|
519
|
-
|
|
520
|
-
if (source.TOPLINE_CERTIFICATION_ALLOW_ANTHROPIC_API_KEY === "1" && source.ANTHROPIC_API_KEY) {
|
|
521
|
-
env.ANTHROPIC_API_KEY = source.ANTHROPIC_API_KEY;
|
|
522
|
-
}
|
|
523
|
-
return env;
|
|
606
|
+
return Object.fromEntries(Object.entries(source).filter(([key]) => allowed.has(key.toUpperCase())));
|
|
524
607
|
}
|
|
525
608
|
|
|
526
609
|
function structured(result) {
|