inscope 0.3.0 → 0.3.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 CHANGED
@@ -9,6 +9,10 @@
9
9
 
10
10
  > #### `cd` into a project and you are the right person: the right GitHub token, the right MCP servers, the right git commit email, all resolved live from `$PWD`. No toggles, no profile switching, and it holds up with several Claude Code sessions open at once.
11
11
 
12
+ <p align="center">
13
+ <img src="https://raw.githubusercontent.com/nrjdalal/inscope/main/docs/demo.gif" alt="inscope demo: interactive add, list, and doctor" width="800" />
14
+ </p>
15
+
12
16
  Concurrent sessions in different projects should never bleed work and personal accounts into each other. You describe each workspace once; `inscope` owns the moving parts and keeps them in sync:
13
17
 
14
18
  - a `.mcp.json` at each workspace root, with uniquely named servers
@@ -53,6 +57,9 @@ inscope add ~/nrjdalal --gh nrjdalal --email you@personal.dev
53
57
  # list what is configured
54
58
  inscope list
55
59
 
60
+ # edit a workspace interactively (gh account, git identity, servers)
61
+ inscope edit acme
62
+
56
63
  # verify tokens, identities, and the hook all resolve
57
64
  inscope doctor
58
65
 
@@ -65,6 +72,10 @@ inscope rm ~/acme
65
72
 
66
73
  `cd ~/acme/api` and you are the work account, with work MCP servers and your work commit email. `cd ~/nrjdalal/blog` and you are you.
67
74
 
75
+ <p align="center">
76
+ <img src="https://raw.githubusercontent.com/nrjdalal/inscope/main/docs/demo-switch.gif" alt="inscope switching git identity and tokens on cd" width="800" />
77
+ </p>
78
+
68
79
  ---
69
80
 
70
81
  ## ✨ Features
@@ -133,6 +144,10 @@ inscope doctor Verify tokens, identities, and the hook resolve correctly
133
144
 
134
145
  Run any command with `-h` for its options.
135
146
 
147
+ <p align="center">
148
+ <img src="https://raw.githubusercontent.com/nrjdalal/inscope/main/docs/demo-manage.gif" alt="inscope edit and rm with type-to-confirm" width="800" />
149
+ </p>
150
+
136
151
  ### `inscope add`
137
152
 
138
153
  Run it bare and it walks you through everything: pick the GitHub account from your signed-in `gh` accounts, accept your global git identity or set a per-workspace one, and toggle which MCP servers to enable. Pass any flag to skip its prompt, or `-y` to take the defaults non-interactively (for scripts and CI).
@@ -61,7 +61,7 @@ __inscope_ws="__init__" # force the first resolve, clearing any inherit
61
61
  __inscope_resolve_identity
62
62
  `},we=[`github`,`linear`,`notion`,`slack`],W=e=>we.map(t=>`${t}-${e}`),G=e=>n.join(u(e.path),`.mcp.json`),K=(e,t)=>e&&typeof e==`object`&&e.url?e.url:t,Te=e=>{let t=e.servers,n={};if(t.github&&(n[`github-${e.name}`]={type:`http`,url:`https://api.githubcopilot.com/mcp/`,headers:{Authorization:"Bearer ${GITHUB_TOKEN}"}}),t.linear&&(n[`linear-${e.name}`]={type:`http`,url:K(t.linear,`https://mcp.linear.app/mcp`)}),t.notion&&(n[`notion-${e.name}`]={type:`http`,url:K(t.notion,`https://mcp.notion.com/mcp`)}),t.slack){let r={SLACK_MCP_XOXP_TOKEN:"${SLACK_MCP_XOXP_TOKEN}"};t.slack.addMessageTool&&(r.SLACK_MCP_ADD_MESSAGE_TOOL=`true`),n[`slack-${e.name}`]={type:`stdio`,command:`npx`,args:[`-y`,`slack-mcp-server@1.3.0`,`--transport`,`stdio`],env:r}}return n},Ee=e=>{if(!t.existsSync(e))return{};try{return JSON.parse(t.readFileSync(e,`utf8`))}catch{return{}}},q=e=>{if(!t.existsSync(e))return{};try{return JSON.parse(t.readFileSync(e,`utf8`))}catch{throw Error(`${e} is not valid JSON; fix or remove it, then re-run inscope (left it untouched)`)}},De=e=>{let n=G(e);return t.existsSync(n)?Ee(n):null},Oe=e=>{let r=G(e);t.mkdirSync(n.dirname(r),{recursive:!0});let i=q(r),a=i.mcpServers&&typeof i.mcpServers==`object`?{...i.mcpServers}:{};for(let t of W(e.name))delete a[t];Object.assign(a,Te(e)),i.mcpServers=a,t.writeFileSync(r,JSON.stringify(i,null,2)+`
63
63
  `)},ke=e=>{let n=G(e);if(!t.existsSync(n))return;let r=q(n);if(r.mcpServers&&typeof r.mcpServers==`object`)for(let t of W(e.name))delete r.mcpServers[t];t.writeFileSync(n,JSON.stringify(r,null,2)+`
64
- `)},Ae=e=>{let t=o();return e===t?`$HOME`:e.startsWith(t+n.sep)?`$HOME/${e.slice(t.length+1)}`:e},J=()=>{let e=Ae(p());return`[ -r "${e}" ] && source "${e}"`},je=e=>{let t=J();if(e.includes(t))return e;let n=e.replace(/\n*$/,``),r=`# inscope: load each workspace's tokens (GitHub, Slack) from \$PWD on every cd\n${t}`;return n.length?`${n}\n\n${r}\n`:`${r}\n`},Me=()=>{let e=g(),n=``;try{n=t.readFileSync(e,`utf8`)}catch{}let r=je(n);r!==n&&t.writeFileSync(e,r)},Ne=()=>{try{return t.readFileSync(g(),`utf8`).includes(J())}catch{return!1}},Y=e=>{let r=p();t.mkdirSync(n.dirname(r),{recursive:!0}),t.writeFileSync(r,U(e)),be(e),Me();let i=[];for(let t of e.workspaces)Oe(t),i.push(G(t));return{hook:r,gitconfig:e.workspaces.some(e=>e.git?.email||e.git?.name),mcp:i}},X=`https://github.com/korotovsky/slack-mcp-server/blob/HEAD/docs/01-authentication-setup.md#option-2-using-slack_mcp_xoxp_token-user-oauth`,Pe=[`github`,`linear`,`notion`,`slack`],Fe=e=>`SLACK_MCP_XOXP_TOKEN_${e.toUpperCase().replace(/[^A-Z0-9]+/g,`_`)}`,Ie=e=>[e.github&&`github`,e.linear&&`linear`,e.notion&&`notion`,e.slack&&`slack`].filter(Boolean),Le=(e,t)=>({github:e.includes(`github`),linear:e.includes(`linear`),notion:e.includes(`notion`),slack:t?{keychain:t.keychain,addMessageTool:t.addMessageTool}:!1}),Re=e=>{let t=w(v()?y():_(),e);b(t),Y(t)},ze=async(e,t)=>{if(!e.servers.slack)return;let n=e.servers.slack.keychain;if(t){let e=await ce(`Paste the Slack xoxp token for ${n}: `);e?(ae(n,e),console.log(`✓ stored ${n} in the macOS keychain`)):console.error(`No token entered; skipped keychain write.`)}else O(n)||console.log(`\nSlack token not in the keychain yet. Create a Slack app (xoxp user OAuth):\n ${X}\nthen store the token once with:\n ${oe(n)}`)};var Z=`inscope`,Be=`0.3.0`,Q={name:`Neeraj Dalal`,email:`admin@nrjdalal.com`,url:`https://nrjdalal.com`};const $=`Map a directory to a GitHub account, git email, and MCP servers.
64
+ `)},Ae=e=>{let t=o();return e===t?`$HOME`:e.startsWith(t+n.sep)?`$HOME/${e.slice(t.length+1)}`:e},J=()=>{let e=Ae(p());return`[ -r "${e}" ] && source "${e}"`},je=e=>{let t=J();if(e.includes(t))return e;let n=e.replace(/\n*$/,``),r=`# inscope: load each workspace's tokens (GitHub, Slack) from \$PWD on every cd\n${t}`;return n.length?`${n}\n\n${r}\n`:`${r}\n`},Me=()=>{let e=g(),n=``;try{n=t.readFileSync(e,`utf8`)}catch{}let r=je(n);r!==n&&t.writeFileSync(e,r)},Ne=()=>{try{return t.readFileSync(g(),`utf8`).includes(J())}catch{return!1}},Y=e=>{let r=p();t.mkdirSync(n.dirname(r),{recursive:!0}),t.writeFileSync(r,U(e)),be(e),Me();let i=[];for(let t of e.workspaces)Oe(t),i.push(G(t));return{hook:r,gitconfig:e.workspaces.some(e=>e.git?.email||e.git?.name),mcp:i}},X=`https://github.com/korotovsky/slack-mcp-server/blob/HEAD/docs/01-authentication-setup.md#option-2-using-slack_mcp_xoxp_token-user-oauth`,Pe=[`github`,`linear`,`notion`,`slack`],Fe=e=>`SLACK_MCP_XOXP_TOKEN_${e.toUpperCase().replace(/[^A-Z0-9]+/g,`_`)}`,Ie=e=>[e.github&&`github`,e.linear&&`linear`,e.notion&&`notion`,e.slack&&`slack`].filter(Boolean),Le=(e,t)=>({github:e.includes(`github`),linear:e.includes(`linear`),notion:e.includes(`notion`),slack:t?{keychain:t.keychain,addMessageTool:t.addMessageTool}:!1}),Re=e=>{let t=w(v()?y():_(),e);b(t),Y(t)},ze=async(e,t)=>{if(!e.servers.slack)return;let n=e.servers.slack.keychain;if(t){let e=await ce(`Paste the Slack xoxp token for ${n}: `);e?(ae(n,e),console.log(`✓ stored ${n} in the macOS keychain`)):console.error(`No token entered; skipped keychain write.`)}else O(n)||console.log(`\nSlack token not in the keychain yet. Create a Slack app (xoxp user OAuth):\n ${X}\nthen store the token once with:\n ${oe(n)}`)};var Z=`inscope`,Be=`0.3.1`,Q={name:`Neeraj Dalal`,email:`admin@nrjdalal.com`,url:`https://nrjdalal.com`};const $=`Map a directory to a GitHub account, git email, and MCP servers.
65
65
  Runs interactively in a terminal; pass flags or -y to skip the prompts. Re-running
66
66
  with the same path or label updates that workspace.
67
67
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inscope",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Per-workspace identity for Claude Code: scope MCP servers, GitHub auth, and git commit identity to the directory you are in.",
5
5
  "keywords": [
6
6
  "claude-code",