bridge-agent 0.2.8 → 0.2.10

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/index.js CHANGED
@@ -373,4 +373,4 @@ ${Qo("bridge_get_project","bridge_get_plan","bridge_get_todos","bridge_add_todo"
373
373
  </plist>
374
374
  `;try{return(0,$.writeFileSync)(it,t,"utf-8"),!0}catch(n){return console.warn("[bridge] launchd.plist.write.failed",{error:String(n)}),!1}}function aa(){try{return(0,ne.execSync)(`launchctl kickstart -kp gui/$(id -u)/${us} 2>/dev/null; launchctl unload "${it}" 2>/dev/null; launchctl load "${it}"`,{stdio:"pipe"}),{ok:!0,permissionDenied:!1}}catch(r){let e=String(r);return{ok:!1,permissionDenied:e.includes("Permission denied")||e.includes("not allowed")||e.includes("bootstrap")}}}function ca(r){try{let e=(0,ne.spawn)(r,["start"],{detached:!0,stdio:"ignore",env:{...process.env,PATH:fs(),BRIDGE_DAEMON:"1"}});e.unref(),setTimeout(()=>{e.pid&&process.kill(e.pid,0)?(console.log("[bridge] daemon.pid",{pid:e.pid}),console.log("[bridge] background.ok",{log:or})):console.error("[bridge] background.failed \u2014 check: tail -f",{log:ar})},2e3)}catch(e){console.error("[bridge] background.spawn.failed",{error:String(e)})}}function la(){let r=parseInt(process.env.HEALTH_PORT??"3101",10),e=Date.now()+6e3,t=()=>{if(Date.now()>e){console.error("[bridge] health.verify.timeout \u2014 daemon may have crashed immediately");return}try{let s=require("node:http").get(`http://127.0.0.1:${r}/health`,i=>{i.statusCode===200?console.log("[bridge] health.verify.ok"):setTimeout(t,500)});s.on("error",()=>{setTimeout(t,500)}),s.setTimeout(1e3,()=>{s.destroy(),setTimeout(t,500)})}catch{setTimeout(t,500)}};setTimeout(t,1e3)}function da(){let r=new Be;ls(r);let e=parseInt(process.env.HEALTH_PORT??"3101",10),t=(0,ds.createServer)((n,s)=>{let i=cs(),o=JSON.stringify({status:"ok",connected:i,uptime:process.uptime()});s.writeHead(i?200:503,{"Content-Type":"application/json"}),s.end(o)});t.listen(e,"127.0.0.1",()=>{console.log(`[bridge] health. listening on 127.0.0.1:${e}`)}),t.on("error",n=>{console.error("[bridge] health.error",{error:n.message})})}function ps(){let r=process.env.BRIDGE_DAEMON==="1"||process.argv.includes("--daemon");if(console.log("[bridge] Starting bridge-agent daemon..."),r){da();return}ia()||(console.warn("[bridge] start.aborted.already.running"),process.exit(1));let e=sa(),t=oa(e),{ok:n,permissionDenied:s}=t?aa():{ok:!1,permissionDenied:!1};if(n){console.log("[bridge] launchd.ok \u2014 managed, auto-restart enabled"),console.log("[bridge] logs: tail -f",{out:or,err:ar}),la(),process.exit(0);return}s&&(console.warn("[bridge] launchd.permission.denied"),console.warn("[bridge] \u2192 Auto-start on login requires:"),console.warn(`[bridge] sudo launchctl bootstrap gui/$(id -u) "${it}"`),console.warn(`[bridge] Falling back to background process...
375
375
  `)),ca(e),process.exit(0)}var gs=y(require("https")),ms=y(require("http"));tt();function ua(r){return(r??"").trim()}async function _s(r,e=!1,t){console.log("[bridge] Starting auth flow..."),console.log(`[bridge] Server: ${r}`),console.log("[bridge] Open this URL to generate a daemon token:"),console.log(` ${r}/connect`);let n=ua(t);n&&console.log("[bridge] Using token from --token"),e&&(n?console.log("[bridge] --no-browser ignored because --token is provided."):(console.log("[bridge] --no-browser: exiting after printing URL."),process.exit(0)));let s=n;s||(console.log(),console.log("[bridge] After authenticating, paste your token here:"),s=await ha()),s||(console.error("[bridge] No token provided. Exiting."),process.exit(1)),await fa(r,s)||(console.error("[bridge] Token validation failed. Please try again."),process.exit(1));let c=r.replace(/^https?:\/\//,a=>a.startsWith("https")?"wss://":"ws://").replace(/\/?$/,"/ws/daemon");Jt({server:c,token:s,name:process.env.HOSTNAME??"My Machine"}),console.log("[bridge] Auth successful! Config saved to ~/.bridge/config.json"),console.log("[bridge] Run: bridge-agent start"),process.exit(0)}async function ha(){return new Promise(r=>{process.stdout.write("Token: ");let e="";process.stdin.setEncoding("utf-8"),process.stdin.on("data",t=>{e+=t,e.includes(`
376
- `)&&(process.stdin.pause(),r(e.trim()))}),process.stdin.resume()})}async function fa(r,e){return new Promise(t=>{let n=new URL("/api/tokens/validate",r),s=n.protocol==="https:",i=s?gs.default:ms.default,o={hostname:n.hostname,port:n.port||(s?443:80),path:n.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}},c=i.request(o,a=>{t(a.statusCode===200)});c.on("error",()=>t(!1)),c.end()})}var Ne=new wr;Ne.name("bridge-agent").description("Bridge local agent \u2014 connects your AI tools to Jerico").version("0.2.8");Ne.command("start").description("Start the bridge-agent daemon").action(()=>{ps()});Ne.command("auth").description("Authenticate with Bridge server").requiredOption("-s, --server <url>","Server URL (e.g., https://your-server.com)").option("-t, --token <token>","Use token non-interactively").option("--no-browser","Print auth URL without opening browser or interactive prompt").action(r=>{_s(r.server,!r.browser,r.token)});Ne.command("status").description("Show connection status").action(async()=>{try{let{loadConfig:r}=await Promise.resolve().then(()=>(tt(),Xn)),e=r();console.log("[bridge] Config found"),console.log(" Server:",e.server),console.log(" Name:",e.name)}catch{console.log("[bridge] Not authenticated. Run: bridge-agent auth")}});Ne.parse();
376
+ `)&&(process.stdin.pause(),r(e.trim()))}),process.stdin.resume()})}async function fa(r,e){return new Promise(t=>{let n=new URL("/api/tokens/validate",r),s=n.protocol==="https:",i=s?gs.default:ms.default,o={hostname:n.hostname,port:n.port||(s?443:80),path:n.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}},c=i.request(o,a=>{t(a.statusCode===200)});c.on("error",()=>t(!1)),c.end()})}var Ne=new wr;Ne.name("bridge-agent").description("Bridge local agent \u2014 connects your AI tools to Jerico").version("0.2.10");Ne.command("start").description("Start the bridge-agent daemon").action(()=>{ps()});Ne.command("auth").description("Authenticate with Bridge server").requiredOption("-s, --server <url>","Server URL (e.g., https://your-server.com)").option("-t, --token <token>","Use token non-interactively").option("--no-browser","Print auth URL without opening browser or interactive prompt").action(r=>{_s(r.server,!r.browser,r.token)});Ne.command("status").description("Show connection status").action(async()=>{try{let{loadConfig:r}=await Promise.resolve().then(()=>(tt(),Xn)),e=r();console.log("[bridge] Config found"),console.log(" Server:",e.server),console.log(" Name:",e.name)}catch{console.log("[bridge] Not authenticated. Run: bridge-agent auth")}});Ne.parse();
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "bridge-agent",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Bridge local agent — connects your AI tools to Jerico",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "bin": {
8
- "bridge-agent": "./dist/index.js"
8
+ "bridge-agent": "dist/index.js"
9
9
  },
10
10
  "files": [
11
11
  "dist/",
12
+ "scripts/postinstall.mjs",
12
13
  "README.md",
13
14
  "LICENSE"
14
15
  ],
@@ -19,7 +20,8 @@
19
20
  "build": "tsc --noEmit && node scripts/build.mjs",
20
21
  "dev": "tsc --watch",
21
22
  "typecheck": "tsc --noEmit",
22
- "prepublishOnly": "npm run build"
23
+ "prepublishOnly": "npm run build",
24
+ "postinstall": "node scripts/postinstall.mjs"
23
25
  },
24
26
  "keywords": [
25
27
  "jerico",
@@ -35,7 +37,7 @@
35
37
  "license": "MIT",
36
38
  "repository": {
37
39
  "type": "git",
38
- "url": "https://github.com/alperduzgun/jerico.git",
40
+ "url": "git+https://github.com/alperduzgun/jerico.git",
39
41
  "directory": "packages/daemon"
40
42
  },
41
43
  "dependencies": {
@@ -0,0 +1,43 @@
1
+ import { chmodSync, readdirSync, statSync } from 'fs'
2
+ import { fileURLToPath } from 'url'
3
+ import { dirname, resolve, join } from 'path'
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url))
6
+
7
+ function findSpawnHelpers(dir) {
8
+ const results = []
9
+ try {
10
+ for (const entry of readdirSync(dir)) {
11
+ const full = join(dir, entry)
12
+ if (statSync(full).isDirectory()) {
13
+ results.push(...findSpawnHelpers(full))
14
+ } else if (entry === 'spawn-helper') {
15
+ results.push(full)
16
+ }
17
+ }
18
+ } catch {}
19
+ return results
20
+ }
21
+
22
+ const searchRoots = [
23
+ resolve(__dirname, '../node_modules/node-pty/prebuilds'),
24
+ resolve(__dirname, '../../node_modules/node-pty/prebuilds'),
25
+ resolve(__dirname, '../../../node_modules/node-pty/prebuilds'),
26
+ ]
27
+
28
+ let fixed = 0
29
+ for (const root of searchRoots) {
30
+ for (const file of findSpawnHelpers(root)) {
31
+ try {
32
+ chmodSync(file, 0o755)
33
+ fixed++
34
+ console.log('[bridge-agent] postinstall: fixed permissions for', file)
35
+ } catch (err) {
36
+ console.warn('[bridge-agent] postinstall: failed to chmod', file, err.message)
37
+ }
38
+ }
39
+ }
40
+
41
+ if (fixed === 0) {
42
+ console.log('[bridge-agent] postinstall: no node-pty spawn-helper found to fix')
43
+ }