REPL (Read-Eval-Print Loop)¶
Launching a binary built with KRKRZ_REPL=ON with the command-line argument -repl
(or -repl=yes) enables an interactive TJS shell. Supported on Windows, macOS, and
Linux. Line editing is provided by
icline (a fork of isocline).
For the full specification (command list, editing features, troubleshooting), see the guide in src/core:
Launching¶
krkrz -repl data/ # SDL 版
krkrz64 -repl data/ # Win32 版 (親コンソールに AttachConsole)
Without -repl, the REPL does not start (there is no automatic TTY detection).
You can also disable it explicitly with -repl=no / -repl=off / -repl=false / -repl=0.
Building with KRKRZ_REPL_LINE_EDIT=OFF produces a minimal mode with no icline
dependency (line editing such as arrow keys is disabled).
Options¶
All REPL-related options are collected here (see each section for details, and Command-line options for the syntax). They are all independent and can be combined.
| Option | Default | Description |
|---|---|---|
-repl[=yes\|no\|new] |
Off | Console REPL. new forces a new console |
-replfile=<dir> |
Off | File channel (the primary choice for agent-driven use) |
-replsocket=<name> |
Off | Abstract Unix socket channel (Linux-family systems) |
-replweb[=[host:]port] |
Off | HTTP + SSE server + browser UI (default 127.0.0.1:8899) |
-replwebopen=app\|tab\|no |
Auto, conditional | Opens the browser automatically. Not opened by default when launched from a terminal |
-replwebidle=<sec>\|no |
5 seconds | Delay before exiting once no browser is connected |
-replwebpad=<dir> |
Writes disabled | Storage prefix under which the Pad tab's [Save] is allowed |
-replwatchfile=<path>\|no |
.krkrz_watch |
Where the watch expression list is saved |
-replmodaltimeout=<sec> |
30 | Timeout when waiting for a modal response (0 = infinite) |
-nostartup (do not run startup.tjs) and -loglevel= are not REPL-specific, but
they are often used together with agent-driven sessions.
Main special commands¶
The prompt is krkrz> and continuation lines show .... You can enter TJS
expressions and statements directly; history is saved to .krkrz_history.
| Command | Description |
|---|---|
exit / quit / Ctrl+D |
Leave the REPL and quit the application |
.help |
Show help |
.clear |
Clear the buffer of a pending multi-line input |
.depth [N] |
Show / set the expansion depth of result output |
.compact [on\|off] |
Toggle compact mode for result output |
.mem |
One-line summary of allocator + process memory |
.memdump |
Dump detailed memory statistics to the log |
.memsites [N] [function] |
Dump the top N live allocations grouped by call site to the log (diagnostic build + launched with -memstatsite. Passing a function name limits output to call chains containing that function) |
.memoverlay [on\|off] |
Toggle the on-screen overlay (SDL3 build) |
.mempeakclear |
Reset the peak measurement to current_used |
.sysalloc |
Show system allocator info (free / allocatable / RSS) on one line |
.padoverlay [on\|off] |
Toggle the pad overlay (SDL3 build) |
.filecache |
Dump all StorageCache (file layer) entries to the log |
.imagecache |
Dump all TVPGraphicCache (decode layer) entries to the log |
.cap [path] |
Save the actual screen of the next frame (including overlays) as PNG |
.dlg |
List active dialogs |
.dlgclose |
Close the frontmost dialog |
.click X Y |
Inject a mouse click at (X,Y) (Agent.click) |
.watch |
List watch expressions as id: expr = value (all are evaluated before display) |
.watch add EXPR |
Add a watch expression and evaluate it immediately |
.watch rm ID / .watch rm all |
Remove a watch expression / remove all |
.watch edit ID EXPR |
Replace a watch expression |
.watch auto [ms\|on\|off] |
Show / set the auto-refresh interval (on = 500ms, 0 = every frame, minimum 100ms) |
.event [on\|off\|toggle] |
Show / toggle System.eventDisabled |
For details on the memory commands see the memory observation guide; for the pad overlay see PadOverlay.
.watch corresponds to the "watch expressions" debug window that Kirikiri 2 had
built into the engine. Once expressions are registered, each .watch (or each
auto-refresh tick) evaluates them all and lists expressions alongside their values.
The evaluation context is always global, and if an expression throws, it just shows
(error) <message> as the value, so one broken watch expression never kills
the REPL or the application.
The expression list and auto-refresh interval are saved to .krkrz_watch in the
current directory and loaded back on the next launch (change it with
-replwatchfile=<path>, disable with =no).
Error handler behavior while the REPL is active¶
When the REPL is enabled with -repl or -replfile, an uncaught exception no longer
terminates Kirikiri Z immediately. Instead of showing a native dialog, the exception
is only logged with a stack trace, so you can fix the problem and eval again.
Likewise, output from System.inform and Application::MessageDlg is redirected to
the REPL console (only the default response is returned, and no dialog is shown), so
headless automated tests do not stall.
Combined with -nostartup, automatic execution of startup.tjs is also suppressed,
which lets you start idle with no window and then kick off processing explicitly
from the REPL (see -nostartup in Command-line options
for details).
File channel (-replfile)¶
Specifying -replfile=<dir> starts a file-based REPL channel that does not go
through the console. An external agent writes a command file in the specified
directory to submit a TJS expression, then reads the result JSON from a response
file (lockstep). It can be enabled independently of -repl, and both can be used
at the same time.
krkrz -replfile=./replbus data/
It is intended for headless automated tests and for controlling krkrz from an agent running in another process. See the src/core documentation for protocol details.
Lines starting with . are treated as special commands, and the same output as
the console REPL goes into the result field of the response JSON (an agent can call
.watch / .mem / .cap and so on directly).
Browser UI (-replweb)¶
The embedded page returned by GET / is organized as Console / Watch tabs.
| Tab | Contents |
|---|---|
| Console | Log on top / input at the bottom (the original page) |
| Watch | Table of watch expressions (expression / value) + add, remove, inline edit (double-click) + auto-refresh interval |
| Pad | Script editor. Run multiple lines with Ctrl+Enter, load / save from storage |
You can add your own panels as tabs (WebServer.registerPanel). Serve your own
page with serveStatic and pass its path; it appears to the right of the built-in
tabs. The content is an iframe, so it does not depend on the built-in UI's internal
structure, and the panel can call /cmd, /watch, /pad/exec, or your own
endpoints on the same origin.
WebServer.serveStatic("/tool/", "web/");
WebServer.registerPanel("mytool", "案件ツール", "/tool/tool.html");
Hosting an entire page of your own (serveStatic alone) loses Console / Watch / Pad
and the controller, so if you just want to add an observation panel, this is the
better fit.
Since it is built into the engine, -replweb alone is all you need (no plugin or
script required). To replace it with your own UI, use WebServer.serveStatic.
Keeping the browser UI and the application lifetimes in sync¶
With a browser as the UI, the worst outcome is one side being left behind (the window is closed but the engine keeps running / the engine has exited but a «disconnected» page remains). Both directions are handled.
Engine side — exits when no browser remains (-replwebidle)
| State | Behavior |
|---|---|
| From launch until the first connection | Waits (never exits) |
| One or more connections | Keeps running |
| All connections gone | Exits after <sec> |
Enabled by default (5 seconds). Disable with -replwebidle=no, or set the
number of seconds with =<sec>. It is armed only when launched with -replweb;
a server started from TJS with WebServer.start() is not armed (so a server the
application manages itself is never shut down behind its back).
It arms only after at least one connection has arrived, so agent-driven use that
never opens a browser, or use as an API surface, is unaffected. Closing the page
sends a signal (POST /bye), so the engine normally exits in about 2 seconds.
Browser side — closes when the engine is gone
| State | Behavior |
|---|---|
Engine announces it is exiting (exiting on /sub/state) |
Closes the window immediately |
| SSE drops and does not recover within 5 seconds (crash, etc.) | Closes the window |
window.close() has no effect (regular tab) |
Shows "Kirikiri Z has exited" full-page |
Display language¶
By default it follows the engine's language setting (-language= and the OS
language are reflected as-is, matching the engine's messages). You can also switch
on the spot with the language selector at the top; the choice is remembered by that
browser.
Currently Japanese / English are supported. If the engine has selected another language (Chinese, etc.), it falls back to English the same way the engine does.
Pad (script editor)¶
Write multi-line TJS and run it all at once with Ctrl+Enter (unlike the
single-line execution of /cmd, you can submit function definitions and loops
as-is). The text is auto-saved to the browser's localStorage, so it survives
a reload.
The path field + [Load] / [Save] exchange files with storage, but saving is
disabled by default. Only when -replwebpad=<dir> is specified can you write
under that directory (a fence against "accidentally hitting [Save] in the UI and
overwriting assets". Anyone who can open -replweb can already run arbitrary TJS,
so this is not a security boundary).
Automatic browser launch (-replwebopen)¶
By default it opens in app mode only when "bound to loopback and there is no console
(GUI launch)". It does not open when launched from a terminal. Explicit values
are -replwebopen=app (app mode) / tab (regular window) / no (do not open).
To launch from a terminal and still open the browser, use -replwebopen=app.
Watch expression HTTP API (-replweb)¶
With -replweb, watch expressions can also be handled from a browser or curl.
| Route | Description |
|---|---|
GET /watch |
List + current values (JSON). Does not evaluate, so polling is safe. ?eval=1 evaluates before returning |
POST /watch |
Operations (form-urlencoded). op=add&expr=… / op=rm&id=… / op=edit&id=…&expr=… / op=clear / op=interval&ms=… / op=eval |
GET /sub/watch |
Auto-refresh push (SSE). Sent when a value changes, and on changes that involve no evaluation (remove / clear / interval change) |
Built-in routes are matched before register
/ /events /cmd /sub/<ch> /watch /state /pad/exec /pad/file
/bye cannot be overridden by WebServer.register /
serveStatic.
Use a different prefix (/api/, /ui/, etc.) for your own endpoints.
curl -s -X POST -d 'op=add&expr=System.getTickCount()' localhost:8899/watch
curl -s -X POST -d 'op=interval&ms=500' localhost:8899/watch
curl -N localhost:8899/sub/watch
Responses and pushes have the same shape.
{"interval":500,"entries":[{"id":1,"expr":"System.getTickCount()","value":"32470","error":false}]}
Socket channel (-replsocket / Linux-family only)¶
Specifying -replsocket=<name> (or the environment variable KRKRZ_REPL_SOCKET)
starts a command channel listening on an abstract-namespace Unix domain socket
(Linux-family builds only; ignored on other OSes). It is the socket version of the
file channel: it accepts one command (TJS expression) per line, runs it on the main
thread, and replies with one line of JSON. It can be started independently of
-repl / -replfile, and they can be used together.
- A
\at the end of a line marks a continuation line, so multiple lines can be run as one command with line breaks preserved (a continuation marker on the wire that also works from tools likenc). - A single line beginning with
.is interpreted as a channel-side dot command (.help/.depth/.compact).
Agent class for agent-driven use (SDL3 build)¶
The SDL3 version of a KRKRZ_REPL build includes the
Agent
TJS class for driving krkrz from external agents and automated tests. Like the
System class, it is called through class methods (no instantiation needed).
| Feature | API (main methods) |
|---|---|
| Input injection | Agent.mouseMove / mouseDown / mouseUp / click / wheel, Agent.keyDown / keyUp / keyPress, Agent.text |
| Dialog observation / control | Agent.dialogs() / Agent.dialogTree(index) / Agent.dialogClick(index, id) / Agent.dialogFocus(index, id) / Agent.closeDialog() / Agent.closeAllDialogs() |
| Screen capture | Agent.captureScreen(path[, x, y, w, h]) / Agent.lastCapture() |
Input via Agent goes through the same TTVPWindowForm::Send* path as real input,
so it reaches both the game and Dialog.
captureScreen reads back the actual screen, including overlays, just before the
next frame's present and saves it as PNG (even if the engine is idle when requested,
it is saved one frame later).
The class is registered only in SDL3 builds with KRKRZ_REPL=ON. For specification
details (button constants, shift mask, the file channel protocol, etc.) see
doc/REPL.md.