neoctl 0.2.29 → 0.2.31

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 (98) hide show
  1. package/README.md +40 -4
  2. package/dist/context/compaction.d.ts +20 -4
  3. package/dist/context/compaction.js +377 -186
  4. package/dist/context/compaction.js.map +1 -1
  5. package/dist/context/context-manager.d.ts +7 -1
  6. package/dist/context/context-manager.js +15 -11
  7. package/dist/context/context-manager.js.map +1 -1
  8. package/dist/context/prompts.js +2 -0
  9. package/dist/context/prompts.js.map +1 -1
  10. package/dist/context/smoke-context.js +266 -17
  11. package/dist/context/smoke-context.js.map +1 -1
  12. package/dist/core/assistant-output-filter.d.ts +1 -0
  13. package/dist/core/assistant-output-filter.js +54 -2
  14. package/dist/core/assistant-output-filter.js.map +1 -1
  15. package/dist/core/context-metrics.d.ts +1 -0
  16. package/dist/core/context-metrics.js +18 -12
  17. package/dist/core/context-metrics.js.map +1 -1
  18. package/dist/core/image-registry.d.ts +16 -3
  19. package/dist/core/image-registry.js +65 -30
  20. package/dist/core/image-registry.js.map +1 -1
  21. package/dist/core/image-storage.d.ts +15 -1
  22. package/dist/core/image-storage.js +140 -17
  23. package/dist/core/image-storage.js.map +1 -1
  24. package/dist/core/message-pipeline.js +18 -4
  25. package/dist/core/message-pipeline.js.map +1 -1
  26. package/dist/core/query-engine.d.ts +12 -2
  27. package/dist/core/query-engine.js +57 -8
  28. package/dist/core/query-engine.js.map +1 -1
  29. package/dist/core/query.d.ts +13 -2
  30. package/dist/core/query.js +56 -21
  31. package/dist/core/query.js.map +1 -1
  32. package/dist/core/smoke-core-loop.js +68 -3
  33. package/dist/core/smoke-core-loop.js.map +1 -1
  34. package/dist/core/smoke-image-integrity.d.ts +1 -0
  35. package/dist/core/smoke-image-integrity.js +67 -0
  36. package/dist/core/smoke-image-integrity.js.map +1 -0
  37. package/dist/core/state.d.ts +1 -1
  38. package/dist/core/state.js.map +1 -1
  39. package/dist/index.d.ts +1 -0
  40. package/dist/index.js +1 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/model/model-metadata.json +4 -4
  43. package/dist/plugins/plugin-system.d.ts +61 -0
  44. package/dist/plugins/plugin-system.js +189 -0
  45. package/dist/plugins/plugin-system.js.map +1 -0
  46. package/dist/plugins/smoke-plugin-system.d.ts +1 -0
  47. package/dist/plugins/smoke-plugin-system.js +63 -0
  48. package/dist/plugins/smoke-plugin-system.js.map +1 -0
  49. package/dist/repl/index.js +8 -3
  50. package/dist/repl/index.js.map +1 -1
  51. package/dist/session/session-export.d.ts +2 -0
  52. package/dist/session/session-export.js +10 -0
  53. package/dist/session/session-export.js.map +1 -1
  54. package/dist/session/session-store.d.ts +41 -0
  55. package/dist/session/session-store.js +292 -59
  56. package/dist/session/session-store.js.map +1 -1
  57. package/dist/session/smoke-session.js +127 -7
  58. package/dist/session/smoke-session.js.map +1 -1
  59. package/dist/tools/builtins/exec-process-manager.d.ts +16 -2
  60. package/dist/tools/builtins/exec-process-manager.js +119 -25
  61. package/dist/tools/builtins/exec-process-manager.js.map +1 -1
  62. package/dist/tools/builtins/exec-tool.js +11 -2
  63. package/dist/tools/builtins/exec-tool.js.map +1 -1
  64. package/dist/tools/builtins/image-generation-tool.js +32 -42
  65. package/dist/tools/builtins/image-generation-tool.js.map +1 -1
  66. package/dist/tools/builtins/image-loader-tool.js +10 -4
  67. package/dist/tools/builtins/image-loader-tool.js.map +1 -1
  68. package/dist/tools/builtins/image-note-tool.js +8 -3
  69. package/dist/tools/builtins/image-note-tool.js.map +1 -1
  70. package/dist/tools/registry.d.ts +8 -1
  71. package/dist/tools/registry.js +37 -13
  72. package/dist/tools/registry.js.map +1 -1
  73. package/dist/tools/smoke-exec-process.js +88 -4
  74. package/dist/tools/smoke-exec-process.js.map +1 -1
  75. package/dist/tools/smoke-tool-system.js +24 -6
  76. package/dist/tools/smoke-tool-system.js.map +1 -1
  77. package/dist/types/events.d.ts +5 -1
  78. package/dist/types/messages.d.ts +13 -5
  79. package/dist/types/messages.js +4 -0
  80. package/dist/types/messages.js.map +1 -1
  81. package/dist/ui/display-message.d.ts +10 -2
  82. package/dist/ui/display-message.js +18 -9
  83. package/dist/ui/display-message.js.map +1 -1
  84. package/dist/web/index.d.ts +176 -11
  85. package/dist/web/index.js +986 -106
  86. package/dist/web/index.js.map +1 -1
  87. package/dist/web/runtime-context-protocol.d.ts +12 -1
  88. package/dist/web/runtime-context-protocol.js +16 -1
  89. package/dist/web/runtime-context-protocol.js.map +1 -1
  90. package/dist/web/smoke-runtime-context-protocol.js +3 -0
  91. package/dist/web/smoke-runtime-context-protocol.js.map +1 -1
  92. package/dist/web/smoke-web-history.d.ts +1 -0
  93. package/dist/web/smoke-web-history.js +121 -0
  94. package/dist/web/smoke-web-history.js.map +1 -0
  95. package/dist/web/smoke-web-terminal-tasks.d.ts +1 -0
  96. package/dist/web/smoke-web-terminal-tasks.js +90 -0
  97. package/dist/web/smoke-web-terminal-tasks.js.map +1 -0
  98. package/package.json +5 -1
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { FileToolResultMemory, PERSISTED_OUTPUT_TAG } from "./tool-result-memory.js";
5
5
  import { SessionStore } from "./session-store.js";
6
6
  import { writeSessionMarkdownExport } from "./session-export.js";
7
- import { createThinkingMessage } from "../types/messages.js";
7
+ import { createTextMessage, createThinkingMessage } from "../types/messages.js";
8
8
  async function main() {
9
9
  const root = await fs.mkdtemp(path.join(os.tmpdir(), "agent-session-smoke-"));
10
10
  const sessionId = "smoke-session";
@@ -17,15 +17,56 @@ async function main() {
17
17
  for (const message of messages)
18
18
  store.recordMessage(message);
19
19
  store.recordMessage(createThinkingMessage("persisted visible reasoning"));
20
+ store.recordMessage(createTextMessage("assistant", "assistant before compact"));
20
21
  store.recordContentReplacements(first.records);
21
22
  store.recordTitle("Smoke Session Title", "initial");
22
23
  store.recordTitle("Refined Smoke Session Title", "refinement");
23
24
  store.recordFastMode(true);
25
+ store.recordContextWindowTokens(256000);
24
26
  store.recordMessage({ ...messages[0], role: "progress" });
27
+ const compactionBoundary = {
28
+ ...createTextMessage("system", "<compact_state>persisted compact state</compact_state>"),
29
+ isMeta: true,
30
+ metadata: { compactBoundary: true, compactionReason: "manualcompact", modelDriven: true },
31
+ };
32
+ const preservedUser = { ...createTextMessage("user", "preserved user request"), metadata: { compactPreservedUser: true } };
33
+ store.recordCompactCheckpoint([preservedUser, compactionBoundary], "manualcompact", {
34
+ reason: "manualcompact",
35
+ summary: "persisted compact summary",
36
+ continuationState: "persisted compact state",
37
+ sourceMessages: messages.length + 2,
38
+ preservedUserMessages: 1,
39
+ newWindowMessages: 2,
40
+ charsFreed: 1234,
41
+ modelDriven: true,
42
+ imageCount: 0,
43
+ });
44
+ store.recordMessage(createTextMessage("assistant", "assistant between compacts"));
45
+ const secondCompactionBoundary = {
46
+ ...createTextMessage("system", "<compact_state>second compact state</compact_state>"),
47
+ isMeta: true,
48
+ metadata: { compactBoundary: true, compactionReason: "manualcompact", modelDriven: true },
49
+ };
50
+ store.recordCompactCheckpoint([preservedUser, secondCompactionBoundary], "manualcompact", {
51
+ reason: "manualcompact",
52
+ summary: "second compact summary",
53
+ continuationState: "second compact state",
54
+ sourceMessages: 3,
55
+ preservedUserMessages: 1,
56
+ newWindowMessages: 2,
57
+ charsFreed: 2345,
58
+ modelDriven: true,
59
+ imageCount: 0,
60
+ });
61
+ store.recordMessage(createTextMessage("assistant", "assistant after second compact"));
25
62
  const resumed = await SessionStore.open({ agentId: "main", rootDir: root, sessionId, resume: true });
26
63
  const latest = await SessionStore.open({ agentId: "main", rootDir: root, resume: true });
27
64
  const listed = await SessionStore.list({ agentId: "main", rootDir: root });
28
65
  const resumedBudget = await resumed.toolResultMemory.applyBudget(resumed.getInitialMessages(), { maxSerializedLength: 180 });
66
+ const displayEntries = resumed.getDisplayEntries();
67
+ const displayMessages = displayEntries.filter((entry) => entry.type === "message").map((entry) => entry.message);
68
+ const displayCompactions = displayEntries.filter((entry) => entry.type === "compact");
69
+ const displayCompactionIndexes = displayEntries.flatMap((entry, index) => entry.type === "compact" ? [index] : []);
29
70
  const exportPath = path.join(root, "exports", "session.md");
30
71
  const exportResult = await writeSessionMarkdownExport({
31
72
  outputPath: exportPath,
@@ -41,6 +82,36 @@ async function main() {
41
82
  maxToolResultLines: 3,
42
83
  });
43
84
  const exportedMarkdown = await fs.readFile(exportPath, "utf8");
85
+ const truncatedTailSessionId = "truncated-tail-session";
86
+ const truncatedTailStore = await SessionStore.open({ agentId: "main", rootDir: root, sessionId: truncatedTailSessionId });
87
+ truncatedTailStore.recordMessage(createTextMessage("user", "durable before partial tail"));
88
+ await fs.appendFile(truncatedTailStore.transcriptPath, '{"type":"message","sessionId":"truncated-tail-session"', "utf8");
89
+ const recoveredTailStore = await SessionStore.open({ agentId: "main", rootDir: root, sessionId: truncatedTailSessionId, resume: true });
90
+ const recoveredTailMessagesBeforeAppend = recoveredTailStore.getInitialMessages();
91
+ const repairedTailText = await fs.readFile(truncatedTailStore.transcriptPath, "utf8");
92
+ recoveredTailStore.recordMessage(createTextMessage("assistant", "durable after partial tail"));
93
+ const recoveredTailAgain = await SessionStore.open({ agentId: "main", rootDir: root, sessionId: truncatedTailSessionId, resume: true });
94
+ const unterminatedValidSessionId = "unterminated-valid-session";
95
+ const unterminatedValidStore = await SessionStore.open({ agentId: "main", rootDir: root, sessionId: unterminatedValidSessionId });
96
+ unterminatedValidStore.recordMessage(createTextMessage("user", "valid record without final newline"));
97
+ const validTranscript = await fs.readFile(unterminatedValidStore.transcriptPath, "utf8");
98
+ await fs.writeFile(unterminatedValidStore.transcriptPath, validTranscript.replace(/\n$/u, ""), "utf8");
99
+ const recoveredValidTail = await SessionStore.open({ agentId: "main", rootDir: root, sessionId: unterminatedValidSessionId, resume: true });
100
+ const repairedValidText = await fs.readFile(unterminatedValidStore.transcriptPath, "utf8");
101
+ const corruptMiddleSessionId = "corrupt-middle-session";
102
+ const corruptMiddleStore = await SessionStore.open({ agentId: "main", rootDir: root, sessionId: corruptMiddleSessionId });
103
+ corruptMiddleStore.recordMessage(createTextMessage("user", "before corrupt middle"));
104
+ corruptMiddleStore.recordMessage(createTextMessage("assistant", "after corrupt middle"));
105
+ const corruptLines = (await fs.readFile(corruptMiddleStore.transcriptPath, "utf8")).trimEnd().split("\n");
106
+ await fs.writeFile(corruptMiddleStore.transcriptPath, `${corruptLines[0]}\n{malformed}\n${corruptLines[1]}\n`, "utf8");
107
+ const corruptMiddleRejected = await SessionStore.open({ agentId: "main", rootDir: root, sessionId: corruptMiddleSessionId, resume: true })
108
+ .then(() => false)
109
+ .catch((error) => error instanceof Error && error.message.includes("Malformed session transcript"));
110
+ const durabilitySessionsDeleted = await Promise.all([
111
+ truncatedTailSessionId,
112
+ unterminatedValidSessionId,
113
+ corruptMiddleSessionId,
114
+ ].map((durabilitySessionId) => SessionStore.delete({ rootDir: root, sessionId: durabilitySessionId })));
44
115
  const afterReset = await SessionStore.open({ agentId: "main", rootDir: root, sessionId, resume: true });
45
116
  afterReset.reset();
46
117
  const resetResume = await SessionStore.open({ agentId: "main", rootDir: root, sessionId, resume: true });
@@ -50,33 +121,82 @@ async function main() {
50
121
  persistedBlocks.length === 1 &&
51
122
  second.records.length === 0 &&
52
123
  JSON.stringify(first.messages) === JSON.stringify(second.messages) &&
53
- resumed.snapshot().resumedMessages === messages.length + 1 &&
54
- resumed.getInitialMessages().some((message) => message.blocks.some((block) => block.type === "thinking" && block.text === "persisted visible reasoning")) &&
124
+ resumed.snapshot().resumedMessages === 3 &&
125
+ resumed.getInitialMessages()[0]?.metadata?.compactPreservedUser === true &&
126
+ resumed.getInitialMessages()[1]?.metadata?.compactBoundary === true &&
127
+ resumed.getInitialMessages().at(-1)?.blocks.some((block) => block.type === "text" && block.text === "assistant after second compact") === true &&
128
+ displayMessages.length === messages.length + 4 &&
129
+ displayMessages.some((message) => message.role === "assistant" && message.blocks.some((block) => block.type === "text" && block.text === "assistant before compact")) &&
130
+ displayMessages.some((message) => message.role === "assistant" && message.blocks.some((block) => block.type === "text" && block.text === "assistant between compacts")) &&
131
+ displayMessages.some((message) => message.role === "assistant" && message.blocks.some((block) => block.type === "text" && block.text === "assistant after second compact")) &&
132
+ displayCompactions.length === 2 &&
133
+ displayCompactions[0]?.report?.summary === "persisted compact summary" &&
134
+ displayCompactions[1]?.report?.summary === "second compact summary" &&
135
+ displayEntries.findIndex((entry) => entry.type === "compact") > displayEntries.findIndex((entry) => entry.type === "message" && entry.message.blocks.some((block) => block.type === "text" && block.text === "assistant before compact")) &&
136
+ displayEntries.findIndex((entry) => entry.type === "message" && entry.message.blocks.some((block) => block.type === "text" && block.text === "assistant between compacts")) > displayEntries.findIndex((entry) => entry.type === "compact") &&
137
+ displayCompactionIndexes.at(-1) < displayEntries.findIndex((entry) => entry.type === "message" && entry.message.blocks.some((block) => block.type === "text" && block.text === "assistant after second compact")) &&
138
+ resumed.snapshot().lastCompaction?.summary === "second compact summary" &&
139
+ resumed.snapshot().lastCompaction?.continuationState === "second compact state" &&
55
140
  resumed.snapshot().title === "Refined Smoke Session Title" &&
56
141
  resumed.snapshot().titleKind === "refinement" &&
57
142
  resumed.snapshot().hasInitialTitle &&
58
143
  resumed.snapshot().hasTitleRefinement &&
59
144
  resumed.snapshot().fastMode === true &&
145
+ resumed.snapshot().contextWindowTokens === 256000 &&
146
+ resumed.getContextWindowTokens() === 256000 &&
60
147
  latest.snapshot().sessionId === sessionId &&
61
- latest.snapshot().resumedMessages === messages.length + 1 &&
148
+ latest.snapshot().resumedMessages === 3 &&
149
+ latest.snapshot().lastCompaction?.charsFreed === 2345 &&
62
150
  latest.snapshot().title === "Refined Smoke Session Title" &&
63
151
  latest.snapshot().titleKind === "refinement" &&
64
152
  listed.length === 1 &&
65
153
  listed[0]?.sessionId === sessionId &&
66
154
  listed[0]?.title === "Refined Smoke Session Title" &&
67
155
  resumedBudget.records.length === 0 &&
68
- resumedBudget.messages.some((message) => message.blocks.some((block) => block.type === "tool_result" && String(block.output).startsWith(PERSISTED_OUTPUT_TAG))) &&
156
+ resumedBudget.messages.every((message) => message.role !== "tool_result") &&
69
157
  exportResult.bytes > 0 &&
70
158
  exportedMarkdown.includes("# Neo Session Export") &&
71
159
  exportedMarkdown.includes("system prompt smoke") &&
72
160
  exportedMarkdown.includes("## Transcript") &&
73
161
  exportedMarkdown.includes("Tool use ID: call_a") &&
74
- exportedMarkdown.includes("persisted visible reasoning") &&
162
+ exportedMarkdown.includes("persisted compact state") &&
163
+ recoveredTailMessagesBeforeAppend.length === 1 &&
164
+ recoveredTailMessagesBeforeAppend[0]?.blocks.some((block) => block.type === "text" && block.text === "durable before partial tail") === true &&
165
+ repairedTailText.endsWith("\n") &&
166
+ repairedTailText.trimEnd().split("\n").length === 1 &&
167
+ recoveredTailAgain.getInitialMessages().length === 2 &&
168
+ recoveredTailAgain.getInitialMessages()[1]?.blocks.some((block) => block.type === "text" && block.text === "durable after partial tail") === true &&
169
+ recoveredValidTail.getInitialMessages().length === 1 &&
170
+ repairedValidText.endsWith("\n") &&
171
+ corruptMiddleRejected &&
172
+ durabilitySessionsDeleted.every(Boolean) &&
75
173
  resetResume.snapshot().resumedMessages === 0 &&
174
+ resetResume.snapshot().lastCompaction === undefined &&
76
175
  resetResume.snapshot().fastMode === true &&
176
+ resetResume.snapshot().contextWindowTokens === 256000 &&
77
177
  deleted &&
78
178
  listedAfterDelete.length === 0;
79
- console.log(JSON.stringify({ ok, firstRecords: first.records.length, persistedBlocks: persistedBlocks.length, exportResult, resumed: resumed.snapshot(), latest: latest.snapshot(), listed, reset: resetResume.snapshot(), deleted, listedAfterDelete }, null, 2));
179
+ console.log(JSON.stringify({
180
+ ok,
181
+ firstRecords: first.records.length,
182
+ persistedBlocks: persistedBlocks.length,
183
+ exportResult,
184
+ resumed: resumed.snapshot(),
185
+ latest: latest.snapshot(),
186
+ listed,
187
+ durability: {
188
+ recoveredTailMessagesBeforeAppend: recoveredTailMessagesBeforeAppend.length,
189
+ repairedTailLines: repairedTailText.trimEnd().split("\n").length,
190
+ recoveredTailAgainMessages: recoveredTailAgain.getInitialMessages().length,
191
+ recoveredValidTailMessages: recoveredValidTail.getInitialMessages().length,
192
+ repairedValidEndsWithNewline: repairedValidText.endsWith("\n"),
193
+ corruptMiddleRejected,
194
+ durabilitySessionsDeleted,
195
+ },
196
+ reset: resetResume.snapshot(),
197
+ deleted,
198
+ listedAfterDelete,
199
+ }, null, 2));
80
200
  if (!ok)
81
201
  process.exitCode = 1;
82
202
  }
@@ -1 +1 @@
1
- {"version":3,"file":"smoke-session.js","sourceRoot":"","sources":["../../src/session/smoke-session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"smoke-session.js","sourceRoot":"","sources":["../../src/session/smoke-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAgB,MAAM,sBAAsB,CAAC;AAE9F,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAC9E,MAAM,SAAS,GAAG,eAAe,CAAC;IAClC,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAEtC,MAAM,MAAM,GAAG,IAAI,oBAAoB,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,cAAc,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3H,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,eAAe,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CACzD,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,CACxH,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACrF,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC7D,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAC1E,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAChF,KAAK,CAAC,yBAAyB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/C,KAAK,CAAC,WAAW,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC;IACpD,KAAK,CAAC,WAAW,CAAC,6BAA6B,EAAE,YAAY,CAAC,CAAC;IAC/D,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IACxC,KAAK,CAAC,aAAa,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1D,MAAM,kBAAkB,GAAG;QACzB,GAAG,iBAAiB,CAAC,QAAQ,EAAE,wDAAwD,CAAC;QACxF,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,eAAe,EAAE,WAAW,EAAE,IAAI,EAAE;KAC1F,CAAC;IACF,MAAM,aAAa,GAAG,EAAE,GAAG,iBAAiB,CAAC,MAAM,EAAE,wBAAwB,CAAC,EAAE,QAAQ,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,EAAE,CAAC;IAC3H,KAAK,CAAC,uBAAuB,CAAC,CAAC,aAAa,EAAE,kBAAkB,CAAC,EAAE,eAAe,EAAE;QAClF,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,2BAA2B;QACpC,iBAAiB,EAAE,yBAAyB;QAC5C,cAAc,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC;QACnC,qBAAqB,EAAE,CAAC;QACxB,iBAAiB,EAAE,CAAC;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,CAAC;KACd,CAAC,CAAC;IACH,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC,CAAC;IAClF,MAAM,wBAAwB,GAAG;QAC/B,GAAG,iBAAiB,CAAC,QAAQ,EAAE,qDAAqD,CAAC;QACrF,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,eAAe,EAAE,WAAW,EAAE,IAAI,EAAE;KAC1F,CAAC;IACF,KAAK,CAAC,uBAAuB,CAAC,CAAC,aAAa,EAAE,wBAAwB,CAAC,EAAE,eAAe,EAAE;QACxF,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,wBAAwB;QACjC,iBAAiB,EAAE,sBAAsB;QACzC,cAAc,EAAE,CAAC;QACjB,qBAAqB,EAAE,CAAC;QACxB,iBAAiB,EAAE,CAAC;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,CAAC;KACd,CAAC,CAAC;IACH,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,WAAW,EAAE,gCAAgC,CAAC,CAAC,CAAC;IAEtF,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACrG,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACzF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7H,MAAM,cAAc,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IACnD,MAAM,eAAe,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjH,MAAM,kBAAkB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACtF,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,MAAM,0BAA0B,CAAC;QACpD,UAAU,EAAE,UAAU;QACtB,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE;QAC3B,OAAO,EAAE,MAAM;QACf,cAAc,EAAE;YACd,KAAK,EAAE,aAAa;YACpB,YAAY,EAAE,qBAAqB;YACnC,iBAAiB,EAAE,wCAAwC;YAC3D,eAAe,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;YAChG,QAAQ,EAAE,CAAC,4BAA4B,CAAC;SACzC;QACD,kBAAkB,EAAE,CAAC;KACtB,CAAC,CAAC;IACH,MAAM,gBAAgB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAE/D,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;IACxD,MAAM,kBAAkB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,sBAAsB,EAAE,CAAC,CAAC;IAC1H,kBAAkB,CAAC,aAAa,CAAC,iBAAiB,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAAC;IAC3F,MAAM,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,cAAc,EAAE,wDAAwD,EAAE,MAAM,CAAC,CAAC;IACzH,MAAM,kBAAkB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACxI,MAAM,iCAAiC,GAAG,kBAAkB,CAAC,kBAAkB,EAAE,CAAC;IAClF,MAAM,gBAAgB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACtF,kBAAkB,CAAC,aAAa,CAAC,iBAAiB,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC,CAAC;IAC/F,MAAM,kBAAkB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAExI,MAAM,0BAA0B,GAAG,4BAA4B,CAAC;IAChE,MAAM,sBAAsB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,0BAA0B,EAAE,CAAC,CAAC;IAClI,sBAAsB,CAAC,aAAa,CAAC,iBAAiB,CAAC,MAAM,EAAE,oCAAoC,CAAC,CAAC,CAAC;IACtG,MAAM,eAAe,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACzF,MAAM,EAAE,CAAC,SAAS,CAAC,sBAAsB,CAAC,cAAc,EAAE,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;IACvG,MAAM,kBAAkB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,0BAA0B,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5I,MAAM,iBAAiB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IAE3F,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;IACxD,MAAM,kBAAkB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,sBAAsB,EAAE,CAAC,CAAC;IAC1H,kBAAkB,CAAC,aAAa,CAAC,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAC;IACrF,kBAAkB,CAAC,aAAa,CAAC,iBAAiB,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC,CAAC;IACzF,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1G,MAAM,EAAE,CAAC,SAAS,CAAC,kBAAkB,CAAC,cAAc,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,kBAAkB,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvH,MAAM,qBAAqB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SACvI,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;SACjB,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC,CAAC;IAC/G,MAAM,yBAAyB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAClD,sBAAsB;QACtB,0BAA0B;QAC1B,sBAAsB;KACvB,CAAC,GAAG,CAAC,CAAC,mBAAmB,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAC;IAExG,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACxG,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACzG,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACxE,MAAM,iBAAiB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtF,MAAM,EAAE,GACN,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QAC1B,eAAe,CAAC,MAAM,KAAK,CAAC;QAC5B,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QAC3B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClE,OAAO,CAAC,QAAQ,EAAE,CAAC,eAAe,KAAK,CAAC;QACxC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,oBAAoB,KAAK,IAAI;QACxE,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,KAAK,IAAI;QACnE,OAAO,CAAC,kBAAkB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,gCAAgC,CAAC,KAAK,IAAI;QAC9I,eAAe,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC;QAC9C,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,0BAA0B,CAAC,CAAC;QACrK,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,4BAA4B,CAAC,CAAC;QACvK,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,gCAAgC,CAAC,CAAC;QAC3K,kBAAkB,CAAC,MAAM,KAAK,CAAC;QAC/B,kBAAkB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,KAAK,2BAA2B;QACtE,kBAAkB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,KAAK,wBAAwB;QACnE,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,0BAA0B,CAAC,CAAC;QACzO,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,4BAA4B,CAAC,CAAC,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;QAC3O,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,gCAAgC,CAAC,CAAC;QAClN,OAAO,CAAC,QAAQ,EAAE,CAAC,cAAc,EAAE,OAAO,KAAK,wBAAwB;QACvE,OAAO,CAAC,QAAQ,EAAE,CAAC,cAAc,EAAE,iBAAiB,KAAK,sBAAsB;QAC/E,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,KAAK,6BAA6B;QAC1D,OAAO,CAAC,QAAQ,EAAE,CAAC,SAAS,KAAK,YAAY;QAC7C,OAAO,CAAC,QAAQ,EAAE,CAAC,eAAe;QAClC,OAAO,CAAC,QAAQ,EAAE,CAAC,kBAAkB;QACrC,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,KAAK,IAAI;QACpC,OAAO,CAAC,QAAQ,EAAE,CAAC,mBAAmB,KAAK,MAAM;QACjD,OAAO,CAAC,sBAAsB,EAAE,KAAK,MAAM;QAC3C,MAAM,CAAC,QAAQ,EAAE,CAAC,SAAS,KAAK,SAAS;QACzC,MAAM,CAAC,QAAQ,EAAE,CAAC,eAAe,KAAK,CAAC;QACvC,MAAM,CAAC,QAAQ,EAAE,CAAC,cAAc,EAAE,UAAU,KAAK,IAAI;QACrD,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,KAAK,6BAA6B;QACzD,MAAM,CAAC,QAAQ,EAAE,CAAC,SAAS,KAAK,YAAY;QAC5C,MAAM,CAAC,MAAM,KAAK,CAAC;QACnB,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,SAAS;QAClC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,6BAA6B;QAClD,aAAa,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QAClC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,aAAa,CAAC;QACzE,YAAY,CAAC,KAAK,GAAG,CAAC;QACtB,gBAAgB,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACjD,gBAAgB,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAChD,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC1C,gBAAgB,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAChD,gBAAgB,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QACpD,iCAAiC,CAAC,MAAM,KAAK,CAAC;QAC9C,iCAAiC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,6BAA6B,CAAC,KAAK,IAAI;QAC5I,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC;QAC/B,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QACnD,kBAAkB,CAAC,kBAAkB,EAAE,CAAC,MAAM,KAAK,CAAC;QACpD,kBAAkB,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,4BAA4B,CAAC,KAAK,IAAI;QACjJ,kBAAkB,CAAC,kBAAkB,EAAE,CAAC,MAAM,KAAK,CAAC;QACpD,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;QAChC,qBAAqB;QACrB,yBAAyB,CAAC,KAAK,CAAC,OAAO,CAAC;QACxC,WAAW,CAAC,QAAQ,EAAE,CAAC,eAAe,KAAK,CAAC;QAC5C,WAAW,CAAC,QAAQ,EAAE,CAAC,cAAc,KAAK,SAAS;QACnD,WAAW,CAAC,QAAQ,EAAE,CAAC,QAAQ,KAAK,IAAI;QACxC,WAAW,CAAC,QAAQ,EAAE,CAAC,mBAAmB,KAAK,MAAM;QACrD,OAAO;QACP,iBAAiB,CAAC,MAAM,KAAK,CAAC,CAAC;IAEjC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;QACzB,EAAE;QACF,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;QAClC,eAAe,EAAE,eAAe,CAAC,MAAM;QACvC,YAAY;QACZ,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;QACzB,MAAM;QACN,UAAU,EAAE;YACV,iCAAiC,EAAE,iCAAiC,CAAC,MAAM;YAC3E,iBAAiB,EAAE,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;YAChE,0BAA0B,EAAE,kBAAkB,CAAC,kBAAkB,EAAE,CAAC,MAAM;YAC1E,0BAA0B,EAAE,kBAAkB,CAAC,kBAAkB,EAAE,CAAC,MAAM;YAC1E,4BAA4B,EAAE,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC9D,qBAAqB;YACrB,yBAAyB;SAC1B;QACD,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE;QAC7B,OAAO;QACP,iBAAiB;KAClB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO;QACL;YACE,EAAE,EAAE,iBAAiB;YACrB,IAAI,EAAE,WAAW;YACjB,SAAS;YACT,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;gBAC5D,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;aAC5D;SACF;QACD;YACE,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,aAAa;YACnB,SAAS;YACT,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;SACzG;QACD;YACE,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,aAAa;YACnB,SAAS;YACT,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;SACxG;KACF,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACrF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export type ExecOutputStream = "stdout" | "stderr";
2
2
  export type ExecProcessStatus = "running" | "exited" | "failed" | "timed_out" | "killed";
3
+ export type ExecTerminationReason = "completed" | "failed" | "user_interrupt" | "user_terminate" | "user_kill" | "timeout" | "external_signal" | "spawn_error";
3
4
  export interface ExecProcessStartOptions {
4
5
  ownerId?: string;
5
6
  command: string;
@@ -9,21 +10,25 @@ export interface ExecProcessStartOptions {
9
10
  requested: string;
10
11
  file: string;
11
12
  args: string[];
13
+ commandPrefix?: string;
12
14
  };
13
15
  env: Record<string, string>;
14
16
  timeoutMs: number;
15
17
  maxOutputChars: number;
16
18
  tty: boolean;
19
+ redactOutput?: (text: string) => string;
17
20
  }
18
21
  export interface ExecProcessOutputDelta {
19
22
  sessionId: string;
20
23
  stream: ExecOutputStream;
21
24
  text: string;
25
+ outputStart?: number;
26
+ outputEnd?: number;
22
27
  }
23
28
  export interface ExecProcessResult {
24
29
  status: ExecProcessStatus;
25
30
  session_id: string;
26
- process_id: number;
31
+ process_id: number | null;
27
32
  command: string;
28
33
  description?: string;
29
34
  cwd: string;
@@ -31,6 +36,7 @@ export interface ExecProcessResult {
31
36
  tty: boolean;
32
37
  exit_code: number | null;
33
38
  signal: string | number | null;
39
+ termination_reason: ExecTerminationReason | null;
34
40
  duration_ms: number;
35
41
  timed_out: boolean;
36
42
  stdout: string;
@@ -56,6 +62,7 @@ export declare class ExecProcessManager {
56
62
  private readonly options;
57
63
  private readonly sessions;
58
64
  private readonly subscribers;
65
+ private readonly outputSubscribers;
59
66
  private nextId;
60
67
  constructor(options?: {
61
68
  maxProcesses?: number;
@@ -64,12 +71,19 @@ export declare class ExecProcessManager {
64
71
  start(options: ExecProcessStartOptions): string;
65
72
  interact(sessionId: string, interaction: ExecProcessInteraction): Promise<ExecProcessResult>;
66
73
  execute(options: ExecProcessStartOptions, yieldTimeMs: number, onOutput?: (delta: ExecProcessOutputDelta) => void, abortSignal?: AbortSignal): Promise<ExecProcessResult>;
67
- list(): Array<Pick<ExecProcessResult, "session_id" | "process_id" | "status" | "command" | "cwd" | "duration_ms" | "tty">>;
74
+ list(): Array<Pick<ExecProcessResult, "session_id" | "process_id" | "status" | "command" | "description" | "cwd" | "shell" | "duration_ms" | "tty" | "termination_reason"> & {
75
+ backgrounded: boolean;
76
+ output: string;
77
+ outputEnd: number;
78
+ }>;
68
79
  activeCount(): number;
80
+ isBackgroundRunning(sessionId: string): boolean;
69
81
  subscribe(listener: () => void): () => void;
82
+ subscribeOutput(listener: (delta: ExecProcessOutputDelta) => void): () => void;
70
83
  terminateAll(): void;
71
84
  private createSession;
72
85
  private signal;
86
+ private finalizeSession;
73
87
  private notifyExit;
74
88
  private waitForExit;
75
89
  private drain;
@@ -2,10 +2,12 @@ import { spawn as spawnChild } from "node:child_process";
2
2
  import { randomBytes } from "node:crypto";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import os from "node:os";
5
+ const LIVE_OUTPUT_MAX_CHARS = 40_000;
5
6
  export class ExecProcessManager {
6
7
  options;
7
8
  sessions = new Map();
8
9
  subscribers = new Set();
10
+ outputSubscribers = new Set();
9
11
  nextId = 1;
10
12
  constructor(options = {}) {
11
13
  this.options = options;
@@ -19,13 +21,12 @@ export class ExecProcessManager {
19
21
  session.timeout = setTimeout(() => {
20
22
  if (session.status !== "running")
21
23
  return;
22
- session.status = "timed_out";
24
+ session.requestedTerminationReason = "timeout";
23
25
  session.backend.terminate(false);
24
- setTimeout(() => {
25
- if (session.status === "timed_out")
26
+ session.escalation = setTimeout(() => {
27
+ if (session.status === "running")
26
28
  session.backend.terminate(true);
27
29
  }, 1_000).unref();
28
- this.notifyExit(session);
29
30
  }, options.timeoutMs);
30
31
  session.timeout.unref();
31
32
  return id;
@@ -65,7 +66,18 @@ export class ExecProcessManager {
65
66
  }
66
67
  async execute(options, yieldTimeMs, onOutput, abortSignal) {
67
68
  const sessionId = this.start(options);
68
- return this.interact(sessionId, { ownerId: options.ownerId, yieldTimeMs, onOutput, abortSignal });
69
+ const result = await this.interact(sessionId, { ownerId: options.ownerId, yieldTimeMs, onOutput, abortSignal });
70
+ if (result.status === "running") {
71
+ const session = this.sessions.get(sessionId);
72
+ if (session && !session.backgrounded) {
73
+ session.backgrounded = true;
74
+ if (session.timeout)
75
+ clearTimeout(session.timeout);
76
+ session.timeout = undefined;
77
+ this.notify();
78
+ }
79
+ }
80
+ return result;
69
81
  }
70
82
  list() {
71
83
  return [...this.sessions.values()].map((session) => ({
@@ -73,46 +85,71 @@ export class ExecProcessManager {
73
85
  process_id: session.backend.pid,
74
86
  status: session.status,
75
87
  command: session.options.command,
88
+ description: session.options.description,
76
89
  cwd: session.options.cwd,
77
- duration_ms: Date.now() - session.startedAt,
90
+ shell: session.options.shell.requested,
91
+ duration_ms: (session.finishedAt ?? Date.now()) - session.startedAt,
78
92
  tty: session.options.tty,
93
+ termination_reason: session.terminationReason,
94
+ backgrounded: session.backgrounded,
95
+ output: session.liveOutput.snapshot().text,
96
+ outputEnd: session.liveOutput.observedChars(),
79
97
  }));
80
98
  }
81
99
  activeCount() {
82
- return [...this.sessions.values()].filter((session) => session.status === "running").length;
100
+ return [...this.sessions.values()].filter((session) => session.status === "running" && session.backgrounded).length;
101
+ }
102
+ isBackgroundRunning(sessionId) {
103
+ const session = this.sessions.get(sessionId);
104
+ return Boolean(session?.backgrounded && session.status === "running");
83
105
  }
84
106
  subscribe(listener) {
85
107
  this.subscribers.add(listener);
86
108
  return () => this.subscribers.delete(listener);
87
109
  }
110
+ subscribeOutput(listener) {
111
+ this.outputSubscribers.add(listener);
112
+ return () => this.outputSubscribers.delete(listener);
113
+ }
88
114
  terminateAll() {
89
115
  for (const session of this.sessions.values()) {
90
116
  if (session.status === "running") {
91
- session.status = "killed";
117
+ session.requestedTerminationReason = "user_kill";
92
118
  session.backend.terminate(true);
93
- this.notifyExit(session);
94
119
  }
95
120
  }
96
121
  }
97
122
  createSession(id, options) {
98
123
  let session;
124
+ let redactOutput = options.redactOutput;
125
+ let liveOutputOffset = 0;
99
126
  const onOutput = (stream, text) => {
100
127
  const normalized = normalizeOutput(text);
101
128
  if (!normalized)
102
129
  return;
103
130
  session[stream].push(normalized);
131
+ const safeOutput = redactOutput?.(normalized) ?? normalized;
132
+ const liveText = stream === "stderr" ? `[stderr] ${safeOutput}` : safeOutput;
133
+ session.liveOutput.push(liveText);
104
134
  const delta = { sessionId: id, stream, text: normalized };
105
135
  for (const subscriber of session.subscribers)
106
136
  subscriber(delta);
137
+ const outputStart = liveOutputOffset;
138
+ liveOutputOffset += liveText.length;
139
+ if (session.backgrounded) {
140
+ const publicDelta = { sessionId: id, stream, text: liveText, outputStart, outputEnd: liveOutputOffset };
141
+ for (const subscriber of this.outputSubscribers)
142
+ subscriber(publicDelta);
143
+ }
107
144
  };
108
145
  const onExit = (exitCode, signal, error) => {
109
- if (session.status === "running")
110
- session.status = error ? "failed" : "exited";
111
- session.exitCode = exitCode;
112
- session.signal = signal;
146
+ if (session.finishedAt !== undefined)
147
+ return;
113
148
  if (error)
114
149
  onOutput("stderr", `${error.message}\n`);
115
- this.notifyExit(session);
150
+ redactOutput = undefined;
151
+ session.options.redactOutput = undefined;
152
+ this.finalizeSession(session, exitCode, signal, error);
116
153
  session.backend.dispose();
117
154
  };
118
155
  const backend = options.tty
@@ -123,11 +160,14 @@ export class ExecProcessManager {
123
160
  options,
124
161
  backend,
125
162
  startedAt: Date.now(),
163
+ backgrounded: false,
126
164
  status: "running",
127
165
  exitCode: null,
128
166
  signal: null,
167
+ terminationReason: null,
129
168
  stdout: new TextWindow(options.maxOutputChars),
130
169
  stderr: new TextWindow(options.maxOutputChars),
170
+ liveOutput: new TextWindow(Math.min(options.maxOutputChars, LIVE_OUTPUT_MAX_CHARS)),
131
171
  waiters: new Set(),
132
172
  subscribers: new Set(),
133
173
  interactionTail: Promise.resolve(),
@@ -138,16 +178,55 @@ export class ExecProcessManager {
138
178
  if (session.status !== "running")
139
179
  return;
140
180
  if (signal === "interrupt") {
181
+ session.requestedTerminationReason = "user_interrupt";
141
182
  session.backend.interrupt();
142
183
  return;
143
184
  }
144
- session.status = "killed";
185
+ session.requestedTerminationReason = signal === "kill" ? "user_kill" : "user_terminate";
145
186
  session.backend.terminate(signal === "kill");
187
+ }
188
+ finalizeSession(session, exitCode, signal, error) {
189
+ if (session.finishedAt !== undefined)
190
+ return;
191
+ session.finishedAt = Date.now();
192
+ const requested = session.requestedTerminationReason;
193
+ if (requested === "timeout") {
194
+ session.status = "timed_out";
195
+ session.exitCode = null;
196
+ session.signal = null;
197
+ session.terminationReason = "timeout";
198
+ }
199
+ else if (requested) {
200
+ session.status = "killed";
201
+ session.exitCode = null;
202
+ session.signal = signal;
203
+ session.terminationReason = requested;
204
+ }
205
+ else if (error) {
206
+ session.status = "failed";
207
+ session.exitCode = null;
208
+ session.signal = signal;
209
+ session.terminationReason = "spawn_error";
210
+ }
211
+ else if (signal !== null) {
212
+ session.status = "killed";
213
+ session.exitCode = exitCode;
214
+ session.signal = signal;
215
+ session.terminationReason = "external_signal";
216
+ }
217
+ else {
218
+ session.status = "exited";
219
+ session.exitCode = exitCode;
220
+ session.signal = null;
221
+ session.terminationReason = exitCode === 0 ? "completed" : "failed";
222
+ }
146
223
  this.notifyExit(session);
147
224
  }
148
225
  notifyExit(session) {
149
226
  if (session.timeout)
150
227
  clearTimeout(session.timeout);
228
+ if (session.escalation)
229
+ clearTimeout(session.escalation);
151
230
  for (const waiter of [...session.waiters])
152
231
  waiter();
153
232
  session.waiters.clear();
@@ -193,7 +272,8 @@ export class ExecProcessManager {
193
272
  tty: session.options.tty,
194
273
  exit_code: session.exitCode,
195
274
  signal: session.signal,
196
- duration_ms: Date.now() - session.startedAt,
275
+ termination_reason: session.terminationReason,
276
+ duration_ms: (session.finishedAt ?? Date.now()) - session.startedAt,
197
277
  timed_out: session.status === "timed_out",
198
278
  stdout: stdout.text,
199
279
  stderr: stderr.text,
@@ -243,10 +323,16 @@ class TextWindow {
243
323
  this.head = combined.slice(0, headSize);
244
324
  this.tail = combined.slice(-tailSize);
245
325
  }
246
- drain() {
326
+ observedChars() {
327
+ return this.observed;
328
+ }
329
+ snapshot() {
247
330
  const omitted = Math.max(0, this.observed - this.head.length - this.tail.length);
248
331
  const marker = omitted > 0 ? `\n[... ${omitted} characters omitted ...]\n` : "";
249
- const result = { text: this.head + marker + this.tail, observed: this.observed, omitted };
332
+ return { text: this.head + marker + this.tail, observed: this.observed, omitted };
333
+ }
334
+ drain() {
335
+ const result = this.snapshot();
250
336
  this.head = "";
251
337
  this.tail = "";
252
338
  this.observed = 0;
@@ -259,7 +345,8 @@ function createPtyBackend(options, onOutput, onExit) {
259
345
  stdio: ["ignore", "ignore", "pipe", "ipc"],
260
346
  windowsHide: true,
261
347
  });
262
- let terminalPid = host.pid ?? -1;
348
+ let terminalPid = host.pid && host.pid > 0 ? host.pid : null;
349
+ let ready = false;
263
350
  let disposed = false;
264
351
  let completed = false;
265
352
  let diagnostic = "";
@@ -273,7 +360,9 @@ function createPtyBackend(options, onOutput, onExit) {
273
360
  return;
274
361
  const record = message;
275
362
  if (record.type === "ready" && typeof record.pid === "number") {
276
- terminalPid = record.pid;
363
+ ready = true;
364
+ if (record.pid > 0)
365
+ terminalPid = record.pid;
277
366
  for (const chars of pendingWrites.splice(0))
278
367
  host.send?.({ type: "write", chars });
279
368
  }
@@ -302,7 +391,7 @@ function createPtyBackend(options, onOutput, onExit) {
302
391
  host.send({
303
392
  type: "start",
304
393
  file: options.shell.file,
305
- args: [...options.shell.args, options.command],
394
+ args: [...options.shell.args, shellCommand(options)],
306
395
  cwd: options.cwd,
307
396
  env: { ...process.env, ...options.env },
308
397
  cols: 120,
@@ -319,7 +408,7 @@ function createPtyBackend(options, onOutput, onExit) {
319
408
  get pid() { return terminalPid; },
320
409
  write: (data) => {
321
410
  const chars = normalizePtyInput(data);
322
- if (terminalPid === (host.pid ?? -1))
411
+ if (!ready)
323
412
  pendingWrites.push(chars);
324
413
  else
325
414
  host.send?.({ type: "write", chars });
@@ -330,7 +419,7 @@ function createPtyBackend(options, onOutput, onExit) {
330
419
  };
331
420
  }
332
421
  function createPipeBackend(options, onOutput, onExit) {
333
- const child = spawnChild(options.shell.file, [...options.shell.args, options.command], {
422
+ const child = spawnChild(options.shell.file, [...options.shell.args, shellCommand(options)], {
334
423
  cwd: options.cwd,
335
424
  env: { ...process.env, ...options.env },
336
425
  windowsHide: true,
@@ -344,7 +433,7 @@ function createPipeBackend(options, onOutput, onExit) {
344
433
  child.once("error", (error) => onExit(null, null, error));
345
434
  child.once("close", (exitCode, signal) => onExit(exitCode, signal));
346
435
  return {
347
- pid: child.pid ?? -1,
436
+ pid: child.pid && child.pid > 0 ? child.pid : null,
348
437
  write: (data) => child.stdin.write(data),
349
438
  interrupt: () => interruptPipe(child),
350
439
  terminate: (force) => terminatePipe(child, force),
@@ -356,6 +445,9 @@ function createPipeBackend(options, onOutput, onExit) {
356
445
  },
357
446
  };
358
447
  }
448
+ function shellCommand(options) {
449
+ return options.shell.commandPrefix ? `${options.shell.commandPrefix}${options.command}` : options.command;
450
+ }
359
451
  function normalizeOutput(text) {
360
452
  return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
361
453
  }
@@ -379,7 +471,9 @@ function terminatePipe(child, force) {
379
471
  if (!child.pid)
380
472
  return;
381
473
  if (os.platform() === "win32") {
382
- const args = ["/pid", String(child.pid), "/t", ...(force ? ["/f"] : [])];
474
+ // Windows console processes do not reliably react to taskkill without /F.
475
+ // The cross-platform intent remains available through termination_reason.
476
+ const args = ["/pid", String(child.pid), "/t", "/f"];
383
477
  const killer = spawnChild("taskkill.exe", args, { windowsHide: true, stdio: "ignore" });
384
478
  killer.unref();
385
479
  return;