shine-code-submit 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/install.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- var D=require("node:fs"),Y1=require("node:path"),Z1=require("node:child_process");var m=require("node:fs"),S=require("node:os"),I=require("node:path"),j=require("node:child_process"),H1=[1,1,0],W1=300000;function y(){let b=j.spawnSync("bun",["--version"],{shell:process.platform==="win32",encoding:"utf8"});if(b.status===0&&(b.stdout??"").trim())return"bun";let q=S.homedir(),z=process.platform==="win32"?[I.join(q,".bun","bin","bun.exe")]:[I.join(q,".bun","bin","bun"),"/usr/local/bin/bun","/opt/homebrew/bin/bun"];for(let Q of z)if(m.existsSync(Q))return Q;return null}function J1(b){return b.trim().split(".").map((q)=>parseInt(q,10)||0)}function F1(b,q){let z=J1(b);for(let Q=0;Q<q.length;Q++){let X=z[Q]??0,J=q[Q]??0;if(X>J)return!0;if(X<J)return!1}return!0}function K1(){let b=process.env.npm_config_registry??"";return/npmmirror|taobao/i.test(b)}function M(b){return j.spawnSync(b,{shell:!0,encoding:"utf8",timeout:W1,stdio:"inherit"}).status??1}async function p(){let b=y();if(b){let z=j.spawnSync(b,["--version"],{shell:process.platform==="win32",encoding:"utf8"}).stdout?.trim()??"";if(z&&F1(z,H1))return console.log(`[shine-code-submit] bun ${z} detected`),b}if(console.log("[shine-code-submit] bun 未找到或版本过低,开始自动安装..."),K1()){if(console.log("[shine-code-submit] 检测到国内 npm 镜像,先尝试 npm install -g bun"),M("npm install -g bun")===0){let z=y();if(z)return console.log("[shine-code-submit] ✓ bun 安装成功(via npm 镜像)"),z}console.log("[shine-code-submit] npm 镜像方式失败,回退官方脚本")}if(process.platform==="win32")M('powershell -c "irm bun.sh/install.ps1 | iex"');else M("curl -fsSL https://bun.sh/install | bash");let q=y();if(!q)throw console.error("[shine-code-submit] bun 自动安装失败。请手动安装后重试:"),console.error(" Windows: winget install Oven-sh.Bun 或 npm install -g bun"),console.error(" macOS: brew install oven-sh/bun/bun"),console.error(" Linux: curl -fsSL https://bun.sh/install | bash"),Error("bun installation failed");return console.log("[shine-code-submit] ✓ bun 安装成功"),q}var $=require("node:fs"),Z=require("node:path"),L=require("node:child_process");var E=require("node:os"),V=require("node:path");function A(){return process.env.CLAUDE_CONFIG_DIR||V.join(E.homedir(),".claude")}function U(){return V.join(A(),"plugins")}function v(){return V.join(U(),"known_marketplaces.json")}function O(){return V.join(U(),"installed_plugins.json")}function B(){return V.join(A(),"settings.json")}var P={name:"shine-code-submit",version:"0.2.1",private:!1,type:"module",description:"Claude Code Hook -> 本地常驻 Daemon 的状态/持久化底座",author:"renguifeng",license:"MIT",repository:{type:"git",url:"http://8.130.168.121:9001/AI/shine-code-submit.git"},homepage:"http://8.130.168.121:9001/AI/shine-code-submit",bugs:{url:"http://8.130.168.121:9001/AI/shine-code-submit/issues"},keywords:["claude","claude-code","plugin","hooks","daemon","dashboard"],bin:{"shine-code-submit":"dist/install.cjs"},files:["dist/install.cjs",".claude-plugin","hooks/hooks.json","bin/launcher.cjs","src","ui","package.json","bun.lock","README.md"],engines:{node:">=18"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},scripts:{daemon:"bun run src/daemon/main.ts",hook:"bun run src/hook/main.ts",cli:"bun run src/cli/main.ts",build:"bun run scripts/build.ts","build:all":"bun run scripts/build.ts --all","build:install":"bun run scripts/build-install.ts","build:dist":"bun run scripts/build.ts && bun run scripts/build-install.ts",prepublishOnly:"bun run build:dist",typecheck:"tsc --noEmit"},devDependencies:{"@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.2.3",typescript:"^6.0.3"},dependencies:{marked:"^18.0.5",react:"^19.2.7","react-dom":"^19.2.7"}};var h=require("node:os"),c="shine-code-submit",W=P.version,_1=process.env.SHINE_CODE_SUBMIT_HOST??"0.0.0.0",U1="127.0.0.1",l=36666,N=`http://${U1}:${l}`;function C1(){let b=["vethernet","vmware","virtualbox","docker","veth","br-","virbr","vnet","utun"],q=(z)=>{let Q=z.toLowerCase();return b.some((X)=>Q.includes(X))};try{let z=h.networkInterfaces();for(let Q of Object.keys(z)){if(q(Q))continue;for(let X of z[Q]??[])if(X.family==="IPv4"&&!X.internal)return X.address}for(let Q of Object.keys(z))for(let X of z[Q]??[])if(X.family==="IPv4"&&!X.internal)return X.address}catch{}return"localhost"}var u=`http://${C1()}:${l}`;var G="shine-code-submit",R="shine-code-submit";function g(b=W){return Z.join(U(),"cache",G,R,b)}function x1(){let b=process.argv[1],q=b?Z.dirname(Z.resolve(b)):process.cwd(),z=q;for(let Q=0;Q<10;Q++){if($.existsSync(Z.join(z,"package.json"))&&$.existsSync(Z.join(z,".claude-plugin")))return z;let X=Z.dirname(z);if(X===z)break;z=X}return Z.dirname(q)}var j1=[".claude-plugin","hooks","bin","src","ui","package.json","bun.lock","README.md"];function d(b){let q=g();if($.existsSync(q))$.rmSync(q,{recursive:!0,force:!0});$.mkdirSync(q,{recursive:!0});let z=x1();console.log(`[shine-code-submit] 部署源:${z}`);for(let X of j1){let J=Z.join(z,X);if(!$.existsSync(J))continue;$.cpSync(J,Z.join(q,X),{recursive:!0})}console.log("[shine-code-submit] 安装运行时依赖(bun install)...");let Q=L.spawnSync(b,["install","--frozen-lockfile"],{cwd:q,shell:process.platform==="win32",encoding:"utf8",stdio:"inherit"}).status;if(Q!==0){if(console.log("[shine-code-submit] --frozen-lockfile 失败,重试普通 bun install"),Q=L.spawnSync(b,["install"],{cwd:q,shell:process.platform==="win32",encoding:"utf8",stdio:"inherit"}).status,Q!==0)throw Error(`bun install 失败(exit ${Q})。请手动在 ${q} 跑 bun install`)}return $.writeFileSync(Z.join(q,".install-version"),JSON.stringify({version:W,installedAt:Date.now()}),"utf8"),console.log(`[shine-code-submit] 已部署到 ${q}`),q}var k=require("node:path");var Y=require("node:fs"),o=require("node:path");function F(b,q){if(!Y.existsSync(b))return q;let z;try{z=Y.readFileSync(b,"utf8")}catch{return q}try{return JSON.parse(z)}catch{let Q=`${b}.bak-corrupt-${Date.now()}`;try{Y.copyFileSync(b,Q),console.error(`[shine-code-submit] WARNING: ${b} JSON 损坏,已备份到 ${Q},用默认值继续`)}catch{}return q}}function K(b,q){let z=`${b}.bak-pre-install`;if(Y.existsSync(b)&&!Y.existsSync(z))try{Y.copyFileSync(b,z)}catch{}Y.mkdirSync(o.dirname(b),{recursive:!0});let Q=`${b}.tmp-${process.pid}`;Y.writeFileSync(Q,JSON.stringify(q,null,2),"utf8"),Y.renameSync(Q,b)}function _(){return`${R}@${G}`}function s(b){let q=v(),z=F(q,{}),Q=k.join(b,".claude-plugin"),X=z[G];if(X?.source&&X.source.source!=="directory")console.log(`[shine-code-submit] WARNING: marketplace "${G}" 已存在(source=${X.source.source}),将覆盖为 directory 源(原文件已备份)`);z[G]={source:{source:"directory",path:Q},installLocation:k.join(U(),"marketplaces",G),lastUpdated:new Date().toISOString(),autoUpdate:!1},K(q,z),console.log(`[shine-code-submit] marketplace 已注册 → ${q}`)}function r(b){let q=O(),z=F(q,{version:2,plugins:{}});if(!z.version)z.version=2;if(!z.plugins)z.plugins={};let Q=_(),X=new Date().toISOString(),J=z.plugins[Q]?.[0];z.plugins[Q]=[{scope:"user",installPath:b,version:W,installedAt:J?.installedAt??X,lastUpdated:X}],K(q,z),console.log(`[shine-code-submit] plugin 已注册 → ${q}`)}function t(b){let q=B(),z=F(q,{});if(!z.enabledPlugins)z.enabledPlugins={};let Q=_();if(z.enabledPlugins[Q]=!0,!z.extraKnownMarketplaces)z.extraKnownMarketplaces={};if(!z.extraKnownMarketplaces[G])z.extraKnownMarketplaces[G]={source:{source:"directory",path:k.join(b,".claude-plugin")}};K(q,z),console.log(`[shine-code-submit] 已启用(enabledPlugins)→ ${q}`)}function i(){let b=_(),q=F(v(),{});if(q[G])delete q[G],K(v(),q);let z=F(O(),{plugins:{}});if(z.plugins&&z.plugins[b])delete z.plugins[b],K(O(),z);let Q=F(B(),{}),X=!1;if(Q.enabledPlugins&&Q.enabledPlugins[b])delete Q.enabledPlugins[b],X=!0;if(Q.extraKnownMarketplaces&&Q.extraKnownMarketplaces[G])delete Q.extraKnownMarketplaces[G],X=!0;if(X)K(B(),Q);console.log("[shine-code-submit] 已从三处 JSON 移除注册")}var n=require("node:child_process"),f=require("node:fs");async function C(b=400){try{let q=await fetch(`${N}/api/health`,{signal:AbortSignal.timeout(b)});if(!q.ok)return!1;return(await q.json())?.service===c}catch{return!1}}function a(b){let q=process.platform,z,Q;if(q==="win32")z="cmd",Q=["/c","start","",b];else if(q==="darwin")z="open",Q=[b];else if(v1())z="cmd.exe",Q=["/c","start","",b];else z="xdg-open",Q=[b];try{n.spawn(z,Q,{detached:!0,stdio:"ignore"}).unref()}catch{}}function v1(){if(process.platform!=="linux")return!1;try{return f.readFileSync("/proc/version","utf8").toLowerCase().includes("microsoft")}catch{return!1}}var H=require("node:path"),e=require("node:fs"),b1=require("node:os"),O1=process.env.LOCALAPPDATA??H.join(b1.homedir(),".local","share"),x=H.join(O1,"shine-code-submit"),B1=H.join(x,"spool"),q1=H.join(x,"log"),z1=H.join(x,"db"),Q1=H.join(x,"daemon.pid"),t1=H.join(q1,"daemon.log"),i1=H.join(z1,"events.sqlite");function X1(){for(let b of[x,B1,q1,z1])e.mkdirSync(b,{recursive:!0})}var w=require("node:fs");function T(){try{let b=w.readFileSync(Q1,"utf8");return JSON.parse(b)}catch{return null}}var[,,$1]=process.argv;N1().catch((b)=>{console.error(`[shine-code-submit] ${b instanceof Error?b.message:String(b)}`),process.exit(1)});async function N1(){switch($1){case void 0:case"install":await u1();break;case"uninstall":await k1();break;case"status":await w1();break;case"--version":case"-v":console.log(W);break;default:M1()}}async function u1(){console.log(`=== shine-code-submit installer v${W} ===`);let b=await p(),q=d(b);s(q),r(q),t(q),X1(),await T1(b,q),y1(),console.log(""),console.log("✓ 安装完成。"),console.log(" · 重启 Claude Code 后,/plugin 列表会显示 shine-code-submit(已启用)。"),console.log(" · 开新会话即触发 SessionStart hook,事件出现在 dashboard。")}async function k1(){console.log("=== shine-code-submit uninstaller ==="),await D1(),i();let b=g();if(D.existsSync(b))D.rmSync(b,{recursive:!0,force:!0}),console.log(`[shine-code-submit] 已删除 ${b}`);console.log("✓ 已卸载。重启 Claude Code 后 /plugin 不再显示。")}async function w1(){let b=await C(),q=T();if(b&&q)console.log(`daemon: running pid=${q.pid} ${u}`);else console.log("daemon: not running")}async function T1(b,q){if(await C()){console.log("[shine-code-submit] daemon 已在运行,跳过启动");return}let z=Y1.join(q,"src","daemon","main.ts");console.log("[shine-code-submit] 启动 daemon...");try{Z1.spawn(b,["run",z],{detached:!0,stdio:"ignore",windowsHide:!0,cwd:q,shell:process.platform==="win32"}).unref()}catch(X){console.error(`[shine-code-submit] 启动 daemon 失败:${X instanceof Error?X.message:X}`),console.error(" plugin 已注册,Claude Code 重启后 hook 会自动拉起 daemon");return}let Q=Date.now()+1e4;while(Date.now()<Q)if(await G1(200),await C()){console.log("[shine-code-submit] daemon 已就绪");return}console.error("[shine-code-submit] daemon 启动超时(10s)。plugin 已注册,可稍后手动 `shine-code-submit start` 或重启 claude。")}async function D1(){let b=T();if(!b){console.log("[shine-code-submit] daemon 未运行(无 pid 文件)");return}if(await C()){try{await fetch(`${N}/api/shutdown`,{method:"POST",headers:{authorization:`Bearer ${b.token}`}})}catch{}if(await G1(1000),await C())try{process.kill(b.pid)}catch{}}console.log("[shine-code-submit] daemon 已停止")}function y1(){let b=T(),q=b?`${u}/ui?t=${b.token}`:`${u}/ui`;console.log(`[shine-code-submit] Dashboard: ${q}`);try{a(q)}catch{}}function G1(b){return new Promise((q)=>setTimeout(q,b))}function M1(){console.log(`shine-code-submit <command>
2
+ var w=require("node:fs"),X1=require("node:path"),Y1=require("node:child_process");var f=require("node:fs"),m=require("node:os"),y=require("node:path"),j=require("node:child_process"),G1=[1,1,0],H1=300000;function D(){let b=j.spawnSync("bun",["--version"],{shell:process.platform==="win32",encoding:"utf8"});if(b.status===0&&(b.stdout??"").trim())return"bun";let q=m.homedir(),z=process.platform==="win32"?[y.join(q,".bun","bin","bun.exe")]:[y.join(q,".bun","bin","bun"),"/usr/local/bin/bun","/opt/homebrew/bin/bun"];for(let Q of z)if(f.existsSync(Q))return Q;return null}function W1(b){return b.trim().split(".").map((q)=>parseInt(q,10)||0)}function J1(b,q){let z=W1(b);for(let Q=0;Q<q.length;Q++){let X=z[Q]??0,J=q[Q]??0;if(X>J)return!0;if(X<J)return!1}return!0}function K1(){let b=process.env.npm_config_registry??"";return/npmmirror|taobao/i.test(b)}function M(b){return j.spawnSync(b,{shell:!0,encoding:"utf8",timeout:H1,stdio:"inherit"}).status??1}async function E(){let b=D();if(b){let z=j.spawnSync(b,["--version"],{shell:process.platform==="win32",encoding:"utf8"}).stdout?.trim()??"";if(z&&J1(z,G1))return console.log(`[shine-code-submit] bun ${z} detected`),b}if(console.log("[shine-code-submit] bun 未找到或版本过低,开始自动安装..."),K1()){if(console.log("[shine-code-submit] 检测到国内 npm 镜像,先尝试 npm install -g bun"),M("npm install -g bun")===0){let z=D();if(z)return console.log("[shine-code-submit] ✓ bun 安装成功(via npm 镜像)"),z}console.log("[shine-code-submit] npm 镜像方式失败,回退官方脚本")}if(process.platform==="win32")M('powershell -c "irm bun.sh/install.ps1 | iex"');else M("curl -fsSL https://bun.sh/install | bash");let q=D();if(!q)throw console.error("[shine-code-submit] bun 自动安装失败。请手动安装后重试:"),console.error(" Windows: winget install Oven-sh.Bun 或 npm install -g bun"),console.error(" macOS: brew install oven-sh/bun/bun"),console.error(" Linux: curl -fsSL https://bun.sh/install | bash"),Error("bun installation failed");return console.log("[shine-code-submit] ✓ bun 安装成功"),q}var Z=require("node:fs"),Y=require("node:path"),I=require("node:child_process");var S=require("node:os"),V=require("node:path");function p(){return process.env.CLAUDE_CONFIG_DIR||V.join(S.homedir(),".claude")}function x(){return V.join(p(),"plugins")}function O(){return V.join(x(),"known_marketplaces.json")}function v(){return V.join(x(),"installed_plugins.json")}function B(){return V.join(p(),"settings.json")}var A={name:"shine-code-submit",version:"0.2.3",private:!1,type:"module",description:"Claude Code Hook -> 本地常驻 Daemon 的状态/持久化底座",author:"renguifeng",license:"MIT",repository:{type:"git",url:"http://8.130.168.121:9001/AI/shine-code-submit.git"},homepage:"http://8.130.168.121:9001/AI/shine-code-submit",bugs:{url:"http://8.130.168.121:9001/AI/shine-code-submit/issues"},keywords:["claude","claude-code","plugin","hooks","daemon","dashboard"],bin:{"shine-code-submit":"dist/install.cjs"},files:["dist/install.cjs",".claude-plugin","hooks/hooks.json","bin/launcher.cjs","src","ui","package.json","bun.lock","README.md"],engines:{node:">=18"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},scripts:{daemon:"bun run src/daemon/main.ts",hook:"bun run src/hook/main.ts",cli:"bun run src/cli/main.ts",build:"bun run scripts/build.ts","build:all":"bun run scripts/build.ts --all","build:install":"bun run scripts/build-install.ts","build:dist":"bun run scripts/build.ts && bun run scripts/build-install.ts",prepublishOnly:"bun run build:dist",typecheck:"tsc --noEmit"},devDependencies:{"@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.2.3",typescript:"^6.0.3"},dependencies:{marked:"^18.0.5",react:"^19.2.7","react-dom":"^19.2.7"}};var P=require("node:os"),h="shine-code-submit",W=A.version,g1=process.env.SHINE_CODE_SUBMIT_HOST??"0.0.0.0",V1="127.0.0.1",c=36666,N=`http://${V1}:${c}`;function U1(){let b=["vethernet","vmware","virtualbox","docker","veth","br-","virbr","vnet","utun"],q=(z)=>{let Q=z.toLowerCase();return b.some((X)=>Q.includes(X))};try{let z=P.networkInterfaces();for(let Q of Object.keys(z)){if(q(Q))continue;for(let X of z[Q]??[])if(X.family==="IPv4"&&!X.internal)return X.address}for(let Q of Object.keys(z))for(let X of z[Q]??[])if(X.family==="IPv4"&&!X.internal)return X.address}catch{}return"localhost"}var u=`http://${U1()}:${c}`;var G="shine-code-submit",L="shine-code-submit";function R(b=W){return Y.join(x(),"cache",G,L,b)}function C1(){let b=process.argv[1],q=process.cwd();if(b)try{q=Y.dirname(Z.realpathSync(Y.resolve(b)))}catch{q=Y.dirname(Y.resolve(b))}let z=q;for(let Q=0;Q<12;Q++){if(Z.existsSync(Y.join(z,"package.json"))&&Z.existsSync(Y.join(z,".claude-plugin")))return z;let X=Y.dirname(z);if(X===z)break;z=X}return Y.dirname(q)}var j1=[".claude-plugin","hooks","bin","src","ui","package.json","bun.lock","README.md"];function l(b){let q=R();if(Z.existsSync(q))Z.rmSync(q,{recursive:!0,force:!0});Z.mkdirSync(q,{recursive:!0});let z=C1();console.log(`[shine-code-submit] 部署源:${z}`);for(let X of j1){let J=Y.join(z,X);if(!Z.existsSync(J))continue;Z.cpSync(J,Y.join(q,X),{recursive:!0})}console.log("[shine-code-submit] 安装运行时依赖(bun install)...");let Q=I.spawnSync(b,["install","--frozen-lockfile"],{cwd:q,shell:process.platform==="win32",encoding:"utf8",stdio:"inherit"}).status;if(Q!==0){if(console.log("[shine-code-submit] --frozen-lockfile 失败,重试普通 bun install"),Q=I.spawnSync(b,["install"],{cwd:q,shell:process.platform==="win32",encoding:"utf8",stdio:"inherit"}).status,Q!==0)throw Error(`bun install 失败(exit ${Q})。请手动在 ${q} 跑 bun install`)}return Z.writeFileSync(Y.join(q,".install-version"),JSON.stringify({version:W,installedAt:Date.now()}),"utf8"),console.log(`[shine-code-submit] 已部署到 ${q}`),q}var $=require("node:fs"),d=require("node:path");function K(b,q){if(!$.existsSync(b))return q;let z;try{z=$.readFileSync(b,"utf8")}catch{return q}try{return JSON.parse(z)}catch{let Q=`${b}.bak-corrupt-${Date.now()}`;try{$.copyFileSync(b,Q),console.error(`[shine-code-submit] WARNING: ${b} JSON 损坏,已备份到 ${Q},用默认值继续`)}catch{}return q}}function F(b,q){let z=`${b}.bak-pre-install`;if($.existsSync(b)&&!$.existsSync(z))try{$.copyFileSync(b,z)}catch{}$.mkdirSync(d.dirname(b),{recursive:!0});let Q=`${b}.tmp-${process.pid}`;$.writeFileSync(Q,JSON.stringify(q,null,2),"utf8"),$.renameSync(Q,b)}function g(){return`${L}@${G}`}function o(b){let q=O(),z=K(q,{}),Q=z[G];if(Q?.source&&Q.source.source!=="directory")console.log(`[shine-code-submit] WARNING: marketplace "${G}" 已存在(source=${Q.source.source}),将覆盖为 directory 源(原文件已备份)`);z[G]={source:{source:"directory",path:b},installLocation:b,lastUpdated:new Date().toISOString(),autoUpdate:!1},F(q,z),console.log(`[shine-code-submit] marketplace 已注册 → ${q}`)}function s(b){let q=v(),z=K(q,{version:2,plugins:{}});if(!z.version)z.version=2;if(!z.plugins)z.plugins={};let Q=g(),X=new Date().toISOString(),J=z.plugins[Q]?.[0];z.plugins[Q]=[{scope:"user",installPath:b,version:W,installedAt:J?.installedAt??X,lastUpdated:X}],F(q,z),console.log(`[shine-code-submit] plugin 已注册 → ${q}`)}function r(b){let q=B(),z=K(q,{});if(!z.enabledPlugins)z.enabledPlugins={};let Q=g();if(z.enabledPlugins[Q]=!0,!z.extraKnownMarketplaces)z.extraKnownMarketplaces={};if(!z.extraKnownMarketplaces[G])z.extraKnownMarketplaces[G]={source:{source:"directory",path:b}};F(q,z),console.log(`[shine-code-submit] 已启用(enabledPlugins)→ ${q}`)}function i(){let b=g(),q=K(O(),{});if(q[G])delete q[G],F(O(),q);let z=K(v(),{plugins:{}});if(z.plugins&&z.plugins[b])delete z.plugins[b],F(v(),z);let Q=K(B(),{}),X=!1;if(Q.enabledPlugins&&Q.enabledPlugins[b])delete Q.enabledPlugins[b],X=!0;if(Q.extraKnownMarketplaces&&Q.extraKnownMarketplaces[G])delete Q.extraKnownMarketplaces[G],X=!0;if(X)F(B(),Q);console.log("[shine-code-submit] 已从三处 JSON 移除注册")}var t=require("node:child_process"),_=require("node:fs");async function U(b=400){try{let q=await fetch(`${N}/api/health`,{signal:AbortSignal.timeout(b)});if(!q.ok)return!1;return(await q.json())?.service===h}catch{return!1}}function n(b){let q=process.platform,z,Q;if(q==="win32")z="cmd",Q=["/c","start","",b];else if(q==="darwin")z="open",Q=[b];else if(x1())z="cmd.exe",Q=["/c","start","",b];else z="xdg-open",Q=[b];try{t.spawn(z,Q,{detached:!0,stdio:"ignore"}).unref()}catch{}}function x1(){if(process.platform!=="linux")return!1;try{return _.readFileSync("/proc/version","utf8").toLowerCase().includes("microsoft")}catch{return!1}}var H=require("node:path"),a=require("node:fs"),e=require("node:os"),O1=process.env.LOCALAPPDATA??H.join(e.homedir(),".local","share"),C=H.join(O1,"shine-code-submit"),v1=H.join(C,"spool"),b1=H.join(C,"log"),q1=H.join(C,"db"),z1=H.join(C,"daemon.pid"),r1=H.join(b1,"daemon.log"),i1=H.join(q1,"events.sqlite");function Q1(){for(let b of[C,v1,b1,q1])a.mkdirSync(b,{recursive:!0})}var k=require("node:fs");function T(){try{let b=k.readFileSync(z1,"utf8");return JSON.parse(b)}catch{return null}}var[,,Z1]=process.argv;B1().catch((b)=>{console.error(`[shine-code-submit] ${b instanceof Error?b.message:String(b)}`),process.exit(1)});async function B1(){switch(Z1){case void 0:case"install":await N1();break;case"uninstall":await u1();break;case"status":await k1();break;case"--version":case"-v":console.log(W);break;default:M1()}}async function N1(){console.log(`=== shine-code-submit installer v${W} ===`);let b=await E(),q=l(b);o(q),s(q),r(q),Q1(),await T1(b,q),D1(),console.log(""),console.log("✓ 安装完成。"),console.log(" · 重启 Claude Code 后,/plugin 列表会显示 shine-code-submit(已启用)。"),console.log(" · 开新会话即触发 SessionStart hook,事件出现在 dashboard。")}async function u1(){console.log("=== shine-code-submit uninstaller ==="),await w1(),i();let b=R();if(w.existsSync(b))w.rmSync(b,{recursive:!0,force:!0}),console.log(`[shine-code-submit] 已删除 ${b}`);console.log("✓ 已卸载。重启 Claude Code 后 /plugin 不再显示。")}async function k1(){let b=await U(),q=T();if(b&&q)console.log(`daemon: running pid=${q.pid} ${u}`);else console.log("daemon: not running")}async function T1(b,q){if(await U()){console.log("[shine-code-submit] daemon 已在运行,跳过启动");return}let z=X1.join(q,"src","daemon","main.ts");console.log("[shine-code-submit] 启动 daemon...");try{Y1.spawn(b,["run",z],{detached:!0,stdio:"ignore",windowsHide:!0,cwd:q,shell:process.platform==="win32"}).unref()}catch(X){console.error(`[shine-code-submit] 启动 daemon 失败:${X instanceof Error?X.message:X}`),console.error(" plugin 已注册,Claude Code 重启后 hook 会自动拉起 daemon");return}let Q=Date.now()+1e4;while(Date.now()<Q)if(await $1(200),await U()){console.log("[shine-code-submit] daemon 已就绪");return}console.error("[shine-code-submit] daemon 启动超时(10s)。plugin 已注册,可稍后手动 `shine-code-submit start` 或重启 claude。")}async function w1(){let b=T();if(!b){console.log("[shine-code-submit] daemon 未运行(无 pid 文件)");return}if(await U()){try{await fetch(`${N}/api/shutdown`,{method:"POST",headers:{authorization:`Bearer ${b.token}`}})}catch{}if(await $1(1000),await U())try{process.kill(b.pid)}catch{}}console.log("[shine-code-submit] daemon 已停止")}function D1(){let b=T(),q=b?`${u}/ui?t=${b.token}`:`${u}/ui`;console.log(`[shine-code-submit] Dashboard: ${q}`);try{n(q)}catch{}}function $1(b){return new Promise((q)=>setTimeout(q,b))}function M1(){console.log(`shine-code-submit <command>
3
3
 
4
4
  install 安装插件(自动装 bun + 部署 + 注册 + 启 daemon + 开 dashboard)
5
5
  uninstall 卸载(停 daemon + 反注册 + 删文件)
6
6
  status 显示 daemon 状态
7
7
 
8
- 通常通过 npx 跑:npx shine-code-submit install`),process.exit($1?1:0)}
8
+ 通常通过 npx 跑:npx shine-code-submit install`),process.exit(Z1?1:0)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shine-code-submit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Claude Code Hook -> 本地常驻 Daemon 的状态/持久化底座",
@@ -1,5 +1,5 @@
1
1
  // 部署 plugin 文件到 claude cache 目录,并跑 bun install 装运行时依赖(marked/react)。
2
- import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import { cpSync, existsSync, mkdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { pluginsRoot } from "./paths";
@@ -15,13 +15,24 @@ export function cacheDir(version: string = SERVICE_VERSION): string {
15
15
 
16
16
  /** 找 npm 包根:运行入口(dist/install.cjs)所在目录上溯到含 package.json + .claude-plugin 的目录。
17
17
  * 不能用 import.meta.url —— Bun 打 cjs 单文件 bundle 时会把它静态固化为构建机的源码绝对路径,
18
- * 换台机器就指向不存在的目录,部署白名单全拷不到、bun install 必失败。
19
- * 改用 process.argv[1](node 入口脚本运行时绝对路径),跨机器 / npx / npm-g 全稳定。 */
18
+ * 换台机器就指向不存在的目录,部署白名单全拷不到、bun install 必失败。改用 process.argv[1]。
19
+ *
20
+ * ⚠️ 必须 realpathSync:npx 下 process.argv[1] 是 node_modules/.bin/<pkg> 符号链接(bundle 带
21
+ * #!/usr/bin/env node shebang,内核按原链接路径执行,node 拿到未解析路径)。path.resolve 不跟符号链接,
22
+ * 会从 .bin 上溯,永远碰不到 sibling 的包根 → 部署源错指到 node_modules、白名单拷空、bun install 崩。
23
+ * realpathSync 把符号链接解析到真实 dist/install.cjs,dirname 后上溯即命中包根。 */
20
24
  function findPackageRoot(): string {
21
25
  const entry = process.argv[1];
22
- const start = entry ? dirname(resolve(entry)) : process.cwd();
26
+ let start = process.cwd();
27
+ if (entry) {
28
+ try {
29
+ start = dirname(realpathSync(resolve(entry)));
30
+ } catch {
31
+ start = dirname(resolve(entry)); // entry 不存在等异常时退回普通解析
32
+ }
33
+ }
23
34
  let dir = start;
24
- for (let i = 0; i < 10; i++) {
35
+ for (let i = 0; i < 12; i++) {
25
36
  if (existsSync(join(dir, "package.json")) && existsSync(join(dir, ".claude-plugin"))) return dir;
26
37
  const parent = dirname(dir);
27
38
  if (parent === dir) break;
@@ -1,9 +1,8 @@
1
1
  // 注册 plugin 到三处 JSON:known_marketplaces + installed_plugins + settings.enabledPlugins。
2
2
  // 关键:directory marketplace 的 plugin 不会自动进 settings.enabledPlugins(bug #17832),
3
3
  // 必须 install 脚本显式写 settings.json,否则 plugin 文件在但 hook 不生效。
4
- import { join } from "node:path";
5
4
  import { readJsonDefault, writeJsonAtomicWithBackup } from "./json-safe";
6
- import { installedPluginsPath, knownMarketplacesPath, pluginsRoot, settingsPath } from "./paths";
5
+ import { installedPluginsPath, knownMarketplacesPath, settingsPath } from "./paths";
7
6
  import { MARKETPLACE_NAME, PLUGIN_NAME } from "./deploy";
8
7
  import { SERVICE_VERSION } from "../shared/config";
9
8
 
@@ -13,11 +12,14 @@ function pluginKey(): string {
13
12
  return `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
14
13
  }
15
14
 
16
- /** 注册 marketplace(directory source,指向 cachePath/.claude-plugin)。幂等。 */
15
+ /** 注册 marketplace(directory source)。幂等。
16
+ * source.path 与 installLocation 都指 cachePath(marketplace 根,含 .claude-plugin/marketplace.json)。
17
+ * 不能指 .claude-plugin 子目录:Claude Code 按 installLocation/.claude-plugin/marketplace.json 读清单,
18
+ * 且 plugin source "./" 相对根解析。指 .claude-plugin 子目录会报 "Plugin X not found in marketplace Y"
19
+ * (实测 Claude Code 2.1.123)。也不能用 ~/.claude/plugins/marketplaces/<name>——那目录我们没填,是空的。 */
17
20
  export function registerMarketplace(cachePath: string): void {
18
21
  const file = knownMarketplacesPath();
19
22
  const data = readJsonDefault<Record<string, any>>(file, {});
20
- const marketplaceDir = join(cachePath, ".claude-plugin");
21
23
  const existing = data[MARKETPLACE_NAME];
22
24
  if (existing?.source && existing.source.source !== "directory") {
23
25
  console.log(
@@ -25,8 +27,8 @@ export function registerMarketplace(cachePath: string): void {
25
27
  );
26
28
  }
27
29
  data[MARKETPLACE_NAME] = {
28
- source: { source: "directory", path: marketplaceDir },
29
- installLocation: join(pluginsRoot(), "marketplaces", MARKETPLACE_NAME),
30
+ source: { source: "directory", path: cachePath },
31
+ installLocation: cachePath,
30
32
  lastUpdated: new Date().toISOString(),
31
33
  autoUpdate: false,
32
34
  };
@@ -70,7 +72,7 @@ export function enablePlugin(cachePath: string): void {
70
72
  if (!data.extraKnownMarketplaces) data.extraKnownMarketplaces = {};
71
73
  if (!data.extraKnownMarketplaces[MARKETPLACE_NAME]) {
72
74
  data.extraKnownMarketplaces[MARKETPLACE_NAME] = {
73
- source: { source: "directory", path: join(cachePath, ".claude-plugin") },
75
+ source: { source: "directory", path: cachePath },
74
76
  };
75
77
  }
76
78
  writeJsonAtomicWithBackup(file, data);