nx_wflow.nx source
↩ module page · 118 lines · 6729 B
1// nx_wflow.nx -- the PRODUCTION CLI over the pure-core workflow engine (nx_wflow_engine.nx). This is how
2// the ecosystem drives workflows: definitions live as DATA FILES (flows: `flowid|event-kind|cond`, steps:
3// `flowid|idx|action|channel|arg|max-attempts`), the run ledger is append-only event-sourced, connectors
4// come from the GREEN fail-closed catalog. The tickless scheduler / dispatcher / vizsla can fork this elf.
5// Commands:
6// fire <flows> <steps> <ledger> <catalog|-> <event> event = kind~k=v~...~id=EN
7// resume <flows> <steps> <ledger> <catalog|-> complete every in-flight run
8// decide <ledger> <rid> <step> <APPROVED|DENIED> <who> unblock or fail a parked approval
9// board <ledger> console run board (ledger replay)
10// html <ledger> <out.html> 0-JS run board page
11// Argless = usage (exit 0 so the build lane passes). license_tier: ORIGINAL expect_exit: 0
12import "nx_wflow_result.nx"
13
14func wu() -> i64 {
15 p("nx_wflow -- sovereign workflow automation CLI (durable runs, retries, approvals, connectors)\n" as *u8)
16 p(" fire <flows> <steps> <ledger> <catalog|-> <event>\n" as *u8)
17 p(" resume <flows> <steps> <ledger> <catalog|->\n" as *u8)
18 p(" fire-result <flows> <steps> <ledger> <catalog|-> <event> <new-evidence-log>\n" as *u8)
19 p(" resume-result <flows> <steps> <ledger> <catalog|-> <new-evidence-log>\n" as *u8)
20 p(" result <ledger> <evidence-log> <run-id|*> read-only; never executes connectors\n" as *u8)
21 p(" event-result <ledger> <evidence-log> <exact-event-id> read-only reconciliation; never retries\n" as *u8)
22 p(" decide <ledger> <rid> <step> <APPROVED|DENIED> <who>\n" as *u8)
23 p(" board <ledger>\n" as *u8)
24 p(" html <ledger> <out.html>\n" as *u8)
25 p(" verify <flows> <steps> validate a draft definition set without firing\n" as *u8)
26 p(" templates [dir] list the template gallery (default knowledge/wflow/templates)\n" as *u8)
27 p(" instantiate <name> <destflows> <deststeps> [dir] adopt a gallery template (validated whole)\n" as *u8)
28 return 0
29}
30
31// Preserve the native failure code without inventing an effect/rollback outcome.
32// A command can fail after an external effect; callers must reconcile its ledger.
33func wu_failure(command:*u8,code:i64)->i64 {
34 p("{\"schema\":\"nishi-workflow-error/1\",\"owner\":\"nx_wflow\",\"command\":\"" as *u8)
35 p(command)
36 p("\",\"native_code\":" as *u8);pn(code)
37 p(",\"state\":\"failed\",\"effects\":\"unverified\",\"retry\":\"reconcile-first\",\"next\":\"Inspect command input, durable run ledger and connector receipts before retrying\"}\n" as *u8)
38 return 1
39}
40
41func main(argc: i64, argv: *i64) -> i64 {
42 if argc < 2 { return wu() }
43 let cmd: *u8 = argv[1] as *u8
44 if seq(cmd,"fire-result")==1{return wfr_execute(argc,argv,0)}
45 if seq(cmd,"resume-result")==1{return wfr_execute(argc,argv,1)}
46 if seq(cmd,"event-result")==1{if argc!=5{return 2};return wfr_summary(argv[2] as *u8,argv[3] as *u8,argv[4] as *u8,1,0,0-1)}
47 if seq(cmd,"result")==1{if argc<5{return 2};return wfr_summary(argv[2] as *u8,argv[3] as *u8,argv[4] as *u8,0,0,0-1)}
48 if seq(cmd, "fire" as *u8) == 1 {
49 if argc < 7 { p("WFLOW fire needs flows steps ledger catalog event -- fail loud\n" as *u8); return 2 }
50 let rc: i64 = wf_fire_files(argv[2] as *u8, argv[3] as *u8, argv[4] as *u8, argv[5] as *u8, argv[6] as *u8)
51 if rc == (0 - 100) { p("WFLOW-FIRE dedup: already started\n" as *u8); return 0 }
52 if rc < 0 { return wu_failure(cmd,rc) }
53 p("WFLOW-FIRE started=" as *u8); pn(rc); p("\n" as *u8)
54 return 0
55 }
56 if seq(cmd, "resume" as *u8) == 1 {
57 if argc < 6 { p("WFLOW resume needs flows steps ledger catalog -- fail loud\n" as *u8); return 2 }
58 let rc: i64 = wf_resume_files(argv[2] as *u8, argv[3] as *u8, argv[4] as *u8, argv[5] as *u8)
59 if rc < 0 { return wu_failure(cmd,rc) }
60 p("WFLOW-RESUME resumed=" as *u8); pn(rc); p("\n" as *u8)
61 return 0
62 }
63 if seq(cmd, "decide" as *u8) == 1 {
64 if argc < 7 { p("WFLOW decide needs ledger rid step decision who -- fail loud\n" as *u8); return 2 }
65 let cx: *i64 = sys_mmap(32) as *i64
66 cx[2] = argv[2] as i64
67 let idx: i64 = wf_atoi(argv[4] as *u8)
68 if idx < 1 { p("WFLOW decide ERROR bad step -- fail loud\n" as *u8); return 2 }
69 let rc: i64 = wf_decide(cx, argv[3] as *u8, idx, argv[5] as *u8, argv[6] as *u8)
70 if rc != 0 { return wu_failure(cmd,rc) }
71 p("WFLOW-DECIDE recorded\n" as *u8)
72 return 0
73 }
74 if seq(cmd, "board" as *u8) == 1 {
75 if argc < 3 { p("WFLOW board needs ledger -- fail loud\n" as *u8); return 2 }
76 let rc: i64 = wf_obs_board(argv[2] as *u8)
77 if rc < 0 { return wu_failure(cmd,rc) }
78 return 0
79 }
80 if seq(cmd, "html" as *u8) == 1 {
81 if argc < 4 { p("WFLOW html needs ledger out -- fail loud\n" as *u8); return 2 }
82 let rc: i64 = wf_obs_html(argv[2] as *u8, argv[3] as *u8)
83 if rc < 0 { return wu_failure(cmd,rc) }
84 p("WFLOW-HTML runs=" as *u8); pn(rc); p("\n" as *u8)
85 return 0
86 }
87 if seq(cmd, "verify" as *u8) == 1 {
88 if argc < 4 { p("WFLOW verify needs flows steps -- fail loud\n" as *u8); return 2 }
89 let fl: *i64 = sys_mmap(8 * 64) as *i64
90 let st2: *i64 = sys_mmap(8 * 128) as *i64
91 let nf: i64 = wf_lines_load(argv[2] as *u8, fl, 64)
92 if nf < 1 { return 1 }
93 let nst: i64 = wf_lines_load(argv[3] as *u8, st2, 128)
94 if nst < 1 { return 1 }
95 if wf_load_flows(fl, nf) < 0 { return 1 }
96 if wf_load(st2, nst) < 0 { return 1 }
97 let v: i64 = wf_defs_version(argv[2] as *u8)
98 p("WFLOW-VERIFY version=" as *u8); pn(v); p(" flows=" as *u8); pn(nf); p(" steps=" as *u8); pn(nst); p(" verdict=VALID\n" as *u8)
99 return 0
100 }
101 if seq(cmd, "templates" as *u8) == 1 {
102 var dirp: *u8 = "knowledge/wflow/templates" as *u8
103 if argc >= 3 { dirp = argv[2] as *u8 }
104 let rc: i64 = wf_tpl_list(dirp)
105 if rc < 0 { return wu_failure(cmd,rc) }
106 return 0
107 }
108 if seq(cmd, "instantiate" as *u8) == 1 {
109 if argc < 5 { p("WFLOW instantiate needs name destflows deststeps -- fail loud\n" as *u8); return 2 }
110 var dirp: *u8 = "knowledge/wflow/templates" as *u8
111 if argc >= 6 { dirp = argv[5] as *u8 }
112 let rc: i64 = wf_tpl_instantiate(dirp, argv[2] as *u8, argv[3] as *u8, argv[4] as *u8)
113 if rc < 0 { return wu_failure(cmd,rc) }
114 return 0
115 }
116 p("WFLOW unknown command -- fail loud\n" as *u8)
117 return 2
118}