@amaster.ai/employee-runtime-connector 0.1.0-beta.43 → 0.1.0-beta.44

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
@@ -32,6 +32,18 @@ The source of truth lives under this package's `src/` directory. The package bui
32
32
 
33
33
  Runtime code belongs in the container image. Persist only connector state, the result outbox, and workspaces under the configured state directory.
34
34
 
35
+ ## Pi terminal cleanup outcome
36
+
37
+ Pi execution uses three separate evidence layers:
38
+
39
+ 1. a valid successful `agent_end` and output/usage contract;
40
+ 2. a durable, inspectable Runtime Action receipt or finalized Runtime Artifact;
41
+ 3. process cleanup disposition.
42
+
43
+ An exact process-kill `EPERM` error emitted only after the first two layers have completed may be isolated as a failed `cleanupDisposition` warning without changing the command's successful business result. Both accepted shapes require `kill` and `EPERM`; generic filesystem/process permission text such as `EPERM: operation not permitted, unlink ...` is a business error. A `runtime_action.status` readback is evidence only when its call/plan ref matches an earlier submit/commit receipt in the same transcript. The diagnostic and durable evidence reference remain in the result. Text-only or action-only-without-assistant-output streams, standalone governed reads, non-effect Runtime Action tools, rejected or pending effects, pre-terminal errors, provider failures, timeout, cancellation, resource limits, any signal, live residue, and uncertain ownership remain failures.
44
+
45
+ This isolation does not schedule a retry or a second business continuation. Command result delivery and the result outbox remain the sole idempotency boundary.
46
+
35
47
  ## Mutation attestation
36
48
 
37
49
  The daemon reports its connector contract, exact package/build, platform/architecture, and discovered executor versions on every heartbeat. The server compares those facts with `AMASTER_RUNTIME_RECOMMENDED_VERSION` and `AMASTER_RUNTIME_RECOMMENDED_BUILD_COMMIT`, persists a short-lived content-bound attestation, and correlates Runtime V2 commands to that proof.
@@ -2558,6 +2558,7 @@ function isTerminalResultOutboxStatus(status) {
2558
2558
 
2559
2559
  // src/amaster-runtime-daemon/prompt-compiler.mjs
2560
2560
  var DEFAULT_PROMPT_BUDGET_CHARS = 32e3;
2561
+ var DEADLINE_POSTURE_GUARD = "Named-window:skip_this_window_and_continue; no lower-quality/approval-bypass/fabrication/whole-task-stop; deadline_posture_receipt=targetMilestoneRef,posture,onMiss,taskContinuation,next owner/action; not Server proof";
2561
2562
  var MIN_PROMPT_BUDGET_CHARS = 8192;
2562
2563
  var CONTINUATION_WAKE_PATTERN = /(continuation|continued|retry|approved|liveness|resume|max_turn)/i;
2563
2564
  var RECOVERY_WAKE_REASONS = /* @__PURE__ */ new Set([
@@ -2670,9 +2671,10 @@ function governedReadSection(context) {
2670
2671
  function fixedRules(input, includeIssueLine) {
2671
2672
  return [
2672
2673
  "## AMaster Runtime Connector Task",
2673
- "You are executing a task dispatched by MirrorX from the central control plane.",
2674
- "Work only inside the declared workspace. Make concrete progress and finish with a concise result summary.",
2674
+ "MirrorX task.",
2675
+ "Use only the declared workspace; make concrete progress and report concisely.",
2675
2676
  "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. 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. 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.",
2677
+ DEADLINE_POSTURE_GUARD,
2676
2678
  "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.",
2677
2679
  `- command id: ${input.commandId}`,
2678
2680
  `- run id: ${input.runId ?? "unknown"}`,
@@ -3690,7 +3692,17 @@ var PI_PROVIDER_AUTH_RE = /(?:(?:\b401\b|\b403\b)[^\n]*(?:unauthorized|forbidden
3690
3692
  var PI_PROVIDER_QUOTA_EXHAUSTED_RE = /(?:\binsufficient[_\s-]?user[_\s-]?quota\b|河狸币余额不足|\b402\b[^\n]*(?:余额不足|payment\s+required))/i;
3691
3693
  var PI_PROVIDER_TRANSIENT_RE = /(?:\b(?:429|5\d{2})\b|rate[-\s]?limit(?:ed)?|too\s+many\s+requests|billing\s+admission\s+failed|service\s+unavailable|upstream[^\n]*(?:unavailable|failed|timeout)|connect(?:ion)?[^\n]*refused|temporar(?:y|ily)[^\n]*(?:unavailable|failed)|try\s+again\s+later)/i;
3692
3694
  var PI_PROVIDER_RETRY_AFTER_SECONDS_RE = /retry[-\s]?after\s*[:=]?\s*(\d{1,6})\s*(?:seconds?|secs?|s)\b/i;
3695
+ var PI_TERMINAL_CLEANUP_PERMISSION_RE = /(?:\bkill\b[^\n]*\bEPERM\b|\bEPERM\b[^\n]*\bkill\b)/i;
3693
3696
  var MAX_PI_PROVIDER_RETRY_AFTER_SECONDS = 7 * 24 * 60 * 60;
3697
+ var PI_DURABLE_RUNTIME_ACTION_WRITE_TOOLS = /* @__PURE__ */ new Set([
3698
+ "runtime_action.submit",
3699
+ "runtime_action.commit"
3700
+ ]);
3701
+ var PI_RUNTIME_ACTION_WRITE_RECEIPT_STATUSES = /* @__PURE__ */ new Set(["accepted", "pending_reconcile"]);
3702
+ var PI_TERMINAL_RUNTIME_ACTION_STATUSES = /* @__PURE__ */ new Set([
3703
+ "completed",
3704
+ "succeeded"
3705
+ ]);
3694
3706
  function approvedMcpInvocationSucceeded(results, invocationId) {
3695
3707
  const approvedInvocationId = readString(invocationId);
3696
3708
  return Boolean(approvedInvocationId && (Array.isArray(results) ? results : []).some((rawResult) => {
@@ -3704,18 +3716,81 @@ function governedMcpToolResult(structuredContent) {
3704
3716
  const invocationId = readString(structuredContent.invocationId);
3705
3717
  const providerContent = asRecord(structuredContent.content);
3706
3718
  const providerStatus = readString(providerContent.status);
3707
- const effectResult = asRecord(asRecord(providerContent.result).effectResult);
3719
+ const providerResult = asRecord(providerContent.result);
3720
+ const effectResult = asRecord(providerResult.effectResult);
3708
3721
  const intentId = readString(effectResult.artifactIntentId);
3709
3722
  const manifestId = readString(effectResult.manifestId);
3710
3723
  const sourceRelativePath = readString(effectResult.sourceRelativePath);
3711
3724
  const sha256 = readString(effectResult.sha256);
3712
3725
  const byteSize = readNumber(effectResult.byteSize, 0);
3713
3726
  const artifactIntent = providerStatus === "pending_reconcile" && intentId && manifestId && sourceRelativePath && /^[a-f0-9]{64}$/.test(sha256 ?? "") && Number.isSafeInteger(byteSize) && byteSize > 0 ? { intentId, manifestId, sourceRelativePath, sha256, byteSize } : null;
3727
+ const runtimeActionToolName = readString(providerContent.toolName);
3728
+ const runtimeAction = runtimeActionToolName?.startsWith("runtime_action.") ? {
3729
+ toolName: runtimeActionToolName,
3730
+ ...readString(providerResult.callId) ? { callId: readString(providerResult.callId) } : {},
3731
+ ...readString(providerResult.planId) ? { planId: readString(providerResult.planId) } : {},
3732
+ ...readString(providerResult.status) ? { resultStatus: readString(providerResult.status) } : {}
3733
+ } : null;
3714
3734
  return {
3715
3735
  ...invocationId ? { invocationId } : {},
3716
3736
  status,
3717
3737
  ...providerStatus ? { providerStatus } : {},
3718
- ...artifactIntent ? { artifactIntent } : {}
3738
+ ...artifactIntent ? { artifactIntent } : {},
3739
+ ...runtimeAction ? { runtimeAction } : {}
3740
+ };
3741
+ }
3742
+ function durablePiRuntimeActionEvidence(results) {
3743
+ const normalizedResults = (Array.isArray(results) ? results : []).map(asRecord);
3744
+ const writeCallIds = /* @__PURE__ */ new Set();
3745
+ const writePlanIds = /* @__PURE__ */ new Set();
3746
+ for (const result2 of normalizedResults) {
3747
+ const runtimeAction = asRecord(result2.runtimeAction);
3748
+ const toolName = readString(runtimeAction.toolName);
3749
+ const callId = readString(runtimeAction.callId);
3750
+ const planId = readString(runtimeAction.planId);
3751
+ const resultStatus = readString(runtimeAction.resultStatus);
3752
+ const status = readString(result2.status);
3753
+ const providerStatus = readString(result2.providerStatus);
3754
+ if (status === "succeeded" && providerStatus === "accepted" && toolName && resultStatus && PI_TERMINAL_RUNTIME_ACTION_STATUSES.has(resultStatus)) {
3755
+ const isLinkedStatus = toolName === "runtime_action.status" && (callId && writeCallIds.has(callId) || planId && writePlanIds.has(planId));
3756
+ const isDurableWrite = toolName === "runtime_action.submit" ? Boolean(callId) : toolName === "runtime_action.commit" && Boolean(planId || callId);
3757
+ if (isLinkedStatus || isDurableWrite) {
3758
+ return {
3759
+ kind: "runtime_action",
3760
+ ...readString(result2.invocationId) ? { invocationId: readString(result2.invocationId) } : {},
3761
+ toolName,
3762
+ ...callId ? { callId } : {},
3763
+ ...planId ? { planId } : {}
3764
+ };
3765
+ }
3766
+ }
3767
+ if (status !== "succeeded" || !PI_DURABLE_RUNTIME_ACTION_WRITE_TOOLS.has(toolName ?? "") || !PI_RUNTIME_ACTION_WRITE_RECEIPT_STATUSES.has(providerStatus ?? "")) continue;
3768
+ if (callId) writeCallIds.add(callId);
3769
+ if (planId) writePlanIds.add(planId);
3770
+ }
3771
+ return null;
3772
+ }
3773
+ function finalizedPiRuntimeArtifactEvidence(runtimeArtifacts) {
3774
+ const artifact = (Array.isArray(runtimeArtifacts) ? runtimeArtifacts : []).map(asRecord).find((entry) => readString(entry.status) === "finalized");
3775
+ if (!artifact) return null;
3776
+ const intentId = readString(artifact.intentId) ?? readString(artifact.artifactIntentId);
3777
+ return {
3778
+ kind: "runtime_artifact",
3779
+ ...intentId ? { intentId } : {}
3780
+ };
3781
+ }
3782
+ function classifyPiTerminalCleanupDisposition(parsed, runtimeArtifacts) {
3783
+ const diagnostics = Array.isArray(parsed?.cleanupDiagnostics) ? parsed.cleanupDiagnostics.map(asRecord) : [];
3784
+ if (parsed?.terminalEventType !== "agent_end" || readString(parsed?.stopReason) || parsed?.hasAssistantOutput !== true || diagnostics.length === 0 || diagnostics.some((diagnostic) => readString(diagnostic.phase) !== "post_terminal" || readString(diagnostic.code) !== "pi_terminal_cleanup_permission_denied") || readNumber(parsed?.nonCleanupErrorCount, 0) > 0) return null;
3785
+ const durableEvidence = durablePiRuntimeActionEvidence(parsed?.mcpToolResults) ?? finalizedPiRuntimeArtifactEvidence(runtimeArtifacts);
3786
+ if (!durableEvidence) return null;
3787
+ return {
3788
+ status: "failed",
3789
+ phase: "post_terminal",
3790
+ errorCode: "pi_terminal_cleanup_permission_denied",
3791
+ isolatedFromBusinessResult: true,
3792
+ durableEvidence,
3793
+ diagnostics
3719
3794
  };
3720
3795
  }
3721
3796
  function codexMcpToolResults(event) {
@@ -4159,8 +4234,11 @@ function parsePiJsonl(stdout) {
4159
4234
  let terminalEventType = null;
4160
4235
  let stopReason = null;
4161
4236
  let hasAssistantOutput = false;
4237
+ let nonCleanupErrorCount = 0;
4238
+ let nonCleanupErrorMessage = null;
4162
4239
  const messages = [];
4163
4240
  const mcpToolResults = [];
4241
+ const cleanupDiagnostics = [];
4164
4242
  const usage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
4165
4243
  for (const rawLine of String(stdout ?? "").split(/\r?\n/)) {
4166
4244
  const event = parseJsonLine(rawLine.trim());
@@ -4191,12 +4269,30 @@ function parsePiJsonl(stdout) {
4191
4269
  if (event.type === "turn_end") sawTurnEnd = true;
4192
4270
  if (event.type === "turn_end" || event.type === "agent_end") terminalEventType = event.type;
4193
4271
  stopReason = readString(event.stopReason ?? event.stop_reason) ?? piNestedMessageStopReason(event) ?? stopReason;
4194
- errorMessage = piStopReasonErrorText(event) ?? piNestedMessageErrorText(event) ?? errorMessage;
4272
+ const terminalError = piStopReasonErrorText(event) ?? piNestedMessageErrorText(event);
4273
+ if (terminalError) {
4274
+ nonCleanupErrorCount += 1;
4275
+ nonCleanupErrorMessage = terminalError;
4276
+ errorMessage = terminalError;
4277
+ }
4195
4278
  hasAssistantOutput = maybeCapturePiMessage(event, messages, usage) || hasAssistantOutput;
4196
4279
  continue;
4197
4280
  }
4198
4281
  if (event.type === "error") {
4199
- errorMessage = readString(event.message) ?? errorMessage;
4282
+ const eventError = readString(event.message);
4283
+ if (!eventError) continue;
4284
+ if (PI_TERMINAL_CLEANUP_PERMISSION_RE.test(eventError)) {
4285
+ cleanupDiagnostics.push({
4286
+ code: "pi_terminal_cleanup_permission_denied",
4287
+ message: eventError,
4288
+ phase: terminalEventType === "agent_end" ? "post_terminal" : "pre_terminal"
4289
+ });
4290
+ errorMessage = nonCleanupErrorMessage ?? eventError;
4291
+ } else {
4292
+ nonCleanupErrorCount += 1;
4293
+ nonCleanupErrorMessage = eventError;
4294
+ errorMessage = eventError;
4295
+ }
4200
4296
  }
4201
4297
  }
4202
4298
  return {
@@ -4208,6 +4304,8 @@ function parsePiJsonl(stdout) {
4208
4304
  stopReason,
4209
4305
  hasAssistantOutput,
4210
4306
  errorMessage,
4307
+ ...nonCleanupErrorCount > 0 ? { nonCleanupErrorCount } : {},
4308
+ ...cleanupDiagnostics.length > 0 ? { cleanupDiagnostics } : {},
4211
4309
  ...mcpToolResults.length > 0 ? { mcpToolResults } : {}
4212
4310
  };
4213
4311
  }
@@ -6061,7 +6159,7 @@ function readWorkspaceStatus(cwd, opts = {}) {
6061
6159
  }
6062
6160
 
6063
6161
  // src/amaster-runtime-daemon.mjs
6064
- var CONNECTOR_VERSION = "0.1.0-beta.43";
6162
+ var CONNECTOR_VERSION = "0.1.0-beta.44";
6065
6163
  var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
6066
6164
  var MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
6067
6165
  var CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -9611,18 +9709,33 @@ async function executeRunCommand(config, command) {
9611
9709
  const memoryLimitError = hasMemoryLimit ? `${executor.kind === "pi" ? "Pi Agent" : "Executor"} memory limit exceeded: RSS ${readNumber(memoryLimit.rssBytes, 0)} bytes exceeded ${readNumber(memoryLimit.limitBytes, config.executorMaxRssMb * 1024 * 1024)} bytes` : null;
9612
9710
  const piUsageDiagnostic = executor.kind === "pi" && !hasOutputFlood && piOutputUsageMetadataMissing(parsed) ? "Pi Agent exited without usage metadata" : null;
9613
9711
  const completionOutputStopped = executor.kind === "pi" && piCompletionOutputStopped(parsed, execution);
9614
- const piInvalidOutputError = executor.kind === "pi" ? piOutputValidationError(parsed, {
9615
- allowMissingTurnEnd: completionOutputStopped,
9712
+ const cleanupDisposition = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError && execution.signal === null ? classifyPiTerminalCleanupDisposition(parsed, runtimeArtifacts) : null;
9713
+ if (cleanupDisposition) {
9714
+ await ingestLog(
9715
+ config,
9716
+ command,
9717
+ "system",
9718
+ "warn",
9719
+ "Pi terminal result was preserved after a post-terminal cleanup permission failure",
9720
+ {
9721
+ presentationKind: "pi_terminal_cleanup",
9722
+ cleanupDisposition
9723
+ }
9724
+ );
9725
+ }
9726
+ const parsedForValidation = cleanupDisposition ? { ...parsed, errorMessage: null } : parsed;
9727
+ const piInvalidOutputError = executor.kind === "pi" ? piOutputValidationError(parsedForValidation, {
9728
+ allowMissingTurnEnd: completionOutputStopped || Boolean(cleanupDisposition),
9616
9729
  allowMissingAssistantOutput: execution.completionOutputType === "approval_required"
9617
9730
  }) : null;
9618
- const piProviderFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiProviderError(parsed) : null;
9619
- const parsedErrorMessage = outputFloodError ?? memoryLimitError ?? piInvalidOutputError ?? nativeSessionRolloutError ?? nativeSessionRolloutCleanupError ?? parsed.errorMessage;
9731
+ const piProviderFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiProviderError(parsedForValidation) : null;
9732
+ const parsedErrorMessage = outputFloodError ?? memoryLimitError ?? piInvalidOutputError ?? nativeSessionRolloutError ?? nativeSessionRolloutCleanupError ?? parsedForValidation.errorMessage;
9620
9733
  const codexTransientFailure = executor.kind === "codex" && (execution.exitCode ?? 0) !== 0 ? classifyCodexTransientUpstreamError({
9621
9734
  stdout: execution.stdout,
9622
9735
  stderr: execution.stderr,
9623
9736
  errorMessage: parsedErrorMessage
9624
9737
  }) : null;
9625
- const succeeded = !cancelled && !hasOutputFlood && !hasMemoryLimit && (execution.exitCode === 0 || completionOutputStopped) && !execution.timedOut && !execution.spawnError && !parsedErrorMessage;
9738
+ const succeeded = !cancelled && !hasOutputFlood && !hasMemoryLimit && (execution.exitCode === 0 || completionOutputStopped || Boolean(cleanupDisposition)) && !execution.timedOut && !execution.spawnError && !parsedErrorMessage;
9626
9739
  const resultStderr = filterExecutionStderrForResult(executor.kind, execution.stderr);
9627
9740
  const error = execution.timedOut ? `Executor timed out after ${config.executorTimeoutSeconds}s` : cancelled ? "Executor cancelled by AMaster control plane" : execution.spawnError ?? parsedErrorMessage ?? (succeeded ? null : `Executor exited with code ${execution.exitCode ?? "unknown"}`);
9628
9741
  const costUsage = parsedCostUsage(parsed.usage);
@@ -9655,6 +9768,7 @@ async function executeRunCommand(config, command) {
9655
9768
  timedOut: execution.timedOut,
9656
9769
  ...execution.outputDrainForcedClosed ? { outputDrainForcedClosed: true } : {},
9657
9770
  ...readString(execution.completionOutputType) ? { completionOutputType: readString(execution.completionOutputType) } : {},
9771
+ ...cleanupDisposition ? { cleanupDisposition } : {},
9658
9772
  ...cancelled ? { cancelledByControlPlane: true } : {},
9659
9773
  ...invocation.nativeSession ? { nativeSession: invocation.nativeSession } : {},
9660
9774
  ...nativeSessionRollout ? { nativeSessionRollout } : {},
@@ -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.0-beta.43";
8
+ const CONNECTOR_VERSION = "0.1.0-beta.44";
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.0-beta.43",
3
+ "version": "0.1.0-beta.44",
4
4
  "description": "MirrorX runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",