@agimon-ai/po-task 0.0.0-alpha.0

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 (161) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/apiContracts.cjs +54 -0
  4. package/dist/apiContracts.cjs.map +1 -0
  5. package/dist/apiContracts.d.mts +53 -0
  6. package/dist/apiContracts.d.mts.map +1 -0
  7. package/dist/apiContracts.mjs +49 -0
  8. package/dist/apiContracts.mjs.map +1 -0
  9. package/dist/config-CFSs3iku.mjs +72 -0
  10. package/dist/config-CFSs3iku.mjs.map +1 -0
  11. package/dist/config-CdX-Bv8q.cjs +173 -0
  12. package/dist/config-CdX-Bv8q.cjs.map +1 -0
  13. package/dist/config.cjs +19 -0
  14. package/dist/config.d.mts +2 -0
  15. package/dist/config.mjs +2 -0
  16. package/dist/delegation-BiOy3_7g.mjs +7 -0
  17. package/dist/delegation-BiOy3_7g.mjs.map +1 -0
  18. package/dist/delegation-CdMqOZB4.mjs +626 -0
  19. package/dist/delegation-CdMqOZB4.mjs.map +1 -0
  20. package/dist/delegation-DsnKjMbJ.cjs +661 -0
  21. package/dist/delegation-DsnKjMbJ.cjs.map +1 -0
  22. package/dist/delegation-LDpHP2CC.cjs +12 -0
  23. package/dist/delegation-LDpHP2CC.cjs.map +1 -0
  24. package/dist/delegationManager.cjs +10 -0
  25. package/dist/delegationManager.d.mts +2 -0
  26. package/dist/delegationManager.mjs +3 -0
  27. package/dist/extensions/mcp-ui.mjs +23 -0
  28. package/dist/extensions/mcp-ui.mjs.map +1 -0
  29. package/dist/extensions/mcp.cjs +1144 -0
  30. package/dist/extensions/mcp.cjs.map +1 -0
  31. package/dist/extensions/mcp.d.mts +5 -0
  32. package/dist/extensions/mcp.d.mts.map +1 -0
  33. package/dist/extensions/mcp.mjs +1115 -0
  34. package/dist/extensions/mcp.mjs.map +1 -0
  35. package/dist/extensions/native.mjs +1175 -0
  36. package/dist/extensions/native.mjs.map +1 -0
  37. package/dist/extensions/server.cjs +569 -0
  38. package/dist/extensions/server.cjs.map +1 -0
  39. package/dist/extensions/server.d.mts +5 -0
  40. package/dist/extensions/server.d.mts.map +1 -0
  41. package/dist/extensions/server.mjs +563 -0
  42. package/dist/extensions/server.mjs.map +1 -0
  43. package/dist/extensions/web.mjs +1018 -0
  44. package/dist/extensions/web.mjs.map +1 -0
  45. package/dist/index-B-3sCF2S.d.mts +43 -0
  46. package/dist/index-B-3sCF2S.d.mts.map +1 -0
  47. package/dist/index-B1JPJdpZ.d.mts +51 -0
  48. package/dist/index-B1JPJdpZ.d.mts.map +1 -0
  49. package/dist/index-CUWCvh-E.d.mts +72 -0
  50. package/dist/index-CUWCvh-E.d.mts.map +1 -0
  51. package/dist/index-DlmXKyhQ.d.mts +34 -0
  52. package/dist/index-DlmXKyhQ.d.mts.map +1 -0
  53. package/dist/index-Dvb8X_qB.d.mts +67 -0
  54. package/dist/index-Dvb8X_qB.d.mts.map +1 -0
  55. package/dist/index-XY9VPmfm.d.mts +26 -0
  56. package/dist/index-XY9VPmfm.d.mts.map +1 -0
  57. package/dist/index-teIf67qQ.d.mts +196 -0
  58. package/dist/index-teIf67qQ.d.mts.map +1 -0
  59. package/dist/index.cjs +93 -0
  60. package/dist/index.d.mts +11 -0
  61. package/dist/index.mjs +12 -0
  62. package/dist/invariants-DhjEjBPU.cjs +79 -0
  63. package/dist/invariants-DhjEjBPU.cjs.map +1 -0
  64. package/dist/invariants-q_UamF7D.mjs +62 -0
  65. package/dist/invariants-q_UamF7D.mjs.map +1 -0
  66. package/dist/logSinkTelemetry-B23qGiP-.cjs +52 -0
  67. package/dist/logSinkTelemetry-B23qGiP-.cjs.map +1 -0
  68. package/dist/logSinkTelemetry-BMBsC54p.mjs +41 -0
  69. package/dist/logSinkTelemetry-BMBsC54p.mjs.map +1 -0
  70. package/dist/logSinkTelemetry.cjs +6 -0
  71. package/dist/logSinkTelemetry.d.mts +23 -0
  72. package/dist/logSinkTelemetry.d.mts.map +1 -0
  73. package/dist/logSinkTelemetry.mjs +3 -0
  74. package/dist/paths-CSya2l9_.cjs +308 -0
  75. package/dist/paths-CSya2l9_.cjs.map +1 -0
  76. package/dist/paths-Cah1vFGv.mjs +207 -0
  77. package/dist/paths-Cah1vFGv.mjs.map +1 -0
  78. package/dist/processLiveness-Ccd9wenT.mjs +20 -0
  79. package/dist/processLiveness-Ccd9wenT.mjs.map +1 -0
  80. package/dist/processLiveness-umpNgsPR.cjs +25 -0
  81. package/dist/processLiveness-umpNgsPR.cjs.map +1 -0
  82. package/dist/reconcile-BcD-hTbd.mjs +63 -0
  83. package/dist/reconcile-BcD-hTbd.mjs.map +1 -0
  84. package/dist/reconcile-cRL0NjDr.cjs +80 -0
  85. package/dist/reconcile-cRL0NjDr.cjs.map +1 -0
  86. package/dist/reducer-BEfJFM5L.mjs +345 -0
  87. package/dist/reducer-BEfJFM5L.mjs.map +1 -0
  88. package/dist/reducer-BV0YIZ2o.cjs +380 -0
  89. package/dist/reducer-BV0YIZ2o.cjs.map +1 -0
  90. package/dist/storeInvariants.cjs +5 -0
  91. package/dist/storeInvariants.d.mts +23 -0
  92. package/dist/storeInvariants.d.mts.map +1 -0
  93. package/dist/storeInvariants.mjs +2 -0
  94. package/dist/storePaths.cjs +14 -0
  95. package/dist/storePaths.d.mts +2 -0
  96. package/dist/storePaths.mjs +2 -0
  97. package/dist/storeProcessLiveness.cjs +3 -0
  98. package/dist/storeProcessLiveness.d.mts +11 -0
  99. package/dist/storeProcessLiveness.d.mts.map +1 -0
  100. package/dist/storeProcessLiveness.mjs +2 -0
  101. package/dist/storeReconcile.cjs +5 -0
  102. package/dist/storeReconcile.d.mts +2 -0
  103. package/dist/storeReconcile.mjs +2 -0
  104. package/dist/storeReducer.cjs +8 -0
  105. package/dist/storeReducer.d.mts +2 -0
  106. package/dist/storeReducer.mjs +2 -0
  107. package/dist/storeTaskGraph.cjs +7 -0
  108. package/dist/storeTaskGraph.d.mts +2 -0
  109. package/dist/storeTaskGraph.mjs +2 -0
  110. package/dist/storeTaskStore.cjs +3 -0
  111. package/dist/storeTaskStore.d.mts +2 -0
  112. package/dist/storeTaskStore.mjs +2 -0
  113. package/dist/storeTypes.cjs +6 -0
  114. package/dist/storeTypes.d.mts +2 -0
  115. package/dist/storeTypes.mjs +2 -0
  116. package/dist/task-CXF9VULl.cjs +49 -0
  117. package/dist/task-CXF9VULl.cjs.map +1 -0
  118. package/dist/task-DJpTteeJ.d.mts +187 -0
  119. package/dist/task-DJpTteeJ.d.mts.map +1 -0
  120. package/dist/task-DO0TwZ0z.mjs +132 -0
  121. package/dist/task-DO0TwZ0z.mjs.map +1 -0
  122. package/dist/task-Dhta7JyA.d.mts +126 -0
  123. package/dist/task-Dhta7JyA.d.mts.map +1 -0
  124. package/dist/task-UvW877Ez.cjs +227 -0
  125. package/dist/task-UvW877Ez.cjs.map +1 -0
  126. package/dist/task-giCbpKzV.mjs +26 -0
  127. package/dist/task-giCbpKzV.mjs.map +1 -0
  128. package/dist/taskGraph-BOQvT0-M.mjs +63 -0
  129. package/dist/taskGraph-BOQvT0-M.mjs.map +1 -0
  130. package/dist/taskGraph-BskRslrr.cjs +92 -0
  131. package/dist/taskGraph-BskRslrr.cjs.map +1 -0
  132. package/dist/taskGraph-D0zFHF2p.d.mts +25 -0
  133. package/dist/taskGraph-D0zFHF2p.d.mts.map +1 -0
  134. package/dist/taskResult-D2G7b4w-.cjs +224 -0
  135. package/dist/taskResult-D2G7b4w-.cjs.map +1 -0
  136. package/dist/taskResult-edBAAKSH.mjs +165 -0
  137. package/dist/taskResult-edBAAKSH.mjs.map +1 -0
  138. package/dist/taskStore-DjU60rMm.cjs +215 -0
  139. package/dist/taskStore-DjU60rMm.cjs.map +1 -0
  140. package/dist/taskStore-pAJ971Ml.mjs +208 -0
  141. package/dist/taskStore-pAJ971Ml.mjs.map +1 -0
  142. package/dist/telemetry-Ca0I3Tqo.cjs +30 -0
  143. package/dist/telemetry-Ca0I3Tqo.cjs.map +1 -0
  144. package/dist/telemetry-DyS44zAD.mjs +25 -0
  145. package/dist/telemetry-DyS44zAD.mjs.map +1 -0
  146. package/dist/telemetry-FMGRovb4.d.mts +35 -0
  147. package/dist/telemetry-FMGRovb4.d.mts.map +1 -0
  148. package/dist/toolPromptGuidelines.cjs +27 -0
  149. package/dist/toolPromptGuidelines.cjs.map +1 -0
  150. package/dist/toolPromptGuidelines.d.mts +13 -0
  151. package/dist/toolPromptGuidelines.d.mts.map +1 -0
  152. package/dist/toolPromptGuidelines.mjs +26 -0
  153. package/dist/toolPromptGuidelines.mjs.map +1 -0
  154. package/dist/toolResponseEnvelope.cjs +12 -0
  155. package/dist/toolResponseEnvelope.d.mts +2 -0
  156. package/dist/toolResponseEnvelope.mjs +2 -0
  157. package/dist/toolSchema.cjs +18 -0
  158. package/dist/toolSchema.d.mts +2 -0
  159. package/dist/toolSchema.mjs +2 -0
  160. package/package.json +223 -0
  161. package/src/types/webTasks.ts +24 -0
@@ -0,0 +1,1175 @@
1
+ import { defineActivityGroup, defineChannelFile, defineFill, defineNativePlugin, defineSessionStore, defineToolRenderer } from "@agimon-ai/po-core/native";
2
+ import { Badge, Button, ChevronDownIcon, ChevronRightIcon, CodeBlock, Dot, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, EditIcon, Input, KebabIcon, Label, ListRow, MessageIcon, MessageItem, MessageItemBody, MessageItemHeader, MessageItemStatus, SegmentedControl, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, StatusBadge, TaskIcon, Textarea, TrashIcon, toolTone } from "@agimon-ai/po-native-components";
3
+ import { createElement, useCallback, useState, useSyncExternalStore } from "react";
4
+ import { View } from "react-native-unistyles/components/native/View";
5
+ import { Text } from "react-native-unistyles/components/native/Text";
6
+ import { StyleSheet } from "react-native-unistyles";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/types/webTasks.ts
9
+ /** Browser-safe task view published by the cockpit hub channel. */
10
+ const TASKS_CHANNEL_TYPE = "task_graph";
11
+ //#endregion
12
+ //#region src/extensions/workspaces/sessions/(frontend)/channel/_lib/tasksModel.ts
13
+ function isRecord$1(value) {
14
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15
+ }
16
+ function parseTask(value) {
17
+ if (!isRecord$1(value) || typeof value.id !== "number" || typeof value.subject !== "string") return null;
18
+ if (![
19
+ "pending",
20
+ "in_progress",
21
+ "completed",
22
+ "failed"
23
+ ].includes(String(value.status))) return null;
24
+ const task = {
25
+ id: value.id,
26
+ subject: value.subject,
27
+ status: value.status,
28
+ blockedBy: Array.isArray(value.blockedBy) ? value.blockedBy.filter((id) => typeof id === "number") : []
29
+ };
30
+ if (typeof value.description === "string") task.description = value.description;
31
+ if (typeof value.activeForm === "string") task.activeForm = value.activeForm;
32
+ if (typeof value.owner === "string") task.owner = value.owner;
33
+ if (typeof value.updatedAt === "string") task.updatedAt = value.updatedAt;
34
+ if (isRecord$1(value.delegation)) {
35
+ task.delegation = {};
36
+ if (typeof value.delegation.agent === "string") task.delegation.agent = value.delegation.agent;
37
+ if (typeof value.delegation.state === "string") task.delegation.state = value.delegation.state;
38
+ }
39
+ return task;
40
+ }
41
+ /** Narrows a hub frame to a task graph payload; null when it is not one. */
42
+ function parseTasksPayload(input) {
43
+ if (!isRecord$1(input) || !Array.isArray(input.tasks) || typeof input.rev !== "number") return null;
44
+ return {
45
+ tasks: input.tasks.map(parseTask).filter((task) => task !== null),
46
+ rev: input.rev
47
+ };
48
+ }
49
+ function taskEditDraft(task) {
50
+ return {
51
+ subject: task.subject,
52
+ description: task.description ?? "",
53
+ status: task.status
54
+ };
55
+ }
56
+ function changedFields(task, draft) {
57
+ const changes = [];
58
+ const subject = draft.subject.trim();
59
+ const description = draft.description.trim();
60
+ if (subject && subject !== task.subject) changes.push(`set subject to "${subject}"`);
61
+ if (description !== (task.description ?? "").trim()) changes.push(description ? `set description to "${description}"` : "clear the description");
62
+ if (draft.status !== task.status) changes.push(`set status to ${draft.status}`);
63
+ return changes;
64
+ }
65
+ /**
66
+ * The agent stays the only writer of task state, so an edit leaves the cockpit
67
+ * as one prompt naming exactly the fields the human changed. Nothing changed
68
+ * means nothing to send.
69
+ */
70
+ function taskEditInstruction(task, draft) {
71
+ const changes = changedFields(task, draft);
72
+ if (changes.length === 0) return null;
73
+ return `Update task #${task.id}: ${changes.join("; ")}. Change nothing else and keep the dependency graph valid.`;
74
+ }
75
+ function requestTaskEdit(send, sessionId, task, draft) {
76
+ const message = taskEditInstruction(task, draft);
77
+ if (message === null) return false;
78
+ send(sessionId, {
79
+ type: "prompt",
80
+ message
81
+ });
82
+ return true;
83
+ }
84
+ /** Steering for the subagent that owns a delegated task. */
85
+ function taskMessageInstruction(taskId, agent, message) {
86
+ return `Steer the ${agent} run working on task #${taskId} with this message, then update the task if its plan changed: ${message.trim()}`;
87
+ }
88
+ function requestTaskMessage(send, sessionId, taskId, agent, message) {
89
+ send(sessionId, {
90
+ type: "prompt",
91
+ message: taskMessageInstruction(taskId, agent, message)
92
+ });
93
+ }
94
+ function requestTaskRemoval(send, sessionId, taskId) {
95
+ send(sessionId, {
96
+ type: "prompt",
97
+ message: `Remove task #${taskId}. Also remove or repair every dependency that references it so the remaining task graph is valid.`
98
+ });
99
+ }
100
+ //#endregion
101
+ //#region src/extensions/workspaces/sessions/(frontend)/channel/_lib/tasksStore.native.ts
102
+ /**
103
+ * The native copy of the task graph store. It mirrors tasksStore.ts with the
104
+ * native SDK, since the app provides `@agimon-ai/po-core/native` and never the
105
+ * web contract; the parsing and the edit prompts come from the same model.
106
+ */
107
+ const tasks = defineSessionStore({
108
+ tasks: [],
109
+ rev: 0
110
+ });
111
+ const tasksChannel = tasks.channel({
112
+ channel: TASKS_CHANNEL_TYPE,
113
+ parse: parseTasksPayload,
114
+ reduce: (_current, payload) => payload
115
+ });
116
+ //#endregion
117
+ //#region src/extensions/workspaces/sessions/(frontend)/activity-group/tasks.native.ts
118
+ /**
119
+ * The live task board in the app's Activity list, matching tasks.web.ts.
120
+ *
121
+ * Active means a delegated run is still out, not that the list has entries: a
122
+ * pending task waits for this agent's next turn and reports to nobody.
123
+ */
124
+ var tasks_native_default = defineActivityGroup({
125
+ keys: "t l",
126
+ icon: (_props) => createElement(TaskIcon),
127
+ statusKey: "@agimon-ai/po-task",
128
+ marksBackgroundWork: false,
129
+ activeSource: {
130
+ subscribe(listener) {
131
+ const subscription = tasks.store.subscribe(listener);
132
+ return () => subscription.unsubscribe();
133
+ },
134
+ isActive(sessionId) {
135
+ return tasks.select(tasks.store.state, sessionId).tasks.some((task) => task.delegation?.state === "requested" || task.delegation?.state === "running");
136
+ }
137
+ },
138
+ order: 65
139
+ });
140
+ //#endregion
141
+ //#region src/extensions/workspaces/sessions/(frontend)/channel/task-graph.native.ts
142
+ var task_graph_native_default = defineChannelFile(tasksChannel);
143
+ //#endregion
144
+ //#region src/extensions/workspaces/sessions/(frontend)/fill/_lib/TaskDetailSheet.native.tsx
145
+ const STATUS_CHOICES = [
146
+ "pending",
147
+ "in_progress",
148
+ "completed",
149
+ "failed"
150
+ ];
151
+ const DESCRIPTION_LINES = 5;
152
+ const MESSAGE_LINES = 4;
153
+ function Field({ label, children }) {
154
+ return /* @__PURE__ */ jsxs(View, {
155
+ style: styles$2.field,
156
+ children: [/* @__PURE__ */ jsx(Label, { children: label }), children]
157
+ });
158
+ }
159
+ function ReadOnlyValue({ value, testID }) {
160
+ return /* @__PURE__ */ jsx(Text, {
161
+ testID,
162
+ style: styles$2.value,
163
+ children: value
164
+ });
165
+ }
166
+ function SheetAction({ label, variant, testID, onPress }) {
167
+ return /* @__PURE__ */ jsx(Button, {
168
+ testID,
169
+ variant,
170
+ onPress,
171
+ children: label
172
+ });
173
+ }
174
+ function TaskFacts({ task }) {
175
+ return /* @__PURE__ */ jsxs(View, {
176
+ style: styles$2.facts,
177
+ children: [
178
+ /* @__PURE__ */ jsx(Field, {
179
+ label: "Status",
180
+ children: /* @__PURE__ */ jsx(ReadOnlyValue, {
181
+ testID: "task-detail-status",
182
+ value: task.status.replace("_", " ")
183
+ })
184
+ }),
185
+ task.activeForm ? /* @__PURE__ */ jsx(Field, {
186
+ label: "Active form",
187
+ children: /* @__PURE__ */ jsx(ReadOnlyValue, {
188
+ testID: "task-detail-active-form",
189
+ value: task.activeForm
190
+ })
191
+ }) : null,
192
+ task.owner ? /* @__PURE__ */ jsx(Field, {
193
+ label: "Owner",
194
+ children: /* @__PURE__ */ jsx(ReadOnlyValue, {
195
+ testID: "task-detail-owner",
196
+ value: task.owner
197
+ })
198
+ }) : null,
199
+ task.delegation?.agent ? /* @__PURE__ */ jsx(Field, {
200
+ label: "Delegated to",
201
+ children: /* @__PURE__ */ jsx(ReadOnlyValue, {
202
+ testID: "task-detail-agent",
203
+ value: task.delegation.state ? `${task.delegation.agent} · ${task.delegation.state}` : task.delegation.agent
204
+ })
205
+ }) : null,
206
+ task.blockedBy.length > 0 ? /* @__PURE__ */ jsx(Field, {
207
+ label: "Blocked by",
208
+ children: /* @__PURE__ */ jsx(ReadOnlyValue, {
209
+ testID: "task-detail-blocked-by",
210
+ value: task.blockedBy.map((id) => `#${id}`).join(", ")
211
+ })
212
+ }) : null,
213
+ task.updatedAt ? /* @__PURE__ */ jsx(Field, {
214
+ label: "Updated",
215
+ children: /* @__PURE__ */ jsx(ReadOnlyValue, {
216
+ testID: "task-detail-updated",
217
+ value: task.updatedAt
218
+ })
219
+ }) : null
220
+ ]
221
+ });
222
+ }
223
+ /**
224
+ * One task in a bottom sheet, read first and changed second, as the web
225
+ * dialog does. Every change leaves as a prompt the session can see, so the
226
+ * agent remains the only writer of task state.
227
+ */
228
+ function TaskDetailSheet({ task, sessionId, mode: initialMode, send, onClose }) {
229
+ const [mode, setMode] = useState(initialMode);
230
+ const [draft, setDraft] = useState(() => taskEditDraft(task));
231
+ const [message, setMessage] = useState("");
232
+ const agent = task.delegation?.agent;
233
+ const submitEdit = () => {
234
+ if (requestTaskEdit(send, sessionId, task, draft)) onClose();
235
+ };
236
+ const submitMessage = () => {
237
+ if (!message.trim() || !agent) return;
238
+ requestTaskMessage(send, sessionId, task.id, agent, message);
239
+ onClose();
240
+ };
241
+ return /* @__PURE__ */ jsx(Sheet, {
242
+ open: true,
243
+ onOpenChange: (open) => {
244
+ if (!open) onClose();
245
+ },
246
+ children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, {
247
+ closeLabel: "close task",
248
+ children: /* @__PURE__ */ jsx(SheetTitle, {
249
+ testID: "task-detail-title",
250
+ accessibilityLabel: `task #${task.id}: ${task.subject}`,
251
+ children: task.subject
252
+ })
253
+ }), /* @__PURE__ */ jsxs(SheetBody, {
254
+ testID: "task-detail-dialog",
255
+ children: [
256
+ mode === "view" ? /* @__PURE__ */ jsxs(Fragment, { children: [
257
+ /* @__PURE__ */ jsx(Field, {
258
+ label: "Description",
259
+ children: /* @__PURE__ */ jsx(ReadOnlyValue, {
260
+ testID: "task-detail-description",
261
+ value: task.description ?? "no description on this task"
262
+ })
263
+ }),
264
+ /* @__PURE__ */ jsx(TaskFacts, { task }),
265
+ /* @__PURE__ */ jsxs(View, {
266
+ style: styles$2.footer,
267
+ children: [agent ? /* @__PURE__ */ jsx(SheetAction, {
268
+ label: "message agent",
269
+ variant: "ghost",
270
+ testID: "task-detail-open-message",
271
+ onPress: () => setMode("message")
272
+ }) : null, /* @__PURE__ */ jsx(SheetAction, {
273
+ label: "edit",
274
+ variant: "primary",
275
+ testID: "task-detail-open-edit",
276
+ onPress: () => setMode("edit")
277
+ })]
278
+ })
279
+ ] }) : null,
280
+ mode === "edit" ? /* @__PURE__ */ jsxs(Fragment, { children: [
281
+ /* @__PURE__ */ jsx(Field, {
282
+ label: "Subject",
283
+ children: /* @__PURE__ */ jsx(Input, {
284
+ testID: "task-detail-subject-input",
285
+ accessibilityLabel: "Subject",
286
+ autoFocus: true,
287
+ value: draft.subject,
288
+ onChangeText: (subject) => setDraft({
289
+ ...draft,
290
+ subject
291
+ })
292
+ })
293
+ }),
294
+ /* @__PURE__ */ jsx(Field, {
295
+ label: "Description",
296
+ children: /* @__PURE__ */ jsx(Textarea, {
297
+ testID: "task-detail-description-input",
298
+ accessibilityLabel: "Description",
299
+ numberOfLines: DESCRIPTION_LINES,
300
+ value: draft.description,
301
+ placeholder: "what this task covers",
302
+ onChangeText: (description) => setDraft({
303
+ ...draft,
304
+ description
305
+ })
306
+ })
307
+ }),
308
+ /* @__PURE__ */ jsx(Field, {
309
+ label: "Status",
310
+ children: /* @__PURE__ */ jsx(SegmentedControl, {
311
+ accessibilityLabel: "Status",
312
+ options: STATUS_CHOICES.map((status) => ({
313
+ value: status,
314
+ label: status.replace("_", " ")
315
+ })),
316
+ value: draft.status,
317
+ onValueChange: (status) => {
318
+ if (STATUS_CHOICES.includes(status)) setDraft({
319
+ ...draft,
320
+ status
321
+ });
322
+ }
323
+ })
324
+ }),
325
+ /* @__PURE__ */ jsx(Text, {
326
+ style: styles$2.hint,
327
+ children: "saved as one prompt naming only the fields you changed"
328
+ }),
329
+ /* @__PURE__ */ jsxs(View, {
330
+ style: styles$2.footer,
331
+ children: [/* @__PURE__ */ jsx(SheetAction, {
332
+ label: "cancel",
333
+ variant: "ghost",
334
+ testID: "task-detail-cancel",
335
+ onPress: onClose
336
+ }), /* @__PURE__ */ jsx(SheetAction, {
337
+ label: "save",
338
+ variant: "primary",
339
+ testID: "task-detail-save",
340
+ onPress: submitEdit
341
+ })]
342
+ })
343
+ ] }) : null,
344
+ mode === "message" && agent ? /* @__PURE__ */ jsxs(Fragment, { children: [
345
+ /* @__PURE__ */ jsx(Field, {
346
+ label: `Message to ${agent}`,
347
+ children: /* @__PURE__ */ jsx(Textarea, {
348
+ testID: "task-detail-message-input",
349
+ accessibilityLabel: "Message to agent",
350
+ autoFocus: true,
351
+ numberOfLines: MESSAGE_LINES,
352
+ value: message,
353
+ placeholder: "guidance for the run working on this task",
354
+ onChangeText: setMessage
355
+ })
356
+ }),
357
+ /* @__PURE__ */ jsx(Text, {
358
+ style: styles$2.hint,
359
+ children: "steers the run, it does not edit the task"
360
+ }),
361
+ /* @__PURE__ */ jsxs(View, {
362
+ style: styles$2.footer,
363
+ children: [/* @__PURE__ */ jsx(SheetAction, {
364
+ label: "cancel",
365
+ variant: "ghost",
366
+ testID: "task-detail-cancel",
367
+ onPress: onClose
368
+ }), /* @__PURE__ */ jsx(SheetAction, {
369
+ label: "send",
370
+ variant: "primary",
371
+ testID: "task-detail-send",
372
+ onPress: submitMessage
373
+ })]
374
+ })
375
+ ] }) : null
376
+ ]
377
+ })] })
378
+ });
379
+ }
380
+ const styles$2 = StyleSheet.create((theme) => ({
381
+ field: {
382
+ gap: theme.spacing(1.5),
383
+ uni__dependencies: [0]
384
+ },
385
+ facts: {
386
+ flexDirection: "row",
387
+ flexWrap: "wrap",
388
+ gap: theme.spacing(5),
389
+ uni__dependencies: [0]
390
+ },
391
+ value: {
392
+ fontSize: theme.fontSize.base,
393
+ lineHeight: theme.lineHeight.lg,
394
+ color: theme.colors.dim,
395
+ uni__dependencies: [0]
396
+ },
397
+ hint: {
398
+ fontSize: theme.fontSize.sm,
399
+ lineHeight: theme.lineHeight.sm,
400
+ color: theme.colors.dim,
401
+ uni__dependencies: [0]
402
+ },
403
+ footer: {
404
+ flexDirection: "row",
405
+ justifyContent: "flex-end",
406
+ gap: theme.spacing(2),
407
+ uni__dependencies: [0]
408
+ }
409
+ }));
410
+ //#endregion
411
+ //#region src/extensions/workspaces/sessions/(frontend)/fill/_lib/taskStatusTone.ts
412
+ const TASK_STATUS_TONE = {
413
+ pending: "muted",
414
+ in_progress: "yellow",
415
+ completed: "green",
416
+ failed: "red",
417
+ deleted: "muted"
418
+ };
419
+ //#endregion
420
+ //#region src/extensions/workspaces/sessions/(frontend)/fill/_lib/TasksActivitySection.native.tsx
421
+ function titleInk(status) {
422
+ if (status === "failed") return "red";
423
+ return status === "completed" ? "dim" : "hi";
424
+ }
425
+ /** The session's tasks, read from the native store without @tanstack/react-store, which the app does not provide. */
426
+ function useSessionTasks(sessionId) {
427
+ const subscribe = useCallback((listener) => {
428
+ const subscription = tasks.store.subscribe(listener);
429
+ return () => subscription.unsubscribe();
430
+ }, []);
431
+ return useSyncExternalStore(subscribe, () => tasks.select(tasks.store.state, sessionId).tasks);
432
+ }
433
+ function TaskRow({ task, sessionId, sendSessionFrame, openSheet }) {
434
+ const detail = task.status === "in_progress" ? task.activeForm : task.description;
435
+ const agent = task.delegation?.agent;
436
+ return /* @__PURE__ */ jsx(View, {
437
+ testID: `activity-task-${task.id}`,
438
+ children: /* @__PURE__ */ jsx(ListRow, {
439
+ leading: /* @__PURE__ */ jsx(Dot, {
440
+ tone: TASK_STATUS_TONE[task.status],
441
+ pulse: task.status === "in_progress"
442
+ }),
443
+ title: /* @__PURE__ */ jsx(Button, {
444
+ variant: "ghost",
445
+ testID: `activity-task-title-${task.id}`,
446
+ accessibilityLabel: task.subject,
447
+ onPress: () => openSheet("view"),
448
+ children: /* @__PURE__ */ jsxs(Text, {
449
+ numberOfLines: 1,
450
+ style: styles$1.title(titleInk(task.status)),
451
+ children: [
452
+ "#",
453
+ task.id,
454
+ " ",
455
+ task.subject
456
+ ]
457
+ })
458
+ }),
459
+ description: detail || agent || task.blockedBy.length > 0 ? /* @__PURE__ */ jsxs(Text, {
460
+ numberOfLines: 1,
461
+ style: styles$1.meta,
462
+ children: [
463
+ agent ? `[${agent}] ` : "",
464
+ detail ?? "",
465
+ task.blockedBy.length > 0 ? ` · blocked by ${task.blockedBy.map((id) => `#${id}`).join(", ")}` : ""
466
+ ]
467
+ }) : void 0,
468
+ trailing: /* @__PURE__ */ jsxs(View, {
469
+ style: styles$1.line,
470
+ children: [/* @__PURE__ */ jsx(Text, {
471
+ style: styles$1.meta,
472
+ children: task.status.replace("_", " ")
473
+ }), task.status !== "completed" && task.status !== "deleted" ? /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
474
+ variant: "ghost",
475
+ size: "icon",
476
+ testID: `activity-task-menu-${task.id}`,
477
+ accessibilityLabel: `task #${task.id} actions`,
478
+ children: /* @__PURE__ */ jsx(KebabIcon, {})
479
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, { children: [
480
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
481
+ onSelect: () => openSheet("edit"),
482
+ children: [/* @__PURE__ */ jsx(EditIcon, {}), "Edit"]
483
+ }),
484
+ agent ? /* @__PURE__ */ jsxs(DropdownMenuItem, {
485
+ onSelect: () => openSheet("message"),
486
+ children: [/* @__PURE__ */ jsx(MessageIcon, {}), "Message agent"]
487
+ }) : null,
488
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
489
+ variant: "destructive",
490
+ onSelect: () => requestTaskRemoval(sendSessionFrame, sessionId, task.id),
491
+ children: [/* @__PURE__ */ jsx(TrashIcon, { color: "red" }), "Remove"]
492
+ })
493
+ ] })] }) : null]
494
+ })
495
+ })
496
+ });
497
+ }
498
+ /**
499
+ * The session task graph in the app's Activity list, mirroring the web
500
+ * section: active rows first, finished ones behind a collapsed history, and a
501
+ * sheet for reading or changing one task. Empty graphs render nothing.
502
+ */
503
+ function TasksActivitySection({ sessionId, sendSessionFrame }) {
504
+ const sessionTasks = useSessionTasks(sessionId);
505
+ const [historyOpen, setHistoryOpen] = useState(false);
506
+ const [sheet, setSheet] = useState();
507
+ if (sessionId === null || sessionTasks.length === 0) return null;
508
+ const active = sessionTasks.filter((task) => task.status === "pending" || task.status === "in_progress");
509
+ const history = sessionTasks.filter((task) => task.status === "completed" || task.status === "failed");
510
+ const sheetTask = sheet ? sessionTasks.find((task) => task.id === sheet.taskId) : void 0;
511
+ const row = (task) => /* @__PURE__ */ jsx(TaskRow, {
512
+ task,
513
+ sessionId,
514
+ sendSessionFrame,
515
+ openSheet: (mode) => setSheet({
516
+ taskId: task.id,
517
+ mode
518
+ })
519
+ }, task.id);
520
+ return /* @__PURE__ */ jsxs(View, {
521
+ style: styles$1.section,
522
+ children: [
523
+ active.length > 0 ? /* @__PURE__ */ jsx(View, {
524
+ style: styles$1.group,
525
+ children: active.map(row)
526
+ }) : null,
527
+ history.length > 0 ? /* @__PURE__ */ jsxs(View, {
528
+ style: styles$1.group,
529
+ children: [/* @__PURE__ */ jsxs(Button, {
530
+ variant: "ghost",
531
+ accessibilityState: { expanded: historyOpen },
532
+ onPress: () => setHistoryOpen((open) => !open),
533
+ style: styles$1.historyToggle,
534
+ children: [
535
+ /* @__PURE__ */ jsx(Fragment, { children: historyOpen ? /* @__PURE__ */ jsx(ChevronDownIcon, {}) : /* @__PURE__ */ jsx(ChevronRightIcon, {}) }),
536
+ /* @__PURE__ */ jsx(Text, {
537
+ style: styles$1.historyLabel,
538
+ children: "Session"
539
+ }),
540
+ /* @__PURE__ */ jsx(Badge, { children: history.length })
541
+ ]
542
+ }), historyOpen ? /* @__PURE__ */ jsx(View, {
543
+ style: [styles$1.group, styles$1.history],
544
+ children: history.map(row)
545
+ }) : null]
546
+ }) : null,
547
+ sheet && sheetTask ? /* @__PURE__ */ jsx(TaskDetailSheet, {
548
+ task: sheetTask,
549
+ sessionId,
550
+ mode: sheet.mode,
551
+ send: sendSessionFrame,
552
+ onClose: () => setSheet(void 0)
553
+ }, `${sheetTask.id}-${sheet.mode}`) : null
554
+ ]
555
+ });
556
+ }
557
+ const styles$1 = StyleSheet.create((theme) => ({
558
+ section: {
559
+ gap: theme.spacing(2),
560
+ uni__dependencies: [0]
561
+ },
562
+ group: {
563
+ gap: theme.spacing(.5),
564
+ uni__dependencies: [0]
565
+ },
566
+ history: {
567
+ paddingLeft: theme.spacing(2),
568
+ uni__dependencies: [0]
569
+ },
570
+ row: {
571
+ gap: theme.spacing(1),
572
+ paddingHorizontal: theme.spacing(1),
573
+ paddingVertical: theme.spacing(1),
574
+ borderRadius: theme.borderRadius.md,
575
+ uni__dependencies: [0]
576
+ },
577
+ line: {
578
+ flexDirection: "row",
579
+ alignItems: "center",
580
+ gap: theme.spacing(1.5),
581
+ uni__dependencies: [0]
582
+ },
583
+ title: (ink) => ({
584
+ fontSize: theme.fontSize.base,
585
+ lineHeight: theme.lineHeight.base,
586
+ fontWeight: "600",
587
+ color: theme.colors[ink],
588
+ uni__dependencies: [0]
589
+ }),
590
+ id: {
591
+ color: theme.colors.dim,
592
+ uni__dependencies: [0]
593
+ },
594
+ meta: {
595
+ fontSize: theme.fontSize.sm,
596
+ lineHeight: theme.lineHeight.sm,
597
+ color: theme.colors.dim,
598
+ uni__dependencies: [0]
599
+ },
600
+ detail: {
601
+ paddingLeft: theme.spacing(3),
602
+ uni__dependencies: [0]
603
+ },
604
+ historyToggle: {
605
+ flexDirection: "row",
606
+ alignItems: "center",
607
+ gap: theme.spacing(1.5),
608
+ minHeight: theme.spacing(11),
609
+ paddingHorizontal: theme.spacing(1),
610
+ borderRadius: theme.borderRadius.md,
611
+ uni__dependencies: [0]
612
+ },
613
+ chevron: {
614
+ fontSize: theme.fontSize.sm,
615
+ lineHeight: theme.lineHeight.sm,
616
+ color: theme.colors.faint,
617
+ uni__dependencies: [0]
618
+ },
619
+ historyLabel: {
620
+ fontSize: theme.fontSize.base,
621
+ lineHeight: theme.lineHeight.base,
622
+ fontWeight: "500",
623
+ color: theme.colors.dim,
624
+ uni__dependencies: [0]
625
+ },
626
+ count: {
627
+ fontSize: theme.fontSize["2xs"],
628
+ lineHeight: theme.lineHeight["2xs"],
629
+ color: theme.colors.faint,
630
+ uni__dependencies: [0]
631
+ }
632
+ }));
633
+ //#endregion
634
+ //#region src/extensions/workspaces/sessions/(frontend)/fill/Tasks.activity.tasks.native.tsx
635
+ var Tasks_activity_tasks_native_default = defineFill({ component: TasksActivitySection });
636
+ //#endregion
637
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_lib/taskToolFormat.ts
638
+ const STATUS_GLYPH = {
639
+ pending: "○",
640
+ in_progress: "◐",
641
+ completed: "●",
642
+ failed: "✗",
643
+ deleted: "⊘"
644
+ };
645
+ const STATUS_LABEL = {
646
+ pending: "pending",
647
+ in_progress: "in progress",
648
+ completed: "completed",
649
+ failed: "failed",
650
+ deleted: "deleted"
651
+ };
652
+ const ACTION_GLYPH = {
653
+ upsert: "✎",
654
+ delete: "×",
655
+ get: "›",
656
+ list: "☰",
657
+ clear: "∅",
658
+ assign: "⇒",
659
+ cancel: "⊗"
660
+ };
661
+ /**
662
+ * `upsert` is two operations behind one name, so a homogeneous batch narrows to
663
+ * the glyph the operator already reads: `+` means new work appeared, `→` means
664
+ * work moved. A mixed batch keeps the neutral write glyph.
665
+ */
666
+ const UPSERT_CREATE_GLYPH = "+";
667
+ const UPSERT_UPDATE_GLYPH = "→";
668
+ /** Task rows kept in a collapsed result, before the card is expanded. */
669
+ const TRANSCRIPT_TASK_ROWS = 8;
670
+ const TASK_STATUSES = [
671
+ "pending",
672
+ "in_progress",
673
+ "completed",
674
+ "failed",
675
+ "deleted"
676
+ ];
677
+ const TASK_ACTIONS = [
678
+ "upsert",
679
+ "list",
680
+ "get",
681
+ "delete",
682
+ "clear",
683
+ "assign",
684
+ "cancel"
685
+ ];
686
+ const INLINE_WHITESPACE = /\s+/gu;
687
+ function isRecord(value) {
688
+ return typeof value === "object" && value !== null && !Array.isArray(value);
689
+ }
690
+ function isStatus(value) {
691
+ return typeof value === "string" && TASK_STATUSES.includes(value);
692
+ }
693
+ function isAction(value) {
694
+ return typeof value === "string" && TASK_ACTIONS.includes(value);
695
+ }
696
+ function taskView(value) {
697
+ if (!isRecord(value) || typeof value.id !== "number" || typeof value.subject !== "string") return null;
698
+ if (!isStatus(value.status)) return null;
699
+ const task = {
700
+ id: value.id,
701
+ subject: value.subject,
702
+ status: value.status
703
+ };
704
+ if (typeof value.activeForm === "string") task.activeForm = value.activeForm;
705
+ if (Array.isArray(value.blockedBy)) task.blockedBy = value.blockedBy.filter((id) => typeof id === "number");
706
+ if (isRecord(value.delegation)) {
707
+ task.delegation = {};
708
+ if (typeof value.delegation.agent === "string") task.delegation.agent = value.delegation.agent;
709
+ if (typeof value.delegation.state === "string") task.delegation.state = value.delegation.state;
710
+ }
711
+ return task;
712
+ }
713
+ function idList(value) {
714
+ return Array.isArray(value) ? value.filter((id) => typeof id === "number") : [];
715
+ }
716
+ /** Narrows the wire details; null when they are not a task result at all. */
717
+ function taskDetailsView(details) {
718
+ if (!isRecord(details) || !isAction(details.action) || !Array.isArray(details.tasks)) return null;
719
+ const view = {
720
+ action: details.action,
721
+ params: isRecord(details.params) ? details.params : {},
722
+ tasks: details.tasks.map(taskView).filter((task) => task !== null)
723
+ };
724
+ if (typeof details.error === "string") view.error = details.error;
725
+ if (isRecord(details.upsert)) view.upsert = {
726
+ applied: idList(details.upsert.applied),
727
+ failed: typeof details.upsert.failed === "number" ? details.upsert.failed : 0
728
+ };
729
+ if (isRecord(details.assignment)) view.assignment = {
730
+ assigned: idList(details.assignment.assigned),
731
+ failed: typeof details.assignment.failed === "number" ? details.assignment.failed : 0
732
+ };
733
+ return view;
734
+ }
735
+ /** `#id` for the wire's id, which the TUI would resolve to a subject through the store. */
736
+ function idLabel(value) {
737
+ return typeof value === "number" || typeof value === "string" ? `#${value}` : "#?";
738
+ }
739
+ /** Keep dynamic content on one line. */
740
+ function inlineText(text) {
741
+ return text.replace(INLINE_WHITESPACE, " ").trim();
742
+ }
743
+ function upsertGlyph(items) {
744
+ if (items.length === 0) return ACTION_GLYPH.upsert;
745
+ if (items.every((item) => item.id === void 0)) return UPSERT_CREATE_GLYPH;
746
+ if (items.every((item) => item.id !== void 0)) return UPSERT_UPDATE_GLYPH;
747
+ return ACTION_GLYPH.upsert;
748
+ }
749
+ /**
750
+ * The TUI resolves an id to its subject through the task store; the card has
751
+ * no store and shows `#id` until the result names the task.
752
+ */
753
+ function taskCallView(args) {
754
+ const action = typeof args.action === "string" ? args.action : "task";
755
+ if (!isAction(action)) return {
756
+ glyph: "?",
757
+ action,
758
+ subjectTone: "dim"
759
+ };
760
+ const items = action === "upsert" && Array.isArray(args.tasks) ? args.tasks.filter(isRecord) : [];
761
+ const view = {
762
+ glyph: action === "upsert" ? upsertGlyph(items) : ACTION_GLYPH[action],
763
+ action,
764
+ subjectTone: "dim"
765
+ };
766
+ if (action === "upsert") {
767
+ if (items.length === 1) {
768
+ const only = items[0] ?? {};
769
+ if (only.id === void 0) {
770
+ if (typeof only.subject === "string") view.subject = inlineText(only.subject);
771
+ } else {
772
+ view.subject = typeof only.subject === "string" ? inlineText(only.subject) : idLabel(only.id);
773
+ view.subjectTone = "accent";
774
+ }
775
+ } else if (items.length > 1) view.subject = `${items.length} tasks`;
776
+ } else if (action === "assign") {
777
+ const assignments = Array.isArray(args.assignments) ? args.assignments.filter(isRecord) : [];
778
+ if (assignments.length === 1) {
779
+ const only = assignments[0] ?? {};
780
+ view.subject = idLabel(only.id);
781
+ view.subjectTone = "accent";
782
+ if (typeof only.agent === "string") view.detail = `→ ${only.agent}`;
783
+ } else if (assignments.length > 1) view.subject = `${assignments.length} tasks`;
784
+ } else if ((action === "get" || action === "delete" || action === "cancel") && args.id !== void 0) {
785
+ view.subject = idLabel(args.id);
786
+ view.subjectTone = "accent";
787
+ } else if (action === "list" && isStatus(args.status)) view.detail = STATUS_LABEL[args.status];
788
+ return view;
789
+ }
790
+ function taskRow(task) {
791
+ const row = {
792
+ id: task.id,
793
+ glyph: STATUS_GLYPH[task.status],
794
+ subject: inlineText(task.subject),
795
+ status: task.status,
796
+ closed: task.status === "completed" || task.status === "deleted",
797
+ blockedBy: task.blockedBy ?? []
798
+ };
799
+ if (task.delegation?.agent) row.agent = inlineText(task.delegation.agent);
800
+ if (task.status === "in_progress" && task.activeForm) row.activeForm = inlineText(task.activeForm);
801
+ return row;
802
+ }
803
+ function nonEmptyLines(text) {
804
+ return text.split("\n").filter((line) => line.trim().length > 0);
805
+ }
806
+ /**
807
+ * The rows `list` reported to the model: `details.tasks` is the whole
808
+ * document, so the call's filters apply again here or the card would disagree
809
+ * with the text the model was given.
810
+ */
811
+ function listedTasks(details) {
812
+ let view = details.tasks;
813
+ if (details.params.includeDeleted !== true) view = view.filter((task) => task.status !== "deleted");
814
+ if (isStatus(details.params.status)) view = view.filter((task) => task.status === details.params.status);
815
+ return view;
816
+ }
817
+ function byIds(details, ids) {
818
+ return ids.flatMap((id) => details.tasks.find((task) => task.id === id) ?? []);
819
+ }
820
+ function batch(tasks, failed, verb, expanded) {
821
+ if (tasks.length === 1 && failed === 0) return {
822
+ rows: [taskRow(tasks[0])],
823
+ status: null
824
+ };
825
+ const shown = expanded ? tasks : tasks.slice(0, TRANSCRIPT_TASK_ROWS);
826
+ let summary = `${tasks.length} ${verb}`;
827
+ if (failed > 0) summary += ` · ${failed} failed`;
828
+ if (tasks.length > shown.length) summary += ` · ${tasks.length - shown.length} more`;
829
+ return {
830
+ rows: shown.map(taskRow),
831
+ status: {
832
+ glyph: failed > 0 ? "!" : "✓",
833
+ tone: failed > 0 ? "warning" : "ok",
834
+ text: summary
835
+ }
836
+ };
837
+ }
838
+ function taskResultView(input) {
839
+ const details = taskDetailsView(input.details);
840
+ if (input.isPartial) return {
841
+ rows: [],
842
+ errorLines: [],
843
+ status: {
844
+ glyph: "◐",
845
+ tone: "running",
846
+ text: nonEmptyLines(input.output).at(-1) ?? "working"
847
+ }
848
+ };
849
+ if (input.isError || details?.error !== void 0) {
850
+ const all = nonEmptyLines(details?.error ?? input.output);
851
+ if (all.length <= 1) return {
852
+ rows: [],
853
+ errorLines: [],
854
+ status: {
855
+ glyph: "✗",
856
+ tone: "error",
857
+ text: all[0] ?? ""
858
+ }
859
+ };
860
+ return {
861
+ rows: [],
862
+ errorLines: input.expanded ? all : all.slice(0, TRANSCRIPT_TASK_ROWS),
863
+ status: {
864
+ glyph: "✗",
865
+ tone: "error",
866
+ text: ""
867
+ }
868
+ };
869
+ }
870
+ if (details === null) return {
871
+ rows: [],
872
+ errorLines: [],
873
+ status: {
874
+ glyph: "✓",
875
+ tone: "ok",
876
+ text: ""
877
+ }
878
+ };
879
+ if (details.action === "list") {
880
+ const tasks = listedTasks(details);
881
+ const shown = input.expanded ? tasks : tasks.slice(0, TRANSCRIPT_TASK_ROWS);
882
+ let summary = tasks.length === 0 ? "no tasks" : `${tasks.length} task${tasks.length === 1 ? "" : "s"}`;
883
+ if (tasks.length > shown.length) summary += ` · ${tasks.length - shown.length} more`;
884
+ return {
885
+ rows: shown.map(taskRow),
886
+ errorLines: [],
887
+ status: {
888
+ glyph: "✓",
889
+ tone: "ok",
890
+ text: summary
891
+ }
892
+ };
893
+ }
894
+ if (details.action === "clear") return {
895
+ rows: [],
896
+ errorLines: [],
897
+ status: {
898
+ glyph: "✓",
899
+ tone: "ok",
900
+ text: "cleared"
901
+ }
902
+ };
903
+ if (details.action === "assign" && details.assignment) return {
904
+ errorLines: [],
905
+ ...batch(byIds(details, details.assignment.assigned), details.assignment.failed, "assigned", input.expanded)
906
+ };
907
+ if (details.action === "upsert") return {
908
+ errorLines: [],
909
+ ...batch(byIds(details, details.upsert?.applied ?? []), details.upsert?.failed ?? 0, "applied", input.expanded)
910
+ };
911
+ const id = details.params.id;
912
+ const task = typeof id === "number" ? details.tasks.find((candidate) => candidate.id === id) : void 0;
913
+ if (!task) return {
914
+ rows: [],
915
+ errorLines: [],
916
+ status: {
917
+ glyph: "✓",
918
+ tone: "ok",
919
+ text: ""
920
+ }
921
+ };
922
+ return {
923
+ rows: [taskRow(task)],
924
+ errorLines: [],
925
+ status: null
926
+ };
927
+ }
928
+ //#endregion
929
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_lib/TaskToolMessage.native.tsx
930
+ const STATUS_DOT = {
931
+ pending: "muted",
932
+ in_progress: "yellow",
933
+ completed: "green",
934
+ failed: "red",
935
+ deleted: "muted"
936
+ };
937
+ const CALL_INK = {
938
+ dim: "hi",
939
+ accent: "blue"
940
+ };
941
+ const STATUS_TONE = {
942
+ pending: "neutral",
943
+ in_progress: "running",
944
+ completed: "ok",
945
+ failed: "error",
946
+ deleted: "neutral"
947
+ };
948
+ const RESULT_TONE = {
949
+ running: "running",
950
+ ok: "ok",
951
+ error: "error",
952
+ warning: "running"
953
+ };
954
+ function subjectInk(row) {
955
+ if (row.closed) return "dim";
956
+ return row.status === "in_progress" ? "blue" : "hi";
957
+ }
958
+ /** One task row: status glyph, id, subject and chips on the left, the status label flushed right. */
959
+ function TaskRowLine({ row }) {
960
+ return /* @__PURE__ */ jsxs(View, {
961
+ testID: "tool-result-task-row",
962
+ style: styles.row,
963
+ children: [
964
+ /* @__PURE__ */ jsx(Dot, {
965
+ tone: STATUS_DOT[row.status],
966
+ pulse: row.status === "in_progress"
967
+ }),
968
+ /* @__PURE__ */ jsxs(Text, {
969
+ style: styles.meta,
970
+ children: ["#", row.id]
971
+ }),
972
+ /* @__PURE__ */ jsxs(Text, {
973
+ numberOfLines: 1,
974
+ style: [
975
+ styles.rowSubject,
976
+ styles.ink(subjectInk(row)),
977
+ row.closed ? styles.struck : null
978
+ ],
979
+ children: [
980
+ row.subject,
981
+ row.agent ? /* @__PURE__ */ jsxs(Text, {
982
+ style: styles.meta,
983
+ children: [
984
+ " [",
985
+ row.agent,
986
+ "]"
987
+ ]
988
+ }) : null,
989
+ row.activeForm ? /* @__PURE__ */ jsxs(Text, {
990
+ style: styles.meta,
991
+ children: [
992
+ " (",
993
+ row.activeForm,
994
+ ")"
995
+ ]
996
+ }) : null,
997
+ row.blockedBy.length > 0 ? /* @__PURE__ */ jsxs(Text, {
998
+ style: styles.meta,
999
+ children: [" ⛓ ", row.blockedBy.map((id) => `#${id}`).join(",")]
1000
+ }) : null
1001
+ ]
1002
+ }),
1003
+ /* @__PURE__ */ jsx(StatusBadge, {
1004
+ tone: STATUS_TONE[row.status],
1005
+ children: STATUS_LABEL[row.status]
1006
+ })
1007
+ ]
1008
+ });
1009
+ }
1010
+ /**
1011
+ * The task tool's timeline item on the phone, laid out as the web card is:
1012
+ * `glyph action subject` with the assignee or list filter in the header, then
1013
+ * the rows the action touched and the batch or list summary.
1014
+ */
1015
+ function TaskToolMessage({ args, result, output, running, isError }) {
1016
+ const call = taskCallView(args);
1017
+ const collapsed = taskResultView({
1018
+ details: result?.details,
1019
+ output,
1020
+ expanded: false,
1021
+ isPartial: running,
1022
+ isError
1023
+ });
1024
+ const full = taskResultView({
1025
+ details: result?.details,
1026
+ output,
1027
+ expanded: true,
1028
+ isPartial: running,
1029
+ isError
1030
+ });
1031
+ const hidden = full.rows.length - collapsed.rows.length + (full.errorLines.length - collapsed.errorLines.length);
1032
+ return /* @__PURE__ */ jsx(MessageItem, {
1033
+ testID: "tool-task",
1034
+ tone: toolTone({
1035
+ running,
1036
+ isError
1037
+ }),
1038
+ expandable: hidden > 0,
1039
+ children: ({ expanded }) => {
1040
+ const view = expanded ? full : collapsed;
1041
+ const empty = view.rows.length === 0 && view.errorLines.length === 0 && view.status === null;
1042
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(MessageItemHeader, {
1043
+ title: "task",
1044
+ testID: "tool-call-task",
1045
+ accessibilityLabel: `task ${call.action}`,
1046
+ children: [
1047
+ /* @__PURE__ */ jsxs(Text, {
1048
+ style: styles.action,
1049
+ children: [
1050
+ call.glyph,
1051
+ " ",
1052
+ call.action
1053
+ ]
1054
+ }),
1055
+ call.subject ? /* @__PURE__ */ jsx(Text, {
1056
+ numberOfLines: 1,
1057
+ style: [styles.subject, styles.ink(CALL_INK[call.subjectTone])],
1058
+ children: call.subject
1059
+ }) : null,
1060
+ call.detail ? /* @__PURE__ */ jsx(Text, {
1061
+ style: styles.meta,
1062
+ children: call.detail
1063
+ }) : null
1064
+ ]
1065
+ }), empty ? null : /* @__PURE__ */ jsxs(MessageItemBody, {
1066
+ testID: "tool-result-task",
1067
+ children: [
1068
+ view.rows.length > 0 ? /* @__PURE__ */ jsx(View, {
1069
+ style: styles.rows,
1070
+ children: view.rows.map((row) => /* @__PURE__ */ jsx(TaskRowLine, { row }, row.id))
1071
+ }) : null,
1072
+ view.errorLines.length > 0 ? /* @__PURE__ */ jsx(CodeBlock, { text: view.errorLines.join("\n") }) : null,
1073
+ !expanded && hidden > 0 ? /* @__PURE__ */ jsxs(MessageItemStatus, {
1074
+ expands: true,
1075
+ accessibilityLabel: `Show ${hidden} more`,
1076
+ children: [hidden, " more"]
1077
+ }) : null,
1078
+ view.status ? /* @__PURE__ */ jsx(MessageItemStatus, {
1079
+ testID: "tool-result-task-status",
1080
+ tone: RESULT_TONE[view.status.tone],
1081
+ glyph: view.status.glyph,
1082
+ children: view.status.text
1083
+ }) : null
1084
+ ]
1085
+ })] });
1086
+ }
1087
+ });
1088
+ }
1089
+ const styles = StyleSheet.create((theme) => ({
1090
+ action: {
1091
+ fontSize: theme.fontSize.base,
1092
+ lineHeight: theme.lineHeight.base,
1093
+ fontWeight: "600",
1094
+ color: theme.colors.text,
1095
+ uni__dependencies: [0]
1096
+ },
1097
+ subject: {
1098
+ flexShrink: 1,
1099
+ fontSize: theme.fontSize.base,
1100
+ lineHeight: theme.lineHeight.base,
1101
+ fontWeight: "600",
1102
+ uni__dependencies: [0]
1103
+ },
1104
+ body: {
1105
+ gap: theme.spacing(1),
1106
+ uni__dependencies: [0]
1107
+ },
1108
+ rows: {
1109
+ gap: theme.spacing(.5),
1110
+ uni__dependencies: [0]
1111
+ },
1112
+ row: {
1113
+ flexDirection: "row",
1114
+ alignItems: "baseline",
1115
+ gap: theme.spacing(2),
1116
+ uni__dependencies: [0]
1117
+ },
1118
+ rowSubject: {
1119
+ flex: 1,
1120
+ fontSize: theme.fontSize.base,
1121
+ lineHeight: theme.lineHeight.base,
1122
+ fontWeight: "600",
1123
+ uni__dependencies: [0]
1124
+ },
1125
+ struck: { textDecorationLine: "line-through" },
1126
+ meta: {
1127
+ fontSize: theme.fontSize.sm,
1128
+ lineHeight: theme.lineHeight.sm,
1129
+ color: theme.colors.dim,
1130
+ uni__dependencies: [0]
1131
+ },
1132
+ statusGlyph: {
1133
+ fontSize: theme.fontSize.sm,
1134
+ lineHeight: theme.lineHeight.sm,
1135
+ fontWeight: "600",
1136
+ uni__dependencies: [0]
1137
+ },
1138
+ ink: (token) => ({
1139
+ color: theme.colors[token],
1140
+ uni__dependencies: [0]
1141
+ })
1142
+ }));
1143
+ //#endregion
1144
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/task.native.tsx
1145
+ var task_native_default = defineToolRenderer({ message: TaskToolMessage });
1146
+ //#endregion
1147
+ //#region generated/native.ts
1148
+ const via = (identity, value) => value === void 0 ? void 0 : {
1149
+ ...identity,
1150
+ ...value
1151
+ };
1152
+ const nativePlugin = defineNativePlugin({
1153
+ id: "task",
1154
+ session: {
1155
+ get activityGroups() {
1156
+ return [via({ name: "tasks" }, tasks_native_default)];
1157
+ },
1158
+ get channels() {
1159
+ return [via({ channel: "task_graph" }, task_graph_native_default)];
1160
+ },
1161
+ get fills() {
1162
+ return [via({
1163
+ slot: "activity.tasks",
1164
+ id: "tasks"
1165
+ }, Tasks_activity_tasks_native_default)];
1166
+ },
1167
+ get toolRenderers() {
1168
+ return [via({ tools: ["task"] }, task_native_default)];
1169
+ }
1170
+ }
1171
+ });
1172
+ //#endregion
1173
+ export { nativePlugin };
1174
+
1175
+ //# sourceMappingURL=native.mjs.map