project-cypher 0.8.0 → 0.10.0

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.
Files changed (2) hide show
  1. package/bin/cypher.js +12 -0
  2. package/package.json +1 -1
package/bin/cypher.js CHANGED
@@ -69,7 +69,14 @@ async function doLink(server) {
69
69
  const k = load(); k.server = base; k.token = j.token; k.machineId = j.machineId; save(k); console.log('linked.'); return;
70
70
  }
71
71
  }
72
+ const dropToken = msg => { const k = rawCfg(); k.token = ''; delete k.machineId; save(k); console.log(msg); };
72
73
  const cmds = {
74
+ // Unlink this computer: tells the server, forgets the token. Projects/Root folder stay on disk.
75
+ async disconnect() {
76
+ const c = load(); if (!c.token) return console.log('already disconnected.');
77
+ await fetch(httpOf(c.server) + '/unlink', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ token: c.token }) }).catch(() => null);
78
+ dropToken('disconnected. This computer is no longer linked to your app. Run cypher init to link again.');
79
+ },
73
80
  // First-run setup: checks Claude Code, reaches the server, shows the QR, adds this folder, goes online.
74
81
  async init(...argv) {
75
82
  const si = argv.indexOf('--server'); const server = si >= 0 ? argv[si + 1] : undefined; const c = load(); const base = httpOf(server || c.server);
@@ -157,10 +164,14 @@ const cmds = {
157
164
  let sig = JSON.stringify(announce());
158
165
  const watch = setInterval(() => { const a = announce(), n = JSON.stringify(a); if (n !== sig) { sig = n; tx({ type: 'hello', name: os.hostname(), projects: a }); console.log(`projects updated: ${a.length - 1}`); } }, 2000);
159
166
  ws.on('close', () => clearInterval(watch));
167
+ ws.on('unexpected-response', (req, res) => { if (res.statusCode === 401) { dropToken('This computer is not linked (removed from the app). Run cypher init to link again.'); process.exit(0); } else { req.destroy(); } });
160
168
  ws.on('message', raw => {
161
169
  let m; try { m = JSON.parse(raw); } catch { return; }
170
+ if (m.type === 'revoked') { runs.forEach(r => r.kill('SIGINT')); dropToken('Disconnected from the app. Run cypher init to link again.'); process.exit(0); }
162
171
  const proj = m.projectId === 'root' ? { id: 'root', path: ROOT_DIR, root: true } : readRegistry().find(p => p.id === m.projectId); const ctx = { reqId: m.reqId, projectId: m.projectId };
163
172
  if (m.type === 'stop') return runs.get(m.projectId)?.kill('SIGINT');
173
+ if (m.type === 'rmproject') { if (m.projectId !== 'root') writeRegistry(readRegistry().filter(x => x.id !== m.projectId)); return; }
174
+ if (m.type === 'reset') { const k = load(); if (k.sessions) { delete k.sessions[m.projectId]; save(k); } return; }
164
175
  if (m.type !== 'prompt') return;
165
176
  if (!proj) return tx({ ...ctx, type: 'error', message: 'unknown project' });
166
177
  if (runs.has(proj.id)) return tx({ ...ctx, type: 'error', message: 'Claude is still working on this project.' });
@@ -199,6 +210,7 @@ const help = () => console.log(`Project Cypher
199
210
  cypher pair <server-url> <code> alternative: pair with a code made in the app
200
211
  cypher add [folder] register a project folder (or just ask Root in the app)
201
212
  cypher projects | remove <id> list / remove projects
213
+ cypher disconnect unlink this computer from the app
202
214
  cypher connect go online, run Claude Code when the app asks
203
215
  cypher status | latest server check / latest app build
204
216
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-cypher",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Connect your machine's Claude Code projects to the Project Cypher phone app.",
5
5
  "bin": {
6
6
  "cypher": "bin/cypher.js"