@amaster.ai/employee-runtime-connector 0.1.0-beta.53 → 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;
@@ -2247,6 +2321,12 @@ function createManagedPiMcpProfileApi(options = {}) {
2247
2321
  };
2248
2322
  writePrivateFile2(join4(agentDir, "settings.json"), `${JSON.stringify(settings, null, 2)}
2249
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
+ );
2250
2330
  copyPrivateFile(join4(source, "models.json"), join4(agentDir, "models.json"));
2251
2331
  const authSource = join4(source, "auth.json");
2252
2332
  const protectedValues = [];
@@ -2395,6 +2475,7 @@ ${result3.stderr ?? ""}`, "Pi", MINIMUM_PI_VERSION);
2395
2475
  ...executorAttestation,
2396
2476
  mcpAdapterVersion: seededRuntime.adapterVersion,
2397
2477
  mcpToolMode: MANAGED_PI_MCP_TOOL_MODE,
2478
+ mcpArgsNormalization: MANAGED_PI_MCP_ARGS_NORMALIZATION,
2398
2479
  configMode: "isolated_home_run_scoped_mcp_file",
2399
2480
  namespace: SUPPORTED_SERVER_NAME2,
2400
2481
  schemaVersion: SUPPORTED_SCHEMA_VERSION2,
@@ -2910,8 +2991,14 @@ function removeRunCompletionState(directory, commandId) {
2910
2991
  }
2911
2992
 
2912
2993
  // src/amaster-runtime-daemon/prompt-compiler.mjs
2913
- 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.";
2914
2995
  var MIN_PROMPT_BUDGET_CHARS = 8192;
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
+ }
2915
3002
  var CONTINUATION_WAKE_PATTERN = /(continuation|continued|retry|approved|liveness|resume|max_turn)/i;
2916
3003
  var RECOVERY_WAKE_REASONS = /* @__PURE__ */ new Set([
2917
3004
  "finish_successful_run_handoff",
@@ -2933,7 +3020,7 @@ function jsonCharLength(value) {
2933
3020
  function estimatedTokens(chars) {
2934
3021
  return Math.ceil(chars / 4);
2935
3022
  }
2936
- function contextMode(input) {
3023
+ function promptContextMode(input) {
2937
3024
  const nativeSession = asRecord(input.nativeSession);
2938
3025
  if (nativeSession.mode === "governed_action_approval" || readString(input.context?.resumeFromRunId) || isRecoveryWakeReason(input.wakeReason) || CONTINUATION_WAKE_PATTERN.test(input.wakeReason ?? "")) return "continuation";
2939
3026
  if (nativeSession.resume === true || Object.keys(asRecord(input.context?.paperclipContinuationSummary)).length > 0) {
@@ -2941,6 +3028,22 @@ function contextMode(input) {
2941
3028
  }
2942
3029
  return "cold";
2943
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
+ }
2944
3047
  function commentRefs(context) {
2945
3048
  const comments = Array.isArray(asRecord(context.paperclipWake).comments) ? asRecord(context.paperclipWake).comments : [];
2946
3049
  return comments.map((entry) => readString(asRecord(entry).id)).filter(Boolean);
@@ -3036,6 +3139,7 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3036
3139
  }
3037
3140
  const summaries = contextCopy ?? wakeCopy ?? [];
3038
3141
  const tuples = [];
3142
+ const overflowRefs = [];
3039
3143
  const seenTuples = /* @__PURE__ */ new Set();
3040
3144
  const detailLines = [];
3041
3145
  const detailSourceRefs = [];
@@ -3086,15 +3190,19 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3086
3190
  ]);
3087
3191
  if (seenTuples.has(tupleKey)) continue;
3088
3192
  seenTuples.add(tupleKey);
3089
- tuples.push({
3090
- blockerId,
3091
- blockerSelector,
3092
- documentId,
3093
- key,
3094
- expectedLatestRevisionId,
3095
- expectedLatestRevisionNumber: latestRevisionNumber ?? null,
3096
- observedAt: readString(document.updatedAt) ?? blockerObservedAt
3097
- });
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
+ }
3098
3206
  const documentTitle = readString(document.title);
3099
3207
  detailLines.push(
3100
3208
  ` Document: ${key}${documentTitle ? ` (${documentTitle})` : ""}${latestRevisionNumber != null ? ` revision ${latestRevisionNumber}` : ""}`
@@ -3113,6 +3221,11 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3113
3221
  if (workProductSummary) detailLines.push(` ${workProductSummary}`);
3114
3222
  }
3115
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
+ }
3116
3229
  const requiredLines = tuples.length > 0 ? [
3117
3230
  "Accepted predecessor outputs are binding inputs unless this issue explicitly requests reconsideration.",
3118
3231
  "Before any downstream document/artifact write, review request, status mutation, or completion, perform every Required read.",
@@ -3148,7 +3261,8 @@ function resolvedDependencySections(context, input, contextScope, snapshotFreshn
3148
3261
  observedAt: detailObservedAt,
3149
3262
  freshness: detailSourceRefs.map(() => snapshotFreshness),
3150
3263
  scope: detailSourceRefs.map(() => contextScope)
3151
- }
3264
+ },
3265
+ overflowRefs
3152
3266
  };
3153
3267
  }
3154
3268
  function verifiedCompanyContextSection(context) {
@@ -3180,12 +3294,29 @@ function verifiedCompanyContextSection(context) {
3180
3294
  ].filter(Boolean)
3181
3295
  };
3182
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
+ }
3183
3312
  function fixedRules(input, includeIssueLine) {
3184
3313
  return [
3185
3314
  "## AMaster Runtime Connector Task",
3186
3315
  "MirrorX task.",
3187
3316
  "Use only the declared workspace; make concrete progress and report concisely.",
3188
- "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.",
3189
3320
  DEADLINE_POSTURE_GUARD,
3190
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.",
3191
3322
  `- command id: ${input.commandId}`,
@@ -3198,9 +3329,10 @@ function fixedRules(input, includeIssueLine) {
3198
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." : "",
3199
3330
  input.wakeReason ? `- wake reason: ${input.wakeReason}` : "",
3200
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),
3201
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.",
3202
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.",
3203
- 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." : ""
3204
3336
  ].filter(Boolean).join("\n");
3205
3337
  }
3206
3338
  function approvalContinuationText(input) {
@@ -3360,6 +3492,25 @@ function runtimeDecompositionRequirementText(context) {
3360
3492
  `Requirement source: ${sourceType}:${sourceId}@${sourceRevision}`
3361
3493
  ].join("\n");
3362
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
+ }
3363
3514
  function piMcpProxyExamplesText(input) {
3364
3515
  if (!input.hasGovernedMcp || input.executorKind !== "pi" || input.managedMcpToolMode !== "proxy_only" || isRecoveryWakeReason(input.wakeReason)) return "";
3365
3516
  const proxy = (tool, args) => JSON.stringify({
@@ -3370,10 +3521,11 @@ function piMcpProxyExamplesText(input) {
3370
3521
  return [
3371
3522
  "The Pi native tool is the outer `mcp` proxy. Emit these as actual tool calls; `args` is the stringified inner canonical object:",
3372
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.",
3373
3525
  `- describe: ${proxy("runtime_action.describe", { schemaVersion: "runtime-action-v1", actionType: "update_parent" })}`,
3374
- `- 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" } })}`,
3375
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 } } } })}`,
3376
- `- 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" }] })}`,
3377
3529
  `- commit the returned plan revision: ${proxy("runtime_action.commit", { schemaVersion: "runtime-action-v1", planId: "11111111-1111-4111-8111-111111111111", revision: "plan-revision-1" })}`,
3378
3530
  `- read document: ${proxy("amaster.read_issue_document", { issueId: "AM-123", key: "plan" })}`
3379
3531
  ].join("\n");
@@ -3444,7 +3596,7 @@ function compileCommandPromptWithManifest(input, options = {}) {
3444
3596
  throw new RangeError(`Prompt budget must be an integer of at least ${MIN_PROMPT_BUDGET_CHARS} characters`);
3445
3597
  }
3446
3598
  const context = asRecord(input.context);
3447
- const mode = contextMode(input);
3599
+ const mode = promptContextMode(input);
3448
3600
  const recoveryInstruction = recoveryInstructionText(input);
3449
3601
  const recoveryContinuationOption = recoveryInstruction ? runtimeActionContinuationOptionText(input) : "";
3450
3602
  const completeRecoveryInstruction = [recoveryInstruction, recoveryContinuationOption].filter(Boolean).join("\n\n");
@@ -3456,7 +3608,8 @@ function compileCommandPromptWithManifest(input, options = {}) {
3456
3608
  const continuationSummary = continuationText(context);
3457
3609
  const includeTask = mode === "cold" || !continuationSummary && asRecord(input.nativeSession).mode !== "governed_action_approval";
3458
3610
  const wakeBodies = commentBodies(context);
3459
- 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));
3460
3613
  const commentsSelected = mode !== "cold" || !commentsDuplicatedByTask;
3461
3614
  const interactionResolution = interactionResolutionText(context);
3462
3615
  const selectedComments = commentsSelected ? readString(input.comments) ?? "" : "";
@@ -3502,11 +3655,11 @@ ${resolvedDependencies.details.content}` : ""
3502
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 },
3503
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 }] : [],
3504
3657
  { name: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
3505
- { 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" },
3506
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 },
3507
3660
  { name: "agent_instructions", title: "Agent Instructions", priority: 100, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
3508
3661
  { name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
3509
- { 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") },
3510
3663
  { name: "raw_snapshot", title: "Raw Context Snapshot", priority: 0, sourceRef: `run:${input.runId ?? "unknown"}`, originalChars: jsonCharLength(context), content: "", truncationReason: "on_demand_large_object" }
3511
3664
  ];
3512
3665
  const seenContent = /* @__PURE__ */ new Set();
@@ -3560,17 +3713,24 @@ ${resolvedDependencies.details.content}` : ""
3560
3713
  const fixedChars = sections.filter((section) => section.priority === 100).map(sectionText).join("\n").length;
3561
3714
  const manifestChars = JSON.stringify(manifest).length;
3562
3715
  if (resolvedDependencies.required.tupleCount > 0) {
3563
- throw new Error(
3716
+ throw promptBudgetError(
3717
+ "resolved_dependencies_budget_exceeded",
3564
3718
  `Resolved dependency mandatory read tuples exceed the unified ${maxChars}-character prompt budget: tupleCount=${resolvedDependencies.required.tupleCount} promptChars=${prompt.length} fixedChars=${fixedChars} manifestChars=${manifestChars}`
3565
3719
  );
3566
3720
  }
3567
- 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
+ );
3568
3725
  }
3569
3726
  truncateSection(candidate, Math.max(0, candidate.content.length - overflow - 32));
3570
3727
  manifest = buildManifest(mode, maxChars, sections, governedReads.provenance, 0);
3571
3728
  }
3572
3729
  if (prompt.length > maxChars || manifest.budget.usedChars !== prompt.length) {
3573
- 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
+ );
3574
3734
  }
3575
3735
  return { prompt, manifest };
3576
3736
  }
@@ -6775,6 +6935,7 @@ var ARTIFACT_EXTENSIONS = /* @__PURE__ */ new Map([
6775
6935
  [".jpeg", "image"],
6776
6936
  [".webp", "image"],
6777
6937
  [".gif", "image"],
6938
+ [".svg", "image"],
6778
6939
  [".mp4", "video"],
6779
6940
  [".m4v", "video"],
6780
6941
  [".mov", "video"],
@@ -6812,7 +6973,7 @@ function isSafeRelativePath(value) {
6812
6973
  const text = String(value ?? "").trim().split(/[\\/]+/).join("/");
6813
6974
  if (!text || text.startsWith("../") || text === ".." || text.startsWith("/")) return false;
6814
6975
  const segments = text.split("/").filter(Boolean);
6815
- 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");
6816
6977
  }
6817
6978
  function gitStatusPath(line) {
6818
6979
  if (line.startsWith("?? ")) return line.slice(3);
@@ -6886,8 +7047,7 @@ function scanArtifactCandidates(cwd, opts = {}) {
6886
7047
  }
6887
7048
  if (!entry.isFile()) continue;
6888
7049
  const ext = extname(entry.name).toLowerCase();
6889
- const type = ARTIFACT_EXTENSIONS.get(ext);
6890
- if (!type) continue;
7050
+ const type = ARTIFACT_EXTENSIONS.get(ext) ?? "file";
6891
7051
  let stat;
6892
7052
  try {
6893
7053
  stat = statSync6(fullPath);
@@ -8744,11 +8904,10 @@ function createPublicNetworkScope(options = {}) {
8744
8904
  }
8745
8905
 
8746
8906
  // src/amaster-runtime-daemon.mjs
8747
- var CONNECTOR_VERSION = "0.1.0-beta.53";
8907
+ var CONNECTOR_VERSION = "0.1.0-beta.54";
8748
8908
  var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
8749
8909
  var MAX_CHECKPOINT_BYTES = 20 * 1024 * 1024;
8750
8910
  var CHECKPOINT_TTL_MS = 24 * 60 * 60 * 1e3;
8751
- var PROMPT_AGENT_INSTRUCTION_FILE_ORDER = ["AGENTS.md", "SOUL.md"];
8752
8911
  var AMASTER_PI_PROHIBITED_EXTRA_ARGS = /* @__PURE__ */ new Set(["--no-extensions", "--no-skills", "--no-tools", "--no-session"]);
8753
8912
  var MAX_PI_CAPABILITY_SOURCE_ENTRIES = 200;
8754
8913
  var PI_COMPLETION_OUTPUT_GRACE_MS = 1e3;
@@ -9869,51 +10028,46 @@ function renderIssueLine(context) {
9869
10028
  const title = readString(issue.title);
9870
10029
  return [identifier, title].filter(Boolean).join(" ");
9871
10030
  }
9872
- function renderComments(context) {
10031
+ function renderComments(context, options = {}) {
9873
10032
  const wake = asRecord(context.paperclipWake);
9874
10033
  const comments = Array.isArray(wake.comments) ? wake.comments : [];
10034
+ const issueId = readString(options.issueId) ?? "";
10035
+ let truncatedCount = 0;
9875
10036
  const rendered = comments.map((entry, index) => {
9876
10037
  const comment = asRecord(entry);
9877
10038
  const id = readString(comment.id) ?? `comment-${index + 1}`;
9878
10039
  const body = readString(comment.body) ?? "";
9879
- const truncatedNote = comment.bodyTruncated === true ? `
9880
- [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}]` : "";
9881
10044
  return `${index + 1}. ${id}
9882
10045
  ${body}${truncatedNote}`;
9883
10046
  }).filter((entry) => entry.trim().length > 0).join("\n\n");
9884
- 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]" : "";
9885
- 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");
9886
10059
  }
9887
10060
  function renderTaskMarkdown(context) {
9888
10061
  return readString(context.paperclipTaskMarkdown);
9889
10062
  }
9890
- function normalizeAgentInstructionsFiles(bundle) {
9891
- const files = asRecord(bundle.files);
9892
- const selected = [];
9893
- const seen = /* @__PURE__ */ new Set();
9894
- for (const path of PROMPT_AGENT_INSTRUCTION_FILE_ORDER) {
9895
- const content = readString(files[path]);
9896
- if (!content) continue;
9897
- selected.push({ path, content });
9898
- seen.add(path);
9899
- }
9900
- const entryFile = readString(bundle.entryFile);
9901
- if (entryFile && !seen.has(entryFile)) {
9902
- const content = readString(files[entryFile]);
9903
- if (content) {
9904
- selected.push({ path: entryFile, content });
9905
- seen.add(entryFile);
9906
- }
9907
- }
9908
- return selected;
9909
- }
9910
10063
  function renderAgentInstructionsBundle(bundle) {
9911
- const files = normalizeAgentInstructionsFiles(asRecord(bundle));
9912
- 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 "";
9913
10067
  return [
9914
- "Current agent instructions:",
9915
- ...files.map((file) => [`### ${file.path}`, file.content].join("\n"))
9916
- ].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");
9917
10071
  }
9918
10072
  function commandRuntimeAuth(command) {
9919
10073
  const topLevel = asRecord(command.runtimeAuth);
@@ -10064,13 +10218,44 @@ async function materializeAgentInstructionsBundle(config, command, workspace) {
10064
10218
  }
10065
10219
  return materialized;
10066
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
+ }
10067
10241
  function buildCommandPrompt(command, workspace, materializedAttachments = [], options = {}) {
10068
10242
  const workspaceContext = normalizeWorkspaceContext(workspace);
10069
10243
  const cwd = workspaceContext.cwd;
10070
10244
  const payload = asRecord(command.payload);
10071
10245
  const context = asRecord(payload.contextSnapshot);
10072
10246
  const issueLine = renderIssueLine(context);
10073
- 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
+ );
10074
10259
  const taskMarkdown = renderTaskMarkdown(context);
10075
10260
  const agentInstructions = renderAgentInstructionsBundle(asRecord(payload.agentInstructionsBundle));
10076
10261
  const runtimeAuth = commandRuntimeAuth(command);
@@ -10110,7 +10295,11 @@ function buildCommandPrompt(command, workspace, materializedAttachments = [], op
10110
10295
  attachmentsText,
10111
10296
  comments,
10112
10297
  context,
10113
- nativeSession: asRecord(payload.nativeSession)
10298
+ nativeSession: asRecord(payload.nativeSession),
10299
+ wikiAccess: {
10300
+ tools: context.wikiToolsAvailable === true,
10301
+ treePath: wikiTreePathForCommand(command, options.workspaceBindings)
10302
+ }
10114
10303
  });
10115
10304
  }
10116
10305
  function companyPiHomeRoot(baseEnv) {
@@ -12858,7 +13047,8 @@ async function executeRunCommand(config, command) {
12858
13047
  const promptCompilation = buildCommandPrompt(command, workspace, materializedAttachments, {
12859
13048
  executorKind: executor.kind,
12860
13049
  managedMcpToolMode: executor.kind === "pi" && Object.keys(governedMcp).length > 0 ? MANAGED_PI_MCP_TOOL_MODE : null,
12861
- artifactVerifierCommands: config.artifactVerifierCommands
13050
+ artifactVerifierCommands: config.artifactVerifierCommands,
13051
+ workspaceBindings: config.workspaceBindings
12862
13052
  });
12863
13053
  const nativeSessionRequest = asRecord(asRecord(command.payload).nativeSession);
12864
13054
  const prompt = promptCompilation.prompt;
@@ -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.53";
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.53",
3
+ "version": "0.1.0-beta.54",
4
4
  "description": "MirrorX runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",