pulse-framework-cli 0.4.2 → 0.4.4
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/dist/commands/doctor.js +1 -1
- package/dist/commands/reset.js +6 -6
- package/dist/commands/run.js +32 -32
- package/dist/hooks/install.js +29 -3
- package/dist/lib/input.js +5 -4
- package/package.json +1 -1
- package/templates/.cursorrules +46 -0
- package/templates/cursor/pulse.mdc +39 -24
package/dist/commands/doctor.js
CHANGED
|
@@ -66,7 +66,7 @@ function registerDoctorCommand(program) {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
// ════════════════════════════════════════════════════════════════════════
|
|
69
|
-
//
|
|
69
|
+
// Add preset limit violations explicitly
|
|
70
70
|
// ════════════════════════════════════════════════════════════════════════
|
|
71
71
|
const scope = (0, briefing_js_1.calculateScopeCheck)(config, scan.stats);
|
|
72
72
|
if (scope.exceeded) {
|
package/dist/commands/reset.js
CHANGED
|
@@ -38,7 +38,7 @@ function registerResetCommand(program) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
// ══════════════════════════════════════════════════════════════════════
|
|
41
|
-
//
|
|
41
|
+
// Show affected commits
|
|
42
42
|
// ══════════════════════════════════════════════════════════════════════
|
|
43
43
|
const recentLog = await (0, git_js_1.gitLogOneline)(repoRoot, numCommits + 2);
|
|
44
44
|
const logLines = recentLog.split("\n").filter((l) => l.trim());
|
|
@@ -57,7 +57,7 @@ function registerResetCommand(program) {
|
|
|
57
57
|
// eslint-disable-next-line no-console
|
|
58
58
|
console.log("");
|
|
59
59
|
// ══════════════════════════════════════════════════════════════════════
|
|
60
|
-
//
|
|
60
|
+
// Choose reset mode
|
|
61
61
|
// ══════════════════════════════════════════════════════════════════════
|
|
62
62
|
let mode = "mixed";
|
|
63
63
|
if (opts.soft) {
|
|
@@ -75,7 +75,7 @@ function registerResetCommand(program) {
|
|
|
75
75
|
mode = await (0, input_js_1.promptSelect)("Reset mode", choices, "mixed");
|
|
76
76
|
}
|
|
77
77
|
// ══════════════════════════════════════════════════════════════════════
|
|
78
|
-
//
|
|
78
|
+
// Final confirmation for hard reset
|
|
79
79
|
// ══════════════════════════════════════════════════════════════════════
|
|
80
80
|
if (mode === "hard" && !opts.yes) {
|
|
81
81
|
// eslint-disable-next-line no-console
|
|
@@ -88,7 +88,7 @@ function registerResetCommand(program) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
// ══════════════════════════════════════════════════════════════════════
|
|
91
|
-
//
|
|
91
|
+
// Execute git reset
|
|
92
92
|
// ══════════════════════════════════════════════════════════════════════
|
|
93
93
|
const resetArg = `HEAD~${numCommits}`;
|
|
94
94
|
const modeArg = mode === "mixed" ? "" : `--${mode}`;
|
|
@@ -102,14 +102,14 @@ function registerResetCommand(program) {
|
|
|
102
102
|
process.exit(1);
|
|
103
103
|
}
|
|
104
104
|
// ══════════════════════════════════════════════════════════════════════
|
|
105
|
-
//
|
|
105
|
+
// Success message
|
|
106
106
|
// ══════════════════════════════════════════════════════════════════════
|
|
107
107
|
const newLog = await (0, git_js_1.gitLogOneline)(repoRoot, 1);
|
|
108
108
|
// eslint-disable-next-line no-console
|
|
109
109
|
console.log(`✅ Reset successful!`);
|
|
110
110
|
// eslint-disable-next-line no-console
|
|
111
111
|
console.log(`📍 New HEAD: ${newLog}\n`);
|
|
112
|
-
//
|
|
112
|
+
// Tips
|
|
113
113
|
if (mode === "soft" || mode === "mixed") {
|
|
114
114
|
// eslint-disable-next-line no-console
|
|
115
115
|
console.log(`💡 Tip: Changes are still there.`);
|
package/dist/commands/run.js
CHANGED
|
@@ -46,15 +46,15 @@ function registerRunCommand(program) {
|
|
|
46
46
|
program
|
|
47
47
|
.command("run")
|
|
48
48
|
.description("Combined workflow: Start → Watch → Checkpoints → Review")
|
|
49
|
-
.option("-t, --template <id>", "
|
|
49
|
+
.option("-t, --template <id>", "Template: feature, bugfix, refactor, concept, analyze, review")
|
|
50
50
|
.option("--minutes <n>", "Minutes between checkpoint reminders")
|
|
51
51
|
.option("--no-watch", "Don't start watcher")
|
|
52
|
-
.option("--action <text>", "ACTION
|
|
53
|
-
.option("-C, --clipboard", "
|
|
52
|
+
.option("--action <text>", "Provide ACTION directly")
|
|
53
|
+
.option("-C, --clipboard", "Copy prompt to clipboard")
|
|
54
54
|
.action(async (opts) => {
|
|
55
55
|
const repoRoot = await (0, paths_js_1.findRepoRoot)(process.cwd());
|
|
56
56
|
if (!repoRoot)
|
|
57
|
-
throw new Error("
|
|
57
|
+
throw new Error("Not in a git repository.");
|
|
58
58
|
const [state, config] = await Promise.all([(0, artifacts_js_1.loadState)(repoRoot), (0, config_js_1.loadConfig)(repoRoot)]);
|
|
59
59
|
// Use preset checkpoint interval if not specified
|
|
60
60
|
const minutes = opts.minutes
|
|
@@ -76,17 +76,17 @@ function registerRunCommand(program) {
|
|
|
76
76
|
// ════════════════════════════════════════════════════════════════════════
|
|
77
77
|
// eslint-disable-next-line no-console
|
|
78
78
|
console.log(`━━━ PHASE 1: Prompt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
79
|
-
//
|
|
79
|
+
// Select template
|
|
80
80
|
let template = opts.template ? (0, prompts_js_1.getTemplateById)(opts.template) : undefined;
|
|
81
81
|
if (!template && !opts.action) {
|
|
82
82
|
const choices = prompts_js_1.PROMPT_TEMPLATES.map((t) => ({
|
|
83
83
|
value: t.id,
|
|
84
84
|
label: `${t.name} - ${t.description}`,
|
|
85
85
|
}));
|
|
86
|
-
const selectedId = await (0, input_js_1.promptSelect)("📋
|
|
86
|
+
const selectedId = await (0, input_js_1.promptSelect)("📋 Choose template", choices, "feature");
|
|
87
87
|
template = (0, prompts_js_1.getTemplateById)(selectedId);
|
|
88
88
|
}
|
|
89
|
-
// 6
|
|
89
|
+
// Collect the 6 elements
|
|
90
90
|
const el = {
|
|
91
91
|
role: template?.defaults.role,
|
|
92
92
|
context: template?.defaults.context,
|
|
@@ -95,14 +95,14 @@ function registerRunCommand(program) {
|
|
|
95
95
|
};
|
|
96
96
|
const layer = template?.layer ?? state.profile;
|
|
97
97
|
if (!el.action?.trim()) {
|
|
98
|
-
el.action = await (0, input_js_1.promptText)("⚡ ACTION (
|
|
98
|
+
el.action = await (0, input_js_1.promptText)("⚡ ACTION (what should be built?)", "");
|
|
99
99
|
}
|
|
100
100
|
if (!el.context?.trim()) {
|
|
101
|
-
el.context = await (0, input_js_1.promptText)("📍
|
|
101
|
+
el.context = await (0, input_js_1.promptText)("📍 CONTEXT (project, stack)", "");
|
|
102
102
|
}
|
|
103
|
-
//
|
|
103
|
+
// Generate prompt
|
|
104
104
|
const prompt = (0, prompts_js_1.renderSixElementPrompt)(layer, el);
|
|
105
|
-
//
|
|
105
|
+
// Save artifact
|
|
106
106
|
const ts = (0, artifacts_js_1.timestampId)();
|
|
107
107
|
const filename = `${ts}-run.md`;
|
|
108
108
|
const content = [
|
|
@@ -110,7 +110,7 @@ function registerRunCommand(program) {
|
|
|
110
110
|
``,
|
|
111
111
|
`- Profile: **${presetProfile}**`,
|
|
112
112
|
`- Layer: **${layer}**`,
|
|
113
|
-
template ? `-
|
|
113
|
+
template ? `- Template: **${template.name}**` : "",
|
|
114
114
|
`- Checkpoint interval: **${minutes} min**`,
|
|
115
115
|
``,
|
|
116
116
|
`## Prompt`,
|
|
@@ -126,7 +126,7 @@ function registerRunCommand(program) {
|
|
|
126
126
|
// eslint-disable-next-line no-console
|
|
127
127
|
console.log(`✅ Template: ${template?.name ?? "custom"}`);
|
|
128
128
|
// eslint-disable-next-line no-console
|
|
129
|
-
console.log(`✅
|
|
129
|
+
console.log(`✅ Artifact: ${artifactPath}`);
|
|
130
130
|
// Clipboard
|
|
131
131
|
if (opts.clipboard) {
|
|
132
132
|
const clipMsg = await (0, clipboard_js_1.copyAndNotify)(prompt);
|
|
@@ -148,19 +148,19 @@ function registerRunCommand(program) {
|
|
|
148
148
|
// ════════════════════════════════════════════════════════════════════════
|
|
149
149
|
if (opts.watch === false) {
|
|
150
150
|
// eslint-disable-next-line no-console
|
|
151
|
-
console.log(`━━━ PHASE 2:
|
|
151
|
+
console.log(`━━━ PHASE 2: Skipped ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
152
152
|
// eslint-disable-next-line no-console
|
|
153
153
|
console.log("Watcher not started (--no-watch).\n");
|
|
154
154
|
// eslint-disable-next-line no-console
|
|
155
155
|
console.log("💡 Next steps:");
|
|
156
156
|
// eslint-disable-next-line no-console
|
|
157
|
-
console.log(" 1.
|
|
157
|
+
console.log(" 1. Paste the prompt into Cursor");
|
|
158
158
|
// eslint-disable-next-line no-console
|
|
159
|
-
console.log(" 2. `pulse checkpoint`
|
|
159
|
+
console.log(" 2. Run `pulse checkpoint` every 5-10 min");
|
|
160
160
|
// eslint-disable-next-line no-console
|
|
161
|
-
console.log(" 3.
|
|
161
|
+
console.log(" 3. If stuck: `pulse escalate`");
|
|
162
162
|
// eslint-disable-next-line no-console
|
|
163
|
-
console.log(" 4.
|
|
163
|
+
console.log(" 4. At the end: `pulse review`\n");
|
|
164
164
|
return;
|
|
165
165
|
}
|
|
166
166
|
// eslint-disable-next-line no-console
|
|
@@ -170,12 +170,12 @@ function registerRunCommand(program) {
|
|
|
170
170
|
// eslint-disable-next-line no-console
|
|
171
171
|
console.log(`📍 Watcher running... (Ctrl+C to stop)\n`);
|
|
172
172
|
// eslint-disable-next-line no-console
|
|
173
|
-
console.log(` 1.
|
|
173
|
+
console.log(` 1. Paste the prompt above into Cursor`);
|
|
174
174
|
// eslint-disable-next-line no-console
|
|
175
|
-
console.log(` 2.
|
|
175
|
+
console.log(` 2. Start working`);
|
|
176
176
|
// eslint-disable-next-line no-console
|
|
177
|
-
console.log(` 3. Ctrl+C
|
|
178
|
-
await (0, notifications_js_1.notify)(config.notifications, "Pulse Run
|
|
177
|
+
console.log(` 3. Ctrl+C when done\n`);
|
|
178
|
+
await (0, notifications_js_1.notify)(config.notifications, "Pulse Run started", `Checkpoint reminder every ${minutes} min. Ctrl+C to exit.`);
|
|
179
179
|
// Update state
|
|
180
180
|
state.lastCheckpointAt = new Date().toISOString();
|
|
181
181
|
await (0, artifacts_js_1.saveState)(repoRoot, state);
|
|
@@ -200,11 +200,11 @@ function registerRunCommand(program) {
|
|
|
200
200
|
// eslint-disable-next-line no-console
|
|
201
201
|
console.log(`└${"─".repeat(58)}┘`);
|
|
202
202
|
// eslint-disable-next-line no-console
|
|
203
|
-
console.log(`
|
|
203
|
+
console.log(` Time: ${new Date().toLocaleTimeString()}`);
|
|
204
204
|
// eslint-disable-next-line no-console
|
|
205
|
-
console.log(` Status:
|
|
205
|
+
console.log(` Status: uncommitted changes present`);
|
|
206
206
|
// eslint-disable-next-line no-console
|
|
207
|
-
console.log(` → pulse checkpoint -m '
|
|
207
|
+
console.log(` → pulse checkpoint -m 'your message'\n`);
|
|
208
208
|
}
|
|
209
209
|
else {
|
|
210
210
|
// eslint-disable-next-line no-console
|
|
@@ -217,15 +217,15 @@ function registerRunCommand(program) {
|
|
|
217
217
|
const cleanup = async (signal) => {
|
|
218
218
|
clearInterval(interval);
|
|
219
219
|
// eslint-disable-next-line no-console
|
|
220
|
-
console.log(`\n\n━━━ PHASE 3:
|
|
220
|
+
console.log(`\n\n━━━ PHASE 3: Wrap-up ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
221
221
|
// eslint-disable-next-line no-console
|
|
222
|
-
console.log(`🛑 ${signal}
|
|
222
|
+
console.log(`🛑 Received ${signal} - stopping Pulse Run...\n`);
|
|
223
223
|
// Check final status
|
|
224
224
|
const status = await (0, git_js_1.gitStatusPorcelain)(repoRoot);
|
|
225
225
|
const dirty = status.trim().length > 0;
|
|
226
226
|
if (dirty) {
|
|
227
227
|
// eslint-disable-next-line no-console
|
|
228
|
-
console.log("📝 Uncommitted
|
|
228
|
+
console.log("📝 Uncommitted changes found:\n");
|
|
229
229
|
const stat = await (0, git_js_1.gitDiffStat)(repoRoot);
|
|
230
230
|
// eslint-disable-next-line no-console
|
|
231
231
|
console.log(stat);
|
|
@@ -243,25 +243,25 @@ function registerRunCommand(program) {
|
|
|
243
243
|
}
|
|
244
244
|
else {
|
|
245
245
|
// eslint-disable-next-line no-console
|
|
246
|
-
console.log("✨
|
|
246
|
+
console.log("✨ No uncommitted changes.\n");
|
|
247
247
|
}
|
|
248
248
|
// Offer review
|
|
249
249
|
const doReview = await (0, input_js_1.promptConfirm)("Create review?", dirty);
|
|
250
250
|
if (doReview) {
|
|
251
251
|
// eslint-disable-next-line no-console
|
|
252
|
-
console.log("\n💡
|
|
252
|
+
console.log("\n💡 Run: pulse review\n");
|
|
253
253
|
}
|
|
254
254
|
// Summary
|
|
255
255
|
// eslint-disable-next-line no-console
|
|
256
256
|
console.log(`┌${"─".repeat(58)}┐`);
|
|
257
257
|
// eslint-disable-next-line no-console
|
|
258
|
-
console.log(`│ 👋 Pulse Run
|
|
258
|
+
console.log(`│ 👋 Pulse Run finished${" ".repeat(35)}│`);
|
|
259
259
|
// eslint-disable-next-line no-console
|
|
260
260
|
console.log(`│ │`);
|
|
261
261
|
// eslint-disable-next-line no-console
|
|
262
262
|
console.log(`│ Checkpoints: ${checkpointCount}${" ".repeat(43 - String(checkpointCount).length)}│`);
|
|
263
263
|
// eslint-disable-next-line no-console
|
|
264
|
-
console.log(`│
|
|
264
|
+
console.log(`│ Artifact: .pulse/pulses/${filename}${" ".repeat(Math.max(0, 32 - filename.length))}│`);
|
|
265
265
|
// eslint-disable-next-line no-console
|
|
266
266
|
console.log(`└${"─".repeat(58)}┘\n`);
|
|
267
267
|
process.exit(0);
|
package/dist/hooks/install.js
CHANGED
|
@@ -75,13 +75,39 @@ fi
|
|
|
75
75
|
`, "utf8");
|
|
76
76
|
await ensureExecutable(postCommit);
|
|
77
77
|
await promises_1.default.writeFile(prePush, `#!/bin/sh
|
|
78
|
-
set -e
|
|
79
|
-
|
|
80
78
|
# Pulse safeguard: never push without explicit permission.
|
|
81
79
|
# Allow push explicitly by running:
|
|
82
80
|
# PULSE_ALLOW_PUSH=1 git push ...
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
if [ "$PULSE_SKIP_HOOKS" = "1" ]; then
|
|
83
|
+
exit 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
if [ "$PULSE_ALLOW_PUSH" != "1" ]; then
|
|
87
|
+
echo "PULSE safeguard: push blocked. Set PULSE_ALLOW_PUSH=1 for an explicit push."
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Run doctor check if pulse CLI is available
|
|
92
|
+
if command -v pulse >/dev/null 2>&1; then
|
|
93
|
+
pulse doctor --hook pre-push
|
|
94
|
+
EXIT_CODE=$?
|
|
95
|
+
elif command -v pulse-framework >/dev/null 2>&1; then
|
|
96
|
+
pulse-framework doctor --hook pre-push
|
|
97
|
+
EXIT_CODE=$?
|
|
98
|
+
else
|
|
99
|
+
EXIT_CODE=0
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Only block on CRITICAL (exit 2), allow warnings (exit 1) - consistent with pre-commit
|
|
103
|
+
if [ $EXIT_CODE -eq 2 ]; then
|
|
104
|
+
echo ""
|
|
105
|
+
echo "❌ Push blocked by PULSE (critical findings)"
|
|
106
|
+
echo " Fix issues or use: PULSE_SKIP_HOOKS=1 git push ..."
|
|
107
|
+
exit 2
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
exit 0
|
|
85
111
|
`, "utf8");
|
|
86
112
|
await ensureExecutable(prePush);
|
|
87
113
|
// eslint-disable-next-line no-console
|
package/dist/lib/input.js
CHANGED
|
@@ -37,7 +37,7 @@ async function promptSelect(label, choices, defaultValue) {
|
|
|
37
37
|
});
|
|
38
38
|
// eslint-disable-next-line no-console
|
|
39
39
|
console.log("");
|
|
40
|
-
const ans = await rl.question("
|
|
40
|
+
const ans = await rl.question("Enter number: ");
|
|
41
41
|
const num = parseInt(ans.trim(), 10);
|
|
42
42
|
if (num >= 1 && num <= choices.length) {
|
|
43
43
|
const choice = choices[num - 1];
|
|
@@ -65,12 +65,13 @@ async function promptSelect(label, choices, defaultValue) {
|
|
|
65
65
|
async function promptConfirm(label, defaultYes = false) {
|
|
66
66
|
const rl = promises_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
67
67
|
try {
|
|
68
|
-
const hint = defaultYes ? "(
|
|
68
|
+
const hint = defaultYes ? "(Y/n)" : "(y/N)";
|
|
69
69
|
const ans = await rl.question(`${label} ${hint}: `);
|
|
70
70
|
const v = ans.trim().toLowerCase();
|
|
71
|
-
|
|
71
|
+
// Accept a few common variants (English + legacy German inputs)
|
|
72
|
+
if (v === "y" || v === "yes" || v === "j" || v === "ja")
|
|
72
73
|
return true;
|
|
73
|
-
if (v === "n" || v === "
|
|
74
|
+
if (v === "n" || v === "no" || v === "nein")
|
|
74
75
|
return false;
|
|
75
76
|
return defaultYes;
|
|
76
77
|
}
|
package/package.json
CHANGED
package/templates/.cursorrules
CHANGED
|
@@ -154,6 +154,52 @@
|
|
|
154
154
|
# 4. ESTIMATE the effort:
|
|
155
155
|
# "Estimated effort: [X] minutes. Should I start?"
|
|
156
156
|
|
|
157
|
+
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
|
158
|
+
# │ 🔧 MCP TOOL TRIGGERS (WHEN TO CALL) │
|
|
159
|
+
# └─────────────────────────────────────────────────────────────────────────────┘
|
|
160
|
+
|
|
161
|
+
# pulse_status → FIRST action of every response
|
|
162
|
+
# pulse_doctor → AFTER any file edit/create/delete
|
|
163
|
+
# pulse_checkpoint → WHEN >10 min since last checkpoint (just do it)
|
|
164
|
+
# pulse_run → WHEN user gives multi-step task (>3 steps)
|
|
165
|
+
# pulse_escalate → WHEN 2-3 failed attempts OR error you don't understand
|
|
166
|
+
# pulse_correct → WHEN user says "wrong", "not what I meant", "stop"
|
|
167
|
+
# pulse_review → BEFORE saying "done", creating PR, or merging
|
|
168
|
+
# pulse_learn → AFTER solving a non-trivial problem (document what worked!)
|
|
169
|
+
# pulse_reset → WHEN pulse_doctor shows loop signal
|
|
170
|
+
|
|
171
|
+
# IMPORTANT: Call these ACTIVELY, not just when user asks!
|
|
172
|
+
# - After success: pulse_learn (build knowledge)
|
|
173
|
+
# - Before "done": pulse_review (final check)
|
|
174
|
+
# - On problems: pulse_escalate (don't keep trying)
|
|
175
|
+
|
|
176
|
+
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
|
177
|
+
# │ 📝 CHANGELOG PROTOCOL (MANDATORY) │
|
|
178
|
+
# └─────────────────────────────────────────────────────────────────────────────┘
|
|
179
|
+
|
|
180
|
+
# EVERY significant change MUST be documented in CHANGELOG.md
|
|
181
|
+
#
|
|
182
|
+
# WHEN to update:
|
|
183
|
+
# - New feature added
|
|
184
|
+
# - Bug fixed
|
|
185
|
+
# - Breaking change
|
|
186
|
+
# - Behavior changed
|
|
187
|
+
# - After each session with multiple changes
|
|
188
|
+
#
|
|
189
|
+
# FORMAT (Keep a Changelog style):
|
|
190
|
+
# ## [version] (YYYY-MM-DD)
|
|
191
|
+
# ### Added - for new features
|
|
192
|
+
# ### Changed - for changes in existing functionality
|
|
193
|
+
# ### Fixed - for bug fixes
|
|
194
|
+
# ### Removed - for removed features
|
|
195
|
+
# ### Security - for security fixes
|
|
196
|
+
#
|
|
197
|
+
# IMPORTANT:
|
|
198
|
+
# - Update CHANGELOG.md BEFORE committing significant changes
|
|
199
|
+
# - Include specific details (what, why)
|
|
200
|
+
# - Reference issue numbers if applicable
|
|
201
|
+
# - Keep the project alive with good documentation!
|
|
202
|
+
|
|
157
203
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
|
158
204
|
# │ 📦 PULSE PUBLISHING PROTOCOL │
|
|
159
205
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
|
@@ -53,18 +53,22 @@ WHEN: pulse_status shows >10 min since checkpoint
|
|
|
53
53
|
WHAT: "Should I create a checkpoint?"
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
## 🔴 AUTOMATIC ACTIONS
|
|
57
|
-
|
|
58
|
-
| Situation | Action |
|
|
59
|
-
|
|
60
|
-
| Start of response | → `pulse_status`
|
|
61
|
-
| Code changed | → `pulse_doctor` |
|
|
62
|
-
| >10 min since checkpoint | →
|
|
63
|
-
| >
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
56
|
+
## 🔴 AUTOMATIC ACTIONS (MANDATORY)
|
|
57
|
+
|
|
58
|
+
| Situation | Action | Example |
|
|
59
|
+
|-----------|--------|---------|
|
|
60
|
+
| Start of response | → `pulse_status` | Every message |
|
|
61
|
+
| Code changed | → `pulse_doctor` | After any edit/create/delete |
|
|
62
|
+
| >10 min since checkpoint | → `pulse_checkpoint` | Just do it, don't ask |
|
|
63
|
+
| >30 min autonomous | → **STOP + ask user** | "I've been working 30 min, should I continue?" |
|
|
64
|
+
| 2-3 failed attempts | → `pulse_escalate` | Build fails twice, test fails twice |
|
|
65
|
+
| Error you don't understand | → `pulse_escalate` | Cryptic error message |
|
|
66
|
+
| User says "that's wrong" | → `pulse_correct` | Course correction |
|
|
67
|
+
| Task completed successfully | → `pulse_learn` | "What did I learn from this?" |
|
|
68
|
+
| Before "done" / PR / merge | → `pulse_review` | Final checklist |
|
|
69
|
+
| New multi-step task | → `pulse_run` | User gives complex task |
|
|
70
|
+
| Loop signal detected | → `pulse_reset` | Doctor shows loop warning |
|
|
71
|
+
| DELETE operation | → **Get user confirmation** | "May I delete X?" |
|
|
68
72
|
|
|
69
73
|
## 🔴 SAFEGUARDS (non-negotiable)
|
|
70
74
|
|
|
@@ -103,19 +107,29 @@ After 2-3 failed attempts:
|
|
|
103
107
|
- Error message
|
|
104
108
|
3. **WAIT** for user instruction
|
|
105
109
|
|
|
106
|
-
##
|
|
110
|
+
## After Success (IMPORTANT!)
|
|
107
111
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
|
112
|
+
When you successfully solve a non-trivial problem:
|
|
113
|
+
|
|
114
|
+
1. **Call `pulse_learn`** to document:
|
|
115
|
+
- What the problem was
|
|
116
|
+
- What solution worked
|
|
117
|
+
- Any rule/pattern to remember
|
|
118
|
+
2. This builds institutional knowledge for future sessions
|
|
119
|
+
|
|
120
|
+
## MCP Tools - WHEN TO CALL
|
|
121
|
+
|
|
122
|
+
| Tool | Trigger (MANDATORY) |
|
|
123
|
+
|------|---------------------|
|
|
124
|
+
| `pulse_status` | **FIRST action** of every response |
|
|
125
|
+
| `pulse_doctor` | **AFTER** any file edit/create/delete |
|
|
126
|
+
| `pulse_checkpoint` | **WHEN** >10 min since last checkpoint |
|
|
127
|
+
| `pulse_run` | **WHEN** user gives multi-step task (>3 steps) |
|
|
128
|
+
| `pulse_escalate` | **WHEN** 2-3 failed attempts OR error you don't understand |
|
|
129
|
+
| `pulse_correct` | **WHEN** user says "wrong", "not what I meant", "stop" |
|
|
130
|
+
| `pulse_review` | **BEFORE** saying "done", creating PR, or merging |
|
|
131
|
+
| `pulse_learn` | **AFTER** solving a non-trivial problem (document what worked) |
|
|
132
|
+
| `pulse_reset` | **WHEN** `pulse_doctor` shows loop signal |
|
|
119
133
|
|
|
120
134
|
## Example Flow
|
|
121
135
|
|
|
@@ -142,3 +156,4 @@ Agent:
|
|
|
142
156
|
- Call the tools ACTIVELY, not only when user asks
|
|
143
157
|
- When uncertain: STOP and ASK
|
|
144
158
|
- The safeguards ALWAYS apply, even if user argues against them
|
|
159
|
+
- **ALWAYS update CHANGELOG.md** after significant changes (features, fixes, changes)
|