mtech-ai-local-runner 0.1.26 → 0.1.28
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
|
@@ -10,6 +10,26 @@ The package stores safe runner configuration locally and keeps OAuth refresh cre
|
|
|
10
10
|
|
|
11
11
|
Public npm installation requires no npm account or publishing OTP. Setup requires Gateway OAuth login, and local Claude Code must already be authenticated (`claude auth status`).
|
|
12
12
|
|
|
13
|
+
## 0.1.28: completion receipt wire compatibility
|
|
14
|
+
|
|
15
|
+
Completion transport separates local timing/process observations from the strict
|
|
16
|
+
official-exec v2/v3 security receipt without changing its authority fields or
|
|
17
|
+
Gateway validation. Other receipt protocols and the original caller result are
|
|
18
|
+
unchanged. The existing 0.1.27 two-document actual acceptance and its same-Job
|
|
19
|
+
completion recovery are recorded separately; installing this patch does not
|
|
20
|
+
rerun Codex, alter personal login/settings or update the daemon.
|
|
21
|
+
|
|
22
|
+
## 0.1.27: explicit job MCP exposure
|
|
23
|
+
|
|
24
|
+
The job-local MCP omits deferred and Code Mode surfaces so the inspected ordinary
|
|
25
|
+
MCP path keeps its tools directly available. Server authentication, enabled tools
|
|
26
|
+
and scoped read-only/private-path checks remain unchanged. Exact-binary no-model
|
|
27
|
+
inspection accepted the configuration and registered four synthetic tools;
|
|
28
|
+
the subsequent separately approved actual run read both documents successfully.
|
|
29
|
+
The initial model-request tool list was not captured; observed scoped reads are
|
|
30
|
+
distinct evidence from a complete model-catalog inspection.
|
|
31
|
+
Foreground installation does not run Codex or update the daemon.
|
|
32
|
+
|
|
13
33
|
## 0.1.26: compiled private-file denial compatibility
|
|
14
34
|
|
|
15
35
|
The compiled `.env.*` blocked-path rule now denies that private-file family
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
export const CODEX_ISOLATION_EXEC_FLAGS = Object.freeze([
|
|
7
7
|
"--ignore-user-config", "--ignore-rules", "--ephemeral", "--strict-config", "--json",
|
|
8
8
|
]);
|
|
9
|
+
// Job MCP tools must be in the initial model catalog, not discoverable only via
|
|
10
|
+
// tool_search or nested Code Mode. This changes exposure, not tool authority.
|
|
11
|
+
export const CODEX_JOB_MCP_OMIT_SURFACES = Object.freeze(['code_mode', 'deferred']);
|
|
9
12
|
export const CODEX_ISOLATION_CONFIG_OVERRIDES = Object.freeze([
|
|
10
13
|
"analytics.enabled=false",
|
|
11
14
|
"project_doc_max_bytes=0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isAbsolute } from "node:path";
|
|
2
|
-
import { CODEX_ISOLATION_EXEC_FLAGS, CODEX_ISOLATION_CONFIG_OVERRIDES } from "./compatibility.js";
|
|
2
|
+
import { CODEX_ISOLATION_EXEC_FLAGS, CODEX_ISOLATION_CONFIG_OVERRIDES, CODEX_JOB_MCP_OMIT_SURFACES } from "./compatibility.js";
|
|
3
3
|
import { codexControlDenials } from './scratch.js';
|
|
4
4
|
/** Candidate invocation; execution still requires independent compatibility admission. */
|
|
5
5
|
export function buildCodexInvocation(input) {
|
|
@@ -22,7 +22,7 @@ export function buildCodexInvocation(input) {
|
|
|
22
22
|
`permissions.local_job.filesystem={":minimal"="read",${deniedFiles}}`,
|
|
23
23
|
"permissions.local_job.network.enabled=false",
|
|
24
24
|
// Only this job server is preauthorized: every operation is checked by Runner policy.
|
|
25
|
-
`mcp_servers={ai_local={url=${JSON.stringify(endpoint.toString())},bearer_token_env_var="AI_GATEWAY_JOB_MCP_TOKEN",required=true,default_tools_approval_mode="approve",enabled_tools=["local_read","local_search","local_edit","local_test"]}}`,
|
|
25
|
+
`mcp_servers={ai_local={url=${JSON.stringify(endpoint.toString())},bearer_token_env_var="AI_GATEWAY_JOB_MCP_TOKEN",required=true,default_tools_approval_mode="approve",enabled_tools=["local_read","local_search","local_edit","local_test"],omit_tools_from=${JSON.stringify(CODEX_JOB_MCP_OMIT_SURFACES)}}}`,
|
|
26
26
|
];
|
|
27
27
|
const env = { HOME: input.env.HOME, AI_GATEWAY_JOB_MCP_TOKEN: input.endpoint.token };
|
|
28
28
|
for (const key of ["PATH", "USER", "LOGNAME", "LANG", "LC_ALL", "TMPDIR", "CODEX_HOME"]) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { record } from './stdio-rpc.js';
|
|
3
|
-
import { CODEX_ISOLATION_CONFIG_OVERRIDES } from './compatibility.js';
|
|
3
|
+
import { CODEX_ISOLATION_CONFIG_OVERRIDES, CODEX_JOB_MCP_OMIT_SURFACES } from './compatibility.js';
|
|
4
4
|
import { localToolInventory } from '../../safety/local-tool-server.js';
|
|
5
5
|
import { codexControlDenials } from './scratch.js';
|
|
6
6
|
export const canonical = (value) => JSON.stringify(normalize(value));
|
|
@@ -102,10 +102,11 @@ export function validateNativeConfig(value, requirements, pin) {
|
|
|
102
102
|
const server = record(servers.ai_local);
|
|
103
103
|
if (server.url !== pin.endpoint || server.bearer_token_env_var !== 'AI_GATEWAY_JOB_MCP_TOKEN'
|
|
104
104
|
|| server.required !== true || server.enabled !== true || server.default_tools_approval_mode !== 'approve'
|
|
105
|
+
|| canonical(server.omit_tools_from) !== canonical(CODEX_JOB_MCP_OMIT_SURFACES)
|
|
105
106
|
|| canonical([...(server.enabled_tools ?? [])].sort()) !== canonical(localToolInventory().map(t => t.name).sort()))
|
|
106
107
|
reject();
|
|
107
108
|
for (const k of Object.keys(server))
|
|
108
|
-
if (!['url', 'bearer_token_env_var', 'environment_id', 'enabled', 'required', 'tool_timeout_sec', 'default_tools_approval_mode', 'enabled_tools'].includes(k))
|
|
109
|
+
if (!['url', 'bearer_token_env_var', 'environment_id', 'enabled', 'required', 'tool_timeout_sec', 'default_tools_approval_mode', 'enabled_tools', 'omit_tools_from'].includes(k))
|
|
109
110
|
reject();
|
|
110
111
|
return fingerprint({ config: c, requirements: req, ...(pin.accountSources ? { accountSources: pin.accountSources.fingerprint } : {}) });
|
|
111
112
|
}
|
|
@@ -481,13 +481,25 @@ export class McpGatewayClient {
|
|
|
481
481
|
};
|
|
482
482
|
}
|
|
483
483
|
async completeLocalJob(input) {
|
|
484
|
+
let result = input.result;
|
|
485
|
+
const receipt = result.security_receipt;
|
|
486
|
+
if (receipt && !Array.isArray(receipt) && receipt.transport === "official_exec_v1"
|
|
487
|
+
&& ["cli-exec-job-security-receipt-v2", "cli-exec-job-security-receipt-v3"].includes(String(receipt.receipt_version))) {
|
|
488
|
+
// These local observations are not part of the strict Gateway authority
|
|
489
|
+
// receipt. Preserve the original locally and every other field unchanged;
|
|
490
|
+
// unknown authority fields must still reach, and be rejected by, Gateway.
|
|
491
|
+
const authority = { ...receipt };
|
|
492
|
+
delete authority.preparation_timing;
|
|
493
|
+
delete authority.launch_process;
|
|
494
|
+
result = { ...result, security_receipt: authority };
|
|
495
|
+
}
|
|
484
496
|
await this.callTool("local_agent_job_complete", {
|
|
485
497
|
job_id: input.jobId,
|
|
486
498
|
generation: input.generation,
|
|
487
499
|
lease_token: input.leaseToken,
|
|
488
500
|
runner_id: this.runnerId,
|
|
489
501
|
status: input.status,
|
|
490
|
-
result
|
|
502
|
+
result,
|
|
491
503
|
});
|
|
492
504
|
}
|
|
493
505
|
async heartbeatLocalJob(input) {
|