moflo 4.10.13 → 4.10.15
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.
|
@@ -145,6 +145,10 @@ For the full `moflo.yaml` schema, gate toggles, model routing, and sandbox confi
|
|
|
145
145
|
| Every 5+ file changes | `map` | Update codebase map |
|
|
146
146
|
| Complex debugging | `deepdive` | Deep code analysis |
|
|
147
147
|
|
|
148
|
+
### Worker Report Location
|
|
149
|
+
|
|
150
|
+
Headless workers (`optimize`, `testgaps`, `ultralearn`, `refactor`, `deepdive`) write the latest run's full output to `.moflo/reports/<workerType>.<ext>` (`.md` for markdown workers, `.json` for `ultralearn`). The path is overwritten each run; for history, see `.moflo/logs/headless/`. The directory is gitignored by `flo init`, so reports never reach a consumer's commit. When the user asks "what did testgaps find?" or "where's the optimize report?", read `.moflo/reports/<workerType>.md` directly — do NOT re-run the worker.
|
|
151
|
+
|
|
148
152
|
### Memory-Enhanced Development
|
|
149
153
|
|
|
150
154
|
| Action | When |
|
package/README.md
CHANGED
|
@@ -419,7 +419,7 @@ flo daemon status # shows whether the service is registered AND running
|
|
|
419
419
|
|
|
420
420
|
`flo spell schedule create` warns when the daemon isn't installed so you don't quietly miss runs.
|
|
421
421
|
|
|
422
|
-
**Monitoring.** **[The Luminarium](#the-luminarium)** — moflo's localhost daemon dashboard — surfaces live schedules, recent executions, and per-schedule controls (disable / re-enable / run now), alongside worker health, memory stats, and Claude Code session stats.
|
|
422
|
+
**Monitoring.** **[The Luminarium](#the-luminarium)** — moflo's localhost daemon dashboard — surfaces live schedules, recent executions, and per-schedule controls (disable / re-enable / run now), alongside worker health, memory stats, and Claude Code session stats. Ask `/luminarium` in your Claude session and it'll print the link.
|
|
423
423
|
|
|
424
424
|
For full configuration (`scheduler:` block in `moflo.yaml`), event types, and the catch-up window after restarts, see [docs/SPELLS.md#scheduling](docs/SPELLS.md#scheduling).
|
|
425
425
|
|
|
@@ -465,13 +465,7 @@ The Luminarium is moflo's localhost daemon dashboard. It boots automatically wit
|
|
|
465
465
|
|
|
466
466
|
### Finding the URL
|
|
467
467
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
Three ways to get the URL:
|
|
471
|
-
|
|
472
|
-
- **`/luminarium`** — inside a Claude Code session in a moflo project, this skill reads `.moflo/daemon.lock` and prints `http://localhost:<port>`. Fastest path.
|
|
473
|
-
- **`flo daemon status`** — prints the URL alongside the health summary.
|
|
474
|
-
- **`cat .moflo/daemon.lock`** — read the JSON directly: `{ "pid": ..., "port": 33421, ... }`.
|
|
468
|
+
Inside a Claude Code session in a moflo project, ask **`/luminarium`** — the skill prints the dashboard URL for the current project. `flo daemon status` prints the same URL alongside the health summary. Each project binds its own port so two projects on the same machine never collide.
|
|
475
469
|
|
|
476
470
|
### What it shows
|
|
477
471
|
|
|
@@ -486,7 +480,7 @@ Three ways to get the URL:
|
|
|
486
480
|
### Flags
|
|
487
481
|
|
|
488
482
|
- `flo daemon start --no-dashboard` — disable the HTTP server entirely (the daemon itself still runs)
|
|
489
|
-
- `flo daemon start --dashboard-port <N>` — pin to a specific port, overriding the
|
|
483
|
+
- `flo daemon start --dashboard-port <N>` — pin to a specific port, overriding the per-project default. Also accepts the `MOFLO_DAEMON_PORT` env var, which the rest of moflo respects when talking to the daemon
|
|
490
484
|
|
|
491
485
|
## Commands
|
|
492
486
|
|
|
@@ -425,13 +425,10 @@ export async function checkNestedMofloIslands(cwd) {
|
|
|
425
425
|
}
|
|
426
426
|
const { islands, truncated } = scan;
|
|
427
427
|
if (islands.length === 0) {
|
|
428
|
-
const baseMsg = 'No nested .moflo/ directories detected';
|
|
429
428
|
return {
|
|
430
429
|
name: 'Nested .moflo/ Islands',
|
|
431
|
-
status:
|
|
432
|
-
message:
|
|
433
|
-
? `${baseMsg} within depth-5 walk — deeper subtrees not inspected`
|
|
434
|
-
: baseMsg,
|
|
430
|
+
status: 'pass',
|
|
431
|
+
message: 'No nested .moflo/ directories detected',
|
|
435
432
|
};
|
|
436
433
|
}
|
|
437
434
|
const rels = islands.map(p => relative(root, p) || '.');
|
|
@@ -90,7 +90,7 @@ Provide actionable suggestions with code examples.`,
|
|
|
90
90
|
- Check for missing error handling tests
|
|
91
91
|
- Identify integration test gaps
|
|
92
92
|
|
|
93
|
-
For each gap,
|
|
93
|
+
For each gap, include a test skeleton inline in the report as a fenced code block — DO NOT create separate test files; the consumer will copy the skeletons into their test tree by hand.`,
|
|
94
94
|
sandbox: 'permissive',
|
|
95
95
|
model: 'sonnet',
|
|
96
96
|
outputFormat: 'markdown',
|
|
@@ -300,11 +300,13 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
300
300
|
maxContextFiles: options?.maxContextFiles ?? 20,
|
|
301
301
|
maxCharsPerFile: options?.maxCharsPerFile ?? 5000,
|
|
302
302
|
logDir: options?.logDir ?? join(projectRoot, '.moflo', 'logs', 'headless'),
|
|
303
|
+
reportsDir: options?.reportsDir ?? join(projectRoot, '.moflo', 'reports'),
|
|
303
304
|
cacheContext: options?.cacheContext ?? true,
|
|
304
305
|
cacheTtlMs: options?.cacheTtlMs ?? 60000, // 1 minute default
|
|
305
306
|
};
|
|
306
|
-
// Ensure log
|
|
307
|
+
// Ensure log + reports directories exist
|
|
307
308
|
this.ensureLogDir();
|
|
309
|
+
this.ensureReportsDir();
|
|
308
310
|
// Register for process-exit cleanup via the shared listener.
|
|
309
311
|
ensureExitListener();
|
|
310
312
|
liveExecutors.add(this);
|
|
@@ -546,6 +548,29 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
546
548
|
this.emit('warning', { message: 'Failed to create log directory', error });
|
|
547
549
|
}
|
|
548
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Ensure the reports directory exists. Reports land under `.moflo/reports/`
|
|
553
|
+
* (gitignored by `flo init`); without this directory the post-spawn write
|
|
554
|
+
* would no-op and the consumer would lose the report entirely.
|
|
555
|
+
*/
|
|
556
|
+
ensureReportsDir() {
|
|
557
|
+
try {
|
|
558
|
+
if (!existsSync(this.config.reportsDir)) {
|
|
559
|
+
mkdirSync(this.config.reportsDir, { recursive: true });
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
catch (error) {
|
|
563
|
+
this.emit('warning', { message: 'Failed to create reports directory', error });
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Resolve the on-disk report path for a worker. Extension matches the
|
|
568
|
+
* declared outputFormat so tools reading the report don't have to sniff.
|
|
569
|
+
*/
|
|
570
|
+
getReportPath(workerType, outputFormat) {
|
|
571
|
+
const ext = outputFormat === 'json' ? 'json' : outputFormat === 'text' ? 'txt' : 'md';
|
|
572
|
+
return join(this.config.reportsDir, `${workerType}.${ext}`);
|
|
573
|
+
}
|
|
549
574
|
/**
|
|
550
575
|
* Internal execution logic
|
|
551
576
|
*/
|
|
@@ -558,8 +583,11 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
558
583
|
try {
|
|
559
584
|
// Build context from file patterns
|
|
560
585
|
const context = await this.buildContext(headless.contextPatterns || []);
|
|
586
|
+
// Resolve the on-disk report path before prompt assembly so the prompt
|
|
587
|
+
// can quote the exact absolute path Claude should write to.
|
|
588
|
+
const reportPath = this.getReportPath(workerType, headless.outputFormat);
|
|
561
589
|
// Build the full prompt
|
|
562
|
-
const fullPrompt = this.buildPrompt(headless.promptTemplate, context);
|
|
590
|
+
const fullPrompt = this.buildPrompt(headless.promptTemplate, context, reportPath);
|
|
563
591
|
// Log prompt for debugging
|
|
564
592
|
this.logExecution(executionId, 'prompt', fullPrompt);
|
|
565
593
|
// Execute Claude Code headlessly
|
|
@@ -571,6 +599,13 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
571
599
|
workerType,
|
|
572
600
|
signal,
|
|
573
601
|
});
|
|
602
|
+
// Persist the spawn output to the canonical report path. Belt-and-braces
|
|
603
|
+
// against Claude ignoring the in-prompt instruction — this guarantees
|
|
604
|
+
// the consumer ends up with a report at a deterministic location no
|
|
605
|
+
// matter what the model chose to do with its Write tool.
|
|
606
|
+
if (result.success && result.output && result.output.trim().length > 0) {
|
|
607
|
+
this.writeReport(reportPath, result.output);
|
|
608
|
+
}
|
|
574
609
|
// Parse output based on format
|
|
575
610
|
let parsedOutput;
|
|
576
611
|
if (headless.outputFormat === 'json' && result.output) {
|
|
@@ -768,15 +803,23 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
768
803
|
return name === pattern;
|
|
769
804
|
}
|
|
770
805
|
/**
|
|
771
|
-
* Build full prompt with context
|
|
806
|
+
* Build full prompt with context. The report path is injected so Claude
|
|
807
|
+
* saves output to the canonical `.moflo/reports/` location instead of
|
|
808
|
+
* dropping `*-analysis.md` / `*-report.md` files at the project root — the
|
|
809
|
+
* behaviour consumers were seeing before this change.
|
|
772
810
|
*/
|
|
773
|
-
buildPrompt(template, context) {
|
|
811
|
+
buildPrompt(template, context, reportPath) {
|
|
812
|
+
const ioInstructions = `## Output
|
|
813
|
+
|
|
814
|
+
Save the full report to \`${reportPath}\` using the Write tool. Overwrite any prior content at that path. DO NOT create any other files anywhere in the project; if you need to suggest test skeletons or code samples, include them inline in the report as fenced code blocks. Moflo persists the same output to that path after you finish, so the location is authoritative.`;
|
|
774
815
|
if (!context) {
|
|
775
816
|
return `${template}
|
|
776
817
|
|
|
777
818
|
## Instructions
|
|
778
819
|
|
|
779
|
-
Analyze the codebase and provide your response following the format specified in the task
|
|
820
|
+
Analyze the codebase and provide your response following the format specified in the task.
|
|
821
|
+
|
|
822
|
+
${ioInstructions}`;
|
|
780
823
|
}
|
|
781
824
|
return `${template}
|
|
782
825
|
|
|
@@ -786,7 +829,9 @@ ${context}
|
|
|
786
829
|
|
|
787
830
|
## Instructions
|
|
788
831
|
|
|
789
|
-
Analyze the above codebase context and provide your response following the format specified in the task
|
|
832
|
+
Analyze the above codebase context and provide your response following the format specified in the task.
|
|
833
|
+
|
|
834
|
+
${ioInstructions}`;
|
|
790
835
|
}
|
|
791
836
|
/**
|
|
792
837
|
* Execute Claude Code in headless mode
|
|
@@ -1011,6 +1056,22 @@ Analyze the above codebase context and provide your response following the forma
|
|
|
1011
1056
|
// Ignore log write errors
|
|
1012
1057
|
}
|
|
1013
1058
|
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Persist a worker's report to the canonical `.moflo/reports/` location.
|
|
1061
|
+
* The directory was created at construction time; we recreate it here as a
|
|
1062
|
+
* safety net in case it was removed between construction and execution.
|
|
1063
|
+
*/
|
|
1064
|
+
writeReport(reportPath, content) {
|
|
1065
|
+
try {
|
|
1066
|
+
if (!existsSync(this.config.reportsDir)) {
|
|
1067
|
+
mkdirSync(this.config.reportsDir, { recursive: true });
|
|
1068
|
+
}
|
|
1069
|
+
writeFileSync(reportPath, content);
|
|
1070
|
+
}
|
|
1071
|
+
catch (error) {
|
|
1072
|
+
this.emit('warning', { message: 'Failed to write worker report', reportPath, error });
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1014
1075
|
}
|
|
1015
1076
|
// Export default
|
|
1016
1077
|
export default HeadlessWorkerExecutor;
|
package/dist/src/cli/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.10.
|
|
3
|
+
"version": "4.10.15",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. A standalone, opinionated toolkit with semantic memory, learned routing, gates, spells, and the /flo issue-execution skill.",
|
|
5
5
|
"main": "dist/src/cli/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
96
96
|
"@typescript-eslint/parser": "^7.18.0",
|
|
97
97
|
"eslint": "^8.0.0",
|
|
98
|
-
"moflo": "^4.10.
|
|
98
|
+
"moflo": "^4.10.14",
|
|
99
99
|
"tsx": "^4.21.0",
|
|
100
100
|
"typescript": "^5.9.3",
|
|
101
101
|
"vitest": "^4.0.0"
|