@slowdini/slow-powers-opencode 0.4.2 → 0.4.3
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/opencode/plugins/slow-powers.js +32 -18
- package/package.json +1 -1
|
@@ -23,11 +23,18 @@ const bootstrapLeadingPhrase = "<EXTREMELY-IMPORTANT>";
|
|
|
23
23
|
// once eliminates redundant fs work on every agent step.
|
|
24
24
|
let _bootstrapCache; // undefined = not yet loaded, null = file missing
|
|
25
25
|
|
|
26
|
-
// Tracks plan files we've already sent the hardening prompt for.
|
|
27
|
-
// Once we ask the agent to harden a plan, we never ask again for that file.
|
|
28
|
-
const hardeningPromptSentFor = new Set();
|
|
29
|
-
|
|
30
26
|
export const SlowPowersPlugin = async ({ client, directory: _directory }) => {
|
|
27
|
+
// Tracks plan files we've already sent the hardening prompt for, keyed by
|
|
28
|
+
// `${sessionID}:${filePath}` so different sessions with the same plan path
|
|
29
|
+
// still get prompted. Scoped to the plugin instance (one per opencode process).
|
|
30
|
+
const hardeningPromptSentFor = new Set();
|
|
31
|
+
|
|
32
|
+
const log = (level, message) => {
|
|
33
|
+
client.app
|
|
34
|
+
.log({ body: { service: "slow-powers", level, message } })
|
|
35
|
+
.catch(() => {});
|
|
36
|
+
};
|
|
37
|
+
|
|
31
38
|
// Helper to load bootstrap content (cached after first call)
|
|
32
39
|
const getBootstrapContent = () => {
|
|
33
40
|
if (_bootstrapCache !== undefined) return _bootstrapCache;
|
|
@@ -46,23 +53,30 @@ export const SlowPowersPlugin = async ({ client, directory: _directory }) => {
|
|
|
46
53
|
const filePath = event.properties.file;
|
|
47
54
|
const sessionID = event.properties.sessionID;
|
|
48
55
|
|
|
49
|
-
if (!filePath || !sessionID)
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
if (!filePath || !sessionID) {
|
|
57
|
+
log("debug", `[hardening] skipped: missing filePath or sessionID`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
52
60
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
session = await client.session.get({ path: { id: sessionID } });
|
|
56
|
-
} catch {
|
|
61
|
+
if (!filePath.match(/\.opencode\/plans\/.*\.md$/)) {
|
|
62
|
+
log("debug", `[hardening] skipped: ${filePath} not in .opencode/plans/`);
|
|
57
63
|
return;
|
|
58
64
|
}
|
|
59
|
-
if (session.agent !== "plan") return;
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
const promptKey = `${sessionID}:${filePath}`;
|
|
67
|
+
|
|
68
|
+
// Only prompt once per plan file per session. After we've asked the agent
|
|
69
|
+
// to harden it, we trust them to do so or not; re-prompting causes loops.
|
|
70
|
+
if (hardeningPromptSentFor.has(promptKey)) {
|
|
71
|
+
log("debug", `[hardening] skipped: already prompted for ${promptKey}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
64
74
|
|
|
65
|
-
hardeningPromptSentFor.add(
|
|
75
|
+
hardeningPromptSentFor.add(promptKey);
|
|
76
|
+
log(
|
|
77
|
+
"info",
|
|
78
|
+
`[hardening] prompting agent to harden ${filePath} in session ${sessionID}`,
|
|
79
|
+
);
|
|
66
80
|
|
|
67
81
|
try {
|
|
68
82
|
await client.session.prompt({
|
|
@@ -78,8 +92,8 @@ export const SlowPowersPlugin = async ({ client, directory: _directory }) => {
|
|
|
78
92
|
},
|
|
79
93
|
});
|
|
80
94
|
} catch (err) {
|
|
81
|
-
hardeningPromptSentFor.delete(
|
|
82
|
-
|
|
95
|
+
hardeningPromptSentFor.delete(promptKey);
|
|
96
|
+
log("error", `[hardening] failed to trigger hardening-plans: ${err}`);
|
|
83
97
|
}
|
|
84
98
|
};
|
|
85
99
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slowdini/slow-powers-opencode",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Slow-powers — structured development workflows for coding agents (TDD, debugging, verification, git hygiene)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./opencode/plugins/slow-powers.js",
|