code wiki / _hdl_build / nx_uigen_sitegen.nx

nx_uigen_sitegen.nx source

↩ module page · 127 lines · 5565 B

1// nx_uigen_sitegen.nx -- CLI front door for prompt-to-site: ONE brief -> a linked multi-page site ON DISK. 2// usage: nx_uigen_sitegen <brief> <outdir> <domain> [title] [brand] 3// Thin syscall wrapper over the pure lib nx_uigen_site.nx (which the gate proves): us_plan -> per-page 4// us_emit_page -> outdir/<slug> + sitemap.xml + robots.txt, then ONE machine-readable JSON summary line 5// (agentic/workflow contract; additive fields only, rule 19). Fail-LOUD: any write failure exits nonzero 6// with the path named -- a partial site is never reported as success. Envelope declared in-band. 7// expect_exit: 0 license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_uigen_site.nx" 10import "nx_emit_guard.nx" 11 12// page + path buffer sizes, named once (rule 11) 13const K_SG_PAGEBUF: i64 = 1048576 14const K_SG_PATHBUF: i64 = 1024 15 16func cp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 17func cn(v: i64) -> i64 { if v==0 { sys_write(1,"0" as *u8,1); return 0 } var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } let t: *u8=sys_mmap(28); var k: i64=0; while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } while k>0 { k=k-1; sys_write(1,(((t as i64)+k) as *u8),1) } return 0 } 18// join dir + "/" + name into dst (0-terminated) 19func pjoin(dst: *u8, dir: *u8, name: *u8) -> i64 { 20 var o: i64 = 0 21 var i: i64 = 0 22 while dir[i] != (0 as u8) { dst[o] = dir[i]; o = o + 1; i = i + 1 } 23 dst[o] = 47 as u8 24 o = o + 1 25 i = 0 26 while name[i] != (0 as u8) { dst[o] = name[i]; o = o + 1; i = i + 1 } 27 dst[o] = 0 as u8 28 return o 29} 30// write len bytes at buf+base to path; returns 1 ok / 0 fail 31func fput(path: *u8, buf: *u8, base: i64, len: i64) -> i64 { 32 let fd: i64 = sys_openat_wr(path, 420) 33 if fd < 0 { return 0 } 34 let w: i64 = sys_write(fd, (((buf as i64) + base) as *u8), len) 35 sys_close(fd) 36 if w != len { return 0 } 37 return 1 38} 39 40func main(argc: i64, argv: *i64) -> i64 { 41 if argc < 4 { 42 cp("usage: nx_uigen_sitegen <brief> <outdir> <domain> [title] [brand] [reqfile]\n" as *u8) 43 cp(" one written brief -> a linked multi-page site (pages + sitemap.xml + robots.txt) in <outdir>\n" as *u8) 44 cp(" reqfile (optional): '<page>|<key>|<value>' lines of real copy; absent keys keep defaults\n" as *u8) 45 sys_exit(2) 46 return 2 47 } 48 let brief: *u8 = argv[1] as *u8 49 let outdir: *u8 = argv[2] as *u8 50 let domain: *u8 = argv[3] as *u8 51 var title: *u8 = "Generated Site" as *u8 52 if argc > 4 { title = argv[4] as *u8 } 53 var brand: *u8 = title 54 if argc > 5 { brand = argv[5] as *u8 } 55 var req: *u8 = 0 as *u8 56 var reqlines: i64 = 0 57 if argc > 6 { 58 let rlen: *i64 = sys_mmap(8) as *i64 59 let raw: *u8 = sys_read_file(argv[6] as *u8, rlen) 60 if (raw as i64) == 0 { 61 cp("SITEGEN-FAIL cannot read reqfile " as *u8); cp(argv[6] as *u8); cp("\n" as *u8) 62 sys_exit(4) 63 return 4 64 } 65 let rl: i64 = rlen[0] 66 req = sys_mmap(rl + 1) 67 var ci: i64 = 0 68 while ci < rl { req[ci] = raw[ci]; ci = ci + 1 } 69 req[rl] = 0 as u8 70 ci = 0 71 while ci < rl { if req[ci] == (10 as u8) { reqlines = reqlines + 1 } ci = ci + 1 } 72 } 73 74 sys_mkdir(outdir, 493) 75 // guards live in nx_emit_guard (one home, both emitter CLIs) -- an unchecked allocation turns a 76 // generator into a silent no-op that still prints success 77 let buf: *u8 = eg_buf(K_SG_PAGEBUF, "sitegen page buffer" as *u8) 78 let path: *u8 = eg_buf(K_SG_PATHBUF, "sitegen path buffer" as *u8) 79 let plan: *i64 = sys_mmap(64) as *i64 80 let n: i64 = us_plan(brief, plan) 81 var total: i64 = 0 82 var i: i64 = 0 83 while i < n { 84 let len: i64 = us_emit_page_req(buf, 0, brief, title, brand, plan, n, plan[i], req) 85 eg_assert_size(len, "generated page" as *u8) 86 pjoin(path, outdir, us_slug(plan[i])) 87 if fput(path, buf, 0, len) == 0 { 88 cp("SITEGEN-FAIL cannot write " as *u8); cp(path); cp("\n" as *u8) 89 sys_exit(3) 90 return 3 91 } 92 total = total + len 93 i = i + 1 94 } 95 var mlen: i64 = us_sitemap(buf, 0, domain, plan, n) 96 pjoin(path, outdir, "sitemap.xml" as *u8) 97 if fput(path, buf, 0, mlen) == 0 { cp("SITEGEN-FAIL cannot write sitemap\n" as *u8); sys_exit(3); return 3 } 98 total = total + mlen 99 mlen = us_robots(buf, 0, domain) 100 pjoin(path, outdir, "robots.txt" as *u8) 101 if fput(path, buf, 0, mlen) == 0 { cp("SITEGEN-FAIL cannot write robots\n" as *u8); sys_exit(3); return 3 } 102 total = total + mlen 103 104 // POST-WRITE SET ASSERTION: prove the whole set exists before claiming success (the round-18 law) 105 var vi: i64 = 0 106 while vi < n { 107 pjoin(path, outdir, us_slug(plan[vi])) 108 eg_assert_present(path) 109 vi = vi + 1 110 } 111 // machine-readable summary (ONE line JSON; additive-only contract) 112 cp("{\"organ\":\"nx_uigen_sitegen\",\"v\":1,\"pages\":" as *u8); cn(n) 113 cp(",\"slugs\":[" as *u8) 114 i = 0 115 while i < n { 116 if i > 0 { cp("," as *u8) } 117 cp("\"" as *u8); cp(us_slug(plan[i])); cp("\"" as *u8) 118 i = i + 1 119 } 120 cp("],\"hue\":" as *u8); cn(l2_hue(brief)) 121 cp(",\"seed\":" as *u8); cn(us_hash(brief)) 122 cp(",\"bytes\":" as *u8); cn(total) 123 cp(",\"req_lines\":" as *u8); cn(reqlines) 124 cp(",\"deterministic\":1,\"env\":\"bounded 6-page vocabulary; copy=req-brief-or-default (prose gen=L4); flat basenames; sitemap+robots derived from the same plan\"}\n" as *u8) 125 sys_exit(0) 126 return 0 127}