Skip to content

Add Dynamic Workflow Console (workflow-console) - #54

Merged
MyPrototypeWhat merged 5 commits into
MiniMax-AI:mainfrom
stevenjj33:feat/workflow-console
Oct 23, 2026
Merged

MyPrototypeWhat merged 5 commits into
MiniMax-AI:mainfrom
stevenjj33:feat/workflow-console

Conversation

@stevenjj33

@stevenjj33 stevenjj33 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What this is

workflow-console is a Mini App that runs, supervises, and inspects MiniMax Code dynamic workflows from one page.

Based on which project

This package is built on top of the mcode-dynamic-workflows plugin by hetaoBackend (Apache-2.0), from https://github.com/MiniMax-AI/MiniMax-Code-Plugins/tree/main/plugins/hetaoBackend/mcode-dynamic-workflows.

That plugin is an MCP server that orchestrates multi-agent workflows. It normally has to be installed as a MiniMax Code plugin and reached through MCP. This package vendors its runtime and runs it as a self-contained Mini App:

  • The upstream runtime is vendored byte-for-byte into miniapp/node/vendor/dynamic-workflows/ and started as a child process, so the app works on machines where the plugin was never installed.
  • The upstream web/ canvas model (graph-model.mjs) is imported directly, so the flow graph in this console is the same graph model Workflow Studio draws, not a second implementation.
  • The console adds what the plugin does not provide: a per-project run list, a live event stream, run approval and control, template management, report export, and a working-directory picker.

miniapp/node/vendor/dynamic-workflows/VENDOR.md records the vendored files, the exact upstream commit, and every behavioural difference between the upstream plugin and this console.

What it does

  • Starts its own Workflow Studio engine and binds it to a project directory the user picks
  • Run list per project, with status filters, a live event log, and per-node results
  • A stage-and-dependency flow graph (SVG, the same model as the Studio canvas)
  • Approve and run a draft, pause / cancel / resume, export Markdown or HTML
  • Save a run as a template, and create a new draft from a template without running it
  • An always-visible working-directory bar, so switching projects is one field

The user interface is in Chinese; README.zh-CN.md is the Chinese README.

Install

Copy plugins/stevenjj33/workflow-console/ (including the hidden .minimax-plugin/) into the MiniMax Code plugins directory as workflow-console/ (~/.minimax/plugins/workflow-console/ by default). Restart MiniMax Code and ask the Agent to "打开动态工作流控制台".

There is no configuration step and no build step.

On first launch the console needs a project directory, and it does not guess one. It uses the Host's current project when the Host declares it through MCODE_WORKSPACE / MCODE_PROJECT_DIR / PROJECT_DIR / WORKSPACE, otherwise the absolute path you type into the working-directory bar at the top of the page. If neither is available the engine does not start and the page asks for a path. The user's home directory and the Host's temporary deployment directory are refused in every case. Saving that bar restarts the embedded engine against the new directory; run history lives in the engine's own database and is not affected.

Running real workflows still needs a working mcode CLI on the machine, because the engine orchestrates agents through it. The demo executor works without it.

Tested environment

  • MiniMax Code 3.1.4 on Windows 11, Node.js 22 and 26. Installed from this directory, opened through the Agent, page rendered, engine started, run approved and executed with the demo executor.
  • MiniMax Code on macOS (arm64), Node.js 26.8.1, on a machine where the upstream plugin had never been installed: working-directory resolution, the "no project directory yet" state, and the same demo-executor run were verified there.
  • Browser: Chromium-based desktop browser, 1280x720 and 589x899 viewports, light and dark themes. Console: 0 errors, 0 warnings.

Tests

node --test "tests/*.test.mjs"

16/16 pass.

  • tests/workspace-resolution.test.mjs — working-directory resolution: the Host's temporary deployment directory and other implausible paths are rejected, the home directory is never used as a fallback, and the engine does not start until a project directory is known.
  • tests/engine-isolation.test.mjs — plants a fake registry of the mcode-dynamic-workflows plugin, pointing at a local server that records every request, and asserts the console never contacts it.
  • tests/vendor-integrity.test.mjs — every vendored file still matches the recorded upstream commit, compared by git blob object ID.
  • tests/end-to-end.test.mjs — starts the real bundled engine and walks the whole path: empty workspace → project directory chosen → engine live → a demo run created → the flow graph → approve → the run finishing → report export → hide and restore → switching to another project → invalid directories refused.
  • tests/manual-mac-scenario.mjs — starts a console in a simulated fresh macOS host and prints the URL to open for manual inspection.

The tests boot an isolated console instance in a sandbox home directory, so they never touch a real project.

Not verified

  • Real model execution. Every execution in testing used the demo executor, which does not call a model.
  • Pause / resume / cancel on the real executor. Verified on the demo executor only; the real executor may differ in how it interrupts a run.
  • mcodeAvailable: true only means the mcode binary exists on the machine. Its login state and quota are not checked by this app.
  • The narrow-viewport layout was not re-tested in the latest round.

About the two warnings

npm run check reports plugins/stevenjj33/workflow-console: 0 errors, 2 warnings.

Both are ENTRY_STDOUT in miniapp/node/vendor/dynamic-workflows/dist/main.mjs and .../sandbox.mjs. Those files are the unmodified upstream runtime, kept byte-identical so the vendored copy stays redistributable under its own Apache-2.0 license — tests/vendor-integrity.test.mjs enforces that byte-identity. The check scans the whole Node payload tree, so it sees the console.log calls the upstream CLI uses. In the mode this app runs the engine in (--workspace), the child's stdout is redirected to engine/service.log under context.dataDir, so nothing reaches the Host's stdout.

Two failures in the repository's own npm test (files: a symlink inside the package is an error and files: a package root that is itself a symlink is rejected before walking) are a Windows limitation, not a problem with this package: the test creates symlinks with fs.symlink, which needs Developer Mode or administrator rights. They fail the same way on a clean checkout without this package.

Files

.minimax-plugin/plugin.json                 Plugin manifest
package.json                                Mini App declaration
miniapp/miniapp.json                        Payload roots, Node entry, page route
miniapp/client/index.html                   The page served at /dashboard
miniapp/client/app.js                       Front end (plain HTML/CSS/JS, no framework, no build)
miniapp/client/style.css                    Styling, light and dark themes
miniapp/node/server.mjs                     Node entry: start(context) -> { dispose }
miniapp/node/miniapp-api.ts                 Type declarations for the runtime context
miniapp/node/vendor/dynamic-workflows/      Vendored upstream runtime (0.8.0, Apache-2.0)
tests/workspace-resolution.test.mjs         Working-directory resolution
tests/engine-isolation.test.mjs             The bundled engine is the only backend
tests/vendor-integrity.test.mjs             Vendored files match the recorded upstream commit
tests/end-to-end.test.mjs                   Full engine lifecycle, from empty workspace to a finished run
tests/manual-mac-scenario.mjs               Isolated instance that mimics a fresh macOS host
icon.png                                    Plugin icon

License

MIT for this package. The vendored upstream runtime keeps its own Apache-2.0 license; attribution is in miniapp/node/vendor/dynamic-workflows/THIRD_PARTY_NOTICES.txt.

@stevenjj33
stevenjj33 force-pushed the feat/workflow-console branch 2 times, most recently from b7db350 to 0c95f20 Compare October 21, 2026 10:25
A Mini App that runs, supervises, and inspects MiniMax Code dynamic workflows
from one page, built on the mcode-dynamic-workflows plugin runtime (0.8.2,
Apache-2.0) by hetaoBackend.

The upstream runtime is vendored unmodified into
miniapp/node/vendor/dynamic-workflows/ and started as a child process, so the
app works on machines where the plugin was never installed. The upstream web
canvas graph model is imported directly, so the flow graph here is the same one
Workflow Studio draws.

The console adds what the plugin does not provide: a per-project run list, a
live event stream, run approval and control, template management, report
export, and a working-directory picker.
@stevenjj33
stevenjj33 force-pushed the feat/workflow-console branch from 0c95f20 to 3235a68 Compare October 21, 2026 10:26
The registry fixture pointed at a loopback port that happens to be in use on the
machine the tests were written on. Any loopback port that nothing listens on
works the same way, so use the discard port instead.
The registry fixture pointed at a loopback port that happens to be in use on the
machine the tests were written on. Any loopback port that nothing listens on
works the same way, so use the discard port instead.

@MyPrototypeWhat MyPrototypeWhat left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @stevenjj33, welcome, and thanks for your first contribution! A live console for dynamic workflows is a useful idea. It's good to see Apache-2.0 attribution for the bundled runtime (LICENSE, THIRD_PARTY_NOTICES, VENDOR.md), the strict 127.0.0.1 checks on upstream addresses, the revision check on approve, and the test suite. Locally npm run check passes (0 errors; the 2 ENTRY_STDOUT warnings are in the bundled dist/ files) and node --test tests passes 10/10.

There are a few things to address before this can merge:

Must-fix

  1. Falling back to the home directory. When no project is found, the engine's workspace becomes homedir() (miniapp/node/server.mjs:291-294), so a run started there could act on the whole home folder. Please refuse to start the engine, or block Start, until the user picks a project directory.
  2. Reading another plugin's service data, including its access token. discoverOnce() and probeRegisteredWorkspace() scan ~/.mcode-dynamic-workflows/projects/*/address.json|endpoint.json (server.mjs:162, 323-335, 627-649). They take the bearer token from the stored URL and use it to call those services (server.mjs:190, 213, 649). That data and token belong to the separate mcode-dynamic-workflows plugin. Please use only the bundled engine under context.dataDir. If you'd like to keep the "connect to an existing service" option, make it something the user explicitly enters rather than an automatic scan.

Suggestions

  • Tell users what runs without asking. The bundled runtime runs the CLI with --permission smart (miniapp/node/vendor/dynamic-workflows/dist/main.mjs:14056), so during a run some file writes and commands are approved automatically, and any step that would need the user's confirmation fails that node instead. That's a sensible choice for a headless run, but the start dialog (miniapp/client/app.js:1586-1594) only mentions model usage. Please say this in the dialog and the README (the runtime already has a similar note at main.mjs:15008).
  • Version of the bundled runtime. VENDOR.md says 0.8.2, "copied unmodified from the local plugin cache", but dist/main.mjs:26447 reports 0.8.0. The upstream repo's main is 0.8.0 and differs from the bundled dist/main.mjs in several hundred lines, so I couldn't confirm it's a verbatim copy. Could you note the exact upstream commit or release it came from, or build it from a published source?
  • Bundle size. The bundle is about 2 MB (a 27k-line main.mjs plus quickjs.wasm) and is pinned to a copy that won't get upstream fixes. Bundling seems reasonable for a standalone app, but please write down how it will be kept up to date. examples/reflection.js from upstream is also missing.
  • Data & access. Once must-fix 2 is addressed, please update the "Data & access" section of the README (README.md:72-77) to match.
  • Display name. The displayName/description in plugin.json are Chinese only; an English name would help non-Chinese readers of the catalog.

Thanks again! Happy to take another look after the update.

title: '开始执行该工作流',
note:
`运行「${run.name}」,静态拓扑共 ${nodeCount} 个节点。` +
(real

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion (non-blocking): with --permission smart (vendor/dynamic-workflows/dist/main.mjs:14056), some file writes and commands are approved automatically during the run, and steps that would need confirmation fail the node. Worth saying so here, since this dialog only mentions model usage.

return cwd;
}
/* 兜底只能落在用户主目录,同时告诉前端「还没绑定到真实项目」。 */
engineWorkspace = homedir();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Falling back to the home directory means a real run could act on the whole home folder. Please refuse to start, or block Start, until a project directory is chosen.

const record = {
id: name.slice(0, 12),
origin: target.origin,
token: target.token,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This takes another plugin's service token from ~/.mcode-dynamic-workflows/projects/*/address.json and uses it. Please limit the console to the bundled engine under context.dataDir, or make connecting to an external service something the user explicitly enters.

## 版本与来源

- 上游:`MiniMax-AI/MiniMax-Code-Plugins` → `plugins/hetaoBackend/mcode-dynamic-workflows`
- 版本:**0.8.2**(从本机插件缓存原样复制,未做任何修改)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dist/main.mjs:26447 reports version 0.8.0, and upstream main (0.8.0) differs from this copy. Could you note the exact upstream commit or release this came from?

… reading the plugin's registry

Addresses the review on MiniMax-AI#54.

Must-fix 1 — no home-directory fallback.

The engine used to fall back to homedir() when no project could be found,
so one run could act on the whole home folder. It now starts only against a
directory that is actually known to be a project:

  - the Host's current project, via MCODE_WORKSPACE / MCODE_PROJECT_DIR /
    PROJECT_DIR / WORKSPACE;
  - an absolute path the user typed into the working-directory bar.

If neither exists the engine does not start at all, the page says so, and
Start stays blocked. The user's home directory is rejected even when typed
in by hand, and so is the Host's temporary deployment directory.

Must-fix 2 — no reading of the other plugin's data.

discoverOnce() and probeRegisteredWorkspace() scanned
~/.mcode-dynamic-workflows/projects/*/address.json|endpoint.json, took the
bearer token out of the stored URL and called those services. That data and
that token belong to the mcode-dynamic-workflows plugin. The console now
uses only its own bundled engine under context.dataDir and contacts nothing
else; the service picker is gone with it.

tests/engine-isolation.test.mjs plants a fake registry of that plugin
pointing at a local server that records every request, and asserts the
console never sends it one.

Vendored runtime — exact version and provenance.

VENDOR.md claimed 0.8.2 "copied unmodified from the local plugin cache", but
upstream has only ever published 0.8.0, and the bundled dist/main.mjs,
web/app.js and web/app.source.mjs matched no upstream commit at all. The
vendor tree is now a byte-for-byte copy of

  MiniMax-AI/MiniMax-Code-Plugins @ 6481e4ae1e0375a4ddb3d5e9b29845354ab1cead

and tests/vendor-integrity.test.mjs records each file's upstream git blob
object ID and recomputes the git blob hash locally, so the claim is checked
rather than asserted. examples/reflection.js is included. The bundle size
and the upgrade procedure are written down in VENDOR.md.

Suggestions.

- The start dialog and both READMEs now say that the runtime calls the CLI
  with --permission smart: some file writes and commands are approved
  automatically, and a step that would need confirmation fails that node.
- README "Data & access" now matches: no ~/.mcode-dynamic-workflows, no
  selection.json, loopback only.
- plugin.json displayName and description are bilingual.

Also fixes the working-directory field being overwritten by the next poll
when its value was set without an input event.

Verified: npm run check (0 errors, the 2 pre-existing ENTRY_STDOUT warnings
in the bundled dist/), node --test tests/ (16/16), and an end-to-end test
that starts the real engine and walks empty workspace -> project chosen ->
engine live -> run created -> flow graph -> approve -> run finished ->
report export -> hide/restore -> switch project -> invalid directories
rejected.
@stevenjj33

Copy link
Copy Markdown
Contributor Author

Thanks for the review — both must-fixes are done, and the suggestions are addressed in 825d846.

Must-fix 1 — falling back to the home directory

The engine no longer starts without a project directory it can trust.

resolveEngineWorkspace() now has exactly two sources: the Host's current project (MCODE_WORKSPACE / MCODE_PROJECT_DIR / PROJECT_DIR / WORKSPACE), and an absolute path the user typed into the working-directory bar. The cwd and registry fallbacks are gone, and so is the homedir() fallback — when neither source exists the function returns null, startEmbedded() refuses to spawn, and the page says "请先选择项目目录" and keeps Start blocked. The home directory is now rejected even when typed in by hand ("用户主目录不是项目目录:在这里运行会改写整个家目录"), as is the Host's temporary deployment directory.

tests/workspace-resolution.test.mjs covers each of those cases, including that the engine data directory is never created and the engine never reports live without a project.

Must-fix 2 — reading the other plugin's service data and token

The console now uses only its own bundled engine under context.dataDir. discoverOnce() no longer scans ~/.mcode-dynamic-workflows/projects/*/address.json|endpoint.json, probeRegisteredWorkspace()/findRegisteredWorkspace() are deleted, and nothing reads a bearer token from another plugin's stored URL. selection.json and the multi-service switcher went away with the code that needed them; the top bar no longer offers a service picker.

tests/engine-isolation.test.mjs plants a registry of that plugin pointing at a local HTTP server that records every request, and asserts the console sends it none.

Suggestions

  • --permission smart — now stated in the start dialog ("内置运行时以 smart 权限调用 CLI:部分文件写入与命令会自动放行,需要你确认的步骤会让该节点直接失败") and in both READMEs' Agent turns section.
  • Version of the bundled runtime — you were right that the old copy was unverifiable: upstream has only ever published 0.8.0, and the old dist/main.mjs, web/app.js and web/app.source.mjs matched no upstream commit (the other 11 files matched 00878c7ef606). The vendor tree is now a byte-for-byte copy of MiniMax-AI/MiniMax-Code-Plugins@6481e4ae1e0375a4ddb3d5e9b29845354ab1cead, and tests/vendor-integrity.test.mjs records each file's upstream git blob object ID and recomputes the git blob hash locally, so the claim is checked rather than asserted. VENDOR.md records the repo, path, commit, date and version.
  • Bundle size and upkeep — VENDOR.md now states the size (~2.3 MB) and gives the upgrade procedure end to end: find the upstream commit, copy dist/, web/, examples/, LICENSE, THIRD_PARTY_NOTICES.txt without renaming, refresh the recorded blob IDs with git ls-tree -r, update the three provenance lines, then run the tests. examples/reflection.js is included.
  • Data & access — README.md and README.zh-CN.md rewritten to match: no ~/.mcode-dynamic-workflows, no selection.json, loopback only, one spawned process, state under context.dataDir.
  • Display name — displayName and description in plugin.json are now bilingual.

Also

The working-directory field was being overwritten by the next poll when its value had been set without an input event. It now only writes back to the field when the field still holds the last value the server reported.

Verification

  • npm run check at the repository root: 0 errors, the same 2 ENTRY_STDOUT warnings in the bundled upstream dist/ files, 69/69 repository tests pass.
  • node --test "tests/*.test.mjs": 16/16 pass, including tests/end-to-end.test.mjs, which starts the real bundled engine and walks empty workspace → project chosen → engine live → run created → flow graph → approve → run finished → report export → hide/restore → switch project → invalid directories rejected.
  • Opened through the Agent on macOS (arm64), Node.js 26.8.1: runtime passed the Host readiness checks, page rendered with 0 console errors and 0 warnings, and the "no project directory yet" state showed the expected prompt.

One note on scope: I did not add the optional "connect to an external service" option. The console runs its own engine, so there was nothing for it to gain, and leaving it out is what keeps the other plugin's data out of the picture.

@stevenjj33

Copy link
Copy Markdown
Contributor Author

@MyPrototypeWhat 麻烦复审一下这个 PR,当前 head 是 14302dc。

上一条评论里逐条回的两条 must-fix 和五条建议都已经改完并推送,摘要:

  • must-fix 1(不再退回用户主目录):resolveEngineWorkspace() 只认宿主声明的当前项目(MCODE_WORKSPACE 等)和用户填的绝对路径,两者都没有时返回 null、引擎不启动、Start 被挡。家目录即使手动填也拒,宿主投放目录也拒。
  • must-fix 2(不再读另一个插件的数据和令牌):~/.mcode-dynamic-workflows 全程不读,控制台只跑 context.dataDir 下自带的引擎,服务选择器一并移除。tests/engine-isolation.test.mjs 用一个会计账的本地服务断言控制台一次请求都没发过去。
  • 内置运行时来源:改为 MiniMax-AI/MiniMax-Code-Plugins@6481e4ae1e0375a4ddb3d5e9b29845354ab1cead 的逐字节副本;tests/vendor-integrity.test.mjs 记录每个文件的 git blob 对象 ID 并本地重算比对,来源可当场复验。
  • 其余建议(--permission smart 说明、版本与提交、bundle 体积与升级流程、examples/reflection.js、README Data & access、plugin.json 双语)见上一条评论。

这一轮只做了一件事:把 upstream main 的 3 个提交合了进来(docs/package-contract.md、docs/agent.md、验证规则 scripts/lib/ 都有更新),用最新的契约重新验过一遍:

  • npm run check → 本插件 0 errors(仍是上游 dist/ 里那 2 条 ENTRY_STDOUT warning),仓库 69/69 通过
  • node --test "tests/*.test.mjs" → 16/16
  • 合并没有改动本插件的任何文件;内置的 17 个文件仍与上游提交逐字节一致

CI 在 14302dc 上是绿的。有需要再改的地方请直接列出来。

@MyPrototypeWhat MyPrototypeWhat left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @stevenjj33 — thanks for the careful follow-up. Re-reviewed at 14302dcdefa8a08fd47229c52c33d2b709ac1d23 (825d846 + merge of current main).

Must-fixes from the previous review

Both are addressed in code:

  1. No home-directory fallback. resolveEngineWorkspace() only accepts the Host-declared project env vars or an absolute path the user set (and persists under context.dataDir/workspace.json). With neither, it returns null, startEmbedded() does not spawn, and Start stays blocked. Home and the Host's temporary deployment directory are rejected even when typed in. Confirmed against miniapp/node/server.mjs and tests/workspace-resolution.test.mjs.
  2. No reading another plugin's registry/token. discoverOnce() only keeps the bundled engine under context.dataDir/engine. probeRegisteredWorkspace / scanning ~/.mcode-dynamic-workflows are gone; the service picker is gone. The only address.json / endpoint.json reads are the console's own engine files. Confirmed against server.mjs and tests/engine-isolation.test.mjs.

Suggestions from last round

Also looked good: --permission smart is in the start dialog and both READMEs; VENDOR.md pins MiniMax-AI/MiniMax-Code-Plugins@6481e4ae… at 0.8.0 with blob IDs checked by tests/vendor-integrity.test.mjs; bundle size / upgrade notes and examples/reflection.js are present; Data & access matches; plugin.json is bilingual.

Optional nit (non-blocking)

LICENSE still attributes the vendored runtime as version 0.8.2 while VENDOR.md / README correctly say 0.8.0. Worth aligning in a tiny follow-up so the attribution file matches the verified copy.

Checks run here

  • node scripts/validate.mjs plugins/stevenjj33/workflow-console → 0 errors, 2 ENTRY_STDOUT warnings in the unmodified vendored dist/ (as you noted).
  • node --test tests/*.test.mjs (Node 22) → 16/16.
  • Repository npm test → 69/69.
  • On Node 20 the end-to-end case timed out waiting for the engine (package engines already asks for >=22); no ajv/jsdom gap for this check path.

Looks good to merge from my side. Thanks again!

--------------------------------------------------------------------------------

`miniapp/node/vendor/dynamic-workflows/` contains an unmodified copy of the
`mcode-dynamic-workflows` plugin runtime (version 0.8.2) by hetaoBackend,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional nit: this still says version 0.8.2, while VENDOR.md / README (and the verified upstream copy) are 0.8.0. Worth aligning so the attribution matches the pinned commit.

@MyPrototypeWhat
MyPrototypeWhat merged commit 16db7c3 into MiniMax-AI:main Oct 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants