agentic-loop 3.13.0 ā 3.14.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/.claude/skills/idea/SKILL.md +56 -0
- package/.claude/skills/loopgram/SKILL.md +19 -0
- package/.claude/skills/prd/SKILL.md +2 -0
- package/README.md +1 -0
- package/bin/ralph.sh +17 -11
- package/dist/loopgram/claude.d.ts +18 -0
- package/dist/loopgram/claude.d.ts.map +1 -0
- package/dist/loopgram/claude.js +89 -0
- package/dist/loopgram/claude.js.map +1 -0
- package/dist/loopgram/context-search.d.ts +26 -0
- package/dist/loopgram/context-search.d.ts.map +1 -0
- package/dist/loopgram/context-search.js +175 -0
- package/dist/loopgram/context-search.js.map +1 -0
- package/dist/loopgram/conversation.d.ts +39 -0
- package/dist/loopgram/conversation.d.ts.map +1 -0
- package/dist/loopgram/conversation.js +158 -0
- package/dist/loopgram/conversation.js.map +1 -0
- package/dist/loopgram/index.d.ts +3 -0
- package/dist/loopgram/index.d.ts.map +1 -0
- package/dist/loopgram/index.js +246 -0
- package/dist/loopgram/index.js.map +1 -0
- package/dist/loopgram/loop-monitor.d.ts +16 -0
- package/dist/loopgram/loop-monitor.d.ts.map +1 -0
- package/dist/loopgram/loop-monitor.js +149 -0
- package/dist/loopgram/loop-monitor.js.map +1 -0
- package/dist/loopgram/loop-runner.d.ts +28 -0
- package/dist/loopgram/loop-runner.d.ts.map +1 -0
- package/dist/loopgram/loop-runner.js +157 -0
- package/dist/loopgram/loop-runner.js.map +1 -0
- package/dist/loopgram/prd-generator.d.ts +37 -0
- package/dist/loopgram/prd-generator.d.ts.map +1 -0
- package/dist/loopgram/prd-generator.js +134 -0
- package/dist/loopgram/prd-generator.js.map +1 -0
- package/dist/loopgram/saver.d.ts +9 -0
- package/dist/loopgram/saver.d.ts.map +1 -0
- package/dist/loopgram/saver.js +35 -0
- package/dist/loopgram/saver.js.map +1 -0
- package/dist/loopgram/types.d.ts +37 -0
- package/dist/loopgram/types.d.ts.map +1 -0
- package/dist/loopgram/types.js +5 -0
- package/dist/loopgram/types.js.map +1 -0
- package/package.json +6 -2
- package/ralph/hooks/common.sh +89 -0
- package/ralph/hooks/warn-debug.sh +14 -32
- package/ralph/hooks/warn-empty-catch.sh +13 -29
- package/ralph/hooks/warn-secrets.sh +19 -37
- package/ralph/hooks/warn-urls.sh +17 -33
- package/ralph/loop.sh +5 -2
- package/ralph/prd-check.sh +35 -8
- package/ralph/setup/quick-setup.sh +25 -12
- package/ralph/setup/ui.sh +0 -42
- package/ralph/setup.sh +71 -46
- package/ralph/utils.sh +167 -31
- package/templates/config/fastmcp.json +6 -1
- package/templates/config/fullstack.json +8 -0
- package/templates/config/node.json +8 -0
- package/templates/config/python.json +8 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { chat, summarize, extractTitle } from './claude.js';
|
|
2
|
+
import { saveIdea, slugify } from './saver.js';
|
|
3
|
+
// Store conversation history per chat (group or DM)
|
|
4
|
+
const conversations = new Map();
|
|
5
|
+
// Store loaded context per chat (from /context command)
|
|
6
|
+
const conversationContexts = new Map();
|
|
7
|
+
// Max history length (20 exchanges = 40 messages)
|
|
8
|
+
const MAX_HISTORY_LENGTH = 40;
|
|
9
|
+
/**
|
|
10
|
+
* Set context for a conversation (from /context command)
|
|
11
|
+
*/
|
|
12
|
+
export function setConversationContext(chatId, context) {
|
|
13
|
+
conversationContexts.set(chatId, context);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get context for a conversation
|
|
17
|
+
*/
|
|
18
|
+
export function getConversationContext(chatId) {
|
|
19
|
+
return conversationContexts.get(chatId);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get conversation history for a chat, creating if needed
|
|
23
|
+
*/
|
|
24
|
+
export function getHistory(chatId) {
|
|
25
|
+
if (!conversations.has(chatId)) {
|
|
26
|
+
conversations.set(chatId, []);
|
|
27
|
+
}
|
|
28
|
+
return conversations.get(chatId);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Clear conversation history for a chat
|
|
32
|
+
*/
|
|
33
|
+
export function clearConversation(chatId) {
|
|
34
|
+
conversations.delete(chatId);
|
|
35
|
+
conversationContexts.delete(chatId);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handle incoming text messages
|
|
39
|
+
*/
|
|
40
|
+
export async function handleMessage(ctx, config, project) {
|
|
41
|
+
const chatId = ctx.chat?.id;
|
|
42
|
+
const message = ctx.message;
|
|
43
|
+
if (!chatId || !message || !('text' in message)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const userMessage = message.text;
|
|
47
|
+
const history = getHistory(chatId);
|
|
48
|
+
// Add user message to history
|
|
49
|
+
history.push({ role: 'user', content: userMessage });
|
|
50
|
+
// Build project context if available
|
|
51
|
+
let projectContext = project
|
|
52
|
+
? `**Project:** ${project.name}\n**Description:** ${project.description || 'No description'}\n**Path:** ${project.path}`
|
|
53
|
+
: undefined;
|
|
54
|
+
// Add loaded context from /context command if available
|
|
55
|
+
const loadedContext = getConversationContext(chatId);
|
|
56
|
+
if (loadedContext && projectContext) {
|
|
57
|
+
projectContext += `\n\n## Codebase Context\n${loadedContext}`;
|
|
58
|
+
}
|
|
59
|
+
else if (loadedContext) {
|
|
60
|
+
projectContext = `## Codebase Context\n${loadedContext}`;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
// Get response from Claude with project context
|
|
64
|
+
const response = await chat(history, config.anthropic.model, projectContext);
|
|
65
|
+
// Add assistant response to history
|
|
66
|
+
history.push({ role: 'assistant', content: response });
|
|
67
|
+
// Trim history if too long
|
|
68
|
+
if (history.length > MAX_HISTORY_LENGTH) {
|
|
69
|
+
history.splice(0, 2);
|
|
70
|
+
}
|
|
71
|
+
await ctx.reply(response);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Error calling Claude:', error);
|
|
75
|
+
await ctx.reply('Sorry, I had trouble processing that. Please try again.');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Handle /save command - summarize and save the conversation
|
|
80
|
+
*/
|
|
81
|
+
export async function handleSaveCommand(ctx, projectPath, config) {
|
|
82
|
+
const chatId = ctx.chat?.id;
|
|
83
|
+
if (!chatId) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (!projectPath) {
|
|
87
|
+
await ctx.reply('This group is not configured for a project. ' +
|
|
88
|
+
'Add this group ID to ~/.config/ralph/brainstorm.json');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const history = getHistory(chatId);
|
|
92
|
+
if (history.length < 2) {
|
|
93
|
+
await ctx.reply('Nothing to save yet. Start a conversation first!');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
await ctx.reply('Summarizing conversation...');
|
|
98
|
+
// Generate summary
|
|
99
|
+
const summary = await summarize(history, config.anthropic.model);
|
|
100
|
+
// Extract title and create filename
|
|
101
|
+
const title = extractTitle(summary);
|
|
102
|
+
const filename = slugify(title);
|
|
103
|
+
// Save to project
|
|
104
|
+
const filepath = saveIdea(projectPath, filename, summary);
|
|
105
|
+
// Report success
|
|
106
|
+
const shortSummary = summary.length > 500 ? summary.slice(0, 500) + '...' : summary;
|
|
107
|
+
await ctx.reply(`ā
Saved to ${filepath}\n\n${shortSummary}`);
|
|
108
|
+
// Clear conversation after saving
|
|
109
|
+
clearConversation(chatId);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error('Error saving idea:', error);
|
|
113
|
+
await ctx.reply('Sorry, I had trouble saving that. Please try again.');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Handle /clear command - clear conversation history
|
|
118
|
+
*/
|
|
119
|
+
export function handleClearCommand(ctx) {
|
|
120
|
+
const chatId = ctx.chat?.id;
|
|
121
|
+
if (chatId) {
|
|
122
|
+
clearConversation(chatId);
|
|
123
|
+
ctx.reply('Conversation cleared. Start fresh!');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Handle /projects command - list configured projects
|
|
128
|
+
*/
|
|
129
|
+
export function handleProjectsCommand(ctx, config) {
|
|
130
|
+
const projects = Object.values(config.projects);
|
|
131
|
+
if (projects.length === 0) {
|
|
132
|
+
ctx.reply('No projects configured yet. Add them to ~/.config/ralph/brainstorm.json');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const list = projects.map((p) => `⢠${p.name}: ${p.path}`).join('\n');
|
|
136
|
+
ctx.reply(`Configured projects:\n${list}`);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Handle /status command - show current conversation status
|
|
140
|
+
*/
|
|
141
|
+
export function handleStatusCommand(ctx, projectPath, config) {
|
|
142
|
+
const chatId = ctx.chat?.id;
|
|
143
|
+
if (!chatId) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const history = getHistory(chatId);
|
|
147
|
+
const project = projectPath
|
|
148
|
+
? Object.values(config.projects).find((p) => p.path === projectPath)
|
|
149
|
+
: null;
|
|
150
|
+
const lines = [
|
|
151
|
+
`š **Status**`,
|
|
152
|
+
`Messages: ${history.length}`,
|
|
153
|
+
`Project: ${project?.name || 'Not configured'}`,
|
|
154
|
+
`Model: ${config.anthropic.model}`,
|
|
155
|
+
];
|
|
156
|
+
ctx.reply(lines.join('\n'));
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=conversation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/loopgram/conversation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE/C,oDAAoD;AACpD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAqB,CAAC;AAEnD,wDAAwD;AACxD,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEvD,kDAAkD;AAClD,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc,EAAE,OAAe;IACpE,oBAAoB,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,OAAO,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,aAAa,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAY,EACZ,MAAwB,EACxB,OAA6B;IAE7B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAE5B,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,IAAI,OAAO,CAAC,EAAE,CAAC;QAChD,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEnC,8BAA8B;IAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IAErD,qCAAqC;IACrC,IAAI,cAAc,GAAG,OAAO;QAC1B,CAAC,CAAC,gBAAgB,OAAO,CAAC,IAAI,sBAAsB,OAAO,CAAC,WAAW,IAAI,gBAAgB,eAAe,OAAO,CAAC,IAAI,EAAE;QACxH,CAAC,CAAC,SAAS,CAAC;IAEd,wDAAwD;IACxD,MAAM,aAAa,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACrD,IAAI,aAAa,IAAI,cAAc,EAAE,CAAC;QACpC,cAAc,IAAI,4BAA4B,aAAa,EAAE,CAAC;IAChE,CAAC;SAAM,IAAI,aAAa,EAAE,CAAC;QACzB,cAAc,GAAG,wBAAwB,aAAa,EAAE,CAAC;IAC3D,CAAC;IAED,IAAI,CAAC;QACH,gDAAgD;QAChD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QAE7E,oCAAoC;QACpC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEvD,2BAA2B;QAC3B,IAAI,OAAO,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;YACxC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACvB,CAAC;QAED,MAAM,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,GAAG,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAY,EACZ,WAA0B,EAC1B,MAAwB;IAExB,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,GAAG,CAAC,KAAK,CACb,8CAA8C;YAC5C,sDAAsD,CACzD,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEnC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAE/C,mBAAmB;QACnB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAEjE,oCAAoC;QACpC,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAEhC,kBAAkB;QAClB,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE1D,iBAAiB;QACjB,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;QACpF,MAAM,GAAG,CAAC,KAAK,CAAC,cAAc,QAAQ,OAAO,YAAY,EAAE,CAAC,CAAC;QAE7D,kCAAkC;QAClC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QAC3C,MAAM,GAAG,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;IAC5B,IAAI,MAAM,EAAE,CAAC;QACX,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC1B,GAAG,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAY,EACZ,MAAwB;IAExB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEhD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,GAAG,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;QACrF,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,GAAG,CAAC,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAY,EACZ,WAA0B,EAC1B,MAAwB;IAExB,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,WAAW;QACzB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;QACpE,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,KAAK,GAAG;QACZ,eAAe;QACf,aAAa,OAAO,CAAC,MAAM,EAAE;QAC7B,YAAY,OAAO,EAAE,IAAI,IAAI,gBAAgB,EAAE;QAC/C,UAAU,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE;KACnC,CAAC;IAEF,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loopgram/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { Telegraf } from 'telegraf';
|
|
3
|
+
import { readFileSync, existsSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { handleMessage, handleSaveCommand, handleClearCommand, handleProjectsCommand, handleStatusCommand, setConversationContext, getConversationContext, getHistory, clearConversation, } from './conversation.js';
|
|
6
|
+
import { parseProgressFile, formatLoopStatus } from './loop-monitor.js';
|
|
7
|
+
import { getTopicContext } from './context-search.js';
|
|
8
|
+
import { generateStories, appendToPRD } from './prd-generator.js';
|
|
9
|
+
import { startLoop, stopLoop } from './loop-runner.js';
|
|
10
|
+
// Load configuration
|
|
11
|
+
function loadConfig() {
|
|
12
|
+
const configPath = join(process.env.HOME || '', '.config/ralph/loopgram.json');
|
|
13
|
+
if (!existsSync(configPath)) {
|
|
14
|
+
console.error(`Config file not found: ${configPath}`);
|
|
15
|
+
console.error('Create it with your Telegram user ID and project mappings.');
|
|
16
|
+
console.error('See setup instructions in the README.');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error(`Error reading config: ${error}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Get project config for a chat ID
|
|
29
|
+
function getProject(chatId, config) {
|
|
30
|
+
return config.projects[chatId] || null;
|
|
31
|
+
}
|
|
32
|
+
// Get project path for a chat ID
|
|
33
|
+
function getProjectPath(chatId, config) {
|
|
34
|
+
const project = config.projects[chatId];
|
|
35
|
+
return project?.path || null;
|
|
36
|
+
}
|
|
37
|
+
// Main entry point
|
|
38
|
+
async function main() {
|
|
39
|
+
// Check for bot token
|
|
40
|
+
const token = process.env.TELEGRAM_BOT_TOKEN;
|
|
41
|
+
if (!token) {
|
|
42
|
+
console.error('TELEGRAM_BOT_TOKEN environment variable is required');
|
|
43
|
+
console.error('Set it in ~/.config/ralph/secrets and source the file');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
// Check for Anthropic API key
|
|
47
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
48
|
+
console.error('ANTHROPIC_API_KEY environment variable is required');
|
|
49
|
+
console.error('Set it in ~/.config/ralph/secrets and source the file');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const config = loadConfig();
|
|
53
|
+
const bot = new Telegraf(token);
|
|
54
|
+
// Security middleware: only respond to allowed users
|
|
55
|
+
bot.use((ctx, next) => {
|
|
56
|
+
const userId = ctx.from?.id.toString();
|
|
57
|
+
if (!userId || !config.telegram.allowedUserIds.includes(userId)) {
|
|
58
|
+
// Silently ignore messages from unauthorized users
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
return next();
|
|
62
|
+
});
|
|
63
|
+
// Logging middleware: log unknown group IDs for easy config setup
|
|
64
|
+
bot.use((ctx, next) => {
|
|
65
|
+
const chatId = ctx.chat?.id.toString();
|
|
66
|
+
if (chatId && !config.projects[chatId]) {
|
|
67
|
+
console.log(`Unknown chat ID: ${chatId} - add to config to enable`);
|
|
68
|
+
}
|
|
69
|
+
return next();
|
|
70
|
+
});
|
|
71
|
+
// Command handlers
|
|
72
|
+
bot.command('save', (ctx) => {
|
|
73
|
+
const chatId = ctx.chat?.id.toString();
|
|
74
|
+
const projectPath = chatId ? getProjectPath(chatId, config) : null;
|
|
75
|
+
return handleSaveCommand(ctx, projectPath, config);
|
|
76
|
+
});
|
|
77
|
+
bot.command('clear', handleClearCommand);
|
|
78
|
+
bot.command('projects', (ctx) => handleProjectsCommand(ctx, config));
|
|
79
|
+
bot.command('status', (ctx) => {
|
|
80
|
+
const chatId = ctx.chat?.id.toString();
|
|
81
|
+
const projectPath = chatId ? getProjectPath(chatId, config) : null;
|
|
82
|
+
return handleStatusCommand(ctx, projectPath, config);
|
|
83
|
+
});
|
|
84
|
+
bot.command('help', (ctx) => {
|
|
85
|
+
ctx.reply(`š± **Loopgram**\n\n` +
|
|
86
|
+
`Your mobile connection to agentic-loop.\n\n` +
|
|
87
|
+
`**Workflow:**\n` +
|
|
88
|
+
`/context <topic> - Load codebase context\n` +
|
|
89
|
+
`(chat about your idea)\n` +
|
|
90
|
+
`/prd - Generate stories from conversation\n` +
|
|
91
|
+
`/start-loop - Start Ralph to execute stories\n` +
|
|
92
|
+
`/loop - Check Ralph progress\n` +
|
|
93
|
+
`/stop-loop - Stop Ralph loop\n\n` +
|
|
94
|
+
`**Other:**\n` +
|
|
95
|
+
`/save - Save conversation as idea file\n` +
|
|
96
|
+
`/clear - Clear conversation history\n` +
|
|
97
|
+
`/status - Show current session info\n` +
|
|
98
|
+
`/projects - List configured projects\n` +
|
|
99
|
+
`/help - Show this message`);
|
|
100
|
+
});
|
|
101
|
+
// /loop command - check Ralph loop status
|
|
102
|
+
bot.command('loop', (ctx) => {
|
|
103
|
+
const chatId = ctx.chat?.id.toString();
|
|
104
|
+
const project = chatId ? getProject(chatId, config) : null;
|
|
105
|
+
if (!project) {
|
|
106
|
+
ctx.reply('This chat is not configured for a project.');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const status = parseProgressFile(project.path);
|
|
110
|
+
if (!status) {
|
|
111
|
+
ctx.reply(`No Ralph loop running in ${project.name}. Start one with /start-loop`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
ctx.reply(formatLoopStatus(status, project.name));
|
|
115
|
+
});
|
|
116
|
+
// /prd command - generate stories from conversation
|
|
117
|
+
bot.command('prd', async (ctx) => {
|
|
118
|
+
const chatId = ctx.chat?.id;
|
|
119
|
+
const chatIdStr = chatId?.toString();
|
|
120
|
+
const project = chatIdStr ? getProject(chatIdStr, config) : null;
|
|
121
|
+
if (!project || !chatId) {
|
|
122
|
+
ctx.reply('This chat is not configured for a project.');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const history = getHistory(chatId);
|
|
126
|
+
if (history.length < 2) {
|
|
127
|
+
ctx.reply('Nothing to generate. Start a conversation first!');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
await ctx.reply('š Generating stories from conversation...');
|
|
131
|
+
try {
|
|
132
|
+
const context = getConversationContext(chatId);
|
|
133
|
+
const { featureName, featureDescription, stories } = await generateStories(history, context, config.anthropic.model);
|
|
134
|
+
const { added, total } = appendToPRD(project.path, featureName, featureDescription, stories);
|
|
135
|
+
// Format story list
|
|
136
|
+
const storyList = stories.map((s) => `⢠${s.title}`).join('\n');
|
|
137
|
+
await ctx.reply(`ā
Added ${added} stories to PRD (${total} total)\n\n` +
|
|
138
|
+
`**${featureName}**\n${storyList}\n\n` +
|
|
139
|
+
`Use /start-loop to execute.`);
|
|
140
|
+
// Clear conversation after generating PRD
|
|
141
|
+
clearConversation(chatId);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
console.error('PRD generation error:', error);
|
|
145
|
+
await ctx.reply('Error generating stories. Check the logs.');
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
// /start-loop command - start Ralph loop
|
|
149
|
+
bot.command('start_loop', (ctx) => {
|
|
150
|
+
const chatId = ctx.chat?.id.toString();
|
|
151
|
+
const project = chatId ? getProject(chatId, config) : null;
|
|
152
|
+
if (!project) {
|
|
153
|
+
ctx.reply('This chat is not configured for a project.');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const result = startLoop(project.path);
|
|
157
|
+
if (result.success) {
|
|
158
|
+
ctx.reply(`š ${result.message}`);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
ctx.reply(`ā ${result.message}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
// /stop-loop command - stop Ralph loop
|
|
165
|
+
bot.command('stop_loop', (ctx) => {
|
|
166
|
+
const chatId = ctx.chat?.id.toString();
|
|
167
|
+
const project = chatId ? getProject(chatId, config) : null;
|
|
168
|
+
if (!project) {
|
|
169
|
+
ctx.reply('This chat is not configured for a project.');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const result = stopLoop(project.path);
|
|
173
|
+
if (result.success) {
|
|
174
|
+
ctx.reply(`ā
${result.message}`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
ctx.reply(`ā ${result.message}`);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
// /context command - search codebase for a topic
|
|
181
|
+
bot.command('context', async (ctx) => {
|
|
182
|
+
const chatId = ctx.chat?.id.toString();
|
|
183
|
+
const project = chatId ? getProject(chatId, config) : null;
|
|
184
|
+
if (!project) {
|
|
185
|
+
ctx.reply('This chat is not configured for a project.');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
// Extract topic from command
|
|
189
|
+
const text = ctx.message?.text || '';
|
|
190
|
+
const topic = text.replace(/^\/context\s*/i, '').trim();
|
|
191
|
+
if (!topic) {
|
|
192
|
+
ctx.reply('Usage: /context <topic>\nExample: /context authentication');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
await ctx.reply(`š Searching ${project.name} for "${topic}"...`);
|
|
196
|
+
try {
|
|
197
|
+
const { summary, filesFound, searchTerms } = await getTopicContext(project.path, project.name, topic, config.anthropic.model);
|
|
198
|
+
// Store this context for the conversation
|
|
199
|
+
if (chatId) {
|
|
200
|
+
setConversationContext(parseInt(chatId), summary);
|
|
201
|
+
}
|
|
202
|
+
let response = `š Searched for: ${searchTerms.join(', ')}\n\n`;
|
|
203
|
+
response += `š Found ${filesFound.length} files:\n`;
|
|
204
|
+
response += filesFound.slice(0, 5).map(f => `⢠${f}`).join('\n');
|
|
205
|
+
if (filesFound.length > 5) {
|
|
206
|
+
response += `\n...and ${filesFound.length - 5} more`;
|
|
207
|
+
}
|
|
208
|
+
response += `\n\n${summary}`;
|
|
209
|
+
response += `\n\nš” Context loaded! Now brainstorm away.`;
|
|
210
|
+
await ctx.reply(response);
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
console.error('Context search error:', error);
|
|
214
|
+
await ctx.reply('Error searching codebase. Check the logs.');
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
// Handle regular text messages
|
|
218
|
+
bot.on('text', (ctx) => {
|
|
219
|
+
const chatId = ctx.chat?.id.toString();
|
|
220
|
+
const project = chatId ? getProject(chatId, config) : null;
|
|
221
|
+
return handleMessage(ctx, config, project);
|
|
222
|
+
});
|
|
223
|
+
// Start the bot
|
|
224
|
+
console.log('š± Loopgram starting...');
|
|
225
|
+
console.log(`Model: ${config.anthropic.model}`);
|
|
226
|
+
console.log(`Configured projects: ${Object.values(config.projects)
|
|
227
|
+
.map((p) => p.name)
|
|
228
|
+
.join(', ') || 'none'}`);
|
|
229
|
+
console.log(`Allowed users: ${config.telegram.allowedUserIds.length} configured`);
|
|
230
|
+
await bot.launch();
|
|
231
|
+
console.log('ā
Loopgram running! Send messages in Telegram.');
|
|
232
|
+
// Graceful shutdown
|
|
233
|
+
process.once('SIGINT', () => {
|
|
234
|
+
console.log('\nShutting down...');
|
|
235
|
+
bot.stop('SIGINT');
|
|
236
|
+
});
|
|
237
|
+
process.once('SIGTERM', () => {
|
|
238
|
+
console.log('\nShutting down...');
|
|
239
|
+
bot.stop('SIGTERM');
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
main().catch((error) => {
|
|
243
|
+
console.error('Fatal error:', error);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
});
|
|
246
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/loopgram/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LoopStatus } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse the Ralph progress file to get loop status
|
|
4
|
+
* Format: [ISO-timestamp] STATUS story_id message
|
|
5
|
+
* Statuses: COMPLETED, FAILED, CLI_CRASH, TIMEOUT, BLOCKED
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseProgressFile(projectPath: string): LoopStatus | null;
|
|
8
|
+
/**
|
|
9
|
+
* Format loop status for Telegram message
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatLoopStatus(status: LoopStatus, projectName: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Watch a project's progress file for changes
|
|
14
|
+
*/
|
|
15
|
+
export declare function watchProgress(projectPath: string, _projectName: string, onUpdate: (status: LoopStatus, changeType: 'started' | 'completed' | 'error' | 'update') => void): () => void;
|
|
16
|
+
//# sourceMappingURL=loop-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-monitor.d.ts","sourceRoot":"","sources":["../../src/loopgram/loop-monitor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK7C;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA6ExE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAyBhF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,KAAK,IAAI,GAC/F,MAAM,IAAI,CAiDZ"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { readFileSync, existsSync, watchFile, unwatchFile } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
// Track last known state per project to detect changes
|
|
4
|
+
const lastState = new Map();
|
|
5
|
+
/**
|
|
6
|
+
* Parse the Ralph progress file to get loop status
|
|
7
|
+
* Format: [ISO-timestamp] STATUS story_id message
|
|
8
|
+
* Statuses: COMPLETED, FAILED, CLI_CRASH, TIMEOUT, BLOCKED
|
|
9
|
+
*/
|
|
10
|
+
export function parseProgressFile(projectPath) {
|
|
11
|
+
const progressPath = join(projectPath, '.ralph/progress.txt');
|
|
12
|
+
if (!existsSync(progressPath)) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const content = readFileSync(progressPath, 'utf-8');
|
|
17
|
+
const lines = content.split('\n').filter(Boolean);
|
|
18
|
+
// Only look at recent lines (last 50)
|
|
19
|
+
const recentLines = lines.slice(-50);
|
|
20
|
+
const errors = [];
|
|
21
|
+
const completedStoryIds = new Set();
|
|
22
|
+
let currentStory = null;
|
|
23
|
+
let lastUpdate = '';
|
|
24
|
+
let isRunning = false;
|
|
25
|
+
let hasRalphActivity = false;
|
|
26
|
+
// Ralph log format: [timestamp] STATUS story_id message
|
|
27
|
+
const logPattern = /^\[([^\]]+)\]\s+(COMPLETED|FAILED|CLI_CRASH|TIMEOUT|BLOCKED)\s+(\S+)(.*)$/;
|
|
28
|
+
for (const line of recentLines) {
|
|
29
|
+
const match = line.match(logPattern);
|
|
30
|
+
if (match) {
|
|
31
|
+
hasRalphActivity = true;
|
|
32
|
+
const [, timestamp, status, storyId, message] = match;
|
|
33
|
+
lastUpdate = timestamp;
|
|
34
|
+
if (status === 'COMPLETED') {
|
|
35
|
+
completedStoryIds.add(storyId);
|
|
36
|
+
if (currentStory === storyId) {
|
|
37
|
+
currentStory = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (status === 'FAILED' || status === 'CLI_CRASH' || status === 'TIMEOUT') {
|
|
41
|
+
errors.push(`${status} ${storyId}${message}`.trim());
|
|
42
|
+
currentStory = storyId; // Still working on this story
|
|
43
|
+
isRunning = true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Check for loop start/end markers
|
|
47
|
+
if (line.includes('Loop starting') || line.includes('Starting loop')) {
|
|
48
|
+
isRunning = true;
|
|
49
|
+
hasRalphActivity = true;
|
|
50
|
+
}
|
|
51
|
+
if (line.includes('Loop complete') || line.includes('All stories done')) {
|
|
52
|
+
isRunning = false;
|
|
53
|
+
}
|
|
54
|
+
// Try to get total stories
|
|
55
|
+
const totalMatch = line.match(/(\d+)\s*(?:stories|story)/i);
|
|
56
|
+
if (totalMatch) {
|
|
57
|
+
// Don't overwrite with smaller numbers
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// If no Ralph activity found, return null
|
|
61
|
+
if (!hasRalphActivity) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
isRunning,
|
|
66
|
+
currentStory,
|
|
67
|
+
completedStories: completedStoryIds.size,
|
|
68
|
+
totalStories: 0, // Would need to read PRD to know this
|
|
69
|
+
lastUpdate,
|
|
70
|
+
errors: errors.slice(-3),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Error parsing progress file:', error);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Format loop status for Telegram message
|
|
80
|
+
*/
|
|
81
|
+
export function formatLoopStatus(status, projectName) {
|
|
82
|
+
const statusEmoji = status.isRunning ? 'š' : 'ā
';
|
|
83
|
+
const progress = status.totalStories > 0
|
|
84
|
+
? `${status.completedStories}/${status.totalStories}`
|
|
85
|
+
: `${status.completedStories} done`;
|
|
86
|
+
let message = `${statusEmoji} **${projectName}**\n`;
|
|
87
|
+
message += `Progress: ${progress}\n`;
|
|
88
|
+
if (status.currentStory) {
|
|
89
|
+
message += `Current: ${status.currentStory}\n`;
|
|
90
|
+
}
|
|
91
|
+
if (status.lastUpdate) {
|
|
92
|
+
message += `Updated: ${status.lastUpdate}\n`;
|
|
93
|
+
}
|
|
94
|
+
if (status.errors.length > 0) {
|
|
95
|
+
message += `\nā ļø Recent errors:\n`;
|
|
96
|
+
for (const err of status.errors) {
|
|
97
|
+
message += `⢠${err.substring(0, 100)}...\n`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return message;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Watch a project's progress file for changes
|
|
104
|
+
*/
|
|
105
|
+
export function watchProgress(projectPath, _projectName, onUpdate) {
|
|
106
|
+
const progressPath = join(projectPath, '.ralph/progress.txt');
|
|
107
|
+
if (!existsSync(progressPath)) {
|
|
108
|
+
return () => { }; // No-op cleanup
|
|
109
|
+
}
|
|
110
|
+
// Store initial state
|
|
111
|
+
const initialContent = readFileSync(progressPath, 'utf-8');
|
|
112
|
+
lastState.set(projectPath, initialContent);
|
|
113
|
+
const checkForChanges = () => {
|
|
114
|
+
try {
|
|
115
|
+
const currentContent = readFileSync(progressPath, 'utf-8');
|
|
116
|
+
const previousContent = lastState.get(projectPath) || '';
|
|
117
|
+
if (currentContent !== previousContent) {
|
|
118
|
+
lastState.set(projectPath, currentContent);
|
|
119
|
+
const status = parseProgressFile(projectPath);
|
|
120
|
+
if (!status)
|
|
121
|
+
return;
|
|
122
|
+
// Determine change type
|
|
123
|
+
let changeType = 'update';
|
|
124
|
+
const newLines = currentContent.substring(previousContent.length);
|
|
125
|
+
if (newLines.includes('ā') || newLines.includes('completed')) {
|
|
126
|
+
changeType = 'completed';
|
|
127
|
+
}
|
|
128
|
+
else if (newLines.includes('ā') || newLines.includes('ERROR')) {
|
|
129
|
+
changeType = 'error';
|
|
130
|
+
}
|
|
131
|
+
else if (newLines.includes('Starting') || newLines.includes('ā¶')) {
|
|
132
|
+
changeType = 'started';
|
|
133
|
+
}
|
|
134
|
+
onUpdate(status, changeType);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
// File might be temporarily unavailable during write
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
// Watch for changes
|
|
142
|
+
watchFile(progressPath, { interval: 5000 }, checkForChanges);
|
|
143
|
+
// Return cleanup function
|
|
144
|
+
return () => {
|
|
145
|
+
unwatchFile(progressPath);
|
|
146
|
+
lastState.delete(projectPath);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=loop-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-monitor.js","sourceRoot":"","sources":["../../src/loopgram/loop-monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a Ralph loop is currently running for a project
|
|
3
|
+
*/
|
|
4
|
+
export declare function isLoopRunning(projectPath: string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Start a Ralph loop for a project
|
|
7
|
+
*/
|
|
8
|
+
export declare function startLoop(projectPath: string): {
|
|
9
|
+
success: boolean;
|
|
10
|
+
message: string;
|
|
11
|
+
pid?: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Stop a running Ralph loop
|
|
15
|
+
*/
|
|
16
|
+
export declare function stopLoop(projectPath: string): {
|
|
17
|
+
success: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Get loop process info
|
|
22
|
+
*/
|
|
23
|
+
export declare function getLoopInfo(projectPath: string): {
|
|
24
|
+
running: boolean;
|
|
25
|
+
pid?: number;
|
|
26
|
+
logTail?: string;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=loop-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-runner.d.ts","sourceRoot":"","sources":["../../src/loopgram/loop-runner.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAsB1D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAyDA;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CA0CA;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CA2BA"}
|