@seat-mesh/core 1.0.2 → 1.0.4

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.
Files changed (133) hide show
  1. package/dist/ack/ack-algo.d.ts +84 -0
  2. package/dist/ack/ack-algo.d.ts.map +1 -0
  3. package/dist/ack/ack-algo.js +155 -0
  4. package/dist/ack/ack-algo.js.map +1 -0
  5. package/dist/ack/ack-algo.test.d.ts +2 -0
  6. package/dist/ack/ack-algo.test.d.ts.map +1 -0
  7. package/dist/ack/ack-algo.test.js +164 -0
  8. package/dist/ack/ack-algo.test.js.map +1 -0
  9. package/dist/ack/ack-copy.d.ts +27 -0
  10. package/dist/ack/ack-copy.d.ts.map +1 -0
  11. package/dist/ack/ack-copy.js +86 -0
  12. package/dist/ack/ack-copy.js.map +1 -0
  13. package/dist/ack/index.d.ts +4 -0
  14. package/dist/ack/index.d.ts.map +1 -0
  15. package/dist/ack/index.js +4 -0
  16. package/dist/ack/index.js.map +1 -0
  17. package/dist/ack/types.d.ts +40 -0
  18. package/dist/ack/types.d.ts.map +1 -0
  19. package/dist/ack/types.js +2 -0
  20. package/dist/ack/types.js.map +1 -0
  21. package/dist/chatfile/slot.js +1 -1
  22. package/dist/chatfile/slot.js.map +1 -1
  23. package/dist/chatroom/checkback-hint.d.ts +22 -4
  24. package/dist/chatroom/checkback-hint.d.ts.map +1 -1
  25. package/dist/chatroom/checkback-hint.js +40 -12
  26. package/dist/chatroom/checkback-hint.js.map +1 -1
  27. package/dist/chatroom/checkback-hint.test.js +4 -4
  28. package/dist/chatroom/checkback-hint.test.js.map +1 -1
  29. package/dist/chatroom/eod.d.ts +17 -0
  30. package/dist/chatroom/eod.d.ts.map +1 -0
  31. package/dist/chatroom/eod.js +32 -0
  32. package/dist/chatroom/eod.js.map +1 -0
  33. package/dist/chatroom/eod.test.d.ts +2 -0
  34. package/dist/chatroom/eod.test.d.ts.map +1 -0
  35. package/dist/chatroom/eod.test.js +24 -0
  36. package/dist/chatroom/eod.test.js.map +1 -0
  37. package/dist/chatroom/inbox-client.d.ts +12 -1
  38. package/dist/chatroom/inbox-client.d.ts.map +1 -1
  39. package/dist/chatroom/inbox-client.js +59 -3
  40. package/dist/chatroom/inbox-client.js.map +1 -1
  41. package/dist/chatroom/index.d.ts +3 -0
  42. package/dist/chatroom/index.d.ts.map +1 -1
  43. package/dist/chatroom/index.js +3 -0
  44. package/dist/chatroom/index.js.map +1 -1
  45. package/dist/chatroom/mdview-publish.d.ts +40 -0
  46. package/dist/chatroom/mdview-publish.d.ts.map +1 -0
  47. package/dist/chatroom/mdview-publish.js +109 -0
  48. package/dist/chatroom/mdview-publish.js.map +1 -0
  49. package/dist/chatroom/mdview-publish.test.d.ts +2 -0
  50. package/dist/chatroom/mdview-publish.test.d.ts.map +1 -0
  51. package/dist/chatroom/mdview-publish.test.js +37 -0
  52. package/dist/chatroom/mdview-publish.test.js.map +1 -0
  53. package/dist/chatroom/notify-act-client.d.ts +24 -6
  54. package/dist/chatroom/notify-act-client.d.ts.map +1 -1
  55. package/dist/chatroom/notify-act-client.js +83 -14
  56. package/dist/chatroom/notify-act-client.js.map +1 -1
  57. package/dist/chatroom/notify-act-client.test.js +32 -14
  58. package/dist/chatroom/notify-act-client.test.js.map +1 -1
  59. package/dist/chatroom/notify-act.d.ts +13 -0
  60. package/dist/chatroom/notify-act.d.ts.map +1 -1
  61. package/dist/chatroom/room.d.ts.map +1 -1
  62. package/dist/chatroom/room.js +7 -1
  63. package/dist/chatroom/room.js.map +1 -1
  64. package/dist/chatroom/room.test.js +15 -6
  65. package/dist/chatroom/room.test.js.map +1 -1
  66. package/dist/chatroom/target-client.d.ts +60 -0
  67. package/dist/chatroom/target-client.d.ts.map +1 -0
  68. package/dist/chatroom/target-client.js +124 -0
  69. package/dist/chatroom/target-client.js.map +1 -0
  70. package/dist/comms/envelope.d.ts +2 -2
  71. package/dist/composer/claude-idle.d.ts +5 -0
  72. package/dist/composer/claude-idle.d.ts.map +1 -1
  73. package/dist/composer/claude-idle.js +17 -3
  74. package/dist/composer/claude-idle.js.map +1 -1
  75. package/dist/index.d.ts +3 -0
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +3 -0
  78. package/dist/index.js.map +1 -1
  79. package/dist/messages/cli-hints.d.ts +29 -5
  80. package/dist/messages/cli-hints.d.ts.map +1 -1
  81. package/dist/messages/cli-hints.js +58 -8
  82. package/dist/messages/cli-hints.js.map +1 -1
  83. package/dist/messages/cli-hints.test.d.ts +2 -0
  84. package/dist/messages/cli-hints.test.d.ts.map +1 -0
  85. package/dist/messages/cli-hints.test.js +20 -0
  86. package/dist/messages/cli-hints.test.js.map +1 -0
  87. package/dist/messages/mesh-inbox-intent.d.ts +3 -1
  88. package/dist/messages/mesh-inbox-intent.d.ts.map +1 -1
  89. package/dist/messages/mesh-inbox-intent.js +5 -0
  90. package/dist/messages/mesh-inbox-intent.js.map +1 -1
  91. package/dist/messages/mesh-inject-text.d.ts +10 -0
  92. package/dist/messages/mesh-inject-text.d.ts.map +1 -0
  93. package/dist/messages/mesh-inject-text.js +45 -0
  94. package/dist/messages/mesh-inject-text.js.map +1 -0
  95. package/dist/messages/peer-bulk.d.ts +28 -0
  96. package/dist/messages/peer-bulk.d.ts.map +1 -0
  97. package/dist/messages/peer-bulk.js +59 -0
  98. package/dist/messages/peer-bulk.js.map +1 -0
  99. package/dist/messages/peer-bulk.test.d.ts +2 -0
  100. package/dist/messages/peer-bulk.test.d.ts.map +1 -0
  101. package/dist/messages/peer-bulk.test.js +30 -0
  102. package/dist/messages/peer-bulk.test.js.map +1 -0
  103. package/dist/paths/paths-manifest.d.ts.map +1 -1
  104. package/dist/paths/paths-manifest.js +14 -2
  105. package/dist/paths/paths-manifest.js.map +1 -1
  106. package/dist/paths/paths-manifest.test.js +10 -0
  107. package/dist/paths/paths-manifest.test.js.map +1 -1
  108. package/dist/paths/runtime-paths.d.ts +2 -0
  109. package/dist/paths/runtime-paths.d.ts.map +1 -1
  110. package/dist/paths/runtime-paths.js +2 -0
  111. package/dist/paths/runtime-paths.js.map +1 -1
  112. package/dist/profile/profile.d.ts +2 -0
  113. package/dist/profile/profile.d.ts.map +1 -1
  114. package/dist/schema/agents.d.ts +75 -75
  115. package/dist/schema/layout.d.ts +5 -5
  116. package/dist/schema/profile.d.ts +33 -9
  117. package/dist/schema/profile.d.ts.map +1 -1
  118. package/dist/schema/profile.js +4 -0
  119. package/dist/schema/profile.js.map +1 -1
  120. package/dist/schema/seat-kind.d.ts +1 -1
  121. package/dist/schema/seat-kind.d.ts.map +1 -1
  122. package/dist/schema/seat-kind.js +5 -3
  123. package/dist/schema/seat-kind.js.map +1 -1
  124. package/dist/schema/seat-kind.test.js +2 -0
  125. package/dist/schema/seat-kind.test.js.map +1 -1
  126. package/dist/slot/guards.d.ts.map +1 -1
  127. package/dist/slot/guards.js +13 -0
  128. package/dist/slot/guards.js.map +1 -1
  129. package/dist/slot/types.d.ts +1 -1
  130. package/dist/slot/types.d.ts.map +1 -1
  131. package/dist/slot/types.js +1 -0
  132. package/dist/slot/types.js.map +1 -1
  133. package/package.json +1 -1
@@ -0,0 +1,84 @@
1
+ import type { AckRow } from "./types.js";
2
+ /** Ask text stored per row — enough to recognise, short enough to inject. */
3
+ export declare const ACK_ASK_MAX = 200;
4
+ /** Reminder injects per row before it stops nagging (stale, report-only). */
5
+ export declare const ACK_REMIND_MAX = 4;
6
+ /** First reminder delay after a row opens; doubles per fire up to the cap. */
7
+ export declare const ACK_REMIND_FIRST_SEC = 90;
8
+ export declare const ACK_REMIND_CAP_SEC = 600;
9
+ /** Open rows listed in one reminder inject — keeps the paste one screen. */
10
+ export declare const ACK_REMIND_LIST_MAX = 3;
11
+ export declare function shortAckId(id: string): string;
12
+ export declare function trimAsk(ask: string): string;
13
+ export declare function isAckOpen(row: AckRow): boolean;
14
+ /** Out of reminders — the agent stopped answering, so surface it to the operator instead. */
15
+ export declare function isAckStale(row: AckRow): boolean;
16
+ export declare function openAcks(rows: AckRow[]): AckRow[];
17
+ export declare function openAcksForSeat(rows: AckRow[], seat: string): AckRow[];
18
+ /** Doubling backoff so a stuck seat is nudged soon, then rarely. */
19
+ export declare function ackRemindDelaySec(reminders: number): number;
20
+ /** Rows worth injecting a reminder for (stale ones are report-only). */
21
+ export declare function remindableAcks(rows: AckRow[]): AckRow[];
22
+ export interface PromptObservation {
23
+ /** Live composer draft this tick ("" when the composer is empty). */
24
+ draft: string;
25
+ /** Full pane capture tail — holds the transcript echo after a submit. */
26
+ captureTail: string;
27
+ }
28
+ export interface PromptWatchState {
29
+ /** Last human draft seen that has not yet been submitted or abandoned. */
30
+ pendingDraft: string;
31
+ pendingAt: number;
32
+ }
33
+ export type PromptWatchEvent = {
34
+ kind: "none";
35
+ } | {
36
+ kind: "typing";
37
+ } | {
38
+ kind: "submitted";
39
+ prompt: string;
40
+ } | {
41
+ kind: "abandoned";
42
+ };
43
+ export declare const EMPTY_PROMPT_WATCH: PromptWatchState;
44
+ export declare function normalizePromptText(s: string): string;
45
+ /**
46
+ * Find the submitted prompt echoed in the transcript.
47
+ *
48
+ * Called only when the composer just went empty, so the draft text cannot still
49
+ * be in the composer — if it is anywhere on screen the CLI committed it to the
50
+ * transcript, which means the operator pressed Enter rather than clearing.
51
+ */
52
+ export declare function extractSubmittedPrompt(captureTail: string, draft: string): string;
53
+ /**
54
+ * Per-pane composer transition: draft seen, then draft gone.
55
+ *
56
+ * Gone + echoed in the transcript = the operator submitted it (an ask that owes
57
+ * an answer). Gone + not echoed = cleared or backspaced away, so nothing is owed.
58
+ * Mesh copy is never an operator ask — the mail path opens those rows itself.
59
+ */
60
+ export declare function classifyPromptTick(prev: PromptWatchState | undefined, obs: PromptObservation, nowMs: number): {
61
+ next: PromptWatchState;
62
+ event: PromptWatchEvent;
63
+ };
64
+ /** An outbound the seat filed through the mesh (peer / inbox / room). */
65
+ export interface SeatFiling {
66
+ seat: string;
67
+ at: string;
68
+ /** Short audit note, e.g. "peer -> manager". */
69
+ what: string;
70
+ }
71
+ /**
72
+ * Pair open rows with filings that came after them.
73
+ *
74
+ * The mesh contract is "answer by filing", so an outbound from a seat is the
75
+ * evidence that the seat acted. Oldest open row pairs with the earliest later
76
+ * filing, one filing per row, so a burst of replies cannot clear a whole backlog.
77
+ */
78
+ export declare function matchFiledAcks(rows: AckRow[], filings: SeatFiling[]): {
79
+ row: AckRow;
80
+ note: string;
81
+ }[];
82
+ /** Apply a close in place — `ackedAt` set is the only thing that ends a row. */
83
+ export declare function closeAckRow(row: AckRow, by: AckRow["ackBy"], note?: string, nowIso?: string): AckRow;
84
+ //# sourceMappingURL=ack-algo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ack-algo.d.ts","sourceRoot":"","sources":["../../src/ack/ack-algo.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,6EAA6E;AAC7E,eAAO,MAAM,WAAW,MAAM,CAAC;AAE/B,6EAA6E;AAC7E,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG3C;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEjD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKtE;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEvD;AAMD,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAE1B,eAAO,MAAM,kBAAkB,EAAE,gBAAqD,CAAC;AAEvF,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD;AASD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAcjF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAClC,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,MAAM,GACZ;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,CAqBrD;AAMD,yEAAyE;AACzE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,UAAU,EAAE,GACpB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAqBjC;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,EACnB,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,SAA2B,GAChC,MAAM,CAMR"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * ACK ledger algorithm (pure).
3
+ *
4
+ * Recurring failure this exists to catch: a seat is given an ask — the operator
5
+ * types it into the pane, or mesh mail lands in it — and the agent answers in
6
+ * chat prose without ever filing, or silently drops it. Nothing in the mesh
7
+ * remembers the ask, so the operator has no list of what is still unanswered.
8
+ *
9
+ * Every ask opens a row. A row clears on evidence (explicit ack, or an outbound
10
+ * filing from that seat afterwards). While rows stay open the daemon re-injects a
11
+ * reminder on a doubling backoff, then gives up nagging and leaves them visible.
12
+ */
13
+ import { isSmInjectText } from "../messages/mesh-inject-text.js";
14
+ /** Ask text stored per row — enough to recognise, short enough to inject. */
15
+ export const ACK_ASK_MAX = 200;
16
+ /** Reminder injects per row before it stops nagging (stale, report-only). */
17
+ export const ACK_REMIND_MAX = 4;
18
+ /** First reminder delay after a row opens; doubles per fire up to the cap. */
19
+ export const ACK_REMIND_FIRST_SEC = 90;
20
+ export const ACK_REMIND_CAP_SEC = 600;
21
+ /** Open rows listed in one reminder inject — keeps the paste one screen. */
22
+ export const ACK_REMIND_LIST_MAX = 3;
23
+ export function shortAckId(id) {
24
+ return id.replace(/^ack-/, "").slice(0, 6);
25
+ }
26
+ export function trimAsk(ask) {
27
+ const t = ask.replace(/\s+/g, " ").trim();
28
+ return t.length > ACK_ASK_MAX ? `${t.slice(0, ACK_ASK_MAX - 1)}…` : t;
29
+ }
30
+ export function isAckOpen(row) {
31
+ return !row.ackedAt;
32
+ }
33
+ /** Out of reminders — the agent stopped answering, so surface it to the operator instead. */
34
+ export function isAckStale(row) {
35
+ return isAckOpen(row) && row.reminders >= ACK_REMIND_MAX;
36
+ }
37
+ export function openAcks(rows) {
38
+ return rows.filter(isAckOpen);
39
+ }
40
+ export function openAcksForSeat(rows, seat) {
41
+ const want = seat.trim().toLowerCase();
42
+ return openAcks(rows)
43
+ .filter((r) => r.seat.trim().toLowerCase() === want)
44
+ .sort((a, b) => a.at.localeCompare(b.at));
45
+ }
46
+ /** Doubling backoff so a stuck seat is nudged soon, then rarely. */
47
+ export function ackRemindDelaySec(reminders) {
48
+ const n = Math.max(0, Math.floor(reminders));
49
+ return Math.min(ACK_REMIND_FIRST_SEC * 2 ** n, ACK_REMIND_CAP_SEC);
50
+ }
51
+ /** Rows worth injecting a reminder for (stale ones are report-only). */
52
+ export function remindableAcks(rows) {
53
+ return openAcks(rows).filter((r) => r.reminders < ACK_REMIND_MAX);
54
+ }
55
+ export const EMPTY_PROMPT_WATCH = { pendingDraft: "", pendingAt: 0 };
56
+ export function normalizePromptText(s) {
57
+ return s.replace(/\s+/g, " ").trim().toLowerCase();
58
+ }
59
+ /** Transcript gutter Claude/Cursor/OpenCode draw in front of an echoed user turn. */
60
+ const PROMPT_GUTTER_RE = /^[\s>❯⏺·•│┃|*+-]+/;
61
+ /** Shortest draft prefix trusted as an echo match — below this, false positives. */
62
+ const ECHO_MIN_PREFIX = 4;
63
+ const ECHO_PREFIX_LEN = 40;
64
+ /**
65
+ * Find the submitted prompt echoed in the transcript.
66
+ *
67
+ * Called only when the composer just went empty, so the draft text cannot still
68
+ * be in the composer — if it is anywhere on screen the CLI committed it to the
69
+ * transcript, which means the operator pressed Enter rather than clearing.
70
+ */
71
+ export function extractSubmittedPrompt(captureTail, draft) {
72
+ const want = normalizePromptText(draft);
73
+ if (want.length < ECHO_MIN_PREFIX)
74
+ return "";
75
+ const prefix = want.slice(0, ECHO_PREFIX_LEN);
76
+ for (const line of captureTail.split("\n")) {
77
+ const body = line.replace(PROMPT_GUTTER_RE, "").trim();
78
+ if (!body)
79
+ continue;
80
+ if (!normalizePromptText(body).includes(prefix))
81
+ continue;
82
+ // A wrapped prompt echoes across rows, so the matched row can be shorter
83
+ // than what we last saw being typed. Keep whichever is more complete.
84
+ return body.length >= draft.trim().length ? body : draft.trim();
85
+ }
86
+ return "";
87
+ }
88
+ /**
89
+ * Per-pane composer transition: draft seen, then draft gone.
90
+ *
91
+ * Gone + echoed in the transcript = the operator submitted it (an ask that owes
92
+ * an answer). Gone + not echoed = cleared or backspaced away, so nothing is owed.
93
+ * Mesh copy is never an operator ask — the mail path opens those rows itself.
94
+ */
95
+ export function classifyPromptTick(prev, obs, nowMs) {
96
+ const draft = obs.draft.trim();
97
+ if (draft) {
98
+ if (isSmInjectText(draft)) {
99
+ return { next: EMPTY_PROMPT_WATCH, event: { kind: "none" } };
100
+ }
101
+ return {
102
+ next: { pendingDraft: draft, pendingAt: prev?.pendingAt || nowMs },
103
+ event: { kind: "typing" },
104
+ };
105
+ }
106
+ const pending = prev?.pendingDraft?.trim() ?? "";
107
+ if (!pending)
108
+ return { next: EMPTY_PROMPT_WATCH, event: { kind: "none" } };
109
+ const prompt = extractSubmittedPrompt(obs.captureTail, pending);
110
+ if (prompt) {
111
+ return { next: EMPTY_PROMPT_WATCH, event: { kind: "submitted", prompt } };
112
+ }
113
+ return { next: EMPTY_PROMPT_WATCH, event: { kind: "abandoned" } };
114
+ }
115
+ /**
116
+ * Pair open rows with filings that came after them.
117
+ *
118
+ * The mesh contract is "answer by filing", so an outbound from a seat is the
119
+ * evidence that the seat acted. Oldest open row pairs with the earliest later
120
+ * filing, one filing per row, so a burst of replies cannot clear a whole backlog.
121
+ */
122
+ export function matchFiledAcks(rows, filings) {
123
+ const bySeat = new Map();
124
+ for (const row of openAcks(rows)) {
125
+ const key = row.seat.trim().toLowerCase();
126
+ const list = bySeat.get(key) ?? [];
127
+ list.push(row);
128
+ bySeat.set(key, list);
129
+ }
130
+ for (const list of bySeat.values())
131
+ list.sort((a, b) => a.at.localeCompare(b.at));
132
+ const matched = [];
133
+ const sorted = [...filings].sort((a, b) => a.at.localeCompare(b.at));
134
+ for (const filing of sorted) {
135
+ const list = bySeat.get(filing.seat.trim().toLowerCase());
136
+ if (!list?.length)
137
+ continue;
138
+ const idx = list.findIndex((r) => r.at < filing.at);
139
+ if (idx < 0)
140
+ continue;
141
+ const [row] = list.splice(idx, 1);
142
+ matched.push({ row: row, note: filing.what });
143
+ }
144
+ return matched;
145
+ }
146
+ /** Apply a close in place — `ackedAt` set is the only thing that ends a row. */
147
+ export function closeAckRow(row, by, note, nowIso = new Date().toISOString()) {
148
+ row.ackedAt = nowIso;
149
+ row.ackBy = by;
150
+ const n = note?.replace(/\s+/g, " ").trim();
151
+ if (n)
152
+ row.ackNote = n.length > ACK_ASK_MAX ? `${n.slice(0, ACK_ASK_MAX - 1)}…` : n;
153
+ return row;
154
+ }
155
+ //# sourceMappingURL=ack-algo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ack-algo.js","sourceRoot":"","sources":["../../src/ack/ack-algo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ack-algo.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ack-algo.test.d.ts","sourceRoot":"","sources":["../../src/ack/ack-algo.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,164 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ACK_REMIND_CAP_SEC, ACK_REMIND_FIRST_SEC, ACK_REMIND_MAX, ackRemindDelaySec, classifyPromptTick, closeAckRow, EMPTY_PROMPT_WATCH, extractSubmittedPrompt, isAckStale, matchFiledAcks, openAcksForSeat, remindableAcks, trimAsk, } from "./ack-algo.js";
3
+ import { formatAckReminder, formatBannerAck } from "./ack-copy.js";
4
+ function row(over = {}) {
5
+ return {
6
+ id: "ack-a7f3k2ff",
7
+ at: "2026-09-14T03:00:00.000Z",
8
+ seat: "secretary",
9
+ paneId: "%23",
10
+ source: "operator",
11
+ ask: "fix the banner overflow",
12
+ reminders: 0,
13
+ ...over,
14
+ };
15
+ }
16
+ /** Claude auto-mode composer: divider-wrapped ❯ with the auto footer beneath. */
17
+ function claudeLive(draftLine) {
18
+ return [
19
+ "✻ Baked for 35s · done 10:12 AM",
20
+ "──────────────────────────────────────────",
21
+ `❯ ${draftLine}`,
22
+ "──────────────────────────────────────────",
23
+ " ⏵⏵ auto mode on (shift+tab to cycle)",
24
+ ].join("\n");
25
+ }
26
+ /** Same pane one tick later: prompt committed to the transcript, composer empty. */
27
+ function claudeSubmitted(prompt) {
28
+ return [
29
+ `> ${prompt}`,
30
+ "⏺ working on it",
31
+ "──────────────────────────────────────────",
32
+ "❯ ",
33
+ "──────────────────────────────────────────",
34
+ " ⏵⏵ auto mode on (shift+tab to cycle)",
35
+ ].join("\n");
36
+ }
37
+ describe("operator prompt detection", () => {
38
+ it("opens nothing while the operator is still typing", () => {
39
+ const out = classifyPromptTick(undefined, { draft: "fix the banner", captureTail: claudeLive("fix the banner") }, 1_000);
40
+ expect(out.event.kind).toBe("typing");
41
+ expect(out.next.pendingDraft).toBe("fix the banner");
42
+ });
43
+ it("treats draft-gone + transcript echo as a submitted prompt", () => {
44
+ const typing = classifyPromptTick(undefined, { draft: "fix the banner overflow", captureTail: claudeLive("fix the banner overflow") }, 1_000);
45
+ const out = classifyPromptTick(typing.next, { draft: "", captureTail: claudeSubmitted("fix the banner overflow") }, 2_000);
46
+ expect(out.event).toEqual({ kind: "submitted", prompt: "fix the banner overflow" });
47
+ expect(out.next).toEqual(EMPTY_PROMPT_WATCH);
48
+ });
49
+ it("treats draft-gone with no echo as abandoned (ctrl-c / backspaced)", () => {
50
+ const typing = classifyPromptTick(undefined, { draft: "never mind this", captureTail: claudeLive("never mind this") }, 1_000);
51
+ const out = classifyPromptTick(typing.next, { draft: "", captureTail: claudeSubmitted("something else entirely") }, 2_000);
52
+ expect(out.event.kind).toBe("abandoned");
53
+ });
54
+ it("never tracks mesh inject copy as an operator ask", () => {
55
+ const out = classifyPromptTick(undefined, {
56
+ draft: "secretary | [mesh-inbox] SUPERVISE: contexts",
57
+ captureTail: claudeLive("secretary | [mesh-inbox] SUPERVISE: contexts"),
58
+ }, 1_000);
59
+ expect(out.event.kind).toBe("none");
60
+ expect(out.next.pendingDraft).toBe("");
61
+ });
62
+ it("recovers the full prompt when the operator kept typing past the last tick", () => {
63
+ // Daemon last saw a prefix; the committed line is longer.
64
+ const out = classifyPromptTick({ pendingDraft: "fix the ban", pendingAt: 1_000 }, { draft: "", captureTail: claudeSubmitted("fix the banner overflow on narrow panes") }, 2_000);
65
+ expect(out.event).toEqual({
66
+ kind: "submitted",
67
+ prompt: "fix the banner overflow on narrow panes",
68
+ });
69
+ });
70
+ it("ignores echoes too short to be distinctive", () => {
71
+ expect(extractSubmittedPrompt(claudeSubmitted("ok"), "ok")).toBe("");
72
+ });
73
+ });
74
+ describe("reminder schedule", () => {
75
+ it("doubles then caps", () => {
76
+ expect(ackRemindDelaySec(0)).toBe(ACK_REMIND_FIRST_SEC);
77
+ expect(ackRemindDelaySec(1)).toBe(ACK_REMIND_FIRST_SEC * 2);
78
+ expect(ackRemindDelaySec(2)).toBe(ACK_REMIND_FIRST_SEC * 4);
79
+ expect(ackRemindDelaySec(99)).toBe(ACK_REMIND_CAP_SEC);
80
+ });
81
+ it("stops nagging at the reminder cap but keeps the row open", () => {
82
+ const done = row({ reminders: ACK_REMIND_MAX });
83
+ expect(isAckStale(done)).toBe(true);
84
+ expect(remindableAcks([done])).toEqual([]);
85
+ expect(openAcksForSeat([done], "secretary")).toHaveLength(1);
86
+ });
87
+ it("drops closed rows from every open view", () => {
88
+ const closed = closeAckRow(row(), "explicit", "restarted inbox");
89
+ expect(closed.ackedAt).toBeTruthy();
90
+ expect(openAcksForSeat([closed], "secretary")).toEqual([]);
91
+ expect(isAckStale(closed)).toBe(false);
92
+ });
93
+ });
94
+ describe("close on filing evidence", () => {
95
+ it("pairs the oldest open row with the first later filing", () => {
96
+ const first = row({ id: "ack-aaa111", at: "2026-09-14T03:00:00.000Z" });
97
+ const second = row({ id: "ack-bbb222", at: "2026-09-14T03:05:00.000Z" });
98
+ const matched = matchFiledAcks([first, second], [{ seat: "secretary", at: "2026-09-14T03:06:00.000Z", what: "peer -> manager" }]);
99
+ expect(matched).toHaveLength(1);
100
+ expect(matched[0].row.id).toBe("ack-aaa111");
101
+ expect(matched[0].note).toBe("peer -> manager");
102
+ });
103
+ it("ignores filings that predate the ask", () => {
104
+ const matched = matchFiledAcks([row({ at: "2026-09-14T03:10:00.000Z" })], [{ seat: "secretary", at: "2026-09-14T03:00:00.000Z", what: "peer -> manager" }]);
105
+ expect(matched).toEqual([]);
106
+ });
107
+ it("spends each filing on one row so a burst cannot clear a backlog", () => {
108
+ const rows = [
109
+ row({ id: "ack-aaa111", at: "2026-09-14T03:00:00.000Z" }),
110
+ row({ id: "ack-bbb222", at: "2026-09-14T03:01:00.000Z" }),
111
+ row({ id: "ack-ccc333", at: "2026-09-14T03:02:00.000Z" }),
112
+ ];
113
+ const matched = matchFiledAcks(rows, [
114
+ { seat: "secretary", at: "2026-09-14T03:03:00.000Z", what: "peer -> manager" },
115
+ { seat: "secretary", at: "2026-09-14T03:04:00.000Z", what: "room say managers" },
116
+ ]);
117
+ expect(matched.map((m) => m.row.id)).toEqual(["ack-aaa111", "ack-bbb222"]);
118
+ });
119
+ it("does not cross seats", () => {
120
+ const matched = matchFiledAcks([row({ seat: "manager" })], [{ seat: "secretary", at: "2026-09-14T04:00:00.000Z", what: "peer -> manager" }]);
121
+ expect(matched).toEqual([]);
122
+ });
123
+ });
124
+ describe("reminder copy", () => {
125
+ it("lists the asks and ends on the shell line", () => {
126
+ const text = formatAckReminder("secretary", [
127
+ row({ id: "ack-aaa111", ask: "fix the banner overflow" }),
128
+ row({
129
+ id: "ack-bbb222",
130
+ source: "peer",
131
+ from: "manager",
132
+ ask: "status on inbox restart",
133
+ }),
134
+ ]);
135
+ expect(text).toContain("[mesh-inbox] ACK 2 unanswered");
136
+ expect(text).toContain("· aaa111 operator: fix the banner overflow");
137
+ expect(text).toContain("· bbb222 manager: status on inbox restart");
138
+ // First open row is operator → ack clear; peer rows prefer --ended.
139
+ expect(text).toMatch(/ack aaa111/);
140
+ expect(formatAckReminder("secretary", [
141
+ row({
142
+ id: "ack-ccc333",
143
+ source: "peer",
144
+ from: "manager",
145
+ ask: "status",
146
+ }),
147
+ ])).toContain("--ended ccc333");
148
+ expect(text).toContain("queued");
149
+ });
150
+ it("is empty when nothing is open", () => {
151
+ expect(formatAckReminder("secretary", [closeAckRow(row(), "explicit")])).toBe("");
152
+ });
153
+ it("flags stale rows in the banner", () => {
154
+ expect(formatBannerAck(2)).toBe("ack 2");
155
+ expect(formatBannerAck(2, 1)).toBe("ack 2!");
156
+ });
157
+ });
158
+ describe("trimAsk", () => {
159
+ it("collapses whitespace and caps length", () => {
160
+ expect(trimAsk(" fix the\nbanner ")).toBe("fix the banner");
161
+ expect(trimAsk("x".repeat(400)).length).toBeLessThanOrEqual(200);
162
+ });
163
+ });
164
+ //# sourceMappingURL=ack-algo.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ack-algo.test.js","sourceRoot":"","sources":["../../src/ack/ack-algo.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { AckRow } from "./types.js";
2
+ export declare const ACK_TAG = "ACK";
3
+ /** Explicit clear when there is no peer reply to send. */
4
+ export declare function formatAckClearCmd(id: string): string;
5
+ /**
6
+ * One shell line that both replies and closes the ACK (stops the waste loop:
7
+ * peer → separate ack → maybe cb cancel across turns).
8
+ */
9
+ export declare function formatPeerEndedCmd(to: string, id: string): string;
10
+ export declare function formatAckListCmd(): string;
11
+ /** One row as a reminder bullet: `· a7f3k2 operator: fix the banner overflow`. */
12
+ export declare function formatAckOpenLine(row: AckRow): string;
13
+ /** Preferred clear shell for one open row. */
14
+ export declare function formatAckCloseShell(row: AckRow): string;
15
+ /**
16
+ * Reminder inject for a seat with open rows.
17
+ *
18
+ * Lists the asks (an agent cannot answer a bare count) and ends on the shell
19
+ * line, because a chat-only "acknowledged" is exactly the failure being caught.
20
+ */
21
+ export declare function formatAckReminder(seat: string, rows: AckRow[]): string;
22
+ /** Banner segment. `ack 2` open, `ack 2!` when a row gave up on reminders. */
23
+ export declare function formatBannerAck(open: number, stale?: number): string;
24
+ export declare function compactBannerAck(full: string): string;
25
+ /** `ack list` row for the operator. */
26
+ export declare function formatAckStatusLine(row: AckRow): string;
27
+ //# sourceMappingURL=ack-copy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ack-copy.d.ts","sourceRoot":"","sources":["../../src/ack/ack-copy.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,eAAO,MAAM,OAAO,QAAQ,CAAC;AAE7B,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAOD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,8CAA8C;AAC9C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CActE;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAG/D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,uCAAuC;AACvC,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAiBvD"}
@@ -0,0 +1,86 @@
1
+ /** ACK inject + banner copy. Consts live here; never paste ad-hoc wording into a pane. */
2
+ import { seatmeshCmd } from "../messages/cli-hints.js";
3
+ import { MESH_INBOX_TAG } from "../messages/mesh-copy.js";
4
+ import { peerTargetFromAgentId } from "../chatroom/checkback-hint.js";
5
+ import { ACK_REMIND_LIST_MAX, isAckStale, openAcks, shortAckId, } from "./ack-algo.js";
6
+ export const ACK_TAG = "ACK";
7
+ /** Explicit clear when there is no peer reply to send. */
8
+ export function formatAckClearCmd(id) {
9
+ return seatmeshCmd(`ack ${shortAckId(id)} "<one line>"`);
10
+ }
11
+ /**
12
+ * One shell line that both replies and closes the ACK (stops the waste loop:
13
+ * peer → separate ack → maybe cb cancel across turns).
14
+ */
15
+ export function formatPeerEndedCmd(to, id) {
16
+ const target = peerTargetFromAgentId(to);
17
+ return seatmeshCmd(`peer ${target} "<msg>" --ended ${shortAckId(id)}`);
18
+ }
19
+ export function formatAckListCmd() {
20
+ return seatmeshCmd("ack");
21
+ }
22
+ function askSnippet(ask, max = 72) {
23
+ const t = ask.replace(/\s+/g, " ").trim();
24
+ return t.length > max ? `${t.slice(0, max - 1)}…` : t;
25
+ }
26
+ /** One row as a reminder bullet: `· a7f3k2 operator: fix the banner overflow`. */
27
+ export function formatAckOpenLine(row) {
28
+ const who = row.source === "operator" ? "operator" : row.from?.trim() || row.source;
29
+ return `· ${shortAckId(row.id)} ${who}: ${askSnippet(row.ask)}`;
30
+ }
31
+ /** Preferred clear shell for one open row. */
32
+ export function formatAckCloseShell(row) {
33
+ if (row.source === "operator" || !row.from?.trim()) {
34
+ return formatAckClearCmd(row.id);
35
+ }
36
+ return formatPeerEndedCmd(row.from, row.id);
37
+ }
38
+ /**
39
+ * Reminder inject for a seat with open rows.
40
+ *
41
+ * Lists the asks (an agent cannot answer a bare count) and ends on the shell
42
+ * line, because a chat-only "acknowledged" is exactly the failure being caught.
43
+ */
44
+ export function formatAckReminder(seat, rows) {
45
+ const open = openAcks(rows);
46
+ if (!open.length)
47
+ return "";
48
+ const shown = open.slice(0, ACK_REMIND_LIST_MAX);
49
+ const more = open.length - shown.length;
50
+ const head = `${seat} | ${MESH_INBOX_TAG} ${ACK_TAG} ${open.length} unanswered — answer + --ended closes it`;
51
+ const body = shown.map(formatAckOpenLine).join("\n");
52
+ const first = shown[0];
53
+ const tail = more > 0 ? `\n· +${more} more — ${formatAckListCmd()}` : "";
54
+ return (`${head}\n${body}${tail}\n` +
55
+ `SHELL (required — chat reply does NOT clear): ${formatAckCloseShell(first)}\n` +
56
+ `FYI: open ACKs also list in whoami context; follow-ups while busy are queued.`);
57
+ }
58
+ /** Banner segment. `ack 2` open, `ack 2!` when a row gave up on reminders. */
59
+ export function formatBannerAck(open, stale = 0) {
60
+ const n = Math.max(0, open);
61
+ return stale > 0 ? `ack ${n}!` : `ack ${n}`;
62
+ }
63
+ export function compactBannerAck(full) {
64
+ const m = full.match(/^ack (\d+)(!?)$/);
65
+ return m ? `a${m[1]}${m[2]}` : full;
66
+ }
67
+ /** `ack list` row for the operator. */
68
+ export function formatAckStatusLine(row) {
69
+ const state = row.ackedAt
70
+ ? `acked:${row.ackBy ?? "?"}`
71
+ : isAckStale(row)
72
+ ? "STALE"
73
+ : `open r${row.reminders}`;
74
+ const who = row.source === "operator" ? "operator" : row.from?.trim() || row.source;
75
+ return [
76
+ shortAckId(row.id),
77
+ row.seat,
78
+ state,
79
+ who,
80
+ askSnippet(row.ask, 60),
81
+ row.ackNote ? `(${askSnippet(row.ackNote, 40)})` : "",
82
+ ]
83
+ .filter(Boolean)
84
+ .join("\t");
85
+ }
86
+ //# sourceMappingURL=ack-copy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ack-copy.js","sourceRoot":"","sources":["../../src/ack/ack-copy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./ack-algo.js";
3
+ export * from "./ack-copy.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ack/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./ack-algo.js";
3
+ export * from "./ack-copy.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ack/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,40 @@
1
+ /** Where the unanswered ask came from. */
2
+ export type AckSource = "operator" | "inbox" | "peer" | "room";
3
+ /** How an open row was cleared (audit only — `ackedAt` is the state). */
4
+ export type AckCloseBy = "explicit" | "filed" | "operator";
5
+ /**
6
+ * One unanswered ask against one seat, in ACK.jsonl.
7
+ *
8
+ * `ackedAt` is the whole state: empty means open, set means cleared. Every other
9
+ * field is provenance for the operator reading `ack list`.
10
+ */
11
+ export interface AckRow {
12
+ id: string;
13
+ /** Opened at (ISO). */
14
+ at: string;
15
+ /** Agent id of the seat that owes the answer (manager, secretary, worker-1). */
16
+ seat: string;
17
+ paneId: string;
18
+ source: AckSource;
19
+ /** Sender agent id for mesh mail; unset for operator prompts. */
20
+ from?: string;
21
+ /** The ask, trimmed to ACK_ASK_MAX. */
22
+ ask: string;
23
+ /** The one state field — empty = open. */
24
+ ackedAt?: string;
25
+ ackBy?: AckCloseBy;
26
+ ackNote?: string;
27
+ /** Reminder injects fired so far. */
28
+ reminders: number;
29
+ remindedAt?: string;
30
+ }
31
+ export interface AckOpenInput {
32
+ seat: string;
33
+ paneId: string;
34
+ source: AckSource;
35
+ ask: string;
36
+ from?: string;
37
+ id?: string;
38
+ at?: string;
39
+ }
40
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ack/types.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/D,yEAAyE;AACzE,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,uBAAuB;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;IAClB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;CACb"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ack/types.ts"],"names":[],"mappings":""}