@amaster.ai/employee-runtime-connector 0.1.1-beta.270 → 0.1.1-beta.272

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -89,12 +89,14 @@ Pi 0.80.10's internal compaction summarizer calls the provider outside `before_p
89
89
 
90
90
  ## WorkBuddy Host (CodeBuddy engine)
91
91
 
92
- The optional `codebuddy` executor exposes the same common governed task contract as
93
- Codex, while remaining deliberately narrower than the WorkBuddy desktop product.
92
+ The optional `codebuddy` executor participates in the same governed task lifecycle
93
+ as Codex, while its local execution surface remains deliberately narrower than both
94
+ Codex and the WorkBuddy desktop product.
94
95
  It does not expose WorkBuddy experts, projects, Office integrations, marketplace
95
96
  connectors, or Pi's `final_model_context_attestation_v1`. The connector creates a
96
97
  private per-run CodeBuddy home, supplies one strict MirrorX MCP definition, uses an
97
- exact native-tool allowlist, and preserves only an authority-bound native session
98
+ exact tool allowlist, exposes the governed namespace directly with
99
+ `NoDefer(mcp__amaster__*)`, and preserves only an authority-bound native session
98
100
  rollout. It never inherits the user's ordinary `.codebuddy` settings, memory,
99
101
  projects, MCP servers, workflows, or marketplace state. When no dedicated provider
100
102
  credential is configured, it reuses only the current OS user's WorkBuddy desktop
@@ -106,10 +108,27 @@ than authentication inputs and are not copied; any logout-marker directory entry
106
108
  including a dangling symlink, makes the desktop session unavailable. CodeBuddy can
107
109
  mutate only the private snapshot.
108
110
 
111
+ Managed CodeBuddy runs expose the native file tools plus `mcp__amaster__*`; they do
112
+ not expose Bash, WebFetch, or WebSearch. CodeBuddy 2.137.1's Bash sandbox cannot
113
+ prevent a command from connecting to an existing loopback service, so allowing Bash
114
+ would leave a path around Governed MCP even with unsandboxed execution disabled.
115
+ Consequently these runs can inspect and edit a workspace and perform governed
116
+ MirrorX actions, but they cannot run tests, builds, package managers, or arbitrary
117
+ shell commands. This is an explicit capability gap rather than claimed Pi/Codex
118
+ parity. Governed result authority remains correlated until a structured receipt is
119
+ actually parsed; an outer transport `status` cannot shadow a nested
120
+ `structuredContent` receipt, and more than 256 unresolved governed calls fails the
121
+ run instead of evicting an unmatched call id. The managed profile also resolves the
122
+ workspace once and uses that same canonical directory for CodeBuddy trust and child
123
+ process execution; an unavailable cwd fails with a stable managed-profile error.
124
+
109
125
  This executor is off by default. Enable discovery with
110
126
  `AMASTER_ENABLE_CODEBUDDY_EXECUTOR=true`. `AMASTER_CODEBUDDY_COMMAND` can select an
111
127
  explicit CLI; on macOS the gated discovery path can also find the CLI bundled in
112
- `/Applications/WorkBuddy.app`. The Server task-session snapshot owns the model for
128
+ `/Applications/WorkBuddy.app`. CodeBuddy `2.137.1` is the minimum supported version
129
+ because that is the oldest release on which the native `NoDefer(mcp__amaster__*)`
130
+ tool surface has been verified end to end; older versions fail readiness. The
131
+ Server task-session snapshot owns the model for
113
132
  current commands; `AMASTER_CODEBUDDY_MODEL` is only a compatibility fallback for
114
133
  older commands without that snapshot. Authentication resolves in two fail-closed
115
134
  modes: exactly one explicitly configured `CODEBUDDY_API_KEY` or
@@ -5033,6 +5033,7 @@ var companyColdStartObligationReadSchema = external_exports.object({
5033
5033
  kind: external_exports.enum(["agent", "board", "external"]),
5034
5034
  id: external_exports.string().trim().min(1).max(200)
5035
5035
  }).strict().nullable(),
5036
+ ownerDisplayName: external_exports.string().trim().min(1).max(200).nullable(),
5036
5037
  reviewAt: external_exports.string().datetime({ offset: true }).nullable(),
5037
5038
  noProgressReviewCount: external_exports.number().int().nonnegative(),
5038
5039
  dueState: external_exports.enum(["scheduled", "due", "overdue", "attention", "stalled"])
@@ -5076,13 +5077,25 @@ var companyColdStartReadModelBaseSchema = external_exports.object({
5076
5077
  workset: companyColdStartWorksetReadModelSchema.nullable(),
5077
5078
  tasks: external_exports.array(companyColdStartTaskReadSchema),
5078
5079
  factCoverage: companyColdStartFactCoverageReadSchema,
5080
+ factOwnerDisplayNames: external_exports.record(
5081
+ companyColdStartFactSlotSchema,
5082
+ external_exports.string().trim().min(1).max(200)
5083
+ ),
5079
5084
  missingFactSlots: external_exports.array(companyColdStartFactSlotSchema),
5080
5085
  taskLocalAttentionIds: external_exports.array(external_exports.string().uuid()),
5081
5086
  wikiProjectionAttentionCount: external_exports.number().int().nonnegative()
5082
5087
  }).strict(),
5083
5088
  operations: external_exports.object({
5084
5089
  currentObligationCount: external_exports.number().int().nonnegative(),
5090
+ currentObligationCountByGoal: external_exports.record(
5091
+ external_exports.string().uuid(),
5092
+ external_exports.number().int().nonnegative()
5093
+ ).optional(),
5085
5094
  actionRequiredCount: external_exports.number().int().nonnegative(),
5095
+ actionRequiredCountByGoal: external_exports.record(
5096
+ external_exports.string().uuid(),
5097
+ external_exports.number().int().nonnegative()
5098
+ ).optional(),
5086
5099
  goalGapRefs: external_exports.array(external_exports.string().trim().min(1).max(200)),
5087
5100
  obligations: external_exports.array(companyColdStartObligationReadSchema)
5088
5101
  }).strict()
@@ -5372,6 +5385,12 @@ var ERROR_PRESENTATIONS = {
5372
5385
  nextAction: null,
5373
5386
  tone: "neutral"
5374
5387
  },
5388
+ issue_terminal_status: {
5389
+ label: "\u4EFB\u52A1\u5DF2\u7ED3\u675F",
5390
+ summary: "\u4EFB\u52A1\u5DF2\u8FDB\u5165\u7EC8\u6001\uFF0C\u672C\u6B21\u6267\u884C\u5DF2\u505C\u6B62\u3002",
5391
+ nextAction: null,
5392
+ tone: "neutral"
5393
+ },
5375
5394
  issue_dependencies_blocked: {
5376
5395
  label: "\u7B49\u5F85\u524D\u7F6E\u4EFB\u52A1",
5377
5396
  summary: "\u524D\u7F6E\u4F9D\u8D56\u5C1A\u672A\u6EE1\u8DB3\uFF0C\u672C\u6B21\u6267\u884C\u5DF2\u505C\u6B62\u3002",
@@ -5507,7 +5526,7 @@ var ERROR_PRESENTATIONS = {
5507
5526
  pi_provider_quota_exhausted: {
5508
5527
  label: "\u6A21\u578B\u989D\u5EA6\u4E0D\u8DB3",
5509
5528
  summary: "\u5F53\u524D Credits \u4F59\u989D\u4E0D\u8DB3\uFF0C\u672C\u6B21\u4EFB\u52A1\u5DF2\u8FDB\u5165\u989D\u5EA6\u6062\u590D\u7B49\u5F85\u3002",
5510
- nextAction: "\u5145\u503C\u540E\u7CFB\u7EDF\u4F1A\u5B9A\u65F6\u68C0\u67E5\u5E76\u81EA\u52A8\u6062\u590D\uFF0C\u65E0\u9700\u624B\u52A8\u91CD\u8BD5\u3002",
5529
+ nextAction: "\u8BF7\u5230 IAM \u8D22\u52A1\u4E2D\u5FC3\u5145\u503C\uFF0C\u5145\u503C\u540E\u7CFB\u7EDF\u4F1A\u5B9A\u65F6\u68C0\u67E5\u5E76\u81EA\u52A8\u6062\u590D\uFF0C\u65E0\u9700\u624B\u52A8\u91CD\u8BD5\u3002",
5511
5530
  tone: "warning"
5512
5531
  },
5513
5532
  pi_governed_tool_surface_changed: {
@@ -8967,6 +8986,7 @@ var recordGoalGapReadinessSchema = external_exports.object({
8967
8986
  }).strict();
8968
8987
  var boardScheduleGoalGapFollowUpSchema = external_exports.object({
8969
8988
  expectedRevision: external_exports.number().int().positive(),
8989
+ ownerAgentId: external_exports.string().uuid(),
8970
8990
  reviewAt: external_exports.string().datetime({ offset: true })
8971
8991
  }).strict();
8972
8992
  var goalGapReadinessStateSchema = external_exports.object({
@@ -19355,7 +19375,7 @@ var KNOWN_EXECUTORS = [
19355
19375
  ["openclaw", "openclaw"]
19356
19376
  ];
19357
19377
  var MACOS_WORKBUDDY_CODEBUDDY_COMMAND = "/Applications/WorkBuddy.app/Contents/Resources/app.asar.unpacked/cli/bin/codebuddy";
19358
- var MINIMUM_CODEBUDDY_VERSION = "2.115.0";
19378
+ var MINIMUM_CODEBUDDY_VERSION = "2.137.1";
19359
19379
  var MINIMUM_CODEBUDDY_VERSION_TUPLE = MINIMUM_CODEBUDDY_VERSION.split(".").map(Number);
19360
19380
  var REQUIRED_CODEBUDDY_FLAGS = [
19361
19381
  "--output-format",
@@ -20332,21 +20352,22 @@ var CODEBUDDY_DESKTOP_AUTH_SOURCE = "workbuddy_desktop_session";
20332
20352
  var CODEBUDDY_WORKBUDDY_AUTH_FILE = "workbuddy-desktop.info";
20333
20353
  var MAX_CODEBUDDY_DESKTOP_AUTH_BYTES = 4 * 1024 * 1024;
20334
20354
  var CODEBUDDY_NATIVE_TOOLS = [
20335
- "Bash",
20336
20355
  "Edit",
20337
20356
  "Read",
20338
20357
  "Write",
20339
20358
  "Glob",
20340
20359
  "Grep",
20341
- "LS",
20342
- "WebFetch",
20343
- "WebSearch"
20360
+ "LS"
20344
20361
  ];
20345
- var CODEBUDDY_ALLOWED_TOOLS = [
20362
+ var CODEBUDDY_MCP_TOOL_GLOB = `mcp__${SUPPORTED_SERVER_NAME2}__*`;
20363
+ var CODEBUDDY_TOOL_SURFACE = [
20346
20364
  ...CODEBUDDY_NATIVE_TOOLS,
20347
- "DeferExecuteTool",
20348
- `mcp__${SUPPORTED_SERVER_NAME2}__*`
20365
+ `NoDefer(${CODEBUDDY_MCP_TOOL_GLOB})`
20366
+ ];
20367
+ var CODEBUDDY_ALLOWED_TOOLS = [
20368
+ CODEBUDDY_MCP_TOOL_GLOB
20349
20369
  ];
20370
+ var CODEBUDDY_DENIED_TOOLS = ["WebFetch", "WebSearch"];
20350
20371
  var REQUIRED_AUTHORITY_HEADERS2 = [
20351
20372
  "x-amaster-company-id",
20352
20373
  "x-amaster-agent-id",
@@ -20805,10 +20826,27 @@ function validateAuthority2(input) {
20805
20826
  function attestCli(executorCommand, env, cwd) {
20806
20827
  return attestCodebuddyCommand(executorCommand, env, cwd).executorVersion;
20807
20828
  }
20829
+ function canonicalCodebuddyCwd(value) {
20830
+ const requestedCwd = resolve6(nonEmpty2(value, "cwd"));
20831
+ try {
20832
+ const canonicalCwd = realpathSync3(requestedCwd);
20833
+ if (!statSync5(canonicalCwd).isDirectory()) {
20834
+ throw new Error("cwd is not a directory");
20835
+ }
20836
+ return canonicalCwd;
20837
+ } catch (cause) {
20838
+ throw new Error(
20839
+ "codebuddy_managed_mcp_cwd_invalid: cwd must resolve to an existing directory",
20840
+ { cause }
20841
+ );
20842
+ }
20843
+ }
20808
20844
  function prepareManagedCodebuddyMcpProfile(input) {
20809
20845
  const authority = validateAuthority2(input);
20810
20846
  const runDir = resolve6(nonEmpty2(input.runDir, "runDir"));
20811
20847
  const executorHome = resolve6(nonEmpty2(input.executorHome, "executorHome"));
20848
+ const cwd = canonicalCodebuddyCwd(input.cwd);
20849
+ const bashSandboxEnabled = ["darwin", "linux"].includes(platform2());
20812
20850
  if (!within3(executorHome, join6(runDir, "executors"))) {
20813
20851
  throw new Error("codebuddy_managed_mcp_owner_mismatch: executorHome is outside the managed run");
20814
20852
  }
@@ -20850,9 +20888,25 @@ function prepareManagedCodebuddyMcpProfile(input) {
20850
20888
  }, null, 2)}
20851
20889
  `);
20852
20890
  privateFile(settingsPath, `${JSON.stringify({
20891
+ trustedDirectories: [cwd],
20892
+ sandbox: {
20893
+ enabled: bashSandboxEnabled,
20894
+ autoAllowBashIfSandboxed: false,
20895
+ network: {
20896
+ allowedDomains: [],
20897
+ deniedDomains: [],
20898
+ allowLocalBinding: false,
20899
+ allowUnixSockets: [],
20900
+ allowAllUnixSockets: false
20901
+ },
20902
+ excludedCommands: [],
20903
+ allowUnsandboxedCommands: false
20904
+ },
20853
20905
  permissions: {
20854
20906
  allow: CODEBUDDY_ALLOWED_TOOLS,
20855
- deny: []
20907
+ deny: CODEBUDDY_DENIED_TOOLS,
20908
+ defaultMode: "acceptEdits",
20909
+ disableBypassPermissionsMode: "disable"
20856
20910
  }
20857
20911
  }, null, 2)}
20858
20912
  `);
@@ -20877,7 +20931,7 @@ function prepareManagedCodebuddyMcpProfile(input) {
20877
20931
  restoredNativeSession,
20878
20932
  nativeSessionRestoreSkippedReason
20879
20933
  } = resolveManagedCodebuddySessionRollout(input, configDir, runDir, executorHome, profileAuthority);
20880
- const executorVersion = attestCli(nonEmpty2(input.executorCommand, "executorCommand"), env, nonEmpty2(input.cwd, "cwd"));
20934
+ const executorVersion = attestCli(nonEmpty2(input.executorCommand, "executorCommand"), env, cwd);
20881
20935
  const cliArgs = [
20882
20936
  "--setting-sources",
20883
20937
  "",
@@ -20887,17 +20941,20 @@ function prepareManagedCodebuddyMcpProfile(input) {
20887
20941
  "--mcp-config",
20888
20942
  mcpConfigPath,
20889
20943
  "--tools",
20890
- CODEBUDDY_NATIVE_TOOLS.join(","),
20944
+ CODEBUDDY_TOOL_SURFACE.join(","),
20891
20945
  "--allowedTools",
20892
20946
  CODEBUDDY_ALLOWED_TOOLS.join(","),
20893
20947
  "--permission-mode",
20894
- "dontAsk"
20948
+ "acceptEdits"
20895
20949
  ];
20896
20950
  const attestationFacts = {
20897
20951
  connectorVersion: nonEmpty2(input.connectorVersion, "connectorVersion"),
20898
20952
  executorKind: "codebuddy",
20899
20953
  executorVersion,
20900
20954
  configMode: "isolated_config_strict_http_headers",
20955
+ mcpExposureMode: "native_nodefer",
20956
+ bashIsolation: "not_exposed",
20957
+ networkAccessMode: "governed_mcp_only",
20901
20958
  namespace: SUPPORTED_SERVER_NAME2,
20902
20959
  schemaVersion: SUPPORTED_SCHEMA_VERSION2,
20903
20960
  platform: platform2(),
@@ -20908,6 +20965,7 @@ function prepareManagedCodebuddyMcpProfile(input) {
20908
20965
  };
20909
20966
  return {
20910
20967
  profileRoot,
20968
+ cwd,
20911
20969
  markerPath,
20912
20970
  mcpConfigPath,
20913
20971
  settingsPath,
@@ -21260,9 +21318,7 @@ const completionAuthority = ${JSON.stringify(completionAuthority)};
21260
21318
  ${managedPiInitializationCompletionSource()}
21261
21319
  export default function(pi) {
21262
21320
  pi.on("tool_result", async (event) => {
21263
- // Linux dir-fd paths prevent a concurrent directory replacement redirecting writes.
21264
- // Other executors retain the original document workflow.
21265
- if (process.platform !== "linux" || event.isError || event.details?.server !== "amaster"
21321
+ if (event.isError || event.details?.server !== "amaster"
21266
21322
  || !["runtime_action_plan", "runtime_action_status"].includes(event.toolName)) return;
21267
21323
  if (!Array.isArray(event.content) || event.content.length !== 1 || event.content[0].type !== "text") return;
21268
21324
  let envelope;
@@ -21289,14 +21345,35 @@ export default function(pi) {
21289
21345
  || doc.contentRef.planId !== result.planId || doc.contentRef.readTool !== "runtime_action.status")) {
21290
21346
  throw new Error("invalid_document_reference");
21291
21347
  }
21292
- // Pin the directory and verify existing bytes before loading credentials or reading chunks.
21348
+ // Linux can safely address descendants through a pinned directory fd. On platforms without
21349
+ // traversable directory-fd paths, keep the governed file directly under the process cwd: a
21350
+ // relative single-component path is resolved from the kernel-pinned cwd and has no replaceable
21351
+ // parent directory that could redirect the write outside the workspace.
21293
21352
  const flags = fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW;
21294
- root = fs.openSync(cwd, flags);
21295
- const rootPath = "/proc/self/fd/" + root;
21296
- try { fs.mkdirSync(rootPath + "/deliverables", { mode: 0o700 }); }
21297
- catch (error) { if (error.code !== "EEXIST") throw error; }
21298
- parent = fs.openSync(rootPath + "/deliverables", flags);
21299
- const parentPath = "/proc/self/fd/" + parent;
21353
+ let parentPath;
21354
+ let materializedPathPrefix;
21355
+ if (process.platform === "linux") {
21356
+ root = fs.openSync(cwd, flags);
21357
+ const rootPath = "/proc/self/fd/" + root;
21358
+ try { fs.mkdirSync(rootPath + "/deliverables", { mode: 0o700 }); }
21359
+ catch (error) { if (error.code !== "EEXIST") throw error; }
21360
+ parent = fs.openSync(rootPath + "/deliverables", flags);
21361
+ parentPath = "/proc/self/fd/" + parent;
21362
+ materializedPathPrefix = "deliverables/";
21363
+ } else {
21364
+ const configured = fs.statSync(cwd);
21365
+ const current = fs.statSync(".");
21366
+ if (!configured.isDirectory() || configured.dev !== current.dev || configured.ino !== current.ino) {
21367
+ throw new Error("workspace_cwd_mismatch");
21368
+ }
21369
+ root = fs.openSync(".", flags);
21370
+ const pinned = fs.fstatSync(root);
21371
+ if (pinned.dev !== current.dev || pinned.ino !== current.ino) {
21372
+ throw new Error("workspace_cwd_changed");
21373
+ }
21374
+ parentPath = ".";
21375
+ materializedPathPrefix = "";
21376
+ }
21300
21377
  let target;
21301
21378
  // Preserve conflicts and select a stable alternate; replay verifies these same candidates.
21302
21379
  function selectTarget() {
@@ -21322,7 +21399,8 @@ export default function(pi) {
21322
21399
  let bytes;
21323
21400
  if (doc.contentRef) {
21324
21401
  // Use this run's existing governed session; references cannot select an endpoint or credential.
21325
- const server = JSON.parse(fs.readFileSync(configPath, "utf8")).mcpServers.amaster;
21402
+ const safeConfigPath = process.platform === "linux" ? configPath : ".pi/mcp.json";
21403
+ const server = JSON.parse(fs.readFileSync(safeConfigPath, "utf8")).mcpServers.amaster;
21326
21404
  const chunks = [];
21327
21405
  let offset = 0;
21328
21406
  while (offset < doc.byteSize) {
@@ -21383,9 +21461,10 @@ export default function(pi) {
21383
21461
  }
21384
21462
  }
21385
21463
  }
21386
- doc.path = "deliverables/" + targetName;
21464
+ const materializedPath = materializedPathPrefix + targetName;
21465
+ doc.path = materializedPath;
21387
21466
  result.initializationDocumentMaterialization = {
21388
- status: "materialized", path: doc.path, sha256: doc.sha256, byteSize: doc.byteSize,
21467
+ status: "materialized", path: materializedPath, sha256: doc.sha256, byteSize: doc.byteSize,
21389
21468
  planId: result.planId, revision: result.revision, replayed, uploaded: false,
21390
21469
  };
21391
21470
  } catch {
@@ -27365,43 +27444,105 @@ function classifyCodexTransientUpstreamError(input, now = /* @__PURE__ */ new Da
27365
27444
  }
27366
27445
 
27367
27446
  // src/amaster-runtime-daemon/executor-protocol/codebuddy.mjs
27368
- function structuredToolResult(value) {
27369
- const record8 = asRecord(value);
27370
- const direct = asRecord(record8.structuredContent);
27371
- if (Object.keys(direct).length > 0) return direct;
27372
- const text2 = readString(record8.text) ?? (typeof value === "string" ? value : null);
27373
- if (text2) {
27447
+ var AMASTER_MCP_TOOL_PREFIX = "mcp__amaster__";
27448
+ var MAX_STRUCTURED_RESULT_DEPTH = 8;
27449
+ var MAX_TRACKED_TOOL_USES = 256;
27450
+ function structuredToolResults(value, depth = 0) {
27451
+ if (depth > MAX_STRUCTURED_RESULT_DEPTH || value === null || value === void 0) return [];
27452
+ if (Array.isArray(value)) {
27453
+ return value.flatMap((part) => structuredToolResults(part, depth + 1));
27454
+ }
27455
+ if (typeof value === "string") {
27374
27456
  try {
27375
- return asRecord(JSON.parse(text2));
27457
+ return structuredToolResults(JSON.parse(value), depth + 1);
27376
27458
  } catch {
27377
- return {};
27459
+ return [];
27378
27460
  }
27379
27461
  }
27380
- for (const part of Array.isArray(record8.content) ? record8.content : []) {
27381
- const parsed = structuredToolResult(part);
27382
- if (Object.keys(parsed).length > 0) return parsed;
27383
- }
27384
- return {};
27385
- }
27386
- function codebuddyMcpToolResults(event) {
27387
- const record8 = asRecord(event);
27462
+ const record8 = asRecord(value);
27463
+ const structuredContent = structuredToolResults(record8.structuredContent, depth + 1);
27464
+ if (structuredContent.length > 0) return structuredContent;
27465
+ if (readString(record8.status)) return [record8];
27388
27466
  const candidates = [];
27389
- if (record8.type === "function_call_result" && ["DeferExecuteTool", "mcp__amaster"].some((prefix) => (readString(record8.name) ?? "").startsWith(prefix))) {
27390
- candidates.push(record8.output ?? record8.result);
27467
+ for (const nested of [
27468
+ record8.content,
27469
+ record8.text,
27470
+ record8.result,
27471
+ record8.output
27472
+ ]) {
27473
+ candidates.push(...structuredToolResults(nested, depth + 1));
27391
27474
  }
27392
- if (record8.type === "user") {
27393
- const message = asRecord(record8.message);
27394
- for (const rawBlock of Array.isArray(message.content) ? message.content : []) {
27395
- const block = asRecord(rawBlock);
27396
- if (block.type === "tool_result" || block.type === "toolResult") {
27397
- candidates.push(block.content ?? block.result);
27475
+ return candidates;
27476
+ }
27477
+ function governedResults(candidates) {
27478
+ return candidates.flatMap((candidate) => structuredToolResults(candidate).flatMap((structured) => {
27479
+ const parsed = governedMcpToolResult(structured);
27480
+ return parsed ? [parsed] : [];
27481
+ }));
27482
+ }
27483
+ function createCodebuddyMcpToolResultTracker() {
27484
+ const toolNamesById = /* @__PURE__ */ new Map();
27485
+ let trackingFailure = null;
27486
+ const rememberToolUse = (id, name) => {
27487
+ if (trackingFailure) return;
27488
+ const toolUseId = readString(id);
27489
+ if (!toolUseId) return;
27490
+ const toolName = readString(name);
27491
+ if (!toolName?.startsWith(AMASTER_MCP_TOOL_PREFIX)) {
27492
+ toolNamesById.delete(toolUseId);
27493
+ return;
27494
+ }
27495
+ if (!toolNamesById.has(toolUseId) && toolNamesById.size >= MAX_TRACKED_TOOL_USES) {
27496
+ trackingFailure = `codebuddy_mcp_tool_tracking_overflow: more than ${MAX_TRACKED_TOOL_USES} unresolved governed tool calls`;
27497
+ return;
27498
+ }
27499
+ toolNamesById.set(toolUseId, toolName);
27500
+ };
27501
+ return {
27502
+ failure() {
27503
+ return trackingFailure;
27504
+ },
27505
+ record(event) {
27506
+ if (trackingFailure) return [];
27507
+ const record8 = asRecord(event);
27508
+ const eventType = readString(record8.type);
27509
+ if (eventType === "assistant") {
27510
+ const message2 = asRecord(record8.message);
27511
+ for (const rawBlock of Array.isArray(message2.content) ? message2.content : []) {
27512
+ const block = asRecord(rawBlock);
27513
+ if (["tool_use", "toolUse"].includes(readString(block.type) ?? "")) {
27514
+ rememberToolUse(block.id ?? block.tool_use_id ?? block.toolUseId, block.name ?? block.tool_name);
27515
+ }
27516
+ }
27517
+ return [];
27518
+ }
27519
+ if (eventType === "function_call") {
27520
+ rememberToolUse(record8.call_id ?? record8.tool_use_id ?? record8.id, record8.name);
27521
+ return [];
27522
+ }
27523
+ if (eventType === "function_call_result") {
27524
+ const callId = readString(record8.call_id ?? record8.tool_use_id ?? record8.id);
27525
+ if (!callId || !toolNamesById.has(callId)) return [];
27526
+ const results2 = governedResults([record8.output ?? record8.result]);
27527
+ if (results2.length > 0) toolNamesById.delete(callId);
27528
+ return results2;
27529
+ }
27530
+ if (eventType !== "user") return [];
27531
+ const message = asRecord(record8.message);
27532
+ const results = [];
27533
+ for (const rawBlock of Array.isArray(message.content) ? message.content : []) {
27534
+ const block = asRecord(rawBlock);
27535
+ if (!["tool_result", "toolResult"].includes(readString(block.type) ?? "")) continue;
27536
+ const toolUseId = readString(block.tool_use_id ?? block.toolUseId ?? block.id);
27537
+ if (!toolUseId || !toolNamesById.has(toolUseId)) continue;
27538
+ const blockResults = governedResults([block.content ?? block.result]);
27539
+ if (blockResults.length === 0) continue;
27540
+ toolNamesById.delete(toolUseId);
27541
+ results.push(...blockResults);
27398
27542
  }
27543
+ return results;
27399
27544
  }
27400
- }
27401
- return candidates.flatMap((candidate) => {
27402
- const parsed = governedMcpToolResult(structuredToolResult(candidate));
27403
- return parsed ? [parsed] : [];
27404
- });
27545
+ };
27405
27546
  }
27406
27547
  function parseCodebuddyStreamJson(stdout) {
27407
27548
  let sessionId = null;
@@ -27410,12 +27551,13 @@ function parseCodebuddyStreamJson(stdout) {
27410
27551
  let sawSuccessfulResult = false;
27411
27552
  const assistantTexts = [];
27412
27553
  const mcpToolResults = [];
27554
+ const mcpToolResultTracker = createCodebuddyMcpToolResultTracker();
27413
27555
  const usage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
27414
27556
  for (const rawLine of String(stdout ?? "").split(/\r?\n/)) {
27415
27557
  const event = parseJsonLine(rawLine.trim());
27416
27558
  if (!event) continue;
27417
27559
  sessionId = readString(event.session_id) ?? readString(event.sessionId) ?? sessionId;
27418
- mcpToolResults.push(...codebuddyMcpToolResults(event));
27560
+ mcpToolResults.push(...mcpToolResultTracker.record(event));
27419
27561
  if (event.type === "assistant") {
27420
27562
  const message = asRecord(event.message);
27421
27563
  for (const rawBlock of Array.isArray(message.content) ? message.content : []) {
@@ -27453,6 +27595,11 @@ function parseCodebuddyStreamJson(stdout) {
27453
27595
  errorMessage = readString(event.message) ?? errorMessage;
27454
27596
  }
27455
27597
  }
27598
+ const trackingFailure = mcpToolResultTracker.failure();
27599
+ if (trackingFailure) {
27600
+ sawSuccessfulResult = false;
27601
+ errorMessage = trackingFailure;
27602
+ }
27456
27603
  const uniqueMcpToolResults = dedupeGovernedMcpToolResults(mcpToolResults);
27457
27604
  return {
27458
27605
  sessionId,
@@ -33904,7 +34051,7 @@ function assertRequiredTaskAttachmentMaterialized(input, materialized) {
33904
34051
  }
33905
34052
 
33906
34053
  // src/amaster-runtime-daemon.mjs
33907
- var CONNECTOR_VERSION = "0.1.1-beta.270";
34054
+ var CONNECTOR_VERSION = "0.1.1-beta.272";
33908
34055
  var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
33909
34056
  var daemonRequire = createRequire(import.meta.url);
33910
34057
  var MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
@@ -36111,6 +36258,7 @@ function createLiveOutputLogger(config, command, executorKind, protectedValues =
36111
36258
  let piTerminalOutput = null;
36112
36259
  let executorSessionId = null;
36113
36260
  const liveMcpToolResults = [];
36261
+ const codebuddyMcpToolResultTracker = executorKind === "codebuddy" ? createCodebuddyMcpToolResultTracker() : null;
36114
36262
  const onWebEvidence = typeof options.onWebEvidence === "function" ? options.onWebEvidence : null;
36115
36263
  let queue = Promise.resolve();
36116
36264
  let observationQueue = Promise.resolve();
@@ -36303,7 +36451,7 @@ function createLiveOutputLogger(config, command, executorKind, protectedValues =
36303
36451
  }
36304
36452
  }
36305
36453
  if (MIRRORX_FORMAL_TASK_EXECUTOR_KINDS.includes(executorKind) && event) {
36306
- const results = executorKind === "codex" ? codexMcpToolResults(event) : executorKind === "codebuddy" ? codebuddyMcpToolResults(event) : piMcpToolResults(event, { runId: commandRunId(command), commandId: command.commandId, issueId: commandIssueId(command) });
36454
+ const results = executorKind === "codex" ? codexMcpToolResults(event) : executorKind === "codebuddy" ? codebuddyMcpToolResultTracker.record(event) : piMcpToolResults(event, { runId: commandRunId(command), commandId: command.commandId, issueId: commandIssueId(command) });
36307
36455
  liveMcpToolResults.push(...results);
36308
36456
  if (results.length > 0) onMcpToolResults?.(results);
36309
36457
  }
@@ -36392,6 +36540,7 @@ function createLiveOutputLogger(config, command, executorKind, protectedValues =
36392
36540
  processLine(stream, buffers[stream]);
36393
36541
  buffers[stream] = "";
36394
36542
  }
36543
+ const codebuddyTrackingFailure = codebuddyMcpToolResultTracker?.failure();
36395
36544
  await observationQueue;
36396
36545
  if (observationError) throw observationError;
36397
36546
  flushPendingBatch();
@@ -36414,6 +36563,7 @@ function createLiveOutputLogger(config, command, executorKind, protectedValues =
36414
36563
  }
36415
36564
  }], { terminalSummary: true });
36416
36565
  }
36566
+ if (codebuddyTrackingFailure) throw new Error(codebuddyTrackingFailure);
36417
36567
  },
36418
36568
  hasStream(stream) {
36419
36569
  return displayCounts[stream] > 0;
@@ -37237,7 +37387,7 @@ async function executePiTerminalTextRepairTurn(config, command, executor, execut
37237
37387
  ]);
37238
37388
  const completionOutputStopped = piCompletionOutputStopped(execution);
37239
37389
  const invalidOutput = piOutputValidationError(parsed, {
37240
- allowMissingTurnEnd: completionOutputStopped || parsed.terminalEventType === "agent_end",
37390
+ allowMissingTurnEnd: piOutputAllowsMissingTurnEnd(execution, parsed, { allowTerminalAgentEnd: true }),
37241
37391
  completionOutputType: execution.completionOutputType,
37242
37392
  completionOutputHasFinalAssistantText: execution.completionOutputHasFinalAssistantText
37243
37393
  });
@@ -38300,6 +38450,11 @@ function piCompletionCleanupStopped(execution) {
38300
38450
  function piCompletionOutputStopped(execution) {
38301
38451
  return piCompletionCleanupStopped(execution) && PI_COMPLETION_OUTPUT_TYPES.has(readString(execution?.completionOutputType) ?? "") && (execution?.completionOutputType === "approval_required" || execution?.completionOutputHasFinalAssistantText === true);
38302
38452
  }
38453
+ function piOutputAllowsMissingTurnEnd(execution, parsed, options = {}) {
38454
+ if (piCompletionOutputStopped(execution)) return true;
38455
+ if (options.allowTerminalAgentEnd === true && parsed?.terminalEventType === "agent_end") return true;
38456
+ return execution?.completionOutputType === "agent_settled" && execution?.completionOutputHasFinalAssistantText === true && execution?.exitCode === 0 && execution?.signal === null;
38457
+ }
38303
38458
  function piOutputValidationError(parsed, options = {}) {
38304
38459
  if (parsed?.errorMessage) return parsed.errorMessage;
38305
38460
  if (options.completionOutputType === "agent_settled" && options.completionOutputHasFinalAssistantText !== true && options.allowMissingFinalAssistantText !== true) {
@@ -38813,7 +38968,7 @@ async function executeRunCommand(config, command) {
38813
38968
  } : null;
38814
38969
  try {
38815
38970
  execution = await runExecutor(invocation.command, invocation.args, {
38816
- cwd,
38971
+ cwd: executor.kind === "codebuddy" ? managedMcpProfile?.cwd ?? cwd : cwd,
38817
38972
  env: executorEnv,
38818
38973
  stdin: invocation.stdin === "prompt" ? prompt : "",
38819
38974
  timeoutSeconds: config.executorTimeoutSeconds,
@@ -39143,15 +39298,16 @@ async function executeRunCommand(config, command) {
39143
39298
  );
39144
39299
  }
39145
39300
  const parsedForValidation = parsed;
39301
+ const effectiveCompletionOutputHasFinalAssistantText = terminalTextRepair?.succeeded === true ? true : execution.completionOutputHasFinalAssistantText;
39146
39302
  const piTurnLimitFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasArgumentAmplification && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiTurnLimitResult(parsedForValidation, {
39147
39303
  authoritativeTerminalDisposition: Boolean(terminalRunDisposition)
39148
39304
  }) : null;
39149
39305
  const piInvalidOutputError = executor.kind === "pi" ? piOutputValidationError(parsedForValidation, {
39150
- allowMissingTurnEnd: completionOutputStopped,
39306
+ allowMissingTurnEnd: piOutputAllowsMissingTurnEnd(execution, parsedForValidation),
39151
39307
  allowMissingAssistantOutput: execution.completionOutputType === "approval_required" || Boolean(terminalRunDisposition),
39152
39308
  allowMissingFinalAssistantText: Boolean(terminalRunDisposition),
39153
39309
  completionOutputType: execution.completionOutputType,
39154
- completionOutputHasFinalAssistantText: terminalTextRepair?.succeeded === true ? true : execution.completionOutputHasFinalAssistantText
39310
+ completionOutputHasFinalAssistantText: effectiveCompletionOutputHasFinalAssistantText
39155
39311
  }) : null;
39156
39312
  const piOutputFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasArgumentAmplification && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiOutputFailure(parsedForValidation, {
39157
39313
  exitCode: execution.exitCode,
@@ -7,7 +7,7 @@ import { homedir, hostname } from "node:os";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { BUILD_SUPPORTED_CAPABILITIES } from "./amaster-runtime-daemon/capability-registry.mjs";
9
9
 
10
- const CONNECTOR_VERSION = "0.1.1-beta.270";
10
+ const CONNECTOR_VERSION = "0.1.1-beta.272";
11
11
 
12
12
  const CONFIG_KEY_MAP = new Map([
13
13
  ["server_url", "AMASTER_EMPLOYEE_SERVER_URL"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amaster.ai/employee-runtime-connector",
3
- "version": "0.1.1-beta.270",
3
+ "version": "0.1.1-beta.272",
4
4
  "description": "MirrorX runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",