@tomismeta/paperclip-aperture 0.2.0 → 0.2.2

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/dist/worker.js CHANGED
@@ -6378,7 +6378,9 @@ var paperclipConfigSchema = external_exports.object({
6378
6378
  }
6379
6379
  });
6380
6380
 
6381
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/frame-score.js
6381
+ // node_modules/.pnpm/@tomismeta+aperture-core@0.4.0/node_modules/@tomismeta/aperture-core/public-dist/index.js
6382
+ import { join, dirname } from "path";
6383
+ import { readFile, mkdir, writeFile, rename } from "fs/promises";
6382
6384
  function scoreCandidate(candidate) {
6383
6385
  return priorityWeight(candidate.priority) * 100 + consequenceWeight(candidate.consequence) * 10 + toneWeight(candidate.tone) + (candidate.blocking ? 1e3 : 0) + (candidate.attentionScoreOffset ?? 0);
6384
6386
  }
@@ -6484,8 +6486,6 @@ function ageProfile(frame) {
6484
6486
  maxPenalty: 18
6485
6487
  };
6486
6488
  }
6487
-
6488
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-view.js
6489
6489
  function buildAttentionView(taskViews, options = {}) {
6490
6490
  let interruptive = [];
6491
6491
  let ambient = [];
@@ -6578,8 +6578,6 @@ function latestTimestamp(frames) {
6578
6578
  }
6579
6579
  return latest;
6580
6580
  }
6581
-
6582
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-state.js
6583
6581
  function deriveAttentionState(summary) {
6584
6582
  const enoughPresentedForPattern = summary.counts.presented >= 5;
6585
6583
  const enoughObservedForPressure = summary.counts.presented + summary.counts.deferred >= 5;
@@ -6597,8 +6595,6 @@ function deriveAttentionState(summary) {
6597
6595
  }
6598
6596
  return "monitoring";
6599
6597
  }
6600
-
6601
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-trends.js
6602
6598
  function deriveAttentionTrends(summary) {
6603
6599
  const trends = [];
6604
6600
  if (summary.counts.contextExpanded >= 1 && summary.counts.responded >= 1) {
@@ -6615,8 +6611,6 @@ function deriveAttentionTrends(summary) {
6615
6611
  }
6616
6612
  return trends;
6617
6613
  }
6618
-
6619
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-adjustments.js
6620
6614
  var AttentionAdjustments = class {
6621
6615
  apply(candidate, taskSummary, globalSummary = taskSummary) {
6622
6616
  const attentionScoreOffset = this.scoreOffset(candidate, taskSummary, globalSummary);
@@ -6718,8 +6712,6 @@ var AttentionAdjustments = class {
6718
6712
  return reasons;
6719
6713
  }
6720
6714
  };
6721
-
6722
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/judgment-defaults.js
6723
6715
  var APERTURE_STATE_SCHEMA_VERSION = 1;
6724
6716
  var MARKDOWN_SCHEMA_VERSION = APERTURE_STATE_SCHEMA_VERSION;
6725
6717
  var JUDGMENT_DEFAULTS = {
@@ -6813,8 +6805,6 @@ var JUDGMENT_DEFAULTS = {
6813
6805
  actionableThreshold: 4
6814
6806
  }
6815
6807
  };
6816
-
6817
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-burden.js
6818
6808
  function deriveAttentionBurden(summary, pressure, attentionState, operatorPresence = "present", now) {
6819
6809
  if (operatorPresence === "absent") {
6820
6810
  return idleAttentionBurden();
@@ -6923,8 +6913,6 @@ function idleAttentionBurden() {
6923
6913
  reasons: []
6924
6914
  };
6925
6915
  }
6926
-
6927
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-pressure.js
6928
6916
  function forecastAttentionPressure(summary, attentionView, now) {
6929
6917
  const interruptiveVisible = countInterruptiveVisible(attentionView);
6930
6918
  const reasons = [];
@@ -7032,8 +7020,6 @@ function countInterruptiveVisible(attentionView) {
7032
7020
  function isInterruptive(frame) {
7033
7021
  return frame.mode !== "status" || frame.consequence === "high" || frame.tone === "critical";
7034
7022
  }
7035
-
7036
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/surface-capabilities.js
7037
7023
  var baseAttentionSurfaceCapabilities = {
7038
7024
  topology: {
7039
7025
  supportsAmbient: true
@@ -7045,8 +7031,6 @@ var baseAttentionSurfaceCapabilities = {
7045
7031
  supportsTextResponse: false
7046
7032
  }
7047
7033
  };
7048
-
7049
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-evidence.js
7050
7034
  function createAttentionEvidenceContext(input = {}) {
7051
7035
  return {
7052
7036
  currentFrame: input.currentFrame ?? null,
@@ -7069,31 +7053,53 @@ function createAttentionEvidenceContext(input = {}) {
7069
7053
  operatorPresence: input.operatorPresence ?? "present"
7070
7054
  };
7071
7055
  }
7072
- function resolveAttentionEvidenceContext(currentFrame, input = {}) {
7073
- if (isAttentionEvidenceContext(input)) {
7074
- if (input.currentFrame === currentFrame) {
7075
- return input;
7056
+ function buildAttentionEvidenceInput(input = {}) {
7057
+ return {
7058
+ ...input.currentFrame !== void 0 ? { currentFrame: input.currentFrame } : {},
7059
+ ...input.currentTaskView !== void 0 ? { currentTaskView: input.currentTaskView } : {},
7060
+ ...input.currentEpisode !== void 0 ? { currentEpisode: input.currentEpisode } : {},
7061
+ ...input.attentionView !== void 0 ? { attentionView: input.attentionView } : {},
7062
+ ...input.taskSignalSummary !== void 0 ? { taskSignalSummary: input.taskSignalSummary } : {},
7063
+ ...input.globalSignalSummary !== void 0 ? { globalSignalSummary: input.globalSignalSummary } : {},
7064
+ ...input.taskAttentionState !== void 0 ? { taskAttentionState: input.taskAttentionState } : {},
7065
+ ...input.globalAttentionState !== void 0 ? { globalAttentionState: input.globalAttentionState } : {},
7066
+ ...input.pressureForecast !== void 0 ? { pressureForecast: input.pressureForecast } : {},
7067
+ ...input.attentionBurden !== void 0 ? { attentionBurden: input.attentionBurden } : {},
7068
+ ...input.surfaceCapabilities !== void 0 ? { surfaceCapabilities: input.surfaceCapabilities } : {},
7069
+ ...input.operatorPresence !== void 0 ? { operatorPresence: input.operatorPresence } : {}
7070
+ };
7071
+ }
7072
+ function resolveAttentionEvidenceContext(currentFrame, input = {}, referenceTimeMs) {
7073
+ const evidenceInput = buildAttentionEvidenceInput(input);
7074
+ if (isAttentionEvidenceContext(evidenceInput)) {
7075
+ if (evidenceInput.currentFrame === currentFrame) {
7076
+ return evidenceInput;
7076
7077
  }
7077
7078
  return createAttentionEvidenceContext({
7078
- ...input,
7079
+ ...evidenceInput,
7079
7080
  currentFrame
7080
7081
  });
7081
7082
  }
7082
- const globalSignalSummary = input.globalSignalSummary ?? emptyAttentionSignalSummary();
7083
- const now = Date.now();
7084
- const pressureForecast = input.pressureForecast ?? forecastAttentionPressure(globalSignalSummary, input.attentionView, now);
7085
- const operatorPresence = input.operatorPresence ?? "present";
7083
+ const globalSignalSummary = evidenceInput.globalSignalSummary ?? emptyAttentionSignalSummary();
7084
+ const pressureForecast = evidenceInput.pressureForecast ?? forecastAttentionPressure(globalSignalSummary, evidenceInput.attentionView, referenceTimeMs);
7085
+ const operatorPresence = evidenceInput.operatorPresence ?? "present";
7086
7086
  return createAttentionEvidenceContext({
7087
- ...input,
7087
+ ...evidenceInput,
7088
7088
  currentFrame,
7089
7089
  globalSignalSummary,
7090
7090
  pressureForecast,
7091
- attentionBurden: input.attentionBurden ?? deriveAttentionBurden(globalSignalSummary, pressureForecast, input.globalAttentionState, operatorPresence, now),
7091
+ attentionBurden: evidenceInput.attentionBurden ?? deriveAttentionBurden(
7092
+ globalSignalSummary,
7093
+ pressureForecast,
7094
+ evidenceInput.globalAttentionState,
7095
+ operatorPresence,
7096
+ referenceTimeMs
7097
+ ),
7092
7098
  operatorPresence
7093
7099
  });
7094
7100
  }
7095
7101
  function isAttentionEvidenceContext(input) {
7096
- return "currentFrame" in input && "currentTaskView" in input && "currentEpisode" in input && "attentionView" in input && "taskSignalSummary" in input && "globalSignalSummary" in input && "taskAttentionState" in input && "globalAttentionState" in input && "pressureForecast" in input && "attentionBurden" in input && "surfaceCapabilities" in input && "operatorPresence" in input && input.attentionView !== void 0 && input.taskSignalSummary !== void 0 && input.globalSignalSummary !== void 0 && input.taskAttentionState !== void 0 && input.globalAttentionState !== void 0 && input.pressureForecast !== void 0 && input.attentionBurden !== void 0 && input.surfaceCapabilities !== void 0 && input.operatorPresence !== void 0;
7102
+ return "currentFrame" in input && "currentTaskView" in input && "currentEpisode" in input && "attentionView" in input && "taskSignalSummary" in input && "globalSignalSummary" in input && "taskAttentionState" in input && "globalAttentionState" in input && "pressureForecast" in input && "attentionBurden" in input && "surfaceCapabilities" in input && "operatorPresence" in input && input.currentFrame !== void 0 && input.currentTaskView !== void 0 && input.currentEpisode !== void 0 && input.attentionView !== void 0 && input.taskSignalSummary !== void 0 && input.globalSignalSummary !== void 0 && input.taskAttentionState !== void 0 && input.globalAttentionState !== void 0 && input.pressureForecast !== void 0 && input.attentionBurden !== void 0 && input.surfaceCapabilities !== void 0 && input.operatorPresence !== void 0;
7097
7103
  }
7098
7104
  function emptyTaskView() {
7099
7105
  return {
@@ -7137,17 +7143,15 @@ function emptyAttentionSignalSummary() {
7137
7143
  lastSignalAt: null
7138
7144
  };
7139
7145
  }
7140
-
7141
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/semantic-relations.js
7142
7146
  function hasSemanticRelationKind(relationHints, kind) {
7143
7147
  return (relationHints ?? []).some((hint) => hint.kind === kind);
7144
7148
  }
7145
7149
  function readSemanticRelationTarget(relationHints) {
7146
- const targetHint = (relationHints ?? []).find((hint) => typeof hint.target === "string" && hint.target.length > 0);
7150
+ const targetHint = (relationHints ?? []).find(
7151
+ (hint) => typeof hint.target === "string" && hint.target.length > 0
7152
+ );
7147
7153
  return targetHint?.target ?? null;
7148
7154
  }
7149
-
7150
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/episode-tracker.js
7151
7155
  var DEFAULTS = JUDGMENT_DEFAULTS.episodeEvidence;
7152
7156
  var EpisodeTracker = class {
7153
7157
  byKey = /* @__PURE__ */ new Map();
@@ -7367,8 +7371,73 @@ function readStringList(value, key) {
7367
7371
  }
7368
7372
  return candidate.filter((entry) => typeof entry === "string" && entry.length > 0);
7369
7373
  }
7370
-
7371
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/semantic-detection.js
7374
+ function semanticIntentFrameForRequestKind(kind) {
7375
+ switch (kind) {
7376
+ case "approval":
7377
+ return "approval_request";
7378
+ case "choice":
7379
+ return "question_request";
7380
+ case "form":
7381
+ return "form_request";
7382
+ }
7383
+ }
7384
+ function semanticActivityClassForRequestKind(kind) {
7385
+ switch (kind) {
7386
+ case "approval":
7387
+ return "permission_request";
7388
+ case "choice":
7389
+ case "form":
7390
+ return "question_request";
7391
+ }
7392
+ }
7393
+ function semanticWhyNowForRequestKind(kind, consequence) {
7394
+ switch (kind) {
7395
+ case "approval":
7396
+ return consequence === "high" ? "A high-risk action needs explicit operator approval." : "Approval is required before work can continue.";
7397
+ case "choice":
7398
+ return "A decision is required before work can continue.";
7399
+ case "form":
7400
+ return "Additional input is required before work can continue.";
7401
+ }
7402
+ }
7403
+ function semanticWhyNowForTaskStatus(status, options) {
7404
+ if (options?.wasCancelled) {
7405
+ return "Work was cancelled and may need review.";
7406
+ }
7407
+ switch (status) {
7408
+ case "failed":
7409
+ return "Work has failed and should be reviewed.";
7410
+ case "blocked":
7411
+ return "Work is blocked and may require operator attention.";
7412
+ case "running":
7413
+ case "waiting":
7414
+ case "completed":
7415
+ return options?.impliedAsk ? "Status text implies the operator may need to respond." : void 0;
7416
+ }
7417
+ }
7418
+ function semanticReasonsForTaskStatus(status, options) {
7419
+ if (options?.wasCancelled) {
7420
+ return ["task cancellation is an explicit lifecycle fact"];
7421
+ }
7422
+ switch (status) {
7423
+ case "failed":
7424
+ return ["task status explicitly indicates failure"];
7425
+ case "blocked":
7426
+ return ["task status explicitly indicates blocked work"];
7427
+ case "running":
7428
+ case "waiting":
7429
+ case "completed":
7430
+ return options?.impliedAsk ? ["status wording suggests an implied operator request"] : ["task update carries a non-blocking lifecycle status"];
7431
+ }
7432
+ }
7433
+ function semanticReasonsForLifecycle(type) {
7434
+ switch (type) {
7435
+ case "task_started":
7436
+ return ["task start is an explicit lifecycle fact"];
7437
+ case "completion":
7438
+ return ["task completion is an explicit lifecycle fact"];
7439
+ }
7440
+ }
7372
7441
  function normalizeSemanticText(value) {
7373
7442
  return value.toLowerCase().replace(/[^a-z0-9/.-]+/g, " ").trim();
7374
7443
  }
@@ -7384,18 +7453,12 @@ function inferSemanticToolFamily(input) {
7384
7453
  return explicit;
7385
7454
  }
7386
7455
  const value = normalizeSemanticText(`${input.title} ${input.summary ?? ""}`);
7387
- if (hasPhrase(value, "wants to read") || hasPhrase(value, "wants to inspect") || hasWord(value, "read") || hasWord(value, "inspect"))
7388
- return "read";
7389
- if (hasPhrase(value, "wants to write") || hasWord(value, "write"))
7390
- return "write";
7391
- if (hasPhrase(value, "wants to edit") || hasWord(value, "edit"))
7392
- return "edit";
7393
- if (hasPhrase(value, "shell command") || hasPhrase(value, "wants to run"))
7394
- return "bash";
7395
- if (hasPhrase(value, "search the web"))
7396
- return "web";
7397
- if (hasPhrase(value, "search files") || hasPhrase(value, "search file contents"))
7398
- return "search";
7456
+ if (hasPhrase(value, "wants to read") || hasPhrase(value, "wants to inspect") || hasWord(value, "read") || hasWord(value, "inspect")) return "read";
7457
+ if (hasPhrase(value, "wants to write") || hasWord(value, "write")) return "write";
7458
+ if (hasPhrase(value, "wants to edit") || hasWord(value, "edit")) return "edit";
7459
+ if (hasPhrase(value, "shell command") || hasPhrase(value, "wants to run")) return "bash";
7460
+ if (hasPhrase(value, "search the web")) return "web";
7461
+ if (hasPhrase(value, "search files") || hasPhrase(value, "search file contents")) return "search";
7399
7462
  return null;
7400
7463
  }
7401
7464
  function detectImpliedOperatorAsk(text) {
@@ -7578,77 +7641,24 @@ function dedupeRelationHints(hints) {
7578
7641
  }
7579
7642
  return result;
7580
7643
  }
7581
-
7582
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/semantic-language.js
7583
- function semanticIntentFrameForRequestKind(kind) {
7584
- switch (kind) {
7585
- case "approval":
7586
- return "approval_request";
7587
- case "choice":
7588
- return "question_request";
7589
- case "form":
7590
- return "form_request";
7591
- }
7592
- }
7593
- function semanticActivityClassForRequestKind(kind) {
7594
- switch (kind) {
7595
- case "approval":
7596
- return "permission_request";
7597
- case "choice":
7598
- case "form":
7599
- return "question_request";
7600
- }
7601
- }
7602
- function semanticWhyNowForRequestKind(kind, consequence) {
7603
- switch (kind) {
7604
- case "approval":
7605
- return consequence === "high" ? "A high-risk action needs explicit operator approval." : "Approval is required before work can continue.";
7606
- case "choice":
7607
- return "A decision is required before work can continue.";
7608
- case "form":
7609
- return "Additional input is required before work can continue.";
7610
- }
7611
- }
7612
- function semanticWhyNowForTaskStatus(status, options) {
7613
- if (options?.wasCancelled) {
7614
- return "Work was cancelled and may need review.";
7615
- }
7616
- switch (status) {
7617
- case "failed":
7618
- return "Work has failed and should be reviewed.";
7619
- case "blocked":
7620
- return "Work is blocked and may require operator attention.";
7621
- case "running":
7622
- case "waiting":
7623
- case "completed":
7624
- return options?.impliedAsk ? "Status text implies the operator may need to respond." : void 0;
7625
- }
7626
- }
7627
- function semanticReasonsForTaskStatus(status, options) {
7628
- if (options?.wasCancelled) {
7629
- return ["task cancellation is an explicit lifecycle fact"];
7630
- }
7631
- switch (status) {
7632
- case "failed":
7633
- return ["task status explicitly indicates failure"];
7634
- case "blocked":
7635
- return ["task status explicitly indicates blocked work"];
7636
- case "running":
7637
- case "waiting":
7638
- case "completed":
7639
- return options?.impliedAsk ? ["status wording suggests an implied operator request"] : ["task update carries a non-blocking lifecycle status"];
7640
- }
7641
- }
7642
- function semanticReasonsForLifecycle(type) {
7643
- switch (type) {
7644
- case "task_started":
7645
- return ["task start is an explicit lifecycle fact"];
7646
- case "completion":
7647
- return ["task completion is an explicit lifecycle fact"];
7644
+ function mergeSemanticProvenance(input = {}) {
7645
+ const base = input.base;
7646
+ const semantic = input.semantic;
7647
+ const whyNow = base?.whyNow ?? semantic?.whyNow ?? input.fallbackWhyNow;
7648
+ const factors = dedupeSemanticStrings([
7649
+ ...base?.factors ?? [],
7650
+ ...semantic?.factors ?? [],
7651
+ ...input.extraFactors ?? []
7652
+ ]);
7653
+ if (base === void 0 && whyNow === void 0 && factors.length === 0) {
7654
+ return void 0;
7648
7655
  }
7656
+ return {
7657
+ ...base ?? {},
7658
+ ...whyNow !== void 0 ? { whyNow } : {},
7659
+ ...factors.length > 0 ? { factors } : {}
7660
+ };
7649
7661
  }
7650
-
7651
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/event-evaluator.js
7652
7662
  var EventEvaluator = class {
7653
7663
  evaluate(event) {
7654
7664
  switch (event.type) {
@@ -7667,7 +7677,8 @@ var EventEvaluator = class {
7667
7677
  priority: "background",
7668
7678
  blocking: false,
7669
7679
  timestamp: event.timestamp,
7670
- ...event.summary !== void 0 ? { summary: event.summary } : {}
7680
+ ...event.summary !== void 0 ? { summary: event.summary } : {},
7681
+ ...buildSemanticUncertainty(event.semantic)
7671
7682
  }
7672
7683
  };
7673
7684
  case "task.updated":
@@ -7709,6 +7720,7 @@ var EventEvaluator = class {
7709
7720
  timestamp: event.timestamp,
7710
7721
  ...event.summary !== void 0 ? { summary: event.summary } : {},
7711
7722
  ...event.semantic?.relationHints?.length ? { relationHints: event.semantic.relationHints } : {},
7723
+ ...buildSemanticUncertainty(event.semantic),
7712
7724
  ...event.progress !== void 0 ? {
7713
7725
  context: {
7714
7726
  progress: event.progress
@@ -7732,18 +7744,19 @@ var EventEvaluator = class {
7732
7744
  title: event.title,
7733
7745
  summary: event.summary,
7734
7746
  ...event.semantic?.relationHints?.length ? { relationHints: event.semantic.relationHints } : {},
7747
+ ...buildSemanticUncertainty(event.semantic),
7735
7748
  responseSpec,
7736
7749
  priority: this.priorityForHumanInput(event),
7737
7750
  blocking: true,
7738
7751
  timestamp: event.timestamp,
7739
7752
  ...event.context !== void 0 ? { context: event.context } : {},
7740
- ...event.provenance !== void 0 || event.semantic?.whyNow !== void 0 || event.semantic?.factors?.length ? {
7741
- provenance: {
7742
- ...event.provenance ?? {},
7743
- ...event.provenance?.whyNow === void 0 && event.semantic?.whyNow !== void 0 ? { whyNow: event.semantic.whyNow } : {},
7744
- ...event.semantic?.factors?.length ? { factors: dedupeSemanticStrings([...event.provenance?.factors ?? [], ...event.semantic.factors]) } : {}
7745
- }
7746
- } : {}
7753
+ ...(() => {
7754
+ const provenance = mergeSemanticProvenance({
7755
+ base: event.provenance,
7756
+ semantic: event.semantic
7757
+ });
7758
+ return provenance !== void 0 ? { provenance } : {};
7759
+ })()
7747
7760
  };
7748
7761
  }
7749
7762
  priorityForHumanInput(event) {
@@ -7853,23 +7866,27 @@ var EventEvaluator = class {
7853
7866
  }
7854
7867
  };
7855
7868
  function buildStatusProvenance(event) {
7856
- const whyNow = event.semantic?.whyNow ?? (event.status === "blocked" ? semanticWhyNowForTaskStatus("blocked") : event.status === "failed" ? semanticWhyNowForTaskStatus("failed") : void 0);
7857
- const factors = dedupeSemanticStrings([
7858
- ...event.semantic?.factors ?? [],
7859
- ...event.status === "blocked" || event.status === "failed" ? [event.status] : []
7860
- ]);
7861
- if (whyNow === void 0 && factors.length === 0) {
7869
+ const provenance = mergeSemanticProvenance({
7870
+ semantic: event.semantic,
7871
+ fallbackWhyNow: event.status === "blocked" ? semanticWhyNowForTaskStatus("blocked") : event.status === "failed" ? semanticWhyNowForTaskStatus("failed") : void 0,
7872
+ extraFactors: event.status === "blocked" || event.status === "failed" ? [event.status] : []
7873
+ });
7874
+ if (provenance === void 0) {
7862
7875
  return {};
7863
7876
  }
7864
7877
  return {
7865
- provenance: {
7866
- ...whyNow !== void 0 ? { whyNow } : {},
7867
- ...factors.length > 0 ? { factors } : {}
7868
- }
7878
+ provenance
7879
+ };
7880
+ }
7881
+ function buildSemanticUncertainty(semantic) {
7882
+ if (!semantic) {
7883
+ return {};
7884
+ }
7885
+ return {
7886
+ semanticConfidence: semantic.confidence,
7887
+ ...semantic.abstained === true ? { semanticAbstained: true } : {}
7869
7888
  };
7870
7889
  }
7871
-
7872
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/frame-planner.js
7873
7890
  var FramePlanner = class {
7874
7891
  plan(candidate, current) {
7875
7892
  const isUpdate = current?.interactionId === candidate.interactionId;
@@ -7926,8 +7943,6 @@ var FramePlanner = class {
7926
7943
  };
7927
7944
  }
7928
7945
  };
7929
-
7930
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/policy-gate-rule.js
7931
7946
  function noopPolicyGateRule(rule, rationale = []) {
7932
7947
  return {
7933
7948
  rule,
@@ -7943,38 +7958,38 @@ function verdictPolicyGateRule(rule, verdict, rationale = verdict.rationale) {
7943
7958
  rationale
7944
7959
  };
7945
7960
  }
7946
-
7947
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/background-policy-gate-rule.js
7948
7961
  var evaluateBackgroundPolicyGateRule = (input) => {
7949
7962
  if (input.candidate.priority !== "background") {
7950
7963
  return noopPolicyGateRule("background");
7951
7964
  }
7952
- return verdictPolicyGateRule("background", {
7953
- autoApprove: false,
7954
- mayInterrupt: false,
7955
- requiresOperatorResponse: false,
7956
- minimumPresentation: "ambient",
7957
- minimumPresentationIsSticky: true,
7958
- rationale: ["background work should remain peripheral by default"]
7959
- });
7965
+ return verdictPolicyGateRule(
7966
+ "background",
7967
+ {
7968
+ autoApprove: false,
7969
+ mayInterrupt: false,
7970
+ requiresOperatorResponse: false,
7971
+ minimumPresentation: "ambient",
7972
+ minimumPresentationIsSticky: true,
7973
+ rationale: ["background work should remain peripheral by default"]
7974
+ }
7975
+ );
7960
7976
  };
7961
-
7962
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/blocking-policy-gate-rule.js
7963
7977
  var evaluateBlockingPolicyGateRule = (input) => {
7964
7978
  if (!input.candidate.blocking) {
7965
7979
  return noopPolicyGateRule("blocking");
7966
7980
  }
7967
- return verdictPolicyGateRule("blocking", {
7968
- autoApprove: false,
7969
- mayInterrupt: true,
7970
- requiresOperatorResponse: true,
7971
- minimumPresentation: "active",
7972
- minimumPresentationIsSticky: false,
7973
- rationale: ["blocking interactions require explicit operator attention"]
7974
- });
7981
+ return verdictPolicyGateRule(
7982
+ "blocking",
7983
+ {
7984
+ autoApprove: false,
7985
+ mayInterrupt: true,
7986
+ requiresOperatorResponse: true,
7987
+ minimumPresentation: "active",
7988
+ minimumPresentationIsSticky: false,
7989
+ rationale: ["blocking interactions require explicit operator attention"]
7990
+ }
7991
+ );
7975
7992
  };
7976
-
7977
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/interaction-taxonomy.js
7978
7993
  function readExplicitToolFamily(input) {
7979
7994
  return readExplicitSemanticToolFamily(input);
7980
7995
  }
@@ -7999,8 +8014,6 @@ function sourceKey(source) {
7999
8014
  }
8000
8015
  return source.kind ?? source.id;
8001
8016
  }
8002
-
8003
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/configured-policy-support.js
8004
8017
  function matchPolicyRule(judgmentConfig, candidate) {
8005
8018
  const policy = judgmentConfig?.policy;
8006
8019
  if (!policy) {
@@ -8082,8 +8095,6 @@ function isToolPolicyActivity(activityClass) {
8082
8095
  }
8083
8096
  }
8084
8097
  }
8085
-
8086
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/configured-policy-gate-rule.js
8087
8098
  var evaluateConfiguredPolicyGateRule = (input) => {
8088
8099
  const { candidate, judgmentConfig, userProfile } = input;
8089
8100
  const toolFamily = inferConfiguredPolicyToolFamily(candidate);
@@ -8106,47 +8117,55 @@ var evaluateConfiguredPolicyGateRule = (input) => {
8106
8117
  }
8107
8118
  if (autoApprove) {
8108
8119
  rationale.push("configured judgment policy auto-approves this bounded approval");
8109
- return verdictPolicyGateRule("configured_policy", {
8110
- autoApprove: true,
8111
- mayInterrupt: false,
8112
- requiresOperatorResponse: false,
8113
- minimumPresentation: "ambient",
8114
- minimumPresentationIsSticky: true,
8115
- rationale
8116
- });
8120
+ return verdictPolicyGateRule(
8121
+ "configured_policy",
8122
+ {
8123
+ autoApprove: true,
8124
+ mayInterrupt: false,
8125
+ requiresOperatorResponse: false,
8126
+ minimumPresentation: "ambient",
8127
+ minimumPresentationIsSticky: true,
8128
+ rationale
8129
+ }
8130
+ );
8117
8131
  }
8118
8132
  if (requiresOperatorResponse) {
8119
8133
  rationale.push("operator-response work cannot remain passive without auto-resolution");
8120
- return verdictPolicyGateRule("configured_policy", {
8134
+ return verdictPolicyGateRule(
8135
+ "configured_policy",
8136
+ {
8137
+ autoApprove: false,
8138
+ mayInterrupt: true,
8139
+ requiresOperatorResponse: true,
8140
+ minimumPresentation: "active",
8141
+ minimumPresentationIsSticky: false,
8142
+ rationale
8143
+ }
8144
+ );
8145
+ }
8146
+ return verdictPolicyGateRule(
8147
+ "configured_policy",
8148
+ {
8121
8149
  autoApprove: false,
8122
- mayInterrupt: true,
8123
- requiresOperatorResponse: true,
8124
- minimumPresentation: "active",
8125
- minimumPresentationIsSticky: false,
8150
+ mayInterrupt: mayInterrupt ?? false,
8151
+ requiresOperatorResponse,
8152
+ minimumPresentation: minimumPresentation ?? (candidate.blocking ? "active" : "queue"),
8153
+ minimumPresentationIsSticky: minimumPresentation !== void 0 || mayInterrupt === false,
8126
8154
  rationale
8127
- });
8128
- }
8129
- return verdictPolicyGateRule("configured_policy", {
8130
- autoApprove: false,
8131
- mayInterrupt: mayInterrupt ?? false,
8132
- requiresOperatorResponse,
8133
- minimumPresentation: minimumPresentation ?? (candidate.blocking ? "active" : "queue"),
8134
- minimumPresentationIsSticky: minimumPresentation !== void 0 || mayInterrupt === false,
8135
- rationale
8136
- });
8155
+ }
8156
+ );
8137
8157
  };
8138
-
8139
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/interruptive-default-policy-gate-rule.js
8140
- var evaluateInterruptiveDefaultPolicyGateRule = () => verdictPolicyGateRule("interruptive_default", {
8141
- autoApprove: false,
8142
- mayInterrupt: true,
8143
- requiresOperatorResponse: false,
8144
- minimumPresentation: "queue",
8145
- minimumPresentationIsSticky: false,
8146
- rationale: ["urgent non-blocking work may compete for interruptive attention"]
8147
- });
8148
-
8149
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/policy-criterion-rule.js
8158
+ var evaluateInterruptiveDefaultPolicyGateRule = () => verdictPolicyGateRule(
8159
+ "interruptive_default",
8160
+ {
8161
+ autoApprove: false,
8162
+ mayInterrupt: true,
8163
+ requiresOperatorResponse: false,
8164
+ minimumPresentation: "queue",
8165
+ minimumPresentationIsSticky: false,
8166
+ rationale: ["urgent non-blocking work may compete for interruptive attention"]
8167
+ }
8168
+ );
8150
8169
  function noopPolicyCriterionRule(rule, rationale = []) {
8151
8170
  return {
8152
8171
  rule,
@@ -8194,28 +8213,43 @@ function ambiguousPeripheralCriterionVerdict(criterion, peripheralResolution, am
8194
8213
  rationale
8195
8214
  };
8196
8215
  }
8197
-
8198
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/attention-budget-criterion-rule.js
8199
8216
  var evaluateAttentionBudgetCriterionRule = (input) => {
8200
8217
  const { evidence, criterion } = input;
8201
8218
  const thresholdOffset = evidence.attentionBurden.thresholdOffset;
8202
8219
  if (thresholdOffset <= 0) {
8203
8220
  return noopPolicyCriterionRule("attention_budget");
8204
8221
  }
8205
- return adjustCriterionRule("attention_budget", {
8206
- activationThreshold: criterion.activationThreshold + thresholdOffset,
8207
- promotionMargin: criterion.promotionMargin + thresholdOffset
8208
- }, ["sustained attention burden raises the interrupt bar until the operator load eases"]);
8222
+ return adjustCriterionRule(
8223
+ "attention_budget",
8224
+ {
8225
+ activationThreshold: criterion.activationThreshold + thresholdOffset,
8226
+ promotionMargin: criterion.promotionMargin + thresholdOffset
8227
+ },
8228
+ ["sustained attention burden raises the interrupt bar until the operator load eases"]
8229
+ );
8209
8230
  };
8210
-
8211
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/interrupt-eligibility-criterion-rule.js
8212
8231
  var evaluateInterruptEligibilityCriterionRule = (input) => {
8213
- const { candidate, policyVerdict, criterion, peripheralResolution, evidence } = input;
8232
+ const {
8233
+ candidate,
8234
+ policyVerdict,
8235
+ criterion,
8236
+ peripheralResolution,
8237
+ evidence
8238
+ } = input;
8214
8239
  if (!policyVerdict.mayInterrupt && policyVerdict.minimumPresentationIsSticky) {
8215
- return verdictPolicyCriterionRule("interrupt_eligibility", preservedPeripheralCriterionVerdict(criterion, readPreservedPeripheralResolution(candidate, peripheralResolution, evidence.surfaceCapabilities)));
8240
+ return verdictPolicyCriterionRule(
8241
+ "interrupt_eligibility",
8242
+ preservedPeripheralCriterionVerdict(
8243
+ criterion,
8244
+ readPreservedPeripheralResolution(candidate, peripheralResolution, evidence.surfaceCapabilities)
8245
+ )
8246
+ );
8216
8247
  }
8217
8248
  if (candidate.blocking || candidate.episodeState === "actionable" || policyVerdict.autoApprove || policyVerdict.requiresOperatorResponse || policyVerdict.minimumPresentation === "active") {
8218
- return verdictPolicyCriterionRule("interrupt_eligibility", clearCriterionVerdict(criterion));
8249
+ return verdictPolicyCriterionRule(
8250
+ "interrupt_eligibility",
8251
+ clearCriterionVerdict(criterion)
8252
+ );
8219
8253
  }
8220
8254
  return noopPolicyCriterionRule("interrupt_eligibility");
8221
8255
  };
@@ -8234,10 +8268,14 @@ function readPreservedPeripheralResolution(candidate, peripheralResolution, surf
8234
8268
  return surfaceCapabilities.responses.supportsForm ? "ambient" : "queue";
8235
8269
  }
8236
8270
  }
8237
-
8238
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/no-active-frame-criterion-rule.js
8239
8271
  var evaluateNoActiveFrameCriterionRule = (input) => {
8240
- const { candidate, evidence, candidateScore, criterion, peripheralResolution } = input;
8272
+ const {
8273
+ candidate,
8274
+ evidence,
8275
+ candidateScore,
8276
+ criterion,
8277
+ peripheralResolution
8278
+ } = input;
8241
8279
  if (evidence.currentFrame) {
8242
8280
  return noopPolicyCriterionRule("no_active_frame");
8243
8281
  }
@@ -8249,62 +8287,134 @@ var evaluateNoActiveFrameCriterionRule = (input) => {
8249
8287
  return noopPolicyCriterionRule("no_active_frame");
8250
8288
  }
8251
8289
  if (candidateScore >= criterion.activationThreshold) {
8252
- return verdictPolicyCriterionRule("no_active_frame", clearCriterionVerdict(criterion));
8253
- }
8254
- return verdictPolicyCriterionRule("no_active_frame", ambiguousPeripheralCriterionVerdict(criterion, peripheralResolution, {
8255
- kind: "interrupt",
8256
- reason: "low_signal",
8257
- resolution: peripheralResolution
8258
- }, ["uncertain interruptive work stays peripheral until its signal is stronger"]));
8290
+ return verdictPolicyCriterionRule(
8291
+ "no_active_frame",
8292
+ clearCriterionVerdict(criterion)
8293
+ );
8294
+ }
8295
+ return verdictPolicyCriterionRule(
8296
+ "no_active_frame",
8297
+ ambiguousPeripheralCriterionVerdict(
8298
+ criterion,
8299
+ peripheralResolution,
8300
+ {
8301
+ kind: "interrupt",
8302
+ reason: "low_signal",
8303
+ resolution: peripheralResolution
8304
+ },
8305
+ ["uncertain interruptive work stays peripheral until its signal is stronger"]
8306
+ )
8307
+ );
8259
8308
  };
8260
-
8261
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/operator-absence-criterion-rule.js
8262
8309
  var evaluateOperatorAbsenceCriterionRule = (input) => {
8263
8310
  const { evidence, criterion, peripheralResolution } = input;
8264
8311
  if (evidence.operatorPresence !== "absent") {
8265
8312
  return noopPolicyCriterionRule("operator_absence");
8266
8313
  }
8267
- return verdictPolicyCriterionRule("operator_absence", {
8268
- criterion,
8269
- peripheralResolution,
8270
- ambiguity: null,
8271
- rationale: ["operator absence keeps interruptive work peripheral until active attention returns"]
8272
- });
8314
+ return verdictPolicyCriterionRule(
8315
+ "operator_absence",
8316
+ {
8317
+ criterion,
8318
+ peripheralResolution,
8319
+ ambiguity: null,
8320
+ rationale: ["operator absence keeps interruptive work peripheral until active attention returns"]
8321
+ }
8322
+ );
8273
8323
  };
8274
-
8275
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/peripheral-status-policy-gate-rule.js
8276
8324
  var evaluatePeripheralStatusPolicyGateRule = (input) => {
8277
8325
  const { candidate } = input;
8278
8326
  if (candidate.mode !== "status" || candidate.consequence === "high" || candidate.tone === "critical") {
8279
8327
  return noopPolicyGateRule("peripheral_status");
8280
8328
  }
8281
- return verdictPolicyGateRule("peripheral_status", {
8282
- autoApprove: false,
8283
- mayInterrupt: false,
8284
- requiresOperatorResponse: false,
8285
- minimumPresentation: "ambient",
8286
- minimumPresentationIsSticky: false,
8287
- rationale: ["non-critical status work should start in the periphery"]
8288
- });
8289
- };
8290
-
8291
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/small-score-gap-criterion-rule.js
8292
- var evaluateSmallScoreGapCriterionRule = (input) => {
8293
- const { candidateScore, currentScore, criterion, peripheralResolution } = input;
8294
- if (currentScore === null || candidateScore <= currentScore) {
8295
- return verdictPolicyCriterionRule("small_score_gap", clearCriterionVerdict(criterion));
8296
- }
8297
- if (candidateScore >= currentScore + criterion.promotionMargin) {
8298
- return verdictPolicyCriterionRule("small_score_gap", clearCriterionVerdict(criterion));
8329
+ return verdictPolicyGateRule(
8330
+ "peripheral_status",
8331
+ {
8332
+ autoApprove: false,
8333
+ mayInterrupt: false,
8334
+ requiresOperatorResponse: false,
8335
+ minimumPresentation: "ambient",
8336
+ minimumPresentationIsSticky: false,
8337
+ rationale: ["non-critical status work should start in the periphery"]
8338
+ }
8339
+ );
8340
+ };
8341
+ var evaluateSemanticUncertaintyCriterionRule = (input) => {
8342
+ const {
8343
+ candidate,
8344
+ criterion,
8345
+ peripheralResolution
8346
+ } = input;
8347
+ if (candidate.blocking) {
8348
+ return noopPolicyCriterionRule("semantic_uncertainty");
8349
+ }
8350
+ if (candidate.semanticAbstained === true) {
8351
+ return verdictPolicyCriterionRule(
8352
+ "semantic_uncertainty",
8353
+ ambiguousPeripheralCriterionVerdict(
8354
+ criterion,
8355
+ peripheralResolution,
8356
+ {
8357
+ kind: "interrupt",
8358
+ reason: "low_signal",
8359
+ resolution: peripheralResolution
8360
+ },
8361
+ ["semantic interpretation abstained, so non-blocking work stays peripheral until stronger explicit evidence arrives"]
8362
+ )
8363
+ );
8364
+ }
8365
+ if (candidate.semanticConfidence === "low") {
8366
+ return verdictPolicyCriterionRule(
8367
+ "semantic_uncertainty",
8368
+ ambiguousPeripheralCriterionVerdict(
8369
+ criterion,
8370
+ peripheralResolution,
8371
+ {
8372
+ kind: "interrupt",
8373
+ reason: "low_signal",
8374
+ resolution: peripheralResolution
8375
+ },
8376
+ ["low-confidence semantic interpretation keeps non-blocking work peripheral until the signal is clearer"]
8377
+ )
8378
+ );
8299
8379
  }
8300
- return verdictPolicyCriterionRule("small_score_gap", ambiguousPeripheralCriterionVerdict(criterion, peripheralResolution, {
8301
- kind: "interrupt",
8302
- reason: "small_score_gap",
8303
- resolution: peripheralResolution
8304
- }, ["small score gaps resolve to the periphery instead of stealing focus immediately"]));
8380
+ return noopPolicyCriterionRule(
8381
+ "semantic_uncertainty",
8382
+ candidate.semanticConfidence !== void 0 ? ["semantic confidence is strong enough to keep ordinary interrupt rules in play"] : []
8383
+ );
8384
+ };
8385
+ var evaluateSmallScoreGapCriterionRule = (input) => {
8386
+ const {
8387
+ candidateScore,
8388
+ currentScore,
8389
+ criterion,
8390
+ peripheralResolution
8391
+ } = input;
8392
+ if (currentScore === null || candidateScore <= currentScore) {
8393
+ return verdictPolicyCriterionRule(
8394
+ "small_score_gap",
8395
+ clearCriterionVerdict(criterion)
8396
+ );
8397
+ }
8398
+ if (candidateScore >= currentScore + criterion.promotionMargin) {
8399
+ return verdictPolicyCriterionRule(
8400
+ "small_score_gap",
8401
+ clearCriterionVerdict(criterion)
8402
+ );
8403
+ }
8404
+ return verdictPolicyCriterionRule(
8405
+ "small_score_gap",
8406
+ ambiguousPeripheralCriterionVerdict(
8407
+ criterion,
8408
+ peripheralResolution,
8409
+ {
8410
+ kind: "interrupt",
8411
+ reason: "small_score_gap",
8412
+ resolution: peripheralResolution
8413
+ },
8414
+ ["small score gaps resolve to the periphery instead of stealing focus immediately"]
8415
+ )
8416
+ );
8305
8417
  };
8306
-
8307
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/policy/source-trust-criterion-rule.js
8308
8418
  var TRUST_CRITERION_DIVISOR = 2;
8309
8419
  var MAX_TRUST_CRITERION_OFFSET = 6;
8310
8420
  var evaluateSourceTrustCriterionRule = (input) => {
@@ -8324,10 +8434,14 @@ function readTrustCriterionOffset(sourceTrustAdjustment) {
8324
8434
  if (sourceTrustAdjustment === 0) {
8325
8435
  return 0;
8326
8436
  }
8327
- return Math.max(-MAX_TRUST_CRITERION_OFFSET, Math.min(MAX_TRUST_CRITERION_OFFSET, Math.trunc(sourceTrustAdjustment / TRUST_CRITERION_DIVISOR)));
8437
+ return Math.max(
8438
+ -MAX_TRUST_CRITERION_OFFSET,
8439
+ Math.min(
8440
+ MAX_TRUST_CRITERION_OFFSET,
8441
+ Math.trunc(sourceTrustAdjustment / TRUST_CRITERION_DIVISOR)
8442
+ )
8443
+ );
8328
8444
  }
8329
-
8330
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-policy.js
8331
8445
  var POLICY_GATE_RULES = [
8332
8446
  evaluateConfiguredPolicyGateRule,
8333
8447
  evaluateBlockingPolicyGateRule,
@@ -8336,10 +8450,14 @@ var POLICY_GATE_RULES = [
8336
8450
  evaluateInterruptiveDefaultPolicyGateRule
8337
8451
  ];
8338
8452
  var POLICY_CRITERION_RULES = [
8453
+ // Order matters: early rules preserve hard boundaries like operator absence
8454
+ // and interrupt eligibility, mid-stage rules tune the criterion, and later
8455
+ // rules resolve ambiguity before threshold-based activation would fire.
8339
8456
  evaluateOperatorAbsenceCriterionRule,
8340
8457
  evaluateInterruptEligibilityCriterionRule,
8341
8458
  evaluateSourceTrustCriterionRule,
8342
8459
  evaluateAttentionBudgetCriterionRule,
8460
+ evaluateSemanticUncertaintyCriterionRule,
8343
8461
  evaluateNoActiveFrameCriterionRule,
8344
8462
  evaluateSmallScoreGapCriterionRule
8345
8463
  ];
@@ -8382,7 +8500,14 @@ var AttentionPolicy = class {
8382
8500
  };
8383
8501
  }
8384
8502
  evaluateInterruptCriterion(candidate, policyVerdict, evidence, candidateScore, currentScore, options = {}) {
8385
- return this.explainInterruptCriterion(candidate, policyVerdict, evidence, candidateScore, currentScore, options).verdict;
8503
+ return this.explainInterruptCriterion(
8504
+ candidate,
8505
+ policyVerdict,
8506
+ evidence,
8507
+ candidateScore,
8508
+ currentScore,
8509
+ options
8510
+ ).verdict;
8386
8511
  }
8387
8512
  explainInterruptCriterion(candidate, policyVerdict, evidence, candidateScore, currentScore, options = {}) {
8388
8513
  let criterion = this.readInterruptCriterion(options.ambiguityDefaults);
@@ -8391,7 +8516,16 @@ var AttentionPolicy = class {
8391
8516
  const criterionRationale = [];
8392
8517
  const evaluations = [];
8393
8518
  for (const rule of POLICY_CRITERION_RULES) {
8394
- const evaluation = rule(this.buildPolicyCriterionInput(candidate, policyVerdict, evidence, candidateScore, currentScore, criterion, sourceTrustAdjustment, peripheralResolution));
8519
+ const evaluation = rule(this.buildPolicyCriterionInput(
8520
+ candidate,
8521
+ policyVerdict,
8522
+ evidence,
8523
+ candidateScore,
8524
+ currentScore,
8525
+ criterion,
8526
+ sourceTrustAdjustment,
8527
+ peripheralResolution
8528
+ ));
8395
8529
  evaluations.push(evaluation);
8396
8530
  if (evaluation.kind === "adjust") {
8397
8531
  criterion = evaluation.criterion;
@@ -8454,8 +8588,6 @@ var AttentionPolicy = class {
8454
8588
  };
8455
8589
  }
8456
8590
  };
8457
-
8458
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/continuity-rule.js
8459
8591
  function noopContinuityRule(rule, rationale = []) {
8460
8592
  return {
8461
8593
  rule,
@@ -8473,8 +8605,6 @@ function overrideContinuityRule(rule, decision, currentPriority, currentScore, r
8473
8605
  rationale
8474
8606
  };
8475
8607
  }
8476
-
8477
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/burst-dampening-continuity-rule.js
8478
8608
  var evaluateBurstDampeningContinuityRule = (input) => {
8479
8609
  const activeFrame = input.evidence.currentFrame;
8480
8610
  const { candidate, context, evidence, helpers, plannerDefaults, routed } = input;
@@ -8492,12 +8622,16 @@ var evaluateBurstDampeningContinuityRule = (input) => {
8492
8622
  if (candidateTimestamp - currentTimestamp > JUDGMENT_DEFAULTS.queuePlanner.statusBurstWindowMs) {
8493
8623
  return noopContinuityRule("burst_dampening");
8494
8624
  }
8495
- return overrideContinuityRule("burst_dampening", helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities), priorityForFrame(activeFrame), context.currentScore, [
8496
- `rapid successive updates within ${candidateTimestamp - currentTimestamp}ms stay bundled instead of stealing focus`
8497
- ]);
8625
+ return overrideContinuityRule(
8626
+ "burst_dampening",
8627
+ helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
8628
+ priorityForFrame(activeFrame),
8629
+ context.currentScore,
8630
+ [
8631
+ `rapid successive updates within ${candidateTimestamp - currentTimestamp}ms stay bundled instead of stealing focus`
8632
+ ]
8633
+ );
8498
8634
  };
8499
-
8500
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/conflicting-interrupt-continuity-rule.js
8501
8635
  var evaluateConflictingInterruptContinuityRule = (input) => {
8502
8636
  const activeFrame = input.evidence.currentFrame;
8503
8637
  const { candidate, context, evidence, helpers, routed, plannerDefaults } = input;
@@ -8513,7 +8647,13 @@ var evaluateConflictingInterruptContinuityRule = (input) => {
8513
8647
  return noopContinuityRule("conflicting_interrupt");
8514
8648
  }
8515
8649
  if (candidateInterruptClass < currentInterruptClass) {
8516
- return overrideContinuityRule("conflicting_interrupt", helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities), priorityForFrame(activeFrame), context.currentScore, ["the current interrupt is more urgent, so the challenger waits instead of stealing focus"]);
8650
+ return overrideContinuityRule(
8651
+ "conflicting_interrupt",
8652
+ helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
8653
+ priorityForFrame(activeFrame),
8654
+ context.currentScore,
8655
+ ["the current interrupt is more urgent, so the challenger waits instead of stealing focus"]
8656
+ );
8517
8657
  }
8518
8658
  const conflictingInterruptMargin = plannerDefaults?.conflictingInterruptMargin ?? JUDGMENT_DEFAULTS.queuePlanner.conflictingInterruptMargin;
8519
8659
  if (conflictingInterruptMargin <= 0) {
@@ -8522,7 +8662,13 @@ var evaluateConflictingInterruptContinuityRule = (input) => {
8522
8662
  if (context.candidateScore >= context.currentScore + conflictingInterruptMargin) {
8523
8663
  return noopContinuityRule("conflicting_interrupt");
8524
8664
  }
8525
- return overrideContinuityRule("conflicting_interrupt", helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities), priorityForFrame(activeFrame), context.currentScore, ["equally interruptive work needs a clear advantage before it can replace the current interrupt"]);
8665
+ return overrideContinuityRule(
8666
+ "conflicting_interrupt",
8667
+ helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
8668
+ priorityForFrame(activeFrame),
8669
+ context.currentScore,
8670
+ ["equally interruptive work needs a clear advantage before it can replace the current interrupt"]
8671
+ );
8526
8672
  };
8527
8673
  function interruptClassForFrame(frame) {
8528
8674
  if (frame.mode !== "status" && frame.responseSpec?.kind !== "none") {
@@ -8548,8 +8694,6 @@ function interruptClassForCandidate(candidate, policyVerdict) {
8548
8694
  }
8549
8695
  return 0;
8550
8696
  }
8551
-
8552
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/context-patience-continuity-rule.js
8553
8697
  var evaluateContextPatienceContinuityRule = (input) => {
8554
8698
  const activeFrame = input.evidence.currentFrame;
8555
8699
  const { candidate, context, evidence, helpers } = input;
@@ -8571,12 +8715,16 @@ var evaluateContextPatienceContinuityRule = (input) => {
8571
8715
  return noopContinuityRule("context_patience");
8572
8716
  }
8573
8717
  const scoreGap = context.candidateScore - context.currentScore;
8574
- return overrideContinuityRule("context_patience", helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities), priorityForFrame(activeFrame), context.currentScore, [
8575
- `memory suggests this interaction usually needs context, so it stays peripheral until it clears the ${margin}-point margin (gap: ${scoreGap})`
8576
- ]);
8718
+ return overrideContinuityRule(
8719
+ "context_patience",
8720
+ helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
8721
+ priorityForFrame(activeFrame),
8722
+ context.currentScore,
8723
+ [
8724
+ `memory suggests this interaction usually needs context, so it stays peripheral until it clears the ${margin}-point margin (gap: ${scoreGap})`
8725
+ ]
8726
+ );
8577
8727
  };
8578
-
8579
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/decision-stream-continuity-rule.js
8580
8728
  var evaluateDecisionStreamContinuityRule = (input) => {
8581
8729
  const activeFrame = input.evidence.currentFrame;
8582
8730
  const { candidate, context, evidence, helpers, routed, plannerDefaults } = input;
@@ -8600,9 +8748,15 @@ var evaluateDecisionStreamContinuityRule = (input) => {
8600
8748
  return noopContinuityRule("decision_stream_continuity");
8601
8749
  }
8602
8750
  const scoreGap = context.candidateScore - context.currentScore;
8603
- return overrideContinuityRule("decision_stream_continuity", helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities), priorityForFrame(activeFrame), context.currentScore, [
8604
- `the current decision stream stays active until cross-stream work clears the ${streamContinuityMargin}-point margin (gap: ${scoreGap})`
8605
- ]);
8751
+ return overrideContinuityRule(
8752
+ "decision_stream_continuity",
8753
+ helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
8754
+ priorityForFrame(activeFrame),
8755
+ context.currentScore,
8756
+ [
8757
+ `the current decision stream stays active until cross-stream work clears the ${streamContinuityMargin}-point margin (gap: ${scoreGap})`
8758
+ ]
8759
+ );
8606
8760
  };
8607
8761
  function isSameDecisionStream(activeFrame, candidate) {
8608
8762
  const activeSourceKey = sourceKey(activeFrame.source);
@@ -8626,8 +8780,6 @@ function isSameDecisionStream(activeFrame, candidate) {
8626
8780
  }
8627
8781
  return false;
8628
8782
  }
8629
-
8630
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/deferral-escalation-continuity-rule.js
8631
8783
  var evaluateDeferralEscalationContinuityRule = (input) => {
8632
8784
  const activeFrame = input.evidence.currentFrame;
8633
8785
  const { candidate, context, evidence } = input;
@@ -8646,10 +8798,14 @@ var evaluateDeferralEscalationContinuityRule = (input) => {
8646
8798
  if (context.candidateScore < context.currentScore - JUDGMENT_DEFAULTS.queuePlanner.escalationScoreSlack) {
8647
8799
  return noopContinuityRule("deferral_escalation");
8648
8800
  }
8649
- return overrideContinuityRule("deferral_escalation", { kind: "activate", candidate }, priorityForFrame(activeFrame), context.currentScore, ["repeated deferral makes this task more deserving of current focus"]);
8801
+ return overrideContinuityRule(
8802
+ "deferral_escalation",
8803
+ { kind: "activate", candidate },
8804
+ priorityForFrame(activeFrame),
8805
+ context.currentScore,
8806
+ ["repeated deferral makes this task more deserving of current focus"]
8807
+ );
8650
8808
  };
8651
-
8652
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/minimum-dwell-continuity-rule.js
8653
8809
  var evaluateMinimumDwellContinuityRule = (input) => {
8654
8810
  const activeFrame = input.evidence.currentFrame;
8655
8811
  const { candidate, context, evidence, helpers, routed, plannerDefaults } = input;
@@ -8672,10 +8828,14 @@ var evaluateMinimumDwellContinuityRule = (input) => {
8672
8828
  return noopContinuityRule("minimum_dwell");
8673
8829
  }
8674
8830
  const remainingMs = minimumDwellMs - (candidateTimestamp - activeTimestamp);
8675
- return overrideContinuityRule("minimum_dwell", helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities), priorityForFrame(activeFrame), context.currentScore, [`recently surfaced work keeps focus for another ${remainingMs}ms to avoid a premature switch`]);
8831
+ return overrideContinuityRule(
8832
+ "minimum_dwell",
8833
+ helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
8834
+ priorityForFrame(activeFrame),
8835
+ context.currentScore,
8836
+ [`recently surfaced work keeps focus for another ${remainingMs}ms to avoid a premature switch`]
8837
+ );
8676
8838
  };
8677
-
8678
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/same-episode-continuity-rule.js
8679
8839
  var evaluateSameEpisodeContinuityRule = (input) => {
8680
8840
  const activeFrame = input.evidence.currentFrame;
8681
8841
  const { candidate, context, evidence, helpers } = input;
@@ -8687,24 +8847,44 @@ var evaluateSameEpisodeContinuityRule = (input) => {
8687
8847
  return noopContinuityRule("same_episode");
8688
8848
  }
8689
8849
  if (candidate.blocking && !isBlockingFrame(activeFrame)) {
8690
- return overrideContinuityRule("same_episode", { kind: "activate", candidate }, priorityForFrame(activeFrame), context.currentScore, ["the active episode has progressed into an interruptive step"]);
8850
+ return overrideContinuityRule(
8851
+ "same_episode",
8852
+ { kind: "activate", candidate },
8853
+ priorityForFrame(activeFrame),
8854
+ context.currentScore,
8855
+ ["the active episode has progressed into an interruptive step"]
8856
+ );
8691
8857
  }
8692
8858
  if (candidate.blocking && hasSemanticRelationKind(candidate.relationHints, "supersedes")) {
8693
- return overrideContinuityRule("same_episode", { kind: "activate", candidate }, priorityForFrame(activeFrame), context.currentScore, ["the active episode has advanced to a superseding step"]);
8694
- }
8695
- return overrideContinuityRule("same_episode", helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities), priorityForFrame(activeFrame), context.currentScore, ["related work stays bundled with the active episode"]);
8859
+ return overrideContinuityRule(
8860
+ "same_episode",
8861
+ { kind: "activate", candidate },
8862
+ priorityForFrame(activeFrame),
8863
+ context.currentScore,
8864
+ ["the active episode has advanced to a superseding step"]
8865
+ );
8866
+ }
8867
+ return overrideContinuityRule(
8868
+ "same_episode",
8869
+ helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
8870
+ priorityForFrame(activeFrame),
8871
+ context.currentScore,
8872
+ ["related work stays bundled with the active episode"]
8873
+ );
8696
8874
  };
8697
-
8698
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/same-interaction-continuity-rule.js
8699
8875
  var evaluateSameInteractionContinuityRule = (input) => {
8700
8876
  const activeFrame = input.evidence.currentFrame;
8701
8877
  if (!activeFrame || activeFrame.interactionId !== input.candidate.interactionId) {
8702
8878
  return noopContinuityRule("same_interaction");
8703
8879
  }
8704
- return overrideContinuityRule("same_interaction", { kind: "activate", candidate: input.candidate }, null, null, ["same interaction refreshes the existing frame"]);
8880
+ return overrideContinuityRule(
8881
+ "same_interaction",
8882
+ { kind: "activate", candidate: input.candidate },
8883
+ null,
8884
+ null,
8885
+ ["same interaction refreshes the existing frame"]
8886
+ );
8705
8887
  };
8706
-
8707
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/continuity/visible-episode-continuity-rule.js
8708
8888
  var evaluateVisibleEpisodeContinuityRule = (input) => {
8709
8889
  const { candidate, context, evidence, helpers } = input;
8710
8890
  if (!candidate.episodeId) {
@@ -8721,12 +8901,21 @@ var evaluateVisibleEpisodeContinuityRule = (input) => {
8721
8901
  if (visibleRelatedFrames.length === 0 || !(candidate.episodeState === "batched" || (candidate.episodeSize ?? 1) >= 2 || visibleRelatedFrames.length >= 2)) {
8722
8902
  return noopContinuityRule("visible_episode");
8723
8903
  }
8724
- return overrideContinuityRule("visible_episode", helpers.batchedDecision(candidate, context.policyVerdict, evidence.attentionView, evidence.surfaceCapabilities), null, evidence.currentFrame ? context.currentScore : null, [
8725
- evidence.currentFrame ? "related episode work is already building in the queue, so this interaction stays bundled with it" : "related episode work is already visible, so this interaction batches with it instead of interrupting"
8726
- ]);
8904
+ return overrideContinuityRule(
8905
+ "visible_episode",
8906
+ helpers.batchedDecision(
8907
+ candidate,
8908
+ context.policyVerdict,
8909
+ evidence.attentionView,
8910
+ evidence.surfaceCapabilities
8911
+ ),
8912
+ null,
8913
+ evidence.currentFrame ? context.currentScore : null,
8914
+ [
8915
+ evidence.currentFrame ? "related episode work is already building in the queue, so this interaction stays bundled with it" : "related episode work is already visible, so this interaction batches with it instead of interrupting"
8916
+ ]
8917
+ );
8727
8918
  };
8728
-
8729
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-planner.js
8730
8919
  var DEFAULTS2 = JUDGMENT_DEFAULTS.queuePlanner;
8731
8920
  var CONTINUITY_RULES = [
8732
8921
  evaluateVisibleEpisodeContinuityRule,
@@ -8745,7 +8934,7 @@ var AttentionPlanner = class {
8745
8934
  this.plannerDefaults = options.plannerDefaults;
8746
8935
  }
8747
8936
  explain(current, candidate, context) {
8748
- const evidence = this.resolveEvidenceContext(current, context);
8937
+ const evidence = this.resolveEvidenceContext(current, context, candidate.timestamp);
8749
8938
  const routing = this.route(candidate, context, evidence);
8750
8939
  return this.applyContinuity(candidate, context, evidence, routing);
8751
8940
  }
@@ -8852,7 +9041,12 @@ var AttentionPlanner = class {
8852
9041
  if (this.shouldPreemptForPressure(candidate, context.policyVerdict, evidence.pressureForecast)) {
8853
9042
  reasons.push("predicted overload keeps lower-value work peripheral before the queue spikes");
8854
9043
  return {
8855
- decision: this.suppressedDecision(candidate, context.policyVerdict, context.utility, evidence.surfaceCapabilities),
9044
+ decision: this.suppressedDecision(
9045
+ candidate,
9046
+ context.policyVerdict,
9047
+ context.utility,
9048
+ evidence.surfaceCapabilities
9049
+ ),
8856
9050
  currentPriority: null,
8857
9051
  currentScore: null,
8858
9052
  reasons
@@ -8880,7 +9074,9 @@ var AttentionPlanner = class {
8880
9074
  const currentScore = context.currentScore;
8881
9075
  if (actionableEpisode) {
8882
9076
  if (currentBlocking || evidence.pressureForecast.overloadRisk === "high") {
8883
- reasons.push(currentBlocking ? "the episode has become actionable, but current blocking work keeps it queued" : "the episode has become actionable, but predicted overload keeps it queued");
9077
+ reasons.push(
9078
+ currentBlocking ? "the episode has become actionable, but current blocking work keeps it queued" : "the episode has become actionable, but predicted overload keeps it queued"
9079
+ );
8884
9080
  return {
8885
9081
  decision: { kind: "queue", candidate },
8886
9082
  currentPriority,
@@ -8935,16 +9131,28 @@ var AttentionPlanner = class {
8935
9131
  if (this.shouldPreemptForPressure(candidate, context.policyVerdict, evidence.pressureForecast)) {
8936
9132
  reasons.push("predicted overload keeps lower-value work peripheral before the queue spikes");
8937
9133
  return {
8938
- decision: this.suppressedDecision(candidate, context.policyVerdict, context.utility, evidence.surfaceCapabilities),
9134
+ decision: this.suppressedDecision(
9135
+ candidate,
9136
+ context.policyVerdict,
9137
+ context.utility,
9138
+ evidence.surfaceCapabilities
9139
+ ),
8939
9140
  currentPriority,
8940
9141
  currentScore,
8941
9142
  reasons
8942
9143
  };
8943
9144
  }
8944
9145
  if (this.shouldSuppressForBacklog(candidate, evidence.attentionView, candidate.timestamp)) {
8945
- reasons.push(context.utility.components.deferralAffinity > 0 ? "existing urgent backlog defers this work, but memory keeps it queued because it usually returns after deferral" : "existing urgent backlog keeps lower-value status work queued");
9146
+ reasons.push(
9147
+ context.utility.components.deferralAffinity > 0 ? "existing urgent backlog defers this work, but memory keeps it queued because it usually returns after deferral" : "existing urgent backlog keeps lower-value status work queued"
9148
+ );
8946
9149
  return {
8947
- decision: this.suppressedDecision(candidate, context.policyVerdict, context.utility, evidence.surfaceCapabilities),
9150
+ decision: this.suppressedDecision(
9151
+ candidate,
9152
+ context.policyVerdict,
9153
+ context.utility,
9154
+ evidence.surfaceCapabilities
9155
+ ),
8948
9156
  currentPriority,
8949
9157
  currentScore,
8950
9158
  reasons
@@ -8997,7 +9205,10 @@ var AttentionPlanner = class {
8997
9205
  if (!disabledContinuityRules.has(evaluation.rule)) {
8998
9206
  return evaluation;
8999
9207
  }
9000
- return noopContinuityRule(evaluation.rule, [`operator disabled the ${evaluation.rule} continuity rule`]);
9208
+ return noopContinuityRule(
9209
+ evaluation.rule,
9210
+ [`operator disabled the ${evaluation.rule} continuity rule`]
9211
+ );
9001
9212
  });
9002
9213
  const winningEvaluation = continuityEvaluations.find((evaluation) => evaluation.kind === "override");
9003
9214
  if (!winningEvaluation) {
@@ -9014,22 +9225,18 @@ var AttentionPlanner = class {
9014
9225
  continuityEvaluations
9015
9226
  };
9016
9227
  }
9017
- resolveEvidenceContext(current, context) {
9018
- return resolveAttentionEvidenceContext(current, {
9019
- ...context.currentTaskView !== void 0 ? { currentTaskView: context.currentTaskView } : {},
9020
- ...context.currentEpisode !== void 0 ? { currentEpisode: context.currentEpisode } : {},
9021
- ...context.attentionView !== void 0 ? { attentionView: context.attentionView } : {},
9022
- ...context.taskSignalSummary !== void 0 ? { taskSignalSummary: context.taskSignalSummary } : {},
9023
- ...context.globalSignalSummary !== void 0 ? { globalSignalSummary: context.globalSignalSummary } : {},
9024
- ...context.taskAttentionState !== void 0 ? { taskAttentionState: context.taskAttentionState } : {},
9025
- ...context.globalAttentionState !== void 0 ? { globalAttentionState: context.globalAttentionState } : {},
9026
- ...context.pressureForecast !== void 0 ? { pressureForecast: context.pressureForecast } : {},
9027
- ...context.attentionBurden !== void 0 ? { attentionBurden: context.attentionBurden } : {},
9028
- ...context.surfaceCapabilities !== void 0 ? { surfaceCapabilities: context.surfaceCapabilities } : {},
9029
- ...context.operatorPresence !== void 0 ? { operatorPresence: context.operatorPresence } : {}
9030
- });
9228
+ resolveEvidenceContext(current, context, referenceTimestamp) {
9229
+ return resolveAttentionEvidenceContext(
9230
+ current,
9231
+ buildAttentionEvidenceInput(context),
9232
+ parseReferenceTime(referenceTimestamp)
9233
+ );
9031
9234
  }
9032
9235
  };
9236
+ function parseReferenceTime(value) {
9237
+ const timestamp = Date.parse(value);
9238
+ return Number.isNaN(timestamp) ? 0 : timestamp;
9239
+ }
9033
9240
  function selectPeripheralBucket(candidate, policyVerdict, surfaceCapabilities = baseAttentionSurfaceCapabilities) {
9034
9241
  if (policyVerdict.minimumPresentation === "ambient" && canRemainAmbientOnSurface(candidate, surfaceCapabilities)) {
9035
9242
  return "ambient";
@@ -9052,8 +9259,6 @@ function canRemainAmbientOnSurface(candidate, surfaceCapabilities) {
9052
9259
  }
9053
9260
  return false;
9054
9261
  }
9055
-
9056
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-value.js
9057
9262
  var AttentionValue = class {
9058
9263
  memoryProfile;
9059
9264
  constructor(options = {}) {
@@ -9235,8 +9440,6 @@ function toneWeight2(tone) {
9235
9440
  return 2;
9236
9441
  }
9237
9442
  }
9238
-
9239
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/judgment-coordinator.js
9240
9443
  var JudgmentCoordinator = class {
9241
9444
  policyGates;
9242
9445
  utilityScore;
@@ -9252,7 +9455,7 @@ var JudgmentCoordinator = class {
9252
9455
  return this.explain(current, candidate, context).decision;
9253
9456
  }
9254
9457
  explain(current, candidate, context = {}) {
9255
- const evidence = this.resolveEvidenceContext(current, context);
9458
+ const evidence = this.resolveEvidenceContext(current, context, candidate.timestamp);
9256
9459
  const gateExplanation = this.policyGates.explainGates(candidate);
9257
9460
  const policy = gateExplanation.verdict;
9258
9461
  const utility = this.utilityScore.scoreCandidate(candidate);
@@ -9288,7 +9491,14 @@ var JudgmentCoordinator = class {
9288
9491
  continuityEvaluations: []
9289
9492
  };
9290
9493
  }
9291
- const criterionExplanation = this.policyGates.explainInterruptCriterion(candidate, policy, evidence, utility.total, currentScore, this.ambiguityDefaults !== void 0 ? { ambiguityDefaults: this.ambiguityDefaults } : {});
9494
+ const criterionExplanation = this.policyGates.explainInterruptCriterion(
9495
+ candidate,
9496
+ policy,
9497
+ evidence,
9498
+ utility.total,
9499
+ currentScore,
9500
+ this.ambiguityDefaults !== void 0 ? { ambiguityDefaults: this.ambiguityDefaults } : {}
9501
+ );
9292
9502
  const criterion = criterionExplanation.verdict;
9293
9503
  if (criterion.peripheralResolution) {
9294
9504
  const reasons = [
@@ -9343,24 +9553,18 @@ var JudgmentCoordinator = class {
9343
9553
  clear() {
9344
9554
  return this.queuePlanner.clear();
9345
9555
  }
9346
- resolveEvidenceContext(current, context) {
9347
- return resolveAttentionEvidenceContext(current, {
9348
- ...context.currentTaskView !== void 0 ? { currentTaskView: context.currentTaskView } : {},
9349
- ...context.currentEpisode !== void 0 ? { currentEpisode: context.currentEpisode } : {},
9350
- ...context.attentionView !== void 0 ? { attentionView: context.attentionView } : {},
9351
- ...context.taskSignalSummary !== void 0 ? { taskSignalSummary: context.taskSignalSummary } : {},
9352
- ...context.globalSignalSummary !== void 0 ? { globalSignalSummary: context.globalSignalSummary } : {},
9353
- ...context.taskAttentionState !== void 0 ? { taskAttentionState: context.taskAttentionState } : {},
9354
- ...context.globalAttentionState !== void 0 ? { globalAttentionState: context.globalAttentionState } : {},
9355
- ...context.pressureForecast !== void 0 ? { pressureForecast: context.pressureForecast } : {},
9356
- ...context.attentionBurden !== void 0 ? { attentionBurden: context.attentionBurden } : {},
9357
- ...context.surfaceCapabilities !== void 0 ? { surfaceCapabilities: context.surfaceCapabilities } : {},
9358
- ...context.operatorPresence !== void 0 ? { operatorPresence: context.operatorPresence } : {}
9359
- });
9556
+ resolveEvidenceContext(current, context, referenceTimestamp) {
9557
+ return resolveAttentionEvidenceContext(
9558
+ current,
9559
+ buildAttentionEvidenceInput(context),
9560
+ parseReferenceTime2(referenceTimestamp)
9561
+ );
9360
9562
  }
9361
9563
  };
9362
-
9363
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/attention-signal-store.js
9564
+ function parseReferenceTime2(value) {
9565
+ const timestamp = Date.parse(value);
9566
+ return Number.isNaN(timestamp) ? 0 : timestamp;
9567
+ }
9364
9568
  var AttentionSignalStore = class _AttentionSignalStore {
9365
9569
  static RECENT_SIGNAL_LIMIT = 32;
9366
9570
  static RECENT_WINDOW_MS = 30 * 60 * 1e3;
@@ -9369,7 +9573,10 @@ var AttentionSignalStore = class _AttentionSignalStore {
9369
9573
  record(signal) {
9370
9574
  const current = this.byTaskId.get(signal.taskId) ?? [];
9371
9575
  const next = [...current, signal];
9372
- this.byTaskId.set(signal.taskId, next.length > _AttentionSignalStore.MAX_RETAINED_SIGNALS ? next.slice(-_AttentionSignalStore.MAX_RETAINED_SIGNALS) : next);
9576
+ this.byTaskId.set(
9577
+ signal.taskId,
9578
+ next.length > _AttentionSignalStore.MAX_RETAINED_SIGNALS ? next.slice(-256) : next
9579
+ );
9373
9580
  }
9374
9581
  list(taskId) {
9375
9582
  if (taskId !== void 0) {
@@ -9459,7 +9666,7 @@ var AttentionSignalStore = class _AttentionSignalStore {
9459
9666
  };
9460
9667
  }
9461
9668
  recentSignals(signals) {
9462
- const bounded = signals.slice(-_AttentionSignalStore.RECENT_SIGNAL_LIMIT);
9669
+ const bounded = signals.slice(-32);
9463
9670
  const latestTimestamp2 = bounded[bounded.length - 1]?.timestamp;
9464
9671
  if (latestTimestamp2 === void 0) {
9465
9672
  return bounded;
@@ -9478,13 +9685,6 @@ var AttentionSignalStore = class _AttentionSignalStore {
9478
9685
  return recent.length > 0 ? recent : bounded;
9479
9686
  }
9480
9687
  };
9481
-
9482
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/judgment-config.js
9483
- import { join } from "node:path";
9484
-
9485
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/markdown-state.js
9486
- import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
9487
- import { dirname } from "node:path";
9488
9688
  async function readMarkdownFile(path2, fallback, parse) {
9489
9689
  try {
9490
9690
  const content = await readFile(path2, "utf8");
@@ -9536,10 +9736,8 @@ function parseBullet(line) {
9536
9736
  return { key, value };
9537
9737
  }
9538
9738
  function parseScalar(value) {
9539
- if (value === "true")
9540
- return true;
9541
- if (value === "false")
9542
- return false;
9739
+ if (value === "true") return true;
9740
+ if (value === "false") return false;
9543
9741
  if (/^-?\d+(?:\.\d+)?$/.test(value)) {
9544
9742
  return Number(value);
9545
9743
  }
@@ -9551,8 +9749,6 @@ function formatBullet(key, value) {
9551
9749
  function formatTextBullet(value) {
9552
9750
  return `- ${value}`;
9553
9751
  }
9554
-
9555
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/judgment-config.js
9556
9752
  async function loadJudgmentConfig(rootDir, fallback) {
9557
9753
  return readMarkdownFile(join(rootDir, "JUDGMENT.md"), fallback, parseJudgmentConfig);
9558
9754
  }
@@ -9658,8 +9854,6 @@ function parseContinuityRuleList(value) {
9658
9854
  function isContinuityRuleName(value) {
9659
9855
  return CONTINUITY_RULE_NAMES.includes(value);
9660
9856
  }
9661
-
9662
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/memory-aggregator.js
9663
9857
  function distillMemoryProfile(baseMemoryProfile, signals, now) {
9664
9858
  const toolFamilies = toolFamilyMemory(baseMemoryProfile, signals);
9665
9859
  const sourceTrust = sourceTrustMemory(baseMemoryProfile, signals);
@@ -9813,10 +10007,20 @@ function toolFamilyMemory(baseMemoryProfile, signals) {
9813
10007
  responses,
9814
10008
  dismissals,
9815
10009
  ...currentResponseAverage !== void 0 ? {
9816
- avgResponseLatencyMs: weightedAverage(previous.avgResponseLatencyMs, previous.responses, currentResponseAverage, current.responseLatencyCount)
10010
+ avgResponseLatencyMs: weightedAverage(
10011
+ previous.avgResponseLatencyMs,
10012
+ previous.responses,
10013
+ currentResponseAverage,
10014
+ current.responseLatencyCount
10015
+ )
9817
10016
  } : previous.avgResponseLatencyMs !== void 0 ? { avgResponseLatencyMs: previous.avgResponseLatencyMs } : {},
9818
10017
  ...currentDismissalAverage !== void 0 ? {
9819
- avgDismissalLatencyMs: weightedAverage(previous.avgDismissalLatencyMs, previous.dismissals, currentDismissalAverage, current.dismissalLatencyCount)
10018
+ avgDismissalLatencyMs: weightedAverage(
10019
+ previous.avgDismissalLatencyMs,
10020
+ previous.dismissals,
10021
+ currentDismissalAverage,
10022
+ current.dismissalLatencyCount
10023
+ )
9820
10024
  } : previous.avgDismissalLatencyMs !== void 0 ? { avgDismissalLatencyMs: previous.avgDismissalLatencyMs } : {},
9821
10025
  ...presentations > 0 ? {
9822
10026
  contextExpansionRate: roundRate((previousContextExpanded + currentContextExpanded) / presentations)
@@ -9931,8 +10135,6 @@ function weightedAverage(previousAverage, previousCount, currentAverage, current
9931
10135
  const currentTotal = currentAverage * currentCount;
9932
10136
  return Math.round((previousTotal + currentTotal) / totalCount);
9933
10137
  }
9934
-
9935
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/semantic-interpreter.js
9936
10138
  function interpretSourceEvent(event) {
9937
10139
  const inferred = inferSemanticInterpretation(event);
9938
10140
  return applySemanticHints(inferred, event.semanticHints);
@@ -9943,8 +10145,6 @@ function inferSemanticInterpretation(event) {
9943
10145
  return {
9944
10146
  intentFrame: "task_started",
9945
10147
  activityClass: "session_status",
9946
- operatorActionRequired: false,
9947
- requestExplicitness: "none",
9948
10148
  consequence: "low",
9949
10149
  factors: ["task.started"],
9950
10150
  relationHints: [],
@@ -9959,8 +10159,6 @@ function inferSemanticInterpretation(event) {
9959
10159
  return {
9960
10160
  intentFrame: "completion",
9961
10161
  activityClass: "tool_completion",
9962
- operatorActionRequired: false,
9963
- requestExplicitness: "none",
9964
10162
  consequence: "low",
9965
10163
  factors: ["task.completed"],
9966
10164
  relationHints: [],
@@ -9971,8 +10169,6 @@ function inferSemanticInterpretation(event) {
9971
10169
  return {
9972
10170
  intentFrame: "cancellation",
9973
10171
  activityClass: "status_update",
9974
- operatorActionRequired: false,
9975
- requestExplicitness: "none",
9976
10172
  consequence: "low",
9977
10173
  ...event.reason ? { whyNow: semanticWhyNowForTaskStatus("completed", { wasCancelled: true }) ?? "Work was cancelled and may need review." } : {},
9978
10174
  factors: ["task.cancelled"],
@@ -9994,8 +10190,6 @@ function inferTaskUpdateSemantics(event) {
9994
10190
  intentFrame: "failure",
9995
10191
  activityClass: "tool_failure",
9996
10192
  ...toolFamily ? { toolFamily } : {},
9997
- operatorActionRequired: true,
9998
- requestExplicitness: impliedAsk ? "implied" : "none",
9999
10193
  consequence: inferConsequenceFromSemanticText(text, "high", toolFamily),
10000
10194
  whyNow: semanticWhyNowForTaskStatus("failed") ?? "Work has failed and should be reviewed.",
10001
10195
  factors: ["task.updated", "failed"],
@@ -10008,8 +10202,6 @@ function inferTaskUpdateSemantics(event) {
10008
10202
  intentFrame: "blocked_work",
10009
10203
  activityClass: "status_update",
10010
10204
  ...toolFamily ? { toolFamily } : {},
10011
- operatorActionRequired: true,
10012
- requestExplicitness: impliedAsk ? "implied" : "none",
10013
10205
  consequence: inferConsequenceFromSemanticText(text, "medium", toolFamily),
10014
10206
  whyNow: semanticWhyNowForTaskStatus("blocked") ?? "Work is blocked and may require operator attention.",
10015
10207
  factors: ["task.updated", "blocked"],
@@ -10024,8 +10216,6 @@ function inferTaskUpdateSemantics(event) {
10024
10216
  intentFrame: "status_update",
10025
10217
  activityClass: "status_update",
10026
10218
  ...toolFamily ? { toolFamily } : {},
10027
- operatorActionRequired: impliedAsk,
10028
- requestExplicitness: impliedAsk ? "implied" : "none",
10029
10219
  consequence: inferConsequenceFromSemanticText(text, "low", toolFamily),
10030
10220
  ...(() => {
10031
10221
  const whyNow = impliedAsk ? semanticWhyNowForTaskStatus(event.status, { impliedAsk }) : void 0;
@@ -10049,8 +10239,6 @@ function inferHumanInputSemantics(event) {
10049
10239
  intentFrame: semanticIntentFrameForRequestKind(event.request.kind),
10050
10240
  activityClass: semanticActivityClassForRequestKind(event.request.kind),
10051
10241
  ...toolFamily ? { toolFamily } : {},
10052
- operatorActionRequired: true,
10053
- requestExplicitness: "explicit",
10054
10242
  consequence,
10055
10243
  whyNow: semanticWhyNowForRequestKind(event.request.kind, consequence),
10056
10244
  factors: ["human.input.requested", event.request.kind],
@@ -10089,9 +10277,6 @@ function consequenceFromRequestKind(kind, toolFamily) {
10089
10277
  if (toolFamily === "read" || toolFamily === "search") {
10090
10278
  return "low";
10091
10279
  }
10092
- if (toolFamily === "write" || toolFamily === "edit" || toolFamily === "bash") {
10093
- return "medium";
10094
- }
10095
10280
  return "medium";
10096
10281
  case "choice":
10097
10282
  case "form":
@@ -10106,8 +10291,6 @@ function buildTaxonomyInput(title, summary, toolFamily, context) {
10106
10291
  ...context?.items !== void 0 ? { context: { items: context.items } } : {}
10107
10292
  };
10108
10293
  }
10109
-
10110
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/semantic-normalizer.js
10111
10294
  function normalizeSourceEvent(event) {
10112
10295
  const semantic = interpretSourceEvent(event);
10113
10296
  switch (event.type) {
@@ -10161,13 +10344,13 @@ function normalizeSourceEvent(event) {
10161
10344
  return normalizeHumanInput(event, semantic);
10162
10345
  }
10163
10346
  }
10164
- function normalizeHumanInput(event, semantic = interpretSourceEvent(event)) {
10347
+ function normalizeHumanInput(event, semantic) {
10165
10348
  const consequence = semantic.consequence ?? event.riskHint ?? "medium";
10166
10349
  const tone = toneForRisk(consequence);
10167
- const factors = [
10168
- ...event.provenance?.factors ?? [],
10169
- ...semantic.factors
10170
- ];
10350
+ const provenance = mergeSemanticProvenance({
10351
+ base: event.provenance,
10352
+ semantic
10353
+ });
10171
10354
  return {
10172
10355
  id: event.id,
10173
10356
  type: event.type,
@@ -10184,13 +10367,7 @@ function normalizeHumanInput(event, semantic = interpretSourceEvent(event)) {
10184
10367
  consequence,
10185
10368
  request: event.request,
10186
10369
  ...event.context !== void 0 ? { context: event.context } : {},
10187
- ...event.provenance !== void 0 || semantic.whyNow !== void 0 || factors.length > 0 ? {
10188
- provenance: {
10189
- ...event.provenance ?? {},
10190
- ...event.provenance?.whyNow === void 0 && semantic.whyNow !== void 0 ? { whyNow: semantic.whyNow } : {},
10191
- ...factors.length > 0 ? { factors: dedupeStrings(factors) } : {}
10192
- }
10193
- } : {}
10370
+ ...provenance !== void 0 ? { provenance } : {}
10194
10371
  };
10195
10372
  }
10196
10373
  function toneForRisk(risk) {
@@ -10202,12 +10379,6 @@ function toneForRisk(risk) {
10202
10379
  return "focused";
10203
10380
  }
10204
10381
  }
10205
- function dedupeStrings(values) {
10206
- return [...new Set(values)];
10207
- }
10208
-
10209
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/profile-store.js
10210
- import { join as join2 } from "node:path";
10211
10382
  var ProfileStore = class {
10212
10383
  rootDir;
10213
10384
  constructor(rootDir) {
@@ -10223,10 +10394,10 @@ var ProfileStore = class {
10223
10394
  return writeMarkdownFile(this.memoryPath(), serializeMemoryProfile(profile));
10224
10395
  }
10225
10396
  userPath() {
10226
- return join2(this.rootDir, "USER.md");
10397
+ return join(this.rootDir, "USER.md");
10227
10398
  }
10228
10399
  memoryPath() {
10229
- return join2(this.rootDir, "MEMORY.md");
10400
+ return join(this.rootDir, "MEMORY.md");
10230
10401
  }
10231
10402
  };
10232
10403
  function parseUserProfile(content) {
@@ -10454,8 +10625,6 @@ function numberValue(value) {
10454
10625
  function camelKey2(value) {
10455
10626
  return value.replace(/\s+([a-z])/g, (_match, letter) => letter.toUpperCase());
10456
10627
  }
10457
-
10458
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/task-view-store.js
10459
10628
  var TaskViewStore = class {
10460
10629
  taskViews = /* @__PURE__ */ new Map();
10461
10630
  get(taskId) {
@@ -10536,8 +10705,6 @@ var TaskViewStore = class {
10536
10705
  return this.taskViews.values();
10537
10706
  }
10538
10707
  };
10539
-
10540
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/trace-recorder.js
10541
10708
  var TraceRecorder = class {
10542
10709
  recordNoop(snapshot) {
10543
10710
  return {
@@ -10583,7 +10750,7 @@ var TraceRecorder = class {
10583
10750
  },
10584
10751
  coordination: {
10585
10752
  kind: explanation.decision.kind,
10586
- resultBucket: findResultBucket(snapshot.attentionView, adjusted.taskId, adjusted.interactionId),
10753
+ resultBucket: findResultBucket(snapshot.attentionView, adjusted.taskId, adjusted.interactionId, explanation.decision.kind),
10587
10754
  candidateScore: explanation.candidateScore,
10588
10755
  currentScore: explanation.currentScore,
10589
10756
  currentPriority: explanation.currentPriority,
@@ -10613,7 +10780,10 @@ function buildEpisodeSummary(candidate) {
10613
10780
  updatedAt: candidate.timestamp
10614
10781
  };
10615
10782
  }
10616
- function findResultBucket(attentionView, taskId, interactionId) {
10783
+ function findResultBucket(attentionView, taskId, interactionId, decisionKind) {
10784
+ if (decisionKind === "auto_approve" || decisionKind === "clear") {
10785
+ return "none";
10786
+ }
10617
10787
  if (attentionView.active && attentionView.active.taskId === taskId && attentionView.active.interactionId === interactionId) {
10618
10788
  return "active";
10619
10789
  }
@@ -10625,8 +10795,6 @@ function findResultBucket(attentionView, taskId, interactionId) {
10625
10795
  }
10626
10796
  return "none";
10627
10797
  }
10628
-
10629
- // node_modules/.pnpm/@tomismeta+aperture-core@0.3.0/node_modules/@tomismeta/aperture-core/dist/aperture-core.js
10630
10798
  var ApertureCore = class _ApertureCore {
10631
10799
  frameListeners = /* @__PURE__ */ new Map();
10632
10800
  taskViewListeners = /* @__PURE__ */ new Map();
@@ -10650,6 +10818,7 @@ var ApertureCore = class _ApertureCore {
10650
10818
  surfaceCapabilities;
10651
10819
  operatorPresence;
10652
10820
  responseExpiryMs;
10821
+ timeSource;
10653
10822
  constructor(options = {}) {
10654
10823
  this.markdownRootDir = options.markdownRootDir;
10655
10824
  this.profileStore = options.profileStore;
@@ -10664,6 +10833,7 @@ var ApertureCore = class _ApertureCore {
10664
10833
  };
10665
10834
  this.operatorPresence = options.operatorPresence ?? "present";
10666
10835
  this.responseExpiryMs = options.responseExpiryMs;
10836
+ this.timeSource = options.timeSource ?? Date.now;
10667
10837
  this.baseMemoryProfile = options.memoryProfile ?? {
10668
10838
  version: MARKDOWN_SCHEMA_VERSION,
10669
10839
  operatorId: "default",
@@ -10673,15 +10843,19 @@ var ApertureCore = class _ApertureCore {
10673
10843
  this.coordinator = this.createCoordinator();
10674
10844
  }
10675
10845
  createCoordinator() {
10676
- return new JudgmentCoordinator(new AttentionPolicy({
10677
- ...this.userProfile !== void 0 ? { userProfile: this.userProfile } : {},
10678
- ...this.judgmentConfig !== void 0 ? { judgmentConfig: this.judgmentConfig } : {},
10679
- memoryProfile: this.baseMemoryProfile
10680
- }), new AttentionValue({
10681
- memoryProfile: this.baseMemoryProfile
10682
- }), new AttentionPlanner({
10683
- ...this.judgmentConfig?.plannerDefaults !== void 0 ? { plannerDefaults: this.judgmentConfig.plannerDefaults } : {}
10684
- }));
10846
+ return new JudgmentCoordinator(
10847
+ new AttentionPolicy({
10848
+ ...this.userProfile !== void 0 ? { userProfile: this.userProfile } : {},
10849
+ ...this.judgmentConfig !== void 0 ? { judgmentConfig: this.judgmentConfig } : {},
10850
+ memoryProfile: this.baseMemoryProfile
10851
+ }),
10852
+ new AttentionValue({
10853
+ memoryProfile: this.baseMemoryProfile
10854
+ }),
10855
+ new AttentionPlanner({
10856
+ ...this.judgmentConfig?.plannerDefaults !== void 0 ? { plannerDefaults: this.judgmentConfig.plannerDefaults } : {}
10857
+ })
10858
+ );
10685
10859
  }
10686
10860
  static async fromMarkdown(rootDir) {
10687
10861
  const profileStore = new ProfileStore(rootDir);
@@ -10757,7 +10931,7 @@ var ApertureCore = class _ApertureCore {
10757
10931
  switch (evaluation.kind) {
10758
10932
  case "noop": {
10759
10933
  this.notifyTrace(this.traceRecorder.recordNoop({
10760
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10934
+ timestamp: this.nowIso(),
10761
10935
  event,
10762
10936
  taskSummary,
10763
10937
  globalSummary,
@@ -10775,7 +10949,7 @@ var ApertureCore = class _ApertureCore {
10775
10949
  const result = this.applyClear(event.taskId);
10776
10950
  const postAttentionView = this.getAttentionView();
10777
10951
  this.notifyTrace(this.traceRecorder.recordClear({
10778
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10952
+ timestamp: this.nowIso(),
10779
10953
  event,
10780
10954
  taskSummary,
10781
10955
  globalSummary,
@@ -10790,29 +10964,54 @@ var ApertureCore = class _ApertureCore {
10790
10964
  return result;
10791
10965
  }
10792
10966
  case "candidate": {
10793
- const candidate = this.episodes.assign(this.heuristics.apply(evaluation.candidate, taskSummary, globalSummary));
10967
+ const candidate = this.episodes.assign(this.heuristics.apply(
10968
+ evaluation.candidate,
10969
+ taskSummary,
10970
+ globalSummary
10971
+ ));
10794
10972
  const explanation = this.coordinator.explain(evidence.currentFrame, candidate, evidence);
10795
10973
  let result;
10796
10974
  switch (explanation.decision.kind) {
10797
10975
  case "auto_approve":
10798
- result = this.applyAutoResponse(explanation.decision.candidate, explanation.decision.response);
10976
+ result = this.applyAutoResponse(
10977
+ explanation.decision.candidate,
10978
+ explanation.decision.response
10979
+ );
10799
10980
  break;
10800
10981
  case "clear":
10801
10982
  result = this.applyClear(event.taskId);
10802
10983
  break;
10803
10984
  case "ambient":
10804
- result = this.materializePeripheralFrame(explanation.decision.candidate, "ambient", preAttentionView);
10985
+ result = this.materializePeripheralFrame(
10986
+ explanation.decision.candidate,
10987
+ "ambient",
10988
+ preAttentionView
10989
+ );
10805
10990
  break;
10806
10991
  case "queue":
10807
- result = this.materializePeripheralFrame(explanation.decision.candidate, "queue", preAttentionView);
10992
+ result = this.materializePeripheralFrame(
10993
+ explanation.decision.candidate,
10994
+ "queue",
10995
+ preAttentionView
10996
+ );
10808
10997
  break;
10809
10998
  case "activate":
10810
- result = explanation.decision.candidate.episodeId && this.findPeripheralEpisodeFrame(explanation.decision.candidate.episodeId, preAttentionView) ? this.materializePeripheralFrame(explanation.decision.candidate, selectPeripheralBucket(explanation.decision.candidate, explanation.policy, evidence.surfaceCapabilities), preAttentionView) : this.commitFrame(this.applyResponseExpiry(this.planner.plan(explanation.decision.candidate, evidence.currentFrame)));
10999
+ result = explanation.decision.candidate.episodeId && this.findPeripheralEpisodeFrame(explanation.decision.candidate.episodeId, preAttentionView) ? this.materializePeripheralFrame(
11000
+ explanation.decision.candidate,
11001
+ selectPeripheralBucket(
11002
+ explanation.decision.candidate,
11003
+ explanation.policy,
11004
+ evidence.surfaceCapabilities
11005
+ ),
11006
+ preAttentionView
11007
+ ) : this.commitFrame(this.applyResponseExpiry(
11008
+ this.planner.plan(explanation.decision.candidate, evidence.currentFrame)
11009
+ ));
10811
11010
  break;
10812
11011
  }
10813
11012
  const postAttentionView = this.getAttentionView();
10814
11013
  this.notifyTrace(this.traceRecorder.recordCandidate({
10815
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11014
+ timestamp: this.nowIso(),
10816
11015
  event,
10817
11016
  taskSummary,
10818
11017
  globalSummary,
@@ -10891,11 +11090,13 @@ var ApertureCore = class _ApertureCore {
10891
11090
  if (!current) {
10892
11091
  return;
10893
11092
  }
10894
- const expiredAt = this.readExpiredResponseTimestamp(current, (/* @__PURE__ */ new Date()).toISOString());
11093
+ const expiredAt = this.readExpiredResponseTimestamp(current, this.nowIso());
10895
11094
  if (expiredAt) {
10896
- throw new Error(`response for interaction ${response.interactionId} expired at ${expiredAt} and must be revalidated before submission`);
11095
+ throw new Error(
11096
+ `response for interaction ${response.interactionId} expired at ${expiredAt} and must be revalidated before submission`
11097
+ );
10897
11098
  }
10898
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
11099
+ const timestamp = this.nowIso();
10899
11100
  this.recordSignal(this.signalForResponse(current, response, timestamp));
10900
11101
  this.episodes.resolveInteraction(response.interactionId);
10901
11102
  const previousTaskView = this.taskViews.get(response.taskId);
@@ -10950,10 +11151,10 @@ var ApertureCore = class _ApertureCore {
10950
11151
  responses: { ...capabilities.responses }
10951
11152
  };
10952
11153
  }
10953
- snapshotMemoryProfile(now = (/* @__PURE__ */ new Date()).toISOString()) {
11154
+ snapshotMemoryProfile(now = this.nowIso()) {
10954
11155
  return distillMemoryProfile(this.baseMemoryProfile, this.signals.list(), now);
10955
11156
  }
10956
- async checkpointMemory(now = (/* @__PURE__ */ new Date()).toISOString()) {
11157
+ async checkpointMemory(now = this.nowIso()) {
10957
11158
  if (!this.profileStore) {
10958
11159
  return null;
10959
11160
  }
@@ -11023,7 +11224,7 @@ var ApertureCore = class _ApertureCore {
11023
11224
  const currentTaskView = this.getTaskView(taskId);
11024
11225
  const attentionView = this.getAttentionView();
11025
11226
  const operatorPresence = this.getOperatorPresence();
11026
- return resolveAttentionEvidenceContext(currentFrame, {
11227
+ return resolveAttentionEvidenceContext(currentFrame, buildAttentionEvidenceInput({
11027
11228
  currentFrame,
11028
11229
  currentTaskView,
11029
11230
  currentEpisode: this.episodes.readFrameEpisode(currentFrame),
@@ -11034,7 +11235,7 @@ var ApertureCore = class _ApertureCore {
11034
11235
  globalAttentionState,
11035
11236
  surfaceCapabilities: this.getSurfaceCapabilities(),
11036
11237
  operatorPresence
11037
- });
11238
+ }), this.timeSource());
11038
11239
  }
11039
11240
  applyClear(taskId) {
11040
11241
  const existingTaskView = this.taskViews.get(taskId);
@@ -11182,7 +11383,7 @@ var ApertureCore = class _ApertureCore {
11182
11383
  };
11183
11384
  }
11184
11385
  applyAutoResponse(candidate, response) {
11185
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
11386
+ const timestamp = this.nowIso();
11186
11387
  this.recordSignal({
11187
11388
  kind: "responded",
11188
11389
  taskId: candidate.taskId,
@@ -11257,7 +11458,7 @@ var ApertureCore = class _ApertureCore {
11257
11458
  kind,
11258
11459
  taskId,
11259
11460
  interactionId,
11260
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11461
+ timestamp: this.nowIso(),
11261
11462
  ...frame?.id !== void 0 ? { frameId: frame.id } : {},
11262
11463
  ...frame?.source !== void 0 ? { source: frame.source } : {},
11263
11464
  ...frame ? { metadata: signalMetadataForFrame(frame) } : {},
@@ -11275,6 +11476,9 @@ var ApertureCore = class _ApertureCore {
11275
11476
  }
11276
11477
  return taskView.ambient.find((frame) => frame.interactionId === interactionId) ?? null;
11277
11478
  }
11479
+ nowIso() {
11480
+ return new Date(this.timeSource()).toISOString();
11481
+ }
11278
11482
  assertValidEvent(event) {
11279
11483
  this.assertNonEmpty("event.id", event.id);
11280
11484
  this.assertNonEmpty("event.taskId", event.taskId);
@@ -11292,9 +11496,6 @@ var ApertureCore = class _ApertureCore {
11292
11496
  this.assertNonEmpty("event.title", event.title);
11293
11497
  this.assertNonEmpty("event.summary", event.summary);
11294
11498
  break;
11295
- case "task.completed":
11296
- case "task.cancelled":
11297
- break;
11298
11499
  }
11299
11500
  }
11300
11501
  assertValidSourceEvent(event) {
@@ -12129,12 +12330,78 @@ function truncate(value, max = 180) {
12129
12330
  function issueText(issue, comment) {
12130
12331
  return [comment?.body, issue.description].filter((value) => !!value).join("\n");
12131
12332
  }
12333
+ function toTimestamp(value) {
12334
+ if (!value) return 0;
12335
+ if (value instanceof Date) return value.getTime();
12336
+ const timestamp = Date.parse(value);
12337
+ return Number.isNaN(timestamp) ? 0 : timestamp;
12338
+ }
12339
+ function toIsoString(value) {
12340
+ if (!value) return null;
12341
+ if (typeof value === "string") return value;
12342
+ return value.toISOString();
12343
+ }
12132
12344
  function normalizeActorKey(value) {
12133
12345
  return value.toLowerCase().replace(/[^a-z0-9]/g, "");
12134
12346
  }
12135
12347
  function escapeRegex(value) {
12136
12348
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12137
12349
  }
12350
+ function issueRelationTarget(issueId) {
12351
+ return `issue:${issueId}`;
12352
+ }
12353
+ function detectIssueIntents(text) {
12354
+ const intents = /* @__PURE__ */ new Set();
12355
+ for (const detector of ISSUE_INTENT_DETECTORS) {
12356
+ if (detector.pattern.test(text)) intents.add(detector.key);
12357
+ }
12358
+ return intents;
12359
+ }
12360
+ function blockingTargetForText(text, identifier) {
12361
+ const normalizedIdentifier = identifier?.toUpperCase();
12362
+ const matches = text.match(/\b[A-Z]+-\d+\b/g) ?? [];
12363
+ return matches.find((match) => match.toUpperCase() !== normalizedIdentifier) ?? null;
12364
+ }
12365
+ function explicitBoardInstructionForText(text) {
12366
+ return text.replace(/\s+/g, " ").trim().match(/(board should either .*?)(?:[.!?]|$)/i)?.[1] ?? null;
12367
+ }
12368
+ function semanticConfidenceForIntents(intents) {
12369
+ if (intents.has("resolution") || intents.has("share_with_board") || intents.has("confirmation") || intents.has("board_instruction")) {
12370
+ return "high";
12371
+ }
12372
+ if (intents.has("clarification")) return "medium";
12373
+ return null;
12374
+ }
12375
+ function relationHintsForIntents(intents, issueTarget) {
12376
+ const hints = [];
12377
+ const target = issueTarget ?? void 0;
12378
+ if (target) {
12379
+ hints.push({ kind: "same_issue", target });
12380
+ }
12381
+ if (intents.has("resolution")) {
12382
+ hints.push(target ? { kind: "resolves", target } : { kind: "resolves" });
12383
+ return hints;
12384
+ }
12385
+ if (intents.has("share_with_board") || intents.has("confirmation") || intents.has("board_instruction")) {
12386
+ hints.push(target ? { kind: "supersedes", target } : { kind: "supersedes" });
12387
+ return hints;
12388
+ }
12389
+ if (intents.has("clarification")) {
12390
+ hints.push(target ? { kind: "repeats", target } : { kind: "repeats" });
12391
+ }
12392
+ return hints;
12393
+ }
12394
+ function analyzeIssueTextSemantics(input) {
12395
+ const intents = detectIssueIntents(input.text);
12396
+ return {
12397
+ text: input.text,
12398
+ blockingTarget: blockingTargetForText(input.text, input.identifier),
12399
+ intents,
12400
+ explicitBoardInstruction: explicitBoardInstructionForText(input.text),
12401
+ semanticConfidence: semanticConfidenceForIntents(intents),
12402
+ relationHints: relationHintsForIntents(intents, input.issueTarget)
12403
+ };
12404
+ }
12138
12405
  function resolveAgentOwner(text, directory) {
12139
12406
  if (!directory || directory.agentNames.length === 0) return null;
12140
12407
  const mentionMatch = text.match(/needed from\s+@([a-z0-9_-]+)/i) ?? text.match(/@([a-z0-9_-]+)/i);
@@ -12147,25 +12414,19 @@ function resolveAgentOwner(text, directory) {
12147
12414
  }
12148
12415
  function analyzeIssueIntents(issue, comment, directory) {
12149
12416
  const text = issueText(issue, comment);
12150
- const intents = /* @__PURE__ */ new Set();
12151
- for (const detector of ISSUE_INTENT_DETECTORS) {
12152
- if (detector.pattern.test(text)) intents.add(detector.key);
12153
- }
12417
+ const semanticAnalysis = analyzeIssueTextSemantics({
12418
+ text,
12419
+ identifier: issue.identifier,
12420
+ issueTarget: issueRelationTarget(issue.id)
12421
+ });
12154
12422
  const agentOwner = resolveAgentOwner(text, directory);
12155
12423
  const mentionMatch = text.match(/needed from\s+@([a-z0-9_-]+)/i) ?? text.match(/@([a-z0-9_-]+)/i);
12156
12424
  const owner = agentOwner ?? (mentionMatch?.[1] ? titleCase(mentionMatch[1]) : /board should|board can/i.test(text) ? "Board" : /ceo agent|@ceo|\bceo\b/i.test(text) ? "CEO" : /requires human|waiting on human|human review/i.test(text) ? "Human" : /operator intervention|operator review/i.test(text) ? "Operator" : null);
12157
12425
  const ownerKind = agentOwner ? "agent" : owner ? "human" : null;
12158
- const identifier = issue.identifier?.toUpperCase();
12159
- const matches = text.match(/\b[A-Z]+-\d+\b/g) ?? [];
12160
- const blockingTarget = matches.find((match) => match.toUpperCase() !== identifier) ?? null;
12161
- const explicitBoardInstruction = text.replace(/\s+/g, " ").trim().match(/(board should either .*?)(?:[.!?]|$)/i)?.[1] ?? null;
12162
12426
  return {
12163
- text,
12427
+ ...semanticAnalysis,
12164
12428
  owner,
12165
- ownerKind,
12166
- blockingTarget,
12167
- intents,
12168
- explicitBoardInstruction
12429
+ ownerKind
12169
12430
  };
12170
12431
  }
12171
12432
  function hasIntent(analysis, key) {
@@ -12175,8 +12436,28 @@ function ownerPhrase(value, ownerKind) {
12175
12436
  if (ownerKind === "agent") return value;
12176
12437
  return actorPhrase(value);
12177
12438
  }
12178
- function issueRecommendedMove(issue, analysis) {
12439
+ function latestIssueDocument(documents) {
12440
+ if (documents.length === 0) return null;
12441
+ return [...documents].sort(
12442
+ (left, right) => toTimestamp(right.updatedAt) - toTimestamp(left.updatedAt)
12443
+ )[0] ?? null;
12444
+ }
12445
+ function analyzeIssueDocuments(documents, comment, analysis) {
12446
+ const latest = latestIssueDocument(documents);
12447
+ const latestUpdatedAt = toIsoString(latest?.updatedAt);
12448
+ const commentUpdatedAt = comment?.updatedAt ?? null;
12449
+ return {
12450
+ hasDocuments: documents.length > 0,
12451
+ latestDocumentTitle: latest?.title ?? null,
12452
+ latestDocumentUpdatedAt: latestUpdatedAt,
12453
+ resolvesArtifactRequest: hasIntent(analysis, "share_with_board") && !!latest && (!commentUpdatedAt || toTimestamp(latestUpdatedAt) >= toTimestamp(commentUpdatedAt))
12454
+ };
12455
+ }
12456
+ function issueRecommendedMove(issue, analysis, documentSignal) {
12179
12457
  const normalized = analysis.text.replace(/\s+/g, " ").trim();
12458
+ if (documentSignal?.resolvesArtifactRequest) {
12459
+ return "Monitor the review now that the memo is attached.";
12460
+ }
12180
12461
  if (hasIntent(analysis, "resolution")) {
12181
12462
  return "Monitor execution and confirm the team resumes work.";
12182
12463
  }
@@ -12201,7 +12482,10 @@ function issueRecommendedMove(issue, analysis) {
12201
12482
  }
12202
12483
  return null;
12203
12484
  }
12204
- function issueHeadline(issue, analysis) {
12485
+ function issueHeadline(issue, analysis, documentSignal) {
12486
+ if (documentSignal?.resolvesArtifactRequest) {
12487
+ return "The requested memo appears attached, so review should be able to continue.";
12488
+ }
12205
12489
  if (hasIntent(analysis, "resolution")) {
12206
12490
  return "Latest operator guidance appears to unblock this issue.";
12207
12491
  }
@@ -12225,7 +12509,13 @@ function issueHeadline(issue, analysis) {
12225
12509
  if (issue.description) return truncate(issue.description);
12226
12510
  return "This issue has new operator-relevant activity.";
12227
12511
  }
12228
- function issueWhyNow(issue, analysis) {
12512
+ function issueWhyNow(issue, analysis, documentSignal) {
12513
+ if (documentSignal?.resolvesArtifactRequest) {
12514
+ return {
12515
+ whyNow: documentSignal.latestDocumentTitle ? `${documentSignal.latestDocumentTitle} was attached after the request, so the missing artifact appears resolved.` : "A review document was attached after the request, so the missing artifact appears resolved.",
12516
+ factors: ["document attached", "review can proceed"]
12517
+ };
12518
+ }
12229
12519
  if (hasIntent(analysis, "resolution")) {
12230
12520
  return {
12231
12521
  whyNow: "The latest comment appears to resolve the blocker; monitor execution rather than intervening.",
@@ -12266,12 +12556,12 @@ function issueWhyNow(issue, analysis) {
12266
12556
 
12267
12557
  // src/aperture/reconciliation.ts
12268
12558
  var COMMENT_LOOKUP_CONCURRENCY = 6;
12269
- function toIsoString(value) {
12559
+ function toIsoString2(value) {
12270
12560
  if (!value) return void 0;
12271
12561
  if (typeof value === "string") return value;
12272
12562
  return value.toISOString();
12273
12563
  }
12274
- function toTimestamp(value) {
12564
+ function toTimestamp2(value) {
12275
12565
  if (!value) return 0;
12276
12566
  if (value instanceof Date) return value.getTime();
12277
12567
  const timestamp = Date.parse(value);
@@ -12288,20 +12578,12 @@ function acknowledgeResponseSpec() {
12288
12578
  function issueTitle(issue) {
12289
12579
  return issue.identifier ? `${issue.identifier} ${issue.title}` : issue.title;
12290
12580
  }
12291
- function recommendedMove(issue, comment, directory) {
12292
- const analysis = analyzeIssueIntents(issue, comment, directory);
12293
- return issueRecommendedMove(issue, analysis);
12294
- }
12295
- function issueHeadline2(issue, comment, directory) {
12296
- const analysis = analyzeIssueIntents(issue, comment, directory);
12297
- return issueHeadline(issue, analysis);
12298
- }
12299
12581
  function latestComment(comments) {
12300
12582
  if (comments.length === 0) return null;
12301
12583
  const newest = [...comments].sort(
12302
- (left, right) => toTimestamp(right.updatedAt) - toTimestamp(left.updatedAt)
12584
+ (left, right) => toTimestamp2(right.updatedAt) - toTimestamp2(left.updatedAt)
12303
12585
  )[0];
12304
- const updatedAt = toIsoString(newest.updatedAt) ?? toIsoString(newest.createdAt) ?? (/* @__PURE__ */ new Date(0)).toISOString();
12586
+ const updatedAt = toIsoString2(newest.updatedAt) ?? toIsoString2(newest.createdAt) ?? (/* @__PURE__ */ new Date(0)).toISOString();
12305
12587
  return {
12306
12588
  body: truncate(newest.body),
12307
12589
  updatedAt
@@ -12310,36 +12592,36 @@ function latestComment(comments) {
12310
12592
  function priorityConsequence(issue) {
12311
12593
  return issue.priority === "critical" || issue.priority === "high" ? "high" : "medium";
12312
12594
  }
12313
- function issueLane(issue, comment, directory) {
12314
- const analysis = analyzeIssueIntents(issue, comment, directory);
12315
- if (issue.status === "blocked" && hasIntent(analysis, "resolution")) {
12316
- return comment || issue.isUnreadForMe ? "ambient" : null;
12595
+ function issueLane(issue, comment, evidence) {
12596
+ if ((issue.status === "blocked" || issue.status === "in_review") && (hasIntent(evidence.analysis, "resolution") || evidence.documentSignal.resolvesArtifactRequest)) {
12597
+ return comment || issue.isUnreadForMe || evidence.documentSignal.hasDocuments ? "ambient" : null;
12317
12598
  }
12318
12599
  if (issue.status === "blocked") return issue.priority === "critical" ? "active" : "queued";
12319
12600
  if (issue.status === "in_review") return "queued";
12320
12601
  if (comment || issue.isUnreadForMe) return "ambient";
12321
12602
  return null;
12322
12603
  }
12323
- function issueSummary(issue, comment, directory) {
12324
- return issueHeadline2(issue, comment, directory);
12604
+ function issueSummary(issue, evidence) {
12605
+ return issueHeadline(issue, evidence.analysis, evidence.documentSignal);
12325
12606
  }
12326
- function issueProvenance(issue, comment, directory) {
12327
- const analysis = analyzeIssueIntents(issue, comment, directory);
12328
- return issueWhyNow(issue, analysis);
12607
+ function issueProvenance(issue, evidence) {
12608
+ return issueWhyNow(issue, evidence.analysis, evidence.documentSignal);
12329
12609
  }
12330
- function issueAttentionTimestamp(issue, comment) {
12331
- const commentSignals = [comment?.updatedAt, toIsoString(issue.lastExternalCommentAt)].filter((value) => !!value).sort();
12610
+ function issueAttentionTimestamp(issue, comment, documentSignal) {
12611
+ const commentSignals = [comment?.updatedAt, toIsoString2(issue.lastExternalCommentAt), documentSignal.latestDocumentUpdatedAt].filter((value) => !!value).sort();
12332
12612
  if (commentSignals.length > 0) return commentSignals.at(-1);
12333
- return toIsoString(issue.updatedAt) ?? toIsoString(issue.createdAt) ?? (/* @__PURE__ */ new Date(0)).toISOString();
12613
+ return toIsoString2(issue.updatedAt) ?? toIsoString2(issue.createdAt) ?? (/* @__PURE__ */ new Date(0)).toISOString();
12334
12614
  }
12335
- function issueFrame(issue, comment, directory) {
12336
- const lane = issueLane(issue, comment, directory);
12337
- if (!lane) return null;
12338
- const updatedAt = issueAttentionTimestamp(issue, comment);
12339
- const provenance = issueProvenance(issue, comment, directory);
12615
+ function issueFrame(issue, comment, documents, directory) {
12340
12616
  const analysis = analyzeIssueIntents(issue, comment, directory);
12341
- const owner = hasIntent(analysis, "resolution") ? null : analysis.owner;
12342
- const move = recommendedMove(issue, comment, directory);
12617
+ const documentSignal = analyzeIssueDocuments(documents, comment, analysis);
12618
+ const evidence = { analysis, documentSignal };
12619
+ const lane = issueLane(issue, comment, evidence);
12620
+ if (!lane) return null;
12621
+ const updatedAt = issueAttentionTimestamp(issue, comment, documentSignal);
12622
+ const provenance = issueProvenance(issue, evidence);
12623
+ const owner = hasIntent(analysis, "resolution") || documentSignal.resolvesArtifactRequest ? null : analysis.owner;
12624
+ const move = issueRecommendedMove(issue, analysis, documentSignal);
12343
12625
  const target = analysis.blockingTarget;
12344
12626
  return {
12345
12627
  lane,
@@ -12357,7 +12639,7 @@ function issueFrame(issue, comment, directory) {
12357
12639
  tone: issue.status === "blocked" ? "focused" : lane === "ambient" ? "ambient" : "focused",
12358
12640
  consequence: issue.status === "blocked" ? priorityConsequence(issue) : lane === "ambient" ? "low" : "medium",
12359
12641
  title: issueTitle(issue),
12360
- summary: issueSummary(issue, comment, directory),
12642
+ summary: issueSummary(issue, evidence),
12361
12643
  context: {
12362
12644
  items: [
12363
12645
  ...owner ? [needsActionFromItem(owner)] : [],
@@ -12371,7 +12653,7 @@ function issueFrame(issue, comment, directory) {
12371
12653
  responseSpec: acknowledgeResponseSpec(),
12372
12654
  provenance,
12373
12655
  timing: {
12374
- createdAt: toIsoString(issue.createdAt) ?? updatedAt,
12656
+ createdAt: toIsoString2(issue.createdAt) ?? updatedAt,
12375
12657
  updatedAt
12376
12658
  },
12377
12659
  metadata: {
@@ -12400,7 +12682,7 @@ function agentSummary(agent) {
12400
12682
  function agentFrame(agent) {
12401
12683
  const lane = agentLane(agent);
12402
12684
  if (!lane) return null;
12403
- const updatedAt = toIsoString(agent.updatedAt) ?? toIsoString(agent.createdAt) ?? (/* @__PURE__ */ new Date(0)).toISOString();
12685
+ const updatedAt = toIsoString2(agent.updatedAt) ?? toIsoString2(agent.createdAt) ?? (/* @__PURE__ */ new Date(0)).toISOString();
12404
12686
  const provenance = agentProvenance(agent);
12405
12687
  return {
12406
12688
  lane,
@@ -12429,7 +12711,7 @@ function agentFrame(agent) {
12429
12711
  responseSpec: acknowledgeResponseSpec(),
12430
12712
  provenance,
12431
12713
  timing: {
12432
- createdAt: toIsoString(agent.createdAt) ?? updatedAt,
12714
+ createdAt: toIsoString2(agent.createdAt) ?? updatedAt,
12433
12715
  updatedAt
12434
12716
  },
12435
12717
  metadata: {
@@ -12454,6 +12736,17 @@ async function safeListComments(ctx, issue) {
12454
12736
  return null;
12455
12737
  }
12456
12738
  }
12739
+ async function safeListDocuments(ctx, issue) {
12740
+ try {
12741
+ return await ctx.issues.documents.list(issue.id, issue.companyId);
12742
+ } catch (error) {
12743
+ ctx.logger.warn("Failed to load issue documents during Aperture reconciliation", {
12744
+ issueId: issue.id,
12745
+ error: error instanceof Error ? error.message : String(error)
12746
+ });
12747
+ return [];
12748
+ }
12749
+ }
12457
12750
  async function mapWithConcurrency(items, limit, mapper) {
12458
12751
  if (items.length === 0) return [];
12459
12752
  const results = new Array(items.length);
@@ -12475,16 +12768,23 @@ async function loadIssueCandidates(ctx, companyId) {
12475
12768
  ctx.issues.list({ companyId, status: "in_review", limit: 25 })
12476
12769
  ]);
12477
12770
  const issues = [...blocked, ...inReview];
12478
- const comments = await mapWithConcurrency(
12479
- issues,
12480
- COMMENT_LOOKUP_CONCURRENCY,
12481
- (issue) => safeListComments(ctx, issue)
12482
- );
12483
- const allAgents = await ctx.agents.list({ companyId, limit: 100 });
12771
+ const [comments, documents, allAgents] = await Promise.all([
12772
+ mapWithConcurrency(
12773
+ issues,
12774
+ COMMENT_LOOKUP_CONCURRENCY,
12775
+ (issue) => safeListComments(ctx, issue)
12776
+ ),
12777
+ mapWithConcurrency(
12778
+ issues,
12779
+ COMMENT_LOOKUP_CONCURRENCY,
12780
+ (issue) => safeListDocuments(ctx, issue)
12781
+ ),
12782
+ ctx.agents.list({ companyId, limit: 100 })
12783
+ ]);
12484
12784
  const directory = {
12485
12785
  agentNames: allAgents.map((agent) => agent.name).filter((name) => typeof name === "string" && name.trim().length > 0)
12486
12786
  };
12487
- return issues.map((issue, index) => issueFrame(issue, comments[index] ?? null, directory)).filter((candidate) => candidate !== null);
12787
+ return issues.map((issue, index) => issueFrame(issue, comments[index] ?? null, documents[index] ?? [], directory)).filter((candidate) => candidate !== null);
12488
12788
  }
12489
12789
  async function loadAgentCandidates(ctx, companyId) {
12490
12790
  const [pendingApproval, errored, paused] = await Promise.all([
@@ -12725,65 +13025,493 @@ function registerDataHandlers(ctx, store) {
12725
13025
  });
12726
13026
  }
12727
13027
 
12728
- // src/aperture/event-mapper.ts
12729
- function readString2(value) {
12730
- return typeof value === "string" && value.trim().length > 0 ? value : void 0;
12731
- }
12732
- function readStringArrayLength(payload, key) {
12733
- if (!payload || typeof payload !== "object") return void 0;
12734
- const value = payload[key];
12735
- return Array.isArray(value) ? value.length : void 0;
13028
+ // node_modules/.pnpm/@tomismeta+aperture-core@0.4.0/node_modules/@tomismeta/aperture-core/public-dist/semantic.js
13029
+ function normalizeSemanticText2(value) {
13030
+ return value.toLowerCase().replace(/[^a-z0-9/.-]+/g, " ").trim();
12736
13031
  }
12737
- function readPayloadString(payload, key) {
12738
- if (!payload || typeof payload !== "object") return void 0;
12739
- return readString2(payload[key]);
13032
+ function dedupeSemanticStrings2(values) {
13033
+ return [...new Set(values)];
12740
13034
  }
12741
- function humanizeApprovalType(value) {
12742
- return value ? humanizeToken(value) : void 0;
13035
+ function readExplicitSemanticToolFamily2(input) {
13036
+ return normalizeToolFamily2(input.toolFamily) ?? normalizeToolFamily2(readMetadataToolFamily2(input.metadata)) ?? normalizeToolFamily2(readContextToolFamily2(input.context));
12743
13037
  }
12744
- function makeTaskId(event) {
12745
- const entityType = event.entityType ?? "event";
12746
- const entityId = event.entityId ?? event.eventId;
12747
- return `${entityType}:${entityId}`;
13038
+ function inferSemanticToolFamily2(input) {
13039
+ const explicit = readExplicitSemanticToolFamily2(input);
13040
+ if (explicit) {
13041
+ return explicit;
13042
+ }
13043
+ const value = normalizeSemanticText2(`${input.title} ${input.summary ?? ""}`);
13044
+ if (hasPhrase2(value, "wants to read") || hasPhrase2(value, "wants to inspect") || hasWord2(value, "read") || hasWord2(value, "inspect")) return "read";
13045
+ if (hasPhrase2(value, "wants to write") || hasWord2(value, "write")) return "write";
13046
+ if (hasPhrase2(value, "wants to edit") || hasWord2(value, "edit")) return "edit";
13047
+ if (hasPhrase2(value, "shell command") || hasPhrase2(value, "wants to run")) return "bash";
13048
+ if (hasPhrase2(value, "search the web")) return "web";
13049
+ if (hasPhrase2(value, "search files") || hasPhrase2(value, "search file contents")) return "search";
13050
+ return null;
12748
13051
  }
12749
- function makeSource(event) {
12750
- const entityType = event.entityType ?? "event";
12751
- switch (entityType) {
12752
- case "approval":
12753
- return {
12754
- id: `paperclip:${entityType}`,
12755
- kind: "paperclip",
12756
- label: "Paperclip approval"
12757
- };
12758
- case "issue":
12759
- return {
12760
- id: `paperclip:${entityType}`,
12761
- kind: "paperclip",
12762
- label: "Paperclip issue"
12763
- };
12764
- case "run":
12765
- return {
12766
- id: `paperclip:${entityType}`,
12767
- kind: "paperclip",
12768
- label: "Paperclip run"
12769
- };
12770
- case "agent":
12771
- return {
12772
- id: `paperclip:${entityType}`,
12773
- kind: "paperclip",
12774
- label: "Paperclip agent"
12775
- };
12776
- default:
12777
- return {
12778
- id: `paperclip:${event.eventType}`,
12779
- kind: "paperclip",
12780
- label: "Paperclip"
12781
- };
13052
+ function detectImpliedOperatorAsk2(text) {
13053
+ if (containsAnySemanticPhrase2(text, IMPLIED_OPERATOR_NEGATIONS2)) {
13054
+ return false;
12782
13055
  }
13056
+ return containsAnySemanticPhrase2(text, IMPLIED_OPERATOR_ASKS2);
12783
13057
  }
12784
- function inferIssueStatus(payload) {
12785
- const raw = readPayloadString(payload, "status")?.toLowerCase();
12786
- const summary = [
13058
+ function detectSemanticRelationHints2(text) {
13059
+ const hints = [];
13060
+ const hasIssueSignal = containsAnySemanticPhrase2(text, ISSUE_SIGNAL_PHRASES2) || containsAnySemanticPhrase2(text, RESOLVE_PHRASES2) || containsAnySemanticPhrase2(text, SUPERSEDE_PHRASES2) || containsAnySemanticPhrase2(text, ESCALATE_PHRASES2);
13061
+ if (containsAnySemanticPhrase2(text, REPEAT_PHRASES2) && hasIssueSignal) {
13062
+ hints.push({ kind: "same_issue" }, { kind: "repeats" });
13063
+ }
13064
+ if (containsAnySemanticPhrase2(text, RESOLVE_PHRASES2) && hasIssueSignal) {
13065
+ hints.push({ kind: "same_issue" }, { kind: "resolves" });
13066
+ }
13067
+ if (containsAnySemanticPhrase2(text, SUPERSEDE_PHRASES2)) {
13068
+ hints.push({ kind: "same_issue" }, { kind: "supersedes" });
13069
+ }
13070
+ if (containsAnySemanticPhrase2(text, ESCALATE_PHRASES2)) {
13071
+ hints.push({ kind: "same_issue" }, { kind: "escalates" });
13072
+ }
13073
+ return dedupeRelationHints2(hints);
13074
+ }
13075
+ function inferConsequenceFromSemanticText2(text, fallback, toolFamily) {
13076
+ if (toolFamily === "read" || toolFamily === "search") {
13077
+ return fallback;
13078
+ }
13079
+ if (containsAnySemanticPhrase2(text, HIGH_RISK_PHRASES2)) {
13080
+ return "high";
13081
+ }
13082
+ if (toolFamily === "write" || toolFamily === "edit" || toolFamily === "bash") {
13083
+ return fallback === "low" ? "medium" : fallback;
13084
+ }
13085
+ return fallback;
13086
+ }
13087
+ function containsAnySemanticPhrase2(value, phrases) {
13088
+ return phrases.some((phrase) => value.includes(phrase));
13089
+ }
13090
+ function readMetadataToolFamily2(metadata) {
13091
+ const value = metadata?.toolFamily;
13092
+ return typeof value === "string" ? value : null;
13093
+ }
13094
+ function readContextToolFamily2(input) {
13095
+ if (!input?.items) {
13096
+ return null;
13097
+ }
13098
+ for (const item2 of input.items) {
13099
+ const id = item2.id.toLowerCase();
13100
+ const label = item2.label.toLowerCase();
13101
+ if (id === "toolfamily" || id === "tool_family" || id === "tool" || label === "tool family") {
13102
+ return item2.value ?? null;
13103
+ }
13104
+ }
13105
+ return null;
13106
+ }
13107
+ function normalizeToolFamily2(value) {
13108
+ if (!value) {
13109
+ return null;
13110
+ }
13111
+ const normalized = value.trim().toLowerCase();
13112
+ return normalized.length > 0 ? normalized : null;
13113
+ }
13114
+ function hasPhrase2(value, phrase) {
13115
+ return value.includes(phrase);
13116
+ }
13117
+ function hasWord2(value, word) {
13118
+ return new RegExp(`(?:^|\\s)${escapeRegExp2(word)}(?:\\s|$)`).test(value);
13119
+ }
13120
+ function escapeRegExp2(value) {
13121
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13122
+ }
13123
+ var IMPLIED_OPERATOR_ASKS2 = [
13124
+ "need your input",
13125
+ "need your approval",
13126
+ "waiting for approval",
13127
+ "approval required",
13128
+ "awaiting sign off",
13129
+ "awaiting sign-off",
13130
+ "sign off required",
13131
+ "sign-off required",
13132
+ "need your sign off",
13133
+ "need your sign-off",
13134
+ "should i continue",
13135
+ "can you approve",
13136
+ "what should i do",
13137
+ "please review"
13138
+ ];
13139
+ var IMPLIED_OPERATOR_NEGATIONS2 = [
13140
+ "no action needed",
13141
+ "no approval needed",
13142
+ "approval is not needed",
13143
+ "approval not needed",
13144
+ "sign off not needed",
13145
+ "sign-off not needed",
13146
+ "no input needed",
13147
+ "for awareness only",
13148
+ "for your awareness",
13149
+ "continuing automatically"
13150
+ ];
13151
+ var HIGH_RISK_PHRASES2 = [
13152
+ "production",
13153
+ "prod",
13154
+ "force push",
13155
+ "git push --force",
13156
+ "rm -rf",
13157
+ "drop table",
13158
+ "delete database",
13159
+ "delete prod",
13160
+ "sudo",
13161
+ "chmod 777",
13162
+ "kill process",
13163
+ "migrate"
13164
+ ];
13165
+ var REPEAT_PHRASES2 = [
13166
+ "still",
13167
+ "again",
13168
+ "continues",
13169
+ "continuing",
13170
+ "remains",
13171
+ "persisting",
13172
+ "retrying",
13173
+ "recurred"
13174
+ ];
13175
+ var RESOLVE_PHRASES2 = [
13176
+ "resolved",
13177
+ "fixed",
13178
+ "unblocked",
13179
+ "recovered",
13180
+ "completed successfully",
13181
+ "no longer blocked",
13182
+ "succeeded after"
13183
+ ];
13184
+ var SUPERSEDE_PHRASES2 = [
13185
+ "instead",
13186
+ "superseded",
13187
+ "supersedes",
13188
+ "replaced by",
13189
+ "use this plan instead",
13190
+ "follow this plan instead"
13191
+ ];
13192
+ var ESCALATE_PHRASES2 = [
13193
+ "worse",
13194
+ "worsened",
13195
+ "escalating",
13196
+ "spread",
13197
+ "broader impact",
13198
+ "degraded further",
13199
+ "critical now",
13200
+ "now failing"
13201
+ ];
13202
+ var ISSUE_SIGNAL_PHRASES2 = [
13203
+ "fail",
13204
+ "failed",
13205
+ "failing",
13206
+ "failure",
13207
+ "error",
13208
+ "broken",
13209
+ "blocked",
13210
+ "stalled",
13211
+ "stall",
13212
+ "incident",
13213
+ "issue",
13214
+ "outage",
13215
+ "degraded",
13216
+ "retry",
13217
+ "rollback"
13218
+ ];
13219
+ function dedupeRelationHints2(hints) {
13220
+ const seen = /* @__PURE__ */ new Set();
13221
+ const result = [];
13222
+ for (const hint of hints) {
13223
+ const key = `${hint.kind}:${hint.target ?? ""}`;
13224
+ if (seen.has(key)) {
13225
+ continue;
13226
+ }
13227
+ seen.add(key);
13228
+ result.push(hint);
13229
+ }
13230
+ return result;
13231
+ }
13232
+ function semanticIntentFrameForRequestKind2(kind) {
13233
+ switch (kind) {
13234
+ case "approval":
13235
+ return "approval_request";
13236
+ case "choice":
13237
+ return "question_request";
13238
+ case "form":
13239
+ return "form_request";
13240
+ }
13241
+ }
13242
+ function semanticActivityClassForRequestKind2(kind) {
13243
+ switch (kind) {
13244
+ case "approval":
13245
+ return "permission_request";
13246
+ case "choice":
13247
+ case "form":
13248
+ return "question_request";
13249
+ }
13250
+ }
13251
+ function semanticWhyNowForRequestKind2(kind, consequence) {
13252
+ switch (kind) {
13253
+ case "approval":
13254
+ return consequence === "high" ? "A high-risk action needs explicit operator approval." : "Approval is required before work can continue.";
13255
+ case "choice":
13256
+ return "A decision is required before work can continue.";
13257
+ case "form":
13258
+ return "Additional input is required before work can continue.";
13259
+ }
13260
+ }
13261
+ function semanticWhyNowForTaskStatus2(status, options) {
13262
+ if (options?.wasCancelled) {
13263
+ return "Work was cancelled and may need review.";
13264
+ }
13265
+ switch (status) {
13266
+ case "failed":
13267
+ return "Work has failed and should be reviewed.";
13268
+ case "blocked":
13269
+ return "Work is blocked and may require operator attention.";
13270
+ case "running":
13271
+ case "waiting":
13272
+ case "completed":
13273
+ return options?.impliedAsk ? "Status text implies the operator may need to respond." : void 0;
13274
+ }
13275
+ }
13276
+ function semanticReasonsForTaskStatus2(status, options) {
13277
+ if (options?.wasCancelled) {
13278
+ return ["task cancellation is an explicit lifecycle fact"];
13279
+ }
13280
+ switch (status) {
13281
+ case "failed":
13282
+ return ["task status explicitly indicates failure"];
13283
+ case "blocked":
13284
+ return ["task status explicitly indicates blocked work"];
13285
+ case "running":
13286
+ case "waiting":
13287
+ case "completed":
13288
+ return options?.impliedAsk ? ["status wording suggests an implied operator request"] : ["task update carries a non-blocking lifecycle status"];
13289
+ }
13290
+ }
13291
+ function semanticReasonsForLifecycle2(type) {
13292
+ switch (type) {
13293
+ case "task_started":
13294
+ return ["task start is an explicit lifecycle fact"];
13295
+ case "completion":
13296
+ return ["task completion is an explicit lifecycle fact"];
13297
+ }
13298
+ }
13299
+ function interpretSourceEvent2(event) {
13300
+ const inferred = inferSemanticInterpretation2(event);
13301
+ return applySemanticHints2(inferred, event.semanticHints);
13302
+ }
13303
+ function inferSemanticInterpretation2(event) {
13304
+ switch (event.type) {
13305
+ case "task.started":
13306
+ return {
13307
+ intentFrame: "task_started",
13308
+ activityClass: "session_status",
13309
+ consequence: "low",
13310
+ factors: ["task.started"],
13311
+ relationHints: [],
13312
+ confidence: "high",
13313
+ reasons: semanticReasonsForLifecycle2("task_started")
13314
+ };
13315
+ case "task.updated":
13316
+ return inferTaskUpdateSemantics2(event);
13317
+ case "human.input.requested":
13318
+ return inferHumanInputSemantics2(event);
13319
+ case "task.completed":
13320
+ return {
13321
+ intentFrame: "completion",
13322
+ activityClass: "tool_completion",
13323
+ consequence: "low",
13324
+ factors: ["task.completed"],
13325
+ relationHints: [],
13326
+ confidence: "high",
13327
+ reasons: semanticReasonsForLifecycle2("completion")
13328
+ };
13329
+ case "task.cancelled":
13330
+ return {
13331
+ intentFrame: "cancellation",
13332
+ activityClass: "status_update",
13333
+ consequence: "low",
13334
+ ...event.reason ? { whyNow: semanticWhyNowForTaskStatus2("completed", { wasCancelled: true }) ?? "Work was cancelled and may need review." } : {},
13335
+ factors: ["task.cancelled"],
13336
+ relationHints: [],
13337
+ confidence: "high",
13338
+ reasons: semanticReasonsForTaskStatus2("completed", { wasCancelled: true })
13339
+ };
13340
+ }
13341
+ }
13342
+ function inferTaskUpdateSemantics2(event) {
13343
+ const text = normalizeSemanticText2(`${event.title} ${event.summary ?? ""}`);
13344
+ const impliedAsk = detectImpliedOperatorAsk2(text);
13345
+ const relationHints = detectSemanticRelationHints2(text);
13346
+ const taxonomyInput = buildTaxonomyInput2(event.title, event.summary, event.toolFamily);
13347
+ const toolFamily = readExplicitSemanticToolFamily2(taxonomyInput) ?? inferSemanticToolFamily2(taxonomyInput) ?? void 0;
13348
+ switch (event.status) {
13349
+ case "failed":
13350
+ return {
13351
+ intentFrame: "failure",
13352
+ activityClass: "tool_failure",
13353
+ ...toolFamily ? { toolFamily } : {},
13354
+ consequence: inferConsequenceFromSemanticText2(text, "high", toolFamily),
13355
+ whyNow: semanticWhyNowForTaskStatus2("failed") ?? "Work has failed and should be reviewed.",
13356
+ factors: ["task.updated", "failed"],
13357
+ relationHints,
13358
+ confidence: impliedAsk ? "medium" : "high",
13359
+ reasons: semanticReasonsForTaskStatus2("failed", { impliedAsk })
13360
+ };
13361
+ case "blocked":
13362
+ return {
13363
+ intentFrame: "blocked_work",
13364
+ activityClass: "status_update",
13365
+ ...toolFamily ? { toolFamily } : {},
13366
+ consequence: inferConsequenceFromSemanticText2(text, "medium", toolFamily),
13367
+ whyNow: semanticWhyNowForTaskStatus2("blocked") ?? "Work is blocked and may require operator attention.",
13368
+ factors: ["task.updated", "blocked"],
13369
+ relationHints,
13370
+ confidence: impliedAsk ? "medium" : "high",
13371
+ reasons: semanticReasonsForTaskStatus2("blocked", { impliedAsk })
13372
+ };
13373
+ case "running":
13374
+ case "waiting":
13375
+ case "completed":
13376
+ return {
13377
+ intentFrame: "status_update",
13378
+ activityClass: "status_update",
13379
+ ...toolFamily ? { toolFamily } : {},
13380
+ consequence: inferConsequenceFromSemanticText2(text, "low", toolFamily),
13381
+ ...(() => {
13382
+ const whyNow = impliedAsk ? semanticWhyNowForTaskStatus2(event.status, { impliedAsk }) : void 0;
13383
+ return whyNow !== void 0 ? { whyNow } : {};
13384
+ })(),
13385
+ factors: ["task.updated", event.status],
13386
+ relationHints,
13387
+ confidence: impliedAsk ? "low" : "high",
13388
+ reasons: semanticReasonsForTaskStatus2(event.status, { impliedAsk })
13389
+ };
13390
+ }
13391
+ }
13392
+ function inferHumanInputSemantics2(event) {
13393
+ const taxonomyInput = buildTaxonomyInput2(event.title, event.summary, event.toolFamily, event.context);
13394
+ const toolFamily = readExplicitSemanticToolFamily2(taxonomyInput) ?? inferSemanticToolFamily2(taxonomyInput) ?? void 0;
13395
+ const text = normalizeSemanticText2(`${event.title} ${event.summary}`);
13396
+ const relationHints = detectSemanticRelationHints2(text);
13397
+ const baseConsequence = event.riskHint ?? consequenceFromRequestKind2(event.request.kind, toolFamily);
13398
+ const consequence = inferConsequenceFromSemanticText2(text, baseConsequence, toolFamily);
13399
+ return {
13400
+ intentFrame: semanticIntentFrameForRequestKind2(event.request.kind),
13401
+ activityClass: semanticActivityClassForRequestKind2(event.request.kind),
13402
+ ...toolFamily ? { toolFamily } : {},
13403
+ consequence,
13404
+ whyNow: semanticWhyNowForRequestKind2(event.request.kind, consequence),
13405
+ factors: ["human.input.requested", event.request.kind],
13406
+ relationHints,
13407
+ confidence: event.riskHint ? "high" : toolFamily ? "medium" : "low",
13408
+ reasons: [
13409
+ event.riskHint ? "source provided an explicit risk hint" : "request kind establishes an explicit operator decision point",
13410
+ ...toolFamily ? ["tool family was inferred or supplied"] : []
13411
+ ]
13412
+ };
13413
+ }
13414
+ function applySemanticHints2(inferred, hints) {
13415
+ if (!hints) {
13416
+ return inferred;
13417
+ }
13418
+ return {
13419
+ ...inferred,
13420
+ ...pickDefined2(hints),
13421
+ factors: dedupeSemanticStrings2([...inferred.factors ?? [], ...hints.factors ?? []]),
13422
+ relationHints: [...hints.relationHints ?? inferred.relationHints],
13423
+ reasons: dedupeSemanticStrings2([...inferred.reasons ?? [], ...hints.reasons ?? []])
13424
+ };
13425
+ }
13426
+ function pickDefined2(value) {
13427
+ const next = {};
13428
+ for (const [key, entry] of Object.entries(value)) {
13429
+ if (entry !== void 0 && key !== "factors" && key !== "relationHints" && key !== "reasons") {
13430
+ next[key] = entry;
13431
+ }
13432
+ }
13433
+ return next;
13434
+ }
13435
+ function consequenceFromRequestKind2(kind, toolFamily) {
13436
+ switch (kind) {
13437
+ case "approval":
13438
+ if (toolFamily === "read" || toolFamily === "search") {
13439
+ return "low";
13440
+ }
13441
+ return "medium";
13442
+ case "choice":
13443
+ case "form":
13444
+ return "medium";
13445
+ }
13446
+ }
13447
+ function buildTaxonomyInput2(title, summary, toolFamily, context) {
13448
+ return {
13449
+ title,
13450
+ ...summary !== void 0 ? { summary } : {},
13451
+ ...toolFamily !== void 0 ? { toolFamily } : {},
13452
+ ...context?.items !== void 0 ? { context: { items: context.items } } : {}
13453
+ };
13454
+ }
13455
+
13456
+ // src/aperture/event-mapper.ts
13457
+ function readString2(value) {
13458
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
13459
+ }
13460
+ function readStringArray(payload, key) {
13461
+ if (!payload || typeof payload !== "object") return void 0;
13462
+ const value = payload[key];
13463
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? value : void 0;
13464
+ }
13465
+ function readPayloadString(payload, key) {
13466
+ if (!payload || typeof payload !== "object") return void 0;
13467
+ return readString2(payload[key]);
13468
+ }
13469
+ function humanizeApprovalType(value) {
13470
+ return value ? humanizeToken(value) : void 0;
13471
+ }
13472
+ function makeTaskId(event) {
13473
+ const entityType = event.entityType ?? "event";
13474
+ const entityId = event.entityId ?? event.eventId;
13475
+ return `${entityType}:${entityId}`;
13476
+ }
13477
+ function makeSource(event) {
13478
+ const entityType = event.entityType ?? "event";
13479
+ switch (entityType) {
13480
+ case "approval":
13481
+ return {
13482
+ id: `paperclip:${entityType}`,
13483
+ kind: "paperclip",
13484
+ label: "Paperclip approval"
13485
+ };
13486
+ case "issue":
13487
+ return {
13488
+ id: `paperclip:${entityType}`,
13489
+ kind: "paperclip",
13490
+ label: "Paperclip issue"
13491
+ };
13492
+ case "run":
13493
+ return {
13494
+ id: `paperclip:${entityType}`,
13495
+ kind: "paperclip",
13496
+ label: "Paperclip run"
13497
+ };
13498
+ case "agent":
13499
+ return {
13500
+ id: `paperclip:${entityType}`,
13501
+ kind: "paperclip",
13502
+ label: "Paperclip agent"
13503
+ };
13504
+ default:
13505
+ return {
13506
+ id: `paperclip:${event.eventType}`,
13507
+ kind: "paperclip",
13508
+ label: "Paperclip"
13509
+ };
13510
+ }
13511
+ }
13512
+ function inferIssueStatus(payload) {
13513
+ const raw = readPayloadString(payload, "status")?.toLowerCase();
13514
+ const summary = [
12787
13515
  readPayloadString(payload, "summary"),
12788
13516
  readPayloadString(payload, "description"),
12789
13517
  readPayloadString(payload, "bodySnippet"),
@@ -12828,6 +13556,59 @@ function issueDisplayTitle(event, fallback) {
12828
13556
  if (issueTitle2) return issueTitle2;
12829
13557
  return fallback;
12830
13558
  }
13559
+ function relationHintsForIssueTargets(issueIds) {
13560
+ if (!issueIds || issueIds.length === 0) return void 0;
13561
+ return {
13562
+ relationHints: issueIds.map((issueId) => ({
13563
+ kind: "same_issue",
13564
+ target: issueRelationTarget(issueId)
13565
+ }))
13566
+ };
13567
+ }
13568
+ function issueSemanticText(payload) {
13569
+ return [
13570
+ readPayloadString(payload, "bodySnippet"),
13571
+ readPayloadString(payload, "summary"),
13572
+ readPayloadString(payload, "description"),
13573
+ readPayloadString(payload, "title"),
13574
+ readPayloadString(payload, "issueTitle")
13575
+ ].filter((value) => !!value).join("\n");
13576
+ }
13577
+ function issueSemanticHints(event) {
13578
+ if (event.entityType !== "issue" || !event.entityId) return void 0;
13579
+ const semanticAnalysis = analyzeIssueTextSemantics({
13580
+ text: issueSemanticText(event.payload),
13581
+ identifier: readPayloadString(event.payload, "identifier"),
13582
+ issueTarget: issueRelationTarget(event.entityId)
13583
+ });
13584
+ return {
13585
+ ...semanticAnalysis.semanticConfidence ? { confidence: semanticAnalysis.semanticConfidence } : {},
13586
+ ...semanticAnalysis.relationHints.length > 0 ? { relationHints: semanticAnalysis.relationHints } : {}
13587
+ };
13588
+ }
13589
+ function approvalSemanticHints(budgetOverride, linkedIssueIds) {
13590
+ return {
13591
+ whyNow: approvalBlockingWhyNow(budgetOverride),
13592
+ factors: budgetOverride ? ["budget stop", "approval", "operator decision"] : ["approval", "operator decision"],
13593
+ ...relationHintsForIssueTargets(linkedIssueIds) ?? {}
13594
+ };
13595
+ }
13596
+ function pendingApprovalSemanticHints() {
13597
+ return {
13598
+ whyNow: pendingApprovalEventWhyNow(),
13599
+ factors: ["pending approval"]
13600
+ };
13601
+ }
13602
+ function runFailureSemanticHints() {
13603
+ return {
13604
+ intentFrame: "failure",
13605
+ whyNow: runFailedWhyNow(),
13606
+ factors: ["run failed", "operator review"]
13607
+ };
13608
+ }
13609
+ function interpretEventSemantic(event) {
13610
+ return interpretSourceEvent2(event);
13611
+ }
12831
13612
  function mapPluginEventToAperture(event) {
12832
13613
  const eventType = event.eventType;
12833
13614
  const taskId = makeTaskId(event);
@@ -12839,6 +13620,24 @@ function mapPluginEventToAperture(event) {
12839
13620
  const requestedAmount = readPayloadString(event.payload, "requestedAmount");
12840
13621
  const reason = readPayloadString(event.payload, "reason");
12841
13622
  const decisionContext = readPayloadString(event.payload, "decisionContext");
13623
+ const linkedIssueIds = readStringArray(event.payload, "issueIds");
13624
+ const title = approvalTitle(event);
13625
+ const summary = readPayloadString(event.payload, "summary") ?? approvalBlockingSummary(budgetOverride);
13626
+ const semantic = interpretEventSemantic({
13627
+ id: `${event.eventId}:approval`,
13628
+ type: "human.input.requested",
13629
+ taskId,
13630
+ interactionId: `${taskId}:approval`,
13631
+ timestamp: event.occurredAt,
13632
+ source,
13633
+ toolFamily: "paperclip",
13634
+ activityClass: "permission_request",
13635
+ title,
13636
+ summary,
13637
+ request: { kind: "approval" },
13638
+ riskHint: budgetOverride ? "high" : "medium",
13639
+ semanticHints: approvalSemanticHints(budgetOverride, linkedIssueIds)
13640
+ });
12842
13641
  return {
12843
13642
  id: `${event.eventId}:approval`,
12844
13643
  type: "human.input.requested",
@@ -12848,18 +13647,19 @@ function mapPluginEventToAperture(event) {
12848
13647
  source,
12849
13648
  toolFamily: "paperclip",
12850
13649
  activityClass: "permission_request",
12851
- title: approvalTitle(event),
12852
- summary: readPayloadString(event.payload, "summary") ?? approvalBlockingSummary(budgetOverride),
13650
+ title,
13651
+ summary,
12853
13652
  consequence: budgetOverride ? "high" : "medium",
12854
13653
  tone: "focused",
12855
13654
  request: { kind: "approval" },
13655
+ semantic,
12856
13656
  context: {
12857
13657
  items: [
12858
13658
  ...humanizeApprovalType(type) ? [approvalTypeItem(humanizeApprovalType(type))] : [],
12859
13659
  ...requestedAmount ? [requestedAmountItem(requestedAmount)] : [],
12860
13660
  ...reason ? [budgetReasonItem(reason)] : [],
12861
13661
  ...decisionContext ? [decisionContextItem(decisionContext)] : [],
12862
- ...readStringArrayLength(event.payload, "issueIds") ? [linkedIssuesItem(String(readStringArrayLength(event.payload, "issueIds")))] : []
13662
+ ...linkedIssueIds?.length ? [linkedIssuesItem(String(linkedIssueIds.length))] : []
12863
13663
  ]
12864
13664
  },
12865
13665
  provenance: {
@@ -12880,52 +13680,110 @@ function mapPluginEventToAperture(event) {
12880
13680
  source,
12881
13681
  summary: readPayloadString(event.payload, "status") ?? (eventType === "approval.approved" ? "Approval approved" : eventType === "approval.rejected" ? "Approval rejected" : eventType === "approval.revision_requested" ? "Revision requested" : "Approval resolved")
12882
13682
  };
12883
- case "issue.created":
12884
- return inferIssueStatus(event.payload) === "running" ? {
13683
+ case "issue.created": {
13684
+ const title = issueDisplayTitle(event, "Issue created");
13685
+ const summary = readPayloadString(event.payload, "description") ?? "A new issue entered Paperclip.";
13686
+ const status = inferIssueStatus(event.payload);
13687
+ return status === "running" ? {
12885
13688
  id: `${event.eventId}:issue-created`,
12886
13689
  type: "task.started",
12887
13690
  taskId,
12888
13691
  timestamp: event.occurredAt,
12889
13692
  source,
12890
- title: issueDisplayTitle(event, "Issue created"),
12891
- summary: readPayloadString(event.payload, "description") ?? "A new issue entered Paperclip."
13693
+ title,
13694
+ summary,
13695
+ semantic: interpretEventSemantic({
13696
+ id: `${event.eventId}:issue-created`,
13697
+ type: "task.started",
13698
+ taskId,
13699
+ timestamp: event.occurredAt,
13700
+ source,
13701
+ title,
13702
+ summary,
13703
+ semanticHints: issueSemanticHints(event)
13704
+ })
12892
13705
  } : {
12893
13706
  id: `${event.eventId}:issue-created-status`,
12894
13707
  type: "task.updated",
12895
13708
  taskId,
12896
13709
  timestamp: event.occurredAt,
12897
13710
  source,
12898
- title: issueDisplayTitle(event, "Issue created"),
12899
- summary: readPayloadString(event.payload, "description") ?? "A new issue entered Paperclip.",
13711
+ title,
13712
+ summary,
12900
13713
  activityClass: "status_update",
12901
- status: inferIssueStatus(event.payload)
13714
+ status,
13715
+ semantic: interpretEventSemantic({
13716
+ id: `${event.eventId}:issue-created-status`,
13717
+ type: "task.updated",
13718
+ taskId,
13719
+ timestamp: event.occurredAt,
13720
+ source,
13721
+ title,
13722
+ summary,
13723
+ activityClass: "status_update",
13724
+ status,
13725
+ semanticHints: issueSemanticHints(event)
13726
+ })
12902
13727
  };
12903
- case "issue.updated":
13728
+ }
13729
+ case "issue.updated": {
13730
+ const title = issueDisplayTitle(event, "Issue updated");
13731
+ const summary = readPayloadString(event.payload, "summary") ?? readPayloadString(event.payload, "description");
13732
+ const status = inferIssueStatus(event.payload);
12904
13733
  return {
12905
13734
  id: `${event.eventId}:issue-updated`,
12906
13735
  type: "task.updated",
12907
13736
  taskId,
12908
13737
  timestamp: event.occurredAt,
12909
13738
  source,
12910
- title: issueDisplayTitle(event, "Issue updated"),
12911
- summary: readPayloadString(event.payload, "summary") ?? readPayloadString(event.payload, "description"),
13739
+ title,
13740
+ summary,
12912
13741
  activityClass: "status_update",
12913
- status: inferIssueStatus(event.payload)
13742
+ status,
13743
+ semantic: interpretEventSemantic({
13744
+ id: `${event.eventId}:issue-updated`,
13745
+ type: "task.updated",
13746
+ taskId,
13747
+ timestamp: event.occurredAt,
13748
+ source,
13749
+ title,
13750
+ ...summary !== void 0 ? { summary } : {},
13751
+ activityClass: "status_update",
13752
+ status,
13753
+ semanticHints: issueSemanticHints(event)
13754
+ })
12914
13755
  };
13756
+ }
12915
13757
  case "issue.comment.created":
12916
- case "issue.comment_added":
13758
+ case "issue.comment_added": {
13759
+ const title = issueDisplayTitle(event, "Issue comment");
13760
+ const summary = readPayloadString(event.payload, "bodySnippet") ?? "A comment added new context in Paperclip.";
13761
+ const status = inferIssueStatus(event.payload);
12917
13762
  return {
12918
13763
  id: `${event.eventId}:issue-comment`,
12919
13764
  type: "task.updated",
12920
13765
  taskId,
12921
13766
  timestamp: event.occurredAt,
12922
13767
  source,
12923
- title: issueDisplayTitle(event, "Issue comment"),
12924
- summary: readPayloadString(event.payload, "bodySnippet") ?? "A comment added new context in Paperclip.",
13768
+ title,
13769
+ summary,
12925
13770
  activityClass: "follow_up",
12926
- status: inferIssueStatus(event.payload),
12927
- progress: void 0
13771
+ status,
13772
+ progress: void 0,
13773
+ semantic: interpretEventSemantic({
13774
+ id: `${event.eventId}:issue-comment`,
13775
+ type: "task.updated",
13776
+ taskId,
13777
+ timestamp: event.occurredAt,
13778
+ source,
13779
+ title,
13780
+ summary,
13781
+ activityClass: "follow_up",
13782
+ status,
13783
+ semanticHints: issueSemanticHints(event)
13784
+ })
12928
13785
  };
13786
+ }
12929
13787
  case "agent.run.started":
12930
13788
  return {
12931
13789
  id: `${event.eventId}:run-started`,
@@ -12936,7 +13794,9 @@ function mapPluginEventToAperture(event) {
12936
13794
  title: readPayloadString(event.payload, "title") ?? "Agent run started",
12937
13795
  summary: readPayloadString(event.payload, "summary") ?? "A Paperclip agent began a new run."
12938
13796
  };
12939
- case "agent.run.failed":
13797
+ case "agent.run.failed": {
13798
+ const title = readPayloadString(event.payload, "title") ?? "Agent run failed";
13799
+ const summary = readPayloadString(event.payload, "summary") ?? runFailedSummary();
12940
13800
  return {
12941
13801
  id: `${event.eventId}:run-failed`,
12942
13802
  type: "human.input.requested",
@@ -12946,16 +13806,32 @@ function mapPluginEventToAperture(event) {
12946
13806
  source,
12947
13807
  toolFamily: "paperclip",
12948
13808
  activityClass: "tool_failure",
12949
- title: readPayloadString(event.payload, "title") ?? "Agent run failed",
12950
- summary: readPayloadString(event.payload, "summary") ?? runFailedSummary(),
13809
+ title,
13810
+ summary,
12951
13811
  consequence: "high",
12952
13812
  tone: "critical",
12953
13813
  request: { kind: "approval" },
13814
+ semantic: interpretEventSemantic({
13815
+ id: `${event.eventId}:run-failed`,
13816
+ type: "human.input.requested",
13817
+ taskId,
13818
+ interactionId: `${taskId}:run-failed`,
13819
+ timestamp: event.occurredAt,
13820
+ source,
13821
+ toolFamily: "paperclip",
13822
+ activityClass: "tool_failure",
13823
+ title,
13824
+ summary,
13825
+ request: { kind: "approval" },
13826
+ riskHint: "high",
13827
+ semanticHints: runFailureSemanticHints()
13828
+ }),
12954
13829
  provenance: {
12955
13830
  whyNow: runFailedWhyNow(),
12956
13831
  factors: ["run failed", "operator review"]
12957
13832
  }
12958
13833
  };
13834
+ }
12959
13835
  case "agent.run.finished":
12960
13836
  return {
12961
13837
  id: `${event.eventId}:run-finished`,
@@ -12977,6 +13853,8 @@ function mapPluginEventToAperture(event) {
12977
13853
  case "agent.status_changed": {
12978
13854
  const status = readPayloadString(event.payload, "status")?.toLowerCase();
12979
13855
  if (status === "pending_approval") {
13856
+ const title2 = pendingApprovalEventTitle();
13857
+ const summary2 = pendingApprovalEventSummary();
12980
13858
  return {
12981
13859
  id: `${event.eventId}:status-pending-approval`,
12982
13860
  type: "human.input.requested",
@@ -12986,27 +13864,56 @@ function mapPluginEventToAperture(event) {
12986
13864
  source,
12987
13865
  toolFamily: "paperclip",
12988
13866
  activityClass: "permission_request",
12989
- title: pendingApprovalEventTitle(),
12990
- summary: pendingApprovalEventSummary(),
13867
+ title: title2,
13868
+ summary: summary2,
12991
13869
  consequence: "medium",
12992
13870
  tone: "focused",
12993
13871
  request: { kind: "approval" },
13872
+ semantic: interpretEventSemantic({
13873
+ id: `${event.eventId}:status-pending-approval`,
13874
+ type: "human.input.requested",
13875
+ taskId,
13876
+ interactionId: `${taskId}:pending-approval`,
13877
+ timestamp: event.occurredAt,
13878
+ source,
13879
+ toolFamily: "paperclip",
13880
+ activityClass: "permission_request",
13881
+ title: title2,
13882
+ summary: summary2,
13883
+ request: { kind: "approval" },
13884
+ riskHint: "medium",
13885
+ semanticHints: pendingApprovalSemanticHints()
13886
+ }),
12994
13887
  provenance: {
12995
13888
  whyNow: pendingApprovalEventWhyNow(),
12996
13889
  factors: ["pending approval"]
12997
13890
  }
12998
13891
  };
12999
13892
  }
13893
+ const normalizedStatus = inferAgentStatus(event.payload);
13894
+ const title = "Agent status changed";
13895
+ const summary = status ? `Agent status is now ${status}.` : "Agent status changed.";
13000
13896
  return {
13001
13897
  id: `${event.eventId}:status-updated`,
13002
13898
  type: "task.updated",
13003
13899
  taskId,
13004
13900
  timestamp: event.occurredAt,
13005
13901
  source,
13006
- title: "Agent status changed",
13007
- summary: status ? `Agent status is now ${status}.` : "Agent status changed.",
13902
+ title,
13903
+ summary,
13008
13904
  activityClass: "session_status",
13009
- status: inferAgentStatus(event.payload)
13905
+ status: normalizedStatus,
13906
+ semantic: interpretEventSemantic({
13907
+ id: `${event.eventId}:status-updated`,
13908
+ type: "task.updated",
13909
+ taskId,
13910
+ timestamp: event.occurredAt,
13911
+ source,
13912
+ title,
13913
+ summary,
13914
+ activityClass: "session_status",
13915
+ status: normalizedStatus
13916
+ })
13010
13917
  };
13011
13918
  }
13012
13919
  default: