diff --git a/README.md b/README.md index 67630db..5799bc2 100644 --- a/README.md +++ b/README.md @@ -41,21 +41,20 @@ apt install clang llvm ## Install the Claude Code skill -The skill teaches Claude how to emit LLVM IR, use the module system, and build native binaries. It lives in `.claude/skills/smlt/SKILL.md` inside the core repo. +The skill teaches Claude how to emit LLVM IR, use the module system, and build native binaries. **For projects inside the core repo** — it works automatically. Claude picks it up from the project directory. -**For any other project** — copy the skill into your project's `.claude/skills/` directory: +**For any other project** — run from your project directory: ```bash -mkdir -p /path/to/your/project/.claude/skills/smlt -cp "$SMLT_HOME/.claude/skills/smlt/SKILL.md" /path/to/your/project/.claude/skills/smlt/ +smlt install-skill ``` -Then point it at the toolchain by adding to your project's `CLAUDE.md`: +This downloads the latest skill into `.claude/skills/smlt/`. For Codex or other agents that use `.agents/`: -``` -The smlt toolchain is at $SMLT_HOME (or the absolute path). +```bash +smlt install-skill --agents ``` ## Usage @@ -67,6 +66,7 @@ smlt cross app.ll myapp --auto # cross-compile for all platforms smlt install app.ll # build and install to $SMLT_HOME/bin/ smlt run app.ll -- args # build to temp, execute, clean up smlt fetch # fetch module from registry +smlt install-skill # install Claude Code skill smlt doctor # check build environment ``` diff --git a/apps/smlt/smlt.ll b/apps/smlt/smlt.ll index 4d61f88..ddd12fd 100644 --- a/apps/smlt/smlt.ll +++ b/apps/smlt/smlt.ll @@ -6,6 +6,7 @@ ; smlt run [opts] [-- args] Build to temp and execute ; smlt doctor Show build environment ; smlt fetch Fetch module from git (core or URL path) +; smlt install-skill [--agents] Install Claude Code skill file ; smlt modules List locally installed modules ; smlt info Show module info (local first, then registry) ; smlt search GET /v1/search/ @@ -156,8 +157,21 @@ declare i32 @proc_exec_capture(ptr, ptr, i64, ptr) @_s_cross = private constant [5 x i8] c"cross" @_s_doctor = private constant [6 x i8] c"doctor" @_s_install = private constant [7 x i8] c"install" +@_s_install_skill = private constant [13 x i8] c"install-skill" @_s_run_cmd = private constant [3 x i8] c"run" +; install-skill constants +; "curl -fsSL https://github.com/smltdev/smlt/releases/latest/download/smlt.skill | tar xz -C " = 90 bytes +; c(1) u(2) r(3) l(4) (5) -(6) f(7) s(8) s(9) L(10) (11) h(12) t(13) t(14) p(15) s(16) :(17) /(18) /(19) g(20) i(21) t(22) h(23) u(24) b(25) .(26) c(27) o(28) m(29) /(30) s(31) m(32) l(33) t(34) d(35) e(36) v(37) /(38) s(39) m(40) l(41) t(42) /(43) r(44) e(45) l(46) e(47) a(48) s(49) e(50) s(51) /(52) l(53) a(54) t(55) e(56) s(57) t(58) /(59) d(60) o(61) w(62) n(63) l(64) o(65) a(66) d(67) /(68) s(69) m(70) l(71) t(72) .(73) s(74) k(75) i(76) l(77) l(78) (79) |(80) (81) t(82) a(83) r(84) (85) x(86) z(87) (88) -(89) C(90) (91) = 91 +@_s_skill_curl_prefix = private constant [91 x i8] c"curl -fsSL https://github.com/smltdev/smlt/releases/latest/download/smlt.skill | tar xz -C " +@_s_skill_dir_claude = private constant [20 x i8] c".claude/skills/smlt/" +@_s_skill_dir_agents = private constant [20 x i8] c".agents/skills/smlt/" +@_s_agents_flag = private constant [8 x i8] c"--agents" +@_s_skill_installed = private constant [22 x i8] c"Skill installed to: \00\00" +@_s_skill_err = private constant [28 x i8] c"Error: install-skill failed\0A" +@_s_sh_path = private constant [8 x i8] c"/bin/sh\00" +@_s_sh_c_flag = private constant [3 x i8] c"-c\00" + ; Platform names (without null) @_s_plat_darwin_arm64 = private constant [12 x i8] c"darwin-arm64" @_s_plat_darwin_x86_64 = private constant [13 x i8] c"darwin-x86_64" @@ -292,6 +306,8 @@ declare i32 @proc_exec_capture(ptr, ptr, i64, ptr) @_s_h_env = private constant [11 x i8] c"Environment" @_s_h_cinstall = private constant [25 x i8] c"install [opts] " @_s_h_crun = private constant [27 x i8] c"run [opts] [-- ..]" +@_s_h_cis = private constant [24 x i8] c"install-skill [--agents]" +@_s_h_dis = private constant [31 x i8] c"Install Claude Code skill file " @_s_h_cm = private constant [7 x i8] c"modules" @_s_h_dm = private constant [30 x i8] c"List locally installed modules" @_s_h_ci = private constant [13 x i8] c"info " @@ -3049,7 +3065,11 @@ check_run: check_fetch: %is_fetch = call i1 @str_eq(ptr %cmd, i64 %cmdlen, ptr @_s_fetch, i64 5) - br i1 %is_fetch, label %do_fetch_cmd, label %check_modules + br i1 %is_fetch, label %do_fetch_cmd, label %check_install_skill + +check_install_skill: + %is_install_skill = call i1 @str_eq(ptr %cmd, i64 %cmdlen, ptr @_s_install_skill, i64 13) + br i1 %is_install_skill, label %do_install_skill, label %check_modules check_modules: %is_modules = call i1 @str_eq(ptr %cmd, i64 %cmdlen, ptr @_s_modules_cmd, i64 7) @@ -3131,6 +3151,68 @@ err_home: call i64 @write(i32 2, ptr @_s_newline, i64 1) ret i32 1 + ; === install-skill === +do_install_skill: + ; Check for --agents flag + %is_has_agents = call i1 @cli_has_flag(i32 %argc, ptr %argv, ptr @_s_agents_flag, i64 8) + ; Select target dir: .agents/skills/smlt/ or .claude/skills/smlt/ + %is_dir_ptr = select i1 %is_has_agents, ptr @_s_skill_dir_agents, ptr @_s_skill_dir_claude + %is_dir_len = select i1 %is_has_agents, i64 20, i64 20 + + ; mkdir -p via argv: ["/usr/bin/env", "mkdir", "-p", dir, null] + %is_mkdir_dir = alloca [64 x i8], align 1 + call ptr @memcpy(ptr %is_mkdir_dir, ptr %is_dir_ptr, i64 %is_dir_len) + %is_mkdir_null = getelementptr i8, ptr %is_mkdir_dir, i64 %is_dir_len + store i8 0, ptr %is_mkdir_null + %is_mkdir_argv = alloca [5 x ptr], align 8 + %is_ma0 = getelementptr ptr, ptr %is_mkdir_argv, i64 0 + store ptr @_s_env_path, ptr %is_ma0 + %is_ma1 = getelementptr ptr, ptr %is_mkdir_argv, i64 1 + store ptr @_s_mkdir_cmd, ptr %is_ma1 + %is_ma2 = getelementptr ptr, ptr %is_mkdir_argv, i64 2 + store ptr @_s_mkdir_p_flag, ptr %is_ma2 + %is_ma3 = getelementptr ptr, ptr %is_mkdir_argv, i64 3 + store ptr %is_mkdir_dir, ptr %is_ma3 + %is_ma4 = getelementptr ptr, ptr %is_mkdir_argv, i64 4 + store ptr null, ptr %is_ma4 + %is_mk_rc = call i32 @proc_exec(ptr %is_mkdir_argv) + + ; Build shell command string: curl ... | tar xz -C + %is_cmd = alloca [512 x i8], align 1 + %is_pos = alloca i64, align 8 + store i64 0, ptr %is_pos + call void @buf_mem(ptr %is_cmd, ptr %is_pos, ptr @_s_skill_curl_prefix, i64 91) + call void @buf_mem(ptr %is_cmd, ptr %is_pos, ptr %is_dir_ptr, i64 %is_dir_len) + ; Null-terminate + %is_clen = load i64, ptr %is_pos + %is_cnull = getelementptr i8, ptr %is_cmd, i64 %is_clen + store i8 0, ptr %is_cnull + + ; Run via sh -c "" since we need pipe + %is_argv = alloca [4 x ptr], align 8 + %is_a0 = getelementptr ptr, ptr %is_argv, i64 0 + store ptr @_s_sh_path, ptr %is_a0 + %is_a1 = getelementptr ptr, ptr %is_argv, i64 1 + store ptr @_s_sh_c_flag, ptr %is_a1 + %is_a2 = getelementptr ptr, ptr %is_argv, i64 2 + store ptr %is_cmd, ptr %is_a2 + %is_a3 = getelementptr ptr, ptr %is_argv, i64 3 + store ptr null, ptr %is_a3 + + %is_rc = call i32 @proc_exec(ptr %is_argv) + %is_ok = icmp eq i32 %is_rc, 0 + br i1 %is_ok, label %is_success, label %is_fail + +is_success: + call i64 @write(i32 1, ptr @_s_skill_installed, i64 20) + call i64 @write(i32 1, ptr %is_dir_ptr, i64 %is_dir_len) + call i64 @write(i32 1, ptr @_s_newline, i64 1) + ret i32 0 + +is_fail: + call i64 @write(i32 2, ptr @_s_skill_err, i64 28) + ret i32 1 + ; === modules (list locally installed modules) === do_modules_cmd: %mod_home_ok = icmp sge i64 %home_len_val, 0 @@ -3631,7 +3713,7 @@ verify_fail: ; === Help === show_help: - %hbuf = alloca [4096 x i8], align 8 + %hbuf = alloca [8192 x i8], align 8 %hpos = alloca i64, align 8 store i64 0, ptr %hpos call void @cli_help_line(ptr %hbuf, ptr %hpos, ptr @_s_h_title, i64 40) @@ -3646,6 +3728,7 @@ show_help: call void @cli_help_row(ptr %hbuf, ptr %hpos, ptr @_s_h_cd, i64 6, ptr @_s_h_dd, i64 22, i64 32) call void @cli_help_row(ptr %hbuf, ptr %hpos, ptr @_s_h_cf, i64 14, ptr @_s_h_df, i64 23, i64 32) call void @cli_help_row(ptr %hbuf, ptr %hpos, ptr @_s_h_ci, i64 13, ptr @_s_h_di, i64 23, i64 32) + call void @cli_help_row(ptr %hbuf, ptr %hpos, ptr @_s_h_cis, i64 24, ptr @_s_h_dis, i64 31, i64 32) call void @cli_help_row(ptr %hbuf, ptr %hpos, ptr @_s_h_cm, i64 7, ptr @_s_h_dm, i64 30, i64 32) call void @cli_help_row(ptr %hbuf, ptr %hpos, ptr @_s_h_cs, i64 14, ptr @_s_h_ds, i64 18, i64 32) call void @cli_help_row(ptr %hbuf, ptr %hpos, ptr @_s_h_cp, i64 13, ptr @_s_h_dp, i64 26, i64 32)