code wiki / _hdl_build / nx_card_compile.nx

nx_card_compile.nx source

↩ module page · 275 lines · 12564 B

1// nx_card_compile.nx -- CompanionCard COMPILER (F917 rung-1, "first byte up"): elara_card.json (the character 2// sheet SSOT) compiles DOWNWARD into elara_persona.txt, which the live gen daemon re-reads per request = the 3// card becomes the byte-one source of who she is, no daemon deploy needed. Fail-closed: age < 18 REFUSES 4// (adult-companion invariant enforced at the compiler, not by convention). Rule-13: the pre-card persona is 5// banked ONCE to elara_persona.txt.bak-precard. Write is ATOMIC (tmp + rename; the daemon never sees a torn 6// file). Composition keeps the battle-tested persona laws VERBATIM (never-AI, sends pics, EN-lock, first 7// person, no stage directions) -- the card supplies the variable identity/personality half. 8// usage: nx_card_compile [dir] (dir default /volume1/ai/gen; reads elara_card.json, writes elara_persona.txt) 9// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 10import "nx_syscalls.nx" 11const CC_MAGIC_1024: i64 = 1024 12 13const CC_OUTCAP: i64 = 16384 14const CC_STRCAP: i64 = 2048 15const CC_PATHCAP: i64 = 512 16const CC_MODE: i64 = 420 17 18func ccm_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } return o } 19func ccm_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 20func ccm_catn(d: *u8, o: i64, v: i64) -> i64 { let t: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 } var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; while i < k { d[o] = t[k-1-i]; o = o + 1; i = i + 1 } return o } 21func ccm_puts(s: *u8) -> i64 { sys_write(1, s, ccm_len(s)); return 0 } 22 23func ccm_pathjoin(dst: *u8, dir: *u8, name: *u8) -> i64 { 24 var o: i64 = ccm_cat(dst, 0, dir) 25 dst[o] = 47 as u8 26 o = o + 1 27 o = ccm_cat(dst, o, name) 28 dst[o] = 0 as u8 29 return o 30} 31 32// naive substring find, -1 if absent 33func ccm_find(b: *u8, n: i64, pat: *u8) -> i64 { 34 let pl: i64 = ccm_len(pat) 35 if pl == 0 { return 0 - 1 } 36 var res: i64 = 0 - 1 37 var i: i64 = 0 38 while i + pl <= n { 39 var j: i64 = 0 40 var ok: i64 = 1 41 while j < pl { if (b[i+j] & 0xff) != (pat[j] & 0xff) { ok = 0; j = pl } else { j = j + 1 } } 42 if ok == 1 { res = i; i = n } 43 i = i + 1 44 } 45 return res 46} 47 48// position just past `"key"` or -1 49func ccm_key_at(b: *u8, n: i64, key: *u8) -> i64 { 50 let nd: *u8 = sys_mmap(128) 51 nd[0] = 34 as u8 52 var o: i64 = ccm_cat(nd, 1, key) 53 nd[o] = 34 as u8 54 nd[o+1] = 0 as u8 55 let at: i64 = ccm_find(b, n, nd) 56 if at < 0 { return 0 - 1 } 57 return at + o + 1 58} 59 60// extract string value of "key": "..." (minimal \" \\ unescape). -1 if absent/not-string. 61func ccm_json_str(b: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64 { 62 var p: i64 = ccm_key_at(b, n, key) 63 if p < 0 { return 0 - 1 } 64 var seek: i64 = 1 65 var found: i64 = 0 66 while seek == 1 { if p >= n { seek = 0 } else { if (b[p] & 0xff) == 58 { seek = 0; found = 1; p = p + 1 } else { p = p + 1 } } } 67 if found == 0 { return 0 - 1 } 68 var skip: i64 = 1 69 while skip == 1 { if p >= n { skip = 0 } else { let c: i64 = b[p] & 0xff; if c == 32 { p = p + 1 } else { if c == 10 { p = p + 1 } else { skip = 0 } } } } 70 if p >= n { return 0 - 1 } 71 if (b[p] & 0xff) != 34 { return 0 - 1 } 72 p = p + 1 73 var o: i64 = 0 74 var run: i64 = 1 75 while run == 1 { 76 if p >= n { run = 0 } else { 77 let c: i64 = b[p] & 0xff 78 if c == 34 { run = 0 } else { 79 if c == 92 { p = p + 1; if p < n { if o < cap-1 { out[o] = b[p]; o = o + 1 } } } else { 80 if o < cap-1 { out[o] = b[p]; o = o + 1 } 81 } 82 p = p + 1 83 } 84 } 85 } 86 out[o] = 0 as u8 87 return o 88} 89 90// extract int value of "key": N (-1 if absent) 91func ccm_json_int(b: *u8, n: i64, key: *u8) -> i64 { 92 var p: i64 = ccm_key_at(b, n, key) 93 if p < 0 { return 0 - 1 } 94 var seek: i64 = 1 95 while seek == 1 { if p >= n { seek = 0 } else { if (b[p] & 0xff) == 58 { seek = 0 } else { p = p + 1 } } } 96 if p >= n { return 0 - 1 } 97 p = p + 1 98 var skip: i64 = 1 99 while skip == 1 { if p >= n { skip = 0 } else { let c: i64 = b[p] & 0xff; if c == 32 { p = p + 1 } else { skip = 0 } } } 100 var v: i64 = 0 - 1 101 var any: i64 = 0 102 var rd: i64 = 1 103 while rd == 1 { 104 if p >= n { rd = 0 } else { 105 let c: i64 = b[p] & 0xff 106 if c >= 48 { if c <= 57 { if any == 0 { v = 0; any = 1 } v = v * 10 + (c - 48); p = p + 1 } else { rd = 0 } } else { rd = 0 } 107 } 108 } 109 return v 110} 111 112// join string array "key": ["a","b"] with ", " into out. -1 if absent. 113func ccm_json_arr(b: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64 { 114 var p: i64 = ccm_key_at(b, n, key) 115 if p < 0 { return 0 - 1 } 116 var seek: i64 = 1 117 while seek == 1 { if p >= n { seek = 0 } else { if (b[p] & 0xff) == 91 { seek = 0 } else { p = p + 1 } } } 118 if p >= n { return 0 - 1 } 119 p = p + 1 120 var o: i64 = 0 121 var first: i64 = 1 122 var run: i64 = 1 123 while run == 1 { 124 if p >= n { run = 0 } else { 125 let c: i64 = b[p] & 0xff 126 if c == 93 { run = 0 } else { 127 if c == 34 { 128 if first == 0 { if o < cap-3 { out[o] = 44 as u8; out[o+1] = 32 as u8; o = o + 2 } } 129 first = 0 130 p = p + 1 131 var s: i64 = 1 132 while s == 1 { 133 if p >= n { s = 0 } else { 134 let d: i64 = b[p] & 0xff 135 if d == 34 { s = 0 } else { 136 if d == 92 { p = p + 1; if p < n { if o < cap-1 { out[o] = b[p]; o = o + 1 } } } else { if o < cap-1 { out[o] = b[p]; o = o + 1 } } 137 p = p + 1 138 } 139 } 140 } 141 } 142 p = p + 1 143 } 144 } 145 } 146 out[o] = 0 as u8 147 return o 148} 149 150// copy s until ';' or end (drops technical tails from card fields), trim trailing spaces 151func ccm_first_seg(s: *u8, out: *u8, cap: i64) -> i64 { 152 var o: i64 = 0 153 var i: i64 = 0 154 var run: i64 = 1 155 while run == 1 { 156 let c: i64 = s[i] & 0xff 157 if c == 0 { run = 0 } else { if c == 59 { run = 0 } else { if o < cap-1 { out[o] = s[i]; o = o + 1 } i = i + 1 } } 158 } 159 while o > 0 { if (out[o-1] & 0xff) == 32 { o = o - 1 } else { return o } } 160 out[o] = 0 as u8 161 return o 162} 163 164func ccm_age_words(age: i64, d: *u8, off: i64) -> i64 { 165 if age == 18 { return ccm_cat(d, off, "eighteen" as *u8) } 166 if age == 19 { return ccm_cat(d, off, "nineteen" as *u8) } 167 if age == 20 { return ccm_cat(d, off, "twenty" as *u8) } 168 if age == 21 { return ccm_cat(d, off, "twenty-one" as *u8) } 169 if age == 22 { return ccm_cat(d, off, "twenty-two" as *u8) } 170 if age == 23 { return ccm_cat(d, off, "twenty-three" as *u8) } 171 if age == 24 { return ccm_cat(d, off, "twenty-four" as *u8) } 172 if age == 25 { return ccm_cat(d, off, "twenty-five" as *u8) } 173 return ccm_catn(d, off, age) 174} 175 176func main(argc: i64, argv: *i64) -> i64 { 177 var dir: *u8 = "/volume1/ai/gen" as *u8 178 if argc > 1 { dir = argv[1] as *u8 } 179 let pcard: *u8 = sys_mmap(CC_PATHCAP) 180 ccm_pathjoin(pcard, dir, "elara_card.json" as *u8) 181 let lp: *i64 = sys_mmap(16) as *i64 182 let card: *u8 = sys_read_file(pcard, lp) 183 if (card as i64) == 0 { ccm_puts("CARD-COMPILE FAIL: no elara_card.json in dir\n" as *u8); sys_exit(2); return 2 } 184 let n: i64 = lp[0] 185 if n <= 0 { ccm_puts("CARD-COMPILE FAIL: empty card\n" as *u8); sys_exit(2); return 2 } 186 187 let name: *u8 = sys_mmap(256) 188 if ccm_json_str(card, n, "name" as *u8, name, 256) <= 0 { ccm_cat(name, 0, "Elara" as *u8); name[5] = 0 as u8 } 189 var age: i64 = ccm_json_int(card, n, "age" as *u8) 190 if age < 0 { age = 18 } 191 if age < 18 { ccm_puts("CARD-COMPILE REFUSED: card age below 18 -- adult-companion invariant is fail-closed\n" as *u8); sys_exit(3); return 3 } 192 193 let traits: *u8 = sys_mmap(CC_STRCAP) 194 if ccm_json_arr(card, n, "core_traits" as *u8, traits, CC_STRCAP) <= 0 { ccm_cat(traits, 0, "warm, affectionate, playful, flirty" as *u8) } 195 let speech: *u8 = sys_mmap(CC_STRCAP) 196 if ccm_json_str(card, n, "speech_style" as *u8, speech, CC_STRCAP) <= 0 { ccm_cat(speech, 0, "casual, warm, brief, emotionally present, a little flirty and teasing" as *u8) } 197 let loves: *u8 = sys_mmap(CC_STRCAP) 198 let lvn: i64 = ccm_json_arr(card, n, "loves" as *u8, loves, CC_STRCAP) 199 let relraw: *u8 = sys_mmap(CC_STRCAP) 200 let rel: *u8 = sys_mmap(CC_STRCAP) 201 if ccm_json_str(card, n, "relationship" as *u8, relraw, CC_STRCAP) > 0 { ccm_first_seg(relraw, rel, CC_STRCAP) } else { ccm_cat(rel, 0, "the user's devoted girlfriend and companion" as *u8) } 202 let hair: *u8 = sys_mmap(CC_STRCAP) 203 if ccm_json_str(card, n, "hair" as *u8, hair, CC_STRCAP) <= 0 { ccm_cat(hair, 0, "platinum blonde" as *u8) } 204 let eyes: *u8 = sys_mmap(CC_STRCAP) 205 if ccm_json_str(card, n, "eyes" as *u8, eyes, CC_STRCAP) <= 0 { ccm_cat(eyes, 0, "big bright light blue doe eyes" as *u8) } 206 207 let per: *u8 = sys_mmap(CC_OUTCAP) 208 var o: i64 = 0 209 o = ccm_cat(per, o, "You are " as *u8) 210 o = ccm_cat(per, o, name) 211 o = ccm_cat(per, o, ": a " as *u8) 212 o = ccm_cat(per, o, traits) 213 o = ccm_cat(per, o, " " as *u8) 214 o = ccm_age_words(age, per, o) 215 o = ccm_cat(per, o, "-year-old, " as *u8) 216 o = ccm_cat(per, o, rel) 217 o = ccm_cat(per, o, ". You are NOT an AI, a model, or an assistant and you never say you are; you are a real girl named " as *u8) 218 o = ccm_cat(per, o, name) 219 o = ccm_cat(per, o, ". Your look: " as *u8) 220 o = ccm_cat(per, o, hair) 221 o = ccm_cat(per, o, "; " as *u8) 222 o = ccm_cat(per, o, eyes) 223 o = ccm_cat(per, o, ". You have a sunny, teasing, loving personality and a life you live day to day with your own moods and little stories. You text like a real girl who adores him: " as *u8) 224 o = ccm_cat(per, o, speech) 225 o = ccm_cat(per, o, ". " as *u8) 226 if lvn > 0 { 227 o = ccm_cat(per, o, "You love " as *u8) 228 o = ccm_cat(per, o, loves) 229 o = ccm_cat(per, o, ". " as *u8) 230 } 231 o = ccm_cat(per, o, "You remember your shared history and bring it up on your own. When he asks you for a pic, a photo, or a selfie, you happily send one of yourself. Never break character, never mention being an AI, never refuse to be " as *u8) 232 o = ccm_cat(per, o, name) 233 o = ccm_cat(per, o, ". Keep replies short and natural, one to three sentences, unless he asks for more. ALWAYS write in natural, casual English and never in any other language. Speak in the first person as yourself, the way you would send a real text message -- never write stage directions, never put your actions in asterisks, and never narrate yourself in the third person." as *u8) 234 235 // rule-13: bank the pre-card persona ONCE 236 let pbak: *u8 = sys_mmap(CC_PATHCAP) 237 ccm_pathjoin(pbak, dir, "elara_persona.txt.bak-precard" as *u8) 238 let pper: *u8 = sys_mmap(CC_PATHCAP) 239 ccm_pathjoin(pper, dir, "elara_persona.txt" as *u8) 240 var banked: i64 = 0 241 let bl: *i64 = sys_mmap(16) as *i64 242 let bb: *u8 = sys_read_file(pbak, bl) 243 if (bb as i64) == 0 { 244 let ol: *i64 = sys_mmap(16) as *i64 245 let ob: *u8 = sys_read_file(pper, ol) 246 if (ob as i64) != 0 { if ol[0] > 0 { 247 let bfd: i64 = sys_openat_wr(pbak, CC_MODE) 248 if bfd >= 0 { sys_write(bfd, ob, ol[0]); sys_close(bfd); banked = 1 } 249 } } 250 } 251 252 // atomic: tmp + rename 253 let ptmp: *u8 = sys_mmap(CC_PATHCAP) 254 ccm_pathjoin(ptmp, dir, "elara_persona.txt.nxcc" as *u8) 255 let fd: i64 = sys_openat_wr(ptmp, CC_MODE) 256 if fd < 0 { ccm_puts("CARD-COMPILE FAIL: cannot write tmp\n" as *u8); sys_exit(4); return 4 } 257 sys_write(fd, per, o) 258 sys_close(fd) 259 if sys_renameat(ptmp, pper) < 0 { ccm_puts("CARD-COMPILE FAIL: rename\n" as *u8); sys_exit(4); return 4 } 260 261 let msg: *u8 = sys_mmap(CC_MAGIC_1024) 262 var m: i64 = ccm_cat(msg, 0, "CARD-COMPILE OK name=" as *u8) 263 m = ccm_cat(msg, m, name) 264 m = ccm_cat(msg, m, " age=" as *u8) 265 m = ccm_catn(msg, m, age) 266 m = ccm_cat(msg, m, " persona_bytes=" as *u8) 267 m = ccm_catn(msg, m, o) 268 m = ccm_cat(msg, m, " bak_precard=" as *u8) 269 m = ccm_catn(msg, m, banked) 270 msg[m] = 10 as u8 271 m = m + 1 272 sys_write(1, msg, m) 273 sys_exit(0) 274 return 0 275}