code wiki / _hdl_build / nx_uigen_refine.nx
nx_uigen_refine.nx source
↩ module page · 131 lines · 6578 B
1// nx_uigen_refine.nx -- R-refine-live front door: apply ONE spec-delta refine command to a generated
2// site's design and emit the refined INDEX page. The v0 chat-loop analog, rule-based and deterministic:
3// the SAME l3_refine grammar the refine gate measured 8/8 (targeted change + preservation + refusal),
4// lifted to site level -- the spec is derived from the brief exactly as nx_uigen_sitegen derives it, the
5// command mutates one axis, and the page re-emits with the site's real nav + requirements copy intact.
6// usage: nx_uigen_refine <brief> <cmd> <outdir> [title] [brand] [domain] [reqfile]
7// cmds: "hue N" | "accent analog|complement|triad" | "rounder"|"sharper" | "compact"|"airy" |
8// "add <band>" | "drop <band>" (bands: features split steps pricing quote faq trust)
9// An invalid or validity-breaking command is REFUSED loudly (exit 5, nothing written) -- never a silent
10// no-op. expect_exit: 0 license_tier: ORIGINAL
11import "nx_syscalls.nx"
12import "nx_uigen_site.nx"
13import "nx_emit_guard.nx"
14
15// one page buffer (a page is ~20KB; 1MiB is 50x headroom) and one path buffer -- named so the
16// magic-number ratchet stays satisfied and the sizes are stated once (rule 11).
17const K_PAGEBUF: i64 = 1048576
18const K_PATHBUF: i64 = 1024
19
20
21func rp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
22func rjoin(dst: *u8, dir: *u8, name: *u8) -> i64 {
23 var o: i64 = 0
24 var i: i64 = 0
25 while dir[i] != (0 as u8) { dst[o] = dir[i]; o = o + 1; i = i + 1 }
26 dst[o] = 47 as u8
27 o = o + 1
28 i = 0
29 while name[i] != (0 as u8) { dst[o] = name[i]; o = o + 1; i = i + 1 }
30 dst[o] = 0 as u8
31 return o
32}
33func rn(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 }
34
35func main(argc: i64, argv: *i64) -> i64 {
36 if argc < 4 {
37 rp("usage: nx_uigen_refine <brief> <cmd> <outdir> [title] [brand] [domain] [reqfile]\n" as *u8)
38 rp(" applies ONE refine command to the brief's generated design and re-emits the WHOLE site\n" as *u8)
39 rp(" <cmd> is ONE argv token: 'hue <0-359>' | 'accent analog|complement|triad' | 'sharper' |\n" as *u8)
40 rp(" 'rounder' | 'compact' | 'airy' | 'add <section>' | 'drop <section>' (quote two-word cmds)\n" as *u8)
41 sys_exit(2)
42 return 2
43 }
44 let brief: *u8 = argv[1] as *u8
45 let cmd: *u8 = argv[2] as *u8
46 let outpath: *u8 = argv[3] as *u8
47 var title: *u8 = "Generated Site" as *u8
48 if argc > 4 { title = argv[4] as *u8 }
49 var brand: *u8 = title
50 if argc > 5 { brand = argv[5] as *u8 }
51 var domain: *u8 = "example.com" as *u8
52 if argc > 6 { domain = argv[6] as *u8 }
53 var req: *u8 = 0 as *u8
54 if argc > 7 {
55 let rlen: *i64 = sys_mmap(8) as *i64
56 let raw: *u8 = sys_read_file(argv[7] as *u8, rlen)
57 if (raw as i64) == 0 { rp("REFINE-FAIL cannot read reqfile\n" as *u8); sys_exit(4); return 4 }
58 let rl: i64 = rlen[0]
59 req = sys_mmap(rl + 1)
60 var ci: i64 = 0
61 while ci < rl { req[ci] = raw[ci]; ci = ci + 1 }
62 req[rl] = 0 as u8
63 }
64
65 let plan: *i64 = sys_mmap(64) as *i64
66 let n: i64 = us_plan(brief, plan)
67 let spec: *i64 = sys_mmap(128) as *i64
68 us_spec(brief, spec)
69 let applied: i64 = l3_refine(spec, cmd)
70 if applied == 0 {
71 rp("REFINE-REFUSED cmd=" as *u8); rp(cmd)
72 rp(" (unknown command or it would break grammar validity); nothing written\n" as *u8)
73 sys_exit(5)
74 return 5
75 }
76 // ★ refine the WHOLE SITE, not just the index. Rewriting only index.html left every subpage on the
77 // OLD palette -- a refined site that contradicts itself, which is precisely the site-wide coherence
78 // this lane advertises. outpath is a DIRECTORY; sitemap+robots re-derive from the same plan.
79 let mk: i64 = sys_mkdir(outpath, 493)
80 // guards live in nx_emit_guard (one home, both emitter CLIs)
81 let buf: *u8 = eg_buf(K_PAGEBUF, "refine page buffer" as *u8)
82 let path: *u8 = eg_buf(K_PATHBUF, "refine path buffer" as *u8)
83 rp("REFINE-DIAG mkdir=" as *u8); rn(mk); rp(" pages=" as *u8); rn(n); rp(" lens=" as *u8)
84 var total: i64 = 0
85 var pi: i64 = 0
86 while pi < n {
87 var len: i64 = 0
88 if plan[pi] == 0 { len = us_page_index_routed(buf, 0, brief, spec, title, brand, plan, n, req) }
89 else { len = us_emit_page_req_spec(buf, 0, brief, spec, title, brand, plan, n, plan[pi], req) }
90 rn(len); rp("," as *u8)
91 eg_assert_size(len, "refined page" as *u8)
92 rjoin(path, outpath, us_slug(plan[pi]))
93 let fd: i64 = sys_openat_wr(path, 420)
94 if fd < 0 { rp("REFINE-FAIL cannot write " as *u8); rp(path); rp("\n" as *u8); sys_exit(3); return 3 }
95 let w: i64 = sys_write(fd, buf, len)
96 sys_close(fd)
97 if w != len { rp("REFINE-FAIL short write\n" as *u8); sys_exit(3); return 3 }
98 total = total + len
99 pi = pi + 1
100 }
101 var ml: i64 = us_sitemap(buf, 0, domain, plan, n)
102 rjoin(path, outpath, "sitemap.xml" as *u8)
103 let mfd: i64 = sys_openat_wr(path, 420)
104 if mfd < 0 { rp("REFINE-FAIL cannot write sitemap\n" as *u8); sys_exit(3); return 3 }
105 sys_write(mfd, buf, ml); sys_close(mfd)
106 ml = us_robots(buf, 0, domain)
107 rjoin(path, outpath, "robots.txt" as *u8)
108 let rfd: i64 = sys_openat_wr(path, 420)
109 if rfd < 0 { rp("REFINE-FAIL cannot write robots\n" as *u8); sys_exit(3); return 3 }
110 sys_write(rfd, buf, ml); sys_close(rfd)
111 // ★ POST-WRITE SET ASSERTION: every planned slug must exist on disk before success is printed.
112 // A tool that emits a SET must prove the SET, not each file in isolation (the round-18 law).
113 var vi: i64 = 0
114 while vi < n {
115 rjoin(path, outpath, us_slug(plan[vi]))
116 eg_assert_present(path)
117 vi = vi + 1
118 }
119 let len: i64 = total
120 rp("\n" as *u8)
121 rp("{\"organ\":\"nx_uigen_refine\",\"v\":1,\"cmd\":\"" as *u8); rp(cmd)
122 rp("\",\"applied\":1,\"hue\":" as *u8); rn(spec[0])
123 rp(",\"accent_rel\":" as *u8); rn(spec[1])
124 rp(",\"radius_idx\":" as *u8); rn(spec[2])
125 rp(",\"density\":" as *u8); rn(spec[3])
126 rp(",\"nmid\":" as *u8); rn(spec[4])
127 rp(",\"bytes\":" as *u8); rn(len)
128 rp(",\"env\":\"one command per call off the brief-derived spec; deterministic; grammar-refusal is loud (exit 5)\"}\n" as *u8)
129 sys_exit(0)
130 return 0
131}