@amaster.ai/employee-runtime-connector 0.1.1-beta.3 → 0.1.1-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/amaster-runtime-daemon.mjs +588 -61
- 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,8 +1965,207 @@ 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
|
+
const proxyPresent = allTools.some((tool) => tool.name === "mcp");
|
|
2100
|
+
const adapterTools = allTools.filter((tool) => sourceIsMcpAdapter(tool.sourceInfo));
|
|
2101
|
+
const directTools = adapterTools.filter((tool) => tool.name !== "mcp").map((tool) => ({
|
|
2102
|
+
name: tool.name,
|
|
2103
|
+
schemaHash: schemaHash(tool.parameters),
|
|
2104
|
+
}));
|
|
2105
|
+
const actualByName = new Map(directTools.map((entry) => [entry.name, entry]));
|
|
2106
|
+
const missing = [...expectedByName.keys()].filter((name) => !actualByName.has(name)).sort();
|
|
2107
|
+
const unexpected = [...actualByName.keys()].filter((name) => !expectedByName.has(name)).sort();
|
|
2108
|
+
const schemaMismatches = [...expectedByName.entries()].flatMap(([name, expected]) => {
|
|
2109
|
+
const actual = actualByName.get(name);
|
|
2110
|
+
return actual && actual.schemaHash !== expected.effectiveSchemaHash
|
|
2111
|
+
? [{ name, expected: expected.effectiveSchemaHash, actual: actual.schemaHash }]
|
|
2112
|
+
: [];
|
|
2113
|
+
});
|
|
2114
|
+
const effectiveSetHash = toolSetHash(directTools);
|
|
2115
|
+
if (proxyPresent || missing.length > 0 || unexpected.length > 0 || schemaMismatches.length > 0) {
|
|
2116
|
+
throw new Error("effective tool surface mismatch: proxy=" + proxyPresent + " missing=" + missing.join(",") + " unexpected=" + unexpected.join(",") + " schemas=" + schemaMismatches.map((entry) => entry.name).join(","));
|
|
2117
|
+
}
|
|
2118
|
+
if (effectiveSetHash !== manifest.effectiveSetHash) throw new Error("effective tool set hash mismatch");
|
|
2119
|
+
receipt = {
|
|
2120
|
+
schemaVersion: SCHEMA_VERSION,
|
|
2121
|
+
status: "attested",
|
|
2122
|
+
mode,
|
|
2123
|
+
proxyPresent,
|
|
2124
|
+
effectiveSetHash,
|
|
2125
|
+
effectiveTools: directTools.sort((left, right) => left.name.localeCompare(right.name)),
|
|
2126
|
+
effectiveToolBindings: expectedEntries
|
|
2127
|
+
.map((entry) => ({ canonicalName: entry.canonicalName, exposedName: entry.name, effectiveSchemaHash: entry.effectiveSchemaHash }))
|
|
2128
|
+
.sort((left, right) => left.canonicalName.localeCompare(right.canonicalName)),
|
|
2129
|
+
attestorSourceSha256: sourceDigest,
|
|
2130
|
+
configSha256: configDigest,
|
|
2131
|
+
cacheSha256: cacheDigest,
|
|
2132
|
+
strictInputValidatorSelfTest: true,
|
|
2133
|
+
modelInvocationStarted: false,
|
|
2134
|
+
attestedAt: new Date().toISOString(),
|
|
2135
|
+
};
|
|
2136
|
+
safeWriteReceipt(receiptPath, receipt);
|
|
2137
|
+
if (mode === "probe") process.exit(0);
|
|
2138
|
+
} catch (error) {
|
|
2139
|
+
receipt = {
|
|
2140
|
+
schemaVersion: SCHEMA_VERSION,
|
|
2141
|
+
status: "rejected",
|
|
2142
|
+
mode,
|
|
2143
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2144
|
+
modelInvocationStarted: false,
|
|
2145
|
+
attestedAt: new Date().toISOString(),
|
|
2146
|
+
};
|
|
2147
|
+
safeWriteReceipt(receiptPath, receipt);
|
|
2148
|
+
process.exit(78);
|
|
2149
|
+
}
|
|
2150
|
+
});
|
|
2151
|
+
|
|
2152
|
+
pi.on("tool_call", (event) => {
|
|
2153
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
2154
|
+
const entry = Array.isArray(manifest.entries)
|
|
2155
|
+
? manifest.entries.find((candidate) => candidate.name === event.toolName)
|
|
2156
|
+
: null;
|
|
2157
|
+
if (!entry) return;
|
|
2158
|
+
const reason = inputErrorReason(entry.schema, event.input);
|
|
2159
|
+
if (!reason) return;
|
|
2160
|
+
return { block: true, reason: "Governed tool input rejected: " + reason };
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
`;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
1968
2166
|
// src/amaster-runtime-daemon/pi-managed-mcp-profile.mjs
|
|
1969
2167
|
var MANAGED_PI_MCP_TOOL_MODE = "proxy_only";
|
|
2168
|
+
var MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE = "direct_typed";
|
|
1970
2169
|
var MANAGED_PI_MCP_ARGS_NORMALIZATION = "json_string_control_characters_v1";
|
|
1971
2170
|
var MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME = "amaster-mcp-args-normalizer.js";
|
|
1972
2171
|
function createManagedPiMcpProfileApi(options = {}) {
|
|
@@ -1974,6 +2173,14 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
1974
2173
|
const nowImpl = typeof options.now === "function" ? options.now : Date.now;
|
|
1975
2174
|
const SUPPORTED_SCHEMA_VERSION2 = "amaster.governed-mcp.v1";
|
|
1976
2175
|
const SUPPORTED_SERVER_NAME2 = "amaster";
|
|
2176
|
+
const DIRECT_CATALOG_SCHEMA_VERSION = "amaster.governed-mcp-direct-catalog.v1";
|
|
2177
|
+
const DIRECT_TYPED_V1_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
2178
|
+
"runtime_action.submit",
|
|
2179
|
+
"amaster.read_company_diagnosis",
|
|
2180
|
+
"amaster.publish_company_diagnosis_brief"
|
|
2181
|
+
]);
|
|
2182
|
+
const PROVIDER_SAFE_TOOL_NAME = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
2183
|
+
const PI_BUILTIN_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "bash", "edit", "write", "grep", "find", "ls", "mcp"]);
|
|
1977
2184
|
const MINIMUM_PI_VERSION = [0, 73, 1];
|
|
1978
2185
|
const MINIMUM_MCP_ADAPTER_VERSION = [2, 6, 1];
|
|
1979
2186
|
const MANAGED_BROWSER_USE_PACKAGE = "@amaster.ai/pi-browser-use";
|
|
@@ -2140,7 +2347,7 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2140
2347
|
nonEmpty2(session.invocationId, "nativeSession.invocationId");
|
|
2141
2348
|
const sourceWorkspacePath = nonEmpty2(session.cwd, "nativeSession.cwd");
|
|
2142
2349
|
const issueRoot = dirname3(runDir);
|
|
2143
|
-
const managedSourceRunDirName = `${sourceRunId}-${
|
|
2350
|
+
const managedSourceRunDirName = `${sourceRunId}-${createHash3("sha256").update(sourceRunId).digest("hex").slice(0, 8)}`;
|
|
2144
2351
|
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
2352
|
if (sourceRunDirs.length !== 1) {
|
|
2146
2353
|
throw new Error(`pi_managed_mcp_session_rollout_missing: expected one source run directory for ${sourceRunId}, received ${sourceRunDirs.length}`);
|
|
@@ -2185,6 +2392,82 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2185
2392
|
if (!Number.isFinite(value)) throw new Error("pi_managed_mcp_attestation_failed: invalid attestation clock");
|
|
2186
2393
|
return value;
|
|
2187
2394
|
}
|
|
2395
|
+
function sha256(value) {
|
|
2396
|
+
return createHash3("sha256").update(value).digest("hex");
|
|
2397
|
+
}
|
|
2398
|
+
function adapterServerConfigHash(definition) {
|
|
2399
|
+
return sha256(stablePiJson({
|
|
2400
|
+
command: definition.command,
|
|
2401
|
+
args: definition.args,
|
|
2402
|
+
env: definition.env,
|
|
2403
|
+
cwd: definition.cwd,
|
|
2404
|
+
url: definition.url,
|
|
2405
|
+
headers: definition.headers,
|
|
2406
|
+
auth: definition.auth,
|
|
2407
|
+
bearerToken: definition.bearerToken,
|
|
2408
|
+
bearerTokenEnv: definition.bearerTokenEnv,
|
|
2409
|
+
exposeResources: definition.exposeResources,
|
|
2410
|
+
excludeTools: definition.excludeTools
|
|
2411
|
+
}));
|
|
2412
|
+
}
|
|
2413
|
+
function validateDirectCatalog(gateway) {
|
|
2414
|
+
const catalog = record6(gateway.toolCatalog);
|
|
2415
|
+
if (catalog.schemaVersion !== DIRECT_CATALOG_SCHEMA_VERSION) {
|
|
2416
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog schema mismatch");
|
|
2417
|
+
}
|
|
2418
|
+
const tools = Array.isArray(catalog.tools) ? catalog.tools.map(record6) : [];
|
|
2419
|
+
if (tools.length !== DIRECT_TYPED_V1_TOOL_NAMES.size) {
|
|
2420
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog size mismatch");
|
|
2421
|
+
}
|
|
2422
|
+
const names = /* @__PURE__ */ new Set();
|
|
2423
|
+
const exposedNames = /* @__PURE__ */ new Set();
|
|
2424
|
+
const normalized = tools.map((tool) => {
|
|
2425
|
+
const name = nonEmpty2(tool.name, "toolCatalog.tools.name");
|
|
2426
|
+
if (!DIRECT_TYPED_V1_TOOL_NAMES.has(name) || names.has(name)) {
|
|
2427
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog name mismatch");
|
|
2428
|
+
}
|
|
2429
|
+
names.add(name);
|
|
2430
|
+
const exposedName = nonEmpty2(tool.exposedName, `toolCatalog.tools.exposedName:${name}`);
|
|
2431
|
+
if (!PROVIDER_SAFE_TOOL_NAME.test(exposedName) || PI_BUILTIN_TOOL_NAMES.has(exposedName)) {
|
|
2432
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool exposed name is unsafe for ${name}`);
|
|
2433
|
+
}
|
|
2434
|
+
if (exposedNames.has(exposedName)) {
|
|
2435
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool exposed name collision for ${exposedName}`);
|
|
2436
|
+
}
|
|
2437
|
+
exposedNames.add(exposedName);
|
|
2438
|
+
const inputSchema = record6(tool.inputSchema);
|
|
2439
|
+
if (inputSchema.type !== "object" || inputSchema.additionalProperties !== false) {
|
|
2440
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool schema is not strict for ${name}`);
|
|
2441
|
+
}
|
|
2442
|
+
const schemaHash = stablePiToolSchemaHash(inputSchema);
|
|
2443
|
+
if (tool.schemaHash !== schemaHash) {
|
|
2444
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool schema hash mismatch for ${name}`);
|
|
2445
|
+
}
|
|
2446
|
+
const riskLevel = nonEmpty2(tool.riskLevel, `toolCatalog.tools.riskLevel:${name}`);
|
|
2447
|
+
if (!(/* @__PURE__ */ new Set(["read", "write", "destructive"])).has(riskLevel)) {
|
|
2448
|
+
throw new Error(`pi_managed_mcp_invalid: direct tool risk level mismatch for ${name}`);
|
|
2449
|
+
}
|
|
2450
|
+
return {
|
|
2451
|
+
name,
|
|
2452
|
+
exposedName,
|
|
2453
|
+
description: typeof tool.description === "string" ? tool.description : "",
|
|
2454
|
+
inputSchema,
|
|
2455
|
+
schemaHash,
|
|
2456
|
+
riskLevel,
|
|
2457
|
+
effectiveSchemaHash: stablePiToolSchemaHash(inputSchema, { adapterNormalized: true })
|
|
2458
|
+
};
|
|
2459
|
+
});
|
|
2460
|
+
const setHash = stablePiDirectCatalogSetHash(normalized.map((tool) => ({
|
|
2461
|
+
name: tool.name,
|
|
2462
|
+
exposedName: tool.exposedName,
|
|
2463
|
+
schemaHash: tool.schemaHash,
|
|
2464
|
+
riskLevel: tool.riskLevel
|
|
2465
|
+
})));
|
|
2466
|
+
if (catalog.setHash !== setHash) {
|
|
2467
|
+
throw new Error("pi_managed_mcp_invalid: direct tool catalog set hash mismatch");
|
|
2468
|
+
}
|
|
2469
|
+
return { setHash, tools: normalized.sort((left, right) => left.name.localeCompare(right.name)) };
|
|
2470
|
+
}
|
|
2188
2471
|
function piExecutableIdentity(executorCommand) {
|
|
2189
2472
|
try {
|
|
2190
2473
|
const realPath = realpathSync2(executorCommand);
|
|
@@ -2192,8 +2475,8 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2192
2475
|
if (!executableStat.isFile() || executableStat.isSymbolicLink()) {
|
|
2193
2476
|
throw Object.assign(new Error("Pi executable is not a regular file"), { code: "EUNSAFE" });
|
|
2194
2477
|
}
|
|
2195
|
-
const contentSha256 =
|
|
2196
|
-
return `sha256:${
|
|
2478
|
+
const contentSha256 = createHash3("sha256").update(readFileSync3(realPath)).digest("hex");
|
|
2479
|
+
return `sha256:${createHash3("sha256").update(JSON.stringify({ realPath, contentSha256 })).digest("hex")}`;
|
|
2197
2480
|
} catch (error) {
|
|
2198
2481
|
const errorCode = typeof error?.code === "string" ? error.code : "UNKNOWN";
|
|
2199
2482
|
throw new Error(`pi_managed_mcp_attestation_failed: --version error=${errorCode}`);
|
|
@@ -2239,7 +2522,15 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2239
2522
|
throw new Error("pi_managed_mcp_invalid: Gateway authority mismatch");
|
|
2240
2523
|
}
|
|
2241
2524
|
if ((runtimeAuth.issueId ?? null) !== (headers["x-amaster-issue-id"] ?? null)) throw new Error("pi_managed_mcp_invalid: issue authority mismatch");
|
|
2242
|
-
|
|
2525
|
+
const mcpToolMode = gateway.mcpToolMode ?? MANAGED_PI_MCP_TOOL_MODE;
|
|
2526
|
+
if (mcpToolMode !== MANAGED_PI_MCP_TOOL_MODE && mcpToolMode !== MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE) {
|
|
2527
|
+
throw new Error("pi_managed_mcp_invalid: unsupported managed Pi MCP tool mode");
|
|
2528
|
+
}
|
|
2529
|
+
const directCatalog = mcpToolMode === MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE ? validateDirectCatalog(gateway) : null;
|
|
2530
|
+
if (mcpToolMode === MANAGED_PI_MCP_TOOL_MODE && gateway.toolCatalog !== void 0) {
|
|
2531
|
+
throw new Error("pi_managed_mcp_invalid: proxy-only authority cannot carry a direct tool catalog");
|
|
2532
|
+
}
|
|
2533
|
+
return { gateway, gatewayUrl, sessionToken, headers, runId, mcpToolMode, directCatalog };
|
|
2243
2534
|
}
|
|
2244
2535
|
function isSensitiveAuthKey2(key) {
|
|
2245
2536
|
const normalized = String(key).trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replaceAll("-", "_");
|
|
@@ -2404,8 +2695,13 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2404
2695
|
config: record6(sourceSettings["pi-telemetry"])
|
|
2405
2696
|
};
|
|
2406
2697
|
}
|
|
2407
|
-
function seedPiRuntime(sourceHome, agentDir, sourceAcquisition = null) {
|
|
2698
|
+
function seedPiRuntime(sourceHome, agentDir, sourceAcquisition = null, mcpToolMode = MANAGED_PI_MCP_TOOL_MODE) {
|
|
2408
2699
|
const source = resolve2(nonEmpty2(sourceHome, "sourcePiHome"));
|
|
2700
|
+
const sourceStat = lstatSync2(source);
|
|
2701
|
+
if (!sourceStat.isDirectory() || sourceStat.isSymbolicLink()) {
|
|
2702
|
+
throw new Error("pi_managed_mcp_source_config_unsafe: Pi home");
|
|
2703
|
+
}
|
|
2704
|
+
chmodSync2(source, sourceStat.mode & 511 | 1);
|
|
2409
2705
|
const npmSource = join4(source, "npm");
|
|
2410
2706
|
const adapterPackagePath = join4(npmSource, "node_modules", "pi-mcp-adapter", "package.json");
|
|
2411
2707
|
if (!existsSync3(adapterPackagePath) || lstatSync2(adapterPackagePath).isSymbolicLink()) {
|
|
@@ -2455,10 +2751,17 @@ function createManagedPiMcpProfileApi(options = {}) {
|
|
|
2455
2751
|
`);
|
|
2456
2752
|
const extensionsDir = join4(agentDir, "extensions");
|
|
2457
2753
|
mkdirSync3(extensionsDir, { recursive: true, mode: 448 });
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2754
|
+
if (mcpToolMode === MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE) {
|
|
2755
|
+
writePrivateFile2(
|
|
2756
|
+
join4(extensionsDir, MANAGED_PI_EFFECTIVE_TOOLS_ATTESTOR_FILENAME),
|
|
2757
|
+
managedPiEffectiveToolsAttestorExtensionSource()
|
|
2758
|
+
);
|
|
2759
|
+
} else {
|
|
2760
|
+
writePrivateFile2(
|
|
2761
|
+
join4(extensionsDir, MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME),
|
|
2762
|
+
managedPiMcpArgsNormalizerExtensionSource()
|
|
2763
|
+
);
|
|
2764
|
+
}
|
|
2462
2765
|
if (sourceAcquisition && !copyPrivateFile(
|
|
2463
2766
|
join4(source, "extensions", "amaster-source-acquisition.js"),
|
|
2464
2767
|
join4(extensionsDir, "amaster-source-acquisition.js")
|
|
@@ -2551,9 +2854,62 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2551
2854
|
liveProbeAgeMs
|
|
2552
2855
|
};
|
|
2553
2856
|
}
|
|
2857
|
+
function attestDirectPiTools(executorCommand, env, input) {
|
|
2858
|
+
const result3 = spawnSyncImpl(executorCommand, [
|
|
2859
|
+
"--no-session",
|
|
2860
|
+
"--no-skills",
|
|
2861
|
+
"--no-context-files",
|
|
2862
|
+
"--no-builtin-tools",
|
|
2863
|
+
"--print",
|
|
2864
|
+
"probe effective tools"
|
|
2865
|
+
], {
|
|
2866
|
+
cwd: env.AMASTER_RUNTIME_EXECUTION_WORKDIR,
|
|
2867
|
+
env: { ...env, AMASTER_PI_EFFECTIVE_TOOLS_MODE: "probe" },
|
|
2868
|
+
encoding: "utf8",
|
|
2869
|
+
timeout: PI_ATTESTATION_TIMEOUT_MS,
|
|
2870
|
+
killSignal: "SIGKILL",
|
|
2871
|
+
maxBuffer: 1024 * 1024
|
|
2872
|
+
});
|
|
2873
|
+
if (result3.error) {
|
|
2874
|
+
const code = typeof result3.error.code === "string" ? result3.error.code : "UNKNOWN";
|
|
2875
|
+
throw new Error(`pi_managed_mcp_effective_tools_failed: probe error=${code}`);
|
|
2876
|
+
}
|
|
2877
|
+
if (result3.status !== 0) {
|
|
2878
|
+
let receiptError = "receipt unavailable";
|
|
2879
|
+
try {
|
|
2880
|
+
const rejectedReceipt = JSON.parse(readFileSync3(input.receiptPath, "utf8"));
|
|
2881
|
+
if (typeof rejectedReceipt.error === "string" && rejectedReceipt.error.length > 0) {
|
|
2882
|
+
receiptError = rejectedReceipt.error.slice(0, 512);
|
|
2883
|
+
}
|
|
2884
|
+
} catch {
|
|
2885
|
+
}
|
|
2886
|
+
throw new Error(`pi_managed_mcp_effective_tools_failed: probe exit=${result3.status ?? "unknown"} reason=${receiptError}`);
|
|
2887
|
+
}
|
|
2888
|
+
let receipt;
|
|
2889
|
+
try {
|
|
2890
|
+
receipt = JSON.parse(readFileSync3(input.receiptPath, "utf8"));
|
|
2891
|
+
} catch {
|
|
2892
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: probe receipt missing");
|
|
2893
|
+
}
|
|
2894
|
+
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) {
|
|
2895
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: probe receipt mismatch");
|
|
2896
|
+
}
|
|
2897
|
+
if (sha256(readFileSync3(input.configPath)) !== input.configSha256) {
|
|
2898
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: config drifted during probe");
|
|
2899
|
+
}
|
|
2900
|
+
if (sha256(readFileSync3(input.cachePath)) !== input.cacheSha256) {
|
|
2901
|
+
throw new Error("pi_managed_mcp_effective_tools_failed: cache drifted during probe");
|
|
2902
|
+
}
|
|
2903
|
+
return {
|
|
2904
|
+
effectiveToolSetHash: receipt.effectiveSetHash,
|
|
2905
|
+
effectiveToolProbeDigest: sha256(stablePiJson(receipt)),
|
|
2906
|
+
effectiveToolProbeAt: receipt.attestedAt,
|
|
2907
|
+
effectiveToolBindings: receipt.effectiveToolBindings
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2554
2910
|
function prepareManagedPiMcpProfile2(input) {
|
|
2555
2911
|
assertInvocationIsolation2(input);
|
|
2556
|
-
const { gateway, gatewayUrl, sessionToken, headers, runId } = validateAuthority2(input);
|
|
2912
|
+
const { gateway, gatewayUrl, sessionToken, headers, runId, mcpToolMode, directCatalog } = validateAuthority2(input);
|
|
2557
2913
|
const runDir = resolve2(nonEmpty2(input.runDir, "runDir"));
|
|
2558
2914
|
const executorHome = resolve2(nonEmpty2(input.executorHome, "executorHome"));
|
|
2559
2915
|
if (!within4(executorHome, join4(runDir, "executors"))) throw new Error("pi_managed_mcp_owner_mismatch: executorHome is outside the managed run");
|
|
@@ -2580,24 +2936,82 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2580
2936
|
commandId: input.commandId
|
|
2581
2937
|
});
|
|
2582
2938
|
const sourcePiHome = nonEmpty2(input.baseEnv?.PI_CODING_AGENT_DIR ?? input.baseEnv?.PI_AGENT_HOME, "sourcePiHome");
|
|
2583
|
-
const seededRuntime = seedPiRuntime(sourcePiHome, piCodingAgentDir, input.sourceAcquisition);
|
|
2939
|
+
const seededRuntime = seedPiRuntime(sourcePiHome, piCodingAgentDir, input.sourceAcquisition, mcpToolMode);
|
|
2584
2940
|
const restoredNativeSession = restoreManagedPiSessionRollout(input, sessionsRoot, runDir, executorHome, authority);
|
|
2585
2941
|
const configPath = join4(piCodingAgentDir, "mcp.json");
|
|
2942
|
+
const directToolNames = directCatalog?.tools.map((tool) => tool.exposedName) ?? [];
|
|
2943
|
+
const serverConfig = {
|
|
2944
|
+
type: "http",
|
|
2945
|
+
url: gatewayUrl,
|
|
2946
|
+
headers: { Authorization: `Bearer ${sessionToken}`, ...headers },
|
|
2947
|
+
lifecycle: directCatalog ? "lazy" : "eager",
|
|
2948
|
+
...directCatalog ? { exposeResources: false, directTools: directToolNames } : {}
|
|
2949
|
+
};
|
|
2586
2950
|
const config = {
|
|
2587
2951
|
settings: {
|
|
2588
|
-
toolPrefix: "none"
|
|
2952
|
+
toolPrefix: "none",
|
|
2953
|
+
...directCatalog ? { disableProxyTool: true } : {}
|
|
2589
2954
|
},
|
|
2590
2955
|
mcpServers: {
|
|
2591
|
-
[SUPPORTED_SERVER_NAME2]:
|
|
2592
|
-
type: "http",
|
|
2593
|
-
url: gatewayUrl,
|
|
2594
|
-
headers: { Authorization: `Bearer ${sessionToken}`, ...headers },
|
|
2595
|
-
lifecycle: "eager"
|
|
2596
|
-
}
|
|
2956
|
+
[SUPPORTED_SERVER_NAME2]: serverConfig
|
|
2597
2957
|
}
|
|
2598
2958
|
};
|
|
2599
2959
|
writePrivateFile2(configPath, `${JSON.stringify(config, null, 2)}
|
|
2600
2960
|
`);
|
|
2961
|
+
let directAttestationInput = null;
|
|
2962
|
+
if (directCatalog) {
|
|
2963
|
+
const cachePath = join4(piCodingAgentDir, "mcp-cache.json");
|
|
2964
|
+
const cache = {
|
|
2965
|
+
version: 1,
|
|
2966
|
+
servers: {
|
|
2967
|
+
[SUPPORTED_SERVER_NAME2]: {
|
|
2968
|
+
configHash: adapterServerConfigHash(serverConfig),
|
|
2969
|
+
tools: directCatalog.tools.map((tool) => ({
|
|
2970
|
+
name: tool.exposedName,
|
|
2971
|
+
description: tool.description,
|
|
2972
|
+
inputSchema: tool.inputSchema
|
|
2973
|
+
})),
|
|
2974
|
+
resources: [],
|
|
2975
|
+
cachedAt: currentTimeMs()
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
};
|
|
2979
|
+
writePrivateFile2(cachePath, `${JSON.stringify(cache, null, 2)}
|
|
2980
|
+
`);
|
|
2981
|
+
const cacheSha256 = sha256(readFileSync3(cachePath));
|
|
2982
|
+
const attestorSourceSha256 = sha256(managedPiEffectiveToolsAttestorExtensionSource());
|
|
2983
|
+
const manifestPath = join4(piCodingAgentDir, "effective-tools-manifest.json");
|
|
2984
|
+
const receiptPath = join4(tmp, "effective-tools-receipt.json");
|
|
2985
|
+
const manifest = {
|
|
2986
|
+
schemaVersion: MANAGED_PI_EFFECTIVE_TOOLS_SCHEMA_VERSION,
|
|
2987
|
+
serverName: SUPPORTED_SERVER_NAME2,
|
|
2988
|
+
entries: directCatalog.tools.map((tool) => ({
|
|
2989
|
+
name: tool.exposedName,
|
|
2990
|
+
canonicalName: tool.name,
|
|
2991
|
+
schema: tool.inputSchema,
|
|
2992
|
+
effectiveSchemaHash: tool.effectiveSchemaHash
|
|
2993
|
+
})),
|
|
2994
|
+
effectiveSetHash: stablePiEffectiveToolSetHash(directCatalog.tools.map((tool) => ({
|
|
2995
|
+
name: tool.exposedName,
|
|
2996
|
+
schemaHash: tool.effectiveSchemaHash
|
|
2997
|
+
}))),
|
|
2998
|
+
attestorSourceSha256,
|
|
2999
|
+
configSha256: sha256(readFileSync3(configPath)),
|
|
3000
|
+
cacheSha256
|
|
3001
|
+
};
|
|
3002
|
+
writePrivateFile2(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
3003
|
+
`);
|
|
3004
|
+
directAttestationInput = {
|
|
3005
|
+
cachePath,
|
|
3006
|
+
manifestPath,
|
|
3007
|
+
receiptPath,
|
|
3008
|
+
cacheSha256,
|
|
3009
|
+
configPath,
|
|
3010
|
+
configSha256: sha256(readFileSync3(configPath)),
|
|
3011
|
+
attestorSourceSha256,
|
|
3012
|
+
effectiveSetHash: manifest.effectiveSetHash
|
|
3013
|
+
};
|
|
3014
|
+
}
|
|
2601
3015
|
const env = {
|
|
2602
3016
|
...buildIsolatedEnvironment2(input.baseEnv, input.commandEnv),
|
|
2603
3017
|
HOME: home,
|
|
@@ -2608,18 +3022,30 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2608
3022
|
"AMASTER-CLI_CODING_AGENT_SESSION_DIR": sessionsRoot,
|
|
2609
3023
|
PI_AGENT_MCP_SERVERS_FILE: configPath,
|
|
2610
3024
|
TMPDIR: tmp,
|
|
3025
|
+
...directAttestationInput ? {
|
|
3026
|
+
AMASTER_PI_EFFECTIVE_TOOLS_MODE: "enforce",
|
|
3027
|
+
AMASTER_PI_EFFECTIVE_TOOLS_MANIFEST: directAttestationInput.manifestPath,
|
|
3028
|
+
AMASTER_PI_EFFECTIVE_TOOLS_RECEIPT: directAttestationInput.receiptPath,
|
|
3029
|
+
AMASTER_PI_EFFECTIVE_TOOLS_CACHE: directAttestationInput.cachePath,
|
|
3030
|
+
AMASTER_PI_EFFECTIVE_TOOLS_CONFIG: directAttestationInput.configPath
|
|
3031
|
+
} : {},
|
|
2611
3032
|
...input.sourceAcquisition ? {
|
|
2612
3033
|
PI_BROWSER_USE_RUNTIME_READ_POLICY: "required"
|
|
2613
3034
|
} : {}
|
|
2614
3035
|
};
|
|
2615
3036
|
const executorAttestation = attestPi(nonEmpty2(input.executorCommand, "executorCommand"), env, configPath, config);
|
|
3037
|
+
const effectiveToolsAttestation = directAttestationInput ? attestDirectPiTools(nonEmpty2(input.executorCommand, "executorCommand"), env, directAttestationInput) : {};
|
|
2616
3038
|
const attestationFacts = {
|
|
2617
3039
|
connectorVersion: nonEmpty2(input.connectorVersion, "connectorVersion"),
|
|
2618
3040
|
executorKind: "pi",
|
|
2619
3041
|
...executorAttestation,
|
|
2620
3042
|
mcpAdapterVersion: seededRuntime.adapterVersion,
|
|
2621
|
-
mcpToolMode
|
|
2622
|
-
mcpArgsNormalization: MANAGED_PI_MCP_ARGS_NORMALIZATION,
|
|
3043
|
+
mcpToolMode,
|
|
3044
|
+
mcpArgsNormalization: directCatalog ? "none" : MANAGED_PI_MCP_ARGS_NORMALIZATION,
|
|
3045
|
+
...directCatalog ? {
|
|
3046
|
+
catalogSetHash: directCatalog.setHash,
|
|
3047
|
+
...effectiveToolsAttestation
|
|
3048
|
+
} : {},
|
|
2623
3049
|
configMode: "isolated_home_run_scoped_mcp_file",
|
|
2624
3050
|
namespace: SUPPORTED_SERVER_NAME2,
|
|
2625
3051
|
schemaVersion: SUPPORTED_SCHEMA_VERSION2,
|
|
@@ -2645,7 +3071,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
|
|
|
2645
3071
|
])],
|
|
2646
3072
|
attestation: {
|
|
2647
3073
|
...attestationFacts,
|
|
2648
|
-
attestationId:
|
|
3074
|
+
attestationId: createHash3("sha256").update(JSON.stringify(attestationFacts)).digest("hex"),
|
|
2649
3075
|
attestedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2650
3076
|
}
|
|
2651
3077
|
};
|
|
@@ -3466,10 +3892,10 @@ function wikiAccessRuleLine(input) {
|
|
|
3466
3892
|
const tools = input.hasGovernedMcp === true && access.tools === true;
|
|
3467
3893
|
const treePath = readString(access.treePath);
|
|
3468
3894
|
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).`;
|
|
3895
|
+
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
3896
|
}
|
|
3471
3897
|
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
|
|
3898
|
+
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
3899
|
}
|
|
3474
3900
|
if (treePath) {
|
|
3475
3901
|
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 +3993,13 @@ function continuationRuntimeActionEnvelope(context) {
|
|
|
3567
3993
|
if (!readString(envelope.schemaVersion) || !readString(envelope.idempotencyKey) || action.type !== "update_parent" || action.status !== "todo" || !readString(action.comment)) return null;
|
|
3568
3994
|
return envelope;
|
|
3569
3995
|
}
|
|
3996
|
+
function managedDirectToolName(input, canonicalName) {
|
|
3997
|
+
if (input.managedMcpToolMode !== "direct_typed") return null;
|
|
3998
|
+
const catalog = asRecord(input.managedMcpToolCatalog);
|
|
3999
|
+
const tools = Array.isArray(catalog.tools) ? catalog.tools.map(asRecord) : [];
|
|
4000
|
+
const match = tools.find((tool) => readString(tool.name) === canonicalName);
|
|
4001
|
+
return readString(match?.exposedName) ?? null;
|
|
4002
|
+
}
|
|
3570
4003
|
function runtimeActionContinuationOptionText(input) {
|
|
3571
4004
|
if (!isRecoveryWakeReason(input.wakeReason)) return "";
|
|
3572
4005
|
const heading = "### Runtime Action Continuation Option";
|
|
@@ -3580,6 +4013,20 @@ Runtime Action continuation is unavailable: managed governed MCP capability is m
|
|
|
3580
4013
|
Runtime Action continuation is unavailable: continuationRuntimeActionEnvelope is missing or invalid. Do not guess a tool call.`;
|
|
3581
4014
|
}
|
|
3582
4015
|
if (input.executorKind === "pi") {
|
|
4016
|
+
if (input.managedMcpToolMode === "direct_typed") {
|
|
4017
|
+
const toolName = managedDirectToolName(input, "runtime_action.submit");
|
|
4018
|
+
if (!toolName) {
|
|
4019
|
+
return `${heading}
|
|
4020
|
+
Runtime Action continuation is unavailable: the run catalog does not advertise the required typed submit tool. Do not guess a tool call.`;
|
|
4021
|
+
}
|
|
4022
|
+
return [
|
|
4023
|
+
heading,
|
|
4024
|
+
`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.`,
|
|
4025
|
+
"```json",
|
|
4026
|
+
jsonText(envelope),
|
|
4027
|
+
"```"
|
|
4028
|
+
].join("\n");
|
|
4029
|
+
}
|
|
3583
4030
|
if (input.managedMcpToolMode !== "proxy_only") {
|
|
3584
4031
|
return `${heading}
|
|
3585
4032
|
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 +4247,19 @@ function piMcpProxyExamplesText(input) {
|
|
|
3800
4247
|
`- read document: ${proxy("amaster.read_issue_document", { issueId: "AM-123", key: "plan" })}`
|
|
3801
4248
|
].join("\n");
|
|
3802
4249
|
}
|
|
4250
|
+
function piDirectTypedToolsText(input) {
|
|
4251
|
+
if (!input.hasGovernedMcp || input.executorKind !== "pi" || input.managedMcpToolMode !== "direct_typed") return "";
|
|
4252
|
+
const catalog = asRecord(input.managedMcpToolCatalog);
|
|
4253
|
+
const tools = (Array.isArray(catalog.tools) ? catalog.tools : []).map(asRecord).map((tool) => ({ name: readString(tool.exposedName), description: readString(tool.description) })).filter((tool) => tool.name);
|
|
4254
|
+
if (tools.length === 0) {
|
|
4255
|
+
return "Direct typed governed tools are unavailable because the run catalog snapshot is empty. Do not guess a proxy or tool name.";
|
|
4256
|
+
}
|
|
4257
|
+
return [
|
|
4258
|
+
"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.",
|
|
4259
|
+
...tools.map((tool) => `- ${tool.name}${tool.description ? `: ${tool.description}` : ""}`),
|
|
4260
|
+
"A tool not listed above is unavailable in this run. Do not infer a namespace or fall back to REST/bare MCP."
|
|
4261
|
+
].join("\n");
|
|
4262
|
+
}
|
|
3803
4263
|
function sectionText(section) {
|
|
3804
4264
|
if (!section.content) return "";
|
|
3805
4265
|
return section.title ? `## ${section.title}
|
|
@@ -3906,10 +4366,14 @@ function compileCommandPromptWithManifest(input, options = {}) {
|
|
|
3906
4366
|
resolvedDependencies.details.content ? `Auxiliary predecessor context (may be truncated):
|
|
3907
4367
|
${resolvedDependencies.details.content}` : ""
|
|
3908
4368
|
].filter(Boolean).join("\n\n") : "";
|
|
3909
|
-
const piMcpProxyExamples = resolvedDependencies.required.content ? "" : piMcpProxyExamplesText(input);
|
|
4369
|
+
const piMcpProxyExamples = resolvedDependencies.required.content ? "" : [piMcpProxyExamplesText(input), piDirectTypedToolsText(input)].filter(Boolean).join("\n");
|
|
3910
4370
|
const deliveryReadinessContent = runtimeDeliveryReadinessText(context, input);
|
|
3911
4371
|
const rawSections = [
|
|
3912
|
-
{ name: "
|
|
4372
|
+
{ name: "recovery_instruction", title: "Recovery Instruction", priority: 100, sourceRef: `run:${input.runId ?? "unknown"}`, content: completeRecoveryInstruction, truncationReason: completeRecoveryInstruction ? null : "mode_selection" },
|
|
4373
|
+
{ name: "approval_continuation", title: "Approved Runtime Action Continuation", priority: 99, sourceRef: `run:${input.runId ?? "unknown"}`, content: approvalContinuationText(input), truncationReason: mode === "continuation" ? null : "mode_selection" },
|
|
4374
|
+
{ name: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
|
|
4375
|
+
{ 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" },
|
|
4376
|
+
{ 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
4377
|
...resolvedDependencyContent ? [{
|
|
3914
4378
|
name: "resolved_dependencies",
|
|
3915
4379
|
title: "Resolved Dependency Outputs",
|
|
@@ -3918,16 +4382,12 @@ ${resolvedDependencies.details.content}` : ""
|
|
|
3918
4382
|
content: resolvedDependencyContent,
|
|
3919
4383
|
mandatoryContent: resolvedDependencies.required.content
|
|
3920
4384
|
}] : [],
|
|
3921
|
-
{ name: "
|
|
3922
|
-
{ name: "
|
|
4385
|
+
...deliveryReadinessContent ? [{ name: "runtime_delivery_readiness", title: "Current Delivery Readiness", priority: 99, sourceRef: `issue:${input.issueId ?? "unknown"}:delivery`, content: deliveryReadinessContent }] : [],
|
|
4386
|
+
{ name: "runtime_rules", title: "", priority: 100, sourceRef: `command:${input.commandId}`, content: fixedRules(input, !hasTask) },
|
|
3923
4387
|
{ name: "runtime_authorization", title: "Runtime Action Contract", priority: 98, sourceRef: `run:${input.runId ?? "unknown"}`, content: runtimeAuthorizationText(context, mode, { suppressOrdinaryCompletionContract }) },
|
|
3924
4388
|
{ 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
4389
|
...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" },
|
|
4390
|
+
...piMcpProxyExamples ? [{ name: "pi_mcp_proxy_examples", title: "Pi MCP Proxy Examples", priority: 96, sourceRef: "amaster_governed_mcp_proxy_contract", content: piMcpProxyExamples }] : [],
|
|
3931
4391
|
{ 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
4392
|
{ name: "agent_instructions", title: "Agent Instructions", priority: 100, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
|
|
3933
4393
|
{ name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
|
|
@@ -5791,7 +6251,7 @@ var postJsonWithRetry = postRuntimeConnectorJsonWithRetry;
|
|
|
5791
6251
|
var bestEffortPostJson = bestEffortPostRuntimeConnectorJson;
|
|
5792
6252
|
|
|
5793
6253
|
// src/amaster-runtime-daemon/runtime-artifact-upload.mjs
|
|
5794
|
-
import { createHash as
|
|
6254
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5795
6255
|
import { lstatSync as lstatSync3, readFileSync as readFileSync6, realpathSync as realpathSync3 } from "node:fs";
|
|
5796
6256
|
import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3 } from "node:path";
|
|
5797
6257
|
var SHA256_PATTERN = /^[a-f0-9]{64}$/;
|
|
@@ -5834,7 +6294,7 @@ function prepareRuntimeArtifactUploads(cwd, mcpToolResults) {
|
|
|
5834
6294
|
throw new Error(`Runtime Artifact ${intentId} source is not an owned regular file`);
|
|
5835
6295
|
}
|
|
5836
6296
|
const body = readFileSync6(sourcePath);
|
|
5837
|
-
const actualSha256 =
|
|
6297
|
+
const actualSha256 = createHash4("sha256").update(body).digest("hex");
|
|
5838
6298
|
if (body.length !== expectedByteSize || actualSha256 !== expectedSha256) {
|
|
5839
6299
|
throw new Error(`Runtime Artifact ${intentId} bytes do not match the governed ownership manifest`);
|
|
5840
6300
|
}
|
|
@@ -5924,7 +6384,7 @@ function createRuntimeArtifactIngestQueue({ ingest, onError }) {
|
|
|
5924
6384
|
}
|
|
5925
6385
|
|
|
5926
6386
|
// src/amaster-runtime-daemon/workspace-guard.mjs
|
|
5927
|
-
import { createHash as
|
|
6387
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5928
6388
|
import { existsSync as existsSync7, mkdirSync as mkdirSync6, realpathSync as realpathSync4, statSync as statSync3 } from "node:fs";
|
|
5929
6389
|
import { basename as basename4, join as join8, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve4 } from "node:path";
|
|
5930
6390
|
|
|
@@ -6035,7 +6495,7 @@ function resolveWorkspaceCwd(config, command) {
|
|
|
6035
6495
|
return cwd;
|
|
6036
6496
|
}
|
|
6037
6497
|
function shortHash(value, length = 12) {
|
|
6038
|
-
return
|
|
6498
|
+
return createHash5("sha256").update(String(value)).digest("hex").slice(0, length);
|
|
6039
6499
|
}
|
|
6040
6500
|
function safeSegment(value, fallback) {
|
|
6041
6501
|
const raw = String(value ?? "").trim();
|
|
@@ -6467,7 +6927,7 @@ function summarizeAmasterRuntimeVersionDrift(input = {}) {
|
|
|
6467
6927
|
}
|
|
6468
6928
|
|
|
6469
6929
|
// src/amaster-runtime-daemon/pi-child-isolation.mjs
|
|
6470
|
-
import { createHash as
|
|
6930
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
6471
6931
|
import {
|
|
6472
6932
|
chmodSync as chmodSync3,
|
|
6473
6933
|
chownSync,
|
|
@@ -6478,7 +6938,7 @@ import {
|
|
|
6478
6938
|
import { resolve as resolve7, sep } from "node:path";
|
|
6479
6939
|
var defaultFs = { chmodSync: chmodSync3, chownSync, lchownSync, lstatSync: lstatSync4, readdirSync: readdirSync6 };
|
|
6480
6940
|
function defaultHashRunId(runId) {
|
|
6481
|
-
return Number.parseInt(
|
|
6941
|
+
return Number.parseInt(createHash6("sha256").update(runId).digest("hex").slice(0, 8), 16);
|
|
6482
6942
|
}
|
|
6483
6943
|
function positiveInteger(value, label) {
|
|
6484
6944
|
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
@@ -6602,7 +7062,7 @@ function preparePiChildIsolation(input) {
|
|
|
6602
7062
|
}
|
|
6603
7063
|
|
|
6604
7064
|
// src/amaster-runtime-daemon/pi-company-memory.mjs
|
|
6605
|
-
import { createHash as
|
|
7065
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
6606
7066
|
import {
|
|
6607
7067
|
chmodSync as chmodSync4,
|
|
6608
7068
|
chownSync as chownSync2,
|
|
@@ -6688,7 +7148,7 @@ function safeCompanyPiHomeSegment(companyId) {
|
|
|
6688
7148
|
const raw = requiredString2(companyId, "companyId");
|
|
6689
7149
|
if (/^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$/.test(raw)) return raw;
|
|
6690
7150
|
const normalized = raw.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "").slice(0, 80);
|
|
6691
|
-
const hash =
|
|
7151
|
+
const hash = createHash7("sha256").update(raw).digest("hex").slice(0, 12);
|
|
6692
7152
|
return normalized ? `${normalized}-${hash}` : `company-${hash}`;
|
|
6693
7153
|
}
|
|
6694
7154
|
function ensureMemoryRoot(root, fs) {
|
|
@@ -6727,7 +7187,7 @@ function allocateCompanyGid(root, companyId, input, fs) {
|
|
|
6727
7187
|
if (groups[companyId]) return groups[companyId];
|
|
6728
7188
|
const used = new Set(Object.values(groups));
|
|
6729
7189
|
const initialOffset = Number.parseInt(
|
|
6730
|
-
|
|
7190
|
+
createHash7("sha256").update(companyId).digest("hex").slice(0, 12),
|
|
6731
7191
|
16
|
|
6732
7192
|
) % gidSpan;
|
|
6733
7193
|
let gid = null;
|
|
@@ -6829,7 +7289,7 @@ function prepareCompanyPiMemory(input, fs = defaultFs2) {
|
|
|
6829
7289
|
}
|
|
6830
7290
|
|
|
6831
7291
|
// src/amaster-runtime-daemon/pi-trusted-runtime-profile.mjs
|
|
6832
|
-
import { createHash as
|
|
7292
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
6833
7293
|
import {
|
|
6834
7294
|
chmodSync as chmodSync5,
|
|
6835
7295
|
copyFileSync as copyFileSync2,
|
|
@@ -6847,6 +7307,8 @@ var ASSERTION_VERSION = "2026-07-25.v1";
|
|
|
6847
7307
|
var SHA256 = /^[a-f0-9]{64}$/;
|
|
6848
7308
|
var COPY_ENTRIES = ["SYSTEM.md", "policy", "skills", "agents", "bundles", "extensions"];
|
|
6849
7309
|
var JSON_ENTRIES = ["settings.json", "models.json"];
|
|
7310
|
+
var ROLE_SKILLS_DIR = "role-skills";
|
|
7311
|
+
var DISABLE_MODEL_INVOCATION_LINE = /^[ \t]*disable-model-invocation:[ \t]*true[ \t]*\r?$/m;
|
|
6850
7312
|
var SECRET_KEY = /(authorization|cookie|api[_-]?key|password|secret|token)$/i;
|
|
6851
7313
|
var SECRET_VALUE = /(?:authorization|cookie|api[_-]?key|password|secret|token)\s*[:=]\s*(?:bearer\s+)?[^\s"',;]+|bearer\s+[^\s"',;]+/i;
|
|
6852
7314
|
var MAX_AUDIT_BYTES = 1024 * 1024;
|
|
@@ -6867,7 +7329,7 @@ function sha256File(path, label) {
|
|
|
6867
7329
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
6868
7330
|
throw new Error(`pi_trusted_runtime_source_unsafe:${label}`);
|
|
6869
7331
|
}
|
|
6870
|
-
return
|
|
7332
|
+
return createHash8("sha256").update(readFileSync9(path)).digest("hex");
|
|
6871
7333
|
}
|
|
6872
7334
|
function verifyDeclaredFiles(manifest, root, label, ignoredPaths = [], enforceComplete = true) {
|
|
6873
7335
|
if (!Array.isArray(manifest.files) || manifest.files.length === 0) {
|
|
@@ -6965,6 +7427,53 @@ function copyTreeNoLinks(source, target) {
|
|
|
6965
7427
|
copyFileSync2(source, target);
|
|
6966
7428
|
chmodSync5(target, 384 | stat.mode & 73);
|
|
6967
7429
|
}
|
|
7430
|
+
var SKILL_PROFILE_NAME = /^[a-z0-9-]+$/;
|
|
7431
|
+
function readSkillProfile(seedRoot, skillProfile) {
|
|
7432
|
+
const agentsRoot = resolve9(seedRoot, "agents");
|
|
7433
|
+
const agentFile = resolve9(agentsRoot, `${skillProfile}.md`);
|
|
7434
|
+
if (!SKILL_PROFILE_NAME.test(skillProfile) || !within3(agentFile, agentsRoot) || !existsSync11(agentFile)) {
|
|
7435
|
+
throw new Error(`pi_trusted_runtime_skill_profile_unknown:${skillProfile}`);
|
|
7436
|
+
}
|
|
7437
|
+
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) ?? [];
|
|
7438
|
+
const bundlesRoot = resolve9(seedRoot, "bundles");
|
|
7439
|
+
const profile = [];
|
|
7440
|
+
for (const name of declared) {
|
|
7441
|
+
let source = join12(bundlesRoot, skillProfile, "skills", name);
|
|
7442
|
+
if (!existsSync11(join12(source, "SKILL.md"))) {
|
|
7443
|
+
const candidates = [];
|
|
7444
|
+
for (const category of readdirSync7(bundlesRoot).sort()) {
|
|
7445
|
+
if (category === skillProfile) continue;
|
|
7446
|
+
const candidate = join12(bundlesRoot, category, "skills", name);
|
|
7447
|
+
if (existsSync11(join12(candidate, "SKILL.md"))) candidates.push(candidate);
|
|
7448
|
+
}
|
|
7449
|
+
if (candidates.length > 1) {
|
|
7450
|
+
throw new Error(`pi_trusted_runtime_skill_profile_ambiguous:${skillProfile}:${name}`);
|
|
7451
|
+
}
|
|
7452
|
+
source = candidates[0];
|
|
7453
|
+
}
|
|
7454
|
+
if (source) profile.push({ name, source });
|
|
7455
|
+
}
|
|
7456
|
+
if (profile.length === 0) {
|
|
7457
|
+
throw new Error(`pi_trusted_runtime_skill_profile_unknown:${skillProfile}`);
|
|
7458
|
+
}
|
|
7459
|
+
return profile;
|
|
7460
|
+
}
|
|
7461
|
+
function materializeRoleSkills(seedRoot, agentDir, skillProfile) {
|
|
7462
|
+
const profile = readSkillProfile(seedRoot, skillProfile);
|
|
7463
|
+
const bundlesRoot = resolve9(seedRoot, "bundles");
|
|
7464
|
+
const enabled = [];
|
|
7465
|
+
for (const entry of profile) {
|
|
7466
|
+
const target = join12(agentDir, ROLE_SKILLS_DIR, entry.name);
|
|
7467
|
+
rmSync6(target, { recursive: true, force: true });
|
|
7468
|
+
copyTreeNoLinks(entry.source, target);
|
|
7469
|
+
const skillFile = join12(target, "SKILL.md");
|
|
7470
|
+
writeFileSync8(skillFile, readFileSync9(skillFile, "utf8").replace(DISABLE_MODEL_INVOCATION_LINE, ""), {
|
|
7471
|
+
mode: 384
|
|
7472
|
+
});
|
|
7473
|
+
enabled.push({ name: entry.name, path: relative6(bundlesRoot, entry.source).split("\\").join("/") });
|
|
7474
|
+
}
|
|
7475
|
+
return enabled;
|
|
7476
|
+
}
|
|
6968
7477
|
function mergeMcp(seedRoot, overlayRoot, governedConfig) {
|
|
6969
7478
|
const seed = record5(readJsonFile2(join12(seedRoot, "mcp.json"), "seed_mcp", { mcpServers: {} }));
|
|
6970
7479
|
const overlay = record5(readJsonFile2(join12(overlayRoot, "mcp.json"), "overlay_mcp", { mcpServers: {} }));
|
|
@@ -7029,6 +7538,8 @@ function materializeTrustedPiRuntimeProfile(input) {
|
|
|
7029
7538
|
if (existsSync11(source)) copyTreeNoLinks(source, target);
|
|
7030
7539
|
}
|
|
7031
7540
|
}
|
|
7541
|
+
const skillProfile = typeof input.skillProfile === "string" && input.skillProfile.trim() ? input.skillProfile.trim() : null;
|
|
7542
|
+
const enabledSkills = skillProfile ? materializeRoleSkills(seedRoot, agentDir, skillProfile) : [];
|
|
7032
7543
|
const mergedJson = {};
|
|
7033
7544
|
for (const entry of JSON_ENTRIES) {
|
|
7034
7545
|
const seed = readJsonFile2(join12(seedRoot, entry), `seed_${entry}`, {});
|
|
@@ -7043,6 +7554,13 @@ function materializeTrustedPiRuntimeProfile(input) {
|
|
|
7043
7554
|
allowSessionGrants: false
|
|
7044
7555
|
}
|
|
7045
7556
|
};
|
|
7557
|
+
if (skillProfile) {
|
|
7558
|
+
const current = Array.isArray(merged.skills) ? merged.skills : [];
|
|
7559
|
+
merged.skills = [
|
|
7560
|
+
ROLE_SKILLS_DIR,
|
|
7561
|
+
...current.filter((value) => value !== ROLE_SKILLS_DIR)
|
|
7562
|
+
];
|
|
7563
|
+
}
|
|
7046
7564
|
}
|
|
7047
7565
|
assertNoPersistentSecrets(merged, [entry]);
|
|
7048
7566
|
writeFileSync8(join12(agentDir, entry), `${JSON.stringify(merged, null, 2)}
|
|
@@ -7074,11 +7592,17 @@ function materializeTrustedPiRuntimeProfile(input) {
|
|
|
7074
7592
|
runtimeEnforcementDigest: input.verifiedAssertion.digests.runtimeEnforcementDigest,
|
|
7075
7593
|
unknownToolMode: input.verifiedAssertion.unknownToolMode,
|
|
7076
7594
|
directToolBudget: input.verifiedAssertion.directToolBudget,
|
|
7077
|
-
inheritedEntries: [...COPY_ENTRIES, ...JSON_ENTRIES, "mcp.json", "npm"]
|
|
7595
|
+
inheritedEntries: [...COPY_ENTRIES, ...JSON_ENTRIES, "mcp.json", "npm"],
|
|
7596
|
+
// What the model can actually see this run: which profile and which exact
|
|
7597
|
+
// bundle skills were enabled. Absent profile => main skills only.
|
|
7598
|
+
...skillProfile ? {
|
|
7599
|
+
skillProfile,
|
|
7600
|
+
enabledSkillsDigest: createHash8("sha256").update(JSON.stringify(enabledSkills)).digest("hex")
|
|
7601
|
+
} : {}
|
|
7078
7602
|
};
|
|
7079
7603
|
return {
|
|
7080
7604
|
facts,
|
|
7081
|
-
attestationId:
|
|
7605
|
+
attestationId: createHash8("sha256").update(JSON.stringify(facts)).digest("hex")
|
|
7082
7606
|
};
|
|
7083
7607
|
}
|
|
7084
7608
|
function assertAuditArgsRedacted(value) {
|
|
@@ -7274,7 +7798,7 @@ function verifyTrustedPiRuntimeAssertion(input) {
|
|
|
7274
7798
|
if (hasSourceAssertion) {
|
|
7275
7799
|
const exactTools = Array.isArray(record5(sourceProfile.tools).exactAllowlist) ? record5(sourceProfile.tools).exactAllowlist : [];
|
|
7276
7800
|
const exactActions = Array.isArray(record5(sourceProfile.actions).exactAllowlist) ? record5(sourceProfile.actions).exactAllowlist : [];
|
|
7277
|
-
const profileHash =
|
|
7801
|
+
const profileHash = createHash8("sha256").update(JSON.stringify(sourceProfile)).digest("hex");
|
|
7278
7802
|
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
7803
|
throw new Error("pi_trusted_runtime_assertion_binding_mismatch:sourceAcquisition");
|
|
7280
7804
|
}
|
|
@@ -7303,7 +7827,7 @@ function verifyTrustedPiRuntimeAssertion(input) {
|
|
|
7303
7827
|
|
|
7304
7828
|
// src/amaster-runtime-daemon/workspace-status.mjs
|
|
7305
7829
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
7306
|
-
import { createHash as
|
|
7830
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
7307
7831
|
import { existsSync as existsSync12, readdirSync as readdirSync8, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
|
|
7308
7832
|
import { basename as basename5, extname, isAbsolute as isAbsolute7, join as join13, relative as relative7, resolve as resolve10 } from "node:path";
|
|
7309
7833
|
var WORKSPACE_RUNTIME_SERVICES_FILENAME = ".amaster-runtime-services.json";
|
|
@@ -7375,7 +7899,7 @@ function sanitizeTrackedChange(line) {
|
|
|
7375
7899
|
return isSafeRelativePath(path) ? line : null;
|
|
7376
7900
|
}
|
|
7377
7901
|
function sha256File2(filePath) {
|
|
7378
|
-
return
|
|
7902
|
+
return createHash9("sha256").update(readFileSync10(filePath)).digest("hex");
|
|
7379
7903
|
}
|
|
7380
7904
|
function artifactHashCacheKey(relativePath, stat) {
|
|
7381
7905
|
return `${relativePath}\0${stat.size}\0${stat.mtimeMs}`;
|
|
@@ -7576,7 +8100,7 @@ function readWorkspaceStatus(cwd, opts = {}) {
|
|
|
7576
8100
|
}
|
|
7577
8101
|
|
|
7578
8102
|
// src/amaster-runtime-daemon/pi-browser-session-adapter.mjs
|
|
7579
|
-
import { createHash as
|
|
8103
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
7580
8104
|
import { spawn, spawnSync as spawnSync5 } from "node:child_process";
|
|
7581
8105
|
import { existsSync as existsSync13 } from "node:fs";
|
|
7582
8106
|
import {
|
|
@@ -7699,7 +8223,7 @@ function fail(code) {
|
|
|
7699
8223
|
throw Object.assign(new Error(code), { code });
|
|
7700
8224
|
}
|
|
7701
8225
|
function profileName(identity2) {
|
|
7702
|
-
return
|
|
8226
|
+
return createHash10("sha256").update(`${identity2.companyId}\0${identity2.bindingId}\0${identity2.localOpaqueRef}`).digest("hex");
|
|
7703
8227
|
}
|
|
7704
8228
|
function expectedMarker(identity2) {
|
|
7705
8229
|
return {
|
|
@@ -8098,7 +8622,7 @@ async function executeBrowserSessionCommand(command, dependencies = {}) {
|
|
|
8098
8622
|
}
|
|
8099
8623
|
|
|
8100
8624
|
// src/amaster-runtime-daemon/source-acquisition-invocation.mjs
|
|
8101
|
-
import { createHash as
|
|
8625
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
8102
8626
|
var SOURCE_ACQUISITION_PUBLIC_TOOLS = Object.freeze([
|
|
8103
8627
|
"source_open",
|
|
8104
8628
|
"source_snapshot",
|
|
@@ -8135,7 +8659,7 @@ function serializeSourceAcquisitionProfile(profile) {
|
|
|
8135
8659
|
const input = Buffer.from(JSON.stringify(profile), "utf8");
|
|
8136
8660
|
return {
|
|
8137
8661
|
input,
|
|
8138
|
-
sha256:
|
|
8662
|
+
sha256: createHash11("sha256").update(input).digest("hex")
|
|
8139
8663
|
};
|
|
8140
8664
|
}
|
|
8141
8665
|
function sourceAcquisitionManagedInputs(options) {
|
|
@@ -8171,7 +8695,7 @@ function assertSourceAcquisitionRuntimeAuthority({
|
|
|
8171
8695
|
}
|
|
8172
8696
|
|
|
8173
8697
|
// src/amaster-runtime-daemon.mjs
|
|
8174
|
-
var CONNECTOR_VERSION = "0.1.1-beta.
|
|
8698
|
+
var CONNECTOR_VERSION = "0.1.1-beta.4";
|
|
8175
8699
|
var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
|
|
8176
8700
|
var SOURCE_ACQUISITION_CAPABILITY = "source_acquisition_v1";
|
|
8177
8701
|
var SOURCE_ACQUISITION_PROFILE_VERSION = "source_acquisition_v1";
|
|
@@ -9468,7 +9992,7 @@ function sourceAcquisitionRuntimeProfile(config, command) {
|
|
|
9468
9992
|
if (!companyId || !bindingId || !/^profile_[a-z0-9]{16,64}$/i.test(localOpaqueRef ?? "")) {
|
|
9469
9993
|
throw new Error("source_acquisition_profile_invalid");
|
|
9470
9994
|
}
|
|
9471
|
-
const profileName2 =
|
|
9995
|
+
const profileName2 = createHash12("sha256").update(`${companyId}\0${bindingId}\0${localOpaqueRef}`).digest("hex");
|
|
9472
9996
|
const stateRoot = resolve12(config.browserSessionStateRoot);
|
|
9473
9997
|
const userDataDir = resolve12(stateRoot, profileName2);
|
|
9474
9998
|
if (!pathWithin2(userDataDir, stateRoot)) throw new Error("source_acquisition_browser_profile_invalid");
|
|
@@ -9665,6 +10189,7 @@ function buildCommandPrompt(command, workspace, materializedAttachments = [], op
|
|
|
9665
10189
|
hasGovernedMcp,
|
|
9666
10190
|
executorKind: options.executorKind,
|
|
9667
10191
|
managedMcpToolMode: options.managedMcpToolMode,
|
|
10192
|
+
managedMcpToolCatalog: options.managedMcpToolCatalog,
|
|
9668
10193
|
agentInstructions,
|
|
9669
10194
|
taskMarkdown,
|
|
9670
10195
|
attachmentsText,
|
|
@@ -12197,7 +12722,7 @@ async function materializeIssueAttachments(config, command, workspace) {
|
|
|
12197
12722
|
const body = await runtimeApiBuffer(runtimeAuth, contentPath);
|
|
12198
12723
|
writeFileSync9(targetPath, body);
|
|
12199
12724
|
const attachmentId = readString(attachment.id);
|
|
12200
|
-
const actualSha256 =
|
|
12725
|
+
const actualSha256 = createHash12("sha256").update(body).digest("hex");
|
|
12201
12726
|
const lineageCandidates = lineageCandidatesByAttachmentId.get(attachmentId) ?? [];
|
|
12202
12727
|
const lineage = selectAttachmentLineage(lineageCandidates, actualSha256);
|
|
12203
12728
|
if (lineageCandidates.length > 0 && !lineage) {
|
|
@@ -12289,7 +12814,7 @@ async function materializeRequiredArtifactInputs(config, command, workspace) {
|
|
|
12289
12814
|
throw new Error(`artifact_input_manifest_invalid: entry ${index} contentPath does not match attachmentId`);
|
|
12290
12815
|
}
|
|
12291
12816
|
const body = await runtimeApiBuffer(runtimeAuth, contentPath);
|
|
12292
|
-
const actualSha256 =
|
|
12817
|
+
const actualSha256 = createHash12("sha256").update(body).digest("hex");
|
|
12293
12818
|
if (body.byteLength !== byteSize || actualSha256 !== sha256) {
|
|
12294
12819
|
throw new Error(
|
|
12295
12820
|
`artifact_input_integrity_mismatch: workProductId=${workProductId} expectedBytes=${byteSize} actualBytes=${body.byteLength} expectedSha256=${sha256} actualSha256=${actualSha256}`
|
|
@@ -12359,7 +12884,7 @@ function safeCheckpointRelativePath(rawPath) {
|
|
|
12359
12884
|
return normalized;
|
|
12360
12885
|
}
|
|
12361
12886
|
function hashFileSha256(filePath) {
|
|
12362
|
-
return
|
|
12887
|
+
return createHash12("sha256").update(readFileSync11(filePath)).digest("hex");
|
|
12363
12888
|
}
|
|
12364
12889
|
async function materializeIssueCheckpoint(config, command, workspace) {
|
|
12365
12890
|
const checkpointDir = issueCheckpointDir(workspace);
|
|
@@ -12545,7 +13070,8 @@ async function executeRunCommand(config, command) {
|
|
|
12545
13070
|
await ingestWorkspaceStatus(config, command, cwd);
|
|
12546
13071
|
const promptCompilation = buildCommandPrompt(command, workspace, materializedAttachments, {
|
|
12547
13072
|
executorKind: executor.kind,
|
|
12548
|
-
managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? MANAGED_PI_MCP_TOOL_MODE : null,
|
|
13073
|
+
managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? readString(governedMcp.mcpToolMode) ?? MANAGED_PI_MCP_TOOL_MODE : null,
|
|
13074
|
+
managedMcpToolCatalog: asRecord(governedMcp.toolCatalog),
|
|
12549
13075
|
artifactVerifierCommands: config.artifactVerifierCommands,
|
|
12550
13076
|
workspaceBindings: config.workspaceBindings
|
|
12551
13077
|
});
|
|
@@ -12668,7 +13194,8 @@ async function executeRunCommand(config, command) {
|
|
|
12668
13194
|
profileRoot: managedMcpProfile.profileRoot,
|
|
12669
13195
|
agentDir: managedMcpProfile.env.PI_CODING_AGENT_DIR,
|
|
12670
13196
|
governedMcpConfigPath: managedMcpProfile.configPath,
|
|
12671
|
-
verifiedAssertion: trustedPiRuntime
|
|
13197
|
+
verifiedAssertion: trustedPiRuntime,
|
|
13198
|
+
skillProfile: readString(asRecord(command.payload).skillProfile)
|
|
12672
13199
|
});
|
|
12673
13200
|
executorEnv = {
|
|
12674
13201
|
...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.4";
|
|
9
9
|
|
|
10
10
|
const CAPABILITIES = [
|
|
11
11
|
"remote_registration",
|