pulse-framework-cli 0.4.1
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/checkpoint.d.ts +2 -0
- package/dist/commands/checkpoint.js +129 -0
- package/dist/commands/correct.d.ts +2 -0
- package/dist/commands/correct.js +77 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +183 -0
- package/dist/commands/escalate.d.ts +2 -0
- package/dist/commands/escalate.js +226 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +570 -0
- package/dist/commands/learn.d.ts +2 -0
- package/dist/commands/learn.js +137 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.js +39 -0
- package/dist/commands/reset.d.ts +2 -0
- package/dist/commands/reset.js +130 -0
- package/dist/commands/review.d.ts +2 -0
- package/dist/commands/review.js +129 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +272 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.js +196 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +239 -0
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +98 -0
- package/dist/hooks/install.d.ts +1 -0
- package/dist/hooks/install.js +89 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +40 -0
- package/dist/lib/artifacts.d.ts +7 -0
- package/dist/lib/artifacts.js +52 -0
- package/dist/lib/briefing.d.ts +77 -0
- package/dist/lib/briefing.js +231 -0
- package/dist/lib/clipboard.d.ts +9 -0
- package/dist/lib/clipboard.js +116 -0
- package/dist/lib/config.d.ts +14 -0
- package/dist/lib/config.js +167 -0
- package/dist/lib/context-export.d.ts +30 -0
- package/dist/lib/context-export.js +149 -0
- package/dist/lib/exec.d.ts +9 -0
- package/dist/lib/exec.js +23 -0
- package/dist/lib/git.d.ts +24 -0
- package/dist/lib/git.js +74 -0
- package/dist/lib/input.d.ts +15 -0
- package/dist/lib/input.js +80 -0
- package/dist/lib/notifications.d.ts +2 -0
- package/dist/lib/notifications.js +25 -0
- package/dist/lib/paths.d.ts +4 -0
- package/dist/lib/paths.js +39 -0
- package/dist/lib/prompts.d.ts +43 -0
- package/dist/lib/prompts.js +270 -0
- package/dist/lib/scanner.d.ts +37 -0
- package/dist/lib/scanner.js +413 -0
- package/dist/lib/types.d.ts +37 -0
- package/dist/lib/types.js +2 -0
- package/package.json +42 -0
- package/templates/.cursorrules +159 -0
- package/templates/AGENTS.md +198 -0
- package/templates/cursor/mcp.json +9 -0
- package/templates/cursor/pulse.mdc +144 -0
- package/templates/roles/architect.cursorrules +15 -0
- package/templates/roles/backend.cursorrules +12 -0
- package/templates/roles/frontend.cursorrules +12 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.registerRunCommand = registerRunCommand;
|
|
37
|
+
const artifacts_js_1 = require("../lib/artifacts.js");
|
|
38
|
+
const config_js_1 = require("../lib/config.js");
|
|
39
|
+
const input_js_1 = require("../lib/input.js");
|
|
40
|
+
const paths_js_1 = require("../lib/paths.js");
|
|
41
|
+
const git_js_1 = require("../lib/git.js");
|
|
42
|
+
const notifications_js_1 = require("../lib/notifications.js");
|
|
43
|
+
const clipboard_js_1 = require("../lib/clipboard.js");
|
|
44
|
+
const prompts_js_1 = require("../lib/prompts.js");
|
|
45
|
+
function registerRunCommand(program) {
|
|
46
|
+
program
|
|
47
|
+
.command("run")
|
|
48
|
+
.description("Combined workflow: Start → Watch → Checkpoints → Review")
|
|
49
|
+
.option("-t, --template <id>", "Vorlage: feature, bugfix, refactor, concept, analyze, review")
|
|
50
|
+
.option("--minutes <n>", "Minutes between checkpoint reminders")
|
|
51
|
+
.option("--no-watch", "Don't start watcher")
|
|
52
|
+
.option("--action <text>", "ACTION direkt angeben")
|
|
53
|
+
.option("-C, --clipboard", "Prompt in Zwischenablage kopieren")
|
|
54
|
+
.action(async (opts) => {
|
|
55
|
+
const repoRoot = await (0, paths_js_1.findRepoRoot)(process.cwd());
|
|
56
|
+
if (!repoRoot)
|
|
57
|
+
throw new Error("Nicht in einem Git-Repository.");
|
|
58
|
+
const [state, config] = await Promise.all([(0, artifacts_js_1.loadState)(repoRoot), (0, config_js_1.loadConfig)(repoRoot)]);
|
|
59
|
+
// Use preset checkpoint interval if not specified
|
|
60
|
+
const minutes = opts.minutes
|
|
61
|
+
? Math.max(5, Number(opts.minutes))
|
|
62
|
+
: config.checkpointReminderMinutes ?? 30;
|
|
63
|
+
const presetProfile = config.preset ? `${config.preset}/${state.profile}` : state.profile;
|
|
64
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
65
|
+
// HEADER
|
|
66
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
67
|
+
// eslint-disable-next-line no-console
|
|
68
|
+
console.log(`
|
|
69
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
70
|
+
┃ 🚀 PULSE Run ┃
|
|
71
|
+
┃ Profile: ${presetProfile.padEnd(49)}┃
|
|
72
|
+
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
73
|
+
`);
|
|
74
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
75
|
+
// PHASE 1: Create prompt
|
|
76
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
77
|
+
// eslint-disable-next-line no-console
|
|
78
|
+
console.log(`━━━ PHASE 1: Prompt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
79
|
+
// Template auswählen
|
|
80
|
+
let template = opts.template ? (0, prompts_js_1.getTemplateById)(opts.template) : undefined;
|
|
81
|
+
if (!template && !opts.action) {
|
|
82
|
+
const choices = prompts_js_1.PROMPT_TEMPLATES.map((t) => ({
|
|
83
|
+
value: t.id,
|
|
84
|
+
label: `${t.name} - ${t.description}`,
|
|
85
|
+
}));
|
|
86
|
+
const selectedId = await (0, input_js_1.promptSelect)("📋 Vorlage wählen", choices, "feature");
|
|
87
|
+
template = (0, prompts_js_1.getTemplateById)(selectedId);
|
|
88
|
+
}
|
|
89
|
+
// 6-Elemente sammeln
|
|
90
|
+
const el = {
|
|
91
|
+
role: template?.defaults.role,
|
|
92
|
+
context: template?.defaults.context,
|
|
93
|
+
output: template?.defaults.output,
|
|
94
|
+
action: opts.action,
|
|
95
|
+
};
|
|
96
|
+
const layer = template?.layer ?? state.profile;
|
|
97
|
+
if (!el.action?.trim()) {
|
|
98
|
+
el.action = await (0, input_js_1.promptText)("⚡ ACTION (Was soll gemacht werden?)", "");
|
|
99
|
+
}
|
|
100
|
+
if (!el.context?.trim()) {
|
|
101
|
+
el.context = await (0, input_js_1.promptText)("📍 KONTEXT (Projekt, Stack)", "");
|
|
102
|
+
}
|
|
103
|
+
// Prompt generieren
|
|
104
|
+
const prompt = (0, prompts_js_1.renderSixElementPrompt)(layer, el);
|
|
105
|
+
// Artefakt speichern
|
|
106
|
+
const ts = (0, artifacts_js_1.timestampId)();
|
|
107
|
+
const filename = `${ts}-run.md`;
|
|
108
|
+
const content = [
|
|
109
|
+
`# Pulse Run (${ts})`,
|
|
110
|
+
``,
|
|
111
|
+
`- Profile: **${presetProfile}**`,
|
|
112
|
+
`- Layer: **${layer}**`,
|
|
113
|
+
template ? `- Vorlage: **${template.name}**` : "",
|
|
114
|
+
`- Checkpoint interval: **${minutes} min**`,
|
|
115
|
+
``,
|
|
116
|
+
`## Prompt`,
|
|
117
|
+
``,
|
|
118
|
+
"```",
|
|
119
|
+
prompt.trimEnd(),
|
|
120
|
+
"```",
|
|
121
|
+
``,
|
|
122
|
+
]
|
|
123
|
+
.filter((line) => line !== "")
|
|
124
|
+
.join("\n");
|
|
125
|
+
const artifactPath = await (0, artifacts_js_1.writeArtifact)(repoRoot, "pulses", filename, content);
|
|
126
|
+
// eslint-disable-next-line no-console
|
|
127
|
+
console.log(`✅ Template: ${template?.name ?? "custom"}`);
|
|
128
|
+
// eslint-disable-next-line no-console
|
|
129
|
+
console.log(`✅ Artefakt: ${artifactPath}`);
|
|
130
|
+
// Clipboard
|
|
131
|
+
if (opts.clipboard) {
|
|
132
|
+
const clipMsg = await (0, clipboard_js_1.copyAndNotify)(prompt);
|
|
133
|
+
// eslint-disable-next-line no-console
|
|
134
|
+
console.log(clipMsg);
|
|
135
|
+
}
|
|
136
|
+
// eslint-disable-next-line no-console
|
|
137
|
+
console.log(`\n┌${"─".repeat(58)}┐`);
|
|
138
|
+
// eslint-disable-next-line no-console
|
|
139
|
+
console.log(`│ PROMPT ${opts.clipboard ? "(copied)" : "(copy and paste into Cursor)"}${" ".repeat(opts.clipboard ? 35 : 19)}│`);
|
|
140
|
+
// eslint-disable-next-line no-console
|
|
141
|
+
console.log(`└${"─".repeat(58)}┘\n`);
|
|
142
|
+
// eslint-disable-next-line no-console
|
|
143
|
+
console.log(prompt.trimEnd());
|
|
144
|
+
// eslint-disable-next-line no-console
|
|
145
|
+
console.log(`\n${"─".repeat(60)}\n`);
|
|
146
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
147
|
+
// PHASE 2: Watch Loop
|
|
148
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
149
|
+
if (opts.watch === false) {
|
|
150
|
+
// eslint-disable-next-line no-console
|
|
151
|
+
console.log(`━━━ PHASE 2: Übersprungen ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
152
|
+
// eslint-disable-next-line no-console
|
|
153
|
+
console.log("Watcher not started (--no-watch).\n");
|
|
154
|
+
// eslint-disable-next-line no-console
|
|
155
|
+
console.log("💡 Next steps:");
|
|
156
|
+
// eslint-disable-next-line no-console
|
|
157
|
+
console.log(" 1. Prompt in Cursor einfügen");
|
|
158
|
+
// eslint-disable-next-line no-console
|
|
159
|
+
console.log(" 2. `pulse checkpoint` alle 5-10 Min");
|
|
160
|
+
// eslint-disable-next-line no-console
|
|
161
|
+
console.log(" 3. Bei Problemen: `pulse escalate`");
|
|
162
|
+
// eslint-disable-next-line no-console
|
|
163
|
+
console.log(" 4. Am Ende: `pulse review`\n");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// eslint-disable-next-line no-console
|
|
167
|
+
console.log(`━━━ PHASE 2: Watcher ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
168
|
+
// eslint-disable-next-line no-console
|
|
169
|
+
console.log(`⏱️ Checkpoint interval: ${minutes} min (${config.preset ?? "custom"} preset)`);
|
|
170
|
+
// eslint-disable-next-line no-console
|
|
171
|
+
console.log(`📍 Watcher running... (Ctrl+C to stop)\n`);
|
|
172
|
+
// eslint-disable-next-line no-console
|
|
173
|
+
console.log(` 1. Kopiere den Prompt oben in Cursor`);
|
|
174
|
+
// eslint-disable-next-line no-console
|
|
175
|
+
console.log(` 2. Arbeite los`);
|
|
176
|
+
// eslint-disable-next-line no-console
|
|
177
|
+
console.log(` 3. Ctrl+C wenn fertig\n`);
|
|
178
|
+
await (0, notifications_js_1.notify)(config.notifications, "Pulse Run gestartet", `Checkpoint reminder every ${minutes} min. Ctrl+C to exit.`);
|
|
179
|
+
// Update state
|
|
180
|
+
state.lastCheckpointAt = new Date().toISOString();
|
|
181
|
+
await (0, artifacts_js_1.saveState)(repoRoot, state);
|
|
182
|
+
let checkpointCount = 0;
|
|
183
|
+
let lastReminderAt = Date.now();
|
|
184
|
+
// Polling loop
|
|
185
|
+
const interval = setInterval(async () => {
|
|
186
|
+
const now = Date.now();
|
|
187
|
+
const shouldRemind = now - lastReminderAt >= minutes * 60_000;
|
|
188
|
+
if (!shouldRemind)
|
|
189
|
+
return;
|
|
190
|
+
lastReminderAt = now;
|
|
191
|
+
const status = await (0, git_js_1.gitStatusPorcelain)(repoRoot);
|
|
192
|
+
const dirty = status.trim().length > 0;
|
|
193
|
+
if (dirty) {
|
|
194
|
+
checkpointCount++;
|
|
195
|
+
await (0, notifications_js_1.notify)(config.notifications, `⏱️ Checkpoint #${checkpointCount}`, `${minutes} min passed. Time for: pulse checkpoint`);
|
|
196
|
+
// eslint-disable-next-line no-console
|
|
197
|
+
console.log(`\n┌${"─".repeat(58)}┐`);
|
|
198
|
+
// eslint-disable-next-line no-console
|
|
199
|
+
console.log(`│ ⏰ CHECKPOINT REMINDER #${checkpointCount}${" ".repeat(58 - 26 - String(checkpointCount).length)}│`);
|
|
200
|
+
// eslint-disable-next-line no-console
|
|
201
|
+
console.log(`└${"─".repeat(58)}┘`);
|
|
202
|
+
// eslint-disable-next-line no-console
|
|
203
|
+
console.log(` Zeit: ${new Date().toLocaleTimeString()}`);
|
|
204
|
+
// eslint-disable-next-line no-console
|
|
205
|
+
console.log(` Status: Uncommitted Changes vorhanden`);
|
|
206
|
+
// eslint-disable-next-line no-console
|
|
207
|
+
console.log(` → pulse checkpoint -m 'deine message'\n`);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
// eslint-disable-next-line no-console
|
|
211
|
+
console.log(`\n✨ [${new Date().toLocaleTimeString()}] Repo is clean - no checkpoint needed\n`);
|
|
212
|
+
}
|
|
213
|
+
}, 30_000); // Check every 30 seconds
|
|
214
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
215
|
+
// PHASE 3: Cleanup on exit
|
|
216
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
217
|
+
const cleanup = async (signal) => {
|
|
218
|
+
clearInterval(interval);
|
|
219
|
+
// eslint-disable-next-line no-console
|
|
220
|
+
console.log(`\n\n━━━ PHASE 3: Abschluss ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
221
|
+
// eslint-disable-next-line no-console
|
|
222
|
+
console.log(`🛑 ${signal} empfangen - Beende Pulse Run...\n`);
|
|
223
|
+
// Check final status
|
|
224
|
+
const status = await (0, git_js_1.gitStatusPorcelain)(repoRoot);
|
|
225
|
+
const dirty = status.trim().length > 0;
|
|
226
|
+
if (dirty) {
|
|
227
|
+
// eslint-disable-next-line no-console
|
|
228
|
+
console.log("📝 Uncommitted Changes gefunden:\n");
|
|
229
|
+
const stat = await (0, git_js_1.gitDiffStat)(repoRoot);
|
|
230
|
+
// eslint-disable-next-line no-console
|
|
231
|
+
console.log(stat);
|
|
232
|
+
// eslint-disable-next-line no-console
|
|
233
|
+
console.log("");
|
|
234
|
+
const doCheckpoint = await (0, input_js_1.promptConfirm)("Create checkpoint?", true);
|
|
235
|
+
if (doCheckpoint) {
|
|
236
|
+
const msg = await (0, input_js_1.promptText)("Commit message", "checkpoint: work in progress");
|
|
237
|
+
const { exec } = await Promise.resolve().then(() => __importStar(require("../lib/exec.js")));
|
|
238
|
+
await exec("git", ["add", "-A"], { cwd: repoRoot });
|
|
239
|
+
await exec("git", ["commit", "-m", msg], { cwd: repoRoot });
|
|
240
|
+
// eslint-disable-next-line no-console
|
|
241
|
+
console.log("✅ Committed.\n");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// eslint-disable-next-line no-console
|
|
246
|
+
console.log("✨ Keine uncommitted Changes.\n");
|
|
247
|
+
}
|
|
248
|
+
// Offer review
|
|
249
|
+
const doReview = await (0, input_js_1.promptConfirm)("Create review?", dirty);
|
|
250
|
+
if (doReview) {
|
|
251
|
+
// eslint-disable-next-line no-console
|
|
252
|
+
console.log("\n💡 Führe aus: pulse review\n");
|
|
253
|
+
}
|
|
254
|
+
// Summary
|
|
255
|
+
// eslint-disable-next-line no-console
|
|
256
|
+
console.log(`┌${"─".repeat(58)}┐`);
|
|
257
|
+
// eslint-disable-next-line no-console
|
|
258
|
+
console.log(`│ 👋 Pulse Run beendet${" ".repeat(37)}│`);
|
|
259
|
+
// eslint-disable-next-line no-console
|
|
260
|
+
console.log(`│ │`);
|
|
261
|
+
// eslint-disable-next-line no-console
|
|
262
|
+
console.log(`│ Checkpoints: ${checkpointCount}${" ".repeat(43 - String(checkpointCount).length)}│`);
|
|
263
|
+
// eslint-disable-next-line no-console
|
|
264
|
+
console.log(`│ Artefakt: .pulse/pulses/${filename}${" ".repeat(Math.max(0, 32 - filename.length))}│`);
|
|
265
|
+
// eslint-disable-next-line no-console
|
|
266
|
+
console.log(`└${"─".repeat(58)}┘\n`);
|
|
267
|
+
process.exit(0);
|
|
268
|
+
};
|
|
269
|
+
process.on("SIGINT", () => cleanup("SIGINT"));
|
|
270
|
+
process.on("SIGTERM", () => cleanup("SIGTERM"));
|
|
271
|
+
});
|
|
272
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerStartCommand = registerStartCommand;
|
|
4
|
+
const artifacts_js_1 = require("../lib/artifacts.js");
|
|
5
|
+
const config_js_1 = require("../lib/config.js");
|
|
6
|
+
const input_js_1 = require("../lib/input.js");
|
|
7
|
+
const paths_js_1 = require("../lib/paths.js");
|
|
8
|
+
const clipboard_js_1 = require("../lib/clipboard.js");
|
|
9
|
+
const git_js_1 = require("../lib/git.js");
|
|
10
|
+
const prompts_js_1 = require("../lib/prompts.js");
|
|
11
|
+
function registerStartCommand(program) {
|
|
12
|
+
program
|
|
13
|
+
.command("start")
|
|
14
|
+
.alias("s") // Kurzform: pulse s
|
|
15
|
+
.description("Start a new Pulse with 6-element prompt")
|
|
16
|
+
.option("-t, --template <id>", "Template: feature, bugfix, refactor, concept, analyze, review")
|
|
17
|
+
.option("-q, --quick", "Quick-Mode: Ask only for ACTION")
|
|
18
|
+
.option("--role <text>", "ROLE")
|
|
19
|
+
.option("--context <text>", "CONTEXT")
|
|
20
|
+
.option("--input <text>", "INPUT")
|
|
21
|
+
.option("--action <text>", "ACTION")
|
|
22
|
+
.option("--output <text>", "OUTPUT")
|
|
23
|
+
.option("--examples <text>", "EXAMPLES")
|
|
24
|
+
.option("--ist <text>", "AS-IS state (for AS-IS/TO-BE prompt)")
|
|
25
|
+
.option("--soll <text>", "TO-BE state (for AS-IS/TO-BE prompt)")
|
|
26
|
+
.option("-C, --clipboard", "Copy prompt to clipboard")
|
|
27
|
+
.option("--no-branch-check", "Skip branch check (for MCP/Automation)")
|
|
28
|
+
.action(async (opts) => {
|
|
29
|
+
const repoRoot = await (0, paths_js_1.findRepoRoot)(process.cwd());
|
|
30
|
+
if (!repoRoot)
|
|
31
|
+
throw new Error("Not in a git repository.");
|
|
32
|
+
const [state, config] = await Promise.all([(0, artifacts_js_1.loadState)(repoRoot), (0, config_js_1.loadConfig)(repoRoot)]);
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.log("\n🎯 PULSE Start\n");
|
|
35
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
36
|
+
// Branch check: Warning on main/master (only interactive, not with --quick)
|
|
37
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
38
|
+
const skipBranchCheck = opts.branchCheck === false || opts.quick;
|
|
39
|
+
if (!skipBranchCheck) {
|
|
40
|
+
const currentBranch = await (0, git_js_1.gitCurrentBranch)(repoRoot);
|
|
41
|
+
const isMain = await (0, git_js_1.gitIsMainBranch)(repoRoot);
|
|
42
|
+
if (isMain) {
|
|
43
|
+
// eslint-disable-next-line no-console
|
|
44
|
+
console.log(`⚠️ You are on '${currentBranch}' – Feature branch recommended!\n`);
|
|
45
|
+
const createBranch = await (0, input_js_1.promptConfirm)("Create feature branch?", true);
|
|
46
|
+
if (createBranch) {
|
|
47
|
+
const branchName = await (0, input_js_1.promptText)("Branch name (e.g., feature/user-dashboard)", "feature/");
|
|
48
|
+
if (branchName && branchName !== "feature/") {
|
|
49
|
+
const success = await (0, git_js_1.gitCreateBranch)(repoRoot, branchName);
|
|
50
|
+
if (success) {
|
|
51
|
+
// eslint-disable-next-line no-console
|
|
52
|
+
console.log(`✅ Branch created: ${branchName}\n`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// eslint-disable-next-line no-console
|
|
56
|
+
console.log(`❌ Could not create branch\n`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
console.log(`ℹ️ Working on '${currentBranch}' (not recommended)\n`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
67
|
+
// AS-IS/TO-BE Quick Prompt (for quick bug fixes)
|
|
68
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
69
|
+
if (opts.ist || opts.soll) {
|
|
70
|
+
const ist = opts.ist ?? (await (0, input_js_1.promptText)("AS-IS (current state)", ""));
|
|
71
|
+
const soll = opts.soll ?? (await (0, input_js_1.promptText)("TO-BE (desired state)", ""));
|
|
72
|
+
const error = await (0, input_js_1.promptText)("ERROR log (optional, Enter to skip)", "");
|
|
73
|
+
const prompt = (0, prompts_js_1.renderIstSollPrompt)({ ist, soll, error, context: opts.context });
|
|
74
|
+
await saveAndPrint(repoRoot, "istsoll", prompt, undefined, opts.clipboard);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
78
|
+
// Template selection (interactive or via flag)
|
|
79
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
80
|
+
let template = opts.template ? (0, prompts_js_1.getTemplateById)(opts.template) : undefined;
|
|
81
|
+
let layer = state.profile;
|
|
82
|
+
// If no template and no flags → interactive selection
|
|
83
|
+
if (!template && (0, prompts_js_1.countProvidedElements)(opts) < 2 && !opts.quick) {
|
|
84
|
+
// eslint-disable-next-line no-console
|
|
85
|
+
console.log("What do you want to do?\n");
|
|
86
|
+
const choices = prompts_js_1.PROMPT_TEMPLATES.map((t) => ({
|
|
87
|
+
value: t.id,
|
|
88
|
+
label: `${t.name} - ${t.description}`,
|
|
89
|
+
}));
|
|
90
|
+
const selectedId = await (0, input_js_1.promptSelect)("Choose template", choices, "feature");
|
|
91
|
+
template = (0, prompts_js_1.getTemplateById)(selectedId);
|
|
92
|
+
}
|
|
93
|
+
// Merge template defaults
|
|
94
|
+
const el = {
|
|
95
|
+
role: opts.role ?? template?.defaults.role,
|
|
96
|
+
context: opts.context ?? template?.defaults.context,
|
|
97
|
+
input: opts.input ?? template?.defaults.input,
|
|
98
|
+
action: opts.action ?? template?.defaults.action,
|
|
99
|
+
output: opts.output ?? template?.defaults.output,
|
|
100
|
+
examples: opts.examples ?? template?.defaults.examples,
|
|
101
|
+
};
|
|
102
|
+
if (template) {
|
|
103
|
+
layer = template.layer;
|
|
104
|
+
}
|
|
105
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
106
|
+
// Interaktive Abfrage der fehlenden Elemente
|
|
107
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
108
|
+
if (opts.quick) {
|
|
109
|
+
// Quick Mode: Nur ACTION
|
|
110
|
+
el.action = el.action ?? (await (0, input_js_1.promptText)("⚡ ACTION (what needs to be done?)", ""));
|
|
111
|
+
}
|
|
112
|
+
else if ((0, prompts_js_1.countProvidedElements)(el) < 3) {
|
|
113
|
+
// Guided Mode: Die wichtigsten Elemente abfragen
|
|
114
|
+
// eslint-disable-next-line no-console
|
|
115
|
+
console.log("\n📝 Create 6-element prompt\n");
|
|
116
|
+
if (!el.action?.trim()) {
|
|
117
|
+
el.action = await (0, input_js_1.promptText)("⚡ ACTION (What should the AI do?)", "");
|
|
118
|
+
}
|
|
119
|
+
if (!el.context?.trim()) {
|
|
120
|
+
el.context = await (0, input_js_1.promptText)("📍 CONTEXT (Project, Stack, Situation)", el.context ?? "");
|
|
121
|
+
}
|
|
122
|
+
if (!el.role?.trim()) {
|
|
123
|
+
el.role = await (0, input_js_1.promptText)("👤 ROLE (Who should the AI be?)", el.role ?? "Senior Software Engineer");
|
|
124
|
+
}
|
|
125
|
+
// Optional: Mehr Details?
|
|
126
|
+
const wantMore = await (0, input_js_1.promptText)("Enter more details? (y/n)", "n");
|
|
127
|
+
if (wantMore.toLowerCase() === "j" || wantMore.toLowerCase() === "y") {
|
|
128
|
+
if (!el.input?.trim()) {
|
|
129
|
+
el.input = await (0, input_js_1.promptText)("📥 INPUT (Code, Error, Screenshot description)", "");
|
|
130
|
+
}
|
|
131
|
+
if (!el.output?.trim()) {
|
|
132
|
+
el.output = await (0, input_js_1.promptText)("📤 OUTPUT (What is the expected outcome?)", "");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
137
|
+
// Generate and save prompt
|
|
138
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
139
|
+
const prompt = (0, prompts_js_1.renderSixElementPrompt)(layer, el);
|
|
140
|
+
const actionWarning = (0, prompts_js_1.validateOneAction)(el.action);
|
|
141
|
+
await saveAndPrint(repoRoot, "start", prompt, {
|
|
142
|
+
layer,
|
|
143
|
+
elementCount: (0, prompts_js_1.countProvidedElements)(el),
|
|
144
|
+
actionWarning,
|
|
145
|
+
template: template?.name,
|
|
146
|
+
}, opts.clipboard);
|
|
147
|
+
if (config.enforcement !== "advisory" && actionWarning) {
|
|
148
|
+
// eslint-disable-next-line no-console
|
|
149
|
+
console.log(`\n⚠️ ${actionWarning}`);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// Helper: Save and output
|
|
154
|
+
async function saveAndPrint(repoRoot, type, prompt, meta, clipboard) {
|
|
155
|
+
const ts = (0, artifacts_js_1.timestampId)();
|
|
156
|
+
const filename = `${ts}-${type}.md`;
|
|
157
|
+
const content = [
|
|
158
|
+
`# Pulse: ${type.toUpperCase()} (${ts})`,
|
|
159
|
+
``,
|
|
160
|
+
meta?.layer ? `- Layer: **${meta.layer}**` : "",
|
|
161
|
+
meta?.template ? `- Template: **${meta.template}**` : "",
|
|
162
|
+
meta?.elementCount ? `- Elements: **${meta.elementCount}/6**` : "",
|
|
163
|
+
meta?.actionWarning ? `- ⚠️ ${meta.actionWarning}` : "",
|
|
164
|
+
``,
|
|
165
|
+
`## Prompt (copy and paste into Cursor/ChatGPT)`,
|
|
166
|
+
``,
|
|
167
|
+
"```",
|
|
168
|
+
prompt.trimEnd(),
|
|
169
|
+
"```",
|
|
170
|
+
``,
|
|
171
|
+
`## Tips`,
|
|
172
|
+
`- Observe safeguards: MAX 30 min autonomous`,
|
|
173
|
+
`- Git commit every 5-10 min`,
|
|
174
|
+
`- If stuck: \`pulse escalate\``,
|
|
175
|
+
``,
|
|
176
|
+
]
|
|
177
|
+
.filter((line) => line !== "")
|
|
178
|
+
.join("\n");
|
|
179
|
+
const p = await (0, artifacts_js_1.writeArtifact)(repoRoot, "pulses", filename, content);
|
|
180
|
+
// eslint-disable-next-line no-console
|
|
181
|
+
console.log(`\n✅ Saved: ${p}`);
|
|
182
|
+
// Clipboard
|
|
183
|
+
if (clipboard) {
|
|
184
|
+
const clipboardMsg = await (0, clipboard_js_1.copyAndNotify)(prompt);
|
|
185
|
+
// eslint-disable-next-line no-console
|
|
186
|
+
console.log(clipboardMsg);
|
|
187
|
+
}
|
|
188
|
+
// eslint-disable-next-line no-console
|
|
189
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
190
|
+
// eslint-disable-next-line no-console
|
|
191
|
+
console.log(`\n📋 PROMPT${clipboard ? " (copied)" : " (copy)"}:\n`);
|
|
192
|
+
// eslint-disable-next-line no-console
|
|
193
|
+
console.log(prompt.trimEnd());
|
|
194
|
+
// eslint-disable-next-line no-console
|
|
195
|
+
console.log(`\n${"─".repeat(60)}\n`);
|
|
196
|
+
}
|