function publicMind(m, me) { return { id: m.id, name: m.name, origin: m.origin, kind: m.kind, scopes: m.scopes.slice(), createdAt: m.createdAt, lastUsedAt: m.lastUsedAt, expiresAt: m.expiresAt, you: !!(me && me.id === m.id) }; } ## Exact source excerpt, characters 34202–34558 function needsToken(method, pathname) { if (method === 'POST' && pathname === '/pair') return false; // how a device gets its token if (method === 'GET' || method === 'HEAD') { return /^\/(code|test|pair|roots)(\/|$)/.test(pathname); } return true; // every POST and any other verb } ## Exact source excerpt, characters 34560–35188 /** Which scope a route uses. Every default scope is on for a new mind. */ function scopeFor(method, pathname) { if (/^\/code\/(tree|read|search|git\/status)$/.test(pathname) || pathname === '/roots') return 'read'; if (pathname === '/code/write') return 'write'; if (pathname === '/code/patch') return 'patch'; if (pathname === '/test/run' || pathname === '/code/test') return 'test'; if (pathname === '/code/git/commit') return 'commit'; if (/^\/(wallet|trade)\//.test(pathname) && method !== 'GET') return 'wallet'; if (/^\/pair\/(list|revoke|revoke-all|scopes)$/.test(pathname)) return 'manage'; return ''; } ## Exact source excerpt, characters 35190–36271 /** Local tools (Claude Code, Cursor, scripts) are trusted by default through the token file. */ function ensureLocalToolsToken() { var st = trustState(); if (!st.localTools) { try { fs.unlinkSync(TOKEN_FILE); } catch (e) {} return null; } var existing = ''; try { existing = fs.readFileSync(TOKEN_FILE, 'utf8').trim(); } catch (e) {} var have = existing ? mindForToken(existing) : null; if (have && have.kind === 'cli') return have; var tok = newToken(); st.minds = st.minds.filter(function (m) { return m.kind !== 'cli'; }); var mind = { id: newMindId(), name: 'Local tools on this computer', origin: '', kind: 'cli', scopes: DEFAULT_SCOPES.slice(), tokenSha256: sha256Hex(tok), createdAt: new Date().toISOString(), lastUsedAt: '', expiresAt: null }; st.minds.push(mind); saveTrust(); try { fs.writeFileSync(TOKEN_FILE, tok + '\n', { mode: 0o600 }); try { fs.chmodSync(TOKEN_FILE, 0o600); } catch (e) {} } catch (e) { console.error(' ! Could not write token file: ' + e.message); } return mind; } ## Exact source excerpt, characters 36273–36575 // ── Pairing code (human reads it here, types it in the app) ── const PAIR_ALPHABET = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'; // no 0/O, 1/I/L const PAIR_TTL_MS = 10 * 60 * 1000; const PAIR_MAX_TRIES = 5; const PAIR_COOLDOWN_MS = 30 * 1000; var pairState = { code: '', expires: 0, tries: 0, coolUntil: 0 }; ## Exact source excerpt, characters 36577–37205 function newPairCode(reason) { var s = ''; for (var i = 0; i < 6; i++) s += PAIR_ALPHABET[crypto.randomInt(0, PAIR_ALPHABET.length)]; pairState = { code: s, expires: Date.now() + PAIR_TTL_MS, tries: 0, coolUntil: reason === 'lockout' ? Date.now() + PAIR_COOLDOWN_MS : 0 }; console.log(''); console.log(' \u2726 Pairing code: ' + s.slice(0, 3) + '-' + s.slice(3) + ' (type it in FreeLattice \u2192 Workshop \u2192 Code. Good for 10 minutes.)'); if (reason === 'lockout') console.log(' \u2726 (New code after 5 wrong tries. It works in 30 seconds.)'); console.log(''); return s; } ## Exact source excerpt, characters 37207–37318 function normalizePairCode(s) { return String(s || '').toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 6); } ## Exact source excerpt, characters 37320–37453 // ── Content-free, hash-chained ledger ── const LEDGER_FILE = path.join(DATA_DIR, 'bridge-ledger.jsonl'); var ledgerLastHash = null; ## Exact source excerpt, characters 37455–37782 function ledgerTip() { if (ledgerLastHash) return ledgerLastHash; try { var lines = fs.readFileSync(LEDGER_FILE, 'utf8').trim().split('\n').filter(Boolean); ledgerLastHash = lines.length ? JSON.parse(lines[lines.length - 1]).self : 'genesis'; } catch (e) { ledgerLastHash = 'genesis'; } return ledgerLastHash; } ## Exact source excerpt, characters 37784–38734 function ledgerAppend(fields) { // Fixed key order. Never message text, never file content, never a token. ledgerLastHash = null; // re-read the tip: the command line may have appended var entry = { ts: new Date().toISOString(), kind: fields.kind || 'commit_request', route: fields.route || '', origin: fields.origin || '', agent: String(fields.agent || '').slice(0, 8), device: String(fields.device || '').slice(0, 8), result: fields.result || '', filesCount: fields.filesCount || 0, filesSha256: fields.filesSha256 || '', messageSha256: fields.messageSha256 || '', commitSha: fields.commitSha || '', prev: ledgerTip() }; entry.self = sha256Hex(JSON.stringify(entry)); try { fs.appendFileSync(LEDGER_FILE, JSON.stringify(entry) + '\n', { mode: 0o600 }); ledgerLastHash = entry.self; } catch (e) { console.error(' ! Ledger append failed: ' + e.message); } return entry; } ## Exact source excerpt, characters 38736–39074 // ── Trusted project folders and path lock ── var PROJECT_ROOT_REAL = null; function projectRootReal() { if (!PROJECT_ROOT_REAL) { var wanted = path.resolve(process.env.FL_PROJECT || process.cwd()); try { PROJECT_ROOT_REAL = fs.realpathSync(wanted); } catch (e) { PROJECT_ROOT_REAL = wanted; } } return PROJECT_ROOT_REAL; } ## Exact source excerpt, characters 39076–39422 /** 'project' is FL_PROJECT (or cwd). Other names come from Kirk's roots list. */ function rootReal(name) { if (!name || name === 'project') return projectRootReal(); var st = trustState(); if (!Object.prototype.hasOwnProperty.call(st.roots, name)) return null; try { return fs.realpathSync(st.roots[name]); } catch (e) { return null; } } ## Exact source excerpt, characters 39424–39626 function rootList() { var st = trustState(); return [{ name: 'project', path: projectRootReal() }].concat(Object.keys(st.roots).map(function (k) { return { name: k, path: st.roots[k] }; })); } ## Exact source excerpt, characters 39628–39812 function isInside(root, candidate) { var rel = path.relative(root, candidate); return rel === '' || (!(rel === '..' || rel.startsWith('..' + path.sep)) && !path.isAbsolute(rel)); } ## Exact source excerpt, characters 39814–41452 const BRIDGE_FORBIDDEN_TOP = ['.git', '.ssh']; function lockedPath(relPath, opts) { opts = opts || {}; if (typeof relPath !== 'string' || !relPath || relPath.length > 1024 || hasControlChars(relPath)) { return { error: 400, reason: 'bad-path' }; } if (path.isAbsolute(relPath) || /^[a-zA-Z]:/.test(relPath) || relPath.charAt(0) === '\\') { return { error: 403, reason: 'absolute-path' }; } var root = opts.root || projectRootReal(); var full = path.resolve(root, relPath); if (!isInside(root, full)) return { error: 403, reason: 'outside-project' }; var rel = path.relative(root, full); var top = rel.split(path.sep)[0]; if (!opts.allowRoot && rel === '') return { error: 400, reason: 'root-not-allowed' }; if (BRIDGE_FORBIDDEN_TOP.indexOf(top) !== -1) return { error: 403, reason: 'forbidden-path' }; if (!opts.secrets && /^\.env(\.|$)/.test(path.basename(rel))) return { error: 403, reason: 'secrets-not-granted' }; // Realpath the nearest existing ancestor (or the file itself) so a // symlink inside the project cannot point writes outside it. var probe = full; for (;;) { try { fs.lstatSync(probe); break; } catch (e) { if (e.code !== 'ENOENT') return { error: 403, reason: 'stat-failed' }; var up = path.dirname(probe); if (up === probe) return { error: 403, reason: 'no-ancestor' }; probe = up; } } var real; try { real = fs.realpathSync(probe); } catch (e) { return { error: 403, reason: 'dangling-symlink' }; } if (!isInside(root, real)) return { error: 403, reason: 'symlink-outside' }; return { full: full, rel: rel === '' ? '.' : rel }; } ## Exact source excerpt, characters 41454–41626 function runGit(args, root) { return execFileSync('git', args, { cwd: root || projectRootReal(), encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 30000 }); } ## Exact source excerpt, characters 41628–42013 function runSmokeFile(timeoutMs, root) { // No shell: node binary + fixed script path. stdout and stderr joined. var r = spawnSync(process.execPath, ['tests/smoke.js'], { cwd: root || projectRootReal(), timeout: timeoutMs, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 }); return { status: r.status, out: String(r.stdout || '') + String(r.stderr || ''), error: r.error }; } ## Exact source excerpt, characters 42015–43195 // ── Command-line trust tools (Kirk's hands, never reachable over HTTP) ── function bridgeLockUsage() { console.log(''); console.log(' Agent Bridge trust tools (run in a terminal on this computer):'); console.log(' node tools/agent-bridge.js --list-minds'); console.log(' node tools/agent-bridge.js --revoke '); console.log(' node tools/agent-bridge.js --revoke-all (every paired device; local tools stay)'); console.log(' node tools/agent-bridge.js --allow-secrets (this mind may read and write .env files)'); console.log(' node tools/agent-bridge.js --deny-secrets '); console.log(' node tools/agent-bridge.js --trust-origin https://example.dev (exact origin, never *)'); console.log(' node tools/agent-bridge.js --untrust-origin https://example.dev'); console.log(' node tools/agent-bridge.js --add-root '); console.log(' node tools/agent-bridge.js --remove-root '); console.log(' node tools/agent-bridge.js --trust-local-tools | --untrust-local-tools'); console.log(' A running bridge picks up every change at once. No restart needed.'); console.log(''); } ## Exact source excerpt, characters 43197–48732