@adhdev/mesh-shared 1.0.82-rc.34 → 1.0.82-rc.35

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/index.mjs CHANGED
@@ -1109,9 +1109,15 @@ var DAEMON_STATUS_EVENT_NAMES = [
1109
1109
  "agent:waiting_choice",
1110
1110
  "agent:generating_completed",
1111
1111
  "agent:stopped",
1112
- "monitor:no_progress"
1112
+ "monitor:no_progress",
1113
+ // An owner decision (structured missions) needs the owner. Server-bound for the push only;
1114
+ // the dashboard learns about decisions over P2P (`mission_decisions_list`).
1115
+ "agent:decision_needed"
1113
1116
  ];
1114
1117
  var isDaemonStatusEventName = makeTypeGuard(DAEMON_STATUS_EVENT_NAMES);
1118
+ var DECISION_PUSH_QUESTION_MAX = 80;
1119
+ var DECISION_PUSH_OPTION_LABEL_MAX = 24;
1120
+ var DECISION_PUSH_OPTIONS_MAX = 3;
1115
1121
  var RELEASE_CHANNELS = ["stable", "preview"];
1116
1122
  var NPM_UPDATE_TAGS = ["latest", "next"];
1117
1123
  var VERSION_UPDATE_REASONS = ["force_update_below", "major_minor_mismatch", "patch_mismatch", "daemon_ahead"];
@@ -1685,6 +1691,10 @@ var WORKER_TOOLS = [
1685
1691
  "driver_list",
1686
1692
  "driver_describe",
1687
1693
  "driver_invoke",
1694
+ "driver_scaffold",
1695
+ "driver_validate",
1696
+ "driver_export",
1697
+ "driver_install",
1688
1698
  "artifact_register",
1689
1699
  "artifact_list",
1690
1700
  "artifact_read",
@@ -1795,7 +1805,9 @@ var ASSISTANT_TOOLS = [
1795
1805
  "driver_list",
1796
1806
  "driver_describe",
1797
1807
  "artifact_list",
1798
- "artifact_read"
1808
+ "artifact_read",
1809
+ "decision_answer",
1810
+ "decision_request"
1799
1811
  ];
1800
1812
  var ASSISTANT_TOOL_SET = new Set(ASSISTANT_TOOLS);
1801
1813
  function isAssistantTool(value) {
@@ -1825,6 +1837,10 @@ var ASSISTANT_VERB = {
1825
1837
  launchDefaultsSet: "assistant_launch_defaults_set",
1826
1838
  artifactList: "assistant_artifact_list",
1827
1839
  artifactRead: "assistant_artifact_read",
1840
+ /** Owner-decision inbox (structured-missions design 2026-10-28 §6.3): the owner's words recorded as answers. */
1841
+ decisionAnswer: "assistant_decision_answer",
1842
+ /** Register a plain-text question a coordinator put to the owner as a decision item (§5.2). */
1843
+ decisionRequest: "assistant_decision_request",
1828
1844
  // assistant-side daemon verbs without a tool of the same name
1829
1845
  launch: "launch_assistant",
1830
1846
  pendingRelays: "assistant_pending_relays",
@@ -1856,9 +1872,11 @@ var ASSISTANT_TOOL_VERBS = {
1856
1872
  launch_defaults: ASSISTANT_VERB.launchDefaults,
1857
1873
  launch_defaults_set: ASSISTANT_VERB.launchDefaultsSet,
1858
1874
  artifact_list: ASSISTANT_VERB.artifactList,
1859
- artifact_read: ASSISTANT_VERB.artifactRead
1875
+ artifact_read: ASSISTANT_VERB.artifactRead,
1876
+ decision_answer: ASSISTANT_VERB.decisionAnswer,
1877
+ decision_request: ASSISTANT_VERB.decisionRequest
1860
1878
  };
1861
- var ASSISTANT_WRITE_TOOLS = ["project_watch", "assistant_action", "memory", "skill_manage", "project_note", "project_send", "project_add", "project_attach_remote", "launch_defaults_set"];
1879
+ var ASSISTANT_WRITE_TOOLS = ["project_watch", "assistant_action", "memory", "skill_manage", "project_note", "project_send", "project_add", "project_attach_remote", "launch_defaults_set", "decision_answer", "decision_request"];
1862
1880
  var ASSISTANT_OWNER_VERBS = [
1863
1881
  ASSISTANT_VERB.executionSettings,
1864
1882
  ASSISTANT_VERB.stagedResolve,
@@ -1879,11 +1897,22 @@ var ASSISTANT_REMOTE_PROJECT_COMMAND = "assistant_remote_project";
1879
1897
  var ASSISTANT_REMOTE_PROJECT_CATALOG_COMMAND = "assistant_remote_project_catalog";
1880
1898
  var ASSISTANT_REMOTE_PROJECT_ACCESS_COMMAND = "assistant_remote_project_access";
1881
1899
  var ASSISTANT_REMOTE_FOLLOW_COMMAND = "assistant_remote_follow";
1882
- var ASSISTANT_FOLLOWER_ALLOWED_OPS = ["status", "read", "poll", "report", "send", "artifact_list", "artifact_read"];
1900
+ var ASSISTANT_FOLLOWER_ALLOWED_OPS = ["status", "read", "poll", "report", "send", "artifact_list", "artifact_read", "decision_list", "decision_answer", "decision_request"];
1883
1901
  var ASSISTANT_FOLLOWER_ALLOWED_OP_SET = new Set(ASSISTANT_FOLLOWER_ALLOWED_OPS);
1884
1902
  function isAssistantFollowerAllowedOp(value) {
1885
1903
  return typeof value === "string" && ASSISTANT_FOLLOWER_ALLOWED_OP_SET.has(value);
1886
1904
  }
1905
+ var DECISION_OP_IMPLIED_BY = {
1906
+ decision_list: "status",
1907
+ decision_answer: "send",
1908
+ decision_request: "send"
1909
+ };
1910
+ function followerOpPermitted(op, allowedOps) {
1911
+ if (!isAssistantFollowerAllowedOp(op)) return false;
1912
+ if (allowedOps.includes(op)) return true;
1913
+ const implied = DECISION_OP_IMPLIED_BY[op];
1914
+ return implied !== void 0 && allowedOps.includes(implied);
1915
+ }
1887
1916
  function followedRemoteProjectKey(hostDaemonId, meshId) {
1888
1917
  const canonHost = canonicalDaemonId(hostDaemonId) ?? hostDaemonId.trim();
1889
1918
  return `${canonHost}::${meshId.trim()}`;
@@ -2782,8 +2811,23 @@ function isMissionBriefWire(value) {
2782
2811
  }
2783
2812
  return true;
2784
2813
  }
2814
+ var STRUCTURED_MISSION_KEYS = ["summary", "outcome", "outcomeReason", "version", "carryOver", "openItems"];
2815
+ function isOpenItemCountsWire(value) {
2816
+ if (!isRecord(value) || !hasOnlyKeys2(value, ["remaining", "live_check", "decision", "evidence"])) return false;
2817
+ return ["remaining", "live_check", "decision", "evidence"].every((k) => isNonNegativeInt(value[k]));
2818
+ }
2819
+ function isStructuredMissionFields(value) {
2820
+ for (const k of ["summary", "outcome", "outcomeReason"]) {
2821
+ if (value[k] !== void 0 && typeof value[k] !== "string") return false;
2822
+ }
2823
+ if (value.version !== void 0 && !isNonNegativeInt(value.version)) return false;
2824
+ if (value.carryOver !== void 0 && typeof value.carryOver !== "boolean") return false;
2825
+ if (value.openItems !== void 0 && !isOpenItemCountsWire(value.openItems)) return false;
2826
+ return true;
2827
+ }
2785
2828
  function isMeshMissionRecordWire(value) {
2786
- if (!isRecord(value) || !hasOnlyKeys2(value, ["id", "meshId", "title", "goal", "status", "brief"])) return false;
2829
+ if (!isRecord(value) || !hasOnlyKeys2(value, ["id", "meshId", "title", "goal", "status", "brief", ...STRUCTURED_MISSION_KEYS])) return false;
2830
+ if (!isStructuredMissionFields(value)) return false;
2787
2831
  if (!isEvidenceIdentifier(value.id) || !isEvidenceIdentifier(value.meshId)) return false;
2788
2832
  if (typeof value.title !== "string" || typeof value.goal !== "string") return false;
2789
2833
  if (!isMeshMissionStatusValue(value.status)) return false;
@@ -2791,11 +2835,22 @@ function isMeshMissionRecordWire(value) {
2791
2835
  return true;
2792
2836
  }
2793
2837
  function isMissionUpsertRequest(value) {
2794
- if (!isRecord(value) || !hasOnlyKeys2(value, ["v", "meshId", "id", "title", "goal", "status", "brief"])) return false;
2838
+ if (!isRecord(value) || !hasOnlyKeys2(value, ["v", "meshId", "id", "title", "goal", "status", "brief", "structured", "summary", "outcome", "outcomeReason", "carryOverTo", "toCarryOver", "itemsAdd", "itemsUpdate"])) return false;
2795
2839
  if (value.v !== TURN_IPC_PROTOCOL_VERSION) return false;
2796
2840
  if (!isEvidenceIdentifier(value.meshId)) return false;
2797
2841
  if (value.id !== void 0 && !isEvidenceIdentifier(value.id)) return false;
2798
- if (typeof value.title !== "string" || value.title.trim().length === 0) return false;
2842
+ if (typeof value.title !== "string") return false;
2843
+ if (value.title.trim().length === 0 && value.toCarryOver !== true && value.id === void 0) return false;
2844
+ if (value.structured !== void 0 && typeof value.structured !== "boolean") return false;
2845
+ if (value.toCarryOver !== void 0 && typeof value.toCarryOver !== "boolean") return false;
2846
+ for (const k of ["summary", "outcome", "outcomeReason"]) {
2847
+ if (value[k] !== void 0 && typeof value[k] !== "string") return false;
2848
+ }
2849
+ if (value.carryOverTo !== void 0 && !isEvidenceIdentifier(value.carryOverTo)) return false;
2850
+ for (const k of ["itemsAdd", "itemsUpdate"]) {
2851
+ const list = value[k];
2852
+ if (list !== void 0 && (!Array.isArray(list) || list.length > 500 || !list.every(isRecord))) return false;
2853
+ }
2799
2854
  if (value.goal !== void 0 && typeof value.goal !== "string") return false;
2800
2855
  if (value.status !== void 0 && !isMeshMissionStatusValue(value.status)) return false;
2801
2856
  if (value.brief !== void 0 && value.brief !== null && !isMissionBriefWire(value.brief)) return false;
@@ -2805,7 +2860,7 @@ function decodeMissionUpsertRequest(value) {
2805
2860
  return isMissionUpsertRequest(value) ? value : null;
2806
2861
  }
2807
2862
  function isMissionUpsertResponse(value) {
2808
- return isRecord(value) && hasOnlyKeys2(value, ["mission"]) && isMeshMissionRecordWire(value.mission);
2863
+ return isRecord(value) && hasOnlyKeys2(value, ["mission", "result"]) && isMeshMissionRecordWire(value.mission) && (value.result === void 0 || isRecord(value.result));
2809
2864
  }
2810
2865
  function decodeMissionUpsertResponse(value) {
2811
2866
  return isMissionUpsertResponse(value) ? value : null;
@@ -2831,7 +2886,10 @@ function decodeMissionQueryResponse(value) {
2831
2886
  return isMissionQueryResponse(value) ? value : null;
2832
2887
  }
2833
2888
  function isMissionListQueryRequest(value) {
2834
- if (!isRecord(value) || !hasOnlyKeys2(value, ["v", "meshId", "statuses", "verbose", "withStats", "limit", "historyIdLimit", "meshStatusView"])) return false;
2889
+ if (!isRecord(value) || !hasOnlyKeys2(value, ["v", "meshId", "statuses", "verbose", "withStats", "limit", "historyIdLimit", "meshStatusView", "structured", "items", "history"])) return false;
2890
+ for (const k of ["structured", "items", "history"]) {
2891
+ if (value[k] !== void 0 && typeof value[k] !== "boolean") return false;
2892
+ }
2835
2893
  if (value.meshStatusView !== void 0 && value.meshStatusView !== "compact" && value.meshStatusView !== "verbose") return false;
2836
2894
  if (value.v !== TURN_IPC_PROTOCOL_VERSION) return false;
2837
2895
  if (!isEvidenceIdentifier(value.meshId)) return false;
@@ -2873,7 +2931,7 @@ function isMissionListSummaryWire(value) {
2873
2931
  const hasGoal = "goal" in value;
2874
2932
  const hasPreview = "goalPreview" in value && "goalTruncated" in value;
2875
2933
  if (hasGoal === hasPreview) return false;
2876
- const baseKeys = ["id", "meshId", "title", "status", "tasks", "stats", "brief", "createdAt", "updatedAt", "closeCandidateEmittedAt"];
2934
+ const baseKeys = ["id", "meshId", "title", "status", "tasks", "stats", "brief", "createdAt", "updatedAt", "closeCandidateEmittedAt", ...STRUCTURED_MISSION_KEYS, "items", "history"];
2877
2935
  const allowed = hasGoal ? [...baseKeys, "goal"] : [...baseKeys, "goalPreview", "goalTruncated"];
2878
2936
  if (!hasOnlyKeys2(value, allowed)) return false;
2879
2937
  if (!isEvidenceIdentifier(value.id) || !isEvidenceIdentifier(value.meshId)) return false;
@@ -2887,6 +2945,10 @@ function isMissionListSummaryWire(value) {
2887
2945
  if (value.createdAt !== void 0 && typeof value.createdAt !== "string") return false;
2888
2946
  if (value.updatedAt !== void 0 && typeof value.updatedAt !== "string") return false;
2889
2947
  if (value.closeCandidateEmittedAt !== void 0 && value.closeCandidateEmittedAt !== null && typeof value.closeCandidateEmittedAt !== "string") return false;
2948
+ if (!isStructuredMissionFields(value)) return false;
2949
+ for (const k of ["items", "history"]) {
2950
+ if (value[k] !== void 0 && (!Array.isArray(value[k]) || !value[k].every(isRecord))) return false;
2951
+ }
2890
2952
  return true;
2891
2953
  }
2892
2954
  function isMeshMissionHistoryFoldWire(value) {
@@ -3409,6 +3471,282 @@ function touchedFilesOutsideOwnership(touched, owned) {
3409
3471
  return { undeclaredTouched, unusedDeclarations };
3410
3472
  }
3411
3473
 
3474
+ // src/mission-items.ts
3475
+ var MISSION_ITEM_KINDS = ["remaining", "live_check", "decision", "evidence"];
3476
+ var MISSION_ITEM_STATES = ["open", "done", "dropped", "moved", "answered", "expired", "withdrawn", "superseded"];
3477
+ var COORDINATOR_SETTABLE_ITEM_STATES = {
3478
+ remaining: ["open", "done", "dropped"],
3479
+ live_check: ["open", "done", "dropped"],
3480
+ evidence: ["open", "done", "dropped"],
3481
+ decision: ["open", "withdrawn", "superseded"]
3482
+ };
3483
+ var MISSION_OUTCOMES = ["merged", "verified_live", "superseded", "not_needed", "owner_abandoned", "unspecified"];
3484
+ function isMissionOutcome(value) {
3485
+ return typeof value === "string" && MISSION_OUTCOMES.includes(value);
3486
+ }
3487
+ var MISSION_REF_KINDS = ["commit", "branch", "pr", "task", "artifact", "mission", "url"];
3488
+ var MISSION_LIMITS = {
3489
+ summary: 300,
3490
+ outcomeReason: 500,
3491
+ itemText: 300,
3492
+ machine: 80,
3493
+ refs: 8,
3494
+ refValue: 300,
3495
+ refRepo: 120,
3496
+ refNote: 200,
3497
+ dedupeKey: 400,
3498
+ question: 300,
3499
+ context: 600,
3500
+ options: 5,
3501
+ optionLabel: 60,
3502
+ optionDetail: 200,
3503
+ /** Open items per mission before the oldest `remaining` fold into a "N more" summary item. */
3504
+ openItemsPerMission: 200,
3505
+ /** One event payload (serialized). */
3506
+ eventPayloadBytes: 16 * 1024,
3507
+ /** items_add / items_update entries honoured per call (extra entries are reported, not applied). */
3508
+ itemsPerCall: 50
3509
+ };
3510
+ var MISSION_DECISION_OPTION_IDS = ["a", "b", "c", "d", "e"];
3511
+ var MISSION_DECISION_URGENCIES = ["normal", "blocking"];
3512
+ var MISSION_DECISION_ON_DUE = ["remind", "apply_recommended"];
3513
+ function truncateMissionText(value, max) {
3514
+ if (value.length <= max) return value;
3515
+ return `${value.slice(0, max - 1).trimEnd()}\u2026`;
3516
+ }
3517
+ function str(value) {
3518
+ return typeof value === "string" ? value.trim() : "";
3519
+ }
3520
+ function collapse(value) {
3521
+ return value.replace(/\s+/g, " ").trim();
3522
+ }
3523
+ function normalizeMissionSummary(value) {
3524
+ if (typeof value !== "string") return null;
3525
+ const text = collapse(value);
3526
+ return { value: truncateMissionText(text, MISSION_LIMITS.summary), truncated: text.length > MISSION_LIMITS.summary };
3527
+ }
3528
+ function normalizeOutcomeReason(value) {
3529
+ if (typeof value !== "string") return null;
3530
+ const text = value.trim();
3531
+ return { value: truncateMissionText(text, MISSION_LIMITS.outcomeReason), truncated: text.length > MISSION_LIMITS.outcomeReason };
3532
+ }
3533
+ function normalizeMissionRefs(value) {
3534
+ if (!Array.isArray(value)) return { refs: [], truncated: false };
3535
+ const refs = [];
3536
+ let truncated = false;
3537
+ for (const raw of value) {
3538
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
3539
+ const r = raw;
3540
+ const kind = str(r.kind);
3541
+ const refValue = str(r.value);
3542
+ if (!MISSION_REF_KINDS.includes(kind) || !refValue) continue;
3543
+ if (refs.length >= MISSION_LIMITS.refs) {
3544
+ truncated = true;
3545
+ break;
3546
+ }
3547
+ const repo = str(r.repo);
3548
+ const note = str(r.note);
3549
+ refs.push({
3550
+ kind,
3551
+ ...repo ? { repo: truncateMissionText(repo, MISSION_LIMITS.refRepo) } : {},
3552
+ value: truncateMissionText(refValue, MISSION_LIMITS.refValue),
3553
+ ...note ? { note: truncateMissionText(note, MISSION_LIMITS.refNote) } : {}
3554
+ });
3555
+ }
3556
+ return { refs, truncated };
3557
+ }
3558
+ function normalizeOptions(value, truncated) {
3559
+ if (!Array.isArray(value)) return [];
3560
+ const out = [];
3561
+ for (const raw of value) {
3562
+ if (typeof raw === "string" && raw.trim()) {
3563
+ if (out.length >= MISSION_LIMITS.options) {
3564
+ truncated.push("options");
3565
+ break;
3566
+ }
3567
+ out.push({ id: MISSION_DECISION_OPTION_IDS[out.length], label: truncateMissionText(raw.trim(), MISSION_LIMITS.optionLabel) });
3568
+ continue;
3569
+ }
3570
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
3571
+ const o = raw;
3572
+ const label = collapse(str(o.label));
3573
+ if (!label) continue;
3574
+ if (out.length >= MISSION_LIMITS.options) {
3575
+ truncated.push("options");
3576
+ break;
3577
+ }
3578
+ const detail = str(o.detail);
3579
+ out.push({
3580
+ id: MISSION_DECISION_OPTION_IDS[out.length],
3581
+ label: truncateMissionText(label, MISSION_LIMITS.optionLabel),
3582
+ ...detail ? { detail: truncateMissionText(detail, MISSION_LIMITS.optionDetail) } : {}
3583
+ });
3584
+ }
3585
+ return out;
3586
+ }
3587
+ function normalizeDueAt(value) {
3588
+ if (typeof value !== "string" || !value.trim()) return void 0;
3589
+ const ms2 = Date.parse(value);
3590
+ return Number.isNaN(ms2) ? void 0 : new Date(ms2).toISOString();
3591
+ }
3592
+ function normalizeDecisionInput(raw, truncated) {
3593
+ const questionSource = collapse(str(raw.question) || str(raw.text));
3594
+ if (!questionSource) return null;
3595
+ if (questionSource.length > MISSION_LIMITS.question) truncated.push("question");
3596
+ const question = truncateMissionText(questionSource, MISSION_LIMITS.question);
3597
+ const contextSource = str(raw.context);
3598
+ if (contextSource.length > MISSION_LIMITS.context) truncated.push("context");
3599
+ const options = normalizeOptions(raw.options, truncated);
3600
+ const recommendedRaw = str(raw.recommended);
3601
+ const recommended = recommendedRaw && options.some((o) => o.id === recommendedRaw) ? recommendedRaw : options.find((o) => recommendedRaw && o.label.toLowerCase() === recommendedRaw.toLowerCase())?.id;
3602
+ const dueAt = normalizeDueAt(raw.dueAt ?? raw.due_at);
3603
+ const onDueRaw = str(raw.onDue ?? raw.on_due);
3604
+ const urgencyRaw = str(raw.urgency);
3605
+ const allowFreeTextRaw = raw.allowFreeText ?? raw.allow_free_text;
3606
+ return {
3607
+ question,
3608
+ ...contextSource ? { context: truncateMissionText(contextSource, MISSION_LIMITS.context) } : {},
3609
+ options,
3610
+ ...recommended ? { recommended } : {},
3611
+ allowFreeText: typeof allowFreeTextRaw === "boolean" ? allowFreeTextRaw : true,
3612
+ ...dueAt ? { dueAt } : {},
3613
+ // apply_recommended without a recommended option has nothing to apply — fall back to remind.
3614
+ onDue: onDueRaw === "apply_recommended" && recommended ? "apply_recommended" : "remind",
3615
+ urgency: urgencyRaw === "blocking" ? "blocking" : "normal"
3616
+ };
3617
+ }
3618
+ function normalizeForDedupe(text) {
3619
+ return collapse(text).toLowerCase().replace(/[\s.!?。]+$/u, "");
3620
+ }
3621
+ function deriveItemDedupeKey(kind, parts) {
3622
+ const explicit = str(parts.explicit);
3623
+ if (explicit) return truncateMissionText(`k:${explicit}`, MISSION_LIMITS.dedupeKey);
3624
+ if (kind === "decision") return truncateMissionText(`decision:${normalizeForDedupe(parts.question ?? parts.text ?? "")}`, MISSION_LIMITS.dedupeKey);
3625
+ if (kind === "evidence") {
3626
+ const ref2 = parts.refs?.[0];
3627
+ if (ref2) return truncateMissionText(`evidence:${ref2.kind}:${ref2.repo ?? ""}:${ref2.value}`, MISSION_LIMITS.dedupeKey);
3628
+ }
3629
+ const machine = parts.machine ? `@${normalizeForDedupe(parts.machine)}` : "";
3630
+ return truncateMissionText(`${kind}${machine}:${normalizeForDedupe(parts.text ?? "")}`, MISSION_LIMITS.dedupeKey);
3631
+ }
3632
+ function normalizeMissionItemInput(raw) {
3633
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { error: "item must be an object" };
3634
+ const r = raw;
3635
+ const kind = str(r.kind) || "remaining";
3636
+ if (!MISSION_ITEM_KINDS.includes(kind)) {
3637
+ return { error: `invalid kind '${kind}' (valid: ${MISSION_ITEM_KINDS.join(", ")})` };
3638
+ }
3639
+ const truncated = [];
3640
+ const { refs, truncated: refsTruncated } = normalizeMissionRefs(r.refs);
3641
+ if (refsTruncated) truncated.push("refs");
3642
+ const machineRaw = collapse(str(r.machine));
3643
+ const machine = machineRaw ? truncateMissionText(machineRaw, MISSION_LIMITS.machine) : void 0;
3644
+ const explicitKey = str(r.dedupe_key ?? r.dedupeKey);
3645
+ if (kind === "decision") {
3646
+ const decisionRaw = r.decision && typeof r.decision === "object" && !Array.isArray(r.decision) ? r.decision : r;
3647
+ const decision = normalizeDecisionInput({ ...decisionRaw, question: decisionRaw.question ?? r.question ?? r.text }, truncated);
3648
+ if (!decision) return { error: "decision item needs a question" };
3649
+ return {
3650
+ item: {
3651
+ kind,
3652
+ text: decision.question,
3653
+ ...machine ? { machine } : {},
3654
+ refs,
3655
+ decision,
3656
+ dedupeKey: deriveItemDedupeKey("decision", { question: decision.question, explicit: explicitKey }),
3657
+ truncated
3658
+ }
3659
+ };
3660
+ }
3661
+ const textSource = collapse(str(r.text));
3662
+ if (!textSource && !(kind === "evidence" && refs.length > 0)) return { error: `${kind} item needs text` };
3663
+ if (textSource.length > MISSION_LIMITS.itemText) truncated.push("text");
3664
+ const text = truncateMissionText(textSource || `${refs[0].kind}: ${refs[0].value}`, MISSION_LIMITS.itemText);
3665
+ return {
3666
+ item: {
3667
+ kind,
3668
+ text,
3669
+ ...machine ? { machine } : {},
3670
+ refs,
3671
+ dedupeKey: deriveItemDedupeKey(kind, { text, machine, refs, explicit: explicitKey }),
3672
+ truncated
3673
+ }
3674
+ };
3675
+ }
3676
+ function normalizeMissionItemUpdate(raw) {
3677
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { error: "update must be an object" };
3678
+ const r = raw;
3679
+ const id2 = str(r.id ?? r.item_id ?? r.itemId);
3680
+ if (!id2) return { error: "update needs an item id" };
3681
+ const truncated = [];
3682
+ const update = { id: id2 };
3683
+ if (r.state !== void 0) {
3684
+ const state = str(r.state);
3685
+ if (!MISSION_ITEM_STATES.includes(state)) return { error: `invalid state '${state}'` };
3686
+ update.state = state;
3687
+ }
3688
+ if (typeof r.text === "string") {
3689
+ const text = collapse(r.text);
3690
+ if (text.length > MISSION_LIMITS.itemText) truncated.push("text");
3691
+ if (text) update.text = truncateMissionText(text, MISSION_LIMITS.itemText);
3692
+ }
3693
+ if (r.machine === null) update.machine = null;
3694
+ else if (typeof r.machine === "string") {
3695
+ const machine = collapse(r.machine);
3696
+ update.machine = machine ? truncateMissionText(machine, MISSION_LIMITS.machine) : null;
3697
+ }
3698
+ if (r.refs !== void 0) {
3699
+ const { refs, truncated: t } = normalizeMissionRefs(r.refs);
3700
+ if (t) truncated.push("refs");
3701
+ update.refs = refs;
3702
+ }
3703
+ return { update, truncated };
3704
+ }
3705
+ function boundEventPayload(payload) {
3706
+ let json = JSON.stringify(payload);
3707
+ if (json.length <= MISSION_LIMITS.eventPayloadBytes) return json;
3708
+ const shrunk = {};
3709
+ for (const [k, v] of Object.entries(payload)) {
3710
+ shrunk[k] = typeof v === "string" && v.length > 4e3 ? `${v.slice(0, 4e3)}\u2026` : v;
3711
+ }
3712
+ shrunk.payloadTruncated = true;
3713
+ json = JSON.stringify(shrunk);
3714
+ if (json.length <= MISSION_LIMITS.eventPayloadBytes) return json;
3715
+ return JSON.stringify({ payloadTruncated: true, keys: Object.keys(payload).slice(0, 20) });
3716
+ }
3717
+ var CARRY_OVER_MISSION_TITLE = "Carry-over \u2014 open items from closed missions";
3718
+ var LEGACY_CARRY_OVER_MISSION_TITLE = "\uC774\uC6D4 \u2014 \uB2EB\uD78C \uBBF8\uC158\uC5D0\uC11C \uB118\uC5B4\uC628 \uD56D\uBAA9";
3719
+ var CARRY_OVER_MISSION_GOAL = "Open items carried over from closed missions, and decisions requested without a mission. Managed automatically \u2014 do not close.";
3720
+ function isCarryOverMissionRecord(m) {
3721
+ return !!m && (m.isCarryOver === true || isCarryOverMissionTitle(m.title));
3722
+ }
3723
+ function isCarryOverMissionTitle(title) {
3724
+ if (typeof title !== "string") return false;
3725
+ const t = title.trim();
3726
+ return t === CARRY_OVER_MISSION_TITLE || t === LEGACY_CARRY_OVER_MISSION_TITLE;
3727
+ }
3728
+ var OWNER_ABANDON_CONFIRM_KEY_PREFIX = "owner-abandon-confirm:";
3729
+ var OWNER_ABANDON_CONFIRM_QUESTION = "The coordinator closed this as 'owner abandoned' \u2014 correct?";
3730
+ var OWNER_ABANDON_CONFIRM_OPTIONS = ["Correct", "Reopen"];
3731
+ var WORKER_DECISIONS_NEEDED_MAX = 3;
3732
+ var WORKER_COMMITS_MAX = 20;
3733
+ var SHA_RE = /^[0-9a-f]{7,64}$/i;
3734
+ function normalizeReportCommits(value) {
3735
+ if (!Array.isArray(value)) return null;
3736
+ const out = [];
3737
+ for (const v of value) {
3738
+ if (typeof v !== "string") return null;
3739
+ const sha = v.trim();
3740
+ if (!SHA_RE.test(sha)) return null;
3741
+ if (!out.includes(sha.toLowerCase())) out.push(sha.toLowerCase());
3742
+ }
3743
+ return out;
3744
+ }
3745
+
3746
+ // src/decision-push-relay.ts
3747
+ var DECISION_PUSH_RELAY_COMMAND = "mission_decision_push_relay_answer";
3748
+ var DECISION_PUSH_RELAY_SOURCE = "push_relay";
3749
+
3412
3750
  // src/keyed-doc-delta.ts
3413
3751
  function sig(value) {
3414
3752
  if (value === void 0) return void 0;
@@ -3870,12 +4208,15 @@ export {
3870
4208
  CANCEL_REASONS,
3871
4209
  CANONICAL_MESH_TOOL_COUNT,
3872
4210
  CANONICAL_MESH_TOOL_NAMES,
4211
+ CARRY_OVER_MISSION_GOAL,
4212
+ CARRY_OVER_MISSION_TITLE,
3873
4213
  CLAUDE_TUI_REVIEW_PAGE_NOT_FOCUSED_PREFIX,
3874
4214
  CLAUDE_TUI_REVIEW_UNCONFIRMED_PREFIX,
3875
4215
  CLI_SLOT_RECIPES,
3876
4216
  COMMIT_STRENGTHS,
3877
4217
  CONSUME_PROFILES,
3878
4218
  COORDINATOR_ACK_OUTCOMES,
4219
+ COORDINATOR_SETTABLE_ITEM_STATES,
3879
4220
  DAEMON_METADATA_DOC_SPEC,
3880
4221
  DAEMON_P2P_SIGNAL_TYPES,
3881
4222
  DAEMON_STATUS_EVENT_NAMES,
@@ -3888,6 +4229,11 @@ export {
3888
4229
  DASHBOARD_TO_DAEMON_P2P_TYPES,
3889
4230
  DASHBOARD_TO_USER_SESSION_TYPES,
3890
4231
  DASHBOARD_WIRE_VERSION,
4232
+ DECISION_PUSH_OPTIONS_MAX,
4233
+ DECISION_PUSH_OPTION_LABEL_MAX,
4234
+ DECISION_PUSH_QUESTION_MAX,
4235
+ DECISION_PUSH_RELAY_COMMAND,
4236
+ DECISION_PUSH_RELAY_SOURCE,
3891
4237
  DEFAULT_DIFFICULTY_BRAINS,
3892
4238
  DELIVERY_OUTCOMES,
3893
4239
  DELIVERY_VIAS,
@@ -3899,6 +4245,7 @@ export {
3899
4245
  LAUNCH_DEFAULT_ERROR_CODES,
3900
4246
  LAUNCH_DEFAULT_ROLES,
3901
4247
  LAUNCH_DEFAULT_SOURCES,
4248
+ LEGACY_CARRY_OVER_MISSION_TITLE,
3902
4249
  LIVENESS_RESULTS,
3903
4250
  MAX_MESH_RECORD_STRING,
3904
4251
  MAX_OWNED_PATHS,
@@ -3924,6 +4271,14 @@ export {
3924
4271
  MESH_TOPIC_ENTRY_KINDS,
3925
4272
  MESH_TOPIC_PROTOCOL_VERSION,
3926
4273
  MISSION_BRIEF_RENDER_MAX_CHARS,
4274
+ MISSION_DECISION_ON_DUE,
4275
+ MISSION_DECISION_OPTION_IDS,
4276
+ MISSION_DECISION_URGENCIES,
4277
+ MISSION_ITEM_KINDS,
4278
+ MISSION_ITEM_STATES,
4279
+ MISSION_LIMITS,
4280
+ MISSION_OUTCOMES,
4281
+ MISSION_REF_KINDS,
3927
4282
  MODEL_AXIS_SOURCES,
3928
4283
  MODEL_SELECTION_HISTORY_LIMIT,
3929
4284
  MeshChunkAssembler,
@@ -3937,6 +4292,9 @@ export {
3937
4292
  OPERATOR_STATUS_REASON_VALUES,
3938
4293
  OPERATOR_STATUS_VALUES,
3939
4294
  OUTBOUND_MESSAGE_ORIGINS,
4295
+ OWNER_ABANDON_CONFIRM_KEY_PREFIX,
4296
+ OWNER_ABANDON_CONFIRM_OPTIONS,
4297
+ OWNER_ABANDON_CONFIRM_QUESTION,
3940
4298
  P2P_SIGNAL_TYPES,
3941
4299
  PROVIDER_FAILURES,
3942
4300
  QUOTA_BACKFILL_HORIZON_MS,
@@ -3988,6 +4346,8 @@ export {
3988
4346
  VERSION_UPDATE_REASONS,
3989
4347
  VIEWER_TO_SHARED_SESSION_TYPES,
3990
4348
  WORKER_BRANCH_STATES,
4349
+ WORKER_COMMITS_MAX,
4350
+ WORKER_DECISIONS_NEEDED_MAX,
3991
4351
  WORKER_PROTOCOL_FOOTER_MARKER,
3992
4352
  WORKER_REPORT_OUTCOMES,
3993
4353
  WORKER_REPORT_SUMMARY_MAX_CHARS,
@@ -3995,6 +4355,7 @@ export {
3995
4355
  appendWorkerProtocolFooter,
3996
4356
  argsCarryStatusProbeMarker,
3997
4357
  assessQuotaFreshness,
4358
+ boundEventPayload,
3998
4359
  buildSlotProposal,
3999
4360
  canonicalDaemonId,
4000
4361
  classifySessionStatus,
@@ -4064,6 +4425,7 @@ export {
4064
4425
  decodeUserSessionToDashboard,
4065
4426
  decodeViewerToSharedSession,
4066
4427
  defaultProviderPriorityFromNodeFacts,
4428
+ deriveItemDedupeKey,
4067
4429
  deriveProviderPriorityFromSlots,
4068
4430
  deriveSlotsFromLegacy,
4069
4431
  describeModelSelection,
@@ -4075,6 +4437,7 @@ export {
4075
4437
  findOwnershipConflicts,
4076
4438
  foldKeyedDoc,
4077
4439
  followedRemoteProjectKey,
4440
+ followerOpPermitted,
4078
4441
  formatQuotaAccount,
4079
4442
  hasGitStatusEvidence,
4080
4443
  hasWorkerProtocolFooter,
@@ -4084,6 +4447,8 @@ export {
4084
4447
  isAssistantTool,
4085
4448
  isBlockedStatus,
4086
4449
  isBusyStatus,
4450
+ isCarryOverMissionRecord,
4451
+ isCarryOverMissionTitle,
4087
4452
  isChunkType,
4088
4453
  isCommitStrength,
4089
4454
  isDaemonDirectCommandType,
@@ -4116,6 +4481,7 @@ export {
4116
4481
  isMeshTerminalTaskStatus,
4117
4482
  isMeshTopicEntry,
4118
4483
  isMessageId,
4484
+ isMissionOutcome,
4119
4485
  isMissionUpsertResponse,
4120
4486
  isModelAxisSource,
4121
4487
  isNativeMarkerRef,
@@ -4166,16 +4532,24 @@ export {
4166
4532
  minutesUntilQuotaCheck,
4167
4533
  normalizeAuthOkLimits,
4168
4534
  normalizeBrainSlot,
4535
+ normalizeDecisionInput,
4169
4536
  normalizeDifficultyBrainMap,
4537
+ normalizeForDedupe,
4170
4538
  normalizeGitStatus,
4171
4539
  normalizeMeshNodeFacts,
4172
4540
  normalizeMeshNodeId,
4173
4541
  normalizeMeshSessionRecord,
4174
4542
  normalizeMeshWorkspaceForCompare,
4175
4543
  normalizeMissionBrief,
4544
+ normalizeMissionItemInput,
4545
+ normalizeMissionItemUpdate,
4546
+ normalizeMissionRefs,
4547
+ normalizeMissionSummary,
4176
4548
  normalizeNodeCapabilitySlot,
4177
4549
  normalizeNodeCapabilitySlots,
4550
+ normalizeOutcomeReason,
4178
4551
  normalizeOwnedPaths,
4552
+ normalizeReportCommits,
4179
4553
  normalizeSessionStatus,
4180
4554
  normalizeThinkingLevel,
4181
4555
  orderProvidersByBuiltinPreference,
@@ -4215,6 +4589,7 @@ export {
4215
4589
  summarizeGitShape,
4216
4590
  supportsQuota,
4217
4591
  touchedFilesOutsideOwnership,
4592
+ truncateMissionText,
4218
4593
  unwrapPastedContent,
4219
4594
  withStatusProbeMarker
4220
4595
  };