mobsession 0.1.0 → 0.1.1
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/README.md +4 -4
- package/index.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# mobsession
|
|
2
2
|
|
|
3
|
-
Drive Claude Code together. `
|
|
3
|
+
Drive Claude Code together. `mobsession` runs a real Claude Code session on your machine and shares a
|
|
4
4
|
link so your whole team can steer it in real time, with your own Claude subscription.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
@@ -14,8 +14,8 @@ npm i -g mobsession
|
|
|
14
14
|
In any project directory:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
|
|
17
|
+
mobsession start # or the short alias: mss start
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
It prints a link. Open it (and share it) at https://mobsession.ai to watch the session live and add
|
|
21
|
-
prompts together.
|
|
21
|
+
prompts together.
|
package/index.js
CHANGED
|
@@ -39,4 +39,4 @@ Expecting one of '${s.join("', '")}'`);let n=`${e}Help`;return this.on(n,i=>{let
|
|
|
39
39
|
`)+`\r
|
|
40
40
|
\r
|
|
41
41
|
`+d)}function y(f,S,d,T,E,W){if(f.listenerCount("wsClientError")){let C=new Error(E);Error.captureStackTrace(C,y),f.emit("wsClientError",C,d,S)}else q(d,T,E,W)}}}),wp=Xe(vl(),1),xp=Xe(on(),1),Sp=Xe(gr(),1),Cp=Xe(vo(),1),kp=Xe(bo(),1),Ep=Xe(wo(),1),wl=Xe(an(),1),Tp=Xe(bl(),1),xl=wl.default,Sl=xl;go(Sl);var $g=H.object({numItems:H.number(),cursor:H.union(H.string(),H.null()),endCursor:H.optional(H.union(H.string(),H.null())),id:H.optional(H.number()),maximumRowsRead:H.optional(H.number()),maximumBytesRead:H.optional(H.number())});function xo(r,e){let t={get(s,n){if(typeof n=="string"){let i=[...e,n];return xo(r,i)}else if(n===Xs){if(e.length<1){let i=[r,...e].join(".");throw new Error(`API path is expected to be of the form \`${r}.childComponent.functionName\`. Found: \`${i}\``)}return"_reference/childComponent/"+e.join("/")}else return}};return new Proxy({},t)}var un=()=>xo("components",[]);var Tl=Symbol("var.requestId"),Ol=Symbol("var.ip"),Al=Symbol("var.userAgent"),Rl=Symbol("var.now"),Il={[Tl]:"requestId",[Ol]:"ip",[Al]:"userAgent",[Rl]:"now"};var Pl=Object.defineProperty,Nl=(r,e,t)=>e in r?Pl(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,je=(r,e,t)=>Nl(r,typeof e!="symbol"?e+"":e,t),is=class{constructor(e){je(this,"indexes"),je(this,"stagedDbIndexes"),je(this,"searchIndexes"),je(this,"stagedSearchIndexes"),je(this,"vectorIndexes"),je(this,"stagedVectorIndexes"),je(this,"validator"),this.indexes=[],this.stagedDbIndexes=[],this.searchIndexes=[],this.stagedSearchIndexes=[],this.vectorIndexes=[],this.stagedVectorIndexes=[],this.validator=e}" indexes"(){return this.indexes}index(e,t){return Array.isArray(t)?this.indexes.push({indexDescriptor:e,fields:t}):t.staged?this.stagedDbIndexes.push({indexDescriptor:e,fields:t.fields}):this.indexes.push({indexDescriptor:e,fields:t.fields}),this}searchIndex(e,t){return t.staged?this.stagedSearchIndexes.push({indexDescriptor:e,searchField:t.searchField,filterFields:t.filterFields||[]}):this.searchIndexes.push({indexDescriptor:e,searchField:t.searchField,filterFields:t.filterFields||[]}),this}vectorIndex(e,t){return t.staged?this.stagedVectorIndexes.push({indexDescriptor:e,vectorField:t.vectorField,dimensions:t.dimensions,filterFields:t.filterFields||[]}):this.vectorIndexes.push({indexDescriptor:e,vectorField:t.vectorField,dimensions:t.dimensions,filterFields:t.filterFields||[]}),this}self(){return this}export(){let e=this.validator.json;if(typeof e!="object")throw new Error("Invalid validator: please make sure that the parameter of `defineTable` is valid (see https://docs.convex.dev/database/schemas)");return{indexes:this.indexes,stagedDbIndexes:this.stagedDbIndexes,searchIndexes:this.searchIndexes,stagedSearchIndexes:this.stagedSearchIndexes,vectorIndexes:this.vectorIndexes,stagedVectorIndexes:this.stagedVectorIndexes,documentType:e}}};function ln(r){return Gs(r)?new is(r):new is(H.object(r))}var hn=class{constructor(e,t){je(this,"tables"),je(this,"strictTableNameTypes"),je(this,"schemaValidation"),this.tables=e,this.schemaValidation=t?.schemaValidation===void 0?!0:t.schemaValidation}export(){return JSON.stringify({tables:Object.entries(this.tables).map(([e,t])=>{let{indexes:s,stagedDbIndexes:n,searchIndexes:i,stagedSearchIndexes:o,vectorIndexes:c,stagedVectorIndexes:a,documentType:u}=t.export();return{tableName:e,indexes:s,stagedDbIndexes:n,searchIndexes:i,stagedSearchIndexes:o,vectorIndexes:c,stagedVectorIndexes:a,documentType:u}}),schemaValidation:this.schemaValidation})}};function So(r,e){return new hn(r,e)}var oy=So({_scheduled_functions:ln({name:H.string(),args:H.array(H.any()),scheduledTime:H.float64(),completedTime:H.optional(H.float64()),state:H.union(H.object({kind:H.literal("pending")}),H.object({kind:H.literal("inProgress")}),H.object({kind:H.literal("success")}),H.object({kind:H.literal("failed"),error:H.string()}),H.object({kind:H.literal("canceled")}))}),_storage:ln({sha256:H.string(),size:H.float64(),contentType:H.optional(H.string())})});var He=en;var By=un();var $l={maxBatch:25,windowMs:200,setTimer:(r,e)=>setTimeout(r,e),clearTimer:r=>clearTimeout(r)},os=class{constructor(e,t={}){this.flush=e;this.opts={...$l,...t}}flush;buffer=[];nextClientEventId=0;timer=null;opts;add(e){this.buffer.push({v:1,clientEventId:this.nextClientEventId++,event:e}),this.buffer.length>=this.opts.maxBatch?this.flushNow():this.timer===null&&(this.timer=this.opts.setTimer(()=>this.flushNow(),this.opts.windowMs))}flushNow(){if(this.timer!==null&&(this.opts.clearTimer(this.timer),this.timer=null),this.buffer.length===0)return;let e=Ml(this.buffer);this.buffer=[],this.flush(e)}};function Ml(r){let e=[];for(let t of r){let s=e[e.length-1];t.event.type==="agent.text"&&s&&s.event.type==="agent.text"&&s.event.turnId===t.event.turnId?s.event={...s.event,text:s.event.text+t.event.text}:e.push(t)}return e}async function Co(r){let e=new Ct(r.convexUrl),t=!1,s=!1,n=null,i=null,o=[],c=new Set,a=v=>{let k=n;t=!1,n=null,i=null,k&&e.mutation(He.prompts.markTurn,{promptId:k,status:v}).catch(()=>{}),l()};async function u(v){if(!v.attachments?.length)return[];let k=await e.query(He.files.attachmentUrls,{storageIds:v.attachments.map(f=>f.storageId)}),q=new Map(k.map(f=>[f.storageId,f.url])),y=[];for(let f of v.attachments){let S=q.get(f.storageId);if(S)try{let d=await fetch(S),T=Buffer.from(await d.arrayBuffer()).toString("base64");y.push({mediaType:f.mediaType,data:T})}catch{}}return y}async function l(){if(!(t||s)){s=!0;try{let v=[...o].sort((k,q)=>k.queueOrder-q.queueOrder);for(let k of v)if(await e.mutation(He.prompts.claimPrompt,{promptId:k._id})){t=!0,n=k._id;try{let y=await u(k);i=r.agent.sendPrompt(k.text,y),r.onPromptInjected?.({text:k.text,submittedBy:k.submittedBy,local:c.has(k._id)})}catch{a("failed");continue}return}}finally{s=!1}}}let h=null,p=[];r.agent.onEvent(v=>{v.type==="agent.turn_result"&&i&&v.turnId===i?a(v.success?"done":"failed"):v.type==="agent.error"&&t&&a("failed"),r.onAgentEvent?.(v),h?h.add(v):p.push(v)}),r.agent.onError(v=>{let k={type:"agent.error",message:v.message};r.onAgentEvent?.(k),h?h.add(k):p.push(k),t&&a("failed")});let m;try{m=await e.mutation(He.sessions.createSession,{cwd:r.cwd,model:r.model})}catch(v){throw await r.agent.stop(),await e.close(),v}let{sessionId:g,joinCode:O}=m,P=Promise.resolve(),j=v=>new Promise(k=>setTimeout(k,v));h=new os(v=>{P=P.then(async()=>{for(let k=0;k<3;k+=1)try{await e.mutation(He.events.appendEvents,{sessionId:g,events:v});return}catch(q){if(k===2){console.error(`Failed to mirror ${v.length} events after retries:`,q);return}await j(200*(k+1))}})});for(let v of p)h.add(v);p.length=0;let w=e.onUpdate(He.prompts.pendingPrompts,{sessionId:g},v=>{o=v,l()});return{joinCode:O,submitLocalPrompt:async v=>{let k=await e.mutation(He.prompts.submitLocalPrompt,{sessionId:g,text:v});c.add(k)},stop:async()=>{h?.flushNow(),await P,w(),await e.mutation(He.sessions.endSession,{sessionId:g}).catch(()=>{}),await e.close()}}}var ql=6e3;async function ko(r){let e=ir({cwd:r.cwd}),t=tt.createInterface({input:process.stdin,output:process.stdout,prompt:"you> "}),s=!1,n=l=>{s&&process.stdout.isTTY&&(tt.cursorTo(process.stdout,0),tt.clearLine(process.stdout,0)),console.log(l),s&&t.prompt(!0)},i=!1,o=l=>{if(l.type==="agent.text"){i||(s&&process.stdout.isTTY&&(tt.cursorTo(process.stdout,0),tt.clearLine(process.stdout,0)),process.stdout.write("claude> "),i=!0),process.stdout.write(l.text);return}i&&(process.stdout.write(`
|
|
42
|
-
`),i=!1);let h=Rr(l);h!==null&&n(h)},c,a=!1,u=async()=>{if(a)return;a=!0,t.close();let l=setTimeout(()=>process.exit(0),ql);try{await c?.stop(),await e.stop()}finally{clearTimeout(l),process.exit(0)}};e.onError(l=>n(`[agent error] ${l.message}`)),process.on("SIGINT",()=>{u()}),process.on("SIGTERM",()=>{u()}),process.on("uncaughtException",l=>{console.error("[fatal]",l),u()}),process.on("unhandledRejection",l=>{console.error("[fatal]",l),u()}),t.on("close",()=>{u()});try{c=await Co({convexUrl:r.convexUrl,cwd:r.cwd,model:r.model,agent:e,onAgentEvent:o,onPromptInjected:({text:l,submittedBy:h,local:p})=>{p||n(`${h}> ${l}`)}})}catch(l){console.error("Could not start the session:",l instanceof Error?l.message:l),await e.stop(),process.exit(1);return}console.log("
|
|
42
|
+
`),i=!1);let h=Rr(l);h!==null&&n(h)},c,a=!1,u=async()=>{if(a)return;a=!0,t.close();let l=setTimeout(()=>process.exit(0),ql);try{await c?.stop(),await e.stop()}finally{clearTimeout(l),process.exit(0)}};e.onError(l=>n(`[agent error] ${l.message}`)),process.on("SIGINT",()=>{u()}),process.on("SIGTERM",()=>{u()}),process.on("uncaughtException",l=>{console.error("[fatal]",l),u()}),process.on("unhandledRejection",l=>{console.error("[fatal]",l),u()}),t.on("close",()=>{u()});try{c=await Co({convexUrl:r.convexUrl,cwd:r.cwd,model:r.model,agent:e,onAgentEvent:o,onPromptInjected:({text:l,submittedBy:h,local:p})=>{p||n(`${h}> ${l}`)}})}catch(l){console.error("Could not start the session:",l instanceof Error?l.message:l),await e.stop(),process.exit(1);return}console.log("mobsession is live."),console.log(`Join: ${r.webBaseUrl}/s/${c.joinCode}`),console.log("You and everyone on the link share this agent. Type a prompt and press Enter. Ctrl+C to end."),s=!0,t.prompt(),t.on("line",l=>{let h=l.trim();h&&c?.submitLocalPrompt(h),t.prompt()})}var Ll="https://standing-mongoose-114.convex.cloud",Vl="https://mobsession.ai",as=new jn;as.name("mobsession").description("mobsession: drive Claude Code together");as.command("dev").description("Run a local agent session and round-trip prompts from the terminal (no cloud)").option("--cwd <dir>","working directory for the agent",process.cwd()).action(r=>Wi(r.cwd));as.command("start").description("Run a cloud session: mirror the agent to the web and inject approved prompts").option("--cwd <dir>","working directory for the agent",process.cwd()).option("--convex-url <url>","Convex deployment URL",process.env.MOB_SQUAD_CONVEX_URL??Ll).option("--web-url <url>","web app base URL for the join link",process.env.MOB_SQUAD_WEB_URL??Vl).option("--model <model>","model label for the session","claude").action(r=>{if(!r.convexUrl){console.error("Missing Convex URL. Set MOB_SQUAD_CONVEX_URL or pass --convex-url."),process.exitCode=1;return}ko({cwd:r.cwd,convexUrl:r.convexUrl,webBaseUrl:r.webUrl,model:r.model})});as.parse();
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mobsession",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "mobsession: drive Claude Code together. A shared, collaborative Claude Code session your whole team can steer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"mobsession": "./index.js",
|
|
8
|
+
"mss": "./index.js"
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=22"
|