@normful/picadillo 3.0.0 → 4.1.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.
File without changes
@@ -0,0 +1,7 @@
1
+ {
2
+ "last_failure": "2026-02-18T01:49:04.979785+09:00",
3
+ "failure_count": 1,
4
+ "backoff_until": "2026-02-18T01:49:34.979785+09:00",
5
+ "needs_manual_sync": false,
6
+ "failure_reason": "git pull failed: exit status 128\nFrom github.com:normful/picadillo\n * branch main -\u003e FETCH_HEAD\nhint: You have divergent branches and need to specify how to reconcile them.\nhint: You can do so by running one of the following commands sometime before\nhint: your next pull:\nhint:\nhint: git config pull.rebase false # merge\nhint: git config pull.rebase true # rebase\nhint: git config pull.ff only # fast-forward only\nhint:\nhint: You can replace \"git config\" with \"git config --global\" to set a default\nhint: preference for all repositories. You can also pass --rebase, --no-rebase,\nhint: or --ff-only on the command line to override the configured default per\nhint: invocation.\nfatal: Need to specify how to reconcile divergent branches.\n"
7
+ }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## [4.1.0] - 2026-02-17
2
+
3
+ ### 🚀 Features
4
+
5
+ - *(overstory)* Ensure extension runs only in an Overstory git repository
6
+ ## [4.0.0] - 2026-02-17
7
+
8
+ ### 🚀 Features
9
+
10
+ - *(extension)* Add overstory extension boilerplate and logic
11
+
12
+ ### 📚 Documentation
13
+
14
+ - Add overstory extension to README
15
+
16
+ ### ⚙️ Miscellaneous Tasks
17
+
18
+ - Shorten package.json description, fix overstory repo URL
19
+ - Release 4.0.0
1
20
  ## [3.0.0] - 2026-02-17
2
21
 
3
22
  ### 🚀 Features
@@ -12,6 +31,10 @@
12
31
  ### 📚 Documentation
13
32
 
14
33
  - Update README with reorganized skills and extensions sections
34
+
35
+ ### ⚙️ Miscellaneous Tasks
36
+
37
+ - Release 3.0.0
15
38
  ## [2.0.3] - 2026-02-16
16
39
 
17
40
  ### 📚 Documentation
package/README.md CHANGED
@@ -67,6 +67,12 @@ Hooks to automatically run `gt prime` and `gt mail` from [gastown](https://githu
67
67
  Hooks to automatically run [mulch](https://github.com/jayminwest/mulch) for
68
68
  recording and retrieving structured project learnings.
69
69
 
70
+ ### overstory
71
+
72
+ Hooks to automatically run `overstory prime` and `overstory mail check` from
73
+ [overstory](https://github.com/jayminwest/overstory/), along with logging tool
74
+ start/end, session end events, and integration with mulch for learning.
75
+
70
76
  ## Parrot Extension Demo
71
77
 
72
78
  [![asciicast](https://asciinema.org/a/788693.svg)](https://asciinema.org/a/788693)
@@ -0,0 +1,230 @@
1
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
+ import type { ExecResult } from "@mariozechner/pi-coding-agent";
3
+
4
+ export type { ExecResult };
5
+ export const OVERSTORY_MESSAGE_TYPE = "overstory";
6
+
7
+ export async function overstoryPrime(
8
+ execFn: ExtensionAPI["exec"],
9
+ forCompact = false,
10
+ ): Promise<string> {
11
+ let primeText = "";
12
+ try {
13
+ const { stdout } = await execFn("overstory", [
14
+ "prime",
15
+ "--agent",
16
+ "orchestrator",
17
+ ...(forCompact ? ["--compact"] : []),
18
+ ]);
19
+ primeText = stdout;
20
+ } catch (e) {
21
+ console.error("overstory prime failed:", e);
22
+ }
23
+ return primeText;
24
+ }
25
+
26
+ export async function overstoryMailCheck(
27
+ execFn: ExtensionAPI["exec"],
28
+ ): Promise<string> {
29
+ let mailText = "";
30
+ try {
31
+ const { stdout } = await execFn("overstory", [
32
+ "mail",
33
+ "check",
34
+ "--inject",
35
+ "--agent",
36
+ "orchestrator",
37
+ ]);
38
+ mailText = stdout;
39
+ } catch (e) {
40
+ console.error("overstory mail check failed:", e);
41
+ }
42
+ return mailText;
43
+ }
44
+
45
+ export async function logToolStart(
46
+ execFn: ExtensionAPI["exec"],
47
+ toolName: string,
48
+ ): Promise<void> {
49
+ try {
50
+ await execFn("overstory", [
51
+ "log",
52
+ "tool-start",
53
+ "--agent",
54
+ "orchestrator",
55
+ "--tool-name",
56
+ toolName,
57
+ ]);
58
+ } catch (e) {
59
+ console.error("overstory log tool-start failed:", e);
60
+ }
61
+ }
62
+
63
+ export async function logToolEnd(
64
+ execFn: ExtensionAPI["exec"],
65
+ toolName: string,
66
+ ): Promise<void> {
67
+ try {
68
+ await execFn("overstory", [
69
+ "log",
70
+ "tool-end",
71
+ "--agent",
72
+ "orchestrator",
73
+ "--tool-name",
74
+ toolName,
75
+ ]);
76
+ } catch (e) {
77
+ console.error("overstory log tool-end failed:", e);
78
+ }
79
+ }
80
+
81
+ export async function logSessionEnd(
82
+ execFn: ExtensionAPI["exec"],
83
+ ): Promise<void> {
84
+ try {
85
+ await execFn("overstory", [
86
+ "log",
87
+ "session-end",
88
+ "--agent",
89
+ "orchestrator",
90
+ ]);
91
+ } catch (e) {
92
+ console.error("overstory log session-end failed:", e);
93
+ }
94
+ }
95
+
96
+ export async function mulchLearn(
97
+ execFn: ExtensionAPI["exec"],
98
+ ): Promise<string> {
99
+ let primeText = "";
100
+ try {
101
+ const { stdout } = await execFn("mulch", ["learn"]);
102
+ primeText = stdout;
103
+ } catch (e) {
104
+ console.error("mulch learn failed:", e);
105
+ }
106
+ return primeText;
107
+ }
108
+
109
+ export async function handleSessionStart(
110
+ execFn: ExtensionAPI["exec"],
111
+ sendMessage: ExtensionAPI["sendMessage"],
112
+ ): Promise<void> {
113
+ const primeText = await overstoryPrime(execFn);
114
+ if (!primeText) return;
115
+
116
+ const mailText = await overstoryMailCheck(execFn);
117
+ sendMessage(
118
+ {
119
+ customType: OVERSTORY_MESSAGE_TYPE,
120
+ content: primeText + "\n\n" + mailText,
121
+ display: true,
122
+ },
123
+ {
124
+ deliverAs: "followUp",
125
+ triggerTurn: true,
126
+ },
127
+ );
128
+ }
129
+
130
+ export function handleBeforeAgentStart(mailText: string) {
131
+ return {
132
+ message: {
133
+ customType: OVERSTORY_MESSAGE_TYPE,
134
+ content: mailText,
135
+ display: true,
136
+ },
137
+ };
138
+ }
139
+
140
+ export async function handleToolExecutionEnd(
141
+ execFn: ExtensionAPI["exec"],
142
+ event: { toolName: string },
143
+ ): Promise<void> {
144
+ logToolEnd(execFn, event.toolName);
145
+ }
146
+
147
+ export async function handleToolExecutionStart(
148
+ execFn: ExtensionAPI["exec"],
149
+ event: { toolName: string },
150
+ ): Promise<void> {
151
+ logToolStart(execFn, event.toolName);
152
+ }
153
+
154
+ export async function handleSessionCompact(
155
+ execFn: ExtensionAPI["exec"],
156
+ sendMessage: ExtensionAPI["sendMessage"],
157
+ ): Promise<void> {
158
+ const primeText = await overstoryPrime(execFn, true);
159
+ if (!primeText) return;
160
+
161
+ sendMessage(
162
+ {
163
+ customType: OVERSTORY_MESSAGE_TYPE,
164
+ content: primeText,
165
+ display: true,
166
+ },
167
+ {
168
+ deliverAs: "followUp",
169
+ triggerTurn: true,
170
+ },
171
+ );
172
+ }
173
+
174
+ export async function handleSessionShutdown(
175
+ execFn: ExtensionAPI["exec"],
176
+ ): Promise<void> {
177
+ await Promise.all([logSessionEnd(execFn), mulchLearn(execFn)]);
178
+ }
179
+
180
+ export async function isOverstoryRepo(
181
+ execFn: ExtensionAPI["exec"],
182
+ ): Promise<boolean> {
183
+ try {
184
+ // Get the git repo root directory (fails if not in a git repo)
185
+ const gitRootResult = await execFn("git", ["rev-parse", "--show-toplevel"]);
186
+ const gitRoot = gitRootResult.stdout.trim();
187
+
188
+ // Check if .overstory directory exists in the git repo root
189
+ const overstoryDirResult = await execFn("ls", ["-d", `${gitRoot}/.overstory`]);
190
+ if (overstoryDirResult.code !== 0) {
191
+ return false; // No .overstory directory
192
+ }
193
+ return true;
194
+ } catch (e) {
195
+ return false; // Not in a git repo or other error
196
+ }
197
+ }
198
+
199
+ export default async function (pi: ExtensionAPI) {
200
+ if (!(await isOverstoryRepo(pi.exec))) {
201
+ return;
202
+ }
203
+
204
+ pi.on("session_start", async (_event, _ctx) => {
205
+ await handleSessionStart(pi.exec, pi.sendMessage);
206
+ });
207
+
208
+ pi.on("before_agent_start", async (_event, _ctx) => {
209
+ const mailText = await overstoryMailCheck(pi.exec);
210
+ return handleBeforeAgentStart(mailText);
211
+ });
212
+
213
+ pi.on("tool_execution_end", async (event, _ctx) => {
214
+ // Fire-and-forget: don't await, let it run in background
215
+ void handleToolExecutionEnd(pi.exec, event);
216
+ });
217
+
218
+ pi.on("tool_execution_start", async (event, _ctx) => {
219
+ // Fire-and-forget: don't await, let it run in background
220
+ void handleToolExecutionStart(pi.exec, event);
221
+ });
222
+
223
+ pi.on("session_compact", async (_event, _ctx) => {
224
+ await handleSessionCompact(pi.exec, pi.sendMessage);
225
+ });
226
+
227
+ pi.on("session_shutdown", async (_event, _ctx) => {
228
+ await handleSessionShutdown(pi.exec);
229
+ });
230
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@normful/picadillo",
3
- "version": "3.0.0",
3
+ "version": "4.1.0",
4
4
  "private": false,
5
- "description": "pi agent skills/extensions: run-in-tmux, parrot (send AI message with edited version of AI message)",
5
+ "description": "pi agent skills & extensions: run-in-tmux, parrot, mulch, overstory",
6
6
  "keywords": [
7
7
  "pi",
8
8
  "pi-coding-agent",