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,145 @@
1
+ /**
2
+ * A small Markdown reader for bead descriptions.
3
+ *
4
+ * Plugins may only use React Native primitives, so there is no Markdown
5
+ * library to lean on. Bead descriptions use a narrow subset — headings,
6
+ * lists, task boxes, code blocks, quotes, tables and inline `code` / **bold** —
7
+ * and this turns exactly that into blocks a renderer can draw. Anything else
8
+ * stays a plain paragraph, so nothing is ever lost.
9
+ *
10
+ * Pure: no React, no React Native.
11
+ */
12
+
13
+ export type Inline = { text: string; bold?: boolean; code?: boolean; italic?: boolean };
14
+
15
+ export type MarkdownBlock =
16
+ | { kind: "heading"; level: number; spans: Inline[] }
17
+ | { kind: "paragraph"; spans: Inline[] }
18
+ | { kind: "bullet"; depth: number; spans: Inline[]; checked?: boolean }
19
+ | { kind: "numbered"; depth: number; number: string; spans: Inline[] }
20
+ | { kind: "quote"; spans: Inline[] }
21
+ | { kind: "code"; language: string | null; text: string }
22
+ | { kind: "table"; header: string[]; rows: string[][] }
23
+ | { kind: "rule" };
24
+
25
+ /** `**bold**`, `*italic*`, `` `code` `` — no nesting, which bead text never needs. */
26
+ export function parseInline(text: string): Inline[] {
27
+ const spans: Inline[] = [];
28
+ const pattern = /(`[^`]+`|\*\*[^*]+\*\*|__[^_]+__|\*[^*\s][^*]*\*)/g;
29
+ let last = 0;
30
+ for (const match of text.matchAll(pattern)) {
31
+ const index = match.index ?? 0;
32
+ if (index > last) spans.push({ text: text.slice(last, index) });
33
+ const token = match[0];
34
+ if (token.startsWith("`")) spans.push({ text: token.slice(1, -1), code: true });
35
+ else if (token.startsWith("**") || token.startsWith("__")) spans.push({ text: token.slice(2, -2), bold: true });
36
+ else spans.push({ text: token.slice(1, -1), italic: true });
37
+ last = index + token.length;
38
+ }
39
+ if (last < text.length) spans.push({ text: text.slice(last) });
40
+ return spans.length === 0 ? [{ text: "" }] : spans;
41
+ }
42
+
43
+ const cells = (line: string) =>
44
+ line
45
+ .trim()
46
+ .replace(/^\|/, "")
47
+ .replace(/\|$/, "")
48
+ .split("|")
49
+ .map((cell) => cell.trim());
50
+
51
+ export function parseMarkdown(source: string): MarkdownBlock[] {
52
+ const lines = source.replace(/\r\n/g, "\n").split("\n");
53
+ const blocks: MarkdownBlock[] = [];
54
+ let paragraph: string[] = [];
55
+ const flush = () => {
56
+ if (paragraph.length > 0) blocks.push({ kind: "paragraph", spans: parseInline(paragraph.join(" ")) });
57
+ paragraph = [];
58
+ };
59
+
60
+ for (let index = 0; index < lines.length; index += 1) {
61
+ const line = lines[index]!;
62
+
63
+ const fence = /^\s*```\s*([\w-]*)\s*$/.exec(line);
64
+ if (fence !== null) {
65
+ flush();
66
+ const body: string[] = [];
67
+ index += 1;
68
+ while (index < lines.length && !/^\s*```\s*$/.test(lines[index]!)) {
69
+ body.push(lines[index]!);
70
+ index += 1;
71
+ }
72
+ blocks.push({ kind: "code", language: fence[1] === "" ? null : fence[1]!, text: body.join("\n") });
73
+ continue;
74
+ }
75
+
76
+ if (line.trim() === "") {
77
+ flush();
78
+ continue;
79
+ }
80
+
81
+ const heading = /^(#{1,6})\s+(.*)$/.exec(line);
82
+ if (heading !== null) {
83
+ flush();
84
+ blocks.push({ kind: "heading", level: heading[1]!.length, spans: parseInline(heading[2]!.trim()) });
85
+ continue;
86
+ }
87
+
88
+ if (/^\s*([-*_])(\s*\1){2,}\s*$/.test(line)) {
89
+ flush();
90
+ blocks.push({ kind: "rule" });
91
+ continue;
92
+ }
93
+
94
+ const next = lines[index + 1];
95
+ if (line.includes("|") && next !== undefined && /^\s*\|?\s*:?-{2,}/.test(next)) {
96
+ flush();
97
+ const header = cells(line);
98
+ const rows: string[][] = [];
99
+ index += 2;
100
+ while (index < lines.length && lines[index]!.includes("|") && lines[index]!.trim() !== "") {
101
+ rows.push(cells(lines[index]!));
102
+ index += 1;
103
+ }
104
+ index -= 1;
105
+ blocks.push({ kind: "table", header, rows });
106
+ continue;
107
+ }
108
+
109
+ const bullet = /^(\s*)[-*+]\s+(?:\[([ xX])\]\s+)?(.*)$/.exec(line);
110
+ if (bullet !== null) {
111
+ flush();
112
+ const block: MarkdownBlock = {
113
+ kind: "bullet",
114
+ depth: Math.floor(bullet[1]!.length / 2),
115
+ spans: parseInline(bullet[3]!),
116
+ };
117
+ if (bullet[2] !== undefined) block.checked = bullet[2].toLowerCase() === "x";
118
+ blocks.push(block);
119
+ continue;
120
+ }
121
+
122
+ const numbered = /^(\s*)(\d+)[.)]\s+(.*)$/.exec(line);
123
+ if (numbered !== null) {
124
+ flush();
125
+ blocks.push({
126
+ kind: "numbered",
127
+ depth: Math.floor(numbered[1]!.length / 2),
128
+ number: numbered[2]!,
129
+ spans: parseInline(numbered[3]!),
130
+ });
131
+ continue;
132
+ }
133
+
134
+ const quote = /^\s*>\s?(.*)$/.exec(line);
135
+ if (quote !== null) {
136
+ flush();
137
+ blocks.push({ kind: "quote", spans: parseInline(quote[1]!) });
138
+ continue;
139
+ }
140
+
141
+ paragraph.push(line.trim());
142
+ }
143
+ flush();
144
+ return blocks;
145
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Plugin settings screen: the trace-store warning threshold
3
+ * (WP-211.2.1; REQ-055d, REQ-055e, REQ-055f).
4
+ *
5
+ * Paseo owns the storage and the revision handling through `useSettings`, so
6
+ * this screen only edits one number. Two things it must say out loud: the
7
+ * threshold is machine-wide (Paseo has no per-workspace settings), and an
8
+ * invalid value leaves the previous one in force.
9
+ *
10
+ * Client rules: React Native primitives only, colours from `theme.colors`, no
11
+ * Node import, no `server/` import.
12
+ */
13
+ import { type PluginSurfaceProps, useSettings } from "@getpaseo/plugin/client";
14
+ import { useMemo, useState } from "react";
15
+ import { Pressable, ScrollView, Text, TextInput, View } from "react-native";
16
+ import {
17
+ DEFAULT_WARN_ABOVE_BYTES,
18
+ dashboardSettings,
19
+ } from "../shared/settings";
20
+ import { HOST_SCOPE_NOTICE, dashboardStyles, formatBytes, toneColor } from "./dashboard-model";
21
+
22
+ /** Settings screen id, used by `openSettings` from the Dashboard. */
23
+ export const SETTINGS_SCREEN_ID = "paseo-bm-settings";
24
+ export const SETTINGS_ICON = "Settings";
25
+
26
+ const MEGABYTE = 1024 * 1024;
27
+
28
+ export function DashboardSettingsScreen({ theme, layout }: PluginSurfaceProps) {
29
+ const styles = useMemo(() => dashboardStyles(theme, layout.compact), [theme, layout.compact]);
30
+ const settings = useSettings(dashboardSettings);
31
+ const [draft, setDraft] = useState<string | null>(null);
32
+ const [error, setError] = useState<string | null>(null);
33
+
34
+ const current =
35
+ settings.status === "ready" ? settings.values.warnAboveBytes : DEFAULT_WARN_ABOVE_BYTES;
36
+ const shown = draft ?? String(Math.round(current / MEGABYTE));
37
+
38
+ const save = async () => {
39
+ if (settings.status !== "ready") return;
40
+ const megabytes = Number.parseInt(shown, 10);
41
+ if (!Number.isFinite(megabytes) || megabytes <= 0) {
42
+ // REQ-055f: refuse, and leave the stored threshold in force.
43
+ setError(`"${shown}" is not a size in MB. The current threshold stays at ${formatBytes(current)}.`);
44
+ return;
45
+ }
46
+ setError(null);
47
+ const saved = await settings.save({ warnAboveBytes: megabytes * MEGABYTE }, settings.revision);
48
+ if (!saved) setError(settings.saveError ?? "Could not save the setting.");
49
+ else setDraft(null);
50
+ };
51
+
52
+ return (
53
+ <ScrollView style={styles.screen} contentContainerStyle={styles.content}>
54
+ <Text style={styles.title}>Beads Dashboard</Text>
55
+ <Text style={styles.sectionTitle}>Trace store warning</Text>
56
+ <Text style={styles.body}>
57
+ The Dashboard warns when paseo-bm&apos;s trace store grows past this size. It never deletes
58
+ anything on its own. {HOST_SCOPE_NOTICE}
59
+ </Text>
60
+
61
+ <View style={styles.card}>
62
+ <Text style={styles.body}>Warn above (MB)</Text>
63
+ <TextInput
64
+ accessibilityLabel="Warn above, in megabytes"
65
+ keyboardType="number-pad"
66
+ value={shown}
67
+ onChangeText={(next) => setDraft(next)}
68
+ style={[styles.mono, { borderColor: theme.colors.border, borderWidth: 1, borderRadius: 8, padding: 8 }]}
69
+ />
70
+ <Text style={styles.body}>{`Currently ${formatBytes(current)}.`}</Text>
71
+ {error !== null ? (
72
+ <Text style={[styles.body, { color: toneColor(theme, "danger") }]}>{error}</Text>
73
+ ) : null}
74
+ {settings.status === "error" ? (
75
+ <Text style={[styles.body, { color: toneColor(theme, "danger") }]}>{settings.error}</Text>
76
+ ) : null}
77
+ <Pressable
78
+ accessibilityRole="button"
79
+ accessibilityLabel="Save the warning threshold"
80
+ accessibilityState={{ disabled: settings.saving }}
81
+ disabled={settings.saving}
82
+ onPress={() => {
83
+ void save();
84
+ }}
85
+ style={[styles.button, settings.saving ? { opacity: 0.5 } : null]}
86
+ >
87
+ <Text style={styles.buttonText}>{settings.saving ? "Saving…" : "Save"}</Text>
88
+ </Pressable>
89
+ <Pressable
90
+ accessibilityRole="button"
91
+ accessibilityLabel="Reset the warning threshold to the default"
92
+ onPress={() => {
93
+ setDraft(null);
94
+ setError(null);
95
+ void settings.reset();
96
+ }}
97
+ style={styles.secondaryButton}
98
+ >
99
+ <Text style={styles.secondaryButtonText}>{`Reset to ${formatBytes(DEFAULT_WARN_ABOVE_BYTES)}`}</Text>
100
+ </Pressable>
101
+ </View>
102
+ </ScrollView>
103
+ );
104
+ }