@amaster.ai/employee-runtime-connector 0.1.1-beta.3 → 0.1.1-beta.5
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/dist/amaster-runtime-daemon.mjs +640 -64
- package/dist/amaster-runtime.mjs +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// MirrorX runtime connector daemon bundle.
|
|
3
3
|
|
|
4
4
|
// src/amaster-runtime-daemon.mjs
|
|
5
|
-
import { createHash as
|
|
5
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
6
6
|
import { chmodSync as chmodSync6, copyFileSync as copyFileSync3, existsSync as existsSync14, lstatSync as lstatSync7, mkdirSync as mkdirSync9, mkdtempSync, readFileSync as readFileSync11, readdirSync as readdirSync9, realpathSync as realpathSync5, renameSync as renameSync6, rmSync as rmSync7, statSync as statSync7, symlinkSync as symlinkSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
|
|
7
7
|
import { arch as arch3, homedir as homedir3, hostname as hostname2, platform as platform3, tmpdir } from "node:os";
|
|
8
8
|
import { basename as basename6, delimiter as delimiter2, dirname as dirname9, extname as extname2, isAbsolute as isAbsolute8, join as join15, relative as relative9, resolve as resolve12 } from "node:path";
|
|
@@ -1560,7 +1560,7 @@ function reconcileManagedCodexMcpProfiles(rootPath, options = {}) {
|
|
|
1560
1560
|
}
|
|
1561
1561
|
|
|
1562
1562
|
// src/amaster-runtime-daemon/pi-managed-mcp-profile.mjs
|
|
1563
|
-
import { createHash as
|
|
1563
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
1564
1564
|
import {
|
|
1565
1565
|
chmodSync as chmodSync2,
|
|
1566
1566
|
copyFileSync,
|
|
@@ -1965,15 +1965,247 @@ function managedPiMcpArgsNormalizerExtensionSource() {
|
|
|
1965
1965
|
].join("\n\n");
|
|
1966
1966
|
}
|
|
1967
1967
|
|
|
1968
|
+
// src/amaster-runtime-daemon/pi-effective-tools-attestor.mjs
|
|
1969
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
1970
|
+
var MANAGED_PI_EFFECTIVE_TOOLS_ATTESTOR_FILENAME = "amaster-effective-tools-attestor.js";
|
|
1971
|
+
var MANAGED_PI_EFFECTIVE_TOOLS_SCHEMA_VERSION = "amaster.pi-effective-tools.v1";
|
|
1972
|
+
function normalizedSchema(value, adapterNormalized) {
|
|
1973
|
+
const schema = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1974
|
+
if (!adapterNormalized) return schema;
|
|
1975
|
+
const { $schema: _schema, additionalProperties: _additionalProperties, ...normalized } = schema;
|
|
1976
|
+
return normalized;
|
|
1977
|
+
}
|
|
1978
|
+
function stablePiJson(value) {
|
|
1979
|
+
if (value === null || value === void 0 || typeof value !== "object") {
|
|
1980
|
+
const serialized = JSON.stringify(value);
|
|
1981
|
+
return serialized === void 0 ? "undefined" : serialized;
|
|
1982
|
+
}
|
|
1983
|
+
if (Array.isArray(value)) return `[${value.map(stablePiJson).join(",")}]`;
|
|
1984
|
+
const keys = Object.keys(value).sort();
|
|
1985
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${stablePiJson(value[key])}`).join(",")}}`;
|
|
1986
|
+
}
|
|
1987
|
+
function stablePiToolSchemaHash(schema, options = {}) {
|
|
1988
|
+
return createHash2("sha256").update(stablePiJson(normalizedSchema(schema, options.adapterNormalized === true))).digest("hex");
|
|
1989
|
+
}
|
|
1990
|
+
function stablePiEffectiveToolSetHash(entries) {
|
|
1991
|
+
const normalized = entries.map((entry) => ({ name: entry.name, schemaHash: entry.schemaHash ?? entry.effectiveSchemaHash })).sort((left, right) => left.name.localeCompare(right.name));
|
|
1992
|
+
return createHash2("sha256").update(stablePiJson(normalized)).digest("hex");
|
|
1993
|
+
}
|
|
1994
|
+
function stablePiDirectCatalogSetHash(entries) {
|
|
1995
|
+
const normalized = entries.map((entry) => ({ name: entry.name, exposedName: entry.exposedName, schemaHash: entry.schemaHash, riskLevel: entry.riskLevel })).sort((left, right) => left.name.localeCompare(right.name));
|
|
1996
|
+
return createHash2("sha256").update(stablePiJson(normalized)).digest("hex");
|
|
1997
|
+
}
|
|
1998
|
+
function managedPiEffectiveToolsAttestorExtensionSource() {
|
|
1999
|
+
return String.raw`import { createHash } from "node:crypto";
|
|
2000
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2001
|
+
import { fileURLToPath } from "node:url";
|
|
2002
|
+
import { Value } from "typebox/value";
|
|
2003
|
+
|
|
2004
|
+
const SCHEMA_VERSION = ${JSON.stringify(MANAGED_PI_EFFECTIVE_TOOLS_SCHEMA_VERSION)};
|
|
2005
|
+
|
|
2006
|
+
function record(value) {
|
|
2007
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
function stableJson(value) {
|
|
2011
|
+
if (value === null || value === undefined || typeof value !== "object") {
|
|
2012
|
+
const serialized = JSON.stringify(value);
|
|
2013
|
+
return serialized === undefined ? "undefined" : serialized;
|
|
2014
|
+
}
|
|
2015
|
+
if (Array.isArray(value)) return "[" + value.map(stableJson).join(",") + "]";
|
|
2016
|
+
const keys = Object.keys(value).sort();
|
|
2017
|
+
return "{" + keys.map((key) => JSON.stringify(key) + ":" + stableJson(value[key])).join(",") + "}";
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
function sha256(value) {
|
|
2021
|
+
return createHash("sha256").update(value).digest("hex");
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
function schemaHash(value) {
|
|
2025
|
+
return sha256(stableJson(record(value)));
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
function toolSetHash(entries) {
|
|
2029
|
+
return sha256(stableJson(entries
|
|
2030
|
+
.map((entry) => ({ name: entry.name, schemaHash: entry.schemaHash }))
|
|
2031
|
+
.sort((left, right) => left.name.localeCompare(right.name))));
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
function requiredPath(name) {
|
|
2035
|
+
const value = process.env[name];
|
|
2036
|
+
if (typeof value !== "string" || value.trim() === "") throw new Error(name + " is required");
|
|
2037
|
+
return value;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
function sourceIsMcpAdapter(sourceInfo) {
|
|
2041
|
+
return stableJson(sourceInfo).includes("pi-mcp-adapter");
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
function safeWriteReceipt(receiptPath, receipt) {
|
|
2045
|
+
writeFileSync(receiptPath, JSON.stringify(receipt) + "\n", { encoding: "utf8", mode: 0o600 });
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
function validationErrorPath(error) {
|
|
2049
|
+
if (typeof error.path === "string" && error.path) return error.path;
|
|
2050
|
+
const base = typeof error.instancePath === "string" ? error.instancePath : "";
|
|
2051
|
+
const params = record(error.params);
|
|
2052
|
+
const additional = Array.isArray(params.additionalProperties) ? params.additionalProperties[0] : null;
|
|
2053
|
+
if (typeof additional === "string" && additional) return base + "/" + additional;
|
|
2054
|
+
const required = Array.isArray(params.requiredProperties) ? params.requiredProperties[0] : null;
|
|
2055
|
+
if (typeof required === "string" && required) return base + "/" + required;
|
|
2056
|
+
return base || "/";
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
function inputErrorReason(schema, input) {
|
|
2060
|
+
const errors = [...Value.Errors(schema, input)];
|
|
2061
|
+
if (errors.length === 0) return null;
|
|
2062
|
+
return errors.slice(0, 8).map((error) => validationErrorPath(error) + ": " + error.message).join("; ");
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
export default function amasterEffectiveToolsAttestor(pi) {
|
|
2066
|
+
const mode = process.env.AMASTER_PI_EFFECTIVE_TOOLS_MODE;
|
|
2067
|
+
if (mode !== "probe" && mode !== "enforce") return;
|
|
2068
|
+
const manifestPath = requiredPath("AMASTER_PI_EFFECTIVE_TOOLS_MANIFEST");
|
|
2069
|
+
const receiptPath = requiredPath("AMASTER_PI_EFFECTIVE_TOOLS_RECEIPT");
|
|
2070
|
+
const cachePath = requiredPath("AMASTER_PI_EFFECTIVE_TOOLS_CACHE");
|
|
2071
|
+
const configPath = requiredPath("AMASTER_PI_EFFECTIVE_TOOLS_CONFIG");
|
|
2072
|
+
|
|
2073
|
+
pi.on("session_start", async () => {
|
|
2074
|
+
let receipt;
|
|
2075
|
+
try {
|
|
2076
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
2077
|
+
if (manifest.schemaVersion !== SCHEMA_VERSION || manifest.serverName !== "amaster") {
|
|
2078
|
+
throw new Error("effective tool manifest identity mismatch");
|
|
2079
|
+
}
|
|
2080
|
+
const sourceDigest = sha256(readFileSync(fileURLToPath(import.meta.url)));
|
|
2081
|
+
if (sourceDigest !== manifest.attestorSourceSha256) throw new Error("attestor source digest mismatch");
|
|
2082
|
+
const configDigest = sha256(readFileSync(configPath));
|
|
2083
|
+
if (configDigest !== manifest.configSha256) throw new Error("managed MCP config digest mismatch");
|
|
2084
|
+
const cacheDigest = sha256(readFileSync(cachePath));
|
|
2085
|
+
if (cacheDigest !== manifest.cacheSha256) throw new Error("managed MCP cache digest mismatch");
|
|
2086
|
+
|
|
2087
|
+
const expectedEntries = Array.isArray(manifest.entries) ? manifest.entries : [];
|
|
2088
|
+
if (expectedEntries.length === 0) throw new Error("effective tool manifest is empty");
|
|
2089
|
+
const expectedByName = new Map(expectedEntries.map((entry) => [entry.name, entry]));
|
|
2090
|
+
if (expectedByName.size !== expectedEntries.length) throw new Error("effective tool manifest has duplicate names");
|
|
2091
|
+
for (const entry of expectedEntries) {
|
|
2092
|
+
const validatorSelfTest = inputErrorReason(entry.schema, { __amasterUnexpected: true });
|
|
2093
|
+
if (!validatorSelfTest || !validatorSelfTest.includes("/__amasterUnexpected")) {
|
|
2094
|
+
throw new Error("strict input validator self-test failed for " + entry.name);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
const allTools = pi.getAllTools();
|
|
2099
|
+
if (allTools.some((tool) => typeof tool.name !== "string" || !tool.name)) {
|
|
2100
|
+
throw new Error("registered tool identity mismatch");
|
|
2101
|
+
}
|
|
2102
|
+
const activeToolNames = pi.getActiveTools();
|
|
2103
|
+
if (activeToolNames.some((name) => typeof name !== "string" || !name)) {
|
|
2104
|
+
throw new Error("active tool identity mismatch");
|
|
2105
|
+
}
|
|
2106
|
+
activeToolNames.sort();
|
|
2107
|
+
const activeToolNameSet = new Set(activeToolNames);
|
|
2108
|
+
const proxyPresent = allTools.some((tool) => tool.name === "mcp");
|
|
2109
|
+
const nonCatalogTools = activeToolNames.filter((name) => !expectedByName.has(name));
|
|
2110
|
+
const adapterTools = allTools.filter((tool) => sourceIsMcpAdapter(tool.sourceInfo));
|
|
2111
|
+
const directTools = adapterTools.filter((tool) => tool.name !== "mcp" && activeToolNameSet.has(tool.name)).map((tool) => ({
|
|
2112
|
+
name: tool.name,
|
|
2113
|
+
schemaHash: schemaHash(tool.parameters),
|
|
2114
|
+
}));
|
|
2115
|
+
const actualByName = new Map(directTools.map((entry) => [entry.name, entry]));
|
|
2116
|
+
const missing = [...expectedByName.keys()].filter((name) => !actualByName.has(name) || !activeToolNameSet.has(name)).sort();
|
|
2117
|
+
const unexpected = adapterTools
|
|
2118
|
+
.map((tool) => tool.name)
|
|
2119
|
+
.filter((name) => name !== "mcp" && !expectedByName.has(name))
|
|
2120
|
+
.sort();
|
|
2121
|
+
const schemaMismatches = [...expectedByName.entries()].flatMap(([name, expected]) => {
|
|
2122
|
+
const actual = actualByName.get(name);
|
|
2123
|
+
return actual && actual.schemaHash !== expected.effectiveSchemaHash
|
|
2124
|
+
? [{ name, expected: expected.effectiveSchemaHash, actual: actual.schemaHash }]
|
|
2125
|
+
: [];
|
|
2126
|
+
});
|
|
2127
|
+
const effectiveSetHash = toolSetHash(directTools);
|
|
2128
|
+
if (proxyPresent || nonCatalogTools.length > 0 || missing.length > 0 || unexpected.length > 0 || schemaMismatches.length > 0) {
|
|
2129
|
+
throw new Error("effective tool surface mismatch: proxy=" + proxyPresent + " nonCatalog=" + nonCatalogTools.join(",") + " missing=" + missing.join(",") + " unexpected=" + unexpected.join(",") + " schemas=" + schemaMismatches.map((entry) => entry.name).join(","));
|
|
2130
|
+
}
|
|
2131
|
+
if (effectiveSetHash !== manifest.effectiveSetHash) throw new Error("effective tool set hash mismatch");
|
|
2132
|
+
receipt = {
|
|
2133
|
+
schemaVersion: SCHEMA_VERSION,
|
|
2134
|
+
status: "attested",
|
|
2135
|
+
mode,
|
|
2136
|
+
proxyPresent,
|
|
2137
|
+
effectiveSetHash,
|
|
2138
|
+
effectiveTools: directTools.sort((left, right) => left.name.localeCompare(right.name)),
|
|
2139
|
+
effectiveToolBindings: expectedEntries
|
|
2140
|
+
.map((entry) => ({ canonicalName: entry.canonicalName, exposedName: entry.name, effectiveSchemaHash: entry.effectiveSchemaHash }))
|
|
2141
|
+
.sort((left, right) => left.canonicalName.localeCompare(right.canonicalName)),
|
|
2142
|
+
attestorSourceSha256: sourceDigest,
|
|
2143
|
+
configSha256: configDigest,
|
|
2144
|
+
cacheSha256: cacheDigest,
|
|
2145
|
+
strictInputValidatorSelfTest: true,
|
|
2146
|
+
modelInvocationStarted: false,
|
|
2147
|
+
attestedAt: new Date().toISOString(),
|
|
2148
|
+
};
|
|
2149
|
+
safeWriteReceipt(receiptPath, receipt);
|
|
2150
|
+
if (mode === "probe") process.exit(0);
|
|
2151
|
+
} catch (error) {
|
|
2152
|
+
receipt = {
|
|
2153
|
+
schemaVersion: SCHEMA_VERSION,
|
|
2154
|
+
status: "rejected",
|
|
2155
|
+
mode,
|
|
2156
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2157
|
+
modelInvocationStarted: false,
|
|
2158
|
+
attestedAt: new Date().toISOString(),
|
|
2159
|
+
};
|
|
2160
|
+
safeWriteReceipt(receiptPath, receipt);
|
|
2161
|
+
process.exit(78);
|
|
2162
|
+
}
|
|
2163
|
+
});
|
|
2164
|
+
|
|
2165
|
+
pi.on("tool_call", (event) => {
|
|
2166
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
2167
|
+
const entry = Array.isArray(manifest.entries)
|
|
2168
|
+
? manifest.entries.find((candidate) => candidate.name === event.toolName)
|
|
2169
|
+
: null;
|
|
2170
|
+
if (!entry) return;
|
|
2171
|
+
const reason = inputErrorReason(entry.schema, event.input);
|
|
2172
|
+
if (!reason) return;
|
|
2173
|
+
return { block: true, reason: "Governed tool input rejected: " + reason };
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
`;
|
|
2177
|
+
}
|
|
2178
|
+
|
|
1968
2179
|
// src/amaster-runtime-daemon/pi-managed-mcp-profile.mjs
|
|
1969
2180
|
var MANAGED_PI_MCP_TOOL_MODE = "proxy_only";
|
|
2181
|
+
var MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE = "direct_typed";
|
|
1970
2182
|
var MANAGED_PI_MCP_ARGS_NORMALIZATION = "json_string_control_characters_v1";
|
|
1971
2183
|
var MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME = "amaster-mcp-args-normalizer.js";
|
|
2184
|
+
function applyManagedPiToolAllowlist(args, profile) {
|
|
2185
|
+
const toolAllowlist = Array.isArray(profile?.toolAllowlist) ? profile.toolAllowlist.filter((name) => typeof name === "string" && name) : [];
|
|
2186
|
+
if (toolAllowlist.length === 0) return [...args];
|
|
2187
|
+
const printArgIndex = Math.max(args.lastIndexOf("-p"), args.lastIndexOf("--print"));
|
|
2188
|
+
if (printArgIndex < 0) throw new Error("pi_managed_mcp_invocation_invalid: print mode argument missing");
|
|
2189
|
+
return [
|
|
2190
|
+
...args.slice(0, printArgIndex),
|
|
2191
|
+
"--tools",
|
|
2192
|
+
toolAllowlist.join(","),
|
|
2193
|
+
...args.slice(printArgIndex)
|
|
2194
|
+
];
|
|
2195
|
+
}
|
|
1972
2196
|
function createManagedPiMcpProfileApi(options = {}) {
|
|
1973
2197
|
const spawnSyncImpl = typeof options.spawnSync === "function" ? options.spawnSync : spawnSync2;
|
|
1974
2198
|
const nowImpl = typeof options.now === "function" ? options.now : Date.now;
|
|
1975
2199
|
const SUPPORTED_SCHEMA_VERSION2 = "amaster.governed-mcp.v1";
|
|
1976
2200
|
const SUPPORTED_SERVER_NAME2 = "amaster";
|
|
2201
|
+
const DIRECT_CATALOG_SCHEMA_VERSION = "amaster.governed-mcp-direct-catalog.v1";
|
|
2202
|
+
const DIRECT_TYPED_V1_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
2203
|
+
"runtime_action.submit",
|
|
2204
|
+
"amaster.read_company_diagnosis",
|
|
2205
|
+
"amaster.publish_company_diagnosis_brief"
|
|
2206
|
+
]);
|
|
2207
|
+
const PROVIDER_SAFE_TOOL_NAME = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
2208
|
+
const PI_BUILTIN_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "bash", "edit", "write", "grep", "find", "ls", "mcp"]);
|
|
1977
2209
|
const MINIMUM_PI_VERSION = [0, 73, 1];
|
|
1978
2210
|
const MINIMUM_MCP_ADAPTER_VERSION = [2, 6, 1];
|
|
1979
2211
|
const MANAGED_BROWSER_USE_PACKAGE = "@amaster.ai/pi-browser-use";
|
|
@@ -2057,6 +2289,12 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2057
2289
|
]);
|
|
2058
2290
|
const FORBIDDEN_ARGV = /* @__PURE__ */ new Set([
|
|
2059
2291
|
"--no-tools",
|
|
2292
|
+
"--no-builtin-tools",
|
|
2293
|
+
"-nbt",
|
|
2294
|
+
"--tools",
|
|
2295
|
+
"-t",
|
|
2296
|
+
"--exclude-tools",
|
|
2297
|
+
"-xt",
|
|
2060
2298
|
"--no-extensions",
|
|
2061
2299
|
"--no-skills",
|
|
2062
2300
|
"--no-session",
|
|
@@ -2140,7 +2378,7 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2140
2378
|
nonEmpty2(session.invocationId, "nativeSession.invocationId");
|
|
2141
2379
|
const sourceWorkspacePath = nonEmpty2(session.cwd, "nativeSession.cwd");
|
|
2142
2380
|
const issueRoot = dirname3(runDir);
|
|
2143
|
-
const managedSourceRunDirName = `${sourceRunId}-${
|
|
2381
|
+
const managedSourceRunDirName = `${sourceRunId}-${createHash3("sha256").update(sourceRunId).digest("hex").slice(0, 8)}`;
|
|
2144
2382
|
const sourceRunDirs = readdirSync2(issueRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.isSymbolicLink() && (entry.name === sourceRunId || entry.name === managedSourceRunDirName)).map((entry) => join4(issueRoot, entry.name));
|
|
2145
2383
|
if (sourceRunDirs.length !== 1) {
|
|
2146
2384
|
throw new Error(`pi_managed_mcp_session_rollout_missing: expected one source run directory for ${sourceRunId}, received ${sourceRunDirs.length}`);
|
|
@@ -2185,6 +2423,82 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2185
2423
|
if (!Number.isFinite(value)) throw new Error("pi_managed_mcp_attestation_failed: invalid attestation clock");
|
|
2186
2424
|
return value;
|
|
2187
2425
|
}
|
|
2426
|
+
function sha256(value) {
|
|
2427
|
+
return createHash3("sha256").update(value).digest("hex");
|
|
2428
|
+
}
|
|
2429
|
+
function adapterServerConfigHash(definition) {
|
|
2430
|
+
return sha256(stablePiJson({
|
|
2431
|
+
command: definition.command,
|
|
2432
|
+
args: definition.args,
|
|
2433
|
+
env: definition.env,
|
|
2434
|
+
cwd: definition.cwd,
|
|
2435
|
+
url: definition.url,
|
|
2436
|
+
headers: definition.headers,
|
|
2437
|
+
auth: definition.auth,
|
|
2438
|
+
bearerToken: definition.bearerToken,
|
|
2439
|
+
bearerTokenEnv: definition.bearerTokenEnv,
|
|
2440
|
+
exposeResources: definition.exposeResources,
|
|
2441
|
+
excludeTools: definition.excludeTools
|
|
2442
|
+
}));
|
|
2443
|
+
}
|
|
2444
|
+
function validateDirectCatalog(gateway) {
|
|
2445
|
+
const catalog = record6(gateway.toolCatalog);
|
|
2446
|
+
if (catalog.schemaVersion !== DIRECT_CATALOG_SCHEMA_VERSION) {
|
|
2447
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog schema mismatch");
|
|
2448
|
+
}
|
|
2449
|
+
const tools = Array.isArray(catalog.tools) ? catalog.tools.map(record6) : [];
|
|
2450
|
+
if (tools.length !== DIRECT_TYPED_V1_TOOL_NAMES.size) {
|
|
2451
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog size mismatch");
|
|
2452
|
+
}
|
|
2453
|
+
const names = /* @__PURE__ */ new Set();
|
|
2454
|
+
const exposedNames = /* @__PURE__ */ new Set();
|
|
2455
|
+
const normalized = tools.map((tool) => {
|
|
2456
|
+
const name = nonEmpty2(tool.name, "toolCatalog.tools.name");
|
|
2457
|
+
if (!DIRECT_TYPED_V1_TOOL_NAMES.has(name) || names.has(name)) {
|
|
2458
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog name mismatch");
|
|
2459
|
+
}
|
|
2460
|
+
names.add(name);
|
|
2461
|
+
const exposedName = nonEmpty2(tool.exposedName, `toolCatalog.tools.exposedName:${name}`);
|
|
2462
|
+
if (!PROVIDER_SAFE_TOOL_NAME.test(exposedName) || PI_BUILTIN_TOOL_NAMES.has(exposedName)) {
|
|
2463
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool exposed name is unsafe for ${name}`);
|
|
2464
|
+
}
|
|
2465
|
+
if (exposedNames.has(exposedName)) {
|
|
2466
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool exposed name collision for ${exposedName}`);
|
|
2467
|
+
}
|
|
2468
|
+
exposedNames.add(exposedName);
|
|
2469
|
+
const inputSchema = record6(tool.inputSchema);
|
|
2470
|
+
if (inputSchema.type !== "object" || inputSchema.additionalProperties !== false) {
|
|
2471
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool schema is not strict for ${name}`);
|
|
2472
|
+
}
|
|
2473
|
+
const schemaHash = stablePiToolSchemaHash(inputSchema);
|
|
2474
|
+
if (tool.schemaHash !== schemaHash) {
|
|
2475
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool schema hash mismatch for ${name}`);
|
|
2476
|
+
}
|
|
2477
|
+
const riskLevel = nonEmpty2(tool.riskLevel, `toolCatalog.tools.riskLevel:${name}`);
|
|
2478
|
+
if (!(/* @__PURE__ */ new Set(["read", "write", "destructive"])).has(riskLevel)) {
|
|
2479
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool risk level mismatch for ${name}`);
|
|
2480
|
+
}
|
|
2481
|
+
return {
|
|
2482
|
+
name,
|
|
2483
|
+
exposedName,
|
|
2484
|
+
description: typeof tool.description === "string" ? tool.description : "",
|
|
2485
|
+
inputSchema,
|
|
2486
|
+
schemaHash,
|
|
2487
|
+
riskLevel,
|
|
2488
|
+
effectiveSchemaHash: stablePiToolSchemaHash(inputSchema, { adapterNormalized: true })
|
|
2489
|
+
};
|
|
2490
|
+
});
|
|
2491
|
+
const setHash = stablePiDirectCatalogSetHash(normalized.map((tool) => ({
|
|
2492
|
+
name: tool.name,
|
|
2493
|
+
exposedName: tool.exposedName,
|
|
2494
|
+
schemaHash: tool.schemaHash,
|
|
2495
|
+
riskLevel: tool.riskLevel
|
|
2496
|
+
})));
|
|
2497
|
+
if (catalog.setHash !== setHash) {
|
|
2498
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog set hash mismatch");
|
|
2499
|
+
}
|
|
2500
|
+
return { setHash, tools: normalized.sort((left, right) => left.name.localeCompare(right.name)) };
|
|
2501
|
+
}
|
|
2188
2502
|
function piExecutableIdentity(executorCommand) {
|
|
2189
2503
|
try {
|
|
2190
2504
|
const realPath = realpathSync2(executorCommand);
|
|
@@ -2192,8 +2506,8 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2192
2506
|
if (!executableStat.isFile() || executableStat.isSymbolicLink()) {
|
|
2193
2507
|
throw Object.assign(new Error("Pi executable is not a regular file"), { code: "EUNSAFE" });
|
|
2194
2508
|
}
|
|
2195
|
-
const contentSha256 =
|
|
2196
|
-
return `sha256:${
|
|
2509
|
+
const contentSha256 = createHash3("sha256").update(readFileSync3(realPath)).digest("hex");
|
|
2510
|
+
return `sha256:${createHash3("sha256").update(JSON.stringify({ realPath, contentSha256 })).digest("hex")}`;
|
|
2197
2511
|
} catch (error) {
|
|
2198
2512
|
const errorCode = typeof error?.code === "string" ? error.code : "UNKNOWN";
|
|
2199
2513
|
throw new Error(`pi_managed_mcp_attestation_failed: --version error=${errorCode}`);
|
|
@@ -2239,7 +2553,15 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2239
2553
|
throw new Error("pi_managed_mcp_invalid: Gateway authority mismatch");
|
|
2240
2554
|
}
|
|
2241
2555
|
if ((runtimeAuth.issueId ?? null) !== (headers["x-amaster-issue-id"] ?? null)) throw new Error("pi_managed_mcp_invalid: issue authority mismatch");
|
|
2242
|
-
|
|
2556
|
+
const mcpToolMode = gateway.mcpToolMode ?? MANAGED_PI_MCP_TOOL_MODE;
|
|
2557
|
+
if (mcpToolMode !== MANAGED_PI_MCP_TOOL_MODE && mcpToolMode !== MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE) {
|
|
2558
|
+
throw new Error("pi_managed_mcp_invalid: unsupported managed Pi MCP tool mode");
|
|
2559
|
+
}
|
|
2560
|
+
const directCatalog = mcpToolMode === MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE ? validateDirectCatalog(gateway) : null;
|
|
2561
|
+
if (mcpToolMode === MANAGED_PI_MCP_TOOL_MODE && gateway.toolCatalog !== void 0) {
|
|
2562
|
+
throw new Error("pi_managed_mcp_invalid: proxy-only authority cannot carry a direct tool catalog");
|
|
2563
|
+
}
|
|
2564
|
+
return { gateway, gatewayUrl, sessionToken, headers, runId, mcpToolMode, directCatalog };
|
|
2243
2565
|
}
|
|
2244
2566
|
function isSensitiveAuthKey2(key) {
|
|
2245
2567
|
const normalized = String(key).trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replaceAll("-", "_");
|
|
@@ -2259,7 +2581,7 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2259
2581
|
if (!ALLOWED_COMMAND_ENV2.has(name)) throw new Error(`pi_managed_mcp_env_injection_blocked: ${name}`);
|
|
2260
2582
|
}
|
|
2261
2583
|
const args = Array.isArray(input.extraArgs) ? input.extraArgs.map(String) : [];
|
|
2262
|
-
if (args.some((arg) => FORBIDDEN_ARGV.has(arg) || arg.startsWith("--session=") || arg.startsWith("--fork=") || arg.startsWith("--session-dir=") || arg.startsWith("--extension=") || arg.startsWith("--package=") || arg.startsWith("--settings="))) {
|
|
2584
|
+
if (args.some((arg) => FORBIDDEN_ARGV.has(arg) || arg.startsWith("--tools=") || arg.startsWith("--exclude-tools=") || arg.startsWith("--session=") || arg.startsWith("--fork=") || arg.startsWith("--session-dir=") || arg.startsWith("--extension=") || arg.startsWith("--package=") || arg.startsWith("--settings="))) {
|
|
2263
2585
|
throw new Error("pi_managed_mcp_config_override_blocked: Pi config/tool/session argv is forbidden for governed runs");
|
|
2264
2586
|
}
|
|
2265
2587
|
}
|
|
@@ -2404,8 +2726,13 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2404
2726
|
config: record6(sourceSettings["pi-telemetry"])
|
|
2405
2727
|
};
|
|
2406
2728
|
}
|
|
2407
|
-
function seedPiRuntime(sourceHome, agentDir, sourceAcquisition = null) {
|
|
2729
|
+
function seedPiRuntime(sourceHome, agentDir, sourceAcquisition = null, mcpToolMode = MANAGED_PI_MCP_TOOL_MODE) {
|
|
2408
2730
|
const source = resolve2(nonEmpty2(sourceHome, "sourcePiHome"));
|
|
2731
|
+
const sourceStat = lstatSync2(source);
|
|
2732
|
+
if (!sourceStat.isDirectory() || sourceStat.isSymbolicLink()) {
|
|
2733
|
+
throw new Error("pi_managed_mcp_source_config_unsafe: Pi home");
|
|
2734
|
+
}
|
|
2735
|
+
chmodSync2(source, sourceStat.mode & 511 | 1);
|
|
2409
2736
|
const npmSource = join4(source, "npm");
|
|
2410
2737
|
const adapterPackagePath = join4(npmSource, "node_modules", "pi-mcp-adapter", "package.json");
|
|
2411
2738
|
if (!existsSync3(adapterPackagePath) || lstatSync2(adapterPackagePath).isSymbolicLink()) {
|
|
@@ -2455,10 +2782,17 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2455
2782
|
`);
|
|
2456
2783
|
const extensionsDir = join4(agentDir, "extensions");
|
|
2457
2784
|
mkdirSync3(extensionsDir, { recursive: true, mode: 448 });
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2785
|
+
if (mcpToolMode === MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE) {
|
|
2786
|
+
writePrivateFile2(
|
|
2787
|
+
join4(extensionsDir, MANAGED_PI_EFFECTIVE_TOOLS_ATTESTOR_FILENAME),
|
|
2788
|
+
managedPiEffectiveToolsAttestorExtensionSource()
|
|
2789
|
+
);
|
|
2790
|
+
} else {
|
|
2791
|
+
writePrivateFile2(
|
|
2792
|
+
join4(extensionsDir, MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME),
|
|
2793
|
+
managedPiMcpArgsNormalizerExtensionSource()
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2462
2796
|
if (sourceAcquisition && !copyPrivateFile(
|
|
2463
2797
|
join4(source, "extensions", "amaster-source-acquisition.js"),
|
|
2464
2798
|
join4(extensionsDir, "amaster-source-acquisition.js")
|
|
@@ -2551,9 +2885,62 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2551
2885
|
liveProbeAgeMs
|
|
2552
2886
|
};
|
|
2553
2887
|
}
|
|
2888
|
+
function attestDirectPiTools(executorCommand, env, input) {
|
|
2889
|
+
const result3 = spawnSyncImpl(executorCommand, [
|
|
2890
|
+
"--no-session",
|
|
2891
|
+
"--no-skills",
|
|
2892
|
+
"--no-context-files",
|
|
2893
|
+
"--no-builtin-tools",
|
|
2894
|
+
"--print",
|
|
2895
|
+
"probe effective tools"
|
|
2896
|
+
], {
|
|
2897
|
+
cwd: env.AMASTER_RUNTIME_EXECUTION_WORKDIR,
|
|
2898
|
+
env: { ...env, AMASTER_PI_EFFECTIVE_TOOLS_MODE: "probe" },
|
|
2899
|
+
encoding: "utf8",
|
|
2900
|
+
timeout: PI_ATTESTATION_TIMEOUT_MS,
|
|
2901
|
+
killSignal: "SIGKILL",
|
|
2902
|
+
maxBuffer: 1024 * 1024
|
|
2903
|
+
});
|
|
2904
|
+
if (result3.error) {
|
|
2905
|
+
const code = typeof result3.error.code === "string" ? result3.error.code : "UNKNOWN";
|
|
2906
|
+
throw new Error(`pi_managed_mcp_effective_tools_failed: probe error=${code}`);
|
|
2907
|
+
}
|
|
2908
|
+
if (result3.status !== 0) {
|
|
2909
|
+
let receiptError = "receipt unavailable";
|
|
2910
|
+
try {
|
|
2911
|
+
const rejectedReceipt = JSON.parse(readFileSync3(input.receiptPath, "utf8"));
|
|
2912
|
+
if (typeof rejectedReceipt.error === "string" && rejectedReceipt.error.length > 0) {
|
|
2913
|
+
receiptError = rejectedReceipt.error.slice(0, 512);
|
|
2914
|
+
}
|
|
2915
|
+
} catch {
|
|
2916
|
+
}
|
|
2917
|
+
throw new Error(`pi_managed_mcp_effective_tools_failed: probe exit=${result3.status ?? "unknown"} reason=${receiptError}`);
|
|
2918
|
+
}
|
|
2919
|
+
let receipt;
|
|
2920
|
+
try {
|
|
2921
|
+
receipt = JSON.parse(readFileSync3(input.receiptPath, "utf8"));
|
|
2922
|
+
} catch {
|
|
2923
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: probe receipt missing");
|
|
2924
|
+
}
|
|
2925
|
+
if (receipt.status !== "attested" || receipt.mode !== "probe" || receipt.proxyPresent !== false || receipt.effectiveSetHash !== input.effectiveSetHash || receipt.attestorSourceSha256 !== input.attestorSourceSha256 || receipt.configSha256 !== input.configSha256 || receipt.cacheSha256 !== input.cacheSha256) {
|
|
2926
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: probe receipt mismatch");
|
|
2927
|
+
}
|
|
2928
|
+
if (sha256(readFileSync3(input.configPath)) !== input.configSha256) {
|
|
2929
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: config drifted during probe");
|
|
2930
|
+
}
|
|
2931
|
+
if (sha256(readFileSync3(input.cachePath)) !== input.cacheSha256) {
|
|
2932
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: cache drifted during probe");
|
|
2933
|
+
}
|
|
2934
|
+
return {
|
|
2935
|
+
effectiveToolSetHash: receipt.effectiveSetHash,
|
|
2936
|
+
effectiveToolProbeDigest: sha256(stablePiJson(receipt)),
|
|
2937
|
+
effectiveToolProbeAt: receipt.attestedAt,
|
|
2938
|
+
effectiveToolBindings: receipt.effectiveToolBindings
|
|
2939
|
+
};
|
|
2940
|
+
}
|
|
2554
2941
|
function prepareManagedPiMcpProfile2(input) {
|
|
2555
2942
|
assertInvocationIsolation2(input);
|
|
2556
|
-
const { gateway, gatewayUrl, sessionToken, headers, runId } = validateAuthority2(input);
|
|
2943
|
+
const { gateway, gatewayUrl, sessionToken, headers, runId, mcpToolMode, directCatalog } = validateAuthority2(input);
|
|
2557
2944
|
const runDir = resolve2(nonEmpty2(input.runDir, "runDir"));
|
|
2558
2945
|
const executorHome = resolve2(nonEmpty2(input.executorHome, "executorHome"));
|
|
2559
2946
|
if (!within4(executorHome, join4(runDir, "executors"))) throw new Error("pi_managed_mcp_owner_mismatch: executorHome is outside the managed run");
|
|
@@ -2580,24 +2967,82 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2580
2967
|
commandId: input.commandId
|
|
2581
2968
|
});
|
|
2582
2969
|
const sourcePiHome = nonEmpty2(input.baseEnv?.PI_CODING_AGENT_DIR ?? input.baseEnv?.PI_AGENT_HOME, "sourcePiHome");
|
|
2583
|
-
const seededRuntime = seedPiRuntime(sourcePiHome, piCodingAgentDir, input.sourceAcquisition);
|
|
2970
|
+
const seededRuntime = seedPiRuntime(sourcePiHome, piCodingAgentDir, input.sourceAcquisition, mcpToolMode);
|
|
2584
2971
|
const restoredNativeSession = restoreManagedPiSessionRollout(input, sessionsRoot, runDir, executorHome, authority);
|
|
2585
2972
|
const configPath = join4(piCodingAgentDir, "mcp.json");
|
|
2973
|
+
const directToolNames = directCatalog?.tools.map((tool) => tool.exposedName) ?? [];
|
|
2974
|
+
const serverConfig = {
|
|
2975
|
+
type: "http",
|
|
2976
|
+
url: gatewayUrl,
|
|
2977
|
+
headers: { Authorization: `Bearer ${sessionToken}`, ...headers },
|
|
2978
|
+
lifecycle: directCatalog ? "lazy" : "eager",
|
|
2979
|
+
...directCatalog ? { exposeResources: false, directTools: directToolNames } : {}
|
|
2980
|
+
};
|
|
2586
2981
|
const config = {
|
|
2587
2982
|
settings: {
|
|
2588
|
-
toolPrefix: "none"
|
|
2983
|
+
toolPrefix: "none",
|
|
2984
|
+
...directCatalog ? { disableProxyTool: true } : {}
|
|
2589
2985
|
},
|
|
2590
2986
|
mcpServers: {
|
|
2591
|
-
[SUPPORTED_SERVER_NAME2]:
|
|
2592
|
-
type: "http",
|
|
2593
|
-
url: gatewayUrl,
|
|
2594
|
-
headers: { Authorization: `Bearer ${sessionToken}`, ...headers },
|
|
2595
|
-
lifecycle: "eager"
|
|
2596
|
-
}
|
|
2987
|
+
[SUPPORTED_SERVER_NAME2]: serverConfig
|
|
2597
2988
|
}
|
|
2598
2989
|
};
|
|
2599
2990
|
writePrivateFile2(configPath, `${JSON.stringify(config, null, 2)}
|
|
2600
2991
|
`);
|
|
2992
|
+
let directAttestationInput = null;
|
|
2993
|
+
if (directCatalog) {
|
|
2994
|
+
const cachePath = join4(piCodingAgentDir, "mcp-cache.json");
|
|
2995
|
+
const cache = {
|
|
2996
|
+
version: 1,
|
|
2997
|
+
servers: {
|
|
2998
|
+
[SUPPORTED_SERVER_NAME2]: {
|
|
2999
|
+
configHash: adapterServerConfigHash(serverConfig),
|
|
3000
|
+
tools: directCatalog.tools.map((tool) => ({
|
|
3001
|
+
name: tool.exposedName,
|
|
3002
|
+
description: tool.description,
|
|
3003
|
+
inputSchema: tool.inputSchema
|
|
3004
|
+
})),
|
|
3005
|
+
resources: [],
|
|
3006
|
+
cachedAt: currentTimeMs()
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
};
|
|
3010
|
+
writePrivateFile2(cachePath, `${JSON.stringify(cache, null, 2)}
|
|
3011
|
+
`);
|
|
3012
|
+
const cacheSha256 = sha256(readFileSync3(cachePath));
|
|
3013
|
+
const attestorSourceSha256 = sha256(managedPiEffectiveToolsAttestorExtensionSource());
|
|
3014
|
+
const manifestPath = join4(piCodingAgentDir, "effective-tools-manifest.json");
|
|
3015
|
+
const receiptPath = join4(tmp, "effective-tools-receipt.json");
|
|
3016
|
+
const manifest = {
|
|
3017
|
+
schemaVersion: MANAGED_PI_EFFECTIVE_TOOLS_SCHEMA_VERSION,
|
|
3018
|
+
serverName: SUPPORTED_SERVER_NAME2,
|
|
3019
|
+
entries: directCatalog.tools.map((tool) => ({
|
|
3020
|
+
name: tool.exposedName,
|
|
3021
|
+
canonicalName: tool.name,
|
|
3022
|
+
schema: tool.inputSchema,
|
|
3023
|
+
effectiveSchemaHash: tool.effectiveSchemaHash
|
|
3024
|
+
})),
|
|
3025
|
+
effectiveSetHash: stablePiEffectiveToolSetHash(directCatalog.tools.map((tool) => ({
|
|
3026
|
+
name: tool.exposedName,
|
|
3027
|
+
schemaHash: tool.effectiveSchemaHash
|
|
3028
|
+
}))),
|
|
3029
|
+
attestorSourceSha256,
|
|
3030
|
+
configSha256: sha256(readFileSync3(configPath)),
|
|
3031
|
+
cacheSha256
|
|
3032
|
+
};
|
|
3033
|
+
writePrivateFile2(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
3034
|
+
`);
|
|
3035
|
+
directAttestationInput = {
|
|
3036
|
+
cachePath,
|
|
3037
|
+
manifestPath,
|
|
3038
|
+
receiptPath,
|
|
3039
|
+
cacheSha256,
|
|
3040
|
+
configPath,
|
|
3041
|
+
configSha256: sha256(readFileSync3(configPath)),
|
|
3042
|
+
attestorSourceSha256,
|
|
3043
|
+
effectiveSetHash: manifest.effectiveSetHash
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
2601
3046
|
const env = {
|
|
2602
3047
|
...buildIsolatedEnvironment2(input.baseEnv, input.commandEnv),
|
|
2603
3048
|
HOME: home,
|
|
@@ -2608,18 +3053,30 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2608
3053
|
"AMASTER-CLI_CODING_AGENT_SESSION_DIR": sessionsRoot,
|
|
2609
3054
|
PI_AGENT_MCP_SERVERS_FILE: configPath,
|
|
2610
3055
|
TMPDIR: tmp,
|
|
3056
|
+
...directAttestationInput ? {
|
|
3057
|
+
AMASTER_PI_EFFECTIVE_TOOLS_MODE: "enforce",
|
|
3058
|
+
AMASTER_PI_EFFECTIVE_TOOLS_MANIFEST: directAttestationInput.manifestPath,
|
|
3059
|
+
AMASTER_PI_EFFECTIVE_TOOLS_RECEIPT: directAttestationInput.receiptPath,
|
|
3060
|
+
AMASTER_PI_EFFECTIVE_TOOLS_CACHE: directAttestationInput.cachePath,
|
|
3061
|
+
AMASTER_PI_EFFECTIVE_TOOLS_CONFIG: directAttestationInput.configPath
|
|
3062
|
+
} : {},
|
|
2611
3063
|
...input.sourceAcquisition ? {
|
|
2612
3064
|
PI_BROWSER_USE_RUNTIME_READ_POLICY: "required"
|
|
2613
3065
|
} : {}
|
|
2614
3066
|
};
|
|
2615
3067
|
const executorAttestation = attestPi(nonEmpty2(input.executorCommand, "executorCommand"), env, configPath, config);
|
|
3068
|
+
const effectiveToolsAttestation = directAttestationInput ? attestDirectPiTools(nonEmpty2(input.executorCommand, "executorCommand"), env, directAttestationInput) : {};
|
|
2616
3069
|
const attestationFacts = {
|
|
2617
3070
|
connectorVersion: nonEmpty2(input.connectorVersion, "connectorVersion"),
|
|
2618
3071
|
executorKind: "pi",
|
|
2619
3072
|
...executorAttestation,
|
|
2620
3073
|
mcpAdapterVersion: seededRuntime.adapterVersion,
|
|
2621
|
-
mcpToolMode
|
|
2622
|
-
mcpArgsNormalization: MANAGED_PI_MCP_ARGS_NORMALIZATION,
|
|
3074
|
+
mcpToolMode,
|
|
3075
|
+
mcpArgsNormalization: directCatalog ? "none" : MANAGED_PI_MCP_ARGS_NORMALIZATION,
|
|
3076
|
+
...directCatalog ? {
|
|
3077
|
+
catalogSetHash: directCatalog.setHash,
|
|
3078
|
+
...effectiveToolsAttestation
|
|
3079
|
+
} : {},
|
|
2623
3080
|
configMode: "isolated_home_run_scoped_mcp_file",
|
|
2624
3081
|
namespace: SUPPORTED_SERVER_NAME2,
|
|
2625
3082
|
schemaVersion: SUPPORTED_SCHEMA_VERSION2,
|
|
@@ -2637,6 +3094,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2637
3094
|
configPath,
|
|
2638
3095
|
markerPath,
|
|
2639
3096
|
env,
|
|
3097
|
+
toolAllowlist: directCatalog ? [...directToolNames] : null,
|
|
2640
3098
|
protectedValues: [.../* @__PURE__ */ new Set([
|
|
2641
3099
|
sessionToken,
|
|
2642
3100
|
...seededRuntime.protectedValues,
|
|
@@ -2645,7 +3103,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2645
3103
|
])],
|
|
2646
3104
|
attestation: {
|
|
2647
3105
|
...attestationFacts,
|
|
2648
|
-
attestationId:
|
|
3106
|
+
attestationId: createHash3("sha256").update(JSON.stringify(attestationFacts)).digest("hex"),
|
|
2649
3107
|
attestedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2650
3108
|
}
|
|
2651
3109
|
};
|
|
@@ -3466,10 +3924,10 @@ function wikiAccessRuleLine(input) {
|
|
|
3466
3924
|
const tools = input.hasGovernedMcp === true && access.tools === true;
|
|
3467
3925
|
const treePath = readString(access.treePath);
|
|
3468
3926
|
if (tools && treePath) {
|
|
3469
|
-
return `- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages via the amaster MCP, and the wiki tree at ${treePath} (read wiki/index.md there first).`;
|
|
3927
|
+
return `- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages / wiki_read_source / wiki_write_page via the amaster MCP, and the wiki tree at ${treePath} (read wiki/index.md there first).`;
|
|
3470
3928
|
}
|
|
3471
3929
|
if (tools) {
|
|
3472
|
-
return "- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages via the amaster MCP. Use them for
|
|
3930
|
+
return "- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages / wiki_read_source / wiki_write_page via the amaster MCP. Use them for governed lookup and durable Wiki updates; Company Knowledge operations must use the exact operationId and sourceRefs named by the issue.";
|
|
3473
3931
|
}
|
|
3474
3932
|
if (treePath) {
|
|
3475
3933
|
return `- Company wiki access in this run: the wiki tree at ${treePath}. Read wiki/index.md first (every page listed with a one-line summary), then open the specific pages you need; wiki_* tools are not available in this run.`;
|
|
@@ -3567,6 +4025,13 @@ function continuationRuntimeActionEnvelope(context) {
|
|
|
3567
4025
|
if (!readString(envelope.schemaVersion) || !readString(envelope.idempotencyKey) || action.type !== "update_parent" || action.status !== "todo" || !readString(action.comment)) return null;
|
|
3568
4026
|
return envelope;
|
|
3569
4027
|
}
|
|
4028
|
+
function managedDirectToolName(input, canonicalName) {
|
|
4029
|
+
if (input.managedMcpToolMode !== "direct_typed") return null;
|
|
4030
|
+
const catalog = asRecord(input.managedMcpToolCatalog);
|
|
4031
|
+
const tools = Array.isArray(catalog.tools) ? catalog.tools.map(asRecord) : [];
|
|
4032
|
+
const match = tools.find((tool) => readString(tool.name) === canonicalName);
|
|
4033
|
+
return readString(match?.exposedName) ?? null;
|
|
4034
|
+
}
|
|
3570
4035
|
function runtimeActionContinuationOptionText(input) {
|
|
3571
4036
|
if (!isRecoveryWakeReason(input.wakeReason)) return "";
|
|
3572
4037
|
const heading = "### Runtime Action Continuation Option";
|
|
@@ -3580,6 +4045,20 @@ Runtime Action continuation is unavailable: managed governed MCP capability is m
|
|
|
3580
4045
|
Runtime Action continuation is unavailable: continuationRuntimeActionEnvelope is missing or invalid. Do not guess a tool call.`;
|
|
3581
4046
|
}
|
|
3582
4047
|
if (input.executorKind === "pi") {
|
|
4048
|
+
if (input.managedMcpToolMode === "direct_typed") {
|
|
4049
|
+
const toolName = managedDirectToolName(input, "runtime_action.submit");
|
|
4050
|
+
if (!toolName) {
|
|
4051
|
+
return `${heading}
|
|
4052
|
+
Runtime Action continuation is unavailable: the run catalog does not advertise the required typed submit tool. Do not guess a tool call.`;
|
|
4053
|
+
}
|
|
4054
|
+
return [
|
|
4055
|
+
heading,
|
|
4056
|
+
`Only after selecting continuation/todo from the disposition menu, emit an actual \`${toolName}\` typed tool call with the exact object arguments below. Do not print this JSON as prose.`,
|
|
4057
|
+
"```json",
|
|
4058
|
+
jsonText(envelope),
|
|
4059
|
+
"```"
|
|
4060
|
+
].join("\n");
|
|
4061
|
+
}
|
|
3583
4062
|
if (input.managedMcpToolMode !== "proxy_only") {
|
|
3584
4063
|
return `${heading}
|
|
3585
4064
|
Runtime Action continuation is unavailable: managed Pi MCP tool mode is not proxy_only. Do not guess a proxy or direct-tool call.`;
|
|
@@ -3800,6 +4279,19 @@ function piMcpProxyExamplesText(input) {
|
|
|
3800
4279
|
`- read document: ${proxy("amaster.read_issue_document", { issueId: "AM-123", key: "plan" })}`
|
|
3801
4280
|
].join("\n");
|
|
3802
4281
|
}
|
|
4282
|
+
function piDirectTypedToolsText(input) {
|
|
4283
|
+
if (!input.hasGovernedMcp || input.executorKind !== "pi" || input.managedMcpToolMode !== "direct_typed") return "";
|
|
4284
|
+
const catalog = asRecord(input.managedMcpToolCatalog);
|
|
4285
|
+
const tools = (Array.isArray(catalog.tools) ? catalog.tools : []).map(asRecord).map((tool) => ({ name: readString(tool.exposedName), description: readString(tool.description) })).filter((tool) => tool.name);
|
|
4286
|
+
if (tools.length === 0) {
|
|
4287
|
+
return "Direct typed governed tools are unavailable because the run catalog snapshot is empty. Do not guess a proxy or tool name.";
|
|
4288
|
+
}
|
|
4289
|
+
return [
|
|
4290
|
+
"This run uses the attested direct typed Governed MCP surface below. Call these exact names with object arguments; do not call the `mcp` proxy and do not stringify an inner argument envelope.",
|
|
4291
|
+
...tools.map((tool) => `- ${tool.name}${tool.description ? `: ${tool.description}` : ""}`),
|
|
4292
|
+
"A tool not listed above is unavailable in this run. Do not infer a namespace or fall back to REST/bare MCP."
|
|
4293
|
+
].join("\n");
|
|
4294
|
+
}
|
|
3803
4295
|
function sectionText(section) {
|
|
3804
4296
|
if (!section.content) return "";
|
|
3805
4297
|
return section.title ? `## ${section.title}
|
|
@@ -3906,10 +4398,14 @@ function compileCommandPromptWithManifest(input, options = {}) {
|
|
|
3906
4398
|
resolvedDependencies.details.content ? `Auxiliary predecessor context (may be truncated):
|
|
3907
4399
|
${resolvedDependencies.details.content}` : ""
|
|
3908
4400
|
].filter(Boolean).join("\n\n") : "";
|
|
3909
|
-
const piMcpProxyExamples = resolvedDependencies.required.content ? "" : piMcpProxyExamplesText(input);
|
|
4401
|
+
const piMcpProxyExamples = resolvedDependencies.required.content ? "" : [piMcpProxyExamplesText(input), piDirectTypedToolsText(input)].filter(Boolean).join("\n");
|
|
3910
4402
|
const deliveryReadinessContent = runtimeDeliveryReadinessText(context, input);
|
|
3911
4403
|
const rawSections = [
|
|
3912
|
-
{ name: "
|
|
4404
|
+
{ name: "recovery_instruction", title: "Recovery Instruction", priority: 100, sourceRef: `run:${input.runId ?? "unknown"}`, content: completeRecoveryInstruction, truncationReason: completeRecoveryInstruction ? null : "mode_selection" },
|
|
4405
|
+
{ name: "approval_continuation", title: "Approved Runtime Action Continuation", priority: 99, sourceRef: `run:${input.runId ?? "unknown"}`, content: approvalContinuationText(input), truncationReason: mode === "continuation" ? null : "mode_selection" },
|
|
4406
|
+
{ name: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
|
|
4407
|
+
{ name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n"), content: includeTask ? [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n") : "", truncationReason: includeTask ? null : "mode_selection" },
|
|
4408
|
+
{ name: "continuation_summary", title: "Continuation Summary", priority: 97, sourceRef: readString(asRecord(context.paperclipContinuationSummary).key) ?? `issue:${input.issueId ?? "unknown"}`, observedAt: readString(asRecord(context.paperclipContinuationSummary).updatedAt), originalContent: continuationSummary, content: mode === "cold" ? "" : continuationSummary, truncationReason: mode === "cold" ? "mode_selection" : null },
|
|
3913
4409
|
...resolvedDependencyContent ? [{
|
|
3914
4410
|
name: "resolved_dependencies",
|
|
3915
4411
|
title: "Resolved Dependency Outputs",
|
|
@@ -3918,16 +4414,12 @@ ${resolvedDependencies.details.content}` : ""
|
|
|
3918
4414
|
content: resolvedDependencyContent,
|
|
3919
4415
|
mandatoryContent: resolvedDependencies.required.content
|
|
3920
4416
|
}] : [],
|
|
3921
|
-
{ name: "
|
|
3922
|
-
{ name: "
|
|
4417
|
+
...deliveryReadinessContent ? [{ name: "runtime_delivery_readiness", title: "Current Delivery Readiness", priority: 99, sourceRef: `issue:${input.issueId ?? "unknown"}:delivery`, content: deliveryReadinessContent }] : [],
|
|
4418
|
+
{ name: "runtime_rules", title: "", priority: 100, sourceRef: `command:${input.commandId}`, content: fixedRules(input, !hasTask) },
|
|
3923
4419
|
{ name: "runtime_authorization", title: "Runtime Action Contract", priority: 98, sourceRef: `run:${input.runId ?? "unknown"}`, content: runtimeAuthorizationText(context, mode, { suppressOrdinaryCompletionContract }) },
|
|
3924
4420
|
{ name: "runtime_decomposition_requirement", title: "Required Task Decomposition", priority: 98, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: runtimeDecompositionRequirementText(context) },
|
|
3925
|
-
...deliveryReadinessContent ? [{ name: "runtime_delivery_readiness", title: "Current Delivery Readiness", priority: 99, sourceRef: `issue:${input.issueId ?? "unknown"}:delivery`, content: deliveryReadinessContent }] : [],
|
|
3926
|
-
...piMcpProxyExamples ? [{ name: "pi_mcp_proxy_examples", title: "Pi MCP Proxy Examples", priority: 96, sourceRef: "amaster_governed_mcp_proxy_contract", content: piMcpProxyExamples }] : [],
|
|
3927
|
-
{ name: "continuation_summary", title: "Continuation Summary", priority: 97, sourceRef: readString(asRecord(context.paperclipContinuationSummary).key) ?? `issue:${input.issueId ?? "unknown"}`, observedAt: readString(asRecord(context.paperclipContinuationSummary).updatedAt), originalContent: continuationSummary, content: mode === "cold" ? "" : continuationSummary, truncationReason: mode === "cold" ? "mode_selection" : null },
|
|
3928
4421
|
...verifiedCompanyContext.content ? [{ name: "verified_company_context", title: "Verified Company Context", priority: 96, sourceRef: verifiedCompanyContext.sourceRef, observedAt: verifiedCompanyContext.observedAt, freshness: { kind: "run_snapshot" }, content: verifiedCompanyContext.content }] : [],
|
|
3929
|
-
{ name: "
|
|
3930
|
-
{ name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n"), content: includeTask ? [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n") : "", truncationReason: includeTask ? null : "mode_selection" },
|
|
4422
|
+
...piMcpProxyExamples ? [{ name: "pi_mcp_proxy_examples", title: "Pi MCP Proxy Examples", priority: 96, sourceRef: "amaster_governed_mcp_proxy_contract", content: piMcpProxyExamples }] : [],
|
|
3931
4423
|
{ name: "governed_reads", title: "Governed External Reads", priority: 88, sourceRef: governedReads.provenance.map((entry) => entry.sourceRef), observedAt: governedReads.provenance.map((entry) => entry.observedAt), freshness: governedReads.provenance.map((entry) => entry.freshness), scope: governedReads.provenance.map((entry) => entry.scope), content: governedReads.content },
|
|
3932
4424
|
{ name: "agent_instructions", title: "Agent Instructions", priority: 100, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
|
|
3933
4425
|
{ name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
|
|
@@ -5321,6 +5813,14 @@ function piMessageText(message) {
|
|
|
5321
5813
|
return readString(block.text) ?? readString(block.content) ?? "";
|
|
5322
5814
|
}).filter(Boolean).join("\n").trim();
|
|
5323
5815
|
}
|
|
5816
|
+
function piMessageHasToolCall(message) {
|
|
5817
|
+
const content = asRecord(message).content;
|
|
5818
|
+
if (!Array.isArray(content)) return false;
|
|
5819
|
+
return content.some((entry) => {
|
|
5820
|
+
const block = asRecord(entry);
|
|
5821
|
+
return block.type === "toolCall" && Boolean(readString(block.name));
|
|
5822
|
+
});
|
|
5823
|
+
}
|
|
5324
5824
|
function appendUniqueText(values, text) {
|
|
5325
5825
|
const normalized = typeof text === "string" ? text.trim() : "";
|
|
5326
5826
|
if (!normalized) return false;
|
|
@@ -5408,7 +5908,7 @@ function maybeCapturePiMessage(event, messages, usage) {
|
|
|
5408
5908
|
const message = asRecord(event.message);
|
|
5409
5909
|
if (message.role === "assistant") {
|
|
5410
5910
|
const text = piMessageText(message);
|
|
5411
|
-
capturedAssistantOutput = capturePiAssistantText(text, messages) || capturedAssistantOutput;
|
|
5911
|
+
capturedAssistantOutput = capturePiAssistantText(text, messages) || piMessageHasToolCall(message) || capturedAssistantOutput;
|
|
5412
5912
|
assignPiUsage(usage, piMessageUsage(message));
|
|
5413
5913
|
}
|
|
5414
5914
|
const eventMessages = Array.isArray(event.messages) ? event.messages : [];
|
|
@@ -5418,7 +5918,7 @@ function maybeCapturePiMessage(event, messages, usage) {
|
|
|
5418
5918
|
continue;
|
|
5419
5919
|
}
|
|
5420
5920
|
const text = piMessageText(eventMessage);
|
|
5421
|
-
capturedAssistantOutput = capturePiAssistantText(text, messages) || capturedAssistantOutput;
|
|
5921
|
+
capturedAssistantOutput = capturePiAssistantText(text, messages) || piMessageHasToolCall(eventMessage) || capturedAssistantOutput;
|
|
5422
5922
|
assignPiUsage(usage, piMessageUsage(eventMessage));
|
|
5423
5923
|
}
|
|
5424
5924
|
return capturedAssistantOutput;
|
|
@@ -5791,7 +6291,7 @@ var postJsonWithRetry = postRuntimeConnectorJsonWithRetry;
|
|
|
5791
6291
|
var bestEffortPostJson = bestEffortPostRuntimeConnectorJson;
|
|
5792
6292
|
|
|
5793
6293
|
// src/amaster-runtime-daemon/runtime-artifact-upload.mjs
|
|
5794
|
-
import { createHash as
|
|
6294
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5795
6295
|
import { lstatSync as lstatSync3, readFileSync as readFileSync6, realpathSync as realpathSync3 } from "node:fs";
|
|
5796
6296
|
import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3 } from "node:path";
|
|
5797
6297
|
var SHA256_PATTERN = /^[a-f0-9]{64}$/;
|
|
@@ -5834,7 +6334,7 @@ function prepareRuntimeArtifactUploads(cwd, mcpToolResults) {
|
|
|
5834
6334
|
throw new Error(`Runtime Artifact ${intentId} source is not an owned regular file`);
|
|
5835
6335
|
}
|
|
5836
6336
|
const body = readFileSync6(sourcePath);
|
|
5837
|
-
const actualSha256 =
|
|
6337
|
+
const actualSha256 = createHash4("sha256").update(body).digest("hex");
|
|
5838
6338
|
if (body.length !== expectedByteSize || actualSha256 !== expectedSha256) {
|
|
5839
6339
|
throw new Error(`Runtime Artifact ${intentId} bytes do not match the governed ownership manifest`);
|
|
5840
6340
|
}
|
|
@@ -5924,7 +6424,7 @@ function createRuntimeArtifactIngestQueue({ ingest, onError }) {
|
|
|
5924
6424
|
}
|
|
5925
6425
|
|
|
5926
6426
|
// src/amaster-runtime-daemon/workspace-guard.mjs
|
|
5927
|
-
import { createHash as
|
|
6427
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5928
6428
|
import { existsSync as existsSync7, mkdirSync as mkdirSync6, realpathSync as realpathSync4, statSync as statSync3 } from "node:fs";
|
|
5929
6429
|
import { basename as basename4, join as join8, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve4 } from "node:path";
|
|
5930
6430
|
|
|
@@ -6035,7 +6535,7 @@ function resolveWorkspaceCwd(config, command) {
|
|
|
6035
6535
|
return cwd;
|
|
6036
6536
|
}
|
|
6037
6537
|
function shortHash(value, length = 12) {
|
|
6038
|
-
return
|
|
6538
|
+
return createHash5("sha256").update(String(value)).digest("hex").slice(0, length);
|
|
6039
6539
|
}
|
|
6040
6540
|
function safeSegment(value, fallback) {
|
|
6041
6541
|
const raw = String(value ?? "").trim();
|
|
@@ -6467,7 +6967,7 @@ function summarizeAmasterRuntimeVersionDrift(input = {}) {
|
|
|
6467
6967
|
}
|
|
6468
6968
|
|
|
6469
6969
|
// src/amaster-runtime-daemon/pi-child-isolation.mjs
|
|
6470
|
-
import { createHash as
|
|
6970
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
6471
6971
|
import {
|
|
6472
6972
|
chmodSync as chmodSync3,
|
|
6473
6973
|
chownSync,
|
|
@@ -6478,7 +6978,7 @@ import {
|
|
|
6478
6978
|
import { resolve as resolve7, sep } from "node:path";
|
|
6479
6979
|
var defaultFs = { chmodSync: chmodSync3, chownSync, lchownSync, lstatSync: lstatSync4, readdirSync: readdirSync6 };
|
|
6480
6980
|
function defaultHashRunId(runId) {
|
|
6481
|
-
return Number.parseInt(
|
|
6981
|
+
return Number.parseInt(createHash6("sha256").update(runId).digest("hex").slice(0, 8), 16);
|
|
6482
6982
|
}
|
|
6483
6983
|
function positiveInteger(value, label) {
|
|
6484
6984
|
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
@@ -6602,7 +7102,7 @@ function preparePiChildIsolation(input) {
|
|
|
6602
7102
|
}
|
|
6603
7103
|
|
|
6604
7104
|
// src/amaster-runtime-daemon/pi-company-memory.mjs
|
|
6605
|
-
import { createHash as
|
|
7105
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
6606
7106
|
import {
|
|
6607
7107
|
chmodSync as chmodSync4,
|
|
6608
7108
|
chownSync as chownSync2,
|
|
@@ -6688,7 +7188,7 @@ function safeCompanyPiHomeSegment(companyId) {
|
|
|
6688
7188
|
const raw = requiredString2(companyId, "companyId");
|
|
6689
7189
|
if (/^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$/.test(raw)) return raw;
|
|
6690
7190
|
const normalized = raw.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "").slice(0, 80);
|
|
6691
|
-
const hash =
|
|
7191
|
+
const hash = createHash7("sha256").update(raw).digest("hex").slice(0, 12);
|
|
6692
7192
|
return normalized ? `${normalized}-${hash}` : `company-${hash}`;
|
|
6693
7193
|
}
|
|
6694
7194
|
function ensureMemoryRoot(root, fs) {
|
|
@@ -6727,7 +7227,7 @@ function allocateCompanyGid(root, companyId, input, fs) {
|
|
|
6727
7227
|
if (groups[companyId]) return groups[companyId];
|
|
6728
7228
|
const used = new Set(Object.values(groups));
|
|
6729
7229
|
const initialOffset = Number.parseInt(
|
|
6730
|
-
|
|
7230
|
+
createHash7("sha256").update(companyId).digest("hex").slice(0, 12),
|
|
6731
7231
|
16
|
|
6732
7232
|
) % gidSpan;
|
|
6733
7233
|
let gid = null;
|
|
@@ -6829,7 +7329,7 @@ function prepareCompanyPiMemory(input, fs = defaultFs2) {
|
|
|
6829
7329
|
}
|
|
6830
7330
|
|
|
6831
7331
|
// src/amaster-runtime-daemon/pi-trusted-runtime-profile.mjs
|
|
6832
|
-
import { createHash as
|
|
7332
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
6833
7333
|
import {
|
|
6834
7334
|
chmodSync as chmodSync5,
|
|
6835
7335
|
copyFileSync as copyFileSync2,
|
|
@@ -6847,6 +7347,8 @@ var ASSERTION_VERSION = "2026-07-25.v1";
|
|
|
6847
7347
|
var SHA256 = /^[a-f0-9]{64}$/;
|
|
6848
7348
|
var COPY_ENTRIES = ["SYSTEM.md", "policy", "skills", "agents", "bundles", "extensions"];
|
|
6849
7349
|
var JSON_ENTRIES = ["settings.json", "models.json"];
|
|
7350
|
+
var ROLE_SKILLS_DIR = "role-skills";
|
|
7351
|
+
var DISABLE_MODEL_INVOCATION_LINE = /^[ \t]*disable-model-invocation:[ \t]*true[ \t]*\r?$/m;
|
|
6850
7352
|
var SECRET_KEY = /(authorization|cookie|api[_-]?key|password|secret|token)$/i;
|
|
6851
7353
|
var SECRET_VALUE = /(?:authorization|cookie|api[_-]?key|password|secret|token)\s*[:=]\s*(?:bearer\s+)?[^\s"',;]+|bearer\s+[^\s"',;]+/i;
|
|
6852
7354
|
var MAX_AUDIT_BYTES = 1024 * 1024;
|
|
@@ -6867,7 +7369,7 @@ function sha256File(path, label) {
|
|
|
6867
7369
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
6868
7370
|
throw new Error(`pi_trusted_runtime_source_unsafe:${label}`);
|
|
6869
7371
|
}
|
|
6870
|
-
return
|
|
7372
|
+
return createHash8("sha256").update(readFileSync9(path)).digest("hex");
|
|
6871
7373
|
}
|
|
6872
7374
|
function verifyDeclaredFiles(manifest, root, label, ignoredPaths = [], enforceComplete = true) {
|
|
6873
7375
|
if (!Array.isArray(manifest.files) || manifest.files.length === 0) {
|
|
@@ -6965,6 +7467,53 @@ function copyTreeNoLinks(source, target) {
|
|
|
6965
7467
|
copyFileSync2(source, target);
|
|
6966
7468
|
chmodSync5(target, 384 | stat.mode & 73);
|
|
6967
7469
|
}
|
|
7470
|
+
var SKILL_PROFILE_NAME = /^[a-z0-9-]+$/;
|
|
7471
|
+
function readSkillProfile(seedRoot, skillProfile) {
|
|
7472
|
+
const agentsRoot = resolve9(seedRoot, "agents");
|
|
7473
|
+
const agentFile = resolve9(agentsRoot, `${skillProfile}.md`);
|
|
7474
|
+
if (!SKILL_PROFILE_NAME.test(skillProfile) || !within3(agentFile, agentsRoot) || !existsSync11(agentFile)) {
|
|
7475
|
+
throw new Error(`pi_trusted_runtime_skill_profile_unknown:${skillProfile}`);
|
|
7476
|
+
}
|
|
7477
|
+
const declared = readFileSync9(agentFile, "utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1].match(/^skills:\s*(.+)$/m)?.[1].split(",").map((entry) => entry.trim()).filter(Boolean) ?? [];
|
|
7478
|
+
const bundlesRoot = resolve9(seedRoot, "bundles");
|
|
7479
|
+
const profile = [];
|
|
7480
|
+
for (const name of declared) {
|
|
7481
|
+
let source = join12(bundlesRoot, skillProfile, "skills", name);
|
|
7482
|
+
if (!existsSync11(join12(source, "SKILL.md"))) {
|
|
7483
|
+
const candidates = [];
|
|
7484
|
+
for (const category of readdirSync7(bundlesRoot).sort()) {
|
|
7485
|
+
if (category === skillProfile) continue;
|
|
7486
|
+
const candidate = join12(bundlesRoot, category, "skills", name);
|
|
7487
|
+
if (existsSync11(join12(candidate, "SKILL.md"))) candidates.push(candidate);
|
|
7488
|
+
}
|
|
7489
|
+
if (candidates.length > 1) {
|
|
7490
|
+
throw new Error(`pi_trusted_runtime_skill_profile_ambiguous:${skillProfile}:${name}`);
|
|
7491
|
+
}
|
|
7492
|
+
source = candidates[0];
|
|
7493
|
+
}
|
|
7494
|
+
if (source) profile.push({ name, source });
|
|
7495
|
+
}
|
|
7496
|
+
if (profile.length === 0) {
|
|
7497
|
+
throw new Error(`pi_trusted_runtime_skill_profile_unknown:${skillProfile}`);
|
|
7498
|
+
}
|
|
7499
|
+
return profile;
|
|
7500
|
+
}
|
|
7501
|
+
function materializeRoleSkills(seedRoot, agentDir, skillProfile) {
|
|
7502
|
+
const profile = readSkillProfile(seedRoot, skillProfile);
|
|
7503
|
+
const bundlesRoot = resolve9(seedRoot, "bundles");
|
|
7504
|
+
const enabled = [];
|
|
7505
|
+
for (const entry of profile) {
|
|
7506
|
+
const target = join12(agentDir, ROLE_SKILLS_DIR, entry.name);
|
|
7507
|
+
rmSync6(target, { recursive: true, force: true });
|
|
7508
|
+
copyTreeNoLinks(entry.source, target);
|
|
7509
|
+
const skillFile = join12(target, "SKILL.md");
|
|
7510
|
+
writeFileSync8(skillFile, readFileSync9(skillFile, "utf8").replace(DISABLE_MODEL_INVOCATION_LINE, ""), {
|
|
7511
|
+
mode: 384
|
|
7512
|
+
});
|
|
7513
|
+
enabled.push({ name: entry.name, path: relative6(bundlesRoot, entry.source).split("\\").join("/") });
|
|
7514
|
+
}
|
|
7515
|
+
return enabled;
|
|
7516
|
+
}
|
|
6968
7517
|
function mergeMcp(seedRoot, overlayRoot, governedConfig) {
|
|
6969
7518
|
const seed = record5(readJsonFile2(join12(seedRoot, "mcp.json"), "seed_mcp", { mcpServers: {} }));
|
|
6970
7519
|
const overlay = record5(readJsonFile2(join12(overlayRoot, "mcp.json"), "overlay_mcp", { mcpServers: {} }));
|
|
@@ -7029,6 +7578,8 @@ function materializeTrustedPiRuntimeProfile(input) {
|
|
|
7029
7578
|
if (existsSync11(source)) copyTreeNoLinks(source, target);
|
|
7030
7579
|
}
|
|
7031
7580
|
}
|
|
7581
|
+
const skillProfile = typeof input.skillProfile === "string" && input.skillProfile.trim() ? input.skillProfile.trim() : null;
|
|
7582
|
+
const enabledSkills = skillProfile ? materializeRoleSkills(seedRoot, agentDir, skillProfile) : [];
|
|
7032
7583
|
const mergedJson = {};
|
|
7033
7584
|
for (const entry of JSON_ENTRIES) {
|
|
7034
7585
|
const seed = readJsonFile2(join12(seedRoot, entry), `seed_${entry}`, {});
|
|
@@ -7043,6 +7594,13 @@ function materializeTrustedPiRuntimeProfile(input) {
|
|
|
7043
7594
|
allowSessionGrants: false
|
|
7044
7595
|
}
|
|
7045
7596
|
};
|
|
7597
|
+
if (skillProfile) {
|
|
7598
|
+
const current = Array.isArray(merged.skills) ? merged.skills : [];
|
|
7599
|
+
merged.skills = [
|
|
7600
|
+
ROLE_SKILLS_DIR,
|
|
7601
|
+
...current.filter((value) => value !== ROLE_SKILLS_DIR)
|
|
7602
|
+
];
|
|
7603
|
+
}
|
|
7046
7604
|
}
|
|
7047
7605
|
assertNoPersistentSecrets(merged, [entry]);
|
|
7048
7606
|
writeFileSync8(join12(agentDir, entry), `${JSON.stringify(merged, null, 2)}
|
|
@@ -7074,11 +7632,17 @@ function materializeTrustedPiRuntimeProfile(input) {
|
|
|
7074
7632
|
runtimeEnforcementDigest: input.verifiedAssertion.digests.runtimeEnforcementDigest,
|
|
7075
7633
|
unknownToolMode: input.verifiedAssertion.unknownToolMode,
|
|
7076
7634
|
directToolBudget: input.verifiedAssertion.directToolBudget,
|
|
7077
|
-
inheritedEntries: [...COPY_ENTRIES, ...JSON_ENTRIES, "mcp.json", "npm"]
|
|
7635
|
+
inheritedEntries: [...COPY_ENTRIES, ...JSON_ENTRIES, "mcp.json", "npm"],
|
|
7636
|
+
// What the model can actually see this run: which profile and which exact
|
|
7637
|
+
// bundle skills were enabled. Absent profile => main skills only.
|
|
7638
|
+
...skillProfile ? {
|
|
7639
|
+
skillProfile,
|
|
7640
|
+
enabledSkillsDigest: createHash8("sha256").update(JSON.stringify(enabledSkills)).digest("hex")
|
|
7641
|
+
} : {}
|
|
7078
7642
|
};
|
|
7079
7643
|
return {
|
|
7080
7644
|
facts,
|
|
7081
|
-
attestationId:
|
|
7645
|
+
attestationId: createHash8("sha256").update(JSON.stringify(facts)).digest("hex")
|
|
7082
7646
|
};
|
|
7083
7647
|
}
|
|
7084
7648
|
function assertAuditArgsRedacted(value) {
|
|
@@ -7274,7 +7838,7 @@ function verifyTrustedPiRuntimeAssertion(input) {
|
|
|
7274
7838
|
if (hasSourceAssertion) {
|
|
7275
7839
|
const exactTools = Array.isArray(record5(sourceProfile.tools).exactAllowlist) ? record5(sourceProfile.tools).exactAllowlist : [];
|
|
7276
7840
|
const exactActions = Array.isArray(record5(sourceProfile.actions).exactAllowlist) ? record5(sourceProfile.actions).exactAllowlist : [];
|
|
7277
|
-
const profileHash =
|
|
7841
|
+
const profileHash = createHash8("sha256").update(JSON.stringify(sourceProfile)).digest("hex");
|
|
7278
7842
|
if (assertion.unknownToolMode !== "deny" || maxCalls !== 0 || sourceAssertion.profileVersion !== sourceProfile.purpose || sourceAssertion.profileHash !== profileHash || sourceAssertion.retentionVersion !== sourceProfile.retention || JSON.stringify(sourceAssertion.exactTools) !== JSON.stringify(exactTools) || JSON.stringify(sourceAssertion.exactActions) !== JSON.stringify(exactActions) || sourceAssertion.sourceId !== sourceProfile.sourceId || sourceAssertion.sourceRevisionId !== sourceProfile.sourceRevisionId || sourceAssertion.sourceRevision !== sourceProfile.sourceRevision || sourceAssertion.attemptId !== sourceProfile.attemptId || sourceAssertion.epoch !== sourceProfile.epoch) {
|
|
7279
7843
|
throw new Error("pi_trusted_runtime_assertion_binding_mismatch:sourceAcquisition");
|
|
7280
7844
|
}
|
|
@@ -7303,7 +7867,7 @@ function verifyTrustedPiRuntimeAssertion(input) {
|
|
|
7303
7867
|
|
|
7304
7868
|
// src/amaster-runtime-daemon/workspace-status.mjs
|
|
7305
7869
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
7306
|
-
import { createHash as
|
|
7870
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
7307
7871
|
import { existsSync as existsSync12, readdirSync as readdirSync8, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
|
|
7308
7872
|
import { basename as basename5, extname, isAbsolute as isAbsolute7, join as join13, relative as relative7, resolve as resolve10 } from "node:path";
|
|
7309
7873
|
var WORKSPACE_RUNTIME_SERVICES_FILENAME = ".amaster-runtime-services.json";
|
|
@@ -7375,7 +7939,7 @@ function sanitizeTrackedChange(line) {
|
|
|
7375
7939
|
return isSafeRelativePath(path) ? line : null;
|
|
7376
7940
|
}
|
|
7377
7941
|
function sha256File2(filePath) {
|
|
7378
|
-
return
|
|
7942
|
+
return createHash9("sha256").update(readFileSync10(filePath)).digest("hex");
|
|
7379
7943
|
}
|
|
7380
7944
|
function artifactHashCacheKey(relativePath, stat) {
|
|
7381
7945
|
return `${relativePath}\0${stat.size}\0${stat.mtimeMs}`;
|
|
@@ -7576,7 +8140,7 @@ function readWorkspaceStatus(cwd, opts = {}) {
|
|
|
7576
8140
|
}
|
|
7577
8141
|
|
|
7578
8142
|
// src/amaster-runtime-daemon/pi-browser-session-adapter.mjs
|
|
7579
|
-
import { createHash as
|
|
8143
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
7580
8144
|
import { spawn, spawnSync as spawnSync5 } from "node:child_process";
|
|
7581
8145
|
import { existsSync as existsSync13 } from "node:fs";
|
|
7582
8146
|
import {
|
|
@@ -7699,7 +8263,7 @@ function fail(code) {
|
|
|
7699
8263
|
throw Object.assign(new Error(code), { code });
|
|
7700
8264
|
}
|
|
7701
8265
|
function profileName(identity2) {
|
|
7702
|
-
return
|
|
8266
|
+
return createHash10("sha256").update(`${identity2.companyId}\0${identity2.bindingId}\0${identity2.localOpaqueRef}`).digest("hex");
|
|
7703
8267
|
}
|
|
7704
8268
|
function expectedMarker(identity2) {
|
|
7705
8269
|
return {
|
|
@@ -8098,7 +8662,7 @@ async function executeBrowserSessionCommand(command, dependencies = {}) {
|
|
|
8098
8662
|
}
|
|
8099
8663
|
|
|
8100
8664
|
// src/amaster-runtime-daemon/source-acquisition-invocation.mjs
|
|
8101
|
-
import { createHash as
|
|
8665
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
8102
8666
|
var SOURCE_ACQUISITION_PUBLIC_TOOLS = Object.freeze([
|
|
8103
8667
|
"source_open",
|
|
8104
8668
|
"source_snapshot",
|
|
@@ -8135,7 +8699,7 @@ function serializeSourceAcquisitionProfile(profile) {
|
|
|
8135
8699
|
const input = Buffer.from(JSON.stringify(profile), "utf8");
|
|
8136
8700
|
return {
|
|
8137
8701
|
input,
|
|
8138
|
-
sha256:
|
|
8702
|
+
sha256: createHash11("sha256").update(input).digest("hex")
|
|
8139
8703
|
};
|
|
8140
8704
|
}
|
|
8141
8705
|
function sourceAcquisitionManagedInputs(options) {
|
|
@@ -8171,7 +8735,7 @@ function assertSourceAcquisitionRuntimeAuthority({
|
|
|
8171
8735
|
}
|
|
8172
8736
|
|
|
8173
8737
|
// src/amaster-runtime-daemon.mjs
|
|
8174
|
-
var CONNECTOR_VERSION = "0.1.1-beta.
|
|
8738
|
+
var CONNECTOR_VERSION = "0.1.1-beta.5";
|
|
8175
8739
|
var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
|
|
8176
8740
|
var SOURCE_ACQUISITION_CAPABILITY = "source_acquisition_v1";
|
|
8177
8741
|
var SOURCE_ACQUISITION_PROFILE_VERSION = "source_acquisition_v1";
|
|
@@ -9468,7 +10032,7 @@ function sourceAcquisitionRuntimeProfile(config, command) {
|
|
|
9468
10032
|
if (!companyId || !bindingId || !/^profile_[a-z0-9]{16,64}$/i.test(localOpaqueRef ?? "")) {
|
|
9469
10033
|
throw new Error("source_acquisition_profile_invalid");
|
|
9470
10034
|
}
|
|
9471
|
-
const profileName2 =
|
|
10035
|
+
const profileName2 = createHash12("sha256").update(`${companyId}\0${bindingId}\0${localOpaqueRef}`).digest("hex");
|
|
9472
10036
|
const stateRoot = resolve12(config.browserSessionStateRoot);
|
|
9473
10037
|
const userDataDir = resolve12(stateRoot, profileName2);
|
|
9474
10038
|
if (!pathWithin2(userDataDir, stateRoot)) throw new Error("source_acquisition_browser_profile_invalid");
|
|
@@ -9665,6 +10229,7 @@ function buildCommandPrompt(command, workspace, materializedAttachments = [], op
|
|
|
9665
10229
|
hasGovernedMcp,
|
|
9666
10230
|
executorKind: options.executorKind,
|
|
9667
10231
|
managedMcpToolMode: options.managedMcpToolMode,
|
|
10232
|
+
managedMcpToolCatalog: options.managedMcpToolCatalog,
|
|
9668
10233
|
agentInstructions,
|
|
9669
10234
|
taskMarkdown,
|
|
9670
10235
|
attachmentsText,
|
|
@@ -9953,6 +10518,14 @@ async function executeModelCallCommand(config, command, signal) {
|
|
|
9953
10518
|
sourceWorkspacePath: process.cwd()
|
|
9954
10519
|
});
|
|
9955
10520
|
piModelCallProfile = executor.kind === "pi" ? preparePiModelCallProfile(command.commandId, baseEnv) : null;
|
|
10521
|
+
if (piModelCallProfile) {
|
|
10522
|
+
await syncPiExecutorProviderConfig(
|
|
10523
|
+
config,
|
|
10524
|
+
command,
|
|
10525
|
+
piModelCallProfile.env.PI_CODING_AGENT_DIR,
|
|
10526
|
+
resolvePiExecutorProviderConfig(config, command, baseEnv)
|
|
10527
|
+
);
|
|
10528
|
+
}
|
|
9956
10529
|
execution = await runExecutor(invocation.command, invocation.args, {
|
|
9957
10530
|
cwd: process.cwd(),
|
|
9958
10531
|
env: piModelCallProfile?.env ?? baseEnv,
|
|
@@ -12197,7 +12770,7 @@ async function materializeIssueAttachments(config, command, workspace) {
|
|
|
12197
12770
|
const body = await runtimeApiBuffer(runtimeAuth, contentPath);
|
|
12198
12771
|
writeFileSync9(targetPath, body);
|
|
12199
12772
|
const attachmentId = readString(attachment.id);
|
|
12200
|
-
const actualSha256 =
|
|
12773
|
+
const actualSha256 = createHash12("sha256").update(body).digest("hex");
|
|
12201
12774
|
const lineageCandidates = lineageCandidatesByAttachmentId.get(attachmentId) ?? [];
|
|
12202
12775
|
const lineage = selectAttachmentLineage(lineageCandidates, actualSha256);
|
|
12203
12776
|
if (lineageCandidates.length > 0 && !lineage) {
|
|
@@ -12289,7 +12862,7 @@ async function materializeRequiredArtifactInputs(config, command, workspace) {
|
|
|
12289
12862
|
throw new Error(`artifact_input_manifest_invalid: entry ${index} contentPath does not match attachmentId`);
|
|
12290
12863
|
}
|
|
12291
12864
|
const body = await runtimeApiBuffer(runtimeAuth, contentPath);
|
|
12292
|
-
const actualSha256 =
|
|
12865
|
+
const actualSha256 = createHash12("sha256").update(body).digest("hex");
|
|
12293
12866
|
if (body.byteLength !== byteSize || actualSha256 !== sha256) {
|
|
12294
12867
|
throw new Error(
|
|
12295
12868
|
`artifact_input_integrity_mismatch: workProductId=${workProductId} expectedBytes=${byteSize} actualBytes=${body.byteLength} expectedSha256=${sha256} actualSha256=${actualSha256}`
|
|
@@ -12359,7 +12932,7 @@ function safeCheckpointRelativePath(rawPath) {
|
|
|
12359
12932
|
return normalized;
|
|
12360
12933
|
}
|
|
12361
12934
|
function hashFileSha256(filePath) {
|
|
12362
|
-
return
|
|
12935
|
+
return createHash12("sha256").update(readFileSync11(filePath)).digest("hex");
|
|
12363
12936
|
}
|
|
12364
12937
|
async function materializeIssueCheckpoint(config, command, workspace) {
|
|
12365
12938
|
const checkpointDir = issueCheckpointDir(workspace);
|
|
@@ -12545,7 +13118,8 @@ async function executeRunCommand(config, command) {
|
|
|
12545
13118
|
await ingestWorkspaceStatus(config, command, cwd);
|
|
12546
13119
|
const promptCompilation = buildCommandPrompt(command, workspace, materializedAttachments, {
|
|
12547
13120
|
executorKind: executor.kind,
|
|
12548
|
-
managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? MANAGED_PI_MCP_TOOL_MODE : null,
|
|
13121
|
+
managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? readString(governedMcp.mcpToolMode) ?? MANAGED_PI_MCP_TOOL_MODE : null,
|
|
13122
|
+
managedMcpToolCatalog: asRecord(governedMcp.toolCatalog),
|
|
12549
13123
|
artifactVerifierCommands: config.artifactVerifierCommands,
|
|
12550
13124
|
workspaceBindings: config.workspaceBindings
|
|
12551
13125
|
});
|
|
@@ -12636,6 +13210,7 @@ async function executeRunCommand(config, command) {
|
|
|
12636
13210
|
}
|
|
12637
13211
|
if (managedMcpProfile) {
|
|
12638
13212
|
executorEnv = managedMcpProfile.env;
|
|
13213
|
+
if (executor.kind === "pi") invocation.args = applyManagedPiToolAllowlist(invocation.args, managedMcpProfile);
|
|
12639
13214
|
await ingestLog(config, command, "system", "info", `Attested isolated ${executor.kind} managed MCP profile`, {
|
|
12640
13215
|
presentationKind: "managed_mcp_attestation",
|
|
12641
13216
|
...managedMcpProfile.attestation
|
|
@@ -12668,7 +13243,8 @@ async function executeRunCommand(config, command) {
|
|
|
12668
13243
|
profileRoot: managedMcpProfile.profileRoot,
|
|
12669
13244
|
agentDir: managedMcpProfile.env.PI_CODING_AGENT_DIR,
|
|
12670
13245
|
governedMcpConfigPath: managedMcpProfile.configPath,
|
|
12671
|
-
verifiedAssertion: trustedPiRuntime
|
|
13246
|
+
verifiedAssertion: trustedPiRuntime,
|
|
13247
|
+
skillProfile: readString(asRecord(command.payload).skillProfile)
|
|
12672
13248
|
});
|
|
12673
13249
|
executorEnv = {
|
|
12674
13250
|
...executorEnv,
|
package/dist/amaster-runtime.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
5
5
|
import { homedir, hostname } from "node:os";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
|
-
const CONNECTOR_VERSION = "0.1.1-beta.
|
|
8
|
+
const CONNECTOR_VERSION = "0.1.1-beta.5";
|
|
9
9
|
|
|
10
10
|
const CAPABILITIES = [
|
|
11
11
|
"remote_registration",
|