@amaster.ai/employee-runtime-connector 0.1.0-beta.20 → 0.1.0-beta.22

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,14 @@ 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
+ ## Mutation attestation
36
+
37
+ 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.
38
+
39
+ `AMASTER_RUNTIME_ATTESTATION_MODE` defaults to `shadow`. Set it to `enforce` only after the expected version and build marker are configured and shadow diagnostics are clean; enforce mode refuses to create or lease Runtime V2 mutation commands without a current exact attestation. `AMASTER_RUNTIME_ATTESTATION_TTL_SECONDS` defaults to `300` and accepts `60`–`3600`. Invalid mode or TTL values fail server startup visibly.
40
+
41
+ Threat model: these facts are self-reported by a connector authenticated with its existing connector credential. There is no hardware-backed signature, remote attestation, or independent trust root. The proof detects accidental version/schema/executor drift by an honest connector and correlates commands to the observed facts; it does not prove that a compromised or malicious connector is running the claimed code. Keep the default `shadow` mode observational. Do not treat this mechanism as a production security boundary or enable `enforce` until credential-epoch identity, transactional create/lease revalidation, batch-local rejection, and recovery from honest drift have passed review.
42
+
35
43
  The AMaster remote stack derives its runtime image from the Pi base image with
36
44
  `docker/Dockerfile.amaster-employee-pi-cli-runtime`. The build installs one exact
37
45
  connector package version under `/opt/pi-cli-runtime` and sets
@@ -2,10 +2,10 @@
2
2
  // AMaster Employee runtime connector daemon bundle.
3
3
 
4
4
  // src/amaster-runtime-daemon.mjs
5
- import { createHash as createHash5 } from "node:crypto";
6
- import { chmodSync as chmodSync3, copyFileSync as copyFileSync2, existsSync as existsSync9, lstatSync as lstatSync3, mkdirSync as mkdirSync5, readFileSync as readFileSync6, readdirSync as readdirSync6, realpathSync as realpathSync2, renameSync as renameSync2, rmSync as rmSync4, statSync as statSync7, symlinkSync as symlinkSync2, unlinkSync, writeFileSync as writeFileSync5 } from "node:fs";
5
+ import { createHash as createHash6 } from "node:crypto";
6
+ import { chmodSync as chmodSync3, copyFileSync as copyFileSync2, existsSync as existsSync9, lstatSync as lstatSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync as readdirSync6, realpathSync as realpathSync3, renameSync as renameSync3, rmSync as rmSync5, statSync as statSync7, symlinkSync as symlinkSync2, unlinkSync, writeFileSync as writeFileSync5 } from "node:fs";
7
7
  import { arch as arch3, homedir as homedir3, hostname as hostname2, platform as platform3 } from "node:os";
8
- import { basename as basename6, delimiter as delimiter2, dirname as dirname6, extname as extname2, isAbsolute as isAbsolute5, join as join10, relative as relative5, resolve as resolve7 } from "node:path";
8
+ import { basename as basename6, delimiter as delimiter2, dirname as dirname6, extname as extname2, isAbsolute as isAbsolute6, join as join10, relative as relative6, resolve as resolve8 } from "node:path";
9
9
  import { spawn, spawnSync as spawnSync5 } from "node:child_process";
10
10
 
11
11
  // src/amaster-runtime-daemon/common.mjs
@@ -2367,6 +2367,8 @@ function compileCommandPromptWithManifest(input, options = {}) {
2367
2367
  const governedReads = governedReadSection(context);
2368
2368
  const hasTask = Boolean(readString(input.taskMarkdown));
2369
2369
  const taskText = readString(input.taskMarkdown) ?? "";
2370
+ const continuationSummary = continuationText(context);
2371
+ const includeTask = mode === "cold" || !continuationSummary && asRecord(input.nativeSession).mode !== "governed_action_approval";
2370
2372
  const wakeBodies = commentBodies(context);
2371
2373
  const commentsDuplicatedByTask = hasTask && wakeBodies.length > 0 && wakeBodies.every((body) => taskText.includes(body));
2372
2374
  const commentsSelected = mode !== "cold" || !commentsDuplicatedByTask;
@@ -2378,9 +2380,9 @@ function compileCommandPromptWithManifest(input, options = {}) {
2378
2380
  const rawSections = [
2379
2381
  { name: "runtime_rules", title: "", priority: 100, sourceRef: `command:${input.commandId}`, content: fixedRules(input, !hasTask) },
2380
2382
  { name: "approval_continuation", title: "Approved Runtime Action Continuation", priority: 99, sourceRef: `run:${input.runId ?? "unknown"}`, content: approvalContinuationText(input), truncationReason: mode === "continuation" ? null : "mode_selection" },
2381
- { 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: continuationText(context), content: mode === "cold" ? "" : continuationText(context), truncationReason: mode === "cold" ? "mode_selection" : null },
2383
+ { 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 },
2382
2384
  { name: "wake_comments", title: "Wake Comment Delta", priority: 95, sourceRef: commentRefs(context).map((id) => `comment:${id}`), originalContent: readString(input.comments) ?? "", content: commentsSelected ? readString(input.comments) ?? "" : "", truncationReason: commentsSelected ? null : "duplicate_task_context" },
2383
- { name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: taskText, content: mode === "cold" ? taskText : "", truncationReason: mode === "cold" ? null : "mode_selection" },
2385
+ { name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: taskText, content: includeTask ? taskText : "", truncationReason: includeTask ? null : "mode_selection" },
2384
2386
  { 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 },
2385
2387
  { name: "agent_instructions", title: "Agent Instructions", priority: 85, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
2386
2388
  { name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
@@ -2433,7 +2435,7 @@ function compileCommandPromptWithManifest(input, options = {}) {
2433
2435
  }
2434
2436
 
2435
2437
  // src/amaster-runtime-daemon/config-state.mjs
2436
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
2438
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
2437
2439
  import { homedir as homedir2, hostname } from "node:os";
2438
2440
  import { dirname as dirname3, join as join4 } from "node:path";
2439
2441
 
@@ -2557,16 +2559,53 @@ function runtimeHome(env) {
2557
2559
  function stateFilePath(env) {
2558
2560
  return env.AMASTER_DAEMON_STATE_FILE ? expandHomePath(String(env.AMASTER_DAEMON_STATE_FILE)) : join4(runtimeHome(env), "runtime-connector-state.json");
2559
2561
  }
2562
+ function corruptStatePath(path) {
2563
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/\D/g, "").slice(0, 14);
2564
+ const base = `${path}.corrupt-${timestamp}Z`;
2565
+ let candidate = base;
2566
+ for (let suffix = 1; existsSync3(candidate); suffix += 1) {
2567
+ candidate = `${base}.${suffix}`;
2568
+ }
2569
+ return candidate;
2570
+ }
2560
2571
  function readState(env) {
2561
2572
  const path = stateFilePath(env);
2562
2573
  if (!existsSync3(path)) return {};
2563
- return JSON.parse(readFileSync3(path, "utf8"));
2574
+ try {
2575
+ const state = JSON.parse(readFileSync3(path, "utf8"));
2576
+ if (!state || typeof state !== "object" || Array.isArray(state)) {
2577
+ throw new TypeError("runtime connector state must be a JSON object");
2578
+ }
2579
+ return state;
2580
+ } catch {
2581
+ const quarantinePath = corruptStatePath(path);
2582
+ try {
2583
+ renameSync(path, quarantinePath);
2584
+ process.stderr.write(`AMaster runtime state was invalid and quarantined at ${quarantinePath}
2585
+ `);
2586
+ } catch (error) {
2587
+ process.stderr.write(
2588
+ `AMaster runtime state was invalid but could not be quarantined (${error?.code ?? "unknown error"})
2589
+ `
2590
+ );
2591
+ }
2592
+ return {};
2593
+ }
2564
2594
  }
2565
2595
  function writeState(env, state) {
2566
2596
  const path = stateFilePath(env);
2567
2597
  mkdirSync3(dirname3(path), { recursive: true });
2568
- writeFileSync3(path, `${JSON.stringify(state, null, 2)}
2569
- `);
2598
+ const temporaryPath = `${path}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
2599
+ try {
2600
+ writeFileSync3(temporaryPath, `${JSON.stringify(state, null, 2)}
2601
+ `, {
2602
+ flag: "wx",
2603
+ mode: 384
2604
+ });
2605
+ renameSync(temporaryPath, path);
2606
+ } finally {
2607
+ rmSync3(temporaryPath, { force: true });
2608
+ }
2570
2609
  }
2571
2610
  function buildConfig(env = process.env, flags = {}) {
2572
2611
  const serverUrl = String(flags.serverUrl ?? env.AMASTER_EMPLOYEE_SERVER_URL ?? "http://127.0.0.1:3100").replace(/\/+$/, "");
@@ -3151,6 +3190,13 @@ function shouldPreserveExecutorJsonlForTranscript(executorKind, event) {
3151
3190
  var CODEX_TRANSIENT_UPSTREAM_RE = /(?:we(?:'|’)re\s+currently\s+experiencing\s+high\s+demand|temporary\s+errors|rate[-\s]?limit(?:ed)?|too\s+many\s+requests|\b429\b|server\s+overloaded|service\s+unavailable|try\s+again\s+later)/i;
3152
3191
  var CODEX_REMOTE_COMPACTION_RE = /remote\s+compact\s+task/i;
3153
3192
  var CODEX_USAGE_LIMIT_RE = /you(?:'|’)ve hit your usage limit for .+\.\s+switch to another model now,\s+or try again at\s+([^.!\n]+)(?:[.!]|\n|$)/i;
3193
+ function approvedMcpInvocationSucceeded(results, invocationId) {
3194
+ const approvedInvocationId = readString(invocationId);
3195
+ return Boolean(approvedInvocationId && (Array.isArray(results) ? results : []).some((rawResult) => {
3196
+ const result2 = asRecord(rawResult);
3197
+ return readString(result2.invocationId) === approvedInvocationId && readString(result2.status) === "succeeded" && !["rejected", "blocked"].includes(readString(result2.providerStatus) ?? "");
3198
+ }));
3199
+ }
3154
3200
  function parseCodexJsonl(stdout) {
3155
3201
  let sessionId = null;
3156
3202
  let summary = "";
@@ -3171,7 +3217,19 @@ function parseCodexJsonl(stdout) {
3171
3217
  summary = readString(item.text) ?? summary;
3172
3218
  }
3173
3219
  if (item.type === "mcp_tool_call") {
3174
- const structuredContent = asRecord(asRecord(item.result).structuredContent);
3220
+ const result2 = asRecord(item.result);
3221
+ let structuredContent = asRecord(result2.structuredContent);
3222
+ if (Object.keys(structuredContent).length === 0 && Array.isArray(result2.content)) {
3223
+ for (const part of result2.content) {
3224
+ const text = readString(asRecord(part).text);
3225
+ if (!text) continue;
3226
+ try {
3227
+ structuredContent = asRecord(JSON.parse(text));
3228
+ } catch {
3229
+ }
3230
+ if (Object.keys(structuredContent).length > 0) break;
3231
+ }
3232
+ }
3175
3233
  const status = readString(structuredContent.status);
3176
3234
  if (status) {
3177
3235
  const invocationId = readString(structuredContent.invocationId);
@@ -3536,7 +3594,21 @@ function piMcpToolResults(event) {
3536
3594
  const status = readString(structuredContent.status);
3537
3595
  if (!status) continue;
3538
3596
  const invocationId = readString(structuredContent.invocationId);
3539
- results.push({ ...invocationId ? { invocationId } : {}, status });
3597
+ const providerContent = asRecord(structuredContent.content);
3598
+ const providerStatus = readString(providerContent.status);
3599
+ const effectResult = asRecord(asRecord(providerContent.result).effectResult);
3600
+ const intentId = readString(effectResult.artifactIntentId);
3601
+ const manifestId = readString(effectResult.manifestId);
3602
+ const sourceRelativePath = readString(effectResult.sourceRelativePath);
3603
+ const sha256 = readString(effectResult.sha256);
3604
+ const byteSize = readNumber(effectResult.byteSize, 0);
3605
+ const artifactIntent = providerContent.status === "pending_reconcile" && intentId && manifestId && sourceRelativePath && /^[a-f0-9]{64}$/.test(sha256 ?? "") && Number.isSafeInteger(byteSize) && byteSize > 0 ? { intentId, manifestId, sourceRelativePath, sha256, byteSize } : null;
3606
+ results.push({
3607
+ ...invocationId ? { invocationId } : {},
3608
+ status,
3609
+ ...providerStatus ? { providerStatus } : {},
3610
+ ...artifactIntent ? { artifactIntent } : {}
3611
+ });
3540
3612
  }
3541
3613
  return results;
3542
3614
  }
@@ -3705,6 +3777,26 @@ async function postRuntimeConnectorJson(config, path, payload) {
3705
3777
  }
3706
3778
  return body;
3707
3779
  }
3780
+ async function postRuntimeConnectorBytes(config, path, body, headers = {}) {
3781
+ if (!Buffer.isBuffer(body)) throw new TypeError("Runtime connector byte upload body must be a Buffer");
3782
+ const res = await fetch(`${config.serverUrl}${path}`, {
3783
+ method: "POST",
3784
+ headers: {
3785
+ ...headers,
3786
+ "content-type": "application/octet-stream",
3787
+ ...buildRuntimeConnectorAuthHeaders(config)
3788
+ },
3789
+ body
3790
+ });
3791
+ const text = await res.text();
3792
+ const response = text ? JSON.parse(text) : null;
3793
+ if (!res.ok) {
3794
+ const error = new Error(`POST ${path} returned HTTP ${res.status}: ${text}`);
3795
+ error.httpStatus = res.status;
3796
+ throw error;
3797
+ }
3798
+ return response;
3799
+ }
3708
3800
  async function bestEffortPostRuntimeConnectorJson(config, path, payload, options = {}) {
3709
3801
  try {
3710
3802
  return await postRuntimeConnectorJson(config, path, payload);
@@ -3722,13 +3814,73 @@ async function bestEffortPostRuntimeConnectorJson(config, path, payload, options
3722
3814
  var postJson = postRuntimeConnectorJson;
3723
3815
  var bestEffortPostJson = bestEffortPostRuntimeConnectorJson;
3724
3816
 
3725
- // src/amaster-runtime-daemon/workspace-guard.mjs
3817
+ // src/amaster-runtime-daemon/runtime-artifact-upload.mjs
3726
3818
  import { createHash as createHash3 } from "node:crypto";
3727
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, realpathSync, statSync as statSync3 } from "node:fs";
3728
- import { basename as basename4, join as join6, isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3 } from "node:path";
3819
+ import { lstatSync as lstatSync3, readFileSync as readFileSync4, realpathSync } from "node:fs";
3820
+ import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3 } from "node:path";
3821
+ var SHA256_PATTERN = /^[a-f0-9]{64}$/;
3822
+ function requiredString(value, name) {
3823
+ if (typeof value !== "string" || !value.trim()) throw new Error(`Runtime Artifact ${name} is required`);
3824
+ return value.trim();
3825
+ }
3826
+ function ownedRelativePath(value) {
3827
+ const normalized = requiredString(value, "sourceRelativePath").replaceAll("\\", "/");
3828
+ if (normalized.startsWith("/") || /^[a-z]:\//i.test(normalized) || normalized.split("/").some((segment) => !segment || segment === "." || segment === "..")) throw new Error(`Runtime Artifact source path is not owned: ${normalized}`);
3829
+ return normalized;
3830
+ }
3831
+ function pathWithin(candidate, root) {
3832
+ const rel = relative3(root, candidate);
3833
+ return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
3834
+ }
3835
+ function prepareRuntimeArtifactUploads(cwd, mcpToolResults) {
3836
+ const root = realpathSync(resolve3(cwd));
3837
+ const uploads = /* @__PURE__ */ new Map();
3838
+ for (const result2 of Array.isArray(mcpToolResults) ? mcpToolResults : []) {
3839
+ const intent = result2 && typeof result2 === "object" && !Array.isArray(result2) ? result2.artifactIntent : null;
3840
+ if (!intent || typeof intent !== "object" || Array.isArray(intent)) continue;
3841
+ const intentId = requiredString(intent.intentId, "intentId");
3842
+ const manifestId = requiredString(intent.manifestId, "manifestId");
3843
+ const sourceRelativePath = ownedRelativePath(intent.sourceRelativePath);
3844
+ const expectedSha256 = requiredString(intent.sha256, "sha256");
3845
+ const expectedByteSize = intent.byteSize;
3846
+ if (!SHA256_PATTERN.test(expectedSha256)) throw new Error(`Runtime Artifact ${intentId} has an invalid SHA-256`);
3847
+ if (!Number.isSafeInteger(expectedByteSize) || expectedByteSize <= 0) {
3848
+ throw new Error(`Runtime Artifact ${intentId} has an invalid byte size`);
3849
+ }
3850
+ const existing = uploads.get(intentId);
3851
+ if (existing) {
3852
+ if (existing.manifestId !== manifestId || existing.sourceRelativePath !== sourceRelativePath || existing.sha256 !== expectedSha256 || existing.byteSize !== expectedByteSize) throw new Error(`Runtime Artifact ${intentId} was emitted with conflicting ownership metadata`);
3853
+ continue;
3854
+ }
3855
+ const sourcePath = resolve3(root, sourceRelativePath);
3856
+ const stat = lstatSync3(sourcePath);
3857
+ if (!stat.isFile() || stat.isSymbolicLink() || !pathWithin(realpathSync(sourcePath), root)) {
3858
+ throw new Error(`Runtime Artifact ${intentId} source is not an owned regular file`);
3859
+ }
3860
+ const body = readFileSync4(sourcePath);
3861
+ const actualSha256 = createHash3("sha256").update(body).digest("hex");
3862
+ if (body.length !== expectedByteSize || actualSha256 !== expectedSha256) {
3863
+ throw new Error(`Runtime Artifact ${intentId} bytes do not match the governed ownership manifest`);
3864
+ }
3865
+ uploads.set(intentId, {
3866
+ intentId,
3867
+ manifestId,
3868
+ sourceRelativePath,
3869
+ sha256: expectedSha256,
3870
+ byteSize: expectedByteSize,
3871
+ body
3872
+ });
3873
+ }
3874
+ return [...uploads.values()];
3875
+ }
3876
+
3877
+ // src/amaster-runtime-daemon/workspace-guard.mjs
3878
+ import { createHash as createHash4 } from "node:crypto";
3879
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, realpathSync as realpathSync2, statSync as statSync3 } from "node:fs";
3880
+ import { basename as basename4, join as join6, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve4 } from "node:path";
3729
3881
 
3730
3882
  // src/amaster-runtime-daemon/workspace-manifest.mjs
3731
- import { existsSync as existsSync4, readFileSync as readFileSync4, renameSync, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
3883
+ import { existsSync as existsSync4, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "node:fs";
3732
3884
  import { basename as basename3, dirname as dirname4, join as join5 } from "node:path";
3733
3885
  var WORKSPACE_MANIFEST_FILENAME = ".amaster-runtime.json";
3734
3886
  function nowIso() {
@@ -3743,7 +3895,7 @@ function workspaceManifestPath(workspaceOrCwd) {
3743
3895
  function readWorkspaceManifest(manifestPath) {
3744
3896
  if (!manifestPath || !existsSync4(manifestPath)) return null;
3745
3897
  try {
3746
- const parsed = JSON.parse(readFileSync4(manifestPath, "utf8"));
3898
+ const parsed = JSON.parse(readFileSync5(manifestPath, "utf8"));
3747
3899
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
3748
3900
  } catch {
3749
3901
  return null;
@@ -3757,9 +3909,9 @@ function writeWorkspaceManifest(manifestPath, manifest) {
3757
3909
  try {
3758
3910
  writeFileSync4(tempPath, `${JSON.stringify(manifest, null, 2)}
3759
3911
  `, { mode: 384 });
3760
- renameSync(tempPath, manifestPath);
3912
+ renameSync2(tempPath, manifestPath);
3761
3913
  } catch (err) {
3762
- rmSync3(tempPath, { force: true });
3914
+ rmSync4(tempPath, { force: true });
3763
3915
  throw err;
3764
3916
  }
3765
3917
  return manifest;
@@ -3807,23 +3959,23 @@ function updateWorkspaceManifest(workspaceOrManifestPath, patch = {}) {
3807
3959
  }
3808
3960
 
3809
3961
  // src/amaster-runtime-daemon/workspace-guard.mjs
3810
- function pathWithin(candidate, root) {
3811
- const rel = relative3(root, candidate);
3812
- return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
3962
+ function pathWithin2(candidate, root) {
3963
+ const rel = relative4(root, candidate);
3964
+ return rel === "" || !rel.startsWith("..") && !isAbsolute4(rel);
3813
3965
  }
3814
3966
  function resolveWorkspaceCwd(config, command) {
3815
3967
  const payload = asRecord(command.payload);
3816
3968
  const requested = readString(payload.workspacePath);
3817
3969
  const fallback = config.workspaceBindings[0] ?? process.cwd();
3818
- const cwd = realpathSync(resolve3(expandHomePath(requested ?? fallback)));
3970
+ const cwd = realpathSync2(resolve4(expandHomePath(requested ?? fallback)));
3819
3971
  const allowlist = config.workspaceBindings.flatMap((entry) => {
3820
3972
  try {
3821
- return [realpathSync(resolve3(expandHomePath(entry)))];
3973
+ return [realpathSync2(resolve4(expandHomePath(entry)))];
3822
3974
  } catch {
3823
3975
  return [];
3824
3976
  }
3825
3977
  });
3826
- const allowed = allowlist.some((entry) => pathWithin(cwd, entry));
3978
+ const allowed = allowlist.some((entry) => pathWithin2(cwd, entry));
3827
3979
  if (!allowed) {
3828
3980
  throw new Error(`Workspace path is outside AMASTER_WORKSPACE_ALLOWLIST: ${cwd}`);
3829
3981
  }
@@ -3833,7 +3985,7 @@ function resolveWorkspaceCwd(config, command) {
3833
3985
  return cwd;
3834
3986
  }
3835
3987
  function shortHash(value, length = 12) {
3836
- return createHash3("sha256").update(String(value)).digest("hex").slice(0, length);
3988
+ return createHash4("sha256").update(String(value)).digest("hex").slice(0, length);
3837
3989
  }
3838
3990
  function safeSegment(value, fallback) {
3839
3991
  const raw = String(value ?? "").trim();
@@ -3857,9 +4009,9 @@ function workspaceLabel(sourceWorkspacePath, payload) {
3857
4009
  return readString(payload.workspaceName) ?? readString(payload.projectName) ?? readString(context.projectName) ?? basename4(sourceWorkspacePath) ?? "workspace";
3858
4010
  }
3859
4011
  function workspacesRoot(config) {
3860
- const root = resolve3(expandHomePath(config.runtimeWorkspacesRoot ?? "~/.amaster-employee/workspaces"));
4012
+ const root = resolve4(expandHomePath(config.runtimeWorkspacesRoot ?? "~/.amaster-employee/workspaces"));
3861
4013
  mkdirSync4(root, { recursive: true });
3862
- return realpathSync(root);
4014
+ return realpathSync2(root);
3863
4015
  }
3864
4016
  function resolveExecutionWorkspace(config, command, opts = {}) {
3865
4017
  const sourceWorkspacePath = resolveWorkspaceCwd(config, command);
@@ -3897,7 +4049,7 @@ function resolveExecutionWorkspace(config, command, opts = {}) {
3897
4049
 
3898
4050
  // src/amaster-runtime-daemon/workspace-gc.mjs
3899
4051
  import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync4 } from "node:fs";
3900
- import { join as join7, resolve as resolve4 } from "node:path";
4052
+ import { join as join7, resolve as resolve5 } from "node:path";
3901
4053
  function readIsoTime(value) {
3902
4054
  if (typeof value !== "string" || !value.trim()) return null;
3903
4055
  const time = new Date(value).getTime();
@@ -3979,7 +4131,7 @@ function summarizeWorkdir(path, manifest, nowMs) {
3979
4131
  };
3980
4132
  }
3981
4133
  function planManagedWorkspaceGcDryRun(input) {
3982
- const root = resolve4(String(input.root ?? ""));
4134
+ const root = resolve5(String(input.root ?? ""));
3983
4135
  const now = input.now instanceof Date ? input.now : /* @__PURE__ */ new Date();
3984
4136
  const nowMs = now.getTime();
3985
4137
  const ttlHours = Math.max(1, Number(input.ttlHours ?? 72));
@@ -4025,7 +4177,7 @@ function planManagedWorkspaceGcDryRun(input) {
4025
4177
 
4026
4178
  // src/amaster-runtime-daemon/runtime-status-summary.mjs
4027
4179
  import { existsSync as existsSync7, readdirSync as readdirSync4, statSync as statSync5 } from "node:fs";
4028
- import { dirname as dirname5, join as join8, resolve as resolve5 } from "node:path";
4180
+ import { dirname as dirname5, join as join8, resolve as resolve6 } from "node:path";
4029
4181
  function runtimeStatusDirectoryEntries(path) {
4030
4182
  try {
4031
4183
  return readdirSync4(path, { withFileTypes: true });
@@ -4117,7 +4269,7 @@ function countRuntimeStatusJsonEntries(dir) {
4117
4269
  }
4118
4270
  function summarizeRuntimeLocalState(input) {
4119
4271
  const config = input.config ?? {};
4120
- const root = resolve5(String(config.AMASTER_RUNTIME_WORKSPACES_ROOT ?? config.runtimeWorkspacesRoot ?? input.runtimeWorkspacesRoot ?? ""));
4272
+ const root = resolve6(String(config.AMASTER_RUNTIME_WORKSPACES_ROOT ?? config.runtimeWorkspacesRoot ?? input.runtimeWorkspacesRoot ?? ""));
4121
4273
  const now = input.now instanceof Date ? input.now : /* @__PURE__ */ new Date();
4122
4274
  const workdirs = walkRuntimeStatusManagedWorkdirs(root);
4123
4275
  let managedWorkdirBytes = 0;
@@ -4193,9 +4345,9 @@ function summarizeAmasterRuntimeVersionDrift(input = {}) {
4193
4345
 
4194
4346
  // src/amaster-runtime-daemon/workspace-status.mjs
4195
4347
  import { spawnSync as spawnSync4 } from "node:child_process";
4196
- import { createHash as createHash4 } from "node:crypto";
4197
- import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync5, statSync as statSync6 } from "node:fs";
4198
- import { basename as basename5, extname, isAbsolute as isAbsolute4, join as join9, relative as relative4, resolve as resolve6 } from "node:path";
4348
+ import { createHash as createHash5 } from "node:crypto";
4349
+ import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync6, statSync as statSync6 } from "node:fs";
4350
+ import { basename as basename5, extname, isAbsolute as isAbsolute5, join as join9, relative as relative5, resolve as resolve7 } from "node:path";
4199
4351
  var WORKSPACE_RUNTIME_SERVICES_FILENAME = ".amaster-runtime-services.json";
4200
4352
  var ARTIFACT_EXTENSIONS = /* @__PURE__ */ new Map([
4201
4353
  [".md", "markdown"],
@@ -4226,9 +4378,12 @@ var SKIP_DIR_NAMES = /* @__PURE__ */ new Set([
4226
4378
  "build",
4227
4379
  "coverage",
4228
4380
  ".turbo",
4229
- ".cache"
4381
+ ".cache",
4382
+ ".venv",
4383
+ "venv"
4230
4384
  ]);
4231
4385
  var SECRET_PATH_PATTERN = /(^|\/)(\.env($|[._-])|.*\.(pem|key|p12|pfx)$|.*(secret|token|credential|password|authorization|cookie).*)/i;
4386
+ var RUNTIME_INSTRUCTION_FILENAMES = /* @__PURE__ */ new Set(["AGENTS.md", "SOUL.md"]);
4232
4387
  var MAX_CANDIDATES = 200;
4233
4388
  var MAX_SCAN_ENTRIES = 5e3;
4234
4389
  var MAX_HASH_BYTES = 50 * 1024 * 1024;
@@ -4237,16 +4392,17 @@ var SAFE_RUNTIME_SERVICE_STATUSES = /* @__PURE__ */ new Set(["starting", "runnin
4237
4392
  var SAFE_RUNTIME_SERVICE_HEALTH_STATUSES = /* @__PURE__ */ new Set(["unknown", "healthy", "unhealthy"]);
4238
4393
  var SAFE_RUNTIME_SERVICE_LIFECYCLES = /* @__PURE__ */ new Set(["shared", "ephemeral"]);
4239
4394
  function statusPathWithin(candidate, root) {
4240
- const rel = relative4(root, candidate);
4241
- return rel === "" || !rel.startsWith("..") && !isAbsolute4(rel);
4395
+ const rel = relative5(root, candidate);
4396
+ return rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
4242
4397
  }
4243
4398
  function normalizeRelativePath(root, filePath) {
4244
- return relative4(root, filePath).split(/[\\/]+/).join("/");
4399
+ return relative5(root, filePath).split(/[\\/]+/).join("/");
4245
4400
  }
4246
4401
  function isSafeRelativePath(value) {
4247
4402
  const text = String(value ?? "").trim().split(/[\\/]+/).join("/");
4248
4403
  if (!text || text.startsWith("../") || text === ".." || text.startsWith("/")) return false;
4249
- return !SECRET_PATH_PATTERN.test(text);
4404
+ const segments = text.split("/").filter(Boolean);
4405
+ return !SECRET_PATH_PATTERN.test(text) && !RUNTIME_INSTRUCTION_FILENAMES.has(basename5(text)) && !segments.some((segment) => segment === ".venv" || segment === "venv");
4250
4406
  }
4251
4407
  function gitStatusPath(line) {
4252
4408
  if (line.startsWith("?? ")) return line.slice(3);
@@ -4260,7 +4416,7 @@ function sanitizeTrackedChange(line) {
4260
4416
  return isSafeRelativePath(path) ? line : null;
4261
4417
  }
4262
4418
  function sha256File(filePath) {
4263
- return createHash4("sha256").update(readFileSync5(filePath)).digest("hex");
4419
+ return createHash5("sha256").update(readFileSync6(filePath)).digest("hex");
4264
4420
  }
4265
4421
  function artifactHashCacheKey(relativePath, stat) {
4266
4422
  return `${relativePath}\0${stat.size}\0${stat.mtimeMs}`;
@@ -4288,7 +4444,7 @@ function artifactSha256(filePath, relativePath, stat, opts = {}) {
4288
4444
  return hash;
4289
4445
  }
4290
4446
  function scanArtifactCandidates(cwd, opts = {}) {
4291
- const root = resolve6(cwd);
4447
+ const root = resolve7(cwd);
4292
4448
  const maxCandidates = opts.maxCandidates ?? MAX_CANDIDATES;
4293
4449
  const maxEntries = opts.maxEntries ?? MAX_SCAN_ENTRIES;
4294
4450
  const candidates = [];
@@ -4328,7 +4484,7 @@ function scanArtifactCandidates(cwd, opts = {}) {
4328
4484
  } catch {
4329
4485
  continue;
4330
4486
  }
4331
- if (!statusPathWithin(resolve6(fullPath), root) || stat.size > MAX_HASH_BYTES) continue;
4487
+ if (!statusPathWithin(resolve7(fullPath), root) || stat.size > MAX_HASH_BYTES) continue;
4332
4488
  candidates.push({
4333
4489
  relativePath,
4334
4490
  name: basename5(fullPath),
@@ -4388,10 +4544,10 @@ function sanitizeRuntimeService(entry) {
4388
4544
  };
4389
4545
  }
4390
4546
  function readRuntimeServicesSnapshot(cwd) {
4391
- const snapshotPath = join9(resolve6(cwd), WORKSPACE_RUNTIME_SERVICES_FILENAME);
4547
+ const snapshotPath = join9(resolve7(cwd), WORKSPACE_RUNTIME_SERVICES_FILENAME);
4392
4548
  if (!existsSync8(snapshotPath)) return [];
4393
4549
  try {
4394
- const parsed = JSON.parse(readFileSync5(snapshotPath, "utf8"));
4550
+ const parsed = JSON.parse(readFileSync6(snapshotPath, "utf8"));
4395
4551
  const rawServices = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.services) ? parsed.services : [];
4396
4552
  return rawServices.map((entry) => sanitizeRuntimeService(entry)).filter((entry) => entry !== null).slice(0, 50);
4397
4553
  } catch {
@@ -4462,7 +4618,8 @@ function readWorkspaceStatus(cwd, opts = {}) {
4462
4618
  }
4463
4619
 
4464
4620
  // src/amaster-runtime-daemon.mjs
4465
- var CONNECTOR_VERSION = "0.1.0-beta.20";
4621
+ var CONNECTOR_VERSION = "0.1.0-beta.22";
4622
+ var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
4466
4623
  var MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
4467
4624
  var CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1e3;
4468
4625
  var PROMPT_AGENT_INSTRUCTION_FILE_ORDER = ["AGENTS.md", "SOUL.md"];
@@ -4575,11 +4732,11 @@ function piExtraArgsDiagnostics(value) {
4575
4732
  }
4576
4733
  function safeExpandPath(value) {
4577
4734
  const text = readString(value);
4578
- return text ? resolve7(expandHomePath(text)) : null;
4735
+ return text ? resolve8(expandHomePath(text)) : null;
4579
4736
  }
4580
4737
  function safeJsonObjectFromFile(filePath) {
4581
4738
  try {
4582
- const parsed = JSON.parse(readFileSync6(filePath, "utf8"));
4739
+ const parsed = JSON.parse(readFileSync7(filePath, "utf8"));
4583
4740
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
4584
4741
  } catch {
4585
4742
  return null;
@@ -4814,6 +4971,11 @@ function buildRegisterPayload(config) {
4814
4971
  networkDomains: config.networkDomains,
4815
4972
  executors: config.executors,
4816
4973
  capabilities: config.capabilities,
4974
+ contractVersion: CONNECTOR_CONTRACT_VERSION,
4975
+ connectorVersion: CONNECTOR_VERSION,
4976
+ ...buildCommit ? { buildCommit } : {},
4977
+ platform: process.platform,
4978
+ arch: process.arch,
4817
4979
  metadata: {
4818
4980
  daemon: "amaster-runtime-daemon.mjs",
4819
4981
  connectorVersion: CONNECTOR_VERSION,
@@ -4856,6 +5018,9 @@ function buildHeartbeatPayload(config, options = {}) {
4856
5018
  capabilities: config.capabilities,
4857
5019
  connectorVersion: CONNECTOR_VERSION,
4858
5020
  ...buildCommit ? { buildCommit } : {},
5021
+ contractVersion: CONNECTOR_CONTRACT_VERSION,
5022
+ platform: process.platform,
5023
+ arch: process.arch,
4859
5024
  runtimeStatus: {
4860
5025
  daemon: "running",
4861
5026
  pid: process.pid,
@@ -5395,7 +5560,7 @@ function commandExecutorEnv(command) {
5395
5560
  }
5396
5561
  function readJsonFile(filePath) {
5397
5562
  try {
5398
- const parsed = JSON.parse(readFileSync6(filePath, "utf8"));
5563
+ const parsed = JSON.parse(readFileSync7(filePath, "utf8"));
5399
5564
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
5400
5565
  } catch {
5401
5566
  return {};
@@ -5406,7 +5571,7 @@ function writeJsonFileAtomic(filePath, value) {
5406
5571
  const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
5407
5572
  writeFileSync5(tmpPath, `${JSON.stringify(value, null, 2)}
5408
5573
  `, { mode: 384 });
5409
- renameSync2(tmpPath, filePath);
5574
+ renameSync3(tmpPath, filePath);
5410
5575
  }
5411
5576
  function isPlainRecord(value) {
5412
5577
  return value && typeof value === "object" && !Array.isArray(value);
@@ -5565,12 +5730,12 @@ function safeAgentInstructionMaterializationTarget(workspace, filePath) {
5565
5730
  const raw = readString(filePath);
5566
5731
  if (!raw || raw.includes("\0")) return null;
5567
5732
  const normalized = raw.replace(/\\/g, "/");
5568
- if (isAbsolute5(normalized)) return null;
5733
+ if (isAbsolute6(normalized)) return null;
5569
5734
  const segments = normalized.split("/").filter(Boolean);
5570
5735
  if (segments.length === 0 || segments.some((segment) => segment === "." || segment === "..")) return null;
5571
5736
  const relativePath = segments.join("/");
5572
- const targetPath = resolve7(workspace.cwd, relativePath);
5573
- if (!pathWithin(targetPath, workspace.cwd)) return null;
5737
+ const targetPath = resolve8(workspace.cwd, relativePath);
5738
+ if (!pathWithin2(targetPath, workspace.cwd)) return null;
5574
5739
  return { relativePath, targetPath };
5575
5740
  }
5576
5741
  async function materializeAgentInstructionsBundle(config, command, workspace) {
@@ -5653,14 +5818,14 @@ function safeCompanyPiHomeSegment(companyId) {
5653
5818
  if (!raw) return null;
5654
5819
  if (/^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$/.test(raw)) return raw;
5655
5820
  const normalized = raw.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "").slice(0, 80);
5656
- const hash = createHash5("sha256").update(raw).digest("hex").slice(0, 12);
5821
+ const hash = createHash6("sha256").update(raw).digest("hex").slice(0, 12);
5657
5822
  return normalized ? `${normalized}-${hash}` : `company-${hash}`;
5658
5823
  }
5659
5824
  function companyPiHomeRoot(baseEnv) {
5660
5825
  const explicitRoot = readString(baseEnv.AMASTER_COMPANY_PI_HOME_ROOT);
5661
- if (explicitRoot) return resolve7(expandHomePath(explicitRoot));
5826
+ if (explicitRoot) return resolve8(expandHomePath(explicitRoot));
5662
5827
  const configuredPiHome = readString(baseEnv.PI_AGENT_HOME) ?? readString(baseEnv.PI_CODING_AGENT_DIR);
5663
- if (configuredPiHome) return join10(dirname6(resolve7(expandHomePath(configuredPiHome))), "companies");
5828
+ if (configuredPiHome) return join10(dirname6(resolve8(expandHomePath(configuredPiHome))), "companies");
5664
5829
  return join10(homedir3(), ".amaster-employee", "companies");
5665
5830
  }
5666
5831
  function companyPiAgentHome(baseEnv, companyId) {
@@ -5725,9 +5890,9 @@ function resolveNativeSessionRequest(command, workspace) {
5725
5890
  let cwdMatched = false;
5726
5891
  if (requestedCwd && sourceWorkspacePath) {
5727
5892
  try {
5728
- cwdMatched = realpathSync2(requestedCwd) === realpathSync2(sourceWorkspacePath);
5893
+ cwdMatched = realpathSync3(requestedCwd) === realpathSync3(sourceWorkspacePath);
5729
5894
  } catch {
5730
- cwdMatched = resolve7(requestedCwd) === resolve7(sourceWorkspacePath);
5895
+ cwdMatched = resolve8(requestedCwd) === resolve8(sourceWorkspacePath);
5731
5896
  }
5732
5897
  }
5733
5898
  const used = Boolean(enabled && requested && sessionId && requestedCwd && cwdMatched);
@@ -6105,6 +6270,11 @@ function createLiveOutputLogger(config, command, executorKind, protectedValues =
6105
6270
  }
6106
6271
  };
6107
6272
  }
6273
+ function isRuntimeMetadataArtifactPath(value) {
6274
+ const normalized = String(value ?? "").replaceAll("\\", "/").replace(/^\.\//, "");
6275
+ const name = basename6(normalized);
6276
+ return name === WORKSPACE_MANIFEST_FILENAME || name === WORKSPACE_RUNTIME_SERVICES_FILENAME;
6277
+ }
6108
6278
  function sampleProcessGroupRssBytes(processGroupId) {
6109
6279
  if (process.platform === "win32" || processGroupId === null) return null;
6110
6280
  const now = Date.now();
@@ -6130,15 +6300,15 @@ function sampleProcessGroupRssBytes(processGroupId) {
6130
6300
  }
6131
6301
  function realOrResolvedPath(value) {
6132
6302
  try {
6133
- return realpathSync2(value);
6303
+ return realpathSync3(value);
6134
6304
  } catch {
6135
- return resolve7(value);
6305
+ return resolve8(value);
6136
6306
  }
6137
6307
  }
6138
6308
  function processCwdForPid(pid) {
6139
6309
  if (process.platform === "linux") {
6140
6310
  try {
6141
- return realpathSync2(`/proc/${pid}/cwd`);
6311
+ return realpathSync3(`/proc/${pid}/cwd`);
6142
6312
  } catch {
6143
6313
  return null;
6144
6314
  }
@@ -6229,7 +6399,7 @@ function listWorkspaceResidentProcesses(cwd, processGroupId, options = {}) {
6229
6399
  if (processGroupId !== null && pgid === processGroupId) continue;
6230
6400
  const commandMatches = commandLine.includes(cwd) || commandLine.includes(normalizedCwd);
6231
6401
  const processCwd = commandMatches ? null : options.processCwdsByPid instanceof Map ? options.processCwdsByPid.get(pid) ?? null : processCwdForPid(pid);
6232
- const cwdMatches = processCwd ? pathWithin(processCwd, normalizedCwd) : false;
6402
+ const cwdMatches = processCwd ? pathWithin2(processCwd, normalizedCwd) : false;
6233
6403
  if (!commandMatches && !cwdMatches) continue;
6234
6404
  rows.push({ pid, pgid, command: commandLine.slice(0, 300) });
6235
6405
  }
@@ -6308,8 +6478,8 @@ function manifestMatchesActiveRuntimeRef(manifest, refs, workdir = null) {
6308
6478
  }
6309
6479
  function buildOrphanReaperSample(root, workdir, manifest, residents) {
6310
6480
  const relativeWorkdir = (() => {
6311
- const value = relative5(root, workdir);
6312
- return value && !value.startsWith("..") && !isAbsolute5(value) ? value : basename6(workdir);
6481
+ const value = relative6(root, workdir);
6482
+ return value && !value.startsWith("..") && !isAbsolute6(value) ? value : basename6(workdir);
6313
6483
  })();
6314
6484
  return {
6315
6485
  workdir: relativeWorkdir,
@@ -6613,6 +6783,53 @@ async function ingestWorkspaceStatus(config, command, cwd) {
6613
6783
  runId: commandRunId(command) ?? void 0,
6614
6784
  ...status
6615
6785
  });
6786
+ return status;
6787
+ }
6788
+ async function ingestRuntimeArtifacts(config, command, cwd, mcpToolResults) {
6789
+ const connectorId = requireConnectorId(config);
6790
+ const runId = commandRunId(command);
6791
+ if (!runId) throw new Error("Runtime Artifact ingest requires a correlated runId");
6792
+ const uploads = prepareRuntimeArtifactUploads(cwd, mcpToolResults);
6793
+ const receipts = [];
6794
+ for (const upload of uploads) {
6795
+ const path = `/api/amaster/runtime-connectors/${connectorId}/artifact-intents/${encodeURIComponent(upload.intentId)}/ingest`;
6796
+ try {
6797
+ const receipt = asRecord(await postRuntimeConnectorBytes(config, path, upload.body, {
6798
+ "x-amaster-command-id": command.commandId,
6799
+ "x-amaster-run-id": runId,
6800
+ "x-amaster-artifact-manifest-id": upload.manifestId,
6801
+ "x-amaster-artifact-source-path": upload.sourceRelativePath
6802
+ }));
6803
+ if (readString(receipt.intentId) !== upload.intentId || readString(receipt.status) !== "finalized") {
6804
+ throw new Error(`Runtime Artifact ${upload.intentId} was not finalized: ${JSON.stringify(receipt)}`);
6805
+ }
6806
+ receipts.push(receipt);
6807
+ await ingestLog(config, command, "system", "info", `Finalized Runtime Artifact ${upload.sourceRelativePath}`, {
6808
+ presentationKind: "runtime_artifact_ingest",
6809
+ intentId: upload.intentId,
6810
+ manifestId: upload.manifestId,
6811
+ sourceRelativePath: upload.sourceRelativePath,
6812
+ sha256: upload.sha256,
6813
+ byteSize: upload.byteSize,
6814
+ attachmentId: readString(receipt.attachmentId),
6815
+ workProductId: readString(receipt.workProductId),
6816
+ status: readString(receipt.status)
6817
+ });
6818
+ } catch (err) {
6819
+ const message = `Runtime Artifact ${upload.intentId} ingest failed: ${err instanceof Error ? err.message : String(err)}`;
6820
+ await ingestLog(config, command, "system", "error", message, {
6821
+ presentationKind: "runtime_artifact_ingest",
6822
+ intentId: upload.intentId,
6823
+ manifestId: upload.manifestId,
6824
+ sourceRelativePath: upload.sourceRelativePath,
6825
+ sha256: upload.sha256,
6826
+ byteSize: upload.byteSize,
6827
+ status: "failed"
6828
+ });
6829
+ throw new Error(message);
6830
+ }
6831
+ }
6832
+ return receipts;
6616
6833
  }
6617
6834
  function resultOutboxActiveRunSnapshot(command) {
6618
6835
  const commandId = readString(command.commandId) ?? readString(command.id);
@@ -6664,7 +6881,7 @@ async function completeCommand(config, command, status, result2, error) {
6664
6881
  }
6665
6882
  function resultOutboxDir(config) {
6666
6883
  const explicit = readString(process.env.AMASTER_RESULT_OUTBOX_DIR);
6667
- if (explicit) return resolve7(expandHomePath(explicit));
6884
+ if (explicit) return resolve8(expandHomePath(explicit));
6668
6885
  return join10(dirname6(stateFilePath(process.env)), "result-outbox");
6669
6886
  }
6670
6887
  function resultOutboxInvalidDir(config) {
@@ -6689,7 +6906,7 @@ function moveResultOutboxEntryToInvalid(config, file, fullPath, reason, detail,
6689
6906
  const invalidPath = join10(invalidDir, file);
6690
6907
  if (original === void 0) {
6691
6908
  try {
6692
- renameSync2(fullPath, invalidPath);
6909
+ renameSync3(fullPath, invalidPath);
6693
6910
  } catch {
6694
6911
  copyFileSync2(fullPath, invalidPath);
6695
6912
  unlinkSync(fullPath);
@@ -6709,7 +6926,7 @@ function moveResultOutboxEntryToInvalid(config, file, fullPath, reason, detail,
6709
6926
  function readValidResultOutboxEntryOrQuarantine(config, file, fullPath) {
6710
6927
  let entry;
6711
6928
  try {
6712
- entry = JSON.parse(readFileSync6(fullPath, "utf8"));
6929
+ entry = JSON.parse(readFileSync7(fullPath, "utf8"));
6713
6930
  } catch (err) {
6714
6931
  const message = err instanceof Error ? err.message : String(err);
6715
6932
  moveResultOutboxEntryToInvalid(config, file, fullPath, "malformed_result_outbox_json", message);
@@ -6987,7 +7204,7 @@ async function materializeIssueAttachments(config, command, workspace) {
6987
7204
  const body = await runtimeApiBuffer(runtimeAuth, contentPath);
6988
7205
  writeFileSync5(targetPath, body);
6989
7206
  const attachmentId = readString(attachment.id);
6990
- const actualSha256 = createHash5("sha256").update(body).digest("hex");
7207
+ const actualSha256 = createHash6("sha256").update(body).digest("hex");
6991
7208
  const lineageCandidates = lineageCandidatesByAttachmentId.get(attachmentId) ?? [];
6992
7209
  const lineage = selectAttachmentLineage(lineageCandidates, actualSha256);
6993
7210
  if (lineageCandidates.length > 0 && !lineage) {
@@ -7010,7 +7227,7 @@ async function materializeIssueAttachments(config, command, workspace) {
7010
7227
  id: attachmentId,
7011
7228
  name: readString(attachment.originalFilename) ?? filename,
7012
7229
  path: targetPath,
7013
- relativePath: relative5(workspace.cwd, targetPath),
7230
+ relativePath: relative6(workspace.cwd, targetPath),
7014
7231
  contentType: readString(attachment.contentType),
7015
7232
  byteSize: body.byteLength,
7016
7233
  contentPath,
@@ -7060,7 +7277,7 @@ async function materializeRequiredArtifactInputs(config, command, workspace) {
7060
7277
  throw new Error("artifact_input_manifest_invalid: expected version 1 entries array");
7061
7278
  }
7062
7279
  const targetRoot = join10(workspace.cwd, "input-artifacts");
7063
- rmSync4(targetRoot, { recursive: true, force: true });
7280
+ rmSync5(targetRoot, { recursive: true, force: true });
7064
7281
  mkdirSync5(targetRoot, { recursive: true });
7065
7282
  const usedPaths = /* @__PURE__ */ new Set();
7066
7283
  const materialized = [];
@@ -7079,7 +7296,7 @@ async function materializeRequiredArtifactInputs(config, command, workspace) {
7079
7296
  throw new Error(`artifact_input_manifest_invalid: entry ${index} contentPath does not match attachmentId`);
7080
7297
  }
7081
7298
  const body = await runtimeApiBuffer(runtimeAuth, contentPath);
7082
- const actualSha256 = createHash5("sha256").update(body).digest("hex");
7299
+ const actualSha256 = createHash6("sha256").update(body).digest("hex");
7083
7300
  if (body.byteLength !== byteSize || actualSha256 !== sha256) {
7084
7301
  throw new Error(
7085
7302
  `artifact_input_integrity_mismatch: workProductId=${workProductId} expectedBytes=${byteSize} actualBytes=${body.byteLength} expectedSha256=${sha256} actualSha256=${actualSha256}`
@@ -7136,53 +7353,56 @@ function issueCheckpointDir(workspace) {
7136
7353
  async function clearIssueCheckpoint(config, command, workspace, reason) {
7137
7354
  const checkpointDir = issueCheckpointDir(workspace);
7138
7355
  if (!existsSync9(checkpointDir)) return false;
7139
- rmSync4(checkpointDir, { recursive: true, force: true });
7356
+ rmSync5(checkpointDir, { recursive: true, force: true });
7140
7357
  await ingestLog(config, command, "system", "info", "Cleared issue continuation checkpoint", { reason });
7141
7358
  return true;
7142
7359
  }
7143
7360
  function safeCheckpointRelativePath(rawPath) {
7144
7361
  const raw = String(rawPath ?? "").trim();
7145
- if (isAbsolute5(raw) || /^[A-Za-z]:[\\/]/.test(raw)) return null;
7362
+ if (isAbsolute6(raw) || /^[A-Za-z]:[\\/]/.test(raw)) return null;
7146
7363
  const normalized = raw.split(/[\\/]+/).filter(Boolean).join("/");
7147
7364
  if (!normalized || normalized.startsWith("../") || normalized.split("/").some((segment) => segment.startsWith("."))) return null;
7148
7365
  if (normalized.startsWith("input-attachments/") || isRuntimeMetadataArtifactPath(normalized)) return null;
7149
7366
  return normalized;
7150
7367
  }
7368
+ function hashFileSha256(filePath) {
7369
+ return createHash6("sha256").update(readFileSync7(filePath)).digest("hex");
7370
+ }
7151
7371
  async function materializeIssueCheckpoint(config, command, workspace) {
7152
7372
  const checkpointDir = issueCheckpointDir(workspace);
7153
7373
  const manifestPath = join10(checkpointDir, "manifest.json");
7154
7374
  if (!existsSync9(manifestPath)) return [];
7155
7375
  let manifest;
7156
7376
  try {
7157
- manifest = asRecord(JSON.parse(readFileSync6(manifestPath, "utf8")));
7377
+ manifest = asRecord(JSON.parse(readFileSync7(manifestPath, "utf8")));
7158
7378
  } catch (err) {
7159
- rmSync4(checkpointDir, { recursive: true, force: true });
7379
+ rmSync5(checkpointDir, { recursive: true, force: true });
7160
7380
  throw new Error(`invalid issue checkpoint manifest: ${err instanceof Error ? err.message : String(err)}`);
7161
7381
  }
7162
7382
  const expiresAt = Date.parse(readString(manifest.expiresAt) ?? "");
7163
7383
  if (!Number.isFinite(expiresAt) || expiresAt <= Date.now() || readString(manifest.issueId) !== commandIssueId(command)) {
7164
- rmSync4(checkpointDir, { recursive: true, force: true });
7384
+ rmSync5(checkpointDir, { recursive: true, force: true });
7165
7385
  return [];
7166
7386
  }
7167
7387
  try {
7168
7388
  const files = Array.isArray(manifest.files) ? manifest.files : [];
7169
7389
  if (files.length > 20) throw new Error("issue checkpoint manifest exceeds the limit of 20 files");
7170
- const filesRoot = realpathSync2(join10(checkpointDir, "files"));
7171
- const workspaceRoot = realpathSync2(workspace.cwd);
7390
+ const filesRoot = realpathSync3(join10(checkpointDir, "files"));
7391
+ const workspaceRoot = realpathSync3(workspace.cwd);
7172
7392
  const validated = [];
7173
7393
  let totalBytes = 0;
7174
7394
  for (const rawFile of files) {
7175
7395
  const file = asRecord(rawFile);
7176
7396
  const relativePath = safeCheckpointRelativePath(readString(file.path));
7177
7397
  if (!relativePath) throw new Error("issue checkpoint manifest contains an invalid file path");
7178
- const sourceCandidate = resolve7(filesRoot, relativePath);
7179
- const target = resolve7(workspaceRoot, relativePath);
7180
- if (!pathWithin(sourceCandidate, filesRoot) || !pathWithin(target, workspaceRoot)) {
7398
+ const sourceCandidate = resolve8(filesRoot, relativePath);
7399
+ const target = resolve8(workspaceRoot, relativePath);
7400
+ if (!pathWithin2(sourceCandidate, filesRoot) || !pathWithin2(target, workspaceRoot)) {
7181
7401
  throw new Error(`issue checkpoint path escapes its workspace: ${relativePath}`);
7182
7402
  }
7183
7403
  if (!existsSync9(sourceCandidate)) throw new Error(`issue checkpoint file is missing: ${relativePath}`);
7184
- const source = realpathSync2(sourceCandidate);
7185
- if (!pathWithin(source, filesRoot) || !statSync7(source).isFile()) {
7404
+ const source = realpathSync3(sourceCandidate);
7405
+ if (!pathWithin2(source, filesRoot) || !statSync7(source).isFile()) {
7186
7406
  throw new Error(`issue checkpoint source escapes its storage root: ${relativePath}`);
7187
7407
  }
7188
7408
  const expectedSha256 = readString(file.sha256);
@@ -7200,14 +7420,14 @@ async function materializeIssueCheckpoint(config, command, workspace) {
7200
7420
  const materialized = [];
7201
7421
  for (const { relativePath, source, target } of validated) {
7202
7422
  try {
7203
- lstatSync3(target);
7423
+ lstatSync4(target);
7204
7424
  continue;
7205
7425
  } catch (err) {
7206
7426
  if (err?.code !== "ENOENT") throw err;
7207
7427
  }
7208
7428
  mkdirSync5(dirname6(target), { recursive: true });
7209
- const targetParent = realpathSync2(dirname6(target));
7210
- if (!pathWithin(targetParent, workspaceRoot)) {
7429
+ const targetParent = realpathSync3(dirname6(target));
7430
+ if (!pathWithin2(targetParent, workspaceRoot)) {
7211
7431
  throw new Error(`issue checkpoint target escapes its workspace: ${relativePath}`);
7212
7432
  }
7213
7433
  copyFileSync2(source, target);
@@ -7232,6 +7452,49 @@ async function materializeIssueCheckpoint(config, command, workspace) {
7232
7452
  throw restoreErr;
7233
7453
  }
7234
7454
  }
7455
+ async function saveIssueCheckpoint(config, command, workspace, candidates) {
7456
+ const checkpointDir = issueCheckpointDir(workspace);
7457
+ const filesDir = join10(checkpointDir, "files");
7458
+ rmSync5(checkpointDir, { recursive: true, force: true });
7459
+ mkdirSync5(filesDir, { recursive: true });
7460
+ const files = [];
7461
+ let totalBytes = 0;
7462
+ const workspaceRoot = realpathSync3(workspace.cwd);
7463
+ for (const candidate of candidates.slice(0, 20)) {
7464
+ const relativePath = safeCheckpointRelativePath(candidate.rawPath);
7465
+ const source = readString(candidate.filePath);
7466
+ if (!relativePath || !source || !existsSync9(source) || !statSync7(source).isFile()) continue;
7467
+ const ownedSource = realpathSync3(source);
7468
+ if (!pathWithin2(ownedSource, workspaceRoot)) {
7469
+ throw new Error(`issue checkpoint source escapes its execution workspace: ${relativePath}`);
7470
+ }
7471
+ const byteSize = statSync7(ownedSource).size;
7472
+ if (byteSize <= 0 || totalBytes + byteSize > MAX_CHECKPOINT_BYTES) continue;
7473
+ const target = resolve8(filesDir, relativePath);
7474
+ if (!pathWithin2(target, filesDir)) continue;
7475
+ mkdirSync5(dirname6(target), { recursive: true });
7476
+ copyFileSync2(ownedSource, target);
7477
+ totalBytes += byteSize;
7478
+ files.push({ path: relativePath, byteSize, sha256: hashFileSha256(ownedSource) });
7479
+ }
7480
+ if (files.length === 0) {
7481
+ rmSync5(checkpointDir, { recursive: true, force: true });
7482
+ return null;
7483
+ }
7484
+ const manifest = {
7485
+ version: 1,
7486
+ issueId: commandIssueId(command),
7487
+ sourceRunId: commandRunId(command),
7488
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
7489
+ expiresAt: new Date(Date.now() + CHECKPOINT_TTL_MS).toISOString(),
7490
+ totalBytes,
7491
+ files
7492
+ };
7493
+ writeFileSync5(join10(checkpointDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
7494
+ `);
7495
+ await ingestLog(config, command, "system", "warn", `Saved ${files.length} required deliverable(s) for continuation recovery`, manifest);
7496
+ return manifest;
7497
+ }
7235
7498
  function piOutputUsageMetadataMissing(parsed) {
7236
7499
  const usage = parsed?.usage ?? {};
7237
7500
  const totalTokens = Number(usage.inputTokens ?? 0) + Number(usage.cachedInputTokens ?? 0) + Number(usage.outputTokens ?? 0);
@@ -7284,6 +7547,7 @@ async function executeRunCommand(config, command) {
7284
7547
  error: err instanceof Error ? err.message : String(err)
7285
7548
  });
7286
7549
  }
7550
+ await ingestWorkspaceStatus(config, command, cwd);
7287
7551
  const promptCompilation = buildCommandPrompt(command, workspace, materializedAttachments, {
7288
7552
  executorKind: executor.kind,
7289
7553
  artifactVerifierCommands: config.artifactVerifierCommands
@@ -7429,7 +7693,7 @@ async function executeRunCommand(config, command) {
7429
7693
  }
7430
7694
  );
7431
7695
  await ingestCost(config, command, executor, parsed);
7432
- await ingestWorkspaceStatus(config, command, cwd);
7696
+ const workspaceStatus = await ingestWorkspaceStatus(config, command, cwd);
7433
7697
  let nativeSessionRollout = null;
7434
7698
  let nativeSessionRolloutError = null;
7435
7699
  let nativeSessionRolloutCleanup = null;
@@ -7438,6 +7702,7 @@ async function executeRunCommand(config, command) {
7438
7702
  ...Array.isArray(parsed.mcpToolResults) ? parsed.mcpToolResults.map(asRecord) : [],
7439
7703
  ...liveOutputLogger.mcpToolResults().map(asRecord)
7440
7704
  ];
7705
+ const runtimeArtifacts = await ingestRuntimeArtifacts(config, command, cwd, mcpToolResults);
7441
7706
  const shouldPreserveNativeSession = managedMcpProfile && parsed.sessionId && (execution.exitCode === 0 || execution.completionOutputType === "approval_required") && !execution.timedOut && execution.cancelled !== true && !execution.spawnError && ["codex", "pi"].includes(executor.kind) && mcpToolResults.some((result3) => readString(result3.status) === "approval_required");
7442
7707
  if (shouldPreserveNativeSession) {
7443
7708
  try {
@@ -7446,7 +7711,20 @@ async function executeRunCommand(config, command) {
7446
7711
  sessionId: parsed.sessionId,
7447
7712
  sourceWorkspacePath: workspace.sourceWorkspacePath
7448
7713
  });
7449
- nativeSessionRollout = { status: preservedRollout.status, sessionId: preservedRollout.sessionId };
7714
+ const checkpoint = await saveIssueCheckpoint(
7715
+ config,
7716
+ command,
7717
+ workspace,
7718
+ workspaceStatus.artifacts.map((artifact) => ({
7719
+ rawPath: artifact.relativePath,
7720
+ filePath: resolve8(cwd, artifact.relativePath)
7721
+ }))
7722
+ );
7723
+ nativeSessionRollout = {
7724
+ status: preservedRollout.status,
7725
+ sessionId: preservedRollout.sessionId,
7726
+ ...checkpoint ? { checkpoint: { fileCount: checkpoint.files.length, totalBytes: checkpoint.totalBytes } } : {}
7727
+ };
7450
7728
  await ingestLog(config, command, "system", "info", `Preserved ${executor.kind} session rollout for an approved action continuation`, {
7451
7729
  presentationKind: "managed_mcp_session_rollout",
7452
7730
  status: nativeSessionRollout.status,
@@ -7461,8 +7739,10 @@ async function executeRunCommand(config, command) {
7461
7739
  });
7462
7740
  }
7463
7741
  }
7464
- const approvedInvocationId = readString(nativeSessionRequest.invocationId);
7465
- const approvedContinuationSucceeded = nativeSessionRequest.mode === "governed_action_approval" && approvedInvocationId && mcpToolResults.some((result3) => readString(result3.invocationId) === approvedInvocationId && readString(result3.status) === "succeeded");
7742
+ const approvedContinuationSucceeded = nativeSessionRequest.mode === "governed_action_approval" && approvedMcpInvocationSucceeded(mcpToolResults, nativeSessionRequest.invocationId);
7743
+ if (approvedContinuationSucceeded) {
7744
+ await clearIssueCheckpoint(config, command, workspace, "approved_action_succeeded");
7745
+ }
7466
7746
  if (managedMcpProfile && executor.kind === "codex" && approvedContinuationSucceeded) {
7467
7747
  try {
7468
7748
  nativeSessionRolloutCleanup = cleanupRestoredManagedCodexSessionRollout(managedMcpProfile);
@@ -7537,6 +7817,7 @@ async function executeRunCommand(config, command) {
7537
7817
  summary: parsed.summary || (succeeded ? "Executor completed without a text summary." : ""),
7538
7818
  usage: parsed.usage,
7539
7819
  ...costUsage ? { costUsage } : {},
7820
+ ...runtimeArtifacts.length > 0 ? { runtimeArtifacts } : {},
7540
7821
  outputTelemetry,
7541
7822
  contextManifest,
7542
7823
  stdout: truncateText(execution.stdout, 8e3),
@@ -7802,7 +8083,7 @@ async function runLoop(config) {
7802
8083
  ${message}
7803
8084
  `);
7804
8085
  }
7805
- await new Promise((resolve8) => setTimeout(resolve8, config.pollIntervalSeconds * 1e3));
8086
+ await new Promise((resolve9) => setTimeout(resolve9, config.pollIntervalSeconds * 1e3));
7806
8087
  }
7807
8088
  }
7808
8089
  function help() {
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { spawn, spawnSync } from "node:child_process";
4
4
  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.20";
8
+ const CONNECTOR_VERSION = "0.1.0-beta.22";
9
9
 
10
10
  const CAPABILITIES = [
11
11
  "remote_registration",
@@ -277,8 +277,26 @@ function readState(config) {
277
277
  const statePath = config.AMASTER_DAEMON_STATE_FILE || join(configDir, "runtime-connector-state.json");
278
278
  if (!existsSync(statePath)) return {};
279
279
  try {
280
- return JSON.parse(readFileSync(statePath, "utf8"));
280
+ const state = JSON.parse(readFileSync(statePath, "utf8"));
281
+ if (!state || typeof state !== "object" || Array.isArray(state)) {
282
+ throw new TypeError("runtime connector state must be a JSON object");
283
+ }
284
+ return state;
281
285
  } catch {
286
+ const timestamp = new Date().toISOString().replace(/\D/g, "").slice(0, 14);
287
+ const base = `${statePath}.corrupt-${timestamp}Z`;
288
+ let quarantinePath = base;
289
+ for (let suffix = 1; existsSync(quarantinePath); suffix += 1) {
290
+ quarantinePath = `${base}.${suffix}`;
291
+ }
292
+ try {
293
+ renameSync(statePath, quarantinePath);
294
+ process.stderr.write(`AMaster runtime state was invalid and quarantined at ${quarantinePath}\n`);
295
+ } catch (error) {
296
+ process.stderr.write(
297
+ `AMaster runtime state was invalid but could not be quarantined (${error?.code ?? "unknown error"})\n`,
298
+ );
299
+ }
282
300
  return {};
283
301
  }
284
302
  }
@@ -286,7 +304,16 @@ function readState(config) {
286
304
  function writeState(config, state) {
287
305
  const statePath = withDefaults(config).AMASTER_DAEMON_STATE_FILE || join(configDir, "runtime-connector-state.json");
288
306
  mkdirSync(dirname(statePath), { recursive: true });
289
- writeFileSync(statePath, `${JSON.stringify(state, null, 2)}\n`);
307
+ const temporaryPath = `${statePath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
308
+ try {
309
+ writeFileSync(temporaryPath, `${JSON.stringify(state, null, 2)}\n`, {
310
+ flag: "wx",
311
+ mode: 0o600,
312
+ });
313
+ renameSync(temporaryPath, statePath);
314
+ } finally {
315
+ rmSync(temporaryPath, { force: true });
316
+ }
290
317
  }
291
318
 
292
319
  function readPidInfo() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amaster.ai/employee-runtime-connector",
3
- "version": "0.1.0-beta.20",
3
+ "version": "0.1.0-beta.22",
4
4
  "description": "AMaster Employee runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",