micode 0.8.0 → 0.8.2
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/package.json +1 -1
- package/src/agents/brainstormer.ts +21 -7
- package/src/hooks/auto-compact.ts +48 -2
package/package.json
CHANGED
|
@@ -32,6 +32,7 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
|
|
|
32
32
|
<subagent name="codebase-analyzer">Deep analysis of specific modules.</subagent>
|
|
33
33
|
<subagent name="pattern-finder">Find existing patterns in codebase.</subagent>
|
|
34
34
|
<subagent name="planner">Creates detailed implementation plan from validated design.</subagent>
|
|
35
|
+
<subagent name="executor">Executes implementation plan with implementer/reviewer cycles.</subagent>
|
|
35
36
|
</available-subagents>
|
|
36
37
|
|
|
37
38
|
<process>
|
|
@@ -87,14 +88,27 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
|
|
|
87
88
|
)
|
|
88
89
|
</spawn>
|
|
89
90
|
<rule>Do NOT ask again - if user approved, spawn planner immediately</rule>
|
|
90
|
-
<after-
|
|
91
|
-
<action>Report
|
|
92
|
-
<action>
|
|
91
|
+
<after-planner>
|
|
92
|
+
<action>Report: "Implementation plan created at thoughts/shared/plans/YYYY-MM-DD-{topic}.md"</action>
|
|
93
|
+
<action>Ask user: "Ready to execute the plan?"</action>
|
|
94
|
+
<rule>Wait for user response before proceeding</rule>
|
|
95
|
+
</after-planner>
|
|
96
|
+
</phase>
|
|
97
|
+
|
|
98
|
+
<phase name="execution" trigger="user approves execution">
|
|
99
|
+
<action>When user says yes/execute/go, spawn the executor:</action>
|
|
100
|
+
<spawn>
|
|
101
|
+
Task(
|
|
102
|
+
subagent_type="executor",
|
|
103
|
+
prompt="Execute the implementation plan at thoughts/shared/plans/YYYY-MM-DD-{topic}.md",
|
|
104
|
+
description="Execute implementation plan"
|
|
105
|
+
)
|
|
106
|
+
</spawn>
|
|
107
|
+
<after-execution>
|
|
108
|
+
<action>Report executor results to user</action>
|
|
93
109
|
<rule priority="CRITICAL">YOUR JOB IS DONE. STOP HERE.</rule>
|
|
94
|
-
<rule>Do NOT
|
|
95
|
-
|
|
96
|
-
<rule>Do NOT continue the conversation - wait for user's next request</rule>
|
|
97
|
-
</after-handoff>
|
|
110
|
+
<rule>Do NOT write any code yourself</rule>
|
|
111
|
+
</after-execution>
|
|
98
112
|
</phase>
|
|
99
113
|
</process>
|
|
100
114
|
|
|
@@ -4,13 +4,23 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
// Compact when this percentage of context is used
|
|
7
|
-
const COMPACT_THRESHOLD = 0.
|
|
7
|
+
const COMPACT_THRESHOLD = 0.5;
|
|
8
8
|
|
|
9
9
|
const LEDGER_DIR = "thoughts/ledgers";
|
|
10
10
|
|
|
11
|
+
// Timeout for waiting for compaction to complete (2 minutes)
|
|
12
|
+
const COMPACTION_TIMEOUT_MS = 120_000;
|
|
13
|
+
|
|
14
|
+
interface PendingCompaction {
|
|
15
|
+
resolve: () => void;
|
|
16
|
+
reject: (error: Error) => void;
|
|
17
|
+
timeoutId: ReturnType<typeof setTimeout>;
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
interface AutoCompactState {
|
|
12
21
|
inProgress: Set<string>;
|
|
13
22
|
lastCompactTime: Map<string, number>;
|
|
23
|
+
pendingCompactions: Map<string, PendingCompaction>;
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
// Cooldown between compaction attempts (prevent rapid re-triggering)
|
|
@@ -20,6 +30,7 @@ export function createAutoCompactHook(ctx: PluginInput) {
|
|
|
20
30
|
const state: AutoCompactState = {
|
|
21
31
|
inProgress: new Set(),
|
|
22
32
|
lastCompactTime: new Map(),
|
|
33
|
+
pendingCompactions: new Map(),
|
|
23
34
|
};
|
|
24
35
|
|
|
25
36
|
async function writeSummaryToLedger(sessionID: string): Promise<void> {
|
|
@@ -78,6 +89,17 @@ ${summaryText}
|
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
91
|
|
|
92
|
+
function waitForCompaction(sessionID: string): Promise<void> {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const timeoutId = setTimeout(() => {
|
|
95
|
+
state.pendingCompactions.delete(sessionID);
|
|
96
|
+
reject(new Error("Compaction timed out"));
|
|
97
|
+
}, COMPACTION_TIMEOUT_MS);
|
|
98
|
+
|
|
99
|
+
state.pendingCompactions.set(sessionID, { resolve, reject, timeoutId });
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
81
103
|
async function triggerCompaction(
|
|
82
104
|
sessionID: string,
|
|
83
105
|
providerID: string,
|
|
@@ -111,15 +133,19 @@ ${summaryText}
|
|
|
111
133
|
})
|
|
112
134
|
.catch(() => {});
|
|
113
135
|
|
|
136
|
+
// Start the compaction - this returns immediately while compaction runs async
|
|
114
137
|
await ctx.client.session.summarize({
|
|
115
138
|
path: { id: sessionID },
|
|
116
139
|
body: { providerID, modelID },
|
|
117
140
|
query: { directory: ctx.directory },
|
|
118
141
|
});
|
|
119
142
|
|
|
143
|
+
// Wait for the session.compacted event to confirm completion
|
|
144
|
+
await waitForCompaction(sessionID);
|
|
145
|
+
|
|
120
146
|
state.lastCompactTime.set(sessionID, Date.now());
|
|
121
147
|
|
|
122
|
-
// Write summary to ledger file
|
|
148
|
+
// Write summary to ledger file (only after compaction is confirmed complete)
|
|
123
149
|
await writeSummaryToLedger(sessionID);
|
|
124
150
|
|
|
125
151
|
await ctx.client.tui
|
|
@@ -153,12 +179,32 @@ ${summaryText}
|
|
|
153
179
|
event: async ({ event }: { event: { type: string; properties?: unknown } }) => {
|
|
154
180
|
const props = event.properties as Record<string, unknown> | undefined;
|
|
155
181
|
|
|
182
|
+
// Handle compaction completion
|
|
183
|
+
if (event.type === "session.compacted") {
|
|
184
|
+
const sessionID = props?.sessionID as string | undefined;
|
|
185
|
+
if (sessionID) {
|
|
186
|
+
const pending = state.pendingCompactions.get(sessionID);
|
|
187
|
+
if (pending) {
|
|
188
|
+
clearTimeout(pending.timeoutId);
|
|
189
|
+
state.pendingCompactions.delete(sessionID);
|
|
190
|
+
pending.resolve();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
156
196
|
// Cleanup on session delete
|
|
157
197
|
if (event.type === "session.deleted") {
|
|
158
198
|
const sessionInfo = props?.info as { id?: string } | undefined;
|
|
159
199
|
if (sessionInfo?.id) {
|
|
160
200
|
state.inProgress.delete(sessionInfo.id);
|
|
161
201
|
state.lastCompactTime.delete(sessionInfo.id);
|
|
202
|
+
const pending = state.pendingCompactions.get(sessionInfo.id);
|
|
203
|
+
if (pending) {
|
|
204
|
+
clearTimeout(pending.timeoutId);
|
|
205
|
+
state.pendingCompactions.delete(sessionInfo.id);
|
|
206
|
+
pending.reject(new Error("Session deleted"));
|
|
207
|
+
}
|
|
162
208
|
}
|
|
163
209
|
return;
|
|
164
210
|
}
|