@amaster.ai/employee-runtime-connector 0.1.1-beta.4 → 0.1.1-beta.6

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.
@@ -2096,15 +2096,28 @@ export default function amasterEffectiveToolsAttestor(pi) {
2096
2096
  }
2097
2097
 
2098
2098
  const allTools = pi.getAllTools();
2099
+ if (allTools.some((tool) => typeof tool.name !== "string" || !tool.name)) {
2100
+ throw new Error("registered tool identity mismatch");
2101
+ }
2102
+ const activeToolNames = pi.getActiveTools();
2103
+ if (activeToolNames.some((name) => typeof name !== "string" || !name)) {
2104
+ throw new Error("active tool identity mismatch");
2105
+ }
2106
+ activeToolNames.sort();
2107
+ const activeToolNameSet = new Set(activeToolNames);
2099
2108
  const proxyPresent = allTools.some((tool) => tool.name === "mcp");
2109
+ const nonCatalogTools = activeToolNames.filter((name) => !expectedByName.has(name));
2100
2110
  const adapterTools = allTools.filter((tool) => sourceIsMcpAdapter(tool.sourceInfo));
2101
- const directTools = adapterTools.filter((tool) => tool.name !== "mcp").map((tool) => ({
2111
+ const directTools = adapterTools.filter((tool) => tool.name !== "mcp" && activeToolNameSet.has(tool.name)).map((tool) => ({
2102
2112
  name: tool.name,
2103
2113
  schemaHash: schemaHash(tool.parameters),
2104
2114
  }));
2105
2115
  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();
2116
+ const missing = [...expectedByName.keys()].filter((name) => !actualByName.has(name) || !activeToolNameSet.has(name)).sort();
2117
+ const unexpected = adapterTools
2118
+ .map((tool) => tool.name)
2119
+ .filter((name) => name !== "mcp" && !expectedByName.has(name))
2120
+ .sort();
2108
2121
  const schemaMismatches = [...expectedByName.entries()].flatMap(([name, expected]) => {
2109
2122
  const actual = actualByName.get(name);
2110
2123
  return actual && actual.schemaHash !== expected.effectiveSchemaHash
@@ -2112,8 +2125,8 @@ export default function amasterEffectiveToolsAttestor(pi) {
2112
2125
  : [];
2113
2126
  });
2114
2127
  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(","));
2128
+ if (proxyPresent || nonCatalogTools.length > 0 || missing.length > 0 || unexpected.length > 0 || schemaMismatches.length > 0) {
2129
+ throw new Error("effective tool surface mismatch: proxy=" + proxyPresent + " nonCatalog=" + nonCatalogTools.join(",") + " missing=" + missing.join(",") + " unexpected=" + unexpected.join(",") + " schemas=" + schemaMismatches.map((entry) => entry.name).join(","));
2117
2130
  }
2118
2131
  if (effectiveSetHash !== manifest.effectiveSetHash) throw new Error("effective tool set hash mismatch");
2119
2132
  receipt = {
@@ -2168,6 +2181,18 @@ var MANAGED_PI_MCP_TOOL_MODE = "proxy_only";
2168
2181
  var MANAGED_PI_DIRECT_TYPED_MCP_TOOL_MODE = "direct_typed";
2169
2182
  var MANAGED_PI_MCP_ARGS_NORMALIZATION = "json_string_control_characters_v1";
2170
2183
  var MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME = "amaster-mcp-args-normalizer.js";
2184
+ function applyManagedPiToolAllowlist(args, profile) {
2185
+ const toolAllowlist = Array.isArray(profile?.toolAllowlist) ? profile.toolAllowlist.filter((name) => typeof name === "string" && name) : [];
2186
+ if (toolAllowlist.length === 0) return [...args];
2187
+ const printArgIndex = Math.max(args.lastIndexOf("-p"), args.lastIndexOf("--print"));
2188
+ if (printArgIndex < 0) throw new Error("pi_managed_mcp_invocation_invalid: print mode argument missing");
2189
+ return [
2190
+ ...args.slice(0, printArgIndex),
2191
+ "--tools",
2192
+ toolAllowlist.join(","),
2193
+ ...args.slice(printArgIndex)
2194
+ ];
2195
+ }
2171
2196
  function createManagedPiMcpProfileApi(options = {}) {
2172
2197
  const spawnSyncImpl = typeof options.spawnSync === "function" ? options.spawnSync : spawnSync2;
2173
2198
  const nowImpl = typeof options.now === "function" ? options.now : Date.now;
@@ -2264,6 +2289,12 @@ function createManagedPiMcpProfileApi(options = {}) {
2264
2289
  ]);
2265
2290
  const FORBIDDEN_ARGV = /* @__PURE__ */ new Set([
2266
2291
  "--no-tools",
2292
+ "--no-builtin-tools",
2293
+ "-nbt",
2294
+ "--tools",
2295
+ "-t",
2296
+ "--exclude-tools",
2297
+ "-xt",
2267
2298
  "--no-extensions",
2268
2299
  "--no-skills",
2269
2300
  "--no-session",
@@ -2550,7 +2581,7 @@ function createManagedPiMcpProfileApi(options = {}) {
2550
2581
  if (!ALLOWED_COMMAND_ENV2.has(name)) throw new Error(`pi_managed_mcp_env_injection_blocked: ${name}`);
2551
2582
  }
2552
2583
  const args = Array.isArray(input.extraArgs) ? input.extraArgs.map(String) : [];
2553
- if (args.some((arg) => FORBIDDEN_ARGV.has(arg) || arg.startsWith("--session=") || arg.startsWith("--fork=") || arg.startsWith("--session-dir=") || arg.startsWith("--extension=") || arg.startsWith("--package=") || arg.startsWith("--settings="))) {
2584
+ if (args.some((arg) => FORBIDDEN_ARGV.has(arg) || arg.startsWith("--tools=") || arg.startsWith("--exclude-tools=") || arg.startsWith("--session=") || arg.startsWith("--fork=") || arg.startsWith("--session-dir=") || arg.startsWith("--extension=") || arg.startsWith("--package=") || arg.startsWith("--settings="))) {
2554
2585
  throw new Error("pi_managed_mcp_config_override_blocked: Pi config/tool/session argv is forbidden for governed runs");
2555
2586
  }
2556
2587
  }
@@ -3063,6 +3094,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
3063
3094
  configPath,
3064
3095
  markerPath,
3065
3096
  env,
3097
+ toolAllowlist: directCatalog ? [...directToolNames] : null,
3066
3098
  protectedValues: [.../* @__PURE__ */ new Set([
3067
3099
  sessionToken,
3068
3100
  ...seededRuntime.protectedValues,
@@ -3912,7 +3944,7 @@ function fixedRules(input, includeIssueLine) {
3912
3944
  "Use only the declared workspace; make concrete progress and report concisely.",
3913
3945
  "Before changing the task status to done, audit every explicit requirement in the task against the final evidence. A successful tool or document write proves delivery, not acceptance: inspect the delivered content for required sections, diagrams, tables, and factual constraints.",
3914
3946
  "Do not leave stale in-progress wording such as \u201Ccurrent run\u201D in a terminal deliverable; rewrite it to the final observed state. Do not list finalization itself as remaining or next work in a terminal deliverable.",
3915
- serverOwnedBusinessOutcomeReview ? "If any requirement is missing or cannot be verified, do not mark done or request final completion or Business Outcome review. Keep the issue in_progress or blocked with the exact gap and next owner. An intermediate review remains available only for an exact document revision that must be approved before execution can continue: use create_interaction with kind request_confirmation, payload.resolutionMode review, and purposeCode review_document_revision; never use that interaction as final completion or Outcome acceptance." : "If any requirement is missing or cannot be verified, do not mark done. To request review, use create_interaction with kind request_confirmation and payload.resolutionMode review; never call update_parent with status in_review. Otherwise keep the issue todo or blocked with the exact gap and next owner.",
3947
+ serverOwnedBusinessOutcomeReview ? "If any requirement is missing or cannot be verified, do not mark done or request final completion or Business Outcome review. Keep the issue in_progress with the exact gap and next owner. An intermediate review remains available only for an exact document revision that must be approved before execution can continue: use create_interaction with kind request_confirmation, payload.resolutionMode review, and purposeCode review_document_revision; never use that interaction as final completion or Outcome acceptance." : "If anything is missing, do not mark done. `update_parent` cannot write `in_review` or `blocked`. Human review: create_interaction kind request_confirmation with payload.resolutionMode review. Required platform/provider/external action needs a typed interaction or first-class blocker; otherwise keep todo with the gap and owner.",
3916
3948
  DEADLINE_POSTURE_GUARD,
3917
3949
  "Do not install operating-system or user-global packages, and do not use host package managers such as brew, apt, yum, or global pip/npm installs. Use tools already available or workspace-local dependencies or virtual environments. If a required renderer or evaluator is unavailable, keep the source artifact, record the exact verification gap, and do not mutate the host.",
3918
3950
  `- command id: ${input.commandId}`,
@@ -3971,9 +4003,13 @@ function recoveryInstructionText(input) {
3971
4003
  if (input.wakeReason === "source_scoped_recovery_action") {
3972
4004
  const wake = asRecord(context.paperclipWake);
3973
4005
  const unresolvedBlockerIssueIds = Array.isArray(wake.unresolvedBlockerIssueIds) ? wake.unresolvedBlockerIssueIds.map(readString).filter(Boolean) : [];
3974
- const blockedDisposition = unresolvedBlockerIssueIds.length > 0 ? `- blocked only when the issue already has an unresolved first-class blocker; name the exact blocker and wait condition from: ${unresolvedBlockerIssueIds.join(", ")};` : [
3975
- "- if source work remains on this issue, choose continuation/todo and then execute the Runtime Action Continuation Option rendered below so the control plane can queue a normal-model continuation;",
3976
- "- do not set `blocked` without an unresolved first-class blocker; a named owner or proposed next action alone is not a blocker;"
4006
+ const blockedDisposition = unresolvedBlockerIssueIds.length > 0 ? [
4007
+ "- `update_parent` cannot write `blocked`; the existing first-class blocker path is authoritative and must not be replaced by `in_progress`;",
4008
+ `- name the exact blocker and wait condition from: ${unresolvedBlockerIssueIds.join(", ")}; continuation/todo can wait behind that blocker when source work remains;`
4009
+ ].join("\n") : [
4010
+ "- `update_parent` cannot write `blocked`; do not use `in_progress` to represent a wait;",
4011
+ "- when a specific human, platform, provider, or external action is required before work can continue, create a typed interaction that names the exact owner and unblock action;",
4012
+ "- otherwise, if source work remains on this issue, choose continuation/todo and then execute the Runtime Action Continuation Option rendered below so the control plane can queue a normal-model continuation;"
3977
4013
  ].join("\n");
3978
4014
  return [
3979
4015
  "This is a status-only source recovery. Do not repeat the original source work or create or revise deliverables.",
@@ -5781,6 +5817,14 @@ function piMessageText(message) {
5781
5817
  return readString(block.text) ?? readString(block.content) ?? "";
5782
5818
  }).filter(Boolean).join("\n").trim();
5783
5819
  }
5820
+ function piMessageHasToolCall(message) {
5821
+ const content = asRecord(message).content;
5822
+ if (!Array.isArray(content)) return false;
5823
+ return content.some((entry) => {
5824
+ const block = asRecord(entry);
5825
+ return block.type === "toolCall" && Boolean(readString(block.name));
5826
+ });
5827
+ }
5784
5828
  function appendUniqueText(values, text) {
5785
5829
  const normalized = typeof text === "string" ? text.trim() : "";
5786
5830
  if (!normalized) return false;
@@ -5868,7 +5912,7 @@ function maybeCapturePiMessage(event, messages, usage) {
5868
5912
  const message = asRecord(event.message);
5869
5913
  if (message.role === "assistant") {
5870
5914
  const text = piMessageText(message);
5871
- capturedAssistantOutput = capturePiAssistantText(text, messages) || capturedAssistantOutput;
5915
+ capturedAssistantOutput = capturePiAssistantText(text, messages) || piMessageHasToolCall(message) || capturedAssistantOutput;
5872
5916
  assignPiUsage(usage, piMessageUsage(message));
5873
5917
  }
5874
5918
  const eventMessages = Array.isArray(event.messages) ? event.messages : [];
@@ -5878,7 +5922,7 @@ function maybeCapturePiMessage(event, messages, usage) {
5878
5922
  continue;
5879
5923
  }
5880
5924
  const text = piMessageText(eventMessage);
5881
- capturedAssistantOutput = capturePiAssistantText(text, messages) || capturedAssistantOutput;
5925
+ capturedAssistantOutput = capturePiAssistantText(text, messages) || piMessageHasToolCall(eventMessage) || capturedAssistantOutput;
5882
5926
  assignPiUsage(usage, piMessageUsage(eventMessage));
5883
5927
  }
5884
5928
  return capturedAssistantOutput;
@@ -8695,7 +8739,7 @@ function assertSourceAcquisitionRuntimeAuthority({
8695
8739
  }
8696
8740
 
8697
8741
  // src/amaster-runtime-daemon.mjs
8698
- var CONNECTOR_VERSION = "0.1.1-beta.4";
8742
+ var CONNECTOR_VERSION = "0.1.1-beta.6";
8699
8743
  var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
8700
8744
  var SOURCE_ACQUISITION_CAPABILITY = "source_acquisition_v1";
8701
8745
  var SOURCE_ACQUISITION_PROFILE_VERSION = "source_acquisition_v1";
@@ -10478,6 +10522,14 @@ async function executeModelCallCommand(config, command, signal) {
10478
10522
  sourceWorkspacePath: process.cwd()
10479
10523
  });
10480
10524
  piModelCallProfile = executor.kind === "pi" ? preparePiModelCallProfile(command.commandId, baseEnv) : null;
10525
+ if (piModelCallProfile) {
10526
+ await syncPiExecutorProviderConfig(
10527
+ config,
10528
+ command,
10529
+ piModelCallProfile.env.PI_CODING_AGENT_DIR,
10530
+ resolvePiExecutorProviderConfig(config, command, baseEnv)
10531
+ );
10532
+ }
10481
10533
  execution = await runExecutor(invocation.command, invocation.args, {
10482
10534
  cwd: process.cwd(),
10483
10535
  env: piModelCallProfile?.env ?? baseEnv,
@@ -13162,6 +13214,7 @@ async function executeRunCommand(config, command) {
13162
13214
  }
13163
13215
  if (managedMcpProfile) {
13164
13216
  executorEnv = managedMcpProfile.env;
13217
+ if (executor.kind === "pi") invocation.args = applyManagedPiToolAllowlist(invocation.args, managedMcpProfile);
13165
13218
  await ingestLog(config, command, "system", "info", `Attested isolated ${executor.kind} managed MCP profile`, {
13166
13219
  presentationKind: "managed_mcp_attestation",
13167
13220
  ...managedMcpProfile.attestation
@@ -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.4";
8
+ const CONNECTOR_VERSION = "0.1.1-beta.6";
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.4",
3
+ "version": "0.1.1-beta.6",
4
4
  "description": "MirrorX runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",