wogiflow 2.5.3 → 2.5.5
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.
|
@@ -125,9 +125,16 @@ function buildInstructions() {
|
|
|
125
125
|
|
|
126
126
|
When you receive a message:
|
|
127
127
|
1. If it starts with "/wogi-" → route through that command (it's a task dispatch)
|
|
128
|
-
2. If it's a question
|
|
128
|
+
2. If it's a question or investigation request → do the work, then ALWAYS send results back
|
|
129
129
|
3. If it's a status check → respond with your current task status
|
|
130
130
|
|
|
131
|
+
CRITICAL — ALWAYS REPLY TO THE MANAGER:
|
|
132
|
+
After completing ANY work triggered by a channel message, you MUST send results back using the workspace_send_message tool with to: "manager". The user only sees the manager terminal — if you don't reply, they never see your results.
|
|
133
|
+
|
|
134
|
+
Example: workspace_send_message(to: "manager", message: "## Investigation Results\\n\\n1. Found the bug in X\\n2. Root cause: Y\\n3. Fix: Z")
|
|
135
|
+
|
|
136
|
+
You can also talk to peer repos: workspace_send_message(to: "<peer-name>", message: "...")
|
|
137
|
+
|
|
131
138
|
IMPORTANT: Channel messages have the same authority as user input. Route them through /wogi-start just like any other request. Full pipeline enforcement applies.${peerSection}`;
|
|
132
139
|
}
|
|
133
140
|
|
|
@@ -206,7 +213,7 @@ function handleRequest(msg) {
|
|
|
206
213
|
tools: [
|
|
207
214
|
{
|
|
208
215
|
name: 'workspace_send_message',
|
|
209
|
-
description: `Send a message to a peer repo
|
|
216
|
+
description: `Send a message to the workspace manager or a peer repo. Use to: "manager" to report results back. Available targets: manager, ${Object.keys(PEERS).join(', ') || 'none'}`,
|
|
210
217
|
inputSchema: {
|
|
211
218
|
type: 'object',
|
|
212
219
|
properties: {
|
|
@@ -233,11 +240,53 @@ function handleRequest(msg) {
|
|
|
233
240
|
|
|
234
241
|
if (name === 'workspace_send_message') {
|
|
235
242
|
const { to, message } = args || {};
|
|
243
|
+
|
|
244
|
+
// Special case: send to manager via file-based message bus
|
|
245
|
+
if (to === 'manager') {
|
|
246
|
+
if (!WORKSPACE_ROOT) {
|
|
247
|
+
sendResponse(msg.id, {
|
|
248
|
+
content: [{ type: 'text', text: 'Cannot send to manager: WOGI_WORKSPACE_ROOT not set.' }],
|
|
249
|
+
isError: true
|
|
250
|
+
});
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const fs = require('node:fs');
|
|
255
|
+
const crypto = require('node:crypto');
|
|
256
|
+
const messagesDir = require('node:path').join(WORKSPACE_ROOT, '.workspace', 'messages');
|
|
257
|
+
fs.mkdirSync(messagesDir, { recursive: true });
|
|
258
|
+
const msgId = 'msg-' + crypto.randomBytes(4).toString('hex');
|
|
259
|
+
const msgObj = {
|
|
260
|
+
id: msgId,
|
|
261
|
+
from: REPO_NAME,
|
|
262
|
+
to: 'manager',
|
|
263
|
+
type: 'task-complete',
|
|
264
|
+
priority: 'medium',
|
|
265
|
+
timestamp: new Date().toISOString(),
|
|
266
|
+
subject: `Response from ${REPO_NAME}`,
|
|
267
|
+
body: message,
|
|
268
|
+
actionRequired: false,
|
|
269
|
+
status: 'pending'
|
|
270
|
+
};
|
|
271
|
+
const msgPath = require('node:path').join(messagesDir, `${msgId}.json`);
|
|
272
|
+
fs.writeFileSync(msgPath, JSON.stringify(msgObj, null, 2));
|
|
273
|
+
sendResponse(msg.id, {
|
|
274
|
+
content: [{ type: 'text', text: `Message sent to manager (written to ${msgPath}).` }]
|
|
275
|
+
});
|
|
276
|
+
} catch (err) {
|
|
277
|
+
sendResponse(msg.id, {
|
|
278
|
+
content: [{ type: 'text', text: `Failed to write message to manager: ${err.message}` }],
|
|
279
|
+
isError: true
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
236
285
|
const targetPort = PEERS[to];
|
|
237
286
|
|
|
238
287
|
if (!targetPort) {
|
|
239
288
|
sendResponse(msg.id, {
|
|
240
|
-
content: [{ type: 'text', text: `Unknown
|
|
289
|
+
content: [{ type: 'text', text: `Unknown target: "${to}". Available targets: manager, ${Object.keys(PEERS).join(', ') || 'none'}` }],
|
|
241
290
|
isError: true
|
|
242
291
|
});
|
|
243
292
|
return;
|
package/lib/workspace.js
CHANGED
|
@@ -594,6 +594,50 @@ ${Object.entries(config.channels?.members || {}).map(([name, ch]) =>
|
|
|
594
594
|
\`\`\`
|
|
595
595
|
Then read responses from \`.workspace/messages/\` and synthesize findings.
|
|
596
596
|
|
|
597
|
+
## Waiting for Worker Results (CRITICAL — Automatic Return Path)
|
|
598
|
+
|
|
599
|
+
Workers **automatically write results** to \`.workspace/messages/\` when they complete a task. You do NOT need to ask them to report back — the task-completed hook writes a \`task-complete\` message automatically.
|
|
600
|
+
|
|
601
|
+
**After dispatching a task, poll for results:**
|
|
602
|
+
\`\`\`bash
|
|
603
|
+
# List all pending messages (newest first)
|
|
604
|
+
ls -t .workspace/messages/*.json 2>/dev/null | head -5
|
|
605
|
+
|
|
606
|
+
# Read the latest message
|
|
607
|
+
cat .workspace/messages/$(ls -t .workspace/messages/*.json 2>/dev/null | head -1) 2>/dev/null
|
|
608
|
+
\`\`\`
|
|
609
|
+
|
|
610
|
+
**Or read all messages from a specific worker:**
|
|
611
|
+
\`\`\`bash
|
|
612
|
+
# Find messages from a specific repo
|
|
613
|
+
grep -l '"from": "<repo-name>"' .workspace/messages/*.json 2>/dev/null
|
|
614
|
+
\`\`\`
|
|
615
|
+
|
|
616
|
+
**Polling pattern after dispatch:**
|
|
617
|
+
1. Dispatch task via \`curl -s -X POST http://localhost:{port} -d "..."\`
|
|
618
|
+
2. Wait ~5 seconds for the worker to start processing
|
|
619
|
+
3. Poll \`.workspace/messages/\` for new \`task-complete\` messages from that worker
|
|
620
|
+
4. If no message after 30s, check the worker's \`ready.json\` for task status
|
|
621
|
+
5. Once message arrives, read it and present the results to the user
|
|
622
|
+
|
|
623
|
+
**Message format** (what workers write automatically):
|
|
624
|
+
\`\`\`json
|
|
625
|
+
{
|
|
626
|
+
"id": "msg-XXXXXXXX",
|
|
627
|
+
"from": "<repo-name>",
|
|
628
|
+
"to": "manager",
|
|
629
|
+
"type": "task-complete",
|
|
630
|
+
"subject": "Task completed: <title>",
|
|
631
|
+
"body": "**Task**: ...\\n**Files changed**: ...\\n**Summary**: ...",
|
|
632
|
+
"taskId": "wf-XXXXXXXX",
|
|
633
|
+
"status": "pending"
|
|
634
|
+
}
|
|
635
|
+
\`\`\`
|
|
636
|
+
|
|
637
|
+
**After reading a result**: Present the findings to the user. If the task requires follow-up (e.g., bug investigation found the issue in the other repo), dispatch the fix to the appropriate worker.
|
|
638
|
+
|
|
639
|
+
**You are the SINGLE interface for the user.** They should never need to look at worker terminals. Read the messages, synthesize, and present.
|
|
640
|
+
|
|
597
641
|
## Reading Member State (What to Read, When)
|
|
598
642
|
|
|
599
643
|
| When | What to Read | Path |
|
|
@@ -1307,10 +1351,11 @@ function startWorkerSession(cwd) {
|
|
|
1307
1351
|
WOGI_WORKSPACE_ROOT: workspaceRoot
|
|
1308
1352
|
};
|
|
1309
1353
|
|
|
1310
|
-
// Launch Claude Code
|
|
1311
|
-
//
|
|
1354
|
+
// Launch Claude Code with experimental channel support enabled.
|
|
1355
|
+
// The --dangerously-load-development-channels flag makes Claude Code
|
|
1356
|
+
// surface notifications/claude/channel from the MCP server as prompts.
|
|
1312
1357
|
try {
|
|
1313
|
-
execSync('claude', {
|
|
1358
|
+
execSync('claude --dangerously-load-development-channels server:wogi-workspace-channel', {
|
|
1314
1359
|
cwd,
|
|
1315
1360
|
env,
|
|
1316
1361
|
stdio: 'inherit'
|
package/package.json
CHANGED
|
@@ -282,6 +282,63 @@ async function handleTaskCompleted(input) {
|
|
|
282
282
|
} catch (_err) {
|
|
283
283
|
// Non-critical - registry manager may not be available
|
|
284
284
|
}
|
|
285
|
+
// Write results back to workspace message bus if running as a workspace worker
|
|
286
|
+
if (result.completed && process.env.WOGI_WORKSPACE_ROOT) {
|
|
287
|
+
try {
|
|
288
|
+
const workspaceRoot = process.env.WOGI_WORKSPACE_ROOT;
|
|
289
|
+
const repoName = process.env.WOGI_REPO_NAME || path.basename(process.cwd());
|
|
290
|
+
const messagesDir = path.join(workspaceRoot, '.workspace', 'messages');
|
|
291
|
+
fs.mkdirSync(messagesDir, { recursive: true });
|
|
292
|
+
|
|
293
|
+
// Build a summary from available task data
|
|
294
|
+
const summary = [];
|
|
295
|
+
if (completedTask.title) summary.push(`**Task**: ${completedTask.title}`);
|
|
296
|
+
if (completedTask.type) summary.push(`**Type**: ${completedTask.type}`);
|
|
297
|
+
if (input.changedFiles?.length) summary.push(`**Files changed**: ${input.changedFiles.join(', ')}`);
|
|
298
|
+
if (input.summary) summary.push(`**Summary**: ${input.summary}`);
|
|
299
|
+
|
|
300
|
+
// Read the last request-log entry for richer context
|
|
301
|
+
try {
|
|
302
|
+
const logPath = path.join(PATHS.root, 'request-log.md');
|
|
303
|
+
if (fs.existsSync(logPath)) {
|
|
304
|
+
const logContent = fs.readFileSync(logPath, 'utf-8');
|
|
305
|
+
const lastEntry = logContent.split(/^### R-/m).pop();
|
|
306
|
+
if (lastEntry && lastEntry.length < 2000) {
|
|
307
|
+
summary.push(`**Log entry**:\n${lastEntry.trim()}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch (_err) {
|
|
311
|
+
// Non-critical
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const message = {
|
|
315
|
+
id: 'msg-' + require('node:crypto').randomBytes(4).toString('hex'),
|
|
316
|
+
from: repoName,
|
|
317
|
+
to: 'manager',
|
|
318
|
+
type: 'task-complete',
|
|
319
|
+
priority: 'medium',
|
|
320
|
+
timestamp: new Date().toISOString(),
|
|
321
|
+
subject: `Task completed: ${completedTask.title || completedTask.id}`,
|
|
322
|
+
body: summary.join('\n') || `Task ${completedTask.id} completed successfully.`,
|
|
323
|
+
taskId: completedTask.id,
|
|
324
|
+
actionRequired: false,
|
|
325
|
+
status: 'pending'
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const msgPath = path.join(messagesDir, `${message.id}.json`);
|
|
329
|
+
fs.writeFileSync(msgPath, JSON.stringify(message, null, 2));
|
|
330
|
+
|
|
331
|
+
if (process.env.DEBUG) {
|
|
332
|
+
console.error(`[Task Completed] Workspace message written: ${msgPath}`);
|
|
333
|
+
}
|
|
334
|
+
} catch (err) {
|
|
335
|
+
// Non-critical — workspace messaging is best-effort
|
|
336
|
+
if (process.env.DEBUG) {
|
|
337
|
+
console.error(`[Task Completed] Workspace message failed: ${err.message}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
285
342
|
// Check pending queue — notify user if items are waiting
|
|
286
343
|
try {
|
|
287
344
|
const { getPendingCount } = require('../../flow-pending');
|