@herbertgao/pi-subagents 0.15.3 → 0.15.4
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.
- package/CHANGELOG.md +8 -0
- package/package.json +8 -4
- package/src/agent-color.ts +72 -67
- package/src/agent-file-toggle.ts +255 -0
- package/src/agent-manager.ts +191 -3
- package/src/agent-runner.ts +15 -2
- package/src/index.ts +289 -113
- package/src/output-file.ts +24 -1
- package/src/ui/agent-widget.ts +24 -2
- package/src/ui/schedule-menu.ts +9 -8
- package/src/ui/select-item.ts +48 -0
package/src/ui/schedule-menu.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent"
|
|
12
12
|
import type { SubagentScheduler } from "../schedule.js"
|
|
13
13
|
import type { ScheduledSubagent } from "../types.js"
|
|
14
|
+
import { selectItem } from "./select-item.js"
|
|
14
15
|
|
|
15
16
|
/** Format an ISO timestamp as relative time ("in 4h", "2d ago", "—"). */
|
|
16
17
|
function relTime(iso: string | undefined, now = Date.now()): string {
|
|
@@ -88,16 +89,16 @@ export async function showSchedulesMenu(
|
|
|
88
89
|
return
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
// Numbered + item-paired: two jobs whose names agree in the first 18
|
|
93
|
+
// characters format identically, and matching the returned string back
|
|
94
|
+
// against a parallel label array cancelled whichever came first.
|
|
95
|
+
const job = await selectItem(
|
|
96
|
+
ctx.ui,
|
|
93
97
|
`Scheduled jobs (${jobs.length}) — select to cancel`,
|
|
94
|
-
|
|
98
|
+
jobs,
|
|
99
|
+
(j) => formatJob(j, scheduler),
|
|
95
100
|
)
|
|
96
|
-
if (!
|
|
97
|
-
|
|
98
|
-
const idx = labels.indexOf(choice)
|
|
99
|
-
if (idx < 0) return
|
|
100
|
-
const job = jobs[idx]
|
|
101
|
+
if (!job) return
|
|
101
102
|
|
|
102
103
|
const ok = await ctx.ui.confirm(
|
|
103
104
|
`Cancel "${job.name}"?`,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* select-item.ts — pick an item from a list via `ctx.ui.select`, safely.
|
|
3
|
+
*
|
|
4
|
+
* Pi's dialog API is `select(title, options: string[]) => Promise<string | undefined>`:
|
|
5
|
+
* strings in, string out, with no index or value form. Callers therefore have to
|
|
6
|
+
* map the returned string back to the item it came from, and the obvious way —
|
|
7
|
+
* `labels.indexOf(choice)` over a parallel array — silently resolves to the
|
|
8
|
+
* FIRST match whenever two rows format identically. Row formatters here truncate
|
|
9
|
+
* (job names to 18 chars, agent descriptions to whatever fits), and the text they
|
|
10
|
+
* truncate is LLM-authored, so collisions are ordinary rather than exotic.
|
|
11
|
+
*
|
|
12
|
+
* This numbers every row, which makes the labels unique by construction — no
|
|
13
|
+
* data-dependent branch that only executes in the case nobody exercises — and
|
|
14
|
+
* keeps each label paired with its item so a later edit that sorts or filters
|
|
15
|
+
* between building and resolving cannot desync them.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Minimal shape of the `ctx.ui` surface this needs. */
|
|
19
|
+
export interface SelectUI {
|
|
20
|
+
select(title: string, options: string[]): Promise<string | undefined>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Show a numbered picker and return the chosen item (not its label).
|
|
25
|
+
*
|
|
26
|
+
* Returns undefined when the user escapes, or when the returned string is not
|
|
27
|
+
* one we offered.
|
|
28
|
+
*/
|
|
29
|
+
export async function selectItem<T>(
|
|
30
|
+
ui: SelectUI,
|
|
31
|
+
title: string,
|
|
32
|
+
items: readonly T[],
|
|
33
|
+
format: (item: T, index: number) => string,
|
|
34
|
+
): Promise<T | undefined> {
|
|
35
|
+
// Pad the number so a 10+ item list keeps its columns aligned.
|
|
36
|
+
const width = String(items.length).length
|
|
37
|
+
const rows = items.map((item, i) => ({
|
|
38
|
+
item,
|
|
39
|
+
label: `${String(i + 1).padStart(width)}. ${format(item, i)}`,
|
|
40
|
+
}))
|
|
41
|
+
|
|
42
|
+
const choice = await ui.select(
|
|
43
|
+
title,
|
|
44
|
+
rows.map((r) => r.label),
|
|
45
|
+
)
|
|
46
|
+
if (!choice) return undefined
|
|
47
|
+
return rows.find((r) => r.label === choice)?.item
|
|
48
|
+
}
|