@stevecastaneda/paseo-progress 1.14.1 → 1.14.3

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 (67) hide show
  1. package/README.md +28 -17
  2. package/client/attachments.tsx +122 -28
  3. package/client/blocks.tsx +33 -8
  4. package/client/chat-row-view.tsx +19 -6
  5. package/client/chat-row.ts +13 -2
  6. package/client/dashboard-query.ts +9 -4
  7. package/client/deliverables.tsx +82 -17
  8. package/client/dialog-stack.tsx +104 -42
  9. package/client/directory.ts +1 -3
  10. package/client/errors.ts +6 -1
  11. package/client/history.tsx +233 -79
  12. package/client/i18n.ts +10 -5
  13. package/client/launcher.tsx +57 -15
  14. package/client/locales/en.ts +28 -22
  15. package/client/locales/zh-CN.ts +18 -17
  16. package/client/messages.ts +1 -0
  17. package/client/motion.tsx +38 -14
  18. package/client/panel-opened.ts +3 -1
  19. package/client/panel.tsx +442 -160
  20. package/client/pdf.tsx +18 -4
  21. package/client/pieces.ts +6 -1
  22. package/client/pill-popover.tsx +108 -23
  23. package/client/pills.tsx +35 -12
  24. package/client/preview.tsx +265 -79
  25. package/client/questions.tsx +176 -55
  26. package/client/row.tsx +14 -3
  27. package/client/section-title.tsx +11 -2
  28. package/client/settings.tsx +76 -24
  29. package/client/show-more.tsx +23 -6
  30. package/client/spinner.tsx +11 -7
  31. package/client/status-badge.tsx +9 -7
  32. package/client/tabs.tsx +98 -20
  33. package/client/ticket-dialog.tsx +241 -73
  34. package/client/time-bar.tsx +5 -2
  35. package/client/video.tsx +15 -6
  36. package/client/whats-new.tsx +94 -36
  37. package/client/when.tsx +2 -1
  38. package/client/write-up.tsx +79 -12
  39. package/dist/server/cli.js +199 -101
  40. package/index.client.tsx +28 -13
  41. package/index.server.ts +19 -1
  42. package/package.json +15 -14
  43. package/server/cli.ts +72 -32
  44. package/server/dashboard.ts +9 -13
  45. package/server/launcher.ts +33 -17
  46. package/server/lock.ts +14 -7
  47. package/server/open.ts +32 -98
  48. package/server/progress-file.ts +6 -6
  49. package/server/question-mode.ts +12 -6
  50. package/server/skill.ts +22 -16
  51. package/server/store.ts +26 -41
  52. package/server/system.ts +113 -0
  53. package/server/tool.ts +89 -44
  54. package/server/whats-new.ts +25 -13
  55. package/shared/attachments.ts +40 -8
  56. package/shared/blocks.ts +9 -6
  57. package/shared/dashboard.ts +46 -29
  58. package/shared/events.ts +12 -10
  59. package/shared/markdown.ts +16 -8
  60. package/shared/question-modes.ts +8 -5
  61. package/shared/rpc.ts +9 -3
  62. package/shared/show.ts +20 -8
  63. package/shared/ticket-story.ts +1 -3
  64. package/skills/paseo-progress/SKILL.md +1 -0
  65. package/tsconfig.json +3 -10
  66. package/client/page-opener.ts +0 -9
  67. package/client/page-screen.tsx +0 -97
@@ -5,7 +5,16 @@ import React from "react";
5
5
  import { Text, View } from "react-native";
6
6
  import { PressScale, Presence } from "./motion";
7
7
  import { raised } from "./surfaces";
8
- import { getLauncherStatus, getSkillStatus, getToolsStatus, installLauncher, installSkill, type LauncherStatus, type SkillStatus, type ToolsState } from "../shared/rpc";
8
+ import {
9
+ getLauncherStatus,
10
+ getSkillStatus,
11
+ getToolsStatus,
12
+ installLauncher,
13
+ installSkill,
14
+ type LauncherStatus,
15
+ type SkillStatus,
16
+ type ToolsState,
17
+ } from "../shared/rpc";
9
18
  import { messagesFor, type ProgressMessages } from "./i18n";
10
19
  import { errorText } from "./errors";
11
20
  import { useProgressLanguage } from "./language";
@@ -111,7 +120,13 @@ export function SkillBanner({ colors, host }: { colors: Colors; host: PluginWork
111
120
  return <SetupBanner colors={colors} icon="Sparkles" notice={skill.notice} pending={skill.pending} onPress={skill.install} />;
112
121
  }
113
122
 
114
- function SetupBanner({ colors, icon, notice, pending, onPress }: {
123
+ function SetupBanner({
124
+ colors,
125
+ icon,
126
+ notice,
127
+ pending,
128
+ onPress,
129
+ }: {
115
130
  colors: Colors;
116
131
  icon: string;
117
132
  notice: { text: string; action?: string } | null;
@@ -120,20 +135,47 @@ function SetupBanner({ colors, icon, notice, pending, onPress }: {
120
135
  }) {
121
136
  const { messages: m } = useProgressLanguage();
122
137
  return (
123
- <Presence show={Boolean(notice)}>{notice ? (
124
- <View style={{ flexDirection: "row", alignItems: "center", flexWrap: "wrap", gap: 10, margin: 12, marginBottom: 0, padding: 8, borderRadius: 12, ...raised(colors), backgroundColor: colors.surface1 }}>
125
- {/* Held on the first line: the text wraps to several lines in the Explorer pane. */}
126
- <View style={{ alignSelf: "flex-start", height: 17, justifyContent: "center" }}><Icon name={icon} size={14} color={colors.foregroundMuted} /></View>
127
- <Text selectable style={{ flex: 1, minWidth: 200, color: colors.foregroundMuted, fontSize: 12, lineHeight: 17 }}>{notice.text}</Text>
128
- {notice.action ? (
129
- <PressScale accessibilityRole="button" disabled={pending} onPress={onPress}
130
- style={({ pressed, hovered }) => ({ paddingHorizontal: 10, paddingVertical: 5, borderRadius: 4, backgroundColor: colors.accent, opacity: pressed || pending ? 0.7 : hovered ? 0.85 : 1 })}>
131
- <Text style={{ color: colors.accentForeground, fontSize: 12, lineHeight: 16, fontWeight: "600" }}>
132
- {pending ? m.installing : notice.action}
138
+ <Presence show={Boolean(notice)}>
139
+ {notice ? (
140
+ <View
141
+ style={{
142
+ flexDirection: "row",
143
+ alignItems: "center",
144
+ flexWrap: "wrap",
145
+ gap: 10,
146
+ margin: 12,
147
+ marginBottom: 0,
148
+ padding: 8,
149
+ borderRadius: 12,
150
+ ...raised(colors),
151
+ backgroundColor: colors.surface1,
152
+ }}
153
+ >
154
+ {/* Held on the first line: the text wraps to several lines in the Explorer pane. */}
155
+ <View style={{ alignSelf: "flex-start", height: 17, justifyContent: "center" }}>
156
+ <Icon name={icon} size={14} color={colors.foregroundMuted} />
157
+ </View>
158
+ <Text selectable style={{ flex: 1, minWidth: 200, color: colors.foregroundMuted, fontSize: 12, lineHeight: 17 }}>
159
+ {notice.text}
133
160
  </Text>
134
- </PressScale>
161
+ {notice.action ? (
162
+ <PressScale
163
+ accessibilityRole="button"
164
+ disabled={pending}
165
+ onPress={onPress}
166
+ style={({ pressed, hovered }) => ({
167
+ paddingHorizontal: 10,
168
+ paddingVertical: 5,
169
+ borderRadius: 4,
170
+ backgroundColor: colors.accent,
171
+ opacity: pressed || pending ? 0.7 : hovered ? 0.85 : 1,
172
+ })}
173
+ >
174
+ <Text style={{ color: colors.accentForeground, fontSize: 12, lineHeight: 16, fontWeight: "600" }}>{pending ? m.installing : notice.action}</Text>
175
+ </PressScale>
176
+ ) : null}
177
+ </View>
135
178
  ) : null}
136
- </View>
137
- ) : null}</Presence>
179
+ </Presence>
138
180
  );
139
181
  }
@@ -2,30 +2,30 @@ import type { ProgressMessages } from "../messages";
2
2
 
3
3
  export const messages: ProgressMessages = {
4
4
  status: {
5
- "not_started": "Not started",
6
- "working": "Working",
7
- "blocked": "Blocked",
8
- "done": "Done",
9
- "skipped": "Skipped"
5
+ not_started: "Not started",
6
+ working: "Working",
7
+ blocked: "Blocked",
8
+ done: "Done",
9
+ skipped: "Skipped",
10
10
  },
11
11
  questionModes: {
12
- "stop": {
13
- "label": "Stop",
14
- "hint": "Agents stop all work when they ask, until you answer."
12
+ stop: {
13
+ label: "Stop",
14
+ hint: "Agents stop all work when they ask, until you answer.",
15
15
  },
16
16
  "work-around": {
17
- "label": "Work around",
18
- "hint": "Agents hold what your answer affects and keep working on the rest."
17
+ label: "Work around",
18
+ hint: "Agents hold what your answer affects and keep working on the rest.",
19
19
  },
20
20
  "keep-building": {
21
- "label": "Keep building",
22
- "hint": "Agents build their recommended option while you decide, and change course if you pick another. Big questions still wait."
23
- }
21
+ label: "Keep building",
22
+ hint: "Agents build their recommended option while you decide, and change course if you pick another. Big questions still wait.",
23
+ },
24
24
  },
25
25
  noteKinds: {
26
- "new": "New",
27
- "improved": "Improved",
28
- "fixed": "Fixed"
26
+ new: "New",
27
+ improved: "Improved",
28
+ fixed: "Fixed",
29
29
  },
30
30
  loading: "Loading…",
31
31
  loadingProgress: "Loading progress",
@@ -33,7 +33,8 @@ export const messages: ProgressMessages = {
33
33
  openSettings: "Open Progress settings",
34
34
  noProgress: "No progress recorded yet",
35
35
  emptyIntro: ["An agent working in this worktree records progress with the ", " command. It shows up here as soon as the first run starts."],
36
- emptyIntroTools: "An agent working in this worktree records progress with the Progress tools Paseo gives it. It shows up here as soon as the first run starts.",
36
+ emptyIntroTools:
37
+ "An agent working in this worktree records progress with the Progress tools Paseo gives it. It shows up here as soon as the first run starts.",
37
38
  toolsOn: "Agents record progress with Paseo tools. The paseo-progress command is a fallback for agents without them.",
38
39
  toolsNote: [
39
40
  "Let agents record progress without the command.",
@@ -108,6 +109,7 @@ export const messages: ProgressMessages = {
108
109
  copyPathDone: "Copied path",
109
110
  copyPathFailure: "Could not copy. Select the path and use Copy.",
110
111
  openFailure: "Could not open it",
112
+ openRefused: "Progress opens only images, video, audio, PDFs and text files",
111
113
  linkFailure: "Could not open this link.",
112
114
  showLess: "Show less",
113
115
  readMore: "Read more",
@@ -175,7 +177,8 @@ export const messages: ProgressMessages = {
175
177
  systemLanguage: "System",
176
178
  readProgressError: (error: string) => `Could not read progress: ${error}`,
177
179
  savedOutside: ["Progress is saved outside the repo, in ", ", so git never sees it."],
178
- staleWarning: (duration: string) => `Possibly stale. No update for ${duration}. The work may have stopped, so working items show a warning until the next update.`,
180
+ staleWarning: (duration: string) =>
181
+ `Possibly stale. No update for ${duration}. The work may have stopped, so working items show a warning until the next update.`,
179
182
  itemHeading: (label: string) => `${label}s`,
180
183
  noItems: (label: string) => `No ${label.toLowerCase()}s yet.`,
181
184
  skippedLines: (count: number, file: string) => `Skipped ${count} ${count === 1 ? "line" : "lines"} in ${file}: `,
@@ -189,7 +192,7 @@ export const messages: ProgressMessages = {
189
192
  details: (id: string) => `${id} details`,
190
193
  stageStarted: (stage: string) => `${stage} stage started `,
191
194
  waitsFor: (title: string) => `Waits for ${title}`,
192
- hasDeliverables: (count: number) => count === 1 ? "Has a deliverable" : `Has ${count} deliverables`,
195
+ hasDeliverables: (count: number) => (count === 1 ? "Has a deliverable" : `Has ${count} deliverables`),
193
196
  questionCount: (count: number) => `${count} ${count === 1 ? "question" : "questions"}`,
194
197
  shortQuestions: (count: number) => `${count}Q`,
195
198
  stuckCount: (count: number) => `${count} stuck`,
@@ -208,7 +211,8 @@ export const messages: ProgressMessages = {
208
211
  waitingForTicket: (id: string) => `Waiting for ${id}`,
209
212
  openItem: (title: string) => `Open ${title}`,
210
213
  workedEstimate: (worked: string, estimate: string) => `Worked ${worked} of a ${estimate} estimate`,
211
- byTimeHint: (id: string, label: string) => `Items marked “by time” weren't tagged to ${id}; they happened while it was the ${label.toLowerCase()} being worked on.`,
214
+ byTimeHint: (id: string, label: string) =>
215
+ `Items marked “by time” weren't tagged to ${id}; they happened while it was the ${label.toLowerCase()} being worked on.`,
212
216
  openAgentChat: (title: string) => `Open the chat with ${title}`,
213
217
  stageLabel: (stage: string) => `${stage} stage`,
214
218
  soFar: (duration: string) => `${duration} so far`,
@@ -230,11 +234,13 @@ export const messages: ProgressMessages = {
230
234
  useNamedFolder: (name: string) => `Use ${name}`,
231
235
  launcherMissing: (path: string) => `Agents record progress with the paseo-progress command, which isn't installed yet. Installing adds it at ${path}`,
232
236
  launcherOutdated: (path: string) => `An older paseo-progress command is installed at ${path}.`,
233
- launcherForeign: (path: string) => `Something else already exists at ${path}, so the plugin won't install there. The README shows how to install it elsewhere.`,
237
+ launcherForeign: (path: string) =>
238
+ `Something else already exists at ${path}, so the plugin won't install there. The README shows how to install it elsewhere.`,
234
239
  launcherOffPath: (path: string) => `paseo-progress is installed, but its folder isn't on the PATH Paseo uses, so agents need the full path: ${path}`,
235
240
  launcherInstalled: (path: string) => `Installed paseo-progress at ${path}`,
236
241
  skillSkipped: (paths: string) => ` Something else is already at ${paths}, so the plugin leaves it alone.`,
237
- skillMissing: (paths: string, skipped: string) => `Agents learn when to record progress from the paseo-progress skill, which isn't installed yet. Installing adds a link in ${paths}.${skipped}`,
242
+ skillMissing: (paths: string, skipped: string) =>
243
+ `Agents learn when to record progress from the paseo-progress skill, which isn't installed yet. Installing adds a link in ${paths}.${skipped}`,
238
244
  skillOutdated: (paths: string, skipped: string) => `The paseo-progress skill in ${paths} points to a copy of the plugin Paseo no longer runs.${skipped}`,
239
245
  resetTo: (label: string) => `Go back to ${label}`,
240
246
  ago: (duration: string) => `${duration} ago`,
@@ -2,30 +2,30 @@ import type { ProgressMessages } from "../messages";
2
2
 
3
3
  export const messages: ProgressMessages = {
4
4
  status: {
5
- "not_started": "未开始",
6
- "working": "进行中",
7
- "blocked": "受阻",
8
- "done": "已完成",
9
- "skipped": "已跳过"
5
+ not_started: "未开始",
6
+ working: "进行中",
7
+ blocked: "受阻",
8
+ done: "已完成",
9
+ skipped: "已跳过",
10
10
  },
11
11
  questionModes: {
12
- "stop": {
13
- "label": "停止",
14
- "hint": "智能体提问后会停止所有工作,直到你回答。"
12
+ stop: {
13
+ label: "停止",
14
+ hint: "智能体提问后会停止所有工作,直到你回答。",
15
15
  },
16
16
  "work-around": {
17
- "label": "继续其他工作",
18
- "hint": "智能体暂停受回答影响的工作,继续处理其余事项。"
17
+ label: "继续其他工作",
18
+ hint: "智能体暂停受回答影响的工作,继续处理其余事项。",
19
19
  },
20
20
  "keep-building": {
21
- "label": "继续构建",
22
- "hint": "你做决定期间,智能体会先按推荐方案构建;若你选择其他方案,则调整方向。重大问题仍会等待回答。"
23
- }
21
+ label: "继续构建",
22
+ hint: "你做决定期间,智能体会先按推荐方案构建;若你选择其他方案,则调整方向。重大问题仍会等待回答。",
23
+ },
24
24
  },
25
25
  noteKinds: {
26
- "new": "新增",
27
- "improved": "改进",
28
- "fixed": "修复"
26
+ new: "新增",
27
+ improved: "改进",
28
+ fixed: "修复",
29
29
  },
30
30
  loading: "加载中…",
31
31
  loadingProgress: "正在加载进度",
@@ -108,6 +108,7 @@ export const messages: ProgressMessages = {
108
108
  copyPathDone: "已复制路径",
109
109
  copyPathFailure: "无法复制。请选中路径后使用复制功能。",
110
110
  openFailure: "无法打开",
111
+ openRefused: "Progress 只打开图片、视频、音频、PDF 和文本文件",
111
112
  linkFailure: "无法打开此链接。",
112
113
  showLess: "收起",
113
114
  readMore: "展开阅读",
@@ -182,7 +183,7 @@ export const messages: ProgressMessages = {
182
183
  issueLine: (line: number, reason: string) => `第 ${line} 行(${reason})`,
183
184
  issueList: (items: string[], more: number) => `${items.join(",")}${more ? `,另有 ${more} 处` : ""}。`,
184
185
  overdueUpdate: (duration: string) => `超过预计的 ${duration} 未更新。最后更新于 `,
185
- blockedSince: (note: string | undefined, narrow: boolean) => `受阻${note ? `:${note}` : ""},始于 `,
186
+ blockedSince: (note: string | undefined, _narrow: boolean) => `受阻${note ? `:${note}` : ""},始于 `,
186
187
  doneCount: (count: number) => `${count} 项已完成`,
187
188
  skippedCount: (count: number) => `${count} 项已跳过`,
188
189
  toggleFinished: (shown: boolean, label: string) => `${shown ? "收起" : "显示"} ${label}`,
@@ -80,6 +80,7 @@ export interface ProgressMessages {
80
80
  copyPathDone: string;
81
81
  copyPathFailure: string;
82
82
  openFailure: string;
83
+ openRefused: string;
83
84
  linkFailure: string;
84
85
  showLess: string;
85
86
  readMore: string;
package/client/motion.tsx CHANGED
@@ -25,7 +25,13 @@ export function useReducedMotion(): boolean {
25
25
  }
26
26
 
27
27
  // A button that scales to 0.96 while pressed. `static` turns the scale off.
28
- export function PressScale({ static: isStatic, style, outerStyle, children, ...props }: Omit<PressableProps, "style" | "children"> & {
28
+ export function PressScale({
29
+ static: isStatic,
30
+ style,
31
+ outerStyle,
32
+ children,
33
+ ...props
34
+ }: Omit<PressableProps, "style" | "children"> & {
29
35
  static?: boolean;
30
36
  // Reaches the pressable itself, e.g. to focus it.
31
37
  ref?: React.Ref<View>;
@@ -40,14 +46,29 @@ export function PressScale({ static: isStatic, style, outerStyle, children, ...p
40
46
  const [pressed, setPressed] = useState(false);
41
47
  const [hovered, setHovered] = useState(false);
42
48
  return (
43
- <Pressable {...props} style={outerStyle}
44
- onHoverIn={(event) => { setHovered(true); props.onHoverIn?.(event); }}
45
- onHoverOut={(event) => { setHovered(false); props.onHoverOut?.(event); }}
46
- onPressIn={(event) => { setPressed(true); if (!isStatic) to(0.96); props.onPressIn?.(event); }}
47
- onPressOut={(event) => { setPressed(false); if (!isStatic) to(1); props.onPressOut?.(event); }}>
48
- <Animated.View style={[typeof style === "function" ? style({ pressed, hovered }) : style, { transform: [{ scale }] }]}>
49
- {children}
50
- </Animated.View>
49
+ <Pressable
50
+ {...props}
51
+ style={outerStyle}
52
+ onHoverIn={(event) => {
53
+ setHovered(true);
54
+ props.onHoverIn?.(event);
55
+ }}
56
+ onHoverOut={(event) => {
57
+ setHovered(false);
58
+ props.onHoverOut?.(event);
59
+ }}
60
+ onPressIn={(event) => {
61
+ setPressed(true);
62
+ if (!isStatic) to(0.96);
63
+ props.onPressIn?.(event);
64
+ }}
65
+ onPressOut={(event) => {
66
+ setPressed(false);
67
+ if (!isStatic) to(1);
68
+ props.onPressOut?.(event);
69
+ }}
70
+ >
71
+ <Animated.View style={[typeof style === "function" ? style({ pressed, hovered }) : style, { transform: [{ scale }] }]}>{children}</Animated.View>
51
72
  </Pressable>
52
73
  );
53
74
  }
@@ -123,7 +144,13 @@ export function Presence({ show, order = 0, children }: { show: boolean; order?:
123
144
  return;
124
145
  }
125
146
  const firstLoad = start !== null && Date.now() - start < FIRST_LOAD_MS;
126
- const animation = Animated.timing(enter, { toValue: 1, duration: ENTER_MS, delay: firstLoad ? order * STAGGER_MS : 0, easing: easeOut(), useNativeDriver: nativeDriver() });
147
+ const animation = Animated.timing(enter, {
148
+ toValue: 1,
149
+ duration: ENTER_MS,
150
+ delay: firstLoad ? order * STAGGER_MS : 0,
151
+ easing: easeOut(),
152
+ useNativeDriver: nativeDriver(),
153
+ });
127
154
  setMoving(true);
128
155
  animation.start(({ finished }) => finished && setMoving(false));
129
156
  return () => animation.stop();
@@ -159,9 +186,6 @@ export function Presence({ show, order = 0, children }: { show: boolean; order?:
159
186
 
160
187
  function blurStyle(enter: Animated.Value, exit: Animated.Value) {
161
188
  // Blur is 4px at either end of the motion and 0 at rest.
162
- const amount = Animated.add(
163
- enter.interpolate({ inputRange: [0, 1], outputRange: [4, 0] }),
164
- exit.interpolate({ inputRange: [0, 1], outputRange: [0, 4] }),
165
- );
189
+ const amount = Animated.add(enter.interpolate({ inputRange: [0, 1], outputRange: [4, 0] }), exit.interpolate({ inputRange: [0, 1], outputRange: [0, 4] }));
166
190
  return { filter: amount.interpolate({ inputRange: [0, 4], outputRange: ["blur(0px)", "blur(4px)"] }) };
167
191
  }
@@ -9,5 +9,7 @@ export function notePanelOpened(workspaceId: string) {
9
9
 
10
10
  export function onPanelOpened(listener: (workspaceId: string) => void): () => void {
11
11
  listeners.add(listener);
12
- return () => { listeners.delete(listener); };
12
+ return () => {
13
+ listeners.delete(listener);
14
+ };
13
15
  }