@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.
- package/.beads/issues.jsonl +0 -0
- package/.beads/sync-state.json +7 -0
- package/CHANGELOG.md +23 -0
- package/README.md +6 -0
- package/extensions/overstory.ts +230 -0
- package/package.json +2 -2
|
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
|
[](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
|
+
"version": "4.1.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "pi agent skills
|
|
5
|
+
"description": "pi agent skills & extensions: run-in-tmux, parrot, mulch, overstory",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"pi",
|
|
8
8
|
"pi-coding-agent",
|