@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.
@@ -2,7 +2,7 @@
2
2
  // MirrorX runtime connector daemon bundle.
3
3
 
4
4
  // src/amaster-runtime-daemon.mjs
5
- import { createHash as createHash11 } from "node:crypto";
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 createHash2 } from "node:crypto";
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}-${createHash2("sha256").update(sourceRunId).digest("hex").slice(0, 8)}`;
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 = createHash2("sha256").update(readFileSync3(realPath)).digest("hex");
2196
- return `sha256:${createHash2("sha256").update(JSON.stringify({ realPath, contentSha256 })).digest("hex")}`;
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
- return { gateway, gatewayUrl, sessionToken, headers, runId };
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
- writePrivateFile2(
2459
- join4(extensionsDir, MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME),
2460
- managedPiMcpArgsNormalizerExtensionSource()
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: MANAGED_PI_MCP_TOOL_MODE,
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: createHash2("sha256").update(JSON.stringify(attestationFacts)).digest("hex"),
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 targeted lookup before re-deriving knowledge the company already holds.";
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: "runtime_rules", title: "", priority: 100, sourceRef: `command:${input.commandId}`, content: fixedRules(input, !hasTask) },
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: "recovery_instruction", title: "Recovery Instruction", priority: 100, sourceRef: `run:${input.runId ?? "unknown"}`, content: completeRecoveryInstruction, truncationReason: completeRecoveryInstruction ? null : "mode_selection" },
3922
- { name: "approval_continuation", title: "Approved Runtime Action Continuation", priority: 99, sourceRef: `run:${input.runId ?? "unknown"}`, content: approvalContinuationText(input), truncationReason: mode === "continuation" ? null : "mode_selection" },
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: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
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 createHash3 } from "node:crypto";
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 = createHash3("sha256").update(body).digest("hex");
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 createHash4 } from "node:crypto";
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 createHash4("sha256").update(String(value)).digest("hex").slice(0, length);
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 createHash5 } from "node:crypto";
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(createHash5("sha256").update(runId).digest("hex").slice(0, 8), 16);
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 createHash6 } from "node:crypto";
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 = createHash6("sha256").update(raw).digest("hex").slice(0, 12);
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
- createHash6("sha256").update(companyId).digest("hex").slice(0, 12),
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 createHash7 } from "node:crypto";
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 createHash7("sha256").update(readFileSync9(path)).digest("hex");
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: createHash7("sha256").update(JSON.stringify(facts)).digest("hex")
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 = createHash7("sha256").update(JSON.stringify(sourceProfile)).digest("hex");
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 createHash8 } from "node:crypto";
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 createHash8("sha256").update(readFileSync10(filePath)).digest("hex");
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 createHash9 } from "node:crypto";
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 createHash9("sha256").update(`${identity2.companyId}\0${identity2.bindingId}\0${identity2.localOpaqueRef}`).digest("hex");
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 createHash10 } from "node:crypto";
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: createHash10("sha256").update(input).digest("hex")
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.3";
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 = createHash11("sha256").update(`${companyId}\0${bindingId}\0${localOpaqueRef}`).digest("hex");
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 = createHash11("sha256").update(body).digest("hex");
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 = createHash11("sha256").update(body).digest("hex");
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 createHash11("sha256").update(readFileSync11(filePath)).digest("hex");
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,
@@ -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.3";
8
+ const CONNECTOR_VERSION = "0.1.1-beta.4";
9
9
 
10
10
  const CAPABILITIES = [
11
11
  "remote_registration",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amaster.ai/employee-runtime-connector",
3
- "version": "0.1.1-beta.3",
3
+ "version": "0.1.1-beta.4",
4
4
  "description": "MirrorX runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",