moflo 4.8.83 → 4.8.84

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moflo",
3
- "version": "4.8.83",
3
+ "version": "4.8.84",
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.82",
120
+ "moflo": "^4.8.83",
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
- BODY=$(gh issue view "$EPIC" --json body -q .body)
132
- UPDATED=$(printf '%s' "$BODY" | sed -E "s/- \[ \] #${STORY}\b/- [x] #${STORY}/")
133
- if [ "$BODY" != "$UPDATED" ]; then
134
- printf '%s' "$UPDATED" | gh issue edit "$EPIC" --body-file -
135
- fi
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
- echo {args.stories} | tr ',' '\n' | awk 'NF {printf "Closes #%s ", $0}'
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
 
@@ -86,13 +86,17 @@ export function mofloResolve(specifier) {
86
86
  * relative to the caller's file — the same src/modules/memory/dist/index.js
87
87
  * layout holds in both dev and consumer.
88
88
  *
89
+ * Callers live at src/modules/cli/src/memory/<file>.ts, so from that dir
90
+ * the memory dist is 3 levels up (cli/src/memory → cli/src → cli → modules)
91
+ * plus `memory/dist/index.js`.
92
+ *
89
93
  * @param callerUrl `import.meta.url` of the file that needs @moflo/memory
90
94
  */
91
95
  export async function importMofloMemory(callerUrl) {
92
96
  const viaRequire = await mofloImport('@moflo/memory');
93
97
  if (viaRequire)
94
98
  return viaRequire;
95
- const memoryUrl = new URL('../../../../memory/dist/index.js', callerUrl);
99
+ const memoryUrl = new URL('../../../memory/dist/index.js', callerUrl);
96
100
  return import(memoryUrl.href);
97
101
  }
98
102
  //# sourceMappingURL=moflo-require.js.map
@@ -2,5 +2,5 @@
2
2
  * Auto-generated by build. Do not edit manually.
3
3
  * Source of truth: root package.json → scripts/sync-version.mjs
4
4
  */
5
- export const VERSION = '4.8.83';
5
+ export const VERSION = '4.8.84';
6
6
  //# sourceMappingURL=version.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moflo/cli",
3
- "version": "4.8.83",
3
+ "version": "4.8.84",
4
4
  "type": "module",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -7,12 +7,19 @@
7
7
  /**
8
8
  * Matches `{path}` variable references in spell step configs.
9
9
  *
10
- * The `(?<!\$)` negative lookbehind skips `${VAR}` — that's bash parameter
11
- * expansion inside shell steps, not a spell template reference. Without it,
12
- * a bash command like `sed "s/#${STORY}/.../"` would try to resolve `STORY`
13
- * as a spell variable and fail.
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 = /(?<!\$)\{([^}]+)\}/g;
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.