@amaster.ai/employee-runtime-connector 0.1.0-beta.52 → 0.1.0-beta.54

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.
@@ -1789,8 +1789,82 @@ function syncAmasterProviderFiles(agentDir, executorEnv) {
1789
1789
  };
1790
1790
  }
1791
1791
 
1792
+ // src/amaster-runtime-daemon/pi-mcp-args-normalizer.mjs
1793
+ function isJsonObject(value) {
1794
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1795
+ }
1796
+ function escapeLiteralJsonStringControlCharacters(value) {
1797
+ let output = "";
1798
+ let inString = false;
1799
+ let escaped = false;
1800
+ let changed = false;
1801
+ for (const character of value) {
1802
+ if (!inString) {
1803
+ output += character;
1804
+ if (character === '"') inString = true;
1805
+ continue;
1806
+ }
1807
+ if (escaped) {
1808
+ output += character;
1809
+ escaped = false;
1810
+ continue;
1811
+ }
1812
+ if (character === "\\") {
1813
+ output += character;
1814
+ escaped = true;
1815
+ continue;
1816
+ }
1817
+ if (character === '"') {
1818
+ output += character;
1819
+ inString = false;
1820
+ continue;
1821
+ }
1822
+ const escapedControlCharacter = character === "\n" ? "\\n" : character === "\r" ? "\\r" : character === " " ? "\\t" : character === "\b" ? "\\b" : character === "\f" ? "\\f" : character.charCodeAt(0) < 32 ? `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}` : null;
1823
+ if (escapedControlCharacter) {
1824
+ output += escapedControlCharacter;
1825
+ changed = true;
1826
+ } else {
1827
+ output += character;
1828
+ }
1829
+ }
1830
+ return changed ? output : value;
1831
+ }
1832
+ function normalizePiMcpProxyArgs(value) {
1833
+ if (typeof value !== "string") return { value, repaired: false };
1834
+ try {
1835
+ JSON.parse(value);
1836
+ return { value, repaired: false };
1837
+ } catch {
1838
+ const repairedValue = escapeLiteralJsonStringControlCharacters(value);
1839
+ if (repairedValue === value) return { value, repaired: false };
1840
+ try {
1841
+ return isJsonObject(JSON.parse(repairedValue)) ? { value: repairedValue, repaired: true } : { value, repaired: false };
1842
+ } catch {
1843
+ return { value, repaired: false };
1844
+ }
1845
+ }
1846
+ }
1847
+ function registerManagedPiMcpArgsNormalizer(pi) {
1848
+ pi.on("tool_call", (event) => {
1849
+ if (event?.toolName !== "mcp" || !event.input || typeof event.input !== "object") return;
1850
+ const normalized = normalizePiMcpProxyArgs(event.input.args);
1851
+ if (normalized.repaired) event.input.args = normalized.value;
1852
+ });
1853
+ }
1854
+ function managedPiMcpArgsNormalizerExtensionSource() {
1855
+ return [
1856
+ isJsonObject.toString(),
1857
+ escapeLiteralJsonStringControlCharacters.toString(),
1858
+ normalizePiMcpProxyArgs.toString(),
1859
+ `export default ${registerManagedPiMcpArgsNormalizer.toString()};`,
1860
+ ""
1861
+ ].join("\n\n");
1862
+ }
1863
+
1792
1864
  // src/amaster-runtime-daemon/pi-managed-mcp-profile.mjs
1793
1865
  var MANAGED_PI_MCP_TOOL_MODE = "proxy_only";
1866
+ var MANAGED_PI_MCP_ARGS_NORMALIZATION = "json_string_control_characters_v1";
1867
+ var MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME = "amaster-mcp-args-normalizer.mjs";
1794
1868
  function createManagedPiMcpProfileApi(options = {}) {
1795
1869
  const spawnSyncImpl = typeof options.spawnSync === "function" ? options.spawnSync : spawnSync2;
1796
1870
  const nowImpl = typeof options.now === "function" ? options.now : Date.now;
@@ -2162,6 +2236,12 @@ function createManagedPiMcpProfileApi(options = {}) {
2162
2236
  if (typeof sourceConfig.channel === "string" && ["stable", "beta", "dev", "canary"].includes(sourceConfig.channel)) {
2163
2237
  config.channel = sourceConfig.channel;
2164
2238
  }
2239
+ if (typeof sourceConfig.sessionMode === "string" && ["persistent", "isolated", "existing"].includes(sourceConfig.sessionMode)) {
2240
+ config.sessionMode = sourceConfig.sessionMode;
2241
+ }
2242
+ if (typeof sourceConfig.userDataDir === "string" && sourceConfig.userDataDir.trim().length > 0) {
2243
+ config.userDataDir = sourceConfig.userDataDir.trim();
2244
+ }
2165
2245
  return {
2166
2246
  packageSpec,
2167
2247
  plugin: {
@@ -2241,6 +2321,12 @@ function createManagedPiMcpProfileApi(options = {}) {
2241
2321
  };
2242
2322
  writePrivateFile2(join4(agentDir, "settings.json"), `${JSON.stringify(settings, null, 2)}
2243
2323
  `);
2324
+ const extensionsDir = join4(agentDir, "extensions");
2325
+ mkdirSync3(extensionsDir, { recursive: true, mode: 448 });
2326
+ writePrivateFile2(
2327
+ join4(extensionsDir, MANAGED_PI_MCP_ARGS_NORMALIZER_FILENAME),
2328
+ managedPiMcpArgsNormalizerExtensionSource()
2329
+ );
2244
2330
  copyPrivateFile(join4(source, "models.json"), join4(agentDir, "models.json"));
2245
2331
  const authSource = join4(source, "auth.json");
2246
2332
  const protectedValues = [];
@@ -2389,6 +2475,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
2389
2475
  ...executorAttestation,
2390
2476
  mcpAdapterVersion: seededRuntime.adapterVersion,
2391
2477
  mcpToolMode: MANAGED_PI_MCP_TOOL_MODE,
2478
+ mcpArgsNormalization: MANAGED_PI_MCP_ARGS_NORMALIZATION,
2392
2479
  configMode: "isolated_home_run_scoped_mcp_file",
2393
2480
  namespace: SUPPORTED_SERVER_NAME2,
2394
2481
  schemaVersion: SUPPORTED_SCHEMA_VERSION2,
@@ -2904,10 +2991,14 @@ function removeRunCompletionState(directory, commandId) {
2904
2991
  }
2905
2992
 
2906
2993
  // src/amaster-runtime-daemon/prompt-compiler.mjs
2907
- var DEFAULT_PROMPT_BUDGET_CHARS = 2e5;
2908
- 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";
2994
+ var DEADLINE_POSTURE_GUARD = "If a named time window or milestone is missed, skip that window and keep the task moving: never lower quality, bypass approvals, fabricate results, or stop the whole task because of the miss. Record a deadline-posture receipt with targetMilestoneRef, posture, onMiss=skip_this_window_and_continue, taskContinuation, and the next owner/action; the receipt is an execution signal, not Server-side proof.";
2909
2995
  var MIN_PROMPT_BUDGET_CHARS = 8192;
2910
- var MAX_PROMPT_SECTION_JSON_CHARS = 1e5;
2996
+ var MAX_RESOLVED_DEPENDENCY_REQUIRED_READS = 20;
2997
+ function promptBudgetError(code, message) {
2998
+ const error = new Error(message);
2999
+ error.code = code;
3000
+ return error;
3001
+ }
2911
3002
  var CONTINUATION_WAKE_PATTERN = /(continuation|continued|retry|approved|liveness|resume|max_turn)/i;
2912
3003
  var RECOVERY_WAKE_REASONS = /* @__PURE__ */ new Set([
2913
3004
  "finish_successful_run_handoff",
@@ -2916,15 +3007,6 @@ var RECOVERY_WAKE_REASONS = /* @__PURE__ */ new Set([
2916
3007
  function isRecoveryWakeReason(wakeReason) {
2917
3008
  return RECOVERY_WAKE_REASONS.has(wakeReason);
2918
3009
  }
2919
- function stringifyBoundedJson(value, maxChars = 24e3) {
2920
- let text = "";
2921
- try {
2922
- text = JSON.stringify(value, null, 2);
2923
- } catch {
2924
- text = String(value);
2925
- }
2926
- return truncateText(text, maxChars);
2927
- }
2928
3010
  function jsonText(value) {
2929
3011
  return JSON.stringify(value, null, 2);
2930
3012
  }
@@ -2938,7 +3020,7 @@ function jsonCharLength(value) {
2938
3020
  function estimatedTokens(chars) {
2939
3021
  return Math.ceil(chars / 4);
2940
3022
  }
2941
- function contextMode(input) {
3023
+ function promptContextMode(input) {
2942
3024
  const nativeSession = asRecord(input.nativeSession);
2943
3025
  if (nativeSession.mode === "governed_action_approval" || readString(input.context?.resumeFromRunId) || isRecoveryWakeReason(input.wakeReason) || CONTINUATION_WAKE_PATTERN.test(input.wakeReason ?? "")) return "continuation";
2944
3026
  if (nativeSession.resume === true || Object.keys(asRecord(input.context?.paperclipContinuationSummary)).length > 0) {
@@ -2946,6 +3028,22 @@ function contextMode(input) {
2946
3028
  }
2947
3029
  return "cold";
2948
3030
  }
3031
+ function filterDuplicatedTaskComments(context, mode) {
3032
+ if (mode !== "cold") return context;
3033
+ const record5 = asRecord(context);
3034
+ const included = new Set(
3035
+ (Array.isArray(record5.paperclipTaskMarkdownCommentIds) ? record5.paperclipTaskMarkdownCommentIds : []).map((entry) => readString(entry)).filter(Boolean)
3036
+ );
3037
+ if (included.size === 0) return context;
3038
+ const wake = asRecord(record5.paperclipWake);
3039
+ const comments = Array.isArray(wake.comments) ? wake.comments : [];
3040
+ const kept = comments.filter((entry) => {
3041
+ const id = readString(asRecord(entry).id);
3042
+ return !id || !included.has(id);
3043
+ });
3044
+ if (kept.length === comments.length) return context;
3045
+ return { ...record5, paperclipWake: { ...wake, comments: kept } };
3046
+ }
2949
3047
  function commentRefs(context) {
2950
3048
  const comments = Array.isArray(asRecord(context.paperclipWake).comments) ? asRecord(context.paperclipWake).comments : [];
2951
3049
  return comments.map((entry) => readString(asRecord(entry).id)).filter(Boolean);
@@ -3041,6 +3139,7 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3041
3139
  }
3042
3140
  const summaries = contextCopy ?? wakeCopy ?? [];
3043
3141
  const tuples = [];
3142
+ const overflowRefs = [];
3044
3143
  const seenTuples = /* @__PURE__ */ new Set();
3045
3144
  const detailLines = [];
3046
3145
  const detailSourceRefs = [];
@@ -3091,15 +3190,19 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3091
3190
  ]);
3092
3191
  if (seenTuples.has(tupleKey)) continue;
3093
3192
  seenTuples.add(tupleKey);
3094
- tuples.push({
3095
- blockerId,
3096
- blockerSelector,
3097
- documentId,
3098
- key,
3099
- expectedLatestRevisionId,
3100
- expectedLatestRevisionNumber: latestRevisionNumber ?? null,
3101
- observedAt: readString(document.updatedAt) ?? blockerObservedAt
3102
- });
3193
+ if (tuples.length >= MAX_RESOLVED_DEPENDENCY_REQUIRED_READS) {
3194
+ overflowRefs.push({ selector: blockerSelector, key });
3195
+ } else {
3196
+ tuples.push({
3197
+ blockerId,
3198
+ blockerSelector,
3199
+ documentId,
3200
+ key,
3201
+ expectedLatestRevisionId,
3202
+ expectedLatestRevisionNumber: latestRevisionNumber ?? null,
3203
+ observedAt: readString(document.updatedAt) ?? blockerObservedAt
3204
+ });
3205
+ }
3103
3206
  const documentTitle = readString(document.title);
3104
3207
  detailLines.push(
3105
3208
  ` Document: ${key}${documentTitle ? ` (${documentTitle})` : ""}${latestRevisionNumber != null ? ` revision ${latestRevisionNumber}` : ""}`
@@ -3118,6 +3221,11 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3118
3221
  if (workProductSummary) detailLines.push(` ${workProductSummary}`);
3119
3222
  }
3120
3223
  }
3224
+ if (overflowRefs.length > 0) {
3225
+ detailLines.push(
3226
+ ` \u2026mandatory required reads are capped at ${MAX_RESOLVED_DEPENDENCY_REQUIRED_READS}; the remaining ${overflowRefs.length} predecessor document(s) are listed under On-demand Context References.`
3227
+ );
3228
+ }
3121
3229
  const requiredLines = tuples.length > 0 ? [
3122
3230
  "Accepted predecessor outputs are binding inputs unless this issue explicitly requests reconsideration.",
3123
3231
  "Before any downstream document/artifact write, review request, status mutation, or completion, perform every Required read.",
@@ -3153,7 +3261,8 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3153
3261
  observedAt: detailObservedAt,
3154
3262
  freshness: detailSourceRefs.map(() => snapshotFreshness),
3155
3263
  scope: detailSourceRefs.map(() => contextScope)
3156
- }
3264
+ },
3265
+ overflowRefs
3157
3266
  };
3158
3267
  }
3159
3268
  function verifiedCompanyContextSection(context) {
@@ -3173,7 +3282,7 @@ function verifiedCompanyContextSection(context) {
3173
3282
  content: [
3174
3283
  "Use these server-snapshotted current Company facts as authoritative context for this run.",
3175
3284
  "The current verification contract does not supply shareholder structure or a financial baseline; treat them as unknown unless separate evidence is present, and do not describe the verified registration facts below as missing.",
3176
- stringifyBoundedJson(companyContext, MAX_PROMPT_SECTION_JSON_CHARS)
3285
+ jsonText(companyContext)
3177
3286
  ].join("\n"),
3178
3287
  sourceRef: [
3179
3288
  `company:${companyId}`,
@@ -3185,12 +3294,29 @@ function verifiedCompanyContextSection(context) {
3185
3294
  ].filter(Boolean)
3186
3295
  };
3187
3296
  }
3297
+ function wikiAccessRuleLine(input) {
3298
+ const access = asRecord(input.wikiAccess);
3299
+ const tools = input.hasGovernedMcp === true && access.tools === true;
3300
+ const treePath = readString(access.treePath);
3301
+ if (tools && treePath) {
3302
+ return `- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages via the amaster MCP, and the wiki tree at ${treePath} (read wiki/index.md there first).`;
3303
+ }
3304
+ if (tools) {
3305
+ return "- Company wiki access in this run: the governed tools wiki_search / wiki_read_page / wiki_list_pages via the amaster MCP. Use them for targeted lookup before re-deriving knowledge the company already holds.";
3306
+ }
3307
+ if (treePath) {
3308
+ return `- Company wiki access in this run: the wiki tree at ${treePath}. Read wiki/index.md first (every page listed with a one-line summary), then open the specific pages you need; wiki_* tools are not available in this run.`;
3309
+ }
3310
+ return "";
3311
+ }
3188
3312
  function fixedRules(input, includeIssueLine) {
3189
3313
  return [
3190
3314
  "## AMaster Runtime Connector Task",
3191
3315
  "MirrorX task.",
3192
3316
  "Use only the declared workspace; make concrete progress and report concisely.",
3193
- "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.",
3317
+ "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.",
3318
+ "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.",
3319
+ "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.",
3194
3320
  DEADLINE_POSTURE_GUARD,
3195
3321
  "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.",
3196
3322
  `- command id: ${input.commandId}`,
@@ -3203,9 +3329,10 @@ function fixedRules(input, includeIssueLine) {
3203
3329
  input.managed ? "Use the execution workspace as cwd. Never recursively scan the source workspace, the user's home directory, or any path outside the execution workspace. Only inspect a specific external source path when the task explicitly requires that exact path." : "",
3204
3330
  input.wakeReason ? `- wake reason: ${input.wakeReason}` : "",
3205
3331
  input.hasGovernedMcp ? "- AMaster mutations are available only through the managed amaster MCP server. Use discovered tools and immediate typed results; never call AMaster mutation REST endpoints directly." : "- No mutation channel is available for this command. Keep the run read-only and report the missing Runtime V2 capability as a blocker.",
3332
+ wikiAccessRuleLine(input),
3206
3333
  "- Runtime Artifact lineage fields sourceWorkProductId and sourceWorkProductIds accept only current artifact work product ids returned as result.effectResult.workProductId by a succeeded upload_artifact action. Never pass a documentId or revisionId as artifact lineage.",
3207
3334
  "- When all inputs are issue documents and there is no source artifact work product, persist the derived result with upsert_document and do not call upload_artifact for a derived or review artifact.",
3208
- input.hasGovernedMcp && input.executorKind === "pi" && input.managedMcpToolMode === "proxy_only" ? "- For proxy-only Pi MCP writes, put the complete target argument object directly in the actual `mcp` call's string `args` field, even for long document bodies. Do not create shell, script, or file intermediates to stage or quote a would-be tool call, and do not narrate or print it as prose. After the needed `runtime_action.describe` result, emit the write call before further planning." : ""
3335
+ input.hasGovernedMcp && input.executorKind === "pi" && input.managedMcpToolMode === "proxy_only" ? "- For proxy-only Pi MCP writes, put the complete target argument object directly in actual `mcp` string `args` as strict JSON; escape quotes, backslashes, and control characters. Do not stage or print tool calls. If inner JSON syntax fails, correct it once without changing values; never repeat a possibly accepted call. After `runtime_action.describe`, emit the write." : ""
3209
3336
  ].filter(Boolean).join("\n");
3210
3337
  }
3211
3338
  function approvalContinuationText(input) {
@@ -3230,7 +3357,7 @@ function interactionResolutionText(context) {
3230
3357
  "Treat this resolved interaction as the authoritative delta for this run.",
3231
3358
  readString(resolution.status) === "changes_requested" ? "Apply every requested change before creating a replacement review." : "",
3232
3359
  exactDocumentRevisionDirective,
3233
- stringifyBoundedJson(resolution, MAX_PROMPT_SECTION_JSON_CHARS)
3360
+ jsonText(resolution)
3234
3361
  ].filter(Boolean).join("\n");
3235
3362
  }
3236
3363
  function recoveryInstructionText(input) {
@@ -3365,6 +3492,25 @@ function runtimeDecompositionRequirementText(context) {
3365
3492
  `Requirement source: ${sourceType}:${sourceId}@${sourceRevision}`
3366
3493
  ].join("\n");
3367
3494
  }
3495
+ function readIssueEvidenceCommentCallText(issueId, commentId, options) {
3496
+ const readArguments = { refs: [{ kind: "issue_comment", issueId, commentId }] };
3497
+ if (options?.executorKind === "pi" && options?.managedMcpToolMode === "proxy_only") {
3498
+ return `emit an mcp proxy call: ${JSON.stringify({ server: "amaster", tool: "amaster.read_issue_evidence", args: JSON.stringify(readArguments) })}`;
3499
+ }
3500
+ return `call amaster.read_issue_evidence with these exact arguments: ${JSON.stringify(readArguments)}`;
3501
+ }
3502
+ function overflowDependencyRefsText(overflowRefs) {
3503
+ if (!Array.isArray(overflowRefs) || overflowRefs.length === 0) return "";
3504
+ return [
3505
+ "Additional predecessor documents available on demand \u2014 fetch each with amaster.read_issue_document before relying on it:",
3506
+ ...overflowRefs.map((ref) => `- issue ${JSON.stringify(ref.selector)}, key ${JSON.stringify(ref.key)}`)
3507
+ ].join("\n");
3508
+ }
3509
+ function taskCommentRefGuidance(input) {
3510
+ if (!input.hasGovernedMcp || !readString(input.issueId)) return "";
3511
+ const call = readIssueEvidenceCommentCallText(input.issueId, "<id>", input);
3512
+ return `References like comment:<id> above mark truncated comment bodies. Fetch the full text before relying on them \u2014 ${call} (replace <id> with the referenced comment id).`;
3513
+ }
3368
3514
  function piMcpProxyExamplesText(input) {
3369
3515
  if (!input.hasGovernedMcp || input.executorKind !== "pi" || input.managedMcpToolMode !== "proxy_only" || isRecoveryWakeReason(input.wakeReason)) return "";
3370
3516
  const proxy = (tool, args) => JSON.stringify({
@@ -3375,10 +3521,11 @@ function piMcpProxyExamplesText(input) {
3375
3521
  return [
3376
3522
  "The Pi native tool is the outer `mcp` proxy. Emit these as actual tool calls; `args` is the stringified inner canonical object:",
3377
3523
  "Keep review payload strings short. Reference the exact document key and revision in `target`; do not duplicate the reviewed document body in `prompt` or `detailsMarkdown`.",
3524
+ "update_parent.comment creates a separate persistent issue comment. Omit it when add_comment already recorded the message.",
3378
3525
  `- describe: ${proxy("runtime_action.describe", { schemaVersion: "runtime-action-v1", actionType: "update_parent" })}`,
3379
- `- submit: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-progress", action: { type: "update_parent", status: "in_progress", comment: "Continue the remaining work." } })}`,
3526
+ `- submit: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-progress", action: { type: "update_parent", status: "in_progress" } })}`,
3380
3527
  `- submit review interaction: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-review", action: { type: "create_interaction", kind: "request_confirmation", continuationPolicy: "wake_assignee_on_accept", payload: { version: 1, resolutionMode: "review", prompt: "Review `plan` revision 1.", target: { type: "issue_document", issueId: "11111111-1111-4111-8111-111111111111", documentId: "33333333-3333-4333-8333-333333333333", key: "plan", revisionId: "22222222-2222-4222-8222-222222222222", revisionNumber: 1 } } } })}`,
3381
- `- plan: ${proxy("runtime_action.plan", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-plan", actions: [{ type: "update_parent", status: "in_progress", comment: "Continue the remaining work." }] })}`,
3528
+ `- plan: ${proxy("runtime_action.plan", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-plan", actions: [{ type: "update_parent", status: "in_progress" }] })}`,
3382
3529
  `- commit the returned plan revision: ${proxy("runtime_action.commit", { schemaVersion: "runtime-action-v1", planId: "11111111-1111-4111-8111-111111111111", revision: "plan-revision-1" })}`,
3383
3530
  `- read document: ${proxy("amaster.read_issue_document", { issueId: "AM-123", key: "plan" })}`
3384
3531
  ].join("\n");
@@ -3437,19 +3584,19 @@ function buildManifest(mode, maxChars, sections, governedReadProvenance, usedCha
3437
3584
  budget: {
3438
3585
  totalChars: maxChars,
3439
3586
  usedChars,
3440
- utilization: (usedChars / maxChars).toFixed(4)
3587
+ utilization: maxChars === null ? null : (usedChars / maxChars).toFixed(4)
3441
3588
  },
3442
3589
  sections: sections.map(manifestEntry),
3443
3590
  governedReadProvenance
3444
3591
  };
3445
3592
  }
3446
3593
  function compileCommandPromptWithManifest(input, options = {}) {
3447
- const maxChars = Number(options.maxChars ?? DEFAULT_PROMPT_BUDGET_CHARS);
3448
- if (!Number.isInteger(maxChars) || maxChars < MIN_PROMPT_BUDGET_CHARS) {
3594
+ const maxChars = options.maxChars == null ? null : Number(options.maxChars);
3595
+ if (maxChars !== null && (!Number.isInteger(maxChars) || maxChars < MIN_PROMPT_BUDGET_CHARS)) {
3449
3596
  throw new RangeError(`Prompt budget must be an integer of at least ${MIN_PROMPT_BUDGET_CHARS} characters`);
3450
3597
  }
3451
3598
  const context = asRecord(input.context);
3452
- const mode = contextMode(input);
3599
+ const mode = promptContextMode(input);
3453
3600
  const recoveryInstruction = recoveryInstructionText(input);
3454
3601
  const recoveryContinuationOption = recoveryInstruction ? runtimeActionContinuationOptionText(input) : "";
3455
3602
  const completeRecoveryInstruction = [recoveryInstruction, recoveryContinuationOption].filter(Boolean).join("\n\n");
@@ -3461,7 +3608,8 @@ function compileCommandPromptWithManifest(input, options = {}) {
3461
3608
  const continuationSummary = continuationText(context);
3462
3609
  const includeTask = mode === "cold" || !continuationSummary && asRecord(input.nativeSession).mode !== "governed_action_approval";
3463
3610
  const wakeBodies = commentBodies(context);
3464
- const commentsDuplicatedByTask = hasTask && wakeBodies.length > 0 && wakeBodies.every((body) => taskText.includes(body));
3611
+ const hasTaskCommentIds = Array.isArray(context.paperclipTaskMarkdownCommentIds);
3612
+ const commentsDuplicatedByTask = !hasTaskCommentIds && hasTask && wakeBodies.length > 0 && wakeBodies.every((body) => taskText.includes(body));
3465
3613
  const commentsSelected = mode !== "cold" || !commentsDuplicatedByTask;
3466
3614
  const interactionResolution = interactionResolutionText(context);
3467
3615
  const selectedComments = commentsSelected ? readString(input.comments) ?? "" : "";
@@ -3507,11 +3655,11 @@ ${resolvedDependencies.details.content}` : ""
3507
3655
  { 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 },
3508
3656
  ...verifiedCompanyContext.content ? [{ name: "verified_company_context", title: "Verified Company Context", priority: 96, sourceRef: verifiedCompanyContext.sourceRef, observedAt: verifiedCompanyContext.observedAt, freshness: { kind: "run_snapshot" }, content: verifiedCompanyContext.content }] : [],
3509
3657
  { name: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
3510
- { name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: taskText, content: includeTask ? taskText : "", truncationReason: includeTask ? null : "mode_selection" },
3658
+ { name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n"), content: includeTask ? [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n") : "", truncationReason: includeTask ? null : "mode_selection" },
3511
3659
  { 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 },
3512
3660
  { name: "agent_instructions", title: "Agent Instructions", priority: 100, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
3513
3661
  { name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
3514
- { name: "on_demand_refs", title: "On-demand Context References", priority: 70, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: onDemandRefs(input) },
3662
+ { name: "on_demand_refs", title: "On-demand Context References", priority: 70, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: [onDemandRefs(input), overflowDependencyRefsText(resolvedDependencies.overflowRefs)].filter(Boolean).join("\n") },
3515
3663
  { name: "raw_snapshot", title: "Raw Context Snapshot", priority: 0, sourceRef: `run:${input.runId ?? "unknown"}`, originalChars: jsonCharLength(context), content: "", truncationReason: "on_demand_large_object" }
3516
3664
  ];
3517
3665
  const seenContent = /* @__PURE__ */ new Set();
@@ -3535,6 +3683,14 @@ ${resolvedDependencies.details.content}` : ""
3535
3683
  let prompt = "";
3536
3684
  let compactManifest = false;
3537
3685
  let manifest = buildManifest(mode, maxChars, sections, governedReads.provenance, 0);
3686
+ if (maxChars === null) {
3687
+ for (let telemetryPass = 0; telemetryPass < 20; telemetryPass += 1) {
3688
+ prompt = renderPrompt(sections, manifest);
3689
+ if (manifest.budget.usedChars === prompt.length) return { prompt, manifest };
3690
+ manifest = buildManifest(mode, null, sections, governedReads.provenance, prompt.length);
3691
+ }
3692
+ throw new Error("Prompt compiler could not stabilize the unbounded Context Manifest");
3693
+ }
3538
3694
  for (let pass = 0; pass < 20; pass += 1) {
3539
3695
  let usedChars = 0;
3540
3696
  for (let telemetryPass = 0; telemetryPass < 3; telemetryPass += 1) {
@@ -3557,17 +3713,24 @@ ${resolvedDependencies.details.content}` : ""
3557
3713
  const fixedChars = sections.filter((section) => section.priority === 100).map(sectionText).join("\n").length;
3558
3714
  const manifestChars = JSON.stringify(manifest).length;
3559
3715
  if (resolvedDependencies.required.tupleCount > 0) {
3560
- throw new Error(
3716
+ throw promptBudgetError(
3717
+ "resolved_dependencies_budget_exceeded",
3561
3718
  `Resolved dependency mandatory read tuples exceed the unified ${maxChars}-character prompt budget: tupleCount=${resolvedDependencies.required.tupleCount} promptChars=${prompt.length} fixedChars=${fixedChars} manifestChars=${manifestChars}`
3562
3719
  );
3563
3720
  }
3564
- throw new Error(`Prompt fixed sections exceed the unified ${maxChars}-character budget: promptChars=${prompt.length} fixedChars=${fixedChars} manifestChars=${manifestChars}`);
3721
+ throw promptBudgetError(
3722
+ "prompt_budget_exceeded",
3723
+ `Prompt fixed sections exceed the unified ${maxChars}-character budget: promptChars=${prompt.length} fixedChars=${fixedChars} manifestChars=${manifestChars}`
3724
+ );
3565
3725
  }
3566
3726
  truncateSection(candidate, Math.max(0, candidate.content.length - overflow - 32));
3567
3727
  manifest = buildManifest(mode, maxChars, sections, governedReads.provenance, 0);
3568
3728
  }
3569
3729
  if (prompt.length > maxChars || manifest.budget.usedChars !== prompt.length) {
3570
- throw new Error(`Prompt compiler could not satisfy the unified ${maxChars}-character budget`);
3730
+ throw promptBudgetError(
3731
+ "prompt_budget_exceeded",
3732
+ `Prompt compiler could not satisfy the unified ${maxChars}-character budget`
3733
+ );
3571
3734
  }
3572
3735
  return { prompt, manifest };
3573
3736
  }
@@ -4370,6 +4533,7 @@ var CODEX_USAGE_LIMIT_RE = /you(?:'|’)ve hit your usage limit for .+\.\s+switc
4370
4533
  var PI_PROVIDER_AUTH_RE = /(?:(?:\b401\b|\b403\b)[^\n]*(?:unauthorized|forbidden|auth(?:entication|orization)?|api[_\s-]?key)|(?:invalid|missing|expired|revoked)\s+(?:provider\s+)?api[_\s-]?key|provider\s+authentication\s+required)/i;
4371
4534
  var PI_PROVIDER_QUOTA_EXHAUSTED_RE = /(?:\binsufficient[_\s-]?user[_\s-]?quota\b|河狸币余额不足|\b402\b[^\n]*(?:余额不足|payment\s+required))/i;
4372
4535
  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;
4536
+ var PI_PROVIDER_PROTOCOL_RE = /provider[^\n]*finish_reason[^\n]*unexpected_state/i;
4373
4537
  var PI_PROVIDER_RETRY_AFTER_SECONDS_RE = /retry[-\s]?after\s*[:=]?\s*(\d{1,6})\s*(?:seconds?|secs?|s)\b/i;
4374
4538
  var PI_TERMINAL_CLEANUP_PERMISSION_RE = /(?:\bkill\b[^\n]*\bEPERM\b|\bEPERM\b[^\n]*\bkill\b)/i;
4375
4539
  var MAX_PI_PROVIDER_RETRY_AFTER_SECONDS = 7 * 24 * 60 * 60;
@@ -4712,6 +4876,12 @@ function extractPiProviderRetryNotBefore(errorMessage, now) {
4712
4876
  function classifyPiProviderError(input, now = /* @__PURE__ */ new Date()) {
4713
4877
  const errorMessage = readString(asRecord(input).errorMessage);
4714
4878
  if (!errorMessage) return null;
4879
+ if (PI_PROVIDER_PROTOCOL_RE.test(errorMessage)) {
4880
+ return {
4881
+ errorCode: "pi_provider_protocol_failure",
4882
+ errorFamily: "provider_protocol"
4883
+ };
4884
+ }
4715
4885
  if (PI_PROVIDER_QUOTA_EXHAUSTED_RE.test(errorMessage)) {
4716
4886
  return {
4717
4887
  errorCode: "pi_provider_quota_exhausted",
@@ -4956,13 +5126,17 @@ function parsePiJsonl(stdout) {
4956
5126
  let hasAssistantOutput = false;
4957
5127
  let nonCleanupErrorCount = 0;
4958
5128
  let nonCleanupErrorMessage = null;
5129
+ let terminalEventIndex = null;
5130
+ let eventIndex = -1;
4959
5131
  const messages = [];
4960
5132
  const mcpToolResults = [];
4961
5133
  const cleanupDiagnostics = [];
5134
+ const diagnostics = [];
4962
5135
  const usage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
4963
5136
  for (const rawLine of String(stdout ?? "").split(/\r?\n/)) {
4964
5137
  const event = parseJsonLine(rawLine.trim());
4965
5138
  if (!event) continue;
5139
+ eventIndex += 1;
4966
5140
  mcpToolResults.push(...piMcpToolResults(event));
4967
5141
  if (event.type === "session") {
4968
5142
  sessionId = readString(event.sessionId) ?? readString(event.id) ?? sessionId;
@@ -4987,13 +5161,26 @@ function parsePiJsonl(stdout) {
4987
5161
  }
4988
5162
  if (["message", "message_update", "message_end", "turn_end", "agent_end"].includes(event.type)) {
4989
5163
  if (event.type === "turn_end") sawTurnEnd = true;
4990
- if (event.type === "turn_end" || event.type === "agent_end") terminalEventType = event.type;
5164
+ if (event.type === "turn_end" || event.type === "agent_end") {
5165
+ terminalEventType = event.type;
5166
+ terminalEventIndex = eventIndex;
5167
+ }
4991
5168
  stopReason = readString(event.stopReason ?? event.stop_reason) ?? piNestedMessageStopReason(event) ?? stopReason;
4992
5169
  const terminalError = piStopReasonErrorText(event) ?? piNestedMessageErrorText(event);
4993
5170
  if (terminalError) {
4994
5171
  nonCleanupErrorCount += 1;
4995
5172
  nonCleanupErrorMessage = terminalError;
4996
5173
  errorMessage = terminalError;
5174
+ if (PI_PROVIDER_PROTOCOL_RE.test(terminalError)) {
5175
+ diagnostics.push({
5176
+ source: "provider",
5177
+ phase: "terminal",
5178
+ severity: "error",
5179
+ code: "pi_provider_protocol_failure",
5180
+ message: terminalError,
5181
+ eventIndex
5182
+ });
5183
+ }
4997
5184
  }
4998
5185
  hasAssistantOutput = maybeCapturePiMessage(event, messages, usage) || hasAssistantOutput;
4999
5186
  continue;
@@ -5002,16 +5189,33 @@ function parsePiJsonl(stdout) {
5002
5189
  const eventError = readString(event.message);
5003
5190
  if (!eventError) continue;
5004
5191
  if (PI_TERMINAL_CLEANUP_PERMISSION_RE.test(eventError)) {
5005
- cleanupDiagnostics.push({
5192
+ const diagnostic = {
5006
5193
  code: "pi_terminal_cleanup_permission_denied",
5007
5194
  message: eventError,
5008
5195
  phase: terminalEventType === "agent_end" ? "post_terminal" : "pre_terminal"
5196
+ };
5197
+ cleanupDiagnostics.push(diagnostic);
5198
+ diagnostics.push({
5199
+ source: "executor",
5200
+ severity: "warning",
5201
+ ...diagnostic,
5202
+ eventIndex
5009
5203
  });
5010
5204
  errorMessage = nonCleanupErrorMessage ?? eventError;
5011
5205
  } else {
5012
5206
  nonCleanupErrorCount += 1;
5013
5207
  nonCleanupErrorMessage = eventError;
5014
5208
  errorMessage = eventError;
5209
+ if (PI_PROVIDER_PROTOCOL_RE.test(eventError)) {
5210
+ diagnostics.push({
5211
+ source: "provider",
5212
+ phase: terminalEventType === "agent_end" ? "post_terminal" : "pre_terminal",
5213
+ severity: "error",
5214
+ code: "pi_provider_protocol_failure",
5215
+ message: eventError,
5216
+ eventIndex
5217
+ });
5218
+ }
5015
5219
  }
5016
5220
  }
5017
5221
  }
@@ -5022,11 +5226,13 @@ function parsePiJsonl(stdout) {
5022
5226
  usage,
5023
5227
  sawTurnEnd,
5024
5228
  terminalEventType,
5229
+ terminalEventIndex,
5025
5230
  stopReason,
5026
5231
  hasAssistantOutput,
5027
5232
  errorMessage,
5028
5233
  ...nonCleanupErrorCount > 0 ? { nonCleanupErrorCount } : {},
5029
5234
  ...cleanupDiagnostics.length > 0 ? { cleanupDiagnostics } : {},
5235
+ ...diagnostics.length > 0 ? { diagnostics } : {},
5030
5236
  ...uniqueMcpToolResults.length > 0 ? { mcpToolResults: uniqueMcpToolResults } : {}
5031
5237
  };
5032
5238
  }
@@ -6729,6 +6935,7 @@ var ARTIFACT_EXTENSIONS = /* @__PURE__ */ new Map([
6729
6935
  [".jpeg", "image"],
6730
6936
  [".webp", "image"],
6731
6937
  [".gif", "image"],
6938
+ [".svg", "image"],
6732
6939
  [".mp4", "video"],
6733
6940
  [".m4v", "video"],
6734
6941
  [".mov", "video"],
@@ -6766,7 +6973,7 @@ function isSafeRelativePath(value) {
6766
6973
  const text = String(value ?? "").trim().split(/[\\/]+/).join("/");
6767
6974
  if (!text || text.startsWith("../") || text === ".." || text.startsWith("/")) return false;
6768
6975
  const segments = text.split("/").filter(Boolean);
6769
- return !SECRET_PATH_PATTERN.test(text) && !RUNTIME_INSTRUCTION_FILENAMES.has(basename5(text)) && !segments.some((segment) => segment === ".venv" || segment === "venv");
6976
+ return !SECRET_PATH_PATTERN.test(text) && !RUNTIME_INSTRUCTION_FILENAMES.has(basename5(text)) && !segments.some((segment) => segment.startsWith(".")) && !segments.some((segment) => segment === ".venv" || segment === "venv");
6770
6977
  }
6771
6978
  function gitStatusPath(line) {
6772
6979
  if (line.startsWith("?? ")) return line.slice(3);
@@ -6840,8 +7047,7 @@ function scanArtifactCandidates(cwd, opts = {}) {
6840
7047
  }
6841
7048
  if (!entry.isFile()) continue;
6842
7049
  const ext = extname(entry.name).toLowerCase();
6843
- const type = ARTIFACT_EXTENSIONS.get(ext);
6844
- if (!type) continue;
7050
+ const type = ARTIFACT_EXTENSIONS.get(ext) ?? "file";
6845
7051
  let stat;
6846
7052
  try {
6847
7053
  stat = statSync6(fullPath);
@@ -8698,11 +8904,10 @@ function createPublicNetworkScope(options = {}) {
8698
8904
  }
8699
8905
 
8700
8906
  // src/amaster-runtime-daemon.mjs
8701
- var CONNECTOR_VERSION = "0.1.0-beta.52";
8907
+ var CONNECTOR_VERSION = "0.1.0-beta.54";
8702
8908
  var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
8703
8909
  var MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
8704
8910
  var CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1e3;
8705
- var PROMPT_AGENT_INSTRUCTION_FILE_ORDER = ["AGENTS.md", "SOUL.md"];
8706
8911
  var AMASTER_PI_PROHIBITED_EXTRA_ARGS = /* @__PURE__ */ new Set(["--no-extensions", "--no-skills", "--no-tools", "--no-session"]);
8707
8912
  var MAX_PI_CAPABILITY_SOURCE_ENTRIES = 200;
8708
8913
  var PI_COMPLETION_OUTPUT_GRACE_MS = 1e3;
@@ -9823,51 +10028,46 @@ function renderIssueLine(context) {
9823
10028
  const title = readString(issue.title);
9824
10029
  return [identifier, title].filter(Boolean).join(" ");
9825
10030
  }
9826
- function renderComments(context) {
10031
+ function renderComments(context, options = {}) {
9827
10032
  const wake = asRecord(context.paperclipWake);
9828
10033
  const comments = Array.isArray(wake.comments) ? wake.comments : [];
10034
+ const issueId = readString(options.issueId) ?? "";
10035
+ let truncatedCount = 0;
9829
10036
  const rendered = comments.map((entry, index) => {
9830
10037
  const comment = asRecord(entry);
9831
10038
  const id = readString(comment.id) ?? `comment-${index + 1}`;
9832
10039
  const body = readString(comment.body) ?? "";
9833
- const truncatedNote = comment.bodyTruncated === true ? `
9834
- [comment body truncated \u2014 fetch full text via typed read tool: comment:${id}]` : "";
10040
+ const truncated = comment.bodyTruncated === true;
10041
+ if (truncated) truncatedCount += 1;
10042
+ const truncatedNote = truncated ? `
10043
+ [comment body truncated \u2014 fetch the full text before relying on it: comment:${id}]` : "";
9835
10044
  return `${index + 1}. ${id}
9836
10045
  ${body}${truncatedNote}`;
9837
10046
  }).filter((entry) => entry.trim().length > 0).join("\n\n");
9838
- const fallbackNote = wake.fallbackFetchNeeded === true ? "[some wake comments were truncated or omitted from this prompt \u2014 fetch full text via managed typed read tools using the comment:<id> references]" : "";
9839
- return [rendered, fallbackNote].filter(Boolean).join("\n\n");
10047
+ const guidance = [];
10048
+ if (truncatedCount > 0 && issueId) {
10049
+ guidance.push(
10050
+ `Truncated comments above are marked comment:<id>. Fetch the full text before relying on a truncated comment \u2014 ${readIssueEvidenceCommentCallText(issueId, "<id>", options)} (replace <id> with the referenced comment id).`
10051
+ );
10052
+ }
10053
+ if (wake.fallbackFetchNeeded === true) {
10054
+ guidance.push(
10055
+ "[some wake comments were truncated or omitted from this prompt \u2014 fetch full text via amaster.read_issue_evidence using the comment:<id> references]"
10056
+ );
10057
+ }
10058
+ return [rendered, ...guidance].filter(Boolean).join("\n\n");
9840
10059
  }
9841
10060
  function renderTaskMarkdown(context) {
9842
10061
  return readString(context.paperclipTaskMarkdown);
9843
10062
  }
9844
- function normalizeAgentInstructionsFiles(bundle) {
9845
- const files = asRecord(bundle.files);
9846
- const selected = [];
9847
- const seen = /* @__PURE__ */ new Set();
9848
- for (const path of PROMPT_AGENT_INSTRUCTION_FILE_ORDER) {
9849
- const content = readString(files[path]);
9850
- if (!content) continue;
9851
- selected.push({ path, content });
9852
- seen.add(path);
9853
- }
9854
- const entryFile = readString(bundle.entryFile);
9855
- if (entryFile && !seen.has(entryFile)) {
9856
- const content = readString(files[entryFile]);
9857
- if (content) {
9858
- selected.push({ path: entryFile, content });
9859
- seen.add(entryFile);
9860
- }
9861
- }
9862
- return selected;
9863
- }
9864
10063
  function renderAgentInstructionsBundle(bundle) {
9865
- const files = normalizeAgentInstructionsFiles(asRecord(bundle));
9866
- if (files.length === 0) return "";
10064
+ const files = asRecord(asRecord(bundle).files);
10065
+ const names = Object.keys(files).filter((path) => readString(files[path])).sort((left, right) => left === right ? 0 : left === "AGENTS.md" ? -1 : right === "AGENTS.md" ? 1 : left.localeCompare(right));
10066
+ if (names.length === 0) return "";
9867
10067
  return [
9868
- "Current agent instructions:",
9869
- ...files.map((file) => [`### ${file.path}`, file.content].join("\n"))
9870
- ].join("\n\n");
10068
+ `Current agent instructions are materialized in the execution workspace as: ${names.map((name) => `./${name}`).join(", ")}.`,
10069
+ "They are authoritative for this run and are not inlined here. Read ./AGENTS.md first and follow it (including any sibling files it references) for the whole run."
10070
+ ].join("\n");
9871
10071
  }
9872
10072
  function commandRuntimeAuth(command) {
9873
10073
  const topLevel = asRecord(command.runtimeAuth);
@@ -10018,13 +10218,44 @@ async function materializeAgentInstructionsBundle(config, command, workspace) {
10018
10218
  }
10019
10219
  return materialized;
10020
10220
  }
10221
+ function wikiTreePathForCommand(command, workspaceBindings) {
10222
+ const runtimeAuth = commandRuntimeAuth(command);
10223
+ const companyId = readString(runtimeAuth.companyId) ?? readString(asRecord(command.payload).companyId) ?? "";
10224
+ for (const binding of Array.isArray(workspaceBindings) ? workspaceBindings : []) {
10225
+ const root = readString(binding);
10226
+ if (!root) continue;
10227
+ const candidates = [];
10228
+ if (root.endsWith("paperclipai.plugin-llm-wiki")) candidates.push(root);
10229
+ if (basename6(root) === "plugin-data" && companyId) {
10230
+ candidates.push(join15(root, companyId, "paperclipai.plugin-llm-wiki"));
10231
+ }
10232
+ for (const candidate of candidates) {
10233
+ try {
10234
+ if (existsSync14(candidate)) return candidate;
10235
+ } catch {
10236
+ }
10237
+ }
10238
+ }
10239
+ return null;
10240
+ }
10021
10241
  function buildCommandPrompt(command, workspace, materializedAttachments = [], options = {}) {
10022
10242
  const workspaceContext = normalizeWorkspaceContext(workspace);
10023
10243
  const cwd = workspaceContext.cwd;
10024
10244
  const payload = asRecord(command.payload);
10025
10245
  const context = asRecord(payload.contextSnapshot);
10026
10246
  const issueLine = renderIssueLine(context);
10027
- const comments = renderComments(context);
10247
+ const comments = renderComments(
10248
+ filterDuplicatedTaskComments(context, promptContextMode({
10249
+ nativeSession: asRecord(payload.nativeSession),
10250
+ wakeReason: readString(context.wakeReason),
10251
+ context
10252
+ })),
10253
+ {
10254
+ executorKind: options.executorKind,
10255
+ managedMcpToolMode: options.managedMcpToolMode,
10256
+ issueId: commandIssueId(command)
10257
+ }
10258
+ );
10028
10259
  const taskMarkdown = renderTaskMarkdown(context);
10029
10260
  const agentInstructions = renderAgentInstructionsBundle(asRecord(payload.agentInstructionsBundle));
10030
10261
  const runtimeAuth = commandRuntimeAuth(command);
@@ -10064,7 +10295,11 @@ function buildCommandPrompt(command, workspace, materializedAttachments = [], op
10064
10295
  attachmentsText,
10065
10296
  comments,
10066
10297
  context,
10067
- nativeSession: asRecord(payload.nativeSession)
10298
+ nativeSession: asRecord(payload.nativeSession),
10299
+ wikiAccess: {
10300
+ tools: context.wikiToolsAvailable === true,
10301
+ treePath: wikiTreePathForCommand(command, options.workspaceBindings)
10302
+ }
10068
10303
  });
10069
10304
  }
10070
10305
  function companyPiHomeRoot(baseEnv) {
@@ -12812,7 +13047,8 @@ async function executeRunCommand(config, command) {
12812
13047
  const promptCompilation = buildCommandPrompt(command, workspace, materializedAttachments, {
12813
13048
  executorKind: executor.kind,
12814
13049
  managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? MANAGED_PI_MCP_TOOL_MODE : null,
12815
- artifactVerifierCommands: config.artifactVerifierCommands
13050
+ artifactVerifierCommands: config.artifactVerifierCommands,
13051
+ workspaceBindings: config.workspaceBindings
12816
13052
  });
12817
13053
  const nativeSessionRequest = asRecord(asRecord(command.payload).nativeSession);
12818
13054
  const prompt = promptCompilation.prompt;
@@ -13030,7 +13266,8 @@ async function executeRunCommand(config, command) {
13030
13266
  ...piCompanyMemory ? { companyMemory: piCompanyMemory.attestation } : {}
13031
13267
  });
13032
13268
  }
13033
- await ingestLog(config, command, "system", "info", `Compiled ${contextManifest.mode} prompt using ${contextManifest.budget.usedChars}/${contextManifest.budget.totalChars} characters`, {
13269
+ const promptBudgetSummary = contextManifest.budget.totalChars === null ? `${contextManifest.budget.usedChars} characters (unbounded)` : `${contextManifest.budget.usedChars}/${contextManifest.budget.totalChars} characters`;
13270
+ await ingestLog(config, command, "system", "info", `Compiled ${contextManifest.mode} prompt using ${promptBudgetSummary}`, {
13034
13271
  presentationKind: "context_manifest",
13035
13272
  contextManifest
13036
13273
  });
@@ -13253,17 +13490,17 @@ async function executeRunCommand(config, command) {
13253
13490
  command,
13254
13491
  "system",
13255
13492
  "warn",
13256
- "Pi terminal result was preserved after a post-terminal cleanup permission failure",
13493
+ "Pi reported a post-terminal cleanup permission failure; server disposition evaluation remains authoritative",
13257
13494
  {
13258
13495
  presentationKind: "pi_terminal_cleanup",
13259
13496
  cleanupDisposition
13260
13497
  }
13261
13498
  );
13262
13499
  }
13263
- const parsedForValidation = cleanupDisposition ? { ...parsed, errorMessage: null } : parsed;
13500
+ const parsedForValidation = parsed;
13264
13501
  const piTurnLimitFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiTurnLimitResult(parsedForValidation) : null;
13265
13502
  const piInvalidOutputError = executor.kind === "pi" ? piOutputValidationError(parsedForValidation, {
13266
- allowMissingTurnEnd: completionOutputStopped || Boolean(cleanupDisposition),
13503
+ allowMissingTurnEnd: completionOutputStopped,
13267
13504
  allowMissingAssistantOutput: execution.completionOutputType === "approval_required"
13268
13505
  }) : null;
13269
13506
  const piProviderFailure = executor.kind === "pi" && !cancelled && !hasOutputFlood && !hasMemoryLimit && execution.timedOut !== true && !execution.spawnError ? classifyPiProviderError(parsedForValidation) : null;
@@ -13273,13 +13510,22 @@ async function executeRunCommand(config, command) {
13273
13510
  stderr: execution.stderr,
13274
13511
  errorMessage: parsedErrorMessage
13275
13512
  }) : null;
13276
- const succeeded = !cancelled && !hasOutputFlood && !hasMemoryLimit && (execution.exitCode === 0 || completionOutputStopped || Boolean(cleanupDisposition)) && !execution.timedOut && !execution.spawnError && !parsedErrorMessage;
13513
+ const succeeded = !cancelled && !hasOutputFlood && !hasMemoryLimit && (execution.exitCode === 0 || completionOutputStopped) && !execution.timedOut && !execution.spawnError && !parsedErrorMessage;
13277
13514
  const resultStderr = filterExecutionStderrForResult(executor.kind, execution.stderr);
13278
13515
  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"}`);
13279
13516
  const costUsage = parsedCostUsage(parsed.usage);
13517
+ const executorOutcome = {
13518
+ status: cancelled ? "cancelled" : execution.timedOut ? "timed_out" : execution.exitCode === 0 && execution.signal === null ? "completed" : "failed",
13519
+ exitCode: execution.exitCode,
13520
+ signal: execution.signal,
13521
+ terminalEvent: ["agent_end", "turn_end"].includes(readString(parsed.terminalEventType) ?? "") ? readString(parsed.terminalEventType) : null,
13522
+ terminalEventIndex: Number.isInteger(parsed.terminalEventIndex) ? parsed.terminalEventIndex : null
13523
+ };
13280
13524
  let result3 = {
13281
13525
  evidenceContract: { version: 1 },
13282
13526
  executorKind: executor.kind,
13527
+ executorOutcome,
13528
+ ...Array.isArray(parsed.diagnostics) && parsed.diagnostics.length > 0 ? { diagnostics: parsed.diagnostics } : {},
13283
13529
  command: invocation.command,
13284
13530
  args: invocation.args,
13285
13531
  cwd,
@@ -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.52";
8
+ const CONNECTOR_VERSION = "0.1.0-beta.54";
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.52",
3
+ "version": "0.1.0-beta.54",
4
4
  "description": "MirrorX runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",