moflo 4.8.83 → 4.8.85
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/package.json +2 -2
- package/src/modules/cli/dist/src/epic/spells/single-branch.yaml +58 -6
- package/src/modules/cli/dist/src/memory/bridge-core.js +5 -1
- package/src/modules/cli/dist/src/memory/memory-initializer.js +2 -2
- package/src/modules/cli/dist/src/services/moflo-require.js +55 -10
- package/src/modules/cli/dist/src/version.js +1 -1
- package/src/modules/cli/package.json +1 -1
- package/src/modules/spells/dist/core/interpolation.js +12 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.85",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. Forked from ruflo/claude-flow with patches applied to source, plus feature-level orchestration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"@types/node": "^24.12.2",
|
|
118
118
|
"@xenova/transformers": "^2.17.0",
|
|
119
119
|
"eslint": "^8.0.0",
|
|
120
|
-
"moflo": "^4.8.
|
|
120
|
+
"moflo": "^4.8.84",
|
|
121
121
|
"tsx": "^4.21.0",
|
|
122
122
|
"typescript": "^5.9.3",
|
|
123
123
|
"vitest": "^4.0.0"
|
|
@@ -120,6 +120,18 @@ steps:
|
|
|
120
120
|
# The github `comment` action only appends a comment — it does NOT
|
|
121
121
|
# touch the task-list checkboxes. We read the body, substitute, and
|
|
122
122
|
# write it back so the epic reflects progress at a glance.
|
|
123
|
+
#
|
|
124
|
+
# Cross-platform notes:
|
|
125
|
+
# - Uses `node -e` instead of sed/awk/tr because coreutils are
|
|
126
|
+
# not guaranteed on PATH (minimal containers, some Git-Bash
|
|
127
|
+
# installs). Node is always available — moflo runs on it.
|
|
128
|
+
# - Values reach node via env vars (not argv) so the script is
|
|
129
|
+
# immune to Node's argv[1]-"[eval]" quirk across versions.
|
|
130
|
+
# - The embedded JS contains ZERO backslashes. When Node spawns
|
|
131
|
+
# `bash -c '<script>'` on Windows, Cygwin/MSYS bash strips one
|
|
132
|
+
# layer of backslash escapes from the command line, which
|
|
133
|
+
# silently broke regex escapes like `\[` and `\b`. Using
|
|
134
|
+
# indexOf + a char-code `isWord` check avoids the trap entirely.
|
|
123
135
|
- id: check-off-story
|
|
124
136
|
type: bash
|
|
125
137
|
permissionLevel: elevated
|
|
@@ -128,11 +140,42 @@ steps:
|
|
|
128
140
|
set -e
|
|
129
141
|
STORY={loop.story_number}
|
|
130
142
|
EPIC={args.epic_number}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
143
|
+
export STORY EPIC
|
|
144
|
+
node -e '
|
|
145
|
+
const cp = require("node:child_process");
|
|
146
|
+
const epic = process.env.EPIC;
|
|
147
|
+
const story = process.env.STORY;
|
|
148
|
+
const view = cp.spawnSync("gh", ["issue", "view", epic, "--json", "body", "-q", ".body"], { encoding: "utf8" });
|
|
149
|
+
if (view.status !== 0) {
|
|
150
|
+
process.stderr.write(view.stderr || "gh issue view failed");
|
|
151
|
+
process.exit(view.status || 1);
|
|
152
|
+
}
|
|
153
|
+
const body = view.stdout;
|
|
154
|
+
const target = "- [ ] #" + story;
|
|
155
|
+
const replacement = "- [x] #" + story;
|
|
156
|
+
function isWord(c) {
|
|
157
|
+
if (!c) return false;
|
|
158
|
+
const n = c.charCodeAt(0);
|
|
159
|
+
return (n >= 48 && n <= 57) || (n >= 65 && n <= 90) || (n >= 97 && n <= 122) || n === 95;
|
|
160
|
+
}
|
|
161
|
+
let updated = "";
|
|
162
|
+
let i = 0;
|
|
163
|
+
while (i < body.length) {
|
|
164
|
+
const idx = body.indexOf(target, i);
|
|
165
|
+
if (idx < 0) { updated += body.slice(i); break; }
|
|
166
|
+
updated += body.slice(i, idx);
|
|
167
|
+
const end = idx + target.length;
|
|
168
|
+
if (isWord(body[end])) {
|
|
169
|
+
updated += body.slice(idx, end);
|
|
170
|
+
} else {
|
|
171
|
+
updated += replacement;
|
|
172
|
+
}
|
|
173
|
+
i = end;
|
|
174
|
+
}
|
|
175
|
+
if (updated === body) process.exit(0);
|
|
176
|
+
const edit = cp.spawnSync("gh", ["issue", "edit", epic, "--body-file", "-"], { input: updated, stdio: ["pipe", "inherit", "inherit"] });
|
|
177
|
+
if (edit.status !== 0) process.exit(edit.status || 1);
|
|
178
|
+
'
|
|
136
179
|
timeout: 60000
|
|
137
180
|
failOnError: true
|
|
138
181
|
|
|
@@ -178,11 +221,20 @@ steps:
|
|
|
178
221
|
# merging the consolidated PR auto-closes each individual story issue,
|
|
179
222
|
# not just the epic. Without this, only the epic would close on merge
|
|
180
223
|
# and story issues would linger open indefinitely.
|
|
224
|
+
#
|
|
225
|
+
# Cross-platform: uses `node -e` instead of tr/awk (see check-off-story
|
|
226
|
+
# for rationale).
|
|
181
227
|
- id: build-closes-list
|
|
182
228
|
type: bash
|
|
183
229
|
config:
|
|
184
230
|
command: |
|
|
185
|
-
|
|
231
|
+
STORIES={args.stories}
|
|
232
|
+
export STORIES
|
|
233
|
+
node -e '
|
|
234
|
+
const raw = process.env.STORIES || "";
|
|
235
|
+
const stories = raw.split(",").map(s => s.trim()).filter(Boolean);
|
|
236
|
+
process.stdout.write(stories.map(s => "Closes #" + s).join(" "));
|
|
237
|
+
'
|
|
186
238
|
timeout: 30000
|
|
187
239
|
failOnError: true
|
|
188
240
|
|
|
@@ -87,7 +87,11 @@ export async function getRegistry(dbPath) {
|
|
|
87
87
|
if (!registryPromise) {
|
|
88
88
|
registryPromise = (async () => {
|
|
89
89
|
try {
|
|
90
|
-
const
|
|
90
|
+
const memoryModule = await importMofloMemory();
|
|
91
|
+
if (!memoryModule) {
|
|
92
|
+
throw new Error('@moflo/memory not available (src/modules/memory/dist/index.js not found)');
|
|
93
|
+
}
|
|
94
|
+
const { ControllerRegistry } = memoryModule;
|
|
91
95
|
const registry = new ControllerRegistry();
|
|
92
96
|
// Suppress noisy init logs
|
|
93
97
|
const origLog = console.log;
|
|
@@ -381,8 +381,8 @@ export async function getHNSWIndex(options) {
|
|
|
381
381
|
// Use HnswLite pure TS implementation (no native dependencies). The
|
|
382
382
|
// shared resolver handles the consumer case where @moflo/memory is not
|
|
383
383
|
// a declared dep and must be loaded via a relative URL fallback.
|
|
384
|
-
const memoryModule = await importMofloMemory(
|
|
385
|
-
if (!('HnswLite' in memoryModule) || memoryModule.HnswLite === undefined) {
|
|
384
|
+
const memoryModule = await importMofloMemory();
|
|
385
|
+
if (!memoryModule || !('HnswLite' in memoryModule) || memoryModule.HnswLite === undefined) {
|
|
386
386
|
// Shape-check (issue #482): warn loudly and bail — the outer catch
|
|
387
387
|
// would otherwise swallow a cryptic "undefined is not a constructor".
|
|
388
388
|
console.warn('[getHNSWIndex] @moflo/memory missing expected export: HnswLite');
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { createRequire } from 'module';
|
|
15
15
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
16
|
+
import { existsSync } from 'fs';
|
|
17
|
+
import { dirname, join } from 'path';
|
|
16
18
|
// createRequire anchored to this file — resolves from moflo's own node_modules
|
|
17
19
|
const mofloRequire = createRequire(fileURLToPath(import.meta.url));
|
|
18
20
|
/**
|
|
@@ -79,20 +81,63 @@ export function mofloResolve(specifier) {
|
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* (
|
|
86
|
-
*
|
|
87
|
-
*
|
|
84
|
+
* Locate `src/modules/memory/dist/index.js` by walking up from this file's
|
|
85
|
+
* directory until the path resolves. Layout-invariant across:
|
|
86
|
+
* - dev source (cli/src/services/)
|
|
87
|
+
* - built output (cli/dist/src/services/)
|
|
88
|
+
* - installed package (node_modules/moflo/src/modules/cli/dist/src/services/)
|
|
89
|
+
* - Windows and POSIX (path.join/dirname are platform-aware)
|
|
88
90
|
*
|
|
89
|
-
*
|
|
91
|
+
* Returns a file:// URL for ESM `import()`, or null if memory isn't built.
|
|
90
92
|
*/
|
|
91
|
-
|
|
93
|
+
let cachedMemoryUrl;
|
|
94
|
+
function locateMofloMemoryDist() {
|
|
95
|
+
if (cachedMemoryUrl !== undefined)
|
|
96
|
+
return cachedMemoryUrl;
|
|
97
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
98
|
+
const rel = join('src', 'modules', 'memory', 'dist', 'index.js');
|
|
99
|
+
// 12 levels is far more than any real moflo install depth
|
|
100
|
+
for (let i = 0; i < 12; i++) {
|
|
101
|
+
const candidate = join(dir, rel);
|
|
102
|
+
if (existsSync(candidate)) {
|
|
103
|
+
cachedMemoryUrl = pathToFileURL(candidate).href;
|
|
104
|
+
return cachedMemoryUrl;
|
|
105
|
+
}
|
|
106
|
+
const parent = dirname(dir);
|
|
107
|
+
if (parent === dir)
|
|
108
|
+
break; // filesystem root
|
|
109
|
+
dir = parent;
|
|
110
|
+
}
|
|
111
|
+
cachedMemoryUrl = null;
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Import `@moflo/memory` from within a moflo source module.
|
|
116
|
+
*
|
|
117
|
+
* The root `moflo` package ships @moflo/memory as a source folder rather than
|
|
118
|
+
* a declared dependency, so `mofloImport('@moflo/memory')` fails in consumer
|
|
119
|
+
* installs (node_modules/@moflo/memory/ doesn't exist). Fall back to a
|
|
120
|
+
* layout-invariant walk-up that finds `src/modules/memory/dist/index.js`
|
|
121
|
+
* regardless of whether the caller is running source, built, or installed.
|
|
122
|
+
*
|
|
123
|
+
* Returns null when memory isn't available — callers must handle that.
|
|
124
|
+
*/
|
|
125
|
+
export async function importMofloMemory() {
|
|
92
126
|
const viaRequire = await mofloImport('@moflo/memory');
|
|
93
127
|
if (viaRequire)
|
|
94
128
|
return viaRequire;
|
|
95
|
-
const
|
|
96
|
-
|
|
129
|
+
const url = locateMofloMemoryDist();
|
|
130
|
+
if (!url)
|
|
131
|
+
return null;
|
|
132
|
+
try {
|
|
133
|
+
return await import(url);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Test-only: reset the cache between unit tests that mutate the filesystem.
|
|
140
|
+
export function _resetMofloMemoryCacheForTest() {
|
|
141
|
+
cachedMemoryUrl = undefined;
|
|
97
142
|
}
|
|
98
143
|
//# sourceMappingURL=moflo-require.js.map
|
|
@@ -7,12 +7,19 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* Matches `{path}` variable references in spell step configs.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* Content must be identifier-shape: letter/underscore followed by
|
|
11
|
+
* letters, digits, `_`, `.`, or `-`. This tight grammar accommodates
|
|
12
|
+
* every real spell ref (`{args.x}`, `{loop.x}`, `{step-id.out}`) while
|
|
13
|
+
* letting bash steps embed literal `{...}` blocks — JS destructuring
|
|
14
|
+
* `{ foo }` (whitespace), object literals `{ a: b }` (colon), shell
|
|
15
|
+
* expansions `${VAR}` (lookbehind), and so on — without tripping the
|
|
16
|
+
* interpolator. A greedy `[^}]+` class ate JS code inside `node -e`
|
|
17
|
+
* scripts and threw "Variable not found" at runtime.
|
|
18
|
+
*
|
|
19
|
+
* The `(?<!\$)` negative lookbehind also skips `${VAR}` — bash parameter
|
|
20
|
+
* expansion inside shell steps must pass through untouched.
|
|
14
21
|
*/
|
|
15
|
-
export const VAR_REF_PATTERN = /(?<!\$)\{([
|
|
22
|
+
export const VAR_REF_PATTERN = /(?<!\$)\{([A-Za-z_][A-Za-z0-9_.-]*)\}/g;
|
|
16
23
|
/**
|
|
17
24
|
* Resolve a dot-separated path against the context variables.
|
|
18
25
|
* Returns undefined if any segment is missing.
|