nx_claude_bridge.nx source
↩ module page · 163 lines · 7935 B
1// nx_claude_bridge.nx -- the CLAUDE <-> NISHI bridge (the "works with you" gap): a sovereign command
2// protocol. Claude writes commands (tool + args) to knowledge/bridge/cmd.txt; this organ reads them,
3// runs the REAL sovereign tool for each (echo / cat / ls -- inline coreutils), and writes the results
4// to knowledge/bridge/result.txt (and stdout). Claude reads the result = the loop where the operator
5// AND Claude drive the Nishi system together. More tools wire in as more dispatch arms.
6// No persistent-hardware writes (Rule 26). expect_exit: 0 license_tier: ORIGINAL
7import "nx_syscalls.nx"
8const K_MAGIC_65536: i64 = 65536
9const K_MAGIC_1000000: i64 = 1000000
10const K_MAGIC_1048576: i64 = 1048576
11const K_MAGIC_1024: i64 = 1024
12
13func cb_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
14func cb_streq(a: *u8, b: *u8) -> i64 { var i: i64=0; while 1==1 { if a[i]!=b[i] { return 0 } if a[i]==(0 as u8) { return 1 } i=i+1 } return 1 }
15func cb_app(out: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ out[off+i]=s[i]; i=i+1 } return off+i }
16func cb_appn(out: *u8, off: i64, src: *u8, n: i64) -> i64 { var i: i64=0; while i<n { out[off+i]=src[i]; i=i+1 } return off+i }
17
18func cb_cat(path: *u8, out: *u8, o: i64) -> i64 {
19 let lenp: *i64 = sys_mmap(8) as *i64
20 let p: *u8 = sys_read_file(path, lenp)
21 var w: i64 = cb_app(out, o, "[cat " as *u8); w = cb_app(out, w, path); w = cb_app(out, w, "]\n" as *u8)
22 if (p as i64)==0 { return cb_app(out, w, "(not found)\n" as *u8) }
23 w = cb_appn(out, w, p, lenp[0])
24 return cb_app(out, w, "\n" as *u8)
25}
26func cb_ls(path: *u8, out: *u8, o: i64) -> i64 {
27 let fd: i64 = sys_openat_rd(path)
28 var w: i64 = cb_app(out, o, "[ls " as *u8); w = cb_app(out, w, path); w = cb_app(out, w, "] " as *u8)
29 if fd<0 { return cb_app(out, w, "(no dir)\n" as *u8) }
30 let db: *u8 = sys_mmap(K_MAGIC_65536)
31 let nb: i64 = sys_getdents64(fd, db, K_MAGIC_65536)
32 sys_close(fd)
33 var off: i64=0
34 while off<nb {
35 let reclen: i64 = (db[off+16] as i64)+((db[off+17] as i64)*256)
36 if reclen<=0 { off=nb } else {
37 var j: i64=off+19
38 while db[j]!=(0 as u8){ out[w]=db[j]; w=w+1; j=j+1 }
39 out[w]=0x20 as u8; w=w+1
40 off=off+reclen
41 }
42 }
43 return cb_app(out, w, "\n" as *u8)
44}
45func cb_sleep_ms(ms: i64) -> i64 {
46 let ts: *i64 = sys_mmap(16) as *i64
47 ts[0] = ms / 1000
48 ts[1] = (ms % 1000) * K_MAGIC_1000000
49 return __syscall(SYS_CLOCK_NANOSLEEP, 0, 0, ts, 0, 0, 0)
50}
51// run ANY sovereign organ from a jobfile (line1 = elf path, lines2.. = one arg each VERBATIM -- no shell,
52// no quoting). Forks/execs directly with a 60s watchdog (kill -9), captures stdout+stderr, folds it into the
53// result. This is what lifts the bridge from 3 inline coreutils to the WHOLE organ set = "Claude in a Nishi CLI".
54func cb_run(jobfile: *u8, out: *u8, o: i64) -> i64 {
55 var w: i64 = cb_app(out, o, "[run " as *u8); w = cb_app(out, w, jobfile); w = cb_app(out, w, "]\n" as *u8)
56 let lenp: *i64 = sys_mmap(8) as *i64; lenp[0] = 0
57 let raw: *u8 = sys_read_file(jobfile, lenp)
58 if (raw as i64) == 0 { return cb_app(out, w, "(jobfile not found)\n" as *u8) }
59 let n: i64 = lenp[0]
60 let buf: *u8 = sys_mmap(n + 8)
61 var ci: i64 = 0; while ci < n { buf[ci] = raw[ci]; ci = ci + 1 } buf[n] = 10 as u8
62 let cargv: *i64 = sys_mmap(8 * 128) as *i64
63 var ac: i64 = 0; var i: i64 = 0; var start: i64 = 0
64 while i <= n {
65 if (buf[i] as i64) == 10 {
66 var end: i64 = i
67 if end > start { if (buf[end - 1] as i64) == 13 { end = end - 1 } }
68 if end > start { buf[end] = 0 as u8; if ac < 127 { cargv[ac] = ((buf as i64) + start) as i64; ac = ac + 1 } }
69 start = i + 1
70 }
71 i = i + 1
72 }
73 cargv[ac] = 0
74 if ac == 0 { return cb_app(out, w, "(empty jobfile)\n" as *u8) }
75 let tmp: *u8 = "/tmp/nxbridge_run.out\x00" as *u8
76 let out_fd: i64 = sys_openat_wr(tmp, 0x180)
77 if out_fd < 0 { return cb_app(out, w, "(cannot open capture file)\n" as *u8) }
78 let pid: i64 = sys_fork()
79 if pid == 0 {
80 sys_dup3(out_fd, 1, 0)
81 sys_dup3(out_fd, 2, 0)
82 let envp: *i64 = sys_mmap(16) as *i64
83 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
84 sys_execve(cargv[0] as *u8, cargv, envp)
85 sys_exit(127)
86 }
87 let st: *i64 = sys_mmap(16) as *i64
88 var ticks: i64 = 0; var rc: i64 = 124; var waiting: i64 = 1
89 while waiting == 1 {
90 let wr: i64 = sys_wait4(pid, st, 1)
91 if wr == pid {
92 waiting = 0
93 if (st[0] % 128) != 0 { rc = 128 + (st[0] % 128) } else { rc = (st[0] >> 8) & 0xff }
94 } else {
95 ticks = ticks + 1
96 if ticks >= 300 { waiting = 0; nx_kill(pid, 9); sys_wait4(pid, st, 0); rc = 124 }
97 else { cb_sleep_ms(200) }
98 }
99 }
100 sys_close(out_fd)
101 let cp: *i64 = sys_mmap(8) as *i64; cp[0] = 0
102 let cap: *u8 = sys_read_file(tmp, cp)
103 if (cap as i64) != 0 { w = cb_appn(out, w, cap, cp[0]) }
104 w = cb_app(out, w, "[exit=" as *u8)
105 let nb: *u8 = sys_mmap(16); var m: i64 = rc; var k: i64 = 0
106 if m == 0 { nb[0] = 48 as u8; k = 1 }
107 while m > 0 { nb[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
108 var z: i64 = 0; while z < k { out[w] = nb[k - 1 - z]; w = w + 1; z = z + 1 }
109 return cb_app(out, w, "]\n" as *u8)
110}
111func cb_dispatch(tool: *u8, arg: *u8, out: *u8, o: i64) -> i64 {
112 if cb_streq(tool, "run\x00" as *u8) == 1 { return cb_run(arg, out, o) }
113 if cb_streq(tool, "echo\x00" as *u8)==1 { var w: i64=cb_app(out,o,"[echo] " as *u8); w=cb_app(out,w,arg); return cb_app(out,w,"\n" as *u8) }
114 if cb_streq(tool, "cat\x00" as *u8)==1 { return cb_cat(arg, out, o) }
115 if cb_streq(tool, "ls\x00" as *u8)==1 { return cb_ls(arg, out, o) }
116 var w: i64 = cb_app(out, o, "[?] unknown tool: " as *u8); w = cb_app(out, w, tool); return cb_app(out, w, "\n" as *u8)
117}
118
119func main() -> i64 {
120 let lenp: *i64 = sys_mmap(8) as *i64
121 let cmd: *u8 = sys_read_file("knowledge/bridge/cmd.txt\x00" as *u8, lenp)
122 if (cmd as i64)==0 { cb_puts("BRIDGE RED: knowledge/bridge/cmd.txt not found\n" as *u8); sys_exit(1); return 1 }
123 let n: i64 = lenp[0]
124
125 let out: *u8 = sys_mmap(K_MAGIC_1048576)
126 var o: i64 = cb_app(out, 0, "=== NISHI <-> CLAUDE BRIDGE :: results ===\n" as *u8)
127 var ncmd: i64 = 0
128
129 var i: i64=0
130 while i<n {
131 let ls: i64=i
132 var le: i64=i
133 var f: i64=1
134 while f==1 { if le>=n { f=0 } else { if cmd[le]==(0x0A as u8) { f=0 } else { le=le+1 } } }
135 var lineend: i64=le
136 if lineend>ls { if cmd[lineend-1]==(0x0D as u8) { lineend=lineend-1 } }
137 if lineend>ls { if cmd[ls]!=(0x23 as u8) {
138 var sp: i64=ls
139 var gs: i64=1
140 while gs==1 { if sp>=lineend { gs=0 } else { if cmd[sp]==(0x20 as u8) { gs=0 } else { sp=sp+1 } } }
141 let tb: *u8 = sys_mmap(64)
142 let ab: *u8 = sys_mmap(K_MAGIC_1024)
143 var ti: i64=0
144 while (ls+ti)<sp { tb[ti]=cmd[ls+ti]; ti=ti+1 }
145 tb[ti]=0 as u8
146 var ai: i64=0
147 if sp<lineend { var k: i64=sp+1; while k<lineend { ab[ai]=cmd[k]; ai=ai+1; k=k+1 } }
148 ab[ai]=0 as u8
149 o = cb_dispatch(tb, ab, out, o)
150 ncmd=ncmd+1
151 } }
152 i=le+1
153 }
154
155 let fd: i64 = sys_openat_wr("knowledge/bridge/result.txt\x00" as *u8, 0x1a4)
156 if fd>0 { sys_write(fd, out, o); sys_close(fd) }
157 sys_write(1, out, o)
158 cb_puts("BRIDGE OK ncmds=" as *u8)
159 let nb: *u8=sys_mmap(16); var m: i64=ncmd; var k: i64=0; if m==0{nb[0]=48 as u8;k=1} while m>0{nb[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var z: i64=0; let rb: *u8=sys_mmap(16); while z<k{rb[z]=nb[k-1-z];z=z+1} sys_write(1,rb,k)
160 cb_puts(" -> knowledge/bridge/result.txt\n" as *u8)
161 sys_exit(0)
162 return 0
163}