@oh-my-pi/pi-coding-agent 3.21.0 → 3.25.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.
- package/CHANGELOG.md +55 -1
- package/docs/sdk.md +47 -50
- package/examples/custom-tools/README.md +0 -15
- package/examples/hooks/custom-compaction.ts +1 -3
- package/examples/sdk/README.md +6 -10
- package/package.json +5 -5
- package/src/cli/args.ts +9 -6
- package/src/core/agent-session.ts +3 -3
- package/src/core/custom-commands/bundled/wt/index.ts +3 -0
- package/src/core/custom-tools/wrapper.ts +0 -1
- package/src/core/extensions/index.ts +1 -6
- package/src/core/extensions/wrapper.ts +0 -7
- package/src/core/file-mentions.ts +5 -8
- package/src/core/sdk.ts +48 -111
- package/src/core/session-manager.ts +7 -0
- package/src/core/system-prompt.ts +22 -33
- package/src/core/tools/ask.ts +14 -7
- package/src/core/tools/bash-interceptor.ts +4 -4
- package/src/core/tools/bash.ts +19 -9
- package/src/core/tools/complete.ts +131 -0
- package/src/core/tools/context.ts +7 -0
- package/src/core/tools/edit.ts +8 -15
- package/src/core/tools/exa/render.ts +4 -16
- package/src/core/tools/find.ts +7 -18
- package/src/core/tools/git.ts +13 -3
- package/src/core/tools/grep.ts +7 -18
- package/src/core/tools/index.test.ts +188 -0
- package/src/core/tools/index.ts +106 -236
- package/src/core/tools/jtd-to-json-schema.ts +274 -0
- package/src/core/tools/ls.ts +4 -9
- package/src/core/tools/lsp/index.ts +32 -29
- package/src/core/tools/lsp/render.ts +7 -28
- package/src/core/tools/notebook.ts +3 -5
- package/src/core/tools/output.ts +130 -31
- package/src/core/tools/read.ts +8 -19
- package/src/core/tools/review.ts +0 -18
- package/src/core/tools/rulebook.ts +8 -2
- package/src/core/tools/task/agents.ts +28 -7
- package/src/core/tools/task/artifacts.ts +6 -9
- package/src/core/tools/task/discovery.ts +0 -6
- package/src/core/tools/task/executor.ts +306 -257
- package/src/core/tools/task/index.ts +65 -235
- package/src/core/tools/task/name-generator.ts +247 -0
- package/src/core/tools/task/render.ts +158 -19
- package/src/core/tools/task/types.ts +13 -11
- package/src/core/tools/task/worker-protocol.ts +18 -0
- package/src/core/tools/task/worker.ts +270 -0
- package/src/core/tools/web-fetch.ts +4 -36
- package/src/core/tools/web-search/index.ts +2 -1
- package/src/core/tools/web-search/render.ts +1 -4
- package/src/core/tools/write.ts +7 -15
- package/src/discovery/helpers.test.ts +1 -1
- package/src/index.ts +5 -16
- package/src/main.ts +4 -4
- package/src/modes/interactive/theme/theme.ts +4 -4
- package/src/prompts/task.md +14 -57
- package/src/prompts/tools/output.md +4 -3
- package/src/prompts/tools/task.md +70 -0
- package/examples/custom-tools/question/index.ts +0 -84
- package/examples/custom-tools/subagent/README.md +0 -172
- package/examples/custom-tools/subagent/agents/planner.md +0 -37
- package/examples/custom-tools/subagent/agents/scout.md +0 -50
- package/examples/custom-tools/subagent/agents/worker.md +0 -24
- package/examples/custom-tools/subagent/agents.ts +0 -156
- package/examples/custom-tools/subagent/commands/implement-and-review.md +0 -10
- package/examples/custom-tools/subagent/commands/implement.md +0 -10
- package/examples/custom-tools/subagent/commands/scout-and-plan.md +0 -9
- package/examples/custom-tools/subagent/index.ts +0 -1002
- package/examples/sdk/05-tools.ts +0 -94
- package/examples/sdk/12-full-control.ts +0 -95
- package/src/prompts/browser.md +0 -71
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate memorable two-word task identifiers.
|
|
3
|
+
* Format: AdjectiveNoun (e.g., "SwiftFalcon", "CalmPanda")
|
|
4
|
+
*
|
|
5
|
+
* Dictionaries sourced from unique-names-generator (MIT license).
|
|
6
|
+
* 1202 adjectives × 355 animals = 426,710 combinations.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const ADJECTIVES = [
|
|
10
|
+
"able", "above", "absent", "absolute", "abstract", "abundant", "academic", "acceptable",
|
|
11
|
+
"accepted", "accessible", "accurate", "accused", "active", "actual", "acute", "added",
|
|
12
|
+
"additional", "adequate", "adjacent", "administrative", "adorable", "advanced", "adverse",
|
|
13
|
+
"advisory", "aesthetic", "afraid", "aggregate", "aggressive", "agreeable", "agreed",
|
|
14
|
+
"agricultural", "alert", "alive", "alleged", "allied", "alone", "alright", "alternative",
|
|
15
|
+
"amateur", "amazing", "ambitious", "amused", "ancient", "angry", "annoyed", "annual",
|
|
16
|
+
"anonymous", "anxious", "appalling", "apparent", "applicable", "appropriate", "arbitrary",
|
|
17
|
+
"architectural", "armed", "arrogant", "artificial", "artistic", "ashamed", "asleep",
|
|
18
|
+
"assistant", "associated", "atomic", "attractive", "automatic", "autonomous", "available",
|
|
19
|
+
"average", "awake", "aware", "awful", "awkward", "back", "bad", "balanced", "bare", "basic",
|
|
20
|
+
"beautiful", "beneficial", "better", "bewildered", "big", "binding", "biological", "bitter",
|
|
21
|
+
"bizarre", "blank", "blind", "blonde", "bloody", "blushing", "boiling", "bold", "bored",
|
|
22
|
+
"boring", "bottom", "brainy", "brave", "breakable", "breezy", "brief", "bright", "brilliant",
|
|
23
|
+
"broad", "broken", "bumpy", "burning", "busy", "calm", "capable", "capitalist", "careful",
|
|
24
|
+
"casual", "causal", "cautious", "central", "certain", "changing", "characteristic", "charming",
|
|
25
|
+
"cheap", "cheerful", "chemical", "chief", "chilly", "chosen", "chronic", "chubby", "circular",
|
|
26
|
+
"civic", "civil", "civilian", "classic", "classical", "clean", "clear", "clever", "clinical",
|
|
27
|
+
"close", "closed", "cloudy", "clumsy", "coastal", "cognitive", "coherent", "cold", "collective",
|
|
28
|
+
"colonial", "colorful", "colossal", "coloured", "colourful", "combative", "combined",
|
|
29
|
+
"comfortable", "coming", "commercial", "common", "communist", "compact", "comparable",
|
|
30
|
+
"comparative", "compatible", "competent", "competitive", "complete", "complex", "complicated",
|
|
31
|
+
"comprehensive", "compulsory", "conceptual", "concerned", "concrete", "condemned", "confident",
|
|
32
|
+
"confidential", "confused", "conscious", "conservation", "conservative", "considerable",
|
|
33
|
+
"consistent", "constant", "constitutional", "contemporary", "content", "continental",
|
|
34
|
+
"continued", "continuing", "continuous", "controlled", "controversial", "convenient",
|
|
35
|
+
"conventional", "convinced", "convincing", "cooing", "cool", "cooperative", "corporate",
|
|
36
|
+
"correct", "corresponding", "costly", "courageous", "crazy", "creative", "creepy", "criminal",
|
|
37
|
+
"critical", "crooked", "crowded", "crucial", "crude", "cruel", "cuddly", "cultural", "curious",
|
|
38
|
+
"curly", "current", "curved", "cute", "daily", "damaged", "damp", "dangerous", "dark", "dead",
|
|
39
|
+
"deaf", "deafening", "dear", "decent", "decisive", "deep", "defeated", "defensive", "defiant",
|
|
40
|
+
"definite", "deliberate", "delicate", "delicious", "delighted", "delightful", "democratic",
|
|
41
|
+
"dependent", "depressed", "desirable", "desperate", "detailed", "determined", "developed",
|
|
42
|
+
"developing", "devoted", "different", "difficult", "digital", "diplomatic", "direct", "dirty",
|
|
43
|
+
"disabled", "disappointed", "disastrous", "disciplinary", "disgusted", "distant", "distinct",
|
|
44
|
+
"distinctive", "distinguished", "disturbed", "disturbing", "diverse", "divine", "dizzy",
|
|
45
|
+
"domestic", "dominant", "double", "doubtful", "drab", "dramatic", "dreadful", "driving",
|
|
46
|
+
"drunk", "dry", "dual", "due", "dull", "dusty", "dying", "dynamic", "eager", "early", "eastern",
|
|
47
|
+
"easy", "economic", "educational", "eerie", "effective", "efficient", "elaborate", "elated",
|
|
48
|
+
"elderly", "eldest", "electoral", "electric", "electrical", "electronic", "elegant", "eligible",
|
|
49
|
+
"embarrassed", "embarrassing", "emotional", "empirical", "empty", "enchanting", "encouraging",
|
|
50
|
+
"endless", "energetic", "enormous", "enthusiastic", "entire", "entitled", "envious",
|
|
51
|
+
"environmental", "equal", "equivalent", "essential", "established", "estimated", "ethical",
|
|
52
|
+
"ethnic", "eventual", "everyday", "evident", "evil", "evolutionary", "exact", "excellent",
|
|
53
|
+
"exceptional", "excess", "excessive", "excited", "exciting", "exclusive", "existing", "exotic",
|
|
54
|
+
"expected", "expensive", "experienced", "experimental", "explicit", "extended", "extensive",
|
|
55
|
+
"external", "extra", "extraordinary", "extreme", "exuberant", "faint", "fair", "faithful",
|
|
56
|
+
"familiar", "famous", "fancy", "fantastic", "far", "fascinating", "fashionable", "fast", "fat",
|
|
57
|
+
"fatal", "favourable", "favourite", "federal", "fellow", "female", "feminist", "few", "fierce",
|
|
58
|
+
"filthy", "final", "financial", "fine", "firm", "fiscal", "fit", "fixed", "flaky", "flat",
|
|
59
|
+
"flexible", "fluffy", "fluttering", "flying", "following", "fond", "foolish", "foreign",
|
|
60
|
+
"formal", "formidable", "forthcoming", "fortunate", "forward", "fragile", "frail", "frantic",
|
|
61
|
+
"free", "frequent", "fresh", "friendly", "frightened", "front", "frozen", "full", "fun",
|
|
62
|
+
"functional", "fundamental", "funny", "furious", "future", "fuzzy", "gastric", "gay", "general",
|
|
63
|
+
"generous", "genetic", "gentle", "genuine", "geographical", "giant", "gigantic", "given",
|
|
64
|
+
"glad", "glamorous", "gleaming", "global", "glorious", "golden", "good", "gorgeous", "gothic",
|
|
65
|
+
"governing", "graceful", "gradual", "grand", "grateful", "greasy", "great", "grieving", "grim",
|
|
66
|
+
"gross", "grotesque", "growing", "grubby", "grumpy", "guilty", "handicapped", "handsome",
|
|
67
|
+
"happy", "hard", "harsh", "head", "healthy", "heavy", "helpful", "helpless", "hidden", "high",
|
|
68
|
+
"hilarious", "hissing", "historic", "historical", "hollow", "holy", "homeless", "homely",
|
|
69
|
+
"honest", "horizontal", "horrible", "hostile", "hot", "huge", "human", "hungry", "hurt",
|
|
70
|
+
"hushed", "husky", "icy", "ideal", "identical", "ideological", "ill", "illegal", "imaginative",
|
|
71
|
+
"immediate", "immense", "imperial", "implicit", "important", "impossible", "impressed",
|
|
72
|
+
"impressive", "improved", "inadequate", "inappropriate", "inclined", "increased", "increasing",
|
|
73
|
+
"incredible", "independent", "indirect", "individual", "industrial", "inevitable", "influential",
|
|
74
|
+
"informal", "inherent", "initial", "injured", "inland", "inner", "innocent", "innovative",
|
|
75
|
+
"inquisitive", "instant", "institutional", "insufficient", "intact", "integral", "integrated",
|
|
76
|
+
"intellectual", "intelligent", "intense", "intensive", "interested", "interesting", "interim",
|
|
77
|
+
"interior", "intermediate", "internal", "international", "intimate", "invisible", "involved",
|
|
78
|
+
"irrelevant", "isolated", "itchy", "jealous", "jittery", "joint", "jolly", "joyous", "judicial",
|
|
79
|
+
"juicy", "junior", "just", "keen", "key", "kind", "known", "labour", "large", "late", "latin",
|
|
80
|
+
"lazy", "leading", "left", "legal", "legislative", "legitimate", "lengthy", "lesser", "level",
|
|
81
|
+
"lexical", "liable", "liberal", "light", "like", "likely", "limited", "linear", "linguistic",
|
|
82
|
+
"liquid", "literary", "little", "live", "lively", "living", "local", "logical", "lonely",
|
|
83
|
+
"long", "loose", "lost", "loud", "lovely", "low", "loyal", "lucky", "mad", "magic", "magnetic",
|
|
84
|
+
"magnificent", "main", "major", "male", "mammoth", "managerial", "managing", "manual", "many",
|
|
85
|
+
"marginal", "marine", "marked", "married", "marvellous", "marxist", "mass", "massive",
|
|
86
|
+
"mathematical", "mature", "maximum", "mean", "meaningful", "mechanical", "medical", "medieval",
|
|
87
|
+
"melodic", "melted", "mental", "mere", "metropolitan", "mid", "middle", "mighty", "mild",
|
|
88
|
+
"military", "miniature", "minimal", "minimum", "ministerial", "minor", "miserable", "misleading",
|
|
89
|
+
"missing", "misty", "mixed", "moaning", "mobile", "moderate", "modern", "modest", "molecular",
|
|
90
|
+
"monetary", "monthly", "moral", "motionless", "muddy", "multiple", "mushy", "musical", "mute",
|
|
91
|
+
"mutual", "mysterious", "naked", "narrow", "nasty", "national", "native", "natural", "naughty",
|
|
92
|
+
"naval", "near", "nearby", "neat", "necessary", "negative", "neighbouring", "nervous", "net",
|
|
93
|
+
"neutral", "new", "nice", "noble", "noisy", "normal", "northern", "nosy", "notable", "novel",
|
|
94
|
+
"nuclear", "numerous", "nursing", "nutritious", "nutty", "obedient", "objective", "obliged",
|
|
95
|
+
"obnoxious", "obvious", "occasional", "occupational", "odd", "official", "old", "olympic",
|
|
96
|
+
"only", "open", "operational", "opposite", "optimistic", "oral", "ordinary", "organic",
|
|
97
|
+
"organisational", "original", "orthodox", "other", "outdoor", "outer", "outrageous", "outside",
|
|
98
|
+
"outstanding", "overall", "overseas", "overwhelming", "painful", "pale", "panicky", "parallel",
|
|
99
|
+
"parental", "parliamentary", "partial", "particular", "passing", "passive", "past", "patient",
|
|
100
|
+
"payable", "peaceful", "peculiar", "perfect", "permanent", "persistent", "personal", "petite",
|
|
101
|
+
"philosophical", "physical", "plain", "planned", "plastic", "pleasant", "pleased", "poised",
|
|
102
|
+
"polite", "political", "poor", "popular", "positive", "possible", "potential", "powerful",
|
|
103
|
+
"practical", "precious", "precise", "preferred", "pregnant", "preliminary", "premier",
|
|
104
|
+
"prepared", "present", "presidential", "pretty", "previous", "prickly", "primary", "prime",
|
|
105
|
+
"primitive", "principal", "printed", "prior", "private", "probable", "productive", "professional",
|
|
106
|
+
"profitable", "profound", "progressive", "prominent", "promising", "proper", "proposed",
|
|
107
|
+
"prospective", "protective", "proud", "provincial", "psychiatric", "psychological", "public",
|
|
108
|
+
"puny", "pure", "purring", "puzzled", "quaint", "qualified", "quarrelsome", "querulous",
|
|
109
|
+
"quick", "quickest", "quiet", "quintessential", "quixotic", "racial", "radical", "rainy",
|
|
110
|
+
"random", "rapid", "rare", "raspy", "rational", "ratty", "raw", "ready", "real", "realistic",
|
|
111
|
+
"rear", "reasonable", "recent", "reduced", "redundant", "regional", "registered", "regular",
|
|
112
|
+
"regulatory", "related", "relative", "relaxed", "relevant", "reliable", "relieved", "religious",
|
|
113
|
+
"reluctant", "remaining", "remarkable", "remote", "renewed", "representative", "repulsive",
|
|
114
|
+
"required", "resident", "residential", "resonant", "respectable", "respective", "responsible",
|
|
115
|
+
"resulting", "retail", "retired", "revolutionary", "rich", "ridiculous", "right", "rigid",
|
|
116
|
+
"ripe", "rising", "rival", "roasted", "robust", "rolling", "romantic", "rotten", "rough",
|
|
117
|
+
"round", "royal", "rubber", "rude", "ruling", "running", "rural", "sacred", "sad", "safe",
|
|
118
|
+
"salty", "satisfactory", "satisfied", "scared", "scary", "scattered", "scientific", "scornful",
|
|
119
|
+
"scrawny", "screeching", "secondary", "secret", "secure", "select", "selected", "selective",
|
|
120
|
+
"selfish", "semantic", "senior", "sensible", "sensitive", "separate", "serious", "severe",
|
|
121
|
+
"sexual", "shaggy", "shaky", "shallow", "shared", "sharp", "sheer", "shiny", "shivering",
|
|
122
|
+
"shocked", "short", "shrill", "shy", "sick", "significant", "silent", "silky", "silly",
|
|
123
|
+
"similar", "simple", "single", "skilled", "skinny", "sleepy", "slight", "slim", "slimy",
|
|
124
|
+
"slippery", "slow", "small", "smart", "smiling", "smoggy", "smooth", "social", "socialist",
|
|
125
|
+
"soft", "solar", "sole", "solid", "sophisticated", "sore", "sorry", "sound", "sour", "southern",
|
|
126
|
+
"soviet", "spare", "sparkling", "spatial", "special", "specific", "specified", "spectacular",
|
|
127
|
+
"spicy", "spiritual", "splendid", "spontaneous", "sporting", "spotless", "spotty", "square",
|
|
128
|
+
"squealing", "stable", "stale", "standard", "static", "statistical", "statutory", "steady",
|
|
129
|
+
"steep", "sticky", "stiff", "still", "stingy", "stormy", "straight", "straightforward",
|
|
130
|
+
"strange", "strategic", "strict", "striking", "striped", "strong", "structural", "stuck",
|
|
131
|
+
"stupid", "subjective", "subsequent", "substantial", "subtle", "successful", "successive",
|
|
132
|
+
"sudden", "sufficient", "suitable", "sunny", "super", "superb", "superior", "supporting",
|
|
133
|
+
"supposed", "supreme", "sure", "surprised", "surprising", "surrounding", "surviving",
|
|
134
|
+
"suspicious", "sweet", "swift", "symbolic", "sympathetic", "systematic", "tall", "tame",
|
|
135
|
+
"tart", "tasteless", "tasty", "technical", "technological", "teenage", "temporary", "tender",
|
|
136
|
+
"tense", "terrible", "territorial", "testy", "theoretical", "thick", "thin", "thirsty",
|
|
137
|
+
"thorough", "thoughtful", "thoughtless", "thundering", "tight", "tiny", "tired", "top", "total",
|
|
138
|
+
"tough", "toxic", "traditional", "tragic", "tremendous", "tricky", "tropical", "troubled",
|
|
139
|
+
"typical", "ugliest", "ugly", "ultimate", "unable", "unacceptable", "unaware", "uncertain",
|
|
140
|
+
"unchanged", "uncomfortable", "unconscious", "underground", "underlying", "unemployed",
|
|
141
|
+
"uneven", "unexpected", "unfair", "unfortunate", "unhappy", "uniform", "uninterested", "unique",
|
|
142
|
+
"united", "universal", "unknown", "unlikely", "unnecessary", "unpleasant", "unsightly",
|
|
143
|
+
"unusual", "unwilling", "upper", "upset", "uptight", "urban", "urgent", "used", "useful",
|
|
144
|
+
"useless", "usual", "vague", "valid", "valuable", "variable", "varied", "various", "varying",
|
|
145
|
+
"vast", "verbal", "vertical", "vicarious", "vicious", "victorious", "violent", "visible",
|
|
146
|
+
"visiting", "visual", "vital", "vivacious", "vivid", "vocal", "vocational", "voiceless",
|
|
147
|
+
"voluminous", "voluntary", "vulnerable", "wandering", "warm", "wasteful", "watery", "weak",
|
|
148
|
+
"wealthy", "weary", "weekly", "weird", "welcome", "well", "western", "wet", "whispering",
|
|
149
|
+
"whole", "wicked", "wide", "widespread", "wild", "willing", "willowy", "wily", "wise", "wispy",
|
|
150
|
+
"witty", "wonderful", "wooden", "working", "worldwide", "worried", "worrying", "worthwhile",
|
|
151
|
+
"worthy", "written", "wrong", "xenial", "xeric", "yawning", "yearning", "young", "youngest",
|
|
152
|
+
"youthful", "zany", "zealous", "zesty", "zippy",
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
const NOUNS = [
|
|
156
|
+
"aardvark", "aardwolf", "albatross", "alligator", "alpaca", "amphibian", "anaconda",
|
|
157
|
+
"angelfish", "anglerfish", "ant", "anteater", "antelope", "antlion", "ape", "aphid",
|
|
158
|
+
"armadillo", "asp", "baboon", "badger", "bandicoot", "barnacle", "barracuda", "basilisk",
|
|
159
|
+
"bass", "bat", "bear", "beaver", "bedbug", "bee", "beetle", "bird", "bison", "blackbird",
|
|
160
|
+
"boa", "boar", "bobcat", "bobolink", "bonobo", "booby", "bovid", "bug", "butterfly", "buzzard",
|
|
161
|
+
"camel", "canid", "capybara", "cardinal", "caribou", "carp", "cat", "caterpillar", "catfish",
|
|
162
|
+
"catshark", "cattle", "centipede", "cephalopod", "chameleon", "cheetah", "chickadee", "chicken",
|
|
163
|
+
"chimpanzee", "chinchilla", "chipmunk", "cicada", "clam", "clownfish", "cobra", "cockroach",
|
|
164
|
+
"cod", "condor", "constrictor", "coral", "cougar", "cow", "coyote", "crab", "crane", "crawdad",
|
|
165
|
+
"crayfish", "cricket", "crocodile", "crow", "cuckoo", "damselfly", "deer", "dingo", "dinosaur",
|
|
166
|
+
"dog", "dolphin", "donkey", "dormouse", "dove", "dragon", "dragonfly", "duck", "eagle",
|
|
167
|
+
"earthworm", "earwig", "echidna", "eel", "egret", "elephant", "elk", "emu", "ermine", "falcon",
|
|
168
|
+
"ferret", "finch", "firefly", "fish", "flamingo", "flea", "fly", "flyingfish", "fowl", "fox",
|
|
169
|
+
"frog", "gamefowl", "gazelle", "gecko", "gerbil", "gibbon", "giraffe", "goat", "goldfish",
|
|
170
|
+
"goose", "gopher", "gorilla", "grasshopper", "grouse", "guan", "guanaco", "guineafowl", "gull",
|
|
171
|
+
"guppy", "haddock", "halibut", "hamster", "hare", "harrier", "hawk", "hedgehog", "heron",
|
|
172
|
+
"herring", "hippopotamus", "hookworm", "hornet", "horse", "hoverfly", "hummingbird", "hyena",
|
|
173
|
+
"iguana", "impala", "jackal", "jaguar", "jay", "jellyfish", "kangaroo", "kingfisher", "kite",
|
|
174
|
+
"kiwi", "koala", "koi", "krill", "ladybug", "lamprey", "lark", "leech", "lemming", "lemur",
|
|
175
|
+
"leopard", "leopon", "limpet", "lion", "lizard", "llama", "lobster", "locust", "loon", "louse",
|
|
176
|
+
"lungfish", "lynx", "macaw", "mackerel", "magpie", "mammal", "manatee", "mandrill", "marlin",
|
|
177
|
+
"marmoset", "marmot", "marsupial", "marten", "mastodon", "meadowlark", "meerkat", "mink",
|
|
178
|
+
"minnow", "mite", "mockingbird", "mole", "mollusk", "mongoose", "monkey", "moose", "mosquito",
|
|
179
|
+
"moth", "mouse", "mule", "muskox", "narwhal", "newt", "nightingale", "ocelot", "octopus",
|
|
180
|
+
"opossum", "orangutan", "orca", "ostrich", "otter", "owl", "ox", "panda", "panther", "parakeet",
|
|
181
|
+
"parrot", "parrotfish", "partridge", "peacock", "peafowl", "pelican", "penguin", "perch",
|
|
182
|
+
"pheasant", "pig", "pigeon", "pike", "pinniped", "piranha", "planarian", "platypus", "pony",
|
|
183
|
+
"porcupine", "porpoise", "possum", "prawn", "primate", "ptarmigan", "puffin", "puma", "python",
|
|
184
|
+
"quail", "quelea", "quokka", "rabbit", "raccoon", "rat", "rattlesnake", "raven", "reindeer",
|
|
185
|
+
"reptile", "rhinoceros", "roadrunner", "rodent", "rook", "rooster", "roundworm", "sailfish",
|
|
186
|
+
"salamander", "salmon", "sawfish", "scallop", "scorpion", "seahorse", "shark", "sheep", "shrew",
|
|
187
|
+
"shrimp", "silkworm", "silverfish", "skink", "skunk", "sloth", "slug", "smelt", "snail",
|
|
188
|
+
"snake", "snipe", "sole", "sparrow", "spider", "spoonbill", "squid", "squirrel", "starfish",
|
|
189
|
+
"stingray", "stoat", "stork", "sturgeon", "swallow", "swan", "swift", "swordfish", "swordtail",
|
|
190
|
+
"tahr", "takin", "tapir", "tarantula", "tarsier", "termite", "tern", "thrush", "tick", "tiger",
|
|
191
|
+
"tiglon", "toad", "tortoise", "toucan", "trout", "tuna", "turkey", "turtle", "tyrannosaurus",
|
|
192
|
+
"unicorn", "urial", "vicuna", "viper", "vole", "vulture", "wallaby", "walrus", "warbler",
|
|
193
|
+
"wasp", "weasel", "whale", "whippet", "whitefish", "wildcat", "wildebeest", "wildfowl", "wolf",
|
|
194
|
+
"wolverine", "wombat", "woodpecker", "worm", "wren", "yak", "zebra",
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
function capitalize(s: string): string {
|
|
198
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
let usedNames = new Set<string>();
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Generate a unique two-word identifier (e.g., "SwiftFalcon").
|
|
205
|
+
* Falls back to numeric suffix if all combinations exhausted.
|
|
206
|
+
*/
|
|
207
|
+
export function generateTaskName(): string {
|
|
208
|
+
// Try random combinations first (50 attempts)
|
|
209
|
+
for (let attempt = 0; attempt < 50; attempt++) {
|
|
210
|
+
const adj = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
|
|
211
|
+
const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
|
|
212
|
+
const name = `${capitalize(adj)}${capitalize(noun)}`;
|
|
213
|
+
if (!usedNames.has(name)) {
|
|
214
|
+
usedNames.add(name);
|
|
215
|
+
return name;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Exhaustive search if random fails
|
|
220
|
+
for (const adj of ADJECTIVES) {
|
|
221
|
+
for (const noun of NOUNS) {
|
|
222
|
+
const name = `${capitalize(adj)}${capitalize(noun)}`;
|
|
223
|
+
if (!usedNames.has(name)) {
|
|
224
|
+
usedNames.add(name);
|
|
225
|
+
return name;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// All 426k combinations used, add numeric suffix
|
|
231
|
+
let counter = 0;
|
|
232
|
+
while (true) {
|
|
233
|
+
const name = `Task${counter}`;
|
|
234
|
+
if (!usedNames.has(name)) {
|
|
235
|
+
usedNames.add(name);
|
|
236
|
+
return name;
|
|
237
|
+
}
|
|
238
|
+
counter++;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Reset name generator state (for testing).
|
|
244
|
+
*/
|
|
245
|
+
export function resetTaskNames(): void {
|
|
246
|
+
usedNames = new Set<string>();
|
|
247
|
+
}
|
|
@@ -69,6 +69,118 @@ function formatFindingSummary(findings: ReportFindingDetails[], theme: Theme): s
|
|
|
69
69
|
return `${theme.fg("dim", "Findings:")} ${parts.join(theme.sep.dot)}`;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
function formatJsonScalar(value: unknown): string {
|
|
73
|
+
if (value === null) return "null";
|
|
74
|
+
if (typeof value === "string") return `"${value}"`;
|
|
75
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
76
|
+
return "";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildTreePrefix(ancestors: boolean[], theme: Theme): string {
|
|
80
|
+
return ancestors.map((hasNext) => (hasNext ? `${theme.tree.vertical} ` : " ")).join("");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function renderJsonTreeLines(
|
|
84
|
+
value: unknown,
|
|
85
|
+
theme: Theme,
|
|
86
|
+
maxDepth: number,
|
|
87
|
+
maxLines: number,
|
|
88
|
+
): { lines: string[]; truncated: boolean } {
|
|
89
|
+
const lines: string[] = [];
|
|
90
|
+
let truncated = false;
|
|
91
|
+
|
|
92
|
+
const iconObject = theme.styledSymbol("icon.folder", "muted");
|
|
93
|
+
const iconArray = theme.styledSymbol("icon.package", "muted");
|
|
94
|
+
const iconScalar = theme.styledSymbol("icon.file", "muted");
|
|
95
|
+
|
|
96
|
+
const pushLine = (line: string) => {
|
|
97
|
+
if (lines.length >= maxLines) {
|
|
98
|
+
truncated = true;
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
lines.push(line);
|
|
102
|
+
return true;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const renderNode = (val: unknown, key: string | undefined, ancestors: boolean[], isLast: boolean, depth: number) => {
|
|
106
|
+
if (lines.length >= maxLines) {
|
|
107
|
+
truncated = true;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const connector = isLast ? theme.tree.last : theme.tree.branch;
|
|
112
|
+
const prefix = `${buildTreePrefix(ancestors, theme)}${theme.fg("dim", connector)} `;
|
|
113
|
+
const scalar = formatJsonScalar(val);
|
|
114
|
+
|
|
115
|
+
if (scalar) {
|
|
116
|
+
const label = key ? theme.fg("muted", key) : theme.fg("muted", "value");
|
|
117
|
+
pushLine(`${prefix}${iconScalar} ${label}: ${theme.fg("dim", scalar)}`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (Array.isArray(val)) {
|
|
122
|
+
const header = key ? theme.fg("muted", key) : theme.fg("muted", "array");
|
|
123
|
+
pushLine(`${prefix}${iconArray} ${header}`);
|
|
124
|
+
if (val.length === 0) {
|
|
125
|
+
pushLine(
|
|
126
|
+
`${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.hook)} ${theme.fg("dim", "[]")}`,
|
|
127
|
+
);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (depth >= maxDepth) {
|
|
131
|
+
pushLine(
|
|
132
|
+
`${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.hook)} ${theme.fg("dim", theme.format.ellipsis)}`,
|
|
133
|
+
);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const nextAncestors = [...ancestors, !isLast];
|
|
137
|
+
for (let i = 0; i < val.length; i++) {
|
|
138
|
+
renderNode(val[i], `[${i}]`, nextAncestors, i === val.length - 1, depth + 1);
|
|
139
|
+
if (lines.length >= maxLines) {
|
|
140
|
+
truncated = true;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (val && typeof val === "object") {
|
|
148
|
+
const header = key ? theme.fg("muted", key) : theme.fg("muted", "object");
|
|
149
|
+
pushLine(`${prefix}${iconObject} ${header}`);
|
|
150
|
+
const entries = Object.entries(val as Record<string, unknown>);
|
|
151
|
+
if (entries.length === 0) {
|
|
152
|
+
pushLine(
|
|
153
|
+
`${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.hook)} ${theme.fg("dim", "{}")}`,
|
|
154
|
+
);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (depth >= maxDepth) {
|
|
158
|
+
pushLine(
|
|
159
|
+
`${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.hook)} ${theme.fg("dim", theme.format.ellipsis)}`,
|
|
160
|
+
);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const nextAncestors = [...ancestors, !isLast];
|
|
164
|
+
for (let i = 0; i < entries.length; i++) {
|
|
165
|
+
const [childKey, child] = entries[i];
|
|
166
|
+
renderNode(child, childKey, nextAncestors, i === entries.length - 1, depth + 1);
|
|
167
|
+
if (lines.length >= maxLines) {
|
|
168
|
+
truncated = true;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const label = key ? theme.fg("muted", key) : theme.fg("muted", "value");
|
|
176
|
+
pushLine(`${prefix}${iconScalar} ${label}: ${theme.fg("dim", String(val))}`);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
renderNode(value, undefined, [], true, 0);
|
|
180
|
+
|
|
181
|
+
return { lines, truncated };
|
|
182
|
+
}
|
|
183
|
+
|
|
72
184
|
function renderOutputSection(
|
|
73
185
|
output: string,
|
|
74
186
|
continuePrefix: string,
|
|
@@ -78,11 +190,30 @@ function renderOutputSection(
|
|
|
78
190
|
maxExpanded = 10,
|
|
79
191
|
): string[] {
|
|
80
192
|
const lines: string[] = [];
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
193
|
+
const trimmedOutput = output.trim();
|
|
194
|
+
if (!trimmedOutput) return lines;
|
|
83
195
|
|
|
84
196
|
lines.push(`${continuePrefix}${theme.fg("dim", "Output")}`);
|
|
85
197
|
|
|
198
|
+
if (trimmedOutput.startsWith("{") || trimmedOutput.startsWith("[")) {
|
|
199
|
+
try {
|
|
200
|
+
const parsed = JSON.parse(trimmedOutput);
|
|
201
|
+
const tree = renderJsonTreeLines(parsed, theme, expanded ? 6 : 2, expanded ? 24 : 6);
|
|
202
|
+
if (tree.lines.length > 0) {
|
|
203
|
+
for (const line of tree.lines) {
|
|
204
|
+
lines.push(`${continuePrefix} ${line}`);
|
|
205
|
+
}
|
|
206
|
+
if (tree.truncated) {
|
|
207
|
+
lines.push(`${continuePrefix} ${theme.fg("dim", theme.format.ellipsis)}`);
|
|
208
|
+
}
|
|
209
|
+
return lines;
|
|
210
|
+
}
|
|
211
|
+
} catch {
|
|
212
|
+
// Fall back to raw output
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const outputLines = output.split("\n").filter((line) => line.trim());
|
|
86
217
|
const previewCount = expanded ? maxExpanded : maxCollapsed;
|
|
87
218
|
for (const line of outputLines.slice(0, previewCount)) {
|
|
88
219
|
lines.push(`${continuePrefix} ${theme.fg("dim", truncate(line, 70, theme.format.ellipsis))}`);
|
|
@@ -144,9 +275,8 @@ function renderAgentProgress(
|
|
|
144
275
|
? "error"
|
|
145
276
|
: "accent";
|
|
146
277
|
|
|
147
|
-
// Main status line -
|
|
148
|
-
|
|
149
|
-
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", agentId)}`;
|
|
278
|
+
// Main status line - use taskId for Output tool
|
|
279
|
+
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", progress.taskId)}`;
|
|
150
280
|
const description = progress.description?.trim();
|
|
151
281
|
if (description) {
|
|
152
282
|
statusLine += ` ${theme.fg("muted", truncate(description, 40, theme.format.ellipsis))}`;
|
|
@@ -181,19 +311,29 @@ function renderAgentProgress(
|
|
|
181
311
|
|
|
182
312
|
lines.push(statusLine);
|
|
183
313
|
|
|
184
|
-
// Current tool (if running)
|
|
185
|
-
if (progress.status === "running"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
314
|
+
// Current tool (if running) or most recent completed tool
|
|
315
|
+
if (progress.status === "running") {
|
|
316
|
+
if (progress.currentTool) {
|
|
317
|
+
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("muted", progress.currentTool)}`;
|
|
318
|
+
if (progress.currentToolArgs) {
|
|
319
|
+
toolLine += `: ${theme.fg("dim", truncate(progress.currentToolArgs, 40, theme.format.ellipsis))}`;
|
|
320
|
+
}
|
|
321
|
+
if (progress.currentToolStartMs) {
|
|
322
|
+
const elapsed = Date.now() - progress.currentToolStartMs;
|
|
323
|
+
if (elapsed > 5000) {
|
|
324
|
+
toolLine += `${theme.sep.dot}${theme.fg("warning", formatDuration(elapsed))}`;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
lines.push(toolLine);
|
|
328
|
+
} else if (progress.recentTools.length > 0) {
|
|
329
|
+
// Show most recent completed tool when idle between tools
|
|
330
|
+
const recent = progress.recentTools[0];
|
|
331
|
+
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("dim", recent.tool)}`;
|
|
332
|
+
if (recent.args) {
|
|
333
|
+
toolLine += `: ${theme.fg("dim", truncate(recent.args, 40, theme.format.ellipsis))}`;
|
|
194
334
|
}
|
|
335
|
+
lines.push(toolLine);
|
|
195
336
|
}
|
|
196
|
-
lines.push(toolLine);
|
|
197
337
|
}
|
|
198
338
|
|
|
199
339
|
// Render extracted tool data inline (e.g., review findings)
|
|
@@ -332,9 +472,8 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
332
472
|
const iconColor = success ? "success" : "error";
|
|
333
473
|
const statusText = aborted ? "aborted" : success ? "done" : "failed";
|
|
334
474
|
|
|
335
|
-
// Main status line -
|
|
336
|
-
|
|
337
|
-
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", agentId)} ${formatBadge(statusText, iconColor, theme)}`;
|
|
475
|
+
// Main status line - use taskId for Output tool
|
|
476
|
+
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", result.taskId)} ${formatBadge(statusText, iconColor, theme)}`;
|
|
338
477
|
const description = result.description?.trim();
|
|
339
478
|
if (description) {
|
|
340
479
|
statusLine += ` ${theme.fg("muted", truncate(description, 40, theme.format.ellipsis))}`;
|
|
@@ -19,14 +19,11 @@ export const MAX_OUTPUT_LINES = 5000;
|
|
|
19
19
|
/** Maximum agents to show in description */
|
|
20
20
|
export const MAX_AGENTS_IN_DESCRIPTION = 10;
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
export const
|
|
22
|
+
/** EventBus channel for raw subagent events */
|
|
23
|
+
export const TASK_SUBAGENT_EVENT_CHANNEL = "task:subagent:event";
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
export const
|
|
27
|
-
|
|
28
|
-
/** Environment variable containing allowed spawn list (propagated to subprocesses) */
|
|
29
|
-
export const OMP_SPAWNS_ENV = "OMP_SPAWNS";
|
|
25
|
+
/** EventBus channel for aggregated subagent progress */
|
|
26
|
+
export const TASK_SUBAGENT_PROGRESS_CHANNEL = "task:subagent:progress";
|
|
30
27
|
|
|
31
28
|
/** Single task item for parallel execution */
|
|
32
29
|
export const taskItemSchema = Type.Object({
|
|
@@ -41,6 +38,11 @@ export type TaskItem = Static<typeof taskItemSchema>;
|
|
|
41
38
|
/** Task tool parameters */
|
|
42
39
|
export const taskSchema = Type.Object({
|
|
43
40
|
context: Type.Optional(Type.String({ description: "Shared context prepended to all task prompts" })),
|
|
41
|
+
output_schema: Type.Optional(
|
|
42
|
+
Type.Any({
|
|
43
|
+
description: "JSON schema for structured subagent output (used by the complete tool)",
|
|
44
|
+
}),
|
|
45
|
+
),
|
|
44
46
|
tasks: Type.Array(taskItemSchema, {
|
|
45
47
|
description: "Tasks to run in parallel",
|
|
46
48
|
maxItems: MAX_PARALLEL_TASKS,
|
|
@@ -81,7 +83,6 @@ export interface AgentDefinition {
|
|
|
81
83
|
tools?: string[];
|
|
82
84
|
spawns?: string[] | "*";
|
|
83
85
|
model?: string;
|
|
84
|
-
recursive?: boolean;
|
|
85
86
|
source: AgentSource;
|
|
86
87
|
filePath?: string;
|
|
87
88
|
}
|
|
@@ -89,6 +90,7 @@ export interface AgentDefinition {
|
|
|
89
90
|
/** Progress tracking for a single agent */
|
|
90
91
|
export interface AgentProgress {
|
|
91
92
|
index: number;
|
|
93
|
+
taskId: string;
|
|
92
94
|
agent: string;
|
|
93
95
|
agentSource: AgentSource;
|
|
94
96
|
status: "pending" | "running" | "completed" | "failed" | "aborted";
|
|
@@ -110,6 +112,7 @@ export interface AgentProgress {
|
|
|
110
112
|
/** Result from a single agent execution */
|
|
111
113
|
export interface SingleResult {
|
|
112
114
|
index: number;
|
|
115
|
+
taskId: string;
|
|
113
116
|
agent: string;
|
|
114
117
|
agentSource: AgentSource;
|
|
115
118
|
task: string;
|
|
@@ -123,10 +126,9 @@ export interface SingleResult {
|
|
|
123
126
|
modelOverride?: string;
|
|
124
127
|
error?: string;
|
|
125
128
|
aborted?: boolean;
|
|
126
|
-
|
|
127
|
-
artifactPaths?: { inputPath: string; outputPath: string; jsonlPath?: string };
|
|
128
|
-
/** Aggregated usage from the subprocess, if available. */
|
|
129
|
+
/** Aggregated usage from the subprocess, accumulated incrementally from message_end events. */
|
|
129
130
|
usage?: Usage;
|
|
131
|
+
artifactPaths?: { inputPath: string; outputPath: string; jsonlPath?: string };
|
|
130
132
|
/** Data extracted by registered subprocess tool handlers (keyed by tool name) */
|
|
131
133
|
extractedToolData?: Record<string, unknown[]>;
|
|
132
134
|
/** Output metadata for Output tool integration */
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentEvent } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
|
|
3
|
+
export interface SubagentWorkerStartPayload {
|
|
4
|
+
cwd: string;
|
|
5
|
+
task: string;
|
|
6
|
+
systemPrompt: string;
|
|
7
|
+
model?: string;
|
|
8
|
+
toolNames?: string[];
|
|
9
|
+
outputSchema?: unknown;
|
|
10
|
+
sessionFile?: string | null;
|
|
11
|
+
spawnsEnv?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type SubagentWorkerRequest = { type: "start"; payload: SubagentWorkerStartPayload } | { type: "abort" };
|
|
15
|
+
|
|
16
|
+
export type SubagentWorkerResponse =
|
|
17
|
+
| { type: "event"; event: AgentEvent }
|
|
18
|
+
| { type: "done"; exitCode: number; durationMs: number; error?: string; aborted?: boolean };
|