@ashx-j/lunr 0.2.18 → 0.2.20

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 (190) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/README.md +2 -2
  3. package/dist/builtin-extensions/ashxj-tui.d.ts +2 -2
  4. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  5. package/dist/builtin-extensions/ashxj-tui.js +11 -8
  6. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  7. package/dist/builtin-extensions/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/index.js +0 -2
  9. package/dist/builtin-extensions/index.js.map +1 -1
  10. package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts +6 -4
  11. package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts.map +1 -1
  12. package/dist/builtin-extensions/pi-intercom/broker/spawn.js +93 -49
  13. package/dist/builtin-extensions/pi-intercom/broker/spawn.js.map +1 -1
  14. package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-intercom/index.js +351 -351
  16. package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +2 -1
  18. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +80 -43
  20. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +18 -8
  22. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  23. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +36 -11
  24. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -3
  26. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  27. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +21 -12
  28. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  29. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts +7 -1
  30. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  31. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js +225 -15
  32. package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js.map +1 -1
  33. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts +29 -0
  34. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts.map +1 -0
  35. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js +179 -0
  36. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js.map +1 -0
  37. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts +89 -0
  38. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts.map +1 -0
  39. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js +541 -0
  40. package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js.map +1 -0
  41. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +9 -1
  42. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  43. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +34 -9
  44. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  45. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.d.ts.map +1 -1
  46. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js +1 -2
  47. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +2 -1
  49. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +35 -8
  51. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts +1 -1
  53. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts.map +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js +3 -3
  55. package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js.map +1 -1
  56. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts +1 -0
  57. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts.map +1 -1
  58. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js +54 -38
  59. package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js.map +1 -1
  60. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +3 -6
  61. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +64 -5
  63. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
  65. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +1 -0
  66. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
  67. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  68. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +21 -8
  69. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  70. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  71. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +62 -16
  72. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  73. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -0
  74. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
  75. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +75 -18
  76. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
  77. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +13 -1
  78. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
  79. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +67 -11
  80. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
  81. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
  82. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +5 -2
  83. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
  84. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  85. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +13 -3
  86. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  87. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +3 -0
  88. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
  89. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +68 -11
  90. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
  91. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +12 -1
  92. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
  93. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +21 -2
  94. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
  95. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +16 -4
  96. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  97. package/dist/builtin-extensions/pi-subagents/src/shared/types.js +1 -1
  98. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  99. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +2 -0
  100. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  101. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +24 -6
  102. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  103. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +44 -4
  104. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  105. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +227 -133
  106. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  107. package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.d.ts.map +1 -1
  108. package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js +1 -1
  109. package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js.map +1 -1
  110. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts +2 -13
  111. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts.map +1 -1
  112. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js +5 -91
  113. package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js.map +1 -1
  114. package/dist/core/permissions.d.ts +1 -0
  115. package/dist/core/permissions.d.ts.map +1 -1
  116. package/dist/core/permissions.js +8 -4
  117. package/dist/core/permissions.js.map +1 -1
  118. package/dist/core/plan-mode.d.ts.map +1 -1
  119. package/dist/core/plan-mode.js +0 -5
  120. package/dist/core/plan-mode.js.map +1 -1
  121. package/dist/core/runtime-bridges.d.ts.map +1 -1
  122. package/dist/core/runtime-bridges.js +0 -2
  123. package/dist/core/runtime-bridges.js.map +1 -1
  124. package/dist/core/subagent-cancellation.d.ts +21 -0
  125. package/dist/core/subagent-cancellation.d.ts.map +1 -0
  126. package/dist/core/subagent-cancellation.js +53 -0
  127. package/dist/core/subagent-cancellation.js.map +1 -0
  128. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  129. package/dist/modes/interactive/components/assistant-message.js +12 -18
  130. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  131. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  132. package/dist/modes/interactive/components/tool-execution.js +12 -0
  133. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  134. package/dist/modes/interactive/interactive-mode.d.ts +1 -2
  135. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  136. package/dist/modes/interactive/interactive-mode.js +29 -22
  137. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  138. package/dist/node-runtime/{agent-session-services-35WNVGMR.js → agent-session-services-75JKASCW.js} +3 -3
  139. package/dist/node-runtime/{builtin-extensions-QATGXENO.js → builtin-extensions-X4JMM4ZS.js} +3 -3
  140. package/dist/node-runtime/{chunk-XATUM2HK.js → chunk-25I2BHAA.js} +1 -1
  141. package/dist/node-runtime/{chunk-MCUNIRD5.js → chunk-46ECNOLF.js} +477 -246
  142. package/dist/node-runtime/{chunk-J26TSGDL.js → chunk-6N22HULO.js} +8 -5
  143. package/dist/node-runtime/{chunk-NI6OTSBH.js → chunk-AL2FMKKM.js} +7 -7
  144. package/dist/node-runtime/chunk-AOFXZQKA.js +24 -0
  145. package/dist/node-runtime/chunk-BBUVIEZB.js +51 -0
  146. package/dist/node-runtime/{chunk-EBF6COVM.js → chunk-ELWEXVO5.js} +7 -7
  147. package/dist/node-runtime/{chunk-R5EDISSV.js → chunk-JHYKXIMM.js} +5 -2
  148. package/dist/node-runtime/{chunk-ATGA2WLC.js → chunk-JYNNB7DU.js} +397 -34
  149. package/dist/node-runtime/{chunk-ZBV7FAHG.js → chunk-K3646JTM.js} +17 -118
  150. package/dist/node-runtime/{chunk-PNJSG3IZ.js → chunk-LTYWTR3V.js} +1 -369
  151. package/dist/node-runtime/{chunk-G4P75AIS.js → chunk-QKFMBRAL.js} +47 -54
  152. package/dist/node-runtime/cli-runtime.js +1 -1
  153. package/dist/node-runtime/{command-AAV3YRR5.js → command-RBTRL55A.js} +1 -1
  154. package/dist/node-runtime/{gateway-OAC4OBBL.js → gateway-L4ANRTVE.js} +2 -2
  155. package/dist/node-runtime/index.js +10 -9
  156. package/dist/node-runtime/{interactive-mode-2SZUO53H.js → interactive-mode-HPUNH7SV.js} +5 -4
  157. package/dist/node-runtime/{interactive-view-S6J3QHEF.js → interactive-view-ILS6TAN5.js} +1 -1
  158. package/dist/node-runtime/{lunr-cron-AUUYP4N4.js → lunr-cron-NNYTWTGF.js} +2 -2
  159. package/dist/node-runtime/main.js +8 -8
  160. package/dist/node-runtime/{pi-intercom-EEMBGQID.js → pi-intercom-DDQMRNPJ.js} +96 -76
  161. package/dist/node-runtime/{pi-subagents-7YJ3I4VE.js → pi-subagents-T5WMMLBB.js} +1040 -318
  162. package/dist/node-runtime/rpc-entry.js +8 -8
  163. package/dist/node-runtime/{runtime-bridges-3RKBDLNA.js → runtime-bridges-NJQERQ72.js} +2 -4
  164. package/dist/node-runtime/{subagent-executor-5Q5A4HJ2.js → subagent-executor-SRFC26SJ.js} +168 -249
  165. package/docs/features.md +17 -3
  166. package/docs/keybindings.md +3 -1
  167. package/docs/settings.md +1 -1
  168. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  169. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  170. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  171. package/examples/extensions/gondolin/package-lock.json +2 -2
  172. package/examples/extensions/gondolin/package.json +1 -1
  173. package/examples/extensions/sandbox/package-lock.json +2 -2
  174. package/examples/extensions/sandbox/package.json +1 -1
  175. package/examples/extensions/with-deps/package-lock.json +2 -2
  176. package/examples/extensions/with-deps/package.json +1 -1
  177. package/package.json +4 -4
  178. package/dist/builtin-extensions/lunr-settings-tools.d.ts +0 -4
  179. package/dist/builtin-extensions/lunr-settings-tools.d.ts.map +0 -1
  180. package/dist/builtin-extensions/lunr-settings-tools.js +0 -120
  181. package/dist/builtin-extensions/lunr-settings-tools.js.map +0 -1
  182. package/dist/core/settings-tools-bridge.d.ts +0 -35
  183. package/dist/core/settings-tools-bridge.d.ts.map +0 -1
  184. package/dist/core/settings-tools-bridge.js +0 -56
  185. package/dist/core/settings-tools-bridge.js.map +0 -1
  186. package/dist/modes/interactive/injected-context.d.ts +0 -2
  187. package/dist/modes/interactive/injected-context.d.ts.map +0 -1
  188. package/dist/modes/interactive/injected-context.js +0 -7
  189. package/dist/modes/interactive/injected-context.js.map +0 -1
  190. package/dist/node-runtime/chunk-3NMWLTPV.js +0 -64
@@ -0,0 +1,89 @@
1
+ export declare const QUESTIONS_DIR = "questions";
2
+ export declare const SUPERVISOR_CHANNEL_ROOT: string;
3
+ export declare const SUBAGENT_SUPERVISOR_ANSWER_TYPE = "subagent_supervisor_answer";
4
+ export declare const SUBAGENT_QUESTION_EVENT = "subagent:supervisor-question";
5
+ export type SupervisorQuestionPublicState = "pending" | "answered" | "expired" | "cancelled";
6
+ export interface SupervisorChildIncarnation {
7
+ pid: number;
8
+ readyAt: number;
9
+ }
10
+ export interface SupervisorQuestion {
11
+ type: "subagent.supervisor.question";
12
+ id: string;
13
+ createdAt: number;
14
+ expiresAt: number;
15
+ reason: string;
16
+ message: string;
17
+ runId: string;
18
+ childIndex: number;
19
+ childId: string;
20
+ parentSessionId: string;
21
+ parentGeneration: number;
22
+ childIncarnation?: SupervisorChildIncarnation;
23
+ deliveredAt?: number;
24
+ answeredAt?: number;
25
+ expiredAt?: number;
26
+ cancelledAt?: number;
27
+ cancelReason?: string;
28
+ notifiedAt?: number;
29
+ lateAnswerAt?: number;
30
+ answer?: string;
31
+ }
32
+ export interface SupervisorQuestionOwner {
33
+ runId: string;
34
+ childIndex: number;
35
+ childId: string;
36
+ pid: number;
37
+ readyAt: number;
38
+ }
39
+ export declare function resolveSupervisorChannelDir(runId: string, agent: string, childIndex: number): string;
40
+ export declare function questionsDir(channelDir: string): string;
41
+ export declare function ensureQuestionsDir(channelDir: string): void;
42
+ export declare function supervisorQuestionPublicState(question: SupervisorQuestion): SupervisorQuestionPublicState;
43
+ export declare function supervisorQuestionIsTerminal(question: SupervisorQuestion): boolean;
44
+ export declare function readSupervisorQuestion(channelDir: string, questionId: string): SupervisorQuestion | undefined;
45
+ export declare function listSupervisorQuestions(channelDir: string): SupervisorQuestion[];
46
+ export declare function createSupervisorQuestion(input: {
47
+ channelDir: string;
48
+ reason: string;
49
+ message: string;
50
+ runId: string;
51
+ childIndex: number;
52
+ childId: string;
53
+ parentSessionId: string;
54
+ parentGeneration: number;
55
+ childIncarnation?: SupervisorChildIncarnation;
56
+ now?: number;
57
+ timeoutMs?: number;
58
+ id?: string;
59
+ }): SupervisorQuestion;
60
+ export declare function outstandingQuestionsForChild(channelDir: string, childIndex: number, childId?: string): SupervisorQuestion[];
61
+ export declare function hasBlockingSupervisorRequest(channelDir: string, runId: string, childIndex: number): boolean;
62
+ export declare function hasOutstandingQuestionForChild(channelDir: string, childIndex: number, childId?: string): boolean;
63
+ export declare function incarnationMatches(expected: SupervisorChildIncarnation | undefined, actual: SupervisorChildIncarnation): boolean;
64
+ export declare function markSupervisorQuestionDelivered(channelDir: string, questionId: string, owner: SupervisorQuestionOwner, now?: number): SupervisorQuestion | undefined;
65
+ export declare function answerSupervisorQuestion(channelDir: string, questionId: string, answer: string, owner: SupervisorQuestionOwner, now?: number): SupervisorQuestion;
66
+ export declare function expireSupervisorQuestion(channelDir: string, questionId: string, now?: number): SupervisorQuestion | undefined;
67
+ export declare function cancelSupervisorQuestion(channelDir: string, questionId: string, reason: string, now?: number): SupervisorQuestion | undefined;
68
+ export declare function refreshSupervisorQuestionLifecycle(channelDir: string, now?: number): SupervisorQuestion[];
69
+ export declare function formatParentQuestionForChild(question: SupervisorQuestion): string;
70
+ export declare function formatSupervisorQuestionAnswer(question: SupervisorQuestion): string;
71
+ export declare function registerQuestionWait(questionIds: Iterable<string>): () => void;
72
+ export declare function isQuestionWaitActive(questionId: string): boolean;
73
+ export declare function claimQuestionNotification(channelDir: string, questionId: string, now?: number): boolean;
74
+ export declare function markSupervisorQuestionNotified(channelDir: string, questionId: string, now?: number): SupervisorQuestion | undefined;
75
+ export declare function resetSupervisorQuestionTestState(): void;
76
+ export declare function listSupervisorChannelDirs(): string[];
77
+ export declare function findSupervisorQuestion(questionId: string): {
78
+ channelDir: string;
79
+ question: SupervisorQuestion;
80
+ } | undefined;
81
+ export declare function cancelPendingSupervisorQuestionsForOwner(input: {
82
+ parentSessionId: string;
83
+ parentGeneration?: number;
84
+ runId?: string;
85
+ reason: string;
86
+ now?: number;
87
+ }): SupervisorQuestion[];
88
+ export declare function pendingSupervisorQuestionsForDelivery(channelDir: string, owner: SupervisorQuestionOwner, now?: number): SupervisorQuestion[];
89
+ //# sourceMappingURL=supervisor-questions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor-questions.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { TEMP_ROOT_DIR } from \"../shared/types.ts\";\n\nexport const QUESTIONS_DIR = \"questions\";\nexport const SUPERVISOR_CHANNEL_ROOT = path.join(TEMP_ROOT_DIR, \"supervisor-channels\");\nexport const SUBAGENT_SUPERVISOR_ANSWER_TYPE = \"subagent_supervisor_answer\";\nexport const SUBAGENT_QUESTION_EVENT = \"subagent:supervisor-question\";\n\nexport type SupervisorQuestionPublicState = \"pending\" | \"answered\" | \"expired\" | \"cancelled\";\n\nexport interface SupervisorChildIncarnation {\n\tpid: number;\n\treadyAt: number;\n}\n\nexport interface SupervisorQuestion {\n\ttype: \"subagent.supervisor.question\";\n\tid: string;\n\tcreatedAt: number;\n\texpiresAt: number;\n\treason: string;\n\tmessage: string;\n\trunId: string;\n\tchildIndex: number;\n\tchildId: string;\n\tparentSessionId: string;\n\tparentGeneration: number;\n\tchildIncarnation?: SupervisorChildIncarnation;\n\tdeliveredAt?: number;\n\tansweredAt?: number;\n\texpiredAt?: number;\n\tcancelledAt?: number;\n\tcancelReason?: string;\n\tnotifiedAt?: number;\n\tlateAnswerAt?: number;\n\tanswer?: string;\n}\n\nexport interface SupervisorQuestionOwner {\n\trunId: string;\n\tchildIndex: number;\n\tchildId: string;\n\tpid: number;\n\treadyAt: number;\n}\n\ninterface QuestionRecord {\n\ttype: \"subagent.supervisor.question\";\n\tid: string;\n\tcreatedAt: number;\n\texpiresAt: number;\n\treason: string;\n\tmessage: string;\n\trunId: string;\n\tchildIndex: number;\n\tchildId: string;\n\tparentSessionId: string;\n\tparentGeneration: number;\n\tchildIncarnation?: SupervisorChildIncarnation;\n}\n\ninterface DeliveredRecord {\n\ttype: \"subagent.supervisor.delivered\";\n\tid: string;\n\tat: number;\n\tpid: number;\n\treadyAt: number;\n}\n\ntype TerminalRecord =\n\t| { type: \"subagent.supervisor.terminal\"; id: string; state: \"answered\"; at: number; message: string }\n\t| { type: \"subagent.supervisor.terminal\"; id: string; state: \"expired\"; at: number }\n\t| { type: \"subagent.supervisor.terminal\"; id: string; state: \"cancelled\"; at: number; reason: string };\n\ninterface NotifiedRecord {\n\ttype: \"subagent.supervisor.notified\";\n\tid: string;\n\tat: number;\n}\n\ninterface LateAnswerRecord {\n\ttype: \"subagent.supervisor.late-answer\";\n\tid: string;\n\tat: number;\n\tmessage: string;\n}\n\nconst MAX_MESSAGE_BYTES = 64 * 1024;\nconst DEFAULT_ASK_TIMEOUT_MS = 10 * 60 * 1000;\nconst activeQuestionWaits = new Set<string>();\n\nfunction askTimeoutMs(): number {\n\tconst parsed = Number(process.env.PI_INTERCOM_ASK_TIMEOUT_MS);\n\treturn Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_ASK_TIMEOUT_MS;\n}\n\nfunction safeSegment(value: string): string {\n\treturn value.trim().replace(/[^A-Za-z0-9._-]+/g, \"-\").replace(/^-+|-+$/g, \"\") || \"unknown\";\n}\n\nexport function resolveSupervisorChannelDir(runId: string, agent: string, childIndex: number): string {\n\treturn path.join(SUPERVISOR_CHANNEL_ROOT, `${safeSegment(runId)}-${safeSegment(agent)}-${childIndex}`);\n}\n\nexport function questionsDir(channelDir: string): string {\n\treturn path.join(channelDir, QUESTIONS_DIR);\n}\n\nfunction questionFile(channelDir: string, questionId: string): string {\n\treturn path.join(questionsDir(channelDir), `${safeSegment(questionId)}.json`);\n}\n\nfunction deliveredFile(channelDir: string, questionId: string): string {\n\treturn path.join(questionsDir(channelDir), `${safeSegment(questionId)}.delivered.json`);\n}\n\nfunction terminalFile(channelDir: string, questionId: string): string {\n\treturn path.join(questionsDir(channelDir), `${safeSegment(questionId)}.terminal.json`);\n}\n\nfunction notifiedFile(channelDir: string, questionId: string): string {\n\treturn path.join(questionsDir(channelDir), `${safeSegment(questionId)}.notified.json`);\n}\n\nfunction lateFile(channelDir: string, questionId: string): string {\n\treturn path.join(questionsDir(channelDir), `${safeSegment(questionId)}.late.json`);\n}\n\nfunction writeExclusiveJson(filePath: string, payload: object): boolean {\n\tfs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n\tconst temporary = `${filePath}.${randomUUID()}.tmp`;\n\ttry {\n\t\tfs.writeFileSync(temporary, JSON.stringify(payload), { encoding: \"utf-8\", flag: \"wx\", mode: 0o600 });\n\t\t// Publish a complete record without overwriting a competing terminal outcome.\n\t\tfs.linkSync(temporary, filePath);\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") return false;\n\t\tthrow error;\n\t} finally {\n\t\tfs.rmSync(temporary, { force: true });\n\t}\n}\n\nfunction readJsonFile(filePath: string): unknown {\n\treturn JSON.parse(fs.readFileSync(filePath, \"utf-8\"));\n}\n\nfunction tryReadJson(filePath: string): unknown | undefined {\n\ttry {\n\t\treturn readJsonFile(filePath);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n\t\treturn undefined;\n\t}\n}\n\nfunction parseIncarnation(raw: unknown): SupervisorChildIncarnation | undefined {\n\tif (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n\tconst input = raw as Partial<SupervisorChildIncarnation>;\n\tconst pid = input.pid;\n\tconst readyAt = input.readyAt;\n\tif (!Number.isInteger(pid) || pid === undefined || pid <= 0) return undefined;\n\tif (typeof readyAt !== \"number\" || !Number.isFinite(readyAt) || readyAt <= 0) return undefined;\n\treturn { pid, readyAt };\n}\n\nfunction parseQuestionRecord(raw: unknown): QuestionRecord | undefined {\n\tif (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n\tconst input = raw as Partial<QuestionRecord>;\n\tif (input.type !== \"subagent.supervisor.question\") return undefined;\n\tif (typeof input.id !== \"string\" || !input.id.trim()) return undefined;\n\tif (typeof input.createdAt !== \"number\" || !Number.isFinite(input.createdAt)) return undefined;\n\tif (typeof input.expiresAt !== \"number\" || !Number.isFinite(input.expiresAt)) return undefined;\n\tif (typeof input.reason !== \"string\" || !input.reason.trim()) return undefined;\n\tif (typeof input.message !== \"string\" || !input.message.trim()) return undefined;\n\tif (typeof input.runId !== \"string\" || !input.runId.trim()) return undefined;\n\tconst childIndex = input.childIndex;\n\tif (!Number.isInteger(childIndex) || childIndex === undefined || childIndex < 0) return undefined;\n\tif (typeof input.childId !== \"string\" || !input.childId.trim()) return undefined;\n\tif (typeof input.parentSessionId !== \"string\" || !input.parentSessionId.trim()) return undefined;\n\tconst parentGeneration = input.parentGeneration;\n\tif (!Number.isInteger(parentGeneration) || parentGeneration === undefined || parentGeneration < 0) return undefined;\n\tconst incarnation = parseIncarnation(input.childIncarnation);\n\treturn {\n\t\ttype: \"subagent.supervisor.question\",\n\t\tid: input.id.trim(),\n\t\tcreatedAt: input.createdAt,\n\t\texpiresAt: input.expiresAt,\n\t\treason: input.reason.trim(),\n\t\tmessage: input.message.trim(),\n\t\trunId: input.runId.trim(),\n\t\tchildIndex,\n\t\tchildId: input.childId.trim(),\n\t\tparentSessionId: input.parentSessionId.trim(),\n\t\tparentGeneration,\n\t\t...(incarnation ? { childIncarnation: incarnation } : {}),\n\t};\n}\n\nfunction parseDeliveredRecord(raw: unknown): DeliveredRecord | undefined {\n\tif (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n\tconst input = raw as Partial<DeliveredRecord>;\n\tif (input.type !== \"subagent.supervisor.delivered\" || typeof input.id !== \"string\" || !input.id.trim()) return undefined;\n\tif (typeof input.at !== \"number\" || !Number.isFinite(input.at)) return undefined;\n\tconst incarnation = parseIncarnation(input);\n\tif (!incarnation) return undefined;\n\treturn { type: \"subagent.supervisor.delivered\", id: input.id.trim(), at: input.at, pid: incarnation.pid, readyAt: incarnation.readyAt };\n}\n\nfunction parseTerminalRecord(raw: unknown): TerminalRecord | undefined {\n\tif (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n\tconst input = raw as Partial<TerminalRecord> & { message?: unknown; reason?: unknown };\n\tif (input.type !== \"subagent.supervisor.terminal\" || typeof input.id !== \"string\" || !input.id.trim()) return undefined;\n\tif (typeof input.at !== \"number\" || !Number.isFinite(input.at)) return undefined;\n\tif (input.state === \"answered\") {\n\t\tif (typeof input.message !== \"string\" || !input.message.trim()) return undefined;\n\t\treturn { type: \"subagent.supervisor.terminal\", id: input.id.trim(), state: \"answered\", at: input.at, message: input.message };\n\t}\n\tif (input.state === \"expired\") {\n\t\treturn { type: \"subagent.supervisor.terminal\", id: input.id.trim(), state: \"expired\", at: input.at };\n\t}\n\tif (input.state === \"cancelled\") {\n\t\tif (typeof input.reason !== \"string\" || !input.reason.trim()) return undefined;\n\t\treturn { type: \"subagent.supervisor.terminal\", id: input.id.trim(), state: \"cancelled\", at: input.at, reason: input.reason.trim() };\n\t}\n\treturn undefined;\n}\n\nfunction parseNotifiedRecord(raw: unknown): NotifiedRecord | undefined {\n\tif (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n\tconst input = raw as Partial<NotifiedRecord>;\n\tif (input.type !== \"subagent.supervisor.notified\" || typeof input.id !== \"string\" || !input.id.trim()) return undefined;\n\tif (typeof input.at !== \"number\" || !Number.isFinite(input.at)) return undefined;\n\treturn { type: \"subagent.supervisor.notified\", id: input.id.trim(), at: input.at };\n}\n\nfunction parseLateRecord(raw: unknown): LateAnswerRecord | undefined {\n\tif (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n\tconst input = raw as Partial<LateAnswerRecord>;\n\tif (input.type !== \"subagent.supervisor.late-answer\" || typeof input.id !== \"string\" || !input.id.trim()) return undefined;\n\tif (typeof input.at !== \"number\" || !Number.isFinite(input.at) || typeof input.message !== \"string\") return undefined;\n\treturn { type: \"subagent.supervisor.late-answer\", id: input.id.trim(), at: input.at, message: input.message };\n}\n\nfunction composeQuestion(record: QuestionRecord, channelDir: string): SupervisorQuestion {\n\tconst delivered = parseDeliveredRecord(tryReadJson(deliveredFile(channelDir, record.id)));\n\tconst terminal = parseTerminalRecord(tryReadJson(terminalFile(channelDir, record.id)));\n\tconst notified = parseNotifiedRecord(tryReadJson(notifiedFile(channelDir, record.id)));\n\tconst late = parseLateRecord(tryReadJson(lateFile(channelDir, record.id)));\n\treturn {\n\t\t...record,\n\t\t...(delivered ? { deliveredAt: delivered.at, childIncarnation: record.childIncarnation ?? { pid: delivered.pid, readyAt: delivered.readyAt } } : {}),\n\t\t...(terminal?.state === \"answered\" ? { answeredAt: terminal.at, answer: terminal.message } : {}),\n\t\t...(terminal?.state === \"expired\" ? { expiredAt: terminal.at } : {}),\n\t\t...(terminal?.state === \"cancelled\" ? { cancelledAt: terminal.at, cancelReason: terminal.reason } : {}),\n\t\t...(notified ? { notifiedAt: notified.at } : {}),\n\t\t...(late ? { lateAnswerAt: late.at, ...(terminal?.state === \"answered\" ? {} : { answer: late.message }) } : {}),\n\t};\n}\n\nfunction assertMessageSize(value: string, label: string): void {\n\tif (Buffer.byteLength(value, \"utf-8\") > MAX_MESSAGE_BYTES) throw new Error(`${label} is too large.`);\n}\n\nexport function ensureQuestionsDir(channelDir: string): void {\n\tfs.mkdirSync(questionsDir(channelDir), { recursive: true, mode: 0o700 });\n}\n\nexport function supervisorQuestionPublicState(question: SupervisorQuestion): SupervisorQuestionPublicState {\n\tif (question.answeredAt) return \"answered\";\n\tif (question.expiredAt) return \"expired\";\n\tif (question.cancelledAt) return \"cancelled\";\n\treturn \"pending\";\n}\n\nexport function supervisorQuestionIsTerminal(question: SupervisorQuestion): boolean {\n\treturn supervisorQuestionPublicState(question) !== \"pending\";\n}\n\nexport function readSupervisorQuestion(channelDir: string, questionId: string): SupervisorQuestion | undefined {\n\tconst record = parseQuestionRecord(tryReadJson(questionFile(channelDir, questionId)));\n\tif (!record || record.id !== questionId) return undefined;\n\treturn composeQuestion(record, channelDir);\n}\n\nexport function listSupervisorQuestions(channelDir: string): SupervisorQuestion[] {\n\tconst dir = questionsDir(channelDir);\n\tlet entries: string[];\n\ttry {\n\t\tentries = fs.readdirSync(dir).filter((name) => name.endsWith(\".json\") && !name.endsWith(\".delivered.json\") && !name.endsWith(\".terminal.json\") && !name.endsWith(\".notified.json\") && !name.endsWith(\".late.json\"));\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n\t\tthrow error;\n\t}\n\tconst questions: SupervisorQuestion[] = [];\n\tfor (const entry of entries.sort()) {\n\t\tconst record = parseQuestionRecord(tryReadJson(path.join(dir, entry)));\n\t\tif (record) questions.push(composeQuestion(record, channelDir));\n\t}\n\treturn questions;\n}\n\nfunction writeTerminal(channelDir: string, record: TerminalRecord): boolean {\n\treturn writeExclusiveJson(terminalFile(channelDir, record.id), record);\n}\n\nfunction readTerminal(channelDir: string, questionId: string): TerminalRecord | undefined {\n\treturn parseTerminalRecord(tryReadJson(terminalFile(channelDir, questionId)));\n}\n\nexport function createSupervisorQuestion(input: {\n\tchannelDir: string;\n\treason: string;\n\tmessage: string;\n\trunId: string;\n\tchildIndex: number;\n\tchildId: string;\n\tparentSessionId: string;\n\tparentGeneration: number;\n\tchildIncarnation?: SupervisorChildIncarnation;\n\tnow?: number;\n\ttimeoutMs?: number;\n\tid?: string;\n}): SupervisorQuestion {\n\tconst reason = input.reason.trim();\n\tconst message = input.message.trim();\n\tif (!reason) throw new Error(\"reason is required and must name the concrete decision the child's answer will change.\");\n\tif (!message) throw new Error(\"message is required for supervisor questions.\");\n\tassertMessageSize(reason, \"reason\");\n\tassertMessageSize(message, \"message\");\n\tconst createdAt = input.now ?? Date.now();\n\tconst timeoutMs = input.timeoutMs && input.timeoutMs > 0 ? input.timeoutMs : askTimeoutMs();\n\tconst record: QuestionRecord = {\n\t\ttype: \"subagent.supervisor.question\",\n\t\tid: input.id ?? randomUUID(),\n\t\tcreatedAt,\n\t\texpiresAt: createdAt + timeoutMs,\n\t\treason,\n\t\tmessage,\n\t\trunId: input.runId,\n\t\tchildIndex: input.childIndex,\n\t\tchildId: input.childId,\n\t\tparentSessionId: input.parentSessionId,\n\t\tparentGeneration: input.parentGeneration,\n\t\t...(input.childIncarnation ? { childIncarnation: input.childIncarnation } : {}),\n\t};\n\tassertMessageSize(JSON.stringify(record), \"Supervisor question\");\n\tensureQuestionsDir(input.channelDir);\n\tif (!writeExclusiveJson(questionFile(input.channelDir, record.id), record)) {\n\t\tthrow new Error(`Supervisor question '${record.id}' already exists.`);\n\t}\n\treturn composeQuestion(record, input.channelDir);\n}\n\nexport function outstandingQuestionsForChild(channelDir: string, childIndex: number, childId?: string): SupervisorQuestion[] {\n\trefreshSupervisorQuestionLifecycle(channelDir);\n\treturn listSupervisorQuestions(channelDir).filter((question) => {\n\t\tif (supervisorQuestionIsTerminal(question)) return false;\n\t\tif (question.childIndex !== childIndex) return false;\n\t\tif (childId && question.childId !== childId) return false;\n\t\treturn true;\n\t});\n}\n\nexport function hasBlockingSupervisorRequest(channelDir: string, runId: string, childIndex: number): boolean {\n\tconst directory = path.join(channelDir, \"requests\");\n\tif (!fs.existsSync(directory)) return false;\n\tfor (const name of fs.readdirSync(directory)) {\n\t\tif (!name.endsWith(\".json\")) continue;\n\t\tconst raw = tryReadJson(path.join(directory, name));\n\t\tif (!raw || typeof raw !== \"object\") continue;\n\t\tconst request = raw as { type?: unknown; id?: unknown; expectsReply?: unknown; runId?: unknown; childIndex?: unknown; expiresAt?: unknown };\n\t\tif (request.type !== \"subagent.supervisor.request\" || request.expectsReply !== true) continue;\n\t\tif (request.runId !== runId || request.childIndex !== childIndex || typeof request.id !== \"string\") continue;\n\t\tif (typeof request.expiresAt === \"number\" && request.expiresAt <= Date.now()) continue;\n\t\tif (!fs.existsSync(path.join(channelDir, \"replies\", `${safeSegment(request.id)}.json`))) return true;\n\t}\n\treturn false;\n}\n\nexport function hasOutstandingQuestionForChild(channelDir: string, childIndex: number, childId?: string): boolean {\n\treturn outstandingQuestionsForChild(channelDir, childIndex, childId).length > 0;\n}\n\nexport function incarnationMatches(expected: SupervisorChildIncarnation | undefined, actual: SupervisorChildIncarnation): boolean {\n\tif (!expected) return true;\n\treturn expected.pid === actual.pid && expected.readyAt === actual.readyAt;\n}\n\nfunction assertOwner(question: SupervisorQuestion, owner: SupervisorQuestionOwner): void {\n\tif (owner.runId !== question.runId || owner.childIndex !== question.childIndex || owner.childId !== question.childId) {\n\t\tthrow new Error(`Supervisor question '${question.id}' is not owned by this child.`);\n\t}\n\tif (!incarnationMatches(question.childIncarnation, { pid: owner.pid, readyAt: owner.readyAt })) {\n\t\tthrow new Error(`Supervisor question '${question.id}' was bound to a different child incarnation.`);\n\t}\n}\n\nfunction ownerMatchesDelivered(channelDir: string, questionId: string, owner: SupervisorQuestionOwner): boolean {\n\tconst delivered = parseDeliveredRecord(tryReadJson(deliveredFile(channelDir, questionId)));\n\tif (!delivered) return true;\n\treturn delivered.pid === owner.pid && delivered.readyAt === owner.readyAt;\n}\n\nexport function markSupervisorQuestionDelivered(\n\tchannelDir: string,\n\tquestionId: string,\n\towner: SupervisorQuestionOwner,\n\tnow = Date.now(),\n): SupervisorQuestion | undefined {\n\tconst current = readSupervisorQuestion(channelDir, questionId);\n\tif (!current || supervisorQuestionIsTerminal(current)) return current;\n\tassertOwner(current, owner);\n\twriteExclusiveJson(deliveredFile(channelDir, questionId), {\n\t\ttype: \"subagent.supervisor.delivered\",\n\t\tid: questionId,\n\t\tat: now,\n\t\tpid: owner.pid,\n\t\treadyAt: owner.readyAt,\n\t} satisfies DeliveredRecord);\n\treturn readSupervisorQuestion(channelDir, questionId);\n}\n\nfunction rejectLateOrDuplicate(channelDir: string, questionId: string, answer: string, now: number, terminal: TerminalRecord): never {\n\twriteExclusiveJson(lateFile(channelDir, questionId), {\n\t\ttype: \"subagent.supervisor.late-answer\",\n\t\tid: questionId,\n\t\tat: now,\n\t\tmessage: answer,\n\t} satisfies LateAnswerRecord);\n\tif (terminal.state === \"answered\") throw new Error(`Supervisor question '${questionId}' was already answered.`);\n\tthrow new Error(`Supervisor question '${questionId}' is ${terminal.state} and no longer accepts an answer.`);\n}\n\nexport function answerSupervisorQuestion(\n\tchannelDir: string,\n\tquestionId: string,\n\tanswer: string,\n\towner: SupervisorQuestionOwner,\n\tnow = Date.now(),\n): SupervisorQuestion {\n\tconst trimmed = answer.trim();\n\tif (!trimmed) throw new Error(\"message is required for supervisor question replies.\");\n\tassertMessageSize(trimmed, \"answer\");\n\tconst current = readSupervisorQuestion(channelDir, questionId);\n\tif (!current) throw new Error(`No supervisor question found for replyTo '${questionId}'.`);\n\tassertOwner(current, owner);\n\tif (!ownerMatchesDelivered(channelDir, questionId, owner)) {\n\t\tthrow new Error(`Supervisor question '${questionId}' was bound to a different child incarnation.`);\n\t}\n\tif (now > current.expiresAt) {\n\t\twriteTerminal(channelDir, { type: \"subagent.supervisor.terminal\", id: questionId, state: \"expired\", at: now });\n\t\tconst terminal = readTerminal(channelDir, questionId);\n\t\tif (terminal && terminal.state !== \"answered\") {\n\t\t\trejectLateOrDuplicate(channelDir, questionId, trimmed, now, terminal);\n\t\t}\n\t\tif (terminal?.state === \"answered\") throw new Error(`Supervisor question '${questionId}' was already answered.`);\n\t}\n\tconst existing = readTerminal(channelDir, questionId);\n\tif (existing) rejectLateOrDuplicate(channelDir, questionId, trimmed, now, existing);\n\tif (!writeTerminal(channelDir, { type: \"subagent.supervisor.terminal\", id: questionId, state: \"answered\", at: now, message: trimmed })) {\n\t\tconst terminal = readTerminal(channelDir, questionId);\n\t\tif (terminal) rejectLateOrDuplicate(channelDir, questionId, trimmed, now, terminal);\n\t\tthrow new Error(`Supervisor question '${questionId}' is no longer pending.`);\n\t}\n\tconst answered = readSupervisorQuestion(channelDir, questionId);\n\tif (!answered) throw new Error(`Supervisor question '${questionId}' is no longer pending.`);\n\treturn answered;\n}\n\nexport function expireSupervisorQuestion(channelDir: string, questionId: string, now = Date.now()): SupervisorQuestion | undefined {\n\tconst current = readSupervisorQuestion(channelDir, questionId);\n\tif (!current || supervisorQuestionIsTerminal(current) || now <= current.expiresAt) return current && supervisorQuestionIsTerminal(current) ? current : undefined;\n\tif (!writeTerminal(channelDir, { type: \"subagent.supervisor.terminal\", id: questionId, state: \"expired\", at: now })) return readSupervisorQuestion(channelDir, questionId);\n\treturn readSupervisorQuestion(channelDir, questionId);\n}\n\nexport function cancelSupervisorQuestion(\n\tchannelDir: string,\n\tquestionId: string,\n\treason: string,\n\tnow = Date.now(),\n): SupervisorQuestion | undefined {\n\tconst current = readSupervisorQuestion(channelDir, questionId);\n\tif (!current || supervisorQuestionIsTerminal(current)) return current;\n\tif (!writeTerminal(channelDir, { type: \"subagent.supervisor.terminal\", id: questionId, state: \"cancelled\", at: now, reason: reason.trim() || \"cancelled\" })) {\n\t\treturn readSupervisorQuestion(channelDir, questionId);\n\t}\n\treturn readSupervisorQuestion(channelDir, questionId);\n}\n\nexport function refreshSupervisorQuestionLifecycle(channelDir: string, now = Date.now()): SupervisorQuestion[] {\n\tconst changed: SupervisorQuestion[] = [];\n\tfor (const question of listSupervisorQuestions(channelDir)) {\n\t\tif (supervisorQuestionIsTerminal(question)) continue;\n\t\tif (now > question.expiresAt) {\n\t\t\tconst expired = expireSupervisorQuestion(channelDir, question.id, now);\n\t\t\tif (expired && expired.expiredAt) changed.push(expired);\n\t\t}\n\t}\n\treturn changed;\n}\n\nexport function formatParentQuestionForChild(question: SupervisorQuestion): string {\n\treturn [\n\t\t`Parent question (${question.id})`,\n\t\t`Decision needed: ${question.reason}`,\n\t\t\"\",\n\t\tquestion.message,\n\t\t\"\",\n\t\t`Reply with: contact_supervisor({ action: \"reply\", replyTo: \"${question.id}\", message: \"...\" })`,\n\t\t\"Answer from current findings and uncertainty. Do not silently start extra investigation. Continue the assigned task after replying.\",\n\t].join(\"\\n\");\n}\n\nexport function formatSupervisorQuestionAnswer(question: SupervisorQuestion): string {\n\tconst state = supervisorQuestionPublicState(question);\n\tconst header = state === \"answered\"\n\t\t? `Subagent answer (${question.id})`\n\t\t: `Subagent question ${state} (${question.id})`;\n\tconst lines = [\n\t\theader,\n\t\t`Run: ${question.runId}`,\n\t\t`Child: ${question.childId} [#${question.childIndex}]`,\n\t\t`Decision: ${question.reason}`,\n\t];\n\tif (state === \"answered\" && question.answer?.trim()) {\n\t\tlines.push(\"\", question.answer.trim());\n\t} else if (question.cancelReason) {\n\t\tlines.push(\"\", question.cancelReason);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function registerQuestionWait(questionIds: Iterable<string>): () => void {\n\tconst ids = [...questionIds];\n\tfor (const id of ids) activeQuestionWaits.add(id);\n\treturn () => {\n\t\tfor (const id of ids) activeQuestionWaits.delete(id);\n\t};\n}\n\nexport function isQuestionWaitActive(questionId: string): boolean {\n\treturn activeQuestionWaits.has(questionId);\n}\n\nexport function claimQuestionNotification(channelDir: string, questionId: string, now = Date.now()): boolean {\n\treturn writeExclusiveJson(notifiedFile(channelDir, questionId), {\n\t\ttype: \"subagent.supervisor.notified\",\n\t\tid: questionId,\n\t\tat: now,\n\t} satisfies NotifiedRecord);\n}\n\nexport function markSupervisorQuestionNotified(channelDir: string, questionId: string, now = Date.now()): SupervisorQuestion | undefined {\n\tclaimQuestionNotification(channelDir, questionId, now);\n\treturn readSupervisorQuestion(channelDir, questionId);\n}\n\nexport function resetSupervisorQuestionTestState(): void {\n\tactiveQuestionWaits.clear();\n}\n\nexport function listSupervisorChannelDirs(): string[] {\n\tlet entries: fs.Dirent[];\n\ttry {\n\t\tentries = fs.readdirSync(SUPERVISOR_CHANNEL_ROOT, { withFileTypes: true });\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n\t\tthrow error;\n\t}\n\treturn entries.filter((entry) => entry.isDirectory()).map((entry) => path.join(SUPERVISOR_CHANNEL_ROOT, entry.name));\n}\n\nexport function findSupervisorQuestion(questionId: string): { channelDir: string; question: SupervisorQuestion } | undefined {\n\tconst id = questionId.trim();\n\tif (!id) return undefined;\n\tfor (const channelDir of listSupervisorChannelDirs()) {\n\t\tconst question = readSupervisorQuestion(channelDir, id);\n\t\tif (question) return { channelDir, question };\n\t}\n\treturn undefined;\n}\n\nexport function cancelPendingSupervisorQuestionsForOwner(input: {\n\tparentSessionId: string;\n\tparentGeneration?: number;\n\trunId?: string;\n\treason: string;\n\tnow?: number;\n}): SupervisorQuestion[] {\n\tif (!input.parentSessionId?.trim()) return [];\n\tconst now = input.now ?? Date.now();\n\tconst cancelled: SupervisorQuestion[] = [];\n\tfor (const channelDir of listSupervisorChannelDirs()) {\n\t\tfor (const question of listSupervisorQuestions(channelDir)) {\n\t\t\tif (supervisorQuestionIsTerminal(question)) continue;\n\t\t\tif (question.parentSessionId !== input.parentSessionId) continue;\n\t\t\tif (input.parentGeneration !== undefined && question.parentGeneration !== input.parentGeneration) continue;\n\t\t\tif (input.runId && question.runId !== input.runId) continue;\n\t\t\tconst next = cancelSupervisorQuestion(channelDir, question.id, input.reason, now);\n\t\t\tif (next?.cancelledAt) cancelled.push(next);\n\t\t}\n\t}\n\treturn cancelled;\n}\n\nexport function pendingSupervisorQuestionsForDelivery(channelDir: string, owner: SupervisorQuestionOwner, now = Date.now()): SupervisorQuestion[] {\n\trefreshSupervisorQuestionLifecycle(channelDir, now);\n\treturn listSupervisorQuestions(channelDir).filter((question) => {\n\t\tif (supervisorQuestionIsTerminal(question)) return false;\n\t\tif (question.deliveredAt) return false;\n\t\tif (question.runId !== owner.runId || question.childIndex !== owner.childIndex || question.childId !== owner.childId) return false;\n\t\tif (!incarnationMatches(question.childIncarnation, { pid: owner.pid, readyAt: owner.readyAt })) return false;\n\t\treturn now <= question.expiresAt;\n\t});\n}\n"]}