///|
/// 毫秒时间戳 → 秒级 Epoch(上游 Epoch 为秒;@async.now() 实测毫秒)
fn current_second() -> Int64 {
@async.now() / 1000L
}
///|
/// stderr 消息收集:不直接写 fd,由 main 统一落盘。
/// (moon test 进程里写 stderr 会 panic,收集式设计同时让错误文案可被测试断言)
fn err_line(errs : Array[String], msg : String) -> Unit {
errs.push(msg)
}
///|
/// 无换行 stdout 输出(对齐上游 print! 语义);写失败吞掉
/// (对齐 main 对 stderr 写失败的处理)
async fn print_stdout(s : String) -> Unit {
@stdio.stdout.write(s) catch {
_ => ()
}
}
///|
/// query --interactive 的 fzf 结果 → 退出码/文案映射(纯逻辑,wbtest 直测;
/// 进程面由 platform 伪 fzf E2E 与 dataset_check D9 对拍覆盖)。
/// stdout 片段收集进 outs 由调用侧落盘(收集式同 errs:moon test 进程内
/// 直写 stdout 会与 test driver 事件协议串扰)。
/// 输出对齐上游 print!:不追加换行(fzf 自身输出带尾换行);--score 输出
/// 整行,否则剥掉 7 字符得分前缀(对齐上游 selection.get(7..),len==7 →
/// 空串原样输出);len<7 上游走错误路(探针 2026-09-13:exit 1 +
/// "could not read selection from fzf")。退出码表:0 成功 / 1 无选择
/// (上游报 "no match found",jumbit 静默——取消语义,README 注明)/
/// 2 与 128..=254 与信号杀死与 3..=127、255 均 exit 1 带对应文案 /
/// 130 静默透传 130
fn finish_interactive(
selection : Result[String, @platform.FzfError],
score : Bool,
errs : Array[String],
outs : Array[String],
) -> Int {
match selection {
Ok(s) => {
if score {
outs.push(s)
} else if s.length() >= 7 {
outs.push(s[7:].to_owned())
} else {
err_line(errs, "could not read selection from fzf")
return 1
}
0
}
Err(@platform.NotFound) => {
err_line(errs, "could not find fzf, is it installed?")
1
}
Err(@platform.NoMatch) => 1
Err(@platform.ReturnedAnError) => {
err_line(errs, "fzf returned an error")
1
}
Err(@platform.Interrupted) => 130
Err(@platform.Terminated) => {
err_line(errs, "fzf was terminated")
1
}
Err(@platform.UnknownExit(_)) => {
err_line(errs, "fzf returned an unknown error")
1
}
}
}
///|
/// 配置解析步骤的统一出口:Err 文案写入 errs 后返回 None,调用方以
/// `match { None => return 1 }` 提前退出。各子命令保留各自的解析顺序
/// (对齐上游:add 先读配置再开库,query/import 先开库)
/// 各子命令保留各自的解析顺序(对齐上游:add 先读配置再开库,query/import 先开库)
fn[T] cfg(r : Result[T, String], errs : Array[String]) -> T? {
match r {
Ok(v) => Some(v)
Err(msg) => {
err_line(errs, msg)
None
}
}
}
///|
/// 打开数据库:打开失败的文案与配置错误分开(含 Repr 调试格式)
async fn open_store(
data_dir : String,
errs : Array[String],
) -> @platform.Store? {
match @platform.load(data_dir) {
Ok(s) => Some(s)
Err(err) => {
err_line(errs, "jumbit: could not open database: \{err.message()}")
None
}
}
}
///|
/// 结束统一落盘:保存失败时退出码覆盖为 1,否则透传原退出码
async fn finish(
store : @platform.Store,
errs : Array[String],
code : Int,
) -> Int {
match store.save() {
Ok(_) => code
Err(err) => {
err_line(errs, "jumbit: could not save database: \{err.message()}")
1
}
}
}
///|
/// 全部子命令的执行入口。
/// 返回进程退出码:0 成功 / 1 运行失败(含配置错误,对齐上游 ExitCode::FAILURE)
/// / 2 用法错误(对齐 clap 参数解析错误)。stderr 消息写入 errs。
pub async fn run(
args : Array[String],
getenv : (String) -> String?,
errs : Array[String],
) -> Int {
match @cli.parse(args) {
@cli.Help => {
println(@cli.usage())
0
}
@cli.Version => {
println(@cli.version())
0
}
@cli.Usage => {
// 帮助全文走 stderr + 退出码 2(对齐上游 clap 无子命令调用)
err_line(errs, @cli.usage())
2
}
@cli.Unknown(cmd) => {
// clap 习语(上游 probe:error: unrecognized subcommand 'x' + try 行)
err_line(errs, "error: unrecognized subcommand '\{cmd}'")
err_line(errs, "For more information, try 'jumbit help'.")
2
}
@cli.Add(aopts) => run_add(aopts, getenv, errs)
@cli.Invalid(msg) => {
err_line(errs, "error: \{msg}")
err_line(errs, "For more information, try 'jumbit help'.")
2
}
@cli.Query(qopts) => run_query(qopts, getenv, errs)
@cli.Remove(paths) => run_remove(paths, getenv, errs)
@cli.Init(iopts) => run_init(iopts, getenv, errs)
@cli.Import(iopts) => run_import(iopts, getenv, errs)
@cli.Describe(dopts) => run_describe(dopts, getenv, errs)
@cli.Export(eopts) => run_export(eopts, getenv, errs)
@cli.Status(sopts) => run_status(sopts, getenv, errs)
@cli.Edit(eopts) => run_edit(eopts, getenv, errs)
@cli.Mcp => run_mcp(getenv)
}
}
///|
/// _JB_ECHO 调试回显开关:仅值 "1" 生效(对齐上游 config::echo)
fn echo_enabled(getenv : (String) -> String?) -> Bool {
match getenv("_JB_ECHO") {
Some("1") => true
_ => false
}
}
///|
/// _JB_EXCLUDE_DIRS glob 命中检测(add 与 import 共用;命中即静默跳过)
fn glob_hit(globs : Array[String], path : String) -> Bool {
for pattern in globs {
if @core.glob_match(pattern, path) {
return true
}
}
false
}
///|
/// 双重尝试(对齐上游 remove.rs 的双重查找语义):先原串,未中再按 cwd 规范化重试
fn try_twice(
db : @core.Database,
path : String,
cwd : String,
op : (@core.Database, String) -> Bool,
) -> Bool {
if op(db, path) {
return true
}
op(db, @core.resolve_path(path, cwd))
}
///|
/// 双重查找:try_twice 的查找版(describe 显示路需要下标而非布尔)
fn find_twice(db : @core.Database, path : String, cwd : String) -> Int? {
match db.find_idx(path) {
Some(i) => Some(i)
None => db.find_idx(@core.resolve_path(path, cwd))
}
}