paseo-bm-plugin 0.0.0-placeholder.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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/client/agent-tree.ts +308 -0
  4. package/client/answer-state.ts +62 -0
  5. package/client/bead-chips.tsx +147 -0
  6. package/client/beads-header-button.ts +108 -0
  7. package/client/beads-model.ts +581 -0
  8. package/client/beads-screen.tsx +516 -0
  9. package/client/beads-tab.tsx +58 -0
  10. package/client/chat-card.tsx +636 -0
  11. package/client/chat-cards.ts +1038 -0
  12. package/client/dashboard-actions.tsx +255 -0
  13. package/client/dashboard-model.ts +947 -0
  14. package/client/dashboard-view.ts +215 -0
  15. package/client/dashboard.tsx +318 -0
  16. package/client/launch-manager.ts +323 -0
  17. package/client/launcher.tsx +516 -0
  18. package/client/markdown-view.tsx +112 -0
  19. package/client/markdown.ts +145 -0
  20. package/client/settings.tsx +104 -0
  21. package/client/setup-model.ts +552 -0
  22. package/client/setup-screen.tsx +913 -0
  23. package/client/slot.ts +47 -0
  24. package/client/tree.tsx +204 -0
  25. package/client/ui.tsx +262 -0
  26. package/client/waiting-pills-model.ts +156 -0
  27. package/client/waiting-pills.tsx +201 -0
  28. package/index.client.tsx +232 -0
  29. package/index.server.ts +168 -0
  30. package/package.json +35 -0
  31. package/paseo-plugin.json +6 -0
  32. package/roles/manager.md +181 -0
  33. package/roles/reviewer.md +160 -0
  34. package/roles/worker.md +407 -0
  35. package/server/agent-labels.ts +194 -0
  36. package/server/agent-role.ts +102 -0
  37. package/server/answer-marks.ts +120 -0
  38. package/server/bead-actions.ts +88 -0
  39. package/server/bead-work.ts +80 -0
  40. package/server/beads-store.ts +342 -0
  41. package/server/bm-report.ts +433 -0
  42. package/server/chat-peers.ts +65 -0
  43. package/server/chat-rpc.ts +122 -0
  44. package/server/chat-waiting.ts +182 -0
  45. package/server/collector.ts +629 -0
  46. package/server/config-writer.ts +222 -0
  47. package/server/cost.ts +88 -0
  48. package/server/dashboard-rpc.ts +662 -0
  49. package/server/fallback-detect.ts +183 -0
  50. package/server/fallback-handover.ts +365 -0
  51. package/server/fallback-manager.ts +170 -0
  52. package/server/fallback-reviewer.ts +198 -0
  53. package/server/fallback-rpc.ts +306 -0
  54. package/server/fallback-settings.ts +322 -0
  55. package/server/fallback-state.ts +518 -0
  56. package/server/fallback-switch.ts +191 -0
  57. package/server/fallback-wait.ts +188 -0
  58. package/server/format-check.ts +352 -0
  59. package/server/install-home.ts +187 -0
  60. package/server/live-timeline.ts +129 -0
  61. package/server/manager-instructions.ts +9 -0
  62. package/server/manager.ts +647 -0
  63. package/server/model-costs.ts +238 -0
  64. package/server/notice-queue.ts +315 -0
  65. package/server/notices.ts +81 -0
  66. package/server/paseo-cli.ts +115 -0
  67. package/server/provider-id.ts +12 -0
  68. package/server/review-budget.ts +208 -0
  69. package/server/reviewer-instructions.ts +9 -0
  70. package/server/role-choices.ts +161 -0
  71. package/server/role-extras.ts +270 -0
  72. package/server/role-hook.ts +347 -0
  73. package/server/role-mode.ts +397 -0
  74. package/server/role-settings-rpc.ts +325 -0
  75. package/server/roles.ts +96 -0
  76. package/server/settings-notices.ts +112 -0
  77. package/server/setup-rpc.ts +70 -0
  78. package/server/setup-skills.ts +121 -0
  79. package/server/setup-tools.ts +162 -0
  80. package/server/shell.ts +68 -0
  81. package/server/stop-propagation.ts +365 -0
  82. package/server/tools-check.ts +118 -0
  83. package/server/trace-store.ts +1137 -0
  84. package/server/traces.ts +1356 -0
  85. package/server/worker-instructions.ts +9 -0
  86. package/server/workflow-steps.ts +422 -0
  87. package/shared/bead-ids.ts +25 -0
  88. package/shared/bm-fallback.ts +91 -0
  89. package/shared/bm-format.ts +424 -0
  90. package/shared/bm-questions.ts +213 -0
  91. package/shared/bm-report.ts +433 -0
  92. package/shared/contracts.ts +1371 -0
  93. package/shared/fallback-patterns.ts +201 -0
  94. package/shared/fallback.ts +46 -0
  95. package/shared/new-request.ts +20 -0
  96. package/shared/order.ts +22 -0
  97. package/shared/prices.ts +65 -0
  98. package/shared/settings.ts +57 -0
  99. package/shared/sole-worker.ts +20 -0
  100. package/shared/version.ts +6 -0
  101. package/tsconfig.json +16 -0
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Destructive Dashboard flows: delete and reassign
3
+ * (WP-211.2.2; REQ-054, REQ-055b, REQ-057d).
4
+ *
5
+ * These live in their own file because they are the only irreversible thing the
6
+ * Dashboard can do, and they have their own review and evidence boundary.
7
+ *
8
+ * The shape is always the same three steps, and none can be skipped:
9
+ *
10
+ * 1. ask the server what would be lost (`dryRun: true`);
11
+ * 2. show that answer and wait — the confirmation gate has no default "Yes",
12
+ * it simply has nothing pending until step 1 returned;
13
+ * 3. only then call the real RPC.
14
+ *
15
+ * Nothing here runs on mount, on a timer, or on a refresh: every path starts
16
+ * with a press (REQ-054f).
17
+ *
18
+ * Client rules: React Native primitives only, colours from `theme.colors`, no
19
+ * Node import, no `server/` import.
20
+ */
21
+ import { type PluginSurfaceProps, useRpc, usePaseo } from "@getpaseo/plugin/client";
22
+ import { useQuery } from "@tanstack/react-query";
23
+ import { useMemo, useState, useSyncExternalStore } from "react";
24
+ import { ActivityIndicator, Pressable, Text, View } from "react-native";
25
+ import { tracesDeleteRpc, tracesReassignRpc, type WorkspaceState } from "../shared/contracts";
26
+ import type { dashboardStyles } from "./dashboard-model";
27
+ import {
28
+ OLDER_THAN_DAYS,
29
+ createConfirmationGate,
30
+ describeAction,
31
+ olderThanCutoff,
32
+ toneColor,
33
+ type DeleteScope,
34
+ } from "./dashboard-model";
35
+ import { errorMessageOf } from "./launch-manager";
36
+
37
+ export interface TraceActionsProps {
38
+ theme: PluginSurfaceProps["theme"];
39
+ layout: PluginSurfaceProps["layout"];
40
+ styles: ReturnType<typeof dashboardStyles>;
41
+ workspaceId: string;
42
+ scope: "workspace" | "trace";
43
+ traceId?: string;
44
+ /** Reassignment is only offered for a workspace Paseo no longer lists. */
45
+ workspaceState?: WorkspaceState;
46
+ onDone: () => void;
47
+ }
48
+
49
+ export function TraceActions({
50
+ theme,
51
+ layout,
52
+ styles,
53
+ workspaceId,
54
+ scope,
55
+ traceId,
56
+ workspaceState,
57
+ onDone,
58
+ }: TraceActionsProps) {
59
+ const deleteTraces = useRpc(tracesDeleteRpc);
60
+ const reassign = useRpc(tracesReassignRpc);
61
+ const paseo = usePaseo();
62
+ const gate = useMemo(() => createConfirmationGate(), []);
63
+ const pending = useSyncExternalStore(gate.subscribe, gate.getPending, gate.getPending);
64
+ const [busy, setBusy] = useState(false);
65
+ const [error, setError] = useState<string | null>(null);
66
+
67
+ const targets = useQuery({
68
+ queryKey: ["paseo-bm", "reassign-targets"],
69
+ queryFn: async () => {
70
+ const result = await paseo.workspaces.list({ sort: [{ key: "activity_at", direction: "desc" }] });
71
+ return result.entries
72
+ .filter((workspace) => !workspace.archivingAt && workspace.id !== workspaceId)
73
+ .map((workspace) => ({ id: workspace.id, label: workspace.title || workspace.name }));
74
+ },
75
+ enabled: workspaceState === "orphaned",
76
+ });
77
+
78
+ /** Step 1: ask what would be lost, then hand it to the gate. */
79
+ const preview = async (deleteScope: DeleteScope) => {
80
+ setError(null);
81
+ setBusy(true);
82
+ try {
83
+ const result = await deleteTraces({ workspaceId, scope: deleteScope, dryRun: true });
84
+ gate.request({
85
+ kind: "delete",
86
+ scope: deleteScope,
87
+ preview: result.deleted,
88
+ running: result.deleted.running,
89
+ });
90
+ } catch (failure) {
91
+ setError(errorMessageOf(failure));
92
+ } finally {
93
+ setBusy(false);
94
+ }
95
+ };
96
+
97
+ const previewReassign = async (toWorkspaceId: string) => {
98
+ setError(null);
99
+ setBusy(true);
100
+ try {
101
+ const result = await reassign({ fromWorkspaceId: workspaceId, toWorkspaceId, dryRun: true });
102
+ gate.request({ kind: "reassign", fromWorkspaceId: workspaceId, toWorkspaceId, preview: result.moved });
103
+ } catch (failure) {
104
+ setError(errorMessageOf(failure));
105
+ } finally {
106
+ setBusy(false);
107
+ }
108
+ };
109
+
110
+ /** Step 3: the only place either destructive RPC is called for real. */
111
+ const runPending = async () => {
112
+ setError(null);
113
+ setBusy(true);
114
+ try {
115
+ await gate.confirm(async (action) => {
116
+ if (action.kind === "delete") {
117
+ await deleteTraces({ workspaceId, scope: action.scope });
118
+ } else {
119
+ await reassign({ fromWorkspaceId: action.fromWorkspaceId, toWorkspaceId: action.toWorkspaceId });
120
+ }
121
+ });
122
+ onDone();
123
+ } catch (failure) {
124
+ setError(errorMessageOf(failure));
125
+ } finally {
126
+ setBusy(false);
127
+ }
128
+ };
129
+
130
+ const described = pending === null ? null : describeAction(pending);
131
+
132
+ return (
133
+ <View style={{ gap: layout.compact ? 6 : 8 }}>
134
+ {error === null ? null : (
135
+ <Text style={[styles.body, { color: toneColor(theme, "danger") }]} accessibilityLiveRegion="polite">
136
+ {error}
137
+ </Text>
138
+ )}
139
+
140
+ {described === null ? (
141
+ <View style={{ flexDirection: layout.compact ? "column" : "row", gap: 8 }}>
142
+ {scope === "trace" && traceId !== undefined ? (
143
+ <Pressable
144
+ accessibilityRole="button"
145
+ accessibilityLabel="Delete this trace"
146
+ accessibilityState={{ disabled: busy }}
147
+ disabled={busy}
148
+ onPress={() => {
149
+ void preview({ traceId });
150
+ }}
151
+ style={styles.dangerButton}
152
+ >
153
+ <Text style={styles.dangerButtonText}>Delete this trace</Text>
154
+ </Pressable>
155
+ ) : null}
156
+
157
+ {scope === "workspace" ? (
158
+ <>
159
+ <Pressable
160
+ accessibilityRole="button"
161
+ accessibilityLabel={`Delete traces older than ${OLDER_THAN_DAYS} days`}
162
+ accessibilityState={{ disabled: busy }}
163
+ disabled={busy}
164
+ onPress={() => {
165
+ void preview({ before: olderThanCutoff(new Date()) });
166
+ }}
167
+ style={styles.dangerButton}
168
+ >
169
+ <Text style={styles.dangerButtonText}>{`Delete traces older than ${OLDER_THAN_DAYS} days`}</Text>
170
+ </Pressable>
171
+ <Pressable
172
+ accessibilityRole="button"
173
+ accessibilityLabel="Delete every trace of this workspace"
174
+ accessibilityState={{ disabled: busy }}
175
+ disabled={busy}
176
+ onPress={() => {
177
+ void preview({ allOfWorkspace: true });
178
+ }}
179
+ style={styles.dangerButton}
180
+ >
181
+ <Text style={styles.dangerButtonText}>Delete all traces here</Text>
182
+ </Pressable>
183
+ </>
184
+ ) : null}
185
+
186
+ {busy ? <ActivityIndicator color={styles.spinner.color} /> : null}
187
+ </View>
188
+ ) : (
189
+ <View style={styles.card}>
190
+ <Text style={styles.sectionTitle}>{described.title}</Text>
191
+ {described.body.map((line) => (
192
+ <Text key={line} style={styles.body}>
193
+ {line}
194
+ </Text>
195
+ ))}
196
+ <View style={{ flexDirection: layout.compact ? "column" : "row", gap: 8 }}>
197
+ {/* Cancel first, so the safe choice is the one under the thumb. */}
198
+ <Pressable
199
+ accessibilityRole="button"
200
+ accessibilityLabel="Cancel and keep the traces"
201
+ onPress={() => {
202
+ setError(null);
203
+ gate.cancel();
204
+ }}
205
+ style={styles.secondaryButton}
206
+ >
207
+ <Text style={styles.secondaryButtonText}>No, keep them</Text>
208
+ </Pressable>
209
+ <Pressable
210
+ accessibilityRole="button"
211
+ accessibilityLabel={described.confirmLabel}
212
+ accessibilityState={{ disabled: busy }}
213
+ disabled={busy}
214
+ onPress={() => {
215
+ void runPending();
216
+ }}
217
+ style={styles.dangerButton}
218
+ >
219
+ <Text style={styles.dangerButtonText}>{busy ? "Working…" : described.confirmLabel}</Text>
220
+ </Pressable>
221
+ </View>
222
+ </View>
223
+ )}
224
+
225
+ {/* Reassignment: only for a workspace Paseo no longer lists (REQ-057d). */}
226
+ {described === null && scope === "workspace" && workspaceState === "orphaned" ? (
227
+ <View style={{ gap: 6 }}>
228
+ <Text style={styles.body}>
229
+ Move these traces onto a workspace that exists. They keep the workspace they were
230
+ recorded under; only the grouping changes.
231
+ </Text>
232
+ {targets.isPending ? <ActivityIndicator color={styles.spinner.color} /> : null}
233
+ {targets.data?.length === 0 ? (
234
+ <Text style={styles.body}>There is no other workspace to move them to.</Text>
235
+ ) : null}
236
+ {targets.data?.map((target) => (
237
+ <Pressable
238
+ key={target.id}
239
+ accessibilityRole="button"
240
+ accessibilityLabel={`Reassign these traces to ${target.label}`}
241
+ accessibilityState={{ disabled: busy }}
242
+ disabled={busy}
243
+ onPress={() => {
244
+ void previewReassign(target.id);
245
+ }}
246
+ style={styles.secondaryButton}
247
+ >
248
+ <Text style={styles.secondaryButtonText}>{`Reassign to ${target.label}`}</Text>
249
+ </Pressable>
250
+ ))}
251
+ </View>
252
+ ) : null}
253
+ </View>
254
+ );
255
+ }